Price calculations
This document provides an overview of how various transaction amount fields in a TransactionItem
are calculated and influenced. Additionally, it provides details on how totalBalance
is calculated for Checkout and Order entities.
Transaction Amount Fields Overview
The following fields are calculated based on transaction events and their types:
authorizedAmount
: The total amount successfully authorized.chargedAmount
: The total amount successfully charged.refundedAmount
: The total amount successfully refunded.canceledAmount
: The total amount successfully canceled.authorizePendingAmount
: The total amount of pending authorizations.chargePendingAmount
: The total amount of pending charges.refundPendingAmount
: The total amount of pending refunds.cancelPendingAmount
: The total amount of pending cancellations.
Calculation process
When the transaction amounts are recalculated, firstly all values are set to zero, then the calculations are applied in the following order:
- recalculate amounts based on events without PSP reference
- recalculate amounts based on
AUTHORIZATION
events - recalculate amounts based on
CHARGE
events - recalculate amounts based on
REFUND
events - recalculate amounts based on
CANCEL
events At each step, the amounts are incrementally adjusted by adding or subtracting values calculated in the current step to the totals from the previous step.
Assumptions
1. Event Grouping:
- Events are grouped based on their PSP reference and type of action (e.g., authorization, charge).
- Grouping ensures that events of the same type and PSP reference are properly matched to calculate amounts accurately.
2. Pending Amounts:
- Pending amounts (
authorizePendingAmount
,chargePendingAmount
,refundPendingAmount
,cancelPendingAmount
) are increased only if aREQUEST
event exists for the corresponding PSP reference. - If a success or failure event is also associated with the same PSP reference, the system assumes the requested amount has already been processed, and the pending amount will not be increased.
3. SUCCESS
and FAILURE
Events:
- The transaction amount (e.g.,
authorizedAmount
,chargedAmount
) is increased only when aSUCCESS
event exists. - If both a
SUCCESS
andFAILURE
event are present for the same PSP reference, the system compares their creation timestamps:- If the
FAILURE
event is newer, theSUCCESS
event is ignored. - If the
SUCCESS
event is newer, it is used for the calculations.
- If the
4. Events Without PSP References Resulting from TransactionCreate
and TransactionUpdate
:
- Events without PSP references can result from using the
TransactionCreate
orTransactionUpdate
mutations. These events are automatically created to ensure accurate transaction amount calculations. The following events might lack a PSP reference:AUTHORIZATION_SUCCESS
AUTHORIZATION_ADJUSTMENT
CHARGE_SUCCESS
CHARGE_BACK
REFUND_SUCCESS
REFUND_REVERSE
CANCEL_SUCCESS
5. Adjustment Events:
- The
AUTHORIZATION_ADJUSTMENT
, overrides previous amount from previousAUTHORIZATION
events, this means that if an adjustment is present, older authorization events are ignored, and the adjusted amount becomes the new authorized value.
This logic ensures that transaction amounts reflect the current state of the transaction based on its event history while accounting for both processed and pending actions.
Calculation details
For events without pspReference
The events that lacks the pspReference
resulting from TransactionCreate
and TransactionUpdate
mutations are influence the transaction amounts as follow:
AUTHORIZATION_SUCCESS
increasesauthorizedAmount
by the event amountAUTHORIZATION_ADJUSTMENT
overrides the existingauthorizedAmount
by the even amountCHARGE_SUCCESS
increaseschargedAmount
by the event amountCHARGE_BACK
reduceschargedAmount
by the event amountREFUND_SUCCESS
increasesrefundedAmount
by the event amountREFUND_REVERSE
increaseschargedAmount
by the event amountCANCEL_SUCCESS
increasescanceledAmount
by the event amount
For events with pspReference
Events like X_REQUEST
, generated by Saleor when calling the payment app, are excluded from calculations until a corresponding event with a valid psp_reference
is received from the payment app.
For example, an AUTHORIZATION_REQUEST
event will not affect the calculations until an AUTHORIZATION_SUCCESS
or a similar event containing a psp_reference
is returned by the payment app.
The following calculation rules apply to events that share the same pspReference
.
Authorized Value (transactionItem.authorizedAmount
)
- GIVEN there is an
AUTHORIZATION_SUCCESS
event- WHEN there is no
AUTHORIZATION_FAILURE
- OR WHEN the
AUTHORIZATION_FAILURE
event is older thanAUTHORIZATION_SUCCESS
- THEN value increases by the
AUTHORIZATION_SUCCESS
event's amount.
- THEN value increases by the
- WHEN there is no
- GIVEN an
AUTHORIZATION_ADJUSTMENT
event- WHEN it's the latest event of this type
- THEN value is overwritten by the
AUTHORIZATION_ADJUSTMENT
event amount.
- THEN value is overwritten by the
- WHEN it's the latest event of this type
- GIVEN there is a
CHARGE_REQUEST
orCHARGE_SUCCESS
event:- THEN value is reduced by the event's amount.
- GIVEN there is a
CANCEL_REQUEST
orCANCEL_SUCCESS
event:- THEN value is reduced by the event's amount.
- GIVEN all calculations were performed and we have result
authorizationAmount
- WHEN calculated
authorizationAmount
is below0
- THEN
authorizationAmount
is set to0
(it cannot be lower than 0)
- THEN
- WHEN calculated
Authorization Pending Value (transactionItem.authorizePendingAmount
)
- GIVEN there is an
AUTHORIZATION_REQUEST
event:- WHEN there is no
AUTHORIZATION_FAILURE
orAUTHORIZATION_SUCCESS
- THEN value increases by the
AUTHORIZATION_REQUEST
event's amount
- THEN value increases by the
- WHEN there is no
Charge Value (transactionItem.chargedAmount
)
- GIVEN there is a
CHARGE_SUCCESS
event- WHEN there is no
CHARGE_FAILURE
- OR WHEN the
CHARGE_FAILURE
event is older thanCHARGE_SUCCESS
- THEN value increases by the
CHARGE_SUCCESS
event's amount.
- THEN value increases by the
- WHEN there is no
- GIVEN there is a
CHARGE_BACK
event- THENvalue is reduced by the event's amount
- GIVEN there is a
REFUND_REQUEST
orREFUND_SUCCESS
event:- THEN value is reduced by the event's amount.
- GIVEN there is a
REFUND_REVERSE
event:- THEN value is increased by the event's amount.
- This value can be negative.
Please note that chargedAmount is not affected by CANCEL
events, as these are solely used for matching with AUTHORIZATION
events.
Charge Pending Value (transactionItem.chargePendingAmount
)
- GIVEN there is a
CHARGE_REQUEST
event:- WHEN there is no
CHARGE_FAILURE
orCHARGE_SUCCESS
- THEN value increases by the
CHARGE_REQUEST
event's amount
- THEN value increases by the
- WHEN there is no
Refunded Value (transactionItem.refundedAmount
)
- GIVEN there is a
REFUND_SUCCESS
event- WHEN there is no
REFUND_FAILURE
- OR WHEN the
REFUND_FAILURE
event is older thanREFUND_SUCCESS
- THEN value increases by the
REFUND_SUCCESS
event's amount.
- THEN value increases by the
- WHEN there is no
- GIVEN there is a
REFUND_REVERSE
event:- THEN value is reduced by the event's amount.
CHARGE_BACK
events, which behave similarly to refunds by reducing the chargedAmount
, are not included in refundedAmount
. This is because they are initiated by the issuing bank, not the merchant.
Refund Pending Value (transactionItem.refundPendingAmount
)
- GIVEN there is a
REFUND_REQUEST
event:- WHEN there is no
REFUND_FAILURE
orREFUND_SUCCESS
- THEN value increases by the
REFUND_REQUEST
event's amount
- THEN value increases by the
- WHEN there is no
Canceled Value (transactionItem.canceledAmount
)
- GIVEN there is a
CANCEL_SUCCESS
event- WHEN there is no
CANCEL_FAILURE
- OR WHEN the
CANCEL_FAILURE
event is older thanCANCEL_SUCCESS
- THEN value increases by the
CANCEL_SUCCESS
event's amount.
- THEN value increases by the
- WHEN there is no
Cancel Pending Value (transactionItem.cancelPendingAmount
)
- GIVEN there is a
CANCEL_REQUEST
event:- WHEN there is no
CANCEL_FAILURE
orCANCEL_REQUEST
- THEN value increases by the
CANCEL_REQUEST
event's amount
- THEN value increases by the
- WHEN there is no
Total Balance Calculation
The totalBalance
represents the difference between the expected total cost and the total amount charged (including pending charges).
This balance indicates whether the customer has overpaid (positive balance) or underpaid (negative balance) for the order.
Below is an explanation of how totalBalance
is computed.
Total balance for Checkout (checkout.totalBalance
)
For a Checkout, totalBalance
reflects the remaining balance after considering the total checkout cost, charged amounts, and pending charges.
It is calculated as the difference between the sum of all successful and pending charges across associated transactions and the checkout’s total price:
totalBalance = totalCharged - checkout.totalPrice
where:
totalCharged = (
sum(transaction.chargedAmount for transaction in transactions)
+ sum(transaction.chargePendingAmount for transaction in transactions)
)
Total balance for Order (order.totalBalance
)
For an Order, totalBalance
represents the remaining balance after accounting for order.totalPrice
, charged amounts, and granted refunds.
It is calculated as the difference between the total charged (including pending charges) and the order cost adjusted for granted refunds:
totalBalance = totalCharged - (order.totalPrice - totalGrantedRefund)
where totalCharged
is sum of all successful and pending charges across associated transactions:
totalCharged = (
sum(transaction.amountCharged for transaction in transactions)
+ sum(transaction.amountChargePending for transaction in transactions)
)
and totalGrantedRefund
is a total of all refunds issued to the customer:
totalGrantedRefund = sum(grantedRefund.amount for grantedRefund in grantedRefunds)