@things-factory/sales-base 4.0.9 → 4.0.13

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 (92) hide show
  1. package/dist-server/constants/order.js +9 -1
  2. package/dist-server/constants/order.js.map +1 -1
  3. package/dist-server/constants/validation-error-code.js +2 -1
  4. package/dist-server/constants/validation-error-code.js.map +1 -1
  5. package/dist-server/controllers/ecommerce/sellercraft-controller.js +3 -3
  6. package/dist-server/controllers/ecommerce/sellercraft-controller.js.map +1 -1
  7. package/dist-server/service/arrival-notice/arrival-notice-mutation.js +21 -0
  8. package/dist-server/service/arrival-notice/arrival-notice-mutation.js.map +1 -1
  9. package/dist-server/service/arrival-notice/arrival-notice-query.js +74 -77
  10. package/dist-server/service/arrival-notice/arrival-notice-query.js.map +1 -1
  11. package/dist-server/service/delivery-order/delivery-order-query.js +21 -5
  12. package/dist-server/service/delivery-order/delivery-order-query.js.map +1 -1
  13. package/dist-server/service/goods-receival-note/goods-receival-note-query.js +93 -43
  14. package/dist-server/service/goods-receival-note/goods-receival-note-query.js.map +1 -1
  15. package/dist-server/service/index.js +4 -0
  16. package/dist-server/service/index.js.map +1 -1
  17. package/dist-server/service/manifest/index.js +9 -0
  18. package/dist-server/service/manifest/index.js.map +1 -0
  19. package/dist-server/service/manifest/manifest-mutation.js +111 -0
  20. package/dist-server/service/manifest/manifest-mutation.js.map +1 -0
  21. package/dist-server/service/manifest/manifest-query.js +128 -0
  22. package/dist-server/service/manifest/manifest-query.js.map +1 -0
  23. package/dist-server/service/manifest/manifest-type.js +125 -0
  24. package/dist-server/service/manifest/manifest-type.js.map +1 -0
  25. package/dist-server/service/manifest/manifest.js +122 -0
  26. package/dist-server/service/manifest/manifest.js.map +1 -0
  27. package/dist-server/service/order-inventory/order-inventory-mutation.js +24 -0
  28. package/dist-server/service/order-inventory/order-inventory-mutation.js.map +1 -1
  29. package/dist-server/service/order-inventory/order-inventory-query.js +20 -19
  30. package/dist-server/service/order-inventory/order-inventory-query.js.map +1 -1
  31. package/dist-server/service/order-inventory/order-inventory-types.js +17 -13
  32. package/dist-server/service/order-inventory/order-inventory-types.js.map +1 -1
  33. package/dist-server/service/order-inventory/order-inventory.js +24 -2
  34. package/dist-server/service/order-inventory/order-inventory.js.map +1 -1
  35. package/dist-server/service/others/other-query.js +1 -0
  36. package/dist-server/service/others/other-query.js.map +1 -1
  37. package/dist-server/service/others/other-types.js +4 -0
  38. package/dist-server/service/others/other-types.js.map +1 -1
  39. package/dist-server/service/release-good/release-good-mutation.js +393 -1
  40. package/dist-server/service/release-good/release-good-mutation.js.map +1 -1
  41. package/dist-server/service/release-good/release-good-query.js +160 -0
  42. package/dist-server/service/release-good/release-good-query.js.map +1 -1
  43. package/dist-server/service/release-good/release-good-types.js +34 -2
  44. package/dist-server/service/release-good/release-good-types.js.map +1 -1
  45. package/dist-server/service/release-good/release-good.js +28 -1
  46. package/dist-server/service/release-good/release-good.js.map +1 -1
  47. package/dist-server/service/reverse-kitting-order/reverse-kitting-order-mutation.js +110 -30
  48. package/dist-server/service/reverse-kitting-order/reverse-kitting-order-mutation.js.map +1 -1
  49. package/dist-server/service/reverse-kitting-order/reverse-kitting-order-query.js +94 -21
  50. package/dist-server/service/reverse-kitting-order/reverse-kitting-order-query.js.map +1 -1
  51. package/dist-server/service/reverse-kitting-order/reverse-kitting-order-type.js +144 -1
  52. package/dist-server/service/reverse-kitting-order/reverse-kitting-order-type.js.map +1 -1
  53. package/dist-server/service/reverse-kitting-order-inventory/reverse-kitting-order-inventory-mutation.js +17 -7
  54. package/dist-server/service/reverse-kitting-order-inventory/reverse-kitting-order-inventory-mutation.js.map +1 -1
  55. package/dist-server/utils/inventory-util.js +26 -7
  56. package/dist-server/utils/inventory-util.js.map +1 -1
  57. package/dist-server/utils/order-no-generator.js +35 -31
  58. package/dist-server/utils/order-no-generator.js.map +1 -1
  59. package/package.json +12 -12
  60. package/server/constants/index.ts +1 -1
  61. package/server/constants/order.ts +10 -0
  62. package/server/constants/validation-error-code.ts +3 -2
  63. package/server/controllers/ecommerce/sellercraft-controller.ts +4 -3
  64. package/server/service/arrival-notice/arrival-notice-mutation.ts +20 -0
  65. package/server/service/arrival-notice/arrival-notice-query.ts +82 -78
  66. package/server/service/delivery-order/delivery-order-query.ts +26 -7
  67. package/server/service/goods-receival-note/goods-receival-note-query.ts +116 -53
  68. package/server/service/index.ts +4 -0
  69. package/server/service/manifest/index.ts +6 -0
  70. package/server/service/manifest/manifest-mutation.ts +102 -0
  71. package/server/service/manifest/manifest-query.ts +99 -0
  72. package/server/service/manifest/manifest-type.ts +78 -0
  73. package/server/service/manifest/manifest.ts +103 -0
  74. package/server/service/order-inventory/order-inventory-mutation.ts +26 -1
  75. package/server/service/order-inventory/order-inventory-query.ts +17 -18
  76. package/server/service/order-inventory/order-inventory-types.ts +15 -10
  77. package/server/service/order-inventory/order-inventory.ts +24 -5
  78. package/server/service/others/other-query.ts +2 -6
  79. package/server/service/others/other-types.ts +3 -0
  80. package/server/service/release-good/release-good-mutation.ts +557 -0
  81. package/server/service/release-good/release-good-query.ts +197 -2
  82. package/server/service/release-good/release-good-types.ts +31 -7
  83. package/server/service/release-good/release-good.ts +26 -0
  84. package/server/service/reverse-kitting-order/reverse-kitting-order-mutation.ts +145 -35
  85. package/server/service/reverse-kitting-order/reverse-kitting-order-query.ts +103 -19
  86. package/server/service/reverse-kitting-order/reverse-kitting-order-type.ts +106 -1
  87. package/server/service/reverse-kitting-order-inventory/reverse-kitting-order-inventory-mutation.ts +31 -14
  88. package/server/utils/inventory-util.ts +30 -7
  89. package/server/utils/order-no-generator.ts +43 -36
  90. package/dist-server/middlewares/index.js +0 -1
  91. package/dist-server/middlewares/index.js.map +0 -1
  92. package/server/middlewares/index.ts +0 -0
