@things-factory/operato-mms 3.7.6 → 3.7.10

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.
@@ -0,0 +1,383 @@
1
+ import '@things-factory/form-ui'
2
+ import '@things-factory/grist-ui'
3
+
4
+ import gql from 'graphql-tag'
5
+ import { css, html } from 'lit-element'
6
+ import { connect } from 'pwa-helpers/connect-mixin.js'
7
+
8
+ import { i18next, localize } from '@things-factory/i18n-base'
9
+ import { client, PageView, store } from '@things-factory/shell'
10
+ import { ScrollbarStyles } from '@things-factory/styles'
11
+ import { isMobileDevice } from '@things-factory/utils'
12
+
13
+ class ShopeeSalesReport extends connect(store)(localize(i18next)(PageView)) {
14
+ static get styles() {
15
+ return [
16
+ ScrollbarStyles,
17
+ css`
18
+ :host {
19
+ display: flex;
20
+ flex-direction: column;
21
+
22
+ overflow: hidden;
23
+ }
24
+
25
+ search-form {
26
+ overflow: visible;
27
+ }
28
+ data-grist {
29
+ overflow-y: auto;
30
+ flex: 1;
31
+ }
32
+ `
33
+ ]
34
+ }
35
+
36
+ static get properties() {
37
+ return {
38
+ _searchFields: Array,
39
+ _config: Object
40
+ }
41
+ }
42
+
43
+ get context() {
44
+ return {
45
+ title: i18next.t('title.shopee_sales_report'),
46
+ exportable: {
47
+ name: i18next.t('title.shopee_sales_report'),
48
+ data: this._exportableData.bind(this)
49
+ }
50
+ }
51
+ }
52
+
53
+ get _searchForm() {
54
+ return this.shadowRoot.querySelector('search-form')
55
+ }
56
+
57
+ get _dataGrist() {
58
+ return this.shadowRoot.querySelector('data-grist')
59
+ }
60
+
61
+ get _toDateInput() {
62
+ return this._searchForm.shadowRoot.querySelector('input[name=toDate]')
63
+ }
64
+
65
+ render() {
66
+ return html`
67
+ <search-form id="search-form" .fields=${this._searchFields} @submit=${e => this._dataGrist.fetch()}></search-form>
68
+ <data-grist
69
+ .mode=${isMobileDevice() ? 'LIST' : 'GRID'}
70
+ .config=${this._config}
71
+ .fetchHandler="${this.fetchHandler.bind(this)}"
72
+ ></data-grist>
73
+ `
74
+ }
75
+
76
+ async pageInitialized() {
77
+ this._searchFields = [
78
+ {
79
+ label: i18next.t('field.store'),
80
+ name: 'marketplaceStoreId',
81
+ type: 'select',
82
+ options: [{ value: '' }],
83
+ props: { searchOper: 'eq' }
84
+ },
85
+ {
86
+ label: i18next.t('field.from_date'),
87
+ name: 'fromDate',
88
+ type: 'date',
89
+ props: {
90
+ searchOper: 'eq',
91
+ max: new Date().toISOString().split('T')[0]
92
+ },
93
+ value: (() => {
94
+ let date = new Date()
95
+ date.setMonth(date.getMonth() - 1)
96
+ return date.toISOString().split('T')[0]
97
+ })(),
98
+ handlers: { change: this._modifyDateRange.bind(this) }
99
+ },
100
+ {
101
+ label: i18next.t('field.to_date'),
102
+ name: 'toDate',
103
+ type: 'date',
104
+ props: {
105
+ searchOper: 'eq',
106
+ min: (() => {
107
+ let date = new Date()
108
+ date.setMonth(date.getMonth() - 1)
109
+ return date.toISOString().split('T')[0]
110
+ })(),
111
+ max: new Date().toISOString().split('T')[0]
112
+ },
113
+ value: new Date().toISOString().split('T')[0]
114
+ }
115
+ ]
116
+
117
+ this._config = {
118
+ rows: { appendable: false },
119
+ pagination: { limit: 50, pages: [50, 100, 200, 500, 1000] },
120
+ columns: [
121
+ { type: 'gutter', gutterName: 'sequence' },
122
+ {
123
+ type: 'string',
124
+ name: 'marketplaceStore',
125
+ header: i18next.t('field.store_name'),
126
+ sortable: true,
127
+ imex: { header: i18next.t('field.store_name'), key: 'marketplaceStore', width: 50, type: 'string' },
128
+ width: 200
129
+ },
130
+ {
131
+ type: 'string',
132
+ name: 'orderNo',
133
+ header: i18next.t('field.order_no'),
134
+ sortable: true,
135
+ imex: { header: i18next.t('field.order_no'), key: 'orderNo', width: 50, type: 'string' },
136
+ width: 200
137
+ },
138
+ {
139
+ type: 'string',
140
+ name: 'marketplaceOrderItem',
141
+ header: i18next.t('field.item'),
142
+ sortable: false,
143
+ imex: { header: i18next.t('field.item'), key: 'marketplaceOrderItem', width: 120, type: 'string' },
144
+ width: 400
145
+ },
146
+ {
147
+ type: 'integer',
148
+ name: 'qty',
149
+ header: i18next.t('field.qty'),
150
+ sortable: false,
151
+ imex: { header: i18next.t('field.qty'), key: 'qty', width: 20, type: 'integer' },
152
+ width: 150
153
+ },
154
+ {
155
+ type: 'datetime',
156
+ name: 'orderCreatedAt',
157
+ header: i18next.t('field.order_created_date'),
158
+ sortable: false,
159
+ imex: { header: i18next.t('field.order_created_date'), key: 'orderCreatedAt', width: 30, type: 'string' },
160
+ width: 200
161
+ },
162
+ {
163
+ type: 'string',
164
+ name: 'buyerUsername',
165
+ header: i18next.t('field.buyer_username'),
166
+ sortable: false,
167
+ imex: { header: i18next.t('field.buyer_username'), key: 'buyerUsername', width: 30, type: 'string' },
168
+ width: 200
169
+ },
170
+ {
171
+ type: 'datetime',
172
+ name: 'payTime',
173
+ header: i18next.t('field.pay_time'),
174
+ sortable: false,
175
+ imex: { header: i18next.t('field.pay_time'), key: 'payTime', width: 20, type: 'string' },
176
+ width: 150
177
+ },
178
+ {
179
+ type: 'float',
180
+ name: 'originalPrice',
181
+ header: i18next.t('field.original_price'),
182
+ sortable: false,
183
+ imex: {
184
+ header: i18next.t('field.original_price'),
185
+ key: 'originalPrice',
186
+ width: 30,
187
+ type: 'float'
188
+ },
189
+ width: 200
190
+ },
191
+ {
192
+ type: 'string',
193
+ name: 'promotionId',
194
+ header: i18next.t('field.promotion_id'),
195
+ sortable: false,
196
+ imex: { header: i18next.t('field.promotion_id'), key: 'promotionId', width: 30, type: 'string' },
197
+ width: 200
198
+ },
199
+ {
200
+ type: 'float',
201
+ name: 'refundAmount',
202
+ header: i18next.t('field.refund_amount'),
203
+ sortable: false,
204
+ imex: { header: i18next.t('field.refund_amount'), key: 'refundAmount', width: 30, type: 'float' },
205
+ width: 200
206
+ },
207
+ {
208
+ type: 'float',
209
+ name: 'productDiscount',
210
+ header: i18next.t('field.product_discount'),
211
+ sortable: false,
212
+ imex: { header: i18next.t('field.product_discount'), key: 'productDiscount', width: 30, type: 'float' },
213
+ width: 200
214
+ },
215
+ {
216
+ type: 'float',
217
+ name: 'shippingFee',
218
+ header: i18next.t('field.shipping_fee'),
219
+ sortable: false,
220
+ imex: { header: i18next.t('field.shipping_fee'), key: 'shippingFee', width: 30, type: 'float' },
221
+ width: 200
222
+ },
223
+ {
224
+ type: 'float',
225
+ name: 'actualShippingFee',
226
+ header: i18next.t('field.actual_shipping_fee'),
227
+ sortable: false,
228
+ imex: {
229
+ header: i18next.t('field.actual_shipping_fee'),
230
+ key: 'actualShippingFee',
231
+ width: 30,
232
+ type: 'float'
233
+ },
234
+ width: 200
235
+ },
236
+ {
237
+ type: 'string',
238
+ name: 'shippingProvider',
239
+ header: i18next.t('field.shipping_provider'),
240
+ sortable: false,
241
+ imex: { header: i18next.t('field.shipping_provider'), key: 'shippingProvider', width: 30, type: 'string' },
242
+ width: 200
243
+ }
244
+ ]
245
+ }
246
+ }
247
+
248
+ async fetchHandler({ page, limit, sorters = [{ name: 'marketplaceStore' }, { name: 'orderNo' }] }) {
249
+ let filters = [...this._searchForm.queryFilters, { name: 'platform', operator: 'eq', value: 'shopee' }]
250
+
251
+ const pagination = { page, limit }
252
+ const sortings = sorters
253
+
254
+ const response = await client.query({
255
+ query: gql`
256
+ query marketplaceSalesReports($filters: [Filter], $pagination: Pagination, $sortings: [Sorting]) {
257
+ marketplaceSalesReports(filters: $filters, pagination: $pagination, sortings: $sortings) {
258
+ items {
259
+ orderNo
260
+ orderCreatedAt
261
+ buyerUsername
262
+ payTime
263
+ totalAmount
264
+ refundAmount
265
+ shippingProvider
266
+ storeName
267
+ storeDescription
268
+ promotionId
269
+ originalPrice
270
+ paidPrice
271
+ sku
272
+ qty
273
+ variationSku
274
+ productName
275
+ productSku
276
+ productDiscount
277
+ paymentFee
278
+ shippingFee
279
+ actualShippingFee
280
+ marketplaceShippingFeeVoucher
281
+ sellerShippingFeeVoucher
282
+ }
283
+ total
284
+ }
285
+ }
286
+ `,
287
+ variables: { filters, pagination, sortings }
288
+ })
289
+
290
+ if (!response.errors) {
291
+ return {
292
+ total: response.data.marketplaceSalesReports.total,
293
+ records: response.data.marketplaceSalesReports.items.map(item => {
294
+ return {
295
+ ...item,
296
+ marketplaceOrderItem: `${item.variationSku} ${item.sku ? `(${item.sku})` : ''}`,
297
+ marketplaceStore: `${item.storeName} ${item.storeDescription ? `(${item.storeDescription})` : ''}`,
298
+ refundAmount: this._getRoundedValue(item.refundAmount),
299
+ originalPrice: this._getRoundedValue(item.originalPrice),
300
+ productDiscount: this._getRoundedValue(item.productDiscount),
301
+ shippingFee: this._getRoundedValue(item.shippingFee),
302
+ actualShippingFee: this._getRoundedValue(item.actualShippingFee)
303
+ }
304
+ })
305
+ }
306
+ }
307
+ }
308
+
309
+ stateChanged(state) {
310
+ if (state.mms && state.mms.stores && state.mms.stores.length) {
311
+ const _shopeeStores = state.mms.stores.filter(store => store.platform.toLowerCase() == 'shopee')
312
+ this._updateSearchFields(_shopeeStores)
313
+ this._dataGrist?.fetch()
314
+ }
315
+ }
316
+
317
+ _updateSearchFields(stores) {
318
+ if (!this._searchFields?.length) return
319
+
320
+ this._searchFields = this._searchFields.map(searchField => {
321
+ if (searchField.name === 'marketplaceStoreId') {
322
+ searchField.options = [
323
+ { value: '' },
324
+ ...stores.map(store => {
325
+ return {
326
+ name: `${store.name} ${store.description ? `(${store.description})` : ''}`,
327
+ value: store.id
328
+ }
329
+ })
330
+ ]
331
+ }
332
+
333
+ return searchField
334
+ })
335
+ }
336
+
337
+ _exportableData() {
338
+ const headerSetting = this._config.columns
339
+ .filter(column => column.type !== 'gutter' && column.imex !== undefined)
340
+ .map(column => {
341
+ return column.imex
342
+ })
343
+
344
+ const data = this._dataGrist.data.records.map(item => {
345
+ return {
346
+ ...this._config.columns
347
+ .filter(column => column.type !== 'gutter' && column.imex !== undefined)
348
+ .reduce((record, column) => {
349
+ record[column.imex.key] = column.imex.key
350
+ .split('.')
351
+ .reduce((obj, key) => (obj && obj[key] !== 'undefined' ? obj[key] : undefined), item)
352
+
353
+ if (column.type === 'datetime' && record[column.imex.key]) {
354
+ record[column.imex.key] = new Date(Number(record[column.imex.key])).toLocaleString()
355
+ }
356
+ return record
357
+ }, {})
358
+ }
359
+ })
360
+
361
+ return { header: headerSetting, data: data }
362
+ }
363
+
364
+ _modifyDateRange(e) {
365
+ const fromDate = e.currentTarget.value
366
+
367
+ if (this._toDateInput.value < fromDate) this._toDateInput.value = fromDate
368
+
369
+ let min = new Date(fromDate)
370
+ let today = new Date()
371
+ today.setHours(0, 0, 0, 0)
372
+
373
+ min = min.toISOString().split('T')[0]
374
+
375
+ this._toDateInput.min = min
376
+ }
377
+
378
+ _getRoundedValue(value = 0) {
379
+ return Math.round((value + Number.EPSILON) * 100) / 100
380
+ }
381
+ }
382
+
383
+ customElements.define('shopee-sales-report', ShopeeSalesReport)
package/client/route.js CHANGED
@@ -93,5 +93,18 @@ export default function route(page) {
93
93
  case 'mms-report-custom':
94
94
  import('./pages/reports/custom')
95
95
  return page
96
+
97
+ // title to be revised
98
+ case 'mms-report-sales-by-platform-home':
99
+ import('./pages/reports/sales-by-platform/home')
100
+ return page
101
+
102
+ case 'lazada-sales-report':
103
+ import('./pages/reports/sales-by-platform/lazada-sales-report')
104
+ return page
105
+
106
+ case 'shopee-sales-report':
107
+ import('./pages/reports/sales-by-platform/shopee-sales-report')
108
+ return page
96
109
  }
