@things-factory/operato-hub 3.7.9 → 3.7.13
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/routers/api/restful-apis/unstable/add-release-order.js +354 -333
- package/dist-server/routers/api/restful-apis/unstable/add-release-order.js.map +1 -1
- package/dist-server/routers/api/restful-apis/v1/add-release-order.js +390 -308
- package/dist-server/routers/api/restful-apis/v1/add-release-order.js.map +1 -1
- package/dist-server/routers/api/restful-apis/v2/add-release-order.js +390 -308
- package/dist-server/routers/api/restful-apis/v2/add-release-order.js.map +1 -1
- package/package.json +9 -9
- package/server/routers/api/restful-apis/unstable/add-release-order.ts +427 -404
- package/server/routers/api/restful-apis/v1/add-release-order.ts +439 -339
- package/server/routers/api/restful-apis/v2/add-release-order.ts +439 -339
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import gql from 'graphql-tag'
|
|
2
|
-
import {
|
|
2
|
+
import { EntityManager, getConnection, SelectQueryBuilder } from 'typeorm'
|
|
3
3
|
|
|
4
4
|
import { restfulApiRouter as router } from '@things-factory/api'
|
|
5
5
|
import { Bizplace, getCompanyBizplace } from '@things-factory/biz-base'
|
|
@@ -19,470 +19,484 @@ router.post(
|
|
|
19
19
|
businessMiddleware,
|
|
20
20
|
warehouseMiddleware,
|
|
21
21
|
async (context, next) => {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
return await getConnection().transaction(async (tx: EntityManager) => {
|
|
23
|
+
const { client, domain } = context.state
|
|
24
|
+
const { warehouseId: customerBizplaceId } = context.params
|
|
25
|
+
const { t } = context
|
|
25
26
|
|
|
26
|
-
|
|
27
|
+
if (!customerBizplaceId) context.throw(404, t('error.warehouse id not found'))
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
let bodyReq = context.request.body
|
|
30
|
+
if (typeof bodyReq === undefined || !Object.keys(bodyReq)?.length) {
|
|
31
|
+
context.throw(400, t('error.invalid body request format'))
|
|
32
|
+
}
|
|
33
|
+
debug('post:/add-release-order request.body', bodyReq)
|
|
34
|
+
await checkMandatoryKey(context, bodyReq)
|
|
34
35
|
|
|
35
|
-
|
|
36
|
+
const isAutoAssign: Boolean = bodyReq.hasOwnProperty('isAutoAssign') ? bodyReq.isAutoAssign : true
|
|
36
37
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
38
|
+
// get customer company's bizplace
|
|
39
|
+
const custCompanyBizplace: Bizplace = await getCompanyBizplace(null, null, customerBizplaceId, tx)
|
|
40
|
+
const customerBizplace: Bizplace = await tx.getRepository(Bizplace).findOne({
|
|
41
|
+
where: { id: customerBizplaceId }
|
|
42
|
+
})
|
|
42
43
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
const pickingProductSetting: Setting = await tx.getRepository(Setting).findOne({
|
|
45
|
+
where: { domain, name: 'rule-for-picking-product' }
|
|
46
|
+
})
|
|
46
47
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
48
|
+
let locationSortingRules = []
|
|
49
|
+
if (pickingProductSetting) {
|
|
50
|
+
let locationSetting = JSON.parse(pickingProductSetting.value)
|
|
51
|
+
for (const key in locationSetting) {
|
|
52
|
+
locationSortingRules.push({ name: key, desc: locationSetting[key] == 'ASC' ? false : true })
|
|
53
|
+
}
|
|
52
54
|
}
|
|
53
|
-
}
|
|
54
55
|
|
|
55
|
-
|
|
56
|
-
|
|
56
|
+
const orderInventories: OrderInventory[] = bodyReq.orderInventories
|
|
57
|
+
let newOrderInventories: OrderInventory[] = []
|
|
57
58
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
59
|
+
await Promise.all(
|
|
60
|
+
orderInventories.map(async orderInventory => {
|
|
61
|
+
const sku: string = orderInventory.product?.sku
|
|
62
|
+
const refCode: string = orderInventory.product?.refCode
|
|
63
|
+
const packingType: string = orderInventory.packingType
|
|
63
64
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
65
|
+
const qb: SelectQueryBuilder<ProductDetail> = tx
|
|
66
|
+
.getRepository(ProductDetail)
|
|
67
|
+
.createQueryBuilder('PD')
|
|
68
|
+
.innerJoinAndSelect('PD.product', 'PROD')
|
|
69
|
+
.where('PROD.bizplace_id = :bizplaceId', { bizplaceId: custCompanyBizplace.id })
|
|
68
70
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
+
if (!sku && !refCode) {
|
|
72
|
+
context.throw(404, t('error.sku or refCode not found'))
|
|
73
|
+
}
|
|
71
74
|
|
|
72
|
-
if (
|
|
73
|
-
qb.andWhere('PD.
|
|
75
|
+
if (refCode) {
|
|
76
|
+
qb.andWhere('PD.ref_code = :refCode', { refCode })
|
|
74
77
|
}
|
|
75
|
-
}
|
|
76
78
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
+
if (sku) {
|
|
80
|
+
qb.andWhere('PROD.sku = :sku', { sku })
|
|
81
|
+
}
|
|
79
82
|
|
|
80
83
|
if (packingType) {
|
|
81
84
|
qb.andWhere('PD.packing_type = :packingType', { packingType })
|
|
82
85
|
}
|
|
83
|
-
}
|
|
84
86
|
|
|
85
|
-
|
|
87
|
+
const productDetail: ProductDetail = await qb.getOne()
|
|
86
88
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
newOrderInventory.product.sku = productDetail.product.sku
|
|
91
|
-
newOrderInventory.product = productDetail.product
|
|
92
|
-
newOrderInventory.packingType = productDetail.packingType
|
|
93
|
-
newOrderInventory.uomValue = productDetail.uomValue
|
|
94
|
-
newOrderInventories.push(newOrderInventory)
|
|
95
|
-
}
|
|
89
|
+
if (productDetail) {
|
|
90
|
+
let newOrderInventory: OrderInventory = Object.assign({}, orderInventory)
|
|
96
91
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
.
|
|
100
|
-
.
|
|
101
|
-
.
|
|
102
|
-
|
|
103
|
-
.where('PB.bizplace_id = :bizplaceId', { bizplaceId: custCompanyBizplace.id })
|
|
92
|
+
newOrderInventory.product.sku = productDetail.product.sku
|
|
93
|
+
newOrderInventory.product = productDetail.product
|
|
94
|
+
newOrderInventory.packingType = productDetail.packingType
|
|
95
|
+
newOrderInventory.uomValue = productDetail.uomValue
|
|
96
|
+
newOrderInventories.push(newOrderInventory)
|
|
97
|
+
}
|
|
104
98
|
|
|
105
|
-
if (
|
|
106
|
-
qb
|
|
99
|
+
if (!productDetail) {
|
|
100
|
+
const qb: SelectQueryBuilder<ProductDetail> = tx
|
|
101
|
+
.getRepository(ProductBundle)
|
|
102
|
+
.createQueryBuilder('PB')
|
|
103
|
+
.innerJoinAndSelect('PB.productBundleSettings', 'PBS')
|
|
104
|
+
.innerJoinAndSelect('PBS.productDetail', 'PBD')
|
|
105
|
+
.innerJoinAndSelect('PBD.product', 'PROD')
|
|
106
|
+
.where('PB.bizplace_id = :bizplaceId', { bizplaceId: custCompanyBizplace.id })
|
|
107
|
+
|
|
108
|
+
if (!sku && !refCode) {
|
|
109
|
+
context.throw(404, t('error.sku or refCode not found'))
|
|
110
|
+
}
|
|
107
111
|
|
|
108
|
-
if (
|
|
109
|
-
qb.andWhere('PB.
|
|
112
|
+
if (refCode) {
|
|
113
|
+
qb.andWhere('PB.ref_code = :refCode', { refCode })
|
|
110
114
|
}
|
|
111
|
-
}
|
|
112
115
|
|
|
113
|
-
|
|
114
|
-
|
|
116
|
+
if (sku) {
|
|
117
|
+
qb.andWhere('PB.sku = :sku', { sku })
|
|
118
|
+
}
|
|
115
119
|
|
|
116
120
|
if (packingType) {
|
|
117
121
|
qb.andWhere('PB.packing_type = :packingType', { packingType })
|
|
118
122
|
}
|
|
119
|
-
}
|
|
120
123
|
|
|
121
|
-
|
|
124
|
+
const foundProductBundle: ProductBundle = await qb.getOne()
|
|
125
|
+
|
|
126
|
+
if (foundProductBundle) {
|
|
127
|
+
const bundleProductSettings: any[] = foundProductBundle.productBundleSettings
|
|
128
|
+
bundleProductSettings.map(bundleProductSetting => {
|
|
129
|
+
const productDetailBundle: ProductDetail = bundleProductSetting.productDetail
|
|
130
|
+
|
|
131
|
+
let newOrderInventory: OrderInventory = Object.assign({}, orderInventory)
|
|
132
|
+
newOrderInventory.product.sku = productDetailBundle.product.sku
|
|
133
|
+
newOrderInventory.packingType = productDetailBundle.packingType
|
|
134
|
+
newOrderInventory.uomValue = productDetailBundle.uomValue
|
|
135
|
+
newOrderInventory.releaseQty = orderInventory.releaseQty * bundleProductSetting.bundleQty
|
|
136
|
+
newOrderInventory.product = productDetailBundle.product
|
|
137
|
+
newOrderInventories.push(newOrderInventory)
|
|
138
|
+
})
|
|
139
|
+
} else {
|
|
140
|
+
if (sku && refCode) {
|
|
141
|
+
context.throw(404, t(`error.sku ${sku} and refCode ${refCode} not exist in product / bundle master`))
|
|
142
|
+
}
|
|
122
143
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
const productDetailBundle: ProductDetail = bundleProductSetting.productDetail
|
|
144
|
+
if (sku) {
|
|
145
|
+
context.throw(404, t(`error.sku ${sku} not exist in product / bundle master`))
|
|
146
|
+
}
|
|
127
147
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
newOrderInventory.uomValue = productDetailBundle.uomValue
|
|
132
|
-
newOrderInventory.releaseQty = orderInventory.releaseQty * bundleProductSetting.bundleQty
|
|
133
|
-
newOrderInventory.product = productDetailBundle.product
|
|
134
|
-
newOrderInventories.push(newOrderInventory)
|
|
135
|
-
})
|
|
136
|
-
} else {
|
|
137
|
-
context.throw(404, t(`error.${orderInventory.product?.sku} not exist in product / bundle master`))
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
})
|
|
141
|
-
)
|
|
142
|
-
|
|
143
|
-
let finalOrderInventories: OrderInventory[] = []
|
|
144
|
-
|
|
145
|
-
// Case 1. Every order inventories has specified batch id
|
|
146
|
-
if (newOrderInventories.every((orderInventory: OrderInventory) => orderInventory.batchId)) {
|
|
147
|
-
finalOrderInventories = await Promise.all(
|
|
148
|
-
newOrderInventories.map(async (orderInventory: OrderInventory) => {
|
|
149
|
-
let filters: any = [
|
|
150
|
-
{
|
|
151
|
-
name: 'batchId',
|
|
152
|
-
operator: 'eq',
|
|
153
|
-
value: orderInventory.batchId
|
|
154
|
-
},
|
|
155
|
-
{
|
|
156
|
-
name: 'productName',
|
|
157
|
-
operator: 'eq',
|
|
158
|
-
value: orderInventory.product.sku
|
|
159
|
-
},
|
|
160
|
-
{
|
|
161
|
-
name: 'bizplace',
|
|
162
|
-
operator: 'in',
|
|
163
|
-
value: [customerBizplaceId]
|
|
148
|
+
if (refCode) {
|
|
149
|
+
context.throw(404, t(`error.refCode ${refCode} not exist in product / bundle master`))
|
|
150
|
+
}
|
|
164
151
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
152
|
+
}
|
|
153
|
+
})
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
let finalOrderInventories: OrderInventory[] = []
|
|
157
|
+
|
|
158
|
+
// Case 1. Every order inventories has specified batch id
|
|
159
|
+
if (newOrderInventories.every((orderInventory: OrderInventory) => orderInventory.batchId)) {
|
|
160
|
+
finalOrderInventories = await Promise.all(
|
|
161
|
+
newOrderInventories.map(async (orderInventory: OrderInventory) => {
|
|
162
|
+
let filters: any = [
|
|
163
|
+
{
|
|
164
|
+
name: 'batchId',
|
|
165
|
+
operator: 'eq',
|
|
166
|
+
value: orderInventory.batchId
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
name: 'productName',
|
|
170
|
+
operator: 'eq',
|
|
171
|
+
value: orderInventory.product.sku
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
name: 'bizplace',
|
|
175
|
+
operator: 'in',
|
|
176
|
+
value: [customerBizplaceId]
|
|
177
|
+
}
|
|
178
|
+
]
|
|
179
|
+
|
|
180
|
+
// 2. get all inventory data according to SKU and batchId
|
|
181
|
+
const response = await client.query({
|
|
182
|
+
query: gql`
|
|
183
|
+
query inventoriesByPallet($filters: [Filter]) {
|
|
184
|
+
inventoriesByPallet(filters: $filters) {
|
|
185
|
+
items {
|
|
186
|
+
product {
|
|
187
|
+
id
|
|
188
|
+
name
|
|
189
|
+
description
|
|
190
|
+
}
|
|
191
|
+
batchId
|
|
192
|
+
packingType
|
|
193
|
+
remainQty
|
|
194
|
+
remainWeight
|
|
195
|
+
remainUomValue
|
|
177
196
|
}
|
|
178
|
-
|
|
179
|
-
packingType
|
|
180
|
-
remainQty
|
|
181
|
-
remainWeight
|
|
182
|
-
remainUomValue
|
|
197
|
+
total
|
|
183
198
|
}
|
|
184
|
-
|
|
199
|
+
}
|
|
200
|
+
`,
|
|
201
|
+
variables: { filters, locationSortingRules },
|
|
202
|
+
context: {
|
|
203
|
+
...context,
|
|
204
|
+
state: {
|
|
205
|
+
...context.state,
|
|
206
|
+
bizplace: customerBizplace,
|
|
207
|
+
domain
|
|
185
208
|
}
|
|
186
209
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
} as any)
|
|
198
|
-
|
|
199
|
-
if (!response.errors) {
|
|
200
|
-
const items = response.data.inventoriesByPallet.items || []
|
|
201
|
-
if (!items?.length)
|
|
202
|
-
context.throw(
|
|
203
|
-
404,
|
|
204
|
-
t(
|
|
205
|
-
`error.no inventories found for ${orderInventory.product?.sku} with batch ID ${orderInventory?.batchId}`
|
|
210
|
+
} as any)
|
|
211
|
+
|
|
212
|
+
if (!response.errors) {
|
|
213
|
+
const items = response.data.inventoriesByPallet.items || []
|
|
214
|
+
if (!items?.length)
|
|
215
|
+
context.throw(
|
|
216
|
+
404,
|
|
217
|
+
t(
|
|
218
|
+
`error.no inventories found for ${orderInventory.product?.sku} with batch ID ${orderInventory?.batchId}`
|
|
219
|
+
)
|
|
206
220
|
)
|
|
207
|
-
)
|
|
208
221
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
222
|
+
items.forEach(item => {
|
|
223
|
+
if (orderInventory.releaseQty > item.remainQty || orderInventory.releaseQty <= 0) {
|
|
224
|
+
context.throw(404, t(`error.invalid release qty for ${orderInventory.product?.sku}`))
|
|
225
|
+
}
|
|
213
226
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
227
|
+
// 3. add more information to orderInventory
|
|
228
|
+
orderInventory.product.id = item.product.id
|
|
229
|
+
orderInventory.packingType = item.packingType
|
|
230
|
+
orderInventory.batchId = item.batchId
|
|
231
|
+
orderInventory.type = ORDER_TYPES.RELEASE_OF_GOODS
|
|
232
|
+
orderInventory.releaseUomValue = orderInventory.releaseQty * orderInventory.uomValue
|
|
233
|
+
orderInventory.uom = item.uom
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
return orderInventory
|
|
237
|
+
} else context.throw(404, t('error.failed to fetch inventory'))
|
|
238
|
+
})
|
|
239
|
+
)
|
|
240
|
+
} else {
|
|
241
|
+
// Case 2. Some of order inventories doesn't have specified batch id
|
|
242
|
+
// MMS order doesn't have batch ID field.
|
|
243
|
+
// To cover this case first result of found inventory will be a target of RO
|
|
244
|
+
|
|
245
|
+
for (let i: number = 0; i < newOrderInventories.length; i++) {
|
|
246
|
+
const orderInventory: OrderInventory = newOrderInventories[i]
|
|
247
|
+
const product: Product = orderInventory.product
|
|
248
|
+
const packingType: string = orderInventory.packingType
|
|
249
|
+
|
|
250
|
+
if (isAutoAssign) {
|
|
251
|
+
let qb: SelectQueryBuilder<Inventory> = tx.getRepository(Inventory).createQueryBuilder('iv')
|
|
252
|
+
qb.leftJoinAndSelect('iv.location', 'loc')
|
|
253
|
+
.andWhere('"iv"."domain_id" = :domainId')
|
|
254
|
+
.andWhere('"iv"."bizplace_id" = :bizplaceId')
|
|
255
|
+
.andWhere('"iv"."packing_type" = :packingType')
|
|
256
|
+
.andWhere('"iv"."product_id" = :productId')
|
|
257
|
+
.andWhere('"iv"."status" = :status')
|
|
258
|
+
.setParameters({
|
|
259
|
+
domainId: domain.id,
|
|
260
|
+
bizplaceId: customerBizplace.id,
|
|
261
|
+
packingType: packingType,
|
|
262
|
+
productId: product.id,
|
|
263
|
+
status: INVENTORY_STATUS.STORED
|
|
264
|
+
})
|
|
265
|
+
|
|
266
|
+
if (locationSortingRules?.length > 0) {
|
|
267
|
+
locationSortingRules.forEach((rule: { name: string; desc: boolean }, idx: number) => {
|
|
268
|
+
idx === 0
|
|
269
|
+
? qb.addOrderBy(`loc.${rule.name}`, rule.desc ? 'DESC' : 'ASC')
|
|
270
|
+
: qb.addOrderBy(`loc.${rule.name}`, rule.desc ? 'DESC' : 'ASC')
|
|
271
|
+
})
|
|
272
|
+
} else {
|
|
273
|
+
qb.addOrderBy('"iv"."created_at"', 'ASC')
|
|
274
|
+
}
|
|
222
275
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
for (let i: number = 0; i < newOrderInventories.length; i++) {
|
|
233
|
-
const orderInventory: OrderInventory = newOrderInventories[i]
|
|
234
|
-
const product: Product = orderInventory.product
|
|
235
|
-
const packingType: string = orderInventory.packingType
|
|
236
|
-
|
|
237
|
-
if (isAutoAssign) {
|
|
238
|
-
let qb: SelectQueryBuilder<Inventory> = getRepository(Inventory).createQueryBuilder('iv')
|
|
239
|
-
qb.leftJoinAndSelect('iv.location', 'loc')
|
|
240
|
-
.andWhere('"iv"."domain_id" = :domainId')
|
|
241
|
-
.andWhere('"iv"."bizplace_id" = :bizplaceId')
|
|
242
|
-
.andWhere('"iv"."packing_type" = :packingType')
|
|
243
|
-
.andWhere('"iv"."product_id" = :productId')
|
|
244
|
-
.andWhere('"iv"."status" = :status')
|
|
245
|
-
.setParameters({
|
|
246
|
-
domainId: domain.id,
|
|
247
|
-
bizplaceId: customerBizplace.id,
|
|
248
|
-
packingType: packingType,
|
|
249
|
-
productId: product.id,
|
|
250
|
-
status: INVENTORY_STATUS.STORED
|
|
276
|
+
let inventories: Inventory[] = await qb.getMany()
|
|
277
|
+
if (!inventories?.length) context.throw(404, t(`error.no inventories found for ${product.sku}`))
|
|
278
|
+
|
|
279
|
+
inventories = inventories.map(inventory => {
|
|
280
|
+
return {
|
|
281
|
+
...inventory,
|
|
282
|
+
remainQty: inventory.qty - inventory.lockedQty,
|
|
283
|
+
remainUomValue: inventory.uomValue - inventory.lockedUomValue
|
|
284
|
+
}
|
|
251
285
|
})
|
|
252
286
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
287
|
+
const targetInventories: WorksheetDetail[] = _composeTargetInventories(
|
|
288
|
+
context,
|
|
289
|
+
product,
|
|
290
|
+
orderInventory,
|
|
291
|
+
inventories
|
|
292
|
+
)
|
|
293
|
+
targetInventories.map(item => {
|
|
294
|
+
finalOrderInventories.push(item.targetInventory)
|
|
258
295
|
})
|
|
259
296
|
} else {
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
},
|
|
290
|
-
{
|
|
291
|
-
name: 'bizplace_id',
|
|
292
|
-
operator: 'eq',
|
|
293
|
-
value: customerBizplaceId
|
|
294
|
-
}
|
|
295
|
-
]
|
|
296
|
-
|
|
297
|
-
// 2. get all inventory data according to SKU and batchId
|
|
298
|
-
const response = await client.query({
|
|
299
|
-
query: gql`
|
|
300
|
-
query inventoryProductGroup($filters: [Filter]) {
|
|
301
|
-
inventoryProductGroup(filters: $filters) {
|
|
302
|
-
items {
|
|
303
|
-
productId
|
|
304
|
-
productSKU
|
|
305
|
-
productName
|
|
306
|
-
batchId
|
|
307
|
-
packingType
|
|
308
|
-
remainQty
|
|
309
|
-
remainWeight
|
|
310
|
-
remainUomValue
|
|
297
|
+
let filters: any = [
|
|
298
|
+
{
|
|
299
|
+
name: 'productName',
|
|
300
|
+
operator: 'eq',
|
|
301
|
+
value: orderInventory.product.sku
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
name: 'bizplace_id',
|
|
305
|
+
operator: 'eq',
|
|
306
|
+
value: customerBizplaceId
|
|
307
|
+
}
|
|
308
|
+
]
|
|
309
|
+
|
|
310
|
+
// 2. get all inventory data according to SKU and batchId
|
|
311
|
+
const response = await client.query({
|
|
312
|
+
query: gql`
|
|
313
|
+
query inventoryProductGroup($filters: [Filter]) {
|
|
314
|
+
inventoryProductGroup(filters: $filters) {
|
|
315
|
+
items {
|
|
316
|
+
productId
|
|
317
|
+
productSKU
|
|
318
|
+
productName
|
|
319
|
+
batchId
|
|
320
|
+
packingType
|
|
321
|
+
remainQty
|
|
322
|
+
remainWeight
|
|
323
|
+
remainUomValue
|
|
324
|
+
}
|
|
325
|
+
total
|
|
311
326
|
}
|
|
312
|
-
|
|
327
|
+
}
|
|
328
|
+
`,
|
|
329
|
+
variables: { filters },
|
|
330
|
+
context: {
|
|
331
|
+
...context,
|
|
332
|
+
state: {
|
|
333
|
+
...context.state,
|
|
334
|
+
bizplace: customerBizplace,
|
|
335
|
+
domain
|
|
313
336
|
}
|
|
314
337
|
}
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
} as any)
|
|
326
|
-
|
|
327
|
-
if (!response.errors) {
|
|
328
|
-
const items = response.data.inventoryProductGroup.items || []
|
|
329
|
-
if (!items?.length)
|
|
330
|
-
context.throw(
|
|
331
|
-
404,
|
|
332
|
-
t(
|
|
333
|
-
`error.no inventories found for ${orderInventory.product?.sku} with batch ID ${orderInventory?.batchId}`
|
|
338
|
+
} as any)
|
|
339
|
+
|
|
340
|
+
if (!response.errors) {
|
|
341
|
+
const items = response.data.inventoryProductGroup.items || []
|
|
342
|
+
if (!items?.length)
|
|
343
|
+
context.throw(
|
|
344
|
+
404,
|
|
345
|
+
t(
|
|
346
|
+
`error.no inventories found for ${orderInventory.product?.sku} with batch ID ${orderInventory?.batchId}`
|
|
347
|
+
)
|
|
334
348
|
)
|
|
335
|
-
)
|
|
336
349
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
// 3. add more information to orderInventory
|
|
343
|
-
orderInventory.product = { id: item.productId }
|
|
344
|
-
orderInventory.packingType = item.packingType
|
|
345
|
-
orderInventory.batchId = item.batchId
|
|
346
|
-
orderInventory.type = ORDER_TYPES.RELEASE_OF_GOODS
|
|
347
|
-
orderInventory.releaseUomValue = orderInventory.releaseQty * orderInventory.uomValue
|
|
348
|
-
orderInventory.uom = item.uom
|
|
349
|
-
})
|
|
350
|
+
items.forEach(item => {
|
|
351
|
+
if (orderInventory.releaseQty > item.remainQty || orderInventory.releaseQty <= 0) {
|
|
352
|
+
context.throw(404, t(`error.invalid release qty for ${orderInventory.product?.sku}`))
|
|
353
|
+
}
|
|
350
354
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
355
|
+
// 3. add more information to orderInventory
|
|
356
|
+
orderInventory.product = { id: item.productId }
|
|
357
|
+
orderInventory.packingType = item.packingType
|
|
358
|
+
orderInventory.batchId = item.batchId
|
|
359
|
+
orderInventory.type = ORDER_TYPES.RELEASE_OF_GOODS
|
|
360
|
+
orderInventory.releaseUomValue = orderInventory.releaseQty * orderInventory.uomValue
|
|
361
|
+
orderInventory.uom = item.uom
|
|
362
|
+
})
|
|
363
|
+
|
|
364
|
+
delete orderInventory.uomValue
|
|
365
|
+
finalOrderInventories.push(orderInventory)
|
|
366
|
+
} else context.throw(404, t('error.failed to fetch inventory'))
|
|
367
|
+
}
|
|
354
368
|
}
|
|
355
369
|
}
|
|
356
|
-
}
|
|
357
370
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
name
|
|
366
|
-
refNo
|
|
367
|
-
status
|
|
368
|
-
truckNo
|
|
369
|
-
ownTransport
|
|
370
|
-
crossDocking
|
|
371
|
-
marketplaceOrderStatus
|
|
372
|
-
billingAddress
|
|
373
|
-
deliveryAddress1
|
|
374
|
-
deliveryAddress2
|
|
375
|
-
deliveryAddress3
|
|
376
|
-
deliveryAddress4
|
|
377
|
-
deliveryAddress5
|
|
378
|
-
attentionTo
|
|
379
|
-
attentionCompany
|
|
380
|
-
city
|
|
381
|
-
state
|
|
382
|
-
postalCode
|
|
383
|
-
country
|
|
384
|
-
phone1
|
|
385
|
-
phone2
|
|
386
|
-
email
|
|
387
|
-
transporter
|
|
388
|
-
trackingNo
|
|
389
|
-
airwayBill
|
|
390
|
-
invoice
|
|
391
|
-
type
|
|
392
|
-
arrivalNotice {
|
|
371
|
+
context.body = {
|
|
372
|
+
result: (
|
|
373
|
+
await client.mutate({
|
|
374
|
+
mutation: gql`
|
|
375
|
+
mutation addReleaseGood($releaseGood: NewReleaseGood, $shippingOrder: ShippingOrderPatch, $file: Upload) {
|
|
376
|
+
addReleaseGood(releaseGood: $releaseGood, shippingOrder: $shippingOrder, file: $file) {
|
|
377
|
+
id
|
|
393
378
|
name
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
379
|
+
refNo
|
|
380
|
+
status
|
|
381
|
+
truckNo
|
|
382
|
+
ownTransport
|
|
383
|
+
crossDocking
|
|
384
|
+
marketplaceOrderStatus
|
|
385
|
+
billingAddress
|
|
386
|
+
deliveryAddress1
|
|
387
|
+
deliveryAddress2
|
|
388
|
+
deliveryAddress3
|
|
389
|
+
deliveryAddress4
|
|
390
|
+
deliveryAddress5
|
|
391
|
+
attentionTo
|
|
392
|
+
attentionCompany
|
|
393
|
+
city
|
|
394
|
+
state
|
|
395
|
+
postalCode
|
|
396
|
+
country
|
|
397
|
+
phone1
|
|
398
|
+
phone2
|
|
399
|
+
email
|
|
400
|
+
transporter
|
|
401
|
+
trackingNo
|
|
402
|
+
airwayBill
|
|
403
|
+
invoice
|
|
404
|
+
type
|
|
405
|
+
arrivalNotice {
|
|
404
406
|
name
|
|
405
|
-
description
|
|
406
407
|
}
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
releaseUomValue
|
|
412
|
-
}
|
|
413
|
-
orderVass {
|
|
414
|
-
vas {
|
|
408
|
+
exportOption
|
|
409
|
+
releaseDate
|
|
410
|
+
collectionOrderNo
|
|
411
|
+
bizplace {
|
|
415
412
|
name
|
|
416
|
-
operationGuide
|
|
417
|
-
operationGuideType
|
|
418
413
|
}
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
414
|
+
orderInventories {
|
|
415
|
+
product {
|
|
416
|
+
sku
|
|
417
|
+
name
|
|
418
|
+
description
|
|
419
|
+
}
|
|
420
|
+
batchId
|
|
421
|
+
packingType
|
|
422
|
+
packingSize
|
|
423
|
+
releaseQty
|
|
424
|
+
releaseUomValue
|
|
425
|
+
}
|
|
426
|
+
orderVass {
|
|
427
|
+
vas {
|
|
428
|
+
name
|
|
429
|
+
operationGuide
|
|
430
|
+
operationGuideType
|
|
431
|
+
}
|
|
432
|
+
set
|
|
433
|
+
targetType
|
|
434
|
+
targetBatchId
|
|
435
|
+
targetProduct {
|
|
436
|
+
name
|
|
437
|
+
description
|
|
438
|
+
}
|
|
439
|
+
packingType
|
|
440
|
+
qty
|
|
441
|
+
uomValue
|
|
442
|
+
otherTarget
|
|
424
443
|
description
|
|
444
|
+
remark
|
|
445
|
+
status
|
|
446
|
+
operationGuide
|
|
425
447
|
}
|
|
426
|
-
packingType
|
|
427
|
-
qty
|
|
428
|
-
uomValue
|
|
429
|
-
otherTarget
|
|
430
|
-
description
|
|
431
|
-
remark
|
|
432
|
-
status
|
|
433
|
-
operationGuide
|
|
434
448
|
}
|
|
435
449
|
}
|
|
450
|
+
`,
|
|
451
|
+
variables: {
|
|
452
|
+
releaseGood: {
|
|
453
|
+
customerBizplaceId: customerBizplace.id,
|
|
454
|
+
courierOption: bodyReq.courierOption,
|
|
455
|
+
collectionOrderNo: bodyReq.collectionOrderNo,
|
|
456
|
+
exportOption: bodyReq.exportOption,
|
|
457
|
+
orderInventories: finalOrderInventories,
|
|
458
|
+
ownTransport: bodyReq.ownTransport,
|
|
459
|
+
packingOption: bodyReq.packingOption,
|
|
460
|
+
refNo: bodyReq.refNo,
|
|
461
|
+
refNo2: bodyReq?.refNo2,
|
|
462
|
+
releaseDate: bodyReq.releaseDate,
|
|
463
|
+
type: bodyReq.type,
|
|
464
|
+
marketplaceOrderStatus: bodyReq?.marketplaceOrderStatus,
|
|
465
|
+
billingAddress: bodyReq?.billTo?.billingAddress || null,
|
|
466
|
+
deliveryAddress1: bodyReq?.deliverTo?.deliveryAddress1 || null,
|
|
467
|
+
deliveryAddress2: bodyReq?.deliverTo?.deliveryAddress2 || null,
|
|
468
|
+
deliveryAddress3: bodyReq?.deliverTo?.deliveryAddress3 || null,
|
|
469
|
+
deliveryAddress4: bodyReq?.deliverTo?.deliveryAddress4 || null,
|
|
470
|
+
deliveryAddress5: bodyReq?.deliverTo?.deliveryAddress5 || null,
|
|
471
|
+
attentionTo: bodyReq?.deliverTo?.attentionTo || null,
|
|
472
|
+
attentionCompany: bodyReq?.deliverTo?.attentionCompany || null,
|
|
473
|
+
city: bodyReq?.deliverTo?.city || null,
|
|
474
|
+
state: bodyReq?.deliverTo?.state || null,
|
|
475
|
+
postalCode: bodyReq?.deliverTo?.postalCode || null,
|
|
476
|
+
country: bodyReq?.deliverTo?.country || null,
|
|
477
|
+
phone1: bodyReq?.deliverTo?.phone1 || null,
|
|
478
|
+
phone2: bodyReq?.deliverTo?.phone2 || null,
|
|
479
|
+
email: bodyReq?.deliverTo?.email || null,
|
|
480
|
+
transporter: bodyReq?.transporter,
|
|
481
|
+
trackingNo: bodyReq?.trackingNo,
|
|
482
|
+
airwayBill: bodyReq?.airwayBill,
|
|
483
|
+
invoice: bodyReq?.invoice
|
|
484
|
+
}
|
|
485
|
+
},
|
|
486
|
+
context: {
|
|
487
|
+
...context,
|
|
488
|
+
hasUpload: true,
|
|
489
|
+
state: {
|
|
490
|
+
...context.state,
|
|
491
|
+
customerBizplace,
|
|
492
|
+
domain,
|
|
493
|
+
type: 'api'
|
|
494
|
+
}
|
|
436
495
|
}
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
courierOption: bodyReq.courierOption,
|
|
442
|
-
collectionOrderNo: bodyReq.collectionOrderNo,
|
|
443
|
-
exportOption: bodyReq.exportOption,
|
|
444
|
-
orderInventories: finalOrderInventories,
|
|
445
|
-
ownTransport: bodyReq.ownTransport,
|
|
446
|
-
packingOption: bodyReq.packingOption,
|
|
447
|
-
refNo: bodyReq.refNo,
|
|
448
|
-
refNo2: bodyReq?.refNo2,
|
|
449
|
-
releaseDate: bodyReq.releaseDate,
|
|
450
|
-
type: bodyReq.type,
|
|
451
|
-
marketplaceOrderStatus: bodyReq?.marketplaceOrderStatus,
|
|
452
|
-
billingAddress: bodyReq?.billTo?.billingAddress || null,
|
|
453
|
-
deliveryAddress1: bodyReq?.deliverTo?.deliveryAddress1 || null,
|
|
454
|
-
deliveryAddress2: bodyReq?.deliverTo?.deliveryAddress2 || null,
|
|
455
|
-
deliveryAddress3: bodyReq?.deliverTo?.deliveryAddress3 || null,
|
|
456
|
-
deliveryAddress4: bodyReq?.deliverTo?.deliveryAddress4 || null,
|
|
457
|
-
deliveryAddress5: bodyReq?.deliverTo?.deliveryAddress5 || null,
|
|
458
|
-
attentionTo: bodyReq?.deliverTo?.attentionTo || null,
|
|
459
|
-
attentionCompany: bodyReq?.deliverTo?.attentionCompany || null,
|
|
460
|
-
city: bodyReq?.deliverTo?.city || null,
|
|
461
|
-
state: bodyReq?.deliverTo?.state || null,
|
|
462
|
-
postalCode: bodyReq?.deliverTo?.postalCode || null,
|
|
463
|
-
country: bodyReq?.deliverTo?.country || null,
|
|
464
|
-
phone1: bodyReq?.deliverTo?.phone1 || null,
|
|
465
|
-
phone2: bodyReq?.deliverTo?.phone2 || null,
|
|
466
|
-
email: bodyReq?.deliverTo?.email || null,
|
|
467
|
-
transporter: bodyReq?.transporter,
|
|
468
|
-
trackingNo: bodyReq?.trackingNo,
|
|
469
|
-
airwayBill: bodyReq?.airwayBill,
|
|
470
|
-
invoice: bodyReq?.invoice
|
|
471
|
-
}
|
|
472
|
-
},
|
|
473
|
-
context: {
|
|
474
|
-
...context,
|
|
475
|
-
hasUpload: true,
|
|
476
|
-
state: {
|
|
477
|
-
...context.state,
|
|
478
|
-
customerBizplace,
|
|
479
|
-
domain,
|
|
480
|
-
type: 'api'
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
} as any)
|
|
484
|
-
).data
|
|
485
|
-
}
|
|
496
|
+
} as any)
|
|
497
|
+
).data
|
|
498
|
+
}
|
|
499
|
+
})
|
|
486
500
|
}
|
|
487
501
|
)
|
|
488
502
|
|
|
@@ -513,9 +527,18 @@ export async function checkMandatoryKey(context, params) {
|
|
|
513
527
|
}
|
|
514
528
|
|
|
515
529
|
if ('orderInventories' in params) {
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
530
|
+
params.orderInventories.forEach((param, key) => {
|
|
531
|
+
let noSubParams = []
|
|
532
|
+
|
|
533
|
+
if (!param?.releaseQty) noSubParams.push('releaseQty')
|
|
534
|
+
|
|
535
|
+
if (!param?.product) noSubParams.push('product')
|
|
536
|
+
|
|
537
|
+
if (noSubParams?.length)
|
|
538
|
+
context.throw(400, context.t('error.required param x not found', { x: `${noSubParams.join(', ')}` }))
|
|
539
|
+
})
|
|
540
|
+
} else {
|
|
541
|
+
noparams.push('orderInventories')
|
|
519
542
|
}
|
|
520
543
|
|
|
521
544
|
if (noparams?.length) {
|