Problem / Context
The neutral invoicing command carries a currency:
// libs/core/src/invoicing/domain/types/invoicing.types.ts:486
currency: string; // ISO 4217, single-currency invoice
The inFakt request type does not have a currency field at all:
// libs/integrations/infakt/src/domain/types/infakt.types.ts:50-81
export interface InfaktInvoice { … } // no currency / kurs field
and infakt-invoicing.adapter.ts contains zero references to .currency — the string "currency" appears only inside comments about the groszy integer format (:232, :425, :686).
So command.currency is silently dropped. Amounts are sent as plain integers in the minor unit with no currency attached, and inFakt books them in the account's default currency (PLN). A EUR 811.37 invoice is issued as PLN 811.37.
Two things make this worse than an ordinary mapping gap:
- It is silent. No log, no validation, no
business_failure. Nothing distinguishes it from a correct issuance.
- It propagates. inFakt relays to KSeF on the seller's behalf (see the Invoicing section of
docs/architecture-overview.md), so an incorrect fiscal document clears the tax authority. A cleared document is not something OL can quietly re-issue.
Surfaced while reviewing #2050 / ADR-040, whose Non-goals section draws a hard line around fiscal currency handling. Independent of that PR.
Proposed Solution
- Establish the contract. Determine from inFakt's API documentation how a document declares its currency — most likely an invoice-level currency field plus an optional rate, given that inFakt performs its own conversion server-side. Record the finding in the issue with a doc reference, since the current absence may be a genuine API limitation rather than an OL oversight.
- If inFakt supports it — add the field to
InfaktInvoice and map command.currency onto it. Verify against the sandbox that the issued document actually renders in that currency.
- If inFakt does not support it — reject issuance for any currency other than the account's default with a terminal
business_failure and an explicit reason, rather than booking in the wrong units. A refused document is recoverable; a cleared wrong one is not.
- Cover the sibling write paths —
issueCorrection and markPaid go through the same async task endpoints and need the same treatment.
Run the same audit against the Subiekt nexo adapter (libs/integrations/subiekt/), which implements the same InvoicingPort. If it has the same gap, file it separately rather than widening this issue.
Classification
Type: Integration
Layer: Infrastructure
File(s):
libs/integrations/infakt/src/infrastructure/adapters/infakt-invoicing.adapter.ts
libs/integrations/infakt/src/domain/types/infakt.types.ts:50-81
Dependencies
Assumptions
- Shipped inFakt accounts are PLN-denominated and every order exercised in testing so far was PLN, which is why the gap has not surfaced in practice.
IssueInvoiceCommand.currency is populated correctly upstream (it is echoed from the order), so the defect is confined to the adapter boundary.
Acceptance Criteria
Problem / Context
The neutral invoicing command carries a currency:
The inFakt request type does not have a currency field at all:
and
infakt-invoicing.adapter.tscontains zero references to.currency— the string "currency" appears only inside comments about the groszy integer format (:232,:425,:686).So
command.currencyis silently dropped. Amounts are sent as plain integers in the minor unit with no currency attached, and inFakt books them in the account's default currency (PLN). A EUR 811.37 invoice is issued as PLN 811.37.Two things make this worse than an ordinary mapping gap:
business_failure. Nothing distinguishes it from a correct issuance.docs/architecture-overview.md), so an incorrect fiscal document clears the tax authority. A cleared document is not something OL can quietly re-issue.Surfaced while reviewing #2050 / ADR-040, whose Non-goals section draws a hard line around fiscal currency handling. Independent of that PR.
Proposed Solution
InfaktInvoiceand mapcommand.currencyonto it. Verify against the sandbox that the issued document actually renders in that currency.business_failureand an explicit reason, rather than booking in the wrong units. A refused document is recoverable; a cleared wrong one is not.issueCorrectionandmarkPaidgo through the same async task endpoints and need the same treatment.Run the same audit against the Subiekt nexo adapter (
libs/integrations/subiekt/), which implements the sameInvoicingPort. If it has the same gap, file it separately rather than widening this issue.Classification
Type: Integration
Layer: Infrastructure
File(s):
libs/integrations/infakt/src/infrastructure/adapters/infakt-invoicing.adapter.tslibs/integrations/infakt/src/domain/types/infakt.types.ts:50-81Dependencies
Assumptions
IssueInvoiceCommand.currencyis populated correctly upstream (it is echoed from the order), so the defect is confined to the adapter boundary.Acceptance Criteria
command.currencyreaches the request and the issued sandbox document renders in that currencyissueCorrectionandmarkPaidare covered by the same behaviour