When it runs
Tax is calculated once, while the order is created, and the resulting lines are stored on the order. They’re included ingetTotalPrice(), so every payment gateway charges the taxed amount without doing anything extra.
If the configured engine can’t be resolved, Aikeedo falls back to the null engine, so a missing plugin never blocks checkout.
The interface
TaxResult is a list of Billing\Domain\ValueObjects\TaxLine objects:
TaxResult::getTaxTotal() sums the lines, so return several when a jurisdiction has more than one component, such as a state and a city tax.
Implementation
src/FlatTaxEngine.php
Rules to follow
- Return an empty
TaxResult()when you can’t calculate, including when an external service fails. Throwing blocks checkout entirely. - Work in minor units. Round once, at the end.
- Decide your base. Tax the discounted amount, or the pre-discount amount, according to the rules you’re implementing, and document which you chose.
- Handle a missing address. Many workspaces have none, and a plan may be sold without one.
- Don’t call a slow API without a timeout. Order creation waits for you.
Register it
src/Plugin.php
option.billing.tax_engine.
The settings page
The tax engines list links each engine to/admin/settings/tax-engines/{key}, so declare that route:
extra.default_url to the same path. For the form itself, see Admin settings pages.
Using an external tax service
For a service such as a rate API, keep the network call tight:Testing
Checkout shows your tax lines, and the total includes them.
A workspace without an address still reaches checkout.
A zero or missing rate produces no tax line at all.
A discounted order taxes the amount you intended.
With the service unreachable, checkout still completes.