@things-factory/operato-hub 4.3.626 → 4.3.629
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/dist-server/controllers/company-initializer/settings.js +2 -1
- package/dist-server/controllers/company-initializer/settings.js.map +1 -1
- package/dist-server/routers/api/restful-apis/v1/utils/params.js +35 -3
- package/dist-server/routers/api/restful-apis/v1/utils/params.js.map +1 -1
- package/dist-server/routers/api/restful-apis/v1/warehouse/add-return-order.js +325 -0
- package/dist-server/routers/api/restful-apis/v1/warehouse/add-return-order.js.map +1 -0
- package/dist-server/routers/api/restful-apis/v1/warehouse/get-return-order-details.js +94 -0
- package/dist-server/routers/api/restful-apis/v1/warehouse/get-return-order-details.js.map +1 -0
- package/dist-server/routers/api/restful-apis/v1/warehouse/get-return-order-list.js +63 -0
- package/dist-server/routers/api/restful-apis/v1/warehouse/get-return-order-list.js.map +1 -0
- package/dist-server/routers/api/restful-apis/v1/warehouse/index.js +13 -10
- package/dist-server/routers/api/restful-apis/v1/warehouse/index.js.map +1 -1
- package/openapi/v1/return-order.yaml +486 -0
- package/package.json +4 -4
- package/server/controllers/company-initializer/settings.ts +2 -1
- package/server/routers/api/restful-apis/v1/utils/params.ts +35 -3
- package/server/routers/api/restful-apis/v1/warehouse/add-return-order.ts +360 -0
- package/server/routers/api/restful-apis/v1/warehouse/get-return-order-details.ts +99 -0
- package/server/routers/api/restful-apis/v1/warehouse/get-return-order-list.ts +68 -0
- package/server/routers/api/restful-apis/v1/warehouse/index.ts +13 -10
|
@@ -633,6 +633,30 @@ export const params = {
|
|
|
633
633
|
'sellerDiscount',
|
|
634
634
|
'shippingFee',
|
|
635
635
|
'actualShippingFee'
|
|
636
|
+
],
|
|
637
|
+
'add-return-order': [
|
|
638
|
+
'bizplaceId',
|
|
639
|
+
'releaseGoodName',
|
|
640
|
+
'orderInventories',
|
|
641
|
+
'orderInventories.productDetail',
|
|
642
|
+
'orderInventories.productDetail.id',
|
|
643
|
+
'orderInventories.returnQty',
|
|
644
|
+
'orderInventories.batchId',
|
|
645
|
+
'remark',
|
|
646
|
+
'ownTransport',
|
|
647
|
+
'warehouseTransport',
|
|
648
|
+
'collectionOrderNo'
|
|
649
|
+
],
|
|
650
|
+
'get-return-order-list': [
|
|
651
|
+
'bizplaceId',
|
|
652
|
+
'name',
|
|
653
|
+
...fromToDate,
|
|
654
|
+
...limitOffset
|
|
655
|
+
],
|
|
656
|
+
'get-return-order-details': [
|
|
657
|
+
'bizplaceId',
|
|
658
|
+
'id',
|
|
659
|
+
'returnOrderNo'
|
|
636
660
|
]
|
|
637
661
|
}
|
|
638
662
|
|
|
@@ -1106,7 +1130,13 @@ export const reqParams = {
|
|
|
1106
1130
|
{ name: 'paidPrice', required: true, type: 'field' }
|
|
1107
1131
|
]
|
|
1108
1132
|
}
|
|
1109
|
-
]
|
|
1133
|
+
],
|
|
1134
|
+
'add-return-order': [
|
|
1135
|
+
{ name: 'bizplaceId', required: true, type: 'field' },
|
|
1136
|
+
{ name: 'releaseGoodName', required: true, type: 'field' }
|
|
1137
|
+
],
|
|
1138
|
+
'get-return-order-list': ['bizplaceId'],
|
|
1139
|
+
'get-return-order-details': []
|
|
1110
1140
|
}
|
|
1111
1141
|
|
|
1112
1142
|
// Require Offset
|
|
@@ -1124,7 +1154,8 @@ export const requireLimitOffsetValidation = [
|
|
|
1124
1154
|
'get-contact-point-list',
|
|
1125
1155
|
'get-bizplace-list',
|
|
1126
1156
|
'get-draft-order-list',
|
|
1127
|
-
'get-inventory-adjustment-list'
|
|
1157
|
+
'get-inventory-adjustment-list',
|
|
1158
|
+
'get-return-order-list'
|
|
1128
1159
|
]
|
|
1129
1160
|
|
|
1130
1161
|
// Require fromDate and toDate
|
|
@@ -1135,5 +1166,6 @@ export const requireFromToDateValidation = [
|
|
|
1135
1166
|
'get-delivery-order-list',
|
|
1136
1167
|
'get-marketplace-order-shipping-list',
|
|
1137
1168
|
'get-draft-order-list',
|
|
1138
|
-
'get-inventory-adjustment-list'
|
|
1169
|
+
'get-inventory-adjustment-list',
|
|
1170
|
+
'get-return-order-list'
|
|
1139
1171
|
]
|
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
import { EntityManager, getConnection, In } from 'typeorm'
|
|
2
|
+
|
|
3
|
+
import { restfulApiRouter as router } from '@things-factory/api'
|
|
4
|
+
import { User } from '@things-factory/auth-base'
|
|
5
|
+
import { Bizplace } from '@things-factory/biz-base'
|
|
6
|
+
import { ORDER_STATUS, generateReturnOrder, ReleaseGood } from '@things-factory/sales-base'
|
|
7
|
+
import { Domain } from '@things-factory/shell'
|
|
8
|
+
|
|
9
|
+
import { businessMiddleware, loggingMiddleware, validationMiddleware } from '../middlewares'
|
|
10
|
+
import { ApiError, ApiErrorHandler, throwInternalServerError } from '../utils/error-util'
|
|
11
|
+
|
|
12
|
+
router.post(
|
|
13
|
+
'/v1/warehouse/add-return-order',
|
|
14
|
+
businessMiddleware,
|
|
15
|
+
validationMiddleware,
|
|
16
|
+
loggingMiddleware,
|
|
17
|
+
async (context, next) => {
|
|
18
|
+
try {
|
|
19
|
+
const { domain, user } = context.state
|
|
20
|
+
const bodyReq = context.request.body.data
|
|
21
|
+
|
|
22
|
+
// // Basic validations before
|
|
23
|
+
// Transport type validations
|
|
24
|
+
if (!bodyReq.ownTransport && !bodyReq.warehouseTransport) {
|
|
25
|
+
throw new ApiError('E01', 'Please select a transport type')
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (bodyReq.ownTransport && bodyReq.warehouseTransport) {
|
|
29
|
+
throw new ApiError('E01', 'You can only select one transport type')
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// // Order inventories basic validations
|
|
33
|
+
if (!bodyReq.orderInventories || !Array.isArray(bodyReq.orderInventories) || bodyReq.orderInventories.length === 0) {
|
|
34
|
+
throw new ApiError('E01', 'orderInventories is required and must be a non-empty array')
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Validate each inventory item's required fields
|
|
38
|
+
for (const returnItem of bodyReq.orderInventories) {
|
|
39
|
+
if (!returnItem.productDetail || !returnItem.productDetail.id) {
|
|
40
|
+
throw new ApiError('E01', 'productDetail.id is required for each order inventory')
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (!returnItem.returnQty || returnItem.returnQty <= 0) {
|
|
44
|
+
throw new ApiError('E01', 'returnQty must be greater than 0 for each order inventory')
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (!returnItem.batchId) {
|
|
48
|
+
throw new ApiError('E01', 'batchId is required for each order inventory')
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
await getConnection().transaction(async (tx: EntityManager) => {
|
|
53
|
+
// 1. Get customer bizplace
|
|
54
|
+
const customerBizplace: Bizplace = await tx.getRepository(Bizplace).findOne({
|
|
55
|
+
where: { id: bodyReq.bizplaceId },
|
|
56
|
+
relations: ['domain']
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
if (!customerBizplace) {
|
|
60
|
+
throw new ApiError('E04', 'customer bizplace not found')
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// 2. Get release good details and validate
|
|
64
|
+
const releaseGood: ReleaseGood = await tx.getRepository(ReleaseGood).findOne({
|
|
65
|
+
where: {
|
|
66
|
+
domain,
|
|
67
|
+
name: bodyReq.releaseGoodName,
|
|
68
|
+
bizplace: customerBizplace,
|
|
69
|
+
status: In([ORDER_STATUS.DONE])
|
|
70
|
+
},
|
|
71
|
+
relations: [
|
|
72
|
+
'orderInventories',
|
|
73
|
+
'orderInventories.product',
|
|
74
|
+
'orderInventories.productDetail',
|
|
75
|
+
'orderInventories.inventory',
|
|
76
|
+
'orderInventories.inventory.product',
|
|
77
|
+
'orderInventories.inventory.product.productDetails'
|
|
78
|
+
]
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
if (!releaseGood) {
|
|
82
|
+
throw new ApiError('E04', `Release good ${bodyReq.releaseGoodName} not found`)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// 3. Validate each return item against original order (by productDetailId only)
|
|
86
|
+
for (const returnItem of bodyReq.orderInventories) {
|
|
87
|
+
const originalOrderInventory = releaseGood.orderInventories.find(oi =>
|
|
88
|
+
oi.productDetail && oi.productDetail.id === returnItem.productDetail.id && oi.inventory.batchId === returnItem.batchId
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
if (!originalOrderInventory) {
|
|
92
|
+
throw new ApiError('E01', `productDetail.id:${returnItem.productDetail.id} with batchId:${returnItem.batchId} was not found in the original order`)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (returnItem.returnQty > originalOrderInventory.releaseQty) {
|
|
96
|
+
throw new ApiError('E01', `Return quantity ${returnItem.returnQty} exceeds original order quantity ${originalOrderInventory.releaseQty} for product detail ${returnItem.productDetail.id}`)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
returnItem.product = originalOrderInventory.product
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// 4. Prepare return order data
|
|
103
|
+
const returnOrder = {
|
|
104
|
+
customerBizplaceId: bodyReq.bizplaceId,
|
|
105
|
+
orderInventories: bodyReq.orderInventories,
|
|
106
|
+
remark: bodyReq.remark || null,
|
|
107
|
+
ownTransport: bodyReq.ownTransport || false,
|
|
108
|
+
collectionOrderNo: bodyReq.collectionOrderNo || null
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// 5. Generate return order
|
|
112
|
+
const result = await generateReturnOrder(tx, domain, user, returnOrder, [], context)
|
|
113
|
+
|
|
114
|
+
// 6. Prepare response data
|
|
115
|
+
const data = {
|
|
116
|
+
id: result.id,
|
|
117
|
+
name: result.name,
|
|
118
|
+
status: result.status,
|
|
119
|
+
remark: result.remark,
|
|
120
|
+
ownTransport: result.ownTransport,
|
|
121
|
+
collectionOrderNo: result.collectionOrderNo,
|
|
122
|
+
bizplace: { name: result.bizplace.name },
|
|
123
|
+
domain: { name: result.domain.name }
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
context.body = {
|
|
127
|
+
responseCode: '200',
|
|
128
|
+
message: 'success',
|
|
129
|
+
data
|
|
130
|
+
}
|
|
131
|
+
})
|
|
132
|
+
} catch (e) {
|
|
133
|
+
if (e instanceof ApiError) {
|
|
134
|
+
ApiErrorHandler(context, e)
|
|
135
|
+
} else {
|
|
136
|
+
throwInternalServerError(context, e)
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
// Sample Request:
|
|
143
|
+
// POST /api/v1/warehouse/add-return-order
|
|
144
|
+
// Headers:
|
|
145
|
+
// Content-Type: application/json
|
|
146
|
+
// Authorization: Bearer <token>
|
|
147
|
+
// Body:
|
|
148
|
+
// {
|
|
149
|
+
// "bizplaceId": "123e4567-e89b-12d3-a456-426614174000",
|
|
150
|
+
// "releaseGoodName": "RG-2023001",
|
|
151
|
+
// "orderInventories": [
|
|
152
|
+
// {
|
|
153
|
+
// "productDetail": {
|
|
154
|
+
// "id": "987e6543-e21b-12d3-a456-426614174999"
|
|
155
|
+
// },
|
|
156
|
+
// "returnQty": 10,
|
|
157
|
+
// "batchId": "batch-001"
|
|
158
|
+
// }
|
|
159
|
+
// ],
|
|
160
|
+
// "remark": "Customer returned items due to defect",
|
|
161
|
+
// "ownTransport": true,
|
|
162
|
+
// "collectionOrderNo": "COL-123456"
|
|
163
|
+
// }
|
|
164
|
+
|
|
165
|
+
// Sample Postman Test Cases:
|
|
166
|
+
// Test Case 1: Valid Return Order with Single Inventory
|
|
167
|
+
// Description: Test the creation of a return order with valid data and a single inventory item.
|
|
168
|
+
// Method: POST
|
|
169
|
+
// URL: http://<server-url>/api/v1/warehouse/add-return-order
|
|
170
|
+
// Headers:
|
|
171
|
+
// Content-Type: application/json
|
|
172
|
+
// Authorization: Bearer <token>
|
|
173
|
+
// Body:
|
|
174
|
+
// {
|
|
175
|
+
// "bizplaceId": "123e4567-e89b-12d3-a456-426614174000",
|
|
176
|
+
// "releaseGoodName": "RG-2023001",
|
|
177
|
+
// "orderInventories": [
|
|
178
|
+
// {
|
|
179
|
+
// "productDetail": {
|
|
180
|
+
// "id": "987e6543-e21b-12d3-a456-426614174999"
|
|
181
|
+
// },
|
|
182
|
+
// "returnQty": 10,
|
|
183
|
+
// "batchId": "batch-001"
|
|
184
|
+
// }
|
|
185
|
+
// ],
|
|
186
|
+
// "remark": "Customer returned items due to defect",
|
|
187
|
+
// "ownTransport": true,
|
|
188
|
+
// "collectionOrderNo": "COL-123456"
|
|
189
|
+
// }
|
|
190
|
+
|
|
191
|
+
// Test Case 2: Valid Return Order with Multiple Inventories
|
|
192
|
+
// Description: Test the creation of a return order with valid data and multiple inventory items.
|
|
193
|
+
// Method: POST
|
|
194
|
+
// URL: http://<server-url>/api/v1/warehouse/add-return-order
|
|
195
|
+
// Headers:
|
|
196
|
+
// Content-Type: application/json
|
|
197
|
+
// Authorization: Bearer <token>
|
|
198
|
+
// Body:
|
|
199
|
+
// {
|
|
200
|
+
// "bizplaceId": "123e4567-e89b-12d3-a456-426614174000",
|
|
201
|
+
// "releaseGoodName": "RG-2023001",
|
|
202
|
+
// "orderInventories": [
|
|
203
|
+
// {
|
|
204
|
+
// "productDetail": {
|
|
205
|
+
// "id": "987e6543-e21b-12d3-a456-426614174999"
|
|
206
|
+
// },
|
|
207
|
+
// "returnQty": 10,
|
|
208
|
+
// "batchId": "batch-001"
|
|
209
|
+
// },
|
|
210
|
+
// {
|
|
211
|
+
// "productDetail": {
|
|
212
|
+
// "id": "123e4567-e89b-12d3-a456-426614174998"
|
|
213
|
+
// },
|
|
214
|
+
// "returnQty": 5,
|
|
215
|
+
// "batchId": "batch-002"
|
|
216
|
+
// }
|
|
217
|
+
// ],
|
|
218
|
+
// "remark": "Customer returned items due to defect",
|
|
219
|
+
// "ownTransport": true,
|
|
220
|
+
// "collectionOrderNo": "COL-123456"
|
|
221
|
+
// }
|
|
222
|
+
|
|
223
|
+
// Test Case 3: Missing Bizplace ID
|
|
224
|
+
// Description: Test the creation of a return order without a bizplace ID.
|
|
225
|
+
// Method: POST
|
|
226
|
+
// URL: http://<server-url>/api/v1/warehouse/add-return-order
|
|
227
|
+
// Headers:
|
|
228
|
+
// Content-Type: application/json
|
|
229
|
+
// Authorization: Bearer <token>
|
|
230
|
+
// Body:
|
|
231
|
+
// {
|
|
232
|
+
// "releaseGoodName": "RG-2023001",
|
|
233
|
+
// "orderInventories": [
|
|
234
|
+
// {
|
|
235
|
+
// "productDetail": {
|
|
236
|
+
// "id": "987e6543-e21b-12d3-a456-426614174999"
|
|
237
|
+
// },
|
|
238
|
+
// "returnQty": 10,
|
|
239
|
+
// "batchId": "batch-001"
|
|
240
|
+
// }
|
|
241
|
+
// ],
|
|
242
|
+
// "remark": "Customer returned items due to defect",
|
|
243
|
+
// "ownTransport": true,
|
|
244
|
+
// "collectionOrderNo": "COL-123456"
|
|
245
|
+
// }
|
|
246
|
+
|
|
247
|
+
// Test Case 4: Invalid Return Quantity
|
|
248
|
+
// Description: Test the creation of a return order with a negative return quantity.
|
|
249
|
+
// Method: POST
|
|
250
|
+
// URL: http://<server-url>/api/v1/warehouse/add-return-order
|
|
251
|
+
// Headers:
|
|
252
|
+
// Content-Type: application/json
|
|
253
|
+
// Authorization: Bearer <token>
|
|
254
|
+
// Body:
|
|
255
|
+
// {
|
|
256
|
+
// "bizplaceId": "123e4567-e89b-12d3-a456-426614174000",
|
|
257
|
+
// "releaseGoodName": "RG-2023001",
|
|
258
|
+
// "orderInventories": [
|
|
259
|
+
// {
|
|
260
|
+
// "productDetail": {
|
|
261
|
+
// "id": "987e6543-e21b-12d3-a456-426614174999"
|
|
262
|
+
// },
|
|
263
|
+
// "returnQty": -5,
|
|
264
|
+
// "batchId": "batch-001"
|
|
265
|
+
// }
|
|
266
|
+
// ],
|
|
267
|
+
// "remark": "Customer returned items due to defect",
|
|
268
|
+
// "ownTransport": true,
|
|
269
|
+
// "collectionOrderNo": "COL-123456"
|
|
270
|
+
// }
|
|
271
|
+
|
|
272
|
+
// Test Case 5: Missing Order Inventories
|
|
273
|
+
// Description: Test the creation of a return order without order inventories.
|
|
274
|
+
// Method: POST
|
|
275
|
+
// URL: http://<server-url>/api/v1/warehouse/add-return-order
|
|
276
|
+
// Headers:
|
|
277
|
+
// Content-Type: application/json
|
|
278
|
+
// Authorization: Bearer <token>
|
|
279
|
+
// Body:
|
|
280
|
+
// {
|
|
281
|
+
// "bizplaceId": "123e4567-e89b-12d3-a456-426614174000",
|
|
282
|
+
// "releaseGoodName": "RG-2023001",
|
|
283
|
+
// "remark": "Customer returned items due to defect",
|
|
284
|
+
// "ownTransport": true,
|
|
285
|
+
// "collectionOrderNo": "COL-123456"
|
|
286
|
+
// }
|
|
287
|
+
|
|
288
|
+
// Test Case 6: Invalid Product Detail ID
|
|
289
|
+
// Description: Test the creation of a return order with an invalid productDetail.id.
|
|
290
|
+
// Method: POST
|
|
291
|
+
// URL: http://<server-url>/api/v1/warehouse/add-return-order
|
|
292
|
+
// Headers:
|
|
293
|
+
// Content-Type: application/json
|
|
294
|
+
// Authorization: Bearer <token>
|
|
295
|
+
// Body:
|
|
296
|
+
// {
|
|
297
|
+
// "bizplaceId": "123e4567-e89b-12d3-a456-426614174000",
|
|
298
|
+
// "releaseGoodName": "RG-2023001",
|
|
299
|
+
// "orderInventories": [
|
|
300
|
+
// {
|
|
301
|
+
// "productDetail": {
|
|
302
|
+
// "id": "invalid-product-detail-id"
|
|
303
|
+
// },
|
|
304
|
+
// "returnQty": 10,
|
|
305
|
+
// "batchId": "batch-001"
|
|
306
|
+
// }
|
|
307
|
+
// ],
|
|
308
|
+
// "remark": "Customer returned items due to defect",
|
|
309
|
+
// "ownTransport": true,
|
|
310
|
+
// "collectionOrderNo": "COL-123456"
|
|
311
|
+
// }
|
|
312
|
+
|
|
313
|
+
// Test Case 7: Missing Release Good Name
|
|
314
|
+
// Description: Test the creation of a return order without a release good name.
|
|
315
|
+
// Method: POST
|
|
316
|
+
// URL: http://<server-url>/api/v1/warehouse/add-return-order
|
|
317
|
+
// Headers:
|
|
318
|
+
// Content-Type: application/json
|
|
319
|
+
// Authorization: Bearer <token>
|
|
320
|
+
// Body:
|
|
321
|
+
// {
|
|
322
|
+
// "bizplaceId": "123e4567-e89b-12d3-a456-426614174000",
|
|
323
|
+
// "orderInventories": [
|
|
324
|
+
// {
|
|
325
|
+
// "productDetail": {
|
|
326
|
+
// "id": "987e6543-e21b-12d3-a456-426614174999"
|
|
327
|
+
// },
|
|
328
|
+
// "returnQty": 10,
|
|
329
|
+
// "batchId": "batch-001"
|
|
330
|
+
// }
|
|
331
|
+
// ],
|
|
332
|
+
// "remark": "Customer returned items due to defect",
|
|
333
|
+
// "ownTransport": true,
|
|
334
|
+
// "collectionOrderNo": "COL-123456"
|
|
335
|
+
// }
|
|
336
|
+
|
|
337
|
+
// Test Case 8: Invalid Release Good Name
|
|
338
|
+
// Description: Test the creation of a return order with a non-existent release good name.
|
|
339
|
+
// Method: POST
|
|
340
|
+
// URL: http://<server-url>/api/v1/warehouse/add-return-order
|
|
341
|
+
// Headers:
|
|
342
|
+
// Content-Type: application/json
|
|
343
|
+
// Authorization: Bearer <token>
|
|
344
|
+
// Body:
|
|
345
|
+
// {
|
|
346
|
+
// "bizplaceId": "123e4567-e89b-12d3-a456-426614174000",
|
|
347
|
+
// "releaseGoodName": "INVALID-RG-2023001",
|
|
348
|
+
// "orderInventories": [
|
|
349
|
+
// {
|
|
350
|
+
// "productDetail": {
|
|
351
|
+
// "id": "987e6543-e21b-12d3-a456-426614174999"
|
|
352
|
+
// },
|
|
353
|
+
// "returnQty": 10,
|
|
354
|
+
// "batchId": "batch-001"
|
|
355
|
+
// }
|
|
356
|
+
// ],
|
|
357
|
+
// "remark": "Customer returned items due to defect",
|
|
358
|
+
// "ownTransport": true,
|
|
359
|
+
// "collectionOrderNo": "COL-123456"
|
|
360
|
+
// }
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import _ from 'lodash'
|
|
2
|
+
import { getRepository } from 'typeorm'
|
|
3
|
+
import { ReturnOrder } from '@things-factory/sales-base'
|
|
4
|
+
|
|
5
|
+
import { restfulApiRouter as router } from '@things-factory/api'
|
|
6
|
+
import { businessMiddleware, loggingMiddleware, validationMiddleware } from '../middlewares'
|
|
7
|
+
import { ApiError, ApiErrorHandler, throwInternalServerError } from '../utils/error-util'
|
|
8
|
+
|
|
9
|
+
router.get(
|
|
10
|
+
'/v1/warehouse/get-return-order-details',
|
|
11
|
+
businessMiddleware,
|
|
12
|
+
validationMiddleware,
|
|
13
|
+
loggingMiddleware,
|
|
14
|
+
async (context, next) => {
|
|
15
|
+
try {
|
|
16
|
+
const { domain } = context.state
|
|
17
|
+
let filter = { ...context.query, domain: domain.id }
|
|
18
|
+
if (filter.bizplaceId) {
|
|
19
|
+
filter['bizplace'] = filter['bizplaceId']
|
|
20
|
+
delete filter['bizplaceId']
|
|
21
|
+
}
|
|
22
|
+
if (filter.id) {
|
|
23
|
+
filter['id'] = filter['id']
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (filter.returnOrderNo) {
|
|
27
|
+
filter['name'] = filter['returnOrderNo']
|
|
28
|
+
delete filter['returnOrderNo']
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (!filter.id && !filter.name) {
|
|
32
|
+
throw new ApiError('E01', 'return order number or id is required')
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const returnOrder: ReturnOrder = await getRepository(ReturnOrder).findOne({
|
|
36
|
+
where: filter,
|
|
37
|
+
relations: [
|
|
38
|
+
'bizplace',
|
|
39
|
+
'orderInventories',
|
|
40
|
+
'orderInventories.product',
|
|
41
|
+
'orderInventories.productDetail',
|
|
42
|
+
'creator',
|
|
43
|
+
'updater',
|
|
44
|
+
'acceptedBy'
|
|
45
|
+
]
|
|
46
|
+
})
|
|
47
|
+
if (!returnOrder) {
|
|
48
|
+
throw new ApiError('E04', 'return order')
|
|
49
|
+
}
|
|
50
|
+
// Flatten inventoryInfos for frontend
|
|
51
|
+
const itemInfos = (returnOrder.orderInventories || []).map(orderInv => {
|
|
52
|
+
return {
|
|
53
|
+
batchId: orderInv.batchId,
|
|
54
|
+
product: {
|
|
55
|
+
id: orderInv.product.id,
|
|
56
|
+
sku: orderInv.product.sku,
|
|
57
|
+
brandSku: orderInv.product?.brandSku,
|
|
58
|
+
brand: orderInv.product?.brand,
|
|
59
|
+
subBrand: orderInv.product?.subBrand
|
|
60
|
+
},
|
|
61
|
+
productDetail: {
|
|
62
|
+
id: orderInv.productDetail.id,
|
|
63
|
+
refCode: orderInv.productDetail.refCode,
|
|
64
|
+
isDefault: orderInv.productDetail?.isDefault,
|
|
65
|
+
packingType: orderInv.productDetail.packingType,
|
|
66
|
+
packingSize: orderInv.productDetail.packingSize,
|
|
67
|
+
movement: orderInv.productDetail?.movement,
|
|
68
|
+
uom: orderInv.productDetail?.uom,
|
|
69
|
+
uomValue: orderInv.productDetail?.uomValue
|
|
70
|
+
},
|
|
71
|
+
returnQty: orderInv.returnQty,
|
|
72
|
+
remark: orderInv.remark,
|
|
73
|
+
status: orderInv.status
|
|
74
|
+
}
|
|
75
|
+
})
|
|
76
|
+
const data = {
|
|
77
|
+
id: returnOrder.id,
|
|
78
|
+
name: returnOrder.name,
|
|
79
|
+
status: returnOrder.status,
|
|
80
|
+
ownTransport: returnOrder.ownTransport,
|
|
81
|
+
eta: returnOrder.eta,
|
|
82
|
+
etaDate: returnOrder.etaDate,
|
|
83
|
+
remark: returnOrder.remark,
|
|
84
|
+
refNo: returnOrder.refNo,
|
|
85
|
+
bizplace: returnOrder.bizplace ? { id: returnOrder.bizplace.id, name: returnOrder.bizplace.name } : null,
|
|
86
|
+
creator: returnOrder.creator ? { id: returnOrder.creator.id, name: returnOrder.creator.name } : null,
|
|
87
|
+
updater: returnOrder.updater ? { id: returnOrder.updater.id, name: returnOrder.updater.name } : null,
|
|
88
|
+
acceptedBy: returnOrder.acceptedBy ? { id: returnOrder.acceptedBy.id, name: returnOrder.acceptedBy.name } : null,
|
|
89
|
+
createdAt: returnOrder.createdAt,
|
|
90
|
+
updatedAt: returnOrder.updatedAt,
|
|
91
|
+
itemInfos
|
|
92
|
+
}
|
|
93
|
+
context.body = { data }
|
|
94
|
+
} catch (e) {
|
|
95
|
+
if (e instanceof ApiError) ApiErrorHandler(context, e)
|
|
96
|
+
else throwInternalServerError(context, e)
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
)
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import _ from 'lodash'
|
|
2
|
+
import { Between, getRepository } from 'typeorm'
|
|
3
|
+
|
|
4
|
+
import { restfulApiRouter as router } from '@things-factory/api'
|
|
5
|
+
import { ReturnOrder } from '@things-factory/sales-base'
|
|
6
|
+
|
|
7
|
+
import { businessMiddleware, loggingMiddleware, validationMiddleware } from '../middlewares'
|
|
8
|
+
import { ApiError, ApiErrorHandler, throwInternalServerError } from '../utils/error-util'
|
|
9
|
+
|
|
10
|
+
router.get(
|
|
11
|
+
'/v1/warehouse/get-return-order-list',
|
|
12
|
+
businessMiddleware,
|
|
13
|
+
validationMiddleware,
|
|
14
|
+
loggingMiddleware,
|
|
15
|
+
async (context, next) => {
|
|
16
|
+
try {
|
|
17
|
+
let filter = { ...context.query }
|
|
18
|
+
const { fromDate, toDate, offset, limit } = filter
|
|
19
|
+
if (filter.bizplaceId) {
|
|
20
|
+
filter['bizplace'] = filter['bizplaceId']
|
|
21
|
+
delete filter['bizplaceId']
|
|
22
|
+
}
|
|
23
|
+
if (filter.name) {
|
|
24
|
+
filter['name'] = filter['name']
|
|
25
|
+
}
|
|
26
|
+
if (fromDate && toDate) {
|
|
27
|
+
filter['createdAt'] = Between(fromDate, toDate)
|
|
28
|
+
}
|
|
29
|
+
delete filter['fromDate']
|
|
30
|
+
delete filter['toDate']
|
|
31
|
+
delete filter['limit']
|
|
32
|
+
delete filter['offset']
|
|
33
|
+
|
|
34
|
+
const [returnOrders, totalCount]: [ReturnOrder[], number] = await getRepository(ReturnOrder).findAndCount({
|
|
35
|
+
where: filter,
|
|
36
|
+
relations: ['bizplace', 'creator', 'updater', 'acceptedBy'],
|
|
37
|
+
skip: offset ? Number(offset) : 0,
|
|
38
|
+
take: limit ? Number(limit) : 100,
|
|
39
|
+
order: { createdAt: 'DESC' }
|
|
40
|
+
})
|
|
41
|
+
const data = returnOrders.map(ro => ({
|
|
42
|
+
id: ro.id,
|
|
43
|
+
name: ro.name,
|
|
44
|
+
status: ro.status,
|
|
45
|
+
ownTransport: ro.ownTransport,
|
|
46
|
+
eta: ro.eta,
|
|
47
|
+
etaDate: ro.etaDate,
|
|
48
|
+
remark: ro.remark,
|
|
49
|
+
refNo: ro.refNo,
|
|
50
|
+
bizplace: ro.bizplace ? { id: ro.bizplace.id, name: ro.bizplace.name } : null,
|
|
51
|
+
creator: ro.creator ? { id: ro.creator.id, name: ro.creator.name } : null,
|
|
52
|
+
updater: ro.updater ? { id: ro.updater.id, name: ro.updater.name } : null,
|
|
53
|
+
acceptedBy: ro.acceptedBy ? { id: ro.acceptedBy.id, name: ro.acceptedBy.name } : null,
|
|
54
|
+
createdAt: ro.createdAt,
|
|
55
|
+
updatedAt: ro.updatedAt
|
|
56
|
+
}))
|
|
57
|
+
context.body = {
|
|
58
|
+
data,
|
|
59
|
+
totalCount,
|
|
60
|
+
limit: limit ? Number(limit) : 100,
|
|
61
|
+
offset: offset ? Number(offset) : 0
|
|
62
|
+
}
|
|
63
|
+
} catch (e) {
|
|
64
|
+
if (e instanceof ApiError) ApiErrorHandler(context, e)
|
|
65
|
+
else throwInternalServerError(context, e)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
)
|
|
@@ -1,26 +1,29 @@
|
|
|
1
1
|
import './add-inbound-order'
|
|
2
2
|
import './add-release-order'
|
|
3
|
+
import './add-return-order'
|
|
4
|
+
import './add-sales-invoice'
|
|
3
5
|
import './cancel-inbound-order'
|
|
4
6
|
import './cancel-release-order'
|
|
7
|
+
import './complete-delivery-order'
|
|
8
|
+
import './dispatch-delivery-order'
|
|
5
9
|
import './get-delivery-order-list'
|
|
10
|
+
import './get-do-document'
|
|
11
|
+
import './get-draft-order-details'
|
|
6
12
|
import './get-draft-order-list'
|
|
7
13
|
import './get-goods-received-note-list'
|
|
14
|
+
import './get-grn-document'
|
|
8
15
|
import './get-inbound-order-details'
|
|
9
16
|
import './get-inbound-order-list'
|
|
17
|
+
import './get-inventory-adjustment-details'
|
|
18
|
+
import './get-inventory-adjustment-list'
|
|
10
19
|
import './get-inventory-product-group-list'
|
|
20
|
+
import './get-manifest-details'
|
|
11
21
|
import './get-onhand-inventory-list'
|
|
12
|
-
import './get-draft-order-details'
|
|
13
22
|
import './get-release-order-details'
|
|
14
23
|
import './get-release-order-list'
|
|
24
|
+
import './get-return-order-details'
|
|
25
|
+
import './get-return-order-list'
|
|
15
26
|
import './get-warehouse-bizplace-onhand-inventories'
|
|
16
|
-
import './update-release-order-details'
|
|
17
|
-
import './get-grn-document'
|
|
18
|
-
import './get-do-document'
|
|
19
|
-
import './dispatch-delivery-order'
|
|
20
27
|
import './update-gan-to-arrived'
|
|
21
|
-
import './complete-delivery-order'
|
|
22
|
-
import './get-inventory-adjustment-list'
|
|
23
|
-
import './get-inventory-adjustment-details'
|
|
24
|
-
import './get-manifest-details'
|
|
25
28
|
import './update-order-package-details'
|
|
26
|
-
import './
|
|
29
|
+
import './update-release-order-details'
|