@things-factory/operato-wms 4.3.761 → 4.3.762

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.
@@ -448,19 +448,58 @@ export class LoadingExecutionBase extends LitElement {
448
448
  throw new Error(i18next.t('text.no_release_order_selected'))
449
449
  }
450
450
 
451
+ // Query for minimum seal number setting
452
+ let minimumSealNumber = 0
453
+ try {
454
+ const validationResponse = await client.query({
455
+ query: VALIDATE_QC_SEALS,
456
+ variables: { releaseGoodNo: orderNo },
457
+ context: gqlContext()
458
+ })
459
+
460
+ if (!validationResponse.errors && validationResponse.data?.validateQcSeals) {
461
+ minimumSealNumber = validationResponse.data.validateQcSeals.minimumSealNumber || 0
462
+ }
463
+ } catch (err) {
464
+ // If query fails, default to 0 (don't block tote scanning)
465
+ console.warn('Failed to fetch minimum seal number:', err)
466
+ }
467
+
451
468
  openPopup(
452
469
  html`
453
470
  <tote-popup
454
471
  .orderNo="${orderNo}"
455
472
  .toteNo="${this.toteNo}"
456
473
  .bizplace="${bizplace}"
474
+ .minimumSealNumber="${minimumSealNumber}"
457
475
  @completed="${async e => {
458
476
  this.toteNo = e.detail
459
477
  // Check seal status after tote is sealed (may have changed)
460
478
  await this._checkAndUpdateSealStatus()
479
+
480
+ // Refresh data for both QC and LOADING tabs to reflect any undone items
481
+ // Use the same logic as validateSorting to determine which order/bin to refresh
482
+ const orderNoForRefresh = this.worksheet?.isReleaseGoodScan
483
+ ? this.worksheet?.releaseGood?.name
484
+ : this._useQcSku
485
+ ? this.worksheet?.binLocationName
486
+ : this.worksheet?.releaseGood?.name
487
+ const useQcSkuForRefresh = this._useQcSku && !this.worksheet?.isReleaseGoodScan
488
+
489
+ const [qcData, loadingData] = await Promise.all([
490
+ this.fetchData(orderNoForRefresh, 'qc', useQcSkuForRefresh),
491
+ this.fetchData(orderNoForRefresh, 'loading', useQcSkuForRefresh)
492
+ ])
493
+
494
+ // QC tab: items that still need QC (sortedQty < pickedQty)
495
+ this.qcData = qcData.filter(data => data?.sortedQty < data?.pickedQty) || []
496
+ // Loading tab: items that have completed QC (sortedQty >= pickedQty) and are not yet loaded
497
+ this.loadingData =
498
+ loadingData.filter(data => data?.sortedQty >= data?.pickedQty && data.status != WORKSHEET_STATUS.DONE.value) || []
499
+
461
500
  // Update button visibility after sealing (Tote button may need to be hidden if sealing is complete)
462
501
  this.getButton()
463
- // Update QC banner state after tote is sealed
502
+ // Update QC banner state after data is refreshed
464
503
  if (this._updateQcBannerState) {
465
504
  await this._updateQcBannerState()
466
505
  }
@@ -33,6 +33,17 @@ import {
33
33
  } from '../constants'
34
34
 
35
35
  const PICKING_TYPES = { PICKING, BATCH_PICKING }
36
+
37
+ const VALIDATE_QC_SEALS = gql`
38
+ query validateQcSeals($releaseGoodNo: String!) {
39
+ validateQcSeals(releaseGoodNo: $releaseGoodNo) {
40
+ valid
41
+ error
42
+ minimumSealNumber
43
+ }
44
+ }
45
+ `
46
+
36
47
  class PickingProduct extends connect(store)(localize(i18next)(PageView)) {
37
48
  static get properties() {
38
49
  return {
@@ -976,14 +987,37 @@ class PickingProduct extends connect(store)(localize(i18next)(PageView)) {
976
987
 
977
988
  async openTotePopup() {
978
989
  await sleep(1010)
990
+
991
+ // Query for minimum seal number setting
992
+ let minimumSealNumber = 0
993
+ try {
994
+ const validationResponse = await client.query({
995
+ query: VALIDATE_QC_SEALS,
996
+ variables: { releaseGoodNo: this.releaseGoodNo },
997
+ context: gqlContext()
998
+ })
999
+
1000
+ if (!validationResponse.errors && validationResponse.data?.validateQcSeals) {
1001
+ minimumSealNumber = validationResponse.data.validateQcSeals.minimumSealNumber || 0
1002
+ }
1003
+ } catch (err) {
1004
+ // If query fails, default to 0 (don't block tote scanning)
1005
+ console.warn('Failed to fetch minimum seal number:', err)
1006
+ }
1007
+
979
1008
  openPopup(
980
1009
  html`
981
1010
  <tote-popup
982
1011
  .orderNo="${this.releaseGoodNo}"
983
1012
  .toteNo="${this.toteNo}"
984
1013
  .bizplace="${this._bizplaceName}"
1014
+ .minimumSealNumber="${minimumSealNumber}"
985
1015
  @completed="${async e => {
986
1016
  this.toteNo = e.detail
1017
+ // Refresh the item list to reflect any undone items
1018
+ await this.fetchInventories(
1019
+ this.refPickingType === PICKING_TYPES.PICKING.value ? this.releaseGoodNo : this.taskNo
1020
+ )
987
1021
  }}"
988
1022
  ></tote-popup>
