Often you will need to add sales tax or value added tax to your cart. In most cases the taxes that you charge will depend on the location of your customer, not your businesses jurisdiction. Furthermore, if your product or service is physically delivered to or rendered at a certain location, the taxes you charge will be specific to this location. In other words, the customer's shipping address influences the taxes to be applied, irrespective of their billing address. If you are a US online merchant selling into multiple states you generally need to charge sales tax when selling taxable goods or services into your "home" state or any other state for which you have a "sales tax nexus".

Taxes and fees are not included in the default cart view since the shipping location is often established later, during the checkout process. In order to see the fees you must call the cart's show_cart_summary method. Here is the signature of this method:

function show_cart_summary($deliver_to_country,$deliver_to_state='')

Base Fee Handling

Default fee handing is set up in the system class called cart_fees_base. This base class supports taxes for several jurisdictions such as:

There is also a generic fee method that can be used for countries that charge a standard tax rate throughout the country.

Extending cart_fees_base

Since the supplied cart_fees_base class is not intended to support taxes and fees in every country you may need to extend this class to add rules specific to your location. Rather than changing cart_fees_base directly it is better to extend this so that if you install a new version of the GenHelm framework you do not have to reapply your changes. 

Configuring Fees

To configure fees for your site you must define a class named cart_fees which extents the system supplied class cart_fees_base or an alternative class which implements fees required by your business. This class must define a method named get_fees which receives the cart object as a parameter and returns a list of fees. Normally, the cart_fees class is defined at the site level, not the system level. This is because each site may have unique requirements in terms of taxes and fees. When possible, try to isolate rates within the system classes so that they can be shared across all sites. This will reduce the maintenance effort when government regulated rates change.

You will use the php_class model to generate your cart_fees class.

Sample cart_fees class

See the code examples below to build the get_fees method according to your country and requirements.

tax_code Values

Recall that one of the base properties of every cart item is a field called tax_code. This field can be used to apply special tax rules to certain cart items. If you assign the value 'zero' to a cart item, it will be excluded from the normal tax calculation. Different tax codes apply to different countries or trading blocks. Generally, you will need a separate tax code for each different rate of taxation associated with the products or services sold by your online store.

Miscellaneous Fee Examples

Certain methods of cart_fees_base allow you to add fees that are independent of tax rules. These are described next.

Shipping and Handling

Shipping and handling can be added to your cart as a item or as a fee. If you are charging taxes on the items in your cart and if the shipping charges are taxable you should add the shipping fee before adding the tax-related fees. If you want the shipping fee to appear before the tax fees without having tax applied to the shipping charge use the other_fee method described below.

function get_fees($cart){
  	// Shipping is a flat fee of $25.75
	$this->shipping($cart, 29.75, 'Shipping and Handling');
	return $this->fee;
}

Other Fees

The other_fee method can be used to apply any miscellaneous fee to your cart. Taxes will not be applied to other fees. If you require other fees that are taxable you should add them as static cart items rather than using the cart_fees module.

