@mercurjs/docs 2.3.8-canary.3 → 2.3.8-canary.4

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.
Files changed (113) hide show
  1. package/content/learn/architecture.mdx +166 -263
  2. package/content/platform/attribute/concepts/attribute-types.mdx +73 -46
  3. package/content/platform/attribute/concepts/global-vs-inline.mdx +54 -32
  4. package/content/platform/attribute/concepts/variant-axes.mdx +54 -32
  5. package/content/platform/attribute/guides/attach-attributes-to-a-product.mdx +96 -53
  6. package/content/platform/attribute/guides/create-a-variant-axis.mdx +106 -57
  7. package/content/platform/attribute/guides/create-an-attribute.mdx +105 -56
  8. package/content/platform/attribute/overview.mdx +37 -33
  9. package/content/platform/attribute/reference/data-models.mdx +53 -38
  10. package/content/platform/attribute/reference/events.mdx +47 -24
  11. package/content/platform/attribute/reference/links.mdx +98 -27
  12. package/content/platform/attribute/reference/service.mdx +71 -32
  13. package/content/platform/attribute/reference/workflows.mdx +158 -28
  14. package/content/platform/catalog/concepts/master-products.mdx +39 -37
  15. package/content/platform/catalog/concepts/product-seller-allowlist.mdx +56 -35
  16. package/content/platform/catalog/concepts/status-lifecycle.mdx +55 -49
  17. package/content/platform/catalog/concepts/variants-categories-collections.mdx +55 -35
  18. package/content/platform/catalog/guides/allowlist-stores.mdx +100 -37
  19. package/content/platform/catalog/guides/create-a-master-product.mdx +124 -48
  20. package/content/platform/catalog/guides/publish-or-reject-a-product.mdx +120 -55
  21. package/content/platform/catalog/overview.mdx +39 -35
  22. package/content/platform/catalog/reference/data-models.mdx +154 -43
  23. package/content/platform/catalog/reference/events.mdx +41 -25
  24. package/content/platform/catalog/reference/links.mdx +196 -28
  25. package/content/platform/catalog/reference/service.mdx +57 -35
  26. package/content/platform/catalog/reference/workflows.mdx +124 -30
  27. package/content/platform/commission/concepts/order-commission-lines.mdx +54 -52
  28. package/content/platform/commission/concepts/rule-matching.mdx +53 -63
  29. package/content/platform/commission/concepts/rules-and-rates.mdx +61 -59
  30. package/content/platform/commission/guides/batch-update-rules.mdx +69 -41
  31. package/content/platform/commission/guides/create-a-rate.mdx +101 -53
  32. package/content/platform/commission/guides/refresh-order-commission-lines.mdx +104 -35
  33. package/content/platform/commission/overview.mdx +43 -35
  34. package/content/platform/commission/reference/data-models.mdx +59 -45
  35. package/content/platform/commission/reference/events.mdx +28 -34
  36. package/content/platform/commission/reference/links.mdx +42 -33
  37. package/content/platform/commission/reference/service.mdx +103 -28
  38. package/content/platform/commission/reference/workflows.mdx +101 -27
  39. package/content/platform/offer/concepts/pricing-and-inventory.mdx +63 -49
  40. package/content/platform/offer/concepts/shipping.mdx +28 -29
  41. package/content/platform/offer/concepts/what-is-an-offer.mdx +48 -45
  42. package/content/platform/offer/guides/bulk-create-offers.mdx +97 -61
  43. package/content/platform/offer/guides/create-an-offer.mdx +112 -60
  44. package/content/platform/offer/guides/manage-offer-inventory.mdx +78 -38
  45. package/content/platform/offer/overview.mdx +39 -32
  46. package/content/platform/offer/reference/data-models.mdx +77 -47
  47. package/content/platform/offer/reference/events.mdx +44 -18
  48. package/content/platform/offer/reference/links.mdx +92 -40
  49. package/content/platform/offer/reference/service.mdx +66 -31
  50. package/content/platform/offer/reference/workflows.mdx +146 -37
  51. package/content/platform/order-group/concepts/computed-totals.mdx +40 -37
  52. package/content/platform/order-group/concepts/order-splitting.mdx +41 -39
  53. package/content/platform/order-group/concepts/the-order-group.mdx +39 -32
  54. package/content/platform/order-group/guides/list-order-groups.mdx +96 -56
  55. package/content/platform/order-group/guides/retrieve-an-order-group.mdx +93 -42
  56. package/content/platform/order-group/guides/split-a-cart.mdx +115 -40
  57. package/content/platform/order-group/overview.mdx +42 -32
  58. package/content/platform/order-group/reference/data-models.mdx +48 -31
  59. package/content/platform/order-group/reference/events.mdx +29 -17
  60. package/content/platform/order-group/reference/links.mdx +90 -29
  61. package/content/platform/order-group/reference/service.mdx +55 -31
  62. package/content/platform/order-group/reference/workflows.mdx +83 -24
  63. package/content/platform/payout/concepts/account-lifecycle.mdx +64 -67
  64. package/content/platform/payout/concepts/accounts-and-onboarding.mdx +50 -40
  65. package/content/platform/payout/concepts/payout-pipeline.mdx +70 -73
  66. package/content/platform/payout/guides/create-a-payout-account.mdx +65 -41
  67. package/content/platform/payout/guides/process-a-provider-webhook.mdx +84 -38
  68. package/content/platform/payout/guides/start-provider-onboarding.mdx +90 -46
  69. package/content/platform/payout/overview.mdx +43 -34
  70. package/content/platform/payout/reference/data-models.mdx +63 -36
  71. package/content/platform/payout/reference/events.mdx +56 -30
  72. package/content/platform/payout/reference/links.mdx +52 -22
  73. package/content/platform/payout/reference/service.mdx +72 -33
  74. package/content/platform/payout/reference/workflows.mdx +80 -19
  75. package/content/platform/product-edit/concepts/change-actions.mdx +52 -45
  76. package/content/platform/product-edit/concepts/change-pipeline.mdx +60 -52
  77. package/content/platform/product-edit/concepts/status-and-auto-confirm.mdx +43 -46
  78. package/content/platform/product-edit/guides/confirm-or-decline-a-change.mdx +104 -56
  79. package/content/platform/product-edit/guides/edit-a-product.mdx +126 -46
  80. package/content/platform/product-edit/guides/request-a-revision.mdx +99 -39
  81. package/content/platform/product-edit/overview.mdx +41 -34
  82. package/content/platform/product-edit/reference/data-models.mdx +73 -47
  83. package/content/platform/product-edit/reference/events.mdx +39 -29
  84. package/content/platform/product-edit/reference/links.mdx +32 -24
  85. package/content/platform/product-edit/reference/service.mdx +45 -26
  86. package/content/platform/product-edit/reference/workflows.mdx +173 -31
  87. package/content/platform/review/concepts/product-vs-seller-reviews.mdx +42 -41
  88. package/content/platform/review/concepts/ratings-and-moderation.mdx +45 -44
  89. package/content/platform/review/concepts/the-review-model.mdx +52 -45
  90. package/content/platform/review/guides/compute-aggregate-ratings.mdx +62 -37
  91. package/content/platform/review/guides/create-a-review.mdx +109 -39
  92. package/content/platform/review/guides/moderate-a-review.mdx +83 -37
  93. package/content/platform/review/guides/respond-to-a-review.mdx +85 -40
  94. package/content/platform/review/overview.mdx +43 -33
  95. package/content/platform/review/reference/data-models.mdx +41 -27
  96. package/content/platform/review/reference/events.mdx +55 -37
  97. package/content/platform/review/reference/links.mdx +80 -22
  98. package/content/platform/review/reference/service.mdx +61 -33
  99. package/content/platform/review/reference/workflows.mdx +80 -24
  100. package/content/platform/store/concepts/lifecycle.mdx +68 -44
  101. package/content/platform/store/concepts/store-entity.mdx +45 -27
  102. package/content/platform/store/concepts/team.mdx +56 -35
  103. package/content/platform/store/guides/create-a-store.mdx +102 -35
  104. package/content/platform/store/guides/manage-the-team.mdx +122 -32
  105. package/content/platform/store/guides/moderate-a-store.mdx +107 -38
  106. package/content/platform/store/overview.mdx +41 -34
  107. package/content/platform/store/reference/data-models.mdx +132 -57
  108. package/content/platform/store/reference/events.mdx +42 -17
  109. package/content/platform/store/reference/links.mdx +67 -49
  110. package/content/platform/store/reference/service.mdx +105 -33
  111. package/content/platform/store/reference/workflows.mdx +304 -24
  112. package/llms.txt +111 -111
  113. package/package.json +1 -1
