@mercurjs/docs 2.3.8-canary.3 → 2.3.9-canary.1

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 (120) hide show
  1. package/content/learn/architecture.mdx +166 -263
  2. package/content/learn/introduction.mdx +9 -1
  3. package/content/learn/use-cases.mdx +70 -0
  4. package/content/platform/attribute/concepts/attribute-types.mdx +73 -46
  5. package/content/platform/attribute/concepts/global-vs-inline.mdx +54 -32
  6. package/content/platform/attribute/concepts/variant-axes.mdx +54 -32
  7. package/content/platform/attribute/guides/attach-attributes-to-a-product.mdx +96 -53
  8. package/content/platform/attribute/guides/create-a-variant-axis.mdx +106 -57
  9. package/content/platform/attribute/guides/create-an-attribute.mdx +105 -56
  10. package/content/platform/attribute/overview.mdx +37 -33
  11. package/content/platform/attribute/reference/data-models.mdx +53 -38
  12. package/content/platform/attribute/reference/events.mdx +47 -24
  13. package/content/platform/attribute/reference/links.mdx +98 -27
  14. package/content/platform/attribute/reference/service.mdx +71 -32
  15. package/content/platform/attribute/reference/workflows.mdx +158 -28
  16. package/content/platform/catalog/concepts/master-products.mdx +39 -37
  17. package/content/platform/catalog/concepts/product-seller-allowlist.mdx +56 -35
  18. package/content/platform/catalog/concepts/status-lifecycle.mdx +55 -49
  19. package/content/platform/catalog/concepts/variants-categories-collections.mdx +55 -35
  20. package/content/platform/catalog/guides/allowlist-stores.mdx +100 -37
  21. package/content/platform/catalog/guides/create-a-master-product.mdx +124 -48
  22. package/content/platform/catalog/guides/publish-or-reject-a-product.mdx +120 -55
  23. package/content/platform/catalog/overview.mdx +39 -35
  24. package/content/platform/catalog/reference/data-models.mdx +154 -43
  25. package/content/platform/catalog/reference/events.mdx +41 -25
  26. package/content/platform/catalog/reference/links.mdx +196 -28
  27. package/content/platform/catalog/reference/service.mdx +57 -35
  28. package/content/platform/catalog/reference/workflows.mdx +124 -30
  29. package/content/platform/commission/concepts/order-commission-lines.mdx +54 -52
  30. package/content/platform/commission/concepts/rule-matching.mdx +53 -63
  31. package/content/platform/commission/concepts/rules-and-rates.mdx +61 -59
  32. package/content/platform/commission/guides/batch-update-rules.mdx +69 -41
  33. package/content/platform/commission/guides/create-a-rate.mdx +101 -53
  34. package/content/platform/commission/guides/refresh-order-commission-lines.mdx +104 -35
  35. package/content/platform/commission/overview.mdx +43 -35
  36. package/content/platform/commission/reference/data-models.mdx +59 -45
  37. package/content/platform/commission/reference/events.mdx +28 -34
  38. package/content/platform/commission/reference/links.mdx +42 -33
  39. package/content/platform/commission/reference/service.mdx +103 -28
  40. package/content/platform/commission/reference/workflows.mdx +101 -27
  41. package/content/platform/offer/concepts/pricing-and-inventory.mdx +63 -49
  42. package/content/platform/offer/concepts/shipping.mdx +28 -29
  43. package/content/platform/offer/concepts/what-is-an-offer.mdx +48 -45
  44. package/content/platform/offer/guides/bulk-create-offers.mdx +97 -61
  45. package/content/platform/offer/guides/create-an-offer.mdx +112 -60
  46. package/content/platform/offer/guides/manage-offer-inventory.mdx +78 -38
  47. package/content/platform/offer/overview.mdx +39 -32
  48. package/content/platform/offer/reference/data-models.mdx +77 -47
  49. package/content/platform/offer/reference/events.mdx +44 -18
  50. package/content/platform/offer/reference/links.mdx +92 -40
  51. package/content/platform/offer/reference/service.mdx +66 -31
  52. package/content/platform/offer/reference/workflows.mdx +146 -37
  53. package/content/platform/order-group/concepts/computed-totals.mdx +40 -37
  54. package/content/platform/order-group/concepts/order-splitting.mdx +41 -39
  55. package/content/platform/order-group/concepts/the-order-group.mdx +39 -32
  56. package/content/platform/order-group/guides/list-order-groups.mdx +96 -56
  57. package/content/platform/order-group/guides/retrieve-an-order-group.mdx +93 -42
  58. package/content/platform/order-group/guides/split-a-cart.mdx +115 -40
  59. package/content/platform/order-group/overview.mdx +42 -32
  60. package/content/platform/order-group/reference/data-models.mdx +48 -31
  61. package/content/platform/order-group/reference/events.mdx +29 -17
  62. package/content/platform/order-group/reference/links.mdx +90 -29
  63. package/content/platform/order-group/reference/service.mdx +55 -31
  64. package/content/platform/order-group/reference/workflows.mdx +83 -24
  65. package/content/platform/payout/concepts/account-lifecycle.mdx +64 -67
  66. package/content/platform/payout/concepts/accounts-and-onboarding.mdx +50 -40
  67. package/content/platform/payout/concepts/payout-pipeline.mdx +70 -73
  68. package/content/platform/payout/guides/create-a-payout-account.mdx +65 -41
  69. package/content/platform/payout/guides/process-a-provider-webhook.mdx +84 -38
  70. package/content/platform/payout/guides/start-provider-onboarding.mdx +90 -46
  71. package/content/platform/payout/overview.mdx +43 -34
  72. package/content/platform/payout/reference/data-models.mdx +63 -36
  73. package/content/platform/payout/reference/events.mdx +56 -30
  74. package/content/platform/payout/reference/links.mdx +52 -22
  75. package/content/platform/payout/reference/service.mdx +72 -33
  76. package/content/platform/payout/reference/workflows.mdx +80 -19
  77. package/content/platform/product-edit/concepts/change-actions.mdx +52 -45
  78. package/content/platform/product-edit/concepts/change-pipeline.mdx +60 -52
  79. package/content/platform/product-edit/concepts/status-and-auto-confirm.mdx +43 -46
  80. package/content/platform/product-edit/guides/confirm-or-decline-a-change.mdx +104 -56
  81. package/content/platform/product-edit/guides/edit-a-product.mdx +126 -46
  82. package/content/platform/product-edit/guides/request-a-revision.mdx +99 -39
  83. package/content/platform/product-edit/overview.mdx +41 -34
  84. package/content/platform/product-edit/reference/data-models.mdx +73 -47
  85. package/content/platform/product-edit/reference/events.mdx +39 -29
  86. package/content/platform/product-edit/reference/links.mdx +32 -24
  87. package/content/platform/product-edit/reference/service.mdx +45 -26
  88. package/content/platform/product-edit/reference/workflows.mdx +173 -31
  89. package/content/platform/review/concepts/product-vs-seller-reviews.mdx +42 -41
  90. package/content/platform/review/concepts/ratings-and-moderation.mdx +45 -44
  91. package/content/platform/review/concepts/the-review-model.mdx +52 -45
  92. package/content/platform/review/guides/compute-aggregate-ratings.mdx +62 -37
  93. package/content/platform/review/guides/create-a-review.mdx +109 -39
  94. package/content/platform/review/guides/moderate-a-review.mdx +83 -37
  95. package/content/platform/review/guides/respond-to-a-review.mdx +85 -40
  96. package/content/platform/review/overview.mdx +43 -33
  97. package/content/platform/review/reference/data-models.mdx +41 -27
  98. package/content/platform/review/reference/events.mdx +55 -37
  99. package/content/platform/review/reference/links.mdx +80 -22
  100. package/content/platform/review/reference/service.mdx +61 -33
  101. package/content/platform/review/reference/workflows.mdx +80 -24
  102. package/content/platform/store/concepts/lifecycle.mdx +68 -44
  103. package/content/platform/store/concepts/store-entity.mdx +45 -27
  104. package/content/platform/store/concepts/team.mdx +56 -35
  105. package/content/platform/store/guides/create-a-store.mdx +102 -35
  106. package/content/platform/store/guides/manage-the-team.mdx +122 -32
  107. package/content/platform/store/guides/moderate-a-store.mdx +107 -38
  108. package/content/platform/store/overview.mdx +41 -34
  109. package/content/platform/store/reference/data-models.mdx +132 -57
  110. package/content/platform/store/reference/events.mdx +42 -17
  111. package/content/platform/store/reference/links.mdx +67 -49
  112. package/content/platform/store/reference/service.mdx +105 -33
  113. package/content/platform/store/reference/workflows.mdx +304 -24
  114. package/content/references/api/conventions.mdx +20 -0
  115. package/content/resources/integrations/magento2.mdx +162 -0
  116. package/content/resources/integrations/overview.mdx +10 -0
  117. package/content/resources/integrations/stripe-connect.mdx +1 -1
  118. package/content/resources/tutorials/custom-api-route.mdx +3 -2
  119. package/llms.txt +113 -111
  120. package/package.json +1 -1
