Skip to content

Commit de5807c

Browse files
committed
fix: docs not building
1 parent 2bb8db1 commit de5807c

File tree

8 files changed

+875
-39
lines changed

8 files changed

+875
-39
lines changed

.readthedocs.yaml

Lines changed: 4 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,31 +8,13 @@ version: 2
88
build:
99
os: ubuntu-22.04
1010
tools:
11-
python: "3.8"
12-
# You can also specify other tool versions:
13-
# nodejs: "19"
14-
# rust: "1.64"
15-
# golang: "1.19"
11+
python: "3.9"
1612
jobs:
1713
post_create_environment:
18-
# Install poetry
19-
# https://python-poetry.org/docs/#installing-manually
20-
- pip install poetry
21-
# Tell poetry to not use a virtual environment
22-
- poetry config virtualenvs.create false
14+
- pip install uv
2315
post_install:
24-
# Install dependencies with 'docs' dependency group
25-
# https://python-poetry.org/docs/managing-dependencies/#dependency-groups
26-
- poetry install --with docs
16+
- uv pip install --system .
17+
- uv pip install --system mkdocs mkdocs-material
2718

28-
# Build documentation in the "docs/" directory with Sphinx
2919
mkdocs:
3020
configuration: documentation/mkdocs.yml
31-
32-
33-
# Optional but recommended, declare the Python requirements required
34-
# to build your documentation
35-
# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
36-
# python:
37-
# install:
38-
# - requirements: docs/requirements.txt

README.md

Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,253 @@ client = Client(authorization=auth, environment=Environment.TEST)
6464
- `Environment.DEMO``https://api-demo.ksef.mf.gov.pl/api/v2/`
6565
- `Environment.TEST``https://api-test.ksef.mf.gov.pl/api/v2/`
6666

