@things-factory/sales-base 4.0.23 → 4.0.27
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/job-sheet/job-sheet-query.js +2 -0
- package/dist-server/service/job-sheet/job-sheet-query.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 +219 -212
- package/dist-server/service/release-good/release-good-mutation.js.map +1 -1
- package/dist-server/service/release-good/release-good-query.js +135 -99
- package/dist-server/service/release-good/release-good-query.js.map +1 -1
- package/dist-server/service/release-good/release-good-types.js +38 -2
- package/dist-server/service/release-good/release-good-types.js.map +1 -1
- package/dist-server/service/release-good/release-good.js +63 -1
- 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/job-sheet/job-sheet-query.ts +3 -1
- package/server/service/order-inventory/order-inventory.ts +17 -1
- package/server/service/release-good/release-good-mutation.ts +280 -283
- package/server/service/release-good/release-good-query.ts +158 -115
- package/server/service/release-good/release-good-types.ts +30 -2
- package/server/service/release-good/release-good.ts +46 -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,12 +1,11 @@
|
|
|
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'
|
|
7
7
|
import {
|
|
8
8
|
Bizplace,
|
|
9
|
-
getCompanyBizplace,
|
|
10
9
|
getDomainUsers,
|
|
11
10
|
getMyBizplace,
|
|
12
11
|
getOutletBizplace,
|
|
@@ -15,6 +14,7 @@ import {
|
|
|
15
14
|
import { generateId } from '@things-factory/id-rule-base'
|
|
16
15
|
import { MarketplaceStore } from '@things-factory/integration-marketplace'
|
|
17
16
|
import { Sellercraft, SellercraftStatus } from '@things-factory/integration-sellercraft'
|
|
17
|
+
import { MarketplaceOrder, MarketplaceProductVariation } from '@things-factory/marketplace-base'
|
|
18
18
|
import { sendNotification } from '@things-factory/notification'
|
|
19
19
|
import { Product, ProductBundleSetting } from '@things-factory/product-base'
|
|
20
20
|
import { PartnerSetting, Setting } from '@things-factory/setting-base'
|
|
@@ -48,9 +48,100 @@ import { ValidationError } from '../../errors'
|
|
|
48
48
|
import { InventoryUtil, OrderNoGenerator } from '../../utils'
|
|
49
49
|
import { confirmArrivalNoticeFunction, deleteArrivalNotice } from '../arrival-notice/arrival-notice-mutation'
|
|
50
50
|
import { ReleaseGood } from './release-good'
|
|
51
|
+
import { bulkReleaseGoodsAvailableItemsFunction } from './release-good-query'
|
|
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 bulkGenerateReleaseGood(
|
|
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 = {
|
|
@@ -683,193 +734,6 @@ export async function generateReleaseGoodFunction(
|
|
|
683
734
|
}
|
|
684
735
|
}
|
|
685
736
|
|
|
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
|
-
|
|
873
737
|
export async function confirmReleaseGood(name: string, context: any, tx?: EntityManager): Promise<ReleaseGood> {
|
|
874
738
|
const { user, domain }: { user: User; domain: Domain } = context.state
|
|
875
739
|
|
|
@@ -883,6 +747,7 @@ export async function confirmReleaseGood(name: string, context: any, tx?: Entity
|
|
|
883
747
|
'bizplace.company.domain',
|
|
884
748
|
'orderProducts',
|
|
885
749
|
'orderProducts.product',
|
|
750
|
+
'orderProducts.product.productDetails',
|
|
886
751
|
'orderInventories',
|
|
887
752
|
'orderInventories.product',
|
|
888
753
|
'orderVass'
|
|
@@ -891,26 +756,77 @@ export async function confirmReleaseGood(name: string, context: any, tx?: Entity
|
|
|
891
756
|
|
|
892
757
|
if (!foundReleaseGood) throw new Error(`Release good order doesn't exists.`)
|
|
893
758
|
let foundOIs: OrderInventory[] = foundReleaseGood.orderInventories
|
|
759
|
+
let foundBundleInfo: any[] = JSON.parse(foundReleaseGood.bundleInfo)
|
|
894
760
|
let foundOVs: OrderVas[] = foundReleaseGood.orderVass
|
|
761
|
+
let foundOPs: OrderProduct[] = foundReleaseGood.orderProducts
|
|
895
762
|
let customerBizplace: Bizplace = foundReleaseGood.bizplace
|
|
896
763
|
const companyDomain: Domain = customerBizplace?.company.domain
|
|
764
|
+
const sellercraft: Sellercraft = await tx
|
|
765
|
+
.getRepository(Sellercraft)
|
|
766
|
+
.findOne({ domain: foundReleaseGood.bizplace.domain, status: SellercraftStatus.ACTIVE })
|
|
897
767
|
|
|
898
768
|
if (foundReleaseGood.type == 'b2c') {
|
|
899
|
-
const sellercraft: Sellercraft = await tx
|
|
900
|
-
.getRepository(Sellercraft)
|
|
901
|
-
.findOne({ domain: foundReleaseGood.bizplace.domain, status: SellercraftStatus.ACTIVE })
|
|
902
|
-
|
|
903
769
|
if (sellercraft) {
|
|
904
770
|
const sellercraftCtrl: SellercraftController = new SellercraftController(tx, domain, user)
|
|
905
771
|
foundReleaseGood = await sellercraftCtrl.packOrder(sellercraft, foundReleaseGood)
|
|
906
772
|
} else {
|
|
907
773
|
// find for any existing marketplace store connections
|
|
908
|
-
|
|
909
|
-
where: { domain: companyDomain, status: 'ACTIVE'
|
|
774
|
+
let marketplaceStores: MarketplaceStore[] = await tx.getRepository(MarketplaceStore).find({
|
|
775
|
+
where: { domain: companyDomain, status: 'ACTIVE' },
|
|
910
776
|
relations: ['marketplaceDistributors']
|
|
911
777
|
})
|
|
912
778
|
|
|
779
|
+
const foundMarketplaceOrder: MarketplaceOrder = await tx.getRepository(MarketplaceOrder).findOne({
|
|
780
|
+
where: { domain: companyDomain, orderNo: foundReleaseGood.refNo },
|
|
781
|
+
relations: ['marketplaceStore']
|
|
782
|
+
})
|
|
783
|
+
|
|
784
|
+
let matchedMarketplaceStore: MarketplaceStore
|
|
785
|
+
if (foundMarketplaceOrder) {
|
|
786
|
+
matchedMarketplaceStore = marketplaceStores.filter(
|
|
787
|
+
marketplaceStore => marketplaceStore.id != foundMarketplaceOrder.marketplaceStore.id
|
|
788
|
+
)[0]
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
let combinedOrderInventories: any[] = foundOIs.map(oi => {
|
|
792
|
+
return {
|
|
793
|
+
sku: oi.product.sku,
|
|
794
|
+
releaseQty: oi.releaseQty
|
|
795
|
+
}
|
|
796
|
+
})
|
|
797
|
+
|
|
798
|
+
if (foundBundleInfo?.length) {
|
|
799
|
+
foundBundleInfo.map(bundle => {
|
|
800
|
+
combinedOrderInventories.push({
|
|
801
|
+
sku: bundle.sku,
|
|
802
|
+
releaseQty: bundle.releaseQty
|
|
803
|
+
})
|
|
804
|
+
})
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
for (let oi of combinedOrderInventories) {
|
|
808
|
+
let foundMarketplaceProductVariations: MarketplaceProductVariation[] = await tx
|
|
809
|
+
.getRepository(MarketplaceProductVariation)
|
|
810
|
+
.find({
|
|
811
|
+
where: { domain: companyDomain, sku: oi.sku },
|
|
812
|
+
relations: ['marketplaceProduct', 'marketplaceProduct.marketplaceStore']
|
|
813
|
+
})
|
|
814
|
+
|
|
815
|
+
if (foundMarketplaceProductVariations) {
|
|
816
|
+
await Promise.all(
|
|
817
|
+
foundMarketplaceProductVariations.map(async variation => {
|
|
818
|
+
if (variation.marketplaceProduct.marketplaceStore.id != matchedMarketplaceStore.id) {
|
|
819
|
+
variation.reserveQty -= oi.releaseQty
|
|
820
|
+
|
|
821
|
+
await tx.getRepository(MarketplaceProductVariation).save(variation)
|
|
822
|
+
}
|
|
823
|
+
})
|
|
824
|
+
)
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
|
|
913
828
|
if (marketplaceStores?.length && marketplaceStores.some(store => store.isAutoUpdateStockQty)) {
|
|
829
|
+
marketplaceStores = marketplaceStores.filter(marketplaceStore => marketplaceStore.isAutoUpdateStockQty)
|
|
914
830
|
let productIds: string[] = foundOIs.map(oi => oi.product.id)
|
|
915
831
|
productIds = Array.from(new Set([...productIds]))
|
|
916
832
|
const ecommerceCtrl: EcommerceController = new EcommerceController(tx, domain, user)
|
|
@@ -919,6 +835,13 @@ export async function confirmReleaseGood(name: string, context: any, tx?: Entity
|
|
|
919
835
|
}
|
|
920
836
|
}
|
|
921
837
|
|
|
838
|
+
if (foundReleaseGood.type == 'b2b') {
|
|
839
|
+
if (sellercraft) {
|
|
840
|
+
const sellercraftCtrl: SellercraftController = new SellercraftController(tx, domain, user)
|
|
841
|
+
await sellercraftCtrl.updateSellercraftStock(sellercraft, foundOPs, 'CONFIRM_ORDER')
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
|
|
922
845
|
// 1. RO Status change (PENDING => PENDING_RECEIVE)
|
|
923
846
|
const releaseGood: ReleaseGood = await tx.getRepository(ReleaseGood).save({
|
|
924
847
|
...foundReleaseGood,
|
|
@@ -1079,7 +1002,17 @@ export async function rejectReleaseGood(
|
|
|
1079
1002
|
|
|
1080
1003
|
const releaseGood: ReleaseGood = await tx.getRepository(ReleaseGood).findOne({
|
|
1081
1004
|
where: { domain, name, status: ORDER_STATUS.PENDING_RECEIVE },
|
|
1082
|
-
relations: [
|
|
1005
|
+
relations: [
|
|
1006
|
+
'bizplace',
|
|
1007
|
+
'bizplace.domain',
|
|
1008
|
+
'orderProducts',
|
|
1009
|
+
'orderProducts.product',
|
|
1010
|
+
'orderProducts.product.productDetails',
|
|
1011
|
+
'orderInventories',
|
|
1012
|
+
'orderInventories.inventory',
|
|
1013
|
+
'orderVass',
|
|
1014
|
+
'shippingOrder'
|
|
1015
|
+
]
|
|
1083
1016
|
})
|
|
1084
1017
|
|
|
1085
1018
|
if (!releaseGood) throw new Error(`Release good doesn't exists.`)
|
|
@@ -1087,6 +1020,7 @@ export async function rejectReleaseGood(
|
|
|
1087
1020
|
|
|
1088
1021
|
let foundOIs: OrderInventory[] = releaseGood.orderInventories
|
|
1089
1022
|
let foundOVs: OrderVas[] = releaseGood.orderVass
|
|
1023
|
+
let foundOPs: OrderProduct[] = releaseGood.orderProducts
|
|
1090
1024
|
|
|
1091
1025
|
// 1. Update status of order products (PENDING_RECEIVE => REJECTED)
|
|
1092
1026
|
if (foundOIs && foundOIs.length) {
|
|
@@ -1112,6 +1046,27 @@ export async function rejectReleaseGood(
|
|
|
1112
1046
|
)
|
|
1113
1047
|
}
|
|
1114
1048
|
|
|
1049
|
+
if (foundOPs && foundOPs.length) {
|
|
1050
|
+
const sellercraft: Sellercraft = await tx
|
|
1051
|
+
.getRepository(Sellercraft)
|
|
1052
|
+
.findOne({ domain: releaseGood.bizplace.domain, status: SellercraftStatus.ACTIVE })
|
|
1053
|
+
|
|
1054
|
+
if (sellercraft) {
|
|
1055
|
+
const sellercraftCtrl: SellercraftController = new SellercraftController(tx, domain, user)
|
|
1056
|
+
await sellercraftCtrl.updateSellercraftStock(sellercraft, foundOPs, 'REJECT_ORDER')
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
await tx.getRepository(OrderProduct).save(
|
|
1060
|
+
await Promise.all(
|
|
1061
|
+
foundOPs.map(async (op: OrderProduct) => {
|
|
1062
|
+
op.status = ORDER_PRODUCT_STATUS.REJECTED
|
|
1063
|
+
op.updater = user
|
|
1064
|
+
return op
|
|
1065
|
+
})
|
|
1066
|
+
)
|
|
1067
|
+
)
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1115
1070
|
// 2. Update status of order vass if it exists (PENDING_RECEIVE => REJECTED)
|
|
1116
1071
|
if (foundOVs && foundOVs.length) {
|
|
1117
1072
|
foundOVs = foundOVs.map((ov: OrderVas) => {
|
|
@@ -1159,7 +1114,7 @@ export async function rejectReleaseGood(
|
|
|
1159
1114
|
return releaseGood
|
|
1160
1115
|
}
|
|
1161
1116
|
|
|
1162
|
-
export async function
|
|
1117
|
+
export async function bulkGenerateReleaseGood(
|
|
1163
1118
|
releaseGood: any,
|
|
1164
1119
|
bizplaceId: string,
|
|
1165
1120
|
roNoSetting: any,
|
|
@@ -1184,7 +1139,6 @@ export async function bulkGenerateReleaseGoods(
|
|
|
1184
1139
|
deliveryAddress2: releaseGood?.deliveryAddress2 || null,
|
|
1185
1140
|
deliveryAddress3: releaseGood?.deliveryAddress3 || null,
|
|
1186
1141
|
deliveryAddress4: releaseGood?.deliveryAddress4 || null,
|
|
1187
|
-
deliveryAddress5: releaseGood?.deliveryAddress5 || null,
|
|
1188
1142
|
attentionTo: releaseGood?.attentionTo || null,
|
|
1189
1143
|
attentionCompany: releaseGood?.attentionCompany || null,
|
|
1190
1144
|
city: releaseGood?.city || null,
|
|
@@ -1206,40 +1160,82 @@ export async function bulkGenerateReleaseGoods(
|
|
|
1206
1160
|
}
|
|
1207
1161
|
|
|
1208
1162
|
newReleaseGood = await tx.getRepository(ReleaseGood).save(newReleaseGood)
|
|
1163
|
+
let finalOrderInventories: OrderInventory[] = []
|
|
1209
1164
|
|
|
1165
|
+
// pre assign inventory to orderInventories
|
|
1210
1166
|
for (let oi of orderInventories) {
|
|
1211
|
-
|
|
1167
|
+
const pickingProductSetting: Setting = await tx.getRepository(Setting).findOne({
|
|
1168
|
+
where: { domain, name: 'rule-for-picking-product' }
|
|
1169
|
+
})
|
|
1212
1170
|
|
|
1213
|
-
let
|
|
1214
|
-
|
|
1215
|
-
|
|
1171
|
+
let locationSortingRules = []
|
|
1172
|
+
if (pickingProductSetting) {
|
|
1173
|
+
let locationSetting = JSON.parse(pickingProductSetting.value)
|
|
1174
|
+
for (const key in locationSetting) {
|
|
1175
|
+
locationSortingRules.push({ name: key, desc: locationSetting[key] == 'ASC' ? false : true })
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
const product: Product = await tx.getRepository(Product).findOne(oi.productId)
|
|
1180
|
+
|
|
1181
|
+
finalOrderInventories.push(
|
|
1182
|
+
...(await InventoryUtil.autoAssignInventoryForRelease(
|
|
1183
|
+
product,
|
|
1184
|
+
oi,
|
|
1185
|
+
oi.packingType,
|
|
1186
|
+
locationSortingRules,
|
|
1187
|
+
bizplace,
|
|
1188
|
+
warehouseDomain,
|
|
1189
|
+
tx
|
|
1190
|
+
))
|
|
1191
|
+
)
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
for (let oi of finalOrderInventories) {
|
|
1195
|
+
let generatedOI: OrderInventory = Object.assign(new OrderInventory(), oi)
|
|
1196
|
+
generatedOI = {
|
|
1197
|
+
...generatedOI,
|
|
1216
1198
|
domain: warehouseDomain,
|
|
1217
|
-
bizplace
|
|
1199
|
+
bizplace,
|
|
1218
1200
|
status: ORDER_INVENTORY_STATUS.PENDING,
|
|
1219
1201
|
name: OrderNoGenerator.orderInventory(),
|
|
1220
|
-
batchId: oi?.batchId || '',
|
|
1221
1202
|
releaseGood: newReleaseGood,
|
|
1222
|
-
product: await tx.getRepository(Product).findOne(oi.productId),
|
|
1223
1203
|
creator: user,
|
|
1224
1204
|
updater: user
|
|
1225
1205
|
}
|
|
1226
1206
|
|
|
1227
|
-
let newOrderProduct: OrderProduct =
|
|
1228
|
-
|
|
1229
|
-
|
|
1207
|
+
let newOrderProduct: Partial<OrderProduct> = {
|
|
1208
|
+
name: generatedOI.name,
|
|
1209
|
+
product: generatedOI.product,
|
|
1210
|
+
batchId: generatedOI.batchId,
|
|
1211
|
+
packingType: generatedOI.packingType,
|
|
1212
|
+
packingSize: generatedOI.packingSize,
|
|
1213
|
+
uom: generatedOI.uom,
|
|
1214
|
+
domain: warehouseDomain,
|
|
1215
|
+
bizplace,
|
|
1216
|
+
releaseQty: generatedOI.releaseQty,
|
|
1217
|
+
releaseUomValue: generatedOI.releaseUomValue,
|
|
1230
1218
|
packQty: 0,
|
|
1231
1219
|
actualPackQty: 0,
|
|
1232
1220
|
palletQty: 0,
|
|
1233
1221
|
actualPalletQty: 0,
|
|
1234
|
-
status: ORDER_PRODUCT_STATUS.PENDING_ASSIGN
|
|
1222
|
+
status: ORDER_PRODUCT_STATUS.PENDING_ASSIGN,
|
|
1223
|
+
releaseGood: newReleaseGood,
|
|
1224
|
+
creator: user,
|
|
1225
|
+
updater: user
|
|
1235
1226
|
}
|
|
1236
1227
|
|
|
1237
1228
|
newOrderProduct = await tx.getRepository(OrderProduct).save(newOrderProduct)
|
|
1238
1229
|
|
|
1239
|
-
await tx.getRepository(OrderInventory).save({ ...
|
|
1240
|
-
}
|
|
1230
|
+
await tx.getRepository(OrderInventory).save({ ...generatedOI, orderProduct: newOrderProduct })
|
|
1241
1231
|
|
|
1242
|
-
|
|
1232
|
+
// update inventory locked qty and uom value
|
|
1233
|
+
await tx.getRepository(Inventory).update(oi.inventory.id, {
|
|
1234
|
+
lockedQty: (oi.inventory?.lockedQty || 0) + generatedOI.releaseQty,
|
|
1235
|
+
lockedUomValue: (oi.inventory?.lockedUomValue || 0) + generatedOI.releaseUomValue,
|
|
1236
|
+
updater: user
|
|
1237
|
+
})
|
|
1238
|
+
}
|
|
1243
1239
|
|
|
1244
1240
|
return newReleaseGood
|
|
1245
1241
|
} catch (error) {
|
|
@@ -1270,7 +1266,7 @@ export async function bulkConfirmReleaseGoods(
|
|
|
1270
1266
|
]
|
|
1271
1267
|
})
|
|
1272
1268
|
|
|
1273
|
-
if (!foundReleaseGoods.length) throw new Error(`
|
|
1269
|
+
if (!foundReleaseGoods.length) throw new Error(`release good order doesn't exists.`)
|
|
1274
1270
|
let customerBizplace: Bizplace = foundReleaseGoods[0].bizplace
|
|
1275
1271
|
|
|
1276
1272
|
let foundOrderInventories: OrderInventory[] = foundReleaseGoods
|
|
@@ -1333,7 +1329,7 @@ export async function bulkConfirmReleaseGoods(
|
|
|
1333
1329
|
})
|
|
1334
1330
|
}
|
|
1335
1331
|
|
|
1336
|
-
|
|
1332
|
+
function extractRawReleaseGoods(rawReleaseGoods): Partial<ReleaseGood[]> {
|
|
1337
1333
|
return rawReleaseGoods.reduce((releaseGoods, item) => {
|
|
1338
1334
|
const idx: number = releaseGoods.findIndex(rg => {
|
|
1339
1335
|
// consider these attributes if they are exist in "item"
|
|
@@ -1370,6 +1366,7 @@ export function extractRawReleaseGoods(rawReleaseGoods): Partial<ReleaseGood[]>
|
|
|
1370
1366
|
oi => oi.sku === item.sku && oi.packingType === item.packingType && oi.packingSize === item.packingSize
|
|
1371
1367
|
)
|
|
1372
1368
|
|
|
1369
|
+
// if there is duplicated SKU, merge them and sum up the releaseQty
|
|
1373
1370
|
if (duplicateSkuIdx >= 0) {
|
|
1374
1371
|
releaseGoods[idx].orderInventories[duplicateSkuIdx].releaseQty += item.releaseQty
|
|
1375
1372
|
} else {
|