@@ -1,58 +1,133 @@
1
1
  ---
2
- title: "Split a cart into orders"
2
+ title: "Split a cart into an order group"
3
3
  sidebarTitle: "Split a cart"
4
- description: "Complete a multi-seller cart into a group of per-seller orders with completeCartWithSplitOrdersWorkflow."
4
+ description: "Run completeCartWithSplitOrdersWorkflow from your own code and change the split with its validate and setOrderStatus hooks."
5
5
  ---
6
6
 
7
- In this guide, you'll learn how the checkout split works and how to run it from
8
- your own server code, such as a custom complete-cart route.
7
+ Run the checkout split yourself when you build a custom completion flow, or hook into it when you need to block a checkout or set the initial status of each seller’s order.
9
8
 
10
- Mercur replaces Medusa's single-order checkout with
11
- `completeCartWithSplitOrdersWorkflow`. It takes a cart that may hold offers from
12
- several sellers, creates one order per seller, and wraps them in an `OrderGroup`.
9
+ ## Before you begin
13
10
 
14
- ## Run the workflow
11
+ You need the following:
15
12
 
16
- ```ts title="src/api/store/carts/[id]/complete/route.ts"
17
- import type { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
18
- import { completeCartWithSplitOrdersWorkflow } from "@mercurjs/core/workflows"
13
+ - **A cart ready to complete**: items bought through offers, a shipping method for each seller that ships, and a payment session
14
+ - **Mercur’s cart completion in place**: Mercur’s cart completion route already runs this workflow, so you only need your own route for a custom flow
19
15
 
20
- export async function POST(req: MedusaRequest, res: MedusaResponse) {
21
- const { result } = await completeCartWithSplitOrdersWorkflow(req.scope).run({
22
- input: { cart_id: req.params.id },
23
- })
16
+ ## Complete a cart from a custom route
17
+
18
+ <Steps>
19
+ <Step title="Run the workflow">
20
+ Call `completeCartWithSplitOrdersWorkflow` with the cart id. Set `throwOnError: false` so you can handle payment errors yourself.
21
+
22
+ ```ts title="src/api/store/carts/[id]/place/route.ts"
23
+ import type {
24
+ MedusaRequest,
25
+ MedusaResponse,
26
+ } from "@medusajs/framework/http"
27
+ import {
28
+ completeCartWithSplitOrdersWorkflow,
29
+ } from "@mercurjs/core/workflows"
30
+
31
+ export async function POST(req: MedusaRequest, res: MedusaResponse) {
32
+ const { result, errors } = await completeCartWithSplitOrdersWorkflow(
33
+ req.scope
34
+ ).run({
35
+ input: { cart_id: req.params.id },
36
+ throwOnError: false,
37
+ })
38
+
39
+ if (errors?.[0]) {
40
+ throw errors[0].error
41
+ }
42
+
43
+ res.json({ order_group_id: result.order_group_id })
44
+ }
45
+ ```
46
+
47
+ The workflow returns `{ order_group_id }`. It runs once per cart: a second call for the same cart returns the existing group’s id.
48
+ </Step>
49
+ <Step title="Return the group to the shopper">
50
+ Load the group with `query.graph` and send it back instead of the bare id:
51
+
52
+ ```ts
53
+ const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
54
+
55
+ const { data: [order_group] } = await query.graph({
56
+ entity: "order_group",
57
+ fields: ["id", "display_id", "total", "orders.id", "orders.total"],
58
+ filters: { id: result.order_group_id },
59
+ })
60
+ ```
61
+
62
+ `ContainerRegistrationKeys` comes from `@medusajs/framework/utils`.
63
+ </Step>
64
+ </Steps>
65
+
66
+ ## Handle a failed payment authorization
67
+
68
+ The workflow authorizes the payment session after it creates the orders. If authorization fails, the workflow rolls back: it deletes the group, and Medusa’s steps undo the orders, links, and reservations. Mercur’s own route answers `PAYMENT_AUTHORIZATION_ERROR` and `PAYMENT_REQUIRES_MORE_ERROR` with a `200` that carries the cart and the error, so the storefront can retry payment. Do the same in a custom route:
69
+
70
+ ```ts
71
+ import { MedusaError } from "@medusajs/framework/utils"
24
72
 
