Cart Calculation

Overview

Cart Calculation is an internal service that is called when you make a GET cart request to the Cart service. This service provides a set of features that performs basic arithmetic calculations according to the business rules. Using standard REST calls, the service calculates the item cost, shipping cost, tax, discount, fees, and total for the cart.

The current implementation of the Cart Calculation service does not support multi-currency scenarios.

There are two tax service providers that you can use to complete the cart calculation, Avalara Tax and Tax. In order to use the specific tax service, you need to first set up and configure the tax service in the Site service. To set up the Avalara Tax service, see Set Up Avalara. To set up the Tax service, see Tax Configuration.


API Reference

/{tenant}/calculation

/{tenant}/calculation

post

Calculate the cart. The response contains the item, discount, tax, and shipping calculation details.


Configuration

In order for the Cart Calculation service to know which fee service to call during the calculation process, you need to set up the fee service in the Site service.

Use the following link (provided by the Schema service) to configure the fee service: https://api.beta.yaas.io/hybris/schema/v1/priceless/siteFeeService

Request

  • Method: POST
  • Request URL: https://api.beta.yaas.io/hybris/site/v1/{tenant}/sites/main1/mixins
  • Example:
    {
     "feeService": {
        "serviceUrl":"https://fee-service.us-east.stage.internal.yaas.io/hybris",
        "active": true,
        "metadata": {
           "schema":"https://api.beta.yaas.io/hybris/schema/v1/priceless/siteFeeService"
        }
     }
    }
    

Response

  • Status code: 201
  • Example:
    {
      "id": "feeService",
      "link": "https://api.beta.yaas.io/hybris/site/v1/conference/sites/SuiteGetCartDetailsByCartIdAcceptanceSpec-canada/mixins/feeService"
    }
    


Cart Calculation Process

The Cart Calculation service is called whenever a GET cart request is made. You can also make a cart calculation request to get the total amount of the cart.

When you complete a cart calculation, it returns:

  • The total amount of each line item.
  • The number of items in the cart.
  • The subtotal of all the cart items.
  • The shipping information, including the shipping fee.
  • The tax amount (if applicable, it calculates the aggregated amounts).
  • The item fee amount (if applicable, it calculates the aggregated amounts including the tax).
  • The payment fee amount (if applicable, it calculates the aggregated amounts including the tax).
  • The discount amount.
  • The total amount of the cart.

Cart Calculation is dependent on three services: Site, Tax/Avalara Tax, and Shipping. Cart Calculation calls the Site service to retrieve the tax configuration, specifically the tax URL. The service then uses the tax URL to call the corresponding tax service (Avalara Tax or Tax) to calculate the tax for the items in the cart. Tax codes can be configured in the Tax service and used to assign different tax amounts to items. If there are different taxes applied to the cart, such as a standard tax rate and different tax codes, the service calculates the amount for the different taxes separately before adding all the totals together to give you a single tax total.

The way that discounts are applied to the cart depends on your tax service provider. You can apply multiple discounts to the cart. If you are using the Tax service as your tax provider, the discount can be applied either before or after the taxes are calculated. If you do not specify a calculation type for Tax, then the discount is applied before the taxes by default. If you're using Avalara Tax service, the discount is always applied proportionally across all of the items in the cart.

Cart Calculation also calls the Site service to retrieve the shipping configuration, specifically the shipping URL. It uses the URL to call the corresponding shipping configuration to retrieve the correct shipping fee based on the calculation type (ESTIMATION or QUOTATION). If you send nothing for the shipping attribute or ESTIMATION for the calculationType, the calculation returns an estimate of the shipping cost. To ensure that you calculate the actual shipping fee, you must include the calculationType (QUOTATION), zoneId, and methodId attributes in the request.

The cart total is the sum of the subtotal of all the items in the cart plus the shipping cost, tax, and discount(s).

Calculation methods

The following table shows how the cart total is calculated based on the various calculation methods.

Calculation TypeCart Total Calculation
Regulartotal = subtotal + item fee + shipping + payment fee
With taxtotal = subtotal + item fee + shipping + tax (on items, item fees, and shipping) + payment fee + payment fee tax
With inclusive (VAT) taxtotal = subtotal + item fee + shipping + payment fee
With discounttotal = subtotal - discount(s) + item fees + shipping + payment fees
With discount (before tax) and taxtotal = subtotal - discount(s) + item fee + shipping + tax (on discounted items, item fees, and shipping) + payment fee + payment fee tax *
With discount (after tax) and taxtotal = subtotal + shipping + tax (on items and shipping) - discount(s) **
With discount (after tax), tax and feetotal = subtotal + item tax - discount(s) + item fee + shipping + tax (on item fees and shipping) + payment fee + payment fee tax ***
With discount (before/after tax) and inclusive (VAT) taxtotal = subtotal + shipping - discount(s)
With discount (before/after tax), fee, and inclusive (VAT) taxtotal = subtotal - discount(s) + item fee + shipping + payment fee

