@things-factory/worksheet-base 4.3.755 → 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/graphql/resolvers/worksheet/find-sorting-release-orders-by-task-no.js +243 -156
- package/dist-server/graphql/resolvers/worksheet/find-sorting-release-orders-by-task-no.js.map +1 -1
- package/package.json +2 -2
- package/server/graphql/resolvers/worksheet/find-sorting-release-orders-by-task-no.ts +303 -172
|
@@ -1,179 +1,266 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.findSortingReleaseOrdersByTaskNoResolver = void 0;
|
|
4
|
-
const typeorm_1 = require("typeorm");
|
|
5
4
|
const sales_base_1 = require("@things-factory/sales-base");
|
|
6
|
-
const shell_1 = require("@things-factory/shell");
|
|
7
5
|
const auth_base_1 = require("@things-factory/auth-base");
|
|
8
|
-
const warehouse_base_1 = require("@things-factory/warehouse-base");
|
|
9
6
|
const controllers_1 = require("../../../controllers/");
|
|
10
7
|
const setting_base_1 = require("@things-factory/setting-base");
|
|
11
8
|
const constants_1 = require("../../../constants");
|
|
12
9
|
const entities_1 = require("../../../entities");
|
|
10
|
+
// Simple in-memory cache for settings with TTL
|
|
11
|
+
const settingsCache = new Map();
|
|
12
|
+
const SETTINGS_CACHE_TTL = 5 * 60 * 1000; // 5 minutes
|
|
13
|
+
/**
|
|
14
|
+
* Get setting with caching to avoid repeated database queries
|
|
15
|
+
*/
|
|
16
|
+
async function getCachedSetting(tx, domain, category, name) {
|
|
17
|
+
const cacheKey = `${domain.id}:${category}:${name}`;
|
|
18
|
+
const cached = settingsCache.get(cacheKey);
|
|
19
|
+
if (cached && cached.expiry > Date.now()) {
|
|
20
|
+
return cached.value;
|
|
21
|
+
}
|
|
22
|
+
const setting = await tx.getRepository(setting_base_1.Setting).findOne({
|
|
23
|
+
where: { domain, category, name }
|
|
24
|
+
});
|
|
25
|
+
settingsCache.set(cacheKey, { value: setting || null, expiry: Date.now() + SETTINGS_CACHE_TTL });
|
|
26
|
+
return setting || null;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Find worksheet by release good name - returns task info if found
|
|
30
|
+
*/
|
|
31
|
+
async function findWorksheetByReleaseGoodName(tx, domain, taskNo) {
|
|
32
|
+
const result = await tx
|
|
33
|
+
.getRepository(entities_1.Worksheet)
|
|
34
|
+
.createQueryBuilder('ws')
|
|
35
|
+
.select('ws.task_no', 'taskNo')
|
|
36
|
+
.addSelect('ws.status', 'wsStatus')
|
|
37
|
+
.addSelect('rg.name', 'releaseGoodName')
|
|
38
|
+
.addSelect('rg.status', 'releaseGoodStatus')
|
|
39
|
+
.innerJoin('worksheet_details', 'wd', `ws.id = wd.worksheet_id`)
|
|
40
|
+
.innerJoin('order_inventories', 'oi', `wd.target_inventory_id = oi.id AND wd."type" = 'SORTING'`)
|
|
41
|
+
.innerJoin('release_goods', 'rg', `rg.id = oi.release_good_id`)
|
|
42
|
+
.where('rg.domain_id = :domainId', { domainId: domain.id })
|
|
43
|
+
.andWhere('rg.name = :name', { name: taskNo })
|
|
44
|
+
.andWhere('rg.status IN (:...statuses)', {
|
|
45
|
+
statuses: [sales_base_1.ORDER_STATUS.READY_TO_SORT, sales_base_1.ORDER_STATUS.SORTING, sales_base_1.ORDER_STATUS.LOADING, sales_base_1.ORDER_STATUS.DONE]
|
|
46
|
+
})
|
|
47
|
+
.andWhere('ws.type = :type', { type: constants_1.WORKSHEET_TYPE.SORTING })
|
|
48
|
+
.getRawOne();
|
|
49
|
+
if (!result)
|
|
50
|
+
return null;
|
|
51
|
+
if (result.releaseGoodStatus === 'LOADING' || result.releaseGoodStatus === 'DONE') {
|
|
52
|
+
throw new Error(`Release Good already sorted`);
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
taskNo: result.taskNo,
|
|
56
|
+
selectedReleaseGood: result.releaseGoodName,
|
|
57
|
+
status: result.wsStatus
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Find worksheet by taskNo directly - optimized to only load needed relations
|
|
62
|
+
*/
|
|
63
|
+
async function findWorksheetByTaskNo(tx, domain, taskNo, loadWorksheetDetails = false) {
|
|
64
|
+
const relations = loadWorksheetDetails ? ['bizplace', 'bizplace.domain', 'worksheetDetails'] : ['bizplace', 'bizplace.domain'];
|
|
65
|
+
return tx.getRepository(entities_1.Worksheet).findOne({
|
|
66
|
+
where: { taskNo, type: constants_1.WORKSHEET_TYPE.SORTING, domain },
|
|
67
|
+
relations
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Find worksheet by bin location - combines location lookup and worksheet query
|
|
72
|
+
* Returns both taskNo and worksheet status in a single optimized query
|
|
73
|
+
*/
|
|
74
|
+
async function findWorksheetByBinLocation(tx, domain, binName) {
|
|
75
|
+
// Combined query: location -> order inventory -> worksheet in one go
|
|
76
|
+
const result = await tx
|
|
77
|
+
.getRepository(sales_base_1.OrderInventory)
|
|
78
|
+
.createQueryBuilder('oi')
|
|
79
|
+
.select('ws2.task_no', 'taskNo')
|
|
80
|
+
.addSelect('ws2.id', 'worksheetId')
|
|
81
|
+
.addSelect('ws2.status', 'status')
|
|
82
|
+
.innerJoin('locations', 'loc', 'oi.bin_location_id = loc.id')
|
|
83
|
+
.innerJoin('worksheets', 'ws', `oi.ref_worksheet_id = ws.id AND ws.type = 'BATCH_PICKING'`)
|
|
84
|
+
.innerJoin('worksheets', 'ws2', `ws2.task_no = ws.task_no AND ws2.type = 'SORTING'`)
|
|
85
|
+
.innerJoin('release_goods', 'rg', 'rg.id = oi.release_good_id')
|
|
86
|
+
.where('oi.domain_id = :domainId', { domainId: domain.id })
|
|
87
|
+
.andWhere('loc.domain_id = :domainId', { domainId: domain.id })
|
|
88
|
+
.andWhere('loc.name = :binName', { binName })
|
|
89
|
+
.andWhere('oi.status IN (:...orderInventoryStatus)', {
|
|
90
|
+
orderInventoryStatus: [sales_base_1.ORDER_INVENTORY_STATUS.READY_TO_SORT, sales_base_1.ORDER_INVENTORY_STATUS.SORTING]
|
|
91
|
+
})
|
|
92
|
+
.andWhere('rg.status IN (:...statuses)', {
|
|
93
|
+
statuses: [sales_base_1.ORDER_STATUS.READY_TO_SORT, sales_base_1.ORDER_STATUS.SORTING]
|
|
94
|
+
})
|
|
95
|
+
.andWhere('ws2.status IN (:...worksheetStatuses)', {
|
|
96
|
+
worksheetStatuses: [constants_1.WORKSHEET_STATUS.DEACTIVATED, constants_1.WORKSHEET_STATUS.EXECUTING]
|
|
97
|
+
})
|
|
98
|
+
.getRawOne();
|
|
99
|
+
if (!result) {
|
|
100
|
+
throw new Error(`Bin do not have any batch picking order.`);
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
taskNo: result.taskNo,
|
|
104
|
+
worksheetId: result.worksheetId,
|
|
105
|
+
status: result.status
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Handle worksheet activation if needed
|
|
110
|
+
*/
|
|
111
|
+
async function handleWorksheetActivation(tx, domain, user, task) {
|
|
112
|
+
var _a, _b, _c;
|
|
113
|
+
if (task.status !== 'DEACTIVATED')
|
|
114
|
+
return;
|
|
115
|
+
const sortingWSCtrl = new controllers_1.SortingWorksheetController(tx, domain, user);
|
|
116
|
+
// Use cached settings
|
|
117
|
+
const directActivateSetting = await getCachedSetting(tx, domain, 'id-rule', 'enable-direct-activate-sorting-worksheet');
|
|
118
|
+
if (!directActivateSetting || ((_a = directActivateSetting.value) === null || _a === void 0 ? void 0 : _a.toLowerCase()) !== 'true') {
|
|
119
|
+
throw new Error('Kindly go to sorting worksheet page to activate the sorting worksheet');
|
|
120
|
+
}
|
|
121
|
+
// Only fetch partner setting if main setting is enabled
|
|
122
|
+
const partnerSetting = await tx.getRepository(setting_base_1.PartnerSetting).findOne({
|
|
123
|
+
where: {
|
|
124
|
+
setting: directActivateSetting,
|
|
125
|
+
domain: domain,
|
|
126
|
+
partnerDomain: (_b = task.bizplace) === null || _b === void 0 ? void 0 : _b.domain
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
// If partner setting exists and is false, don't activate
|
|
130
|
+
if (partnerSetting && ((_c = partnerSetting.value) === null || _c === void 0 ? void 0 : _c.toLowerCase()) !== 'true') {
|
|
131
|
+
throw new Error('Kindly go to sorting worksheet page to activate the sorting worksheet');
|
|
132
|
+
}
|
|
133
|
+
// Load worksheet details only when needed for activation
|
|
134
|
+
if (!task.worksheetDetails) {
|
|
135
|
+
const taskWithDetails = await tx.getRepository(entities_1.Worksheet).findOne({
|
|
136
|
+
where: { id: task.id },
|
|
137
|
+
relations: ['worksheetDetails']
|
|
138
|
+
});
|
|
139
|
+
task.worksheetDetails = (taskWithDetails === null || taskWithDetails === void 0 ? void 0 : taskWithDetails.worksheetDetails) || [];
|
|
140
|
+
}
|
|
141
|
+
await sortingWSCtrl.activateSorting(task.name, task.worksheetDetails);
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Build and execute release goods query with item counts in a SINGLE query
|
|
145
|
+
* Optimizations:
|
|
146
|
+
* - Removed redundant Domain join (filter directly on ws.domain_id)
|
|
147
|
+
* - Combined release goods + counts into one query using aggregate functions
|
|
148
|
+
*/
|
|
149
|
+
async function getReleaseGoodsWithCounts(tx, domain, taskNo) {
|
|
150
|
+
// Single query that gets release goods with their counts using aggregation
|
|
151
|
+
const releaseGoods = await tx
|
|
152
|
+
.getRepository(entities_1.Worksheet)
|
|
153
|
+
.createQueryBuilder('ws')
|
|
154
|
+
.select('rg.id', 'id')
|
|
155
|
+
.addSelect('rg.name', 'name')
|
|
156
|
+
.addSelect('rg.refNo', 'refNo')
|
|
157
|
+
.addSelect('rg.refNo2', 'refNo2')
|
|
158
|
+
.addSelect('rg.status', 'status')
|
|
159
|
+
.addSelect('rg.district', 'district')
|
|
160
|
+
.addSelect('rg.attention_company', 'attentionCompany')
|
|
161
|
+
.addSelect('rg.delivery_address_1', 'deliveryAddress1')
|
|
162
|
+
.addSelect('rg.delivery_address_2', 'deliveryAddress2')
|
|
163
|
+
.addSelect('rg.delivery_address_3', 'deliveryAddress3')
|
|
164
|
+
.addSelect('rg.delivery_address_4', 'deliveryAddress4')
|
|
165
|
+
.addSelect('rg.delivery_address_5', 'deliveryAddress5')
|
|
166
|
+
.addSelect('rg.created_at', 'createdAt')
|
|
167
|
+
.addSelect('u.name', 'sortedByUser')
|
|
168
|
+
// Counts computed directly in the same query
|
|
169
|
+
.addSelect('COUNT(oi.id)', 'totalCount')
|
|
170
|
+
.addSelect('SUM(CASE WHEN oi.sorted_qty = oi.release_qty THEN 1 ELSE 0 END)', 'completedCount')
|
|
171
|
+
.innerJoin(entities_1.WorksheetDetail, 'wsd', 'ws.id = wsd.worksheet_id')
|
|
172
|
+
.innerJoin(sales_base_1.OrderInventory, 'oi', 'oi.id = wsd.target_inventory_id')
|
|
173
|
+
.innerJoin(sales_base_1.ReleaseGood, 'rg', 'rg.id = oi.release_good_id')
|
|
174
|
+
.leftJoin(auth_base_1.User, 'u', 'rg.sorted_by_id = u.id')
|
|
175
|
+
// Filter directly on ws.domain_id - no need to join Domain table
|
|
176
|
+
.where('ws.domain_id = :domainId', { domainId: domain.id })
|
|
177
|
+
.andWhere('ws.taskNo = :taskNo', { taskNo })
|
|
178
|
+
.andWhere('ws.type = :worksheetType', { worksheetType: constants_1.WORKSHEET_TYPE.SORTING })
|
|
179
|
+
.andWhere('ws.status = :worksheetStatus', { worksheetStatus: constants_1.WORKSHEET_STATUS.EXECUTING })
|
|
180
|
+
.groupBy('rg.id')
|
|
181
|
+
.addGroupBy('rg.name')
|
|
182
|
+
.addGroupBy('rg.refNo')
|
|
183
|
+
.addGroupBy('rg.refNo2')
|
|
184
|
+
.addGroupBy('rg.status')
|
|
185
|
+
.addGroupBy('rg.district')
|
|
186
|
+
.addGroupBy('rg.attention_company')
|
|
187
|
+
.addGroupBy('rg.delivery_address_1')
|
|
188
|
+
.addGroupBy('rg.delivery_address_2')
|
|
189
|
+
.addGroupBy('rg.delivery_address_3')
|
|
190
|
+
.addGroupBy('rg.delivery_address_4')
|
|
191
|
+
.addGroupBy('rg.delivery_address_5')
|
|
192
|
+
.addGroupBy('rg.created_at')
|
|
193
|
+
.addGroupBy('u.name')
|
|
194
|
+
.orderBy('rg.created_at', 'ASC')
|
|
195
|
+
.getRawMany();
|
|
196
|
+
// Transform results to include itemCounts
|
|
197
|
+
return releaseGoods.map(rg => {
|
|
198
|
+
const total = parseInt(rg.totalCount) || 0;
|
|
199
|
+
const completed = parseInt(rg.completedCount) || 0;
|
|
200
|
+
return {
|
|
201
|
+
id: rg.id,
|
|
202
|
+
name: rg.name,
|
|
203
|
+
refNo: rg.refNo,
|
|
204
|
+
refNo2: rg.refNo2,
|
|
205
|
+
status: rg.status,
|
|
206
|
+
district: rg.district,
|
|
207
|
+
attentionCompany: rg.attentionCompany,
|
|
208
|
+
deliveryAddress1: rg.deliveryAddress1,
|
|
209
|
+
deliveryAddress2: rg.deliveryAddress2,
|
|
210
|
+
deliveryAddress3: rg.deliveryAddress3,
|
|
211
|
+
deliveryAddress4: rg.deliveryAddress4,
|
|
212
|
+
deliveryAddress5: rg.deliveryAddress5,
|
|
213
|
+
sortedByUser: rg.sortedByUser,
|
|
214
|
+
itemCounts: {
|
|
215
|
+
total,
|
|
216
|
+
pending: total - completed
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
});
|
|
220
|
+
}
|
|
13
221
|
exports.findSortingReleaseOrdersByTaskNoResolver = {
|
|
14
222
|
async findSortingReleaseOrdersByTaskNo(_, { taskNo }, context) {
|
|
15
|
-
|
|
223
|
+
const startTime = Date.now();
|
|
16
224
|
const { domain, tx, user } = context.state;
|
|
17
225
|
let selectedReleaseGood = null;
|
|
18
|
-
let
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
.andWhere('rg.status IN (:...statuses)', {
|
|
29
|
-
statuses: [sales_base_1.ORDER_STATUS.READY_TO_SORT, sales_base_1.ORDER_STATUS.SORTING, sales_base_1.ORDER_STATUS.LOADING, sales_base_1.ORDER_STATUS.DONE]
|
|
30
|
-
})
|
|
31
|
-
.andWhere('ws.type = :type', { type: constants_1.WORKSHEET_TYPE.SORTING })
|
|
32
|
-
.getRawOne();
|
|
33
|
-
if (ws) {
|
|
34
|
-
if (ws.release_good_status == 'LOADING' || ws.release_good_status == 'DONE') {
|
|
35
|
-
throw new Error(`Release Good already sorted`);
|
|
36
|
-
}
|
|
37
|
-
selectedReleaseGood = ws.release_good_name;
|
|
38
|
-
taskNo = ws.ws_task_no;
|
|
226
|
+
let task = null;
|
|
227
|
+
let resolvedTaskNo = taskNo;
|
|
228
|
+
// Step 1: Try to find by release good name first (most common case)
|
|
229
|
+
const releaseGoodResult = await findWorksheetByReleaseGoodName(tx, domain, taskNo);
|
|
230
|
+
if (releaseGoodResult) {
|
|
231
|
+
selectedReleaseGood = releaseGoodResult.selectedReleaseGood;
|
|
232
|
+
resolvedTaskNo = releaseGoodResult.taskNo;
|
|
233
|
+
// Only load worksheetDetails if we need them for activation
|
|
234
|
+
const needsActivation = releaseGoodResult.status === 'DEACTIVATED';
|
|
235
|
+
task = await findWorksheetByTaskNo(tx, domain, resolvedTaskNo, needsActivation);
|
|
39
236
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
//
|
|
237
|
+
// Step 2: Try to find by worksheet taskNo directly
|
|
238
|
+
if (!task) {
|
|
239
|
+
task = await findWorksheetByTaskNo(tx, domain, taskNo, false);
|
|
240
|
+
}
|
|
241
|
+
// Step 3: Try to find by bin location
|
|
45
242
|
if (!task) {
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
.createQueryBuilder('orderInventory');
|
|
53
|
-
qb.innerJoinAndSelect('orderInventory.releaseGood', 'releaseGood')
|
|
54
|
-
.innerJoinAndSelect('worksheets', 'ws', `orderInventory.ref_worksheet_id = ws.id AND ws.type = 'BATCH_PICKING'`)
|
|
55
|
-
.innerJoinAndSelect('worksheets', 'ws2', `ws2.task_no = ws.task_no AND ws2.type = 'SORTING'`)
|
|
56
|
-
.innerJoinAndSelect('releaseGood.bizplace', 'bizplace')
|
|
57
|
-
.innerJoinAndSelect('bizplace.domain', 'domain')
|
|
58
|
-
.where('orderInventory.domain_id = :domainId', { domainId: domain.id })
|
|
59
|
-
.andWhere('orderInventory.status IN (:...orderInventoryStatus)', {
|
|
60
|
-
orderInventoryStatus: [sales_base_1.ORDER_INVENTORY_STATUS.READY_TO_SORT, sales_base_1.ORDER_INVENTORY_STATUS.SORTING]
|
|
61
|
-
})
|
|
62
|
-
.andWhere('orderInventory.bin_location_id = :locationId', { locationId: binLocation.id })
|
|
63
|
-
.andWhere('releaseGood.status IN (:...statuses)', {
|
|
64
|
-
statuses: [sales_base_1.ORDER_STATUS.READY_TO_SORT, sales_base_1.ORDER_STATUS.SORTING]
|
|
65
|
-
});
|
|
66
|
-
const orderInventoryByBin = await qb.getRawOne();
|
|
67
|
-
if (orderInventoryByBin === null || orderInventoryByBin === void 0 ? void 0 : orderInventoryByBin.releaseGood_id) {
|
|
68
|
-
taskNo = orderInventoryByBin.ws_task_no;
|
|
69
|
-
task = await tx.getRepository(entities_1.Worksheet).findOne({
|
|
70
|
-
where: {
|
|
71
|
-
taskNo,
|
|
72
|
-
status: (0, typeorm_1.In)([constants_1.WORKSHEET_STATUS.DEACTIVATED, constants_1.WORKSHEET_STATUS.EXECUTING]),
|
|
73
|
-
type: constants_1.WORKSHEET_TYPE.SORTING,
|
|
74
|
-
domain
|
|
75
|
-
},
|
|
76
|
-
relations: ['worksheetDetails']
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
else {
|
|
80
|
-
throw new Error(`Bin do not have any batch picking order.`);
|
|
81
|
-
}
|
|
243
|
+
const binResult = await findWorksheetByBinLocation(tx, domain, taskNo);
|
|
244
|
+
if (binResult) {
|
|
245
|
+
resolvedTaskNo = binResult.taskNo;
|
|
246
|
+
// Only load worksheetDetails if we need them for activation
|
|
247
|
+
const needsActivation = binResult.status === 'DEACTIVATED';
|
|
248
|
+
task = await findWorksheetByTaskNo(tx, domain, resolvedTaskNo, needsActivation);
|
|
82
249
|
}
|
|
83
250
|
}
|
|
84
|
-
if (!task)
|
|
251
|
+
if (!task) {
|
|
85
252
|
throw new Error('Unable to find task no.');
|
|
86
|
-
if (task.status === 'DEACTIVATED') {
|
|
87
|
-
const sortingWSCtrl = new controllers_1.SortingWorksheetController(tx, domain, user);
|
|
88
|
-
const directActivateSortingWorksheet = await tx.getRepository(setting_base_1.Setting).findOne({
|
|
89
|
-
where: { domain: domain, category: 'id-rule', name: 'enable-direct-activate-sorting-worksheet' }
|
|
90
|
-
});
|
|
91
|
-
const partnerDirectActivateSortingWorksheetSetting = await tx
|
|
92
|
-
.getRepository(setting_base_1.PartnerSetting)
|
|
93
|
-
.findOne({
|
|
94
|
-
where: {
|
|
95
|
-
setting: directActivateSortingWorksheet,
|
|
96
|
-
domain: domain,
|
|
97
|
-
partnerDomain: (_a = task.bizplace) === null || _a === void 0 ? void 0 : _a.domain
|
|
98
|
-
}
|
|
99
|
-
});
|
|
100
|
-
if (directActivateSortingWorksheet != undefined && directActivateSortingWorksheet.value.toLowerCase() == 'true') {
|
|
101
|
-
if (partnerDirectActivateSortingWorksheetSetting != undefined) {
|
|
102
|
-
if (partnerDirectActivateSortingWorksheetSetting.value.toLowerCase() == 'true')
|
|
103
|
-
await sortingWSCtrl.activateSorting(task.name, task.worksheetDetails);
|
|
104
|
-
}
|
|
105
|
-
else {
|
|
106
|
-
await sortingWSCtrl.activateSorting(task.name, task.worksheetDetails);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
else {
|
|
110
|
-
throw new Error('Kindly go to sorting worksheet page to activate the sorting worksheet');
|
|
111
|
-
}
|
|
112
253
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
.
|
|
121
|
-
.addSelect('rg.district as "district"')
|
|
122
|
-
.addSelect('rg.attention_company as "attentionCompany"')
|
|
123
|
-
.addSelect('rg.delivery_address_1 as "deliveryAddress1"')
|
|
124
|
-
.addSelect('rg.delivery_address_2 as "deliveryAddress2"')
|
|
125
|
-
.addSelect('rg.delivery_address_3 as "deliveryAddress3"')
|
|
126
|
-
.addSelect('rg.delivery_address_4 as "deliveryAddress4"')
|
|
127
|
-
.addSelect('rg.delivery_address_5 as "deliveryAddress5"')
|
|
128
|
-
.addSelect('user.name as "sortedByUser"')
|
|
129
|
-
.innerJoin(shell_1.Domain, 'domain', 'ws.domain_id = domain.id')
|
|
130
|
-
.innerJoin(entities_1.WorksheetDetail, 'wsd', 'ws.id = wsd.worksheet_id')
|
|
131
|
-
.innerJoin(sales_base_1.OrderInventory, 'oi', 'oi.id = wsd.target_inventory_id')
|
|
132
|
-
.innerJoin(sales_base_1.ReleaseGood, 'rg', 'rg.id = oi.release_good_id')
|
|
133
|
-
.leftJoin(auth_base_1.User, 'user', 'rg.sorted_by_id = user.id')
|
|
134
|
-
.where('domain.id = :domainId', { domainId: domain.id })
|
|
135
|
-
.andWhere('ws.taskNo = :taskNo', { taskNo: taskNo })
|
|
136
|
-
.andWhere('ws.type = :worksheetType', { worksheetType: constants_1.WORKSHEET_TYPE.SORTING })
|
|
137
|
-
.andWhere('ws.status = :worksheetStatus', { worksheetStatus: constants_1.WORKSHEET_STATUS.EXECUTING })
|
|
138
|
-
.groupBy('rg.id')
|
|
139
|
-
.addGroupBy('rg.name')
|
|
140
|
-
.addGroupBy('rg.status')
|
|
141
|
-
.addGroupBy('user.name')
|
|
142
|
-
.orderBy('rg.createdAt', 'ASC');
|
|
143
|
-
const releaseGoods = await qb.getRawMany();
|
|
144
|
-
if (releaseGoods.length > 0) {
|
|
145
|
-
// Get counts for all release goods in a single query (avoids N+1 problem)
|
|
146
|
-
const releaseGoodIds = releaseGoods.map(rg => rg.id);
|
|
147
|
-
const countsResult = await tx
|
|
148
|
-
.getRepository(sales_base_1.OrderInventory)
|
|
149
|
-
.createQueryBuilder('orderInventory')
|
|
150
|
-
.innerJoin(entities_1.WorksheetDetail, 'wsd', 'orderInventory.id = wsd.target_inventory_id')
|
|
151
|
-
.innerJoin(entities_1.Worksheet, 'ws', 'wsd.worksheet_id = ws.id')
|
|
152
|
-
.select('orderInventory.release_good_id', 'releaseGoodId')
|
|
153
|
-
.addSelect('COUNT(*)', 'total')
|
|
154
|
-
.addSelect('SUM(CASE WHEN orderInventory.sortedQty = orderInventory.releaseQty THEN 1 ELSE 0 END)', 'completed')
|
|
155
|
-
.where('orderInventory.release_good_id IN (:...releaseGoodIds)', { releaseGoodIds })
|
|
156
|
-
.andWhere('orderInventory.domain_id = :domainId', { domainId: domain.id })
|
|
157
|
-
.andWhere('ws.taskNo = :taskNo', { taskNo: taskNo })
|
|
158
|
-
.andWhere('ws.type = :worksheetType', { worksheetType: constants_1.WORKSHEET_TYPE.SORTING })
|
|
159
|
-
.andWhere('ws.status = :worksheetStatus', { worksheetStatus: constants_1.WORKSHEET_STATUS.EXECUTING })
|
|
160
|
-
.groupBy('orderInventory.release_good_id')
|
|
161
|
-
.getRawMany();
|
|
162
|
-
// Build a map for quick lookup
|
|
163
|
-
const countsById = new Map(countsResult.map(c => [
|
|
164
|
-
c.releaseGoodId,
|
|
165
|
-
{ total: parseInt(c.total) || 0, completed: parseInt(c.completed) || 0 }
|
|
166
|
-
]));
|
|
167
|
-
// Assign itemCounts to each release good
|
|
168
|
-
for (const releaseGood of releaseGoods) {
|
|
169
|
-
const counts = countsById.get(releaseGood.id) || { total: 0, completed: 0 };
|
|
170
|
-
releaseGood['itemCounts'] = {
|
|
171
|
-
total: counts.total,
|
|
172
|
-
pending: counts.total - counts.completed
|
|
173
|
-
};
|
|
174
|
-
}
|
|
254
|
+
// Step 4: Handle activation if needed
|
|
255
|
+
await handleWorksheetActivation(tx, domain, user, task);
|
|
256
|
+
// Step 5: Get release goods with counts
|
|
257
|
+
const releaseGoods = await getReleaseGoodsWithCounts(tx, domain, resolvedTaskNo);
|
|
258
|
+
// Performance logging (only in development/debug mode)
|
|
259
|
+
const elapsed = Date.now() - startTime;
|
|
260
|
+
if (elapsed > 1000) {
|
|
261
|
+
console.warn(`[PERF] findSortingReleaseOrdersByTaskNo took ${elapsed}ms for taskNo: ${taskNo}`);
|
|
175
262
|
}
|
|
176
|
-
return { releaseGoods, taskNo, selectedReleaseGood };
|
|
263
|
+
return { releaseGoods, taskNo: resolvedTaskNo, selectedReleaseGood };
|
|
177
264
|
}
|
|
178
265
|
};
|
|
179
266
|
//# sourceMappingURL=find-sorting-release-orders-by-task-no.js.map
|
package/dist-server/graphql/resolvers/worksheet/find-sorting-release-orders-by-task-no.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"find-sorting-release-orders-by-task-no.js","sourceRoot":"","sources":["../../../../server/graphql/resolvers/worksheet/find-sorting-release-orders-by-task-no.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"find-sorting-release-orders-by-task-no.js","sourceRoot":"","sources":["../../../../server/graphql/resolvers/worksheet/find-sorting-release-orders-by-task-no.ts"],"names":[],"mappings":"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"}
|
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,
|
|
@@ -46,5 +46,5 @@
|
|
|
46
46
|
"puppeteer": "21.0.3",
|
|
47
47
|
"uuid": "^9.0.0"
|
|
48
48
|
},
|
|
49
|
-
"gitHead": "
|
|
49
|
+
"gitHead": "b16ce3a1cde77139646a0812c3b198a854e48a19"
|
|
50
50
|
}
|
|
@@ -8,199 +8,330 @@ import {
|
|
|
8
8
|
} from '@things-factory/sales-base'
|
|
9
9
|
import { Domain } from '@things-factory/shell'
|
|
10
10
|
import { User } from '@things-factory/auth-base'
|
|
11
|
-
import { Location } from '@things-factory/warehouse-base'
|
|
12
11
|
import { SortingWorksheetController } from '../../../controllers/'
|
|
13
12
|
import { PartnerSetting, Setting } from '@things-factory/setting-base'
|
|
14
13
|
|
|
15
14
|
import { WORKSHEET_STATUS, WORKSHEET_TYPE } from '../../../constants'
|
|
16
15
|
import { Worksheet as WorksheetEntity, WorksheetDetail as WorksheetDetailEntity } from '../../../entities'
|
|
17
16
|
|
|
17
|
+
// Simple in-memory cache for settings with TTL
|
|
18
|
+
const settingsCache = new Map<string, { value: Setting | null; expiry: number }>()
|
|
19
|
+
const SETTINGS_CACHE_TTL = 5 * 60 * 1000 // 5 minutes
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Get setting with caching to avoid repeated database queries
|
|
23
|
+
*/
|
|
24
|
+
async function getCachedSetting(
|
|
25
|
+
tx: EntityManager,
|
|
26
|
+
domain: Domain,
|
|
27
|
+
category: string,
|
|
28
|
+
name: string
|
|
29
|
+
): Promise<Setting | null> {
|
|
30
|
+
const cacheKey = `${domain.id}:${category}:${name}`
|
|
31
|
+
const cached = settingsCache.get(cacheKey)
|
|
32
|
+
|
|
33
|
+
if (cached && cached.expiry > Date.now()) {
|
|
34
|
+
return cached.value
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const setting = await tx.getRepository(Setting).findOne({
|
|
38
|
+
where: { domain, category, name }
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
settingsCache.set(cacheKey, { value: setting || null, expiry: Date.now() + SETTINGS_CACHE_TTL })
|
|
42
|
+
return setting || null
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Find worksheet by release good name - returns task info if found
|
|
47
|
+
*/
|
|
48
|
+
async function findWorksheetByReleaseGoodName(
|
|
49
|
+
tx: EntityManager,
|
|
50
|
+
domain: Domain,
|
|
51
|
+
taskNo: string
|
|
52
|
+
): Promise<{ taskNo: string; selectedReleaseGood: string; status: string } | null> {
|
|
53
|
+
const result = await tx
|
|
54
|
+
.getRepository(WorksheetEntity)
|
|
55
|
+
.createQueryBuilder('ws')
|
|
56
|
+
.select('ws.task_no', 'taskNo')
|
|
57
|
+
.addSelect('ws.status', 'wsStatus')
|
|
58
|
+
.addSelect('rg.name', 'releaseGoodName')
|
|
59
|
+
.addSelect('rg.status', 'releaseGoodStatus')
|
|
60
|
+
.innerJoin('worksheet_details', 'wd', `ws.id = wd.worksheet_id`)
|
|
61
|
+
.innerJoin('order_inventories', 'oi', `wd.target_inventory_id = oi.id AND wd."type" = 'SORTING'`)
|
|
62
|
+
.innerJoin('release_goods', 'rg', `rg.id = oi.release_good_id`)
|
|
63
|
+
.where('rg.domain_id = :domainId', { domainId: domain.id })
|
|
64
|
+
.andWhere('rg.name = :name', { name: taskNo })
|
|
65
|
+
.andWhere('rg.status IN (:...statuses)', {
|
|
66
|
+
statuses: [ORDER_STATUS.READY_TO_SORT, ORDER_STATUS.SORTING, ORDER_STATUS.LOADING, ORDER_STATUS.DONE]
|
|
67
|
+
})
|
|
68
|
+
.andWhere('ws.type = :type', { type: WORKSHEET_TYPE.SORTING })
|
|
69
|
+
.getRawOne()
|
|
70
|
+
|
|
71
|
+
if (!result) return null
|
|
72
|
+
|
|
73
|
+
if (result.releaseGoodStatus === 'LOADING' || result.releaseGoodStatus === 'DONE') {
|
|
74
|
+
throw new Error(`Release Good already sorted`)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return {
|
|
78
|
+
taskNo: result.taskNo,
|
|
79
|
+
selectedReleaseGood: result.releaseGoodName,
|
|
80
|
+
status: result.wsStatus
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Find worksheet by taskNo directly - optimized to only load needed relations
|
|
86
|
+
*/
|
|
87
|
+
async function findWorksheetByTaskNo(
|
|
88
|
+
tx: EntityManager,
|
|
89
|
+
domain: Domain,
|
|
90
|
+
taskNo: string,
|
|
91
|
+
loadWorksheetDetails: boolean = false
|
|
92
|
+
): Promise<WorksheetEntity | null> {
|
|
93
|
+
const relations = loadWorksheetDetails ? ['bizplace', 'bizplace.domain', 'worksheetDetails'] : ['bizplace', 'bizplace.domain']
|
|
94
|
+
|
|
95
|
+
return tx.getRepository(WorksheetEntity).findOne({
|
|
96
|
+
where: { taskNo, type: WORKSHEET_TYPE.SORTING, domain },
|
|
97
|
+
relations
|
|
98
|
+
})
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Find worksheet by bin location - combines location lookup and worksheet query
|
|
103
|
+
* Returns both taskNo and worksheet status in a single optimized query
|
|
104
|
+
*/
|
|
105
|
+
async function findWorksheetByBinLocation(
|
|
106
|
+
tx: EntityManager,
|
|
107
|
+
domain: Domain,
|
|
108
|
+
binName: string
|
|
109
|
+
): Promise<{ taskNo: string; worksheetId: string; status: string } | null> {
|
|
110
|
+
// Combined query: location -> order inventory -> worksheet in one go
|
|
111
|
+
const result = await tx
|
|
112
|
+
.getRepository(OrderInventoryEntity)
|
|
113
|
+
.createQueryBuilder('oi')
|
|
114
|
+
.select('ws2.task_no', 'taskNo')
|
|
115
|
+
.addSelect('ws2.id', 'worksheetId')
|
|
116
|
+
.addSelect('ws2.status', 'status')
|
|
117
|
+
.innerJoin('locations', 'loc', 'oi.bin_location_id = loc.id')
|
|
118
|
+
.innerJoin('worksheets', 'ws', `oi.ref_worksheet_id = ws.id AND ws.type = 'BATCH_PICKING'`)
|
|
119
|
+
.innerJoin('worksheets', 'ws2', `ws2.task_no = ws.task_no AND ws2.type = 'SORTING'`)
|
|
120
|
+
.innerJoin('release_goods', 'rg', 'rg.id = oi.release_good_id')
|
|
121
|
+
.where('oi.domain_id = :domainId', { domainId: domain.id })
|
|
122
|
+
.andWhere('loc.domain_id = :domainId', { domainId: domain.id })
|
|
123
|
+
.andWhere('loc.name = :binName', { binName })
|
|
124
|
+
.andWhere('oi.status IN (:...orderInventoryStatus)', {
|
|
125
|
+
orderInventoryStatus: [ORDER_INVENTORY_STATUS.READY_TO_SORT, ORDER_INVENTORY_STATUS.SORTING]
|
|
126
|
+
})
|
|
127
|
+
.andWhere('rg.status IN (:...statuses)', {
|
|
128
|
+
statuses: [ORDER_STATUS.READY_TO_SORT, ORDER_STATUS.SORTING]
|
|
129
|
+
})
|
|
130
|
+
.andWhere('ws2.status IN (:...worksheetStatuses)', {
|
|
131
|
+
worksheetStatuses: [WORKSHEET_STATUS.DEACTIVATED, WORKSHEET_STATUS.EXECUTING]
|
|
132
|
+
})
|
|
133
|
+
.getRawOne()
|
|
134
|
+
|
|
135
|
+
if (!result) {
|
|
136
|
+
throw new Error(`Bin do not have any batch picking order.`)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return {
|
|
140
|
+
taskNo: result.taskNo,
|
|
141
|
+
worksheetId: result.worksheetId,
|
|
142
|
+
status: result.status
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Handle worksheet activation if needed
|
|
148
|
+
*/
|
|
149
|
+
async function handleWorksheetActivation(
|
|
150
|
+
tx: EntityManager,
|
|
151
|
+
domain: Domain,
|
|
152
|
+
user: User,
|
|
153
|
+
task: WorksheetEntity
|
|
154
|
+
): Promise<void> {
|
|
155
|
+
if (task.status !== 'DEACTIVATED') return
|
|
156
|
+
|
|
157
|
+
const sortingWSCtrl = new SortingWorksheetController(tx, domain, user)
|
|
158
|
+
|
|
159
|
+
// Use cached settings
|
|
160
|
+
const directActivateSetting = await getCachedSetting(
|
|
161
|
+
tx,
|
|
162
|
+
domain,
|
|
163
|
+
'id-rule',
|
|
164
|
+
'enable-direct-activate-sorting-worksheet'
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
if (!directActivateSetting || directActivateSetting.value?.toLowerCase() !== 'true') {
|
|
168
|
+
throw new Error('Kindly go to sorting worksheet page to activate the sorting worksheet')
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Only fetch partner setting if main setting is enabled
|
|
172
|
+
const partnerSetting: PartnerSetting | null = await tx.getRepository(PartnerSetting).findOne({
|
|
173
|
+
where: {
|
|
174
|
+
setting: directActivateSetting,
|
|
175
|
+
domain: domain,
|
|
176
|
+
partnerDomain: task.bizplace?.domain
|
|
177
|
+
}
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
// If partner setting exists and is false, don't activate
|
|
181
|
+
if (partnerSetting && (partnerSetting.value as string)?.toLowerCase() !== 'true') {
|
|
182
|
+
throw new Error('Kindly go to sorting worksheet page to activate the sorting worksheet')
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Load worksheet details only when needed for activation
|
|
186
|
+
if (!task.worksheetDetails) {
|
|
187
|
+
const taskWithDetails = await tx.getRepository(WorksheetEntity).findOne({
|
|
188
|
+
where: { id: task.id },
|
|
189
|
+
relations: ['worksheetDetails']
|
|
190
|
+
})
|
|
191
|
+
task.worksheetDetails = taskWithDetails?.worksheetDetails || []
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
await sortingWSCtrl.activateSorting(task.name, task.worksheetDetails)
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Build and execute release goods query with item counts in a SINGLE query
|
|
199
|
+
* Optimizations:
|
|
200
|
+
* - Removed redundant Domain join (filter directly on ws.domain_id)
|
|
201
|
+
* - Combined release goods + counts into one query using aggregate functions
|
|
202
|
+
*/
|
|
203
|
+
async function getReleaseGoodsWithCounts(
|
|
204
|
+
tx: EntityManager,
|
|
205
|
+
domain: Domain,
|
|
206
|
+
taskNo: string
|
|
207
|
+
): Promise<ReleaseGoodEntity[]> {
|
|
208
|
+
// Single query that gets release goods with their counts using aggregation
|
|
209
|
+
const releaseGoods: any[] = await tx
|
|
210
|
+
.getRepository(WorksheetEntity)
|
|
211
|
+
.createQueryBuilder('ws')
|
|
212
|
+
.select('rg.id', 'id')
|
|
213
|
+
.addSelect('rg.name', 'name')
|
|
214
|
+
.addSelect('rg.refNo', 'refNo')
|
|
215
|
+
.addSelect('rg.refNo2', 'refNo2')
|
|
216
|
+
.addSelect('rg.status', 'status')
|
|
217
|
+
.addSelect('rg.district', 'district')
|
|
218
|
+
.addSelect('rg.attention_company', 'attentionCompany')
|
|
219
|
+
.addSelect('rg.delivery_address_1', 'deliveryAddress1')
|
|
220
|
+
.addSelect('rg.delivery_address_2', 'deliveryAddress2')
|
|
221
|
+
.addSelect('rg.delivery_address_3', 'deliveryAddress3')
|
|
222
|
+
.addSelect('rg.delivery_address_4', 'deliveryAddress4')
|
|
223
|
+
.addSelect('rg.delivery_address_5', 'deliveryAddress5')
|
|
224
|
+
.addSelect('rg.created_at', 'createdAt')
|
|
225
|
+
.addSelect('u.name', 'sortedByUser')
|
|
226
|
+
// Counts computed directly in the same query
|
|
227
|
+
.addSelect('COUNT(oi.id)', 'totalCount')
|
|
228
|
+
.addSelect('SUM(CASE WHEN oi.sorted_qty = oi.release_qty THEN 1 ELSE 0 END)', 'completedCount')
|
|
229
|
+
.innerJoin(WorksheetDetailEntity, 'wsd', 'ws.id = wsd.worksheet_id')
|
|
230
|
+
.innerJoin(OrderInventoryEntity, 'oi', 'oi.id = wsd.target_inventory_id')
|
|
231
|
+
.innerJoin(ReleaseGoodEntity, 'rg', 'rg.id = oi.release_good_id')
|
|
232
|
+
.leftJoin(User, 'u', 'rg.sorted_by_id = u.id')
|
|
233
|
+
// Filter directly on ws.domain_id - no need to join Domain table
|
|
234
|
+
.where('ws.domain_id = :domainId', { domainId: domain.id })
|
|
235
|
+
.andWhere('ws.taskNo = :taskNo', { taskNo })
|
|
236
|
+
.andWhere('ws.type = :worksheetType', { worksheetType: WORKSHEET_TYPE.SORTING })
|
|
237
|
+
.andWhere('ws.status = :worksheetStatus', { worksheetStatus: WORKSHEET_STATUS.EXECUTING })
|
|
238
|
+
.groupBy('rg.id')
|
|
239
|
+
.addGroupBy('rg.name')
|
|
240
|
+
.addGroupBy('rg.refNo')
|
|
241
|
+
.addGroupBy('rg.refNo2')
|
|
242
|
+
.addGroupBy('rg.status')
|
|
243
|
+
.addGroupBy('rg.district')
|
|
244
|
+
.addGroupBy('rg.attention_company')
|
|
245
|
+
.addGroupBy('rg.delivery_address_1')
|
|
246
|
+
.addGroupBy('rg.delivery_address_2')
|
|
247
|
+
.addGroupBy('rg.delivery_address_3')
|
|
248
|
+
.addGroupBy('rg.delivery_address_4')
|
|
249
|
+
.addGroupBy('rg.delivery_address_5')
|
|
250
|
+
.addGroupBy('rg.created_at')
|
|
251
|
+
.addGroupBy('u.name')
|
|
252
|
+
.orderBy('rg.created_at', 'ASC')
|
|
253
|
+
.getRawMany()
|
|
254
|
+
|
|
255
|
+
// Transform results to include itemCounts
|
|
256
|
+
return releaseGoods.map(rg => {
|
|
257
|
+
const total = parseInt(rg.totalCount) || 0
|
|
258
|
+
const completed = parseInt(rg.completedCount) || 0
|
|
259
|
+
return {
|
|
260
|
+
id: rg.id,
|
|
261
|
+
name: rg.name,
|
|
262
|
+
refNo: rg.refNo,
|
|
263
|
+
refNo2: rg.refNo2,
|
|
264
|
+
status: rg.status,
|
|
265
|
+
district: rg.district,
|
|
266
|
+
attentionCompany: rg.attentionCompany,
|
|
267
|
+
deliveryAddress1: rg.deliveryAddress1,
|
|
268
|
+
deliveryAddress2: rg.deliveryAddress2,
|
|
269
|
+
deliveryAddress3: rg.deliveryAddress3,
|
|
270
|
+
deliveryAddress4: rg.deliveryAddress4,
|
|
271
|
+
deliveryAddress5: rg.deliveryAddress5,
|
|
272
|
+
sortedByUser: rg.sortedByUser,
|
|
273
|
+
itemCounts: {
|
|
274
|
+
total,
|
|
275
|
+
pending: total - completed
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}) as ReleaseGoodEntity[]
|
|
279
|
+
}
|
|
280
|
+
|
|
18
281
|
export const findSortingReleaseOrdersByTaskNoResolver = {
|
|
19
282
|
async findSortingReleaseOrdersByTaskNo(_: any, { taskNo }, context: any) {
|
|
283
|
+
const startTime = Date.now()
|
|
20
284
|
const { domain, tx, user }: { domain: Domain; tx: EntityManager; user: User } = context.state
|
|
21
285
|
|
|
22
|
-
let selectedReleaseGood = null
|
|
23
|
-
let
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
.innerJoin('worksheet_details', 'wd', `ws.id = wd.worksheet_id`)
|
|
29
|
-
.innerJoin('order_inventories', 'oi', `wd.target_inventory_id = oi.id and wd."type" ='SORTING'`)
|
|
30
|
-
.innerJoin('release_goods', 'rg', `rg.id = oi.release_good_id`)
|
|
31
|
-
.where('rg.domain_id = :domainId', { domainId: domain.id })
|
|
32
|
-
.andWhere('rg.name = :name', { name: taskNo })
|
|
33
|
-
.andWhere('rg.status IN (:...statuses)', {
|
|
34
|
-
statuses: [ORDER_STATUS.READY_TO_SORT, ORDER_STATUS.SORTING, ORDER_STATUS.LOADING, ORDER_STATUS.DONE]
|
|
35
|
-
})
|
|
36
|
-
.andWhere('ws.type = :type', { type: WORKSHEET_TYPE.SORTING })
|
|
37
|
-
.getRawOne()
|
|
38
|
-
|
|
39
|
-
if (ws) {
|
|
40
|
-
if (ws.release_good_status == 'LOADING' || ws.release_good_status == 'DONE') {
|
|
41
|
-
throw new Error(`Release Good already sorted`)
|
|
42
|
-
}
|
|
286
|
+
let selectedReleaseGood: string | null = null
|
|
287
|
+
let task: WorksheetEntity | null = null
|
|
288
|
+
let resolvedTaskNo = taskNo
|
|
289
|
+
|
|
290
|
+
// Step 1: Try to find by release good name first (most common case)
|
|
291
|
+
const releaseGoodResult = await findWorksheetByReleaseGoodName(tx, domain, taskNo)
|
|
43
292
|
|
|
44
|
-
|
|
45
|
-
|
|
293
|
+
if (releaseGoodResult) {
|
|
294
|
+
selectedReleaseGood = releaseGoodResult.selectedReleaseGood
|
|
295
|
+
resolvedTaskNo = releaseGoodResult.taskNo
|
|
296
|
+
|
|
297
|
+
// Only load worksheetDetails if we need them for activation
|
|
298
|
+
const needsActivation = releaseGoodResult.status === 'DEACTIVATED'
|
|
299
|
+
task = await findWorksheetByTaskNo(tx, domain, resolvedTaskNo, needsActivation)
|
|
46
300
|
}
|
|
47
301
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
302
|
+
// Step 2: Try to find by worksheet taskNo directly
|
|
303
|
+
if (!task) {
|
|
304
|
+
task = await findWorksheetByTaskNo(tx, domain, taskNo, false)
|
|
305
|
+
}
|
|
52
306
|
|
|
53
|
-
//
|
|
307
|
+
// Step 3: Try to find by bin location
|
|
54
308
|
if (!task) {
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
.createQueryBuilder('orderInventory')
|
|
63
|
-
|
|
64
|
-
qb.innerJoinAndSelect('orderInventory.releaseGood', 'releaseGood')
|
|
65
|
-
.innerJoinAndSelect(
|
|
66
|
-
'worksheets',
|
|
67
|
-
'ws',
|
|
68
|
-
`orderInventory.ref_worksheet_id = ws.id AND ws.type = 'BATCH_PICKING'`
|
|
69
|
-
)
|
|
70
|
-
.innerJoinAndSelect('worksheets', 'ws2', `ws2.task_no = ws.task_no AND ws2.type = 'SORTING'`)
|
|
71
|
-
.innerJoinAndSelect('releaseGood.bizplace', 'bizplace')
|
|
72
|
-
.innerJoinAndSelect('bizplace.domain', 'domain')
|
|
73
|
-
.where('orderInventory.domain_id = :domainId', { domainId: domain.id })
|
|
74
|
-
.andWhere('orderInventory.status IN (:...orderInventoryStatus)', {
|
|
75
|
-
orderInventoryStatus: [ORDER_INVENTORY_STATUS.READY_TO_SORT, ORDER_INVENTORY_STATUS.SORTING]
|
|
76
|
-
})
|
|
77
|
-
.andWhere('orderInventory.bin_location_id = :locationId', { locationId: binLocation.id })
|
|
78
|
-
.andWhere('releaseGood.status IN (:...statuses)', {
|
|
79
|
-
statuses: [ORDER_STATUS.READY_TO_SORT, ORDER_STATUS.SORTING]
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
const orderInventoryByBin = await qb.getRawOne()
|
|
83
|
-
if (orderInventoryByBin?.releaseGood_id) {
|
|
84
|
-
taskNo = orderInventoryByBin.ws_task_no
|
|
85
|
-
task = await tx.getRepository(WorksheetEntity).findOne({
|
|
86
|
-
where: {
|
|
87
|
-
taskNo,
|
|
88
|
-
status: In([WORKSHEET_STATUS.DEACTIVATED, WORKSHEET_STATUS.EXECUTING]),
|
|
89
|
-
type: WORKSHEET_TYPE.SORTING,
|
|
90
|
-
domain
|
|
91
|
-
},
|
|
92
|
-
relations: ['worksheetDetails']
|
|
93
|
-
})
|
|
94
|
-
} else {
|
|
95
|
-
throw new Error(`Bin do not have any batch picking order.`)
|
|
96
|
-
}
|
|
309
|
+
const binResult = await findWorksheetByBinLocation(tx, domain, taskNo)
|
|
310
|
+
|
|
311
|
+
if (binResult) {
|
|
312
|
+
resolvedTaskNo = binResult.taskNo
|
|
313
|
+
// Only load worksheetDetails if we need them for activation
|
|
314
|
+
const needsActivation = binResult.status === 'DEACTIVATED'
|
|
315
|
+
task = await findWorksheetByTaskNo(tx, domain, resolvedTaskNo, needsActivation)
|
|
97
316
|
}
|
|
98
317
|
}
|
|
99
318
|
|
|
100
|
-
if (!task)
|
|
101
|
-
|
|
102
|
-
if (task.status === 'DEACTIVATED') {
|
|
103
|
-
const sortingWSCtrl: SortingWorksheetController = new SortingWorksheetController(tx, domain, user)
|
|
104
|
-
|
|
105
|
-
const directActivateSortingWorksheet: Setting = await tx.getRepository(Setting).findOne({
|
|
106
|
-
where: { domain: domain, category: 'id-rule', name: 'enable-direct-activate-sorting-worksheet' }
|
|
107
|
-
})
|
|
108
|
-
|
|
109
|
-
const partnerDirectActivateSortingWorksheetSetting: PartnerSetting = await tx
|
|
110
|
-
.getRepository(PartnerSetting)
|
|
111
|
-
.findOne({
|
|
112
|
-
where: {
|
|
113
|
-
setting: directActivateSortingWorksheet,
|
|
114
|
-
domain: domain,
|
|
115
|
-
partnerDomain: task.bizplace?.domain
|
|
116
|
-
}
|
|
117
|
-
})
|
|
118
|
-
|
|
119
|
-
if (directActivateSortingWorksheet != undefined && directActivateSortingWorksheet.value.toLowerCase() == 'true') {
|
|
120
|
-
if (partnerDirectActivateSortingWorksheetSetting != undefined) {
|
|
121
|
-
if (partnerDirectActivateSortingWorksheetSetting.value.toLowerCase() == 'true')
|
|
122
|
-
await sortingWSCtrl.activateSorting(task.name, task.worksheetDetails)
|
|
123
|
-
} else {
|
|
124
|
-
await sortingWSCtrl.activateSorting(task.name, task.worksheetDetails)
|
|
125
|
-
}
|
|
126
|
-
} else {
|
|
127
|
-
throw new Error('Kindly go to sorting worksheet page to activate the sorting worksheet')
|
|
128
|
-
}
|
|
319
|
+
if (!task) {
|
|
320
|
+
throw new Error('Unable to find task no.')
|
|
129
321
|
}
|
|
130
322
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
.
|
|
141
|
-
.addSelect('rg.delivery_address_1 as "deliveryAddress1"')
|
|
142
|
-
.addSelect('rg.delivery_address_2 as "deliveryAddress2"')
|
|
143
|
-
.addSelect('rg.delivery_address_3 as "deliveryAddress3"')
|
|
144
|
-
.addSelect('rg.delivery_address_4 as "deliveryAddress4"')
|
|
145
|
-
.addSelect('rg.delivery_address_5 as "deliveryAddress5"')
|
|
146
|
-
.addSelect('user.name as "sortedByUser"')
|
|
147
|
-
.innerJoin(Domain, 'domain', 'ws.domain_id = domain.id')
|
|
148
|
-
.innerJoin(WorksheetDetailEntity, 'wsd', 'ws.id = wsd.worksheet_id')
|
|
149
|
-
.innerJoin(OrderInventoryEntity, 'oi', 'oi.id = wsd.target_inventory_id')
|
|
150
|
-
.innerJoin(ReleaseGoodEntity, 'rg', 'rg.id = oi.release_good_id')
|
|
151
|
-
.leftJoin(User, 'user', 'rg.sorted_by_id = user.id')
|
|
152
|
-
.where('domain.id = :domainId', { domainId: domain.id })
|
|
153
|
-
.andWhere('ws.taskNo = :taskNo', { taskNo: taskNo })
|
|
154
|
-
.andWhere('ws.type = :worksheetType', { worksheetType: WORKSHEET_TYPE.SORTING })
|
|
155
|
-
.andWhere('ws.status = :worksheetStatus', { worksheetStatus: WORKSHEET_STATUS.EXECUTING })
|
|
156
|
-
.groupBy('rg.id')
|
|
157
|
-
.addGroupBy('rg.name')
|
|
158
|
-
.addGroupBy('rg.status')
|
|
159
|
-
.addGroupBy('user.name')
|
|
160
|
-
.orderBy('rg.createdAt', 'ASC')
|
|
161
|
-
|
|
162
|
-
const releaseGoods: ReleaseGoodEntity[] = await qb.getRawMany()
|
|
163
|
-
|
|
164
|
-
if (releaseGoods.length > 0) {
|
|
165
|
-
// Get counts for all release goods in a single query (avoids N+1 problem)
|
|
166
|
-
const releaseGoodIds = releaseGoods.map(rg => rg.id)
|
|
167
|
-
const countsResult = await tx
|
|
168
|
-
.getRepository(OrderInventoryEntity)
|
|
169
|
-
.createQueryBuilder('orderInventory')
|
|
170
|
-
.innerJoin(WorksheetDetailEntity, 'wsd', 'orderInventory.id = wsd.target_inventory_id')
|
|
171
|
-
.innerJoin(WorksheetEntity, 'ws', 'wsd.worksheet_id = ws.id')
|
|
172
|
-
.select('orderInventory.release_good_id', 'releaseGoodId')
|
|
173
|
-
.addSelect('COUNT(*)', 'total')
|
|
174
|
-
.addSelect(
|
|
175
|
-
'SUM(CASE WHEN orderInventory.sortedQty = orderInventory.releaseQty THEN 1 ELSE 0 END)',
|
|
176
|
-
'completed'
|
|
177
|
-
)
|
|
178
|
-
.where('orderInventory.release_good_id IN (:...releaseGoodIds)', { releaseGoodIds })
|
|
179
|
-
.andWhere('orderInventory.domain_id = :domainId', { domainId: domain.id })
|
|
180
|
-
.andWhere('ws.taskNo = :taskNo', { taskNo: taskNo })
|
|
181
|
-
.andWhere('ws.type = :worksheetType', { worksheetType: WORKSHEET_TYPE.SORTING })
|
|
182
|
-
.andWhere('ws.status = :worksheetStatus', { worksheetStatus: WORKSHEET_STATUS.EXECUTING })
|
|
183
|
-
.groupBy('orderInventory.release_good_id')
|
|
184
|
-
.getRawMany()
|
|
185
|
-
|
|
186
|
-
// Build a map for quick lookup
|
|
187
|
-
const countsById = new Map(
|
|
188
|
-
countsResult.map(c => [
|
|
189
|
-
c.releaseGoodId,
|
|
190
|
-
{ total: parseInt(c.total) || 0, completed: parseInt(c.completed) || 0 }
|
|
191
|
-
])
|
|
192
|
-
)
|
|
193
|
-
|
|
194
|
-
// Assign itemCounts to each release good
|
|
195
|
-
for (const releaseGood of releaseGoods) {
|
|
196
|
-
const counts = countsById.get(releaseGood.id) || { total: 0, completed: 0 }
|
|
197
|
-
releaseGood['itemCounts'] = {
|
|
198
|
-
total: counts.total,
|
|
199
|
-
pending: counts.total - counts.completed
|
|
200
|
-
}
|
|
201
|
-
}
|
|
323
|
+
// Step 4: Handle activation if needed
|
|
324
|
+
await handleWorksheetActivation(tx, domain, user, task)
|
|
325
|
+
|
|
326
|
+
// Step 5: Get release goods with counts
|
|
327
|
+
const releaseGoods = await getReleaseGoodsWithCounts(tx, domain, resolvedTaskNo)
|
|
328
|
+
|
|
329
|
+
// Performance logging (only in development/debug mode)
|
|
330
|
+
const elapsed = Date.now() - startTime
|
|
331
|
+
if (elapsed > 1000) {
|
|
332
|
+
console.warn(`[PERF] findSortingReleaseOrdersByTaskNo took ${elapsed}ms for taskNo: ${taskNo}`)
|
|
202
333
|
}
|
|
203
334
|
|
|
204
|
-
return { releaseGoods, taskNo, selectedReleaseGood }
|
|
335
|
+
return { releaseGoods, taskNo: resolvedTaskNo, selectedReleaseGood }
|
|
205
336
|
}
|
|
206
337
|
}
|