Skip to content

Developer notes

  1. Number and date: Invoices & Credit Notes (Tygh\Addons\KvInvoiceBuilder\Issuer::issueInvoice() when the order has no invoice yet) or the add-on’s own series (kv_einv_counters, counter row locked with SELECT ... FOR UPDATE, retried on deadlocks; a rolled back transaction never consumes a number).
  2. Model: Model\Builder::invoice() reads fn_get_order_info() and builds the EN 16931 semantic model (array): seller (seller data with company fallback), buyer (billing address, profile fields, EU VAT Number Validation row), delivery (shipping address, first shipment date or the issue date), lines, allowances and charges, payment instructions. Model\Calculator::finish() adds the VAT breakdown per category and rate (tax = taxable amount × rate, rounded to 2 decimals) and the totals; the difference to the charged order total becomes a rounding amount (BT-114) or, above 1.00, a prepaid amount (gift certificates).
  3. Freeze + check: the model is stored as JSON in kv_einv_documents.data; Validator::all() stores the check per format in checks.
  4. Files on demand: Formats::render($model, $format) adapts the model to the format (electronic addresses, contact point) and writes it: Format\Ubl (Peppol BIS 3.0 / XRechnung UBL, Invoice and CreditNote), Format\Cii (XRechnung CII / Factur-X), Pdf\FacturX (PDF/A-3b with factur-x.xml, AFRelationship Alternative).

Order lines are matched to taxes through order.taxes[tax_id].applies: P_<item_id> (tax per unit price) or items.P[<item_id>] (tax on the subtotal); shipping through S_<group>_<shipping_id> / items.S, the payment surcharge through PS_* / items.PS. Rates of several taxes on one line are added up (with a warning); fixed-amount taxes are left out (warning). Prices that include tax are turned into net amounts with the stored tax of the line, or by the rate when the tax was calculated on the subtotal. Order discounts are split over the VAT groups in proportion to their gross value.

Plain PHP, no library: Pdf\Document writes PDF 1.7 objects with Type0 / CIDFontType2 fonts (Identity-H, ToUnicode), XMP metadata (pdfaid part 3, conformance B, the Factur-X extension schema), an sRGB output intent with an ICC profile generated by Pdf\Icc, and the embedded file. Pdf\TrueType reads the bundled Noto Sans fonts (SIL Open Font License, resources/fonts/OFL.txt, Latin, Greek and Cyrillic) and embeds only the glyphs used. Pdf\Layout draws the A4 page; labels are language variables kv_eu_e_invoicing.pdf_*.

The add-on ships no access point account. A driver is any class implementing Tygh\Addons\KvEuEInvoicing\Peppol\TransportInterface, registered from your own add-on:

func.php
// init.php of your add-on
fn_register_hooks('kv_eu_e_invoicing_peppol_transports');
function fn_my_addon_kv_eu_e_invoicing_peppol_transports(&$transports)
{
$transports['my_ap'] = new \Tygh\Addons\MyAddon\AccessPoint();
}
class AccessPoint implements \Tygh\Addons\KvEuEInvoicing\Peppol\TransportInterface
{
public function getName() { return 'My access point'; }
public function isConfigured() { return (bool) $this->apiKey(); }
public function send($xml, array $document)
{
// $xml: Peppol BIS Billing 3.0 UBL Invoice or CreditNote
// $document: doc_id, doc_type (I|C), number, order_id, company_id, seller_id, buyer, buyer_vat,
// data (the EN 16931 model; data.buyer.endpoint / endpoint_scheme = receiver)
// POST it to your access point here.
return ['ok' => true, 'message_id' => 'AP-12345', 'error' => ''];
}
}

The driver then appears in Send e-invoices with. Sending is refused while the license is not valid or the Peppol check of the document has errors. The result is stored in peppol_status (S sent, E error), peppol_ref, peppol_error, peppol_at.

