docs: update pricing docs (#7895)

Update pricing docs following latest changes
This commit is contained in:
Shahed Nasser
2024-07-01 16:34:13 +00:00
committed by GitHub
parent 357621d5d6
commit a8f2115157
5 changed files with 84 additions and 310 deletions
@@ -14,36 +14,6 @@ A [PriceSet](/references/pricing/models/PriceSet) represents a collection of pri
---
## Rule Type
Each price within a price set can be applied for different conditions. These conditions are represented as rule types.
A [RuleType](/references/pricing/models/RuleType) defines custom conditions. A rule type has a unique `rule_attribute` which indicates the property this rule applies on. For example, `region_id`.
This is referenced when setting a rule of a price. For example:
export const ruleTypeHighlights = [
["8", "region_id", "Reference a rule type by its `rule_attribute`."],
["8", `"PL"`, "The value of this rule."]
]
```ts highlights={ruleTypeHighlights}
const priceSet = await pricingModuleService.addPrices({
priceSetId,
prices: [
{
amount: 500,
currency_code: "EUR",
rules: {
region_id: "PL",
},
},
],
})
```
---
## Price List
A [PriceList](/references/pricing/models/PriceList) is a group of prices only enabled if their conditions and rules are satisfied. A price list has optional `start_date` and `end_date` properties, which indicate the date range in which a price list can be applied.
@@ -25,17 +25,14 @@ In this document, youll find common examples of how you can use the Pricing M
const pricingModuleService: IPricingModuleService =
request.scope.resolve(ModuleRegistrationName.PRICING)
// A rule type with \`rule_field=region_id\` should
// already be present in the database
const priceSet = await pricingModuleService.createPriceSets([
{
rules: [{ rule_field: "region_id" }],
prices: [
{
currency_code: request.body.currency_code,
amount: request.body.amount,
currency_code: "eur",
amount: 10,
rules: {
region_id: request.body.region_id,
region_id: "reg_123",
},
},
],
@@ -60,17 +57,14 @@ In this document, youll find common examples of how you can use the Pricing M
const pricingModuleService = await initializePricingModule()
const body = await request.json()
// A rule type with \`rule_field=region_i\` should
// already be present in the database
const priceSet = await pricingModuleService.createPriceSets([
{
rules: [{ rule_field: "region_id" }],
prices: [
{
currency_code: body.currency_code,
amount: body.amount,
currency_code: "eur",
amount: 10,
rules: {
region_id: body.region_id,
region_id: "reg_123",
},
},
],
@@ -151,7 +145,7 @@ In this document, youll find common examples of how you can use the Pricing M
request.scope.resolve(ModuleRegistrationName.PRICING)
const priceSet = await pricingModuleService.retrievePriceSet(
request.params.id
"pset_123"
)
res.json({ price_set: priceSet })
@@ -168,20 +162,13 @@ In this document, youll find common examples of how you can use the Pricing M
initialize as initializePricingModule,
} from "@medusajs/pricing"
type ContextType = {
params: {
id: string
}
}
export async function GET(
request: Request,
{ params }: ContextType
) {
const pricingModuleService = await initializePricingModule()
const priceSet = await pricingModuleService.retrievePriceSet(
params.id
"pset_123"
)
return NextResponse.json({ price_set: priceSet })
@@ -193,61 +180,6 @@ In this document, youll find common examples of how you can use the Pricing M
---
## Create a Rule Type
<CodeTabs groupId="app-type">
<CodeTab value="medusa" label="Medusa API Router">
```ts
import { MedusaRequest, MedusaResponse } from "@medusajs/medusa"
import { IPricingModuleService } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
export async function POST(
request: MedusaRequest,
res: MedusaResponse
): Promise<void> {
const pricingModuleService: IPricingModuleService =
request.scope.resolve(ModuleRegistrationName.PRICING)
const ruleType = await pricingModuleService.createRuleTypes([{
name: "Customer Group",
rule_attribute: "customer_group_id",
}])
res.json({ rule_type: ruleType })
}
```
</CodeTab>
<CodeTab value="nextjs" label="Next.js App Router">
```ts
import { NextResponse } from "next/server"
import {
initialize as initializePricingModule,
} from "@medusajs/pricing"
export async function POST(
request: Request
) {
const pricingModuleService = await initializePricingModule()
const ruleType = await pricingModuleService.createRuleTypes([{
name: "Customer Group",
rule_attribute: "customer_group_id",
}])
return NextResponse.json({ rule_type: ruleType })
}
```
</CodeTab>
</CodeTabs>
---
## Add Prices with Rules
<CodeTabs groupId="app-type">
@@ -266,13 +198,13 @@ In this document, youll find common examples of how you can use the Pricing M
request.scope.resolve(ModuleRegistrationName.PRICING)
const priceSet = await pricingModuleService.addPrices({
priceSetId: request.body.price_set_id,
priceSetId: "pset_123",
prices: [
{
amount: 500,
currency_code: "USD",
rules: {
region_id: request.body.region_id,
region_id: "reg_123",
},
},
],
@@ -297,13 +229,13 @@ In this document, youll find common examples of how you can use the Pricing M
const body = await request.json()
const priceSet = await pricingModuleService.addPrices({
priceSetId: body.price_set_id,
priceSetId: "pset_123",
prices: [
{
{
amount: 500,
currency_code: "USD",
rules: {
region_id: body.region_id,
region_id: "reg_123",
},
},
],
@@ -325,10 +257,8 @@ In this document, youll find common examples of how you can use the Pricing M
```ts collapsibleLines="1-8" expandButtonLabel="Show Imports"
import { MedusaRequest, MedusaResponse } from "@medusajs/medusa"
import {
IPricingModuleService,
PriceListType,
} from "@medusajs/types"
import { IPricingModuleService } from "@medusajs/types"
import { PriceListType } from "@medusajs/utils"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
export async function POST(
@@ -347,7 +277,7 @@ In this document, youll find common examples of how you can use the Pricing M
starts_at: Date.parse("01/10/2023").toString(),
ends_at: Date.parse("31/10/2023").toString(),
rules: {
region_id: ["DE", "DK"],
region_id: ["reg_123", "reg_321"],
},
prices: [
{
@@ -373,11 +303,12 @@ In this document, youll find common examples of how you can use the Pricing M
import {
initialize as initializePricingModule,
} from "@medusajs/pricing"
import { PriceListType } from "@medusajs/utils"
export async function POST(request: Request) {
const pricingModuleService = await initializePricingModule()
const priceLists =
const priceLists =
await pricingModuleService.createPriceLists([
{
title: "My Sale",
@@ -386,7 +317,7 @@ In this document, youll find common examples of how you can use the Pricing M
starts_at: Date.parse("01/10/2023").toString(),
ends_at: Date.parse("31/10/2023").toString(),
rules: {
region_id: ["DE", "DK"],
region_id: ["reg_123", "reg_321"],
},
prices: [
{
@@ -426,11 +357,11 @@ In this document, youll find common examples of how you can use the Pricing M
const price = await pricingModuleService.calculatePrices(
{
id: [request.params.id],
id: ["pset_123"],
},
{
context: {
currency_code: request.params.currency_code,
currency_code: "eur",
},
}
)
@@ -449,26 +380,21 @@ In this document, youll find common examples of how you can use the Pricing M
initialize as initializePricingModule,
} from "@medusajs/pricing"
type ContextType = {
params: {
id: string
currency_code: string
}
}
export async function GET(
request: Request,
{ params }: ContextType
) {
const pricingModuleService = await initializePricingModule()
const price = await pricingModuleService.calculatePrices({
id: [params.id],
}, {
context: {
currency_code: params.currency_code,
const price = await pricingModuleService.calculatePrices(
{
id: ["pset_123"],
},
})
{
context: {
currency_code: "eur",
},
}
)
return NextResponse.json({ price })
}
@@ -18,9 +18,8 @@ Prices are grouped in a price set, allowing you to add more than one price for a
```ts
const priceSet = await pricingModuleService.createPriceSets({
rules: [],
prices: [
{
{
amount: 500,
currency_code: "USD",
},
@@ -37,24 +36,17 @@ const priceSet = await pricingModuleService.createPriceSets({
### Advanced Rule Engine
Create custom rules and apply them to prices. This gives you more flexibility in how you condition prices, filter them, and ensure the best prices are retrieved for custom contexts.
```ts
const ruleTypes = await pricingModuleService.createRuleTypes([
{
name: "Region",
rule_field: "region_id",
},
])
Create prices with custom rules. This gives you more flexibility in how you condition prices, filter them, and ensure the best prices are retrieved for custom contexts.
```ts highlights={[["8"]]}
const priceSet = await pricingModuleService.addPrices({
priceSetId,
priceSetId: "pset_123",
prices: [
{
{
amount: 500,
currency_code: "EUR",
rules: {
region_id: "PL",
region_id: "reg_123",
},
},
],
@@ -66,22 +58,23 @@ const priceSet = await pricingModuleService.addPrices({
Price lists allow you to group prices and apply them only in specific conditions. You can also use them to override existing prices for the specified conditions.
```ts
const priceList = await pricingModuleService.createPriceLists({
const priceList = await pricingModuleService.createPriceLists([{
title: "My Sale",
description: "Sale on selected items.",
type: "sale",
starts_at: Date.parse("01/10/2023"),
ends_at: Date.parse("31/10/2023"),
starts_at: Date.parse("01/10/2023").toString(),
ends_at: Date.parse("31/10/2023").toString(),
rules: {
region_id: ["DE", "DK"],
region_id: ["reg_123", "reg_321"],
},
prices: [
{
amount: 400,
currency_code: "EUR",
price_set_id: priceSet.id,
price_set_id: "pset_123",
},
],
})
}])
```
### Price Calculation Strategy
@@ -90,11 +83,11 @@ Retrieve the best price in a given context and for the specified rule values.
```ts
const price = await pricingModuleService.calculatePrices(
{ id: [priceSetId] },
{ id: ["pset_123"] },
{
context: {
currency_code: "EUR",
region_id: "PL",
region_id: "reg_123",
},
}
)
@@ -8,15 +8,17 @@ export const metadata = {
In this document, you'll learn how prices are calculated when you use the `calculatePrices` method of the Pricing Module's main service.
## Overview
## calculatePrices Method
The [calculatePrices method](/references/pricing/calculatePrices) accepts the ID of one or more price sets and a context. It returns a price object with the best matching price for each price set.
The [calculatePrices method](/references/pricing/calculatePrices) accepts as parameters the ID of one or more price sets and a context.
It returns a price object with the best matching price for each price set.
---
## Calculation Context
The context is an object passed as a second parameter to the `calculatePrices` method. It must contain at least the `currency_code`. Only prices in the price sets with the same currency code are considered for the price selection.
The calculation context is an optional object passed as a second parameter to the `calculatePrices` method. It accepts rules to restrict the selected prices in the price set.
For example:
@@ -26,22 +28,7 @@ const price = await pricingModuleService.calculatePrices(
{
context: {
currency_code: currencyCode,
},
}
)
```
The context object can also contain any custom rules, with the key being the `rule_attribute` of a rule type and its value being the rule's value.
For example:
```ts
const price = await pricingModuleService.calculatePrices(
{ id: [priceSetId] },
{
context: {
currency_code: currencyCode,
region_id: "US",
region_id: "reg_123",
},
}
)
@@ -53,12 +40,10 @@ const price = await pricingModuleService.calculatePrices(
For each price set, the method selects two prices:
- The calculated price: a price that belongs to a price list. If there are no prices associated with a price list, itll be the same as the original price.
- The original price: If the calculated price's price list type is `override`, then the original price will be the same as the calculated price. Otheriwse, a price that doesn't belong to a price list.
- The calculated price: Either the best context-matching price that belongs to a price list or the same as the original price.
- The original price: Either the same as the calculated price if its price list is of type `override`, or the best context-matching price that doesn't belong to a price list.
After the original and calculated prices are selected, the method will use them to create a price object for each price set.
The price object has the following properties:
Both prices are returned in an object along with the following properties:
<TypeList
types={[
@@ -70,7 +55,7 @@ The price object has the following properties:
{
name: "is_calculated_price_price_list",
type: "`boolean`",
description: "Whether the calculated price belongs to a price list. As mentioned earlier, if no valid price list is found, the calculated price is set to the original price, which doesn't belong to a price list."
description: "Whether the calculated price belongs to a price list."
},
{
name: "calculated_amount",
@@ -80,7 +65,7 @@ The price object has the following properties:
{
name: "is_original_price_price_list",
type: "`boolean`",
description: "Whether the original price belongs to a price list. As mentioned earlier, if the price list of the calculated price is of type `override`, the original price will be the same as the calculated price."
description: "Whether the original price belongs to a price list."
},
{
name: "original_amount",
@@ -95,10 +80,10 @@ The price object has the following properties:
{
name: "calculated_price",
type: "`object`",
description: "The calculated price's price details and potentially its associated price list.",
description: "The calculated price's price details.",
children: [
{
name: "price_id",
name: "id",
type: "`string`",
description: "The ID of the price."
},
@@ -127,10 +112,10 @@ The price object has the following properties:
{
name: "original_price",
type: "`object`",
description: "The original price's price details and potentially its associated price list.",
description: "The original price's price details.",
children: [
{
name: "price_id",
name: "id",
type: "`string`",
description: "The ID of the price."
},
@@ -162,29 +147,14 @@ The price object has the following properties:
---
## Example
## Examples
Consider the following rule types and price sets:
Consider the following price set:
```ts
const ruleTypes = await pricingModuleService.createRuleTypes([
{
name: "Region",
rule_attribute: "region_id",
},
{
name: "City",
rule_attribute: "city",
},
])
const priceSet = await pricingModuleService.createPriceSets({
rules: [
{ rule_attribute: "region_id" },
{ rule_attribute: "city" },
],
prices: [
//default
// default price
{
amount: 500,
currency_code: "EUR",
@@ -195,7 +165,7 @@ const priceSet = await pricingModuleService.createPriceSets({
amount: 400,
currency_code: "EUR",
rules: {
region_id: "PL",
region_id: "reg_123",
},
},
{
@@ -210,7 +180,7 @@ const priceSet = await pricingModuleService.createPriceSets({
currency_code: "EUR",
rules: {
city: "warsaw",
region_id: "PL",
region_id: "reg_123",
},
},
],
@@ -279,7 +249,7 @@ const priceSet = await pricingModuleService.createPriceSets({
</TabsContentWrapper>
</Tabs>
### Exact Match Rule in Context
### Calculate Prices with Rules
<Tabs defaultValue="code">
<TabsList>
@@ -295,70 +265,7 @@ const priceSet = await pricingModuleService.createPriceSets({
{
context: {
currency_code: "EUR",
region_id: "PL"
}
}
)
```
</TabsContent>
<TabsContent value="result">
The returned price is:
```ts
const price = {
id: "<PRICE_SET_ID>",
is_calculated_price_price_list: false,
calculated_amount: 400,
is_original_price_price_list: false,
original_amount: 400,
currency_code: "EUR",
calculated_price: {
price_id: "<SECOND_PRICE_ID>",
price_list_id: null,
price_list_type: null,
min_quantity: null,
max_quantity: null,
},
original_price: {
price_id: "<SECOND_PRICE_ID>",
price_list_id: null,
price_list_type: null,
min_quantity: null,
max_quantity: null,
},
}
```
- Original price selection: Since the second price of the price set has the same context as the provided one, it's selected as the original price.
- Calculated price selection: since there are no associated price lists, the calculated price is set to the original price.
</TabsContent>
</TabsContentWrapper>
</Tabs>
### Context without Exact Matching Rules
<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: {
currency_code: "EUR",
region_id: "PL",
region_id: "reg_123",
city: "krakow"
}
}
@@ -399,12 +306,7 @@ const priceSet = await pricingModuleService.createPriceSets({
}
```
- Original price selection: The fourth price in the price list is selected based on the following process:
- There are no prices having the same rules as the context.
- Retrieve all prices matching some combination of the rules in the context.
- Sort the prices in descending order by their number of rules, each rule type's default priority, and the priority of the rule values.
- All rule types, in this case, don't have a priority. So, the sorting depends on the number of rules each price has.
- The fourth price has two rules, and the second and third have one rule. So, the fourth price is selected as the original price.
- Original price selection: The fourth price in the price list is selected as the best price.
- Calculated price selection: since there are no associated price lists, the calculated price is set to the original price.
</TabsContent>
@@ -422,14 +324,15 @@ const priceSet = await pricingModuleService.createPriceSets({
<TabsContent value="code">
```ts
const priceList = pricingModuleService.createPriceLists({
name: "Test Price List",
starts_at: Date.parse("01/10/2023"),
ends_at: Date.parse("31/10/2023"),
const priceList = pricingModuleService.createPriceLists([{
title: "Summer Price List",
description: "Price list for summer sale",
starts_at: Date.parse("01/10/2023").toString(),
ends_at: Date.parse("31/10/2023").toString(),
rules: {
region_id: ['PL']
},
type: "sale"
type: "sale",
prices: [
{
amount: 400,
@@ -442,7 +345,7 @@ const priceSet = await pricingModuleService.createPriceSets({
price_set_id: priceSet.id,
},
],
});
}]);
const price = await pricingModuleService.calculatePrices(
{ id: [priceSet.id] },
@@ -490,10 +393,8 @@ const priceSet = await pricingModuleService.createPriceSets({
}
```
- Original price selection: The process is explained in the Context without Exact Matching Rules section.
- Calculated price selection: The first price of the price list is selected based on the following process:
- The price set has a price list associated with it. So, retrieve its prices and sort them in ascending order by their amount.
- Since the first price of the price list has the lowest amount, it's selected as the calculated price.
- Original price selection: The fourth price in the price list is selected as the best price.
- Calculated price selection: The first price of the price list is selected as the best price.
</TabsContent>
</TabsContentWrapper>
@@ -8,33 +8,19 @@ In this document, you'll learn about price rules for price sets and price lists.
## Price Rule
Each rule of a price within a price set is represented by the [PriceRule data model](/references/pricing/models/PriceRule), which holds the value of a rule type. The `Price` data model has a `rules_count` property, which indicates how many rules, represented by `PriceRule`, are applied to the price.
Prices can be restricted by rules. Each rule of a price is represented by the [PriceRule data model](/references/pricing/models/PriceRule).
![A diagram showcasing the relation between the PriceRule, PriceSet, Price, and RuleType.](https://res.cloudinary.com/dza7lstvk/image/upload/v1709648772/Medusa%20Resources/price-rule-1_vy8bn9.jpg)
The `Price` data model has a `rules_count` property, which indicates how many rules, represented by `PriceRule`, are applied to the price.
For example, you create a `zip_code` rule type. Then, a price within the price set can have the rule value `10557`, indicating that the price can only be applied within the `10557` zip code.
![A diagram showcasing the relation between the PriceRule and Price](https://res.cloudinary.com/dza7lstvk/image/upload/v1709648772/Medusa%20Resources/price-rule-1_vy8bn9.jpg)
Each price within the price set can have different values for the same rule type.
For exmaple, you create a price restricted to `10557` zip codes.
For example:
A price can have multiple price rules. For example:
![A diagram showcasing the relation between the PriceRule, PriceSet, Price, and RuleType.](https://res.cloudinary.com/dza7lstvk/image/upload/v1709648884/Medusa%20Resources/price-rule-2_b6fuyb.jpg)
![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)
Each price can have multiple rules applied to it as well.
For example, a price can have the rules `zip_code` and `region_id` applied to it. In this case, the value of each rule is represented by a `PriceRule`.
![A diagram showcasing the relation between the PriceRule, PriceSet, Price, and RuleType with multiple rules.](https://res.cloudinary.com/dza7lstvk/image/upload/v1709649296/Medusa%20Resources/price-rule-3_pwpocz.jpg)
---
## Restrict Price Rules
The [PriceSetRuleType data model](/references/pricing/models/PriceSetRuleType) indicates what rules the prices can have within a price set. It creates a relation between the `PriceSet` and `RuleType` data models.
For example, to use the `zip_code` rule type on a price in a price set, the rule type must first be enabled on the price set through the `PriceSetRuleType`.
![A diagram showcasing the relation between the PriceSet, PriceRule, Price, RuleType, and PriceSetRuleType](https://res.cloudinary.com/dza7lstvk/image/upload/v1709649375/Medusa%20Resources/price-set-rule-type_cqqt0u.jpg)
For example, a price can be restricted by a region and a zip code.
---
@@ -42,6 +28,4 @@ For example, to use the `zip_code` rule type on a price in a price set, the rule
Rules that can be applied to a price list are represented by the [PriceListRule data model](/references/pricing/models/PriceListRule). The `rules_count` property of a `PriceList` indicates how many rules are applied to it.
Each rule of a price list can have more than one value, representing its values by the [PriceListRuleValue data model](/references/pricing/models/PriceListRuleValue).
![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)