@things-factory/sales-base 4.0.24 → 4.0.25
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.
- package/dist-server/controllers/ecommerce/ecommerce-controller.js +7 -4
- package/dist-server/controllers/ecommerce/ecommerce-controller.js.map +1 -1
- package/dist-server/controllers/ecommerce/sellercraft-controller.js +59 -0
- package/dist-server/controllers/ecommerce/sellercraft-controller.js.map +1 -1
- package/dist-server/controllers/order-controller.js +40 -1
- package/dist-server/controllers/order-controller.js.map +1 -1
- package/dist-server/service/arrival-notice/arrival-notice-mutation.js +180 -0
- package/dist-server/service/arrival-notice/arrival-notice-mutation.js.map +1 -1
- package/dist-server/service/arrival-notice/arrival-notice-query.js +193 -1
- package/dist-server/service/arrival-notice/arrival-notice-query.js.map +1 -1
- package/dist-server/service/arrival-notice/arrival-notice-types.js +160 -2
- package/dist-server/service/arrival-notice/arrival-notice-types.js.map +1 -1
- package/dist-server/service/delivery-order/delivery-order-types.js +1 -1
- package/dist-server/service/delivery-order/delivery-order-types.js.map +1 -1
- package/dist-server/service/goods-receival-note/goods-receival-note.js +5 -0
- package/dist-server/service/goods-receival-note/goods-receival-note.js.map +1 -1
- package/dist-server/service/order-inventory/order-inventory.js +22 -1
- package/dist-server/service/order-inventory/order-inventory.js.map +1 -1
- package/dist-server/service/release-good/release-good-mutation.js +242 -81
- package/dist-server/service/release-good/release-good-mutation.js.map +1 -1
- package/dist-server/service/release-good/release-good-types.js +8 -0
- package/dist-server/service/release-good/release-good-types.js.map +1 -1
- package/dist-server/service/release-good/release-good.js +4 -0
- package/dist-server/service/release-good/release-good.js.map +1 -1
- package/dist-server/service/return-order/return-order-mutation.js +1 -1
- package/dist-server/service/return-order/return-order-mutation.js.map +1 -1
- package/dist-server/utils/inventory-util.js +89 -1
- package/dist-server/utils/inventory-util.js.map +1 -1
- package/package.json +12 -12
- package/server/controllers/ecommerce/ecommerce-controller.ts +15 -6
- package/server/controllers/ecommerce/sellercraft-controller.ts +77 -1
- package/server/controllers/order-controller.ts +55 -2
- package/server/service/arrival-notice/arrival-notice-mutation.ts +237 -1
- package/server/service/arrival-notice/arrival-notice-query.ts +214 -4
- package/server/service/arrival-notice/arrival-notice-types.ts +120 -1
- package/server/service/delivery-order/delivery-order-types.ts +1 -1
- package/server/service/goods-receival-note/goods-receival-note.ts +4 -0
- package/server/service/order-inventory/order-inventory.ts +17 -1
- package/server/service/release-good/release-good-mutation.ts +310 -119
- package/server/service/release-good/release-good-types.ts +6 -0
- package/server/service/release-good/release-good.ts +3 -0
- package/server/service/return-order/return-order-mutation.ts +1 -1
- package/server/utils/index.ts +1 -1
- package/server/utils/inventory-util.ts +129 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { FileUpload, GraphQLUpload } from 'graphql-upload'
|
|
2
2
|
import { Arg, Ctx, Directive, Mutation, Resolver } from 'type-graphql'
|
|
3
|
-
import { EntityManager, getRepository, In, Not, Repository } from 'typeorm'
|
|
3
|
+
import { EntityManager, getConnection, getRepository, In, Not, Repository } from 'typeorm'
|
|
4
4
|
|
|
5
5
|
import { Attachment, createAttachments } from '@things-factory/attachment-base'
|
|
6
6
|
import { Partner, Role, User } from '@things-factory/auth-base'
|
|
@@ -15,11 +15,12 @@ import {
|
|
|
15
15
|
import { generateId } from '@things-factory/id-rule-base'
|
|
16
16
|
import { MarketplaceStore } from '@things-factory/integration-marketplace'
|
|
17
17
|
import { Sellercraft, SellercraftStatus } from '@things-factory/integration-sellercraft'
|
|
18
|
+
import { MarketplaceOrder, MarketplaceProductVariation } from '@things-factory/marketplace-base'
|
|
18
19
|
import { sendNotification } from '@things-factory/notification'
|
|
19
20
|
import { Product, ProductBundleSetting } from '@things-factory/product-base'
|
|
20
21
|
import { PartnerSetting, Setting } from '@things-factory/setting-base'
|
|
21
22
|
import { Domain } from '@things-factory/shell'
|
|
22
|
-
import { Inventory } from '@things-factory/warehouse-base'
|
|
23
|
+
import { Inventory, LOCATION_TYPE } from '@things-factory/warehouse-base'
|
|
23
24
|
|
|
24
25
|
import {
|
|
25
26
|
ArrivalNotice,
|
|
@@ -51,6 +52,96 @@ import { ReleaseGood } from './release-good'
|
|
|
51
52
|
|
|
52
53
|
@Resolver(ReleaseGood)
|
|
53
54
|
export class ReleaseGoodMutation {
|
|
55
|
+
@Directive('@privilege(category: "order_customer", privilege: "mutation")')
|
|
56
|
+
@Directive('@transaction')
|
|
57
|
+
@Mutation(returns => [ReleaseGood])
|
|
58
|
+
async bulkAddReleaseGoods(
|
|
59
|
+
@Ctx() context: any,
|
|
60
|
+
@Arg('rawReleaseGoods', type => [NewReleaseGood], { nullable: true }) rawReleaseGoods: NewReleaseGood[],
|
|
61
|
+
@Arg('bizplaceId', type => String) bizplaceId: string
|
|
62
|
+
): Promise<ReleaseGood[]> {
|
|
63
|
+
const { domain, user, tx } = context.state
|
|
64
|
+
|
|
65
|
+
if (!bizplaceId) throw new Error('company ID is not provided')
|
|
66
|
+
|
|
67
|
+
let createdReleaseGoods: ReleaseGood[] = []
|
|
68
|
+
const settingRepo: Repository<Setting> = tx?.getRepository(Setting) || getRepository(Setting)
|
|
69
|
+
|
|
70
|
+
const roNoSetting: Setting = await settingRepo.findOne({
|
|
71
|
+
where: {
|
|
72
|
+
domain,
|
|
73
|
+
name: ORDER_NUMBER_SETTING_KEY.RO_NUMBER_RULE
|
|
74
|
+
}
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
let releaseGoods: Partial<ReleaseGood[]> = extractRawReleaseGoods(rawReleaseGoods)
|
|
78
|
+
|
|
79
|
+
let errorsFound: any[] = []
|
|
80
|
+
for (let i = 0, l = releaseGoods.length; i < l; i++) {
|
|
81
|
+
// generate release good by group to avoid duplication
|
|
82
|
+
// if this function is called simultaneously by different users
|
|
83
|
+
try {
|
|
84
|
+
await getConnection().transaction(async (childTx: EntityManager) => {
|
|
85
|
+
const existingReleaseGood: ReleaseGood = await childTx.getRepository(ReleaseGood).findOne({
|
|
86
|
+
where: {
|
|
87
|
+
...Object.fromEntries(
|
|
88
|
+
Object.entries(releaseGoods[i]).filter(([_, val]) => !/^\s*$/.test(val) && _ != 'orderInventories')
|
|
89
|
+
),
|
|
90
|
+
domain
|
|
91
|
+
}
|
|
92
|
+
})
|
|
93
|
+
if (existingReleaseGood) throw new Error('release good order is already exist in the system')
|
|
94
|
+
|
|
95
|
+
let availableItems: any[] = await bulkReleaseGoodsAvailableItemsFunction(
|
|
96
|
+
[...releaseGoods[i].orderInventories],
|
|
97
|
+
bizplaceId,
|
|
98
|
+
context,
|
|
99
|
+
childTx
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
if (availableItems.some(item => !item.releaseQty || item.releaseQty > item.assignedQty))
|
|
103
|
+
throw new ValidationError({
|
|
104
|
+
...ValidationError.ERROR_CODES.INSUFFICIENT_STOCK,
|
|
105
|
+
detail: { data: JSON.stringify(availableItems) }
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
// update orderInventories if availableItems are valid
|
|
109
|
+
releaseGoods[i].orderInventories = availableItems
|
|
110
|
+
|
|
111
|
+
const createdReleaseGood: ReleaseGood = await bulkGenerateReleaseGoods(
|
|
112
|
+
releaseGoods[i],
|
|
113
|
+
bizplaceId,
|
|
114
|
+
roNoSetting,
|
|
115
|
+
domain,
|
|
116
|
+
user,
|
|
117
|
+
childTx
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
createdReleaseGoods.push(createdReleaseGood)
|
|
121
|
+
})
|
|
122
|
+
} catch (e) {
|
|
123
|
+
errorsFound.push(e)
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
let confirmedReleaseGoods: ReleaseGood[] = []
|
|
128
|
+
try {
|
|
129
|
+
confirmedReleaseGoods = await bulkConfirmReleaseGoods(
|
|
130
|
+
createdReleaseGoods.map(rg => rg.name),
|
|
131
|
+
domain,
|
|
132
|
+
user,
|
|
133
|
+
context,
|
|
134
|
+
tx
|
|
135
|
+
)
|
|
136
|
+
} catch (e) {
|
|
137
|
+
errorsFound.push(e)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// if (errorsFound.length) { then ?? }
|
|
141
|
+
|
|
142
|
+
return confirmedReleaseGoods
|
|
143
|
+
}
|
|
144
|
+
|
|
54
145
|
@Directive('@privilege(category: "order_customer", privilege: "mutation")')
|
|
55
146
|
@Directive('@transaction')
|
|
56
147
|
@Mutation(returns => Boolean)
|
|
@@ -206,71 +297,6 @@ export class ReleaseGoodMutation {
|
|
|
206
297
|
|
|
207
298
|
return receivedRO
|
|
208
299
|
}
|
|
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
|
-
}
|
|
274
300
|
}
|
|
275
301
|
|
|
276
302
|
export async function deleteReleaseGood(tx: EntityManager, name: string, user: User, domain: Domain): Promise<boolean> {
|
|
@@ -433,10 +459,33 @@ export async function generateReleaseGoodFunction(
|
|
|
433
459
|
domain: warehouseDomain,
|
|
434
460
|
refNo,
|
|
435
461
|
status: Not(In([ORDER_STATUS.CANCELLED, ORDER_STATUS.PENDING_CANCEL]))
|
|
436
|
-
}
|
|
462
|
+
},
|
|
463
|
+
relations: ['bizplace', 'bizplace.domain', 'bizplace.company', 'bizplace.company.domain']
|
|
437
464
|
})
|
|
438
465
|
|
|
439
|
-
if (foundReleaseGood)
|
|
466
|
+
if (foundReleaseGood) {
|
|
467
|
+
const customerCompanyDomain: Domain = foundReleaseGood.bizplace.company.domain
|
|
468
|
+
const marketplaceOrder: MarketplaceOrder = await tx.getRepository(MarketplaceOrder).findOne({
|
|
469
|
+
where: { orderNo: refNo, domain: customerCompanyDomain }
|
|
470
|
+
})
|
|
471
|
+
|
|
472
|
+
// Need to restructure the validation
|
|
473
|
+
if (marketplaceOrder.isSplitted) {
|
|
474
|
+
const refNo2: string = releaseGood.refNo2
|
|
475
|
+
const foundSplittedReleaseGood = await tx.getRepository(ReleaseGood).findOne({
|
|
476
|
+
where: {
|
|
477
|
+
domain: warehouseDomain,
|
|
478
|
+
refNo2,
|
|
479
|
+
status: Not(In([ORDER_STATUS.CANCELLED, ORDER_STATUS.PENDING_CANCEL]))
|
|
480
|
+
},
|
|
481
|
+
relations: ['bizplace', 'bizplace.domain', 'bizplace.company', 'bizplace.company.domain']
|
|
482
|
+
})
|
|
483
|
+
|
|
484
|
+
if (foundSplittedReleaseGood) throw new Error('Existing release order found')
|
|
485
|
+
} else {
|
|
486
|
+
throw new Error('Existing release order found')
|
|
487
|
+
}
|
|
488
|
+
}
|
|
440
489
|
}
|
|
441
490
|
}
|
|
442
491
|
|
|
@@ -503,6 +552,7 @@ export async function generateReleaseGoodFunction(
|
|
|
503
552
|
refNo3: releaseGood.refNo3,
|
|
504
553
|
releaseDate: releaseGood.releaseDate,
|
|
505
554
|
truckNo: releaseGood.truckNo,
|
|
555
|
+
bundleInfo: releaseGood?.bundleInfo || [],
|
|
506
556
|
orderInventories: releaseGood.orderInventories,
|
|
507
557
|
type: releaseGood?.type ? releaseGood.type : 'b2b',
|
|
508
558
|
status: ORDER_STATUS.PENDING,
|
|
@@ -521,8 +571,6 @@ export async function generateReleaseGoodFunction(
|
|
|
521
571
|
newReleaseGood.arrivalNotice = crossDockingGAN
|
|
522
572
|
}
|
|
523
573
|
|
|
524
|
-
newReleaseGood = await tx.getRepository(ReleaseGood).save(newReleaseGood)
|
|
525
|
-
|
|
526
574
|
// Make relation with RO for cross docking
|
|
527
575
|
if (newReleaseGood.crossDocking) {
|
|
528
576
|
crossDockingGAN.releaseGood = newReleaseGood
|
|
@@ -572,6 +620,9 @@ export async function generateReleaseGoodFunction(
|
|
|
572
620
|
|
|
573
621
|
orderInventories = [...singleProductOIs, ...splitBundleOIs]
|
|
574
622
|
|
|
623
|
+
newReleaseGood.noOfItems = orderInventories.length
|
|
624
|
+
newReleaseGood = await tx.getRepository(ReleaseGood).save(newReleaseGood)
|
|
625
|
+
|
|
575
626
|
for (let oi of orderInventories) {
|
|
576
627
|
let newOrderInv: OrderInventory = Object.assign({}, oi)
|
|
577
628
|
newOrderInv = {
|
|
@@ -711,6 +762,7 @@ export async function bulkReleaseGoodsAvailableItemsFunction(
|
|
|
711
762
|
CREATE TEMP TABLE temp_order_products(
|
|
712
763
|
product_id VARCHAR(50),
|
|
713
764
|
sku VARCHAR(150),
|
|
765
|
+
product_info VARCHAR(250),
|
|
714
766
|
packing_type VARCHAR(50),
|
|
715
767
|
packing_size INT,
|
|
716
768
|
uom VARCHAR(10),
|
|
@@ -723,6 +775,8 @@ export async function bulkReleaseGoodsAvailableItemsFunction(
|
|
|
723
775
|
`
|
|
724
776
|
INSERT INTO temp_order_products
|
|
725
777
|
SELECT p.id AS product_id, js.sku,
|
|
778
|
+
CASE WHEN p.description NOT IN (NULL, '', '-') THEN CONCAT(p.name, '(', p.description, ')')
|
|
779
|
+
ELSE p.name END AS product_info,
|
|
726
780
|
CASE WHEN js.packing_type NOTNULL AND js.packing_size NOTNULL THEN js.packing_type ELSE pd.packing_type END,
|
|
727
781
|
CASE WHEN js.packing_type NOTNULL AND js.packing_size NOTNULL THEN js.packing_size ELSE pd.packing_size END,
|
|
728
782
|
CASE WHEN js.uom NOTNULL THEN js.uom ELSE pd.uom END,
|
|
@@ -736,16 +790,12 @@ export async function bulkReleaseGoodsAvailableItemsFunction(
|
|
|
736
790
|
|
|
737
791
|
let availableItems = await tx.query(
|
|
738
792
|
`
|
|
739
|
-
|
|
793
|
+
WITH inv AS (
|
|
794
|
+
SELECT i.product_id, foo.sku, foo.product_info, i.batch_id, i.packing_type, i.packing_size, i.uom,
|
|
740
795
|
SUM(i.qty - COALESCE(i.locked_qty, 0)) - COALESCE(
|
|
741
796
|
(
|
|
742
797
|
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
|
-
)
|
|
798
|
+
WHERE oi.status IN ('PENDING', 'PENDING_RECEIVE', 'PENDING_WORKSHEET', 'PENDING_SPLIT')
|
|
749
799
|
AND oi.inventory_id IS null
|
|
750
800
|
AND oi.product_id = i.product_id::uuid
|
|
751
801
|
AND oi.packing_type = i.packing_type
|
|
@@ -756,12 +806,7 @@ export async function bulkReleaseGoodsAvailableItemsFunction(
|
|
|
756
806
|
SUM(i.uom_value - COALESCE(i.locked_uom_value, 0)) - COALESCE(
|
|
757
807
|
(
|
|
758
808
|
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
|
-
)
|
|
809
|
+
WHERE oi.status IN ('PENDING', 'PENDING_RECEIVE', 'PENDING_WORKSHEET', 'PENDING_SPLIT')
|
|
765
810
|
AND oi.inventory_id IS null
|
|
766
811
|
AND oi.product_id = i.product_id::uuid
|
|
767
812
|
AND oi.packing_type = i.packing_type
|
|
@@ -770,10 +815,12 @@ export async function bulkReleaseGoodsAvailableItemsFunction(
|
|
|
770
815
|
AND oi.bizplace_id = $2
|
|
771
816
|
), 0) as "remain_uom_value"
|
|
772
817
|
FROM inventories i
|
|
818
|
+
LEFT JOIN locations l
|
|
819
|
+
ON i.location_id = l.id
|
|
773
820
|
INNER JOIN (
|
|
774
|
-
SELECT top.product_id, top.sku, top.packing_type, top.packing_size, top.uom
|
|
821
|
+
SELECT top.product_id, top.sku, top.product_info, top.packing_type, top.packing_size, top.uom
|
|
775
822
|
FROM temp_order_products top
|
|
776
|
-
GROUP BY top.product_id, top.sku, top.packing_type, top.packing_size, top.uom
|
|
823
|
+
GROUP BY top.product_id, top.sku, top.product_info, top.packing_type, top.packing_size, top.uom
|
|
777
824
|
) AS foo
|
|
778
825
|
ON i.product_id = foo.product_id::uuid
|
|
779
826
|
AND i.packing_type = foo.packing_type
|
|
@@ -781,10 +828,12 @@ export async function bulkReleaseGoodsAvailableItemsFunction(
|
|
|
781
828
|
AND i.uom = foo.uom
|
|
782
829
|
AND i.domain_id = $1
|
|
783
830
|
AND i.bizplace_id = $2
|
|
784
|
-
|
|
831
|
+
WHERE l.type NOT IN ($3, $4)
|
|
832
|
+
GROUP BY i.product_id, foo.sku,foo.product_info, i.batch_id, i.packing_type, i.packing_size, i.uom
|
|
785
833
|
ORDER BY foo.sku, remain_qty
|
|
786
|
-
|
|
787
|
-
|
|
834
|
+
) SELECT * FROM inv WHERE remain_qty > 0
|
|
835
|
+
`,
|
|
836
|
+
[domain.id, bizplaceId, LOCATION_TYPE.QUARANTINE, LOCATION_TYPE.RESERVE]
|
|
788
837
|
)
|
|
789
838
|
|
|
790
839
|
await tx.query('DROP TABLE temp_order_products')
|
|
@@ -792,6 +841,7 @@ export async function bulkReleaseGoodsAvailableItemsFunction(
|
|
|
792
841
|
availableItems = availableItems.map(item => {
|
|
793
842
|
return {
|
|
794
843
|
productId: item.product_id,
|
|
844
|
+
productInfo: item.product_info,
|
|
795
845
|
sku: item.sku,
|
|
796
846
|
batchId: item.batch_id,
|
|
797
847
|
packingType: item.packing_type,
|
|
@@ -826,33 +876,41 @@ function _extractData(rawData, validatedData) {
|
|
|
826
876
|
return val.sku == raw.sku && a === b
|
|
827
877
|
})
|
|
828
878
|
|
|
829
|
-
let releaseUomValue = 0
|
|
879
|
+
let releaseUomValue: number = 0
|
|
830
880
|
|
|
831
881
|
// if sku is matched, assign qty and product id
|
|
832
882
|
if (idx >= 0) {
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
(Math.round((validatedData[idx]?.remainUomValue / validatedData[idx]?.remainQty) * 100) / 100) * raw.releaseQty
|
|
883
|
+
const uomValuePerQty: number =
|
|
884
|
+
Math.round((validatedData[idx].remainUomValue / validatedData[idx].remainQty) * 100) / 100
|
|
836
885
|
|
|
886
|
+
// use Math.round again because 4.2 * 6 = 25.200000000000003
|
|
887
|
+
releaseUomValue = Math.round(uomValuePerQty * raw.releaseQty * 100) / 100
|
|
888
|
+
|
|
889
|
+
// assign qty to rawData as much as possible
|
|
837
890
|
raw.assignedQty =
|
|
838
891
|
validatedData[idx].remainQty >= raw.releaseQty
|
|
839
892
|
? raw.releaseQty > 0
|
|
840
893
|
? raw.releaseQty
|
|
841
894
|
: 0
|
|
842
|
-
: validatedData[idx].remainQty
|
|
895
|
+
: validatedData[idx].remainQty > 0
|
|
896
|
+
? validatedData[idx].remainQty
|
|
897
|
+
: 0
|
|
843
898
|
|
|
844
899
|
raw.assignedUomValue =
|
|
845
900
|
validatedData[idx].remainUomValue >= releaseUomValue
|
|
846
901
|
? releaseUomValue > 0
|
|
847
902
|
? releaseUomValue
|
|
848
903
|
: 0
|
|
849
|
-
: validatedData[idx].remainUomValue
|
|
904
|
+
: validatedData[idx].remainUomValue > 0
|
|
905
|
+
? validatedData[idx].remainUomValue
|
|
906
|
+
: 0
|
|
850
907
|
|
|
851
908
|
// deduct qty & uomValue from validateData
|
|
852
909
|
validatedData[idx].remainQty -= raw.assignedQty
|
|
853
910
|
validatedData[idx].remainUomValue -= raw.assignedUomValue
|
|
854
911
|
|
|
855
912
|
raw.productId = validatedData[idx].productId
|
|
913
|
+
raw.productInfo = validatedData[idx].productInfo
|
|
856
914
|
raw.packingType = validatedData[idx].packingType
|
|
857
915
|
raw.packingSize = validatedData[idx].packingSize
|
|
858
916
|
raw.uom = validatedData[idx].uom
|
|
@@ -883,6 +941,7 @@ export async function confirmReleaseGood(name: string, context: any, tx?: Entity
|
|
|
883
941
|
'bizplace.company.domain',
|
|
884
942
|
'orderProducts',
|
|
885
943
|
'orderProducts.product',
|
|
944
|
+
'orderProducts.product.productDetails',
|
|
886
945
|
'orderInventories',
|
|
887
946
|
'orderInventories.product',
|
|
888
947
|
'orderVass'
|
|
@@ -891,26 +950,77 @@ export async function confirmReleaseGood(name: string, context: any, tx?: Entity
|
|
|
891
950
|
|
|
892
951
|
if (!foundReleaseGood) throw new Error(`Release good order doesn't exists.`)
|
|
893
952
|
let foundOIs: OrderInventory[] = foundReleaseGood.orderInventories
|
|
953
|
+
let foundBundleInfo: any[] = JSON.parse(foundReleaseGood.bundleInfo)
|
|
894
954
|
let foundOVs: OrderVas[] = foundReleaseGood.orderVass
|
|
955
|
+
let foundOPs: OrderProduct[] = foundReleaseGood.orderProducts
|
|
895
956
|
let customerBizplace: Bizplace = foundReleaseGood.bizplace
|
|
896
957
|
const companyDomain: Domain = customerBizplace?.company.domain
|
|
958
|
+
const sellercraft: Sellercraft = await tx
|
|
959
|
+
.getRepository(Sellercraft)
|
|
960
|
+
.findOne({ domain: foundReleaseGood.bizplace.domain, status: SellercraftStatus.ACTIVE })
|
|
897
961
|
|
|
898
962
|
if (foundReleaseGood.type == 'b2c') {
|
|
899
|
-
const sellercraft: Sellercraft = await tx
|
|
900
|
-
.getRepository(Sellercraft)
|
|
901
|
-
.findOne({ domain: foundReleaseGood.bizplace.domain, status: SellercraftStatus.ACTIVE })
|
|
902
|
-
|
|
903
963
|
if (sellercraft) {
|
|
904
964
|
const sellercraftCtrl: SellercraftController = new SellercraftController(tx, domain, user)
|
|
905
965
|
foundReleaseGood = await sellercraftCtrl.packOrder(sellercraft, foundReleaseGood)
|
|
906
966
|
} else {
|
|
907
967
|
// find for any existing marketplace store connections
|
|
908
|
-
|
|
909
|
-
where: { domain: companyDomain, status: 'ACTIVE'
|
|
968
|
+
let marketplaceStores: MarketplaceStore[] = await tx.getRepository(MarketplaceStore).find({
|
|
969
|
+
where: { domain: companyDomain, status: 'ACTIVE' },
|
|
910
970
|
relations: ['marketplaceDistributors']
|
|
911
971
|
})
|
|
912
972
|
|
|
973
|
+
const foundMarketplaceOrder: MarketplaceOrder = await tx.getRepository(MarketplaceOrder).findOne({
|
|
974
|
+
where: { domain: companyDomain, orderNo: foundReleaseGood.refNo },
|
|
975
|
+
relations: ['marketplaceStore']
|
|
976
|
+
})
|
|
977
|
+
|
|
978
|
+
let matchedMarketplaceStore: MarketplaceStore
|
|
979
|
+
if (foundMarketplaceOrder) {
|
|
980
|
+
matchedMarketplaceStore = marketplaceStores.filter(
|
|
981
|
+
marketplaceStore => marketplaceStore.id != foundMarketplaceOrder.marketplaceStore.id
|
|
982
|
+
)[0]
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
let combinedOrderInventories: any[] = foundOIs.map(oi => {
|
|
986
|
+
return {
|
|
987
|
+
sku: oi.product.sku,
|
|
988
|
+
releaseQty: oi.releaseQty
|
|
989
|
+
}
|
|
990
|
+
})
|
|
991
|
+
|
|
992
|
+
if (foundBundleInfo?.length) {
|
|
993
|
+
foundBundleInfo.map(bundle => {
|
|
994
|
+
combinedOrderInventories.push({
|
|
995
|
+
sku: bundle.sku,
|
|
996
|
+
releaseQty: bundle.releaseQty
|
|
997
|
+
})
|
|
998
|
+
})
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
for (let oi of combinedOrderInventories) {
|
|
1002
|
+
let foundMarketplaceProductVariations: MarketplaceProductVariation[] = await tx
|
|
1003
|
+
.getRepository(MarketplaceProductVariation)
|
|
1004
|
+
.find({
|
|
1005
|
+
where: { domain: companyDomain, sku: oi.sku },
|
|
1006
|
+
relations: ['marketplaceProduct', 'marketplaceProduct.marketplaceStore']
|
|
1007
|
+
})
|
|
1008
|
+
|
|
1009
|
+
if (foundMarketplaceProductVariations) {
|
|
1010
|
+
await Promise.all(
|
|
1011
|
+
foundMarketplaceProductVariations.map(async variation => {
|
|
1012
|
+
if (variation.marketplaceProduct.marketplaceStore.id != matchedMarketplaceStore.id) {
|
|
1013
|
+
variation.reserveQty -= oi.releaseQty
|
|
1014
|
+
|
|
1015
|
+
await tx.getRepository(MarketplaceProductVariation).save(variation)
|
|
1016
|
+
}
|
|
1017
|
+
})
|
|
1018
|
+
)
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
|
|
913
1022
|
if (marketplaceStores?.length && marketplaceStores.some(store => store.isAutoUpdateStockQty)) {
|
|
1023
|
+
marketplaceStores = marketplaceStores.filter(marketplaceStore => marketplaceStore.isAutoUpdateStockQty)
|
|
914
1024
|
let productIds: string[] = foundOIs.map(oi => oi.product.id)
|
|
915
1025
|
productIds = Array.from(new Set([...productIds]))
|
|
916
1026
|
const ecommerceCtrl: EcommerceController = new EcommerceController(tx, domain, user)
|
|
@@ -919,6 +1029,13 @@ export async function confirmReleaseGood(name: string, context: any, tx?: Entity
|
|
|
919
1029
|
}
|
|
920
1030
|
}
|
|
921
1031
|
|
|
1032
|
+
if (foundReleaseGood.type == 'b2b') {
|
|
1033
|
+
if (sellercraft) {
|
|
1034
|
+
const sellercraftCtrl: SellercraftController = new SellercraftController(tx, domain, user)
|
|
1035
|
+
await sellercraftCtrl.updateSellercraftStock(sellercraft, foundOPs, 'CONFIRM_ORDER')
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
|
|
922
1039
|
// 1. RO Status change (PENDING => PENDING_RECEIVE)
|
|
923
1040
|
const releaseGood: ReleaseGood = await tx.getRepository(ReleaseGood).save({
|
|
924
1041
|
...foundReleaseGood,
|
|
@@ -1079,7 +1196,17 @@ export async function rejectReleaseGood(
|
|
|
1079
1196
|
|
|
1080
1197
|
const releaseGood: ReleaseGood = await tx.getRepository(ReleaseGood).findOne({
|
|
1081
1198
|
where: { domain, name, status: ORDER_STATUS.PENDING_RECEIVE },
|
|
1082
|
-
relations: [
|
|
1199
|
+
relations: [
|
|
1200
|
+
'bizplace',
|
|
1201
|
+
'bizplace.domain',
|
|
1202
|
+
'orderProducts',
|
|
1203
|
+
'orderProducts.product',
|
|
1204
|
+
'orderProducts.product.productDetails',
|
|
1205
|
+
'orderInventories',
|
|
1206
|
+
'orderInventories.inventory',
|
|
1207
|
+
'orderVass',
|
|
1208
|
+
'shippingOrder'
|
|
1209
|
+
]
|
|
1083
1210
|
})
|
|
1084
1211
|
|
|
1085
1212
|
if (!releaseGood) throw new Error(`Release good doesn't exists.`)
|
|
@@ -1087,6 +1214,7 @@ export async function rejectReleaseGood(
|
|
|
1087
1214
|
|
|
1088
1215
|
let foundOIs: OrderInventory[] = releaseGood.orderInventories
|
|
1089
1216
|
let foundOVs: OrderVas[] = releaseGood.orderVass
|
|
1217
|
+
let foundOPs: OrderProduct[] = releaseGood.orderProducts
|
|
1090
1218
|
|
|
1091
1219
|
// 1. Update status of order products (PENDING_RECEIVE => REJECTED)
|
|
1092
1220
|
if (foundOIs && foundOIs.length) {
|
|
@@ -1112,6 +1240,27 @@ export async function rejectReleaseGood(
|
|
|
1112
1240
|
)
|
|
1113
1241
|
}
|
|
1114
1242
|
|
|
1243
|
+
if (foundOPs && foundOPs.length) {
|
|
1244
|
+
const sellercraft: Sellercraft = await tx
|
|
1245
|
+
.getRepository(Sellercraft)
|
|
1246
|
+
.findOne({ domain: releaseGood.bizplace.domain, status: SellercraftStatus.ACTIVE })
|
|
1247
|
+
|
|
1248
|
+
if (sellercraft) {
|
|
1249
|
+
const sellercraftCtrl: SellercraftController = new SellercraftController(tx, domain, user)
|
|
1250
|
+
await sellercraftCtrl.updateSellercraftStock(sellercraft, foundOPs, 'REJECT_ORDER')
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
await tx.getRepository(OrderProduct).save(
|
|
1254
|
+
await Promise.all(
|
|
1255
|
+
foundOPs.map(async (op: OrderProduct) => {
|
|
1256
|
+
op.status = ORDER_PRODUCT_STATUS.REJECTED
|
|
1257
|
+
op.updater = user
|
|
1258
|
+
return op
|
|
1259
|
+
})
|
|
1260
|
+
)
|
|
1261
|
+
)
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1115
1264
|
// 2. Update status of order vass if it exists (PENDING_RECEIVE => REJECTED)
|
|
1116
1265
|
if (foundOVs && foundOVs.length) {
|
|
1117
1266
|
foundOVs = foundOVs.map((ov: OrderVas) => {
|
|
@@ -1184,7 +1333,6 @@ export async function bulkGenerateReleaseGoods(
|
|
|
1184
1333
|
deliveryAddress2: releaseGood?.deliveryAddress2 || null,
|
|
1185
1334
|
deliveryAddress3: releaseGood?.deliveryAddress3 || null,
|
|
1186
1335
|
deliveryAddress4: releaseGood?.deliveryAddress4 || null,
|
|
1187
|
-
deliveryAddress5: releaseGood?.deliveryAddress5 || null,
|
|
1188
1336
|
attentionTo: releaseGood?.attentionTo || null,
|
|
1189
1337
|
attentionCompany: releaseGood?.attentionCompany || null,
|
|
1190
1338
|
city: releaseGood?.city || null,
|
|
@@ -1206,40 +1354,82 @@ export async function bulkGenerateReleaseGoods(
|
|
|
1206
1354
|
}
|
|
1207
1355
|
|
|
1208
1356
|
newReleaseGood = await tx.getRepository(ReleaseGood).save(newReleaseGood)
|
|
1357
|
+
let finalOrderInventories: OrderInventory[] = []
|
|
1209
1358
|
|
|
1359
|
+
// pre assign inventory to orderInventories
|
|
1210
1360
|
for (let oi of orderInventories) {
|
|
1211
|
-
|
|
1361
|
+
const pickingProductSetting: Setting = await tx.getRepository(Setting).findOne({
|
|
1362
|
+
where: { domain, name: 'rule-for-picking-product' }
|
|
1363
|
+
})
|
|
1212
1364
|
|
|
1213
|
-
let
|
|
1214
|
-
|
|
1215
|
-
|
|
1365
|
+
let locationSortingRules = []
|
|
1366
|
+
if (pickingProductSetting) {
|
|
1367
|
+
let locationSetting = JSON.parse(pickingProductSetting.value)
|
|
1368
|
+
for (const key in locationSetting) {
|
|
1369
|
+
locationSortingRules.push({ name: key, desc: locationSetting[key] == 'ASC' ? false : true })
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1373
|
+
const product: Product = await tx.getRepository(Product).findOne(oi.productId)
|
|
1374
|
+
|
|
1375
|
+
finalOrderInventories.push(
|
|
1376
|
+
...(await InventoryUtil.autoAssignInventoryForRelease(
|
|
1377
|
+
product,
|
|
1378
|
+
oi,
|
|
1379
|
+
oi.packingType,
|
|
1380
|
+
locationSortingRules,
|
|
1381
|
+
bizplace,
|
|
1382
|
+
warehouseDomain,
|
|
1383
|
+
tx
|
|
1384
|
+
))
|
|
1385
|
+
)
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1388
|
+
for (let oi of finalOrderInventories) {
|
|
1389
|
+
let generatedOI: OrderInventory = Object.assign(new OrderInventory(), oi)
|
|
1390
|
+
generatedOI = {
|
|
1391
|
+
...generatedOI,
|
|
1216
1392
|
domain: warehouseDomain,
|
|
1217
|
-
bizplace
|
|
1393
|
+
bizplace,
|
|
1218
1394
|
status: ORDER_INVENTORY_STATUS.PENDING,
|
|
1219
1395
|
name: OrderNoGenerator.orderInventory(),
|
|
1220
|
-
batchId: oi?.batchId || '',
|
|
1221
1396
|
releaseGood: newReleaseGood,
|
|
1222
|
-
product: await tx.getRepository(Product).findOne(oi.productId),
|
|
1223
1397
|
creator: user,
|
|
1224
1398
|
updater: user
|
|
1225
1399
|
}
|
|
1226
1400
|
|
|
1227
|
-
let newOrderProduct: OrderProduct =
|
|
1228
|
-
|
|
1229
|
-
|
|
1401
|
+
let newOrderProduct: Partial<OrderProduct> = {
|
|
1402
|
+
name: generatedOI.name,
|
|
1403
|
+
product: generatedOI.product,
|
|
1404
|
+
batchId: generatedOI.batchId,
|
|
1405
|
+
packingType: generatedOI.packingType,
|
|
1406
|
+
packingSize: generatedOI.packingSize,
|
|
1407
|
+
uom: generatedOI.uom,
|
|
1408
|
+
domain: warehouseDomain,
|
|
1409
|
+
bizplace,
|
|
1410
|
+
releaseQty: generatedOI.releaseQty,
|
|
1411
|
+
releaseUomValue: generatedOI.releaseUomValue,
|
|
1230
1412
|
packQty: 0,
|
|
1231
1413
|
actualPackQty: 0,
|
|
1232
1414
|
palletQty: 0,
|
|
1233
1415
|
actualPalletQty: 0,
|
|
1234
|
-
status: ORDER_PRODUCT_STATUS.PENDING_ASSIGN
|
|
1416
|
+
status: ORDER_PRODUCT_STATUS.PENDING_ASSIGN,
|
|
1417
|
+
releaseGood: newReleaseGood,
|
|
1418
|
+
creator: user,
|
|
1419
|
+
updater: user
|
|
1235
1420
|
}
|
|
1236
1421
|
|
|
1237
1422
|
newOrderProduct = await tx.getRepository(OrderProduct).save(newOrderProduct)
|
|
1238
1423
|
|
|
1239
|
-
await tx.getRepository(OrderInventory).save({ ...
|
|
1240
|
-
}
|
|
1424
|
+
await tx.getRepository(OrderInventory).save({ ...generatedOI, orderProduct: newOrderProduct })
|
|
1241
1425
|
|
|
1242
|
-
|
|
1426
|
+
// update inventory locked qty and uom value
|
|
1427
|
+
await tx.getRepository(Inventory).update(oi.inventory.id, {
|
|
1428
|
+
lockedQty: (oi.inventory?.lockedQty || 0) + generatedOI.releaseQty,
|
|
1429
|
+
lockedUomValue: (oi.inventory?.lockedUomValue || 0) + generatedOI.releaseUomValue,
|
|
1430
|
+
updater: user
|
|
1431
|
+
})
|
|
1432
|
+
}
|
|
1243
1433
|
|
|
1244
1434
|
return newReleaseGood
|
|
1245
1435
|
} catch (error) {
|
|
@@ -1270,7 +1460,7 @@ export async function bulkConfirmReleaseGoods(
|
|
|
1270
1460
|
]
|
|
1271
1461
|
})
|
|
1272
1462
|
|
|
1273
|
-
if (!foundReleaseGoods.length) throw new Error(`
|
|
1463
|
+
if (!foundReleaseGoods.length) throw new Error(`release good order doesn't exists.`)
|
|
1274
1464
|
let customerBizplace: Bizplace = foundReleaseGoods[0].bizplace
|
|
1275
1465
|
|
|
1276
1466
|
let foundOrderInventories: OrderInventory[] = foundReleaseGoods
|
|
@@ -1333,7 +1523,7 @@ export async function bulkConfirmReleaseGoods(
|
|
|
1333
1523
|
})
|
|
1334
1524
|
}
|
|
1335
1525
|
|
|
1336
|
-
|
|
1526
|
+
function extractRawReleaseGoods(rawReleaseGoods): Partial<ReleaseGood[]> {
|
|
1337
1527
|
return rawReleaseGoods.reduce((releaseGoods, item) => {
|
|
1338
1528
|
const idx: number = releaseGoods.findIndex(rg => {
|
|
1339
1529
|
// consider these attributes if they are exist in "item"
|
|
@@ -1370,6 +1560,7 @@ export function extractRawReleaseGoods(rawReleaseGoods): Partial<ReleaseGood[]>
|
|
|
1370
1560
|
oi => oi.sku === item.sku && oi.packingType === item.packingType && oi.packingSize === item.packingSize
|
|
1371
1561
|
)
|
|
1372
1562
|
|
|
1563
|
+
// if there is duplicated SKU, merge them and sum up the releaseQty
|
|
1373
1564
|
if (duplicateSkuIdx >= 0) {
|
|
1374
1565
|
releaseGoods[idx].orderInventories[duplicateSkuIdx].releaseQty += item.releaseQty
|
|
1375
1566
|
} else {
|
|
@@ -158,6 +158,9 @@ export class NewReleaseGood {
|
|
|
158
158
|
@Field({ nullable: true })
|
|
159
159
|
name: string
|
|
160
160
|
|
|
161
|
+
@Field({ nullable: true })
|
|
162
|
+
bundleInfo: string
|
|
163
|
+
|
|
161
164
|
@Field({ nullable: true })
|
|
162
165
|
releaseDate: string
|
|
163
166
|
|
|
@@ -323,6 +326,9 @@ export class NewReleaseGood {
|
|
|
323
326
|
|
|
324
327
|
@InputType()
|
|
325
328
|
export class ReleaseGoodPatch {
|
|
329
|
+
@Field({ nullable: true })
|
|
330
|
+
id: string
|
|
331
|
+
|
|
326
332
|
@Field({ nullable: true })
|
|
327
333
|
name: string
|
|
328
334
|
|