@things-factory/operato-wms 5.0.0-alpha.38 → 5.0.0-alpha.39

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 (54) hide show
  1. package/client/pages/inbound/unload-product.js +11 -7
  2. package/client/pages/inventory/inventory-adjustment.js +8 -8
  3. package/client/pages/inventory-check/inspecting-product.js +13 -7
  4. package/client/pages/order/goods-received-note/customer-received-note.js +3 -0
  5. package/client/pages/order/goods-received-note/received-note-detail.js +3 -0
  6. package/client/pages/order/release-order/release-extra-product-popup.js +15 -10
  7. package/client/pages/outbound/merged-outbound-worksheet.js +7 -1
  8. package/client/pages/outbound/picking-product.js +1 -1
  9. package/client/pages/outbound/select-operator-popup.js +86 -14
  10. package/client/pages/outbound/single-outbound-worksheet.js +22 -14
  11. package/client/pages/outbound/worksheet-batch-picking.js +1 -1
  12. package/client/pages/outbound/worksheet-picking.js +1 -1
  13. package/client/pages/report/costing-report.js +453 -0
  14. package/client/pages/report/inbound-order-details-report.js +14 -0
  15. package/client/pages/report/outbound-order-details-report.js +12 -0
  16. package/client/pages/vas/print-product-label.js +15 -6
  17. package/client/route.js +4 -0
  18. package/dist-server/graphql/resolvers/reports/costing-report.js +172 -0
  19. package/dist-server/graphql/resolvers/reports/costing-report.js.map +1 -0
  20. package/dist-server/graphql/resolvers/reports/inbound-order-details-report.js +2 -0
  21. package/dist-server/graphql/resolvers/reports/inbound-order-details-report.js.map +1 -1
  22. package/dist-server/graphql/resolvers/reports/index.js +2 -1
  23. package/dist-server/graphql/resolvers/reports/index.js.map +1 -1
  24. package/dist-server/graphql/resolvers/reports/outbound-order-details-report.js +10 -3
  25. package/dist-server/graphql/resolvers/reports/outbound-order-details-report.js.map +1 -1
  26. package/dist-server/graphql/types/reports/costing-report-list.js +14 -0
  27. package/dist-server/graphql/types/reports/costing-report-list.js.map +1 -0
  28. package/dist-server/graphql/types/reports/costing-report.js +19 -0
  29. package/dist-server/graphql/types/reports/costing-report.js.map +1 -0
  30. package/dist-server/graphql/types/reports/inbound-order-details-report.js +1 -0
  31. package/dist-server/graphql/types/reports/inbound-order-details-report.js.map +1 -1
  32. package/dist-server/graphql/types/reports/index.js +6 -1
  33. package/dist-server/graphql/types/reports/index.js.map +1 -1
  34. package/dist-server/graphql/types/reports/outbound-order-details-report.js +1 -0
  35. package/dist-server/graphql/types/reports/outbound-order-details-report.js.map +1 -1
  36. package/helps/release-note.ko.md +22 -19
  37. package/helps/release-note.md +22 -19
  38. package/helps/release-note.ms.md +22 -19
  39. package/helps/release-note.zh.md +22 -19
  40. package/package.json +43 -43
  41. package/server/graphql/resolvers/reports/costing-report.ts +196 -0
  42. package/server/graphql/resolvers/reports/inbound-order-details-report.ts +2 -0
  43. package/server/graphql/resolvers/reports/index.ts +2 -0
  44. package/server/graphql/resolvers/reports/outbound-order-details-report.ts +10 -3
  45. package/server/graphql/types/reports/costing-report-list.ts +8 -0
  46. package/server/graphql/types/reports/costing-report.ts +13 -0
  47. package/server/graphql/types/reports/inbound-order-details-report.ts +1 -0
  48. package/server/graphql/types/reports/index.ts +7 -1
  49. package/server/graphql/types/reports/outbound-order-details-report.ts +1 -0
  50. package/things-factory.config.js +4 -0
  51. package/translations/en.json +8 -2
  52. package/translations/ko.json +2 -0
  53. package/translations/ms.json +2 -0
  54. package/translations/zh.json +2 -0