@@ -6,6 +6,7 @@ import { Attachment, createAttachments } from '@things-factory/attachment-base'
6
6
  import { Partner, Role, User } from '@things-factory/auth-base'
7
7
  import {
8
8
  Bizplace,
9
+ getCompanyBizplace,
9
10
  getDomainUsers,
10
11
  getMyBizplace,
11
12
  getOutletBizplace,
@@ -43,6 +44,7 @@ import {
43
44
  PRODUCT_GROUP_TYPE
44
45
  } from '../../constants'
45
46
  import { EcommerceController, SellercraftController } from '../../controllers'
47
+ import { ValidationError } from '../../errors'
46
48
  import { InventoryUtil, OrderNoGenerator } from '../../utils'
47
49
  import { confirmArrivalNoticeFunction, deleteArrivalNotice } from '../arrival-notice/arrival-notice-mutation'
48
50
  import { ReleaseGood } from './release-good'
@@ -91,6 +93,51 @@ export class ReleaseGoodMutation {
91
93
  return createdReleaseGood
92
94
  }
93
95
 
96
+ @Directive('@privilege(category: "order_customer", privilege: "mutation")')
97
+ @Directive('@transaction')
98
+ @Mutation(returns => ReleaseGood)
99
+ async updateReleaseGoodDetails(
100
+ @Ctx() context: any,
101
+ @Arg('releaseGood', type => ReleaseGoodPatch, { nullable: true }) releaseGood?: ReleaseGoodPatch,
102
+ @Arg('shippingOrder', type => ShippingOrderPatch, { nullable: true }) shippingOrder?: ShippingOrderPatch
103
+ ): Promise<ReleaseGood> {
104
+ const { tx, domain, user } = context.state
105
+ let foundReleaseGood = await tx.getRepository(ReleaseGood).findOne({
106
+ where: { name: releaseGood.name, domain },
107
+ relations: ['shippingOrder']
108
+ })
109
+
110
+ if (!foundReleaseGood) {
111
+ throw new Error(`Release order ${releaseGood.name} is not found.`)
112
+ }
113
+
114
+ // case to update existing shippingOrder
115
+ if (foundReleaseGood.shippingOrder && shippingOrder) {
116
+ await tx.getRepository(ShippingOrder).update(foundReleaseGood.shippingOrder.id, shippingOrder)
117
+ }
118
+ // case for new shippingOrder
119
+ else if (!foundReleaseGood.shippingOrder && shippingOrder) {
120
+ let newShippingOrder: ShippingOrder = await tx.getRepository(ShippingOrder).save({
121
+ ...shippingOrder,
122
+ name: OrderNoGenerator.shippingOrder(),
123
+ domain,
124
+ bizplace: await getMyBizplace(domain, user),
125
+ status: ORDER_STATUS.PENDING,
126
+ creator: user,
127
+ updater: user
128
+ })
129
+
130
+ releaseGood.shippingOrder = newShippingOrder
131
+ }
132
+
133
+ foundReleaseGood = await tx.getRepository(ReleaseGood).save({
134
+ ...foundReleaseGood,
135
+ ...releaseGood
136
+ })
137
+
138
+ return foundReleaseGood
139
+ }
140
+
94
141
  @Directive('@privilege(category: "order_customer", privilege: "mutation")')
95
142
  @Directive('@transaction')
96
143
  @Mutation(returns => ReleaseGood)
@@ -159,6 +206,71 @@ export class ReleaseGoodMutation {
159
206
 
160
207
  return receivedRO
161
208
  }
209
+
210
+ @Directive('@transaction')
211
+ @Mutation(returns => [ReleaseGood])
212
+ async bulkAddReleaseGoods(
213
+ @Ctx() context: any,
214
+ @Arg('rawReleaseGoods', type => [NewReleaseGood], { nullable: true }) rawReleaseGoods: NewReleaseGood[],
215
+ @Arg('bizplaceId', type => String) bizplaceId: string
216
+ ): Promise<ReleaseGood[]> {
217
+ const { domain, user, tx } = context.state
218
+
219
+ if (!bizplaceId) throw new Error('company ID is not provided')
220
+
221
+ let createdReleaseGoods: ReleaseGood[] = []
222
+ const settingRepo: Repository<Setting> = tx?.getRepository(Setting) || getRepository(Setting)
223
+
224
+ const roNoSetting: Setting = await settingRepo.findOne({
225
+ where: {
226
+ domain,
227
+ name: ORDER_NUMBER_SETTING_KEY.RO_NUMBER_RULE
228
+ }
229
+ })
230
+
231
+ let releaseGoods: Partial<ReleaseGood[]> = extractRawReleaseGoods(rawReleaseGoods)
232
+
233
+ for (let i = 0, l = releaseGoods.length; i < l; i++) {
234
+ // generate release good by group to avoid duplication
235
+ // if this function is called simultaneously by different users
236
+ let availableItems: any[] = await bulkReleaseGoodsAvailableItemsFunction(
237
+ [...releaseGoods[i].orderInventories],
238
+ bizplaceId,
239
+ context,
240
+ tx
241
+ )
242
+
243
+ if (availableItems.some(item => !item.releaseQty || item.releaseQty > item.assignedQty))
244
+ throw new ValidationError({
245
+ ...ValidationError.ERROR_CODES.INSUFFICIENT_STOCK,
246
+ detail: { data: JSON.stringify(availableItems) }
247
+ })
248
+
249
+ // update orderInventories if availableItems are valid
250
+ releaseGoods[i].orderInventories = availableItems
251
+
252
+ const createdReleaseGood: ReleaseGood = await bulkGenerateReleaseGoods(
253
+ releaseGoods[i],
254
+ bizplaceId,
255
+ roNoSetting,
256
+ domain,
257
+ user,
258
+ tx
259
+ )
260
+
261
+ createdReleaseGoods.push(createdReleaseGood)
262
+ }
263
+
264
+ let confirmedReleaseGoods: ReleaseGood[] = await bulkConfirmReleaseGoods(
265
+ createdReleaseGoods.map(rg => rg.name),
266
+ domain,
267
+ user,
268
+ context,
269
+ tx
270
+ )
271
+
272
+ return confirmedReleaseGoods
273
+ }
162
274
  }
