@things-factory/sales-base 4.0.21 → 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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@things-factory/sales-base",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.25",
|
|
4
4
|
"main": "dist-server/index.js",
|
|
5
5
|
"browser": "client/index.js",
|
|
6
6
|
"things-factory": true,
|
|
@@ -24,16 +24,16 @@
|
|
|
24
24
|
"migration:create": "node ../../node_modules/typeorm/cli.js migration:create -d ./server/migrations"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@things-factory/attachment-base": "^4.0.
|
|
28
|
-
"@things-factory/auth-base": "^4.0.
|
|
29
|
-
"@things-factory/biz-base": "^4.0.
|
|
30
|
-
"@things-factory/code-base": "^4.0.
|
|
31
|
-
"@things-factory/notification": "^4.0.
|
|
32
|
-
"@things-factory/product-base": "^4.0.
|
|
33
|
-
"@things-factory/setting-base": "^4.0.
|
|
34
|
-
"@things-factory/shell": "^4.0.
|
|
35
|
-
"@things-factory/transport-base": "^4.0.
|
|
36
|
-
"@things-factory/warehouse-base": "^4.0.
|
|
27
|
+
"@things-factory/attachment-base": "^4.0.25",
|
|
28
|
+
"@things-factory/auth-base": "^4.0.25",
|
|
29
|
+
"@things-factory/biz-base": "^4.0.25",
|
|
30
|
+
"@things-factory/code-base": "^4.0.25",
|
|
31
|
+
"@things-factory/notification": "^4.0.25",
|
|
32
|
+
"@things-factory/product-base": "^4.0.25",
|
|
33
|
+
"@things-factory/setting-base": "^4.0.25",
|
|
34
|
+
"@things-factory/shell": "^4.0.25",
|
|
35
|
+
"@things-factory/transport-base": "^4.0.25",
|
|
36
|
+
"@things-factory/warehouse-base": "^4.0.25"
|
|
37
37
|
},
|
|
38
|
-
"gitHead": "
|
|
38
|
+
"gitHead": "9c44141d651dab7b4a9c0f0b6fecb8d6937d116f"
|
|
39
39
|
}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
import { MarketplaceStore, MarketplaceSetting, StoreAPI } from '@things-factory/integration-marketplace'
|
|
1
|
+
import { Equal, Not } from 'typeorm'
|
|
2
|
+
|
|
3
|
+
import { MarketplaceSetting, MarketplaceStore, StoreAPI } from '@things-factory/integration-marketplace'
|
|
5
4
|
import { MarketplaceProductVariation } from '@things-factory/marketplace-base'
|
|
5
|
+
import { Product } from '@things-factory/product-base'
|
|
6
|
+
import { Domain } from '@things-factory/shell'
|
|
7
|
+
import { Inventory, INVENTORY_STATUS, LOCATION_TYPE } from '@things-factory/warehouse-base'
|
|
8
|
+
|
|
6
9
|
import { OrderController } from '../order-controller'
|
|
7
10
|
|
|
8
11
|
export class EcommerceController extends OrderController {
|
|
@@ -14,10 +17,16 @@ export class EcommerceController extends OrderController {
|
|
|
14
17
|
const inventoryProducts: any[] = await Promise.all(
|
|
15
18
|
productIds.map(async productId => {
|
|
16
19
|
const product: Product = await this.trxMgr.getRepository(Product).findOne(productId)
|
|
17
|
-
|
|
18
|
-
where: { domain: this.domain, product }
|
|
20
|
+
let inventories: Inventory[] = await this.trxMgr.getRepository(Inventory).find({
|
|
21
|
+
where: { domain: this.domain, product, status: Not(Equal(INVENTORY_STATUS.TERMINATED)) },
|
|
22
|
+
relations: ['location']
|
|
19
23
|
})
|
|
20
24
|
|
|
25
|
+
inventories = inventories.filter(
|
|
26
|
+
inventory =>
|
|
27
|
+
inventory?.location.type !== LOCATION_TYPE.QUARANTINE || inventory?.location.type !== LOCATION_TYPE.RESERVE
|
|
28
|
+
)
|
|
29
|
+
|
|
21
30
|
const inventoryQty: number = inventories.reduce((total, currentValue) => {
|
|
22
31
|
total += currentValue.qty
|
|
23
32
|
return total
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
import { Equal, Not } from 'typeorm'
|
|
2
|
+
|
|
1
3
|
import { Sellercraft, SellercraftAPI } from '@things-factory/integration-sellercraft'
|
|
2
|
-
import { Product } from '@things-factory/product-base'
|
|
4
|
+
import { Product, ProductDetail } from '@things-factory/product-base'
|
|
5
|
+
import { Inventory, INVENTORY_STATUS } from '@things-factory/warehouse-base'
|
|
3
6
|
|
|
7
|
+
import { ORDER_PRODUCT_STATUS } from '../../constants'
|
|
4
8
|
import { OrderProduct, ReleaseGood } from '../../service'
|
|
5
9
|
import { OrderController } from '../order-controller'
|
|
6
10
|
|
|
@@ -31,6 +35,78 @@ export class SellercraftController extends OrderController {
|
|
|
31
35
|
return releaseGood
|
|
32
36
|
}
|
|
33
37
|
|
|
38
|
+
async updateSellercraftStock(sellercraft: Sellercraft, orderProducts: OrderProduct[], type: string): Promise<void> {
|
|
39
|
+
for (var i = 0; i < orderProducts.length; i++) {
|
|
40
|
+
const orderProduct: OrderProduct = orderProducts[i]
|
|
41
|
+
|
|
42
|
+
const product: Product = orderProduct.product
|
|
43
|
+
const pendingAssignOPs: OrderProduct[] = await this.trxMgr
|
|
44
|
+
.getRepository(OrderProduct)
|
|
45
|
+
.find({ where: { domain: this.domain, product, status: ORDER_PRODUCT_STATUS.PENDING_ASSIGN } })
|
|
46
|
+
|
|
47
|
+
const productDetails: ProductDetail[] = product.productDetails
|
|
48
|
+
|
|
49
|
+
let totalUnassignReleaseQty: number = 0
|
|
50
|
+
if (pendingAssignOPs?.length) {
|
|
51
|
+
totalUnassignReleaseQty = pendingAssignOPs.reduce((total, currentValue) => {
|
|
52
|
+
total += currentValue.releaseQty
|
|
53
|
+
return total
|
|
54
|
+
}, 0)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const inventories: Inventory[] = await this.trxMgr.getRepository(Inventory).find({
|
|
58
|
+
where: { domain: this.domain, product, status: Not(Equal(INVENTORY_STATUS.TERMINATED)) }
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
let defaultProductDetail: ProductDetail
|
|
62
|
+
const sellercraftInvs: any[] = await Promise.all(
|
|
63
|
+
inventories.map(async (inventory: Inventory) => {
|
|
64
|
+
const inventoryPackingType: string = inventory.packingType
|
|
65
|
+
defaultProductDetail = product.productDetails.find(productDetail => productDetail.isDefault)
|
|
66
|
+
|
|
67
|
+
let packingSize: number = 1
|
|
68
|
+
if (inventoryPackingType !== defaultProductDetail.packingType) {
|
|
69
|
+
const unmatchingProductDetail: ProductDetail = product.productDetails.find(
|
|
70
|
+
productDetail => productDetail.packingType === inventoryPackingType
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
packingSize = await this.getChildPackingSize(productDetails, defaultProductDetail, unmatchingProductDetail)
|
|
74
|
+
if (packingSize == 0) packingSize = 1
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return { quantity: inventory.qty * packingSize - inventory.lockedQty * packingSize }
|
|
78
|
+
})
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
let inventoryTotalQty: number = sellercraftInvs.reduce((total, currentValue) => {
|
|
82
|
+
total += currentValue.quantity
|
|
83
|
+
return total
|
|
84
|
+
}, 0)
|
|
85
|
+
|
|
86
|
+
switch (type) {
|
|
87
|
+
case 'CONFIRM_ORDER':
|
|
88
|
+
inventoryTotalQty -= totalUnassignReleaseQty
|
|
89
|
+
break
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const sellercraftInv: any = {
|
|
93
|
+
accountId: sellercraft.accountId,
|
|
94
|
+
sku: product.sku,
|
|
95
|
+
uom: 'EA',
|
|
96
|
+
quantity: inventoryTotalQty,
|
|
97
|
+
gtin: defaultProductDetail.gtin,
|
|
98
|
+
weight: defaultProductDetail.nettWeight < 1 ? 1 : defaultProductDetail.nettWeight,
|
|
99
|
+
packageDimension: {
|
|
100
|
+
length: defaultProductDetail.depth < 1 ? 1 : defaultProductDetail.depth,
|
|
101
|
+
width: defaultProductDetail.width < 1 ? 1 : defaultProductDetail.width,
|
|
102
|
+
height: defaultProductDetail.height < 1 ? 1 : defaultProductDetail.height
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
await SellercraftAPI.updateProduct(sellercraft, { sellercraftInv })
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
34
110
|
async checkExistingReleaseGood(sellercraft: Sellercraft, releaseGood: ReleaseGood): Promise<void> {
|
|
35
111
|
const { refNo, refNo2 } = releaseGood
|
|
36
112
|
const foundReleaseGood: ReleaseGood = await this.trxMgr.getRepository(ReleaseGood).findOne({
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
import { EntityManager, EntitySchema, FindOneOptions } from 'typeorm'
|
|
2
|
+
|
|
1
3
|
import { Role, User } from '@things-factory/auth-base'
|
|
2
4
|
import { Bizplace, getDomainUsers } from '@things-factory/biz-base'
|
|
3
5
|
import { sendNotification } from '@things-factory/notification'
|
|
6
|
+
import { ProductDetail } from '@things-factory/product-base'
|
|
4
7
|
import { Domain } from '@things-factory/shell'
|
|
5
8
|
import { Inventory } from '@things-factory/warehouse-base'
|
|
6
|
-
|
|
9
|
+
|
|
7
10
|
import {
|
|
8
11
|
ArrivalNotice,
|
|
9
12
|
DeliveryOrder,
|
|
@@ -48,7 +51,9 @@ export type NotificationMsgInterface = {
|
|
|
48
51
|
export class OrderController {
|
|
49
52
|
public readonly ERROR_MSG = {
|
|
50
53
|
FIND: {
|
|
51
|
-
NO_RESULT: (condition: any) => `There's no results matched with condition ${condition}
|
|
54
|
+
NO_RESULT: (condition: any) => `There's no results matched with condition ${condition}`,
|
|
55
|
+
NO_CHILD_RESULT: (condition: any) => `There's no child result matched with condition ${condition}`,
|
|
56
|
+
NOT_MATCH: (source: any, target: any) => `Unable to find matching ${target} using ${source}`
|
|
52
57
|
},
|
|
53
58
|
CREATE: {
|
|
54
59
|
ID_EXISTS: 'Target has ID already',
|
|
@@ -217,6 +222,54 @@ export class OrderController {
|
|
|
217
222
|
return await this.trxMgr.getRepository(Inventory).save(inventory)
|
|
218
223
|
}
|
|
219
224
|
|
|
225
|
+
async getChildPackingSize(
|
|
226
|
+
productDetails: ProductDetail[],
|
|
227
|
+
defaultProductDetail: ProductDetail,
|
|
228
|
+
unmatchingProductDetail: ProductDetail
|
|
229
|
+
): Promise<number> {
|
|
230
|
+
let hasChildRelation: boolean = Boolean(unmatchingProductDetail?.childProductDetail)
|
|
231
|
+
let hasMatchingChild: boolean
|
|
232
|
+
let packingSize: number = 1
|
|
233
|
+
let currentChildProductDetail: ProductDetail
|
|
234
|
+
|
|
235
|
+
if (hasChildRelation) {
|
|
236
|
+
currentChildProductDetail = productDetails.find(
|
|
237
|
+
(productDetail: ProductDetail) => productDetail.id === unmatchingProductDetail.childProductDetail.id
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
if (!currentChildProductDetail) {
|
|
241
|
+
throw new Error(this.ERROR_MSG.FIND.NOT_MATCH('packing type', `GTIN (${unmatchingProductDetail.gtin})`))
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
hasMatchingChild = Boolean(defaultProductDetail.id === currentChildProductDetail.id)
|
|
245
|
+
if (hasMatchingChild) {
|
|
246
|
+
packingSize = unmatchingProductDetail.packingSize
|
|
247
|
+
} else {
|
|
248
|
+
packingSize = unmatchingProductDetail.packingSize * packingSize
|
|
249
|
+
}
|
|
250
|
+
} else {
|
|
251
|
+
throw new Error(this.ERROR_MSG.FIND.NO_CHILD_RESULT(`${unmatchingProductDetail.gtin}`))
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
while (hasChildRelation && !hasMatchingChild) {
|
|
255
|
+
if (hasMatchingChild) {
|
|
256
|
+
packingSize = currentChildProductDetail.packingSize * packingSize // 12 x 10
|
|
257
|
+
} else if (!hasMatchingChild && hasChildRelation) {
|
|
258
|
+
packingSize = currentChildProductDetail.packingSize * packingSize // 12 x 10
|
|
259
|
+
currentChildProductDetail = productDetails.find(
|
|
260
|
+
(productDetail: ProductDetail) => productDetail.id === currentChildProductDetail.childProductDetail.id
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
hasChildRelation = Boolean(currentChildProductDetail?.childProductDetail)
|
|
264
|
+
hasMatchingChild = Boolean(defaultProductDetail.id === currentChildProductDetail.id)
|
|
265
|
+
} else if (!hasChildRelation && !hasMatchingChild) {
|
|
266
|
+
throw new Error(this.ERROR_MSG.FIND.NO_RESULT(unmatchingProductDetail.gtin))
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
return packingSize
|
|
271
|
+
}
|
|
272
|
+
|
|
220
273
|
/**
|
|
221
274
|
* @summary set common stamp like domain, creator, updater
|
|
222
275
|
* @description Set common stamp to passed record
|
|
@@ -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, Repository } from 'typeorm'
|
|
3
|
+
import { EntityManager, getConnection, getRepository, In, Repository } from 'typeorm'
|
|
4
4
|
|
|
5
5
|
import { Attachment, createAttachments } from '@things-factory/attachment-base'
|
|
6
6
|
import { Role, User } from '@things-factory/auth-base'
|
|
@@ -38,10 +38,13 @@ import {
|
|
|
38
38
|
ORDER_VAS_STATUS
|
|
39
39
|
} from '../../constants'
|
|
40
40
|
import { ATTACHMENT_TYPE } from '../../constants/attachment-type'
|
|
41
|
+
import { ValidationError } from '../../errors'
|
|
41
42
|
import { OrderNoGenerator } from '../../utils/order-no-generator'
|
|
42
43
|
import { generateJobSheet } from '../job-sheet/job-sheet-mutation'
|
|
43
44
|
import { confirmReleaseGood, deleteReleaseGood, rejectReleaseGood } from '../release-good/release-good-mutation'
|
|
45
|
+
import { validateBulkArrivalNoticesFunction } from './'
|
|
44
46
|
import { ArrivalNotice } from './arrival-notice'
|
|
47
|
+
import { ArrivalNoticeList, RawArrivalNotice } from './arrival-notice-types'
|
|
45
48
|
|
|
46
49
|
const debug = require('debug')('things-factory:operato-wms:addArrivalNotice')
|
|
47
50
|
|
|
@@ -230,6 +233,139 @@ export class ArrivalNoticeMutation {
|
|
|
230
233
|
await tx.getRepository(ArrivalNotice).update(existingArrivalNotice.id, arrivalNotice)
|
|
231
234
|
return await tx.getRepository(ArrivalNotice).findOne(existingArrivalNotice.id)
|
|
232
235
|
}
|
|
236
|
+
|
|
237
|
+
@Directive('@privilege(category: "order_customer", privilege: "mutation")')
|
|
238
|
+
@Directive('@transaction')
|
|
239
|
+
@Mutation(returns => ArrivalNoticeList)
|
|
240
|
+
async bulkGenerateArrivalNotices(
|
|
241
|
+
@Ctx() context: any,
|
|
242
|
+
@Arg('rawArrivalNotices', type => [NewArrivalNotice], { nullable: true }) rawArrivalNotices: NewArrivalNotice[],
|
|
243
|
+
@Arg('bizplaceId', type => String) bizplaceId: string
|
|
244
|
+
): Promise<ArrivalNoticeList> {
|
|
245
|
+
const { domain, user, tx }: { domain: Domain; user: User; tx: EntityManager } = context.state
|
|
246
|
+
let createdArrivalNoticeIds: string[] = [],
|
|
247
|
+
createdOrderProductIds: string[] = [],
|
|
248
|
+
errorsCaught: any[] = [],
|
|
249
|
+
finalArrivalNoticeList: ArrivalNotice[] = []
|
|
250
|
+
|
|
251
|
+
const foundBizplace: Bizplace = await tx.getRepository(Bizplace).findOne(bizplaceId)
|
|
252
|
+
|
|
253
|
+
if (!foundBizplace) throw new Error('company not found')
|
|
254
|
+
|
|
255
|
+
// to check whether the raw data are valid
|
|
256
|
+
const validatedArrivalNotices: RawArrivalNotice[] = await validateBulkArrivalNoticesFunction(
|
|
257
|
+
rawArrivalNotices,
|
|
258
|
+
bizplaceId,
|
|
259
|
+
tx
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
// check for custom GAN order no setting
|
|
263
|
+
const ganNoSetting: Setting = await tx.getRepository(Setting).findOne({
|
|
264
|
+
where: {
|
|
265
|
+
domain,
|
|
266
|
+
name: ORDER_NUMBER_SETTING_KEY.GAN_NUMBER_RULE
|
|
267
|
+
}
|
|
268
|
+
})
|
|
269
|
+
|
|
270
|
+
// extract rawArrivalNotices data into normal ArrivalNotice format
|
|
271
|
+
let arrivalNotices: Partial<ArrivalNotice[]> = extractArrivalNotices(validatedArrivalNotices)
|
|
272
|
+
|
|
273
|
+
for (let i = 0, l = arrivalNotices.length; i < l; i++) {
|
|
274
|
+
try {
|
|
275
|
+
await getConnection().transaction(async childTx => {
|
|
276
|
+
// check for duplication
|
|
277
|
+
const duplicatedArrivalNotice: ArrivalNotice = await childTx.getRepository(ArrivalNotice).findOne({
|
|
278
|
+
where: {
|
|
279
|
+
refNo: arrivalNotices[i].refNo,
|
|
280
|
+
refNo2: arrivalNotices[i].refNo2,
|
|
281
|
+
refNo3: arrivalNotices[i].refNo3,
|
|
282
|
+
etaDate: arrivalNotices[i].etaDate,
|
|
283
|
+
truckNo: arrivalNotices[i].truckNo,
|
|
284
|
+
containerNo: arrivalNotices[i].containerNo,
|
|
285
|
+
containerSize: arrivalNotices[i].containerSize,
|
|
286
|
+
looseItem: arrivalNotices[i].looseItem,
|
|
287
|
+
importCargo: arrivalNotices[i].importCargo
|
|
288
|
+
}
|
|
289
|
+
})
|
|
290
|
+
|
|
291
|
+
if (duplicatedArrivalNotice) {
|
|
292
|
+
throw new Error(`duplicated with ${duplicatedArrivalNotice.name}`)
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// save new arrival notice
|
|
296
|
+
const createdArrivalNotice: ArrivalNotice = await childTx.getRepository(ArrivalNotice).save({
|
|
297
|
+
...arrivalNotices[i],
|
|
298
|
+
name: ganNoSetting
|
|
299
|
+
? await generateId({ domain, type: ORDER_NUMBER_RULE_TYPE.GAN_NUMBER, seed: {} })
|
|
300
|
+
: OrderNoGenerator.arrivalNotice(),
|
|
301
|
+
domain,
|
|
302
|
+
bizplace: foundBizplace,
|
|
303
|
+
status: ORDER_STATUS.PENDING,
|
|
304
|
+
creator: user,
|
|
305
|
+
updater: user
|
|
306
|
+
})
|
|
307
|
+
|
|
308
|
+
// save new order products
|
|
309
|
+
let createdOrderProducts: OrderProduct[] = await Promise.all(
|
|
310
|
+
arrivalNotices[i].orderProducts.map(async (op: OrderProduct) => {
|
|
311
|
+
return {
|
|
312
|
+
...op,
|
|
313
|
+
domain,
|
|
314
|
+
bizplace: foundBizplace,
|
|
315
|
+
name: OrderNoGenerator.orderProduct(),
|
|
316
|
+
// product: await childTx.getRepository(Product).findOne(op.product.id),
|
|
317
|
+
status: ORDER_PRODUCT_STATUS.PENDING,
|
|
318
|
+
arrivalNotice: createdArrivalNotice,
|
|
319
|
+
creator: user
|
|
320
|
+
}
|
|
321
|
+
})
|
|
322
|
+
)
|
|
323
|
+
createdOrderProducts = await childTx.getRepository(OrderProduct).save(createdOrderProducts)
|
|
324
|
+
|
|
325
|
+
// generate new jobsheet
|
|
326
|
+
await generateJobSheet(domain, user, createdArrivalNotice, childTx)
|
|
327
|
+
|
|
328
|
+
// push arrivalNotice and orderProducts IDs if successfully saved
|
|
329
|
+
createdArrivalNoticeIds.push(createdArrivalNotice.id)
|
|
330
|
+
createdOrderProductIds.push(...createdOrderProducts.map(op => op.id))
|
|
331
|
+
})
|
|
332
|
+
} catch (error) {
|
|
333
|
+
// collect the arrivalNotice details and its error
|
|
334
|
+
let rawArrivalNotices: RawArrivalNotice[] = formRawArrivalNotices(arrivalNotices[i], error.message)
|
|
335
|
+
errorsCaught.push(...rawArrivalNotices)
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
if (createdArrivalNoticeIds.length && createdOrderProductIds.length) {
|
|
340
|
+
await getConnection().transaction(async childTx => {
|
|
341
|
+
// update arrivalNotices status to PENDING_RECEIVE
|
|
342
|
+
await childTx
|
|
343
|
+
.getRepository(ArrivalNotice)
|
|
344
|
+
.update({ id: In(createdArrivalNoticeIds) }, { status: ORDER_STATUS.PENDING_RECEIVE, updater: user })
|
|
345
|
+
|
|
346
|
+
// update orderProducts status to PENDING_RECEIVE
|
|
347
|
+
await childTx
|
|
348
|
+
.getRepository(OrderProduct)
|
|
349
|
+
.update({ id: In(createdOrderProductIds) }, { status: ORDER_PRODUCT_STATUS.PENDING_RECEIVE, updater: user })
|
|
350
|
+
|
|
351
|
+
finalArrivalNoticeList = await childTx.getRepository(ArrivalNotice).find({
|
|
352
|
+
where: { id: In(createdArrivalNoticeIds) },
|
|
353
|
+
relations: ['orderProducts', 'orderProducts.product', 'bizplace']
|
|
354
|
+
})
|
|
355
|
+
})
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
if (errorsCaught.length) {
|
|
359
|
+
// should return this error list in the grist so that user know which gan need to amend
|
|
360
|
+
throw new ValidationError({
|
|
361
|
+
...ValidationError.ERROR_CODES.INVALID_DATA_FOUND,
|
|
362
|
+
detail: { data: JSON.stringify(errorsCaught) }
|
|
363
|
+
})
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// return arrivalNotices with its orderProducts list
|
|
367
|
+
return { items: finalArrivalNoticeList, total: 0 }
|
|
368
|
+
}
|
|
233
369
|
}
|
|
234
370
|
|
|
235
371
|
export async function deleteArrivalNotice(
|
|
@@ -780,3 +916,103 @@ export async function editArrivalNoticeProducts(
|
|
|
780
916
|
debug('gan-updated-order-products', updatedOrderProducts)
|
|
781
917
|
await orderProductRepo.save(updatedOrderProducts)
|
|
782
918
|
}
|
|
919
|
+
|
|
920
|
+
function extractArrivalNotices(rawArrivalNotices): Partial<ArrivalNotice[]> {
|
|
921
|
+
return rawArrivalNotices.reduce((arrivalNotices, raw) => {
|
|
922
|
+
// discard the item that has no productId or productDetailId
|
|
923
|
+
if (!raw.productId || !raw.productDetailId) return
|
|
924
|
+
|
|
925
|
+
const idx: number = arrivalNotices.findIndex(an => {
|
|
926
|
+
// consider these attributes if they are exist in "item"
|
|
927
|
+
const comparison = [
|
|
928
|
+
'refNo2',
|
|
929
|
+
'refNo3',
|
|
930
|
+
'truckNo',
|
|
931
|
+
'ownTransport',
|
|
932
|
+
'container',
|
|
933
|
+
'containerNo',
|
|
934
|
+
'containerSize',
|
|
935
|
+
'looseItem',
|
|
936
|
+
'importCargo'
|
|
937
|
+
]
|
|
938
|
+
|
|
939
|
+
let a: any = {},
|
|
940
|
+
b: any = {}
|
|
941
|
+
|
|
942
|
+
comparison.forEach(cc => {
|
|
943
|
+
if (raw[cc] !== null) {
|
|
944
|
+
a[cc] = raw[cc]
|
|
945
|
+
b[cc] = an[cc]
|
|
946
|
+
}
|
|
947
|
+
})
|
|
948
|
+
|
|
949
|
+
a = JSON.stringify(Object.fromEntries(Object.entries(a).sort()))
|
|
950
|
+
b = JSON.stringify(Object.fromEntries(Object.entries(b).sort()))
|
|
951
|
+
|
|
952
|
+
return an.refNo == raw.refNo && an.etaDate == raw.etaDate && a === b
|
|
953
|
+
})
|
|
954
|
+
|
|
955
|
+
const product: Product = Object.assign(new Product(), { id: raw.productId, sku: raw.sku })
|
|
956
|
+
const orderProduct: Partial<OrderProduct> = {
|
|
957
|
+
product,
|
|
958
|
+
batchId: raw.batchId,
|
|
959
|
+
packingType: raw.packingType,
|
|
960
|
+
packingSize: raw.packingSize,
|
|
961
|
+
packQty: raw.packQty,
|
|
962
|
+
uomValue: raw.uomValue,
|
|
963
|
+
uom: raw.uom,
|
|
964
|
+
totalUomValue: raw.totalUomValue,
|
|
965
|
+
palletQty: raw.palletQty,
|
|
966
|
+
unitPrice: raw.unitPrice,
|
|
967
|
+
manufactureYear: raw.manufactureYear
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
if (idx >= 0) {
|
|
971
|
+
const duplicateSkuIdx: number = arrivalNotices[idx].orderProducts.findIndex(
|
|
972
|
+
op =>
|
|
973
|
+
op.sku === raw.sku &&
|
|
974
|
+
op.packingType === raw.packingType &&
|
|
975
|
+
op.packingSize === raw.packingSize &&
|
|
976
|
+
op.batchId === raw.batchId
|
|
977
|
+
)
|
|
978
|
+
|
|
979
|
+
if (duplicateSkuIdx >= 0) arrivalNotices[idx].orderProducts[duplicateSkuIdx].packQty += raw.packQty
|
|
980
|
+
else arrivalNotices[idx].orderProducts.push(orderProduct)
|
|
981
|
+
} else {
|
|
982
|
+
arrivalNotices.push({
|
|
983
|
+
refNo: raw.refNo,
|
|
984
|
+
refNo2: raw.refNo2,
|
|
985
|
+
refNo3: raw.refNo3,
|
|
986
|
+
etaDate: raw.etaDate,
|
|
987
|
+
truckNo: raw.truckNo,
|
|
988
|
+
ownTransport: raw.ownTransport,
|
|
989
|
+
container: raw.container,
|
|
990
|
+
containerNo: raw.containerNo,
|
|
991
|
+
containerSize: raw.containerSize,
|
|
992
|
+
importCargo: raw.importCargo,
|
|
993
|
+
looseItem: raw.looseItem,
|
|
994
|
+
orderProducts: [orderProduct]
|
|
995
|
+
})
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
return arrivalNotices
|
|
999
|
+
}, [])
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
function formRawArrivalNotices(arrivalNotice, errorMessage) {
|
|
1003
|
+
let rawArrivalNotices = []
|
|
1004
|
+
for (let i = 0, l = arrivalNotice.orderProducts.length; i < l; i++) {
|
|
1005
|
+
let rawArrivalNotice = {
|
|
1006
|
+
...arrivalNotice,
|
|
1007
|
+
...arrivalNotice.orderProducts[i],
|
|
1008
|
+
sku: arrivalNotice.orderProducts[i].product.sku,
|
|
1009
|
+
remark: errorMessage
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
delete rawArrivalNotice.orderProducts
|
|
1013
|
+
delete rawArrivalNotice.product
|
|
1014
|
+
|
|
1015
|
+
rawArrivalNotices.push(rawArrivalNotice)
|
|
1016
|
+
}
|
|
1017
|
+
return rawArrivalNotices
|
|
1018
|
+
}
|