Hook Arguments Use
kv_eu_e_invoicing_peppol_transports &$transports (id => TransportInterface) Register Peppol drivers
use Tygh\Addons\KvEuEInvoicing\Documents;
use Tygh\Addons\KvEuEInvoicing\Issuer;
use Tygh\Addons\KvEuEInvoicing\Output;
$doc = Documents::invoiceForOrder($order_id); // or Issuer::issueInvoice($order_id, 'manual')['doc']
$file = Output::file($doc, 'xrechnung_cii'); // facturx | xrechnung_cii | xrechnung_ubl | peppol
// $file = ['content' => ..., 'filename' => 'INV-2026-00042-xrechnung-cii.xml', 'mime' => 'application/xml']
Table Contents
kv_einv_documents doc_id, doc_type (I/C), order_id, company_id, seller_id, number, issue_date, issued_at, invoice_id (credit note → invoice), ib_doc_id (Invoices & Credit Notes document), source, source_key (unique, idempotency), series_key + seq_no (own numbers), currency, total (amount due), with_vat, tax_total, buyer, buyer_vat, buyer_ref, email, user_id, status (check of the main format), checks (JSON), peppol_status / ref / error / at, data (JSON model), order_deleted
kv_einv_counters series_key (`I
kv_einv_sellers company_id (0 = store / marketplace, storefront, vendor) + seller data fields
kv_einv_maps map_type (tax, payment), map_key (tax_id, payment_id), value (category / means code), extra (exemption text)
kv_einv_products product_id, unit_code

Documents are never deleted while the add-on is installed. When an order is deleted, its documents are kept and flagged order_deleted.

PHP: change_order_status (create e-invoices, own credit notes, pick up Invoices & Credit Notes credit notes), mailer_send_pre (attachment), delete_order, update_product_post / delete_product_post (unit), delete_company (seller data), rma_update_details_post (credit notes of returns), kv_invoice_builder_document_issued (Invoices & Credit Notes 1.0.1+: e-credit note at once for every credit note issued there). All exist with the same arguments in 4.17.2 and 4.21.2. The add-on priority is 1100, so Invoices & Credit Notes (1000) has issued its number first in shared hooks.

Templates: admin orders:tabs_extra (post), orders:details_tools (post), products:update_product_amount (post), index:styles; storefront orders:details_tools (post), index:styles. Context menu: orders (Print documents → e-Invoices (ZIP)).

Nothing is printed on cacheable storefront pages. Customer links are on the session-bound order page; downloads are sent with Cache-Control: private, no-store.

Add-on Integration
Invoices & Credit Notes Numbers, dates and credit notes (read through its public classes; when it is not active, own numbering). Its per-vendor numbering makes vendors the sellers (Multi-Vendor, automatic mode).
EU VAT Number Validation Buyer VAT ID and reverse-charge decision from kv_vat_orders; store VAT number as the seller VAT fallback.
Sell by Weight & Length Measured quantity (extra.kv_fq.qty / 10000) and unit (kg → KGM, m → MTR, l → LTR …).
app/addons/kv_eu_e_invoicing/
addon.xml, init.php, func.php
controllers/backend/kv_eu_e_invoicing.php list, document page, downloads, ZIP, issue, rebuild, credit, send, seller data, mapping
controllers/backend/orders.post.php order page tab
controllers/backend/products.post.php unit field data
controllers/frontend/kv_eu_e_invoicing.php customer download
controllers/frontend/orders.post.php customer order page links
resources/fonts/ Noto Sans Regular/Bold (subset) + OFL.txt
schemas/ context_menu, menu, permissions, settings
Tygh/Addons/KvEuEInvoicing/
Config, Codes, Lang, Sellers, Maps, Buyer, InvoiceBuilder, Series, Documents, Issuer, Validator, Formats, Output,
Access, Hooks, View, Model/{Builder,Calculator}, Format/{Xml,Ubl,Cii}, Pdf/{Document,TrueType,Icc,Layout,FacturX},
Peppol/{TransportInterface,Transports}, License/*, Upgrade/Synchronizer
design/backend/templates/addons/kv_eu_e_invoicing/ views, components, hooks, settings, license
design/backend/css/addons/kv_eu_e_invoicing/styles.less
design/backend/media/images/addons/kv_eu_e_invoicing/icon.png
var/themes_repository/responsive/templates/addons/kv_eu_e_invoicing/hooks
var/themes_repository/responsive/css/addons/kv_eu_e_invoicing/styles.less
var/langs/en/addons/kv_eu_e_invoicing.po

The license client is Tygh\Addons\KvEuEInvoicing\License\Client (isActive()); the gate is Config::canIssue() (enabled and licensed). Gated: creating, rebuilding and crediting documents, e-mail attachments, Peppol sending. Not gated: lists, document pages, downloads (admin, vendor, customer).