@things-factory/sales-base 8.0.0-beta.0 → 8.0.0-beta.2

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 (177) hide show
  1. package/package.json +13 -13
  2. package/server/constants/attachment-type.ts +0 -9
  3. package/server/constants/index.ts +0 -7
  4. package/server/constants/load-type.ts +0 -4
  5. package/server/constants/order.ts +0 -203
  6. package/server/constants/product-group-type.ts +0 -4
  7. package/server/constants/release-good.ts +0 -9
  8. package/server/constants/transfer-order-type.ts +0 -6
  9. package/server/constants/validation-error-code.ts +0 -3
  10. package/server/constants/vas-target-type.ts +0 -25
  11. package/server/controllers/ecommerce/ecommerce-controller.ts +0 -122
  12. package/server/controllers/ecommerce/index.ts +0 -2
  13. package/server/controllers/ecommerce/sellercraft-controller.ts +0 -182
  14. package/server/controllers/index.ts +0 -2
  15. package/server/controllers/order-controller.ts +0 -296
  16. package/server/errors/index.ts +0 -1
  17. package/server/errors/validation-error.ts +0 -25
  18. package/server/index.ts +0 -5
  19. package/server/migrations/index.ts +0 -9
  20. package/server/service/arrival-notice/arrival-notice-mutation.ts +0 -1152
  21. package/server/service/arrival-notice/arrival-notice-query.ts +0 -549
  22. package/server/service/arrival-notice/arrival-notice-types.ts +0 -310
  23. package/server/service/arrival-notice/arrival-notice.ts +0 -202
  24. package/server/service/arrival-notice/index.ts +0 -9
  25. package/server/service/claim/claim-mutation.ts +0 -308
  26. package/server/service/claim/claim-query.ts +0 -122
  27. package/server/service/claim/claim-types.ts +0 -130
  28. package/server/service/claim/claim.ts +0 -140
  29. package/server/service/claim/index.ts +0 -9
  30. package/server/service/claim-detail/claim-detail-mutation.ts +0 -102
  31. package/server/service/claim-detail/claim-detail-query.ts +0 -55
  32. package/server/service/claim-detail/claim-detail-types.ts +0 -47
  33. package/server/service/claim-detail/claim-detail.ts +0 -69
  34. package/server/service/claim-detail/index.ts +0 -9
  35. package/server/service/claim-order/claim-order-mutation.ts +0 -101
  36. package/server/service/claim-order/claim-order-query.ts +0 -47
  37. package/server/service/claim-order/claim-order-types.ts +0 -35
  38. package/server/service/claim-order/claim-order.ts +0 -81
  39. package/server/service/claim-order/index.ts +0 -9
  40. package/server/service/collection-order/collection-order-mutation.ts +0 -245
  41. package/server/service/collection-order/collection-order-query.ts +0 -97
  42. package/server/service/collection-order/collection-order-types.ts +0 -165
  43. package/server/service/collection-order/collection-order.ts +0 -135
  44. package/server/service/collection-order/index.ts +0 -9
  45. package/server/service/delivery-order/delivery-order-mutation.ts +0 -967
  46. package/server/service/delivery-order/delivery-order-query.ts +0 -631
  47. package/server/service/delivery-order/delivery-order-types.ts +0 -268
  48. package/server/service/delivery-order/delivery-order.ts +0 -258
  49. package/server/service/delivery-order/index.ts +0 -9
  50. package/server/service/draft-release-good/draft-release-good-mutation.ts +0 -765
  51. package/server/service/draft-release-good/draft-release-good-query.ts +0 -354
  52. package/server/service/draft-release-good/draft-release-good-type.ts +0 -261
  53. package/server/service/draft-release-good/draft-release-good.ts +0 -284
  54. package/server/service/draft-release-good/index.ts +0 -9
  55. package/server/service/goods-receival-note/goods-receival-note-mutation.ts +0 -129
  56. package/server/service/goods-receival-note/goods-receival-note-query.ts +0 -280
  57. package/server/service/goods-receival-note/goods-receival-note-types.ts +0 -105
  58. package/server/service/goods-receival-note/goods-receival-note.ts +0 -127
  59. package/server/service/goods-receival-note/index.ts +0 -9
  60. package/server/service/index.ts +0 -238
  61. package/server/service/inventory-check/index.ts +0 -9
  62. package/server/service/inventory-check/inventory-check-mutation.ts +0 -149
  63. package/server/service/inventory-check/inventory-check-query.ts +0 -48
  64. package/server/service/inventory-check/inventory-check-types.ts +0 -48
  65. package/server/service/inventory-check/inventory-check.ts +0 -90
  66. package/server/service/invoice/index.ts +0 -9
  67. package/server/service/invoice/invoice-mutation.ts +0 -95
  68. package/server/service/invoice/invoice-query.ts +0 -53
  69. package/server/service/invoice/invoice-types.ts +0 -279
  70. package/server/service/invoice/invoice.ts +0 -230
  71. package/server/service/invoice-product/index.ts +0 -9
  72. package/server/service/invoice-product/invoice-product-mutation.ts +0 -54
  73. package/server/service/invoice-product/invoice-product-query.ts +0 -54
  74. package/server/service/invoice-product/invoice-product-types.ts +0 -84
  75. package/server/service/invoice-product/invoice-product.ts +0 -92
  76. package/server/service/job-sheet/index.ts +0 -9
  77. package/server/service/job-sheet/job-sheet-mutation.ts +0 -92
  78. package/server/service/job-sheet/job-sheet-query.ts +0 -112
  79. package/server/service/job-sheet/job-sheet-types.ts +0 -78
  80. package/server/service/job-sheet/job-sheet.ts +0 -102
  81. package/server/service/manifest/index.ts +0 -6
  82. package/server/service/manifest/manifest-mutation.ts +0 -190
  83. package/server/service/manifest/manifest-query.ts +0 -149
  84. package/server/service/manifest/manifest-type.ts +0 -84
  85. package/server/service/manifest/manifest.ts +0 -114
  86. package/server/service/order-inventory/index.ts +0 -9
  87. package/server/service/order-inventory/order-inventory-mutation.ts +0 -54
  88. package/server/service/order-inventory/order-inventory-query.ts +0 -722
  89. package/server/service/order-inventory/order-inventory-types.ts +0 -238
  90. package/server/service/order-inventory/order-inventory.ts +0 -401
  91. package/server/service/order-product/index.ts +0 -9
  92. package/server/service/order-product/order-product-mutation.ts +0 -48
  93. package/server/service/order-product/order-product-query.ts +0 -89
  94. package/server/service/order-product/order-product-types.ts +0 -335
  95. package/server/service/order-product/order-product.ts +0 -362
  96. package/server/service/order-tote/index.ts +0 -9
  97. package/server/service/order-tote/order-tote-mutation.ts +0 -31
  98. package/server/service/order-tote/order-tote-query.ts +0 -112
  99. package/server/service/order-tote/order-tote-types.ts +0 -47
  100. package/server/service/order-tote/order-tote.ts +0 -73
  101. package/server/service/order-tote-item/index.ts +0 -9
  102. package/server/service/order-tote-item/order-tote-item-mutation.ts +0 -31
  103. package/server/service/order-tote-item/order-tote-item-query.ts +0 -82
  104. package/server/service/order-tote-item/order-tote-item-types.ts +0 -56
  105. package/server/service/order-tote-item/order-tote-item.ts +0 -72
  106. package/server/service/order-tote-seal/index.ts +0 -9
  107. package/server/service/order-tote-seal/order-tote-seal-mutation.ts +0 -31
  108. package/server/service/order-tote-seal/order-tote-seal-query.ts +0 -59
  109. package/server/service/order-tote-seal/order-tote-seal-types.ts +0 -41
  110. package/server/service/order-tote-seal/order-tote-seal.ts +0 -46
  111. package/server/service/order-vas/index.ts +0 -9
  112. package/server/service/order-vas/order-vas-mutation.ts +0 -20
  113. package/server/service/order-vas/order-vas-query.ts +0 -72
  114. package/server/service/order-vas/order-vas-types.ts +0 -159
  115. package/server/service/order-vas/order-vas.ts +0 -207
  116. package/server/service/others/index.ts +0 -5
  117. package/server/service/others/other-query.ts +0 -563
  118. package/server/service/others/other-types.ts +0 -115
  119. package/server/service/purchase-order/index.ts +0 -9
  120. package/server/service/purchase-order/purchase-order-mutation.ts +0 -458
  121. package/server/service/purchase-order/purchase-order-query.ts +0 -90
  122. package/server/service/purchase-order/purchase-order-types.ts +0 -154
  123. package/server/service/purchase-order/purchase-order.ts +0 -172
  124. package/server/service/purchase-order-other-charge/index.ts +0 -9
  125. package/server/service/purchase-order-other-charge/purchase-order-other-charge-mutation.ts +0 -31
  126. package/server/service/purchase-order-other-charge/purchase-order-other-charge-query.ts +0 -52
  127. package/server/service/purchase-order-other-charge/purchase-order-other-charge-types.ts +0 -44
  128. package/server/service/purchase-order-other-charge/purchase-order-other-charge.ts +0 -68
  129. package/server/service/release-good/index.ts +0 -9
  130. package/server/service/release-good/release-good-mutation.ts +0 -1686
  131. package/server/service/release-good/release-good-query.ts +0 -980
  132. package/server/service/release-good/release-good-types.ts +0 -662
  133. package/server/service/release-good/release-good.ts +0 -490
  134. package/server/service/retail-replenishment-order/index.ts +0 -9
  135. package/server/service/retail-replenishment-order/retail-replenishment-order-mutation.ts +0 -382
  136. package/server/service/retail-replenishment-order/retail-replenishment-order-query.ts +0 -54
  137. package/server/service/retail-replenishment-order/retail-replenishment-order-types.ts +0 -101
  138. package/server/service/retail-replenishment-order/retail-replenishment-order.ts +0 -115
  139. package/server/service/return-order/index.ts +0 -9
  140. package/server/service/return-order/return-order-mutation.ts +0 -516
  141. package/server/service/return-order/return-order-query.ts +0 -226
  142. package/server/service/return-order/return-order-types.ts +0 -196
  143. package/server/service/return-order/return-order.ts +0 -127
  144. package/server/service/reverse-kitting-order/index.ts +0 -9
  145. package/server/service/reverse-kitting-order/reverse-kitting-order-mutation.ts +0 -500
  146. package/server/service/reverse-kitting-order/reverse-kitting-order-query.ts +0 -197
  147. package/server/service/reverse-kitting-order/reverse-kitting-order-type.ts +0 -173
  148. package/server/service/reverse-kitting-order/reverse-kitting-order.ts +0 -121
  149. package/server/service/reverse-kitting-order-inventory/index.ts +0 -9
  150. package/server/service/reverse-kitting-order-inventory/reverse-kitting-order-inventory-mutation.ts +0 -129
  151. package/server/service/reverse-kitting-order-inventory/reverse-kitting-order-inventory-query.ts +0 -52
  152. package/server/service/reverse-kitting-order-inventory/reverse-kitting-order-inventory-type.ts +0 -95
  153. package/server/service/reverse-kitting-order-inventory/reverse-kitting-order-inventory.ts +0 -143
  154. package/server/service/shipping-order/index.ts +0 -9
  155. package/server/service/shipping-order/shipping-order-mutation.ts +0 -61
  156. package/server/service/shipping-order/shipping-order-query.ts +0 -61
  157. package/server/service/shipping-order/shipping-order-types.ts +0 -89
  158. package/server/service/shipping-order/shipping-order.ts +0 -129
  159. package/server/service/transfer-order/index.ts +0 -9
  160. package/server/service/transfer-order/transfer-order-mutation.ts +0 -309
  161. package/server/service/transfer-order/transfer-order-query.ts +0 -66
  162. package/server/service/transfer-order/transfer-order-types.ts +0 -97
  163. package/server/service/transfer-order/transfer-order.ts +0 -117
  164. package/server/service/vas/index.ts +0 -9
  165. package/server/service/vas/vas-mutation.ts +0 -106
  166. package/server/service/vas/vas-query.ts +0 -60
  167. package/server/service/vas/vas-types.ts +0 -71
  168. package/server/service/vas/vas.ts +0 -77
  169. package/server/service/vas-order/index.ts +0 -9
  170. package/server/service/vas-order/vas-order-mutation.ts +0 -259
  171. package/server/service/vas-order/vas-order-query.ts +0 -119
  172. package/server/service/vas-order/vas-order-types.ts +0 -49
  173. package/server/service/vas-order/vas-order.ts +0 -81
  174. package/server/utils/datetime-util.ts +0 -54
  175. package/server/utils/index.ts +0 -3
  176. package/server/utils/inventory-util.ts +0 -1155
  177. package/server/utils/order-no-generator.ts +0 -146
