Skip to content

Add Canada VAT rules with province-specific rates#10

Open
johngathure wants to merge 9 commits intomasterfrom
enhancement/9-canada-vat-rates
Open

Add Canada VAT rules with province-specific rates#10
johngathure wants to merge 9 commits intomasterfrom
enhancement/9-canada-vat-rates

Conversation

@johngathure
Copy link
Copy Markdown
Collaborator

@johngathure johngathure commented Nov 18, 2025

Summary

Implements Canadian province-specific VAT rates (GST/HST/PST) based on postal code prefixes, addressing issue #9.

pyvat/vat_rules.pyCanadaVatRules

  • Added CanadaVatRules class extending NonEuVatRules with full province-level rate logic
  • PROVINCE_VAT_RATES maps each postal code prefix (A–Y) to the correct combined rate
  • get_vat_rate(item_type, postal_code) resolves rate from the first character of the postal code
  • Defaults to Ontario (13 %) when no postal code is provided, as agreed in the issue
  • Provinces where we are not registered for provincial tax (Quebec, Manitoba) correctly charge GST only (5 %)
  • No B2B exemption — Canadian business customers are taxed identically to consumers

pyvat/region_rules.pyRegionRules / CanadaRegionRules

  • Added RegionRules abstract base class to support future region-level rules for other countries (e.g. US states, Swiss cantons)
  • CanadaRegionRules exposes get_rate(postal_code) and get_region(postal_code) for consumers that need more than just a rate
  • get_region() returns a ProvinceRate (nested NamedTuple) containing the prefix, province name, combined rate, and a tax_types tuple (e.g. (HST,) or (GST, PST)) — useful for rendering invoice line items correctly
  • Tax type constants (GST, HST, PST, QST, RST) are scoped to CanadaRegionRules since they are Canada-specific
  • Rates are not duplicated — CanadaRegionRules reads directly from CanadaVatRules.PROVINCE_VAT_RATES

setup.py

  • Replaced hardcoded packages list with find_packages() so any future sub-packages are picked up automatically without touching setup.py

Provincial rate table

Prefix Province / Territory Rate Tax type
A Newfoundland and Labrador 15 % HST
B Nova Scotia 14 % HST
C Prince Edward Island 15 % HST
E New Brunswick 15 % HST
G, H, J Quebec 5 % GST only (not registered for QST)
K, L, M, N, P Ontario 13 % HST
R Manitoba 5 % GST only (not registered for RST)
S Saskatchewan 11 % GST + PST
T Alberta 5 % GST only
V British Columbia 12 % GST + PST
X Northwest Territories / Nunavut 5 % GST only
Y Yukon 5 % GST only
No postal code 13 % Ontario fallback

Test plan

  • Rate returned for every postal code prefix (A–Y)
  • Ontario (13 %) fallback when no postal code is provided
  • Quebec and Manitoba return 5 % (GST only) — not registered for QST/RST
  • B2B transactions charged the same rate as B2C (no exemption)
  • Integration with get_sale_vat_charge end-to-end
  • Populate gst_number and pst_number registration numbers once available (post-release)
  • Update company VAT rates database (post-release, noted in issue)

Related Issues

Closes #9

🤖 Generated with Claude Code

Implements CaVatRules class to support Canadian GST/HST/PST rates for all provinces and territories. The first letter of the postal code determines the region and corresponding tax rate (5%-15%).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
@johngathure
Copy link
Copy Markdown
Collaborator Author

To release this after review, follow the following steps:

  1. Merge into master.
  2. Create a release 1.0.4 here.
  3. Update Imagify and Monies requirement of pyvat to use the newly created tag on step 2 1.0.4 .

@nicomollet
Copy link
Copy Markdown

⏯️ Merge only after knowing the exact Canadian tax values and follow steps above.

Putting as QA done. QA will be done with Monies.

@nicomollet
Copy link
Copy Markdown

@johngathure Mathieu updated the issue description with the values depending on each Canada state.

  1. Update the value for each state and consider the Quebec and Manitoba to be 5%
  2. Include a fallback to Ontario value when no postal code (13%)
  3. Develop tests for Canada especially:
    • fallback when no postal code
    • state: Quebec, Ontario, British Columbia (we have postal code examples in the issue desc)

⏯️ Make this PR in a ready state and wait for signal for release

@johngathure
Copy link
Copy Markdown
Collaborator Author

johngathure commented Apr 10, 2026

Hi @nicomollet 👋

I've made the changes to use the rates shared by Mathieu and added some tests. Whenever we are ready to QA, I will update monies to use the last commit on this pr, so it picks the newly updated Canadian VAT rates.

Copy link
Copy Markdown

@nicomollet nicomollet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved, let's move to QA in progress until more news in the issue

@johngathure Prepare a PR on Monies side (linked to this issue) matching this (unreleased) version of Pyvat. So that we can eventually deploy to staging for testing.

@nicomollet
Copy link
Copy Markdown

Add update the doc https://www.notion.so/wpmedia/VAT-Tax-rates-Exemption-for-all-countries-2beed22a22f080658719c05700236045 as post release actions please in the PR

@johngathure johngathure force-pushed the enhancement/9-canada-vat-rates branch from 62b26d5 to b46fdc3 Compare April 14, 2026 11:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Canada specific regions VAT rates (ETA May 11)

3 participants