@things-factory/operato-wms 4.3.656 → 4.3.660

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.
@@ -1,6 +1,7 @@
1
1
  import '@things-factory/biz-ui'
2
2
  import '@things-factory/grist-ui'
3
3
  import '@things-factory/import-ui'
4
+ import '@things-factory/warehouse-ui'
4
5
  import '../../components/select-product-popup'
5
6
  import '../../components/select-transport-vehicle-popup'
6
7
  import '../../order/vas-order/popup/vas-create-popup'
@@ -55,7 +56,8 @@ class CreateArrivalNotice extends localize(i18next)(PageView) {
55
56
  _bizplaceName: String,
56
57
  _showAddProducts: Boolean,
57
58
  _vasExpanded: Boolean,
58
- _transportVehicle: String
59
+ _transportVehicle: String,
60
+ enableDirectInbound: Boolean
59
61
  }
60
62
  }
61
63
 
@@ -421,6 +423,7 @@ class CreateArrivalNotice extends localize(i18next)(PageView) {
421
423
  this._showAddProducts = false
422
424
  this._vasExpanded = false
423
425
  this._transportVehicle = ''
426
+ this.enableDirectInbound = false
424
427
  }
425
428
 
426
429
  get arrivalNoticeForm() {
@@ -470,6 +473,7 @@ class CreateArrivalNotice extends localize(i18next)(PageView) {
470
473
  this._disableCrossDockingSetting = await fetchSettingRule('disable-cross-dock')
471
474
  this._hideCrossDockingSetting = await fetchSettingRule('hide-cross-dock')
472
475
  this._bizplaces = await this.fetchBizplaces()
476
+ this.enableDirectInbound = await fetchSettingRule('enable-direct-gan-order')
473
477
 
474
478
  this._validateTransport()
475
479
 
@@ -767,6 +771,49 @@ class CreateArrivalNotice extends localize(i18next)(PageView) {
767
771
  productGristColumns.splice(packQtyColumnIdx + 1, 0, ...crossDockingColumns)
768
772
  }
769
773
 
774
+ const expDateColumn = {
775
+ type: 'date',
776
+ name: 'expDate',
777
+ header: i18next.t('field.exp_date'),
778
+ imex: { key: 'expDate', width: 25, type: 'string' },
779
+ record: { editable: editable },
780
+ width: 150
781
+ }
782
+
783
+ const locationColumn = {
784
+ type: 'object',
785
+ name: 'location',
786
+ header: i18next.t('field.location'),
787
+ imex: { header: i18next.t('field.location'), key: 'location', width: 30, type: 'object' },
788
+ handlers: {
789
+ click: (columns, data, column, record, rowIndex) => {
790
+ this._openLocationSelection(rowIndex)
791
+ }
792
+ },
793
+ width: 150
794
+ }
795
+
796
+ const warehouseColumn = {
797
+ type: 'object',
798
+ name: 'warehouse',
799
+ header: i18next.t('field.warehouse'),
800
+ imex: { key: 'warehouse', width: 30, type: 'string' },
801
+ width: 150,
802
+ recordFormatter: (warehouse, updatedRecords) => warehouse?.name || ''
803
+ }
804
+
805
+ function insertAfter(cols, anchorName, newCols) {
806
+ const idx = cols.findIndex(c => c.name === anchorName)
807
+ if (idx >= 0) cols.splice(idx + 1, 0, ...newCols)
808
+ }
809
+
810
+ if (this.enableDirectInbound) {
811
+ const anchor = this._enableLotIdInput ? 'palletId' : 'palletQty'
812
+ insertAfter(productGristColumns, anchor, [expDateColumn])
813
+
814
+ insertAfter(productGristColumns, 'batchIdRef', [warehouseColumn, locationColumn])
815
+ }
816
+
770
817
  this.productGristConfig = {
771
818
  pagination: { infinite: true },
772
819
  list: { fields: ['batch_no', 'product', 'packingType', 'totalUomValue'] },
@@ -843,7 +890,8 @@ class CreateArrivalNotice extends localize(i18next)(PageView) {
843
890
  // update existing product data records
844
891
  this.productGrist.dirtyData.records.splice(rowIndex, 1, {
845
892
  ...this.productGrist.dirtyData.records[rowIndex],
846
- ...e.detail
893
+ ...e.detail,
894
+ isRequiredCheckExpiry: e.detail.product.isRequiredCheckExpiry
847
895
  })
848
896
 
849
897
  this.productGrist.dirtyData.records = this.productGrist.dirtyData.records.map(item => {
@@ -882,9 +930,57 @@ class CreateArrivalNotice extends localize(i18next)(PageView) {
882
930
  }
883
931
  }
884
932
 
933
+ _openLocationSelection(rowIndex) {
934
+ if (this._bizplaceId) {
935
+ openPopup(
936
+ html`
937
+ <buffer-location-selector
938
+ .bizplaceId="${this._bizplaceId}"
939
+ .enableDirectInbound="${this.enableDirectInbound}"
940
+ @selected="${async e => {
941
+ this.productGrist.dirtyData.records[rowIndex].location = { id: e.detail.id, name: e.detail.name }
942
+ this.productGrist.dirtyData.records[rowIndex].warehouse = {
943
+ id: e.detail.warehouse.id,
944
+ name: e.detail.warehouse.name
945
+ }
946
+ this.productGrist.dirtyData.records[rowIndex].__dirty__ = true
947
+
948
+ if (this.productGrist.dirtyData.records.length !== rowIndex) {
949
+ this.productGrist.dirtyData.records.splice(rowIndex, 1, {
950
+ ...this.productGrist.dirtyData.records[rowIndex]
951
+ })
952
+
953
+ this.productData = {
954
+ ...this.productData,
955
+ records: [...this.productGrist.dirtyData.records]
956
+ }
957
+
958
+ this.productGrist.data.records = this.productGrist.dirtyData.records
959
+ } else {
960
+ this.productData = {
961
+ ...this.productData,
962
+ records: [...this.productGrist.dirtyData.records]
963
+ }
964
+ }
965
+ }}"
966
+ ></buffer-location-selector>
967
+ `,
968
+ {
969
+ backdrop: true,
970
+ size: 'large',
971
+ title: i18next.t('title.select_location', 'Select Location')
972
+ }
973
+ )
974
+ } else {
975
+ this._showToast({ message: i18next.t('text.company_selection_is_empty') })
976
+ }
977
+ }
978
+
885
979
  _onProductChangeHandler(event) {
886
980
  try {
887
- this._checkProductDuplication()
981
+ if (!this.enableDirectInbound) {
982
+ this._checkProductDuplication
983
+ }
888
984
  let changeRecord = event.detail.after
889
985
  const changedColumn = event.detail.column.name
890
986
 
@@ -936,6 +1032,17 @@ class CreateArrivalNotice extends localize(i18next)(PageView) {
936
1032
  }
937
1033
  }
938
1034
 
1035
+ if (changedColumn === 'expDate') {
1036
+ if (!changeRecord.product?.isRequiredCheckExpiry) {
1037
+ delete changeRecord.expDate
1038
+ throw new Error(
1039
+ i18next.t('text.exp_date_not_required_for_this_product', {
1040
+ defaultValue: 'Expiry date is not required for this product'
1041
+ })
1042
+ )
1043
+ }
1044
+ }
1045
+
939
1046
  this._updateVasTargets(true)
940
1047
  } catch (e) {
941
1048
  const beforeValue = event.detail.before && event.detail.before[event.detail.column.name]
@@ -1047,6 +1154,34 @@ class CreateArrivalNotice extends localize(i18next)(PageView) {
1047
1154
  return calcedRecord
1048
1155
  }
1049
1156
 
1157
+ async fetchLocation() {
1158
+ const filter = []
1159
+ if (this.enableDirectInbound) {
1160
+ filter.push({
1161
+ name: 'type',
1162
+ operator: 'noteq',
1163
+ value: 'BIN'
1164
+ })
1165
+ }
1166
+ const response = await client.query({
1167
+ query: gql`
1168
+ query locations($filters: [Filter!]!) {
1169
+ locations(filters: $filters) {
1170
+ items {
1171
+ id
1172
+ name
1173
+ warehouse {
1174
+ name
1175
+ }
1176
+ }
1177
+ }
1178
+ }
1179
+ `,
1180
+ variables: { filters: filter }
1181
+ })
1182
+ return response.data.locations.items
1183
+ }
1184
+
1050
1185
  async fetchBizplaces() {
1051
1186
  const filters = []
1052
1187
  const response = await client.query({
@@ -1116,16 +1251,28 @@ class CreateArrivalNotice extends localize(i18next)(PageView) {
1116
1251
  delete arrivalNotice.bizplaceId
1117
1252
  delete arrivalNotice.bizplaceName
1118
1253
 
1119
- const response = await client.mutate({
1120
- mutation: gql`
1121
- mutation generateArrivalNotice($arrivalNotice: NewArrivalNotice!, $files: [Upload!]) {
1122
- generateArrivalNotice(arrivalNotice: $arrivalNotice, files: $files) {
1123
- id
1124
- name
1125
- crossDocking
1254
+ const mutation = this.enableDirectInbound
1255
+ ? gql`
1256
+ mutation submitDirectInboundArrivalNotice($arrivalNotice: NewArrivalNotice!, $files: [Upload!]) {
1257
+ submitDirectInboundArrivalNotice(arrivalNotice: $arrivalNotice, files: $files) {
1258
+ id
1259
+ name
1260
+ crossDocking
1261
+ }
1126
1262
  }
1127
- }
1128
- `,
1263
+ `
1264
+ : gql`
1265
+ mutation generateArrivalNotice($arrivalNotice: NewArrivalNotice!, $files: [Upload!]) {
1266
+ generateArrivalNotice(arrivalNotice: $arrivalNotice, files: $files) {
1267
+ id
1268
+ name
1269
+ crossDocking
1270
+ }
1271
+ }
1272
+ `
1273
+
1274
+ const response = await client.mutate({
1275
+ mutation,
1129
1276
  variables: {
1130
1277
  arrivalNotice: {
1131
1278
  ...arrivalNotice,
@@ -1139,8 +1286,13 @@ class CreateArrivalNotice extends localize(i18next)(PageView) {
1139
1286
 
1140
1287
  if (!response.errors) {
1141
1288
  this._clearView()
1142
- const ganNo = response.data.generateArrivalNotice.name
1143
- const isCrossDocking = response.data.generateArrivalNotice.crossDocking
1289
+
1290
+ const resultData = this.enableDirectInbound
1291
+ ? response.data.submitDirectInboundArrivalNotice
1292
+ : response.data.generateArrivalNotice
1293
+
1294
+ const ganNo = resultData.name
1295
+ const isCrossDocking = resultData.crossDocking
1144
1296
  if (!isCrossDocking) {
1145
1297
  navigate(`arrival_notice_detail/${ganNo}`)
1146
1298
  } else {
@@ -1260,7 +1412,9 @@ class CreateArrivalNotice extends localize(i18next)(PageView) {
1260
1412
  if (!records?.length) records = this.productGrist.dirtyData.records
1261
1413
  if (!records?.length) throw new Error(i18next.t('text.no_products'))
1262
1414
 
1263
- this._checkProductDuplication()
1415
+ if (!this.enableDirectInbound) {
1416
+ this._checkProductDuplication()
1417
+ }
1264
1418
 
1265
1419
  const checkRequiredFields = ({ batchId, packQty }) => !batchId || !packQty
1266
1420
 
@@ -1309,6 +1463,30 @@ class CreateArrivalNotice extends localize(i18next)(PageView) {
1309
1463
  })
1310
1464
  )
1311
1465
  }
1466
+
1467
+ if (this.enableDirectInbound) {
1468
+ records.forEach((record, index) => {
1469
+ if (this.enableDirectInbound && record?.product?.isRequiredCheckExpiry && !record.expDate) {
1470
+ throw new Error(
1471
+ i18next.t('text.exp_date_required_for_product', {
1472
+ defaultValue: `Row ${index + 1}: Expiry date is required for product "${record.product.name}"`,
1473
+ product: record.product.name,
1474
+ row: index + 1
1475
+ })
1476
+ )
1477
+ }
1478
+
1479
+ if (!record.location || !record.location.id) {
1480
+ throw new Error(
1481
+ i18next.t('text.location_required_for_product', {
1482
+ defaultValue: `Row ${index + 1}: Location is missing for product "${record.product?.name}"`,
1483
+ product: record.product.name,
1484
+ row: index + 1
1485
+ })
1486
+ )
1487
+ }
1488
+ })
1489
+ }
1312
1490
  }
1313
1491
 
1314
1492
  _validateVas() {
@@ -1409,7 +1587,10 @@ class CreateArrivalNotice extends localize(i18next)(PageView) {
1409
1587
  totalUomValue: record?.totalUomValue ? record?.totalUomValue : 0,
1410
1588
  unitPrice: record?.unitPrice ? record.unitPrice : 0,
1411
1589
  remark: record?.remark ? record.remark : null,
1590
+ expDate: record?.expDate ? record.expDate : null,
1412
1591
  manufactureDate: record?.manufactureDate ? record.manufactureDate : null,
1592
+ warehouse: record?.warehouse ? record.warehouse : null,
1593
+ location: record?.location ? record.location : null,
1413
1594
  palletId: record?.palletId ? record.palletId : null
1414
1595
  }
1415
1596
 
@@ -1692,6 +1873,23 @@ class CreateArrivalNotice extends localize(i18next)(PageView) {
1692
1873
  imex: { header: i18next.t('field.batch_id_ref'), key: 'batchIdRef', width: 25, type: 'string' },
1693
1874
  width: 100
1694
1875
  },
1876
+ ...(this.enableDirectInbound
1877
+ ? [
1878
+ {
1879
+ type: 'object',
1880
+ name: 'location',
1881
+ header: i18next.t('field.location'),
1882
+ imex: {
1883
+ header: i18next.t('field.location'),
1884
+ key: 'location.name',
1885
+ width: 30,
1886
+ type: 'array',
1887
+ arrData: []
1888
+ },
1889
+ width: 120
1890
+ }
1891
+ ]
1892
+ : []),
1695
1893
  {
1696
1894
  type: 'float',
1697
1895
  name: 'unitPrice',
@@ -1705,18 +1903,41 @@ class CreateArrivalNotice extends localize(i18next)(PageView) {
1705
1903
  header: i18next.t('field.remark'),
1706
1904
  imex: { header: i18next.t('field.remark'), key: 'remark', width: 25, type: 'string' },
1707
1905
  width: 100
1708
- }
1906
+ },
1907
+ ...(this.enableDirectInbound
1908
+ ? [
1909
+ {
1910
+ type: 'string',
1911
+ name: 'errMsg',
1912
+ header: i18next.t('field.error_message'),
1913
+ imex: { header: i18next.t('field.error_message'), key: 'errMsg', width: 25, type: 'string' },
1914
+ width: 350
1915
+ }
1916
+ ]
1917
+ : [])
1709
1918
  ]
1710
1919
 
1711
1920
  return productColumns
1712
1921
  }
1713
1922
 
1714
1923
  async _exportableData() {
1924
+ let location = await this.fetchLocation()
1715
1925
  try {
1716
1926
  var headerSetting = [
1717
1927
  ...this.excelColumns()
1718
1928
  .filter(column => column.type !== 'gutter' && column.imex !== undefined)
1719
1929
  .map(column => {
1930
+ if (this.enableDirectInbound && column.header == 'location') {
1931
+ location = location.map(item => {
1932
+ let newName = `${item.name} (${item.warehouse.name})`
1933
+ return {
1934
+ ...item,
1935
+ name: newName
1936
+ }
1937
+ })
1938
+
1939
+ column.imex.arrData = location
1940
+ }
1720
1941
  return column.imex
1721
1942
  })
1722
1943
  ]
@@ -1750,6 +1971,14 @@ class CreateArrivalNotice extends localize(i18next)(PageView) {
1750
1971
  productName
1751
1972
  productBrand
1752
1973
  isError
1974
+ warehouse {
1975
+ id
1976
+ name
1977
+ }
1978
+ location {
1979
+ id
1980
+ name
1981
+ }
1753
1982
  product {
1754
1983
  id
1755
1984
  name
@@ -1787,6 +2016,8 @@ class CreateArrivalNotice extends localize(i18next)(PageView) {
1787
2016
  }
1788
2017
  }
1789
2018
 
2019
+ // Validate for location
2020
+
1790
2021
  if (!foundErrors) {
1791
2022
  if (!response.errors) {
1792
2023
  const data = response.data.bulkUploadValidateOrderProducts.map(item => {
@@ -1828,14 +2059,13 @@ class CreateArrivalNotice extends localize(i18next)(PageView) {
1828
2059
  try {
1829
2060
  const orderProducts = patches.map(patch => {
1830
2061
  if (patch.manufactureDate) {
1831
- const mdt = new Date(patch.manufactureDate);
1832
- patch.manufactureDate = mdt < new Date()
1833
- ? `${mdt.getFullYear()}-${mdt.getMonth() + 1}-${mdt.getDate()}`
1834
- : ''
2062
+ const mdt = new Date(patch.manufactureDate)
2063
+ patch.manufactureDate = mdt < new Date() ? `${mdt.getFullYear()}-${mdt.getMonth() + 1}-${mdt.getDate()}` : ''
1835
2064
  } else {
1836
2065
  delete patch.manufactureDate
1837
2066
  }
1838
2067
  delete patch.cuFlag
2068
+ delete patch.errMsg
1839
2069
  return {
1840
2070
  ...patch,
1841
2071
  uomValue: Math.round(parseFloat(patch.uomValue) * 1000) / 1000 || 0,
@@ -1844,10 +2074,6 @@ class CreateArrivalNotice extends localize(i18next)(PageView) {
1844
2074
  unitPrice: patch.unitPrice ? parseFloat(patch.unitPrice) : null
1845
2075
  }
1846
2076
  })
1847
- // redundant as records also patched during bulkUploadValidateOrderProducts and we don't need it to write on grist before validation
1848
- // this.productData = {
1849
- // records: [...patches]
1850
- // }
1851
2077
  await this.bulkUploadValidateOrderProducts(orderProducts)
1852
2078
  history.back()
1853
2079
  } catch (e) {
@@ -1858,10 +2084,26 @@ class CreateArrivalNotice extends localize(i18next)(PageView) {
1858
2084
 
1859
2085
  async _importableData(records) {
1860
2086
  try {
2087
+ if (!this.enableDirectInbound && records.some(record => record.location)) {
2088
+ throw new Error(
2089
+ 'Location-based assignment is not allowed. Please delete the' +
2090
+ ' location ' +
2091
+ 'column or enable Direct GAN Order in settings.'
2092
+ )
2093
+ }
1861
2094
  if (this._bizplaceId) {
1862
2095
  records = records
1863
2096
  .filter(record => record.productSKU)
1864
2097
  .map(record => {
2098
+ let warehouseName
2099
+ if (this.enableDirectInbound) {
2100
+ const match = record.location.name.match(/(.*) \((.*)\)/)
2101
+ if (match && match.length === 3) {
2102
+ record.location.name = match[1].trim()
2103
+ warehouseName = match[2].trim()
2104
+ record = { ...record, warehouseName: warehouseName }
2105
+ }
2106
+ }
1865
2107
  return {
1866
2108
  ...record,
1867
2109
  unitPrice:
@@ -1869,24 +2111,24 @@ class CreateArrivalNotice extends localize(i18next)(PageView) {
1869
2111
  ? '0.00'
1870
2112
  : record.unitPrice === undefined
1871
2113
  ? null
1872
- : parseFloat(record.unitPrice).toFixed(2),
2114
+ : parseFloat(parseFloat(record.unitPrice).toFixed(2)),
1873
2115
  packQty:
1874
2116
  record.packQty == null && record.packQty !== undefined
1875
2117
  ? '0'
1876
2118
  : record.packQty === undefined
1877
2119
  ? null
1878
- : parseFloat(record.packQty).toFixed(3),
2120
+ : parseFloat(parseFloat(record.packQty).toFixed(3)),
1879
2121
  palletQty:
1880
2122
  record.palletQty == null && record.palletQty !== undefined
1881
- ? '0'
2123
+ ? parseInt('0')
1882
2124
  : record.palletQty === undefined
1883
2125
  ? null
1884
- : parseInt(record.palletQty)
2126
+ : parseInt(record.palletQty),
2127
+ uomValue: record.uomValue !== null && record.uomValue !== undefined ? parseFloat(record.uomValue) : ''
1885
2128
  }
1886
2129
  })
1887
2130
 
1888
2131
  this._validateProducts(records)
1889
-
1890
2132
  openPopup(
1891
2133
  html`
1892
2134
  <import-pop-up
@@ -1896,6 +2138,7 @@ class CreateArrivalNotice extends localize(i18next)(PageView) {
1896
2138
  columns: [...this.excelColumns().filter(column => column.imex !== undefined)]
1897
2139
  }}
1898
2140
  .importHandler="${await this.importHandler.bind(this)}"
2141
+ .enableDirectInbound=${this.enableDirectInbound}
1899
2142
  ></import-pop-up>
1900
2143
  `,
1901
2144
  {