TaxManager
in package
VAT engine orchestrator.
Manager-tier (no entity of its own): loads the seller profile on the tax date (SellerTaxProfileManager), countries, supply kind natures, rates and the VAT id verification, classifies the customer and asks TaxRuleTable, the only place with rules. It never persists anything except VIES evidence (through VatIdCheckManager) and never touches amounts except the gross split and the ancillary allocation (TaxAmountCalculator).
IMPORTANT: all reads are raw DBAL (no UoW::clear()), because consumers call it while building an
order / payment graph. Lookups are cached per request (rates per kind, country and day, natures, regions).
Consumers: the bridge api/system/tax/resolve (payment form), InvoiceGenerator (legacy
payments without a snapshot, rate on the payment date), InvoiceTaxManager (manual invoices) and the
e-shop (OrderTaxManager, ProductSetManager).
Table of Contents
Properties
- $countryManager : CountryManager
- $natures : array<int, SupplyNature|false>
- $paymentRegionManager : PaymentRegionManager
- $rates : array<string, numeric-string|null>
- $regionCountryCodes : array<int, string|null>
- $sellerTaxProfileManager : SellerTaxProfileManager
- $supplyKindManager : SupplyKindManager
- $taxAmountCalculator : TaxAmountCalculator
- $taxRuleTable : TaxRuleTable
- $vatIdCheckManager : VatIdCheckManager
- $vatRateManager : VatRateManager
Methods
- __construct() : mixed
- allocateAncillary() : array<int, TaxAncillaryShare>
- proportionally to their bases; the rounding remainder goes to the largest group.
- findNoteKey() : string|null
- Note key (`tax.note.<CODE>[.<status>]`) of a snapshotted treatment code: the invoice from a payment copies the code and re-translates the note in the document language. An unknown or `DOMESTIC` code gives null.
- rate() : numeric-string|null
- Rate of a supply kind in a country on a date ('21.00'); null means `RATE_MISSING` (never a default).
- resetCache() : void
- Drops request caches (long-running CLI after an admin change of rates / kinds).
- resolve() : TaxResolution
- resolveDisplay() : array<int, TaxTreatment>
- Catalog / detail display: anonymous consumer in the country of the display region (region without a country gives the seller country + `COUNTRY_ASSUMED`). Never calls VIES.
- sellerStatusAt() : SellerVatStatus|null
- verifyVatId() : VatIdVerification
- Verification outside a resolution (profile save, admin "verify in VIES" action).
- buildAmounts() : array{0: numeric-string, 1: numeric-string|null}
- buildHeader() : TaxTreatment|null
- Header = main supply (highest base, first on a tie), `chargeVat` = any line charges VAT, all flags.
- buildTreatment() : TaxTreatment
- classifyCustomer() : CustomerClass
- Customer class C. The VAT id is verified lazily: at most once per resolution and only when a line goes to another EU member state; its flags are collected in `$state`.
- findCountryOrPlaceholder() : TaxCountry
- findNatures() : array<int, SupplyNature>
- isEuB2cThresholdExceeded() : bool
- Hook: limit `EU_B2C_DISTANCE` of the seller (sum of the period + this document). Until the limits exist there is no active limit, so the result is no.
- mergeFlags() : array<int, TaxFlag>
- resolveCustomerCountry() : TaxCountry
- Customer country, then payment region country, then seller country; the fallbacks flag `COUNTRY_ASSUMED`.
Properties
$countryManager read-only
private
CountryManager
$countryManager
$natures
private
array<int, SupplyNature|false>
$natures
= []
$paymentRegionManager read-only
private
PaymentRegionManager
$paymentRegionManager
$rates
private
array<string, numeric-string|null>
$rates
= []
$regionCountryCodes
private
array<int, string|null>
$regionCountryCodes
= []
$sellerTaxProfileManager read-only
private
SellerTaxProfileManager
$sellerTaxProfileManager
$supplyKindManager read-only
private
SupplyKindManager
$supplyKindManager
$taxAmountCalculator read-only
private
TaxAmountCalculator
$taxAmountCalculator
$taxRuleTable read-only
private
TaxRuleTable
$taxRuleTable
$vatIdCheckManager read-only
private
VatIdCheckManager
$vatIdCheckManager
$vatRateManager read-only
private
VatRateManager
$vatRateManager
Methods
__construct()
public
__construct(SellerTaxProfileManager $sellerTaxProfileManager, SupplyKindManager $supplyKindManager, CountryManager $countryManager, VatRateManager $vatRateManager, PaymentRegionManager $paymentRegionManager, VatIdCheckManager $vatIdCheckManager, TaxRuleTable $taxRuleTable, TaxAmountCalculator $taxAmountCalculator) : mixed
Parameters
- $sellerTaxProfileManager : SellerTaxProfileManager
- $supplyKindManager : SupplyKindManager
- $countryManager : CountryManager
- $vatRateManager : VatRateManager
- $paymentRegionManager : PaymentRegionManager
- $vatIdCheckManager : VatIdCheckManager
- $taxRuleTable : TaxRuleTable
- $taxAmountCalculator : TaxAmountCalculator
allocateAncillary()
proportionally to their bases; the rounding remainder goes to the largest group.
public
allocateAncillary(TaxResolution $resolution, numeric-string $amount[, bool $grossPrice = false ]) : array<int, TaxAncillaryShare>
Lines with an error are ignored. $grossPrice means the amount includes VAT (split from the top per group).
Parameters
- $resolution : TaxResolution
- $amount : numeric-string
- $grossPrice : bool = false
Return values
array<int, TaxAncillaryShare>findNoteKey()
Note key (`tax.note.<CODE>[.<status>]`) of a snapshotted treatment code: the invoice from a payment copies the code and re-translates the note in the document language. An unknown or `DOMESTIC` code gives null.
public
findNoteKey(string $code, int $sellerId, DateTimeInterface $at) : string|null
Parameters
- $code : string
- $sellerId : int
- $at : DateTimeInterface
Return values
string|nullrate()
Rate of a supply kind in a country on a date ('21.00'); null means `RATE_MISSING` (never a default).
public
rate(int $supplyKindId, string $countryCode, DateTimeInterface $at) : numeric-string|null
Parameters
- $supplyKindId : int
- $countryCode : string
- $at : DateTimeInterface
Return values
numeric-string|nullresetCache()
Drops request caches (long-running CLI after an admin change of rates / kinds).
public
resetCache() : void
resolve()
public
resolve(TaxContext $context, array<int, TaxLine> $lines) : TaxResolution
Parameters
- $context : TaxContext
- $lines : array<int, TaxLine>
-
order = line index in the result
Return values
TaxResolutionresolveDisplay()
Catalog / detail display: anonymous consumer in the country of the display region (region without a country gives the seller country + `COUNTRY_ASSUMED`). Never calls VIES.
public
resolveDisplay(int $sellerId, int|null $paymentRegionId, array<int, int> $supplyKindIds, DateTimeInterface $at) : array<int, TaxTreatment>
Parameters
- $sellerId : int
- $paymentRegionId : int|null
- $supplyKindIds : array<int, int>
- $at : DateTimeInterface
Return values
array<int, TaxTreatment> —keyed by supply kind id; unknown kinds are left out
sellerStatusAt()
public
sellerStatusAt(int $sellerId, DateTimeInterface $at) : SellerVatStatus|null
Parameters
- $sellerId : int
- $at : DateTimeInterface
Return values
SellerVatStatus|nullverifyVatId()
Verification outside a resolution (profile save, admin "verify in VIES" action).
public
verifyVatId(string $vatId[, bool $forceOnline = false ][, int|null $sellerId = null ][, string|null $fallbackCountryCode = null ][, VatIdCheckLimit|null $limit = null ]) : VatIdVerification
$sellerId supplies the requester VAT id for the VIES consultation number.
$limit is the rate limit of the online call (VatIdCheckManager::buildUserCheckLimit()); null means unlimited.
Parameters
- $vatId : string
- $forceOnline : bool = false
- $sellerId : int|null = null
- $fallbackCountryCode : string|null = null
- $limit : VatIdCheckLimit|null = null
Return values
VatIdVerificationbuildAmounts()
private
buildAmounts(TaxLine $line, TaxTreatment $treatment, TaxError|null $error) : array{0: numeric-string, 1: numeric-string|null}
Parameters
- $line : TaxLine
- $treatment : TaxTreatment
- $error : TaxError|null
Return values
array{0: numeric-string, 1: numeric-string|null}buildHeader()
Header = main supply (highest base, first on a tie), `chargeVat` = any line charges VAT, all flags.
private
buildHeader(array<int, TaxLineResult> $results, array<int, TaxFlag> $flags, VatIdVerification|null $verification) : TaxTreatment|null
Parameters
- $results : array<int, TaxLineResult>
- $flags : array<int, TaxFlag>
- $verification : VatIdVerification|null
Return values
TaxTreatment|nullbuildTreatment()
private
buildTreatment(int $supplyKindId, SupplyNature $nature, SellerVatStatus $sellerStatus, SellerTaxProfile|null $profile, TaxCountry $sellerCountry, CustomerClass $customerClass, bool|null $placeDomestic, DateTimeInterface $taxDate, VatIdVerification|null $verification) : TaxTreatment
Parameters
- $supplyKindId : int
- $nature : SupplyNature
- $sellerStatus : SellerVatStatus
- $profile : SellerTaxProfile|null
- $sellerCountry : TaxCountry
- $customerClass : CustomerClass
- $placeDomestic : bool|null
- $taxDate : DateTimeInterface
- $verification : VatIdVerification|null
Return values
TaxTreatmentclassifyCustomer()
Customer class C. The VAT id is verified lazily: at most once per resolution and only when a line goes to another EU member state; its flags are collected in `$state`.
private
classifyCustomer(TaxCountry $country, TaxCountry $sellerCountry, DateTimeInterface $taxDate, bool $isBusiness, bool $hasVatId, callable(): VatIdVerification $verify, callable(TaxCountry): Array $findEvidence, TaxFlag>, evidenceLooked: bool} &$state) : CustomerClass
A non-EU business stays declared (BUSINESS_STATUS_DECLARED); its manual evidence ("prove company") is only
attached as the verification (snapshot customer_vat_id_check_id), looked up once per resolution.
Parameters
- $country : TaxCountry
- $sellerCountry : TaxCountry
- $taxDate : DateTimeInterface
- $isBusiness : bool
- $hasVatId : bool
- $verify : callable(): VatIdVerification
- $findEvidence : callable(TaxCountry): Array
- $state : TaxFlag>, evidenceLooked: bool}
Return values
CustomerClassfindCountryOrPlaceholder()
private
findCountryOrPlaceholder(string $countryCode) : TaxCountry
Parameters
- $countryCode : string
Return values
TaxCountryfindNatures()
private
findNatures(array<int, int> $supplyKindIds) : array<int, SupplyNature>
Parameters
- $supplyKindIds : array<int, int>
Return values
array<int, SupplyNature>isEuB2cThresholdExceeded()
Hook: limit `EU_B2C_DISTANCE` of the seller (sum of the period + this document). Until the limits exist there is no active limit, so the result is no.
private
isEuB2cThresholdExceeded() : bool
Return values
boolmergeFlags()
private
mergeFlags(array<int, TaxFlag> ...$lists) : array<int, TaxFlag>
Parameters
- $lists : array<int, TaxFlag>
Return values
array<int, TaxFlag>resolveCustomerCountry()
Customer country, then payment region country, then seller country; the fallbacks flag `COUNTRY_ASSUMED`.
private
resolveCustomerCountry(string|null $customerCountryCode, int|null $paymentRegionId, TaxCountry $sellerCountry, array<int, TaxFlag> &$flags) : TaxCountry
An unknown ISO code from the client counts as missing.
Parameters
- $customerCountryCode : string|null
- $paymentRegionId : int|null
- $sellerCountry : TaxCountry
- $flags : array<int, TaxFlag>