@things-factory/worksheet-base 8.0.0-beta.9 → 8.0.0

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 (288) hide show
  1. package/dist-server/controllers/inbound/unloading-worksheet-controller.js +2 -0
  2. package/dist-server/controllers/inbound/unloading-worksheet-controller.js.map +1 -1
  3. package/dist-server/graphql/resolvers/worksheet/vas-candidates.d.ts +2 -0
  4. package/dist-server/tsconfig.tsbuildinfo +1 -1
  5. package/dist-server/utils/inventory-util.d.ts +2 -0
  6. package/package.json +17 -17
  7. package/server/constants/index.ts +5 -0
  8. package/server/constants/rule-type.ts +4 -0
  9. package/server/constants/target-type.ts +6 -0
  10. package/server/constants/template.ts +12 -0
  11. package/server/constants/transaction-type.ts +9 -0
  12. package/server/constants/worksheet.ts +38 -0
  13. package/server/controllers/ecommerce/ecommerce-controller.ts +209 -0
  14. package/server/controllers/ecommerce/index.ts +2 -0
  15. package/server/controllers/ecommerce/sellercraft-controller.ts +358 -0
  16. package/server/controllers/inbound/index.ts +4 -0
  17. package/server/controllers/inbound/putaway-returning-worksheet-controller.ts +450 -0
  18. package/server/controllers/inbound/putaway-worksheet-controller.ts +454 -0
  19. package/server/controllers/inbound/unloading-returning-worksheet-controller.ts +291 -0
  20. package/server/controllers/inbound/unloading-worksheet-controller.ts +1400 -0
  21. package/server/controllers/index.ts +21 -0
  22. package/server/controllers/inspect/cycle-count-worksheet-controller.ts +537 -0
  23. package/server/controllers/inspect/index.ts +1 -0
  24. package/server/controllers/outbound/index.ts +5 -0
  25. package/server/controllers/outbound/loading-worksheet-controller.ts +377 -0
  26. package/server/controllers/outbound/packing-worksheet-controller.ts +449 -0
  27. package/server/controllers/outbound/picking-worksheet-controller.ts +1769 -0
  28. package/server/controllers/outbound/returning-worksheet-controller.ts +254 -0
  29. package/server/controllers/outbound/sorting-worksheet-controller.ts +554 -0
  30. package/server/controllers/render-elccl-grn.ts +228 -0
  31. package/server/controllers/render-fm-grn.ts +287 -0
  32. package/server/controllers/render-grn.ts +285 -0
  33. package/server/controllers/render-invoices.ts +201 -0
  34. package/server/controllers/render-job-sheet.ts +208 -0
  35. package/server/controllers/render-kimeda-grn.ts +185 -0
  36. package/server/controllers/render-manifest.ts +76 -0
  37. package/server/controllers/render-manual-do.ts +227 -0
  38. package/server/controllers/render-orientage-do.ts +376 -0
  39. package/server/controllers/render-orientage-grn.ts +191 -0
  40. package/server/controllers/render-po.ts +182 -0
  41. package/server/controllers/render-ro-do.ts +404 -0
  42. package/server/controllers/render-seebuu-grn.ts +208 -0
  43. package/server/controllers/vas/index.ts +1 -0
  44. package/server/controllers/vas/vas-worksheet-controller.ts +848 -0
  45. package/server/controllers/worksheet-controller.ts +1267 -0
  46. package/server/entities/index.ts +8 -0
  47. package/server/entities/warehouse-bizplace-onhand-inventory.ts +148 -0
  48. package/server/entities/worksheet-detail.ts +106 -0
  49. package/server/entities/worksheet-movement.ts +34 -0
  50. package/server/entities/worksheet.ts +100 -0
  51. package/server/graphql/index.ts +7 -0
  52. package/server/graphql/resolvers/index.ts +8 -0
  53. package/server/graphql/resolvers/pallet/index.ts +7 -0
  54. package/server/graphql/resolvers/pallet/pallet-outbound.ts +92 -0
  55. package/server/graphql/resolvers/worksheet/batch-picking-worksheet.ts +137 -0
  56. package/server/graphql/resolvers/worksheet/cancel-draft-release-order.ts +20 -0
  57. package/server/graphql/resolvers/worksheet/check-inventory-release.ts +37 -0
  58. package/server/graphql/resolvers/worksheet/check-stock-take-current-location.ts +63 -0
  59. package/server/graphql/resolvers/worksheet/confirm-cancellation-release-order.ts +213 -0
  60. package/server/graphql/resolvers/worksheet/create-worksheet.ts +21 -0
  61. package/server/graphql/resolvers/worksheet/cross-dock-picking.ts +173 -0
  62. package/server/graphql/resolvers/worksheet/cycle-count-adjustment.ts +211 -0
  63. package/server/graphql/resolvers/worksheet/cycle-count-worksheet.ts +79 -0
  64. package/server/graphql/resolvers/worksheet/delete-worksheet.ts +21 -0
  65. package/server/graphql/resolvers/worksheet/delivery-order-by-worksheet.ts +104 -0
  66. package/server/graphql/resolvers/worksheet/fetch-delivery-order-ro.ts +191 -0
  67. package/server/graphql/resolvers/worksheet/fetch-sellercraft-document.ts +69 -0
  68. package/server/graphql/resolvers/worksheet/find-release-orders-by-task-no.ts +36 -0
  69. package/server/graphql/resolvers/worksheet/find-release-orders-by-worksheet-no.ts +29 -0
  70. package/server/graphql/resolvers/worksheet/find-sorting-release-orders-by-task-no.ts +80 -0
  71. package/server/graphql/resolvers/worksheet/generate-worksheet/generate-arrival-notice-worksheet.ts +100 -0
  72. package/server/graphql/resolvers/worksheet/generate-worksheet/generate-batch-picking-worksheet.ts +26 -0
  73. package/server/graphql/resolvers/worksheet/generate-worksheet/generate-cycle-count-worksheet.ts +51 -0
  74. package/server/graphql/resolvers/worksheet/generate-worksheet/generate-multiple-release-good-worksheet.ts +17 -0
  75. package/server/graphql/resolvers/worksheet/generate-worksheet/generate-partial-putaway-return-worksheet.ts +69 -0
  76. package/server/graphql/resolvers/worksheet/generate-worksheet/generate-partial-putaway-worksheet.ts +65 -0
  77. package/server/graphql/resolvers/worksheet/generate-worksheet/generate-putaway-worksheet.ts +54 -0
  78. package/server/graphql/resolvers/worksheet/generate-worksheet/generate-release-good-worksheet.ts +114 -0
  79. package/server/graphql/resolvers/worksheet/generate-worksheet/generate-return-order-worksheet.ts +45 -0
  80. package/server/graphql/resolvers/worksheet/generate-worksheet/generate-vas-order-worksheet.ts +35 -0
  81. package/server/graphql/resolvers/worksheet/generate-worksheet/index.ts +23 -0
  82. package/server/graphql/resolvers/worksheet/having-vas.ts +45 -0
  83. package/server/graphql/resolvers/worksheet/index.ts +142 -0
  84. package/server/graphql/resolvers/worksheet/inspecting/activate-cycle-count.ts +24 -0
  85. package/server/graphql/resolvers/worksheet/inspecting/add-extra-pallet.ts +49 -0
  86. package/server/graphql/resolvers/worksheet/inspecting/check-missing-pallet.ts +18 -0
  87. package/server/graphql/resolvers/worksheet/inspecting/complete-inspection.ts +41 -0
  88. package/server/graphql/resolvers/worksheet/inspecting/index.ts +17 -0
  89. package/server/graphql/resolvers/worksheet/inspecting/inspecting.ts +30 -0
  90. package/server/graphql/resolvers/worksheet/inspecting/relocate-pallet.ts +46 -0
  91. package/server/graphql/resolvers/worksheet/inspecting/undo-inspection.ts +23 -0
  92. package/server/graphql/resolvers/worksheet/inventories-by-pallet.ts +150 -0
  93. package/server/graphql/resolvers/worksheet/loaded-inventories.ts +40 -0
  94. package/server/graphql/resolvers/worksheet/loading/activate-loading.ts +73 -0
  95. package/server/graphql/resolvers/worksheet/loading/complete-loading.ts +165 -0
  96. package/server/graphql/resolvers/worksheet/loading/index.ts +11 -0
  97. package/server/graphql/resolvers/worksheet/loading/loading.ts +46 -0
  98. package/server/graphql/resolvers/worksheet/loading/undo-loading.ts +25 -0
  99. package/server/graphql/resolvers/worksheet/loading-worksheet.ts +150 -0
  100. package/server/graphql/resolvers/worksheet/not-tally-target-inventories.ts +34 -0
  101. package/server/graphql/resolvers/worksheet/packing/activate-packing.ts +69 -0
  102. package/server/graphql/resolvers/worksheet/packing/complete-packing.ts +102 -0
  103. package/server/graphql/resolvers/worksheet/packing/index.ts +13 -0
  104. package/server/graphql/resolvers/worksheet/packing/packing.ts +59 -0
  105. package/server/graphql/resolvers/worksheet/packing/scan-product-packing.ts +70 -0
  106. package/server/graphql/resolvers/worksheet/packing/undo-serial-number-packing.ts +24 -0
  107. package/server/graphql/resolvers/worksheet/packing-worksheet.ts +378 -0
  108. package/server/graphql/resolvers/worksheet/palletizing-pallets.ts +142 -0
  109. package/server/graphql/resolvers/worksheet/pending-cancellation-release-order.ts +234 -0
  110. package/server/graphql/resolvers/worksheet/picking/activate-batch-picking.ts +40 -0
  111. package/server/graphql/resolvers/worksheet/picking/activate-picking.ts +98 -0
  112. package/server/graphql/resolvers/worksheet/picking/assign-picking-inventories.ts +50 -0
  113. package/server/graphql/resolvers/worksheet/picking/assign-picking-worker.ts +44 -0
  114. package/server/graphql/resolvers/worksheet/picking/batch-picking.ts +32 -0
  115. package/server/graphql/resolvers/worksheet/picking/complete-batch-picking.ts +137 -0
  116. package/server/graphql/resolvers/worksheet/picking/complete-picking.ts +282 -0
  117. package/server/graphql/resolvers/worksheet/picking/fetch-and-assign-picking-task.ts +121 -0
  118. package/server/graphql/resolvers/worksheet/picking/index.ts +31 -0
  119. package/server/graphql/resolvers/worksheet/picking/my-picking-assignment-status.ts +35 -0
  120. package/server/graphql/resolvers/worksheet/picking/picking-assignment-status-by-user.ts +96 -0
  121. package/server/graphql/resolvers/worksheet/picking/picking.ts +55 -0
  122. package/server/graphql/resolvers/worksheet/picking/scan-product-batch-picking.ts +52 -0
  123. package/server/graphql/resolvers/worksheet/picking/scan-product-picking.ts +25 -0
  124. package/server/graphql/resolvers/worksheet/picking/seal-tote.ts +25 -0
  125. package/server/graphql/resolvers/worksheet/picking/undo-picking-assignment.ts +31 -0
  126. package/server/graphql/resolvers/worksheet/picking/undo-serial-number-picking.ts +24 -0
  127. package/server/graphql/resolvers/worksheet/picking-worksheet.ts +147 -0
  128. package/server/graphql/resolvers/worksheet/proceed-extra-products.ts +242 -0
  129. package/server/graphql/resolvers/worksheet/putaway/activate-putaway.ts +51 -0
  130. package/server/graphql/resolvers/worksheet/putaway/complete-putaway.ts +105 -0
  131. package/server/graphql/resolvers/worksheet/putaway/index.ts +11 -0
  132. package/server/graphql/resolvers/worksheet/putaway/putaway.ts +26 -0
  133. package/server/graphql/resolvers/worksheet/putaway/undo-putaway.ts +25 -0
  134. package/server/graphql/resolvers/worksheet/putaway-return/activate-putaway-return.ts +55 -0
  135. package/server/graphql/resolvers/worksheet/putaway-return/complete-putaway-return.ts +38 -0
  136. package/server/graphql/resolvers/worksheet/putaway-return/index.ts +11 -0
  137. package/server/graphql/resolvers/worksheet/putaway-return/putaway-return.ts +30 -0
  138. package/server/graphql/resolvers/worksheet/putaway-return/undo-putaway-return.ts +29 -0
  139. package/server/graphql/resolvers/worksheet/putaway-returning-worksheet.ts +83 -0
  140. package/server/graphql/resolvers/worksheet/putaway-worksheet.ts +82 -0
  141. package/server/graphql/resolvers/worksheet/recommend-putway-location.ts +133 -0
  142. package/server/graphql/resolvers/worksheet/reject-cancellation-release-order.ts +186 -0
  143. package/server/graphql/resolvers/worksheet/relocate-pallet.ts +67 -0
  144. package/server/graphql/resolvers/worksheet/replace-picking-pallets.ts +127 -0
  145. package/server/graphql/resolvers/worksheet/return-worksheet.ts +70 -0
  146. package/server/graphql/resolvers/worksheet/returning/activate-return.ts +24 -0
  147. package/server/graphql/resolvers/worksheet/returning/complete-return.ts +39 -0
  148. package/server/graphql/resolvers/worksheet/returning/index.ts +9 -0
  149. package/server/graphql/resolvers/worksheet/returning/returning.ts +26 -0
  150. package/server/graphql/resolvers/worksheet/sorting/activate-sorting.ts +25 -0
  151. package/server/graphql/resolvers/worksheet/sorting/complete-order-sorting.ts +40 -0
  152. package/server/graphql/resolvers/worksheet/sorting/complete-worksheet-sorting.ts +23 -0
  153. package/server/graphql/resolvers/worksheet/sorting/index.ts +13 -0
  154. package/server/graphql/resolvers/worksheet/sorting/scan-product-sorting.ts +31 -0
  155. package/server/graphql/resolvers/worksheet/sorting/sorting-product.ts +32 -0
  156. package/server/graphql/resolvers/worksheet/sorting-worksheet.ts +87 -0
  157. package/server/graphql/resolvers/worksheet/transfer.ts +176 -0
  158. package/server/graphql/resolvers/worksheet/unloaded-inventories-by-reusable-pallet.ts +54 -0
  159. package/server/graphql/resolvers/worksheet/unloaded-inventories.ts +78 -0
  160. package/server/graphql/resolvers/worksheet/unloading/activate-unloading.ts +56 -0
  161. package/server/graphql/resolvers/worksheet/unloading/complete-product-scan-unload.ts +25 -0
  162. package/server/graphql/resolvers/worksheet/unloading/complete-unloading-partially.ts +25 -0
  163. package/server/graphql/resolvers/worksheet/unloading/complete-unloading.ts +76 -0
  164. package/server/graphql/resolvers/worksheet/unloading/index.ts +21 -0
  165. package/server/graphql/resolvers/worksheet/unloading/scan-product-unload.ts +26 -0
  166. package/server/graphql/resolvers/worksheet/unloading/scan-serial-number-unload.ts +26 -0
  167. package/server/graphql/resolvers/worksheet/unloading/undo-serial-number-unload.ts +24 -0
  168. package/server/graphql/resolvers/worksheet/unloading/undo-unloading.ts +25 -0
  169. package/server/graphql/resolvers/worksheet/unloading/unload.ts +26 -0
  170. package/server/graphql/resolvers/worksheet/unloading-return/activate-unloading-return.ts +28 -0
  171. package/server/graphql/resolvers/worksheet/unloading-return/complete-unload-return-partially.ts +29 -0
  172. package/server/graphql/resolvers/worksheet/unloading-return/complete-unload-returning.ts +91 -0
  173. package/server/graphql/resolvers/worksheet/unloading-return/index.ts +9 -0
  174. package/server/graphql/resolvers/worksheet/unloading-return-worksheet.ts +75 -0
  175. package/server/graphql/resolvers/worksheet/unloading-worksheet.ts +98 -0
  176. package/server/graphql/resolvers/worksheet/update-worksheet.ts +25 -0
  177. package/server/graphql/resolvers/worksheet/vas/activate-vas.ts +25 -0
  178. package/server/graphql/resolvers/worksheet/vas/assign-vas-inventories.ts +25 -0
  179. package/server/graphql/resolvers/worksheet/vas/complete-vas.ts +72 -0
  180. package/server/graphql/resolvers/worksheet/vas/execute-vas.ts +31 -0
  181. package/server/graphql/resolvers/worksheet/vas/index.ts +15 -0
  182. package/server/graphql/resolvers/worksheet/vas/undo-vas-inventory.ts +24 -0
  183. package/server/graphql/resolvers/worksheet/vas/undo-vas.ts +24 -0
  184. package/server/graphql/resolvers/worksheet/vas-candidates.ts +177 -0
  185. package/server/graphql/resolvers/worksheet/vas-inventories.ts +41 -0
  186. package/server/graphql/resolvers/worksheet/vas-transactions/common-utils.ts +1182 -0
  187. package/server/graphql/resolvers/worksheet/vas-transactions/index.ts +5 -0
  188. package/server/graphql/resolvers/worksheet/vas-transactions/interfaces/index.ts +56 -0
  189. package/server/graphql/resolvers/worksheet/vas-transactions/interfaces/relabeling.ts +20 -0
  190. package/server/graphql/resolvers/worksheet/vas-transactions/interfaces/repackaging.ts +27 -0
  191. package/server/graphql/resolvers/worksheet/vas-transactions/interfaces/repalletizing.ts +14 -0
  192. package/server/graphql/resolvers/worksheet/vas-transactions/interfaces/unpacking.ts +14 -0
  193. package/server/graphql/resolvers/worksheet/vas-transactions/relabeling/check-relabelable.ts +96 -0
  194. package/server/graphql/resolvers/worksheet/vas-transactions/relabeling/complete-relabeling.ts +93 -0
  195. package/server/graphql/resolvers/worksheet/vas-transactions/relabeling/index.ts +4 -0
  196. package/server/graphql/resolvers/worksheet/vas-transactions/relabeling/relabeling.ts +105 -0
  197. package/server/graphql/resolvers/worksheet/vas-transactions/relabeling/undo-relabeling.ts +40 -0
  198. package/server/graphql/resolvers/worksheet/vas-transactions/repackaging/complete-repackaging.ts +236 -0
  199. package/server/graphql/resolvers/worksheet/vas-transactions/repackaging/index.ts +3 -0
  200. package/server/graphql/resolvers/worksheet/vas-transactions/repackaging/repackaging.ts +402 -0
  201. package/server/graphql/resolvers/worksheet/vas-transactions/repackaging/undo-repackaging.ts +166 -0
  202. package/server/graphql/resolvers/worksheet/vas-transactions/repalletizing/complete-repalletizing.ts +116 -0
  203. package/server/graphql/resolvers/worksheet/vas-transactions/repalletizing/index.ts +3 -0
  204. package/server/graphql/resolvers/worksheet/vas-transactions/repalletizing/repalletizing.ts +167 -0
  205. package/server/graphql/resolvers/worksheet/vas-transactions/repalletizing/undo-repalletizing.ts +74 -0
  206. package/server/graphql/resolvers/worksheet/vas-transactions/unpacking/complete-unpacking.ts +20 -0
  207. package/server/graphql/resolvers/worksheet/vas-transactions/unpacking/index.ts +2 -0
  208. package/server/graphql/resolvers/worksheet/vas-transactions/unpacking/unpacking.ts +164 -0
  209. package/server/graphql/resolvers/worksheet/vas-worksheet.ts +110 -0
  210. package/server/graphql/resolvers/worksheet/worksheet-by-order-no.ts +43 -0
  211. package/server/graphql/resolvers/worksheet/worksheet-with-pagination.ts +46 -0
  212. package/server/graphql/resolvers/worksheet/worksheet.ts +330 -0
  213. package/server/graphql/resolvers/worksheet/worksheets.ts +493 -0
  214. package/server/graphql/resolvers/worksheet-detail/check-progressing-pallet.ts +22 -0
  215. package/server/graphql/resolvers/worksheet-detail/create-worksheet-detail.ts +38 -0
  216. package/server/graphql/resolvers/worksheet-detail/delete-worksheet-detail.ts +18 -0
  217. package/server/graphql/resolvers/worksheet-detail/generate-batch-picking-worksheet-details-by-bulk.ts +206 -0
  218. package/server/graphql/resolvers/worksheet-detail/generate-batch-picking-worksheet-details.ts +165 -0
  219. package/server/graphql/resolvers/worksheet-detail/generate-carton-id.ts +26 -0
  220. package/server/graphql/resolvers/worksheet-detail/generate-pallet-id.ts +94 -0
  221. package/server/graphql/resolvers/worksheet-detail/generate-picking-worksheet-details.ts +259 -0
  222. package/server/graphql/resolvers/worksheet-detail/generate-release-good-worksheet-details.ts +142 -0
  223. package/server/graphql/resolvers/worksheet-detail/index.ts +34 -0
  224. package/server/graphql/resolvers/worksheet-detail/regenerate-release-good-worksheet-details.ts +165 -0
  225. package/server/graphql/resolvers/worksheet-detail/update-worksheet-detail.ts +39 -0
  226. package/server/graphql/resolvers/worksheet-detail/worksheet-detail.ts +19 -0
  227. package/server/graphql/resolvers/worksheet-detail/worksheet-details-by-product-group.ts +56 -0
  228. package/server/graphql/resolvers/worksheet-detail/worksheet-details.ts +21 -0
  229. package/server/graphql/resolvers/worksheet-movement/create-worksheet-movement.ts +17 -0
  230. package/server/graphql/resolvers/worksheet-movement/delete-worksheet-movement.ts +12 -0
  231. package/server/graphql/resolvers/worksheet-movement/index.ts +17 -0
  232. package/server/graphql/resolvers/worksheet-movement/update-worksheet-movement.ts +15 -0
  233. package/server/graphql/resolvers/worksheet-movement/worksheet-movement.ts +10 -0
  234. package/server/graphql/resolvers/worksheet-movement/worksheet-movements.ts +14 -0
  235. package/server/graphql/types/index.ts +15 -0
  236. package/server/graphql/types/pallet/index.ts +12 -0
  237. package/server/graphql/types/pallet/pallet.ts +7 -0
  238. package/server/graphql/types/worksheet/arrival-notice-worksheet.ts +8 -0
  239. package/server/graphql/types/worksheet/batch-pick-worksheet-info.ts +9 -0
  240. package/server/graphql/types/worksheet/contact-point-info.ts +12 -0
  241. package/server/graphql/types/worksheet/cycle-count-worksheet.ts +16 -0
  242. package/server/graphql/types/worksheet/delivery-info.ts +11 -0
  243. package/server/graphql/types/worksheet/delivery-order-info.ts +25 -0
  244. package/server/graphql/types/worksheet/delivery-order-ro.ts +15 -0
  245. package/server/graphql/types/worksheet/delivery-worksheet.ts +7 -0
  246. package/server/graphql/types/worksheet/executing-worksheet.ts +8 -0
  247. package/server/graphql/types/worksheet/find-release-orders-by-task-no.ts +8 -0
  248. package/server/graphql/types/worksheet/goods-delivery-note.ts +8 -0
  249. package/server/graphql/types/worksheet/index.ts +750 -0
  250. package/server/graphql/types/worksheet/inventory-check-worksheet.ts +7 -0
  251. package/server/graphql/types/worksheet/loaded-worksheet-detail.ts +9 -0
  252. package/server/graphql/types/worksheet/multiple-release-good-worksheet.ts +8 -0
  253. package/server/graphql/types/worksheet/my-picking-assignment-status.ts +9 -0
  254. package/server/graphql/types/worksheet/new-worksheet.ts +10 -0
  255. package/server/graphql/types/worksheet/picking-assignment-status.ts +9 -0
  256. package/server/graphql/types/worksheet/product-approval.ts +11 -0
  257. package/server/graphql/types/worksheet/release-good-worksheet.ts +8 -0
  258. package/server/graphql/types/worksheet/return-order-worksheet.ts +8 -0
  259. package/server/graphql/types/worksheet/sellercraft-document.ts +8 -0
  260. package/server/graphql/types/worksheet/vas-order-worksheet.ts +7 -0
  261. package/server/graphql/types/worksheet/vas-worksheet.ts +8 -0
  262. package/server/graphql/types/worksheet/worksheet-detail-info.ts +68 -0
  263. package/server/graphql/types/worksheet/worksheet-info.ts +33 -0
  264. package/server/graphql/types/worksheet/worksheet-list.ts +8 -0
  265. package/server/graphql/types/worksheet/worksheet-patch.ts +19 -0
  266. package/server/graphql/types/worksheet/worksheet-with-pagination.ts +9 -0
  267. package/server/graphql/types/worksheet/worksheet.ts +34 -0
  268. package/server/graphql/types/worksheet-detail/index.ts +81 -0
  269. package/server/graphql/types/worksheet-detail/inventory-detail.ts +39 -0
  270. package/server/graphql/types/worksheet-detail/new-worksheet-detail.ts +20 -0
  271. package/server/graphql/types/worksheet-detail/pallet-info.ts +8 -0
  272. package/server/graphql/types/worksheet-detail/worksheet-detail-list.ts +8 -0
  273. package/server/graphql/types/worksheet-detail/worksheet-detail-patch.ts +28 -0
  274. package/server/graphql/types/worksheet-detail/worksheet-detail.ts +29 -0
  275. package/server/graphql/types/worksheet-movement/index.ts +30 -0
  276. package/server/graphql/types/worksheet-movement/new-worksheet-movement.ts +8 -0
  277. package/server/graphql/types/worksheet-movement/worksheet-movement-list.ts +8 -0
  278. package/server/graphql/types/worksheet-movement/worksheet-movement-patch.ts +8 -0
  279. package/server/graphql/types/worksheet-movement/worksheet-movement.ts +10 -0
  280. package/server/index.ts +14 -0
  281. package/server/middlewares/index.ts +3 -0
  282. package/server/migrations/index.ts +9 -0
  283. package/server/routes.ts +80 -0
  284. package/server/utils/datetime-util.ts +54 -0
  285. package/server/utils/index.ts +4 -0
  286. package/server/utils/inventory-util.ts +390 -0
  287. package/server/utils/worksheet-no-generator.ts +206 -0
  288. package/server/utils/worksheet-util.ts +85 -0