@@ -1,75 +1,89 @@
1
1
  ---
2
- title: "Data models"
2
+ title: "Commission data models"
3
3
  sidebarTitle: "Data models"
4
- description: "The data models owned by the Commission domain."
4
+ description: "Every field of CommissionRate, CommissionRule, CommissionRateValue, and CommissionLine."
5
5
  ---
6
6
 
7
- The Commission domain is owned by the **Commission module**. This reference
8
- lists its data models and their fields. For the full module overview, see the
9
- [Commission overview](/platform/commission/overview).
7
+ The Commission module owns four data models, defined in `packages/core/src/modules/commission/models`. Every model also has `created_at`, `updated_at`, and a nullable `deleted_at`, which Medusa adds and the tables below leave out.
10
8
 
11
9
  ## CommissionRate
12
10
 
13
- Table `commission_rate`, id prefix `comrate`. The rate the marketplace takes
14
- from a sale.
11
+ The rate the marketplace takes from a sale. Table `commission_rate`, id prefix `comrate`.
15
12
 
16
- | Field | Type | Notes |
13
+ | Field | Type | Description |
17
14
  | --- | --- | --- |
18
15
  | `id` | text | Primary key |
19
- | `name` | text | Searchable |
20
- | `code` | text | Unique, searchable; auto-generated from `name` when omitted |
21
- | `type` | enum | `CommissionRateType`, `fixed` or `percentage` |
22
- | `value` | bigNumber | Percent (for `percentage`) or fallback amount (for `fixed`) |
23
- | `currency_code` | text | Nullable; when set, the rate applies only to that currency |
24
- | `include_tax` | boolean | Default `false`; add `tax_total` to the base amount |
25
- | `include_shipping` | boolean | Default `false`; only meaningful on the global rate |
26
- | `is_enabled` | boolean | Default `true`; only enabled rates are evaluated |
27
- | `is_default` | boolean | Default `false`; the single Global Commission |
28
-
29
- Relations: `rules` (one-to-many `CommissionRule`), `values` (one-to-many
30
- `CommissionRateValue`).
16
+ | `name` | text | Display name, searchable |
17
+ | `code` | text | Unique among non-deleted rates and searchable. Generated from `name` when omitted on create |
18
+ | `type` | enum | `CommissionRateType`: `fixed` or `percentage` |
19
+ | `value` | bigNumber | The percent for `percentage`, the fallback amount for `fixed` |
20
+ | `currency_code` | text, nullable | When set, the rate applies only to orders in this currency |
21
+ | `include_tax` | boolean | Default `false`. Adds the line’s `tax_total` to the base amount |
22
+ | `include_shipping` | boolean | Default `false`. Produces shipping lines, on the `is_default` rate only |
23
+ | `is_enabled` | boolean | Default `true`. Disabled rates are skipped |
24
+ | `is_default` | boolean | Default `false`. Marks the global commission, which can’t be deleted |
25
+
26
+ Relations:
27
+
28
+ - **`rules`**: has many `CommissionRule`
29
+ - **`values`**: has many `CommissionRateValue`
31
30
 