25
- res.json({ order_group_id: result.order_group_id })
73
+ const retryable: string[] = [
74
+ MedusaError.Types.PAYMENT_AUTHORIZATION_ERROR,
75
+ MedusaError.Types.PAYMENT_REQUIRES_MORE_ERROR,
76
+ ]
77
+
78
+ if (errors?.[0] && retryable.includes(errors[0].error?.type)) {
79
+ res.json({ type: "cart", error: errors[0].error.message })
80
+ return
26
81
  }
27
82
  ```
28
83
 
29
- The workflow is idempotent per cart: if a group already exists for the cart it
30
- returns the existing `order_group_id` instead of splitting again. It acquires a
31
- lock on the cart id for the duration of the split so concurrent completions can't
32
- create duplicate orders.
84
+ Throw every other error so Medusa’s error handler responds with the matching status.
85
+
86
+ ## Block a checkout with the validate hook
87
+
88
+ The `validate` hook runs before the split and receives the workflow `input` and the `cart`. Throw to stop the checkout:
89
+
90
+ ```ts title="src/workflows/hooks/validate-split-cart.ts"
91
+ import { MedusaError } from "@medusajs/framework/utils"
92
+ import { completeCartWithSplitOrdersWorkflow } from "@mercurjs/core/workflows"
93
+
94
+ completeCartWithSplitOrdersWorkflow.hooks.validate(async ({ cart }) => {
95
+ if (!cart.email) {
96
+ throw new MedusaError(
97
+ MedusaError.Types.INVALID_DATA,
98
+ "Add an email address before you complete the cart"
99
+ )
100
+ }
101
+ })
102
+ ```
103
+
104
+ The hook runs on every cart completion, including completions started by a payment webhook through `processPaymentWorkflow`.
105
+
106
+ ## Set the initial order status with setOrderStatus
33
107
 
34
- <Note>
35
- Line items are grouped by `item.offer.seller_id`. Sellers sell against the
36
- shared master catalog through **offers**, so a line item's seller comes from
37
- its offer, never from product ownership.
38
- </Note>
108
+ Child orders start as `pending`. Return a status from the `setOrderStatus` hook to change that, for example when sellers must accept an order before they fulfill it:
109
+
110
+ ```ts title="src/workflows/hooks/set-split-order-status.ts"
111
+ import { OrderStatus } from "@medusajs/framework/utils"
112
+ import { StepResponse } from "@medusajs/framework/workflows-sdk"
113
+ import { completeCartWithSplitOrdersWorkflow } from "@mercurjs/core/workflows"
114
+
115
+ completeCartWithSplitOrdersWorkflow.hooks.setOrderStatus(async () => {
116
+ return new StepResponse({
117
+ status: OrderStatus.REQUIRES_ACTION,
118
+ status_by_seller_id: { sel_01JD8Q1234567: OrderStatus.PENDING },
119
+ })
120
+ })
121
+ ```
39
122
 
40
- ## What happens during the split
123
+ `status` applies to every child order. `status_by_seller_id` overrides it for the sellers you list. Return nothing to keep `pending`.
41
124
 
42
- For the cart, the workflow validates payments and per-seller shipping, then in a
43
- single transaction:
125
+ ## React to the new group
44
126
 
45
- - creates the parent `OrderGroup` (`customer_id`, `cart_id`)
46
- - creates one child `Order` per seller from that seller's items and shipping
47
- - links each order to the group, its seller, and the originating cart
48
- - mirrors line-item → offer links, reserves offer inventory, and splits payment captures proportionally
49
- - refreshes commission lines per order and marks the cart `completed_at`
127
+ The split emits `order_group.created` with the group id, and `order.placed` once for each child order. Subscribe to the first for purchase-level work, such as a single confirmation email, and to the second for per-seller work. The [event reference](/platform/order-group/reference/events) has a subscriber example.
50
128
 
51
- Finally it emits `order.placed` for the created orders and `order_group.created`
52
- for the group.
129
+ ## Next steps
53
130
 
54
- <Tip>
55
- The workflow exposes hooks `validate`, `beforePaymentAuthorization`, and
56
- `orderGroupCreated`, so you can inject marketplace-specific logic around the
57
- split without forking it.
58
- </Tip>
131
+ - [How the split assigns items, shipping, and promotions](/platform/order-group/concepts/order-splitting)
132
+ - [`completeCartWithSplitOrdersWorkflow` reference](/platform/order-group/reference/workflows#completecartwithsplitordersworkflow)
133
+ - [Retrieve the new group](/platform/order-group/guides/retrieve-an-order-group)
@@ -1,83 +1,93 @@
1
1
  ---
2
- title: "Order Group"
2
+ title: "Order groups"
3
3
  sidebarTitle: "Overview"
4
- description: "Wrap a multi-seller cart into one shopper-facing order made of independent per-seller orders."
4
+ description: "Turn a cart with items from several sellers into per-seller orders under one group the shopper can track."
5
5
  ---
6
6
 
7
- Use Order Groups to turn a single customer cart that spans multiple sellers into
8
- one coherent order for the shopper.
7
+ Use order groups to give the shopper one purchase while each seller gets an order of their own.
9
8
 
10
- A marketplace cart can contain offers from several sellers at once. On checkout,
11
- Mercur splits that cart into one child order per seller and wraps them in an
12
- **Order Group**. This is the aggregate the shopper sees as "their order". Each
13
- child order is then fulfilled, returned, and refunded independently, while the
14
- group gives you a single handle over the whole purchase.
9
+ A marketplace cart can hold offers from several sellers. At checkout, Mercur creates one child order per seller and wraps them in an order group. The group is the record the shopper sees as “my order”, while each seller fulfills, returns, and refunds their own child order. The group stores almost nothing itself: its seller count and total are summed from the child orders every time you read it.
10
+
11
+ <img className="block dark:hidden" src="/images/figures/order-group-overview-light.svg" alt="The order_group record og_01JD8Q1234567 in front, with display_id 98, its customer and read-only cart link, and computed seller_count 2 and total 87.00. Behind it, the order_group_order link lists the two child orders it sums: 47.00 for ACME and 40.00 for GLOBEX." />
12
+ <img className="hidden dark:block" src="/images/figures/order-group-overview-dark.svg" alt="The order_group record og_01JD8Q1234567 in front, with display_id 98, its customer and read-only cart link, and computed seller_count 2 and total 87.00. Behind it, the order_group_order link lists the two child orders it sums: 47.00 for ACME and 40.00 for GLOBEX." />
15
13
 
16
14
  <Note>
17
- An order group is the `OrderGroup` entity. It lives in the **Seller module**
18
- (id prefix `og`), not a module of its own. There is no `ORDER_GROUP` module
19
- key. Resolve its service through `MercurModules.SELLER`.
15
+ An order group is the `OrderGroup` data model (id prefix `og`). It belongs to the Seller module, not a module of its own, so there is no `ORDER_GROUP` key. Resolve its service with `MercurModules.SELLER`.
20
16
  </Note>
21
17
 
22
18
  ## Key features
23
19
 
24
- - **Multi-seller checkout:** one cart with offers from many sellers becomes one group of per-seller orders.
25
- - **Human-readable id:** an auto-incrementing `display_id` the shopper and operator can reference.
26
- - **Immutable cart link:** a read-only `cart_id` back to the originating cart. Carts are frozen after checkout.
27
- - **Computed totals:** `seller_count` and `total` are derived at query time, never stored.
28
- - **Independent child orders:** fulfillment, returns, and refunds happen per seller order.
29
- - **Scoped visibility:** admins see every group platform-wide. Vendors see only their slice.
20
+ Order groups cover a multi-seller purchase from checkout to the order history:
21
+
22
+ - **Split checkout**: `completeCartWithSplitOrdersWorkflow` turns one cart into one order per seller under a single group
23
+ - **One group per cart**: completing the same cart twice returns the existing group instead of splitting again
24
+ - **Readable reference**: an auto-incrementing `display_id` that shoppers and operators can quote
25
+ - **Frozen cart link**: a read-only `cart_id` that points at the completed cart
26
+ - **Live totals**: `seller_count` and `total` are computed from the child orders at query time, never stored
27
+ - **Derived child statuses**: the read workflows add `payment_status` and `fulfillment_status` to every child order
28
+ - **Seller scoping**: the list workflow can trim each group down to one seller’s orders
29
+
30
+ ## How it works
31
+
32
+ A group comes to life when a cart completes:
33
+
34
+ 1. The shopper completes a cart that holds offers from ACME and GLOBEX.
35
+ 2. `completeCartWithSplitOrdersWorkflow` groups the line items by `item.offer.seller_id`.
36
+ 3. It creates one `OrderGroup` and one child `Order` per seller, then links them.
37
+ 4. It authorizes the cart’s payment and refreshes commission lines for each order.
38
+ 5. It emits `order.placed` for each child order and `order_group.created` for the group.
39
+ 6. When you read the group, the Seller module sums its child orders into `seller_count` and `total`.
30
40
 
31
41
  ## Get started
32
42
 
33
- Learn how the domain fits together.
43
+ Learn how the group, the split, and the computed totals fit together.
34
44
 
35
45
  <CardGroup cols={2}>
36
46
  <Card title="The order group" icon="layer-group" href="/platform/order-group/concepts/the-order-group">
37
- The aggregate entity, its `display_id`, and the read-only cart link.
47
+ The record over a multi-seller purchase, its `display_id`, and the cart link.
38
48
  </Card>
39
49
  <Card title="Order splitting" icon="scissors" href="/platform/order-group/concepts/order-splitting">
40
- How a multi-seller cart is split into per-seller child orders.
50
+ How checkout turns one cart into one order per seller.
41
51
  </Card>
42
52
  <Card title="Computed totals" icon="calculator" href="/platform/order-group/concepts/computed-totals">
43
- Why `seller_count` and `total` are calculated at query time.
53
+ Where `seller_count`, `total`, and child order statuses come from.
44
54
  </Card>
45
55
  </CardGroup>
46
56
 
47
57
  ## Examples
48
58
 
49
- Build against Order Groups in your own code.
59
+ Build against order groups in your own server code.
50
60
 
51
61
  <CardGroup cols={2}>
52
62
  <Card title="Retrieve an order group" icon="magnifying-glass" href="/platform/order-group/guides/retrieve-an-order-group">
53
- Load a group and its aggregated child orders.
63
+ Load one group with its child orders and their statuses.
54
64
  </Card>
55
65
  <Card title="List order groups" icon="list" href="/platform/order-group/guides/list-order-groups">
56
- Page through groups, optionally scoped to a seller.
66
+ Filter, page, and scope groups to a seller.
57
67
  </Card>
58
68
  <Card title="Split a cart" icon="scissors" href="/platform/order-group/guides/split-a-cart">
59
- Complete a multi-seller cart into a group of orders.
69
+ Complete a cart into a group and hook into the split.
60
70
  </Card>
61
71
  </CardGroup>
62
72
 
63
73
  ## Resources
64
74
 
65
- Data models, links, workflows, service methods, and events for Order Groups.
75
+ The data model, links, workflows, service methods, and events behind order groups.
66
76
 
67
77
  <CardGroup cols={2}>
68
78
  <Card title="Data models" icon="table" href="/platform/order-group/reference/data-models">
69
- The `OrderGroup` entity and its fields.
79
+ The `OrderGroup` model, its fields, and indexes.
70
80
  </Card>
71
81
  <Card title="Links" icon="link" href="/platform/order-group/reference/links">
72
- How order groups link to carts, orders, sellers, and offers.
82
+ How a group connects to its cart, orders, sellers, and offers.
73
83
  </Card>
74
84
  <Card title="Workflows" icon="diagram-project" href="/platform/order-group/reference/workflows">
75
- Splitting, retrieving, and listing order groups.
85
+ The checkout split, the read workflows, and their hooks.
76
86
  </Card>
77
87
  <Card title="Service" icon="gear" href="/platform/order-group/reference/service">
78
- Seller module methods for working with groups directly.
88
+ Seller module methods for order group records.
79
89
  </Card>
80
90
  <Card title="Events" icon="bell" href="/platform/order-group/reference/events">
81
- Events emitted as order groups are created.
91
+ The events emitted when a cart splits into a group.
82
92
  </Card>
83
93
  </CardGroup>
@@ -1,40 +1,57 @@
1
1
  ---
2
- title: "Data models"
2
+ title: "Order group data models"
3
3
  sidebarTitle: "Data models"
4
- description: "The data model owned by the Order Group domain."
4
+ description: "Fields, indexes, and relations of the OrderGroup data model in the Seller module."
5
5
  ---
6
6
 
7
- The Order Group domain is owned by the **Seller module**. There is no separate
8
- order-group module. This reference lists its data model and fields. For the full
9
- module overview, see the [Order Group overview](/platform/order-group/overview).
7
+ Order groups have one data model, `OrderGroup`, registered on the Seller module. There is no separate order group module: resolve it with `MercurModules.SELLER`. The model is defined in `packages/core/src/modules/seller/models/order-group.ts`, and its record type is `OrderGroupDTO` from `@mercurjs/types`.
10
8
 
11
9
  ## OrderGroup
12
10
 
13
- Table `order_group`, id prefix `og`. The aggregate over the per-seller orders
14
- created from a single cart.
11
+ The parent record over the child orders created from one completed cart. Table `order_group`, id prefix `og`.
15
12
 
16
- | Field | Type | Notes |
13
+ | Field | Type | Description |
17
14
  | --- | --- | --- |
18
- | `id` | text | Primary key (prefix `og`) |
19
- | `display_id` | integer | Auto-incrementing, human-readable reference |
20
- | `customer_id` | text | Nullable; who placed the group |
21
- | `cart_id` | text | The originating cart (read-only link to Cart) |
22
- | `seller_count` | number | **Computed**: distinct sellers with a child order |
23
- | `total` | bigNumber | **Computed**: sum of child order totals |
24
- | `created_at` / `updated_at` | dateTime | Timestamps |
25
- | `deleted_at` | dateTime | Nullable; soft-delete marker |
26
-
27
- Relations: `orders` (one-to-many through the `order_group_order` link table),
28
- `cart` (read-only, via `cart_id`).
29
-
30
- <Note>
31
- `seller_count` and `total` are marked `computed()`. They hold no value on the
32
- row and are aggregated from the group's child orders each time it's read. See
33
- [Computed totals](/platform/order-group/concepts/computed-totals).
34
- </Note>
35
-
36
- <Warning>
37
- The `cart_id` link is **read-only**. The cart is frozen (`completed_at` is set)
38
- the moment the split runs, so it's a historical reference and can't be written
39
- through the group.
40
- </Warning>
15
+ | `id` | `text` | Primary key with the prefix `og` |
16
+ | `display_id` | `autoincrement` | Integer assigned by the database in creation order, for people to quote |
17
+ | `customer_id` | `text`, nullable | Id of the customer on the completed cart, or `null` when the cart had none |
18
+ | `cart_id` | `text` | Id of the completed cart; backs the read-only link to the Cart module |
19
+ | `seller_count` | `number`, computed | Number of distinct sellers across the group’s child orders; not stored |
20
+ | `total` | `bigNumber`, computed | Sum of the child orders’ `current_order_total`; not stored, returned as a `number` |
21
+ | `created_at` | `dateTime` | Set when the record is created |
22
+ | `updated_at` | `dateTime` | Set when the record changes |
23
+ | `deleted_at` | `dateTime`, nullable | Soft-delete marker |
24
+
25
+ The computed fields are filled by the Seller module’s `OrderGroupRepository` on every read. See [Computed totals](/platform/order-group/concepts/computed-totals).
26
+
27
+ ### Indexes
28
+
29
+ The model declares three partial indexes, each limited to rows where `deleted_at IS NULL`:
30
+
31
+ | Index | Columns | Serves |
32
+ | --- | --- | --- |
33
+ | `IDX_order_group_cart_id` | `cart_id` | The one-group-per-cart lookup at checkout |
34
+ | `IDX_order_group_customer_id_created_at` | `customer_id`, `created_at` | A customer’s order history, newest first |
35
+ | `IDX_order_group_created_at` | `created_at` | The default newest-first list |
36
+
37
+ ### Relations
38
+
39
+ `OrderGroup` has no relations inside the Seller module. It reaches other modules through module links:
40
+
41
+ | Alias | Target | Cardinality | Link |
42
+ | --- | --- | --- | --- |
43
+ | `orders` | `Order` (Order module) | One group to many orders | `order_group_order` |
44
+ | `cart` | `Cart` (Cart module) | One group to one cart, read-only | `cart_id` field |
45
+
46
+ See [Links](/platform/order-group/reference/links) for the definitions and `query.graph` examples.
47
+
48
+ ## Mutation types
49
+
50
+ `@mercurjs/types` exports the input shapes for the generated create and update methods:
51
+
52
+ | Type | Fields |
53
+ | --- | --- |
54
+ | `CreateOrderGroupDTO` | `cart_id: string`, `customer_id?: string \| null` |
55
+ | `UpdateOrderGroupDTO` | `id: string`, `customer_id?: string`, `cart_id?: string` |
56
+
57
+ Checkout creates every group through `createOrderGroupStep`. Mercur never updates a group after that.
@@ -1,22 +1,40 @@
1
1
  ---
2
- title: "Event reference"
2
+ title: "Order group events"
3
3
  sidebarTitle: "Events"
4
- description: "Events emitted by the Order Group domain, for subscribers and side effects."
4
+ description: "The events emitted when checkout splits a cart into an order group, with their payloads and a subscriber example."
5
5
  ---
6
6
 
7
- The Order Group domain emits an event when a group is created during checkout.
8
- Subscribe to it to run side effects such as sending an order confirmation,
9
- syncing external systems, or kicking off follow-up workflows, instead of polling.
7
+ Order groups emit one event of their own, `order_group.created`, when checkout splits a cart. The same run emits Medusa’s `order.placed` for every child order. Subscribe to these events to send confirmations, sync external systems, or start follow-up workflows.
8
+
9
+ ## Events
10
+
11
+ Both events come from `completeCartWithSplitOrdersWorkflow`. Neither is emitted when the workflow returns an existing group for a cart that was already split.
12
+
13
+ | Event | Emitted when | Payload |
14
+ | --- | --- | --- |
15
+ | `order_group.created` | Checkout creates a group for a completed cart | `{ id }`, the group id |
16
+ | `order.placed` | Checkout creates a child order, once per seller | `{ id }`, the order id |
17
+
18
+ The event name is available as `OrderGroupWorkflowEvents.CREATED` from `@mercurjs/core/workflows`. `order.placed` is Medusa’s `OrderWorkflowEvents.PLACED` from `@medusajs/framework/utils`.
19
+
20
+ ## Subscribe to a new group
21
+
22
+ Use `order_group.created` for work that concerns the whole purchase, such as one confirmation email for a checkout that spans three sellers:
10
23
 
11
24
  ```ts title="src/subscribers/order-group-created.ts"