* If the total discount(s) are greater than the subtotal, then the total = shipping + tax (on shipping).

** If the total discount(s) are greater than the subtotal + shipping + tax, then the total = 0.

** In case of an absolute discount amount with an item with a percentage fee, the fee is calculated by applying its percentage on the subtotal minus the amount of discount that is applied on the item. Since the discount is applied on item and the taxes, this means that a share of the discount is applied to the taxes and not considered into the percentage fee.

Keep in mind the following:

  • For VAT, the item fee and payment fee are always tax-inclusive, with or without the discount and/or shipping.
  • Currently discount is only supported on items at the cart level. This means that discounts are applied on all of the items in the cart. Discounts on fees, shipping, or a specific item is not supported.
  • Cart fee, shipping fee, and discount after fee is currently not supported.
  • For tax-exclusive, the shipping cost is based on the discounted item and item fee excluding the tax. For tax-inclusive (VAT), the shipping cost is based on the discounted item and item fee including the tax.
  • All monetary values returned at the end of the calculation has a precision of two decimal places using a roundup strategy. For example, a value of $19.755 is returned as $19.76. The Cart Calculation service receives the entire value (1.98374829) from other services, like Tax service, but the roundup strategy is only applied at the end of the calculation.

Malformed fees

A malformed fee is a fee whose data does not correctly or uniquely identify the identity of the fee. Since the Cart Calculation service is receiving the fee from a third party provider, it has some rules about what fee type it accepts from the fee service in order to perform the calculation. If a fee falls into one of the service's malformed scenarios, then this fee is corrected to use a default value of zero (0). This ensures that the fee has no impact on the cart calculation totals and it helps to serve as a visual cue that something may be wrong with the fee.

Supported fee types

The Cart Calculation service supports the following fee type values:

  • ABSOLUTE
  • ABSOLUTE_MULTIPLY_ITEMQUANTITY
  • PERCENT

If the fee type attribute is undefined or it does not match one of the three values, it is considered a malformed fee. See the following scenarios to see how malformed fees are handled during the cart calculation.

Malformed fee scenarios

The Cart Calculation service considers the following scenarios as malformed fees:

ScenarioFee Type AttributeFee Absolute AttributeFee Percentage Attribute
1Undefined/UnknownDefinedDefined
2Undefined/UnknownDefinedUndefined

In scenario #1, it is deduced that the fee is a percentage value if the fee type is undefined and therefore the fee percentage attribute is defined and fee absolute is undefined.

In scenario #2, the service cannot deduce the fee type if the fee type attribute is undefined and the fee absolute attribute is defined since it may still be a ABSOLUTE_MULTIPLY_ITEMQUANTITY fee.

In cases where the fee type attribute is unknown or undefined, it is assumed that the fee type is ABSOLUTE and the value defaults to zero (0).

When the fee type is defined and valid, but the fee value is undefined (for example, the fee percentage is set to -10, or the fee absolute is undefined), the value defaults to zero (0).


Fallback Implementation

If a calculation error occurs during a GET cart or within the checkout process, the Cart Calculation service supports a fallback implementation. The implementation determines whether the calculation returns an error message or a value if an error occurs. The fallback attribute can be set to true or false (default is true). If fallback is false, the calculation fails and an error message describing the failure is returned. If fallback is true, a value is returned based on the calculation that could be completed. The Cart Calculation service depends on values passed from the Site, Tax or Avalara Tax, and Shipping services.

<img style="width:350px;"src="img/fallbackdiagram.png">

Errors with tax

When there is an error with the tax, it might be because of the tax (Avalara or Tax) service or the Site service. The table below depicts which situations return an error message and which return a default value of zero for tax when the calculation is completed.

Fallback ValueService AvailabilityReturned Value
TrueSite service has an errortotalTax.amount is zero (0)
TrueSite service has no errors, but Tax service has an errortotalTax.amount is zero (0)
TrueSite does not existError message
FalseSite service has an errorError message
FalseSite service has no errors, but Tax service has an errorError message
FalseSite does not existError message

