@things-factory/sales-base 4.0.11 → 4.0.16
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/constants/order.js +9 -1
- package/dist-server/constants/order.js.map +1 -1
- package/dist-server/constants/validation-error-code.js +2 -1
- package/dist-server/constants/validation-error-code.js.map +1 -1
- package/dist-server/controllers/ecommerce/sellercraft-controller.js +3 -3
- package/dist-server/controllers/ecommerce/sellercraft-controller.js.map +1 -1
- package/dist-server/service/arrival-notice/arrival-notice-mutation.js +21 -0
- package/dist-server/service/arrival-notice/arrival-notice-mutation.js.map +1 -1
- package/dist-server/service/arrival-notice/arrival-notice-query.js +74 -77
- package/dist-server/service/arrival-notice/arrival-notice-query.js.map +1 -1
- package/dist-server/service/delivery-order/delivery-order-query.js +21 -5
- package/dist-server/service/delivery-order/delivery-order-query.js.map +1 -1
- package/dist-server/service/goods-receival-note/goods-receival-note-query.js +93 -43
- package/dist-server/service/goods-receival-note/goods-receival-note-query.js.map +1 -1
- package/dist-server/service/index.js +4 -0
- package/dist-server/service/index.js.map +1 -1
- package/dist-server/service/manifest/index.js +9 -0
- package/dist-server/service/manifest/index.js.map +1 -0
- package/dist-server/service/manifest/manifest-mutation.js +111 -0
- package/dist-server/service/manifest/manifest-mutation.js.map +1 -0
- package/dist-server/service/manifest/manifest-query.js +128 -0
- package/dist-server/service/manifest/manifest-query.js.map +1 -0
- package/dist-server/service/manifest/manifest-type.js +125 -0
- package/dist-server/service/manifest/manifest-type.js.map +1 -0
- package/dist-server/service/manifest/manifest.js +122 -0
- package/dist-server/service/manifest/manifest.js.map +1 -0
- package/dist-server/service/order-inventory/order-inventory-mutation.js +24 -0
- package/dist-server/service/order-inventory/order-inventory-mutation.js.map +1 -1
- package/dist-server/service/order-inventory/order-inventory-query.js +20 -19
- package/dist-server/service/order-inventory/order-inventory-query.js.map +1 -1
- package/dist-server/service/order-inventory/order-inventory-types.js +17 -13
- package/dist-server/service/order-inventory/order-inventory-types.js.map +1 -1
- package/dist-server/service/order-inventory/order-inventory.js +24 -2
- package/dist-server/service/order-inventory/order-inventory.js.map +1 -1
- package/dist-server/service/others/other-query.js +1 -0
- package/dist-server/service/others/other-query.js.map +1 -1
- package/dist-server/service/others/other-types.js +4 -0
- package/dist-server/service/others/other-types.js.map +1 -1
- package/dist-server/service/release-good/release-good-mutation.js +393 -1
- package/dist-server/service/release-good/release-good-mutation.js.map +1 -1
- package/dist-server/service/release-good/release-good-query.js +160 -0
- package/dist-server/service/release-good/release-good-query.js.map +1 -1
- package/dist-server/service/release-good/release-good-types.js +34 -2
- package/dist-server/service/release-good/release-good-types.js.map +1 -1
- package/dist-server/service/release-good/release-good.js +28 -1
- package/dist-server/service/release-good/release-good.js.map +1 -1
- package/dist-server/service/reverse-kitting-order/reverse-kitting-order-mutation.js +110 -30
- package/dist-server/service/reverse-kitting-order/reverse-kitting-order-mutation.js.map +1 -1
- package/dist-server/service/reverse-kitting-order/reverse-kitting-order-query.js +94 -21
- package/dist-server/service/reverse-kitting-order/reverse-kitting-order-query.js.map +1 -1
- package/dist-server/service/reverse-kitting-order/reverse-kitting-order-type.js +144 -1
- package/dist-server/service/reverse-kitting-order/reverse-kitting-order-type.js.map +1 -1
- package/dist-server/service/reverse-kitting-order-inventory/reverse-kitting-order-inventory-mutation.js +17 -7
- package/dist-server/service/reverse-kitting-order-inventory/reverse-kitting-order-inventory-mutation.js.map +1 -1
- package/dist-server/utils/inventory-util.js +26 -7
- package/dist-server/utils/inventory-util.js.map +1 -1
- package/dist-server/utils/order-no-generator.js +35 -31
- package/dist-server/utils/order-no-generator.js.map +1 -1
- package/package.json +12 -12
- package/server/constants/index.ts +1 -1
- package/server/constants/order.ts +10 -0
- package/server/constants/validation-error-code.ts +3 -2
- package/server/controllers/ecommerce/sellercraft-controller.ts +4 -3
- package/server/service/arrival-notice/arrival-notice-mutation.ts +20 -0
- package/server/service/arrival-notice/arrival-notice-query.ts +82 -78
- package/server/service/delivery-order/delivery-order-query.ts +26 -7
- package/server/service/goods-receival-note/goods-receival-note-query.ts +116 -53
- package/server/service/index.ts +4 -0
- package/server/service/manifest/index.ts +6 -0
- package/server/service/manifest/manifest-mutation.ts +102 -0
- package/server/service/manifest/manifest-query.ts +99 -0
- package/server/service/manifest/manifest-type.ts +78 -0
- package/server/service/manifest/manifest.ts +103 -0
- package/server/service/order-inventory/order-inventory-mutation.ts +26 -1
- package/server/service/order-inventory/order-inventory-query.ts +17 -18
- package/server/service/order-inventory/order-inventory-types.ts +15 -10
- package/server/service/order-inventory/order-inventory.ts +24 -5
- package/server/service/others/other-query.ts +2 -6
- package/server/service/others/other-types.ts +3 -0
- package/server/service/release-good/release-good-mutation.ts +557 -0
- package/server/service/release-good/release-good-query.ts +197 -2
- package/server/service/release-good/release-good-types.ts +31 -7
- package/server/service/release-good/release-good.ts +26 -0
- package/server/service/reverse-kitting-order/reverse-kitting-order-mutation.ts +145 -35
- package/server/service/reverse-kitting-order/reverse-kitting-order-query.ts +103 -19
- package/server/service/reverse-kitting-order/reverse-kitting-order-type.ts +106 -1
- package/server/service/reverse-kitting-order-inventory/reverse-kitting-order-inventory-mutation.ts +31 -14
- package/server/utils/inventory-util.ts +30 -7
- package/server/utils/order-no-generator.ts +43 -36
- package/dist-server/middlewares/index.js +0 -1
- package/dist-server/middlewares/index.js.map +0 -1
- 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
|
+
}
|