Tax
Commerce represents taxes for an order using tax categories, tax rates, and tax zones. Each can be configured from the control panel via Commerce → Tax.
Tax features differ depending on your edition of Craft Commerce.
You can model common sales tax policies—like those typical in U.S. retail and European Value Added Tax (VAT)—but those aren’t the only types of tax rules that you can model in Commerce. With an understanding of Commerce’s basic taxation concepts you should be able to model the tax rules of your country or jurisdiction.
# Tax Categories
Every product designates a single tax category that determines how it’s taxed:
Commerce creates a default “General” category when it’s installed. Every newly-created product is automatically assigned to that default category, but you can add as many categories as you’d like and designate any one of them as the system-wide default.
To create a new tax category, visit Commerce → Tax → Tax Categories and press + New tax category:
Each new tax category should identify the product types it applies to. A new product will use the first tax category that’s available to it, or fall back on the default category.
Every line item must have a tax category, and Commerce will pick the most appropriate one you’ve established. It’s possible your default category will be used for product types that aren’t explicitly selected, if no other tax categories are available.
A tax category may have zero or more tax rates, which we’ll explore further below.
# Fetching Tax Categories
You can fetch your site’s tax categories through the TaxCategories (opens new window) service:
This returns an array of TaxCategory (opens new window) models. You can use these to work with basic details like the category’s ID, name, and description, as well as related product types and tax rates:
{% for categories as taxCategory %}
{# @var taxCategory craft\commerce\models\TaxCategory #}
{{ taxCategory.id }}
{{ taxCategory.name }}
{{ taxCategory.description }}
{{ taxCategory.default }}
{{ taxCategory.productTypes }}
{{ taxCategory.taxRates }}
{% endfor %}
You can fetch the tax categories for a specific product type using its ID:
{% set categories = craft.commerce
.getTaxCategories()
.getTaxCategoriesByProductTypeId(123) %}
In some cases you may need to get a single, specific tax category:
{# Get a reference to the service for brevity below #}
{% set taxCategories = craft.commerce.getTaxCategories() %}
{# Get the default tax category #}
{% set category = taxCategories.getDefaultTaxCategory() %}
{# Get tax category with an ID of `123` #}
{% set category = taxCategories.getTaxCategoryById(123) %}
{# Get tax category with a handle of `general` #}
{% set category = taxCategories.getTaxCategoryByHandle('general') %}
# Example
Stores operating in countries like Australia, India, and Canada may need to apply a Goods and Services Tax (GST) to some of the store’s products while others are exempt from that tax.
In that case, you may configure your store with GST
and GSTFREE
tax categories with GST
being the default.
This would mean that all items in your store would get the GST
tax category, and a store manager could specifically select the GSTFREE
tax category for each item that should be exempt.
# Tax Rates
A tax rate is a simple percentage that may be applied to relevant cart items. The rate is only applied when an item’s tax category and tax zone qualify it for the rate.
Commerce does not add any tax rates by default; you’ll need to explicitly create any that you’d like to be available.
To create a new tax category, visit Commerce → Tax → Tax Rates and press + New tax rate:
Every tax rate must specify a single tax category it applies to.
Multiple tax rates can apply to a single tax category and/or tax zone.
Specifying a tax zone is optional. By default, a tax rate won’t be limited to a particular zone—meaning it will qualify for any order item based on its tax category alone with no consideration for the order address.
The tax rate also has settings for exactly what it applies to and how it should be applied:
- Taxable Subject determines what part(s) of an item’s price should be taxed
- Disqualify with valid business tax ID? allows skipping the tax when certain business tax IDs exist on the order
- Included in price? determines whether the rate should be incorporated into the price of the item and whether disqualified items should have their prices adjusted
# Fetching Tax Rates
You can fetch all of your site’s tax rates through the TaxRates (opens new window) service:
This returns an array of TaxRate (opens new window) models. You can use these to work with basic details like the rate’s ID, name, code, and rate, as well as related tax zones and categories:
{% for rates as taxRate %}
{# @var taxRate craft\commerce\models\TaxRate #}
{{ taxRate.id }}
{{ taxRate.name }}
{{ taxRate.code }}
{{ taxRate.rate }}
{{ taxRate.taxable }}
{{ taxRate.getRateAsPercent() }}
{{ taxRate.getTaxZone() }}
{{ taxRate.getTaxCategory() }}
{{ taxRate.getIsEverywhere() }}
{% endfor %}
You can also fetch tax rates for a specific tax zone by providing a zone object or ID:
{# Fetch rates for a `zone` we’ve already got #}
{# @var zone craft\commerce\models\TaxAddressZone #}
{% set rates = craft.commerce
.getTaxRates()
.getTaxRatesForZone(zone) %}
{# Fetch rates for a tax zone with an ID of `123` #}
{% set rates = craft.commerce
.getTaxRates()
.getTaxRatesByTaxZoneId(123) %}
In some cases you may need to get a single, specific tax rate by its ID:
{# Get tax rate with an ID of `123` #}
{% set rate = craft.commerce
.getTaxRates()
.getTaxRateById(123) %}
# Tax Zones
A tax zone represents a physical area that can be used to influence tax based on an order’s shipping address.
When an order address falls within that zone, any rates tied to that zone may be factored into tax calculation. An order may have more than one matching tax zone, and all of them will be factored in.
Commerce does not add any tax zones by default. Like tax rates, you’ll need to create any tax zones you’d like to use for your store.
To create a new tax zone, visit Commerce → Tax → Tax Zones and press + New tax zone:
The tax zone consists of a Name, Description, and three fields you can use to define the relevant area: Type, Countries, and Zip Code Condition Formula. You can also designate a single zone to be used as the default when an order doesn’t have a shipping address.
# Zip Code Condition Formula
The zip code formula is an expression written in Twig’s expression syntax (opens new window) that returns true
or false
.
This will match if the zip code’s first two characters are 60
or 70
:
zipCode[0:2] == '60' or zipCode[0:2] == '70'
The will match if the zip code is equal to NG102
, NG103
, or NG104
:
zipCode in ['NG102', 'NG103', 'NG104']
# Fetching Tax Zones
You can fetch your site’s tax zones through the TaxZones (opens new window) service:
This returns an array of TaxAddressZone (opens new window) models. You can use these to work with basic details like the zone’s ID, name, and description and the geographic conditions you’ve established for it:
{% for zones as taxZone %}
{# @var taxZone craft\commerce\models\TaxAddressZone #}
{{ taxZone.id }}
{{ taxZone.name }}
{{ taxZone.description }}
{{ taxZone.dateCreated }}
{{ taxZone.dateUpdated }}
{{ taxZone.default }}
{{ taxZone.getCondition() }}
{% endfor %}
In some cases you may need to get a single, specific tax zone by its ID:
{# Get tax zone with an ID of `123` #}
{% set zone = craft.commerce
.getTaxZones()
.getTaxZoneById(123) %}
# Basic Zone Examples
# Example A
Let’s say you need to charge 5% tax for all items that ship to New York and 6% only on clothing items that ship to Pennsylvania. You’ll need to set up two zones: one for the state of New York, and another for the state of Pennsylvania.
# Example B
You would like to charge 10% tax on all electronic items and 5% tax on everything else. This tax should apply to all countries in the European Union (EU). In this case you would construct just a single zone consisting of all the countries in the EU. Even though you need to charge two different rates for a product, you don’t necessarily need to have two zones.
# Templating
It’s common to display tax information to a customer in the context of their cart, since applicable taxes may depend on order items and the shipping address. Check out the cart (opens new window) in the Commerce example templates, which includes taxable totals.
# Further Reading
See Tax Engines if you’re interested in customizing the Commerce tax system.