@things-factory/worksheet-base 4.3.186 → 4.3.188

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.
Files changed (115) hide show
  1. package/dist-server/constants/worksheet.js +3 -1
  2. package/dist-server/constants/worksheet.js.map +1 -1
  3. package/dist-server/controllers/ecommerce/sellercraft-controller.js +14 -3
  4. package/dist-server/controllers/ecommerce/sellercraft-controller.js.map +1 -1
  5. package/dist-server/controllers/index.js +1 -0
  6. package/dist-server/controllers/index.js.map +1 -1
  7. package/dist-server/controllers/outbound/picking-worksheet-controller.js +6 -2
  8. package/dist-server/controllers/outbound/picking-worksheet-controller.js.map +1 -1
  9. package/dist-server/controllers/replenishment/index.js +18 -0
  10. package/dist-server/controllers/replenishment/index.js.map +1 -0
  11. package/dist-server/controllers/replenishment/replenishment-worksheet-controller.js +455 -0
  12. package/dist-server/controllers/replenishment/replenishment-worksheet-controller.js.map +1 -0
  13. package/dist-server/controllers/worksheet-controller.js +32 -9
  14. package/dist-server/controllers/worksheet-controller.js.map +1 -1
  15. package/dist-server/entities/index.js +10 -2
  16. package/dist-server/entities/index.js.map +1 -1
  17. package/dist-server/entities/warehouse-bizplace-onhand-inventory.js +15 -1
  18. package/dist-server/entities/warehouse-bizplace-onhand-inventory.js.map +1 -1
  19. package/dist-server/entities/warehouse-inventory-assignment-ranking.js +37 -0
  20. package/dist-server/entities/warehouse-inventory-assignment-ranking.js.map +1 -0
  21. package/dist-server/entities/worksheet.js +13 -9
  22. package/dist-server/entities/worksheet.js.map +1 -1
  23. package/dist-server/graphql/resolvers/worksheet/cancel-replenishment.js +57 -0
  24. package/dist-server/graphql/resolvers/worksheet/cancel-replenishment.js.map +1 -0
  25. package/dist-server/graphql/resolvers/worksheet/generate-worksheet/generate-release-good-worksheet.js +7 -1
  26. package/dist-server/graphql/resolvers/worksheet/generate-worksheet/generate-release-good-worksheet.js.map +1 -1
  27. package/dist-server/graphql/resolvers/worksheet/generate-worksheet/generate-replenishement-worksheet.js +19 -0
  28. package/dist-server/graphql/resolvers/worksheet/generate-worksheet/generate-replenishement-worksheet.js.map +1 -0
  29. package/dist-server/graphql/resolvers/worksheet/generate-worksheet/index.js +2 -1
  30. package/dist-server/graphql/resolvers/worksheet/generate-worksheet/index.js.map +1 -1
  31. package/dist-server/graphql/resolvers/worksheet/index.js +5 -2
  32. package/dist-server/graphql/resolvers/worksheet/index.js.map +1 -1
  33. package/dist-server/graphql/resolvers/worksheet/inventories-by-pallet.js +3 -1
  34. package/dist-server/graphql/resolvers/worksheet/inventories-by-pallet.js.map +1 -1
  35. package/dist-server/graphql/resolvers/worksheet/picking/complete-picking.js +284 -270
  36. package/dist-server/graphql/resolvers/worksheet/picking/complete-picking.js.map +1 -1
  37. package/dist-server/graphql/resolvers/worksheet/picking/index.js +2 -1
  38. package/dist-server/graphql/resolvers/worksheet/picking/index.js.map +1 -1
  39. package/dist-server/graphql/resolvers/worksheet/picking/replenishment-picking.js +12 -0
  40. package/dist-server/graphql/resolvers/worksheet/picking/replenishment-picking.js.map +1 -0
  41. package/dist-server/graphql/resolvers/worksheet/picking-worksheet.js +142 -78
  42. package/dist-server/graphql/resolvers/worksheet/picking-worksheet.js.map +1 -1
  43. package/dist-server/graphql/resolvers/worksheet/putaway/complete-replenishment-putaway.js +16 -0
  44. package/dist-server/graphql/resolvers/worksheet/putaway/complete-replenishment-putaway.js.map +1 -0
  45. package/dist-server/graphql/resolvers/worksheet/putaway/index.js +4 -1
  46. package/dist-server/graphql/resolvers/worksheet/putaway/index.js.map +1 -1
  47. package/dist-server/graphql/resolvers/worksheet/putaway/replenishment-putaway.js +15 -0
  48. package/dist-server/graphql/resolvers/worksheet/putaway/replenishment-putaway.js.map +1 -0
  49. package/dist-server/graphql/resolvers/worksheet/putaway/undo-replenishment-putaway.js +16 -0
  50. package/dist-server/graphql/resolvers/worksheet/putaway/undo-replenishment-putaway.js.map +1 -0
  51. package/dist-server/graphql/resolvers/worksheet/putaway-replenishment-worksheet.js +81 -0
  52. package/dist-server/graphql/resolvers/worksheet/putaway-replenishment-worksheet.js.map +1 -0
  53. package/dist-server/graphql/resolvers/worksheet/replenishment/activate-picking-replenishment.js +17 -0
  54. package/dist-server/graphql/resolvers/worksheet/replenishment/activate-picking-replenishment.js.map +1 -0
  55. package/dist-server/graphql/resolvers/worksheet/replenishment/index.js +6 -0
  56. package/dist-server/graphql/resolvers/worksheet/replenishment/index.js.map +1 -0
  57. package/dist-server/graphql/resolvers/worksheet/worksheet.js +1 -0
  58. package/dist-server/graphql/resolvers/worksheet/worksheet.js.map +1 -1
  59. package/dist-server/graphql/resolvers/worksheet/worksheets.js +28 -2
  60. package/dist-server/graphql/resolvers/worksheet/worksheets.js.map +1 -1
  61. package/dist-server/graphql/types/worksheet/index.js +42 -1
  62. package/dist-server/graphql/types/worksheet/index.js.map +1 -1
  63. package/dist-server/graphql/types/worksheet/replenish-inventory-patch.js +11 -0
  64. package/dist-server/graphql/types/worksheet/replenish-inventory-patch.js.map +1 -0
  65. package/dist-server/graphql/types/worksheet/worksheet-info.js +1 -0
  66. package/dist-server/graphql/types/worksheet/worksheet-info.js.map +1 -1
  67. package/dist-server/graphql/types/worksheet/worksheet.js +1 -0
  68. package/dist-server/graphql/types/worksheet/worksheet.js.map +1 -1
  69. package/dist-server/utils/datetime-util.js +13 -1
  70. package/dist-server/utils/datetime-util.js.map +1 -1
  71. package/dist-server/utils/inventory-util.js +2 -0
  72. package/dist-server/utils/inventory-util.js.map +1 -1
  73. package/dist-server/utils/worksheet-no-generator.js +21 -1
  74. package/dist-server/utils/worksheet-no-generator.js.map +1 -1
  75. package/dist-server/utils/worksheet-util.js +3 -0
  76. package/dist-server/utils/worksheet-util.js.map +1 -1
  77. package/package.json +5 -5
  78. package/server/constants/worksheet.ts +3 -1
  79. package/server/controllers/ecommerce/sellercraft-controller.ts +25 -6
  80. package/server/controllers/index.ts +1 -1
  81. package/server/controllers/outbound/picking-worksheet-controller.ts +12 -3
  82. package/server/controllers/replenishment/index.ts +1 -0
  83. package/server/controllers/replenishment/replenishment-worksheet-controller.ts +632 -0
  84. package/server/controllers/worksheet-controller.ts +47 -13
  85. package/server/entities/index.ts +15 -2
  86. package/server/entities/warehouse-bizplace-onhand-inventory.ts +13 -1
  87. package/server/entities/warehouse-inventory-assignment-ranking.ts +19 -0
  88. package/server/entities/worksheet.ts +5 -1
  89. package/server/graphql/resolvers/worksheet/cancel-replenishment.ts +69 -0
  90. package/server/graphql/resolvers/worksheet/generate-worksheet/generate-release-good-worksheet.ts +6 -1
  91. package/server/graphql/resolvers/worksheet/generate-worksheet/generate-replenishement-worksheet.ts +30 -0
  92. package/server/graphql/resolvers/worksheet/generate-worksheet/index.ts +3 -1
  93. package/server/graphql/resolvers/worksheet/index.ts +8 -2
  94. package/server/graphql/resolvers/worksheet/inventories-by-pallet.ts +4 -2
  95. package/server/graphql/resolvers/worksheet/picking/complete-picking.ts +342 -310
  96. package/server/graphql/resolvers/worksheet/picking/index.ts +3 -1
  97. package/server/graphql/resolvers/worksheet/picking/replenishment-picking.ts +27 -0
  98. package/server/graphql/resolvers/worksheet/picking-worksheet.ts +177 -95
  99. package/server/graphql/resolvers/worksheet/putaway/complete-replenishment-putaway.ts +25 -0
  100. package/server/graphql/resolvers/worksheet/putaway/index.ts +7 -1
  101. package/server/graphql/resolvers/worksheet/putaway/replenishment-putaway.ts +23 -0
  102. package/server/graphql/resolvers/worksheet/putaway/undo-replenishment-putaway.ts +22 -0
  103. package/server/graphql/resolvers/worksheet/putaway-replenishment-worksheet.ts +95 -0
  104. package/server/graphql/resolvers/worksheet/replenishment/activate-picking-replenishment.ts +26 -0
  105. package/server/graphql/resolvers/worksheet/replenishment/index.ts +5 -0
  106. package/server/graphql/resolvers/worksheet/worksheet.ts +1 -0
  107. package/server/graphql/resolvers/worksheet/worksheets.ts +38 -3
  108. package/server/graphql/types/worksheet/index.ts +42 -1
  109. package/server/graphql/types/worksheet/replenish-inventory-patch.ts +8 -0
  110. package/server/graphql/types/worksheet/worksheet-info.ts +1 -0
  111. package/server/graphql/types/worksheet/worksheet.ts +1 -0
  112. package/server/utils/datetime-util.ts +14 -0
  113. package/server/utils/inventory-util.ts +3 -0
  114. package/server/utils/worksheet-no-generator.ts +29 -1
  115. package/server/utils/worksheet-util.ts +4 -2