32
31
  ## CommissionRule
33
32
 
34
- Table `commission_rule`, id prefix `comrule`. Scopes a rate to a slice of the
35
- catalog.
33
+ Scopes a rate to one record in one dimension. Table `commission_rule`, id prefix `comrule`.
36
34
 
37
- | Field | Type | Notes |
35
+ | Field | Type | Description |
38
36
  | --- | --- | --- |
39
37
  | `id` | text | Primary key |
40
38
  | `reference` | text | The dimension: `product`, `product_type`, `product_collection`, `product_category`, or `seller` |
41
39
  | `reference_id` | text | The id of the record in that dimension |
42
- | `commission_rate` | relation | The rate this rule belongs to (`belongsTo`) |
40
+ | `commission_rate_id` | text | Foreign key to the owning rate |
41
+
42
+ Relations:
43
+
44
+ - **`commission_rate`**: belongs to `CommissionRate`
45
+
46
+ The table has an index on `(reference, reference_id)` for non-deleted rows.
43
47
 
44
48
  ## CommissionRateValue
45
49
 
46
- Table `commission_rate_value`, id prefix `comval`. A per-currency amount for a
47
- fixed rate.
50
+ A per-currency amount for a fixed rate. Table `commission_rate_value`, id prefix `comval`.
48
51
 
49
- | Field | Type | Notes |
52
+ | Field | Type | Description |
50
53
  | --- | --- | --- |
51
54
  | `id` | text | Primary key |
52
- | `currency_code` | text | The currency this amount applies to |
53
- | `amount` | bigNumber | The flat commission for that currency |
54
- | `commission_rate` | relation | The rate this value belongs to (`belongsTo`) |
55
+ | `currency_code` | text | The currency this amount applies to, such as `usd` |
56
+ | `amount` | bigNumber | The fixed commission per line item in that currency |
57
+ | `commission_rate_id` | text | Foreign key to the owning rate |
58
+
59
+ Relations:
60
+
61
+ - **`commission_rate`**: belongs to `CommissionRate`
55
62
 
56
63
  ## CommissionLine
57
64
 
58
- Table `commission_line`, id prefix `comline`. The resolved commission for one
59
- order line.
65
+ The resolved commission for one order line item or shipping method. Table `commission_line`, id prefix `comline`.
60
66
 
61
- | Field | Type | Notes |
67
+ | Field | Type | Description |
62
68
  | --- | --- | --- |
63
69
  | `id` | text | Primary key |
64
- | `item_id` | text | Nullable; the order line item this line commissions |
65
- | `shipping_method_id` | text | Nullable; the shipping method this line commissions |
66
- | `commission_rate_id` | text | Nullable; the rate that matched |
67
- | `code` | text | The matched rate's code |
68
- | `rate` | float | The applied rate |
69
- | `amount` | bigNumber | The computed commission amount |
70
- | `description` | text | Nullable; `"Shipping Commission"` on shipping lines |
71
-
72
- <Note>
73
- A commission line anchors to **either** `item_id` **or** `shipping_method_id`.
74
- It references those records by id, not through a module link.
75
- </Note>
70
+ | `item_id` | text, nullable | The order line item this line commissions |
71
+ | `shipping_method_id` | text, nullable | The order shipping method this line commissions |
72
+ | `commission_rate_id` | text, nullable | The rate that produced the line. Plain text, not a relation |
73
+ | `provider_id` | text | Default `system`. The provider that computed the line |
74
+ | `code` | text | The code of the rate that produced the line |
75
+ | `rate` | float | The percent, or the fixed amount, that was applied |
76
+ | `amount` | bigNumber | The commission amount |
77
+ | `description` | text, nullable | `Shipping Commission` on shipping lines from the `system` provider |
78
+ | `data` | json, nullable | Free data from the provider |
79
+
80
+ The table has indexes on `item_id` and on `shipping_method_id` for non-deleted rows. A line sets one of the two anchors and leaves the other `null`.
81
+
82
+ ## Enums
83
+
84
+ `CommissionRateType` is exported from `@mercurjs/types`.
85
+
86
+ | Member | Value |
87
+ | --- | --- |
88
+ | `CommissionRateType.FIXED` | `fixed` |
89
+ | `CommissionRateType.PERCENTAGE` | `percentage` |
@@ -1,58 +1,52 @@
1
1
  ---