@@ -0,0 +1,1769 @@
1
+ import { EntityManager, Equal, getConnection, In, IsNull, Not } from 'typeorm'
2
+
3
+ import { Bizplace } from '@things-factory/biz-base'
4
+ import { generateId } from '@things-factory/id-rule-base'
5
+ import { Product, ProductDetail } from '@things-factory/product-base'
6
+ import {
7
+ //@ts-ignore
8
+ GenerateBatchPickInfo,
9
+ ORDER_INVENTORY_STATUS,
10
+ ORDER_PRODUCT_STATUS,
11
+ ORDER_STATUS,
12
+ OrderInventory,
13
+ OrderNoGenerator,
14
+ OrderProduct,
15
+ OrderTote,
16
+ OrderToteItem,
17
+ OrderToteSeal,
18
+ OrderVas,
19
+ ReleaseGood
20
+ } from '@things-factory/sales-base'
21
+ import { Setting } from '@things-factory/setting-base'
22
+ import {
23
+ Inventory,
24
+ INVENTORY_ITEM_SOURCE,
25
+ INVENTORY_STATUS,
26
+ INVENTORY_TRANSACTION_TYPE,
27
+ InventoryItem,
28
+ InventoryNoGenerator,
29
+ Location,
30
+ LOCATION_TYPE,
31
+ Tote,
32
+ TOTE_STATUS
33
+ } from '@things-factory/warehouse-base'
34
+
35
+ import { TASK_NUMBER_RULE_TYPE, TASK_NUMBER_SETTING_KEY, WORKSHEET_STATUS, WORKSHEET_TYPE } from '../../constants'
36
+ import { Worksheet, WorksheetDetail } from '../../entities'
37
+ import { generateInventoryHistory, WorksheetNoGenerator } from '../../utils'
38
+ import { VasWorksheetController } from '../vas/vas-worksheet-controller'
39
+
40
+ export class PickingWorksheetController extends VasWorksheetController {
41
+ async generatePickingWorksheet(releaseGoodNo: string, currentStatus: string = null): Promise<Worksheet> {
42
+ //@ts-ignore
43
+ let releaseGood: ReleaseGood = await this.findRefOrder(
44
+ //@ts-ignore
45
+ ReleaseGood,
46
+ {
47
+ domain: { id: this.domain.id },
48
+ name: releaseGoodNo,
49
+ status: ORDER_STATUS.PENDING_WORKSHEET
50
+ },
51
+ ['orderInventories', 'orderInventories.inventory', 'orderVass']
52
+ )
53
+ const orderInventories: OrderInventory[] = releaseGood.orderInventories
54
+ const orderVASs: OrderVas[] = releaseGood.orderVass
55
+
56
+ let worksheet: Worksheet = await this.createWorksheet(releaseGood, WORKSHEET_TYPE.PICKING)
57
+
58
+ if (orderInventories.every((oi: OrderInventory) => oi.inventory?.id) || releaseGood.crossDocking) {
59
+ worksheet.worksheetDetails = await this.createWorksheetDetails(
60
+ worksheet,
61
+ WORKSHEET_TYPE.PICKING,
62
+ orderInventories
63
+ )
64
+ }
65
+
66
+ orderInventories.forEach((oi: OrderInventory) => {
67
+ oi.status =
68
+ oi.crossDocking || oi.inventory?.id
69
+ ? ORDER_INVENTORY_STATUS.READY_TO_PICK
70
+ : ORDER_INVENTORY_STATUS.PENDING_SPLIT
71
+ oi.updater = this.user
72
+ })
73
+ await this.updateOrderTargets(orderInventories)
74
+
75
+ if (orderVASs?.length > 0) {
76
+ await this.generateVasWorksheet(releaseGood)
77
+ }
78
+
79
+ releaseGood.status = ORDER_STATUS.READY_TO_PICK
80
+ releaseGood.updater = this.user
81
+ await this.updateRefOrder(releaseGood, null, currentStatus)
82
+
83
+ return worksheet
84
+ }
85
+
86
+ async generateBatchPickingWorksheet(releaseGoodWithBiz: [GenerateBatchPickInfo[]]): Promise<Worksheet[]> {
87
+ let worksheets = []
88
+
89
+ for (let i = 0; i < releaseGoodWithBiz.length; i++) {
90
+ let releaseGoodNos = releaseGoodWithBiz[i].map(itm => itm.releaseGoodNo)
91
+
92
+ let releaseGoods: ReleaseGood[] = await this.trxMgr.getRepository(ReleaseGood).find({
93
+ where: { domain: { id: this.domain.id }, name: In(releaseGoodNos), status: ORDER_STATUS.PENDING_WORKSHEET },
94
+ relations: [
95
+ 'orderProducts',
96
+ 'orderProducts.product',
97
+ 'orderInventories',
98
+ 'orderInventories.inventory',
99
+ 'bizplace',
100
+ 'bizplace.domain'
101
+ ]
102
+ })
103
+
104
+ let orderInventories: OrderInventory[] = []
105
+ releaseGoods.map((releaseGood: ReleaseGood) => {
106
+ const foundOIs: OrderInventory[] = releaseGood.orderInventories
107
+ foundOIs.map((oi: OrderInventory) => {
108
+ orderInventories.push(oi)
109
+ })
110
+ })
111
+
112
+ const worksheetSetting: Setting = await this.trxMgr.getRepository(Setting).findOne({
113
+ where: {
114
+ domain: { id: this.domain.id },
115
+ name: TASK_NUMBER_SETTING_KEY.TASK_NO_RULE
116
+ }
117
+ })
118
+ if (!worksheetSetting) throw new Error(this.ERROR_MSG.FIND.NO_RESULT('task number rule'))
119
+
120
+ let worksheet: Worksheet = new Worksheet()
121
+ worksheet.name = WorksheetNoGenerator.generate(WORKSHEET_TYPE.BATCH_PICKING)
122
+ worksheet.type = WORKSHEET_TYPE.BATCH_PICKING
123
+ worksheet.taskNo = await generateId({
124
+ domain: this.domain,
125
+ type: TASK_NUMBER_RULE_TYPE.TASK_NO,
126
+ seed: {}
127
+ })
128
+ worksheet.status = WORKSHEET_STATUS.DEACTIVATED
129
+ worksheet.bizplace = releaseGoodWithBiz[i][0].bizplaceId
130
+ worksheet.domain = this.domain
131
+ worksheet.creator = this.user
132
+ worksheet.updater = this.user
133
+ worksheet = await this.trxMgr.getRepository(Worksheet).save(worksheet)
134
+
135
+ if (orderInventories.some((oi: OrderInventory) => oi.inventory?.id)) {
136
+ const hasInventoryOIs: OrderInventory[] = orderInventories.filter(
137
+ (orderInventory: OrderInventory) => orderInventory.inventory !== null
138
+ )
139
+
140
+ worksheet.worksheetDetails = await this.createWorksheetDetails(
141
+ worksheet,
142
+ WORKSHEET_TYPE.BATCH_PICKING,
143
+ hasInventoryOIs
144
+ )
145
+ }
146
+
147
+ orderInventories.forEach((oi: OrderInventory) => {
148
+ oi.refWorksheetId = worksheet.id
149
+ oi.status = oi.inventory?.id ? ORDER_INVENTORY_STATUS.READY_TO_PICK : ORDER_INVENTORY_STATUS.PENDING_SPLIT
150
+ oi.updater = this.user
151
+ })
152
+ await this.updateOrderTargets(orderInventories)
153
+
154
+ releaseGoods = releaseGoods.map((releaseGood: ReleaseGood) => {
155
+ return {
156
+ ...releaseGood,
157
+ status: ORDER_STATUS.READY_TO_PICK,
158
+ updater: this.user
159
+ }
160
+ })
161
+ await this.trxMgr.getRepository(ReleaseGood).save(releaseGoods)
162
+
163
+ worksheets.push(worksheet)
164
+ }
165
+ return worksheets
166
+ }
167
+
168
+ async generateBatchPickingWorksheetDetail(
169
+ worksheet: Worksheet,
170
+ targetInventory: Partial<OrderInventory>[]
171
+ ): Promise<WorksheetDetail[]> {
172
+ // Create worksheet details
173
+ //@ts-ignore
174
+ return await this.createWorksheetDetails(worksheet, WORKSHEET_TYPE.BATCH_PICKING, [targetInventory])
175
+ }
176
+
177
+ async generatePickingWorksheetDetail(
178
+ worksheet: Worksheet,
179
+ targetInventory: Partial<OrderInventory>[]
180
+ ): Promise<WorksheetDetail[]> {
181
+ // Create worksheet details
182
+ //@ts-ignore
183
+ return await this.createWorksheetDetails(worksheet, WORKSHEET_TYPE.PICKING, [targetInventory])
184
+ }
185
+
186
+ async activatePicking(worksheetNo: string): Promise<Worksheet> {
187
+ let worksheet: Worksheet = await this.findActivatableWorksheet(worksheetNo, WORKSHEET_TYPE.PICKING, [
188
+ 'releaseGood',
189
+ 'releaseGood.bizplace',
190
+ 'domain',
191
+ 'bizplace',
192
+ 'bizplace.domain',
193
+ 'bizplace.company',
194
+ 'bizplace.company.domain',
195
+ 'worksheetDetails',
196
+ 'worksheetDetails.targetInventory',
197
+ 'worksheetDetails.targetInventory.product'
198
+ ])
199
+
200
+ const worksheetDetails: WorksheetDetail[] = worksheet.worksheetDetails.filter(x => x.status == 'DEACTIVATED')
201
+ const targetInventories: OrderInventory[] = worksheetDetails.map((wsd: WorksheetDetail) => {
202
+ let targetInventory: OrderInventory = wsd.targetInventory
203
+ targetInventory.status = ORDER_INVENTORY_STATUS.PICKING
204
+ targetInventory.updater = this.user
205
+ return targetInventory
206
+ })
207
+ this.updateOrderTargets(targetInventories)
208
+
209
+ let releaseGood: ReleaseGood = worksheet.releaseGood
210
+ releaseGood.status = ORDER_STATUS.PICKING
211
+ releaseGood.updater = this.user
212
+ this.updateRefOrder(releaseGood)
213
+
214
+ worksheet = await this.activateWorksheet(worksheet, worksheetDetails, [])
215
+
216
+ try {
217
+ const vasWorksheet: Worksheet = await this.findWorksheetByRefOrder(releaseGood, WORKSHEET_TYPE.VAS)
218
+ if (vasWorksheet) {
219
+ await this.activateVAS(vasWorksheet.name, vasWorksheet.worksheetDetails)
220
+ }
221
+ } catch (e) {}
222
+
223
+ const pendingSplitOIs: OrderInventory[] = await this.trxMgr.getRepository(OrderInventory).find({
224
+ where: {
225
+ domain: { id: this.domain.id },
226
+ releaseGood: { id: releaseGood.id },
227
+ status: ORDER_INVENTORY_STATUS.PENDING_SPLIT
228
+ }
229
+ })
230
+ if (pendingSplitOIs?.length) {
231
+ const ids: string[] = pendingSplitOIs.map((oi: OrderInventory) => oi.id)
232
+ await this.trxMgr.getRepository(OrderInventory).delete(ids)
233
+ }
234
+
235
+ return worksheet
236
+ }
237
+
238
+ async activateBatchPicking(worksheetNo: string): Promise<Worksheet> {
239
+ let worksheet: Worksheet = await this.findActivatableWorksheet(worksheetNo, WORKSHEET_TYPE.BATCH_PICKING, [
240
+ 'worksheetDetails',
241
+ 'worksheetDetails.targetInventory',
242
+ 'worksheetDetails.targetInventory.releaseGood',
243
+ 'worksheetDetails.targetInventory.product',
244
+ 'worksheetDetails.targetInventory.releaseGood.orderProducts',
245
+ 'worksheetDetails.targetInventory.releaseGood.orderProducts.product',
246
+ 'bizplace',
247
+ 'bizplace.domain',
248
+ 'bizplace.company',
249
+ 'bizplace.company.domain'
250
+ ])
251
+
252
+ const worksheetDetails: WorksheetDetail[] = worksheet.worksheetDetails.filter(x => x.status == 'DEACTIVATED')
253
+ const targetInventories: OrderInventory[] = worksheetDetails.map((wsd: WorksheetDetail) => {
254
+ let targetInventory: OrderInventory = wsd.targetInventory
255
+ targetInventory.status = ORDER_INVENTORY_STATUS.PICKING
256
+ targetInventory.updater = this.user
257
+ return targetInventory
258
+ })
259
+ this.updateOrderTargets(targetInventories)
260
+
261
+ worksheet = await this.activateWorksheet(worksheet, worksheetDetails, [])
262
+
263
+ // retrieve order inventory
264
+ const pickingOrderInventory: OrderInventory[] = await this.trxMgr.getRepository(OrderInventory).find({
265
+ where: { domain: { id: this.domain.id }, refWorksheetId: worksheet.id, status: ORDER_STATUS.PICKING },
266
+ relations: ['releaseGood']
267
+ })
268
+
269
+ let releaseGoods: ReleaseGood[] = pickingOrderInventory.map((oi: OrderInventory) => oi.releaseGood)
270
+
271
+ if (releaseGoods?.length) {
272
+ releaseGoods = releaseGoods.map((rg: ReleaseGood) => {
273
+ return {
274
+ ...rg,
275
+ status: ORDER_STATUS.PICKING,
276
+ updater: this.user
277
+ }
278
+ })
279
+ await this.trxMgr.getRepository(ReleaseGood).save(releaseGoods)
280
+ }
281
+
282
+ return worksheet
283
+ }
284
+
285
+ async assignPickingInventories(
286
+ worksheetNo: string,
287
+ batchId: string,
288
+ productId: string,
289
+ packingType: string,
290
+ packingSize: number,
291
+ worksheetDetails: Partial<WorksheetDetail>[]
292
+ ): Promise<void> {
293
+ // 1. Remove prev worksheet details if it's exists
294
+ const worksheet: Worksheet = await this.findWorksheetByNo(worksheetNo, [
295
+ 'bizplace',
296
+ 'releaseGood',
297
+ 'worksheetDetails'
298
+ ])
299
+ const releaseGood: ReleaseGood = worksheet.releaseGood
300
+ const bizplace: Bizplace = worksheet.bizplace
301
+ const prevWorksheetDetails: WorksheetDetail[] = await this.extractMatchedWorksheetDetails(
302
+ worksheet.worksheetDetails,
303
+ batchId,
304
+ productId,
305
+ packingType,
306
+ packingSize
307
+ )
308
+ // Delete order inventories
309
+ if (prevWorksheetDetails?.length) {
310
+ const worksheetDetailIds: string[] = prevWorksheetDetails.map((wsd: WorksheetDetail) => wsd.id)
311
+ const prevTargetInventoryIds: string[] = prevWorksheetDetails.map(
312
+ (wsd: WorksheetDetail) => wsd.targetInventory.id
313
+ )
314
+
315
+ await this.trxMgr.getRepository(WorksheetDetail).delete(worksheetDetailIds)
316
+ await this.trxMgr.getRepository(OrderInventory).delete(prevTargetInventoryIds)
317
+ }
318
+
319
+ for (let worksheetDetail of worksheetDetails) {
320
+ if (worksheetDetail.targetInventory?.inventory?.id) {
321
+ worksheetDetail = await this.findWorksheetDetail(worksheetDetail, [
322
+ 'targetInventory',
323
+ 'targetInventory.inventory'
324
+ ])
325
+ }
326
+
327
+ const targetInventory: OrderInventory = worksheetDetail.targetInventory
328
+ let inventory: Inventory = await this.trxMgr
329
+ .getRepository(Inventory)
330
+ .findOneBy({ id: targetInventory.inventory.id })
331
+ const product: Product = await this.trxMgr.getRepository(Product).findOneBy({ id: productId })
332
+
333
+ // Create order inventories
334
+ let newTargetInventory: OrderInventory = Object.assign({}, targetInventory)
335
+ //@ts-ignore
336
+ delete newTargetInventory.id
337
+ newTargetInventory.domain = this.domain
338
+ newTargetInventory.bizplace = bizplace
339
+ newTargetInventory.name = OrderNoGenerator.orderInventory()
340
+ newTargetInventory.releaseGood = releaseGood
341
+ newTargetInventory.inventory = inventory
342
+ newTargetInventory.batchId = batchId
343
+ newTargetInventory.product = product
344
+ newTargetInventory.packingType = packingType
345
+ newTargetInventory.packingSize = packingSize
346
+ newTargetInventory.creator = this.user
347
+ newTargetInventory.updater = this.user
348
+ newTargetInventory = await this.trxMgr.getRepository(OrderInventory).save(newTargetInventory)
349
+
350
+ // Update locked qty and uomValue of inventory
351
+ inventory.lockedQty = targetInventory.releaseQty + (inventory.lockedQty || 0)
352
+ inventory.lockedUomValue = targetInventory.releaseUomValue + (inventory.lockedUomValue || 0)
353
+ await this.updateInventory(inventory)
354
+
355
+ // Create worksheet details
356
+ await this.createWorksheetDetails(worksheet, WORKSHEET_TYPE.PICKING, [newTargetInventory])
357
+ }
358
+ }
359
+
360
+ async undoPickingAssigment(
361
+ worksheetNo: string,
362
+ batchId: string,
363
+ productId: string,
364
+ packingType: string,
365
+ packingSize: number
366
+ ): Promise<void> {
367
+ const worksheet: Worksheet = await this.findWorksheetByNo(worksheetNo, [
368
+ 'worksheetDetails',
369
+ 'worksheetDetails.targetInventory',
370
+ 'worksheetDetails.targetInventory.inventory',
371
+ 'worksheetDetails.targetInventory.product',
372
+ 'worksheetDetails.targetInventory.orderProduct'
373
+ ])
374
+
375
+ const worksheetDetails: WorksheetDetail[] = await this.extractMatchedWorksheetDetails(
376
+ worksheet.worksheetDetails,
377
+ batchId,
378
+ productId,
379
+ packingType,
380
+ packingSize,
381
+ ['targetInventory', 'targetInventory.inventory', 'targetInventory.orderProduct']
382
+ )
383
+
384
+ let worksheetDetailIds: string[] = []
385
+ let targetInventoryIds: string[] = []
386
+
387
+ for (const worksheetDetail of worksheetDetails) {
388
+ worksheetDetailIds.push(worksheetDetail.id)
389
+ const targetInventory: OrderInventory = worksheetDetail.targetInventory
390
+ targetInventoryIds.push(targetInventory.id)
391
+
392
+ let inventory: Inventory = await this.trxMgr
393
+ .getRepository(Inventory)
394
+ .findOne({ where: { id: worksheetDetail.targetInventory.inventory.id } })
395
+ inventory.lockedQty = inventory.lockedQty - targetInventory.releaseQty
396
+ inventory.lockedUomValue = inventory.lockedUomValue - targetInventory.releaseUomValue
397
+ await this.updateInventory(inventory)
398
+
399
+ await this.trxMgr
400
+ .getRepository(OrderProduct)
401
+ .update(
402
+ { id: targetInventory.orderProduct.id },
403
+ { status: ORDER_PRODUCT_STATUS.PENDING_ASSIGN, updater: this.user as any }
404
+ )
405
+ }
406
+
407
+ await this.trxMgr.getRepository(WorksheetDetail).delete(worksheetDetailIds)
408
+ await this.trxMgr.getRepository(OrderInventory).delete(targetInventoryIds)
409
+
410
+ await this.trxMgr.getRepository(OrderInventory).update(
411
+ {
412
+ refWorksheetId: worksheet.id,
413
+ batchId,
414
+ product: { id: productId },
415
+ packingType,
416
+ packingSize,
417
+ status: ORDER_INVENTORY_STATUS.COMPLETE_SPLIT
418
+ },
419
+ {
420
+ status: ORDER_INVENTORY_STATUS.PENDING_SPLIT,
421
+ updater: this.user as any,
422
+ updatedAt: new Date() as any
423
+ }
424
+ )
425
+ }
426
+
427
+ async scanProductPicking(
428
+ worksheetDetailName: string,
429
+ worksheetType: string,
430
+ productBarcode: string,
431
+ cartonId: string,
432
+ binLocation?: string,
433
+ serialNumber?: string,
434
+ toteNo?: string,
435
+ pickedQty: number = 1
436
+ ): Promise<WorksheetDetail> {
437
+ try {
438
+ //find existing worksheet detail
439
+ let worksheetDetail: WorksheetDetail = await this.trxMgr
440
+ .getRepository(WorksheetDetail)
441
+ .createQueryBuilder('wd')
442
+ .innerJoinAndSelect('wd.worksheet', 'ws')
443
+ .innerJoinAndSelect('ws.bizplace', 'bz')
444
+ .innerJoinAndSelect('wd.targetInventory', 'oi')
445
+ .innerJoinAndSelect('oi.releaseGood', 'rg')
446
+ .innerJoinAndSelect('oi.inventory', 'inv')
447
+ .leftJoinAndSelect('oi.orderProduct', 'op')
448
+ .innerJoinAndSelect('oi.product', 'prd')
449
+ .leftJoinAndSelect(
450
+ 'prd.productDetails',
451
+ 'pd',
452
+ 'pd.product_id = oi.product_id AND pd.deleted_at is null AND pd.packing_type = oi.packing_type AND pd.packing_size = oi.packing_size AND pd.uom = oi.uom'
453
+ )
454
+ .where('wd.name = :name', { name: worksheetDetailName })
455
+ .andWhere('wd.domain_id = :domainId', { domainId: this.domain.id })
456
+ .andWhere('wd.type = :type', { type: worksheetType })
457
+ .andWhere('wd.status = :status', { status: WORKSHEET_STATUS.EXECUTING })
458
+ .andWhere('inv.carton_id = :cartonId', { cartonId: cartonId })
459
+ .getOne()
460
+
461
+ //validation to check matching worksheet detail based on name
462
+ if (!worksheetDetail || !worksheetDetail.targetInventory)
463
+ throw new Error(this.ERROR_MSG.FIND.NO_RESULT(worksheetDetailName))
464
+
465
+ //validation to prevent duplicated picking
466
+ if (worksheetDetail?.targetInventory?.status != ORDER_INVENTORY_STATUS.PICKING)
467
+ throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `is done`))
468
+
469
+ let matchingProduct = await this.getDirectQty(
470
+ {
471
+ ...worksheetDetail?.targetInventory?.product?.productDetails[0],
472
+ product: worksheetDetail?.targetInventory?.product
473
+ },
474
+ productBarcode,
475
+ pickedQty
476
+ )
477
+
478
+ //validate matching product details based on scanned barcode
479
+ if (!matchingProduct) throw new Error(this.ERROR_MSG.FIND.NO_RESULT(productBarcode))
480
+
481
+ pickedQty = matchingProduct.qty
482
+ let pickedUomValue = matchingProduct.uomValue
483
+
484
+ //validation to prevent over release
485
+ if (
486
+ !worksheetDetail?.targetInventory ||
487
+ worksheetDetail?.targetInventory.inventory.qty < 1 ||
488
+ pickedQty + (worksheetDetail.targetInventory?.pickedQty || 0) > worksheetDetail.targetInventory.releaseQty
489
+ )
490
+ throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `over release`))
491
+
492
+ const releaseGood: ReleaseGood = worksheetDetail.targetInventory.releaseGood
493
+
494
+ let targetInventory: OrderInventory = worksheetDetail.targetInventory
495
+ let targetProduct: OrderProduct = targetInventory.orderProduct
496
+ let inventory: Inventory = targetInventory.inventory
497
+ let bizplace: Bizplace = worksheetDetail.worksheet.bizplace
498
+ const product: Product = targetInventory.product
499
+
500
+ targetInventory = await this.checkAndSetBinPicking(targetInventory, binLocation)
501
+
502
+ // for required outbound serial number scanning
503
+ if (product?.isRequireSerialNumberScanningOutbound) {
504
+ if (!serialNumber || serialNumber == '') {
505
+ throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `require serial number`))
506
+ }
507
+
508
+ let totalInventoryItems = await this.trxMgr.getRepository(InventoryItem).count({
509
+ where: {
510
+ inventory: { id: inventory.id },
511
+ status: Not(In([INVENTORY_STATUS.TERMINATED, INVENTORY_STATUS.PICKED]))
512
+ }
513
+ })
514
+
515
+ let foundSerialNumber: InventoryItem = await this.trxMgr.getRepository(InventoryItem).findOne({
516
+ where: { domain: { id: this.domain.id }, serialNumber: serialNumber, product: { id: product.id } }
517
+ })
518
+
519
+ if (foundSerialNumber) {
520
+ if (foundSerialNumber.inventoryId !== inventory.id) {
521
+ throw new Error('Serial Number scanned is in another inventory')
522
+ }
523
+
524
+ if (foundSerialNumber.outboundOrderId) {
525
+ let releaseGood: ReleaseGood = await this.trxMgr
526
+ .getRepository(ReleaseGood)
527
+ .findOne({ where: { id: foundSerialNumber.outboundOrderId } })
528
+ throw new Error(`Inventory Item is already picked in ${releaseGood.name}`)
529
+ }
530
+
531
+ foundSerialNumber.status = INVENTORY_STATUS.PICKING
532
+ foundSerialNumber.updater = this.user
533
+ foundSerialNumber.outboundOrderId = releaseGood.id
534
+
535
+ await this.trxMgr.getRepository(InventoryItem).save(foundSerialNumber)
536
+ } else {
537
+ if (totalInventoryItems >= inventory.qty) {
538
+ throw new Error('Insufficient inventory quantity to scan new serial number')
539
+ }
540
+
541
+ let inventoryItem: InventoryItem = new InventoryItem()
542
+ inventoryItem.name = InventoryNoGenerator.inventoryItemName()
543
+ inventoryItem.serialNumber = serialNumber
544
+ inventoryItem.status = INVENTORY_STATUS.PICKING
545
+ inventoryItem.outboundOrderId = releaseGood.id
546
+ inventoryItem.source = INVENTORY_ITEM_SOURCE.OUTBOUND
547
+ inventoryItem.product = product
548
+ inventoryItem.inventory = inventory
549
+ inventoryItem.domain = this.domain
550
+
551
+ await this.trxMgr.getRepository(InventoryItem).save(inventoryItem)
552
+ }
553
+ }
554
+
555
+ // for tote scanning
556
+ if (toteNo) {
557
+ await this.toteScanning(toteNo, targetProduct, targetInventory, pickedQty, releaseGood, bizplace)
558
+ }
559
+
560
+ // temporarily override with separate logic to handle transaction to speed up function
561
+ // await this.updatePickingTransaction(releaseGood, targetInventory, worksheetDetail, inventory, pickedQty)
562
+
563
+ const releaseQty: number = targetInventory.releaseQty
564
+
565
+ targetInventory.pickedQty = (targetInventory?.pickedQty || 0) + pickedQty
566
+
567
+ let updateOiObj = {
568
+ pickedQty: () => `"picked_qty" + ${pickedQty}`,
569
+ updatedAt: new Date(),
570
+ updater: this.user,
571
+ pickedBy: this.user.name,
572
+ pickedByUser: this.user,
573
+ pickedAt: new Date()
574
+ }
575
+
576
+ if (targetInventory.pickedQty == releaseQty) {
577
+ updateOiObj['status'] = ORDER_INVENTORY_STATUS.PICKED
578
+ }
579
+
580
+ if (targetInventory.binLocation) {
581
+ updateOiObj['binLocation'] = targetInventory.binLocation
582
+ }
583
+
584
+ await this.trxMgr
585
+ .getRepository(OrderInventory)
586
+ .createQueryBuilder()
587
+ .update(OrderInventory)
588
+ .set(updateOiObj as any)
589
+ .where({ id: targetInventory.id })
590
+ .andWhere(`picked_qty + :pickedQty <= release_qty`, { pickedQty })
591
+ .execute()
592
+
593
+ if (targetInventory.pickedQty == releaseQty) {
594
+ //update worksheet details only when line item picking complete
595
+ await this.trxMgr
596
+ .getRepository(WorksheetDetail)
597
+ .createQueryBuilder()
598
+ .update(WorksheetDetail)
599
+ .set({
600
+ status: WORKSHEET_STATUS.DONE,
601
+ updater: this.user,
602
+ updatedAt: new Date()
603
+ })
604
+ .where('id = :id', { id: worksheetDetail.id })
605
+ .execute()
606
+
607
+ getConnection().transaction(async (tx: EntityManager) => {
608
+ let releaseUomValue = Math.round((pickedUomValue / pickedQty) * releaseQty * 100) / 100
609
+
610
+ let updateInvObj = {
611
+ qty: () => `"qty" - ${releaseQty}`,
612
+ lockedQty: () => `"locked_qty" - ${releaseQty}`,
613
+ uomValue: () => `"uom_value" - ${releaseUomValue}`,
614
+ lockedUomValue: () => `"locked_uom_value" - ${releaseUomValue}`,
615
+ updater: this.user,
616
+ updatedAt: new Date()
617
+ }
618
+
619
+ let remainingQty = await tx
620
+ .getRepository(Inventory)
621
+ .createQueryBuilder()
622
+ .update(Inventory)
623
+ .set(updateInvObj as any)
624
+ .where('id = :id', { id: targetInventory.inventory.id })
625
+ .returning(['qty'])
626
+ .execute()
627
+ .then(dt => {
628
+ return dt.raw[0].qty
629
+ })
630
+
631
+ await generateInventoryHistory(
632
+ inventory,
633
+ releaseGood,
634
+ INVENTORY_TRANSACTION_TYPE.PICKING,
635
+ -releaseQty,
636
+ -releaseUomValue,
637
+ this.user,
638
+ tx
639
+ )
640
+
641
+ //@ts-ignore
642
+ let inventoryItems: InventoryItem = await tx
643
+ .getRepository(InventoryItem)
644
+ .find({ where: { outboundOrderId: releaseGood.id } })
645
+
646
+ //@ts-ignore
647
+ if (inventoryItems.length > 0) {
648
+ //@ts-ignore
649
+ inventoryItems.forEach((itm: InventoryItem) => {
650
+ itm.status = INVENTORY_STATUS.PICKED
651
+ itm.updater = this.user
652
+ })
653
+
654
+ await tx.getRepository(InventoryItem).save(inventoryItems)
655
+ }
656
+
657
+ if (remainingQty === 0) {
658
+ await tx
659
+ .getRepository(Inventory)
660
+ .createQueryBuilder()
661
+ .update(Inventory)
662
+ .set({ status: INVENTORY_STATUS.TERMINATED })
663
+ .where('id = :id', { id: targetInventory.inventory.id })
664
+ .execute()
665
+
666
+ await generateInventoryHistory(
667
+ inventory,
668
+ releaseGood,
669
+ INVENTORY_TRANSACTION_TYPE.TERMINATED,
670
+ 0,
671
+ 0,
672
+ this.user,
673
+ tx
674
+ )
675
+ }
676
+ })
677
+ }
678
+
679
+ // return worksheet details
680
+ worksheetDetail = await this.trxMgr
681
+ .getRepository(WorksheetDetail)
682
+ .createQueryBuilder('wd')
683
+ .innerJoin('wd.targetInventory', 'oi')
684
+ .innerJoinAndSelect('oi.releaseGood', 'rg')
685
+ .where('wd.id = :id', { id: worksheetDetail.id })
686
+ .getOne()
687
+
688
+ return worksheetDetail
689
+ } catch (error) {
690
+ throw error
691
+ }
692
+ }
693
+
694
+ async picking(
695
+ worksheetDetailName: string,
696
+ worksheetType: string,
697
+ palletId: string,
698
+ locationName: string,
699
+ pickedQty: number,
700
+ binLocation?: string,
701
+ serialNumber?: string,
702
+ toteNo?: string
703
+ ): Promise<void> {
704
+ try {
705
+ let worksheetDetail: WorksheetDetail = await this.findExecutableWorksheetDetailByName(
706
+ worksheetDetailName,
707
+ worksheetType,
708
+ [
709
+ 'worksheet',
710
+ 'worksheet.bizplace',
711
+ 'targetInventory',
712
+ 'targetInventory.releaseGood',
713
+ 'targetInventory.orderProduct',
714
+ 'targetInventory.inventory',
715
+ 'targetInventory.inventory.location',
716
+ 'targetInventory.product'
717
+ ]
718
+ )
719
+
720
+ const releaseGood: ReleaseGood = worksheetDetail.targetInventory.releaseGood
721
+ let targetInventory: OrderInventory = worksheetDetail.targetInventory
722
+ const product: Product = targetInventory.product
723
+ let inventory: Inventory = targetInventory.inventory
724
+ let targetProduct: OrderProduct = targetInventory.orderProduct
725
+ let bizplace: Bizplace = worksheetDetail.worksheet.bizplace
726
+
727
+ //validation to prevent duplicated picking
728
+ let oiValidate: OrderInventory = await this.trxMgr.getRepository(OrderInventory).findOne({
729
+ where: { domain: { id: this.domain.id }, id: targetInventory.id, status: ORDER_INVENTORY_STATUS.PICKING }
730
+ })
731
+ if (!oiValidate) throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `is done`))
732
+
733
+ //validation to prevent over release
734
+ if (inventory.qty <= 0) throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `over release`))
735
+
736
+ if (inventory.palletId !== palletId && !product?.isRequireSerialNumberScanningOutbound)
737
+ throw new Error(this.ERROR_MSG.VALIDITY.UNEXPECTED_FIELD_VALUE('Pallet ID', palletId, inventory.palletId))
738
+
739
+ if (product?.isRequireSerialNumberScanningOutbound) {
740
+ if (!serialNumber || serialNumber == '') {
741
+ throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `require serial number`))
742
+ }
743
+
744
+ let totalInventoryItems = await this.trxMgr.getRepository(InventoryItem).count({
745
+ where: {
746
+ inventory: { id: inventory.id },
747
+ status: Not(In([INVENTORY_STATUS.TERMINATED, INVENTORY_STATUS.PICKED]))
748
+ }
749
+ })
750
+
751
+ let foundSerialNumber: InventoryItem = await this.trxMgr.getRepository(InventoryItem).findOne({
752
+ where: { domain: { id: this.domain.id }, serialNumber: serialNumber, product: { id: product.id } },
753
+ relations: ['product', 'inventory']
754
+ })
755
+
756
+ let scannedPalletIdInventory: Inventory = await this.trxMgr
757
+ .getRepository(Inventory)
758
+ .findOne({ where: { domain: { id: this.domain.id }, palletId }, relations: ['product'] })
759
+
760
+ if (foundSerialNumber) {
761
+ if (foundSerialNumber.outboundOrderId) {
762
+ let releaseGood: ReleaseGood = await this.trxMgr
763
+ .getRepository(ReleaseGood)
764
+ .findOne({ where: { id: foundSerialNumber.outboundOrderId } })
765
+ throw new Error(`Inventory Item is already picked in ${releaseGood.name}`)
766
+ }
767
+
768
+ foundSerialNumber.status = INVENTORY_STATUS.PICKING
769
+ foundSerialNumber.updater = this.user
770
+ foundSerialNumber.outboundOrderId = releaseGood.id
771
+
772
+ await this.trxMgr.getRepository(InventoryItem).save(foundSerialNumber)
773
+ } else {
774
+ if (totalInventoryItems >= inventory.qty) {
775
+ throw new Error('Insufficient inventory quantity to scan new serial number')
776
+ }
777
+
778
+ let inventoryItem: InventoryItem = new InventoryItem()
779
+ inventoryItem.name = InventoryNoGenerator.inventoryItemName()
780
+ inventoryItem.serialNumber = serialNumber
781
+ inventoryItem.status = INVENTORY_STATUS.PICKING
782
+ inventoryItem.source = INVENTORY_ITEM_SOURCE.OUTBOUND
783
+ inventoryItem.outboundOrderId = releaseGood.id
784
+ inventoryItem.product = product
785
+ inventoryItem.inventory = scannedPalletIdInventory
786
+ inventoryItem.domain = this.domain
787
+
788
+ foundSerialNumber = await this.trxMgr.getRepository(InventoryItem).save(inventoryItem)
789
+ }
790
+
791
+ if (inventory.palletId !== palletId) {
792
+ let existingOrderInv = await this.trxMgr.getRepository(OrderInventory).findOne({
793
+ where: {
794
+ domain: { id: this.domain.id },
795
+ inventory: { id: scannedPalletIdInventory.id },
796
+ releaseGood: { id: releaseGood.id }
797
+ }
798
+ })
799
+
800
+ if (existingOrderInv) {
801
+ //if replacement order inventory already existed in worksheet detail
802
+ await this.serialNumberReplacementForExistingOrderInv(
803
+ existingOrderInv,
804
+ targetInventory,
805
+ worksheetDetail,
806
+ foundSerialNumber
807
+ )
808
+ } else if (
809
+ scannedPalletIdInventory.batchId == inventory.batchId &&
810
+ scannedPalletIdInventory.product.id == product.id &&
811
+ scannedPalletIdInventory.product.packingType == product.packingType
812
+ ) {
813
+ //if replacement order inventory does not exist
814
+ await this.serialNumberReplacement(
815
+ targetInventory,
816
+ scannedPalletIdInventory,
817
+ releaseGood,
818
+ product,
819
+ worksheetDetail,
820
+ foundSerialNumber
821
+ )
822
+ } else {
823
+ throw new Error(this.ERROR_MSG.VALIDITY.UNEXPECTED_FIELD_VALUE('Pallet ID', palletId, inventory.palletId))
824
+ }
825
+ }
826
+ }
827
+
828
+ targetInventory = await this.checkAndSetBinPicking(targetInventory, binLocation)
829
+
830
+ if (toteNo) {
831
+ await this.toteScanning(toteNo, targetProduct, targetInventory, pickedQty, releaseGood, bizplace)
832
+ }
833
+
834
+ await this.updatePickingTransaction(releaseGood, targetInventory, worksheetDetail, inventory, pickedQty)
835
+
836
+ const fromLocation: Location = targetInventory.inventory.location
837
+ if (locationName) {
838
+ const toLocation: Location = await this.trxMgr.getRepository(Location).findOne({
839
+ where: { domain: { id: this.domain.id }, name: locationName },
840
+ relations: ['warehouse']
841
+ })
842
+
843
+ if (!toLocation) throw new Error(this.ERROR_MSG.FIND.NO_RESULT(locationName))
844
+
845
+ if (fromLocation.id !== toLocation.id) {
846
+ inventory.location = toLocation
847
+ inventory.warehouse = toLocation.warehouse
848
+ inventory.zone = toLocation.zone
849
+ inventory = await this.transactionInventory(inventory, releaseGood, 0, 0, INVENTORY_TRANSACTION_TYPE.RELOCATE)
850
+ }
851
+ }
852
+ } catch (error) {
853
+ throw error
854
+ }
855
+ }
856
+
857
+ async batchPicking(
858
+ taskNo: string,
859
+ worksheetType: string,
860
+ palletId: string,
861
+ locationName: string,
862
+ binLocationName: string,
863
+ releaseQty: number
864
+ ): Promise<void> {
865
+ const worksheet: Worksheet = await this.trxMgr.getRepository(Worksheet).findOne({
866
+ where: { domain: { id: this.domain.id }, taskNo, type: worksheetType, status: WORKSHEET_STATUS.EXECUTING }
867
+ })
868
+
869
+ const foundInventory: Inventory = await this.trxMgr.getRepository(Inventory).findOne({
870
+ where: { domain: { id: this.domain.id }, palletId }
871
+ })
872
+
873
+ const targetInventories: OrderInventory[] = await this.trxMgr.getRepository(OrderInventory).find({
874
+ where: {
875
+ domain: { id: this.domain.id },
876
+ refWorksheetId: worksheet.id,
877
+ status: ORDER_INVENTORY_STATUS.PICKING,
878
+ inventory: { id: foundInventory.id }
879
+ },
880
+ relations: ['inventory', 'inventory.location', 'releaseGood']
881
+ })
882
+
883
+ const targetInventoryId: string[] = targetInventories.map((oi: OrderInventory) => oi.id)
884
+
885
+ let worksheetDetails: WorksheetDetail[] = await this.trxMgr.getRepository(WorksheetDetail).find({
886
+ where: {
887
+ domain: { id: this.domain.id },
888
+ type: worksheetType,
889
+ status: WORKSHEET_STATUS.EXECUTING,
890
+ targetInventory: { id: In(targetInventoryId) }
891
+ }
892
+ })
893
+
894
+ const sumOfReleaseQty: number = targetInventories
895
+ .map((oi: OrderInventory) => oi.releaseQty)
896
+ .reduce((a, b) => a + b, 0)
897
+
898
+ if (sumOfReleaseQty != releaseQty)
899
+ throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `insufficient picking quantity`))
900
+
901
+ for (var i = 0; i < targetInventories.length; i++) {
902
+ let targetInventory: OrderInventory = targetInventories[i]
903
+ let inventory: Inventory = await this.trxMgr.getRepository(Inventory).findOne({
904
+ where: { domain: { id: this.domain.id }, id: targetInventory.inventory.id }
905
+ })
906
+
907
+ const releaseGood: ReleaseGood = targetInventory.releaseGood
908
+
909
+ if (inventory.palletId !== palletId)
910
+ throw new Error(this.ERROR_MSG.VALIDITY.UNEXPECTED_FIELD_VALUE('Pallet ID', palletId, inventory.palletId))
911
+
912
+ const leftQty: number = inventory.qty - targetInventory.releaseQty
913
+ if (leftQty < 0) {
914
+ throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `quantity can't exceed limitation`))
915
+ }
916
+
917
+ if (binLocationName) {
918
+ const binLocation: Location = await this.trxMgr.getRepository(Location).findOne({
919
+ where: { domain: { id: this.domain.id }, name: binLocationName, type: LOCATION_TYPE.BIN }
920
+ })
921
+
922
+ if (!binLocation)
923
+ throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `invalid bin location id`))
924
+
925
+ targetInventory.binLocation = binLocation
926
+ }
927
+
928
+ targetInventory.pickedQty = targetInventory.releaseQty
929
+ targetInventory.status = ORDER_INVENTORY_STATUS.PICKED
930
+ await this.updateOrderTargets([targetInventory])
931
+
932
+ inventory.qty -= targetInventory.releaseQty
933
+ inventory.uomValue = Math.round((inventory.uomValue - targetInventory.releaseUomValue) * 100) / 100
934
+ inventory.lockedQty = inventory.lockedQty - targetInventory.releaseQty
935
+ inventory.lockedUomValue = Math.round((inventory.lockedUomValue - targetInventory.releaseUomValue) * 100) / 100
936
+ await this.transactionInventory(
937
+ inventory,
938
+ releaseGood,
939
+ -targetInventory.releaseQty,
940
+ -targetInventory.releaseUomValue,
941
+ INVENTORY_TRANSACTION_TYPE.PICKING
942
+ )
943
+
944
+ if (leftQty === 0) {
945
+ inventory.status = INVENTORY_STATUS.TERMINATED
946
+ await this.transactionInventory(inventory, releaseGood, 0, 0, INVENTORY_TRANSACTION_TYPE.TERMINATED)
947
+ }
948
+
949
+ const fromLocation: Location = targetInventory.inventory.location
950
+ if (locationName) {
951
+ const toLocation: Location = await this.trxMgr.getRepository(Location).findOne({
952
+ where: { domain: { id: this.domain.id }, name: locationName },
953
+ relations: ['warehouse']
954
+ })
955
+
956
+ if (!toLocation) throw new Error(this.ERROR_MSG.FIND.NO_RESULT(locationName))
957
+
958
+ if (fromLocation.id !== toLocation.id) {
959
+ inventory.location = toLocation
960
+ inventory.warehouse = toLocation.warehouse
961
+ inventory.zone = toLocation.zone
962
+ await this.transactionInventory(inventory, releaseGood, 0, 0, INVENTORY_TRANSACTION_TYPE.RELOCATE)
963
+ }
964
+ }
965
+ }
966
+
967
+ worksheetDetails = worksheetDetails.map((worksheetDetail: WorksheetDetail) => {
968
+ return {
969
+ ...worksheetDetail,
970
+ status: WORKSHEET_STATUS.DONE,
971
+ updater: this.user
972
+ }
973
+ })
974
+ await this.trxMgr.getRepository(WorksheetDetail).save(worksheetDetails)
975
+ }
976
+
977
+ async scanProductBatchPicking(
978
+ taskNo: string,
979
+ worksheetType: string,
980
+ cartonId: string,
981
+ productBarcode: string,
982
+ inventory: any,
983
+ binLocationName: string,
984
+ pickingQty: number
985
+ ): Promise<void> {
986
+ const worksheet: Worksheet = await this.trxMgr.getRepository(Worksheet).findOne({
987
+ where: { domain: { id: this.domain.id }, taskNo, type: worksheetType, status: WORKSHEET_STATUS.EXECUTING },
988
+ relations: [
989
+ 'worksheetDetails',
990
+ 'worksheetDetails.targetInventory',
991
+ 'worksheetDetails.targetInventory.releaseGood',
992
+ 'worksheetDetails.targetInventory.inventory',
993
+ 'worksheetDetails.targetInventory.inventory.location',
994
+ 'worksheetDetails.targetInventory.product',
995
+ 'worksheetDetails.targetInventory.product.productDetails',
996
+ 'worksheetDetails.targetInventory.product.productDetails.childProductDetail'
997
+ ]
998
+ })
999
+
1000
+ const worksheetDetails: WorksheetDetail[] = worksheet.worksheetDetails
1001
+ const product: Product = worksheetDetails
1002
+ .map((wsd: WorksheetDetail) => wsd.targetInventory.product)
1003
+ .find((product: Product) => product.id === inventory.product.id)
1004
+
1005
+ const batchId: string = inventory.batchId
1006
+ const packingType: string = inventory.packingType
1007
+ const packingSize: number = inventory.packingSize
1008
+ let pickedQty: number = pickingQty ? pickingQty : 1
1009
+
1010
+ const targetInventories: OrderInventory[] = worksheetDetails
1011
+ .map((wsd: WorksheetDetail) => wsd.targetInventory)
1012
+ .filter(
1013
+ (targetInventory: OrderInventory) =>
1014
+ targetInventory.batchId === batchId &&
1015
+ targetInventory.packingType === packingType &&
1016
+ targetInventory.inventory.cartonId === cartonId &&
1017
+ targetInventory.product.id === product.id
1018
+ )
1019
+
1020
+ // search for matching product barcode
1021
+ const productDetails: ProductDetail[] = product?.productDetails.filter(detail => !detail.deletedAt)
1022
+ const isMatchingBarcode: boolean = productDetails.map(detail => detail.gtin).includes(productBarcode)
1023
+ if (!isMatchingBarcode) throw new Error(this.ERROR_MSG.FIND.NO_RESULT(`GTIN (${productBarcode})`))
1024
+
1025
+ // case for scanning parent packing type, packing size
1026
+ const foundProductDetail: ProductDetail = productDetails.find(
1027
+ (detail: ProductDetail) =>
1028
+ detail.gtin === productBarcode && detail.packingType === packingType && detail.packingSize == packingSize
1029
+ )
1030
+
1031
+ if (!foundProductDetail) {
1032
+ const roProductDetail: ProductDetail = productDetails.find(
1033
+ (parentDetail: ProductDetail) =>
1034
+ parentDetail.packingType === packingType && parentDetail.packingSize == packingSize
1035
+ )
1036
+ if (!roProductDetail)
1037
+ throw new Error(
1038
+ this.ERROR_MSG.FIND.NO_RESULT(`Packing Type ( ${packingType}) or Packing Size (${packingSize})`)
1039
+ )
1040
+
1041
+ let childQty = await this.getChildQty(productDetails, productBarcode, roProductDetail)
1042
+ pickedQty *= childQty
1043
+ }
1044
+
1045
+ const sumOfReleaseQty: number = targetInventories
1046
+ .map((oi: OrderInventory) => oi.releaseQty)
1047
+ .reduce((a, b) => a + b, 0)
1048
+
1049
+ const sumOfPickedQty: number =
1050
+ targetInventories.map((oi: OrderInventory) => oi.pickedQty).reduce((a, b) => a + b, 0) + pickedQty
1051
+
1052
+ if (sumOfPickedQty > sumOfReleaseQty)
1053
+ throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `quantity can't exceed limitation`))
1054
+
1055
+ for (var i = 0; i < targetInventories.length; i++) {
1056
+ let targetInventory: OrderInventory = targetInventories[i]
1057
+ let inventory: Inventory = targetInventory.inventory
1058
+ const targetReleaseQty: number = targetInventory.releaseQty
1059
+ const targetPickedQty: number = targetInventory.pickedQty
1060
+ const releaseGood: ReleaseGood = targetInventory.releaseGood
1061
+ if (pickedQty <= 0) break
1062
+
1063
+ if (
1064
+ targetInventory.status === ORDER_INVENTORY_STATUS.PICKING &&
1065
+ targetReleaseQty > targetPickedQty &&
1066
+ pickedQty > 0
1067
+ ) {
1068
+ let remainingAssignedQty: number = pickedQty - (targetReleaseQty - targetPickedQty) // -1, 0, 1
1069
+ const gapQtyRemaining: number = targetReleaseQty - targetPickedQty // > 0
1070
+
1071
+ if (binLocationName && !targetInventory?.binLocation) {
1072
+ const binLocation: Location = await this.trxMgr.getRepository(Location).findOne({
1073
+ where: { domain: { id: this.domain.id }, name: binLocationName, type: LOCATION_TYPE.BIN }
1074
+ })
1075
+
1076
+ if (!binLocation)
1077
+ throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `invalid bin location id`))
1078
+
1079
+ targetInventory.binLocation = binLocation
1080
+ }
1081
+
1082
+ // pickedQty = 1, gap = 5 || pickedQty = 12, gap = 5 || pickedQty = 5, gap = 5
1083
+ targetInventory.pickedQty += pickedQty > gapQtyRemaining ? gapQtyRemaining : pickedQty
1084
+ remainingAssignedQty = remainingAssignedQty < 0 ? 0 : remainingAssignedQty
1085
+
1086
+ if (targetInventory.pickedQty == targetReleaseQty) {
1087
+ const leftQty: number = inventory.qty - targetInventory.releaseQty
1088
+ if (leftQty < 0) {
1089
+ throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `quantity can't exceed limitation`))
1090
+ }
1091
+
1092
+ targetInventory.status = ORDER_INVENTORY_STATUS.PICKED
1093
+ await this.updateOrderTargets([targetInventory])
1094
+
1095
+ inventory.qty -= targetInventory.releaseQty
1096
+ inventory.uomValue = Math.round((inventory.uomValue - targetInventory.releaseUomValue) * 100) / 100
1097
+ inventory.lockedQty = inventory.lockedQty - targetInventory.releaseQty
1098
+ inventory.lockedUomValue =
1099
+ Math.round((inventory.lockedUomValue - targetInventory.releaseUomValue) * 100) / 100
1100
+ await this.transactionInventory(
1101
+ inventory,
1102
+ releaseGood,
1103
+ -targetInventory.releaseQty,
1104
+ -targetInventory.releaseUomValue,
1105
+ INVENTORY_TRANSACTION_TYPE.PICKING
1106
+ )
1107
+
1108
+ if (leftQty === 0) {
1109
+ inventory.status = INVENTORY_STATUS.TERMINATED
1110
+ await this.transactionInventory(inventory, releaseGood, 0, 0, INVENTORY_TRANSACTION_TYPE.TERMINATED)
1111
+ }
1112
+
1113
+ let worksheetDetail: WorksheetDetail = worksheetDetails.find(
1114
+ (wsd: WorksheetDetail) => wsd.targetInventory.id === targetInventory.id
1115
+ )
1116
+ worksheetDetail.status = WORKSHEET_STATUS.DONE
1117
+ worksheetDetail.updater = this.user
1118
+ await this.trxMgr.getRepository(WorksheetDetail).save(worksheetDetail)
1119
+ } else {
1120
+ await this.updateOrderTargets([targetInventory])
1121
+ }
1122
+ pickedQty = pickedQty - (targetReleaseQty - targetPickedQty)
1123
+ }
1124
+ }
1125
+ }
1126
+
1127
+ async completePicking(releaseGoodNo: string): Promise<Worksheet> {
1128
+ //@ts-ignore
1129
+ let releaseGood: ReleaseGood = await this.findRefOrder(ReleaseGood, {
1130
+ domain: { id: this.domain.id },
1131
+ name: releaseGoodNo,
1132
+ status: ORDER_STATUS.PICKING
1133
+ })
1134
+
1135
+ const foundNotSealedOrderTote = await this.trxMgr
1136
+ .getRepository(OrderTote)
1137
+ .findOne({ where: { releaseGood: { id: releaseGood.id }, closedDate: IsNull() } })
1138
+
1139
+ if (foundNotSealedOrderTote) {
1140
+ throw new Error('Please seal the tote(s) before completing')
1141
+ }
1142
+
1143
+ let worksheet: Worksheet = await this.findWorksheetByRefOrder(releaseGood, WORKSHEET_TYPE.PICKING, [
1144
+ 'worksheetDetails',
1145
+ 'worksheetDetails.targetInventory'
1146
+ ])
1147
+ await this.checkRecordValidity(worksheet, { status: WORKSHEET_STATUS.EXECUTING })
1148
+
1149
+ //@ts-ignore
1150
+ let inventoryItems: InventoryItem = await this.trxMgr
1151
+ .getRepository(InventoryItem)
1152
+ .find({ where: { outboundOrderId: releaseGood.id } })
1153
+
1154
+ //@ts-ignore
1155
+ if (inventoryItems.length > 0) {
1156
+ //@ts-ignore
1157
+ inventoryItems.forEach((itm: InventoryItem) => {
1158
+ itm.status = INVENTORY_STATUS.TERMINATED
1159
+ itm.updater = this.user
1160
+ })
1161
+
1162
+ await this.trxMgr.getRepository(InventoryItem).save(inventoryItems)
1163
+ }
1164
+
1165
+ let orderStatus: string
1166
+ if (releaseGood?.packingOption) {
1167
+ orderStatus = ORDER_STATUS.READY_TO_PACK
1168
+ } else {
1169
+ orderStatus = ORDER_STATUS.LOADING
1170
+ }
1171
+
1172
+ return await this.completeWorksheet(worksheet, orderStatus)
1173
+ }
1174
+
1175
+ async completeBatchPicking(taskNo: string): Promise<Worksheet> {
1176
+ let worksheet: Worksheet = await this.trxMgr.getRepository(Worksheet).findOne({
1177
+ where: {
1178
+ domain: { id: this.domain.id },
1179
+ taskNo,
1180
+ type: WORKSHEET_TYPE.BATCH_PICKING
1181
+ },
1182
+ relations: [
1183
+ 'bizplace',
1184
+ 'bizplace.domain',
1185
+ 'worksheetDetails',
1186
+ 'worksheetDetails.targetInventory',
1187
+ 'worksheetDetails.targetInventory.releaseGood'
1188
+ ]
1189
+ })
1190
+
1191
+ this.checkRecordValidity(worksheet, { status: WORKSHEET_STATUS.EXECUTING })
1192
+
1193
+ worksheet.status = WORKSHEET_STATUS.DONE
1194
+ worksheet.endedAt = new Date()
1195
+ worksheet.updater = this.user
1196
+ worksheet = await this.trxMgr.getRepository(Worksheet).save(worksheet)
1197
+
1198
+ const worksheetDetails: any = worksheet.worksheetDetails.filter(wsD => wsD.status != 'MISSING')
1199
+ worksheetDetails.forEach((wsd: WorksheetDetail) => {
1200
+ wsd.status = WORKSHEET_STATUS.DONE
1201
+ wsd.updater = this.user
1202
+ })
1203
+ await this.trxMgr.getRepository(WorksheetDetail).save(worksheetDetails)
1204
+
1205
+ const targetInventories: OrderInventory[] = worksheetDetails.map((wsd: WorksheetDetail) => {
1206
+ let targetInventory: OrderInventory = wsd.targetInventory
1207
+ targetInventory.status = ORDER_INVENTORY_STATUS.TERMINATED
1208
+ targetInventory.updater = this.user
1209
+ return targetInventory
1210
+ })
1211
+ await this.updateOrderTargets(targetInventories)
1212
+
1213
+ const releaseGoods: ReleaseGood[] = worksheetDetails.map((wsd: WorksheetDetail) => {
1214
+ let releaseGood: ReleaseGood = wsd.targetInventory.releaseGood
1215
+
1216
+ let orderStatus: string
1217
+ if (releaseGood?.packingOption) {
1218
+ orderStatus = ORDER_STATUS.READY_TO_PACK
1219
+ } else {
1220
+ orderStatus = ORDER_STATUS.READY_TO_SORT
1221
+ }
1222
+
1223
+ releaseGood.status = orderStatus
1224
+ releaseGood.updater = this.user
1225
+ return releaseGood
1226
+ })
1227
+ await this.trxMgr.getRepository(ReleaseGood).save(releaseGoods)
1228
+
1229
+ return worksheet
1230
+ }
1231
+
1232
+ private async extractMatchedWorksheetDetails(
1233
+ worksheetDetails: Partial<WorksheetDetail[]>,
1234
+ standardBatchId: string,
1235
+ standardProductId: string,
1236
+ standardPackingType: string,
1237
+ standardPackingSize: number,
1238
+ relations: string[] = ['targetInventory', 'targetInventory.product']
1239
+ ): Promise<WorksheetDetail[]> {
1240
+ for (let wsd of worksheetDetails) {
1241
+ if (!wsd.targetInventory?.batchId || !wsd.targetInventory?.product?.id || !wsd.targetInventory?.packingType) {
1242
+ wsd = await this.findWorksheetDetail(wsd, ['targetInventory', 'targetInventory.product'])
1243
+ }
1244
+ }
1245
+
1246
+ worksheetDetails = worksheetDetails.filter(
1247
+ (wsd: WorksheetDetail) =>
1248
+ wsd.targetInventory.batchId === standardBatchId &&
1249
+ wsd.targetInventory.product.id === standardProductId &&
1250
+ wsd.targetInventory.packingType === standardPackingType &&
1251
+ wsd.targetInventory.packingSize === standardPackingSize
1252
+ )
1253
+
1254
+ for (let wsd of worksheetDetails) {
1255
+ wsd = await this.findWorksheetDetail(wsd, relations)
1256
+ }
1257
+
1258
+ return worksheetDetails
1259
+ }
1260
+
1261
+ private async checkAndSetBinPicking(orderInventory, binLocation) {
1262
+ // bin picking validation
1263
+ if (binLocation) {
1264
+ const foundBinLocation: Location = await this.trxMgr.getRepository(Location).findOne({
1265
+ where: { domain: { id: this.domain.id }, name: binLocation, type: LOCATION_TYPE.BIN }
1266
+ })
1267
+
1268
+ if (!foundBinLocation)
1269
+ throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `invalid bin location id`))
1270
+
1271
+ orderInventory.binLocation = foundBinLocation
1272
+ }
1273
+
1274
+ return orderInventory
1275
+ }
1276
+
1277
+ private async updatePickingTransaction(releaseGood, orderInventory, worksheetDetail, inventory, pickedQty) {
1278
+ const releaseQty: number = orderInventory.releaseQty
1279
+
1280
+ orderInventory.pickedQty = (orderInventory?.pickedQty || 0) + pickedQty
1281
+ if (orderInventory.pickedQty == releaseQty) {
1282
+ const leftQty: number = inventory.qty - releaseQty
1283
+ if (leftQty < 0) {
1284
+ throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `quantity can't exceed limitation`))
1285
+ }
1286
+
1287
+ orderInventory.status = ORDER_INVENTORY_STATUS.PICKED
1288
+ orderInventory.pickedBy = this.user?.name
1289
+ orderInventory.pickedByUser = this.user
1290
+ orderInventory.pickedAt = new Date()
1291
+
1292
+ inventory.qty -= orderInventory.releaseQty
1293
+ inventory.uomValue = Math.round((inventory.uomValue - orderInventory.releaseUomValue) * 100) / 100
1294
+ inventory.lockedQty = inventory.lockedQty - orderInventory.releaseQty
1295
+ inventory.lockedUomValue = Math.round((inventory.lockedUomValue - orderInventory.releaseUomValue) * 100) / 100
1296
+ inventory = await this.transactionInventory(
1297
+ inventory,
1298
+ releaseGood,
1299
+ -orderInventory.releaseQty,
1300
+ -orderInventory.releaseUomValue,
1301
+ INVENTORY_TRANSACTION_TYPE.PICKING
1302
+ )
1303
+
1304
+ worksheetDetail.status = WORKSHEET_STATUS.DONE
1305
+ worksheetDetail.updater = this.user
1306
+ await this.trxMgr.getRepository(WorksheetDetail).save(worksheetDetail)
1307
+
1308
+ //@ts-ignore
1309
+ let inventoryItems: InventoryItem = await this.trxMgr
1310
+ .getRepository(InventoryItem)
1311
+ .find({ where: { outboundOrderId: releaseGood.id } })
1312
+
1313
+ //@ts-ignore
1314
+ if (inventoryItems.length > 0) {
1315
+ //@ts-ignore
1316
+ inventoryItems.forEach((itm: InventoryItem) => {
1317
+ itm.status = INVENTORY_STATUS.PICKED
1318
+ itm.updater = this.user
1319
+ })
1320
+
1321
+ await this.trxMgr.getRepository(InventoryItem).save(inventoryItems)
1322
+ }
1323
+
1324
+ if (leftQty === 0) {
1325
+ inventory.status = INVENTORY_STATUS.TERMINATED
1326
+ await this.transactionInventory(inventory, releaseGood, 0, 0, INVENTORY_TRANSACTION_TYPE.TERMINATED)
1327
+ }
1328
+ }
1329
+
1330
+ await this.updateOrderTargets([orderInventory])
1331
+
1332
+ return orderInventory
1333
+ }
1334
+
1335
+ private async serialNumberReplacementForExistingOrderInv(
1336
+ existingOrderInv,
1337
+ targetInventory,
1338
+ worksheetDetail,
1339
+ foundSerialNumber
1340
+ ) {
1341
+ try {
1342
+ //1. update replacement inventory, order inventory, old inventory, old order inventory quantity
1343
+ let newInventory: Inventory = await this.trxMgr
1344
+ .getRepository(Inventory)
1345
+ .findOne({ where: { domain: { id: this.domain.id }, id: existingOrderInv?.inventoryId } })
1346
+
1347
+ let newOrderInventory: OrderInventory = await this.trxMgr
1348
+ .getRepository(OrderInventory)
1349
+ .findOne({ where: { domain: { id: this.domain.id }, id: existingOrderInv?.id } })
1350
+
1351
+ let oldInventory: Inventory = await this.trxMgr
1352
+ .getRepository(Inventory)
1353
+ .findOne({ where: { domain: { id: this.domain.id }, id: targetInventory?.inventory.id } })
1354
+
1355
+ let oldOrderInventory: OrderInventory = await this.trxMgr
1356
+ .getRepository(OrderInventory)
1357
+ .findOne({ where: { domain: { id: this.domain.id }, id: targetInventory?.id } })
1358
+
1359
+ //if replacement inventory quantity insufficient
1360
+ if (newInventory.qty - newInventory.lockedQty < targetInventory.releaseQty - targetInventory.pickedQty) {
1361
+ newOrderInventory.releaseQty += newInventory.qty - newInventory.lockedQty
1362
+ newOrderInventory.releaseUomValue += newInventory.uomValue - newInventory.lockedUomValue
1363
+
1364
+ oldOrderInventory.releaseQty -= newOrderInventory.releaseQty
1365
+ oldOrderInventory.releaseUomValue -= newOrderInventory.releaseUomValue
1366
+
1367
+ oldInventory.lockedQty -= newOrderInventory.releaseQty
1368
+ oldInventory.lockedUomValue -= newOrderInventory.releaseUomValue
1369
+
1370
+ newInventory.lockedQty = newInventory.qty
1371
+ newInventory.lockedUomValue = newInventory.uomValue
1372
+ } else {
1373
+ newOrderInventory.releaseQty += targetInventory.releaseQty - targetInventory.pickedQty
1374
+ newOrderInventory.releaseUomValue +=
1375
+ newOrderInventory.releaseQty * (targetInventory.releaseUomValue / targetInventory.releaseQty)
1376
+
1377
+ oldOrderInventory.releaseQty = targetInventory.pickedQty
1378
+ oldOrderInventory.status = ORDER_INVENTORY_STATUS.PICKED
1379
+ oldOrderInventory.releaseUomValue =
1380
+ (targetInventory.releaseUomValue / targetInventory.releaseQty) * oldOrderInventory.releaseQty
1381
+
1382
+ oldInventory.lockedQty -= targetInventory.releaseQty - targetInventory.pickedQty
1383
+ oldInventory.lockedUomValue =
1384
+ oldInventory.lockedQty * (targetInventory.releaseUomValue / targetInventory.releaseQty)
1385
+
1386
+ newInventory.lockedQty = newInventory.lockedQty + (targetInventory.releaseQty - targetInventory.pickedQty)
1387
+ newInventory.lockedUomValue =
1388
+ (targetInventory.releaseUomValue / targetInventory.releaseQty) * newInventory.lockedQty
1389
+ }
1390
+
1391
+ newInventory = await this.trxMgr.getRepository(Inventory).save({ ...newInventory, updater: this.user })
1392
+
1393
+ newOrderInventory = await this.trxMgr.getRepository(OrderInventory).save({
1394
+ ...newOrderInventory,
1395
+ status: INVENTORY_STATUS.PICKING,
1396
+ pickedQty: existingOrderInv.pickedQty++,
1397
+ updater: this.user
1398
+ })
1399
+
1400
+ oldInventory = await this.trxMgr.getRepository(Inventory).save({ ...oldInventory, updater: this.user })
1401
+
1402
+ foundSerialNumber = await this.trxMgr
1403
+ .getRepository(InventoryItem)
1404
+ .save({ ...foundSerialNumber, inventory: newInventory })
1405
+
1406
+ //2. update replacement worksheet detail
1407
+ await this.trxMgr.getRepository(WorksheetDetail).update(
1408
+ {
1409
+ targetInventory: existingOrderInv
1410
+ },
1411
+ {
1412
+ status: WORKSHEET_STATUS.EXECUTING,
1413
+ updater: this.user
1414
+ }
1415
+ )
1416
+
1417
+ if (oldOrderInventory.releaseQty !== 0) {
1418
+ oldOrderInventory = await this.trxMgr
1419
+ .getRepository(OrderInventory)
1420
+ .save({ ...oldOrderInventory, updater: this.user })
1421
+
1422
+ await this.trxMgr.getRepository(WorksheetDetail).update(
1423
+ {
1424
+ name: worksheetDetail.name
1425
+ },
1426
+ {
1427
+ status: WORKSHEET_STATUS.DONE,
1428
+ updater: this.user
1429
+ }
1430
+ )
1431
+ } else {
1432
+ await this.trxMgr.getRepository(WorksheetDetail).delete(worksheetDetail.ild)
1433
+ await this.trxMgr.getRepository(OrderInventory).delete(targetInventory.id)
1434
+ }
1435
+ } catch (e) {}
1436
+ }
1437
+
1438
+ private async serialNumberReplacement(
1439
+ targetInventory,
1440
+ scannedPalletIdInventory,
1441
+ releaseGood,
1442
+ product,
1443
+ worksheetDetail,
1444
+ foundSerialNumber
1445
+ ) {
1446
+ try {
1447
+ //1. create new inventory, new order inventory, update old inventory, old order inventory quantity
1448
+ let newInventory: Inventory = await this.trxMgr
1449
+ .getRepository(Inventory)
1450
+ .findOne({ where: { id: scannedPalletIdInventory?.id } })
1451
+
1452
+ let oldInventory: Inventory = await this.trxMgr
1453
+ .getRepository(Inventory)
1454
+ .findOne({ where: { domain: { id: this.domain.id }, id: targetInventory?.inventory.id } })
1455
+
1456
+ let oldOrderInventory: OrderInventory = await this.trxMgr
1457
+ .getRepository(OrderInventory)
1458
+ .findOne({ where: { domain: { id: this.domain.id }, id: targetInventory?.id } })
1459
+
1460
+ let newOrderInventoryReleaseQty = 0
1461
+ let newOrderInventoryReleaseUomValue = 0
1462
+
1463
+ //if replacement inventory quantity insufficient
1464
+ if (newInventory.qty - newInventory.lockedQty < targetInventory.releaseQty - targetInventory.pickedQty) {
1465
+ newOrderInventoryReleaseQty = newInventory.qty - newInventory.lockedQty
1466
+ newOrderInventoryReleaseUomValue = newInventory.uomValue - newInventory.lockedUomValue
1467
+
1468
+ oldOrderInventory.releaseQty -= newOrderInventoryReleaseQty
1469
+ oldOrderInventory.releaseUomValue -= newOrderInventoryReleaseUomValue
1470
+
1471
+ oldInventory.lockedQty -= newOrderInventoryReleaseQty
1472
+ oldInventory.lockedUomValue -= newOrderInventoryReleaseUomValue
1473
+
1474
+ newInventory.lockedQty = newInventory.qty
1475
+ newInventory.lockedUomValue = newInventory.uomValue
1476
+ } else {
1477
+ newOrderInventoryReleaseQty = targetInventory.releaseQty - targetInventory.pickedQty
1478
+ newOrderInventoryReleaseUomValue =
1479
+ newOrderInventoryReleaseQty * (targetInventory.releaseUomValue / targetInventory.releaseQty)
1480
+
1481
+ oldOrderInventory.releaseQty = targetInventory.pickedQty
1482
+ oldOrderInventory.status = ORDER_INVENTORY_STATUS.PICKED
1483
+ oldOrderInventory.releaseUomValue =
1484
+ (targetInventory.releaseUomValue / targetInventory.releaseQty) * oldOrderInventory.releaseQty
1485
+
1486
+ oldInventory.lockedQty -= newOrderInventoryReleaseQty
1487
+ oldInventory.lockedUomValue -= newOrderInventoryReleaseUomValue
1488
+
1489
+ newInventory.lockedQty = newInventory.lockedQty + (targetInventory.releaseQty - targetInventory.pickedQty)
1490
+ newInventory.lockedUomValue =
1491
+ (targetInventory.releaseUomValue / targetInventory.releaseQty) * newInventory.lockedQty
1492
+ }
1493
+
1494
+ newInventory = await this.trxMgr.getRepository(Inventory).save({ ...newInventory, updater: this.user })
1495
+
1496
+ let newTargetInventory = (({ id, ...targetInventory }) => targetInventory)(targetInventory)
1497
+
1498
+ let newOrderInventory = await this.trxMgr.getRepository(OrderInventory).save({
1499
+ ...newTargetInventory,
1500
+ domain: this.domain,
1501
+ name: OrderNoGenerator.orderInventory(),
1502
+ releaseGood,
1503
+ releaseQty: newOrderInventoryReleaseQty,
1504
+ releaseUomValue: newOrderInventoryReleaseUomValue,
1505
+ pickedQty: 1,
1506
+ product,
1507
+ inventory: scannedPalletIdInventory,
1508
+ creator: this.user,
1509
+ updater: this.user
1510
+ })
1511
+
1512
+ oldInventory = await this.trxMgr.getRepository(Inventory).save({ ...oldInventory, updater: this.user })
1513
+
1514
+ foundSerialNumber = await this.trxMgr
1515
+ .getRepository(InventoryItem)
1516
+ .save({ ...foundSerialNumber, inventory: newInventory })
1517
+
1518
+ //3. create new worksheet detail
1519
+ let NewWorksheetDetail = (({ id, ...worksheetDetail }) => worksheetDetail)(worksheetDetail)
1520
+ await this.trxMgr.getRepository(WorksheetDetail).save({
1521
+ ...NewWorksheetDetail,
1522
+ domain: this.domain,
1523
+ name: WorksheetNoGenerator.pickingDetail(),
1524
+ targetInventory: newOrderInventory,
1525
+ status: WORKSHEET_STATUS.EXECUTING,
1526
+ creator: this.user,
1527
+ updater: this.user
1528
+ })
1529
+
1530
+ //if old order inventory release quantity is 0 then delete
1531
+ if (oldOrderInventory.releaseQty !== 0) {
1532
+ oldOrderInventory = await this.trxMgr
1533
+ .getRepository(OrderInventory)
1534
+ .save({ ...oldOrderInventory, updater: this.user })
1535
+
1536
+ //4. update old worksheet detail
1537
+ worksheetDetail = await this.trxMgr.getRepository(WorksheetDetail).update(
1538
+ {
1539
+ name: worksheetDetail.name
1540
+ },
1541
+ {
1542
+ status: WORKSHEET_STATUS.DONE,
1543
+ updater: this.user
1544
+ }
1545
+ )
1546
+ } else {
1547
+ await this.trxMgr.getRepository(WorksheetDetail).delete(worksheetDetail.id)
1548
+ await this.trxMgr.getRepository(OrderInventory).delete(targetInventory.id)
1549
+ }
1550
+ } catch (e) {}
1551
+ }
1552
+
1553
+ private async toteScanning(toteNo, targetProduct, targetInventory, pickedQty, releaseGood, bizplace) {
1554
+ //1. find tote
1555
+ let foundTote: Tote = await this.trxMgr
1556
+ .getRepository(Tote)
1557
+ .findOne({ where: { bizplace: { id: bizplace.id }, name: toteNo, deletedAt: IsNull() } })
1558
+
1559
+ if (foundTote?.status == TOTE_STATUS.DAMAGED || foundTote?.status == TOTE_STATUS.DISPATCHED) {
1560
+ foundTote = null
1561
+ }
1562
+
1563
+ //2. find order tote
1564
+ let foundOrderTote: OrderTote = await this.trxMgr
1565
+ .getRepository(OrderTote)
1566
+ .findOne({ where: { domain: { id: this.domain.id }, name: toteNo, releaseGood: { id: releaseGood.id } } })
1567
+
1568
+ //if order tote not found the create one, if tote not found means it's tote box
1569
+ //create order tote item
1570
+ if (!foundOrderTote) {
1571
+ const orderTote = await this.trxMgr.getRepository(OrderTote).save({
1572
+ name: toteNo,
1573
+ domain: this.domain,
1574
+ releaseGood,
1575
+ tote: foundTote ? foundTote : null,
1576
+ updater: this.user
1577
+ })
1578
+
1579
+ const orderToteItem = await this.trxMgr.getRepository(OrderToteItem).save({
1580
+ domain: this.domain,
1581
+ name: OrderNoGenerator.orderToteItem(),
1582
+ orderProduct: targetProduct,
1583
+ orderInventory: targetInventory,
1584
+ orderTote,
1585
+ qty: pickedQty,
1586
+ updater: this.user
1587
+ })
1588
+ } else {
1589
+ if (foundOrderTote.closedDate) {
1590
+ throw new Error('Tote has been sealed, please try another tote!')
1591
+ }
1592
+
1593
+ //if found order tote then check if order tote item exist
1594
+ const foundOrderToteItem: OrderToteItem = await this.trxMgr.getRepository(OrderToteItem).findOneBy({
1595
+ domain: { id: this.domain.id },
1596
+ orderProduct: targetProduct,
1597
+ orderInventory: targetInventory,
1598
+ orderTote: foundOrderTote
1599
+ })
1600
+
1601
+ //if not order tote item doesnt exist then create one
1602
+ if (!foundOrderToteItem) {
1603
+ const orderToteItem = await this.trxMgr.getRepository(OrderToteItem).save({
1604
+ domain: this.domain,
1605
+ name: OrderNoGenerator.orderToteItem(),
1606
+ orderProduct: targetProduct,
1607
+ orderInventory: targetInventory,
1608
+ orderTote: foundOrderTote,
1609
+ qty: pickedQty,
1610
+ updater: this.user
1611
+ })
1612
+ } else {
1613
+ //if found order tote item found then add the quantity
1614
+ const orderToteItem = await this.trxMgr.getRepository(OrderToteItem).save({
1615
+ ...foundOrderToteItem,
1616
+ qty: foundOrderToteItem.qty + pickedQty
1617
+ })
1618
+ }
1619
+ }
1620
+ }
1621
+
1622
+ async undoSerialNumberPicking(worksheetDetailName: string, inventoryItemId: string): Promise<void> {
1623
+ const worksheetDetail: WorksheetDetail = await this.trxMgr.getRepository(WorksheetDetail).findOne({
1624
+ where: {
1625
+ name: worksheetDetailName,
1626
+ domain: { id: this.domain.id },
1627
+ status: Not(Equal(WORKSHEET_STATUS.DEACTIVATED))
1628
+ },
1629
+ relations: [
1630
+ 'worksheet',
1631
+ 'worksheet.releaseGood',
1632
+ 'targetInventory',
1633
+ 'targetInventory.product',
1634
+ 'targetInventory.inventory'
1635
+ ]
1636
+ })
1637
+
1638
+ let targetInventory: OrderInventory = worksheetDetail.targetInventory
1639
+ let releaseGood: ReleaseGood = worksheetDetail.worksheet.releaseGood
1640
+
1641
+ if (
1642
+ targetInventory.releaseQty == targetInventory.pickedQty &&
1643
+ targetInventory.status == ORDER_INVENTORY_STATUS.PICKED
1644
+ ) {
1645
+ targetInventory.status = INVENTORY_STATUS.PICKING
1646
+
1647
+ await this.trxMgr
1648
+ .getRepository(WorksheetDetail)
1649
+ .update({ id: worksheetDetail.id }, { status: WORKSHEET_STATUS.EXECUTING })
1650
+
1651
+ targetInventory.inventory.qty += targetInventory.releaseQty
1652
+ targetInventory.inventory.uomValue =
1653
+ Math.round((targetInventory.inventory.uomValue + targetInventory.releaseUomValue) * 100) / 100
1654
+ targetInventory.inventory.lockedQty = targetInventory.inventory.lockedQty + targetInventory.releaseQty
1655
+ targetInventory.inventory.lockedUomValue =
1656
+ Math.round((targetInventory.inventory.lockedUomValue + targetInventory.releaseUomValue) * 100) / 100
1657
+
1658
+ await this.trxMgr.getRepository(Inventory).save(targetInventory.inventory)
1659
+ }
1660
+
1661
+ //@ts-ignore
1662
+ let InventoryItems: InventoryItem = await this.trxMgr
1663
+ .getRepository(InventoryItem)
1664
+ .find({ where: { outboundOrderId: releaseGood.id } })
1665
+
1666
+ let removeInventoryItem: InventoryItem = await this.trxMgr
1667
+ .getRepository(InventoryItem)
1668
+ .findOne({ where: { id: inventoryItemId } })
1669
+
1670
+ //@ts-ignore
1671
+ if (InventoryItems.length > 0) {
1672
+ //@ts-ignore
1673
+ InventoryItems.forEach((itm: InventoryItem) => {
1674
+ itm.status = INVENTORY_STATUS.PICKING
1675
+ itm.updater = this.user
1676
+ })
1677
+
1678
+ await this.trxMgr.getRepository(InventoryItem).save(InventoryItems)
1679
+ }
1680
+
1681
+ if (removeInventoryItem.source == INVENTORY_ITEM_SOURCE.OUTBOUND) {
1682
+ await this.trxMgr.getRepository(InventoryItem).delete(removeInventoryItem.id)
1683
+ } else {
1684
+ await this.trxMgr.getRepository(InventoryItem).update(
1685
+ {
1686
+ id: inventoryItemId
1687
+ },
1688
+ {
1689
+ status: INVENTORY_STATUS.STORED,
1690
+ outboundOrderId: null,
1691
+ updater: this.user as any
1692
+ }
1693
+ )
1694
+ }
1695
+
1696
+ targetInventory.pickedQty--
1697
+ targetInventory.updater = this.user
1698
+ await this.updateOrderTargets([targetInventory])
1699
+ }
1700
+
1701
+ async sealTote(sealNo: string, toteNo: string, orderNo: string): Promise<void> {
1702
+ const checkDuplicateSeal = await this.trxMgr.getRepository(OrderToteSeal).findOne({
1703
+ where: {
1704
+ name: sealNo
1705
+ }
1706
+ })
1707
+
1708
+ if (checkDuplicateSeal) {
1709
+ throw new Error('Seal has been scanned before')
1710
+ }
1711
+
1712
+ const releaseGood: ReleaseGood = await this.trxMgr
1713
+ .getRepository(ReleaseGood)
1714
+ .findOne({ where: { domain: { id: this.domain.id }, name: orderNo }, relations: ['bizplace', 'bizplace.domain'] })
1715
+
1716
+ let sealNoSetting: Setting = await this.trxMgr.getRepository(Setting).findOne({
1717
+ where: {
1718
+ domain: { id: releaseGood.bizplace.domain.id },
1719
+ name: 'minimum-seal-number'
1720
+ }
1721
+ })
1722
+
1723
+ if (!sealNoSetting) {
1724
+ sealNoSetting = await this.trxMgr.getRepository(Setting).findOne({
1725
+ where: {
1726
+ domain: { id: this.domain.id },
1727
+ name: 'minimum-seal-number'
1728
+ }
1729
+ })
1730
+ }
1731
+
1732
+ const foundOrderTote: OrderTote = await this.trxMgr
1733
+ .getRepository(OrderTote)
1734
+ .findOne({ where: { domain: { id: this.domain.id }, name: toteNo, releaseGood: { id: releaseGood.id } } })
1735
+
1736
+ if (!foundOrderTote) {
1737
+ throw new Error('Tote not scanned under this order')
1738
+ }
1739
+
1740
+ let totalOrderToteItems = await this.trxMgr.getRepository(OrderToteItem).count({
1741
+ where: {
1742
+ orderTote: { id: foundOrderTote.id }
1743
+ }
1744
+ })
1745
+
1746
+ if (totalOrderToteItems < 1) {
1747
+ throw new Error('Tote carton is empty')
1748
+ }
1749
+
1750
+ const newToteOrderSeal: OrderToteSeal = await this.trxMgr.getRepository(OrderToteSeal).save({
1751
+ domain: this.domain,
1752
+ name: sealNo,
1753
+ orderTote: foundOrderTote,
1754
+ updater: this.user
1755
+ })
1756
+
1757
+ const totalSeal = await this.trxMgr.getRepository(OrderToteSeal).countBy({
1758
+ orderTote: foundOrderTote
1759
+ })
1760
+
1761
+ //@ts-ignore
1762
+ if (totalSeal >= parseInt(sealNoSetting?.value || 0)) {
1763
+ await this.trxMgr.getRepository(OrderTote).save({
1764
+ ...foundOrderTote,
1765
+ closedDate: new Date()
1766
+ })
1767
+ }
1768
+ }
1769
+ }