67+
## Building Invoices
68+
69+
### Basic invoice structure
70+
71+
```python
72+
from datetime import date
73+
from decimal import Decimal
74+
75+
from ksef.models.invoice import (
76+
Address,
77+
Invoice,
78+
InvoiceData,
79+
InvoiceType,
80+
Issuer,
81+
IssuerIdentificationData,
82+
NipIdentification,
83+
Subject,
84+
)
85+
from ksef.models.invoice_rows import InvoiceRow, InvoiceRows
86+
from ksef.models.invoice_annotations import InvoiceAnnotations
87+
88+
invoice = Invoice(
89+
issuer=Issuer(
90+
identification_data=IssuerIdentificationData(
91+
nip="1234567890",
92+
full_name="My Company Sp. z o.o.",
93+
),
94+
address=Address(
95+
country_code="PL",
96+
city="Warszawa",
97+
street="Marszałkowska",
98+
house_number="10",
99+
apartment_number="5",
100+
postal_code="00-001",
101+
),
102+
),
103+
recipient=Subject(
104+
identification_data=NipIdentification(nip="0987654321"),
105+
address=Address(
106+
country_code="PL",
107+
city="Kraków",
108+
street="Floriańska",
109+
house_number="1",
110+
postal_code="30-001",
111+
),
112+
name="Customer Sp. z o.o.",
113+
),
114+
invoice_data=InvoiceData(
115+
currency_code="PLN",
116+
issue_date=date(2026, 3, 25),
117+
issue_number="2026/03/001",
118+
sell_date=date(2026, 3, 25),
119+
total_amount=Decimal("123.00"),
120+
invoice_type=InvoiceType.REGULAR_VAT,
121+
invoice_annotations=InvoiceAnnotations(),
122+
invoice_rows=InvoiceRows(rows=[
123+
InvoiceRow(
124+
name="Hosting service",
125+
unit_of_measure="szt.",
126+
quantity=Decimal("1"),
127+
unit_net_price=Decimal("100.00"),
128+
net_value=Decimal("100.00"),
129+
tax=23,
130+
delivery_date=date(2026, 3, 25),
131+
),
132+
]),
133+
),
134+
)
135+
```
136+
137+
### Recipient identification types
138+
139+
The library supports all KSeF recipient identification methods:
140+
141+
```python
142+
from ksef.models.invoice import (
143+
NipIdentification, # Polish NIP
144+
EuVatIdentification, # EU VAT number
145+
ForeignIdentification, # Non-EU tax ID
146+
NoIdentification, # No tax ID (individuals)
147+
)
148+
149+
# Polish company
150+
id_pl = NipIdentification(nip="1234567890")
151+
152+
# EU company
153+
id_eu = EuVatIdentification(eu_country_code="DE", eu_vat_number="123456789")
154+
155+
# Non-EU company
156+
id_foreign = ForeignIdentification(country_code="US", tax_id="12-3456789")
157+
158+
# Individual (no tax ID)
159+
id_none = NoIdentification()
160+
```
161+
162+
### Tax rates
163+
164+
Invoice rows support all valid KSeF tax rates via the `tax` field, plus OSS/IOSS rates via `tax_oss`:
165+
166+
```python
167+
from ksef.models.invoice_rows import (
168+
InvoiceRow,
169+
# Standard rates
170+
TAX_23, TAX_22, TAX_8, TAX_7, TAX_5, TAX_4, TAX_3,
171+
# Zero rates
172+
TAX_0_KR, # 0% domestic
173+
TAX_0_WDT, # 0% intra-Community supply
174+
TAX_0_EX, # 0% export
175+
# Special rates
176+
TAX_ZW, # exempt from tax
177+
TAX_OO, # reverse charge
178+
TAX_NP_I, # not subject to taxation
179+
TAX_NP_II, # not subject (art. 100)
180+
)
181+
182+
# Standard 23% rate
183+
row = InvoiceRow(name="Service", tax=TAX_23)
184+
185+
# Intra-Community supply at 0%
186+
row = InvoiceRow(name="Goods to EU", tax=TAX_0_WDT)
187+
188+
# OSS rate for EU consumer (e.g. 21% Belgian VAT)
189+
row = InvoiceRow(name="Digital service", tax_oss=Decimal("21"))
190+
```
191+
192+
### Tax summary (P_13/P_14 fields)
193+
194+
For KSeF to display Netto/VAT totals, provide a `TaxSummary` on `InvoiceData`:
195+
196+
```python
197+
from ksef.models.invoice import TaxSummary
198+
199+
tax_summary = TaxSummary(
200+
net_standard=Decimal("100.00"), # P_13_1 — net at 23%/22%
201+
vat_standard=Decimal("23.00"), # P_14_1 — VAT at 23%/22%
202+
)
203+
```
204+
205+
Available fields:
206+
207+
| Fields | Rate | XML |
208+
|--------|------|-----|
209+
| `net_standard` / `vat_standard` | 23% or 22% | P_13_1 / P_14_1 |
210+
| `net_reduced_1` / `vat_reduced_1` | 8% or 7% | P_13_2 / P_14_2 |
211+
| `net_reduced_2` / `vat_reduced_2` | 5% | P_13_3 / P_14_3 |
212+
| `net_flat_rate` / `vat_flat_rate` | 4% or 3% | P_13_4 / P_14_4 |
213+
| `net_oss` / `vat_oss` | OSS/IOSS | P_13_5 / P_14_5 |
214+
| `net_zero_domestic` | 0% domestic | P_13_6_1 |
215+
| `net_zero_wdt` | 0% intra-Community | P_13_6_2 |
216+
| `net_zero_export` | 0% export | P_13_6_3 |
217+
| `net_exempt` | exempt (zw) | P_13_7 |
218+
| `net_not_subject` | not subject (np I) | P_13_8 |
219+
| `net_not_subject_art100` | not subject (np II) | P_13_9 |
220+
| `net_reverse_charge` | reverse charge (oo) | P_13_10 |
221+
222+
For foreign currency invoices, use the `*_pln` fields to provide VAT converted to PLN:
223+
224+
```python
225+
TaxSummary(
226+
net_standard=Decimal("100.00"), # EUR
227+
vat_standard=Decimal("23.00"), # EUR
228+
vat_standard_pln=Decimal("98.31"), # P_14_1W — VAT in PLN
229+
)
230+
```
231+
232+
### Foreign currency invoices
233+
234+
For non-PLN invoices, set the exchange rate per row and add descriptions for the rate source:
235+
236+
```python
237+
from ksef.models.invoice import AdditionalDescription
238+
239+
row = InvoiceRow(
240+
name="Service",
241+
tax=23,
242+
unit_net_price=Decimal("100.00"),
243+
net_value=Decimal("100.00"),
244+
quantity=Decimal("1"),
245+
exchange_rate=Decimal("4.2867"), # KursWaluty per row
246+
)
247+
248+
# NBP rate source as a key-value note
249+
desc = AdditionalDescription(
250+
key="Kurs waluty",
251+
value="4.2867 PLN/EUR, tabela kursów średnich NBP nr 056/A/NBP/2026 z dnia 23.03.2026",
252+
)
253+
254+
invoice_data = InvoiceData(
255+
currency_code="EUR",
256+
additional_descriptions=[desc],
257+
# ...
258+
)
259+
```
260+
261+
### Additional recipients (Podmiot3)
262+
263+
For invoices with a third party (e.g. a government receiver/school when the buyer is a city hall):
264+
265+
```python
266+
from ksef.models.invoice import (
267+
AdditionalRecipient,
268+
ROLE_RECEIVER, # 2 — internal unit/branch of the buyer
269+
ROLE_JST_RECEIVER, # 8 — government unit receiver
270+
ROLE_FAKTOR, # 1 — factoring entity
271+
ROLE_ADDITIONAL_BUYER, # 4 — additional buyer
272+
)
273+
274+
receiver = AdditionalRecipient(
275+
identification_data=NipIdentification(nip="9876543210"),
276+
name="Szkoła Podstawowa nr 1",
277+
address=Address(
278+
country_code="PL",
279+
city="Tarnów",
280+
street="Słoneczna",
281+
house_number="15",
282+
postal_code="33-100",
283+
),
284+
role=ROLE_RECEIVER,
285+
)
286+
287+
invoice = Invoice(
288+
issuer=issuer,
289+
recipient=buyer,
290+
additional_recipients=[receiver],
291+
invoice_data=invoice_data,
292+
)
293+
```
294+
295+
### Sending an invoice
296+
297+
```python
298+
from ksef.xml_converters import convert_invoice_to_xml
299+
300+
# Convert to XML and send
301+
result = client.send_invoice(invoice)
302+
print(result.reference_number)
303+
print(result.session_reference_number)
304+
305+
# Check status later
306+
status = client.get_invoice_status(
307+
session_reference_number=result.session_reference_number,
308+
reference_number=result.reference_number,
309+
)
310+
print(status.status.code) # 200 = accepted
311+
print(status.ksef_number) # e.g. "1234567890-20260325-ABCDEF-01"
312+
```
313+
67314
## Integration Tests
68315

69316
Integration tests connect to the live KSEF test environment using real credentials. They are excluded from the default test run and must be invoked explicitly:

0 commit comments

Comments
 (0)