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