Developed by Fayna Digital for CampScout Author: Volodymyr Shevchenko
Professional integration between Odoo 17 Community and the Polish National e-Invoicing System (KSeF 2.0).
Built specifically to support VAT Marża (tourist margin scheme) — a procedure critical for travel agencies in Poland, missing from standard EDI solutions.
- KSeF 2.0 API — full compliance with the latest Polish e-invoicing standard
- FA(3) XML — generates structured invoices per schema
http://crd.gov.pl/wzor/2025/06/25/13775/ - VAT Marża — automatic detection and tagging (
P_PMarzy+P_PMarzy_3_3for travel agencies) - Secure Auth — RSA-OAEP token encryption + AES-256-CBC invoice encryption via
ksef-clientSDK - Outbound — send customer invoices to KSeF directly from Odoo invoice form
- Inbound Buffer — sync incoming vendor invoices from KSeF into an isolated buffer (no accounting clutter)
- Test & Production environments configurable per company
l10n_pl_ksef_margin/
├── models/
│ ├── account_move.py # Outbound: FA(3) XML generation + KSeF send
│ ├── ksef_vendor_buffer.py # Inbound: sync & buffer for vendor invoices
│ └── res_company.py # Company fields: KSeF token + environment
├── views/
│ ├── account_move_views.xml # KSeF tab on invoice form
│ └── ksef_vendor_buffer_views.xml # Tree/form + menu + sync action
└── security/
└── ir.model.access.csv
| Component | Technology |
|---|---|
| ERP Framework | Odoo 17.0 Community |
| KSeF API | KSeF 2.0 (api-test.ksef.mf.gov.pl, api.ksef.mf.gov.pl) |
| Python SDK | ksef-client 0.8.0 |
| Encryption | RSA-OAEP (auth) + AES-256-CBC (invoice) — automatic |
| Invoice Schema | FA(3) — crd.gov.pl/wzor/2025/06/25/13775 |
| VAT Margin | P_PMarzy + P_PMarzy_3_3 (biura podróży) |
pip install ksef-clientNote:
ksef-clientinstallscryptography 46.x. If you have an older Odoo stack, upgrade dependencies first:pip install --upgrade pyOpenSSL urllib3 requests
# Clone the repository
git clone https://github.com/VladSh77/odoo17-l10n_pl_ksef_margin.git /opt/odoo/addons/odoo17-l10n_pl_ksef_marginAdd to odoo.conf:
addons_path = ...,/opt/odoo/addons/odoo17-l10n_pl_ksef_marginApps → Update Apps List → search ksef → Install
docker restart <odoo_container_name>
# or
systemctl restart odoo- Go to ksef.mf.gov.pl (or ksef-test.mf.gov.pl for testing)
- Log in with Profil Zaufany or qualified electronic signature
- Navigate to Tokeny → Generuj token
- Select required permissions:
wystawianie faktur(InvoiceWrite) — for sending invoicesprzeglądanie faktur(InvoiceRead) — for syncing incoming invoices
- Copy the generated token
Settings → Companies → [your company] → General Information
| Field | Value |
|---|---|
| KSeF API Token | paste token from ksef.mf.gov.pl |
| KSeF Environment | Test or Production |
- Accounting → Invoices — open a posted customer invoice
- Go to tab KSeF
- Click Wyślij do KSeF
- Status changes:
Not Sent→Waiting→Accepted - KSeF Reference Number (
KSeF ID) is saved on the invoice
- Accounting → KSeF → Faktury Przychodzące
- Click Synchronizuj z KSeF
- New vendor invoices from KSeF appear in the buffer list
- Review and process as needed (buffer is isolated — does not affect accounting until manually processed)
For invoices with the margin scheme (travel agencies, tourist services):
- The module detects margin-type tax lines automatically
- Adds
<P_PMarzy>1</P_PMarzy>to the FA(3) XML - For travel agencies (biura podróży): also adds
<P_PMarzy_3_3>1</P_PMarzy_3_3> - These flags are required by KSeF for correct classification under Art. 119 of the VAT Act
1. GET /auth/challenge/{nip} → challenge token
2. Encrypt: RSA-OAEP(token|timestamp, KSeF_public_key)
3. POST /auth/initialise → session reference
4. GET /auth/status/{reference} → poll until Authorised
5. GET /auth/token/{reference} → redeem accessToken
All handled automatically by ksef-client SDK via AuthCoordinator.authenticate_with_ksef_token().
1. GET /common/publicKey → fetch KSeF RSA public certificate
2. POST /online/Session/InitUpload → open session (AES-256-CBC key encrypted with RSA)
3. POST /online/Invoice/Send → send AES-encrypted FA(3) XML invoice
4. POST /online/Session/Terminate → close session
All handled automatically by OnlineSessionWorkflow.
# Clone and start
git clone https://github.com/VladSh77/odoo17-l10n_pl_ksef_margin.git
cd odoo17-l10n_pl_ksef_margin
docker-compose up
# Open http://localhost:8070
# Install ksef-client inside container:
docker exec -u root <container_id> pip install ksef-client
# Restart to apply
docker restart <container_id>Then in Odoo: Apps → Update Apps List → search ksef → Install
| Error | Cause | Fix |
|---|---|---|
ValueError: Wrong value for ir.module.module.license |
Old Odoo cached manifest | docker restart <odoo_container> then Update Apps List |
AttributeError: module 'cryptography.utils' has no attribute 'Buffer' |
pyksef incompatible with cryptography≥42 |
Module uses ksef-client instead — ensure no old pyksef installed |
ImportError: lxml.html.clean |
lxml 6.x installed |
Rebuild container: docker-compose down && docker-compose up |
500 Internal Server Error after pip install ksef-client |
cryptography 46.x breaks pyOpenSSL 21 | pip install --upgrade pyOpenSSL urllib3 requests |
ParseError: attrs not used since 17.0 |
Views written for Odoo 16 syntax | Use invisible="..." instead of attrs="{'invisible':...}" |
| Module not visible in Apps | addons_path not configured | Add module path to odoo.conf → addons_path |
To give an accountant access to KSeF features:
- Settings → Users → [accountant user]
- Ensure role: Accounting / Accountant (or higher)
- The KSeF menu (Faktury Przychodzące) and KSeF tab on invoices are visible to all users with Accounting access
- Only users with Accounting / Administrator can modify KSeF token settings
Apache 2.0 — see LICENSE
Developed by Fayna Digital · Volodymyr Shevchenko