diff --git a/resources/tax_type/ca_ab_gst.json b/resources/tax_type/ca_ab_gst.json new file mode 100755 index 0000000..98b8f11 --- /dev/null +++ b/resources/tax_type/ca_ab_gst.json @@ -0,0 +1,20 @@ +{ + "name": "Canada - Alberta", + "generic_label": "gst", + "zone": "ca_ab", + "tag": "CA", + "rates": [ + { + "id": "ca_ab_gst_standard", + "name": "Standard", + "default": true, + "amounts": [ + { + "id": "ca_ab_gst_standard_2013", + "amount": 0.05, + "start_date": "2013-04-01" + } + ] + } + ] +} diff --git a/resources/tax_type/ca_bc_gst.json b/resources/tax_type/ca_bc_gst.json new file mode 100755 index 0000000..69cd8a9 --- /dev/null +++ b/resources/tax_type/ca_bc_gst.json @@ -0,0 +1,20 @@ +{ + "name": "Canada - British Columbia", + "generic_label": "gst", + "zone": "ca_bc", + "tag": "CA", + "rates": [ + { + "id": "ca_bc_gst_standard", + "name": "Standard", + "default": true, + "amounts": [ + { + "id": "ca_bc_gst_standard_2013", + "amount": 0.05, + "start_date": "2013-04-01" + } + ] + } + ] +} diff --git a/resources/tax_type/ca_bc_pst.json b/resources/tax_type/ca_bc_pst.json new file mode 100755 index 0000000..105011b --- /dev/null +++ b/resources/tax_type/ca_bc_pst.json @@ -0,0 +1,20 @@ +{ + "name": "Canada - British Columbia", + "generic_label": "PST", + "zone": "ca_bc", + "tag": "CA", + "rates": [ + { + "id": "ca_bc_pst_standard", + "name": "Standard", + "default": true, + "amounts": [ + { + "id": "ca_bc_pst_standard_2013", + "amount": 0.07, + "start_date": "2013-04-01" + } + ] + } + ] +} diff --git a/resources/tax_type/ca_mb_gst.json b/resources/tax_type/ca_mb_gst.json new file mode 100755 index 0000000..484d369 --- /dev/null +++ b/resources/tax_type/ca_mb_gst.json @@ -0,0 +1,20 @@ +{ + "name": "Canada - Manitoba", + "generic_label": "gst", + "zone": "ca_mb", + "tag": "CA", + "rates": [ + { + "id": "ca_mb_gst_standard", + "name": "Standard", + "default": true, + "amounts": [ + { + "id": "ca_mb_gst_standard_2013", + "amount": 0.05, + "start_date": "2013-04-01" + } + ] + } + ] +} diff --git a/resources/tax_type/ca_mb_rst.json b/resources/tax_type/ca_mb_rst.json new file mode 100755 index 0000000..cd4475d --- /dev/null +++ b/resources/tax_type/ca_mb_rst.json @@ -0,0 +1,26 @@ +{ + "name": "Canada - Manitoba", + "generic_label": "RST", + "zone": "ca_mb", + "tag": "CA", + "rates": [ + { + "id": "ca_mb_rst_standard", + "name": "Standard", + "default": true, + "amounts": [ + { + "id": "ca_mb_rst_standard_2013", + "amount": 0.08, + "start_date": "2013-07-01", + "end_date": "2019-06-30" + }, + { + "id": "ca_mb_rst_standard_2019", + "amount": 0.07, + "start_date": "2019-07-01" + } + ] + } + ] +} diff --git a/resources/tax_type/ca_nb_hst.json b/resources/tax_type/ca_nb_hst.json new file mode 100755 index 0000000..fae13b2 --- /dev/null +++ b/resources/tax_type/ca_nb_hst.json @@ -0,0 +1,27 @@ +{ + "name": "Canada - New Brunswick", + "generic_label": "hst", + "zone": "ca_nb", + "tag": "CA", + "compound": false, + "rates": [ + { + "id": "ca_nb_hst_standard", + "name": "Standard", + "default": true, + "amounts": [ + { + "id": "ca_nb_hst_standard_2013", + "amount": 0.13, + "start_date": "2013-04-01", + "end_date": "2016-06-30" + }, + { + "id": "ca_nb_hst_standard_2016", + "amount": 0.15, + "start_date": "2016-07-01" + } + ] + } + ] +} diff --git a/resources/tax_type/ca_nl_hst.json b/resources/tax_type/ca_nl_hst.json new file mode 100755 index 0000000..4b65661 --- /dev/null +++ b/resources/tax_type/ca_nl_hst.json @@ -0,0 +1,26 @@ +{ + "name": "Canada - Newfoundland and Labrador", + "generic_label": "hst", + "zone": "ca_nl", + "tag": "CA", + "rates": [ + { + "id": "ca_nl_hst_standard", + "name": "Standard", + "default": true, + "amounts": [ + { + "id": "ca_nl_hst_standard_2013", + "amount": 0.13, + "start_date": "2013-04-01", + "end_date": "2015-12-31" + }, + { + "id": "ca_nl_hst_standard_2016", + "amount": 0.15, + "start_date": "2016-01-01" + } + ] + } + ] +} diff --git a/resources/tax_type/ca_ns_hst.json b/resources/tax_type/ca_ns_hst.json new file mode 100755 index 0000000..cb16ba6 --- /dev/null +++ b/resources/tax_type/ca_ns_hst.json @@ -0,0 +1,20 @@ +{ + "name": "Canada - Nova Scotia", + "generic_label": "hst", + "zone": "ca_ns", + "tag": "CA", + "rates": [ + { + "id": "ca_ns_hst_standard", + "name": "Standard", + "default": true, + "amounts": [ + { + "id": "ca_ns_hst_standard_2013", + "amount": 0.15, + "start_date": "2013-04-01" + } + ] + } + ] +} diff --git a/resources/tax_type/ca_nt_gst.json b/resources/tax_type/ca_nt_gst.json new file mode 100755 index 0000000..f9638ee --- /dev/null +++ b/resources/tax_type/ca_nt_gst.json @@ -0,0 +1,20 @@ +{ + "name": "Canada - Northwest Territories", + "generic_label": "gst", + "zone": "ca_nt", + "tag": "CA", + "rates": [ + { + "id": "ca_nt_gst_standard", + "name": "Standard", + "default": true, + "amounts": [ + { + "id": "ca_nt_gst_standard_2013", + "amount": 0.05, + "start_date": "2013-04-01" + } + ] + } + ] +} diff --git a/resources/tax_type/ca_nu_gst.json b/resources/tax_type/ca_nu_gst.json new file mode 100755 index 0000000..63e0127 --- /dev/null +++ b/resources/tax_type/ca_nu_gst.json @@ -0,0 +1,20 @@ +{ + "name": "Canada - Nunavut", + "generic_label": "gst", + "zone": "ca_nu", + "tag": "CA", + "rates": [ + { + "id": "ca_nu_gst_standard", + "name": "Standard", + "default": true, + "amounts": [ + { + "id": "ca_nu_gst_standard_2013", + "amount": 0.05, + "start_date": "2013-04-01" + } + ] + } + ] +} diff --git a/resources/tax_type/ca_on_hst.json b/resources/tax_type/ca_on_hst.json new file mode 100755 index 0000000..2d1aea6 --- /dev/null +++ b/resources/tax_type/ca_on_hst.json @@ -0,0 +1,20 @@ +{ + "name": "Canada - Ontario", + "generic_label": "hst", + "zone": "ca_on", + "tag": "CA", + "rates": [ + { + "id": "ca_on_hst_standard", + "name": "Standard", + "default": true, + "amounts": [ + { + "id": "ca_on_hst_standard_2013", + "amount": 0.13, + "start_date": "2013-04-01" + } + ] + } + ] +} diff --git a/resources/tax_type/ca_pe_hst.json b/resources/tax_type/ca_pe_hst.json new file mode 100755 index 0000000..64d0be8 --- /dev/null +++ b/resources/tax_type/ca_pe_hst.json @@ -0,0 +1,26 @@ +{ + "name": "Canada - Prince Edward Island", + "generic_label": "hst", + "zone": "ca_pe", + "tag": "CA", + "rates": [ + { + "id": "ca_pe_hst_standard", + "name": "Standard", + "default": true, + "amounts": [ + { + "id": "ca_pe_hst_standard_2013", + "amount": 0.14, + "start_date": "2013-04-01", + "end_date": "2016-09-30" + }, + { + "id": "ca_pe_hst_standard_2016", + "amount": 0.15, + "start_date": "2016-10-01" + } + ] + } + ] +} diff --git a/resources/tax_type/ca_qc_gst.json b/resources/tax_type/ca_qc_gst.json new file mode 100755 index 0000000..fd1f8d8 --- /dev/null +++ b/resources/tax_type/ca_qc_gst.json @@ -0,0 +1,20 @@ +{ + "name": "Canada - Quebec", + "generic_label": "gst", + "zone": "ca_qc", + "tag": "CA", + "rates": [ + { + "id": "ca_qc_gst_standard", + "name": "Standard", + "default": true, + "amounts": [ + { + "id": "ca_qc_gst_standard_2013", + "amount": 0.05, + "start_date": "2013-04-01" + } + ] + } + ] +} diff --git a/resources/tax_type/ca_qc_qst.json b/resources/tax_type/ca_qc_qst.json new file mode 100755 index 0000000..9acf684 --- /dev/null +++ b/resources/tax_type/ca_qc_qst.json @@ -0,0 +1,20 @@ +{ + "name": "Canada - Quebec", + "generic_label": "QST", + "zone": "ca_qc", + "tag": "CA", + "rates": [ + { + "id": "ca_qc_qst_standard", + "name": "Standard", + "default": true, + "amounts": [ + { + "id": "ca_qc_qst_standard_2013", + "amount": 0.09975, + "start_date": "2013-04-01" + } + ] + } + ] +} diff --git a/resources/tax_type/ca_sk_gst.json b/resources/tax_type/ca_sk_gst.json new file mode 100755 index 0000000..5f692c3 --- /dev/null +++ b/resources/tax_type/ca_sk_gst.json @@ -0,0 +1,20 @@ +{ + "name": "Canada - Saskatchewan", + "generic_label": "gst", + "zone": "ca_sk", + "tag": "CA", + "rates": [ + { + "id": "ca_sk_gst_standard", + "name": "Standard", + "default": true, + "amounts": [ + { + "id": "ca_sk_gst_standard_2013", + "amount": 0.05, + "start_date": "2013-04-01" + } + ] + } + ] +} diff --git a/resources/tax_type/ca_sk_pst.json b/resources/tax_type/ca_sk_pst.json new file mode 100755 index 0000000..ec9b525 --- /dev/null +++ b/resources/tax_type/ca_sk_pst.json @@ -0,0 +1,26 @@ +{ + "name": "Canada - Saskatchewan", + "generic_label": "PST", + "zone": "ca_sk", + "tag": "CA", + "rates": [ + { + "id": "ca_sk_pst_standard", + "name": "Standard", + "default": true, + "amounts": [ + { + "id": "ca_sk_pst_standard_2006", + "amount": 0.05, + "start_date": "2006-10-28", + "end_date": "2017-03-22" + }, + { + "id": "ca_sk_pst_standard_2017", + "amount": 0.06, + "start_date": "2017-03-23" + } + ] + } + ] +} diff --git a/resources/tax_type/ca_yt_gst.json b/resources/tax_type/ca_yt_gst.json new file mode 100755 index 0000000..57e1b82 --- /dev/null +++ b/resources/tax_type/ca_yt_gst.json @@ -0,0 +1,20 @@ +{ + "name": "Canada - Yukon", + "generic_label": "gst", + "zone": "ca_yt", + "tag": "CA", + "rates": [ + { + "id": "ca_yt_gst_standard", + "name": "Standard", + "default": true, + "amounts": [ + { + "id": "ca_yt_gst_standard_2013", + "amount": 0.05, + "start_date": "2013-04-01" + } + ] + } + ] +} diff --git a/resources/tax_type/id_gst.json b/resources/tax_type/id_gst.json index 01e60d2..682cfa1 100644 --- a/resources/tax_type/id_gst.json +++ b/resources/tax_type/id_gst.json @@ -1,6 +1,6 @@ { "name": "Indonesian GST", - "generic_label": "GST", + "generic_label": "gst", "display_inclusive": true, "zone": "id_gst", "rates": [ diff --git a/resources/zone/ca_ab.json b/resources/zone/ca_ab.json new file mode 100755 index 0000000..1dbf388 --- /dev/null +++ b/resources/zone/ca_ab.json @@ -0,0 +1,13 @@ +{ + "name": "Canada - Alberta (GST)", + "scope": "tax", + "members": [ + { + "type": "country", + "id": "ca_ab", + "name": "Canada - Alberta", + "country_code": "CA", + "administrative_area": "AB" + } + ] +} diff --git a/resources/zone/ca_bc.json b/resources/zone/ca_bc.json new file mode 100755 index 0000000..5b8965b --- /dev/null +++ b/resources/zone/ca_bc.json @@ -0,0 +1,13 @@ +{ + "name": "Canada - British Columbia (GST + PST)", + "scope": "tax", + "members": [ + { + "type": "country", + "id": "ca_bc", + "name": "Canada - British Columbia", + "country_code": "CA", + "administrative_area": "BC" + } + ] +} diff --git a/resources/zone/ca_mb.json b/resources/zone/ca_mb.json new file mode 100755 index 0000000..146c0c9 --- /dev/null +++ b/resources/zone/ca_mb.json @@ -0,0 +1,13 @@ +{ + "name": "Canada - Manitoba (GST + RST)", + "scope": "tax", + "members": [ + { + "type": "country", + "id": "ca_mb", + "name": "Canada - Manitoba", + "country_code": "CA", + "administrative_area": "MB" + } + ] +} diff --git a/resources/zone/ca_nb.json b/resources/zone/ca_nb.json new file mode 100755 index 0000000..b1f886b --- /dev/null +++ b/resources/zone/ca_nb.json @@ -0,0 +1,13 @@ +{ + "name": "Canada - New Brunswick (HST)", + "scope": "tax", + "members": [ + { + "type": "country", + "id": "ca_nb", + "name": "Canada - New Brunswick", + "country_code": "CA", + "administrative_area": "NB" + } + ] +} diff --git a/resources/zone/ca_nl.json b/resources/zone/ca_nl.json new file mode 100755 index 0000000..24c5258 --- /dev/null +++ b/resources/zone/ca_nl.json @@ -0,0 +1,13 @@ +{ + "name": "Canada - Newfoundland and Labrador (HST)", + "scope": "tax", + "members": [ + { + "type": "country", + "id": "ca_nl", + "name": "Canada - Newfoundland and Labrador", + "country_code": "CA", + "administrative_area": "NL" + } + ] +} diff --git a/resources/zone/ca_ns.json b/resources/zone/ca_ns.json new file mode 100755 index 0000000..4a78fe2 --- /dev/null +++ b/resources/zone/ca_ns.json @@ -0,0 +1,13 @@ +{ + "name": "Canada - Nova Scotia (HST)", + "scope": "tax", + "members": [ + { + "type": "country", + "id": "ca_ns", + "name": "Canada - Nova Scotia", + "country_code": "CA", + "administrative_area": "NS" + } + ] +} diff --git a/resources/zone/ca_nt.json b/resources/zone/ca_nt.json new file mode 100755 index 0000000..f3c94a3 --- /dev/null +++ b/resources/zone/ca_nt.json @@ -0,0 +1,13 @@ +{ + "name": "Canada - Northwest Territories (GST)", + "scope": "tax", + "members": [ + { + "type": "country", + "id": "ca_nt", + "name": "Canada - Northwest Territories", + "country_code": "CA", + "administrative_area": "NT" + } + ] +} diff --git a/resources/zone/ca_nu.json b/resources/zone/ca_nu.json new file mode 100755 index 0000000..57180dc --- /dev/null +++ b/resources/zone/ca_nu.json @@ -0,0 +1,13 @@ +{ + "name": "Canada - Nunavut (GST)", + "scope": "tax", + "members": [ + { + "type": "country", + "id": "ca_ns", + "name": "Canada - Nunavut", + "country_code": "CA", + "administrative_area": "NU" + } + ] +} diff --git a/resources/zone/ca_on.json b/resources/zone/ca_on.json new file mode 100755 index 0000000..9f5c37f --- /dev/null +++ b/resources/zone/ca_on.json @@ -0,0 +1,13 @@ +{ + "name": "Canada - Ontario (HST)", + "scope": "tax", + "members": [ + { + "type": "country", + "id": "ca_on", + "name": "Canada - Ontario", + "country_code": "CA", + "administrative_area": "ON" + } + ] +} diff --git a/resources/zone/ca_pe.json b/resources/zone/ca_pe.json new file mode 100755 index 0000000..97a164f --- /dev/null +++ b/resources/zone/ca_pe.json @@ -0,0 +1,13 @@ +{ + "name": "Canada - Prince Edward Island (HST)", + "scope": "tax", + "members": [ + { + "type": "country", + "id": "ca_pe", + "name": "Canada - Prince Edward Island", + "country_code": "CA", + "administrative_area": "PE" + } + ] +} diff --git a/resources/zone/ca_qc.json b/resources/zone/ca_qc.json new file mode 100755 index 0000000..d4737ed --- /dev/null +++ b/resources/zone/ca_qc.json @@ -0,0 +1,13 @@ +{ + "name": "Canada - Quebec (GST + QST)", + "scope": "tax", + "members": [ + { + "type": "country", + "id": "ca_qc", + "name": "Canada - Quebec", + "country_code": "CA", + "administrative_area": "QC" + } + ] +} diff --git a/resources/zone/ca_sk.json b/resources/zone/ca_sk.json new file mode 100755 index 0000000..27406f6 --- /dev/null +++ b/resources/zone/ca_sk.json @@ -0,0 +1,13 @@ +{ + "name": "Canada - Saskatchewan (GST + PST)", + "scope": "tax", + "members": [ + { + "type": "country", + "id": "ca_sk", + "name": "Canada - Saskatchewan", + "country_code": "CA", + "administrative_area": "SK" + } + ] +} diff --git a/resources/zone/ca_yt.json b/resources/zone/ca_yt.json new file mode 100755 index 0000000..e178476 --- /dev/null +++ b/resources/zone/ca_yt.json @@ -0,0 +1,13 @@ +{ + "name": "Canada - Yukon (GST)", + "scope": "tax", + "members": [ + { + "type": "country", + "id": "ca_yt", + "name": "Canada - Yukon", + "country_code": "CA", + "administrative_area": "YT" + } + ] +} diff --git a/src/Resolver/TaxType/CanadaTaxTypeResolver.php b/src/Resolver/TaxType/CanadaTaxTypeResolver.php index 79e092c..8c8c0c8 100644 --- a/src/Resolver/TaxType/CanadaTaxTypeResolver.php +++ b/src/Resolver/TaxType/CanadaTaxTypeResolver.php @@ -8,7 +8,12 @@ use CommerceGuys\Tax\Resolver\Context; /** - * Resolver for Canada's tax types (HST, PST, GST). + * Resolver for Canada's tax types: + * GST Goods and Services Tax + * HST Harmonized Sales Tax + * PST Provincial Sales Tax (generic provincial label) + * QST Quebec Sales Tax (local label for PST) + * RST Retail Sales Tax (local label for PST) */ class CanadaTaxTypeResolver implements TaxTypeResolverInterface { @@ -40,15 +45,30 @@ public function resolve(TaxableInterface $taxable, Context $context) // The customer or the store is not in Canada. return []; } - - // Canadian tax types are matched by the customer address. - // If the customer is from Ontario, the tax types are for Ontario. + // Canadian tax types are divided in two separate levels: + // FEDERAL - GST and HST always apply between canadian stores and clients + // PROVINCIAL - PST, QST and RST only apply when the store is registered in the client's province $taxTypes = $this->getTaxTypes(); + $storeProvince = $storeAddress->getAdministrativeArea(); $results = []; foreach ($taxTypes as $taxType) { $zone = $taxType->getZone(); if ($zone->match($customerAddress)) { - $results[] = $taxType; + // Federal taxes (GST or HST) + if ($taxType->getGenericLabel() == 'gst' || $taxType->getGenericLabel() == 'hst') { + $results[] = $taxType; + } + // Provincial taxes (PST, QST, RST), where the store is registered + $storeRegistrationTaxProvinces = $context->getStoreRegistrations(); + // Add store's province of origin, as it should always be registered there + $storeRegistrationTaxProvinces[] = !in_array($storeProvince, $storeRegistrationTaxProvinces) ? $storeProvince : ''; + if (!empty($storeRegistrationTaxProvinces)) { + foreach ($storeRegistrationTaxProvinces as $province) { + if ($zone->getMembers()->first()->getAdministrativeArea() == $province) { + $results[] = $taxType; + } + } + } } } diff --git a/tests/Resolver/TaxRate/DefaultTaxRateResolverTest.php b/tests/Resolver/TaxRate/DefaultTaxRateResolverTest.php index 9413375..d764b8d 100644 --- a/tests/Resolver/TaxRate/DefaultTaxRateResolverTest.php +++ b/tests/Resolver/TaxRate/DefaultTaxRateResolverTest.php @@ -10,6 +10,8 @@ */ class DefaultTaxRateResolverTest extends TestCase { + private $resolver; + /** * {@inheritdoc} */ diff --git a/tests/Resolver/TaxType/CanadaTaxTypeResolverTest.php b/tests/Resolver/TaxType/CanadaTaxTypeResolverTest.php index adf340a..291e9bd 100644 --- a/tests/Resolver/TaxType/CanadaTaxTypeResolverTest.php +++ b/tests/Resolver/TaxType/CanadaTaxTypeResolverTest.php @@ -23,7 +23,7 @@ class CanadaTaxTypeResolverTest extends TestCase 'name' => 'Ontario HST', 'generic_label' => 'hst', 'tag' => 'CA', - 'zone' => 'ca_on_hst', + 'zone' => 'ca_on', 'rates' => [ [ 'id' => 'ca_on_hst', @@ -42,7 +42,7 @@ class CanadaTaxTypeResolverTest extends TestCase 'name' => 'Nova Scotia HST', 'generic_label' => 'hst', 'tag' => 'CA', - 'zone' => 'ca_ns_hst', + 'zone' => 'ca_ns', 'rates' => [ [ 'id' => 'ca_ns_hst', @@ -65,24 +65,24 @@ class CanadaTaxTypeResolverTest extends TestCase * @var array */ protected $zones = [ - 'ca_on_hst' => [ + 'ca_on' => [ 'name' => 'Ontario (HST)', 'members' => [ [ 'type' => 'country', - 'id' => '1', + 'id' => 'ca_on', 'name' => 'Canada - Ontario', 'country_code' => 'CA', 'administrative_area' => 'ON', ], ], ], - 'ca_ns_hst' => [ + 'ca_ns' => [ 'name' => 'Nova Scotia (HST)', 'members' => [ [ 'type' => 'country', - 'id' => '2', + 'id' => 'ca_ns', 'name' => 'Canada - Nova Scotia', 'country_code' => 'CA', 'administrative_area' => 'NS',