order-management 0.0.94 → 0.0.96
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/.medusa/server/src/admin/index.js +212 -212
- package/.medusa/server/src/admin/index.mjs +212 -212
- package/.medusa/server/src/api/admin/payment-transactions/validators.js +2 -2
- package/.medusa/server/src/api/admin/refund-payment-mapping/validators.js +2 -2
- package/.medusa/server/src/api/admin/refunds/validators.js +2 -2
- package/.medusa/server/src/api/admin/return/[id]/reject/route.js +2 -2
- package/.medusa/server/src/api/admin/return/validators.js +2 -2
- package/.medusa/server/src/api/admin/swaps/validators.js +2 -2
- package/.medusa/server/src/api/middlewares/block-refund-until-return-received.js +141 -42
- package/.medusa/server/src/api/middlewares.js +11 -5
- package/.medusa/server/src/api/store/guest-orders/[id]/returns/route.js +2 -2
- package/.medusa/server/src/api/store/guest-orders/[id]/swaps/route.js +2 -2
- package/.medusa/server/src/api/store/payment-details/validators.js +2 -2
- package/.medusa/server/src/api/store/returns/validators.js +2 -2
- package/.medusa/server/src/api/store/swaps/route.js +2 -2
- package/.medusa/server/src/api/store/validators/cancel-order.js +2 -2
- package/.medusa/server/src/helpers/refund-receive-guard.js +102 -1
- package/README.md +2 -2
- package/package.json +5 -3
|
@@ -1,17 +1,64 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.refundBlockedByReturnMessage = refundBlockedByReturnMessage;
|
|
4
|
+
exports.refundBlockedByExchangeMessage = refundBlockedByExchangeMessage;
|
|
5
|
+
exports.refundBlockedByWalletSettleMessage = refundBlockedByWalletSettleMessage;
|
|
6
|
+
exports.refundBlockedOrderUnresolvedMessage = refundBlockedOrderUnresolvedMessage;
|
|
7
|
+
exports.isWalletSettleOrderTransaction = isWalletSettleOrderTransaction;
|
|
8
|
+
exports.isWalletSettlePaymentRefund = isWalletSettlePaymentRefund;
|
|
9
|
+
exports.orderHasWalletSettle = orderHasWalletSettle;
|
|
4
10
|
exports.getUnreceivedReturnBlockingRefund = getUnreceivedReturnBlockingRefund;
|
|
11
|
+
exports.shouldBlockRefundForRma = shouldBlockRefundForRma;
|
|
5
12
|
exports.assertReturnReceivedForRefund = assertReturnReceivedForRefund;
|
|
6
13
|
exports.canProcessRefundForReturn = canProcessRefundForReturn;
|
|
7
14
|
const utils_1 = require("@medusajs/framework/utils");
|
|
8
15
|
const return_exchange_guard_1 = require("./return-exchange-guard");
|
|
16
|
+
const WALLET_SETTLE_REFERENCE_PREFIXES = [
|
|
17
|
+
"wallet:exchange:",
|
|
18
|
+
"wallet:return:",
|
|
19
|
+
"wallet:payment:",
|
|
20
|
+
];
|
|
9
21
|
/**
|
|
10
22
|
* Message when a refund is attempted before the return is fully received.
|
|
11
23
|
*/
|
|
12
24
|
function refundBlockedByReturnMessage(status) {
|
|
13
25
|
return `Cannot process a refund while the return is ${status}. Receive the returned items first.`;
|
|
14
26
|
}
|
|
27
|
+
function refundBlockedByExchangeMessage() {
|
|
28
|
+
return "Cannot process a refund while an exchange is in progress. Receive the returned items first.";
|
|
29
|
+
}
|
|
30
|
+
function refundBlockedByWalletSettleMessage() {
|
|
31
|
+
return "Cannot process a payment refund; this order was already settled to the customer wallet.";
|
|
32
|
+
}
|
|
33
|
+
function refundBlockedOrderUnresolvedMessage() {
|
|
34
|
+
return "Cannot process a refund: unable to resolve the order for this payment. Verify the payment is linked to an order.";
|
|
35
|
+
}
|
|
36
|
+
function isWalletSettleOrderTransaction(tx) {
|
|
37
|
+
if ((tx.reference ?? "").trim() !== "refund") {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
const refId = (tx.reference_id ?? "").trim();
|
|
41
|
+
return WALLET_SETTLE_REFERENCE_PREFIXES.some((prefix) => refId.startsWith(prefix));
|
|
42
|
+
}
|
|
43
|
+
function isWalletSettlePaymentRefund(refund) {
|
|
44
|
+
if (refund.created_by === "wallet_settle") {
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
if (refund.metadata?.wallet_settle === true) {
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
const note = refund.note ?? "";
|
|
51
|
+
return note.startsWith("wallet_settle:");
|
|
52
|
+
}
|
|
53
|
+
function orderHasWalletSettle(input) {
|
|
54
|
+
if ((input.orderTransactions ?? []).some(isWalletSettleOrderTransaction)) {
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
if ((input.paymentRefunds ?? []).some(isWalletSettlePaymentRefund)) {
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
15
62
|
/**
|
|
16
63
|
* First unreceived return that must block a refund (`open` | `requested` | `partially_received`).
|
|
17
64
|
* Exchange-linked returns are included — refunds are blocked until items are received.
|
|
@@ -24,6 +71,60 @@ function getUnreceivedReturnBlockingRefund(returns) {
|
|
|
24
71
|
}
|
|
25
72
|
return null;
|
|
26
73
|
}
|
|
74
|
+
/**
|
|
75
|
+
* Whether admin payment refund should be blocked for open RMA or prior wallet settle.
|
|
76
|
+
*/
|
|
77
|
+
function shouldBlockRefundForRma(input) {
|
|
78
|
+
if (orderHasWalletSettle({
|
|
79
|
+
orderTransactions: input.orderTransactions,
|
|
80
|
+
paymentRefunds: input.paymentRefunds,
|
|
81
|
+
})) {
|
|
82
|
+
return {
|
|
83
|
+
blocked: true,
|
|
84
|
+
reason: "wallet_settle",
|
|
85
|
+
message: refundBlockedByWalletSettleMessage(),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
const blockingReturn = getUnreceivedReturnBlockingRefund(input.returns);
|
|
89
|
+
if (blockingReturn) {
|
|
90
|
+
return {
|
|
91
|
+
blocked: true,
|
|
92
|
+
reason: "return",
|
|
93
|
+
message: refundBlockedByReturnMessage(blockingReturn.status ?? "requested"),
|
|
94
|
+
returnId: blockingReturn.id,
|
|
95
|
+
status: blockingReturn.status ?? undefined,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
for (const exchange of input.exchanges) {
|
|
99
|
+
let linked = exchange.return ?? null;
|
|
100
|
+
if (!linked && exchange.return_id) {
|
|
101
|
+
linked =
|
|
102
|
+
input.returns.find((r) => r.id === exchange.return_id) ?? null;
|
|
103
|
+
}
|
|
104
|
+
const linkedForGuard = linked
|
|
105
|
+
? {
|
|
106
|
+
id: linked.id,
|
|
107
|
+
status: linked.status ?? undefined,
|
|
108
|
+
exchange_id: linked.exchange_id,
|
|
109
|
+
}
|
|
110
|
+
: null;
|
|
111
|
+
if ((0, return_exchange_guard_1.isActiveExchange)({
|
|
112
|
+
id: exchange.id,
|
|
113
|
+
canceled_at: exchange.canceled_at,
|
|
114
|
+
return_id: exchange.return_id,
|
|
115
|
+
return: linkedForGuard,
|
|
116
|
+
}, linkedForGuard)) {
|
|
117
|
+
return {
|
|
118
|
+
blocked: true,
|
|
119
|
+
reason: "exchange",
|
|
120
|
+
message: refundBlockedByExchangeMessage(),
|
|
121
|
+
exchangeId: exchange.id,
|
|
122
|
+
status: linked?.status ?? undefined,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return { blocked: false };
|
|
127
|
+
}
|
|
27
128
|
/**
|
|
28
129
|
* Throw NOT_ALLOWED when this return is still unreceived.
|
|
29
130
|
* No return / already received / canceled → allow.
|
|
@@ -45,4 +146,4 @@ function canProcessRefundForReturn(input) {
|
|
|
45
146
|
Boolean(input.has_mapping) &&
|
|
46
147
|
!input.is_refunded);
|
|
47
148
|
}
|
|
48
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
149
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVmdW5kLXJlY2VpdmUtZ3VhcmQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvaGVscGVycy9yZWZ1bmQtcmVjZWl2ZS1ndWFyZC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQWtEQSxvRUFFQztBQUVELHdFQUVDO0FBRUQsZ0ZBRUM7QUFFRCxrRkFFQztBQUVELHdFQVVDO0FBRUQsa0VBV0M7QUFFRCxvREFXQztBQU1ELDhFQVNDO0FBS0QsMERBbUVDO0FBTUQsc0VBYUM7QUFLRCw4REFVQztBQS9ORCxxREFBdUQ7QUFDdkQsbUVBR2dDO0FBcUNoQyxNQUFNLGdDQUFnQyxHQUFHO0lBQ3ZDLGtCQUFrQjtJQUNsQixnQkFBZ0I7SUFDaEIsaUJBQWlCO0NBQ1QsQ0FBQTtBQUVWOztHQUVHO0FBQ0gsU0FBZ0IsNEJBQTRCLENBQUMsTUFBYztJQUN6RCxPQUFPLCtDQUErQyxNQUFNLHFDQUFxQyxDQUFBO0FBQ25HLENBQUM7QUFFRCxTQUFnQiw4QkFBOEI7SUFDNUMsT0FBTyw2RkFBNkYsQ0FBQTtBQUN0RyxDQUFDO0FBRUQsU0FBZ0Isa0NBQWtDO0lBQ2hELE9BQU8seUZBQXlGLENBQUE7QUFDbEcsQ0FBQztBQUVELFNBQWdCLG1DQUFtQztJQUNqRCxPQUFPLGtIQUFrSCxDQUFBO0FBQzNILENBQUM7QUFFRCxTQUFnQiw4QkFBOEIsQ0FDNUMsRUFBa0M7SUFFbEMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxTQUFTLElBQUksRUFBRSxDQUFDLENBQUMsSUFBSSxFQUFFLEtBQUssUUFBUSxFQUFFLENBQUM7UUFDN0MsT0FBTyxLQUFLLENBQUE7SUFDZCxDQUFDO0lBQ0QsTUFBTSxLQUFLLEdBQUcsQ0FBQyxFQUFFLENBQUMsWUFBWSxJQUFJLEVBQUUsQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFBO0lBQzVDLE9BQU8sZ0NBQWdDLENBQUMsSUFBSSxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FDdEQsS0FBSyxDQUFDLFVB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
|
package/README.md
CHANGED
|
@@ -245,7 +245,6 @@ curl "http://localhost:9000/admin/orders/order_123/refund-context" \
|
|
|
245
245
|
| Swaps routes | `/swaps`, `/swaps/:id` | Exchange listing/detail pages | Search, filters, reject/cancel exchange; uses `/admin/swaps*`. |
|
|
246
246
|
| Payments routes | `/payments`, `/payments/:id` | Transaction list + detail pages | Filter transactions and inspect gateway payload. |
|
|
247
247
|
| Refunds routes | `/refunds`, `/refunds/:id` | Refund list + detail pages | Filter by status/provider/date/amount; view computed refund context. |
|
|
248
|
-
| `order-refund-context-widget` | `order.details.after` | Refund context panel | Order checkout payment method (including guest orders), refund calculation (product amount, return charge, processed final refund), edit refund mode/details/images, upload images, mark refunded. |
|
|
249
248
|
| `order-gift-items-widget` | `order.details.side.after` | Gift item widget | Reads gift metadata and downloads generated gift card image. |
|
|
250
249
|
|
|
251
250
|
## Models & Entities
|
|
@@ -271,6 +270,7 @@ curl "http://localhost:9000/admin/orders/order_123/refund-context" \
|
|
|
271
270
|
| OTP request fails with template/config message | Missing `email.otpTemplate` or unresolved plugin options | Configure plugin options in `medusa-config.ts`; verify template path exists. |
|
|
272
271
|
| Guest JWT endpoints return unauthorized | Invalid/expired token or `jwtSecret` mismatch | Re-run OTP verify and ensure same `jwtSecret` is used in runtime config. |
|
|
273
272
|
| Store cancel returns generic `An error occurred` | Workflow failure was wrapped and not unwrapped by the cancel route | Upgrade this plugin. Nested Medusa/workflow errors are now unwrapped into a real `message`. Check payment refund/void logs if cancel still fails. |
|
|
273
|
+
| Backend fails to start: `Package subpath './zod' is not defined` in `@medusajs/framework` | Validators imported `@medusajs/framework/zod`, which older framework builds do not export | Upgrade to `order-management` ≥ `0.0.95` (validators import `zod` directly). |
|
|
274
274
|
| Cancel blocked by open fulfillments on a “not fulfilled” order | Core cancel requires all fulfillments to have `canceled_at` | Upgrade this plugin. Unshipped open fulfillments are canceled automatically before core cancel. |
|
|
275
275
|
| Return/exchange blocked with `RETURN_WINDOW_EXPIRED` | Delivery date outside configured window | Increase `returnValidInDays`/`exchangeValidInDays` or update storefront UX for expiry handling. |
|
|
276
276
|
| Refund mapping routes fail | `refund-payment-mapping` module not registered/migrated | Register module and run migrations. |
|
|
@@ -591,7 +591,7 @@ The plugin includes a `refund_payment_mapping` module: one row per return linkin
|
|
|
591
591
|
- `PUT /admin/refund-payment-mapping/:return_id` — update admin-only fields. Body: `{ refund_mode?: "offline" | "online" | null, images?: string[], details?: string | null }` (partial; only provided keys are updated).
|
|
592
592
|
- `POST /admin/refund-payment-mapping/:return_id/mark-refunded` — set `is_refunded = true` (idempotent). Requires Medusa return status `received`; otherwise `400 NOT_ALLOWED`. Already-refunded mappings still succeed without re-checking receive status.
|
|
593
593
|
- **Receive-before-refund guard**: Middleware on Medusa core `POST /admin/payments/:id/refund` rejects the request with `400 NOT_ALLOWED` when the order has any return in `open`, `requested`, or `partially_received` (including exchange-linked returns). Message: `Cannot process a refund while the return is {status}. Receive the returned items first.` Orders with no return, or only `received` / `canceled` returns, are not blocked.
|
|
594
|
-
- **Order detail integration**: `GET /admin/orders/:order_id/refund-context` — aggregated read returning `return_id`, `return_status`, `can_process_refund` (`true` only when status is `received` and the mapping exists and is not already refunded), `order_payment` (checkout `provider_id`, human-readable `label`, `is_cod` — used for guest orders that have no saved `payment_detail`), `refund_mapping` (id, payment_id, is_refunded, refund_mode, images, details), `payment_detail` (id, type, detail_json, is_default) resolved from the customer's specified or default payment detail, and `refund` (product_amount, return_charge, expected_net_amount, final_refund_amount, currency_code, is_processed, breakdown_matches, destination_label). `final_refund_amount` is the processed payment refund (or COD/offline `return.refund_amount` after mark-refunded), not `product_amount - return_charge`. Returns null blocks when no return or mapping exists.
|
|
594
|
+
- **Order detail integration**: `GET /admin/orders/:order_id/refund-context` — aggregated read returning `return_id`, `return_status`, `can_process_refund` (`true` only when status is `received` and the mapping exists and is not already refunded), `order_payment` (checkout `provider_id`, human-readable `label`, `is_cod` — used for guest orders that have no saved `payment_detail`), `refund_mapping` (id, payment_id, is_refunded, refund_mode, images, details), `payment_detail` (id, type, detail_json, is_default) resolved from the customer's specified or default payment detail, and `refund` (product_amount, return_charge, expected_net_amount, final_refund_amount, currency_code, is_processed, breakdown_matches, destination_label). `final_refund_amount` is the processed payment refund (or COD/offline `return.refund_amount` after mark-refunded), not `product_amount - return_charge`. Returns null blocks when no return or mapping exists. Used by admin refund/return detail pages; refund_mode, images, and details are admin-only via the mapping APIs above.
|
|
595
595
|
- **Store return payload**: `GET /store/returns` and `GET /store/returns/:id` attach the same `refund` object so the storefront can render the breakdown. `GET /store/orders/:order_id/refund-payment-mappings` includes `refund` per mapping.
|
|
596
596
|
- **Registration**: Add the module in `medusa-config.js` (e.g. `orderManagement.modules["refund-payment-mapping"]`) and run migrations.
|
|
597
597
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "order-management",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.96",
|
|
4
4
|
"description": "A starter for Medusa plugins.",
|
|
5
5
|
"author": "Medusa (https://medusajs.com)",
|
|
6
6
|
"license": "MIT",
|
|
@@ -56,7 +56,8 @@
|
|
|
56
56
|
"typescript": "^5.9.3",
|
|
57
57
|
"vite": "^8.3.0",
|
|
58
58
|
"vitest": "^5.0.1",
|
|
59
|
-
"yalc": "^1.0.0-pre.53"
|
|
59
|
+
"yalc": "^1.0.0-pre.53",
|
|
60
|
+
"zod": "4.2.0"
|
|
60
61
|
},
|
|
61
62
|
"peerDependencies": {
|
|
62
63
|
"@medusajs/admin-sdk": "2.11.2",
|
|
@@ -66,7 +67,8 @@
|
|
|
66
67
|
"@medusajs/medusa": "2.11.2",
|
|
67
68
|
"@medusajs/test-utils": "2.11.2",
|
|
68
69
|
"@medusajs/ui": "4.0.25",
|
|
69
|
-
"medusa-plugin-dynamic-config": ">=0.0.36"
|
|
70
|
+
"medusa-plugin-dynamic-config": ">=0.0.36",
|
|
71
|
+
"zod": ">=3.0.0"
|
|
70
72
|
},
|
|
71
73
|
"engines": {
|
|
72
74
|
"node": ">=20"
|