docs: add missing details for tiered pricing (#12374)

* docs: add missing details for tiered pricing

* adjustments
This commit is contained in:
Shahed Nasser
2025-05-06 14:44:50 +03:00
committed by GitHub
parent f74586e772
commit ea6faa8c82
9 changed files with 14642 additions and 14274 deletions
File diff suppressed because it is too large Load Diff
@@ -31,6 +31,7 @@ Learn more about why modules are isolated in [this documentation](!docs!/learn/f
- [Integrate Third-Party Fulfillment Providers](./fulfillment-provider/page.mdx): Create third-party fulfillment providers to provide customers with shipping options and fulfill their orders.
- [Restrict By Location and Rules](./shipping-option/page.mdx): Shipping options can be restricted to specific geographical locations. You can also specify custom rules to restrict shipping options.
- [Support Different Fulfillment Forms](./concepts/page.mdx): Support various fulfillment forms, such as shipping or pick up.
- [Tiered Pricing and Price Rules](../pricing/price-rules/page.mdx): Set prices for shipping options with tiers and rules, allowing you to create complex pricing strategies.
---
@@ -25,7 +25,7 @@ Learn more about why modules are isolated in [this documentation](!docs!/learn/f
## Pricing Features
- [Price Management](./concepts/page.mdx): Store and manage prices of a resource, such as a product or a variant.
- [Advanced Rule Engine](./price-rules/page.mdx): Create prices with custom rules to condition prices based on different contexts.
- [Advanced Rule Engine](./price-rules/page.mdx): Create prices with tiers and custom rules to condition prices based on different contexts.
- [Price Lists](./concepts/page.mdx#price-list): Group prices and apply them only in specific conditions with price lists.
- [Price Calculation Strategy](./price-calculation/page.mdx): Retrieve the best price in a given context and for the specified rule values.
- [Tax-Inclusive Pricing](./tax-inclusive-pricing/page.mdx): Calculate prices with taxes included in the price, and Medusa will handle calculating the taxes automatically.
@@ -193,6 +193,11 @@ const priceSet = await pricingModuleService.createPriceSets({
region_id: "reg_123",
},
},
{
amount: 200,
currency_code: "EUR",
min_quantity: 100,
}
],
})
```
@@ -329,6 +334,83 @@ const priceSet = await pricingModuleService.createPriceSets({
</TabsContentWrapper>
</Tabs>
### Tiered Pricing Selection
<Tabs defaultValue="code">
<TabsList>
<TabsTrigger value="code">Code</TabsTrigger>
<TabsTrigger value="result">Result</TabsTrigger>
</TabsList>
<TabsContentWrapper>
<TabsContent value="code">
```ts
const price = await pricingModuleService.calculatePrices(
{ id: [priceSet.id] },
{
context: {
cart: {
items: [
{
id: "item_1",
quantity: 200,
// assuming the price set belongs to this variant
variant_id: "variant_1",
// ...
}
],
// ...
}
}
}
)
```
</TabsContent>
<TabsContent value="result">
The returned price is:
```ts
const price = {
id: "<PRICE_SET_ID>",
is_calculated_price_price_list: false,
calculated_amount: 200,
is_original_price_price_list: false,
original_amount: 200,
currency_code: "EUR",
is_calculated_price_tax_inclusive: false,
is_original_price_tax_inclusive: false,
calculated_price: {
price_id: "<DEFAULT_PRICE_ID>",
price_list_id: null,
price_list_type: null,
min_quantity: 100,
max_quantity: null,
},
original_price: {
price_id: "<DEFAULT_PRICE_ID>",
price_list_id: null,
price_list_type: null,
min_quantity: 100,
max_quantity: null,
},
}
```
- Original price selection: the fifth price in the price list is selected as the best price because the cart item quantity is 200.
- This is assuming the price set belongs to the cart item's variant.
- Calculated price selection: since there are no associated price lists, the calculated price is set to the original price.
</TabsContent>
</TabsContentWrapper>
</Tabs>
### Price Selection with Price List
<Tabs defaultValue="code">
@@ -7,17 +7,161 @@ tags:
- concept
---
import { CodeTabs, CodeTab } from "docs-ui"
export const metadata = {
title: `Price Rules`,
title: `Price Tiers and Rules`,
}
# {metadata.title}
In this Pricing Module guide, you'll learn about price rules for price sets and price lists, and how to add rules to a price.
In this Pricing Module guide, you'll learn about tired prices, price rules for price sets and price lists, and how to add rules to a price.
## Tiered Pricing
Each price, represented by the [Price data model](/references/pricing/models/Price), has two optional properties that can be used to create tiered prices:
- `min_quantity`: The minimum quantity that must be in the cart for the price to be applied.
- `max_quantity`: The maximum quantity that can be in the cart for the price to be applied.
This is useful to set tiered pricing for resources like product variants and shipping options.
For example, you can set a variant's price to:
- `$10` by default.
- `$8` when the customer adds `10` or more of the variant to the cart.
- `$6` when the customer adds `20` or more of the variant to the cart.
These price definitions would look like this:
```json title="Example Prices"
[
// default price
{
"amount": 10,
"currency_code": "usd",
},
{
"amount": 8,
"currency_code": "usd",
"min_quantity": 10,
"max_quantity": 19,
},
{
"amount": 6,
"currency_code": "usd",
"min_quantity": 20,
},
],
```
### How to Create Tiered Prices?
When you create prices, you can specify a `min_quantity` and `max_quantity` for each price. This allows you to create tiered pricing, where the price changes based on the quantity of items in the cart.
For example:
<Note>
For most use cases where you're building customizations in the Medusa application, it's highly recommended to use [Medusa's workflows](../../../medusa-workflows-reference/page.mdx) rather than using the Pricing Module directly. Medusa's workflows already implement extensive functionalities that you can re-use in your custom flows, with reliable roll-back mechanism.
</Note>
<CodeTabs group="price-example">
<CodeTab label="Using Medusa Workflows" value="workflows">
export const tieredPricingHighlights = [
["16", "min_quantity", "The minimum quantity that must be in the cart for the price to be applied."],
["17", "max_quantity", "The maximum quantity that can be in the cart for the price to be applied."],
]
```ts highlights={tieredPricingHighlights}
const { result } = await createProductsWorkflow(container)
.run({
input: {
products: [{
variants: [{
id: "variant_1",
prices: [
// default price
{
amount: 10,
currency_code: "usd",
},
{
amount: 8,
currency_code: "usd",
min_quantity: 10,
max_quantity: 19,
},
{
amount: 6,
currency_code: "usd",
min_quantity: 20,
},
],
// ...
}]
}],
// ...
}
})
```
</CodeTab>
<CodeTab label="Using the Pricing Module" value="pricing-module">
```ts
const priceSet = await pricingModule.addPrices({
priceSetId: "pset_1",
prices: [
// default price
{
amount: 10,
currency_code: "usd",
},
// tiered prices
{
amount: 8,
currency_code: "usd",
min_quantity: 10,
max_quantity: 19,
},
{
amount: 6,
currency_code: "usd",
min_quantity: 20,
},
],
})
```
</CodeTab>
</CodeTabs>
In this example, you create a product with a variant whose default price is `$10`. You also add two tiered prices that set the price to `$8` when the quantity is between `10` and `19`, and to `$6` when the quantity is `20` or more.
### How are Tiered Prices Applied?
The [price calculation](../price-calculation/page.mdx) mechanism considers the cart's items as a context when choosing the best price to apply.
For example, consider the customer added the `variant_1` product variant (created in the workflow snippet of the [above section](#how-to-create-tiered-prices)) to their cart with a quantity of `15`.
The price calculation mechanism will choose the second price, which is `$8`, because the quantity of `15` is between `10` and `19`.
<Note>
If there are other rules applied to the price, they may affect the price calculation. Keep reading to learn about other price rules, and refer to the [Price Calculation](../price-calculation/page.mdx) guide for more details on the calculation mechanism.
</Note>
---
## Price Rule
You can restrict prices by rules. Each rule of a price is represented by the [PriceRule data model](/references/pricing/models/PriceRule).
You can also restrict prices by advanced rules, such as a customer's group, zip code, or a cart's total.
Each rule of a price is represented by the [PriceRule data model](/references/pricing/models/PriceRule).
The `Price` data model has a `rules_count` property, which indicates how many rules, represented by `PriceRule`, are applied to the price.
@@ -31,9 +175,7 @@ For example, a price can be restricted by a region and a zip code.
![A diagram showcasing the relation between the PriceRule and Price with multiple rules.](https://res.cloudinary.com/dza7lstvk/image/upload/v1709649296/Medusa%20Resources/price-rule-3_pwpocz.jpg)
---
## Price List Rules
### Price List Rules
Rules applied to a price list are represented by the [PriceListRule data model](/references/pricing/models/PriceListRule).
@@ -41,17 +183,20 @@ The `rules_count` property of a `PriceList` indicates how many rules are applied
![A diagram showcasing the relation between the PriceSet, PriceList, Price, RuleType, and PriceListRuleValue](https://res.cloudinary.com/dza7lstvk/image/upload/v1709641999/Medusa%20Resources/price-list_zd10yd.jpg)
---
### How to Create Prices with Rules?
## How to Set Rules on a Price?
When you create prices, you can specify rules for each price. This allows you to create complex pricing strategies based on different contexts.
### Using Workflows
For example:
Medusa uses the Pricing Module to store prices of different resources, such as product variants and shipping options.
<Note>
When you manage one of these resources using [Medusa's workflows](../../../medusa-workflows-reference/page.mdx) or using the API routes that use them, you can set rules on a price using the `rules` property of the price object.
For most use cases where you're building customizations in the Medusa application, it's highly recommended to use [Medusa's workflows](../../../medusa-workflows-reference/page.mdx) rather than using the Pricing Module directly. Medusa's workflows already implement extensive functionalities that you can re-use in your custom flows, with reliable roll-back mechanism.
For example, when creating a shipping option using the [createShippingOptionsWorkflow](!resources!/references/medusa-workflows/createShippingOptionsWorkflow) to create a shipping option, you can make the shipping price free based on the cart total:
</Note>
<CodeTabs group="price-example">
<CodeTab label="Using Medusa Workflows" value="workflows">
export const workflowHighlights = [
["19", "rules", "The default price doesn't have rules."],
@@ -95,19 +240,8 @@ const { result } = await createShippingOptionsWorkflow(container)
})
```
In this example, you create a shipping option whose default price is `$10`. When the total of the cart or order using this shipping option is greater than `$100`, the shipping option's price becomes free.
### Using Pricing Module's Service
<Note>
For most use cases, it's recommended to use [workflows](#using-workflows) instead of directly using the module's service.
</Note>
When adding a price using the [addPrices](!resources!/references/pricing/addPrices) method of the Pricing Module's service, pass the `rules` property to a price object.
For example:
</CodeTab>
<CodeTab label="Using the Pricing Module" value="pricing-module">
```ts
const priceSet = await pricingModule.addPrices({
@@ -134,7 +268,10 @@ const priceSet = await pricingModule.addPrices({
})
```
In this example, you set the default price of a resource (for example, a shipping option), to `$10`. You also add a conditioned price that sets the price to `0` when the cart or order's total is greater than or equal to `$100`.
</CodeTab>
</CodeTabs>
In this example, you create a shipping option whose default price is `$10`. When the total of the cart or order using this shipping option is greater than `$100`, the shipping option's price becomes free.
### How is the Price Rule Applied?
@@ -27,6 +27,7 @@ Learn more about why modules are isolated in [this documentation](!docs!/learn/f
- [Products Management](/references/product/models/Product): Store and manage products. Products have custom options, such as color or size, and each variant in the product sets the value for these options.
- [Product Organization](/references/product/models): The Product Module provides different data models used to organize products, including categories, collections, tags, and more.
- [Bundled and Multi-Part Products](../inventory/inventory-kit/page.mdx): Create and manage inventory kits for a single product, allowing you to implement use cases like bundled or multi-part products.
- [Tiered Pricing and Price Rules](../pricing/price-rules/page.mdx): Set prices for product variants with tiers and rules, allowing you to create complex pricing strategies.
---
+5 -5
View File
@@ -25,7 +25,7 @@ export const generatedEditDates = {
"app/commerce-modules/fulfillment/item-fulfillment/page.mdx": "2024-10-08T14:38:15.496Z",
"app/commerce-modules/fulfillment/module-options/page.mdx": "2024-10-15T12:51:56.118Z",
"app/commerce-modules/fulfillment/shipping-option/page.mdx": "2025-04-24T09:21:52.540Z",
"app/commerce-modules/fulfillment/page.mdx": "2025-04-17T08:48:19.367Z",
"app/commerce-modules/fulfillment/page.mdx": "2025-05-06T10:33:48.708Z",
"app/commerce-modules/inventory/_events/_events-table/page.mdx": "2024-07-03T19:27:13+03:00",
"app/commerce-modules/inventory/_events/page.mdx": "2024-07-03T19:27:13+03:00",
"app/commerce-modules/inventory/concepts/page.mdx": "2025-02-13T12:37:28.918Z",
@@ -56,15 +56,15 @@ export const generatedEditDates = {
"app/commerce-modules/pricing/_events/_events-table/page.mdx": "2024-07-03T19:27:13+03:00",
"app/commerce-modules/pricing/_events/page.mdx": "2024-07-03T19:27:13+03:00",
"app/commerce-modules/pricing/concepts/page.mdx": "2024-10-09T13:37:25.678Z",
"app/commerce-modules/pricing/price-calculation/page.mdx": "2024-10-09T13:43:14.038Z",
"app/commerce-modules/pricing/price-rules/page.mdx": "2025-04-17T14:31:26.650Z",
"app/commerce-modules/pricing/price-calculation/page.mdx": "2025-05-06T10:31:48.476Z",
"app/commerce-modules/pricing/price-rules/page.mdx": "2025-05-06T10:52:21.010Z",
"app/commerce-modules/pricing/tax-inclusive-pricing/page.mdx": "2024-10-09T13:48:23.261Z",
"app/commerce-modules/pricing/page.mdx": "2025-04-17T08:48:29.165Z",
"app/commerce-modules/pricing/page.mdx": "2025-05-06T10:48:45.645Z",
"app/commerce-modules/product/_events/_events-table/page.mdx": "2024-07-03T19:27:13+03:00",
"app/commerce-modules/product/_events/page.mdx": "2024-07-03T19:27:13+03:00",
"app/commerce-modules/product/guides/price/page.mdx": "2024-12-25T15:10:37.730Z",
"app/commerce-modules/product/guides/price-with-taxes/page.mdx": "2024-12-25T15:10:40.879Z",
"app/commerce-modules/product/page.mdx": "2025-04-17T08:48:20.755Z",
"app/commerce-modules/product/page.mdx": "2025-05-06T10:33:30.948Z",
"app/commerce-modules/promotion/_events/_events-table/page.mdx": "2024-07-03T19:27:13+03:00",
"app/commerce-modules/promotion/_events/page.mdx": "2024-07-03T19:27:13+03:00",
"app/commerce-modules/promotion/actions/page.mdx": "2024-10-09T14:49:01.645Z",
@@ -10182,7 +10182,7 @@ const generatedgeneratedCommerceModulesSidebarSidebar = {
"isPathHref": true,
"type": "link",
"path": "/commerce-modules/pricing/price-rules",
"title": "Price Rules",
"title": "Price Tiers and Rules",
"children": []
},
{
+1 -1
View File
@@ -25,7 +25,7 @@ export const pricingSidebar = [
{
type: "link",
path: "/commerce-modules/pricing/price-rules",
title: "Price Rules",
title: "Price Tiers and Rules",
},
{
type: "link",