@things-factory/operato-wms 4.3.769 → 4.3.770

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.
Files changed (42) hide show
  1. package/client/pages/components/list-view/product-list-view.js +28 -3
  2. package/client/pages/components/mobile-condition-of-goods-listing.js +342 -0
  3. package/client/pages/components/unloading-worksheet-information-popup.js +299 -0
  4. package/client/pages/constants/order.js +7 -0
  5. package/client/pages/inbound/condition-of-goods-popup.js +646 -0
  6. package/client/pages/inbound/putaway/putaway-product.js +35 -6
  7. package/client/pages/inbound/unload-product-landing-page.js +282 -0
  8. package/client/pages/inbound/unload-product.js +707 -175
  9. package/client/pages/inbound/unloaded-inventories-popup.js +3 -0
  10. package/client/pages/inventory/inventory-adjustment-approval.js +28 -1
  11. package/client/pages/inventory/inventory-adjustment.js +31 -1
  12. package/client/pages/inventory/inventory-by-product-detail.js +15 -0
  13. package/client/pages/inventory/inventory-history.js +18 -0
  14. package/client/pages/inventory/onhand-inventory.js +14 -0
  15. package/client/pages/order/release-order/b2b/b2b-order-list.js +99 -0
  16. package/client/pages/order/release-order/packing-label-history-popup.js +378 -0
  17. package/client/pages/order/release-order/preview-print-packing-list.js +533 -0
  18. package/client/pages/order/release-order/print-quantity-popup.js +118 -0
  19. package/client/pages/outbound/loading-v2/loading-execution-base.js +29 -0
  20. package/client/pages/outbound/loading-v2/loading-execution.js +579 -2
  21. package/client/pages/outbound/loading-v2/loading-package-info-popup.js +182 -0
  22. package/client/pages/outbound/loading-v2/loading.js +18 -0
  23. package/client/pages/report/inbound-order-details-report.js +26 -1
  24. package/client/route.js +17 -0
  25. package/dist-server/graphql/resolvers/outbound/find-loadable-release-good-by-bin.js +9 -1
  26. package/dist-server/graphql/resolvers/outbound/find-loadable-release-good-by-bin.js.map +1 -1
  27. package/dist-server/graphql/resolvers/outbound/loading-worksheet-v2.js +11 -5
  28. package/dist-server/graphql/resolvers/outbound/loading-worksheet-v2.js.map +1 -1
  29. package/dist-server/graphql/resolvers/reports/inbound-order-details-report.js +2 -1
  30. package/dist-server/graphql/resolvers/reports/inbound-order-details-report.js.map +1 -1
  31. package/dist-server/graphql/types/reports/inbound-order-details-report.js +1 -0
  32. package/dist-server/graphql/types/reports/inbound-order-details-report.js.map +1 -1
  33. package/package.json +15 -15
  34. package/server/graphql/resolvers/outbound/find-loadable-release-good-by-bin.ts +9 -1
  35. package/server/graphql/resolvers/outbound/loading-worksheet-v2.ts +13 -1
  36. package/server/graphql/resolvers/reports/inbound-order-details-report.ts +2 -1
  37. package/server/graphql/types/reports/inbound-order-details-report.ts +1 -0
  38. package/things-factory.config.js +8 -0
  39. package/translations/en.json +45 -1
  40. package/translations/ko.json +40 -0
  41. package/translations/ms.json +40 -0
  42. package/translations/zh.json +40 -0
@@ -121,14 +121,20 @@ const FIND_LOADABLE_RELEASE_GOOD_BY_BIN = gql`
121
121
  batchId
122
122
  packingType
123
123
  refWorksheetId
124
+ packedQty
125
+ releaseQty
124
126
  product {
125
127
  id
126
128
  sku
127
129
  name
130
+ isInventoryDecimal
128
131
  }
129
132
  productDetail {
130
133
  id
131
134
  }
135
+ orderProduct {
136
+ id
137
+ }
132
138
  }
133
139
  }
134
140
  }
@@ -182,14 +188,20 @@ const LOADING_WORKSHEET_V2 = gql`
182
188
  batchId
