Bakery for Canada

sky writer

In an effort to incorporate Canada's confusing tax laws into the Bakery WITHOUT affecting the module for those operating outside of Canada, I added a couple of checks for the $setting_shop_country so only those shops with Canada 'CA' set as their "Shop Country" will run the new code.  I hope this helps someone.  I welcome any feedback or improvements to my code.  Much credit to Jacobi for his guidance and expertise.

I have only tested this with Bakery v1.72 on WB 2.8.3 SP4

All changes take place in view_summary.php
~line 293
after:
// Convert state code to state name
add:
// Retain shipping state code for Canadian sales tax calculation
$shipping_state_code = $ship_state;


starting ~line 362
replace:
// CALCULATE ITEMS SALES TAX
// *************************

// Initialize vars
$sales_tax        = 0;
$f_tax_rate_array = array();

// Calculate items sales tax
for ($i = 1; $i <= sizeof($items); $i++) {
    if ($setting_tax_included == 'included') {
        // Calculate tax amount for prices including tax (brutto)
        $sales_tax = $sales_tax + $items[$i]['price'] * $items[$i]['quantity'] * $items[$i]['tax_rate'] / (100 + $items[$i]['tax_rate']);
    }
    else {
        // Calculate tax amount for prices excluding tax (netto)
        $sales_tax = $sales_tax + $items[$i]['price'] * $items[$i]['quantity'] / 100 * $items[$i]['tax_rate'];
    }
    // Get tax rate(s) for display
    $f_tax_rate_array[] = number_format($items[$i]['tax_rate'], 1);
}

with:
// CALCULATE ITEMS SALES TAX
// *************************

// Initialize vars
$sales_tax        = 0;
$f_tax_rate_array = array();

// Check if Shop Country is Canada
if ($setting_shop_country=='CA') {
    // Canadian Shop - Check if there is a shipping address
    if (!is_null($shipping_state_code)) {
     $shipping_prov_code = $shipping_state_code;
     }
    else {
     $shipping_prov_code = $cust_state_code;
     }
    $gst_ca = array("AB","BC","SK","MB","QC","YT","NT","NU");
    $hst_ca = array("ON","NL","NB");
   
    // Calculate Canadian tax on total order based on shipping destination
    for ($i = 1; $i <= sizeof($items); $i++) {
// Calculate items Canadian sales tax
    if(in_array($shipping_prov_code, $gst_ca))
        {$sItemTaxRate[$i] = 5;}
    elseif(in_array($shipping_prov_code, $hst_ca))
        {$sItemTaxRate[$i] = 13;}
    elseif($shipping_prov_code == "PE")
       {$sItemTaxRate[$i] = 14;}
    elseif($shipping_prov_code == "NS")
       {$sItemTaxRate[$i] = 15;}
    else {
    $sItemTaxRate = $items[$i]['tax_rate'];
    }

if ($setting_tax_included == 'included') {

        // Calculate tax amount for prices including tax (brutto)
      $sales_tax = $sales_tax + $items[$i]['price'] * $items[$i]['quantity'] * $sItemTaxRate[$i] / (100 + $sItemTaxRate[$i]);
          }


   else {
      // Calculate tax amount for prices excluding tax (netto)
      $sales_tax = $sales_tax + $items[$i]['price'] * $items[$i]['quantity'] / 100 * $sItemTaxRate[$i];
   }

   // Get tax rate(s) for display
   $f_tax_rate_array[] = number_format($sItemTaxRate[$i], 1);
    }
}
else{
    // Calculate items sales tax
    for ($i = 1; $i <= sizeof($items); $i++) {
    if ($setting_tax_included == 'included') {
        // Calculate tax amount for prices including tax (brutto)
        $sales_tax = $sales_tax + $items[$i]['price'] * $items[$i]['quantity'] * $items[$i]['tax_rate'] / (100 + $items[$i]['tax_rate']);
    }
    else {
        // Calculate tax amount for prices excluding tax (netto)
        $sales_tax = $sales_tax + $items[$i]['price'] * $items[$i]['quantity'] / 100 * $items[$i]['tax_rate'];
    }
    // Get tax rate(s) for display
    $f_tax_rate_array[] = number_format($items[$i]['tax_rate'], 1);
    }
}

