@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
@@ -1,7 +1,7 @@
1
1
  import '@things-factory/form-ui'
2
2
  import '../components/camera-capturer'
3
3
 
4
- import { gql } from 'graphql-tag'
4
+ import gql from 'graphql-tag'
5
5
  import { css, html } from 'lit'
6
6
  import { connect } from 'pwa-helpers/connect-mixin.js'
7
7
 
@@ -0,0 +1,85 @@
1
+ import gql from 'graphql-tag'
2
+
3
+ import { client } from '@operato/graphql'
4
+
5
+ export async function fetchOperations({ filters = [], page, limit, sortings = [] }) {
6
+ return await client.query({
7
+ query: gql`
8
+ query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {
9
+ operations(filters: $filters, pagination: $pagination, sortings: $sortings) {
10
+ items {
11
+ id
12
+ name
13
+ description
14
+ type
15
+ operationStdChart
16
+ operationStdTime
17
+ active
18
+ thumbnail
19
+ updatedAt
20
+ updater {
21
+ id
22
+ name
23
+ description
24
+ }
25
+ }
26
+ total
27
+ }
28
+ }
29
+ `,
30
+ variables: {
31
+ filters,
32
+ pagination: { page, limit },
33
+ sortings
34
+ }
35
+ })
36
+ }
37
+
38
+ export async function deleteOperations(ids) {
39
+ return await client.query({
40
+ query: gql`
41
+ mutation ($ids: [String!]!) {
42
+ deleteOperations(ids: $ids)
43
+ }
44
+ `,
45
+ variables: {
46
+ ids
47
+ }
48
+ })
49
+ }
50
+
51
+ export async function saveOperations(patches) {
52
+ return await client.query({
53
+ query: gql`
54
+ mutation ($patches: [OperationPatch!]!) {
55
+ updateMultipleOperation(patches: $patches) {
56
+ id
57
+ }
58
+ }
59
+ `,
60
+ variables: {
61
+ patches
62
+ },
63
+ context: {
64
+ hasUpload: true
65
+ }
66
+ })
67
+ }
68
+
69
+ export async function createOperation(operation) {
70
+ return await client.query({
71
+ query: gql`
72
+ mutation ($operation: NewOperation!) {
73
+ createOperation(operation: $operation) {
74
+ id
75
+ }
76
+ }
77
+ `,
78
+ variables: {
79
+ operation
80
+ },
81
+ context: {
82
+ hasUpload: true
83
+ }
84
+ })
85
+ }
@@ -0,0 +1,432 @@
1
+ import '@material/mwc-icon'
2
+ import '@things-factory/import-ui'
3
+ import '@operato/data-grist/ox-grist.js'
4
+ import '@operato/data-grist/ox-filters-form.js'
5
+ import '@operato/data-grist/ox-sorters-control.js'
6
+ import '@operato/data-grist/ox-record-creator.js'
7
+
8
+ import { css, html } from 'lit'
9
+
10
+ import { i18next, localize } from '@operato/i18n'
11
+ import { openPopup } from '@operato/layout'
12
+ import { CommonButtonStyles, CommonGristStyles } from '@operato/styles'
13
+ import { isMobileDevice } from '@operato/utils'
14
+ import { CustomAlert, PageView } from '@things-factory/shell'
15
+
16
+ import { createOperation, deleteOperations, fetchOperations, saveOperations } from './operation-api'
17
+
18
+ const OperationStatus = ['ASSY', 'INV', 'PACK', 'SMT', 'STD', 'TEST']
19
+
20
+ class OperationMaster extends localize(i18next)(PageView) {
21
+ static get styles() {
22
+ return [
23
+ CommonGristStyles,
24
+ css`
25
+ :host {
26
+ display: flex;
27
+
28
+ width: 100%;
29
+
30
+ --grid-record-emphasized-background-color: red;
31
+ --grid-record-emphasized-color: yellow;
32
+ }
33
+ `
34
+ ]
35
+ }
36
+
37
+ static get properties() {
38
+ return {
39
+ config: Object,
40
+ data: Object,
41
+ mode: String,
42
+ importHandler: Object
43
+ }
44
+ }
45
+
46
+ constructor() {
47
+ super()
48
+ this.mode = isMobileDevice() ? 'CARD' : 'GRID'
49
+ }
50
+
51
+ render() {
52
+ let mode = this.mode
53
+
54
+ return html`
55
+ <ox-grist .config=${this.config} .mode=${mode} auto-fetch .fetchHandler=${this.fetchHandler.bind(this)}>
56
+ <div slot="headroom">
57
+ <div id="filters">
58
+ <ox-filters-form autofocus></ox-filters-form>
59
+ </div>
60
+
61
+ <div id="sorters">
62
+ Sort
63
+ <mwc-icon
64
+ @click=${e => {
65
+ const target = e.currentTarget
66
+ this.renderRoot.querySelector('#sorter-control').open({
67
+ right: 0,
68
+ top: target.offsetTop + target.offsetHeight
69
+ })
70
+ }}
71
+ >expand_more</mwc-icon
72
+ >
73
+ <ox-popup id="sorter-control">
74
+ <ox-sorters-control> </ox-sorters-control>
75
+ </ox-popup>
76
+ </div>
77
+
78
+ <div id="modes">
79
+ <mwc-icon @click=${() => (this.mode = 'GRID')} ?active=${mode == 'GRID'}>grid_on</mwc-icon>
80
+ <mwc-icon @click=${() => (this.mode = 'CARD')} ?active=${mode == 'CARD'}>apps</mwc-icon>
81
+ </div>
82
+
83
+ <ox-record-creator id="add" .callback=${this.operationCreationCallback.bind(this)}>
84
+ <button><mwc-icon>add</mwc-icon></button>
85
+ </ox-record-creator>
86
+ </div>
87
+ </ox-grist>
88
+ `
89
+ }
90
+
91
+ get context() {
92
+ return {
93
+ title: i18next.t('title.operation'),
94
+ help: 'master/operation-master',
95
+ actions: [
96
+ {
97
+ title: i18next.t('button.save'),
98
+ action: this._saveOperations.bind(this),
99
+ ...CommonButtonStyles.save
100
+ },
101
+ {
102
+ title: i18next.t('button.delete'),
103
+ action: this._deleteOperations.bind(this),
104
+ ...CommonButtonStyles.delete
105
+ }
106
+ ],
107
+ exportable: {
108
+ name: i18next.t('title.operation'),
109
+ data: this._exportableData.bind(this)
110
+ },
111
+ importable: {
112
+ handler: this._importableData.bind(this)
113
+ }
114
+ }
115
+ }
116
+
117
+ async pageInitialized() {
118
+ this.config = {
119
+ list: {
120
+ thumbnail: 'thumbnail',
121
+ fields: ['name', 'description'],
122
+ details: ['type', 'operationStdChart', 'operationStdTime', 'updatedAt']
123
+ },
124
+ rows: {
125
+ selectable: {
126
+ multiple: true
127
+ },
128
+ handlers: {
129
+ click: 'select-row-toggle'
130
+ },
131
+ classifier: function (record, rowIndex) {}
132
+ },
133
+ columns: [
134
+ { type: 'gutter', gutterName: 'dirty' },
135
+ { type: 'gutter', gutterName: 'sequence' },
136
+ { type: 'gutter', gutterName: 'row-selector', multiple: true },
137
+ {
138
+ type: 'string',
139
+ name: 'id',
140
+ header: i18next.t('field.id'),
141
+ hidden: true,
142
+ record: { editable: false },
143
+ imex: { header: i18next.t('field.id'), key: 'id', width: 100, type: 'string' },
144
+ width: 70
145
+ },
146
+ {
147
+ type: 'gutter',
148
+ gutterName: 'button',
149
+ icon: 'drive_file_rename_outline',
150
+ handlers: {
151
+ click: 'record-view'
152
+ }
153
+ },
154
+ {
155
+ type: 'string',
156
+ name: 'name',
157
+ header: i18next.t('field.operation'),
158
+ record: { editable: true, mandatory: true },
159
+ imex: { header: i18next.t('field.operation'), key: 'name', width: 100, type: 'string' },
160
+ filter: 'search',
161
+ sortable: true,
162
+ width: 120
163
+ },
164
+ {
165
+ type: 'string',
166
+ name: 'description',
167
+ header: i18next.t('field.description'),
168
+ record: { editable: true },
169
+ imex: { header: i18next.t('field.description'), key: 'description', width: 100, type: 'string' },
170
+ filter: 'search',
171
+ width: 240
172
+ },
173
+ {
174
+ type: 'select',
175
+ name: 'type',
176
+ header: i18next.t('field.type'),
177
+ label: true,
178
+ record: {
179
+ editable: true,
180
+ align: 'center',
181
+ options: ['', ...OperationStatus]
182
+ },
183
+ sortable: true,
184
+ props: { searchOper: 'eq' },
185
+ width: 120,
186
+ hidden: true
187
+ },
188
+ {
189
+ type: 'string',
190
+ name: 'operationStdChart',
191
+ header: i18next.t('field.operation_std_chart'),
192
+ label: true,
193
+ record: { editable: true },
194
+ imex: {
195
+ header: i18next.t('field.operation_std_chart'),
196
+ key: 'operationStdChart',
197
+ width: 100,
198
+ type: 'string'
199
+ },
200
+ width: 120,
201
+ hidden: true
202
+ },
203
+ {
204
+ type: 'string',
205
+ name: 'operationStdTime',
206
+ header: i18next.t('field.operation_std_time'),
207
+ label: true,
208
+ record: { editable: true },
209
+ imex: { header: i18next.t('field.operation_std_time'), key: 'operationStdTime', width: 100, type: 'integer' },
210
+ width: 120,
211
+ hidden: true
212
+ },
213
+ {
214
+ type: 'boolean',
215
+ name: 'active',
216
+ header: i18next.t('field.active'),
217
+ record: { editable: true },
218
+ imex: { header: i18next.t('field.active'), key: 'active', width: 100, type: 'boolean' },
219
+ width: 120,
220
+ hidden: true
221
+ },
222
+ {
223
+ type: 'image',
224
+ name: 'thumbnail',
225
+ header: i18next.t('field.thumbnail'),
226
+ record: { editable: true },
227
+ width: 120
228
+ },
229
+ {
230
+ type: 'object',
231
+ name: 'updater',
232
+ header: i18next.t('field.updater'),
233
+ record: { editable: false },
234
+ width: 80
235
+ },
236
+ {
237
+ type: 'datetime',
238
+ name: 'updatedAt',
239
+ header: i18next.t('field.updated_at'),
240
+ record: { editable: false },
241
+ sortable: true,
242
+ width: 180
243
+ }
244
+ ],
245
+ sorters: [
246
+ {
247
+ name: 'name',
248
+ desc: false
249
+ }
250
+ ]
251
+ }
252
+ }
253
+
254
+ pageUpdated(changes, lifecycle, before) {
255
+ if (this.active) {
256
+ this.grist.fetch()
257
+ }
258
+ }
259
+
260
+ get grist() {
261
+ return this.renderRoot.querySelector('ox-grist')
262
+ }
263
+
264
+ _importableData(records) {
265
+ setTimeout(() => {
266
+ openPopup(
267
+ html`
268
+ <import-pop-up
269
+ .records=${records}
270
+ .config=${{
271
+ rows: this.config.rows,
272
+ columns: [...this.config.columns.filter(column => !!column.imex)]
273
+ }}
274
+ .importHandler="${this.importHandler.bind(this)}"
275
+ ></import-pop-up>
276
+ `,
277
+ {
278
+ backdrop: true,
279
+ size: 'large',
280
+ title: i18next.t('title.import')
281
+ }
282
+ )
283
+ }, 500)
284
+ }
285
+
286
+ async fetchHandler() {
287
+ const response = await fetchOperations(...arguments)
288
+
289
+ return {
290
+ total: response.data.operations.total || 0,
291
+ records: response.data.operations.items || []
292
+ }
293
+ }
294
+
295
+ async importHandler(patches) {
296
+ const response = await saveOperations(patches)
297
+
298
+ if (!response.errors) {
299
+ history.back()
300
+ this.grist.fetch()
301
+ document.dispatchEvent(
302
+ new CustomEvent('notify', {
303
+ detail: {
304
+ message: i18next.t('text.data_imported_successfully')
305
+ }
306
+ })
307
+ )
308
+ }
309
+ }
310
+
311
+ async operationCreationCallback(operation) {
312
+ try {
313
+ const response = await createOperation(operation)
314
+
315
+ if (!response.errors) {
316
+ this.grist.fetch()
317
+ document.dispatchEvent(
318
+ new CustomEvent('notify', {
319
+ detail: {
320
+ message: i18next.t('text.data_created_successfully')
321
+ }
322
+ })
323
+ )
324
+ }
325
+
326
+ return true
327
+ } catch (ex) {
328
+ console.error(ex)
329
+ document.dispatchEvent(
330
+ new CustomEvent('notify', {
331
+ detail: {
332
+ type: 'error',
333
+ message: i18next.t('text.error')
334
+ }
335
+ })
336
+ )
337
+ return false
338
+ }
339
+ }
340
+
341
+ async _saveOperations() {
342
+ let patches = this.grist.exportPatchList({ flagName: 'cuFlag' })
343
+ if (patches && patches.length) {
344
+ const response = await saveOperations(patches)
345
+
346
+ if (!response.errors) {
347
+ this.grist.fetch()
348
+ document.dispatchEvent(
349
+ new CustomEvent('notify', {
350
+ detail: {
351
+ message: i18next.t('text.data_updated_successfully')
352
+ }
353
+ })
354
+ )
355
+ }
356
+ }
357
+ }
358
+
359
+ async _deleteOperations() {
360
+ const select = this.grist.selected
361
+ if (!select.length) {
362
+ CustomAlert({
363
+ title: i18next.t('text.nothing_selected'),
364
+ text: i18next.t('text.there_is_nothing_to_delete')
365
+ })
366
+ } else {
367
+ CustomAlert({
368
+ title: i18next.t('text.are_you_sure'),
369
+ text: i18next.t('text.you_wont_be_able_to_revert_this'),
370
+ type: 'warning',
371
+ confirmButton: { text: i18next.t('button.delete'), color: '#22a6a7' },
372
+ cancelButton: { text: 'cancel', color: '#cfcfcf' },
373
+ callback: async result => {
374
+ if (result.value) {
375
+ const ids = this.grist.selected.map(record => record.id)
376
+ if (ids && ids.length > 0) {
377
+ const response = await deleteOperations(ids)
378
+
379
+ if (!response.errors) {
380
+ this.grist.fetch()
381
+ document.dispatchEvent(
382
+ new CustomEvent('notify', {
383
+ detail: {
384
+ message: i18next.t('text.data_deleted_successfully')
385
+ }
386
+ })
387
+ )
388
+ }
389
+ }
390
+ }
391
+ }
392
+ })
393
+ }
394
+ }
395
+
396
+ get _columns() {
397
+ return this.config.columns
398
+ }
399
+
400
+ _exportableData() {
401
+ let records = []
402
+ if (this.grist.selected && this.grist.selected.length > 0) {
403
+ records = this.grist.selected
404
+ } else {
405
+ records = this.grist.data.records
406
+ }
407
+
408
+ var headerSetting = this.grist.compiledConfig.columns
409
+ .filter(column => column.type !== 'gutter' && column.record !== undefined && column.imex !== undefined)
410
+ .map(column => {
411
+ return column.imex
412
+ })
413
+
414
+ var data = records.map(item => {
415
+ return {
416
+ id: item.id,
417
+ ...this._columns
418
+ .filter(column => column.type !== 'gutter' && column.record !== undefined && column.imex !== undefined)
419
+ .reduce((record, column) => {
420
+ record[column.imex.key] = column.imex.key
421
+ .split('.')
422
+ .reduce((obj, key) => (obj && obj[key] !== 'undefined' ? obj[key] : undefined), item)
423
+ return record
424
+ }, {})
425
+ }
426
+ })
427
+
428
+ return { header: headerSetting, data: data }
429
+ }
430
+ }
431
+
432
+ customElements.define('operation-master', OperationMaster)
@@ -1,7 +1,7 @@
1
1
  import '@material/mwc-linear-progress'