163
275
 
164
276
  export async function deleteReleaseGood(tx: EntityManager, name: string, user: User, domain: Domain): Promise<boolean> {
@@ -571,6 +683,193 @@ export async function generateReleaseGoodFunction(
571
683
  }
572
684
  }
573
685
 
686
+ export async function bulkReleaseGoodsAvailableItemsFunction(
687
+ rawReleaseGoods: any[],
688
+ bizplaceId: string,
689
+ context: any,
690
+ tx?: EntityManager
691
+ ): Promise<any[]> {
692
+ const { domain }: { domain: Domain } = context.state
693
+ const companyBizplaceId: Bizplace = await getCompanyBizplace(null, null, bizplaceId)
694
+
695
+ if (!rawReleaseGoods) return
696
+
697
+ const json_oi = JSON.stringify(
698
+ rawReleaseGoods.map(raw => {
699
+ return {
700
+ sku: raw.sku,
701
+ packing_type: raw.packingType,
702
+ packing_size: raw.packingSize,
703
+ uom: raw.uom,
704
+ release_qty: raw.releaseQty
705
+ }
706
+ })
707
+ )
708
+
709
+ await tx.query(
710
+ `
711
+ CREATE TEMP TABLE temp_order_products(
712
+ product_id VARCHAR(50),
713
+ sku VARCHAR(150),
714
+ packing_type VARCHAR(50),
715
+ packing_size INT,
716
+ uom VARCHAR(10),
717
+ release_qty INT
718
+ );
719
+ `
720
+ )
721
+
722
+ await tx.query(
723
+ `
724
+ INSERT INTO temp_order_products
725
+ SELECT p.id AS product_id, js.sku,
726
+ CASE WHEN js.packing_type NOTNULL AND js.packing_size NOTNULL THEN js.packing_type ELSE pd.packing_type END,
727
+ CASE WHEN js.packing_type NOTNULL AND js.packing_size NOTNULL THEN js.packing_size ELSE pd.packing_size END,
728
+ CASE WHEN js.uom NOTNULL THEN js.uom ELSE pd.uom END,
729
+ js.release_qty
730
+ FROM JSON_POPULATE_RECORDSET(NULL::temp_order_products,'${json_oi}') js
731
+ LEFT JOIN products p ON js.sku = p.sku AND p.bizplace_id = $1
732
+ LEFT JOIN product_details pd ON p.id = pd.product_id AND pd.is_default = TRUE;
733
+ `,
734
+ [companyBizplaceId.id]
735
+ )
736
+
737
+ let availableItems = await tx.query(
738
+ `
739
+ SELECT i.product_id, foo.sku, i.batch_id, i.packing_type, i.packing_size, i.uom,
740
+ SUM(i.qty - COALESCE(i.locked_qty, 0)) - COALESCE(
741
+ (
742
+ SELECT SUM(oi.release_qty) FROM order_inventories oi
743
+ WHERE (
744
+ oi.status = 'PENDING'
745
+ OR oi.status = 'PENDING_RECEIVE'
746
+ OR oi.status = 'PENDING_WORKSHEET'
747
+ OR oi.status = 'PENDING_SPLIT'
748
+ )
749
+ AND oi.inventory_id IS null
750
+ AND oi.product_id = i.product_id::uuid
751
+ AND oi.packing_type = i.packing_type
752
+ AND oi.uom = i.uom
753
+ AND oi.domain_id = $1
754
+ AND oi.bizplace_id = $2
755
+ ), 0) as "remain_qty",
756
+ SUM(i.uom_value - COALESCE(i.locked_uom_value, 0)) - COALESCE(
757
+ (
758
+ SELECT SUM(oi.release_uom_value) FROM order_inventories oi
759
+ WHERE (
760
+ oi.status = 'PENDING'
761
+ OR oi.status = 'PENDING_RECEIVE'
762
+ OR oi.status = 'PENDING_WORKSHEET'
763
+ OR oi.status = 'PENDING_SPLIT'
764
+ )
765
+ AND oi.inventory_id IS null
766
+ AND oi.product_id = i.product_id::uuid
767
+ AND oi.packing_type = i.packing_type
768
+ AND oi.uom = i.uom
769
+ AND oi.domain_id = $1
770
+ AND oi.bizplace_id = $2
771
+ ), 0) as "remain_uom_value"
772
+ FROM inventories i
773
+ INNER JOIN (
774
+ SELECT top.product_id, top.sku, top.packing_type, top.packing_size, top.uom
775
+ FROM temp_order_products top
776
+ GROUP BY top.product_id, top.sku, top.packing_type, top.packing_size, top.uom
777
+ ) AS foo
778
+ ON i.product_id = foo.product_id::uuid
779
+ AND i.packing_type = foo.packing_type
780
+ AND i.packing_size = foo.packing_size
781
+ AND i.uom = foo.uom
782
+ AND i.domain_id = $1
783
+ AND i.bizplace_id = $2
784
+ GROUP BY i.product_id, foo.sku, i.batch_id, i.packing_type, i.packing_size, i.uom
785
+ ORDER BY foo.sku, remain_qty
786
+ `,
787
+ [domain.id, bizplaceId]
788
+ )
789
+
790
+ await tx.query('DROP TABLE temp_order_products')
791
+
792
+ availableItems = availableItems.map(item => {
793
+ return {
794
+ productId: item.product_id,
795
+ sku: item.sku,
796
+ batchId: item.batch_id,
797
+ packingType: item.packing_type,
798
+ packingSize: item.packing_size,
799
+ uom: item.uom,
800
+ remainQty: item.remain_qty,
801
+ remainUomValue: item.remain_uom_value
802
+ }
803
+ })
804
+
805
+ return _extractData(rawReleaseGoods, availableItems)
806
+ }
807
+
808
+ function _extractData(rawData, validatedData) {
809
+ return rawData.map(raw => {
810
+ const idx = validatedData.findIndex(val => {
811
+ const comparison = ['packingType', 'packingSize', 'uom']
812
+
813
+ let a: any = {},
814
+ b: any = {}
815
+
816
+ comparison.forEach(cc => {
817
+ if (raw[cc]) {
818
+ a[cc] = raw[cc]
819
+ b[cc] = val[cc]
820
+ }
821
+ })
822
+
823
+ a = JSON.stringify(Object.fromEntries(Object.entries(a).sort()))
824
+ b = JSON.stringify(Object.fromEntries(Object.entries(b).sort()))
825
+
826
+ return val.sku == raw.sku && a === b
827
+ })
828
+
829
+ let releaseUomValue = 0
830
+
831
+ // if sku is matched, assign qty and product id
832
+ if (idx >= 0) {
833
+ // assign qty to rawData as much as possible
834
+ releaseUomValue =
835
+ (Math.round((validatedData[idx]?.remainUomValue / validatedData[idx]?.remainQty) * 100) / 100) * raw.releaseQty
836
+
837
+ raw.assignedQty =
838
+ validatedData[idx].remainQty >= raw.releaseQty
839
+ ? raw.releaseQty > 0
840
+ ? raw.releaseQty
841
+ : 0
842
+ : validatedData[idx].remainQty
843
+
844
+ raw.assignedUomValue =
845
+ validatedData[idx].remainUomValue >= releaseUomValue
846
+ ? releaseUomValue > 0
847
+ ? releaseUomValue
848
+ : 0
849
+ : validatedData[idx].remainUomValue
850
+
851
+ // deduct qty & uomValue from validateData
852
+ validatedData[idx].remainQty -= raw.assignedQty
853
+ validatedData[idx].remainUomValue -= raw.assignedUomValue
854
+
855
+ raw.productId = validatedData[idx].productId
856
+ raw.packingType = validatedData[idx].packingType
857
+ raw.packingSize = validatedData[idx].packingSize
858
+ raw.uom = validatedData[idx].uom
859
+ raw.batchId = validatedData[idx].batchId
860
+ } else {
861
+ raw.assignedQty = 0
862
+ raw.assignedUomValue = 0
863
+ raw.productId = null
864
+ }
865
+
866
+ return {
867
+ ...raw,
868
+ releaseUomValue
869
+ }
870
+ })
871
+ }
872
+
574
873
  export async function confirmReleaseGood(name: string, context: any, tx?: EntityManager): Promise<ReleaseGood> {
575
874
  const { user, domain }: { user: User; domain: Domain } = context.state
576
875
 
@@ -859,3 +1158,261 @@ export async function rejectReleaseGood(
859
1158
 
860
1159
  return releaseGood
861
1160
  }
1161
+
1162
+ export async function bulkGenerateReleaseGoods(
1163
+ releaseGood: any,
1164
+ bizplaceId: string,
1165
+ roNoSetting: any,
1166
+ domain: Domain,
1167
+ user: User,
1168
+ tx?: EntityManager
1169
+ ): Promise<ReleaseGood> {
1170
+ try {
1171
+ let warehouseDomain: Domain = domain
1172
+ let { orderInventories } = releaseGood
1173
+
1174
+ let bizplace: Bizplace = await tx.getRepository(Bizplace).findOne(bizplaceId)
1175
+
1176
+ let newReleaseGood: ReleaseGood = {
1177
+ ...releaseGood,
1178
+ name: roNoSetting
1179
+ ? await generateId({ domain, type: ORDER_NUMBER_RULE_TYPE.RO_NUMBER, seed: {} })
1180
+ : OrderNoGenerator.releaseGood(),
1181
+ domain: warehouseDomain,
1182
+ bizplace: bizplace,
1183
+ deliveryAddress1: releaseGood?.deliveryAddress1 || null,
1184
+ deliveryAddress2: releaseGood?.deliveryAddress2 || null,
1185
+ deliveryAddress3: releaseGood?.deliveryAddress3 || null,
1186
+ deliveryAddress4: releaseGood?.deliveryAddress4 || null,
1187
+ deliveryAddress5: releaseGood?.deliveryAddress5 || null,
1188
+ attentionTo: releaseGood?.attentionTo || null,
1189
+ attentionCompany: releaseGood?.attentionCompany || null,
1190
+ city: releaseGood?.city || null,
1191
+ state: releaseGood?.state || null,
1192
+ postalCode: releaseGood?.postalCode || null,
1193
+ country: releaseGood?.country || null,
1194
+ phone1: releaseGood?.phone1 || null,
1195
+ phone2: releaseGood?.phone2 || null,
1196
+ email: releaseGood?.email || null,
1197
+ airwayBill: releaseGood?.airwayBill,
1198
+ refNo: releaseGood.refNo,
1199
+ refNo2: releaseGood.refNo2,
1200
+ refNo3: releaseGood.refNo3,
1201
+ releaseDate: releaseGood.releaseDate,
1202
+ ownTransport: releaseGood?.ownTransport || false,
1203
+ status: ORDER_STATUS.PENDING,
1204
+ creator: user,
1205
+ updater: user
1206
+ }
1207
+
1208
+ newReleaseGood = await tx.getRepository(ReleaseGood).save(newReleaseGood)
1209
+
1210
+ for (let oi of orderInventories) {
1211
+ delete oi.sku
1212
+
1213
+ let newOrderInv: OrderInventory = Object.assign(new OrderInventory(), oi)
1214
+ newOrderInv = {
1215
+ ...newOrderInv,
1216
+ domain: warehouseDomain,
1217
+ bizplace: bizplace,
1218
+ status: ORDER_INVENTORY_STATUS.PENDING,
1219
+ name: OrderNoGenerator.orderInventory(),
1220
+ batchId: oi?.batchId || '',
1221
+ releaseGood: newReleaseGood,
1222
+ product: await tx.getRepository(Product).findOne(oi.productId),
1223
+ creator: user,
1224
+ updater: user
1225
+ }
1226
+
1227
+ let newOrderProduct: OrderProduct = Object.assign(new OrderProduct(), newOrderInv)
1228
+ newOrderProduct = {
1229
+ ...newOrderProduct,
1230
+ packQty: 0,
1231
+ actualPackQty: 0,
1232
+ palletQty: 0,
1233
+ actualPalletQty: 0,
1234
+ status: ORDER_PRODUCT_STATUS.PENDING_ASSIGN
1235
+ }
1236
+
1237
+ newOrderProduct = await tx.getRepository(OrderProduct).save(newOrderProduct)
1238
+
1239
+ await tx.getRepository(OrderInventory).save({ ...newOrderInv, orderProduct: newOrderProduct })
1240
+ }
1241
+
1242
+ // Change the status to PENDING_RECEIVE
1243
+
1244
+ return newReleaseGood
1245
+ } catch (error) {
1246
+ throw error
1247
+ }
1248
+ }
1249
+
1250
+ export async function bulkConfirmReleaseGoods(
1251
+ releaseGoodsNo: string[],
1252
+ domain: Domain,
1253
+ user: User,
1254
+ context: any,
1255
+ tx?: EntityManager
1256
+ ): Promise<ReleaseGood[]> {
1257
+ let foundReleaseGoods: ReleaseGood[] = await tx.getRepository(ReleaseGood).find({
1258
+ where: { name: In(releaseGoodsNo), status: ORDER_STATUS.PENDING },
1259
+ relations: [
1260
+ 'domain',
1261
+ 'bizplace',
1262
+ 'bizplace.domain',
1263
+ 'bizplace.company',
1264
+ 'bizplace.company.domain',
1265
+ 'orderProducts',
1266
+ 'orderProducts.product',
1267
+ 'orderInventories',
1268
+ 'orderInventories.product',
1269
+ 'orderVass'
1270
+ ]
1271
+ })
1272
+
1273
+ if (!foundReleaseGoods.length) throw new Error(`Release good order doesn't exists.`)
1274
+ let customerBizplace: Bizplace = foundReleaseGoods[0].bizplace
1275
+
1276
+ let foundOrderInventories: OrderInventory[] = foundReleaseGoods
1277
+ .map((releaseGood: ReleaseGood) => releaseGood.orderInventories)
1278
+ .reduce((orderInventories, currOIs) => {
1279
+ orderInventories.push(...currOIs)
1280
+ return orderInventories
1281
+ }, [])
1282
+
1283
+ await tx
1284
+ .getRepository(ReleaseGood)
1285
+ .update({ id: In(foundReleaseGoods.map(rg => rg.id)) }, { status: ORDER_STATUS.PENDING_RECEIVE, updater: user })
1286
+
1287
+ await tx
1288
+ .getRepository(OrderInventory)
1289
+ .update(
1290
+ { id: In(foundOrderInventories.map(oi => oi.id)) },
1291
+ { status: ORDER_INVENTORY_STATUS.PENDING_RECEIVE, updater: user }
1292
+ )
1293
+
1294
+ if (context?.state?.type != 'api') {
1295
+ const users: any[] = await tx
1296
+ .getRepository('users_roles')
1297
+ .createQueryBuilder('ur')
1298
+ .select('ur.users_id', 'id')
1299
+ .where(qb => {
1300
+ const subQuery = qb
1301
+ .subQuery()
1302
+ .select('role.id')
1303
+ .from(Role, 'role')
1304
+ .where("role.name = 'Office Admin'")
1305
+ .andWhere('role.domain_id = :domain', { domain: domain.id })
1306
+ .getQuery()
1307
+ return 'ur.roles_id IN ' + subQuery
1308
+ })
1309
+ .getRawMany()
1310
+
1311
+ // send notification to Office Admin Users
1312
+ if (users?.length) {
1313
+ const receivers: any[] = users.map(user => user.id)
1314
+ const msg = {
1315
+ title: `New Release Order from ${customerBizplace.name}`,
1316
+ body: `New incoming bulk release orders are pending for receiving`,
1317
+ url: context.header.referer,
1318
+ data: { url: context.header.referer }
1319
+ }
1320
+ await sendNotification({
1321
+ receivers,
1322
+ message: { ...msg }
1323
+ })
1324
+ }
1325
+ }
1326
+
1327
+ return foundReleaseGoods.map((releaseGood: ReleaseGood) => {
1328
+ return {
1329
+ ...releaseGood,
1330
+ status: ORDER_STATUS.PENDING_RECEIVE,
1331
+ updater: user
1332
+ }
1333
+ })
1334
+ }
1335
+
1336
+ export function extractRawReleaseGoods(rawReleaseGoods): Partial<ReleaseGood[]> {
1337
+ return rawReleaseGoods.reduce((releaseGoods, item) => {
1338
+ const idx: number = releaseGoods.findIndex(rg => {
1339
+ // consider these attributes if they are exist in "item"
1340
+ const comparison = [
1341
+ 'refNo2',
1342
+ 'refNo3',
1343
+ 'attentionTo',
1344
+ 'phone1',
1345
+ 'deliveryAddress1',
1346
+ 'deliveryAddress2',
1347
+ 'deliveryAddress3',
1348
+ 'deliveryAddress4',
1349
+ 'postalCode'
1350
+ ]
1351
+
1352
+ let a: any = {},
1353
+ b: any = {}
1354
+
1355
+ comparison.forEach(cc => {
1356
+ if (item[cc]) {
1357
+ a[cc] = item[cc]
1358
+ b[cc] = rg[cc]
1359
+ }
1360
+ })
1361
+
1362
+ a = JSON.stringify(Object.fromEntries(Object.entries(a).sort()))
1363
+ b = JSON.stringify(Object.fromEntries(Object.entries(b).sort()))
1364
+
1365
+ return rg.refNo == item.refNo && rg.releaseDate == item.releaseDate && a === b
1366
+ })
1367
+
1368
+ if (idx >= 0) {
1369
+ const duplicateSkuIdx: number = releaseGoods[idx].orderInventories.findIndex(
1370
+ oi => oi.sku === item.sku && oi.packingType === item.packingType && oi.packingSize === item.packingSize
1371
+ )
1372
+
1373
+ if (duplicateSkuIdx >= 0) {
1374
+ releaseGoods[idx].orderInventories[duplicateSkuIdx].releaseQty += item.releaseQty
1375
+ } else {
1376
+ releaseGoods[idx].orderInventories.push({
1377
+ sku: item.sku,
1378
+ productId: item.productId,
1379
+ packingType: item.packingType,
1380
+ packingSize: item.packingSize,
1381
+ uom: item.uom,
1382
+ releaseQty: item.releaseQty,
1383
+ releaseUomValue: item.releaseUomValue
1384
+ })
1385
+ }
1386
+ } else {
1387
+ releaseGoods.push({
1388
+ releaseDate: item.releaseDate,
1389
+ refNo: item.refNo,
1390
+ refNo2: item.refNo2,
1391
+ refNo3: item.refNo3,
1392
+ attentionTo: item.attentionTo,
1393
+ phone1: item.phone1,
1394
+ deliveryAddress1: item.deliveryAddress1,
1395
+ deliveryAddress2: item.deliveryAddress2,
1396
+ deliveryAddress3: item.deliveryAddress3,
1397
+ deliveryAddress4: item.deliveryAddress4,
1398
+ city: item.city,
1399
+ postalCode: item.postalCode,
1400
+ state: item.state,
1401
+ country: item.country,
1402
+ orderInventories: [
1403
+ {
1404
+ sku: item.sku,
1405
+ productId: item.productId,
1406
+ packingType: item.packingType,
1407
+ packingSize: item.packingSize,
1408
+ uom: item.uom,
1409
+ releaseQty: item.releaseQty,
1410
+ releaseUomValue: item.releaseUomValue
1411
+ }
1412
+ ]
1413
+ })
1414
+ }
1415
+
1416
+ return releaseGoods
1417
+ }, [])
1418
+ }