That takes care of the item tax based on the shipping destination.


Now for the shipping tax based on shipping destination:
starting ~line 743
replace:
// CALCULATE SHIPPING SALES TAX
// ****************************

// Calculate tax amount for shipping including tax (brutto)
if ($setting_tax_included == 'included') {
    $sales_tax_shipping = $shipping * $setting_tax_rate_shipping / (100 + $setting_tax_rate_shipping);
}
else {
    // Calculate tax amount for shipping excluding tax (netto)
    $sales_tax_shipping = $shipping / 100 * $setting_tax_rate_shipping;
}

with:
// CALCULATE SHIPPING SALES TAX
// ****************************

// Check if Shop Country is Canada
if ($setting_shop_country=='CA') {
// Calculate Canadian shipping tax based on shipping destination
    $ship_tax_prov_code = $shipping_prov_code;
   
    // Calculate shipping Canadian sales tax
    if(in_array($ship_tax_prov_code, $gst_ca))
        {$sShipTaxRate = 5;
     }
    elseif(in_array($ship_tax_prov_code, $hst_ca))
        {$sShipTaxRate = 13;
     }
    elseif($ship_tax_prov_code == "PE")
       {$sShipTaxRate = 14;
     }
    elseif($ship_tax_prov_code == "NS")
       {$sShipTaxRate = 15;
     }
   
    else {
    $sShipTaxRate = $setting_tax_rate_shipping;
    }

// Calculate tax amount for shipping including tax (brutto)
if ($setting_tax_included == 'included') {
    $sales_tax_shipping = $shipping * $sShipTaxRate / (100 + $sShipTaxRate);
}
else {
    // Calculate tax amount for shipping excluding tax (netto)
    $sales_tax_shipping = $shipping / 100 * $sShipTaxRate;
}
}
else {
// Calculate tax amount for shipping including tax (brutto)
if ($setting_tax_included == 'included') {
    $sales_tax_shipping = $shipping * $setting_tax_rate_shipping / (100 + $setting_tax_rate_shipping);
}
else {
    // Calculate tax amount for shipping excluding tax (netto)
    $sales_tax_shipping = $shipping / 100 * $setting_tax_rate_shipping;
}
}

sky writer

Quotei use in_array(), array_search doesnt give the key No == 0, it sends false for that
I missed that line, sorry, and thank you.  I don't understand this part - "key No == 0, it sends false for that".  But I will do some homework and figure it out.

QuoteTip: make a renamed copy from this view_summary.php (maybe view_summary_canada .php) and let it stay in the bakery-folder as a backup. so that you dont overwrite your work in the next upgrade.
Wise advice, thank you!

Gast

Quote from: sky writer on October 13, 2015, 03:23:40 AM
Everything worked except when the customer's province was Ontario (ON), then no tax was added (it should have been 13%).  I thought it might be because it matched the shop_state, but then I changed the shop_state to another province and still Ontario did not show the proper tax of 13%.  Can't figure that out.
i write this yesterday - use in_array() instead of array_search()

Quote from: sky writer on October 13, 2015, 03:23:40 AMIs the key the "i" variable in $sItemTaxRate[$i]?

[i.] is a counter for the loop's btw for the items in the for-loop here
// Calculate items sales tax
for ($i = 1; $i <= sizeof($items); $i++) {


it counts the different kind of articles. $items is a big array with all item datas from the items in the basket. every array-part has the datas for this one item (quantity, price, tax-rate etc)
if you dont use the counter [i.] to split the item array, the next loop for the next item use the item datas from the last loop


Quote from: sky writer on October 13, 2015, 03:23:40 AM
Now I just have to make the tax on shipping act the same way (tax on shipping based on shipping province).  Can I do this in the view_summary.php file as well, or do I have to go further?

i see, you solved the problem ;-)  (Y)
Tip: make a renamed copy from this view_summary.php (maybe view_summary_canada.php) and let it stay in the bakery-folder as a backup. so that you dont overwrite your work in the next upgrade.

