@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.
@@ -1,5 +1,5 @@
1
1
  import gql from 'graphql-tag'
2
- import { getRepository, SelectQueryBuilder } from 'typeorm'
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
- const { client, domain } = context.state
23
- const { warehouseId: customerBizplaceId } = context.params
24
- const { t } = context
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
- if (!customerBizplaceId) context.throw(404, t('error.warehouse id not found'))
27
+ if (!customerBizplaceId) context.throw(404, t('error.warehouse id not found'))
27
28
 
28
- let bodyReq = context.request.body
29
- if (typeof bodyReq === undefined || !Object.keys(bodyReq)?.length) {
30
- context.throw(400, t('error.invalid body request format'))
31
- }
32
- debug('post:/add-release-order request.body', bodyReq)
33
- await checkMandatoryKey(context, bodyReq)
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
- const isAutoAssign: Boolean = bodyReq.hasOwnProperty('isAutoAssign') ? bodyReq.isAutoAssign : true
36
+ const isAutoAssign: Boolean = bodyReq.hasOwnProperty('isAutoAssign') ? bodyReq.isAutoAssign : true
36
37
 
37
- // get customer company's bizplace
38
- const custCompanyBizplace: Bizplace = await getCompanyBizplace(null, null, customerBizplaceId)
39
- const customerBizplace: Bizplace = await getRepository(Bizplace).findOne({
40
- where: { id: customerBizplaceId }
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
- const pickingProductSetting: Setting = await getRepository(Setting).findOne({
44
- where: { domain, name: 'rule-for-picking-product' }
45
- })
44
+ const pickingProductSetting: Setting = await tx.getRepository(Setting).findOne({
45
+ where: { domain, name: 'rule-for-picking-product' }
46
+ })
46
47
 
47
- let locationSortingRules = []
48
- if (pickingProductSetting) {
49
- let locationSetting = JSON.parse(pickingProductSetting.value)
50
- for (const key in locationSetting) {
51
- locationSortingRules.push({ name: key, desc: locationSetting[key] == 'ASC' ? false : true })
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
- const orderInventories: OrderInventory[] = bodyReq.orderInventories
56
- let newOrderInventories: OrderInventory[] = []
56
+ const orderInventories: OrderInventory[] = bodyReq.orderInventories
57
+ let newOrderInventories: OrderInventory[] = []
57
58
 
58
- await Promise.all(
59
- orderInventories.map(async orderInventory => {
60
- const sku: string = orderInventory.product?.sku
61
- const refCode: string = orderInventory.product?.refCode
62
- const packingType: string = orderInventory.packingType
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
- const qb: SelectQueryBuilder<ProductDetail> = getRepository(ProductDetail)
65
- .createQueryBuilder('PD')
66
- .innerJoinAndSelect('PD.product', 'PROD')
67
- .where('PROD.bizplace_id = :bizplaceId', { bizplaceId: custCompanyBizplace.id })
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
- if (sku) {
70
- qb.andWhere('PROD.sku = :sku', { sku })
71
+ if (!sku && !refCode) {
72
+ context.throw(404, t('error.sku or refCode not found'))
73
+ }
71
74
 
72
- if (packingType) {
73
- qb.andWhere('PD.packing_type = :packingType', { packingType })
75
+ if (refCode) {
76
+ qb.andWhere('PD.ref_code = :refCode', { refCode })
74
77
  }
75
- }
76
78
 
77
- if (refCode) {
78
- qb.andWhere('PD.ref_code = :refCode', { refCode })
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
- const productDetail: ProductDetail = await qb.getOne()
87
+ const productDetail: ProductDetail = await qb.getOne()
86
88
 
87
- if (productDetail) {
88
- let newOrderInventory: OrderInventory = Object.assign({}, orderInventory)
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
- if (!productDetail) {
98
- const qb: SelectQueryBuilder<ProductDetail> = getRepository(ProductBundle)
99
- .createQueryBuilder('PB')
100
- .innerJoinAndSelect('PB.productBundleSettings', 'PBS')
101
- .innerJoinAndSelect('PBS.productDetail', 'PBD')
102
- .innerJoinAndSelect('PBD.product', 'PROD')
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 (sku) {
106
- qb.andWhere('PB.sku = :sku', { sku })
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 (packingType) {
109
- qb.andWhere('PB.packing_type = :packingType', { packingType })
112
+ if (refCode) {
113
+ qb.andWhere('PB.ref_code = :refCode', { refCode })
110
114
  }
111
- }
112
115
 
113
- if (refCode) {
114
- qb.andWhere('PB.ref_code = :refCode', { refCode })
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
- const foundProductBundle: ProductBundle = await qb.getOne()
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
- if (foundProductBundle) {
124
- const bundleProductSettings: any[] = foundProductBundle.productBundleSettings
125
- bundleProductSettings.map(bundleProductSetting => {
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
- let newOrderInventory: OrderInventory = Object.assign({}, orderInventory)
129
- newOrderInventory.product.sku = productDetailBundle.product.sku
130
- newOrderInventory.packingType = productDetailBundle.packingType
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
- // 2. get all inventory data according to SKU and batchId
168
- const response = await client.query({
169
- query: gql`
170
- query inventoriesByPallet($filters: [Filter]) {
171
- inventoriesByPallet(filters: $filters) {
172
- items {
173
- product {
174
- id
175
- name
176
- description
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
- batchId
179
- packingType
180
- remainQty
181
- remainWeight
182
- remainUomValue
197
+ total
183
198
  }
184
- total
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
- variables: { filters, locationSortingRules },
189
- context: {
190
- ...context,
191
- state: {
192
- ...context.state,
193
- bizplace: customerBizplace,
194
- domain
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
- items.forEach(item => {
210
- if (orderInventory.releaseQty > item.remainQty || orderInventory.releaseQty <= 0) {
211
- context.throw(404, t(`error.invalid release qty for ${orderInventory.product?.sku}`))
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
- // 3. add more information to orderInventory
215
- orderInventory.product.id = item.product.id
216
- orderInventory.packingType = item.packingType
217
- orderInventory.batchId = item.batchId
218
- orderInventory.type = ORDER_TYPES.RELEASE_OF_GOODS
219
- orderInventory.releaseUomValue = orderInventory.releaseQty * orderInventory.uomValue
220
- orderInventory.uom = item.uom
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
- return orderInventory
224
- } else context.throw(404, t('error.failed to fetch inventory'))
225
- })
226
- )
227
- } else {
228
- // Case 2. Some of order inventories doesn't have specified batch id
229
- // MMS order doesn't have batch ID field.
230
- // To cover this case first result of found inventory will be a target of RO
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
- if (locationSortingRules?.length > 0) {
254
- locationSortingRules.forEach((rule: { name: string; desc: boolean }, idx: number) => {
255
- idx === 0
256
- ? qb.addOrderBy(`loc.${rule.name}`, rule.desc ? 'DESC' : 'ASC')
257
- : qb.addOrderBy(`loc.${rule.name}`, rule.desc ? 'DESC' : 'ASC')
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
- qb.addOrderBy('"iv"."created_at"', 'ASC')
261
- }
262
-
263
- let inventories: Inventory[] = await qb.getMany()
264
- if (!inventories?.length) context.throw(404, t(`error.no inventories found for ${product.sku}`))
265
-
266
- inventories = inventories.map(inventory => {
267
- return {
268
- ...inventory,
269
- remainQty: inventory.qty - inventory.lockedQty,
270
- remainUomValue: inventory.uomValue - inventory.lockedUomValue
271
- }
272
- })
273
-
274
- const targetInventories: WorksheetDetail[] = _composeTargetInventories(
275
- context,
276
- product,
277
- orderInventory,
278
- inventories
279
- )
280
- targetInventories.map(item => {
281
- finalOrderInventories.push(item.targetInventory)
282
- })
283
- } else {
284
- let filters: any = [
285
- {
286
- name: 'productName',
287
- operator: 'eq',
288
- value: orderInventory.product.sku
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
- total
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
- variables: { filters },
317
- context: {
318
- ...context,
319
- state: {
320
- ...context.state,
321
- bizplace: customerBizplace,
322
- domain
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
- items.forEach(item => {
338
- if (orderInventory.releaseQty > item.remainQty || orderInventory.releaseQty <= 0) {
339
- context.throw(404, t(`error.invalid release qty for ${orderInventory.product?.sku}`))
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
- delete orderInventory.uomValue
352
- finalOrderInventories.push(orderInventory)
353
- } else context.throw(404, t('error.failed to fetch inventory'))
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
- context.body = {
359
- result: (
360
- await client.mutate({
361
- mutation: gql`
362
- mutation addReleaseGood($releaseGood: NewReleaseGood, $shippingOrder: ShippingOrderPatch, $file: Upload) {
363
- addReleaseGood(releaseGood: $releaseGood, shippingOrder: $shippingOrder, file: $file) {
364
- id
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
- exportOption
396
- releaseDate
397
- collectionOrderNo
398
- bizplace {
399
- name
400
- }
401
- orderInventories {
402
- product {
403
- sku
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
- batchId
408
- packingType
409
- packingSize
410
- releaseQty
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
- set
420
- targetType
421
- targetBatchId
422
- targetProduct {
423
- name
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
- variables: {
439
- releaseGood: {
440
- customerBizplaceId: customerBizplace.id,
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
- if (params.orderInventories.filter(record => !record.releaseQty || !record.product).length) {
517
- noparams.push('orderInventories')
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) {