@things-factory/worksheet-base 4.3.795 → 4.3.798
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/outbound/picking-worksheet-controller.js +32 -35
- package/dist-server/controllers/outbound/picking-worksheet-controller.js.map +1 -1
- package/dist-server/controllers/render-ro-do.js +2 -0
- package/dist-server/controllers/render-ro-do.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/batch-picking-worksheet.js +48 -3
- package/dist-server/graphql/resolvers/worksheet/batch-picking-worksheet.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/delivery-order-by-worksheet.js +2 -1
- package/dist-server/graphql/resolvers/worksheet/delivery-order-by-worksheet.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/picking/activate-batch-picking.js +71 -47
- package/dist-server/graphql/resolvers/worksheet/picking/activate-batch-picking.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/picking-worksheet.js +50 -33
- package/dist-server/graphql/resolvers/worksheet/picking-worksheet.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/sorting-worksheet.js +12 -0
- package/dist-server/graphql/resolvers/worksheet/sorting-worksheet.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/worksheets.js +9 -1
- package/dist-server/graphql/resolvers/worksheet/worksheets.js.map +1 -1
- package/dist-server/graphql/types/worksheet/contact-point-info.js +1 -0
- package/dist-server/graphql/types/worksheet/contact-point-info.js.map +1 -1
- package/dist-server/graphql/types/worksheet/worksheet-detail-info.js +1 -0
- package/dist-server/graphql/types/worksheet/worksheet-detail-info.js.map +1 -1
- package/dist-server/graphql/types/worksheet/worksheet-info.js +1 -0
- package/dist-server/graphql/types/worksheet/worksheet-info.js.map +1 -1
- package/dist-server/utils/worksheet-util.js +40 -1
- package/dist-server/utils/worksheet-util.js.map +1 -1
- package/package.json +13 -13
- package/server/controllers/outbound/picking-worksheet-controller.ts +35 -42
- package/server/controllers/render-ro-do.ts +2 -0
- package/server/graphql/resolvers/worksheet/batch-picking-worksheet.ts +52 -3
- package/server/graphql/resolvers/worksheet/delivery-order-by-worksheet.ts +2 -1
- package/server/graphql/resolvers/worksheet/picking/activate-batch-picking.ts +88 -63
- package/server/graphql/resolvers/worksheet/picking-worksheet.ts +54 -36
- package/server/graphql/resolvers/worksheet/sorting-worksheet.ts +18 -2
- package/server/graphql/resolvers/worksheet/worksheets.ts +13 -1
- package/server/graphql/types/worksheet/contact-point-info.ts +1 -0
- package/server/graphql/types/worksheet/worksheet-detail-info.ts +1 -0
- package/server/graphql/types/worksheet/worksheet-info.ts +1 -0
- package/server/utils/worksheet-util.ts +51 -0
|
@@ -125,7 +125,8 @@ export const deliveryOrderByWorksheetResolver = {
|
|
|
125
125
|
fax: releaseOrderDeliverTo.fax || '',
|
|
126
126
|
phone: releaseOrderDeliverTo.phone || '',
|
|
127
127
|
contactName: releaseOrderDeliverTo.name || '',
|
|
128
|
-
businessRestDay: releaseOrderDeliverTo.businessRestDay || ''
|
|
128
|
+
businessRestDay: releaseOrderDeliverTo.businessRestDay || '',
|
|
129
|
+
customerCode: releaseOrderDeliverTo.customerCode || ''
|
|
129
130
|
}
|
|
130
131
|
: null
|
|
131
132
|
}
|
|
@@ -26,51 +26,81 @@ export async function activateBatchPicking(
|
|
|
26
26
|
): Promise<Worksheet> {
|
|
27
27
|
try {
|
|
28
28
|
const worksheetController: PickingWorksheetController = new PickingWorksheetController(tx, domain, user)
|
|
29
|
-
const ecommerceCtrl: EcommerceController = new EcommerceController(tx, domain, user)
|
|
30
29
|
const worksheet = await worksheetController.activateBatchPicking(worksheetNo)
|
|
31
30
|
const worksheetDetails = worksheet.worksheetDetails
|
|
32
31
|
const companyDomain: Domain = worksheet?.bizplace.company.domain
|
|
33
32
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
33
|
+
// Collect release good IDs from the controller result for post-commit processing
|
|
34
|
+
const orderInventories: any[] = worksheetDetails.map(wsd => wsd.targetInventory)
|
|
35
|
+
const releaseGoodIds: string[] = orderInventories.reduce((data, orderInventory) => {
|
|
36
|
+
if (orderInventory?.releaseGood?.id && !data.includes(orderInventory.releaseGood.id)) {
|
|
37
|
+
data.push(orderInventory.releaseGood.id)
|
|
38
|
+
}
|
|
39
|
+
return data
|
|
40
|
+
}, [])
|
|
41
|
+
|
|
42
|
+
// Schedule all marketplace/LMD side effects to run AFTER the transaction commits.
|
|
43
|
+
// This prevents deadlocks caused by nested transactions competing for locks
|
|
44
|
+
// held by the outer @transaction decorator.
|
|
45
|
+
setImmediate(() => {
|
|
46
|
+
processPostActivationSideEffects(
|
|
47
|
+
domain,
|
|
48
|
+
user,
|
|
49
|
+
companyDomain,
|
|
50
|
+
worksheetNo,
|
|
51
|
+
worksheetDetails,
|
|
52
|
+
releaseGoodIds
|
|
53
|
+
).catch(error => {
|
|
54
|
+
logger.error(`activate-batch-picking[postActivation]: ${worksheetNo}: ${error}`)
|
|
55
|
+
})
|
|
40
56
|
})
|
|
41
57
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
58
|
+
return worksheet
|
|
59
|
+
} catch (error) {
|
|
60
|
+
logger.error(`activate-batch-picking[activateBatchPicking]: ${worksheetNo + ':' + error}`)
|
|
61
|
+
throw new Error('Something went wrong. Please contact support.')
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Handles marketplace stock sync, MMS order packages, and LMD parcel creation.
|
|
67
|
+
* Runs outside the main activation transaction to prevent deadlocks.
|
|
68
|
+
*/
|
|
69
|
+
async function processPostActivationSideEffects(
|
|
70
|
+
domain: Domain,
|
|
71
|
+
user: User,
|
|
72
|
+
companyDomain: Domain,
|
|
73
|
+
worksheetNo: string,
|
|
74
|
+
worksheetDetails: any[],
|
|
75
|
+
releaseGoodIds: string[]
|
|
76
|
+
) {
|
|
77
|
+
try {
|
|
78
|
+
// Find marketplace store connections
|
|
79
|
+
const marketplaceStores: MarketplaceStore[] = await getConnection()
|
|
80
|
+
.getRepository(MarketplaceStore)
|
|
81
|
+
.find({
|
|
82
|
+
where: { domain: companyDomain, status: 'ACTIVE', isAutoUpdateStockQty: true },
|
|
83
|
+
relations: ['marketplaceDistributors']
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
// Update marketplace product variation stock
|
|
87
|
+
if (marketplaceStores?.length && marketplaceStores.some(store => store.isAutoUpdateStockQty)) {
|
|
49
88
|
try {
|
|
50
89
|
await getConnection().transaction(async (tx2: EntityManager) => {
|
|
51
|
-
|
|
90
|
+
const orderInventories: any[] = worksheetDetails.map(wsd => wsd.targetInventory)
|
|
52
91
|
const ecommerceCtrl: EcommerceController = new EcommerceController(tx2, domain, user)
|
|
53
92
|
await ecommerceCtrl.updateProductVariationStock(marketplaceStores, orderInventories, companyDomain)
|
|
54
93
|
})
|
|
55
94
|
} catch (error) {
|
|
56
|
-
logger.error(`activate-batch-picking[
|
|
95
|
+
logger.error(`activate-batch-picking[marketplaceStockUpdate]: ${worksheetNo}: ${error}`)
|
|
57
96
|
}
|
|
58
97
|
}
|
|
59
98
|
|
|
60
|
-
if (
|
|
61
|
-
updateMarketplaceProductVariationStock(worksheetDetails, domain, user, marketplaceStores, companyDomain)
|
|
62
|
-
}
|
|
99
|
+
if (!releaseGoodIds.length) return
|
|
63
100
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
if (!data.find(x => x.id == orderInventory.releaseGood.id)) {
|
|
68
|
-
data.push(orderInventory.releaseGood.id)
|
|
69
|
-
}
|
|
70
|
-
return data
|
|
71
|
-
}, [])
|
|
72
|
-
|
|
73
|
-
releaseGoods = await tx.getRepository(ReleaseGood).find({
|
|
101
|
+
// Load release goods and process marketplace order packages
|
|
102
|
+
await getConnection().transaction(async (tx: EntityManager) => {
|
|
103
|
+
const releaseGoods: ReleaseGood[] = await tx.getRepository(ReleaseGood).find({
|
|
74
104
|
where: { id: In(releaseGoodIds) },
|
|
75
105
|
relations: [
|
|
76
106
|
'domain',
|
|
@@ -88,48 +118,43 @@ export async function activateBatchPicking(
|
|
|
88
118
|
]
|
|
89
119
|
})
|
|
90
120
|
|
|
91
|
-
if (releaseGoods?.length)
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
break
|
|
121
|
+
if (!releaseGoods?.length) return
|
|
122
|
+
|
|
123
|
+
// Batch load marketplace orders for MMS release goods (avoids N+1 queries)
|
|
124
|
+
const mmsReleaseGoods = releaseGoods.filter(rg => rg?.source === ApplicationType.MMS)
|
|
125
|
+
|
|
126
|
+
if (mmsReleaseGoods.length && marketplaceStores?.length) {
|
|
127
|
+
const refNos = mmsReleaseGoods.map(rg => rg.refNo).filter(Boolean)
|
|
128
|
+
const marketplaceOrders: MarketplaceOrder[] = refNos.length
|
|
129
|
+
? await tx.getRepository(MarketplaceOrder).find({
|
|
130
|
+
where: { orderNo: In(refNos), domain: companyDomain },
|
|
131
|
+
relations: ['marketplaceStore']
|
|
132
|
+
})
|
|
133
|
+
: []
|
|
134
|
+
|
|
135
|
+
const ecommerceCtrl: EcommerceController = new EcommerceController(tx, domain, user)
|
|
136
|
+
for (const releaseGood of mmsReleaseGoods) {
|
|
137
|
+
try {
|
|
138
|
+
const marketplaceOrder = marketplaceOrders.find(mo => mo.orderNo === releaseGood.refNo)
|
|
139
|
+
if (marketplaceOrder) {
|
|
140
|
+
const marketplaceStore: MarketplaceStore = marketplaceOrder.marketplaceStore
|
|
141
|
+
await ecommerceCtrl.createOrderPackage(tx, marketplaceOrder, companyDomain, marketplaceStore, releaseGood)
|
|
142
|
+
}
|
|
143
|
+
} catch (error) {
|
|
144
|
+
logger.error(`activate-batch-picking[mmsOrderPackage]: ${worksheetNo}: ${error}`)
|
|
116
145
|
}
|
|
117
146
|
}
|
|
118
|
-
// Process LMD orders
|
|
119
|
-
processLmdOrders(releaseGoods, domain, companyDomain, user)
|
|
120
147
|
}
|
|
121
|
-
} catch (e) {
|
|
122
|
-
logger.error(e)
|
|
123
|
-
}
|
|
124
148
|
|
|
125
|
-
|
|
149
|
+
// Process LMD orders
|
|
150
|
+
processLmdOrders(releaseGoods, domain, companyDomain, user)
|
|
151
|
+
})
|
|
126
152
|
} catch (error) {
|
|
127
|
-
logger.error(`activate-batch-picking[
|
|
128
|
-
throw new Error('Something went wrong. Please contact support.')
|
|
153
|
+
logger.error(`activate-batch-picking[postActivation]: ${worksheetNo}: ${error}`)
|
|
129
154
|
}
|
|
130
155
|
}
|
|
131
156
|
|
|
132
|
-
//
|
|
157
|
+
// Trigger create parcel for LMD orders
|
|
133
158
|
async function processLmdOrders(releaseGoods: ReleaseGood[], domain: Domain, companyDomain: Domain, user: User) {
|
|
134
159
|
// Filter only those that need processing
|
|
135
160
|
const validReleaseGoods = releaseGoods.filter(
|
|
@@ -7,12 +7,13 @@ import {
|
|
|
7
7
|
Replenishment,
|
|
8
8
|
ShippingOrder
|
|
9
9
|
} from '@things-factory/sales-base'
|
|
10
|
+
import { ProductDetail } from '@things-factory/product-base'
|
|
10
11
|
import { Domain } from '@things-factory/shell'
|
|
11
12
|
import { Inventory, InventoryChange, Location } from '@things-factory/warehouse-base'
|
|
12
13
|
|
|
13
14
|
import { WORKSHEET_STATUS, WORKSHEET_TYPE } from '../../../constants'
|
|
14
15
|
import { WorksheetDetail } from '../../../entities'
|
|
15
|
-
import { fetchExecutingWorksheet } from '../../../utils'
|
|
16
|
+
import { computeConversionString, fetchExecutingWorksheet } from '../../../utils'
|
|
16
17
|
|
|
17
18
|
export const pickingWorksheetResolver = {
|
|
18
19
|
async pickingWorksheet(_: any, { orderNo, locationSortingRules }, context: any) {
|
|
@@ -86,6 +87,8 @@ export async function pickingWorksheet(domain: Domain, orderNo: String, location
|
|
|
86
87
|
.leftJoinAndSelect('T_INV.inventory', 'INV')
|
|
87
88
|
.leftJoinAndSelect('T_INV.product', 'PROD')
|
|
88
89
|
.leftJoinAndSelect('T_INV.productDetail', 'PROD_DET')
|
|
90
|
+
.leftJoinAndSelect('PROD_DET.childProductDetail', 'CHILD_PROD_DET')
|
|
91
|
+
.leftJoinAndSelect('PROD_DET.parentProductDetails', 'PARENT_PROD_DETS')
|
|
89
92
|
.leftJoinAndSelect('INV.location', 'LOC')
|
|
90
93
|
|
|
91
94
|
if (locationSortingRules?.length > 0) {
|
|
@@ -106,6 +109,50 @@ export async function pickingWorksheet(domain: Domain, orderNo: String, location
|
|
|
106
109
|
.andWhere('"T_INV"."status" != :t_invstatus', { t_invstatus: ORDER_INVENTORY_STATUS.CANCELLED })
|
|
107
110
|
.getMany()
|
|
108
111
|
|
|
112
|
+
const inventoryIds = worksheetDetails
|
|
113
|
+
.map((wd: WorksheetDetail) => wd.targetInventory?.inventory?.id)
|
|
114
|
+
.filter((id): id is string => id != null)
|
|
115
|
+
const inventoryIdsWithMissing = new Set<string>()
|
|
116
|
+
if (inventoryIds.length > 0) {
|
|
117
|
+
const rows = await tx
|
|
118
|
+
.getRepository(InventoryChange)
|
|
119
|
+
.createQueryBuilder('ic')
|
|
120
|
+
.select('DISTINCT ic.inventory_id', 'inventoryId')
|
|
121
|
+
.where('ic.inventory_id IN (:...ids)', { ids: inventoryIds })
|
|
122
|
+
.andWhere('ic.status = :status', { status: 'PENDING' })
|
|
123
|
+
.andWhere('ic.transaction_type = :transactionType', { transactionType: 'MISSING' })
|
|
124
|
+
.getRawMany()
|
|
125
|
+
rows.forEach((r: { inventoryId: string }) => inventoryIdsWithMissing.add(r.inventoryId))
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const worksheetDetailInfos = worksheetDetails.map((pickingWSD: WorksheetDetail) => {
|
|
129
|
+
const targetInventory: OrderInventory = pickingWSD.targetInventory
|
|
130
|
+
const inventory: Inventory = targetInventory.inventory
|
|
131
|
+
const productDetail: ProductDetail = targetInventory.productDetail as ProductDetail
|
|
132
|
+
return {
|
|
133
|
+
name: pickingWSD.name,
|
|
134
|
+
palletId: inventory?.palletId,
|
|
135
|
+
cartonId: inventory?.cartonId,
|
|
136
|
+
batchId: inventory?.batchId,
|
|
137
|
+
batchIdRef: inventory?.batchIdRef,
|
|
138
|
+
product: inventory?.product,
|
|
139
|
+
qty: inventory?.qty,
|
|
140
|
+
binLocation: targetInventory?.binLocation || '',
|
|
141
|
+
releaseQty: targetInventory.releaseQty,
|
|
142
|
+
pickedQty: targetInventory.pickedQty,
|
|
143
|
+
status: pickingWSD.status,
|
|
144
|
+
description: pickingWSD.description,
|
|
145
|
+
targetName: targetInventory.name,
|
|
146
|
+
packingType: inventory?.packingType,
|
|
147
|
+
packingSize: inventory?.packingSize,
|
|
148
|
+
expirationDate: inventory?.expirationDate,
|
|
149
|
+
location: inventory?.location,
|
|
150
|
+
relatedOrderInv: targetInventory,
|
|
151
|
+
hasMissingInventoryChanges: inventory?.id ? inventoryIdsWithMissing.has(inventory.id) : false,
|
|
152
|
+
conversion: computeConversionString(targetInventory.releaseQty, productDetail)
|
|
153
|
+
}
|
|
154
|
+
})
|
|
155
|
+
|
|
109
156
|
return {
|
|
110
157
|
worksheetInfo: {
|
|
111
158
|
worksheet,
|
|
@@ -123,40 +170,7 @@ export async function pickingWorksheet(domain: Domain, orderNo: String, location
|
|
|
123
170
|
customerCompanyDomainId: releaseGood.bizplace?.company?.domain?.id,
|
|
124
171
|
releaseGood
|
|
125
172
|
},
|
|
126
|
-
worksheetDetailInfos
|
|
127
|
-
const targetInventory: OrderInventory = pickingWSD.targetInventory
|
|
128
|
-
const inventory: Inventory = targetInventory.inventory
|
|
129
|
-
|
|
130
|
-
const inventoryChangesCount: number = await tx.getRepository(InventoryChange).count({
|
|
131
|
-
where: {
|
|
132
|
-
inventory: inventory.id,
|
|
133
|
-
status: 'PENDING',
|
|
134
|
-
transactionType: 'MISSING'
|
|
135
|
-
}
|
|
136
|
-
})
|
|
137
|
-
|
|
138
|
-
return {
|
|
139
|
-
name: pickingWSD.name,
|
|
140
|
-
palletId: inventory?.palletId,
|
|
141
|
-
cartonId: inventory?.cartonId,
|
|
142
|
-
batchId: inventory?.batchId,
|
|
143
|
-
batchIdRef: inventory?.batchIdRef,
|
|
144
|
-
product: inventory?.product,
|
|
145
|
-
qty: inventory?.qty,
|
|
146
|
-
binLocation: targetInventory?.binLocation || '',
|
|
147
|
-
releaseQty: targetInventory.releaseQty,
|
|
148
|
-
pickedQty: targetInventory.pickedQty,
|
|
149
|
-
status: pickingWSD.status,
|
|
150
|
-
description: pickingWSD.description,
|
|
151
|
-
targetName: targetInventory.name,
|
|
152
|
-
packingType: inventory?.packingType,
|
|
153
|
-
packingSize: inventory?.packingSize,
|
|
154
|
-
expirationDate: inventory?.expirationDate,
|
|
155
|
-
location: inventory?.location,
|
|
156
|
-
relatedOrderInv: targetInventory,
|
|
157
|
-
hasMissingInventoryChanges: inventoryChangesCount > 0 ? true : false
|
|
158
|
-
}
|
|
159
|
-
})
|
|
173
|
+
worksheetDetailInfos
|
|
160
174
|
}
|
|
161
175
|
}
|
|
162
176
|
}
|
|
@@ -183,6 +197,8 @@ async function replenishmentWorksheet(orderNo: String, tx, domain, locationSorti
|
|
|
183
197
|
.leftJoinAndSelect('T_INV.inventory', 'INV')
|
|
184
198
|
.leftJoinAndSelect('T_INV.product', 'PROD')
|
|
185
199
|
.leftJoinAndSelect('T_INV.productDetail', 'PROD_DET')
|
|
200
|
+
.leftJoinAndSelect('PROD_DET.childProductDetail', 'CHILD_PROD_DET')
|
|
201
|
+
.leftJoinAndSelect('PROD_DET.parentProductDetails', 'PARENT_PROD_DETS')
|
|
186
202
|
.leftJoinAndSelect('INV.location', 'LOC')
|
|
187
203
|
|
|
188
204
|
if (locationSortingRules?.length > 0) {
|
|
@@ -210,6 +226,7 @@ async function replenishmentWorksheet(orderNo: String, tx, domain, locationSorti
|
|
|
210
226
|
worksheetDetailInfos: worksheetDetails.map(async (pickingWSD: WorksheetDetail) => {
|
|
211
227
|
const targetInventory: OrderInventory = pickingWSD.targetInventory
|
|
212
228
|
const inventory: Inventory = targetInventory.inventory
|
|
229
|
+
const productDetail: ProductDetail = targetInventory.productDetail as ProductDetail
|
|
213
230
|
|
|
214
231
|
return {
|
|
215
232
|
name: pickingWSD.name,
|
|
@@ -229,7 +246,8 @@ async function replenishmentWorksheet(orderNo: String, tx, domain, locationSorti
|
|
|
229
246
|
packingSize: inventory?.packingSize,
|
|
230
247
|
expirationDate: inventory?.expirationDate,
|
|
231
248
|
location: inventory?.location,
|
|
232
|
-
relatedOrderInv: targetInventory
|
|
249
|
+
relatedOrderInv: targetInventory,
|
|
250
|
+
conversion: computeConversionString(targetInventory.releaseQty, productDetail)
|
|
233
251
|
}
|
|
234
252
|
})
|
|
235
253
|
}
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
SelectQueryBuilder
|
|
4
4
|
} from 'typeorm'
|
|
5
5
|
|
|
6
|
-
import { ProductBarcode } from '@things-factory/product-base'
|
|
6
|
+
import { ProductBarcode, ProductDetail } from '@things-factory/product-base'
|
|
7
7
|
import {
|
|
8
8
|
ORDER_INVENTORY_STATUS,
|
|
9
9
|
ORDER_STATUS,
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
import { Domain } from '@things-factory/shell'
|
|
14
14
|
|
|
15
15
|
import { WORKSHEET_TYPE } from '../../../constants'
|
|
16
|
-
import { fetchExecutingBatchWorksheet } from '../../../utils'
|
|
16
|
+
import { computeConversionString, fetchExecutingBatchWorksheet } from '../../../utils'
|
|
17
17
|
|
|
18
18
|
export const sortingWorksheetResolver = {
|
|
19
19
|
async sortingWorksheet(_: any, { releaseGoodNo, taskNo }, context: any) {
|
|
@@ -66,6 +66,19 @@ export const sortingWorksheetResolver = {
|
|
|
66
66
|
.orderBy('PROD.sku', 'ASC')
|
|
67
67
|
|
|
68
68
|
const items: any[] = await qb.getRawMany()
|
|
69
|
+
|
|
70
|
+
// Collect unique productDetail IDs to fetch with relationships
|
|
71
|
+
const productDetailIds = [...new Set(items.map(item => item.productDetailId).filter(Boolean))]
|
|
72
|
+
const productDetailsMap = new Map<string, ProductDetail>()
|
|
73
|
+
|
|
74
|
+
if (productDetailIds.length > 0) {
|
|
75
|
+
const productDetails: ProductDetail[] = await getRepository(ProductDetail).find({
|
|
76
|
+
where: productDetailIds.map(id => ({ id })),
|
|
77
|
+
relations: ['childProductDetail', 'parentProductDetails']
|
|
78
|
+
})
|
|
79
|
+
productDetails.forEach(pd => productDetailsMap.set(pd.id, pd))
|
|
80
|
+
}
|
|
81
|
+
|
|
69
82
|
let results = {
|
|
70
83
|
worksheetInfo: {
|
|
71
84
|
bizplaceName: releaseGood.bizplace.name,
|
|
@@ -79,6 +92,8 @@ export const sortingWorksheetResolver = {
|
|
|
79
92
|
},
|
|
80
93
|
worksheetDetailInfos: await Promise.all(
|
|
81
94
|
items.map(async (item: any) => {
|
|
95
|
+
const productDetail = productDetailsMap.get(item.productDetailId)
|
|
96
|
+
|
|
82
97
|
return {
|
|
83
98
|
batchId: item?.batchId,
|
|
84
99
|
productId: item?.productId,
|
|
@@ -96,6 +111,7 @@ export const sortingWorksheetResolver = {
|
|
|
96
111
|
packingType: item?.packingType,
|
|
97
112
|
packingSize: item?.packingSize,
|
|
98
113
|
binRemarks: item?.binRemarks,
|
|
114
|
+
conversion: computeConversionString(item.releaseQty, productDetail),
|
|
99
115
|
releaseGood
|
|
100
116
|
}
|
|
101
117
|
})
|
|
@@ -118,6 +118,7 @@ export const worksheetsResolver = {
|
|
|
118
118
|
const releaseGoodPriorityDeliveryParam = params.filters.find(
|
|
119
119
|
param => param.name === 'releaseGoodPriorityDelivery'
|
|
120
120
|
)
|
|
121
|
+
const releaseGoodRtmParam = params.filters.find(param => param.name === 'releaseGoodRtm')
|
|
121
122
|
|
|
122
123
|
if (
|
|
123
124
|
releaseGoodParam ||
|
|
@@ -125,7 +126,8 @@ export const worksheetsResolver = {
|
|
|
125
126
|
releaseGoodCrossDockingParam ||
|
|
126
127
|
releaseGoodCourierOptionParam ||
|
|
127
128
|
releaseGoodPackingOptionParam ||
|
|
128
|
-
releaseGoodPriorityDeliveryParam
|
|
129
|
+
releaseGoodPriorityDeliveryParam ||
|
|
130
|
+
releaseGoodRtmParam
|
|
129
131
|
) {
|
|
130
132
|
// let arrFilters = []
|
|
131
133
|
if (releaseGoodParam) {
|
|
@@ -176,6 +178,13 @@ export const worksheetsResolver = {
|
|
|
176
178
|
)
|
|
177
179
|
}
|
|
178
180
|
|
|
181
|
+
if (releaseGoodRtmParam) {
|
|
182
|
+
params.filters.splice(
|
|
183
|
+
params.filters.findIndex(item => item.name == 'releaseGoodRtm'),
|
|
184
|
+
1
|
|
185
|
+
)
|
|
186
|
+
}
|
|
187
|
+
|
|
179
188
|
// const foundReleaseGoods: ReleaseGood[] = await getRepository(ReleaseGood).find({
|
|
180
189
|
// ...convertListParams({ filters: arrFilters }, domain.id)
|
|
181
190
|
// })
|
|
@@ -555,6 +564,9 @@ export const worksheetsResolver = {
|
|
|
555
564
|
priorityDelivery: releaseGoodPriorityDeliveryParam.value
|
|
556
565
|
})
|
|
557
566
|
}
|
|
567
|
+
if (releaseGoodRtmParam) {
|
|
568
|
+
qb.andWhere(`releaseGood.rtm = :rtm`, { rtm: releaseGoodRtmParam.value })
|
|
569
|
+
}
|
|
558
570
|
|
|
559
571
|
////Add sorting conditions
|
|
560
572
|
const arrChildSortData = ['bizplace', 'arrivalNotice', 'releaseGood', 'returnOrder', 'inventoryCheck']
|
|
@@ -20,6 +20,13 @@ import { Domain } from '@things-factory/shell'
|
|
|
20
20
|
import { WORKSHEET_STATUS } from '../constants'
|
|
21
21
|
import { Worksheet } from '../entities'
|
|
22
22
|
|
|
23
|
+
export interface PackingConversionDetail {
|
|
24
|
+
packingType?: string
|
|
25
|
+
packingSize?: number
|
|
26
|
+
childProductDetail?: PackingConversionDetail | null
|
|
27
|
+
parentProductDetails?: PackingConversionDetail[] | null
|
|
28
|
+
}
|
|
29
|
+
|
|
23
30
|
export async function fetchExecutingWorksheet(
|
|
24
31
|
domain: Domain,
|
|
25
32
|
bizplace: Bizplace,
|
|
@@ -101,3 +108,47 @@ export async function fetchExecutingBatchWorksheet(
|
|
|
101
108
|
throw new Error(`Current worksheet status (${worksheet.status}) is not proper to execute it.`)
|
|
102
109
|
}
|
|
103
110
|
}
|
|
111
|
+
|
|
112
|
+
export function computeConversionString(releaseQty: number, productDetail: PackingConversionDetail | null): string {
|
|
113
|
+
if (!productDetail || !releaseQty || releaseQty <= 0) {
|
|
114
|
+
return ''
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const currentPackingType = productDetail.packingType
|
|
118
|
+
const childProductDetail = productDetail.childProductDetail
|
|
119
|
+
const parentProductDetails = productDetail.parentProductDetails
|
|
120
|
+
|
|
121
|
+
// Priority 1: If has child → convert to child terms (downward)
|
|
122
|
+
if (childProductDetail) {
|
|
123
|
+
const packingSize = productDetail.packingSize || 1
|
|
124
|
+
const childPackingType = childProductDetail.packingType
|
|
125
|
+
|
|
126
|
+
if (packingSize > 1) {
|
|
127
|
+
const totalChildUnits = releaseQty * packingSize
|
|
128
|
+
return `${totalChildUnits} ${childPackingType}`
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Priority 2: If has parent (no child) → convert to parent terms (upward)
|
|
133
|
+
// If multiple parents, select the one with lowest packingSize
|
|
134
|
+
if (parentProductDetails && parentProductDetails.length > 0) {
|
|
135
|
+
const parent = parentProductDetails.reduce((min, p) => ((p.packingSize || 1) < (min.packingSize || 1) ? p : min))
|
|
136
|
+
const parentPackingSize = parent.packingSize || 1
|
|
137
|
+
const parentPackingType = parent.packingType
|
|
138
|
+
|
|
139
|
+
if (parentPackingSize > 1) {
|
|
140
|
+
const fullParents = Math.floor(releaseQty / parentPackingSize)
|
|
141
|
+
const remainder = releaseQty % parentPackingSize
|
|
142
|
+
|
|
143
|
+
if (fullParents > 0 && remainder > 0) {
|
|
144
|
+
return `${fullParents} ${parentPackingType}, ${remainder} ${currentPackingType}`
|
|
145
|
+
} else if (fullParents > 0) {
|
|
146
|
+
return `${fullParents} ${parentPackingType}`
|
|
147
|
+
} else if (remainder > 0) {
|
|
148
|
+
return `${remainder} ${currentPackingType}`
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return ''
|
|
154
|
+
}
|