diff --git a/CHANGELOG.md b/CHANGELOG.md index e116381481..820c625bce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Fixed product link in wishlist and microcart - @michasik (#2987) +- Fixed naming strategy for product prices - `special_priceInclTax` -> `special_price_incl_tax`, `priceInclTax` -> `price_incl_tax`, `priceTax` -> `price_tax`; old names have been kept as @deprecated - @pkarw (#2918) +- The `final_price` field is now being used for setting the `special_price` or `price` of the product (depending on the +value); `final_price` might been used along with `special_price` with Magento for the products with activated catalog pricing rules - @pkarw (#3099) - Resolve problem with getting CMS block from cache - @qiqqq (#2499) - Make image proxy url work with relative base url - @cewald (#3158) - Fixed memory leak with enabled dynamicConfigReload - @dimasch (#3075) diff --git a/config/default.json b/config/default.json index 8b5f9acfe5..f8a9884064 100644 --- a/config/default.json +++ b/config/default.json @@ -163,11 +163,11 @@ }, "productList": { "sort": "updated_at:desc", - "includeFields": [ "type_id", "sku", "product_links", "tax_class_id", "special_price", "special_to_date", "special_from_date", "name", "price", "priceInclTax", "originalPriceInclTax", "originalPrice", "specialPriceInclTax", "id", "image", "sale", "new", "url_path", "url_key", "status", "tier_prices", "configurable_children.sku", "configurable_children.price", "configurable_children.special_price", "configurable_children.priceInclTax", "configurable_children.specialPriceInclTax", "configurable_children.originalPrice", "configurable_children.originalPriceInclTax" ], + "includeFields": [ "type_id", "sku", "product_links", "tax_class_id", "special_price", "special_to_date", "special_from_date", "name", "price", "price_incl_tax", "original_price_incl_tax", "original_price", "special_price_incl_tax", "id", "image", "sale", "new", "url_path", "url_key", "status", "tier_prices", "configurable_children.sku", "configurable_children.price", "configurable_children.special_price", "configurable_children.price_incl_tax", "configurable_children.special_price_incl_tax", "configurable_children.original_price", "configurable_children.original_price_incl_tax" ], "excludeFields": [ "description", "configurable_options", "sgn", "*.sgn", "msrp_display_actual_price_type", "*.msrp_display_actual_price_type", "required_options" ] }, "productListWithChildren": { - "includeFields": [ "type_id", "sku", "name", "tax_class_id", "special_price", "special_to_date", "special_from_date", "price", "priceInclTax", "originalPriceInclTax", "originalPrice", "specialPriceInclTax", "id", "image", "sale", "new", "configurable_children.image", "configurable_children.sku", "configurable_children.price", "configurable_children.special_price", "configurable_children.priceInclTax", "configurable_children.specialPriceInclTax", "configurable_children.originalPrice", "configurable_children.originalPriceInclTax", "configurable_children.color", "configurable_children.size", "configurable_children.id", "configurable_children.tier_prices", "product_links", "url_path", "url_key", "status", "tier_prices"], + "includeFields": [ "type_id", "sku", "name", "tax_class_id", "special_price", "special_to_date", "special_from_date", "price", "price_incl_tax", "original_price_incl_tax", "original_price", "special_price_incl_tax", "id", "image", "sale", "new", "configurable_children.image", "configurable_children.sku", "configurable_children.price", "configurable_children.special_price", "configurable_children.price_incl_tax", "configurable_children.special_price_incl_tax", "configurable_children.original_price", "configurable_children.original_price_incl_tax", "configurable_children.color", "configurable_children.size", "configurable_children.id", "configurable_children.tier_prices", "product_links", "url_path", "url_key", "status", "tier_prices"], "excludeFields": [ "description", "sgn", "*.sgn", "msrp_display_actual_price_type", "*.msrp_display_actual_price_type", "required_options"] }, "review": { @@ -185,6 +185,8 @@ "size_options", "regular_price", "final_price", + "final_price_incl_tax", + "final_price_tax", "price", "color_options", "id", @@ -210,10 +212,10 @@ "max_regular_price", "category", "status", - "priceTax", - "priceInclTax", - "specialPriceTax", - "specialPriceInclTax", + "price_tax", + "price_incl_tax", + "special_price_tax", + "special_price_incl_tax", "_score", "slug", "errors", @@ -222,8 +224,8 @@ "special_from_date", "news_from_date", "custom_design_from", - "originalPrice", - "originalPriceInclTax", + "original_price", + "original_price_incl_tax", "parentSku", "options", "product_option", diff --git a/core/app.ts b/core/app.ts index f5b0e2181f..5c7ac2f9e3 100755 --- a/core/app.ts +++ b/core/app.ts @@ -4,6 +4,7 @@ import Vue from 'vue' import { isServer } from '@vue-storefront/core/helpers' // Plugins +import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus' import i18n from '@vue-storefront/i18n' import VueRouter from 'vue-router' import VueLazyload from 'vue-lazyload' @@ -115,7 +116,7 @@ const createApp = async (ssrContext, config, storeCode = null): Promise<{app: Vu registerExtensions(extensions, app, router, store, config, ssrContext) registerTheme(globalConfig.theme, app, router, store, globalConfig, ssrContext) - Vue.prototype.$bus.$emit('application-after-init', app) + EventBus.$emit('application-after-init', app) return { app, router, store } } diff --git a/core/compatibility/plugins/event-bus/index.js b/core/compatibility/plugins/event-bus/index.js index 959a24038b..a81ebee444 100644 --- a/core/compatibility/plugins/event-bus/index.js +++ b/core/compatibility/plugins/event-bus/index.js @@ -61,7 +61,7 @@ if (!EventBus.$dataFilters) { const EventBusPlugin = { install (Vue) { - if (!Vue.prototype.$bus) { + if (!Vue.prototype.$bus) { /** Vue.prototype.$bus is now @deprecated please do use `EventBus` instead */ Object.defineProperties(Vue.prototype, { $bus: { get: function () { diff --git a/core/helpers/index.ts b/core/helpers/index.ts index 7d22f26d75..d37a7babf8 100644 --- a/core/helpers/index.ts +++ b/core/helpers/index.ts @@ -5,6 +5,11 @@ import Vue from 'vue' import config from 'config' import { sha3_224 } from 'js-sha3' +export const processURLAddress = (url: string = '') => { + if (url.startsWith('/')) return `${config.api.url}${url}` + return url +} + /** * Create slugify -> "create-slugify" permalink of text * @param {String} text @@ -172,11 +177,6 @@ export const onlineHelper = Vue.observable({ !isServer && window.addEventListener('online', () => { onlineHelper.isOnline = true }) !isServer && window.addEventListener('offline', () => { onlineHelper.isOnline = false }) -export const processURLAddress = (url: string = '') => { - if (url.startsWith('/')) return `${config.api.url}${url}` - return url -} - /* * serial executes Promises sequentially. * @param {funcs} An array of funcs that return promises. diff --git a/core/helpers/initCacheStorage.ts b/core/helpers/initCacheStorage.ts index c0127bf89d..21fcd87fc4 100644 --- a/core/helpers/initCacheStorage.ts +++ b/core/helpers/initCacheStorage.ts @@ -1,12 +1,12 @@ import * as localForage from 'localforage' import UniversalStorage from '@vue-storefront/core/store/lib/storage' +import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' import { currentStoreView } from '@vue-storefront/core/lib/multistore' import config from 'config' -/** Inits cache storage for given module. By default via local storage */ -export function initCacheStorage (key, localised = true) { +function _prepareCachestorage (key, localised = true) { const storeView = currentStoreView() - const dbNamePrefix = storeView.storeCode ? storeView.storeCode + '-' : '' + const dbNamePrefix = storeView && storeView.storeCode ? storeView.storeCode + '-' : '' const cacheDriver = config.localForage && config.localForage.defaultDrivers[key] ? config.localForage.defaultDrivers[key] : 'LOCALSTORAGE' @@ -17,3 +17,16 @@ export function initCacheStorage (key, localised = true) { driver: localForage[cacheDriver] })) } + +/** Inits cache storage for given module. By default via local storage */ +export function initCacheStorage (key, localised = true, registerStorgeManager = true) { + if (registerStorgeManager) { + if (!StorageManager.exists(key)) { + return StorageManager.set(key, _prepareCachestorage(key, localised)) + } else { + return StorageManager.get(key) + } + } else { + return _prepareCachestorage(key, localised) + } +} diff --git a/core/lib/multistore.ts b/core/lib/multistore.ts index 78bc63a25f..7cdbdb0870 100644 --- a/core/lib/multistore.ts +++ b/core/lib/multistore.ts @@ -8,6 +8,7 @@ import merge from 'lodash-es/merge' import { RouterManager } from '@vue-storefront/core/lib/router-manager' import VueRouter, { RouteConfig, RawLocation } from 'vue-router' import config from 'config' +import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' export interface LocalizedRoute { path?: string, @@ -98,13 +99,9 @@ export function prepareStoreView (storeCode: string): StoreView { if (storeViewHasChanged) { rootStore.state.storeView = storeView } - - if (storeViewHasChanged || Vue.prototype.$db.currentStoreCode !== storeCode) { - if (typeof Vue.prototype.$db === 'undefined') { - Vue.prototype.$db = {} - } + if (storeViewHasChanged || StorageManager.currentStoreCode !== storeCode) { initializeSyncTaskStorage() - Vue.prototype.$db.currentStoreCode = storeView.storeCode + StorageManager.currentStoreCode = storeView.storeCode } return storeView diff --git a/core/lib/search.ts b/core/lib/search.ts index 76a0c44040..7e9d99167d 100644 --- a/core/lib/search.ts +++ b/core/lib/search.ts @@ -9,6 +9,7 @@ import { SearchResponse } from '@vue-storefront/core/types/search/SearchResponse import { Logger } from '@vue-storefront/core/lib/logger' import config from 'config' import { isServer } from '@vue-storefront/core/helpers' +import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' // TODO - use one from helpers instead export function isOnline (): boolean { @@ -52,7 +53,7 @@ export const quickSearchByQuery = async ({ query = {}, start = 0, size = 50, ent Request.groupId = rootStore.state.user.groupId } - const cache = Vue.prototype.$db.elasticCacheCollection // switch to appcache? + const cache = StorageManager.get('elasticCacheCollection') // switch to appcache? let servedFromCache = false const cacheKey = sha3_224(JSON.stringify(Request)) const benchmarkTime = new Date() diff --git a/core/lib/sync/index.ts b/core/lib/sync/index.ts index 5c272e48d3..9407422965 100644 --- a/core/lib/sync/index.ts +++ b/core/lib/sync/index.ts @@ -6,16 +6,18 @@ import { execute as taskExecute, _prepareTask } from './task' import { isServer } from '@vue-storefront/core/helpers' import config from 'config' import Task from '@vue-storefront/core/lib/sync/types/Task' +import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus' +import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' /** Syncs given task. If user is offline requiest will be sent to the server after restored connection */ async function queue (task) { - const tasksCollection = Vue.prototype.$db.syncTaskCollection + const tasksCollection = StorageManager.get('syncTaskCollection') task = _prepareTask(task) Logger.info('Sync task queued ' + task.url, 'sync', { task })() return new Promise((resolve, reject) => { tasksCollection.setItem(task.task_id.toString(), task, (err, resp) => { if (err) Logger.error(err, 'sync')() - Vue.prototype.$bus.$emit('sync/PROCESS_QUEUE', { config: config }) // process checkout queue + EventBus.$emit('sync/PROCESS_QUEUE', { config: config }) // process checkout queue resolve(task) }, config.syncTasks.disablePersistentTaskQueue).catch((reason) => { Logger.error(reason, 'sync')() // it doesn't work on SSR @@ -48,7 +50,7 @@ async function execute (task): Promise { // not offline task /** Clear sync tasks that were not transmitted yet */ function clearNotTransmited () { - const syncTaskCollection = Vue.prototype.$db.syncTaskCollection + const syncTaskCollection = StorageManager.get('syncTaskCollection') syncTaskCollection.iterate((task, id, iterationNumber) => { if (!task.transmited) { syncTaskCollection.removeItem(id) diff --git a/core/lib/sync/task.ts b/core/lib/sync/task.ts index a83924681f..f0bf29967f 100644 --- a/core/lib/sync/task.ts +++ b/core/lib/sync/task.ts @@ -7,17 +7,18 @@ import fetch from 'isomorphic-fetch' import * as localForage from 'localforage' import rootStore from '@vue-storefront/core/store' import { adjustMultistoreApiUrl, currentStoreView } from '@vue-storefront/core/lib/multistore' +import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus' import Task from '@vue-storefront/core/lib/sync/types/Task' import { Logger } from '@vue-storefront/core/lib/logger' import { TaskQueue } from '@vue-storefront/core/lib/sync' import * as entities from '@vue-storefront/core/store/lib/entities' import UniversalStorage from '@vue-storefront/core/store/lib/storage' +import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' import { processURLAddress } from '@vue-storefront/core/helpers' import { serial } from '@vue-storefront/core/helpers' import config from 'config' import { onlineHelper } from '@vue-storefront/core/helpers' - export function _prepareTask (task) { const taskId = entities.uniqueEntityId(task) // timestamp as a order id is not the best we can do but it's enough task.task_id = taskId.toString() @@ -88,7 +89,7 @@ function _internalExecute (resolve, reject, task: Task, currentToken, currentCar rootStore.state.userTokenInvalidateLock = -1 rootStore.dispatch('user/logout', { silent: true }) TaskQueue.clearNotTransmited() - Vue.prototype.$bus.$emit('modal-show', 'modal-signup') + EventBus.$emit('modal-show', 'modal-signup') rootStore.dispatch('notification/spawnNotification', { type: 'error', message: i18n.t('Internal Application error while refreshing the tokens. Please clear the storage and refresh page.'), @@ -106,14 +107,14 @@ function _internalExecute (resolve, reject, task: Task, currentToken, currentCar } else { rootStore.state.userTokenInvalidateLock = -1 rootStore.dispatch('user/logout', { silent: true }) - Vue.prototype.$bus.$emit('modal-show', 'modal-signup') + EventBus.$emit('modal-show', 'modal-signup') TaskQueue.clearNotTransmited() Logger.error('Error refreshing user token' + resp.result, 'sync')() } }).catch((excp) => { rootStore.state.userTokenInvalidateLock = -1 rootStore.dispatch('user/logout', { silent: true }) - Vue.prototype.$bus.$emit('modal-show', 'modal-signup') + EventBus.$emit('modal-show', 'modal-signup') TaskQueue.clearNotTransmited() Logger.error('Error refreshing user token' + excp, 'sync')() }) @@ -123,7 +124,7 @@ function _internalExecute (resolve, reject, task: Task, currentToken, currentCar } else { Logger.info('Invalidation process is disabled (autoRefreshTokens is set to false)', 'sync')() rootStore.dispatch('user/logout', { silent: true }) - Vue.prototype.$bus.$emit('modal-show', 'modal-signup') + EventBus.$emit('modal-show', 'modal-signup') } } @@ -150,7 +151,7 @@ function _internalExecute (resolve, reject, task: Task, currentToken, currentCar if (task.callback_event.startsWith('store:')) { rootStore.dispatch(task.callback_event.split(':')[1], task) } else { - Vue.prototype.$bus.$emit(task.callback_event, task) + EventBus.$emit(task.callback_event, task) } } if (!rootStore.state.userTokenInvalidateLock) { // in case we're revalidaing the token - user must wait for it @@ -179,19 +180,19 @@ export function initializeSyncTaskStorage () { const storeView = currentStoreView() const dbNamePrefix = storeView.storeCode ? storeView.storeCode + '-' : '' - Vue.prototype.$db.syncTaskCollection = new UniversalStorage(localForage.createInstance({ + StorageManager.set('syncTaskCollection', new UniversalStorage(localForage.createInstance({ name: dbNamePrefix + 'shop', storeName: 'syncTasks', driver: localForage[config.localForage.defaultDrivers['syncTasks']] - })) + }))) } export function registerSyncTaskProcessor () { const mutex = {} - Vue.prototype.$bus.$on('sync/PROCESS_QUEUE', async data => { + EventBus.$on('sync/PROCESS_QUEUE', async data => { if (onlineHelper.isOnline) { // event.data.config - configuration, endpoints etc - const syncTaskCollection = Vue.prototype.$db.syncTaskCollection + const syncTaskCollection = StorageManager.get('syncTaskCollection') const currentUserToken = rootStore.getters['user/getUserToken'] const currentCartToken = rootStore.getters['cart/getCartToken'] diff --git a/core/lib/test/unit/multistore.spec.ts b/core/lib/test/unit/multistore.spec.ts index 56cf9155cc..759c30872d 100644 --- a/core/lib/test/unit/multistore.spec.ts +++ b/core/lib/test/unit/multistore.spec.ts @@ -1,5 +1,6 @@ import { storeCodeFromRoute } from '../../multistore' import config from 'config' +jest.mock('@vue-storefront/core/app', () => ({ createApp: jest.fn() })) jest.mock('../../../store', () => ({})) jest.mock('@vue-storefront/i18n', () => ({loadLanguageAsync: jest.fn()})) jest.mock('../../sync/task', () => ({initializeSyncTaskStorage: jest.fn()})) diff --git a/core/modules/cart/components/AddToCart.ts b/core/modules/cart/components/AddToCart.ts index 228abefbf6..26817176ed 100644 --- a/core/modules/cart/components/AddToCart.ts +++ b/core/modules/cart/components/AddToCart.ts @@ -1,4 +1,5 @@ import Product from '@vue-storefront/core/modules/catalog/types/Product' +import { Logger } from '@vue-storefront/core/lib/logger'; export const AddToCart = { name: 'AddToCart', @@ -20,13 +21,18 @@ export const AddToCart = { methods: { async addToCart (product: Product) { this.isAddingToCart = true - const diffLog = await this.$store.dispatch('cart/addItem', { productToAdd: product }) - if (diffLog.clientNotifications && diffLog.clientNotifications.length > 0) { - diffLog.clientNotifications.forEach(notificationData => { - this.$store.dispatch('notification/spawnNotification', notificationData, { root: true }) - }) + try { + const diffLog = await this.$store.dispatch('cart/addItem', { productToAdd: product }) + if (diffLog.clientNotifications && diffLog.clientNotifications.length > 0) { + diffLog.clientNotifications.forEach(notificationData => { + this.$store.dispatch('notification/spawnNotification', notificationData, { root: true }) + }) + } + } catch (e) { + Logger.error(e, 'cart')() + } finally { + this.isAddingToCart = false } - this.isAddingToCart = false } } } diff --git a/core/modules/cart/helpers/cartCacheHandler.ts b/core/modules/cart/helpers/cartCacheHandler.ts index 75fc5b49ad..53593c0ae0 100644 --- a/core/modules/cart/helpers/cartCacheHandler.ts +++ b/core/modules/cart/helpers/cartCacheHandler.ts @@ -1,5 +1,7 @@ import * as types from '../store/mutation-types'; +import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' + export function cartCacheHandlerFactory (Vue) { return (mutation, state) => { const type = mutation.type; @@ -11,19 +13,19 @@ export function cartCacheHandlerFactory (Vue) { type.endsWith(types.CART_UPD_ITEM) || type.endsWith(types.CART_UPD_ITEM_PROPS) ) { - return Vue.prototype.$db.cartsCollection.setItem('current-cart', state.cart.cartItems).catch((reason) => { + return StorageManager.get('cartsCollection').setItem('current-cart', state.cart.cartItems).catch((reason) => { console.error(reason) // it doesn't work on SSR }) // populate cache } else if ( type.endsWith(types.CART_LOAD_CART_SERVER_TOKEN) ) { - return Vue.prototype.$db.cartsCollection.setItem('current-cart-token', state.cart.cartServerToken).catch((reason) => { + return StorageManager.get('cartsCollection').setItem('current-cart-token', state.cart.cartServerToken).catch((reason) => { console.error(reason) }) } else if ( type.endsWith(types.CART_SET_ITEMS_HASH) ) { - return Vue.prototype.$db.cartsCollection.setItem('current-cart-hash', state.cart.cartItemsHash).catch((reason) => { + return StorageManager.get('cartsCollection').setItem('current-cart-hash', state.cart.cartItemsHash).catch((reason) => { console.error(reason) }) } diff --git a/core/modules/cart/hooks/beforeRegistration.ts b/core/modules/cart/hooks/beforeRegistration.ts index 7aeda78bc4..1fe99a637b 100644 --- a/core/modules/cart/hooks/beforeRegistration.ts +++ b/core/modules/cart/hooks/beforeRegistration.ts @@ -1,14 +1,15 @@ import * as localForage from 'localforage' import UniversalStorage from '@vue-storefront/core/store/lib/storage' import { currentStoreView } from '@vue-storefront/core/lib/multistore' +import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' export function beforeRegistration ({ Vue, config, store, isServer }) { const storeView = currentStoreView() const dbNamePrefix = storeView.storeCode ? storeView.storeCode + '-' : '' - Vue.prototype.$db.cartsCollection = new UniversalStorage(localForage.createInstance({ + StorageManager.set('cartsCollection', new UniversalStorage(localForage.createInstance({ name: (config.storeViews.commonCache ? '' : dbNamePrefix) + 'shop', storeName: 'carts', driver: localForage[config.localForage.defaultDrivers['carts']] - })) + }))) } diff --git a/core/modules/cart/store/actions.ts b/core/modules/cart/store/actions.ts index 368336740c..1272cdd1b8 100644 --- a/core/modules/cart/store/actions.ts +++ b/core/modules/cart/store/actions.ts @@ -1,4 +1,3 @@ -import Vue from 'vue' import { ActionTree } from 'vuex' import * as types from './mutation-types' import i18n from '@vue-storefront/i18n' @@ -15,6 +14,8 @@ import SearchQuery from '@vue-storefront/core/lib/search/searchQuery' import { isServer } from '@vue-storefront/core/helpers' import config from 'config' import Task from '@vue-storefront/core/lib/sync/types/Task' +import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus' +import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' let _connectBypassCount = 0 @@ -164,7 +165,7 @@ const actions: ActionTree = { } } await dispatch('payment/replaceMethods', paymentMethods, { root: true }) - Vue.prototype.$bus.$emit('set-unique-payment-methods', uniqueBackendMethods) + EventBus.$emit('set-unique-payment-methods', uniqueBackendMethods) } else { Logger.debug('Payment methods does not need to be updated', 'cart')() } @@ -240,11 +241,11 @@ const actions: ActionTree = { let paymentMethod = rootGetters['payment/paymentMethods'].find(item => item.default) commit(types.CART_UPD_PAYMENT, paymentMethod) } - const storedItems = await Vue.prototype.$db.cartsCollection.getItem('current-cart') + const storedItems = await StorageManager.get('cartsCollection').getItem('current-cart') commit(types.CART_LOAD_CART, storedItems) if (config.cart.synchronize) { - const token = await Vue.prototype.$db.cartsCollection.getItem('current-cart-token') - const hash = await Vue.prototype.$db.cartsCollection.getItem('current-cart-hash') + const token = await StorageManager.get('cartsCollection').getItem('current-cart-token') + const hash = await StorageManager.get('cartsCollection').getItem('current-cart-hash') if (hash) { commit(types.CART_SET_ITEMS_HASH, hash) Logger.info('Cart hash received from cache.', 'cache', hash)() @@ -285,7 +286,7 @@ const actions: ActionTree = { for (let product of productsToAdd) { if (typeof product === 'undefined' || product === null) continue if (product.qty && typeof product.qty !== 'number') product.qty = parseInt(product.qty) - if ((config.useZeroPriceProduct) ? product.priceInclTax < 0 : product.priceInclTax <= 0) { + if ((config.useZeroPriceProduct) ? product.price_incl_tax < 0 : product.price_incl_tax <= 0) { diffLog.clientNotifications.push({ type: 'error', message: i18n.t('Product price is unknown, product cannot be added to the cart!'), @@ -502,7 +503,7 @@ const actions: ActionTree = { }, /** authorize the cart after user got logged in using the current cart token */ authorize ({ dispatch }) { - Vue.prototype.$db.usersCollection.getItem('last-cart-bypass-ts', (err, lastCartBypassTs) => { + StorageManager.get('usersCollection').getItem('last-cart-bypass-ts', (err, lastCartBypassTs) => { if (err) { Logger.error(err, 'cart')() } @@ -566,7 +567,7 @@ const actions: ActionTree = { const _updateClientItem = async function ({ dispatch }, event, clientItem) { if (typeof event.result.item_id !== 'undefined') { await dispatch('updateItem', { product: { server_item_id: event.result.item_id, sku: clientItem.sku, server_cart_id: event.result.quote_id, prev_qty: clientItem.qty } }) // update the server_id reference - Vue.prototype.$bus.$emit('cart-after-itemchanged', { item: clientItem }) + EventBus.$emit('cart-after-itemchanged', { item: clientItem }) } } @@ -582,7 +583,7 @@ const actions: ActionTree = { Logger.log('Restoring qty after error' + clientItem.sku + cartItem.prev_qty, 'cart')() if (cartItem.prev_qty > 0) { dispatch('updateItem', { product: { qty: cartItem.prev_qty } }) // update the server_id reference - Vue.prototype.$bus.$emit('cart-after-itemchanged', { item: cartItem }) + EventBus.$emit('cart-after-itemchanged', { item: cartItem }) } else { dispatch('removeItem', { product: cartItem, removeByParentSku: false }) // update the server_id reference } @@ -744,7 +745,7 @@ const actions: ActionTree = { } commit(types.CART_SET_ITEMS_HASH, getters.getCurrentCartHash) // update the cart hash } - Vue.prototype.$bus.$emit('servercart-after-diff', { diffLog: diffLog, serverItems: serverItems, clientItems: clientItems, dryRun: dryRun, event: event }) // send the difflog + EventBus.$emit('servercart-after-diff', { diffLog: diffLog, serverItems: serverItems, clientItems: clientItems, dryRun: dryRun, event: event }) // send the difflog Logger.info('Client/Server cart synchronised ', 'cart', diffLog)() return diffLog }, diff --git a/core/modules/cart/store/getters.ts b/core/modules/cart/store/getters.ts index 4fd87f72a8..ea78684a4f 100644 --- a/core/modules/cart/store/getters.ts +++ b/core/modules/cart/store/getters.ts @@ -62,17 +62,17 @@ const getters: GetterTree = { let payment = state.payment instanceof Array ? state.payment[0] : state.payment const totalsArray = [ { - code: 'subtotalInclTax', + code: 'subtotal_incl_tax', title: i18n.t('Subtotal incl. tax'), value: sumBy(state.cartItems, (p) => { - return p.qty * p.priceInclTax + return p.qty * p.price_incl_tax }) }, { code: 'grand_total', title: i18n.t('Grand total'), value: sumBy(state.cartItems, (p) => { - return p.qty * p.priceInclTax + (shipping ? shipping.price_incl_tax : 0) + return p.qty * p.price_incl_tax + (shipping ? shipping.price_incl_tax : 0) }) } ] @@ -80,7 +80,7 @@ const getters: GetterTree = { totalsArray.push({ code: 'payment', title: i18n.t(payment.title), - value: payment.costInclTax + value: payment.cost_incl_tax }) } if (shipping) { diff --git a/core/modules/cart/store/mutations.ts b/core/modules/cart/store/mutations.ts index c3bc3a8c67..b2f111cba1 100644 --- a/core/modules/cart/store/mutations.ts +++ b/core/modules/cart/store/mutations.ts @@ -1,9 +1,8 @@ -import Vue from 'vue' import { MutationTree } from 'vuex' import * as types from './mutation-types' import CartState from '../types/CartState' import config from 'config' -import { calcItemsHmac } from '@vue-storefront/core/helpers' +import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus' const mutations: MutationTree = { /** @@ -17,10 +16,10 @@ const mutations: MutationTree = { ...product, qty: parseInt(product.qty ? product.qty : 1) } - Vue.prototype.$bus.$emit('cart-before-add', { product: item }) + EventBus.$emit('cart-before-add', { product: item }) state.cartItems.push(item) } else { - Vue.prototype.$bus.$emit('cart-before-update', { product: record }) + EventBus.$emit('cart-before-update', { product: record }) record.qty += parseInt((product.qty ? product.qty : 1)) } }, @@ -34,30 +33,30 @@ const mutations: MutationTree = { state.cartServerLastTotalsSyncDate = new Date().getTime() }, [types.CART_DEL_ITEM] (state, { product, removeByParentSku = true }) { - Vue.prototype.$bus.$emit('cart-before-delete', { items: state.cartItems }) + EventBus.$emit('cart-before-delete', { items: state.cartItems }) state.cartItems = state.cartItems.filter(p => p.sku !== product.sku && (p.parentSku !== product.sku || removeByParentSku === false)) - Vue.prototype.$bus.$emit('cart-after-delete', { items: state.cartItems }) + EventBus.$emit('cart-after-delete', { items: state.cartItems }) }, [types.CART_DEL_NON_CONFIRMED_ITEM] (state, { product, removeByParentSku = true }) { - Vue.prototype.$bus.$emit('cart-before-delete', { items: state.cartItems }) + EventBus.$emit('cart-before-delete', { items: state.cartItems }) state.cartItems = state.cartItems.filter(p => (p.sku !== product.sku && (p.parentSku !== product.sku || removeByParentSku === false)) || p.server_item_id/* it's confirmed if server_item_id is set */) - Vue.prototype.$bus.$emit('cart-after-delete', { items: state.cartItems }) + EventBus.$emit('cart-after-delete', { items: state.cartItems }) }, [types.CART_UPD_ITEM] (state, { product, qty }) { const record = state.cartItems.find(p => p.sku === product.sku) if (record) { - Vue.prototype.$bus.$emit('cart-before-update', { product: record }) + EventBus.$emit('cart-before-update', { product: record }) record.qty = parseInt(qty) - Vue.prototype.$bus.$emit('cart-after-update', { product: record }) + EventBus.$emit('cart-after-update', { product: record }) } }, [types.CART_UPD_ITEM_PROPS] (state, { product }) { let record = state.cartItems.find(p => (p.sku === product.sku || (p.server_item_id && p.server_item_id === product.server_item_id))) if (record) { - Vue.prototype.$bus.$emit('cart-before-itemchanged', { item: record }) + EventBus.$emit('cart-before-itemchanged', { item: record }) record = Object.assign(record, product) - Vue.prototype.$bus.$emit('cart-after-itemchanged', { item: record }) + EventBus.$emit('cart-after-itemchanged', { item: record }) } }, [types.CART_UPD_SHIPPING] (state, shippingMethod) { @@ -67,10 +66,10 @@ const mutations: MutationTree = { state.cartItems = storedItems || [] state.cartIsLoaded = true - // Vue.prototype.$bus.$emit('order/PROCESS_QUEUE', { config: config }) // process checkout queue - Vue.prototype.$bus.$emit('sync/PROCESS_QUEUE', { config }) // process checkout queue - Vue.prototype.$bus.$emit('application-after-loaded') - Vue.prototype.$bus.$emit('cart-after-loaded') + // EventBus.$emit('order/PROCESS_QUEUE', { config: config }) // process checkout queue + EventBus.$emit('sync/PROCESS_QUEUE', { config }) // process checkout queue + EventBus.$emit('application-after-loaded') + EventBus.$emit('cart-after-loaded') }, [types.CART_LOAD_CART_SERVER_TOKEN] (state, token) { state.cartServerToken = token @@ -79,7 +78,7 @@ const mutations: MutationTree = { state.itemsAfterPlatformTotals = itemsAfterTotals state.platformTotals = totals state.platformTotalSegments = platformTotalSegments - Vue.prototype.$bus.$emit('cart-after-updatetotals', { platformTotals: totals, platformTotalSegments: platformTotalSegments }) + EventBus.$emit('cart-after-updatetotals', { platformTotals: totals, platformTotalSegments: platformTotalSegments }) }, [types.CART_UPD_PAYMENT] (state, paymentMethod) { state.payment = paymentMethod diff --git a/core/modules/cart/test/unit/components/AddToCart.spec.ts b/core/modules/cart/test/unit/components/AddToCart.spec.ts index e825db35f2..ef948b857e 100644 --- a/core/modules/cart/test/unit/components/AddToCart.spec.ts +++ b/core/modules/cart/test/unit/components/AddToCart.spec.ts @@ -1,8 +1,16 @@ import { mountMixinWithStore } from '@vue-storefront/unit-tests/utils'; - import Product from '@vue-storefront/core/modules/catalog/types/Product'; - import { AddToCart } from '../../../components/AddToCart' +jest.mock('@vue-storefront/core/lib/logger', () => ({ + Logger: { + log: jest.fn(() => () => {}), + debug: jest.fn(() => () => {}), + warn: jest.fn(() => () => {}), + error: jest.fn(() => () => {}) + } +})); +jest.mock('@vue-storefront/core/app', () => ({ createApp: jest.fn() })) +jest.mock('@vue-storefront/i18n', () => ({loadLanguageAsync: jest.fn()})) describe('AddToCart', () => { it('addToCart dispatches addItem action', () => { diff --git a/core/modules/cart/test/unit/helpers/cartCacheHandler.spec.ts b/core/modules/cart/test/unit/helpers/cartCacheHandler.spec.ts index e24976e784..1ce9a8571c 100644 --- a/core/modules/cart/test/unit/helpers/cartCacheHandler.spec.ts +++ b/core/modules/cart/test/unit/helpers/cartCacheHandler.spec.ts @@ -1,16 +1,26 @@ import Vue from 'vue' import Vuex from 'vuex' -import * as types from '../../../store/mutation-types' - -import { cartCacheHandlerFactory } from '../../../helpers/cartCacheHandler'; -Vue.use(Vuex); +import * as types from '../../../store/mutation-types' -Vue.prototype.$db = { +const StorageManager = { cartsCollection: { setItem: jest.fn() + }, + get (key) { + return this[key] } }; +const cartCacheHandlerFactory = require('../../../helpers/cartCacheHandler').cartCacheHandlerFactory + +jest.mock('@vue-storefront/core/store/lib/storage-manager', () => ({StorageManager})) +jest.mock('@vue-storefront/core/helpers', () => ({ + isServer: () => false +})); +jest.mock('@vue-storefront/core/app', () => ({ createApp: jest.fn() })) +jest.mock('@vue-storefront/i18n', () => ({loadLanguageAsync: jest.fn()})) + +Vue.use(Vuex); describe('Cart afterRegistration', () => { beforeEach(() => { @@ -30,11 +40,11 @@ describe('Cart afterRegistration', () => { } }; - Vue.prototype.$db.cartsCollection.setItem.mockImplementationOnce(() => Promise.resolve('foo')); + StorageManager.get('cartsCollection').setItem.mockImplementationOnce(() => Promise.resolve('foo')); await cartCacheHandlerFactory(Vue)({ type: mutationType }, stateMock); - expect(Vue.prototype.$db.cartsCollection.setItem) + expect(StorageManager.get('cartsCollection').setItem) .toBeCalledWith('current-cart', stateMock.cart.cartItems); }); @@ -47,7 +57,7 @@ describe('Cart afterRegistration', () => { const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementationOnce(() => {}); - Vue.prototype.$db.cartsCollection.setItem.mockImplementationOnce(() => Promise.reject('foo')); + StorageManager.get('cartsCollection').setItem.mockImplementationOnce(() => Promise.reject('foo')); await cartCacheHandlerFactory(Vue)({ type: types.CART_LOAD_CART }, stateMock); @@ -61,11 +71,11 @@ describe('Cart afterRegistration', () => { } }; - Vue.prototype.$db.cartsCollection.setItem.mockImplementationOnce(() => Promise.resolve('foo')); + StorageManager.get('cartsCollection').setItem.mockImplementationOnce(() => Promise.resolve('foo')); await cartCacheHandlerFactory(Vue)({ type: types.CART_LOAD_CART_SERVER_TOKEN }, stateMock); - expect(Vue.prototype.$db.cartsCollection.setItem) + expect(StorageManager.get('cartsCollection').setItem) .toBeCalledWith('current-cart-token', stateMock.cart.cartServerToken); }); @@ -78,7 +88,7 @@ describe('Cart afterRegistration', () => { const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementationOnce(() => {}); - Vue.prototype.$db.cartsCollection.setItem.mockImplementationOnce(() => Promise.reject('foo')); + StorageManager.get('cartsCollection').setItem.mockImplementationOnce(() => Promise.reject('foo')); await cartCacheHandlerFactory(Vue)({ type: types.CART_LOAD_CART_SERVER_TOKEN }, stateMock); @@ -94,7 +104,7 @@ describe('Cart afterRegistration', () => { const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementationOnce(() => {}); - Vue.prototype.$db.cartsCollection.setItem.mockImplementationOnce(() => Promise.reject('foo')); + StorageManager.get('cartsCollection').setItem.mockImplementationOnce(() => Promise.reject('foo')); await cartCacheHandlerFactory(Vue)({ type: 'bar' }, stateMock); diff --git a/core/modules/cart/test/unit/hooks/afterRegistration.spec.ts b/core/modules/cart/test/unit/hooks/afterRegistration.spec.ts index 83551fa114..76ec6ced2e 100644 --- a/core/modules/cart/test/unit/hooks/afterRegistration.spec.ts +++ b/core/modules/cart/test/unit/hooks/afterRegistration.spec.ts @@ -9,9 +9,12 @@ Vue.use(Vuex); jest.mock('../../../helpers/cartCacheHandler', () => ({ cartCacheHandlerFactory: jest.fn() })); -Vue.prototype.$db = { +const StorageManager = { cartsCollection: { setItem: jest.fn() + }, + get: (key) => { + return this[key] } }; diff --git a/core/modules/cart/test/unit/hooks/beforeRegistration.spec.ts b/core/modules/cart/test/unit/hooks/beforeRegistration.spec.ts index c970c35f87..568110dd1a 100644 --- a/core/modules/cart/test/unit/hooks/beforeRegistration.spec.ts +++ b/core/modules/cart/test/unit/hooks/beforeRegistration.spec.ts @@ -1,6 +1,7 @@ import Vue from 'vue' import UniversalStorage from '@vue-storefront/core/store/lib/storage'; +import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager'; import { currentStoreView } from '@vue-storefront/core/lib/multistore'; import { beforeRegistration } from '../../../hooks/beforeRegistration'; import * as localForage from 'localforage'; @@ -10,7 +11,7 @@ jest.mock('localforage', () => ({ createInstance: jest.fn(), someDriver: {} })); jest.mock('@vue-storefront/core/store/lib/storage', () => jest.fn()); jest.mock('@vue-storefront/core/lib/multistore', () => ({ currentStoreView: jest.fn() })); -Vue.prototype.$db = {}; +StorageManager.get('cartsCollection').setItem = jest.fn() describe('Cart beforeRegistration', () => { beforeEach(() => { @@ -30,12 +31,12 @@ describe('Cart beforeRegistration', () => { }; const storageMock = {foo: 'bar'}; - (currentStoreView as Mock).mockReturnValueOnce({}); + (currentStoreView as Mock).mockReturnValue({}); (UniversalStorage as unknown as Mock).mockImplementationOnce(() => storageMock); beforeRegistration({ Vue, config, store: undefined, isServer: undefined }); - expect(Vue.prototype.$db.cartsCollection).toEqual(storageMock); + expect(StorageManager.get('cartsCollection')).toEqual(storageMock); }); it('hook initializes cart cache with storeCode sufix in name', () => { @@ -61,6 +62,6 @@ describe('Cart beforeRegistration', () => { storeName: 'carts', driver: {} }); - expect(Vue.prototype.$db.cartsCollection).toEqual(storageMock); + expect(StorageManager.get('cartsCollection')).toEqual(storageMock); }); }); diff --git a/core/modules/cart/test/unit/store/actions.spec.ts b/core/modules/cart/test/unit/store/actions.spec.ts index 572672cf0f..eb11613bf3 100644 --- a/core/modules/cart/test/unit/store/actions.spec.ts +++ b/core/modules/cart/test/unit/store/actions.spec.ts @@ -1,5 +1,3 @@ -import Vue from 'vue' - import * as types from '../../../store/mutation-types'; import cartActions from '../../../store/actions'; import config from 'config'; @@ -7,7 +5,6 @@ import rootStore from '@vue-storefront/core/store'; import { sha3_224 } from 'js-sha3'; import { TaskQueue } from '../../../../../lib/sync'; import * as coreHelper from '@vue-storefront/core/helpers'; -import { currentStoreView } from '@vue-storefront/core/lib/multistore'; import { onlineHelper } from '@vue-storefront/core/helpers'; jest.mock('@vue-storefront/core/store', () => ({ @@ -45,7 +42,7 @@ jest.mock('@vue-storefront/core/helpers', () => ({ } })); -Vue.prototype.$bus = { +const EventBus = { $emit: jest.fn() }; @@ -124,6 +121,7 @@ describe('Cart actions', () => { rootGetters: { checkout: { isUserInCheckout: () => false } }, getters: { isCartSyncEnabled: true, isTotalsSyncRequired: true, isSyncRequired: true, isCartConnected: true }, dispatch: jest.fn(), + commit: jest.fn(), state: { cartItems: [], cartServerToken: 'some-token', @@ -142,16 +140,14 @@ describe('Cart actions', () => { const expectedState = { cartItems: [], - cartItemsHash: 'new-hash', - cartServerPullAt: 1000003000 + cartItemsHash: 'new-hash' }; isServerSpy.mockReturnValueOnce(false); - Date.now = jest.fn(() => expectedState.cartServerPullAt); (sha3_224 as any).mockReturnValueOnce(expectedState.cartItemsHash); (TaskQueue.execute as jest.Mock).mockImplementationOnce(() => Promise.resolve({})); - const wrapper = (actions: any) => actions.serverPull(contextMock, {}); + const wrapper = (actions: any) => actions.sync(contextMock, {}); await wrapper(cartActions); @@ -160,38 +156,6 @@ describe('Cart actions', () => { { country_id: 'us' } ); }); - - it('does not do anything if synchronization is off', async () => { - const contextMock = { - rootGetters: { checkout: { isUserInCheckout: () => false } }, - getters: { isCartSyncEnabled: true, isTotalsSyncRequired: true, isSyncRequired: true, isCartConnected: true }, - dispatch: jest.fn() - }; - - config.cart = { synchronize: false }; - - const wrapper = (actions: any) => actions.serverPull(contextMock, {}); - - await wrapper(cartActions); - - expect(TaskQueue.execute).not.toBeCalled(); - }); - - it('does not do anything in SSR environment', async () => { - const contextMock = { - rootGetters: { checkout: { isUserInCheckout: () => false } }, - getters: { isCartSyncEnabled: true, isTotalsSyncRequired: true, isSyncRequired: true, isCartConnected: true }, - dispatch: jest.fn() - }; - - config.cart = { synchronize: true }; - - const wrapper = (actions: any) => actions.serverPull(contextMock, {}); - - await wrapper(cartActions); - - expect(TaskQueue.execute).not.toBeCalled(); - }); }); describe('syncTotals', () => { @@ -216,6 +180,8 @@ describe('Cart actions', () => { it('does not do anything in SSR environment', () => { const contextMock = { + commit: jest.fn(), + dispatch: jest.fn(), getters: { isTotalsSyncRequired: false } @@ -237,7 +203,9 @@ describe('Cart actions', () => { getters: { isCartSyncEnabled: true, isTotalsSyncRequired: true, isSyncRequired: true, isCartConnected: true }, state: { cartconnectdAt: 1000000000 - } + }, + commit: jest.fn(), + dispatch: jest.fn() }; config.cart = { synchronize: true }; diff --git a/core/modules/cart/test/unit/store/getters.spec.ts b/core/modules/cart/test/unit/store/getters.spec.ts index 5b54f2ae2c..7714edc315 100644 --- a/core/modules/cart/test/unit/store/getters.spec.ts +++ b/core/modules/cart/test/unit/store/getters.spec.ts @@ -48,14 +48,14 @@ describe('Cart getters', () => { nor additional prices`, () => { const stateMock = { cartItems: [ - {qty: 1, priceInclTax: 1}, - {qty: 2, priceInclTax: 2} + {qty: 1, price_incl_tax: 1}, + {qty: 2, price_incl_tax: 2} ] }; const wrapper = (getters: any) => getters.getTotals(stateMock); expect(wrapper(cartGetters)).toEqual([ - {'code': 'subtotalInclTax', 'title': 'Subtotal incl. tax', 'value': 5}, + {'code': 'subtotal_incl_tax', 'title': 'Subtotal incl. tax', 'value': 5}, {'code': 'grand_total', 'title': 'Grand total', 'value': 5} ]); }); @@ -68,14 +68,14 @@ describe('Cart getters', () => { {'code': 'shipping', 'title': 'Shipping & Handling (Flat Rate - Fixed)', 'value': 5} ], cartItems: [ - {qty: 1, priceInclTax: 1}, - {qty: 2, priceInclTax: 2} + {qty: 1, price_incl_tax: 1}, + {qty: 2, price_incl_tax: 2} ] }; const wrapper = (getters: any) => getters.getTotals(stateMock); expect(wrapper(cartGetters)).toEqual([ - {'code': 'subtotalInclTax', 'title': 'Subtotal incl. tax', 'value': 5}, + {'code': 'subtotal_incl_tax', 'title': 'Subtotal incl. tax', 'value': 5}, {'code': 'grand_total', 'title': 'Grand total', 'value': 5} ]); }); @@ -84,12 +84,12 @@ describe('Cart getters', () => { but no platformTotalSegments`, () => { const stateMock = { cartItems: [ - {qty: 1, priceInclTax: 1}, - {qty: 2, priceInclTax: 2} + {qty: 1, price_incl_tax: 1}, + {qty: 2, price_incl_tax: 2} ], payment: { title: 'payment', - costInclTax: 4 + cost_incl_tax: 4 }, shipping: { method_title: 'shipping', @@ -99,7 +99,7 @@ describe('Cart getters', () => { const wrapper = (getters: any) => getters.getTotals(stateMock); expect(wrapper(cartGetters)).toEqual([ - {'code': 'subtotalInclTax', 'title': 'Subtotal incl. tax', 'value': 5}, + {'code': 'subtotal_incl_tax', 'title': 'Subtotal incl. tax', 'value': 5}, {'code': 'grand_total', 'title': 'Grand total', 'value': 21}, {'code': 'payment', 'title': 'payment', 'value': 4}, {'code': 'shipping', 'title': 'shipping', 'value': 8} @@ -110,17 +110,17 @@ describe('Cart getters', () => { but no platformTotalSegments`, () => { const stateMock = { cartItems: [ - {qty: 1, priceInclTax: 1}, - {qty: 2, priceInclTax: 2} + {qty: 1, price_incl_tax: 1}, + {qty: 2, price_incl_tax: 2} ], payment: [ { title: 'payment', - costInclTax: 4 + cost_incl_tax: 4 }, { title: 'another-payment', - costInclTax: 16 + cost_incl_tax: 16 } ], shipping: [ @@ -137,7 +137,7 @@ describe('Cart getters', () => { const wrapper = (getters: any) => getters.getTotals(stateMock); expect(wrapper(cartGetters)).toEqual([ - {'code': 'subtotalInclTax', 'title': 'Subtotal incl. tax', 'value': 5}, + {'code': 'subtotal_incl_tax', 'title': 'Subtotal incl. tax', 'value': 5}, {'code': 'grand_total', 'title': 'Grand total', 'value': 21}, {'code': 'payment', 'title': 'payment', 'value': 4}, {'code': 'shipping', 'title': 'shipping', 'value': 8} diff --git a/core/modules/cart/test/unit/store/mutations.spec.ts b/core/modules/cart/test/unit/store/mutations.spec.ts index 0cac88f2e5..9eb2fc0941 100644 --- a/core/modules/cart/test/unit/store/mutations.spec.ts +++ b/core/modules/cart/test/unit/store/mutations.spec.ts @@ -1,14 +1,11 @@ -import Vue from 'vue' import * as types from '../../../store/mutation-types' import cartMutations from '../../../store/mutations' - +import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus' jest.mock('@vue-storefront/core/helpers', () => ({ once: (str) => jest.fn() })) -Vue.prototype.$bus = { - $emit: jest.fn() -} +EventBus.$emit = jest.fn() jest.mock('@vue-storefront/core/store', () => ({ state: { @@ -42,7 +39,7 @@ describe('Cart mutations', () => { wrapper(cartMutations) - expect(Vue.prototype.$bus.$emit).toBeCalledWith('cart-before-add', { product }) + expect(EventBus.$emit).toBeCalledWith('cart-before-add', { product }) expect(stateMock).toEqual(expectedState) }) @@ -65,7 +62,7 @@ describe('Cart mutations', () => { wrapper(cartMutations) - expect(Vue.prototype.$bus.$emit).toBeCalledWith('cart-before-add', { product: { ...product, qty: 1 } }) + expect(EventBus.$emit).toBeCalledWith('cart-before-add', { product: { ...product, qty: 1 } }) expect(stateMock).toEqual(expectedState) }) @@ -148,13 +145,13 @@ describe('Cart mutations', () => { wrapper(cartMutations) - expect(Vue.prototype.$bus.$emit).toBeCalledWith('cart-before-delete', { + expect(EventBus.$emit).toBeCalledWith('cart-before-delete', { items: [{ qty: 10, sku: 'foo' }] }) - expect(Vue.prototype.$bus.$emit).toBeCalledWith('cart-after-delete', {items: expectedState.cartItems}) + expect(EventBus.$emit).toBeCalledWith('cart-after-delete', {items: expectedState.cartItems}) expect(stateMock).toEqual(expectedState) }) @@ -179,13 +176,13 @@ describe('Cart mutations', () => { wrapper(cartMutations) - expect(Vue.prototype.$bus.$emit).toBeCalledWith('cart-before-delete', { + expect(EventBus.$emit).toBeCalledWith('cart-before-delete', { items: [{ qty: 10, sku: 'foo' }] }) - expect(Vue.prototype.$bus.$emit).toBeCalledWith('cart-after-delete', {items: expectedState.cartItems}) + expect(EventBus.$emit).toBeCalledWith('cart-after-delete', {items: expectedState.cartItems}) expect(stateMock).toEqual(expectedState) }) }) @@ -211,13 +208,13 @@ describe('Cart mutations', () => { ) wrapper(cartMutations) - expect(Vue.prototype.$bus.$emit).toBeCalledWith('cart-before-delete', { + expect(EventBus.$emit).toBeCalledWith('cart-before-delete', { items: [{ qty: 10, sku: 'foo' }] }) - expect(Vue.prototype.$bus.$emit).toBeCalledWith('cart-after-delete', {items: expectedState.cartItems}) + expect(EventBus.$emit).toBeCalledWith('cart-after-delete', {items: expectedState.cartItems}) expect(stateMock).toEqual(expectedState) }) @@ -242,13 +239,13 @@ describe('Cart mutations', () => { wrapper(cartMutations) - expect(Vue.prototype.$bus.$emit).toBeCalledWith('cart-before-delete', { + expect(EventBus.$emit).toBeCalledWith('cart-before-delete', { items: [{ qty: 10, sku: 'foo' }] }) - expect(Vue.prototype.$bus.$emit).toBeCalledWith('cart-after-delete', {items: expectedState.cartItems}) + expect(EventBus.$emit).toBeCalledWith('cart-after-delete', {items: expectedState.cartItems}) expect(stateMock).toEqual(expectedState) }) @@ -281,8 +278,8 @@ describe('Cart mutations', () => { wrapper(cartMutations) - expect(Vue.prototype.$bus.$emit).toBeCalledWith('cart-before-delete', {items: stateMock.cartItems}) - expect(Vue.prototype.$bus.$emit).toBeCalledWith('cart-after-delete', {items: expectedState.cartItems}) + expect(EventBus.$emit).toBeCalledWith('cart-before-delete', {items: stateMock.cartItems}) + expect(EventBus.$emit).toBeCalledWith('cart-after-delete', {items: expectedState.cartItems}) expect(stateMock).toEqual(expectedState) }) }) @@ -316,8 +313,8 @@ describe('Cart mutations', () => { // unfortunately before and after events return a reference to the same object, therefore // after performing this mutation after event return same object with same, updated value as before event - expect(Vue.prototype.$bus.$emit).toBeCalledWith('cart-before-update', { product: expectedState.cartItems[0] }) - expect(Vue.prototype.$bus.$emit).toBeCalledWith('cart-after-update', { product: expectedState.cartItems[0] }) + expect(EventBus.$emit).toBeCalledWith('cart-before-update', { product: expectedState.cartItems[0] }) + expect(EventBus.$emit).toBeCalledWith('cart-after-update', { product: expectedState.cartItems[0] }) expect(stateMock).toEqual(expectedState) }) @@ -341,7 +338,7 @@ describe('Cart mutations', () => { wrapper(cartMutations) - expect(Vue.prototype.$bus.$emit).not.toBeCalled() + expect(EventBus.$emit).not.toBeCalled() expect(stateMock).toEqual(expectedState) }) }) @@ -374,14 +371,14 @@ describe('Cart mutations', () => { ) let firstEmitCall = [] - Vue.prototype.$bus.$emit.mockImplementationOnce((eventName, args) => { + EventBus.$emit.mockImplementationOnce((eventName, args) => { firstEmitCall.push(eventName) firstEmitCall.push(args) }) wrapper(cartMutations) expect(firstEmitCall).toEqual(['cart-before-itemchanged', { item: expectedState.cartItems[0] }]) - expect(Vue.prototype.$bus.$emit).toBeCalledWith('cart-after-itemchanged', { item: expectedState.cartItems[0] }) + expect(EventBus.$emit).toBeCalledWith('cart-after-itemchanged', { item: expectedState.cartItems[0] }) expect(stateMock).toEqual(expectedState) }) @@ -414,14 +411,14 @@ describe('Cart mutations', () => { ) let firstEmitCall = [] - Vue.prototype.$bus.$emit.mockImplementationOnce((eventName, args) => { + EventBus.$emit.mockImplementationOnce((eventName, args) => { firstEmitCall.push(eventName) firstEmitCall.push(args) }) wrapper(cartMutations) expect(firstEmitCall).toEqual(['cart-before-itemchanged', { item: expectedState.cartItems[0] }]) - expect(Vue.prototype.$bus.$emit).toBeCalledWith('cart-after-itemchanged', { item: expectedState.cartItems[0] }) + expect(EventBus.$emit).toBeCalledWith('cart-after-itemchanged', { item: expectedState.cartItems[0] }) expect(stateMock).toEqual(expectedState) }) @@ -445,7 +442,7 @@ describe('Cart mutations', () => { wrapper(cartMutations) - expect(Vue.prototype.$bus.$emit).not.toBeCalled() + expect(EventBus.$emit).not.toBeCalled() expect(stateMock).toEqual(expectedState) }) }) @@ -484,9 +481,9 @@ describe('Cart mutations', () => { ) wrapper(cartMutations) - expect(Vue.prototype.$bus.$emit).toBeCalledWith('sync/PROCESS_QUEUE', expect.anything()) - expect(Vue.prototype.$bus.$emit).toBeCalledWith('application-after-loaded') - expect(Vue.prototype.$bus.$emit).toBeCalledWith('cart-after-loaded') + expect(EventBus.$emit).toBeCalledWith('sync/PROCESS_QUEUE', expect.anything()) + expect(EventBus.$emit).toBeCalledWith('application-after-loaded') + expect(EventBus.$emit).toBeCalledWith('cart-after-loaded') expect(stateMock).toEqual(expectedState) }) @@ -502,9 +499,9 @@ describe('Cart mutations', () => { wrapper(cartMutations) - expect(Vue.prototype.$bus.$emit).toBeCalledWith('sync/PROCESS_QUEUE', expect.anything()) - expect(Vue.prototype.$bus.$emit).toBeCalledWith('application-after-loaded') - expect(Vue.prototype.$bus.$emit).toBeCalledWith('cart-after-loaded') + expect(EventBus.$emit).toBeCalledWith('sync/PROCESS_QUEUE', expect.anything()) + expect(EventBus.$emit).toBeCalledWith('application-after-loaded') + expect(EventBus.$emit).toBeCalledWith('cart-after-loaded') expect(stateMock).toEqual(expectedState) }) @@ -546,7 +543,7 @@ describe('Cart mutations', () => { wrapper(cartMutations) - expect(Vue.prototype.$bus.$emit).toBeCalledWith('cart-after-updatetotals', { + expect(EventBus.$emit).toBeCalledWith('cart-after-updatetotals', { platformTotals: expectedState.platformTotals, platformTotalSegments: expectedState.platformTotalSegments }) diff --git a/core/modules/catalog-next/store/category/actions.ts b/core/modules/catalog-next/store/category/actions.ts index 1835dec4bc..fc4f7104e4 100644 --- a/core/modules/catalog-next/store/category/actions.ts +++ b/core/modules/catalog-next/store/category/actions.ts @@ -25,7 +25,7 @@ const actions: ActionTree = { const {items, perPage, start, total} = await quickSearchByQuery({ query: filterQr, sort: searchQuery.sort }) commit(types.CATEGORY_SET_SEARCH_PRODUCTS_STATS, { perPage, start, total }) let configuredProducts = items.map(product => { - const configuredProductVariant = configureProductAsync({rootState, state: {current_configuration: {}}}, {product, configuration: searchQuery.filters, selectDefaultVariant: false, fallbackToDefaultWhenNoAvailable: true, setProductErorrs: false}) + const configuredProductVariant = configureProductAsync({rootState}, {product, configuration: searchQuery.filters, selectDefaultVariant: false, fallbackToDefaultWhenNoAvailable: true, setProductErorrs: false}) return Object.assign(product, configuredProductVariant) }) commit(types.CATEGORY_SET_PRODUCTS, configuredProducts) diff --git a/core/modules/catalog/components/Search.ts b/core/modules/catalog/components/Search.ts index c4c010582b..a4fa3db75f 100644 --- a/core/modules/catalog/components/Search.ts +++ b/core/modules/catalog/components/Search.ts @@ -47,7 +47,7 @@ export const Search = { let startValue = 0; this.start = startValue this.readMore = true - this.$store.dispatch('product/list', { query, start: this.start, size: this.size, updateState: false }).then(resp => { + this.$store.dispatch('product/list', { query, start: this.start, configuration: {}, size: this.size, updateState: false }).then(resp => { this.products = resp.items this.start = startValue + this.size this.emptyResults = resp.items.length < 1 diff --git a/core/modules/catalog/helpers/index.ts b/core/modules/catalog/helpers/index.ts index 7a80e417b5..01783a5699 100644 --- a/core/modules/catalog/helpers/index.ts +++ b/core/modules/catalog/helpers/index.ts @@ -1,4 +1,4 @@ -import Vue from 'vue' +import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus' import rootStore from '@vue-storefront/core/store' import { calculateProductTax } from '../helpers/tax' import flattenDeep from 'lodash-es/flattenDeep' @@ -22,7 +22,7 @@ function _filterRootProductByStockitem (context, stockItem, product, errorCallba if (stockItem.is_in_stock === false) { product.errors.variants = i18n.t('No available product variants') context.state.current.errors = product.errors - Vue.prototype.$bus.$emit('product-after-removevariant', { product: product }) + EventBus.$emit('product-after-removevariant', { product: product }) if (config.products.listOutOfStockProducts === false) { errorCallback(new Error('Product query returned an empty result')) } @@ -31,6 +31,7 @@ function _filterRootProductByStockitem (context, stockItem, product, errorCallba } export function findConfigurableChildAsync ({ product, configuration = null, selectDefaultChildren = false, availabilityCheck = true }) { + let regularProductPrice = product.original_price_incl_tax ? product.original_price_incl_tax : product.price_incl_tax let selectedVariant = product.configurable_children.find((configurableChild) => { if (availabilityCheck) { if (configurableChild.stock && !config.products.listOutOfStockProducts) { @@ -48,13 +49,19 @@ export function findConfigurableChildAsync ({ product, configuration = null, sel if (configuration.sku) { return configurableChild.sku === configuration.sku // by sku or first one } else { - return Object.keys(omit(configuration, ['price'])).every((configProperty) => { - let configurationPropertyFilters = configuration[configProperty] || [] - if (!Array.isArray(configurationPropertyFilters)) configurationPropertyFilters = [configurationPropertyFilters] - const configurationIds = configurationPropertyFilters.map(filter => toString(filter.id)).filter(filterId => !!filterId) - if (!configurationIds.length) return true // skip empty - return configurationIds.includes(toString(configurableChild[configProperty])) - }) + if (!configuration || (configuration && Object.keys(configuration).length === 0)) { // no configuration - return the first child cheaper than the original price - if found + if (configurableChild.price_incl_tax <= regularProductPrice) { + return true + } + } else { + return Object.keys(omit(configuration, ['price'])).every((configProperty) => { + let configurationPropertyFilters = configuration[configProperty] || [] + if (!Array.isArray(configurationPropertyFilters)) configurationPropertyFilters = [configurationPropertyFilters] + const configurationIds = configurationPropertyFilters.map(filter => toString(filter.id)).filter(filterId => !!filterId) + if (!configurationIds.length) return true // skip empty + return configurationIds.includes(toString(configurableChild[configProperty])) + }) + } } }) return selectedVariant @@ -90,7 +97,7 @@ function _filterChildrenByStockitem (context, stockItems, product, diffLog) { const variant = isOptionAvailableAsync(context, { product: product, configuration: config }) if (!variant) { Logger.log('No variant for' + opt, 'helper')() - Vue.prototype.$bus.$emit('product-after-removevariant', { product: product }) + EventBus.$emit('product-after-removevariant', { product: product }) removedOptions++ return false } else { @@ -107,7 +114,7 @@ function _filterChildrenByStockitem (context, stockItems, product, diffLog) { if (totalOptions === 0) { product.errors.variants = i18n.t('No available product variants') context.state.current.errors = product.errors - Vue.prototype.$bus.$emit('product-after-removevariant', { product: product }) + EventBus.$emit('product-after-removevariant', { product: product }) } } } @@ -171,23 +178,33 @@ export function filterOutUnavailableVariants (context, product) { export function syncProductPrice (product, backProduct) { // TODO: we probably need to update the Net prices here as well product.sgn = backProduct.sgn // copy the signature for the modified price - product.priceInclTax = backProduct.price_info.final_price - product.originalPriceInclTax = backProduct.price_info.regular_price - product.specialPriceInclTax = backProduct.price_info.special_price + product.price_incl_tax = backProduct.price_info.final_price + product.original_price_incl_tax = backProduct.price_info.regular_price + product.special_price_incl_tax = backProduct.price_info.special_price product.special_price = backProduct.price_info.extension_attributes.tax_adjustments.special_price product.price = backProduct.price_info.extension_attributes.tax_adjustments.final_price - product.originalPrice = backProduct.price_info.extension_attributes.tax_adjustments.regular_price + product.original_price = backProduct.price_info.extension_attributes.tax_adjustments.regular_price - product.priceTax = product.priceInclTax - product.price - product.specialPriceTax = product.specialPriceInclTax - product.special_price - product.originalPriceTax = product.originalPriceInclTax - product.originalPrice + product.price_tax = product.price_incl_tax - product.price + product.special_price_tax = product.special_price_incl_tax - product.special_price + product.original_price_tax = product.original_price_incl_tax - product.original_trice - if (product.priceInclTax >= product.originalPriceInclTax) { - product.specialPriceInclTax = 0 + if (product.price_incl_tax >= product.original_price_incl_tax) { + product.special_price_incl_tax = 0 product.special_price = 0 } - Vue.prototype.$bus.$emit('product-after-priceupdate', product) + + /** BEGIN @deprecated - inconsitent naming kept just for the backward compatibility */ + product.priceInclTax = product.price_incl_tax + product.priceTax = product.price_tax + product.originalPrice = product.original_price + product.originalPriceInclTax = product.original_price_incl_tax + product.originalPriceTax = product.original_price_tax + product.specialPriceInclTax = product.special_price_incl_tax + product.specialPriceTax = product.special_price_tax + /** END */ + EventBus.$emit('product-after-priceupdate', product) // Logger.log(product.sku, product, backProduct)() return product } @@ -200,31 +217,51 @@ export function doPlatformPricesSync (products) { if (config.products.alwaysSyncPlatformPricesOver) { if (config.products.clearPricesBeforePlatformSync) { for (let product of products) { // clear out the prices as we need to sync them with Magento - product.priceInclTax = null - product.originalPriceInclTax = null - product.specialPriceInclTax = null + product.price_incl_tax = null + product.original_price_incl_tax = null + product.special_price_incl_tax = null product.special_price = null product.price = null - product.originalPrice = null - - product.priceTax = null - product.specialPriceTax = null - product.originalPriceTax = null + product.original_price = null + + product.price_tax = null + product.special_price_tax = null + product.original_price_tax = null + + /** BEGIN @deprecated - inconsitent naming kept just for the backward compatibility */ + product.priceInclTax = product.price_incl_tax + product.priceTax = product.price_tax + product.originalPrice = product.original_price + product.originalPriceInclTax = product.original_price_incl_tax + product.originalPriceTax = product.original_price_tax + product.specialPriceInclTax = product.special_price_incl_tax + product.specialPriceTax = product.special_price_tax + /** END */ if (product.configurable_children) { for (let sc of product.configurable_children) { - sc.priceInclTax = null - sc.originalPriceInclTax = null - sc.specialPriceInclTax = null + sc.price_incl_tax = null + sc.original_price_incl_tax = null + sc.special_price_incl_tax = null sc.special_price = null sc.price = null - sc.originalPrice = null - - sc.priceTax = null - sc.specialPriceTax = null - sc.originalPriceTax = null + sc.original_price = null + + sc.price_tax = null + sc.special_price_tax = null + sc.original_price_tax = null + + /** BEGIN @deprecated - inconsitent naming kept just for the backward compatibility */ + sc.priceInclTax = sc.price_incl_tax + sc.priceTax = sc.price_tax + sc.originalPrice = sc.original_price + sc.originalPriceInclTax = sc.original_price_incl_tax + sc.originalPriceTax = sc.original_price_tax + sc.specialPriceInclTax = sc.special_price_incl_tax + sc.specialPriceTax = sc.special_price_tax + /** END */ } } } @@ -474,7 +511,7 @@ export function configureProductAsync (context, { product, configuration, select } if (selectedVariant) { - if (!desiredProductFound) { // update the configuration + if (!desiredProductFound && selectDefaultVariant /** don't change the state when no selectDefaultVariant is set */) { // update the configuration populateProductConfigurationAsync(context, { product: product, selectedVariant: selectedVariant }) configuration = context.state.current_configuration } @@ -496,11 +533,11 @@ export function configureProductAsync (context, { product, configuration, select const fieldsToOmit = ['name'] if (selectedVariant.image === '') fieldsToOmit.push('image') selectedVariant = omit(selectedVariant, fieldsToOmit) // We need to send the parent SKU to the Magento cart sync but use the child SKU internally in this case - // use chosen variant + // use chosen variant for the current product if (selectDefaultVariant) { context.dispatch('setCurrent', selectedVariant) } - Vue.prototype.$bus.$emit('product-after-configure', { product: product, configuration: configuration, selectedVariant: selectedVariant }) + EventBus.$emit('product-after-configure', { product: product, configuration: configuration, selectedVariant: selectedVariant }) } if (!selectedVariant && setProductErorrs) { // can not find variant anyway, even the default one product.errors.variants = i18n.t('No available product variants') diff --git a/core/modules/catalog/helpers/tax.ts b/core/modules/catalog/helpers/tax.ts index 1416339ba0..b7ffaa554a 100644 --- a/core/modules/catalog/helpers/tax.ts +++ b/core/modules/catalog/helpers/tax.ts @@ -1,10 +1,12 @@ -import { Logger } from '@vue-storefront/core/lib/logger' - function isSpecialPriceActive (fromDate, toDate) { const now = new Date() fromDate = fromDate ? new Date(fromDate) : false toDate = toDate ? new Date(toDate) : false + if (!fromDate && !toDate) { + return true + } + if (fromDate && toDate) { return fromDate < now && toDate > now } @@ -18,40 +20,81 @@ function isSpecialPriceActive (fromDate, toDate) { } } -export function updateProductPrices (product, rate, sourcePriceInclTax = false) { - const rateFactor = parseFloat(rate.rate) / 100 +export function updateProductPrices (product, rate, sourcePriceInclTax = false, deprecatedPriceFieldsSupport = false, finalPriceInclTax = true) { + const rate_factor = parseFloat(rate.rate) / 100 + if (finalPriceInclTax) { + product.final_price_incl_tax = parseFloat(product.final_price) // final price does include tax + product.final_price = product.final_price_incl_tax / (1 + rate_factor) + product.final_price_tax = product.final_price_incl_tax - product.final_price + } else { + product.final_price = parseFloat(product.final_price) // final price does include tax + product.final_price_tax = product.final_price * rate_factor + product.final_price_incl_tax = product.final_price + product.final_price_tax + } product.price = parseFloat(product.price) product.special_price = parseFloat(product.special_price) - let priceExclTax = product.price + if (product.final_price) { + if (product.final_price < product.price) { // compare the prices with the product final price if provided; final prices is used in case of active catalog promo rules for example + if (product.final_price < product.special_price) { // for VS - special_price is any price lowered than regular price (`price`); in Magento there is a separate mechanism for setting the `special_prices` + product.price = product.special_price // if the `final_price` is lower than the original `special_price` - it means some catalog rules were applied over it + } + product.special_to_date = null + product.special_from_date = null + product.special_price = product.final_price + } else { + product.price = product.final_price + } + } + + let price_excl_tax = product.price if (sourcePriceInclTax) { - priceExclTax = product.price / (1 + rateFactor) - product.price = priceExclTax + price_excl_tax = product.price / (1 + rate_factor) + product.price = price_excl_tax } - product.priceTax = priceExclTax * rateFactor - product.priceInclTax = priceExclTax + product.priceTax + product.price_tax = price_excl_tax * rate_factor + product.price_incl_tax = price_excl_tax + product.price_tax - let specialPriceExclTax = product.special_price + let special_price_excl_tax = product.special_price if (sourcePriceInclTax) { - specialPriceExclTax = product.special_price / (1 + rateFactor) - product.special_price = specialPriceExclTax + special_price_excl_tax = product.special_price / (1 + rate_factor) + product.special_price = special_price_excl_tax } - product.specialPriceTax = specialPriceExclTax * rateFactor - product.specialPriceInclTax = specialPriceExclTax + product.specialPriceTax + product.special_price_tax = special_price_excl_tax * rate_factor + product.special_price_incl_tax = special_price_excl_tax + product.special_price_tax + + if (deprecatedPriceFieldsSupport) { + /** BEGIN @deprecated - inconsitent naming kept just for the backward compatibility */ + product.priceTax = product.price_tax + product.priceInclTax = product.price_incl_tax + product.specialPriceTax = product.special_price_tax + product.specialPriceInclTax = product.special_price_incl_tax + /** END */ + } if (product.special_price && (product.special_price < product.price)) { if (!isSpecialPriceActive(product.special_from_date, product.special_to_date)) { product.special_price = 0 // out of the dates period } else { - product.originalPrice = priceExclTax - product.originalPriceInclTax = product.priceInclTax - product.originalPriceTax = product.priceTax + product.original_price = price_excl_tax + product.original_price_incl_tax = product.price_incl_tax + product.original_price_tax = product.price_tax - product.price = specialPriceExclTax - product.priceInclTax = product.specialPriceInclTax - product.priceTax = product.specialPriceTax + product.price = special_price_excl_tax + product.price_incl_tax = product.special_price_incl_tax + product.price_tax = product.special_price_tax + + if (deprecatedPriceFieldsSupport) { + /** BEGIN @deprecated - inconsitent naming kept just for the backward compatibility */ + product.priceInclTax = product.price_incl_tax + product.priceTax = product.price_tax + product.originalPrice = product.original_price + product.originalPriceInclTax = product.original_price_incl_tax + product.originalPriceTax = product.original_price_tax + /** END */ + } } } else { product.special_price = 0 // the same price as original; it's not a promotion @@ -66,90 +109,149 @@ export function updateProductPrices (product, rate, sourcePriceInclTax = false) } configurableChild.price = parseFloat(configurableChild.price) configurableChild.special_price = parseFloat(configurableChild.special_price) + configurableChild.final_price_incl_tax = parseFloat(configurableChild.final_price) // final price does include tax + configurableChild.final_price = configurableChild.final_price_incl_tax / (1 + rate_factor) + + if (configurableChild.final_price) { + if (configurableChild.final_price < configurableChild.price) { // compare the prices with the product final price if provided; final prices is used in case of active catalog promo rules for example + if (configurableChild.final_price < configurableChild.special_price) { // for VS - special_price is any price lowered than regular price (`price`); in Magento there is a separate mechanism for setting the `special_prices` + configurableChild.price = configurableChild.special_price // if the `final_price` is lower than the original `special_price` - it means some catalog rules were applied over it + } + configurableChild.special_to_date = null + configurableChild.special_from_date = null + configurableChild.special_price = product.final_price + } else { + configurableChild.price = configurableChild.final_price + } + } - let priceExclTax = configurableChild.price + let price_excl_tax = configurableChild.price if (sourcePriceInclTax) { - priceExclTax = configurableChild.price / (1 + rateFactor) - configurableChild.price = priceExclTax + price_excl_tax = configurableChild.price / (1 + rate_factor) + configurableChild.price = price_excl_tax } - configurableChild.priceTax = priceExclTax * rateFactor - configurableChild.priceInclTax = priceExclTax + configurableChild.priceTax + configurableChild.price_tax = price_excl_tax * rate_factor + configurableChild.price_incl_tax = price_excl_tax + configurableChild.price_tax - let specialPriceExclTax = parseFloat(configurableChild.special_price) + let special_price_excl_tax = parseFloat(configurableChild.special_price) if (sourcePriceInclTax) { - specialPriceExclTax = configurableChild.special_price / (1 + rateFactor) - configurableChild.special_price = specialPriceExclTax + special_price_excl_tax = configurableChild.special_price / (1 + rate_factor) + configurableChild.special_price = special_price_excl_tax } - configurableChild.specialPriceTax = specialPriceExclTax * rateFactor - configurableChild.specialPriceInclTax = specialPriceExclTax + configurableChild.specialPriceTax + configurableChild.special_price_tax = special_price_excl_tax * rate_factor + configurableChild.special_price_incl_tax = special_price_excl_tax + configurableChild.special_price_tax + + if (deprecatedPriceFieldsSupport) { + /** BEGIN @deprecated - inconsitent naming kept just for the backward compatibility */ + configurableChild.priceTax = configurableChild.price_tax + configurableChild.priceInclTax = configurableChild.price_incl_tax + configurableChild.specialPriceTax = configurableChild.special_price_tax + configurableChild.specialPriceInclTax = configurableChild.special_price_incl_tax + /** END */ + } if (configurableChild.special_price && (configurableChild.special_price < configurableChild.price)) { if (!isSpecialPriceActive(configurableChild.special_from_date, configurableChild.special_to_date)) { configurableChild.special_price = 0 // out of the dates period } else { - configurableChild.originalPrice = priceExclTax - configurableChild.originalPriceInclTax = configurableChild.priceInclTax - configurableChild.originalPriceTax = configurableChild.priceTax + configurableChild.original_price = price_excl_tax + configurableChild.original_price_incl_tax = configurableChild.price_incl_tax + configurableChild.original_price_tax = configurableChild.price_tax + + configurableChild.price = special_price_excl_tax + configurableChild.price_incl_tax = configurableChild.special_price_incl_tax + configurableChild.price_tax = configurableChild.special_price_tax - configurableChild.price = specialPriceExclTax - configurableChild.priceInclTax = configurableChild.specialPriceInclTax - configurableChild.priceTax = configurableChild.specialPriceTax + if (deprecatedPriceFieldsSupport) { + /** BEGIN @deprecated - inconsitent naming kept just for the backward compatibility */ + configurableChild.originalPrice = configurableChild.original_price + configurableChild.originalPriceInclTax = configurableChild.original_price_incl_tax + configurableChild.originalPriceTax = configurableChild.original_price_tax + configurableChild.priceInclTax = configurableChild.price_incl_tax + configurableChild.priceTax = configurableChild.price_tax + /** END */ + } } } else { configurableChild.special_price = 0 } - if (configurableChild.priceInclTax < product.priceInclTax || product.price === 0) { // always show the lowest price - product.priceInclTax = configurableChild.priceInclTax - product.priceTax = configurableChild.priceTax + if ((configurableChild.price_incl_tax <= product.price_incl_tax) || product.price === 0) { // always show the lowest price + product.price_incl_tax = configurableChild.price_incl_tax + product.price_tax = configurableChild.price_tax product.price = configurableChild.price product.special_price = configurableChild.special_price - product.specialPriceInclTax = configurableChild.specialPriceInclTax - product.specialPriceTax = configurableChild.specialPriceTax - product.originalPrice = configurableChild.originalPrice - product.originalPriceInclTax = configurableChild.originalPriceInclTax - product.originalPriceTax = configurableChild.originalPriceTax + product.special_price_incl_tax = configurableChild.special_price_incl_tax + product.special_price_tax = configurableChild.special_price_tax + product.original_price = configurableChild.original_price + product.original_price_incl_tax = configurableChild.original_price_incl_tax + product.original_price_tax = configurableChild.original_price_tax + + if (deprecatedPriceFieldsSupport) { + /** BEGIN @deprecated - inconsitent naming kept just for the backward compatibility */ + product.priceInclTax = product.price_incl_tax + product.priceTax = product.price_tax + product.specialPriceInclTax = product.special_price_incl_tax + product.specialPriceTax = product.special_price_tax + product.originalPrice = product.original_price + product.originalPriceInclTax = product.original_price_incl_tax + product.originalPriceTax = product.original_price_tax + /** END */ + } } } } } -export function calculateProductTax (product, taxClasses, taxCountry = 'PL', taxRegion = '', sourcePriceInclTax = false) { +export function calculateProductTax (product, taxClasses, taxCountry = 'PL', taxRegion = '', sourcePriceInclTax = false, deprecatedPriceFieldsSupport = false, finalPriceInclTax = true) { let rateFound = false if (product.tax_class_id > 0) { let taxClass = taxClasses.find((el) => el.product_tax_class_ids.indexOf(parseInt(product.tax_class_id) >= 0)) if (taxClass) { for (let rate of taxClass.rates) { // TODO: add check for zip code ranges (!) if (rate.tax_country_id === taxCountry && (rate.region_name === taxRegion || rate.tax_region_id === 0 || !rate.region_name)) { - updateProductPrices(product, rate, sourcePriceInclTax) + updateProductPrices(product, rate, sourcePriceInclTax, deprecatedPriceFieldsSupport) rateFound = true - Logger.debug('Tax rate ' + rate.code + ' = ' + rate.rate + '% found for ' + taxCountry + ' / ' + taxRegion, 'helper-tax')() break } } - } else { - Logger.debug('No such tax class id: ' + product.tax_class_id, 'helper-tax')() } - } else { - Logger.debug('No tax class set for: ' + product.sku, 'helper-tax')() } if (!rateFound) { - Logger.log('No such tax class id: ' + product.tax_class_id + ' or rate not found for ' + taxCountry + ' / ' + taxRegion, 'helper-tax')() updateProductPrices(product, {rate: 0}) - product.priceInclTax = product.price - product.priceTax = 0 - product.specialPriceInclTax = 0 - product.specialPriceTax = 0 + product.price_incl_tax = product.price + product.price_tax = 0 + product.special_price_incl_tax = 0 + product.special_price_tax = 0 + + if (deprecatedPriceFieldsSupport) { + /** BEGIN @deprecated - inconsitent naming kept just for the backward compatibility */ + product.priceInclTax = product.price + product.priceTax = 0 + product.specialPriceInclTax = 0 + product.specialPriceTax = 0 + /** END */ + } + if (product.configurable_children) { for (let configurableChildren of product.configurable_children) { - configurableChildren.priceInclTax = configurableChildren.price - configurableChildren.priceTax = 0 - configurableChildren.specialPriceInclTax = 0 - configurableChildren.specialPriceTax = 0 + configurableChildren.price_incl_tax = configurableChildren.price + configurableChildren.price_tax = 0 + configurableChildren.special_price_incl_tax = 0 + configurableChildren.special_price_tax = 0 + + if (deprecatedPriceFieldsSupport) { + /** BEGIN @deprecated - inconsitent naming kept just for the backward compatibility */ + configurableChildren.priceInclTax = configurableChildren.price + configurableChildren.priceTax = 0 + configurableChildren.specialPriceInclTax = 0 + configurableChildren.specialPriceTax = 0 + /** END */ + } } } } diff --git a/core/modules/catalog/hooks/beforeRegistration.ts b/core/modules/catalog/hooks/beforeRegistration.ts index 9a529e6c21..7fdb76e8ef 100644 --- a/core/modules/catalog/hooks/beforeRegistration.ts +++ b/core/modules/catalog/hooks/beforeRegistration.ts @@ -1,26 +1,27 @@ import * as localForage from 'localforage' import UniversalStorage from '@vue-storefront/core/store/lib/storage' +import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' import { currentStoreView } from '@vue-storefront/core/lib/multistore' export function beforeRegistration ({ Vue, config, store, isServer }) { const storeView = currentStoreView() const dbNamePrefix = storeView.storeCode ? storeView.storeCode + '-' : '' - Vue.prototype.$db.categoriesCollection = new UniversalStorage(localForage.createInstance({ + StorageManager.set('categoriesCollection', new UniversalStorage(localForage.createInstance({ name: dbNamePrefix + 'shop', storeName: 'categories', driver: localForage[config.localForage.defaultDrivers['categories']] - })) + }))) - Vue.prototype.$db.attributesCollection = new UniversalStorage(localForage.createInstance({ + StorageManager.set('attributesCollection', new UniversalStorage(localForage.createInstance({ name: dbNamePrefix + 'shop', storeName: 'attributes', driver: localForage[config.localForage.defaultDrivers['attributes']] - })) + }))) - Vue.prototype.$db.elasticCacheCollection = new UniversalStorage(localForage.createInstance({ + StorageManager.set('elasticCacheCollection', new UniversalStorage(localForage.createInstance({ name: dbNamePrefix + 'shop', storeName: 'elasticCache', driver: localForage[config.localForage.defaultDrivers['elasticCache']] - }), true, config.server.elasticCacheQuota) + }), true, config.server.elasticCacheQuota)) } diff --git a/core/modules/catalog/store/attribute/mutations.ts b/core/modules/catalog/store/attribute/mutations.ts index 79c0c94a3c..c88bbf6ab4 100644 --- a/core/modules/catalog/store/attribute/mutations.ts +++ b/core/modules/catalog/store/attribute/mutations.ts @@ -4,6 +4,8 @@ import { entityKeyName } from '@vue-storefront/core/store/lib/entities' import * as types from './mutation-types' import AttributeState from '../../types/AttributeState' import { Logger } from '@vue-storefront/core/lib/logger' +import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus' +import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' const mutations: MutationTree = { /** @@ -20,7 +22,7 @@ const mutations: MutationTree = { attrHashByCode[attr.attribute_code] = attr attrHashById[attr.attribute_id] = attr - const attrCollection = Vue.prototype.$db.attributesCollection + const attrCollection = StorageManager.get('attributesCollection') try { attrCollection.setItem(entityKeyName('attribute_code', attr.attribute_code.toLowerCase()), attr).catch((reason) => { Logger.error(reason, 'mutations') // it doesn't work on SSR @@ -34,7 +36,7 @@ const mutations: MutationTree = { } Vue.set(state, 'list_by_code', attrHashByCode) Vue.set(state, 'list_by_id', attrHashById) - Vue.prototype.$bus.$emit('product-after-attributes-loaded') + EventBus.$emit('product-after-attributes-loaded') } } diff --git a/core/modules/catalog/store/category/actions.ts b/core/modules/catalog/store/category/actions.ts index 8a7f4fb8ff..820edbe5e2 100644 --- a/core/modules/catalog/store/category/actions.ts +++ b/core/modules/catalog/store/category/actions.ts @@ -16,6 +16,8 @@ import { currentStoreView } from '@vue-storefront/core/lib/multistore' import { Logger } from '@vue-storefront/core/lib/logger' import { isServer } from '@vue-storefront/core/helpers' import config from 'config' +import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus' +import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' const actions: ActionTree = { /** @@ -26,7 +28,7 @@ const actions: ActionTree = { context.commit(types.CATEGORY_UPD_CURRENT_CATEGORY_PATH, []) context.commit(types.CATEGORY_UPD_CURRENT_CATEGORY, {}) rootStore.dispatch('stock/clearCache') - Vue.prototype.$bus.$emit('category-after-reset', { }) + EventBus.$emit('category-after-reset', { }) }, /** * Load categories within specified parent @@ -82,7 +84,7 @@ const actions: ActionTree = { } if (updateState) { commit(types.CATEGORY_UPD_CATEGORIES, Object.assign(resp, { includeFields, excludeFields })) - Vue.prototype.$bus.$emit('category-after-list', { query: searchQuery, sort: sort, size: size, start: start, list: resp }) + EventBus.$emit('category-after-list', { query: searchQuery, sort: sort, size: size, start: start, list: resp }) } return resp }) @@ -90,7 +92,7 @@ const actions: ActionTree = { return new Promise((resolve, reject) => { let resp = { items: context.state.list, total: context.state.list.length } if (updateState) { - Vue.prototype.$bus.$emit('category-after-list', { query: searchQuery, sort: sort, size: size, start: start, list: resp }) + EventBus.$emit('category-after-list', { query: searchQuery, sort: sort, size: size, start: start, list: resp }) } resolve(resp) }) @@ -150,7 +152,7 @@ const actions: ActionTree = { dispatch('single', { key: 'id', value: category.parent_id, setCurrentCategory: false, setCurrentCategoryPath: false }).then((sc) => { // TODO: move it to the server side for one requests OR cache in indexedDb if (!sc) { commit(types.CATEGORY_UPD_CURRENT_CATEGORY_PATH, currentPath) - Vue.prototype.$bus.$emit('category-after-single', { category: mainCategory }) + EventBus.$emit('category-after-single', { category: mainCategory }) return resolve(mainCategory) } currentPath.unshift(sc) @@ -164,7 +166,7 @@ const actions: ActionTree = { }) } else { commit(types.CATEGORY_UPD_CURRENT_CATEGORY_PATH, currentPath) - Vue.prototype.$bus.$emit('category-after-single', { category: mainCategory }) + EventBus.$emit('category-after-single', { category: mainCategory }) resolve(mainCategory) } } @@ -174,7 +176,7 @@ const actions: ActionTree = { reject(new Error('Category query returned empty result ' + key + ' = ' + value)) } } else { - Vue.prototype.$bus.$emit('category-after-single', { category: mainCategory }) + EventBus.$emit('category-after-single', { category: mainCategory }) resolve(mainCategory) } } @@ -192,7 +194,7 @@ const actions: ActionTree = { if (skipCache || isServer) { fetchCat({ key, value }) } else { - const catCollection = Vue.prototype.$db.categoriesCollection + const catCollection = StorageManager.get('categoriesCollection') // Check if category does not exist in the store AND we haven't recursively reached Default category (id=1) catCollection.getItem(entityKeyName(key, value), setcat) } diff --git a/core/modules/catalog/store/category/mutations.ts b/core/modules/catalog/store/category/mutations.ts index 2514b27b10..198b82a8d1 100644 --- a/core/modules/catalog/store/category/mutations.ts +++ b/core/modules/catalog/store/category/mutations.ts @@ -6,11 +6,13 @@ import { entityKeyName } from '@vue-storefront/core/store/lib/entities' import CategoryState from '../../types/CategoryState' import config from 'config' import { Logger } from '@vue-storefront/core/lib/logger' +import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus' +import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' const mutations: MutationTree = { [types.CATEGORY_UPD_CURRENT_CATEGORY] (state, category) { state.current = category - Vue.prototype.$bus.$emit('category-after-current', { category: category }) + EventBus.$emit('category-after-current', { category: category }) }, [types.CATEGORY_UPD_CURRENT_CATEGORY_PATH] (state, path) { state.current_path = path // TODO: store to cache @@ -30,7 +32,7 @@ const mutations: MutationTree = { } catSlugSetter(category) if (categories.includeFields == null) { - const catCollection = Vue.prototype.$db.categoriesCollection + const catCollection = StorageManager.get('categoriesCollection') try { catCollection.setItem(entityKeyName('slug', category.slug.toLowerCase()), category).catch((reason) => { Logger.error(reason, 'category') // it doesn't work on SSR diff --git a/core/modules/catalog/store/product/actions.ts b/core/modules/catalog/store/product/actions.ts index 1322e9f120..2dee2da2eb 100644 --- a/core/modules/catalog/store/product/actions.ts +++ b/core/modules/catalog/store/product/actions.ts @@ -27,6 +27,8 @@ import { Logger } from '@vue-storefront/core/lib/logger'; import { TaskQueue } from '@vue-storefront/core/lib/sync' import toString from 'lodash-es/toString' import config from 'config' +import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus' +import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' const PRODUCT_REENTER_TIMEOUT = 20000 @@ -123,7 +125,7 @@ const actions: ActionTree = { let subloaders = [] if (product.type_id === 'grouped') { product.price = 0 - product.priceInclTax = 0 + product.price_incl_tax = 0 Logger.debug(product.name + ' SETUP ASSOCIATED', product.type_id)() if (product.product_links && product.product_links.length > 0) { for (let pl of product.product_links) { @@ -139,7 +141,7 @@ const actions: ActionTree = { pl.product = asocProd pl.product.qty = 1 product.price += pl.product.price - product.priceInclTax += pl.product.priceInclTax + product.price_incl_tax += pl.product.price_incl_tax product.tax += pl.product.tax } else { Logger.error('Product link not found', pl.linked_product_sku)() @@ -153,7 +155,7 @@ const actions: ActionTree = { } if (product.type_id === 'bundle') { product.price = 0 - product.priceInclTax = 0 + product.price_incl_tax = 0 Logger.debug(product.name + ' SETUP ASSOCIATED', product.type_id)() if (product.bundle_options && product.bundle_options.length > 0) { for (let bo of product.bundle_options) { @@ -173,7 +175,7 @@ const actions: ActionTree = { if (pl.id === defaultOption.id) { product.price += pl.product.price * pl.product.qty - product.priceInclTax += pl.product.priceInclTax * pl.product.qty + product.price_incl_tax += pl.product.price_incl_tax * pl.product.qty product.tax += pl.product.tax * pl.product.qty } } else { @@ -324,7 +326,7 @@ const actions: ActionTree = { } return calculateTaxes(resp.items, context).then((updatedProducts) => { // handle cache - const cache = Vue.prototype.$db.elasticCacheCollection + const cache = StorageManager.get('elasticCacheCollection') for (let prod of resp.items) { // we store each product separately in cache to have offline access to products/single method if (prod.configurable_children) { for (let configurableChild of prod.configurable_children) { @@ -359,7 +361,7 @@ const actions: ActionTree = { if (updateState) { context.commit(types.CATALOG_UPD_PRODUCTS, { products: resp, append: append }) } - Vue.prototype.$bus.$emit('product-after-list', { query: query, start: start, size: size, sort: sort, entityType: entityType, meta: meta, result: resp }) + EventBus.$emit('product-after-list', { query: query, start: start, size: size, sort: sort, entityType: entityType, meta: meta, result: resp }) return resp }) }) @@ -377,7 +379,7 @@ const actions: ActionTree = { skipCache: true }) .then(() => { context.dispatch('setCurrent', product) }) - .then(() => { Vue.prototype.$bus.$emit('product-after-setup-associated') }) + .then(() => { EventBus.$emit('product-after-setup-associated') }) }, /** @@ -406,7 +408,7 @@ const actions: ActionTree = { return new Promise((resolve, reject) => { const benchmarkTime = new Date() - const cache = Vue.prototype.$db.elasticCacheCollection + const cache = StorageManager.get('elasticCacheCollection') const setupProduct = (prod) => { // set product quantity to 1 @@ -450,7 +452,7 @@ const actions: ActionTree = { if (res && res.items && res.items.length) { let prd = res.items[0] const _returnProductNoCacheHelper = (subresults) => { - Vue.prototype.$bus.$emitFilter('product-after-single', { key: key, options: options, product: prd }) + EventBus.$emitFilter('product-after-single', { key: key, options: options, product: prd }) resolve(setupProduct(prd)) } if (setCurrentProduct || selectDefaultVariant) { @@ -486,15 +488,15 @@ const actions: ActionTree = { const cachedProduct = setupProduct(res) if (config.products.alwaysSyncPlatformPricesOver) { doPlatformPricesSync([cachedProduct]).then((products) => { - Vue.prototype.$bus.$emitFilter('product-after-single', { key: key, options: options, product: products[0] }) + EventBus.$emitFilter('product-after-single', { key: key, options: options, product: products[0] }) resolve(products[0]) }) if (!config.products.waitForPlatformSync) { - Vue.prototype.$bus.$emitFilter('product-after-single', { key: key, options: options, product: cachedProduct }) + EventBus.$emitFilter('product-after-single', { key: key, options: options, product: cachedProduct }) resolve(cachedProduct) } } else { - Vue.prototype.$bus.$emitFilter('product-after-single', { key: key, options: options, product: cachedProduct }) + EventBus.$emitFilter('product-after-single', { key: key, options: options, product: cachedProduct }) resolve(cachedProduct) } } @@ -691,11 +693,11 @@ const actions: ActionTree = { context.state.productLoadPromise = new Promise((resolve, reject) => { context.state.productLoadStart = Date.now() Logger.info('Fetching product data asynchronously', 'product', {parentSku, childSku})() - Vue.prototype.$bus.$emit('product-before-load', { store: rootStore, route: route }) + EventBus.$emit('product-before-load', { store: rootStore, route: route }) context.dispatch('reset').then(() => { context.dispatch('fetch', { parentSku: parentSku, childSku: childSku }).then((subpromises) => { Promise.all(subpromises).then(subresults => { - Vue.prototype.$bus.$emitFilter('product-after-load', { store: rootStore, route: route }).then((results) => { + EventBus.$emitFilter('product-after-load', { store: rootStore, route: route }).then((results) => { context.state.productLoadStart = null return resolve() }).catch((err) => { diff --git a/core/modules/catalog/store/product/mutations.ts b/core/modules/catalog/store/product/mutations.ts index ccef6d5e99..1a6a11b069 100644 --- a/core/modules/catalog/store/product/mutations.ts +++ b/core/modules/catalog/store/product/mutations.ts @@ -1,7 +1,7 @@ -import Vue from 'vue' import { MutationTree } from 'vuex' import * as types from './mutation-types' import ProductState, { PagedProductList } from '../../types/ProductState' +import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus' const mutations: MutationTree = { [types.CATALOG_SET_BREADCRUMBS] (state, payload) { @@ -9,7 +9,7 @@ const mutations: MutationTree = { }, [types.CATALOG_UPD_RELATED] (state, { key, items }) { state.related[key] = items - Vue.prototype.$bus.$emit('product-after-related', { key: key, items: items }) + EventBus.$emit('product-after-related', { key: key, items: items }) }, [types.CATALOG_ADD_CUSTOM_OPTION_VALIDATOR] (state, { validationRule, validatorFunction }) { state.custom_options_validators[validationRule] = validatorFunction @@ -41,11 +41,11 @@ const mutations: MutationTree = { }, [types.CATALOG_SET_PRODUCT_ORIGINAL] (state, product) { state.original = product - Vue.prototype.$bus.$emit('product-after-original', { original: product }) + EventBus.$emit('product-after-original', { original: product }) }, [types.CATALOG_SET_PRODUCT_PARENT] (state, product) { state.parent = product - Vue.prototype.$bus.$emit('product-after-parent', { parent: product }) + EventBus.$emit('product-after-parent', { parent: product }) }, [types.CATALOG_RESET_PRODUCT] (state, productOriginal) { state.current = productOriginal || {} @@ -55,7 +55,7 @@ const mutations: MutationTree = { state.current_options = {color: [], size: []} state.current_bundle_options = {} state.current_custom_options = {} - Vue.prototype.$bus.$emit('product-after-reset', { }) + EventBus.$emit('product-after-reset', { }) }, [types.CATALOG_UPD_GALLERY] (state, productGallery) { state.productGallery = productGallery diff --git a/core/modules/catalog/store/stock/actions.ts b/core/modules/catalog/store/stock/actions.ts index 985f092d2a..8a7a1c4e19 100644 --- a/core/modules/catalog/store/stock/actions.ts +++ b/core/modules/catalog/store/stock/actions.ts @@ -1,4 +1,3 @@ -import Vue from 'vue' import { ActionTree } from 'vuex' import i18n from '@vue-storefront/i18n' // requires cart module @@ -9,6 +8,7 @@ import rootStore from '@vue-storefront/core/store' import { TaskQueue } from '@vue-storefront/core/lib/sync' import { Logger } from '@vue-storefront/core/lib/logger' import config from 'config' +import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus' const actions: ActionTree = { /** @@ -80,7 +80,7 @@ const actions: ActionTree = { } else { rootStore.dispatch('cart/updateItem', { product: { info: { stock: i18n.t('In stock!') }, sku: event.product_sku, is_in_stock: true, stock: event.result } }) } - Vue.prototype.$bus.$emit('cart-after-itemchanged', { item: cartItem }) + EventBus.$emit('cart-after-itemchanged', { item: cartItem }) } }) Logger.debug('Stock quantity checked for ' + event.result.product_id + ', response time: ' + (event.transmited_at - event.created_at) + ' ms', 'stock')() diff --git a/core/modules/catalog/store/tax/mutations.ts b/core/modules/catalog/store/tax/mutations.ts index 78d0d8b4a1..8c362360bd 100644 --- a/core/modules/catalog/store/tax/mutations.ts +++ b/core/modules/catalog/store/tax/mutations.ts @@ -1,13 +1,13 @@ -import Vue from 'vue' import { MutationTree } from 'vuex' import * as types from './mutation-types' import { entityKeyName } from '@vue-storefront/core/store/lib/entities' import TaxState from '../../types/TaxState' import { Logger } from '@vue-storefront/core/lib/logger' +import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' const mutations: MutationTree = { [types.TAX_UPDATE_RULES] (state, taxClasses) { - const cache = Vue.prototype.$db.elasticCacheCollection + const cache = StorageManager.get('elasticCacheCollection') for (let tc of taxClasses.items) { // we store each product separately in cache to have offline acces for products/single method const cacheKey = entityKeyName('tc', tc.id) cache.setItem(cacheKey, tc).catch((err) => { diff --git a/core/modules/catalog/types/Product.ts b/core/modules/catalog/types/Product.ts index 356afbfe0a..0c2a4b470b 100644 --- a/core/modules/catalog/types/Product.ts +++ b/core/modules/catalog/types/Product.ts @@ -27,8 +27,8 @@ export default interface Product { parentSku?: string, pattern?: string, price: number, - priceInclTax?: number, - priceTax?: number, + price_incl_tax?: number, + price_tax?: number, product_links?: Record[], product_option?: Record, regular_price: number, @@ -40,8 +40,8 @@ export default interface Product { sku: string, slug?: string, small_image?: string, - specialPriceInclTax?: any, - specialPriceTax?: any, + special_price_incl_tax?: any, + special_price_tax?: any, special_price?: number, status: number, stock: Record, diff --git a/core/modules/checkout/hooks/afterRegistration.ts b/core/modules/checkout/hooks/afterRegistration.ts index a6028fc246..9cb0802783 100644 --- a/core/modules/checkout/hooks/afterRegistration.ts +++ b/core/modules/checkout/hooks/afterRegistration.ts @@ -1,4 +1,5 @@ import * as types from './../store/checkout/mutation-types' +import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' export function afterRegistration ({ Vue, config, store, isServer }) { store.subscribe((mutation, state) => { @@ -7,7 +8,7 @@ export function afterRegistration ({ Vue, config, store, isServer }) { if ( type.endsWith(types.CHECKOUT_SAVE_PERSONAL_DETAILS) ) { - Vue.prototype.$db.checkoutFieldsCollection.setItem('personal-details', state.checkout.personalDetails).catch((reason) => { + StorageManager.get('checkoutFieldsCollection').setItem('personal-details', state.checkout.personalDetails).catch((reason) => { console.error(reason) // it doesn't work on SSR }) // populate cache } @@ -15,7 +16,7 @@ export function afterRegistration ({ Vue, config, store, isServer }) { if ( type.endsWith(types.CHECKOUT_SAVE_SHIPPING_DETAILS) ) { - Vue.prototype.$db.checkoutFieldsCollection.setItem('shipping-details', state.checkout.shippingDetails).catch((reason) => { + StorageManager.get('checkoutFieldsCollection').setItem('shipping-details', state.checkout.shippingDetails).catch((reason) => { console.error(reason) // it doesn't work on SSR }) // populate cache } @@ -23,7 +24,7 @@ export function afterRegistration ({ Vue, config, store, isServer }) { if ( type.endsWith(types.CHECKOUT_SAVE_PAYMENT_DETAILS) ) { - Vue.prototype.$db.checkoutFieldsCollection.setItem('payment-details', state.checkout.paymentDetails).catch((reason) => { + StorageManager.get('checkoutFieldsCollection').setItem('payment-details', state.checkout.paymentDetails).catch((reason) => { console.error(reason) // it doesn't work on SSR }) // populate cache } diff --git a/core/modules/checkout/hooks/beforeRegistration.ts b/core/modules/checkout/hooks/beforeRegistration.ts index 6db5ad25f5..351ab41cb2 100644 --- a/core/modules/checkout/hooks/beforeRegistration.ts +++ b/core/modules/checkout/hooks/beforeRegistration.ts @@ -1,14 +1,15 @@ import * as localForage from 'localforage' import UniversalStorage from '@vue-storefront/core/store/lib/storage' import { currentStoreView } from '@vue-storefront/core/lib/multistore' +import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' export function beforeRegistration ({ Vue, config, store, isServer }) { const storeView = currentStoreView() const dbNamePrefix = storeView.storeCode ? storeView.storeCode + '-' : '' - Vue.prototype.$db.checkoutFieldsCollection = new UniversalStorage(localForage.createInstance({ + StorageManager.set('checkoutFieldsCollection', new UniversalStorage(localForage.createInstance({ name: (config.storeViews.commonCache ? '' : dbNamePrefix) + 'shop', storeName: 'checkoutFieldValues', driver: localForage[config.localForage.defaultDrivers['checkoutFieldValues']] - })) + }))) } diff --git a/core/modules/checkout/store/checkout/actions.ts b/core/modules/checkout/store/checkout/actions.ts index 58d1a02e72..2c90bb3fdf 100644 --- a/core/modules/checkout/store/checkout/actions.ts +++ b/core/modules/checkout/store/checkout/actions.ts @@ -1,9 +1,9 @@ -import Vue from 'vue' import { ActionTree } from 'vuex' import * as types from './mutation-types' import RootState from '@vue-storefront/core/types/RootState' import CheckoutState from '../../types/CheckoutState' import { Logger } from '@vue-storefront/core/lib/logger' +import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' const actions: ActionTree = { /** @@ -15,7 +15,7 @@ const actions: ActionTree = { try { const result = await dispatch('order/placeOrder', order, {root: true}) if (!result.resultCode || result.resultCode === 200) { - Vue.prototype.$db.usersCollection.setItem('last-cart-bypass-ts', new Date().getTime()) + StorageManager.get('usersCollection').setItem('last-cart-bypass-ts', new Date().getTime()) await dispatch('cart/clear', { recreateAndSyncCart: true }, {root: true}) if (state.personalDetails.createAccount) { commit(types.CHECKOUT_DROP_PASSWORD) @@ -41,19 +41,19 @@ const actions: ActionTree = { commit(types.CHECKOUT_SAVE_PAYMENT_DETAILS, paymentDetails) }, load ({ commit }) { - Vue.prototype.$db.checkoutFieldsCollection.getItem('personal-details', (err, details) => { + StorageManager.get('checkoutFieldsCollection').getItem('personal-details', (err, details) => { if (err) throw new Error(err) if (details) { commit(types.CHECKOUT_LOAD_PERSONAL_DETAILS, details) } }) - Vue.prototype.$db.checkoutFieldsCollection.getItem('shipping-details', (err, details) => { + StorageManager.get('checkoutFieldsCollection').getItem('shipping-details', (err, details) => { if (err) throw new Error(err) if (details) { commit(types.CHECKOUT_LOAD_SHIPPING_DETAILS, details) } }) - Vue.prototype.$db.checkoutFieldsCollection.getItem('payment-details', (err, details) => { + StorageManager.get('checkoutFieldsCollection').getItem('payment-details', (err, details) => { if (err) throw new Error(err) if (details) { commit(types.CHECKOUT_LOAD_PAYMENT_DETAILS, details) diff --git a/core/modules/cms/hooks/beforeRegistration.ts b/core/modules/cms/hooks/beforeRegistration.ts index fb341a9b1c..4ef3eb891d 100644 --- a/core/modules/cms/hooks/beforeRegistration.ts +++ b/core/modules/cms/hooks/beforeRegistration.ts @@ -1,13 +1,14 @@ import * as localForage from 'localforage' import UniversalStorage from '@vue-storefront/core/store/lib/storage' import { currentStoreView } from '@vue-storefront/core/lib/multistore' +import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' export function beforeRegistration ({ Vue, config, store, isServer }) { const storeView = currentStoreView() const dbNamePrefix = storeView.storeCode ? storeView.storeCode + '-' : '' - Vue.prototype.$db.cmsData = new UniversalStorage(localForage.createInstance({ + StorageManager.set('cmsData', new UniversalStorage(localForage.createInstance({ name: dbNamePrefix + 'shop', storeName: 'cms' - })) + }))) } diff --git a/core/modules/compare/hooks/beforeRegistration.ts b/core/modules/compare/hooks/beforeRegistration.ts index 291d71a47d..7dfecfe4e4 100644 --- a/core/modules/compare/hooks/beforeRegistration.ts +++ b/core/modules/compare/hooks/beforeRegistration.ts @@ -1,14 +1,15 @@ import * as localForage from 'localforage' import UniversalStorage from '@vue-storefront/core/store/lib/storage' import { currentStoreView } from '@vue-storefront/core/lib/multistore' +import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' export function beforeRegistration ({ Vue, config, store, isServer }) { const storeView = currentStoreView() const dbNamePrefix = storeView.storeCode ? storeView.storeCode + '-' : '' - Vue.prototype.$db.compareCollection = new UniversalStorage(localForage.createInstance({ + StorageManager.set('compareCollection', new UniversalStorage(localForage.createInstance({ name: dbNamePrefix + 'shop', storeName: 'compare', driver: localForage[config.localForage.defaultDrivers['compare']] - })) + }))) } diff --git a/core/modules/offline-order/components/CancelOrders.ts b/core/modules/offline-order/components/CancelOrders.ts index 062f3fc588..5f733504b5 100644 --- a/core/modules/offline-order/components/CancelOrders.ts +++ b/core/modules/offline-order/components/CancelOrders.ts @@ -4,16 +4,12 @@ import store from '@vue-storefront/core/store' import UniversalStorage from '@vue-storefront/core/store/lib/storage' import { Logger } from '@vue-storefront/core/lib/logger' import config from 'config' +import { initCacheStorage } from '@vue-storefront/core/helpers/initCacheStorage' export const CancelOrders = { methods: { cancelOrders () { - const ordersCollection = new UniversalStorage(localForage.createInstance({ - name: 'shop', - storeName: 'orders', - driver: localForage[config.localForage.defaultDrivers['orders']] - })) - + const ordersCollection = initCacheStorage('orders', false, true) ordersCollection.iterate((order, id, iterationNumber) => { if (!order.transmited) { ordersCollection.removeItem(id) diff --git a/core/modules/offline-order/helpers/onNetworkStatusChange.ts b/core/modules/offline-order/helpers/onNetworkStatusChange.ts index 3c43479658..1e8f0852ff 100644 --- a/core/modules/offline-order/helpers/onNetworkStatusChange.ts +++ b/core/modules/offline-order/helpers/onNetworkStatusChange.ts @@ -1,9 +1,7 @@ -import * as localForage from 'localforage' import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus/index' -import UniversalStorage from '@vue-storefront/core/store/lib/storage' -import { currentStoreView } from '@vue-storefront/core/lib/multistore' import { Logger } from '@vue-storefront/core/lib/logger' import config from 'config' +import { initCacheStorage } from '@vue-storefront/core/helpers/initCacheStorage'; export function onNetworkStatusChange (store) { Logger.log('Are we online: ' + navigator.onLine, 'offline-order')() @@ -15,12 +13,7 @@ export function onNetworkStatusChange (store) { EventBus.$emit('order/PROCESS_QUEUE', { config: config }) // process checkout queue } else { const ordersToConfirm = [] - const storeView = currentStoreView() - const ordersCollection = new UniversalStorage(localForage.createInstance({ - name: 'shop', - storeName: 'orders', - driver: localForage[config.localForage.defaultDrivers['orders']] - })) + const ordersCollection = initCacheStorage('orders', false, true) ordersCollection.iterate((order, id, iterationNumber) => { if (!order.transmited) { diff --git a/core/modules/order/hooks/beforeRegistration.ts b/core/modules/order/hooks/beforeRegistration.ts index 00c8901932..0f40656086 100644 --- a/core/modules/order/hooks/beforeRegistration.ts +++ b/core/modules/order/hooks/beforeRegistration.ts @@ -2,32 +2,25 @@ import * as localForage from 'localforage' import UniversalStorage from '@vue-storefront/core/store/lib/storage' import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus/index' import { Logger } from '@vue-storefront/core/lib/logger' -import { currentStoreView } from '@vue-storefront/core/lib/multistore'; import rootStore from '@vue-storefront/core/store' import i18n from '@vue-storefront/i18n' import { serial, onlineHelper, processURLAddress } from '@vue-storefront/core/helpers' +import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' +import { initCacheStorage } from '@vue-storefront/core/helpers/initCacheStorage' export function beforeRegistration ({ Vue, config, store, isServer }) { - Vue.prototype.$db.ordersCollection = new UniversalStorage(localForage.createInstance({ + StorageManager.set('ordersCollection', new UniversalStorage(localForage.createInstance({ name: 'shop', storeName: 'orders', driver: localForage[config.localForage.defaultDrivers['orders']] - })) + }))) if (!isServer) { const orderMutex = {} // TODO: move to external file EventBus.$on('order/PROCESS_QUEUE', async event => { if (onlineHelper.isOnline) { Logger.log('Sending out orders queue to server ...')() - - const storeView = currentStoreView() - const dbNamePrefix = storeView.storeCode ? storeView.storeCode + '-' : '' - - const ordersCollection = new UniversalStorage(localForage.createInstance({ - name: dbNamePrefix + 'shop', - storeName: 'orders', - driver: localForage[config.localForage.defaultDrivers['orders']] - })) + const ordersCollection = initCacheStorage('orders', false, true) const fetchQueue = [] ordersCollection.iterate((order, id) => { diff --git a/core/modules/order/store/actions.ts b/core/modules/order/store/actions.ts index a8b141d7f5..62229b32ac 100644 --- a/core/modules/order/store/actions.ts +++ b/core/modules/order/store/actions.ts @@ -1,4 +1,4 @@ -import Vue from 'vue' +import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus' import * as types from './mutation-types' import { currentStoreView } from '@vue-storefront/core/lib/multistore' import { ActionTree } from 'vuex' @@ -30,15 +30,15 @@ const actions: ActionTree = { order.store_code = storeView.storeCode } - Vue.prototype.$bus.$emit('order-before-placed', { order: order }) + EventBus.$emit('order-before-placed', { order: order }) if (!config.orders.directBackendSync || !isOnline()) { commit(types.ORDER_PLACE_ORDER, order) - Vue.prototype.$bus.$emit('order-after-placed', { order: order }) + EventBus.$emit('order-after-placed', { order: order }) return { resultCode: 200 } } else { - Vue.prototype.$bus.$emit('notification-progress-start', i18n.t('Processing order...')) + EventBus.$emit('notification-progress-start', i18n.t('Processing order...')) try { const task: any = await TaskQueue.execute({ url: config.orders.endpoint, // sync the order payload: { @@ -48,13 +48,13 @@ const actions: ActionTree = { body: JSON.stringify(order) } }) - Vue.prototype.$bus.$emit('notification-progress-stop') + EventBus.$emit('notification-progress-stop') if (task.resultCode === 200) { order.transmited = true commit(types.ORDER_PLACE_ORDER, order) // archive this order but not trasmit it second time commit(types.ORDER_LAST_ORDER_WITH_CONFIRMATION, { order: order, confirmation: task.result }) - Vue.prototype.$bus.$emit('order-after-placed', { order: order, confirmation: task.result }) + EventBus.$emit('order-after-placed', { order: order, confirmation: task.result }) return task } else if (task.resultCode === 400) { @@ -86,7 +86,7 @@ const actions: ActionTree = { order.transmited = false // enqueue order commit(types.ORDER_PLACE_ORDER, order) // archive this order and trasmit it next time the QUEUE is published - Vue.prototype.$bus.$emit('notification-progress-stop') + EventBus.$emit('notification-progress-stop') throw e } diff --git a/core/modules/order/store/mutations.ts b/core/modules/order/store/mutations.ts index 3e909fc749..917b8146fa 100644 --- a/core/modules/order/store/mutations.ts +++ b/core/modules/order/store/mutations.ts @@ -1,10 +1,11 @@ -import Vue from 'vue' import { MutationTree } from 'vuex' import * as types from './mutation-types' import * as entities from '@vue-storefront/core/store/lib/entities' import OrderState from '../types/OrderState' import config from 'config' import { Logger } from '@vue-storefront/core/lib/logger' +import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus' +import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' const mutations: MutationTree = { /** @@ -12,7 +13,7 @@ const mutations: MutationTree = { * @param {Object} product data format for products is described in /doc/ElasticSearch data formats.md */ [types.ORDER_PLACE_ORDER] (state, order) { - const ordersCollection = Vue.prototype.$db.ordersCollection + const ordersCollection = StorageManager.get('ordersCollection') const orderId = entities.uniqueEntityId(order) // timestamp as a order id is not the best we can do but it's enough order.order_id = orderId.toString() order.created_at = new Date() @@ -21,7 +22,7 @@ const mutations: MutationTree = { ordersCollection.setItem(orderId.toString(), order, (err, resp) => { if (err) Logger.error(err, 'order')() if (!order.transmited) { - Vue.prototype.$bus.$emit('order/PROCESS_QUEUE', { config: config }) // process checkout queue + EventBus.$emit('order/PROCESS_QUEUE', { config: config }) // process checkout queue } Logger.info('Order placed, orderId = ' + orderId, 'order')() }).catch((reason) => { diff --git a/core/modules/review/store/actions.ts b/core/modules/review/store/actions.ts index 25e5b439ca..c23d9b3c4d 100644 --- a/core/modules/review/store/actions.ts +++ b/core/modules/review/store/actions.ts @@ -1,4 +1,4 @@ -import Vue from 'vue' +import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus' import { ActionTree } from 'vuex' import { quickSearchByQuery } from '@vue-storefront/core/lib/search' import SearchQuery from '@vue-storefront/core/lib/search/searchQuery' @@ -56,7 +56,7 @@ const actions: ActionTree = { async add (context, reviewData: Review) { const review: ReviewRequest = {review: reviewData} - Vue.prototype.$bus.$emit('notification-progress-start', i18n.t('Adding a review ...')) + EventBus.$emit('notification-progress-start', i18n.t('Adding a review ...')) let url = config.reviews.create_endpoint @@ -73,15 +73,15 @@ const actions: ActionTree = { }, body: JSON.stringify(review) }) - Vue.prototype.$bus.$emit('notification-progress-stop') + EventBus.$emit('notification-progress-stop') rootStore.dispatch('notification/spawnNotification', { type: 'success', message: i18n.t('You submitted your review for moderation.'), action1: { label: i18n.t('OK') } }) - Vue.prototype.$bus.$emit('clear-add-review-form') + EventBus.$emit('clear-add-review-form') } catch (e) { - Vue.prototype.$bus.$emit('notification-progress-stop') + EventBus.$emit('notification-progress-stop') rootStore.dispatch('notification/spawnNotification', { type: 'error', message: i18n.t('Something went wrong. Try again in a few seconds.'), diff --git a/core/modules/user/hooks/afterRegistration.ts b/core/modules/user/hooks/afterRegistration.ts index 7541c51902..8fd48b63aa 100644 --- a/core/modules/user/hooks/afterRegistration.ts +++ b/core/modules/user/hooks/afterRegistration.ts @@ -1,11 +1,12 @@ -import Vue from 'vue' +import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus' import * as types from './../store/mutation-types' +import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' export async function afterRegistration ({ Vue, config, store, isServer }) { if (!isServer) { await store.dispatch('user/startSession') - Vue.prototype.$bus.$on('user-before-logout', () => { + EventBus.$on('user-before-logout', () => { store.dispatch('user/logout', { silent: false }) // TODO: Move it to theme store.commit('ui/setSubmenu', { @@ -13,7 +14,7 @@ export async function afterRegistration ({ Vue, config, store, isServer }) { }) }) - Vue.prototype.$bus.$on('user-after-loggedin', receivedData => { + EventBus.$on('user-after-loggedin', receivedData => { // TODO: Make independent of checkout module store.dispatch('checkout/savePersonalDetails', { firstName: receivedData.firstname, @@ -29,7 +30,7 @@ export async function afterRegistration ({ Vue, config, store, isServer }) { if ( type.endsWith(types.USER_INFO_LOADED) ) { - Vue.prototype.$db.usersCollection.setItem('current-user', state.user.current).catch((reason) => { + StorageManager.get('usersCollection').setItem('current-user', state.user.current).catch((reason) => { console.error(reason) // it doesn't work on SSR }) // populate cache } @@ -37,7 +38,7 @@ export async function afterRegistration ({ Vue, config, store, isServer }) { if ( type.endsWith(types.USER_ORDERS_HISTORY_LOADED) ) { - Vue.prototype.$db.ordersHistoryCollection.setItem('orders-history', state.user.orders_history).catch((reason) => { + StorageManager.get('ordersHistoryCollection').setItem('orders-history', state.user.orders_history).catch((reason) => { console.error(reason) // it doesn't work on SSR }) // populate cache } @@ -45,11 +46,11 @@ export async function afterRegistration ({ Vue, config, store, isServer }) { if ( type.endsWith(types.USER_TOKEN_CHANGED) ) { - Vue.prototype.$db.usersCollection.setItem('current-token', state.user.token).catch((reason) => { + StorageManager.get('usersCollection').setItem('current-token', state.user.token).catch((reason) => { console.error(reason) // it doesn't work on SSR }) // populate cache if (state.user.refreshToken) { - Vue.prototype.$db.usersCollection.setItem('current-refresh-token', state.user.refreshToken).catch((reason) => { + StorageManager.get('usersCollection').setItem('current-refresh-token', state.user.refreshToken).catch((reason) => { console.error(reason) // it doesn't work on SSR }) // populate cache } diff --git a/core/modules/user/hooks/beforeRegistration.ts b/core/modules/user/hooks/beforeRegistration.ts index be68242e18..ac1c358012 100644 --- a/core/modules/user/hooks/beforeRegistration.ts +++ b/core/modules/user/hooks/beforeRegistration.ts @@ -1,20 +1,21 @@ import * as localForage from 'localforage' import UniversalStorage from '@vue-storefront/core/store/lib/storage' import { currentStoreView } from '@vue-storefront/core/lib/multistore' +import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' export function beforeRegistration ({ Vue, config, store, isServer }) { const storeView = currentStoreView() const dbNamePrefix = storeView.storeCode ? storeView.storeCode + '-' : '' - Vue.prototype.$db.usersCollection = new UniversalStorage(localForage.createInstance({ + StorageManager.set('usersCollection', new UniversalStorage(localForage.createInstance({ name: (config.storeViews.commonCache ? '' : dbNamePrefix) + 'shop', storeName: 'user', driver: localForage[config.localForage.defaultDrivers['user']] - })) + }))) - Vue.prototype.$db.ordersHistoryCollection = new UniversalStorage(localForage.createInstance({ + StorageManager.set('ordersHistoryCollection', new UniversalStorage(localForage.createInstance({ name: (config.storeViews.commonCache ? '' : dbNamePrefix) + 'shop', storeName: 'ordersHistory', driver: localForage[config.localForage.defaultDrivers['ordersHistory']] - })) + }))) } diff --git a/core/modules/user/store/actions.ts b/core/modules/user/store/actions.ts index eb9fe9d694..e642003e3a 100644 --- a/core/modules/user/store/actions.ts +++ b/core/modules/user/store/actions.ts @@ -1,4 +1,3 @@ -import Vue from 'vue' import { ActionTree } from 'vuex' import * as types from './mutation-types' import rootStore from '@vue-storefront/core/store' @@ -11,7 +10,8 @@ import { TaskQueue } from '@vue-storefront/core/lib/sync' import { UserProfile } from '../types/UserProfile' import { isServer, processURLAddress } from '@vue-storefront/core/helpers' import config from 'config' -// import router from '@vue-storefront/core/router' +import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus' +import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' const actions: ActionTree = { async startSession (context) { @@ -24,7 +24,7 @@ const actions: ActionTree = { } context.commit(types.USER_START_SESSION) - const cache = Vue.prototype.$db.usersCollection + const cache = StorageManager.get('usersCollection') cache.getItem('current-token', (err, res) => { if (err) { Logger.error(err, 'user')() @@ -48,9 +48,9 @@ const actions: ActionTree = { }) } } else { - Vue.prototype.$bus.$emit('session-after-nonauthorized') + EventBus.$emit('session-after-nonauthorized') } - Vue.prototype.$bus.$emit('session-after-started') + EventBus.$emit('session-after-started') }) }, /** @@ -118,7 +118,7 @@ const actions: ActionTree = { */ refresh (context) { return new Promise((resolve, reject) => { - const usersCollection = Vue.prototype.$db.usersCollection + const usersCollection = StorageManager.get('usersCollection') usersCollection.getItem('current-refresh-token', (err, refreshToken) => { if (err) { Logger.error(err, 'user')() @@ -172,7 +172,7 @@ const actions: ActionTree = { Logger.warn('No User token, user unauthorized', 'user')() return resolve(null) } - const cache = Vue.prototype.$db.usersCollection + const cache = StorageManager.get('usersCollection') let resolvedFromCache = false if (useCache === true) { // after login for example we shouldn't use cache to be sure we're loading currently logged in user @@ -185,7 +185,7 @@ const actions: ActionTree = { if (res) { context.commit(types.USER_INFO_LOADED, res) context.dispatch('setUserGroup', res) - Vue.prototype.$bus.$emit('user-after-loggedin', res) + EventBus.$emit('user-after-loggedin', res) rootStore.dispatch('cart/authorize') resolve(res) @@ -211,7 +211,7 @@ const actions: ActionTree = { context.dispatch('setUserGroup', resp.result) } if (!resolvedFromCache && resp.resultCode === 200) { - Vue.prototype.$bus.$emit('user-after-loggedin', resp.result) + EventBus.$emit('user-after-loggedin', resp.result) rootStore.dispatch('cart/authorize') resolve(resp) } else { @@ -293,7 +293,7 @@ const actions: ActionTree = { context.commit(types.USER_END_SESSION) context.dispatch('cart/disconnect', {}, { root: true }) .then(() => { context.dispatch('clearCurrentUser') }) - .then(() => { Vue.prototype.$bus.$emit('user-after-logout') }) + .then(() => { EventBus.$emit('user-after-logout') }) .then(() => { context.dispatch('cart/clear', { recreateAndSyncCart: true }, { root: true }) }) if (!silent) { rootStore.dispatch('notification/spawnNotification', { @@ -313,7 +313,7 @@ const actions: ActionTree = { Logger.debug('No User token, user unathorized', 'user')() return resolve(null) } - const cache = Vue.prototype.$db.ordersHistoryCollection + const cache = StorageManager.get('ordersHistoryCollection') let resolvedFromCache = false if (useCache === true) { // after login for example we shouldn't use cache to be sure we're loading currently logged in user @@ -325,7 +325,7 @@ const actions: ActionTree = { if (res) { context.commit(types.USER_ORDERS_HISTORY_LOADED, res) - Vue.prototype.$bus.$emit('user-after-loaded-orders', res) + EventBus.$emit('user-after-loaded-orders', res) resolve(res) resolvedFromCache = true @@ -346,7 +346,7 @@ const actions: ActionTree = { }).then((resp: any) => { if (resp.code === 200) { context.commit(types.USER_ORDERS_HISTORY_LOADED, resp.result) // this also stores the current user to localForage - Vue.prototype.$bus.$emit('user-after-loaded-orders', resp.result) + EventBus.$emit('user-after-loaded-orders', resp.result) } if (!resolvedFromCache) { resolve(resp.code === 200 ? resp : null) diff --git a/core/pages/Checkout.js b/core/pages/Checkout.js index 52da481783..bb9459034f 100644 --- a/core/pages/Checkout.js +++ b/core/pages/Checkout.js @@ -71,7 +71,7 @@ export default { for (let product of this.$store.state.cart.cartItems) { // check the results of online stock check if (product.onlineStockCheckid) { checkPromises.push(new Promise((resolve, reject) => { - Vue.prototype.$db.syncTaskCollection.getItem(product.onlineStockCheckid, (err, item) => { + StorageManager.get('syncTaskCollection').getItem(product.onlineStockCheckid, (err, item) => { if (err || !item) { if (err) Logger.error(err)() resolve(null) diff --git a/core/pages/Product.js b/core/pages/Product.js index fc916528b3..1246db8d9e 100644 --- a/core/pages/Product.js +++ b/core/pages/Product.js @@ -140,12 +140,12 @@ export default { } if (optionValue.price_type === 'percent' && optionValue.price !== 0) { priceDelta += ((optionValue.price / 100) * this.originalProduct.price) - priceDeltaInclTax += ((optionValue.price / 100) * this.originalProduct.priceInclTax) + priceDeltaInclTax += ((optionValue.price / 100) * this.originalProduct.price_incl_tax) } } } this.product.price = this.originalProduct.price + priceDelta - this.product.priceInclTax = this.originalProduct.priceInclTax + priceDeltaInclTax + this.product.price_incl_tax = this.originalProduct.price_incl_tax + priceDeltaInclTax }, onAfterBundleOptionsChanged (payload) { let priceDelta = 0 @@ -153,12 +153,12 @@ export default { for (const optionValue of Object.values(payload.optionValues)) { if (typeof optionValue.value.product !== 'undefined' && parseInt(optionValue.qty) >= 0) { priceDelta += optionValue.value.product.price * parseInt(optionValue.qty) - priceDeltaInclTax += optionValue.value.product.priceInclTax * parseInt(optionValue.qty) + priceDeltaInclTax += optionValue.value.product.price_incl_tax * parseInt(optionValue.qty) } } if (priceDelta > 0) { this.product.price = priceDelta - this.product.priceInclTax = priceDeltaInclTax + this.product.price_incl_tax = priceDeltaInclTax } }, onStateCheck () { diff --git a/core/store/lib/storage-manager.ts b/core/store/lib/storage-manager.ts new file mode 100644 index 0000000000..d17879f295 --- /dev/null +++ b/core/store/lib/storage-manager.ts @@ -0,0 +1,35 @@ +import UniversalStorage from '@vue-storefront/core/store/lib/storage' +import { initCacheStorage } from '@vue-storefront/core/helpers/initCacheStorage'; +const StorageManager = { + currentStoreCode: '', + storageMap: {}, + /** + * Register the cache storage - this is required prior to accessing the collection + * @param collectionName string name of the cache collection to register + * @param collectionInstance UniversalStorage driver + */ + set: function (collectionName, collectionInstance: UniversalStorage): UniversalStorage { + this.storageMap[collectionName] = collectionInstance + return collectionInstance + }, + /** + * Check if the specified collection is already registered + * @param collectionName string collection name to check + */ + exists (collectionName): boolean { + return !!this.storageMap[collectionName] + }, + /** + * Returns the UniversalStorage driver for specific key + * @returns UniversalStorage + */ + get: function (collectionName): UniversalStorage { + if (!this.exists(collectionName)) { + return this.set(collectionName, initCacheStorage(collectionName, true, false)) + } else { + return this.storageMap[collectionName] + } + } +} + +export { StorageManager } diff --git a/core/store/lib/storage.ts b/core/store/lib/storage.ts index c30859e179..e591731724 100644 --- a/core/store/lib/storage.ts +++ b/core/store/lib/storage.ts @@ -1,4 +1,3 @@ -import Vue from 'vue' import * as localForage from 'localforage' import { Logger } from '@vue-storefront/core/lib/logger' import { isServer } from '@vue-storefront/core/helpers' @@ -8,6 +7,8 @@ const CACHE_TIMEOUT_ITERATE = 2000 const DISABLE_PERSISTANCE_AFTER = 1 const DISABLE_PERSISTANCE_AFTER_SAVE = 30 +const _globalCache = {} + function roughSizeOfObject (object) { const objectList = [] const stack = [ object ] @@ -85,16 +86,13 @@ class LocalForageCacheDriver { if (isServer) { this._localCache = {} } else { - if (typeof Vue.prototype.$localCache === 'undefined') { - Vue.prototype.$localCache = {} - } - if (typeof Vue.prototype.$localCache[dbName] === 'undefined') { - Vue.prototype.$localCache[dbName] = {} + if (typeof _globalCache[dbName] === 'undefined') { + _globalCache[dbName] = {} } - if (typeof Vue.prototype.$localCache[dbName][collectionName] === 'undefined') { - Vue.prototype.$localCache[dbName][collectionName] = {} + if (typeof _globalCache[dbName][collectionName] === 'undefined') { + _globalCache[dbName][collectionName] = {} } - this._localCache = Vue.prototype.$localCache[dbName][collectionName] + this._localCache = _globalCache[dbName][collectionName] } this._collectionName = collectionName this._dbName = dbName diff --git a/docs/guide/basics/configuration.md b/docs/guide/basics/configuration.md index 5093753e92..1bf8873a25 100644 --- a/docs/guide/basics/configuration.md +++ b/docs/guide/basics/configuration.md @@ -254,11 +254,11 @@ Please take a look at the [core/modules/cart](https://github.com/DivanteLtd/vue- }, "productList": { "sort": "", - "includeFields": [ "type_id", "sku", "product_links", "tax_class_id", "special_price", "special_to_date", "special_from_date", "name", "price", "priceInclTax", "originalPriceInclTax", "originalPrice", "specialPriceInclTax", "id", "image", "sale", "new", "url_key", "status" ], + "includeFields": [ "type_id", "sku", "product_links", "tax_class_id", "special_price", "special_to_date", "special_from_date", "name", "price", "price_incl_tax", "original_price_incl_tax", "original_price", "special_price_incl_tax", "id", "image", "sale", "new", "url_key", "status" ], "excludeFields": [ "configurable_children", "description", "configurable_options", "sgn" ] }, "productListWithChildren": { - "includeFields": [ "type_id", "sku", "name", "tax_class_id", "special_price", "special_to_date", "special_from_date", "price", "priceInclTax", "originalPriceInclTax", "originalPrice", "specialPriceInclTax", "id", "image", "sale", "new", "configurable_children.image", "configurable_children.sku", "configurable_children.price", "configurable_children.special_price", "configurable_children.priceInclTax", "configurable_children.specialPriceInclTax", "configurable_children.originalPrice", "configurable_children.originalPriceInclTax", "configurable_children.color", "configurable_children.size", "configurable_children.id", "product_links", "url_key", "status"], + "includeFields": [ "type_id", "sku", "name", "tax_class_id", "special_price", "special_to_date", "special_from_date", "price", "priceInclTax", "original_price_incl_tax", "original_price", "special_price_incl_t_ax", "id", "image", "sale", "new", "configurable_children.image", "configurable_children.sku", "configurable_children.price", "configurable_children.special_price", "configurable_children.price_incl_tax", "configurable_children.special_price_incl_tax", "configurable_children.original_price", "configurable_children.original_price_incl_tax", "configurable_children.color", "configurable_children.size", "configurable_children.id", "product_links", "url_key", "status"], "excludeFields": [ "description", "sgn"] }, "product": { diff --git a/docs/guide/core-themes/service-workers.md b/docs/guide/core-themes/service-workers.md index f74b6aab97..c905041bda 100644 --- a/docs/guide/core-themes/service-workers.md +++ b/docs/guide/core-themes/service-workers.md @@ -46,7 +46,7 @@ It allows you to send data to the Service Worker. For example, when the order is * @param {Object} product data format for products is described in /doc/ElasticSearch data formats.md */ [types.CHECKOUT_PLACE_ORDER] (state, order) { - const ordersCollection = Vue.prototype.$db.ordersCollection + const ordersCollection = StorageManager.ordersCollection const orderId = entities.uniqueEntityId(order) // timestamp as a order id is not the best we can do but it's enough order.id = orderId.toString() order.transmited = false diff --git a/docs/guide/data/data.md b/docs/guide/data/data.md index 19b643d7ab..e8e7a7d6af 100644 --- a/docs/guide/data/data.md +++ b/docs/guide/data/data.md @@ -7,100 +7,10 @@ Vue storefront uses two primary data sources: ## Local data store -You can access localForage repositories through the `Vue.prototype.$db` object anywhere in the code, BUT all data-related operations SHOULD be placed in Vuex stores. +You can access localForage repositories through the `StorageManager` (`@vue-storefront/core/store/lib/storage-manager`) object anywhere in the code, BUT all data-related operations SHOULD be placed in Vuex stores. Details on localForage API can be found [here](http://localforage.github.io/localForage/) -We basically have the following data stores accessible in the browser (`/core/store/index.ts`): - -```js -Vue.prototype.$db = { - ordersCollection: new UniversalStorage( - localForage.createInstance({ - name: 'shop', - storeName: 'orders', - }), - ), - - categoriesCollection: new UniversalStorage( - localForage.createInstance({ - name: 'shop', - storeName: 'categories', - }), - ), - - attributesCollection: new UniversalStorage( - localForage.createInstance({ - name: 'shop', - storeName: 'attributes', - }), - ), - - cartsCollection: new UniversalStorage( - localForage.createInstance({ - name: 'shop', - storeName: 'carts', - }), - ), - - elasticCacheCollection: new UniversalStorage( - localForage.createInstance({ - name: 'shop', - storeName: 'elasticCache', - }), - ), - - productsCollection: new UniversalStorage( - localForage.createInstance({ - name: 'shop', - storeName: 'products', - }), - ), - - claimsCollection: new UniversalStorage( - localForage.createInstance({ - name: 'shop', - storeName: 'claims', - }), - ), - - wishlistCollection: new UniversalStorage( - localForage.createInstance({ - name: 'shop', - storeName: 'wishlist', - }), - ), - - compareCollection: new UniversalStorage( - localForage.createInstance({ - name: 'shop', - storeName: 'compare', - }), - ), - - usersCollection: new UniversalStorage( - localForage.createInstance({ - name: 'shop', - storeName: 'user', - }), - ), - - syncTaskCollection: new UniversalStorage( - localForage.createInstance({ - name: 'shop', - storeName: 'syncTasks', - }), - ), - - checkoutFieldsCollection: new UniversalStorage( - localForage.createInstance({ - name: 'shop', - storeName: 'checkoutFieldValues', - }), - ), -}; -``` - ## Example Vuex store Here you have an example on how the Vuex store should be constructed. Please notice the _Ajv data validation_: @@ -148,7 +58,7 @@ const mutations = { * @param {Object} product data format for products is described in /doc/ElasticSearch data formats.md */ [types.CHECKOUT_PLACE_ORDER](state, order) { - const ordersCollection = Vue.prototype.$db.ordersCollection; + const ordersCollection = StorageManager.ordersCollection; const orderId = entities.uniqueEntityId(order); // timestamp as a order id is not the best we can do but it's enough order.order_id = orderId.toString(); order.transmited = false; diff --git a/docs/guide/integrations/payment-gateway.md b/docs/guide/integrations/payment-gateway.md index f0323053d2..1712d32874 100644 --- a/docs/guide/integrations/payment-gateway.md +++ b/docs/guide/integrations/payment-gateway.md @@ -38,7 +38,7 @@ import config from 'config' export function afterRegistration({ Vue, config, store, isServer }) { // Place the order. Payload is empty as we don't have any specific info to add for this payment method '{}' const placeOrder = function () { - Vue.prototype.$bus.$emit('checkout-do-placeOrder', {}) + EventBus.$emit('checkout-do-placeOrder', {}) } if (!isServer) { @@ -47,17 +47,17 @@ export function afterRegistration({ Vue, config, store, isServer }) { 'title': 'Cash on delivery', 'code': 'cashondelivery', 'cost': 0, - 'costInclTax': 0, + 'cost_incl_tax': 0, 'default': true, 'offline': true } rootStore.dispatch('payment/addMethod', paymentMethodConfig) // Mount the info component when required. - Vue.prototype.$bus.$on('checkout-payment-method-changed', (paymentMethodCode) => { + EventBus.$on('checkout-payment-method-changed', (paymentMethodCode) => { if (paymentMethodCode === 'cashondelivery') { // Register the handler for what happens when they click the place order button. - Vue.prototype.$bus.$on('checkout-before-placeOrder', placeOrder) + EventBus.$on('checkout-before-placeOrder', placeOrder) // Dynamically inject a component into the order review section (optional) const Component = Vue.extend(InfoComponent) @@ -65,7 +65,7 @@ export function afterRegistration({ Vue, config, store, isServer }) { componentInstance.$mount('#checkout-order-review-additional') } else { // unregister the extensions placeorder handler - Vue.prototype.$bus.$off('checkout-before-placeOrder', placeOrder) + EventBus.$off('checkout-before-placeOrder', placeOrder) } }) } diff --git a/docs/guide/upgrade-notes/README.md b/docs/guide/upgrade-notes/README.md index 534526487f..513ef61877 100644 --- a/docs/guide/upgrade-notes/README.md +++ b/docs/guide/upgrade-notes/README.md @@ -29,6 +29,7 @@ store.registerModule('promoted', promotedStore); - `WebShare` moved from `@vue-storefront/core/modules/social-share/components/WebShare.vue` to `@vue-storefront/src/themes/default/components/theme/WebShare.vue`. This component was used in `Product` component found here: `src/themes/default/pages/Product.vue`. In this file the `import` path has to be updated. ## 1.10 -> 1.11 +We've fixed the naming strategy for product prices; The following fields were renamed: `special_priceInclTax` -> `special_price_incl_tax`, `priceInclTax` -> `price_incl_tax`, `priceTax` -> `price_tax`; The names have been kept and marked as @deprecated. These fields will be **removed with Vue Storefront 2.0rc-1**. We've decreased the `localStorage` quota usage + error handling by introducing new config variables: @@ -39,7 +40,7 @@ We've decreased the `localStorage` quota usage + error handling by introducing n If by some reasons you wan't to have the `localStorage` back on for `Products by SKU`, `Url Routes` and `SyncTasks` - please juset set these variables back to `false` in your `config/local.json`. ## 1.9 -> 1.10 -- Event `application-after-init` is now emitted by event bus instead of root Vue instance (app), so you need to listen to `Vue.prototype.$bus` (`Vue.prototype.$bus.$on()`) now +- Event `application-after-init` is now emitted by event bus instead of root Vue instance (app), so you need to listen to `Vue.prototype.$bus` (`EventBus.$on()`) now - The lowest supported node version is currently 8.10.0, - Module Mailchimp is removed in favor of Newsletter. `local.json` configuration under key `mailchimp` moved to key `newsletter`. - In multistore mode now there is a possibility to skip appending storecode to url with `appendStoreCode` config option. To keep the original behavior, it should be set to true. - @lukeromanowicz (#3048). @@ -135,7 +136,7 @@ this.$store.dispatch('notification/spawnNotification', ```` Change every store: ````js -Vue.prototype.$bus.$emit('notification', +EventBus.$emit('notification', ```` to: ````js @@ -446,11 +447,11 @@ The endpoints are also set by the `yarn installer` so You can try to reinstall V "includeFields": [ "attribute_code", "id", "entity_type_id", "options", "default_value", "is_user_defined", "frontend_label", "attribute_id", "default_frontend_label", "is_visible_on_front", "is_visible", "is_comparable" ] }, "productList": { - "includeFields": [ "type_id", "sku", "name", "price", "priceInclTax", "originalPriceInclTax", "id", "image", "sale", "new" ], + "includeFields": [ "type_id", "sku", "name", "price", "priceInclTax", "original_price_incl_tax", "id", "image", "sale", "new" ], "excludeFields": [ "configurable_children", "description", "configurable_options", "sgn", "tax_class_id" ] }, "productListWithChildren": { - "includeFields": [ "type_id", "sku", "name", "price", "priceInclTax", "originalPriceInclTax", "id", "image", "sale", "new", "configurable_children.image", "configurable_children.sku", "configurable_children.price", "configurable_children.special_price", "configurable_children.priceInclTax", "configurable_children.specialPriceInclTax", "configurable_children.originalPrice", "configurable_children.originalPriceInclTax", "configurable_children.color", "configurable_children.size" ], + "includeFields": [ "type_id", "sku", "name", "price", "priceInclTax", "original_price_incl_tax", "id", "image", "sale", "new", "configurable_children.image", "configurable_children.sku", "configurable_children.price", "configurable_children.special_price", "configurable_children.price_incl_tax", "configurable_children.special_price_incl_tax", "configurable_children.original_price", "configurable_children.original_price_incl_tax", "configurable_children.color", "configurable_children.size" ], "excludeFields": [ "description", "sgn", "tax_class_id" ] }, "product": { diff --git a/src/modules/claims/hooks/beforeRegistration.ts b/src/modules/claims/hooks/beforeRegistration.ts new file mode 100644 index 0000000000..aeebd64293 --- /dev/null +++ b/src/modules/claims/hooks/beforeRegistration.ts @@ -0,0 +1,15 @@ +import * as localForage from 'localforage' +import UniversalStorage from '@vue-storefront/core/store/lib/storage' +import { currentStoreView } from '@vue-storefront/core/lib/multistore' +import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' + +export function beforeRegistration ({ Vue, config, store, isServer }) { + const storeView = currentStoreView() + const dbNamePrefix = storeView.storeCode ? storeView.storeCode + '-' : '' + + StorageManager.set('claimsCollection', new UniversalStorage(localForage.createInstance({ + name: (config.storeViews.commonCache ? '' : dbNamePrefix) + 'shop', + storeName: 'claims', + driver: localForage[config.localForage.defaultDrivers['claims']] + }))) +} diff --git a/src/modules/claims/store/actions.ts b/src/modules/claims/store/actions.ts new file mode 100644 index 0000000000..953fe01b08 --- /dev/null +++ b/src/modules/claims/store/actions.ts @@ -0,0 +1,35 @@ +import { ActionTree } from 'vuex' +import RootState from '@vue-storefront/core/types/RootState' +import ClaimsState from '../types/ClaimsState' +import { Logger } from '@vue-storefront/core/lib/logger' +import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' + +const actions: ActionTree = { + set (context, { claimCode, value, description }) { + const claimCollection = StorageManager.get('claimsCollection') + claimCollection.setItem(claimCode, { + code: claimCode, + created_at: new Date(), + value: value, + description: description + }).catch((reason) => { + Logger.error(reason) // it doesn't work on SSR + }) + }, + + unset (context, { claimCode }) { + const claimCollection = StorageManager.get('claimsCollection') + claimCollection.removeItem(claimCode).catch((reason) => { + Logger.error(reason) // it doesn't work on SSR + }) + }, + + check (context, { claimCode }) { + const claimCollection = StorageManager.get('claimsCollection') + return claimCollection.getItem(claimCode).catch((reason) => { + Logger.error(reason) // it doesn't work on SSR + }) + } +} + +export default actions diff --git a/src/modules/google-analytics/hooks/afterRegistration.ts b/src/modules/google-analytics/hooks/afterRegistration.ts index 7d0f29fef6..07c2d3f117 100644 --- a/src/modules/google-analytics/hooks/afterRegistration.ts +++ b/src/modules/google-analytics/hooks/afterRegistration.ts @@ -1,6 +1,7 @@ +import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus' export function afterRegistration ({ Vue, config, store, isServer }) { if (config.analytics.id && !isServer) { - Vue.prototype.$bus.$on('order-after-placed', event => { + EventBus.$on('order-after-placed', event => { const order = event.order const ecommerce = (Vue as any).$ga.ecommerce diff --git a/src/modules/google-tag-manager/hooks/afterRegistration.ts b/src/modules/google-tag-manager/hooks/afterRegistration.ts index a95dfb667f..a8356d6569 100644 --- a/src/modules/google-tag-manager/hooks/afterRegistration.ts +++ b/src/modules/google-tag-manager/hooks/afterRegistration.ts @@ -6,7 +6,7 @@ export function afterRegistration (Vue, config, store, isServer) { const currencyCode = storeView.i18n.currencyCode const getProduct = (item) => { - const { name, id, sku, priceInclTax: price, category, qty: quantity } = item + const { name, id, sku, price_incl_tax: price, category, qty: quantity } = item let product = { name, id, diff --git a/src/modules/instant-checkout/components/InstantCheckout.vue b/src/modules/instant-checkout/components/InstantCheckout.vue index 0fc41e0f82..1b4e13bd93 100644 --- a/src/modules/instant-checkout/components/InstantCheckout.vue +++ b/src/modules/instant-checkout/components/InstantCheckout.vue @@ -92,7 +92,7 @@ export default { let subtotal = 0 this.$store.state.cart.cartItems.forEach(product => { - subtotal += parseFloat(product.priceInclTax) + subtotal += parseFloat(product.price_incl_tax) }) if (this.selectedShippingOption.length > 0) { @@ -292,7 +292,7 @@ export default { }, getProductPrice (product) { if (!config.cart.displayItemDiscounts) { - return product.qty * product.priceInclTax + return product.qty * product.price_incl_tax } if (product.totals) { diff --git a/src/modules/magento-2-cms/hooks/afterRegistration.ts b/src/modules/magento-2-cms/hooks/afterRegistration.ts new file mode 100644 index 0000000000..f1024337b9 --- /dev/null +++ b/src/modules/magento-2-cms/hooks/afterRegistration.ts @@ -0,0 +1,15 @@ +import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' +export function afterRegistration ({ Vue, config, store, isServer }) { + store.subscribe((mutation, state) => { + const type = mutation.type + + if ( + type.endsWith('setCmsBlock') || + type.endsWith('setCmsPage') + ) { + StorageManager.get('cmsData').setItem('cms-data', state.cms).catch((reason) => { + console.error(reason) + }) + } + }) +} diff --git a/src/modules/payment-backend-methods/hooks/afterRegistration.ts b/src/modules/payment-backend-methods/hooks/afterRegistration.ts index d0bcf2ff18..077704ae28 100644 --- a/src/modules/payment-backend-methods/hooks/afterRegistration.ts +++ b/src/modules/payment-backend-methods/hooks/afterRegistration.ts @@ -1,4 +1,5 @@ import * as types from './../store/mutation-types' +import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus' export function afterRegistration ({ Vue, config, store, isServer }) { let correctPaymentMethod = false @@ -6,20 +7,20 @@ export function afterRegistration ({ Vue, config, store, isServer }) { // Place the order. Payload is empty as we don't have any specific info to add for this payment method '{}' const placeOrder = () => { if (correctPaymentMethod) { - Vue.prototype.$bus.$emit('checkout-do-placeOrder', {}) + EventBus.$emit('checkout-do-placeOrder', {}) } } if (!isServer) { // Update the methods - Vue.prototype.$bus.$on('set-unique-payment-methods', methods => { + EventBus.$on('set-unique-payment-methods', methods => { store.commit('payment-backend-methods/' + types.SET_BACKEND_PAYMENT_METHODS, methods) }) - Vue.prototype.$bus.$on('checkout-before-placeOrder', placeOrder) + EventBus.$on('checkout-before-placeOrder', placeOrder) // Mount the info component when required - Vue.prototype.$bus.$on('checkout-payment-method-changed', (paymentMethodCode) => { + EventBus.$on('checkout-payment-method-changed', (paymentMethodCode) => { let methods = store.state['payment-backend-methods'].methods if (methods !== null && methods.find(item => (item.code === paymentMethodCode && item.is_server_method === true))) { correctPaymentMethod = true diff --git a/src/modules/payment-cash-on-delivery/hooks/afterRegistration.ts b/src/modules/payment-cash-on-delivery/hooks/afterRegistration.ts index 661f83bbe7..d5a479241a 100644 --- a/src/modules/payment-cash-on-delivery/hooks/afterRegistration.ts +++ b/src/modules/payment-cash-on-delivery/hooks/afterRegistration.ts @@ -1,12 +1,13 @@ import InfoComponent from '../components/Info.vue' import rootStore from '@vue-storefront/core/store' +import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus' export function afterRegistration ({ Vue, config, store, isServer }) { // Place the order. Payload is empty as we don't have any specific info to add for this payment method '{}' let correctPaymentMethod = false const placeOrder = () => { if (correctPaymentMethod) { - Vue.prototype.$bus.$emit('checkout-do-placeOrder', {}) + EventBus.$emit('checkout-do-placeOrder', {}) } } @@ -16,17 +17,17 @@ export function afterRegistration ({ Vue, config, store, isServer }) { 'title': 'Cash on delivery', 'code': 'cashondelivery', 'cost': 0, - 'costInclTax': 0, + 'cost_incl_tax': 0, 'default': true, 'offline': true, 'is_server_method': false } rootStore.dispatch('payment/addMethod', paymentMethodConfig) - Vue.prototype.$bus.$on('checkout-before-placeOrder', placeOrder) + EventBus.$on('checkout-before-placeOrder', placeOrder) // Mount the info component when required. - Vue.prototype.$bus.$on('checkout-payment-method-changed', (paymentMethodCode) => { + EventBus.$on('checkout-payment-method-changed', (paymentMethodCode) => { let methods = store.state['payment-backend-methods'].methods if (methods) { let method = methods.find(item => (item.code === paymentMethodCode)) diff --git a/src/modules/sample-custom-entity-graphql/hooks/afterRegistration.ts b/src/modules/sample-custom-entity-graphql/hooks/afterRegistration.ts index b4066b6bbf..1195b1ec35 100644 --- a/src/modules/sample-custom-entity-graphql/hooks/afterRegistration.ts +++ b/src/modules/sample-custom-entity-graphql/hooks/afterRegistration.ts @@ -4,12 +4,13 @@ import { processESResponseType } from '@vue-storefront/core/lib/search/adapter/g import { currentStoreView } from '@vue-storefront/core/lib/multistore' import SearchQuery from '@vue-storefront/core/lib/search/searchQuery' import { Logger } from '@vue-storefront/core/lib/logger' +import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus' const EXTENSION_KEY = 'sample-custom-entity-graphql-extension' const TEST_ENTITY_TYPE = 'testentity' export function afterRegistration ({ Vue, config, store, isServer }) { - Vue.prototype.$bus.$on('application-after-init', async () => { + EventBus.$on('application-after-init', async () => { Logger.debug('Example of custom entity graphql extension')() // create GraphQL searchAdapter diff --git a/src/themes/default-amp/components/core/ProductTile.vue b/src/themes/default-amp/components/core/ProductTile.vue index 97ed4e9b76..0063742964 100755 --- a/src/themes/default-amp/components/core/ProductTile.vue +++ b/src/themes/default-amp/components/core/ProductTile.vue @@ -26,23 +26,23 @@ - {{ product.originalPriceInclTax | price }} + {{ product.original_price_incl_tax | price }} - {{ product.priceInclTax | price }} + {{ product.price_incl_tax | price }} - {{ product.priceInclTax | price }} + {{ product.price_incl_tax | price }} diff --git a/src/themes/default-amp/pages/Product.vue b/src/themes/default-amp/pages/Product.vue index 410ac31210..4e402dc475 100755 --- a/src/themes/default-amp/pages/Product.vue +++ b/src/themes/default-amp/pages/Product.vue @@ -36,27 +36,27 @@
- +
- {{ product.priceInclTax * product.qty | price }} + {{ product.price_incl_tax * product.qty | price }}   - {{ product.originalPriceInclTax * product.qty | price }} + {{ product.original_price_incl_tax * product.qty | price }}
- {{ product.priceInclTax * product.qty | price }} + {{ product.price_incl_tax * product.qty | price }}
-
- {{ productLink.product.priceInclTax | price }}  - {{ productLink.product.originalPriceInclTax | price }} +
+ {{ productLink.product.price_incl_tax | price }}  + {{ productLink.product.original_price_incl_tax | price }}
-
- {{ productLink.product.priceInclTax | price }} +
+ {{ productLink.product.price_incl_tax | price }}
diff --git a/src/themes/default/components/core/ProductTile.vue b/src/themes/default/components/core/ProductTile.vue index 8d2aba3aa5..018c82d00a 100644 --- a/src/themes/default/components/core/ProductTile.vue +++ b/src/themes/default/components/core/ProductTile.vue @@ -26,23 +26,23 @@ - {{ product.originalPriceInclTax | price }} + {{ product.original_price_incl_tax | price }} - {{ product.priceInclTax | price }} + {{ product.price_incl_tax | price }} - {{ product.priceInclTax | price }} + {{ product.price_incl_tax | price }}
diff --git a/src/themes/default/components/core/blocks/Checkout/OrderConfirmation.vue b/src/themes/default/components/core/blocks/Checkout/OrderConfirmation.vue index a85b94395d..aa284119ad 100644 --- a/src/themes/default/components/core/blocks/Checkout/OrderConfirmation.vue +++ b/src/themes/default/components/core/blocks/Checkout/OrderConfirmation.vue @@ -34,13 +34,13 @@ - {{ product.priceInclTax | price }} + {{ product.price_incl_tax | price }} {{ product.qty }} - {{ product.priceInclTax * product.qty | price }} + {{ product.price_incl_tax * product.qty | price }} diff --git a/src/themes/default/components/core/blocks/Checkout/Product.vue b/src/themes/default/components/core/blocks/Checkout/Product.vue index 4bdbdd2035..ec92c6f2a5 100644 --- a/src/themes/default/components/core/blocks/Checkout/Product.vue +++ b/src/themes/default/components/core/blocks/Checkout/Product.vue @@ -45,9 +45,9 @@ {{ product.totals.row_total_incl_tax | price }}
- {{ product.priceInclTax * product.qty | price }} - {{ product.originalPriceInclTax * product.qty | price }} - {{ product.priceInclTax * product.qty | price }} + {{ product.price_incl_tax * product.qty | price }} + {{ product.original_price_incl_tax * product.qty | price }} + {{ product.price_incl_tax * product.qty | price }}
diff --git a/src/themes/default/components/core/blocks/Microcart/Product.vue b/src/themes/default/components/core/blocks/Microcart/Product.vue index 696fc0f429..59644a65d9 100644 --- a/src/themes/default/components/core/blocks/Microcart/Product.vue +++ b/src/themes/default/components/core/blocks/Microcart/Product.vue @@ -49,13 +49,13 @@
- {{ product.priceInclTax * product.qty | price }}  + {{ product.price_incl_tax * product.qty | price }}  - {{ product.originalPriceInclTax * product.qty | price }} + {{ product.original_price_incl_tax * product.qty | price }} - {{ (product.originalPriceInclTax ? product.originalPriceInclTax : product.priceInclTax) * product.qty | price }} + {{ (product.original_price_incl_tax ? product.original_price_incl_tax : product.price_incl_tax) * product.qty | price }}
diff --git a/src/themes/default/components/core/blocks/Wishlist/Product.vue b/src/themes/default/components/core/blocks/Wishlist/Product.vue index e9815a59c1..41ade97626 100644 --- a/src/themes/default/components/core/blocks/Wishlist/Product.vue +++ b/src/themes/default/components/core/blocks/Wishlist/Product.vue @@ -17,11 +17,11 @@
- {{ product.priceInclTax | price }}  - {{ product.originalPriceInclTax | price }} + {{ product.price_incl_tax | price }}  + {{ product.original_price_incl_tax | price }} - {{ product.priceInclTax | price }} + {{ product.price_incl_tax | price }}
diff --git a/src/themes/default/pages/Product.vue b/src/themes/default/pages/Product.vue index aa90315daa..9d7edf9016 100644 --- a/src/themes/default/pages/Product.vue +++ b/src/themes/default/pages/Product.vue @@ -26,7 +26,7 @@
- +
- {{ product.priceInclTax * product.qty | price }} + {{ product.price_incl_tax * product.qty | price }}   - {{ product.originalPriceInclTax * product.qty | price }} + {{ product.original_price_incl_tax * product.qty | price }}
- {{ product.qty > 0 ? product.priceInclTax * product.qty : product.priceInclTax | price }} + {{ product.qty > 0 ? product.price_incl_tax * product.qty : product.price_incl_tax | price }}