@things-factory/reference-app 5.0.0-zeta.8 → 5.0.1

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 (67) hide show
  1. package/client/bootstrap.js +21 -11
  2. package/client/components/ocr-viewpart.js +1 -1
  3. package/client/editors/id-editor.js +1 -1
  4. package/client/editors/id-selector.js +1 -1
  5. package/client/menu.js +10 -5
  6. package/client/pages/data-entry/data-entry-form.js +117 -0
  7. package/client/pages/data-entry/data-entry-generator-popup.js +110 -0
  8. package/client/pages/data-set/data-item-list.js +277 -0
  9. package/client/pages/data-set/data-set-importer.js +103 -0
  10. package/client/pages/data-set/data-set-list-page.js +738 -0
  11. package/client/pages/ocr-page.js +1 -1
  12. package/client/pages/operation/operation-api.js +85 -0
  13. package/client/pages/operation/operation-master.js +432 -0
  14. package/client/pages/pending-job-page.js +1 -1
  15. package/client/pages/product/product-api.js +150 -0
  16. package/client/pages/product/product-master.js +888 -0
  17. package/client/pages/product-combination-settings-popup.js +395 -0
  18. package/client/pages/product-combinations-popup.js +372 -0
  19. package/client/pages/product-details-popup.js +744 -0
  20. package/client/pages/upload-page.js +1 -1
  21. package/client/route.js +12 -0
  22. package/config/config.development.js +1 -1
  23. package/config.development.js +21 -0
  24. package/db.sqlite +0 -0
  25. package/dist-server/constants/index.js +18 -0
  26. package/dist-server/constants/index.js.map +1 -0
  27. package/dist-server/constants/type-constants.js +26 -0
  28. package/dist-server/constants/type-constants.js.map +1 -0
  29. package/dist-server/controllers/create-data-sample-mockup.js +236 -0
  30. package/dist-server/controllers/create-data-sample-mockup.js.map +1 -0
  31. package/dist-server/controllers/index.js +17 -0
  32. package/dist-server/controllers/index.js.map +1 -1
  33. package/dist-server/service/data-sample-mockup/data-sample-mockup-mutation.js +40 -0
  34. package/dist-server/service/data-sample-mockup/data-sample-mockup-mutation.js.map +1 -0
  35. package/dist-server/service/data-sample-mockup/data-sample-mockup-type.js +28 -0
  36. package/dist-server/service/data-sample-mockup/data-sample-mockup-type.js.map +1 -0
  37. package/dist-server/service/data-sample-mockup/index.js +7 -0
  38. package/dist-server/service/data-sample-mockup/index.js.map +1 -0
  39. package/dist-server/service/index.js +5 -2
  40. package/dist-server/service/index.js.map +1 -1
  41. package/dist-server/service/reference/reference-mutation.js +6 -3
  42. package/dist-server/service/reference/reference-mutation.js.map +1 -1
  43. package/dist-server/service/reference/reference-query.js +7 -4
  44. package/dist-server/service/reference/reference-query.js.map +1 -1
  45. package/logs/.08636eb59927f12972f6774f5947c8507b3564c2-audit.json +4 -14
  46. package/logs/.5e5d741d8b7784a2fbad65eedc0fd46946aaf6f2-audit.json +19 -69
  47. package/logs/application-2022-07-22-10.log +26 -0
  48. package/logs/connections-2022-07-12-00.log +0 -0
  49. package/logs/connections-2022-07-14-14.log +0 -0
  50. package/logs/connections-2022-07-14-15.log +0 -0
  51. package/logs/connections-2022-07-14-16.log +0 -0
  52. package/logs/connections-2022-07-14-17.log +0 -0
  53. package/logs/connections-2022-07-22-10.log +0 -0
  54. package/package.json +58 -56
  55. package/server/constants/index.ts +1 -0
  56. package/server/constants/type-constants.ts +24 -0
  57. package/server/controllers/create-data-sample-mockup.ts +268 -0
  58. package/server/controllers/index.ts +1 -0
  59. package/server/service/data-sample-mockup/data-sample-mockup-mutation.ts +18 -0
  60. package/server/service/data-sample-mockup/data-sample-mockup-type.ts +10 -0
  61. package/server/service/data-sample-mockup/index.ts +4 -0
  62. package/server/service/index.ts +5 -2
  63. package/server/service/reference/reference-mutation.ts +5 -3
  64. package/server/service/reference/reference-query.ts +8 -7
  65. package/things-factory.config.js +8 -0
  66. package/translations/en.json +6 -1
  67. package/translations/ko.json +7 -1