97
110
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@things-factory/operato-mms",
3
- "version": "3.7.6",
3
+ "version": "3.7.10",
4
4
  "main": "dist-server/index.js",
5
5
  "browser": "client/index.js",
6
6
  "things-factory": true,
@@ -44,7 +44,7 @@
44
44
  "@operato/ghost-print": "0.1.14",
45
45
  "@things-factory/apptool-ui": "^3.7.5",
46
46
  "@things-factory/attachment-base": "^3.7.5",
47
- "@things-factory/auth-ui": "^3.7.5",
47
+ "@things-factory/auth-ui": "^3.7.7",
48
48
  "@things-factory/biz-base": "^3.7.5",
49
49
  "@things-factory/board-service": "^3.7.5",
50
50
  "@things-factory/board-ui": "^3.7.5",
@@ -58,16 +58,16 @@
58
58
  "@things-factory/grist-ui": "^3.7.5",
59
59
  "@things-factory/help": "^3.7.5",
60
60
  "@things-factory/i18n-ui": "^3.7.5",
61
- "@things-factory/integration-fulfillment": "^3.7.5",
62
- "@things-factory/integration-lmd": "^3.7.5",
61
+ "@things-factory/integration-fulfillment": "^3.7.7",
62
+ "@things-factory/integration-lmd": "^3.7.7",
63
63
  "@things-factory/lite-menu": "^3.7.5",
