CoolCMS API

InvoiceTaxManager
in package

FinalYes

Applies VAT of a manually issued invoice from the unified tax engine.

Counterpart of OrderTaxManager for Invoicer: the only place where a manual invoice (admin form, invoice template, scheduler, InvoiceComposer and Company through it) learns anything about VAT. TaxManager decides the rate, treatment code, clause and summary report code; this class only maps them to invoice lines and the header snapshot (invoices.tax_*). Consumers then just read the snapshot.

An invoice created from a payment does not belong here: it copies the snapshot from the payment (InvoiceGenerator::applyTaxTreatment()), so the invoice shows what the customer saw at payment. Call this manager only where the invoice originates and the treatment is still undecided.

Contract:

  1. Nothing is saved. Only the passed (unsaved or just edited) entity changes; totals are recomputed by InvoiceCalculator in beforeSave().
  2. Backward compatible. An invoice with no line that has a supply kind, and no manual override, does not call the engine: apply() returns false and the rates stay as the caller sent them. The same happens when the engine returns no usable answer (missing seller status for the date, rate or supply kind).
  3. A manual override wins. InvoiceTaxOverride replaces the code and rate of all lines with a supply kind, the invoice gets the MANUAL_OVERRIDE flag and the reason in tax_override_reason. The DOMESTIC_REVERSE_CHARGE code arises only this way.
  4. The clause is written in the invoice language plus Czech (DocumentLocale::taxNote()), not in the page language.

IMPORTANT: TaxManager reads the code lists with raw DBAL, so it is safe to call in the middle of building an invoice object graph; a find() here would run UoW::clear() and break the graph.

Table of Contents

Constants

MONEY_SCALE  : int = 3
Scale of the Invoicer money columns (`decimal(10,3)`).

Properties

$languageManager  : LanguageManager
$supplyKindManager  : SupplyKindManager
$taxManager  : TaxManager
$translator  : Translator

Methods

__construct()  : mixed
apply()  : bool
Determines VAT of the whole invoice and writes it to the entity: rate and supply kind on the lines, header `use_vat` (derived from `chargeVat`) and the tax snapshot.
displayRate()  : string
Returns the rate for display and for prefilling a line in the admin: an anonymous consumer in the country of the invoice's payment region. An unknown supply kind or a seller without status gives `'0.00'` (never a silent default).
resolve()  : TaxResolution|null
Returns the treatment of the invoice on the tax point date; `null` when the engine is not called (no line has a supply kind) or gave no usable answer. Callers may request the resolution on its own (admin preview).
applyHeader()  : void
Writes the header snapshot: treatment code, date and country of the rate, clause, VAT id verification, flags and summary report code. `use_vat` is only derived from `chargeVat`; the calculator and the PDF read it.
applyLines()  : void
Writes the rates and the `use_vat` flag of the lines. A line without a supply kind (rounding, a hand-written item of an old invoice) is unknown to the engine: it keeps its rate, but the header silences it anyway when no tax is charged (the calculator uses `useVat && line.useVat`).
applyOverrideOnly()  : bool
Applies a manual override when the engine gave no usable answer (invoice without supply kinds, seller without status): the admin said explicitly how to tax the invoice, so the choice holds anyway. The snapshot then carries only what is certain (code, rate, date and reason); the country of the rate stays empty.
buildContext()  : TaxContext
Builds the customer context for the engine: ISO country from the invoice snapshot (empty means the engine derives it from the payment region and sets `COUNTRY_ASSUMED`), VAT id, company id and business nature.
buildLines()  : array<int, TaxLine>
Builds the engine lines: invoice items that have a supply kind, base after discount times quantity. The order matches the order of such items on the invoice (`applyLines()` walks the same loop), so results map back by index.
isUsable()  : bool
itemBase()  : string
Line base after discount times quantity; the same values `InvoiceCalculator` uses.
money()  : numeric-string
Returns a decimal column value for bcmath; non-numeric or empty counts as zero.
normalizeCountryCode()  : string|null
Normalizes to an uppercase ISO2 code; empty or invalid gives `null` (the engine derives the country itself).
normalizeDate()  : DateTimeImmutable
rateOf()  : string
Rate of the treatment for the snapshot: `0.00` when no tax is charged (or the engine returned no line).
summaryReportCode()  : string|null
Returns the summary report code for a manual override: `3` for services with reverse charge, `0` for goods supplied to the EU. Other codes are not reported; domestic reverse charge goes to a separate ledger, not to the summary report.
translateNote()  : string|null
Translates the VAT clause into the invoice language plus Czech; `null` when the code has no clause (domestic).

Constants

MONEY_SCALE

Scale of the Invoicer money columns (`decimal(10,3)`).

private int MONEY_SCALE = 3

Properties

Methods

apply()

Determines VAT of the whole invoice and writes it to the entity: rate and supply kind on the lines, header `use_vat` (derived from `chargeVat`) and the tax snapshot.

public apply(Invoice $invoice, int $sellerId[, DateTimeInterface|null $taxDate = null ][, InvoiceTaxOverride|null $override = null ][, string|null $supplyPlaceCountryCode = null ][, bool|null $customerIsBusiness = null ]) : bool
Parameters
$invoice : Invoice
$sellerId : int
$taxDate : DateTimeInterface|null = null
$override : InvoiceTaxOverride|null = null
$supplyPlaceCountryCode : string|null = null

ISO2 country of the property; read only for the immovable_service nature

$customerIsBusiness : bool|null = null

null derives it from the customer's company and VAT ids on the invoice