@@ -0,0 +1,744 @@
1
+ import '@things-factory/form-ui'
2
+ import '@operato/data-grist'
3
+ import './product-combinations-popup'
4
+
5
+ import gql from 'graphql-tag'
6
+ import { css, html, LitElement } from 'lit'
7
+
8
+ import { i18next, localize } from '@operato/i18n'
9
+ import { openPopup } from '@operato/layout'
10
+ import { ScrollbarStyles } from '@operato/styles'
11
+ import { isMobileDevice } from '@operato/utils'
12
+ import { getCodeByName } from '@things-factory/code-base'
13
+ import { client, CustomAlert, gqlContext } from '@things-factory/shell'
14
+
15
+ const _ = require('lodash')
16
+
17
+ export class ProductDetailsPopup extends localize(i18next)(LitElement) {
18
+ static get styles() {
19
+ return [
20
+ ScrollbarStyles,
21
+ css`
22
+ :host {
23
+ display: flex;
24
+ flex-direction: column;
25
+ overflow: hidden;
26
+ background-color: white;
27
+
28
+ --grid-record-emphasized-background-color: #ffdbdb;
29
+ --grid-record-emphasized-color: #703f3f;
30
+ }
31
+ search-form {
32
+ overflow: visible;
33
+ }
34
+ ox-grist {
35
+ overflow-y: auto;
36
+ flex: 1;
37
+ }
38
+ .button-container {
39
+ padding: 10px 0 12px 0;
40
+ text-align: center;
41
+ }
42
+ [danger] {
43
+ --mdc-theme-primary: var(--mdc-danger-button-primary-color);
44
+ }
45
+ .header {
46
+ display: grid;
47
+ grid-template-columns: repeat(24, 1fr);
48
+ grid-gap: var(--form-grid-gap);
49
+ grid-auto-rows: minmax(24px, auto);
50
+ max-width: var(--form-multi-column-max-width);
51
+ margin-top: var(--form-margin);
52
+ margin-left: var(--form-margin);
53
+ margin-right: var(--form-margin);
54
+ }
55
+ .header legend {
56
+ grid-column: span 24;
57
+ text-transform: capitalize;
58
+
59
+ padding: var(--legend-padding);
60
+ font: var(--legend-font);
61
+ color: var(--legend-text-color);
62
+ border-bottom: var(--legend-border-bottom);
63
+ }
64
+ `
65
+ ]
66
+ }
67
+
68
+ static get properties() {
69
+ return {
70
+ _searchFields: Array,
71
+ config: Object,
72
+ _data: Object,
73
+ productId: String,
74
+ _gtins: Array
75
+ }
76
+ }
77
+
78
+ constructor() {
79
+ super()
80
+ this._gtins = []
81
+ }
82
+
83
+ get dataGrist() {
84
+ return this.shadowRoot.querySelector('ox-grist')
85
+ }
86
+
87
+ get buttonSave() {
88
+ return this.shadowRoot.querySelector('#buttonSave')
89
+ }
90
+
91
+ render() {
92
+ return html`
93
+ <ox-grist
94
+ .mode=${isMobileDevice() ? 'LIST' : 'GRID'}
95
+ .config=${this.config}
96
+ .data=${this._data}
97
+ .fetchHandler="${this.fetchHandler.bind(this)}"
98
+ @field-change="${this._fieldChange.bind(this)}"
99
+ ></ox-grist>
100
+
101
+ <div class="button-container">
102
+ <mwc-button
103
+ id="buttonSave"
104
+ @click=${this.updateProductDetail}
105
+ raised
106
+ label="${i18next.t('button.save')}"
107
+ ></mwc-button>
108
+ <mwc-button
109
+ raised
110
+ danger
111
+ @click=${() => {
112
+ history.back()
113
+ }}
114
+ label="${i18next.t('button.back')}"
115
+ ></mwc-button>
116
+ </div>
117
+ `
118
+ }
119
+
120
+ async firstUpdated() {
121
+ const packingType = await getCodeByName('PACKING_TYPES')
122
+ const uom = await getCodeByName('UOM')
123
+ const weightUnit = await getCodeByName('WEIGHT_UNITS')
124
+ const lengthUnit = await getCodeByName('LENGTH_UNITS')
125
+
126
+ this.config = {
127
+ rows: {
128
+ appendable: true,
129
+ classifier: record => {
130
+ return {
131
+ emphasized: record.error || false
132
+ }
133
+ }
134
+ },
135
+ pagination: { infinite: true },
136
+ list: {
137
+ fields: ['isDefault', 'gtin', 'refCode', 'packingType', 'uom', 'uomValue', 'childProductDetail', 'packingSize']
138
+ },
139
+ columns: [
140
+ { type: 'gutter', gutterName: 'sequence' },
141
+ {
142
+ type: 'gutter',
143
+ gutterName: 'button',
144
+ icon: 'clear',
145
+ handlers: {
146
+ click: (_columns, _data, _column, record, _rowIndex) => {
147
+ if (record) this._removeGtin(record, _rowIndex)
148
+ }
149
+ }
150
+ },
151
+ {
152
+ type: 'gutter',
153
+ gutterName: 'button',
154
+ icon: 'assignment',
155
+ handlers: {
156
+ click: this._showProductCombinations.bind(this)
157
+ }
158
+ },
159
+ {
160
+ type: 'boolean',
161
+ name: 'isDefault',
162
+ header: i18next.t('field.default'),
163
+ record: { editable: true, align: 'center' },
164
+ sortable: true,
165
+ width: 80
166
+ },
167
+ {
168
+ type: 'string',
169
+ name: 'gtin',
170
+ header: i18next.t('field.gtin'),
171
+ record: { editable: true },
172
+ sortable: true,
173
+ width: 180
174
+ },
175
+ {
176
+ type: 'string',
177
+ name: 'refCode',
178
+ header: i18next.t('field.ref_code'),
179
+ record: { editable: true },
180
+ sortable: true,
181
+ width: 150
182
+ },
183
+ {
184
+ type: 'select',
185
+ name: 'packingType',
186
+ header: i18next.t('field.packing_type'),
187
+ record: {
188
+ editable: true,
189
+ options: ['', ...Object.keys(packingType).map(key => packingType[key].name)]
190
+ },
191
+ width: 120
192
+ },
193
+ {
194
+ type: 'select',
195
+ name: 'uom',
196
+ record: {
197
+ editable: true,
198
+ options: ['', ...Object.keys(uom).map(key => uom[key].name)]
199
+ },
200
+ header: `${i18next.t('field.uom')}`,
201
+ width: 80
202
+ },
203
+ {
204
+ type: 'float',
205
+ name: 'uomValue',
206
+ record: { editable: true, options: { min: 0 } },
207
+ header: `${i18next.t('field.uom_value')}`,
208
+ width: 100
209
+ },
210
+ {
211
+ type: 'select',
212
+ name: 'childProductDetail',
213
+ header: i18next.t('field.child_gtin'),
214
+ record: { editable: true, rowOptionField: 'rowOptionProductDetail' },
215
+ width: 180
216
+ },
217
+ {
218
+ type: 'float',
219
+ name: 'packingSize',
220
+ record: { editable: true, options: { min: 1 } },
221
+ header: i18next.t('field.packing_size'),
222
+ width: 110
223
+ },
224
+ {
225
+ type: 'float',
226
+ name: 'bufferQty',
227
+ record: { editable: true, options: { min: 0 } },
228
+ header: i18next.t('field.buffer_qty'),
229
+ width: 80
230
+ },
231
+ {
232
+ type: 'float',
233
+ name: 'minQty',
234
+ record: { editable: true, options: { min: 0 } },
235
+ header: i18next.t('field.min_qty'),
236
+ width: 80
237
+ },
238
+ {
239
+ type: 'float',
240
+ name: 'maxQty',
241
+ record: { editable: true, options: { min: 0 } },
242
+ header: i18next.t('field.max_qty'),
243
+ width: 80
244
+ },
245
+ {
246
+ type: 'select',
247
+ name: 'weightUnit',
248
+ record: {
249
+ editable: true,
250
+ options: ['', ...Object.keys(weightUnit).map(key => weightUnit[key].name)]
251
+ },
252
+ header: `${i18next.t('field.weight_unit')}`,
253
+ width: 100
254
+ },
255
+ {
256
+ type: 'float',
257
+ name: 'grossWeight',
258
+ record: { editable: true, options: { min: 0 } },
259
+ header: i18next.t('field.gross_weight'),
260
+ width: 140
261
+ },
262
+ {
263
+ type: 'float',
264
+ name: 'nettWeight',
265
+ record: { editable: true, options: { min: 0 } },
266
+ header: i18next.t('field.nett_weight'),
267
+ width: 140
268
+ },
269
+ {
270
+ type: 'select',
271
+ name: 'lengthUnit',
272
+ record: {
273
+ editable: true,
274
+ options: ['', ...Object.keys(lengthUnit).map(key => lengthUnit[key].name)]
275
+ },
276
+ header: `${i18next.t('field.length_unit')}`,
277
+ width: 80
278
+ },
279
+ {
280
+ type: 'float',
281
+ name: 'width',
282
+ record: { editable: true, options: { min: 0 } },
283
+ header: i18next.t('field.width'),
284
+ width: 70
285
+ },
286
+ {
287
+ type: 'float',
288
+ name: 'depth',
289
+ record: { editable: true, options: { min: 0 } },
290
+ header: i18next.t('field.depth'),
291
+ width: 70
292
+ },
293
+ {
294
+ type: 'float',
295
+ name: 'height',
296
+ record: { editable: true, options: { min: 0 } },
297
+ header: i18next.t('field.height'),
298
+ width: 70
299
+ },
300
+ {
301
+ type: 'float',
302
+ name: 'volume',
303
+ record: { editable: true, options: { min: 0 } },
304
+ header: i18next.t('field.volume'),
305
+ width: 70
306
+ },
307
+ {
308
+ type: 'string',
309
+ name: 'auxUnit1',
310
+ record: { editable: true },
311
+ header: `${i18next.t('field.aux_unit')} 1`,
312
+ width: 80
313
+ },
314
+ {
315
+ type: 'string',
316
+ name: 'auxValue1',
317
+ record: { editable: true },
318
+ header: `${i18next.t('field.aux_value')} 1`,
319
+ width: 90
320
+ },
321
+ {
322
+ type: 'string',
323
+ name: 'auxUnit2',
324
+ record: { editable: true },
325
+ header: `${i18next.t('field.aux_unit')} 2`,
326
+ width: 90
327
+ },
328
+ {
329
+ type: 'string',
330
+ name: 'auxValue2',
331
+ record: { editable: true },
332
+ header: `${i18next.t('field.aux_value')} 2`,
333
+ width: 90
334
+ },
335
+ {
336
+ type: 'string',
337
+ name: 'auxUnit3',
338
+ record: { editable: true },
339
+ header: `${i18next.t('field.aux_unit')} 3`,
340
+ width: 90
341
+ },
342
+ {
343
+ type: 'string',
344
+ name: 'auxValue3',
345
+ record: { editable: true },
346
+ header: `${i18next.t('field.aux_value')} 3`,
347
+ width: 90
348
+ },
349
+ {
350
+ type: 'string',
351
+ name: 'auxUnit4',
352
+ record: { editable: true },
353
+ header: `${i18next.t('field.aux_unit')} 4`,
354
+ width: 90
355
+ },
356
+ {
357
+ type: 'string',
358
+ name: 'auxValue4',
359
+ record: { editable: true },
360
+ header: `${i18next.t('field.aux_value')} 4`,
361
+ width: 90
362
+ },
363
+ {
364
+ type: 'string',
365
+ name: 'auxUnit5',
366
+ record: { editable: true },
367
+ header: `${i18next.t('field.aux_unit')} 5`,
368
+ width: 90
369
+ },
370
+ {
371
+ type: 'string',
372
+ name: 'auxValue5',
373
+ record: { editable: true },
374
+ header: `${i18next.t('field.aux_value')} 5`,
375
+ width: 90
376
+ }
377
+ ]
378
+ }
379
+ }
380
+
381
+ async fetchHandler({ page, limit, sorters = [] }) {
382
+ try {
383
+ if (!this.productId) return
384
+
385
+ const pagination = { page, limit }
386
+ const sortings = sorters
387
+
388
+ const filters = [{ name: 'product', operator: 'eq', value: this.productId }]
389
+
390
+ const response = await client.query({
391
+ query: gql`
392
+ query productDetails($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {
393
+ productDetails(filters: $filters, pagination: $pagination, sortings: $sortings) {
394
+ items {
395
+ id
396
+ name
397
+ gtin
398
+ refCode
399
+ product {
400
+ id
401
+ sku
402
+ name
403
+ description
404
+ }
405
+ isDefault
406
+ packingType
407
+ movement
408
+ uom
409
+ uomValue
410
+ childProductDetail {
411
+ id
412
+ name
413
+ gtin
414
+ }
415
+ packingSize
416
+ bundleQty
417
+ weightUnit
418
+ nettWeight
419
+ grossWeight
420
+ lengthUnit
421
+ width
422
+ depth
423
+ height
424
+ volume
425
+ bufferQty
426
+ minQty
427
+ maxQty
428
+ auxUnit1
429
+ auxValue1
430
+ auxUnit2
431
+ auxValue2
432
+ auxUnit3
433
+ auxValue3
434
+ auxUnit4
435
+ auxValue4
436
+ auxUnit5
437
+ auxValue5
438
+ isTrackedAsInventory
439
+ discountId
440
+ costPrice
441
+ mrpPrice
442
+ sellPrice
443
+ afterTaxCostPrice
444
+ afterTaxSalesPrice
445
+ inventoryAccountCode
446
+ cogsAccountCode
447
+ }
448
+ total
449
+ }
450
+ }
451
+ `,
452
+ variables: { filters, pagination, sortings },
453
+ context: gqlContext()
454
+ })
455
+
456
+ let data = this._updateRowOption(response.data.productDetails.items)
457
+
458
+ if (!response.errors) {
459
+ this._data = {
460
+ total: response.data.productDetails.total || 0,
461
+ records: data
462
+ }
463
+ }
464
+ } catch (e) {
465
+ this._showToast(e)
466
+ }
467
+ }
468
+
469
+ async updateProductDetail() {
470
+ try {
471
+ this.buttonSave.disabled = true
472
+ this.dataGrist.showSpinner()
473
+
474
+ let patches = this.dataGrist._data.records
475
+
476
+ this._validate()
477
+
478
+ patches = this.dataGrist._data.records.map(itm => {
479
+ return {
480
+ id: itm.id,
481
+ name: itm.name,
482
+ gtin: itm.gtin,
483
+ refCode: itm.refCode,
484
+ isDefault: itm.isDefault,
485
+ packingType: itm.packingType,
486
+ movement: itm.movement,
487
+ uom: itm.uom,
488
+ uomValue: itm.uomValue,
489
+ childProductDetail: itm.childProductDetail,
490
+ packingSize: itm.packingSize,
491
+ weightUnit: itm.weightUnit,
492
+ nettWeight: itm.nettWeight,
493
+ grossWeight: itm.grossWeight,
494
+ lengthUnit: itm.lengthUnit,
495
+ width: itm.width,
496
+ depth: itm.depth,
497
+ height: itm.height,
498
+ volume: itm.volume,
499
+ bufferQty: itm.bufferQty,
500
+ minQty: itm.minQty,
501
+ maxQty: itm.maxQty,
502
+ auxUnit1: itm.auxUnit1,
503
+ auxValue1: itm.auxValue1,
504
+ auxUnit2: itm.auxUnit2,
505
+ auxValue2: itm.auxValue2,
506
+ auxUnit3: itm.auxUnit3,
507
+ auxValue3: itm.auxValue3,
508
+ auxUnit4: itm.auxUnit4,
509
+ auxValue4: itm.auxValue4,
510
+ auxUnit5: itm.auxUnit5,
511
+ auxValue5: itm.auxValue5,
512
+ isTrackedAsInventory: itm.isTrackedAsInventory,
513
+ discountId: itm.discountId,
514
+ costPrice: itm.costPrice,
515
+ mrpPrice: itm.mrpPrice,
516
+ sellPrice: itm.sellPrice,
517
+ afterTaxCostPrice: itm.afterTaxCostPrice,
518
+ afterTaxSalesPrice: itm.afterTaxSalesPrice,
519
+ inventoryAccountCode: itm.inventoryAccountCode,
520
+ cogsAccountCode: itm.cogsAccountCode
521
+ }
522
+ })
523
+
524
+ let productId = this.productId
525
+
526
+ if (!productId) throw new Error('Product not found')
527
+
528
+ if (productId && patches) {
529
+ const response = await client.mutate({
530
+ mutation: gql`
531
+ mutation updateMultipleProductDetail($productId: String!, $patches: [ProductDetailPatch!]!) {
532
+ updateMultipleProductDetail(productId: $productId, patches: $patches) {
533
+ name
534
+ }
535
+ }
536
+ `,
537
+ variables: { productId, patches },
538
+ context: gqlContext()
539
+ })
540
+ if (response.errors) {
541
+ throw response.errors
542
+ }
543
+ } else {
544
+ CustomAlert({
545
+ title: i18next.t('text.nothing_changed'),
546
+ text: i18next.t('text.there_is_nothing_to_save')
547
+ })
548
+ }
549
+
550
+ this.dataGrist.hideSpinner()
551
+ this.buttonSave.disabled = false
552
+ this.dispatchEvent(new CustomEvent('saved', {}))
553
+ history.back()
554
+ } catch (error) {
555
+ this._showToast(error)
556
+ this.dataGrist.hideSpinner()
557
+ this.buttonSave.disabled = false
558
+ }
559
+ }
560
+
561
+ _validate() {
562
+ let errors = []
563
+
564
+ if (!this.dataGrist._data.records.find(x => x.isDefault)) {
565
+ errors.push({ type: 'isDefault', value: 'Must have 1 default' })
566
+ }
567
+
568
+ let data = this.dataGrist._data.records.map(itm => {
569
+ itm.error = false
570
+
571
+ if (_.isEmpty(itm.gtin) || '') {
572
+ itm.error = true
573
+ if (!errors.find(err => err.type == 'gtin')) errors.push({ type: 'gtin', value: 'GTIN is required' })
574
+ }
575
+ if (_.isEmpty(itm.packingType) || '') {
576
+ itm.error = true
577
+ if (!errors.find(err => err.type == 'packingType'))
578
+ errors.push({ type: 'packingType', value: 'Packing type is required' })
579
+ }
580
+ if (_.isEmpty(itm.uom) || '') {
581
+ itm.error = true
582
+ if (!errors.find(err => err.type == 'uom')) errors.push({ type: 'uom', value: 'UOM is required' })
583
+ }
584
+ if (!_.isNumber(itm.uomValue) || _.isNaN(itm.uomValue) || '') {
585
+ itm.error = true
586
+ if (!errors.find(err => err.type == 'uomValue'))
587
+ errors.push({ type: 'uomValue', value: 'UOM Value is required' })
588
+ }
589
+ return itm
590
+ })
591
+
592
+ if (errors.length > 0) {
593
+ this._data = {
594
+ ...this.dataGrist.dirtyData,
595
+ records: data
596
+ }
597
+
598
+ throw new Error(errors.map(itm => itm.value).join(', '))
599
+ }
600
+ }
601
+
602
+ _fieldChange(e) {
603
+ var { after, before, column, record, row } = e.detail
604
+ let updatedRecords = {
605
+ ...this.dataGrist._data,
606
+ records: this._updateRowOption(this.dataGrist._data.records)
607
+ }
608
+
609
+ switch (column.name) {
610
+ case 'isDefault':
611
+ if (this.dataGrist._data.records.filter(x => x.isDefault).length == 0) {
612
+ this._showToast({ type: 'error', message: 'Must have 1 default' })
613
+ break
614
+ }
615
+
616
+ updatedRecords = {
617
+ ...this.dataGrist._data,
618
+ records: this.dataGrist._data.records.map((record, idx) => {
619
+ if (idx !== e.detail.row) {
620
+ record.isDefault = false
621
+ }
622
+ return record
623
+ })
624
+ }
625
+ break
626
+ case 'gtin':
627
+ if (this.dataGrist._data.records.filter(x => x.gtin == after).length > 1) {
628
+ this.dataGrist._data.records[row].gtin = before
629
+
630
+ updatedRecords = {
631
+ ...this.dataGrist._data
632
+ }
633
+
634
+ this._showToast({ type: 'error', message: 'Duplicated GTIN' })
635
+ break
636
+ }
637
+
638
+ updatedRecords = {
639
+ ...this.dataGrist._data,
640
+ records: this._updateRowOption(
641
+ this.dataGrist._data.records.map((record, idx) => {
642
+ if (!_.isEmpty(record.childProductDetail) && record.childProductDetail == before) {
643
+ record.childProductDetail = after
644
+ }
645
+ return record
646
+ })
647
+ )
648
+ }
649
+
650
+ break
651
+ case 'uomValue':
652
+ if (_.isNaN(after)) {
653
+ updatedRecords.records[row].uomValue = 1
654
+ }
655
+ break
656
+ default:
657
+ break
658
+ }
659
+
660
+ if (column.record?.options?.min > after) {
661
+ this.dataGrist._data.records[row][column.name] = before
662
+ updatedRecords = {
663
+ ...this.dataGrist._data
664
+ }
665
+
666
+ this._showToast({ type: 'error', message: `Minimum value of ${column.record.options.min} is required.` })
667
+ }
668
+
669
+ this._data = { ...updatedRecords }
670
+ }
671
+
672
+ _removeGtin(record, index) {
673
+ let data = [...this.dataGrist._data.records]
674
+ data.splice(index, 1)
675
+
676
+ data = data.map(itm => {
677
+ return { ...itm, childProductDetail: itm.childProductDetail == record.gtin ? '' : itm.childProductDetail }
678
+ })
679
+
680
+ if (
681
+ !data.find(itm => {
682
+ itm.isDefault
683
+ })
684
+ ) {
685
+ data[0].isDefault = true
686
+ }
687
+
688
+ this._data = {
689
+ ...this._data,
690
+ records: [...this._updateRowOption(data)]
691
+ }
692
+ }
693
+
694
+ _updateRowOption(data) {
695
+ return (
696
+ data.map(itm => {
697
+ return {
698
+ ...itm,
699
+ childProductDetail: itm?.childProductDetail?.gtin || itm?.childProductDetail || '',
700
+ rowOptionProductDetail: {
701
+ options: [
702
+ {
703
+ display: '',
704
+ value: ''
705
+ },
706
+ ...data
707
+ .filter(child => child.gtin != itm.gtin && !_.isEmpty(child.gtin))
708
+ .map(x => {
709
+ const rowOption = {
710
+ display: x.gtin,
711
+ value: x.gtin
712
+ }
713
+ return rowOption
714
+ })
715
+ ]
716
+ }
717
+ }
718
+ }) || []
719
+ )
720
+ }
721
+
722
+ _showProductCombinations(columns, data, column, record, rowIndex) {
723
+ if (record.id) {
724
+ openPopup(html` <product-combinations-popup .productDetailId="${record.id}"></product-combinations-popup> `, {
725
+ backdrop: true,
726
+ size: 'large',
727
+ title: `${record.product.sku}`
728
+ })
729
+ }
730
+ }
731
+
732
+ _showToast({ type, message }) {
733
+ document.dispatchEvent(
734
+ new CustomEvent('notify', {
735
+ detail: {
736
+ type,
737
+ message
738
+ }
739
+ })
740
+ )
741
+ }
742
+ }
743
+
744
+ window.customElements.define('product-details-popup', ProductDetailsPopup)