sky writer

I seem to have the CANADIAN shipping tax based on shipping destination working now as well.

~ line 735
// CALCULATE SHIPPING SALES TAX
// ****************************

// Calculate Canadian shipping tax based on shipping destination
    $ship_tax_prov_code = $shipping_prov_code;
   
    // Calculate shipping Canadian sales tax
    if(in_array($ship_tax_prov_code, $gst_ca))
        {$sShipTaxRate[$i] = 5;
     }
    elseif(in_array($ship_tax_prov_code, $hst_ca))
        {$sShipTaxRate[$i] = 13;
     }
    elseif($ship_tax_prov_code == "PE")
       {$sShipTaxRate[$i] = 14;
     }
    elseif($ship_tax_prov_code == "NS")
       {$sShipTaxRate[$i] = 15;
     }
   
    else {
    $sShipTaxRate = $setting_tax_rate_shipping;
    }

// Calculate tax amount for shipping including tax (brutto)
if ($setting_tax_included == 'included') {
    $sales_tax_shipping = $shipping * $sShipTaxRate[$i] / (100 + $sShipTaxRate[$i]);
    //$sales_tax_shipping = $shipping * $setting_tax_rate_shipping / (100 + $setting_tax_rate_shipping);
}
else {
    // Calculate tax amount for shipping excluding tax (netto)
    $sales_tax_shipping = $shipping / 100 * $sShipTaxRate[$i];
//    $sales_tax_shipping = $shipping / 100 * $setting_tax_rate_shipping;
}


Many thanks Jacobi for your guidance.

sky writer

Here is how far I got:
// CALCULATE ITEMS SALES TAX
// *************************

// Initialize vars
$sales_tax        = 0;
$f_tax_rate_array = array();


// Calculate Canadian tax based on shipping destination

        if (!is_null($shipping_state_code)) {
            $shipping_prov_code = $shipping_state_code;
            }
        else {
            $shipping_prov_code = $cust_state_code;
            }
        $ca_gst = array("BC","AB","SK","MB","QC","YT","NT","NU");
        $ca_hst = array("ON","NL","NB");
           
        if(array_search($shipping_prov_code, $ca_gst))
                {$sItemTaxRate = 5;
            }
        elseif(array_search($shipping_prov_code, $ca_hst))
                {$sItemTaxRate = 13;
            }
        elseif($shipping_prov_code == "PE")
              {$sItemTaxRate = 14;
            }
        elseif($shipping_prov_code == "NS")
              {$sItemTaxRate = 15;
            }
       
        else {
        $sItemTaxRate = $items[$i]['tax_rate'];
        }

// Calculate items sales tax
for ($i = 1; $i <= sizeof($items); $i++) {

if ($setting_tax_included == 'included') {
        // Calculate tax amount for prices including tax (brutto)
               $sales_tax = $sales_tax + $items[$i]['price'] * $items[$i]['quantity'] * $items[$i]['tax_rate'] / (100 + $sItemTaxRate);
//        $sales_tax = $sales_tax + $items[$i]['price'] * $items[$i]['quantity'] * $items[$i]['tax_rate'] / (100 + $items[$i]['tax_rate']);
            }

    else {
        // Calculate tax amount for prices excluding tax (netto)
       
        $sales_tax = $sales_tax + $items[$i]['price'] * $items[$i]['quantity'] / 100 * $sItemTaxRate;
//        $sales_tax = $sales_tax + $items[$i]['price'] * $items[$i]['quantity'] / 100 * $items[$i]['tax_rate'];
    }
   
    // Get tax rate(s) for display
    $f_tax_rate_array[] = number_format($sItemTaxRate, 1);
//    $f_tax_rate_array[] = number_format($items[$i]['tax_rate'], 1);
}


