@things-factory/operato-wms 4.3.736 → 4.3.737

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.
@@ -35,6 +35,114 @@ const toFloatOrUndefined = v => {
35
35
  return Number.isFinite(n) ? n : undefined
36
36
  }
37
37
 
38
+ // Import UI may produce human headers (e.g. "packing type") instead of GraphQL input keys (e.g. "packingType").
39
+ // GraphQL rejects unknown fields, so normalize/sanitize patches before submitting.
40
+ const INVENTORY_PATCH_KEYS = new Set([
41
+ 'id',
42
+ 'name',
43
+ 'bizplace',
44
+ 'refInventory',
45
+ 'bizplaceName',
46
+ 'palletId',
47
+ 'cartonId',
48
+ 'batchId',
49
+ 'batchIdRef',
50
+ 'product',
51
+ 'productDetail',
52
+ 'sku',
53
+ 'brand',
54
+ 'productName',
55
+ 'productDetailName',
56
+ 'productDetailId',
57
+ 'reusablePallet',
58
+ 'reusablePalletId',
59
+ 'location',
60
+ 'locationName',
61
+ 'warehouse',
62
+ 'warehouseName',
63
+ 'packingType',
64
+ 'packingSize',
65
+ 'otherRef',
66
+ 'transactionType',
67
+ 'details',
68
+ 'zone',
69
+ 'weight',
70
+ 'uom',
71
+ 'uomValue',
72
+ 'qty',
73
+ 'status',
74
+ 'description',
75
+ 'remark',
76
+ 'expirationDate',
77
+ 'manufactureDate',
78
+ 'unitCost',
79
+ 'adjustmentCode',
80
+ 'adjustmentNote',
81
+ 'inventoryItemChangesJson',
82
+ 'serialNumbers',
83
+ 'updatedAt',
84
+ 'updater',
85
+ 'cuFlag',
86
+ 'transferQty',
87
+ 'transferUomValue',
88
+ 'obsolete'
89
+ ])
90
+
91
+ const toCamelKey = key =>
92
+ String(key)
93
+ .trim()
94
+ .replace(/[_-]+/g, ' ')
95
+ .replace(/\s+([a-zA-Z0-9])/g, (_, c) => String(c).toUpperCase())
96
+ .replace(/^\w/, c => c.toLowerCase())
97
+
98
+ const normalizeInventoryPatch = patch => {
99
+ if (!patch || typeof patch !== 'object') return patch
100
+
101
+ const headerKeyMap = {
102
+ 'packing type': 'packingType',
103
+ 'packing size': 'packingSize',
104
+ 'uom value': 'uomValue',
105
+ 'unit cost': 'unitCost',
106
+ 'batch id': 'batchId',
107
+ 'batch no': 'batchId',
108
+ 'batch no.': 'batchId',
109
+ 'batch id ref': 'batchIdRef',
110
+ 'batch no ref': 'batchIdRef',
111
+ 'batch no. ref': 'batchIdRef'
112
+ }
113
+
114
+ const normalized = {}
115
+
116
+ Object.entries(patch).forEach(([rawKey, value]) => {
117
+ const lower = String(rawKey).trim().toLowerCase()
118
+ let key = headerKeyMap[lower] || rawKey
119
+
120
+ if (!INVENTORY_PATCH_KEYS.has(key)) {
121
+ const camel = toCamelKey(rawKey)
122
+ if (INVENTORY_PATCH_KEYS.has(camel)) key = camel
123
+ }
124
+
125
+ if (!INVENTORY_PATCH_KEYS.has(key)) return
126
+
127
+ // prefer already-correct keys if both exist
128
+ if (normalized[key] === undefined) normalized[key] = value
129
+ })
130
+
131
+ // sanitize nested refs to what GraphQL expects
132
+ if (normalized.bizplace && normalized.bizplace.id) normalized.bizplace = { id: normalized.bizplace.id }
133
+ if (normalized.location && normalized.location.id) {
134
+ normalized.location = { id: normalized.location.id, name: normalized.location.name }
135
+ }
136
+ if (normalized.product && normalized.product.id) normalized.product = { id: normalized.product.id }
137
+ if (normalized.productDetail && normalized.productDetail.id)
138
+ normalized.productDetail = { id: normalized.productDetail.id }
139
+
140
+ // ScalarDate cannot parse empty string; treat blank as undefined.
141
+ if (normalized.manufactureDate === '') delete normalized.manufactureDate
142
+
143
+ return normalized
144
+ }
145
+
38
146
  class InventoryAdjustment extends connect(store)(localize(i18next)(PageView)) {
39
147
  static get styles() {
40
148
  return [
@@ -1161,17 +1269,19 @@ class InventoryAdjustment extends connect(store)(localize(i18next)(PageView)) {
1161
1269
 
1162
1270
  async importHandler(patches) {
1163
1271
  try {
1272
+ patches = patches.map(patch => normalizeInventoryPatch(patch))
1273
+
1164
1274
  patches.map(itm => {
1165
- if (itm?.uomValue < 0 || itm?.uommValue?.toString() == NaN.toString()) {
1275
+ if (toFloatOrUndefined(itm?.uomValue) < 0) {
1166
1276
  throw new Error(i18next.t('text.invalid_uom_value'))
1167
1277
  }
1168
- if (itm?.qty < 0) {
1278
+ if (toFloatOrUndefined(itm?.qty) < 0) {
1169
1279
  throw new Error(i18next.t('text.invalid_qty'))
1170
1280
  }
1171
1281
  if (itm?.packingType?.trim() == '') {
1172
1282
  throw new Error(i18next.t('text.invalid_packing_type'))
1173
1283
  }
1174
- if (itm?.unitCost < 0) {
1284
+ if (toFloatOrUndefined(itm?.unitCost) < 0) {
1175
1285
  throw new Error(i18next.t('text.invalid_unit_cost'))
1176
1286
  }
1177
1287
  if (new Date(itm?.manufactureDate) > new Date()) {
@@ -1211,9 +1321,9 @@ class InventoryAdjustment extends connect(store)(localize(i18next)(PageView)) {
1211
1321
  throw new Error(i18next.t('text.invalid_value_in_list'))
1212
1322
  }
1213
1323
  }
1214
- itm.qty = parseFloat(itm.qty)
1215
- itm.packingSize = parseFloat(itm.packingSize)
1216
- itm.uomValue = parseFloat(itm.uomValue)
1324
+ itm.qty = toFloatOrUndefined(itm.qty)
1325
+ itm.packingSize = toFloatOrUndefined(itm.packingSize)
1326
+ itm.uomValue = toFloatOrUndefined(itm.uomValue)
1217
1327
  itm.transferQty = toFloatOrUndefined(itm.transferQty)
1218
1328
  itm.transferUomValue = toFloatOrUndefined(itm.transferUomValue)
1219
1329
 
@@ -1221,7 +1331,7 @@ class InventoryAdjustment extends connect(store)(localize(i18next)(PageView)) {
1221
1331
  itm.unitCost = null
1222
1332
  }
1223
1333
  if (itm.unitCost != null) {
1224
- itm.unitCost = parseFloat(itm.unitCost)
1334
+ itm.unitCost = toFloatOrUndefined(itm.unitCost)
1225
1335
  if (isNaN(itm.unitCost)) {
1226
1336
  throw new Error(i18next.t('text.invalid_unit_cost'))
1227
1337
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@things-factory/operato-wms",
3
- "version": "4.3.736",
3
+ "version": "4.3.737",
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": "02dc436ab7770e7186c50311b0d3c844d847b2ab"
120
+ "gitHead": "e6f8a64149623c60ac264af2d2060bbe823e1d36"
121
121
  }