Discounts
Introduction
Discounts allow for the reduction of prices for selected variants, products, collections,
or categories by a given percentage or a fixed value.
There are two kinds of discounts in Saleor: Sales
and Vouchers
.
The sale discount is automatically applied to all products included in the sale, without requiring
any additional actions from the user. In contrast, vouchers require the user to provide
a code during the checkout process. Both the sale and voucher discounts can be used together.
Sale
Sales are automatically applied when a product is added to the checkout.
For instance, if a product is priced at $9 and has a 10% discount, it will be available for $8.1.
The discount will be visible on the line prices. To calculate the total applied discount,
subtract the line.undiscountedTotalPrice
from the line.totalPrice
.
To calculate the discount on one unit, subtract the line.undiscountedUnitPrice
from the line.unitPrice
.
The sale discount is not visible on checkout.discount.amount
.
In the example below, we add an on-sale product to the checkout.
The response of the checkoutLinesAdd
mutation will include the discounted product price.
mutation {
checkoutLinesAdd(
checkoutId: "Q2hlY2tvdXQ6NzMwMzkwMmItZGRhOC00MzU3LTk1YTAtNjRiODNiNTllMmUy"
lines: { quantity: 1, variantId: "UHJvZHVjdFZhcmlhbnQ6Mzcx" }
) {
errors {
message
}
checkout {
discount {
amount
}
token
lines {
quantity
variant {
name
}
totalPrice {
gross {
amount
}
net {
amount
}
}
undiscountedTotalPrice {
amount
}
unitPrice {
gross {
amount
}
net {
amount
}
}
undiscountedUnitPrice {
amount
}
}
}
}
}
Please note the line prices in the following response.
The line.totalPrice
is 8.1, and the line.undiscountedTotalPrice
is 9.0.
{
"data": {
"checkoutLinesAdd": {
"errors": [],
"checkout": {
"discount": {
"amount": 0.0
},
"token": "7303902b-dda8-4357-95a0-64b83b59e2e2",
"lines": [
{
"quantity": 1,
"variant": {
"name": "UHJvZHVjdFZhcmlhbnQ6Mzcx"
},
"totalPrice": {
"gross": {
"amount": 8.1
},
"net": {
"amount": 8.1
}
},
"undiscountedTotalPrice": {
"amount": 9.0
},
"unitPrice": {
"gross": {
"amount": 8.1
},
"net": {
"amount": 8.1
}
},
"undiscountedUnitPrice": {
"amount": 9.0
}
}
]
}
}
}
}
Voucher
There are three types of vouchers:
- Fixed amount: reduces the price by a specified value.
- Percentage: reduces the price by a specified percentage value.
- Shipping: reduces the shipping price.
The voucher can be applied to all checkout products, or only to specified ones.
There is also an option to apply the discount only to the cheapest eligible product. If the voucher specifies certain products, the discount will be applied only to the cheapest item included in the discount. If the voucher applies to all products, the discount will be applied only to the cheapest item overall.
To apply the voucher on checkout use checkoutAddPromoCode
mutation. The discount will be visible both in the line prices and in the checkout.discount
field. Let's see the examples.
Applying the entire order voucher
In the example below, the entire order voucher with a fixed discount of $5 is applied at checkout. The order consists of two lines: the first for $4 and the second for $45.
mutation {
checkoutAddPromoCode(
token: 7303902b-dda8-4357-95a0-64b83b59e2e2, promoCode: "DISCOUNT"
) {
errors {
field
message
code
}
checkout {
id
token
voucherCode
discountName
discount {
amount
}
subtotalPrice {
tax {
amount
}
gross {
amount
}
net {
amount
}
}
lines {
quantity
totalPrice {
net {
amount
}
gross {
amount
}
}
undiscountedTotalPrice {
amount
}
unitPrice {
net {
amount
}
gross {
amount
}
}
undiscountedUnitPrice {
amount
}
}
}
}
}
Here is the response:
{
"data": {
"checkoutAddPromoCode": {
"errors": [],
"checkout": {
"id": "Q2hlY2tvdXQ6OTNmMWQxZjItMjBjNC00ZWMyLTkwYzgtOThjYmEzY2YyNTU1",
"token": "93f1d1f2-20c4-4ec2-90c8-98cba3cf2555",
"voucherCode": "DISCOUNT",
"discountName": "Big order discount",
"discount": {
"amount": 5.0
},
"subtotalPrice": {
"tax": {
"amount": 0.0
},
"gross": {
"amount": 44.0
},
"net": {
"amount": 44.0
}
},
"lines": [
{
"quantity": 1,
"totalPrice": {
"net": {
"amount": 3.59
},
"gross": {
"amount": 3.59
}
},
"undiscountedTotalPrice": {
"amount": 4.0
},
"unitPrice": {
"net": {
"amount": 3.59
},
"gross": {
"amount": 3.59
}
},
"undiscountedUnitPrice": {
"amount": 4.0
}
},
{
"quantity": 1,
"totalPrice": {
"net": {
"amount": 40.41
},
"gross": {
"amount": 40.41
}
},
"undiscountedTotalPrice": {
"amount": 45.0
},
"unitPrice": {
"net": {
"amount": 40.41
},
"gross": {
"amount": 40.41
}
},
"undiscountedUnitPrice": {
"amount": 45.0
}
}
]
}
}
}
}
The discount is visible on both the checkout.discount
field and the prices in checkout.lines
.
In the first line, the totalPrice
is $0.41 less than the undiscountedTotalPrice
,
while the difference in the second line is $4.59.
The checkout.discount
is the sum of the differences between totalPrice
and undiscountedTotalPrice
of the lines.
If the user applied a fixed-amount order voucher during checkout, and the order contains multiple lines, the discount will be distributed evenly in proportion to the total price of each line.
Applying the once-per-order entire order voucher
If a voucher with the applyOncePerOrder
flag set to True
is used in a similar scenario,
the discount will only apply to the cheapest eligible product. In this checkout,
the cheapest eligible product is priced at $4.
Therefore, the discount will be $4 and will only appear on one line.
Refer to the response from running the same mutation as before.
The checkout.discount
is 4.0. The cheapest line's totalPrice
is 0.0,
and the undiscountedTotalPrice
is 4.0.
{
"data": {
"checkoutAddPromoCode": {
"errors": [],
"checkout": {
"id": "Q2hlY2tvdXQ6OTNmMWQxZjItMjBjNC00ZWMyLTkwYzgtOThjYmEzY2YyNTU1",
"token": "93f1d1f2-20c4-4ec2-90c8-98cba3cf2555",
"voucherCode": "DISCOUNT",
"discountName": "Big order discount",
"discount": {
"amount": 4.0
},
"subtotalPrice": {
"tax": {
"amount": 0.0
},
"gross": {
"amount": 45.0
},
"net": {
"amount": 45.0
}
},
"lines": [
{
"quantity": 1,
"totalPrice": {
"net": {
"amount": 0.0
},
"gross": {
"amount": 0.0
}
},
"undiscountedTotalPrice": {
"amount": 4.0
},
"unitPrice": {
"net": {
"amount": 0.0
},
"gross": {
"amount": 0.0
}
},
"undiscountedUnitPrice": {
"amount": 4.0
}
},
{
"quantity": 1,
"totalPrice": {
"net": {
"amount": 45.0
},
"gross": {
"amount": 45.0
}
},
"undiscountedTotalPrice": {
"amount": 45.0
},
"unitPrice": {
"net": {
"amount": 45.0
},
"gross": {
"amount": 45.0
}
},
"undiscountedUnitPrice": {
"amount": 45.0
}
}
]
}
}
}
Applying the specific product voucher
In the following example, a 10% voucher for a specific product is applied during checkout.
The discount applies to the first two lines, one for $45 and the other for $20, but not to the third line for $1.99.
The response of running the checkoutAddPromoCode
mutation with the voucher code for this discount is shown below:
{
"data": {
"checkoutAddPromoCode": {
"errors": [],
"checkout": {
"id": "Q2hlY2tvdXQ6YWJlZTQzNTEtMGZjMS00MWYzLTk1YzEtMTIyMTc4NWMwYzY2",
"token": "abee4351-0fc1-41f3-95c1-1221785c0c66",
"voucherCode": "SPECIFIC PRODUCT",
"discountName": null,
"discount": {
"amount": 6.5
},
"subtotalPrice": {
"tax": {
"amount": 0.0
},
"gross": {
"amount": 60.49
},
"net": {
"amount": 60.49
}
},
"lines": [
{
"quantity": 1,
"totalPrice": {
"net": {
"amount": 40.5
},
"gross": {
"amount": 40.5
}
},
"undiscountedTotalPrice": {
"amount": 45.0
},
"unitPrice": {
"net": {
"amount": 40.5
},
"gross": {
"amount": 40.5
}
},
"undiscountedUnitPrice": {
"amount": 45.0
}
},
{
"quantity": 1,
"totalPrice": {
"net": {
"amount": 18.0
},
"gross": {
"amount": 18.0
}
},
"undiscountedTotalPrice": {
"amount": 20.0
},
"unitPrice": {
"net": {
"amount": 18.0
},
"gross": {
"amount": 18.0
}
},
"undiscountedUnitPrice": {
"amount": 20.0
}
},
{
"quantity": 1,
"totalPrice": {
"net": {
"amount": 1.99
},
"gross": {
"amount": 1.99
}
},
"undiscountedTotalPrice": {
"amount": 1.99
},
"unitPrice": {
"net": {
"amount": 1.99
},
"gross": {
"amount": 1.99
}
},
"undiscountedUnitPrice": {
"amount": 1.99
}
}
]
}
}
}
}
As we can see, the 10% discount has been applied to the first two lines.
The total discount amount is visible in the checkout.discount
field, which is equal to
the sum of the differences between the undiscountedTotalPrice
and totalPrice
of all lines.
Applying the once-per-order specific product voucher
If the voucher has the applyOncePerOrder
flag set to True
, the discount will only be applied to
the single cheapest product eligible for the discount. In the scenario described,
the discount would only be applied to the product with a price of $20, and would be visible on only one line of the order.
{
"data": {
"checkoutAddPromoCode": {
"errors": [],
"checkout": {
"id": "Q2hlY2tvdXQ6YWJlZTQzNTEtMGZjMS00MWYzLTk1YzEtMTIyMTc4NWMwYzY2",
"token": "abee4351-0fc1-41f3-95c1-1221785c0c66",
"voucherCode": "SPECIFIC PRODUCT",
"discountName": null,
"discount": {
"amount": 2.0
},
"subtotalPrice": {
"tax": {
"amount": 0.0
},
"gross": {
"amount": 64.99
},
"net": {
"amount": 64.99
}
},
"lines": [
{
"quantity": 1,
"totalPrice": {
"net": {
"amount": 45.0
},
"gross": {
"amount": 45.0
}
},
"undiscountedTotalPrice": {
"amount": 45.0
},
"unitPrice": {
"net": {
"amount": 45.0
},
"gross": {
"amount": 45.0
}
},
"undiscountedUnitPrice": {
"amount": 45.0
}
},
{
"quantity": 1,
"totalPrice": {
"net": {
"amount": 18.0
},
"gross": {
"amount": 18.0
}
},
"undiscountedTotalPrice": {
"amount": 20.0
},
"unitPrice": {
"net": {
"amount": 18.0
},
"gross": {
"amount": 18.0
}
},
"undiscountedUnitPrice": {
"amount": 20.0
}
},
{
"quantity": 1,
"totalPrice": {
"net": {
"amount": 1.99
},
"gross": {
"amount": 1.99
}
},
"undiscountedTotalPrice": {
"amount": 1.99
},
"unitPrice": {
"net": {
"amount": 1.99
},
"gross": {
"amount": 1.99
}
},
"undiscountedUnitPrice": {
"amount": 1.99
}
}
]
}
}
}
}
Here, we can see that the discount was only applied to the cheapest line included in the voucher discount.
The total checkout.discount
is $2.0 in this case. The difference between
totalPrice
and undiscountedTotalPrice
is only visible on the second line.
Sale and Voucher together
Sales and vouchers can be combined. In this case, the voucher discount is applied to the price after the sale. Let's consider an example: the checkout has two items, and the second item is on sale. A fixed discount of $5 is being applied to the entire order.
Here is the checkout data before applying the voucher code (only the sale is included in the price).
{
"data": {
"checkout": {
"id": "Q2hlY2tvdXQ6YzhkYmIxMWEtYzQyMi00ODdiLTg3ZTUtMGQ0NzhiNTU2N2Fj",
"token": "c8dbb11a-c422-487b-87e5-0d478b5567ac",
"channel": {
"slug": "default-channel"
},
"voucherCode": null,
"discount": {
"amount": 0.0
},
"discountName": null,
"totalPrice": {
"gross": {
"amount": 51.5
},
"net": {
"amount": 51.5
}
},
"subtotalPrice": {
"gross": {
"amount": 51.5
},
"net": {
"amount": 51.5
},
"__typename": "TaxedMoney"
},
"lines": [
{
"quantity": 1,
"undiscountedTotalPrice": {
"amount": 20.0
},
"totalPrice": {
"gross": {
"amount": 20.0
},
"net": {
"amount": 20.0
}
},
"unitPrice": {
"net": {
"amount": 20.0
}
},
"undiscountedUnitPrice": {
"amount": 20.0
}
},
{
"quantity": 1,
"undiscountedTotalPrice": {
"amount": 35.0
},
"totalPrice": {
"gross": {
"amount": 31.5
},
"net": {
"amount": 31.5
}
},
"unitPrice": {
"gross": {
"amount": 31.5
},
"net": {
"amount": 31.5
}
},
"undiscountedUnitPrice": {
"amount": 35.0
}
}
]
}
}
}
As we can see the price of the second line is reduced by $3.5. The checkout.discount
is $0.0.
Below is the checkout data after applying the entire order voucher.
{
"data": {
"checkoutAddPromoCode": {
"errors": [],
"checkout": {
"id": "Q2hlY2tvdXQ6YzhkYmIxMWEtYzQyMi00ODdiLTg3ZTUtMGQ0NzhiNTU2N2Fj",
"token": "c8dbb11a-c422-487b-87e5-0d478b5567ac",
"voucherCode": "DISCOUNT",
"discountName": "Big order discount",
"discount": {
"amount": 5.0
},
"subtotalPrice": {
"tax": {
"amount": 0.0
},
"gross": {
"amount": 46.5
},
"net": {
"amount": 46.5
}
},
"lines": [
{
"quantity": 1,
"totalPrice": {
"net": {
"amount": 18.06
},
"gross": {
"amount": 18.06
}
},
"undiscountedTotalPrice": {
"amount": 20.0
},
"unitPrice": {
"net": {
"amount": 18.06
},
"gross": {
"amount": 18.06
}
},
"undiscountedUnitPrice": {
"amount": 20.0
}
},
{
"quantity": 1,
"totalPrice": {
"net": {
"amount": 28.44
},
"gross": {
"amount": 28.44
}
},
"undiscountedTotalPrice": {
"amount": 35.0
},
"unitPrice": {
"net": {
"amount": 28.44
},
"gross": {
"amount": 28.44
}
},
"undiscountedUnitPrice": {
"amount": 35.0
}
}
]
}
}
}
As we can see, the total discount is $5.0. In the first line,
the entire difference between totalPrice
and undiscountedTotalPrice
comes from
the voucher discount ($1.94). However, in the second line, the difference
between those values ($6.56) is the total discount applied to this line,
which includes both sales and voucher discounts.
To calculate the value of the applied sale, we can sum up the line discounts and subtract
checkout.discount
. In this example, the calculation would be: ($1.94 + $6.56) - $5.00 = $3.5.
Therefore, we end up with the same value as before applying the voucher.
Completing checkout with discounts
Voucher discount
When completing the checkout with an assigned voucher, the applied voucher discount
will be visible on the order and order line prices. Additionally, the sum of voucher
discounts will be reflected in the order.discounts
field. This behavior is consistent
across all voucher types.
The following example shows the response from the checkoutComplete mutation for a checkout that includes two items of the same variant with a 10% voucher discount applied.
{
"data": {
"checkoutComplete": {
"order": {
"id": "T3JkZXI6NmM1MjhkNGYtZjc5YS00OGM1LTk2ZWUtYjI0M2U2ZjdmMDBm",
"status": "UNFULFILLED",
"totalCaptured": {
"amount": 113.51
},
"subtotal": {
"net": {
"amount": 33.96
},
"gross": {
"amount": 36.0
}
},
"total": {
"currency": "USD",
"net": {
"amount": 107.08
},
"gross": {
"amount": 113.51
}
},
"undiscountedTotal": {
"currency": "USD",
"net": {
"amount": 113.12
},
"gross": {
"amount": 117.51
}
},
"discounts": [
{
"name": null,
"type": "VOUCHER",
"valueType": "FIXED",
"amount": {
"amount": 4.0
}
}
],
"lines": [
{
"quantity": 2,
"totalPrice": {
"gross": {
"amount": 36.0
},
"net": {
"amount": 33.96
}
},
"unitPrice": {
"gross": {
"amount": 18.0
},
"net": {
"amount": 16.98
}
},
"undiscountedUnitPrice": {
"gross": {
"amount": 20.0
},
"net": {
"amount": 20.0
}
},
"unitDiscount": {
"amount": 2.0
}
}
]
},
"errors": []
}
}
}
The discount amount can be found in order.discounts.amount
, the value is equal to the
order.lines.unitDiscount
multiplied by the line quantity.
The discount can also be seen in the line prices - compare the undiscountedUnitPrice
and the unitPrice
.
Sale discount
In the case of a product on sale, the applied discount is visible only on the order and lines
prices; the order.discounts
field is empty. Let's see the following example,
for completing the checkout with two items of the product on sale.
{
"data": {
"checkoutComplete": {
"order": {
"id": "T3JkZXI6ZmQwNDFiMGMtZjFmYy00MjNjLTllMmUtOGJlOTY1ZDQwOGYy",
"status": "UNFULFILLED",
"totalCaptured": {
"amount": 133.51
},
"subtotal": {
"net": {
"amount": 52.83
},
"gross": {
"amount": 56.0
}
},
"total": {
"currency": "USD",
"net": {
"amount": 125.95
},
"gross": {
"amount": 133.51
}
},
"undiscountedTotal": {
"currency": "USD",
"net": {
"amount": 143.12
},
"gross": {
"amount": 147.51
}
},
"discounts": [],
"lines": [
{
"quantity": 2,
"totalPrice": {
"gross": {
"amount": 56.0
},
"net": {
"amount": 52.83
}
},
"unitPrice": {
"gross": {
"amount": 28.0
},
"net": {
"amount": 26.42
}
},
"undiscountedUnitPrice": {
"gross": {
"amount": 35.0
},
"net": {
"amount": 35.0
}
},
"unitDiscount": {
"amount": 7.0
}
}
]
},
"errors": []
}
}
}
As you can see, the order.discounts
field is empty, but there is a difference between
order.total
and order.undiscountedTotal
. The applied discount can be checked
on the unit level in the order.lines.unitDiscount
field, as well as by comparing
the order.lines.undiscountedUnitPrice
and order.lines.unitPrice
. The sum of line unit
discounts multiplied by the quantity of the line gives the total discount, which is
equal to the difference between order.total
and order.undiscountedTotal
.