Everything worked except when the customer's province was Ontario (ON), then no tax was added (it should have been 13%).  I thought it might be because it matched the shop_state, but then I changed the shop_state to another province and still Ontario did not show the proper tax of 13%.  Can't figure that out.

Your code works.  Is the key the "i" variable in $sItemTaxRate[$i]?
My shop_country is Canada
shop_state is Ontario
Tax: Shop Country
Tax Rate Product: 0% 0% 0%
Prices including tax: No

This shop will mainly ship to Canada, but also anywhere else.  But no tax is charged when shipping outside Canada.  Which seems to work with the code I have in place.

Now I just have to make the tax on shipping act the same way (tax on shipping based on shipping province).  Can I do this in the view_summary.php file as well, or do I have to go further?

Gast

if i understand everything correct, here my version
but it works for canada only - do you sell products to other country too??


my settings in the shop:
Shop Land == Canada
Shop State = Alberta
Tax == Shop Land
Tax rate == 0%
Price inclusive Tax? == NO

startet at line ~364 of the view_summary.php

// CALCULATE ITEMS SALES TAX
// *************************

// Initialize vars
$sales_tax        = 0;
$f_tax_rate_array = array();

// Calculate tax for Canadian Shop Shipping to Canadian Province/Territory
      if (!empty($shipping_state_code)) {
         $shipping_prov_code = $shipping_state_code;
         }
      else {
         $shipping_prov_code = $cust_state_code;
         }
         $can_gst = array("AB","BC","SK","MB","QC","YT","NT","NU");
         $can_hst = array("ON","NL","NB");


// Calculate items sales tax
for ($i = 1; $i <= sizeof($items); $i++) {

      if(in_array($shipping_prov_code, $can_gst))

            {$sItemTaxRate[$i] = 5;
         }
      elseif(in_array($shipping_prov_code, $can_hst))
            {$sItemTaxRate[$i] = 13;
         }
      elseif($shipping_prov_code == "PE")
           {$sItemTaxRate[$i] = 14;
         }
      elseif($shipping_prov_code == "NS")
           {$sItemTaxRate[$i] = 15;
         }

      else {
      $sItemTaxRate = $items[$i]['tax_rate'];
      }

if ($setting_tax_included == 'included') {

        // Calculate tax amount for prices including tax (brutto)
      $sales_tax = $sales_tax + $items[$i]['price'] * $items[$i]['quantity'] * $sItemTaxRate[$i] / (100 + $sItemTaxRate[$i]);
          }


   else {
      // Calculate tax amount for prices excluding tax (netto)

      $sales_tax = $sales_tax + $items[$i]['price'] * $items[$i]['quantity'] / 100 * $sItemTaxRate[$i];

   }

   // Get tax rate(s) for display
   $f_tax_rate_array[] = number_format($sItemTaxRate[$i], 1);
}


i use in_array(), array_search doesnt give the key No == 0, it sends false for that

testet with all your provinces with two articles with different item price


Gast

#6
i try to implemented your code from the last post. Did it work for you? if yes - whats your main bakery settings?

i use for a test
Shop Land == Canada
Shop Province / State == Manitoba (or others)

i try different tax setting, Shop Land, Shop State, Nothing
Tax Rate == 0%, 13%, 0%

My Customer Adress data in the adress form
Country == Canada
State == different to the shop state in my settings

if everything works for you, maybe i've a problem to understand
but if its not work, i'm sure, that the order in the code is the problem

i'll wait for your answer before i write a new (wrong) code

Gast

looks good, but its difficult to test it  for me. i know nothing about your tax-system in CA, so its not possible to say, this output is correct or not (for me), but i like the way  (Y)

maybe its possible for a next bakery-version to work with more arrays in the language/state-files
one for the tax-rate in this state/province
one for the shipping-cost in this state/province

or (more work) another table in the database and two new subpages in the bakery settings  like "advanced state settings"

One point
in Germany we have actual 3 possible tax-rates. 19% for the most normal products, 7% for some special products (books, papers, food etc) and 0%. If you use two or more of this tax rates, its needed to show the sum of the tax in extra lines on the invoice
Example with fictive sum's
Summary without Tax = 100,00 Euro
2 Articles with Tax 19% -> Taxsum 19% = 36 Euro
2 Articles with Tax 7% -> Taxsum 7% = 14,86 Euro
Tax for shipping 19% = 19,00 Euro

