Skip to main content
Lunar provides configurable tax rules for calculating sales tax on orders.

Overview

Lunar provides manual tax rules to implement the correct sales tax for each order. For complex taxation scenarios (e.g. US states), integrating with a service such as TaxJar is recommended.

Tax Classes

Tax Classes are assigned to products and allow classification into taxable groups that may have differing tax rates.

Fields

Tax Zones

Tax Zones specify a geographic zone for tax rates to be applied. They can be based on countries, states, or zip/postcodes.

Fields

Tax-inclusive versus tax-exclusive price display is no longer stored on the tax zone. It is a per-Region preference (Region::displaysPricesIncludingTax()), falling back to the global config('lunar.pricing.stored_inclusive_of_tax') default when the region has no override. The tax arithmetic (whether stored prices already include tax) is always driven by that global config, never by the zone or region.

Tax Zone Countries

Tax Zone States

State lookups are scoped to the address country, so a state zone only applies to addresses in that state’s own country. This matters because state codes are reused across countries: WA is both Washington and Western Australia.

Tax Zone Postcodes

Tax Zone Customer Groups

Zone resolution

Lunar\Core\Actions\Taxes\GetTaxZone resolves the tax zone for an address, checking each type of zone in turn and returning the first match:
  1. Postcode — matched against the address postcode, honoring wildcards.
  2. State — matched against the address state, scoped to the address country.
  3. Country — matched against the address country.
  4. Default — the tax zone flagged as the default, returned when nothing above matches.
Passing no address (or an address with none of these fields set) returns the default tax zone. A cart can also override this resolution entirely, see Carts → Addresses and tax zone.

Tax Rates

Tax Zones have one or many tax rates. For example, a zone might have a tax rate for the state and also the city, which collectively make up the total tax amount.

Fields

Tax Rate Amounts

Settings

  • Shipping and other specific costs are assigned to tax classes in the settings.
  • Tax calculation can be based on the shipping or billing address.
  • A default Tax Zone can be configured.

The tax driver

Tax calculation for a cart line is delegated to a Lunar\Core\Drivers\TaxDriver implementation, resolved through Lunar\Core\Facades\Taxes (backed by Lunar\Core\Contracts\TaxManager). The driver receives the shipping and billing addresses, the currency, and the purchasable/cart line being priced, and returns a Lunar\Core\ValueObjects\Cart\TaxBreakdown describing the tax amount per rate.
setTaxZone() lets a caller override zone resolution entirely — for example to tax on IP-derived location — bypassing the address-derived lookup. Lunar ships one built-in driver, Lunar\Core\Drivers\SystemTaxDriver, which resolves the tax zone via GetsTaxZone (or the overridden zone), looks up the tax class’s rates in that zone, and calculates each rate’s share of the sub total.

Extending

Sometimes the standard tax calculations are not sufficient, and custom logic may be needed, perhaps connecting to a tax service such as TaxJar. Lunar allows custom tax drivers to be implemented via Taxes::extend(). See the Extending Taxation section for more information.