2
- title: "Event reference"
2
+ title: "Commission events"
3
3
  sidebarTitle: "Events"
4
- description: "How the Commission domain stays in sync with order changes."
4
+ description: "Commission emits no domain events of its own. It listens to four order events and recomputes commission lines."
5
5
  ---
6
6
 
7
- The Commission domain does **not** emit its own domain events. Commission lines
8
- are derived data, so instead of broadcasting changes, the module **subscribes**
9
- to order lifecycle events and recomputes lines whenever an order's composition
10
- changes.
7
+ The Commission module doesn’t define or emit domain events. Commission lines are derived from the order, so the module listens to order events instead and recomputes the lines when the order’s contents change.
11
8
 
12
- ## Events it reacts to
9
+ ## Events that trigger a recompute
13
10
 
14
- Mercur ships a subscriber (`order-commission-refresh-handler`) that re-runs
15
- `refreshOrderCommissionLinesWorkflow` for the affected order on each of these
16
- events:
11
+ The `order-commission-refresh-handler` subscriber, in `packages/core/src/subscribers/order-edit-confirmed.ts`, runs `refreshOrderCommissionLinesWorkflow` for the order on each of these events.
17
12
 
18
- | Event | Emitted when |
19
- | --- | --- |
20
- | `OrderEditWorkflowEvents.CONFIRMED` | An order edit is confirmed |
21
- | `OrderWorkflowEvents.RETURN_RECEIVED` | A return is received |
22
- | `OrderWorkflowEvents.CLAIM_CREATED` | A claim is created |
23
- | `OrderWorkflowEvents.EXCHANGE_CREATED` | An exchange is created |
13
+ | Event | Emitted when | Payload the subscriber reads |
14
+ | --- | --- | --- |
15
+ | `order-edit.confirmed` | An order edit is confirmed | `order_id` |
16
+ | `order.return_received` | A return is received | `order_id` |
17
+ | `order.claim_created` | A claim is created | `order_id` |
18
+ | `order.exchange_created` | An exchange is created | `order_id` |
24
19
 
25
- Because the refresh is idempotent (delete-then-insert), reacting to several
26
- events for the same order never duplicates lines.
20
+ The subscriber reads `order_id` and falls back to `id`. It does nothing when the payload has neither. The events come from Medusa as `OrderEditWorkflowEvents.CONFIRMED`, `OrderWorkflowEvents.RETURN_RECEIVED`, `OrderWorkflowEvents.CLAIM_CREATED`, and `OrderWorkflowEvents.EXCHANGE_CREATED`.
27
21
 
28
- ## Run your own side effects
22
+ Checkout doesn’t go through an event. `completeCartWithSplitOrdersWorkflow` runs the refresh as a nested step for every seller order it creates.
29
23
 
30
- To run logic when an order's commission changes, subscribe to the same order
31
- events the module listens to, then read the refreshed lines from the commission
32
- module.
24
+ ## Run your own logic after a recompute
33
25
 
34
- ```ts title="src/subscribers/commission-changed.ts"
26
+ Subscribe to the same order events to run your own logic when an order’s commission may change.
27
+
28
+ ```ts title="src/subscribers/commission-audit.ts"
35
29
  import type { SubscriberArgs, SubscriberConfig } from "@medusajs/framework"
36
30
  import { OrderWorkflowEvents } from "@medusajs/framework/utils"
37
31
 
