@things-factory/operato-hub 4.3.78 → 4.3.79-alpha.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 (168) hide show
  1. package/dist-server/middlewares/business-middleware.js +4 -1
  2. package/dist-server/middlewares/business-middleware.js.map +1 -1
  3. package/dist-server/middlewares/store-middleware.js.map +1 -1
  4. package/dist-server/routers/api/restful-apis/unstable/add-draft-release-order.js +3 -2
  5. package/dist-server/routers/api/restful-apis/unstable/add-draft-release-order.js.map +1 -1
  6. package/dist-server/routers/api/restful-apis/unstable/add-inbound-order.js +5 -2
  7. package/dist-server/routers/api/restful-apis/unstable/add-inbound-order.js.map +1 -1
  8. package/dist-server/routers/api/restful-apis/unstable/add-release-order.js +4 -2
  9. package/dist-server/routers/api/restful-apis/unstable/add-release-order.js.map +1 -1
  10. package/dist-server/routers/api/restful-apis/v1/company/add-contact-points.js +94 -0
  11. package/dist-server/routers/api/restful-apis/v1/company/add-contact-points.js.map +1 -0
  12. package/dist-server/routers/api/restful-apis/v1/company/add-marketplace-order.js +208 -0
  13. package/dist-server/routers/api/restful-apis/v1/company/add-marketplace-order.js.map +1 -0
  14. package/dist-server/routers/api/restful-apis/v1/company/add-product.js +65 -0
  15. package/dist-server/routers/api/restful-apis/v1/company/add-product.js.map +1 -0
  16. package/dist-server/routers/api/restful-apis/v1/company/cancel-marketplace-order.js +97 -0
  17. package/dist-server/routers/api/restful-apis/v1/company/cancel-marketplace-order.js.map +1 -0
  18. package/dist-server/routers/api/restful-apis/v1/company/get-bizplace-list.js +50 -0
  19. package/dist-server/routers/api/restful-apis/v1/company/get-bizplace-list.js.map +1 -0
  20. package/dist-server/routers/api/restful-apis/v1/company/get-contact-point-list.js +63 -0
  21. package/dist-server/routers/api/restful-apis/v1/company/get-contact-point-list.js.map +1 -0
  22. package/dist-server/routers/api/restful-apis/v1/company/get-marketplace-order-shipping-list.js +110 -0
  23. package/dist-server/routers/api/restful-apis/v1/company/get-marketplace-order-shipping-list.js.map +1 -0
  24. package/dist-server/routers/api/restful-apis/v1/company/get-marketplace-store-list.js +52 -0
  25. package/dist-server/routers/api/restful-apis/v1/company/get-marketplace-store-list.js.map +1 -0
  26. package/dist-server/routers/api/restful-apis/v1/company/get-partner-list.js +90 -0
  27. package/dist-server/routers/api/restful-apis/v1/company/get-partner-list.js.map +1 -0
  28. package/dist-server/routers/api/restful-apis/v1/company/get-product-list.js +99 -0
  29. package/dist-server/routers/api/restful-apis/v1/company/get-product-list.js.map +1 -0
  30. package/dist-server/routers/api/restful-apis/v1/company/index.js +14 -0
  31. package/dist-server/routers/api/restful-apis/v1/company/index.js.map +1 -0
  32. package/dist-server/routers/api/restful-apis/v1/company/update-marketplace-order-delivered.js +65 -0
  33. package/dist-server/routers/api/restful-apis/v1/company/update-marketplace-order-delivered.js.map +1 -0
  34. package/dist-server/routers/api/restful-apis/v1/index.js +2 -31
  35. package/dist-server/routers/api/restful-apis/v1/index.js.map +1 -1
  36. package/dist-server/routers/api/restful-apis/v1/middlewares/business-middleware.js +29 -0
  37. package/dist-server/routers/api/restful-apis/v1/middlewares/business-middleware.js.map +1 -0
  38. package/dist-server/routers/api/restful-apis/v1/middlewares/index.js +40 -0
  39. package/dist-server/routers/api/restful-apis/v1/middlewares/index.js.map +1 -0
  40. package/dist-server/routers/api/restful-apis/v1/middlewares/logging-middleware.js +23 -0
  41. package/dist-server/routers/api/restful-apis/v1/middlewares/logging-middleware.js.map +1 -0
  42. package/dist-server/routers/api/restful-apis/v1/middlewares/store-middleware.js +32 -0
  43. package/dist-server/routers/api/restful-apis/v1/middlewares/store-middleware.js.map +1 -0
  44. package/dist-server/routers/api/restful-apis/v1/middlewares/validation-middleware.js +53 -0
  45. package/dist-server/routers/api/restful-apis/v1/middlewares/validation-middleware.js.map +1 -0
  46. package/dist-server/routers/api/restful-apis/v1/middlewares/warehouse-middleware.js +31 -0
  47. package/dist-server/routers/api/restful-apis/v1/middlewares/warehouse-middleware.js.map +1 -0
  48. package/dist-server/routers/api/restful-apis/v1/utils/error-util.js +71 -0
  49. package/dist-server/routers/api/restful-apis/v1/utils/error-util.js.map +1 -0
  50. package/dist-server/routers/api/restful-apis/v1/utils/expected-parameters.js +201 -0
  51. package/dist-server/routers/api/restful-apis/v1/utils/expected-parameters.js.map +1 -0
  52. package/dist-server/routers/api/restful-apis/v1/utils/params.js +293 -0
  53. package/dist-server/routers/api/restful-apis/v1/utils/params.js.map +1 -0
  54. package/dist-server/routers/api/restful-apis/v1/utils/validate-util.js +90 -0
  55. package/dist-server/routers/api/restful-apis/v1/utils/validate-util.js.map +1 -0
  56. package/dist-server/routers/api/restful-apis/v1/warehouse/add-inbound-order.js +277 -0
  57. package/dist-server/routers/api/restful-apis/v1/warehouse/add-inbound-order.js.map +1 -0
  58. package/dist-server/routers/api/restful-apis/v1/warehouse/add-release-order.js +810 -0
  59. package/dist-server/routers/api/restful-apis/v1/warehouse/add-release-order.js.map +1 -0
  60. package/dist-server/routers/api/restful-apis/v1/warehouse/cancel-inbound-order.js +116 -0
  61. package/dist-server/routers/api/restful-apis/v1/warehouse/cancel-inbound-order.js.map +1 -0
  62. package/dist-server/routers/api/restful-apis/v1/warehouse/get-delivery-order-list.js +140 -0
  63. package/dist-server/routers/api/restful-apis/v1/warehouse/get-delivery-order-list.js.map +1 -0
  64. package/dist-server/routers/api/restful-apis/v1/warehouse/get-goods-received-note-list.js +100 -0
  65. package/dist-server/routers/api/restful-apis/v1/warehouse/get-goods-received-note-list.js.map +1 -0
  66. package/dist-server/routers/api/restful-apis/v1/warehouse/get-inbound-order-details.js +78 -0
  67. package/dist-server/routers/api/restful-apis/v1/warehouse/get-inbound-order-details.js.map +1 -0
  68. package/dist-server/routers/api/restful-apis/v1/warehouse/get-inbound-order-list.js +96 -0
  69. package/dist-server/routers/api/restful-apis/v1/warehouse/get-inbound-order-list.js.map +1 -0
  70. package/dist-server/routers/api/restful-apis/v1/warehouse/get-inventory-product-group-list.js +244 -0
  71. package/dist-server/routers/api/restful-apis/v1/warehouse/get-inventory-product-group-list.js.map +1 -0
  72. package/dist-server/routers/api/restful-apis/v1/warehouse/get-onhand-inventory-list.js +96 -0
  73. package/dist-server/routers/api/restful-apis/v1/warehouse/get-onhand-inventory-list.js.map +1 -0
  74. package/dist-server/routers/api/restful-apis/v1/warehouse/get-release-order-details.js +94 -0
  75. package/dist-server/routers/api/restful-apis/v1/warehouse/get-release-order-details.js.map +1 -0
  76. package/dist-server/routers/api/restful-apis/v1/warehouse/get-release-order-list.js +112 -0
  77. package/dist-server/routers/api/restful-apis/v1/warehouse/get-release-order-list.js.map +1 -0
  78. package/dist-server/routers/api/restful-apis/v1/warehouse/index.js +13 -0
  79. package/dist-server/routers/api/restful-apis/v1/warehouse/index.js.map +1 -0
  80. package/package.json +54 -54
  81. package/server/middlewares/business-middleware.ts +5 -1
  82. package/server/middlewares/store-middleware.ts +1 -0
  83. package/server/routers/api/restful-apis/unstable/add-draft-release-order.ts +3 -2
  84. package/server/routers/api/restful-apis/unstable/add-inbound-order.ts +5 -2
  85. package/server/routers/api/restful-apis/unstable/add-release-order.ts +4 -2
  86. package/server/routers/api/restful-apis/v1/company/add-contact-points.ts +94 -0
  87. package/server/routers/api/restful-apis/v1/company/add-marketplace-order.ts +242 -0
  88. package/server/routers/api/restful-apis/v1/company/add-product.ts +78 -0
  89. package/server/routers/api/restful-apis/v1/company/cancel-marketplace-order.ts +102 -0
  90. package/server/routers/api/restful-apis/v1/company/get-bizplace-list.ts +56 -0
  91. package/server/routers/api/restful-apis/v1/company/get-contact-point-list.ts +69 -0
  92. package/server/routers/api/restful-apis/v1/company/get-marketplace-order-shipping-list.ts +118 -0
  93. package/server/routers/api/restful-apis/v1/company/get-marketplace-store-list.ts +58 -0
  94. package/server/routers/api/restful-apis/v1/company/get-partner-list.ts +97 -0
  95. package/server/routers/api/restful-apis/v1/company/get-product-list.ts +105 -0
  96. package/server/routers/api/restful-apis/v1/company/index.ts +11 -0
  97. package/server/routers/api/restful-apis/v1/company/update-marketplace-order-delivered.ts +70 -0
  98. package/server/routers/api/restful-apis/v1/index.ts +2 -31
  99. package/server/routers/api/restful-apis/v1/middlewares/business-middleware.ts +31 -0
  100. package/server/routers/api/restful-apis/v1/middlewares/index.ts +26 -0
  101. package/server/routers/api/restful-apis/v1/middlewares/logging-middleware.ts +24 -0
  102. package/server/routers/api/restful-apis/v1/middlewares/store-middleware.ts +34 -0
  103. package/server/routers/api/restful-apis/v1/middlewares/validation-middleware.ts +50 -0
  104. package/server/routers/api/restful-apis/v1/middlewares/warehouse-middleware.ts +31 -0
  105. package/server/routers/api/restful-apis/v1/utils/error-util.ts +70 -0
  106. package/server/routers/api/restful-apis/v1/utils/expected-parameters.ts +199 -0
  107. package/server/routers/api/restful-apis/v1/utils/params.ts +291 -0
  108. package/server/routers/api/restful-apis/v1/utils/validate-util.ts +74 -0
  109. package/server/routers/api/restful-apis/v1/warehouse/add-inbound-order.ts +361 -0
  110. package/server/routers/api/restful-apis/v1/warehouse/add-release-order.ts +1000 -0
  111. package/server/routers/api/restful-apis/v1/warehouse/cancel-inbound-order.ts +139 -0
  112. package/server/routers/api/restful-apis/v1/warehouse/get-delivery-order-list.ts +144 -0
  113. package/server/routers/api/restful-apis/v1/warehouse/get-goods-received-note-list.ts +109 -0
  114. package/server/routers/api/restful-apis/v1/warehouse/get-inbound-order-details.ts +74 -0
  115. package/server/routers/api/restful-apis/v1/warehouse/get-inbound-order-list.ts +99 -0
  116. package/server/routers/api/restful-apis/v1/warehouse/get-inventory-product-group-list.ts +295 -0
  117. package/server/routers/api/restful-apis/v1/warehouse/get-onhand-inventory-list.ts +99 -0
  118. package/server/routers/api/restful-apis/v1/warehouse/get-release-order-details.ts +97 -0
  119. package/server/routers/api/restful-apis/v1/warehouse/get-release-order-list.ts +116 -0
  120. package/server/routers/api/restful-apis/v1/warehouse/index.ts +10 -0
  121. package/dist-server/routers/api/restful-apis/v1/bizplace.js +0 -45
  122. package/dist-server/routers/api/restful-apis/v1/bizplace.js.map +0 -1
  123. package/dist-server/routers/api/restful-apis/v1/get-contact-point-list.js +0 -103
  124. package/dist-server/routers/api/restful-apis/v1/get-contact-point-list.js.map +0 -1
  125. package/dist-server/routers/api/restful-apis/v1/get-delivery-order-detail.js +0 -47
  126. package/dist-server/routers/api/restful-apis/v1/get-delivery-order-detail.js.map +0 -1
  127. package/dist-server/routers/api/restful-apis/v1/get-delivery-order-list.js +0 -124
  128. package/dist-server/routers/api/restful-apis/v1/get-delivery-order-list.js.map +0 -1
  129. package/dist-server/routers/api/restful-apis/v1/get-delivery-orders.js +0 -164
  130. package/dist-server/routers/api/restful-apis/v1/get-delivery-orders.js.map +0 -1
  131. package/dist-server/routers/api/restful-apis/v1/get-goods-received-notes.js +0 -120
  132. package/dist-server/routers/api/restful-apis/v1/get-goods-received-notes.js.map +0 -1
  133. package/dist-server/routers/api/restful-apis/v1/get-inbound-order-detail.js +0 -115
  134. package/dist-server/routers/api/restful-apis/v1/get-inbound-order-detail.js.map +0 -1
  135. package/dist-server/routers/api/restful-apis/v1/get-inbound-order-list.js +0 -125
  136. package/dist-server/routers/api/restful-apis/v1/get-inbound-order-list.js.map +0 -1
  137. package/dist-server/routers/api/restful-apis/v1/get-inventory-overall-product-group.js +0 -88
  138. package/dist-server/routers/api/restful-apis/v1/get-inventory-overall-product-group.js.map +0 -1
  139. package/dist-server/routers/api/restful-apis/v1/get-marketplace-store-list.js +0 -79
  140. package/dist-server/routers/api/restful-apis/v1/get-marketplace-store-list.js.map +0 -1
  141. package/dist-server/routers/api/restful-apis/v1/get-onhand-inventories.js +0 -110
  142. package/dist-server/routers/api/restful-apis/v1/get-onhand-inventories.js.map +0 -1
  143. package/dist-server/routers/api/restful-apis/v1/get-partners.js +0 -23
  144. package/dist-server/routers/api/restful-apis/v1/get-partners.js.map +0 -1
  145. package/dist-server/routers/api/restful-apis/v1/get-products.js +0 -210
  146. package/dist-server/routers/api/restful-apis/v1/get-products.js.map +0 -1
  147. package/dist-server/routers/api/restful-apis/v1/get-release-order-detail.js +0 -122
  148. package/dist-server/routers/api/restful-apis/v1/get-release-order-detail.js.map +0 -1
  149. package/dist-server/routers/api/restful-apis/v1/get-release-order-list.js +0 -191
  150. package/dist-server/routers/api/restful-apis/v1/get-release-order-list.js.map +0 -1
  151. package/dist-server/routers/api/restful-apis/v1/get-warehouses.js +0 -20
  152. package/dist-server/routers/api/restful-apis/v1/get-warehouses.js.map +0 -1
  153. package/server/routers/api/restful-apis/v1/bizplace.ts +0 -45
  154. package/server/routers/api/restful-apis/v1/get-contact-point-list.ts +0 -110
  155. package/server/routers/api/restful-apis/v1/get-delivery-order-detail.ts +0 -46
  156. package/server/routers/api/restful-apis/v1/get-delivery-order-list.ts +0 -121
  157. package/server/routers/api/restful-apis/v1/get-delivery-orders.ts +0 -178
  158. package/server/routers/api/restful-apis/v1/get-goods-received-notes.ts +0 -134
  159. package/server/routers/api/restful-apis/v1/get-inbound-order-detail.ts +0 -128
  160. package/server/routers/api/restful-apis/v1/get-inbound-order-list.ts +0 -126
  161. package/server/routers/api/restful-apis/v1/get-inventory-overall-product-group.ts +0 -99
  162. package/server/routers/api/restful-apis/v1/get-marketplace-store-list.ts +0 -81
  163. package/server/routers/api/restful-apis/v1/get-onhand-inventories.ts +0 -125
  164. package/server/routers/api/restful-apis/v1/get-partners.ts +0 -24
  165. package/server/routers/api/restful-apis/v1/get-products.ts +0 -216
  166. package/server/routers/api/restful-apis/v1/get-release-order-detail.ts +0 -134
  167. package/server/routers/api/restful-apis/v1/get-release-order-list.ts +0 -198
  168. package/server/routers/api/restful-apis/v1/get-warehouses.ts +0 -18
