From 6cee436a06b452b53e84f391504516ded1a84bc4 Mon Sep 17 00:00:00 2001 From: Oleksii Korshenko Date: Wed, 28 Sep 2016 17:43:35 -0500 Subject: [PATCH 1/4] MAGETWO-58035: [Backport] - Configurable product options not saved when editing - for 2.0 --- .../Checkout/CustomerData/DefaultItem.php | 1 + .../Model/Product/Type/Configurable.php | 8 +- .../Model/Product/Type/ConfigurableTest.php | 9 ++- ...ckout_cart_configure_type_configurable.xml | 3 + .../web/js/configurable-customer-data.js | 28 +++++++ .../view/frontend/web/js/configurable.js | 2 + .../view/frontend/web/js/options-updater.js | 77 +++++++++++++++++++ ...ckout_cart_configure_type_configurable.xml | 14 ++++ .../view/frontend/requirejs-config.js | 12 --- .../templates/product/layered/renderer.phtml | 2 +- .../templates/product/listing/renderer.phtml | 2 +- .../templates/product/view/renderer.phtml | 21 ++--- .../view/frontend/web/js/SwatchRenderer.js | 26 +++++++ .../web/js/configurable-customer-data.js | 28 +++++++ .../Model/Product/Type/ConfigurableTest.php | 12 +-- 15 files changed, 214 insertions(+), 31 deletions(-) create mode 100644 app/code/Magento/ConfigurableProduct/view/frontend/web/js/configurable-customer-data.js create mode 100644 app/code/Magento/ConfigurableProduct/view/frontend/web/js/options-updater.js create mode 100644 app/code/Magento/Swatches/view/frontend/layout/checkout_cart_configure_type_configurable.xml delete mode 100644 app/code/Magento/Swatches/view/frontend/requirejs-config.js create mode 100644 app/code/Magento/Swatches/view/frontend/web/js/configurable-customer-data.js diff --git a/app/code/Magento/Checkout/CustomerData/DefaultItem.php b/app/code/Magento/Checkout/CustomerData/DefaultItem.php index 887928ab34dda..e6b78a55e8db9 100644 --- a/app/code/Magento/Checkout/CustomerData/DefaultItem.php +++ b/app/code/Magento/Checkout/CustomerData/DefaultItem.php @@ -70,6 +70,7 @@ protected function doGetItemData() 'item_id' => $this->item->getId(), 'configure_url' => $this->getConfigureUrl(), 'is_visible_in_site_visibility' => $this->item->getProduct()->isVisibleInSiteVisibility(), + 'product_id' => $this->item->getProduct()->getId(), 'product_name' => $this->item->getProduct()->getName(), 'product_url' => $this->getProductUrl(), 'product_has_url' => $this->hasProductUrl(), diff --git a/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php b/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php index bcb6ed462c45d..17cda65d76da2 100644 --- a/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php +++ b/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php @@ -818,9 +818,15 @@ public function getSelectedAttributesInfo($product) $value = $value->getSource()->getOptionText($attributeValue); } else { $value = ''; + $attributeValue = ''; } - $attributes[] = ['label' => $label, 'value' => $value]; + $attributes[] = [ + 'label' => $label, + 'value' => $value, + 'option_id' => $attributeId, + 'option_value' => $attributeValue, + ]; } } } diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Product/Type/ConfigurableTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Product/Type/ConfigurableTest.php index 2ff10098c1cf3..92952e9556481 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Product/Type/ConfigurableTest.php +++ b/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Product/Type/ConfigurableTest.php @@ -564,7 +564,14 @@ public function testGetSelectedAttributesInfo() $this->assertEquals( $this->_model->getSelectedAttributesInfo($productMock), - [['label' => 'attr_store_label', 'value' => '']] + [ + [ + 'label' => 'attr_store_label', + 'value' => '', + 'option_id' => 1, + 'option_value' => '' + ] + ] ); } diff --git a/app/code/Magento/ConfigurableProduct/view/frontend/layout/checkout_cart_configure_type_configurable.xml b/app/code/Magento/ConfigurableProduct/view/frontend/layout/checkout_cart_configure_type_configurable.xml index bd61a5d5db520..41655260017b1 100644 --- a/app/code/Magento/ConfigurableProduct/view/frontend/layout/checkout_cart_configure_type_configurable.xml +++ b/app/code/Magento/ConfigurableProduct/view/frontend/layout/checkout_cart_configure_type_configurable.xml @@ -6,6 +6,9 @@ */ --> + + + diff --git a/app/code/Magento/ConfigurableProduct/view/frontend/web/js/configurable-customer-data.js b/app/code/Magento/ConfigurableProduct/view/frontend/web/js/configurable-customer-data.js new file mode 100644 index 0000000000000..7316f7b75e8be --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/view/frontend/web/js/configurable-customer-data.js @@ -0,0 +1,28 @@ +require([ + 'jquery', + 'Magento_ConfigurableProduct/js/options-updater' +], function ($, Updater) { + 'use strict'; + + var selectors = { + formSelector: '#product_addtocart_form' + }, + configurableWidgetName = 'mageConfigurable', + widgetInitEvent = 'configurable.initialized', + + /** + * Sets all configurable attribute's selected values + */ + updateConfigurableOptions = function () { + var configurableWidget = $(selectors.formSelector).data(configurableWidgetName); + + if (!configurableWidget) { + return; + } + configurableWidget.options.values = this.productOptions || {}; + configurableWidget._configureForValues(); + }, + updater = new Updater(widgetInitEvent, updateConfigurableOptions); + + updater.listen(); +}); diff --git a/app/code/Magento/ConfigurableProduct/view/frontend/web/js/configurable.js b/app/code/Magento/ConfigurableProduct/view/frontend/web/js/configurable.js index aa98309b2f244..b6a3948a28c5e 100644 --- a/app/code/Magento/ConfigurableProduct/view/frontend/web/js/configurable.js +++ b/app/code/Magento/ConfigurableProduct/view/frontend/web/js/configurable.js @@ -53,6 +53,8 @@ define([ // Setup/configure values to inputs this._configureForValues(); + + $(this.element).trigger('configurable.initialized'); }, /** diff --git a/app/code/Magento/ConfigurableProduct/view/frontend/web/js/options-updater.js b/app/code/Magento/ConfigurableProduct/view/frontend/web/js/options-updater.js new file mode 100644 index 0000000000000..64aefc27dc080 --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/view/frontend/web/js/options-updater.js @@ -0,0 +1,77 @@ +define([ + 'jquery', + 'Magento_Customer/js/customer-data' +], function ($, customerData) { + 'use strict'; + + var selectors = { + formSelector: '#product_addtocart_form', + productIdSelector: '#product_addtocart_form [name="product"]' + }, + cartData = customerData.get('cart'), + productId = $(selectors.productIdSelector).val(), + + /** + * set productOptions according to cart data from customer-data + * + * @param {Object} data - cart data from customer-data + * @returns {Boolean} - whether the new options differ from previous + */ + setProductOptions = function (data) { + var changedProductOptions; + + if (!(data && data.items && data.items.length && productId)) { + return false; + } + changedProductOptions = data.items.find(function (item) { + return item['product_id'] === productId; + }); + changedProductOptions = changedProductOptions && changedProductOptions.options && + changedProductOptions.options.reduce(function (obj, val) { + obj[val['option_id']] = val['option_value']; + + return obj; + }, {}); + + if (JSON.stringify(this.productOptions || {}) === JSON.stringify(changedProductOptions || {})) { + return false; + } + + this.productOptions = changedProductOptions; + + return true; + }, + + /** + * Listens to update of cart data or options initialization and update selected option according to customer data + * + */ + listen = function () { + cartData.subscribe(function (updateCartData) { + if (this.setProductOptions(updateCartData)) { + this.updateOptions(); + } + }.bind(this)); + $(selectors.formSelector).on(this.eventName, function () { + this.setProductOptions(cartData()); + this.updateOptions(); + }.bind(this)); + }, + + /** + * Updater constructor function + * + */ + Updater = function (eventName, updateOptionsCallback) { + if (this instanceof Updater) { + this.eventName = eventName; + this.updateOptions = updateOptionsCallback; + this.productOptions = {}; + } + }; + + Updater.prototype.setProductOptions = setProductOptions; + Updater.prototype.listen = listen; + + return Updater; +}); diff --git a/app/code/Magento/Swatches/view/frontend/layout/checkout_cart_configure_type_configurable.xml b/app/code/Magento/Swatches/view/frontend/layout/checkout_cart_configure_type_configurable.xml new file mode 100644 index 0000000000000..accd5e81277e0 --- /dev/null +++ b/app/code/Magento/Swatches/view/frontend/layout/checkout_cart_configure_type_configurable.xml @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/app/code/Magento/Swatches/view/frontend/requirejs-config.js b/app/code/Magento/Swatches/view/frontend/requirejs-config.js deleted file mode 100644 index 3a8dc64d13d2d..0000000000000 --- a/app/code/Magento/Swatches/view/frontend/requirejs-config.js +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Copyright © 2016 Magento. All rights reserved. - * See COPYING.txt for license details. - */ - -var config = { - map: { - '*': { - swatchRenderer: 'Magento_Swatches/js/SwatchRenderer' - } - } -}; \ No newline at end of file diff --git a/app/code/Magento/Swatches/view/frontend/templates/product/layered/renderer.phtml b/app/code/Magento/Swatches/view/frontend/templates/product/layered/renderer.phtml index 5f26d947a5d4f..78c1b50da9fa3 100644 --- a/app/code/Magento/Swatches/view/frontend/templates/product/layered/renderer.phtml +++ b/app/code/Magento/Swatches/view/frontend/templates/product/layered/renderer.phtml @@ -69,7 +69,7 @@ diff --git a/app/code/Magento/Swatches/view/frontend/web/js/SwatchRenderer.js b/app/code/Magento/Swatches/view/frontend/web/js/SwatchRenderer.js index 2549d4d9b62cf..9859a3c74236a 100644 --- a/app/code/Magento/Swatches/view/frontend/web/js/SwatchRenderer.js +++ b/app/code/Magento/Swatches/view/frontend/web/js/SwatchRenderer.js @@ -191,6 +191,7 @@ define(['jquery', 'underscore', 'jquery/ui'], function ($, _) { _init: function () { if (this.options.jsonConfig != '' && this.options.jsonSwatchConfig != '') { this._RenderControls(); + $(this.element).trigger('swatch.initialized'); } else { console.log('SwatchRenderer: No input data received'); } @@ -834,6 +835,30 @@ define(['jquery', 'underscore', 'jquery/ui'], function ($, _) { }); }, + /** + * Emulate mouse click or selection change on all swatches that should be selected + * @param {Object} [selectedAttributes] + * @private + */ + _EmulateSelectedByAttributeId: function (selectedAttributes) { + $.each(selectedAttributes, $.proxy(function (attributeId, optionId) { + var elem = this.element.find('.' + this.options.classes.attributeClass + + '[attribute-id="' + attributeId + '"] [option-id="' + optionId + '"]'), + parentInput = elem.parent(); + + if (elem.hasClass('selected')) { + return; + } + + if (parentInput.hasClass(this.options.classes.selectClass)) { + parentInput.val(optionId); + parentInput.trigger('change'); + } else { + elem.trigger('click'); + } + }, this)); + }, + /** * Returns an array/object's length * @param obj @@ -851,4 +876,5 @@ define(['jquery', 'underscore', 'jquery/ui'], function ($, _) { return size; } }); + return $.custom.SwatchRenderer; }); diff --git a/app/code/Magento/Swatches/view/frontend/web/js/configurable-customer-data.js b/app/code/Magento/Swatches/view/frontend/web/js/configurable-customer-data.js new file mode 100644 index 0000000000000..43d31fabecea1 --- /dev/null +++ b/app/code/Magento/Swatches/view/frontend/web/js/configurable-customer-data.js @@ -0,0 +1,28 @@ +require([ + 'jquery', + 'Magento_ConfigurableProduct/js/options-updater' +], function ($, Updater) { + 'use strict'; + + var selectors = { + formSelector: '#product_addtocart_form', + swatchSelector: '.swatch-opt' + }, + swatchWidgetName = 'customSwatchRenderer', + widgetInitEvent = 'swatch.initialized', + + /** + * Sets all configurable swatch attribute's selected values + */ + updateSwatchOptions = function () { + var swatchWidget = $(selectors.swatchSelector).data(swatchWidgetName); + + if (!swatchWidget || !swatchWidget._EmulateSelectedByAttributeId) { + return; + } + swatchWidget._EmulateSelectedByAttributeId(this.productOptions); + }, + updater = new Updater(widgetInitEvent, updateSwatchOptions); + + updater.listen(); +}); diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/Product/Type/ConfigurableTest.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/Product/Type/ConfigurableTest.php index 0b4c736b40991..eb942ad392d19 100644 --- a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/Product/Type/ConfigurableTest.php +++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/Product/Type/ConfigurableTest.php @@ -239,7 +239,8 @@ public function testGetSelectedAttributesInfo() $this->_product->addCustomOption('attributes', serialize([$attribute['attribute_id'] => $optionValueId])); $info = $this->_model->getSelectedAttributesInfo($this->_product); - $this->assertEquals([['label' => 'Test Configurable', 'value' => 'Option 1']], $info); + $this->assertEquals('Test Configurable', $info[0]['label']); + $this->assertEquals('Option 1', $info[0]['value']); } /** @@ -259,7 +260,8 @@ public function testGetSelectedAttributesInfoForStore() $attribute->getProductAttribute()->setStoreLabel('store label'); $info = $this->_model->getSelectedAttributesInfo($this->_product); - $this->assertEquals([['label' => 'store label', 'value' => 'Option 1']], $info); + $this->assertEquals('store label', $info[0]['label']); + $this->assertEquals('Option 1', $info[0]['value']); } /** @@ -302,10 +304,8 @@ public function testGetOrderOptions() $result = $this->_model->getOrderOptions($this->_product); $this->assertArrayHasKey('info_buyRequest', $result); $this->assertArrayHasKey('attributes_info', $result); - $this->assertEquals( - [['label' => 'Test Configurable', 'value' => 'Option 1']], - $result['attributes_info'] - ); + $this->assertEquals('Test Configurable', $result['attributes_info'][0]['label']); + $this->assertEquals('Option 1', $result['attributes_info'][0]['value']); $this->assertArrayHasKey('product_calculations', $result); $this->assertArrayHasKey('shipment_type', $result); $this->assertEquals( From cf98306c43f440f721eedd510e45d4af6e39baf1 Mon Sep 17 00:00:00 2001 From: Oleksii Korshenko Date: Fri, 30 Sep 2016 10:54:08 -0500 Subject: [PATCH 2/4] MAGETWO-58035: [Backport] - Configurable product options not saved when editing - for 2.0 - fixed static tests --- .../view/frontend/web/js/configurable-customer-data.js | 5 +++++ .../view/frontend/web/js/options-updater.js | 5 +++++ .../view/frontend/templates/product/view/renderer.phtml | 4 ++-- .../view/frontend/web/js/configurable-customer-data.js | 5 +++++ 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/ConfigurableProduct/view/frontend/web/js/configurable-customer-data.js b/app/code/Magento/ConfigurableProduct/view/frontend/web/js/configurable-customer-data.js index 7316f7b75e8be..434d2ee1f30fa 100644 --- a/app/code/Magento/ConfigurableProduct/view/frontend/web/js/configurable-customer-data.js +++ b/app/code/Magento/ConfigurableProduct/view/frontend/web/js/configurable-customer-data.js @@ -1,3 +1,8 @@ +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + require([ 'jquery', 'Magento_ConfigurableProduct/js/options-updater' diff --git a/app/code/Magento/ConfigurableProduct/view/frontend/web/js/options-updater.js b/app/code/Magento/ConfigurableProduct/view/frontend/web/js/options-updater.js index 64aefc27dc080..cb467915c998b 100644 --- a/app/code/Magento/ConfigurableProduct/view/frontend/web/js/options-updater.js +++ b/app/code/Magento/ConfigurableProduct/view/frontend/web/js/options-updater.js @@ -1,3 +1,8 @@ +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + define([ 'jquery', 'Magento_Customer/js/customer-data' diff --git a/app/code/Magento/Swatches/view/frontend/templates/product/view/renderer.phtml b/app/code/Magento/Swatches/view/frontend/templates/product/view/renderer.phtml index 1f718ff8d82f9..e231a89824ccd 100644 --- a/app/code/Magento/Swatches/view/frontend/templates/product/view/renderer.phtml +++ b/app/code/Magento/Swatches/view/frontend/templates/product/view/renderer.phtml @@ -11,8 +11,8 @@ { "[data-role=swatch-options]": { "Magento_Swatches/js/swatchRenderer": { - "jsonConfig": getJsonConfig(); ?>, - "jsonSwatchConfig": getJsonSwatchConfig(); ?>, + "jsonConfig": getJsonConfig(); ?>, + "jsonSwatchConfig": getJsonSwatchConfig(); ?>, "mediaCallback": "getMediaCallback() ?>" } } diff --git a/app/code/Magento/Swatches/view/frontend/web/js/configurable-customer-data.js b/app/code/Magento/Swatches/view/frontend/web/js/configurable-customer-data.js index 43d31fabecea1..7ae2477513cf6 100644 --- a/app/code/Magento/Swatches/view/frontend/web/js/configurable-customer-data.js +++ b/app/code/Magento/Swatches/view/frontend/web/js/configurable-customer-data.js @@ -1,3 +1,8 @@ +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + require([ 'jquery', 'Magento_ConfigurableProduct/js/options-updater' From c7353f2646039698031d74d8ea745d9f9304d8e5 Mon Sep 17 00:00:00 2001 From: Oleksii Korshenko Date: Wed, 5 Oct 2016 16:56:53 -0500 Subject: [PATCH 3/4] MAGETWO-59102: Bundle Products - The options you selected are not available - for 2.0.x --- .../Magento/Bundle/Model/Product/Type.php | 12 +- .../Test/Unit/Model/Product/TypeTest.php | 148 +++--------------- 2 files changed, 27 insertions(+), 133 deletions(-) diff --git a/app/code/Magento/Bundle/Model/Product/Type.php b/app/code/Magento/Bundle/Model/Product/Type.php index 5d8d7c2bba8a1..9a289fdc0c9cc 100644 --- a/app/code/Magento/Bundle/Model/Product/Type.php +++ b/app/code/Magento/Bundle/Model/Product/Type.php @@ -716,6 +716,12 @@ protected function _prepareProduct(\Magento\Framework\DataObject $buyRequest, $p if (!empty($selectionIds)) { $selections = $this->getSelectionsByIds($selectionIds, $product); + if (count($selections->getItems()) !== count($selectionIds)) { + throw new \Magento\Framework\Exception\LocalizedException( + __('The options you selected are not available.') + ); + } + // Check if added selections are still on sale $this->checkSelectionsIsSale( $selections, @@ -888,12 +894,6 @@ public function getSelectionsByIds($selectionIds, $product) ->addFilterByRequiredOptions() ->setSelectionIdsFilter($selectionIds); - if (count($usedSelections->getItems()) !== count($selectionIds)) { - throw new \Magento\Framework\Exception\LocalizedException( - __('The options you selected are not available.') - ); - } - if (!$this->_catalogData->isPriceGlobal() && $storeId) { $websiteId = $this->_storeManager->getStore($storeId) ->getWebsiteId(); diff --git a/app/code/Magento/Bundle/Test/Unit/Model/Product/TypeTest.php b/app/code/Magento/Bundle/Test/Unit/Model/Product/TypeTest.php index 106c9879fbb7b..c60c0f33d189c 100644 --- a/app/code/Magento/Bundle/Test/Unit/Model/Product/TypeTest.php +++ b/app/code/Magento/Bundle/Test/Unit/Model/Product/TypeTest.php @@ -377,7 +377,7 @@ function ($key) use ($optionCollection, $selectionCollection) { $resultValue = $selectionCollection; break; case '_cache_instance_used_selections_ids': - $resultValue = [2, 5, 14]; + $resultValue = [5]; break; } @@ -402,7 +402,7 @@ function ($key) use ($optionCollection, $selectionCollection) { ->method('setStoreFilter'); $buyRequest->expects($this->once()) ->method('getBundleOption') - ->willReturn([3 => 5, 10 => [7 => 2, 11 => 14]]); + ->willReturn([3 => 5]); $selectionCollection->expects($this->any()) ->method('getItems') ->willReturn([$selection]); @@ -431,13 +431,13 @@ function ($key) use ($optionCollection, $selectionCollection) { ->willReturn($productType); $option->expects($this->at(3)) ->method('getId') - ->willReturn(10); + ->willReturn(3); $option->expects($this->at(9)) ->method('getId') - ->willReturn(10); + ->willReturn(3); $option->expects($this->once()) ->method('getRequired') - ->willReturn(true); + ->willReturn(false); $option->expects($this->once()) ->method('isMultiSelection') ->willReturn(true); @@ -608,7 +608,7 @@ function ($key) use ($optionCollection, $selectionCollection) { $resultValue = $selectionCollection; break; case '_cache_instance_used_selections_ids': - $resultValue = [2, 5, 14]; + $resultValue = [5]; break; } @@ -633,7 +633,7 @@ function ($key) use ($optionCollection, $selectionCollection) { ->method('setStoreFilter'); $buyRequest->expects($this->once()) ->method('getBundleOption') - ->willReturn([3 => 5, 10 => [7 => 2, 11 => 14]]); + ->willReturn([3 => 5]); $selectionCollection->expects($this->any()) ->method('getItems') ->willReturn([$selection]); @@ -662,13 +662,13 @@ function ($key) use ($optionCollection, $selectionCollection) { ->willReturn($productType); $option->expects($this->at(3)) ->method('getId') - ->willReturn(10); + ->willReturn(3); $option->expects($this->at(9)) ->method('getId') - ->willReturn(10); + ->willReturn(3); $option->expects($this->once()) ->method('getRequired') - ->willReturn(true); + ->willReturn(false); $option->expects($this->once()) ->method('isMultiSelection') ->willReturn(true); @@ -827,7 +827,7 @@ function ($key) use ($optionCollection, $selectionCollection) { $resultValue = $selectionCollection; break; case '_cache_instance_used_selections_ids': - $resultValue = [2, 5, 14]; + $resultValue = [5]; break; } @@ -852,7 +852,7 @@ function ($key) use ($optionCollection, $selectionCollection) { ->method('setStoreFilter'); $buyRequest->expects($this->once()) ->method('getBundleOption') - ->willReturn([3 => 5, 10 => [7 => 2, 11 => 14]]); + ->willReturn([3 => 5]); $selectionCollection->expects($this->any()) ->method('getItems') ->willReturn([$selection]); @@ -881,13 +881,13 @@ function ($key) use ($optionCollection, $selectionCollection) { ->willReturn($productType); $option->expects($this->at(3)) ->method('getId') - ->willReturn(10); + ->willReturn(3); $option->expects($this->at(9)) ->method('getId') - ->willReturn(10); + ->willReturn(3); $option->expects($this->once()) ->method('getRequired') - ->willReturn(true); + ->willReturn(false); $option->expects($this->once()) ->method('isMultiSelection') ->willReturn(true); @@ -1112,41 +1112,29 @@ function ($key) use ($optionCollection, $selectionCollection) { $resultValue = $selectionCollection; break; case '_cache_instance_used_selections_ids': - $resultValue = [2, 5, 14]; + $resultValue = [5]; break; } return $resultValue; } ); - $optionCollection->expects($this->once()) - ->method('getItemById') - ->willReturn($option); $optionCollection->expects($this->once()) ->method('appendSelections'); $productType->expects($this->once()) ->method('setStoreFilter'); $buyRequest->expects($this->once()) ->method('getBundleOption') - ->willReturn([3 => 5, 10 => [7 => 2, 11 => 14]]); + ->willReturn([3 => 5]); $selectionCollection->expects($this->at(0)) ->method('getItems') ->willReturn([$selection]); $selectionCollection->expects($this->at(1)) ->method('getItems') ->willReturn([]); - $selection->expects($this->once()) - ->method('isSalable') - ->willReturn(false); - $option->expects($this->at(3)) + $option->expects($this->any()) ->method('getId') - ->willReturn(10); - $option->expects($this->once()) - ->method('getRequired') - ->willReturn(true); - $option->expects($this->once()) - ->method('isMultiSelection') - ->willReturn(true); + ->willReturn(3); $result = $this->model->prepareForCartAdvanced($buyRequest, $product); $this->assertEquals('Please specify product option(s).', $result); @@ -1255,7 +1243,7 @@ function ($key) use ($optionCollection, $selectionCollection) { $buyRequest->expects($this->once()) ->method('getBundleOption') ->willReturn([3 => 5]); - $selectionCollection->expects($this->once()) + $selectionCollection->expects($this->any()) ->method('getItems') ->willReturn([$selection]); $selection->expects($this->once()) @@ -1901,8 +1889,7 @@ public function testGetSelectionsByIds() 'setPositionOrder', 'addFilterByRequiredOptions', 'setSelectionIdsFilter', - 'joinPrices', - 'getItems' + 'joinPrices' ] ) ->disableOriginalConstructor() @@ -1971,9 +1958,6 @@ public function testGetSelectionsByIds() ->method('setSelectionIdsFilter') ->with($selectionIds) ->will($this->returnSelf()); - $usedSelectionsMock->expects($this->once()) - ->method('getItems') - ->willReturn($usedSelectionsIds); $usedSelectionsMock->expects($this->once()) ->method('joinPrices') @@ -1987,96 +1971,6 @@ public function testGetSelectionsByIds() $this->model->getSelectionsByIds($selectionIds, $productMock); } - /** - * @expectedException \Magento\Framework\Exception\LocalizedException - * @expectedExceptionMessage The options you selected are not available. - * - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) - */ - public function testGetSelectionsByIdsException() - { - $selectionIds = [1, 2, 3]; - $usedSelectionsIds = [4, 5]; - $storeId = 2; - $storeFilter = 'store_filter'; - $productMock = $this->getMockBuilder('Magento\Catalog\Model\Product') - ->disableOriginalConstructor() - ->getMock(); - $usedSelectionsMock = $this->getMockBuilder('Magento\Bundle\Model\ResourceModel\Selection\Collection') - ->setMethods( - [ - 'addAttributeToSelect', - 'setFlag', - 'addStoreFilter', - 'setStoreId', - 'setPositionOrder', - 'addFilterByRequiredOptions', - 'setSelectionIdsFilter', - 'joinPrices', - 'getItems' - ] - ) - ->disableOriginalConstructor() - ->getMock(); - $productGetMap = [ - ['_cache_instance_used_selections', null, null], - ['_cache_instance_used_selections_ids', null, $usedSelectionsIds], - ['_cache_instance_store_filter', null, $storeFilter], - ]; - $productMock->expects($this->any()) - ->method('getData') - ->will($this->returnValueMap($productGetMap)); - $productSetMap = [ - ['_cache_instance_used_selections', $usedSelectionsMock, $productMock], - ['_cache_instance_used_selections_ids', $selectionIds, $productMock], - ]; - $productMock->expects($this->any()) - ->method('setData') - ->will($this->returnValueMap($productSetMap)); - $productMock->expects($this->once()) - ->method('getStoreId') - ->will($this->returnValue($storeId)); - - $this->bundleCollection->expects($this->once()) - ->method('create') - ->will($this->returnValue($usedSelectionsMock)); - - $usedSelectionsMock->expects($this->once()) - ->method('addAttributeToSelect') - ->with('*') - ->will($this->returnSelf()); - $flagMap = [ - ['require_stock_items', true, $usedSelectionsMock], - ['product_children', true, $usedSelectionsMock], - ]; - $usedSelectionsMock->expects($this->any()) - ->method('setFlag') - ->will($this->returnValueMap($flagMap)); - $usedSelectionsMock->expects($this->once()) - ->method('addStoreFilter') - ->with($storeFilter) - ->will($this->returnSelf()); - $usedSelectionsMock->expects($this->once()) - ->method('setStoreId') - ->with($storeId) - ->will($this->returnSelf()); - $usedSelectionsMock->expects($this->once()) - ->method('setPositionOrder') - ->will($this->returnSelf()); - $usedSelectionsMock->expects($this->once()) - ->method('addFilterByRequiredOptions') - ->will($this->returnSelf()); - $usedSelectionsMock->expects($this->once()) - ->method('setSelectionIdsFilter') - ->with($selectionIds) - ->will($this->returnSelf()); - $usedSelectionsMock->expects($this->once()) - ->method('getItems') - ->willReturn($usedSelectionsIds); - - - $this->model->getSelectionsByIds($selectionIds, $productMock); - } /** * @return void */ From 726635e948fb66ff109ff8148701e12e808aa77a Mon Sep 17 00:00:00 2001 From: Oleksii Korshenko Date: Thu, 6 Oct 2016 11:03:17 -0500 Subject: [PATCH 4/4] MAGETWO-59102: Bundle Products - The options you selected are not available - for 2.0.x --- .../Magento/Bundle/Model/Product/TypeTest.php | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/TypeTest.php b/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/TypeTest.php index 03abeaf837ff7..e2d835c07d4b2 100644 --- a/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/TypeTest.php +++ b/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/TypeTest.php @@ -62,4 +62,97 @@ public function testPrepareProductIndexForBundleProduct() $result = $this->connectionMock->fetchAll($select); $this->assertCount(1, $result); } + + /** + * Test that having valid buyRequest it can be successfully prepared fro shopping cart + * + * @magentoDataFixture Magento/Bundle/_files/product_with_multiple_options.php + * @magentoAppArea frontend + * @magentoAppIsolation enabled + */ + public function testPrepareForCart() + { + /** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */ + $productRepository = $this->objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); + $product = $productRepository->get('bundle-product'); + + /** @var \Magento\Bundle\Api\ProductOptionRepositoryInterface $optionsRepository */ + $optionsRepository = $this->objectManager->create(\Magento\Bundle\Api\ProductOptionRepositoryInterface::class); + $options = $optionsRepository->getList($product->getSku()); + + $data = [ + 'id' => '10', + 'product' => '3', + 'selected_configurable_option' => '', + 'related_product' => '', + 'bundle_option' => [], + 'bundle_option_qty' => [], + 'qty' => '1', + 'options' => [], + 'reset_count' => true, + ]; + + foreach ($options as $option) { + /** @var \Magento\Bundle\Api\Data\LinkInterface $link */ + $link = current($option->getProductLinks()); + $data['bundle_option'][$option->getOptionId()] = $link->getId(); + $data['bundle_option_qty'][$option->getOptionId()] = 1; + } + + $request = $this->objectManager->create(\Magento\Framework\DataObject::class, ['data' => $data]); + /** @var \Magento\Bundle\Model\Product\Type $typeInstance */ + $typeInstance = $product->getTypeInstance(); + + $result = $typeInstance->prepareForCart($request, $product); + $this->assertEquals(count($data['bundle_option']) + 1, count($result), 'Incorrect product count'); + } + + /** + * Test that having invalid selection option in buyRequest + * prepareForCart method will return meaningful error message + * + * @magentoDataFixture Magento/Bundle/_files/product_with_multiple_options.php + * @magentoAppArea frontend + * @magentoAppIsolation enabled + */ + public function testPrepareForCartWithUnavailableOption() + { + /** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */ + $productRepository = $this->objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); + $product = $productRepository->get('bundle-product'); + + /** @var \Magento\Bundle\Api\ProductOptionRepositoryInterface $optionsRepository */ + $optionsRepository = $this->objectManager->create(\Magento\Bundle\Api\ProductOptionRepositoryInterface::class); + $options = $optionsRepository->getList($product->getSku()); + + $data = [ + 'id' => '10', + 'product' => '3', + 'selected_configurable_option' => '', + 'related_product' => '', + 'bundle_option' => [], + 'bundle_option_qty' => [], + 'qty' => '1', + 'options' => [], + 'reset_count' => true, + ]; + + $option = null; + foreach ($options as $option) { + /** @var \Magento\Bundle\Api\Data\LinkInterface $link */ + $link = current($option->getProductLinks()); + $data['bundle_option'][$option->getOptionId()] = $link->getId(); + $data['bundle_option_qty'][$option->getOptionId()] = 1; + } + + /** Set latest option selection to unavailable option */ + $data['bundle_option'][$option->getOptionId()] = 300; + + $buyRequest = $this->objectManager->create(\Magento\Framework\DataObject::class, ['data' => $data]); + /** @var \Magento\Bundle\Model\Product\Type $typeInstance */ + $typeInstance = $product->getTypeInstance(); + + $result = $typeInstance->prepareForCart($buyRequest, $product); + $this->assertEquals('The options you selected are not available.', $result); + } }