@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.
@@ -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('rg.status = :status', { status: 'LOADING' })
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
- let reducedItemIndex = prev.findIndex(itm => itm.releaseGoodNo == curr.releaseGoodNo && itm.tote == curr.tote)
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
- prev.push(curr)
127
- prev[prev.length - 1].totalSeal = 1
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
- prev[reducedItemIndex].orderQuantity += curr.orderQuantity
130
- prev[reducedItemIndex].totalCarton += curr.totalCarton
131
- if (!prev[reducedItemIndex].sealId.includes(curr.sealId)) {
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
- prev.push(curr)
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
@@ -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",
@@ -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",
@@ -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",
@@ -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": "跟踪号已存在于其他清单列表中",