@@ -0,0 +1,1000 @@
1
+ import { EntityManager, getConnection, getRepository, In, Not, Repository, SelectQueryBuilder } from 'typeorm'
2
+ import { v4 as uuidv4 } from 'uuid'
3
+
4
+ import { restfulApiRouter as router } from '@things-factory/api'
5
+ import { User } from '@things-factory/auth-base'
6
+ import { Bizplace, getCompanyBizplace } from '@things-factory/biz-base'
7
+ import { generateId } from '@things-factory/id-rule-base'
8
+ import { Sellercraft } from '@things-factory/integration-sellercraft'
9
+ import { MarketplaceOrder } from '@things-factory/marketplace-base'
10
+ import { ProductBundle, ProductDetail } from '@things-factory/product-base'
11
+ import {
12
+ createDraftReleaseGoodFunction,
13
+ DRAFT_RELEASE_ORDER_STATUS,
14
+ DraftReleaseGood,
15
+ ORDER_INVENTORY_STATUS,
16
+ ORDER_NUMBER_RULE_TYPE,
17
+ ORDER_NUMBER_SETTING_KEY,
18
+ ORDER_PRODUCT_STATUS,
19
+ ORDER_STATUS,
20
+ ORDER_TYPES,
21
+ OrderInventory,
22
+ OrderNoGenerator,
23
+ OrderProduct,
24
+ ReleaseGood,
25
+ SellercraftController,
26
+ ShippingOrder
27
+ } from '@things-factory/sales-base'
28
+ import { Setting } from '@things-factory/setting-base'
29
+ import { Domain } from '@things-factory/shell'
30
+ import { Inventory, INVENTORY_STATUS, LOCATION_TYPE } from '@things-factory/warehouse-base'
31
+
32
+ // import { ValidationError } from '../../../../errors/index'
33
+
34
+ import { loggingMiddleware, businessMiddleware, validationMiddleware } from '../middlewares'
35
+ import { ApiError, ApiErrorHandler, throwInternalServerError } from '../utils/error-util'
36
+
37
+ const debug = require('debug')('things-factory:operato-hub:restful-api:unstable:add-release-order')
38
+ const apiVersion = 'v1'
39
+
40
+ router.post(
41
+ `/${apiVersion}/warehouse/add-release-order`,
42
+ businessMiddleware,
43
+ validationMiddleware,
44
+ loggingMiddleware,
45
+ async (context, next) => {
46
+ return await getConnection().transaction(async (tx: EntityManager) => {
47
+ const { client, domain, user, application } = context.state
48
+ const { bizplaceId: customerBizplaceId } = context.request.body
49
+ const { t } = context
50
+ const bodyReq = context.request.body.data
51
+ const requiredDraft: Boolean = bodyReq.hasOwnProperty('requiredDraft') ? bodyReq.requiredDraft : true
52
+ let releaseGood
53
+ let massagedData = { orderProducts: [], combinedItems: [] }
54
+ // const isAutoAssign: Boolean = bodyReq.hasOwnProperty('isAutoAssign') ? bodyReq.isAutoAssign : true
55
+
56
+ try {
57
+ if (!customerBizplaceId) throw new ApiError('E04', 'warehouse id not found')
58
+
59
+ if (typeof bodyReq === undefined || !Object.keys(bodyReq)?.length) {
60
+ throw new ApiError('E01', 'invalid body request format')
61
+ }
62
+ debug('post:/add-release-order request.body', bodyReq)
63
+
64
+ // get customer company's bizplace
65
+ const custCompanyBizplace: Bizplace = await getCompanyBizplace(null, null, customerBizplaceId, tx)
66
+ const customerBizplace: Bizplace = await tx.getRepository(Bizplace).findOne({
67
+ where: { id: customerBizplaceId },
68
+ relations: ['domain']
69
+ })
70
+
71
+ // conditional validation
72
+ if (bodyReq.ownTransport && !bodyReq.collectionOrderNo) throw new ApiError('E03', 'collectionOrderNo')
73
+ if (bodyReq.exportOption && !bodyReq.shippingOrder) throw new ApiError('E03', 'shippingOrder')
74
+
75
+ bodyReq.exportOption
76
+ releaseGood = {
77
+ domain,
78
+ bizplace: customerBizplace,
79
+ companyBizplace: custCompanyBizplace,
80
+ courierOption: bodyReq.courierOption,
81
+ collectionOrderNo: bodyReq?.collectionOrderNo,
82
+ exportOption: bodyReq.exportOption,
83
+ ownTransport: bodyReq.ownTransport,
84
+ packingOption: bodyReq.packingOption,
85
+ refNo: bodyReq.refNo,
86
+ refNo2: bodyReq?.refNo2,
87
+ refNo3: bodyReq?.refNo3,
88
+ releaseDate: bodyReq.releaseDate,
89
+ type: bodyReq.type,
90
+ marketplaceOrderStatus: bodyReq?.marketplaceOrderStatus,
91
+ remark: bodyReq?.remark || null,
92
+ billingAddress: bodyReq?.billTo?.billingAddress || null,
93
+ deliveryAddress1: bodyReq?.deliverTo?.deliveryAddress1 || null,
94
+ deliveryAddress2: bodyReq?.deliverTo?.deliveryAddress2 || null,
95
+ deliveryAddress3: bodyReq?.deliverTo?.deliveryAddress3 || null,
96
+ deliveryAddress4: bodyReq?.deliverTo?.deliveryAddress4 || null,
97
+ deliveryAddress5: bodyReq?.deliverTo?.deliveryAddress5 || null,
98
+ attentionTo: bodyReq?.deliverTo?.attentionTo || null,
99
+ attentionCompany: bodyReq?.deliverTo?.attentionCompany || null,
100
+ city: bodyReq?.deliverTo?.city || null,
101
+ state: bodyReq?.deliverTo?.state || null,
102
+ postalCode: bodyReq?.deliverTo?.postalCode || null,
103
+ country: bodyReq?.deliverTo?.country || null,
104
+ phone1: bodyReq?.deliverTo?.phone1 || null,
105
+ phone2: bodyReq?.deliverTo?.phone2 || null,
106
+ email: bodyReq?.deliverTo?.email || null,
107
+ transporter: bodyReq?.transporter,
108
+ trackingNo: bodyReq?.trackingNo,
109
+ airwayBill: bodyReq?.airwayBill,
110
+ invoice: bodyReq?.invoice,
111
+ packageId: bodyReq?.packageId,
112
+ storeName: bodyReq?.storeName,
113
+ storeId: bodyReq?.storeId,
114
+ routeId: bodyReq?.routeId,
115
+ stopId: bodyReq?.stopId,
116
+ source: application?.type,
117
+ shippingOrder: {
118
+ shipName: bodyReq?.ShippingOrder.shipName,
119
+ containerNo: bodyReq?.shippingOrder.containerNo,
120
+ loadType: bodyReq?.shippingOrder?.loadType,
121
+ from: bodyReq?.shippingOrder?.from,
122
+ to: bodyReq?.shippingOrder?.to,
123
+ containerArrivalDate: bodyReq?.shippingOrder.containerArrivalDate,
124
+ containerLeavingDate: bodyReq?.shippingOrder.containerLeavingDate
125
+ }
126
+ }
127
+
128
+ // check existing order
129
+ await checkExistingOrder(releaseGood, customerBizplace, bodyReq?.checkDuplicationValidation, context, tx)
130
+
131
+ // massage data
132
+ massagedData = await massageOrderItems(releaseGood, bodyReq.orderInventories, context)
133
+
134
+ // validation
135
+ let errorList = []
136
+ await Promise.all(
137
+ massagedData.combinedItems.map(async item => {
138
+ let itemList = await tx.query(
139
+ `
140
+ select wboi.* from warehouse_bizplace_onhand_inventories wboi
141
+ where wboi."domainId"= $1 and
142
+ wboi."bizplaceId" = $2 and
143
+ wboi."groupType" = 'SINGLE' and
144
+ wboi."productId" = $3 and
145
+ wboi."packingType" = $4 and
146
+ wboi."packingSize" = $5 and
147
+ wboi."uom" = $6 and
148
+ wboi."remainQty" >= $7 and
149
+ wboi."remainUomValue" >= $8
150
+ `,
151
+ [
152
+ domain.id,
153
+ customerBizplace.id,
154
+ item.product.id,
155
+ item.packingType,
156
+ item.packingSize,
157
+ item.uom,
158
+ item.releaseQty,
159
+ item.releaseUomValue
160
+ ]
161
+ )
162
+ if (itemList.length <= 0) {
163
+ errorList.push(
164
+ JSON.stringify({
165
+ code: 'insufficient stock',
166
+ sku: item.product.sku,
167
+ packingType: item.packingType,
168
+ packingSize: item.packingSize,
169
+ uom: item.uom,
170
+ qty: item.releaseQty,
171
+ uom_value: item.releaseUomValue
172
+ })
173
+ )
174
+ }
175
+ console.log()
176
+ })
177
+ )
178
+
179
+ if (errorList.length > 0) {
180
+ throw new ApiError('E01', `insufficient stock, ${errorList.join(', ')}`)
181
+ }
182
+ // assignment
183
+ // console.time('assign')
184
+ let assignedOrderProducts = await assignToInventory(massagedData.orderProducts, customerBizplace, context, tx)
185
+ // console.timeEnd('assign')
186
+
187
+ // create order
188
+ // console.time('save')
189
+ let result = await createReleaseGood(releaseGood, assignedOrderProducts, customerBizplace, context, tx)
190
+ // console.timeEnd('save')
191
+
192
+ let addReleaseGood = {
193
+ id: result.id,
194
+ roNo: result.name,
195
+ refNo: result.refNo,
196
+ refNo2: result.refNo2,
197
+ refNo3: result.refNo3,
198
+ status: result.status,
199
+ truckNo: result.truckNo,
200
+ ownTransport: result.ownTransport,
201
+ crossDocking: result.crossDocking,
202
+ marketplaceOrderStatus: result.marketplaceOrderStatus,
203
+ billingAddress: result.billingAddress,
204
+ deliveryAddress1: result.deliveryAddress1,
205
+ deliveryAddress2: result.deliveryAddress2,
206
+ deliveryAddress3: result.deliveryAddress3,
207
+ deliveryAddress4: result.deliveryAddress4,
208
+ deliveryAddress5: result.deliveryAddress5,
209
+ attentionTo: result.attentionTo,
210
+ attentionCompany: result.attentionCompany,
211
+ city: result.city,
212
+ state: result.state,
213
+ postalCode: result.postalCode,
214
+ country: result.country,
215
+ phone1: result.phone1,
216
+ phone2: result.phone2,
217
+ email: result.email,
218
+ transporter: result.transporter,
219
+ trackingNo: result.trackingNo,
220
+ airwayBill: result.airwayBill,
221
+ invoice: result.invoice,
222
+ type: result.type,
223
+ packageId: result.packageId,
224
+ storeName: result.storeName,
225
+ storeId: result.storeId,
226
+ routeId: result.routeId,
227
+ stopId: result.stopId,
228
+ exportOption: result.exportOption,
229
+ releaseDate: result.releaseDate,
230
+ collectionOrderNo: result.collectionOrderNo,
231
+ bizplace: { name: result.bizplace.name },
232
+ domain: { name: result.domain.name },
233
+ orderInventories: result.orderInventories
234
+ }
235
+ // return body
236
+ context.body = { result: { addReleaseGood } }
237
+ } catch (error) {
238
+ if (error.errorCode) {
239
+ if (error.errorCode == 'INSUFFICIENT_STOCK' && requiredDraft) {
240
+ const result = await createDraftOrder(releaseGood, massagedData.orderProducts, context)
241
+ let createdDraftOrder = {
242
+ id: result.id,
243
+ name: result.name,
244
+ refNo: result.refNo,
245
+ refNo2: result.refNo2,
246
+ refNo3: result.refNo3,
247
+ status: result.status,
248
+ truckNo: result.truckNo,
249
+ ownTransport: result.ownTransport,
250
+ marketplaceOrderStatus: result.marketplaceOrderStatus,
251
+ billingAddress: result.billingAddress,
252
+ deliveryAddress1: result.deliveryAddress1,
253
+ deliveryAddress2: result.deliveryAddress2,
254
+ deliveryAddress3: result.deliveryAddress3,
255
+ deliveryAddress4: result.deliveryAddress4,
256
+ deliveryAddress5: result.deliveryAddress5,
257
+ attentionTo: result.attentionTo,
258
+ attentionCompany: result.attentionCompany,
259
+ city: result.city,
260
+ state: result.state,
261
+ postalCode: result.postalCode,
262
+ country: result.country,
263
+ phone1: result.phone1,
264
+ phone2: result.phone2,
265
+ email: result.email,
266
+ type: result.type,
267
+ packageId: result.packageId,
268
+ exportOption: result.exportOption,
269
+ releaseDate: result.releaseDate,
270
+ collectionOrderNo: result.collectionOrderNo,
271
+ bizplace: { name: result.bizplace.name },
272
+ domain: { name: result.domain.name }
273
+ }
274
+ context.body = { result: { createdDraftOrder } }
275
+ } else {
276
+ if (error instanceof ApiError) ApiErrorHandler(context, error)
277
+ else throwInternalServerError(context, error)
278
+ }
279
+ } else {
280
+ if (error instanceof ApiError) ApiErrorHandler(context, error)
281
+ else throwInternalServerError(context, error)
282
+ }
283
+ }
284
+ })
285
+ }
286
+ )
287
+
288
+ async function checkExistingOrder(releaseGood, bizplace, checkDuplicationValidation = true, context, tx) {
289
+ const { domain, user }: { domain: Domain; user: User } = context.state
290
+ const refNo: string = releaseGood.refNo
291
+ const refNo2: string = releaseGood.refNo2
292
+ const refNo3: string = releaseGood.refNo3
293
+
294
+ if (checkDuplicationValidation) {
295
+ const foundDraftReleaseGood: DraftReleaseGood = await tx.getRepository(DraftReleaseGood).findOne({
296
+ where: {
297
+ domain,
298
+ refNo: refNo || null,
299
+ refNo2: refNo2 || null,
300
+ refNo3: refNo3 || null,
301
+ status: Not(In([DRAFT_RELEASE_ORDER_STATUS.CANCELLED]))
302
+ }
303
+ })
304
+
305
+ if (foundDraftReleaseGood) {
306
+ throw new ApiError('E05', `existing draft release order found: ${foundDraftReleaseGood.name}`)
307
+ }
308
+
309
+ const sellercraft: Sellercraft = await tx.getRepository(Sellercraft).findOne({ domain: bizplace.domain })
310
+
311
+ if (sellercraft) {
312
+ const sellercraftCtrl: SellercraftController = new SellercraftController(tx, bizplace.domain, user)
313
+ await sellercraftCtrl.checkExistingReleaseGood(sellercraft, releaseGood)
314
+ } else {
315
+ const foundReleaseGood: ReleaseGood = await tx.getRepository(ReleaseGood).findOne({
316
+ where: {
317
+ domain: domain,
318
+ refNo,
319
+ status: Not(In([ORDER_STATUS.CANCELLED, ORDER_STATUS.PENDING_CANCEL]))
320
+ },
321
+ relations: ['bizplace', 'bizplace.domain', 'bizplace.company', 'bizplace.company.domain']
322
+ })
323
+
324
+ if (foundReleaseGood) {
325
+ const customerCompanyDomain: Domain = foundReleaseGood.bizplace.company.domain
326
+ const marketplaceOrder: MarketplaceOrder = await tx.getRepository(MarketplaceOrder).findOne({
327
+ where: { orderNo: refNo, domain: customerCompanyDomain }
328
+ })
329
+
330
+ // Need to restructure the validation
331
+ if (marketplaceOrder?.isSplitted) {
332
+ const refNo2: string = releaseGood.refNo2
333
+ const foundSplittedReleaseGood = await tx.getRepository(ReleaseGood).findOne({
334
+ where: {
335
+ domain,
336
+ refNo2,
337
+ status: Not(In([ORDER_STATUS.CANCELLED, ORDER_STATUS.PENDING_CANCEL]))
338
+ },
339
+ relations: ['bizplace', 'bizplace.domain', 'bizplace.company', 'bizplace.company.domain']
340
+ })
341
+
342
+ if (foundSplittedReleaseGood)
343
+ throw new ApiError('E05', `existing release order found: ${foundSplittedReleaseGood.name}`)
344
+ } else {
345
+ throw new ApiError('E05', `existing release order found: ${foundReleaseGood.name}`)
346
+ }
347
+ }
348
+ }
349
+ }
350
+ }
351
+
352
+ async function createDraftOrder(releaseGood, orderProducts, context) {
353
+ return await getConnection().transaction(async (tx: EntityManager) => {
354
+ return await createDraftReleaseGoodFunction(null, releaseGood, orderProducts, null, [], context, tx)
355
+ })
356
+ }
357
+
358
+ async function createReleaseGood(
359
+ releaseGood: any,
360
+ orderProducts: OrderProduct[],
361
+ bizplace: Bizplace,
362
+ context: any,
363
+ tx?: EntityManager
364
+ ): Promise<ReleaseGood> {
365
+ try {
366
+ const { domain, user }: { domain: Domain; user: User } = context.state
367
+ const settingRepo: Repository<Setting> = tx?.getRepository(Setting) || getRepository(Setting)
368
+
369
+ if (orderProducts.length <= 0) {
370
+ throw new ApiError('E04', `no order items found: ${JSON.stringify(releaseGood)}`)
371
+ }
372
+
373
+ let newReleaseGood: ReleaseGood = new ReleaseGood()
374
+
375
+ // find RO number rule setting
376
+ const roNoSetting: Setting = await settingRepo.findOne({
377
+ where: {
378
+ domain,
379
+ name: ORDER_NUMBER_SETTING_KEY.RO_NUMBER_RULE
380
+ }
381
+ })
382
+
383
+ let shippingOrder: ShippingOrder
384
+ if (releaseGood?.shippingOrder) {
385
+ shippingOrder = await tx.getRepository(ShippingOrder).save({
386
+ shipName: releaseGood.shippingOrder.shipName,
387
+ containerNo: releaseGood.shippingOrder.containerNo,
388
+ loadType: releaseGood.shippingOrder.loadType,
389
+ from: releaseGood.shippingOrder.from,
390
+ to: releaseGood.shippingOrder.to,
391
+ containerArrivalDate: releaseGood.shippingOrder.containerArrivalDate,
392
+ containerLeavingDate: releaseGood.shippingOrder.containerLeavingDate
393
+ })
394
+ }
395
+
396
+ newReleaseGood = {
397
+ name: roNoSetting
398
+ ? await generateId({ domain, type: ORDER_NUMBER_RULE_TYPE.RO_NUMBER, seed: {} })
399
+ : OrderNoGenerator.releaseGood(),
400
+ domain: domain,
401
+ bizplace: bizplace,
402
+ collectionOrderNo: releaseGood.collectionOrderNo,
403
+ courierOption: releaseGood.courierOption,
404
+ exportOption: releaseGood.exportOption,
405
+ ownTransport: releaseGood.ownTransport,
406
+ packingOption: releaseGood.packingOption,
407
+ marketplaceOrderStatus: releaseGood?.marketplaceOrderStatus || null,
408
+ billingAddress: releaseGood?.billingAddress || null,
409
+ deliveryAddress1: releaseGood?.deliveryAddress1 || null,
410
+ deliveryAddress2: releaseGood?.deliveryAddress2 || null,
411
+ deliveryAddress3: releaseGood?.deliveryAddress3 || null,
412
+ deliveryAddress4: releaseGood?.deliveryAddress4 || null,
413
+ deliveryAddress5: releaseGood?.deliveryAddress5 || null,
414
+ attentionTo: releaseGood?.attentionTo || null,
415
+ attentionCompany: releaseGood?.attentionCompany || null,
416
+ city: releaseGood?.city || null,
417
+ state: releaseGood?.state || null,
418
+ postalCode: releaseGood?.postalCode || null,
419
+ country: releaseGood?.country || null,
420
+ phone1: releaseGood?.phone1 || null,
421
+ phone2: releaseGood?.phone2 || null,
422
+ email: releaseGood?.email || null,
423
+ transporter: releaseGood?.transporter,
424
+ trackingNo: releaseGood?.trackingNo,
425
+ airwayBill: releaseGood?.airwayBill,
426
+ invoice: releaseGood?.invoice,
427
+ refNo: releaseGood.refNo,
428
+ refNo2: releaseGood.refNo2 || null,
429
+ refNo3: releaseGood.refNo3 || null,
430
+ remark: releaseGood?.remark || null,
431
+ releaseDate: releaseGood.releaseDate,
432
+ truckNo: releaseGood.truckNo,
433
+ type: releaseGood?.type ? releaseGood.type : 'b2b',
434
+ status: ORDER_STATUS.PENDING_WORKSHEET,
435
+ storeName: releaseGood?.storeName,
436
+ storeId: releaseGood?.storeId,
437
+ routeId: releaseGood?.routeId,
438
+ stopId: releaseGood?.stopId,
439
+ packageId: releaseGood?.packageId || null,
440
+ noOfItems: orderProducts.length,
441
+ source: releaseGood?.source,
442
+ creator: user,
443
+ updater: user,
444
+ acceptedBy: user,
445
+ acceptedAt: new Date(),
446
+ shippingOrder: shippingOrder ? shippingOrder : null
447
+ }
448
+
449
+ let resultReleaseGood = await tx.getRepository(ReleaseGood).save(newReleaseGood)
450
+ let combinedOrderInventories: OrderInventory[] = []
451
+ let savedOrderProducts = await Promise.all(
452
+ orderProducts.map(async orderProduct => {
453
+ let orderInventories: OrderInventory[] = orderProduct.orderInventories
454
+ orderProduct = Object.assign(new OrderProduct(), {
455
+ ...orderProduct,
456
+ name: uuidv4(),
457
+ domain: domain,
458
+ bizplace: bizplace,
459
+ releaseGood: resultReleaseGood,
460
+ type: ORDER_TYPES.RELEASE_OF_GOODS,
461
+ status: ORDER_PRODUCT_STATUS.ASSIGNED
462
+ })
463
+ let result = await tx.getRepository(OrderProduct).save(orderProduct)
464
+
465
+ for (let oiIdx = 0; oiIdx < orderInventories.length; oiIdx++) {
466
+ let orderInventory = Object.assign(new OrderInventory(), {
467
+ ...orderInventories[oiIdx],
468
+ name: uuidv4(),
469
+ domain: domain,
470
+ bizplace: bizplace,
471
+ releaseGood: resultReleaseGood,
472
+ type: ORDER_TYPES.RELEASE_OF_GOODS,
473
+ status: ORDER_INVENTORY_STATUS.PENDING_WORKSHEET
474
+ })
475
+ await tx.getRepository(OrderInventory).save(orderInventory)
476
+
477
+ combinedOrderInventories.push({
478
+ product: { name: orderInventory.product.name, sku: orderInventory.product.sku },
479
+ batchId: orderInventory.batchId,
480
+ packingType: orderInventory.packingType,
481
+ packingSize: orderInventory.packingSize,
482
+ releaseQty: orderInventory.releaseQty,
483
+ releaseUomValue: orderInventory.releaseUomValue
484
+ })
485
+ }
486
+
487
+ return result
488
+ })
489
+ )
490
+
491
+ newReleaseGood.orderProducts = savedOrderProducts
492
+ newReleaseGood.orderInventories = combinedOrderInventories
493
+
494
+ return newReleaseGood
495
+ } catch (error) {
496
+ if (error instanceof ApiError) ApiErrorHandler(context, error)
497
+ else throwInternalServerError(context, error)
498
+ }
499
+ }
500
+
501
+ async function massageOrderItems(
502
+ releaseGood,
503
+ inputOrderProducts,
504
+ context
505
+ ): Promise<{ orderProducts: OrderProduct[]; combinedItems: OrderProduct[] }> {
506
+ const { t } = context
507
+ try {
508
+ let orderProducts: OrderProduct[] = []
509
+ let errorList = []
510
+ //combine any repeated skus
511
+ inputOrderProducts = inputOrderProducts.reduce((acc, itm, idx) => {
512
+ let { sku, refCode } = itm.product
513
+ let { packingType, packingSize, batchId, releaseQty } = itm
514
+
515
+ if (!sku && !refCode) {
516
+ errorList.push(
517
+ JSON.stringify({
518
+ code: 'INVALID_DATA',
519
+ message: 'sku or refCode not found',
520
+ sku: sku,
521
+ refCode: refCode,
522
+ packingType: packingType?.trim(),
523
+ packingSize: packingSize,
524
+ qty: releaseQty
525
+ })
526
+ )
527
+ }
528
+
529
+ if (releaseQty <= 0) {
530
+ errorList.push(
531
+ JSON.stringify({
532
+ code: 'INVALID_DATA',
533
+ message: 'negative stock request',
534
+ sku: sku,
535
+ refCode: refCode,
536
+ packingType: packingType?.trim(),
537
+ packingSize: packingSize,
538
+ qty: releaseQty
539
+ })
540
+ )
541
+ }
542
+
543
+ let existingIndex = acc.findIndex(
544
+ itm =>
545
+ itm?.sku == sku?.trim() &&
546
+ itm?.refCode == refCode?.trim() &&
547
+ itm?.packingType == packingType?.trim() &&
548
+ itm?.packingSize == packingSize
549
+ )
550
+
551
+ if (existingIndex >= 0 && releaseQty > 0) {
552
+ acc[existingIndex].releaseQty = acc[existingIndex].releaseQty + releaseQty
553
+ } else {
554
+ acc.push({
555
+ sku: sku?.trim(),
556
+ refCode: refCode?.trim(),
557
+ packingType: packingType?.trim(),
558
+ packingSize: packingSize,
559
+ releaseQty: releaseQty
560
+ })
561
+ }
562
+
563
+ return acc
564
+ }, [])
565
+
566
+ if (errorList.length > 0) {
567
+ throw new ApiError('E01', errorList.join(', '))
568
+ }
569
+
570
+ //find customer sku in system
571
+ await Promise.all(
572
+ inputOrderProducts.map(async inputOrderItem => {
573
+ const sku: string = inputOrderItem.sku
574
+ const refCode: string = inputOrderItem.refCode
575
+ const packingType: string = inputOrderItem.packingType
576
+ const packingSize: string = inputOrderItem.packingSize
577
+
578
+ const qb: SelectQueryBuilder<ProductDetail> = getRepository(ProductDetail)
579
+ .createQueryBuilder('PD')
580
+ .innerJoinAndSelect('PD.product', 'PROD')
581
+ .where('PROD.bizplace_id = :bizplaceId', { bizplaceId: releaseGood.companyBizplace.id })
582
+
583
+ if (!sku && !refCode) {
584
+ throw new ApiError('E04', t('sku or refCode not found'))
585
+ }
586
+
587
+ if (refCode) {
588
+ qb.andWhere('PD.ref_code = :refCode', { refCode })
589
+ }
590
+
591
+ if (sku) {
592
+ qb.andWhere('PROD.sku = :sku', { sku })
593
+ }
594
+
595
+ if (packingType) {
596
+ qb.andWhere('PD.packing_type = :packingType', { packingType })
597
+ }
598
+
599
+ if ((!packingType && !refCode) || !packingSize) {
600
+ qb.andWhere('PD.is_default = :isDefault', { isDefault: true })
601
+ }
602
+
603
+ const productDetail: ProductDetail = await qb.getOne()
604
+
605
+ // order Product based on product detail
606
+ if (productDetail) {
607
+ let newOrderProduct: OrderInventory = Object.assign({}, inputOrderItem)
608
+ newOrderProduct = {
609
+ ...newOrderProduct,
610
+ product: productDetail.product,
611
+ productDetail: productDetail,
612
+ packingType: productDetail.packingType,
613
+ packingSize: packingSize || productDetail.packingSize,
614
+ uom: productDetail.uom,
615
+ uomValue: productDetail.uomValue,
616
+ refCode: inputOrderItem.refCode,
617
+ releaseQty: inputOrderItem.releaseQty,
618
+ releaseUomValue: inputOrderItem.releaseQty * (productDetail.uomValue || 1),
619
+ packQty: 0,
620
+ actualPackQty: 0,
621
+ palletQty: 0,
622
+ actualPalletQty: 0,
623
+ type: 'RELEASE_OF_GOODS',
624
+ status: ORDER_PRODUCT_STATUS.ASSIGNED,
625
+ batchId: '-'
626
+ }
627
+
628
+ newOrderProduct.orderInventories = [
629
+ {
630
+ ...newOrderProduct,
631
+ packQty: 0,
632
+ actualPackQty: 0,
633
+ palletQty: 0,
634
+ actualPalletQty: 0,
635
+ type: 'RELEASE_OF_GOODS',
636
+ status: ORDER_INVENTORY_STATUS.PENDING_WORKSHEET
637
+ }
638
+ ]
639
+
640
+ orderProducts.push(newOrderProduct)
641
+ }
642
+
643
+ if (!productDetail) {
644
+ const qb: SelectQueryBuilder<ProductDetail> = getRepository(ProductBundle)
645
+ .createQueryBuilder('PB')
646
+ .innerJoinAndSelect('PB.productBundleSettings', 'PBS')
647
+ .innerJoinAndSelect('PBS.productDetail', 'PBD')
648
+ .innerJoinAndSelect('PBD.product', 'PROD')
649
+ .where('PB.bizplace_id = :bizplaceId', { bizplaceId: releaseGood.companyBizplace.id })
650
+
651
+ if (!sku && !refCode) {
652
+ throw new ApiError('E04', 'sku or refCode not found')
653
+ }
654
+
655
+ if (refCode) {
656
+ qb.andWhere('PB.ref_code = :refCode', { refCode })
657
+ }
658
+
659
+ if (sku) {
660
+ qb.andWhere('PB.sku = :sku', { sku })
661
+ }
662
+
663
+ if (packingType) {
664
+ qb.andWhere('PB.packing_type = :packingType', { packingType })
665
+ }
666
+
667
+ const foundProductBundle: ProductBundle = await qb.getOne()
668
+
669
+ if (foundProductBundle) {
670
+ let orderProduct = {
671
+ productBundle: foundProductBundle,
672
+ refCode,
673
+ packingType: foundProductBundle.packingType,
674
+ packingSize: packingSize || 1,
675
+ uom: inputOrderItem?.uom,
676
+ releaseQty: inputOrderItem.releaseQty,
677
+ releaseUomValue: inputOrderItem.releaseQty,
678
+ packQty: 0,
679
+ actualPackQty: 0,
680
+ palletQty: 0,
681
+ actualPalletQty: 0,
682
+ orderInventories: [],
683
+ type: 'RELEASE_OF_GOODS',
684
+ status: ORDER_PRODUCT_STATUS.ASSIGNED,
685
+ batchId: '-'
686
+ }
687
+
688
+ const bundleProductSettings: any[] = foundProductBundle.productBundleSettings
689
+ bundleProductSettings.map(bundleProductSetting => {
690
+ const productDetailBundle: ProductDetail = bundleProductSetting.productDetail
691
+
692
+ let newOrderInventory: OrderInventory = {
693
+ product: productDetailBundle.product,
694
+ productDetail: productDetailBundle,
695
+ sku: productDetailBundle.product.sku,
696
+ packingType: productDetailBundle.packingType,
697
+ packingSize: productDetailBundle.packingSize,
698
+ uom: productDetailBundle.uom,
699
+ packQty: 0,
700
+ actualPackQty: 0,
701
+ palletQty: 0,
702
+ actualPalletQty: 0,
703
+ releaseQty: inputOrderItem.releaseQty * bundleProductSetting.bundleQty,
704
+ releaseUomValue:
705
+ inputOrderItem.releaseQty *
706
+ bundleProductSetting.bundleQty *
707
+ (productDetailBundle.uomValue <= 0 ? 1 : productDetailBundle.uomValue),
708
+ type: 'RELEASE_OF_GOODS',
709
+ status: ORDER_INVENTORY_STATUS.PENDING_WORKSHEET
710
+ }
711
+
712
+ orderProduct.orderInventories.push(newOrderInventory)
713
+ })
714
+ orderProducts.push(orderProduct)
715
+ } else {
716
+ if (sku && refCode) {
717
+ throw new ApiError(
718
+ 'E04',
719
+ t(`error.sku ${sku} and refCode ${refCode} not exist in product / bundle master`)
720
+ )
721
+ }
722
+
723
+ if (sku) {
724
+ throw new ApiError('E04', t(`error.sku ${sku} not exist in product / bundle master`))
725
+ }
726
+
727
+ if (refCode) {
728
+ throw new ApiError('E04', t(`error.refCode ${refCode} not exist in product / bundle master`))
729
+ }
730
+ }
731
+ }
732
+ })
733
+ )
734
+
735
+ //combine any repeated skus
736
+ let combinedItems: OrderProduct[] = orderProducts.reduce((acc, op, idx) => {
737
+ let oi = op?.orderInventories || []
738
+ oi.forEach(itm => {
739
+ let { sku, refCode } = itm.product
740
+ let { packingType, packingSize, batchId, releaseQty, product, productDetail, uom } = itm
741
+
742
+ if (!sku && !refCode) {
743
+ throw new ApiError('E04', t('error.sku or refCode not found'))
744
+ }
745
+ let existingIndex = acc.findIndex(
746
+ itm =>
747
+ itm?.sku == sku?.trim() &&
748
+ itm?.refCode == refCode?.trim() &&
749
+ itm?.packingType == packingType?.trim() &&
750
+ itm?.packingSize == packingSize &&
751
+ itm?.batchId == batchId?.trim() &&
752
+ itm?.uom == uom?.trim()
753
+ )
754
+
755
+ if (existingIndex >= 0 && releaseQty > 0) {
756
+ acc[existingIndex].releaseQty = acc[existingIndex].releaseQty + releaseQty
757
+ acc[existingIndex].releaseUomValue =
758
+ acc[existingIndex].releaseUomValue + releaseQty * (productDetail.uomValue <= 0 ? 1 : productDetail.uomValue)
759
+ } else {
760
+ let updateObj = {
761
+ sku: sku?.trim(),
762
+ packingType: packingType?.trim(),
763
+ packingSize: packingSize,
764
+ uom: uom?.trim(),
765
+ releaseQty: releaseQty,
766
+ releaseUomValue: releaseQty * (productDetail.uomValue <= 0 ? 1 : productDetail.uomValue),
767
+ product,
768
+ productDetail
769
+ }
770
+
771
+ if (refCode) updateObj['refCode'] = refCode.trim()
772
+ updateObj['batchId'] = batchId ? batchId?.trim() : '-'
773
+
774
+ acc.push(updateObj)
775
+ }
776
+ })
777
+ return acc
778
+ }, [])
779
+
780
+ return { orderProducts, combinedItems }
781
+ } catch (error) {
782
+ if (error instanceof ApiError) ApiErrorHandler(context, error)
783
+ else throwInternalServerError(context, error)
784
+ }
785
+ }
786
+
787
+ async function assignToInventory(orderProducts: OrderProduct[], customerBizplace, context, tx) {
788
+ const { client, domain, user } = context.state
789
+ for (let opIdx = 0; opIdx < orderProducts.length; opIdx++) {
790
+ let orderProduct = orderProducts[opIdx]
791
+
792
+ let assignedOrderInventories = []
793
+ const pickingProductSetting: Setting = await tx.getRepository(Setting).findOne({
794
+ where: { domain, name: 'rule-for-picking-product' }
795
+ })
796
+
797
+ for (let oiIdx = 0; oiIdx < orderProducts[opIdx].orderInventories.length; oiIdx++) {
798
+ const orderInventory = orderProduct.orderInventories[oiIdx]
799
+ let sortings: any = []
800
+
801
+ switch (orderInventory.product.pickingStrategy) {
802
+ case 'LIFO':
803
+ sortings.push({ name: 'iv.created_at', desc: true })
804
+ if (pickingProductSetting?.value) {
805
+ for (const [key, value] of Object.entries(JSON.parse(pickingProductSetting.value))) {
806
+ sortings.push({ name: `loc.${key}`, desc: value == 'DESC' ? true : false })
807
+ }
808
+ } else {
809
+ sortings.push({ name: 'loc.name', desc: false }, { name: 'iv.created_at', desc: false })
810
+ }
811
+
812
+ break
813
+ case 'FEFO':
814
+ sortings.push({ name: 'iv.expiration_date', desc: false }, { name: 'iv.created_at', desc: false })
815
+ if (pickingProductSetting?.value) {
816
+ for (const [key, value] of Object.entries(JSON.parse(pickingProductSetting.value))) {
817
+ sortings.push({ name: `loc.${key}`, desc: value == 'DESC' ? true : false })
818
+ }
819
+ } else {
820
+ sortings.push({ name: 'loc.name', desc: false }, { name: 'iv.created_at', desc: false })
821
+ }
822
+
823
+ break
824
+ case 'FMFO':
825
+ sortings.push({ name: 'iv.manufacture_date', desc: false }, { name: 'iv.created_at', desc: false })
826
+ if (pickingProductSetting?.value) {
827
+ for (const [key, value] of Object.entries(JSON.parse(pickingProductSetting.value))) {
828
+ sortings.push({ name: `loc.${key}`, desc: value == 'DESC' ? true : false })
829
+ }
830
+ } else {
831
+ sortings.push({ name: 'loc.name', desc: false }, { name: 'iv.created_at', desc: false })
832
+ }
833
+
834
+ break
835
+ case 'LOCATION':
836
+ if (pickingProductSetting?.value) {
837
+ for (const [key, value] of Object.entries(JSON.parse(pickingProductSetting.value))) {
838
+ sortings.push({ name: `loc.${key}`, desc: value == 'DESC' ? true : false })
839
+ }
840
+ } else {
841
+ sortings.push({ name: 'loc.name', desc: false }, { name: 'iv.created_at', desc: false })
842
+ }
843
+
844
+ break
845
+ //Every other case includes 'FIFO' will be applicable for this case
846
+ default:
847
+ sortings.push({ name: 'iv.created_at', desc: false })
848
+ if (pickingProductSetting?.value) {
849
+ for (const [key, value] of Object.entries(JSON.parse(pickingProductSetting.value))) {
850
+ sortings.push({ name: `loc.${key}`, desc: value == 'DESC' ? true : false })
851
+ }
852
+ } else {
853
+ sortings.push({ name: 'loc.name', desc: false })
854
+ sortings.push({ name: 'iv.pallet_id', desc: false })
855
+ }
856
+ break
857
+ }
858
+
859
+ let queryFilters = []
860
+
861
+ let queryStrings = queryFilters.reduce(
862
+ (acc, itm, idx, arr) => {
863
+ acc.values.push(itm.filters)
864
+
865
+ switch (itm?.operator) {
866
+ case 'notin':
867
+ case 'in':
868
+ acc.query.push(
869
+ `${itm.query} ${itm.operator == 'notin' ? 'NOT IN' : 'IN'} (${itm.filtes
870
+ .map((itm, idx) => {
871
+ return `$${acc.values.length + 1}`
872
+ })
873
+ .join(',')})`
874
+ )
875
+ break
876
+
877
+ default:
878
+ acc.query.push(`${itm.query} ${itm?.operator ? itm.operator : '='} $${acc.values.length + 1}`)
879
+ break
880
+ }
881
+ acc.query.push(`${itm.query} ${itm?.operator ? itm.operator : '='} $${acc.values.length + 1}`)
882
+ },
883
+ {
884
+ query: [],
885
+ values: []
886
+ }
887
+ )
888
+
889
+ let sortQuery = sortings
890
+ .map(itm => {
891
+ return `${itm.name} ${itm.desc ? 'DESC' : 'ASC'}`
892
+ })
893
+ .join(`,`)
894
+
895
+ let updatedInventories = await tx.getRepository(Inventory).query(
896
+ `
897
+ update inventories tgt set locked_qty = coalesce(locked_qty,0) + src.reserve_qty,
898
+ locked_uom_value = coalesce(locked_uom_value,0) + src.reserve_uom_value,
899
+ updated_at = NOW(),
900
+ updater_id = $1
901
+ from (
902
+ select "id", "pallet_id","carton_id", "batch_id", "batch_id_ref", "unit", "uom", "packing_type", "packing_size", "manufacture_year",
903
+ "reserve_qty", (("uom_value"/"qty") * "reserve_qty") as "reserve_uom_value" from (
904
+ select "sort_seq", "id", "pallet_id", "batch_id", "batch_id_ref", "unit", "uom", "packing_type", "packing_size", "manufacture_year", "carton_id", "uom_value", "locked_uom_value", "qty", "locked_qty", "created_at",
905
+ "release_qty", "release_uom_value", lock_amount,
906
+ case when "lock_amount" < 0 then "available_qty" else "available_qty" - "lock_amount" end as "reserve_qty"
907
+ from (
908
+ select *,
909
+ qty - locked_qty as available_qty,
910
+ sum(qty - locked_qty - release_qty) over (order by sort_seq asc rows between unbounded preceding and current row) as lock_amount
911
+ from (
912
+ SELECT 0 as sort_seq, null as id, null as pallet_id, null as batch_id, null as batch_id_ref,
913
+ null as unit, '${orderInventory.uom}' as uom, '${orderInventory.packingType}' as packing_type, '${
914
+ orderInventory.packingSize
915
+ }' as packing_size,
916
+ null as manufacture_year, null as carton_id, 0 as uom_value, 0 as locked_uom_value, 0 as qty, 0 as locked_qty, null as created_at,
917
+ '${orderInventory.releaseQty}' as release_qty, '${orderInventory.releaseUomValue}' as release_uom_value
918
+ UNION
919
+ (
920
+ SELECT ROW_NUMBER() OVER(PARTITION BY iv.domain_id ORDER BY ${sortQuery}) as sort_seq,
921
+ iv.id, iv.pallet_id, iv.batch_id, iv.batch_id_ref,
922
+ iv.unit, iv.uom, iv.packing_type, iv.packing_size,
923
+ iv.manufacture_year, iv.carton_id, iv.uom_value,
924
+ coalesce(iv.locked_uom_value,0) as locked_uom_value, iv.qty, coalesce(iv.locked_qty,0) as locked_qty, iv.created_at,
925
+ 0 as release_qty, 0 as release_uom_value
926
+ FROM "inventories" "iv"
927
+ INNER JOIN "locations" "loc" ON "loc"."id"="iv"."location_id"
928
+ WHERE case when coalesce("iv"."locked_qty",0) < 0 then 0 else ("iv"."qty" - coalesce("iv"."locked_qty",0)) end > 0 AND
929
+ "iv"."domain_id" = $2 AND "iv"."bizplace_id" = $3 AND "iv"."packing_type" = $4 AND "iv"."packing_size" = $5 AND "iv"."product_id" = $6 AND "iv"."status" = $7 AND "loc"."type" NOT IN ($8, $9)
930
+ ${queryStrings.query.length > 0 ? `AND ${queryStrings.join(' AND ')}` : ''}
931
+ ORDER BY ${sortQuery}
932
+ )
933
+ ) dt1
934
+ ) dt2 where case when "lock_amount" < 0 then "available_qty" else "available_qty" - "lock_amount" end > 0
935
+ ) dt3 where sort_seq > 0
936
+ ) src where src.id = tgt.id
937
+ returning
938
+ tgt."id", tgt."qty", tgt."pallet_id", tgt."carton_id", tgt."batch_id", tgt."batch_id_ref", tgt."unit",
939
+ tgt."uom", tgt."packing_type", tgt."packing_size", tgt."manufacture_year",
940
+ tgt."locked_qty", tgt."uom_value", tgt."locked_uom_value", src."reserve_qty", src."reserve_uom_value";`,
941
+ [
942
+ user.id,
943
+ domain.id,
944
+ customerBizplace.id,
945
+ orderInventory.packingType,
946
+ orderInventory.packingSize,
947
+ orderInventory.product.id,
948
+ INVENTORY_STATUS.STORED,
949
+ LOCATION_TYPE.QUARANTINE,
950
+ LOCATION_TYPE.RESERVE,
951
+ ...queryStrings.values
952
+ ]
953
+ )
954
+
955
+ let totalAssigned = updatedInventories[0].reduce((acc, inv) => {
956
+ return acc + inv.reserve_qty
957
+ }, 0)
958
+
959
+ if (orderInventory.releaseQty != totalAssigned) {
960
+ throw new ApiError(
961
+ 'E01',
962
+ `insufficient stock:
963
+ ${JSON.stringify({
964
+ code: 'insufficient stock',
965
+ sku: orderInventory.product.sku,
966
+ packingType: orderInventory.packingType,
967
+ packingSize: orderInventory.packingSize,
968
+ uom: orderInventory.uom,
969
+ qty: orderInventory.releaseQty,
970
+ uom_value: orderInventory.releaseUomValue
971
+ })}`
972
+ )
973
+ }
974
+
975
+ updatedInventories[0].forEach(inv => {
976
+ let oi = {
977
+ ...orderInventory,
978
+ inventory: { id: inv.id },
979
+ uom: inv.uom,
980
+ packingType: inv.packing_type,
981
+ batchId: inv.batch_id,
982
+ releaseQty: inv.reserve_qty,
983
+ releaseUomValue: inv.reserve_uom_value,
984
+ pickedQty: 0,
985
+ packedQty: 0,
986
+ type: ORDER_TYPES.RELEASE_OF_GOODS,
987
+ status: ORDER_INVENTORY_STATUS.PENDING_WORKSHEET,
988
+ domain: { id: domain.id },
989
+ bizplace: { id: customerBizplace.id }
990
+ }
991
+
992
+ assignedOrderInventories.push(oi)
993
+ })
994
+ }
995
+
996
+ orderProducts[opIdx].orderInventories = assignedOrderInventories
997
+ }
998
+
999
+ return orderProducts
1000
+ }