@things-factory/operato-wms 4.3.823 → 4.3.825
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/adjustment/transfer-inventory.js +24 -64
- package/client/pages/components/select-product-popup.js +20 -0
- package/client/pages/constants/location.js +4 -0
- package/client/pages/master/location-list.js +140 -18
- package/client/pages/order/arrival-notice/create-arrival-notice.js +18 -0
- package/client/pages/order/draft-release-good/draft-release-good-list.js +1 -0
- package/client/pages/outbound/packing-product.js +10 -2
- package/dist-server/graphql/resolvers/index.js +2 -0
- package/dist-server/graphql/resolvers/index.js.map +1 -1
- package/dist-server/graphql/resolvers/outbound/get-loading-task.js +15 -5
- package/dist-server/graphql/resolvers/outbound/get-loading-task.js.map +1 -1
- package/dist-server/graphql/resolvers/transfer-location/check-transfer-location-recommendation.js +108 -0
- package/dist-server/graphql/resolvers/transfer-location/check-transfer-location-recommendation.js.map +1 -0
- package/dist-server/graphql/resolvers/transfer-location/index.js +7 -0
- package/dist-server/graphql/resolvers/transfer-location/index.js.map +1 -0
- package/dist-server/graphql/resolvers/zone-worksheet/get-zone-picking-task.js +17 -2
- package/dist-server/graphql/resolvers/zone-worksheet/get-zone-picking-task.js.map +1 -1
- package/dist-server/graphql/resolvers/zone-worksheet/zone-worksheet.js +13 -2
- package/dist-server/graphql/resolvers/zone-worksheet/zone-worksheet.js.map +1 -1
- package/dist-server/graphql/types/index.js +3 -0
- package/dist-server/graphql/types/index.js.map +1 -1
- package/dist-server/graphql/types/transfer-location/index.js +14 -0
- package/dist-server/graphql/types/transfer-location/index.js.map +1 -0
- package/dist-server/graphql/types/transfer-location/transfer-location-recommendation.js +13 -0
- package/dist-server/graphql/types/transfer-location/transfer-location-recommendation.js.map +1 -0
- package/dist-server/graphql/types/zone-worksheet/index.js +5 -1
- package/dist-server/graphql/types/zone-worksheet/index.js.map +1 -1
- package/package.json +6 -6
- package/server/graphql/resolvers/index.ts +2 -0
- package/server/graphql/resolvers/outbound/get-loading-task.ts +15 -5
- package/server/graphql/resolvers/transfer-location/check-transfer-location-recommendation.ts +123 -0
- package/server/graphql/resolvers/transfer-location/index.ts +7 -0
- package/server/graphql/resolvers/zone-worksheet/get-zone-picking-task.ts +17 -2
- package/server/graphql/resolvers/zone-worksheet/zone-worksheet.ts +17 -6
- package/server/graphql/types/index.ts +3 -0
- package/server/graphql/types/transfer-location/index.ts +13 -0
- package/server/graphql/types/transfer-location/transfer-location-recommendation.ts +7 -0
- package/server/graphql/types/zone-worksheet/index.ts +5 -1
- package/translations/en.json +12 -0
- package/translations/ko.json +12 -0
- package/translations/ms.json +12 -0
- package/translations/zh.json +12 -0
package/dist-server/graphql/resolvers/transfer-location/check-transfer-location-recommendation.js
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkTransferLocationRecommendation = void 0;
|
|
4
|
+
const setting_base_1 = require("@things-factory/setting-base");
|
|
5
|
+
const warehouse_base_1 = require("@things-factory/warehouse-base");
|
|
6
|
+
exports.checkTransferLocationRecommendation = {
|
|
7
|
+
async checkTransferLocationRecommendation(_, { originPalletId, toLocationName, qty }, context) {
|
|
8
|
+
var _a, _b, _c, _d, _e, _f;
|
|
9
|
+
const { domain, tx } = context.state;
|
|
10
|
+
const levelSetting = await tx
|
|
11
|
+
.getRepository(setting_base_1.Setting)
|
|
12
|
+
.findOne({ where: { domain, name: 'location-recommendation-level' } });
|
|
13
|
+
const level = (_a = levelSetting === null || levelSetting === void 0 ? void 0 : levelSetting.value) === null || _a === void 0 ? void 0 : _a.toUpperCase().trim();
|
|
14
|
+
if (!level)
|
|
15
|
+
return { warningMessage: null };
|
|
16
|
+
const inventory = await tx
|
|
17
|
+
.getRepository(warehouse_base_1.Inventory)
|
|
18
|
+
.createQueryBuilder('inv')
|
|
19
|
+
.innerJoinAndSelect('inv.product', 'product')
|
|
20
|
+
.leftJoinAndSelect('inv.productDetail', 'productDetail')
|
|
21
|
+
.where('inv.domain_id = :domainId', { domainId: domain.id })
|
|
22
|
+
.andWhere('inv.pallet_id = :palletId', { palletId: originPalletId })
|
|
23
|
+
.getOne();
|
|
24
|
+
if (!inventory)
|
|
25
|
+
return { warningMessage: null }; // Return silently. Actual transfer location process will only prompt error
|
|
26
|
+
const toLocation = await tx.getRepository(warehouse_base_1.Location).findOne({ where: { domain, name: toLocationName } });
|
|
27
|
+
if (!toLocation)
|
|
28
|
+
return { warningMessage: null }; // Return silently. Actual transfer location process will only prompt error
|
|
29
|
+
const inventoriesAtLocation = await tx
|
|
30
|
+
.getRepository(warehouse_base_1.Inventory)
|
|
31
|
+
.createQueryBuilder('inv')
|
|
32
|
+
.innerJoinAndSelect('inv.product', 'product')
|
|
33
|
+
.leftJoinAndSelect('inv.productDetail', 'productDetail')
|
|
34
|
+
.where('inv.domain_id = :domainId', { domainId: domain.id })
|
|
35
|
+
.andWhere('inv.location_id = :locationId', { locationId: toLocation.id })
|
|
36
|
+
.andWhere('inv.status = :status', { status: warehouse_base_1.INVENTORY_STATUS.STORED })
|
|
37
|
+
.getMany();
|
|
38
|
+
switch (level) {
|
|
39
|
+
case 'LEVEL 1': {
|
|
40
|
+
if (((_b = toLocation.status) === null || _b === void 0 ? void 0 : _b.toUpperCase()) !== warehouse_base_1.LOCATION_STATUS.EMPTY) {
|
|
41
|
+
return { warningMessage: 'reminder_location_assigned_to_another_sku' };
|
|
42
|
+
}
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
case 'LEVEL 2': {
|
|
46
|
+
const fromSku = (_c = inventory.product) === null || _c === void 0 ? void 0 : _c.sku;
|
|
47
|
+
const hasDifferentSku = inventoriesAtLocation.some(inv => { var _a; return ((_a = inv.product) === null || _a === void 0 ? void 0 : _a.sku) !== fromSku; });
|
|
48
|
+
if (hasDifferentSku) {
|
|
49
|
+
return { warningMessage: 'reminder_location_assigned_to_another_sku' };
|
|
50
|
+
}
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
case 'LEVEL 3': {
|
|
54
|
+
const fromSku = (_d = inventory.product) === null || _d === void 0 ? void 0 : _d.sku;
|
|
55
|
+
const hasDifferentSku = inventoriesAtLocation.some(inv => { var _a; return ((_a = inv.product) === null || _a === void 0 ? void 0 : _a.sku) !== fromSku; });
|
|
56
|
+
const stackingSetting = await tx.getRepository(setting_base_1.Setting).findOne({ where: { domain, name: 'stacking-option-limit' } });
|
|
57
|
+
let maxLimit = 1;
|
|
58
|
+
if (stackingSetting === null || stackingSetting === void 0 ? void 0 : stackingSetting.value) {
|
|
59
|
+
try {
|
|
60
|
+
const parsed = JSON.parse(stackingSetting.value);
|
|
61
|
+
maxLimit = Number(parsed.Max) || 1;
|
|
62
|
+
}
|
|
63
|
+
catch (_g) {
|
|
64
|
+
// ignore malformed setting
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
const stackingLimit = ((_e = inventory.product) === null || _e === void 0 ? void 0 : _e.allowStackingOption) ? maxLimit : null;
|
|
68
|
+
const hitStackingLimit = stackingLimit != null && inventoriesAtLocation.length >= stackingLimit;
|
|
69
|
+
if (hasDifferentSku || hitStackingLimit) {
|
|
70
|
+
return { warningMessage: 'reminder_location_occupied_by_different_sku_or_stacking_capacity' };
|
|
71
|
+
}
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
case 'LEVEL 4': {
|
|
75
|
+
if (!toLocation.volume)
|
|
76
|
+
return { warningMessage: 'location_missing_volume' };
|
|
77
|
+
// Check selected inventory's product
|
|
78
|
+
const incomingPd = inventory.productDetail;
|
|
79
|
+
const incomingInvalid = !(incomingPd === null || incomingPd === void 0 ? void 0 : incomingPd.lengthUnit) ||
|
|
80
|
+
((incomingPd === null || incomingPd === void 0 ? void 0 : incomingPd.volume) == null && (!(incomingPd === null || incomingPd === void 0 ? void 0 : incomingPd.width) || !(incomingPd === null || incomingPd === void 0 ? void 0 : incomingPd.depth) || !(incomingPd === null || incomingPd === void 0 ? void 0 : incomingPd.height)));
|
|
81
|
+
if (incomingInvalid)
|
|
82
|
+
return { warningMessage: 'incoming_inventory_missing_product_dimensions' };
|
|
83
|
+
// Check products stored in the targeted destination location
|
|
84
|
+
const existingInvalid = inventoriesAtLocation.some(inv => {
|
|
85
|
+
const pd = inv.productDetail;
|
|
86
|
+
return !(pd === null || pd === void 0 ? void 0 : pd.lengthUnit) || ((pd === null || pd === void 0 ? void 0 : pd.volume) == null && (!(pd === null || pd === void 0 ? void 0 : pd.width) || !(pd === null || pd === void 0 ? void 0 : pd.depth) || !(pd === null || pd === void 0 ? void 0 : pd.height)));
|
|
87
|
+
});
|
|
88
|
+
if (existingInvalid)
|
|
89
|
+
return { warningMessage: 'existing_inventory_missing_product_dimensions' };
|
|
90
|
+
const locationVolume = toLocation.volume;
|
|
91
|
+
const existingVolume = inventoriesAtLocation.reduce((sum, inv) => {
|
|
92
|
+
var _a, _b;
|
|
93
|
+
const pd = inv.productDetail;
|
|
94
|
+
const detail = (0, warehouse_base_1.buildProductDetailLabel)(pd);
|
|
95
|
+
const label = `SKU: ${(_a = inv.product) === null || _a === void 0 ? void 0 : _a.sku} ${detail}`.trim();
|
|
96
|
+
return sum + (0, warehouse_base_1.calcVolumeInM3)(pd, label) * ((_b = inv.qty) !== null && _b !== void 0 ? _b : 0);
|
|
97
|
+
}, 0);
|
|
98
|
+
const incomingDetail = (0, warehouse_base_1.buildProductDetailLabel)(incomingPd);
|
|
99
|
+
const incomingLabel = `SKU: ${(_f = inventory.product) === null || _f === void 0 ? void 0 : _f.sku} ${incomingDetail}`.trim();
|
|
100
|
+
if (existingVolume + (0, warehouse_base_1.calcVolumeInM3)(incomingPd, incomingLabel) * qty > locationVolume)
|
|
101
|
+
return { warningMessage: 'volume_over_location_capacity' };
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return { warningMessage: null };
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
//# sourceMappingURL=check-transfer-location-recommendation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-transfer-location-recommendation.js","sourceRoot":"","sources":["../../../../server/graphql/resolvers/transfer-location/check-transfer-location-recommendation.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 check_transfer_location_recommendation_1 = require("./check-transfer-location-recommendation");
|
|
5
|
+
exports.Query = Object.assign({}, check_transfer_location_recommendation_1.checkTransferLocationRecommendation);
|
|
6
|
+
exports.Mutation = {};
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../server/graphql/resolvers/transfer-location/index.ts"],"names":[],"mappings":";;;AAAA,qGAA8F;AAEjF,QAAA,KAAK,qBACb,4EAAmC,EACvC;AAEY,QAAA,QAAQ,GAAG,EAAE,CAAA"}
|
|
@@ -35,19 +35,34 @@ exports.getZonePickingTask = {
|
|
|
35
35
|
worksheet = await worksheetQb.getOne();
|
|
36
36
|
if (!worksheet) {
|
|
37
37
|
//find a worksheet and update assignee to user
|
|
38
|
+
// Claim a single oldest unassigned worksheet. The LIMIT 1 + FOR UPDATE
|
|
39
|
+
// SKIP LOCKED inside the subquery makes this safe under concurrent clicks:
|
|
40
|
+
// - LIMIT 1 prevents bulk-claiming every unassigned worksheet for one user
|
|
41
|
+
// (the previous version assigned ALL of them to the clicker and only
|
|
42
|
+
// returned x[0], silently mis-assigning the rest to whoever clicked first).
|
|
43
|
+
// - FOR UPDATE SKIP LOCKED makes concurrent callers pick different rows
|
|
44
|
+
// instead of waiting on each other and then failing with "no suitable
|
|
45
|
+
// worksheet found" because the first user already grabbed everything.
|
|
46
|
+
//
|
|
47
|
+
// Use an independent inner transaction (not the outer `tx`) so the UPDATE
|
|
48
|
+
// commits before the surrounding resolver transaction finishes. Otherwise
|
|
49
|
+
// the row lock acquired by the UPDATE would persist for the whole resolver,
|
|
50
|
+
// defeating SKIP LOCKED for any concurrent click that arrives mid-flight.
|
|
38
51
|
let updatedWorksheets = await (0, typeorm_1.getConnection)().transaction(async (tx2) => {
|
|
39
52
|
let x = await tx2.getRepository(worksheet_base_1.Worksheet).query(`
|
|
40
|
-
UPDATE worksheets ws SET
|
|
53
|
+
UPDATE worksheets ws SET
|
|
41
54
|
assignee_id = $2,
|
|
42
55
|
updated_at = NOW(),
|
|
43
56
|
updater_id = $2
|
|
44
57
|
FROM (
|
|
45
|
-
SELECT ws.id
|
|
58
|
+
SELECT ws.id FROM worksheets ws
|
|
46
59
|
WHERE ws.domain_id = $1
|
|
47
60
|
AND ws.type = 'ZONE_PICKING'
|
|
48
61
|
AND ws.status IN ('EXECUTING', 'DEACTIVATED')
|
|
49
62
|
AND ws.assignee_id IS NULL
|
|
50
63
|
ORDER BY ws.created_at
|
|
64
|
+
LIMIT 1
|
|
65
|
+
FOR UPDATE SKIP LOCKED
|
|
51
66
|
) src where src.id = ws.id
|
|
52
67
|
RETURNING ws.id;
|
|
53
68
|
`, [domain.id, assignee.id]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-zone-picking-task.js","sourceRoot":"","sources":["../../../../server/graphql/resolvers/zone-worksheet/get-zone-picking-task.ts"],"names":[],"mappings":";;;AAAA,qCAA0D;AAE1D,yDAAgD;AAEhD,2DAA8G;AAE9G,mEAA6G;AAC7G,+DAAsD;AACtD,qDAAuD;AAE1C,QAAA,kBAAkB,GAAG;IAChC,KAAK,CAAC,kBAAkB,CAAC,CAAM,EAAE,EAAE,EAAE,OAAY;QAC/C,IAAI;YACF,IAAI,SAAoB,CAAA;YACxB,IAAI,oBAA6B,CAAA;YACjC,MAAM,IAAA,uBAAa,GAAE,CAAC,WAAW,CAAC,KAAK,EAAE,EAAiB,EAAE,EAAE;gBAC5D,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAmC,OAAO,CAAC,KAAK,CAAA;gBACtE,MAAM,QAAQ,GAAS,MAAM,EAAE,CAAC,aAAa,CAAC,gBAAI,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,CAAA;gBAChG,IAAI,CAAC,CAAA,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAE,OAAO,KAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,UAAkB,EAAE,EAAE,CAAC,UAAU,CAAC,EAAE,KAAK,MAAM,CAAC,EAAE,CAAC;oBACtF,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAA;gBAEhE,IAAI,CAAC,QAAQ;oBAAE,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAA;gBAE5D,IAAI,WAAW,GAAG,MAAM,EAAE;qBACvB,aAAa,CAAC,0BAAS,CAAC;qBACxB,kBAAkB,CAAC,IAAI,CAAC;qBACxB,MAAM,CAAC,OAAO,CAAC;qBACf,SAAS,CAAC,SAAS,CAAC;qBACpB,SAAS,CAAC,WAAW,CAAC;qBACtB,KAAK,CACJ,mIAAmI,EACnI;oBACE,SAAS,EAAE,MAAM,CAAC,EAAE;oBACpB,IAAI,EAAE,+BAAc,CAAC,YAAY;oBACjC,QAAQ,EAAE,QAAQ,CAAC,EAAE;oBACrB,OAAO,EAAE,iCAAgB,CAAC,SAAS;oBACnC,OAAO,EAAE,iCAAgB,CAAC,WAAW;iBACtC,CACF,CAAA;gBACH,SAAS,GAAG,MAAM,WAAW,CAAC,MAAM,EAAE,CAAA;gBAEtC,IAAI,CAAC,SAAS,EAAE;oBACd,8CAA8C;oBAC9C,IAAI,iBAAiB,GAAG,MAAM,IAAA,uBAAa,GAAE,CAAC,WAAW,CAAC,KAAK,EAAE,GAAkB,EAAE,EAAE;wBACrF,IAAI,CAAC,GAAG,MAAM,GAAG,CAAC,aAAa,CAAC,0BAAS,CAAC,CAAC,KAAK,CAC9C
|
|
1
|
+
{"version":3,"file":"get-zone-picking-task.js","sourceRoot":"","sources":["../../../../server/graphql/resolvers/zone-worksheet/get-zone-picking-task.ts"],"names":[],"mappings":"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"}
|
|
@@ -55,6 +55,15 @@ exports.zonePickingWorksheet = {
|
|
|
55
55
|
zoneWorksheet.worksheetDetail = await (0, typeorm_1.getRepository)(worksheet_base_1.WorksheetDetail).find({
|
|
56
56
|
where: { worksheet }
|
|
57
57
|
});
|
|
58
|
+
// Lightweight pre-pass: only the columns needed to compute invIds, roIds, and
|
|
59
|
+
// isCompletable. Avoids running the heavy joined SELECT (product/inventory/
|
|
60
|
+
// location/productDetail/...) twice — the second, filtered getMany() below
|
|
61
|
+
// produces the rows actually returned to the client.
|
|
62
|
+
const orderInventories = await (0, typeorm_1.getRepository)(sales_base_1.OrderInventory)
|
|
63
|
+
.createQueryBuilder('oi')
|
|
64
|
+
.select(['oi.id', 'oi.inventoryId', 'oi.releaseGoodId', 'oi.status'])
|
|
65
|
+
.where('oi.ref_worksheet_id = :worksheetId', { worksheetId: worksheet.id })
|
|
66
|
+
.getMany();
|
|
58
67
|
//fetch order inventories
|
|
59
68
|
let qb = (0, typeorm_1.getRepository)(sales_base_1.OrderInventory)
|
|
60
69
|
.createQueryBuilder('oi')
|
|
@@ -66,8 +75,6 @@ exports.zonePickingWorksheet = {
|
|
|
66
75
|
.leftJoinAndSelect('pd.childProductDetail', 'cpd')
|
|
67
76
|
.leftJoinAndSelect('pd.parentProductDetails', 'ppd')
|
|
68
77
|
.where('ref_worksheet_id = :worksheetId', { worksheetId: worksheet.id });
|
|
69
|
-
//get all oi to find inventory changes and determine if the worksheet is completable
|
|
70
|
-
const orderInventories = await qb.getMany();
|
|
71
78
|
//item assigned to obsolete inventories will not be displayed during picking
|
|
72
79
|
if (filter) {
|
|
73
80
|
qb.andWhere('rg.status != :orderStatus', { orderStatus: sales_base_1.ORDER_STATUS.OBSOLETE });
|
|
@@ -136,6 +143,10 @@ exports.zonePickingWorksheet = {
|
|
|
136
143
|
}
|
|
137
144
|
};
|
|
138
145
|
function isCompletable(oi, ic) {
|
|
146
|
+
// NOTE: callers may pass a partial OrderInventory with only id/inventoryId/
|
|
147
|
+
// releaseGoodId/status populated (see the lightweight pre-pass in
|
|
148
|
+
// zonePickingWorksheet). Don't reference other fields here without first
|
|
149
|
+
// widening that SELECT.
|
|
139
150
|
//find processing oi and check if there is any pending inventory adjustment
|
|
140
151
|
let processingOi = oi.filter(item => item.status === sales_base_1.ORDER_INVENTORY_STATUS.PROCESSING);
|
|
141
152
|
processingOi = processingOi.filter(item => !ic.filter(change => change.status === 'APPROVED').some(change => change.inventory.id === item.inventoryId));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"zone-worksheet.js","sourceRoot":"","sources":["../../../../server/graphql/resolvers/zone-worksheet/zone-worksheet.ts"],"names":[],"mappings":";;;AAAA,
|
|
1
|
+
{"version":3,"file":"zone-worksheet.js","sourceRoot":"","sources":["../../../../server/graphql/resolvers/zone-worksheet/zone-worksheet.ts"],"names":[],"mappings":"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"}
|
|
@@ -33,6 +33,7 @@ const OpaMenu = __importStar(require("./opa-menu"));
|
|
|
33
33
|
const Reports = __importStar(require("./reports"));
|
|
34
34
|
const InventoryComparison = __importStar(require("./inventory-comparison"));
|
|
35
35
|
const ShippingProvider = __importStar(require("./shipping-provider"));
|
|
36
|
+
const TransferLocation = __importStar(require("./transfer-location"));
|
|
36
37
|
const WarehouseInventory = __importStar(require("./warehouse-inventory-adjustment"));
|
|
37
38
|
const RouteLabel = __importStar(require("./route-label"));
|
|
38
39
|
const ZoneWorksheet = __importStar(require("./zone-worksheet"));
|
|
@@ -47,6 +48,7 @@ exports.queries = [
|
|
|
47
48
|
InventoryComparison.Query,
|
|
48
49
|
ShippingProvider.Query,
|
|
49
50
|
Other.Query,
|
|
51
|
+
TransferLocation.Query,
|
|
50
52
|
RouteLabel.Query,
|
|
51
53
|
ZoneWorksheet.Query,
|
|
52
54
|
Outbound.Query
|
|
@@ -67,6 +69,7 @@ exports.types = [
|
|
|
67
69
|
...InventoryComparison.Types,
|
|
68
70
|
...ShippingProvider.Types,
|
|
69
71
|
...Other.Types,
|
|
72
|
+
...TransferLocation.Types,
|
|
70
73
|
...RouteLabel.Types,
|
|
71
74
|
...ZoneWorksheet.Types,
|
|
72
75
|
...Outbound.Types
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../server/graphql/types/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,8DAA+C;AAC/C,4DAA6C;AAC7C,8DAA+C;AAC/C,uDAAwC;AACxC,+CAAgC;AAChC,oDAAqC;AACrC,mDAAoC;AACpC,4EAA6D;AAC7D,sEAAuD;AACvD,qFAAsE;AACtE,0DAA2C;AAC3C,gEAAiD;AACjD,qDAAsC;AAEzB,QAAA,OAAO,GAAG;IACrB,YAAY,CAAC,KAAK;IAClB,WAAW,CAAC,KAAK;IACjB,YAAY,CAAC,KAAK;IAClB,SAAS,CAAC,KAAK;IACf,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,KAAK;IACb,mBAAmB,CAAC,KAAK;IACzB,gBAAgB,CAAC,KAAK;IACtB,KAAK,CAAC,KAAK;IACX,UAAU,CAAC,KAAK;IAChB,aAAa,CAAC,KAAK;IACnB,QAAQ,CAAC,KAAK;CACf,CAAA;AAEY,QAAA,SAAS,GAAG;IACvB,KAAK,CAAC,QAAQ;IACd,kBAAkB,CAAC,QAAQ;IAC3B,UAAU,CAAC,QAAQ;IACnB,aAAa,CAAC,QAAQ;IACtB,QAAQ,CAAC,QAAQ;CAClB,CAAA;AAEY,QAAA,KAAK,GAAG;IACnB,GAAG,YAAY,CAAC,KAAK;IACrB,GAAG,WAAW,CAAC,KAAK;IACpB,GAAG,SAAS,CAAC,KAAK;IAClB,GAAG,OAAO,CAAC,KAAK;IAChB,GAAG,OAAO,CAAC,KAAK;IAChB,GAAG,mBAAmB,CAAC,KAAK;IAC5B,GAAG,gBAAgB,CAAC,KAAK;IACzB,GAAG,KAAK,CAAC,KAAK;IACd,GAAG,UAAU,CAAC,KAAK;IACnB,GAAG,aAAa,CAAC,KAAK;IACtB,GAAG,QAAQ,CAAC,KAAK;CAClB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../server/graphql/types/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,8DAA+C;AAC/C,4DAA6C;AAC7C,8DAA+C;AAC/C,uDAAwC;AACxC,+CAAgC;AAChC,oDAAqC;AACrC,mDAAoC;AACpC,4EAA6D;AAC7D,sEAAuD;AACvD,sEAAuD;AACvD,qFAAsE;AACtE,0DAA2C;AAC3C,gEAAiD;AACjD,qDAAsC;AAEzB,QAAA,OAAO,GAAG;IACrB,YAAY,CAAC,KAAK;IAClB,WAAW,CAAC,KAAK;IACjB,YAAY,CAAC,KAAK;IAClB,SAAS,CAAC,KAAK;IACf,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,KAAK;IACb,mBAAmB,CAAC,KAAK;IACzB,gBAAgB,CAAC,KAAK;IACtB,KAAK,CAAC,KAAK;IACX,gBAAgB,CAAC,KAAK;IACtB,UAAU,CAAC,KAAK;IAChB,aAAa,CAAC,KAAK;IACnB,QAAQ,CAAC,KAAK;CACf,CAAA;AAEY,QAAA,SAAS,GAAG;IACvB,KAAK,CAAC,QAAQ;IACd,kBAAkB,CAAC,QAAQ;IAC3B,UAAU,CAAC,QAAQ;IACnB,aAAa,CAAC,QAAQ;IACtB,QAAQ,CAAC,QAAQ;CAClB,CAAA;AAEY,QAAA,KAAK,GAAG;IACnB,GAAG,YAAY,CAAC,KAAK;IACrB,GAAG,WAAW,CAAC,KAAK;IACpB,GAAG,SAAS,CAAC,KAAK;IAClB,GAAG,OAAO,CAAC,KAAK;IAChB,GAAG,OAAO,CAAC,KAAK;IAChB,GAAG,mBAAmB,CAAC,KAAK;IAC5B,GAAG,gBAAgB,CAAC,KAAK;IACzB,GAAG,KAAK,CAAC,KAAK;IACd,GAAG,gBAAgB,CAAC,KAAK;IACzB,GAAG,UAAU,CAAC,KAAK;IACnB,GAAG,aAAa,CAAC,KAAK;IACtB,GAAG,QAAQ,CAAC,KAAK;CAClB,CAAA"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Types = exports.Mutation = exports.Query = void 0;
|
|
4
|
+
const transfer_location_recommendation_1 = require("./transfer-location-recommendation");
|
|
5
|
+
exports.Query = `
|
|
6
|
+
checkTransferLocationRecommendation(
|
|
7
|
+
originPalletId: String!
|
|
8
|
+
toLocationName: String!
|
|
9
|
+
qty: Float!
|
|
10
|
+
): TransferLocationRecommendationResult @privilege(category: "inventory", privilege: "query") @transaction
|
|
11
|
+
`;
|
|
12
|
+
exports.Mutation = ``;
|
|
13
|
+
exports.Types = [transfer_location_recommendation_1.TransferLocationRecommendationResult];
|
|
14
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../server/graphql/types/transfer-location/index.ts"],"names":[],"mappings":";;;AAAA,yFAAyF;AAE5E,QAAA,KAAK,GAAG;;;;;;CAMpB,CAAA;AAEY,QAAA,QAAQ,GAAG,EAAE,CAAA;AAEb,QAAA,KAAK,GAAG,CAAC,uEAAoC,CAAC,CAAA"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.TransferLocationRecommendationResult = void 0;
|
|
7
|
+
const graphql_tag_1 = __importDefault(require("graphql-tag"));
|
|
8
|
+
exports.TransferLocationRecommendationResult = (0, graphql_tag_1.default) `
|
|
9
|
+
type TransferLocationRecommendationResult {
|
|
10
|
+
warningMessage: String
|
|
11
|
+
}
|
|
12
|
+
`;
|
|
13
|
+
//# sourceMappingURL=transfer-location-recommendation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transfer-location-recommendation.js","sourceRoot":"","sources":["../../../../server/graphql/types/transfer-location/transfer-location-recommendation.ts"],"names":[],"mappings":";;;;;;AAAA,8DAA6B;AAEhB,QAAA,oCAAoC,GAAG,IAAA,qBAAG,EAAA;;;;CAItD,CAAA"}
|
|
@@ -16,7 +16,11 @@ exports.Mutation = `
|
|
|
16
16
|
assignSorter(releaseGoodId: [String]!, userId: String): Boolean @transaction
|
|
17
17
|
completeZonePicking(worksheetId: String!): Boolean @transaction
|
|
18
18
|
completeZonePickingPartially(worksheetId: String!): Boolean @transaction
|
|
19
|
-
|
|
19
|
+
# Intentionally NOT @transaction — the resolver opens its own
|
|
20
|
+
# getConnection().transaction() and uses an independent inner transaction
|
|
21
|
+
# to commit the worksheet-claim UPDATE early (releases the row lock so
|
|
22
|
+
# SKIP LOCKED works for concurrent clicks). See get-zone-picking-task.ts.
|
|
23
|
+
getZonePickingTask: ZonePickingWorksheet @privilege(category: "worksheet_control", privilege: "mutation")
|
|
20
24
|
`;
|
|
21
25
|
exports.Types = [zone_worksheet_overview_1.ZoneWorksheetOverview, zone_worksheet_overview_list_1.ZoneWorksheetOverviewList, zone_picking_worksheet_1.ZonePickingWorksheet];
|
|
22
26
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../server/graphql/types/zone-worksheet/index.ts"],"names":[],"mappings":";;;AAAA,uEAAiE;AACjE,iFAA0E;AAC1E,qEAA+D;AAElD,QAAA,KAAK,GAAG;;;CAGpB,CAAA;AAEY,QAAA,QAAQ,GAAG
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../server/graphql/types/zone-worksheet/index.ts"],"names":[],"mappings":";;;AAAA,uEAAiE;AACjE,iFAA0E;AAC1E,qEAA+D;AAElD,QAAA,KAAK,GAAG;;;CAGpB,CAAA;AAEY,QAAA,QAAQ,GAAG;;;;;;;;;;;;;CAavB,CAAA;AAEY,QAAA,KAAK,GAAG,CAAC,+CAAqB,EAAE,wDAAyB,EAAE,6CAAoB,CAAC,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@things-factory/operato-wms",
|
|
3
|
-
"version": "4.3.
|
|
3
|
+
"version": "4.3.825",
|
|
4
4
|
"main": "dist-server/index.js",
|
|
5
5
|
"browser": "client/index.js",
|
|
6
6
|
"things-factory": true,
|
|
@@ -89,9 +89,9 @@
|
|
|
89
89
|
"@things-factory/pdf": "^4.3.815",
|
|
90
90
|
"@things-factory/print-proxy-service": "^4.3.815",
|
|
91
91
|
"@things-factory/print-ui": "^4.3.815",
|
|
92
|
-
"@things-factory/product-base": "^4.3.
|
|
92
|
+
"@things-factory/product-base": "^4.3.824",
|
|
93
93
|
"@things-factory/resource-ui": "^4.3.823",
|
|
94
|
-
"@things-factory/sales-ui": "^4.3.
|
|
94
|
+
"@things-factory/sales-ui": "^4.3.825",
|
|
95
95
|
"@things-factory/scene-data-transform": "^4.3.815",
|
|
96
96
|
"@things-factory/scene-excel": "^4.3.815",
|
|
97
97
|
"@things-factory/scene-firebase": "^4.3.815",
|
|
@@ -107,8 +107,8 @@
|
|
|
107
107
|
"@things-factory/system-ui": "^4.3.815",
|
|
108
108
|
"@things-factory/transport-base": "^4.3.819",
|
|
109
109
|
"@things-factory/tutorial-ui": "^4.3.815",
|
|
110
|
-
"@things-factory/warehouse-base": "^4.3.
|
|
111
|
-
"@things-factory/worksheet-base": "^4.3.
|
|
110
|
+
"@things-factory/warehouse-base": "^4.3.825",
|
|
111
|
+
"@things-factory/worksheet-base": "^4.3.825"
|
|
112
112
|
},
|
|
113
113
|
"devDependencies": {
|
|
114
114
|
"@things-factory/builder": "^4.3.815",
|
|
@@ -117,5 +117,5 @@
|
|
|
117
117
|
"cypress-localstorage-commands": "^1.6.1",
|
|
118
118
|
"eslint-plugin-cypress": "^2.12.1"
|
|
119
119
|
},
|
|
120
|
-
"gitHead": "
|
|
120
|
+
"gitHead": "43cdee469c00d0a82d5ebbe0dc5a2be173bbb370"
|
|
121
121
|
}
|
|
@@ -7,6 +7,7 @@ import * as OpaMenu from './opa-menu'
|
|
|
7
7
|
import * as Reports from './reports'
|
|
8
8
|
import * as InventoryComparison from './inventory-comparison'
|
|
9
9
|
import * as ShippingProviders from './shipping-provider'
|
|
10
|
+
import * as TransferLocation from './transfer-location'
|
|
10
11
|
import * as WarehouseInventoryAdjustment from './warehouse-inventory-adjustment'
|
|
11
12
|
import * as RouteLabel from './route-label'
|
|
12
13
|
import * as ZoneWorksheet from './zone-worksheet'
|
|
@@ -22,6 +23,7 @@ export const queries = [
|
|
|
22
23
|
Other.Query,
|
|
23
24
|
Reports.Query,
|
|
24
25
|
ShippingProviders.Query,
|
|
26
|
+
TransferLocation.Query,
|
|
25
27
|
RouteLabel.Query,
|
|
26
28
|
ZoneWorksheet.Query,
|
|
27
29
|
Outbound.Query
|
|
@@ -34,29 +34,39 @@ export const getLoadingTask = {
|
|
|
34
34
|
.getOne()
|
|
35
35
|
|
|
36
36
|
// 2. If no assigned worksheet, find and assign next available one
|
|
37
|
+
// FOR UPDATE OF ws SKIP LOCKED: under concurrent clicks, two callers
|
|
38
|
+
// used to SELECT the same row and the second UPDATE would re-evaluate,
|
|
39
|
+
// find sorter_id no longer NULL, update zero rows, and the user would
|
|
40
|
+
// see a confusing "no suitable worksheet found" error even though other
|
|
41
|
+
// unassigned rows existed. SKIP LOCKED makes concurrent callers pick
|
|
42
|
+
// different rows. `OF ws` scopes the row lock to the worksheets table
|
|
43
|
+
// only (not the joined release_goods / worksheet_details rows). Inner
|
|
44
|
+
// transaction is independent so the row lock is released as soon as
|
|
45
|
+
// the UPDATE commits.
|
|
37
46
|
if (!worksheet) {
|
|
38
47
|
let updatedWorksheets = await getConnection().transaction(async (tx2: EntityManager) => {
|
|
39
48
|
let x = await tx2.query(
|
|
40
49
|
`
|
|
41
|
-
UPDATE worksheets ws SET
|
|
50
|
+
UPDATE worksheets ws SET
|
|
42
51
|
sorter_id = $2,
|
|
43
52
|
updated_at = NOW(),
|
|
44
53
|
updater_id = $2
|
|
45
54
|
FROM (
|
|
46
|
-
SELECT ws.id
|
|
55
|
+
SELECT ws.id
|
|
47
56
|
FROM worksheets ws
|
|
48
57
|
INNER JOIN release_goods rg ON rg.id = ws.release_good_id
|
|
49
58
|
INNER JOIN worksheet_details wsd ON wsd.worksheet_id = ws.id
|
|
50
|
-
WHERE ws.domain_id = $1
|
|
59
|
+
WHERE ws.domain_id = $1
|
|
51
60
|
AND ws.type = 'LOADING'
|
|
52
61
|
AND ws.status IN ('EXECUTING', 'DEACTIVATED')
|
|
53
62
|
AND ws.sorter_id IS NULL
|
|
54
63
|
AND rg.status IN ('LOADING', 'PROCESSING', 'PARTIAL_PROCESSING')
|
|
55
64
|
AND wsd.status NOT IN ('DONE', 'DEACTIVATED')
|
|
56
65
|
AND (rg.sorted_by_id = $2 OR rg.sorted_by_id IS NULL)
|
|
57
|
-
ORDER BY rg.created_at
|
|
66
|
+
ORDER BY rg.created_at
|
|
58
67
|
LIMIT 1
|
|
59
|
-
|
|
68
|
+
FOR UPDATE OF ws SKIP LOCKED
|
|
69
|
+
) src
|
|
60
70
|
WHERE src.id = ws.id
|
|
61
71
|
RETURNING ws.id
|
|
62
72
|
`,
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { EntityManager } from 'typeorm'
|
|
2
|
+
|
|
3
|
+
import { Setting } from '@things-factory/setting-base'
|
|
4
|
+
import { Domain } from '@things-factory/shell'
|
|
5
|
+
import { Inventory, Location, INVENTORY_STATUS, LOCATION_STATUS, calcVolumeInM3, buildProductDetailLabel } from '@things-factory/warehouse-base'
|
|
6
|
+
|
|
7
|
+
export const checkTransferLocationRecommendation = {
|
|
8
|
+
async checkTransferLocationRecommendation(
|
|
9
|
+
_: any,
|
|
10
|
+
{ originPalletId, toLocationName, qty }: { originPalletId: string; toLocationName: string; qty: number },
|
|
11
|
+
context: any
|
|
12
|
+
): Promise<{ warningMessage: string | null }> {
|
|
13
|
+
const { domain, tx }: { domain: Domain; tx: EntityManager } = context.state
|
|
14
|
+
|
|
15
|
+
const levelSetting: Setting = await tx
|
|
16
|
+
.getRepository(Setting)
|
|
17
|
+
.findOne({ where: { domain, name: 'location-recommendation-level' } })
|
|
18
|
+
|
|
19
|
+
const level = levelSetting?.value?.toUpperCase().trim()
|
|
20
|
+
if (!level) return { warningMessage: null }
|
|
21
|
+
|
|
22
|
+
const inventory: Inventory = await tx
|
|
23
|
+
.getRepository(Inventory)
|
|
24
|
+
.createQueryBuilder('inv')
|
|
25
|
+
.innerJoinAndSelect('inv.product', 'product')
|
|
26
|
+
.leftJoinAndSelect('inv.productDetail', 'productDetail')
|
|
27
|
+
.where('inv.domain_id = :domainId', { domainId: domain.id })
|
|
28
|
+
.andWhere('inv.pallet_id = :palletId', { palletId: originPalletId })
|
|
29
|
+
.getOne()
|
|
30
|
+
if (!inventory) return { warningMessage: null } // Return silently. Actual transfer location process will only prompt error
|
|
31
|
+
|
|
32
|
+
const toLocation: Location = await tx.getRepository(Location).findOne({ where: { domain, name: toLocationName } })
|
|
33
|
+
if (!toLocation) return { warningMessage: null } // Return silently. Actual transfer location process will only prompt error
|
|
34
|
+
|
|
35
|
+
const inventoriesAtLocation: Inventory[] = await tx
|
|
36
|
+
.getRepository(Inventory)
|
|
37
|
+
.createQueryBuilder('inv')
|
|
38
|
+
.innerJoinAndSelect('inv.product', 'product')
|
|
39
|
+
.leftJoinAndSelect('inv.productDetail', 'productDetail')
|
|
40
|
+
.where('inv.domain_id = :domainId', { domainId: domain.id })
|
|
41
|
+
.andWhere('inv.location_id = :locationId', { locationId: toLocation.id })
|
|
42
|
+
.andWhere('inv.status = :status', { status: INVENTORY_STATUS.STORED })
|
|
43
|
+
.getMany()
|
|
44
|
+
|
|
45
|
+
switch (level) {
|
|
46
|
+
case 'LEVEL 1': {
|
|
47
|
+
if (toLocation.status?.toUpperCase() !== LOCATION_STATUS.EMPTY) {
|
|
48
|
+
return { warningMessage: 'reminder_location_assigned_to_another_sku' }
|
|
49
|
+
}
|
|
50
|
+
break
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
case 'LEVEL 2': {
|
|
54
|
+
const fromSku = inventory.product?.sku
|
|
55
|
+
const hasDifferentSku = inventoriesAtLocation.some(inv => inv.product?.sku !== fromSku)
|
|
56
|
+
if (hasDifferentSku) {
|
|
57
|
+
return { warningMessage: 'reminder_location_assigned_to_another_sku' }
|
|
58
|
+
}
|
|
59
|
+
break
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
case 'LEVEL 3': {
|
|
63
|
+
const fromSku = inventory.product?.sku
|
|
64
|
+
const hasDifferentSku = inventoriesAtLocation.some(inv => inv.product?.sku !== fromSku)
|
|
65
|
+
|
|
66
|
+
const stackingSetting: Setting = await tx.getRepository(Setting).findOne({ where: { domain, name: 'stacking-option-limit' } })
|
|
67
|
+
|
|
68
|
+
let maxLimit = 1
|
|
69
|
+
if (stackingSetting?.value) {
|
|
70
|
+
try {
|
|
71
|
+
const parsed = JSON.parse(stackingSetting.value)
|
|
72
|
+
maxLimit = Number(parsed.Max) || 1
|
|
73
|
+
} catch {
|
|
74
|
+
// ignore malformed setting
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const stackingLimit = inventory.product?.allowStackingOption ? maxLimit : null
|
|
79
|
+
const hitStackingLimit = stackingLimit != null && inventoriesAtLocation.length >= stackingLimit
|
|
80
|
+
|
|
81
|
+
if (hasDifferentSku || hitStackingLimit) {
|
|
82
|
+
return { warningMessage: 'reminder_location_occupied_by_different_sku_or_stacking_capacity' }
|
|
83
|
+
}
|
|
84
|
+
break
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
case 'LEVEL 4': {
|
|
88
|
+
if (!toLocation.volume) return { warningMessage: 'location_missing_volume' }
|
|
89
|
+
|
|
90
|
+
// Check selected inventory's product
|
|
91
|
+
const incomingPd = inventory.productDetail
|
|
92
|
+
const incomingInvalid =
|
|
93
|
+
!incomingPd?.lengthUnit ||
|
|
94
|
+
(incomingPd?.volume == null && (!incomingPd?.width || !incomingPd?.depth || !incomingPd?.height))
|
|
95
|
+
if (incomingInvalid) return { warningMessage: 'incoming_inventory_missing_product_dimensions' }
|
|
96
|
+
|
|
97
|
+
// Check products stored in the targeted destination location
|
|
98
|
+
const existingInvalid = inventoriesAtLocation.some(inv => {
|
|
99
|
+
const pd = inv.productDetail
|
|
100
|
+
return !pd?.lengthUnit || (pd?.volume == null && (!pd?.width || !pd?.depth || !pd?.height))
|
|
101
|
+
})
|
|
102
|
+
if (existingInvalid) return { warningMessage: 'existing_inventory_missing_product_dimensions' }
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
const locationVolume = toLocation.volume
|
|
106
|
+
const existingVolume = inventoriesAtLocation.reduce((sum, inv) => {
|
|
107
|
+
const pd = inv.productDetail
|
|
108
|
+
const detail = buildProductDetailLabel(pd)
|
|
109
|
+
const label = `SKU: ${inv.product?.sku} ${detail}`.trim()
|
|
110
|
+
return sum + calcVolumeInM3(pd, label) * (inv.qty ?? 0)
|
|
111
|
+
}, 0)
|
|
112
|
+
|
|
113
|
+
const incomingDetail = buildProductDetailLabel(incomingPd)
|
|
114
|
+
const incomingLabel = `SKU: ${inventory.product?.sku} ${incomingDetail}`.trim()
|
|
115
|
+
if (existingVolume + calcVolumeInM3(incomingPd, incomingLabel) * qty > locationVolume) return { warningMessage: 'volume_over_location_capacity' }
|
|
116
|
+
break
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return { warningMessage: null }
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
@@ -41,20 +41,35 @@ export const getZonePickingTask = {
|
|
|
41
41
|
|
|
42
42
|
if (!worksheet) {
|
|
43
43
|
//find a worksheet and update assignee to user
|
|
44
|
+
// Claim a single oldest unassigned worksheet. The LIMIT 1 + FOR UPDATE
|
|
45
|
+
// SKIP LOCKED inside the subquery makes this safe under concurrent clicks:
|
|
46
|
+
// - LIMIT 1 prevents bulk-claiming every unassigned worksheet for one user
|
|
47
|
+
// (the previous version assigned ALL of them to the clicker and only
|
|
48
|
+
// returned x[0], silently mis-assigning the rest to whoever clicked first).
|
|
49
|
+
// - FOR UPDATE SKIP LOCKED makes concurrent callers pick different rows
|
|
50
|
+
// instead of waiting on each other and then failing with "no suitable
|
|
51
|
+
// worksheet found" because the first user already grabbed everything.
|
|
52
|
+
//
|
|
53
|
+
// Use an independent inner transaction (not the outer `tx`) so the UPDATE
|
|
54
|
+
// commits before the surrounding resolver transaction finishes. Otherwise
|
|
55
|
+
// the row lock acquired by the UPDATE would persist for the whole resolver,
|
|
56
|
+
// defeating SKIP LOCKED for any concurrent click that arrives mid-flight.
|
|
44
57
|
let updatedWorksheets = await getConnection().transaction(async (tx2: EntityManager) => {
|
|
45
58
|
let x = await tx2.getRepository(Worksheet).query(
|
|
46
59
|
`
|
|
47
|
-
UPDATE worksheets ws SET
|
|
60
|
+
UPDATE worksheets ws SET
|
|
48
61
|
assignee_id = $2,
|
|
49
62
|
updated_at = NOW(),
|
|
50
63
|
updater_id = $2
|
|
51
64
|
FROM (
|
|
52
|
-
SELECT ws.id
|
|
65
|
+
SELECT ws.id FROM worksheets ws
|
|
53
66
|
WHERE ws.domain_id = $1
|
|
54
67
|
AND ws.type = 'ZONE_PICKING'
|
|
55
68
|
AND ws.status IN ('EXECUTING', 'DEACTIVATED')
|
|
56
69
|
AND ws.assignee_id IS NULL
|
|
57
70
|
ORDER BY ws.created_at
|
|
71
|
+
LIMIT 1
|
|
72
|
+
FOR UPDATE SKIP LOCKED
|
|
58
73
|
) src where src.id = ws.id
|
|
59
74
|
RETURNING ws.id;
|
|
60
75
|
`,
|