38
- export default async function commissionChangedHandler({
32
+ export default async function commissionAudit({
39
33
  event,
40
34
  container,
41
- }: SubscriberArgs<{ order_id?: string; id?: string }>) {
42
- const orderId = event.data.order_id ?? event.data.id
43
- if (!orderId) {
44
- return
45
- }
46
- // ...read commission lines for the order, notify, sync an external ledger, etc.
35
+ }: SubscriberArgs<{ order_id: string }>) {
36
+ const logger = container.resolve("logger")
37
+ logger.info(`Commission may have changed on ${event.data.order_id}`)
47
38
  }
48
39
 
49
40
  export const config: SubscriberConfig = {
50
- event: OrderWorkflowEvents.RETURN_RECEIVED,
41
+ event: [
42
+ OrderWorkflowEvents.RETURN_RECEIVED,
43
+ OrderWorkflowEvents.CLAIM_CREATED,
44
+ ],
51
45
  }
52
46
  ```
53
47
 
48
+ Subscribers run independently, so this one can run before the refresh finishes. When you need the new lines, use the `commissionLinesUpserted` hook of `refreshOrderCommissionLinesWorkflow`, which runs after they’re written. See [Refresh order commission lines](/platform/commission/guides/refresh-order-commission-lines).
49
+
54
50
  <Note>
55
- Commission is also refreshed at checkout, as each per-seller order is created
56
- from the split cart. That refresh happens as a **step inside** the checkout
57
- workflow rather than via a separate event.
51
+ Like every `MedusaService` module, the Commission service also emits Medusa’s internal data-mutation events when records are created, updated, or deleted. Mercur doesn’t subscribe to them, and this reference doesn’t treat them as a stable contract.
58
52
  </Note>
@@ -1,45 +1,54 @@
1
1
  ---
2
- title: "Links to other modules"
2
+ title: "Commission links to other modules"
3
3
  sidebarTitle: "Links"
4
- description: "How the Commission domain connects to the catalog, sellers, and orders."
4
+ description: "Commission defines no module links. Rules and lines reference the catalog, sellers, and orders by plain id."
5
5
  ---
6
6
 
7
- Most Mercur modules connect to each other through **module links** (`defineLink`)
8
- resolved with `query.graph`. The Commission module is deliberately different: it
9
- defines **no** module links. Instead it connects to the rest of the marketplace
10
- through **soft references**. These are plain id fields resolved at calculation
11
- time. This keeps commission configuration independent of the catalog and order
12
- modules it scopes against.
7
+ The Commission module defines no module links. None of the files in `packages/core/src/links` has a commission side. Rules and lines point at records in other modules through plain id fields, which Mercur resolves at calculation time or which you filter on directly.
13
8
 
14
- ## Rules → catalog & sellers
9
+ ## Rules point at the catalog and sellers
15
10
 
16
- A `CommissionRule` points at a record in another domain through its
17
- `reference` / `reference_id` pair, resolved against the order line's product when
18
- commission is calculated:
11
+ A `CommissionRule` names its target with `reference` and `reference_id`. The `refreshOrderCommissionLinesWorkflow` reads the target’s fields from the order with `query.graph`, so the commission records never need a link.
19
12
 
20
- | `reference` | Points at | Resolved from |
13
+ | `reference` | Points at | Read from the order line |
21
14
  | --- | --- | --- |
22
- | `product` | A master product | `item.product.id` |
23
- | `product_type` | A product type | `item.product.type_id` |
24
- | `product_collection` | A collection | `item.product.collection_id` |
25
- | `product_category` | A category | `item.product.categories[].id` |
26
- | `seller` | A store | `item.offer.seller_id` |
15
+ | `product` | A master product | `items.product.id` |
16
+ | `product_type` | A product type | `items.product.type_id` |
17
+ | `product_collection` | A product collection | `items.product.collection_id` |
18
+ | `product_category` | A product category | `items.product.categories.id` |
19
+ | `seller` | A seller | `items.offer.seller_id` |
27
20
 
28
- <Note>
29
- Products are the shared master catalog, not seller-owned. The `seller`
30
- dimension resolves through the **offer** on the order line, which carries the
31
- selling store.
32
- </Note>
21
+ The `seller` row goes through the `order-line-item-offer-link` from the Offer module. Products belong to the shared catalog, so the seller of a line is the seller of the offer the customer bought.
22
+
23
+ ## Lines point at order items and shipping methods
24
+
25
+ A `CommissionLine` stores `item_id` or `shipping_method_id` as plain text. To get an order’s lines, collect the ids from the order, then filter `commission_line` by them.
26
+
27
+ ```ts
28
+ const { data: [order] } = await query.graph({
29
+ entity: "order",
30
+ fields: ["items.id", "shipping_methods.id"],
31
+ filters: { id: "order_01JD8Q1234567" },
32
+ })
33
33
 
34
- ## Lines → orders
34
+ const { data: lines } = await query.graph({
35
+ entity: "commission_line",
36
+ fields: ["item_id", "shipping_method_id", "code", "amount"],
37
+ filters: {
38
+ $or: [
39
+ { item_id: order.items.map((item) => item.id) },
40
+ { shipping_method_id: order.shipping_methods.map((m) => m.id) },
41
+ ],
42
+ },
43
+ })
44
+ ```
35
45
 
36
- A `CommissionLine` records which order line it commissions through its
37
- `item_id` (an order line item) or `shipping_method_id` (a shipping method).
38
- These are stored as plain ids, so the payout pipeline reads an order's lines by
39
- querying the commission module directly rather than traversing a link.
46
+ `createPayoutWorkflow` and the order commission-lines routes read lines the same way.
40
47
 
41
- <Tip>
42
- Because these are soft references, deleting a product, category, or order does
43
- not cascade to commission records. Rules and lines simply stop matching or are
44
- refreshed on the next order change.
45
- </Tip>
48
+ ## Lines point at their rate
49
+
50
+ `commission_rate_id` on a line is also plain text, not a relation. Query the rate separately if you need more than the `code` the line already stores.
51
+
52
+ <Note>
53
+ Plain ids don’t cascade. Deleting a product, category, or seller leaves its rules in place, where they stop matching. Deleting a rate soft-deletes it and leaves existing lines untouched.
54
+ </Note>
@@ -1,51 +1,126 @@
1
1
  ---
2
- title: "Service reference"
2
+ title: "Commission module service"
3
3
  sidebarTitle: "Service"
4
- description: "The Commission module service and its methods for working with records directly."
4
+ description: "Resolve the Commission module service, its generated and custom methods, and the commission provider interface."
5
5
  ---
6
6
 
7
- The Commission module exposes a service you can resolve from the Medusa
8
- container to read and write records directly, without going through a workflow.
9
- Use it inside custom services, subscribers, or scheduled jobs.
7
+ The Commission module service reads and writes commission records without a workflow. Use it in steps, subscribers, and scheduled jobs, and use the [workflows](/platform/commission/reference/workflows) when you need rollback or the global-rate delete guard.
8
+
9
+ ## Resolve the service
10
+
11
+ Resolve the service from the container with `MercurModules.COMMISSION`.
10
12
 
11
13
  ```ts
12
14
  import { MercurModules } from "@mercurjs/types"
13
15
 
14
- const commissionModuleService = container.resolve(MercurModules.COMMISSION)
16
+ const commission = container.resolve(MercurModules.COMMISSION)
15
17
 
16
- const [rates, count] = await commissionModuleService.listAndCountCommissionRates(
17
- { is_enabled: true }
18
+ const [rates, count] = await commission.listAndCountCommissionRates(
19
+ { is_enabled: true },
20
+ { relations: ["rules", "values"] }
18
21
  )
19
22
  ```
20
23
 
24
+ The call returns enabled rates with their rules and per-currency values, plus the total count.
25
+
21
26
  ## Generated methods
22
27
 
23
- Each data model gets a standard set of auto-generated methods. For
24
- `CommissionRate`:
28
+ The service extends `MedusaService`, so every model gets the standard methods. For `CommissionRate` they are:
25
29
 
26
30
  | Method | Description |
27
31
  | --- | --- |
28
- | `createCommissionRates(data)` | Create one or more rates (auto-generates `code`) |
29
- | `retrieveCommissionRate(id, config?)` | Retrieve a rate by id |
30
- | `listCommissionRates(filters?, config?)` | List rates matching filters |
31
- | `listAndCountCommissionRates(filters?, config?)` | List rates with a total count |
32
- | `updateCommissionRates(data)` | Update one or more rates |
33
- | `deleteCommissionRates(ids)` | Delete one or more rates |
32
+ | `retrieveCommissionRate(id, config?)` | Retrieve one rate |
33
+ | `listCommissionRates(filters?, config?)` | List rates |
34
+ | `listAndCountCommissionRates(filters?, config?)` | List rates with a count |
35
+ | `createCommissionRates(data)` | Create one rate or an array of rates |
36
+ | `updateCommissionRates(data)` | Update rates |
37
+ | `deleteCommissionRates(ids)` | Hard-delete rates |
38
+ | `softDeleteCommissionRates(ids)` | Soft-delete rates |
39
+ | `restoreCommissionRates(ids)` | Restore soft-deleted rates |
40
+
41
+ The same set exists for `CommissionRule`, `CommissionRateValue`, and `CommissionLine`, for example `listCommissionRules`, `createCommissionRateValues`, and `retrieveCommissionLine`.
34
42
 
35
- The same set exists for every model in the module: `CommissionRule`,
36
- `CommissionRateValue`, and `CommissionLine` (e.g. `createCommissionRules`,
37
- `listCommissionRateValues`, `deleteCommissionLines`).
43
+ <Warning>
44
+ `deleteCommissionRates` doesn’t check for the global rate. Use `deleteCommissionRatesWorkflow` to keep the `is_default` rate safe.
45
+ </Warning>
38
46
 
39
- ## Calculation & line methods
47
+ ## Custom methods
48
+
49
+ The service overrides or adds these methods:
40
50
 
41
51
  | Method | Description |
42
52
  | --- | --- |
43
- | `getCommissionLines(context)` | Resolve the commission lines for a calculation context (items + shipping in a currency), most-specific-wins, without persisting |
44
- | `upsertCommissionLines(lines)` | Replace lines by anchor (`item_id` / `shipping_method_id`), making refreshes idempotent |
53
+ | `createCommissionRates(data)` | Fills a missing `code` from `name` plus a random suffix, then creates. Returns one rate for one input, an array for an array |
54
+ | `listCommissionRates(filters?, config?)` | Accepts a virtual `scope_type` filter |
55
+ | `listAndCountCommissionRates(filters?, config?)` | Accepts the same `scope_type` filter |
56
+ | `getCommissionLines(context)` | Computes lines for one context with the default provider. Doesn’t persist |
57
+ | `getCommissionLinesBatch(contexts)` | Computes lines for several contexts, one array per context in order. Doesn’t persist |
58
+ | `upsertCommissionLines(lines)` | Deletes existing lines with the same `item_id` or `shipping_method_id`, then inserts `lines` |
45
59
 
46
- <Warning>
47
- Prefer [workflows](/platform/commission/reference/workflows) for order-line
48
- refreshes and rate deletion. `refreshOrderCommissionLinesWorkflow` builds the
49
- calculation context from the order and calls these methods for you;
50
- `deleteCommissionRatesWorkflow` validates that a rate is safe to delete first.
51
- </Warning>
60
+ `getCommissionLines` and `getCommissionLinesBatch` stamp the default provider’s id on any line without a `provider_id`. `getCommissionLinesBatch` falls back to one `getCommissionLines` call per context when the provider has no batch method.
61
+
62
+ ## Filter rates by scope type
63
+
64
+ `scope_type` filters rates by the dimensions their rules use, computed in the database. Pass one value, an array, or a comma-separated string. Several values are combined with OR, and an unknown value matches nothing.
65
+
66
+ | `scope_type` | Rates whose rules use |
67
+ | --- | --- |
68
+ | `store` | `seller` only, without `product_type` or `product_category` |
69
+ | `product_type` | `product_type`, without `seller` or `product_category` |
70
+ | `category` | `product_category`, without `seller` or `product_type` |
71
+ | `store_product_type` | `seller` and `product_type` |
72
+ | `store_category` | `seller` and `product_category`, without `product_type` |
73
+
74
+ ## Commission providers
75
+
76
+ A provider computes the lines from a calculation context. The module always registers the built-in `system` provider, which implements the [rule matching](/platform/commission/concepts/rule-matching) algorithm, and uses it unless you configure another one.
77
+
78
+ ```ts title="src/modules/tiered-commission/service.ts"
79
+ import { MathBN } from "@medusajs/framework/utils"
80
+ import type {
81
+ CommissionCalculationContext,
82
+ CreateCommissionLineDTO,
83
+ ICommissionProvider,
84
+ } from "@mercurjs/types"
85
+
86
+ export default class TieredCommissionProvider
87
+ implements ICommissionProvider
88
+ {
89
+ static identifier = "tiered"
90
+
91
+ async getCommissionLines(
92
+ context: CommissionCalculationContext
93
+ ): Promise<CreateCommissionLineDTO[]> {
94
+ const percent = context.additional_context?.tier === "gold" ? 8 : 12
95
+ return (context.items ?? []).map((item) => ({
96
+ item_id: item.id,
97
+ code: "tiered",
98
+ rate: percent,
99
+ amount: MathBN.div(MathBN.mult(item.subtotal, percent), 100).toNumber(),
100
+ }))
101
+ }
102
+ }
103
+ ```
104
+
105
+ A provider class needs a static `identifier` and `getCommissionLines`. It can add `getCommissionLinesBatch(contexts)` to load its data once per batch. The module doesn’t cap `amount`, so keep it within the item’s `total` yourself.
106
+
107
+ Export the class as a module provider so the commission module can register it.
108
+
109
+ ```ts title="src/modules/tiered-commission/index.ts"
110
+ import { ModuleProvider } from "@medusajs/framework/utils"
111
+ import { MercurModules } from "@mercurjs/types"
112
+ import TieredCommissionProvider from "./service"
113
+
114
+ export default ModuleProvider(MercurModules.COMMISSION, {
115
+ services: [TieredCommissionProvider],
116
+ })
117
+ ```
118
+
119
+ The module takes these options, typed as `CommissionModuleOptions`:
120
+
121
+ | Option | Description |
122
+ | --- | --- |
123
+ | `providers` | Array of `{ resolve, id, options?, is_default? }` registered next to `system` |
124
+ | `default_provider` | Provider id used for every calculation. Overrides `is_default` |
125
+
126
+ A single configured provider becomes the default without `is_default`.
@@ -1,40 +1,114 @@
1
1
  ---
2
- title: "Workflows"
2
+ title: "Commission workflows"
3
3
  sidebarTitle: "Workflows"
4
- description: "Commission rate, rule, and order-line workflows."
4
+ description: "Inputs, outputs, steps, and hooks of the rate, rule, and order-line commission workflows."
5
5
  ---
6
6
 
7
- This reference lists the workflows for the Commission domain. Import them from
8
- `@mercurjs/core/workflows` and run them against the Medusa container.
7
+ The Commission module ships five workflows, exported from `@mercurjs/core/workflows`. They run against the Medusa container, and each step compensates on failure unless noted. None of them emits an event.
9
8
 
10
- ## Rate workflows
9
+ ## createCommissionRatesWorkflow
11
10
 
12
- | Workflow | Input | Purpose |
11
+ Creates one or more commission rates. Workflow id `create-commission-rates`.
12
+
13
+ | Input | Type |
14
+ | --- | --- |
15
+ | (root) | `CreateCommissionRateDTO[]` |
16
+
17
+ `CreateCommissionRateDTO` takes `name`, `type`, and `value`, and optionally `code`, `currency_code`, `include_tax`, `include_shipping`, `is_enabled`, and `is_default`. The module also accepts nested `rules` and `values` arrays, which the DTO doesn’t declare. A missing `code` is generated from `name`.
18
+
19
+ - **Output**: the created rates, in input order
20
+ - **Steps**: `createCommissionRatesStep`, compensated by deleting the created rates
21
+ - **Hooks**: none
22
+
23
+ ## updateCommissionRatesWorkflow
24
+
25
+ Updates fields on one or more rates. Workflow id `update-commission-rates`.
26
+
27
+ | Input | Type |
28
+ | --- | --- |
29
+ | (root) | `UpdateCommissionRateDTO[]` |
30
+
31
+ Each item needs an `id` and takes any `CreateCommissionRateDTO` field as optional.
32
+
33
+ - **Output**: the updated rates
34
+ - **Steps**: `updateCommissionRatesStep`
35
+ - **Hooks**: none
36
+
37
+ <Warning>
38
+ The compensation of `updateCommissionRatesStep` re-applies the step’s input, not the previous values. If a later step in a parent workflow fails, the rate keeps the new values.
39
+ </Warning>
40
+
41
+ ## deleteCommissionRatesWorkflow
42
+
43
+ Soft-deletes rates after checking that none of them is the global rate. Workflow id `delete-commission-rates`.
44
+
45
+ | Input | Type | Description |
46
+ | --- | --- | --- |
47
+ | `ids` | `string[]` | Ids of the rates to delete |
48
+
49
+ - **Output**: none
50
+ - **Steps**: `validateCommissionRatesDeletableStep`, which throws `NOT_ALLOWED` for an `is_default` rate, then `deleteCommissionRatesStep`, compensated by restoring the rates
51
+ - **Hooks**: `commissionRatesDeleted`, with `{ ids }`
52
+
53
+ ## batchCommissionRulesWorkflow
54
+
55
+ Creates, updates, and deletes the rules of one rate. Workflow id `batch-commission-rules`.
56
+
57
+ | Input | Type | Description |
13
58
  | --- | --- | --- |
14
- | `createCommissionRatesWorkflow` | `CreateCommissionRateDTO[]` | Create rates (auto-generates `code`) |
15
- | `updateCommissionRatesWorkflow` | `UpdateCommissionRateDTO[]` | Update rate fields |
16
- | `deleteCommissionRatesWorkflow` | `{ ids[] }` | Delete rates (validates deletability first) |
59
+ | `commission_rate_id` | `string` | The rate that new rules attach to |
60
+ | `create` | `CreateCommissionRuleDTO[]`, optional | `{ reference, reference_id }` |
61
+ | `update` | `UpdateCommissionRuleDTO[]`, optional | `{ id, reference?, reference_id? }` |
62
+ | `delete` | `string[]`, optional | Ids of rules to delete |
63
+
64
+ - **Output**: `{ created, updated, deleted }`, where `deleted` holds the ids
65
+ - **Steps**: `createCommissionRulesStep`, `updateCommissionRulesStep`, and `deleteCommissionRulesStep`, run in parallel
66
+ - **Hooks**: none
67
+
68
+ Only `create` uses `commission_rate_id`. The ids in `update` and `delete` aren’t checked against it.
69
+
70
+ ## refreshOrderCommissionLinesWorkflow
17
71
 
18
- ## Rule workflows
72
+ Recomputes and replaces the commission lines of one or more orders. Workflow id `refresh-order-commission-lines`.
19
73
 
20
- | Workflow | Input | Purpose |
74
+ | Input | Type | Description |
21
75
  | --- | --- | --- |
22
- | `batchCommissionRulesWorkflow` | `{ commission_rate_id, create?, update?, delete? }` | Create, update, and delete a rate's rules in one call |
76
+ | `order_ids` | `string[]` | Orders to refresh. An unknown id throws |
23
77
 
24
- ## Order-line workflows
78
+ - **Output**: `CommissionLineDTO[]`, the lines written for all the orders
79
+ - **Steps**: `fetch-orders` (`useQueryGraphStep`), `getCommissionLinesStep`, `upsertCommissionLinesStep`
80
+ - **Called by**: `completeCartWithSplitOrdersWorkflow` and the `order-commission-refresh-handler` subscriber
25
81
 
26
- | Workflow | Input | Purpose |
82
+ The workflow exposes two hooks:
83
+
84
+ | Hook | Input | Return |
27
85
  | --- | --- | --- |
28
- | `refreshOrderCommissionLinesWorkflow` | `{ order_ids[] }` | Recompute and upsert an order's commission lines (idempotent) |
29
-
30
- <Note>
31
- `deleteCommissionRatesWorkflow` exposes a `commissionRatesDeleted` hook, and
32
- `batchCommissionRulesWorkflow` runs its create / update / delete steps in
33
- parallel. `refreshOrderCommissionLinesWorkflow` also runs as a step inside the
34
- cart-split checkout workflow.
35
- </Note>
36
-
37
- To work with records directly instead of through a workflow, see the
38
- [Service reference](/platform/commission/reference/service). To run side effects
39
- when an order changes, see the
40
- [Event reference](/platform/commission/reference/events).
86
+ | `setCommissionContext` | `{ contexts: CommissionCalculationContext[] }` | `StepResponse` of new contexts, or nothing |
87
+ | `commissionLinesUpserted` | `{ order_ids, commission_lines }` | Ignored |
88
+
89
+ ```ts
90
+ refreshOrderCommissionLinesWorkflow.hooks.setCommissionContext(
91
+ ({ contexts }) =>
92
+ new StepResponse(
93
+ contexts.map((c) => ({ ...c, additional_context: { tier: "gold" } }))
94
+ )
95
+ )
96
+ ```
97
+
98
+ The handler above adds data to every context before the provider sees it. Neither `getCommissionLinesStep` nor `upsertCommissionLinesStep` defines a compensation.
99
+
100
+ ## Exported steps
101
+
102
+ `@mercurjs/core/workflows` also exports each step, with its id, for use in your own workflows:
103
+
104
+ | Step | Id |
105
+ | --- | --- |
106
+ | `createCommissionRatesStep` | `create-commission-rates-step` |
107
+ | `updateCommissionRatesStep` | `update-commission-rates-step` |
108
+ | `deleteCommissionRatesStep` | `delete-commission-rates-step` |
109
+ | `validateCommissionRatesDeletableStep` | `validate-commission-rates-deletable-step` |
110
+ | `createCommissionRulesStep` | `create-commission-rules-step` |
111
+ | `updateCommissionRulesStep` | `update-commission-rules-step` |
112
+ | `deleteCommissionRulesStep` | `delete-commission-rules-step` |
113
+ | `getCommissionLinesStep` | `get-commission-lines` |
114
+ | `upsertCommissionLinesStep` | `upsert-commission-lines` |