From 8e55868e05ad2f64d93410d79f390f0bd494c388 Mon Sep 17 00:00:00 2001 From: Anton Ohorodnyk Date: Mon, 18 Apr 2016 21:22:32 +0300 Subject: [PATCH 01/22] MAGETWO-51210: Can't save qty more than 10000000 after loading saved product --- .../Product/Initialization/StockDataFilter.php | 2 +- .../Product/Form/Modifier/AdvancedInventory.php | 1 + .../view/adminhtml/ui_component/product_form.xml | 1 + .../web/js/components/qty-validator-changer.js | 1 + .../Ui/view/base/web/js/lib/validation/rules.js | 16 ++++++++-------- 5 files changed, 12 insertions(+), 9 deletions(-) diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Initialization/StockDataFilter.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Initialization/StockDataFilter.php index 7ad9c3f4d888d..805800c7bc2ac 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Initialization/StockDataFilter.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Initialization/StockDataFilter.php @@ -16,7 +16,7 @@ class StockDataFilter /** * The greatest value which could be stored in CatalogInventory Qty field */ - const MAX_QTY_VALUE = 99999999.9999; + const MAX_QTY_VALUE = 99999999; /** * @var ScopeConfigInterface diff --git a/app/code/Magento/CatalogInventory/Ui/DataProvider/Product/Form/Modifier/AdvancedInventory.php b/app/code/Magento/CatalogInventory/Ui/DataProvider/Product/Form/Modifier/AdvancedInventory.php index 7a81ad48398bf..9be1ef6066122 100644 --- a/app/code/Magento/CatalogInventory/Ui/DataProvider/Product/Form/Modifier/AdvancedInventory.php +++ b/app/code/Magento/CatalogInventory/Ui/DataProvider/Product/Form/Modifier/AdvancedInventory.php @@ -188,6 +188,7 @@ private function prepareMeta() 'validation' => [ 'validate-number' => true, 'validate-digits' => true, + 'less-than-equals-to' => 99999999, ], 'imports' => [ 'handleChanges' => '${$.provider}:data.product.stock_data.is_qty_decimal', diff --git a/app/code/Magento/CatalogInventory/view/adminhtml/ui_component/product_form.xml b/app/code/Magento/CatalogInventory/view/adminhtml/ui_component/product_form.xml index 47d1ca2346d4c..42903c49e9c9a 100644 --- a/app/code/Magento/CatalogInventory/view/adminhtml/ui_component/product_form.xml +++ b/app/code/Magento/CatalogInventory/view/adminhtml/ui_component/product_form.xml @@ -86,6 +86,7 @@ true true + 99999999 200 [GLOBAL] diff --git a/app/code/Magento/CatalogInventory/view/adminhtml/web/js/components/qty-validator-changer.js b/app/code/Magento/CatalogInventory/view/adminhtml/web/js/components/qty-validator-changer.js index b10711671d502..b14527c9c9ec6 100644 --- a/app/code/Magento/CatalogInventory/view/adminhtml/web/js/components/qty-validator-changer.js +++ b/app/code/Magento/CatalogInventory/view/adminhtml/web/js/components/qty-validator-changer.js @@ -21,6 +21,7 @@ define([ this.validation['validate-number'] = !isDigits; this.validation['validate-digits'] = isDigits; + this.validation['less-than-equals-to'] = isDigits ? 99999999 : 99999999.9999; this.validate(); } }); diff --git a/app/code/Magento/Ui/view/base/web/js/lib/validation/rules.js b/app/code/Magento/Ui/view/base/web/js/lib/validation/rules.js index 7ab8c6f3258e9..b1665f3fdfc39 100644 --- a/app/code/Magento/Ui/view/base/web/js/lib/validation/rules.js +++ b/app/code/Magento/Ui/view/base/web/js/lib/validation/rules.js @@ -702,26 +702,26 @@ define([ ], "less-than-equals-to": [ function(value, params) { - if ($.isNumeric($(params).val()) && $.isNumeric(value)) { - this.lteToVal = $(params).val(); - return parseFloat(value) <= parseFloat($(params).val()); + if ($.isNumeric(params) && $.isNumeric(value)) { + this.lteToVal = params; + return parseFloat(value) <= parseFloat(params); } return true; }, function() { - return 'Please enter a value less than or equal to %s.'.replace('%s', this.lteToVal); + return $.mage.__('Please enter a value less than or equal to {0}.'); } ], "greater-than-equals-to": [ function(value, params) { - if ($.isNumeric($(params).val()) && $.isNumeric(value)) { - this.gteToVal = $(params).val(); - return parseFloat(value) >= parseFloat($(params).val()); + if ($.isNumeric(params) && $.isNumeric(value)) { + this.gteToVal = params; + return parseFloat(value) >= parseFloat(params); } return true; }, function() { - return 'Please enter a value greater than or equal to %s.'.replace('%s', this.gteToVal); + return $.mage.__('Please enter a value greater than or equal to {0}.'); } ], "validate-emails": [ From 39f18b8718ad28dcb4a2359090e459476f9371ee Mon Sep 17 00:00:00 2001 From: Illia Grybkov Date: Wed, 20 Apr 2016 17:27:08 +0300 Subject: [PATCH 02/22] MAGETWO-50571: [Configurable product] Newly created attributes are non-usable in attributes grid --- .../Product/Attribute/Edit/Tab/Main.php | 4 +- .../Adminhtml/Product/Attribute.php | 2 +- .../HideUnsupportedAttributeTypes.php | 68 +++++++ .../HideUnsupportedAttributeTypesTest.php | 175 ++++++++++++++++++ .../etc/adminhtml/events.xml | 12 ++ 5 files changed, 258 insertions(+), 3 deletions(-) create mode 100644 app/code/Magento/ConfigurableProduct/Observer/HideUnsupportedAttributeTypes.php create mode 100644 app/code/Magento/ConfigurableProduct/Test/Unit/Observer/HideUnsupportedAttributeTypesTest.php create mode 100644 app/code/Magento/ConfigurableProduct/etc/adminhtml/events.xml diff --git a/app/code/Magento/Catalog/Block/Adminhtml/Product/Attribute/Edit/Tab/Main.php b/app/code/Magento/Catalog/Block/Adminhtml/Product/Attribute/Edit/Tab/Main.php index 8fe925252dc42..4ad87969f0489 100644 --- a/app/code/Magento/Catalog/Block/Adminhtml/Product/Attribute/Edit/Tab/Main.php +++ b/app/code/Magento/Catalog/Block/Adminhtml/Product/Attribute/Edit/Tab/Main.php @@ -70,11 +70,11 @@ protected function _prepareForm() } $this->_coreRegistry->register('attribute_type_hidden_fields', $_hiddenFields); - $this->_eventManager->dispatch('product_attribute_form_build_main_tab', ['form' => $form]); - $frontendInputValues = array_merge($frontendInputElm->getValues(), $additionalTypes); $frontendInputElm->setValues($frontendInputValues); + $this->_eventManager->dispatch('product_attribute_form_build_main_tab', ['form' => $form]); + return $this; } diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute.php index 5409d2cf73b88..2917708741475 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute.php @@ -88,7 +88,7 @@ protected function createActionPage($title = null) /** @var \Magento\Backend\Model\View\Result\Page $resultPage */ $resultPage = $this->resultPageFactory->create(); if ($this->getRequest()->getParam('popup')) { - if ($this->getRequest()->getParam('product_tab') == 'variations') { + if ($this->getRequest()->getParam('product_tab') === 'variations') { $resultPage->addHandle(['popup', 'catalog_product_attribute_edit_product_tab_variations_popup']); } else { $resultPage->addHandle(['popup', 'catalog_product_attribute_edit_popup']); diff --git a/app/code/Magento/ConfigurableProduct/Observer/HideUnsupportedAttributeTypes.php b/app/code/Magento/ConfigurableProduct/Observer/HideUnsupportedAttributeTypes.php new file mode 100644 index 0000000000000..2a46c7f283de5 --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/Observer/HideUnsupportedAttributeTypes.php @@ -0,0 +1,68 @@ +request = $request; + $this->supportedTypes = array_merge($this->supportedTypes, $supportedTypes); + } + + /** + * @param \Magento\Framework\Event\Observer $observer + * @return void + */ + public function execute(EventObserver $observer) + { + if (!$this->isVariationsPopupUsed() ) { + return; + } + + /** @var \Magento\Framework\Data\Form $form */ + $form = $observer->getForm(); + + $filteredValues = []; + /** @var \Magento\Framework\Data\Form\Element\Select $frontendInput */ + $frontendInput = $form->getElement('frontend_input'); + foreach ($frontendInput->getValues() as $frontendValue) { + if (in_array($frontendValue['value'], $this->supportedTypes, true)) { + $filteredValues[] = $frontendValue; + } + } + $frontendInput->setValues($filteredValues); + } + + /** + * @return bool + */ + private function isVariationsPopupUsed() + { + $popup = $this->request->getParam('popup'); + $productTab = $this->request->getParam('product_tab') === 'variations'; + return $popup && $productTab; + } +} diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Observer/HideUnsupportedAttributeTypesTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Observer/HideUnsupportedAttributeTypesTest.php new file mode 100644 index 0000000000000..cb75be4f2afad --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/Test/Unit/Observer/HideUnsupportedAttributeTypesTest.php @@ -0,0 +1,175 @@ +objectManager = new ObjectManager($this); + } + + /** + * @return void + */ + public function testExecuteWhenBlockNotPassed() + { + $target = $this->createTarget($this->createRequestMock(false)); + $event = $this->createEventMock(); + $this->assertEquals(null, $target->execute($event)); + } + + /** + * @param RequestInterface|MockObject $request + * @param array $supportedTypes + * @return HideUnsupportedAttributeTypes + */ + private function createTarget(MockObject $request, array $supportedTypes = []) + { + return $this->objectManager->getObject( + HideUnsupportedAttributeTypes::class, + [ + 'request' => $request, + 'supportedTypes' => $supportedTypes + ] + ); + } + + private function createRequestMock($popup, $productTab = 'variations') + { + $request = $this->getMockBuilder(RequestInterface::class) + ->setMethods(['getParam']) + ->getMockForAbstractClass(); + $request->method('getParam') + ->willReturnCallback( + function ($name) use ($popup, $productTab) { + switch ($name) { + case 'popup': + return $popup; + case 'product_tab': + return $productTab; + default: + return null; + } + } + ); + return $request; + } + + /** + * @param MockObject|null $form + * @return EventObserver|MockObject + * @internal param null|MockObject $block + */ + private function createEventMock(MockObject $form = null) + { + $event = $this->getMockBuilder(EventObserver::class) + ->setMethods(['getForm', 'getBlock']) + ->disableOriginalConstructor() + ->getMock(); + $event->expects($this->any()) + ->method('getForm') + ->willReturn($form); + return $event; + } + + /** + * @dataProvider executeDataProvider + */ + public function testExecuteWithDefaultTypes(array $supportedTypes, array $originalValues, array $expectedValues) + { + $target = $this->createTarget($this->createRequestMock(true), $supportedTypes); + $event = $this->createEventMock($this->createForm($originalValues, $expectedValues)); + $this->assertEquals(null, $target->execute($event)); + } + + public function executeDataProvider() { + return [ + 'testWithDefaultTypes' => [ + 'supportedTypes' => [], + 'originalValues' => [ + $this->createFrontendInputValue('text2', 'Text2'), + $this->createFrontendInputValue('select', 'Select'), + $this->createFrontendInputValue('text', 'Text'), + $this->createFrontendInputValue('multiselect', 'Multiselect'), + $this->createFrontendInputValue('text3', 'Text3'), + ], + 'expectedValues' => [ + $this->createFrontendInputValue('select', 'Select'), + $this->createFrontendInputValue('multiselect', 'Multiselect'), + ], + ], + 'testWithCustomTypes' => [ + 'supportedTypes' => ['custom_type', 'second_custom_type'], + 'originalValues' => [ + $this->createFrontendInputValue('custom_type', 'CustomType'), + $this->createFrontendInputValue('text2', 'Text2'), + $this->createFrontendInputValue('select', 'Select'), + $this->createFrontendInputValue('text', 'Text'), + $this->createFrontendInputValue('second_custom_type', 'SecondCustomType'), + $this->createFrontendInputValue('multiselect', 'Multiselect'), + $this->createFrontendInputValue('text3', 'Text3'), + ], + 'expectedValues' => [ + $this->createFrontendInputValue('custom_type', 'CustomType'), + $this->createFrontendInputValue('select', 'Select'), + $this->createFrontendInputValue('second_custom_type', 'SecondCustomType'), + $this->createFrontendInputValue('multiselect', 'Multiselect'), + ], + ] + ]; + } + + private function createFrontendInputValue($value, $label) + { + return ['value' => $value, 'label' => $label]; + } + + private function createForm(array $originalValues = [], array $expectedValues = []) + { + $form = $this->getMockBuilder(\Magento\Framework\Data\Form::class) + ->setMethods(['getElement']) + ->disableOriginalConstructor() + ->getMock(); + $frontendInput = $this->getMockBuilder(\Magento\Framework\Data\Form\Element\Select::class) + ->setMethods(['getValues', 'setValues']) + ->disableOriginalConstructor() + ->getMock(); + $frontendInput->expects($this->once()) + ->method('getValues') + ->willReturn($originalValues); + $frontendInput->expects($this->once()) + ->method('setValues') + ->with($expectedValues) + ->willReturnSelf(); + $form->expects($this->once()) + ->method('getElement') + ->with('frontend_input') + ->willReturn($frontendInput); + return $form; + } +} diff --git a/app/code/Magento/ConfigurableProduct/etc/adminhtml/events.xml b/app/code/Magento/ConfigurableProduct/etc/adminhtml/events.xml new file mode 100644 index 0000000000000..88df2d60a7dd4 --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/etc/adminhtml/events.xml @@ -0,0 +1,12 @@ + + + + + + + From 9270352e933f1ea854caa2aa4bced7ffa57d4c5b Mon Sep 17 00:00:00 2001 From: Illia Grybkov Date: Thu, 21 Apr 2016 11:14:05 +0300 Subject: [PATCH 03/22] MAGETWO-50571: [Configurable product] Newly created attributes are non-usable in attributes grid --- .../Observer/HideUnsupportedAttributeTypes.php | 2 +- .../Test/Unit/Observer/HideUnsupportedAttributeTypesTest.php | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/ConfigurableProduct/Observer/HideUnsupportedAttributeTypes.php b/app/code/Magento/ConfigurableProduct/Observer/HideUnsupportedAttributeTypes.php index 2a46c7f283de5..dc4ea5163dc5c 100644 --- a/app/code/Magento/ConfigurableProduct/Observer/HideUnsupportedAttributeTypes.php +++ b/app/code/Magento/ConfigurableProduct/Observer/HideUnsupportedAttributeTypes.php @@ -38,7 +38,7 @@ public function __construct(RequestInterface $request, array $supportedTypes = [ */ public function execute(EventObserver $observer) { - if (!$this->isVariationsPopupUsed() ) { + if (!$this->isVariationsPopupUsed()) { return; } diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Observer/HideUnsupportedAttributeTypesTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Observer/HideUnsupportedAttributeTypesTest.php index cb75be4f2afad..b33f151f540be 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Unit/Observer/HideUnsupportedAttributeTypesTest.php +++ b/app/code/Magento/ConfigurableProduct/Test/Unit/Observer/HideUnsupportedAttributeTypesTest.php @@ -107,7 +107,8 @@ public function testExecuteWithDefaultTypes(array $supportedTypes, array $origin $this->assertEquals(null, $target->execute($event)); } - public function executeDataProvider() { + public function executeDataProvider() + { return [ 'testWithDefaultTypes' => [ 'supportedTypes' => [], From 08947e71865d19712f9b68df7cac5774cc065c83 Mon Sep 17 00:00:00 2001 From: Valeriy Nayda Date: Sun, 24 Apr 2016 17:13:20 +0300 Subject: [PATCH 04/22] MAGETWO-52017: Bundle product price absent in shopping cart product grid --- .../Entity/Attribute/AbstractAttribute.php | 18 +++++++++++++++--- .../Eav/Model/ResourceModel/CreateHandler.php | 1 + 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Eav/Model/Entity/Attribute/AbstractAttribute.php b/app/code/Magento/Eav/Model/Entity/Attribute/AbstractAttribute.php index ed4ab88fb4a9d..4004e0bedacea 100644 --- a/app/code/Magento/Eav/Model/Entity/Attribute/AbstractAttribute.php +++ b/app/code/Magento/Eav/Model/Entity/Attribute/AbstractAttribute.php @@ -597,13 +597,25 @@ public function isValueEmpty($value) $isEmpty = (is_array($value) && count($value) == 0) || $value === null || $value === false && $attrType != 'int' || - $value === '' && ($attrType == 'int' || - $attrType == 'decimal' || - $attrType == 'datetime'); + $value === '' && ($attrType == 'int' || $attrType == 'decimal' || $attrType == 'datetime'); return $isEmpty; } + /** + * @param array|null|bool|int|float|string $value + * @return bool + */ + public function isApplicable($value) + { + $attrType = $this->getBackend()->getType(); + $isApplicable = true; + if (!is_scalar($value) && ($attrType == 'int' || $attrType == 'decimal')) { + $isApplicable = false; + } + return $isApplicable; + } + /** * Check if attribute in specified set * diff --git a/app/code/Magento/Eav/Model/ResourceModel/CreateHandler.php b/app/code/Magento/Eav/Model/ResourceModel/CreateHandler.php index c988700ee94b3..991450e56bf05 100644 --- a/app/code/Magento/Eav/Model/ResourceModel/CreateHandler.php +++ b/app/code/Magento/Eav/Model/ResourceModel/CreateHandler.php @@ -100,6 +100,7 @@ public function execute($entityType, $entityData, $arguments = []) continue; } if (isset($entityData[$attribute->getAttributeCode()]) + && $attribute->isApplicable($entityData[$attribute->getAttributeCode()]) && !$attribute->isValueEmpty($entityData[$attribute->getAttributeCode()]) ) { $this->attributePersistor->registerInsert( From d769af00a339fb1dd8948f741a1d856331ddf5b7 Mon Sep 17 00:00:00 2001 From: Valeriy Nayda Date: Sun, 24 Apr 2016 18:40:44 +0300 Subject: [PATCH 05/22] MAGETWO-52017: Bundle product price absent in shopping cart product grid --- app/code/Magento/Bundle/Model/Product/Price.php | 3 ++- app/code/Magento/Eav/Model/ResourceModel/CreateHandler.php | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Bundle/Model/Product/Price.php b/app/code/Magento/Bundle/Model/Product/Price.php index 4d65e1df627aa..83bfcbbabc253 100644 --- a/app/code/Magento/Bundle/Model/Product/Price.php +++ b/app/code/Magento/Bundle/Model/Product/Price.php @@ -183,8 +183,9 @@ public function getFinalPrice($qty, $product) $finalPrice = $this->_applyOptionsPrice($product, $qty, $finalPrice); $finalPrice += $this->getTotalBundleItemsPrice($product, $qty); + $finalPrice = max(0, $finalPrice); $product->setFinalPrice($finalPrice); - return max(0, $product->getData('final_price')); + return $finalPrice; } /** diff --git a/app/code/Magento/Eav/Model/ResourceModel/CreateHandler.php b/app/code/Magento/Eav/Model/ResourceModel/CreateHandler.php index 991450e56bf05..0aa37878f2ad9 100644 --- a/app/code/Magento/Eav/Model/ResourceModel/CreateHandler.php +++ b/app/code/Magento/Eav/Model/ResourceModel/CreateHandler.php @@ -14,6 +14,7 @@ /** * Class CreateHandler + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class CreateHandler implements AttributeInterface { @@ -87,6 +88,7 @@ protected function getAttributes($entityType) * @return array * @throws \Exception * @throws \Magento\Framework\Exception\ConfigurationMismatchException + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function execute($entityType, $entityData, $arguments = []) { From eb5ef435421678f7dacc18a767a7e94a8550e2fe Mon Sep 17 00:00:00 2001 From: Anton Ohorodnyk Date: Mon, 25 Apr 2016 12:48:40 +0300 Subject: [PATCH 06/22] MAGETWO-51210: Can't save qty more than 10000000 after loading saved product - Fixed translation --- .../Ui/view/base/web/js/lib/validation/rules.js | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/app/code/Magento/Ui/view/base/web/js/lib/validation/rules.js b/app/code/Magento/Ui/view/base/web/js/lib/validation/rules.js index b1665f3fdfc39..449c529dfdfb9 100644 --- a/app/code/Magento/Ui/view/base/web/js/lib/validation/rules.js +++ b/app/code/Magento/Ui/view/base/web/js/lib/validation/rules.js @@ -703,26 +703,20 @@ define([ "less-than-equals-to": [ function(value, params) { if ($.isNumeric(params) && $.isNumeric(value)) { - this.lteToVal = params; return parseFloat(value) <= parseFloat(params); } return true; }, - function() { - return $.mage.__('Please enter a value less than or equal to {0}.'); - } + $.mage.__('Please enter a value less than or equal to {0}.') ], "greater-than-equals-to": [ function(value, params) { if ($.isNumeric(params) && $.isNumeric(value)) { - this.gteToVal = params; return parseFloat(value) >= parseFloat(params); } return true; }, - function() { - return $.mage.__('Please enter a value greater than or equal to {0}.'); - } + $.mage.__('Please enter a value greater than or equal to {0}.') ], "validate-emails": [ function(value) { From e16efc58f74bc5c71bbd680a490ec5f43ee47cfe Mon Sep 17 00:00:00 2001 From: Anton Ohorodnyk Date: Mon, 25 Apr 2016 13:47:02 +0300 Subject: [PATCH 07/22] MAGETWO-51210: Can't save qty more than 10000000 after loading saved product - Changed int to const --- .../DataProvider/Product/Form/Modifier/AdvancedInventory.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/CatalogInventory/Ui/DataProvider/Product/Form/Modifier/AdvancedInventory.php b/app/code/Magento/CatalogInventory/Ui/DataProvider/Product/Form/Modifier/AdvancedInventory.php index 9be1ef6066122..cc6f44fbfb17e 100644 --- a/app/code/Magento/CatalogInventory/Ui/DataProvider/Product/Form/Modifier/AdvancedInventory.php +++ b/app/code/Magento/CatalogInventory/Ui/DataProvider/Product/Form/Modifier/AdvancedInventory.php @@ -5,6 +5,7 @@ */ namespace Magento\CatalogInventory\Ui\DataProvider\Product\Form\Modifier; +use Magento\Catalog\Controller\Adminhtml\Product\Initialization\StockDataFilter; use Magento\Catalog\Model\Locator\LocatorInterface; use Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\AbstractModifier; use Magento\CatalogInventory\Api\StockRegistryInterface; @@ -188,7 +189,7 @@ private function prepareMeta() 'validation' => [ 'validate-number' => true, 'validate-digits' => true, - 'less-than-equals-to' => 99999999, + 'less-than-equals-to' => StockDataFilter::MAX_QTY_VALUE, ], 'imports' => [ 'handleChanges' => '${$.provider}:data.product.stock_data.is_qty_decimal', From cce83d754fe8789b509348207ed5aa50fe10fc9c Mon Sep 17 00:00:00 2001 From: Valeriy Nayda Date: Mon, 25 Apr 2016 13:58:05 +0300 Subject: [PATCH 08/22] MAGETWO-52017: Bundle product price absent in shopping cart product grid --- .../Model/Entity/Attribute/AbstractAttribute.php | 14 -------------- .../Eav/Model/ResourceModel/CreateHandler.php | 2 +- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/app/code/Magento/Eav/Model/Entity/Attribute/AbstractAttribute.php b/app/code/Magento/Eav/Model/Entity/Attribute/AbstractAttribute.php index 4004e0bedacea..fee7047d2d7e0 100644 --- a/app/code/Magento/Eav/Model/Entity/Attribute/AbstractAttribute.php +++ b/app/code/Magento/Eav/Model/Entity/Attribute/AbstractAttribute.php @@ -602,20 +602,6 @@ public function isValueEmpty($value) return $isEmpty; } - /** - * @param array|null|bool|int|float|string $value - * @return bool - */ - public function isApplicable($value) - { - $attrType = $this->getBackend()->getType(); - $isApplicable = true; - if (!is_scalar($value) && ($attrType == 'int' || $attrType == 'decimal')) { - $isApplicable = false; - } - return $isApplicable; - } - /** * Check if attribute in specified set * diff --git a/app/code/Magento/Eav/Model/ResourceModel/CreateHandler.php b/app/code/Magento/Eav/Model/ResourceModel/CreateHandler.php index 0aa37878f2ad9..1050280a46300 100644 --- a/app/code/Magento/Eav/Model/ResourceModel/CreateHandler.php +++ b/app/code/Magento/Eav/Model/ResourceModel/CreateHandler.php @@ -102,7 +102,7 @@ public function execute($entityType, $entityData, $arguments = []) continue; } if (isset($entityData[$attribute->getAttributeCode()]) - && $attribute->isApplicable($entityData[$attribute->getAttributeCode()]) + && !is_array($entityData[$attribute->getAttributeCode()]) && !$attribute->isValueEmpty($entityData[$attribute->getAttributeCode()]) ) { $this->attributePersistor->registerInsert( From 5d5e9c3cc00b333d0561ea34d71698d429248cce Mon Sep 17 00:00:00 2001 From: Maksym Aposov Date: Tue, 26 Apr 2016 13:32:45 +0300 Subject: [PATCH 09/22] MAGETWO-52186: Invalid selector for delete configuration action menu item --- .../Edit/Section/Variations/Config/Matrix.php | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Section/Variations/Config/Matrix.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Section/Variations/Config/Matrix.php index ed8cbc800b2e6..d9df10ad306d1 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Section/Variations/Config/Matrix.php +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Section/Variations/Config/Matrix.php @@ -79,7 +79,7 @@ class Matrix extends Form * * @var string */ - protected $deleteVariation = '[data-bind*="deleteRecord"]'; + protected $deleteVariation = '[data-bind*="Remove Product"]'; /** * Choose a different Product button selector. @@ -194,11 +194,22 @@ public function getTemplateBlock() public function deleteVariations() { $variations = $this->_rootElement->getElements($this->variationRow, Locator::SELECTOR_XPATH); - foreach (array_reverse($variations) as $variation) { - $variation->find($this->actionMenu)->hover(); - $variation->find($this->actionMenu)->click(); - $variation->find($this->deleteVariation)->click(); + while (count($variations) > 1) { + $variation = array_pop($variations); + $this->deleteVariation($variation); + $variations = $this->_rootElement->getElements($this->variationRow, Locator::SELECTOR_XPATH); } + $this->deleteVariation(array_pop($variations)); + } + + /** + * @param \Magento\Mtf\Client\ElementInterface $variation + */ + private function deleteVariation($variation) + { + $variation->find($this->actionMenu)->hover(); + $variation->find($this->actionMenu)->click(); + $variation->find($this->deleteVariation)->click(); } /** From 66d7fb288280342c20c395fdd85feb0c88eed142 Mon Sep 17 00:00:00 2001 From: Valeriy Nayda Date: Tue, 26 Apr 2016 13:55:18 +0300 Subject: [PATCH 10/22] MAGETWO-52015: Bundle Product price range not include custom options --- app/code/Magento/Catalog/Block/Product/ListProduct.php | 1 + app/code/Magento/Catalog/Model/Product.php | 6 +----- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Catalog/Block/Product/ListProduct.php b/app/code/Magento/Catalog/Block/Product/ListProduct.php index 996dbc191dfd1..0b251d96cd37c 100644 --- a/app/code/Magento/Catalog/Block/Product/ListProduct.php +++ b/app/code/Magento/Catalog/Block/Product/ListProduct.php @@ -122,6 +122,7 @@ protected function _getProductCollection() } } $this->_productCollection = $layer->getProductCollection(); + $this->_productCollection->addOptionsToResult(); $this->prepareSortableFieldsByCategory($layer->getCurrentCategory()); diff --git a/app/code/Magento/Catalog/Model/Product.php b/app/code/Magento/Catalog/Model/Product.php index d1f91a90e105c..8769df70dbb7a 100644 --- a/app/code/Magento/Catalog/Model/Product.php +++ b/app/code/Magento/Catalog/Model/Product.php @@ -142,11 +142,6 @@ class Product extends \Magento\Catalog\Model\AbstractModel implements */ protected $optionInstance; - /** - * @var bool - */ - protected $optionsInitialized = false; - /** * @var array */ @@ -1901,6 +1896,7 @@ public function addOption(Product\Option $option) { $options = (array)$this->getData('options'); $options[] = $option; + $option->setProduct($this); $this->setData('options', $options); return $this; } From 619ebcd46d9b4aadfd5551dc096c3e5829b28a55 Mon Sep 17 00:00:00 2001 From: Illia Grybkov Date: Tue, 26 Apr 2016 17:44:52 +0300 Subject: [PATCH 11/22] MAGETWO-52030: Downloadable product show as out of stock in category page --- app/code/Magento/Downloadable/Model/Product/Type.php | 7 ++++--- .../Downloadable/Test/Unit/Model/Product/TypeTest.php | 9 +++++++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Downloadable/Model/Product/Type.php b/app/code/Magento/Downloadable/Model/Product/Type.php index 8b385cf74bd38..64c00d208b86f 100644 --- a/app/code/Magento/Downloadable/Model/Product/Type.php +++ b/app/code/Magento/Downloadable/Model/Product/Type.php @@ -164,10 +164,11 @@ public function getLinks($product) */ public function hasLinks($product) { - if ($product->hasData('links_exist')) { - return $product->getData('links_exist'); + $hasLinks = $product->getData('links_exist'); + if (null === $hasLinks) { + $hasLinks = (count($this->getLinks($product)) > 0); } - return count($this->getLinks($product)) > 0; + return $hasLinks; } /** diff --git a/app/code/Magento/Downloadable/Test/Unit/Model/Product/TypeTest.php b/app/code/Magento/Downloadable/Test/Unit/Model/Product/TypeTest.php index 9ee0351e64d13..b7db6111a50c1 100644 --- a/app/code/Magento/Downloadable/Test/Unit/Model/Product/TypeTest.php +++ b/app/code/Magento/Downloadable/Test/Unit/Model/Product/TypeTest.php @@ -83,6 +83,7 @@ protected function setUp() 'getDownloadableData', 'setTypeHasOptions', 'setLinksExist', + 'getDownloadableLinks', '__wakeup', ], [], @@ -144,4 +145,12 @@ public function testBeforeSave() { $this->target->beforeSave($this->product); } + + public function testHasLinks() + { + $this->product->expects($this->exactly(2)) + ->method('getDownloadableLinks') + ->willReturn(['link1', 'link2']); + $this->assertTrue($this->target->hasLinks($this->product)); + } } From 7eae298fabeb570181a453f50ebf58023b873b48 Mon Sep 17 00:00:00 2001 From: Illia Grybkov Date: Tue, 26 Apr 2016 18:14:02 +0300 Subject: [PATCH 12/22] MAGETWO-52030: Downloadable product show as out of stock in category page - Fix static test --- .../Magento/Downloadable/Test/Unit/Model/Product/TypeTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Downloadable/Test/Unit/Model/Product/TypeTest.php b/app/code/Magento/Downloadable/Test/Unit/Model/Product/TypeTest.php index b7db6111a50c1..c4be8f5d5aee1 100644 --- a/app/code/Magento/Downloadable/Test/Unit/Model/Product/TypeTest.php +++ b/app/code/Magento/Downloadable/Test/Unit/Model/Product/TypeTest.php @@ -17,6 +17,7 @@ class TypeTest extends \PHPUnit_Framework_TestCase * @var \Magento\Downloadable\Model\Product\Type */ private $target; + /** * @var TypeHandlerInterface|\PHPUnit_Framework_MockObject_MockObject */ From c80a3081e007e7b2ce58baaf77748b87cf134298 Mon Sep 17 00:00:00 2001 From: Illia Grybkov Date: Wed, 27 Apr 2016 13:01:04 +0300 Subject: [PATCH 13/22] MAGETWO-50571: [Configurable product] Newly created attributes are non-usable in attributes grid --- .../Observer/HideUnsupportedAttributeTypes.php | 8 ++++---- app/code/Magento/ConfigurableProduct/etc/di.xml | 7 +++++++ app/code/Magento/Swatches/etc/di.xml | 8 ++++++++ 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/ConfigurableProduct/Observer/HideUnsupportedAttributeTypes.php b/app/code/Magento/ConfigurableProduct/Observer/HideUnsupportedAttributeTypes.php index dc4ea5163dc5c..4ccbab7e1af05 100644 --- a/app/code/Magento/ConfigurableProduct/Observer/HideUnsupportedAttributeTypes.php +++ b/app/code/Magento/ConfigurableProduct/Observer/HideUnsupportedAttributeTypes.php @@ -15,7 +15,7 @@ class HideUnsupportedAttributeTypes implements ObserverInterface /** * @var string[] */ - protected $supportedTypes = ['select', 'multiselect']; + protected $supportedTypes = []; /** * @var RequestInterface @@ -23,13 +23,13 @@ class HideUnsupportedAttributeTypes implements ObserverInterface private $request; /** - * @param RequestInterface $request * @param string[] $supportedTypes + * @param RequestInterface $request */ - public function __construct(RequestInterface $request, array $supportedTypes = []) + public function __construct(array $supportedTypes, RequestInterface $request) { + $this->supportedTypes = $supportedTypes; $this->request = $request; - $this->supportedTypes = array_merge($this->supportedTypes, $supportedTypes); } /** diff --git a/app/code/Magento/ConfigurableProduct/etc/di.xml b/app/code/Magento/ConfigurableProduct/etc/di.xml index 992642ddc0871..c57194c664bd1 100644 --- a/app/code/Magento/ConfigurableProduct/etc/di.xml +++ b/app/code/Magento/ConfigurableProduct/etc/di.xml @@ -151,4 +151,11 @@ Magento\Framework\App\Cache\Type\Collection + + + + select + + + diff --git a/app/code/Magento/Swatches/etc/di.xml b/app/code/Magento/Swatches/etc/di.xml index 26c86388231e9..525456d1f9eb6 100644 --- a/app/code/Magento/Swatches/etc/di.xml +++ b/app/code/Magento/Swatches/etc/di.xml @@ -21,6 +21,14 @@ + + + + swatch_visual + swatch_text + + + From 739faf7762cd0f915d470e45ad5f54efc3557f39 Mon Sep 17 00:00:00 2001 From: Maksym Aposov Date: Wed, 27 Apr 2016 14:39:27 +0300 Subject: [PATCH 14/22] MAGETWO-52186: Invalid selector for delete configuration action menu item --- .../Edit/Section/Variations/Config/Matrix.php | 27 ++++++++----------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Section/Variations/Config/Matrix.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Section/Variations/Config/Matrix.php index d9df10ad306d1..893d01f7ccb92 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Section/Variations/Config/Matrix.php +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Section/Variations/Config/Matrix.php @@ -193,23 +193,18 @@ public function getTemplateBlock() public function deleteVariations() { - $variations = $this->_rootElement->getElements($this->variationRow, Locator::SELECTOR_XPATH); - while (count($variations) > 1) { - $variation = array_pop($variations); - $this->deleteVariation($variation); - $variations = $this->_rootElement->getElements($this->variationRow, Locator::SELECTOR_XPATH); + $rowLocator = sprintf($this->variationRowByNumber, 1); + $variationText = ''; + while ($this->_rootElement->find($rowLocator, Locator::SELECTOR_XPATH)->isVisible()) { + $variation = $this->_rootElement->find($rowLocator, Locator::SELECTOR_XPATH); + if ($variationText == $variation->getText()) { + throw new \Exception("Failed to delete configurable product variation"); + } + $variationText = $variation->getText(); + $variation->find($this->actionMenu)->hover(); + $variation->find($this->actionMenu)->click(); + $variation->find($this->deleteVariation)->click(); } - $this->deleteVariation(array_pop($variations)); - } - - /** - * @param \Magento\Mtf\Client\ElementInterface $variation - */ - private function deleteVariation($variation) - { - $variation->find($this->actionMenu)->hover(); - $variation->find($this->actionMenu)->click(); - $variation->find($this->deleteVariation)->click(); } /** From 8d098dcbbd688d3da24c0a7722e59036a9d2ce5b Mon Sep 17 00:00:00 2001 From: Maksym Aposov Date: Wed, 27 Apr 2016 15:41:22 +0300 Subject: [PATCH 15/22] MAGETWO-52180: Failed CreateBundleProductEntityTestVariation8 test --- .../Bundle/Test/TestCase/CreateBundleProductEntityTest.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/CreateBundleProductEntityTest.xml b/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/CreateBundleProductEntityTest.xml index b9e5f6e317e62..6fcef33132603 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/CreateBundleProductEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/CreateBundleProductEntityTest.xml @@ -195,8 +195,8 @@ Yes dynamic-8 20 - m/d/Y -1 day - m/d/Y +3 days + M j, Y -1 day + M j, Y +3 days default_dynamic catalogProductSimple::product_100_dollar,catalogProductSimple::product_40_dollar bundle_default From 6c6e210fc1d313e6b937ef0aeae1d7618f613c81 Mon Sep 17 00:00:00 2001 From: Illia Grybkov Date: Wed, 27 Apr 2016 16:25:20 +0300 Subject: [PATCH 16/22] MAGETWO-50571: [Configurable product] Newly created attributes are non-usable in attributes grid - Fix unit test --- .../Unit/Observer/HideUnsupportedAttributeTypesTest.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Observer/HideUnsupportedAttributeTypesTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Observer/HideUnsupportedAttributeTypesTest.php index b33f151f540be..a6f15699d417e 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Unit/Observer/HideUnsupportedAttributeTypesTest.php +++ b/app/code/Magento/ConfigurableProduct/Test/Unit/Observer/HideUnsupportedAttributeTypesTest.php @@ -111,7 +111,7 @@ public function executeDataProvider() { return [ 'testWithDefaultTypes' => [ - 'supportedTypes' => [], + 'supportedTypes' => ['select'], 'originalValues' => [ $this->createFrontendInputValue('text2', 'Text2'), $this->createFrontendInputValue('select', 'Select'), @@ -121,11 +121,10 @@ public function executeDataProvider() ], 'expectedValues' => [ $this->createFrontendInputValue('select', 'Select'), - $this->createFrontendInputValue('multiselect', 'Multiselect'), ], ], 'testWithCustomTypes' => [ - 'supportedTypes' => ['custom_type', 'second_custom_type'], + 'supportedTypes' => ['select', 'custom_type', 'second_custom_type'], 'originalValues' => [ $this->createFrontendInputValue('custom_type', 'CustomType'), $this->createFrontendInputValue('text2', 'Text2'), @@ -139,7 +138,6 @@ public function executeDataProvider() $this->createFrontendInputValue('custom_type', 'CustomType'), $this->createFrontendInputValue('select', 'Select'), $this->createFrontendInputValue('second_custom_type', 'SecondCustomType'), - $this->createFrontendInputValue('multiselect', 'Multiselect'), ], ] ]; From 3fd3c55b1a46b338ae603e4401bf1150b52e6dc8 Mon Sep 17 00:00:00 2001 From: Valeriy Nayda Date: Thu, 28 Apr 2016 15:55:13 +0300 Subject: [PATCH 17/22] MAGETWO-51611: Layered navigation include list of all product attributes --- .../Model/Layer/Filter/Attribute.php | 11 +- .../Unit/Model/Layer/Filter/AttributeTest.php | 112 +++++++++++++++++- 2 files changed, 117 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/CatalogSearch/Model/Layer/Filter/Attribute.php b/app/code/Magento/CatalogSearch/Model/Layer/Filter/Attribute.php index bff84a9236564..8c46242abb110 100644 --- a/app/code/Magento/CatalogSearch/Model/Layer/Filter/Attribute.php +++ b/app/code/Magento/CatalogSearch/Model/Layer/Filter/Attribute.php @@ -84,6 +84,12 @@ protected function _getItemsData() ->getProductCollection(); $optionsFacetedData = $productCollection->getFacetedData($attribute->getAttributeCode()); + if (count($optionsFacetedData) === 0 + && $this->getAttributeIsFilterable($attribute) !== static::ATTRIBUTE_OPTIONS_ONLY_WITH_RESULTS + ) { + return $this->itemDataBuilder->build(); + } + $productSize = $productCollection->getSize(); $options = $attribute->getFrontend() @@ -100,9 +106,8 @@ protected function _getItemsData() : 0; // Check filter type if ( - $count === 0 - && $this->getAttributeIsFilterable($attribute) === static::ATTRIBUTE_OPTIONS_ONLY_WITH_RESULTS - && !$this->isOptionReducesResults($count, $productSize) + $this->getAttributeIsFilterable($attribute) === static::ATTRIBUTE_OPTIONS_ONLY_WITH_RESULTS + && (!$this->isOptionReducesResults($count, $productSize) || $count === 0) ) { continue; } diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Layer/Filter/AttributeTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Layer/Filter/AttributeTest.php index fae8db405ea3c..4afe01f845f94 100644 --- a/app/code/Magento/CatalogSearch/Test/Unit/Model/Layer/Filter/AttributeTest.php +++ b/app/code/Magento/CatalogSearch/Test/Unit/Model/Layer/Filter/AttributeTest.php @@ -6,6 +6,7 @@ namespace Magento\CatalogSearch\Test\Unit\Model\Layer\Filter; +use Magento\Catalog\Model\Layer\Filter\AbstractFilter; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; use PHPUnit_Framework_MockObject_MockObject as MockObject; @@ -104,9 +105,6 @@ protected function setUp() ->disableOriginalConstructor() ->setMethods(['getAttributeCode', 'getFrontend', 'getIsFilterable']) ->getMock(); - $this->attribute->expects($this->atLeastOnce()) - ->method('getFrontend') - ->will($this->returnValue($this->frontend)); $this->request = $this->getMockBuilder('\Magento\Framework\App\RequestInterface') ->setMethods(['getParam']) @@ -143,6 +141,9 @@ public function testApplyFilter() $this->attribute->expects($this->exactly(2)) ->method('getAttributeCode') ->will($this->returnValue($attributeCode)); + $this->attribute->expects($this->atLeastOnce()) + ->method('getFrontend') + ->will($this->returnValue($this->frontend)); $this->target->setAttributeModel($this->attribute); @@ -202,6 +203,9 @@ public function testGetItemsWithApply() $this->attribute->expects($this->exactly(2)) ->method('getAttributeCode') ->will($this->returnValue($attributeCode)); + $this->attribute->expects($this->atLeastOnce()) + ->method('getFrontend') + ->will($this->returnValue($this->frontend)); $this->target->setAttributeModel($this->attribute); @@ -283,6 +287,9 @@ public function testGetItemsWithoutApply() $this->attribute->expects($this->exactly(2)) ->method('getAttributeCode') ->will($this->returnValue($attributeCode)); + $this->attribute->expects($this->atLeastOnce()) + ->method('getFrontend') + ->will($this->returnValue($this->frontend)); $this->target->setAttributeModel($this->attribute); @@ -329,6 +336,105 @@ public function testGetItemsWithoutApply() $this->assertEquals($expectedFilterItems, $result); } + /** + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function testGetItemsOnlyWithResults() + { + $attributeCode = 'attributeCode'; + $selectedOptions = [ + [ + 'label' => 'selectedOptionLabel1', + 'value' => 'selectedOptionValue1', + ], + [ + 'label' => 'selectedOptionLabel2', + 'value' => 'selectedOptionValue2', + ], + ]; + $facetedData = [ + 'selectedOptionValue1' => ['count' => 10], + 'selectedOptionValue2' => ['count' => 0], + ]; + $builtData = [ + [ + 'label' => $selectedOptions[0]['label'], + 'value' => $selectedOptions[0]['value'], + 'count' => $facetedData[$selectedOptions[0]['value']]['count'], + ], + ]; + + $this->attribute->expects($this->atLeastOnce()) + ->method('getAttributeCode') + ->willReturn($attributeCode); + $this->attribute->expects($this->atLeastOnce()) + ->method('getIsFilterable') + ->willReturn(AbstractFilter::ATTRIBUTE_OPTIONS_ONLY_WITH_RESULTS); + $this->attribute->expects($this->atLeastOnce()) + ->method('getFrontend') + ->will($this->returnValue($this->frontend)); + + $this->target->setAttributeModel($this->attribute); + + $this->frontend->expects($this->once()) + ->method('getSelectOptions') + ->willReturn($selectedOptions); + + $this->fulltextCollection->expects($this->once()) + ->method('getFacetedData') + ->willReturn($facetedData); + $this->fulltextCollection->expects($this->once()) + ->method('getSize') + ->will($this->returnValue(50)); + + $this->itemDataBuilder->expects($this->once()) + ->method('addItemData') + ->with( + $selectedOptions[0]['label'], + $selectedOptions[0]['value'], + $facetedData[$selectedOptions[0]['value']]['count'] + ) + ->will($this->returnSelf()); + + $this->itemDataBuilder->expects($this->once()) + ->method('build') + ->willReturn($builtData); + + $expectedFilterItems = [ + $this->createFilterItem(0, $builtData[0]['label'], $builtData[0]['value'], $builtData[0]['count']), + ]; + $result = $this->target->getItems(); + + $this->assertEquals($expectedFilterItems, $result); + } + + /** + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function testGetItemsIfFacetedDataIsEmpty() + { + $attributeCode = 'attributeCode'; + + $this->attribute->expects($this->atLeastOnce()) + ->method('getAttributeCode') + ->willReturn($attributeCode); + $this->attribute->expects($this->atLeastOnce()) + ->method('getIsFilterable') + ->willReturn(0); + + $this->target->setAttributeModel($this->attribute); + + $this->fulltextCollection->expects($this->once()) + ->method('getFacetedData') + ->willReturn([]); + + $this->itemDataBuilder->expects($this->once()) + ->method('build') + ->willReturn([]); + + $this->assertEquals([], $this->target->getItems()); + } + /** * @param int $index * @param string $label From f3cf5d507f13686cb96ce3f986fb274bfb8234ba Mon Sep 17 00:00:00 2001 From: Maksym Aposov Date: Thu, 5 May 2016 16:22:37 +0300 Subject: [PATCH 18/22] MAGETWO-51975: Product attribute with date type has incorrect value --- .../Search/Adapter/Mysql/AdapterTest.php | 39 +++++++++++- .../Search/_files/date_attribute.php | 59 +++++++++++++++++++ .../Search/_files/date_attribute_rollback.php | 35 +++++++++++ .../Search/_files/filterable_attribute.php | 2 +- .../Framework/Search/_files/requests.xml | 21 +++++++ 5 files changed, 153 insertions(+), 3 deletions(-) create mode 100644 dev/tests/integration/testsuite/Magento/Framework/Search/_files/date_attribute.php create mode 100644 dev/tests/integration/testsuite/Magento/Framework/Search/_files/date_attribute_rollback.php diff --git a/dev/tests/integration/testsuite/Magento/Framework/Search/Adapter/Mysql/AdapterTest.php b/dev/tests/integration/testsuite/Magento/Framework/Search/Adapter/Mysql/AdapterTest.php index 6390f1d3c995c..fda3851989ea8 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Search/Adapter/Mysql/AdapterTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Search/Adapter/Mysql/AdapterTest.php @@ -364,6 +364,7 @@ public function advancedSearchDataProvider() } /** + * @magentoDataFixture Magento/Framework/Search/_files/filterable_attribute.php * @magentoConfigFixture current_store catalog/search/engine mysql */ public function testCustomFilterableAttribute() @@ -384,12 +385,46 @@ public function testCustomFilterableAttribute() $this->requestBuilder->bind('select_attribute', $selectOptions->getLastItem()->getId()); $this->requestBuilder->bind('multiselect_attribute', $multiselectOptions->getLastItem()->getId()); - $this->requestBuilder->bind('price.from', 9); - $this->requestBuilder->bind('price.to', 12); + $this->requestBuilder->bind('price.from', 98); + $this->requestBuilder->bind('price.to', 100); $this->requestBuilder->bind('category_ids', 2); $this->requestBuilder->setRequestName('filterable_custom_attributes'); $queryResponse = $this->executeQuery(); $this->assertEquals(1, $queryResponse->count()); } + + /** + * Advanced search request using date product attribute + * + * @param $rangeFilter + * @param $expectedRecordsCount + * @magentoDataFixture Magento/Framework/Search/_files/date_attribute.php + * @magentoConfigFixture current_store catalog/search/engine mysql + * @dataProvider dateDataProvider + */ + public function testAdvancedSearchDateField($rangeFilter, $expectedRecordsCount) + { + array_walk($rangeFilter, function (&$item) { + if (!empty($item)) { + $item = gmdate('c', strtotime($item)) . 'Z'; + } + }); + $this->requestBuilder->bind('date.from', $rangeFilter['from']); + $this->requestBuilder->bind('date.to', $rangeFilter['to']); + $this->requestBuilder->setRequestName('advanced_search_date_field'); + + $queryResponse = $this->executeQuery(); + $this->assertEquals($expectedRecordsCount, $queryResponse->count()); + } + + public function dateDataProvider() + { + return [ + [['from' => '2000-01-01', 'to' => '2000-01-01'], 1], //Y-m-d + [['from' => '2000-01-01', 'to' => ''], 1], + [['from' => '1999-12-31', 'to' => '2000-01-01'], 1], + [['from' => '2000-02-01', 'to' => ''], 0], + ]; + } } diff --git a/dev/tests/integration/testsuite/Magento/Framework/Search/_files/date_attribute.php b/dev/tests/integration/testsuite/Magento/Framework/Search/_files/date_attribute.php new file mode 100644 index 0000000000000..606a53acbfd72 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/Search/_files/date_attribute.php @@ -0,0 +1,59 @@ +create( + 'Magento\Catalog\Setup\CategorySetup', + ['resourceName' => 'catalog_setup'] +); + +/** @var $selectAttribute \Magento\Catalog\Model\ResourceModel\Eav\Attribute */ +$dateAttribute = $objectManager->create( + 'Magento\Catalog\Model\ResourceModel\Eav\Attribute' +); +$dateAttribute->setData( + [ + 'attribute_code' => 'date_attribute', + 'entity_type_id' => $installer->getEntityTypeId('catalog_product'), + 'is_global' => 1, + 'is_filterable' => 1, + 'backend_type' => 'datetime', + 'frontend_input' => 'date', + 'frontend_label' => 'Test Date', + ] +); +$dateAttribute->save(); +/* Assign attribute to attribute set */ +$installer->addAttributeToGroup('catalog_product', 'Default', 'General', $dateAttribute->getId()); + +/** @var $product \Magento\Catalog\Model\Product */ +$product = $objectManager->create('Magento\Catalog\Model\Product'); +$product + ->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE) + ->setAttributeSetId($installer->getAttributeSetId('catalog_product', 'Default')) + ->setWebsiteIds([1]) + ->setName('Simple Product with date attribute') + ->setSku('simple_product_with_date_attribute') + ->setPrice(1) + ->setCategoryIds([2]) + ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH) + ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED) + ->setStockData(['use_config_manage_stock' => 1, 'qty' => 5, 'is_in_stock' => 1]) + ->save(); + +$objectManager->get('Magento\Catalog\Model\Product\Action') + ->updateAttributes( + [$product->getId()], + [ + $dateAttribute->getAttributeCode() => '01/01/2000' // m/d/Y + ], + $product->getStoreId() + ); diff --git a/dev/tests/integration/testsuite/Magento/Framework/Search/_files/date_attribute_rollback.php b/dev/tests/integration/testsuite/Magento/Framework/Search/_files/date_attribute_rollback.php new file mode 100644 index 0000000000000..2f59c100ca3b1 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/Search/_files/date_attribute_rollback.php @@ -0,0 +1,35 @@ +create( + 'Magento\Catalog\Setup\CategorySetup', + ['resourceName' => 'catalog_setup'] +); +$registry = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get('Magento\Framework\Registry'); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +/** @var $product \Magento\Catalog\Model\Product */ +$product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create('Magento\Catalog\Model\Product'); +$product = $product->loadByAttribute('sku', 'simple_product_with_date_attribute'); +if ($product->getId()) { + $product->delete(); +} + +/** @var $attribute \Magento\Catalog\Model\ResourceModel\Eav\Attribute */ +$attribute = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + 'Magento\Catalog\Model\ResourceModel\Eav\Attribute' +); +$attribute->loadByCode($installer->getEntityTypeId('catalog_product'), 'date_attribute'); +if ($attribute->getId()) { + $attribute->delete(); +} + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); diff --git a/dev/tests/integration/testsuite/Magento/Framework/Search/_files/filterable_attribute.php b/dev/tests/integration/testsuite/Magento/Framework/Search/_files/filterable_attribute.php index 3103d25cc1fb5..6a2e967560987 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Search/_files/filterable_attribute.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Search/_files/filterable_attribute.php @@ -81,7 +81,7 @@ )->setSku( 'simple_product_' . $option->getId() )->setPrice( - 10 + 99 )->setCategoryIds( [2] )->setVisibility( diff --git a/dev/tests/integration/testsuite/Magento/Framework/Search/_files/requests.xml b/dev/tests/integration/testsuite/Magento/Framework/Search/_files/requests.xml index 76e044afcba49..0cdfa11c3b6b5 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Search/_files/requests.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/Search/_files/requests.xml @@ -366,4 +366,25 @@ 0 10 + + + + + + + + + + + + + + + + + + + 0 + 10 + From e3b578ef976f01b95b18746b49eb43553b4ca1f7 Mon Sep 17 00:00:00 2001 From: Illia Grybkov Date: Tue, 10 May 2016 17:28:47 +0300 Subject: [PATCH 19/22] MAGETWO-52482: Fatal error appears if user less symbols in quick search field than minimal query length --- .../ResourceModel/Fulltext/Collection.php | 19 ++++++++++++------- .../Model/Search/TableMapper.php | 4 ++-- .../Framework/Search/Request/Cleaner.php | 2 +- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/app/code/Magento/CatalogSearch/Model/ResourceModel/Fulltext/Collection.php b/app/code/Magento/CatalogSearch/Model/ResourceModel/Fulltext/Collection.php index 1d3749f4a95a9..0b5ee319b8088 100644 --- a/app/code/Magento/CatalogSearch/Model/ResourceModel/Fulltext/Collection.php +++ b/app/code/Magento/CatalogSearch/Model/ResourceModel/Fulltext/Collection.php @@ -5,6 +5,7 @@ */ namespace Magento\CatalogSearch\Model\ResourceModel\Fulltext; +use Magento\CatalogSearch\Model\Search\RequestGenerator; use Magento\Framework\DB\Select; use Magento\Framework\Exception\StateException; use Magento\Framework\Search\Adapter\Mysql\TemporaryStorage; @@ -398,14 +399,18 @@ public function getFacetedData($field) $this->_renderFilters(); $result = []; $aggregations = $this->searchResult->getAggregations(); - $bucket = $aggregations->getBucket($field . '_bucket'); - if ($bucket) { - foreach ($bucket->getValues() as $value) { - $metrics = $value->getMetrics(); - $result[$metrics['value']] = $metrics; + // This behavior is for case with empty object when we got EmptyRequestDataException + // TODO: Cover this behavior with unit test in scope of MAGETWO-51447 + if (null !== $aggregations) { + $bucket = $aggregations->getBucket($field . RequestGenerator::BUCKET_SUFFIX); + if ($bucket) { + foreach ($bucket->getValues() as $value) { + $metrics = $value->getMetrics(); + $result[$metrics['value']] = $metrics; + } + } else { + throw new StateException(__('Bucket does not exist')); } - } else { - throw new StateException(__('Bucket do not exists')); } return $result; } diff --git a/app/code/Magento/CatalogSearch/Model/Search/TableMapper.php b/app/code/Magento/CatalogSearch/Model/Search/TableMapper.php index 98facef4679c2..c0057e3515c2a 100644 --- a/app/code/Magento/CatalogSearch/Model/Search/TableMapper.php +++ b/app/code/Magento/CatalogSearch/Model/Search/TableMapper.php @@ -108,7 +108,7 @@ private function getMappingData(FilterInterface $filter) && in_array($attribute->getFrontendInput(), ['select', 'multiselect'], true) ) { $table = $this->resource->getTableName('catalog_product_index_eav'); - $alias = $field . '_filter'; + $alias = $field . RequestGenerator::FILTER_SUFFIX; $mapOn = sprintf( 'search_index.entity_id = %1$s.entity_id AND %1$s.attribute_id = %2$d AND %1$s.store_id = %3$d', $alias, @@ -118,7 +118,7 @@ private function getMappingData(FilterInterface $filter) $mappedFields = []; } elseif ($attribute->getBackendType() === AbstractAttribute::TYPE_STATIC) { $table = $attribute->getBackendTable(); - $alias = $field . '_filter'; + $alias = $field . RequestGenerator::FILTER_SUFFIX; $mapOn = 'search_index.entity_id = ' . $alias . '.entity_id'; $mappedFields = null; } diff --git a/lib/internal/Magento/Framework/Search/Request/Cleaner.php b/lib/internal/Magento/Framework/Search/Request/Cleaner.php index 7d2ad5173fd6b..bceeedc79df9a 100644 --- a/lib/internal/Magento/Framework/Search/Request/Cleaner.php +++ b/lib/internal/Magento/Framework/Search/Request/Cleaner.php @@ -57,7 +57,7 @@ public function clean(array $requestData) $this->clear(); if (empty($requestData['queries']) && empty($requestData['filters'])) { - throw new EmptyRequestDataException(new Phrase('Request query and filter is not set')); + throw new EmptyRequestDataException(new Phrase('Request query and filters are not set')); } return $requestData; From 0611722194ceda21424d1a2fcee0dab4bb61a1ad Mon Sep 17 00:00:00 2001 From: Illia Grybkov Date: Tue, 10 May 2016 17:52:17 +0300 Subject: [PATCH 20/22] MAGETWO-52482: Fatal error appears if user less symbols in quick search field than minimal query length - Fix tests --- app/code/Magento/CatalogSearch/Model/Search/TableMapper.php | 3 +++ .../Magento/Framework/Search/Test/Unit/Request/CleanerTest.php | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/CatalogSearch/Model/Search/TableMapper.php b/app/code/Magento/CatalogSearch/Model/Search/TableMapper.php index c0057e3515c2a..d4f371e965e07 100644 --- a/app/code/Magento/CatalogSearch/Model/Search/TableMapper.php +++ b/app/code/Magento/CatalogSearch/Model/Search/TableMapper.php @@ -17,6 +17,9 @@ use Magento\Framework\Search\Request\QueryInterface as RequestQueryInterface; use Magento\Store\Model\StoreManagerInterface; +/** + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ class TableMapper { /** diff --git a/lib/internal/Magento/Framework/Search/Test/Unit/Request/CleanerTest.php b/lib/internal/Magento/Framework/Search/Test/Unit/Request/CleanerTest.php index 2d3368345b910..41346379f1ebc 100644 --- a/lib/internal/Magento/Framework/Search/Test/Unit/Request/CleanerTest.php +++ b/lib/internal/Magento/Framework/Search/Test/Unit/Request/CleanerTest.php @@ -338,7 +338,7 @@ public function testCleanQueryNotExists() /** * @expectedException \Magento\Framework\Search\Request\EmptyRequestDataException - * @expectedExceptionMessage Request query and filter is not set + * @expectedExceptionMessage Request query and filters are not set */ public function testCleanEmptyQueryAndFilter() { From bd169960286066ebaa9456eb4e6dd4e50e0c0ff5 Mon Sep 17 00:00:00 2001 From: Illia Grybkov Date: Wed, 11 May 2016 10:20:26 +0300 Subject: [PATCH 21/22] MAGETWO-52482: Fatal error appears if user less symbols in quick search field than minimal query length - Remove redundant ToDO --- .../CatalogSearch/Model/ResourceModel/Fulltext/Collection.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/code/Magento/CatalogSearch/Model/ResourceModel/Fulltext/Collection.php b/app/code/Magento/CatalogSearch/Model/ResourceModel/Fulltext/Collection.php index 0b5ee319b8088..9a1e4bbcf1b4c 100644 --- a/app/code/Magento/CatalogSearch/Model/ResourceModel/Fulltext/Collection.php +++ b/app/code/Magento/CatalogSearch/Model/ResourceModel/Fulltext/Collection.php @@ -400,7 +400,6 @@ public function getFacetedData($field) $result = []; $aggregations = $this->searchResult->getAggregations(); // This behavior is for case with empty object when we got EmptyRequestDataException - // TODO: Cover this behavior with unit test in scope of MAGETWO-51447 if (null !== $aggregations) { $bucket = $aggregations->getBucket($field . RequestGenerator::BUCKET_SUFFIX); if ($bucket) { From 01ec09a9511a8716331bacfe533375bb69682ae9 Mon Sep 17 00:00:00 2001 From: Anton Ohorodnyk Date: Thu, 12 May 2016 11:57:14 +0300 Subject: [PATCH 22/22] Revert "MAGETWO-52015: Bundle Product price range not include custom options" This reverts commit 66d7fb288280342c20c395fdd85feb0c88eed142. --- app/code/Magento/Catalog/Block/Product/ListProduct.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/code/Magento/Catalog/Block/Product/ListProduct.php b/app/code/Magento/Catalog/Block/Product/ListProduct.php index 0b251d96cd37c..996dbc191dfd1 100644 --- a/app/code/Magento/Catalog/Block/Product/ListProduct.php +++ b/app/code/Magento/Catalog/Block/Product/ListProduct.php @@ -122,7 +122,6 @@ protected function _getProductCollection() } } $this->_productCollection = $layer->getProductCollection(); - $this->_productCollection->addOptionsToResult(); $this->prepareSortableFieldsByCategory($layer->getCurrentCategory());