order-management 0.0.16 → 0.0.18
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 +638 -5
- package/.medusa/server/src/admin/index.mjs +638 -5
- package/.medusa/server/src/api/admin/swaps/[id]/approve/route.js +45 -0
- package/.medusa/server/src/api/admin/swaps/[id]/reject/route.js +43 -0
- package/.medusa/server/src/api/admin/swaps/[id]/route.js +70 -0
- package/.medusa/server/src/api/admin/swaps/[id]/status/route.js +45 -0
- package/.medusa/server/src/api/admin/swaps/route.js +51 -0
- package/.medusa/server/src/api/admin/swaps/validators.js +22 -0
- package/.medusa/server/src/api/store/guest-orders/[id]/invoice/route.js +19 -2
- package/.medusa/server/src/api/store/guest-orders/[id]/returns/route.js +19 -2
- package/.medusa/server/src/api/store/guest-orders/[id]/route.js +19 -2
- package/.medusa/server/src/api/store/guest-orders/route.js +19 -2
- package/.medusa/server/src/api/store/orders/[order_id]/swaps/route.js +107 -0
- package/.medusa/server/src/api/store/otp/request/route.js +12 -5
- package/.medusa/server/src/api/store/otp/verify/route.js +3 -2
- package/.medusa/server/src/api/store/swaps/[id]/cancel/route.js +64 -0
- package/.medusa/server/src/api/store/swaps/[id]/route.js +112 -0
- package/.medusa/server/src/api/store/swaps/route.js +117 -0
- package/.medusa/server/src/config.js +3 -24
- package/.medusa/server/src/helpers/index.js +18 -0
- package/.medusa/server/src/helpers/swaps.js +88 -0
- package/.medusa/server/src/modules/swap/index.js +13 -0
- package/.medusa/server/src/modules/swap/migrations/Migration20260121164326.js +49 -0
- package/.medusa/server/src/modules/swap/models/swap.js +21 -0
- package/.medusa/server/src/modules/swap/service.js +154 -0
- package/.medusa/server/src/services/otp-service.js +21 -4
- package/.medusa/server/src/subscribers/send-order-email.js +29 -7
- package/.medusa/server/src/workflows/index.js +8 -2
- package/.medusa/server/src/workflows/steps/swap/calculate-difference-step.js +56 -0
- package/.medusa/server/src/workflows/steps/swap/create-swap-step.js +29 -0
- package/.medusa/server/src/workflows/steps/swap/index.js +16 -0
- package/.medusa/server/src/workflows/steps/swap/retrieve-swap-step.js +26 -0
- package/.medusa/server/src/workflows/steps/swap/update-swap-status-step.js +25 -0
- package/.medusa/server/src/workflows/steps/swap/validate-order-step.js +47 -0
- package/.medusa/server/src/workflows/steps/swap/validate-swap-items-step.js +41 -0
- package/.medusa/server/src/workflows/swaps/approve-swap-workflow.js +38 -0
- package/.medusa/server/src/workflows/swaps/create-swap-workflow.js +46 -0
- package/.medusa/server/src/workflows/swaps/types.js +3 -0
- package/.medusa/server/src/workflows/swaps/update-swap-status-workflow.js +23 -0
- package/README.md +247 -5
- package/package.json +1 -1
- package/.medusa/server/src/utils/resolve-options.js +0 -57
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createSwapWorkflow = void 0;
|
|
4
|
+
const workflows_sdk_1 = require("@medusajs/framework/workflows-sdk");
|
|
5
|
+
const swap_1 = require("../steps/swap");
|
|
6
|
+
exports.createSwapWorkflow = (0, workflows_sdk_1.createWorkflow)("create-swap", (input) => {
|
|
7
|
+
const { order_id, return_items, new_items, reason, note, customer_id } = input;
|
|
8
|
+
// Step 1: Validate order exists and belongs to customer
|
|
9
|
+
const { order } = (0, swap_1.validateOrderStep)({
|
|
10
|
+
order_id,
|
|
11
|
+
customer_id,
|
|
12
|
+
});
|
|
13
|
+
// Step 2: Validate swap items
|
|
14
|
+
const { return_items: validatedReturnItems, new_items: validatedNewItems } = (0, swap_1.validateSwapItemsStep)({
|
|
15
|
+
order,
|
|
16
|
+
return_items,
|
|
17
|
+
new_items,
|
|
18
|
+
});
|
|
19
|
+
// Step 3: Calculate price difference
|
|
20
|
+
const { difference_due } = (0, swap_1.calculateDifferenceStep)({
|
|
21
|
+
order,
|
|
22
|
+
return_items: validatedReturnItems,
|
|
23
|
+
new_items: validatedNewItems,
|
|
24
|
+
});
|
|
25
|
+
// Step 4: Create swap record
|
|
26
|
+
const { swap } = (0, swap_1.createSwapStep)({
|
|
27
|
+
order_id,
|
|
28
|
+
return_items: validatedReturnItems,
|
|
29
|
+
new_items: validatedNewItems,
|
|
30
|
+
difference_due,
|
|
31
|
+
reason,
|
|
32
|
+
note,
|
|
33
|
+
});
|
|
34
|
+
// Step 5: Send notification (optional - can be skipped if no email template)
|
|
35
|
+
// sendNotificationStep({
|
|
36
|
+
// to: order.email || "",
|
|
37
|
+
// subject: "Swap Request Created",
|
|
38
|
+
// renderedContent: null, // Would need email template
|
|
39
|
+
// templateData: {},
|
|
40
|
+
// })
|
|
41
|
+
return new workflows_sdk_1.WorkflowResponse({
|
|
42
|
+
swap,
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
exports.default = exports.createSwapWorkflow;
|
|
46
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3JlYXRlLXN3YXAtd29ya2Zsb3cuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvd29ya2Zsb3dzL3N3YXBzL2NyZWF0ZS1zd2FwLXdvcmtmbG93LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLHFFQUcwQztBQUMxQyx3Q0FLc0I7QUFPVCxRQUFBLGtCQUFrQixHQUFHLElBQUEsOEJBQWMsRUFDOUMsYUFBYSxFQUNiLENBQ0UsS0FBd0QsRUFDWixFQUFFO0lBQzlDLE1BQU0sRUFBRSxRQUFRLEVBQUUsWUFBWSxFQUFFLFNBQVMsRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFLFdBQVcsRUFBRSxHQUFHLEtBQUssQ0FBQTtJQUU5RSx3REFBd0Q7SUFDeEQsTUFBTSxFQUFFLEtBQUssRUFBRSxHQUFHLElBQUEsd0JBQWlCLEVBQUM7UUFDbEMsUUFBUTtRQUNSLFdBQVc7S0FDWixDQUFDLENBQUE7SUFFRiw4QkFBOEI7SUFDOUIsTUFBTSxFQUFFLFlBQVksRUFBRSxvQkFBb0IsRUFBRSxTQUFTLEVBQUUsaUJBQWlCLEVBQUUsR0FDeEUsSUFBQSw0QkFBcUIsRUFBQztRQUNwQixLQUFLO1FBQ0wsWUFBWTtRQUNaLFNBQVM7S0FDVixDQUFDLENBQUE7SUFFSixxQ0FBcUM7SUFDckMsTUFBTSxFQUFFLGNBQWMsRUFBRSxHQUFHLElBQUEsOEJBQXVCLEVBQUM7UUFDakQsS0FBSztRQUNMLFlBQVksRUFBRSxvQkFBb0I7UUFDbEMsU0FBUyxFQUFFLGlCQUFpQjtLQUM3QixDQUFDLENBQUE7SUFFRiw2QkFBNkI7SUFDN0IsTUFBTSxFQUFFLElBQUksRUFBRSxHQUFHLElBQUEscUJBQWMsRUFBQztRQUM5QixRQUFRO1FBQ1IsWUFBWSxFQUFFLG9CQUFvQjtRQUNsQyxTQUFTLEVBQUUsaUJBQWlCO1FBQzVCLGNBQWM7UUFDZCxNQUFNO1FBQ04sSUFBSTtLQUNMLENBQUMsQ0FBQTtJQUVGLDZFQUE2RTtJQUM3RSx5QkFBeUI7SUFDekIsMkJBQTJCO0lBQzNCLHFDQUFxQztJQUNyQyx3REFBd0Q7SUFDeEQsc0JBQXNCO0lBQ3RCLEtBQUs7SUFFTCxPQUFPLElBQUksZ0NBQWdCLENBQTJCO1FBQ3BELElBQUk7S0FDTCxDQUFDLENBQUE7QUFDSixDQUFDLENBQ0YsQ0FBQTtBQUVELGtCQUFlLDBCQUFrQixDQUFBIn0=
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvd29ya2Zsb3dzL3N3YXBzL3R5cGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiIifQ==
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.updateSwapStatusWorkflow = void 0;
|
|
4
|
+
const workflows_sdk_1 = require("@medusajs/framework/workflows-sdk");
|
|
5
|
+
const swap_1 = require("../steps/swap");
|
|
6
|
+
exports.updateSwapStatusWorkflow = (0, workflows_sdk_1.createWorkflow)("update-swap-status", (input) => {
|
|
7
|
+
const { swap_id, status, metadata } = input;
|
|
8
|
+
// Step 1: Retrieve swap to validate it exists
|
|
9
|
+
(0, swap_1.retrieveSwapStep)({
|
|
10
|
+
swap_id,
|
|
11
|
+
});
|
|
12
|
+
// Step 2: Update status (validation happens in updateSwapStatusStep)
|
|
13
|
+
const { swap } = (0, swap_1.updateSwapStatusStep)({
|
|
14
|
+
swap_id,
|
|
15
|
+
status,
|
|
16
|
+
metadata,
|
|
17
|
+
});
|
|
18
|
+
return new workflows_sdk_1.WorkflowResponse({
|
|
19
|
+
swap,
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
exports.default = exports.updateSwapStatusWorkflow;
|
|
23
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXBkYXRlLXN3YXAtc3RhdHVzLXdvcmtmbG93LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL3dvcmtmbG93cy9zd2Fwcy91cGRhdGUtc3dhcC1zdGF0dXMtd29ya2Zsb3cudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEscUVBRzBDO0FBQzFDLHdDQUdzQjtBQU1ULFFBQUEsd0JBQXdCLEdBQUcsSUFBQSw4QkFBYyxFQUNwRCxvQkFBb0IsRUFDcEIsQ0FDRSxLQUFvQyxFQUNjLEVBQUU7SUFDcEQsTUFBTSxFQUFFLE9BQU8sRUFBRSxNQUFNLEVBQUUsUUFBUSxFQUFFLEdBQUcsS0FBSyxDQUFBO0lBRTNDLDhDQUE4QztJQUM5QyxJQUFBLHVCQUFnQixFQUFDO1FBQ2YsT0FBTztLQUNSLENBQUMsQ0FBQTtJQUVGLHFFQUFxRTtJQUNyRSxNQUFNLEVBQUUsSUFBSSxFQUFFLEdBQUcsSUFBQSwyQkFBb0IsRUFBQztRQUNwQyxPQUFPO1FBQ1AsTUFBTTtRQUNOLFFBQVE7S0FDVCxDQUFDLENBQUE7SUFFRixPQUFPLElBQUksZ0NBQWdCLENBQWlDO1FBQzFELElBQUk7S0FDTCxDQUFDLENBQUE7QUFDSixDQUFDLENBQ0YsQ0FBQTtBQUVELGtCQUFlLGdDQUF3QixDQUFBIn0=
|
package/README.md
CHANGED
|
@@ -43,22 +43,43 @@ This starter is compatible with versions >= 2.4.0 of `@medusajs/medusa`.
|
|
|
43
43
|
- **Order Confirmation Emails**: Automatically sends email notifications when orders are placed (with "Claim Order" support for registered users)
|
|
44
44
|
- **Return Orders Admin Panel**: Complete return orders management section in the Medusa Admin Panel with list view, filtering, search, detail pages, and status management
|
|
45
45
|
- **Guest Returns & Invoices**: Secure endpoints for guest users to initiate returns and download invoices
|
|
46
|
+
- **Customer-Initiated Swaps**: Complete swap/exchange functionality allowing customers to request item swaps directly from the storefront with full status lifecycle management
|
|
46
47
|
|
|
47
48
|
## Configuration
|
|
48
49
|
|
|
49
50
|
The plugin can be configured in your `medusa-config.js` file:
|
|
50
51
|
|
|
51
52
|
```js
|
|
53
|
+
import { defineConfig } from "@medusajs/framework/utils"
|
|
54
|
+
|
|
52
55
|
module.exports = defineConfig({
|
|
53
56
|
// ...
|
|
54
57
|
plugins: [
|
|
55
58
|
{
|
|
56
59
|
resolve: "order-management",
|
|
57
60
|
options: {
|
|
61
|
+
// Required options
|
|
62
|
+
storefrontUrl: process.env.STOREFRONT_URL || "http://localhost:8000",
|
|
63
|
+
jwtSecret: process.env.JWT_SECRET || "medusa-secret-guest-access",
|
|
64
|
+
|
|
65
|
+
// Email template options
|
|
58
66
|
email: {
|
|
59
67
|
orderConfirmTemplate: "src/templates/emails/order-confirmation.html", // Path to HTML template file
|
|
60
68
|
otpTemplate: "src/templates/emails/otp-verification.html", // Path to HTML template file (required)
|
|
61
69
|
},
|
|
70
|
+
|
|
71
|
+
// Optional SMTP configuration (for email delivery)
|
|
72
|
+
smtp: {
|
|
73
|
+
enabled: process.env.FORCE_SMTP_REDELIVER === "true",
|
|
74
|
+
host: process.env.SMTP_HOST,
|
|
75
|
+
port: process.env.SMTP_PORT ? Number(process.env.SMTP_PORT) : undefined,
|
|
76
|
+
secure: process.env.SMTP_SECURE === "true",
|
|
77
|
+
auth: {
|
|
78
|
+
user: process.env.SMTP_AUTH_USER,
|
|
79
|
+
pass: process.env.SMTP_AUTH_PASS,
|
|
80
|
+
},
|
|
81
|
+
from: process.env.SMTP_FROM || process.env.SMTP_AUTH_USER,
|
|
82
|
+
},
|
|
62
83
|
},
|
|
63
84
|
},
|
|
64
85
|
],
|
|
@@ -67,15 +88,29 @@ module.exports = defineConfig({
|
|
|
67
88
|
|
|
68
89
|
### Configuration Options
|
|
69
90
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
91
|
+
**Required Options:**
|
|
92
|
+
- `storefrontUrl` - Your storefront URL (required)
|
|
93
|
+
- `jwtSecret` - JWT secret for guest order tokens (required)
|
|
94
|
+
|
|
95
|
+
**Email Template Options:**
|
|
96
|
+
- `email.orderConfirmTemplate` - Path to HTML template file for order confirmation emails (optional)
|
|
97
|
+
- `email.otpTemplate` - Path to HTML template file for OTP verification emails (required for guest OTP functionality)
|
|
98
|
+
|
|
99
|
+
**Optional SMTP Options:**
|
|
100
|
+
- `smtp.enabled` - Enable SMTP email delivery (default: `false`)
|
|
101
|
+
- `smtp.host` - SMTP server host (required if enabled)
|
|
102
|
+
- `smtp.port` - SMTP server port (required if enabled)
|
|
103
|
+
- `smtp.secure` - Use secure connection (default: `true`)
|
|
104
|
+
- `smtp.auth.user` - SMTP username (required if enabled)
|
|
105
|
+
- `smtp.auth.pass` - SMTP password (required if enabled)
|
|
106
|
+
- `smtp.from` - From email address (optional, defaults to `smtp.auth.user`)
|
|
74
107
|
|
|
75
108
|
**Notes**:
|
|
109
|
+
- `storefrontUrl` and `jwtSecret` are required. All other options are optional.
|
|
76
110
|
- Order confirmation emails are only sent if a template path is provided. If no template is configured, emails will not be sent.
|
|
77
|
-
- OTP template is **mandatory
|
|
111
|
+
- OTP template is **mandatory** for guest OTP functionality. The guest OTP request API will return an error if `email.otpTemplate` is not configured.
|
|
78
112
|
- OTP templates should include `{{otp}}` placeholder for the verification code.
|
|
113
|
+
- SMTP configuration is optional. If not enabled, emails will use Medusa's default email provider.
|
|
79
114
|
|
|
80
115
|
## Return Orders Admin Panel
|
|
81
116
|
|
|
@@ -210,6 +245,213 @@ The following variables are available in order confirmation email templates:
|
|
|
210
245
|
| `{{is_registered}}` | Whether the customer email has a registered account | `true` |
|
|
211
246
|
| `{{claim_link}}` | Link for registered users to claim their guest order | `http://.../claim?order_id=...` |
|
|
212
247
|
|
|
248
|
+
## Customer-Initiated Swaps
|
|
249
|
+
|
|
250
|
+
The plugin includes a complete swap/exchange feature that allows customers to request item swaps directly from the storefront. This extends Medusa v2's native OrderExchange functionality with customer-facing APIs and admin management tools.
|
|
251
|
+
|
|
252
|
+
### Features
|
|
253
|
+
|
|
254
|
+
- **Customer-Initiated Swaps**: Customers can request swaps for their orders directly from the storefront
|
|
255
|
+
- **Complete Status Lifecycle**: Full status tracking from `requested` → `approved` → `return_started` → `return_shipped` → `return_received` → `new_items_shipped` → `completed`
|
|
256
|
+
- **Admin Management**: Complete admin panel for viewing, approving, rejecting, and managing swaps
|
|
257
|
+
- **Price Difference Calculation**: Automatic calculation of price differences between returned and new items
|
|
258
|
+
- **Status History**: Complete audit trail of all status changes
|
|
259
|
+
|
|
260
|
+
### Swap Status Flow
|
|
261
|
+
|
|
262
|
+
```
|
|
263
|
+
requested → approved → return_started → return_shipped → return_received → new_items_shipped → completed
|
|
264
|
+
↘ rejected
|
|
265
|
+
↘ cancelled (from any status except completed)
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### Storefront API Endpoints
|
|
269
|
+
|
|
270
|
+
#### Create Swap Request
|
|
271
|
+
|
|
272
|
+
```bash
|
|
273
|
+
POST /store/swaps
|
|
274
|
+
Authorization: Bearer <customer_token>
|
|
275
|
+
Content-Type: application/json
|
|
276
|
+
|
|
277
|
+
{
|
|
278
|
+
"order_id": "order_123",
|
|
279
|
+
"return_items": [
|
|
280
|
+
{
|
|
281
|
+
"id": "item_123",
|
|
282
|
+
"quantity": 1,
|
|
283
|
+
"reason": "Wrong size"
|
|
284
|
+
}
|
|
285
|
+
],
|
|
286
|
+
"new_items": [
|
|
287
|
+
{
|
|
288
|
+
"variant_id": "variant_456",
|
|
289
|
+
"quantity": 1
|
|
290
|
+
}
|
|
291
|
+
],
|
|
292
|
+
"reason": "Size exchange",
|
|
293
|
+
"note": "Please send size M instead"
|
|
294
|
+
}
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
#### List Customer Swaps
|
|
298
|
+
|
|
299
|
+
```bash
|
|
300
|
+
GET /store/swaps
|
|
301
|
+
Authorization: Bearer <customer_token>
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
#### Get Swap Details
|
|
305
|
+
|
|
306
|
+
```bash
|
|
307
|
+
GET /store/swaps/{swap_id}
|
|
308
|
+
Authorization: Bearer <customer_token>
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
#### List Swaps for Order
|
|
312
|
+
|
|
313
|
+
```bash
|
|
314
|
+
GET /store/orders/{order_id}/swaps
|
|
315
|
+
Authorization: Bearer <customer_token>
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
#### Create Swap for Order
|
|
319
|
+
|
|
320
|
+
```bash
|
|
321
|
+
POST /store/orders/{order_id}/swaps
|
|
322
|
+
Authorization: Bearer <customer_token>
|
|
323
|
+
Content-Type: application/json
|
|
324
|
+
|
|
325
|
+
{
|
|
326
|
+
"return_items": [
|
|
327
|
+
{
|
|
328
|
+
"id": "item_123",
|
|
329
|
+
"quantity": 1
|
|
330
|
+
}
|
|
331
|
+
],
|
|
332
|
+
"new_items": [
|
|
333
|
+
{
|
|
334
|
+
"variant_id": "variant_456",
|
|
335
|
+
"quantity": 1
|
|
336
|
+
}
|
|
337
|
+
],
|
|
338
|
+
"reason": "Size exchange"
|
|
339
|
+
}
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
#### Cancel Swap
|
|
343
|
+
|
|
344
|
+
```bash
|
|
345
|
+
POST /store/swaps/{swap_id}/cancel
|
|
346
|
+
Authorization: Bearer <customer_token>
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
### Admin API Endpoints
|
|
350
|
+
|
|
351
|
+
#### List All Swaps
|
|
352
|
+
|
|
353
|
+
```bash
|
|
354
|
+
GET /admin/swaps?status=requested&order_id=order_123&limit=50&offset=0
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
#### Get Swap Details
|
|
358
|
+
|
|
359
|
+
```bash
|
|
360
|
+
GET /admin/swaps/{swap_id}
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
#### Approve Swap
|
|
364
|
+
|
|
365
|
+
```bash
|
|
366
|
+
POST /admin/swaps/{swap_id}/approve
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
#### Reject Swap
|
|
370
|
+
|
|
371
|
+
```bash
|
|
372
|
+
POST /admin/swaps/{swap_id}/reject
|
|
373
|
+
Content-Type: application/json
|
|
374
|
+
|
|
375
|
+
{
|
|
376
|
+
"reason": "Item out of stock"
|
|
377
|
+
}
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
#### Update Swap Status
|
|
381
|
+
|
|
382
|
+
```bash
|
|
383
|
+
POST /admin/swaps/{swap_id}/status
|
|
384
|
+
Content-Type: application/json
|
|
385
|
+
|
|
386
|
+
{
|
|
387
|
+
"status": "return_started",
|
|
388
|
+
"metadata": {
|
|
389
|
+
"return_label_id": "label_123"
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
### Admin UI
|
|
395
|
+
|
|
396
|
+
The plugin includes a complete admin UI for managing swaps:
|
|
397
|
+
|
|
398
|
+
- **Swaps List Page**: View all swaps with filtering by status, search by order ID, and pagination
|
|
399
|
+
- **Swap Detail Page**: View complete swap information including:
|
|
400
|
+
- Swap details (ID, status, dates, price difference)
|
|
401
|
+
- Original order information
|
|
402
|
+
- Return items list
|
|
403
|
+
- New items list
|
|
404
|
+
- Status history timeline
|
|
405
|
+
- Action buttons (approve/reject/update status)
|
|
406
|
+
|
|
407
|
+
Access the Swaps section from the Admin Panel sidebar.
|
|
408
|
+
|
|
409
|
+
### Storefront Helpers
|
|
410
|
+
|
|
411
|
+
The plugin provides helper methods for easy integration:
|
|
412
|
+
|
|
413
|
+
```typescript
|
|
414
|
+
import { createSwapRequest, getSwaps, getSwap, cancelSwap } from "order-management/helpers"
|
|
415
|
+
|
|
416
|
+
// Create a swap request
|
|
417
|
+
const swap = await createSwapRequest({
|
|
418
|
+
orderId: "order_123",
|
|
419
|
+
returnItems: [
|
|
420
|
+
{ id: "item_123", quantity: 1, reason: "Wrong size" }
|
|
421
|
+
],
|
|
422
|
+
newItems: [
|
|
423
|
+
{ variant_id: "variant_456", quantity: 1 }
|
|
424
|
+
],
|
|
425
|
+
reason: "Size exchange",
|
|
426
|
+
note: "Please send size M"
|
|
427
|
+
}, container)
|
|
428
|
+
|
|
429
|
+
// Get swaps for an order
|
|
430
|
+
const swaps = await getSwaps("order_123", container)
|
|
431
|
+
|
|
432
|
+
// Get a specific swap
|
|
433
|
+
const swapDetails = await getSwap("swap_123", container)
|
|
434
|
+
|
|
435
|
+
// Cancel a swap
|
|
436
|
+
const cancelledSwap = await cancelSwap("swap_123", container)
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
### Status Transitions
|
|
440
|
+
|
|
441
|
+
The swap status flow enforces valid transitions:
|
|
442
|
+
|
|
443
|
+
- **requested** → `approved`, `rejected`, `cancelled`
|
|
444
|
+
- **approved** → `return_started`, `cancelled`
|
|
445
|
+
- **return_started** → `return_shipped`, `cancelled`
|
|
446
|
+
- **return_shipped** → `return_received`, `cancelled`
|
|
447
|
+
- **return_received** → `new_items_shipped`, `cancelled`
|
|
448
|
+
- **new_items_shipped** → `completed`, `cancelled`
|
|
449
|
+
- **rejected** → (terminal state)
|
|
450
|
+
- **completed** → (terminal state)
|
|
451
|
+
- **cancelled** → (terminal state)
|
|
452
|
+
|
|
453
|
+
Invalid status transitions will be rejected with a descriptive error message.
|
|
454
|
+
|
|
213
455
|
## Getting Started
|
|
214
456
|
|
|
215
457
|
Visit the [Quickstart Guide](https://docs.medusajs.com/learn/installation) to set up a server.
|
package/package.json
CHANGED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.resolveOrderManagementOptions = resolveOrderManagementOptions;
|
|
4
|
-
exports.extractOrderManagementOptions = extractOrderManagementOptions;
|
|
5
|
-
const DEFAULT_OPTIONS = {
|
|
6
|
-
email: {
|
|
7
|
-
orderConfirmTemplate: null,
|
|
8
|
-
otpTemplate: null,
|
|
9
|
-
},
|
|
10
|
-
};
|
|
11
|
-
/**
|
|
12
|
-
* Resolve and normalize plugin options with defaults
|
|
13
|
-
*/
|
|
14
|
-
function resolveOrderManagementOptions(options) {
|
|
15
|
-
if (!options) {
|
|
16
|
-
return DEFAULT_OPTIONS;
|
|
17
|
-
}
|
|
18
|
-
return {
|
|
19
|
-
email: {
|
|
20
|
-
orderConfirmTemplate: options.email?.orderConfirmTemplate ?? DEFAULT_OPTIONS.email.orderConfirmTemplate,
|
|
21
|
-
otpTemplate: options.email?.otpTemplate ?? DEFAULT_OPTIONS.email.otpTemplate,
|
|
22
|
-
},
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Extract plugin options from config module
|
|
27
|
-
*/
|
|
28
|
-
function extractOrderManagementOptions(configModule) {
|
|
29
|
-
// Try from projectConfig.plugins first
|
|
30
|
-
const plugins = configModule?.projectConfig?.plugins ?? [];
|
|
31
|
-
for (const plugin of plugins) {
|
|
32
|
-
if (typeof plugin === "string") {
|
|
33
|
-
if (plugin === "order-management") {
|
|
34
|
-
return {};
|
|
35
|
-
}
|
|
36
|
-
continue;
|
|
37
|
-
}
|
|
38
|
-
if (plugin?.resolve === "order-management") {
|
|
39
|
-
return plugin.options;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
// Try from direct config.plugins (fallback)
|
|
43
|
-
const directPlugins = configModule?.plugins ?? [];
|
|
44
|
-
for (const plugin of directPlugins) {
|
|
45
|
-
if (typeof plugin === "string") {
|
|
46
|
-
if (plugin === "order-management") {
|
|
47
|
-
return {};
|
|
48
|
-
}
|
|
49
|
-
continue;
|
|
50
|
-
}
|
|
51
|
-
if (plugin?.resolve === "order-management") {
|
|
52
|
-
return plugin.options;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
return undefined;
|
|
56
|
-
}
|
|
57
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVzb2x2ZS1vcHRpb25zLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3V0aWxzL3Jlc29sdmUtb3B0aW9ucy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQW1CQSxzRUFhQztBQUtELHNFQW9DQztBQWhFRCxNQUFNLGVBQWUsR0FBbUM7SUFDdEQsS0FBSyxFQUFFO1FBQ0wsb0JBQW9CLEVBQUUsSUFBSTtRQUMxQixXQUFXLEVBQUUsSUFBSTtLQUNsQjtDQUNGLENBQUE7QUFFRDs7R0FFRztBQUNILFNBQWdCLDZCQUE2QixDQUMzQyxPQUE2QztJQUU3QyxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDYixPQUFPLGVBQWUsQ0FBQTtJQUN4QixDQUFDO0lBRUQsT0FBTztRQUNMLEtBQUssRUFBRTtZQUNMLG9CQUFvQixFQUFFLE9BQU8sQ0FBQyxLQUFLLEVBQUUsb0JBQW9CLElBQUksZUFBZSxDQUFDLEtBQUssQ0FBQyxvQkFBb0I7WUFDdkcsV0FBVyxFQUFFLE9BQU8sQ0FBQyxLQUFLLEVBQUUsV0FBVyxJQUFJLGVBQWUsQ0FBQyxLQUFLLENBQUMsV0FBVztTQUM3RTtLQUNGLENBQUE7QUFDSCxDQUFDO0FBRUQ7O0dBRUc7QUFDSCxTQUFnQiw2QkFBNkIsQ0FDM0MsWUFBa0I7SUFFbEIsdUNBQXVDO0lBQ3ZDLE1BQU0sT0FBTyxHQUFHLFlBQVksRUFBRSxhQUFhLEVBQUUsT0FBTyxJQUFJLEVBQUUsQ0FBQTtJQUUxRCxLQUFLLE1BQU0sTUFBTSxJQUFJLE9BQU8sRUFBRSxDQUFDO1FBQzdCLElBQUksT0FBTyxNQUFNLEtBQUssUUFBUSxFQUFFLENBQUM7WUFDL0IsSUFBSSxNQUFNLEtBQUssa0JBQWtCLEVBQUUsQ0FBQztnQkFDbEMsT0FBTyxFQUFFLENBQUE7WUFDWCxDQUFDO1lBQ0QsU0FBUTtRQUNWLENBQUM7UUFFRCxJQUFJLE1BQU0sRUFBRSxPQUFPLEtBQUssa0JBQWtCLEVBQUUsQ0FBQztZQUMzQyxPQUFPLE1BQU0sQ0FBQyxPQUF1QyxDQUFBO1FBQ3ZELENBQUM7SUFDSCxDQUFDO0lBRUQsNENBQTRDO0lBQzVDLE1BQU0sYUFBYSxHQUFJLFlBQW9CLEVBQUUsT0FBTyxJQUFJLEVBQUUsQ0FBQTtJQUUxRCxLQUFLLE1BQU0sTUFBTSxJQUFJLGFBQWEsRUFBRSxDQUFDO1FBQ25DLElBQUksT0FBTyxNQUFNLEtBQUssUUFBUSxFQUFFLENBQUM7WUFDL0IsSUFBSSxNQUFNLEtBQUssa0JBQWtCLEVBQUUsQ0FBQztnQkFDbEMsT0FBTyxFQUFFLENBQUE7WUFDWCxDQUFDO1lBQ0QsU0FBUTtRQUNWLENBQUM7UUFFRCxJQUFJLE1BQU0sRUFBRSxPQUFPLEtBQUssa0JBQWtCLEVBQUUsQ0FBQztZQUMzQyxPQUFPLE1BQU0sQ0FBQyxPQUF1QyxDQUFBO1FBQ3ZELENBQUM7SUFDSCxDQUFDO0lBRUQsT0FBTyxTQUFTLENBQUE7QUFDbEIsQ0FBQyJ9
|