@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,1267 @@
1
+ import { EntityManager, EntitySchema, Equal, FindOneOptions, In, Not } from 'typeorm'
2
+
3
+ import { Role, User } from '@things-factory/auth-base'
4
+ import { Bizplace, getDomainUsers } from '@things-factory/biz-base'
5
+ import { Product, ProductDetail } from '@things-factory/product-base'
6
+ import {
7
+ ArrivalNotice,
8
+ DeliveryOrder,
9
+ InventoryCheck,
10
+ ORDER_INVENTORY_STATUS,
11
+ ORDER_PRODUCT_STATUS,
12
+ ORDER_VAS_STATUS,
13
+ OrderInventory,
14
+ OrderProduct,
15
+ OrderVas,
16
+ ReleaseGood,
17
+ ReturnOrder,
18
+ VasOrder
19
+ } from '@things-factory/sales-base'
20
+ import { Domain, getRepository } from '@things-factory/shell'
21
+ import { Inventory, INVENTORY_STATUS, InventoryItem, Pallet } from '@things-factory/warehouse-base'
22
+
23
+ import { WORKSHEET_STATUS, WORKSHEET_TYPE } from '../constants'
24
+ import { Worksheet, WorksheetDetail } from '../entities'
25
+ import { generateInventoryHistory, WorksheetNoGenerator } from '../utils'
26
+
27
+ export type ReferenceOrderType = ArrivalNotice | ReleaseGood | VasOrder | InventoryCheck | DeliveryOrder | ReturnOrder
28
+ export type OrderTargetTypes = OrderProduct | OrderInventory | OrderVas
29
+
30
+ export enum ReferenceOrderFields {
31
+ ArrivalNotice = 'arrivalNotice',
32
+ ReleaseGood = 'releaseGood',
33
+ VasOrder = 'vasOrder',
34
+ InventoryCheck = 'inventoryCheck',
35
+ ReturnOrder = 'returnOrder'
36
+ }
37
+
38
+ export enum OrderTargetFields {
39
+ OrderProduct = 'targetProduct',
40
+ OrderInventory = 'targetInventory',
41
+ OrderVas = 'targetVas'
42
+ }
43
+
44
+ export interface BasicInterface {
45
+ domain: Domain
46
+ user: User
47
+ }
48
+
49
+ export type NotificationMsgInterface = {
50
+ title: string
51
+ body: string
52
+ url: string
53
+ data: any
54
+ }
55
+
56
+ export class WorksheetController {
57
+ public readonly ERROR_MSG = {
58
+ FIND: {
59
+ NO_RESULT: (condition: any) => `There's no results matched with condition ${condition}`,
60
+ NO_CHILD_RESULT: (condition: any) => `There's no child result matched with condition ${condition}`,
61
+ NOT_MATCH: (source: any, target: any) => `Unable to find matching ${target} using ${source}`
62
+ },
63
+ ORDER_ITEM: {
64
+ NO_MATCHING_RESULT: (condition: any, condition2: any) =>
65
+ `Current item with ${condition} (${condition2}) not belong to this order`,
66
+ EXCESS_QTY: (condition: any, condition2: any, condition3: any) =>
67
+ `Excess qty is scanned for item ${condition}, ${condition2} (${condition3})`
68
+ },
69
+ PRODUCT: {
70
+ NO_MATCHING_RESULT: (condition: any, condition2: any) =>
71
+ `Order packing type and packing size not match with product master, ${condition} (${condition2})`,
72
+ BARCODE_NOT_EXIST: (condition: any, condition2: any, condition3: any) =>
73
+ `Product barcode - ${condition} with ${condition2} ${condition3}, not exist in master data.`
74
+ },
75
+ CREATE: {
76
+ ID_EXISTS: 'Target has ID already',
77
+ EMPTY_CREATOR: 'Cannot create without creator',
78
+ EMPTY_UPDATER: 'Cannot create without updater'
79
+ },
80
+ UPDATE: {
81
+ ID_NOT_EXISTS: `Target doesn't have ID`,
82
+ EMPTY_UPDATER: 'Cannot update without updater'
83
+ },
84
+ VALIDITY: {
85
+ UNEXPECTED_FIELD_VALUE: (field: string, expectedValue: any, actualValue: any) =>
86
+ `Expected ${field} value is ${expectedValue} but got ${actualValue}`,
87
+ DUPLICATED: (field: string, value: any) => `There is duplicated ${field} value (${value})`,
88
+ CANT_PROCEED_STEP_BY: (step: string, reason: string) => `Can't proceed to ${step} because ${reason}`
89
+ }
90
+ }
91
+
92
+ private readonly ROLE_NAMES: Record<string, string> = {
93
+ OFFICE_ADMIN: 'Office Admin'
94
+ }
95
+
96
+ protected trxMgr: EntityManager
97
+ protected domain: Domain
98
+ protected user: User
99
+
100
+ constructor(trxMgr: EntityManager, domain: Domain, user: User) {
101
+ this.trxMgr = trxMgr
102
+ this.domain = domain
103
+ this.user = user
104
+ }
105
+
106
+ private getRefOrderField(refOrder: ReferenceOrderType): string {
107
+ if (refOrder instanceof ArrivalNotice) {
108
+ return ReferenceOrderFields.ArrivalNotice
109
+ } else if (refOrder instanceof ReleaseGood) {
110
+ return ReferenceOrderFields.ReleaseGood
111
+ } else if (refOrder instanceof VasOrder) {
112
+ return ReferenceOrderFields.VasOrder
113
+ } else if (refOrder instanceof InventoryCheck) {
114
+ return ReferenceOrderFields.InventoryCheck
115
+ } else if (refOrder instanceof ReturnOrder) {
116
+ return ReferenceOrderFields.ReturnOrder
117
+ } else {
118
+ throw new Error(
119
+ this.ERROR_MSG.VALIDITY.UNEXPECTED_FIELD_VALUE('refOrder', 'One of reference order type', refOrder)
120
+ )
121
+ }
122
+ }
123
+
124
+ private getOrderTargetField(orderTarget: OrderTargetTypes): string {
125
+ if (orderTarget instanceof OrderProduct) {
126
+ return OrderTargetFields.OrderProduct
127
+ } else if (orderTarget instanceof OrderInventory) {
128
+ return OrderTargetFields.OrderInventory
129
+ } else if (orderTarget instanceof OrderVas) {
130
+ return OrderTargetFields.OrderVas
131
+ } else {
132
+ this.ERROR_MSG.VALIDITY.UNEXPECTED_FIELD_VALUE('orderTarget', 'One of order target type', orderTarget)
133
+ }
134
+ }
135
+
136
+ /**
137
+ * @summary Find reference order (ArrivalNotice, ReleaseGood, VasOrder, etc...)
138
+ * @description
139
+ * Find and return reference order with its relations based on passed condition & reltaions
140
+ */
141
+ async findRefOrder(
142
+ entitySchema: EntitySchema,
143
+ condition: Partial<ReferenceOrderType>,
144
+ relations?: string[]
145
+ ): Promise<ReferenceOrderType> {
146
+ condition = this.tidyConditions(condition)
147
+ let findOption: FindOneOptions = { where: condition }
148
+ if (relations?.length > 0) findOption.relations = relations
149
+
150
+ const refOrder: ReferenceOrderType = await this.trxMgr.getRepository(entitySchema).findOne(findOption)
151
+ if (!refOrder) throw new Error(this.ERROR_MSG.FIND.NO_RESULT(findOption))
152
+
153
+ return refOrder
154
+ }
155
+
156
+ /**
157
+ * @summary find worksheet by passed condition
158
+ * @description find worksheey based on passed condition
159
+ * It will return worksheetDetail as its relation by default
160
+ * If you want to get additional relations you need to define reltaions
161
+ * ex) findWorksheet(condition, ['arrivalNotice', 'releaseGood'])
162
+ */
163
+ async findWorksheet(condition: Record<string, any>, relations: string[] = ['worksheetDetails']): Promise<Worksheet> {
164
+ condition = this.tidyConditions(condition)
165
+ const worksheet: Worksheet = await this.trxMgr.getRepository(Worksheet).findOne({
166
+ where: {
167
+ domain: { id: this.domain.id },
168
+ ...condition
169
+ },
170
+ relations
171
+ })
172
+
173
+ if (!worksheet) throw new Error(this.ERROR_MSG.FIND.NO_RESULT(condition))
174
+ return worksheet
175
+ }
176
+
177
+ /**
178
+ * @summary Find worksheet by passed params
179
+ * @description Find and return worksheet based on passed ID
180
+ * It will return worksheetDetail as its relation by default
181
+ * If you want to get additional relations you need to define reltaions
182
+ * ex) findWorksheetById(id, ['arrivalNotice', 'releaseGood'])
183
+ */
184
+ async findWorksheetById(id: string, relations: string[] = ['worksheetDetails']): Promise<Worksheet> {
185
+ const worksheet: Worksheet = await this.trxMgr.getRepository(Worksheet).findOne({ where: { id }, relations })
186
+ if (!worksheet) throw new Error(this.ERROR_MSG.FIND.NO_RESULT(id))
187
+
188
+ return worksheet
189
+ }
190
+
191
+ /**
192
+ * @summary Find worksheet by passed params
193
+ * @description Find and return worksheet based on worksheet no
194
+ * It will return worksheetDetail as its relation by default
195
+ * If you want to get additional relations you need to define reltaions
196
+ * ex) findWorksheetByNo(worksheetNo, ['arrivalNotice', 'releaseGood'])
197
+ */
198
+ async findWorksheetByNo(worksheetNo: string, relations: string[] = ['worksheetDetails']): Promise<Worksheet> {
199
+ const worksheet: Worksheet = await this.trxMgr.getRepository(Worksheet).findOne({
200
+ where: { domain: { id: this.domain.id }, name: worksheetNo },
201
+ relations
202
+ })
203
+
204
+ if (!worksheet) throw new Error(this.ERROR_MSG.FIND.NO_RESULT(worksheetNo))
205
+
206
+ return worksheet
207
+ }
208
+
209
+ /**
210
+ * @summary Find worksheet by passed params.
211
+ * @description Find and return worksheet based on worksheet no
212
+ * It will return worksheetDetail as its relation by default
213
+ * If you want to get additional relations you need to define reltaions
214
+ * ex) findWorksheetByNo(worksheetNo, ['arrivalNotice', 'releaseGood'])
215
+ */
216
+ async findWorksheetByRefOrder(
217
+ refOrder: ReferenceOrderType,
218
+ type: string,
219
+ relations: string[] = ['worksheetDetails']
220
+ ): Promise<Worksheet> {
221
+ const refOrderField: string = this.getRefOrderField(refOrder)
222
+ if (!refOrder.bizplace?.id) {
223
+ switch (refOrderField) {
224
+ case ReferenceOrderFields.ArrivalNotice:
225
+ //@ts-ignore
226
+ refOrder = await this.findRefOrder(ArrivalNotice, refOrder, ['bizplace'])
227
+ break
228
+
229
+ case ReferenceOrderFields.ReleaseGood:
230
+ //@ts-ignore
231
+ refOrder = await this.findRefOrder(ReleaseGood, refOrder, ['bizplace'])
232
+ break
233
+
234
+ case ReferenceOrderFields.VasOrder:
235
+ //@ts-ignore
236
+ refOrder = await this.findRefOrder(VasOrder, refOrder, ['bizplace'])
237
+ break
238
+
239
+ case ReferenceOrderFields.InventoryCheck:
240
+ //@ts-ignore
241
+ refOrder = await this.findRefOrder(InventoryCheck, refOrder, ['bizplace'])
242
+ break
243
+
244
+ case ReferenceOrderFields.ReturnOrder:
245
+ //@ts-ignore
246
+ refOrder = await this.findRefOrder(ReturnOrder, refOrder, ['bizplace'])
247
+ break
248
+ }
249
+ }
250
+
251
+ const bizplace: Bizplace = refOrder.bizplace
252
+ const condition: FindOneOptions = {
253
+ where: {
254
+ bizplace: { id: bizplace.id },
255
+ domain: { id: this.domain.id },
256
+ type,
257
+ [refOrderField]: { id: refOrder.id }
258
+ },
259
+ relations
260
+ }
261
+
262
+ const worksheet: Worksheet = await this.trxMgr.getRepository(Worksheet).findOne(condition)
263
+ if (!worksheet) throw new Error(this.ERROR_MSG.FIND.NO_RESULT(type))
264
+
265
+ return worksheet
266
+ }
267
+
268
+ /**
269
+ * @summary Find activatable worksheet by worksheet no and type
270
+ * @description Find worksheet by passed worksheet no
271
+ * and check validity by passed type and status (DEACTIVATED)
272
+ * It will return worksheetDetail as its relation by default
273
+ * If you want to get additional relations you need to define reltaions
274
+ * ex) findActivatableWorksheet(worksheetNo, type, ['arrivalNotice])
275
+ */
276
+ async findActivatableWorksheet(
277
+ worksheetNo: string,
278
+ type: string,
279
+ relations: string[] = ['worksheetDetails']
280
+ ): Promise<Worksheet> {
281
+ const worksheet: Worksheet = await this.findWorksheetByNo(worksheetNo, relations)
282
+ this.checkRecordValidity(worksheet, { type, status: WORKSHEET_STATUS.DEACTIVATED })
283
+
284
+ return worksheet
285
+ }
286
+
287
+ /**
288
+ * @summary Find executable worksheet detail by its name
289
+ * @description Find worksheet detail by passwd worksheet detail name
290
+ * and check validity by passed type and status (EXECUTING)
291
+ * If you want to get additional relations you need to define relations
292
+ * ex) findExecutableWorksheetDetailByName(worksheetDetailName, type, ['arrivalNotice'])
293
+ */
294
+ async findActivatableWorksheetDetailByName(
295
+ worksheetDetailName: string,
296
+ type: string,
297
+ relations: string[] = []
298
+ ): Promise<WorksheetDetail> {
299
+ const worksheetDetail: WorksheetDetail = await this.findWorksheetDetailByName(worksheetDetailName, relations)
300
+ this.checkRecordValidity(worksheetDetail, { type, status: WORKSHEET_STATUS.DEACTIVATED })
301
+
302
+ return worksheetDetail
303
+ }
304
+
305
+ /**
306
+ * @summary find worksheet detail by passed condition
307
+ * @description find worksheet detail based on passed condition
308
+ * If you want to get additional relations you need to define reltaions
309
+ * ex) findWorksheetDetail(condition, ['worksheet'])
310
+ */
311
+ async findWorksheetDetail(condition: Record<string, any>, relations?: string[]): Promise<WorksheetDetail> {
312
+ condition = this.tidyConditions(condition)
313
+ const worksheetDetail: WorksheetDetail = await this.trxMgr.getRepository(WorksheetDetail).findOne({
314
+ where: {
315
+ domain: { id: this.domain.id },
316
+ ...condition
317
+ },
318
+ relations
319
+ })
320
+
321
+ if (!worksheetDetail) throw new Error(this.ERROR_MSG.FIND.NO_RESULT(condition))
322
+ return worksheetDetail
323
+ }
324
+
325
+ /**
326
+ * @summary find worksheet detail by passed worksheet detail name
327
+ * @description find worksheey based on passed name of worksheet detail
328
+ * If you want to get additional relations you need to define reltaions
329
+ * ex) findWorksheetDetail(condition, ['worksheet'])
330
+ */
331
+ async findWorksheetDetailByName(worksheetDetailName: string, relations?: string[]): Promise<WorksheetDetail> {
332
+ const worksheetDetail: WorksheetDetail = await this.trxMgr.getRepository(WorksheetDetail).findOne({
333
+ where: { domain: { id: this.domain.id }, name: worksheetDetailName },
334
+ relations
335
+ })
336
+
337
+ if (!worksheetDetail) throw new Error(this.ERROR_MSG.FIND.NO_RESULT(worksheetDetailName))
338
+ return worksheetDetail
339
+ }
340
+
341
+ async findWorksheetDetailByNames(worksheetDetailNames: [string], relations?: string[]): Promise<WorksheetDetail[]> {
342
+ const worksheetDetails: WorksheetDetail[] = await this.trxMgr.getRepository(WorksheetDetail).find({
343
+ where: { domain: { id: this.domain.id }, name: In(worksheetDetailNames) },
344
+ relations
345
+ })
346
+
347
+ if (!worksheetDetails?.length) throw new Error(this.ERROR_MSG.FIND.NO_RESULT(worksheetDetailNames.toString()))
348
+ return worksheetDetails
349
+ }
350
+
351
+ /**
352
+ * @summary Find executable worksheet detail by its name
353
+ * @description Find worksheet detail by passwd worksheet detail name
354
+ * and check validity by passed type and status (EXECUTING)
355
+ * If you want to get additional relations you need to define relations
356
+ * ex) findExecutableWorksheetDetailByName(worksheetDetailName, type, ['arrivalNotice'])
357
+ */
358
+ async findExecutableWorksheetDetailByName(
359
+ worksheetDetailName: string,
360
+ type: string,
361
+ relations: string[] = []
362
+ ): Promise<WorksheetDetail> {
363
+ const worksheetDetail: WorksheetDetail = await this.findWorksheetDetailByName(worksheetDetailName, relations)
364
+ this.checkRecordValidity(worksheetDetail, { type, status: WORKSHEET_STATUS.EXECUTING })
365
+
366
+ return worksheetDetail
367
+ }
368
+
369
+ async findExecutableWorksheetDetailByNames(
370
+ worksheetDetailNames: [string],
371
+ type: string,
372
+ relations: string[] = []
373
+ ): Promise<WorksheetDetail[]> {
374
+ const worksheetDetails: WorksheetDetail[] = await this.findWorksheetDetailByNames(worksheetDetailNames, relations)
375
+ worksheetDetails.map(worksheetDetail => {
376
+ this.checkRecordValidity(worksheetDetail, { type, status: WORKSHEET_STATUS.EXECUTING })
377
+ })
378
+
379
+ return worksheetDetails
380
+ }
381
+
382
+ /**
383
+ * @summary Creating worksheet
384
+ * @description creating worksheet by passed params
385
+ * It will set status as DEACTIVATED by default
386
+ * If you want to define status by yourself, need to pass status in additionalProps
387
+ * ex) createWorksheet(refOrder, type, { status: WORKSHEET_STATUS.ACTIVATED })
388
+ */
389
+ async createWorksheet(
390
+ refOrder: ReferenceOrderType,
391
+ type: string,
392
+ additionalProps: Partial<Worksheet> = {}
393
+ ): Promise<Worksheet> {
394
+ let refOrderType: string = await this.getRefOrderField(refOrder)
395
+ const bizplace: Bizplace = await this.extractBizplaceFromRefOrder(refOrder)
396
+
397
+ let existingWorksheet: Worksheet
398
+ try {
399
+ existingWorksheet = await this.findWorksheetByRefOrder(refOrder, type)
400
+ } catch (e) {}
401
+
402
+ if (existingWorksheet)
403
+ throw new Error(
404
+ this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY(
405
+ `create ${type.toLocaleLowerCase()} worksheet`,
406
+ 'existing worksheet is found'
407
+ )
408
+ )
409
+
410
+ const worksheet: Partial<Worksheet> = {
411
+ domain: this.domain,
412
+ bizplace,
413
+ name: WorksheetNoGenerator.generate(type),
414
+ type,
415
+ status: WORKSHEET_STATUS.DEACTIVATED,
416
+ creator: this.user,
417
+ updater: this.user,
418
+ [refOrderType]: refOrder,
419
+ ...additionalProps
420
+ }
421
+
422
+ if (worksheet.id) throw new Error(this.ERROR_MSG.CREATE.ID_EXISTS)
423
+
424
+ return await this.trxMgr.getRepository(Worksheet).save(worksheet)
425
+ }
426
+
427
+ async createBatchWorksheet(
428
+ taskNo: string,
429
+ bizplace: Bizplace,
430
+ type: string,
431
+ additionalProps: Partial<Worksheet> = {}
432
+ ): Promise<Worksheet> {
433
+ const worksheet: Partial<Worksheet> = {
434
+ domain: this.domain,
435
+ bizplace,
436
+ name: WorksheetNoGenerator.generate(type),
437
+ type,
438
+ taskNo,
439
+ status: WORKSHEET_STATUS.DEACTIVATED,
440
+ creator: this.user,
441
+ updater: this.user,
442
+ ...additionalProps
443
+ }
444
+
445
+ if (worksheet.id) throw new Error(this.ERROR_MSG.CREATE.ID_EXISTS)
446
+
447
+ return await this.trxMgr.getRepository(Worksheet).save(worksheet)
448
+ }
449
+
450
+ /**
451
+ * @summary Creating worksheet details
452
+ * @description creating worksheet details by passed params
453
+ * It will set status as DEACTIVATED by default
454
+ * If you want to define status by yourself, need to pass status in additionalProps
455
+ * ex) createWorksheetDetails(refOrder, type, { status: WORKSHEET_STATUS.ACTIVATED })
456
+ *
457
+ */
458
+ async createWorksheetDetails(
459
+ worksheet: Worksheet,
460
+ type: string,
461
+ orderTargets: OrderTargetTypes[],
462
+ additionalProps: Partial<WorksheetDetail> = {}
463
+ ): Promise<WorksheetDetail[]> {
464
+ if (!worksheet.bizplace?.id) {
465
+ worksheet = await this.findWorksheetById(worksheet.id, ['bizplace'])
466
+ }
467
+ const bizplace: Bizplace = worksheet.bizplace
468
+
469
+ const worksheetDetails: Partial<WorksheetDetail>[] = orderTargets.map((orderTarget: OrderTargetTypes) => {
470
+ const orderTargetField: string = this.getOrderTargetField(orderTarget)
471
+ return {
472
+ domain: this.domain,
473
+ bizplace,
474
+ worksheet,
475
+ name: WorksheetNoGenerator.generate(type, true),
476
+ type,
477
+ status: WORKSHEET_STATUS.DEACTIVATED,
478
+ [orderTargetField]: orderTarget,
479
+ creator: this.user,
480
+ updater: this.user,
481
+ ...additionalProps
482
+ }
483
+ })
484
+
485
+ if (worksheetDetails.some((wsd: Partial<WorksheetDetail>) => wsd.id))
486
+ throw new Error(this.ERROR_MSG.CREATE.ID_EXISTS)
487
+
488
+ return await this.trxMgr.getRepository(WorksheetDetail).save(worksheetDetails)
489
+ }
490
+
491
+ /**
492
+ * @summary Update reference order (ArrivalNotice, ReleaseGood, VasOrder, InventoryCheck)
493
+ * @description
494
+ * Update reference order like (ArrivalNotice, ReleaseGood, VasOrder, InventoryCheck)
495
+ */
496
+ async updateRefOrder(
497
+ refOrder: ReferenceOrderType,
498
+ entitySchema?: EntitySchema,
499
+ currentStatus?: string
500
+ ): Promise<any> {
501
+ if (!entitySchema) {
502
+ if (refOrder instanceof ArrivalNotice) {
503
+ //@ts-ignore
504
+ entitySchema = ArrivalNotice
505
+ } else if (refOrder instanceof ReleaseGood) {
506
+ //@ts-ignore
507
+ entitySchema = ReleaseGood
508
+ } else if (refOrder instanceof VasOrder) {
509
+ //@ts-ignore
510
+ entitySchema = VasOrder
511
+ } else if (refOrder instanceof InventoryCheck) {
512
+ //@ts-ignore
513
+ entitySchema = InventoryCheck
514
+ } else if (refOrder instanceof ReturnOrder) {
515
+ //@ts-ignore
516
+ entitySchema = ReturnOrder
517
+ }
518
+ }
519
+
520
+ if (!refOrder.id) throw new Error(this.ERROR_MSG.UPDATE.ID_NOT_EXISTS)
521
+ //@ts-ignore
522
+ if (!refOrder.updater?.id) refOrder = this.setStamp(refOrder)
523
+
524
+ //@ts-ignore
525
+ if (currentStatus && entitySchema == ReleaseGood) {
526
+ let res = await getRepository(entitySchema).query(
527
+ `
528
+ update release_goods
529
+ set status = $1
530
+ where id = $2
531
+ and status = $3
532
+ returning id
533
+ `,
534
+ [refOrder.status, refOrder.id, currentStatus]
535
+ )
536
+
537
+ if (res[1] == 0) {
538
+ this.trxMgr.queryRunner.rollbackTransaction()
539
+ throw new Error('Worksheet has already been created')
540
+ }
541
+ }
542
+
543
+ return await this.trxMgr.getRepository(entitySchema).save(refOrder)
544
+ }
545
+
546
+ /**
547
+ * @summary Update order targets (OrderProduct, OrderInventory, OrderVas)
548
+ * @description
549
+ * Update order targets like (OrderProduct, OrderInventory, OrderVas)
550
+ */
551
+ async updateOrderTargets(orderTargets: OrderTargetTypes[], entitySchema?: EntitySchema): Promise<any> {
552
+ if (!entitySchema) {
553
+ if (orderTargets[0] instanceof OrderProduct) {
554
+ //@ts-ignore
555
+ entitySchema = OrderProduct
556
+ } else if (orderTargets[0] instanceof OrderInventory) {
557
+ //@ts-ignore
558
+ entitySchema = OrderInventory
559
+ } else if (orderTargets[0] instanceof OrderVas) {
560
+ //@ts-ignore
561
+ entitySchema = OrderVas
562
+ }
563
+ }
564
+
565
+ if (orderTargets.some((orderTarget: any) => !orderTarget.id)) throw new Error(this.ERROR_MSG.UPDATE.ID_NOT_EXISTS)
566
+ orderTargets.forEach((orderTarget: OrderTargetTypes) => {
567
+ //@ts-ignore
568
+ if (!orderTarget.updater?.id) orderTarget = this.setStamp(orderTarget)
569
+ })
570
+
571
+ return await this.trxMgr.getRepository(entitySchema).save(orderTargets)
572
+ }
573
+
574
+ /**
575
+ * @summary generate worksheet and worksheet details
576
+ * @description It will generate worksheet and worksheet details in onetime
577
+ * Step 1. Call createWorksheet to create worksheet
578
+ * The status of worksheet will be DEACTIVATED by default
579
+ * You can change it through passing additionalProps
580
+ * Step 2. Update status of order targets
581
+ * Beacuse its status can be different based on type of worksheet
582
+ * Step 3. Call createWorksheetDetails to create worksheet details
583
+ * Step 4. Call updateRefOrder to change status of reference order
584
+ */
585
+ async generateWorksheet(
586
+ worksheetType: string,
587
+ refOrder: ReferenceOrderType,
588
+ orderTargets: OrderTargetTypes[],
589
+ refOrderStatus: string,
590
+ orderTargetStatus: string,
591
+ additionalProps: Partial<Worksheet> = {}
592
+ ): Promise<Worksheet> {
593
+ const worksheet: Worksheet = await this.createWorksheet(refOrder, worksheetType, additionalProps)
594
+
595
+ orderTargets.forEach((orderTarget: OrderTargetTypes) => {
596
+ orderTarget.status = orderTargetStatus
597
+ })
598
+ orderTargets = await this.updateOrderTargets(orderTargets)
599
+
600
+ worksheet.worksheetDetails = await this.createWorksheetDetails(worksheet, worksheetType, orderTargets)
601
+
602
+ refOrder.status = refOrderStatus
603
+ await this.updateRefOrder(refOrder)
604
+
605
+ return worksheet
606
+ }
607
+
608
+ // @chernhaoee I think the naming of this function is not proper. Seems like it should be something like "updateLoadingWorksheet" since the logic targets only Loading Order Target
609
+ async updateWorksheet(
610
+ worksheetType: string,
611
+ refOrder: ReferenceOrderType,
612
+ worksheet: Worksheet,
613
+ orderTargets: OrderTargetTypes[],
614
+ refOrderStatus: string,
615
+ orderTargetStatus: string
616
+ ): Promise<Worksheet> {
617
+ let newOrderTarget = []
618
+
619
+ orderTargets.forEach((orderTarget: OrderTargetTypes) => {
620
+ orderTarget.status = orderTargetStatus
621
+ })
622
+ orderTargets = await this.updateOrderTargets(orderTargets)
623
+
624
+ for (let orderTarget of orderTargets) {
625
+ try {
626
+ await this.findWorksheetDetail({
627
+ targetInventory: orderTarget.id,
628
+ type: WORKSHEET_TYPE.LOADING
629
+ })
630
+ } catch (e) {
631
+ newOrderTarget.push(orderTarget)
632
+ }
633
+ }
634
+
635
+ worksheet.worksheetDetails = await this.createWorksheetDetails(worksheet, worksheetType, newOrderTarget)
636
+
637
+ // find worksheet details that doesnt exist based on order inventory
638
+ //worksheet.worksheetDetails = await this.findWorksheetDetail(worksheet.id)
639
+
640
+ refOrder.status = refOrderStatus
641
+ await this.updateRefOrder(refOrder)
642
+
643
+ return worksheet
644
+ }
645
+
646
+ async generateBatchWorksheet(
647
+ worksheetType: string,
648
+ batchPickingWorksheet: Worksheet,
649
+ orderTargets: OrderTargetTypes[],
650
+ orderTargetStatus: string,
651
+ additionalProps: Partial<Worksheet> = {}
652
+ ): Promise<Worksheet> {
653
+ const worksheet: Worksheet = await this.createBatchWorksheet(
654
+ batchPickingWorksheet.taskNo,
655
+ batchPickingWorksheet.bizplace,
656
+ worksheetType,
657
+ additionalProps
658
+ )
659
+
660
+ orderTargets.forEach((orderTarget: OrderTargetTypes) => {
661
+ orderTarget.status = orderTargetStatus
662
+ })
663
+ orderTargets = await this.updateOrderTargets(orderTargets)
664
+
665
+ worksheet.worksheetDetails = await this.createWorksheetDetails(worksheet, worksheetType, orderTargets)
666
+
667
+ return worksheet
668
+ }
669
+
670
+ /**
671
+ * @summary Activate worksheet
672
+ * @description It will activate passed worksheet
673
+ * Every passed worksheet and worksheet details should have value on its id field
674
+ * Because this function has logic to update worksheet and worksheet details
675
+ * Step 1. Check whether every passed worksheet and worksheet details has id
676
+ * Step 2. Change worksheet properly and update it
677
+ * Step 3. Change worksheet details properly and update it
678
+ */
679
+ async activateWorksheet(
680
+ worksheet: Worksheet,
681
+ worksheetDetails: WorksheetDetail[],
682
+ changedWorksheetDetails: Partial<WorksheetDetail>[]
683
+ ): Promise<Worksheet> {
684
+ if (!worksheet.id || worksheetDetails.some((wsd: WorksheetDetail) => !wsd.id)) {
685
+ throw new Error(this.ERROR_MSG.UPDATE.ID_NOT_EXISTS)
686
+ }
687
+
688
+ worksheet.status = WORKSHEET_STATUS.EXECUTING
689
+ worksheet.startedAt = new Date()
690
+ worksheet.updater = this.user
691
+ worksheet = await this.trxMgr.getRepository(Worksheet).save(worksheet)
692
+
693
+ worksheetDetails = this.renewWorksheetDetails(worksheetDetails, changedWorksheetDetails, 'name', {
694
+ status: WORKSHEET_STATUS.EXECUTING,
695
+ updater: this.user
696
+ })
697
+ worksheet.worksheetDetails = await this.trxMgr.getRepository(WorksheetDetail).save(worksheetDetails)
698
+
699
+ return worksheet
700
+ }
701
+
702
+ /**
703
+ * @summary Complete worksheet
704
+ * @description It will activate passed worksheet
705
+ * Passed worksheet should have value on its id field
706
+ * Because this function has logic to update worksheet
707
+ * Step 1. Check whether passed worksheet has id
708
+ * Step 2. Change worksheet properly and update it
709
+ * Step 3. Renew worksheet with relations which is needed to complete worksheet
710
+ * Step 4. Change order targets properly and update it based on type of worksheet
711
+ * Step 5. If passed updatedRefOrderStatus has value it update reference order status
712
+ */
713
+ async completeWorksheet(worksheet: Worksheet, updatedRefOrderStatus?: string): Promise<Worksheet> {
714
+ if (!worksheet.id) throw new Error(this.ERROR_MSG.UPDATE.ID_NOT_EXISTS)
715
+
716
+ worksheet.status = WORKSHEET_STATUS.DONE
717
+ worksheet.endedAt = new Date()
718
+ worksheet.updater = this.user
719
+ worksheet = await this.trxMgr.getRepository(Worksheet).save(worksheet)
720
+
721
+ const worksheetType: string = worksheet.type
722
+ worksheet = await this.findWorksheet(worksheet, [
723
+ 'worksheetDetails',
724
+ 'worksheetDetails.targetProduct',
725
+ 'worksheetDetails.targetInventory',
726
+ 'worksheetDetails.targetVas'
727
+ ])
728
+
729
+ let worksheetDetails: WorksheetDetail[] = worksheet.worksheetDetails
730
+
731
+ worksheetDetails
732
+ .filter((wsd: WorksheetDetail) => wsd.status !== ORDER_INVENTORY_STATUS.REPLACED)
733
+ .forEach((wsd: WorksheetDetail) => {
734
+ wsd.status = WORKSHEET_STATUS.DONE
735
+ wsd.updater = this.user
736
+ })
737
+ await this.trxMgr.getRepository(WorksheetDetail).save(worksheetDetails)
738
+
739
+ if (worksheetType === WORKSHEET_TYPE.UNLOADING) {
740
+ let targetProducts: OrderProduct[] = worksheet.worksheetDetails.map((wsd: WorksheetDetail) => {
741
+ let targetProduct: OrderProduct = wsd.targetProduct
742
+ targetProduct.status = ORDER_PRODUCT_STATUS.TERMINATED
743
+ targetProduct.updater = this.user
744
+ return targetProduct
745
+ })
746
+
747
+ await this.updateOrderTargets(targetProducts)
748
+ } else if (worksheetType === WORKSHEET_TYPE.VAS) {
749
+ let targetVASs: OrderVas[] = worksheet.worksheetDetails.map((wsd: WorksheetDetail) => {
750
+ let targetVAS: OrderVas = wsd.targetVas
751
+ targetVAS.status = ORDER_VAS_STATUS.TERMINATED
752
+ targetVAS.updater = this.user
753
+ return targetVAS
754
+ })
755
+
756
+ await this.updateOrderTargets(targetVASs)
757
+ } else if (
758
+ worksheetType === WORKSHEET_TYPE.PUTAWAY ||
759
+ worksheetType === WORKSHEET_TYPE.PICKING ||
760
+ worksheetType === WORKSHEET_TYPE.PACKING ||
761
+ worksheetType === WORKSHEET_TYPE.LOADING ||
762
+ worksheetType === WORKSHEET_TYPE.WAREHOUSE_RETURN ||
763
+ worksheetType === WORKSHEET_TYPE.UNLOADING_RETURN
764
+ ) {
765
+ let targetInventories: OrderInventory[] = worksheet.worksheetDetails
766
+ .filter((wsd: WorksheetDetail) => wsd.status !== ORDER_INVENTORY_STATUS.REPLACED)
767
+ .map((wsd: WorksheetDetail) => {
768
+ let targetInventory: OrderInventory = wsd.targetInventory
769
+ targetInventory.status = ORDER_INVENTORY_STATUS.TERMINATED
770
+ targetInventory.updater = this.user
771
+ return targetInventory
772
+ })
773
+
774
+ await this.updateOrderTargets(targetInventories)
775
+ }
776
+
777
+ if (updatedRefOrderStatus) {
778
+ const refOrder: ReferenceOrderType = await this.extractRefOrderFromWorksheet(worksheet)
779
+ refOrder.status = updatedRefOrderStatus
780
+ refOrder.updater = this.user
781
+ await this.updateRefOrder(refOrder)
782
+ }
783
+
784
+ return worksheet
785
+ }
786
+
787
+ /**
788
+ * @summary Renew worksheet details by changed worksheet details
789
+ * @description When you want to merge changed worksheet detail list into original worksheet detail list
790
+ * you can use this function
791
+ * it will loop through whole passed original worksheet details and find out matched changed one by value of 'ID' or its 'name'
792
+ * Because of this, every passed origin worksheet details and changed worksheet details should have one of those values
793
+ */
794
+ renewWorksheetDetails(
795
+ originWSDs: WorksheetDetail[],
796
+ changedWSDs: Partial<WorksheetDetail>[],
797
+ identifier: string,
798
+ additionalProps: Partial<WorksheetDetail> = {}
799
+ ): WorksheetDetail[] {
800
+ if (
801
+ originWSDs.some((wsd: WorksheetDetail) => !wsd[identifier]) ||
802
+ changedWSDs.some((wsd: Partial<WorksheetDetail>) => !wsd[identifier])
803
+ ) {
804
+ throw new Error(
805
+ this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY(
806
+ 'renew worksheet details',
807
+ `some passed parameter doesn't have identifier (${identifier})`
808
+ )
809
+ )
810
+ }
811
+
812
+ return originWSDs.map((originWSD: WorksheetDetail) => {
813
+ const changedWSD: Partial<WorksheetDetail> = this.findMatchedWSD(originWSD[identifier], changedWSDs)
814
+
815
+ return {
816
+ ...originWSD,
817
+ ...changedWSD,
818
+ ...additionalProps
819
+ }
820
+ })
821
+ }
822
+
823
+ /**
824
+ * @summary Find out matched worksheet detail by identifier
825
+ * @description Find out matched worksheet detail by identifier
826
+ * identifier can be 'ID' or 'name' of worksheet detail
827
+ */
828
+ findMatchedWSD(identifier: string, candidates: any[]): any {
829
+ return candidates.find(
830
+ (candidate: Partial<WorksheetDetail>) => candidate.id === identifier || candidate.name === identifier
831
+ )
832
+ }
833
+
834
+ /**
835
+ * @summary Valitiy checker
836
+ * @description It will try to check whether passed record has same properties with passed conditions
837
+ * Basically it will check equality of value
838
+ * If you want to check advanced validation you can pass function to customize the logic of validation
839
+ * Passed function will be call with actual value of record as parameter
840
+ */
841
+ checkRecordValidity(record: Record<string, any>, conditions: Record<string, any>): void {
842
+ for (let field in conditions) {
843
+ let isValid: boolean = false
844
+ if (typeof conditions[field] === 'function') {
845
+ isValid = conditions[field](record[field])
846
+ } else {
847
+ isValid = conditions[field] === record[field]
848
+ }
849
+
850
+ if (!isValid)
851
+ throw new Error(this.ERROR_MSG.VALIDITY.UNEXPECTED_FIELD_VALUE(field, conditions[field], record[field]))
852
+ }
853
+ }
854
+
855
+ /**
856
+ * @summary Notify to passed users
857
+ * @description Passed notification message will be sent to passed users
858
+ */
859
+ async notifyToUsers(users: User[], message: NotificationMsgInterface): Promise<void> {
860
+ const receivers: any[] = users.map(user => user.id)
861
+
862
+ /**
863
+ * @notes Temporary off sendNotification due to suspect of causing wms down
864
+ */
865
+
866
+ // await sendNotification({
867
+ // receivers,
868
+ // message
869
+ // })
870
+ }
871
+
872
+ /**
873
+ * @summary Notify to office admin
874
+ * @description Passed notification message will be sent to office admin of current domain
875
+ * default role name is defiend as ROLE_NAME.OFFICE_ADMIn by default
876
+ * You can change role name by passing roleName as parameter
877
+ */
878
+ async notifyToOfficeAdmin(message: NotificationMsgInterface, roleName?: string): Promise<void> {
879
+ const users: User[] = await this.trxMgr
880
+ .getRepository('users_roles')
881
+ .createQueryBuilder('ur')
882
+ .select('ur.users_id', 'id')
883
+ .where(qb => {
884
+ const subQuery = qb
885
+ .subQuery()
886
+ .select('role.id')
887
+ .from(Role, 'role')
888
+ .where('role.name = :roleName', { roleName: roleName || this.ROLE_NAMES.OFFICE_ADMIN })
889
+ .andWhere('role.domain_id = :domainId', { domainId: this.domain.id })
890
+ .getQuery()
891
+ return 'ur.roles_id IN ' + subQuery
892
+ })
893
+ .getRawMany()
894
+
895
+ this.notifyToUsers(users, message)
896
+ }
897
+
898
+ /**
899
+ * @summary Notify to customer of passed bizplace
900
+ * @description Passed notification message will be sent to customer of passed bizplace
901
+ */
902
+ async notifyToCustomer(bizplace: Bizplace, message: NotificationMsgInterface): Promise<void> {
903
+ const users: any[] = await getDomainUsers(bizplace, this.trxMgr)
904
+
905
+ this.notifyToUsers(users, message)
906
+ }
907
+
908
+ /**
909
+ * @summary extract out referenc order from given worksheet
910
+ * @description If it doesn't have any reference order
911
+ * find worksheet with every possible reference order once again
912
+ * and extract out reference order from found worksheet
913
+ */
914
+ async extractRefOrderFromWorksheet(worksheet: Worksheet): Promise<ReferenceOrderType> {
915
+ let refOrder: ReferenceOrderType =
916
+ worksheet.arrivalNotice ||
917
+ worksheet.releaseGood ||
918
+ worksheet.vasOrder ||
919
+ worksheet.inventoryCheck ||
920
+ worksheet.returnOrder ||
921
+ null
922
+ if (!refOrder) {
923
+ const wsWithRefOrd: Worksheet = await this.trxMgr.getRepository(Worksheet).findOne({
924
+ where: { id: worksheet.id },
925
+ relations: ['arrivalNotice', 'releaseGood', 'vasOrder', 'inventoryCheck', 'returnOrder']
926
+ })
927
+
928
+ refOrder =
929
+ wsWithRefOrd.arrivalNotice ||
930
+ wsWithRefOrd.releaseGood ||
931
+ wsWithRefOrd.vasOrder ||
932
+ wsWithRefOrd.inventoryCheck ||
933
+ wsWithRefOrd.returnOrder ||
934
+ null
935
+ if (!refOrder) throw new Error(this.ERROR_MSG.FIND.NO_RESULT(worksheet.id))
936
+ }
937
+
938
+ return refOrder
939
+ }
940
+
941
+ /**
942
+ * @summary extract out reference orders from given merged order worksheet
943
+ * @description If it doesn't have any reference order
944
+ * find worksheet with every possible reference order once again
945
+ * and extract out reference order from found worksheet
946
+ */
947
+ async extractMultipleRefOrderFromWorksheet(worksheet: Worksheet): Promise<ReferenceOrderType> {
948
+ const wsdWithRefOrd: WorksheetDetail[] = await this.trxMgr.getRepository(WorksheetDetail).find({
949
+ where: { domain: { id: this.domain.id }, worksheet: { id: worksheet.id } },
950
+ relations: ['targetInventory', 'targetInventory.releaseGood']
951
+ })
952
+
953
+ let refOrder: ReferenceOrderType[] = wsdWithRefOrd.map((ord: WorksheetDetail) => ord.targetInventory.releaseGood)
954
+
955
+ if (!refOrder) throw new Error(this.ERROR_MSG.FIND.NO_RESULT(worksheet.id))
956
+
957
+ //@ts-ignore
958
+ return refOrder
959
+ }
960
+
961
+ /**
962
+ * @summary Check whether passed pallet is existing alreay
963
+ * @description It will try to count inventories which has same domain and same pallet Id and not terminated one
964
+ * If there's positive result it will throw an error cause pallet is duplicated
965
+ */
966
+ async checkPalletDuplication(palletId: string): Promise<void> {
967
+ const duplicatedPalletCnt: number = await this.trxMgr.getRepository(Inventory).countBy({
968
+ domain: { id: this.domain.id },
969
+ palletId,
970
+ status: Not(Equal(INVENTORY_STATUS.TERMINATED))
971
+ })
972
+
973
+ if (duplicatedPalletCnt) throw new Error(this.ERROR_MSG.VALIDITY.DUPLICATED('Pallet ID', palletId))
974
+
975
+ const duplicatedReusablePalletCnt: number = await this.trxMgr.getRepository(Pallet).count({
976
+ where: {
977
+ domain: { id: this.domain.id },
978
+ name: palletId
979
+ }
980
+ })
981
+
982
+ if (duplicatedReusablePalletCnt) throw new Error(this.ERROR_MSG.VALIDITY.DUPLICATED('Pallet ID', palletId))
983
+ }
984
+
985
+ /**
986
+ * @summary Check whether passed carton is existing alreay
987
+ * @description It will try to count inventories which has same domain and same carton Id and not terminated one
988
+ * If there's positive result it will throw an error cause carton is duplicated
989
+ */
990
+ async checkCartonDuplication(cartonId: string, orderId: string): Promise<void> {
991
+ const duplicatedCartonCnt: number = await this.trxMgr.getRepository(Inventory).countBy({
992
+ domain: { id: this.domain.id },
993
+ cartonId,
994
+ refOrderId: Not(Equal(orderId)),
995
+ status: Not(Equal(INVENTORY_STATUS.TERMINATED))
996
+ })
997
+
998
+ if (duplicatedCartonCnt) throw new Error(this.ERROR_MSG.VALIDITY.DUPLICATED('Carton ID', cartonId))
999
+ }
1000
+
1001
+ /**
1002
+ * @summary Check whether passed serial number is existing already
1003
+ * @description It will try to count inventories which has same domain and same serial number and and not terminated one
1004
+ * If there's positive result it will throw an error cause serial number is duplicated
1005
+ */
1006
+ async checkSerialNumberDuplication(serialNumber: string, product: Product): Promise<void> {
1007
+ const duplicatedSerialNumberCnt: number = await this.trxMgr.getRepository(InventoryItem).countBy({
1008
+ domain: { id: this.domain.id },
1009
+ product: { id: product.id },
1010
+ serialNumber,
1011
+ status: Not(Equal(INVENTORY_STATUS.DELETED))
1012
+ })
1013
+
1014
+ if (duplicatedSerialNumberCnt) throw new Error(this.ERROR_MSG.VALIDITY.DUPLICATED('Serial Number', serialNumber))
1015
+ }
1016
+
1017
+ /**
1018
+ * @summary Check for product child qty at any scanned level
1019
+ * @description It will check every level of product detail by comparing scanned level and GAN registered level.
1020
+ * By getting the level that has relation, child qty will be retrieved
1021
+ * 1st level: PALLET -> 2 CARTONS (scan), 2nd level: CARTON -> 6 BAGS, 3rd level: BAG -> 10 UNITS, lowest: UNIT (order registered packing type)
1022
+ */
1023
+ async getChildQty(
1024
+ productDetails: ProductDetail[],
1025
+ productBarcode: string,
1026
+ orderProductDetail: ProductDetail
1027
+ ): Promise<number> {
1028
+ const scannedProductDetail: ProductDetail = productDetails.find(
1029
+ (productDetail: ProductDetail) => productDetail.gtin === productBarcode
1030
+ )
1031
+ let hasChildRelation: boolean = Boolean(scannedProductDetail?.childProductDetail)
1032
+ let hasMatchingChild: boolean
1033
+ let childQty: number
1034
+ let currentProductDetail: ProductDetail
1035
+
1036
+ if (hasChildRelation) {
1037
+ hasMatchingChild = Boolean(orderProductDetail.id === scannedProductDetail.childProductDetail.id)
1038
+ currentProductDetail = productDetails.find(
1039
+ (productDetail: ProductDetail) => productDetail.id === scannedProductDetail.childProductDetail.id
1040
+ )
1041
+ if (!currentProductDetail)
1042
+ throw new Error(this.ERROR_MSG.FIND.NOT_MATCH('inner pack', `GTIN (${productBarcode})`))
1043
+ childQty = scannedProductDetail.packingSize
1044
+ } else {
1045
+ throw new Error(this.ERROR_MSG.FIND.NO_RESULT(productBarcode))
1046
+ }
1047
+
1048
+ if (hasMatchingChild) {
1049
+ childQty = scannedProductDetail.packingSize
1050
+ } else {
1051
+ while (hasChildRelation && !hasMatchingChild) {
1052
+ hasChildRelation = Boolean(currentProductDetail?.childProductDetail)
1053
+
1054
+ if (hasChildRelation)
1055
+ hasMatchingChild = Boolean(orderProductDetail.id === currentProductDetail.childProductDetail.id)
1056
+
1057
+ if (hasMatchingChild) {
1058
+ childQty = currentProductDetail.packingSize * childQty
1059
+ } else if (!hasMatchingChild && hasChildRelation) {
1060
+ childQty = currentProductDetail.packingSize * childQty
1061
+ currentProductDetail = productDetails.find(
1062
+ (productDetail: ProductDetail) => productDetail.id === currentProductDetail.childProductDetail.id
1063
+ )
1064
+ } else if (!hasChildRelation && !hasMatchingChild) {
1065
+ throw new Error(this.ERROR_MSG.FIND.NO_RESULT(productBarcode))
1066
+ }
1067
+ }
1068
+ }
1069
+
1070
+ return childQty
1071
+ }
1072
+
1073
+ public async getDirectQty(productDetail: ProductDetail, productBarcode: string, qty: number): Promise<any> {
1074
+ try {
1075
+ console.time('getDirectQty')
1076
+ let results = await this.trxMgr.query(
1077
+ `
1078
+ WITH RECURSIVE cte as (
1079
+ select * from (
1080
+ select pd.product_id as "productId", id, pd.packing_size as "packingSize",
1081
+ pd.packing_type as "packingType", pd.uom as "uom", (pd.uom_value * $2::float) as "uomValue", $2::float as "qty", pd.gtin
1082
+ from product_details pd
1083
+ where pd.id = $1
1084
+ ) as dt
1085
+ union all
1086
+ select pd.product_id as "productId", pd.id, pd.packing_size as "packingSize",
1087
+ pd.packing_type as "packingType", pd.uom,
1088
+ dt1.qty * pd.packing_size * pd.uom_value as "uomValue", dt1.qty * pd.packing_size as "qty", pd.gtin
1089
+ from product_details pd
1090
+ inner join cte dt1 on dt1.id = pd.child_product_detail_id
1091
+ where pd.deleted_at is null
1092
+ )
1093
+ select * from cte where gtin = $3
1094
+ `,
1095
+ [productDetail.id, qty, productBarcode]
1096
+ )
1097
+
1098
+ if (results.length <= 0) throw new Error(this.ERROR_MSG.FIND.NO_RESULT(productBarcode))
1099
+
1100
+ console.timeEnd('getDirectQty')
1101
+ return results[0]
1102
+ } catch (error) {
1103
+ throw error
1104
+ }
1105
+ }
1106
+
1107
+ /**
1108
+ * @summary Check for product child qty at any scanned level
1109
+ * @description It will check every level of product detail by comparing scanned level and GAN registered level.
1110
+ * By getting the level that has relation, child qty will be retrieved
1111
+ * 1st level: PALLET -> 2 CARTONS (scan), 2nd level: CARTON -> 6 BAGS, 3rd level: BAG -> 10 UNITS, lowest: UNIT (order registered packing type)
1112
+ */
1113
+ async getChildPackingSize(
1114
+ productDetails: ProductDetail[],
1115
+ defaultProductDetail: ProductDetail,
1116
+ unmatchingProductDetail: ProductDetail
1117
+ ): Promise<number> {
1118
+ let hasChildRelation: boolean = Boolean(unmatchingProductDetail?.childProductDetail)
1119
+ let hasMatchingChild: boolean
1120
+ let packingSize: number = 1
1121
+ let currentChildProductDetail: ProductDetail
1122
+
1123
+ if (hasChildRelation) {
1124
+ currentChildProductDetail = productDetails.find(
1125
+ (productDetail: ProductDetail) => productDetail.id === unmatchingProductDetail.childProductDetail.id
1126
+ )
1127
+
1128
+ if (!currentChildProductDetail) {
1129
+ throw new Error(this.ERROR_MSG.FIND.NOT_MATCH('packing type', `GTIN (${unmatchingProductDetail.gtin})`))
1130
+ }
1131
+
1132
+ hasMatchingChild = Boolean(defaultProductDetail.id === currentChildProductDetail.id)
1133
+ if (hasMatchingChild) {
1134
+ packingSize = unmatchingProductDetail.packingSize
1135
+ } else {
1136
+ packingSize = unmatchingProductDetail.packingSize * packingSize
1137
+ }
1138
+ } else {
1139
+ throw new Error(this.ERROR_MSG.FIND.NO_CHILD_RESULT(`${unmatchingProductDetail.gtin}`))
1140
+ }
1141
+
1142
+ while (hasChildRelation && !hasMatchingChild) {
1143
+ if (hasMatchingChild) {
1144
+ packingSize = currentChildProductDetail.packingSize * packingSize // 12 x 10
1145
+ } else if (!hasMatchingChild && hasChildRelation) {
1146
+ packingSize = currentChildProductDetail.packingSize * packingSize // 12 x 10
1147
+ currentChildProductDetail = productDetails.find(
1148
+ (productDetail: ProductDetail) => productDetail.id === currentChildProductDetail.childProductDetail.id
1149
+ )
1150
+
1151
+ hasChildRelation = Boolean(currentChildProductDetail?.childProductDetail)
1152
+ hasMatchingChild = Boolean(defaultProductDetail.id === currentChildProductDetail.id)
1153
+ } else if (!hasChildRelation && !hasMatchingChild) {
1154
+ throw new Error(this.ERROR_MSG.FIND.NO_RESULT(unmatchingProductDetail.gtin))
1155
+ }
1156
+ }
1157
+
1158
+ return packingSize
1159
+ }
1160
+
1161
+ async createInventory(inventory: Partial<Inventory> | Partial<Inventory>[]): Promise<Inventory | Inventory[]> {
1162
+ inventory = this.setStamp(inventory)
1163
+ return await this.trxMgr.getRepository(Inventory).save(inventory)
1164
+ }
1165
+
1166
+ /**
1167
+ * @summary Update inventory record
1168
+ * @description It will update inventory after set a stamp (domain, updater)
1169
+ * The special point of this function is that this changes won't generate inventory history
1170
+ * If you want to generate inventory history automatically you would better to use transactionInventory function
1171
+ */
1172
+ async updateInventory(inventory: Partial<Inventory> | Partial<Inventory>[]): Promise<Inventory | Inventory[]> {
1173
+ //@ts-ignore
1174
+ if (!inventory.id) throw new Error(this.ERROR_MSG.UPDATE.ID_NOT_EXISTS)
1175
+ inventory = this.setStamp(inventory)
1176
+ return await this.trxMgr.getRepository(Inventory).save(inventory)
1177
+ }
1178
+
1179
+ /**
1180
+ * @summary Do transaction on inventory record
1181
+ * @description It will update inventory after set a temp (domain, updater)
1182
+ * and then generate inventory history based on current changes
1183
+ */
1184
+ async transactionInventory(
1185
+ inventory: Partial<Inventory>,
1186
+ referencOrder: ReferenceOrderType,
1187
+ changedQty: number,
1188
+ changedWeight: number,
1189
+ transactionType: string
1190
+ ): Promise<Inventory> {
1191
+ if (inventory.id) {
1192
+ //@ts-ignore
1193
+ inventory = await this.updateInventory(inventory)
1194
+ } else {
1195
+ //@ts-ignore
1196
+ inventory = await this.createInventory(inventory)
1197
+ }
1198
+
1199
+ await generateInventoryHistory(
1200
+ //@ts-ignore
1201
+ inventory,
1202
+ referencOrder,
1203
+ transactionType,
1204
+ changedQty,
1205
+ changedWeight,
1206
+ this.user,
1207
+ this.trxMgr
1208
+ )
1209
+
1210
+ //@ts-ignore
1211
+ return inventory
1212
+ }
1213
+
1214
+ /**
1215
+ * @summary set common stamp like domain, creator, updater
1216
+ * @description Set common stamp to passed record
1217
+ * If it doesn't have id it will handle it as creating one
1218
+ * If it has id it will handle it as updating one
1219
+ */
1220
+ setStamp(record: Record<string, any>): Record<string, any> {
1221
+ if (!record.domain) record.domain = this.domain
1222
+ if (!record.id && !record.creator) record.creator = this.user
1223
+ if (!record.updater) record.updater = this.user
1224
+
1225
+ return record
1226
+ }
1227
+
1228
+ /**
1229
+ * @summary Extract bizplace from reference order
1230
+ * @description It will find reference order with bizplace and return only bizplace to extract it out
1231
+ */
1232
+ async extractBizplaceFromRefOrder(refOrder: ReferenceOrderType, entitySchema?: EntitySchema): Promise<Bizplace> {
1233
+ if (!entitySchema) {
1234
+ if (refOrder instanceof ArrivalNotice) {
1235
+ //@ts-ignore
1236
+ entitySchema = ArrivalNotice
1237
+ } else if (refOrder instanceof ReleaseGood) {
1238
+ //@ts-ignore
1239
+ entitySchema = ReleaseGood
1240
+ } else if (refOrder instanceof VasOrder) {
1241
+ //@ts-ignore
1242
+ entitySchema = VasOrder
1243
+ } else if (refOrder instanceof InventoryCheck) {
1244
+ //@ts-ignore
1245
+ entitySchema = InventoryCheck
1246
+ } else if (refOrder instanceof ReturnOrder) {
1247
+ //@ts-ignore
1248
+ entitySchema = ReturnOrder
1249
+ }
1250
+ }
1251
+
1252
+ const { bizplace }: { bizplace: Bizplace } = await this.findRefOrder(entitySchema, refOrder, ['bizplace'])
1253
+ return bizplace
1254
+ }
1255
+
1256
+ tidyConditions(record: Record<string, any>): Record<string, any> {
1257
+ if ('id' in record) {
1258
+ return { id: record.id }
1259
+ } else {
1260
+ Object.keys(record).forEach((key: string) => {
1261
+ if (record[key] === null || record[key] instanceof Date || Array.isArray(record[key])) delete record[key]
1262
+ })
1263
+ }
1264
+
1265
+ return record
1266
+ }
1267
+ }