do you need something like that also in canada?
i build the output like that for a german shop and it was a lot of work to show the different tax sum in the invoice and in the emails

sky writer

Thank you for the push Jacobi.  I tried to follow your lead.  I'm not quite there yet, but I thought I would share my amended view_summary.php file, before I got myself into too much trouble.

Something I am not sure how to work in is that I need to be able to say an individual item does not have any tax, even if it is going to be shipped to one of the provinces in Canada.  In the current version o Bakery, I had set a tax rate of 0.0%, then one with 13%.  That way I could choose the 0% option to show no tax on an an item.  But with this new code checking to see if there is a ship_state or cust_state, the only way the default 0/13% get used is if no matching state (province) is found.  But of course a match will be found and so the corresponding tax rate for that province will be used.  Hope this makes sense.

Anyway, here are the code changes to view_summary.php that I have made:
~ line 294

// Retain shipping state code for Canadian sales tax calculation
    $shipping_state_code = $ship_state;



starting ~line 363

// CALCULATE ITEMS SALES TAX
// *************************

// Initialize vars
$sales_tax        = 0;
$f_tax_rate_array = array();


// Calculate tax for Canadian Shop Shipping to Canadian Province/Territory
      if (!empty($shipping_state_code)) {
         $shipping_prov_code = $shipping_state_code;
         }
      else {
         $shipping_prov_code = $cust_state_code;
         }
         $can_gst = array("BC","AB","SK","MB","QC","YT","NT","NU");
         $can_hst = array("ON","NL","NB");


// Calculate items sales tax
for ($i = 1; $i <= sizeof($items); $i++) {

if ($setting_tax_included == 'included') {
        // Calculate tax amount for prices including tax (brutto)
      $sales_tax = $sales_tax + $items[$i]['price'] * $items[$i]['quantity'] * $items[$i]['tax_rate'] / (100 + $items[$i]['tax_rate']);
          }


   else {
      // Calculate tax amount for prices excluding tax (netto)
     
     
      if(array_search($shipping_prov_code, $can_gst))
            {$sItemTaxRate = 5;
         }
      elseif(array_search($shipping_prov_code, $can_hst))
            {$sItemTaxRate = 13;
         }
      elseif($shipping_prov_code == "PE")
           {$sItemTaxRate = 14;
         }
      elseif($shipping_prov_code == "NS")
           {$sItemTaxRate = 15;
         }
     
      else {
      $sItemTaxRate = $items[$i]['tax_rate'];
      }
      $sales_tax = $sales_tax + $items[$i]['price'] * $items[$i]['quantity'] / 100 * $sItemTaxRate;
//      $sales_tax = $sales_tax + $items[$i]['price'] * $items[$i]['quantity'] / 100 * $items[$i]['tax_rate'];
   }
   
   // Get tax rate(s) for display
   $f_tax_rate_array[] = number_format($items[$i]['tax_rate'], 1);
}


I welcome any feedback

Gast

Quote from: sky writer on October 11, 2015, 06:12:24 PM
My question is, is it possible to "do something" based on the setting of an Item Option being added to an item.  More specifically, if "Canada Tax is added to an item, could we check for the shipping address for the order, and then calculate the item and shipping tax based on that provinces tax rates?

its not possible without complex modifications, because you cannot use the implemented tax-function.
but its possible in the view_summary.php. there you need the selected province from the adress datas and with this informations you can build a intern if -> elseif -> else -> Switch. In the else-part must be the original-code to calculate the tax for other countrys

at first.... make a copy of the original view_summary.php

a simple example
view_summary.php // line 370ff.
i'm not sure, where you define the province and what is standard, if nobody select a province. normalize your need $cust_state instead of your province in the follow code (cust_country is the state like canada or german, cust_state is the province
see also the different tax rates in the code. If you have 4 provinces, you need one IF and 3 elseif