@@ -1,1686 +0,0 @@
1
- import type { FileUpload } from 'graphql-upload/GraphQLUpload.js'
2
- import GraphQLUpload from 'graphql-upload/GraphQLUpload.js'
3
- import { Arg, Ctx, Directive, Mutation, Resolver } from 'type-graphql'
4
- import { EntityManager, getConnection, In, Not, Repository } from 'typeorm'
5
-
6
- import { Attachment, createAttachments } from '@things-factory/attachment-base'
7
- import { ApplicationType, Partner, Role, User } from '@things-factory/auth-base'
8
- import {
9
- Bizplace,
10
- ContactPoint,
11
- getDomainUsers,
12
- getMyBizplace,
13
- getOutletBizplace,
14
- getPermittedBizplaces
15
- } from '@things-factory/biz-base'
16
- import { logger } from '@things-factory/env'
17
- import { generateId } from '@things-factory/id-rule-base'
18
- import { MarketplaceStore } from '@things-factory/integration-marketplace'
19
- import { Sellercraft, SellercraftStatus } from '@things-factory/integration-sellercraft'
20
- import { MarketplaceOrder, MarketplaceProductVariation } from '@things-factory/marketplace-base'
21
- import { Product, ProductBundleSetting } from '@things-factory/product-base'
22
- import { PartnerSetting, Setting } from '@things-factory/setting-base'
23
- import { Domain, getRepository } from '@things-factory/shell'
24
- import { Inventory } from '@things-factory/warehouse-base'
25
-
26
- // import { NewOrderProduct } from '../order-product/order-product-types'
27
- import {
28
- ATTACHMENT_TYPE,
29
- ORDER_INVENTORY_STATUS,
30
- ORDER_METHOD,
31
- ORDER_NUMBER_RULE_TYPE,
32
- ORDER_NUMBER_SETTING_KEY,
33
- ORDER_PRODUCT_STATUS,
34
- ORDER_STATUS,
35
- ORDER_TYPES,
36
- ORDER_VAS_STATUS,
37
- PRODUCT_GROUP_TYPE
38
- } from '../../constants'
39
- import { EcommerceController, SellercraftController } from '../../controllers'
40
- import { ValidationError } from '../../errors'
41
- import { InventoryUtil, OrderNoGenerator } from '../../utils'
42
- import { ArrivalNotice } from '../arrival-notice/arrival-notice'
43
- import { confirmArrivalNoticeFunction, deleteArrivalNotice } from '../arrival-notice/arrival-notice-mutation'
44
- import { OrderInventory } from '../order-inventory/order-inventory'
45
- import { OrderProduct } from '../order-product/order-product'
46
- import { OrderVas } from '../order-vas/order-vas'
47
- import { NewReleaseGood, ReleaseGoodPatch, ShippingOrderInfoPatch } from '../release-good/release-good-types'
48
- import { ShippingOrder } from '../shipping-order/shipping-order'
49
- import { ShippingOrderPatch } from '../shipping-order/shipping-order-types'
50
- import { Vas } from '../vas/vas'
51
- import { ReleaseGood } from './release-good'
52
- import { bulkReleaseGoodsAvailableItemsFunction } from './release-good-query'
53
-
54
- @Resolver(ReleaseGood)
55
- export class ReleaseGoodMutation {
56
- @Directive('@privilege(category: "order_customer", privilege: "mutation")')
57
- @Directive('@transaction')
58
- @Mutation(returns => [ReleaseGood])
59
- async bulkAddReleaseGoods(
60
- @Ctx() context: ResolverContext,
61
- @Arg('rawReleaseGoods', type => [NewReleaseGood], { nullable: true }) rawReleaseGoods: NewReleaseGood[],
62
- @Arg('bizplaceId', type => String) bizplaceId: string
63
- ): Promise<ReleaseGood[]> {
64
- const { domain, user, tx } = context.state
65
-
66
- if (!bizplaceId) throw new Error('company ID is not provided')
67
-
68
- let createdReleaseGoods: ReleaseGood[] = []
69
- const settingRepo: Repository<Setting> = tx?.getRepository(Setting) || getRepository(Setting)
70
-
71
- const roNoSetting: Setting = await settingRepo.findOne({
72
- where: {
73
- domain: { id: domain.id },
74
- name: ORDER_NUMBER_SETTING_KEY.RO_NUMBER_RULE
75
- }
76
- })
77
-
78
- let releaseGoods: Partial<ReleaseGood[]> = extractRawReleaseGoods(rawReleaseGoods)
79
-
80
- let errorsCaught: any[] = []
81
- for (let i = 0, l = releaseGoods.length; i < l; i++) {
82
- // generate release good by group to avoid duplication
83
- // if this function is called simultaneously by different users
84
- try {
85
- await getConnection().transaction(async (childTx: EntityManager) => {
86
- const existingReleaseGood: ReleaseGood = await childTx.getRepository(ReleaseGood).findOne({
87
- where: {
88
- ...Object.fromEntries(
89
- Object.entries(releaseGoods[i]).filter(([_, val]) => !/^\s*$/.test(val) && _ != 'orderInventories')
90
- ),
91
- domain: { id: domain.id }
92
- }
93
- })
94
- if (existingReleaseGood) throw new Error('this order is already exist in the system')
95
-
96
- let availableItems: any[] = await bulkReleaseGoodsAvailableItemsFunction(
97
- [...releaseGoods[i].orderInventories],
98
- bizplaceId,
99
- context,
100
- childTx
101
- )
102
-
103
- if (availableItems.some(item => !item.releaseQty || item.releaseQty > item.assignedQty))
104
- throw new ValidationError({
105
- ...ValidationError.ERROR_CODES.INSUFFICIENT_STOCK,
106
- detail: { data: JSON.stringify(availableItems) }
107
- })
108
-
109
- // update orderInventories if availableItems are valid
110
- releaseGoods[i].orderInventories = availableItems
111
-
112
- const createdReleaseGood: ReleaseGood = await bulkGenerateReleaseGood(
113
- releaseGoods[i],
114
- bizplaceId,
115
- roNoSetting,
116
- domain,
117
- user,
118
- childTx
119
- )
120
-
121
- createdReleaseGoods.push(createdReleaseGood)
122
- })
123
- } catch (error) {
124
- let rawReleaseGoods = formRawReleaseGoods(releaseGoods[i], error.message)
125
- errorsCaught.push(...rawReleaseGoods)
126
- }
127
- }
128
-
129
- let confirmedReleaseGoods: ReleaseGood[] = []
130
-
131
- if (createdReleaseGoods.length)
132
- try {
133
- confirmedReleaseGoods = await bulkConfirmReleaseGoods(
134
- createdReleaseGoods.map(rg => rg.name),
135
- domain,
136
- user,
137
- context,
138
- tx
139
- )
140
- } catch (error) {}
141
-
142
- if (errorsCaught.length)
143
- throw new ValidationError({
144
- ...ValidationError.ERROR_CODES.INVALID_DATA_FOUND,
145
- detail: { data: JSON.stringify(errorsCaught) }
146
- })
147
-
148
- return confirmedReleaseGoods
149
- }
150
-
151
- @Directive('@privilege(category: "order_customer", privilege: "mutation")')
152
- @Directive('@transaction')
153
- @Mutation(returns => Boolean)
154
- async deleteReleaseGood(@Arg('name') name: string, @Ctx() context: ResolverContext): Promise<Boolean> {
155
- const { tx, user, domain } = context.state
156
- return await deleteReleaseGood(tx, name, user, domain)
157
- }
158
-
159
- @Directive('@privilege(category: "order_customer", privilege: "mutation")')
160
- @Directive('@transaction')
161
- @Mutation(returns => Boolean)
162
- async deleteReleaseGoods(
163
- @Arg('names', type => [String]) names: string[],
164
- @Ctx() context: ResolverContext
165
- ): Promise<Boolean> {
166
- const { tx } = context.state
167
- await tx.getRepository(ReleaseGood).delete({
168
- domain: { id: context.state.domain.id },
169
- name: In(names)
170
- })
171
- return true
172
- }
173
-
174
- @Directive('@privilege(category: "order_customer", privilege: "mutation")')
175
- @Directive('@transaction')
176
- @Mutation(returns => ReleaseGood)
177
- async generateReleaseGood(
178
- @Ctx() context: ResolverContext,
179
- @Arg('attachments', type => [GraphQLUpload], { nullable: true }) attachments?: FileUpload[],
180
- @Arg('releaseGood', type => NewReleaseGood, { nullable: true }) releaseGood?: NewReleaseGood,
181
- @Arg('shippingOrder', type => ShippingOrderPatch, { nullable: true }) shippingOrder?: ShippingOrderPatch,
182
- @Arg('shippingOrderInfo', type => ShippingOrderInfoPatch, { nullable: true })
183
- shippingOrderInfo?: ShippingOrderInfoPatch
184
- ): Promise<ReleaseGood> {
185
- const { tx } = context.state
186
- const createdReleaseGood: ReleaseGood = await generateReleaseGoodFunction(
187
- null,
188
- releaseGood,
189
- shippingOrder,
190
- shippingOrderInfo,
191
- attachments,
192
- context,
193
- tx
194
- )
195
-
196
- return createdReleaseGood
197
- }
198
-
199
- @Directive('@privilege(category: "order_customer", privilege: "mutation")')
200
- @Directive('@transaction')
201
- @Mutation(returns => ReleaseGood)
202
- async updateReleaseGoodDetails(
203
- @Ctx() context: ResolverContext,
204
- @Arg('releaseGood', type => ReleaseGoodPatch, { nullable: true }) releaseGood?: ReleaseGoodPatch,
205
- @Arg('shippingOrder', type => ShippingOrderPatch, { nullable: true }) shippingOrder?: ShippingOrderPatch,
206
- @Arg('shippingOrderInfo', type => ShippingOrderInfoPatch, { nullable: true })
207
- shippingOrderInfo?: ShippingOrderInfoPatch
208
- ): Promise<ReleaseGood> {
209
- const { tx, domain, user } = context.state
210
- let foundReleaseGood = await tx.getRepository(ReleaseGood).findOne({
211
- where: { id: releaseGood.id, domain: { id: domain.id } },
212
- relations: ['shippingOrder']
213
- })
214
-
215
- if (!foundReleaseGood) {
216
- throw new Error(`Release order ${releaseGood.id} is not found.`)
217
- }
218
-
219
- // case to update existing shippingOrder
220
- if (shippingOrder !== null) {
221
- shippingOrder.remark = shippingOrder.exportRemark
222
- shippingOrder.containerClosureDateTime = new Date(shippingOrder.containerClosureDate)
223
- delete shippingOrder.exportRemark
224
- }
225
-
226
- if (foundReleaseGood.shippingOrder && shippingOrder) {
227
- await tx.getRepository(ShippingOrder).update(foundReleaseGood.shippingOrder.id, shippingOrder)
228
- }
229
- // case for new shippingOrder
230
- else if (!foundReleaseGood.shippingOrder && shippingOrder) {
231
- let newShippingOrder: ShippingOrder = await tx.getRepository(ShippingOrder).save({
232
- ...shippingOrder,
233
- name: OrderNoGenerator.shippingOrder(),
234
- domain,
235
- bizplace: await getMyBizplace(domain, user),
236
- status: ORDER_STATUS.PENDING,
237
- creator: user,
238
- updater: user
239
- })
240
-
241
- releaseGood.shippingOrder = newShippingOrder
242
- }
243
-
244
- foundReleaseGood = await tx.getRepository(ReleaseGood).save({
245
- ...(foundReleaseGood as any),
246
- ...releaseGood,
247
- ...shippingOrderInfo,
248
- remark: releaseGood?.remark ? releaseGood.remark : null
249
- })
250
-
251
- return foundReleaseGood
252
- }
253
-
254
- @Directive('@privilege(category: "order_customer", privilege: "mutation")')
255
- @Directive('@transaction')
256
- @Mutation(returns => ReleaseGood)
257
- async confirmReleaseGood(@Arg('name') name: string, @Ctx() context: ResolverContext): Promise<ReleaseGood> {
258
- const { tx } = context.state
259
- const releaseGood: ReleaseGood = await confirmReleaseGood(name, context, tx)
260
-
261
- // If current RO has cross docking
262
- if (releaseGood.crossDocking) {
263
- const { arrivalNotice } = await tx.getRepository(ReleaseGood).findOne({
264
- where: { id: releaseGood.id },
265
- relations: ['arrivalNotice']
266
- })
267
-
268
- // If status of related GAN is not equal to PENDING_RECEIVE (i.e. Wasn't confirmed yet.)
269
- if (arrivalNotice.status !== ORDER_STATUS.PENDING_RECEIVE) {
270
- await confirmArrivalNoticeFunction(arrivalNotice.name, context, tx)
271
- }
272
- }
273
-
274
- return releaseGood
275
- }
276
-
277
- @Directive('@privilege(category: "order_customer", privilege: "mutation")')
278
- @Directive('@transaction')
279
- @Mutation(returns => ReleaseGood)
280
- async receiveReleaseGood(@Arg('name') name: string, @Ctx() context: ResolverContext): Promise<ReleaseGood> {
281
- const { tx } = context.state
282
- const releaseGood: ReleaseGood = await receiveReleaseGood(name, context, tx)
283
- return releaseGood
284
- }
285
-
286
- @Directive('@privilege(category: "order_warehouse", privilege: "mutation")')
287
- @Directive('@transaction')
288
- @Mutation(returns => ReleaseGood)
289
- async rejectReleaseGood(
290
- @Arg('name') name: string,
291
- @Arg('patch', type => ReleaseGoodPatch) patch: ReleaseGoodPatch,
292
- @Ctx() context: ResolverContext
293
- ): Promise<ReleaseGood> {
294
- const { tx } = context.state
295
-
296
- return await rejectReleaseGood(tx, context, name, patch.remark)
297
- }
298
-
299
- @Directive('@transaction')
300
- @Mutation(returns => ReleaseGood)
301
- async addReleaseGood(
302
- @Ctx() context: ResolverContext,
303
- @Arg('releaseGood', type => NewReleaseGood, { nullable: true }) releaseGood: NewReleaseGood,
304
- @Arg('shippingOrder', type => ShippingOrderPatch, { nullable: true }) shippingOrder: ShippingOrderPatch,
305
- @Arg('file', type => GraphQLUpload, { nullable: true }) file: FileUpload
306
- ): Promise<ReleaseGood> {
307
- const { tx } = context.state
308
- const createdRO: ReleaseGood = await generateReleaseGoodFunction(
309
- null,
310
- releaseGood,
311
- shippingOrder,
312
- null,
313
- file,
314
- context,
315
- tx
316
- )
317
-
318
- const confirmedRO: ReleaseGood = await confirmReleaseGood(createdRO.name, context, tx)
319
-
320
- const receivedRO: ReleaseGood = await receiveReleaseGood(confirmedRO.name, context, tx)
321
-
322
- return receivedRO
323
- }
324
-
325
- @Directive('@privilege(category: "order_customer", privilege: "mutation")')
326
- @Directive('@transaction')
327
- @Mutation(returns => Boolean)
328
- async executeOrderRemark(
329
- @Arg('releaseGoodNo') releaseGoodNo: string,
330
- @Ctx() context: ResolverContext
331
- ): Promise<boolean> {
332
- const { domain, tx, user } = context.state
333
-
334
- await tx.getRepository(ReleaseGood).update(
335
- {
336
- domain: { id: domain.id },
337
- name: releaseGoodNo
338
- },
339
- {
340
- checkedRemarkAt: new Date(),
341
- checkedRemarkUser: user,
342
- checkedRemarkBy: user.name
343
- }
344
- )
345
-
346
- return true
347
- }
348
- }
349
-
350
- export async function deleteReleaseGood(tx: EntityManager, name: string, user: User, domain: Domain): Promise<boolean> {
351
- let foundReleaseOrder: ReleaseGood = await tx.getRepository(ReleaseGood).findOne({
352
- where: { domain: { id: domain.id }, name },
353
- relations: [
354
- 'arrivalNotice',
355
- 'orderInventories',
356
- 'orderInventories.orderProduct',
357
- 'orderInventories.inventory',
358
- 'orderVass',
359
- 'shippingOrder',
360
- 'creator',
361
- 'updater'
362
- ]
363
- })
364
-
365
- if (!foundReleaseOrder) throw new Error(`Release order doesn't exists.`)
366
- const foundOIs: OrderInventory[] = foundReleaseOrder.orderInventories
367
- const foundOVs: OrderVas[] = foundReleaseOrder.orderVass
368
- const foundSO: ShippingOrder = foundReleaseOrder.shippingOrder
369
-
370
- let foundAttachment: Attachment
371
- if (foundReleaseOrder?.ownTransport) {
372
- foundAttachment = await tx.getRepository(Attachment).findOne({
373
- where: {
374
- domain: { id: domain.id },
375
- refBy: foundReleaseOrder.id,
376
- category: ATTACHMENT_TYPE.DELIVERY_ORDER
377
- }
378
- })
379
- }
380
-
381
- // Delete order inventories by ids
382
- await Promise.all(
383
- foundOIs.map(async (oi: OrderInventory) => {
384
- if (oi?.inventory?.id) {
385
- oi.inventory = await tx.getRepository(Inventory).findOneBy({ id: oi.inventory.id })
386
-
387
- await tx.getRepository(Inventory).save({
388
- ...oi.inventory,
389
- lockedQty: oi.inventory.lockedQty - oi.releaseQty,
390
- lockedUomValue: oi.inventory.lockedUomValue - oi.releaseUomValue,
391
- updater: user
392
- })
393
- }
394
-
395
- await tx.getRepository(OrderInventory).delete({ id: oi.id })
396
-
397
- if (oi?.orderProduct?.id) {
398
- await tx.getRepository(OrderProduct).delete({ id: oi.orderProduct.id })
399
- }
400
-
401
- return oi
402
- })
403
- )
404
-
405
- // 2. delete order vass
406
- const vasIds = foundOVs.map((vas: OrderVas) => vas.id)
407
- if (vasIds.length) {
408
- await tx.getRepository(OrderVas).delete({ id: In(vasIds) })
409
- }
410
-
411
- if (foundAttachment) {
412
- await tx.getRepository(Attachment).delete({ domain: { id: domain.id }, id: foundAttachment.id })
413
- }
414
-
415
- // 4. Remove relation with GAN if it's cross docking
416
- if (foundReleaseOrder.crossDocking && foundReleaseOrder.arrivalNotice?.id) {
417
- let arrivalNotice: ArrivalNotice = foundReleaseOrder.arrivalNotice
418
- arrivalNotice.releaseGood = null
419
- arrivalNotice = await tx.getRepository(ArrivalNotice).save(arrivalNotice)
420
-
421
- await tx.getRepository(ReleaseGood).delete({ domain: { id: domain.id }, name })
422
- await deleteArrivalNotice(tx, arrivalNotice.name, user, domain)
423
- } else {
424
- await tx.getRepository(ReleaseGood).delete({ domain: { id: domain.id }, name })
425
- }
426
-
427
- // 5. if there is SO, delete SO
428
- if (foundSO) {
429
- await tx.getRepository(ShippingOrder).delete({ domain: { id: domain.id }, id: foundSO.id })
430
- }
431
- return true
432
- }
433
-
434
- export async function generateReleaseGoodFunction(
435
- _: any,
436
- releaseGood: any,
437
- shippingOrder: ShippingOrderPatch,
438
- shippingOrderInfo: any,
439
- attachments: FileUpload[],
440
- context: ResolverContext,
441
- tx?: EntityManager
442
- ): Promise<ReleaseGood> {
443
- try {
444
- const { domain, user } = context.state
445
- const settingRepo: Repository<Setting> = tx?.getRepository(Setting) || getRepository(Setting)
446
-
447
- // let orderInventories: OrderInventory[] = releaseGood.orderInventories
448
- // let orderVass: OrderVas[] = releaseGood.orderVass
449
-
450
- let { orderInventories, orderVass }: { orderInventories: OrderInventory[]; orderVass: OrderVas[] } = releaseGood
451
-
452
- let bizplace: Bizplace
453
- let warehouseDomain: Domain = domain
454
- let finalOrderInventories: OrderInventory[] = []
455
-
456
- if (releaseGood.deliverTo) {
457
- const deliverTo: ContactPoint = await tx.getRepository(ContactPoint).findOne({
458
- where: { id: releaseGood.deliverTo.id },
459
- relations: ['bizplace']
460
- })
461
-
462
- if (!deliverTo) throw new Error('contact point does not exist')
463
-
464
- releaseGood.deliverTo = deliverTo
465
- }
466
-
467
- /** Validate user permitted Bizplace */
468
- if (releaseGood.warehouseId) {
469
- bizplace = await getOutletBizplace(releaseGood.warehouseId)
470
- } else if (releaseGood.customerBizplaceId) {
471
- const permittedBizplaces: Bizplace[] = await getPermittedBizplaces(domain, user)
472
- let foundPermittedBizplace: Bizplace = permittedBizplaces.find(biz => biz.id == releaseGood.customerBizplaceId)
473
-
474
- if (!foundPermittedBizplace) throw new Error(`This user does not permitted for this company`)
475
-
476
- bizplace = await tx.getRepository(Bizplace).findOne({
477
- where: {
478
- id: releaseGood.customerBizplaceId
479
- },
480
- relations: ['domain']
481
- })
482
- const customerPartner: Partner = await tx.getRepository(Partner).findOne({
483
- where: { partnerDomain: { id: bizplace.domain.id }, domain: { id: domain.id } },
484
- relations: ['domain']
485
- })
486
- warehouseDomain = customerPartner.domain
487
- } else if (releaseGood.partnerBizplaceId) {
488
- const permittedBizplaces: Bizplace[] = await getPermittedBizplaces(domain, user)
489
- let foundPermittedBizplace: Bizplace = permittedBizplaces.find(biz => biz.id == releaseGood.partnerBizplaceId)
490
-
491
- if (!foundPermittedBizplace) throw new Error(`This user does not permitted for this company`)
492
-
493
- bizplace = await tx.getRepository(Bizplace).findOne({
494
- where: {
495
- id: releaseGood.partnerBizplaceId
496
- },
497
- relations: ['domain']
498
- })
499
- warehouseDomain = domain
500
- } else {
501
- bizplace = await getMyBizplace(domain, user)
502
- }
503
- /** End Validate user permitted Bizplace Section */
504
-
505
- /** Validate Release Order Product Quantity */
506
- await InventoryUtil.validateWarehousePartnersProductsQuantity(domain, bizplace, orderInventories, context, tx)
507
- /** End Validate Release Order Product Quantity Section */
508
-
509
- const orderSource: string = releaseGood.source
510
- switch (orderSource) {
511
- case ApplicationType.SELLERCRAFT:
512
- const sellercraft: Sellercraft = await tx
513
- .getRepository(Sellercraft)
514
- .findOneBy({ domain: { id: bizplace.domain.id }, status: SellercraftStatus.ACTIVE })
515
-
516
- if (sellercraft) {
517
- const sellercraftCtrl: SellercraftController = new SellercraftController(tx, domain, user)
518
- await sellercraftCtrl.checkExistingReleaseGood(sellercraft, releaseGood)
519
- }
520
-
521
- break
522
-
523
- case ApplicationType.MMS:
524
- const refNo: string = releaseGood.refNo
525
- const foundReleaseGood: ReleaseGood = await tx.getRepository(ReleaseGood).findOne({
526
- where: {
527
- domain: { id: warehouseDomain.id },
528
- refNo,
529
- status: Not(In([ORDER_STATUS.CANCELLED, ORDER_STATUS.PENDING_CANCEL]))
530
- },
531
- relations: ['bizplace', 'bizplace.domain', 'bizplace.company', 'bizplace.company.domain']
532
- })
533
-
534
- if (foundReleaseGood) {
535
- const customerCompanyDomain: Domain = foundReleaseGood.bizplace.company.domain
536
- const marketplaceOrder: MarketplaceOrder = await tx.getRepository(MarketplaceOrder).findOne({
537
- where: { orderNo: refNo, domain: { id: customerCompanyDomain.id } }
538
- })
539
-
540
- // Need to restructure the validation
541
- if (marketplaceOrder?.isSplitted) {
542
- const refNo2: string = releaseGood.refNo2
543
- const foundSplittedReleaseGood = await tx.getRepository(ReleaseGood).findOne({
544
- where: {
545
- domain: { id: warehouseDomain.id },
546
- refNo2,
547
- status: Not(In([ORDER_STATUS.CANCELLED, ORDER_STATUS.PENDING_CANCEL]))
548
- },
549
- relations: ['bizplace', 'bizplace.domain', 'bizplace.company', 'bizplace.company.domain']
550
- })
551
-
552
- if (foundSplittedReleaseGood) throw new Error('Existing release order found')
553
- } else {
554
- throw new Error('Existing release order found')
555
- }
556
- }
557
- break
558
-
559
- default:
560
- break
561
- }
562
-
563
- let newReleaseGood: ReleaseGood = new ReleaseGood()
564
-
565
- /** Generate Shipping Order */
566
- if (shippingOrder) {
567
- shippingOrder.remark = shippingOrder.exportRemark
568
- if (shippingOrder.containerClosureDate !== undefined) {
569
- shippingOrder.containerClosureDateTime = new Date(shippingOrder.containerClosureDate)
570
- }
571
- delete shippingOrder.exportRemark
572
-
573
- const createdSO: ShippingOrder = await tx.getRepository(ShippingOrder).save({
574
- ...shippingOrder,
575
- name: OrderNoGenerator.shippingOrder(),
576
- domain,
577
- bizplace,
578
- status: ORDER_STATUS.PENDING,
579
- creator: user,
580
- updater: user
581
- })
582
-
583
- newReleaseGood.shippingOrder = createdSO
584
- }
585
- /** End Generate Shipping Order Section */
586
-
587
- // find RO number rule setting
588
- const roNoSetting: Setting = await settingRepo.findOne({
589
- where: {
590
- domain: { id: domain.id },
591
- name: ORDER_NUMBER_SETTING_KEY.RO_NUMBER_RULE
592
- }
593
- })
594
-
595
- newReleaseGood = {
596
- ...newReleaseGood,
597
- name: roNoSetting
598
- ? await generateId({ domain, type: ORDER_NUMBER_RULE_TYPE.RO_NUMBER, seed: {} })
599
- : OrderNoGenerator.releaseGood(),
600
- domain: warehouseDomain,
601
- bizplace: bizplace,
602
- collectionOrderNo: releaseGood.collectionOrderNo,
603
- courierOption: releaseGood.courierOption,
604
- exportOption: releaseGood.exportOption,
605
- ownTransport: releaseGood.ownTransport,
606
- packingOption: releaseGood.packingOption,
607
- recall: releaseGood.recall,
608
- marketplaceOrderStatus: releaseGood?.marketplaceOrderStatus || null,
609
- deliverTo: releaseGood.deliverTo,
610
- billingAddress:
611
- releaseGood.type == 'b2c' ? releaseGood?.billingAddress || null : shippingOrderInfo.billingAddress || null,
612
- deliveryAddress1: releaseGood?.deliveryAddress1 || shippingOrderInfo.deliveryAddress1 || null,
613
- deliveryAddress2: releaseGood?.deliveryAddress2 || null,
614
- deliveryAddress3: releaseGood?.deliveryAddress3 || null,
615
- deliveryAddress4: releaseGood?.deliveryAddress4 || null,
616
- deliveryAddress5: releaseGood?.deliveryAddress5 || null,
617
- attentionTo: releaseGood.type == 'b2c' ? releaseGood?.attentionTo || null : shippingOrderInfo.attentionTo || null,
618
- attentionCompany:
619
- releaseGood.type == 'b2c' ? releaseGood?.companyName || null : shippingOrderInfo.attentionCompany || null,
620
- city: releaseGood.type == 'b2c' ? releaseGood?.city || null : shippingOrderInfo.city || null,
621
- state: releaseGood.type == 'b2c' ? releaseGood?.state || null : shippingOrderInfo.state || null,
622
- postalCode: releaseGood.type == 'b2c' ? releaseGood?.postalCode || null : shippingOrderInfo.postalCode || null,
623
- country: releaseGood.type == 'b2c' ? releaseGood?.country || null : shippingOrderInfo.country || null,
624
- phone1: releaseGood.type == 'b2c' ? releaseGood?.phone1 || null : shippingOrderInfo.phone1 || null,
625
- phone2: releaseGood?.phone2 || null,
626
- email: releaseGood?.email || null,
627
- billingCity: releaseGood.type == 'b2c' ? releaseGood?.billingCity || null : shippingOrderInfo.billingCity || null,
628
- billingCountry:
629
- releaseGood.type == 'b2c' ? releaseGood?.billingCountry || null : shippingOrderInfo.billingCountry || null,
630
- billingPostalCode:
631
- releaseGood.type == 'b2c'
632
- ? releaseGood?.billingPostalCode || null
633
- : shippingOrderInfo.billingPostalCode || null,
634
- billingState:
635
- releaseGood.type == 'b2c' ? releaseGood?.billingState || null : shippingOrderInfo.billingState || null,
636
- transporter: releaseGood?.transporter,
637
- trackingNo: releaseGood?.trackingNo,
638
- airwayBill: releaseGood?.airwayBill,
639
- invoice: releaseGood?.invoice,
640
- refNo: releaseGood.refNo,
641
- refNo2: releaseGood.refNo2,
642
- refNo3: releaseGood.refNo3,
643
- remark: releaseGood?.remark || null,
644
- releaseDate: releaseGood.releaseDate,
645
- truckNo: releaseGood.truckNo,
646
- bundleInfo: releaseGood?.bundleInfo || [],
647
- orderInventories: releaseGood.orderInventories,
648
- type: releaseGood?.type ? releaseGood.type : 'b2b',
649
- orderMethod: releaseGood?.orderMethod
650
- ? releaseGood.orderMethod
651
- : releaseGood.orderInventories[0]?.inventory?.id
652
- ? ORDER_METHOD.SELECT_BY_PALLET
653
- : ORDER_METHOD.SELECT_BY_PRODUCT,
654
- status: ORDER_STATUS.PENDING,
655
- packageId: releaseGood?.packageId,
656
- storeName: releaseGood?.storeName,
657
- storeId: releaseGood?.storeId,
658
- routeId: releaseGood?.routeId,
659
- stopId: releaseGood?.stopId,
660
- creator: user,
661
- updater: user
662
- }
663
-
664
- // Make relation with GAN for cross docking
665
- let crossDockingGAN: ArrivalNotice = undefined
666
- if (releaseGood.crossDocking && releaseGood.ganNo) {
667
- crossDockingGAN = await tx.getRepository(ArrivalNotice).findOne({
668
- where: {
669
- domain: { id: domain.id },
670
- bizplace: { id: bizplace.id },
671
- name: releaseGood.ganNo,
672
- status: ORDER_STATUS.PENDING
673
- }
674
- })
675
- if (!crossDockingGAN) throw new Error(`Failed to find GAN (${releaseGood.ganNo}) for cross docking`)
676
-
677
- newReleaseGood.arrivalNotice = crossDockingGAN
678
- }
679
-
680
- // Make relation with RO for cross docking
681
- if (newReleaseGood.crossDocking) {
682
- crossDockingGAN.releaseGood = newReleaseGood
683
- await tx.getRepository(ArrivalNotice).save(crossDockingGAN)
684
- }
685
-
686
- // Check if there is bundle item in orderInventories
687
- const bundledOIs: OrderInventory[] = orderInventories.filter(
688
- oi => (oi.product as any).groupType === PRODUCT_GROUP_TYPE.BUNDLE
689
- )
690
-
691
- const singleProductOIs: OrderInventory[] = orderInventories.filter(
692
- oi => (oi.product as any).groupType !== PRODUCT_GROUP_TYPE.BUNDLE
693
- )
694
-
695
- const splitBundleOIs: OrderInventory[] = []
696
-
697
- // If there is bundle item, split each item in that bundle into into each product
698
- if (bundledOIs && bundledOIs.length > 0) {
699
- await Promise.all(
700
- bundledOIs.map(async (oi: OrderInventory) => {
701
- let splitOI: OrderInventory = null
702
-
703
- const pbSettings: ProductBundleSetting[] = await tx.getRepository(ProductBundleSetting).find({
704
- where: { productBundle: { id: oi.product.id } },
705
- relations: ['product', 'productBundle']
706
- })
707
-
708
- pbSettings.forEach(pbs => {
709
- splitOI = {
710
- ...oi,
711
- releaseQty: oi.releaseQty * pbs.bundleQty,
712
- releaseUomValue: oi.releaseUomValue * pbs.bundleQty * pbs.product.primaryValue,
713
- packingType: pbs.product.packingType,
714
- batchId: '',
715
- product: {
716
- id: pbs.product.id,
717
- name: pbs.product.name,
718
- groupType: PRODUCT_GROUP_TYPE.SINGLE
719
- } as any
720
- }
721
- splitBundleOIs.push(splitOI)
722
- })
723
- })
724
- )
725
- }
726
-
727
- orderInventories = [...singleProductOIs, ...splitBundleOIs]
728
-
729
- newReleaseGood.noOfItems = orderInventories.length
730
- newReleaseGood = await tx.getRepository(ReleaseGood).save(newReleaseGood)
731
-
732
- for (let oi of orderInventories) {
733
- let newOrderInv: OrderInventory = Object.assign({}, oi)
734
- newOrderInv = {
735
- ...newOrderInv,
736
- domain: warehouseDomain,
737
- bizplace: bizplace,
738
- status: ORDER_INVENTORY_STATUS.PENDING,
739
- name: OrderNoGenerator.orderInventory(),
740
- releaseGood: newReleaseGood,
741
- product: await tx.getRepository(Product).findOneBy({ id: oi.product.id }),
742
- creator: user,
743
- updater: user
744
- }
745
-
746
- let newOrderProduct: OrderProduct = Object.assign(new OrderProduct(), newOrderInv)
747
- newOrderProduct = {
748
- ...newOrderProduct,
749
- packQty: 0,
750
- actualPackQty: 0,
751
- palletQty: 0,
752
- actualPalletQty: 0,
753
- status: ORDER_PRODUCT_STATUS.ASSIGNED
754
- }
755
-
756
- newOrderProduct = await tx.getRepository(OrderProduct).save(newOrderProduct)
757
-
758
- if (newOrderInv.inventory?.id) {
759
- const foundInv: Inventory = await tx.getRepository(Inventory).findOneBy({ id: newOrderInv.inventory.id })
760
- newOrderInv.inventory = foundInv
761
- newOrderInv.orderProduct = newOrderProduct
762
-
763
- finalOrderInventories.push(newOrderInv)
764
- } else {
765
- // Preassign Inventories
766
- const inventoryAssignmentSetting: Setting = await tx.getRepository(Setting).findOne({
767
- where: { domain: { id: domain.id }, name: 'rule-for-inventory-assignment' }
768
- })
769
-
770
- let locationSortingRules = []
771
- if (inventoryAssignmentSetting) {
772
- let locationSetting = JSON.parse(inventoryAssignmentSetting.value)
773
- for (const key in locationSetting) {
774
- locationSortingRules.push({ name: key, desc: locationSetting[key] == 'ASC' ? false : true })
775
- }
776
- }
777
-
778
- let assignedOrderInventories: OrderInventory[] = await InventoryUtil.autoAssignInventoryForRelease(
779
- newOrderInv.product,
780
- oi,
781
- oi.packingType,
782
- locationSortingRules,
783
- bizplace,
784
- warehouseDomain,
785
- tx,
786
- oi.batchId
787
- )
788
-
789
- assignedOrderInventories = assignedOrderInventories.map(aoi => {
790
- return {
791
- ...aoi,
792
- orderProduct: newOrderProduct
793
- }
794
- })
795
-
796
- finalOrderInventories.push(...assignedOrderInventories)
797
- }
798
- }
799
-
800
- for (let oi of finalOrderInventories) {
801
- let generatedOI: OrderInventory = Object.assign(new OrderInventory(), oi)
802
- generatedOI = {
803
- ...generatedOI,
804
- domain: warehouseDomain,
805
- bizplace,
806
- status: ORDER_INVENTORY_STATUS.PENDING,
807
- name: OrderNoGenerator.orderInventory(),
808
- releaseGood: newReleaseGood,
809
- creator: user,
810
- updater: user
811
- }
812
-
813
- await tx.getRepository(OrderInventory).save({ ...generatedOI })
814
-
815
- // update inventory locked qty and uom value
816
- await tx.getRepository(Inventory).update({ id: oi.inventory.id }, {
817
- lockedQty: (oi.inventory?.lockedQty || 0) + generatedOI.releaseQty,
818
- lockedUomValue: (oi.inventory?.lockedUomValue || 0) + generatedOI.releaseUomValue,
819
- updater: user
820
- } as any)
821
- }
822
-
823
- if (orderVass?.length) {
824
- orderVass = await Promise.all(
825
- orderVass.map(async orderVas => {
826
- if (orderVas?.targetProduct?.id) {
827
- orderVas.targetProduct = await tx.getRepository(Product).findOneBy({ id: orderVas.targetProduct.id })
828
- }
829
-
830
- let newOrderVas: OrderVas = {
831
- ...orderVas,
832
- domain: warehouseDomain,
833
- bizplace,
834
- name: OrderNoGenerator.releaseVas(),
835
- vas: await tx.getRepository(Vas).findOneBy({ id: orderVas.vas.id }),
836
- type: ORDER_TYPES.RELEASE_OF_GOODS,
837
- releaseGood: newReleaseGood,
838
- status: ORDER_VAS_STATUS.PENDING,
839
- creator: user,
840
- updater: user
841
- }
842
-
843
- if (orderVas?.inventory?.id) {
844
- newOrderVas.inventory = await tx.getRepository(Inventory).findOneBy({ id: orderVas.inventory.id })
845
- }
846
-
847
- return newOrderVas
848
- })
849
- )
850
-
851
- await tx.getRepository(OrderVas).save(orderVass)
852
- }
853
-
854
- if (attachments?.length > 0) {
855
- const files: Partial<Attachment>[] = attachments.map(attachment => {
856
- return {
857
- file: attachment,
858
- refType: ATTACHMENT_TYPE.DELIVERY_ORDER,
859
- refBy: newReleaseGood.id,
860
- category: ATTACHMENT_TYPE.DELIVERY_ORDER /* TODO use refType */
861
- }
862
- })
863
- await createAttachments(_, { attachments: files }, context)
864
- }
865
-
866
- const directReceiveSetting: Setting = await tx.getRepository(Setting).findOne({
867
- where: { domain: { id: domain.id }, category: 'id-rule', name: 'enable-direct-receive-release-order' }
868
- })
869
-
870
- if (directReceiveSetting) {
871
- const partnerDirectReceiveSetting: PartnerSetting = await tx.getRepository(PartnerSetting).findOne({
872
- where: {
873
- setting: { id: directReceiveSetting?.id },
874
- domain: { id: domain.id },
875
- partnerDomain: { id: bizplace?.domain.id }
876
- }
877
- })
878
-
879
- // If status of create RO is PENDING then directly CONFIRM -> RECEIVE
880
- if (
881
- !isNaN(Number(partnerDirectReceiveSetting?.value)) &&
882
- !isNaN(parseFloat(partnerDirectReceiveSetting?.value)) &&
883
- newReleaseGood.status === ORDER_STATUS.PENDING
884
- ) {
885
- let partnerDirectReceiveSettingValue = parseFloat(partnerDirectReceiveSetting.value)
886
-
887
- // CONFIRM if setting value is > 0
888
- if (partnerDirectReceiveSettingValue > 0) await confirmReleaseGood(newReleaseGood.name, context, tx)
889
-
890
- // RECEIVE if setting value is > 1
891
- if (partnerDirectReceiveSettingValue > 1) await receiveReleaseGood(newReleaseGood.name, context, tx)
892
- }
893
- }
894
-
895
- return newReleaseGood
896
- } catch (error) {
897
- throw error
898
- }
899
- }
900
-
901
- export async function confirmReleaseGood(name: string, context: any, tx?: EntityManager): Promise<ReleaseGood> {
902
- const { user, domain } = context.state
903
-
904
- let foundReleaseGood: ReleaseGood = await tx.getRepository(ReleaseGood).findOne({
905
- where: { name, status: ORDER_STATUS.PENDING },
906
- relations: ['domain', 'bizplace', 'bizplace.domain', 'bizplace.company', 'bizplace.company.domain', 'orderVass']
907
- })
908
-
909
- if (!foundReleaseGood) throw new Error(`Release good order doesn't exists.`)
910
-
911
- // query orderInventories separately from releaseGood to reduce resource usage
912
- let foundOIs: OrderInventory[] = await tx.getRepository(OrderInventory).find({
913
- where: { domain: { id: domain.id }, releaseGood: { id: foundReleaseGood.id } },
914
- relations: ['product']
915
- })
916
-
917
- // query orderProducts separately from releaseGood to reduce resource usage
918
- let foundOPs: OrderProduct[] = await tx.getRepository(OrderProduct).find({
919
- where: { domain: { id: domain.id }, releaseGood: { id: foundReleaseGood.id } },
920
- relations: ['bizplace', 'product', 'product.productDetails']
921
- })
922
-
923
- let foundBundleInfo: any[] = JSON.parse(foundReleaseGood.bundleInfo)
924
- let foundOVs: OrderVas[] = foundReleaseGood.orderVass
925
- let customerBizplace: Bizplace = foundReleaseGood.bizplace
926
- const companyDomain: Domain = customerBizplace?.company.domain
927
-
928
- const sellercraft: Sellercraft = await tx.getRepository(Sellercraft).findOne({
929
- where: { domain: { id: foundReleaseGood.bizplace.domain.id }, status: SellercraftStatus.ACTIVE },
930
- relations: ['domain']
931
- })
932
-
933
- const sellercraftCtrl: SellercraftController = new SellercraftController(tx, domain, user)
934
-
935
- let updateSCStock = async sellercraft => {
936
- if (sellercraft) {
937
- await sellercraftCtrl.updateSellercraftStock(sellercraft, foundOPs, 'CONFIRM_ORDER')
938
- }
939
- }
940
-
941
- const orderSource: string = foundReleaseGood.source
942
- switch (orderSource) {
943
- case ApplicationType.SELLERCRAFT:
944
- if (foundReleaseGood.type == 'b2c' && sellercraft) {
945
- try {
946
- let rg = await sellercraftCtrl.packOrder(sellercraft, {
947
- ...foundReleaseGood,
948
- orderProducts: foundOPs
949
- })
950
- foundReleaseGood = rg
951
- } catch (error) {
952
- logger.error(
953
- `release-good-mutation[confirmReleaseGood]:(data:${JSON.stringify({
954
- sellercraft,
955
- foundReleaseGood,
956
- domain,
957
- user
958
- })}) ${error} `
959
- )
960
- }
961
- }
962
- break
963
-
964
- case ApplicationType.MMS:
965
- // find for any existing marketplace store connections
966
- let marketplaceStores: MarketplaceStore[] = await tx.getRepository(MarketplaceStore).find({
967
- where: { domain: { id: companyDomain.id }, status: 'ACTIVE' },
968
- relations: ['marketplaceDistributors']
969
- })
970
-
971
- const foundMarketplaceOrder: MarketplaceOrder = await tx.getRepository(MarketplaceOrder).findOne({
972
- where: { domain: { id: companyDomain.id }, orderNo: foundReleaseGood.refNo },
973
- relations: ['marketplaceStore']
974
- })
975
-
976
- let matchedMarketplaceStore: MarketplaceStore
977
- if (foundMarketplaceOrder) {
978
- matchedMarketplaceStore = marketplaceStores.filter(
979
- marketplaceStore => marketplaceStore.id == foundMarketplaceOrder.marketplaceStore.id
980
- )[0]
981
- }
982
-
983
- let combinedOrderInventories: any[] = foundOIs.map(oi => {
984
- return {
985
- sku: oi.product.sku,
986
- releaseQty: oi.releaseQty
987
- }
988
- })
989
-
990
- if (foundBundleInfo?.length) {
991
- foundBundleInfo.map(bundle => {
992
- combinedOrderInventories.push({
993
- sku: bundle.sku,
994
- releaseQty: bundle.releaseQty
995
- })
996
- })
997
- }
998
-
999
- for (let oi of combinedOrderInventories) {
1000
- let foundMarketplaceProductVariations: MarketplaceProductVariation[] = await tx
1001
- .getRepository(MarketplaceProductVariation)
1002
- .find({
1003
- where: { domain: { id: companyDomain.id }, sku: oi.sku },
1004
- relations: ['marketplaceProduct', 'marketplaceProduct.marketplaceStore']
1005
- })
1006
-
1007
- if (foundMarketplaceProductVariations) {
1008
- await Promise.all(
1009
- foundMarketplaceProductVariations.map(async variation => {
1010
- if (variation.marketplaceProduct.marketplaceStore.reserveEnabled) {
1011
- variation.reserveQty -= oi.releaseQty
1012
- }
1013
-
1014
- await tx.getRepository(MarketplaceProductVariation).save(variation)
1015
- })
1016
- )
1017
- }
1018
- }
1019
-
1020
- if (marketplaceStores?.length && marketplaceStores.some(store => store.isAutoUpdateStockQty)) {
1021
- marketplaceStores = marketplaceStores.filter(marketplaceStore => marketplaceStore.isAutoUpdateStockQty)
1022
- let productIds: string[] = foundOIs.map(oi => oi.product.id)
1023
- productIds = Array.from(new Set([...productIds]))
1024
- const ecommerceCtrl: EcommerceController = new EcommerceController(tx, domain, user)
1025
- await ecommerceCtrl.updateProductVariationStock(marketplaceStores, productIds, companyDomain)
1026
- }
1027
-
1028
- updateSCStock(sellercraft)
1029
- break
1030
-
1031
- default:
1032
- updateSCStock(sellercraft)
1033
- break
1034
- }
1035
-
1036
- // 1. RO Status change (PENDING => PENDING_RECEIVE)
1037
- const releaseGood: ReleaseGood = await tx.getRepository(ReleaseGood).save({
1038
- ...foundReleaseGood,
1039
- status: ORDER_STATUS.PENDING_RECEIVE,
1040
- updater: user
1041
- })
1042
-
1043
- // 1. Update status of order inventories
1044
- foundOIs = foundOIs.map((orderInventory: OrderInventory) => {
1045
- return {
1046
- ...orderInventory,
1047
- status: ORDER_INVENTORY_STATUS.PENDING_RECEIVE,
1048
- updater: user
1049
- }
1050
- })
1051
- await tx.getRepository(OrderInventory).save(foundOIs)
1052
-
1053
- // 2. Update status of order vass
1054
- if (foundOVs && foundOVs.length) {
1055
- foundOVs = foundOVs.map((orderVas: OrderVas) => {
1056
- return {
1057
- ...orderVas,
1058
- status: ORDER_VAS_STATUS.PENDING_RECEIVE,
1059
- updater: user
1060
- }
1061
- })
1062
- await tx.getRepository(OrderVas).save(foundOVs)
1063
- }
1064
-
1065
- // notification logics
1066
- // get Office Admin Users
1067
- if (context?.state?.type != 'api') {
1068
- const users: any[] = await tx
1069
- .getRepository('users_roles')
1070
- .createQueryBuilder('ur')
1071
- .select('ur.users_id', 'id')
1072
- .where(qb => {
1073
- const subQuery = qb
1074
- .subQuery()
1075
- .select('role.id')
1076
- .from(Role, 'role')
1077
- .where("role.name = 'Office Admin'")
1078
- .andWhere('role.domain_id = :domain', { domain: domain.id })
1079
- .getQuery()
1080
- return 'ur.roles_id IN ' + subQuery
1081
- })
1082
- .getRawMany()
1083
-
1084
- // send notification to Office Admin Users
1085
- if (users?.length && context.header?.referer) {
1086
- const receivers: any[] = users.map(user => user.id)
1087
- const msg = {
1088
- title: `New Release Order from ${customerBizplace.name}`,
1089
- body: `New incoming order, ${foundReleaseGood.name} is pending for receiving`,
1090
- url: context.header.referer,
1091
- data: { url: context.header.referer }
1092
- }
1093
-
1094
- /**
1095
- * @notes Temporary off sendNotification due to suspect of causing wms down
1096
- */
1097
-
1098
- // await sendNotification({
1099
- // receivers,
1100
- // message: { ...msg }
1101
- // })
1102
- }
1103
- }
1104
-
1105
- return releaseGood
1106
- }
1107
-
1108
- export async function receiveReleaseGood(name: string, context: any, tx: EntityManager): Promise<ReleaseGood> {
1109
- const { domain, user } = context.state
1110
-
1111
- const foundReleaseGood: ReleaseGood = await tx.getRepository(ReleaseGood).findOne({
1112
- where: { domain: { id: domain.id }, name, status: ORDER_STATUS.PENDING_RECEIVE },
1113
- relations: ['bizplace', 'orderInventories', 'orderVass']
1114
- })
1115
-
1116
- if (!foundReleaseGood) throw new Error(`Release good order doesn't exists.`)
1117
- let foundOIs: OrderInventory[] = foundReleaseGood.orderInventories
1118
- let foundOVs: OrderVas[] = foundReleaseGood.orderVass
1119
- let customerBizplace: Bizplace = foundReleaseGood.bizplace
1120
-
1121
- // 1. RO Status change (PENDING_RECEIVE => PENDING_WORKSHEET)
1122
- const releaseGood: ReleaseGood = await tx.getRepository(ReleaseGood).save({
1123
- ...foundReleaseGood,
1124
- status: ORDER_STATUS.PENDING_WORKSHEET,
1125
- acceptedBy: user,
1126
- acceptedAt: new Date(),
1127
- updater: user
1128
- })
1129
-
1130
- // 1. Update status of order inventories
1131
- foundOIs = foundOIs.map((orderInventory: OrderInventory) => {
1132
- return {
1133
- ...orderInventory,
1134
- status: ORDER_INVENTORY_STATUS.PENDING_WORKSHEET,
1135
- updater: user
1136
- }
1137
- })
1138
- await tx.getRepository(OrderInventory).save(foundOIs)
1139
-
1140
- // 2. Update status of order vass
1141
- if (foundOVs && foundOVs.length) {
1142
- foundOVs = foundOVs.map((orderVas: OrderVas) => {
1143
- return {
1144
- ...orderVas,
1145
- status: ORDER_VAS_STATUS.READY_TO_PROCESS,
1146
- updater: user
1147
- }
1148
- })
1149
- await tx.getRepository(OrderVas).save(foundOVs)
1150
- }
1151
-
1152
- // notification logics
1153
- // get Office Admin Users
1154
- if (context?.state?.type != 'api') {
1155
- const users: any[] = await tx
1156
- .getRepository('users_roles')
1157
- .createQueryBuilder('ur')
1158
- .select('ur.users_id', 'id')
1159
- .where(qb => {
1160
- const subQuery = qb
1161
- .subQuery()
1162
- .select('role.id')
1163
- .from(Role, 'role')
1164
- .where("role.name = 'Office Admin'")
1165
- .andWhere('role.domain_id = :domain', { domain: domain.id })
1166
- .getQuery()
1167
- return 'ur.roles_id IN ' + subQuery
1168
- })
1169
- .getRawMany()
1170
-
1171
- // send notification to Office Admin Users
1172
- if (users?.length && context.header?.referer) {
1173
- const receivers: any[] = users.map(user => user.id)
1174
- const msg = {
1175
- title: `New Release Order from ${customerBizplace.name}`,
1176
- body: `New incoming order, ${foundReleaseGood.name} is pending for receiving`,
1177
- url: context.header.referer,
1178
- data: { url: context.header.referer }
1179
- }
1180
-
1181
- /**
1182
- * @notes Temporary off sendNotification due to suspect of causing wms down
1183
- */
1184
-
1185
- // await sendNotification({
1186
- // receivers,
1187
- // message: { ...msg }
1188
- // })
1189
- }
1190
- }
1191
-
1192
- return releaseGood
1193
- }
1194
-
1195
- export async function rejectReleaseGood(
1196
- tx: EntityManager,
1197
- context: ResolverContext,
1198
- name: string,
1199
- remark: string
1200
- ): Promise<ReleaseGood> {
1201
- const { domain, user } = context.state
1202
-
1203
- const releaseGood: ReleaseGood = await tx.getRepository(ReleaseGood).findOne({
1204
- where: { domain: { id: domain.id }, name, status: ORDER_STATUS.PENDING_RECEIVE },
1205
- relations: [
1206
- 'bizplace',
1207
- 'bizplace.domain',
1208
- 'orderProducts',
1209
- 'orderProducts.product',
1210
- 'orderProducts.product.productDetails',
1211
- 'orderInventories',
1212
- 'orderInventories.inventory',
1213
- 'orderVass',
1214
- 'shippingOrder'
1215
- ]
1216
- })
1217
-
1218
- if (!releaseGood) throw new Error(`Release good doesn't exists.`)
1219
- if (!remark) throw new Error('Remark is not exist.')
1220
-
1221
- let foundOIs: OrderInventory[] = releaseGood.orderInventories
1222
- let foundOVs: OrderVas[] = releaseGood.orderVass
1223
- let foundOPs: OrderProduct[] = releaseGood.orderProducts
1224
-
1225
- // 1. Update status of order products (PENDING_RECEIVE => REJECTED)
1226
- if (foundOIs && foundOIs.length) {
1227
- await tx.getRepository(OrderInventory).save(
1228
- await Promise.all(
1229
- foundOIs.map(async (oi: OrderInventory) => {
1230
- if (oi?.inventory?.id) {
1231
- oi.inventory = await tx.getRepository(Inventory).findOneBy({ id: oi.inventory.id })
1232
-
1233
- await tx.getRepository(Inventory).save({
1234
- ...oi.inventory,
1235
- lockedQty: oi.inventory.lockedQty - oi.releaseQty,
1236
- lockedUomValue: oi.inventory.lockedUomValue - oi.releaseUomValue,
1237
- updater: user
1238
- })
1239
- }
1240
-
1241
- oi.status = ORDER_INVENTORY_STATUS.REJECTED
1242
- oi.updater = user
1243
- return oi
1244
- })
1245
- )
1246
- )
1247
- }
1248
-
1249
- if (foundOPs && foundOPs.length) {
1250
- const orderSource: string = releaseGood.source
1251
- switch (orderSource) {
1252
- case ApplicationType.SELLERCRAFT:
1253
- const sellercraft: Sellercraft = await tx
1254
- .getRepository(Sellercraft)
1255
- .findOneBy({ domain: { id: releaseGood.bizplace.domain.id }, status: SellercraftStatus.ACTIVE })
1256
-
1257
- if (sellercraft) {
1258
- const sellercraftCtrl: SellercraftController = new SellercraftController(tx, domain, user)
1259
- await sellercraftCtrl.updateSellercraftStock(sellercraft, foundOPs, 'REJECT_ORDER')
1260
- }
1261
- break
1262
-
1263
- default:
1264
- break
1265
- }
1266
-
1267
- await tx.getRepository(OrderProduct).save(
1268
- await Promise.all(
1269
- foundOPs.map(async (op: OrderProduct) => {
1270
- op.status = ORDER_PRODUCT_STATUS.REJECTED
1271
- op.updater = user
1272
- return op
1273
- })
1274
- )
1275
- )
1276
- }
1277
-
1278
- // 2. Update status of order vass if it exists (PENDING_RECEIVE => REJECTED)
1279
- if (foundOVs && foundOVs.length) {
1280
- foundOVs = foundOVs.map((ov: OrderVas) => {
1281
- ov.status = ORDER_VAS_STATUS.REJECTED
1282
- ov.updater = user
1283
- return ov
1284
- })
1285
- await tx.getRepository(OrderVas).save(foundOVs)
1286
- }
1287
-
1288
- if (releaseGood.shippingOrder) {
1289
- // 2. 1) if it's yes update status of collection order
1290
- const shippingOrder: ShippingOrder = await tx.getRepository(ShippingOrder).findOne({
1291
- where: { domain: { id: domain.id }, name: releaseGood.shippingOrder.name }
1292
- })
1293
-
1294
- shippingOrder.status = ORDER_STATUS.REJECTED
1295
- shippingOrder.updater = user
1296
- await tx.getRepository(ShippingOrder).save(shippingOrder)
1297
- }
1298
-
1299
- releaseGood.remark = remark
1300
- releaseGood.status = ORDER_STATUS.REJECTED
1301
- releaseGood.updater = user
1302
- await tx.getRepository(ReleaseGood).save(releaseGood)
1303
-
1304
- // notification logics
1305
- const users: any[] = await getDomainUsers(releaseGood?.bizplace, tx)
1306
-
1307
- if (users?.length && context.header?.referer) {
1308
- const receivers: any[] = users.map(user => user.id)
1309
- const msg = {
1310
- title: `Latest status for ${releaseGood.name}`,
1311
- body: `Your RO has been rejected.`,
1312
- url: context.header.referer,
1313
- data: { url: context.header.referer }
1314
- }
1315
-
1316
- /**
1317
- * @notes Temporary off sendNotification due to suspect of causing wms down
1318
- */
1319
-
1320
- // await sendNotification({
1321
- // receivers,
1322
- // message: { ...msg }
1323
- // })
1324
- }
1325
-
1326
- return releaseGood
1327
- }
1328
-
1329
- export async function bulkGenerateReleaseGood(
1330
- releaseGood: any,
1331
- bizplaceId: string,
1332
- roNoSetting: any,
1333
- domain: Domain,
1334
- user: User,
1335
- tx?: EntityManager
1336
- ): Promise<ReleaseGood> {
1337
- try {
1338
- let warehouseDomain: Domain = domain
1339
- let { orderInventories, shippingOrder } = releaseGood
1340
-
1341
- let bizplace: Bizplace = await tx.getRepository(Bizplace).findOneBy({ id: bizplaceId })
1342
-
1343
- let newReleaseGood: ReleaseGood = {
1344
- ...releaseGood,
1345
- name: roNoSetting
1346
- ? await generateId({ domain, type: ORDER_NUMBER_RULE_TYPE.RO_NUMBER, seed: {} })
1347
- : OrderNoGenerator.releaseGood(),
1348
- domain: warehouseDomain,
1349
- bizplace: bizplace,
1350
- deliveryAddress1: releaseGood?.deliveryAddress1 || null,
1351
- deliveryAddress2: releaseGood?.deliveryAddress2 || null,
1352
- deliveryAddress3: releaseGood?.deliveryAddress3 || null,
1353
- deliveryAddress4: releaseGood?.deliveryAddress4 || null,
1354
- attentionTo: releaseGood?.attentionTo || null,
1355
- attentionCompany: releaseGood?.attentionCompany || null,
1356
- city: releaseGood?.city || null,
1357
- state: releaseGood?.state || null,
1358
- postalCode: releaseGood?.postalCode || null,
1359
- country: releaseGood?.country || null,
1360
- phone1: releaseGood?.phone1 || null,
1361
- phone2: releaseGood?.phone2 || null,
1362
- email: releaseGood?.email || null,
1363
- source: releaseGood?.source || null,
1364
- airwayBill: releaseGood?.airwayBill,
1365
- refNo: releaseGood.refNo,
1366
- refNo2: releaseGood.refNo2,
1367
- refNo3: releaseGood.refNo3,
1368
- releaseDate: releaseGood.releaseDate,
1369
- ownTransport: releaseGood?.ownTransport || false,
1370
- orderMethod: ORDER_METHOD.SELECT_BY_PRODUCT,
1371
- status: ORDER_STATUS.PENDING,
1372
- creator: releaseGood?.creator || user,
1373
- updater: releaseGood?.updater || user
1374
- }
1375
-
1376
- newReleaseGood = await tx.getRepository(ReleaseGood).save(newReleaseGood)
1377
-
1378
- /** Generate Shipping Order */
1379
- if (shippingOrder) {
1380
- shippingOrder.remark = shippingOrder.exportRemark
1381
- if (shippingOrder.containerClosureDate !== undefined) {
1382
- shippingOrder.containerClosureDateTime = new Date(shippingOrder.containerClosureDate)
1383
- }
1384
- delete shippingOrder.exportRemark
1385
-
1386
- const createdSO: ShippingOrder = await tx.getRepository(ShippingOrder).save({
1387
- ...shippingOrder,
1388
- name: OrderNoGenerator.shippingOrder(),
1389
- domain,
1390
- bizplace,
1391
- status: ORDER_STATUS.PENDING,
1392
- creator: user,
1393
- updater: user
1394
- })
1395
-
1396
- newReleaseGood.shippingOrder = createdSO
1397
- }
1398
-
1399
- let finalOrderInventories: Partial<OrderInventory>[] = []
1400
-
1401
- // pre assign inventory to orderInventories
1402
- for (let oi of orderInventories) {
1403
- const pickingProductSetting: Setting = await tx.getRepository(Setting).findOne({
1404
- where: { domain: { id: domain.id }, name: 'rule-for-picking-product' }
1405
- })
1406
-
1407
- let locationSortingRules = []
1408
- if (pickingProductSetting) {
1409
- let locationSetting = JSON.parse(pickingProductSetting.value)
1410
- for (const key in locationSetting) {
1411
- locationSortingRules.push({ name: key, desc: locationSetting[key] == 'ASC' ? false : true })
1412
- }
1413
- }
1414
-
1415
- const product: Product = await tx.getRepository(Product).findOneBy({ id: oi.productId })
1416
-
1417
- let assignedResult = await InventoryUtil.autoAssignInventoryForRelease(
1418
- product,
1419
- oi,
1420
- oi.packingType,
1421
- locationSortingRules,
1422
- bizplace,
1423
- warehouseDomain,
1424
- tx
1425
- )
1426
-
1427
- finalOrderInventories.push(
1428
- ...assignedResult.map(itm => {
1429
- return {
1430
- ...itm,
1431
- orderProduct: oi?.orderProduct
1432
- }
1433
- })
1434
- )
1435
- }
1436
-
1437
- for (let oi of finalOrderInventories) {
1438
- let generatedOI: OrderInventory = Object.assign(new OrderInventory(), oi)
1439
- generatedOI = {
1440
- ...generatedOI,
1441
- domain: warehouseDomain,
1442
- bizplace,
1443
- status: ORDER_INVENTORY_STATUS.PENDING,
1444
- name: OrderNoGenerator.orderInventory(),
1445
- releaseGood: newReleaseGood,
1446
- creator: newReleaseGood?.creator || user,
1447
- updater: newReleaseGood?.updater || user
1448
- }
1449
-
1450
- let newOrderProduct: Partial<OrderProduct>
1451
- if (!oi?.orderProduct) {
1452
- newOrderProduct = {
1453
- name: generatedOI.name,
1454
- product: generatedOI.product,
1455
- batchId: generatedOI.batchId,
1456
- packingType: generatedOI.packingType,
1457
- packingSize: generatedOI.packingSize,
1458
- uom: generatedOI.uom,
1459
- domain: warehouseDomain,
1460
- bizplace,
1461
- releaseQty: generatedOI.releaseQty,
1462
- releaseUomValue: generatedOI.releaseUomValue,
1463
- packQty: 0,
1464
- actualPackQty: 0,
1465
- palletQty: 0,
1466
- actualPalletQty: 0,
1467
- status: ORDER_PRODUCT_STATUS.ASSIGNED,
1468
- releaseGood: newReleaseGood,
1469
- creator: newReleaseGood?.creator || user,
1470
- updater: newReleaseGood?.updater || user
1471
- }
1472
-
1473
- newOrderProduct = await tx.getRepository(OrderProduct).save(newOrderProduct)
1474
- } else {
1475
- newOrderProduct = await tx.getRepository(OrderProduct).save({
1476
- ...oi.orderProduct,
1477
- totalUomValue: `${oi.orderProduct.releaseUomValue} ${oi.orderProduct.uom}`,
1478
- status: ORDER_PRODUCT_STATUS.ASSIGNED,
1479
- updater: newReleaseGood?.updater || user
1480
- })
1481
- }
1482
-
1483
- await tx.getRepository(OrderInventory).save({ ...generatedOI, orderProduct: newOrderProduct })
1484
-
1485
- // update inventory locked qty and uom value
1486
- await tx.getRepository(Inventory).update(oi.inventory.id, {
1487
- lockedQty: (oi.inventory?.lockedQty || 0) + generatedOI.releaseQty,
1488
- lockedUomValue: (oi.inventory?.lockedUomValue || 0) + generatedOI.releaseUomValue,
1489
- updater: user
1490
- } as any)
1491
- }
1492
-
1493
- return newReleaseGood
1494
- } catch (error) {
1495
- throw error
1496
- }
1497
- }
1498
-
1499
- export async function bulkConfirmReleaseGoods(
1500
- releaseGoodsNo: string[],
1501
- domain: Domain,
1502
- user: User,
1503
- context: any,
1504
- tx?: EntityManager
1505
- ): Promise<ReleaseGood[]> {
1506
- let foundReleaseGoods: ReleaseGood[] = await tx.getRepository(ReleaseGood).find({
1507
- where: { name: In(releaseGoodsNo), status: ORDER_STATUS.PENDING },
1508
- relations: ['bizplace']
1509
- })
1510
-
1511
- if (!foundReleaseGoods.length) throw new Error(`release good order doesn't exists.`)
1512
- let customerBizplace: Bizplace = foundReleaseGoods[0].bizplace
1513
-
1514
- let foundOrderInventories: OrderInventory[] = await tx.getRepository(OrderInventory).find({
1515
- where: { domain: { id: domain.id }, releaseGood: { id: In(foundReleaseGoods.map((rg: ReleaseGood) => rg.id)) } }
1516
- })
1517
-
1518
- await tx
1519
- .getRepository(ReleaseGood)
1520
- .update({ id: In(foundReleaseGoods.map(rg => rg.id)) }, { status: ORDER_STATUS.PENDING_RECEIVE, updater: user })
1521
-
1522
- await tx
1523
- .getRepository(OrderInventory)
1524
- .update(
1525
- { id: In(foundOrderInventories.map(oi => oi.id)) },
1526
- { status: ORDER_INVENTORY_STATUS.PENDING_RECEIVE, updater: user }
1527
- )
1528
-
1529
- if (context?.state?.type != 'api') {
1530
- const users: any[] = await tx
1531
- .getRepository('users_roles')
1532
- .createQueryBuilder('ur')
1533
- .select('ur.users_id', 'id')
1534
- .where(qb => {
1535
- const subQuery = qb
1536
- .subQuery()
1537
- .select('role.id')
1538
- .from(Role, 'role')
1539
- .where("role.name = 'Office Admin'")
1540
- .andWhere('role.domain_id = :domain', { domain: domain.id })
1541
- .getQuery()
1542
- return 'ur.roles_id IN ' + subQuery
1543
- })
1544
- .getRawMany()
1545
-
1546
- // send notification to Office Admin Users
1547
- if (users?.length && context.header?.referer) {
1548
- const receivers: any[] = users.map(user => user.id)
1549
- const message = {
1550
- title: `New Release Order from ${customerBizplace.name}`,
1551
- body: `New incoming bulk release orders are pending for receiving`,
1552
- url: context.header.referer,
1553
- data: { url: context.header.referer }
1554
- }
1555
-
1556
- /**
1557
- * @notes Temporary off sendNotification due to suspect of causing wms down
1558
- */
1559
-
1560
- // await sendNotification({
1561
- // receivers,
1562
- // message
1563
- // })
1564
- }
1565
- }
1566
-
1567
- return Promise.all(
1568
- foundReleaseGoods.map(async (releaseGood: ReleaseGood) => {
1569
- return {
1570
- ...releaseGood,
1571
- orderInventories: await tx
1572
- .getRepository(OrderInventory)
1573
- .find({ where: { releaseGood: { id: releaseGood.id } } }) /* CONFIRMME regarding TYPEORM */,
1574
- status: ORDER_STATUS.PENDING_RECEIVE,
1575
- updater: user
1576
- }
1577
- })
1578
- )
1579
- }
1580
-
1581
- function extractRawReleaseGoods(rawReleaseGoods): Partial<ReleaseGood[]> {
1582
- return rawReleaseGoods.reduce((releaseGoods, item) => {
1583
- const idx: number = releaseGoods.findIndex(rg => {
1584
- // consider these attributes if they are exist in "item"
1585
- const comparison = [
1586
- 'refNo2',
1587
- 'refNo3',
1588
- 'attentionTo',
1589
- 'phone1',
1590
- 'deliveryAddress1',
1591
- 'deliveryAddress2',
1592
- 'deliveryAddress3',
1593
- 'deliveryAddress4',
1594
- 'postalCode'
1595
- ]
1596
-
1597
- let a: any = {},
1598
- b: any = {}
1599
-
1600
- comparison.forEach(cc => {
1601
- if (item[cc]) {
1602
- a[cc] = item[cc]
1603
- b[cc] = rg[cc]
1604
- }
1605
- })
1606
-
1607
- a = JSON.stringify(Object.fromEntries(Object.entries(a).sort()))
1608
- b = JSON.stringify(Object.fromEntries(Object.entries(b).sort()))
1609
-
1610
- return rg.refNo == item.refNo && rg.releaseDate == item.releaseDate && a === b
1611
- })
1612
-
1613
- if (idx >= 0) {
1614
- const duplicateSkuIdx: number = releaseGoods[idx].orderInventories.findIndex(
1615
- oi => oi.sku === item.sku && oi.packingType === item.packingType && oi.packingSize === item.packingSize
1616
- )
1617
-
1618
- // if there is duplicated SKU, merge them and sum up the releaseQty
1619
- if (duplicateSkuIdx >= 0) {
1620
- releaseGoods[idx].orderInventories[duplicateSkuIdx].releaseQty += item.releaseQty
1621
- } else {
1622
- releaseGoods[idx].orderInventories.push({
1623
- sku: item.sku,
1624
- productId: item.productId,
1625
- packingType: item.packingType,
1626
- packingSize: item.packingSize,
1627
- uom: item.uom,
1628
- releaseQty: item.releaseQty,
1629
- releaseUomValue: item.releaseUomValue
1630
- })
1631
- }
1632
- } else {
1633
- releaseGoods.push({
1634
- releaseDate: item.releaseDate,
1635
- refNo: item.refNo,
1636
- refNo2: item.refNo2,
1637
- refNo3: item.refNo3,
1638
- attentionTo: item.attentionTo,
1639
- phone1: item.phone1,
1640
- deliveryAddress1: item.deliveryAddress1,
1641
- deliveryAddress2: item.deliveryAddress2,
1642
- deliveryAddress3: item.deliveryAddress3,
1643
- deliveryAddress4: item.deliveryAddress4,
1644
- billingAddress: item.billingAddress,
1645
- billingCity: item.billingPostalCode,
1646
- billingState: item.billingState,
1647
- billingCountry: item.billingCountry,
1648
- billingPostalCode: item.billingPostalCode,
1649
- city: item.city,
1650
- postalCode: item.postalCode,
1651
- state: item.state,
1652
- country: item.country,
1653
- orderInventories: [
1654
- {
1655
- sku: item.sku,
1656
- productId: item.productId,
1657
- packingType: item.packingType,
1658
- packingSize: item.packingSize,
1659
- uom: item.uom,
1660
- releaseQty: item.releaseQty,
1661
- releaseUomValue: item.releaseUomValue
1662
- }
1663
- ]
1664
- })
1665
- }
1666
-
1667
- return releaseGoods
1668
- }, [])
1669
- }
1670
-
1671
- function formRawReleaseGoods(releaseGood, errorMsg) {
1672
- let rawReleaseGoods = []
1673
- for (let i = 0, l = releaseGood.orderInventories.length; i < l; i++) {
1674
- let rawReleaseGood = {
1675
- ...releaseGood,
1676
- ...releaseGood.orderInventories[i],
1677
- errorMsg
1678
- }
1679
-
1680
- delete rawReleaseGood.orderInventories
1681
- delete rawReleaseGood.product
1682
-
1683
- rawReleaseGoods.push(rawReleaseGood)
1684
- }
1685
- return rawReleaseGoods
1686
- }