function get_fees($cart){
	$this->other_fee($cart, 10.00, 'admin', 'Administration Fee'){
	$this->other_fee($cart, 5.75, 'access', 'Access Fee'){
	return $this->fee;
}

Sales Taxes and VAT or GST

GST/VAT Exemptions

Some countries that normally charge GST or VAT offer exemptions to certain businesses or individuals. For example, Canadian First Nations' businesses are eligible for GST payment exemptions. In order to support such an exemption you can call the following cart method:

$cart->set_gst_vat_exempt(true);

When a cart has been designated as exempt in this way, GST and/or VAT charges won't be applied regardless of which tax_codes are specified on the cart items. If exemptions only apply to certain items in the cart you should set the tax_code for these items to 'zero' (instead of calling the cart's set_gst_vat_exempt method).

Normally you will require a separate internal order form that can be used to set this tax exempt status. This is needed to prevent non-exempt buyers from claiming an exemption.

Sales Tax Exemptions

In some situations buyers may be excluded from having to pay provincial or state sales taxes. Normally, to be eligible for such an exemption the buyer would need to furnish a vendor permit number or some other tax number. This number can be assigned to the cart using the following code:

$cart->set_state_prov_tax_exempt_number($buyer_tax_number);

By doing so, sales taxes will not be collected for this buyer.

Setting Your Buyer's Location

Most taxes are applied based on where the goods or services are to be delivered. Therefore, before applying any taxes you must copy a portion of the shipping address of your buyer to your cart. If you are not actually shipping anything, for example if you are selling an online subscription, you would use your customer's billing address. To set the customer's location you must pass the country and optional state/province value to the cart's show_cart_summary method.

// Obtain the order details, including taxes, as an HTML table
$order_summary = $cart->show_cart_summary($_SESSION['shipping_country'],$_SESSION['shipping_state_or_province']);

You should always pass the long form of these values, as opposed to abbreviated state codes for example. The case is not important. Although the state is optional, it is required if the selected tax calculation utilizes the state or province value.

Setting Your Location

Certain taxes will vary depending on whether the seller has a physical presence in the buyer's jurisdiction or is obliged to collect sales tax in the location where your goods and services are being delivered. When dealing with tax calculations there are a couple of methods you should call first to specify your location as the seller. For example, if your company is based in New York state you should perform the following call before calling any tax related calculations:

$this->set_seller_country('United States');
$this->set_seller_state_prov('New York');

If your company has "nexus" in New Jersey and Pennsylvania as well you should pass an array including all of the states for which state taxes apply.

$this->set_seller_country('United States');
$this->set_seller_state_prov(array('New Jersey','New York','Pennsylvania'));

If you must collect taxes in all states, you can specify an '*' as the state name rather than listing all states.

The following sections show examples of how you might apply fees in various jurisdictions.

US State Taxes

Note that there is no built-in support for local taxes applied at the city or county level. If this is required you will need to implement this on your own.

The following function would be used to collect state taxes in all states. If certain items in the cart are not subject to state taxes, these can be assigned a tax_code of 'zero'.

function get_fees($cart){
	$this->set_seller_country('United States');
	$this->set_seller_state_prov('*'); // Collect taxes in all states
	$this->sales_tax($cart); // Calculate the taxes
	return $this->fee;
}

European Union VAT

VAT charges apply when one EU country sells taxable items to domestic buyers or when delivering goods or services to other EU countries.  EU VAT rates are supplied in the system php_array_data definition named eu_vat_rates. This definition defines the following rates for each EU country.

When adding items to your cart, you must assign the tax_code property according to the rate at which the item should be taxed. If the tax_code is not assigned, or if it does not match one of the codes listed above, the standard tax rate will be applied to the item. Here we see an example of the cart_fees class' get_fees function for a seller in Germany.

function get_fees($cart){
	$this->set_seller_country('Germany');
  	// VAT number is optional. If supplied this will appear on the invoice
	$cart->set_gst_vat_number('#123456789');
	$this->eu_vat($cart); 
	return $this->fee;
 }

UK VAT

UK VAT is charged for goods and services sold domestically by UK merchants. Supported tax_code values are:

Any cart items that are not assigned one of these tax codes will be taxed at the standard rate. Here is an example of the UK VAT fee setup.

function get_fees($cart){
  	// VAT number is optional. If supplied this will appear on the invoice
	$cart->set_gst_vat_number('GB123456789');
	$this->uk_vat($cart); 
	return $this->fee;
 }

Canada Sales Tax

Canadian provinces may charge a combination of GST/HST and provincial sales tax. GST is always charged according to the rate associated with the province of delivery. If your business has a physical presence in this province you are also obliged to charge provincial sales tax for provinces that charge such a tax. If your business sells into the province of Quebec, you may also need to collect QST even if you don't have a physical location in Quebec. This will depend on your Quebec sales volume.

If your business is located in a province that does not charge provincial sales tax (and does not meet the threshold for collecting QST) your fee setup will generally look like this:

function get_fees($cart){
	$this->set_seller_country('Canada');
	$this->set_seller_state_prov('Alberta');
	$cart->set_gst_vat_number('#12345 1234');
	$this->canada_gst($cart); // Charge GST
	return $this->fee;
}

In this next example, we show the setup for an Ontario based company that is obliged to collect Quebec Sales Tax. Notice that Quebec is listed as one the the seller's states and in addition to calling canada_gst to collect GST there is also a call to sales_tax which will add the QST if the buyer is in Quebec.

function get_fees($cart){
	$this->set_seller_country('Canada');
	$this->set_seller_state_prov(array('Ontario','Quebec'));
	$cart->set_gst_vat_number('#12345 1234');
	$this->canada_gst($cart); // Charge GST
	$this->sales_tax($cart); // QST
	return $this->fee;
}

If your business has a physical presence in every province that levies a provincial sales tax, your fee setup would look like this:

function get_fees($cart,'gst'){
	$this->set_seller_country('Canada');
	$this->set_seller_state_prov('*');
	$cart->set_gst_vat_number('#12345 1234');
	$this->canada_gst($cart); // Charge GST
	$this->sales_tax($cart); // Provincial tax
	return $this->fee;
}

Notice in the above example we pass the code that we want the GST to be stored under (within the fees table). By default, this would be dependent on the GST rate that is levied so it would otherwise be stored under either 'gst', 'hst' or 'on hst'. This is important if you want to ask the cart for the total amount of a certain fee (see Cart Fee Retrieval below).

If your business sells items that are not subject to GST and/or Provincial Sales Tax, you should assign one of the following tax_codes to these items:

Australia

This example shows the typical setup for Australian companies.

function get_fees($cart){
	$this->set_seller_country('Australia');
	$cart->set_gst_vat_number('51 824 753 556');
	$this->australia_gst($cart); // Charge GST
	return $this->fee;
}

New Zealand

This example shows how New Zealand based companies should add GST to their cart.

function get_fees($cart){
	$this->set_seller_country('New Zealand');
	$cart->set_gst_vat_number('123-456-789');
	$this->new_zealand_gst($cart); // Charge GST
	return $this->fee;
}

Generic Tax Collection

If your country is not listed in the examples above, and you wish to collect a fixed VAT like tax, you may be able to use the generic method shown below:

function get_fees($cart){
	$this->set_seller_country('Israel');
	$cart->set_gst_vat_number('123456789');
  	// Pass the cart, the internal code, the external name and the rate
	$this->general($cart,'vat','VAT Tax',.17){
	return $this->fee;
}

Unsupported Countries

If your tax situation is not specifically supported you should review the code in the supplied cart_fees_base class and find a tax calculation that is similar to the one you require and then extend this class to include methods to support your requirements. 

Cart Fee Retrieval

You can call methods of the cart to retrieve fees levied (provided the cart_summary method has been called). Here we show how you could determine the total fees levied by iterating through all of the fees.

$fees = $cart->get_fees();
$total_fees = 0;
if ($fees) {
  foreach ($fees as $fee) {
	$total_fees += $fee['total']; // Other keys are rate, rate_desc, description
  }
}

Use the get_fee method to get the total charge for the supplied fee. If you don't pass a parameter to this method it returns the total of all fees (this is easier that the iteration method shown above).

$shipping = $cart->get_fee('shipping');
$gst = $cart->get_fee('gst');
$all_fees = $cart->get_fee();

Ecommerce Help Index

E-Commerce Overview Features and components used to build an online store.
Cart Items Defining products and services.
Shopping Cart Interacting with a shopping cart.
Working with Text Files How to store and process transactional data using text files.
Working with Databases Saving and retrieving database table data.
Transaction Numbers Generating identifiers for invoices and other transactions.
Taxes and Fees Configuring sales taxes and other cart fees.
Saving Customer Information Reading and writing customer information.
Accounting Data Managing account records.
Collecting Payments Processing credits cards as order payments.