if ($setting_tax_included == 'included') {
        // Calculate tax amount for prices including tax (brutto)
        if(your province == "AAAAA")
          {$sItemTaxRate = 19;
       }
       elseif(your province == "BBBB")
          {$sItemTaxRate = 17;
      }
      elseif(your province == "CCCC")
          {$sItemTaxRate = 15;
      }
       else
     {$sItemTaxRate = $items[$i]['tax_rate']}
        $sales_tax = $sales_tax + $items[$i]['price'] * $items[$i]['quantity'] * $items[$i]['tax_rate'] / (100 + $sItemTaxRate);
    }


in the original-Code you have there three possible variants, with tax, without tax and formated tax value. if the privinces are not in the questions, it takes the original-code with the defined tax rate from the item settings


this three variants using $items[$i]['tax_rate']. here you need the $sItemTaxRate

this solution look's, that the selected province name == the hardcoded variable. if yes, it set the tax to the hardcoded value in this part

sky writer

In writing my OP, I started toying with the idea of using the Item Options as a possible work-flow, which would have the least impact on the current Bakery module.  I tried adding an Item Option of
"Canada Taxable", with a value of "yes".  So, this could be added to the item in the backend, or not, depending on whether the item is taxable.  This way the current tax EU friendly implementation would stay as is.

In the current bakery work-flow, this would show a "Canada Taxable" drop-down field with "yes", and no other choice.  I would prefer this was a hidden variable, but I'm not going to be picky.  Getting the desired end result is the most important thing at this time.

My question is, is it possible to "do something" based on the setting of an Item Option being added to an item.  More specifically, if "Canada Tax is added to an item, could we check for the shipping address for the order, and then calculate the item and shipping tax based on that provinces tax rates?

sky writer

I really value the streamlined implementation of an e-commerce solution into WB.  I appreciate all the time and effort which has gone into building and maintaining the Bakery module.  That said, sadly, in it's present form, Bakery is totally useless for anyone operating an online store in Canada.  Canadian sales and shipping tax laws are beyond the scope of the present tax implementation.  I truly want to try to fix this deficiency.

If you're interested in seeing a brief description (and map) of the taxes in Canada, here is a good resource - https://dandelionwebdesign.com/canadian-taxes/

But in a nutshell, we have three possible taxes, PST, GST and HST.  Every province/territory has it's own tax amount.  And the tax you charge for sales and shipping online is not based on where your store is located, it is charged at the rate in the province/territory where the item is being shipped.  Yes, it sounds like a nightmare, but it's our reality.  I mentioned in another thread that I developed and managed an online store for a client years ago on OScommerce and it was fully able to handle the Canadian Tax situation.

I realize that Bakery for Canada is not going to be priority to anyone outside the country, and that you have your EU tax zone implementation working for you.  But to make this module and CMS more attractive to a wider audience, this extension would help.

If nothing else, I am going to attempt to create a working Canadian bakery for myself and my future clients.  But if this implementation might be of interest to others, I would invite you to please provide any input you can.  Having the Canadian Tax environment truly incorporated would be awesome.

To that end, I am asking if anyone could help me on my quest by pointing me at the main files I should be "hacking" in order to make the following possible.

My plan is to follow the work-flow used in OScommerce.  If anyone has a better idea, please make it known, as I am not set in my ways, I just want something that will work and be helpful to others.  In OScommerce the implementation seems simple during the "Add Item" stage:

       
  • Each item in the shop would have a simplfied "Taxable" "yes" or "no" radio button instead of the current dropdown tax blanket tax choice.
  • Then in the final tax calculation, we would have to get the "shipping" province/territory and then calculate the item and shipping tax based on that province/territory
The real heavy lifting is done in the tax setup stage, which I would envision being set by a new button on the Admin modify page, like the "Item Options" or "Order Administration".  There would have to be "Tax Zones" and "Tax Rates" set.

That's all I will say for now.  I am hopeful to get some hint of guidance to set me on my way.

Thank you.