---
title: "Tax — Money for Laravel | Roundly"
description: "Net, tax and gross from exact rates with one rounding per call, breakdowns where net + tax always equals gross, and invoice summaries."
url: https://roundly-consulting.com/open-source/docs/money-for-laravel/tax
language: en
---

[All packages](https://roundly-consulting.com/open-source.md)

[Money for Laravel](https://roundly-consulting.com/open-source/docs/money-for-laravel.md)

# Tax

TaxRate computes net, tax and gross with one exact rational and one rounding per call — no float divisor, no int conversion:

```php
use RoundlyConsulting\Money\Tax\TaxRate;

$vat   = TaxRate::fromBasisPoints(2000, 'VAT');   // 20 %
$net   = Money::ofMajor('10', 'EUR');
$gross = Money::ofMajor('12', 'EUR');

$vat->taxOnNet($net);         // 2.00 EUR
$vat->grossFromNet($net);     // 12.00 EUR
$vat->netFromGross($gross);   // 10.00 EUR
$vat->taxInGross($gross);     // 2.00 EUR

$line = TaxRate::of('19')->breakdownFromGross(Money::ofMajor('10', 'EUR'));
$line->net;     // 8.40 EUR
$line->tax;     // 1.60 EUR
$line->gross;   // 10.00 EUR — net + tax === gross, always

TaxRate::of('8.875', 'Sales tax');   // precise to a thousandth of a percent
TaxRate::zero();
```

- TaxRate::of($percent, ?$label), TaxRate::fromBasisPoints($bp, ?$label), TaxRate::zero().
- taxOnNet() and grossFromNet() — for prices without tax.
- netFromGross() and taxInGross() — for prices that include tax.
- breakdownFromNet() rounds the tax and derives the gross; breakdownFromGross() rounds the net and derives the tax.

In both directions net + tax === gross exactly: one side rounds, the other is derived by subtraction. The package property-tests this on 10 000 seeded amounts across all eight rounding modes.

## Invoice summaries

```php
use RoundlyConsulting\Money\Tax\TaxSummary;

$vat     = TaxRate::of(20, 'VAT');
$reduced = TaxRate::of(10, 'Reduced');

$summary = TaxSummary::of(
    $vat->breakdownFromNet(Money::ofMajor('10', 'EUR')),
    $vat->breakdownFromNet(Money::ofMajor('25', 'EUR')),
    $reduced->breakdownFromNet(Money::ofMajor('8', 'EUR')),
);

$summary->perRate();   // list<TaxBreakdown>, one per rate, sorted by rate:
                       // 10 %: 8.00 + 0.80 = 8.80 · 20 %: 35.00 + 7.00 = 42.00
$summary->net();       // 43.00 EUR
$summary->tax();       // 7.80 EUR
$summary->gross();     // 50.80 EUR
```

TaxSummary re-aggregates lines without re-rounding. Whether tax is rounded per line or per total is your policy — which is why both primitives exist. Mixed currencies throw CurrencyMismatch.

## Show your open-source love

This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.

[More ways to support, including crypto](https://roundly-consulting.com/support-us.md)

By donating, you agree to our [donation terms](https://roundly-consulting.com/donation-terms.md).

[Support our open source work (opens in a new tab)](https://donate.stripe.com/dRmeVe8FX5PF1Qd9pXcEw00) [Join us on Patreon (opens in a new tab)](https://www.patreon.com/cw/roundly)

## Want this built into your product?

We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.

[Get a quote in 48 hours](https://roundly-consulting.com/contact.md) [Browse all packages](https://roundly-consulting.com/open-source/docs/money-for-laravel.md)
