@things-factory/operato-wms 4.3.752 → 4.3.755
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/client/pages/inbound/unload-product.js +30 -33
- package/client/pages/outbound/loading-product.js +2 -3
- package/client/pages/outbound/loading-v2/loading-execution-base.js +568 -56
- package/client/pages/outbound/loading-v2/loading-execution.js +258 -8
- package/client/pages/outbound/loading-v2/loading.js +82 -12
- package/client/pages/outbound/picking-product.js +11 -6
- package/client/pages/outbound/picking-v2/picking-execution-base.js +8 -8
- package/client/pages/outbound/picking-v2/picking-execution.js +75 -0
- package/client/pages/outbound/route-label-history-dialog.js +253 -0
- package/client/pages/outbound/route-label-popup.js +637 -131
- package/client/pages/outbound/show-ro-list-popup.js +8 -4
- package/client/pages/outbound/single-outbound-worksheet.js +55 -6
- package/client/pages/outbound/sorting-product.js +71 -25
- package/client/pages/outbound/zone-worksheet.js +62 -3
- package/dist-server/entities/index.js +9 -0
- package/dist-server/entities/index.js.map +1 -0
- package/dist-server/entities/route-label-sequence-counter.js +75 -0
- package/dist-server/entities/route-label-sequence-counter.js.map +1 -0
- package/dist-server/entities/route-label-sequence-log.js +74 -0
- package/dist-server/entities/route-label-sequence-log.js.map +1 -0
- package/dist-server/graphql/resolvers/index.js +3 -0
- package/dist-server/graphql/resolvers/index.js.map +1 -1
- package/dist-server/graphql/resolvers/outbound/complete-load.js +40 -3
- package/dist-server/graphql/resolvers/outbound/complete-load.js.map +1 -1
- package/dist-server/graphql/resolvers/outbound/find-loadable-release-good-by-bin.js +50 -11
- package/dist-server/graphql/resolvers/outbound/find-loadable-release-good-by-bin.js.map +1 -1
- package/dist-server/graphql/resolvers/outbound/find-loadable-release-good.js +90 -48
- package/dist-server/graphql/resolvers/outbound/find-loadable-release-good.js.map +1 -1
- package/dist-server/graphql/resolvers/outbound/loading-worksheet-v2.js +15 -7
- package/dist-server/graphql/resolvers/outbound/loading-worksheet-v2.js.map +1 -1
- package/dist-server/graphql/resolvers/outbound/sort-item.js +95 -16
- package/dist-server/graphql/resolvers/outbound/sort-item.js.map +1 -1
- package/dist-server/graphql/resolvers/route-label/index.js +7 -0
- package/dist-server/graphql/resolvers/route-label/index.js.map +1 -0
- package/dist-server/graphql/resolvers/route-label/route-label.js +220 -0
- package/dist-server/graphql/resolvers/route-label/route-label.js.map +1 -0
- package/dist-server/graphql/resolvers/zone-worksheet/index.js.map +1 -1
- package/dist-server/graphql/resolvers/zone-worksheet/zone-picking.js +123 -27
- package/dist-server/graphql/resolvers/zone-worksheet/zone-picking.js.map +1 -1
- package/dist-server/graphql/resolvers/zone-worksheet/zone-worksheet.js.map +1 -1
- package/dist-server/graphql/types/index.js +4 -0
- package/dist-server/graphql/types/index.js.map +1 -1
- package/dist-server/graphql/types/outbound/index.js +7 -1
- package/dist-server/graphql/types/outbound/index.js.map +1 -1
- package/dist-server/graphql/types/route-label/index.js +14 -0
- package/dist-server/graphql/types/route-label/index.js.map +1 -0
- package/dist-server/graphql/types/route-label/route-label-sequence.js +53 -0
- package/dist-server/graphql/types/route-label/route-label-sequence.js.map +1 -0
- package/dist-server/index.js +5 -0
- package/dist-server/index.js.map +1 -1
- package/dist-server/validators/setting-validators.js +519 -0
- package/dist-server/validators/setting-validators.js.map +1 -0
- package/helps/operato-wms/outbound/picking-product.en.md +156 -158
- package/package.json +50 -50
- package/server/entities/index.ts +6 -0
- package/server/entities/route-label-sequence-counter.ts +56 -0
- package/server/entities/route-label-sequence-log.ts +47 -0
- package/server/graphql/resolvers/index.ts +3 -0
- package/server/graphql/resolvers/outbound/complete-load.ts +42 -1
- package/server/graphql/resolvers/outbound/find-loadable-release-good-by-bin.ts +56 -13
- package/server/graphql/resolvers/outbound/find-loadable-release-good.ts +120 -57
- package/server/graphql/resolvers/outbound/loading-worksheet-v2.ts +9 -2
- package/server/graphql/resolvers/outbound/sort-item.ts +125 -21
- package/server/graphql/resolvers/route-label/index.ts +16 -0
- package/server/graphql/resolvers/route-label/route-label.ts +264 -0
- package/server/graphql/resolvers/zone-worksheet/index.ts +2 -2
- package/server/graphql/resolvers/zone-worksheet/zone-picking.ts +156 -39
- package/server/graphql/resolvers/zone-worksheet/zone-worksheet.ts +1 -2
- package/server/graphql/types/index.ts +4 -0
- package/server/graphql/types/outbound/index.ts +7 -1
- package/server/graphql/types/route-label/index.ts +18 -0
- package/server/graphql/types/route-label/route-label-sequence.ts +50 -0
- package/server/index.ts +7 -1
- package/server/validators/setting-validators.ts +668 -0
- package/translations/en.json +280 -252
- package/translations/ko.json +29 -1
- package/translations/ms.json +28 -0
- package/translations/zh.json +28 -0
|
@@ -3,8 +3,49 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.sortItem = void 0;
|
|
4
4
|
const typeorm_1 = require("typeorm");
|
|
5
5
|
const sales_base_1 = require("@things-factory/sales-base");
|
|
6
|
+
const warehouse_base_1 = require("@things-factory/warehouse-base");
|
|
7
|
+
/**
|
|
8
|
+
* Calculates the available quantity that can still be sorted for an order inventory
|
|
9
|
+
*/
|
|
10
|
+
function getAvailableQty(oi) {
|
|
11
|
+
const available = Math.min(oi.releaseQty, oi.pickedQty) - oi.sortedQty;
|
|
12
|
+
return available > 0 ? available : 0;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Creates or updates an order tote item with the given quantity
|
|
16
|
+
*/
|
|
17
|
+
async function upsertOrderToteItem(tx, domain, user, orderTote, orderInventory, qtyToAdd) {
|
|
18
|
+
var _a;
|
|
19
|
+
const orderToteItemRepo = tx.getRepository(sales_base_1.OrderToteItem);
|
|
20
|
+
const existingItem = (await orderToteItemRepo.findOne({
|
|
21
|
+
where: {
|
|
22
|
+
domain,
|
|
23
|
+
orderTote,
|
|
24
|
+
orderInventory,
|
|
25
|
+
orderProduct: orderInventory.orderProduct
|
|
26
|
+
}
|
|
27
|
+
}));
|
|
28
|
+
if (!existingItem) {
|
|
29
|
+
await orderToteItemRepo.save({
|
|
30
|
+
domain,
|
|
31
|
+
name: sales_base_1.OrderNoGenerator.orderToteItem(),
|
|
32
|
+
orderTote,
|
|
33
|
+
orderInventory,
|
|
34
|
+
orderProduct: orderInventory.orderProduct,
|
|
35
|
+
qty: qtyToAdd,
|
|
36
|
+
updater: user
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
await orderToteItemRepo.update(existingItem.id, {
|
|
41
|
+
qty: Number((_a = existingItem.qty) !== null && _a !== void 0 ? _a : 0) + qtyToAdd,
|
|
42
|
+
updater: user,
|
|
43
|
+
updatedAt: new Date()
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
6
47
|
exports.sortItem = {
|
|
7
|
-
async sortItem(_, { releaseGoodNo, productBarcode, qty, worksheetDetails }, context) {
|
|
48
|
+
async sortItem(_, { releaseGoodNo, productBarcode, qty, worksheetDetails, toteNo }, context) {
|
|
8
49
|
const { domain, user, tx } = context.state;
|
|
9
50
|
// Single query to get order inventories based on either releaseGood name or binLocation
|
|
10
51
|
const orderInventories = await tx
|
|
@@ -12,20 +53,17 @@ exports.sortItem = {
|
|
|
12
53
|
.createQueryBuilder('orderInventory')
|
|
13
54
|
.innerJoinAndSelect('orderInventory.productDetail', 'productDetail')
|
|
14
55
|
.innerJoinAndSelect('productDetail.productBarcodes', 'productBarcode')
|
|
56
|
+
.leftJoinAndSelect('orderInventory.orderProduct', 'orderProduct')
|
|
15
57
|
.leftJoinAndSelect('orderInventory.releaseGood', 'releaseGood')
|
|
58
|
+
.leftJoinAndSelect('releaseGood.bizplace', 'bizplace')
|
|
16
59
|
.leftJoinAndSelect('orderInventory.binLocation', 'binLocation')
|
|
17
60
|
.where('orderInventory.domain_id = :domainId', { domainId: domain.id })
|
|
18
61
|
.andWhere('orderInventory.status IN (:...statuses)', {
|
|
19
|
-
statuses: [
|
|
20
|
-
sales_base_1.ORDER_INVENTORY_STATUS.SORTING,
|
|
21
|
-
sales_base_1.ORDER_INVENTORY_STATUS.LOADING
|
|
22
|
-
]
|
|
62
|
+
statuses: [sales_base_1.ORDER_INVENTORY_STATUS.SORTING, sales_base_1.ORDER_INVENTORY_STATUS.LOADING]
|
|
23
63
|
})
|
|
24
64
|
.andWhere('productBarcode.gtin = :gtin', { gtin: productBarcode })
|
|
25
65
|
.andWhere(new typeorm_1.Brackets(qb => {
|
|
26
|
-
qb
|
|
27
|
-
.where('orderInventory.sortedQty < orderInventory.pickedQty')
|
|
28
|
-
.andWhere('orderInventory.sortedQty < orderInventory.releaseQty');
|
|
66
|
+
qb.where('orderInventory.sortedQty < orderInventory.pickedQty').andWhere('orderInventory.sortedQty < orderInventory.releaseQty');
|
|
29
67
|
}))
|
|
30
68
|
.andWhere(new typeorm_1.Brackets(qb => {
|
|
31
69
|
qb.where('releaseGood.name = :releaseGoodNo', { releaseGoodNo }).orWhere('binLocation.name = :releaseGoodNo', { releaseGoodNo });
|
|
@@ -33,11 +71,49 @@ exports.sortItem = {
|
|
|
33
71
|
.getMany();
|
|
34
72
|
if (!orderInventories.length)
|
|
35
73
|
throw new Error('No matching product barcode found');
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
74
|
+
let resolvedReleaseGood = null;
|
|
75
|
+
let resolvedOrderTote = null;
|
|
76
|
+
if (toteNo) {
|
|
77
|
+
// Ensure we can identify a single release order when scanning by BIN
|
|
78
|
+
const uniqueReleaseGoodIds = [...new Set(orderInventories.map(oi => oi.releaseGoodId).filter(Boolean))];
|
|
79
|
+
if (uniqueReleaseGoodIds.length > 1) {
|
|
80
|
+
throw new Error('Multiple release orders detected. Please select a release order before tote scanning.');
|
|
81
|
+
}
|
|
82
|
+
resolvedReleaseGood = await tx.getRepository(sales_base_1.ReleaseGood).findOne({
|
|
83
|
+
where: { domain, id: uniqueReleaseGoodIds[0] },
|
|
84
|
+
relations: ['bizplace']
|
|
85
|
+
});
|
|
86
|
+
if (!resolvedReleaseGood) {
|
|
87
|
+
throw new Error('Release good not found for tote scanning');
|
|
88
|
+
}
|
|
89
|
+
resolvedOrderTote = await tx.getRepository(sales_base_1.OrderTote).findOne({
|
|
90
|
+
where: { domain, name: toteNo, releaseGood: resolvedReleaseGood }
|
|
91
|
+
});
|
|
92
|
+
if (!resolvedOrderTote) {
|
|
93
|
+
// Query for valid totes (NOT dispatched or damaged)
|
|
94
|
+
const foundTote = await tx.getRepository(warehouse_base_1.Tote).findOne({
|
|
95
|
+
where: {
|
|
96
|
+
bizplace: resolvedReleaseGood.bizplace,
|
|
97
|
+
name: toteNo,
|
|
98
|
+
deletedAt: (0, typeorm_1.IsNull)(),
|
|
99
|
+
status: (0, typeorm_1.Not)((0, typeorm_1.In)([warehouse_base_1.TOTE_STATUS.DISPATCHED, warehouse_base_1.TOTE_STATUS.DAMAGED]))
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
resolvedOrderTote = await tx.getRepository(sales_base_1.OrderTote).save({
|
|
103
|
+
name: toteNo,
|
|
104
|
+
domain,
|
|
105
|
+
releaseGood: resolvedReleaseGood,
|
|
106
|
+
tote: foundTote !== null && foundTote !== void 0 ? foundTote : null,
|
|
107
|
+
creator: user,
|
|
108
|
+
updater: user
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
else if (resolvedOrderTote.closedDate) {
|
|
112
|
+
throw new Error('Tote has been sealed, please try another tote!');
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// Calculate total available quantity using helper function
|
|
116
|
+
const totalAvailableQty = orderInventories.reduce((sum, oi) => sum + getAvailableQty(oi), 0);
|
|
41
117
|
if (qty > totalAvailableQty) {
|
|
42
118
|
throw new Error(`Sort qty (${qty}) exceeds total available quantity (${totalAvailableQty})`);
|
|
43
119
|
}
|
|
@@ -46,18 +122,21 @@ exports.sortItem = {
|
|
|
46
122
|
for (const orderInventory of orderInventories) {
|
|
47
123
|
if (remainingQty <= 0)
|
|
48
124
|
break;
|
|
49
|
-
const availableQty =
|
|
125
|
+
const availableQty = getAvailableQty(orderInventory);
|
|
50
126
|
if (availableQty <= 0)
|
|
51
127
|
continue;
|
|
52
128
|
const qtyToAdd = Math.min(remainingQty, availableQty);
|
|
53
|
-
const newSortQty = orderInventory.sortedQty + qtyToAdd;
|
|
54
129
|
// Update the order inventory
|
|
55
130
|
await tx.getRepository(sales_base_1.OrderInventory).update(orderInventory.id, {
|
|
56
|
-
sortedQty:
|
|
131
|
+
sortedQty: orderInventory.sortedQty + qtyToAdd,
|
|
57
132
|
status: sales_base_1.ORDER_INVENTORY_STATUS.LOADING,
|
|
58
133
|
updatedAt: new Date(),
|
|
59
134
|
updater: user
|
|
60
135
|
});
|
|
136
|
+
// Create / update order tote items to reflect tote allocation during QC
|
|
137
|
+
if (resolvedOrderTote) {
|
|
138
|
+
await upsertOrderToteItem(tx, domain, user, resolvedOrderTote, orderInventory, qtyToAdd);
|
|
139
|
+
}
|
|
61
140
|
remainingQty -= qtyToAdd;
|
|
62
141
|
}
|
|
63
142
|
return true;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sort-item.js","sourceRoot":"","sources":["../../../../server/graphql/resolvers/outbound/sort-item.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"sort-item.js","sourceRoot":"","sources":["../../../../server/graphql/resolvers/outbound/sort-item.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Mutation = exports.Query = void 0;
|
|
4
|
+
const route_label_1 = require("./route-label");
|
|
5
|
+
exports.Query = Object.assign(Object.assign(Object.assign({}, route_label_1.routeLabelReleaseGoodsInExecutingWorksheet), route_label_1.routeLabelSequenceStatuses), route_label_1.routeLabelSequenceLogs);
|
|
6
|
+
exports.Mutation = Object.assign({}, route_label_1.reserveRouteLabelSequence);
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../server/graphql/resolvers/route-label/index.ts"],"names":[],"mappings":";;;AAAA,+CAKsB;AAET,QAAA,KAAK,iDACb,wDAA0C,GAC1C,wCAA0B,GAC1B,oCAAsB,EAC1B;AAEY,QAAA,QAAQ,qBAChB,uCAAyB,EAC7B"}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.routeLabelSequenceLogs = exports.reserveRouteLabelSequence = exports.routeLabelSequenceStatuses = exports.routeLabelReleaseGoodsInExecutingWorksheet = void 0;
|
|
4
|
+
const typeorm_1 = require("typeorm");
|
|
5
|
+
const worksheet_base_1 = require("@things-factory/worksheet-base");
|
|
6
|
+
const route_label_sequence_counter_1 = require("../../../entities/route-label-sequence-counter");
|
|
7
|
+
const route_label_sequence_log_1 = require("../../../entities/route-label-sequence-log");
|
|
8
|
+
function ensureSeqField(field) {
|
|
9
|
+
if (!['refNo', 'refNo2', 'refNo3'].includes(field)) {
|
|
10
|
+
throw new Error('Invalid sequence field. Allowed: refNo, refNo2, refNo3');
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
function parseNonNegativeInt(value) {
|
|
14
|
+
const n = parseInt(value !== null && value !== void 0 ? value : '0', 10);
|
|
15
|
+
return Number.isFinite(n) ? Math.max(0, n) : 0;
|
|
16
|
+
}
|
|
17
|
+
exports.routeLabelReleaseGoodsInExecutingWorksheet = {
|
|
18
|
+
async routeLabelReleaseGoodsInExecutingWorksheet(_, { partnerId, refNo, worksheetType, seqField }, context) {
|
|
19
|
+
const { domain, tx } = context.state;
|
|
20
|
+
let filterRefNo = '';
|
|
21
|
+
if (refNo) {
|
|
22
|
+
const removeSymbol = refNo
|
|
23
|
+
.split('')
|
|
24
|
+
.filter(res => res !== '%')
|
|
25
|
+
.join('');
|
|
26
|
+
const filterInfos = removeSymbol
|
|
27
|
+
.toLowerCase()
|
|
28
|
+
.split(',')
|
|
29
|
+
.map(value => "'%" + value.trim().replace(/'/g, "''") + "%'")
|
|
30
|
+
.join(',');
|
|
31
|
+
filterRefNo = ` and (
|
|
32
|
+
lower(rg.ref_no) like any(array[${filterInfos}])
|
|
33
|
+
or lower(rg.ref_no_2) like any(array[${filterInfos}])
|
|
34
|
+
or lower(rg.ref_no_3) like any(array[${filterInfos}])
|
|
35
|
+
)`;
|
|
36
|
+
}
|
|
37
|
+
const rows = await tx.query(`
|
|
38
|
+
select distinct
|
|
39
|
+
rg.id as "id",
|
|
40
|
+
rg.name as "name",
|
|
41
|
+
rg.ref_no as "refNo",
|
|
42
|
+
rg.ref_no_2 as "refNo2",
|
|
43
|
+
rg.ref_no_3 as "refNo3",
|
|
44
|
+
rg.route_id as "routeId",
|
|
45
|
+
rg.store_id as "storeId",
|
|
46
|
+
rg.store_name as "storeName",
|
|
47
|
+
rg.stop_id as "stopId",
|
|
48
|
+
rg.created_at as "createdAt"
|
|
49
|
+
from worksheets ws
|
|
50
|
+
inner join worksheet_details wsd on wsd.worksheet_id = ws.id
|
|
51
|
+
inner join order_inventories oi on oi.id = wsd.target_inventory_id
|
|
52
|
+
inner join release_goods rg on rg.id = oi.release_good_id
|
|
53
|
+
where ws.domain_id = $1
|
|
54
|
+
and ws.type = $2
|
|
55
|
+
and ws.status = $3
|
|
56
|
+
and rg.domain_id = $1
|
|
57
|
+
and rg.bizplace_id = $4
|
|
58
|
+
${filterRefNo}
|
|
59
|
+
order by rg.created_at desc
|
|
60
|
+
`, [domain.id, worksheetType, worksheet_base_1.WORKSHEET_STATUS.EXECUTING, partnerId]);
|
|
61
|
+
const releaseGoods = rows || [];
|
|
62
|
+
// If seqField is provided, fetch and merge sequence data
|
|
63
|
+
if (seqField && ['refNo', 'refNo2', 'refNo3'].includes(seqField) && releaseGoods.length > 0) {
|
|
64
|
+
const releaseGoodIds = releaseGoods.map((rg) => rg.id);
|
|
65
|
+
// Fetch lastSeq from counters
|
|
66
|
+
const lastSeqById = new Map();
|
|
67
|
+
const counterRepo = tx.getRepository(route_label_sequence_counter_1.RouteLabelSequenceCounter);
|
|
68
|
+
const counters = await counterRepo.find({
|
|
69
|
+
where: { domain, releaseGoodId: (0, typeorm_1.In)(releaseGoodIds), field: seqField }
|
|
70
|
+
});
|
|
71
|
+
for (const c of counters) {
|
|
72
|
+
lastSeqById.set(c.releaseGoodId, parseNonNegativeInt(c.lastSeq));
|
|
73
|
+
}
|
|
74
|
+
// Fetch lastPrintedBy from logs (most recent per releaseGood)
|
|
75
|
+
const lastPrintedById = new Map();
|
|
76
|
+
const logRepo = tx.getRepository(route_label_sequence_log_1.RouteLabelSequenceLog);
|
|
77
|
+
const logs = await logRepo.find({
|
|
78
|
+
where: { domain, releaseGoodId: (0, typeorm_1.In)(releaseGoodIds), field: seqField },
|
|
79
|
+
relations: ['creator'],
|
|
80
|
+
order: { createdAt: 'DESC' },
|
|
81
|
+
take: 500
|
|
82
|
+
});
|
|
83
|
+
for (const log of logs) {
|
|
84
|
+
if (!lastPrintedById.has(log.releaseGoodId) && log.creator) {
|
|
85
|
+
lastPrintedById.set(log.releaseGoodId, log.creator.name || '');
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// Merge sequence data into release goods
|
|
89
|
+
return releaseGoods.map((rg) => (Object.assign(Object.assign({}, rg), { lastSeq: lastSeqById.get(rg.id) || 0, lastPrintedBy: lastPrintedById.get(rg.id) || null })));
|
|
90
|
+
}
|
|
91
|
+
return releaseGoods;
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
exports.routeLabelSequenceStatuses = {
|
|
95
|
+
async routeLabelSequenceStatuses(_, { releaseGoodIds, field }, context) {
|
|
96
|
+
const { domain, tx } = context.state;
|
|
97
|
+
ensureSeqField(field);
|
|
98
|
+
const lastSeqById = new Map();
|
|
99
|
+
const counterRepo = tx.getRepository(route_label_sequence_counter_1.RouteLabelSequenceCounter);
|
|
100
|
+
const counters = await counterRepo.find({
|
|
101
|
+
where: { domain, releaseGoodId: (0, typeorm_1.In)(releaseGoodIds), field }
|
|
102
|
+
});
|
|
103
|
+
for (const c of counters) {
|
|
104
|
+
lastSeqById.set(c.releaseGoodId, parseNonNegativeInt(c.lastSeq));
|
|
105
|
+
}
|
|
106
|
+
const histById = new Map();
|
|
107
|
+
const lastPrintedById = new Map();
|
|
108
|
+
const logRepo = tx.getRepository(route_label_sequence_log_1.RouteLabelSequenceLog);
|
|
109
|
+
const logs = await logRepo.find({
|
|
110
|
+
where: { domain, releaseGoodId: (0, typeorm_1.In)(releaseGoodIds), field },
|
|
111
|
+
relations: ['creator'],
|
|
112
|
+
order: { createdAt: 'DESC' },
|
|
113
|
+
take: 500
|
|
114
|
+
});
|
|
115
|
+
for (const log of logs) {
|
|
116
|
+
const list = histById.get(log.releaseGoodId) || [];
|
|
117
|
+
if (list.length >= 5)
|
|
118
|
+
continue;
|
|
119
|
+
list.push(`${log.from}-${log.to}`);
|
|
120
|
+
histById.set(log.releaseGoodId, list);
|
|
121
|
+
// Store the creator name from the most recent log entry (first one due to DESC order)
|
|
122
|
+
if (!lastPrintedById.has(log.releaseGoodId) && log.creator) {
|
|
123
|
+
lastPrintedById.set(log.releaseGoodId, log.creator.name || '');
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return releaseGoodIds.map((releaseGoodId) => {
|
|
127
|
+
return {
|
|
128
|
+
releaseGoodId,
|
|
129
|
+
field,
|
|
130
|
+
lastSeq: lastSeqById.get(releaseGoodId) || 0,
|
|
131
|
+
history: histById.get(releaseGoodId) || [],
|
|
132
|
+
lastPrintedBy: lastPrintedById.get(releaseGoodId) || null
|
|
133
|
+
};
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
exports.reserveRouteLabelSequence = {
|
|
138
|
+
async reserveRouteLabelSequence(_, { releaseGoodId, field, qty }, context) {
|
|
139
|
+
const { domain, tx, user } = context.state;
|
|
140
|
+
ensureSeqField(field);
|
|
141
|
+
const q = parseNonNegativeInt(qty);
|
|
142
|
+
if (q <= 0) {
|
|
143
|
+
throw new Error('Print qty must be greater than 0');
|
|
144
|
+
}
|
|
145
|
+
const counterRepo = tx.getRepository(route_label_sequence_counter_1.RouteLabelSequenceCounter);
|
|
146
|
+
const logRepo = tx.getRepository(route_label_sequence_log_1.RouteLabelSequenceLog);
|
|
147
|
+
// Lock counter row to avoid duplicated sequences under concurrent prints.
|
|
148
|
+
let counter = await counterRepo
|
|
149
|
+
.createQueryBuilder('c')
|
|
150
|
+
.setLock('pessimistic_write')
|
|
151
|
+
.where('c.domain = :domainId and c.releaseGoodId = :releaseGoodId and c.field = :field', {
|
|
152
|
+
domainId: domain.id,
|
|
153
|
+
releaseGoodId,
|
|
154
|
+
field
|
|
155
|
+
})
|
|
156
|
+
.getOne();
|
|
157
|
+
if (!counter) {
|
|
158
|
+
try {
|
|
159
|
+
await counterRepo.save({
|
|
160
|
+
domain,
|
|
161
|
+
releaseGoodId,
|
|
162
|
+
field,
|
|
163
|
+
lastSeq: 0,
|
|
164
|
+
creator: user,
|
|
165
|
+
updater: user
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
catch (e) {
|
|
169
|
+
// ignore: concurrent insert can violate unique index
|
|
170
|
+
}
|
|
171
|
+
counter = await counterRepo
|
|
172
|
+
.createQueryBuilder('c')
|
|
173
|
+
.setLock('pessimistic_write')
|
|
174
|
+
.where('c.domain = :domainId and c.releaseGoodId = :releaseGoodId and c.field = :field', {
|
|
175
|
+
domainId: domain.id,
|
|
176
|
+
releaseGoodId,
|
|
177
|
+
field
|
|
178
|
+
})
|
|
179
|
+
.getOne();
|
|
180
|
+
}
|
|
181
|
+
if (!counter) {
|
|
182
|
+
throw new Error('Failed to initialize route label sequence counter');
|
|
183
|
+
}
|
|
184
|
+
const last = parseNonNegativeInt(counter.lastSeq);
|
|
185
|
+
const from = last + 1;
|
|
186
|
+
const to = last + q;
|
|
187
|
+
await counterRepo.update(counter.id, { lastSeq: to, updater: user, updatedAt: new Date() });
|
|
188
|
+
await logRepo.save({ domain, releaseGoodId, field, from, to, qty: q, creator: user });
|
|
189
|
+
return { releaseGoodId, field, from, to };
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
exports.routeLabelSequenceLogs = {
|
|
193
|
+
async routeLabelSequenceLogs(_, { releaseGoodId, field }, context) {
|
|
194
|
+
const { domain, tx } = context.state;
|
|
195
|
+
ensureSeqField(field);
|
|
196
|
+
const rows = (await tx.query(`
|
|
197
|
+
select
|
|
198
|
+
l.id as "id",
|
|
199
|
+
l.release_good_id as "releaseGoodId",
|
|
200
|
+
l.field as "field",
|
|
201
|
+
l."from" as "from",
|
|
202
|
+
l."to" as "to",
|
|
203
|
+
l.qty as "qty",
|
|
204
|
+
l.created_at as "createdAt",
|
|
205
|
+
u.name as "creatorName"
|
|
206
|
+
from route_label_sequence_logs l
|
|
207
|
+
left join users u on u.id = l.creator_id
|
|
208
|
+
where l.domain_id = $1
|
|
209
|
+
and l.release_good_id = $2
|
|
210
|
+
and l.field = $3
|
|
211
|
+
order by l.created_at desc
|
|
212
|
+
limit 200
|
|
213
|
+
`, [domain.id, releaseGoodId, field])) || [];
|
|
214
|
+
return rows.map((row) => {
|
|
215
|
+
const createdAt = row.createdAt ? new Date(row.createdAt) : null;
|
|
216
|
+
return Object.assign(Object.assign({}, row), { createdAt: createdAt ? createdAt.toISOString() : null });
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
//# sourceMappingURL=route-label.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route-label.js","sourceRoot":"","sources":["../../../../server/graphql/resolvers/route-label/route-label.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../server/graphql/resolvers/zone-worksheet/index.ts"],"names":[],"mappings":";;;AAAA,qDAA8E;AAC9E,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../server/graphql/resolvers/zone-worksheet/index.ts"],"names":[],"mappings":";;;AAAA,qDAA8E;AAC9E,uEAAwE;AACxE,uEAA0G;AAC1G,iDAA4C;AAC5C,mDAA8C;AAC9C,mEAA4D;AAE/C,QAAA,KAAK,mCACb,sCAAqB,GACrB,qCAAoB,EACxB;AAEY,QAAA,QAAQ,2FAChB,sDAA4B,GAC5B,sDAA4B,GAC5B,0DAAgC,GAChC,0BAAW,GACX,4BAAY,GACZ,0CAAkB,EACtB"}
|
|
@@ -6,6 +6,7 @@ const worksheet_base_1 = require("@things-factory/worksheet-base");
|
|
|
6
6
|
const sales_base_1 = require("@things-factory/sales-base");
|
|
7
7
|
const warehouse_base_1 = require("@things-factory/warehouse-base");
|
|
8
8
|
const product_base_1 = require("@things-factory/product-base");
|
|
9
|
+
const setting_base_1 = require("@things-factory/setting-base");
|
|
9
10
|
const uuid_1 = require("uuid");
|
|
10
11
|
exports.zonePicking = {
|
|
11
12
|
async scanProductZonePicking(_, { worksheetId, cartonId, productBarcode, binNo, pickingQty }, context) {
|
|
@@ -244,11 +245,51 @@ async function completeZonePicking(worksheetId, context, isPartial) {
|
|
|
244
245
|
});
|
|
245
246
|
}
|
|
246
247
|
else if (!isPartial) {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
248
|
+
// When completing fully, check if all OrderInventories for each ReleaseGood are actually completed
|
|
249
|
+
// Only update from PARTIAL_PROCESSING to PROCESSING if all OrderInventories are completed
|
|
250
|
+
const releaseGoods = await tx.getRepository(sales_base_1.ReleaseGood).find({
|
|
251
|
+
where: { id: (0, typeorm_1.In)(roIds) },
|
|
252
|
+
relations: ['orderInventories']
|
|
251
253
|
});
|
|
254
|
+
const completedRoIds = [];
|
|
255
|
+
const incompleteRoIds = [];
|
|
256
|
+
for (const rg of releaseGoods) {
|
|
257
|
+
// Check if all OrderInventories are in a completed state (not PROCESSING)
|
|
258
|
+
const completedStatuses = [
|
|
259
|
+
sales_base_1.ORDER_INVENTORY_STATUS.PICKED,
|
|
260
|
+
sales_base_1.ORDER_INVENTORY_STATUS.SORTING,
|
|
261
|
+
sales_base_1.ORDER_INVENTORY_STATUS.LOADING,
|
|
262
|
+
sales_base_1.ORDER_INVENTORY_STATUS.LOADED,
|
|
263
|
+
sales_base_1.ORDER_INVENTORY_STATUS.TERMINATED,
|
|
264
|
+
sales_base_1.ORDER_INVENTORY_STATUS.MISSING,
|
|
265
|
+
sales_base_1.ORDER_INVENTORY_STATUS.CANCELLED
|
|
266
|
+
];
|
|
267
|
+
const allCompleted = rg.orderInventories.every(oi => completedStatuses.includes(oi.status));
|
|
268
|
+
if (allCompleted) {
|
|
269
|
+
completedRoIds.push(rg.id);
|
|
270
|
+
}
|
|
271
|
+
else {
|
|
272
|
+
incompleteRoIds.push(rg.id);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
// Update ReleaseGoods that are fully completed from PARTIAL_PROCESSING to PROCESSING
|
|
276
|
+
if (completedRoIds.length > 0) {
|
|
277
|
+
await tx.getRepository(sales_base_1.ReleaseGood).update({ id: (0, typeorm_1.In)(completedRoIds), status: sales_base_1.ORDER_STATUS.PARTIAL_PROCESSING }, {
|
|
278
|
+
status: sales_base_1.ORDER_STATUS.PROCESSING,
|
|
279
|
+
updater: user,
|
|
280
|
+
updatedAt: new Date()
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
// For ReleaseGoods that still have incomplete OrderInventories:
|
|
284
|
+
// - If they're in PROCESSING, update to PARTIAL_PROCESSING
|
|
285
|
+
// - If they're already in PARTIAL_PROCESSING, leave them as is
|
|
286
|
+
if (incompleteRoIds.length > 0) {
|
|
287
|
+
await tx.getRepository(sales_base_1.ReleaseGood).update({ id: (0, typeorm_1.In)(incompleteRoIds), status: sales_base_1.ORDER_STATUS.PROCESSING }, {
|
|
288
|
+
status: sales_base_1.ORDER_STATUS.PARTIAL_PROCESSING,
|
|
289
|
+
updater: user,
|
|
290
|
+
updatedAt: new Date()
|
|
291
|
+
});
|
|
292
|
+
}
|
|
252
293
|
}
|
|
253
294
|
//find exist loading worksheet
|
|
254
295
|
const existLoadingWorksheet = await tx
|
|
@@ -261,31 +302,67 @@ async function completeZonePicking(worksheetId, context, isPartial) {
|
|
|
261
302
|
.getMany();
|
|
262
303
|
let roWithoutLoadingWorksheet = roIds.filter(roId => !existLoadingWorksheet.some(ws => ws.releaseGood.id === roId));
|
|
263
304
|
let roWithLoadingWorksheet = roIds.filter(roId => existLoadingWorksheet.some(ws => ws.releaseGood.id === roId));
|
|
305
|
+
// Get disable-QC-in-loading setting
|
|
306
|
+
const disableQcSetting = await tx.getRepository(setting_base_1.Setting).findOne({
|
|
307
|
+
where: {
|
|
308
|
+
domain,
|
|
309
|
+
name: 'disable-QC-in-loading'
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
const disableQc = (disableQcSetting === null || disableQcSetting === void 0 ? void 0 : disableQcSetting.value) === 'true';
|
|
264
313
|
if (roWithoutLoadingWorksheet.length > 0) {
|
|
265
|
-
await generateLoadingWorksheets(tx, domain, user, roWithoutLoadingWorksheet);
|
|
314
|
+
await generateLoadingWorksheets(tx, domain, user, roWithoutLoadingWorksheet, disableQc);
|
|
266
315
|
}
|
|
267
316
|
if (roWithLoadingWorksheet.length > 0) {
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
317
|
+
if (disableQc) {
|
|
318
|
+
// When QC is disabled: update PICKED to LOADING status and set sortedQty = pickedQty automatically
|
|
319
|
+
// Use query builder with raw SQL to set sortedQty = pickedQty in a single update
|
|
320
|
+
await tx
|
|
321
|
+
.getRepository(sales_base_1.OrderInventory)
|
|
322
|
+
.createQueryBuilder()
|
|
323
|
+
.update(sales_base_1.OrderInventory)
|
|
324
|
+
.set({
|
|
325
|
+
status: sales_base_1.ORDER_INVENTORY_STATUS.LOADING,
|
|
326
|
+
sortedQty: () => '"picked_qty"',
|
|
327
|
+
updater: user,
|
|
328
|
+
updatedAt: new Date()
|
|
329
|
+
})
|
|
330
|
+
.where('release_good_id IN (:...roIds)', { roIds: roWithLoadingWorksheet })
|
|
331
|
+
.andWhere('status = :status', { status: sales_base_1.ORDER_INVENTORY_STATUS.PICKED })
|
|
332
|
+
.execute();
|
|
333
|
+
const loadingOrderInventories = await tx.getRepository(sales_base_1.OrderInventory).find({
|
|
334
|
+
where: { releaseGood: (0, typeorm_1.In)(roWithLoadingWorksheet), status: sales_base_1.ORDER_INVENTORY_STATUS.LOADING }
|
|
335
|
+
});
|
|
336
|
+
//update loading wsd deactivated to executing
|
|
337
|
+
await tx.getRepository(worksheet_base_1.WorksheetDetail).update({
|
|
338
|
+
targetInventory: (0, typeorm_1.In)(loadingOrderInventories.map(oi => oi.id)),
|
|
339
|
+
type: worksheet_base_1.WORKSHEET_TYPE.LOADING,
|
|
340
|
+
status: worksheet_base_1.WORKSHEET_STATUS.DEACTIVATED
|
|
341
|
+
}, { status: worksheet_base_1.WORKSHEET_STATUS.EXECUTING, updatedAt: new Date(), updater: user });
|
|
342
|
+
}
|
|
343
|
+
else {
|
|
344
|
+
// When QC is enabled: update PICKED to SORTING status (existing behavior)
|
|
345
|
+
await tx.getRepository(sales_base_1.OrderInventory).update({ releaseGood: (0, typeorm_1.In)(roWithLoadingWorksheet), status: sales_base_1.ORDER_INVENTORY_STATUS.PICKED }, {
|
|
346
|
+
status: sales_base_1.ORDER_INVENTORY_STATUS.SORTING,
|
|
347
|
+
updater: user,
|
|
348
|
+
updatedAt: new Date()
|
|
349
|
+
});
|
|
350
|
+
const loadingOrderInventories = await tx.getRepository(sales_base_1.OrderInventory).find({
|
|
351
|
+
where: { releaseGood: (0, typeorm_1.In)(roWithLoadingWorksheet), status: sales_base_1.ORDER_INVENTORY_STATUS.SORTING }
|
|
352
|
+
});
|
|
353
|
+
//update loading wsd deactivated to executing
|
|
354
|
+
await tx.getRepository(worksheet_base_1.WorksheetDetail).update({
|
|
355
|
+
targetInventory: (0, typeorm_1.In)(loadingOrderInventories.map(oi => oi.id)),
|
|
356
|
+
type: worksheet_base_1.WORKSHEET_TYPE.LOADING,
|
|
357
|
+
status: worksheet_base_1.WORKSHEET_STATUS.DEACTIVATED
|
|
358
|
+
}, { status: worksheet_base_1.WORKSHEET_STATUS.EXECUTING, updatedAt: new Date(), updater: user });
|
|
359
|
+
}
|
|
283
360
|
}
|
|
284
361
|
const wsStatus = isPartial ? worksheet_base_1.WORKSHEET_STATUS.PARTIAL_EXECUTING : worksheet_base_1.WORKSHEET_STATUS.DONE;
|
|
285
362
|
await updateWorksheetsAndDetails(tx, worksheet, worksheetDetails, wsStatus, user);
|
|
286
363
|
return true;
|
|
287
364
|
}
|
|
288
|
-
async function generateLoadingWorksheets(tx, domain, user, roWithoutLoadingWorksheet) {
|
|
365
|
+
async function generateLoadingWorksheets(tx, domain, user, roWithoutLoadingWorksheet, disableQc) {
|
|
289
366
|
const releaseGoods = await tx.getRepository(sales_base_1.ReleaseGood).find({
|
|
290
367
|
where: { id: (0, typeorm_1.In)(roWithoutLoadingWorksheet), status: (0, typeorm_1.Not)((0, typeorm_1.In)(sales_base_1.ORDER_STATUS.OBSOLETE)) },
|
|
291
368
|
relations: ['orderInventories', 'sortedBy']
|
|
@@ -320,12 +397,31 @@ async function generateLoadingWorksheets(tx, domain, user, roWithoutLoadingWorks
|
|
|
320
397
|
};
|
|
321
398
|
});
|
|
322
399
|
await tx.getRepository(worksheet_base_1.WorksheetDetail).insert(loadingWorksheetDetails);
|
|
323
|
-
//
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
400
|
+
// Update picked OrderInventories based on disableQc setting
|
|
401
|
+
if (disableQc) {
|
|
402
|
+
// When QC is disabled: update PICKED to LOADING status and set sortedQty = pickedQty automatically
|
|
403
|
+
await tx
|
|
404
|
+
.getRepository(sales_base_1.OrderInventory)
|
|
405
|
+
.createQueryBuilder()
|
|
406
|
+
.update(sales_base_1.OrderInventory)
|
|
407
|
+
.set({
|
|
408
|
+
status: sales_base_1.ORDER_INVENTORY_STATUS.LOADING,
|
|
409
|
+
sortedQty: () => '"picked_qty"',
|
|
410
|
+
updater: user,
|
|
411
|
+
updatedAt: new Date()
|
|
412
|
+
})
|
|
413
|
+
.where('id IN (:...oiIds)', { oiIds: orderInventories.map(oi => oi.id) })
|
|
414
|
+
.andWhere('status = :status', { status: sales_base_1.ORDER_INVENTORY_STATUS.PICKED })
|
|
415
|
+
.execute();
|
|
416
|
+
}
|
|
417
|
+
else {
|
|
418
|
+
// When QC is enabled: update PICKED to SORTING status (existing behavior)
|
|
419
|
+
await tx.getRepository(sales_base_1.OrderInventory).update({ id: (0, typeorm_1.In)(orderInventories.map(oi => oi.id)), status: sales_base_1.ORDER_INVENTORY_STATUS.PICKED }, {
|
|
420
|
+
status: sales_base_1.ORDER_INVENTORY_STATUS.SORTING,
|
|
421
|
+
updater: user,
|
|
422
|
+
updatedAt: new Date()
|
|
423
|
+
});
|
|
424
|
+
}
|
|
329
425
|
}
|
|
330
426
|
}
|
|
331
427
|
async function updateWorksheetsAndDetails(tx, worksheet, worksheetDetails, status, updater) {
|