From a3cae984638f949bcc9d782defa21cb92c593f0c Mon Sep 17 00:00:00 2001 From: tkostuch Date: Wed, 15 Apr 2020 10:58:11 +0200 Subject: [PATCH 01/36] adjust changes to lru bc --- core/package.json | 2 +- core/scripts/utils/ssr-renderer.js | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/core/package.json b/core/package.json index 950a554ea..632dc472f 100644 --- a/core/package.json +++ b/core/package.json @@ -16,7 +16,7 @@ "lean-he": "^2.0.0", "localforage": "^1.7.2", "lodash-es": "^4.17", - "lru-cache": "^4.0.1", + "lru-cache": "^5.1.1", "query-string": "^6.2.0", "redis-tag-cache": "^1.2.1", "remove-accents": "^0.4.2", diff --git a/core/scripts/utils/ssr-renderer.js b/core/scripts/utils/ssr-renderer.js index ad3e2efc2..8694fe9d7 100644 --- a/core/scripts/utils/ssr-renderer.js +++ b/core/scripts/utils/ssr-renderer.js @@ -10,11 +10,12 @@ const config = require('config') const minify = require('html-minifier').minify function createRenderer (bundle, clientManifest, template) { + const LRU = require('lru-cache') // https://github.com/vuejs/vue/blob/dev/packages/vue-server-renderer/README.md#why-use-bundlerenderer return require('vue-server-renderer').createBundleRenderer(bundle, { clientManifest, // runInNewContext: false, - cache: require('lru-cache')({ + cache: new LRU({ max: 1000, maxAge: 1000 * 60 * 15 }) From b35bc2019b12fa7da6152359c2d5f2881927cab7 Mon Sep 17 00:00:00 2001 From: tkostuch Date: Wed, 15 Apr 2020 11:00:45 +0200 Subject: [PATCH 02/36] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6366b8022..dea0db65d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - update replaceNumberToString, so it will change ONLY numbers to string - @gibkigonzo (#4217) - allow empty shipping methods in checkout - @gibkigozno (#4192) - configure products before price update - this is needed to have variant sku as product sku - @gibkigonzo (#4053) +- Use LRU as object contructor based on newest changes in module - @gibkigonzo (#4242) ## [1.11.2] - 2020.03.10 From c4c2c6747a359ceffe129f3169d12fea02027301 Mon Sep 17 00:00:00 2001 From: SDLyu Date: Tue, 5 May 2020 23:29:49 +0800 Subject: [PATCH 03/36] Fix options undefined bug --- core/modules/cart/helpers/getProductConfiguration.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/modules/cart/helpers/getProductConfiguration.ts b/core/modules/cart/helpers/getProductConfiguration.ts index 901a9edd5..df5a9b8f9 100644 --- a/core/modules/cart/helpers/getProductConfiguration.ts +++ b/core/modules/cart/helpers/getProductConfiguration.ts @@ -6,8 +6,8 @@ const ATTRIBUTES = ['color', 'size'] const getProductConfiguration = (product: CartItem): ProductConfiguration => { const options = getProductOptions(product) - const getAttributesFields = (attributeCode) => - options[attributeCode].find(c => c.id === parseInt(product[attributeCode])) + const getAttributesFields = (attributeCode) => + (options[attributeCode] || []).find(c => c.id === parseInt(product[attributeCode])) if (!options) { return null From 14106a77fd9e4a2dfbad4fd3571a961c9e386c51 Mon Sep 17 00:00:00 2001 From: Therm Scissorpunch <61228862+ThermScissorpunch@users.noreply.github.com> Date: Wed, 6 May 2020 17:58:07 +0200 Subject: [PATCH 04/36] Fix typo --- core/lib/sync/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/lib/sync/index.ts b/core/lib/sync/index.ts index 7f57ef691..999d37b7a 100644 --- a/core/lib/sync/index.ts +++ b/core/lib/sync/index.ts @@ -9,7 +9,7 @@ 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/lib/storage-manager' -/** Syncs given task. If user is offline requiest will be sent to the server after restored connection */ +/** Syncs given task. If user is offline request will be sent to the server after restored connection */ async function queue (task) { const tasksCollection = StorageManager.get('syncTasks') task = _prepareTask(task) From 76de366305eb901f33a2682d6a381e3a312f8159 Mon Sep 17 00:00:00 2001 From: tkostuch Date: Thu, 7 May 2020 09:36:39 +0200 Subject: [PATCH 05/36] exit from errorHandler after redirection --- core/scripts/server.ts | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/core/scripts/server.ts b/core/scripts/server.ts index 0976f2199..c8dcf54d4 100755 --- a/core/scripts/server.ts +++ b/core/scripts/server.ts @@ -156,18 +156,16 @@ app.get('*', (req, res, next) => { const errorHandler = err => { if (err && err.code === 404) { if (NOT_ALLOWED_SSR_EXTENSIONS_REGEX.test(req.url)) { - apiStatus(res, 'Vue Storefront: Resource is not found', 404) console.error(`Resource is not found : ${req.url}`) - next() + return apiStatus(res, 'Vue Storefront: Resource is not found', 404) } else { - res.redirect('/page-not-found') console.error(`Redirect for resource not found : ${req.url}`) + return res.redirect('/page-not-found') } } else { - res.redirect('/error') console.error(`Error during render : ${req.url}`) console.error(err) - next() + return res.redirect('/error') } } @@ -221,10 +219,10 @@ app.get('*', (req, res, next) => { isProd }) - if (typeof afterOutputRenderedResponse.output === 'string') { - res.end(afterOutputRenderedResponse.output) - } else if (typeof afterOutputRenderedResponse === 'string') { + if (typeof afterOutputRenderedResponse === 'string') { res.end(afterOutputRenderedResponse) + } else if (typeof afterOutputRenderedResponse.output === 'string') { + res.end(afterOutputRenderedResponse.output) } else { res.end(output) } From c164e0bc1f4515a683ba8dd55d7a1163f81898b8 Mon Sep 17 00:00:00 2001 From: tkostuch Date: Mon, 27 Apr 2020 15:35:07 +0200 Subject: [PATCH 06/36] use yarn in cli installer --- core/scripts/all.js | 2 +- core/scripts/installer.js | 46 +++++++++---------- docs/guide/basics/recipes.md | 13 +----- docs/guide/basics/ssr-cache.md | 8 ++-- docs/guide/cookbook/data-import.md | 12 ++--- docs/guide/cookbook/internals.md | 2 +- docs/guide/cookbook/setup.md | 2 +- docs/guide/data/data-migrations.md | 4 +- docs/guide/installation/production-setup.md | 10 ++-- docs/guide/integrations/direct-prices-sync.md | 2 +- docs/guide/integrations/multistore.md | 10 ++-- docs/guide/integrations/totals-sync.md | 2 +- docs/guide/upgrade-notes/README.md | 2 +- 13 files changed, 52 insertions(+), 63 deletions(-) diff --git a/core/scripts/all.js b/core/scripts/all.js index 37dba7b24..a7f6a3930 100644 --- a/core/scripts/all.js +++ b/core/scripts/all.js @@ -23,7 +23,7 @@ class Manager extends installer.Manager { */ initStorefront () { return this.storefront.goToDirectory() - .then(this.storefront.npmBuild.bind(this.storefront)) + .then(this.storefront.depBuild.bind(this.storefront)) .then(this.storefront.runDevEnvironment.bind(this.storefront)) } diff --git a/core/scripts/installer.js b/core/scripts/installer.js index e7a2f72ec..21e6d35ad 100644 --- a/core/scripts/installer.js +++ b/core/scripts/installer.js @@ -168,16 +168,16 @@ class Backend extends Abstract { } /** - * Run 'npm install' in backend directory + * Run 'yarn install' in backend directory * * @returns {Promise} */ - npmInstall () { + depInstall () { return new Promise((resolve, reject) => { - Message.info('Installing backend npm...') + Message.info('Installing backend dep...') - if (shell.exec(`npm i >> ${Abstract.infoLogStream} 2>&1`).code !== 0) { - reject(new Error('Can\'t install backend npm.')) + if (shell.exec(`yarn >> ${Abstract.infoLogStream} 2>&1`).code !== 0) { + reject(new Error('Can\'t install backend dep.')) } resolve() @@ -280,7 +280,7 @@ class Backend extends Abstract { } /** - * Run 'npm run restore' + * Run 'yarn restore' * * @returns {Promise} */ @@ -288,7 +288,7 @@ class Backend extends Abstract { return new Promise((resolve, reject) => { Message.info('Restoring data for ElasticSearch...') - if (shell.exec(`npm run restore >> ${Abstract.infoLogStream} 2>&1`).code !== 0) { + if (shell.exec(`yarn restore >> ${Abstract.infoLogStream} 2>&1`).code !== 0) { reject(new Error('Can\'t restore data for ElasticSearch.')) } @@ -297,7 +297,7 @@ class Backend extends Abstract { } /** - * Run 'npm run migrate' + * Run 'yarn migrate' * * @returns {Promise} */ @@ -305,7 +305,7 @@ class Backend extends Abstract { return new Promise((resolve, reject) => { Message.info('Migrating data into ElasticSearch...') - if (shell.exec(`npm run migrate >> ${Abstract.infoLogStream} 2>&1`).code !== 0) { + if (shell.exec(`yarn migrate >> ${Abstract.infoLogStream} 2>&1`).code !== 0) { reject(new Error('Can\'t migrate data into ElasticSearch.')) } @@ -348,7 +348,7 @@ class Backend extends Abstract { } /** - * Start 'npm run dev' in background + * Start 'yarn dev' in background * * @returns {Promise} */ @@ -357,11 +357,11 @@ class Backend extends Abstract { Message.info('Starting backend server...') if (isWindows()) { - if (shell.exec(`start /min npm run dev > ${Abstract.backendLogStream} 2>&1 &`).code !== 0) { + if (shell.exec(`start /min yarn dev > ${Abstract.backendLogStream} 2>&1 &`).code !== 0) { reject(new Error('Can\'t start dev server.', VUE_STOREFRONT_BACKEND_LOG_FILE)) } } else { - if (shell.exec(`nohup npm run dev > ${Abstract.backendLogStream} 2>&1 &`).code !== 0) { + if (shell.exec(`nohup yarn dev > ${Abstract.backendLogStream} 2>&1 &`).code !== 0) { reject(new Error('Can\'t start dev server.', VUE_STOREFRONT_BACKEND_LOG_FILE)) } } @@ -472,16 +472,16 @@ class Storefront extends Abstract { } /** - * Run 'npm run build' on storefront + * Run 'yarn build' on storefront * * @returns {Promise} */ - npmBuild () { + depBuild () { return new Promise((resolve, reject) => { - Message.info('Build storefront npm...') + Message.info('Build storefront dep...') - if (shell.exec(`npm run build > ${Abstract.storefrontLogStream} 2>&1`).code !== 0) { - reject(new Error('Can\'t build storefront npm.', VUE_STOREFRONT_LOG_FILE)) + if (shell.exec(`yarn build > ${Abstract.storefrontLogStream} 2>&1`).code !== 0) { + reject(new Error('Can\'t build storefront dep.', VUE_STOREFRONT_LOG_FILE)) } resolve() @@ -489,7 +489,7 @@ class Storefront extends Abstract { } /** - * Start 'npm run dev' in background + * Start 'yarn dev' in background * * @returns {Promise} */ @@ -498,11 +498,11 @@ class Storefront extends Abstract { Message.info('Starting storefront server...') if (isWindows()) { - if (shell.exec(`start /min npm run dev >> ${Abstract.storefrontLogStream} 2>&1 &`).code !== 0) { + if (shell.exec(`start /min yarn dev >> ${Abstract.storefrontLogStream} 2>&1 &`).code !== 0) { reject(new Error('Can\'t start storefront server.', VUE_STOREFRONT_LOG_FILE)) } } else { - if (shell.exec(`nohup npm run dev >> ${Abstract.storefrontLogStream} 2>&1 &`).code !== 0) { + if (shell.exec(`nohup yarn dev >> ${Abstract.storefrontLogStream} 2>&1 &`).code !== 0) { reject(new Error('Can\'t start storefront server.', VUE_STOREFRONT_LOG_FILE)) } } @@ -574,7 +574,7 @@ class Manager extends Abstract { return this.backend.validateM2Integration() .then(this.backend.cloneRepository.bind(this.backend)) .then(this.backend.goToDirectory.bind(this.backend)) - .then(this.backend.npmInstall.bind(this.backend)) + .then(this.backend.depInstall.bind(this.backend)) .then(this.backend.createConfig.bind(this.backend)) .then(this.backend.dockerComposeUp.bind(this.backend)) .then(this.backend.importElasticSearch.bind(this.backend)) @@ -582,7 +582,7 @@ class Manager extends Abstract { } else { return this.backend.cloneRepository() .then(this.backend.goToDirectory.bind(this.backend)) - .then(this.backend.npmInstall.bind(this.backend)) + .then(this.backend.depInstall.bind(this.backend)) .then(this.backend.createConfig.bind(this.backend)) .then(this.backend.dockerComposeUp.bind(this.backend)) .then(this.backend.restoreElasticSearch.bind(this.backend)) @@ -603,7 +603,7 @@ class Manager extends Abstract { initStorefront () { return this.storefront.goToDirectory() .then(this.storefront.createConfig.bind(this.storefront)) - .then(this.storefront.npmBuild.bind(this.storefront)) + .then(this.storefront.depBuild.bind(this.storefront)) .then(this.storefront.runDevEnvironment.bind(this.storefront)) } diff --git a/docs/guide/basics/recipes.md b/docs/guide/basics/recipes.md index d707b89c8..1e42d6fa2 100644 --- a/docs/guide/basics/recipes.md +++ b/docs/guide/basics/recipes.md @@ -183,17 +183,6 @@ To make it work, you need have Magento 2 OAuth keys configured in your `vue-stor After this change, you need to restart the `yarn dev` command to take the config changes into consideration by the VS. All the cart actions (add to cart, remove from cart, modify the quantity) are now synchronized directly with Magento 2 for both guest and logged-in clients. -## How to prevent an error "Can’t build storefront npm" - -The error, "Can't build storefront npm", appears because npm can't automatically install required modules. To prevent this error, you should manually install those modules before running the installer. It's easy: - -```bash -git clone https://github.com/DivanteLtd/vue-storefront.git vue-storefront && cd vue-storefront -npm install -npm install vue-carousel vue-no-ssr -npm run build # check if no errors -npm run installer -``` ## How to integrate 3rd party platform? Do you think it could be used with a legacy bespoke PHP eCommerce? @@ -240,7 +229,7 @@ If you would like to have a Category filter working with configurable products, There is an SEO redirects generator for NGINX -> `https://serverfault.com/a/441517` available within the [vue-storefront-api](https://github.com/DivanteLtd/vue-storefront-api/commit/2c7e10b4c4294f222f7a1aae96627d6a0e23f30e). Now you can generate an SEO map redirecting users from the original Magento URLs to Vue Storefront URLs by running: ```bash -npm run seo redirects — —oldFormat=true | false +yarn seo redirects — —oldFormat=true | false ``` Please make sure that `vue-storefront/config/local.json` setting of `useMagentoUrlKeys` is set to `true` and you have ElasticSearch synchronized with the Magento2 instance using the current version of [mage2vuestorefront](https://github.com/DivanteLtd/mage2vuestorefront). diff --git a/docs/guide/basics/ssr-cache.md b/docs/guide/basics/ssr-cache.md index e79df35ab..7da4fbffe 100644 --- a/docs/guide/basics/ssr-cache.md +++ b/docs/guide/basics/ssr-cache.md @@ -69,10 +69,10 @@ We strongly recommend you DO NOT USE output cache in development mode. By using You can manually clear the Redis cache for specific tags by running the following command: ```bash -npm run cache clear -npm run cache clear -- --tag=product,category -npm run cache clear -- --tag=P198 -npm run cache clear -- --tag=* +yarn cache clear +yarn cache clear -- --tag=product,category +yarn cache clear -- --tag=P198 +yarn cache clear -- --tag=* ``` **Note:** The commands presented above works exactly the same way in the `vue-storefront-api`. diff --git a/docs/guide/cookbook/data-import.md b/docs/guide/cookbook/data-import.md index 60fa01cbd..f31590ab4 100644 --- a/docs/guide/cookbook/data-import.md +++ b/docs/guide/cookbook/data-import.md @@ -22,7 +22,7 @@ Vue Storefront uses a data-migration mechanism based on [node-migrate](https://g ### 2. Recipe 1. Run a node script from **Vue Storefront API root path** which is configured out of the box. ```bash -npm run migrate +yarn migrate ``` which runs the migrations in `migrations` folder. @@ -370,7 +370,7 @@ We worked in the red rectangle part of the architecture as a preparation for dat What we did in a simple term, we taught Elasticsearch types and sorts of data(mapping, also known as schema) we will use for Vue Storefront API later on. -Upon running `npm run migrate`, it runs the pre-configured [migration scripts](https://github.com/DivanteLtd/vue-storefront-api/tree/master/migrations) using [node-migrate](https://github.com/tj/node-migrate). If you take a closer look into the migration scripts, you will notice the ultimate js file which is located at [`./src/lib/elastic.js`](https://github.com/DivanteLtd/vue-storefront-api/blob/master/src/lib/elastic.js) that does the actual labor for migration. +Upon running `yarn migrate`, it runs the pre-configured [migration scripts](https://github.com/DivanteLtd/vue-storefront-api/tree/master/migrations) using [node-migrate](https://github.com/tj/node-migrate). If you take a closer look into the migration scripts, you will notice the ultimate js file which is located at [`./src/lib/elastic.js`](https://github.com/DivanteLtd/vue-storefront-api/blob/master/src/lib/elastic.js) that does the actual labor for migration. If you take one more closer look in the `elastic.js` file, you will also find all the schema files are located under [`./config`](https://github.com/DivanteLtd/vue-storefront-api/tree/master/config) folder. What those scripts do can be divided into steps as per the file name. It first creates index from index schema, then import schema from `elastic.schema.[types].json` files. It will then reindex them, and delete temporary index. Finally it will work a few workarounds to deal with deprecated process. @@ -386,14 +386,14 @@ If you encountered with the exception as follows during the migration script : It means you don't have the temporary index `vue_storefront_catalog_temp` which is required. Solution is : ```bash -npm run restore +yarn restore ``` This will create the necessary temporary index, then the necessary temp index will be deleted by the steps mentioned [above](#_3-peep-into-the-kitchen-what-happens-internally) when the migration is finished #### Secret 2. Add a new migration script You might need to write your own migration script. In that case, you can do so by adding a file under the `./migrations` directory though this is not a recommended way. `node-migrate` provides you with the cli command for the purpose as follows : ```bash -npm run migrate create name-of-migration +yarn migrate create name-of-migration ``` This wil create a migration script template under `./migration` folder with the standard naming convention. [more info](https://github.com/tj/node-migrate#creating-migrations) @@ -438,7 +438,7 @@ module.exports.down = function(next) { ``` #### Secret 3. Execute migration multiple times -If you run a migration multiple times using `npm run migrate`, it will only run the migration once and subsequent execution will be ignored and only repeat the result as follows : +If you run a migration multiple times using `yarn migrate`, it will only run the migration once and subsequent execution will be ignored and only repeat the result as follows : ![migration complete](../images/npm-run-migrate-result.png) @@ -725,7 +725,7 @@ node --harmony cli.js pages 7. Finally, reindex the Elasticsearch making sure up-to-date with data source in **Vue Storefront API** root path. ```bash -npm run db rebuild +yarn db rebuild ``` ### 3. Peep into the kitchen (what happens internally) diff --git a/docs/guide/cookbook/internals.md b/docs/guide/cookbook/internals.md index 966ca78c5..da8efdae3 100644 --- a/docs/guide/cookbook/internals.md +++ b/docs/guide/cookbook/internals.md @@ -22,7 +22,7 @@ Ever wonder what happens when you enter into **Vue Storefront** shop? From gatew 1. Go to **Vue Storefront** root path and run the following : ```bash -npm run dev +yarn dev ``` 2. Open your browser and go to your development **Vue Storefront** store, for example, [_http://localhost:3000_](http://localhost:3000) if you run it by default. diff --git a/docs/guide/cookbook/setup.md b/docs/guide/cookbook/setup.md index 24c2e4fdf..12b0eba88 100644 --- a/docs/guide/cookbook/setup.md +++ b/docs/guide/cookbook/setup.md @@ -1362,7 +1362,7 @@ Upon the release of 1.10, we also present a new way of setup and all its sorts f We will continuously add new features to [`CLI`](https://www.npmjs.com/package/@vue-storefront/cli) as the version goes up. ### 1. Preparation -- You need to have installed [`npm`](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) on your machine. (or [`yarn`](https://yarnpkg.com/lang/en/docs/install/#debian-stable) if you chose it) +- You need to have installed [`npm`](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) on your machine and [`yarn`](https://yarnpkg.com/lang/en/docs/install/#debian-stable). ### 2. Recipe 1. Install _Vue Storefront CLI_ package on your machine with `-g` flag as follows : diff --git a/docs/guide/data/data-migrations.md b/docs/guide/data/data-migrations.md index fa2080a43..14019fefd 100644 --- a/docs/guide/data/data-migrations.md +++ b/docs/guide/data/data-migrations.md @@ -11,7 +11,7 @@ Vue Storefront uses a data-migration mechanism based on [node-migrate](https://g We use node-migrate, which is pre-configured with npm, so we're using the following alias: ```bash -npm run migrate +yarn migrate ``` which runs the migrations against `migrations` folder. @@ -21,7 +21,7 @@ which runs the migrations against `migrations` folder. You can add a new migration by simply adding a file to the `migrations` directory (not recommended) or using the command line tool: ```bash -npm run migrate create name-of-my-migration +yarn migrate create name-of-my-migration ``` The tool automatically generates the file under the `migrations` folder. diff --git a/docs/guide/installation/production-setup.md b/docs/guide/installation/production-setup.md index 69ba38214..75a6ddcb7 100644 --- a/docs/guide/installation/production-setup.md +++ b/docs/guide/installation/production-setup.md @@ -1,6 +1,6 @@ # Production setup -If you’d like to start developing sites using Vue Storefront, you should start with the [Installation guide](linux-mac.md). For development purposes, you'll likely use the `yarn install` / `npm run installer` sequence, which will set up Vue Storefront locally using the automated installer and prepared Docker images for having Elasticsearch and Redis support. +If you’d like to start developing sites using Vue Storefront, you should start with the [Installation guide](linux-mac.md). For development purposes, you'll likely use the `yarn install` sequence, which will set up Vue Storefront locally using the automated installer and prepared Docker images for having Elasticsearch and Redis support. Development mode means you're using a node.js-based server as HTTP service and running the app on the `3000` TCP port. As it's great for local testing, it's not recommended to use the installer and direct-user access to node.js in production configurations. @@ -412,7 +412,7 @@ You can easily dump your current VS index using the following command (your loca ```bash cd vue-storefront-api rm var/catalog.json -npm run dump +yarn dump ``` Now in the `var/catalog.json` you have your current database dump. Please transfer this file to the server—for example, using the following ssh command: @@ -426,9 +426,9 @@ Then, after logging in to your `prod.vuestorefront.io` server as a `vuestorefron ```bash cd vue-storefront-api -npm run db new -npm run restore2main -npm run db rebuild +yarn db new +yarn restore2main +yarn db rebuild ``` #### Running the Vue Storefront and Vue Storefront API diff --git a/docs/guide/integrations/direct-prices-sync.md b/docs/guide/integrations/direct-prices-sync.md index 176bbdf92..1db1b88f8 100644 --- a/docs/guide/integrations/direct-prices-sync.md +++ b/docs/guide/integrations/direct-prices-sync.md @@ -28,4 +28,4 @@ To use this feature, you should also modify `config/local.json` within your `vue }, ``` -_Important note_: To use the dynamic Magento 2 prices sync, you should restore the database using `npm run restore` within the `vue-storefront-api` or re-run the `mage2vuestorefront` product sync, because an "ID" field has been added to the `configurable_children` products and it's required for the prices sync. +_Important note_: To use the dynamic Magento 2 prices sync, you should restore the database using `yarn restore` within the `vue-storefront-api` or re-run the `mage2vuestorefront` product sync, because an "ID" field has been added to the `configurable_children` products and it's required for the prices sync. diff --git a/docs/guide/integrations/multistore.md b/docs/guide/integrations/multistore.md index 09a3b5841..d7839c779 100644 --- a/docs/guide/integrations/multistore.md +++ b/docs/guide/integrations/multistore.md @@ -57,9 +57,9 @@ In the result, you should get: Then, to use these indexes in Vue Storefront, you should index the database schema using the `vue-storefront-api` db tool: ```bash -npm run db rebuild -- --indexName=vue_storefront_catalog_it -npm run db rebuild -- --indexName=vue_storefront_catalog_de -npm run db rebuild -- --indexName=vue_storefront_catalog +yarn db rebuild -- --indexName=vue_storefront_catalog_it +yarn db rebuild -- --indexName=vue_storefront_catalog_de +yarn db rebuild -- --indexName=vue_storefront_catalog ``` ## Vue Storefront and Vue Storefront API configuration @@ -154,9 +154,9 @@ By default, the language / store is switched by the URL prefix: General URL format is: `http://localhost:3000/{storeCode}` -The storeCode may be switched by ENV variable set before running `npm run dev` / `npm start`: +The storeCode may be switched by ENV variable set before running `yarn dev` / `yarn start`: -- `export STORE_CODE=de && npm run dev` will run the shop with the `de` shop loaded +- `export STORE_CODE=de && yarn dev` will run the shop with the `de` shop loaded Another option, useful when using multistore mode with the NGINX/varnish mode, is to set the shop code by the `x-vs-store-code` http reqeuest header. diff --git a/docs/guide/integrations/totals-sync.md b/docs/guide/integrations/totals-sync.md index 330d6d055..de95988d5 100644 --- a/docs/guide/integrations/totals-sync.md +++ b/docs/guide/integrations/totals-sync.md @@ -87,6 +87,6 @@ This process doesn't require much additional configuration: 1. You must have the Magento2 API access configures in the `config/local.json` file of `vue-storefront-api` 2. You must have the "Orders" section marked On within the "Permissions" section of Magento Integration ([see the previous tutorial for the reference on how to set it up](../installation/magento.md)). -3. After the configuration step You just run `npm run o2m` inside your `vue-storefront-api` directory. +3. After the configuration step You just run `yarn o2m` inside your `vue-storefront-api` directory. ![This is the output of o2m after successfull setup](../images/o2m-output.png) diff --git a/docs/guide/upgrade-notes/README.md b/docs/guide/upgrade-notes/README.md index c91a09a4b..5034414a4 100644 --- a/docs/guide/upgrade-notes/README.md +++ b/docs/guide/upgrade-notes/README.md @@ -432,7 +432,7 @@ Now it mirrors `core/` folder structure, which is desired behaviour. We added the possibility to run the `vue-storefront-api` fully in Docker (previously, just the Elastic and Redis images were present in the `docker-compose.yml`. Please read the [README.md](https://github.com/DivanteLtd/vue-storefront-api) for more details. -**PLEASE NOTE:** We changed the structure of the `elasticsearch` section of the config files, moving `esIndexes` to `elasticsearch.indices` etc. There is an automatic migration that will update your config files automatically by running: `npm run migrate` in the `vue-storefront-api` folder. +**PLEASE NOTE:** We changed the structure of the `elasticsearch` section of the config files, moving `esIndexes` to `elasticsearch.indices` etc. There is an automatic migration that will update your config files automatically by running: `yarn migrate` in the `vue-storefront-api` folder. ### Default storage of the shopping carts and user data moved to localStorage From d28fab6040c86367995207c2f0caa10a21e22e54 Mon Sep 17 00:00:00 2001 From: tkostuch Date: Thu, 7 May 2020 10:29:33 +0200 Subject: [PATCH 07/36] update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 661cdbd72..8a70562de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed / Improved +- use yarn in cli installer - @gibkigonzo (#4292) + ### Fixed From 0bcb30713e3e03fe1b7cc6deb79ff32d6d85d741 Mon Sep 17 00:00:00 2001 From: tkostuch Date: Thu, 7 May 2020 10:34:32 +0200 Subject: [PATCH 08/36] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 661cdbd72..ee227a9a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Use LRU as object contructor based on newest changes in module - @gibkigonzo (#4242) +- exit from errorHandler after redirection - @gibkigonzo (#4246) ## [1.11.3] - 2020.04.27 From 3e8add5777cd640ce0a9dc00afe8487be9e426a5 Mon Sep 17 00:00:00 2001 From: Juho Jaakkola Date: Tue, 12 May 2020 09:05:37 +0200 Subject: [PATCH 09/36] Fixes problems related to tax calculation and price filter in multistore setup Closes: #4376 --- CHANGELOG.md | 1 + core/lib/types.ts | 4 +++- core/modules/catalog-next/store/category/getters.ts | 6 +++--- core/modules/catalog/store/tax/actions.ts | 5 ++++- core/modules/catalog/store/tax/getters.ts | 3 ++- 5 files changed, 13 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 661cdbd72..c176e5b1d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Use LRU as object contructor based on newest changes in module - @gibkigonzo (#4242) +- Fixes problems related to tax calculation and price filter in multistore setup - @juho-jaakkola (#4376) ## [1.11.3] - 2020.04.27 diff --git a/core/lib/types.ts b/core/lib/types.ts index 507806fab..ed2dc34b3 100644 --- a/core/lib/types.ts +++ b/core/lib/types.ts @@ -20,7 +20,9 @@ export interface StoreView { index: string }, tax: { - sourcePriceIncludesTax: boolean, + sourcePriceIncludesTax?: boolean, + finalPriceIncludesTax?: boolean, + deprecatedPriceFieldsSupport?: boolean, defaultCountry: string, defaultRegion: null | string, calculateServerSide: boolean, diff --git a/core/modules/catalog-next/store/category/getters.ts b/core/modules/catalog-next/store/category/getters.ts index 8b5bde50b..57d2e79a5 100644 --- a/core/modules/catalog-next/store/category/getters.ts +++ b/core/modules/catalog-next/store/category/getters.ts @@ -14,7 +14,7 @@ import { getFiltersFromQuery } from '../../helpers/filterHelpers' import { Category } from '../../types/Category' import { parseCategoryPath } from '@vue-storefront/core/modules/breadcrumbs/helpers' import { _prepareCategoryPathIds, getSearchOptionsFromRouteParams } from '../../helpers/categoryHelpers'; -import { removeStoreCodeFromRoute } from '@vue-storefront/core/lib/multistore' +import { currentStoreView, removeStoreCodeFromRoute } from '@vue-storefront/core/lib/multistore' import cloneDeep from 'lodash-es/cloneDeep' function mapCategoryProducts (productsFromState, productsData) { @@ -77,8 +77,8 @@ const getters: GetterTree = { }); filters[attrToFilter] = filterOptions.sort(compareByLabel) } else { // special case is range filter for prices - const storeView = rootState.storeView - const currencySign = storeView.i18n.currencySign + const currencySign = currentStoreView().i18n.currencySign + if (aggregations['agg_range_' + attrToFilter]) { let index = 0 let count = aggregations['agg_range_' + attrToFilter].buckets.length diff --git a/core/modules/catalog/store/tax/actions.ts b/core/modules/catalog/store/tax/actions.ts index 8847c2fa5..72faad3ea 100644 --- a/core/modules/catalog/store/tax/actions.ts +++ b/core/modules/catalog/store/tax/actions.ts @@ -11,6 +11,7 @@ import config from 'config' import { calculateProductTax } from '@vue-storefront/core/modules/catalog/helpers/taxCalc' import { doPlatformPricesSync } from '@vue-storefront/core/modules/catalog/helpers' import { catalogHooksExecutors } from './../../hooks' +import { currentStoreView } from '@vue-storefront/core/lib/multistore'; const actions: ActionTree = { async list ({ state, commit, dispatch }, { entityType = 'taxrule' }) { @@ -48,6 +49,8 @@ const actions: ActionTree = { return doPlatformPricesSync(mutatedProducts) } + let storeView = currentStoreView() + const tcs = await dispatch('list', {}) const { defaultCountry, @@ -55,7 +58,7 @@ const actions: ActionTree = { sourcePriceIncludesTax, finalPriceIncludesTax, deprecatedPriceFieldsSupport - } = rootState.storeView.tax + } = storeView.tax const recalculatedProducts = mutatedProducts.map(product => calculateProductTax({ diff --git a/core/modules/catalog/store/tax/getters.ts b/core/modules/catalog/store/tax/getters.ts index 1fc26780a..aa65d66f7 100644 --- a/core/modules/catalog/store/tax/getters.ts +++ b/core/modules/catalog/store/tax/getters.ts @@ -1,6 +1,7 @@ import { GetterTree } from 'vuex' import RootState from '@vue-storefront/core/types/RootState' import TaxState from '../../types/TaxState' +import { currentStoreView } from '@vue-storefront/core/lib/multistore'; const getters: GetterTree = { getRules: (state) => state.rules, @@ -17,7 +18,7 @@ const getters: GetterTree = { return currentUser.group_id }, getIsUserGroupedTaxActive: (state, getters, rootState) => { - return typeof rootState.storeView.tax.userGroupId === 'number' + return typeof currentStoreView().tax.userGroupId === 'number' } } From 918f7a7d7df956e3c3ab897f77357a44da4b7310 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Dani=C5=82owicz?= Date: Tue, 12 May 2020 12:25:44 +0200 Subject: [PATCH 10/36] Blank order details page fix --- CHANGELOG.md | 2 +- .../default/components/core/blocks/MyAccount/MyOrder.vue | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 661cdbd72..73e05acf4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,7 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Use LRU as object contructor based on newest changes in module - @gibkigonzo (#4242) - +- Blank order details page - @mdanilowicz (#4382) ## [1.11.3] - 2020.04.27 diff --git a/src/themes/default/components/core/blocks/MyAccount/MyOrder.vue b/src/themes/default/components/core/blocks/MyAccount/MyOrder.vue index e34a73aea..f1fac6fee 100644 --- a/src/themes/default/components/core/blocks/MyAccount/MyOrder.vue +++ b/src/themes/default/components/core/blocks/MyAccount/MyOrder.vue @@ -110,7 +110,7 @@

{{ $t('Order informations') }}

-
+
{{ $t('Shipping address') }}

{{ shippingAddress.firstname }} {{ shippingAddress.lastname }}

@@ -119,7 +119,7 @@

{{ shippingAddress.country }}

-
+
{{ $t('Shipping method') }}

{{ order.shipping_description }}

From 0e6d71d8c5aec5c873a5dc3b1fac48ae5c115404 Mon Sep 17 00:00:00 2001 From: tkostuch Date: Tue, 12 May 2020 15:11:52 +0200 Subject: [PATCH 11/36] upadate cart hash after sync with backend --- core/modules/cart/store/actions/synchronizeActions.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/modules/cart/store/actions/synchronizeActions.ts b/core/modules/cart/store/actions/synchronizeActions.ts index eb625f634..da181d895 100644 --- a/core/modules/cart/store/actions/synchronizeActions.ts +++ b/core/modules/cart/store/actions/synchronizeActions.ts @@ -75,9 +75,10 @@ const synchronizeActions = { Logger.error(result, 'cart') cartHooksExecutors.afterSync(result) + commit(types.CART_SET_ITEMS_HASH, getters.getCurrentCartHash) return createDiffLog() }, - async stockSync ({ dispatch, commit }, stockTask) { + async stockSync ({ dispatch, commit, getters }, stockTask) { const product = { sku: stockTask.product_sku } const cartItem = await dispatch('getItem', { product }) @@ -102,6 +103,7 @@ const synchronizeActions = { product: { info: { stock: i18n.t('In stock!') }, sku: stockTask.product_sku, is_in_stock: true } }) EventBus.$emit('cart-after-itemchanged', { item: cartItem }) + commit(types.CART_SET_ITEMS_HASH, getters.getCurrentCartHash) } } From 14e13bb844981c14abb13d6765027a29fda7650f Mon Sep 17 00:00:00 2001 From: tkostuch Date: Tue, 12 May 2020 15:14:25 +0200 Subject: [PATCH 12/36] upadate tests --- .../modules/cart/test/unit/store/synchronizeActions.spec.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/modules/cart/test/unit/store/synchronizeActions.spec.ts b/core/modules/cart/test/unit/store/synchronizeActions.spec.ts index 0ff073402..ae866ecb0 100644 --- a/core/modules/cart/test/unit/store/synchronizeActions.spec.ts +++ b/core/modules/cart/test/unit/store/synchronizeActions.spec.ts @@ -224,7 +224,11 @@ describe('Cart synchronizeActions', () => { config.cart = { synchronize: false } - const contextMock = createContextMock(); + const contextMock = createContextMock({ + getters: { + getCurrentCartHash: 'zyx' + } + }); (contextMock.dispatch as jest.Mock).mockImplementationOnce(() => product) From 8fe0eed41fda8818c1e846a69815e0af95bda2c3 Mon Sep 17 00:00:00 2001 From: tkostuch Date: Tue, 12 May 2020 15:18:07 +0200 Subject: [PATCH 13/36] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 661cdbd72..525fb7249 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Use LRU as object contructor based on newest changes in module - @gibkigonzo (#4242) +- upadate cart hash after sync with backend - @gibkigonzo (#4387) ## [1.11.3] - 2020.04.27 From a9ca912eea871e0c769d737796d4de25d271d26c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Dani=C5=82owicz?= Date: Thu, 14 May 2020 10:31:02 +0200 Subject: [PATCH 14/36] Broken Key Event Listener on Sidemenu --- CHANGELOG.md | 2 +- core/modules/wishlist/components/Wishlist.ts | 2 +- .../default/components/core/blocks/Microcart/Microcart.vue | 2 +- src/themes/default/store/ui.ts | 6 ++++++ 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 661cdbd72..0a1ada7b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,7 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Use LRU as object contructor based on newest changes in module - @gibkigonzo (#4242) - +- Fixed ESC button action (minicart, wishlist) - @mdanilowicz (#4393) ## [1.11.3] - 2020.04.27 diff --git a/core/modules/wishlist/components/Wishlist.ts b/core/modules/wishlist/components/Wishlist.ts index 0fbb366ee..221ea995c 100644 --- a/core/modules/wishlist/components/Wishlist.ts +++ b/core/modules/wishlist/components/Wishlist.ts @@ -18,7 +18,7 @@ export const Wishlist = { }, methods: { closeWishlist () { - this.$store.dispatch('ui/toggleWishlist') + this.$store.dispatch('ui/closeWishlist') } } } diff --git a/src/themes/default/components/core/blocks/Microcart/Microcart.vue b/src/themes/default/components/core/blocks/Microcart/Microcart.vue index 49060343f..8a3194ed8 100644 --- a/src/themes/default/components/core/blocks/Microcart/Microcart.vue +++ b/src/themes/default/components/core/blocks/Microcart/Microcart.vue @@ -222,7 +222,7 @@ export default { this.addCouponPressed = false }, onEscapePress () { - this.toggleMicrocart() + this.$store.dispatch('ui/closeMicrocart') }, clearCart () { this.$store.dispatch('notification/spawnNotification', { diff --git a/src/themes/default/store/ui.ts b/src/themes/default/store/ui.ts index e1a6f8c29..a92769c46 100644 --- a/src/themes/default/store/ui.ts +++ b/src/themes/default/store/ui.ts @@ -62,6 +62,12 @@ export const uiStore = { }, toggleWishlist ({ commit, state }) { commit('setWishlist', !state.wishlist) + }, + closeMicrocart ({ commit, state }) { + if (state.microcart) commit('setMicrocart', false) + }, + closeWishlist ({ commit, state }) { + if (state.wishlist) commit('setWishlist', false) } } } From cee9b9a5b7391f3c52f2c96ecece2548249a443f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Dani=C5=82owicz?= Date: Thu, 14 May 2020 10:39:14 +0200 Subject: [PATCH 15/36] Broken Key Event Listener on Sidemenu --- core/compatibility/components/blocks/Wishlist/Wishlist.js | 2 +- core/modules/wishlist/components/Wishlist.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/compatibility/components/blocks/Wishlist/Wishlist.js b/core/compatibility/components/blocks/Wishlist/Wishlist.js index dc474a660..97d9235b7 100644 --- a/core/compatibility/components/blocks/Wishlist/Wishlist.js +++ b/core/compatibility/components/blocks/Wishlist/Wishlist.js @@ -13,7 +13,7 @@ export default { methods: { // theme-specific onEscapePress () { - this.closeWishlist() + this.$store.dispatch('ui/closeWishlist') } }, mixins: [ Wishlist, onEscapePress ] diff --git a/core/modules/wishlist/components/Wishlist.ts b/core/modules/wishlist/components/Wishlist.ts index 221ea995c..0fbb366ee 100644 --- a/core/modules/wishlist/components/Wishlist.ts +++ b/core/modules/wishlist/components/Wishlist.ts @@ -18,7 +18,7 @@ export const Wishlist = { }, methods: { closeWishlist () { - this.$store.dispatch('ui/closeWishlist') + this.$store.dispatch('ui/toggleWishlist') } } } From 84b32ad5d672e8e8f8b2e840e7a8003fdd757af6 Mon Sep 17 00:00:00 2001 From: tkostuch Date: Wed, 20 May 2020 07:51:17 +0200 Subject: [PATCH 16/36] disable out of stock notification when config.stock.allowOutOfStockInCart --- core/modules/cart/store/actions/itemActions.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/modules/cart/store/actions/itemActions.ts b/core/modules/cart/store/actions/itemActions.ts index fcaf2d6dd..3ce9518e9 100644 --- a/core/modules/cart/store/actions/itemActions.ts +++ b/core/modules/cart/store/actions/itemActions.ts @@ -9,6 +9,7 @@ import { notifications } from '@vue-storefront/core/modules/cart/helpers' import { cartHooksExecutors } from './../../hooks' +import config from 'config' const itemActions = { async configureItem (context, { product, configuration }) { @@ -62,7 +63,7 @@ const itemActions = { if (errors.length === 0) { const { status, onlineCheckTaskId } = await dispatch('checkProductStatus', { product }) - if (status === 'volatile') { + if (status === 'volatile' && !config.stock.allowOutOfStockInCart) { diffLog.pushNotification(notifications.unsafeQuantity()) } if (status === 'out_of_stock') { From 3869b28cbfe09af0be05f9c88e3857555f127d24 Mon Sep 17 00:00:00 2001 From: tkostuch Date: Wed, 20 May 2020 07:51:56 +0200 Subject: [PATCH 17/36] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index adfd4b2fe..cd6fdb4e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed / Improved - use yarn in cli installer - @gibkigonzo (#4292) +- disable out of stock notification when config.stock.allowOutOfStockInCart is true - @gibigonzo (#4340) ### Fixed From 9b2c63f1e375ddad73101b4e30da6db62b95c93a Mon Sep 17 00:00:00 2001 From: tkostuch Date: Wed, 20 May 2020 09:17:43 +0200 Subject: [PATCH 18/36] add redirection in component for simple product related to configurable product --- core/modules/catalog/events.ts | 20 ++++++++++++++++++++ src/themes/default/pages/Product.vue | 2 ++ 2 files changed, 22 insertions(+) diff --git a/core/modules/catalog/events.ts b/core/modules/catalog/events.ts index fe2f0ded6..93dae4ee6 100644 --- a/core/modules/catalog/events.ts +++ b/core/modules/catalog/events.ts @@ -2,6 +2,10 @@ import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus' import { PRODUCT_SET_CURRENT_CONFIGURATION, PRODUCT_SET_CURRENT } from './store/product/mutation-types' import omit from 'lodash-es/omit' import config from 'config' +import { AsyncDataLoader } from '@vue-storefront/core/lib/async-data-loader'; +import { currentStoreView } from '@vue-storefront/core/lib/multistore'; +import { formatProductLink } from '@vue-storefront/core/modules/url/helpers'; +import { Logger } from '@vue-storefront/core/lib/logger'; // Listeners moved from Product.js @@ -110,3 +114,19 @@ export const onUserPricesRefreshed = async (store, router) => { }, { root: true }) } } + +export const checkConfigurableParent = (store) => { + const parentProduct = store.getters['product/getParentProduct'] + const currentProduct = store.getters['product/getCurrentProduct'] + if (parentProduct && parentProduct.id !== currentProduct.id && config.products.preventConfigurableChildrenDirectAccess) { + Logger.log('Redirecting to parent, configurable product', parentProduct.sku)() + const parentUrl = formatProductLink(parentProduct, currentStoreView().storeCode) + AsyncDataLoader.push({ + execute: async ({ context }) => { + if (context && !context.url.includes(parentUrl)) { + context.server.response.redirect(301, parentUrl) + } + } + }) + } +} diff --git a/src/themes/default/pages/Product.vue b/src/themes/default/pages/Product.vue index 95d040e8a..9ef307a6d 100644 --- a/src/themes/default/pages/Product.vue +++ b/src/themes/default/pages/Product.vue @@ -225,6 +225,7 @@ import { registerModule, isModuleRegistered } from '@vue-storefront/core/lib/mod import { onlineHelper, isServer } from '@vue-storefront/core/helpers' import { catalogHooksExecutors } from '@vue-storefront/core/modules/catalog-next/hooks' import ProductPrice from 'theme/components/core/ProductPrice.vue' +import { checkConfigurableParent } from '@vue-storefront/core/modules/catalog/events' export default { components: { @@ -337,6 +338,7 @@ export default { const loadBreadcrumbsPromise = store.dispatch('product/loadProductBreadcrumbs', { product }) if (isServer) await loadBreadcrumbsPromise catalogHooksExecutors.productPageVisited(product) + checkConfigurableParent(store) }, beforeRouteEnter (to, from, next) { if (isServer) { From 5b89b8ef721ff0ae8b1431721285e28d802adc78 Mon Sep 17 00:00:00 2001 From: tkostuch Date: Wed, 20 May 2020 09:18:16 +0200 Subject: [PATCH 19/36] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index adfd4b2fe..a7d5f828f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Blank order details page - @mdanilowicz (#4382) - upadate cart hash after sync with backend - @gibkigonzo (#4387) - exit from errorHandler after redirection - @gibkigonzo (#4246) +- add redirection in component for simple product related to configurable product - @gibkigonzo (#4359) ## [1.11.3] - 2020.04.27 From 9b427c26679998cb529f7e0e017ff7ff35ce0802 Mon Sep 17 00:00:00 2001 From: tkostuch Date: Wed, 20 May 2020 10:28:45 +0200 Subject: [PATCH 20/36] check parent only if product isn't visible --- core/modules/catalog/events.ts | 22 +++++++++++-------- core/modules/catalog/store/product/actions.ts | 15 +++++++------ src/themes/default/pages/Product.vue | 2 -- 3 files changed, 21 insertions(+), 18 deletions(-) diff --git a/core/modules/catalog/events.ts b/core/modules/catalog/events.ts index 93dae4ee6..a924bb6be 100644 --- a/core/modules/catalog/events.ts +++ b/core/modules/catalog/events.ts @@ -6,6 +6,8 @@ import { AsyncDataLoader } from '@vue-storefront/core/lib/async-data-loader'; import { currentStoreView } from '@vue-storefront/core/lib/multistore'; import { formatProductLink } from '@vue-storefront/core/modules/url/helpers'; import { Logger } from '@vue-storefront/core/lib/logger'; +import { isServer } from '@vue-storefront/core/helpers'; +import { router } from '@vue-storefront/core/app' // Listeners moved from Product.js @@ -115,18 +117,20 @@ export const onUserPricesRefreshed = async (store, router) => { } } -export const checkConfigurableParent = (store) => { - const parentProduct = store.getters['product/getParentProduct'] - const currentProduct = store.getters['product/getCurrentProduct'] +export const checkParentRedirection = (currentProduct, parentProduct) => { if (parentProduct && parentProduct.id !== currentProduct.id && config.products.preventConfigurableChildrenDirectAccess) { Logger.log('Redirecting to parent, configurable product', parentProduct.sku)() const parentUrl = formatProductLink(parentProduct, currentStoreView().storeCode) - AsyncDataLoader.push({ - execute: async ({ context }) => { - if (context && !context.url.includes(parentUrl)) { - context.server.response.redirect(301, parentUrl) + if (isServer) { + AsyncDataLoader.push({ + execute: async ({ context }) => { + if (context && !context.url.includes(parentUrl)) { + context.server.response.redirect(301, parentUrl) + } } - } - }) + }) + } else { + router.replace(parentUrl as string) + } } } diff --git a/core/modules/catalog/store/product/actions.ts b/core/modules/catalog/store/product/actions.ts index 26a1363af..b8fbd4b32 100644 --- a/core/modules/catalog/store/product/actions.ts +++ b/core/modules/catalog/store/product/actions.ts @@ -32,6 +32,7 @@ import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus' import { StorageManager } from '@vue-storefront/core/lib/storage-manager' import { quickSearchByQuery } from '@vue-storefront/core/lib/search' import { formatProductLink } from 'core/modules/url/helpers' +import { checkParentRedirection } from '@vue-storefront/core/modules/catalog/events' const PRODUCT_REENTER_TIMEOUT = 20000 @@ -212,6 +213,7 @@ const actions: ActionTree = { if (resp.items.length >= 1) { const parentProduct = resp.items[0] context.commit(types.PRODUCT_SET_PARENT, parentProduct) + return parentProduct } }).catch((err) => { Logger.error(err)() @@ -640,7 +642,12 @@ const actions: ActionTree = { throw new Error(`Product query returned empty result product status = ${product.status}`) } if (product.visibility === 1) { // not visible individually (https://magento.stackexchange.com/questions/171584/magento-2-table-name-for-product-visibility) - throw new Error(`Product query returned empty result product visibility = ${product.visibility}`) + if (config.products.preventConfigurableChildrenDirectAccess) { + const parentProduct = await dispatch('checkConfigurableParent', { product }) + checkParentRedirection(product, parentProduct) + } else { + throw new Error(`Product query returned empty result product visibility = ${product.visibility}`) + } } await dispatch('loadProductAttributes', { product }) @@ -651,12 +658,6 @@ const actions: ActionTree = { syncPromises.push(variantsFilter) syncPromises.push(gallerySetup) } - if (config.products.preventConfigurableChildrenDirectAccess) { - const parentChecker = dispatch('checkConfigurableParent', { product }) - if (isServer) { - syncPromises.push(parentChecker) - } - } await Promise.all(syncPromises) await EventBus.$emitFilter('product-after-load', { store: rootStore, route: route }) return product diff --git a/src/themes/default/pages/Product.vue b/src/themes/default/pages/Product.vue index 9ef307a6d..95d040e8a 100644 --- a/src/themes/default/pages/Product.vue +++ b/src/themes/default/pages/Product.vue @@ -225,7 +225,6 @@ import { registerModule, isModuleRegistered } from '@vue-storefront/core/lib/mod import { onlineHelper, isServer } from '@vue-storefront/core/helpers' import { catalogHooksExecutors } from '@vue-storefront/core/modules/catalog-next/hooks' import ProductPrice from 'theme/components/core/ProductPrice.vue' -import { checkConfigurableParent } from '@vue-storefront/core/modules/catalog/events' export default { components: { @@ -338,7 +337,6 @@ export default { const loadBreadcrumbsPromise = store.dispatch('product/loadProductBreadcrumbs', { product }) if (isServer) await loadBreadcrumbsPromise catalogHooksExecutors.productPageVisited(product) - checkConfigurableParent(store) }, beforeRouteEnter (to, from, next) { if (isServer) { From 41c791b59939fbe4b86fa908ec0000aa95cfda9a Mon Sep 17 00:00:00 2001 From: tkostuch Date: Wed, 20 May 2020 10:32:34 +0200 Subject: [PATCH 21/36] use findConfigurableParent instead of checkConfigurableParent --- core/modules/catalog/store/product/actions.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/modules/catalog/store/product/actions.ts b/core/modules/catalog/store/product/actions.ts index b8fbd4b32..0f0c7e9fe 100644 --- a/core/modules/catalog/store/product/actions.ts +++ b/core/modules/catalog/store/product/actions.ts @@ -213,7 +213,6 @@ const actions: ActionTree = { if (resp.items.length >= 1) { const parentProduct = resp.items[0] context.commit(types.PRODUCT_SET_PARENT, parentProduct) - return parentProduct } }).catch((err) => { Logger.error(err)() @@ -643,7 +642,7 @@ const actions: ActionTree = { } if (product.visibility === 1) { // not visible individually (https://magento.stackexchange.com/questions/171584/magento-2-table-name-for-product-visibility) if (config.products.preventConfigurableChildrenDirectAccess) { - const parentProduct = await dispatch('checkConfigurableParent', { product }) + const parentProduct = await dispatch('findConfigurableParent', { product }) checkParentRedirection(product, parentProduct) } else { throw new Error(`Product query returned empty result product visibility = ${product.visibility}`) From 68b0a4b567a131853b6adc1d5d2ef54d8105e4d4 Mon Sep 17 00:00:00 2001 From: tkostuch Date: Wed, 20 May 2020 10:39:14 +0200 Subject: [PATCH 22/36] change skus to add proper configuration --- core/modules/catalog/events.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/modules/catalog/events.ts b/core/modules/catalog/events.ts index a924bb6be..f99f03716 100644 --- a/core/modules/catalog/events.ts +++ b/core/modules/catalog/events.ts @@ -120,6 +120,8 @@ export const onUserPricesRefreshed = async (store, router) => { export const checkParentRedirection = (currentProduct, parentProduct) => { if (parentProduct && parentProduct.id !== currentProduct.id && config.products.preventConfigurableChildrenDirectAccess) { Logger.log('Redirecting to parent, configurable product', parentProduct.sku)() + parentProduct.parentSku = parentProduct.sku + parentProduct.sku = currentProduct.sku const parentUrl = formatProductLink(parentProduct, currentStoreView().storeCode) if (isServer) { AsyncDataLoader.push({ From a34b9a20c4812db6775a92d30fd8ea1e87f2056d Mon Sep 17 00:00:00 2001 From: tkostuch Date: Mon, 25 May 2020 11:08:15 +0200 Subject: [PATCH 23/36] dont add shipping codes for virtual product --- core/modules/cart/helpers/createShippingInfoData.ts | 4 ++-- .../unit/helpers/createShippingInfoData.spec.ts | 13 +++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/core/modules/cart/helpers/createShippingInfoData.ts b/core/modules/cart/helpers/createShippingInfoData.ts index e42b0f19f..8395dcd81 100644 --- a/core/modules/cart/helpers/createShippingInfoData.ts +++ b/core/modules/cart/helpers/createShippingInfoData.ts @@ -6,8 +6,8 @@ const createShippingInfoData = (methodsData) => ({ billingAddress: { ...(methodsData.billingAddress ? methodsData.billingAddress : {}) }, - shippingCarrierCode: methodsData.carrier_code, - shippingMethodCode: methodsData.method_code + ...(methodsData.carrier_code ? { shippingCarrierCode: methodsData.carrier_code } : {}), + ...(methodsData.method_code ? { shippingMethodCode: methodsData.method_code } : {}) }); export default createShippingInfoData diff --git a/core/modules/cart/test/unit/helpers/createShippingInfoData.spec.ts b/core/modules/cart/test/unit/helpers/createShippingInfoData.spec.ts index ed2bfbfc8..3fbcf461f 100644 --- a/core/modules/cart/test/unit/helpers/createShippingInfoData.spec.ts +++ b/core/modules/cart/test/unit/helpers/createShippingInfoData.spec.ts @@ -76,4 +76,17 @@ describe('Cart createShippingInfoData', () => { shippingMethodCode: 'YY' }); }); + + it('doesn\t add shippingCarrierCode or shippingMethodCode if missing carrier_code or method_code', async () => { + const methodsData = { + country: 'UK' + }; + const shippingInfoData = createShippingInfoData(methodsData); + expect(shippingInfoData).toEqual({ + billingAddress: {}, + shippingAddress: { + countryId: 'UK' + } + }); + }); }); From 7f9955a8d85bb906ae4e51c974ba703bdb0eae90 Mon Sep 17 00:00:00 2001 From: tkostuch Date: Mon, 25 May 2020 11:59:12 +0200 Subject: [PATCH 24/36] change required to sameAs for checkbox --- src/themes/default/components/core/blocks/Auth/Register.vue | 4 ++-- .../default/components/core/blocks/Checkout/OrderReview.vue | 6 +++--- .../components/core/blocks/Checkout/PersonalDetails.vue | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/themes/default/components/core/blocks/Auth/Register.vue b/src/themes/default/components/core/blocks/Auth/Register.vue index 26b7cf410..3689f1442 100644 --- a/src/themes/default/components/core/blocks/Auth/Register.vue +++ b/src/themes/default/components/core/blocks/Auth/Register.vue @@ -113,7 +113,7 @@ @blur="$v.conditions.$reset()" @change="$v.conditions.$touch()" :validations="[{ - condition: !$v.conditions.required && $v.conditions.$error, + condition: !$v.conditions.sameAs && $v.conditions.$error, text: $t('You must accept the terms and conditions.') }]" > @@ -163,7 +163,7 @@ export default { sameAsPassword: sameAs('password') }, conditions: { - required + sameAs: sameAs(() => true) } }, mixins: [Register], diff --git a/src/themes/default/components/core/blocks/Checkout/OrderReview.vue b/src/themes/default/components/core/blocks/Checkout/OrderReview.vue index 0899de8ba..2731a02b4 100644 --- a/src/themes/default/components/core/blocks/Checkout/OrderReview.vue +++ b/src/themes/default/components/core/blocks/Checkout/OrderReview.vue @@ -42,7 +42,7 @@ @blur="$v.orderReview.terms.$touch()" v-model="orderReview.terms" :validations="[{ - condition: !$v.orderReview.terms.required && $v.orderReview.terms.$error, + condition: !$v.orderReview.terms.sameAs && $v.orderReview.terms.$error, text: $t('Field is required') }]" > @@ -108,7 +108,7 @@