183
189
  packingType
184
190
  refWorksheetId
191
+ packedQty
192
+ releaseQty
185
193
  product {
186
194
  id
187
195
  sku
188
196
  name
197
+ isInventoryDecimal
189
198
  }
190
199
  productDetail {
191
200
  id
192
201
  }
202
+ orderProduct {
203
+ id
204
+ }
193
205
  }
194
206
  }
195
207
  }
@@ -519,6 +531,18 @@ export class LoadingExecutionBase extends LitElement {
519
531
  }
520
532
  }
521
533
 
534
+ get groupPackingListButton() {
535
+ // Only return button when active tab is LOADING
536
+ if (this.state?.activeTab !== TAB_TYPES.LOADING) {
537
+ return null
538
+ }
539
+ return {
540
+ title: i18next.t('button.group_packing_list'),
541
+ action: async () => {},
542
+ ...CommonButtonStyles.inspect
543
+ }
544
+ }
545
+
522
546
  // Input Getters
523
547
  get productBarcodeInput() {
524
548
  return this.shadowRoot
@@ -1152,6 +1176,11 @@ export class LoadingExecutionBase extends LitElement {
1152
1176
  if (this._useQcSku) {
1153
1177
  buttons.unshift(this.orderListButton)
1154
1178
  }
1179
+ // Only add button if getter returns a valid button (checks activeTab internally)
1180
+ const groupPackingButton = this.groupPackingListButton
1181
+ if (groupPackingButton) {
1182
+ buttons.unshift(groupPackingButton)
1183
+ }
1155
1184
  buttons.unshift(this.warehouseReturnButton)
1156
1185
  buttons.unshift(this.loadButton)
1157
1186
  }
@@ -9,7 +9,11 @@ import { isMobileDevice } from '@things-factory/utils'
9
9
  import { LoadingExecutionBase } from './loading-execution-base'
10
10
  import '../../components/list-view/product-list-view'
11
11
  import { fetchSettingRule } from '../../../fetch-setting-value'
12
- import { client, gqlContext } from '@things-factory/shell'
12
+ import { CommonButtonStyles } from '@things-factory/styles'
13
+ import { client, CustomAlert, gqlContext } from '@things-factory/shell'
14
+ import { openPopup } from '@things-factory/layout-base'
15
+ import { showToast } from '../../../util'
16
+ import './loading-package-info-popup'
13
17
 
14
18
  // Constants
15
19
  const SETTINGS = {
@@ -37,6 +41,61 @@ const VALIDATE_QC_SEALS = gql`
37
41
  }
38
42
  `
39
43
 
44
+ const GROUP_PACKING_TAB_TYPES = {
45
+ SKU: 'SKU',
46
+ PACKING_LIST: 'Packing Label'
47
+ }
48
+
49
+ const GROUP_PACKING_TABS = [GROUP_PACKING_TAB_TYPES.SKU, GROUP_PACKING_TAB_TYPES.PACKING_LIST]
50
+
51
+ const CREATE_GROUP_LOADING_PACKAGES = gql`
52
+ mutation createGroupLoadingPackages($releaseGoodNo: String!, $groupedItems: [GroupLoadingPackageItem!]!) {
53
+ createGroupLoadingPackages(releaseGoodNo: $releaseGoodNo, groupedItems: $groupedItems) {
54
+ id
55
+ name
56
+ status
57
+ loadingPackageItems {
58
+ id
59
+ name
60
+ releaseQty
61
+ orderProduct {
62
+ id
63
+ }
64
+ }
65
+ }
66
+ }
67
+ `
68
+
69
+ const GET_LOADING_PACKAGES = gql`
70
+ query loadingPackagesByReleaseGoodNo($releaseGoodNo: String!) {
71
+ loadingPackagesByReleaseGoodNo(releaseGoodNo: $releaseGoodNo) {
72
+ id
73
+ name
74
+ status
75
+ createdAt
76
+ loadingPackageItems {
77
+ id
78
+ name
79
+ packedQty
80
+ orderProduct {
81
+ id
82
+ name
83
+ packingType
84
+ product {
85
+ id
86
+ name
87
+ sku
88
+ }
89
+ }
90
+ productDetail {
91
+ id
92
+ packingType
93
+ }
94
+ }
95
+ }
96
+ }
97
+ `
98
+
40
99
  // List View Configurations
41
100
  const QC_LIST_CONFIG = {
42
101
  selectable: true,
@@ -134,6 +193,65 @@ const LOADING_LIST_CONFIG = {
134
193
  }
135
194
  }
136
195
 
196
+ const SKU_LIST_CONFIG = {
197
+ selectable: true,
198
+ columnLeft: {
199
+ size: 8,
200
+ fields: [
201
+ {
202
+ type: 'row',
203
+ content: [
204
+ {
205
+ header: 'SKU No.',
206
+ field: 'relatedOrderInv.product.sku',
207
+ type: 'string'
208
+ }
209
+ ]
210
+ },
211
+ {
212
+ type: 'row',
213
+ content: [
214
+ {
215
+ header: 'Product Name',
216
+ field: 'relatedOrderInv.product.name',
217
+ type: 'string',
218
+ style: '-webkit-line-clamp: 2;'
219
+ }
220
+ ]
221
+ },
222
+ {
223
+ type: 'row',
224
+ content: [
225
+ {
226
+ header: 'Packing Type',
227
+ field: 'relatedOrderInv.packingType',
228
+ type: 'string'
229
+ }
230
+ ]
231
+ }
232
+ ]
233
+ },
234
+ columnRight: {
235
+ size: 4,
236
+ fields: [
237
+ {
238
+ type: 'row',
239
+ content: [
240
+ {
241
+ header: 'Total Qty.',
242
+ field: 'remainingQty',
243
+ type: 'string'
244
+ }
245
+ ]
246
+ },
247
+ {
248
+ type: 'editableValueBox',
249
+ content: { header: 'Group Qty.', field: 'groupQty', type: 'number', placeholder: 'e.g. 10', defaultValue: '' }
250
+ }
251
+ ]
252
+ }
253
+ }
254
+
137
255
  export class LoadingExecution extends LoadingExecutionBase {
138
256
  static get properties() {
139
257
  return {
@@ -141,7 +259,11 @@ export class LoadingExecution extends LoadingExecutionBase {
141
259
  _useQcSku: { type: Boolean },
142
260
  _currentReleaseGood: { type: Object },
143
261
  _tabCounts: { type: Object },
144
- _qcBannerState: { type: Object }
262
+ _qcBannerState: { type: Object },
263
+ _isGroupPackingMode: { type: Boolean },
264
+ _groupPackingActiveTab: { type: String },
265
+ _loadingPackages: { type: Array },
266
+ _combinedSkuData: { type: Array }
145
267
  }
146
268
  }
147
269
 
@@ -325,6 +447,9 @@ export class LoadingExecution extends LoadingExecutionBase {
325
447
  this._useQcSku = false
326
448
  this._currentReleaseGood = null
327
449
  this._qcBannerState = { show: false, needsSealing: false, minimumSealNumber: 0 }
450
+ this._isGroupPackingMode = false
451
+ this._loadingPackages = []
452
+ this._combinedSkuData = []
328
453
  this._deliveryOrderConfig = {
329
454
  columnLeft: {
330
455
  size: 8,
@@ -367,6 +492,7 @@ export class LoadingExecution extends LoadingExecutionBase {
367
492
  startedAt: this.worksheet?.startedAt
368
493
  }
369
494
  }
495
+
370
496
  // Update banner state when QC or loading data changes
371
497
  if (changedProperties.has('qcData') || changedProperties.has('loadingData')) {
372
498
  if (this._updateQcBannerState) {
@@ -375,6 +501,66 @@ export class LoadingExecution extends LoadingExecutionBase {
375
501
  }
376
502
  }
377
503
 
504
+ get groupPackingListButton() {
505
+ return {
506
+ title: i18next.t('button.group_packing_label'),
507
+ action: async () => {
508
+ if (this.state?.activeTab !== TAB_TYPES.LOADING) {
509
+ showToast({ message: i18next.t('text.only_available_on_loading_tab'), type: 'error' })
510
+ return
511
+ }
512
+
513
+ await this._fetchLoadingPackages()
514
+ this._calculateAndCombineSkuData()
515
+ this._isGroupPackingMode = true
516
+ this.getButton()
517
+ },
518
+ ...CommonButtonStyles.inspect
519
+ }
520
+ }
521
+
522
+ //===== OVERWRITE PARENT CLASS, FOR GROUP PACKING MODE =====
523
+ getButton() {
524
+ if (this._isGroupPackingMode) {
525
+ const actions = [
526
+ {
527
+ title: i18next.t('button.back'),
528
+ action: () => {
529
+ this._isGroupPackingMode = false
530
+ this.getButton()
531
+ },
532
+ ...CommonButtonStyles.back
533
+ },
534
+ {
535
+ title: i18next.t('button.group'),
536
+ action: async () => {
537
+ await this.handleGroupPackages()
538
+ },
539
+ ...CommonButtonStyles.submit
540
+ }
541
+ ]
542
+
543
+ this.parent.configContext(actions)
544
+ } else {
545
+ super.getButton()
546
+ }
547
+ }
548
+
549
+ get backButton() {
550
+ const base = super.backButton
551
+ return {
552
+ ...base,
553
+ action: () => {
554
+ if (this._isGroupPackingMode) {
555
+ this._groupPackingActiveTab = GROUP_PACKING_TAB_TYPES.SKU
556
+ this._isGroupPackingMode = false
557
+ } else {
558
+ base.action()
559
+ }
560
+ }
561
+ }
562
+ }
563
+
378
564
  combineSameProducts(data) {
379
565
  const combinedMap = new Map()
380
566
 
@@ -453,10 +639,137 @@ export class LoadingExecution extends LoadingExecutionBase {
453
639
  return LOADING_LIST_CONFIG
454
640
  }
455
641
 
642
+ get skuListItemConfig() {
643
+ return SKU_LIST_CONFIG
644
+ }
645
+
456
646
  get deliveryOrderConfig() {
457
647
  return this._deliveryOrderConfig
458
648
  }
459
649
 
650
+ _calculateAndCombineSkuData() {
651
+ if (!this.loadingData || this.loadingData.length === 0) {
652
+ this._combinedSkuData = []
653
+ return
654
+ }
655
+
656
+ // Step 1: Group loadingData by orderProductId and sum their releaseQty
657
+ const releaseQtyByOrderProductId = new Map()
658
+ this.loadingData.forEach(item => {
659
+ const orderProductId = item.relatedOrderInv?.orderProduct?.id
660
+ if (orderProductId) {
661
+ const currentReleaseQty = parseFloat(item.relatedOrderInv?.releaseQty || item.releaseQty) || 0
662
+ const existing = releaseQtyByOrderProductId.get(orderProductId) || 0
663
+ releaseQtyByOrderProductId.set(orderProductId, existing + currentReleaseQty)
664
+ }
665
+ })
666
+
667
+ // Step 2: Group loadingPackageItems by orderProductId and sum their packedQty
668
+ const packedQtyByOrderProductId = new Map()
669
+ if (this._loadingPackages && this._loadingPackages.length > 0) {
670
+ this._loadingPackages.forEach(pkg => {
671
+ if (pkg.loadingPackageItems && pkg.loadingPackageItems.length > 0) {
672
+ pkg.loadingPackageItems.forEach(item => {
673
+ const orderProductId = item.orderProduct?.id
674
+ if (orderProductId) {
675
+ const packedQty = parseFloat(item.packedQty) || 0
676
+ const existing = packedQtyByOrderProductId.get(orderProductId) || 0
677
+ packedQtyByOrderProductId.set(orderProductId, existing + packedQty)
678
+ }
679
+ })
680
+ }
681
+ })
682
+ }
683
+
684
+ // Step 3: Combine items by orderProductId and create simple array
685
+ const combinedMap = new Map()
686
+
687
+ this.loadingData.forEach(item => {
688
+ const orderProductId = item.relatedOrderInv?.orderProduct?.id
689
+ if (!orderProductId) return
690
+
691
+ if (!combinedMap.has(orderProductId)) {
692
+ const totalReleaseQty = releaseQtyByOrderProductId.get(orderProductId) || 0
693
+ const totalPackedQty = packedQtyByOrderProductId.get(orderProductId) || 0
694
+ const remainingQty = Math.max(0, totalReleaseQty - totalPackedQty)
695
+
696
+ // Create simple object with only needed fields
697
+ combinedMap.set(orderProductId, {
698
+ id: item.id, // Keep first item's id for selection
699
+ orderProductId: orderProductId,
700
+ remainingQty: remainingQty.toString(),
701
+ packedQty: totalPackedQty,
702
+ sku: item.relatedOrderInv?.product?.sku || '',
703
+ productName: item.relatedOrderInv?.product?.name || '',
704
+ packingType: item.relatedOrderInv?.packingType || '',
705
+ isInventoryDecimal: item.relatedOrderInv?.product?.isInventoryDecimal || false,
706
+ groupQty: null, // Reset to null (empty field, will use full availableQty)
707
+ relatedOrderInv: {
708
+ ...item.relatedOrderInv,
709
+ orderProduct: {
710
+ id: orderProductId
711
+ }
712
+ }
713
+ })
714
+ }
715
+ })
716
+
717
+ // Step 4: Filter out items with remainingQty === 0
718
+ this._combinedSkuData = Array.from(combinedMap.values()).filter(item => {
719
+ const remainingQty = parseFloat(item.remainingQty || 0)
720
+ return remainingQty > 0
721
+ })
722
+ }
723
+
724
+ get filteredSkuData() {
725
+ return this._combinedSkuData || []
726
+ }
727
+
728
+ get packingListConfig() {
729
+ return {
730
+ selectable: false,
731
+ columnLeft: {
732
+ size: 8,
733
+ fields: [
734
+ {
735
+ type: 'row',
736
+ content: [
737
+ {
738
+ header: 'Packing Label No.',
739
+ field: 'displayNumber',
740
+ type: 'number',
741
+ style: 'font-weight: bold;'
742
+ }
743
+ ]
744
+ }
745
+ ]
746
+ },
747
+ columnRight: {
748
+ size: 4,
749
+ fields: [
750
+ {
751
+ type: 'actionBox',
752
+ content: [
753
+ {
754
+ header: 'View Info',
755
+ btnClass: 'btn-common',
756
+ callback: rowData => {
757
+ const originalPackage = this._loadingPackages.find(pkg => pkg.id === rowData.id)
758
+ if (originalPackage) {
759
+ this.openLoadingPackageInfoPopup(originalPackage)
760
+ } else {
761
+ console.error('Loading package not found:', rowData.id)
762
+ showToast({ message: i18next.t('text.error_occurred') || 'Error loading package details', type: 'error' })
763
+ }
764
+ }
765
+ }
766
+ ]
767
+ }
768
+ ]
769
+ }
770
+ }
771
+ }
772
+
460
773
  /**
461
774
  * Determines if the "Go to LOADED" banner should be shown.
462
775
  * Banner appears when:
@@ -557,7 +870,271 @@ export class LoadingExecution extends LoadingExecutionBase {
557
870
  return this._qcBannerState?.show || false
558
871
  }
559
872
 
873
+ async openGroupPackingTab(e, tabName) {
874
+ if (this.state?.activeTab !== TAB_TYPES.LOADING) {
875
+ showToast({ message: i18next.t('text.only_available_on_loading_tab'), type: 'error' })
876
+ return
877
+ }
878
+
879
+ this._groupPackingActiveTab = tabName
880
+ await this.updateComplete
881
+
882
+ await this._fetchLoadingPackages()
883
+ if (tabName === GROUP_PACKING_TAB_TYPES.SKU) {
884
+ this._calculateAndCombineSkuData()
885
+ }
886
+ }
887
+
888
+ async _fetchLoadingPackages() {
889
+ const releaseGoodNo = this._currentReleaseGood?.releaseGood?.name || this.worksheet?.releaseGood?.name
890
+ if (!releaseGoodNo) {
891
+ console.warn('No release good number available to fetch loading packages')
892
+ this._loadingPackages = []
893
+ return
894
+ }
895
+
896
+ try {
897
+ const response = await client.query({
898
+ query: GET_LOADING_PACKAGES,
899
+ variables: { releaseGoodNo },
900
+ })
901
+
902
+ if (response.errors) {
903
+ throw new Error(response.errors[0]?.message || i18next.t('text.error_occurred'))
904
+ }
905
+
906
+ const packages = response.data.loadingPackagesByReleaseGoodNo || []
907
+ this._loadingPackages = packages.map((pkg, index) => ({
908
+ ...pkg,
909
+ displayNumber: index + 1
910
+ }))
911
+ this.requestUpdate()
912
+ } catch (error) {
913
+ console.error('Error fetching loading packages:', error)
914
+ showToast({ message: error.message || i18next.t('text.error_occurred'), type: 'error' })
915
+ this._loadingPackages = []
916
+ }
917
+ }
918
+
919
+
920
+ async openLoadingPackageInfoPopup(loadingPackage) {
921
+ if (!loadingPackage || !loadingPackage.loadingPackageItems || loadingPackage.loadingPackageItems.length === 0) {
922
+ showToast({ message: i18next.t('text.no_items_found') || 'No items found in this package', type: 'info' })
923
+ return
924
+ }
925
+
926
+ const items = loadingPackage.loadingPackageItems.map(item => ({
927
+ id: item.id,
928
+ sku: item.orderProduct?.product?.sku || '',
929
+ productName: item.orderProduct?.product?.name || item.orderProduct?.name || '',
930
+ packingType: item.productDetail?.packingType || item.orderProduct?.packingType || '',
931
+ qty: item.packedQty
932
+ }))
933
+
934
+ await openPopup(
935
+ html`
936
+ <loading-package-info-popup
937
+ ._data=${items}
938
+ ._packageName=${loadingPackage.name}
939
+ ._packageNumber=${loadingPackage.displayNumber}
940
+ ._packageId=${loadingPackage.id}
941
+ @undo=${async e => {
942
+ await this._fetchLoadingPackages()
943
+ this._calculateAndCombineSkuData()
944
+ this.requestUpdate()
945
+ }}
946
+ ></loading-package-info-popup>
947
+ `,
948
+ {
949
+ backdrop: true,
950
+ size: 'large',
951
+ title: `${i18next.t('text.packing_list_info') || 'Packing List Info'}: ${loadingPackage.name}`
952
+ }
953
+ )
954
+ }
955
+
956
+ async handleGroupPackages() {
957
+ try {
958
+ const skuListView = this.shadowRoot.querySelector('#sku')
959
+ if (!skuListView) {
960
+ showToast({ message: i18next.t('text.sku_list_view_not_found') })
961
+ return
962
+ }
963
+
964
+ const selectedItemIds = skuListView.selectedItems || []
965
+ if (selectedItemIds.length === 0) {
966
+ showToast({ message: i18next.t('text.no_sku_selected') })
967
+ return
968
+ }
969
+
970
+ const viewData = skuListView.data || []
971
+ const selectedItems = viewData.filter(item => selectedItemIds.includes(item.id))
972
+
973
+ if (selectedItems.length === 0) {
974
+ showToast({ message: i18next.t('text.selected_items_not_found') })
975
+ return
976
+ }
977
+
978
+ const groupedItems = selectedItems.map(item => {
979
+ const availableQty = parseFloat(item.remainingQty) || 0
980
+ // Check direct property first (from combined SKU data), then fallback to nested path
981
+ const isInventoryDecimal = item.isInventoryDecimal === true || item.relatedOrderInv?.product?.isInventoryDecimal === true
982
+ const productSku = item.sku || item.relatedOrderInv?.product?.sku || 'Unknown'
983
+
984
+ let groupQty
985
+
986
+ if (item.groupQty == null) {
987
+ groupQty = availableQty
988
+ } else {
989
+ const enteredQty = parseFloat(item.groupQty)
990
+
991
+ if (isNaN(enteredQty)) {
992
+ throw new Error(i18next.t('text.invalid_quantity_input') || 'Invalid quantity input')
993
+ } else if (enteredQty === 0) {
994
+ throw new Error(i18next.t('text.group_quantity_cannot_be_zero') || 'Group quantity cannot be zero')
995
+ } else if (enteredQty < 0) {
996
+ throw new Error(i18next.t('text.group_quantity_cannot_be_negative') || 'Group quantity cannot be negative')
997
+ } else {
998
+ groupQty = enteredQty
999
+ }
1000
+ }
1001
+
1002
+ // Validate decimal values - only allow decimals if isInventoryDecimal is true
1003
+ if (!isInventoryDecimal && !Number.isInteger(groupQty)) {
1004
+ throw new Error(
1005
+ i18next.t('text.decimal_not_allowed_for_product', { sku: productSku }) ||
1006
+ `Decimal quantity is not allowed for product ${productSku}`
1007
+ )
1008
+ }
1009
+
1010
+ // Validate groupQty doesn't exceed available quantity
1011
+ if (groupQty > availableQty) {
1012
+ throw new Error(i18next.t('text.group_quantity_exceeds_total'))
1013
+ }
1014
+
1015
+ return {
1016
+ orderProductId: item.orderProductId,
1017
+ groupQty: groupQty
1018
+ }
1019
+ })
1020
+
1021
+ const releaseGoodNo = this._currentReleaseGood?.releaseGood?.name
1022
+ if (!releaseGoodNo) {
1023
+ showToast({ message: i18next.t('text.release_good_number_not_found') })
1024
+ return
1025
+ }
1026
+
1027
+ const response = await client.mutate({
1028
+ mutation: CREATE_GROUP_LOADING_PACKAGES,
1029
+ variables: {
1030
+ releaseGoodNo: releaseGoodNo,
1031
+ groupedItems: groupedItems
1032
+ },
1033
+ context: gqlContext()
1034
+ })
1035
+
1036
+ if (response.errors) {
1037
+ throw new Error(response.errors[0]?.message || i18next.t('text.failed_to_create_group_loading_packages'))
1038
+ }
1039
+
1040
+ const loadingPackage = response.data.createGroupLoadingPackages
1041
+ showToast({
1042
+ message: i18next.t('text.new_packing_label_created'),
1043
+ type: 'success'
1044
+ })
1045
+
1046
+ if (this._isGroupPackingMode) {
1047
+ await this._fetchLoadingPackages()
1048
+ await this.updateComplete
1049
+ if (this._groupPackingActiveTab === GROUP_PACKING_TAB_TYPES.SKU) {
1050
+ this._calculateAndCombineSkuData()
1051
+ await this.updateComplete
1052
+ const skuListView = this.shadowRoot.querySelector('#sku')
1053
+ if (skuListView) {
1054
+ skuListView.selectedItems = []
1055
+ }
1056
+ }
1057
+ }
1058
+
1059
+ this.getButton()
1060
+ } catch (error) {
1061
+ console.error('Error creating group loading packages:', error)
1062
+ showToast({ message: error.message || i18next.t('text.failed_to_create_group_loading_packages'), type: 'error' })
1063
+ }
1064
+ }
1065
+
560
1066
  render() {
1067
+ if (this._isGroupPackingMode) {
1068
+ if (!this._groupPackingActiveTab) this._groupPackingActiveTab = GROUP_PACKING_TAB_TYPES.SKU
1069
+
1070
+ return html`
1071
+ <button
1072
+ class="order-info text-center"
1073
+ ?disabled=${!Boolean(this._currentReleaseGood?.releaseGood?.name)}
1074
+ @click=${e => {
1075
+ if (this._currentReleaseGood?.releaseGood?.name) {
1076
+ this.showOrderInfo()
1077
+ }
1078
+ }}
1079
+ >
1080
+ <label class="text-14 font-bold order-no"
1081
+ >${i18next.t('label.order_no')}: ${this._currentReleaseGood?.releaseGood?.name || this.worksheet?.binLocationName || ''}</label
1082
+ >
1083
+ <mwc-icon style="color:#007E7F;">info</mwc-icon>
1084
+ </button>
1085
+
1086
+ <div class="tabs">
1087
+ ${GROUP_PACKING_TABS.map(
1088
+ tab => html`
1089
+ <button
1090
+ class="font-bold tab-button ${this._groupPackingActiveTab === tab ? 'active' : ''}"
1091
+ @click=${async e => {
1092
+ await this.openGroupPackingTab(e, tab)
1093
+ }}
1094
+ >
1095
+ ${tab === GROUP_PACKING_TAB_TYPES.SKU ? i18next.t('label.sku') : i18next.t('label.packing_label')}
1096
+ </button>
1097
+ `
1098
+ )}
1099
+ </div>
1100
+
1101
+ ${this._groupPackingActiveTab === GROUP_PACKING_TAB_TYPES.SKU
1102
+ ? html`
1103
+ <div class="tab-info text-center">
1104
+ <label class="text-14 font-bold">${i18next.t('label.total_sku')}: ${this.filteredSkuData.length}</label>
1105
+ </div>
1106
+ `
1107
+ : ''}
1108
+
1109
+ ${this._groupPackingActiveTab === GROUP_PACKING_TAB_TYPES.PACKING_LIST
1110
+ ? html`
1111
+ <div class="tab-info text-center">
1112
+ <label class="text-14 font-bold">${i18next.t('label.total_packing_label')}: ${(this._loadingPackages || []).length}</label>
1113
+ </div>
1114
+ `
1115
+ : ''}
1116
+
1117
+ <div class="tab-content ${this._groupPackingActiveTab === GROUP_PACKING_TAB_TYPES.SKU ? 'active' : ''}">
1118
+ <product-list-view
1119
+ id="sku"
1120
+ .config=${this.skuListItemConfig}
1121
+ .data=${this.filteredSkuData}
1122
+ ></product-list-view>
1123
+ </div>
1124
+
1125
+ <div class="tab-content ${this._groupPackingActiveTab === GROUP_PACKING_TAB_TYPES.PACKING_LIST ? 'active' : ''}">
1126
+ ${this._loadingPackages && this._loadingPackages.length > 0
1127
+ ? html`
1128
+ <product-list-view
1129
+ .config=${this.packingListConfig}
1130
+ .data=${this._loadingPackages}
1131
+ ></product-list-view>
1132
+ `
1133
+ : ''}
1134
+ </div>
1135
+ `
1136
+ }
1137
+
561
1138
  if (!this.state) {
562
1139
  this.resetView()
563
1140
  }