64
- "@things-factory/marketplace-base": "^3.7.6",
64
+ "@things-factory/marketplace-base": "^3.7.10",
65
65
  "@things-factory/more-ui": "^3.7.5",
66
66
  "@things-factory/notification": "^3.7.5",
67
67
  "@things-factory/oauth2-client": "^3.7.5",
68
68
  "@things-factory/pdf": "^3.7.5",
69
- "@things-factory/product-base": "^3.7.5",
70
- "@things-factory/resource-ui": "^3.7.5",
69
+ "@things-factory/product-base": "^3.7.8",
70
+ "@things-factory/resource-ui": "^3.7.7",
71
71
  "@things-factory/scene-chartjs": "^3.7.5",
72
72
  "@things-factory/scene-clock": "^3.7.5",
73
73
  "@things-factory/scene-clone": "^3.7.5",
@@ -83,7 +83,7 @@
83
83
  "@things-factory/scene-half-roundrect": "^3.7.5",
84
84
  "@things-factory/scene-indoor-map": "^3.7.5",
85
85
  "@things-factory/scene-integration": "^3.7.5",
86
- "@things-factory/scene-label": "^3.7.6",
86
+ "@things-factory/scene-label": "^3.7.7",
87
87
  "@things-factory/scene-legend": "^3.7.5",
