Calculation 3.0
Edit on GitHubSpryker uses the Calculation module to calculate the cart totals that are displayed in the cart/checkout or when the order is placed.
The Calculation module extensively uses plugins to inject calculation algorithms.
How calculation works
The quote transfer object is used to store data and plugins that calculate the amounts.
There is already a list of plugins which populate quote transfer with corresponding data. Calculations are executed every time the content of the cart is updated.
For more details, check Cart Data Flow in the Cart Functionality section.
If manual recalculation of cart is required, then CalculationFacade::recalculate
can be called from Zed or CalculationClient::recalculate
from Yves with prepared Calculation Data Structure. When the recalculation operation is called, the calculator runs the calculator plugin stack and each plugin modifies the QuoteTransfer
(calculates discounts, adds sum gross prices, calculates taxes). Most plugins require the unitGrossPrice
and the quantity
to be provided.
Each amount is being calculated and stored in cents.
Calculator plugins
Calculator plugins are registered in the CalculationDependencyProvider::getCalculatorStack()
method. This method can be extended on the project level and the plugin stack can be updated with your own plugins. Each calculator must implement CalculatorPluginInterface
.
For more information see:
<?php
interface CalculatorPluginInterface
{
/**
* @param QuoteTransfer $quoteTransfer
*
public function recalculate(QuoteTransfer $quoteTransfer);
}
RemoveTotalsCalculatorPlugin
—resets quote totals, setsTotalsTransfer
empty.RemoveAllCalculatedDiscountsCalculatorPlugin
—resets everyCalculatedDiscountTransfer
.ItemGrossAmountsCalculatorPlugin
—calculatessumGrossPrice
for eachItemTransfer
.
ItemTransfer::sumGrossPrice = ItemTransfer::unitGrossPrice * ItemTransfer::quantity
ProductOptionGrossSumCalculatorPlugin
—calculatesunitGrossPriceWithProductOptions
,sumGrossPriceWithProductOptions
forItemTransfer
andsumGrossPrice
forProductOptionTransfer
—calculatesunitGrossPriceWithProductOptions
,sumGrossPriceWithProductOptions
forItemTransfer
andsumGrossPrice
forProductOptionTransfer
.
ProductOptionTransfer::sumGrossPrice = ProductOptionTransfer::unitGrossPrice * ProductOptionTransfer::quantity
ItemTransfer::unitGrossPriceWithProductOptions = sum(ProductOptionTransfer::unitGrossPrice) + ItemTransfer::unitGrossPrice
ItemTransfer::sumGrossPriceWithProductOptions = sum(ProductOptionTransfer::sumGrossPrice) + ItemTransfer:sumGrossPrice
SubtotalTotalsCalculatorPlugin
—sums each of thesumGrossPriceWithProductOptions
items.TotalsTransfer::subtotal = sum(ItemTransfer::sumGrossPriceWithProductOptions)
ExpensesGrossSumAmountCalculatorPlugin
—calculatessumGrossPrice
for each item.ExpenseTransfer::sumGrossPrice = ExpenseTransfer::unitGrossPrice * ExpenseTransfer::quantity
ExpenseTotalsCalculatorPlugin
—calculatesexpenseTotal
inTotalsTransfer
.TotalsTransfer::expenseTotal = sum(ExpenseTransfer::sumGrossPrice)
DiscountCalculatorPlugin
—applies discounts to currentQuoteTransfer
each discountable item with propertycalculatedDiscounts
, gets discounts filled. Also,voucherDiscounts
andcartRuleDiscounts
are populated with additional used discount data for order level.
Discount calculation is a separate topic and is explained in the Discount article.
SumGrossCalculatedDiscountAmountCalculatorPlugin
—calculates and setsItemTransfer
amounts after discounts tosumGrossPriceWithProductOptionAndDiscountAmounts
andunitGrossPriceWithProductOptionAndDiscountAmounts
; sets expense amounts after discounts tounitGrossPriceWithDiscounts
andsumGrossPriceWithDiscounts
.
ItemTransfer::unitGrossPriceWithProductOptionAndDiscountAmounts = ItemTransfer::unitGrossPriceWithProductOptions— (sum(ItemTransfer:calculatedDiscounts::unitGrossPrice) + sum(ProductOptionTransfer::calculatedDiscounts::unitGrossPrice))
ItemTransfer::sumGrossPriceWithProductOptionAndDiscountAmounts = ItemTransfer::sumGrossPriceWithProductOptions— (sum(ItemTransfer:calculatedDiscounts::sumGrossPrice) + sum(ProductOptionTransfer::calculatedDiscounts::sumGrossPrice))
DiscountTotalsCalculatorPlugin
—calculates total for discounts used and sets it tototalDiscount
inTotalsTransfer
. Sum all discountable itemCalculatedDiscountTransfer
gross amounts:
TotalsTransfer:discountTotal += sum(ItemTransfer::CalculateDiscountTransfer::sumGrossAmount +
ItemTransfer::ProductOptionTransfer::CalculateDiscountTransfer::sumGrossAmount + ExpenseTransfer::sumGrossAmount)
GrandTotalTotalsCalculatorPlugin—Calculates grandTotal in TotalsTransfer.
TotalsTransfer:grandTotal = TotalsTransfer::subtotal + TotalsTransfer:expenseTotal
GrandTotalWithDiscountsCalculatorPlugin
—calculatesGrandTotal
after discounts inTotalsTransfer
.TotalsTransfer:grandTotal = TotalsTransfer::subtotal + TotalsTransfer:expenseTotal - TotalsTransfer::discountTotal
TaxTotalsCalculatorPlugin
—calculates taxTotal and taxRate used fromTotalTransfer::grandTotal
, sets it inTotalsTransfer::TaxTotalsTransfer
.
TaxableItems = ItemTransfer, ProductOptionTransfer, ExpenseTransfer. TaxTotalsTransfer::taxRate = sum(TaxableItems) / TaxableItems TaxTotalsTransfer::taxAmount = round((TotalsTransfer::grandTotal * TaxTotalsTransfer::taxRate) / TaxTotalsTransfer::taxRate / 100)
Calculation data structure
This section describes calculation data structure.
Quote transfer
QuoteTransfer
is the main data transfer object used in Cart, Calculation, Checkout and when order is placed. This object is created when first item is added to the cart. The entire data object is stored into the session. It consists of:
FIELD | DESCRIPTION |
---|---|
totals (TotalsTransfer) | Order totals. |
items (ItemTransfer[]) | CartItem collection. |
voucherDiscounts (DiscountTransfer[]) | |
cartRuleDiscounts (DiscountTransfer[]) | |
expenses (ExpenseTransfer) | |
billingAddress (AddressTransfer) | Current checkout customer billing address. |
shippingAddress (AddressTransfer) | Current checkout customer shipment address. |
customer (CustomerTransfer) | Current checkout customer details. |
orderReference (string) | Current checkout order reference, available after PlaceOrderStep . |
payment (PaymentTransfer) | Information about currently selected payment, available after PaymentStep . |
shipment (ShipmentTransfer) | Information about currently selected shipment, available after ShipmentStep . |
Totals transfer
TotalsTransfer
is a data object holding cart totals, subtotal, expenses (shipping), discount total and grand total. Here should the amounts for order level be stored.
FIELD | DESCRIPTION |
---|---|
subtotal (int) | Calculated total amount before taxes and discounts. Is set by SubtotalTotalsCalculatorPlugin . |
expenseTotal (int) | Total expenses amount (shipping). It is set by ExpenseTotalsCalculatorPlugin . |
discountTotal (int) | Total discount amount. It is set by DiscountTotalsCalculatorPlugin . |
taxTotal (TaxTotalsTransfer) | Tax totals for current cart. Is set by TaxTotalsCalculatorPlugin . |
grandTotal (int) | The total amount the customer needs to pay after the discounts are applied. It is set by GrandTotalWithDiscountsCalculatorPlugin calculator plugin. |
hash (string) | Hash from total values to identify amount changes. It is set by GrandTotalCalculatorPlugin . |
Tax total transfer
TaxTotalsTransfer
holds taxRate and taxAmount used for grandTotal.
FIELD | DESCRIPTION |
---|---|
taxRate (int) | Current tax rate in percentage. |
amount (int) | Current tax amount from grandTotal. |
Item transfer
ItemTransfer
is a cart item transfer, holds single product information.
FIELD | DESCRIPTION |
---|---|
id (int) | ID of the concrete product |
sku (string) | Concrete product sku |
groupKey (string) | Group key used for grouping items in cart |
quantity (int) | Number of items selected |
IDSalesOrderItem (int) | ID of order item, stored when items is saved after PlaceOrderStep |
name (string) | Concrete product name |
IDProductAbstract (int) | ID of abstract product |
abstractSku (string) | Abstract product sku |
variety (string) | Used when an item is in a module |
status (string) | State machine state when an item used as order item |
addedAt (string) | Used in wishlist to have date when an item was added |
productConcrete (ProductConcreteTransfer) | Concrete product details added to the wishlist |
unitGrossPrice (int) | Single item gross price. It’s set with the CartItemPricePlugin cart expander plugin |
sumGrossPrice (int) | Sum of items gross price. Calculated with ExpensesGrossSumAmountCalculatorPlugin . |
unitGrossPriceWithDiscounts (int) | Unit gross price after the discounts are applied. It’s set by SumGrossCalculatedDiscountAmountCalculatorPlugin . |
sumGrossPriceWithDiscounts (int) | Sum of an item gross price after discounts. It’s set by SumGrossCalculatedDiscountAmountCalculatorPlugin . |
taxRate (int) | Current tax rate. It’s set by the ProductCartPlugin cart expander plugin. |
unitGrossPriceWithProductOptions (int) | Single item with product options gross price. It’s set by ProductOptionGrossSumCalculatorPlugin . |
sumGrossPriceWithProductOptions (int) | Sum of item gross price with product options. It’s set by ProductOptionGrossSumCalculatorPlugin . |
unitGrossPriceWithProductOptionAndDiscountAmounts (int) | Single item with product options gross price and after discounts. It’s set by SumGrossCalculatedDiscountAmountCalculatorPlugin . |
sumGrossPriceWithProductOptionAndDiscountAmounts (int) | Sum of item gross price with product options and after discounts. It’s set by SumGrossCalculatedDiscountAmountCalculatorPlugin . |
unitTaxAmountWithProductOptionAndDiscountAmounts (int) | Single item tax amount with product options after discounts. (order only) |
sumTaxAmountWithProductOptionAndDiscountAmounts (int) | Sum of items gross price with product options after discounts. (order only) |
refundableAmount (int) | Item available refundable amount (order only) |
unitTaxAmount (int) | Tax amount for single item (order only) |
sumTaxAmount (int) | Tax amount for sum of items (order only) |
calculatedDiscounts[] (CalculatedDiscountTransfer) | Item calculated discount collection. It’s set by DiscountCalculatorPlugin . |
canceledAmount (int) | Canceled amount for this item (order only) |
productOptions (ProductOptionTransfer[]) | Assigned product options. It’s set by CartItemProductOptionPlugin cart expander plugin. |
Calculated discount transfer
Each item which can have discounts applied have calculatedDiscounts
property added which holds the collection of discounts for each discount type.
FIELD | DESCRIPTION |
---|---|
displayName (string) | Applied discount name |
description (string) | Applied discount description |
voucherCode (string) | Used voucher code |
quantity(int) | Number of discounted items |
unitGrossAmount (int) | Discount gross amount for single items; it’s set by DiscountCalculatorPlugin . |
sumGrossAmount (int) | Discount gross amount for sum of items; it’s set by DiscountCalculatorPlugin . |
Product option transfer
ProductOptionTransfer
, some items may have product option collection attached which also have amounts calculated.
FIELD | DESCRIPTION |
---|---|
idSalesOrderItemOption (int) | ID of sales order item option stored after the order is placed |
unitGrossPrice (int) | Single item gross price. It’s set by CartItemProductOptionPlugin cart expander plugin. |
sumGrossPrice (int) | Sum of items gross price. It’s set by ProductOptionGrossSumCalculatorPlugin cart expander plugin. |
taxRate (int) | Tax rate in percentage. It’s set by CartItemProductOptionPlugin cart expander plugin. |
calculatedDiscounts[] (CalculatedDiscountTransfer) | Product Option calculated discount collection. It’s set by DiscountCalculatorPlugin . |
refundableAmount (int) | Item available refundable amount (order only) |
unitTaxAmount (int) | |
Tax amount for single product option (order only) | |
sumTaxAmount (int) | Tax amount for sum of product options (order only) |
Discount transfer
DiscountTransfer
is a collection of discounts used in all QuoteTransfer
discountable items. It can be voucherDiscounts
or cartRuleDiscounts
.
FIELD | DESCRIPTION |
---|---|
displayName (string) | Discount name |
IDDiscount (int) | ID of discount, as stored in the discount table |
description (string) | description of the applied discount |
calculatorPlugin (string) | discount calculator plugin used to calculate this discount (Fixed, Percentage) |
IsPrivileged (bool) | Is the discount privileged, can be combined with other discounts |
IsActive (bool) | Is the discount active |
validFrom (string) | starting date for discount validity |
validTo (string) | Ending date for discount validity |
collectorLogicalOperator (string) | Logical operator for collector (OR, AND) when combining multiple discounts |
discountCollectors (DiscountCollectionTransfer[] | List of discount collectors used for this discount |
amount (int) | Total discount amount used for this discount type. It’s set by DiscountCalculatorPlugin . |
Expense transfer
FIELD | DESCRIPTION |
---|---|
idExpense (int) | Unique identifier of the expense |
sumGrossPrice (int) | Sum of item gross price. It’s set by ExpensesGrossSumAmountCalculatorPlugin . |
unitGrossPrice (string) | Single expense price, e.g., shipment expenses are set in the ShipmentStep |
type (string) | Type of expense (shipping) |
taxRate (int) | Tax in percents |
calculatedDiscounts (CalculatedDiscountTransfer[] | List of applied discounts for this item |
quantity (int) | Number of items |
IDSalesExpense (int) | ID of expense as stored in the sales_expense |
unitGrossPriceWithDiscounts (int) | Single item price after discounts. Set by SumGrossCalculatedDiscountAmountCalculator and OrderAmountAggregator/ItemDiscounts . |
sumGrossPriceWithDiscounts (int) | Sum off all item prices after discounts. Set by SumGrossCalculatedDiscountAmountCalculator and OrderAmountAggregator/ItemDiscounts . |
unitTaxAmountWithDiscounts (int) | Tax amount for single item after discounts(order only) |
sumTaxAmountWithDiscounts (int) | Tax amount for sum of items after discounts(order only) |
refundableAmount (int) | Total refundable amount for this item (order only) |
canceledAmount (int) | Total cancelled amount for this item (order only) |
unitTaxAmount (int) | Tax amount for single item (order only) sumTaxAmount (int) |
Thank you!
For submitting the form