Return values
bool —

true when the snapshot was written; false when the engine was not called or gave no usable answer and the invoice stayed unchanged

displayRate()

Returns the rate for display and for prefilling a line in the admin: an anonymous consumer in the country of the invoice's payment region. An unknown supply kind or a seller without status gives `'0.00'` (never a silent default).

public displayRate(int $sellerId, int|null $paymentRegionId, int|null $supplyKindId[, DateTimeInterface|null $at = null ]) : string
Parameters
$sellerId : int
$paymentRegionId : int|null
$supplyKindId : int|null
$at : DateTimeInterface|null = null
Return values
string

resolve()

Returns the treatment of the invoice on the tax point date; `null` when the engine is not called (no line has a supply kind) or gave no usable answer. Callers may request the resolution on its own (admin preview).

public resolve(Invoice $invoice, int $sellerId[, DateTimeInterface|null $taxDate = null ][, string|null $supplyPlaceCountryCode = null ][, bool|null $customerIsBusiness = null ]) : TaxResolution|null
Parameters
$invoice : Invoice
$sellerId : int
$taxDate : DateTimeInterface|null = null
$supplyPlaceCountryCode : string|null = null
$customerIsBusiness : bool|null = null
Return values
TaxResolution|null

applyHeader()

Writes the header snapshot: treatment code, date and country of the rate, clause, VAT id verification, flags and summary report code. `use_vat` is only derived from `chargeVat`; the calculator and the PDF read it.

private applyHeader(Invoice $invoice, TaxResolution $resolution, int $sellerId, DateTimeImmutable $date, InvoiceTaxOverride|null $override) : void
Parameters
$invoice : Invoice
$resolution : TaxResolution
$sellerId : int
$date : DateTimeImmutable
$override : InvoiceTaxOverride|null

applyLines()

Writes the rates and the `use_vat` flag of the lines. A line without a supply kind (rounding, a hand-written item of an old invoice) is unknown to the engine: it keeps its rate, but the header silences it anyway when no tax is charged (the calculator uses `useVat && line.useVat`).

private applyLines(Invoice $invoice, TaxResolution $resolution, InvoiceTaxOverride|null $override) : void
Parameters
$invoice : Invoice
$resolution : TaxResolution
$override : InvoiceTaxOverride|null

applyOverrideOnly()

Applies a manual override when the engine gave no usable answer (invoice without supply kinds, seller without status): the admin said explicitly how to tax the invoice, so the choice holds anyway. The snapshot then carries only what is certain (code, rate, date and reason); the country of the rate stays empty.

private applyOverrideOnly(Invoice $invoice, int $sellerId, DateTimeImmutable $date, InvoiceTaxOverride $override) : bool
Parameters
$invoice : Invoice
$sellerId : int
$date : DateTimeImmutable
$override : InvoiceTaxOverride
Return values
bool

buildContext()

Builds the customer context for the engine: ISO country from the invoice snapshot (empty means the engine derives it from the payment region and sets `COUNTRY_ASSUMED`), VAT id, company id and business nature.

private buildContext(Invoice $invoice, int $sellerId, DateTimeImmutable $date, string|null $supplyPlaceCountryCode, bool|null $customerIsBusiness) : TaxContext

VatIdPolicy::CacheOnly is deliberate: a manual invoice is issued in the admin, where VAT id verification is a separate button. Saving the invoice must not depend on VIES availability.

Parameters
$invoice : Invoice
$sellerId : int
$date : DateTimeImmutable
$supplyPlaceCountryCode : string|null
$customerIsBusiness : bool|null
Return values
TaxContext

buildLines()

Builds the engine lines: invoice items that have a supply kind, base after discount times quantity. The order matches the order of such items on the invoice (`applyLines()` walks the same loop), so results map back by index.

private buildLines(Invoice $invoice) : array<int, TaxLine>
Parameters
$invoice : Invoice
Return values
array<int, TaxLine>

itemBase()

Line base after discount times quantity; the same values `InvoiceCalculator` uses.

private itemBase(InvoiceItem $item) : string
Parameters
$item : InvoiceItem
Return values
string

money()

Returns a decimal column value for bcmath; non-numeric or empty counts as zero.

private money(string $value) : numeric-string
Parameters
$value : string
Return values
numeric-string

normalizeCountryCode()

Normalizes to an uppercase ISO2 code; empty or invalid gives `null` (the engine derives the country itself).

private normalizeCountryCode(string|null $countryCode) : string|null
Parameters
$countryCode : string|null
Return values
string|null

normalizeDate()

private normalizeDate(DateTimeInterface|null $date) : DateTimeImmutable
Parameters
$date : DateTimeInterface|null
Return values
DateTimeImmutable

rateOf()

Rate of the treatment for the snapshot: `0.00` when no tax is charged (or the engine returned no line).

private rateOf(TaxTreatment|null $treatment) : string
Parameters
$treatment : TaxTreatment|null
Return values
string

summaryReportCode()

Returns the summary report code for a manual override: `3` for services with reverse charge, `0` for goods supplied to the EU. Other codes are not reported; domestic reverse charge goes to a separate ledger, not to the summary report.

private summaryReportCode(TaxTreatmentCode $code) : string|null
Parameters
$code : TaxTreatmentCode
Return values
string|null

translateNote()

Translates the VAT clause into the invoice language plus Czech; `null` when the code has no clause (domestic).

private translateNote(Invoice $invoice, string|null $noteKey) : string|null
Parameters
$invoice : Invoice
$noteKey : string|null
Return values
string|null
On this page

Search results