@mercurjs/docs 2.3.8-canary.2 → 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.
- package/content/learn/architecture.mdx +166 -263
- package/content/platform/attribute/concepts/attribute-types.mdx +73 -46
- package/content/platform/attribute/concepts/global-vs-inline.mdx +54 -32
- package/content/platform/attribute/concepts/variant-axes.mdx +54 -32
- package/content/platform/attribute/guides/attach-attributes-to-a-product.mdx +96 -53
- package/content/platform/attribute/guides/create-a-variant-axis.mdx +106 -57
- package/content/platform/attribute/guides/create-an-attribute.mdx +105 -56
- package/content/platform/attribute/overview.mdx +37 -33
- package/content/platform/attribute/reference/data-models.mdx +53 -38
- package/content/platform/attribute/reference/events.mdx +47 -24
- package/content/platform/attribute/reference/links.mdx +98 -27
- package/content/platform/attribute/reference/service.mdx +71 -32
- package/content/platform/attribute/reference/workflows.mdx +158 -28
- package/content/platform/catalog/concepts/master-products.mdx +39 -37
- package/content/platform/catalog/concepts/product-seller-allowlist.mdx +56 -35
- package/content/platform/catalog/concepts/status-lifecycle.mdx +55 -49
- package/content/platform/catalog/concepts/variants-categories-collections.mdx +55 -35
- package/content/platform/catalog/guides/allowlist-stores.mdx +100 -37
- package/content/platform/catalog/guides/create-a-master-product.mdx +124 -48
- package/content/platform/catalog/guides/publish-or-reject-a-product.mdx +120 -55
- package/content/platform/catalog/overview.mdx +39 -35
- package/content/platform/catalog/reference/data-models.mdx +154 -43
- package/content/platform/catalog/reference/events.mdx +41 -25
- package/content/platform/catalog/reference/links.mdx +196 -28
- package/content/platform/catalog/reference/service.mdx +57 -35
- package/content/platform/catalog/reference/workflows.mdx +124 -30
- package/content/platform/commission/concepts/order-commission-lines.mdx +54 -52
- package/content/platform/commission/concepts/rule-matching.mdx +53 -63
- package/content/platform/commission/concepts/rules-and-rates.mdx +61 -59
- package/content/platform/commission/guides/batch-update-rules.mdx +69 -41
- package/content/platform/commission/guides/create-a-rate.mdx +101 -53
- package/content/platform/commission/guides/refresh-order-commission-lines.mdx +104 -35
- package/content/platform/commission/overview.mdx +43 -35
- package/content/platform/commission/reference/data-models.mdx +59 -45
- package/content/platform/commission/reference/events.mdx +28 -34
- package/content/platform/commission/reference/links.mdx +42 -33
- package/content/platform/commission/reference/service.mdx +103 -28
- package/content/platform/commission/reference/workflows.mdx +101 -27
- package/content/platform/offer/concepts/pricing-and-inventory.mdx +63 -49
- package/content/platform/offer/concepts/shipping.mdx +28 -29
- package/content/platform/offer/concepts/what-is-an-offer.mdx +48 -45
- package/content/platform/offer/guides/bulk-create-offers.mdx +97 -61
- package/content/platform/offer/guides/create-an-offer.mdx +112 -60
- package/content/platform/offer/guides/manage-offer-inventory.mdx +78 -38
- package/content/platform/offer/overview.mdx +39 -32
- package/content/platform/offer/reference/data-models.mdx +77 -47
- package/content/platform/offer/reference/events.mdx +44 -18
- package/content/platform/offer/reference/links.mdx +92 -40
- package/content/platform/offer/reference/service.mdx +66 -31
- package/content/platform/offer/reference/workflows.mdx +146 -37
- package/content/platform/order-group/concepts/computed-totals.mdx +40 -37
- package/content/platform/order-group/concepts/order-splitting.mdx +41 -39
- package/content/platform/order-group/concepts/the-order-group.mdx +39 -32
- package/content/platform/order-group/guides/list-order-groups.mdx +96 -56
- package/content/platform/order-group/guides/retrieve-an-order-group.mdx +93 -42
- package/content/platform/order-group/guides/split-a-cart.mdx +115 -40
- package/content/platform/order-group/overview.mdx +42 -32
- package/content/platform/order-group/reference/data-models.mdx +48 -31
- package/content/platform/order-group/reference/events.mdx +29 -17
- package/content/platform/order-group/reference/links.mdx +90 -29
- package/content/platform/order-group/reference/service.mdx +55 -31
- package/content/platform/order-group/reference/workflows.mdx +83 -24
- package/content/platform/payout/concepts/account-lifecycle.mdx +64 -67
- package/content/platform/payout/concepts/accounts-and-onboarding.mdx +50 -40
- package/content/platform/payout/concepts/payout-pipeline.mdx +70 -73
- package/content/platform/payout/guides/create-a-payout-account.mdx +65 -41
- package/content/platform/payout/guides/process-a-provider-webhook.mdx +84 -38
- package/content/platform/payout/guides/start-provider-onboarding.mdx +90 -46
- package/content/platform/payout/overview.mdx +43 -34
- package/content/platform/payout/reference/data-models.mdx +63 -36
- package/content/platform/payout/reference/events.mdx +56 -30
- package/content/platform/payout/reference/links.mdx +52 -22
- package/content/platform/payout/reference/service.mdx +72 -33
- package/content/platform/payout/reference/workflows.mdx +80 -19
- package/content/platform/product-edit/concepts/change-actions.mdx +52 -45
- package/content/platform/product-edit/concepts/change-pipeline.mdx +60 -52
- package/content/platform/product-edit/concepts/status-and-auto-confirm.mdx +43 -46
- package/content/platform/product-edit/guides/confirm-or-decline-a-change.mdx +104 -56
- package/content/platform/product-edit/guides/edit-a-product.mdx +126 -46
- package/content/platform/product-edit/guides/request-a-revision.mdx +99 -39
- package/content/platform/product-edit/overview.mdx +41 -34
- package/content/platform/product-edit/reference/data-models.mdx +73 -47
- package/content/platform/product-edit/reference/events.mdx +39 -29
- package/content/platform/product-edit/reference/links.mdx +32 -24
- package/content/platform/product-edit/reference/service.mdx +45 -26
- package/content/platform/product-edit/reference/workflows.mdx +173 -31
- package/content/platform/review/concepts/product-vs-seller-reviews.mdx +42 -41
- package/content/platform/review/concepts/ratings-and-moderation.mdx +45 -44
- package/content/platform/review/concepts/the-review-model.mdx +52 -45
- package/content/platform/review/guides/compute-aggregate-ratings.mdx +62 -37
- package/content/platform/review/guides/create-a-review.mdx +109 -39
- package/content/platform/review/guides/moderate-a-review.mdx +83 -37
- package/content/platform/review/guides/respond-to-a-review.mdx +85 -40
- package/content/platform/review/overview.mdx +43 -33
- package/content/platform/review/reference/data-models.mdx +41 -27
- package/content/platform/review/reference/events.mdx +55 -37
- package/content/platform/review/reference/links.mdx +80 -22
- package/content/platform/review/reference/service.mdx +61 -33
- package/content/platform/review/reference/workflows.mdx +80 -24
- package/content/platform/store/concepts/lifecycle.mdx +68 -44
- package/content/platform/store/concepts/store-entity.mdx +45 -27
- package/content/platform/store/concepts/team.mdx +56 -35
- package/content/platform/store/guides/create-a-store.mdx +102 -35
- package/content/platform/store/guides/manage-the-team.mdx +122 -32
- package/content/platform/store/guides/moderate-a-store.mdx +107 -38
- package/content/platform/store/overview.mdx +41 -34
- package/content/platform/store/reference/data-models.mdx +132 -57
- package/content/platform/store/reference/events.mdx +42 -17
- package/content/platform/store/reference/links.mdx +67 -49
- package/content/platform/store/reference/service.mdx +105 -33
- package/content/platform/store/reference/workflows.mdx +304 -24
- package/content/references/panel-extensions/layouts.mdx +169 -0
- package/llms.txt +112 -111
- package/package.json +1 -1
|
@@ -1,83 +1,135 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: "Create an offer"
|
|
2
|
+
title: "Create an offer from your server code"
|
|
3
3
|
sidebarTitle: "Create an offer"
|
|
4
|
-
description: "
|
|
4
|
+
description: "Run createOffersWorkflow to list a master variant for a store with a SKU, price, stock, and shipping profile."
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
for example in a custom API route, a seed script, or an import flow.
|
|
7
|
+
Create an offer with `createOffersWorkflow` when you list products for a store outside the Vendor panel, for example in a custom route, a seed script, or an import job.
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
inventory items, and its price rows, and wires up every link in one run. Run it
|
|
12
|
-
from any place that has access to the Medusa container.
|
|
9
|
+
## Before you begin
|
|
13
10
|
|
|
14
|
-
|
|
11
|
+
You need these records in place:
|
|
15
12
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
- **A store**: its `seller_id` and the id of a member to record as `created_by`
|
|
14
|
+
- **A master variant**: the `variant_id` the store will sell
|
|
15
|
+
- **A shipping profile**: one that belongs to the store
|
|
16
|
+
- **A stock location**: where the starting stock is held
|
|
17
|
+
|
|
18
|
+
## Create the offer
|
|
19
|
+
|
|
20
|
+
<Steps>
|
|
21
|
+
<Step title="Add a route that runs the workflow">
|
|
22
|
+
Create an API route that runs `createOffersWorkflow` with one offer.
|
|
19
23
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
prices: [{ amount: 2500, currency_code: "usd" }],
|
|
31
|
-
inventory_items: [
|
|
24
|
+
```ts title="src/api/admin/custom/offers/route.ts"
|
|
25
|
+
import type { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
|
|
26
|
+
import { createOffersWorkflow } from "@mercurjs/core/workflows"
|
|
27
|
+
|
|
28
|
+
const stock = [{ location_id: "sloc_01JD8Q1234567", stocked_quantity: 50 }]
|
|
29
|
+
|
|
30
|
+
export async function POST(req: MedusaRequest, res: MedusaResponse) {
|
|
31
|
+
const { result } = await createOffersWorkflow(req.scope).run({
|
|
32
|
+
input: {
|
|
33
|
+
offers: [
|
|
32
34
|
{
|
|
33
|
-
|
|
35
|
+
seller_id: "sel_01JD8Q1234567",
|
|
36
|
+
created_by: "mem_01JD8Q1234567",
|
|
37
|
+
variant_id: "variant_01JD8Q1234567",
|
|
38
|
+
shipping_profile_id: "sp_01JD8Q1234567",
|
|
39
|
+
sku: "ACME-LS-M",
|
|
40
|
+
prices: [{ amount: 4700, currency_code: "eur" }],
|
|
41
|
+
inventory_items: [{ stock_levels: stock }],
|
|
34
42
|
},
|
|
35
43
|
],
|
|
36
44
|
},
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
res.status(201).json({ offer: result[0] })
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The workflow returns the created `Offer` rows. The one `inventory_items` entry becomes a new inventory item with 50 units at the location.
|
|
52
|
+
</Step>
|
|
53
|
+
<Step title="Know what the run wires up">
|
|
54
|
+
One run does more than insert the row:
|
|
55
|
+
|
|
56
|
+
- **Inventory**: creates an `InventoryItem` per entry, links it to the offer with its `required_quantity`, and links it to the store
|
|
57
|
+
- **Prices**: adds each price to the variant’s price set with an `offer_id` rule and links it to the offer
|
|
58
|
+
- **Barcodes**: copies `ean` and `upc` from the variant when you leave them out
|
|
59
|
+
- **Shipping**: links the master product to the shipping profile if the product has none
|
|
60
|
+
- **Event**: emits `offer.created` with `{ id, product_id }`
|
|
61
|
+
</Step>
|
|
62
|
+
<Step title="Read the offer back with its links">
|
|
63
|
+
Query the offer with its prices and stock to confirm the result.
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
const { data: [offer] } = await query.graph({
|
|
67
|
+
entity: "offer",
|
|
68
|
+
fields: [
|
|
69
|
+
"id",
|
|
70
|
+
"sku",
|
|
71
|
+
"prices.amount",
|
|
72
|
+
"prices.currency_code",
|
|
73
|
+
"inventory_item_link.required_quantity",
|
|
74
|
+
"inventory_item_link.inventory_item.location_levels.*",
|
|
37
75
|
],
|
|
38
|
-
|
|
39
|
-
|
|
76
|
+
filters: { id: result[0].id },
|
|
77
|
+
})
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
`prices` reads the offer’s own rows on the shared price set. `inventory_item_link` returns the pivot rows, so you get `required_quantity` with each item.
|
|
81
|
+
</Step>
|
|
82
|
+
</Steps>
|
|
83
|
+
|
|
84
|
+
## Set selling terms and a condition
|
|
40
85
|
|
|
41
|
-
|
|
86
|
+
The offer accepts optional fields beyond the required ones. Add them to the same entry:
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
{
|
|
90
|
+
sku: "ACME-LS-M-RF",
|
|
91
|
+
condition_id: "ofcond_01JD8Q1234567",
|
|
92
|
+
manage_inventory: true,
|
|
93
|
+
allow_backorder: false,
|
|
94
|
+
leadtime_to_ship: 3,
|
|
95
|
+
metadata: { source: "erp" },
|
|
42
96
|
}
|
|
43
97
|
```
|
|
44
98
|
|
|
45
|
-
|
|
46
|
-
Each offer must reference an existing master `variant_id` and include at least
|
|
47
|
-
one `inventory_items` entry. The SKU must be unique within the store.
|
|
48
|
-
Reusing an existing `(seller_id, sku)` pair is rejected.
|
|
49
|
-
</Note>
|
|
99
|
+
`condition_id` must point at an active offer condition. `manage_inventory` defaults to `true`, `allow_backorder` to `false`, and `leadtime_to_ship` to `null`.
|
|
50
100
|
|
|
51
|
-
##
|
|
101
|
+
## Attach custom data with additional_data
|
|
52
102
|
|
|
53
|
-
|
|
103
|
+
Pass `additional_data` to the run to hand extra values to the `offersCreated` hook. Use it to store data from your own module next to the offer.
|
|
54
104
|
|
|
55
|
-
-
|
|
56
|
-
|
|
57
|
-
- Links the offer to its store, product, variant, and shipping profile.
|
|
58
|
-
- Emits `offer.created`.
|
|
105
|
+
```ts title="src/workflows/hooks/offers-created.ts"
|
|
106
|
+
import { createOffersWorkflow } from "@mercurjs/core/workflows"
|
|
59
107
|
|
|
60
|
-
|
|
108
|
+
createOffersWorkflow.hooks.offersCreated(
|
|
109
|
+
async ({ offers, additional_data }, { container }) => {
|
|
110
|
+
const logger = container.resolve("logger")
|
|
111
|
+
for (const offer of offers) {
|
|
112
|
+
logger.info(`${offer.sku}: ${additional_data?.source ?? "api"}`)
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
)
|
|
116
|
+
```
|
|
61
117
|
|
|
62
|
-
The
|
|
63
|
-
`offersCreated` hook, letting you persist marketplace-specific data alongside the
|
|
64
|
-
offer without forking the workflow.
|
|
118
|
+
The hook receives the created offers with their `prices` loaded. Run the workflow with `additional_data: { source: "erp" }` to see the value in the handler.
|
|
65
119
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
})
|
|
83
|
-
```
|
|
120
|
+
## Handle a failed run
|
|
121
|
+
|
|
122
|
+
The workflow validates the whole input and rolls back on failure. Compensation removes the inventory items, prices, and links it already created.
|
|
123
|
+
|
|
124
|
+
A run fails when:
|
|
125
|
+
|
|
126
|
+
- **A variant doesn’t exist**: `Variant with id … was not found`
|
|
127
|
+
- **An offer has no inventory items**: `Offer must have at least one inventory item`
|
|
128
|
+
- **A condition is unknown or inactive**: `Offer condition … is not active` or not found
|
|
129
|
+
- **A SKU is taken in the store**: the `(seller_id, sku)` unique index rejects the insert
|
|
130
|
+
|
|
131
|
+
## Next steps
|
|
132
|
+
|
|
133
|
+
- [Bulk-create offers](/platform/offer/guides/bulk-create-offers)
|
|
134
|
+
- [Manage offer inventory](/platform/offer/guides/manage-offer-inventory)
|
|
135
|
+
- [createOffersWorkflow reference](/platform/offer/reference/workflows)
|
|
@@ -1,53 +1,93 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: "
|
|
2
|
+
title: "Change the inventory items behind an offer"
|
|
3
3
|
sidebarTitle: "Manage offer inventory"
|
|
4
|
-
description: "
|
|
4
|
+
description: "Use batchOfferInventoryItemsWorkflow to link, relink, and unlink existing inventory items on an offer."
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
existing offer from your own server code.
|
|
7
|
+
Run `batchOfferInventoryItemsWorkflow` when an existing offer needs different stock behind it, for example to turn it into a kit or to swap a component. The workflow changes the `offer ↔ inventory_item` links and their `required_quantity` in one run.
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
items backing an offer is managed through the `offer ↔ inventory_item` link.
|
|
12
|
-
`batchOfferInventoryItemsWorkflow` applies creates, updates, and deletes to that
|
|
13
|
-
link in a single run.
|
|
9
|
+
## Before you begin
|
|
14
10
|
|
|
15
|
-
|
|
11
|
+
You need these records in place:
|
|
16
12
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
import { batchOfferInventoryItemsWorkflow } from "@mercurjs/core/workflows"
|
|
13
|
+
- **An offer**: the `offer_id` whose stock you change
|
|
14
|
+
- **Existing inventory items**: the workflow links items that already exist and doesn’t create new ones
|
|
20
15
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
|
|
16
|
+
## Change the links
|
|
17
|
+
|
|
18
|
+
<Steps>
|
|
19
|
+
<Step title="Add a route that runs the batch">
|
|
20
|
+
Pass the offer and the three optional lists: `create`, `update`, and `delete`.
|
|
21
|
+
|
|
22
|
+
```ts title="src/api/admin/custom/offers/[id]/inventory/route.ts"
|
|
23
|
+
import type { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
|
|
24
|
+
import { batchOfferInventoryItemsWorkflow } from "@mercurjs/core/workflows"
|
|
25
|
+
|
|
26
|
+
export async function POST(req: MedusaRequest, res: MedusaResponse) {
|
|
27
|
+
const { result } = await batchOfferInventoryItemsWorkflow(req.scope).run({
|
|
28
|
+
input: {
|
|
29
|
+
offer_id: req.params.id,
|
|
30
|
+
create: [
|
|
31
|
+
{ inventory_item_id: "iitem_01JD8Q1234567", required_quantity: 2 },
|
|
32
|
+
],
|
|
33
|
+
update: [
|
|
34
|
+
{ inventory_item_id: "iitem_01JD8Q1234568", required_quantity: 1 },
|
|
35
|
+
],
|
|
36
|
+
delete: ["iitem_01JD8Q1234569"],
|
|
37
|
+
},
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
res.json(result)
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
`create` links a new item, `update` changes the `required_quantity` of a linked item, and `delete` unlinks an item. The inventory item itself stays in place after an unlink.
|
|
45
|
+
</Step>
|
|
46
|
+
<Step title="Read the result">
|
|
47
|
+
The workflow returns what changed:
|
|
48
|
+
|
|
49
|
+
- **`created`**: the link definitions it added
|
|
50
|
+
- **`updated`**: the link definitions it rewrote
|
|
51
|
+
- **`deleted`**: the inventory item ids it unlinked
|
|
52
|
+
|
|
53
|
+
It also emits `offer.updated` with `{ id }` for the offer.
|
|
54
|
+
</Step>
|
|
55
|
+
</Steps>
|
|
34
56
|
|
|
35
|
-
|
|
57
|
+
## Rules the batch enforces
|
|
36
58
|
|
|
37
|
-
|
|
59
|
+
The workflow checks the whole payload before it writes anything. Any broken rule fails the run:
|
|
38
60
|
|
|
39
|
-
-
|
|
40
|
-
-
|
|
41
|
-
- `
|
|
42
|
-
-
|
|
61
|
+
- **Unknown offer**: `Offer with id: … was not found`
|
|
62
|
+
- **Unknown item in `create`**: the inventory item must exist
|
|
63
|
+
- **Item not linked, in `delete`**: fails with not found instead of a silent no-op
|
|
64
|
+
- **Same id twice**: an id can appear once per list and in only one of the three lists
|
|
65
|
+
|
|
66
|
+
`required_quantity` defaults to `1` in `create` and is required in `update`.
|
|
43
67
|
|
|
44
68
|
<Note>
|
|
45
|
-
|
|
46
|
-
items and their `required_quantity`. To create brand-new inventory items with
|
|
47
|
-
starting stock as part of listing an offer, pass `inventory_items` to
|
|
48
|
-
[`createOffersWorkflow`](/platform/offer/guides/create-an-offer) instead.
|
|
69
|
+
The workflow doesn’t check that an item in `create` is already linked or that an item in `update` is linked, and it doesn’t check which store owns an item. Read the offer’s `inventory_item_link` and the item’s store first when your input comes from a seller.
|
|
49
70
|
</Note>
|
|
50
71
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
72
|
+
## Run code after the batch
|
|
73
|
+
|
|
74
|
+
The workflow exposes an `offerInventoryItemsBatched` hook. It receives the `offer_id`, the `result`, and any `additional_data` you passed.
|
|
75
|
+
|
|
76
|
+
```ts title="src/workflows/hooks/offer-inventory-batched.ts"
|
|
77
|
+
import { batchOfferInventoryItemsWorkflow } from "@mercurjs/core/workflows"
|
|
78
|
+
|
|
79
|
+
batchOfferInventoryItemsWorkflow.hooks.offerInventoryItemsBatched(
|
|
80
|
+
async ({ offer_id, result }, { container }) => {
|
|
81
|
+
const logger = container.resolve("logger")
|
|
82
|
+
logger.info(`${offer_id}: ${result.deleted.length} items unlinked`)
|
|
83
|
+
}
|
|
84
|
+
)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
A `validate` hook runs first with the raw `input`, so you can reject a batch with your own rules before any link changes.
|
|
88
|
+
|
|
89
|
+
## Next steps
|
|
90
|
+
|
|
91
|
+
- [How offer stock works](/platform/offer/concepts/pricing-and-inventory)
|
|
92
|
+
- [The offer to inventory item link](/platform/offer/reference/links)
|
|
93
|
+
- [batchOfferInventoryItemsWorkflow reference](/platform/offer/reference/workflows)
|
|
@@ -1,60 +1,67 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: "
|
|
2
|
+
title: "Offers"
|
|
3
3
|
sidebarTitle: "Overview"
|
|
4
|
-
description: "
|
|
4
|
+
description: "Let every store sell a shared catalog product with its own SKU, price, stock, condition, and shipping profile."
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
Use offers to let
|
|
8
|
-
own terms.
|
|
7
|
+
Use offers to let several stores sell the same catalog product, each on its own terms.
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
Cart and order line items link back to the exact offer that was purchased, so the
|
|
15
|
-
whole order lifecycle knows which store fulfills and gets paid.
|
|
9
|
+
Products in Mercur live in one shared master catalog that no store owns. An offer is the record that connects a store to one master variant. It carries everything that makes the listing the store’s own: its SKU, price, inventory, condition, and shipping profile. The Offer module holds the offer and its conditions, and links reach out to the store, the catalog, pricing, inventory, fulfillment, and the cart and order line items that buy it.
|
|
10
|
+
|
|
11
|
+
<img className="block dark:hidden" src="/images/figures/offer-overview-light.svg" alt="The Linen shirt master product sits behind an Offers list for its M variant: ACME, GLOBEX, and INITECH each list the same variant with their own SKU, condition, price, and stock." />
|
|
12
|
+
<img className="hidden dark:block" src="/images/figures/offer-overview-dark.svg" alt="The Linen shirt master product sits behind an Offers list for its M variant: ACME, GLOBEX, and INITECH each list the same variant with their own SKU, condition, price, and stock." />
|
|
16
13
|
|
|
17
14
|
<Note>
|
|
18
|
-
|
|
19
|
-
publishes an offer against a master product variant. Two stores selling the
|
|
20
|
-
same product each have their own offer, with their own SKU, price, and stock.
|
|
15
|
+
The data model is `Offer` (id prefix `offer`), resolved with `MercurModules.OFFER` from `@mercurjs/types`. A store never owns a product. Two stores selling the same variant each hold their own offer.
|
|
21
16
|
</Note>
|
|
22
17
|
|
|
23
18
|
## Key features
|
|
24
19
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
- **
|
|
28
|
-
- **
|
|
29
|
-
- **
|
|
30
|
-
- **
|
|
20
|
+
The Offer module covers everything a store needs to sell a catalog variant:
|
|
21
|
+
|
|
22
|
+
- **Per-store listings**: an offer points at one master variant, with a SKU that’s unique within its store
|
|
23
|
+
- **Offer-scoped pricing**: price rows sit on the variant’s shared price set, each tagged with an `offer_id` price rule
|
|
24
|
+
- **Offer-scoped inventory**: inventory items link to the offer, not the variant, so stock never mixes between stores
|
|
25
|
+
- **Conditions**: operators define conditions such as `new` or `refurbished`, and stores list offers under the active ones
|
|
26
|
+
- **Per-offer shipping**: each offer names the store’s own shipping profile
|
|
27
|
+
- **Order attribution**: cart and order line items link to the offer that was bought
|
|
28
|
+
- **Hooks and events**: every workflow exposes hooks and emits `offer.*` events for your own side effects
|
|
29
|
+
|
|
30
|
+
## How it works
|
|
31
|
+
|
|
32
|
+
An offer moves through the marketplace in four steps:
|
|
33
|
+
|
|
34
|
+
1. A store runs `createOffersWorkflow` against a master variant, with a SKU, prices, inventory items, and a shipping profile.
|
|
35
|
+
2. The workflow writes the prices onto the variant’s price set with an `offer_id` rule and creates inventory items linked to the offer.
|
|
36
|
+
3. When a shopper adds the offer to a cart, the line item links to the offer and pricing resolves the offer’s own rows.
|
|
37
|
+
4. At checkout the order line item keeps the offer link, so the right store fulfills the item and gets paid.
|
|
31
38
|
|
|
32
39
|
## Get started
|
|
33
40
|
|
|
34
|
-
Learn how
|
|
41
|
+
Learn how offers, prices, stock, and shipping fit together.
|
|
35
42
|
|
|
36
43
|
<CardGroup cols={2}>
|
|
37
44
|
<Card title="What is an offer" icon="tag" href="/platform/offer/concepts/what-is-an-offer">
|
|
38
|
-
The offer record,
|
|
45
|
+
The offer record, its SKU rules, and offer conditions.
|
|
39
46
|
</Card>
|
|
40
47
|
<Card title="Pricing & inventory" icon="coins" href="/platform/offer/concepts/pricing-and-inventory">
|
|
41
|
-
|
|
48
|
+
Prices on the shared price set and stock linked to the offer.
|
|
42
49
|
</Card>
|
|
43
50
|
<Card title="Shipping" icon="truck" href="/platform/offer/concepts/shipping">
|
|
44
|
-
How an offer
|
|
51
|
+
How an offer ships with its store’s shipping profile.
|
|
45
52
|
</Card>
|
|
46
53
|
</CardGroup>
|
|
47
54
|
|
|
48
55
|
## Examples
|
|
49
56
|
|
|
50
|
-
Build against
|
|
57
|
+
Build against offers in your own server code.
|
|
51
58
|
|
|
52
59
|
<CardGroup cols={2}>
|
|
53
60
|
<Card title="Create an offer" icon="plus" href="/platform/offer/guides/create-an-offer">
|
|
54
|
-
Run `createOffersWorkflow`
|
|
61
|
+
Run `createOffersWorkflow` from an API route.
|
|
55
62
|
</Card>
|
|
56
63
|
<Card title="Bulk-create offers" icon="layer-group" href="/platform/offer/guides/bulk-create-offers">
|
|
57
|
-
List
|
|
64
|
+
List a store’s catalog in a single run.
|
|
58
65
|
</Card>
|
|
59
66
|
<Card title="Manage offer inventory" icon="boxes-stacked" href="/platform/offer/guides/manage-offer-inventory">
|
|
60
67
|
Attach, update, and detach inventory items on an offer.
|
|
@@ -63,22 +70,22 @@ Build against the Offer domain in your own code:
|
|
|
63
70
|
|
|
64
71
|
## Resources
|
|
65
72
|
|
|
66
|
-
|
|
73
|
+
The data models, links, workflows, service methods, and events behind offers.
|
|
67
74
|
|
|
68
75
|
<CardGroup cols={2}>
|
|
69
76
|
<Card title="Data models" icon="table" href="/platform/offer/reference/data-models">
|
|
70
|
-
|
|
77
|
+
`Offer` and `OfferCondition`, field by field.
|
|
71
78
|
</Card>
|
|
72
79
|
<Card title="Links" icon="link" href="/platform/offer/reference/links">
|
|
73
|
-
How
|
|
80
|
+
How offers link to stores, catalog, pricing, inventory, and orders.
|
|
74
81
|
</Card>
|
|
75
82
|
<Card title="Workflows" icon="diagram-project" href="/platform/offer/reference/workflows">
|
|
76
|
-
|
|
83
|
+
Offer, price, inventory, and condition workflows with their hooks.
|
|
77
84
|
</Card>
|
|
78
85
|
<Card title="Service" icon="gear" href="/platform/offer/reference/service">
|
|
79
|
-
Module service methods for
|
|
86
|
+
Module service methods for reading and writing records directly.
|
|
80
87
|
</Card>
|
|
81
88
|
<Card title="Events" icon="bell" href="/platform/offer/reference/events">
|
|
82
|
-
Events emitted as offers change.
|
|
89
|
+
Events emitted as offers and conditions change.
|
|
83
90
|
</Card>
|
|
84
91
|
</CardGroup>
|
|
@@ -1,56 +1,86 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: "
|
|
2
|
+
title: "Offer data models"
|
|
3
3
|
sidebarTitle: "Data models"
|
|
4
|
-
description: "
|
|
4
|
+
description: "Every field of the Offer and OfferCondition data models in the Offer module."
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
The Offer
|
|
8
|
-
model and fields. For the full module overview, see the
|
|
9
|
-
[Offer overview](/platform/offer/overview).
|
|
7
|
+
The Offer module owns two data models: `Offer` and `OfferCondition`. Prices, inventory, the store, and catalog records aren’t columns on these models. They attach through [module links](/platform/offer/reference/links).
|
|
10
8
|
|
|
11
9
|
## Offer
|
|
12
10
|
|
|
13
|
-
Table `offer`, id prefix `offer`.
|
|
14
|
-
variant. Price and inventory are attached through links rather than stored on the
|
|
15
|
-
row.
|
|
11
|
+
A store’s listing of one master product variant. Table `offer`, id prefix `offer`.
|
|
16
12
|
|
|
17
|
-
| Field | Type |
|
|
13
|
+
| Field | Type | Description |
|
|
18
14
|
| --- | --- | --- |
|
|
19
|
-
| `id` | text | Primary key |
|
|
20
|
-
| `seller_id` | text | The store that owns the offer
|
|
21
|
-
| `variant_id` | text | The master `ProductVariant` the offer
|
|
22
|
-
| `product_id` | text | The master `Product
|
|
23
|
-
| `shipping_profile_id` | text | The store
|
|
24
|
-
| `sku` | text | Searchable
|
|
25
|
-
| `ean` | text |
|
|
26
|
-
| `upc` | text |
|
|
27
|
-
| `
|
|
28
|
-
| `
|
|
29
|
-
| `
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
`
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
15
|
+
| `id` | `text` | Primary key, prefixed `offer_` |
|
|
16
|
+
| `seller_id` | `text` | The store that owns the offer |
|
|
17
|
+
| `variant_id` | `text` | The master `ProductVariant` the offer sells |
|
|
18
|
+
| `product_id` | `text` | The master `Product`, read from the variant on create |
|
|
19
|
+
| `shipping_profile_id` | `text` | The store’s shipping profile for this offer |
|
|
20
|
+
| `sku` | `text` | Searchable. Unique per store among live offers |
|
|
21
|
+
| `ean` | `text \| null` | Searchable. Copied from the variant when omitted on create |
|
|
22
|
+
| `upc` | `text \| null` | Searchable. Copied from the variant when omitted on create |
|
|
23
|
+
| `manage_inventory` | `boolean` | Default `true`. Whether stock is checked for the offer |
|
|
24
|
+
| `allow_backorder` | `boolean` | Default `false`. Whether the offer sells past its stock |
|
|
25
|
+
| `leadtime_to_ship` | `number \| null` | Lead time before the offer ships |
|
|
26
|
+
| `created_by` | `text` | The member who created the offer |
|
|
27
|
+
| `condition_id` | `text \| null` | Foreign key to `OfferCondition` |
|
|
28
|
+
| `variant_count` | `number` | Computed, not stored. Set only by `group_by_seller` reads |
|
|
29
|
+
| `metadata` | `json \| null` | Custom key-value data |
|
|
30
|
+
| `created_at` | `timestamp` | Set on create |
|
|
31
|
+
| `updated_at` | `timestamp` | Set on every write |
|
|
32
|
+
| `deleted_at` | `timestamp \| null` | Set when the offer is soft-deleted |
|
|
33
|
+
|
|
34
|
+
`OfferDTO` also has `offer_ids`, the list of offer ids in a `group_by_seller` group. It isn’t a model field.
|
|
35
|
+
|
|
36
|
+
### Offer relations
|
|
37
|
+
|
|
38
|
+
The offer has one relation inside the module:
|
|
39
|
+
|
|
40
|
+
- **`condition`**: belongs to one `OfferCondition`, nullable
|
|
41
|
+
|
|
42
|
+
### Offer indexes
|
|
43
|
+
|
|
44
|
+
Every index applies only to rows where `deleted_at IS NULL`:
|
|
45
|
+
|
|
46
|
+
| Index | Columns | Notes |
|
|
47
|
+
| --- | --- | --- |
|
|
48
|
+
| `IDX_offer_seller_sku_unique` | `seller_id`, `sku` | Unique |
|
|
49
|
+
| `IDX_offer_variant_id` | `variant_id` | |
|
|
50
|
+
| `IDX_offer_product_id` | `product_id` | |
|
|
51
|
+
| `IDX_offer_seller_id` | `seller_id` | |
|
|
52
|
+
| `IDX_offer_shipping_profile_id` | `shipping_profile_id` | |
|
|
53
|
+
| `IDX_offer_ean` | `ean` | Only where `ean IS NOT NULL` |
|
|
54
|
+
| `IDX_offer_upc` | `upc` | Only where `upc IS NOT NULL` |
|
|
55
|
+
| `IDX_offer_condition_id` | `condition_id` | Only where `condition_id IS NOT NULL` |
|
|
56
|
+
| `IDX_offer_seller_id_created_at` | `seller_id`, `created_at` | |
|
|
57
|
+
| `IDX_offer_product_id_seller_id_created_at` | `product_id`, `seller_id`, `created_at` | |
|
|
58
|
+
|
|
59
|
+
## OfferCondition
|
|
60
|
+
|
|
61
|
+
A physical condition an offer can be listed under, such as `new` or `refurbished`. Operators manage the list. Id prefix `ofcond`.
|
|
62
|
+
|
|
63
|
+
| Field | Type | Description |
|
|
64
|
+
| --- | --- | --- |
|
|
65
|
+
| `id` | `text` | Primary key, prefixed `ofcond_` |
|
|
66
|
+
| `code` | `text` | Searchable. Unique among live conditions |
|
|
67
|
+
| `label` | `text` | Searchable. Display name |
|
|
68
|
+
| `is_active` | `boolean` | Default `true`. Inactive conditions can’t be assigned |
|
|
69
|
+
| `rank` | `number` | Default `0`. Sort order of the list |
|
|
70
|
+
| `metadata` | `json \| null` | Custom key-value data |
|
|
71
|
+
| `created_at` | `timestamp` | Set on create |
|
|
72
|
+
| `updated_at` | `timestamp` | Set on every write |
|
|
73
|
+
| `deleted_at` | `timestamp \| null` | Set when the condition is soft-deleted |
|
|
74
|
+
|
|
75
|
+
### OfferCondition relations
|
|
76
|
+
|
|
77
|
+
The condition has one relation inside the module:
|
|
78
|
+
|
|
79
|
+
- **`offers`**: has many `Offer` records, mapped by `condition`
|
|
80
|
+
|
|
81
|
+
The index `IDX_offer_condition_code_unique` keeps `code` unique while `deleted_at IS NULL`.
|
|
82
|
+
|
|
83
|
+
## Related
|
|
84
|
+
|
|
85
|
+
- [Links to other modules](/platform/offer/reference/links)
|
|
86
|
+
- [What is an offer](/platform/offer/concepts/what-is-an-offer)
|