Developer notes
Technical reference for developers who customize Fakturownia Invoicing for CS-Cart.
Add-on identity
Section titled “Add-on identity”| Item | Value |
|---|---|
| Add-on id | kv_fakturownia |
| Function prefix | fn_kv_fakturownia_ |
| Language variables | kv_fakturownia.* |
| CSS scope | .kv-fakturownia |
| PHP namespace | Tygh\Addons\KvFakturownia |
| Preset | accounting (generated by kv new --kind integration), OAuth part replaced by API token authentication |
Structure
Section titled “Structure”| Class | Role |
|---|---|
Client\BaseClient |
HTTP (cURL, TLS verification, timeouts), JSON, error mapping, masked logging |
Client\Api |
All Fakturownia calls (below); the only place that knows paths and field names |
Client |
Client per company, the connection test |
Sync |
Pure builders (taxId, kind, lines, buyer, invoicePayload, correctionPayload) and the jobs syncInvoice, syncPayment, syncRefund, syncReturn, syncCustomer |
Docs |
Document of an order: number, PDF stream, merchant triggered e-mail, KSeF read-back |
Accounts, Secret |
Subdomain + API token (test and live), token sealed with AES-256-GCM; one account per store owner or per vendor |
Config, Access |
Settings, owner mode, who may see and manage what |
Queue, Jobs, JobException |
Job queue: back-off 5 min / 15 min / 1 h / 3 h / 12 h, per-job isolation, overlap lock; job types sync_invoice, sync_payment, sync_refund, sync_return |
Log |
Event log with masking (the api_token is masked), filters, CSV, retention |
Database tables
Section titled “Database tables”| Table | Purpose |
|---|---|
?:kv_fakturownia_accounts |
Subdomain (test_id / live_id) and sealed API token (test_secret / live_secret) per company, mapping in extra, last connection check |
?:kv_fakturownia_log |
Log |
?:kv_fakturownia_jobs |
Queue |
?:kv_fakturownia_map |
Per order: Fakturownia id, payload hash, meta (document number, kind, position to order item map, KSeF flag). Entities: customer, invoice, payment, refund, return |
Fakturownia API: endpoints and fields, with source
Section titled “Fakturownia API: endpoints and fields, with source”Sources: the official repository github.com/fakturownia/API (README.md, KSeF.md), read on 2026-11-07. “Flag” marks what the documentation does not state precisely; the add-on never relies on a guess for money, and each flag is covered by a test against the mock or a note below.
Base URL: https://<account>.fakturownia.pl (README: “https://twojaDomena.fakturownia.pl”). Authentication: the account’s API authorization code as api_token, “as the api_token query parameter or as a field in the JSON body” (README). Requests with a body send Content-Type: application/json; the document is wrapped in an object (invoice, client).
| Call | Used for | Documented fields and source |
|---|---|---|
GET /invoices.json?page=1&per_page=1 |
Connection test | page, per_page (max 100): README “list parameters” |
POST /invoices.json |
Receipt, VAT invoice, proforma | README “Invoices”: kind (vat, receipt, proforma, correction …), issue_date, sell_date, payment_to, payment_type (transfer, card, cash, cash_on_delivery, payu, paypal, off, or any text), currency, description, oid (order number from an external system), department_id (issuing department), client_id or buyer data, positions |
| buyer fields | Buyer on the document | buyer_name, buyer_tax_no, buyer_email, buyer_post_code, buyer_city, buyer_street, buyer_country (ISO 3166, “PL”), buyer_company: README “Invoices”; buyer_tax_no_kind = nip_ue for EU numbers: KSeF.md / README note “nip_ue, other, empty” |
| position fields | Lines | name, quantity, tax (rate, np, zw), total_price_gross: README. total_price_gross is the gross total of the line: the correction sample shows quantity 2 with 20, then quantity 1 with 10 |
oid_unique |
One document per order id | README: “setting oid_unique to yes blocks creating two invoices with the same OID”. Flag: the README names the field but not its exact place in the request; it is sent inside the invoice object. If it were ignored, the add-on still creates one document per order from its own map table |
POST /invoices.json?gov_save_and_send=1 |
Create and send to KSeF in one step | KSeF.md: “gov_save_and_send=1 in the query string, or gov_save_and_send: true in the JSON body”. Only when the merchant turns “Send VAT invoices to KSeF through Fakturownia” on |
| Correction | Refund / return | README “Corrections”: kind: correction, correction_reason, invoice_id, from_invoice_id, client_id, per position correction_before_attributes and correction_after_attributes (name, quantity, total_price_gross, tax, kind: correction_before / correction_after). The add-on reproduces the documented sample. Flag: the README shows a correction of a VAT invoice; corrections of a receipt are attempted the same way and a refusal is reported in the Jobs tab. client_id is taken from the original document when it has one |
GET /invoices/{id}.json |
Read the original document before a correction (positions, client_id) |
README “Invoices” |
GET /invoices/{id}.json?fields[invoice]=gov_status,gov_id,gov_error_messages |
KSeF status in the order tab | KSeF.md “Checking status” (gov_status, gov_id, gov_error_messages) |
POST /invoices/{id}/change_status.json?status=paid |
Paid status | README “Status”: status one of issued, sent, paid, partial, rejected |
GET /invoices/{id}.pdf?api_token=... |
PDF in the admin order tab and the customer account | README “PDF” (streamed through the store: the browser never sees the token) |
POST /invoices/{id}/send_by_email.json |
Merchant triggered e-mail | README: optional email_to, email_cc, email_pdf, update_buyer_email, print_option. Only email_to is sent. Flag: the README does not say whether the parameters go in the query or the body; they are sent in the query string. Called only by the admin button |
POST /clients.json, PUT /clients/{id}.json |
Client cards (optional) | README “Clients”: name, tax_no, email, post_code, city, street, country, company, external_id |
GET /departments.json |
Department chooser on the Mapping page | README “Departments”: id, name, shortcut, tax_no |
Not used, on purpose:
- Webhooks (
/webhooks.json): the README does not document the payload or a signature scheme, so there is no webhook endpoint (a signature check cannot be built on a guess). - Products (
/products.json), warehouses, payments (/banking/payments.json): the order lines carry the product name, so no product sync is needed; the paid status useschange_status. - Telephone number of the buyer: not in the documented buyer fields, so it is not sent.
- Rate limits and error codes other than the documented
422body ({"code": "error", "message": {"field": ["text"]}}): not documented;429and5xxare retried with the queue back-off,4xxare permanent and shown with the API’s message. - InvoiceOcean (the same software under another brand): the account field accepts
*.invoiceocean.comas well. Flag: the README is the Fakturownia one; that the same endpoints answer there is the product’s statement, not verified in this documentation.
How the order becomes a document
Section titled “How the order becomes a document”change_order_status_postqueuessync_invoice(status “Issue the document when the order status becomes”),sync_payment(status “Mark the document as paid …”) andsync_refund(status “Issue a correction …”). Parent orders of Multi-Vendor are skipped: the child orders carry the documents.Sync::taxId()reads the NIP / EU VAT number from the profile field (configured, or detected by its name), validates the NIP checksum. A buyer with a number gets the company document (vatorproforma), others the consumer document (receiptorvat).Sync::lines()builds the positions from the stored order: gross line total = price x quantity + added tax (taxes with “price includes tax” are not added again); shipping, order discount and payment fee are separate lines. Thetaxvalue comes from the Mapping page (CS-Cart tax id to Fakturownia value) or the percentage of the CS-Cart tax, else the default tax. Amounts are in the store’s primary currency, which is sent ascurrency.- The document is created once per order (map table,
oid_unique); an issued document is never rewritten. Retry safety (invoices and corrections): the object id (oid:<prefix><order>for an invoice,<prefix><order>-KRfor a whole-order correction,<prefix><order>-K<return id>for a return) is written to the map row with statusPBEFORE the POST. A retry after a timeout / 5xx / crash, or anoid422, first callsGET /invoices.json?oid=<oid>&period=all&order=updated_at.descand adopts the document whoseoidmatches exactly. Flag: the README documentsoidonly as a sort field and says list calls take the parameters of the application, so the filter is a hint; the client checks the exactoidin the newest 200 documents itself. If the document cannot be read back, the job stops with a message asking for a manual check instead of creating another one. Corrections are serialised per document with a database lock and remember the quantities already corrected in the invoice’s map meta (corrected,applied), so a refund after a return credits only the rest. Corrections of a document that went to KSeF carrygov_save_and_send(KSeF.md). Receipts are not corrected automatically (not documented: logged). Dates areEurope/Warsawcalendar days. The job logs a warning when the positions do not add up to the order total. sync_return(RMA add-on): on completion as a refund, a correction for the accepted items only (hookrma_update_details_post).
Hooks used
Section titled “Hooks used”| Hook | File | Purpose |
|---|---|---|
PHP change_order_status_post |
func.php |
Queue invoice, payment, correction jobs |
PHP rma_update_details_post |
func.php |
Queue the return correction (only fires when the RMA add-on is active) |
Admin template orders:tabs_extra (post) |
hooks/orders/tabs_extra.post.tpl |
“Fakturownia” tab: number, PDF, e-mail, KSeF status |
Storefront template orders:details_bullets (post) |
hooks/orders/details_bullets.post.tpl |
“Download invoice (PDF)” in the customer account |
Controllers orders.post.php (backend, frontend) |
controllers/ |
Assign the document data to the order pages |
The storefront output exists only on the customer’s order page (a session page that the full page cache does not serve) and on the kv_fakturownia.pdf / .cron endpoints.
Test the HTTP layer without the provider
Section titled “Test the HTTP layer without the provider”The base URL can be overridden for tests in config.local.php (development only):
$config['kv_fakturownia_base_url'] = 'http://127.0.0.1:11830';node tests/mock-server/server.js 11830 starts a local stand-in that follows the documentation (api_token required, 422 bodies in the documented shape, oid_unique, correction attributes, PDF, e-mail, KSeF fields); node tests/e2e/e2e.mjs --store cs417 runs the HTTP end-to-end test with real CS-Cart orders against it; php tests/unit.php runs the unit tests against the samples of the documentation.
Template overrides
Section titled “Template overrides”Admin templates live in design/backend/templates/addons/kv_fakturownia/. Do not edit them in a store; they are replaced on update.