@things-factory/sales-base 8.0.2 → 8.0.5

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 (178) hide show
  1. package/dist-server/tsconfig.tsbuildinfo +1 -1
  2. package/package.json +12 -12
  3. package/server/constants/attachment-type.ts +0 -9
  4. package/server/constants/index.ts +0 -7
  5. package/server/constants/load-type.ts +0 -4
  6. package/server/constants/order.ts +0 -203
  7. package/server/constants/product-group-type.ts +0 -4
  8. package/server/constants/release-good.ts +0 -9
  9. package/server/constants/transfer-order-type.ts +0 -6
  10. package/server/constants/validation-error-code.ts +0 -3
  11. package/server/constants/vas-target-type.ts +0 -25
  12. package/server/controllers/ecommerce/ecommerce-controller.ts +0 -122
  13. package/server/controllers/ecommerce/index.ts +0 -2
  14. package/server/controllers/ecommerce/sellercraft-controller.ts +0 -182
  15. package/server/controllers/index.ts +0 -2
  16. package/server/controllers/order-controller.ts +0 -296
  17. package/server/errors/index.ts +0 -1
  18. package/server/errors/validation-error.ts +0 -25
  19. package/server/index.ts +0 -5
  20. package/server/migrations/index.ts +0 -9
  21. package/server/service/arrival-notice/arrival-notice-mutation.ts +0 -1152
  22. package/server/service/arrival-notice/arrival-notice-query.ts +0 -549
  23. package/server/service/arrival-notice/arrival-notice-types.ts +0 -310
  24. package/server/service/arrival-notice/arrival-notice.ts +0 -202
  25. package/server/service/arrival-notice/index.ts +0 -9
  26. package/server/service/claim/claim-mutation.ts +0 -308
  27. package/server/service/claim/claim-query.ts +0 -122
  28. package/server/service/claim/claim-types.ts +0 -130
  29. package/server/service/claim/claim.ts +0 -140
  30. package/server/service/claim/index.ts +0 -9
  31. package/server/service/claim-detail/claim-detail-mutation.ts +0 -102
  32. package/server/service/claim-detail/claim-detail-query.ts +0 -55
  33. package/server/service/claim-detail/claim-detail-types.ts +0 -47
  34. package/server/service/claim-detail/claim-detail.ts +0 -69
  35. package/server/service/claim-detail/index.ts +0 -9
  36. package/server/service/claim-order/claim-order-mutation.ts +0 -101
  37. package/server/service/claim-order/claim-order-query.ts +0 -47
  38. package/server/service/claim-order/claim-order-types.ts +0 -35
  39. package/server/service/claim-order/claim-order.ts +0 -81
  40. package/server/service/claim-order/index.ts +0 -9
  41. package/server/service/collection-order/collection-order-mutation.ts +0 -245
  42. package/server/service/collection-order/collection-order-query.ts +0 -97
  43. package/server/service/collection-order/collection-order-types.ts +0 -165
  44. package/server/service/collection-order/collection-order.ts +0 -135
  45. package/server/service/collection-order/index.ts +0 -9
  46. package/server/service/delivery-order/delivery-order-mutation.ts +0 -967
  47. package/server/service/delivery-order/delivery-order-query.ts +0 -631
  48. package/server/service/delivery-order/delivery-order-types.ts +0 -268
  49. package/server/service/delivery-order/delivery-order.ts +0 -258
  50. package/server/service/delivery-order/index.ts +0 -9
  51. package/server/service/draft-release-good/draft-release-good-mutation.ts +0 -765
  52. package/server/service/draft-release-good/draft-release-good-query.ts +0 -354
  53. package/server/service/draft-release-good/draft-release-good-type.ts +0 -261
  54. package/server/service/draft-release-good/draft-release-good.ts +0 -284
  55. package/server/service/draft-release-good/index.ts +0 -9
  56. package/server/service/goods-receival-note/goods-receival-note-mutation.ts +0 -129
  57. package/server/service/goods-receival-note/goods-receival-note-query.ts +0 -280
  58. package/server/service/goods-receival-note/goods-receival-note-types.ts +0 -105
  59. package/server/service/goods-receival-note/goods-receival-note.ts +0 -127
  60. package/server/service/goods-receival-note/index.ts +0 -9
  61. package/server/service/index.ts +0 -238
  62. package/server/service/inventory-check/index.ts +0 -9
  63. package/server/service/inventory-check/inventory-check-mutation.ts +0 -149
  64. package/server/service/inventory-check/inventory-check-query.ts +0 -48
  65. package/server/service/inventory-check/inventory-check-types.ts +0 -48
  66. package/server/service/inventory-check/inventory-check.ts +0 -90
  67. package/server/service/invoice/index.ts +0 -9
  68. package/server/service/invoice/invoice-mutation.ts +0 -95
  69. package/server/service/invoice/invoice-query.ts +0 -53
  70. package/server/service/invoice/invoice-types.ts +0 -279
  71. package/server/service/invoice/invoice.ts +0 -230
  72. package/server/service/invoice-product/index.ts +0 -9
  73. package/server/service/invoice-product/invoice-product-mutation.ts +0 -54
  74. package/server/service/invoice-product/invoice-product-query.ts +0 -54
  75. package/server/service/invoice-product/invoice-product-types.ts +0 -84
  76. package/server/service/invoice-product/invoice-product.ts +0 -92
  77. package/server/service/job-sheet/index.ts +0 -9
  78. package/server/service/job-sheet/job-sheet-mutation.ts +0 -92
  79. package/server/service/job-sheet/job-sheet-query.ts +0 -112
  80. package/server/service/job-sheet/job-sheet-types.ts +0 -78
  81. package/server/service/job-sheet/job-sheet.ts +0 -102
  82. package/server/service/manifest/index.ts +0 -6
  83. package/server/service/manifest/manifest-mutation.ts +0 -190
  84. package/server/service/manifest/manifest-query.ts +0 -149
  85. package/server/service/manifest/manifest-type.ts +0 -84
  86. package/server/service/manifest/manifest.ts +0 -114
  87. package/server/service/order-inventory/index.ts +0 -9
  88. package/server/service/order-inventory/order-inventory-mutation.ts +0 -54
  89. package/server/service/order-inventory/order-inventory-query.ts +0 -722
  90. package/server/service/order-inventory/order-inventory-types.ts +0 -238
  91. package/server/service/order-inventory/order-inventory.ts +0 -401
  92. package/server/service/order-product/index.ts +0 -9
  93. package/server/service/order-product/order-product-mutation.ts +0 -48
  94. package/server/service/order-product/order-product-query.ts +0 -89
  95. package/server/service/order-product/order-product-types.ts +0 -335
  96. package/server/service/order-product/order-product.ts +0 -362
  97. package/server/service/order-tote/index.ts +0 -9
  98. package/server/service/order-tote/order-tote-mutation.ts +0 -31
  99. package/server/service/order-tote/order-tote-query.ts +0 -112
  100. package/server/service/order-tote/order-tote-types.ts +0 -47
  101. package/server/service/order-tote/order-tote.ts +0 -73
  102. package/server/service/order-tote-item/index.ts +0 -9
  103. package/server/service/order-tote-item/order-tote-item-mutation.ts +0 -31
  104. package/server/service/order-tote-item/order-tote-item-query.ts +0 -82
  105. package/server/service/order-tote-item/order-tote-item-types.ts +0 -56
  106. package/server/service/order-tote-item/order-tote-item.ts +0 -72
  107. package/server/service/order-tote-seal/index.ts +0 -9
  108. package/server/service/order-tote-seal/order-tote-seal-mutation.ts +0 -31
  109. package/server/service/order-tote-seal/order-tote-seal-query.ts +0 -59
  110. package/server/service/order-tote-seal/order-tote-seal-types.ts +0 -41
  111. package/server/service/order-tote-seal/order-tote-seal.ts +0 -46
  112. package/server/service/order-vas/index.ts +0 -9
  113. package/server/service/order-vas/order-vas-mutation.ts +0 -20
  114. package/server/service/order-vas/order-vas-query.ts +0 -72
  115. package/server/service/order-vas/order-vas-types.ts +0 -159
  116. package/server/service/order-vas/order-vas.ts +0 -207
  117. package/server/service/others/index.ts +0 -5
  118. package/server/service/others/other-query.ts +0 -563
  119. package/server/service/others/other-types.ts +0 -115
  120. package/server/service/purchase-order/index.ts +0 -9
  121. package/server/service/purchase-order/purchase-order-mutation.ts +0 -458
  122. package/server/service/purchase-order/purchase-order-query.ts +0 -90
  123. package/server/service/purchase-order/purchase-order-types.ts +0 -154
  124. package/server/service/purchase-order/purchase-order.ts +0 -172
  125. package/server/service/purchase-order-other-charge/index.ts +0 -9
  126. package/server/service/purchase-order-other-charge/purchase-order-other-charge-mutation.ts +0 -31
  127. package/server/service/purchase-order-other-charge/purchase-order-other-charge-query.ts +0 -52
  128. package/server/service/purchase-order-other-charge/purchase-order-other-charge-types.ts +0 -44
  129. package/server/service/purchase-order-other-charge/purchase-order-other-charge.ts +0 -68
  130. package/server/service/release-good/index.ts +0 -9
  131. package/server/service/release-good/release-good-mutation.ts +0 -1686
  132. package/server/service/release-good/release-good-query.ts +0 -980
  133. package/server/service/release-good/release-good-types.ts +0 -662
  134. package/server/service/release-good/release-good.ts +0 -490
  135. package/server/service/retail-replenishment-order/index.ts +0 -9
  136. package/server/service/retail-replenishment-order/retail-replenishment-order-mutation.ts +0 -382
  137. package/server/service/retail-replenishment-order/retail-replenishment-order-query.ts +0 -54
  138. package/server/service/retail-replenishment-order/retail-replenishment-order-types.ts +0 -101
  139. package/server/service/retail-replenishment-order/retail-replenishment-order.ts +0 -115
  140. package/server/service/return-order/index.ts +0 -9
  141. package/server/service/return-order/return-order-mutation.ts +0 -516
  142. package/server/service/return-order/return-order-query.ts +0 -226
  143. package/server/service/return-order/return-order-types.ts +0 -196
  144. package/server/service/return-order/return-order.ts +0 -127
  145. package/server/service/reverse-kitting-order/index.ts +0 -9
  146. package/server/service/reverse-kitting-order/reverse-kitting-order-mutation.ts +0 -500
  147. package/server/service/reverse-kitting-order/reverse-kitting-order-query.ts +0 -197
  148. package/server/service/reverse-kitting-order/reverse-kitting-order-type.ts +0 -173
  149. package/server/service/reverse-kitting-order/reverse-kitting-order.ts +0 -121
  150. package/server/service/reverse-kitting-order-inventory/index.ts +0 -9
  151. package/server/service/reverse-kitting-order-inventory/reverse-kitting-order-inventory-mutation.ts +0 -129
  152. package/server/service/reverse-kitting-order-inventory/reverse-kitting-order-inventory-query.ts +0 -52
  153. package/server/service/reverse-kitting-order-inventory/reverse-kitting-order-inventory-type.ts +0 -95
  154. package/server/service/reverse-kitting-order-inventory/reverse-kitting-order-inventory.ts +0 -143
  155. package/server/service/shipping-order/index.ts +0 -9
  156. package/server/service/shipping-order/shipping-order-mutation.ts +0 -61
  157. package/server/service/shipping-order/shipping-order-query.ts +0 -61
  158. package/server/service/shipping-order/shipping-order-types.ts +0 -89
  159. package/server/service/shipping-order/shipping-order.ts +0 -129
  160. package/server/service/transfer-order/index.ts +0 -9
  161. package/server/service/transfer-order/transfer-order-mutation.ts +0 -309
  162. package/server/service/transfer-order/transfer-order-query.ts +0 -66
  163. package/server/service/transfer-order/transfer-order-types.ts +0 -97
  164. package/server/service/transfer-order/transfer-order.ts +0 -117
  165. package/server/service/vas/index.ts +0 -9
  166. package/server/service/vas/vas-mutation.ts +0 -106
  167. package/server/service/vas/vas-query.ts +0 -60
  168. package/server/service/vas/vas-types.ts +0 -71
  169. package/server/service/vas/vas.ts +0 -77
  170. package/server/service/vas-order/index.ts +0 -9
  171. package/server/service/vas-order/vas-order-mutation.ts +0 -259
  172. package/server/service/vas-order/vas-order-query.ts +0 -119
  173. package/server/service/vas-order/vas-order-types.ts +0 -49
  174. package/server/service/vas-order/vas-order.ts +0 -81
  175. package/server/utils/datetime-util.ts +0 -54
  176. package/server/utils/index.ts +0 -3
  177. package/server/utils/inventory-util.ts +0 -1155
  178. 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
- }