@@ -0,0 +1,632 @@
1
+ import { In, Not, getConnection, EntityManager } from 'typeorm'
2
+
3
+ import {
4
+ ORDER_INVENTORY_STATUS,
5
+ ORDER_STATUS,
6
+ OrderInventory,
7
+ Replenishment,
8
+ ORDER_TYPES,
9
+ ORDER_PRODUCT_STATUS
10
+ } from '@things-factory/sales-base'
11
+
12
+ import { generateId } from '@things-factory/id-rule-base'
13
+ import { DateGenerator } from '../../utils'
14
+ import { WORKSHEET_TYPE, WORKSHEET_STATUS, RULE_TYPE } from '../../constants'
15
+ import { Worksheet, WorksheetDetail } from '../../entities'
16
+ import { WorksheetController } from '../worksheet-controller'
17
+ import { Product, ProductBarcode, ProductDetail } from '@things-factory/product-base'
18
+ import {
19
+ Inventory,
20
+ LOCATION_TYPE,
21
+ InventoryItem,
22
+ INVENTORY_STATUS,
23
+ InventoryNoGenerator,
24
+ INVENTORY_ITEM_SOURCE,
25
+ generateInventoryHistory,
26
+ INVENTORY_TRANSACTION_TYPE,
27
+ Warehouse,
28
+ Location,
29
+ InventoryHistory
30
+ } from '@things-factory/warehouse-base'
31
+
32
+ export class ReplenishmentWorksheetController extends WorksheetController {
33
+ async generateReplenishmentWorksheet(replenishmentNo: string): Promise<Worksheet> {
34
+ let replenishment: Replenishment = await this.findRefOrder(
35
+ Replenishment,
36
+ {
37
+ domain: this.domain,
38
+ name: replenishmentNo,
39
+ status: ORDER_STATUS.PENDING_WORKSHEET
40
+ },
41
+ ['orderInventories', 'orderInventories.inventory', 'orderInventories.bizplace']
42
+ )
43
+ const orderInventories: OrderInventory[] = replenishment.orderInventories
44
+
45
+ let worksheet: Worksheet = await this.createWorksheet(replenishment, WORKSHEET_TYPE.PICKING_REPLENISHMENT)
46
+
47
+ if (orderInventories.every((oi: OrderInventory) => oi.inventory?.id)) {
48
+ worksheet.worksheetDetails = await this.createWorksheetDetails(
49
+ worksheet,
50
+ WORKSHEET_TYPE.PICKING_REPLENISHMENT,
51
+ orderInventories
52
+ )
53
+ }
54
+
55
+ await this.trxMgr
56
+ .getRepository(OrderInventory)
57
+ .update(
58
+ { id: In(orderInventories.map(oi => oi.id)) },
59
+ { status: ORDER_INVENTORY_STATUS.READY_TO_PICK, updater: this.user }
60
+ )
61
+
62
+ await this.trxMgr
63
+ .getRepository(Replenishment)
64
+ .update({ id: replenishment.id }, { status: ORDER_STATUS.READY_TO_PICK, updater: this.user })
65
+
66
+ return worksheet
67
+ }
68
+
69
+ async activatePickingReplenishment(worksheetNo: string): Promise<Worksheet> {
70
+ let worksheet: Worksheet = await this.findActivatableWorksheet(worksheetNo, WORKSHEET_TYPE.PICKING_REPLENISHMENT, [
71
+ 'replenishment',
72
+ 'worksheetDetails',
73
+ 'worksheetDetails.targetInventory'
74
+ ])
75
+ let updater = this.user
76
+ const worksheetDetails: WorksheetDetail[] = worksheet.worksheetDetails.filter(x => x.status == 'DEACTIVATED')
77
+ const targetInventories: OrderInventory[] = worksheetDetails.map(wds => wds.targetInventory)
78
+
79
+ await this.trxMgr
80
+ .getRepository(OrderInventory)
81
+ .update({ id: In(targetInventories.map(itm => itm.id)) }, { status: ORDER_INVENTORY_STATUS.PICKING, updater })
82
+
83
+ let replenishment: Replenishment = worksheet.replenishment
84
+ await this.trxMgr
85
+ .getRepository(Replenishment)
86
+ .update({ id: replenishment.id }, { status: ORDER_STATUS.PICKING, updater })
87
+
88
+ worksheet = await this.activateWorksheet(worksheet, worksheetDetails, [])
89
+
90
+ return worksheet
91
+ }
92
+
93
+ async replenishmentPicking(
94
+ worksheetDetailName: string,
95
+ worksheetType: string,
96
+ productBarcode: string,
97
+ cartonId: string,
98
+ binLocation?: string,
99
+ serialNumber?: string,
100
+ pickedQty: number = 1
101
+ ): Promise<WorksheetDetail> {
102
+ try {
103
+ //find existing worksheet detail
104
+ let worksheetDetail: WorksheetDetail = await this.trxMgr
105
+ .getRepository(WorksheetDetail)
106
+ .createQueryBuilder('wd')
107
+ .innerJoinAndSelect('wd.worksheet', 'ws')
108
+ .innerJoinAndSelect('wd.targetInventory', 'oi')
109
+ .innerJoinAndSelect('oi.replenishment', 'rp')
110
+ .innerJoinAndSelect('oi.inventory', 'inv')
111
+ .innerJoinAndSelect('oi.product', 'prd')
112
+ .innerJoinAndSelect('oi.productDetail', 'pd')
113
+ .innerJoinAndSelect('pd.productBarcodes', 'pb')
114
+ .where('wd.name = :name', { name: worksheetDetailName })
115
+ .andWhere('wd.domain_id = :domainId', { domainId: this.domain.id })
116
+ .andWhere('wd.type = :type', { type: worksheetType })
117
+ .andWhere('wd.status = :status', { status: WORKSHEET_STATUS.EXECUTING })
118
+ .andWhere('inv.carton_id = :cartonId', { cartonId: cartonId })
119
+ .getOne()
120
+
121
+ //validation to check matching worksheet detail based on name
122
+ if (!worksheetDetail) throw new Error(this.ERROR_MSG.FIND.NO_RESULT(worksheetDetailName))
123
+
124
+ const replenishment: Replenishment = worksheetDetail.targetInventory.replenishment
125
+ let targetInventory: OrderInventory = worksheetDetail.targetInventory
126
+ const product: Product = targetInventory.product
127
+ const productDetail: ProductDetail = targetInventory.productDetail
128
+ const productBarcodes: [ProductBarcode] = productDetail.productBarcodes
129
+ let inventory: Inventory = targetInventory.inventory
130
+ let pickedUomValue = pickedQty * productDetail.uomValue
131
+ let matchingProduct
132
+
133
+ //validation to prevent duplicated picking
134
+ if (targetInventory?.status != ORDER_INVENTORY_STATUS.PICKING)
135
+ throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `is done`))
136
+
137
+ if (!productBarcodes.find(itm => itm.gtin == productBarcode) && product?.isRequireSerialNumberScanningOutbound) {
138
+ throw new Error(this.ERROR_MSG.FIND.NO_RESULT(productBarcode))
139
+ }
140
+
141
+ matchingProduct = await this.getDirectQty(
142
+ {
143
+ ...productDetail,
144
+ product: targetInventory?.product
145
+ },
146
+ productBarcode,
147
+ pickedQty
148
+ )
149
+
150
+ //validate matching product details based on scanned barcode
151
+ if (!matchingProduct) throw new Error(this.ERROR_MSG.FIND.NO_RESULT(productBarcode))
152
+
153
+ pickedQty = matchingProduct.qty
154
+ pickedUomValue = matchingProduct.uomValue
155
+
156
+ //validation to prevent over release
157
+ if (
158
+ !worksheetDetail?.targetInventory ||
159
+ worksheetDetail?.targetInventory.inventory.qty < 1 ||
160
+ pickedQty + (worksheetDetail.targetInventory?.pickedQty || 0) > worksheetDetail.targetInventory.releaseQty
161
+ )
162
+ throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `over release`))
163
+
164
+ targetInventory = await this.checkAndSetBinPicking(targetInventory, binLocation)
165
+
166
+ // for required outbound serial number scanning
167
+ if (product?.isRequireSerialNumberScanningOutbound) {
168
+ if (!serialNumber || serialNumber == '') {
169
+ throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `require serial number`))
170
+ }
171
+
172
+ let totalInventoryItems = await this.trxMgr.getRepository(InventoryItem).count({
173
+ where: {
174
+ inventory,
175
+ status: Not(In([INVENTORY_STATUS.TERMINATED, INVENTORY_STATUS.PICKED]))
176
+ }
177
+ })
178
+
179
+ let foundSerialNumber: InventoryItem = await this.trxMgr
180
+ .getRepository(InventoryItem)
181
+ .findOne({ where: { domain: this.domain, serialNumber: serialNumber, product } })
182
+
183
+ if (foundSerialNumber) {
184
+ if (foundSerialNumber.inventoryId !== inventory.id) {
185
+ throw new Error('Serial Number scanned is in another inventory')
186
+ }
187
+
188
+ if (foundSerialNumber.outboundOrderId) {
189
+ let replenishment: Replenishment = await this.trxMgr
190
+ .getRepository(Replenishment)
191
+ .findOne({ where: { id: foundSerialNumber.outboundOrderId } })
192
+ throw new Error(`Inventory Item is already picked in ${replenishment.name}`)
193
+ }
194
+
195
+ foundSerialNumber.status = INVENTORY_STATUS.PICKING
196
+ foundSerialNumber.updater = this.user
197
+ foundSerialNumber.outboundOrderId = replenishment.id
198
+
199
+ await this.trxMgr.getRepository(InventoryItem).save(foundSerialNumber)
200
+ } else {
201
+ if (totalInventoryItems >= inventory.qty) {
202
+ throw new Error('Insufficient inventory quantity to scan new serial number')
203
+ }
204
+
205
+ let inventoryItem: InventoryItem = new InventoryItem()
206
+ inventoryItem.name = InventoryNoGenerator.inventoryItemName()
207
+ inventoryItem.serialNumber = serialNumber
208
+ inventoryItem.status = INVENTORY_STATUS.PICKING
209
+ inventoryItem.outboundOrderId = replenishment.id
210
+ inventoryItem.source = INVENTORY_ITEM_SOURCE.OUTBOUND
211
+ inventoryItem.product = product
212
+ inventoryItem.productDetail = productDetail
213
+ inventoryItem.inventory = inventory
214
+ inventoryItem.domain = this.domain
215
+
216
+ await this.trxMgr.getRepository(InventoryItem).save(inventoryItem)
217
+ }
218
+ }
219
+
220
+ const releaseQty: number = targetInventory.releaseQty
221
+
222
+ targetInventory.pickedQty = (targetInventory?.pickedQty || 0) + pickedQty
223
+
224
+ let updateOiObj = {
225
+ pickedQty: () => `"picked_qty" + ${pickedQty}`,
226
+ updatedAt: new Date(),
227
+ updater: this.user,
228
+ pickedBy: this.user.name,
229
+ pickedByUser: this.user,
230
+ pickedAt: new Date()
231
+ }
232
+
233
+ if (targetInventory.pickedQty == releaseQty) {
234
+ updateOiObj['status'] = ORDER_INVENTORY_STATUS.PICKED
235
+ }
236
+
237
+ if (targetInventory.binLocation) {
238
+ updateOiObj['binLocation'] = targetInventory.binLocation
239
+ }
240
+
241
+ await this.trxMgr
242
+ .getRepository(OrderInventory)
243
+ .createQueryBuilder()
244
+ .update(OrderInventory)
245
+ .set(updateOiObj)
246
+ .where({ id: targetInventory.id })
247
+ .andWhere(`picked_qty + :pickedQty <= release_qty`, { pickedQty })
248
+ .execute()
249
+
250
+ if (targetInventory.pickedQty == releaseQty) {
251
+ //update worksheet details only when line item picking complete
252
+ await this.trxMgr
253
+ .getRepository(WorksheetDetail)
254
+ .createQueryBuilder()
255
+ .update(WorksheetDetail)
256
+ .set({
257
+ status: WORKSHEET_STATUS.DONE,
258
+ updater: this.user,
259
+ updatedAt: new Date()
260
+ })
261
+ .where('id = :id', { id: worksheetDetail.id })
262
+ .execute()
263
+
264
+ getConnection().transaction(async (tx: EntityManager) => {
265
+ let releaseUomValue = Math.round((pickedUomValue / pickedQty) * releaseQty * 100) / 100
266
+
267
+ let updateInvObj = {
268
+ qty: () => `"qty" - ${releaseQty}`,
269
+ uomValue: () => `"uom_value" - ${releaseUomValue}`,
270
+ updater: this.user,
271
+ updatedAt: new Date()
272
+ }
273
+
274
+ let remainingQty = await tx
275
+ .getRepository(Inventory)
276
+ .createQueryBuilder()
277
+ .update(Inventory)
278
+ .set(updateInvObj)
279
+ .where('id = :id', { id: targetInventory.inventory.id })
280
+ .returning(['qty'])
281
+ .execute()
282
+ .then(dt => {
283
+ return dt.raw[0].qty
284
+ })
285
+
286
+ await generateInventoryHistory(
287
+ inventory,
288
+ replenishment,
289
+ INVENTORY_TRANSACTION_TYPE.RELOCATE,
290
+ -releaseQty,
291
+ -releaseUomValue,
292
+ this.user,
293
+ tx
294
+ )
295
+
296
+ let inventoryItems: InventoryItem = await tx
297
+ .getRepository(InventoryItem)
298
+ .find({ where: { outboundOrderId: replenishment.id } })
299
+
300
+ if (inventoryItems.length > 0) {
301
+ inventoryItems.forEach((itm: InventoryItem) => {
302
+ itm.status = INVENTORY_STATUS.PICKED
303
+ itm.updater = this.user
304
+ })
305
+
306
+ await tx.getRepository(InventoryItem).save(inventoryItems)
307
+ }
308
+
309
+ if (remainingQty === 0) {
310
+ await tx
311
+ .getRepository(Inventory)
312
+ .createQueryBuilder()
313
+ .update(Inventory)
314
+ .set({ status: INVENTORY_STATUS.TERMINATED })
315
+ .where('id = :id', { id: targetInventory.inventory.id })
316
+ .execute()
317
+ }
318
+ })
319
+ }
320
+
321
+ // return worksheet details
322
+ worksheetDetail = await this.trxMgr
323
+ .getRepository(WorksheetDetail)
324
+ .createQueryBuilder('wd')
325
+ .innerJoin('wd.targetInventory', 'oi')
326
+ .innerJoinAndSelect('oi.replenishment', 'rg')
327
+ .where('wd.id = :id', { id: worksheetDetail.id })
328
+ .getOne()
329
+
330
+ return worksheetDetail
331
+ } catch (error) {
332
+ throw error
333
+ }
334
+ }
335
+
336
+ private async checkAndSetBinPicking(orderInventory, binLocation) {
337
+ // bin picking validation
338
+ if (binLocation) {
339
+ const foundBinLocation: Location = await this.trxMgr.getRepository(Location).findOne({
340
+ where: { domain: this.domain, name: binLocation, type: LOCATION_TYPE.BIN }
341
+ })
342
+
343
+ if (!foundBinLocation)
344
+ throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `invalid bin location id`))
345
+
346
+ orderInventory.binLocation = foundBinLocation
347
+ }
348
+
349
+ return orderInventory
350
+ }
351
+
352
+ async completeReplenishmentPicking(replenishment: Replenishment, worksheet: Worksheet): Promise<any> {
353
+ await this.checkRecordValidity(worksheet, { status: WORKSHEET_STATUS.EXECUTING })
354
+
355
+ let inventoryItems: InventoryItem = await this.trxMgr
356
+ .getRepository(InventoryItem)
357
+ .find({ where: { outboundOrderId: replenishment.id } })
358
+
359
+ if (inventoryItems.length > 0) {
360
+ inventoryItems.forEach((itm: InventoryItem) => {
361
+ itm.status = INVENTORY_STATUS.RELOCATE
362
+ itm.updater = this.user
363
+ })
364
+
365
+ await this.trxMgr.getRepository(InventoryItem).save(inventoryItems)
366
+ }
367
+
368
+ let orderStatus: string = ORDER_STATUS.PUTTING_AWAY
369
+
370
+ return await this.completeWorksheet(worksheet, orderStatus)
371
+ }
372
+
373
+ async generatePutawayReplenishmentWorksheet(replenishmentNo: string): Promise<Worksheet> {
374
+ let replenishment: Replenishment = await this.findRefOrder(
375
+ Replenishment,
376
+ {
377
+ domain: this.domain,
378
+ name: replenishmentNo
379
+ },
380
+ ['orderInventories', 'orderInventories.inventory']
381
+ )
382
+ let orderInventories: OrderInventory[] = replenishment.orderInventories
383
+
384
+ const existingPutawayReplenishmentWorksheet: Worksheet = await this.trxMgr.getRepository(Worksheet).findOne({
385
+ where: {
386
+ domain: this.domain,
387
+ replenishment,
388
+ type: WORKSHEET_TYPE.PUTAWAY_REPLENISHMENT
389
+ }
390
+ })
391
+
392
+ if (existingPutawayReplenishmentWorksheet)
393
+ throw new Error('There is existing putaway replenishment worksheet that has been generated')
394
+ let worksheet: Worksheet = await this.createWorksheet(replenishment, WORKSHEET_TYPE.PUTAWAY_REPLENISHMENT)
395
+
396
+ if (orderInventories.every((oi: OrderInventory) => oi.inventory?.id)) {
397
+ worksheet.worksheetDetails = await this.createWorksheetDetails(
398
+ worksheet,
399
+ WORKSHEET_TYPE.PUTAWAY_REPLENISHMENT,
400
+ orderInventories
401
+ )
402
+ }
403
+
404
+ orderInventories.forEach((oi: OrderInventory) => {
405
+ oi.status = ORDER_INVENTORY_STATUS.PUTTING_AWAY
406
+ oi.updater = this.user
407
+ })
408
+ await this.updateOrderTargets(orderInventories)
409
+
410
+ return worksheet
411
+ }
412
+
413
+ async replenishmentPutaway(worksheetDetailName: [string], cartonId: string, locationName: string): Promise<void> {
414
+ const worksheetDetails: WorksheetDetail[] = await this.findExecutableWorksheetDetailByNames(
415
+ worksheetDetailName,
416
+ WORKSHEET_TYPE.PUTAWAY_REPLENISHMENT,
417
+ [
418
+ 'worksheet',
419
+ 'worksheet.replenishment',
420
+ 'targetInventory',
421
+ 'targetInventory.inventory',
422
+ 'targetInventory.inventory.bizplace',
423
+ 'targetInventory.inventory.product',
424
+ 'targetInventory.inventory.productDetail'
425
+ ]
426
+ )
427
+
428
+ for (var i = 0; i < worksheetDetails.length; i++) {
429
+ const worksheetDetail = worksheetDetails[i]
430
+ const worksheet: Worksheet = worksheetDetail.worksheet
431
+ const replenishment: Replenishment = worksheet.replenishment
432
+ let targetInventory: OrderInventory = worksheetDetail.targetInventory
433
+ let inventory: Inventory = targetInventory.inventory
434
+
435
+ if (inventory.cartonId !== cartonId) {
436
+ throw new Error(this.ERROR_MSG.VALIDITY.UNEXPECTED_FIELD_VALUE('cartonId', cartonId, inventory.cartonId))
437
+ }
438
+
439
+ const location: Location = await this.trxMgr.getRepository(Location).findOne({
440
+ where: {
441
+ domain: this.domain,
442
+ name: locationName,
443
+ type: In([
444
+ LOCATION_TYPE.SHELF,
445
+ LOCATION_TYPE.BUFFER,
446
+ LOCATION_TYPE.FLOOR,
447
+ LOCATION_TYPE.BIN,
448
+ LOCATION_TYPE.QUARANTINE,
449
+ LOCATION_TYPE.RESERVE
450
+ ])
451
+ },
452
+ relations: ['warehouse']
453
+ })
454
+
455
+ if (!location) throw new Error(this.ERROR_MSG.FIND.NO_RESULT(locationName))
456
+ const warehouse: Warehouse = location.warehouse
457
+ const zone: string = location.zone
458
+
459
+ let updateInvObj = {
460
+ transferQty: () => `"transfer_qty" - ${targetInventory.releaseQty}`,
461
+ transferUomValue: () => `"transfer_uom_value" - ${targetInventory.releaseUomValue}`,
462
+ updater: this.user,
463
+ updatedAt: new Date()
464
+ }
465
+
466
+ await this.trxMgr
467
+ .getRepository(Inventory)
468
+ .createQueryBuilder()
469
+ .update(Inventory)
470
+ .set(updateInvObj)
471
+ .where('id = :id', { id: targetInventory.inventory.id })
472
+ .execute()
473
+
474
+ let newInventory = {
475
+ ...inventory,
476
+ palletId: await generateId({
477
+ domain: this.domain,
478
+ type: RULE_TYPE.LOT_NUMBER_ID,
479
+ seed: { date: DateGenerator.generateDate() }
480
+ }),
481
+ location: location,
482
+ status: INVENTORY_STATUS.STORED,
483
+ warehouse: warehouse,
484
+ zone: zone,
485
+ creator: this.user,
486
+ updater: this.user
487
+ }
488
+
489
+ delete newInventory.id
490
+ delete newInventory.updatedAt
491
+ delete newInventory.created_at
492
+ delete newInventory.adjustmentCode
493
+ delete newInventory.adjustmentNote
494
+
495
+ newInventory.cartonId = cartonId
496
+ newInventory.qty = targetInventory.releaseQty
497
+ newInventory.lockedQty = 0
498
+ newInventory.transferQty = 0
499
+ newInventory.uomValue = targetInventory.releaseUomValue
500
+ newInventory.lockedUomValue = 0
501
+ newInventory.transferUomValue = 0
502
+ newInventory.refOrderId = replenishment.id
503
+
504
+ await this.trxMgr.getRepository(Inventory).save(newInventory)
505
+
506
+ let inventoryItems: InventoryItem = await this.trxMgr
507
+ .getRepository(InventoryItem)
508
+ .find({ where: { outboundOrderId: replenishment.id, inventory, status: INVENTORY_STATUS.RELOCATE } })
509
+
510
+ if (inventoryItems.length > 0) {
511
+ inventoryItems.forEach((itm: InventoryItem) => {
512
+ itm.status = INVENTORY_STATUS.STORED
513
+ itm.source = INVENTORY_ITEM_SOURCE.RELOCATE
514
+ itm.updater = this.user
515
+ itm.inventory = newInventory
516
+ })
517
+
518
+ await this.trxMgr.getRepository(InventoryItem).save(inventoryItems)
519
+ }
520
+
521
+ await this.transactionInventory(
522
+ newInventory,
523
+ replenishment,
524
+ targetInventory.releaseQty,
525
+ targetInventory.releaseUomValue,
526
+ INVENTORY_TRANSACTION_TYPE.RELOCATE
527
+ )
528
+
529
+ targetInventory.status = ORDER_INVENTORY_STATUS.TERMINATED
530
+ targetInventory.updater = this.user
531
+ await this.updateOrderTargets([targetInventory])
532
+
533
+ worksheetDetail.status = WORKSHEET_STATUS.DONE
534
+ worksheetDetail.updater = this.user
535
+ await this.trxMgr.getRepository(WorksheetDetail).save(worksheetDetail)
536
+ }
537
+ }
538
+
539
+ async undoReplenishmentPutaway(worksheetDetailName: [string], cartonId: string): Promise<void> {
540
+ let worksheetDetails: WorksheetDetail[] = await this.findWorksheetDetailByNames(worksheetDetailName, [
541
+ 'worksheet',
542
+ 'worksheet.replenishment',
543
+ 'targetInventory',
544
+ 'targetInventory.inventory',
545
+ 'fromLocation'
546
+ ])
547
+
548
+ for (var i = 0; i < worksheetDetails?.length; i++) {
549
+ const worksheetDetail = worksheetDetails[i]
550
+ this.checkRecordValidity(worksheetDetail, { status: WORKSHEET_STATUS.DONE })
551
+ const worksheet: Worksheet = worksheetDetail.worksheet
552
+ const replenishment: Replenishment = worksheet.replenishment
553
+ const targetInventory: OrderInventory = worksheetDetail.targetInventory
554
+
555
+ let inventory: Inventory = await this.trxMgr.getRepository(Inventory).findOne({
556
+ where: { domain: this.domain, cartonId, refOrderId: replenishment.id }
557
+ })
558
+
559
+ let inventoryItems: InventoryItem = await this.trxMgr
560
+ .getRepository(InventoryItem)
561
+ .find({ where: { outboundOrderId: replenishment.id, inventory } })
562
+
563
+ if (inventoryItems.length > 0) {
564
+ inventoryItems.forEach((itm: InventoryItem) => {
565
+ itm.status = INVENTORY_STATUS.RELOCATE
566
+ itm.updater = this.user
567
+ itm.inventory = targetInventory.inventory
568
+ })
569
+
570
+ await this.trxMgr.getRepository(InventoryItem).save(inventoryItems)
571
+ }
572
+
573
+ let updateInvObj = {
574
+ transferQty: () => `"transfer_qty" + ${targetInventory.releaseQty}`,
575
+ transferUomValue: () => `"transfer_uom_value" + ${targetInventory.releaseUomValue}`,
576
+ updater: this.user,
577
+ updatedAt: new Date()
578
+ }
579
+
580
+ await this.trxMgr
581
+ .getRepository(Inventory)
582
+ .createQueryBuilder()
583
+ .update(Inventory)
584
+ .set(updateInvObj)
585
+ .where('id = :id', { id: targetInventory.inventory.id })
586
+ .execute()
587
+
588
+ await this.checkReleaseTarget(inventory)
589
+
590
+ await this.trxMgr.getRepository(InventoryHistory).delete({ inventory })
591
+
592
+ await this.trxMgr.getRepository(Inventory).delete(inventory.id)
593
+
594
+ targetInventory.status = ORDER_PRODUCT_STATUS.PUTTING_AWAY
595
+ targetInventory.updater = this.user
596
+ await this.updateOrderTargets([targetInventory])
597
+
598
+ worksheetDetail.status = WORKSHEET_STATUS.EXECUTING
599
+ worksheetDetail.updater = this.user
600
+ await this.trxMgr.getRepository(WorksheetDetail).save(worksheetDetail)
601
+ }
602
+ }
603
+
604
+ async completeReplenishmentPutaway(replenishmentNo: string): Promise<Worksheet> {
605
+ let replenishment: Replenishment = await this.findRefOrder(Replenishment, {
606
+ name: replenishmentNo,
607
+ status: ORDER_STATUS.PUTTING_AWAY
608
+ })
609
+
610
+ const putawayReplenishmentWorksheet: Worksheet = await this.findWorksheetByRefOrder(
611
+ replenishment,
612
+ WORKSHEET_TYPE.PUTAWAY_REPLENISHMENT,
613
+ ['worksheetDetails', 'worksheetDetails.targetInventory']
614
+ )
615
+ return await this.completeWorksheet(putawayReplenishmentWorksheet, ORDER_STATUS.DONE)
616
+ }
617
+
618
+ private async checkReleaseTarget(inventory: Inventory): Promise<void> {
619
+ const releaseTargetInventory: OrderInventory = await this.trxMgr.getRepository(OrderInventory).findOne({
620
+ where: {
621
+ domain: this.domain,
622
+ type: ORDER_TYPES.RELEASE_OF_GOODS,
623
+ inventory
624
+ }
625
+ })
626
+
627
+ if (releaseTargetInventory)
628
+ throw new Error(
629
+ this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('undo putaway', 'this pallet ID has been selected for releasing')
630
+ )
631
+ }
632
+ }