@things-factory/operato-mms 4.0.8 → 4.0.12

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 (46) hide show
  1. package/client/menu.js +40 -2
  2. package/client/pages/catalogue-variation/product-variations.js +1 -1
  3. package/client/pages/order/logistics/lazada-order-init-batch-popup.js +1 -2
  4. package/client/pages/order/logistics/request-ro-popup.js +69 -4
  5. package/client/pages/order/logistics/shopee-order-init-batch-popup.js +1 -2
  6. package/client/pages/order/order-by-store.js +71 -3
  7. package/client/pages/reports/sales-by-platform/home.js +144 -0
  8. package/client/pages/reports/sales-by-platform/index.js +3 -0
  9. package/client/pages/reports/sales-by-platform/lazada-sales-report.js +504 -0
  10. package/client/pages/reports/sales-by-platform/shopee-sales-report.js +496 -0
  11. package/client/pages/setting/marketplace-setting.js +9 -6
  12. package/client/route.js +13 -0
  13. package/config.development.js +15 -49
  14. package/dist-server/graphql/resolvers/index.js +2 -1
  15. package/dist-server/graphql/resolvers/index.js.map +1 -1
  16. package/dist-server/graphql/resolvers/interface-with-hub/auto-add-release-order.js +3 -1
  17. package/dist-server/graphql/resolvers/interface-with-hub/auto-add-release-order.js.map +1 -1
  18. package/dist-server/graphql/resolvers/shipping-provider/index.js +6 -0
  19. package/dist-server/graphql/resolvers/shipping-provider/index.js.map +1 -0
  20. package/dist-server/graphql/resolvers/shipping-provider/shipping-providers.js +32 -0
  21. package/dist-server/graphql/resolvers/shipping-provider/shipping-providers.js.map +1 -0
  22. package/dist-server/graphql/types/index.js +3 -2
  23. package/dist-server/graphql/types/index.js.map +1 -1
  24. package/dist-server/graphql/types/shipping-provider/index.js +10 -0
  25. package/dist-server/graphql/types/shipping-provider/index.js.map +1 -0
  26. package/dist-server/graphql/types/shipping-provider/shipping-provider-list.js +13 -0
  27. package/dist-server/graphql/types/shipping-provider/shipping-provider-list.js.map +1 -0
  28. package/dist-server/graphql/types/shipping-provider/shipping-provider.js +13 -0
  29. package/dist-server/graphql/types/shipping-provider/shipping-provider.js.map +1 -0
  30. package/dist-server/routers/etrax-router.js +2 -2
  31. package/dist-server/routers/etrax-router.js.map +1 -1
  32. package/package.json +62 -62
  33. package/server/graphql/resolvers/index.ts +2 -1
  34. package/server/graphql/resolvers/interface-with-hub/auto-add-release-order.ts +3 -1
  35. package/server/graphql/resolvers/shipping-provider/index.ts +5 -0
  36. package/server/graphql/resolvers/shipping-provider/shipping-providers.ts +37 -0
  37. package/server/graphql/types/index.ts +3 -2
  38. package/server/graphql/types/shipping-provider/index.ts +8 -0
  39. package/server/graphql/types/shipping-provider/shipping-provider-list.ts +7 -0
  40. package/server/graphql/types/shipping-provider/shipping-provider.ts +7 -0
  41. package/server/routers/etrax-router.ts +2 -2
  42. package/things-factory.config.js +13 -1
  43. package/translations/en.json +63 -15
  44. package/translations/ko.json +57 -9
  45. package/translations/ms.json +57 -9
  46. package/translations/zh.json +57 -9