88
88
  "@things-factory/scene-marker": "^3.7.5",
89
89
  "@things-factory/scene-mqtt": "^3.7.5",
@@ -99,11 +99,11 @@
99
99
  "@things-factory/scene-wheel-sorter": "^3.7.5",
100
100
  "@things-factory/setting-ui": "^3.7.5",
101
101
  "@things-factory/system-ui": "^3.7.5",
102
- "@things-factory/warehouse-base": "^3.7.6"
102
+ "@things-factory/warehouse-base": "^3.7.10"
103
103
  },
104
104
  "devDependencies": {
105
105
  "@things-factory/builder": "^3.7.5",
106
106
  "@types/node-fetch": "^2.5.7"
107
107
  },
108
- "gitHead": "d9d72c07fc3b01af2ede46808ec0aced3241ed51"
108
+ "gitHead": "dc4aa344ee524651b4e633c3647c85c8daad8eb6"
109
109
  }
@@ -1,5 +1,5 @@
1
- import route from './client/route'
2
1
  import bootstrap from './client/bootstrap'
2
+ import route from './client/route'
3
3
 
4
4
  export default {
5
5
  route,
@@ -95,6 +95,18 @@ export default {
95
95
  {
96
96
  tagname: 'mms-report-custom',
97
97
  page: 'mms-report-custom'
98
+ },
99
+ {
100
+ tagname: 'mms-report-sales-by-platform-home',
101
+ page: 'mms-report-sales-by-platform-home'
102
+ },
103
+ {
104
+ tagname: 'lazada-sales-report',
105
+ page: 'lazada-sales-report'
106
+ },
107
+ {
108
+ tagname: 'shopee-sales-report',
109
+ page: 'shopee-sales-report'
98
110
  }
99
111
  ],
100
112
  bootstrap