@things-factory/operato-wms 4.3.761 → 4.3.764
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/outbound/loading-v2/loading-execution-base.js +40 -1
- package/client/pages/outbound/picking-product.js +34 -0
- package/client/pages/outbound/sorting-product.js +30 -0
- package/client/pages/outbound/tote-popup.js +226 -36
- package/config.development.js +105 -88
- package/dist-server/graphql/resolvers/outbound/index.js +2 -1
- package/dist-server/graphql/resolvers/outbound/index.js.map +1 -1
- package/dist-server/graphql/resolvers/outbound/unsort-item.js +65 -0
- package/dist-server/graphql/resolvers/outbound/unsort-item.js.map +1 -0
- package/dist-server/graphql/resolvers/reports/tote-loading-qc-report.js +19 -10
- package/dist-server/graphql/resolvers/reports/tote-loading-qc-report.js.map +1 -1
- package/dist-server/graphql/types/outbound/index.js +4 -0
- package/dist-server/graphql/types/outbound/index.js.map +1 -1
- package/package.json +50 -50
- package/server/graphql/resolvers/outbound/index.ts +2 -0
- package/server/graphql/resolvers/outbound/unsort-item.ts +78 -0
- package/server/graphql/resolvers/reports/tote-loading-qc-report.ts +34 -11
- package/server/graphql/types/outbound/index.ts +4 -0
- package/translations/en.json +8 -0
- package/translations/ko.json +7 -0
- package/translations/ms.json +7 -0
- package/translations/zh.json +7 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { EntityManager, Not } from 'typeorm'
|
|
2
|
+
import { User } from '@things-factory/auth-base'
|
|
3
|
+
import { Domain } from '@things-factory/shell'
|
|
4
|
+
import { ORDER_INVENTORY_STATUS, OrderInventory, OrderToteItem } from '@things-factory/sales-base'
|
|
5
|
+
|
|
6
|
+
export const unsortItem = {
|
|
7
|
+
async unsortItem(_: any, { orderToteItemId, reason }, context: any) {
|
|
8
|
+
const { domain, user, tx }: { domain: Domain; user: User; tx: EntityManager } = context.state
|
|
9
|
+
|
|
10
|
+
// Find the order tote item with relations
|
|
11
|
+
const orderToteItem = (await tx.getRepository(OrderToteItem).findOne({
|
|
12
|
+
where: { domain, id: orderToteItemId },
|
|
13
|
+
relations: ['orderTote', 'orderInventory']
|
|
14
|
+
})) as OrderToteItem | null
|
|
15
|
+
|
|
16
|
+
if (!orderToteItem) {
|
|
17
|
+
throw new Error('Order tote item not found')
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Check if tote is sealed - cannot undo if sealed
|
|
21
|
+
if (orderToteItem.orderTote?.closedDate) {
|
|
22
|
+
throw new Error('Cannot remove item from sealed tote.')
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const orderInventory: OrderInventory = orderToteItem.orderInventory
|
|
26
|
+
const qtyToRemove = orderToteItem.qty
|
|
27
|
+
|
|
28
|
+
if (!orderInventory) {
|
|
29
|
+
throw new Error('Associated order inventory not found')
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Validate that we can reduce the sorted quantity
|
|
33
|
+
if (orderInventory.sortedQty < qtyToRemove) {
|
|
34
|
+
throw new Error(`Cannot remove ${qtyToRemove} items. Current sorted quantity is ${orderInventory.sortedQty}`)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Calculate new sorted quantity
|
|
38
|
+
const newSortedQty = orderInventory.sortedQty - qtyToRemove
|
|
39
|
+
|
|
40
|
+
// Determine new status - revert to PICKED if no more sorted items
|
|
41
|
+
let newStatus = orderInventory.status
|
|
42
|
+
if (newSortedQty === 0 && orderInventory.status === ORDER_INVENTORY_STATUS.LOADING) {
|
|
43
|
+
// Check if there are other order tote items for this order inventory
|
|
44
|
+
const otherToteItems = await tx.getRepository(OrderToteItem).count({
|
|
45
|
+
where: {
|
|
46
|
+
domain,
|
|
47
|
+
orderInventory: { id: orderInventory.id },
|
|
48
|
+
id: Not(orderToteItemId)
|
|
49
|
+
}
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
// Only revert to PICKED if this is the last tote item (no more sorted items)
|
|
53
|
+
if (otherToteItems === 0) {
|
|
54
|
+
newStatus = ORDER_INVENTORY_STATUS.SORTING
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Update the order inventory
|
|
59
|
+
await tx.getRepository(OrderInventory).update(orderInventory.id, {
|
|
60
|
+
sortedQty: newSortedQty,
|
|
61
|
+
status: newStatus,
|
|
62
|
+
updatedAt: new Date(),
|
|
63
|
+
updater: user
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
// Delete the order tote item
|
|
67
|
+
await tx.getRepository(OrderToteItem).delete(orderToteItem.id)
|
|
68
|
+
|
|
69
|
+
// Log the undo action if reason provided
|
|
70
|
+
if (reason) {
|
|
71
|
+
console.log(
|
|
72
|
+
`[UNSORT] User ${user.name} removed ${qtyToRemove} items from tote ${orderToteItem.orderTote?.name}. Reason: ${reason}`
|
|
73
|
+
)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return true
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -62,7 +62,8 @@ export const loadingQcReport = {
|
|
|
62
62
|
ELSE NULL
|
|
63
63
|
END
|
|
64
64
|
END`,
|
|
65
|
-
'totalCarton'
|
|
65
|
+
'totalCarton'
|
|
66
|
+
)
|
|
66
67
|
.addSelect('case when oti.qty is null then oi.release_qty else oti.qty end', 'orderQuantity')
|
|
67
68
|
.addSelect('ot.name', 'tote')
|
|
68
69
|
.addSelect('case when ot.tote_id is null then false else true end', 'toteBox')
|
|
@@ -74,14 +75,17 @@ export const loadingQcReport = {
|
|
|
74
75
|
.leftJoin('order_totes', 'ot', 'ot.id = oti.order_tote_id')
|
|
75
76
|
.leftJoin('order_tote_seals', 'ots', 'ots.order_tote_id = ot.id')
|
|
76
77
|
.innerJoin('product_details', 'pd', 'oi.product_detail_id = pd.id')
|
|
77
|
-
.where('
|
|
78
|
-
.andWhere('bizplace.id = :bizplaceId', { bizplaceId: bizplaceFilter.value })
|
|
78
|
+
.where('bizplace.id = :bizplaceId', { bizplaceId: bizplaceFilter.value })
|
|
79
79
|
.andWhere('rg.release_date <= :toDate', { toDate: toDateFilter.value })
|
|
80
80
|
.andWhere('rg.release_date >= :fromDate', { fromDate: fromDateFilter.value })
|
|
81
81
|
.andWhere('w.type = :type', { type: 'LOADING' })
|
|
82
82
|
.andWhere('rg.domain_id = :domainId', { domainId: domain.id })
|
|
83
|
+
.andWhere('rg.name IS NOT NULL')
|
|
84
|
+
.andWhere('rg.status NOT IN (:...excludedStatuses)', {
|
|
85
|
+
excludedStatuses: ['PENDING_CANCEL', 'CANCELLED', 'PENDING_WORKSHEET', 'READY_TO_PICK']
|
|
86
|
+
})
|
|
83
87
|
.groupBy('bizplace.name')
|
|
84
|
-
.addGroupBy('rg.name
|
|
88
|
+
.addGroupBy('rg.name')
|
|
85
89
|
.addGroupBy('rg.route_id')
|
|
86
90
|
.addGroupBy('rg.stop_id')
|
|
87
91
|
.addGroupBy('rg.release_date')
|
|
@@ -121,21 +125,40 @@ export const loadingQcReport = {
|
|
|
121
125
|
|
|
122
126
|
items = items.reduce((prev, curr, idx) => {
|
|
123
127
|
if (curr.tote) {
|
|
124
|
-
|
|
128
|
+
// Find duplicate by releaseGoodNo, tote, and additional fields to ensure proper grouping
|
|
129
|
+
let reducedItemIndex = prev.findIndex(
|
|
130
|
+
itm =>
|
|
131
|
+
itm.releaseGoodNo === curr.releaseGoodNo &&
|
|
132
|
+
itm.tote === curr.tote &&
|
|
133
|
+
itm.bizplaceName === curr.bizplaceName
|
|
134
|
+
)
|
|
125
135
|
if (reducedItemIndex == -1) {
|
|
126
|
-
|
|
127
|
-
prev
|
|
136
|
+
// Ensure numeric fields are properly typed when adding new item
|
|
137
|
+
prev.push({
|
|
138
|
+
...curr,
|
|
139
|
+
orderQuantity: Number(curr.orderQuantity) || 0,
|
|
140
|
+
totalCarton: Number(curr.totalCarton) || 0,
|
|
141
|
+
totalSeal: curr.sealId ? 1 : 0
|
|
142
|
+
})
|
|
128
143
|
} else {
|
|
129
|
-
|
|
130
|
-
prev[reducedItemIndex].
|
|
131
|
-
|
|
144
|
+
// Aggregate quantities with explicit numeric conversion
|
|
145
|
+
prev[reducedItemIndex].orderQuantity += Number(curr.orderQuantity) || 0
|
|
146
|
+
prev[reducedItemIndex].totalCarton += Number(curr.totalCarton) || 0
|
|
147
|
+
// Concatenate seal IDs only if they're unique and not null
|
|
148
|
+
if (curr.sealId && !prev[reducedItemIndex].sealId.includes(curr.sealId)) {
|
|
132
149
|
prev[reducedItemIndex].sealId = prev[reducedItemIndex].sealId.concat(', ', curr.sealId)
|
|
133
150
|
prev[reducedItemIndex].totalSeal++
|
|
134
151
|
}
|
|
135
152
|
}
|
|
136
153
|
return prev
|
|
137
154
|
} else {
|
|
138
|
-
|
|
155
|
+
// Ensure numeric fields are properly typed for items without totes
|
|
156
|
+
prev.push({
|
|
157
|
+
...curr,
|
|
158
|
+
orderQuantity: Number(curr.orderQuantity) || 0,
|
|
159
|
+
totalCarton: Number(curr.totalCarton) || 0,
|
|
160
|
+
totalSeal: 0
|
|
161
|
+
})
|
|
139
162
|
return prev
|
|
140
163
|
}
|
|
141
164
|
}, [])
|
|
@@ -19,6 +19,10 @@ export const Mutation = `
|
|
|
19
19
|
worksheetDetails: [Object!]
|
|
20
20
|
toteNo: String
|
|
21
21
|
): Boolean @transaction
|
|
22
|
+
unsortItem(
|
|
23
|
+
orderToteItemId: String!
|
|
24
|
+
reason: String
|
|
25
|
+
): Boolean @transaction
|
|
22
26
|
loadByQty(worksheetDetailPatch: LoadingWorksheetDetails): Boolean @transaction
|
|
23
27
|
undoLoad(doId: String!): Boolean @transaction
|
|
24
28
|
warehouseReturn (releaseGoodNo: String!, worksheetDetails: [Object!]): Worksheet @privilege(category: "worksheet_control", privilege: "mutation") @transaction
|
package/translations/en.json
CHANGED
|
@@ -1258,6 +1258,7 @@
|
|
|
1258
1258
|
"label.transfer_inventory": "transfer inventory",
|
|
1259
1259
|
"label.transfer_qty": "transfer qty",
|
|
1260
1260
|
"label.transfer": "transfer",
|
|
1261
|
+
"label.aggregation-function": "aggregation",
|
|
1261
1262
|
"label.transport_type": "transport type",
|
|
1262
1263
|
"label.transport_vehicle": "transport vehicle",
|
|
1263
1264
|
"label.transporter": "transporter",
|
|
@@ -1907,6 +1908,13 @@
|
|
|
1907
1908
|
"text.tote_is_not_scanned": "tote is not scanned",
|
|
1908
1909
|
"text.tote_number": "tote number",
|
|
1909
1910
|
"text.tote_status_does_not_exist": "tote status does not exist",
|
|
1911
|
+
"text.are_you_sure_to_remove_x_from_tote": "are you sure you want to remove {x} from this tote?",
|
|
1912
|
+
"text.item_removed_from_tote": "item removed from tote",
|
|
1913
|
+
"text.items_removed_from_tote": "{count} items removed from tote",
|
|
1914
|
+
"text.nothing_selected": "nothing selected",
|
|
1915
|
+
"text.please_select_items_to_undo": "please select items to undo",
|
|
1916
|
+
"text.viewing_items_in_tote": "viewing items in tote",
|
|
1917
|
+
"text.list_refreshed": "list refreshed",
|
|
1910
1918
|
"text.tracking_no_added_successfully": "tracking no added successfully",
|
|
1911
1919
|
"text.tracking_no_already_exist_in_manifest_list": "tracking no already exist in manifest list",
|
|
1912
1920
|
"text.tracking_no_already_exist_in_other_manifest_list": "tracking no already exist in other manifest list",
|
package/translations/ko.json
CHANGED
|
@@ -1249,6 +1249,7 @@
|
|
|
1249
1249
|
"label.transfer_inventory": "재고 이동",
|
|
1250
1250
|
"label.transfer_qty": "[ko]transfer qty",
|
|
1251
1251
|
"label.transfer": "재고 이동",
|
|
1252
|
+
"label.aggregation-function": "집계함수",
|
|
1252
1253
|
"label.transport_type": "운송 유형",
|
|
1253
1254
|
"label.transport_vehicle": "[ko] transport vehicle",
|
|
1254
1255
|
"label.transporter": "[ko] transporter",
|
|
@@ -1892,6 +1893,12 @@
|
|
|
1892
1893
|
"text.tote_is_not_scanned": "[ko] tote is not scanned",
|
|
1893
1894
|
"text.tote_number": "[ko] tote number",
|
|
1894
1895
|
"text.tote_status_does_not_exist": "[ko] tote status does not exist",
|
|
1896
|
+
"text.are_you_sure_to_remove_x_from_tote": "[ko] are you sure you want to remove {x} from this tote?",
|
|
1897
|
+
"text.item_removed_from_tote": "[ko] item removed from tote",
|
|
1898
|
+
"text.items_removed_from_tote": "[ko] {count} items removed from tote",
|
|
1899
|
+
"text.please_select_items_to_undo": "[ko] please select items to undo",
|
|
1900
|
+
"text.viewing_items_in_tote": "[ko] viewing items in tote",
|
|
1901
|
+
"text.list_refreshed": "[ko] list refreshed",
|
|
1895
1902
|
"text.tracking_no_added_successfully": "[ko] tracking no added successfully",
|
|
1896
1903
|
"text.tracking_no_already_exist_in_manifest_list": "[ko] tracking no already exist in manifest list",
|
|
1897
1904
|
"text.tracking_no_already_exist_in_other_manifest_list": "[ko]tracking no already exist in other manifest list",
|
package/translations/ms.json
CHANGED
|
@@ -1275,6 +1275,7 @@
|
|
|
1275
1275
|
"label.transfer": "pemindahan",
|
|
1276
1276
|
"label.transfer_inventory": "pemindahan inventori",
|
|
1277
1277
|
"label.transfer_qty": "transfer qty",
|
|
1278
|
+
"label.aggregation-function": "aggregation",
|
|
1278
1279
|
"label.transport_type": "jenis pengangkutan",
|
|
1279
1280
|
"label.transport_vehicle": "transport vehicle",
|
|
1280
1281
|
"label.transporter": "transporter",
|
|
@@ -1944,6 +1945,12 @@
|
|
|
1944
1945
|
"text.tote_is_not_scanned": "kotak tote tidak dipindai",
|
|
1945
1946
|
"text.tote_number": "nombor tote",
|
|
1946
1947
|
"text.tote_status_does_not_exist": "status tote tidak wujud",
|
|
1948
|
+
"text.are_you_sure_to_remove_x_from_tote": "[ms] are you sure you want to remove {x} from this tote?",
|
|
1949
|
+
"text.item_removed_from_tote": "[ms] item removed from tote",
|
|
1950
|
+
"text.items_removed_from_tote": "[ms] {count} items removed from tote",
|
|
1951
|
+
"text.please_select_items_to_undo": "[ms] please select items to undo",
|
|
1952
|
+
"text.viewing_items_in_tote": "[ms] viewing items in tote",
|
|
1953
|
+
"text.list_refreshed": "[ms] list refreshed",
|
|
1947
1954
|
"text.tracking_no_added_successfully": "no. penjejak telah ditambah",
|
|
1948
1955
|
"text.tracking_no_already_exist_in_manifest_list": "no. penjejak sudah wujud dalam senarai manifest",
|
|
1949
1956
|
"text.tracking_no_already_exist_in_other_manifest_list": "no. penjejak sudah wujud dalam senarai manifest lain",
|
package/translations/zh.json
CHANGED
|
@@ -1293,6 +1293,7 @@
|
|
|
1293
1293
|
"label.transfer": "转移",
|
|
1294
1294
|
"label.transfer_inventory": "转移库存",
|
|
1295
1295
|
"label.transfer_qty": "转移数量",
|
|
1296
|
+
"label.aggregation-function": "聚合函数",
|
|
1296
1297
|
"label.transport_type": "运输类型",
|
|
1297
1298
|
"label.transport_vehicle": "运输车辆",
|
|
1298
1299
|
"label.transporter": "运输商",
|
|
@@ -1977,6 +1978,12 @@
|
|
|
1977
1978
|
"text.tote_is_not_scanned": "箱子未扫描",
|
|
1978
1979
|
"text.tote_number": "箱子编号",
|
|
1979
1980
|
"text.tote_status_does_not_exist": "箱子状态不存在",
|
|
1981
|
+
"text.are_you_sure_to_remove_x_from_tote": "[zh] are you sure you want to remove {x} from this tote?",
|
|
1982
|
+
"text.item_removed_from_tote": "[zh] item removed from tote",
|
|
1983
|
+
"text.items_removed_from_tote": "[zh] {count} items removed from tote",
|
|
1984
|
+
"text.please_select_items_to_undo": "[zh] please select items to undo",
|
|
1985
|
+
"text.viewing_items_in_tote": "[zh] viewing items in tote",
|
|
1986
|
+
"text.list_refreshed": "[zh] list refreshed",
|
|
1980
1987
|
"text.tracking_no_added_successfully": "跟踪号已添加成功",
|
|
1981
1988
|
"text.tracking_no_already_exist_in_manifest_list": "跟踪号已存在于清单列表中",
|
|
1982
1989
|
"text.tracking_no_already_exist_in_other_manifest_list": "跟踪号已存在于其他清单列表中",
|