@things-factory/worksheet-base 4.3.753 → 4.3.756
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 +97 -27
- package/dist-server/controllers/outbound/picking-worksheet-controller.js.map +1 -1
- package/dist-server/controllers/outbound/sorting-worksheet-controller.js +117 -24
- package/dist-server/controllers/outbound/sorting-worksheet-controller.js.map +1 -1
- package/dist-server/controllers/render-ro-do.js +324 -96
- package/dist-server/controllers/render-ro-do.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/find-sorting-release-orders-by-task-no.js +244 -123
- package/dist-server/graphql/resolvers/worksheet/find-sorting-release-orders-by-task-no.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/index.js +1 -1
- package/dist-server/graphql/resolvers/worksheet/index.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/loading/index.js +3 -1
- package/dist-server/graphql/resolvers/worksheet/loading/index.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/loading/validate-qc-seals.js +79 -0
- package/dist-server/graphql/resolvers/worksheet/loading/validate-qc-seals.js.map +1 -0
- package/dist-server/graphql/types/worksheet/index.js +5 -1
- package/dist-server/graphql/types/worksheet/index.js.map +1 -1
- package/dist-server/graphql/types/worksheet/validate-qc-seals-result.js +12 -0
- package/dist-server/graphql/types/worksheet/validate-qc-seals-result.js.map +1 -0
- package/dist-server/graphql/types/worksheet/worksheet-info.js +1 -0
- package/dist-server/graphql/types/worksheet/worksheet-info.js.map +1 -1
- package/package.json +21 -21
- package/server/controllers/outbound/picking-worksheet-controller.ts +105 -31
- package/server/controllers/outbound/sorting-worksheet-controller.ts +137 -25
- package/server/controllers/render-ro-do.ts +378 -136
- package/server/graphql/resolvers/worksheet/find-sorting-release-orders-by-task-no.ts +305 -128
- package/server/graphql/resolvers/worksheet/index.ts +3 -2
- package/server/graphql/resolvers/worksheet/loading/index.ts +5 -0
- package/server/graphql/resolvers/worksheet/loading/validate-qc-seals.ts +91 -0
- package/server/graphql/types/worksheet/index.ts +5 -1
- package/server/graphql/types/worksheet/validate-qc-seals-result.ts +9 -0
- package/server/graphql/types/worksheet/worksheet-info.ts +1 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ValidateQcSealsResult = void 0;
|
|
4
|
+
const apollo_server_koa_1 = require("apollo-server-koa");
|
|
5
|
+
exports.ValidateQcSealsResult = (0, apollo_server_koa_1.gql) `
|
|
6
|
+
type ValidateQcSealsResult {
|
|
7
|
+
valid: Boolean!
|
|
8
|
+
error: String
|
|
9
|
+
minimumSealNumber: Int
|
|
10
|
+
}
|
|
11
|
+
`;
|
|
12
|
+
//# sourceMappingURL=validate-qc-seals-result.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate-qc-seals-result.js","sourceRoot":"","sources":["../../../../server/graphql/types/worksheet/validate-qc-seals-result.ts"],"names":[],"mappings":";;;AAAA,yDAAuC;AAE1B,QAAA,qBAAqB,GAAG,IAAA,uBAAG,EAAA;;;;;;CAMvC,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worksheet-info.js","sourceRoot":"","sources":["../../../../server/graphql/types/worksheet/worksheet-info.ts"],"names":[],"mappings":";;;AAAA,yDAAuC;AAE1B,QAAA,aAAa,GAAG,IAAA,uBAAG,EAAA
|
|
1
|
+
{"version":3,"file":"worksheet-info.js","sourceRoot":"","sources":["../../../../server/graphql/types/worksheet/worksheet-info.ts"],"names":[],"mappings":";;;AAAA,yDAAuC;AAE1B,QAAA,aAAa,GAAG,IAAA,uBAAG,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0C/B,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@things-factory/worksheet-base",
|
|
3
|
-
"version": "4.3.
|
|
3
|
+
"version": "4.3.756",
|
|
4
4
|
"main": "dist-server/index.js",
|
|
5
5
|
"browser": "client/index.js",
|
|
6
6
|
"things-factory": true,
|
|
@@ -23,28 +23,28 @@
|
|
|
23
23
|
"migration:create": "node ../../node_modules/typeorm/cli.js migration:create -d ./server/migrations"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@things-factory/auth-base": "^4.3.
|
|
27
|
-
"@things-factory/biz-base": "^4.3.
|
|
28
|
-
"@things-factory/document-template-base": "^4.3.
|
|
29
|
-
"@things-factory/id-rule-base": "^4.3.
|
|
30
|
-
"@things-factory/integration-accounting": "^4.3.
|
|
31
|
-
"@things-factory/integration-base": "^4.3.
|
|
32
|
-
"@things-factory/integration-lmd": "^4.3.
|
|
33
|
-
"@things-factory/integration-marketplace": "^4.3.
|
|
34
|
-
"@things-factory/integration-powrup": "^4.3.
|
|
35
|
-
"@things-factory/integration-sellercraft": "^4.3.
|
|
36
|
-
"@things-factory/integration-sftp": "^4.3.
|
|
37
|
-
"@things-factory/marketplace-base": "^4.3.
|
|
38
|
-
"@things-factory/notification": "^4.3.
|
|
39
|
-
"@things-factory/sales-base": "^4.3.
|
|
40
|
-
"@things-factory/setting-base": "^4.3.
|
|
41
|
-
"@things-factory/shell": "^4.3.
|
|
42
|
-
"@things-factory/transport-base": "^4.3.
|
|
43
|
-
"@things-factory/warehouse-base": "^4.3.
|
|
44
|
-
"@things-factory/worksheet-ui": "^4.3.
|
|
26
|
+
"@things-factory/auth-base": "^4.3.755",
|
|
27
|
+
"@things-factory/biz-base": "^4.3.755",
|
|
28
|
+
"@things-factory/document-template-base": "^4.3.755",
|
|
29
|
+
"@things-factory/id-rule-base": "^4.3.755",
|
|
30
|
+
"@things-factory/integration-accounting": "^4.3.755",
|
|
31
|
+
"@things-factory/integration-base": "^4.3.755",
|
|
32
|
+
"@things-factory/integration-lmd": "^4.3.755",
|
|
33
|
+
"@things-factory/integration-marketplace": "^4.3.755",
|
|
34
|
+
"@things-factory/integration-powrup": "^4.3.755",
|
|
35
|
+
"@things-factory/integration-sellercraft": "^4.3.755",
|
|
36
|
+
"@things-factory/integration-sftp": "^4.3.755",
|
|
37
|
+
"@things-factory/marketplace-base": "^4.3.755",
|
|
38
|
+
"@things-factory/notification": "^4.3.755",
|
|
39
|
+
"@things-factory/sales-base": "^4.3.755",
|
|
40
|
+
"@things-factory/setting-base": "^4.3.755",
|
|
41
|
+
"@things-factory/shell": "^4.3.755",
|
|
42
|
+
"@things-factory/transport-base": "^4.3.755",
|
|
43
|
+
"@things-factory/warehouse-base": "^4.3.755",
|
|
44
|
+
"@things-factory/worksheet-ui": "^4.3.755",
|
|
45
45
|
"jspdf": "2.5.1",
|
|
46
46
|
"puppeteer": "21.0.3",
|
|
47
47
|
"uuid": "^9.0.0"
|
|
48
48
|
},
|
|
49
|
-
"gitHead": "
|
|
49
|
+
"gitHead": "b16ce3a1cde77139646a0812c3b198a854e48a19"
|
|
50
50
|
}
|
|
@@ -1730,12 +1730,59 @@ export class PickingWorksheetController extends VasWorksheetController {
|
|
|
1730
1730
|
}
|
|
1731
1731
|
|
|
1732
1732
|
async completePicking(releaseGood: ReleaseGood, worksheet: Worksheet, inventories: Inventory[]): Promise<any> {
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1733
|
+
// Check enable-tote-scanning setting
|
|
1734
|
+
let enableToteScanningSetting: Setting = await this.trxMgr.getRepository(Setting).findOne({
|
|
1735
|
+
where: {
|
|
1736
|
+
domain: this.domain,
|
|
1737
|
+
category: 'id-rule',
|
|
1738
|
+
name: 'enable-tote-scanning'
|
|
1739
|
+
}
|
|
1740
|
+
})
|
|
1741
|
+
|
|
1742
|
+
if (enableToteScanningSetting) {
|
|
1743
|
+
// enable-tote-scanning is numeric: 0 = disabled, >= 1 = enabled
|
|
1744
|
+
const enableToteScanningValue = parseInt(enableToteScanningSetting.value || '0', 10)
|
|
1745
|
+
|
|
1746
|
+
if (enableToteScanningValue >= 1) {
|
|
1747
|
+
// Check minimum-seal-number setting
|
|
1748
|
+
let minimumSealNumberSetting: Setting = await this.trxMgr.getRepository(Setting).findOne({
|
|
1749
|
+
where: {
|
|
1750
|
+
domain: this.domain,
|
|
1751
|
+
category: 'id-rule',
|
|
1752
|
+
name: 'minimum-seal-number'
|
|
1753
|
+
}
|
|
1754
|
+
})
|
|
1736
1755
|
|
|
1737
|
-
|
|
1738
|
-
|
|
1756
|
+
const minimumSealNumber = parseInt(minimumSealNumberSetting?.value || '0', 10)
|
|
1757
|
+
|
|
1758
|
+
// Check if there are unsealed totes (closedDate is null)
|
|
1759
|
+
const foundNotSealedOrderTote = await this.trxMgr
|
|
1760
|
+
.getRepository(OrderTote)
|
|
1761
|
+
.findOne({ where: { releaseGood, closedDate: IsNull() } })
|
|
1762
|
+
|
|
1763
|
+
if (foundNotSealedOrderTote) {
|
|
1764
|
+
throw new Error('Please seal the tote(s) before completing')
|
|
1765
|
+
}
|
|
1766
|
+
|
|
1767
|
+
// If minimum-seal-number > 0, validate seal counts per tote
|
|
1768
|
+
if (minimumSealNumber > 0) {
|
|
1769
|
+
// Get all order totes for this release good
|
|
1770
|
+
const orderTotes: OrderTote[] = await this.trxMgr.getRepository(OrderTote).find({
|
|
1771
|
+
where: { releaseGood },
|
|
1772
|
+
relations: ['orderToteSeals']
|
|
1773
|
+
})
|
|
1774
|
+
|
|
1775
|
+
// Validate each tote has at least minimum-seal-number seals
|
|
1776
|
+
for (const orderTote of orderTotes) {
|
|
1777
|
+
const sealCount = orderTote.orderToteSeals?.length || 0
|
|
1778
|
+
if (sealCount < minimumSealNumber) {
|
|
1779
|
+
throw new Error(
|
|
1780
|
+
`Tote ${orderTote.name} has ${sealCount} seal(s), but minimum ${minimumSealNumber} seal(s) required`
|
|
1781
|
+
)
|
|
1782
|
+
}
|
|
1783
|
+
}
|
|
1784
|
+
}
|
|
1785
|
+
}
|
|
1739
1786
|
}
|
|
1740
1787
|
|
|
1741
1788
|
//check if any inventories is obsolete
|
|
@@ -2198,31 +2245,30 @@ export class PickingWorksheetController extends VasWorksheetController {
|
|
|
2198
2245
|
|
|
2199
2246
|
private async toteScanning(toteNo, targetProduct, targetInventory, pickedQty, releaseGood, bizplace) {
|
|
2200
2247
|
//1. find tote
|
|
2201
|
-
|
|
2248
|
+
const foundTote: Tote = await this.trxMgr
|
|
2202
2249
|
.getRepository(Tote)
|
|
2203
2250
|
.findOne({ where: { bizplace, name: toteNo, deletedAt: IsNull() } })
|
|
2204
2251
|
|
|
2205
|
-
|
|
2206
|
-
foundTote
|
|
2207
|
-
|
|
2252
|
+
const validTote = foundTote?.status !== TOTE_STATUS.DAMAGED && foundTote?.status !== TOTE_STATUS.DISPATCHED
|
|
2253
|
+
? foundTote
|
|
2254
|
+
: null
|
|
2208
2255
|
|
|
2209
2256
|
//2. find order tote
|
|
2210
|
-
let
|
|
2257
|
+
let orderTote: OrderTote = await this.trxMgr
|
|
2211
2258
|
.getRepository(OrderTote)
|
|
2212
2259
|
.findOne({ where: { domain: this.domain, name: toteNo, releaseGood } })
|
|
2213
2260
|
|
|
2214
|
-
//if order tote not found
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
const orderTote = await this.trxMgr.getRepository(OrderTote).save({
|
|
2261
|
+
//if order tote not found then create one, if tote not found means it's tote box
|
|
2262
|
+
if (!orderTote) {
|
|
2263
|
+
orderTote = await this.trxMgr.getRepository(OrderTote).save({
|
|
2218
2264
|
name: toteNo,
|
|
2219
2265
|
domain: this.domain,
|
|
2220
2266
|
releaseGood,
|
|
2221
|
-
tote:
|
|
2267
|
+
tote: validTote ?? null,
|
|
2222
2268
|
updater: this.user
|
|
2223
2269
|
})
|
|
2224
2270
|
|
|
2225
|
-
|
|
2271
|
+
await this.trxMgr.getRepository(OrderToteItem).save({
|
|
2226
2272
|
domain: this.domain,
|
|
2227
2273
|
name: OrderNoGenerator.orderToteItem(),
|
|
2228
2274
|
orderProduct: targetProduct,
|
|
@@ -2232,7 +2278,7 @@ export class PickingWorksheetController extends VasWorksheetController {
|
|
|
2232
2278
|
updater: this.user
|
|
2233
2279
|
})
|
|
2234
2280
|
} else {
|
|
2235
|
-
if (
|
|
2281
|
+
if (orderTote.closedDate) {
|
|
2236
2282
|
throw new Error('Tote has been sealed, please try another tote!')
|
|
2237
2283
|
}
|
|
2238
2284
|
|
|
@@ -2241,25 +2287,45 @@ export class PickingWorksheetController extends VasWorksheetController {
|
|
|
2241
2287
|
domain: this.domain,
|
|
2242
2288
|
orderProduct: targetProduct,
|
|
2243
2289
|
orderInventory: targetInventory,
|
|
2244
|
-
orderTote
|
|
2290
|
+
orderTote
|
|
2245
2291
|
})
|
|
2246
2292
|
|
|
2247
|
-
//if not order tote item doesnt exist then create one
|
|
2248
2293
|
if (!foundOrderToteItem) {
|
|
2249
|
-
|
|
2294
|
+
await this.trxMgr.getRepository(OrderToteItem).save({
|
|
2250
2295
|
domain: this.domain,
|
|
2251
2296
|
name: OrderNoGenerator.orderToteItem(),
|
|
2252
2297
|
orderProduct: targetProduct,
|
|
2253
2298
|
orderInventory: targetInventory,
|
|
2254
|
-
orderTote
|
|
2299
|
+
orderTote,
|
|
2255
2300
|
qty: pickedQty,
|
|
2256
2301
|
updater: this.user
|
|
2257
2302
|
})
|
|
2258
2303
|
} else {
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2304
|
+
await this.trxMgr.getRepository(OrderToteItem).update(foundOrderToteItem.id, {
|
|
2305
|
+
qty: foundOrderToteItem.qty + pickedQty,
|
|
2306
|
+
updater: this.user,
|
|
2307
|
+
updatedAt: new Date()
|
|
2308
|
+
})
|
|
2309
|
+
}
|
|
2310
|
+
}
|
|
2311
|
+
|
|
2312
|
+
// Check minimum-seal-number setting - if 0, automatically close the tote
|
|
2313
|
+
if (!orderTote.closedDate) {
|
|
2314
|
+
const sealNoSetting: Setting = await this.trxMgr.getRepository(Setting).findOne({
|
|
2315
|
+
where: {
|
|
2316
|
+
domain: this.domain,
|
|
2317
|
+
name: 'minimum-seal-number'
|
|
2318
|
+
}
|
|
2319
|
+
})
|
|
2320
|
+
|
|
2321
|
+
const minimumSealRequiredRaw = parseInt(sealNoSetting?.value ?? '0', 10)
|
|
2322
|
+
const minimumSealRequired = isNaN(minimumSealRequiredRaw) ? 0 : Math.max(0, minimumSealRequiredRaw)
|
|
2323
|
+
|
|
2324
|
+
if (minimumSealRequired === 0) {
|
|
2325
|
+
await this.trxMgr.getRepository(OrderTote).update(orderTote.id, {
|
|
2326
|
+
closedDate: new Date(),
|
|
2327
|
+
updater: this.user,
|
|
2328
|
+
updatedAt: new Date()
|
|
2263
2329
|
})
|
|
2264
2330
|
}
|
|
2265
2331
|
}
|
|
@@ -2376,7 +2442,7 @@ export class PickingWorksheetController extends VasWorksheetController {
|
|
|
2376
2442
|
throw new Error('Tote not scanned under this order')
|
|
2377
2443
|
}
|
|
2378
2444
|
|
|
2379
|
-
|
|
2445
|
+
const totalOrderToteItems = await this.trxMgr.getRepository(OrderToteItem).count({
|
|
2380
2446
|
where: {
|
|
2381
2447
|
orderTote: foundOrderTote
|
|
2382
2448
|
}
|
|
@@ -2386,7 +2452,7 @@ export class PickingWorksheetController extends VasWorksheetController {
|
|
|
2386
2452
|
throw new Error('Tote carton is empty')
|
|
2387
2453
|
}
|
|
2388
2454
|
|
|
2389
|
-
|
|
2455
|
+
await this.trxMgr.getRepository(OrderToteSeal).save({
|
|
2390
2456
|
domain: this.domain,
|
|
2391
2457
|
name: sealNo,
|
|
2392
2458
|
orderTote: foundOrderTote,
|
|
@@ -2397,10 +2463,18 @@ export class PickingWorksheetController extends VasWorksheetController {
|
|
|
2397
2463
|
orderTote: foundOrderTote
|
|
2398
2464
|
})
|
|
2399
2465
|
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2466
|
+
// Determine minimum seals required; clamp negative values to 0
|
|
2467
|
+
const minimumSealRequiredRaw = parseInt(sealNoSetting?.value ?? '0', 10)
|
|
2468
|
+
const minimumSealRequired = isNaN(minimumSealRequiredRaw) ? 0 : Math.max(0, minimumSealRequiredRaw)
|
|
2469
|
+
|
|
2470
|
+
// Close tote if: seals are optional (0) OR minimum seal count reached
|
|
2471
|
+
const shouldCloseTote = minimumSealRequired === 0 || totalSeal >= minimumSealRequired
|
|
2472
|
+
|
|
2473
|
+
if (shouldCloseTote) {
|
|
2474
|
+
await this.trxMgr.getRepository(OrderTote).update(foundOrderTote.id, {
|
|
2475
|
+
closedDate: new Date(),
|
|
2476
|
+
updater: this.user,
|
|
2477
|
+
updatedAt: new Date()
|
|
2404
2478
|
})
|
|
2405
2479
|
}
|
|
2406
2480
|
}
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
OrderNoGenerator,
|
|
10
10
|
OrderTote,
|
|
11
11
|
OrderToteItem,
|
|
12
|
+
OrderToteSeal,
|
|
12
13
|
ReleaseGood
|
|
13
14
|
} from '@things-factory/sales-base'
|
|
14
15
|
import { Setting } from '@things-factory/setting-base'
|
|
@@ -250,7 +251,7 @@ export class SortingWorksheetController extends VasWorksheetController {
|
|
|
250
251
|
} else {
|
|
251
252
|
sortedQty = matchingProduct.qty
|
|
252
253
|
}
|
|
253
|
-
|
|
254
|
+
|
|
254
255
|
const releaseGood: ReleaseGood =
|
|
255
256
|
orderInventories.length > 1
|
|
256
257
|
? orderInventories.find(item => item.productId === scanProductBarcode.productId)?.releaseGood
|
|
@@ -535,12 +536,59 @@ export class SortingWorksheetController extends VasWorksheetController {
|
|
|
535
536
|
throw new Error('Order is already sorted')
|
|
536
537
|
}
|
|
537
538
|
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
539
|
+
// Check enable-tote-scanning setting
|
|
540
|
+
let enableToteScanningSetting: Setting = await this.trxMgr.getRepository(Setting).findOne({
|
|
541
|
+
where: {
|
|
542
|
+
domain: this.domain,
|
|
543
|
+
category: 'id-rule',
|
|
544
|
+
name: 'enable-tote-scanning'
|
|
545
|
+
}
|
|
546
|
+
})
|
|
547
|
+
|
|
548
|
+
if (enableToteScanningSetting) {
|
|
549
|
+
// enable-tote-scanning is numeric: 0 = disabled, >= 1 = enabled
|
|
550
|
+
const enableToteScanningValue = parseInt(enableToteScanningSetting.value || '0', 10)
|
|
551
|
+
|
|
552
|
+
if (enableToteScanningValue >= 1) {
|
|
553
|
+
// Check minimum-seal-number setting
|
|
554
|
+
let minimumSealNumberSetting: Setting = await this.trxMgr.getRepository(Setting).findOne({
|
|
555
|
+
where: {
|
|
556
|
+
domain: this.domain,
|
|
557
|
+
category: 'id-rule',
|
|
558
|
+
name: 'minimum-seal-number'
|
|
559
|
+
}
|
|
560
|
+
})
|
|
541
561
|
|
|
542
|
-
|
|
543
|
-
|
|
562
|
+
const minimumSealNumber = parseInt(minimumSealNumberSetting?.value || '0', 10)
|
|
563
|
+
|
|
564
|
+
// Check if there are unsealed totes (closedDate is null)
|
|
565
|
+
const foundNotSealedOrderTote = await this.trxMgr
|
|
566
|
+
.getRepository(OrderTote)
|
|
567
|
+
.findOne({ where: { releaseGood, closedDate: IsNull() } })
|
|
568
|
+
|
|
569
|
+
if (foundNotSealedOrderTote) {
|
|
570
|
+
throw new Error('Please seal the tote(s) before proceeding')
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
// If minimum-seal-number > 0, validate seal counts per tote
|
|
574
|
+
if (minimumSealNumber > 0) {
|
|
575
|
+
// Get all order totes for this release good
|
|
576
|
+
const orderTotes: OrderTote[] = await this.trxMgr.getRepository(OrderTote).find({
|
|
577
|
+
where: { releaseGood },
|
|
578
|
+
relations: ['orderToteSeals']
|
|
579
|
+
})
|
|
580
|
+
|
|
581
|
+
// Validate each tote has at least minimum-seal-number seals
|
|
582
|
+
for (const orderTote of orderTotes) {
|
|
583
|
+
const sealCount = orderTote.orderToteSeals?.length || 0
|
|
584
|
+
if (sealCount < minimumSealNumber) {
|
|
585
|
+
throw new Error(
|
|
586
|
+
`Tote ${orderTote.name} has ${sealCount} seal(s), but minimum ${minimumSealNumber} seal(s) required`
|
|
587
|
+
)
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
}
|
|
544
592
|
}
|
|
545
593
|
|
|
546
594
|
releaseGood.status = ORDER_STATUS.READY_TO_LOAD
|
|
@@ -583,12 +631,59 @@ export class SortingWorksheetController extends VasWorksheetController {
|
|
|
583
631
|
|
|
584
632
|
let releaseGoodIds = worksheet.worksheetDetails.map(itm => itm.targetInventory.releaseGood.id)
|
|
585
633
|
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
634
|
+
// Check enable-tote-scanning setting
|
|
635
|
+
let enableToteScanningSetting: Setting = await this.trxMgr.getRepository(Setting).findOne({
|
|
636
|
+
where: {
|
|
637
|
+
domain: this.domain,
|
|
638
|
+
category: 'id-rule',
|
|
639
|
+
name: 'enable-tote-scanning'
|
|
640
|
+
}
|
|
641
|
+
})
|
|
589
642
|
|
|
590
|
-
if (
|
|
591
|
-
|
|
643
|
+
if (enableToteScanningSetting) {
|
|
644
|
+
// enable-tote-scanning is numeric: 0 = disabled, >= 1 = enabled
|
|
645
|
+
const enableToteScanningValue = parseInt(enableToteScanningSetting.value || '0', 10)
|
|
646
|
+
|
|
647
|
+
if (enableToteScanningValue >= 1) {
|
|
648
|
+
// Check minimum-seal-number setting
|
|
649
|
+
let minimumSealNumberSetting: Setting = await this.trxMgr.getRepository(Setting).findOne({
|
|
650
|
+
where: {
|
|
651
|
+
domain: this.domain,
|
|
652
|
+
category: 'id-rule',
|
|
653
|
+
name: 'minimum-seal-number'
|
|
654
|
+
}
|
|
655
|
+
})
|
|
656
|
+
|
|
657
|
+
const minimumSealNumber = parseInt(minimumSealNumberSetting?.value || '0', 10)
|
|
658
|
+
|
|
659
|
+
// Check if there are unsealed totes (closedDate is null) for any of the release goods
|
|
660
|
+
const foundNotSealedOrderTote = await this.trxMgr
|
|
661
|
+
.getRepository(OrderTote)
|
|
662
|
+
.findOne({ where: { releaseGood: In(releaseGoodIds), closedDate: IsNull() } })
|
|
663
|
+
|
|
664
|
+
if (foundNotSealedOrderTote) {
|
|
665
|
+
throw new Error('Please seal the tote(s) before proceeding')
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
// If minimum-seal-number > 0, validate seal counts per tote for all release goods
|
|
669
|
+
if (minimumSealNumber > 0) {
|
|
670
|
+
// Get all order totes for all release goods in this worksheet
|
|
671
|
+
const orderTotes: OrderTote[] = await this.trxMgr.getRepository(OrderTote).find({
|
|
672
|
+
where: { releaseGood: In(releaseGoodIds) },
|
|
673
|
+
relations: ['orderToteSeals']
|
|
674
|
+
})
|
|
675
|
+
|
|
676
|
+
// Validate each tote has at least minimum-seal-number seals
|
|
677
|
+
for (const orderTote of orderTotes) {
|
|
678
|
+
const sealCount = orderTote.orderToteSeals?.length || 0
|
|
679
|
+
if (sealCount < minimumSealNumber) {
|
|
680
|
+
throw new Error(
|
|
681
|
+
`Tote ${orderTote.name} has ${sealCount} seal(s), but minimum ${minimumSealNumber} seal(s) required`
|
|
682
|
+
)
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
}
|
|
592
687
|
}
|
|
593
688
|
|
|
594
689
|
this.checkRecordValidity(worksheet, { status: WORKSHEET_STATUS.EXECUTING })
|
|
@@ -617,7 +712,7 @@ export class SortingWorksheetController extends VasWorksheetController {
|
|
|
617
712
|
|
|
618
713
|
private async toteScanning(toteNo, targetProduct, targetInventory, pickedQty, releaseGood, bizplace) {
|
|
619
714
|
//1. find tote
|
|
620
|
-
|
|
715
|
+
const foundTote: Tote = await this.trxMgr
|
|
621
716
|
.getRepository(Tote)
|
|
622
717
|
.findOne({ where: { bizplace, name: toteNo, deletedAt: IsNull() } })
|
|
623
718
|
|
|
@@ -630,22 +725,21 @@ export class SortingWorksheetController extends VasWorksheetController {
|
|
|
630
725
|
}
|
|
631
726
|
|
|
632
727
|
//2. find order tote
|
|
633
|
-
let
|
|
728
|
+
let orderTote: OrderTote = await this.trxMgr
|
|
634
729
|
.getRepository(OrderTote)
|
|
635
730
|
.findOne({ where: { domain: this.domain, name: toteNo, releaseGood } })
|
|
636
731
|
|
|
637
732
|
//if order tote not found then create one, if tote not found means it's tote box
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
const orderTote = await this.trxMgr.getRepository(OrderTote).save({
|
|
733
|
+
if (!orderTote) {
|
|
734
|
+
orderTote = await this.trxMgr.getRepository(OrderTote).save({
|
|
641
735
|
name: toteNo,
|
|
642
736
|
domain: this.domain,
|
|
643
737
|
releaseGood,
|
|
644
|
-
tote: foundTote
|
|
738
|
+
tote: foundTote ?? null,
|
|
645
739
|
updater: this.user
|
|
646
740
|
})
|
|
647
741
|
|
|
648
|
-
|
|
742
|
+
await this.trxMgr.getRepository(OrderToteItem).save({
|
|
649
743
|
domain: this.domain,
|
|
650
744
|
name: OrderNoGenerator.orderToteItem(),
|
|
651
745
|
orderProduct: targetProduct,
|
|
@@ -655,7 +749,7 @@ export class SortingWorksheetController extends VasWorksheetController {
|
|
|
655
749
|
updater: this.user
|
|
656
750
|
})
|
|
657
751
|
} else {
|
|
658
|
-
if (
|
|
752
|
+
if (orderTote.closedDate) {
|
|
659
753
|
throw new Error('Tote has been sealed, please try another tote!')
|
|
660
754
|
}
|
|
661
755
|
|
|
@@ -664,27 +758,45 @@ export class SortingWorksheetController extends VasWorksheetController {
|
|
|
664
758
|
domain: this.domain,
|
|
665
759
|
orderProduct: targetProduct,
|
|
666
760
|
orderInventory: targetInventory,
|
|
667
|
-
orderTote
|
|
761
|
+
orderTote
|
|
668
762
|
})
|
|
669
763
|
|
|
670
|
-
//if not order tote item doesnt exist then create one
|
|
671
764
|
if (!foundOrderToteItem) {
|
|
672
|
-
|
|
765
|
+
await this.trxMgr.getRepository(OrderToteItem).save({
|
|
673
766
|
domain: this.domain,
|
|
674
767
|
name: OrderNoGenerator.orderToteItem(),
|
|
675
768
|
orderProduct: targetProduct,
|
|
676
769
|
orderInventory: targetInventory,
|
|
677
|
-
orderTote
|
|
770
|
+
orderTote,
|
|
678
771
|
qty: pickedQty,
|
|
679
772
|
updater: this.user
|
|
680
773
|
})
|
|
681
774
|
} else {
|
|
682
|
-
|
|
683
|
-
const orderToteItem = await this.trxMgr.getRepository(OrderToteItem).save({
|
|
775
|
+
await this.trxMgr.getRepository(OrderToteItem).save({
|
|
684
776
|
...foundOrderToteItem,
|
|
685
777
|
qty: foundOrderToteItem.qty + pickedQty
|
|
686
778
|
})
|
|
687
779
|
}
|
|
688
780
|
}
|
|
781
|
+
|
|
782
|
+
// Check minimum-seal-number setting - if 0, automatically close the tote
|
|
783
|
+
if (!orderTote.closedDate) {
|
|
784
|
+
const sealNoSetting: Setting = await this.trxMgr.getRepository(Setting).findOne({
|
|
785
|
+
where: {
|
|
786
|
+
domain: this.domain,
|
|
787
|
+
name: 'minimum-seal-number'
|
|
788
|
+
}
|
|
789
|
+
})
|
|
790
|
+
|
|
791
|
+
const minimumSealRequiredRaw = parseInt(sealNoSetting?.value ?? '0', 10)
|
|
792
|
+
const minimumSealRequired = isNaN(minimumSealRequiredRaw) ? 0 : Math.max(0, minimumSealRequiredRaw)
|
|
793
|
+
|
|
794
|
+
if (minimumSealRequired === 0) {
|
|
795
|
+
await this.trxMgr.getRepository(OrderTote).save({
|
|
796
|
+
...orderTote,
|
|
797
|
+
closedDate: new Date()
|
|
798
|
+
})
|
|
799
|
+
}
|
|
800
|
+
}
|
|
689
801
|
}
|
|
690
802
|
}
|