@things-factory/worksheet-base 5.0.0-alpha.4 → 5.0.0-alpha.40

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 (160) hide show
  1. package/dist-server/constants/template.js +1 -0
  2. package/dist-server/constants/template.js.map +1 -1
  3. package/dist-server/controllers/ecommerce/sellercraft-controller.js +9 -3
  4. package/dist-server/controllers/ecommerce/sellercraft-controller.js.map +1 -1
  5. package/dist-server/controllers/inbound/unloading-worksheet-controller.js +309 -4
  6. package/dist-server/controllers/inbound/unloading-worksheet-controller.js.map +1 -1
  7. package/dist-server/controllers/index.js +2 -0
  8. package/dist-server/controllers/index.js.map +1 -1
  9. package/dist-server/controllers/outbound/loading-worksheet-controller.js +10 -0
  10. package/dist-server/controllers/outbound/loading-worksheet-controller.js.map +1 -1
  11. package/dist-server/controllers/outbound/packing-worksheet-controller.js +172 -7
  12. package/dist-server/controllers/outbound/packing-worksheet-controller.js.map +1 -1
  13. package/dist-server/controllers/outbound/picking-worksheet-controller.js +352 -11
  14. package/dist-server/controllers/outbound/picking-worksheet-controller.js.map +1 -1
  15. package/dist-server/controllers/outbound/returning-worksheet-controller.js +11 -1
  16. package/dist-server/controllers/outbound/returning-worksheet-controller.js.map +1 -1
  17. package/dist-server/controllers/outbound/sorting-worksheet-controller.js +110 -3
  18. package/dist-server/controllers/outbound/sorting-worksheet-controller.js.map +1 -1
  19. package/dist-server/controllers/render-fm-grn.js +229 -0
  20. package/dist-server/controllers/render-fm-grn.js.map +1 -0
  21. package/dist-server/controllers/render-grn.js +45 -21
  22. package/dist-server/controllers/render-grn.js.map +1 -1
  23. package/dist-server/controllers/render-invoices.js +103 -65
  24. package/dist-server/controllers/render-invoices.js.map +1 -1
  25. package/dist-server/controllers/render-orientage-do.js.map +1 -1
  26. package/dist-server/controllers/render-orientage-grn.js +1 -0
  27. package/dist-server/controllers/render-orientage-grn.js.map +1 -1
  28. package/dist-server/controllers/render-po.js +147 -0
  29. package/dist-server/controllers/render-po.js.map +1 -0
  30. package/dist-server/controllers/render-ro-do.js +65 -1
  31. package/dist-server/controllers/render-ro-do.js.map +1 -1
  32. package/dist-server/controllers/worksheet-controller.js +15 -0
  33. package/dist-server/controllers/worksheet-controller.js.map +1 -1
  34. package/dist-server/graphql/resolvers/worksheet/cycle-count-adjustment.js +10 -3
  35. package/dist-server/graphql/resolvers/worksheet/cycle-count-adjustment.js.map +1 -1
  36. package/dist-server/graphql/resolvers/worksheet/find-release-orders-by-task-no.js +30 -1
  37. package/dist-server/graphql/resolvers/worksheet/find-release-orders-by-task-no.js.map +1 -1
  38. package/dist-server/graphql/resolvers/worksheet/generate-worksheet/generate-arrival-notice-worksheet.js +27 -23
  39. package/dist-server/graphql/resolvers/worksheet/generate-worksheet/generate-arrival-notice-worksheet.js.map +1 -1
  40. package/dist-server/graphql/resolvers/worksheet/inventories-by-pallet.js +3 -0
  41. package/dist-server/graphql/resolvers/worksheet/inventories-by-pallet.js.map +1 -1
  42. package/dist-server/graphql/resolvers/worksheet/loading/complete-loading.js +26 -2
  43. package/dist-server/graphql/resolvers/worksheet/loading/complete-loading.js.map +1 -1
  44. package/dist-server/graphql/resolvers/worksheet/packing/index.js +2 -1
  45. package/dist-server/graphql/resolvers/worksheet/packing/index.js.map +1 -1
  46. package/dist-server/graphql/resolvers/worksheet/packing/packing.js +4 -4
  47. package/dist-server/graphql/resolvers/worksheet/packing/packing.js.map +1 -1
  48. package/dist-server/graphql/resolvers/worksheet/packing/scan-product-packing.js +4 -4
  49. package/dist-server/graphql/resolvers/worksheet/packing/scan-product-packing.js.map +1 -1
  50. package/dist-server/graphql/resolvers/worksheet/packing/undo-serial-number-packing.js +15 -0
  51. package/dist-server/graphql/resolvers/worksheet/packing/undo-serial-number-packing.js.map +1 -0
  52. package/dist-server/graphql/resolvers/worksheet/packing-worksheet.js +152 -132
  53. package/dist-server/graphql/resolvers/worksheet/packing-worksheet.js.map +1 -1
  54. package/dist-server/graphql/resolvers/worksheet/picking/assign-picking-worker.js +13 -10
  55. package/dist-server/graphql/resolvers/worksheet/picking/assign-picking-worker.js.map +1 -1
  56. package/dist-server/graphql/resolvers/worksheet/picking/complete-picking.js +6 -19
  57. package/dist-server/graphql/resolvers/worksheet/picking/complete-picking.js.map +1 -1
  58. package/dist-server/graphql/resolvers/worksheet/picking/index.js +2 -1
  59. package/dist-server/graphql/resolvers/worksheet/picking/index.js.map +1 -1
  60. package/dist-server/graphql/resolvers/worksheet/picking/picking-assignment-status-by-user.js +49 -58
  61. package/dist-server/graphql/resolvers/worksheet/picking/picking-assignment-status-by-user.js.map +1 -1
  62. package/dist-server/graphql/resolvers/worksheet/picking/undo-serial-number-picking.js +15 -0
  63. package/dist-server/graphql/resolvers/worksheet/picking/undo-serial-number-picking.js.map +1 -0
  64. package/dist-server/graphql/resolvers/worksheet/sorting/scan-product-sorting.js +4 -4
  65. package/dist-server/graphql/resolvers/worksheet/sorting/scan-product-sorting.js.map +1 -1
  66. package/dist-server/graphql/resolvers/worksheet/sorting/sorting-product.js +4 -4
  67. package/dist-server/graphql/resolvers/worksheet/sorting/sorting-product.js.map +1 -1
  68. package/dist-server/graphql/resolvers/worksheet/sorting-worksheet.js +6 -0
  69. package/dist-server/graphql/resolvers/worksheet/sorting-worksheet.js.map +1 -1
  70. package/dist-server/graphql/resolvers/worksheet/unloaded-inventories.js +3 -2
  71. package/dist-server/graphql/resolvers/worksheet/unloaded-inventories.js.map +1 -1
  72. package/dist-server/graphql/resolvers/worksheet/unloading/index.js +3 -1
  73. package/dist-server/graphql/resolvers/worksheet/unloading/index.js.map +1 -1
  74. package/dist-server/graphql/resolvers/worksheet/unloading/scan-serial-number-unload.js +15 -0
  75. package/dist-server/graphql/resolvers/worksheet/unloading/scan-serial-number-unload.js.map +1 -0
  76. package/dist-server/graphql/resolvers/worksheet/unloading/undo-serial-number-unload.js +15 -0
  77. package/dist-server/graphql/resolvers/worksheet/unloading/undo-serial-number-unload.js.map +1 -0
  78. package/dist-server/graphql/resolvers/worksheet/unloading/unload.js.map +1 -1
  79. package/dist-server/graphql/resolvers/worksheet/unloading-worksheet.js +3 -1
  80. package/dist-server/graphql/resolvers/worksheet/unloading-worksheet.js.map +1 -1
  81. package/dist-server/graphql/resolvers/worksheet/worksheets.js +18 -0
  82. package/dist-server/graphql/resolvers/worksheet/worksheets.js.map +1 -1
  83. package/dist-server/graphql/resolvers/worksheet-detail/generate-batch-picking-worksheet-details-by-bulk.js +4 -5
  84. package/dist-server/graphql/resolvers/worksheet-detail/generate-batch-picking-worksheet-details-by-bulk.js.map +1 -1
  85. package/dist-server/graphql/resolvers/worksheet-detail/generate-picking-worksheet-details.js +4 -2
  86. package/dist-server/graphql/resolvers/worksheet-detail/generate-picking-worksheet-details.js.map +1 -1
  87. package/dist-server/graphql/types/worksheet/find-release-orders-by-task-no.js +11 -0
  88. package/dist-server/graphql/types/worksheet/find-release-orders-by-task-no.js.map +1 -0
  89. package/dist-server/graphql/types/worksheet/index.js +33 -6
  90. package/dist-server/graphql/types/worksheet/index.js.map +1 -1
  91. package/dist-server/graphql/types/worksheet/picking-assignment-status.js +2 -2
  92. package/dist-server/graphql/types/worksheet/worksheet-detail-info.js +3 -0
  93. package/dist-server/graphql/types/worksheet/worksheet-detail-info.js.map +1 -1
  94. package/dist-server/graphql/types/worksheet/worksheet-info.js +1 -0
  95. package/dist-server/graphql/types/worksheet/worksheet-info.js.map +1 -1
  96. package/dist-server/graphql/types/worksheet/worksheet-patch.js +1 -0
  97. package/dist-server/graphql/types/worksheet/worksheet-patch.js.map +1 -1
  98. package/dist-server/graphql/types/worksheet-detail/index.js +0 -2
  99. package/dist-server/graphql/types/worksheet-detail/index.js.map +1 -1
  100. package/dist-server/index.js +5 -0
  101. package/dist-server/index.js.map +1 -1
  102. package/dist-server/routes.js +12 -0
  103. package/dist-server/routes.js.map +1 -1
  104. package/dist-server/utils/inventory-util.js +14 -25
  105. package/dist-server/utils/inventory-util.js.map +1 -1
  106. package/package.json +17 -17
  107. package/server/constants/template.ts +1 -0
  108. package/server/controllers/ecommerce/sellercraft-controller.ts +10 -3
  109. package/server/controllers/inbound/unloading-worksheet-controller.ts +376 -8
  110. package/server/controllers/index.ts +3 -0
  111. package/server/controllers/outbound/loading-worksheet-controller.ts +13 -0
  112. package/server/controllers/outbound/packing-worksheet-controller.ts +224 -9
  113. package/server/controllers/outbound/picking-worksheet-controller.ts +465 -16
  114. package/server/controllers/outbound/returning-worksheet-controller.ts +12 -1
  115. package/server/controllers/outbound/sorting-worksheet-controller.ts +149 -4
  116. package/server/controllers/render-fm-grn.ts +266 -0
  117. package/server/controllers/render-grn.ts +57 -23
  118. package/server/controllers/render-invoices.ts +119 -72
  119. package/server/controllers/render-orientage-do.ts +11 -11
  120. package/server/controllers/render-orientage-grn.ts +12 -11
  121. package/server/controllers/render-po.ts +170 -0
  122. package/server/controllers/render-ro-do.ts +93 -8
  123. package/server/controllers/worksheet-controller.ts +18 -2
  124. package/server/graphql/resolvers/worksheet/cycle-count-adjustment.ts +13 -4
  125. package/server/graphql/resolvers/worksheet/find-release-orders-by-task-no.ts +35 -2
  126. package/server/graphql/resolvers/worksheet/generate-worksheet/generate-arrival-notice-worksheet.ts +35 -25
  127. package/server/graphql/resolvers/worksheet/inventories-by-pallet.ts +2 -0
  128. package/server/graphql/resolvers/worksheet/loading/complete-loading.ts +41 -8
  129. package/server/graphql/resolvers/worksheet/packing/index.ts +3 -1
  130. package/server/graphql/resolvers/worksheet/packing/packing.ts +5 -4
  131. package/server/graphql/resolvers/worksheet/packing/scan-product-packing.ts +9 -4
  132. package/server/graphql/resolvers/worksheet/packing/undo-serial-number-packing.ts +24 -0
  133. package/server/graphql/resolvers/worksheet/packing-worksheet.ts +167 -145
  134. package/server/graphql/resolvers/worksheet/picking/assign-picking-worker.ts +15 -11
  135. package/server/graphql/resolvers/worksheet/picking/complete-picking.ts +5 -20
  136. package/server/graphql/resolvers/worksheet/picking/index.ts +3 -1
  137. package/server/graphql/resolvers/worksheet/picking/picking-assignment-status-by-user.ts +62 -61
  138. package/server/graphql/resolvers/worksheet/picking/undo-serial-number-picking.ts +24 -0
  139. package/server/graphql/resolvers/worksheet/sorting/scan-product-sorting.ts +5 -4
  140. package/server/graphql/resolvers/worksheet/sorting/sorting-product.ts +5 -4
  141. package/server/graphql/resolvers/worksheet/sorting-worksheet.ts +6 -0
  142. package/server/graphql/resolvers/worksheet/unloaded-inventories.ts +6 -2
  143. package/server/graphql/resolvers/worksheet/unloading/index.ts +4 -0
  144. package/server/graphql/resolvers/worksheet/unloading/scan-serial-number-unload.ts +26 -0
  145. package/server/graphql/resolvers/worksheet/unloading/undo-serial-number-unload.ts +24 -0
  146. package/server/graphql/resolvers/worksheet/unloading/unload.ts +3 -1
  147. package/server/graphql/resolvers/worksheet/unloading-worksheet.ts +3 -1
  148. package/server/graphql/resolvers/worksheet/worksheets.ts +26 -0
  149. package/server/graphql/resolvers/worksheet-detail/generate-batch-picking-worksheet-details-by-bulk.ts +10 -12
  150. package/server/graphql/resolvers/worksheet-detail/generate-picking-worksheet-details.ts +4 -2
  151. package/server/graphql/types/worksheet/find-release-orders-by-task-no.ts +8 -0
  152. package/server/graphql/types/worksheet/index.ts +33 -6
  153. package/server/graphql/types/worksheet/picking-assignment-status.ts +2 -2
  154. package/server/graphql/types/worksheet/worksheet-detail-info.ts +3 -0
  155. package/server/graphql/types/worksheet/worksheet-info.ts +1 -0
  156. package/server/graphql/types/worksheet/worksheet-patch.ts +1 -0
  157. package/server/graphql/types/worksheet-detail/index.ts +0 -2
  158. package/server/index.ts +5 -0
  159. package/server/routes.ts +17 -0
  160. package/server/utils/inventory-util.ts +15 -23