989
1023
  `,
@@ -21,6 +21,16 @@ import { fetchSettingRule } from '../../fetch-setting-value'
21
21
  import { WORKSHEET_STATUS } from '../constants'
22
22
  import { decodeQR, fetchPageSettings, isValidHttpUrl } from '../../util'
23
23
 
24
+ const VALIDATE_QC_SEALS = gql`
25
+ query validateQcSeals($releaseGoodNo: String!) {
26
+ validateQcSeals(releaseGoodNo: $releaseGoodNo) {
27
+ valid
28
+ error
29
+ minimumSealNumber
30
+ }
31
+ }
32
+ `
33
+
24
34
  class SortingProduct extends connect(store)(localize(i18next)(PageView)) {
25
35
  static get properties() {
26
36
  return {
@@ -515,14 +525,34 @@ class SortingProduct extends connect(store)(localize(i18next)(PageView)) {
515
525
 
516
526
  async _openTotePopup() {
517
527
  await sleep(1010)
528
+
529
+ // Query for minimum seal number setting
530
+ let minimumSealNumber = 0
531
+ try {
532
+ const validationResponse = await client.query({
533
+ query: VALIDATE_QC_SEALS,
534
+ variables: { releaseGoodNo: this._selectedReleaseGood }
535
+ })
536
+
537
+ if (!validationResponse.errors && validationResponse.data?.validateQcSeals) {
538
+ minimumSealNumber = validationResponse.data.validateQcSeals.minimumSealNumber || 0
539
+ }
540
+ } catch (err) {
541
+ // If query fails, default to 0 (don't block tote scanning)
542
+ console.warn('Failed to fetch minimum seal number:', err)
543
+ }
544
+
518
545
  openPopup(
519
546
  html`
520
547
  <tote-popup
521
548
  .orderNo="${this._selectedReleaseGood}"
522
549
  .toteNo="${this.toteNo}"
523
550
  .bizplace="${this.bizplaceName}"
551
+ .minimumSealNumber="${minimumSealNumber}"
524
552
  @completed="${async e => {
525
553
  this.toteNo = e.detail
554
+ // Refresh the item list to reflect any undone items
555
+ await this._fetchItemList(this._selectedReleaseGood)
526
556
  }}"
527
557
  ></tote-popup>
528
558
  `,
@@ -6,7 +6,7 @@ import { css, html, LitElement } from 'lit-element'
6
6
 
7
7
  import { MultiColumnFormStyles, SingleColumnFormStyles } from '@things-factory/form-ui'
8
8
  import { i18next, localize } from '@things-factory/i18n-base'
9
- import { client } from '@things-factory/shell'
9
+ import { client, CustomAlert } from '@things-factory/shell'
10
10
  import { ScrollbarStyles } from '@things-factory/styles'
11
11
  import { isMobileDevice } from '@things-factory/utils'
12
12
  import { TOTE_STATUS } from '../constants'
@@ -20,6 +20,7 @@ class TotePopup extends localize(i18next)(LitElement) {
20
20
  data: Object,
21
21
  orderNo: String,
22
22
  toteNo: String,
23
+ minimumSealNumber: Number,
23
24
  _totalSeal: Number,
24
25
  _selectedToteNo: String,
25
26
  _toteNoList: Object,
@@ -76,11 +77,26 @@ class TotePopup extends localize(i18next)(LitElement) {
76
77
  .break {
77
78
  word-wrap: break-word;
78
79
  }
80
+ .mobile-hint {
81
+ padding: 10px;
82
+ background-color: var(--primary-light-color, #f0f0f0);
83
+ border-left: 4px solid var(--primary-color, #2196f3);
84
+ margin: 10px;
85
+ font-size: 0.9em;
86
+ }
87
+ .refresh-button {
88
+ margin: 10px;
89
+ display: flex;
90
+ justify-content: center;
91
+ }
79
92
  `
80
93
  ]
81
94
  }
82
95
 
