@medusajs/pricing 2.22.0-snapshot-20261020204851 → 2.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +55 -0
- package/README.md +91 -2
- package/package.json +8 -4
package/AGENTS.md
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# @medusajs/pricing
|
|
2
|
+
|
|
3
|
+
Pricing Module (`Modules.PRICING`): price sets with rule-based and quantity-based prices, price lists (sales / overrides), tax-inclusive price preferences, and the price calculation used for products and shipping options.
|
|
4
|
+
|
|
5
|
+
## Using this package
|
|
6
|
+
|
|
7
|
+
- Registered by default; consumers import it as `@medusajs/medusa/pricing`. No module options.
|
|
8
|
+
- Resolve: `container.resolve(Modules.PRICING)` (`IPricingModuleService`). Prefer core-flows workflows (price lists, product variants, shipping options) for writes so links stay in sync.
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
const [price] = await pricingModuleService.calculatePrices(
|
|
12
|
+
{ id: [priceSetId] },
|
|
13
|
+
{ context: { currency_code: "eur", region_id: "reg_123", quantity: 2 } }
|
|
14
|
+
)
|
|
15
|
+
// price.calculated_amount, price.original_amount, price.is_calculated_price_tax_inclusive
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
- Through Query, request the virtual `calculated_price` relation with a `context` filter; `listPriceSets` strips it from `relations` and fills it via `calculatePrices`.
|
|
19
|
+
|
|
20
|
+
**Data models** (`src/models`): `PriceSet` (`pset_`) -> `Price` (`price_`: `currency_code`, `amount`, `min_quantity`, `max_quantity`, `rules_count`, optional `price_list`) -> `PriceRule` (`attribute`, `value`, `operator` eq/gt/gte/lt/lte, `priority`). `PriceList` (`plist_`: `status` draft/active, `type` sale/override, `starts_at`, `ends_at`, `rules_count`) -> `PriceListRule` (`attribute`, JSON `value`). `PricePreference` (`attribute` `region_id` or `currency_code`, `value`, `is_tax_inclusive`).
|
|
21
|
+
|
|
22
|
+
**Custom service methods** (`src/services/pricing-module.ts`): `calculatePrices`, `addPrices`, `removePrices`, `createPriceLists`, `updatePriceLists`, `addPriceListPrices`, `updatePriceListPrices`, `setPriceListRules`, `removePriceListRules`, `create/upsert/updatePricePreferences`; `create/update/upsertPriceSets` and `listPriceSets` / `retrievePriceSet` are overridden. Price rules are passed as an object: `prices: [{ amount, currency_code, rules: { region_id: "reg_123" } }]`.
|
|
23
|
+
|
|
24
|
+
**Events**: no custom builders; `MedusaService` emits `pricing.<kebab-entity>.<action>` (e.g. `pricing.price-set.created`, `pricing.price.updated`) from ORM hooks. The Index Module listens to the `pricing.price.*` events.
|
|
25
|
+
|
|
26
|
+
**Module links** (in `packages/modules/link-modules`): `product_variant_price_set` and `shipping_option_price_set`; deleting the variant or shipping option cascades to its price set.
|
|
27
|
+
|
|
28
|
+
Docs: https://docs.medusajs.com/resources/commerce-modules/pricing.md, https://docs.medusajs.com/resources/commerce-modules/pricing/concepts.md, https://docs.medusajs.com/resources/commerce-modules/pricing/price-rules.md, https://docs.medusajs.com/resources/commerce-modules/pricing/price-calculation.md, https://docs.medusajs.com/resources/commerce-modules/pricing/tax-inclusive-pricing.md, https://docs.medusajs.com/resources/commerce-modules/pricing/links-to-other-modules.md
|
|
29
|
+
|
|
30
|
+
## Architecture
|
|
31
|
+
|
|
32
|
+
- `src/repositories/pricing.ts` (`PricingRepository.calculatePrices`): one SQL query. Removes `currency_code` and `quantity` from the context, matches a price when all its rules (`rules_count`) match the context, and joins only active price lists within `starts_at` / `ends_at` whose list rules all match. Ordering: price-list prices first, then more rules first, then lowest amount.
|
|
33
|
+
- `calculatePrices` in the service picks per price set: `override` list price always wins; `sale` list price is used only if lower than the default price. `original_amount` is the override price if any, else the default price. Tax-inclusiveness comes from price rules / `PricePreference` for `region_id` or `currency_code`.
|
|
34
|
+
- `src/utils/validate-price-list-dates.ts` validates `starts_at` / `ends_at` input.
|
|
35
|
+
|
|
36
|
+
## Development
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
cd packages/modules/pricing
|
|
40
|
+
yarn build
|
|
41
|
+
yarn test # src/services/__tests__
|
|
42
|
+
yarn test:integration # needs Postgres
|
|
43
|
+
../../../node_modules/.bin/jest integration-tests/__tests__/services/pricing-module/calculate-price.spec.ts
|
|
44
|
+
yarn migration:create # after any change in src/models
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
- Integration tests: `integration-tests/__tests__/services/pricing-module/` (`calculate-price`, `price-list`, `price-list-rule`, `price-rule`, `price-set`, `index`).
|
|
48
|
+
|
|
49
|
+
## Gotchas
|
|
50
|
+
|
|
51
|
+
- `calculatePrices` throws `INVALID_DATA` without `context.currency_code`.
|
|
52
|
+
- A price with rules only matches when every rule matches the context; extra context keys are ignored. With more than 10 context keys, keys not used by any `price_rule` / `price_list_rule` attribute are dropped using an in-process cache that is only cleared by `create/updatePriceRules` and `create/updatePriceListRules` on this instance.
|
|
53
|
+
- Price sets without a matching price are omitted from the `calculatePrices` result (not returned as null).
|
|
54
|
+
- `updatePriceSets` with `prices` replaces the set's prices: existing prices whose IDs are not in the payload are deleted.
|
|
55
|
+
- A price list only applies when `status: "active"`, not soft-deleted, and `now()` (database time) is within `starts_at` / `ends_at`; lists default to `draft`.
|
package/README.md
CHANGED
|
@@ -1,3 +1,92 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://www.medusajs.com">
|
|
3
|
+
<picture>
|
|
4
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/59018053/229103275-b5e482bb-4601-46e6-8142-244f531cebdb.svg">
|
|
5
|
+
<source media="(prefers-color-scheme: light)" srcset="https://user-images.githubusercontent.com/59018053/229103726-e5b529a3-9b3f-4970-8a1f-c6af37f087bf.svg">
|
|
6
|
+
<img alt="Medusa logo" src="https://user-images.githubusercontent.com/59018053/229103726-e5b529a3-9b3f-4970-8a1f-c6af37f087bf.svg">
|
|
7
|
+
</picture>
|
|
8
|
+
</a>
|
|
9
|
+
</p>
|
|
10
|
+
<h1 align="center">
|
|
11
|
+
@medusajs/pricing
|
|
12
|
+
</h1>
|
|
2
13
|
|
|
3
|
-
|
|
14
|
+
<h4 align="center">
|
|
15
|
+
<a href="https://docs.medusajs.com">Documentation</a> |
|
|
16
|
+
<a href="https://www.medusajs.com">Website</a>
|
|
17
|
+
</h4>
|
|
18
|
+
|
|
19
|
+
<p align="center">
|
|
20
|
+
Building blocks for digital commerce
|
|
21
|
+
</p>
|
|
22
|
+
<p align="center">
|
|
23
|
+
<a href="https://github.com/medusajs/medusa/blob/develop/LICENSE">
|
|
24
|
+
<img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="Medusa is released under the MIT license." />
|
|
25
|
+
</a>
|
|
26
|
+
<a href="https://github.com/medusajs/medusa/blob/develop/CONTRIBUTING.md">
|
|
27
|
+
<img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat" alt="PRs welcome!" />
|
|
28
|
+
</a>
|
|
29
|
+
<a href="https://discord.gg/xpCwq3Kfn8">
|
|
30
|
+
<img src="https://img.shields.io/badge/chat-on%20discord-7289DA.svg" alt="Discord Chat" />
|
|
31
|
+
</a>
|
|
32
|
+
<a href="https://twitter.com/intent/follow?screen_name=medusajs">
|
|
33
|
+
<img src="https://img.shields.io/twitter/follow/medusajs.svg?label=Follow%20@medusajs" alt="Follow @medusajs" />
|
|
34
|
+
</a>
|
|
35
|
+
</p>
|
|
36
|
+
|
|
37
|
+
Pricing Module for Medusa: manages price sets, prices, price rules, price lists, price list rules, and price preferences. Use it to store prices in multiple currencies, apply rule-based and tiered pricing, run sales or overrides with price lists, and calculate the price that applies in a given context. It ships with `@medusajs/medusa` and is registered by default, so Medusa applications don't install it directly.
|
|
38
|
+
|
|
39
|
+
## At a glance
|
|
40
|
+
|
|
41
|
+
| | |
|
|
42
|
+
| --- | --- |
|
|
43
|
+
| Package | `@medusajs/pricing` |
|
|
44
|
+
| Type | Commerce Module |
|
|
45
|
+
| Module key | `Modules.PRICING` (`"pricing"`) |
|
|
46
|
+
| Registered by default | Yes |
|
|
47
|
+
| Import from | `@medusajs/medusa/pricing` |
|
|
48
|
+
|
|
49
|
+
## Features
|
|
50
|
+
|
|
51
|
+
- Store prices per currency in price sets, with quantity tiers and rules.
|
|
52
|
+
- Create price lists for sales and price overrides.
|
|
53
|
+
- Calculate the best price for a context, such as currency, region, or customer group.
|
|
54
|
+
- Configure tax-inclusive pricing with price preferences.
|
|
55
|
+
|
|
56
|
+
## Installation
|
|
57
|
+
|
|
58
|
+
No installation needed. The module is included in `@medusajs/medusa` and registered by default.
|
|
59
|
+
|
|
60
|
+
## Usage
|
|
61
|
+
|
|
62
|
+
Resolve the module's service from the container, for example in a workflow step:
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
import { createStep, StepResponse } from "@medusajs/framework/workflows-sdk"
|
|
66
|
+
import { Modules } from "@medusajs/framework/utils"
|
|
67
|
+
|
|
68
|
+
const createPriceSetStep = createStep(
|
|
69
|
+
"create-price-set",
|
|
70
|
+
async ({}, { container }) => {
|
|
71
|
+
const pricingModuleService = container.resolve(Modules.PRICING)
|
|
72
|
+
|
|
73
|
+
const priceSet = await pricingModuleService.createPriceSets({
|
|
74
|
+
prices: [
|
|
75
|
+
{
|
|
76
|
+
amount: 500,
|
|
77
|
+
currency_code: "USD",
|
|
78
|
+
},
|
|
79
|
+
],
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
return new StepResponse({ priceSet }, priceSet.id)
|
|
83
|
+
}
|
|
84
|
+
)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Resources
|
|
88
|
+
|
|
89
|
+
- [Pricing Module](https://docs.medusajs.com/resources/commerce-modules/pricing)
|
|
90
|
+
- [Price rules](https://docs.medusajs.com/resources/commerce-modules/pricing/price-rules)
|
|
91
|
+
- [Price calculation](https://docs.medusajs.com/resources/commerce-modules/pricing/price-calculation)
|
|
92
|
+
- [Tax-inclusive pricing](https://docs.medusajs.com/resources/commerce-modules/pricing/tax-inclusive-pricing)
|
package/package.json
CHANGED
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@medusajs/pricing",
|
|
3
|
-
"version": "2.22.0
|
|
3
|
+
"version": "2.22.0",
|
|
4
4
|
"description": "Medusa Pricing module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"files": [
|
|
8
8
|
"dist",
|
|
9
|
+
"AGENTS.md",
|
|
9
10
|
"!dist/**/__tests__",
|
|
10
11
|
"!dist/**/__mocks__",
|
|
11
12
|
"!dist/**/__fixtures__"
|
|
12
13
|
],
|
|
14
|
+
"llms": "https://docs.medusajs.com/llms.txt",
|
|
15
|
+
"llmsFull": "https://docs.medusajs.com/llms-full.txt",
|
|
16
|
+
"mcpServer": "https://docs.medusajs.com/mcp",
|
|
13
17
|
"engines": {
|
|
14
18
|
"node": ">=22.22.0"
|
|
15
19
|
},
|
|
@@ -39,10 +43,10 @@
|
|
|
39
43
|
"orm:cache:clear": "MIKRO_ORM_CLI_CONFIG=./mikro-orm.config.dev.ts MIKRO_ORM_ALLOW_GLOBAL_CLI=true medusa-mikro-orm cache:clear"
|
|
40
44
|
},
|
|
41
45
|
"devDependencies": {
|
|
42
|
-
"@medusajs/framework": "2.22.0
|
|
43
|
-
"@medusajs/test-utils": "2.22.0
|
|
46
|
+
"@medusajs/framework": "2.22.0",
|
|
47
|
+
"@medusajs/test-utils": "2.22.0"
|
|
44
48
|
},
|
|
45
49
|
"peerDependencies": {
|
|
46
|
-
"@medusajs/framework": "2.22.0
|
|
50
|
+
"@medusajs/framework": "2.22.0"
|
|
47
51
|
}
|
|
48
52
|
}
|