Skip to content

Commit 18e02fb

Browse files
authored
feat(core-flows,dashboard,js-sdk, medusa,types,utils): support notification preferences for order edits (#16238)
* feat(core-flows,dashboard,js-sdk, medusa,types,utils): support no_notification when requesting an order edit * store notification + add it to confirm event * change changeset
1 parent 11d58f7 commit 18e02fb

24 files changed

Lines changed: 211 additions & 12 deletions

File tree

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
"@medusajs/core-flows": patch
3+
"@medusajs/dashboard": patch
4+
"@medusajs/js-sdk": minor
5+
"@medusajs/medusa": patch
6+
"@medusajs/order": patch
7+
"@medusajs/types": patch
8+
"@medusajs/utils": patch
9+
---
10+
11+
feat(core-flows,dashboard,js-sdk, medusa,types,utils): support notification preferences for order edits

CLAUDE.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,14 @@ yarn test:integration:api
6666
yarn test:integration:modules
6767
```
6868

69+
**Generated Files:**
70+
71+
After adding or removing keys in `packages/admin/dashboard/src/i18n/translations/en.json`, regenerate the JSON schema that validates all translation files:
72+
```bash
73+
cd packages/admin/dashboard && yarn i18n:schema
74+
```
75+
Skipping this leaves `Property <key> is not allowed` warnings on `en.json`, since `translations/$schema.json` is generated from `en.json` and lists every key in both `properties` and `required`. Commit the regenerated `$schema.json` with the translation change.
76+
6977
### 3. Testing Conventions
7078

7179
**Frameworks:**

integration-tests/http/__tests__/order-edits/order-edits.spec.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
ContainerRegistrationKeys,
55
Modules,
66
OrderChangeStatus,
7+
OrderEditWorkflowEvents,
78
ProductStatus,
89
PromotionStatus,
910
PromotionType,
@@ -1083,6 +1084,81 @@ medusaIntegrationTestRunner({
10831084
OrderChangeStatus.CONFIRMED
10841085
)
10851086
})
1087+
1088+
it("should store no_notification on the order change and pass it to the order edit events", async () => {
1089+
const eventBus = container.resolve(Modules.EVENT_BUS)
1090+
const requestedSubscriber = jest.fn()
1091+
const confirmedSubscriber = jest.fn()
1092+
1093+
eventBus.subscribe(
1094+
OrderEditWorkflowEvents.REQUESTED,
1095+
requestedSubscriber
1096+
)
1097+
eventBus.subscribe(
1098+
OrderEditWorkflowEvents.CONFIRMED,
1099+
confirmedSubscriber
1100+
)
1101+
1102+
const orderId = order.id
1103+
1104+
await api.post(
1105+
"/admin/order-edits",
1106+
{ order_id: orderId, description: "Test" },
1107+
adminHeaders
1108+
)
1109+
1110+
await api.post(
1111+
`/admin/order-edits/${orderId}/shipping-method`,
1112+
{ shipping_option_id: shippingOption.id, custom_amount: 5 },
1113+
adminHeaders
1114+
)
1115+
1116+
const requestResult = await api.post(
1117+
`/admin/order-edits/${orderId}/request`,
1118+
{ no_notification: true },
1119+
adminHeaders
1120+
)
1121+
1122+
expect(requestResult.data.order_preview.order_change).toEqual(
1123+
expect.objectContaining({ no_notification: true })
1124+
)
1125+
1126+
await api.post(
1127+
`/admin/order-edits/${orderId}/confirm`,
1128+
{},
1129+
adminHeaders
1130+
)
1131+
1132+
const orderChangesResult = await api.get(
1133+
`/admin/orders/${orderId}/changes?change_type=edit`,
1134+
adminHeaders
1135+
)
1136+
1137+
expect(orderChangesResult.data.order_changes[0]).toEqual(
1138+
expect.objectContaining({ no_notification: true })
1139+
)
1140+
1141+
await new Promise((resolve) => setTimeout(resolve, 100))
1142+
1143+
expect(requestedSubscriber.mock.calls[0][0].data).toMatchObject({
1144+
order_id: orderId,
1145+
no_notification: true,
1146+
})
1147+
1148+
expect(confirmedSubscriber.mock.calls[0][0].data).toMatchObject({
1149+
order_id: orderId,
1150+
no_notification: true,
1151+
})
1152+
1153+
eventBus.unsubscribe(
1154+
OrderEditWorkflowEvents.REQUESTED,
1155+
requestedSubscriber
1156+
)
1157+
eventBus.unsubscribe(
1158+
OrderEditWorkflowEvents.CONFIRMED,
1159+
confirmedSubscriber
1160+
)
1161+
})
10861162
})
10871163

10881164
describe("Order Edit Payment Collection", () => {

packages/admin/dashboard/src/hooks/api/order-edits.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,12 @@ export const useRequestOrderEdit = (
3939
options?: UseMutationOptions<
4040
HttpTypes.AdminOrderEditPreviewResponse,
4141
FetchError,
42-
void
42+
HttpTypes.AdminRequestOrderEdit
4343
>
4444
) => {
4545
return useMutation({
46-
mutationFn: () => sdk.admin.orderEdit.request(id),
46+
mutationFn: (payload: HttpTypes.AdminRequestOrderEdit) =>
47+
sdk.admin.orderEdit.request(id, payload),
4748
onSuccess: (data: any, variables: any, context: any) => {
4849
queryClient.invalidateQueries({
4950
queryKey: ordersQueryKeys.details(),

packages/admin/dashboard/src/i18n/translations/$schema.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5123,6 +5123,12 @@
51235123
"noteHint": {
51245124
"type": "string"
51255125
},
5126+
"sendNotification": {
5127+
"type": "string"
5128+
},
5129+
"sendNotificationHint": {
5130+
"type": "string"
5131+
},
51265132
"cancelSuccessToast": {
51275133
"type": "string"
51285134
},
@@ -5184,6 +5190,8 @@
51845190
"create",
51855191
"currentTotal",
51865192
"noteHint",
5193+
"sendNotification",
5194+
"sendNotificationHint",
51875195
"cancelSuccessToast",
51885196
"createSuccessToast",
51895197
"activeChangeError",

packages/admin/dashboard/src/i18n/translations/en.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1315,6 +1315,8 @@
13151315
"create": "Edit Order",
13161316
"currentTotal": "Current total",
13171317
"noteHint": "Add an internal note for the edit",
1318+
"sendNotification": "Send notification",
1319+
"sendNotificationHint": "Notify the customer about this order edit.",
13181320
"cancelSuccessToast": "Order edit canceled",
13191321
"createSuccessToast": "Order edit request created",
13201322
"activeChangeError": "There is already active order change on the order (return, claim, exchange etc.). Please finish or cancel the change before editing the order.",

packages/admin/dashboard/src/routes/orders/order-create-edit/components/order-edit-create-form/order-edit-create-form.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ export const OrderEditCreateForm = ({
5555
defaultValues: () => {
5656
return Promise.resolve({
5757
note: "",
58-
send_notification: false, // TODO: not supported in the API ATM
58+
send_notification: false,
5959
})
6060
},
6161
resolver: zodResolver(OrderEditCreateSchema),
@@ -81,7 +81,7 @@ export const OrderEditCreateForm = ({
8181
await updateOrderChange({ internal_note: data.note })
8282
}
8383

84-
await requestOrderEdit()
84+
await requestOrderEdit({ no_notification: !data.send_notification })
8585

8686
toast.success(t("orders.edits.createSuccessToast"))
8787
handleSuccess()
@@ -198,10 +198,10 @@ export const OrderEditCreateForm = ({
198198
</Form.Control>
199199
<div className="block">
200200
<Form.Label>
201-
{t("orders.returns.sendNotification")}
201+
{t("orders.edits.sendNotification")}
202202
</Form.Label>
203203
<Form.Hint className="!mt-1">
204-
{t("orders.returns.sendNotificationHint")}
204+
{t("orders.edits.sendNotificationHint")}
205205
</Form.Hint>
206206
</div>
207207
</div>

packages/core/core-flows/src/order/workflows/order-edit/confirm-order-edit-request.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ export const confirmOrderEditRequestWorkflow = createWorkflow(
152152
fields: [
153153
"id",
154154
"status",
155+
"no_notification",
155156
"actions.id",
156157
"actions.order_id",
157158
"actions.return_id",
@@ -319,6 +320,7 @@ export const confirmOrderEditRequestWorkflow = createWorkflow(
319320
return {
320321
order_id: order.id,
321322
actions: orderChange.actions,
323+
no_notification: orderChange.no_notification,
322324
}
323325
}
324326
)

packages/core/core-flows/src/order/workflows/order-edit/request-order-edit.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ function getOrderChangesData({
2727
input,
2828
orderChange,
2929
}: {
30-
input: { requested_by?: string }
30+
input: { requested_by?: string; no_notification?: boolean }
3131
orderChange: { id: string }
3232
}) {
3333
return transform({ input, orderChange }, ({ input, orderChange }) => {
@@ -37,6 +37,7 @@ function getOrderChangesData({
3737
status: OrderChangeStatus.REQUESTED,
3838
requested_at: new Date(),
3939
requested_by: input.requested_by,
40+
no_notification: input.no_notification,
4041
},
4142
]
4243
})
@@ -102,6 +103,15 @@ export type OrderEditRequestWorkflowInput = {
102103
* The ID of the user requesting the edit.
103104
*/
104105
requested_by?: string
106+
/**
107+
* Whether to prevent sending the customer a notification about the order edit.
108+
* The value is stored on the order change and passed to the emitted
109+
* `order-edit.requested` event, allowing subscribers to check it before sending
110+
* a notification.
111+
*
112+
* @since 2.19.0
113+
*/
114+
no_notification?: boolean
105115
}
106116

107117
export const requestOrderEditRequestWorkflowId = "order-edit-request"
@@ -173,11 +183,12 @@ export const requestOrderEditRequestWorkflow = createWorkflow(
173183
updateOrderChangesStep(updateOrderChangesData)
174184

175185
const eventData = transform(
176-
{ order, orderChange },
177-
({ order, orderChange }) => {
186+
{ input, order, orderChange },
187+
({ input, order, orderChange }) => {
178188
return {
179189
order_id: order.id,
180190
actions: orderChange.actions,
191+
no_notification: input.no_notification,
181192
}
182193
}
183194
)

packages/core/js-sdk/src/admin/order-edit.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,18 +54,22 @@ export class OrderEdit {
5454
* API route.
5555
*
5656
* @param id - The ID of the order that is being edited.
57+
* @param body - The order edit request's details.
5758
* @param query - Configure the fields to retrieve in the order preview.
5859
* @param headers - Headers to pass in the request.
5960
* @returns The order preview's details.
6061
*
6162
* @example
62-
* sdk.admin.orderEdit.request("order_123")
63+
* sdk.admin.orderEdit.request("order_123", {
64+
* no_notification: false
65+
* })
6366
* .then(({ order_preview }) => {
6467
* console.log(order_preview)
6568
* })
6669
*/
6770
async request(
6871
id: string,
72+
body?: HttpTypes.AdminRequestOrderEdit,
6973
query?: HttpTypes.SelectParams,
7074
headers?: ClientHeaders
7175
) {
@@ -74,6 +78,7 @@ export class OrderEdit {
7478
{
7579
method: "POST",
7680
headers,
81+
body,
7782
query,
7883
}
7984
)

0 commit comments

Comments
 (0)