83
96
  render() {
97
+ const shouldShowSealSection = this._shouldShowSealSection()
98
+ const sealInputDisabled = !this.toteNo || this.toteNo === ''
99
+
84
100
  return html`
85
101
  <form class="multi-column-form">
86
102
  <fieldset>
@@ -121,34 +137,46 @@ class TotePopup extends localize(i18next)(LitElement) {
121
137
  </fieldset>
122
138
  </form>
123
139
 
124
- <form class="multi-column-form">
125
- <fieldset>
126
- <label>${i18next.t('field.seal_no')}</label>
127
- <barcode-scanable-input
128
- name="sealNo"
129
- custom-input
130
- @keypress="${e => {
131
- if (e.keyCode === 13) {
132
- e.preventDefault()
133
- this.sealNo = this.sealNoInput.value
134
- if (this.toteNo) {
135
- this._sealTote()
136
- } else {
137
- this._showToast({ message: i18next.t('text.tote_is_not_scanned') })
138
- }
139
- }
140
- }}"
141
- ></barcode-scanable-input>
142
- </fieldset>
143
-
144
- <label>${i18next.t('field.scanned')} (${this._totalSeal || 0})</label>
145
- <select name="sealNoList">
146
- <option value="">-- ${i18next.t('text.seal_number')} --</option>
147
- ${(this._sealNoList?.orderToteSeals || []).map(
148
- list => html` <option value="${list.name}">${list.name}</option> `
149
- )}
150
- </select>
151
- </form>
140
+ ${shouldShowSealSection
141
+ ? html`
142
+ <form class="multi-column-form">
143
+ <fieldset>
144
+ <label>${i18next.t('field.seal_no')}</label>
145
+ <barcode-scanable-input
146
+ name="sealNo"
147
+ custom-input
148
+ ?disabled="${sealInputDisabled}"
149
+ @keypress="${e => {
150
+ if (e.keyCode === 13) {
151
+ e.preventDefault()
152
+ this.sealNo = this.sealNoInput.value
153
+ if (this.toteNo) {
154
+ this._sealTote()
155
+ } else {
156
+ this._showToast({ message: i18next.t('text.tote_is_not_scanned') })
157
+ }
158
+ }
159
+ }}"
160
+ ></barcode-scanable-input>
161
+ </fieldset>
162
+
163
+ <label>${i18next.t('field.scanned')} (${this._totalSeal || 0})</label>
164
+ <select name="sealNoList">
165
+ <option value="">-- ${i18next.t('text.seal_number')} --</option>
166
+ ${(this._sealNoList?.orderToteSeals || []).map(
167
+ list => html` <option value="${list.name}">${list.name}</option> `
168
+ )}
169
+ </select>
170
+ </form>
171
+ `
172
+ : ''}
173
+ ${isMobileDevice() && this._selectedToteNo?.length > 0
174
+ ? html`
175
+ <div class="mobile-hint">
176
+ ${i18next.t('text.viewing_items_in_tote')}: <strong>${this._selectedToteNo[0].name}</strong>
177
+ </div>
178
+ `
179
+ : ''}
152
180
 
153
181
  <div class="grist-container">
154
182
  <div class="grist">
@@ -161,9 +189,35 @@ class TotePopup extends localize(i18next)(LitElement) {
161
189
  </div>
162
190
  </div>
163
191
 
192
+ ${isMobileDevice()
193
+ ? html`
194
+ <div class="refresh-button">
195
+ <mwc-button
196
+ icon="refresh"
197
+ @click=${async () => {
198
+ if (this.grist) {
199
+ await this.grist.fetch()
200
+ this._showToast({ type: 'info', message: i18next.t('text.list_refreshed') })
201
+ }
202
+ }}
203
+ label="${i18next.t('button.refresh')}"
204
+ ></mwc-button>
205
+ </div>
206
+ `
207
+ : ''}
208
+
164
209
  <div class="button-container">
210
+ ${this._shouldShowUndoButton()
211
+ ? html`
212
+ <mwc-button
213
+ @click=${this._undoSelectedItems.bind(this)}
214
+ raised
215
+ style="--mdc-theme-primary: var(--status-warning-color, #ff9800); margin-right: 10px;"
216
+ label="${i18next.t('button.undo')}"
217
+ ></mwc-button>
218
+ `
219
+ : ''}
165
220
  <mwc-button
166
- danger
167
221
  @click=${() => {
168
222
  this.dispatchEvent(
169
223
  new CustomEvent('completed', {
@@ -188,11 +242,25 @@ class TotePopup extends localize(i18next)(LitElement) {
188
242
  }
189
243
 
190
244
  get sealNoInput() {
191
- return this.shadowRoot.querySelector('barcode-scanable-input[name=sealNo]').shadowRoot.querySelector('input')
245
+ return this.shadowRoot.querySelector('barcode-scanable-input[name=sealNo]')?.shadowRoot?.querySelector('input')
246
+ }
247
+
248
+ _shouldShowSealSection() {
249
+ // Only show seal section if minimumSealNumber is greater than 0
250
+ return (this.minimumSealNumber || 0) > 0
251
+ }
252
+
253
+ _shouldShowUndoButton() {
254
+ // Show undo button only if selected tote is not sealed
255
+ const selectedTote = this._selectedToteNo?.[0]
256
+ return selectedTote && !selectedTote?.closedDate
192
257
  }
193
258
 
194
259
  _focusOnSealNoInput() {
195
- setTimeout(() => this.sealNoInput.focus(), 50)
260
+ const sealInput = this.sealNoInput
261
+ if (sealInput) {
262
+ setTimeout(() => sealInput.focus(), 50)
263
+ }
196
264
  }
197
265
 
198
266
  _focusOnToteNoInput() {
@@ -201,28 +269,36 @@ class TotePopup extends localize(i18next)(LitElement) {
201
269
 
202
270
  async firstUpdated() {
203
271
  this.config = {
272
+ list: { fields: ['sku', 'packingType', 'pickedQty'] },
204
273
  pagination: { pages: [10, 20, 50, 100] },
205
274
  rows: {
206
- appendable: false
275
+ appendable: false,
276
+ selectable: {
277
+ multiple: true
278
+ }
207
279
  },
208
280
  columns: [
209
281
  { type: 'gutter', gutterName: 'sequence' },
282
+ { type: 'gutter', gutterName: 'row-selector', multiple: true },
210
283
  {
211
284
  type: 'string',
212
285
  name: 'sku',
213
286
  header: i18next.t('field.sku'),
287
+ label: true,
214
288
  width: 180
215
289
  },
216
290
  {
217
291
  type: 'string',
218
292
  name: 'packingType',
219
293
  header: i18next.t('field.packing_type'),
294
+ label: true,
220
295
  width: 180
221
296
  },
222
297
  {
223
298
  type: 'string',
224
299
  name: 'pickedQty',
225
300
  header: i18next.t('field.picked_qty'),
301
+ label: true,
226
302
  width: 180
227
303
  }
228
304
  ]
@@ -269,7 +345,8 @@ class TotePopup extends localize(i18next)(LitElement) {
269
345
  toteNo: this._selectedToteNo[0].name,
270
346
  sortings,
271
347
  orderNo: this.orderNo
272
- }
348
+ },
349
+ fetchPolicy: 'no-cache'
273
350
  })
274
351
 
275
352
  if (!response.errors) {
@@ -279,7 +356,10 @@ class TotePopup extends localize(i18next)(LitElement) {
279
356
  }
280
357
 
281
358
  if (this.toteNo && this.toteNo !== '') {
282
- this._focusOnSealNoInput()
359
+ // Only focus on seal input if seal section is visible
360
+ if (this._shouldShowSealSection()) {
361
+ this._focusOnSealNoInput()
362
+ }
283
363
  } else {
284
364
  this._focusOnToteNoInput()
285
365
  }
@@ -306,6 +386,21 @@ class TotePopup extends localize(i18next)(LitElement) {
306
386
 
307
387
  if (result) {
308
388
  await this._checkToteAvailability()
389
+
390
+ // After successful tote scan, refresh the tote list and auto-select the scanned tote
391
+ if (this.toteNo && this.toteNo !== '') {
392
+ await this._fetchToteList()
393
+
394
+ // Auto-select the scanned tote for PDA/mobile users
395
+ const scannedTote = this._toteNoList?.find(tote => tote.name === this.toteNo)
396
+ if (scannedTote) {
397
+ this._selectedToteNo = [scannedTote]
398
+ // Trigger grist to fetch items for the selected tote
399
+ if (this.grist) {
400
+ await this.grist.fetch()
401
+ }
402
+ }
403
+ }
309
404
  } else {
310
405
  this.toteNoInput.value = ''
311
406
  this.toteNo = ''
@@ -315,7 +410,10 @@ class TotePopup extends localize(i18next)(LitElement) {
315
410
  }
316
411
 
317
412
  if (this.toteNo && this.toteNo !== '') {
318
- this._focusOnSealNoInput()
413
+ // Only focus on seal input if seal section is visible
414
+ if (this._shouldShowSealSection()) {
415
+ this._focusOnSealNoInput()
416
+ }
319
417
  } else {
320
418
  this._focusOnToteNoInput()
321
419
  }
@@ -420,6 +518,7 @@ class TotePopup extends localize(i18next)(LitElement) {
420
518
  items {
421
519
  id
422
520
  name
521
+ closedDate
423
522
  orderToteSeals {
424
523
  id
425
524
  name
@@ -446,6 +545,97 @@ class TotePopup extends localize(i18next)(LitElement) {
446
545
  }
447
546
  }
448
547
 
548
+ async _undoSelectedItems() {
549
+ // Get selected rows from grist
550
+ const selectedRecords = this.grist.selected
551
+
552
+ if (!selectedRecords || selectedRecords.length === 0) {
553
+ await CustomAlert({
554
+ type: 'info',
555
+ title: i18next.t('text.nothing_selected'),
556
+ text: i18next.t('text.please_select_items_to_undo')
557
+ })
558
+ return
559
+ }
560
+
561
+ // Confirm before deleting
562
+ const itemCount = selectedRecords.length
563
+ const itemText =
564
+ itemCount > 1
565
+ ? `${itemCount} items`
566
+ : `${selectedRecords[0].sku} (${selectedRecords[0].pickedQty} ${selectedRecords[0].packingType})`
567
+
568
+ const answer = await CustomAlert({
569
+ type: 'warning',
570
+ title: i18next.t('button.undo'),
571
+ text: i18next.t('text.are_you_sure_to_remove_x_from_tote', { x: itemText }),
572
+ confirmButton: {
573
+ text: i18next.t('button.confirm'),
574
+ color: '#ff9800'
575
+ },
576
+ cancelButton: {
577
+ text: i18next.t('button.cancel'),
578
+ color: '#cfcfcf'
579
+ }
580
+ })
581
+
582
+ if (!answer.value) return
583
+
584
+ try {
585
+ // Undo all selected items
586
+ for (const record of selectedRecords) {
587
+ await this._unsortItem(record.id, false) // Don't show individual toasts
588
+ }
589
+
590
+ // Show single success message for all items
591
+ this._showToast({
592
+ type: 'info',
593
+ message:
594
+ itemCount > 1
595
+ ? i18next.t('text.items_removed_from_tote', { count: itemCount })
596
+ : i18next.t('text.item_removed_from_tote')
597
+ })
598
+
599
+ // Refresh once after all items are removed
600
+ await this._fetchToteList()
601
+ await this.grist.fetch()
602
+ } catch (e) {
603
+ this._showToast(e)
604
+ }
605
+ }
606
+
607
+ async _unsortItem(orderToteItemId, showToast = true) {
608
+ try {
609
+ const response = await client.mutate({
610
+ mutation: gql`
611
+ mutation unsortItem($orderToteItemId: String!, $reason: String) {
612
+ unsortItem(orderToteItemId: $orderToteItemId, reason: $reason)
613
+ }
614
+ `,
615
+ variables: {
616
+ orderToteItemId,
617
+ reason: 'Removed by user from tote popup'
618
+ }
619
+ })
620
+
621
+ if (!response.errors) {
622
+ if (showToast) {
623
+ this._showToast({
624
+ type: 'info',
625
+ message: i18next.t('text.item_removed_from_tote')
626
+ })
627
+
628
+ // Refresh the tote list and grist
629
+ await this._fetchToteList()
630
+ await this.grist.fetch()
631
+ }
632
+ }
633
+ } catch (e) {
634
+ this._showToast(e)
635
+ throw e // Re-throw to stop batch processing
636
+ }
637
+ }
638
+
449
639
  _showToast({ type, message }) {
450
640
  document.dispatchEvent(
451
641
  new CustomEvent('notify', {
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Mutation = exports.Query = void 0;
4
4
  const get_loading_task_1 = require("./get-loading-task");
5
5
  const sort_item_1 = require("./sort-item");
6
+ const unsort_item_1 = require("./unsort-item");
6
7
  const find_loadable_release_good_1 = require("./find-loadable-release-good");
7
8
  const find_loadable_release_good_by_bin_1 = require("./find-loadable-release-good-by-bin");
8
9
  const loading_worksheet_v2_1 = require("./loading-worksheet-v2");
@@ -13,5 +14,5 @@ const undo_load_1 = require("./undo-load");
13
14
  const warehouse_return_1 = require("./warehouse-return");
14
15
  const complete_load_1 = require("./complete-load");
15
16
  exports.Query = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, find_loadable_release_good_1.findLoadableReleaseGood), find_loadable_release_good_by_bin_1.findLoadableReleaseGoodByBin), loading_worksheet_v2_1.loadingWorksheetv2), my_loading_assignment_status_1.myLoadingAssignmentStatus), get_delivery_orders_1.getDeliveryOrders);
16
- exports.Mutation = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, get_loading_task_1.getLoadingTask), sort_item_1.sortItem), load_by_qty_1.loadByQty), undo_load_1.undoLoad), warehouse_return_1.warehouseReturn), complete_load_1.completeLoad);
17
+ exports.Mutation = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, get_loading_task_1.getLoadingTask), sort_item_1.sortItem), unsort_item_1.unsortItem), load_by_qty_1.loadByQty), undo_load_1.undoLoad), warehouse_return_1.warehouseReturn), complete_load_1.completeLoad);
17
18
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../server/graphql/resolvers/outbound/index.ts"],"names":[],"mappings":";;;AAAA,yDAAmD;AACnD,2CAAsC;AACtC,6EAAsE;AACtE,2FAAkF;AAClF,iEAA2D;AAC3D,+CAAyC;AACzC,iFAA0E;AAC1E,+DAAyD;AACzD,2CAAsC;AACtC,yDAAoD;AACpD,mDAA8C;AAEjC,QAAA,KAAK,6EACb,oDAAuB,GACvB,gEAA4B,GAC5B,yCAAkB,GAClB,wDAAyB,GACzB,uCAAiB,EACrB;AAEY,QAAA,QAAQ,2FAChB,iCAAc,GACd,oBAAQ,GACR,uBAAS,GACT,oBAAQ,GACR,kCAAe,GACf,4BAAY,EAChB"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../server/graphql/resolvers/outbound/index.ts"],"names":[],"mappings":";;;AAAA,yDAAmD;AACnD,2CAAsC;AACtC,+CAA0C;AAC1C,6EAAsE;AACtE,2FAAkF;AAClF,iEAA2D;AAC3D,+CAAyC;AACzC,iFAA0E;AAC1E,+DAAyD;AACzD,2CAAsC;AACtC,yDAAoD;AACpD,mDAA8C;AAEjC,QAAA,KAAK,6EACb,oDAAuB,GACvB,gEAA4B,GAC5B,yCAAkB,GAClB,wDAAyB,GACzB,uCAAiB,EACrB;AAEY,QAAA,QAAQ,yGAChB,iCAAc,GACd,oBAAQ,GACR,wBAAU,GACV,uBAAS,GACT,oBAAQ,GACR,kCAAe,GACf,4BAAY,EAChB"}
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.unsortItem = void 0;
4
+ const typeorm_1 = require("typeorm");
5
+ const sales_base_1 = require("@things-factory/sales-base");
6
+ exports.unsortItem = {
7
+ async unsortItem(_, { orderToteItemId, reason }, context) {
8
+ var _a, _b;
9
+ const { domain, user, tx } = context.state;
10
+ // Find the order tote item with relations
11
+ const orderToteItem = (await tx.getRepository(sales_base_1.OrderToteItem).findOne({
12
+ where: { domain, id: orderToteItemId },
13
+ relations: ['orderTote', 'orderInventory']
14
+ }));
15
+ if (!orderToteItem) {
16
+ throw new Error('Order tote item not found');
17
+ }
18
+ // Check if tote is sealed - cannot undo if sealed
19
+ if ((_a = orderToteItem.orderTote) === null || _a === void 0 ? void 0 : _a.closedDate) {
20
+ throw new Error('Cannot remove item from sealed tote.');
21
+ }
22
+ const orderInventory = orderToteItem.orderInventory;
23
+ const qtyToRemove = orderToteItem.qty;
24
+ if (!orderInventory) {
25
+ throw new Error('Associated order inventory not found');
26
+ }
27
+ // Validate that we can reduce the sorted quantity
28
+ if (orderInventory.sortedQty < qtyToRemove) {
29
+ throw new Error(`Cannot remove ${qtyToRemove} items. Current sorted quantity is ${orderInventory.sortedQty}`);
30
+ }
31
+ // Calculate new sorted quantity
32
+ const newSortedQty = orderInventory.sortedQty - qtyToRemove;
33
+ // Determine new status - revert to PICKED if no more sorted items
34
+ let newStatus = orderInventory.status;
35
+ if (newSortedQty === 0 && orderInventory.status === sales_base_1.ORDER_INVENTORY_STATUS.LOADING) {
36
+ // Check if there are other order tote items for this order inventory
37
+ const otherToteItems = await tx.getRepository(sales_base_1.OrderToteItem).count({
38
+ where: {
39
+ domain,
40
+ orderInventory: { id: orderInventory.id },
41
+ id: (0, typeorm_1.Not)(orderToteItemId)
42
+ }
43
+ });
44
+ // Only revert to PICKED if this is the last tote item (no more sorted items)
45
+ if (otherToteItems === 0) {
46
+ newStatus = sales_base_1.ORDER_INVENTORY_STATUS.SORTING;
47
+ }
48
+ }
49
+ // Update the order inventory
50
+ await tx.getRepository(sales_base_1.OrderInventory).update(orderInventory.id, {
51
+ sortedQty: newSortedQty,
52
+ status: newStatus,
53
+ updatedAt: new Date(),
54
+ updater: user
55
+ });
56
+ // Delete the order tote item
57
+ await tx.getRepository(sales_base_1.OrderToteItem).delete(orderToteItem.id);
58
+ // Log the undo action if reason provided
59
+ if (reason) {
60
+ console.log(`[UNSORT] User ${user.name} removed ${qtyToRemove} items from tote ${(_b = orderToteItem.orderTote) === null || _b === void 0 ? void 0 : _b.name}. Reason: ${reason}`);
61
+ }
62
+ return true;
63
+ }
64
+ };
65
+ //# sourceMappingURL=unsort-item.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unsort-item.js","sourceRoot":"","sources":["../../../../server/graphql/resolvers/outbound/unsort-item.ts"],"names":[],"mappings":";;;AAAA,qCAA4C;AAG5C,2DAAkG;AAErF,QAAA,UAAU,GAAG;IACxB,KAAK,CAAC,UAAU,CAAC,CAAM,EAAE,EAAE,eAAe,EAAE,MAAM,EAAE,EAAE,OAAY;;QAChE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,GAAsD,OAAO,CAAC,KAAK,CAAA;QAE7F,0CAA0C;QAC1C,MAAM,aAAa,GAAG,CAAC,MAAM,EAAE,CAAC,aAAa,CAAC,0BAAa,CAAC,CAAC,OAAO,CAAC;YACnE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,eAAe,EAAE;YACtC,SAAS,EAAE,CAAC,WAAW,EAAE,gBAAgB,CAAC;SAC3C,CAAC,CAAyB,CAAA;QAE3B,IAAI,CAAC,aAAa,EAAE;YAClB,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAA;SAC7C;QAED,kDAAkD;QAClD,IAAI,MAAA,aAAa,CAAC,SAAS,0CAAE,UAAU,EAAE;YACvC,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAA;SACxD;QAED,MAAM,cAAc,GAAmB,aAAa,CAAC,cAAc,CAAA;QACnE,MAAM,WAAW,GAAG,aAAa,CAAC,GAAG,CAAA;QAErC,IAAI,CAAC,cAAc,EAAE;YACnB,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAA;SACxD;QAED,kDAAkD;QAClD,IAAI,cAAc,CAAC,SAAS,GAAG,WAAW,EAAE;YAC1C,MAAM,IAAI,KAAK,CAAC,iBAAiB,WAAW,sCAAsC,cAAc,CAAC,SAAS,EAAE,CAAC,CAAA;SAC9G;QAED,gCAAgC;QAChC,MAAM,YAAY,GAAG,cAAc,CAAC,SAAS,GAAG,WAAW,CAAA;QAE3D,kEAAkE;QAClE,IAAI,SAAS,GAAG,cAAc,CAAC,MAAM,CAAA;QACrC,IAAI,YAAY,KAAK,CAAC,IAAI,cAAc,CAAC,MAAM,KAAK,mCAAsB,CAAC,OAAO,EAAE;YAClF,qEAAqE;YACrE,MAAM,cAAc,GAAG,MAAM,EAAE,CAAC,aAAa,CAAC,0BAAa,CAAC,CAAC,KAAK,CAAC;gBACjE,KAAK,EAAE;oBACL,MAAM;oBACN,cAAc,EAAE,EAAE,EAAE,EAAE,cAAc,CAAC,EAAE,EAAE;oBACzC,EAAE,EAAE,IAAA,aAAG,EAAC,eAAe,CAAC;iBACzB;aACF,CAAC,CAAA;YAEF,6EAA6E;YAC7E,IAAI,cAAc,KAAK,CAAC,EAAE;gBACxB,SAAS,GAAG,mCAAsB,CAAC,OAAO,CAAA;aAC3C;SACF;QAED,6BAA6B;QAC7B,MAAM,EAAE,CAAC,aAAa,CAAC,2BAAc,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,EAAE;YAC/D,SAAS,EAAE,YAAY;YACvB,MAAM,EAAE,SAAS;YACjB,SAAS,EAAE,IAAI,IAAI,EAAE;YACrB,OAAO,EAAE,IAAI;SACd,CAAC,CAAA;QAEF,6BAA6B;QAC7B,MAAM,EAAE,CAAC,aAAa,CAAC,0BAAa,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC,CAAA;QAE9D,yCAAyC;QACzC,IAAI,MAAM,EAAE;YACV,OAAO,CAAC,GAAG,CACT,iBAAiB,IAAI,CAAC,IAAI,YAAY,WAAW,oBAAoB,MAAA,aAAa,CAAC,SAAS,0CAAE,IAAI,aAAa,MAAM,EAAE,CACxH,CAAA;SACF;QAED,OAAO,IAAI,CAAA;IACb,CAAC;CACF,CAAA"}
@@ -63,14 +63,17 @@ exports.loadingQcReport = {
63
63
  .leftJoin('order_totes', 'ot', 'ot.id = oti.order_tote_id')
64
64
  .leftJoin('order_tote_seals', 'ots', 'ots.order_tote_id = ot.id')
65
65
  .innerJoin('product_details', 'pd', 'oi.product_detail_id = pd.id')
66
- .where('rg.status = :status', { status: 'LOADING' })
67
- .andWhere('bizplace.id = :bizplaceId', { bizplaceId: bizplaceFilter.value })
66
+ .where('bizplace.id = :bizplaceId', { bizplaceId: bizplaceFilter.value })
68
67
  .andWhere('rg.release_date <= :toDate', { toDate: toDateFilter.value })
69
68
  .andWhere('rg.release_date >= :fromDate', { fromDate: fromDateFilter.value })
70
69
  .andWhere('w.type = :type', { type: 'LOADING' })
71
70
  .andWhere('rg.domain_id = :domainId', { domainId: domain.id })
71
+ .andWhere('rg.name IS NOT NULL')
72
+ .andWhere('rg.status NOT IN (:...excludedStatuses)', {
73
+ excludedStatuses: ['PENDING_CANCEL', 'CANCELLED', 'PENDING_WORKSHEET', 'READY_TO_PICK']
74
+ })
72
75
  .groupBy('bizplace.name')
73
- .addGroupBy('rg.name ')
76
+ .addGroupBy('rg.name')
74
77
  .addGroupBy('rg.route_id')
75
78
  .addGroupBy('rg.stop_id')
76
79
  .addGroupBy('rg.release_date')
@@ -99,15 +102,20 @@ exports.loadingQcReport = {
99
102
  console.timeEnd('loadingQcReport');
100
103
  items = items.reduce((prev, curr, idx) => {
101
104
  if (curr.tote) {
102
- let reducedItemIndex = prev.findIndex(itm => itm.releaseGoodNo == curr.releaseGoodNo && itm.tote == curr.tote);
105
+ // Find duplicate by releaseGoodNo, tote, and additional fields to ensure proper grouping
106
+ let reducedItemIndex = prev.findIndex(itm => itm.releaseGoodNo === curr.releaseGoodNo &&
107
+ itm.tote === curr.tote &&
108
+ itm.bizplaceName === curr.bizplaceName);
103
109
  if (reducedItemIndex == -1) {
104
- prev.push(curr);
105
- prev[prev.length - 1].totalSeal = 1;
110
+ // Ensure numeric fields are properly typed when adding new item
111
+ prev.push(Object.assign(Object.assign({}, curr), { orderQuantity: Number(curr.orderQuantity) || 0, totalCarton: Number(curr.totalCarton) || 0, totalSeal: curr.sealId ? 1 : 0 }));
106
112
  }
107
113
  else {
108
- prev[reducedItemIndex].orderQuantity += curr.orderQuantity;
109
- prev[reducedItemIndex].totalCarton += curr.totalCarton;
110
- if (!prev[reducedItemIndex].sealId.includes(curr.sealId)) {
114
+ // Aggregate quantities with explicit numeric conversion
115
+ prev[reducedItemIndex].orderQuantity += Number(curr.orderQuantity) || 0;
116
+ prev[reducedItemIndex].totalCarton += Number(curr.totalCarton) || 0;
117
+ // Concatenate seal IDs only if they're unique and not null
118
+ if (curr.sealId && !prev[reducedItemIndex].sealId.includes(curr.sealId)) {
111
119
  prev[reducedItemIndex].sealId = prev[reducedItemIndex].sealId.concat(', ', curr.sealId);
112
120
  prev[reducedItemIndex].totalSeal++;
113
121
  }
@@ -115,7 +123,8 @@ exports.loadingQcReport = {
115
123
  return prev;
116
124
  }
117
125
  else {
118
- prev.push(curr);
126
+ // Ensure numeric fields are properly typed for items without totes
127
+ prev.push(Object.assign(Object.assign({}, curr), { orderQuantity: Number(curr.orderQuantity) || 0, totalCarton: Number(curr.totalCarton) || 0, totalSeal: 0 }));
119
128
  return prev;
120
129
  }
121
130
  }, []);
@@ -1 +1 @@
1
- {"version":3,"file":"tote-loading-qc-report.js","sourceRoot":"","sources":["../../../../server/graphql/resolvers/reports/tote-loading-qc-report.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tote-loading-qc-report.js","sourceRoot":"","sources":["../../../../server/graphql/resolvers/reports/tote-loading-qc-report.ts"],"names":[],"mappings":"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"}
@@ -20,6 +20,10 @@ exports.Mutation = `
20
20
  worksheetDetails: [Object!]
