From 9532df60963c9fceeff5884b8e805c694b2a2393 Mon Sep 17 00:00:00 2001 From: Dzmitry Tabusheu Date: Fri, 21 Sep 2018 13:53:49 +0300 Subject: [PATCH 01/41] MAGETWO-91631: [Magento Cloud]Prefix in checkout not starting with blank value - Changed attribute validation class retrieving algorithm --- app/code/Magento/Customer/Block/Widget/Name.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Customer/Block/Widget/Name.php b/app/code/Magento/Customer/Block/Widget/Name.php index d50045f4a4092..6f1b051af7465 100644 --- a/app/code/Magento/Customer/Block/Widget/Name.php +++ b/app/code/Magento/Customer/Block/Widget/Name.php @@ -55,7 +55,7 @@ public function __construct( } /** - * @return void + * @inheritdoc */ public function _construct() { @@ -245,10 +245,13 @@ public function getStoreLabel($attributeCode) */ public function getAttributeValidationClass($attributeCode) { - return $this->_addressHelper->getAttributeValidationClass($attributeCode); + $attributeMetadata = $this->_getAttribute($attributeCode); + return $attributeMetadata ? $attributeMetadata->getFrontendClass() : ''; } /** + * Check if attribute is required + * * @param string $attributeCode * @return bool */ @@ -259,6 +262,8 @@ private function _isAttributeRequired($attributeCode) } /** + * Check if attribute is visible + * * @param string $attributeCode * @return bool */ From 482a1ba7e706266dd16f2c890cf41ad39d32c573 Mon Sep 17 00:00:00 2001 From: Alexey Yakimovich Date: Tue, 20 Nov 2018 16:44:44 +0300 Subject: [PATCH 02/41] MAGETWO-95836: [Magento Cloud] If a product has a custom attributes which requires a Unique Value, it cannot be saved when there's an active Scheduled Update - Fixed an issue with incorrect unique attributes validation when Scheduled Update is active; --- .../Model/ResourceModel/AbstractResource.php | 16 +++++++---- .../Catalog/Model/ResourceModel/Product.php | 23 +++++++++++---- .../Eav/Model/Entity/AbstractEntity.php | 28 +++++++++++++------ .../Attribute/UniqueValidationInterface.php | 23 +++++++++++++++ .../Entity/Attribute/UniqueValidator.php | 23 +++++++++++++++ app/code/Magento/Eav/etc/di.xml | 1 + 6 files changed, 94 insertions(+), 20 deletions(-) create mode 100644 app/code/Magento/Eav/Model/Entity/Attribute/UniqueValidationInterface.php create mode 100644 app/code/Magento/Eav/Model/Entity/Attribute/UniqueValidator.php diff --git a/app/code/Magento/Catalog/Model/ResourceModel/AbstractResource.php b/app/code/Magento/Catalog/Model/ResourceModel/AbstractResource.php index b9e629912a5b3..9cf1431317944 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/AbstractResource.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/AbstractResource.php @@ -7,6 +7,10 @@ namespace Magento\Catalog\Model\ResourceModel; use Magento\Eav\Model\Entity\Attribute\AbstractAttribute; +use Magento\Eav\Model\Entity\Attribute\Backend\AbstractBackend; +use Magento\Eav\Model\Entity\Attribute\Frontend\AbstractFrontend; +use Magento\Eav\Model\Entity\Attribute\Source\AbstractSource; +use Magento\Eav\Model\Entity\Attribute\UniqueValidationInterface; /** * Catalog entity abstract model @@ -37,16 +41,18 @@ abstract class AbstractResource extends \Magento\Eav\Model\Entity\AbstractEntity * @param \Magento\Store\Model\StoreManagerInterface $storeManager * @param \Magento\Catalog\Model\Factory $modelFactory * @param array $data + * @param UniqueValidationInterface|null $uniqueValidator */ public function __construct( \Magento\Eav\Model\Entity\Context $context, \Magento\Store\Model\StoreManagerInterface $storeManager, \Magento\Catalog\Model\Factory $modelFactory, - $data = [] + $data = [], + UniqueValidationInterface $uniqueValidator = null ) { $this->_storeManager = $storeManager; $this->_modelFactory = $modelFactory; - parent::__construct($context, $data); + parent::__construct($context, $data, $uniqueValidator); } /** @@ -86,9 +92,7 @@ protected function _isApplicableAttribute($object, $attribute) /** * Check whether attribute instance (attribute, backend, frontend or source) has method and applicable * - * @param AbstractAttribute|\Magento\Eav\Model\Entity\Attribute\Backend\AbstractBackend - * |\Magento\Eav\Model\Entity\Attribute\Frontend\AbstractFrontend - * |\Magento\Eav\Model\Entity\Attribute\Source\AbstractSource $instance + * @param AbstractAttribute|AbstractBackend|AbstractFrontend|AbstractSource $instance * @param string $method * @param array $args array of arguments * @return boolean @@ -112,6 +116,7 @@ protected function _isCallableAttributeInstance($instance, $method, $args) /** * Retrieve select object for loading entity attributes values + * * Join attribute store value * * @param \Magento\Framework\DataObject $object @@ -244,6 +249,7 @@ protected function _saveAttributeValue($object, $attribute, $value) /** * Check if attribute present for non default Store View. + * * Prevent "delete" query locking in a case when nothing to delete * * @param AbstractAttribute $attribute diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product.php b/app/code/Magento/Catalog/Model/ResourceModel/Product.php index d71ec23881982..24174391be829 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Product.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Product.php @@ -8,6 +8,7 @@ use Magento\Catalog\Model\ResourceModel\Product\Website\Link as ProductWebsiteLink; use Magento\Framework\App\ObjectManager; use Magento\Catalog\Model\Indexer\Category\Product\TableMaintainer; +use Magento\Eav\Model\Entity\Attribute\UniqueValidationInterface; /** * Product entity resource model @@ -101,6 +102,7 @@ class Product extends AbstractResource * @param \Magento\Catalog\Model\Product\Attribute\DefaultAttributes $defaultAttributes * @param array $data * @param TableMaintainer|null $tableMaintainer + * @param UniqueValidationInterface|null $uniqueValidator * * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ @@ -115,7 +117,8 @@ public function __construct( \Magento\Eav\Model\Entity\TypeFactory $typeFactory, \Magento\Catalog\Model\Product\Attribute\DefaultAttributes $defaultAttributes, $data = [], - TableMaintainer $tableMaintainer = null + TableMaintainer $tableMaintainer = null, + UniqueValidationInterface $uniqueValidator = null ) { $this->_categoryCollectionFactory = $categoryCollectionFactory; $this->_catalogCategory = $catalogCategory; @@ -127,7 +130,8 @@ public function __construct( $context, $storeManager, $modelFactory, - $data + $data, + $uniqueValidator ); $this->connectionName = 'catalog'; $this->tableMaintainer = $tableMaintainer ?: ObjectManager::getInstance()->get(TableMaintainer::class); @@ -289,7 +293,7 @@ protected function _afterSave(\Magento\Framework\DataObject $product) } /** - * {@inheritdoc} + * @inheritdoc */ public function delete($object) { @@ -593,7 +597,7 @@ public function countAll() } /** - * {@inheritdoc} + * @inheritdoc */ public function validate($object) { @@ -633,7 +637,7 @@ public function load($object, $entityId, $attributes = []) } /** - * {@inheritdoc} + * @inheritdoc * @SuppressWarnings(PHPMD.UnusedLocalVariable) * @since 101.0.0 */ @@ -675,6 +679,8 @@ public function save(\Magento\Framework\Model\AbstractModel $object) } /** + * Retrieve entity manager object + * * @return \Magento\Framework\EntityManager\EntityManager */ private function getEntityManager() @@ -687,6 +693,8 @@ private function getEntityManager() } /** + * Retrieve ProductWebsiteLink object + * * @deprecated 101.1.0 * @return ProductWebsiteLink */ @@ -696,6 +704,8 @@ private function getProductWebsiteLink() } /** + * Retrieve CategoryLink object + * * @deprecated 101.1.0 * @return \Magento\Catalog\Model\ResourceModel\Product\CategoryLink */ @@ -710,9 +720,10 @@ private function getProductCategoryLink() /** * Extends parent method to be appropriate for product. + * * Store id is required to correctly identify attribute value we are working with. * - * {@inheritdoc} + * @inheritdoc * @since 101.1.0 */ protected function getAttributeRow($entity, $object, $attribute) diff --git a/app/code/Magento/Eav/Model/Entity/AbstractEntity.php b/app/code/Magento/Eav/Model/Entity/AbstractEntity.php index 0522ea0432176..58350973b8de6 100644 --- a/app/code/Magento/Eav/Model/Entity/AbstractEntity.php +++ b/app/code/Magento/Eav/Model/Entity/AbstractEntity.php @@ -10,6 +10,7 @@ use Magento\Eav\Model\Entity\Attribute\Backend\AbstractBackend; use Magento\Eav\Model\Entity\Attribute\Frontend\AbstractFrontend; use Magento\Eav\Model\Entity\Attribute\Source\AbstractSource; +use Magento\Eav\Model\Entity\Attribute\UniqueValidationInterface; use Magento\Framework\App\Config\Element; use Magento\Framework\DataObject; use Magento\Framework\DB\Adapter\DuplicateException; @@ -215,12 +216,21 @@ abstract class AbstractEntity extends AbstractResource implements EntityInterfac */ protected $objectRelationProcessor; + /** + * @var UniqueValidationInterface + */ + private $uniqueValidator; + /** * @param Context $context * @param array $data + * @param UniqueValidationInterface|null $uniqueValidator */ - public function __construct(Context $context, $data = []) - { + public function __construct( + Context $context, + $data = [], + UniqueValidationInterface $uniqueValidator = null + ) { $this->_eavConfig = $context->getEavConfig(); $this->_resource = $context->getResource(); $this->_attrSetEntity = $context->getAttributeSetEntity(); @@ -229,6 +239,8 @@ public function __construct(Context $context, $data = []) $this->_universalFactory = $context->getUniversalFactory(); $this->transactionManager = $context->getTransactionManager(); $this->objectRelationProcessor = $context->getObjectRelationProcessor(); + $this->uniqueValidator = $uniqueValidator ?: + ObjectManager::getInstance()->get(UniqueValidationInterface::class); parent::__construct(); $properties = get_object_vars($this); foreach ($data as $key => $value) { @@ -488,6 +500,7 @@ public function addAttribute(AbstractAttribute $attribute, $object = null) /** * Get attributes by scope * + * @param string $suffix * @return array */ private function getAttributesByScope($suffix) @@ -958,12 +971,8 @@ public function checkAttributeUniqueValue(AbstractAttribute $attribute, $object) $data = $connection->fetchCol($select, $bind); - $objectId = $object->getData($entityIdField); - if ($objectId) { - if (isset($data[0])) { - return $data[0] == $objectId; - } - return true; + if ($object->getData($entityIdField)) { + return $this->uniqueValidator->validate($attribute, $object, $entityIdField, $data); } return !count($data); @@ -1972,7 +1981,8 @@ public function afterDelete(DataObject $object) /** * Load attributes for object - * if the object will not pass all attributes for this entity type will be loaded + * + * If the object will not pass all attributes for this entity type will be loaded * * @param array $attributes * @param AbstractEntity|null $object diff --git a/app/code/Magento/Eav/Model/Entity/Attribute/UniqueValidationInterface.php b/app/code/Magento/Eav/Model/Entity/Attribute/UniqueValidationInterface.php new file mode 100644 index 0000000000000..fcad9ae622a84 --- /dev/null +++ b/app/code/Magento/Eav/Model/Entity/Attribute/UniqueValidationInterface.php @@ -0,0 +1,23 @@ +getData($entityIdField); + } + return true; + } +} diff --git a/app/code/Magento/Eav/etc/di.xml b/app/code/Magento/Eav/etc/di.xml index 8e897b979d2f0..a4c89dcfab2af 100644 --- a/app/code/Magento/Eav/etc/di.xml +++ b/app/code/Magento/Eav/etc/di.xml @@ -8,6 +8,7 @@ + From 61e333de1769fadfb3178327ed0c5d0093e268b8 Mon Sep 17 00:00:00 2001 From: David Grigoryan Date: Tue, 27 Nov 2018 12:24:12 +0400 Subject: [PATCH 03/41] MAGETWO-95836: [Magento Cloud] If a product has a custom attributes which requires a Unique Value, it cannot be saved when there's an active Scheduled Update - Add automated test --- .../Test/Mftf/Section/AdminCreateProductAttributeSection.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminCreateProductAttributeSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminCreateProductAttributeSection.xml index 78d06afa7f003..7c330d90e20ac 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminCreateProductAttributeSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminCreateProductAttributeSection.xml @@ -73,6 +73,7 @@ type="button" selector="#advanced_fieldset-wrapper"/> + From 5bbda3ee0b29ff034496e4a8e8bcc4954ba0b0e4 Mon Sep 17 00:00:00 2001 From: Aliaksei_Manenak Date: Thu, 29 Nov 2018 19:05:22 +0300 Subject: [PATCH 04/41] MAGETWO-95836: [Magento Cloud] If a product has a custom attributes which requires a Unique Value, it cannot be saved when there's an active Scheduled Update - Get appropriate linked field. --- app/code/Magento/Eav/Model/Entity/AbstractEntity.php | 3 +-- .../Eav/Model/Entity/Attribute/UniqueValidationInterface.php | 4 ++-- .../Magento/Eav/Model/Entity/Attribute/UniqueValidator.php | 4 ++-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/Eav/Model/Entity/AbstractEntity.php b/app/code/Magento/Eav/Model/Entity/AbstractEntity.php index 58350973b8de6..704ec0a7f701b 100644 --- a/app/code/Magento/Eav/Model/Entity/AbstractEntity.php +++ b/app/code/Magento/Eav/Model/Entity/AbstractEntity.php @@ -931,7 +931,7 @@ public function checkAttributeUniqueValue(AbstractAttribute $attribute, $object) $connection = $this->getConnection(); $select = $connection->select(); - $entityIdField = $this->getEntityIdField(); + $entityIdField = $object->getResource()->getLinkField(); $attributeBackend = $attribute->getBackend(); if ($attributeBackend->getType() === 'static') { $value = $object->getData($attribute->getAttributeCode()); @@ -953,7 +953,6 @@ public function checkAttributeUniqueValue(AbstractAttribute $attribute, $object) 'value' => trim($value), ]; - $entityIdField = $object->getResource()->getLinkField(); $select->from( $attributeBackend->getTable(), $entityIdField diff --git a/app/code/Magento/Eav/Model/Entity/Attribute/UniqueValidationInterface.php b/app/code/Magento/Eav/Model/Entity/Attribute/UniqueValidationInterface.php index fcad9ae622a84..648f51ade11de 100644 --- a/app/code/Magento/Eav/Model/Entity/Attribute/UniqueValidationInterface.php +++ b/app/code/Magento/Eav/Model/Entity/Attribute/UniqueValidationInterface.php @@ -15,9 +15,9 @@ interface UniqueValidationInterface * * @param AbstractAttribute $attribute * @param \Magento\Framework\DataObject $object - * @param string $entityIdField + * @param string $entityLinkField * @param array $entityIds * @return bool */ - public function validate(AbstractAttribute $attribute, $object, $entityIdField, array $entityIds); + public function validate(AbstractAttribute $attribute, $object, $entityLinkField, array $entityIds); } diff --git a/app/code/Magento/Eav/Model/Entity/Attribute/UniqueValidator.php b/app/code/Magento/Eav/Model/Entity/Attribute/UniqueValidator.php index e439293ae46c2..f9c7ffecedc60 100644 --- a/app/code/Magento/Eav/Model/Entity/Attribute/UniqueValidator.php +++ b/app/code/Magento/Eav/Model/Entity/Attribute/UniqueValidator.php @@ -13,10 +13,10 @@ class UniqueValidator implements UniqueValidationInterface /** * @inheritdoc */ - public function validate(AbstractAttribute $attribute, $object, $entityIdField, array $entityIds) + public function validate(AbstractAttribute $attribute, $object, $entityLinkField, array $entityIds) { if (isset($entityIds[0])) { - return $entityIds[0] == $object->getData($entityIdField); + return $entityIds[0] == $object->getData($entityLinkField); } return true; } From 70157b22377d2f9b94375888e89476427ed20893 Mon Sep 17 00:00:00 2001 From: vprohorov Date: Mon, 10 Dec 2018 16:18:13 +0300 Subject: [PATCH 05/41] MAGETWO-96852: [2.3.x] Impossible to sort Root Categories via drag'n'drop - Added possibility to drag'n'drop root categories --- .../Adminhtml/Category/AbstractCategory.php | 29 +++++++++++++++++-- .../templates/catalog/category/tree.phtml | 1 + 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Catalog/Block/Adminhtml/Category/AbstractCategory.php b/app/code/Magento/Catalog/Block/Adminhtml/Category/AbstractCategory.php index 331679874629b..ffb648cdf438a 100644 --- a/app/code/Magento/Catalog/Block/Adminhtml/Category/AbstractCategory.php +++ b/app/code/Magento/Catalog/Block/Adminhtml/Category/AbstractCategory.php @@ -67,6 +67,8 @@ public function getCategory() } /** + * Get category id + * * @return int|string|null */ public function getCategoryId() @@ -78,6 +80,8 @@ public function getCategoryId() } /** + * Get category name + * * @return string */ public function getCategoryName() @@ -86,6 +90,8 @@ public function getCategoryName() } /** + * Get category path + * * @return mixed */ public function getCategoryPath() @@ -97,6 +103,8 @@ public function getCategoryPath() } /** + * Check store root category + * * @return bool */ public function hasStoreRootCategory() @@ -109,6 +117,8 @@ public function hasStoreRootCategory() } /** + * Get store from request + * * @return Store */ public function getStore() @@ -118,6 +128,8 @@ public function getStore() } /** + * Get root category for tree + * * @param mixed|null $parentNodeCategory * @param int $recursionLevel * @return Node|array|null @@ -149,10 +161,11 @@ public function getRoot($parentNodeCategory = null, $recursionLevel = 3) $root = $tree->getNodeById($rootId); - if ($root && $rootId != \Magento\Catalog\Model\Category::TREE_ROOT_ID) { + if ($root) { $root->setIsVisible(true); - } elseif ($root && $root->getId() == \Magento\Catalog\Model\Category::TREE_ROOT_ID) { - $root->setName(__('Root')); + if ($root->getId() == \Magento\Catalog\Model\Category::TREE_ROOT_ID) { + $root->setName(__('Root')); + } } $this->_coreRegistry->register('root', $root); @@ -162,6 +175,8 @@ public function getRoot($parentNodeCategory = null, $recursionLevel = 3) } /** + * Get Default Store Id + * * @return int */ protected function _getDefaultStoreId() @@ -170,6 +185,8 @@ protected function _getDefaultStoreId() } /** + * Get category collection + * * @return \Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection */ public function getCategoryCollection() @@ -227,6 +244,8 @@ public function getRootByIds($ids) } /** + * Get category node for tree + * * @param mixed $parentNodeCategory * @param int $recursionLevel * @return Node @@ -249,6 +268,8 @@ public function getNode($parentNodeCategory, $recursionLevel = 2) } /** + * Get category save url + * * @param array $args * @return string */ @@ -260,6 +281,8 @@ public function getSaveUrl(array $args = []) } /** + * Get category edit url + * * @return string */ public function getEditUrl() diff --git a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/category/tree.phtml b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/category/tree.phtml index 9865589556e7b..ba386f89d6ccd 100644 --- a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/category/tree.phtml +++ b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/category/tree.phtml @@ -302,6 +302,7 @@ } //updateContent(url); //commented since ajax requests replaced with http ones to load a category + jQuery('#tree-div').find('.x-tree-node-el').first().remove(); } jQuery(function () { From 1c7f70378d230d184eea99987bb02599e9d7b42e Mon Sep 17 00:00:00 2001 From: Mikalai Shostka Date: Wed, 12 Dec 2018 12:36:28 +0300 Subject: [PATCH 06/41] MAGETWO-96421: [2.3.x] Header Minicart ,Shopping cart page and Checkout page show incorrect product name - Add store id for sidebar - Add plugin for switch store --- .../Magento/Checkout/Block/Cart/Sidebar.php | 10 ++- .../Magento/Checkout/CustomerData/Cart.php | 5 +- .../Test/Unit/Block/Cart/SidebarTest.php | 5 +- .../Test/Unit/CustomerData/CartTest.php | 6 +- .../view/frontend/web/js/view/minicart.js | 4 +- app/code/Magento/Quote/Model/Quote.php | 5 +- .../Quote/Plugin/UpdateQuoteItemStore.php | 70 +++++++++++++++++++ app/code/Magento/Quote/etc/frontend/di.xml | 3 + 8 files changed, 97 insertions(+), 11 deletions(-) create mode 100644 app/code/Magento/Quote/Plugin/UpdateQuoteItemStore.php diff --git a/app/code/Magento/Checkout/Block/Cart/Sidebar.php b/app/code/Magento/Checkout/Block/Cart/Sidebar.php index 92ba6bf2bbbb1..c5e309df3cad6 100644 --- a/app/code/Magento/Checkout/Block/Cart/Sidebar.php +++ b/app/code/Magento/Checkout/Block/Cart/Sidebar.php @@ -82,11 +82,14 @@ public function getConfig() 'baseUrl' => $this->getBaseUrl(), 'minicartMaxItemsVisible' => $this->getMiniCartMaxItemsCount(), 'websiteId' => $this->_storeManager->getStore()->getWebsiteId(), - 'maxItemsToDisplay' => $this->getMaxItemsToDisplay() + 'maxItemsToDisplay' => $this->getMaxItemsToDisplay(), + 'storeId' => $this->_storeManager->getStore()->getId() ]; } /** + * Get serialized config + * * @return string * @since 100.2.0 */ @@ -96,6 +99,8 @@ public function getSerializedConfig() } /** + * Get image html template + * * @return string */ public function getImageHtmlTemplate() @@ -130,6 +135,7 @@ public function getShoppingCartUrl() * * @return string * @codeCoverageIgnore + * @SuppressWarnings(PHPMD.RequestAwareBlockMethod) */ public function getUpdateItemQtyUrl() { @@ -141,6 +147,7 @@ public function getUpdateItemQtyUrl() * * @return string * @codeCoverageIgnore + * @SuppressWarnings(PHPMD.RequestAwareBlockMethod) */ public function getRemoveItemUrl() { @@ -210,6 +217,7 @@ private function getMiniCartMaxItemsCount() /** * Returns maximum cart items to display + * * This setting regulates how many items will be displayed in minicart * * @return int diff --git a/app/code/Magento/Checkout/CustomerData/Cart.php b/app/code/Magento/Checkout/CustomerData/Cart.php index ddb077462ef10..0589a5c5b97f7 100644 --- a/app/code/Magento/Checkout/CustomerData/Cart.php +++ b/app/code/Magento/Checkout/CustomerData/Cart.php @@ -82,7 +82,7 @@ public function __construct( } /** - * {@inheritdoc} + * @inheritdoc */ public function getSectionData() { @@ -98,7 +98,8 @@ public function getSectionData() 'items' => $this->getRecentItems(), 'extra_actions' => $this->layout->createBlock(\Magento\Catalog\Block\ShortcutButtons::class)->toHtml(), 'isGuestCheckoutAllowed' => $this->isGuestCheckoutAllowed(), - 'website_id' => $this->getQuote()->getStore()->getWebsiteId() + 'website_id' => $this->getQuote()->getStore()->getWebsiteId(), + 'storeId' => $this->getQuote()->getStore()->getStoreId() ]; } diff --git a/app/code/Magento/Checkout/Test/Unit/Block/Cart/SidebarTest.php b/app/code/Magento/Checkout/Test/Unit/Block/Cart/SidebarTest.php index 1c5224d007ec8..f69ced3b094c7 100644 --- a/app/code/Magento/Checkout/Test/Unit/Block/Cart/SidebarTest.php +++ b/app/code/Magento/Checkout/Test/Unit/Block/Cart/SidebarTest.php @@ -144,7 +144,8 @@ public function testGetConfig() 'baseUrl' => $baseUrl, 'minicartMaxItemsVisible' => 3, 'websiteId' => 100, - 'maxItemsToDisplay' => 8 + 'maxItemsToDisplay' => 8, + 'storeId' => null ]; $valueMap = [ @@ -161,7 +162,7 @@ public function testGetConfig() $this->urlBuilderMock->expects($this->exactly(4)) ->method('getUrl') ->willReturnMap($valueMap); - $this->storeManagerMock->expects($this->exactly(2))->method('getStore')->willReturn($storeMock); + $this->storeManagerMock->expects($this->any())->method('getStore')->willReturn($storeMock); $storeMock->expects($this->once())->method('getBaseUrl')->willReturn($baseUrl); $this->scopeConfigMock->expects($this->at(0)) diff --git a/app/code/Magento/Checkout/Test/Unit/CustomerData/CartTest.php b/app/code/Magento/Checkout/Test/Unit/CustomerData/CartTest.php index 75e181cbabd08..e3e13cc5b1e69 100644 --- a/app/code/Magento/Checkout/Test/Unit/CustomerData/CartTest.php +++ b/app/code/Magento/Checkout/Test/Unit/CustomerData/CartTest.php @@ -113,7 +113,7 @@ public function testGetSectionData() $storeMock = $this->createPartialMock(\Magento\Store\Model\System\Store::class, ['getWebsiteId']); $storeMock->expects($this->once())->method('getWebsiteId')->willReturn($websiteId); - $quoteMock->expects($this->once())->method('getStore')->willReturn($storeMock); + $quoteMock->expects($this->any())->method('getStore')->willReturn($storeMock); $productMock = $this->createPartialMock( \Magento\Catalog\Model\Product::class, @@ -162,6 +162,7 @@ public function testGetSectionData() 'isGuestCheckoutAllowed' => 1, 'website_id' => $websiteId, 'subtotalAmount' => 200, + 'storeId' => null ]; $this->assertEquals($expectedResult, $this->model->getSectionData()); } @@ -199,7 +200,7 @@ public function testGetSectionDataWithCompositeProduct() $storeMock = $this->createPartialMock(\Magento\Store\Model\System\Store::class, ['getWebsiteId']); $storeMock->expects($this->once())->method('getWebsiteId')->willReturn($websiteId); - $quoteMock->expects($this->once())->method('getStore')->willReturn($storeMock); + $quoteMock->expects($this->any())->method('getStore')->willReturn($storeMock); $this->checkoutCartMock->expects($this->once())->method('getSummaryQty')->willReturn($summaryQty); $this->checkoutHelperMock->expects($this->once()) @@ -265,6 +266,7 @@ public function testGetSectionDataWithCompositeProduct() 'isGuestCheckoutAllowed' => 1, 'website_id' => $websiteId, 'subtotalAmount' => 200, + 'storeId' => null ]; $this->assertEquals($expectedResult, $this->model->getSectionData()); } diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/minicart.js b/app/code/Magento/Checkout/view/frontend/web/js/view/minicart.js index a2f8c8c56ff33..f3dddbe218fe9 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/view/minicart.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/view/minicart.js @@ -101,7 +101,9 @@ define([ self.isLoading(true); }); - if (cartData()['website_id'] !== window.checkout.websiteId) { + if (cartData()['website_id'] !== window.checkout.websiteId || + cartData()['storeId'] !== window.checkout.storeId + ) { customerData.reload(['cart'], false); } diff --git a/app/code/Magento/Quote/Model/Quote.php b/app/code/Magento/Quote/Model/Quote.php index 3f04519713687..cb5a36f8dd728 100644 --- a/app/code/Magento/Quote/Model/Quote.php +++ b/app/code/Magento/Quote/Model/Quote.php @@ -1375,14 +1375,13 @@ public function addShippingAddress(\Magento\Quote\Api\Data\AddressInterface $add * * @param bool $useCache * @return \Magento\Eav\Model\Entity\Collection\AbstractCollection - * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function getItemsCollection($useCache = true) { - if ($this->hasItemsCollection()) { + if ($this->hasItemsCollection() && $useCache) { return $this->getData('items_collection'); } - if (null === $this->_items) { + if (null === $this->_items || !$useCache) { $this->_items = $this->_quoteItemCollectionFactory->create(); $this->extensionAttributesJoinProcessor->process($this->_items); $this->_items->setQuote($this); diff --git a/app/code/Magento/Quote/Plugin/UpdateQuoteItemStore.php b/app/code/Magento/Quote/Plugin/UpdateQuoteItemStore.php new file mode 100644 index 0000000000000..bc783ce3541d2 --- /dev/null +++ b/app/code/Magento/Quote/Plugin/UpdateQuoteItemStore.php @@ -0,0 +1,70 @@ +quoteRepository = $quoteRepository; + $this->checkoutSession = $checkoutSession; + } + + /** + * Update store id in active quote after store view switching. + * + * @param StoreSwitcherInterface $subject + * @param string $result + * @param StoreInterface $fromStore store where we came from + * @param StoreInterface $targetStore store where to go to + * @param string $redirectUrl original url requested for redirect after switching + * @return string url to be redirected after switching + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterSwitch( + StoreSwitcherInterface $subject, + $result, + StoreInterface $fromStore, + StoreInterface $targetStore, + string $redirectUrl + ): string { + $quote = $this->checkoutSession->getQuote(); + if ($quote->getIsActive()) { + $quote->setStoreId( + $targetStore->getId() + ); + $quote->getItemsCollection(false); + $this->quoteRepository->save($quote); + } + return $result; + } +} diff --git a/app/code/Magento/Quote/etc/frontend/di.xml b/app/code/Magento/Quote/etc/frontend/di.xml index 25acd6763ba56..91f4cfbf60aba 100644 --- a/app/code/Magento/Quote/etc/frontend/di.xml +++ b/app/code/Magento/Quote/etc/frontend/di.xml @@ -12,6 +12,9 @@ Magento\Checkout\Model\Session\Proxy + + + From d5da4872c2378e488695a3fbf7eb52413b3f66a1 Mon Sep 17 00:00:00 2001 From: vprohorov Date: Tue, 8 Jan 2019 18:30:37 +0300 Subject: [PATCH 07/41] MAGETWO-96852: [2.3.x] Impossible to sort Root Categories via drag'n'drop - Hiding root category for category widget --- .../adminhtml/templates/catalog/category/widget/tree.phtml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/category/widget/tree.phtml b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/category/widget/tree.phtml index dbe66ef1aecd3..69737b8a37c1c 100644 --- a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/category/widget/tree.phtml +++ b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/category/widget/tree.phtml @@ -160,7 +160,7 @@ jQuery(function() loader: categoryLoader, enableDD: false, containerScroll: true, - rootVisible: 'getRoot()->getIsVisible() ?>', + rootVisible: false, useAjax: true, currentNodeId: getCategoryId() ?>, addNodeTo: false @@ -177,7 +177,7 @@ jQuery(function() text: 'Psw', draggable: false, id: getRoot()->getId() ?>, - expanded: getIsWasExpanded() ?>, + expanded: true, category_id: getCategoryId() ?> }; From 67591560a5dcc88ad57339f3417b18701bf1d70c Mon Sep 17 00:00:00 2001 From: Lusine Papyan Date: Wed, 9 Jan 2019 15:17:28 +0400 Subject: [PATCH 08/41] MAGETWO-95812: Required RMA Attributes are not validated while Customer submits a return - Update automated test --- .../ActionGroup/OrderAndReturnActionGroup.xml | 36 ------------------- .../SalesEnableRMAStorefrontConfigData.xml | 23 ------------ .../Metadata/sales_enable_rma_config-meta.xml | 20 ----------- .../Page/StorefrontCreateNewReturnPage.xml | 14 -------- .../Page/StorefrontOrderInformationPage.xml | 14 -------- .../Page/StorefrontOrdersAndReturnsPage.xml | 15 -------- .../StorefrontCreateNewReturnMainSection.xml | 18 ---------- ...efrontOrderAndReturnInformationSection.xml | 20 ----------- .../StorefrontOrderInformationMainSection.xml | 15 -------- 9 files changed, 175 deletions(-) delete mode 100644 app/code/Magento/Sales/Test/Mftf/ActionGroup/OrderAndReturnActionGroup.xml delete mode 100644 app/code/Magento/Sales/Test/Mftf/Data/SalesEnableRMAStorefrontConfigData.xml delete mode 100644 app/code/Magento/Sales/Test/Mftf/Metadata/sales_enable_rma_config-meta.xml delete mode 100644 app/code/Magento/Sales/Test/Mftf/Page/StorefrontCreateNewReturnPage.xml delete mode 100644 app/code/Magento/Sales/Test/Mftf/Page/StorefrontOrderInformationPage.xml delete mode 100644 app/code/Magento/Sales/Test/Mftf/Page/StorefrontOrdersAndReturnsPage.xml delete mode 100644 app/code/Magento/Sales/Test/Mftf/Section/StorefrontCreateNewReturnMainSection.xml delete mode 100644 app/code/Magento/Sales/Test/Mftf/Section/StorefrontOrderAndReturnInformationSection.xml delete mode 100644 app/code/Magento/Sales/Test/Mftf/Section/StorefrontOrderInformationMainSection.xml diff --git a/app/code/Magento/Sales/Test/Mftf/ActionGroup/OrderAndReturnActionGroup.xml b/app/code/Magento/Sales/Test/Mftf/ActionGroup/OrderAndReturnActionGroup.xml deleted file mode 100644 index c46dd612022fd..0000000000000 --- a/app/code/Magento/Sales/Test/Mftf/ActionGroup/OrderAndReturnActionGroup.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/code/Magento/Sales/Test/Mftf/Data/SalesEnableRMAStorefrontConfigData.xml b/app/code/Magento/Sales/Test/Mftf/Data/SalesEnableRMAStorefrontConfigData.xml deleted file mode 100644 index 76ff20813483e..0000000000000 --- a/app/code/Magento/Sales/Test/Mftf/Data/SalesEnableRMAStorefrontConfigData.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - EnableRMAStorefront - - - 1 - - - - DisableRMAStorefront - - - 0 - - diff --git a/app/code/Magento/Sales/Test/Mftf/Metadata/sales_enable_rma_config-meta.xml b/app/code/Magento/Sales/Test/Mftf/Metadata/sales_enable_rma_config-meta.xml deleted file mode 100644 index 86226265dd146..0000000000000 --- a/app/code/Magento/Sales/Test/Mftf/Metadata/sales_enable_rma_config-meta.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - string - - - - - - diff --git a/app/code/Magento/Sales/Test/Mftf/Page/StorefrontCreateNewReturnPage.xml b/app/code/Magento/Sales/Test/Mftf/Page/StorefrontCreateNewReturnPage.xml deleted file mode 100644 index 2a14f814eac16..0000000000000 --- a/app/code/Magento/Sales/Test/Mftf/Page/StorefrontCreateNewReturnPage.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - -
- - diff --git a/app/code/Magento/Sales/Test/Mftf/Page/StorefrontOrderInformationPage.xml b/app/code/Magento/Sales/Test/Mftf/Page/StorefrontOrderInformationPage.xml deleted file mode 100644 index 4159f9435c866..0000000000000 --- a/app/code/Magento/Sales/Test/Mftf/Page/StorefrontOrderInformationPage.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - -
- - diff --git a/app/code/Magento/Sales/Test/Mftf/Page/StorefrontOrdersAndReturnsPage.xml b/app/code/Magento/Sales/Test/Mftf/Page/StorefrontOrdersAndReturnsPage.xml deleted file mode 100644 index 32d94c3175807..0000000000000 --- a/app/code/Magento/Sales/Test/Mftf/Page/StorefrontOrdersAndReturnsPage.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - -
-
- - diff --git a/app/code/Magento/Sales/Test/Mftf/Section/StorefrontCreateNewReturnMainSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/StorefrontCreateNewReturnMainSection.xml deleted file mode 100644 index fe8391cf3c28f..0000000000000 --- a/app/code/Magento/Sales/Test/Mftf/Section/StorefrontCreateNewReturnMainSection.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - -
- - - - - -
-
diff --git a/app/code/Magento/Sales/Test/Mftf/Section/StorefrontOrderAndReturnInformationSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/StorefrontOrderAndReturnInformationSection.xml deleted file mode 100644 index aa57dd9bc17ba..0000000000000 --- a/app/code/Magento/Sales/Test/Mftf/Section/StorefrontOrderAndReturnInformationSection.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - -
- - - - - - - -
-
diff --git a/app/code/Magento/Sales/Test/Mftf/Section/StorefrontOrderInformationMainSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/StorefrontOrderInformationMainSection.xml deleted file mode 100644 index e42c301206152..0000000000000 --- a/app/code/Magento/Sales/Test/Mftf/Section/StorefrontOrderInformationMainSection.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - -
- - -
-
From 827235f34d52d8077176880a4bf53704ffc78a0c Mon Sep 17 00:00:00 2001 From: Yauhen_Lyskavets Date: Fri, 4 Jan 2019 17:47:11 +0300 Subject: [PATCH 09/41] MAGETWO-95186: [2.3] Incorrect table rates shipping charge at check out with cart price rule - Fix shipping discounts. --- .../Model/Carrier/Tablerate.php | 12 ++- .../Patch/Data/UpdateShippingTablerate.php | 73 +++++++++++++ .../Magento/OfflineShipping/etc/db_schema.xml | 2 +- .../Quote/Model/Cart/CartTotalRepository.php | 2 +- .../Model/Cart/CartTotalRepositoryTest.php | 3 +- app/code/Magento/Quote/etc/sales.xml | 2 +- .../Quote/Address/Total/ShippingDiscount.php | 101 ++++++++++++++++++ .../SalesRule/Model/Quote/Discount.php | 22 ++-- app/code/Magento/SalesRule/etc/sales.xml | 3 +- app/code/Magento/Tax/etc/sales.xml | 2 +- .../Quote/Api/CartTotalRepositoryTest.php | 68 +++++------- .../Api/GuestCartTotalRepositoryTest.php | 9 +- .../_files/quote_with_shipping_method.php | 12 ++- 13 files changed, 245 insertions(+), 66 deletions(-) create mode 100644 app/code/Magento/OfflineShipping/Setup/Patch/Data/UpdateShippingTablerate.php create mode 100644 app/code/Magento/SalesRule/Model/Quote/Address/Total/ShippingDiscount.php diff --git a/app/code/Magento/OfflineShipping/Model/Carrier/Tablerate.php b/app/code/Magento/OfflineShipping/Model/Carrier/Tablerate.php index 2c4fc9a4ccfe1..ab0aed3b71453 100644 --- a/app/code/Magento/OfflineShipping/Model/Carrier/Tablerate.php +++ b/app/code/Magento/OfflineShipping/Model/Carrier/Tablerate.php @@ -18,6 +18,8 @@ class Tablerate extends \Magento\Shipping\Model\Carrier\AbstractCarrier implements \Magento\Shipping\Model\Carrier\CarrierInterface { + const CONDITION_CODE_PACKAGE_VALUE_WITH_DISCOUNT = 'package_value_with_discount'; + /** * @var string */ @@ -82,6 +84,8 @@ public function __construct( } /** + * Collect rates. + * * @param RateRequest $request * @return \Magento\Shipping\Model\Rate\Result * @SuppressWarnings(PHPMD.CyclomaticComplexity) @@ -199,6 +203,8 @@ public function collectRates(RateRequest $request) } /** + * Get rate. + * * @param \Magento\Quote\Model\Quote\Address\RateRequest $request * @return array|bool */ @@ -208,6 +214,8 @@ public function getRate(\Magento\Quote\Model\Quote\Address\RateRequest $request) } /** + * Get code. + * * @param string $type * @param string $code * @return array @@ -218,12 +226,12 @@ public function getCode($type, $code = '') $codes = [ 'condition_name' => [ 'package_weight' => __('Weight vs. Destination'), - 'package_value' => __('Price vs. Destination'), + self::CONDITION_CODE_PACKAGE_VALUE_WITH_DISCOUNT => __('Price vs. Destination'), 'package_qty' => __('# of Items vs. Destination'), ], 'condition_name_short' => [ 'package_weight' => __('Weight (and above)'), - 'package_value' => __('Order Subtotal (and above)'), + self::CONDITION_CODE_PACKAGE_VALUE_WITH_DISCOUNT => __('Order Subtotal (and above)'), 'package_qty' => __('# of Items (and above)'), ], ]; diff --git a/app/code/Magento/OfflineShipping/Setup/Patch/Data/UpdateShippingTablerate.php b/app/code/Magento/OfflineShipping/Setup/Patch/Data/UpdateShippingTablerate.php new file mode 100644 index 0000000000000..3cfc752fdcf05 --- /dev/null +++ b/app/code/Magento/OfflineShipping/Setup/Patch/Data/UpdateShippingTablerate.php @@ -0,0 +1,73 @@ +moduleDataSetup = $moduleDataSetup; + } + + /** + * @inheritdoc + */ + public function apply() + { + $this->moduleDataSetup->getConnection()->startSetup(); + $connection = $this->moduleDataSetup->getConnection(); + $connection->update( + $this->moduleDataSetup->getTable('shipping_tablerate'), + ['condition_name' => Tablerate::CONDITION_CODE_PACKAGE_VALUE_WITH_DISCOUNT], + [new \Zend_Db_Expr('condition_name = \'package_value\'')] + ); + $connection->update( + $this->moduleDataSetup->getTable('core_config_data'), + ['value' => Tablerate::CONDITION_CODE_PACKAGE_VALUE_WITH_DISCOUNT], + [ + new \Zend_Db_Expr('value = \'package_value\''), + new \Zend_Db_Expr('path = \'carriers/tablerate/condition_name\'') + ] + ); + $this->moduleDataSetup->getConnection()->endSetup(); + + $connection->endSetup(); + } + + /** + * @inheritdoc + */ + public static function getDependencies() + { + return []; + } + + /** + * @inheritdoc + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/OfflineShipping/etc/db_schema.xml b/app/code/Magento/OfflineShipping/etc/db_schema.xml index 80f4b56a1723d..25a3ce306ef68 100644 --- a/app/code/Magento/OfflineShipping/etc/db_schema.xml +++ b/app/code/Magento/OfflineShipping/etc/db_schema.xml @@ -18,7 +18,7 @@ default="0" comment="Destination Region Id"/> - + quoteRepositoryMock = $this->createMock(\Magento\Quote\Api\CartRepositoryInterface::class); $this->addressMock = $this->createPartialMock( diff --git a/app/code/Magento/Quote/etc/sales.xml b/app/code/Magento/Quote/etc/sales.xml index 3d54a6375c8d9..3db72a1226236 100644 --- a/app/code/Magento/Quote/etc/sales.xml +++ b/app/code/Magento/Quote/etc/sales.xml @@ -9,7 +9,7 @@
- +
diff --git a/app/code/Magento/SalesRule/Model/Quote/Address/Total/ShippingDiscount.php b/app/code/Magento/SalesRule/Model/Quote/Address/Total/ShippingDiscount.php new file mode 100644 index 0000000000000..c37ca276e0ee2 --- /dev/null +++ b/app/code/Magento/SalesRule/Model/Quote/Address/Total/ShippingDiscount.php @@ -0,0 +1,101 @@ +calculator = $calculator; + } + + /** + * @inheritdoc + * + * @param Quote $quote + * @param ShippingAssignment $shippingAssignment + * @param Total $total + * @return ShippingDiscount + */ + public function collect(Quote $quote, ShippingAssignment $shippingAssignment, Total $total): self + { + parent::collect($quote, $shippingAssignment, $total); + + $address = $shippingAssignment->getShipping()->getAddress(); + $this->calculator->reset($address); + + $items = $shippingAssignment->getItems(); + if (!count($items)) { + return $this; + } + + $address->setShippingDiscountAmount(0); + $address->setBaseShippingDiscountAmount(0); + if ($address->getShippingAmount()) { + $this->calculator->processShippingAmount($address); + $total->addTotalAmount(DiscountCollector::COLLECTOR_TYPE_CODE, -$address->getShippingDiscountAmount()); + $total->addBaseTotalAmount( + DiscountCollector::COLLECTOR_TYPE_CODE, + -$address->getBaseShippingDiscountAmount() + ); + $total->setShippingDiscountAmount($address->getShippingDiscountAmount()); + $total->setBaseShippingDiscountAmount($address->getBaseShippingDiscountAmount()); + + $this->calculator->prepareDescription($address); + $total->setDiscountDescription($address->getDiscountDescription()); + $total->setSubtotalWithDiscount($total->getSubtotal() + $total->getDiscountAmount()); + $total->setBaseSubtotalWithDiscount($total->getBaseSubtotal() + $total->getBaseDiscountAmount()); + + $address->setDiscountAmount($total->getDiscountAmount()); + $address->setBaseDiscountAmount($total->getBaseDiscountAmount()); + } + + return $this; + } + + /** + * @inheritdoc + * + * @param \Magento\Quote\Model\Quote $quote + * @param \Magento\Quote\Model\Quote\Address\Total $total + * @return array + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function fetch(Quote $quote, Total $total): array + { + $result = []; + $amount = $total->getDiscountAmount(); + + if ($amount != 0) { + $description = $total->getDiscountDescription() ?: ''; + $result = [ + 'code' => DiscountCollector::COLLECTOR_TYPE_CODE, + 'title' => strlen($description) ? __('Discount (%1)', $description) : __('Discount'), + 'value' => $amount + ]; + } + return $result; + } +} diff --git a/app/code/Magento/SalesRule/Model/Quote/Discount.php b/app/code/Magento/SalesRule/Model/Quote/Discount.php index 693a61b272f66..315ce874513a3 100644 --- a/app/code/Magento/SalesRule/Model/Quote/Discount.php +++ b/app/code/Magento/SalesRule/Model/Quote/Discount.php @@ -5,8 +5,13 @@ */ namespace Magento\SalesRule\Model\Quote; +/** + * Discount totals calculation model. + */ class Discount extends \Magento\Quote\Model\Quote\Address\Total\AbstractTotal { + const COLLECTOR_TYPE_CODE = 'discount'; + /** * Discount calculation object * @@ -43,7 +48,7 @@ public function __construct( \Magento\SalesRule\Model\Validator $validator, \Magento\Framework\Pricing\PriceCurrencyInterface $priceCurrency ) { - $this->setCode('discount'); + $this->setCode(self::COLLECTOR_TYPE_CODE); $this->eventManager = $eventManager; $this->calculator = $validator; $this->storeManager = $storeManager; @@ -124,21 +129,14 @@ public function collect( } } - /** Process shipping amount discount */ - $address->setShippingDiscountAmount(0); - $address->setBaseShippingDiscountAmount(0); - if ($address->getShippingAmount()) { - $this->calculator->processShippingAmount($address); - $total->addTotalAmount($this->getCode(), -$address->getShippingDiscountAmount()); - $total->addBaseTotalAmount($this->getCode(), -$address->getBaseShippingDiscountAmount()); - $total->setShippingDiscountAmount($address->getShippingDiscountAmount()); - $total->setBaseShippingDiscountAmount($address->getBaseShippingDiscountAmount()); - } - $this->calculator->prepareDescription($address); $total->setDiscountDescription($address->getDiscountDescription()); $total->setSubtotalWithDiscount($total->getSubtotal() + $total->getDiscountAmount()); $total->setBaseSubtotalWithDiscount($total->getBaseSubtotal() + $total->getBaseDiscountAmount()); + + $address->setDiscountAmount($total->getDiscountAmount()); + $address->setBaseDiscountAmount($total->getBaseDiscountAmount()); + return $this; } diff --git a/app/code/Magento/SalesRule/etc/sales.xml b/app/code/Magento/SalesRule/etc/sales.xml index 3ab197d40b0df..d2db664224873 100644 --- a/app/code/Magento/SalesRule/etc/sales.xml +++ b/app/code/Magento/SalesRule/etc/sales.xml @@ -8,7 +8,8 @@
- + +
diff --git a/app/code/Magento/Tax/etc/sales.xml b/app/code/Magento/Tax/etc/sales.xml index 64d29ece898de..15afd499bce3f 100644 --- a/app/code/Magento/Tax/etc/sales.xml +++ b/app/code/Magento/Tax/etc/sales.xml @@ -9,7 +9,7 @@
- + diff --git a/dev/tests/api-functional/testsuite/Magento/Quote/Api/CartTotalRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Quote/Api/CartTotalRepositoryTest.php index 609ae1cfe094c..25a17df823856 100644 --- a/dev/tests/api-functional/testsuite/Magento/Quote/Api/CartTotalRepositoryTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Quote/Api/CartTotalRepositoryTest.php @@ -12,6 +12,8 @@ use Magento\Framework\Api\SearchCriteriaBuilder; use Magento\TestFramework\ObjectManager; use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Quote\Model\Quote; +use Magento\Quote\Model\Quote\Address; class CartTotalRepositoryTest extends WebapiAbstract { @@ -54,36 +56,10 @@ public function testGetTotals() /** @var \Magento\Quote\Model\Quote\Address $shippingAddress */ $shippingAddress = $quote->getShippingAddress(); - $data = [ - Totals::KEY_GRAND_TOTAL => $quote->getGrandTotal(), - Totals::KEY_BASE_GRAND_TOTAL => $quote->getBaseGrandTotal(), - Totals::KEY_SUBTOTAL => $quote->getSubtotal(), - Totals::KEY_BASE_SUBTOTAL => $quote->getBaseSubtotal(), - Totals::KEY_DISCOUNT_AMOUNT => $shippingAddress->getDiscountAmount(), - Totals::KEY_BASE_DISCOUNT_AMOUNT => $shippingAddress->getBaseDiscountAmount(), - Totals::KEY_SUBTOTAL_WITH_DISCOUNT => $quote->getSubtotalWithDiscount(), - Totals::KEY_BASE_SUBTOTAL_WITH_DISCOUNT => $quote->getBaseSubtotalWithDiscount(), - Totals::KEY_SHIPPING_AMOUNT => $shippingAddress->getShippingAmount(), - Totals::KEY_BASE_SHIPPING_AMOUNT => $shippingAddress->getBaseShippingAmount(), - Totals::KEY_SHIPPING_DISCOUNT_AMOUNT => $shippingAddress->getShippingDiscountAmount(), - Totals::KEY_BASE_SHIPPING_DISCOUNT_AMOUNT => $shippingAddress->getBaseShippingDiscountAmount(), - Totals::KEY_TAX_AMOUNT => $shippingAddress->getTaxAmount(), - Totals::KEY_BASE_TAX_AMOUNT => $shippingAddress->getBaseTaxAmount(), - Totals::KEY_SHIPPING_TAX_AMOUNT => $shippingAddress->getShippingTaxAmount(), - Totals::KEY_BASE_SHIPPING_TAX_AMOUNT => $shippingAddress->getBaseShippingTaxAmount(), - Totals::KEY_SUBTOTAL_INCL_TAX => $shippingAddress->getSubtotalInclTax(), - Totals::KEY_BASE_SUBTOTAL_INCL_TAX => $shippingAddress->getBaseSubtotalTotalInclTax(), - Totals::KEY_SHIPPING_INCL_TAX => $shippingAddress->getShippingInclTax(), - Totals::KEY_BASE_SHIPPING_INCL_TAX => $shippingAddress->getBaseShippingInclTax(), - Totals::KEY_BASE_CURRENCY_CODE => $quote->getBaseCurrencyCode(), - Totals::KEY_QUOTE_CURRENCY_CODE => $quote->getQuoteCurrencyCode(), - Totals::KEY_ITEMS_QTY => $quote->getItemsQty(), - Totals::KEY_ITEMS => [$this->getQuoteItemTotalsData($quote)], - ]; + $data = $this->getData($quote, $shippingAddress); $requestData = ['cartId' => $cartId]; - $data = $this->formatTotalsData($data); $actual = $this->_webApiCall($this->getServiceInfoForTotalsService($cartId), $requestData); unset($actual['items'][0]['options']); unset($actual['weee_tax_applied_amount']); @@ -213,7 +189,31 @@ public function testGetMyTotals() /** @var \Magento\Quote\Model\Quote\Address $shippingAddress */ $shippingAddress = $quote->getShippingAddress(); - $data = [ + $data = $this->getData($quote, $shippingAddress); + + $actual = $this->_webApiCall($serviceInfo); + unset($actual['items'][0]['options']); + unset($actual['weee_tax_applied_amount']); + + /** TODO: cover total segments with separate test */ + unset($actual['total_segments']); + if (array_key_exists('extension_attributes', $actual)) { + unset($actual['extension_attributes']); + } + $this->assertEquals($data, $actual); + } + + /** + * Get expected data. + * + * @param Quote $quote + * @param Address $shippingAddress + * + * @return array + */ + private function getData(Quote $quote, Address $shippingAddress) : array + { + return [ Totals::KEY_GRAND_TOTAL => $quote->getGrandTotal(), Totals::KEY_BASE_GRAND_TOTAL => $quote->getBaseGrandTotal(), Totals::KEY_SUBTOTAL => $quote->getSubtotal(), @@ -239,17 +239,5 @@ public function testGetMyTotals() Totals::KEY_ITEMS_QTY => $quote->getItemsQty(), Totals::KEY_ITEMS => [$this->getQuoteItemTotalsData($quote)], ]; - - $data = $this->formatTotalsData($data); - $actual = $this->_webApiCall($serviceInfo); - unset($actual['items'][0]['options']); - unset($actual['weee_tax_applied_amount']); - - /** TODO: cover total segments with separate test */ - unset($actual['total_segments']); - if (array_key_exists('extension_attributes', $actual)) { - unset($actual['extension_attributes']); - } - $this->assertEquals($data, $actual); } } diff --git a/dev/tests/api-functional/testsuite/Magento/Quote/Api/GuestCartTotalRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Quote/Api/GuestCartTotalRepositoryTest.php index 7ad0e62f29dc3..28195cca679f8 100644 --- a/dev/tests/api-functional/testsuite/Magento/Quote/Api/GuestCartTotalRepositoryTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Quote/Api/GuestCartTotalRepositoryTest.php @@ -63,14 +63,14 @@ public function testGetTotals() $shippingAddress = $quote->getShippingAddress(); $data = [ - Totals::KEY_BASE_GRAND_TOTAL => $quote->getBaseGrandTotal(), Totals::KEY_GRAND_TOTAL => $quote->getGrandTotal(), - Totals::KEY_BASE_SUBTOTAL => $quote->getBaseSubtotal(), + Totals::KEY_BASE_GRAND_TOTAL => $quote->getBaseGrandTotal(), Totals::KEY_SUBTOTAL => $quote->getSubtotal(), - Totals::KEY_BASE_SUBTOTAL_WITH_DISCOUNT => $quote->getBaseSubtotalWithDiscount(), - Totals::KEY_SUBTOTAL_WITH_DISCOUNT => $quote->getSubtotalWithDiscount(), + Totals::KEY_BASE_SUBTOTAL => $quote->getBaseSubtotal(), Totals::KEY_DISCOUNT_AMOUNT => $shippingAddress->getDiscountAmount(), Totals::KEY_BASE_DISCOUNT_AMOUNT => $shippingAddress->getBaseDiscountAmount(), + Totals::KEY_SUBTOTAL_WITH_DISCOUNT => $quote->getSubtotalWithDiscount(), + Totals::KEY_BASE_SUBTOTAL_WITH_DISCOUNT => $quote->getBaseSubtotalWithDiscount(), Totals::KEY_SHIPPING_AMOUNT => $shippingAddress->getShippingAmount(), Totals::KEY_BASE_SHIPPING_AMOUNT => $shippingAddress->getBaseShippingAmount(), Totals::KEY_SHIPPING_DISCOUNT_AMOUNT => $shippingAddress->getShippingDiscountAmount(), @@ -94,6 +94,7 @@ public function testGetTotals() $data = $this->formatTotalsData($data); $actual = $this->_webApiCall($this->getServiceInfoForTotalsService($cartId), $requestData); + $actual = $this->formatTotalsData($actual); unset($actual['items'][0]['options']); unset($actual['weee_tax_applied_amount']); diff --git a/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_shipping_method.php b/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_shipping_method.php index 3c54fe16db7d3..61779da29c65f 100644 --- a/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_shipping_method.php +++ b/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_shipping_method.php @@ -11,10 +11,18 @@ require 'quote_with_address_saved.php'; +$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); +$rate = $objectManager->get(\Magento\Quote\Model\Quote\Address\Rate::class); + $quote->load('test_order_1', 'reserved_order_id'); $shippingAddress = $quote->getShippingAddress(); $shippingAddress->setShippingMethod('flatrate_flatrate') ->setShippingDescription('Flat Rate - Fixed') - ->setShippingAmount(10.0) - ->setBaseShippingAmount(12.0) ->save(); + +$rate->setPrice(0) + ->setAddressId($shippingAddress->getId()) + ->save(); +$shippingAddress->setBaseShippingAmount($rate->getPrice()); +$shippingAddress->setShippingAmount($rate->getPrice()); +$rate->delete(); From 2bb407e3334e88267904842c5496524e177f8290 Mon Sep 17 00:00:00 2001 From: Yuliya Labudova Date: Wed, 9 Jan 2019 17:19:07 +0300 Subject: [PATCH 10/41] MC-4316: Tax calculation process does not follow "Apply Tax On" setting - Apply the setting for tax calculation. --- .../AbstractAggregateCalculator.php | 31 ++++++- .../Sales/Total/Quote/CommonTaxCollector.php | 83 ++++++++++++++++--- .../RowBaseAndTotalBaseCalculatorTestCase.php | 15 +++- .../Magento/Tax/etc/extension_attributes.xml | 3 + 4 files changed, 117 insertions(+), 15 deletions(-) diff --git a/app/code/Magento/Tax/Model/Calculation/AbstractAggregateCalculator.php b/app/code/Magento/Tax/Model/Calculation/AbstractAggregateCalculator.php index bad64260cf58a..9000b61a8e8bf 100644 --- a/app/code/Magento/Tax/Model/Calculation/AbstractAggregateCalculator.php +++ b/app/code/Magento/Tax/Model/Calculation/AbstractAggregateCalculator.php @@ -7,6 +7,9 @@ use Magento\Tax\Api\Data\QuoteDetailsItemInterface; +/** + * Abstract aggregate calculator. + */ abstract class AbstractAggregateCalculator extends AbstractCalculator { /** @@ -106,11 +109,12 @@ protected function calculateWithTaxNotInPrice(QuoteDetailsItemInterface $item, $ $rowTaxes = []; $rowTaxesBeforeDiscount = []; $appliedTaxes = []; + $rowTotalForTaxCalculation = $this->getPriceForTaxCalculation($item, $price) * $quantity; //Apply each tax rate separately foreach ($appliedRates as $appliedRate) { $taxId = $appliedRate['id']; $taxRate = $appliedRate['percent']; - $rowTaxPerRate = $this->calculationTool->calcTaxAmount($rowTotal, $taxRate, false, false); + $rowTaxPerRate = $this->calculationTool->calcTaxAmount($rowTotalForTaxCalculation, $taxRate, false, false); $deltaRoundingType = self::KEY_REGULAR_DELTA_ROUNDING; if ($applyTaxAfterDiscount) { $deltaRoundingType = self::KEY_TAX_BEFORE_DISCOUNT_DELTA_ROUNDING; @@ -121,7 +125,10 @@ protected function calculateWithTaxNotInPrice(QuoteDetailsItemInterface $item, $ //Handle discount if ($applyTaxAfterDiscount) { //TODO: handle originalDiscountAmount - $taxableAmount = max($rowTotal - $discountAmount, 0); + $taxableAmount = max($rowTotalForTaxCalculation - $discountAmount, 0); + if ($taxableAmount) { + $taxableAmount = $rowTotalForTaxCalculation; + } $rowTaxAfterDiscount = $this->calculationTool->calcTaxAmount( $taxableAmount, $taxRate, @@ -168,6 +175,26 @@ protected function calculateWithTaxNotInPrice(QuoteDetailsItemInterface $item, $ ->setAppliedTaxes($appliedTaxes); } + /** + * Get price for tax calculation. + * + * @param QuoteDetailsItemInterface $item + * @param float $price + * @return float + */ + private function getPriceForTaxCalculation(QuoteDetailsItemInterface $item, float $price) + { + if ($item->getExtensionAttributes() && $item->getExtensionAttributes()->getPriceForTaxCalculation()) { + $priceForTaxCalculation = $this->calculationTool->round( + $item->getExtensionAttributes()->getPriceForTaxCalculation() + ); + } else { + $priceForTaxCalculation = $price; + } + + return $priceForTaxCalculation; + } + /** * Round amount * diff --git a/app/code/Magento/Tax/Model/Sales/Total/Quote/CommonTaxCollector.php b/app/code/Magento/Tax/Model/Sales/Total/Quote/CommonTaxCollector.php index 0901e1b7bc78c..bff489ee50c2f 100644 --- a/app/code/Magento/Tax/Model/Sales/Total/Quote/CommonTaxCollector.php +++ b/app/code/Magento/Tax/Model/Sales/Total/Quote/CommonTaxCollector.php @@ -15,12 +15,17 @@ use Magento\Quote\Model\Quote\Item\AbstractItem; use Magento\Store\Model\Store; use Magento\Tax\Api\Data\QuoteDetailsInterfaceFactory; +use Magento\Tax\Api\Data\QuoteDetailsItemInterface; use Magento\Tax\Api\Data\TaxClassKeyInterfaceFactory; use Magento\Tax\Api\Data\TaxClassKeyInterface; use Magento\Tax\Api\Data\TaxDetailsInterface; use Magento\Tax\Api\Data\TaxDetailsItemInterface; use Magento\Tax\Api\Data\QuoteDetailsInterface; use Magento\Quote\Api\Data\ShippingAssignmentInterface; +use Magento\Tax\Helper\Data as TaxHelper; +use Magento\Framework\App\ObjectManager; +use Magento\Tax\Api\Data\QuoteDetailsItemExtensionInterface; +use Magento\Tax\Api\Data\QuoteDetailsItemExtensionInterfaceFactory; /** * Tax totals calculation model @@ -129,6 +134,16 @@ class CommonTaxCollector extends AbstractTotal */ protected $quoteDetailsItemDataObjectFactory; + /** + * @var TaxHelper + */ + private $taxHelper; + + /** + * @var QuoteDetailsItemExtensionInterfaceFactory + */ + private $quoteDetailsItemExtensionFactory; + /** * Class constructor * @@ -139,6 +154,8 @@ class CommonTaxCollector extends AbstractTotal * @param \Magento\Tax\Api\Data\TaxClassKeyInterfaceFactory $taxClassKeyDataObjectFactory * @param CustomerAddressFactory $customerAddressFactory * @param CustomerAddressRegionFactory $customerAddressRegionFactory + * @param TaxHelper|null $taxHelper + * @param QuoteDetailsItemExtensionInterfaceFactory|null $quoteDetailsItemExtensionInterfaceFactory */ public function __construct( \Magento\Tax\Model\Config $taxConfig, @@ -147,7 +164,9 @@ public function __construct( \Magento\Tax\Api\Data\QuoteDetailsItemInterfaceFactory $quoteDetailsItemDataObjectFactory, \Magento\Tax\Api\Data\TaxClassKeyInterfaceFactory $taxClassKeyDataObjectFactory, CustomerAddressFactory $customerAddressFactory, - CustomerAddressRegionFactory $customerAddressRegionFactory + CustomerAddressRegionFactory $customerAddressRegionFactory, + TaxHelper $taxHelper = null, + QuoteDetailsItemExtensionInterfaceFactory $quoteDetailsItemExtensionInterfaceFactory = null ) { $this->taxCalculationService = $taxCalculationService; $this->quoteDetailsDataObjectFactory = $quoteDetailsDataObjectFactory; @@ -156,6 +175,9 @@ public function __construct( $this->quoteDetailsItemDataObjectFactory = $quoteDetailsItemDataObjectFactory; $this->customerAddressFactory = $customerAddressFactory; $this->customerAddressRegionFactory = $customerAddressRegionFactory; + $this->taxHelper = $taxHelper ?: ObjectManager::getInstance()->get(TaxHelper::class); + $this->quoteDetailsItemExtensionFactory = $quoteDetailsItemExtensionInterfaceFactory ?: + ObjectManager::getInstance()->get(QuoteDetailsItemExtensionInterfaceFactory::class); } /** @@ -186,7 +208,7 @@ public function mapAddress(QuoteAddress $address) * @param bool $priceIncludesTax * @param bool $useBaseCurrency * @param string $parentCode - * @return \Magento\Tax\Api\Data\QuoteDetailsItemInterface + * @return QuoteDetailsItemInterface */ public function mapItem( \Magento\Tax\Api\Data\QuoteDetailsItemInterfaceFactory $itemDataObjectFactory, @@ -199,7 +221,7 @@ public function mapItem( $sequence = 'sequence-' . $this->getNextIncrement(); $item->setTaxCalculationItemId($sequence); } - /** @var \Magento\Tax\Api\Data\QuoteDetailsItemInterface $itemDataObject */ + /** @var QuoteDetailsItemInterface $itemDataObject */ $itemDataObject = $itemDataObjectFactory->create(); $itemDataObject->setCode($item->getTaxCalculationItemId()) ->setQuantity($item->getQty()) @@ -215,12 +237,28 @@ public function mapItem( if (!$item->getBaseTaxCalculationPrice()) { $item->setBaseTaxCalculationPrice($item->getBaseCalculationPriceOriginal()); } + + if ($this->taxHelper->applyTaxOnOriginalPrice()) { + $baseTaxCalculationPrice = $item->getBaseOriginalPrice(); + } else { + $baseTaxCalculationPrice = $item->getBaseCalculationPriceOriginal(); + } + $this->setPriceForTaxCalculation($itemDataObject, (float)$baseTaxCalculationPrice); + $itemDataObject->setUnitPrice($item->getBaseTaxCalculationPrice()) ->setDiscountAmount($item->getBaseDiscountAmount()); } else { if (!$item->getTaxCalculationPrice()) { $item->setTaxCalculationPrice($item->getCalculationPriceOriginal()); } + + if ($this->taxHelper->applyTaxOnOriginalPrice()) { + $taxCalculationPrice = $item->getOriginalPrice(); + } else { + $taxCalculationPrice = $item->getCalculationPriceOriginal(); + } + $this->setPriceForTaxCalculation($itemDataObject, (float)$taxCalculationPrice); + $itemDataObject->setUnitPrice($item->getTaxCalculationPrice()) ->setDiscountAmount($item->getDiscountAmount()); } @@ -230,6 +268,23 @@ public function mapItem( return $itemDataObject; } + /** + * Set price for tax calculation. + * + * @param QuoteDetailsItemInterface $quoteDetailsItem + * @param float $taxCalculationPrice + * @return void + */ + private function setPriceForTaxCalculation(QuoteDetailsItemInterface $quoteDetailsItem, float $taxCalculationPrice) + { + $extensionAttributes = $quoteDetailsItem->getExtensionAttributes(); + if (!$extensionAttributes) { + $extensionAttributes = $this->quoteDetailsItemExtensionFactory->create(); + } + $extensionAttributes->setPriceForTaxCalculation($taxCalculationPrice); + $quoteDetailsItem->setExtensionAttributes($extensionAttributes); + } + /** * Map item extra taxables * @@ -237,7 +292,7 @@ public function mapItem( * @param AbstractItem $item * @param bool $priceIncludesTax * @param bool $useBaseCurrency - * @return \Magento\Tax\Api\Data\QuoteDetailsItemInterface[] + * @return QuoteDetailsItemInterface[] */ public function mapItemExtraTaxables( \Magento\Tax\Api\Data\QuoteDetailsItemInterfaceFactory $itemDataObjectFactory, @@ -260,7 +315,7 @@ public function mapItemExtraTaxables( } else { $unitPrice = $extraTaxable[self::KEY_ASSOCIATED_TAXABLE_UNIT_PRICE]; } - /** @var \Magento\Tax\Api\Data\QuoteDetailsItemInterface $itemDataObject */ + /** @var QuoteDetailsItemInterface $itemDataObject */ $itemDataObject = $itemDataObjectFactory->create(); $itemDataObject->setCode($extraTaxable[self::KEY_ASSOCIATED_TAXABLE_CODE]) ->setType($extraTaxable[self::KEY_ASSOCIATED_TAXABLE_TYPE]) @@ -283,9 +338,9 @@ public function mapItemExtraTaxables( * Add quote items * * @param ShippingAssignmentInterface $shippingAssignment - * @param bool $useBaseCurrency * @param bool $priceIncludesTax - * @return \Magento\Tax\Api\Data\QuoteDetailsItemInterface[] + * @param bool $useBaseCurrency + * @return QuoteDetailsItemInterface[] */ public function mapItems( ShippingAssignmentInterface $shippingAssignment, @@ -361,10 +416,12 @@ public function populateAddressData(QuoteDetailsInterface $quoteDetails, QuoteAd } /** + * Get shipping data object. + * * @param ShippingAssignmentInterface $shippingAssignment * @param QuoteAddress\Total $total * @param bool $useBaseCurrency - * @return \Magento\Tax\Api\Data\QuoteDetailsItemInterface + * @return QuoteDetailsItemInterface */ public function getShippingDataObject( ShippingAssignmentInterface $shippingAssignment, @@ -379,7 +436,7 @@ public function getShippingDataObject( $total->setBaseShippingTaxCalculationAmount($total->getBaseShippingAmount()); } if ($total->getShippingTaxCalculationAmount() !== null) { - /** @var \Magento\Tax\Api\Data\QuoteDetailsItemInterface $itemDataObject */ + /** @var QuoteDetailsItemInterface $itemDataObject */ $itemDataObject = $this->quoteDetailsItemDataObjectFactory->create() ->setType(self::ITEM_TYPE_SHIPPING) ->setCode(self::ITEM_CODE_SHIPPING) @@ -414,7 +471,7 @@ public function getShippingDataObject( * Populate QuoteDetails object from quote address object * * @param ShippingAssignmentInterface $shippingAssignment - * @param \Magento\Tax\Api\Data\QuoteDetailsItemInterface[] $itemDataObjects + * @param QuoteDetailsItemInterface[] $itemDataObjects * @return \Magento\Tax\Api\Data\QuoteDetailsInterface */ protected function prepareQuoteDetails(ShippingAssignmentInterface $shippingAssignment, $itemDataObjects) @@ -543,6 +600,7 @@ protected function processProductItems( * Process applied taxes for items and quote * * @param QuoteAddress\Total $total + * @param ShippingAssignmentInterface $shippingAssignment * @param array $itemsByType * @return $this */ @@ -846,8 +904,9 @@ protected function saveAppliedTaxes() } /** - * Increment and return counter. This function is intended to be used to generate temporary - * id for an item. + * Increment and return counter. + * + * This function is intended to be used to generate temporary id for an item. * * @return int */ diff --git a/app/code/Magento/Tax/Test/Unit/Model/Calculation/RowBaseAndTotalBaseCalculatorTestCase.php b/app/code/Magento/Tax/Test/Unit/Model/Calculation/RowBaseAndTotalBaseCalculatorTestCase.php index cbd7ed46e38d7..2a7eeb27ee07e 100644 --- a/app/code/Magento/Tax/Test/Unit/Model/Calculation/RowBaseAndTotalBaseCalculatorTestCase.php +++ b/app/code/Magento/Tax/Test/Unit/Model/Calculation/RowBaseAndTotalBaseCalculatorTestCase.php @@ -9,6 +9,7 @@ use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; use Magento\Tax\Model\Calculation\RowBaseCalculator; use Magento\Tax\Model\Calculation\TotalBaseCalculator; +use Magento\Tax\Api\Data\QuoteDetailsItemExtensionInterface; /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) @@ -66,6 +67,11 @@ class RowBaseAndTotalBaseCalculatorTestCase extends \PHPUnit\Framework\TestCase */ protected $taxDetailsItem; + /** + * @var \Magento\Tax\Api\Data\QuoteDetailsItemExtensionInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $quoteDetailsItemExtension; + /** * initialize all mocks * @@ -101,7 +107,14 @@ protected function setUp() ->disableOriginalConstructor() ->getMock(); - $this->mockItem = $this->getMockBuilder(\Magento\Tax\Api\Data\QuoteDetailsItemInterface::class)->getMock(); + $this->mockItem = $this->getMockBuilder(\Magento\Tax\Api\Data\QuoteDetailsItemInterface::class) + ->disableOriginalConstructor()->setMethods(['getExtensionAttributes', 'getUnitPrice']) + ->getMockForAbstractClass(); + $this->quoteDetailsItemExtension = $this->getMockBuilder(QuoteDetailsItemExtensionInterface::class) + ->disableOriginalConstructor()->setMethods(['getPriceForTaxCalculation']) + ->getMockForAbstractClass(); + $this->mockItem->expects($this->any())->method('getExtensionAttributes') + ->willReturn($this->quoteDetailsItemExtension); $this->appliedTaxDataObjectFactory = $this->createPartialMock( \Magento\Tax\Api\Data\AppliedTaxInterfaceFactory::class, diff --git a/app/code/Magento/Tax/etc/extension_attributes.xml b/app/code/Magento/Tax/etc/extension_attributes.xml index 90a5e6d2ecee3..41af1df836d6f 100644 --- a/app/code/Magento/Tax/etc/extension_attributes.xml +++ b/app/code/Magento/Tax/etc/extension_attributes.xml @@ -20,4 +20,7 @@ + + + From 2fb6b3b81ada22e1a172272a7eb5454a50a71a2d Mon Sep 17 00:00:00 2001 From: Alexey Yakimovich Date: Thu, 10 Jan 2019 13:07:53 +0300 Subject: [PATCH 11/41] MAGETWO-96545: Wrong calculation of invoiced items in shipment document in order with bundle product after partial invoice - Partial invoice feature has been removed for bundled products when it should be shipped together; --- .../sales/invoice/create/items/renderer.phtml | 19 ++++- .../Sales/Model/Service/InvoiceService.php | 85 +++++++++++++++---- 2 files changed, 84 insertions(+), 20 deletions(-) diff --git a/app/code/Magento/Bundle/view/adminhtml/templates/sales/invoice/create/items/renderer.phtml b/app/code/Magento/Bundle/view/adminhtml/templates/sales/invoice/create/items/renderer.phtml index ff26d67bd8378..ae1e9f3483192 100644 --- a/app/code/Magento/Bundle/view/adminhtml/templates/sales/invoice/create/items/renderer.phtml +++ b/app/code/Magento/Bundle/view/adminhtml/templates/sales/invoice/create/items/renderer.phtml @@ -28,8 +28,21 @@ + getOrderItem(); + if ($orderItem->getProductType() == \Magento\Catalog\Model\Product\Type::TYPE_BUNDLE) { + $shipTogether = !$orderItem->isShipSeparately(); + } else { + $shipTogether = !$orderItem->getParentItem()->isShipSeparately(); + } + ?> setPriceDataObject($_item) ?> getOrderItem()->getParentItem()): ?> + getSelectionAttributes($_item) ?> @@ -60,14 +73,14 @@ - canShowPriceInfo($_item)): ?> + canShowPriceInfo($_item) || $shipTogether): ?> getColumnHtml($_item, 'price') ?>   - canShowPriceInfo($_item)): ?> + canShowPriceInfo($_item) || $shipTogether): ?> @@ -116,7 +129,7 @@
- canShowPriceInfo($_item)): ?> + canShowPriceInfo($_item) || $shipTogether): ?> canEditQty()) : ?> repository = $repository; $this->commentRepository = $commentRepository; @@ -85,6 +99,7 @@ public function __construct( $this->invoiceNotifier = $notifier; $this->orderRepository = $orderRepository; $this->orderConverter = $orderConverter; + $this->serializer = $serializer ?: ObjectManager::getInstance()->get(Json::class); } /** @@ -142,10 +157,10 @@ public function prepareInvoice(Order $order, array $qtys = []) continue; } $item = $this->orderConverter->itemToInvoiceItem($orderItem); - if ($orderItem->isDummy()) { - $qty = $orderItem->getQtyOrdered() ? $orderItem->getQtyOrdered() : 1; - } elseif (isset($qtys[$orderItem->getId()])) { + if (isset($qtys[$orderItem->getId()])) { $qty = (double) $qtys[$orderItem->getId()]; + } elseif ($orderItem->isDummy()) { + $qty = $orderItem->getQtyOrdered() ? $orderItem->getQtyOrdered() : 1; } elseif (empty($qtys)) { $qty = $orderItem->getQtyToInvoice(); } else { @@ -172,25 +187,61 @@ private function prepareItemsQty(Order $order, array $qtys = []) { foreach ($order->getAllItems() as $orderItem) { if (empty($qtys[$orderItem->getId()])) { - continue; + if ($orderItem->getProductType() == Type::TYPE_BUNDLE && !$orderItem->isShipSeparately()) { + $qtys[$orderItem->getId()] = $orderItem->getQtyOrdered() - $orderItem->getQtyInvoiced(); + } else { + continue; + } } - if ($orderItem->isDummy()) { - if ($orderItem->getHasChildren()) { - foreach ($orderItem->getChildrenItems() as $child) { - if (!isset($qtys[$child->getId()])) { - $qtys[$child->getId()] = $child->getQtyToInvoice(); - } - } - } elseif ($orderItem->getParentItem()) { - $parent = $orderItem->getParentItem(); - if (!isset($qtys[$parent->getId()])) { - $qtys[$parent->getId()] = $parent->getQtyToInvoice(); + + $this->prepareItemQty($orderItem, $qtys); + } + + return $qtys; + } + + /** + * Prepare qty_invoiced for order item + * + * @param \Magento\Sales\Api\Data\OrderItemInterface $orderItem + * @param array $qtys + */ + private function prepareItemQty(\Magento\Sales\Api\Data\OrderItemInterface $orderItem, &$qtys) + { + $this->prepareBundleQty($orderItem, $qtys); + + if ($orderItem->isDummy()) { + if ($orderItem->getHasChildren()) { + foreach ($orderItem->getChildrenItems() as $child) { + if (!isset($qtys[$child->getId()])) { + $qtys[$child->getId()] = $child->getQtyToInvoice(); } } + } elseif ($orderItem->getParentItem()) { + $parent = $orderItem->getParentItem(); + if (!isset($qtys[$parent->getId()])) { + $qtys[$parent->getId()] = $parent->getQtyToInvoice(); + } } } + } - return $qtys; + /** + * Prepare qty to invoice for bundle products + * + * @param \Magento\Sales\Api\Data\OrderItemInterface $orderItem + * @param array $qtys + */ + private function prepareBundleQty(\Magento\Sales\Api\Data\OrderItemInterface $orderItem, &$qtys) + { + if ($orderItem->getProductType() == Type::TYPE_BUNDLE && !$orderItem->isShipSeparately()) { + foreach ($orderItem->getChildrenItems() as $childItem) { + $bundleSelectionAttributes = $this->serializer->unserialize( + $childItem->getProductOptionByCode('bundle_selection_attributes') + ); + $qtys[$childItem->getId()] = $qtys[$orderItem->getId()] * $bundleSelectionAttributes['qty']; + } + } } /** From 792509245b10fbeae758efbabe69bc6784d401c4 Mon Sep 17 00:00:00 2001 From: Lusine Papyan Date: Wed, 19 Dec 2018 09:01:00 +0400 Subject: [PATCH 12/41] MAGETWO-96421: [2.3.x] Header Minicart ,Shopping cart page and Checkout page show incorrect product name - Add automated test script --- .../Section/CheckoutCartProductSection.xml | 1 + .../CheckoutShippingGuestInfoSection.xml | 4 + .../Section/StorefrontMiniCartSection.xml | 1 + ...tOnCheckoutPageDifferentStoreViewsTest.xml | 89 +++++++++++++++++++ 4 files changed, 95 insertions(+) create mode 100644 app/code/Magento/Checkout/Test/Mftf/Test/StorefrontProductNameMinicartOnCheckoutPageDifferentStoreViewsTest.xml diff --git a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutCartProductSection.xml b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutCartProductSection.xml index ab82d9fdd93b5..5306b301d95d7 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutCartProductSection.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutCartProductSection.xml @@ -26,6 +26,7 @@ parameterized="true"/> + diff --git a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutShippingGuestInfoSection.xml b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutShippingGuestInfoSection.xml index ad2a43eb90c8c..6838824400b96 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutShippingGuestInfoSection.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutShippingGuestInfoSection.xml @@ -19,5 +19,9 @@ + + + + diff --git a/app/code/Magento/Checkout/Test/Mftf/Section/StorefrontMiniCartSection.xml b/app/code/Magento/Checkout/Test/Mftf/Section/StorefrontMiniCartSection.xml index 3f717943fe8f0..f76101de17aec 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Section/StorefrontMiniCartSection.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Section/StorefrontMiniCartSection.xml @@ -13,6 +13,7 @@ + diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontProductNameMinicartOnCheckoutPageDifferentStoreViewsTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontProductNameMinicartOnCheckoutPageDifferentStoreViewsTest.xml new file mode 100644 index 0000000000000..3401369a8c749 --- /dev/null +++ b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontProductNameMinicartOnCheckoutPageDifferentStoreViewsTest.xml @@ -0,0 +1,89 @@ + + + + + + + + + <description value="Checking Product name in Minicart and on Checkout page with different store views"/> + <severity value="MAJOR"/> + <testCaseId value="MAGETWO-96466"/> + <useCaseId value="MAGETWO-96421"/> + <group value="checkout"/> + </annotations> + <before> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + + <!--Create a product--> + <createData entity="SimpleProduct2" stepKey="createProduct"/> + </before> + <after> + <!--Delete created data--> + <deleteData createDataKey="createProduct" stepKey="deleteProduct"/> + <actionGroup ref="AdminDeleteStoreViewActionGroup" stepKey="deleteStoreView"> + <argument name="customStore" value="customStore"/> + </actionGroup> + + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!-- Create store view --> + <actionGroup ref="AdminCreateStoreViewActionGroup" stepKey="createStoreView"> + <argument name="customStore" value="customStore"/> + </actionGroup> + + <!--Go to created product page--> + <amOnPage url="{{AdminProductEditPage.url($$createProduct.id$$)}}" stepKey="goToEditPage"/> + <waitForPageLoad stepKey="waitForProductPage"/> + + <!--Switch to second store view and change the product name--> + <actionGroup ref="SwitchToTheNewStoreView" stepKey="switchToCustomStoreView"> + <argument name="storeViewName" value="{{customStore.name}}"/> + </actionGroup> + <waitForPageLoad stepKey="waitForPageLoad"/> + <click selector="{{AdminProductFormSection.productNameUseDefault}}" stepKey="uncheckUseDefault"/> + <fillField selector="{{AdminProductFormSection.productName}}" userInput="$$createProduct.name$$-new" stepKey="fillProductName"/> + <click selector="{{AdminProductFormActionSection.saveButton}}" stepKey="saveProduct"/> + + <!--Add product to cart--> + <amOnPage url="{{StorefrontProductPage.url($$createProduct.name$$)}}" stepKey="amOnSimpleProductPage"/> + <waitForPageLoad stepKey="waitForProductPageLoad"/> + <actionGroup ref="addToCartFromStorefrontProductPage" stepKey="addToCartFromStorefrontProductPage"> + <argument name="productName" value="$createProduct.name$$"/> + </actionGroup> + + <!--Switch to second store view--> + <actionGroup ref="StorefrontSwitchStoreViewActionGroup" stepKey="switchStoreView"> + <argument name="storeView" value="customStore"/> + </actionGroup> + <waitForPageLoad stepKey="waitForStoreView"/> + + <!--Check product name in Minicart--> + <click selector="{{StorefrontMinicartSection.showCart}}" stepKey="clickCart"/> + <grabTextFrom selector="{{StorefrontMinicartSection.productName}}" stepKey="grabProductNameMinicart"/> + <assertContains expected="$$createProduct.name$$" actual="$grabProductNameMinicart" stepKey="assertProductNameMinicart"/> + <assertContains expectedType="string" expected="-new" actual="$grabProductNameMinicart" stepKey="assertProductNameMinicart1"/> + + <!--Check product name in Shopping Cart page--> + <click selector="{{StorefrontMinicartSection.viewAndEditCart}}" stepKey="clickViewAndEdit"/> + <waitForPageLoad stepKey="waitForShoppingCartPageLoad"/> + <grabTextFrom selector="{{CheckoutCartProductSection.productName}}" stepKey="grabProductNameCart"/> + <assertContains expected="$$createProduct.name$$" actual="$grabProductNameCart" stepKey="assertProductNameCart"/> + <assertContains expectedType="string" expected="-new" actual="$grabProductNameCart" stepKey="assertProductNameCart1"/> + + <!--Proceed to checkout and check product name in Order Summary area--> + <click selector="{{CheckoutCartSummarySection.proceedToCheckout}}" stepKey="proceedToCheckout"/> + <waitForPageLoad stepKey="waitForShippingPageLoad"/> + <click selector="{{CheckoutShippingGuestInfoSection.itemInCart}}" stepKey="clickItemInCart"/> + <grabTextFrom selector="{{CheckoutShippingGuestInfoSection.productName}}" stepKey="grabProductNameShipping"/> + <assertContains expected="$$createProduct.name$$" actual="$grabProductNameShipping" stepKey="assertProductNameShipping"/> + <assertContains expectedType="string" expected="-new" actual="$grabProductNameShipping" stepKey="assertProductNameShipping1"/> + </test> +</tests> From 87b5a5e8d54768de9498e452d5e84d1d14b6785b Mon Sep 17 00:00:00 2001 From: Lusine Papyan <Lusine_Papyan@epam.com> Date: Tue, 15 Jan 2019 11:35:57 +0400 Subject: [PATCH 13/41] MAGETWO-95812: Required RMA Attributes are not validated while Customer submits a return - Update automated test script --- .../StorefrontOrderActionGroupActionGroup.xml | 27 +++++++++++++++++++ .../Page/StorefrontOrderInformationPage.xml | 14 ++++++++++ .../Page/StorefrontOrdersAndReturnsPage.xml | 14 ++++++++++ ...efrontOrderAndReturnInformationSection.xml | 20 ++++++++++++++ .../StorefrontOrderInformationMainSection.xml | 15 +++++++++++ 5 files changed, 90 insertions(+) create mode 100644 app/code/Magento/Sales/Test/Mftf/ActionGroup/StorefrontOrderActionGroupActionGroup.xml create mode 100644 app/code/Magento/Sales/Test/Mftf/Page/StorefrontOrderInformationPage.xml create mode 100644 app/code/Magento/Sales/Test/Mftf/Page/StorefrontOrdersAndReturnsPage.xml create mode 100644 app/code/Magento/Sales/Test/Mftf/Section/StorefrontOrderAndReturnInformationSection.xml create mode 100644 app/code/Magento/Sales/Test/Mftf/Section/StorefrontOrderInformationMainSection.xml diff --git a/app/code/Magento/Sales/Test/Mftf/ActionGroup/StorefrontOrderActionGroupActionGroup.xml b/app/code/Magento/Sales/Test/Mftf/ActionGroup/StorefrontOrderActionGroupActionGroup.xml new file mode 100644 index 0000000000000..fcea25f997591 --- /dev/null +++ b/app/code/Magento/Sales/Test/Mftf/ActionGroup/StorefrontOrderActionGroupActionGroup.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <!--Fill order information fields and click continue--> + <actionGroup name="StorefrontSearchGuestOrderActionGroup"> + <arguments> + <argument name="orderId" type="string"/> + <argument name="orderLastName" type="string"/> + <argument name="orderEmail" type="string"/> + </arguments> + <amOnPage url="{{StorefrontOrdersAndReturnsPage.url}}" stepKey="navigateToOrderAndReturnPage"/> + <waitForPageLoad stepKey="waitForPageLoad"/> + <fillField selector="{{StorefrontOrderAndReturnInformationSection.orderId}}" userInput="{{orderId}}" stepKey="fillOrderId"/> + <fillField selector="{{StorefrontOrderAndReturnInformationSection.bilingLastName}}" userInput="{{orderLastName}}" stepKey="fillBillingLastName"/> + <fillField selector="{{StorefrontOrderAndReturnInformationSection.email}}" userInput="{{orderEmail}}" stepKey="fillEmail"/> + <click selector="{{StorefrontOrderAndReturnInformationSection.continueButton}}" stepKey="clickContinue"/> + <waitForPageLoad stepKey="waitForOrderInformationPageLoad"/> + <seeInCurrentUrl url="{{StorefrontOrderInformationPage.url}}" stepKey="seeOrderInformationUrl"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Sales/Test/Mftf/Page/StorefrontOrderInformationPage.xml b/app/code/Magento/Sales/Test/Mftf/Page/StorefrontOrderInformationPage.xml new file mode 100644 index 0000000000000..4159f9435c866 --- /dev/null +++ b/app/code/Magento/Sales/Test/Mftf/Page/StorefrontOrderInformationPage.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd"> + <page name="StorefrontOrderInformationPage" url="sales/guest/view" area="guest" module="Magento_Sales"> + <section name="StorefrontOrderInformationMainSection"/> + </page> +</pages> diff --git a/app/code/Magento/Sales/Test/Mftf/Page/StorefrontOrdersAndReturnsPage.xml b/app/code/Magento/Sales/Test/Mftf/Page/StorefrontOrdersAndReturnsPage.xml new file mode 100644 index 0000000000000..ee546174d9680 --- /dev/null +++ b/app/code/Magento/Sales/Test/Mftf/Page/StorefrontOrdersAndReturnsPage.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd"> + <page name="StorefrontOrdersAndReturnsPage" url="sales/guest/form" area="guest" module="Magento_Sales"> + <section name="StorefrontOrderAndReturnInformationSection"/> + </page> +</pages> diff --git a/app/code/Magento/Sales/Test/Mftf/Section/StorefrontOrderAndReturnInformationSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/StorefrontOrderAndReturnInformationSection.xml new file mode 100644 index 0000000000000..aa57dd9bc17ba --- /dev/null +++ b/app/code/Magento/Sales/Test/Mftf/Section/StorefrontOrderAndReturnInformationSection.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="StorefrontOrderAndReturnInformationSection"> + <element name="orderId" type="input" selector="#oar-order-id"/> + <element name="bilingLastName" type="input" selector="#oar-billing-lastname"/> + <element name="findOrderBy" type="select" selector="#quick-search-type-id"/> + <element name="email" type="input" selector="#oar_email"/> + <element name="bilingZipCode" type="input" selector="//input[@id='oar_zip']"/> + <element name="continueButton" type="submit" selector="//button[@title='Continue']"/> + <element name="ordersAndReturnsTitle" type="span" selector="//span[@id='page-title-wrapper']"/> + </section> +</sections> diff --git a/app/code/Magento/Sales/Test/Mftf/Section/StorefrontOrderInformationMainSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/StorefrontOrderInformationMainSection.xml new file mode 100644 index 0000000000000..e42c301206152 --- /dev/null +++ b/app/code/Magento/Sales/Test/Mftf/Section/StorefrontOrderInformationMainSection.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="StorefrontOrderInformationMainSection"> + <element name="orderTitle" type="span" selector="#page-title-wrapper"/> + <element name="return" type="span" selector="//span[contains(text(), 'Return')]"/> + </section> +</sections> From 87082e69cd81480b82a3d92b3321bd47fd97604e Mon Sep 17 00:00:00 2001 From: Lusine Papyan <Lusine_Papyan@epam.com> Date: Fri, 18 Jan 2019 14:52:22 +0400 Subject: [PATCH 14/41] MAGETWO-96545: Wrong calculation of invoiced items in shipment document in order with bundle product after partial invoice - Add automated test script --- ...ectnessInvoicedItemInBundleProductTest.xml | 91 +++++++++++++++++++ .../Section/AdminShipmentItemsSection.xml | 3 +- 2 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 app/code/Magento/Sales/Test/Mftf/Test/AdminCorrectnessInvoicedItemInBundleProductTest.xml diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminCorrectnessInvoicedItemInBundleProductTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminCorrectnessInvoicedItemInBundleProductTest.xml new file mode 100644 index 0000000000000..7c83f35468ce6 --- /dev/null +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminCorrectnessInvoicedItemInBundleProductTest.xml @@ -0,0 +1,91 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="AdminCorrectnessInvoicedItemInBundleProductTest"> + <annotations> + <features value="Sales"/> + <title value="Check correctness of invoiced items in a Bundle Product"/> + <description value="Check correctness of invoiced items in a Bundle Product"/> + <severity value="CRITICAL"/> + <testCaseId value="MC-11059"/> + <useCaseId value="MC-10969"/> + <group value="sales"/> + </annotations> + <before> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + + <!--Create category and simple product--> + <createData entity="SimpleSubCategory" stepKey="createCategory"/> + <createData entity="_defaultProduct" stepKey="createSimpleProduct"> + <requiredEntity createDataKey="createCategory"/> + </createData> + + <!--Create bundle product--> + <createData entity="ApiBundleProductPriceViewRange" stepKey="createBundleProduct"> + <requiredEntity createDataKey="createCategory"/> + </createData> + <createData entity="DropDownBundleOption" stepKey="bundleOption"> + <requiredEntity createDataKey="createBundleProduct"/> + </createData> + <createData entity="ApiBundleLink" stepKey="createBundleLink1"> + <requiredEntity createDataKey="createBundleProduct"/> + <requiredEntity createDataKey="bundleOption"/> + <requiredEntity createDataKey="createSimpleProduct"/> + <field key="qty">10</field> + </createData> + </before> + <after> + <!--Delete created data--> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + <deleteData createDataKey="createSimpleProduct" stepKey="deleteSimpleProduct"/> + <deleteData createDataKey="createBundleProduct" stepKey="deleteBundleProduct"/> + + <actionGroup ref="logout" stepKey="logOut"/> + </after> + + <!--Complete Bundle product creation--> + <amOnPage url="{{AdminProductEditPage.url($$createBundleProduct.id$$)}}" stepKey="goToProductEditPage"/> + <actionGroup ref="saveProductForm" stepKey="saveProduct"/> + + <!--Go to bundle product page--> + <amOnPage url="{{StorefrontProductPage.url($$createCategory.name$$)}}" stepKey="navigateToBundleProductPage"/> + + <!--Place order bundle product with 10 options--> + <actionGroup ref="StorefrontAddCategoryBundleProductToCartActionGroup" stepKey="addBundleProductToCart"> + <argument name="product" value="$$createBundleProduct$$"/> + <argument name="quantity" value="10"/> + </actionGroup> + <actionGroup ref="GoToCheckoutFromMinicartActionGroup" stepKey="goToCheckoutFromMinicart" /> + <actionGroup ref="GuestCheckoutFillingShippingSectionActionGroup" stepKey="guestCheckoutFillingShipping"/> + <actionGroup ref="CheckoutPlaceOrderActionGroup" stepKey="placeOrder"> + <argument name="orderNumberMessage" value="CONST.successGuestCheckoutOrderNumberMessage" /> + <argument name="emailYouMessage" value="CONST.successCheckoutEmailYouMessage"/> + </actionGroup> + + <!--Go to order page submit invoice--> + <grabTextFrom selector="{{CheckoutSuccessMainSection.orderNumber}}" stepKey="grabOrderNumber"/> + <amOnPage url="{{AdminOrdersPage.url}}" stepKey="onOrdersPage"/> + <actionGroup ref="filterOrderGridById" stepKey="filterOrderGridById"> + <argument name="orderId" value="$grabOrderNumber"/> + </actionGroup> + <click selector="{{AdminOrdersGridSection.firstRow}}" stepKey="clickOrderRow"/> + <waitForPageLoad stepKey="waitForCreatedOrderPageOpened"/> + <actionGroup ref="goToInvoiceIntoOrder" stepKey="goToInvoiceIntoOrderPage"/> + <fillField selector="{{AdminInvoiceItemsSection.qtyToInvoiceColumn}}" userInput="5" stepKey="ChangeQtyToInvoice"/> + <click selector="{{AdminInvoiceItemsSection.updateQty}}" stepKey="updateQunatity"/> + <waitForPageLoad stepKey="waitPageToBeLoaded"/> + <actionGroup ref="submitInvoiceIntoOrder" stepKey="submitInvoice"/> + + <!--Verify invoiced items qty in ship tab--> + <actionGroup ref="goToShipmentIntoOrder" stepKey="goToShipment"/> + <grabTextFrom selector="{{AdminShipmentItemsSection.itemQtyInvoiced('1')}}" stepKey="grabInvoicedItemQty"/> + <assertEquals expected="5" expectedType="string" actual="$grabInvoicedItemQty" stepKey="assertInvoicedItemsQty"/> + </test> +</tests> diff --git a/app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentItemsSection.xml b/app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentItemsSection.xml index a7bf82588f7c7..0345c3f2949f4 100644 --- a/app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentItemsSection.xml +++ b/app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentItemsSection.xml @@ -15,5 +15,6 @@ <element name="itemQtyToShip" type="input" selector=".order-shipment-table tbody:nth-of-type({{var1}}) .col-qty input.qty-item" parameterized="true"/> <element name="nameColumn" type="text" selector=".order-shipment-table .col-product .product-title"/> <element name="skuColumn" type="text" selector=".order-shipment-table .col-product .product-sku-block"/> + <element name="itemQtyInvoiced" type="text" selector="(//*[@class='col-ordered-qty']//th[contains(text(), 'Invoiced')]/following-sibling::td)[{{var}}]" parameterized="true"/> </section> -</sections> \ No newline at end of file +</sections> From 2f13eb19083e6d00ad65b9992c68a39d9b7c118b Mon Sep 17 00:00:00 2001 From: Oksana_Kremen <Oksana_Kremen@epam.com> Date: Mon, 21 Jan 2019 16:43:16 +0200 Subject: [PATCH 15/41] MC-10963: Can only export default store view items when upgrade to 2.3.0 - Fixing correct loading of product collection for all store ids during export --- .../Magento/CatalogImportExport/Model/Export/Product.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/CatalogImportExport/Model/Export/Product.php b/app/code/Magento/CatalogImportExport/Model/Export/Product.php index c047e9c9bef21..eb362a69fa955 100644 --- a/app/code/Magento/CatalogImportExport/Model/Export/Product.php +++ b/app/code/Magento/CatalogImportExport/Model/Export/Product.php @@ -351,6 +351,7 @@ class Product extends \Magento\ImportExport\Model\Export\Entity\AbstractEntity /** * Product constructor. + * * @param \Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate * @param \Magento\Eav\Model\Config $config * @param \Magento\Framework\App\ResourceConnection $resource @@ -941,15 +942,17 @@ protected function getExportData() protected function loadCollection(): array { $data = []; - $collection = $this->_getEntityCollection(); foreach (array_keys($this->_storeIdToCode) as $storeId) { + $collection->setOrder('entity_id', 'asc'); + $this->_prepareEntityCollection($collection); $collection->setStoreId($storeId); + $collection->load(); foreach ($collection as $itemId => $item) { $data[$itemId][$storeId] = $item; } + $collection->clear(); } - $collection->clear(); return $data; } From 007ac8e0a8564d0367b958a4effe0d160bc24993 Mon Sep 17 00:00:00 2001 From: vprohorov <prohorov.vital@gmail.com> Date: Tue, 22 Jan 2019 15:49:22 +0300 Subject: [PATCH 16/41] MAGETWO-96852: [2.3.x] Impossible to sort Root Categories via drag'n'drop - Removed root category from tree --- .../templates/catalog/category/checkboxes/tree.phtml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/category/checkboxes/tree.phtml b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/category/checkboxes/tree.phtml index 00a1580923a7b..ee67acd0ebd46 100644 --- a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/category/checkboxes/tree.phtml +++ b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/category/checkboxes/tree.phtml @@ -20,7 +20,7 @@ "categoryCheckboxTree": { "dataUrl": "<?= $block->escapeUrl($block->getLoadTreeUrl()) ?>", "divId": "<?= /* @noEscape */ $divId ?>", - "rootVisible": <?= /* @noEscape */ $block->getRoot()->getIsVisible() ? 'true' : 'false' ?>, + "rootVisible": false, "useAjax": <?= $block->escapeHtml($block->getUseAjax()) ?>, "currentNodeId": <?= (int)$block->getCategoryId() ?>, "jsFormObject": "<?= /* @noEscape */ $block->getJsFormObject() ?>", @@ -28,7 +28,7 @@ "checked": "<?= $block->escapeHtml($block->getRoot()->getChecked()) ?>", "allowdDrop": <?= /* @noEscape */ $block->getRoot()->getIsVisible() ? 'true' : 'false' ?>, "rootId": <?= (int)$block->getRoot()->getId() ?>, - "expanded": <?= (int)$block->getIsWasExpanded() ?>, + "expanded": true, "categoryId": <?= (int)$block->getCategoryId() ?>, "treeJson": <?= /* @noEscape */ $block->getTreeJson() ?> } From 9aeb1b5bf298b151d5a989fffd0c0e07680b4891 Mon Sep 17 00:00:00 2001 From: Oksana_Kremen <Oksana_Kremen@epam.com> Date: Thu, 24 Jan 2019 17:55:39 +0200 Subject: [PATCH 17/41] MAGETWO-95186: [2.3] Incorrect table rates shipping charge at check out with cart price rule - Fixing web-api tests --- .../testsuite/Magento/Quote/Api/CartTotalRepositoryTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dev/tests/api-functional/testsuite/Magento/Quote/Api/CartTotalRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Quote/Api/CartTotalRepositoryTest.php index 93a46c07512ac..a3ded4f5f125c 100644 --- a/dev/tests/api-functional/testsuite/Magento/Quote/Api/CartTotalRepositoryTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Quote/Api/CartTotalRepositoryTest.php @@ -57,6 +57,7 @@ public function testGetTotals() $shippingAddress = $quote->getShippingAddress(); $data = $this->getData($quote, $shippingAddress); + $data = $this->formatTotalsData($data); $requestData = ['cartId' => $cartId]; @@ -190,6 +191,7 @@ public function testGetMyTotals() $shippingAddress = $quote->getShippingAddress(); $data = $this->getData($quote, $shippingAddress); + $data = $this->formatTotalsData($data); $actual = $this->_webApiCall($serviceInfo); unset($actual['items'][0]['options']); From 68e33d8216e02ca33e9c0dcfb7c2b4ce6e6ca123 Mon Sep 17 00:00:00 2001 From: Dzmitry Tabusheu <dzmitry_tabusheu@epam.com> Date: Thu, 24 Jan 2019 20:35:45 +0300 Subject: [PATCH 18/41] MAGETWO-64324: WebAPI: product has_options flag not updated when options added via API - Added product 'has_options' flag set on option save --- app/code/Magento/Catalog/Model/Product.php | 2 - .../Model/Product/Option/Repository.php | 40 ++++++++++++++----- .../Model/Product/Option/SaveHandler.php | 6 +++ .../Api/ProductCustomOptionRepositoryTest.php | 10 +++++ 4 files changed, 47 insertions(+), 11 deletions(-) diff --git a/app/code/Magento/Catalog/Model/Product.php b/app/code/Magento/Catalog/Model/Product.php index 44c5c891f4d6a..74a077835b6f7 100644 --- a/app/code/Magento/Catalog/Model/Product.php +++ b/app/code/Magento/Catalog/Model/Product.php @@ -874,8 +874,6 @@ public function beforeSave() $this->cleanCache(); $this->setTypeHasOptions(false); $this->setTypeHasRequiredOptions(false); - $this->setHasOptions(false); - $this->setRequiredOptions(false); $this->getTypeInstance()->beforeSave($this); diff --git a/app/code/Magento/Catalog/Model/Product/Option/Repository.php b/app/code/Magento/Catalog/Model/Product/Option/Repository.php index 9dc9695daffd1..b2de927254882 100644 --- a/app/code/Magento/Catalog/Model/Product/Option/Repository.php +++ b/app/code/Magento/Catalog/Model/Product/Option/Repository.php @@ -14,6 +14,8 @@ use Magento\Framework\App\ObjectManager; /** + * Product custom options repository + * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class Repository implements \Magento\Catalog\Api\ProductCustomOptionRepositoryInterface @@ -83,7 +85,7 @@ public function __construct( } /** - * {@inheritdoc} + * @inheritdoc */ public function getList($sku) { @@ -92,7 +94,7 @@ public function getList($sku) } /** - * {@inheritdoc} + * @inheritdoc */ public function getProductOptions(ProductInterface $product, $requiredOnly = false) { @@ -104,7 +106,7 @@ public function getProductOptions(ProductInterface $product, $requiredOnly = fal } /** - * {@inheritdoc} + * @inheritdoc */ public function get($sku, $optionId) { @@ -117,7 +119,7 @@ public function get($sku, $optionId) } /** - * {@inheritdoc} + * @inheritdoc */ public function delete(\Magento\Catalog\Api\Data\ProductCustomOptionInterface $entity) { @@ -126,7 +128,7 @@ public function delete(\Magento\Catalog\Api\Data\ProductCustomOptionInterface $e } /** - * {@inheritdoc} + * @inheritdoc */ public function duplicate( \Magento\Catalog\Api\Data\ProductInterface $product, @@ -142,7 +144,7 @@ public function duplicate( } /** - * {@inheritdoc} + * @inheritdoc */ public function save(\Magento\Catalog\Api\Data\ProductCustomOptionInterface $option) { @@ -180,11 +182,12 @@ public function save(\Magento\Catalog\Api\Data\ProductCustomOptionInterface $opt } } $option->save(); + $this->updateProductOptionsData($product, $option); return $option; } /** - * {@inheritdoc} + * @inheritdoc */ public function deleteByIdentifier($sku, $optionId) { @@ -209,8 +212,8 @@ public function deleteByIdentifier($sku, $optionId) /** * Mark original values for removal if they are absent among new values * - * @param $newValues array - * @param $originalValues \Magento\Catalog\Model\Product\Option\Value[] + * @param array $newValues + * @param \Magento\Catalog\Model\Product\Option\Value[] $originalValues * @return array */ protected function markRemovedValues($newValues, $originalValues) @@ -234,6 +237,8 @@ protected function markRemovedValues($newValues, $originalValues) } /** + * Get hydrator pool + * * @return \Magento\Framework\EntityManager\HydratorPool * @deprecated 101.0.0 */ @@ -245,4 +250,21 @@ private function getHydratorPool() } return $this->hydratorPool; } + + /** + * Update product 'has_options' and 'required_options' attributes + * + * @param \Magento\Catalog\Model\Product $product + * @param \Magento\Catalog\Api\Data\ProductCustomOptionInterface $option + */ + private function updateProductOptionsData($product, $option) + { + if (!$product->getHasOptions() || + ($option->getIsRequire() && !$product->getRequiredOptions())) { + $product->setCanSaveCustomOptions(true); + $product->setOptionsSaved(true); + $product->setOptions([$option]); + $product->save(); + } + } } diff --git a/app/code/Magento/Catalog/Model/Product/Option/SaveHandler.php b/app/code/Magento/Catalog/Model/Product/Option/SaveHandler.php index c4a2d60414a7b..0941aa2478935 100644 --- a/app/code/Magento/Catalog/Model/Product/Option/SaveHandler.php +++ b/app/code/Magento/Catalog/Model/Product/Option/SaveHandler.php @@ -28,6 +28,8 @@ public function __construct( } /** + * Perform action on relation/extension attribute + * * @param object $entity * @param array $arguments * @return \Magento\Catalog\Api\Data\ProductInterface|object @@ -35,6 +37,10 @@ public function __construct( */ public function execute($entity, $arguments = []) { + if ($entity->getOptionsSaved()) { + return $entity; + } + $options = $entity->getOptions(); $optionIds = []; diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductCustomOptionRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductCustomOptionRepositoryTest.php index c335b66505b0e..f3be684f93a4d 100644 --- a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductCustomOptionRepositoryTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductCustomOptionRepositoryTest.php @@ -146,6 +146,10 @@ public function testGetList() public function testSave($optionData) { $productSku = 'simple'; + /** @var \Magento\Catalog\Model\ProductRepository $productRepository */ + $productRepository = $this->objectManager->create( + \Magento\Catalog\Model\ProductRepository::class + ); $optionDataPost = $optionData; $optionDataPost['product_sku'] = $productSku; @@ -162,6 +166,7 @@ public function testSave($optionData) ]; $result = $this->_webApiCall($serviceInfo, ['option' => $optionDataPost]); + $product = $productRepository->get($productSku); unset($result['product_sku']); unset($result['option_id']); if (!empty($result['values'])) { @@ -169,7 +174,12 @@ public function testSave($optionData) unset($result['values'][$key]['option_type_id']); } } + $this->assertEquals($optionData, $result); + $this->assertTrue($product->getHasOptions() == 1); + if ($optionDataPost['is_require']) { + $this->assertTrue($product->getRequiredOptions() == 1); + } } public function optionDataProvider() From 2d9647ad547edc92ac2b7a8488f967f52148649d Mon Sep 17 00:00:00 2001 From: Yauhen_Lyskavets <yauhen_lyskavets@epam.com> Date: Mon, 28 Jan 2019 14:26:10 +0300 Subject: [PATCH 19/41] MC-10938: 2.3.0 - clearing pub/static makes me login 3 times - Disable session initialization when backend json statics generated. --- .../Translation/Model/Json/PreProcessor.php | 10 +++- .../Test/Unit/Model/Json/PreProcessorTest.php | 58 ++++++++++++++++--- 2 files changed, 57 insertions(+), 11 deletions(-) diff --git a/app/code/Magento/Translation/Model/Json/PreProcessor.php b/app/code/Magento/Translation/Model/Json/PreProcessor.php index 5d46c3c8b0618..c178a324cb40b 100644 --- a/app/code/Magento/Translation/Model/Json/PreProcessor.php +++ b/app/code/Magento/Translation/Model/Json/PreProcessor.php @@ -6,6 +6,7 @@ namespace Magento\Translation\Model\Json; +use Magento\Framework\App\Area; use Magento\Framework\App\AreaList; use Magento\Framework\App\ObjectManager; use Magento\Framework\TranslateInterface; @@ -13,6 +14,7 @@ use Magento\Framework\View\Asset\PreProcessor\Chain; use Magento\Framework\View\Asset\PreProcessorInterface; use Magento\Framework\View\DesignInterface; +use Magento\Backend\App\Area\FrontNameResolver; use Magento\Translation\Model\Js\Config; use Magento\Translation\Model\Js\DataProviderInterface; @@ -83,7 +85,7 @@ public function process(Chain $chain) $context = $chain->getAsset()->getContext(); $themePath = '*/*'; - $areaCode = \Magento\Backend\App\Area\FrontNameResolver::AREA_CODE; + $areaCode = FrontNameResolver::AREA_CODE; if ($context instanceof FallbackContext) { $themePath = $context->getThemePath(); @@ -92,8 +94,10 @@ public function process(Chain $chain) $this->viewDesign->setDesignTheme($themePath, $areaCode); } - $area = $this->areaList->getArea($areaCode); - $area->load(\Magento\Framework\App\Area::PART_TRANSLATE); + if ($areaCode !== FrontNameResolver::AREA_CODE) { + $area = $this->areaList->getArea($areaCode); + $area->load(Area::PART_TRANSLATE); + } $this->translate->setLocale($context->getLocale())->loadData($areaCode, true); diff --git a/app/code/Magento/Translation/Test/Unit/Model/Json/PreProcessorTest.php b/app/code/Magento/Translation/Test/Unit/Model/Json/PreProcessorTest.php index d9340e03dc996..cbeeefed6be6e 100644 --- a/app/code/Magento/Translation/Test/Unit/Model/Json/PreProcessorTest.php +++ b/app/code/Magento/Translation/Test/Unit/Model/Json/PreProcessorTest.php @@ -8,39 +8,43 @@ use Magento\Translation\Model\Js\Config; use Magento\Translation\Model\Js\DataProvider; use Magento\Translation\Model\Json\PreProcessor; +use Magento\Backend\App\Area\FrontNameResolver; class PreProcessorTest extends \PHPUnit\Framework\TestCase { /** * @var PreProcessor */ - protected $model; + private $model; /** * @var Config|\PHPUnit_Framework_MockObject_MockObject */ - protected $configMock; + private $configMock; /** * @var DataProvider|\PHPUnit_Framework_MockObject_MockObject */ - protected $dataProviderMock; + private $dataProviderMock; /** * @var \Magento\Framework\App\AreaList|\PHPUnit_Framework_MockObject_MockObject */ - protected $areaListMock; + private $areaListMock; /** * @var \Magento\Framework\TranslateInterface|\PHPUnit_Framework_MockObject_MockObject */ - protected $translateMock; + private $translateMock; /** * @var \Magento\Framework\View\DesignInterface|\PHPUnit_Framework_MockObject_MockObject */ private $designMock; + /** + * @inheritdoc + */ protected function setUp() { $this->configMock = $this->createMock(\Magento\Translation\Model\Js\Config::class); @@ -57,7 +61,14 @@ protected function setUp() ); } - public function testGetData() + /** + * Test 'process' method. + * + * @param array $data + * @param array $expects + * @dataProvider processDataProvider + */ + public function testProcess(array $data, array $expects) { $chain = $this->createMock(\Magento\Framework\View\Asset\PreProcessor\Chain::class); $asset = $this->createMock(\Magento\Framework\View\Asset\File::class); @@ -66,8 +77,10 @@ public function testGetData() $targetPath = 'path/js-translation.json'; $themePath = '*/*'; $dictionary = ['hello' => 'bonjour']; - $areaCode = 'adminhtml'; + $areaCode = $data['area_code']; + $area = $this->createMock(\Magento\Framework\App\Area::class); + $area->expects($expects['area_load'])->method('load')->willReturnSelf(); $chain->expects($this->once()) ->method('getTargetAssetPath') @@ -93,7 +106,7 @@ public function testGetData() $this->designMock->expects($this->once())->method('setDesignTheme')->with($themePath, $areaCode); - $this->areaListMock->expects($this->once()) + $this->areaListMock->expects($expects['areaList_getArea']) ->method('getArea') ->with($areaCode) ->willReturn($area); @@ -114,4 +127,33 @@ public function testGetData() $this->model->process($chain); } + + /** + * Data provider for 'process' method test. + * + * @return array + */ + public function processDataProvider() + { + return [ + [ + [ + 'area_code' => FrontNameResolver::AREA_CODE + ], + [ + 'areaList_getArea' => $this->never(), + 'area_load' => $this->never(), + ] + ], + [ + [ + 'area_code' => 'frontend' + ], + [ + 'areaList_getArea' => $this->once(), + 'area_load' => $this->once(), + ] + ], + ]; + } } From 7022cadd60c752da5f32a8d4354d332b4ba64a03 Mon Sep 17 00:00:00 2001 From: Lusine Papyan <Lusine_Papyan@epam.com> Date: Thu, 24 Jan 2019 12:31:12 +0400 Subject: [PATCH 20/41] MC-10944: Menu point disappears from Customer account when FPC is on - Add automated test script --- .../Test/Mftf/Section/StorefrontCustomerSidebarSection.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Customer/Test/Mftf/Section/StorefrontCustomerSidebarSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/StorefrontCustomerSidebarSection.xml index 7482193031091..0e31f0e0c7782 100644 --- a/app/code/Magento/Customer/Test/Mftf/Section/StorefrontCustomerSidebarSection.xml +++ b/app/code/Magento/Customer/Test/Mftf/Section/StorefrontCustomerSidebarSection.xml @@ -10,5 +10,6 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="StorefrontCustomerSidebarSection"> <element name="sidebarTab" type="text" selector="//div[@id='block-collapsible-nav']//a[text()='{{var1}}']" parameterized="true"/> + <element name="sidebarCurrentTab" type="text" selector="//div[@id='block-collapsible-nav']//strong[contains(text(), '{{var}}')]" parameterized="true"/> </section> </sections> From 27e5a62e9efed7425b7b67d0a92b32644c7d9fba Mon Sep 17 00:00:00 2001 From: Oksana_Kremen <Oksana_Kremen@epam.com> Date: Tue, 29 Jan 2019 17:35:03 +0200 Subject: [PATCH 21/41] MC-5542: Fix testOutputErrorsWithMessageCategoryAndTrace on PHP 7.2 - Avoiding to include trace in developer mode as it causes error in webonyx graphql php 'Warning 'count' parameter must be an array or an object that implements Countable' - Unskipping unit test --- .../Magento/GraphQl/Controller/GraphQlControllerTest.php | 1 - lib/internal/Magento/Framework/GraphQl/Query/QueryProcessor.php | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/GraphQl/Controller/GraphQlControllerTest.php b/dev/tests/integration/testsuite/Magento/GraphQl/Controller/GraphQlControllerTest.php index 16a15cfcd2e26..384892d6fd5d2 100644 --- a/dev/tests/integration/testsuite/Magento/GraphQl/Controller/GraphQlControllerTest.php +++ b/dev/tests/integration/testsuite/Magento/GraphQl/Controller/GraphQlControllerTest.php @@ -116,7 +116,6 @@ public function testDispatch() : void */ public function testError() : void { - $this->markTestSkipped('Causes failiure with php unit and php 7.2'); $query = <<<QUERY { diff --git a/lib/internal/Magento/Framework/GraphQl/Query/QueryProcessor.php b/lib/internal/Magento/Framework/GraphQl/Query/QueryProcessor.php index a6ad10dded849..0a0dba36ef0ed 100644 --- a/lib/internal/Magento/Framework/GraphQl/Query/QueryProcessor.php +++ b/lib/internal/Magento/Framework/GraphQl/Query/QueryProcessor.php @@ -69,7 +69,7 @@ public function process( $operationName )->toArray( $this->exceptionFormatter->shouldShowDetail() ? - \GraphQL\Error\Debug::INCLUDE_DEBUG_MESSAGE | \GraphQL\Error\Debug::INCLUDE_TRACE : false + \GraphQL\Error\Debug::INCLUDE_DEBUG_MESSAGE : false ); } } From fcd3fb665e7279238fd7875115ca56f7c0326379 Mon Sep 17 00:00:00 2001 From: Alexey Yakimovich <yakimovich@almagy.com> Date: Wed, 30 Jan 2019 15:30:15 +0300 Subject: [PATCH 22/41] MAGETWO-96545: Wrong calculation of invoiced items in shipment document in order with bundle product after partial invoice - Moved logic part from template to block; --- .../Adminhtml/Sales/Order/Items/Renderer.php | 32 +++++++++++++++++++ .../sales/invoice/create/items/renderer.phtml | 7 +--- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/Bundle/Block/Adminhtml/Sales/Order/Items/Renderer.php b/app/code/Magento/Bundle/Block/Adminhtml/Sales/Order/Items/Renderer.php index 23fc2026ab111..c8dd23fe120c9 100644 --- a/app/code/Magento/Bundle/Block/Adminhtml/Sales/Order/Items/Renderer.php +++ b/app/code/Magento/Bundle/Block/Adminhtml/Sales/Order/Items/Renderer.php @@ -100,6 +100,8 @@ public function getChildren($item) } /** + * Check if item can be shipped separately + * * @param mixed $item * @return bool * @SuppressWarnings(PHPMD.CyclomaticComplexity) @@ -136,6 +138,8 @@ public function isShipmentSeparately($item = null) } /** + * Check if child items calculated + * * @param mixed $item * @return bool * @SuppressWarnings(PHPMD.CyclomaticComplexity) @@ -174,6 +178,8 @@ public function isChildCalculated($item = null) } /** + * Retrieve selection attributes values + * * @param mixed $item * @return mixed|null */ @@ -191,6 +197,8 @@ public function getSelectionAttributes($item) } /** + * Retrieve order item options array + * * @return array */ public function getOrderOptions() @@ -212,6 +220,8 @@ public function getOrderOptions() } /** + * Retrieve order item + * * @return mixed */ public function getOrderItem() @@ -223,6 +233,8 @@ public function getOrderItem() } /** + * Get html info for item + * * @param mixed $item * @return string */ @@ -245,6 +257,8 @@ public function getValueHtml($item) } /** + * Check if we can show price info for this item + * * @param object $item * @return bool */ @@ -257,4 +271,22 @@ public function canShowPriceInfo($item) } return false; } + + /** + * Check if this iten should be shipped together + * + * @param object $item + * @return bool + */ + public function isShipTogether($item) + { + $orderItem = $item->getOrderItem(); + if ($orderItem->getProductType() == \Magento\Catalog\Model\Product\Type::TYPE_BUNDLE) { + $shipTogether = !$orderItem->isShipSeparately(); + } else { + $shipTogether = !$orderItem->getParentItem()->isShipSeparately(); + } + + return $shipTogether; + } } diff --git a/app/code/Magento/Bundle/view/adminhtml/templates/sales/invoice/create/items/renderer.phtml b/app/code/Magento/Bundle/view/adminhtml/templates/sales/invoice/create/items/renderer.phtml index ae1e9f3483192..6437c578caa0f 100644 --- a/app/code/Magento/Bundle/view/adminhtml/templates/sales/invoice/create/items/renderer.phtml +++ b/app/code/Magento/Bundle/view/adminhtml/templates/sales/invoice/create/items/renderer.phtml @@ -29,12 +29,7 @@ <?php foreach ($items as $_item): ?> <?php - $orderItem = $_item->getOrderItem(); - if ($orderItem->getProductType() == \Magento\Catalog\Model\Product\Type::TYPE_BUNDLE) { - $shipTogether = !$orderItem->isShipSeparately(); - } else { - $shipTogether = !$orderItem->getParentItem()->isShipSeparately(); - } + $shipTogether = $block->isShipTogether($_item); ?> <?php $block->setPriceDataObject($_item) ?> <?php if ($_item->getOrderItem()->getParentItem()): ?> From 1ddcb05c2a6ef063c97f89a9b852e2ec0343d734 Mon Sep 17 00:00:00 2001 From: Yuliya Labudova <Yuliya_Labudova@epam.com> Date: Wed, 30 Jan 2019 17:44:57 +0300 Subject: [PATCH 23/41] MAGETWO-55841: API call with pageSize and currentPage > items should return error - Fix for category list. --- app/code/Magento/Catalog/Model/CategoryList.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Model/CategoryList.php b/app/code/Magento/Catalog/Model/CategoryList.php index 790ea6b921fbe..6fecafb52cde9 100644 --- a/app/code/Magento/Catalog/Model/CategoryList.php +++ b/app/code/Magento/Catalog/Model/CategoryList.php @@ -15,6 +15,9 @@ use Magento\Framework\Api\SearchCriteriaInterface; use Magento\Framework\Api\SearchCriteria\CollectionProcessorInterface; +/** + * Class for getting category list. + */ class CategoryList implements CategoryListInterface { /** @@ -64,7 +67,7 @@ public function __construct( } /** - * {@inheritdoc} + * @inheritdoc */ public function getList(SearchCriteriaInterface $searchCriteria) { @@ -73,6 +76,7 @@ public function getList(SearchCriteriaInterface $searchCriteria) $this->extensionAttributesJoinProcessor->process($collection); $this->collectionProcessor->process($searchCriteria, $collection); + $collection->load(); $items = []; foreach ($collection->getAllIds() as $id) { From 6cc7700565c5e00b04bea55579562c3d2bd21c71 Mon Sep 17 00:00:00 2001 From: Alexey Yakimovich <yakimovich@almagy.com> Date: Wed, 30 Jan 2019 17:56:51 +0300 Subject: [PATCH 24/41] MAGETWO-96545: Wrong calculation of invoiced items in shipment document in order with bundle product after partial invoice - Fixed issue aftef incorrect conflict merge; --- app/code/Magento/Sales/Model/Service/InvoiceService.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/code/Magento/Sales/Model/Service/InvoiceService.php b/app/code/Magento/Sales/Model/Service/InvoiceService.php index 9db6afa1ce793..cc037ad7327b5 100644 --- a/app/code/Magento/Sales/Model/Service/InvoiceService.php +++ b/app/code/Magento/Sales/Model/Service/InvoiceService.php @@ -229,7 +229,6 @@ private function prepareItemQty(\Magento\Sales\Api\Data\OrderItemInterface $orde $qtys[$parent->getId()] = $parent->getQtyToInvoice(); } } - $this->prepareItemQty($orderItem, $qtys); } } From c142e71f88efedef992362d70b694b1dd8b430b3 Mon Sep 17 00:00:00 2001 From: Alexey Yakimovich <yakimovich@almagy.com> Date: Thu, 31 Jan 2019 12:59:42 +0300 Subject: [PATCH 25/41] MAGETWO-96545: Wrong calculation of invoiced items in shipment document in order with bundle product after partial invoice - Fixed WebApi test issue; --- app/code/Magento/Sales/Model/Service/InvoiceService.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Sales/Model/Service/InvoiceService.php b/app/code/Magento/Sales/Model/Service/InvoiceService.php index cc037ad7327b5..ba6ae7eb14ba7 100644 --- a/app/code/Magento/Sales/Model/Service/InvoiceService.php +++ b/app/code/Magento/Sales/Model/Service/InvoiceService.php @@ -242,9 +242,11 @@ private function prepareBundleQty(\Magento\Sales\Api\Data\OrderItemInterface $or { if ($orderItem->getProductType() == Type::TYPE_BUNDLE && !$orderItem->isShipSeparately()) { foreach ($orderItem->getChildrenItems() as $childItem) { - $bundleSelectionAttributes = $this->serializer->unserialize( - $childItem->getProductOptionByCode('bundle_selection_attributes') - ); + $bundleSelectionAttributes = $childItem->getProductOptionByCode('bundle_selection_attributes'); + if (is_string($bundleSelectionAttributes)) { + $bundleSelectionAttributes = $this->serializer->unserialize($bundleSelectionAttributes); + } + $qtys[$childItem->getId()] = $qtys[$orderItem->getId()] * $bundleSelectionAttributes['qty']; } } From 3f84c310e47575b17864a2776d4b10366d33e616 Mon Sep 17 00:00:00 2001 From: Alexey Yakimovich <yakimovich@almagy.com> Date: Thu, 31 Jan 2019 17:10:36 +0300 Subject: [PATCH 26/41] MAGETWO-95836: [Magento Cloud] If a product has a custom attributes which requires a Unique Value, it cannot be saved when there's an active Scheduled Update - Fixed circular dependency issue; --- app/code/Magento/Eav/Model/Entity/AbstractEntity.php | 2 +- .../Entity/Attribute/UniqueValidationInterface.php | 9 ++++++--- .../Eav/Model/Entity/Attribute/UniqueValidator.php | 12 ++++++++++-- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/Eav/Model/Entity/AbstractEntity.php b/app/code/Magento/Eav/Model/Entity/AbstractEntity.php index 704ec0a7f701b..2c8898b154195 100644 --- a/app/code/Magento/Eav/Model/Entity/AbstractEntity.php +++ b/app/code/Magento/Eav/Model/Entity/AbstractEntity.php @@ -971,7 +971,7 @@ public function checkAttributeUniqueValue(AbstractAttribute $attribute, $object) $data = $connection->fetchCol($select, $bind); if ($object->getData($entityIdField)) { - return $this->uniqueValidator->validate($attribute, $object, $entityIdField, $data); + return $this->uniqueValidator->validate($attribute, $object, $this, $entityIdField, $data); } return !count($data); diff --git a/app/code/Magento/Eav/Model/Entity/Attribute/UniqueValidationInterface.php b/app/code/Magento/Eav/Model/Entity/Attribute/UniqueValidationInterface.php index 648f51ade11de..374ed04e5c6ea 100644 --- a/app/code/Magento/Eav/Model/Entity/Attribute/UniqueValidationInterface.php +++ b/app/code/Magento/Eav/Model/Entity/Attribute/UniqueValidationInterface.php @@ -5,6 +5,8 @@ */ namespace Magento\Eav\Model\Entity\Attribute; +use Magento\Framework\DataObject; +use Magento\Eav\Model\Entity\AbstractEntity; /** * Interface for unique attribute validator */ @@ -14,10 +16,11 @@ interface UniqueValidationInterface * Validate if attribute value is unique * * @param AbstractAttribute $attribute - * @param \Magento\Framework\DataObject $object - * @param string $entityLinkField + * @param DataObject $object + * @param AbstractEntity $entity + * @param $entityLinkField * @param array $entityIds * @return bool */ - public function validate(AbstractAttribute $attribute, $object, $entityLinkField, array $entityIds); + public function validate(AbstractAttribute $attribute, DataObject $object, AbstractEntity $entity, $entityLinkField, array $entityIds); } diff --git a/app/code/Magento/Eav/Model/Entity/Attribute/UniqueValidator.php b/app/code/Magento/Eav/Model/Entity/Attribute/UniqueValidator.php index f9c7ffecedc60..b1888b42bef92 100644 --- a/app/code/Magento/Eav/Model/Entity/Attribute/UniqueValidator.php +++ b/app/code/Magento/Eav/Model/Entity/Attribute/UniqueValidator.php @@ -5,6 +5,9 @@ */ namespace Magento\Eav\Model\Entity\Attribute; +use Magento\Framework\DataObject; +use Magento\Eav\Model\Entity\AbstractEntity; + /** * Class for validate unique attribute value */ @@ -13,8 +16,13 @@ class UniqueValidator implements UniqueValidationInterface /** * @inheritdoc */ - public function validate(AbstractAttribute $attribute, $object, $entityLinkField, array $entityIds) - { + public function validate( + AbstractAttribute $attribute, + DataObject $object, + AbstractEntity $entity, + $entityLinkField, + array $entityIds + ) { if (isset($entityIds[0])) { return $entityIds[0] == $object->getData($entityLinkField); } From d95ceb74c23d6bbb8ae7f437ad4fe5f60c1a8f1f Mon Sep 17 00:00:00 2001 From: Alexey Yakimovich <yakimovich@almagy.com> Date: Fri, 1 Feb 2019 10:16:02 +0300 Subject: [PATCH 27/41] MAGETWO-95836: [Magento Cloud] If a product has a custom attributes which requires a Unique Value, it cannot be saved when there's an active Scheduled Update - Fixed static test; --- .../Entity/Attribute/UniqueValidationInterface.php | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Eav/Model/Entity/Attribute/UniqueValidationInterface.php b/app/code/Magento/Eav/Model/Entity/Attribute/UniqueValidationInterface.php index 374ed04e5c6ea..b68e79d7b7d20 100644 --- a/app/code/Magento/Eav/Model/Entity/Attribute/UniqueValidationInterface.php +++ b/app/code/Magento/Eav/Model/Entity/Attribute/UniqueValidationInterface.php @@ -7,6 +7,7 @@ use Magento\Framework\DataObject; use Magento\Eav\Model\Entity\AbstractEntity; + /** * Interface for unique attribute validator */ @@ -18,9 +19,15 @@ interface UniqueValidationInterface * @param AbstractAttribute $attribute * @param DataObject $object * @param AbstractEntity $entity - * @param $entityLinkField + * @param string $entityLinkField * @param array $entityIds * @return bool */ - public function validate(AbstractAttribute $attribute, DataObject $object, AbstractEntity $entity, $entityLinkField, array $entityIds); + public function validate( + AbstractAttribute $attribute, + DataObject $object, + AbstractEntity $entity, + $entityLinkField, + array $entityIds + ); } From a48cd8b634e6042051e82727f264b18b7137c952 Mon Sep 17 00:00:00 2001 From: Yuliya Labudova <Yuliya_Labudova@epam.com> Date: Fri, 1 Feb 2019 11:05:37 +0300 Subject: [PATCH 28/41] MAGETWO-58841: API call with pageSize and currentPage > items should return error - Return only requested category --- app/code/Magento/Catalog/Model/CategoryList.php | 4 ++-- app/code/Magento/Catalog/Test/Unit/Model/CategoryListTest.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Catalog/Model/CategoryList.php b/app/code/Magento/Catalog/Model/CategoryList.php index 6fecafb52cde9..e3318db505489 100644 --- a/app/code/Magento/Catalog/Model/CategoryList.php +++ b/app/code/Magento/Catalog/Model/CategoryList.php @@ -79,8 +79,8 @@ public function getList(SearchCriteriaInterface $searchCriteria) $collection->load(); $items = []; - foreach ($collection->getAllIds() as $id) { - $items[] = $this->categoryRepository->get($id); + foreach ($collection->getItems() as $category) { + $items[] = $this->categoryRepository->get($category->getId()); } /** @var CategorySearchResultsInterface $searchResult */ diff --git a/app/code/Magento/Catalog/Test/Unit/Model/CategoryListTest.php b/app/code/Magento/Catalog/Test/Unit/Model/CategoryListTest.php index b8b76524099f4..f78c0ad924954 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/CategoryListTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/CategoryListTest.php @@ -93,7 +93,7 @@ public function testGetList() $collection = $this->getMockBuilder(Collection::class)->disableOriginalConstructor()->getMock(); $collection->expects($this->once())->method('getSize')->willReturn($totalCount); - $collection->expects($this->once())->method('getAllIds')->willReturn([$categoryIdFirst, $categoryIdSecond]); + $collection->expects($this->once())->method('getItems')->willReturn([$categoryFirst, $categorySecond]); $this->collectionProcessorMock->expects($this->once()) ->method('process') From 27a5a52a25dedf2f6d8e211275c92bed866c0df4 Mon Sep 17 00:00:00 2001 From: Alexey Yakimovich <yakimovich@almagy.com> Date: Fri, 1 Feb 2019 12:18:02 +0300 Subject: [PATCH 29/41] MAGETWO-95836: [Magento Cloud] If a product has a custom attributes which requires a Unique Value, it cannot be saved when there's an active Scheduled Update - Fixed integration test issue; --- app/code/Magento/Eav/Model/Entity/AbstractEntity.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Eav/Model/Entity/AbstractEntity.php b/app/code/Magento/Eav/Model/Entity/AbstractEntity.php index 2c8898b154195..d0a5e8de53ae9 100644 --- a/app/code/Magento/Eav/Model/Entity/AbstractEntity.php +++ b/app/code/Magento/Eav/Model/Entity/AbstractEntity.php @@ -931,7 +931,7 @@ public function checkAttributeUniqueValue(AbstractAttribute $attribute, $object) $connection = $this->getConnection(); $select = $connection->select(); - $entityIdField = $object->getResource()->getLinkField(); + $entityIdField = $this->getEntityIdField(); $attributeBackend = $attribute->getBackend(); if ($attributeBackend->getType() === 'static') { $value = $object->getData($attribute->getAttributeCode()); @@ -953,6 +953,7 @@ public function checkAttributeUniqueValue(AbstractAttribute $attribute, $object) 'value' => trim($value), ]; + $entityIdField = $object->getResource()->getLinkField(); $select->from( $attributeBackend->getTable(), $entityIdField From a05fdf65c34be11b39b66ce4f0b30e31dd827a2d Mon Sep 17 00:00:00 2001 From: Davit Zakharyan <davit_zakharyan@epam.com> Date: Fri, 25 Jan 2019 12:35:09 +0400 Subject: [PATCH 30/41] MC-4316: Tax calculation process does not follow "Apply Tax On" setting - Added automated test script. --- .../Catalog/Test/Mftf/Data/ProductData.xml | 3 + .../ConfigSalesTaxClassActionGroup.xml | 14 ++++ .../Tax/Test/Mftf/Data/TaxRateData.xml | 4 + .../Test/Mftf/Page/AdminEditTaxRatePage.xml | 14 ++++ .../Test/Mftf/Page/AdminEditTaxRulePage.xml | 14 ++++ .../Mftf/Section/AdminConfigureTaxSection.xml | 2 + .../Mftf/Section/AdminTaxRulesSection.xml | 1 + .../AdminTaxCalcWithApplyTaxOnSettingTest.xml | 75 +++++++++++++++++++ 8 files changed, 127 insertions(+) create mode 100644 app/code/Magento/Tax/Test/Mftf/Page/AdminEditTaxRatePage.xml create mode 100644 app/code/Magento/Tax/Test/Mftf/Page/AdminEditTaxRulePage.xml create mode 100644 app/code/Magento/Tax/Test/Mftf/Test/AdminTaxCalcWithApplyTaxOnSettingTest.xml diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml index 23253ad6ad8f8..1fea608c5f786 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml @@ -35,6 +35,9 @@ <requiredEntity type="product_extension_attribute">EavStockItem</requiredEntity> <requiredEntity type="custom_attribute_array">CustomAttributeCategoryIds</requiredEntity> </entity> + <entity name="ApiSimpleProductWithCustomPrice" type="product" extends="ApiSimpleProduct"> + <data key="price">100</data> + </entity> <entity name="ApiSimpleProductUpdateDescription" type="product2"> <requiredEntity type="custom_attribute">ApiProductDescription</requiredEntity> <requiredEntity type="custom_attribute">ApiProductShortDescription</requiredEntity> diff --git a/app/code/Magento/Config/Test/Mftf/ActionGroup/ConfigSalesTaxClassActionGroup.xml b/app/code/Magento/Config/Test/Mftf/ActionGroup/ConfigSalesTaxClassActionGroup.xml index 06c041fabeb35..e896d7d0f76a6 100644 --- a/app/code/Magento/Config/Test/Mftf/ActionGroup/ConfigSalesTaxClassActionGroup.xml +++ b/app/code/Magento/Config/Test/Mftf/ActionGroup/ConfigSalesTaxClassActionGroup.xml @@ -28,4 +28,18 @@ <click selector="{{SalesConfigSection.TaxClassesTab}}" stepKey="collapseTaxClassesTab"/> <click selector="{{ContentManagementSection.Save}}" stepKey="saveConfiguration"/> </actionGroup> + <actionGroup name="SetTaxApplyOnSetting"> + <arguments> + <argument name="userInput" type="string"/> + </arguments> + <conditionalClick selector="{{AdminConfigureTaxSection.taxCalculationSettings}}" dependentSelector="{{AdminConfigureTaxSection.taxCalculationAlgorithm}}" visible="false" stepKey="openTaxCalcSettingsSection"/> + <scrollTo selector="{{AdminConfigureTaxSection.taxCalculationApplyTaxOnInherit}}" stepKey="goToCheckbox"/> + <uncheckOption selector="{{AdminConfigureTaxSection.taxCalculationApplyTaxOnInherit}}" stepKey="enableApplyTaxOnSetting"/> + <selectOption selector="{{AdminConfigureTaxSection.taxCalculationApplyTaxOn}}" userInput="{{userInput}}" stepKey="setApplyTaxOn"/> + <scrollTo selector="{{SalesConfigSection.TaxClassesTab}}" stepKey="scrollToTop"/> + <click selector="{{AdminConfigureTaxSection.taxCalculationSettings}}" stepKey="collapseCalcSettingsTab"/> + <click selector="{{AdminConfigureTaxSection.save}}" stepKey="saveConfig"/> + <waitForPageLoad stepKey="waitForConfigSaved"/> + <see userInput="You saved the configuration." stepKey="seeSuccessMessage"/> + </actionGroup> </actionGroups> \ No newline at end of file diff --git a/app/code/Magento/Tax/Test/Mftf/Data/TaxRateData.xml b/app/code/Magento/Tax/Test/Mftf/Data/TaxRateData.xml index 887203a76fdad..4409ea0a21df6 100644 --- a/app/code/Magento/Tax/Test/Mftf/Data/TaxRateData.xml +++ b/app/code/Magento/Tax/Test/Mftf/Data/TaxRateData.xml @@ -106,4 +106,8 @@ <data key="zip_is_range">0</data> <data key="rate">0.1</data> </entity> + <entity name="taxRateForPensylvannia" extends="defaultTaxRate"> + <data key="tax_region_id">51</data> + <data key="rate">6</data> + </entity> </entities> diff --git a/app/code/Magento/Tax/Test/Mftf/Page/AdminEditTaxRatePage.xml b/app/code/Magento/Tax/Test/Mftf/Page/AdminEditTaxRatePage.xml new file mode 100644 index 0000000000000..26152d5497a98 --- /dev/null +++ b/app/code/Magento/Tax/Test/Mftf/Page/AdminEditTaxRatePage.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd"> + <page name="AdminEditTaxRatePage" url="tax/rate/edit/rate/{{var1}}/" module="Magento_Tax" area="admin" parameterized="true"> + <section name="AdminTaxRateFormSection"/> + </page> +</pages> diff --git a/app/code/Magento/Tax/Test/Mftf/Page/AdminEditTaxRulePage.xml b/app/code/Magento/Tax/Test/Mftf/Page/AdminEditTaxRulePage.xml new file mode 100644 index 0000000000000..c0e4958619c89 --- /dev/null +++ b/app/code/Magento/Tax/Test/Mftf/Page/AdminEditTaxRulePage.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd"> + <page name="AdminEditTaxRulePage" url="tax/rule/edit/rule/{{var}}/" module="Magento_Tax" area="admin" parameterized="true"> + <section name="AdminTaxRulesSection"/> + </page> +</pages> diff --git a/app/code/Magento/Tax/Test/Mftf/Section/AdminConfigureTaxSection.xml b/app/code/Magento/Tax/Test/Mftf/Section/AdminConfigureTaxSection.xml index bfb082c145f07..e69bfbaebbfd9 100644 --- a/app/code/Magento/Tax/Test/Mftf/Section/AdminConfigureTaxSection.xml +++ b/app/code/Magento/Tax/Test/Mftf/Section/AdminConfigureTaxSection.xml @@ -28,6 +28,8 @@ <element name="taxCalculationPrices" type="select" selector="#tax_calculation_price_includes_tax"/> <element name="taxCalculationPricesDisabled" type="select" selector="#tax_calculation_price_includes_tax[disabled='disabled']"/> <element name="taxCalculationPricesInherit" type="checkbox" selector="#tax_calculation_price_includes_tax_inherit"/> + <element name="taxCalculationApplyTaxOn" type="select" selector="#tax_calculation_apply_tax_on"/> + <element name="taxCalculationApplyTaxOnInherit" type="checkbox" selector="#tax_calculation_apply_tax_on_inherit"/> <element name="defaultDestination" type="block" selector="#tax_defaults-head" timeout="30"/> <element name="systemValueDefaultState" type="checkbox" selector="#row_tax_defaults_region input[type='checkbox']"/> diff --git a/app/code/Magento/Tax/Test/Mftf/Section/AdminTaxRulesSection.xml b/app/code/Magento/Tax/Test/Mftf/Section/AdminTaxRulesSection.xml index 29c53242b90f6..46d92e30395e0 100644 --- a/app/code/Magento/Tax/Test/Mftf/Section/AdminTaxRulesSection.xml +++ b/app/code/Magento/Tax/Test/Mftf/Section/AdminTaxRulesSection.xml @@ -33,5 +33,6 @@ <element name="deleteTaxClass" type="button" selector="//span[contains(text(),'{{var1}}')]/../..//*[@class='mselect-delete']" parameterized="true"/> <element name="popUpDialogOK" type="button" selector="//*[@class='modal-footer']//*[contains(text(),'OK')]"/> <element name="taxRateMultiSelectItems" type="block" selector=".mselect-list-item"/> + <element name="taxRateNumber" type="button" selector="//div[@data-ui-id='tax-rate-form-fieldset-element-form-field-tax-rate']//div[@class='mselect-items-wrapper']//label[{{var}}]" parameterized="true"/> </section> </sections> diff --git a/app/code/Magento/Tax/Test/Mftf/Test/AdminTaxCalcWithApplyTaxOnSettingTest.xml b/app/code/Magento/Tax/Test/Mftf/Test/AdminTaxCalcWithApplyTaxOnSettingTest.xml new file mode 100644 index 0000000000000..d02cfd7ee39fc --- /dev/null +++ b/app/code/Magento/Tax/Test/Mftf/Test/AdminTaxCalcWithApplyTaxOnSettingTest.xml @@ -0,0 +1,75 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="AdminTaxCalcWithApplyTaxOnSettingTest"> + <annotations> + <features value="AdminTaxCalcWithApplyTaxOnSettingTest"/> + <title value="Tax calculation process following 'Apply Tax On' setting"/> + <description value="Tax calculation process following 'Apply Tax On' setting"/> + <severity value="MAJOR"/> + <testCaseId value="MC-11026"/> + <useCaseId value="MC-4316"/> + <group value="Tax"/> + </annotations> + + <before> + <createData entity="taxRateForPensylvannia" stepKey="initialTaxRate"/> + <createData entity="defaultTaxRule" stepKey="createTaxRule"/> + <createData entity="ApiCategory" stepKey="createCategory"/> + <createData entity="ApiSimpleProductWithCustomPrice" stepKey="createProduct"> + <requiredEntity createDataKey="createCategory"/> + </createData> + <actionGroup ref="LoginActionGroup" stepKey="loginAsAdmin"/> + <actionGroup ref="SetTaxClassForShipping" stepKey="setTaxClass"/> + <actionGroup ref="SetTaxApplyOnSetting" stepKey="setApplyTaxOnSetting"> + <argument name="userInput" value="Original price only"/> + </actionGroup> + <amOnPage url="{{AdminEditTaxRulePage.url($$createTaxRule.id$$)}}" stepKey="navigateToEditTaxRulePage"/> + <waitForPageLoad stepKey="waitEditTaxRulePageToLoad"/> + <click selector="{{AdminTaxRulesSection.taxRateNumber('1')}}" stepKey="clickonTaxRate"/> + <click selector="{{AdminTaxRulesSection.deleteTaxClassName($$initialTaxRate.code$$)}}" stepKey="checkTaxRate"/> + <click selector="{{AdminTaxRulesSection.saveRule}}" stepKey="saveChanges"/> + <waitForPageLoad stepKey="waitTaxRulesToBeSaved"/> + <see selector="{{AdminMessagesSection.success}}" userInput="You saved the tax rule." stepKey="seeSuccessMessage2"/> + </before> + <after> + <deleteData createDataKey="createProduct" stepKey="deleteSimpleProduct"/> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + <deleteData createDataKey="createTaxRule" stepKey="deleteTaxRule"/> + <deleteData stepKey="deleteTaxRate" createDataKey="initialTaxRate" /> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <actionGroup ref="navigateToNewOrderPageNewCustomerSingleStore" stepKey="gotoNewOrderCreationPage"/> + <actionGroup ref="addSimpleProductToOrder" stepKey="addSimpleProductToOrder"> + <argument name="product" value="$$createProduct$$"></argument> + </actionGroup> + <fillField selector="{{AdminOrderFormAccountSection.email}}" userInput="{{Simple_US_Customer.email}}" stepKey="fillEmailField"/> + <actionGroup ref="fillOrderCustomerInformation" stepKey="fillCustomerAddress"> + <argument name="customer" value="Simple_US_Customer"/> + <argument name="address" value="US_Address_CA"/> + </actionGroup> + <scrollTo selector="{{AdminOrderFormAccountSection.email}}" stepKey="scrollToEmailField"/> + <waitForElementVisible selector="{{AdminOrderFormAccountSection.email}}" stepKey="waitEmailFieldToBeVisible"/> + <click selector="{{AdminOrderFormShippingAddressSection.SameAsBilling}}" stepKey="uncheckSameAsBillingAddressCheckbox"/> + <waitForPageLoad stepKey="waitSectionToReload"/> + <selectOption selector="{{AdminOrderFormShippingAddressSection.State}}" stepKey="switchOnVisibleInAdvancedSearch" userInput="Pennsylvania"/> + <click selector="{{AdminOrderFormPaymentSection.getShippingMethods}}" stepKey="getShippingMethods"/> + <waitForPageLoad stepKey="waitForApplyingShippingMethods"/> + <grabTextFrom selector="{{AdminOrderFormTotalSection.subtotalRow('3')}}" stepKey="grabTaxCost"/> + <assertEquals expected='$6.00' expectedType="string" actual="($grabTaxCost)" stepKey="assertTax"/> + <scrollTo selector="{{AdminOrderFormItemsSection.addProducts}}" stepKey="scrollToSubmitButton"/> + <waitForElementVisible selector="{{AdminOrderFormItemsSection.addProducts}}" stepKey="waitElementToBeVisble"/> + <click selector="{{AdminOrderFormItemsSection.customPriceCheckbox}}" stepKey="clickOnCustomPriceCheckbox"/> + <fillField selector="{{AdminOrderFormItemsSection.customPriceField}}" userInput="{{SimpleProductNameWithDoubleQuote.price}}" stepKey="changePrice"/> + <click selector="{{AdminOrderFormItemsSection.updateItemsAndQuantities}}" stepKey="updateItemsAndQunatities"/> + <assertEquals expected='$6.00' expectedType="string" actual="($grabTaxCost)" stepKey="assertTaxAfterCustomPrice"/> + </test> +</tests> From 4ec8dfb6c71aeccafe9f9b64a4192b28d5fdec84 Mon Sep 17 00:00:00 2001 From: Yuliya Labudova <Yuliya_Labudova@epam.com> Date: Mon, 4 Feb 2019 11:11:05 +0300 Subject: [PATCH 31/41] MC-4316: Tax calculation process does not follow "Apply Tax On" setting - Fix for integration and functional tests. --- .../ActionGroup/ConfigSalesTaxClassActionGroup.xml | 14 ++++++++++++++ .../Calculation/AbstractAggregateCalculator.php | 2 +- .../Test/AdminTaxCalcWithApplyTaxOnSettingTest.xml | 4 ++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Config/Test/Mftf/ActionGroup/ConfigSalesTaxClassActionGroup.xml b/app/code/Magento/Config/Test/Mftf/ActionGroup/ConfigSalesTaxClassActionGroup.xml index e896d7d0f76a6..1a7b641070ad8 100644 --- a/app/code/Magento/Config/Test/Mftf/ActionGroup/ConfigSalesTaxClassActionGroup.xml +++ b/app/code/Magento/Config/Test/Mftf/ActionGroup/ConfigSalesTaxClassActionGroup.xml @@ -42,4 +42,18 @@ <waitForPageLoad stepKey="waitForConfigSaved"/> <see userInput="You saved the configuration." stepKey="seeSuccessMessage"/> </actionGroup> + <actionGroup name="DisableTaxApplyOnOriginalPrice"> + <arguments> + <argument name="userInput" type="string"/> + </arguments> + <amOnPage url="{{AdminSalesTaxClassPage.url}}" stepKey="navigateToSalesTaxPage"/> + <waitForPageLoad stepKey="waitForPageLoad"/> + <conditionalClick selector="{{AdminConfigureTaxSection.taxCalculationSettings}}" dependentSelector="{{AdminConfigureTaxSection.taxCalculationAlgorithm}}" visible="false" stepKey="openTaxCalcSettingsSection"/> + <scrollTo selector="{{AdminConfigureTaxSection.taxCalculationApplyTaxOnInherit}}" stepKey="goToCheckbox"/> + <selectOption selector="{{AdminConfigureTaxSection.taxCalculationApplyTaxOn}}" userInput="{{userInput}}" stepKey="setApplyTaxOff"/> + <checkOption selector="{{AdminConfigureTaxSection.taxCalculationApplyTaxOnInherit}}" stepKey="disableApplyTaxOnSetting"/> + <click selector="{{AdminConfigureTaxSection.save}}" stepKey="saveConfig"/> + <waitForPageLoad stepKey="waitForConfigSaved"/> + <see userInput="You saved the configuration." stepKey="seeSuccessMessage"/> + </actionGroup> </actionGroups> \ No newline at end of file diff --git a/app/code/Magento/Tax/Model/Calculation/AbstractAggregateCalculator.php b/app/code/Magento/Tax/Model/Calculation/AbstractAggregateCalculator.php index 9000b61a8e8bf..939facd02c02d 100644 --- a/app/code/Magento/Tax/Model/Calculation/AbstractAggregateCalculator.php +++ b/app/code/Magento/Tax/Model/Calculation/AbstractAggregateCalculator.php @@ -126,7 +126,7 @@ protected function calculateWithTaxNotInPrice(QuoteDetailsItemInterface $item, $ if ($applyTaxAfterDiscount) { //TODO: handle originalDiscountAmount $taxableAmount = max($rowTotalForTaxCalculation - $discountAmount, 0); - if ($taxableAmount) { + if ($taxableAmount && !$applyTaxAfterDiscount) { $taxableAmount = $rowTotalForTaxCalculation; } $rowTaxAfterDiscount = $this->calculationTool->calcTaxAmount( diff --git a/app/code/Magento/Tax/Test/Mftf/Test/AdminTaxCalcWithApplyTaxOnSettingTest.xml b/app/code/Magento/Tax/Test/Mftf/Test/AdminTaxCalcWithApplyTaxOnSettingTest.xml index d02cfd7ee39fc..732470d2558c7 100644 --- a/app/code/Magento/Tax/Test/Mftf/Test/AdminTaxCalcWithApplyTaxOnSettingTest.xml +++ b/app/code/Magento/Tax/Test/Mftf/Test/AdminTaxCalcWithApplyTaxOnSettingTest.xml @@ -44,6 +44,10 @@ <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> <deleteData createDataKey="createTaxRule" stepKey="deleteTaxRule"/> <deleteData stepKey="deleteTaxRate" createDataKey="initialTaxRate" /> + <actionGroup ref="DisableTaxApplyOnOriginalPrice" stepKey="setApplyTaxOffSetting"> + <argument name="userInput" value="Custom price if available"/> + </actionGroup> + <actionGroup ref="ResetTaxClassForShipping" stepKey="resetTaxClassForShipping"/> <actionGroup ref="logout" stepKey="logout"/> </after> From 7ed99cbf258cf5e38663179a95e4ca8f9ddb4386 Mon Sep 17 00:00:00 2001 From: Yuliya Labudova <Yuliya_Labudova@epam.com> Date: Mon, 4 Feb 2019 18:23:01 +0300 Subject: [PATCH 32/41] MAGETWO-96421: Header Minicart ,Shopping cart page and Checkout page show incorrect product name - Fix static and integration test --- .../Magento/Checkout/view/frontend/web/js/view/minicart.js | 4 ++-- .../Magento/Customer/Block/Adminhtml/Edit/Tab/View/Cart.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/minicart.js b/app/code/Magento/Checkout/view/frontend/web/js/view/minicart.js index f3dddbe218fe9..6babf0161527e 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/view/minicart.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/view/minicart.js @@ -101,8 +101,8 @@ define([ self.isLoading(true); }); - if (cartData()['website_id'] !== window.checkout.websiteId || - cartData()['storeId'] !== window.checkout.storeId + if (cartData().website_id !== window.checkout.websiteId || + cartData().store_id !== window.checkout.storeId ) { customerData.reload(['cart'], false); } diff --git a/app/code/Magento/Customer/Block/Adminhtml/Edit/Tab/View/Cart.php b/app/code/Magento/Customer/Block/Adminhtml/Edit/Tab/View/Cart.php index 3f2c7cda7608d..d0973d3baf383 100644 --- a/app/code/Magento/Customer/Block/Adminhtml/Edit/Tab/View/Cart.php +++ b/app/code/Magento/Customer/Block/Adminhtml/Edit/Tab/View/Cart.php @@ -94,7 +94,7 @@ protected function _prepareCollection() $quote = $this->getQuote(); if ($quote) { - $collection = $quote->getItemsCollection(false); + $collection = $quote->getItemsCollection(true); } else { $collection = $this->_dataCollectionFactory->create(); } From eea93d0ce0fe351cd588b714df2037b29811abb3 Mon Sep 17 00:00:00 2001 From: Dzmitry Tabusheu <dzmitry_tabusheu@epam.com> Date: Mon, 4 Feb 2019 18:30:48 +0300 Subject: [PATCH 33/41] MAGETWO-64324: WebAPI: product 'has_options' flag not updated when options added via API - Added plugin for updating product 'has_options' flag after option save --- app/code/Magento/Catalog/Model/Product.php | 2 + .../Model/Product/Option/Repository.php | 18 ------ .../UpdateProductCustomOptionsAttributes.php | 56 +++++++++++++++++++ .../Magento/Catalog/etc/webapi_rest/di.xml | 3 + .../Magento/Catalog/etc/webapi_soap/di.xml | 3 + 5 files changed, 64 insertions(+), 18 deletions(-) create mode 100644 app/code/Magento/Catalog/Plugin/Model/Product/Option/UpdateProductCustomOptionsAttributes.php diff --git a/app/code/Magento/Catalog/Model/Product.php b/app/code/Magento/Catalog/Model/Product.php index 8ce754388fadf..5d47e85768fad 100644 --- a/app/code/Magento/Catalog/Model/Product.php +++ b/app/code/Magento/Catalog/Model/Product.php @@ -874,6 +874,8 @@ public function beforeSave() $this->cleanCache(); $this->setTypeHasOptions(false); $this->setTypeHasRequiredOptions(false); + $this->setHasOptions(false); + $this->setRequiredOptions(false); $this->getTypeInstance()->beforeSave($this); diff --git a/app/code/Magento/Catalog/Model/Product/Option/Repository.php b/app/code/Magento/Catalog/Model/Product/Option/Repository.php index b2de927254882..bb4e247de32db 100644 --- a/app/code/Magento/Catalog/Model/Product/Option/Repository.php +++ b/app/code/Magento/Catalog/Model/Product/Option/Repository.php @@ -182,7 +182,6 @@ public function save(\Magento\Catalog\Api\Data\ProductCustomOptionInterface $opt } } $option->save(); - $this->updateProductOptionsData($product, $option); return $option; } @@ -250,21 +249,4 @@ private function getHydratorPool() } return $this->hydratorPool; } - - /** - * Update product 'has_options' and 'required_options' attributes - * - * @param \Magento\Catalog\Model\Product $product - * @param \Magento\Catalog\Api\Data\ProductCustomOptionInterface $option - */ - private function updateProductOptionsData($product, $option) - { - if (!$product->getHasOptions() || - ($option->getIsRequire() && !$product->getRequiredOptions())) { - $product->setCanSaveCustomOptions(true); - $product->setOptionsSaved(true); - $product->setOptions([$option]); - $product->save(); - } - } } diff --git a/app/code/Magento/Catalog/Plugin/Model/Product/Option/UpdateProductCustomOptionsAttributes.php b/app/code/Magento/Catalog/Plugin/Model/Product/Option/UpdateProductCustomOptionsAttributes.php new file mode 100644 index 0000000000000..dd750cfbc696e --- /dev/null +++ b/app/code/Magento/Catalog/Plugin/Model/Product/Option/UpdateProductCustomOptionsAttributes.php @@ -0,0 +1,56 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Catalog\Plugin\Model\Product\Option; + +/** + * Plugin for updating product 'has_options' and 'required_options' attributes + */ +class UpdateProductCustomOptionsAttributes +{ + /** + * @var \Magento\Catalog\Api\ProductRepositoryInterface + */ + private $productRepository; + + /** + * @param \Magento\Catalog\Api\ProductRepositoryInterface $productRepository + */ + public function __construct(\Magento\Catalog\Api\ProductRepositoryInterface $productRepository) + { + $this->productRepository = $productRepository; + } + + /** + * Update product 'has_options' and 'required_options' attributes after option save + * + * @param \Magento\Catalog\Api\ProductCustomOptionRepositoryInterface $subject + * @param \Magento\Catalog\Api\Data\ProductCustomOptionInterface $option + * + * @return \Magento\Catalog\Api\Data\ProductCustomOptionInterface + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterSave( + \Magento\Catalog\Api\ProductCustomOptionRepositoryInterface $subject, + \Magento\Catalog\Api\Data\ProductCustomOptionInterface $option + ) { + $product = $this->productRepository->get($option->getProductSku()); + if (!$product->getHasOptions() || + ($option->getIsRequire() && !$product->getRequiredOptions())) { + $product->setCanSaveCustomOptions(true); + $product->setOptionsSaved(true); + $currentOptions = array_filter($product->getOptions(), function ($iOption) use ($option) { + return $option->getOptionId() != $iOption->getOptionId(); + }); + $currentOptions[] = $option; + $product->setOptions($currentOptions); + $product->save(); + } + + return $option; + } +} diff --git a/app/code/Magento/Catalog/etc/webapi_rest/di.xml b/app/code/Magento/Catalog/etc/webapi_rest/di.xml index 2a5d60222e9f8..44cdd473bf74e 100644 --- a/app/code/Magento/Catalog/etc/webapi_rest/di.xml +++ b/app/code/Magento/Catalog/etc/webapi_rest/di.xml @@ -19,4 +19,7 @@ <plugin name="get_catalog_category_product_index_table_name" type="Magento\Catalog\Model\Indexer\Category\Product\Plugin\TableResolver"/> <plugin name="get_catalog_product_price_index_table_name" type="Magento\Catalog\Model\Indexer\Product\Price\Plugin\TableResolver"/> </type> + <type name="Magento\Catalog\Api\ProductCustomOptionRepositoryInterface"> + <plugin name="updateProductCustomOptionsAttributes" type="Magento\Catalog\Plugin\Model\Product\Option\UpdateProductCustomOptionsAttributes"/> + </type> </config> diff --git a/app/code/Magento/Catalog/etc/webapi_soap/di.xml b/app/code/Magento/Catalog/etc/webapi_soap/di.xml index 2a5d60222e9f8..44cdd473bf74e 100644 --- a/app/code/Magento/Catalog/etc/webapi_soap/di.xml +++ b/app/code/Magento/Catalog/etc/webapi_soap/di.xml @@ -19,4 +19,7 @@ <plugin name="get_catalog_category_product_index_table_name" type="Magento\Catalog\Model\Indexer\Category\Product\Plugin\TableResolver"/> <plugin name="get_catalog_product_price_index_table_name" type="Magento\Catalog\Model\Indexer\Product\Price\Plugin\TableResolver"/> </type> + <type name="Magento\Catalog\Api\ProductCustomOptionRepositoryInterface"> + <plugin name="updateProductCustomOptionsAttributes" type="Magento\Catalog\Plugin\Model\Product\Option\UpdateProductCustomOptionsAttributes"/> + </type> </config> From b623211f30dd6fbbf434d0376597c07a512c5079 Mon Sep 17 00:00:00 2001 From: Yuliya Labudova <Yuliya_Labudova@epam.com> Date: Tue, 5 Feb 2019 11:26:24 +0300 Subject: [PATCH 34/41] MAGETWO-96421: Header Minicart ,Shopping cart page and Checkout page show incorrect product name - Fix static test --- app/code/Magento/Checkout/CustomerData/Cart.php | 2 ++ .../Checkout/view/frontend/web/js/view/minicart.js | 3 +++ .../Customer/Block/Adminhtml/Edit/Tab/View/Cart.php | 8 ++++---- app/code/Magento/Quote/Plugin/UpdateQuoteItemStore.php | 2 ++ 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Checkout/CustomerData/Cart.php b/app/code/Magento/Checkout/CustomerData/Cart.php index 21ba04af0ccc4..169be4cc62f01 100644 --- a/app/code/Magento/Checkout/CustomerData/Cart.php +++ b/app/code/Magento/Checkout/CustomerData/Cart.php @@ -10,6 +10,8 @@ /** * Cart source + * + * @SuppressWarnings(PHPMD.CookieAndSessionMisuse) */ class Cart extends \Magento\Framework\DataObject implements SectionSourceInterface { diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/minicart.js b/app/code/Magento/Checkout/view/frontend/web/js/view/minicart.js index 6babf0161527e..5e29fa209a641 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/view/minicart.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/view/minicart.js @@ -81,6 +81,7 @@ define([ maxItemsToDisplay: window.checkout.maxItemsToDisplay, cart: {}, + // jscs:disable requireCamelCaseOrUpperCaseIdentifiers /** * @override */ @@ -109,6 +110,8 @@ define([ return this._super(); }, + //jscs:enable requireCamelCaseOrUpperCaseIdentifiers + isLoading: ko.observable(false), initSidebar: initSidebar, diff --git a/app/code/Magento/Customer/Block/Adminhtml/Edit/Tab/View/Cart.php b/app/code/Magento/Customer/Block/Adminhtml/Edit/Tab/View/Cart.php index d0973d3baf383..1bc6bb1da3680 100644 --- a/app/code/Magento/Customer/Block/Adminhtml/Edit/Tab/View/Cart.php +++ b/app/code/Magento/Customer/Block/Adminhtml/Edit/Tab/View/Cart.php @@ -71,7 +71,7 @@ public function __construct( } /** - * {@inheritdoc} + * @inheritdoc */ protected function _construct() { @@ -106,7 +106,7 @@ protected function _prepareCollection() } /** - * {@inheritdoc} + * @inheritdoc */ protected function _prepareColumns() { @@ -144,7 +144,7 @@ protected function _prepareColumns() } /** - * {@inheritdoc} + * @inheritdoc */ public function getRowUrl($row) { @@ -152,7 +152,7 @@ public function getRowUrl($row) } /** - * {@inheritdoc} + * @inheritdoc */ public function getHeadersVisibility() { diff --git a/app/code/Magento/Quote/Plugin/UpdateQuoteItemStore.php b/app/code/Magento/Quote/Plugin/UpdateQuoteItemStore.php index bc783ce3541d2..19a7e03264d8a 100644 --- a/app/code/Magento/Quote/Plugin/UpdateQuoteItemStore.php +++ b/app/code/Magento/Quote/Plugin/UpdateQuoteItemStore.php @@ -14,6 +14,8 @@ /** * Updates quote items store id. + * + * @SuppressWarnings(PHPMD.CookieAndSessionMisuse) */ class UpdateQuoteItemStore { From d496c099df119ff1c294d0e7330ee5933fca6079 Mon Sep 17 00:00:00 2001 From: Yuliya Labudova <Yuliya_Labudova@epam.com> Date: Tue, 5 Feb 2019 13:20:04 +0300 Subject: [PATCH 35/41] MAGETWO-96852: Impossible to sort Root Categories via drag'n'drop - Stabilize mftf test. --- .../Test/Mftf/Section/AdminCategorySidebarTreeSection.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminCategorySidebarTreeSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminCategorySidebarTreeSection.xml index ef6fb99e88eed..14e714cb2b6b7 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminCategorySidebarTreeSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminCategorySidebarTreeSection.xml @@ -13,7 +13,7 @@ <element name="expandAll" type="button" selector=".tree-actions a:last-child"/> <element name="categoryTreeRoot" type="text" selector="div.x-tree-root-node>li.x-tree-node:first-of-type>div.x-tree-node-el:first-of-type" timeout="30"/> <element name="categoryInTree" type="text" selector="//a/span[contains(text(), '{{name}}')]" parameterized="true" timeout="30"/> - <element name="categoryInTreeUnderRoot" type="text" selector="//div[@class='x-tree-root-node']/li/ul/li[@class='x-tree-node']/div/a/span[contains(text(), '{{name}}')]" parameterized="true"/> + <element name="categoryInTreeUnderRoot" type="text" selector="//li/ul/li[@class='x-tree-node']/div/a/span[contains(text(), '{{name}}')]" parameterized="true"/> <element name="lastCreatedCategory" type="block" selector=".x-tree-root-ct li li:last-child" /> <element name="treeContainer" type="block" selector=".tree-holder" /> </section> From 4a5cc0c43bea5ec59a2c989b84f8898846f5dafd Mon Sep 17 00:00:00 2001 From: Yuliya Labudova <Yuliya_Labudova@epam.com> Date: Wed, 6 Feb 2019 13:09:45 +0300 Subject: [PATCH 36/41] MAGETWO-96545: Wrong calculation of invoiced items in shipment document in order with bundle product after partial invoice - Stabilize functional tets. --- .../tests/app/Magento/Bundle/Test/Fixture/Cart/Item.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Fixture/Cart/Item.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Fixture/Cart/Item.php index 9b12c467e5775..6f36c9b8fcbc9 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Fixture/Cart/Item.php +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Fixture/Cart/Item.php @@ -45,8 +45,8 @@ public function getData($key = null) : number_format($bundleOptions['assigned_products'][$optionKey]['data']['selection_price_value'], 2); $optionData = [ 'title' => $checkoutOption['title'], - 'value' => "{$qty} x {$value} {$price}", - 'sku' => "{$qty} x {$value}" + 'value' => "{$value} {$price}", + 'sku' => "{$value}" ]; $checkoutBundleOptions[$checkoutOptionKey] = $optionData; From 7de83c75ed94544c8cfd237ff4c00f6fa19d6a6e Mon Sep 17 00:00:00 2001 From: Mikalai Shostka <mikalai_shostka@epam.com> Date: Wed, 6 Feb 2019 19:04:41 +0300 Subject: [PATCH 37/41] MAGETWO-96545: Wrong calculation of invoiced items in shipment document in order with bundle product after partial invoice - Stabilize functional tets. --- .../tests/app/Magento/Bundle/Test/Fixture/Cart/Item.php | 6 ++++-- .../Bundle/Test/TestStep/CreatePartialInvoiceStep.php | 7 ++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Fixture/Cart/Item.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Fixture/Cart/Item.php index 6f36c9b8fcbc9..b76bd74e71ce6 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Fixture/Cart/Item.php +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Fixture/Cart/Item.php @@ -45,8 +45,10 @@ public function getData($key = null) : number_format($bundleOptions['assigned_products'][$optionKey]['data']['selection_price_value'], 2); $optionData = [ 'title' => $checkoutOption['title'], - 'value' => "{$value} {$price}", - 'sku' => "{$value}" + 'value' => "{$qty} x {$value} {$price}", + 'sku' => "{$qty} x {$value}", + 'partialInvoiceValue' => "{$value} {$price}", + 'partialInvoiceSku' => "{$value}" ]; $checkoutBundleOptions[$checkoutOptionKey] = $optionData; diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/TestStep/CreatePartialInvoiceStep.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/TestStep/CreatePartialInvoiceStep.php index 4f6d46dc7842d..34bfde2809461 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/TestStep/CreatePartialInvoiceStep.php +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/TestStep/CreatePartialInvoiceStep.php @@ -20,6 +20,11 @@ class CreatePartialInvoiceStep extends \Magento\Sales\Test\TestStep\CreateInvoic protected function getItems() { $items = parent::getItems(); - return $items[0]->getData()['options']; + $items = $items[0]->getData()['options']; + foreach ($items as &$item) { + $item['value'] = $item['partialInvoiceValue']; + $item['sku'] = $item['partialInvoiceSku']; + } + return $items; } } From 22b4e3fd30fb0ba0a429e65e721ae008c2e748dd Mon Sep 17 00:00:00 2001 From: Yuliya Labudova <Yuliya_Labudova@epam.com> Date: Wed, 6 Feb 2019 20:40:34 +0300 Subject: [PATCH 38/41] MAGETWO-96545: Wrong calculation of invoiced items in shipment document in order with bundle product after partial invoice - Stabilize functional test --- .../tests/app/Magento/Bundle/Test/Fixture/Cart/Item.php | 4 +--- .../Bundle/Test/TestStep/CreatePartialInvoiceStep.php | 7 +------ 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Fixture/Cart/Item.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Fixture/Cart/Item.php index b76bd74e71ce6..4d6d06ac6e625 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Fixture/Cart/Item.php +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Fixture/Cart/Item.php @@ -46,9 +46,7 @@ public function getData($key = null) $optionData = [ 'title' => $checkoutOption['title'], 'value' => "{$qty} x {$value} {$price}", - 'sku' => "{$qty} x {$value}", - 'partialInvoiceValue' => "{$value} {$price}", - 'partialInvoiceSku' => "{$value}" + 'sku' => "{$value}" ]; $checkoutBundleOptions[$checkoutOptionKey] = $optionData; diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/TestStep/CreatePartialInvoiceStep.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/TestStep/CreatePartialInvoiceStep.php index 34bfde2809461..4f6d46dc7842d 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/TestStep/CreatePartialInvoiceStep.php +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/TestStep/CreatePartialInvoiceStep.php @@ -20,11 +20,6 @@ class CreatePartialInvoiceStep extends \Magento\Sales\Test\TestStep\CreateInvoic protected function getItems() { $items = parent::getItems(); - $items = $items[0]->getData()['options']; - foreach ($items as &$item) { - $item['value'] = $item['partialInvoiceValue']; - $item['sku'] = $item['partialInvoiceSku']; - } - return $items; + return $items[0]->getData()['options']; } } From 47df547da1d9de7db42d0dada79437a9c0f0bd1f Mon Sep 17 00:00:00 2001 From: Yauhen_Lyskavets <yauhen_lyskavets@epam.com> Date: Thu, 7 Feb 2019 13:28:28 +0300 Subject: [PATCH 39/41] MAGETWO-95186: [2.3] Incorrect table rates shipping charge at check out with cart price rule - Health check test fix. --- .../Magento/OfflineShipping/Model/Carrier/Tablerate.php | 6 ++---- .../Setup/Patch/Data/UpdateShippingTablerate.php | 4 ++-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/OfflineShipping/Model/Carrier/Tablerate.php b/app/code/Magento/OfflineShipping/Model/Carrier/Tablerate.php index 6a4ac8b67e06a..373d64afc8cc3 100644 --- a/app/code/Magento/OfflineShipping/Model/Carrier/Tablerate.php +++ b/app/code/Magento/OfflineShipping/Model/Carrier/Tablerate.php @@ -18,8 +18,6 @@ class Tablerate extends \Magento\Shipping\Model\Carrier\AbstractCarrier implements \Magento\Shipping\Model\Carrier\CarrierInterface { - const CONDITION_CODE_PACKAGE_VALUE_WITH_DISCOUNT = 'package_value_with_discount'; - /** * @var string */ @@ -229,12 +227,12 @@ public function getCode($type, $code = '') $codes = [ 'condition_name' => [ 'package_weight' => __('Weight vs. Destination'), - self::CONDITION_CODE_PACKAGE_VALUE_WITH_DISCOUNT => __('Price vs. Destination'), + 'package_value_with_discount' => __('Price vs. Destination'), 'package_qty' => __('# of Items vs. Destination'), ], 'condition_name_short' => [ 'package_weight' => __('Weight (and above)'), - self::CONDITION_CODE_PACKAGE_VALUE_WITH_DISCOUNT => __('Order Subtotal (and above)'), + 'package_value_with_discount' => __('Order Subtotal (and above)'), 'package_qty' => __('# of Items (and above)'), ], ]; diff --git a/app/code/Magento/OfflineShipping/Setup/Patch/Data/UpdateShippingTablerate.php b/app/code/Magento/OfflineShipping/Setup/Patch/Data/UpdateShippingTablerate.php index 3cfc752fdcf05..070105846fdd8 100644 --- a/app/code/Magento/OfflineShipping/Setup/Patch/Data/UpdateShippingTablerate.php +++ b/app/code/Magento/OfflineShipping/Setup/Patch/Data/UpdateShippingTablerate.php @@ -39,12 +39,12 @@ public function apply() $connection = $this->moduleDataSetup->getConnection(); $connection->update( $this->moduleDataSetup->getTable('shipping_tablerate'), - ['condition_name' => Tablerate::CONDITION_CODE_PACKAGE_VALUE_WITH_DISCOUNT], + ['condition_name' => 'package_value_with_discount'], [new \Zend_Db_Expr('condition_name = \'package_value\'')] ); $connection->update( $this->moduleDataSetup->getTable('core_config_data'), - ['value' => Tablerate::CONDITION_CODE_PACKAGE_VALUE_WITH_DISCOUNT], + ['value' => 'package_value_with_discount'], [ new \Zend_Db_Expr('value = \'package_value\''), new \Zend_Db_Expr('path = \'carriers/tablerate/condition_name\'') From fe34767e919bd450c31bcb574da3a5c6c9c63d4a Mon Sep 17 00:00:00 2001 From: Vital_Pantsialeyeu <vital_pantsialeyeu@epam.com> Date: Fri, 8 Feb 2019 23:19:18 +0300 Subject: [PATCH 40/41] MAGETWO-96545: Wrong calculation of invoiced items in shipment document in order with bundle product after partial invoice - Partial invoice feature has been removed for bundled products when it should be shipped together; --- .../Adminhtml/Sales/Order/Items/Renderer.php | 18 ------------------ .../sales/invoice/create/items/renderer.phtml | 3 ++- 2 files changed, 2 insertions(+), 19 deletions(-) diff --git a/app/code/Magento/Bundle/Block/Adminhtml/Sales/Order/Items/Renderer.php b/app/code/Magento/Bundle/Block/Adminhtml/Sales/Order/Items/Renderer.php index c8dd23fe120c9..82a0086ad67ec 100644 --- a/app/code/Magento/Bundle/Block/Adminhtml/Sales/Order/Items/Renderer.php +++ b/app/code/Magento/Bundle/Block/Adminhtml/Sales/Order/Items/Renderer.php @@ -271,22 +271,4 @@ public function canShowPriceInfo($item) } return false; } - - /** - * Check if this iten should be shipped together - * - * @param object $item - * @return bool - */ - public function isShipTogether($item) - { - $orderItem = $item->getOrderItem(); - if ($orderItem->getProductType() == \Magento\Catalog\Model\Product\Type::TYPE_BUNDLE) { - $shipTogether = !$orderItem->isShipSeparately(); - } else { - $shipTogether = !$orderItem->getParentItem()->isShipSeparately(); - } - - return $shipTogether; - } } diff --git a/app/code/Magento/Bundle/view/adminhtml/templates/sales/invoice/create/items/renderer.phtml b/app/code/Magento/Bundle/view/adminhtml/templates/sales/invoice/create/items/renderer.phtml index 6437c578caa0f..12da960a9c6cf 100644 --- a/app/code/Magento/Bundle/view/adminhtml/templates/sales/invoice/create/items/renderer.phtml +++ b/app/code/Magento/Bundle/view/adminhtml/templates/sales/invoice/create/items/renderer.phtml @@ -29,7 +29,8 @@ <?php foreach ($items as $_item): ?> <?php - $shipTogether = $block->isShipTogether($_item); + $shipTogether = ($_item->getOrderItem()->getProductType() == \Magento\Catalog\Model\Product\Type::TYPE_BUNDLE) ? + !$_item->getOrderItem()->isShipSeparately() : !$_item->getOrderItem()->getParentItem()->isShipSeparately() ?> <?php $block->setPriceDataObject($_item) ?> <?php if ($_item->getOrderItem()->getParentItem()): ?> From 7b2e71d5efa55d62e637be76ee8629c347e95023 Mon Sep 17 00:00:00 2001 From: Vital_Pantsialeyeu <vital_pantsialeyeu@epam.com> Date: Sun, 10 Feb 2019 02:58:35 +0300 Subject: [PATCH 41/41] MAGETWO-95186: [2.3] Incorrect table rates shipping charge at check out with cart price rule - check if there is shipping rate --- .../Magento/Checkout/Model/PaymentInformationManagement.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Checkout/Model/PaymentInformationManagement.php b/app/code/Magento/Checkout/Model/PaymentInformationManagement.php index d2bd680aa38f3..e0de45a3f0dea 100644 --- a/app/code/Magento/Checkout/Model/PaymentInformationManagement.php +++ b/app/code/Magento/Checkout/Model/PaymentInformationManagement.php @@ -118,7 +118,9 @@ public function savePaymentInformation( $shippingAddress = $quote->getShippingAddress(); if ($shippingAddress && $shippingAddress->getShippingMethod()) { $shippingRate = $shippingAddress->getShippingRateByCode($shippingAddress->getShippingMethod()); - $shippingAddress->setLimitCarrier($shippingRate->getCarrier()); + $shippingAddress->setLimitCarrier( + $shippingRate ? $shippingRate->getCarrier() : $shippingAddress->getShippingMethod() + ); } } $this->paymentMethodManagement->set($cartId, $paymentMethod);