12
25
  import type { SubscriberArgs, SubscriberConfig } from "@medusajs/framework"
26
+ import { getOrderGroupDetailWorkflow } from "@mercurjs/core/workflows"
13
27
 
14
28
  export default async function orderGroupCreatedHandler({
15
29
  event,
16
30
  container,
17
31
  }: SubscriberArgs<{ id: string }>) {
18
- const orderGroupId = event.data.id
19
- // ...send a confirmation, notify sellers, etc.
32
+ const { result: group } = await getOrderGroupDetailWorkflow(container).run({
33
+ input: {
34
+ order_group_id: event.data.id,
35
+ fields: ["id", "display_id", "total", "orders.seller.name"],
36
+ },
37
+ })
20
38
  }
21
39
 
22
40
  export const config: SubscriberConfig = {
@@ -24,14 +42,8 @@ export const config: SubscriberConfig = {
24
42
  }
25
43
  ```
26
44
 
27
- ## Order group events
28
-
29
- | Event | Emitted when | Payload |
30
- | --- | --- | --- |
31
- | `order_group.created` | A cart is split and its parent group is created | `{ id }` |
45
+ The subscriber loads the new group with its child orders and sellers, ready to pass to your notification provider.
32
46
 
33
- <Note>
34
- The same checkout split also emits `order.placed` for each child order created.
35
- Subscribe to `order.placed` when you need to react per seller order, and to
36
- `order_group.created` when you need the purchase as a whole.
37
- </Note>
47
+ <Tip>
48
+ Subscribe to `order.placed` instead when the work belongs to one seller, such as notifying that seller of a new order. Each child order fires its own event.
49
+ </Tip>
@@ -1,45 +1,106 @@
1
1
  ---
2
- title: "Links to other modules"
2
+ title: "Order group links"
3
3
  sidebarTitle: "Links"
4
- description: "How the Order Group domain links to carts, orders, sellers, and offers."
4
+ description: "The module links that connect an order group to its cart and child orders, and its orders to sellers and offers."
5
5
  ---
6
6
 
7
- Modules in Mercur never reference each other directly. They connect through
8
- **module links**. The `OrderGroup` entity (owned by the Seller module) sits at
9
- the center of a completed multi-seller purchase, linking the cart it came from to
10
- the per-seller orders it produced. Once a link is defined, you retrieve related
11
- records with `query.graph` using the link alias.
7
+ Mercur modules never reference each other directly, so an order group reaches carts and orders through module links. Two links start at the group. Two more, on the child orders, connect each order to its seller and each order line item to its offer. All four are defined in `packages/core/src/links/`, and checkout creates their rows when it splits a cart.
8
+
9
+ ## Order group to order
10
+
11
+ Connects a group to its child orders, one per seller.
12
+
13
+ | | |
14
+ | --- | --- |
15
+ | **Sides** | `OrderGroup` (Seller module) and `Order` (Order module) |
16
+ | **Cardinality** | One group to many orders |
17
+ | **Table** | `order_group_order` |
18
+ | **Defined in** | `order-group-order-link.ts` |
12
19
 
13
20
  ```ts
14
- const { data: groups } = await query.graph({
21
+ const { data: [group] } = await query.graph({
15
22
  entity: "order_group",
16
- fields: ["id", "display_id", "cart.id", "orders.id", "orders.total"],
23
+ fields: ["id", "display_id", "orders.id", "orders.total"],
24
+ filters: { id: "og_01JD8Q1234567" },
25
+ })
26
+ ```
27
+
28
+ To go from an order to its group, query the link entity directly:
29
+
30
+ ```ts
31
+ const { data: [row] } = await query.graph({
32
+ entity: "order_group_order",
33
+ fields: ["order_group_id"],
34
+ filters: { order_id: "order_01JD8Q1234568" },
17
35
  })
18
36
  ```
19
37
 
20
- ## Group links
38
+ ## Order group to cart
21
39
 
22
- | Linked module | Relationship |
40
+ Exposes the completed cart a group was created from. The link is read-only: it reads the group’s `cart_id` column and has no table of its own.
41
+
42
+ | | |
23
43
  | --- | --- |
24
- | **Cart** | A group references the one cart it was created from (`order_group.cart_id`, **read-only**). Carts are immutable after checkout. |
25
- | **Order** | A group has many child orders, one per seller, through the `order_group_order` table. |
44
+ | **Sides** | `OrderGroup.cart_id` (Seller module) and `Cart` (Cart module) |
45
+ | **Cardinality** | One group to one cart |
46
+ | **Table** | None, `readOnly: true` |
47
+ | **Defined in** | `order-group-cart-link.ts` |
26
48
 
27
- ## Order links
49
+ ```ts
50
+ const { data: [group] } = await query.graph({
51
+ entity: "order_group",
52
+ fields: ["id", "cart.id", "cart.email", "cart.completed_at"],
53
+ filters: { id: "og_01JD8Q1234567" },
54
+ })
55
+ ```
28
56
 
29
- The child orders produced by the split carry their own marketplace links:
57
+ You can’t create or dismiss this link with `link.create` or `link.dismiss`. It changes only if `cart_id` changes, and Mercur never updates it.
30
58
 
31
- | Linked module | Relationship |
59
+ ## Order to seller
60
+
61
+ Connects each child order to the seller who fulfills it.
62
+
63
+ | | |
32
64
  | --- | --- |
33
- | **Seller** | Each order belongs to one seller (`order_order_seller_seller`); a seller has many orders. |
34
- | **Offer** | Each order line item links to the offer it was purchased from (`order_line_item` → `offer`, list on the line-item side so one offer can back many order lines). |
35
-
36
- <Note>
37
- The `cart_id` link is resolved from the field on the group and can't be written
38
- through the link itself. The split sets it once, at creation.
39
- </Note>
40
-
41
- <Tip>
42
- To scope a group to a single seller, filter its child orders by
43
- `orders.seller.id`. The list workflow does exactly this when you pass a
44
- `sellerId`. See [List order groups](/platform/order-group/guides/list-order-groups).
45
- </Tip>
65
+ | **Sides** | `Order` (Order module) and `Seller` (Seller module) |
66
+ | **Cardinality** | Many orders to one seller |
67
+ | **Link entity** | `order_seller` |
68
+ | **Defined in** | `order-seller-link.ts` |
69
+
70
+ ```ts
71
+ const { data: [group] } = await query.graph({
72
+ entity: "order_group",
73
+ fields: ["id", "orders.id", "orders.seller.id", "orders.seller.name"],
74
+ filters: { id: "og_01JD8Q1234567" },
75
+ })
76
+ ```
77
+
78
+ `getOrderGroupsListWorkflow` reads `orders.seller.id` to trim each group to one seller when you pass `sellerId`.
79
+
80
+ ## Order line item to offer
81
+
82
+ Records which offer each order line item was bought from. Checkout copies it from the matching cart line item’s offer link.
83
+
84
+ | | |
85
+ | --- | --- |
86
+ | **Sides** | `OrderLineItem` (Order module) and `Offer` (Offer module) |
87
+ | **Cardinality** | Many order line items to one offer |
88
+ | **Defined in** | `order-line-item-offer-link.ts` |
89
+
90
+ ```ts
91
+ const { data: [group] } = await query.graph({
92
+ entity: "order_group",
93
+ fields: ["id", "orders.items.id", "orders.items.offer.id"],
94
+ filters: { id: "og_01JD8Q1234567" },
95
+ })
96
+ ```
97
+
98
+ The line item side is a list, so one offer can back line items in any number of orders and groups.
99
+
100
+ ## Links checkout creates for each order
101
+
102
+ Besides the links above, `completeCartWithSplitOrdersWorkflow` creates these rows for every child order:
103
+
104
+ - **Order to cart**: Medusa’s own link from each child order to the completed cart
105
+ - **Order to promotion**: for each promotion owned by the order’s seller
106
+ - **Seller to customer**: when the customer hasn’t bought from that seller before