@things-factory/sales-base 4.0.12 → 4.0.17
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/service/arrival-notice/arrival-notice-query.js +0 -1
- package/dist-server/service/arrival-notice/arrival-notice-query.js.map +1 -1
- package/dist-server/service/manifest/manifest-mutation.js +63 -72
- package/dist-server/service/manifest/manifest-mutation.js.map +1 -1
- package/dist-server/service/manifest/manifest-query.js +49 -8
- package/dist-server/service/manifest/manifest-query.js.map +1 -1
- package/dist-server/service/manifest/manifest-type.js +67 -27
- package/dist-server/service/manifest/manifest-type.js.map +1 -1
- package/dist-server/service/manifest/manifest.js +5 -0
- package/dist-server/service/manifest/manifest.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 +360 -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/reverse-kitting-order/reverse-kitting-order-mutation.js +66 -19
- 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 +84 -72
- 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/package.json +12 -12
- package/server/service/arrival-notice/arrival-notice-query.ts +0 -2
- package/server/service/manifest/manifest-mutation.ts +78 -88
- package/server/service/manifest/manifest-query.ts +64 -8
- package/server/service/manifest/manifest-type.ts +47 -20
- package/server/service/manifest/manifest.ts +5 -0
- package/server/service/others/other-types.ts +3 -0
- package/server/service/release-good/release-good-mutation.ts +512 -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/reverse-kitting-order/reverse-kitting-order-mutation.ts +82 -21
- package/server/service/reverse-kitting-order/reverse-kitting-order-query.ts +95 -79
- 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
|
@@ -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'
|
|
@@ -204,6 +206,71 @@ export class ReleaseGoodMutation {
|
|
|
204
206
|
|
|
205
207
|
return receivedRO
|
|
206
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
|
+
}
|
|
207
274
|
}
|
|
208
275
|
|
|
209
276
|
export async function deleteReleaseGood(tx: EntityManager, name: string, user: User, domain: Domain): Promise<boolean> {
|
|
@@ -616,6 +683,193 @@ export async function generateReleaseGoodFunction(
|
|
|
616
683
|
}
|
|
617
684
|
}
|
|
618
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
|
+
|
|
619
873
|
export async function confirmReleaseGood(name: string, context: any, tx?: EntityManager): Promise<ReleaseGood> {
|
|
620
874
|
const { user, domain }: { user: User; domain: Domain } = context.state
|
|
621
875
|
|
|
@@ -904,3 +1158,261 @@ export async function rejectReleaseGood(
|
|
|
904
1158
|
|
|
905
1159
|
return releaseGood
|
|
906
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
|
+
}
|