Errors with shipping

A situation could arise where the Shipping service has an error. The table below depicts whether an error message is returned or a default value for the shipping information is used.

ScenarioReturned Value
Shipping service has an errorshipping.fee is zero (0)
Shipping service isn't defined for the siteshipping.fee is zero (0)
Shipping service is defined for the site but the shipping URL is not definedError message


Calculate a Cart

Introduction

This tutorial shows you how to calculate the total of a cart using the Cart Calculation service.

Setup

The following sections show what you need to set up before you can execute any of the calls to this service.

Assertion

Define variable assert:

    assert = chai.assert;

Get access token

To perform any operations with a specific service, you always need an access token. For this purpose, create an API Client for the oAuth2 service:

    API.createClient('oAuth2Service',
    '/services/oauth2/v1/api.raml');

Now, get the token:

    tenant = projectIdPlaceholder;
    AccessToken = oAuth2Service.token.post({
      'client_id' : clientIdPlaceholder,
      'client_secret':clientSecretPlaceholder,
      'grant_type' : 'client_credentials',
      'token_type': 'Bearer',
      'scope': 'hybris.tenant='+tenant+ ' hybris.site_manage hybris.tax_manage hybris.shipping_manage'
    });

To ensure the calls are simple and the code is clean, you need to assign the id of the returned object to a variable:

    access_token = AccessToken.body.access_token;

Create an API client for the Cart Calculation service

    API.createClient('cartCalculationService',
    '/services/cartcalculation/v1/api.raml');

Create an API client for the Site service

    API.createClient('siteService',
    '/services/site/v1/api.raml');

Create an API client for the Shipping service

    API.createClient('shippingService',
    '/services/shipping/v1/api.raml');

Create an API client for the Tax service

    API.createClient('taxService',
    '/services/tax/v1/api.raml');

Create a site and establish the shipping zone and method

To complete a cart calculation, you need to first create a site for the cart to belong to.

    response = siteService.tenant(tenant).sites.post({
            "code": "canada",
          "name": "Canadian Site",
          "active": false,
          "default": false,
          "defaultLanguage": "en",
          "languages": [
            "en",
            "fr"
          ],
          "currency": "CAD",
          "homeBase": {
            "address": {
              "street": "Maisonneuve",
              "streetNumber": "999",
              "zipCode": "H3A 3L4",
              "city": "Montreal",
              "state": "Quebec",
              "country": "CA"
            }
          },
          "shipToCountries" : [
            "CA",
            "US"
          ],
          "shipping": [
              {
                  "id": "UPS",
                  "name": "UPS Shipping Service",
                  "serviceType": "urn:x-yaas:service:shipping",
                  "serviceUrl": "https://api.stage.yaas.io/hybris/shipping/v1",
                  "active": true
              }
          ],
          "tax": [
            {
              "id": "FLATRATE",
              "name": "Tax Service",
              "serviceType": "urn:x-yaas:service:tax",
              "serviceUrl": "https://api.stage.yaas.io/hybris/tax/v1",
              "active": true,
              "configuration": {
                "public": {
                  "rate": 5,
                  "code": "FRT",
                  "name": "flat rate tax",
                  "description": "The standard sales tax rate in Canada is 5%."
                },
                "restricted": null
              }
            }
          ]
        }, {
        headers: {
            'Authorization': 'Bearer ' + access_token,
            'Content-Type' : 'application/json'
        }
    });
    assert.equal(response.status, 201);
    response.body;

When you created the site, you established that there is a shipping charge. Now you need to define the zone and method for the shipping details.

        response = shippingService.tenant(tenant).site('canada').zones.post({
          "id": "NA",
          "name": "NA",
          "default": true,
          "shipTo": [
            "CA",
            "US"
          ]
        }, {
        headers: {
            'Authorization': 'Bearer ' + access_token,
            'Content-Type' : 'application/json',
              'Content-Language' : 'en_US'
        }
    });
    assert.equal(response.status, 201);
    response.body;
        response = shippingService.tenant(tenant).site('canada').zones.zoneId('NA').methods.post({
          "id": "UPS",
          "name": "UPS",
              "active": true,
          "fees": [
            {
              "minOrderValue": {
                "amount": "0",
                "currency": "CAD"
              },
              "cost": {
                "amount": "10",
                "currency": "CAD"
              }
            },
            {
              "minOrderValue": {
                "amount": "500",
                "currency": "CAD"
              },
              "cost": {
                "amount": "5",
                "currency": "CAD"
              }
            },
              {
              "minOrderValue": {
                "amount": "1000",
                "currency": "CAD"
              },
              "cost": {
                "amount": "1",
                "currency": "CAD"
              }
            }
          ]
        }, {
        headers: {
            'Authorization': 'Bearer ' + access_token,
            'Content-Type' : 'application/json',
              'Content-Language' : 'en_US'
        }
    });
    assert.equal(response.status, 201);
    response.body;