21
21
  toteNo: String
22
22
  ): Boolean @transaction
23
+ unsortItem(
24
+ orderToteItemId: String!
25
+ reason: String
26
+ ): Boolean @transaction
23
27
  loadByQty(worksheetDetailPatch: LoadingWorksheetDetails): Boolean @transaction
24
28
  undoLoad(doId: String!): Boolean @transaction
25
29
  warehouseReturn (releaseGoodNo: String!, worksheetDetails: [Object!]): Worksheet @privilege(category: "worksheet_control", privilege: "mutation") @transaction
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../server/graphql/types/outbound/index.ts"],"names":[],"mappings":";;;AAAA,qEAAoF;AACpF,yEAAkE;AAClE,6DAA8D;AAEjD,QAAA,KAAK,GAAG;;;;;;CAMpB,CAAA;AAEY,QAAA,QAAQ,GAAG;;;;;;;;;;;;;;CAcvB,CAAA;AAEY,QAAA,KAAK,GAAG,CAAC,yCAAgB,EAAE,gDAAuB,EAAE,gDAAqB,EAAE,4CAAuB,CAAC,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../server/graphql/types/outbound/index.ts"],"names":[],"mappings":";;;AAAA,qEAAoF;AACpF,yEAAkE;AAClE,6DAA8D;AAEjD,QAAA,KAAK,GAAG;;;;;;CAMpB,CAAA;AAEY,QAAA,QAAQ,GAAG;;;;;;;;;;;;;;;;;;CAkBvB,CAAA;AAEY,QAAA,KAAK,GAAG,CAAC,yCAAgB,EAAE,gDAAuB,EAAE,gDAAqB,EAAE,4CAAuB,CAAC,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@things-factory/operato-wms",
3
- "version": "4.3.761",
3
+ "version": "4.3.762",
4
4
  "main": "dist-server/index.js",