2
2
  import '@operato/help/ox-help-icon.js'
3
3
 
4
- import { gql } from 'graphql-tag'
4
+ import gql from 'graphql-tag'
5
5
  import { css, html } from 'lit'
6
6
  import { connect } from 'pwa-helpers/connect-mixin.js'
7
7
 
@@ -0,0 +1,150 @@
1
+ import gql from 'graphql-tag'
2
+
3
+ import { client } from '@operato/graphql'
4
+
5
+ export async function fetchProducts({ filters = [], page, limit, sortings = [] }) {
6
+ const response = await client.query({
7
+ query: gql`
8
+ query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {
9
+ myBizplaceProducts(filters: $filters, pagination: $pagination, sortings: $sortings) {
10
+ items {
11
+ sku
12
+ id
13
+ name
14
+ description
15
+ productRef {
16
+ sku
17
+ name
18
+ description
19
+ }
20
+ parentProductRef {
21
+ sku
22
+ name
23
+ description
24
+ }
25
+ routing {
26
+ id
27
+ name
28
+ }
29
+ refCode
30
+ bundleQty
31
+ packingType
32
+ type
33
+ thumbnail
34
+ inventoryAccountCode
35
+ cogsAccountCode
36
+ expirationPeriod
37
+ isRequiredCheckExpiry
38
+ weightUnit
39
+ nettWeight
40
+ grossWeight
41
+ density
42
+ lengthUnit
43
+ volume
44
+ width
45
+ depth
46
+ height
47
+ volumeSize
48
+ uom
49
+ uomValue
50
+ costPrice
51
+ afterTaxCostPrice
52
+ sellPrice
53
+ afterTaxSalesPrice
54
+ mrpPrice
55
+ bufferQty
56
+ minQty
57
+ maxQty
58
+ auxUnit1
59
+ auxValue1
60
+ auxUnit2
61
+ auxValue2
62
+ auxUnit3
63
+ auxValue3
64
+ auxUnit4
65
+ auxValue4
66
+ auxUnit5
67
+ auxValue5
68
+ brandSku
69
+ brand
70
+ subBrand
71
+ gtin
72
+ updater {
73
+ name
74
+ description
75
+ }
76
+ updatedAt
77
+ }
78
+ total
79
+ }
80
+ }
81
+ `,
82
+ variables: {
83
+ filters,
84
+ pagination: { page, limit },
85
+ sortings
86
+ }
87
+ })
88
+
89
+ if (!response.errors) {
90
+ return {
91
+ total: response.data.myBizplaceProducts.total || 0,
92
+ records:
93
+ response.data.myBizplaceProducts.items.map(itm => {
94
+ return {
95
+ ...itm,
96
+ productRef: { name: itm?.productRef ? '(' + itm.productRef.sku + ') ' + itm.productRef.name : '' }
97
+ }
98
+ }) || []
99
+ }
100
+ }
101
+ }
102
+
103
+ export async function deleteProducts(ids) {
104
+ return await client.query({
105
+ query: gql`
106
+ mutation ($ids: [String!]!) {
107
+ deleteProducts(ids: $ids)
108
+ }
109
+ `,
110
+ variables: {
111
+ ids
112
+ }
113
+ })
114
+ }
115
+
116
+ export async function saveProducts(patches) {
117
+ return await client.query({
118
+ query: gql`
119
+ mutation ($patches: [ProductPatch!]!) {
120
+ updateMultipleProduct(patches: $patches) {
121
+ id
122
+ }
123
+ }
124
+ `,
125
+ variables: {
126
+ patches
127
+ },
128
+ context: {
129
+ hasUpload: true
130
+ }
131
+ })
132
+ }
133
+
134
+ export async function createProduct(product) {
135
+ return await client.query({
136
+ query: gql`
137
+ mutation ($product: NewProduct!) {
138
+ createProduct(product: $product) {
139
+ id
140
+ }
141
+ }
142
+ `,
143
+ variables: {
144
+ product
145
+ },
146
+ context: {
147
+ hasUpload: true
148
+ }
149
+ })
150
+ }