@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.
- 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/llms.txt +111 -111
- package/package.json +1 -1
|
@@ -1,32 +1,93 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: "
|
|
2
|
+
title: "Payout workflows"
|
|
3
3
|
sidebarTitle: "Workflows"
|
|
4
|
-
description: "
|
|
4
|
+
description: "The 4 payout workflows and 6 payout steps exported from @mercurjs/core/workflows, with their inputs, steps, and hooks."
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
`@mercurjs/core/workflows` and run them against the Medusa container.
|
|
7
|
+
The Payout module ships 4 workflows in `packages/core/src/workflows/payout`. Import them, and their steps, from `@mercurjs/core/workflows`. None of them emits a custom event. Medusa’s data-model events still fire for the records they write, as listed in [Events](/platform/payout/reference/events).
|
|
9
8
|
|
|
10
|
-
##
|
|
9
|
+
## createPayoutAccountWorkflow
|
|
11
10
|
|
|
12
|
-
|
|
11
|
+
Creates a payout account for a seller through the provider and links it to the seller. Workflow id `create-payout-account-for-seller`.
|
|
12
|
+
|
|
13
|
+
| Input | Type | Description |
|
|
14
|
+
| --- | --- | --- |
|
|
15
|
+
| `seller_id` | `string` | Seller to create the account for |
|
|
16
|
+
| `data` | `Record<string, unknown>`, optional | Passed to the provider; Stripe Connect needs `country` |
|
|
17
|
+
| `context` | `PayoutProviderContext`, optional | Provider context, such as `idempotency_key` |
|
|
18
|
+
|
|
19
|
+
Steps, in order:
|
|
20
|
+
|
|
21
|
+
1. `validate-seller-payout-account`: fails with `Seller already has a payout account` when a `seller_payout_account` row exists
|
|
22
|
+
2. `create-payout-account`: calls the service’s `createPayoutAccount`
|
|
23
|
+
3. `create-remote-links`: links the seller and the account
|
|
24
|
+
|
|
25
|
+
Returns the `PayoutAccountDTO`. Exposes no hooks.
|
|
26
|
+
|
|
27
|
+
## createOnboardingWorkflow
|
|
28
|
+
|
|
29
|
+
Creates or updates the onboarding record for a payout account through the provider. Workflow id `create-onboarding`.
|
|
30
|
+
|
|
31
|
+
| Input | Type | Description |
|
|
32
|
+
| --- | --- | --- |
|
|
33
|
+
| `account_id` | `string` | The `pacc` id |
|
|
34
|
+
| `data` | `Record<string, unknown>`, optional | Merged over the account’s `data`; Stripe Connect needs `refresh_url` and `return_url` |
|
|
35
|
+
| `context` | `PayoutProviderContext`, optional | Provider context, stored on the record |
|
|
36
|
+
|
|
37
|
+
It runs one step, `create-onboarding`, and returns the `OnboardingDTO`. Exposes no hooks.
|
|
38
|
+
|
|
39
|
+
## createPayoutWorkflow
|
|
40
|
+
|
|
41
|
+
Pays the seller’s share of one order through the provider. Workflow id `create-payout`, exported as `createPayoutWorkflowId`.
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
const { result } = await createPayoutWorkflow(container).run({
|
|
45
|
+
input: { order_id: "order_01JD8Q1234567" },
|
|
46
|
+
})
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Steps, in order:
|
|
50
|
+
|
|
51
|
+
1. `fetch-order`: loads `total`, `currency_code`, `seller.payout_account`, items, and shipping methods
|
|
52
|
+
2. `fetch-commission-lines`: loads the `commission_line` rows for those items and shipping methods
|
|
53
|
+
3. `create-payout-step`: creates the payout for `total` minus the commission sum, with the order id as `context.idempotency_key`
|
|
54
|
+
4. `create-remote-links`: links the payout to the seller
|
|
55
|
+
|
|
56
|
+
It throws `Seller does not have a payout account` when the seller has none. Returns the `PayoutDTO`.
|
|
57
|
+
|
|
58
|
+
| Hook | Payload | Use it to |
|
|
59
|
+
| --- | --- | --- |
|
|
60
|
+
| `payoutCreated` | `{ order_id, payout_id }` | Link the payout to the order, notify the seller, or sync a ledger |
|
|
61
|
+
|
|
62
|
+
## processPayoutForWebhookWorkflow
|
|
63
|
+
|
|
64
|
+
Applies a parsed provider webhook to an account or a payout. Workflow id `process-payout-for-webhook`, exported as `processPayoutForWebhookWorkflowId`. Its input is a `PayoutWebhookResult`: an `action` and an optional `data.id`.
|
|
65
|
+
|
|
66
|
+
| Action | Step name | Effect |
|
|
13
67
|
| --- | --- | --- |
|
|
14
|
-
| `
|
|
15
|
-
| `
|
|
68
|
+
| `account.activated` | `activate-payout-account` | Account `status` to `active` |
|
|
69
|
+
| `account.restricted` | `restrict-payout-account` | Account `status` to `restricted` |
|
|
70
|
+
| `account.rejected` | `reject-payout-account` | Account `status` to `rejected` |
|
|
71
|
+
| `payout.processing` | `processing-payout` | Payout `status` to `processing` |
|
|
72
|
+
| `payout.paid` | `paid-payout` | Payout `status` to `paid` |
|
|
73
|
+
| `payout.failed` | `failed-payout` | Payout `status` to `failed` |
|
|
74
|
+
| `payout.canceled` | `canceled-payout` | Payout `status` to `canceled` |
|
|
16
75
|
|
|
17
|
-
|
|
76
|
+
Each branch runs only when `data.id` is set. `not_supported` runs no step. Returns nothing and exposes no hooks.
|
|
18
77
|
|
|
19
|
-
|
|
78
|
+
## Steps
|
|
79
|
+
|
|
80
|
+
You can compose these steps into your own workflows:
|
|
81
|
+
|
|
82
|
+
| Step | Id | Compensation |
|
|
20
83
|
| --- | --- | --- |
|
|
21
|
-
| `
|
|
22
|
-
| `
|
|
84
|
+
| `validateSellerPayoutAccountStep` | `validate-seller-payout-account` | None |
|
|
85
|
+
| `createPayoutAccountStep` | `create-payout-account` | None |
|
|
86
|
+
| `createOnboardingStep` | `create-onboarding` | None |
|
|
87
|
+
| `createPayoutStep` | `create-payout-step` | None |
|
|
88
|
+
| `updatePayoutAccountStep` | `update-payout-account-step` | Restores the previous status |
|
|
89
|
+
| `updatePayoutStep` | `update-payout-step` | Restores the previous status |
|
|
23
90
|
|
|
24
91
|
<Note>
|
|
25
|
-
|
|
26
|
-
commission lines, then uses the order id as the transfer's idempotency key so
|
|
27
|
-
a re-run never double-pays.
|
|
92
|
+
The create steps have no compensation. If a later step fails, the account, onboarding record, or payout stays, and the provider-side object stays too. The service only deletes a new row when the provider call itself throws.
|
|
28
93
|
</Note>
|
|
29
|
-
|
|
30
|
-
To work with records directly instead of through a workflow, see the
|
|
31
|
-
[Service reference](/platform/payout/reference/service). For the events that
|
|
32
|
-
drive these workflows, see the [Event reference](/platform/payout/reference/events).
|
|
@@ -1,66 +1,73 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: "
|
|
2
|
+
title: "What a change action records and how it applies"
|
|
3
3
|
sidebarTitle: "Change actions"
|
|
4
|
-
description: "The
|
|
4
|
+
description: "The ProductChangeAction types, the details each one carries, and the order they apply in."
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
modeled.
|
|
7
|
+
A change action is one operation inside a product change: set a field, add a variant, detach an attribute, delete the product. Splitting a change into typed actions lets an operator see exactly what a seller asked for, and lets Mercur apply each operation through the right Medusa workflow when the change is confirmed.
|
|
9
8
|
|
|
10
|
-
##
|
|
9
|
+
## The action record
|
|
11
10
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
field. The operation's payload lives in the `details` JSON, and an `applied`
|
|
16
|
-
boolean records whether it has already been written to the product.
|
|
11
|
+
A `ProductChangeAction` (id prefix `prodchact`) belongs to a parent change through `product_change_id` and targets a `product_id`. Its `action` field names the operation, and its `details` JSON holds the payload. The `applied` boolean starts `false` and flips to `true` once the action has been written to the product.
|
|
12
|
+
|
|
13
|
+
Actions also carry an auto-incrementing `ordering`, plus `reference` and `reference_id` columns. Mercur’s workflows don’t set the reference columns, so you can use them to point an action at a record of your own.
|
|
17
14
|
|
|
18
15
|
```ts
|
|
19
16
|
const action = {
|
|
20
|
-
product_id: "
|
|
21
|
-
action:
|
|
22
|
-
details: { field: "title", value: "
|
|
17
|
+
product_id: "prod_01JD8Q1234567",
|
|
18
|
+
action: ProductChangeActionType.UPDATE,
|
|
19
|
+
details: { field: "title", value: "Linen shirt" },
|
|
23
20
|
}
|
|
24
21
|
```
|
|
25
22
|
|
|
26
|
-
|
|
27
|
-
applies them deterministically.
|
|
23
|
+
This is the shape you pass to `stageProductChangeWorkflow` in its `actions` array. `ProductChangeActionType` is exported from `@mercurjs/types`.
|
|
28
24
|
|
|
29
25
|
## Action types
|
|
30
26
|
|
|
31
|
-
The `action` field
|
|
32
|
-
reads a different shape out of `details`:
|
|
27
|
+
The `action` field takes one of the 11 `ProductChangeActionType` values. The edit workflows also store the previous value in `details`, so a reviewer can see the before and after:
|
|
33
28
|
|
|
34
|
-
| Action | `details`
|
|
29
|
+
| Action | `details` written by Mercur | Applies |
|
|
35
30
|
| --- | --- | --- |
|
|
36
|
-
| `UPDATE` | `{ field, value }` |
|
|
37
|
-
| `STATUS_CHANGE` | `{ status }` |
|
|
38
|
-
| `VARIANT_ADD` | `{ variant }` |
|
|
39
|
-
| `VARIANT_UPDATE` | `{ variant_id, fields }` |
|
|
40
|
-
| `VARIANT_REMOVE` | `{ variant_id }` |
|
|
41
|
-
| `ATTRIBUTE_ADD` | `{ attribute }` |
|
|
42
|
-
| `ATTRIBUTE_UPDATE` | `{ update }` |
|
|
43
|
-
| `ATTRIBUTE_REMOVE` | `{ attribute_id }` |
|
|
44
|
-
| `
|
|
45
|
-
| `
|
|
46
|
-
| `CHANGE_REQUESTED` | `{ message }` |
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
31
|
+
| `UPDATE` | `{ field, value, previous_value }` | Sets one product field |
|
|
32
|
+
| `STATUS_CHANGE` | `{ status, previous_status }` | Sets the product status |
|
|
33
|
+
| `VARIANT_ADD` | `{ variant }` | Creates a variant |
|
|
34
|
+
| `VARIANT_UPDATE` | `{ variant_id, fields, previous_fields }` | Updates a variant and its image links |
|
|
35
|
+
| `VARIANT_REMOVE` | `{ variant_id }` | Deletes a variant |
|
|
36
|
+
| `ATTRIBUTE_ADD` | `{ attribute, attribute_id, previous_value }` | Attaches an attribute |
|
|
37
|
+
| `ATTRIBUTE_UPDATE` | `{ update, attribute_id, value, previous_value }` | Changes an attached attribute |
|
|
38
|
+
| `ATTRIBUTE_REMOVE` | `{ attribute_id, previous_value }` | Detaches an attribute |
|
|
39
|
+
| `PRODUCT_DELETE` | `{}` | Deletes the product and its offers |
|
|
40
|
+
| `PRODUCT_ADD` | `{ status, attribute_ids }` | Nothing: records the product’s creation |
|
|
41
|
+
| `CHANGE_REQUESTED` | `{ message }` | Nothing: records a revision request |
|
|
42
|
+
|
|
43
|
+
`PRODUCT_ADD` and `CHANGE_REQUESTED` only appear on audit changes, which Mercur stores with `applied: true`. See [The change pipeline](/platform/product-edit/concepts/change-pipeline#audit-changes).
|
|
44
|
+
|
|
45
|
+
## What the edit workflows diff
|
|
46
|
+
|
|
47
|
+
The edit workflows stage an action only when your input differs from the product. Arrays of relations compare by id or URL, ignoring order, so resending the same categories stages nothing:
|
|
48
|
+
|
|
49
|
+
- **Product fields**: `title`, `subtitle`, `handle`, `description`, `discountable`, `is_giftcard`, `thumbnail`, `images`, `material`, `weight`, `length`, `height`, `width`, `hs_code`, `mid_code`, `origin_country`, `type_id`, `collection_id`, `categories`, `tags`, `sales_channels`, `metadata`
|
|
50
|
+
- **Status**: a `status` key in the update becomes a `STATUS_CHANGE` action instead of an `UPDATE`
|
|
51
|
+
- **Variants**: `manage_inventory` is skipped on update, and `images` takes `{ add, remove }` image ids
|
|
52
|
+
- **Attributes**: an add the product already holds, or a remove of an attribute it doesn’t hold, stages nothing
|
|
53
|
+
|
|
54
|
+
A key outside the product field list is ignored by `productEditUpdateProductWorkflow`.
|
|
54
55
|
|
|
55
56
|
## How actions apply
|
|
56
57
|
|
|
57
|
-
When a change is confirmed, its
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
When a change is confirmed, `applyProductChangeActionsWorkflow` loads its actions with `applied: false`, groups them by type, and runs each group once. The groups run in this order:
|
|
59
|
+
|
|
60
|
+
1. `STATUS_CHANGE` and `UPDATE`, merged per product into one `updateProductsWorkflow` call
|
|
61
|
+
2. `VARIANT_REMOVE` through `deleteProductVariantsWorkflow`
|
|
62
|
+
3. `VARIANT_ADD` through `createProductVariantsWorkflow`
|
|
63
|
+
4. `VARIANT_UPDATE` scalar fields through `updateProductVariantsWorkflow`, then the variant image links
|
|
64
|
+
5. `ATTRIBUTE_*` as one batch through `createAndLinkProductAttributesToProductWorkflow`
|
|
65
|
+
6. `PRODUCT_DELETE` through `deleteProductsWorkflow`, followed by `deleteOffersWorkflow` for the product’s offers
|
|
66
|
+
|
|
67
|
+
The workflow then marks every action it handled as `applied: true`, so running the apply workflow again on the same change never writes an action twice. Types it doesn’t handle, `PRODUCT_ADD` and `CHANGE_REQUESTED`, keep whatever `applied` value they were stored with.
|
|
68
|
+
|
|
69
|
+
## Related
|
|
61
70
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
itself. They exist purely as history.
|
|
66
|
-
</Tip>
|
|
71
|
+
- [The change lifecycle and auto-confirm](/platform/product-edit/concepts/status-and-auto-confirm)
|
|
72
|
+
- [Stage actions directly](/platform/product-edit/guides/edit-a-product#stage-actions-directly)
|
|
73
|
+
- [The `ProductChangeAction` data model](/platform/product-edit/reference/data-models#productchangeaction)
|
|
@@ -1,69 +1,77 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: "
|
|
2
|
+
title: "How product changes are staged and recorded"
|
|
3
3
|
sidebarTitle: "The change pipeline"
|
|
4
|
-
description: "
|
|
4
|
+
description: "How an edit becomes a ProductChange, who can have one open, and how the audit trail builds up."
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
pipeline is built on immutable records.
|
|
7
|
+
A product change is one reviewable edit to one product. Because every seller sells against the same shared product, a seller’s edit can’t take effect the moment it’s made. Mercur stores the edit as a `ProductChange` with its actions, holds it for review, and applies it only on confirmation. The same records double as the product’s history.
|
|
9
8
|
|
|
10
|
-
##
|
|
9
|
+
## The product change record
|
|
11
10
|
|
|
12
|
-
A product
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
A `ProductChange` (id prefix `prodch`) points at its product through `product_id` and carries a `status` from the `ProductChangeStatus` enum. It owns one or more `ProductChangeAction` rows in `actions`, one per operation it will apply. The change is the unit you review. The actions are what gets written.
|
|
12
|
+
|
|
13
|
+
Each resolution stamps an actor and a time on the record:
|
|
14
|
+
|
|
15
|
+
- **Staging**: `created_by`
|
|
16
|
+
- **Confirm**: `confirmed_by`, `confirmed_at`
|
|
17
|
+
- **Decline**: `declined_by`, `declined_at`, `declined_reason`
|
|
18
|
+
- **Cancel**: `canceled_by`, `canceled_at`
|
|
19
|
+
|
|
20
|
+
The actor fields are plain text. Vendor routes write the seller id (`sel_…`) into `created_by`, and admin routes write the operator’s user id. Two notes travel with the change: `internal_note` for operators and `external_note` for the seller.
|
|
17
21
|
|
|
18
22
|
```ts
|
|
19
|
-
|
|
23
|
+
import { MercurModules } from "@mercurjs/types"
|
|
20
24
|
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
25
|
+
const productEdit = container.resolve(MercurModules.PRODUCT_EDIT)
|
|
26
|
+
|
|
27
|
+
const change = await productEdit.retrieveProductChange(
|
|
28
|
+
"prodch_01JD8Q1234567",
|
|
29
|
+
{ relations: ["actions"] }
|
|
30
|
+
)
|
|
24
31
|
```
|
|
25
32
|
|
|
26
|
-
|
|
27
|
-
is the reviewable unit; the actions are the individual operations it will apply.
|
|
28
|
-
See [Change actions](/platform/product-edit/concepts/change-actions).
|
|
33
|
+
The service call loads one change with its actions. To read a product’s full history, use the `product.changes` link instead, covered in [Links](/platform/product-edit/reference/links).
|
|
29
34
|
|
|
30
|
-
|
|
31
|
-
A product can have **only one active (pending) change at a time**. Staging a
|
|
32
|
-
new change while one is still pending is rejected. The vendor resolves or
|
|
33
|
-
cancels the open change first.
|
|
34
|
-
</Note>
|
|
35
|
+
## How an edit is staged
|
|
35
36
|
|
|
36
|
-
|
|
37
|
+
Seller edits reach the pipeline through four edit workflows. Each one loads the current product, compares your input against it, and passes only the differences to `stageProductChangeWorkflow`:
|
|
37
38
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
- **`productEditUpdateProductWorkflow`**: product fields and status, as `UPDATE` and `STATUS_CHANGE` actions
|
|
40
|
+
- **`productEditUpdateVariantsWorkflow`**: variant add, update, and remove operations, as `VARIANT_*` actions
|
|
41
|
+
- **`productEditUpdateAttributesWorkflow`**: attribute add, update, and remove, as `ATTRIBUTE_*` actions
|
|
42
|
+
- **`productEditDeleteProductWorkflow`**: a single `PRODUCT_DELETE` action
|
|
42
43
|
|
|
43
|
-
|
|
44
|
-
request. They still belong in the history. Those are recorded as changes created
|
|
45
|
-
already `confirmed`, so the audit trail captures them without waiting on review.
|
|
44
|
+
`stageProductChangeWorkflow` creates the `pending` change, creates its actions, emits `product-change.created`, and then runs `autoConfirmProductChangeWorkflow`. Whether the change confirms in that same run is covered in [Status & auto-confirm](/platform/product-edit/concepts/status-and-auto-confirm).
|
|
46
45
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
46
|
+
## One open change per author
|
|
47
|
+
|
|
48
|
+
The edit workflows and `createProductChangeWorkflow` refuse to stage a change when the same author already has a `pending` change on that product. The check is scoped by `created_by`, so two different sellers can each have one open change on the same shared product. When `created_by` is missing, the check covers every pending change on the product.
|
|
49
|
+
|
|
50
|
+
<Warning>
|
|
51
|
+
`stageProductChangeWorkflow` doesn’t run this check. Call it directly only when you’ve handled conflicts yourself, or prefer an edit workflow.
|
|
52
|
+
</Warning>
|
|
53
|
+
|
|
54
|
+
The conflict surfaces as a `NOT_ALLOWED` error: “There is already an active update request for this product. Only one request can be active at a time.” The author resolves it by canceling the open change or waiting for an operator to resolve it.
|
|
55
|
+
|
|
56
|
+
## Audit changes
|
|
57
|
+
|
|
58
|
+
Some events change a product without a review, yet still belong in its history. `recordProductAuditChangeWorkflow` stores them as changes created already `confirmed`, with every action marked `applied`, so confirming never replays them. Mercur’s product workflows call it in four places:
|
|
59
|
+
|
|
60
|
+
| Workflow | Action recorded | `details` |
|
|
61
|
+
| --- | --- | --- |
|
|
62
|
+
| `createProductsWorkflow` | `PRODUCT_ADD` | `{ status, attribute_ids }` |
|
|
63
|
+
| `confirmProductsWorkflow` | `STATUS_CHANGE` | `{ status: "published" }` |
|
|
64
|
+
| `rejectProductWorkflow` | `STATUS_CHANGE` | `{ status: "rejected" }` |
|
|
65
|
+
| `requestProductChangeWorkflow` | `CHANGE_REQUESTED` | `{ message }` |
|
|
66
|
+
|
|
67
|
+
The `PRODUCT_ADD` record does real work: its `created_by` is the seller who submitted the product, and the vendor API reads it to tell which products a seller created.
|
|
68
|
+
|
|
69
|
+
<Note>
|
|
70
|
+
Operator edits through the admin product update route run Medusa’s `updateProductsWorkflow` directly and don’t create a change. The pipeline governs seller edits.
|
|
71
|
+
</Note>
|
|
72
|
+
|
|
73
|
+
## Related
|
|
63
74
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
querying the module directly. The link keeps the audit trail attached to the
|
|
68
|
-
product.
|
|
69
|
-
</Tip>
|
|
75
|
+
- [The action types and their `details`](/platform/product-edit/concepts/change-actions)
|
|
76
|
+
- [Statuses, revision requests, and auto-confirm](/platform/product-edit/concepts/status-and-auto-confirm)
|
|
77
|
+
- [Stage an edit from your own route](/platform/product-edit/guides/edit-a-product)
|
|
@@ -1,66 +1,63 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: "
|
|
2
|
+
title: "Change statuses, revision requests, and auto-confirm"
|
|
3
3
|
sidebarTitle: "Status & auto-confirm"
|
|
4
|
-
description: "The
|
|
4
|
+
description: "The four ProductChangeStatus values, how a revision request fits in, and when a change confirms without review."
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
it resolves without operator review.
|
|
7
|
+
Every product change has a status that says whether it’s waiting for review or already resolved. A change starts `pending` and is resolved exactly once: confirmed, declined, or canceled. Whether a seller’s edit waits for an operator at all depends on the `product_request` feature flag and on the `auto_confirm` input.
|
|
9
8
|
|
|
10
|
-
##
|
|
9
|
+
## The status lifecycle
|
|
11
10
|
|
|
12
|
-
|
|
13
|
-
typed by the `ProductChangeStatus` enum. A change moves through four statuses:
|
|
11
|
+
The `status` field takes one of the four `ProductChangeStatus` values, exported from `@mercurjs/types`. Each resolution has its own workflow, which checks that the change is still `pending`, stamps the actor field, and emits an event.
|
|
14
12
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
└───────────┘ └──────────┘ └──────────┘
|
|
25
|
-
```
|
|
13
|
+
<img className="block dark:hidden" src="/images/figures/product-edit-lifecycle-light.svg" alt="The ProductChangeStatus table: a change enters pending through stageProductChangeWorkflow, then confirmProductChangeWorkflow, rejectProductChangeWorkflow, or cancelProductChangeWorkflow moves it to confirmed, declined, or canceled, each emitting its own event and stamping its own actor field." />
|
|
14
|
+
<img className="hidden dark:block" src="/images/figures/product-edit-lifecycle-dark.svg" alt="The ProductChangeStatus table: a change enters pending through stageProductChangeWorkflow, then confirmProductChangeWorkflow, rejectProductChangeWorkflow, or cancelProductChangeWorkflow moves it to confirmed, declined, or canceled, each emitting its own event and stamping its own actor field." />
|
|
15
|
+
|
|
16
|
+
| Status | Meaning | Product touched |
|
|
17
|
+
| --- | --- | --- |
|
|
18
|
+
| `pending` | Staged and waiting for review. The default | No |
|
|
19
|
+
| `confirmed` | Approved, or recorded as an audit change | Yes, its actions are applied |
|
|
20
|
+
| `declined` | Rejected by an operator, with an optional `declined_reason` | No |
|
|
21
|
+
| `canceled` | Withdrawn, by the seller or an operator, before review | No |
|
|
26
22
|
|
|
27
|
-
|
|
28
|
-
| --- | --- |
|
|
29
|
-
| `pending` | Awaiting operator review. The default for a staged edit |
|
|
30
|
-
| `confirmed` | Approved; its actions are applied to the product |
|
|
31
|
-
| `declined` | Rejected by the operator; nothing is applied |
|
|
32
|
-
| `canceled` | Withdrawn (e.g. by the vendor) before review |
|
|
23
|
+
Confirming, declining, or canceling a change that isn’t `pending` fails with a `NOT_ALLOWED` error. Each resolution step saves the previous values, so if a later step fails, the workflow restores the change to `pending`.
|
|
33
24
|
|
|
34
25
|
<Note>
|
|
35
|
-
|
|
36
|
-
resolution workflows validate the current status first, so a change is
|
|
37
|
-
resolved exactly once.
|
|
26
|
+
The model also has `requires_action_by`, `requires_action_at`, and `requires_action_reason` columns, but `ProductChangeStatus` has no `requires_action` value and no workflow writes those columns.
|
|
38
27
|
</Note>
|
|
39
28
|
|
|
40
29
|
## Revision requests
|
|
41
30
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
`product.change-requested`. The product stays with the vendor to revise and
|
|
46
|
-
resubmit. A revision request is a signal in the audit trail, not a fourth
|
|
47
|
-
resolution of the pending change.
|
|
31
|
+
A revision request sends a proposed product back to its seller without approving or rejecting it. `requestProductChangeWorkflow` checks that the product status is `proposed`, records an audit change with a `CHANGE_REQUESTED` action, and emits `product.change-requested`. The product stays `proposed` for the seller to revise.
|
|
32
|
+
|
|
33
|
+
A revision request isn’t a fifth status, and it doesn’t resolve any pending change. It’s an already-`confirmed` entry in the product’s history. The operator’s message is stored twice: in the action’s `details.message` and in the change’s `external_note`.
|
|
48
34
|
|
|
49
35
|
## Auto-confirm
|
|
50
36
|
|
|
51
|
-
Staging
|
|
52
|
-
|
|
37
|
+
Staging always runs `autoConfirmProductChangeWorkflow` right after the change is created. It runs `confirmProductChangeWorkflow` in the same workflow run when either condition holds:
|
|
38
|
+
|
|
39
|
+
- **The flag is off**: the `product_request` feature flag is disabled
|
|
40
|
+
- **Forced**: the caller passed `auto_confirm: true`, which reaches the workflow as `force`
|
|
41
|
+
|
|
42
|
+
Otherwise the change stays `pending`. The flag is on by default. Turn it off with an environment variable:
|
|
43
|
+
|
|
44
|
+
```bash title=".env"
|
|
45
|
+
MEDUSA_FF_PRODUCT_REQUEST=false
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
With the flag off, every seller edit applies immediately and still leaves a confirmed change in the trail. The same flag also controls product creation: while it’s on, a seller can only create products as `draft` or `proposed`.
|
|
49
|
+
|
|
50
|
+
## When Mercur forces auto-confirm
|
|
51
|
+
|
|
52
|
+
There’s no risk scoring: Mercur doesn’t classify edits as low or high risk. It forces auto-confirm in two places:
|
|
53
|
+
|
|
54
|
+
- **Draft deletes**: `productEditDeleteProductWorkflow` defaults `auto_confirm` to `true` when the product is a `draft`
|
|
55
|
+
- **Operator deletes**: the admin product delete route always passes `auto_confirm: true`
|
|
53
56
|
|
|
54
|
-
-
|
|
55
|
-
low-friction edits don't wait for an operator.
|
|
56
|
-
- **Review on:** the change stays `pending` for an operator to resolve.
|
|
57
|
+
An auto-confirmed change goes through the same `confirmProductChangeWorkflow` as a manual approval. It emits `product-change.confirmed` and fires the same hooks, with `confirmed_by` set to the change’s author.
|
|
57
58
|
|
|
58
|
-
|
|
59
|
-
trusted-source import) via the `auto_confirm` flag on the staging workflow,
|
|
60
|
-
regardless of the review setting.
|
|
59
|
+
## Related
|
|
61
60
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
an operator approves by hand.
|
|
66
|
-
</Tip>
|
|
61
|
+
- [Confirm, decline, or cancel a change in code](/platform/product-edit/guides/confirm-or-decline-a-change)
|
|
62
|
+
- [Request a revision](/platform/product-edit/guides/request-a-revision)
|
|
63
|
+
- [The events each transition emits](/platform/product-edit/reference/events)
|