@@ -0,0 +1,504 @@
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 } 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 LazadaSalesReport extends connect(store)(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.lazada_sales_report'),
46
+ exportable: {
47
+ name: i18next.t('title.lazada_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: 'datetime',
140
+ name: 'orderCreatedAt',
141
+ header: i18next.t('field.order_created_date'),
142
+ sortable: false,
143
+ imex: { header: i18next.t('field.order_created_date'), key: 'orderCreatedAt', width: 30, type: 'string' },
144
+ width: 200
145
+ },,
146
+ {
147
+ type: 'string',
148
+ name: 'fulfillmentCenter',
149
+ header: i18next.t('field.fulfillment_partner'),
150
+ sortable: false,
151
+ imex: { header: i18next.t('field.fulfillment_partner'), key: 'fulfillmentCenter', width: 50, type: 'string' },
152
+ width: 200
153
+ },
154
+ {
155
+ type: 'string',
156
+ name: 'status',
157
+ header: i18next.t('field.status'),
158
+ sortable: false,
159
+ imex: { header: i18next.t('field.status'), key: 'status', width: 50, type: 'string' },
160
+ width: 200
161
+ },
162
+ {
163
+ type: 'string',
164
+ name: 'sku',
165
+ header: i18next.t('field.warehouse_sku'),
166
+ sortable: false,
167
+ imex: { header: i18next.t('field.warehouse_sku'), key: 'sku', width: 50, type: 'string' },
168
+ width: 200
169
+ },
170
+ {
171
+ type: 'string',
172
+ name: 'variationId',
173
+ header: i18next.t('field.variation_id'),
174
+ sortable: false,
175
+ imex: { header: i18next.t('field.variation_id'), key: 'variationId', width: 50, type: 'string' },
176
+ width: 200
177
+ },
178
+ {
179
+ type: 'string',
180
+ name: 'marketplaceOrderItem',
181
+ header: i18next.t('field.item'),
182
+ sortable: false,
183
+ imex: { header: i18next.t('field.item'), key: 'marketplaceOrderItem', width: 120, type: 'string' },
184
+ width: 400
185
+ },
186
+ {
187
+ type: 'integer',
188
+ name: 'qty',
189
+ header: i18next.t('field.qty'),
190
+ sortable: false,
191
+ imex: { header: i18next.t('field.qty'), key: 'qty', width: 20, type: 'integer' },
192
+ width: 150
193
+ },
194
+ {
195
+ type: 'float',
196
+ name: 'itemCommissionFee',
197
+ header: i18next.t('field.commission_fee'),
198
+ sortable: false,
199
+ imex: { header: i18next.t('field.commission_fee'), key: 'itemCommissionFee', width: 30, type: 'float' },
200
+ width: 200
201
+ },
202
+ {
203
+ type: 'float',
204
+ name: 'marketplaceBonusSeller',
205
+ header: i18next.t('field.lazada_bonus'),
206
+ sortable: false,
207
+ imex: { header: i18next.t('field.lazada_bonus'), key: 'marketplaceBonusSeller', width: 30, type: 'float' },
208
+ width: 200
209
+ },
210
+ {
211
+ type: 'float',
212
+ name: 'marketplaceBonus',
213
+ header: i18next.t('field.lazada_bonus_lzd_cofund'),
214
+ sortable: false,
215
+ imex: { header: i18next.t('field.lazada_bonus_lzd_cofund'), key: 'marketplaceBonus', width: 30, type: 'float' },
216
+ width: 200
217
+ },
218
+ {
219
+ type: 'float',
220
+ name: 'paymentFee',
221
+ header: i18next.t('field.payment_fee'),
222
+ sortable: false,
223
+ imex: { header: i18next.t('field.payment_fee'), key: 'paymentFee', width: 30, type: 'float' },
224
+ width: 200
225
+ },
226
+ {
227
+ type: 'float',
228
+ name: 'ordersMarketplaceFeesTotal',
229
+ header: i18next.t('field.orders_lazada_fees_total'),
230
+ sortable: false,
231
+ imex: { header: i18next.t('field.orders_lazada_fees_total'), key: 'ordersMarketplaceFeesTotal', width: 30, type: 'float' },
232
+ width: 200
233
+ },
234
+ {
235
+ type: 'float',
236
+ name: 'originalShippingFee',
237
+ header: i18next.t('field.shipping_fee'),
238
+ sortable: false,
239
+ imex: { header: i18next.t('field.shipping_fee'), key: 'originalShippingFee', width: 30, type: 'float' },
240
+ width: 200
241
+ },
242
+ {
243
+ type: 'float',
244
+ name: 'shippingFeePaidByCustomer',
245
+ header: i18next.t('field.shipping_fee_paid_by_customer'),
246
+ sortable: false,
247
+ imex: { header: i18next.t('field.shipping_fee_paid_by_customer'), key: 'shippingFeePaidByCustomer', width: 30, type: 'float' },
248
+ width: 200
249
+ },
250
+ {
251
+ type: 'float',
252
+ name: 'shippingFeeDiscountMarketplace',
253
+ header: i18next.t('field.shipping_fee_voucher_by_lazada'),
254
+ sortable: false,
255
+ imex: { header: i18next.t('field.shipping_fee_voucher_by_lazada'), key: 'shippingFeeDiscountMarketplace', width: 30, type: 'float' },
256
+ width: 200
257
+ },
258
+ {
259
+ type: 'float',
260
+ name: 'shippingFeeDiscountSeller',
261
+ header: i18next.t('field.shipping_fee_voucher_by_seller'),
262
+ sortable: false,
263
+ imex: { header: i18next.t('field.shipping_fee_voucher_by_seller'), key: 'shippingFeeDiscountSeller', width: 30, type: 'float' },
264
+ width: 200
265
+ },
266
+ {
267
+ type: 'float',
268
+ name: 'autoShippingSubsidyMarketplace',
269
+ header: i18next.t('field.auto_shipping_fee_subsidy_by_lazada'),
270
+ sortable: false,
271
+ imex: { header: i18next.t('field.auto_shipping_fee_subsidy_by_lazada'), key: 'autoShippingSubsidyMarketplace', width: 30, type: 'float' },
272
+ width: 200
273
+ },
274
+ {
275
+ type: 'float',
276
+ name: 'ordersLogisticsTotal',
277
+ header: i18next.t('field.orders_logistics_total'),
278
+ sortable: false,
279
+ imex: { header: i18next.t('field.orders_logistics_total'), key: 'ordersLogisticsTotal', width: 30, type: 'float' },
280
+ width: 200
281
+ },
282
+ {
283
+ type: 'float',
284
+ name: 'promotionalChargesFlexiCombo',
285
+ header: i18next.t('field.promotional_charges_flexi_combo'),
286
+ sortable: false,
287
+ imex: { header: i18next.t('field.promotional_charges_flexi_combo'), key: 'promotionalChargesFlexiCombo', width: 30, type: 'float' },
288
+ width: 200
289
+ },
290
+ {
291
+ type: 'float',
292
+ name: 'promotionalCharges',
293
+ header: i18next.t('field.promotional_charges_vouchers'),
294
+ sortable: false,
295
+ imex: { header: i18next.t('field.promotional_charges_vouchers'), key: 'promotionalCharges', width: 30, type: 'float' },
296
+ width: 200
297
+ },
298
+ {
299
+ type: 'float',
300
+ name: 'ordersMarketingFeesTotal',
301
+ header: i18next.t('field.orders_marketing_fees_total'),
302
+ sortable: false,
303
+ imex: { header: i18next.t('field.orders_marketing_fees_total'), key: 'ordersMarketingFeesTotal', width: 30, type: 'float' },
304
+ width: 200
305
+ },
306
+ {
307
+ type: 'float',
308
+ name: 'itemPriceCredit',
309
+ header: i18next.t('field.item_price_credit'),
310
+ sortable: false,
311
+ imex: { header: i18next.t('field.item_price_credit'), key: 'itemPriceCredit', width: 30, type: 'float' },
312
+ width: 200
313
+ },
314
+ {
315
+ type: 'float',
316
+ name: 'ordersSalesTotal',
317
+ header: i18next.t('field.orders_sales_total'),
318
+ sortable: false,
319
+ imex: { header: i18next.t('field.orders_sales_total'), key: 'ordersSalesTotal', width: 30, type: 'float' },
320
+ width: 200
321
+ },
322
+ {
323
+ type: 'float',
324
+ name: 'taxAmount',
325
+ header: i18next.t('field.tax_amount'),
326
+ sortable: false,
327
+ imex: { header: i18next.t('field.tax_amount'), key: 'taxAmount', width: 30, type: 'float' },
328
+ width: 200
329
+ },
330
+ {
331
+ type: 'float',
332
+ name: 'grandTotal',
333
+ header: i18next.t('field.grand_total'),
334
+ sortable: false,
335
+ imex: { header: i18next.t('field.grand_total'), key: 'grandTotal', width: 30, type: 'float' },
336
+ width: 200
337
+ }
338
+ ]
339
+ }
340
+ }
341
+
342
+ async fetchHandler({ page, limit, sorters = [{ name: 'marketplaceStore' }, { name: 'orderNo' }] }) {
343
+ let filters = [...this._searchForm.queryFilters, { name: 'platform', operator: 'eq', value: 'lazada' }]
344
+
345
+ const pagination = { page, limit }
346
+ const sortings = sorters
347
+
348
+ const response = await client.query({
349
+ query: gql`
350
+ query marketplaceSalesReports($filters: [Filter], $pagination: Pagination, $sortings: [Sorting]) {
351
+ marketplaceSalesReports(filters: $filters, pagination: $pagination, sortings: $sortings) {
352
+ items {
353
+ orderNo
354
+ orderCreatedAt
355
+ buyerUsername
356
+ payTime
357
+ refundAmount
358
+ shippingProvider
359
+ storeName
360
+ storeDescription
361
+ promotionId
362
+ sku
363
+ variationSku
364
+ productName
365
+ productSku
366
+ productDiscount
367
+ paymentFee
368
+ itemCommissionFee
369
+ shippingFeePaidByCustomer
370
+ promotionalCharges
371
+ ordersMarketplaceFeesTotal
372
+ ordersMarketingFeesTotal
373
+ ordersSalesTotal
374
+ ordersLogisticsTotal
375
+ itemPriceCredit
376
+ marketplaceBonus
377
+ marketplaceBonusSeller
378
+ shippingFeeDiscountMarketplace
379
+ shippingFeeDiscountSeller
380
+ promotionalChargesFlexiCombo
381
+ autoShippingSubsidyMarketplace
382
+ grandTotal
383
+ originalShippingFee
384
+ taxAmount
385
+ status
386
+ qty
387
+ fulfillmentCenter
388
+ variationId
389
+ variationName
390
+ }
391
+ total
392
+ }
393
+ }
394
+ `,
395
+ variables: { filters, pagination, sortings }
396
+ })
397
+
398
+ if (!response.errors) {
399
+ return {
400
+ total: response.data.marketplaceSalesReports.total,
401
+ records: response.data.marketplaceSalesReports.items.map(item => {
402
+ return {
403
+ ...item,
404
+ marketplaceOrderItem: `${item.variationSku} ${item.variationName ? `(${item.variationName})` : ''}`,
405
+ marketplaceStore: `${item.storeName} ${item.storeDescription ? `(${item.storeDescription})` : ''}`,
406
+ paymentFee: this._getRoundedValue(item.paymentFee),
407
+ itemCommissionFee: this._getRoundedValue(item.itemCommissionFee),
408
+ shippingFeePaidByCustomer: this._getRoundedValue(item.shippingFeePaidByCustomer),
409
+ promotionalCharges: this._getRoundedValue(item.promotionalCharges),
410
+ ordersMarketplaceFeesTotal: this._getRoundedValue(item.ordersMarketplaceFeesTotal),
411
+ ordersMarketingFeesTotal: this._getRoundedValue(item.ordersMarketingFeesTotal),
412
+ ordersSalesTotal: this._getRoundedValue(item.ordersSalesTotal),
413
+ ordersLogisticsTotal: this._getRoundedValue(item.ordersLogisticsTotal),
414
+ itemPriceCredit: this._getRoundedValue(item.itemPriceCredit),
415
+ marketplaceBonus: this._getRoundedValue(item.marketplaceBonus),
416
+ marketplaceBonusSeller: this._getRoundedValue(item.marketplaceBonusSeller),
417
+ shippingFeeDiscountMarketplace: this._getRoundedValue(item.shippingFeeDiscountMarketplace),
418
+ shippingFeeDiscountSeller: this._getRoundedValue(item.shippingFeeDiscountSeller),
419
+ promotionalChargesFlexiCombo: this._getRoundedValue(item.promotionalChargesFlexiCombo),
420
+ autoShippingSubsidyMarketplace: this._getRoundedValue(item.autoShippingSubsidyMarketplace),
421
+ grandTotal: this._getRoundedValue(item.grandTotal),
422
+ originalShippingFee: this._getRoundedValue(item.originalShippingFee),
423
+ taxAmount: this._getRoundedValue(item.taxAmount)
424
+ }
425
+ })
426
+ }
427
+ }
428
+ }
429
+
430
+ stateChanged(state) {
431
+ if (state.mms && state.mms.stores && state.mms.stores.length) {
432
+ const _lazadaStores = state.mms.stores.filter(store => store.platform.toLowerCase() == 'lazada')
433
+ this._updateSearchFields(_lazadaStores)
434
+ this._dataGrist?.fetch()
435
+ }
436
+ }
437
+
438
+ _updateSearchFields(stores) {
439
+ if (!this._searchFields?.length) return
440
+
441
+ this._searchFields = this._searchFields.map(searchField => {
442
+ if (searchField.name === 'marketplaceStoreId') {
443
+ searchField.options = [
444
+ { value: '' },
445
+ ...stores.map(store => {
446
+ return {
447
+ name: `${store.name} ${store.description ? `(${store.description})` : ''}`,
448
+ value: store.id
449
+ }
450
+ })
451
+ ]
452
+ }
453
+
454
+ return searchField
455
+ })
456
+ }
457
+
458
+ _exportableData() {
459
+ const headerSetting = this._config.columns
460
+ .filter(column => column.type !== 'gutter' && column.imex !== undefined)
461
+ .map(column => {
462
+ return column.imex
463
+ })
464
+
465
+ const data = this._dataGrist.data.records.map(item => {
466
+ return {
467
+ ...this._config.columns
468
+ .filter(column => column.type !== 'gutter' && column.imex !== undefined)
469
+ .reduce((record, column) => {
470
+ record[column.imex.key] = column.imex.key
471
+ .split('.')
472
+ .reduce((obj, key) => (obj && obj[key] !== 'undefined' ? obj[key] : undefined), item)
473
+
474
+ if (column.type === 'datetime' && record[column.imex.key]) {
475
+ record[column.imex.key] = new Date(Number(record[column.imex.key])).toLocaleString()
476
+ }
477
+ return record
478
+ }, {})
479
+ }
480
+ })
481
+
482
+ return { header: headerSetting, data: data }
483
+ }
484
+
485
+ _modifyDateRange(e) {
486
+ const fromDate = e.currentTarget.value
487
+
488
+ if (this._toDateInput.value < fromDate) this._toDateInput.value = fromDate
489
+
490
+ let min = new Date(fromDate)
491
+ let today = new Date()
492
+ today.setHours(0, 0, 0, 0)
493
+
494
+ min = min.toISOString().split('T')[0]
495
+
496
+ this._toDateInput.min = min
497
+ }
498
+
499
+ _getRoundedValue(value = 0) {
500
+ return Math.round((value + Number.EPSILON) * 100) / 100
501
+ }
502
+ }
503
+
504
+ customElements.define('lazada-sales-report', LazadaSalesReport)