@@ -1,6 +1,13 @@
1
1
  import { VasWorksheetController } from '../vas/vas-worksheet-controller'
2
2
  import { Product, ProductDetail } from '@things-factory/product-base'
3
- import { Inventory, INVENTORY_TRANSACTION_TYPE } from '@things-factory/warehouse-base'
3
+ import {
4
+ Inventory,
5
+ INVENTORY_TRANSACTION_TYPE,
6
+ InventoryItem,
7
+ INVENTORY_STATUS,
8
+ InventoryNoGenerator,
9
+ INVENTORY_ITEM_SOURCE
10
+ } from '@things-factory/warehouse-base'
4
11
  import { ReleaseGood, OrderInventory, ORDER_INVENTORY_STATUS, ORDER_STATUS } from '@things-factory/sales-base'
5
12
  import { Worksheet, WorksheetDetail } from '../../entities'
6
13
  import { WORKSHEET_STATUS, WORKSHEET_TYPE } from '../../constants'
@@ -51,7 +58,12 @@ export class SortingWorksheetController extends VasWorksheetController {
51
58
  return await this.activateWorksheet(worksheet, worksheetDetails, sortingWorksheetDetails)
52
59
  }
53
60
 
54
- async scanProductSorting(taskNo: string, releaseGoodNo: string, productBarcode: string): Promise<void> {
61
+ async scanProductSorting(
62
+ taskNo: string,
63
+ releaseGoodNo: string,
64
+ productBarcode: string,
65
+ serialNumber: string
66
+ ): Promise<void> {
55
67
  const worksheet: Worksheet = await this.trxMgr.getRepository(Worksheet).findOne({
56
68
  where: {
57
69
  domain: this.domain,
@@ -113,8 +125,53 @@ export class SortingWorksheetController extends VasWorksheetController {
113
125
  const releaseQty: number = matchingOI.releaseQty
114
126
  const inventory: Inventory = matchingOI.inventory
115
127
  const releaseGood: ReleaseGood = matchingOI.releaseGood
128
+ const product: Product = inventory.product
116
129
 
117
130
  if (releaseQty != matchingOI?.sortedQty && sortedQty == 1) {
131
+ // Serial Number scanning for batch picking
132
+ if (matchingOI?.refWorksheetId) {
133
+ if (product?.isRequireSerialNumberScanningOutbound) {
134
+ if (!serialNumber || serialNumber == '') {
135
+ throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('sorting', `require serial number`))
136
+ }
137
+
138
+ let foundSerialNumber: InventoryItem = await this.trxMgr
139
+ .getRepository(InventoryItem)
140
+ .findOne({ where: { domain: this.domain, serialNumber: serialNumber, product } })
141
+
142
+ if (foundSerialNumber) {
143
+ if (foundSerialNumber.inventoryId !== inventory.id) {
144
+ throw new Error('Serial Number scanned is in another inventory')
145
+ }
146
+
147
+ if (foundSerialNumber.outboundOrderId) {
148
+ let releaseGood: ReleaseGood = await this.trxMgr
149
+ .getRepository(ReleaseGood)
150
+ .findOne({ where: { id: foundSerialNumber.outboundOrderId } })
151
+ throw new Error(`Inventory Item is already picked/sorted in ${releaseGood.name}`)
152
+ }
153
+
154
+ foundSerialNumber.status = INVENTORY_STATUS.SORTING
155
+ foundSerialNumber.updater = this.user
156
+ foundSerialNumber.outboundOrderId = releaseGood.id
157
+
158
+ await this.trxMgr.getRepository(InventoryItem).save(foundSerialNumber)
159
+ } else {
160
+ let inventoryItem: InventoryItem = new InventoryItem()
161
+ inventoryItem.name = InventoryNoGenerator.inventoryItemName()
162
+ inventoryItem.serialNumber = serialNumber
163
+ inventoryItem.status = INVENTORY_STATUS.SORTING
164
+ inventoryItem.outboundOrderId = releaseGood.id
165
+ inventoryItem.source = INVENTORY_ITEM_SOURCE.OUTBOUND
166
+ inventoryItem.product = product
167
+ inventoryItem.inventory = inventory
168
+ inventoryItem.domain = this.domain
169
+
170
+ await this.trxMgr.getRepository(InventoryItem).save(inventoryItem)
171
+ }
172
+ }
173
+ }
174
+
118
175
  matchingOI.sortedQty = Boolean(matchingOI?.sortedQty) ? matchingOI.sortedQty + sortedQty : sortedQty
119
176
  sortedQty -= 1
120
177
  if (matchingOI.sortedQty == releaseQty) {
@@ -128,6 +185,19 @@ export class SortingWorksheetController extends VasWorksheetController {
128
185
  worksheetDetail.status = WORKSHEET_STATUS.DONE
129
186
  worksheetDetail.updater = this.user
130
187
  await this.trxMgr.getRepository(WorksheetDetail).save(worksheetDetail)
188
+
189
+ let inventoryItems: InventoryItem = await this.trxMgr
190
+ .getRepository(InventoryItem)
191
+ .find({ where: { outboundOrderId: releaseGood.id } })
192
+
193
+ if (inventoryItems.length > 0) {
194
+ inventoryItems.forEach((itm: InventoryItem) => {
195
+ itm.status = INVENTORY_STATUS.SORTED
196
+ itm.updater = this.user
197
+ })
198
+
199
+ await this.trxMgr.getRepository(InventoryItem).save(inventoryItems)
200
+ }
131
201
  } else if (matchingOI?.sortedQty > releaseQty) {
132
202
  const product: Product = matchingOI.inventory.product
133
203
  throw new Error(this.ERROR_MSG.ORDER_ITEM.EXCESS_QTY(product.sku, packingType, packingSize))
@@ -141,7 +211,13 @@ export class SortingWorksheetController extends VasWorksheetController {
141
211
  }
142
212
  }
143
213
 
144
- async sortingProduct(taskNo: string, releaseGoodNo: string, productId: string, sortingQty: number): Promise<void> {
214
+ async sortingProduct(
215
+ taskNo: string,
216
+ releaseGoodNo: string,
217
+ productId: string,
218
+ sortingQty: number,
219
+ serialNumber: string
220
+ ): Promise<void> {
145
221
  const worksheet: Worksheet = await this.trxMgr.getRepository(Worksheet).findOne({
146
222
  where: {
147
223
  domain: this.domain,
@@ -180,14 +256,70 @@ export class SortingWorksheetController extends VasWorksheetController {
180
256
  const packingType: string = matchingOI.packingType
181
257
  const packingSize: number = matchingOI.packingSize
182
258
 
259
+ if (product?.isRequireSerialNumberScanningOutbound) {
260
+ if (!serialNumber || serialNumber == '') {
261
+ throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('sorting', `require serial number`))
262
+ }
263
+
264
+ let foundSerialNumber: InventoryItem = await this.trxMgr.getRepository(InventoryItem).findOne({
265
+ where: { domain: this.domain, serialNumber: serialNumber, product },
266
+ relations: ['product', 'inventory']
267
+ })
268
+
269
+ if (foundSerialNumber) {
270
+ if (foundSerialNumber.outboundOrderId) {
271
+ let releaseGood: ReleaseGood = await this.trxMgr
272
+ .getRepository(ReleaseGood)
273
+ .findOne({ where: { id: foundSerialNumber.outboundOrderId } })
274
+ throw new Error(`Inventory Item is already picked/sorted in ${releaseGood.name}`)
275
+ }
276
+
277
+ foundSerialNumber.status = INVENTORY_STATUS.SORTING
278
+ foundSerialNumber.updater = this.user
279
+ foundSerialNumber.outboundOrderId = releaseGood.id
280
+
281
+ await this.trxMgr.getRepository(InventoryItem).save(foundSerialNumber)
282
+ } else {
283
+ let inventoryItem: InventoryItem = new InventoryItem()
284
+ inventoryItem.name = InventoryNoGenerator.inventoryItemName()
285
+ inventoryItem.serialNumber = serialNumber
286
+ inventoryItem.status = INVENTORY_STATUS.SORTING
287
+ inventoryItem.source = INVENTORY_ITEM_SOURCE.OUTBOUND
288
+ inventoryItem.outboundOrderId = releaseGood.id
289
+ inventoryItem.product = product
290
+ inventoryItem.inventory = inventory
291
+ inventoryItem.domain = this.domain
292
+
293
+ foundSerialNumber = await this.trxMgr.getRepository(InventoryItem).save(inventoryItem)
294
+ }
295
+ }
296
+
183
297
  if (releaseQty != matchingOI?.sortedQty && sortingQty != 0) {
184
- matchingOI.sortedQty = releaseQty
298
+ if (product?.isRequireSerialNumberScanningOutbound) {
299
+ matchingOI.sortedQty += sortingQty
300
+ } else {
301
+ matchingOI.sortedQty = releaseQty
302
+ }
303
+
185
304
  sortingQty -= releaseQty
186
305
  if (matchingOI.sortedQty == releaseQty) {
187
306
  matchingOI.status = ORDER_INVENTORY_STATUS.SORTED
188
307
  await this.updateOrderTargets([matchingOI])
189
308
  await this.transactionInventory(inventory, releaseGood, 0, 0, INVENTORY_TRANSACTION_TYPE.SORTING)
190
309
 
310
+ let inventoryItems: InventoryItem = await this.trxMgr
311
+ .getRepository(InventoryItem)
312
+ .find({ where: { outboundOrderId: releaseGood.id } })
313
+
314
+ if (inventoryItems.length > 0) {
315
+ inventoryItems.forEach((itm: InventoryItem) => {
316
+ itm.status = INVENTORY_STATUS.PACKED
317
+ itm.updater = this.user
318
+ })
319
+
320
+ await this.trxMgr.getRepository(InventoryItem).save(inventoryItems)
321
+ }
322
+
191
323
  let worksheetDetail: WorksheetDetail = worksheetDetails.find(
192
324
  wsd => wsd.targetInventory.id === matchingOI.id
193
325
  )
@@ -220,6 +352,19 @@ export class SortingWorksheetController extends VasWorksheetController {
220
352
  releaseGood.updater = this.user
221
353
  await this.trxMgr.getRepository(ReleaseGood).save(releaseGood)
222
354
 
355
+ let inventoryItems: InventoryItem = await this.trxMgr
356
+ .getRepository(InventoryItem)
357
+ .find({ where: { outboundOrderId: releaseGood.id } })
358
+
359
+ if (inventoryItems.length > 0) {
360
+ inventoryItems.forEach((itm: InventoryItem) => {
361
+ itm.status = INVENTORY_STATUS.TERMINATED
362
+ itm.updater = this.user
363
+ })
364
+
365
+ await this.trxMgr.getRepository(InventoryItem).save(inventoryItems)
366
+ }
367
+
223
368
  return releaseGood
224
369
  }
225
370
 
@@ -0,0 +1,266 @@
1
+ import FormData from 'form-data'
2
+ import _ from 'lodash'
3
+ import fetch from 'node-fetch'
4
+ import { getRepository, IsNull, Not } from 'typeorm'
5
+
6
+ import { Attachment, STORAGE } from '@things-factory/attachment-base'
7
+ import { Partner } from '@things-factory/auth-base'
8
+ import { Bizplace, ContactPoint } from '@things-factory/biz-base'
9
+ import { config } from '@things-factory/env'
10
+ import { ArrivalNotice, GoodsReceivalNote, ORDER_STATUS, OrderProduct } from '@things-factory/sales-base'
11
+ import { Domain } from '@things-factory/shell'
12
+ import { InventoryItem, ReducedInventoryHistory } from '@things-factory/warehouse-base'
13
+
14
+ import { TEMPLATE_TYPE, WORKSHEET_TYPE } from '../constants'
15
+ import { Worksheet } from '../entities'
16
+ import { DateTimeConverter } from '../utils/datetime-util'
17
+
18
+ const REPORT_API_URL = config.get('reportApiUrl', 'http://localhost:8888/rest/report/show_html')
19
+
20
+ export async function renderFmGRN({ grnNo, timezoneOffSet }, context: any) {
21
+ // 1. find domain
22
+ const domain: Domain = await getRepository(Domain).findOne({
23
+ where: { id: context.state.domain.id }
24
+ })
25
+
26
+ // 2. find grn
27
+ const foundGRN: GoodsReceivalNote = await getRepository(GoodsReceivalNote).findOne({
28
+ where: { domain, name: grnNo },
29
+ relations: ['domain', 'bizplace', 'bizplace.domain', 'bizplace.company', 'arrivalNotice']
30
+ })
31
+
32
+ // 3. find GAN
33
+ const foundGAN: ArrivalNotice = foundGRN.arrivalNotice
34
+ const ownRefNo = foundGAN.refNo
35
+
36
+ const foundInventoryItem: InventoryItem[] = await getRepository(InventoryItem).query(
37
+ `select row_number() over (partition by p.sku) as "seq",p.sku,p.brand_sku, ii.serial_number from inventory_items ii left join products p on ii.product_id = p.id where inbound_order_id = '${foundGAN.id}' group by p.sku,ii.serial_number,p.brand_sku`
38
+ )
39
+
40
+ // 4. find customer bizplace
41
+ const partnerBiz: Bizplace = foundGRN.bizplace
42
+
43
+ const partnerDomain: Partner = await getRepository(Partner).findOne({
44
+ where: { partnerDomain: partnerBiz.domain, domain },
45
+ relations: ['domain']
46
+ })
47
+
48
+ const domainOwner: Domain = partnerDomain.domain
49
+ const domainBizplace: Bizplace = await getRepository(Bizplace).findOne({
50
+ where: { domain: domainOwner },
51
+ relations: ['company']
52
+ })
53
+
54
+ const qbReducedInventory = getRepository(ReducedInventoryHistory)
55
+ .createQueryBuilder('ivh')
56
+ .select('product_id', 'productId')
57
+ .addSelect('batch_id', 'batchId')
58
+ .addSelect('reusable_pallet_id', 'reusablePalletId')
59
+ .addSelect('packing_type', 'packingType')
60
+ .addSelect('sum(qty)', 'qty')
61
+ .addSelect('sum(uom_value)', 'uomValue')
62
+ .addSelect('uom', 'uom')
63
+ .addSelect('expiration_date', 'expiryDate')
64
+ .addSelect('count(distinct pallet_id)', 'pallet')
65
+ .addSelect(`string_agg(distinct pallet_id::varchar,', ' order by pallet_id::varchar)`, 'palletId')
66
+ .where('ivh.domain_id = :domainId', { domainId: domain.id })
67
+ .andWhere('ivh.ref_order_id = :refOrderId', { refOrderId: foundGAN.id })
68
+ .andWhere(`ivh.transaction_type = 'UNLOADING'`)
69
+ .groupBy('reusable_pallet_id')
70
+ .addGroupBy('product_id')
71
+ .addGroupBy('batch_id')
72
+ .addGroupBy('packing_type')
73
+ .addGroupBy('uom')
74
+ .addGroupBy('expiration_date')
75
+ .getRawMany()
76
+
77
+ // 5. find domain contact point
78
+ const foundCP: ContactPoint = await getRepository(ContactPoint).findOne({
79
+ where: { domain, bizplace: domainBizplace }
80
+ })
81
+
82
+ // 5. find domain contact point
83
+ const foundPartnerCP: ContactPoint = await getRepository(ContactPoint).findOne({
84
+ where: { domain, bizplace: partnerBiz }
85
+ })
86
+
87
+ // 6. find unloading worksheet
88
+ const foundWS: Worksheet = await getRepository(Worksheet).findOne({
89
+ where: { domain, arrivalNotice: foundGAN, type: WORKSHEET_TYPE.UNLOADING, status: ORDER_STATUS.DONE },
90
+ relations: ['worksheetDetails', 'updater']
91
+ })
92
+
93
+ // find putaway worksheet
94
+ const foundPutawayWS: Worksheet = await getRepository(Worksheet).findOne({
95
+ where: { domain, arrivalNotice: foundGAN, type: WORKSHEET_TYPE.PUTAWAY, status: ORDER_STATUS.DONE },
96
+ relations: ['worksheetDetails', 'updater']
97
+ })
98
+
99
+ const targetProducts: OrderProduct[] = await getRepository(OrderProduct).find({
100
+ where: { domain, arrivalNotice: foundGAN, actualPalletQty: Not(IsNull()), actualPackQty: Not(IsNull()) },
101
+ relations: ['product']
102
+ })
103
+
104
+ // 7. find grn template based on category
105
+ const foundTemplate: Attachment = await getRepository(Attachment).findOne({
106
+ where: { domain, category: TEMPLATE_TYPE.GRN_TEMPLATE }
107
+ })
108
+
109
+ // 8. find grn logo
110
+ const foundLogo: Attachment = await getRepository(Attachment).findOne({
111
+ where: {
112
+ domain,
113
+ category: TEMPLATE_TYPE.LOGO
114
+ }
115
+ })
116
+
117
+ // 9. find signature
118
+ const foundSignature: Attachment = await getRepository(Attachment).findOne({
119
+ where: {
120
+ domain,
121
+ category: TEMPLATE_TYPE.SIGNATURE
122
+ }
123
+ })
124
+
125
+ const foundCop: Attachment = await getRepository(Attachment).findOne({
126
+ where: {
127
+ domain,
128
+ category: TEMPLATE_TYPE.COP
129
+ }
130
+ })
131
+
132
+ const inboundInventories: any[] = await qbReducedInventory
133
+
134
+ const template = await STORAGE.readFile(foundTemplate.path, 'utf-8')
135
+
136
+ let logo = null
137
+ if (foundLogo?.path) {
138
+ logo = 'data:' + foundLogo.mimetype + ';base64,' + (await STORAGE.readFile(foundLogo.path, 'base64'))
139
+ }
140
+
141
+ let signature = null
142
+ if (foundSignature?.path) {
143
+ signature = 'data:' + foundSignature.mimetype + ';base64,' + (await STORAGE.readFile(foundSignature.path, 'base64'))
144
+ }
145
+
146
+ let cop = null
147
+ if (foundCop?.path) {
148
+ cop = 'data:' + foundSignature.mimetype + ';base64,' + (await STORAGE.readFile(foundCop.path, 'base64'))
149
+ }
150
+
151
+ const filterInventoryItem = _.groupBy(foundInventoryItem, i => i.sku)
152
+
153
+ const tempIndexArr = []
154
+
155
+ const tempTotalQuantity = []
156
+
157
+ Object.keys(filterInventoryItem).forEach(k => {
158
+ const tempIndex = foundInventoryItem.findIndex(i => {
159
+ return i.sku == k
160
+ })
161
+
162
+ tempIndexArr.push(tempIndex)
163
+ })
164
+
165
+ Object.values(filterInventoryItem).forEach(k => {
166
+ const tempQuantity = k.length
167
+
168
+ tempTotalQuantity.push(tempQuantity)
169
+ })
170
+
171
+ tempIndexArr.forEach((t, index) => {
172
+ if (t >= 0) foundInventoryItem[t].totalQuantity = tempTotalQuantity[index]
173
+ })
174
+
175
+ const data = {
176
+ logo_url: logo,
177
+ sign_url: signature,
178
+ cop_url: cop,
179
+ customer_biz: partnerBiz.name,
180
+ customer_address: partnerBiz.address,
181
+ company_domain: domainBizplace.company.name,
182
+ company_phone: foundCP.phone,
183
+ company_email: foundCP.email,
184
+ company_brn: domainBizplace.company.brn,
185
+ company_address: domainBizplace.company.address,
186
+ warehouse_address: foundCP.address,
187
+ warehouse_address2: foundCP.address2,
188
+ warehouse_postcode: foundCP.postCode,
189
+ warehouse_city: foundCP.city,
190
+ warehouse_state: foundCP.state,
191
+ warehouse_phone: foundCP.phone,
192
+ warehouse_fax: foundCP.fax,
193
+ warehouse_email: foundCP.email,
194
+ order_no: foundGRN.name,
195
+ gan_no: foundGAN.name,
196
+ gan_accepted_at: foundGAN.acceptedAt ? DateTimeConverter.datetime(foundGAN.acceptedAt, timezoneOffSet) : '',
197
+ unload_date: DateTimeConverter.date(foundWS.endedAt),
198
+ ref_no: ownRefNo ? `${foundGAN.name} / ${foundGAN.refNo}` : `${foundGAN.name}`,
199
+ ref_no_only: ownRefNo ? ` ${foundGAN.refNo}` : '',
200
+ ref_no1: foundGAN.refNo2 ? `${foundGAN.refNo2}` : '',
201
+ ref_no2: foundGAN.refNo3 ? `${foundGAN.refNo3}` : '',
202
+ received_date: DateTimeConverter.date(foundWS.endedAt),
203
+ truck_no: foundGAN.truckNo || '',
204
+ container_no: foundGAN.containerNo || '',
205
+ container_size: foundGAN.containerSize || '',
206
+ delivery_order_no: foundGAN.deliveryOrderNo ? foundGAN.deliveryOrderNo : '',
207
+ account_no: foundPartnerCP ? foundPartnerCP.accountNo : '',
208
+ unloaded_by: foundWS ? foundWS.updater.name : '',
209
+ putaway_by: foundPutawayWS ? foundPutawayWS.updater.name : '',
210
+ product_list: targetProducts
211
+ .reduce((acc, item) => {
212
+ acc.push(
213
+ ...inboundInventories
214
+ .filter(
215
+ ih =>
216
+ ih.productId == item.product.id &&
217
+ ih.batchId == item.batchId &&
218
+ ih.packingType == item.packingType &&
219
+ ih.uom == item.uom
220
+ )
221
+ .map(unloadInvHistory => {
222
+ return {
223
+ product_sku: `${item.product.sku}`,
224
+ product_brand_sku: `${item.product.brandSku}`,
225
+ product_name: `${item.product.name}(${item.product.description})`,
226
+ product_desc: item.product.description,
227
+ product_nameOnly: item.product.name,
228
+ product_type: item.packingType,
229
+ product_size: item.packingSize,
230
+ product_batch: item.batchId,
231
+ batch_id_ref: item?.batchIdRef ? item.batchIdRef : '',
232
+ pallet_qty: item.actualPalletQty,
233
+ product_qty: unloadInvHistory.qty || item.actualPackQty,
234
+ product_pack_qty: item.packQty,
235
+ descrepancy_qty: (unloadInvHistory.qty || item.actualPackQty) - item.packQty,
236
+ product_unit_uom_value: `${Math.round(item.uomValue * 100) / 100}`,
237
+ product_total_uom_value: `${
238
+ Math.round((unloadInvHistory.uomValue || item.uomValue * item.actualPackQty) * 100) / 100
239
+ }`,
240
+ product_uom: `${unloadInvHistory.uom || item.uom}`,
241
+ product_gross_weight: item.product.grossWeight || null,
242
+ unit_price: item.unitPrice || null,
243
+ expiry_date: unloadInvHistory.expiryDate && unloadInvHistory.expiryDate != '' ? new Date(unloadInvHistory.expiryDate).toISOString().split('T')[0] : '',
244
+ manufacture_date: item.manufactureDate,
245
+ reusable_pallet_id: unloadInvHistory.reusablePalletId || '',
246
+ remark: (item.remark ? item.remark : '') + (item.issue ? ' [Issue]: ' + item.issue : '')
247
+ }
248
+ })
249
+ )
250
+ return acc
251
+ }, [])
252
+ .map((item, idx) => ({ list_no: idx + 1, ...item })),
253
+ serialNumber: foundInventoryItem
254
+ }
255
+
256
+ const formData = new FormData()
257
+ formData.append('template', template)
258
+ formData.append('jsonString', JSON.stringify(data))
259
+
260
+ const response = await fetch(REPORT_API_URL, {
261
+ method: 'POST',
262
+ body: formData
263
+ })
264
+
265
+ return await response.text()
266
+ }
@@ -1,7 +1,8 @@
1
+ import _ from 'lodash'
1
2
  import FormData from 'form-data'
2
3
  import fetch from 'node-fetch'
3
4
  import { getRepository, IsNull, Not } from 'typeorm'
4
-
5
+ import { InventoryItem } from '@things-factory/warehouse-base'
5
6
  import { Attachment, STORAGE } from '@things-factory/attachment-base'
6
7
  import { Partner } from '@things-factory/auth-base'
7
8
  import { Bizplace, ContactPoint } from '@things-factory/biz-base'
@@ -32,6 +33,10 @@ export async function renderGRN({ grnNo, timezoneOffSet }, context: any) {
32
33
  const foundGAN: ArrivalNotice = foundGRN.arrivalNotice
33
34
  const ownRefNo = foundGAN.refNo
34
35
 
36
+ const foundInventoryItem: InventoryItem[] = await getRepository(InventoryItem).query(
37
+ `select row_number() over (partition by p.sku) as "seq",p.sku,p.brand_sku, ii.serial_number from inventory_items ii left join products p on ii.product_id = p.id where inbound_order_id = '${foundGAN.id}' group by p.sku,ii.serial_number,p.brand_sku`
38
+ )
39
+
35
40
  // 4. find customer bizplace
36
41
  const partnerBiz: Bizplace = foundGRN.bizplace
37
42
 
@@ -47,25 +52,25 @@ export async function renderGRN({ grnNo, timezoneOffSet }, context: any) {
47
52
  })
48
53
 
49
54
  const qbReducedInventory = getRepository(ReducedInventoryHistory)
50
- .createQueryBuilder(`ivh`)
51
- .select(`product_id`, `productId`)
52
- .addSelect(`batch_id`, `batchId`)
53
- .addSelect(`reusable_pallet_id`, `reusablePalletId`)
54
- .addSelect(`packing_type`, `packingType`)
55
- .addSelect(`sum(qty)`, `qty`)
56
- .addSelect(`sum(uom_value)`, `uomValue`)
57
- .addSelect(`uom`, `uom`)
58
- .addSelect(`count(distinct pallet_id)`, `pallet`)
59
- .addSelect(`string_agg(distinct expiration_date::varchar,', ' order by expiration_date::varchar)`, `expiryDate`)
60
- .addSelect(`string_agg(distinct pallet_id::varchar,', ' order by pallet_id::varchar)`, `palletId`)
61
- .where(`ivh.domain_id = :domainId`, { domainId: domain.id })
62
- .andWhere(`ivh.ref_order_id = :refOrderId`, { refOrderId: foundGAN.id })
55
+ .createQueryBuilder('ivh')
56
+ .select('product_id', 'productId')
57
+ .addSelect('batch_id', 'batchId')
58
+ .addSelect('reusable_pallet_id', 'reusablePalletId')
59
+ .addSelect('packing_type', 'packingType')
60
+ .addSelect('sum(qty)', 'qty')
61
+ .addSelect('sum(uom_value)', 'uomValue')
62
+ .addSelect('uom', 'uom')
63
+ .addSelect('count(distinct pallet_id)', 'pallet')
64
+ .addSelect(`string_agg(distinct expiration_date::varchar,', ' order by expiration_date::varchar)`, 'expiryDate')
65
+ .addSelect(`string_agg(distinct pallet_id::varchar,', ' order by pallet_id::varchar)`, 'palletId')
66
+ .where('ivh.domain_id = :domainId', { domainId: domain.id })
67
+ .andWhere('ivh.ref_order_id = :refOrderId', { refOrderId: foundGAN.id })
63
68
  .andWhere(`ivh.transaction_type = 'UNLOADING'`)
64
- .groupBy(`reusable_pallet_id`)
65
- .addGroupBy(`product_id`)
66
- .addGroupBy(`batch_id`)
67
- .addGroupBy(`packing_type`)
68
- .addGroupBy(`uom`)
69
+ .groupBy('reusable_pallet_id')
70
+ .addGroupBy('product_id')
71
+ .addGroupBy('batch_id')
72
+ .addGroupBy('packing_type')
73
+ .addGroupBy('uom')
69
74
  .getRawMany()
70
75
 
71
76
  // 5. find domain contact point
@@ -142,6 +147,32 @@ export async function renderGRN({ grnNo, timezoneOffSet }, context: any) {
142
147
  cop = 'data:' + foundSignature.mimetype + ';base64,' + (await STORAGE.readFile(foundCop.path, 'base64'))
143
148
  }
144
149
 
150
+ const filterInventoryItem = _.groupBy(foundInventoryItem, i => i.sku)
151
+
152
+ const tempIndexArr = []
153
+
154
+ const tempTotalQuantity = []
155
+
156
+ Object.keys(filterInventoryItem).forEach(k => {
157
+ const tempIndex = foundInventoryItem.findIndex(i => {
158
+ return i.sku == k
159
+ })
160
+
161
+ tempIndexArr.push(tempIndex)
162
+ })
163
+
164
+ Object.values(filterInventoryItem).forEach(k => {
165
+ const tempQuantity = k.length
166
+
167
+ tempTotalQuantity.push(tempQuantity)
168
+ })
169
+
170
+ tempIndexArr.forEach((t, index) => {
171
+ if (t >= 0)
172
+ foundInventoryItem[t].totalQuantity = tempTotalQuantity[index]
173
+ })
174
+
175
+
145
176
  const data = {
146
177
  logo_url: logo,
147
178
  sign_url: signature,
@@ -166,6 +197,7 @@ export async function renderGRN({ grnNo, timezoneOffSet }, context: any) {
166
197
  gan_accepted_at: foundGAN.acceptedAt ? DateTimeConverter.datetime(foundGAN.acceptedAt, timezoneOffSet) : '',
167
198
  unload_date: DateTimeConverter.date(foundWS.endedAt),
168
199
  ref_no: ownRefNo ? `${foundGAN.name} / ${foundGAN.refNo}` : `${foundGAN.name}`,
200
+ ref_no_only: ownRefNo ? ` ${foundGAN.refNo}` : '',
169
201
  ref_no1: foundGAN.refNo2 ? `${foundGAN.refNo2}` : '',
170
202
  ref_no2: foundGAN.refNo3 ? `${foundGAN.refNo3}` : '',
171
203
  received_date: DateTimeConverter.date(foundWS.endedAt),
@@ -188,6 +220,7 @@ export async function renderGRN({ grnNo, timezoneOffSet }, context: any) {
188
220
  return {
189
221
  list_no: idx + 1,
190
222
  product_sku: `${item.product.sku}`,
223
+ product_brand_sku: `${item.product.brandSku}`,
191
224
  product_name: `${item.product.name}(${item.product.description})`,
192
225
  product_desc: item.product.description,
193
226
  product_nameOnly: item.product.name,
@@ -198,17 +231,18 @@ export async function renderGRN({ grnNo, timezoneOffSet }, context: any) {
198
231
  pallet_qty: item.actualPalletQty,
199
232
  product_qty: unloadInvHistory.qty || item.actualPackQty,
200
233
  product_unit_uom_value: `${Math.round(item.uomValue * 100) / 100}`,
201
- product_total_uom_value: `${
202
- Math.round((unloadInvHistory.uomValue || item.uomValue * item.actualPackQty) * 100) / 100
203
- }`,
234
+ product_total_uom_value: `${Math.round((unloadInvHistory.uomValue || item.uomValue * item.actualPackQty) * 100) / 100
235
+ }`,
204
236
  product_uom: `${unloadInvHistory.uom || item.uom}`,
205
237
  product_gross_weight: item.product.grossWeight || null,
206
238
  unit_price: item.unitPrice || null,
207
239
  expiry_date: unloadInvHistory.expiryDate || '',
240
+ manufacture_date: item.manufactureDate,
208
241
  reusable_pallet_id: unloadInvHistory.reusablePalletId || '',
209
242
  remark: (item.remark ? item.remark : '') + (item.issue ? ' [Issue]: ' + item.issue : '')
210
243
  }
211
- })
244
+ }),
245
+ serialNumber: foundInventoryItem
212
246
  }
213
247
 
214
248
  const formData = new FormData()