5
5
  "browser": "client/index.js",
6
6
  "things-factory": true,
@@ -117,5 +117,5 @@
117
117
  "cypress-localstorage-commands": "^1.6.1",
118
118
  "eslint-plugin-cypress": "^2.12.1"
119
119
  },
120
- "gitHead": "ed2c237b4da43cdb1f9902ab9bfc6fbadb1cc53a"
120
+ "gitHead": "baadfe656ab39bd1a0623465d4e722e4f6afdbda"
121
121
  }
@@ -1,5 +1,6 @@
1
1
  import { getLoadingTask } from './get-loading-task'
2
2
  import { sortItem } from './sort-item'
3
+ import { unsortItem } from './unsort-item'
3
4
  import { findLoadableReleaseGood } from './find-loadable-release-good'
4
5
  import { findLoadableReleaseGoodByBin } from './find-loadable-release-good-by-bin'
5
6
  import { loadingWorksheetv2 } from './loading-worksheet-v2'
@@ -21,6 +22,7 @@ export const Query = {
21
22
  export const Mutation = {
22
23
  ...getLoadingTask,
23
24
  ...sortItem,
25
+ ...unsortItem,
24
26
  ...loadByQty,
25
27
  ...undoLoad,
26
28
  ...warehouseReturn,
@@ -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
@@ -1907,6 +1907,13 @@
1907
1907
  "text.tote_is_not_scanned": "tote is not scanned",
1908
1908
  "text.tote_number": "tote number",
1909
1909
  "text.tote_status_does_not_exist": "tote status does not exist",
1910
+ "text.are_you_sure_to_remove_x_from_tote": "are you sure you want to remove {x} from this tote?",
1911
+ "text.item_removed_from_tote": "item removed from tote",
1912
+ "text.items_removed_from_tote": "{count} items removed from tote",
1913
+ "text.nothing_selected": "nothing selected",
1914
+ "text.please_select_items_to_undo": "please select items to undo",
1915
+ "text.viewing_items_in_tote": "viewing items in tote",
1916
+ "text.list_refreshed": "list refreshed",
1910
1917
  "text.tracking_no_added_successfully": "tracking no added successfully",
1911
1918
  "text.tracking_no_already_exist_in_manifest_list": "tracking no already exist in manifest list",
1912
1919
  "text.tracking_no_already_exist_in_other_manifest_list": "tracking no already exist in other manifest list",
@@ -1892,6 +1892,12 @@
1892
1892
  "text.tote_is_not_scanned": "[ko] tote is not scanned",
1893
1893
  "text.tote_number": "[ko] tote number",
1894
1894
  "text.tote_status_does_not_exist": "[ko] tote status does not exist",
1895
+ "text.are_you_sure_to_remove_x_from_tote": "[ko] are you sure you want to remove {x} from this tote?",
1896
+ "text.item_removed_from_tote": "[ko] item removed from tote",
1897
+ "text.items_removed_from_tote": "[ko] {count} items removed from tote",
1898
+ "text.please_select_items_to_undo": "[ko] please select items to undo",
1899
+ "text.viewing_items_in_tote": "[ko] viewing items in tote",
1900
+ "text.list_refreshed": "[ko] list refreshed",
1895
1901
  "text.tracking_no_added_successfully": "[ko] tracking no added successfully",
1896
1902
  "text.tracking_no_already_exist_in_manifest_list": "[ko] tracking no already exist in manifest list",
1897
1903
  "text.tracking_no_already_exist_in_other_manifest_list": "[ko]tracking no already exist in other manifest list",
@@ -1944,6 +1944,12 @@
1944
1944
  "text.tote_is_not_scanned": "kotak tote tidak dipindai",
1945
1945
  "text.tote_number": "nombor tote",
1946
1946
  "text.tote_status_does_not_exist": "status tote tidak wujud",
1947
+ "text.are_you_sure_to_remove_x_from_tote": "[ms] are you sure you want to remove {x} from this tote?",
1948
+ "text.item_removed_from_tote": "[ms] item removed from tote",
1949
+ "text.items_removed_from_tote": "[ms] {count} items removed from tote",
1950
+ "text.please_select_items_to_undo": "[ms] please select items to undo",
1951
+ "text.viewing_items_in_tote": "[ms] viewing items in tote",
1952
+ "text.list_refreshed": "[ms] list refreshed",
1947
1953
  "text.tracking_no_added_successfully": "no. penjejak telah ditambah",
1948
1954
  "text.tracking_no_already_exist_in_manifest_list": "no. penjejak sudah wujud dalam senarai manifest",
1949
1955
  "text.tracking_no_already_exist_in_other_manifest_list": "no. penjejak sudah wujud dalam senarai manifest lain",
@@ -1977,6 +1977,12 @@
1977
1977
  "text.tote_is_not_scanned": "箱子未扫描",
1978
1978
  "text.tote_number": "箱子编号",
1979
1979
  "text.tote_status_does_not_exist": "箱子状态不存在",
1980
+ "text.are_you_sure_to_remove_x_from_tote": "[zh] are you sure you want to remove {x} from this tote?",
1981
+ "text.item_removed_from_tote": "[zh] item removed from tote",
1982
+ "text.items_removed_from_tote": "[zh] {count} items removed from tote",
1983
+ "text.please_select_items_to_undo": "[zh] please select items to undo",
1984
+ "text.viewing_items_in_tote": "[zh] viewing items in tote",
1985
+ "text.list_refreshed": "[zh] list refreshed",
1980
1986
  "text.tracking_no_added_successfully": "跟踪号已添加成功",
1981
1987
  "text.tracking_no_already_exist_in_manifest_list": "跟踪号已存在于清单列表中",
1982
1988
  "text.tracking_no_already_exist_in_other_manifest_list": "跟踪号已存在于其他清单列表中",