@things-factory/operato-wms 4.3.767 → 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.
- package/client/pages/bulk-operation/validate-gan-popup.js +2 -2
- package/client/pages/components/list-view/product-list-view.js +28 -3
- package/client/pages/components/mobile-condition-of-goods-listing.js +342 -0
- package/client/pages/components/unloading-worksheet-information-popup.js +299 -0
- package/client/pages/constants/order.js +7 -0
- package/client/pages/inbound/condition-of-goods-popup.js +646 -0
- package/client/pages/inbound/putaway/putaway-product.js +35 -6
- package/client/pages/inbound/unload-product-landing-page.js +282 -0
- package/client/pages/inbound/unload-product.js +707 -175
- package/client/pages/inbound/unloaded-inventories-popup.js +3 -0
- package/client/pages/inventory/inventory-adjustment-approval.js +28 -1
- package/client/pages/inventory/inventory-adjustment.js +77 -44
- package/client/pages/inventory/inventory-by-product-detail.js +15 -0
- package/client/pages/inventory/inventory-history.js +18 -0
- package/client/pages/inventory/onhand-inventory.js +14 -0
- package/client/pages/order/arrival-notice/create-arrival-notice.js +209 -206
- package/client/pages/order/arrival-notice/duplicate-arrival-notice.js +132 -129
- package/client/pages/order/arrival-notice/edit-product-popup.js +97 -92
- package/client/pages/order/release-order/b2b/b2b-order-list.js +99 -0
- package/client/pages/order/release-order/packing-label-history-popup.js +378 -0
- package/client/pages/order/release-order/preview-print-packing-list.js +533 -0
- package/client/pages/order/release-order/print-quantity-popup.js +118 -0
- package/client/pages/outbound/loading-v2/loading-execution-base.js +29 -0
- package/client/pages/outbound/loading-v2/loading-execution.js +579 -2
- package/client/pages/outbound/loading-v2/loading-package-info-popup.js +182 -0
- package/client/pages/outbound/loading-v2/loading.js +18 -0
- package/client/pages/report/inbound-order-details-report.js +26 -1
- package/client/route.js +17 -0
- package/dist-server/graphql/resolvers/outbound/find-loadable-release-good-by-bin.js +9 -1
- package/dist-server/graphql/resolvers/outbound/find-loadable-release-good-by-bin.js.map +1 -1
- package/dist-server/graphql/resolvers/outbound/loading-worksheet-v2.js +11 -5
- package/dist-server/graphql/resolvers/outbound/loading-worksheet-v2.js.map +1 -1
- package/dist-server/graphql/resolvers/reports/inbound-order-details-report.js +2 -1
- package/dist-server/graphql/resolvers/reports/inbound-order-details-report.js.map +1 -1
- package/dist-server/graphql/types/reports/inbound-order-details-report.js +1 -0
- package/dist-server/graphql/types/reports/inbound-order-details-report.js.map +1 -1
- package/package.json +15 -15
- package/server/graphql/resolvers/outbound/find-loadable-release-good-by-bin.ts +9 -1
- package/server/graphql/resolvers/outbound/loading-worksheet-v2.ts +13 -1
- package/server/graphql/resolvers/reports/inbound-order-details-report.ts +2 -1
- package/server/graphql/types/reports/inbound-order-details-report.ts +1 -0
- package/things-factory.config.js +8 -0
- package/translations/en.json +45 -1
- package/translations/ko.json +40 -0
- package/translations/ms.json +40 -0
- package/translations/zh.json +40 -0
|
@@ -353,8 +353,8 @@ class ValidateGanPopup extends localize(i18next)(LitElement) {
|
|
|
353
353
|
containerNo: raw.containerNo,
|
|
354
354
|
containerSize: raw.containerSize,
|
|
355
355
|
sku: raw.sku,
|
|
356
|
-
batchId: raw.batchId,
|
|
357
|
-
batchIdRef: raw.batchIdRef,
|
|
356
|
+
batchId: raw.batchId ? raw.batchId.trim() : raw.batchId,
|
|
357
|
+
batchIdRef: raw.batchIdRef ? raw.batchIdRef.trim() : raw.batchIdRef,
|
|
358
358
|
packingType: raw.packingType,
|
|
359
359
|
packingSize: raw.packingSize,
|
|
360
360
|
uom: raw.uom,
|
|
@@ -6,6 +6,9 @@ class ProductListView extends localize(i18next)(LitElement) {
|
|
|
6
6
|
static get styles() {
|
|
7
7
|
return [
|
|
8
8
|
css`
|
|
9
|
+
:host {
|
|
10
|
+
--product-item-selected-bg: transparent;
|
|
11
|
+
}
|
|
9
12
|
.flex-col {
|
|
10
13
|
display: flex;
|
|
11
14
|
flex-direction: column;
|
|
@@ -38,6 +41,10 @@ class ProductListView extends localize(i18next)(LitElement) {
|
|
|
38
41
|
grid-gap: 3px;
|
|
39
42
|
color: #3a5877;
|
|
40
43
|
border-bottom: solid 0.5px #3a5877;
|
|
44
|
+
cursor: pointer;
|
|
45
|
+
}
|
|
46
|
+
.product-item[selected] {
|
|
47
|
+
background-color: var(--product-item-selected-bg);
|
|
41
48
|
}
|
|
42
49
|
.product-item-info {
|
|
43
50
|
grid-column: span 8;
|
|
@@ -159,7 +166,8 @@ class ProductListView extends localize(i18next)(LitElement) {
|
|
|
159
166
|
callback: Object,
|
|
160
167
|
_show: Boolean,
|
|
161
168
|
selectedItems: { type: Array },
|
|
162
|
-
selectAll: { type: Boolean }
|
|
169
|
+
selectAll: { type: Boolean },
|
|
170
|
+
selectedRecordId: { type: String, attribute: false }
|
|
163
171
|
}
|
|
164
172
|
}
|
|
165
173
|
|
|
@@ -183,12 +191,23 @@ class ProductListView extends localize(i18next)(LitElement) {
|
|
|
183
191
|
try {
|
|
184
192
|
itm = flattenObject(itm, '.')
|
|
185
193
|
|
|
194
|
+
const isSelected = this.selectedRecordId && itm.id === this.selectedRecordId
|
|
195
|
+
|
|
186
196
|
return html`
|
|
187
197
|
<div
|
|
188
198
|
class="product-item"
|
|
199
|
+
?selected=${isSelected}
|
|
189
200
|
style="grid-template-columns: repeat(${
|
|
190
201
|
this.config.columnLeft.size + this.config.columnRight.size + (this.config?.selectable ? 1 : 0)
|
|
191
202
|
}, 1fr) !important;"
|
|
203
|
+
@click=${e => {
|
|
204
|
+
if (e.target.closest('button') || e.target.closest('input') || e.target.closest('.action-box')) {
|
|
205
|
+
return
|
|
206
|
+
}
|
|
207
|
+
if (typeof this.config?.onRecordClick === 'function') {
|
|
208
|
+
this.config.onRecordClick(itm, e, index)
|
|
209
|
+
}
|
|
210
|
+
}}
|
|
192
211
|
>
|
|
193
212
|
${
|
|
194
213
|
this.config?.selectable
|
|
@@ -243,14 +262,20 @@ class ProductListView extends localize(i18next)(LitElement) {
|
|
|
243
262
|
case 'editableValueBox':
|
|
244
263
|
const data = itm[field.field]
|
|
245
264
|
const header = field.header
|
|
265
|
+
const placeholder = field.placeholder || ''
|
|
266
|
+
const defaultValue = field.defaultValue !== undefined ? field.defaultValue : 0
|
|
246
267
|
return html`
|
|
247
268
|
<div class="flex-col mt-5px">
|
|
248
269
|
${header != null || header != undefined ? html` <label class="product-item-info-title">${header}</label> ` : ``}
|
|
249
270
|
<div class="qty-box">
|
|
250
271
|
<input
|
|
251
272
|
class="input-field"
|
|
252
|
-
|
|
253
|
-
|
|
273
|
+
placeholder="${placeholder}"
|
|
274
|
+
.value="${data ? data : defaultValue}"
|
|
275
|
+
@change=${e => {
|
|
276
|
+
const val = e.target.value.trim()
|
|
277
|
+
this._handleValueChange(field.field, val === '' ? null : parseFloat(val), index)
|
|
278
|
+
}}
|
|
254
279
|
/>
|
|
255
280
|
</div>
|
|
256
281
|
</div>`
|
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
import { i18next, localize } from '@things-factory/i18n-base'
|
|
2
|
+
import { css, html, LitElement } from 'lit-element'
|
|
3
|
+
import { flattenObject } from '@things-factory/utils'
|
|
4
|
+
import '@material/mwc-icon'
|
|
5
|
+
|
|
6
|
+
class MobileConditionOfGoodsListing extends localize(i18next)(LitElement) {
|
|
7
|
+
static get properties() {
|
|
8
|
+
return {
|
|
9
|
+
config: Object,
|
|
10
|
+
fetchHandler: Function,
|
|
11
|
+
_data: Array,
|
|
12
|
+
_showSpinner: Boolean
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
constructor() {
|
|
17
|
+
super()
|
|
18
|
+
this._data = []
|
|
19
|
+
this._originalData = []
|
|
20
|
+
this._showSpinner = false
|
|
21
|
+
this._isExecuting = false // Flag to prevent fetching during confirmation
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
static get styles() {
|
|
25
|
+
return [
|
|
26
|
+
css`
|
|
27
|
+
:host {
|
|
28
|
+
display: flex;
|
|
29
|
+
flex-direction: column;
|
|
30
|
+
flex: 1;
|
|
31
|
+
overflow: hidden;
|
|
32
|
+
position: relative;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.list-container {
|
|
36
|
+
flex: 1;
|
|
37
|
+
overflow-y: auto;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.list-item {
|
|
41
|
+
padding: 12px;
|
|
42
|
+
color: #3a5877;
|
|
43
|
+
border-bottom: solid 0.5px #3a5877;
|
|
44
|
+
position: relative;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.list-item[dirty]::before {
|
|
48
|
+
content: '';
|
|
49
|
+
position: absolute;
|
|
50
|
+
left: 0;
|
|
51
|
+
top: 0;
|
|
52
|
+
width: 0;
|
|
53
|
+
height: 0;
|
|
54
|
+
border-top: 12px solid #4caf50;
|
|
55
|
+
border-right: 12px solid transparent;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.dirty-icon {
|
|
59
|
+
position: absolute;
|
|
60
|
+
left: 2px;
|
|
61
|
+
top: 2px;
|
|
62
|
+
color: white;
|
|
63
|
+
font-size: 12px;
|
|
64
|
+
z-index: 1;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.list-item:hover {
|
|
68
|
+
background-color: var(--grid-record-hover-background-color, #f0f0f0);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.list-item[selected] {
|
|
72
|
+
background-color: var(--grid-record-selected-background-color, #e3f2fd);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.field-row {
|
|
76
|
+
display: flex;
|
|
77
|
+
flex-direction: row;
|
|
78
|
+
align-items: center;
|
|
79
|
+
padding: 0px;
|
|
80
|
+
gap: 16px;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.field-label {
|
|
84
|
+
font-weight: bold;
|
|
85
|
+
text-transform: capitalize;
|
|
86
|
+
font-size: 14px;
|
|
87
|
+
min-width: 150px;
|
|
88
|
+
color: #3a5877;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.field-value {
|
|
92
|
+
font-size: 14px;
|
|
93
|
+
color: #3a5877;
|
|
94
|
+
flex: 1;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.field-col {
|
|
98
|
+
display: flex;
|
|
99
|
+
flex-direction: row;
|
|
100
|
+
align-items: center;
|
|
101
|
+
gap: 16px;
|
|
102
|
+
width: 100%;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.selection-box {
|
|
106
|
+
flex: 1;
|
|
107
|
+
max-width: 300px;
|
|
108
|
+
padding: 6px;
|
|
109
|
+
border: 1px solid #ccc;
|
|
110
|
+
border-radius: 4px;
|
|
111
|
+
font-size: 14px;
|
|
112
|
+
background-color: var(--theme-white-color);
|
|
113
|
+
color: #3a5877;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.selection-box:focus {
|
|
117
|
+
outline: none;
|
|
118
|
+
border-color: var(--primary-color);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
oops-spinner {
|
|
122
|
+
display: none;
|
|
123
|
+
position: absolute;
|
|
124
|
+
left: 50%;
|
|
125
|
+
top: 50%;
|
|
126
|
+
transform: translate(-50%, -50%);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
oops-spinner[show] {
|
|
130
|
+
display: block;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
oops-note {
|
|
134
|
+
display: block;
|
|
135
|
+
position: absolute;
|
|
136
|
+
left: 50%;
|
|
137
|
+
top: 50%;
|
|
138
|
+
transform: translate(-50%, -50%);
|
|
139
|
+
}
|
|
140
|
+
`
|
|
141
|
+
]
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
firstUpdated() {
|
|
145
|
+
this._fetchData()
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
updated(changedProperties) {
|
|
149
|
+
// Like data-grist: only update handler reference when fetchHandler changes, don't fetch
|
|
150
|
+
if (changedProperties.has('fetchHandler')) {
|
|
151
|
+
// Just update the reference, don't fetch automatically
|
|
152
|
+
// Fetch will be called explicitly via fetch() method when needed
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Only fetch when config changes (like data-grist does)
|
|
156
|
+
if (changedProperties.has('config') && !this._isExecuting && !this._showSpinner) {
|
|
157
|
+
this._fetchData()
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
async _fetchData() {
|
|
162
|
+
if (!this.fetchHandler || !this.config) return
|
|
163
|
+
|
|
164
|
+
// Don't fetch if we're currently executing (e.g., during confirmation)
|
|
165
|
+
if (this._isExecuting) return
|
|
166
|
+
|
|
167
|
+
this._showSpinner = true
|
|
168
|
+
this.requestUpdate()
|
|
169
|
+
|
|
170
|
+
try {
|
|
171
|
+
const result = await this.fetchHandler({
|
|
172
|
+
page: 1,
|
|
173
|
+
limit: 9999 // Fetch all records for mobile view
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
// Only update data if we're not executing (to prevent resetting during confirmation)
|
|
177
|
+
if (!this._isExecuting) {
|
|
178
|
+
this._data = result.records || []
|
|
179
|
+
this._originalData = this._data.map(record => ({ ...record }))
|
|
180
|
+
}
|
|
181
|
+
} catch (error) {
|
|
182
|
+
console.error('Error fetching data:', error)
|
|
183
|
+
if (!this._isExecuting) {
|
|
184
|
+
this._data = []
|
|
185
|
+
this._originalData = []
|
|
186
|
+
}
|
|
187
|
+
} finally {
|
|
188
|
+
// Only hide spinner if we're not executing (spinner is controlled externally during execution)
|
|
189
|
+
if (!this._isExecuting) {
|
|
190
|
+
this._showSpinner = false
|
|
191
|
+
this.requestUpdate()
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
_onSelectionChange(e, record, field) {
|
|
197
|
+
const newValue = e.target.value
|
|
198
|
+
|
|
199
|
+
// Update the record
|
|
200
|
+
const updatedRecord = {
|
|
201
|
+
...record,
|
|
202
|
+
[field]: newValue
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Update in data array
|
|
206
|
+
const index = this._data.findIndex(r => r.id === record.id)
|
|
207
|
+
if (index !== -1) {
|
|
208
|
+
this._data[index] = updatedRecord
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Trigger re-render to show dirty indicator
|
|
212
|
+
this.requestUpdate()
|
|
213
|
+
|
|
214
|
+
// Dispatch change event
|
|
215
|
+
this.dispatchEvent(
|
|
216
|
+
new CustomEvent('field-change', {
|
|
217
|
+
bubbles: true,
|
|
218
|
+
composed: true,
|
|
219
|
+
detail: {
|
|
220
|
+
record: updatedRecord,
|
|
221
|
+
field: field,
|
|
222
|
+
value: newValue,
|
|
223
|
+
originalRecord: record
|
|
224
|
+
}
|
|
225
|
+
})
|
|
226
|
+
)
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
_isRecordDirty(record) {
|
|
230
|
+
const original = this._originalData.find(r => r.id === record.id)
|
|
231
|
+
if (!original) return false
|
|
232
|
+
return original.conditionOfGoods !== record.conditionOfGoods
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
_renderField(fieldConfig, record) {
|
|
236
|
+
const fieldType = fieldConfig.type || 'text'
|
|
237
|
+
const field = fieldConfig.field
|
|
238
|
+
const header = fieldConfig.header
|
|
239
|
+
const value = record[field]
|
|
240
|
+
const fieldColor = fieldConfig.color || '#3A5877'
|
|
241
|
+
|
|
242
|
+
switch (fieldType) {
|
|
243
|
+
case 'selectionBox':
|
|
244
|
+
const options = fieldConfig.options || []
|
|
245
|
+
const optionValueKey = fieldConfig.optionValueKey || 'value'
|
|
246
|
+
const optionLabelKey = fieldConfig.optionLabelKey || 'label'
|
|
247
|
+
const currentValue = value || ''
|
|
248
|
+
|
|
249
|
+
return html`
|
|
250
|
+
<div class="field-row">
|
|
251
|
+
<div class="field-label" style="color: ${fieldColor}">${header || ''}</div>
|
|
252
|
+
<select
|
|
253
|
+
class="selection-box"
|
|
254
|
+
.value="${String(currentValue)}"
|
|
255
|
+
@change="${e => this._onSelectionChange(e, record, field)}"
|
|
256
|
+
style="color: ${fieldColor}"
|
|
257
|
+
>
|
|
258
|
+
${fieldConfig.placeholder
|
|
259
|
+
? html`<option value="">${fieldConfig.placeholder}</option>`
|
|
260
|
+
: ''}
|
|
261
|
+
${options.map(option => {
|
|
262
|
+
const optValue = typeof option === 'object' ? option[optionValueKey] : option
|
|
263
|
+
const optLabel = typeof option === 'object' ? option[optionLabelKey] : option
|
|
264
|
+
const isSelected = String(optValue) === String(currentValue)
|
|
265
|
+
return html`<option value="${optValue}" ?selected="${isSelected}">${optLabel}</option>`
|
|
266
|
+
})}
|
|
267
|
+
</select>
|
|
268
|
+
</div>
|
|
269
|
+
`
|
|
270
|
+
case 'text':
|
|
271
|
+
default:
|
|
272
|
+
return html`
|
|
273
|
+
<div class="field-row">
|
|
274
|
+
<div class="field-label" style="color: ${fieldColor}">${header || ''}</div>
|
|
275
|
+
<div class="field-value" style="color: ${fieldColor}">${value || '-'}</div>
|
|
276
|
+
</div>
|
|
277
|
+
`
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
render() {
|
|
282
|
+
if (!this.config || !this.fetchHandler) {
|
|
283
|
+
return html``
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
var oops = !this._showSpinner && (!this._data || this._data.length === 0)
|
|
287
|
+
|
|
288
|
+
return html`
|
|
289
|
+
${oops
|
|
290
|
+
? html` <oops-note icon="list" title="EMPTY LIST" description="There are no records to be shown"></oops-note> `
|
|
291
|
+
: html``}
|
|
292
|
+
<div class="list-container">
|
|
293
|
+
${this._data.map(record => {
|
|
294
|
+
try {
|
|
295
|
+
const flattenedRecord = flattenObject(record, '.')
|
|
296
|
+
const isDirty = this._isRecordDirty(record)
|
|
297
|
+
return html`
|
|
298
|
+
<div class="list-item" ?dirty=${isDirty}>
|
|
299
|
+
${isDirty ? html`<mwc-icon class="dirty-icon">done</mwc-icon>` : ''}
|
|
300
|
+
${this.config.columns.map(columnConfig => this._renderField(columnConfig, flattenedRecord))}
|
|
301
|
+
</div>
|
|
302
|
+
`
|
|
303
|
+
} catch (e) {
|
|
304
|
+
console.error('Error rendering record:', e)
|
|
305
|
+
return html``
|
|
306
|
+
}
|
|
307
|
+
})}
|
|
308
|
+
</div>
|
|
309
|
+
<oops-spinner ?show=${this._showSpinner}></oops-spinner>
|
|
310
|
+
`
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
fetch() {
|
|
314
|
+
this._fetchData()
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
getRecords() {
|
|
318
|
+
return this._data
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
getChangedRecords() {
|
|
322
|
+
return this._data.filter(record => {
|
|
323
|
+
const original = this._originalData.find(r => r.id === record.id)
|
|
324
|
+
if (!original) return false
|
|
325
|
+
return original.conditionOfGoods !== record.conditionOfGoods
|
|
326
|
+
})
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
showSpinner() {
|
|
330
|
+
this._showSpinner = true
|
|
331
|
+
this._isExecuting = true // Prevent fetching during execution
|
|
332
|
+
this.requestUpdate()
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
hideSpinner() {
|
|
336
|
+
this._showSpinner = false
|
|
337
|
+
this._isExecuting = false
|
|
338
|
+
this.requestUpdate()
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
window.customElements.define('mobile-condition-of-goods-listing', MobileConditionOfGoodsListing)
|