@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,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
|
+
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { Arg, Args, Ctx, Directive, FieldResolver, Query, Resolver, Root } from 'type-graphql'
|
|
2
|
-
import { getRepository, In, SelectQueryBuilder } from 'typeorm'
|
|
2
|
+
import { EntityManager, getRepository, In, SelectQueryBuilder } from 'typeorm'
|
|
3
3
|
|
|
4
4
|
import { Attachment } from '@things-factory/attachment-base'
|
|
5
|
-
import { User } from '@things-factory/auth-base'
|
|
6
|
-
import { Bizplace, getPermittedBizplaceIds } from '@things-factory/biz-base'
|
|
5
|
+
import { checkUserBelongsDomain, User } from '@things-factory/auth-base'
|
|
6
|
+
import { Bizplace, getCompanyBizplace, getPermittedBizplaceIds } from '@things-factory/biz-base'
|
|
7
7
|
import { ProductDetail } from '@things-factory/product-base'
|
|
8
8
|
import { buildQuery, Domain, ListParam } from '@things-factory/shell'
|
|
9
9
|
|
|
10
|
-
import { ArrivalNoticeList } from '../'
|
|
10
|
+
import { ArrivalNoticeList, NewArrivalNotice, RawArrivalNotice } from '../'
|
|
11
11
|
import { ATTACHMENT_TYPE, ORDER_STATUS } from '../../constants'
|
|
12
12
|
import { OrderInventory, OrderProduct } from '../../service'
|
|
13
13
|
import { ArrivalNotice } from './arrival-notice'
|
|
@@ -34,6 +34,7 @@ export class ArrivalNoticeQuery {
|
|
|
34
34
|
relations: [
|
|
35
35
|
'domain',
|
|
36
36
|
'bizplace',
|
|
37
|
+
'bizplace.domain',
|
|
37
38
|
'releaseGood',
|
|
38
39
|
'purchaseOrder',
|
|
39
40
|
'purchaseOrder.bufferLocation',
|
|
@@ -117,6 +118,17 @@ export class ArrivalNoticeQuery {
|
|
|
117
118
|
async arrivalNotices(@Ctx() context: any, @Args() params: ListParam): Promise<ArrivalNoticeList> {
|
|
118
119
|
const { domain, user }: { domain: Domain; user: User } = context.state
|
|
119
120
|
|
|
121
|
+
if (await checkUserBelongsDomain(domain, user)) {
|
|
122
|
+
if (!params.filters.some(e => e.name === 'status') && !params.filters.some(e => e.name === 'name')) {
|
|
123
|
+
params.filters.push({
|
|
124
|
+
name: 'status',
|
|
125
|
+
operator: 'notin',
|
|
126
|
+
value: [ORDER_STATUS.PENDING, ORDER_STATUS.EDITING],
|
|
127
|
+
relation: false
|
|
128
|
+
})
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
120
132
|
if (!params.filters.find((filter: any) => filter.name === 'bizplace')) {
|
|
121
133
|
params.filters.push({
|
|
122
134
|
name: 'bizplaceId',
|
|
@@ -287,6 +299,17 @@ export class ArrivalNoticeQuery {
|
|
|
287
299
|
}
|
|
288
300
|
}
|
|
289
301
|
|
|
302
|
+
@Directive('@transaction')
|
|
303
|
+
@Query(returns => [RawArrivalNotice])
|
|
304
|
+
async validateBulkArrivalNotices(
|
|
305
|
+
@Ctx() context: any,
|
|
306
|
+
@Arg('rawArrivalNotices', type => [NewArrivalNotice], { nullable: true }) rawArrivalNotices: NewArrivalNotice[],
|
|
307
|
+
@Arg('bizplaceId', type => String) bizplaceId: string
|
|
308
|
+
): Promise<RawArrivalNotice[]> {
|
|
309
|
+
const tx: EntityManager = context.state.tx
|
|
310
|
+
return await validateBulkArrivalNoticesFunction(rawArrivalNotices, bizplaceId, tx)
|
|
311
|
+
}
|
|
312
|
+
|
|
290
313
|
@FieldResolver(type => Domain)
|
|
291
314
|
async domain(@Root() arrivalNotice: ArrivalNotice): Promise<Domain> {
|
|
292
315
|
return await getRepository(Domain).findOne(arrivalNotice.domainId)
|
|
@@ -302,3 +325,190 @@ export class ArrivalNoticeQuery {
|
|
|
302
325
|
return await getRepository(User).findOne(arrivalNotice.updaterId)
|
|
303
326
|
}
|
|
304
327
|
}
|
|
328
|
+
|
|
329
|
+
export async function validateBulkArrivalNoticesFunction(
|
|
330
|
+
rawArrivalNotices: NewArrivalNotice[],
|
|
331
|
+
bizplaceId: string,
|
|
332
|
+
trxMgr: EntityManager
|
|
333
|
+
): Promise<RawArrivalNotice[]> {
|
|
334
|
+
const companyBizplace: Bizplace = await getCompanyBizplace(null, null, bizplaceId)
|
|
335
|
+
|
|
336
|
+
const json_oi = JSON.stringify(
|
|
337
|
+
rawArrivalNotices.map(raw => {
|
|
338
|
+
return {
|
|
339
|
+
ref_no: raw.refNo || null,
|
|
340
|
+
ref_no_2: raw.refNo2 || null,
|
|
341
|
+
ref_no_3: raw.refNo3 || null,
|
|
342
|
+
eta_date: raw.etaDate || null,
|
|
343
|
+
truck_no: raw.truckNo || null,
|
|
344
|
+
own_transport: !!raw.truckNo || false,
|
|
345
|
+
loose_item: raw.looseItem || false,
|
|
346
|
+
import_cargo: raw.importCargo || false,
|
|
347
|
+
container: (!!raw.containerNo && !!raw.containerSize) || false,
|
|
348
|
+
container_no: raw.containerNo || null,
|
|
349
|
+
container_size: raw.containerSize || null,
|
|
350
|
+
sku: raw.sku || null,
|
|
351
|
+
batch_id: raw.batchId || null,
|
|
352
|
+
packing_type: raw.packingType || null,
|
|
353
|
+
packing_size: raw.packingSize || null,
|
|
354
|
+
uom: raw.uom || null,
|
|
355
|
+
pack_qty: raw.packQty || null,
|
|
356
|
+
pallet_qty: raw.palletQty || null,
|
|
357
|
+
unit_price: raw.unitPrice || null,
|
|
358
|
+
manufacture_year: raw.manufactureYear || null
|
|
359
|
+
}
|
|
360
|
+
})
|
|
361
|
+
)
|
|
362
|
+
|
|
363
|
+
await trxMgr.query(
|
|
364
|
+
`
|
|
365
|
+
CREATE TEMP TABLE temp_order_products(
|
|
366
|
+
ref_no VARCHAR(150),
|
|
367
|
+
ref_no_2 VARCHAR(150),
|
|
368
|
+
ref_no_3 VARCHAR(150),
|
|
369
|
+
eta_date VARCHAR(24),
|
|
370
|
+
truck_no VARCHAR(10),
|
|
371
|
+
own_transport BOOLEAN,
|
|
372
|
+
container BOOLEAN,
|
|
373
|
+
container_no VARCHAR(50),
|
|
374
|
+
container_size VARCHAR(24),
|
|
375
|
+
import_cargo BOOLEAN,
|
|
376
|
+
loose_item BOOLEAN,
|
|
377
|
+
sku VARCHAR(150),
|
|
378
|
+
batch_id VARCHAR(100),
|
|
379
|
+
packing_type VARCHAR(50),
|
|
380
|
+
packing_size INT,
|
|
381
|
+
uom VARCHAR(10),
|
|
382
|
+
pack_qty INT,
|
|
383
|
+
pallet_qty INT,
|
|
384
|
+
unit_price FLOAT8,
|
|
385
|
+
manufacture_year INT4
|
|
386
|
+
);
|
|
387
|
+
`
|
|
388
|
+
)
|
|
389
|
+
|
|
390
|
+
await trxMgr.query(
|
|
391
|
+
`
|
|
392
|
+
INSERT INTO temp_order_products
|
|
393
|
+
SELECT
|
|
394
|
+
js.ref_no,
|
|
395
|
+
js.ref_no_2,
|
|
396
|
+
js.ref_no_3,
|
|
397
|
+
js.eta_date,
|
|
398
|
+
js.truck_no,
|
|
399
|
+
js.own_transport,
|
|
400
|
+
js.container,
|
|
401
|
+
js.container_no,
|
|
402
|
+
js.container_size,
|
|
403
|
+
js.import_cargo,
|
|
404
|
+
js.loose_item,
|
|
405
|
+
js.sku,
|
|
406
|
+
js.batch_id,
|
|
407
|
+
js.packing_type,
|
|
408
|
+
js.packing_size,
|
|
409
|
+
js.uom,
|
|
410
|
+
js.pack_qty,
|
|
411
|
+
js.pallet_qty,
|
|
412
|
+
js.unit_price,
|
|
413
|
+
js.manufacture_year
|
|
414
|
+
FROM
|
|
415
|
+
JSON_POPULATE_RECORDSET(NULL :: temp_order_products, $1) js;
|
|
416
|
+
`,
|
|
417
|
+
[json_oi]
|
|
418
|
+
)
|
|
419
|
+
|
|
420
|
+
let validatedItems = await trxMgr.query(
|
|
421
|
+
`
|
|
422
|
+
SELECT
|
|
423
|
+
tp.ref_no,
|
|
424
|
+
tp.ref_no_2,
|
|
425
|
+
tp.ref_no_3,
|
|
426
|
+
tp.eta_date,
|
|
427
|
+
tp.truck_no,
|
|
428
|
+
tp.own_transport,
|
|
429
|
+
tp.container,
|
|
430
|
+
tp.container_no,
|
|
431
|
+
tp.container_size,
|
|
432
|
+
tp.import_cargo,
|
|
433
|
+
tp.loose_item,
|
|
434
|
+
pr.id AS product_id,
|
|
435
|
+
pd.id AS product_detail_id,
|
|
436
|
+
pr.sku AS sku,
|
|
437
|
+
CASE WHEN pr.description NOT IN (NULL, '', '-') THEN CONCAT(pr.name, '(', pr.description, ')') ELSE pr.name END AS product_info,
|
|
438
|
+
tp.batch_id,
|
|
439
|
+
pd.packing_type,
|
|
440
|
+
pd.packing_size,
|
|
441
|
+
tp.pack_qty,
|
|
442
|
+
pd.uom_value,
|
|
443
|
+
pd.uom,
|
|
444
|
+
CONCAT(COALESCE(ROUND(pd.uom_value :: numeric, 2), 0) * tp.pack_qty, ' ', pd.uom) AS total_uom_value,
|
|
445
|
+
tp.pallet_qty,
|
|
446
|
+
tp.unit_price,
|
|
447
|
+
tp.manufacture_year,
|
|
448
|
+
CASE WHEN an.id NOTNULL THEN CONCAT('duplicated with ', an.name) ELSE CASE WHEN pr.id ISNULL OR pd.id ISNULL OR tp.sku ISNULL THEN 'product not found'
|
|
449
|
+
ELSE CASE WHEN tp.pack_qty <= 0 THEN 'pack qty must be integer'
|
|
450
|
+
ELSE CASE WHEN tp.batch_id ISNULL THEN 'batch no. is required'
|
|
451
|
+
ELSE CASE WHEN tp.ref_no ISNULL OR tp.ref_no = '' THEN 'ref no. is required'
|
|
452
|
+
ELSE CASE WHEN tp.eta_date ISNULL OR tp.eta_date = '' THEN 'eta date is required'
|
|
453
|
+
ELSE CASE WHEN tp.eta_date::date < now()::date THEN 'backdate is not allowed'
|
|
454
|
+
ELSE CASE WHEN tp.container_no NOTNULL AND tp.container_size ISNULL OR tp.container_no ISNULL AND tp.container_size NOTNULL THEN 'incomplete container information'
|
|
455
|
+
ELSE '' END END END END END END END END AS remark
|
|
456
|
+
FROM
|
|
457
|
+
temp_order_products tp
|
|
458
|
+
LEFT JOIN arrival_notices an ON tp.ref_no = an.ref_no
|
|
459
|
+
AND CASE WHEN tp.ref_no_2 NOTNULL THEN tp.ref_no_2 = an.ref_no_2 ELSE 1 = 1 END
|
|
460
|
+
AND CASE WHEN tp.ref_no_3 NOTNULL THEN tp.ref_no_3 = an.ref_no_3 ELSE 1 = 1 END
|
|
461
|
+
AND CASE WHEN tp.truck_no NOTNULL THEN tp.truck_no = an.truck_no ELSE 1 = 1 END
|
|
462
|
+
AND CASE WHEN tp.own_transport NOTNULL THEN tp.own_transport = an.own_transport ELSE 1 = 1 END
|
|
463
|
+
AND CASE WHEN tp.container NOTNULL THEN tp.container = an.container ELSE 1 = 1 END
|
|
464
|
+
AND CASE WHEN tp.container_no NOTNULL THEN tp.container_no = an.container_no ELSE 1 = 1 END
|
|
465
|
+
AND CASE WHEN tp.container_size NOTNULL THEN tp.container_size = an.container_size ELSE 1 = 1 END
|
|
466
|
+
AND CASE WHEN tp.loose_item NOTNULL THEN tp.loose_item = an.loose_item ELSE 1 = 1 END
|
|
467
|
+
AND CASE WHEN tp.import_cargo NOTNULL THEN tp.import_cargo = an.import_cargo ELSE 1 = 1 END
|
|
468
|
+
LEFT JOIN products pr ON pr.sku = tp.sku
|
|
469
|
+
LEFT JOIN product_details pd ON pr.id = pd.product_id
|
|
470
|
+
AND CASE WHEN tp.packing_type NOTNULL
|
|
471
|
+
AND tp.packing_size NOTNULL
|
|
472
|
+
AND tp.uom NOTNULL THEN pd.packing_type = tp.packing_type
|
|
473
|
+
AND pd.packing_size = tp.packing_size
|
|
474
|
+
AND pd.uom = tp.uom ELSE pd.is_default = TRUE END
|
|
475
|
+
WHERE
|
|
476
|
+
pr.bizplace_id = $1
|
|
477
|
+
|
|
478
|
+
`,
|
|
479
|
+
[companyBizplace.id]
|
|
480
|
+
)
|
|
481
|
+
|
|
482
|
+
await trxMgr.query('DROP TABLE temp_order_products')
|
|
483
|
+
|
|
484
|
+
return validatedItems.map(item => {
|
|
485
|
+
return {
|
|
486
|
+
refNo: item.ref_no,
|
|
487
|
+
refNo2: item.ref_no_2,
|
|
488
|
+
refNo3: item.ref_no_3,
|
|
489
|
+
etaDate: item.eta_date,
|
|
490
|
+
truckNo: item.truck_no,
|
|
491
|
+
ownTransport: !!item.own_transport,
|
|
492
|
+
container: item.container,
|
|
493
|
+
containerNo: item.container_no,
|
|
494
|
+
containerSize: item.container_size,
|
|
495
|
+
importCargo: !!item.import_cargo,
|
|
496
|
+
looseItem: !!item.loose_item,
|
|
497
|
+
productId: item.product_id,
|
|
498
|
+
productDetailId: item.product_detail_id,
|
|
499
|
+
sku: item.sku,
|
|
500
|
+
productInfo: item.product_info,
|
|
501
|
+
batchId: item.batch_id,
|
|
502
|
+
packingType: item.packing_type,
|
|
503
|
+
packingSize: item.packing_size,
|
|
504
|
+
uom: item.uom,
|
|
505
|
+
packQty: item.pack_qty,
|
|
506
|
+
uomValue: item.uom_value,
|
|
507
|
+
totalUomValue: item.total_uom_value,
|
|
508
|
+
palletQty: item.pallet_qty,
|
|
509
|
+
unitPrice: item.unit_price,
|
|
510
|
+
manufactureYear: item.manufacture_year,
|
|
511
|
+
remark: item.remark
|
|
512
|
+
}
|
|
513
|
+
})
|
|
514
|
+
}
|