@@ -0,0 +1,453 @@
1
+ import '@things-factory/form-ui'
2
+ import '@things-factory/grist-ui'
3
+ import '../inventory/inventory-by-product-detail'
4
+
5
+ import gql from 'graphql-tag'
6
+ import { css, html } from 'lit-element'
7
+ import { connect } from 'pwa-helpers/connect-mixin'
8
+
9
+ import { getCodeByName } from '@things-factory/code-base'
10
+ import { i18next, localize } from '@things-factory/i18n-base'
11
+ import { client, gqlContext, PageView, store } from '@things-factory/shell'
12
+ import { flattenObject, isMobileDevice } from '@things-factory/utils'
13
+
14
+ class CostingReport extends connect(store)(localize(i18next)(PageView)) {
15
+ static get styles() {
16
+ return css`
17
+ :host {
18
+ display: flex;
19
+ flex-direction: column;
20
+ width: 100%;
21
+ }
22
+
23
+ data-grist {
24
+ overflow-y: auto;
25
+ flex: 1;
26
+ }
27
+
28
+ .summary {
29
+ background-color: var(--main-section-background-color);
30
+ display: flex;
31
+ flex-direction: column;
32
+ overflow-y: auto;
33
+ align-items: flex-end;
34
+ padding: var(--data-list-item-padding);
35
+ display: grid;
36
+ font-size: 14px;
37
+ color: #394e64;
38
+ grid-template-columns: repeat(2, 1fr);
39
+ grid-auto-rows: minmax(24px, auto);
40
+ }
41
+ `
42
+ }
43
+
44
+ static get properties() {
45
+ return {
46
+ _searchFields: Object,
47
+ _config: Object,
48
+ _partners: Object,
49
+ _gristData: Object,
50
+ data: Object
51
+ }
52
+ }
53
+
54
+ get context() {
55
+ return {
56
+ title: 'Costing Report',
57
+ exportable: {
58
+ name: i18next.t('title.costing_report'),
59
+ data: this._exportableData.bind(this)
60
+ },
61
+ help: 'operato-wms/report/costing-report'
62
+ }
63
+ }
64
+
65
+ get dataGrist() {
66
+ return this.shadowRoot.querySelector('data-grist')
67
+ }
68
+
69
+ get searchForm() {
70
+ return this.shadowRoot.querySelector('search-form')
71
+ }
72
+
73
+ get _bizplaceSelector() {
74
+ return this.searchForm.shadowRoot.querySelector('select[name=bizplace]')
75
+ }
76
+
77
+ get _fromDateInput() {
78
+ return this.searchForm.shadowRoot.querySelector('input[name=fromDate]')
79
+ }
80
+
81
+ get _toDateInput() {
82
+ return this.searchForm.shadowRoot.querySelector('input[name=toDate]')
83
+ }
84
+
85
+ get searchFields() {
86
+ return [
87
+ {
88
+ label: i18next.t('field.company'),
89
+ name: 'bizplace',
90
+ type: 'select',
91
+ options: [
92
+ { value: '' },
93
+ ...this._partners
94
+ .map(partner => {
95
+ return {
96
+ name: `${partner.name} ${partner.description ? `(${partner.description})` : ''}`,
97
+ value: partner.id
98
+ }
99
+ })
100
+ .sort(this._compareValues('name', 'asc'))
101
+ ],
102
+ props: { searchOper: 'eq' }
103
+ },
104
+ {
105
+ label: i18next.t('field.from_date'),
106
+ name: 'fromDate',
107
+ type: 'date',
108
+ props: {
109
+ searchOper: 'eq',
110
+ max: new Date().toISOString().split('T')[0]
111
+ },
112
+ value: (() => {
113
+ let date = new Date()
114
+ date.setMonth(date.getMonth() - 1)
115
+ return date.toISOString().split('T')[0]
116
+ })(),
117
+ handlers: { change: this._modifyDateRange.bind(this) }
118
+ },
119
+ {
120
+ label: i18next.t('field.to_date'),
121
+ name: 'toDate',
122
+ type: 'date',
123
+ props: {
124
+ searchOper: 'eq',
125
+ min: (() => {
126
+ let date = new Date()
127
+ date.setMonth(date.getMonth() - 1)
128
+ return date.toISOString().split('T')[0]
129
+ })(),
130
+ max: (() => {
131
+ var max = new Date()
132
+ max.setMonth(max.getMonth() + 1)
133
+ return max.toISOString().split('T')[0]
134
+ })()
135
+ },
136
+ value: new Date().toISOString().split('T')[0]
137
+ // handlers: { change: this._submit.bind(this) }
138
+ }
139
+ ]
140
+ }
141
+
142
+ get reportConfig() {
143
+ let columns = [
144
+ { type: 'gutter', gutterName: 'sequence' },
145
+ {
146
+ type: 'string',
147
+ name: 'bizplace|name',
148
+ header: i18next.t('field.company'),
149
+ width: 200
150
+ },
151
+ {
152
+ type: 'string',
153
+ name: 'product|sku',
154
+ header: i18next.t('field.sku'),
155
+ width: 150
156
+ },
157
+ {
158
+ type: 'string',
159
+ name: 'product|name',
160
+ header: i18next.t('field.product_name'),
161
+ width: 200
162
+ },
163
+ {
164
+ type: 'string',
165
+ name: 'product|description',
166
+ header: i18next.t('field.product_description'),
167
+ width: 300
168
+ },
169
+ {
170
+ type: 'string',
171
+ name: 'product|type',
172
+ header: i18next.t('field.product_type'),
173
+ width: 150
174
+ },
175
+ {
176
+ type: 'float',
177
+ name: 'qty',
178
+ header: i18next.t('field.qty'),
179
+ width: 120
180
+ },
181
+ {
182
+ type: 'float',
183
+ name: 'uomValue',
184
+ header: i18next.t('field.uom_value'),
185
+ width: 120
186
+ },
187
+ {
188
+ type: 'string',
189
+ name: 'uom',
190
+ header: i18next.t('field.uom'),
191
+ width: 100
192
+ },
193
+ {
194
+ type: 'string',
195
+ name: 'weightedAvgUnitCost',
196
+ header: 'Weighted Avg Unit Cost',
197
+ width: 100
198
+ },
199
+ {
200
+ type: 'string',
201
+ name: 'totalCost',
202
+ header: i18next.t('field.total_cost'),
203
+ width: 100
204
+ }
205
+ ]
206
+ let list = {
207
+ fields: [
208
+ 'bizplace|name',
209
+ 'product|sku',
210
+ 'product|name',
211
+ 'product|description',
212
+ 'product|type',
213
+ 'qty',
214
+ 'uomValue',
215
+ 'uom',
216
+ 'weightedAvgUnitCost',
217
+ 'totalCost'
218
+ ]
219
+ }
220
+
221
+ return {
222
+ columns: columns,
223
+ list,
224
+ pagination: { limit: 100, pages: [100, 200, 500, 1000] },
225
+ rows: {
226
+ selectable: false,
227
+ insertable: false,
228
+ appendable: false
229
+ }
230
+ }
231
+ }
232
+
233
+ render() {
234
+ return html`
235
+ <search-form id="search-form" .fields=${this._searchFields} @submit=${e => this.dataGrist.fetch()}></search-form>
236
+
237
+ <data-grist
238
+ .mode=${isMobileDevice() ? 'LIST' : 'GRID'}
239
+ .config=${this._config}
240
+ .fetchHandler="${this.fetchHandler.bind(this)}"
241
+ ></data-grist>
242
+ `
243
+ }
244
+
245
+ async pageInitialized() {
246
+ this._gristData = { total: 0, records: [] }
247
+ this._products = []
248
+
249
+ const [_partnersReq] = await Promise.allSettled([this._fetchPartners()])
250
+
251
+ this._partners = _partnersReq.status == 'fulfilled' ? _partnersReq.value : []
252
+
253
+ this._searchFields = this.searchFields
254
+ this._config = this.reportConfig
255
+ }
256
+
257
+ async pageUpdated(changes, lifecycle) {
258
+ if (this.active) {
259
+ this.dataGrist.fetch()
260
+ }
261
+ }
262
+
263
+ async fetchHandler({ page, limit, sorters = [] }) {
264
+ try {
265
+ this._validate()
266
+ let filters = this.searchForm.queryFilters.map(filter => {
267
+ switch (filter.name) {
268
+ case 'fromDate':
269
+ let fromDt = new Date(filter.value)
270
+ fromDt.setHours(0)
271
+ filter.value = fromDt.toISOString()
272
+ break
273
+ case 'toDate':
274
+ let toDt = new Date(filter.value)
275
+ toDt.setHours(23, 59, 59)
276
+ filter.value = toDt.toISOString()
277
+ break
278
+ default:
279
+ break
280
+ }
281
+ return filter
282
+ })
283
+
284
+ const pagination = { page, limit }
285
+ const sortings = sorters
286
+
287
+ const response = await client.query({
288
+ query: gql`
289
+ query costingReport($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {
290
+ costingReport(filters: $filters, pagination: $pagination, sortings: $sortings) {
291
+ items {
292
+ bizplace {
293
+ name
294
+ description
295
+ }
296
+ product {
297
+ sku
298
+ name
299
+ description
300
+ type
301
+ }
302
+ qty
303
+ uomValue
304
+ uom
305
+ weightedAvgUnitCost
306
+ totalCost
307
+ }
308
+ total
309
+ }
310
+ }
311
+ `,
312
+ variables: { filters, pagination, sortings },
313
+ context: gqlContext()
314
+ })
315
+
316
+ const data = {
317
+ total: response.data.costingReport.total,
318
+ records:
319
+ response.data.costingReport.items.map(itm => {
320
+ itm = {
321
+ ...itm,
322
+ weightedAvgUnitCost: parseFloat(itm.weightedAvgUnitCost ? itm.weightedAvgUnitCost : 0).toFixed(4),
323
+ totalCost: parseFloat(itm.totalCost ? itm.totalCost : 0).toFixed(4)
324
+ }
325
+ return flattenObject({ ...itm, bizplace: { name: `${itm.bizplace.name} ${itm.bizplace.description}` } })
326
+ }) || []
327
+ }
328
+
329
+ this._gristData = {
330
+ ...data
331
+ }
332
+
333
+ return data
334
+ } catch (e) {
335
+ this._showToast(e)
336
+ }
337
+ }
338
+
339
+ async _fetchPartners() {
340
+ const filters = []
341
+ const response = await client.query({
342
+ query: gql`
343
+ query partnersBizplaces($filters: [Filter!]) {
344
+ partnersBizplaces(filters: $filters) {
345
+ items {
346
+ id
347
+ name
348
+ description
349
+ }
350
+ }
351
+ }
352
+ `,
353
+ variables: { filters }
354
+ })
355
+
356
+ if (!response.errors) {
357
+ return response.data.partnersBizplaces.items
358
+ }
359
+ }
360
+ _validate() {
361
+ if (!this.searchForm.shadowRoot.querySelector('form').checkValidity())
362
+ throw new Error(i18next.t('text.invalid_form_value'))
363
+ if (!this._bizplaceSelector.value) throw new Error(i18next.t('text.no_company_selected'))
364
+ if (!this._fromDateInput.value) throw new Error(i18next.t('text.from_date_is_empty'))
365
+ if (!this._toDateInput.value) throw new Error(i18next.t('text.to_date_is_empty'))
366
+ }
367
+
368
+ _compareValues(key, order = 'asc') {
369
+ return function innerSort(a, b) {
370
+ if (!a.hasOwnProperty(key) || !b.hasOwnProperty(key)) {
371
+ return 0
372
+ }
373
+
374
+ const varA = typeof a[key] === 'string' ? a[key].toUpperCase() : a[key]
375
+ const varB = typeof b[key] === 'string' ? b[key].toUpperCase() : b[key]
376
+
377
+ let comparison = 0
378
+ if (varA > varB) {
379
+ comparison = 1
380
+ } else if (varA < varB) {
381
+ comparison = -1
382
+ }
383
+ return order === 'desc' ? comparison * -1 : comparison
384
+ }
385
+ }
386
+
387
+ _modifyDateRange(e) {
388
+ const fromDate = e.currentTarget.value
389
+
390
+ let min = new Date(fromDate)
391
+ let max = new Date(fromDate)
392
+ max.setMonth(max.getMonth() + 2)
393
+
394
+ min = min.toISOString().split('T')[0]
395
+ max = max.toISOString().split('T')[0]
396
+
397
+ if (this._toDateInput.value < fromDate) this._toDateInput.value = fromDate
398
+
399
+ if (this._toDateInput.value > max) this._toDateInput.value = max
400
+
401
+ this._toDateInput.max = max
402
+ this._toDateInput.min = min
403
+ this._submit()
404
+ }
405
+
406
+ _submit(e) {
407
+ this._config = { ...this.reportConfig }
408
+ this.searchForm.submit()
409
+ }
410
+
411
+ async _exportableData() {
412
+ try {
413
+ var headerSetting = [
414
+ { header: i18next.t('field.company'), key: 'bizplace|name', width: 60, type: 'string' },
415
+ { header: i18next.t('field.sku'), key: 'product|sku', width: 25, type: 'string' },
416
+ { header: i18next.t('field.product_name'), key: 'product|name', width: 50, type: 'string' },
417
+ { header: i18next.t('field.product_description'), key: 'product|description', width: 50, type: 'string' },
418
+ { header: i18next.t('field.product_type'), key: 'product|type', width: 30, type: 'string' },
419
+ { header: i18next.t('field.qty'), key: 'qty', width: 15, type: 'string' },
420
+ { header: i18next.t('field.uom_value'), key: 'uomValue', width: 15, type: 'string' },
421
+ { header: i18next.t('field.uom'), key: 'uom', width: 15, type: 'string' },
422
+ { header: 'Weighted Avg Unit Cost', key: 'weightedAvgUnitCost', width: 15, type: 'string' },
423
+ { header: i18next.t('field.total_cost'), key: 'totalCost', width: 15, type: 'string' }
424
+ ]
425
+
426
+ var exportData = {
427
+ header: [...headerSetting],
428
+ data: (await this.fetchHandler({ page: 1, limit: 9999999 })).records.map(itm => {
429
+ return {
430
+ ...itm
431
+ }
432
+ })
433
+ }
434
+
435
+ return exportData
436
+ } catch (e) {
437
+ this._showToast(e)
438
+ }
439
+ }
440
+
441
+ _showToast({ type, message }) {
442
+ document.dispatchEvent(
443
+ new CustomEvent('notify', {
444
+ detail: {
445
+ type,
446
+ message
447
+ }
448
+ })
449
+ )
450
+ }
451
+ }
452
+
453
+ window.customElements.define('costing-report', CostingReport)
@@ -362,6 +362,12 @@ class InboundOrderDetailsReport extends connect(store)(localize(i18next)(PageVie
362
362
  header: i18next.t('field.uom'),
363
363
  width: 100
364
364
  },
365
+ {
366
+ type: 'string',
367
+ name: 'unitCost',
368
+ header: i18next.t('field.unit_cost'),
369
+ width: 100
370
+ },
365
371
  {
366
372
  type: 'float',
367
373
  name: 'unitVolume',
@@ -497,6 +503,7 @@ class InboundOrderDetailsReport extends connect(store)(localize(i18next)(PageVie
497
503
  'qty',
498
504
  'uomValue',
499
505
  'uom',
506
+ 'unitCost',
500
507
  'unitVolume',
501
508
  'totalVolume',
502
509
  'unitNettWeight',
@@ -613,6 +620,7 @@ class InboundOrderDetailsReport extends connect(store)(localize(i18next)(PageVie
613
620
  qty
614
621
  uomValue
615
622
  uom
623
+ unitCost
616
624
  unitVolume
617
625
  totalVolume
618
626
  unitNettWeight
@@ -643,6 +651,11 @@ class InboundOrderDetailsReport extends connect(store)(localize(i18next)(PageVie
643
651
  total: response.data.inboundOrderDetailsReport.total,
644
652
  records:
645
653
  response.data.inboundOrderDetailsReport.items.map(itm => {
654
+ itm = {
655
+ ...itm,
656
+ unitCost: parseFloat(itm.unitCost ? itm.unitCost : 0).toFixed(2)
657
+ }
658
+
646
659
  return flattenObject({ ...itm, bizplace: { name: `${itm.bizplace.name} ${itm.bizplace.description}` } })
647
660
  }) || []
648
661
  }
@@ -758,6 +771,7 @@ class InboundOrderDetailsReport extends connect(store)(localize(i18next)(PageVie
758
771
  { header: i18next.t('field.qty'), key: 'qty', width: 15, type: 'string' },
759
772
  { header: i18next.t('field.uom_value'), key: 'uomValue', width: 15, type: 'string' },
760
773
  { header: i18next.t('field.uom'), key: 'uom', width: 15, type: 'string' },
774
+ { header: i18next.t('field.unit_cost'), key: 'unitCost', width: 15, type: 'string' },
761
775
  { header: i18next.t('field.unit_volume'), key: 'unitVolume', width: 15, type: 'string' },
762
776
  { header: i18next.t('field.total_volume'), key: 'totalVolume', width: 15, type: 'string' },
763
777
  { header: i18next.t('field.unit_nett_weight'), key: 'unitNettWeight', width: 15, type: 'string' },
@@ -330,6 +330,12 @@ class OutboundOrderDetailsReport extends connect(store)(localize(i18next)(PageVi
330
330
  header: i18next.t('field.uom'),
331
331
  width: 100
332
332
  },
333
+ {
334
+ type: 'string',
335
+ name: 'unitCost',
336
+ header: i18next.t('field.unit_cost'),
337
+ width: 100
338
+ },
333
339
  {
334
340
  type: 'float',
335
341
  name: 'returnToLocationQty',
@@ -489,6 +495,7 @@ class OutboundOrderDetailsReport extends connect(store)(localize(i18next)(PageVi
489
495
  'qty',
490
496
  'uomValue',
491
497
  'uom',
498
+ 'unitCost',
492
499
  'returnToLocationQty',
493
500
  'returnToLocationUomValue',
494
501
  'unitVolume',
@@ -609,6 +616,7 @@ class OutboundOrderDetailsReport extends connect(store)(localize(i18next)(PageVi
609
616
  returnToLocationQty
610
617
  returnToLocationUomValue
611
618
  uom
619
+ unitCost
612
620
  unitVolume
613
621
  totalVolume
614
622
  unitNettWeight
@@ -642,6 +650,10 @@ class OutboundOrderDetailsReport extends connect(store)(localize(i18next)(PageVi
642
650
  total: response.data.outboundOrderDetailsReport.total,
643
651
  records:
644
652
  response.data.outboundOrderDetailsReport.items.map(itm => {
653
+ itm = {
654
+ ...itm,
655
+ unitCost: parseFloat(itm.unitCost ? itm.unitCost : 0).toFixed(2)
656
+ }
645
657
  return flattenObject({ ...itm, bizplace: { name: `${itm.bizplace.name} ${itm.bizplace.description}` } })
646
658
  }) || []
647
659
  }
@@ -786,12 +786,21 @@ class PrintProductLabel extends connect(store)(localize(i18next)(PageView)) {
786
786
  }
787
787
  } catch (ex) {
788
788
  this._showToast({ level: 'error', message: ex })
789
-
790
789
  delete this.printer
791
790
  break
792
791
  } finally {
793
792
  // we only need to update when the counter is more than 0
794
- if (printCounter > 0) await this._updatePrintedLabelSequence(record.type, printCounter, record.bizplaceId)
793
+ if (printCounter > 0) {
794
+ try {
795
+ await this._updatePrintedLabelSequence(record.type, printCounter, record.bizplaceId)
796
+ } catch (e) {
797
+ this._showToast({
798
+ level: 'error',
799
+ message: i18next.t('text.unable_to_save_print_history_x', { state: { counter: printCounter } })
800
+ })
801
+ return
802
+ }
803
+ }
795
804
  }
796
805
  }
797
806
  }
@@ -801,8 +810,8 @@ class PrintProductLabel extends connect(store)(localize(i18next)(PageView)) {
801
810
  try {
802
811
  await client.mutate({
803
812
  mutation: gql`
804
- mutation updateInsertSequence($type: String!, $counter: Int, $bizplaceId: String!) {
805
- updateInsertSequence(type: $type, counter: $counter, bizplaceId: $bizplaceId) {
813
+ mutation upsertSequence($type: String!, $counter: Float!, $bizplaceId: String!) {
814
+ upsertSequence(type: $type, counter: $counter, bizplaceId: $bizplaceId) {
806
815
  pattern
807
816
  seq
808
817
  }
@@ -814,8 +823,8 @@ class PrintProductLabel extends connect(store)(localize(i18next)(PageView)) {
814
823
  bizplaceId
815
824
  }
816
825
  })
817
- } catch (e) {
818
- this._showToast({ message: e })
826
+ } catch (error) {
827
+ throw error
819
828
  }
820
829
  }
821
830
 
package/client/route.js CHANGED
@@ -463,6 +463,10 @@ export default function route(page) {
463
463
  case 'outbound_serial_number_report':
464
464
  import('./pages/report/outbound-serial-number-report')
465
465
  return page
466
+
467
+ case 'costing_report':
468
+ import('./pages/report/costing-report')
469
+ return page
466
470
  /**
467
471
  * Custom ELCCL Menus Section
468
472
  */