@mercurjs/docs 2.3.7 → 2.3.8-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.
|
@@ -12,7 +12,7 @@ This reference lists the workflows for the Offer domain. Import them from
|
|
|
12
12
|
| Workflow | Input | Purpose |
|
|
13
13
|
| --- | --- | --- |
|
|
14
14
|
| `createOffersWorkflow` | `{ offers[], additional_data? }` | Create offers with prices, inventory, and links |
|
|
15
|
-
| `updateOffersWorkflow` | `{ offers[], additional_data? }` | Update offer rows and rewrite their price ladders |
|
|
15
|
+
| `updateOffersWorkflow` | `{ offers[], updated_by?, additional_data? }` | Update offer rows and rewrite their price ladders |
|
|
16
16
|
| `deleteOffersWorkflow` | `{ ids[], additional_data? }` | Delete offers |
|
|
17
17
|
| `batchOfferInventoryItemsWorkflow` | `{ offer_id, create?, update?, delete?, additional_data? }` | Add, update, and detach an offer's inventory-item links |
|
|
18
18
|
|
|
@@ -24,9 +24,37 @@ Each workflow exposes hooks so you can extend it without forking:
|
|
|
24
24
|
| --- | --- |
|
|
25
25
|
| `createOffersWorkflow` | `validate`, `offersCreated` |
|
|
26
26
|
| `updateOffersWorkflow` | `validate`, `offersUpdated` |
|
|
27
|
+
| `upsertOfferPricesWorkflow` | `offerPricesUpserted` |
|
|
27
28
|
| `deleteOffersWorkflow` | `offersDeleted` |
|
|
28
29
|
| `batchOfferInventoryItemsWorkflow` | `validate`, `offerInventoryItemsBatched` |
|
|
29
30
|
|
|
31
|
+
### Hook payloads
|
|
32
|
+
|
|
33
|
+
| Hook | Payload |
|
|
34
|
+
| --- | --- |
|
|
35
|
+
| `offersCreated` | `{ offers: OfferDTO[], additional_data? }` — each offer carries `created_by` and its `prices` |
|
|
36
|
+
| `offersUpdated` | `{ offers: OfferDTO[], previous_offers: OfferDTO[], updated_by?, additional_data? }` — `previous_offers` is the row state before the write |
|
|
37
|
+
| `offerPricesUpserted` | `{ offers: Array<{ offer_id, previous_prices: OfferPriceDTO[], prices: OfferPriceDTO[], created: string[], updated: string[], deleted: string[] }>, updated_by: string \| null }` |
|
|
38
|
+
| `offersDeleted` | `{ ids: string[], offers: OfferDTO[], additional_data? }` — `offers` is a snapshot taken before deletion, including `prices` |
|
|
39
|
+
|
|
40
|
+
`updated_by` is the authenticated actor id. Vendor routes fill it from the session; pass it yourself when running `updateOffersWorkflow` or `upsertOfferPricesWorkflow` directly.
|
|
41
|
+
|
|
42
|
+
In `offerPricesUpserted`, `previous_prices` and `prices` are the offer's ladder before and after the write (`amount`, `currency_code`, `min_quantity`, `max_quantity`, `price_rules`). `created` and `deleted` hold the price ids added and removed; `updated` holds the ids rewritten in place whose amount, quantity bounds, or rules actually changed — an unchanged row resent with its id is not listed. The hook also fires when `updateOffersWorkflow` runs the price upsert for you, so a single handler on `upsertOfferPricesWorkflow` covers both entry points. Prices are hard-deleted and Medusa's pricing events carry ids only, so these payloads (and the `offersDeleted` snapshot) are the only place the previous values can be read.
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
import { upsertOfferPricesWorkflow } from "@mercurjs/core/workflows"
|
|
46
|
+
import { StepResponse } from "@medusajs/framework/workflows-sdk"
|
|
47
|
+
|
|
48
|
+
upsertOfferPricesWorkflow.hooks.offerPricesUpserted(
|
|
49
|
+
async ({ offers, updated_by }, { container }) => {
|
|
50
|
+
for (const { offer_id, previous_prices, prices, updated } of offers) {
|
|
51
|
+
// record a price-history entry for every id in `updated`
|
|
52
|
+
}
|
|
53
|
+
return new StepResponse(undefined)
|
|
54
|
+
}
|
|
55
|
+
)
|
|
56
|
+
```
|
|
57
|
+
|
|
30
58
|
## Behavior notes
|
|
31
59
|
|
|
32
60
|
- **Prices** are written on the master variant's shared price set, each row scoped by an `offer_id` `PriceRule`. On update, supplying `prices` replaces the ladder with the given rows; omitting it leaves prices untouched.
|
|
@@ -134,6 +134,60 @@ Each field is a `CustomFormField`.
|
|
|
134
134
|
onto the product's `metadata`.
|
|
135
135
|
</Warning>
|
|
136
136
|
|
|
137
|
+
## Customize the onboarding wizard
|
|
138
|
+
|
|
139
|
+
The vendor onboarding wizard is the `onboarding` form zone of the `seller` model. Each step is a `tab`. Use the same `forms` entries to add fields to a step, add a step, remove a step, or reorder the steps.
|
|
140
|
+
|
|
141
|
+
```tsx apps/vendor/src/custom-fields/seller.tsx
|
|
142
|
+
import { defineCustomFieldsConfig } from "@mercurjs/dashboard-sdk"
|
|
143
|
+
import { createFormHelper } from "@mercurjs/dashboard-shared"
|
|
144
|
+
|
|
145
|
+
const form = createFormHelper()
|
|
146
|
+
|
|
147
|
+
export default defineCustomFieldsConfig({
|
|
148
|
+
model: "seller",
|
|
149
|
+
forms: [
|
|
150
|
+
// Add fields to a built-in step
|
|
151
|
+
{ zone: "onboarding", tab: "address", fields: { region_note: form.define({ validation: form.string().optional() }) } },
|
|
152
|
+
// An unknown tab becomes a new step
|
|
153
|
+
{
|
|
154
|
+
zone: "onboarding",
|
|
155
|
+
tab: "documents",
|
|
156
|
+
label: "Documents",
|
|
157
|
+
rank: 25,
|
|
158
|
+
optional: true,
|
|
159
|
+
fields: {
|
|
160
|
+
vat_document_url: form.define({ validation: form.string().url(), label: "VAT document URL" }),
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
// Remove a built-in step
|
|
164
|
+
{ zone: "onboarding", tab: "company", disabled: true },
|
|
165
|
+
],
|
|
166
|
+
})
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
| Option | Type | Description |
|
|
170
|
+
| ---------- | --------- | ------------------------------------------------------------------------------------------------- |
|
|
171
|
+
| `label` | `string` | Step heading. Set it on every new step. |
|
|
172
|
+
| `rank` | `number` | Sort position. New steps without a rank go last. Also reorders a built-in step. |
|
|
173
|
+
| `optional` | `boolean` | Shows a **Skip** button. Set `false` on a built-in step to hide its Skip button. |
|
|
174
|
+
| `disabled` | `true` | Removes a built-in step. Takes no `fields`. The `store` step can't be removed. |
|
|
175
|
+
|
|
176
|
+
The built-in steps and their defaults:
|
|
177
|
+
|
|
178
|
+
| Step | `rank` | `optional` |
|
|
179
|
+
| --------- | ------ | ---------- |
|
|
180
|
+
| `store` | 10 | `false` |
|
|
181
|
+
| `address` | 20 | `true` |
|
|
182
|
+
| `company` | 30 | `true` |
|
|
183
|
+
| `payment` | 40 | `true` |
|
|
184
|
+
|
|
185
|
+
The last step's button reads **Finish** and creates the seller. Values from every step's custom fields are merged into one `additional_data` object on `POST /vendor/sellers`, which reaches the `sellerAccountCreated` hook of `createSellerAccountWorkflow`. A skipped step contributes nothing, even if its fields are required.
|
|
186
|
+
|
|
187
|
+
<Note>
|
|
188
|
+
Always set `tab` on an onboarding entry. An entry without a `tab` renders its fields on every step.
|
|
189
|
+
</Note>
|
|
190
|
+
|
|
137
191
|
## Extend detail sections
|
|
138
192
|
|
|
139
193
|
Add, replace, or remove fields on a detail section, and add actions to its
|
|
@@ -238,6 +292,36 @@ built-in ones.
|
|
|
238
292
|
the field list. The `link` declaration drives it.
|
|
239
293
|
</Warning>
|
|
240
294
|
|
|
295
|
+
## Combine configs from plugins and your app
|
|
296
|
+
|
|
297
|
+
Every config for a model applies in order: installed plugins first, then your
|
|
298
|
+
app's `src/custom-fields/` files. A later config sees everything earlier configs
|
|
299
|
+
added, not only the built-ins, so your app can change what a plugin contributed.
|
|
300
|
+
|
|
301
|
+
| Contribution | Matched by | A later config with the same id/key |
|
|
302
|
+
| --------------------- | ---------- | -------------------------------------------------------------------------- |
|
|
303
|
+
| `list.columns` | `id` | Replaces the column in place. Hide it with `columnVisibility: { id: false }`. |
|
|
304
|
+
| `list.filters` | `key` | Replaces the filter in place, or drops it with `remove: true`. |
|
|
305
|
+
| `displays[].fields` | `id` | Replaces the field in place, or drops it with `component: null`. |
|
|
306
|
+
| `forms[].fields` | field name | Replaces the field, including its `zone` and `tab`. |
|
|
307
|
+
| `columnVisibility` | column id | Overrides the earlier value for that column. |
|
|
308
|
+
| `columnOrder` | n/a | Replaces the earlier order. |
|
|
309
|
+
|
|
310
|
+
`link`, `bulkActions`, display `actions`, `activity`, and `actionLocks` add up
|
|
311
|
+
across configs.
|
|
312
|
+
|
|
313
|
+
```tsx
|
|
314
|
+
// src/custom-fields/product-brand.tsx: rework the plugin's "brand" column
|
|
315
|
+
export default defineCustomFieldsConfig({
|
|
316
|
+
model: "product",
|
|
317
|
+
link: "brand",
|
|
318
|
+
list: {
|
|
319
|
+
columns: [{ id: "brand", header: "Maker", component: ({ row }) => row.brand?.name }],
|
|
320
|
+
filters: [{ key: "brand_id", remove: true }],
|
|
321
|
+
},
|
|
322
|
+
})
|
|
323
|
+
```
|
|
324
|
+
|
|
241
325
|
## Fetch linked module data
|
|
242
326
|
|
|
243
327
|
Declare `link` to fetch a module link alongside the entity. Its data rides on the
|
|
@@ -12,6 +12,10 @@ The vendor store-setup and onboarding surface is a widget zone, `seller.setup`,
|
|
|
12
12
|
**Three layers, one flow.** The panel, a `seller.setup` widget, renders and collects. The vendor seller route carries the value through `additional_data` with no core schema change. A `sellersUpdated` workflow hook persists it. Each layer is additive: nothing built-in is replaced.
|
|
13
13
|
</Info>
|
|
14
14
|
|
|
15
|
+
<Tip>
|
|
16
|
+
To change the onboarding wizard itself (fields on any step, new steps, removed or reordered steps), use `forms` entries with `zone: "onboarding"`. See [Customize the onboarding wizard](/references/panel-extensions/custom-fields#customize-the-onboarding-wizard).
|
|
17
|
+
</Tip>
|
|
18
|
+
|
|
15
19
|
## What you build
|
|
16
20
|
|
|
17
21
|
A "Tax ID" prompt on the vendor store-setup surface. The vendor types a VAT number. It rides `additional_data` to `POST /vendor/sellers/:id`, and a workflow hook stores it durably through the [Custom Fields module](/rc/resources/customization/custom-fields).
|