veltix/tax-engine
Tax Engine
A Laravel package for EU tax/VAT calculation with support for OSS, IOSS, reverse charge, and export rules.
Requirements
- PHP 8.3+
- Laravel 12 or 13
ext-bcmath
Installation
composer require veltix/tax-engine
Publish the configuration:
php artisan vendor:publish --tag=tax-engine-config
If using database storage for compliance snapshots, publish and run migrations:
php artisan vendor:publish --tag=tax-engine-migrations
php artisan migrate
Configuration
Key settings in config/tax.php:
| Key | Description | Default |
|---|---|---|
seller.country |
Seller's EU country code | NL |
oss.enabled |
Enable One-Stop Shop | false |
ioss.enabled |
Enable Import One-Stop Shop | false |
rounding.mode |
Rounding mode (half_up, half_down, half_even) |
half_up |
compliance.store_decisions |
Store tax decisions | true |
compliance.store_evidence |
Store evidence (requires store_decisions with database driver) |
true |
compliance.storage_driver |
Storage backend (array or database) |
array |
Usage
use Veltix\TaxEngine\Actions\CalculateTaxAction;
use Veltix\TaxEngine\Data\TransactionData;
use Veltix\TaxEngine\Enums\CustomerType;
use Veltix\TaxEngine\Enums\SupplyType;
use Veltix\TaxEngine\Support\Country;
use Veltix\TaxEngine\Support\Money;
$action = app(CalculateTaxAction::class);
$result = $action->execute(new TransactionData(
transactionId: 'order-123',
amount: Money::fromCents(10000), // EUR 100.00
sellerCountry: new Country('DE'),
buyerCountry: new Country('FR'),
customerType: CustomerType::B2C,
supplyType: SupplyType::DigitalServices,
));
$result->taxAmount; // Money object with calculated tax
$result->grossAmount; // Net + tax
$result->decision; // TaxDecisionData with scheme, rate, reasoning
VAT Rates
The built-in StaticRateRepository uses the EU VAT rates in EuVatRates (rate table version 2026.1, rates in force on 2026-10-05). The table holds current rates only; it does not give a past date its old rate. Sources and the dates of recent changes are in docs/rates-sources.md. To use your own rates, bind your own RateRepositoryContract implementation.
Available Rules
Rules are evaluated by priority (highest first):
| Rule | Priority | Description |
|---|---|---|
| IOSS | 70 | Import of goods into EU (max EUR 150) |
| Export | 60 | Goods export from EU to non-EU |
| Service Export | 59 | Services from EU to non-EU (outside scope) |
| Reverse Charge | 50 | B2B cross-border EU with VAT number |
| OSS | 40 | B2C cross-border EU (when OSS enabled) |
| Domestic Reverse Charge | 30 | Domestic B2B reverse charge |
| Cross-Border B2C Fallback | 20 | B2C cross-border EU without OSS (seller rate) |
| Domestic Standard | 10 | Domestic EU sale |
Extending with Custom Rules
Implement RuleContract and tag it in your service provider:
use Veltix\TaxEngine\Contracts\RuleContract;
class MyCustomRule implements RuleContract
{
public function applies(TransactionData $transaction): bool { /* ... */ }
public function evaluate(TransactionData $transaction): TaxDecisionData { /* ... */ }
public function priority(): int { return 25; }
}
// In your service provider:
$this->app->bind(MyCustomRule::class, fn () => new MyCustomRule());
$this->app->tag(MyCustomRule::class, 'tax-engine.rules');
License
MIT
Related Packages
Powerful PHP database abstraction layer (DBAL) with many features for database s...
Laravel Serializable Closure provides an easy and secure way to serialize closur...
Cli error handling for console/command-line PHP applications.
Version History
| Version | Released | PHP | Laravel | License |
|---|---|---|---|---|
| v1.1.0 | ^8.3 | ^12.0| | MIT | |
| v1.0.4 | ^8.3 | ^12.0| | MIT | |
| v1.0.3 | ^8.3 | ^12.0| | MIT | |
| v1.0.2 | ^8.3 | ^12.0| | MIT | |
| v1.0.1 | ^8.2 | ^11.0| | MIT | |
| v1.0.0 | ^8.2 | ^11.0| | MIT |