Create a tax code

Using the Tax service, create a tax code that will be used in this tutorial.

    response = taxService.tenant(tenant).tax.codes.post({
          "code": "TAX_SPECIFIC_001",
          "siteCode": "canada",
          "name": "Canada specific tax",
          "rate": 25,
          "yrn": "urn:yaas:hybris:tax:taxCode:{tenant};5405e6419a2ef90c6077afdf"
           },{
        headers: {
            'Authorization': 'Bearer ' + access_token,
            'Content-Type' : 'application/json'
        }
    });
    assert.equal(response.status, 201);
    taxCodeId = response.body.id;
    response.body;

Calculate the cart

After you have defined the components that are needed to complete a cart calculation, you can calculate the items in the cart.

    response = cartCalculationService.tenant(tenant).calculation.post({
            "cartId":"SmithCart001",
            "currency":"CAD",
            "siteCode":"canada",
            "fallback":false,
            "items":[
              {
                "itemId":"53599d5ae4b08806bb0e2771",
                "productId":"CanonSLR",
                "quantity":2,
                "taxCode": "TAX_SPECIFIC_001",
                "unitPrice":{
                  "amount":99.99,
                  "currency":"CAD"
                }
              },
              {
                "itemId":"53599dbce4b08806bb0e2772",
                "productId":"NikonSLR",
                "quantity":3,
                "unitPrice":{
                  "amount":99.99,
                  "currency":"CAD"
                }
              },
              {
                "itemId":"53599dbce4b08806bb0e2773",
                "productId":"OptimaSLR",
                "quantity":2,
                "unitPrice":{
                  "amount":99.99,
                  "currency":"CAD"
                }
              }
            ],
            "shipping": {
              "calculationType": "QUOTATION",
              "methodId": "UPS",
              "zoneId": "NA"
            },
            "discounts": [
              {
                "amount": 19.99,
                "currency": "CAD",
                "calculationType": "ApplyDiscountBeforeTax"
              }
            ],
            "addresses": [
              {
                "type": "SHIP_FROM",
                "addressLine1": "123 rue Des Passereaux",
                "zipCode": "J0L 1C0",
                "city": "St-Clin",
                "state": "QC",
                "country": "CA"
              },
              {
                "type": "SHIP_TO",
                "addressLine1": "1741 Boulevard Alexis-Nihon",
                "zipCode": "H4R3A2",
                "city": "Saint-Laurent",
                "state": "QC",
                "country": "CA"
              }
            ]
        }, {
        headers: {
            'Authorization': 'Bearer ' + access_token,
            'Content-Type' : 'application/json'
        }
    });
    assert.equal(response.status, 200);
    response.body;

Cleanup

Delete the site and tax codes created for this project before you move on to another tutorial.

    response = siteService.tenant(tenant).sites.code('canada').delete({}, {
        headers: {
            'Authorization': 'Bearer ' + access_token,
            'Content-Type' : 'application/json'
        }
        }
    );
    assert.equal(response.status, 204);
    response;
response = taxService.tenant(tenant).tax.codes.id(taxCodeId).delete({}, {
      headers: {
        'Authorization': 'Bearer ' + access_token,
        'Content-Type' : 'application/json'
      }
    }
);
assert.equal(response.status, 204);
response;


Error Codes

For more information about error codes, see the API Reference.


Glossary

TermDescription
AvalaraA company that provides services for sales tax management.
cartA location where a customer keeps the items they want to purchase.
discountA percentage or dollar amount that is subtracted from the product"s original price or from the cart"s total.
itemAn object that is in the cart.
taxAn amount that is paid to a governing body for the sale of certain goods and services. This amount is charged to the customer at the point of purchase.
tax codeA code created in the Tax service that is then assigned to a product.


  • Send feedback

    If you find any information that is unclear or incorrect, please let us know so that we can improve the Dev Portal content.

  • Get Help

    Use our private help channel. Receive updates over email and contact our specialists directly.

  • hybris Experts

    If you need more information about this topic, visit hybris Experts to post your own question and interact with our community and experts.