diff --git a/app/code/Magento/Backend/Block/Widget/Form.php b/app/code/Magento/Backend/Block/Widget/Form.php index 02ef3b1135009ebace6542173bfbf6a6ce6f701f..3f258a48ca38361aa96e4c7bf6ce4219d319079c 100644 --- a/app/code/Magento/Backend/Block/Widget/Form.php +++ b/app/code/Magento/Backend/Block/Widget/Form.php @@ -187,7 +187,7 @@ class Form extends \Magento\Backend\Block\Widget $fieldType, [ 'name' => $attribute->getAttributeCode(), - 'label' => $attribute->getFrontend()->getLabel(), + 'label' => $attribute->getFrontend()->getLocalizedLabel(), 'class' => $attribute->getFrontend()->getClass(), 'required' => $attribute->getIsRequired(), 'note' => $attribute->getNote() diff --git a/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/System/Account/SaveTest.php b/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/System/Account/SaveTest.php index b63c4f1e1a5ad33a38144569dba89dcda1892fa7..b36c9a59ab9d42e65bb20e0d337b9bf1f53ccd2d 100644 --- a/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/System/Account/SaveTest.php +++ b/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/System/Account/SaveTest.php @@ -9,88 +9,105 @@ namespace Magento\Backend\Test\Unit\Controller\Adminhtml\System\Account; class SaveTest extends \PHPUnit_Framework_TestCase { - /** @var \Magento\Backend\Controller\Adminhtml\System\Account */ - protected $_controller; - - /** @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\App\RequestInterface */ - protected $_requestMock; - - /** @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\App\ResponseInterface */ - protected $_responseMock; - - /** @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\ObjectManager\ObjectManager */ - protected $_objectManagerMock; - - /** @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\Message\ManagerInterface */ - protected $_messagesMock; - - /** @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Backend\Helper\Data */ - protected $_helperMock; - - /** @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Backend\Model\Auth\Session */ - protected $_authSessionMock; - - /** @var \PHPUnit_Framework_MockObject_MockObject|\Magento\User\Model\User */ - protected $_userMock; - - /** @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\Validator\locale */ - protected $_validatorMock; - - /** @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Backend\Model\Locale\Manager */ - protected $_managerMock; - - /** @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\TranslateInterface */ - protected $_translatorMock; + /** + * @var \Magento\Backend\Controller\Adminhtml\System\Account\Save + */ + protected $controller; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\App\RequestInterface + */ + protected $requestMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\App\ResponseInterface + */ + protected $responseMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\ObjectManager\ObjectManager + */ + protected $objectManagerMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\Message\ManagerInterface + */ + protected $messagesMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Backend\Helper\Data + */ + protected $helperMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Backend\Model\Auth\Session + */ + protected $authSessionMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\User\Model\User + */ + protected $userMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\Validator\locale + */ + protected $validatorMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Backend\Model\Locale\Manager + */ + protected $managerMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\TranslateInterface + */ + protected $translatorMock; protected function setUp() { - $this->_requestMock = $this->getMockBuilder('Magento\Framework\App\Request\Http') + $frontControllerMock = $this->getMockBuilder('Magento\Framework\App\FrontController') + ->disableOriginalConstructor() + ->getMock(); + + $this->requestMock = $this->getMockBuilder('Magento\Framework\App\Request\Http') ->disableOriginalConstructor()->setMethods(['getOriginalPathInfo']) ->getMock(); - $this->_responseMock = $this->getMockBuilder('Magento\Framework\App\Response\Http') + $this->responseMock = $this->getMockBuilder('Magento\Framework\App\Response\Http') ->disableOriginalConstructor() ->setMethods([]) ->getMock(); - $this->_objectManagerMock = $this->getMockBuilder('Magento\Framework\ObjectManager\ObjectManager') + $this->objectManagerMock = $this->getMockBuilder('Magento\Framework\ObjectManager\ObjectManager') ->disableOriginalConstructor() ->setMethods(['get', 'create']) ->getMock(); - $frontControllerMock = $this->getMockBuilder('Magento\Framework\App\FrontController') - ->disableOriginalConstructor() - ->getMock(); - - $this->_helperMock = $this->getMockBuilder('Magento\Backend\Helper\Data') + $this->helperMock = $this->getMockBuilder('Magento\Backend\Helper\Data') ->disableOriginalConstructor() ->setMethods(['getUrl']) ->getMock(); - $this->_messagesMock = $this->getMockBuilder('Magento\Framework\Message\Manager') + $this->messagesMock = $this->getMockBuilder('Magento\Framework\Message\Manager') ->disableOriginalConstructor() ->setMethods(['addSuccess']) ->getMockForAbstractClass(); - - $this->_authSessionMock = $this->getMockBuilder('Magento\Backend\Model\Auth\Session') + $this->authSessionMock = $this->getMockBuilder('Magento\Backend\Model\Auth\Session') ->disableOriginalConstructor() ->setMethods(['getUser']) ->getMock(); - - $this->_userMock = $this->getMockBuilder('Magento\User\Model\User') + $this->userMock = $this->getMockBuilder('Magento\User\Model\User') ->disableOriginalConstructor() ->setMethods( ['load', 'save', 'sendPasswordResetNotificationEmail', 'verifyIdentity', '__sleep', '__wakeup'] ) ->getMock(); - - $this->_validatorMock = $this->getMockBuilder('Magento\Framework\Validator\Locale') + $this->validatorMock = $this->getMockBuilder('Magento\Framework\Validator\Locale') ->disableOriginalConstructor() ->setMethods(['isValid']) ->getMock(); - - $this->_managerMock = $this->getMockBuilder('Magento\Backend\Model\Locale\Manager') + $this->managerMock = $this->getMockBuilder('Magento\Backend\Model\Locale\Manager') ->disableOriginalConstructor() ->setMethods(['switchBackendInterfaceLocale']) ->getMock(); - - $this->_translatorMock = $this->getMockBuilder('Magento\Framework\TranslateInterface') + $this->translatorMock = $this->getMockBuilder('Magento\Framework\TranslateInterface') ->disableOriginalConstructor() ->getMock(); @@ -107,19 +124,19 @@ class SaveTest extends \PHPUnit_Framework_TestCase ->willReturn($resultRedirect); $contextMock = $this->getMock('Magento\Backend\App\Action\Context', [], [], '', false); - $contextMock->expects($this->any())->method('getRequest')->willReturn($this->_requestMock); - $contextMock->expects($this->any())->method('getResponse')->willReturn($this->_responseMock); - $contextMock->expects($this->any())->method('getObjectManager')->willReturn($this->_objectManagerMock); + $contextMock->expects($this->any())->method('getRequest')->willReturn($this->requestMock); + $contextMock->expects($this->any())->method('getResponse')->willReturn($this->responseMock); + $contextMock->expects($this->any())->method('getObjectManager')->willReturn($this->objectManagerMock); $contextMock->expects($this->any())->method('getFrontController')->willReturn($frontControllerMock); - $contextMock->expects($this->any())->method('getHelper')->willReturn($this->_helperMock); - $contextMock->expects($this->any())->method('getMessageManager')->willReturn($this->_messagesMock); - $contextMock->expects($this->any())->method('getTranslator')->willReturn($this->_translatorMock); + $contextMock->expects($this->any())->method('getHelper')->willReturn($this->helperMock); + $contextMock->expects($this->any())->method('getMessageManager')->willReturn($this->messagesMock); + $contextMock->expects($this->any())->method('getTranslator')->willReturn($this->translatorMock); $contextMock->expects($this->once())->method('getResultFactory')->willReturn($resultFactory); $args = ['context' => $contextMock]; $testHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); - $this->_controller = $testHelper->getObject('Magento\Backend\Controller\Adminhtml\System\Account\Save', $args); + $this->controller = $testHelper->getObject('Magento\Backend\Controller\Adminhtml\System\Account\Save', $args); } public function testSaveAction() @@ -136,69 +153,50 @@ class SaveTest extends \PHPUnit_Framework_TestCase \Magento\Backend\Block\System\Account\Edit\Form::IDENTITY_VERIFICATION_PASSWORD_FIELD => 'current_password', ]; - $testedMessage = 'You saved the account.'; - - $this->_authSessionMock->expects($this->any())->method('getUser')->will($this->returnValue($this->_userMock)); - - $this->_userMock->expects($this->any())->method('load')->will($this->returnSelf()); - $this->_validatorMock->expects( - $this->once() - )->method( - 'isValid' - )->with( - $this->equalTo($requestParams['interface_locale']) - )->will( - $this->returnValue(true) - ); - $this->_managerMock->expects($this->any())->method('switchBackendInterfaceLocale'); - - $this->_objectManagerMock->expects( - $this->at(0) - )->method( - 'get' - )->with( - $this->equalTo('Magento\Backend\Model\Auth\Session') - )->will( - $this->returnValue($this->_authSessionMock) - ); - $this->_objectManagerMock->expects( - $this->at(1) - )->method( - 'create' - )->with( - $this->equalTo('Magento\User\Model\User') - )->will( - $this->returnValue($this->_userMock) - ); - $this->_objectManagerMock->expects( - $this->at(2) - )->method( - 'get' - )->with( - $this->equalTo('Magento\Framework\Validator\Locale') - )->will( - $this->returnValue($this->_validatorMock) - ); - $this->_objectManagerMock->expects( - $this->at(3) - )->method( - 'get' - )->with( - $this->equalTo('Magento\Backend\Model\Locale\Manager') - )->will( - $this->returnValue($this->_managerMock) - ); - - $this->_userMock->setUserId($userId); - - $this->_userMock->expects($this->once())->method('save'); - $this->_userMock->expects($this->once())->method('verifyIdentity')->will($this->returnValue(true)); - $this->_userMock->expects($this->once())->method('sendPasswordResetNotificationEmail'); - - $this->_requestMock->setParams($requestParams); - - $this->_messagesMock->expects($this->once())->method('addSuccess')->with($this->equalTo($testedMessage)); - - $this->_controller->execute(); + $testedMessage = __('You saved the account.'); + + $this->authSessionMock->expects($this->any()) + ->method('getUser') + ->willReturn($this->userMock); + $this->userMock->expects($this->any()) + ->method('load') + ->will($this->returnSelf()); + $this->validatorMock->expects($this->once()) + ->method('isValid') + ->with($this->equalTo($requestParams['interface_locale'])) + ->willReturn(true); + $this->managerMock->expects($this->any()) + ->method('switchBackendInterfaceLocale'); + $this->objectManagerMock->expects($this->at(0)) + ->method('get') + ->with($this->equalTo('Magento\Backend\Model\Auth\Session')) + ->willReturn($this->authSessionMock); + $this->objectManagerMock->expects($this->at(1)) + ->method('create') + ->with($this->equalTo('Magento\User\Model\User')) + ->willReturn($this->userMock); + $this->objectManagerMock->expects($this->at(2)) + ->method('get') + ->with($this->equalTo('Magento\Framework\Validator\Locale')) + ->willReturn($this->validatorMock); + $this->objectManagerMock->expects($this->at(3)) + ->method('get') + ->with($this->equalTo('Magento\Backend\Model\Locale\Manager')) + ->willReturn($this->managerMock); + $this->userMock->expects($this->once()) + ->method('save'); + $this->userMock->expects($this->once()) + ->method('verifyIdentity') + ->willReturn(true); + $this->userMock->expects($this->once()) + ->method('sendPasswordResetNotificationEmail'); + $this->messagesMock->expects($this->once()) + ->method('addSuccess') + ->with($this->equalTo($testedMessage)); + + $this->userMock->setUserId($userId); + $this->requestMock->setParams($requestParams); + + $this->controller->execute(); } } diff --git a/app/code/Magento/Backend/i18n/en_US.csv b/app/code/Magento/Backend/i18n/en_US.csv index 7c6b4dab5992d69ca9214ebabc18c6b9e4e6eca3..82284a014c7e3cd704ee91ecec88f82e7524693a 100644 --- a/app/code/Magento/Backend/i18n/en_US.csv +++ b/app/code/Magento/Backend/i18n/en_US.csv @@ -606,6 +606,12 @@ Tags,Tags Options,Options "Magento Admin","Magento Admin" "Community Edition","Community Edition" +"Last Orders","Last Orders" +"Last Search Terms","Last Search Terms" +"Top Search Terms","Top Search Terms" +"Your Password","Your Password" +"You saved the account.","You saved the account." +"Current User Identity Verification","Current User Identity Verification" Marketing,Marketing Communications,Communications "SEO & Search","SEO & Search" diff --git a/app/code/Magento/Catalog/Api/Data/ProductWebsiteLinkInterface.php b/app/code/Magento/Catalog/Api/Data/ProductWebsiteLinkInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..08c8f6b97058335041348bbd57224133fbeb0a9b --- /dev/null +++ b/app/code/Magento/Catalog/Api/Data/ProductWebsiteLinkInterface.php @@ -0,0 +1,39 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Catalog\Api\Data; + +/** + * @api + */ +interface ProductWebsiteLinkInterface +{ + /** + * @return string + */ + public function getSku(); + + /** + * @param string $sku + * @return $this + */ + public function setSku($sku); + + /** + * Get website ids + * + * @return int + */ + public function getWebsiteId(); + + /** + * Set website id + * + * @param int $websiteId + * @return $this + */ + public function setWebsiteId($websiteId); +} diff --git a/app/code/Magento/Catalog/Api/ProductWebsiteLinkRepositoryInterface.php b/app/code/Magento/Catalog/Api/ProductWebsiteLinkRepositoryInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..55e875c2cfd37f951ba45ad251615c74b66700e8 --- /dev/null +++ b/app/code/Magento/Catalog/Api/ProductWebsiteLinkRepositoryInterface.php @@ -0,0 +1,42 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Catalog\Api; + +interface ProductWebsiteLinkRepositoryInterface +{ + /** + * Assign a product to the website + * + * @param \Magento\Catalog\Api\Data\ProductWebsiteLinkInterface $productWebsiteLink + * @return bool will returned True if website successfully assigned to product + * + * @throws \Magento\Framework\Exception\CouldNotSaveException + * @throws \Magento\Framework\Exception\InputException + */ + public function save(Data\ProductWebsiteLinkInterface $productWebsiteLink); + + /** + * Remove the website assignment from the product + * + * @param \Magento\Catalog\Api\Data\ProductWebsiteLinkInterface $productWebsiteLink + * @return bool will returned True if website successfully unassigned from product + * + * @throws \Magento\Framework\Exception\CouldNotSaveException + */ + public function delete(Data\ProductWebsiteLinkInterface $productWebsiteLink); + + /** + * Remove the website assignment from the product by product sku + * + * @param string $sku + * @param int $websiteId + * @return bool will returned True if website successfully unassigned from product + * + * @throws \Magento\Framework\Exception\CouldNotSaveException + */ + public function deleteById($sku, $websiteId); +} diff --git a/app/code/Magento/Catalog/Model/ProductWebsiteLink.php b/app/code/Magento/Catalog/Model/ProductWebsiteLink.php new file mode 100644 index 0000000000000000000000000000000000000000..614cd579281f1cfe5317299ff89b1821fe3bc81a --- /dev/null +++ b/app/code/Magento/Catalog/Model/ProductWebsiteLink.php @@ -0,0 +1,51 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Catalog\Model; + +class ProductWebsiteLink extends \Magento\Framework\Api\AbstractSimpleObject implements + \Magento\Catalog\Api\Data\ProductWebsiteLinkInterface +{ + /**#@+ + * Field names + */ + const KEY_SKU = 'sku'; + const WEBSITE_ID = 'website_id'; + /**#@-*/ + + /** + * {@inheritdoc} + */ + public function getSku() + { + return $this->_get(self::KEY_SKU); + } + + /** + * {@inheritdoc} + */ + public function getWebsiteId() + { + return $this->_get(self::WEBSITE_ID); + } + + /** + * @param string $sku + * @return $this + */ + public function setSku($sku) + { + return $this->setData(self::KEY_SKU, $sku); + } + + /** + * {@inheritdoc} + */ + public function setWebsiteId($websiteId) + { + return $this->setData(self::WEBSITE_ID, $websiteId); + } +} diff --git a/app/code/Magento/Catalog/Model/ProductWebsiteLinkRepository.php b/app/code/Magento/Catalog/Model/ProductWebsiteLinkRepository.php new file mode 100644 index 0000000000000000000000000000000000000000..4e24fc5ef9c9b7ead4c51cb2a0d3bd347f7767ea --- /dev/null +++ b/app/code/Magento/Catalog/Model/ProductWebsiteLinkRepository.php @@ -0,0 +1,84 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Catalog\Model; + +use Magento\Framework\Exception\InputException; +use Magento\Framework\Exception\CouldNotSaveException; +use Magento\Catalog\Api\Data\ProductWebsiteLinkInterface; + +class ProductWebsiteLinkRepository implements \Magento\Catalog\Api\ProductWebsiteLinkRepositoryInterface +{ + /** + * @var \Magento\Catalog\Api\ProductRepositoryInterface + */ + protected $productRepository; + + /** + * @param \Magento\Catalog\Api\ProductRepositoryInterface $productRepository + */ + public function __construct( + \Magento\Catalog\Api\ProductRepositoryInterface $productRepository + ) { + $this->productRepository = $productRepository; + } + + /** + * {@inheritdoc} + */ + public function save(ProductWebsiteLinkInterface $productWebsiteLink) + { + if (!$productWebsiteLink->getWebsiteId()) { + throw new InputException(__('There are not websites for assign to product')); + } + $product = $this->productRepository->get($productWebsiteLink->getSku()); + $product->setWebsiteIds(array_merge($product->getWebsiteIds(), [$productWebsiteLink->getWebsiteId()])); + try { + $product->save(); + } catch (\Exception $e) { + throw new CouldNotSaveException( + __( + 'Could not assign product "%1" to websites "%2"', + $product->getId(), + $productWebsiteLink->getWebsiteId() + ), + $e + ); + } + return true; + } + + /** + * {@inheritdoc} + */ + public function delete(ProductWebsiteLinkInterface $productLink) + { + return $this->deleteById($productLink->getSku(), $productLink->getSku()); + } + + /** + * {@inheritdoc} + */ + public function deleteById($sku, $websiteId) + { + $product = $this->productRepository->get($sku); + $product->setWebsiteIds(array_diff($product->getWebsiteIds(), [$websiteId])); + + try { + $product->save(); + } catch (\Exception $e) { + throw new CouldNotSaveException( + __( + 'Could not save product "%1" with websites %2', + $product->getId(), + implode(', ', $product->getWebsiteIds()) + ), + $e + ); + } + return true; + } +} diff --git a/app/code/Magento/Catalog/etc/di.xml b/app/code/Magento/Catalog/etc/di.xml index 7bd251153314e365e0b9ed8c27de9939ac8f5a8a..3ffee9360469843e9db628e2ce7fec5b0316c97c 100644 --- a/app/code/Magento/Catalog/etc/di.xml +++ b/app/code/Magento/Catalog/etc/di.xml @@ -459,6 +459,8 @@ <preference for="Magento\Catalog\Api\ProductLinkManagementInterface" type="Magento\Catalog\Model\ProductLink\Management" /> <preference for="Magento\Catalog\Api\Data\ProductLinkInterface" type="Magento\Catalog\Model\ProductLink\Link" /> <preference for="\Magento\Catalog\Api\CategoryLinkManagementInterface" type="\Magento\Catalog\Model\CategoryLinkManagement" /> + <preference for="Magento\Catalog\Api\Data\ProductWebsiteLinkInterface" type="Magento\Catalog\Model\ProductWebsiteLink" /> + <preference for="Magento\Catalog\Api\ProductWebsiteLinkRepositoryInterface" type="Magento\Catalog\Model\ProductWebsiteLinkRepository" /> <preference for="\Magento\Catalog\Api\CategoryLinkRepositoryInterface" type="\Magento\Catalog\Model\CategoryLinkRepository" /> <preference for="Magento\Catalog\Api\Data\ProductCustomOptionInterface" type="Magento\Catalog\Model\Product\Option" /> <preference for="Magento\Catalog\Api\ProductCustomOptionRepositoryInterface" type="\Magento\Catalog\Model\Product\Option\Repository" /> diff --git a/app/code/Magento/Catalog/etc/webapi.xml b/app/code/Magento/Catalog/etc/webapi.xml index 24492cbc019b977e402a81c66b1f2f81163b2a2a..d447b748a9ef4139f8777627c08274165383599c 100644 --- a/app/code/Magento/Catalog/etc/webapi.xml +++ b/app/code/Magento/Catalog/etc/webapi.xml @@ -385,4 +385,24 @@ <resource ref="Magento_Catalog::categories" /> </resources> </route> + + <!-- Product Website Links --> + <route url="/V1/products/:sku/websites" method="POST"> + <service class="Magento\Catalog\Api\ProductWebsiteLinkRepositoryInterface" method="save" /> + <resources> + <resource ref="Magento_Catalog::products" /> + </resources> + </route> + <route url="/V1/products/:sku/websites" method="PUT"> + <service class="Magento\Catalog\Api\ProductWebsiteLinkRepositoryInterface" method="save" /> + <resources> + <resource ref="Magento_Catalog::products" /> + </resources> + </route> + <route url="/V1/products/:sku/websites/:websiteId" method="DELETE"> + <service class="Magento\Catalog\Api\ProductWebsiteLinkRepositoryInterface" method="deleteById" /> + <resources> + <resource ref="Magento_Catalog::products" /> + </resources> + </route> </routes> diff --git a/app/code/Magento/Catalog/i18n/en_US.csv b/app/code/Magento/Catalog/i18n/en_US.csv index 87bcbd26408da6c7cf300b6a6af1bbe718158aad..b692356a48f6e8fcbc7090a36f1de08bd452636e 100644 --- a/app/code/Magento/Catalog/i18n/en_US.csv +++ b/app/code/Magento/Catalog/i18n/en_US.csv @@ -633,3 +633,24 @@ Set,Set none,none Overview,Overview "Field ""%1"" was not found in DO ""%2"".","Field ""%1"" was not found in DO ""%2""." +"Is Active","Is Active" +"URL Key","URL Key" +"Description","Description" +"Image","Image" +"Page Title","Page Title" +"Meta Keywords","Meta Keywords" +"Meta Description","Meta Description" +"Include in Navigation Menu","Include in Navigation Menu" +"Display Mode","Display Mode" +"CMS Block","CMS Block" +"Is Anchor","Is Anchor" +"Available Product Listing Sort By","Available Product Listing Sort By" +"Default Product Listing Sort By","Default Product Listing Sort By" +"Layered Navigation Price Step","Layered Navigation Price Step" +"Use Parent Category Settings","Use Parent Category Settings" +"Apply To Products","Apply To Products" +"Active From","Active From" +"Active To","Active To" +"Page Layout","Page Layout" +"Custom Layout Update","Custom Layout Update" +"Name","Name" diff --git a/app/code/Magento/CatalogRule/Model/Rule.php b/app/code/Magento/CatalogRule/Model/Rule.php index 66f3affdcea910662767f599d9bf3767194a7ba0..dcd36cfaf3086a4b739ada152ab23ee06bf8839d 100644 --- a/app/code/Magento/CatalogRule/Model/Rule.php +++ b/app/code/Magento/CatalogRule/Model/Rule.php @@ -342,6 +342,10 @@ class Rule extends \Magento\Rule\Model\AbstractModel $map = []; $websites = $this->_storeManager->getWebsites(true); foreach ($websites as $website) { + // Continue if website has no store to be able to create catalog rule for website without store + if ($website->getDefaultStore() === null) { + continue; + } $map[$website->getId()] = $website->getDefaultStore()->getId(); } return $map; diff --git a/app/code/Magento/CatalogUrlRewrite/Model/CategoryUrlPathGenerator.php b/app/code/Magento/CatalogUrlRewrite/Model/CategoryUrlPathGenerator.php index d978d726a58c7c889309cd4d0d21402124e2eee7..69b955cf78a3927f3da912ca61f34c1c83f82ecf 100644 --- a/app/code/Magento/CatalogUrlRewrite/Model/CategoryUrlPathGenerator.php +++ b/app/code/Magento/CatalogUrlRewrite/Model/CategoryUrlPathGenerator.php @@ -73,7 +73,9 @@ class CategoryUrlPathGenerator return $category->getUrlPath(); } if ($this->isNeedToGenerateUrlPathForParent($category)) { - $parentPath = $this->getUrlPath($this->categoryRepository->get($category->getParentId())); + $parentPath = $this->getUrlPath( + $this->categoryRepository->get($category->getParentId(), $category->getStoreId()) + ); $path = $parentPath === '' ? $path : $parentPath . '/' . $path; } return $path; @@ -141,7 +143,7 @@ class CategoryUrlPathGenerator * @param \Magento\Catalog\Model\Category $category * @return string */ - public function generateUrlKey($category) + public function getUrlKey($category) { $urlKey = $category->getUrlKey(); return $category->formatUrlKey($urlKey === '' || $urlKey === null ? $category->getName() : $urlKey); diff --git a/app/code/Magento/CatalogUrlRewrite/Model/ProductUrlPathGenerator.php b/app/code/Magento/CatalogUrlRewrite/Model/ProductUrlPathGenerator.php index 90e65b9094f5e01163510cbfea5e8db9ea8cd2f1..7656610422d4a4084b6ff56d3cbe23224d9aed3e 100644 --- a/app/code/Magento/CatalogUrlRewrite/Model/ProductUrlPathGenerator.php +++ b/app/code/Magento/CatalogUrlRewrite/Model/ProductUrlPathGenerator.php @@ -114,7 +114,7 @@ class ProductUrlPathGenerator * @param \Magento\Catalog\Model\Product $product * @return string */ - public function generateUrlKey($product) + public function getUrlKey($product) { return $product->getUrlKey() === false ? false : $this->prepareProductUrlKey($product); } diff --git a/app/code/Magento/CatalogUrlRewrite/Observer/CategoryUrlPathAutogeneratorObserver.php b/app/code/Magento/CatalogUrlRewrite/Observer/CategoryUrlPathAutogeneratorObserver.php index e72b5df170485db13ce1e9d931f0bb48552d4163..1a903432cc1eee43fbf22919b81c1a004ac20b97 100644 --- a/app/code/Magento/CatalogUrlRewrite/Observer/CategoryUrlPathAutogeneratorObserver.php +++ b/app/code/Magento/CatalogUrlRewrite/Observer/CategoryUrlPathAutogeneratorObserver.php @@ -7,9 +7,11 @@ namespace Magento\CatalogUrlRewrite\Observer; use Magento\Catalog\Model\Category; use Magento\CatalogUrlRewrite\Model\CategoryUrlPathGenerator; +use Magento\CatalogUrlRewrite\Service\V1\StoreViewService; use Magento\Framework\Event\Observer; use Magento\CatalogUrlRewrite\Model\Category\ChildrenCategoriesProvider; use Magento\Framework\Event\ObserverInterface; +use Magento\Store\Model\Store; class CategoryUrlPathAutogeneratorObserver implements ObserverInterface { @@ -19,16 +21,22 @@ class CategoryUrlPathAutogeneratorObserver implements ObserverInterface /** @var \Magento\CatalogUrlRewrite\Model\Category\ChildrenCategoriesProvider */ protected $childrenCategoriesProvider; + /** @var StoreViewService */ + protected $storeViewService; + /** * @param CategoryUrlPathGenerator $categoryUrlPathGenerator * @param ChildrenCategoriesProvider $childrenCategoriesProvider + * @param \Magento\CatalogUrlRewrite\Service\V1\StoreViewService $storeViewService */ public function __construct( CategoryUrlPathGenerator $categoryUrlPathGenerator, - ChildrenCategoriesProvider $childrenCategoriesProvider + ChildrenCategoriesProvider $childrenCategoriesProvider, + StoreViewService $storeViewService ) { $this->categoryUrlPathGenerator = $categoryUrlPathGenerator; $this->childrenCategoriesProvider = $childrenCategoriesProvider; + $this->storeViewService = $storeViewService; } /** @@ -40,7 +48,7 @@ class CategoryUrlPathAutogeneratorObserver implements ObserverInterface /** @var Category $category */ $category = $observer->getEvent()->getCategory(); if ($category->getUrlKey() !== false) { - $category->setUrlKey($this->categoryUrlPathGenerator->generateUrlKey($category)) + $category->setUrlKey($this->categoryUrlPathGenerator->getUrlKey($category)) ->setUrlPath($this->categoryUrlPathGenerator->getUrlPath($category)); if (!$category->isObjectNew()) { $category->getResource()->saveAttribute($category, 'url_path'); @@ -57,10 +65,48 @@ class CategoryUrlPathAutogeneratorObserver implements ObserverInterface */ protected function updateUrlPathForChildren(Category $category) { - foreach ($this->childrenCategoriesProvider->getChildren($category, true) as $childCategory) { - $childCategory->unsUrlPath(); - $childCategory->setUrlPath($this->categoryUrlPathGenerator->getUrlPath($childCategory)); - $childCategory->getResource()->saveAttribute($childCategory, 'url_path'); + $children = $this->childrenCategoriesProvider->getChildren($category, true); + + if ($this->isGlobalScope($category->getStoreId())) { + foreach ($children as $child) { + foreach ($category->getStoreIds() as $storeId) { + if ($this->storeViewService->doesEntityHaveOverriddenUrlPathForStore( + $storeId, + $child->getId(), + Category::ENTITY + )) { + $child->setStoreId($storeId); + $this->updateUrlPathForCategory($child); + } + } + } + } else { + foreach ($children as $child) { + $child->setStoreId($category->getStoreId()); + $this->updateUrlPathForCategory($child); + } } } + + /** + * Check is global scope + * + * @param int|null $storeId + * @return bool + */ + protected function isGlobalScope($storeId) + { + return null === $storeId || $storeId == Store::DEFAULT_STORE_ID; + } + + /** + * @param Category $category + * @return void + */ + protected function updateUrlPathForCategory(Category $category) + { + $category->unsUrlPath(); + $category->setUrlPath($this->categoryUrlPathGenerator->getUrlPath($category)); + $category->getResource()->saveAttribute($category, 'url_path'); + } } diff --git a/app/code/Magento/CatalogUrlRewrite/Observer/ProductUrlKeyAutogeneratorObserver.php b/app/code/Magento/CatalogUrlRewrite/Observer/ProductUrlKeyAutogeneratorObserver.php index 5a3cd8bb47a0a04cf66aa595990b34486719c88d..525cc1568a77c2688aabc38a45092d9d9e0a18e5 100644 --- a/app/code/Magento/CatalogUrlRewrite/Observer/ProductUrlKeyAutogeneratorObserver.php +++ b/app/code/Magento/CatalogUrlRewrite/Observer/ProductUrlKeyAutogeneratorObserver.php @@ -31,6 +31,6 @@ class ProductUrlKeyAutogeneratorObserver implements ObserverInterface { /** @var Product $product */ $product = $observer->getEvent()->getProduct(); - $product->setUrlKey($this->productUrlPathGenerator->generateUrlKey($product)); + $product->setUrlKey($this->productUrlPathGenerator->getUrlKey($product)); } } diff --git a/app/code/Magento/CatalogUrlRewrite/Service/V1/StoreViewService.php b/app/code/Magento/CatalogUrlRewrite/Service/V1/StoreViewService.php index 958e882c46013b2153bb3a782c779fdd960acfb9..71e33a74111018446eec2532f4654d90e6d0b98a 100644 --- a/app/code/Magento/CatalogUrlRewrite/Service/V1/StoreViewService.php +++ b/app/code/Magento/CatalogUrlRewrite/Service/V1/StoreViewService.php @@ -46,14 +46,43 @@ class StoreViewService */ public function doesEntityHaveOverriddenUrlKeyForStore($storeId, $entityId, $entityType) { - $attribute = $this->eavConfig->getAttribute($entityType, 'url_key'); + return $this->doesEntityHaveOverriddenUrlAttributeForStore($storeId, $entityId, $entityType, 'url_key'); + } + + /** + * Check that entity has overridden url path for specific store + * + * @param int $storeId + * @param int $entityId + * @param string $entityType + * @throws \InvalidArgumentException + * @return bool + */ + public function doesEntityHaveOverriddenUrlPathForStore($storeId, $entityId, $entityType) + { + return $this->doesEntityHaveOverriddenUrlAttributeForStore($storeId, $entityId, $entityType, 'url_path'); + } + + /** + * Check that entity has overridden url attribute for specific store + * + * @param int $storeId + * @param int $entityId + * @param string $entityType + * @param mixed $attributeName + * @throws \InvalidArgumentException + * @return bool + */ + protected function doesEntityHaveOverriddenUrlAttributeForStore($storeId, $entityId, $entityType, $attributeName) + { + $attribute = $this->eavConfig->getAttribute($entityType, $attributeName); if (!$attribute) { throw new \InvalidArgumentException(sprintf('Cannot retrieve attribute for entity type "%s"', $entityType)); } $select = $this->connection->select() - ->from($attribute->getBackendTable(), 'store_id') - ->where('attribute_id = ?', $attribute->getId()) - ->where('entity_id = ?', $entityId); + ->from($attribute->getBackendTable(), 'store_id') + ->where('attribute_id = ?', $attribute->getId()) + ->where('entity_id = ?', $entityId); return in_array($storeId, $this->connection->fetchCol($select)); } diff --git a/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/CategoryUrlPathGeneratorTest.php b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/CategoryUrlPathGeneratorTest.php index 94dc7f9c33ae26d258eb85148b783efe31941dbf..41300634caaa45df604eda79b1bc075aceb3463b 100644 --- a/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/CategoryUrlPathGeneratorTest.php +++ b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/CategoryUrlPathGeneratorTest.php @@ -235,7 +235,7 @@ class CategoryUrlPathGeneratorTest extends \PHPUnit_Framework_TestCase /** * @return array */ - public function generateUrlKeyDataProvider() + public function getUrlKeyDataProvider() { return [ ['url-key', null, 'url-key'], @@ -244,17 +244,17 @@ class CategoryUrlPathGeneratorTest extends \PHPUnit_Framework_TestCase } /** - * @dataProvider generateUrlKeyDataProvider - * @param string $urlKey - * @param string $name + * @dataProvider getUrlKeyDataProvider + * @param string|null|bool $urlKey + * @param string|null|bool $name * @param string $result */ - public function testGenerateUrlKey($urlKey, $name, $result) + public function testGetUrlKey($urlKey, $name, $result) { $this->category->expects($this->once())->method('getUrlKey')->will($this->returnValue($urlKey)); $this->category->expects($this->any())->method('getName')->will($this->returnValue($name)); $this->category->expects($this->once())->method('formatUrlKey')->will($this->returnArgument(0)); - $this->assertEquals($result, $this->categoryUrlPathGenerator->generateUrlKey($this->category)); + $this->assertEquals($result, $this->categoryUrlPathGenerator->getUrlKey($this->category)); } } diff --git a/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/ProductUrlPathGeneratorTest.php b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/ProductUrlPathGeneratorTest.php index 7b733303bf4d4d16803cd889754af67408136a3d..fe4895c721bb2cda4fc1058ffa58ed5f01805193 100644 --- a/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/ProductUrlPathGeneratorTest.php +++ b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/ProductUrlPathGeneratorTest.php @@ -85,11 +85,11 @@ class ProductUrlPathGeneratorTest extends \PHPUnit_Framework_TestCase /** * @dataProvider getUrlPathDataProvider - * @param $urlKey - * @param $productName - * @param $result + * @param string|null|bool $urlKey + * @param string|null|bool $productName + * @param string $result */ - public function testGenerateUrlPath($urlKey, $productName, $result) + public function testGetUrlPath($urlKey, $productName, $result) { $this->product->expects($this->once())->method('getData')->with('url_path') ->will($this->returnValue(null)); @@ -101,19 +101,21 @@ class ProductUrlPathGeneratorTest extends \PHPUnit_Framework_TestCase } /** - * @param $productUrlKey - * @param $expectedUrlKey - * - * @dataProvider generateUrlKeyDataProvider + * @param string|bool $productUrlKey + * @param string|bool $expectedUrlKey + * @dataProvider getUrlKeyDataProvider */ - public function testGenerateUrlKey($productUrlKey, $expectedUrlKey) + public function testGetUrlKey($productUrlKey, $expectedUrlKey) { $this->product->expects($this->any())->method('getUrlKey')->will($this->returnValue($productUrlKey)); $this->product->expects($this->any())->method('formatUrlKey')->will($this->returnValue($productUrlKey)); - $this->assertEquals($expectedUrlKey, $this->productUrlPathGenerator->generateUrlKey($this->product)); + $this->assertEquals($expectedUrlKey, $this->productUrlPathGenerator->getUrlKey($this->product)); } - public function generateUrlKeyDataProvider() + /** + * @return array + */ + public function getUrlKeyDataProvider() { return [ 'URL Key use default' => [false, false], @@ -121,17 +123,10 @@ class ProductUrlPathGeneratorTest extends \PHPUnit_Framework_TestCase ]; } - public function testGetUrlPath() - { - $this->product->expects($this->once())->method('getData')->with('url_path') - ->will($this->returnValue('url-path')); - $this->product->expects($this->never())->method('getUrlKey'); - - $this->assertEquals('url-path', $this->productUrlPathGenerator->getUrlPath($this->product, null)); - } - /** - * + * @param string|null|bool $storedUrlKey + * @param string|null|bool $productName + * @param string $expectedUrlKey * @dataProvider getUrlPathDefaultUrlKeyDataProvider */ public function testGetUrlPathDefaultUrlKey($storedUrlKey, $productName, $expectedUrlKey) @@ -144,13 +139,15 @@ class ProductUrlPathGeneratorTest extends \PHPUnit_Framework_TestCase $this->assertEquals($expectedUrlKey, $this->productUrlPathGenerator->getUrlPath($this->product, null)); } + /** + * @return array + */ public function getUrlPathDefaultUrlKeyDataProvider() { return [ ['default-store-view-url-key', null, 'default-store-view-url-key'], [false, 'default-store-view-product-name', 'default-store-view-product-name'] ]; - } public function testGetUrlPathWithCategory() diff --git a/app/code/Magento/CatalogUrlRewrite/Test/Unit/Observer/CategoryUrlPathAutogeneratorObserverTest.php b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Observer/CategoryUrlPathAutogeneratorObserverTest.php index 8088fcf653a18e0699e7533aeb54097ceedc9165..e400fe924c68639c0cd3d9c35fc904b56852bccd 100644 --- a/app/code/Magento/CatalogUrlRewrite/Test/Unit/Observer/CategoryUrlPathAutogeneratorObserverTest.php +++ b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Observer/CategoryUrlPathAutogeneratorObserverTest.php @@ -24,6 +24,16 @@ class CategoryUrlPathAutogeneratorObserverTest extends \PHPUnit_Framework_TestCa /** @var \PHPUnit_Framework_MockObject_MockObject */ protected $category; + /** + * @var \Magento\CatalogUrlRewrite\Service\V1\StoreViewService|\PHPUnit_Framework_MockObject_MockObject + */ + protected $storeViewService; + + /** + * @var \Magento\Catalog\Model\ResourceModel\Category|\PHPUnit_Framework_MockObject_MockObject + */ + protected $categoryResource; + protected function setUp() { $this->observer = $this->getMock( @@ -33,13 +43,15 @@ class CategoryUrlPathAutogeneratorObserverTest extends \PHPUnit_Framework_TestCa '', false ); + $this->categoryResource = $this->getMock('Magento\Catalog\Model\ResourceModel\Category', [], [], '', false); $this->category = $this->getMock( 'Magento\Catalog\Model\Category', - ['setUrlKey', 'setUrlPath', 'dataHasChangedFor', 'isObjectNew', 'getResource', 'getUrlKey'], + ['setUrlKey', 'setUrlPath', 'dataHasChangedFor', 'isObjectNew', 'getResource', 'getUrlKey', 'getStoreId'], [], '', false ); + $this->category->expects($this->any())->method('getResource')->willReturn($this->categoryResource); $this->observer->expects($this->any())->method('getEvent')->willReturnSelf(); $this->observer->expects($this->any())->method('getCategory')->willReturn($this->category); $this->categoryUrlPathGenerator = $this->getMock( @@ -53,11 +65,20 @@ class CategoryUrlPathAutogeneratorObserverTest extends \PHPUnit_Framework_TestCa 'Magento\CatalogUrlRewrite\Model\Category\ChildrenCategoriesProvider' ); + $this->storeViewService = $this->getMock( + 'Magento\CatalogUrlRewrite\Service\V1\StoreViewService', + [], + [], + '', + false + ); + $this->categoryUrlPathAutogeneratorObserver = (new ObjectManagerHelper($this))->getObject( 'Magento\CatalogUrlRewrite\Observer\CategoryUrlPathAutogeneratorObserver', [ 'categoryUrlPathGenerator' => $this->categoryUrlPathGenerator, - 'childrenCategoriesProvider' => $this->childrenCategoriesProvider + 'childrenCategoriesProvider' => $this->childrenCategoriesProvider, + 'storeViewService' => $this->storeViewService, ] ); } @@ -65,7 +86,7 @@ class CategoryUrlPathAutogeneratorObserverTest extends \PHPUnit_Framework_TestCa public function testSetCategoryUrlAndCategoryPath() { $this->category->expects($this->once())->method('getUrlKey')->willReturn('category'); - $this->categoryUrlPathGenerator->expects($this->once())->method('generateUrlKey')->willReturn('urk_key'); + $this->categoryUrlPathGenerator->expects($this->once())->method('getUrlKey')->willReturn('urk_key'); $this->category->expects($this->once())->method('setUrlKey')->with('urk_key')->willReturnSelf(); $this->categoryUrlPathGenerator->expects($this->once())->method('getUrlPath')->willReturn('url_path'); $this->category->expects($this->once())->method('setUrlPath')->with('url_path')->willReturnSelf(); @@ -74,7 +95,7 @@ class CategoryUrlPathAutogeneratorObserverTest extends \PHPUnit_Framework_TestCa $this->categoryUrlPathAutogeneratorObserver->execute($this->observer); } - public function testExecuteWithoutGeneration() + public function testExecuteWithoutUrlKeyAndUrlPathUpdating() { $this->category->expects($this->once())->method('getUrlKey')->willReturn(false); $this->category->expects($this->never())->method('setUrlKey'); @@ -82,30 +103,103 @@ class CategoryUrlPathAutogeneratorObserverTest extends \PHPUnit_Framework_TestCa $this->categoryUrlPathAutogeneratorObserver->execute($this->observer); } - public function testUpdateUrlPathForChildren() + public function testUrlKeyAndUrlPathUpdating() { - $this->category->expects($this->once())->method('getUrlKey')->willReturn('category'); - $this->category->expects($this->once())->method('setUrlKey')->willReturnSelf(); - $this->category->expects($this->once())->method('setUrlPath')->willReturnSelf(); + $this->categoryUrlPathGenerator->expects($this->once())->method('getUrlKey')->with($this->category) + ->willReturn('url_key'); + $this->categoryUrlPathGenerator->expects($this->once())->method('getUrlPath')->with($this->category) + ->willReturn('url_path'); + + $this->category->expects($this->once())->method('getUrlKey')->willReturn('not_formatted_url_key'); + $this->category->expects($this->once())->method('setUrlKey')->with('url_key')->willReturnSelf(); + $this->category->expects($this->once())->method('setUrlPath')->with('url_path')->willReturnSelf(); + // break code execution + $this->category->expects($this->once())->method('isObjectNew')->willReturn(true); + + $this->categoryUrlPathAutogeneratorObserver->execute($this->observer); + } + + public function testUrlPathAttributeNoUpdatingIfCategoryIsNew() + { + $this->categoryUrlPathGenerator->expects($this->any())->method('getUrlKey')->willReturn('url_key'); + $this->categoryUrlPathGenerator->expects($this->any())->method('getUrlPath')->willReturn('url_path'); + + $this->category->expects($this->any())->method('getUrlKey')->willReturn('not_formatted_url_key'); + $this->category->expects($this->any())->method('setUrlKey')->willReturnSelf(); + $this->category->expects($this->any())->method('setUrlPath')->willReturnSelf(); + + $this->category->expects($this->once())->method('isObjectNew')->willReturn(true); + $this->categoryResource->expects($this->never())->method('saveAttribute'); + + $this->categoryUrlPathAutogeneratorObserver->execute($this->observer); + } + + public function testUrlPathAttributeUpdating() + { + $this->categoryUrlPathGenerator->expects($this->any())->method('getUrlKey')->willReturn('url_key'); + $this->categoryUrlPathGenerator->expects($this->any())->method('getUrlPath')->willReturn('url_path'); + + $this->category->expects($this->any())->method('getUrlKey')->willReturn('not_formatted_url_key'); + $this->category->expects($this->any())->method('setUrlKey')->willReturnSelf(); + $this->category->expects($this->any())->method('setUrlPath')->willReturnSelf(); $this->category->expects($this->once())->method('isObjectNew')->willReturn(false); - $this->category->expects($this->once())->method('dataHasChangedFor')->with('url_path')->willReturn(true); - $categoryResource = $this->getMockBuilder('Magento\Catalog\Model\ResourceModel\Category') - ->disableOriginalConstructor()->getMock(); - $this->category->expects($this->once())->method('getResource')->willReturn($categoryResource); - $categoryResource->expects($this->once())->method('saveAttribute')->with($this->category, 'url_path'); + $this->categoryResource->expects($this->once())->method('saveAttribute')->with($this->category, 'url_path'); + + // break code execution + $this->category->expects($this->once())->method('dataHasChangedFor')->with('url_path')->willReturn(false); + + $this->categoryUrlPathAutogeneratorObserver->execute($this->observer); + } + + public function testChildrenUrlPathAttributeNoUpdatingIfParentUrlPathIsNotChanged() + { + $this->categoryUrlPathGenerator->expects($this->any())->method('getUrlKey')->willReturn('url_key'); + $this->categoryUrlPathGenerator->expects($this->any())->method('getUrlPath')->willReturn('url_path'); + + $this->categoryResource->expects($this->once())->method('saveAttribute')->with($this->category, 'url_path'); + + $this->category->expects($this->any())->method('getUrlKey')->willReturn('not_formatted_url_key'); + $this->category->expects($this->any())->method('setUrlKey')->willReturnSelf(); + $this->category->expects($this->any())->method('setUrlPath')->willReturnSelf(); + $this->category->expects($this->once())->method('isObjectNew')->willReturn(false); + // break code execution + $this->category->expects($this->once())->method('dataHasChangedFor')->with('url_path')->willReturn(false); + + $this->categoryUrlPathAutogeneratorObserver->execute($this->observer); + } + + public function testChildrenUrlPathAttributeUpdatingForSpecificStore() + { + $this->categoryUrlPathGenerator->expects($this->any())->method('getUrlKey')->willReturn('generated_url_key'); + $this->categoryUrlPathGenerator->expects($this->any())->method('getUrlPath')->willReturn('generated_url_path'); + + $this->category->expects($this->any())->method('getUrlKey')->willReturn('not_formatted_url_key'); + $this->category->expects($this->any())->method('setUrlKey')->willReturnSelf(); + $this->category->expects($this->any())->method('setUrlPath')->willReturnSelf(); + $this->category->expects($this->any())->method('isObjectNew')->willReturn(false); + $this->category->expects($this->any())->method('dataHasChangedFor')->willReturn(true); + // only for specific store + $this->category->expects($this->atLeastOnce())->method('getStoreId')->willReturn(1); + + $childCategoryResource = $this->getMockBuilder('Magento\Catalog\Model\ResourceModel\Category') + ->disableOriginalConstructor()->getMock(); $childCategory = $this->getMockBuilder('Magento\Catalog\Model\Category') - ->setMethods(['getUrlPath', 'setUrlPath', 'getResource', 'unsUrlPath']) + ->setMethods([ + 'getUrlPath', + 'setUrlPath', + 'getResource', + 'getStore', + 'getStoreId', + 'setStoreId' + ]) ->disableOriginalConstructor()->getMock(); + $childCategory->expects($this->any())->method('getResource')->willReturn($childCategoryResource); + $childCategory->expects($this->once())->method('setStoreId')->with(1); $this->childrenCategoriesProvider->expects($this->once())->method('getChildren')->willReturn([$childCategory]); - $childCategoryResource = $this->getMockBuilder('Magento\Catalog\Model\ResourceModel\Category') - ->disableOriginalConstructor()->getMock(); - $childCategory->expects($this->once())->method('unsUrlPath')->willReturnSelf(); - $childCategory->expects($this->once())->method('getResource')->willReturn($childCategoryResource); + $childCategory->expects($this->once())->method('setUrlPath')->with('generated_url_path')->willReturnSelf(); $childCategoryResource->expects($this->once())->method('saveAttribute')->with($childCategory, 'url_path'); - $childCategory->expects($this->once())->method('setUrlPath')->with('category-url_path')->willReturnSelf(); - $this->categoryUrlPathGenerator->expects($this->any())->method('getUrlPath')->willReturn('category-url_path'); $this->categoryUrlPathAutogeneratorObserver->execute($this->observer); } diff --git a/app/code/Magento/ConfigurableProduct/Block/Product/View/Type/Configurable.php b/app/code/Magento/ConfigurableProduct/Block/Product/View/Type/Configurable.php index fce1979115e66199ff8932a3de3dbc8bac44cf5c..356f9b2f2b8cd63a34a01978954170f082561a2e 100644 --- a/app/code/Magento/ConfigurableProduct/Block/Product/View/Type/Configurable.php +++ b/app/code/Magento/ConfigurableProduct/Block/Product/View/Type/Configurable.php @@ -184,15 +184,15 @@ class Configurable extends \Magento\Catalog\Block\Product\View\AbstractView 'optionPrices' => $this->getOptionPrices(), 'prices' => [ 'oldPrice' => [ - 'amount' => $this->_registerJsPrice($this->_convertPrice($regularPrice->getAmount()->getValue())), + 'amount' => $this->_registerJsPrice($regularPrice->getAmount()->getValue()), ], 'basePrice' => [ 'amount' => $this->_registerJsPrice( - $this->_convertPrice($finalPrice->getAmount()->getBaseAmount()) + $finalPrice->getAmount()->getBaseAmount() ), ], 'finalPrice' => [ - 'amount' => $this->_registerJsPrice($this->_convertPrice($finalPrice->getAmount()->getValue())), + 'amount' => $this->_registerJsPrice($finalPrice->getAmount()->getValue()), ], ], 'productId' => $currentProduct->getId(), @@ -223,17 +223,17 @@ class Configurable extends \Magento\Catalog\Block\Product\View\AbstractView [ 'oldPrice' => [ 'amount' => $this->_registerJsPrice( - $this->_convertPrice($priceInfo->getPrice('regular_price')->getAmount()->getValue()) + $priceInfo->getPrice('regular_price')->getAmount()->getValue() ), ], 'basePrice' => [ 'amount' => $this->_registerJsPrice( - $this->_convertPrice($priceInfo->getPrice('final_price')->getAmount()->getBaseAmount()) + $priceInfo->getPrice('final_price')->getAmount()->getBaseAmount() ), ], 'finalPrice' => [ 'amount' => $this->_registerJsPrice( - $this->_convertPrice($priceInfo->getPrice('final_price')->getAmount()->getValue()) + $priceInfo->getPrice('final_price')->getAmount()->getValue() ), ] ]; @@ -251,25 +251,4 @@ class Configurable extends \Magento\Catalog\Block\Product\View\AbstractView { return str_replace(',', '.', $price); } - - /** - * Convert price from default currency to current currency - * - * @param float $price - * @param bool $round - * @return float - */ - protected function _convertPrice($price, $round = false) - { - if (empty($price)) { - return 0; - } - - $price = $this->priceCurrency->convert($price); - if ($round) { - $price = $this->priceCurrency->round($price); - } - - return $price; - } } diff --git a/app/code/Magento/ConfigurableProduct/Helper/Data.php b/app/code/Magento/ConfigurableProduct/Helper/Data.php index 91dd722424219c550a555622bd165df5e242706d..8ab8a52a9ee65b69218978cc774e24f1e85ef546 100644 --- a/app/code/Magento/ConfigurableProduct/Helper/Data.php +++ b/app/code/Magento/ConfigurableProduct/Helper/Data.php @@ -40,7 +40,7 @@ class Data { $images = $product->getMediaGalleryImages(); if ($images instanceof \Magento\Framework\Data\Collection) { - foreach ($images as &$image) { + foreach ($images as $image) { /** @var $image \Magento\Catalog\Model\Product\Image */ $image->setData( 'small_image_url', diff --git a/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable/Price.php b/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable/Price.php index bd74b867c86103a67177628d8bef0e30609261cb..aeae1374a9813916bee8a2b97bdfe089e0c4ec7c 100644 --- a/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable/Price.php +++ b/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable/Price.php @@ -7,8 +7,6 @@ */ namespace Magento\ConfigurableProduct\Model\Product\Type\Configurable; -use Magento\Framework\Pricing\PriceCurrencyInterface; - class Price extends \Magento\Catalog\Model\Product\Type\Price { /** @@ -24,17 +22,27 @@ class Price extends \Magento\Catalog\Model\Product\Type\Price return $product->getCalculatedFinalPrice(); } if ($product->getCustomOption('simple_product')) { - $simpleProduct = $product->getCustomOption('simple_product')->getProduct(); - $product->setSelectedConfigurableOption($simpleProduct); - $priceInfo = $simpleProduct->getPriceInfo(); + return parent::getFinalPrice($qty, $product->getCustomOption('simple_product')->getProduct()); } else { $priceInfo = $product->getPriceInfo(); + $finalPrice = $priceInfo->getPrice('final_price')->getAmount()->getValue(); + $finalPrice = $this->_applyOptionsPrice($product, $qty, $finalPrice); + $finalPrice = max(0, $finalPrice); + $product->setFinalPrice($finalPrice); + + return $finalPrice; } - $finalPrice = $priceInfo->getPrice('final_price')->getAmount()->getValue(); - $finalPrice = $this->_applyOptionsPrice($product, $qty, $finalPrice); - $finalPrice = max(0, $finalPrice); - $product->setFinalPrice($finalPrice); + } - return $finalPrice; + /** + * {@inheritdoc} + */ + public function getPrice($product) + { + if ($product->getCustomOption('simple_product')) { + return $product->getCustomOption('simple_product')->getProduct()->getPrice(); + } else { + return 0; + } } } diff --git a/app/code/Magento/ConfigurableProduct/Pricing/Price/BasePrice.php b/app/code/Magento/ConfigurableProduct/Pricing/Price/BasePrice.php deleted file mode 100644 index 76f2ef5cdd900bfe3b68950147c2f0ec988c16c8..0000000000000000000000000000000000000000 --- a/app/code/Magento/ConfigurableProduct/Pricing/Price/BasePrice.php +++ /dev/null @@ -1,68 +0,0 @@ -<?php -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\ConfigurableProduct\Pricing\Price; - -use \Magento\Framework\Pricing\Price\BasePriceProviderInterface; - -class BasePrice extends \Magento\Catalog\Pricing\Price\BasePrice -{ - /** - * @var array - */ - protected $values = []; - - /** - * @var null|boolean|float - */ - protected $minimumAdditionalPrice; - - /** - * {@inheritdoc} - */ - public function getValue() - { - $selectedConfigurableOption = $this->product->getSelectedConfigurableOption(); - $productId = $selectedConfigurableOption ? $selectedConfigurableOption->getId() : $this->product->getId(); - if (!isset($this->values[$productId])) { - $this->value = null; - if (!$selectedConfigurableOption) { - $this->values[$productId] = parent::getValue(); - } else { - if (false !== $this->getMinimumAdditionalPrice()) { - $this->values[$productId] = $this->getMinimumAdditionalPrice(); - } else { - $this->values[$productId] = parent::getValue(); - } - } - } - return $this->values[$productId]; - } - - /** - * @return bool|float - */ - protected function getMinimumAdditionalPrice() - { - if (null === $this->minimumAdditionalPrice) { - $priceCodes = [ - \Magento\Catalog\Pricing\Price\SpecialPrice::PRICE_CODE, - \Magento\Catalog\Pricing\Price\TierPrice::PRICE_CODE, - ]; - $this->minimumAdditionalPrice = false; - foreach ($priceCodes as $priceCode) { - $price = $this->product->getPriceInfo()->getPrice($priceCode); - if ($price instanceof BasePriceProviderInterface && $price->getValue() !== false) { - $this->minimumAdditionalPrice = min( - $price->getValue(), - $this->minimumAdditionalPrice ?: $price->getValue() - ); - } - } - } - return $this->minimumAdditionalPrice; - } -} diff --git a/app/code/Magento/ConfigurableProduct/Pricing/Price/ConfigurablePriceResolver.php b/app/code/Magento/ConfigurableProduct/Pricing/Price/ConfigurablePriceResolver.php index d0f2461c96a3e1f866c9eae498c2c3bebd81c741..a4fe3d76da22b5316ce64399329f9ed6261ee253 100644 --- a/app/code/Magento/ConfigurableProduct/Pricing/Price/ConfigurablePriceResolver.php +++ b/app/code/Magento/ConfigurableProduct/Pricing/Price/ConfigurablePriceResolver.php @@ -37,22 +37,22 @@ class ConfigurablePriceResolver implements PriceResolverInterface } /** - * @param \Magento\Framework\Pricing\SaleableInterface $product + * @param \Magento\Framework\Pricing\SaleableInterface|\Magento\Catalog\Model\Product $product * @return float + * @throws \Magento\Framework\Exception\LocalizedException */ public function resolvePrice(\Magento\Framework\Pricing\SaleableInterface $product) { - $selectedConfigurableOption = $product->getSelectedConfigurableOption(); - if ($selectedConfigurableOption) { - $price = $this->priceResolver->resolvePrice($selectedConfigurableOption); - } else { - $price = null; - foreach ($this->configurable->getUsedProducts($product) as $subProduct) { - $productPrice = $this->priceResolver->resolvePrice($subProduct); - $price = $price ? min($price, $productPrice) : $productPrice; - } + $price = null; + foreach ($this->configurable->getUsedProducts($product) as $subProduct) { + $productPrice = $this->priceResolver->resolvePrice($subProduct); + $price = $price ? min($price, $productPrice) : $productPrice; } - $priceInCurrentCurrency = $this->priceCurrency->convertAndRound($price); - return $priceInCurrentCurrency ? (float)$priceInCurrentCurrency : false; + if (!$price) { + throw new \Magento\Framework\Exception\LocalizedException( + __('Configurable product "%1" do not have sub-products', $product->getName()) + ); + } + return (float)$price; } } diff --git a/app/code/Magento/ConfigurableProduct/Pricing/Price/ConfigurableRegularPrice.php b/app/code/Magento/ConfigurableProduct/Pricing/Price/ConfigurableRegularPrice.php index de5ea0dcb0716011e643e34e4f1cef439c9384a4..936698cef3567b14ea4ad9dc219702d210e49962 100644 --- a/app/code/Magento/ConfigurableProduct/Pricing/Price/ConfigurableRegularPrice.php +++ b/app/code/Magento/ConfigurableProduct/Pricing/Price/ConfigurableRegularPrice.php @@ -61,20 +61,19 @@ class ConfigurableRegularPrice extends AbstractPrice implements ConfigurableRegu */ public function getValue() { - $selectedConfigurableOption = $this->product->getSelectedConfigurableOption(); - $productId = $selectedConfigurableOption ? $selectedConfigurableOption->getId() : $this->product->getId(); - if (!isset($this->values[$productId])) { - $this->values[$productId] = $this->priceResolver->resolvePrice($this->product); + if (!isset($this->values[$this->product->getId()])) { + $this->values[$this->product->getId()] = $this->priceResolver->resolvePrice($this->product); } - return $this->values[$productId]; + return $this->values[$this->product->getId()]; } + /** * {@inheritdoc} */ public function getAmount() { - return $this->getMinRegularAmount($this->product); + return $this->getMinRegularAmount(); } /** @@ -116,7 +115,6 @@ class ConfigurableRegularPrice extends AbstractPrice implements ConfigurableRegu $this->minRegularAmount = $this->doGetMinRegularAmount() ?: false; } return $this->minRegularAmount; - } /** diff --git a/app/code/Magento/ConfigurableProduct/Pricing/Price/FinalPrice.php b/app/code/Magento/ConfigurableProduct/Pricing/Price/FinalPrice.php index 3d7cfd251d54e466fe74514e16c1a58646b44d78..834df6ffd429aa75c8c90f060ad80103f5326713 100644 --- a/app/code/Magento/ConfigurableProduct/Pricing/Price/FinalPrice.php +++ b/app/code/Magento/ConfigurableProduct/Pricing/Price/FinalPrice.php @@ -34,28 +34,15 @@ class FinalPrice extends \Magento\Catalog\Pricing\Price\FinalPrice $this->priceResolver = $priceResolver; } - /** - * {@inheritdoc} - */ - public function getAmount() - { - if ($this->product->getSelectedConfigurableOption()) { - $this->amount = null; - } - return parent::getAmount(); - } - /** * {@inheritdoc} */ public function getValue() { - $selectedConfigurableOption = $this->product->getSelectedConfigurableOption(); - $productId = $selectedConfigurableOption ? $selectedConfigurableOption->getId() : $this->product->getId(); - if (!isset($this->values[$productId])) { - $this->values[$productId] = $this->priceResolver->resolvePrice($this->product); + if (!isset($this->values[$this->product->getId()])) { + $this->values[$this->product->getId()] = $this->priceResolver->resolvePrice($this->product); } - return $this->values[$productId]; + return $this->values[$this->product->getId()]; } } diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Product/Type/Configurable/PriceTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Product/Type/Configurable/PriceTest.php index 7d14671ec0d7db501a3bd58fba10ecf9d4b265d6..7757b4356244206b5b17b0e52a948d4f03126a3b 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Product/Type/Configurable/PriceTest.php +++ b/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Product/Type/Configurable/PriceTest.php @@ -31,11 +31,7 @@ class PriceTest extends \PHPUnit_Framework_TestCase $qty = 1; $configurableProduct = $this->getMockBuilder('Magento\Catalog\Model\Product') ->disableOriginalConstructor() - ->setMethods(['getCustomOption', 'setSelectedConfigurableOption', 'setFinalPrice', '__wakeUp']) - ->getMock(); - $childProduct = $this->getMockBuilder('Magento\Catalog\Model\Product') - ->disableOriginalConstructor() - ->setMethods(['getPriceInfo', '__wakeUp']) + ->setMethods(['getCustomOption', 'getPriceInfo', 'setFinalPrice', '__wakeUp']) ->getMock(); $customOption = $this->getMockBuilder('Magento\Catalog\Model\Product\Configuration\Item\Option') ->disableOriginalConstructor() @@ -52,24 +48,14 @@ class PriceTest extends \PHPUnit_Framework_TestCase ->disableOriginalConstructor() ->getMock(); - $configurableProduct->expects($this->at(0)) - ->method('getCustomOption') - ->with('simple_product') - ->willReturn($customOption); - $configurableProduct->expects($this->at(1)) + $configurableProduct->expects($this->any()) ->method('getCustomOption') - ->with('simple_product') - ->willReturn($customOption); - $customOption->expects($this->once())->method('getProduct')->willReturn($childProduct); - $configurableProduct->expects($this->once()) - ->method('setSelectedConfigurableOption') - ->with($childProduct) - ->willReturnSelf(); - $childProduct->expects($this->once())->method('getPriceInfo')->willReturn($priceInfo); + ->willReturnMap([['simple_product', false], ['option_ids', false]]); + $customOption->expects($this->never())->method('getProduct'); + $configurableProduct->expects($this->once())->method('getPriceInfo')->willReturn($priceInfo); $priceInfo->expects($this->once())->method('getPrice')->with('final_price')->willReturn($price); $price->expects($this->once())->method('getAmount')->willReturn($amount); $amount->expects($this->once())->method('getValue')->willReturn($finalPrice); - $configurableProduct->expects($this->at(3))->method('getCustomOption')->with('option_ids')->willReturn(false); $configurableProduct->expects($this->once())->method('setFinalPrice')->with($finalPrice)->willReturnSelf(); $this->assertEquals($finalPrice, $this->model->getFinalPrice($qty, $configurableProduct)); diff --git a/app/code/Magento/ConfigurableProduct/etc/di.xml b/app/code/Magento/ConfigurableProduct/etc/di.xml index ff1173c2e0908c55d8ef1f8fb338eafd562ed4eb..e2463e52daa8127d663d9abfca26801cda0a3f70 100644 --- a/app/code/Magento/ConfigurableProduct/etc/di.xml +++ b/app/code/Magento/ConfigurableProduct/etc/di.xml @@ -70,7 +70,6 @@ <argument name="prices" xsi:type="array"> <item name="regular_price" xsi:type="string">Magento\ConfigurableProduct\Pricing\Price\ConfigurableRegularPrice</item> <item name="final_price" xsi:type="string">Magento\ConfigurableProduct\Pricing\Price\FinalPrice</item> - <item name="base_price" xsi:type="string">Magento\ConfigurableProduct\Pricing\Price\BasePrice</item> </argument> <argument name="target" xsi:type="object">Magento\Catalog\Pricing\Price\Pool</argument> </arguments> diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/steps/bulk.js b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/steps/bulk.js index 499962f8e59f8f68e598ce4800ac90ff824f7578..788d4eed83235cd3f6169039787a74e540b93d2e 100644 --- a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/steps/bulk.js +++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/steps/bulk.js @@ -55,7 +55,7 @@ define([ type: ko.observable('none'), value: ko.observable(), attribute: ko.observable(), - currencySymbol: this.variationsComponent().getCurrencySymbol() + currencySymbol: '' }, quantity: { label: 'quantity', @@ -64,6 +64,11 @@ define([ attribute: ko.observable() } }); + + this.variationsComponent(function (variationsComponent) { + this.sections().price.currencySymbol = variationsComponent.getCurrencySymbol() + }.bind(this)); + this.makeOptionSections = function () { this.images = new self.makeImages(null); this.price = self.price; diff --git a/app/code/Magento/Deploy/Model/Deployer.php b/app/code/Magento/Deploy/Model/Deployer.php index 60480c220e23ccc1762243ab61075bf7fb7aec7b..c63bed567703b56f9b33eec1438537fabd9646b5 100644 --- a/app/code/Magento/Deploy/Model/Deployer.php +++ b/app/code/Magento/Deploy/Model/Deployer.php @@ -312,12 +312,11 @@ class Deployer } } - $logMessage = "Processing file '$filePath' for area '$area', theme '$themePath', locale '$locale'"; - if ($module) { - $logMessage .= ", module '$module'"; - } - if ($this->output->isVeryVerbose()) { + $logMessage = "Processing file '$filePath' for area '$area', theme '$themePath', locale '$locale'"; + if ($module) { + $logMessage .= ", module '$module'"; + } $this->output->writeln($logMessage); } diff --git a/app/code/Magento/Developer/i18n/en_US.csv b/app/code/Magento/Developer/i18n/en_US.csv index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..1cf1f795360955ee458246a6975d78a27f761282 100644 --- a/app/code/Magento/Developer/i18n/en_US.csv +++ b/app/code/Magento/Developer/i18n/en_US.csv @@ -0,0 +1,40 @@ +"Front-end development workflow","Front-end development workflow" +"Workflow type","Workflow type" +"Not available in production mode","Not available in production mode" +"Developer Client Restrictions","Developer Client Restrictions" +"Allowed IPs (comma separated)","Allowed IPs (comma separated)" +"Leave empty for access from any location.","Leave empty for access from any location." +"Debug","Debug" +"Enabled Template Path Hints for Storefront","Enabled Template Path Hints for Storefront" +"Enabled Template Path Hints for Admin","Enabled Template Path Hints for Admin" +"Add Block Names to Hints","Add Block Names to Hints" +"Template Settings","Template Settings" +"Allow Symlinks","Allow Symlinks" +"Warning! Enabling this feature is not recommended on production environments because it represents a potential security risk.","Warning! Enabling this feature is not recommended on production environments because it represents a potential security risk." +"Minify Html","Minify Html" +"Translate Inline","Translate Inline" +"Enabled for Storefront","Enabled for Storefront" +"Enabled for Admin","Enabled for Admin" +"Translate, blocks and other output caches should be disabled for both Storefront and Admin inline translations.","Translate, blocks and other output caches should be disabled for both Storefront and Admin inline translations." +"JavaScript Settings","JavaScript Settings" +"Enable Javascript Bundling","Enable Javascript Bundling" +"Merge JavaScript Files","Merge JavaScript Files" +"Minify JavaScript Files","Minify JavaScript Files" +"Translation Strategy","Translation Strategy" +"Dictionary (Translation on Storefront side)","Dictionary (Translation on Storefront side)" +"Embedded (Translation on Admin side)","Embedded (Translation on Admin side)" +"Log JS Errors to Session Storage","Log JS Errors to Session Storage" +"Log JS Errors to Session Storage Key","Log JS Errors to Session Storage Key" +"CSS Settings","CSS Settings" +"Merge CSS Files","Merge CSS Files" +"Minify CSS Files","Minify CSS Files" +"Image Processing Settings","Image Processing Settings" +"Image Adapter","Image Adapter" +"Static Files Settings","Static Files Settings" +"Sign Static Files","Sign Static Files" +"Grid Settings","Grid Settings" +"Asynchronous indexing","Asynchronous indexing" +"Client side less compilation","Client side less compilation" +"Server side less compilation","Server side less compilation" +"Disable","Disable" +"Enable","Enable" diff --git a/app/code/Magento/Downloadable/Block/Adminhtml/Catalog/Product/Edit/Tab/Downloadable/Links.php b/app/code/Magento/Downloadable/Block/Adminhtml/Catalog/Product/Edit/Tab/Downloadable/Links.php index fb92f2bc3fffd09f5ac54eca2a2fb65e77bd913b..ee184dff0e6d59f349ce9b94cfcc07041b7a0523 100644 --- a/app/code/Magento/Downloadable/Block/Adminhtml/Catalog/Product/Edit/Tab/Downloadable/Links.php +++ b/app/code/Magento/Downloadable/Block/Adminhtml/Catalog/Product/Edit/Tab/Downloadable/Links.php @@ -157,27 +157,13 @@ class Links extends \Magento\Backend\Block\Template } /** - * Retrieve Purchased Separately HTML select + * Get Links can be purchased separately value for current product * - * @return string + * @return bool */ - public function getPurchasedSeparatelySelect() + public function isProductLinksCanBePurchasedSeparately() { - $select = $this->getLayout()->createBlock( - 'Magento\Framework\View\Element\Html\Select' - )->setName( - 'product[links_purchased_separately]' - )->setId( - 'downloadable_link_purchase_type' - )->setOptions( - $this->_sourceModel->toOptionArray() - )->setValue( - $this->getProduct()->getLinksPurchasedSeparately() - )->setClass( - 'admin__control-select' - ); - - return $select->getHtml(); + return (bool) $this->getProduct()->getData('links_purchased_separately'); } /** diff --git a/app/code/Magento/Downloadable/view/adminhtml/templates/product/edit/downloadable.phtml b/app/code/Magento/Downloadable/view/adminhtml/templates/product/edit/downloadable.phtml index dac2edad7be49ec47e029d391901da6842ed6154..dd2cf918d704e910e5712a57e0634ac5a84c6064 100644 --- a/app/code/Magento/Downloadable/view/adminhtml/templates/product/edit/downloadable.phtml +++ b/app/code/Magento/Downloadable/view/adminhtml/templates/product/edit/downloadable.phtml @@ -25,17 +25,6 @@ require([ //<![CDATA[> var uploaderTemplate = '<div class="no-display" id="[[idName]]-template">' + - '<div id="<%- data.id %>" class="file-row file-row-narrow">' + - '<span class="file-info">' + - '<span class="file-info-name"><%= data.name %></span>' + - ' ' + - '<span class="file-info-size">(<%- data.size %>)</span>' + - '</span>' + - '<div class="progressbar-container">' + - '<div class="progressbar upload-progress" style="width: 0%;"></div>' + - '</div>' + - '<div class="clear"></div>' + - '</div>' + '</div>' + '<div class="no-display" id="[[idName]]-template-progress">' + '<%- data.percent %>% <%- data.uploaded %> / <%- data.total %>' + diff --git a/app/code/Magento/Downloadable/view/adminhtml/templates/product/edit/downloadable/links.phtml b/app/code/Magento/Downloadable/view/adminhtml/templates/product/edit/downloadable/links.phtml index cf43aa7d3f4f62de46a4d86395648c671a654c2a..909ab56b200492fafa5e5611832c919e2ecdd726 100644 --- a/app/code/Magento/Downloadable/view/adminhtml/templates/product/edit/downloadable/links.phtml +++ b/app/code/Magento/Downloadable/view/adminhtml/templates/product/edit/downloadable/links.phtml @@ -34,7 +34,34 @@ <div class="admin__field" <?php echo !$block->isSingleStoreMode() ? ' data-config-scope="' . __('[GLOBAL]') . '"' : ''; ?>> <label class="admin__field-label" for="downloadable_link_purchase_type"><span><?php /* @escapeNotVerified */ echo __('Links can be purchased separately')?></span></label> <div class="admin__field-control"> - <?php /* @escapeNotVerified */ echo $block->getPurchasedSeparatelySelect()?> + <div class="admin__field-control link-switcher" data-role="link-switcher"> + <div class="admin__field-control-group"> + <div class="admin__field admin__field-option"> + <input type="radio" name="product[links_purchased_separately]" value="1" + class="admin__control-radio" + id="link-switcher1" + <?php if($block->isProductLinksCanBePurchasedSeparately()): ?> + checked="checked" + <?php endif; ?> + > + <label class="admin__field-label" for="link-switcher1"> + <span>Yes</span> + </label> + </div> + <div class="admin__field admin__field-option"> + <input type="radio" name="product[links_purchased_separately]" value="0" + class="admin__control-radio" + id="link-switcher0" + <?php if(!$block->isProductLinksCanBePurchasedSeparately()): ?> + checked="checked" + <?php endif; ?> + > + <label class="admin__field-label" for="link-switcher0"> + <span>No</span> + </label> + </div> + </div> + </div> </div> </div> <div class="admin__field admin__field-wide"> @@ -357,9 +384,9 @@ require([ } }, togglePriceFields : function(){ - var toogleTo = $('downloadable_link_purchase_type').value; + var toogleTo = jQuery('#link-switcher1').is(':checked'); var disableFlag = true; - if (toogleTo == '1') { + if (toogleTo) { disableFlag = false; } $$('.link-prices[type="text"]').each(function(elm){ @@ -442,9 +469,10 @@ require([ })(jQuery); }; - - if ($('downloadable_link_purchase_type')) { - Event.observe('downloadable_link_purchase_type', 'change', linkItems.togglePriceFields.bind()); + if (jQuery('input[name="product[links_purchased_separately]"]')) { + jQuery('input[name="product[links_purchased_separately]"]').on('change', function () { + linkItems.togglePriceFields.bind() + }); } if($('add_link_item')) { diff --git a/app/code/Magento/Eav/Model/Entity/Attribute/Frontend/AbstractFrontend.php b/app/code/Magento/Eav/Model/Entity/Attribute/Frontend/AbstractFrontend.php index 65644c94f260574a221062bd559a0d335291cdb4..943cf2d3530de8edd94cfef35f95dc0fa3d36fa2 100644 --- a/app/code/Magento/Eav/Model/Entity/Attribute/Frontend/AbstractFrontend.php +++ b/app/code/Magento/Eav/Model/Entity/Attribute/Frontend/AbstractFrontend.php @@ -70,7 +70,7 @@ abstract class AbstractFrontend implements \Magento\Eav\Model\Entity\Attribute\F } /** - * Retrieve lable + * Retrieve label * * @return string */ @@ -84,6 +84,16 @@ abstract class AbstractFrontend implements \Magento\Eav\Model\Entity\Attribute\F return $label; } + /** + * Retrieve localized label + * + * @return \Magento\Framework\Phrase + */ + public function getLocalizedLabel() + { + return __($this->getLabel()); + } + /** * Retrieve attribute value * diff --git a/app/code/Magento/Eav/Test/Unit/Model/Entity/Attribute/Frontend/DatetimeTest.php b/app/code/Magento/Eav/Test/Unit/Model/Entity/Attribute/Frontend/DatetimeTest.php index f28fe8386eee309b308d26a8455012ba045ffbcb..6c1263ef01ecef944e5f0426c123c93dca3a34e6 100644 --- a/app/code/Magento/Eav/Test/Unit/Model/Entity/Attribute/Frontend/DatetimeTest.php +++ b/app/code/Magento/Eav/Test/Unit/Model/Entity/Attribute/Frontend/DatetimeTest.php @@ -38,17 +38,14 @@ class DatetimeTest extends \PHPUnit_Framework_TestCase '', false ); - $this->localeDateMock = $this->getMock('\Magento\Framework\Stdlib\DateTime\TimezoneInterface'); - $this->attributeMock = $this->getMock( '\Magento\Eav\Model\Entity\Attribute\AbstractAttribute', - [], + ['getAttributeCode', 'getFrontendLabel'], [], '', false ); - $this->attributeMock->expects($this->any())->method('getAttributeCode')->will($this->returnValue('datetime')); $this->model = new Datetime($this->booleanFactoryMock, $this->localeDateMock); $this->model->setAttribute($this->attributeMock); @@ -59,13 +56,50 @@ class DatetimeTest extends \PHPUnit_Framework_TestCase $attributeValue = '11-11-2011'; $date = new \DateTime($attributeValue); $object = new \Magento\Framework\DataObject(['datetime' => $attributeValue]); - $this->attributeMock->expects($this->any())->method('getData')->with('frontend_input') - ->will($this->returnValue('text')); - $this->localeDateMock->expects($this->once())->method('formatDateTime') + $this->attributeMock->expects($this->any()) + ->method('getAttributeCode') + ->willReturn('datetime'); + $this->attributeMock->expects($this->any()) + ->method('getData') + ->with('frontend_input') + ->willReturn('text'); + $this->localeDateMock->expects($this->once()) + ->method('formatDateTime') ->with($date, \IntlDateFormatter::MEDIUM, \IntlDateFormatter::NONE, null, null, null) ->willReturn($attributeValue); $this->assertEquals($attributeValue, $this->model->getValue($object)); } + + /** + * @param mixed $labelText + * @param string $attributeCode + * @param string $expectedResult + * @dataProvider getLabelDataProvider + */ + public function testGetLocalizedLabel($labelText, $attributeCode, $expectedResult) + { + $this->attributeMock->expects($this->exactly(2)) + ->method('getFrontendLabel') + ->willReturn($labelText); + $this->attributeMock->expects($this->any()) + ->method('getAttributeCode') + ->willReturn($attributeCode); + + $this->assertInstanceOf('\Magento\Framework\Phrase', $this->model->getLocalizedLabel()); + $this->assertSame($expectedResult, (string)$this->model->getLocalizedLabel()); + } + + /** + * @return array + */ + public function getLabelDataProvider() + { + return [ + [null, 'test code', 'test code'], + ['', 'test code', 'test code'], + ['test label', 'test code', 'test label'], + ]; + } } diff --git a/app/code/Magento/Email/Block/Adminhtml/Template/Preview.php b/app/code/Magento/Email/Block/Adminhtml/Template/Preview.php index eb34ed100fd5c2ac178744ea260aa74a3aa5d8da..d215d37d7df3aa59aaaac441f4f08251268f3328 100644 --- a/app/code/Magento/Email/Block/Adminhtml/Template/Preview.php +++ b/app/code/Magento/Email/Block/Adminhtml/Template/Preview.php @@ -23,6 +23,11 @@ class Preview extends \Magento\Backend\Block\Widget */ protected $_emailFactory; + /** + * @var string + */ + protected $profilerName = 'email_template_proccessing'; + /** * @param \Magento\Backend\Block\Template\Context $context * @param \Magento\Framework\Filter\Input\MaliciousCode $maliciousCode @@ -48,16 +53,10 @@ class Preview extends \Magento\Backend\Block\Widget protected function _toHtml() { $storeId = $this->getAnyStoreView()->getId(); - /** @var $template \Magento\Email\Model\Template */ - $template = $this->_emailFactory->create( - ['data' => [ - 'area' => \Magento\Framework\App\Area::AREA_FRONTEND, - 'store' => $storeId - ]] - ); - $id = (int) $this->getRequest()->getParam('id'); - if ($id) { + $template = $this->_emailFactory->create(); + + if ($id = (int)$this->getRequest()->getParam('id')) { $template->load($id); } else { $template->setTemplateType($this->getRequest()->getParam('type')); @@ -67,7 +66,7 @@ class Preview extends \Magento\Backend\Block\Widget $template->setTemplateText($this->_maliciousCode->filter($template->getTemplateText())); - \Magento\Framework\Profiler::start("email_template_proccessing"); + \Magento\Framework\Profiler::start($this->profilerName); $template->emulateDesign($storeId); $templateProcessed = $this->_appState->emulateAreaCode( @@ -80,7 +79,7 @@ class Preview extends \Magento\Backend\Block\Widget $templateProcessed = "<pre>" . htmlspecialchars($templateProcessed) . "</pre>"; } - \Magento\Framework\Profiler::stop("email_template_proccessing"); + \Magento\Framework\Profiler::stop($this->profilerName); return $templateProcessed; } diff --git a/app/code/Magento/Email/Controller/Adminhtml/Email/Template/Preview.php b/app/code/Magento/Email/Controller/Adminhtml/Email/Template/Preview.php index fceea747f03b99ffbde4a9ccc23a6bf700feac0c..c85cc7d4a6c486a755d1d23702b8513de24a48b6 100644 --- a/app/code/Magento/Email/Controller/Adminhtml/Email/Template/Preview.php +++ b/app/code/Magento/Email/Controller/Adminhtml/Email/Template/Preview.php @@ -16,7 +16,8 @@ class Preview extends \Magento\Email\Controller\Adminhtml\Email\Template public function execute() { try { - $this->_view->loadLayout('systemPreview'); + $this->_view->loadLayout(); + $this->_view->getPage()->getConfig()->getTitle()->prepend(__('Email Preview')); $this->_view->renderLayout(); } catch (\Exception $e) { $this->messageManager->addError(__('An error occurred. The email template can not be opened for preview.')); diff --git a/app/code/Magento/Email/Test/Unit/Block/Adminhtml/Template/PreviewTest.php b/app/code/Magento/Email/Test/Unit/Block/Adminhtml/Template/PreviewTest.php index 599c1b81010d4c5688df278234ccac6cae4e0608..3a7d91dfefb72d2ab23ac1c54867b46fd017ddcc 100644 --- a/app/code/Magento/Email/Test/Unit/Block/Adminhtml/Template/PreviewTest.php +++ b/app/code/Magento/Email/Test/Unit/Block/Adminhtml/Template/PreviewTest.php @@ -46,42 +46,37 @@ class PreviewTest extends \PHPUnit_Framework_TestCase 'revertDesign' ]) ->disableOriginalConstructor() - ->getMock() - ; + ->getMock(); $template->expects($this->once()) ->method('getProcessedTemplate') ->with($this->equalTo([])) - ->will($this->returnValue(self::MALICIOUS_TEXT)); - $designConfigData = [ - 'area' => \Magento\Framework\App\Area::AREA_FRONTEND, - 'store' => $storeId - ]; + ->willReturn(self::MALICIOUS_TEXT); + $designConfigData = []; $template->expects($this->atLeastOnce()) ->method('getDesignConfig') - ->will($this->returnValue(new \Magento\Framework\DataObject( + ->willReturn(new \Magento\Framework\DataObject( $designConfigData - ))); + )); $emailFactory = $this->getMock('Magento\Email\Model\TemplateFactory', ['create'], [], '', false); - $emailFactory->expects($this->once()) + $emailFactory->expects($this->any()) ->method('create') - ->with($this->equalTo(['data' => $designConfigData])) - ->will($this->returnValue($template)); + ->willReturn($template); $request = $this->getMock('Magento\Framework\App\RequestInterface'); - $request->expects($this->any())->method('getParam')->will($this->returnValueMap($requestParamMap)); + $request->expects($this->any())->method('getParam')->willReturnMap($requestParamMap); $eventManage = $this->getMock('Magento\Framework\Event\ManagerInterface'); $scopeConfig = $this->getMock('Magento\Framework\App\Config\ScopeConfigInterface'); $design = $this->getMock('Magento\Framework\View\DesignInterface'); $store = $this->getMock('Magento\Store\Model\Store', ['getId', '__wakeup'], [], '', false); - $store->expects($this->any())->method('getId')->will($this->returnValue($storeId)); + $store->expects($this->any())->method('getId')->willReturn($storeId); $storeManager = $this->getMockBuilder('\Magento\Store\Model\StoreManagerInterface') ->disableOriginalConstructor() ->getMock(); $storeManager->expects($this->atLeastOnce()) ->method('getDefaultStoreView') - ->will($this->returnValue($store)); - $storeManager->expects($this->any())->method('getDefaultStoreView')->will($this->returnValue(null)); - $storeManager->expects($this->any())->method('getStores')->will($this->returnValue([$store])); + ->willReturn($store); + $storeManager->expects($this->any())->method('getDefaultStoreView')->willReturn(null); + $storeManager->expects($this->any())->method('getStores')->willReturn([$store]); $appState = $this->getMockBuilder('Magento\Framework\App\State') ->setConstructorArgs([ $scopeConfig @@ -94,12 +89,12 @@ class PreviewTest extends \PHPUnit_Framework_TestCase ['getRequest', 'getEventManager', 'getScopeConfig', 'getDesignPackage', 'getStoreManager', 'getAppState'], [], '', false ); - $context->expects($this->any())->method('getRequest')->will($this->returnValue($request)); - $context->expects($this->any())->method('getEventManager')->will($this->returnValue($eventManage)); - $context->expects($this->any())->method('getScopeConfig')->will($this->returnValue($scopeConfig)); - $context->expects($this->any())->method('getDesignPackage')->will($this->returnValue($design)); - $context->expects($this->any())->method('getStoreManager')->will($this->returnValue($storeManager)); - $context->expects($this->once())->method('getAppState')->will($this->returnValue($appState)); + $context->expects($this->any())->method('getRequest')->willReturn($request); + $context->expects($this->any())->method('getEventManager')->willReturn($eventManage); + $context->expects($this->any())->method('getScopeConfig')->willReturn($scopeConfig); + $context->expects($this->any())->method('getDesignPackage')->willReturn($design); + $context->expects($this->any())->method('getStoreManager')->willReturn($storeManager); + $context->expects($this->once())->method('getAppState')->willReturn($appState); $maliciousCode = $this->getMock( 'Magento\Framework\Filter\Input\MaliciousCode', @@ -108,9 +103,12 @@ class PreviewTest extends \PHPUnit_Framework_TestCase '', false ); - $maliciousCode->expects($this->once())->method('filter')->with($this->equalTo($requestParamMap[1][2])) - ->will($this->returnValue(self::MALICIOUS_TEXT)); + $maliciousCode->expects($this->once()) + ->method('filter') + ->with($this->equalTo($requestParamMap[1][2])) + ->willReturn(self::MALICIOUS_TEXT); + /** @var \Magento\Email\Block\Adminhtml\Template\Preview $preview */ $preview = $this->objectManagerHelper->getObject( 'Magento\Email\Block\Adminhtml\Template\Preview', [ diff --git a/app/code/Magento/Email/Test/Unit/Controller/Adminhtml/Email/Template/PreviewTest.php b/app/code/Magento/Email/Test/Unit/Controller/Adminhtml/Email/Template/PreviewTest.php new file mode 100644 index 0000000000000000000000000000000000000000..59fccebfe385890f7535394a0cb60f8c001feebd --- /dev/null +++ b/app/code/Magento/Email/Test/Unit/Controller/Adminhtml/Email/Template/PreviewTest.php @@ -0,0 +1,115 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Email\Test\Unit\Controller\Adminhtml\Email\Template; + +use Magento\Email\Controller\Adminhtml\Email\Template\Preview; +use Magento\Framework\App\Action\Context; +use Magento\Framework\App\RequestInterface; +use Magento\Framework\App\View; +use Magento\Framework\Registry; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Framework\View\Config; +use Magento\Framework\View\Page\Title; +use Magento\Framework\View\Result\Page; + +/** + * Preview Test + */ +class PreviewTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var Preview + */ + protected $object; + + /** + * @var Context + */ + protected $context; + + /** + * @var Registry|\PHPUnit_Framework_MockObject_MockObject + */ + protected $coreRegistryMock; + + /** + * @var View|\PHPUnit_Framework_MockObject_MockObject + */ + protected $viewMock; + + /** + * @var RequestInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $requestMock; + + /** + * @var Page|\PHPUnit_Framework_MockObject_MockObject + */ + protected $pageMock; + + /** + * @var Config|\PHPUnit_Framework_MockObject_MockObject + */ + protected $pageConfigMock; + + /** + * @var Title|\PHPUnit_Framework_MockObject_MockObject + */ + protected $pageTitleMock; + + protected function setUp() + { + $objectManager = new ObjectManager($this); + + $this->coreRegistryMock = $this->getMockBuilder('Magento\Framework\Registry') + ->disableOriginalConstructor() + ->getMock(); + $this->viewMock = $this->getMockBuilder('Magento\Framework\App\View') + ->disableOriginalConstructor() + ->getMock(); + $this->requestMock = $this->getMockBuilder('Magento\Framework\App\RequestInterface') + ->getMock(); + $this->pageMock = $this->getMockBuilder('Magento\Framework\View\Result\Page') + ->disableOriginalConstructor() + ->setMethods(['getConfig']) + ->getMock(); + $this->pageConfigMock = $this->getMockBuilder('Magento\Framework\View\Page\Config') + ->setMethods(['getTitle']) + ->disableOriginalConstructor() + ->getMock(); + $this->pageTitleMock = $this->getMockBuilder('Magento\Framework\View\Page\Title') + ->setMethods(['prepend']) + ->disableOriginalConstructor() + ->getMock(); + + $this->context = $objectManager->getObject('Magento\Backend\App\Action\Context', [ + 'request' => $this->requestMock, + 'view' => $this->viewMock + ]); + $this->object = $objectManager->getObject('Magento\Email\Controller\Adminhtml\Email\Template\Preview', [ + 'context' => $this->context, + 'coreRegistry' => $this->coreRegistryMock, + ]); + } + + public function testExecute() + { + $this->viewMock->expects($this->once()) + ->method('getPage') + ->willReturn($this->pageMock); + $this->pageMock->expects($this->once()) + ->method('getConfig') + ->willReturn($this->pageConfigMock); + $this->pageConfigMock->expects($this->once()) + ->method('getTitle') + ->willReturn($this->pageTitleMock); + $this->pageTitleMock->expects($this->once()) + ->method('prepend') + ->willReturnSelf(); + + $this->assertNull($this->object->execute()); + } +} diff --git a/app/code/Magento/Email/view/adminhtml/layout/adminhtml_email_template_preview.xml b/app/code/Magento/Email/view/adminhtml/layout/adminhtml_email_template_preview.xml new file mode 100644 index 0000000000000000000000000000000000000000..242cda682c53ffda07febb0fe612d0b70aae3616 --- /dev/null +++ b/app/code/Magento/Email/view/adminhtml/layout/adminhtml_email_template_preview.xml @@ -0,0 +1,16 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="admin-1column" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd"> + <body> + <referenceContainer name="page.content"> + <block name="preview.page.content" class="Magento\Framework\View\Element\Template" template="Magento_Email::template/preview.phtml"> + <block class="Magento\Email\Block\Adminhtml\Template\Preview" name="content" as="content"/> + </block> + </referenceContainer> + </body> +</page> diff --git a/app/code/Magento/Email/view/adminhtml/layout/systemPreview.xml b/app/code/Magento/Email/view/adminhtml/layout/systemPreview.xml deleted file mode 100644 index f58984cc6ed62500df26595e7355357dcb713bab..0000000000000000000000000000000000000000 --- a/app/code/Magento/Email/view/adminhtml/layout/systemPreview.xml +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0"?> -<!-- -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<layout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/layout_generic.xsd"> - <container name="root"> - <block class="Magento\Framework\View\Element\Template" name="page.block" template="Magento_Email::template/preview.phtml"> - <block class="Magento\Email\Block\Adminhtml\Template\Preview" name="content" as="content"/> - </block> - </container> -</layout> diff --git a/app/code/Magento/Email/view/adminhtml/templates/template/preview.phtml b/app/code/Magento/Email/view/adminhtml/templates/template/preview.phtml index d54075edcb69bebe0854a65fd36359d4d82a95cc..c90ad26855528e3faf831ff36838cf3ba5add04e 100644 --- a/app/code/Magento/Email/view/adminhtml/templates/template/preview.phtml +++ b/app/code/Magento/Email/view/adminhtml/templates/template/preview.phtml @@ -3,6 +3,8 @@ * Copyright © 2015 Magento. All rights reserved. * See COPYING.txt for license details. */ + +/* @var $block \Magento\Email\Block\Adminhtml\Template\Preview */ ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html lang="en"> diff --git a/app/code/Magento/Marketplace/i18n/en_US.csv b/app/code/Magento/Marketplace/i18n/en_US.csv index e0a266e1291f3390c5baee7087ada17c1bcdf28a..8c1698ba3b1abe8ad5120033d8d2b25e56502596 100644 --- a/app/code/Magento/Marketplace/i18n/en_US.csv +++ b/app/code/Magento/Marketplace/i18n/en_US.csv @@ -1 +1,13 @@ +"Platinum Partners","Platinum Partners" +"Representing Magento's highest level of partner engagement, Magento Platinum Partners have established themselves as leaders and innovators of key products and services designed to help merchants and brands grow their business. Magento reserves the Platinum level for select trusted partners that are committed to offering integrations of commerce features, functions, and tools, as well as back-end systems and operations, to extend and enhance the power of the Magento commerce platform.","Representing Magento's highest level of partner engagement, Magento Platinum Partners have established themselves as leaders and innovators of key products and services designed to help merchants and brands grow their business. Magento reserves the Platinum level for select trusted partners that are committed to offering integrations of commerce features, functions, and tools, as well as back-end systems and operations, to extend and enhance the power of the Magento commerce platform." +"Featured Platinum Partners","Featured Platinum Partners" +"Partner search","Partner search" +"Magento has a thriving ecosystem of technology partners to help merchants and brands deliver the best possible customer experiences. They are recognized as experts in eCommerce, search, email marketing, payments, tax, fraud, optimization and analytics, fulfillment, and more. Visit the Magento Partner Directory to see all of our trusted partners.","Magento has a thriving ecosystem of technology partners to help merchants and brands deliver the best possible customer experiences. They are recognized as experts in eCommerce, search, email marketing, payments, tax, fraud, optimization and analytics, fulfillment, and more. Visit the Magento Partner Directory to see all of our trusted partners." +"More Partners","More Partners" +"Magento Marketplace","Magento Marketplace" +"Extensions and Themes are an essential component of the Magento Ecosystem. Please visit the Magento Marketplace to see the latest innovations that developers have created to enhance your Magento Store.","Extensions and Themes are an essential component of the Magento Ecosystem. Please visit the Magento Marketplace to see the latest innovations that developers have created to enhance your Magento Store." +"Visit Magento Marketplaces","Visit Magento Marketplaces" +"Read More","Read More" +"Partner Page","Partner Page" +"No partners were found","No partners were found" "Find Partners & Extensions","Find Partners & Extensions" diff --git a/app/code/Magento/Marketplace/view/adminhtml/templates/index.phtml b/app/code/Magento/Marketplace/view/adminhtml/templates/index.phtml index 53c60cf1d7a00bebac89179f49548b916811f8eb..4a2301057c6e576896001027351e90fc5a15b77f 100644 --- a/app/code/Magento/Marketplace/view/adminhtml/templates/index.phtml +++ b/app/code/Magento/Marketplace/view/adminhtml/templates/index.phtml @@ -3,21 +3,20 @@ * Copyright © 2015 Magento. All rights reserved. * See COPYING.txt for license details. */ + +// @codingStandardsIgnoreFile ?> <section class="page-partners"> - <h2 class="page-sub-title">Platinum Partners</h2> + <h2 class="page-sub-title"><?php /* @escapeNotVerified */ echo __('Platinum Partners'); ?></h2> <p class="partners-description"> - Representing Magento's highest level of partner engagement, - Magento Platinum Partners have established themselves as - leaders and innovators of key products and services designed - to help merchants and brands grow their business. Magento - reserves the Platinum level for select trusted partners that - are committed to offering integrations of commerce features, - functions, and tools, as well as back-end systems and operations, - to extend and enhance the power of the Magento commerce platform. + <?php /* @escapeNotVerified */ + echo __( + 'Representing Magento\'s highest level of partner engagement, Magento Platinum Partners have established themselves as leaders and innovators of key products and services designed to help merchants and brands grow their business. ' . + 'Magento reserves the Platinum level for select trusted partners that are committed to offering integrations of commerce features, functions, and tools, as well as back-end systems and operations, to extend and enhance the power of the Magento commerce platform.' + ); ?> </p> - <h3 class="page-sub-sub-title">Featured Platinum Partners</h3> + <h3 class="page-sub-sub-title"><?php /* @escapeNotVerified */ echo __('Featured Platinum Partners'); ?></h3> <div data-role="partners-block"> <div data-role="spinner" class="admin__data-grid-loading-mask" data-bind="visible: loading"> <div class="spinner"> @@ -30,19 +29,18 @@ <div class="row row-gutter partners-footer"> <div class="col-m-5"> <div class="partners-search"> - <h2 class="page-sub-title">Partner search</h2> + <h2 class="page-sub-title"><?php /* @escapeNotVerified */ echo __('Partner search'); ?></h2> <p> - Magento has a thriving ecosystem of technology partners to - help merchants and brands deliver the best possible - customer experiences. They are recognized as experts in - eCommerce, search, email marketing, payments, tax, - fraud, optimization and analytics, fulfillment, and more. - Visit the Magento Partner Directory to see all of - our trusted partners. + <?php /* @escapeNotVerified */ + echo __( + 'Magento has a thriving ecosystem of technology partners to help merchants and brands deliver the best possible customer experiences. ' . + 'They are recognized as experts in eCommerce, search, email marketing, payments, tax, fraud, optimization and analytics, fulfillment, and more. ' . + 'Visit the Magento Partner Directory to see all of our trusted partners.' + ); ?> </p> <a class="action-secondary" target="_blank" href="http://partners.magento.com/partner_locator/search.aspx"> - More Partners + <?php /* @escapeNotVerified */ echo __('More Partners'); ?> </a> </div> </div> @@ -55,16 +53,16 @@ alt="Partner"/> </div> <div class="col-m-4"> - <h2 class="page-sub-title">Magento Marketplace</h2> + <h2 class="page-sub-title"><?php /* @escapeNotVerified */ echo __('Magento Marketplace'); ?></h2> <p class="partner-description"> - Extensions and Themes are an essential component of the Magento - Ecosystem. Please visit the Magento Marketplace - to see the latest innovations that developers - have created to enhance your Magento Store. + <?php /* @escapeNotVerified */ echo __( + 'Extensions and Themes are an essential component of the Magento Ecosystem. ' . + 'Please visit the Magento Marketplace to see the latest innovations that developers have created to enhance your Magento Store.' + ); ?> </p> <a class="action-secondary" target="_blank" href="http://www.magentocommerce.com/magento-connect/"> - Visit Magento Marketplaces + <?php /* @escapeNotVerified */ echo __('Visit Magento Marketplaces'); ?> </a> </div> </div> diff --git a/app/code/Magento/Marketplace/view/adminhtml/templates/partners.phtml b/app/code/Magento/Marketplace/view/adminhtml/templates/partners.phtml index ae31e3005513a88478cae04b1435f00616856ad3..7787b9d33a47da2879d700d15aeb0ddd657409f9 100644 --- a/app/code/Magento/Marketplace/view/adminhtml/templates/partners.phtml +++ b/app/code/Magento/Marketplace/view/adminhtml/templates/partners.phtml @@ -23,11 +23,11 @@ $partners = $block->getPartners(); <?php echo $block->escapeHtml($partner['description']);?> <br /> <a href="<?php echo $block->escapeHtml($partner['url_page']);?>" target="_blank"> - Read More + <?php /* @escapeNotVerified */ echo __('Read More'); ?> </a> <br /> <a href="<?php echo $block->escapeHtml($partner['url_partner_page']);?>" target="_blank"> - Partner Page + <?php /* @escapeNotVerified */ echo __('Partner Page'); ?> </a> </p> </div> @@ -35,6 +35,6 @@ $partners = $block->getPartners(); </div> <?php else : ?> <p> - No partners were found + <?php /* @escapeNotVerified */ echo __('No partners were found'); ?> </p> <?php endif; ?> diff --git a/app/code/Magento/Multishipping/view/frontend/layout/multishipping_checkout.xml b/app/code/Magento/Multishipping/view/frontend/layout/multishipping_checkout.xml index 097574d31074727178ac7c858fbccd10ee295b24..46ec2dcccadd71ea6de1922c03f0cdfd42259fe8 100644 --- a/app/code/Magento/Multishipping/view/frontend/layout/multishipping_checkout.xml +++ b/app/code/Magento/Multishipping/view/frontend/layout/multishipping_checkout.xml @@ -7,6 +7,24 @@ --> <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="2columns-left" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd" label="Multishipping Checkout" design_abstraction="custom"> <body> + <referenceBlock name="authentication-popup"> + <arguments> + <argument name="jsLayout" xsi:type="array"> + <item name="components" xsi:type="array"> + <item name="authenticationPopup" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="captcha" xsi:type="array"> + <item name="component" xsi:type="string">Magento_Captcha/js/view/checkout/loginCaptcha</item> + <item name="displayArea" xsi:type="string">additional-login-form-fields</item> + <item name="formId" xsi:type="string">user_login</item> + <item name="configSource" xsi:type="string">authenticationPopup</item> + </item> + </item> + </item> + </item> + </argument> + </arguments> + </referenceBlock> <referenceContainer name="sidebar.main"> <block class="Magento\Multishipping\Block\Checkout\State" name="checkout_state" template="checkout/state.phtml" cacheable="false"/> </referenceContainer> diff --git a/app/code/Magento/Sales/Helper/Guest.php b/app/code/Magento/Sales/Helper/Guest.php index baf3512eed4c3019f589b641364d3f31200e57e3..a69fa337b8da2c19710a94c655a64aa165b6abf0 100644 --- a/app/code/Magento/Sales/Helper/Guest.php +++ b/app/code/Magento/Sales/Helper/Guest.php @@ -139,8 +139,9 @@ class Guest extends \Magento\Framework\App\Helper\AbstractHelper $lastName = $post['oar_billing_lastname']; $email = $post['oar_email']; $zip = $post['oar_zip']; + $storeId = $this->_storeManager->getStore()->getId(); - if (empty($incrementId) || empty($lastName) || empty($type) || !in_array( + if (empty($incrementId) || empty($lastName) || empty($type) || empty($storeId) || !in_array( $type, ['email', 'zip'] ) || $type == 'email' && empty($email) || $type == 'zip' && empty($zip) @@ -149,7 +150,7 @@ class Guest extends \Magento\Framework\App\Helper\AbstractHelper } if (!$errors) { - $order->loadByIncrementId($incrementId); + $order = $order->loadByIncrementIdAndStoreId($incrementId, $storeId); } $errors = true; diff --git a/app/code/Magento/Sales/Model/Order.php b/app/code/Magento/Sales/Model/Order.php index e53438bd6844b88d4a9f91fefb81da78d5ae7f07..e289e654b98d6c7c22b5de527e175ea5e610eca2 100644 --- a/app/code/Magento/Sales/Model/Order.php +++ b/app/code/Magento/Sales/Model/Order.php @@ -252,6 +252,11 @@ class Order extends AbstractModel implements EntityInterface, OrderInterface */ protected $_trackCollectionFactory; + /** + * @var \Magento\Sales\Model\ResourceModel\Order\CollectionFactory + */ + protected $salesOrderCollectionFactory; + /** * @var PriceCurrencyInterface */ @@ -284,6 +289,7 @@ class Order extends AbstractModel implements EntityInterface, OrderInterface * @param \Magento\Sales\Model\ResourceModel\Order\Shipment\CollectionFactory $shipmentCollectionFactory * @param \Magento\Sales\Model\ResourceModel\Order\Creditmemo\CollectionFactory $memoCollectionFactory * @param \Magento\Sales\Model\ResourceModel\Order\Shipment\Track\CollectionFactory $trackCollectionFactory + * @param ResourceModel\Order\CollectionFactory $salesOrderCollectionFactory * @param PriceCurrencyInterface $priceCurrency * @param \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $productListFactory * @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource @@ -313,6 +319,7 @@ class Order extends AbstractModel implements EntityInterface, OrderInterface \Magento\Sales\Model\ResourceModel\Order\Shipment\CollectionFactory $shipmentCollectionFactory, \Magento\Sales\Model\ResourceModel\Order\Creditmemo\CollectionFactory $memoCollectionFactory, \Magento\Sales\Model\ResourceModel\Order\Shipment\Track\CollectionFactory $trackCollectionFactory, + \Magento\Sales\Model\ResourceModel\Order\CollectionFactory $salesOrderCollectionFactory, PriceCurrencyInterface $priceCurrency, \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $productListFactory, \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null, @@ -337,6 +344,7 @@ class Order extends AbstractModel implements EntityInterface, OrderInterface $this->_shipmentCollectionFactory = $shipmentCollectionFactory; $this->_memoCollectionFactory = $memoCollectionFactory; $this->_trackCollectionFactory = $trackCollectionFactory; + $this->salesOrderCollectionFactory = $salesOrderCollectionFactory; $this->priceCurrency = $priceCurrency; parent::__construct( $context, @@ -435,6 +443,40 @@ class Order extends AbstractModel implements EntityInterface, OrderInterface return $this->loadByAttribute('increment_id', $incrementId); } + /** + * Load order by system increment and store identifiers + * + * @param string $incrementId + * @param string $storeId + * @return \Magento\Sales\Model\Order + */ + public function loadByIncrementIdAndStoreId($incrementId, $storeId) + { + $orderCollection = $this->getSalesOrderCollection( + [ + 'increment_id' => $incrementId, + 'store_id' => $storeId + ] + ); + return $orderCollection->getFirstItem(); + } + + /** + * Get sales Order collection model populated with data + * + * @param array $filters + * @return \Magento\Sales\Model\ResourceModel\Order\Collection + */ + protected function getSalesOrderCollection(array $filters = []) + { + /** @var \Magento\Sales\Model\ResourceModel\Order\Collection $salesOrderCollection */ + $salesOrderCollection = $this->salesOrderCollectionFactory->create(); + foreach ($filters as $field => $condition) { + $salesOrderCollection->addFieldToFilter($field, $condition); + } + return $salesOrderCollection->load(); + } + /** * Load order by custom attribute value. Attribute value should be unique * diff --git a/app/code/Magento/Sales/Test/Unit/Helper/GuestTest.php b/app/code/Magento/Sales/Test/Unit/Helper/GuestTest.php index 208fc66106dfbf91b2044c7c4b54b0f61a37dfab..6772ac7276d6895cf3b817333ae42e68b8724dc9 100644 --- a/app/code/Magento/Sales/Test/Unit/Helper/GuestTest.php +++ b/app/code/Magento/Sales/Test/Unit/Helper/GuestTest.php @@ -3,15 +3,12 @@ * Copyright © 2015 Magento. All rights reserved. * See COPYING.txt for license details. */ - namespace Magento\Sales\Test\Unit\Helper; -use \Magento\Sales\Helper\Guest; - +use Magento\Sales\Helper\Guest; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; /** - * Class GuestTest * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class GuestTest extends \PHPUnit_Framework_TestCase @@ -49,6 +46,12 @@ class GuestTest extends \PHPUnit_Framework_TestCase /** @var \Magento\Framework\App\ViewInterface|\PHPUnit_Framework_MockObject_MockObject */ protected $viewInterfaceMock; + /** @var \Magento\Store\Model\Store|\PHPUnit_Framework_MockObject_MockObject */ + protected $storeModelMock; + + /** @var \Magento\Sales\Model\Order|\PHPUnit_Framework_MockObject_MockObject */ + protected $salesOrderMock; + protected function setUp() { $this->appContextHelperMock = $this->getMock('Magento\Framework\App\Helper\Context', [], [], '', false); @@ -66,6 +69,19 @@ class GuestTest extends \PHPUnit_Framework_TestCase $this->managerInterfaceMock = $this->getMock('Magento\Framework\Message\ManagerInterface'); $this->orderFactoryMock = $this->getMock('Magento\Sales\Model\OrderFactory', ['create'], [], '', false); $this->viewInterfaceMock = $this->getMock('Magento\Framework\App\ViewInterface'); + $this->storeModelMock = $this->getMockBuilder('Magento\Store\Model\Store') + ->disableOriginalConstructor() + ->getMock(); + $this->salesOrderMock = $this->getMock( + 'Magento\Sales\Model\Order', + [ + 'getProtectCode', 'loadByIncrementIdAndStoreId', 'loadByIncrementId', + 'getId', 'getBillingAddress', '__wakeup' + ], + [], + '', + false + ); $this->objectManagerHelper = new ObjectManagerHelper($this); $this->guest = $this->objectManagerHelper->getObject( @@ -86,8 +102,6 @@ class GuestTest extends \PHPUnit_Framework_TestCase public function testLoadValidOrderNotEmptyPost() { - $this->sessionMock->expects($this->once())->method('isLoggedIn')->will($this->returnValue(false)); - $post = [ 'oar_order_id' => 1, 'oar_type' => 'email', @@ -96,20 +110,17 @@ class GuestTest extends \PHPUnit_Framework_TestCase 'oar_zip' => 'oar_zip', ]; + $storeId = '1'; $incrementId = $post['oar_order_id']; + $protectedCode = 'protectedCode'; + $this->sessionMock->expects($this->once())->method('isLoggedIn')->willReturn(false); $requestMock = $this->getMock('Magento\Framework\App\Request\Http', [], [], '', false); - $requestMock->expects($this->once())->method('getPostValue')->will($this->returnValue($post)); - - $orderMock = $this->getMock( - 'Magento\Sales\Model\Order', - ['getProtectCode', 'loadByIncrementId', 'getId', 'getBillingAddress', '__wakeup'], - [], - '', - false - ); - $this->orderFactoryMock->expects($this->once())->method('create')->will($this->returnValue($orderMock)); - $orderMock->expects($this->once())->method('loadByIncrementId')->with($incrementId); - $orderMock->expects($this->exactly(2))->method('getId')->will($this->returnValue($incrementId)); + $requestMock->expects($this->once())->method('getPostValue')->willReturn($post); + $this->storeManagerInterfaceMock->expects($this->once())->method('getStore')->willReturn($this->storeModelMock); + $this->storeModelMock->expects($this->once())->method('getId')->willReturn($storeId); + $this->orderFactoryMock->expects($this->once())->method('create')->willReturn($this->salesOrderMock); + $this->salesOrderMock->expects($this->once())->method('loadByIncrementIdAndStoreId')->willReturnSelf(); + $this->salesOrderMock->expects($this->any())->method('getId')->willReturn($incrementId); $billingAddressMock = $this->getMock( 'Magento\Sales\Model\Order\Address', @@ -118,15 +129,10 @@ class GuestTest extends \PHPUnit_Framework_TestCase '', false ); - $billingAddressMock->expects($this->once())->method('getLastname')->will( - $this->returnValue($post['oar_billing_lastname']) - ); - $billingAddressMock->expects($this->once())->method('getEmail')->will( - $this->returnValue($post['oar_email']) - ); - $orderMock->expects($this->once())->method('getBillingAddress')->will($this->returnValue($billingAddressMock)); - $protectedCode = 'protectedCode'; - $orderMock->expects($this->once())->method('getProtectCode')->will($this->returnValue($protectedCode)); + $billingAddressMock->expects($this->once())->method('getLastname')->willReturn(($post['oar_billing_lastname'])); + $billingAddressMock->expects($this->once())->method('getEmail')->willReturn(($post['oar_email'])); + $this->salesOrderMock->expects($this->once())->method('getBillingAddress')->willReturn($billingAddressMock); + $this->salesOrderMock->expects($this->once())->method('getProtectCode')->willReturn($protectedCode); $metaDataMock = $this->getMock( 'Magento\Framework\Stdlib\Cookie\PublicCookieMetadata', [], @@ -134,17 +140,16 @@ class GuestTest extends \PHPUnit_Framework_TestCase '', false ); - $metaDataMock->expects($this->once()) - ->method('setPath') + $metaDataMock->expects($this->once())->method('setPath') ->with(Guest::COOKIE_PATH) - ->will($this->returnSelf()); + ->willReturnSelf(); $metaDataMock->expects($this->once()) ->method('setHttpOnly') ->with(true) - ->will($this->returnSelf()); + ->willReturnSelf(); $this->cookieMetadataFactoryMock->expects($this->once()) ->method('createPublicCookieMetadata') - ->will($this->returnValue($metaDataMock)); + ->willReturn($metaDataMock); $this->cookieManagerMock->expects($this->once()) ->method('setPublicCookie') ->with(Guest::COOKIE_NAME, $this->anything(), $metaDataMock); @@ -153,26 +158,22 @@ class GuestTest extends \PHPUnit_Framework_TestCase public function testLoadValidOrderStoredCookie() { - $this->sessionMock->expects($this->once())->method('isLoggedIn')->will($this->returnValue(false)); - $orderMock = $this->getMock( - 'Magento\Sales\Model\Order', - ['getProtectCode', 'loadByIncrementId', 'getId', 'getBillingAddress', '__wakeup'], - [], - '', - false - ); $protectedCode = 'protectedCode'; $incrementId = 1; $cookieData = $protectedCode . ':' . $incrementId; $cookieDataHash = base64_encode($cookieData); - $this->orderFactoryMock->expects($this->once())->method('create')->will($this->returnValue($orderMock)); - - $this->cookieManagerMock->expects($this->once())->method('getCookie')->with(Guest::COOKIE_NAME)->will( - $this->returnValue($cookieDataHash) - ); - $orderMock->expects($this->once())->method('loadByIncrementId')->with($incrementId); - $orderMock->expects($this->exactly(1))->method('getId')->will($this->returnValue($incrementId)); - $orderMock->expects($this->once())->method('getProtectCode')->will($this->returnValue($protectedCode)); + $this->sessionMock->expects($this->once())->method('isLoggedIn')->willReturn(false); + $this->orderFactoryMock->expects($this->once())->method('create')->willReturn($this->salesOrderMock); + $this->cookieManagerMock->expects($this->once()) + ->method('getCookie') + ->with(Guest::COOKIE_NAME) + ->willReturn($cookieDataHash); + $this->salesOrderMock->expects($this->once()) + ->method('loadByIncrementId') + ->with($incrementId) + ->willReturnSelf(); + $this->salesOrderMock->expects($this->exactly(1))->method('getId')->willReturn($incrementId); + $this->salesOrderMock->expects($this->once())->method('getProtectCode')->willReturn($protectedCode); $metaDataMock = $this->getMock( 'Magento\Framework\Stdlib\Cookie\PublicCookieMetadata', [], @@ -183,18 +184,17 @@ class GuestTest extends \PHPUnit_Framework_TestCase $metaDataMock->expects($this->once()) ->method('setPath') ->with(Guest::COOKIE_PATH) - ->will($this->returnSelf()); + ->willReturnSelf(); $metaDataMock->expects($this->once()) ->method('setHttpOnly') ->with(true) - ->will($this->returnSelf()); + ->willReturnSelf(); $this->cookieMetadataFactoryMock->expects($this->once()) ->method('createPublicCookieMetadata') - ->will($this->returnValue($metaDataMock)); + ->willReturn($metaDataMock); $this->cookieManagerMock->expects($this->once()) ->method('setPublicCookie') ->with(Guest::COOKIE_NAME, $this->anything(), $metaDataMock); - $requestMock = $this->getMock('Magento\Framework\App\Request\Http', [], [], '', false); $this->assertTrue($this->guest->loadValidOrder($requestMock)); } diff --git a/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php b/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php index e334be584109f0df3fda0bb7d0ef2c62296107f6..7ed438f3ce7f129fbec4fd2d61723d6ff17803b4 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php @@ -5,8 +5,7 @@ */ namespace Magento\Sales\Test\Unit\Model; -use \Magento\Sales\Model\Order; - +use Magento\Sales\Model\Order; use Magento\Sales\Model\ResourceModel\Order\Status\History\CollectionFactory as HistoryCollectionFactory; /** @@ -54,6 +53,16 @@ class OrderTest extends \PHPUnit_Framework_TestCase */ protected $priceCurrency; + /** + * @var \Magento\Sales\Model\ResourceModel\Order\CollectionFactory|\PHPUnit_Framework_MockObject_MockObject + */ + protected $salesOrderCollectionFactoryMock; + + /** + * @var \Magento\Sales\Model\ResourceModel\Order\Collection|\PHPUnit_Framework_MockObject_MockObject + */ + protected $salesOrderCollectionMock; + protected function setUp() { $helper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); @@ -78,6 +87,13 @@ class OrderTest extends \PHPUnit_Framework_TestCase '', false ); + $this->salesOrderCollectionFactoryMock = $this->getMock( + 'Magento\Sales\Model\ResourceModel\Order\CollectionFactory', + ['create'], + [], + '', + false + ); $this->item = $this->getMock( 'Magento\Sales\Model\ResourceModel\Order\Item', ['isDeleted', 'getQtyToInvoice', 'getParentItemId', 'getQuoteItemId', 'getLockedDoInvoice'], @@ -85,6 +101,10 @@ class OrderTest extends \PHPUnit_Framework_TestCase '', false ); + $this->salesOrderCollectionMock = $this->getMockBuilder('Magento\Sales\Model\ResourceModel\Order\Collection') + ->disableOriginalConstructor() + ->setMethods(['addFieldToFilter', 'load', 'getFirstItem']) + ->getMock(); $collection = $this->getMock('Magento\Sales\Model\ResourceModel\Order\Item\Collection', [], [], '', false); $collection->expects($this->any()) ->method('setOrderFilter') @@ -121,6 +141,7 @@ class OrderTest extends \PHPUnit_Framework_TestCase 'data' => ['increment_id' => $this->incrementId], 'context' => $context, 'historyCollectionFactory' => $this->historyCollectionFactoryMock, + 'salesOrderCollectionFactory' => $this->salesOrderCollectionFactoryMock, 'priceCurrency' => $this->priceCurrency ] ); @@ -722,6 +743,20 @@ class OrderTest extends \PHPUnit_Framework_TestCase } } + public function testLoadByIncrementIdAndStoreId() + { + $incrementId = '000000001'; + $storeId = '2'; + $this->salesOrderCollectionFactoryMock + ->expects($this->once()) + ->method('create') + ->willReturn($this->salesOrderCollectionMock); + $this->salesOrderCollectionMock->expects($this->any())->method('addFieldToFilter')->willReturnSelf(); + $this->salesOrderCollectionMock->expects($this->once())->method('load')->willReturnSelf(); + $this->salesOrderCollectionMock->expects($this->once())->method('getFirstItem')->willReturn($this->order); + $this->assertSame($this->order, $this->order->loadByIncrementIdAndStoreId($incrementId, $storeId)); + } + public function notInvoicingStatesProvider() { return [ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/components/_file-insertion.less b/app/design/adminhtml/Magento/backend/web/css/source/components/_file-insertion.less index cdc66d477555dc532e9f3d9d264c6df18ad0a131..9dd4fec9c3c71d7638c283fd18d0f4eddfa5a483 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/components/_file-insertion.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/components/_file-insertion.less @@ -18,7 +18,7 @@ display: none; } input { - -moz-transforms: none; + -moz-transform: none; border: none; opacity: 1; position: static; diff --git a/app/design/frontend/Magento/blank/Magento_Catalog/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_Catalog/web/css/source/_module.less index d65fc3090a9fa3be0da8cb586092370826853fee..67d9400be23c9caf497a7977364bf16942a70928 100644 --- a/app/design/frontend/Magento/blank/Magento_Catalog/web/css/source/_module.less +++ b/app/design/frontend/Magento/blank/Magento_Catalog/web/css/source/_module.less @@ -558,9 +558,12 @@ .product-info-main { float: right; } + .product.media { float: left; + margin-bottom: @indent__m; } + .page-layout-1column { .product-info-main { width: 40%; @@ -569,6 +572,7 @@ width: 57%; } } + .page-layout-2columns-left, .page-layout-2columns-right, .page-layout-3columns { diff --git a/app/design/frontend/Magento/blank/Magento_Catalog/web/css/source/module/_toolbar.less b/app/design/frontend/Magento/blank/Magento_Catalog/web/css/source/module/_toolbar.less index 95ae194085ad27548b7e7384351409c9f8424e31..c6e638f56f4506159a5971a0f24c7e06ed65730b 100644 --- a/app/design/frontend/Magento/blank/Magento_Catalog/web/css/source/module/_toolbar.less +++ b/app/design/frontend/Magento/blank/Magento_Catalog/web/css/source/module/_toolbar.less @@ -4,105 +4,109 @@ // */ // -// Common -//-------------------------------------- +// Common +// _____________________________________________ @toolbar-mode-icon-font-size: 24px; @toolbar-element-background: @panel__background-color; & when (@media-common = true) { -.page-products .columns { - position: relative; - z-index: 1; -} - -.toolbar { - &:extend(.abs-add-clearfix all); - &-amount { - display: block; - line-height: @toolbar-mode-icon-font-size+2; - padding: 8px 0 0; - margin: 0; - vertical-align: middle; - .products.wrapper ~ .toolbar & { - display: none; + .page-products { + .columns { + position: relative; + z-index: 1; } } - &-products { - margin-bottom: @indent__xl; - text-align: center; - padding: 0 @indent__s; + + .toolbar { &:extend(.abs-add-clearfix all); - .pages { - display: none; - .products.wrapper ~ & { - display: block; + &-amount { + display: block; + line-height: @toolbar-mode-icon-font-size+2; + margin: 0; + padding: 8px 0 0; + vertical-align: middle; + .products.wrapper ~ .toolbar & { + display: none; } } - .limiter { - display: none; - .control { - display: inline-block; + &-products { + margin-bottom: @indent__xl; + padding: 0 @indent__s; + text-align: center; + &:extend(.abs-add-clearfix all); + .pages { + display: none; + .products.wrapper ~ & { + display: block; + } + } + .limiter { + display: none; + .control { + display: inline-block; + } } } } -} -.sorter { - padding: 4px 0 0; - .products.wrapper ~ .toolbar & { - display: none; - } - &-options { - margin: 0 0 0 7px; - width: auto; - } - &-action { - vertical-align: top; - .lib-icon-font( + .sorter { + padding: 4px 0 0; + .products.wrapper ~ .toolbar & { + display: none; + } + &-options { + margin: 0 0 0 7px; + width: auto; + } + &-action { + vertical-align: top; + .lib-icon-font( @icon-arrow-up, @_icon-font-size: 28px, @_icon-font-line-height: 32px, @_icon-font-color: @header-icons-color, @_icon-font-color-hover: @header-icons-color-hover, @_icon-font-text-hide: true - ); - &.sort-desc:before { - content: @icon-arrow-down; + ); + &.sort-desc:before { + content: @icon-arrow-down; + } } } -} -.modes { - display: none; -} - -.limiter { - &-options { - width: auto; - margin: 0 5px 0 7px; - } - &-label { - font-weight: 400; - } - .page-products .toolbar & { + .modes { display: none; } -} + .limiter { + &-options { + width: auto; + margin: 0 5px 0 7px; + } + &-label { + font-weight: 400; + } + .page-products .toolbar & { + display: none; + } + } } // -// Mobile -// --------------------------------------------- +// Desctop +// _____________________________________________ .media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__s) { - .page-products .columns { - position: relative; - z-index: 1; - padding-top: 0; + .page-products { + .columns { + padding-top: 0; + position: relative; + z-index: 1; + } } + .toolbar { .products.wrapper ~ & .pages { float: left; @@ -111,19 +115,24 @@ float: left; } } + .sorter { float: right; } + .modes { - float: left; display: inline-block; + float: left; margin-right: @indent__base; + .products.wrapper ~ .toolbar & { display: none; } + &-label { &:extend(.abs-visually-hidden-desktop-s all); } + &-mode { .lib-css(color, @text__color__muted); border: 1px solid @border-color__base; @@ -134,8 +143,8 @@ padding: 7px 10px; text-align: center; &:not(.active):hover { - background: darken(@toolbar-element-background, 7%); .lib-css(color, @text__color__muted); + background: darken(@toolbar-element-background, 7%); } &:last-child { border-right: 1px solid @border-color__base; @@ -144,15 +153,19 @@ .lib-css(color, @primary__color__light); } .lib-icon-font( - @icon-grid, - @_icon-font-size: @toolbar-mode-icon-font-size, - @_icon-font-text-hide: true + @icon-grid, + @_icon-font-size: @toolbar-mode-icon-font-size, + @_icon-font-text-hide: true, + @_icon-font-color: @text__color__muted, + @_icon-font-color-hover: @text__color__muted ); } } + .mode-list { .lib-icon-font-symbol(@icon-list); } + .limiter { float: right; .products.wrapper ~ .toolbar & { diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_minicart.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_minicart.less index fb76486d5287a9bc062e141fbc6a5c3dcfd6ed30..a0396d053157fe30fb27526c8b5bd458faa300e2 100644 --- a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_minicart.less +++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_minicart.less @@ -49,8 +49,6 @@ } .subtitle { display: none; - } - .subtitle { &.empty { display: block; font-size: 14px; @@ -124,10 +122,14 @@ right: 26px; } } - .product.actions { - text-align: right; - > .primary, > .secondary { - display: inline; + .product { + .actions { + float: right; + margin: -24px 0 0; + text-align: right; + > .primary, > .secondary { + display: inline; + } } } @@ -165,7 +167,7 @@ text-align: center; white-space: normal; &.empty { - &:extend(.abs-no-display all); + display: none; } .loader { > img { @@ -184,8 +186,8 @@ } .minicart-items-wrapper { - .lib-css(margin, 0 -@minicart__padding-horizontal); .lib-css(border, 1px solid @minicart__border-color); + .lib-css(margin, 0 -@minicart__padding-horizontal); border-left: 0; border-right: 0; overflow-x: auto; @@ -301,12 +303,12 @@ text-align: center; width: 40px; } - .item-update { + .update-cart-item { .lib-font-size(11); vertical-align: top; } .subtitle { - &:extend(.abs-no-display all); + display: none; } .action { &.edit, diff --git a/app/design/frontend/Magento/blank/Magento_LayeredNavigation/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_LayeredNavigation/web/css/source/_module.less index c51aac33382940011e165490c0ca0eae85451536..47ac371e1cdf5d8544ec77ca6ba5d37d0af66081 100644 --- a/app/design/frontend/Magento/blank/Magento_LayeredNavigation/web/css/source/_module.less +++ b/app/design/frontend/Magento/blank/Magento_LayeredNavigation/web/css/source/_module.less @@ -11,68 +11,69 @@ .block.filter { margin-bottom: @indent__xl ; - .title { + .filter-title { margin-bottom: @indent__base; strong { font-size: 18px; } } - .subtitle { - display: none; + } + .filter-subtitle { + display: none; + } + + .filter-options-content { + .filter-count-label { + &:extend(.abs-visually-hidden all); } - .filter-options-content { - .filter-count-label { - &:extend(.abs-visually-hidden all); - } + } + .filter-options { + margin: 0; + > dt { + .lib-heading(h4); + margin: 0 0 @indent__s; } - .options { - margin: 0; - > dt { - .lib-heading(h4); - margin: 0 0 @indent__s; - } - > dd { - margin: 0 0 @indent__m; + > dd { + margin: 0 0 @indent__m; - .item { - margin-bottom: 3px; - } + .item { + margin-bottom: 3px; } - .count { - .lib-css(color, @text__color__muted); - &:before { - content: '('; - } - &:after { - content: ')'; - } + } + .count { + .lib-css(color, @text__color__muted); + &:before { + content: '('; + } + &:after { + content: ')'; } } + } + .items { + &:extend(.abs-reset-list all); + } + .filtered { .items { - &:extend(.abs-reset-list all); + margin: 15px 0; } - .filtered { - .items { - margin: 15px 0; + .item { + position: relative; + padding-left: 22px; + margin-bottom: 6px; + .label { + font-weight: @font-weight__bold; } - .item { - margin-bottom: 6px; - padding-left: 22px; - position: relative; - .label { - font-weight: @font-weight__bold; - } - .action.remove { - &:extend(.abs-remove-button-for-blocks all); - left: -6px; - position: absolute; - top: 0; - } - } - & + .actions { - margin-bottom: 35px; + .action.remove { + &:extend(.abs-remove-button-for-blocks all); + position: absolute; + left: -6px; + top: 0; } } + & + .actions { + margin-bottom: 35px; + } } } diff --git a/app/design/frontend/Magento/blank/Magento_Multishipping/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_Multishipping/web/css/source/_module.less index fd2eb640f58f3ace9e12477cf2240860b0acf476..9e80d9980430ed01de7bb2867a93612cc7e86ad0 100644 --- a/app/design/frontend/Magento/blank/Magento_Multishipping/web/css/source/_module.less +++ b/app/design/frontend/Magento/blank/Magento_Multishipping/web/css/source/_module.less @@ -253,8 +253,8 @@ margin-bottom: @indent__m; } > .primary { - margin-right: 0; margin-bottom: @indent__m; + margin-right: 0; } } } @@ -295,9 +295,19 @@ width: 25%; } .box-shipping-method { - padding-right: @indent__m; padding-left: @indent__m; + padding-right: @indent__m; width: 50%; + .fieldset { + .legend { + &:extend(.abs-reset-left-margin-desktop-s all); + } + .field { + &:before { + display: none; + } + } + } } } diff --git a/app/design/frontend/Magento/blank/Magento_Wishlist/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_Wishlist/web/css/source/_module.less index 506bbbd71fe10f26fa97847a9ff1575c4e622e57..49720b30a2cf62c57dbcf5d3fb19bdde080b2063 100644 --- a/app/design/frontend/Magento/blank/Magento_Wishlist/web/css/source/_module.less +++ b/app/design/frontend/Magento/blank/Magento_Wishlist/web/css/source/_module.less @@ -4,143 +4,143 @@ // */ // -// Common -//-------------------------------------- +// Common +// _____________________________________________ & when (@media-common = true) { -.form.wishlist.items { - .actions-toolbar { - &:extend(.abs-reset-left-margin all); + .form.wishlist.items { + .actions-toolbar { + &:extend(.abs-reset-left-margin all); + } } -} -.product-info-main, -.product-options-bottom, -.block-bundle-summary { - .action.towishlist { - &:extend(.abs-action-addto-product all); + .product-info-main, + .product-options-bottom, + .block-bundle-summary { + .action.towishlist { + &:extend(.abs-action-addto-product all); + } } -} -.products.list.items, -.table-comparison { - .action { - &.towishlist { - &:extend(.abs-actions-addto-gridlist all); - .lib-icon-font-symbol( - @icon-wishlist-empty - ); + .products.list.items, + .table-comparison { + .action { + &.towishlist { + &:extend(.abs-actions-addto-gridlist all); + .lib-icon-font-symbol( + @icon-wishlist-empty + ); + } } } -} -.account .table-wrapper .data.table.wishlist { - .lib-table-bordered( - @_table_type: horizontal - ); - thead > tr > th { - border-bottom: 0; - } - tbody > tr:last-child > td { - border-bottom: 1px solid @table__border-color; - } - .product.name { - display: inline-block; - margin-bottom: @indent__s; - } - .box-tocart { - margin: @indent__s 0; - .qty { - vertical-align: middle; - &:extend(.abs-input-qty all); + .account .table-wrapper .data.table.wishlist { + .lib-table-bordered( + @_table_type: horizontal + ); + thead > tr > th { + border-bottom: 0; } - } - .col { - &.item { - width: 50%; + tbody > tr:last-child > td { + border-bottom: 1px solid @table__border-color; } - &.photo { - max-width: 150px; + .product.name { + display: inline-block; + margin-bottom: @indent__s; } - &.selector { - max-width: 15px; + .box-tocart { + margin: @indent__s 0; + .qty { + vertical-align: middle; + &:extend(.abs-input-qty all); + } + } + .col { + &.item { + width: 50%; + } + &.photo { + max-width: 150px; + } + &.selector { + max-width: 15px; + } + } + textarea { + margin: @indent__s 0; + } + .input-text.qty { + margin-bottom: @indent__s; + } + .action.primary { + vertical-align: top; + } + .price { + font-weight: @font-weight__bold; } } - textarea { - margin: 10px 0; - } - .input-text.qty { - margin-bottom: 10px; - } - .action.primary { - vertical-align: top; - } - .price { - font-weight: @font-weight__bold; - } -} -.block-wishlist { - .block-title { - &:extend(.abs-block-title all); - } - .counter { - &:extend(.abs-block-items-counter all); - } - .product-item-name { - margin-right: @indent__m; + .block-wishlist { + .block-title { + &:extend(.abs-block-title all); + } + .counter { + &:extend(.abs-block-items-counter all); + } + .product-item-name { + margin-right: @indent__m; + } } -} -.products-grid.wishlist { - .product { - &-item { - &-photo { - margin-bottom: @indent__s; - display: block; - } - &-name { - margin-top: 0; - } - .price-box { - margin: 0; - } - &-tooltip { - } - .comment-box { - .label { - &:extend(.abs-visually-hidden all); + .products-grid.wishlist { + .product { + &-item { + &-photo { + display: block; + margin-bottom: @indent__s; } - } - &-comment { - display: block; - margin: @indent__s 0; - height: 42px; - } - &-actions { - > * { - margin-right: 15px; - &:last-child { - margin-right: 0; + &-name { + margin-top: 0; + } + .price-box { + margin: 0; + } + &-tooltip { + } + .comment-box { + .label { + &:extend(.abs-visually-hidden all); } } - } - .box-tocart { - input.qty { - height: 32px; - &:extend(.abs-input-qty all); + &-comment { + display: block; + height: 42px; + margin: @indent__s 0; + } + &-actions { + > * { + margin-right: 15px; + &:last-child { + margin-right: 0; + } + } + } + .box-tocart { + input.qty { + height: 32px; + &:extend(.abs-input-qty all); + } } } } } } -} - // -// Mobile -//-------------------------------------- +// Mobile +// _____________________________________________ + .media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__s) { .products-grid.wishlist { .product-item { @@ -154,15 +154,15 @@ .media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__m) { .products-grid.wishlist { - margin-right: -@indent__s; margin-bottom: @indent__l; + margin-right: -@indent__s; .product { &-item { padding: @indent__base @indent__s @indent__base @indent__base; position: relative; &-photo { - margin-right: @indent__base; float: left; + margin-right: @indent__base; } &-name { .lib-font-size(16); @@ -211,8 +211,9 @@ } // - // Grid view for wishlist - //-------------------------------------- + // Grid view for wishlist + // ----------------------------------------- + .wishlist-index-index { .product { &-item { @@ -229,7 +230,7 @@ .wishlist-index-index { .products-grid { .product-item { - margin-bottom: 20px; + margin-bottom: @indent__base; width: 50%; } .product-item-actions { @@ -240,8 +241,9 @@ } // -// Desktop -//-------------------------------------- +// Desktop +// _____________________________________________ + .media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) { .products-grid.wishlist { .product { @@ -253,12 +255,9 @@ margin: @indent__s 0 0; } .fieldset { - .field.qty, - .product-item-actions { - } .field.qty { - padding-right: @indent__s; margin-bottom: @indent__s; + padding-right: @indent__s; .label { width: auto; } @@ -275,7 +274,7 @@ } } } - .wishlist-index-index { + .wishlist-index-index { .product { &-item { &-info { @@ -283,17 +282,30 @@ } } } + .main { + .form-wishlist-items { + .actions-toolbar { + &:extend(.abs-reset-left-margin-desktop all); + } + } + } } } .media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__l) { - .wishlist-index-index .products-grid .product-items { margin: 0; } - .wishlist-index-index .products-grid .product-item { - width: 24.439%; - margin-left: calc(~"(100% - 4 * 24.439%) / 3"); - padding: 0; - &:nth-child(4n+1) { - margin-left: 0; + .wishlist-index-index { + .products-grid { + .product-items { + margin: 0; + } + .product-item { + margin-left: calc(~"(100% - 4 * 24.439%) / 3"); + padding: 0; + width: 24.439%; + &:nth-child(4n+1) { + margin-left: 0; + } + } } } } diff --git a/app/design/frontend/Magento/luma/Magento_Catalog/web/css/source/_module.less b/app/design/frontend/Magento/luma/Magento_Catalog/web/css/source/_module.less index e322d35fe9c551acf327f97a514cceed78982447..555101ccdbd5ce14e784b65290f7414aee7eee67 100644 --- a/app/design/frontend/Magento/luma/Magento_Catalog/web/css/source/_module.less +++ b/app/design/frontend/Magento/luma/Magento_Catalog/web/css/source/_module.less @@ -579,9 +579,12 @@ .product-info-main { float: right; } + .product.media { float: left; + margin-bottom: @indent__m; } + .page-layout-1column { .product-info-main { width: 40%; @@ -590,6 +593,7 @@ width: 57%; } } + .page-layout-2columns-left, .page-layout-2columns-right, .page-layout-3columns { diff --git a/app/design/frontend/Magento/luma/Magento_Catalog/web/css/source/module/_toolbar.less b/app/design/frontend/Magento/luma/Magento_Catalog/web/css/source/module/_toolbar.less index 3eefdcaa2b74c24112ef02e551053460e08360b8..bb25b47c668dac3073a63b97dd78561e3565d097 100644 --- a/app/design/frontend/Magento/luma/Magento_Catalog/web/css/source/module/_toolbar.less +++ b/app/design/frontend/Magento/luma/Magento_Catalog/web/css/source/module/_toolbar.less @@ -11,114 +11,117 @@ @pager__font-weight: @font-weight__bold; // -// Common -//-------------------------------------- +// Common +// _____________________________________________ & when (@media-common = true) { - -.page-products .columns { - position: relative; - z-index: 1; - padding-top: 60px; -} - -.toolbar { - select { - .lib-css(background-color, @toolbar-element-background); - border-radius: 3px; - .lib-css(box-shadow, @button__shadow); + .page-products { + .columns { + padding-top: 60px; + position: relative; + z-index: 1; + } } - text-align: center; - &:extend(.abs-add-clearfix all); - &-amount { - position: absolute; - left: 0; - top: 0; - line-height: @toolbar-mode-icon-font-size+2; - padding: 7px 0; - margin: 0; - vertical-align: middle; - text-align: left; - .products.wrapper ~ .toolbar & { - display: none; + .toolbar { + &:extend(.abs-add-clearfix all); + margin-bottom: @indent__l; + text-align: center; + + select { + .lib-css(background-color, @toolbar-element-background); + .lib-css(box-shadow, @button__shadow); + border-radius: 3px; } - } - .page-with-filter & { + &-amount { - position: static; + left: 0; + line-height: @toolbar-mode-icon-font-size+2; + margin: 0; + padding: 7px 0; + position: absolute; + text-align: left; + top: 0; + vertical-align: middle; + .products.wrapper ~ .toolbar & { + display: none; + } } - } - margin-bottom: @indent__l; - &-products { - .lib-css(background-color, @toolbar-background); - .pages { - display: none; - .products.wrapper ~ & { - display: block; + + .page-with-filter & { + &-amount { + position: static; } } - } - .pages { - margin-bottom: @indent__m; - } -} -.sorter { - float: right; - .page-products & { - position: absolute; - z-index: 1; - top: 0; - right: @indent__s; - } - .products.wrapper ~ .toolbar & { - display: none; - } - &-options { - margin: 0 @indent__xs 0 7px; - width: auto; + &-products { + .lib-css(background-color, @toolbar-background); + .pages { + display: none; + .products.wrapper ~ & { + display: block; + } + } + } + .pages { + margin-bottom: @indent__m; + } } - &-action { - .lib-icon-font( + + .sorter { + float: right; + .page-products & { + position: absolute; + right: @indent__s; + top: 0; + z-index: 1; + } + .products.wrapper ~ .toolbar & { + display: none; + } + &-options { + margin: 0 @indent__xs 0 7px; + width: auto; + } + &-action { + .lib-icon-font( @icon-arrow-up, @_icon-font-size: 16px, @_icon-font-color: @header-icons-color, @_icon-font-color-hover: @header-icons-color-hover - ); - .lib-icon-text-hide(); - &.sort-desc:before { - content: @icon-arrow-down; + ); + .lib-icon-text-hide(); + &.sort-desc:before { + content: @icon-arrow-down; + } } } -} -.modes { - display: none; -} - -.limiter { - display: none; - &-options { - width: auto; - margin: 0 5px 0 7px; - } - &-label { - font-weight: 400; - } - .page-products .toolbar & { + .modes { display: none; } - .control { - display: inline-block; - } -} + .limiter { + display: none; + &-options { + margin: 0 5px 0 7px; + width: auto; + } + &-label { + font-weight: 400; + } + .page-products .toolbar & { + display: none; + } + .control { + display: inline-block; + } + } } // -// Mobile -//-------------------------------------- +// Desctop +// _____________________________________________ .media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__s) { .toolbar-products { @@ -127,26 +130,31 @@ } .media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__s) { - .page-products .columns { - position: relative; - z-index: 1; - padding-top: 0; + .page-products { + .columns { + padding-top: 0; + position: relative; + z-index: 1; + } } + .toolbar { &-amount { - position: static; display: block; float: left; + position: static; } .products.wrapper ~ & .pages { float: left; margin-bottom: 0; } } + .modes { - float: left; display: inline-block; + float: left; margin-right: @indent__base; + .products.wrapper ~ .toolbar & { display: none; } @@ -156,22 +164,23 @@ } &-mode { - float: left; + .lib-css(background-color, @toolbar-element-background); + .lib-css(box-shadow, @button__shadow); + .lib-css(color, @text__color__muted); border: 1px solid @border-color__base; + border-right: 0; + float: left; font-weight: @font-weight__regular; - .lib-css(color, @text__color__muted); - text-align: center; - padding: 7px 10px; line-height: 1; - border-right: 0; - .lib-css(background-color, @toolbar-element-background); - .lib-css(box-shadow, @button__shadow); + padding: 7px 10px; + text-align: center; + .modes-label + & { border-radius: 3px 0 0 3px; } &:hover { - background: darken(@toolbar-element-background, 2%); .lib-css(color, @text__color__muted); + background: darken(@toolbar-element-background, 2%); } &:last-child { border-radius: 0 3px 3px 0; @@ -182,21 +191,29 @@ background: darken(@toolbar-element-background, 7%); color: @color-gray62; } + .lib-icon-font( - @icon-grid, - @_icon-font-size: @toolbar-mode-icon-font-size, - @_icon-font-text-hide: true + @icon-grid, + @_icon-font-size: @toolbar-mode-icon-font-size, + @_icon-font-text-hide: true, + @_icon-font-color: @text__color__muted, + @_icon-font-color-hover: @text__color__muted ); } } + .sorter { .page-products & { position: static; } } - .mode-list:before { - content: @icon-list; + + .mode-list { + &:before { + content: @icon-list; + } } + .limiter { float: right; .products.wrapper ~ .toolbar & { diff --git a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_minicart.less b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_minicart.less index e4a039fac1df3d756dfe28b7e4df43f39aadc96c..10a28b07bdd6b3249982da6ea3e8a500d3a3329a 100644 --- a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_minicart.less +++ b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_minicart.less @@ -12,7 +12,6 @@ @minicart-qty__height: 24px; - // // Common // _____________________________________________ @@ -52,9 +51,9 @@ display: none; &.empty { display: block; + font-size: 14px; padding: @indent__l 0 @indent__base; text-align: center; - font-size: 14px; } } .text { @@ -95,18 +94,18 @@ .minicart-wrapper { .lib-dropdown( - @_toggle-selector: ~".action.showcart", - @_options-selector: ~".block-minicart", - @_dropdown-toggle-icon-content: @icon-cart, - @_dropdown-toggle-active-icon-content: @icon-cart, - @_dropdown-list-item-padding: false, - @_dropdown-list-item-hover: false, - @_icon-font-position: before, - @_icon-font-size: 22px, - @_icon-font-line-height: 28px, - @_icon-font-color: @minicart-icons-color, - @_icon-font-color-hover: @minicart-icons-color-hover, - @_icon-font-color-active: @minicart-icons-color + @_toggle-selector: ~".action.showcart", + @_options-selector: ~".block-minicart", + @_dropdown-toggle-icon-content: @icon-cart, + @_dropdown-toggle-active-icon-content: @icon-cart, + @_dropdown-list-item-padding: false, + @_dropdown-list-item-hover: false, + @_icon-font-position: before, + @_icon-font-size: 22px, + @_icon-font-line-height: 28px, + @_icon-font-color: @minicart-icons-color, + @_icon-font-color-hover: @minicart-icons-color-hover, + @_icon-font-color-active: @minicart-icons-color ); float: right; .block-minicart { @@ -140,11 +139,11 @@ } .action { &.close { - width: 40px; height: 40px; - top: 0; - right: 0; position: absolute; + right: 0; + top: 0; + width: 40px; .lib-button-reset(); .lib-button-icon( @icon-remove, @@ -155,10 +154,10 @@ ); } &.showcart { + white-space: nowrap; .text { &:extend(.abs-visually-hidden all); } - white-space: nowrap; .counter.qty { .lib-css(background, @active__color); .lib-css(color, @page__background-color); @@ -203,10 +202,10 @@ .minicart-items { .lib-list-reset-styles(); .product-item { + padding: @indent__base 0; &:not(:first-child) { .lib-css(border-top, 1px solid @minicart__border-color); } - padding: @indent__base 0; &:first-child { padding-top: 0; } @@ -260,9 +259,9 @@ .toggle { &:extend(.abs-toggling-title all); &:after { - position: static; - margin: 0 0 0 @indent__xs; .lib-css(color, @color-gray56); + margin: 0 0 0 @indent__xs; + position: static; } border: 0; padding: 0 @indent__xl @indent__xs 0; @@ -281,12 +280,12 @@ &.options { .tooltip.toggle { .lib-icon-font( - @icon-down, - @_icon-font-size: 12px, - @_icon-font-line-height: 12px, - @_icon-font-text-hide: true, - @_icon-font-margin: -3px 0 0 7px, - @_icon-font-position: after + @icon-down, + @_icon-font-size: 12px, + @_icon-font-line-height: 12px, + @_icon-font-text-hide: true, + @_icon-font-margin: -3px 0 0 7px, + @_icon-font-position: after ); } .details { @@ -301,38 +300,37 @@ } } .item-qty { - width: 40px; - text-align: center; margin-right: @indent__s; + text-align: center; + width: 40px; } .update-cart-item { - vertical-align: top; .lib-font-size(11); + vertical-align: top; + } + .subtitle { + display: none; } .action { &.edit, &.delete { .lib-icon-font( - @icon-edit, - @_icon-font-size: 18px, - @_icon-font-line-height: 20px, - @_icon-font-text-hide: true, - @_icon-font-color: @minicart-icons-color, - @_icon-font-color-hover: @primary__color, - @_icon-font-color-active: @minicart-icons-color + @icon-edit, + @_icon-font-size: 18px, + @_icon-font-line-height: 20px, + @_icon-font-text-hide: true, + @_icon-font-color: @minicart-icons-color, + @_icon-font-color-hover: @primary__color, + @_icon-font-color-active: @minicart-icons-color ); } &.delete { .lib-icon-font-symbol( - @_icon-font-content: @icon-trash + @_icon-font-content: @icon-trash ); } } - .subtitle { - display: none; - } } - } // @@ -351,7 +349,6 @@ } } - // // Desktop // _____________________________________________ diff --git a/app/design/frontend/Magento/luma/Magento_LayeredNavigation/web/css/source/_module.less b/app/design/frontend/Magento/luma/Magento_LayeredNavigation/web/css/source/_module.less index 17cadfeb19cd5bec72ae4e0f54888586dbf3f39e..276730fafe6962c624f12c807c58c4e44f59d741 100644 --- a/app/design/frontend/Magento/luma/Magento_LayeredNavigation/web/css/source/_module.less +++ b/app/design/frontend/Magento/luma/Magento_LayeredNavigation/web/css/source/_module.less @@ -102,9 +102,10 @@ font-weight: @font-weight__semibold; margin: 0; overflow: hidden; - padding: @indent__s 20px+@indent__s 0 @indent__s; + padding: @indent__s 30px+@indent__s 0 @indent__s; position: relative; text-transform: uppercase; + word-break: break-all; z-index: 1; .lib-icon-font( @_icon-font-content: @icon-down, @@ -267,10 +268,10 @@ text-transform: uppercase; z-index: 1; .lib-icon-font( - @_icon-font-content: @icon-down, - @_icon-font-size: 13px, - @_icon-font-position: before, - @_icon-font-display: block + @_icon-font-content: @icon-down, + @_icon-font-size: 13px, + @_icon-font-position: before, + @_icon-font-display: block ); &:before { position: absolute; @@ -288,8 +289,8 @@ padding-bottom: 30px; .block-subtitle { .lib-icon-font-symbol( - @_icon-font-content: @icon-up, - @_icon-font-position: before + @_icon-font-content: @icon-up, + @_icon-font-position: before ); } .items { diff --git a/app/design/frontend/Magento/luma/Magento_Theme/web/css/source/_module.less b/app/design/frontend/Magento/luma/Magento_Theme/web/css/source/_module.less index 6327a89678098ed5ba19078cd7821020c87842f2..a1f0aac552bc6011d8eb667686c03d0af9f6ad0a 100644 --- a/app/design/frontend/Magento/luma/Magento_Theme/web/css/source/_module.less +++ b/app/design/frontend/Magento/luma/Magento_Theme/web/css/source/_module.less @@ -465,6 +465,9 @@ padding: 8px; } } + .customer-name { + cursor: pointer; + } .customer-menu { display: none; } diff --git a/app/etc/di.xml b/app/etc/di.xml index 598bc2c341ed351b1cb1ebd20feee0d742330b33..3932bcf133661c8c8b5b9e9eb66355468cc55425 100755 --- a/app/etc/di.xml +++ b/app/etc/di.xml @@ -176,7 +176,7 @@ <type name="Magento\Framework\View\BlockPool" shared="false" /> <type name="Magento\Framework\App\Request\Http"> <arguments> - <argument name="pathInfoProcessor" xsi:type="object">Magento\Store\App\Request\PathInfoProcessor\Proxy</argument> + <argument name="pathInfoProcessor" xsi:type="object">Magento\Backend\App\Request\PathInfoProcessor\Proxy</argument> </arguments> </type> <preference for="Magento\Framework\Session\SaveHandlerInterface" type="Magento\Framework\Session\SaveHandler" /> diff --git a/dev/tests/api-functional/testsuite/Magento/ConfigurableProduct/Api/ProductRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/ConfigurableProduct/Api/ProductRepositoryTest.php index e8719f6f4e276d3185856c04af776a8b38e61048..21f313bcf0c3515ace3d47586740cde1b1f4dd68 100644 --- a/dev/tests/api-functional/testsuite/Magento/ConfigurableProduct/Api/ProductRepositoryTest.php +++ b/dev/tests/api-functional/testsuite/Magento/ConfigurableProduct/Api/ProductRepositoryTest.php @@ -126,7 +126,6 @@ class ProductRepositoryTest extends WebapiAbstract $response = $this->createConfigurableProduct(); $this->assertEquals(self::CONFIGURABLE_PRODUCT_SKU, $response[ProductInterface::SKU]); - $this->assertEquals(50, $response['price']); $this->assertTrue( isset($response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]["configurable_product_options"]) ); diff --git a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Block/Adminhtml/Catalog/Product/Edit/Tab/Downloadable/Links.xml b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Block/Adminhtml/Catalog/Product/Edit/Tab/Downloadable/Links.xml index bd1e9e70f43f105f410210cefdb87a358a4ab8dd..6d6f3231f3e8e71c9b51474a8d4dbf3f5801c0cf 100644 --- a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Block/Adminhtml/Catalog/Product/Edit/Tab/Downloadable/Links.xml +++ b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Block/Adminhtml/Catalog/Product/Edit/Tab/Downloadable/Links.xml @@ -14,7 +14,7 @@ <links_purchased_separately> <selector>[name="product[links_purchased_separately]"]</selector> <strategy>css selector</strategy> - <input>select</input> + <input>checkbox</input> </links_purchased_separately> </fields> </mapping> diff --git a/dev/tests/integration/testsuite/Magento/Email/Model/TemplateTest.php b/dev/tests/integration/testsuite/Magento/Email/Model/TemplateTest.php index 48d237cd8d627ad9f0614ff20e0e7bda9af7aa7b..5680b57d0fc2c33cde82ddad0da453523c5c12b1 100644 --- a/dev/tests/integration/testsuite/Magento/Email/Model/TemplateTest.php +++ b/dev/tests/integration/testsuite/Magento/Email/Model/TemplateTest.php @@ -122,17 +122,19 @@ class TemplateTest extends \PHPUnit_Framework_TestCase ->getArea(Area::AREA_FRONTEND) ->load(); - $this->setNotDefaultThemeForFixtureStore(); $expectedViewUrl = 'static/frontend/Magento/blank/en_US/Magento_Theme/favicon.ico'; - $this->model->setTemplateText('{{view url="Magento_Theme::favicon.ico"}}'); - $this->assertStringEndsNotWith($expectedViewUrl, $this->model->getProcessedTemplate()); $this->model->setDesignConfig([ 'area' => 'frontend', 'store' => $this->objectManager->get('Magento\Store\Model\StoreManagerInterface') ->getStore('fixturestore') ->getId(), ]); + $this->model->setTemplateText('{{view url="Magento_Theme::favicon.ico"}}'); + $this->setNotDefaultThemeForFixtureStore(); + $this->assertStringEndsNotWith($expectedViewUrl, $this->model->getProcessedTemplate()); + + $this->setDefaultThemeForFixtureStore(); $this->assertStringEndsWith($expectedViewUrl, $this->model->getProcessedTemplate()); } @@ -529,6 +531,28 @@ class TemplateTest extends \PHPUnit_Framework_TestCase */ protected function setNotDefaultThemeForFixtureStore() { + /** @var \Magento\Framework\View\Design\ThemeInterface $theme */ + $theme = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + 'Magento\Framework\View\Design\ThemeInterface' + ); + $theme->load('Magento/luma', 'theme_path'); + \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( + 'Magento\Framework\App\Config\MutableScopeConfigInterface' + )->setValue( + \Magento\Framework\View\DesignInterface::XML_PATH_THEME_ID, + $theme->getId(), + \Magento\Store\Model\ScopeInterface::SCOPE_STORE, + 'fixturestore' + ); + } + + /** + * Set 'Magento/blank' for the 'fixturestore' store. + * Application isolation is required, if a test uses this method. + */ + protected function setDefaultThemeForFixtureStore() + { + /** @var \Magento\Framework\View\Design\ThemeInterface $theme */ $theme = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( 'Magento\Framework\View\Design\ThemeInterface' ); @@ -554,10 +578,8 @@ class TemplateTest extends \PHPUnit_Framework_TestCase ->getArea(Area::AREA_FRONTEND) ->load(); - $this->setNotDefaultThemeForFixtureStore(); $expectedViewUrl = 'static/frontend/Magento/blank/en_US/Magento_Theme/favicon.ico'; $this->model->setTemplateSubject('{{view url="Magento_Theme::favicon.ico"}}'); - $this->assertStringEndsNotWith($expectedViewUrl, $this->model->getProcessedTemplateSubject([])); $this->model->setDesignConfig([ 'area' => 'frontend', 'store' => $this->objectManager->get('Magento\Store\Model\StoreManagerInterface') @@ -565,6 +587,10 @@ class TemplateTest extends \PHPUnit_Framework_TestCase ->getId(), ]); + $this->setNotDefaultThemeForFixtureStore(); + $this->assertStringEndsNotWith($expectedViewUrl, $this->model->getProcessedTemplateSubject([])); + + $this->setDefaultThemeForFixtureStore(); $this->assertStringEndsWith($expectedViewUrl, $this->model->getProcessedTemplateSubject([])); } diff --git a/lib/internal/Magento/Framework/Component/ComponentRegistrar.php b/lib/internal/Magento/Framework/Component/ComponentRegistrar.php index 44258c7f135ce0e122f3a63d6f0fe1fd26737fe4..c2c928b2376efe8589e86741e5fa8d3df1c4966b 100644 --- a/lib/internal/Magento/Framework/Component/ComponentRegistrar.php +++ b/lib/internal/Magento/Framework/Component/ComponentRegistrar.php @@ -48,7 +48,7 @@ class ComponentRegistrar implements ComponentRegistrarInterface if (isset(self::$paths[$type][$componentName])) { throw new \LogicException('\'' . $componentName . '\' component already exists'); } else { - self::$paths[$type][$componentName] = str_replace('\\', '/', $path); + self::$paths[$type][$componentName] = $path; } } diff --git a/lib/internal/Magento/Framework/View/Asset/Bundle.php b/lib/internal/Magento/Framework/View/Asset/Bundle.php index 380d87d31155e0366758b65c55c1aca966575099..d19d667d6121600700dd09c11d3a6d1f432e8cc4 100644 --- a/lib/internal/Magento/Framework/View/Asset/Bundle.php +++ b/lib/internal/Magento/Framework/View/Asset/Bundle.php @@ -150,7 +150,7 @@ class Bundle */ protected function getAssetSize(LocalInterface $asset) { - return mb_strlen(utf8_encode($asset->getContent()), 'utf-8') / 1024; + return mb_strlen(json_encode(utf8_encode($asset->getContent()), JSON_UNESCAPED_SLASHES), 'utf-8') / 1024; } /** diff --git a/lib/internal/Magento/Framework/View/Asset/Source.php b/lib/internal/Magento/Framework/View/Asset/Source.php index d47a76a4fe58c928e247cf4d98790b8ef6258eea..53965c612a41e57600803b7d973f4f6283d8765a 100644 --- a/lib/internal/Magento/Framework/View/Asset/Source.php +++ b/lib/internal/Magento/Framework/View/Asset/Source.php @@ -128,9 +128,12 @@ class Source $this->preProcessorPool->process($chain); $chain->assertValid(); $dirCode = DirectoryList::ROOT; - if ($chain->isChanged()) { + $directoryReader = $this->filesystem->getDirectoryRead(DirectoryList::STATIC_VIEW); + $targetPath = DirectoryList::TMP_MATERIALIZATION_DIR . '/source/' . $chain->getTargetAssetPath(); + + if ($chain->isChanged() || !$directoryReader->isExist($targetPath)) { $dirCode = DirectoryList::VAR_DIR; - $path = DirectoryList::TMP_MATERIALIZATION_DIR . '/source/' . $chain->getTargetAssetPath(); + $path = $targetPath; $this->varDir->writeFile($path, $chain->getContent()); } $result = [$dirCode, $path]; diff --git a/lib/internal/Magento/Framework/View/Layout/Data/Structure.php b/lib/internal/Magento/Framework/View/Layout/Data/Structure.php index 79e514b42b23a782e208ca25558a7a21ac6eb3f5..ee2fe6bd206a87c7f894e82232007abe92beadf8 100644 --- a/lib/internal/Magento/Framework/View/Layout/Data/Structure.php +++ b/lib/internal/Magento/Framework/View/Layout/Data/Structure.php @@ -6,6 +6,7 @@ namespace Magento\Framework\View\Layout\Data; use Magento\Framework\Data\Structure as DataStructure; +use Magento\Framework\App\State; /** * An associative data structure, that features "nested set" parent-child relations @@ -24,17 +25,25 @@ class Structure extends DataStructure */ protected $logger; + /** + * @var State + */ + protected $state; + /** * Constructor * * @param \Psr\Log\LoggerInterface $logger + * @param State $state * @param array $elements */ public function __construct( \Psr\Log\LoggerInterface $logger, + State $state, array $elements = null ) { $this->logger = $logger; + $this->state = $state; parent::__construct($elements); } @@ -109,10 +118,12 @@ class Structure extends DataStructure if ($childName !== $sibling) { $siblingParentName = $this->getParentId($sibling); if ($parentName !== $siblingParentName) { - $this->logger->critical( - "Broken reference: the '{$childName}' tries to reorder itself towards '{$sibling}', but " . - "their parents are different: '{$parentName}' and '{$siblingParentName}' respectively." - ); + if ($this->state->getMode() === State::MODE_DEVELOPER) { + $this->logger->critical( + "Broken reference: the '{$childName}' tries to reorder itself towards '{$sibling}', but " . + "their parents are different: '{$parentName}' and '{$siblingParentName}' respectively." + ); + } return; } $this->reorderToSibling($parentName, $childName, $sibling, $after ? 1 : -1); diff --git a/lib/internal/Magento/Framework/View/Layout/ScheduledStructure/Helper.php b/lib/internal/Magento/Framework/View/Layout/ScheduledStructure/Helper.php index aaa2e5fe1ecdd33140ff323f20a8906d6c78040b..c71c27beeb4705608e69d428a9989b4a56d68ce4 100644 --- a/lib/internal/Magento/Framework/View/Layout/ScheduledStructure/Helper.php +++ b/lib/internal/Magento/Framework/View/Layout/ScheduledStructure/Helper.php @@ -6,6 +6,7 @@ namespace Magento\Framework\View\Layout\ScheduledStructure; use Magento\Framework\View\Layout; +use Magento\Framework\App\State; class Helper { @@ -31,13 +32,21 @@ class Helper */ protected $logger; + /** + * @var State + */ + protected $state; + /** * @param \Psr\Log\LoggerInterface $logger + * @param State $state */ public function __construct( - \Psr\Log\LoggerInterface $logger + \Psr\Log\LoggerInterface $logger, + State $state ) { $this->logger = $logger; + $this->state = $state; } /** @@ -190,10 +199,13 @@ class Helper } } else { $scheduledStructure->setElementToBrokenParentList($key); - $this->logger->critical( - "Broken reference: the '{$name}' element cannot be added as child to '{$parentName}', " . - 'because the latter doesn\'t exist' - ); + + if ($this->state->getMode() === State::MODE_DEVELOPER) { + $this->logger->critical( + "Broken reference: the '{$name}' element cannot be added as child to '{$parentName}', " . + 'because the latter doesn\'t exist' + ); + } } } diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Asset/SourceTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Asset/SourceTest.php index 6901f2d06062e08ca7ab1cea51cbd9caa6b8a00c..427ed2bc1557804cc5658cc21c0fbe3d893b3bca 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/Asset/SourceTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Asset/SourceTest.php @@ -94,7 +94,7 @@ class SourceTest extends \PHPUnit_Framework_TestCase $themeList->expects($this->any()) ->method('getThemeByFullPath') ->with('frontend/magento_theme') - ->will($this->returnValue($this->theme)); + ->willReturn($this->theme); $this->initFilesystem(); @@ -104,32 +104,36 @@ class SourceTest extends \PHPUnit_Framework_TestCase } /** - * @param $origFile - * @param $origPath - * @param $origContent - * @param $isMaterialization + * @param string $origFile + * @param string $origPath + * @param string $origContent + * @param bool $isMaterialization + * @param bool $isExist * * @dataProvider getFileDataProvider */ - public function testGetFile($origFile, $origPath, $origContent, $isMaterialization) + public function testGetFile($origFile, $origPath, $origContent, $isMaterialization, $isExist) { $filePath = 'some/file.ext'; $this->viewFileResolution->expects($this->once()) ->method('getFile') ->with('frontend', $this->theme, 'en_US', $filePath, 'Magento_Module') - ->will($this->returnValue($origFile)); + ->willReturn($origFile); $this->rootDirRead->expects($this->once()) ->method('getRelativePath') ->with($origFile) - ->will($this->returnValue($origPath)); + ->willReturn($origPath); $this->rootDirRead->expects($this->once()) ->method('readFile') ->with($origPath) - ->will($this->returnValue($origContent)); + ->willReturn($origContent); $this->preProcessorPool->expects($this->once()) ->method('process') ->with($this->chain); - if ($isMaterialization) { + $this->staticDirRead->expects($this->any()) + ->method('isExist') + ->willReturn($isExist); + if ($isMaterialization || !$isExist) { $this->chain ->expects($this->once()) ->method('isChanged') @@ -147,13 +151,13 @@ class SourceTest extends \PHPUnit_Framework_TestCase ->with('view_preprocessed/source/some/file.ext', 'processed'); $this->varDir->expects($this->once()) ->method('getAbsolutePath') - ->with('view_preprocessed/source/some/file.ext')->will($this->returnValue('result')); + ->with('view_preprocessed/source/some/file.ext')->willReturn('result'); } else { $this->varDir->expects($this->never())->method('writeFile'); $this->rootDirRead->expects($this->once()) ->method('getAbsolutePath') ->with('source/some/file.ext') - ->will($this->returnValue('result')); + ->willReturn('result'); } $this->assertSame('result', $this->object->getFile($this->getAsset())); } @@ -197,10 +201,10 @@ class SourceTest extends \PHPUnit_Framework_TestCase public function getFileDataProvider() { return [ - ['/root/some/file.ext', 'source/some/file.ext', 'processed', false], - ['/root/some/file.ext', 'source/some/file.ext', 'not_processed', true], - ['/root/some/file.ext2', 'source/some/file.ext2', 'processed', true], - ['/root/some/file.ext2', 'source/some/file.ext2', 'not_processed', true], + ['/root/some/file.ext', 'source/some/file.ext', 'processed', false, true], + ['/root/some/file.ext', 'source/some/file.ext', 'not_processed', true, false], + ['/root/some/file.ext2', 'source/some/file.ext2', 'processed', true, true], + ['/root/some/file.ext2', 'source/some/file.ext2', 'not_processed', true, false], ]; } @@ -219,11 +223,11 @@ class SourceTest extends \PHPUnit_Framework_TestCase $this->filesystem->expects($this->any()) ->method('getDirectoryRead') - ->will($this->returnValueMap($readDirMap)); + ->willReturnMap($readDirMap); $this->filesystem->expects($this->any()) ->method('getDirectoryWrite') ->with(DirectoryList::VAR_DIR) - ->will($this->returnValue($this->varDir)); + ->willReturn($this->varDir); } /** @@ -252,19 +256,19 @@ class SourceTest extends \PHPUnit_Framework_TestCase $asset = $this->getMock('Magento\Framework\View\Asset\File', [], [], '', false); $asset->expects($this->any()) ->method('getContext') - ->will($this->returnValue($context)); + ->willReturn($context); $asset->expects($this->any()) ->method('getFilePath') - ->will($this->returnValue('some/file.ext')); + ->willReturn('some/file.ext'); $asset->expects($this->any()) ->method('getPath') - ->will($this->returnValue('some/file.ext')); + ->willReturn('some/file.ext'); $asset->expects($this->any()) ->method('getModule') - ->will($this->returnValue('Magento_Module')); + ->willReturn('Magento_Module'); $asset->expects($this->any()) ->method('getContentType') - ->will($this->returnValue('ext')); + ->willReturn('ext'); return $asset; } diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Layout/Data/StructureTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Layout/Data/StructureTest.php new file mode 100644 index 0000000000000000000000000000000000000000..f5d47e87b95cd33b6494dbcb87af32bfde92a791 --- /dev/null +++ b/lib/internal/Magento/Framework/View/Test/Unit/Layout/Data/StructureTest.php @@ -0,0 +1,96 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\View\Test\Unit\Layout\Data; + +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; +use Magento\Framework\App\State; + +class StructureTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \Psr\Log\LoggerInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $loggerMock; + + /** + * @var State|\PHPUnit_Framework_MockObject_MockObject + */ + protected $stateMock; + + /** + * @var ObjectManagerHelper + */ + protected $objectManagerHelper; + + /** + * @var \Magento\Framework\View\Layout\Data\Structure + */ + protected $dataStructure; + + /** + * @return void + */ + protected function setUp() + { + $this->loggerMock = $this->getMock('Psr\Log\LoggerInterface'); + $this->stateMock = $this->getMock('Magento\Framework\App\State', [], [], '', false); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + $this->dataStructure = $this->objectManagerHelper->getObject( + 'Magento\Framework\View\Layout\Data\Structure', + [ + 'logger' => $this->loggerMock, + 'state' => $this->stateMock + ] + ); + } + + /** + * @param \PHPUnit_Framework_MockObject_Matcher_InvokedCount $loggerExpects + * @param string $stateMode + * @return void + * @dataProvider reorderChildElementLogDataProvider + */ + public function testReorderChildElementLog($loggerExpects, $stateMode) + { + $parentName = 'parent'; + $childName = 'child'; + $offsetOrSibling = '-'; + + $this->stateMock->expects($this->once()) + ->method('getMode') + ->willReturn($stateMode); + $this->loggerMock->expects($loggerExpects) + ->method('critical') + ->with( + "Broken reference: the '{$childName}' tries to reorder itself towards '', but " . + "their parents are different: '{$parentName}' and '' respectively." + ); + + $this->dataStructure->reorderChildElement($parentName, $childName, $offsetOrSibling); + } + + /** + * @return array + */ + public function reorderChildElementLogDataProvider() + { + return [ + [ + 'loggerExpects' => $this->once(), + 'stateMode' => State::MODE_DEVELOPER + ], + [ + 'loggerExpects' => $this->never(), + 'stateMode' => State::MODE_DEFAULT + ], + [ + 'loggerExpects' => $this->never(), + 'stateMode' => State::MODE_PRODUCTION + ] + ]; + } +} diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Layout/ScheduledStructure/HelperTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Layout/ScheduledStructure/HelperTest.php index 4aeff78304d3191d5e6e1ac9569a5955d2a87785..82619fa03d207777a312626e8c5ece42577e0084 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/Layout/ScheduledStructure/HelperTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Layout/ScheduledStructure/HelperTest.php @@ -7,6 +7,7 @@ namespace Magento\Framework\View\Test\Unit\Layout\ScheduledStructure; use Magento\Framework\View\Layout; +use Magento\Framework\App\State; /** * Class HelperTest @@ -22,7 +23,17 @@ class HelperTest extends \PHPUnit_Framework_TestCase /** * @var \Magento\Framework\View\Layout\Data\Structure|\PHPUnit_Framework_MockObject_MockObject */ - protected $dataStructure; + protected $dataStructureMock; + + /** + * @var \Psr\Log\LoggerInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $loggerMock; + + /** + * @var State|\PHPUnit_Framework_MockObject_MockObject + */ + protected $stateMock; /** * @var \Magento\Framework\View\Layout\ScheduledStructure\Helper @@ -37,13 +48,20 @@ class HelperTest extends \PHPUnit_Framework_TestCase $this->scheduledStructureMock = $this->getMockBuilder('Magento\Framework\View\Layout\ScheduledStructure') ->disableOriginalConstructor() ->getMock(); - - $this->dataStructure = $this->getMockBuilder('Magento\Framework\View\Layout\Data\Structure') + $this->dataStructureMock = $this->getMockBuilder('Magento\Framework\View\Layout\Data\Structure') ->disableOriginalConstructor() ->getMock(); + $this->loggerMock = $this->getMock('Psr\Log\LoggerInterface'); + $this->stateMock = $this->getMock('Magento\Framework\App\State', [], [], '', false); $helperObjectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); - $this->helper = $helperObjectManager->getObject('Magento\Framework\View\Layout\ScheduledStructure\Helper'); + $this->helper = $helperObjectManager->getObject( + 'Magento\Framework\View\Layout\ScheduledStructure\Helper', + [ + 'logger' => $this->loggerMock, + 'state' => $this->stateMock + ] + ); } /** @@ -122,7 +140,75 @@ class HelperTest extends \PHPUnit_Framework_TestCase $this->scheduledStructureMock->expects($this->once())->method('unsetPathElement')->with($key); $this->scheduledStructureMock->expects($this->once())->method('unsetStructureElement')->with($key); - $this->helper->scheduleElement($this->scheduledStructureMock, $this->dataStructure, $key); + $this->helper->scheduleElement($this->scheduledStructureMock, $this->dataStructureMock, $key); + } + + /** + * @param \PHPUnit_Framework_MockObject_Matcher_InvokedCount $loggerExpects + * @param string $stateMode + * @return void + * @dataProvider scheduleElementLogDataProvider + */ + public function testScheduleElementLog($loggerExpects, $stateMode) + { + $key = 'key'; + $parentName = 'parent'; + $alias = 'alias'; + $block = 'block'; + $siblingName = null; + $isAfter = false; + + $this->scheduledStructureMock->expects($this->once()) + ->method('getStructureElement') + ->willReturn( + [ + Layout\ScheduledStructure\Helper::SCHEDULED_STRUCTURE_INDEX_TYPE => $block, + Layout\ScheduledStructure\Helper::SCHEDULED_STRUCTURE_INDEX_ALIAS => $alias, + Layout\ScheduledStructure\Helper::SCHEDULED_STRUCTURE_INDEX_PARENT_NAME => $parentName, + Layout\ScheduledStructure\Helper::SCHEDULED_STRUCTURE_INDEX_SIBLING_NAME => $siblingName, + Layout\ScheduledStructure\Helper::SCHEDULED_STRUCTURE_INDEX_IS_AFTER => $isAfter + ] + ); + $this->scheduledStructureMock->expects($this->once()) + ->method('hasStructureElement') + ->with($parentName) + ->willReturn(false); + $this->dataStructureMock->expects($this->once()) + ->method('hasElement') + ->with($parentName) + ->willReturn(false); + $this->stateMock->expects($this->once()) + ->method('getMode') + ->willReturn($stateMode); + $this->loggerMock->expects($loggerExpects) + ->method('critical') + ->with( + "Broken reference: the '{$key}' element cannot be added as child to '{$parentName}', " . + 'because the latter doesn\'t exist' + ); + + $this->helper->scheduleElement($this->scheduledStructureMock, $this->dataStructureMock, $key); + } + + /** + * @return array + */ + public function scheduleElementLogDataProvider() + { + return [ + [ + 'loggerExpects' => $this->once(), + 'stateMode' => State::MODE_DEVELOPER + ], + [ + 'loggerExpects' => $this->never(), + 'stateMode' => State::MODE_DEFAULT + ], + [ + 'loggerExpects' => $this->never(), + 'stateMode' => State::MODE_PRODUCTION + ] + ]; } /** @@ -170,14 +256,15 @@ class HelperTest extends \PHPUnit_Framework_TestCase ); $this->scheduledStructureMock->expects($this->any())->method('hasStructureElement')->willReturn(true); $this->scheduledStructureMock->expects($this->once())->method('setElement')->with($key, [$block, $data]); - - $this->dataStructure->expects($this->once())->method('createElement')->with($key, ['type' => $block]); - $this->dataStructure->expects($this->once())->method('hasElement')->with($parentName)->willReturn($hasParent); - $this->dataStructure->expects($this->exactly($setAsChild)) + $this->dataStructureMock->expects($this->once())->method('createElement')->with($key, ['type' => $block]); + $this->dataStructureMock->expects($this->once()) + ->method('hasElement') + ->with($parentName) + ->willReturn($hasParent); + $this->dataStructureMock->expects($this->exactly($setAsChild)) ->method('setAsChild') ->with($key, $parentName, $alias) ->willReturn(true); - $this->scheduledStructureMock->expects($this->exactly($toRemoveList)) ->method('setElementToBrokenParentList') ->with($key); @@ -185,7 +272,7 @@ class HelperTest extends \PHPUnit_Framework_TestCase ->method('setElementToSortList') ->with($parentName, $key, $siblingName, $isAfter); - $this->helper->scheduleElement($this->scheduledStructureMock, $this->dataStructure, $key); + $this->helper->scheduleElement($this->scheduledStructureMock, $this->dataStructureMock, $key); } /** diff --git a/setup/performance-toolkit/benchmark.jmx b/setup/performance-toolkit/benchmark.jmx index af73293f01a30ce66daa74a2fdf6bfa3fb0f4376..c5060028b3454fdf63b76b3faf7467e57b5cdf35 100644 --- a/setup/performance-toolkit/benchmark.jmx +++ b/setup/performance-toolkit/benchmark.jmx @@ -1890,7 +1890,7 @@ vars.put("testLabel", "CatProdBrows");</stringProp> <collectionProp name="Arguments.arguments"> <elementProp name="sections" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> - <stringProp name="Argument.value">banner</stringProp> + <stringProp name="Argument.value">customer</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> @@ -1929,7 +1929,7 @@ vars.put("testLabel", "CatProdBrows");</stringProp> <hashTree> <ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Response Assertion" enabled="true"> <collectionProp name="Asserion.test_strings"> - <stringProp name="-1898134910">\"banner\":</stringProp> + <stringProp name="1393473040">\"customer\":</stringProp> </collectionProp> <stringProp name="Assertion.test_field">Assertion.response_data</stringProp> <boolProp name="Assertion.assume_success">false</boolProp> @@ -1981,7 +1981,7 @@ vars.put("testLabel", "CatProdBrows");</stringProp> <collectionProp name="Arguments.arguments"> <elementProp name="sections" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> - <stringProp name="Argument.value">banner</stringProp> + <stringProp name="Argument.value">customer</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> @@ -2020,7 +2020,7 @@ vars.put("testLabel", "CatProdBrows");</stringProp> <hashTree> <ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Response Assertion" enabled="true"> <collectionProp name="Asserion.test_strings"> - <stringProp name="-1898134910">\"banner\":</stringProp> + <stringProp name="1393473040">\"customer\":</stringProp> </collectionProp> <stringProp name="Assertion.test_field">Assertion.response_data</stringProp> <boolProp name="Assertion.assume_success">false</boolProp> @@ -2103,7 +2103,7 @@ vars.put("testLabel", "CatProdBrows");</stringProp> <collectionProp name="Arguments.arguments"> <elementProp name="sections" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> - <stringProp name="Argument.value">banner</stringProp> + <stringProp name="Argument.value">customer</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> @@ -2142,7 +2142,7 @@ vars.put("testLabel", "CatProdBrows");</stringProp> <hashTree> <ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Response Assertion" enabled="true"> <collectionProp name="Asserion.test_strings"> - <stringProp name="-1898134910">\"banner\":</stringProp> + <stringProp name="1393473040">\"customer\":</stringProp> </collectionProp> <stringProp name="Assertion.test_field">Assertion.response_data</stringProp> <boolProp name="Assertion.assume_success">false</boolProp> @@ -2225,7 +2225,7 @@ vars.put("testLabel", "CatProdBrows");</stringProp> <collectionProp name="Arguments.arguments"> <elementProp name="sections" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> - <stringProp name="Argument.value">banner</stringProp> + <stringProp name="Argument.value">customer</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> @@ -2264,7 +2264,7 @@ vars.put("testLabel", "CatProdBrows");</stringProp> <hashTree> <ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Response Assertion" enabled="true"> <collectionProp name="Asserion.test_strings"> - <stringProp name="-1898134910">\"banner\":</stringProp> + <stringProp name="1393473040">\"customer\":</stringProp> </collectionProp> <stringProp name="Assertion.test_field">Assertion.response_data</stringProp> <boolProp name="Assertion.assume_success">false</boolProp> @@ -2621,7 +2621,7 @@ vars.put("loadType", "Guest");</stringProp> <collectionProp name="Arguments.arguments"> <elementProp name="sections" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> - <stringProp name="Argument.value">banner</stringProp> + <stringProp name="Argument.value">customer</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> @@ -2660,7 +2660,7 @@ vars.put("loadType", "Guest");</stringProp> <hashTree> <ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Response Assertion" enabled="true"> <collectionProp name="Asserion.test_strings"> - <stringProp name="-1898134910">\"banner\":</stringProp> + <stringProp name="1393473040">\"customer\":</stringProp> </collectionProp> <stringProp name="Assertion.test_field">Assertion.response_data</stringProp> <boolProp name="Assertion.assume_success">false</boolProp> @@ -2712,7 +2712,7 @@ vars.put("loadType", "Guest");</stringProp> <collectionProp name="Arguments.arguments"> <elementProp name="sections" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> - <stringProp name="Argument.value">banner</stringProp> + <stringProp name="Argument.value">customer</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> @@ -2751,7 +2751,7 @@ vars.put("loadType", "Guest");</stringProp> <hashTree> <ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Response Assertion" enabled="true"> <collectionProp name="Asserion.test_strings"> - <stringProp name="-1898134910">\"banner\":</stringProp> + <stringProp name="1393473040">\"customer\":</stringProp> </collectionProp> <stringProp name="Assertion.test_field">Assertion.response_data</stringProp> <boolProp name="Assertion.assume_success">false</boolProp> @@ -2863,7 +2863,7 @@ vars.put("loadType", "Guest");</stringProp> <collectionProp name="Arguments.arguments"> <elementProp name="sections" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> - <stringProp name="Argument.value">cart,banner,messages</stringProp> + <stringProp name="Argument.value">cart,messages</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> @@ -2982,7 +2982,7 @@ vars.put("loadType", "Guest");</stringProp> <collectionProp name="Arguments.arguments"> <elementProp name="sections" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> - <stringProp name="Argument.value">banner</stringProp> + <stringProp name="Argument.value">customer</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> @@ -3021,7 +3021,7 @@ vars.put("loadType", "Guest");</stringProp> <hashTree> <ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Response Assertion" enabled="true"> <collectionProp name="Asserion.test_strings"> - <stringProp name="-1898134910">\"banner\":</stringProp> + <stringProp name="1393473040">\"customer\":</stringProp> </collectionProp> <stringProp name="Assertion.test_field">Assertion.response_data</stringProp> <boolProp name="Assertion.assume_success">false</boolProp> @@ -3132,7 +3132,7 @@ vars.put("loadType", "Guest");</stringProp> <collectionProp name="Arguments.arguments"> <elementProp name="sections" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> - <stringProp name="Argument.value">cart,banner,messages</stringProp> + <stringProp name="Argument.value">cart,messages</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> @@ -3254,7 +3254,7 @@ vars.put("loadType", "Guest");</stringProp> <collectionProp name="Arguments.arguments"> <elementProp name="sections" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> - <stringProp name="Argument.value">banner</stringProp> + <stringProp name="Argument.value">customer</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> @@ -3293,7 +3293,7 @@ vars.put("loadType", "Guest");</stringProp> <hashTree> <ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Response Assertion" enabled="true"> <collectionProp name="Asserion.test_strings"> - <stringProp name="-1898134910">\"banner\":</stringProp> + <stringProp name="1393473040">\"customer\":</stringProp> </collectionProp> <stringProp name="Assertion.test_field">Assertion.response_data</stringProp> <boolProp name="Assertion.assume_success">false</boolProp> @@ -3411,7 +3411,7 @@ vars.put("loadType", "Guest");</stringProp> <collectionProp name="Arguments.arguments"> <elementProp name="sections" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> - <stringProp name="Argument.value">cart,banner,messages</stringProp> + <stringProp name="Argument.value">cart,messages</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> @@ -3807,7 +3807,7 @@ vars.put("loadType", "Guest");</stringProp> <collectionProp name="Arguments.arguments"> <elementProp name="sections" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> - <stringProp name="Argument.value">banner</stringProp> + <stringProp name="Argument.value">customer</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> @@ -3846,7 +3846,7 @@ vars.put("loadType", "Guest");</stringProp> <hashTree> <ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Response Assertion" enabled="true"> <collectionProp name="Asserion.test_strings"> - <stringProp name="-1898134910">\"banner\":</stringProp> + <stringProp name="1393473040">\"customer\":</stringProp> </collectionProp> <stringProp name="Assertion.test_field">Assertion.response_data</stringProp> <boolProp name="Assertion.assume_success">false</boolProp> @@ -3898,7 +3898,7 @@ vars.put("loadType", "Guest");</stringProp> <collectionProp name="Arguments.arguments"> <elementProp name="sections" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> - <stringProp name="Argument.value">banner</stringProp> + <stringProp name="Argument.value">customer</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> @@ -3937,7 +3937,7 @@ vars.put("loadType", "Guest");</stringProp> <hashTree> <ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Response Assertion" enabled="true"> <collectionProp name="Asserion.test_strings"> - <stringProp name="-1898134910">\"banner\":</stringProp> + <stringProp name="1393473040">\"customer\":</stringProp> </collectionProp> <stringProp name="Assertion.test_field">Assertion.response_data</stringProp> <boolProp name="Assertion.assume_success">false</boolProp> @@ -4049,7 +4049,7 @@ vars.put("loadType", "Guest");</stringProp> <collectionProp name="Arguments.arguments"> <elementProp name="sections" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> - <stringProp name="Argument.value">cart,banner,messages</stringProp> + <stringProp name="Argument.value">cart,messages</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> @@ -4168,7 +4168,7 @@ vars.put("loadType", "Guest");</stringProp> <collectionProp name="Arguments.arguments"> <elementProp name="sections" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> - <stringProp name="Argument.value">banner</stringProp> + <stringProp name="Argument.value">customer</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> @@ -4207,7 +4207,7 @@ vars.put("loadType", "Guest");</stringProp> <hashTree> <ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Response Assertion" enabled="true"> <collectionProp name="Asserion.test_strings"> - <stringProp name="-1898134910">\"banner\":</stringProp> + <stringProp name="1393473040">\"customer\":</stringProp> </collectionProp> <stringProp name="Assertion.test_field">Assertion.response_data</stringProp> <boolProp name="Assertion.assume_success">false</boolProp> @@ -4318,7 +4318,7 @@ vars.put("loadType", "Guest");</stringProp> <collectionProp name="Arguments.arguments"> <elementProp name="sections" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> - <stringProp name="Argument.value">cart,banner,messages</stringProp> + <stringProp name="Argument.value">cart,messages</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> @@ -4440,7 +4440,7 @@ vars.put("loadType", "Guest");</stringProp> <collectionProp name="Arguments.arguments"> <elementProp name="sections" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> - <stringProp name="Argument.value">banner</stringProp> + <stringProp name="Argument.value">customer</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> @@ -4479,7 +4479,7 @@ vars.put("loadType", "Guest");</stringProp> <hashTree> <ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Response Assertion" enabled="true"> <collectionProp name="Asserion.test_strings"> - <stringProp name="-1898134910">\"banner\":</stringProp> + <stringProp name="1393473040">\"customer\":</stringProp> </collectionProp> <stringProp name="Assertion.test_field">Assertion.response_data</stringProp> <boolProp name="Assertion.assume_success">false</boolProp> @@ -4597,7 +4597,7 @@ vars.put("loadType", "Guest");</stringProp> <collectionProp name="Arguments.arguments"> <elementProp name="sections" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> - <stringProp name="Argument.value">cart,banner,messages</stringProp> + <stringProp name="Argument.value">cart,messages</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> @@ -4767,7 +4767,7 @@ vars.put("loadType", "Guest");</stringProp> <collectionProp name="Arguments.arguments"> <elementProp name="sections" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> - <stringProp name="Argument.value">banner</stringProp> + <stringProp name="Argument.value">customer</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> @@ -4806,7 +4806,7 @@ vars.put("loadType", "Guest");</stringProp> <hashTree> <ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Response Assertion" enabled="true"> <collectionProp name="Asserion.test_strings"> - <stringProp name="-1898134910">\"banner\":</stringProp> + <stringProp name="1393473040">\"customer\":</stringProp> </collectionProp> <stringProp name="Assertion.test_field">Assertion.response_data</stringProp> <boolProp name="Assertion.assume_success">false</boolProp> @@ -5074,7 +5074,7 @@ vars.put("loadType", "Guest");</stringProp> <collectionProp name="Arguments.arguments"> <elementProp name="sections" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> - <stringProp name="Argument.value">banner</stringProp> + <stringProp name="Argument.value">customer</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> @@ -5113,7 +5113,7 @@ vars.put("loadType", "Guest");</stringProp> <hashTree> <ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Response Assertion" enabled="true"> <collectionProp name="Asserion.test_strings"> - <stringProp name="-1898134910">\"banner\":</stringProp> + <stringProp name="1393473040">\"customer\":</stringProp> </collectionProp> <stringProp name="Assertion.test_field">Assertion.response_data</stringProp> <boolProp name="Assertion.assume_success">false</boolProp> @@ -5243,7 +5243,7 @@ vars.put("loadType", "Guest");</stringProp> <collectionProp name="Arguments.arguments"> <elementProp name="sections" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> - <stringProp name="Argument.value">banner</stringProp> + <stringProp name="Argument.value">customer</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> @@ -5282,7 +5282,7 @@ vars.put("loadType", "Guest");</stringProp> <hashTree> <ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Response Assertion" enabled="true"> <collectionProp name="Asserion.test_strings"> - <stringProp name="-1898134910">\"banner\":</stringProp> + <stringProp name="1393473040">\"customer\":</stringProp> </collectionProp> <stringProp name="Assertion.test_field">Assertion.response_data</stringProp> <boolProp name="Assertion.assume_success">false</boolProp> @@ -5520,7 +5520,7 @@ vars.put("loadType", "Customer");</stringProp> <collectionProp name="Arguments.arguments"> <elementProp name="sections" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> - <stringProp name="Argument.value">banner</stringProp> + <stringProp name="Argument.value">customer</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> @@ -5559,7 +5559,7 @@ vars.put("loadType", "Customer");</stringProp> <hashTree> <ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Response Assertion" enabled="true"> <collectionProp name="Asserion.test_strings"> - <stringProp name="-1898134910">\"banner\":</stringProp> + <stringProp name="1393473040">\"customer\":</stringProp> </collectionProp> <stringProp name="Assertion.test_field">Assertion.response_data</stringProp> <boolProp name="Assertion.assume_success">false</boolProp> @@ -5728,7 +5728,7 @@ vars.put("loadType", "Customer");</stringProp> <collectionProp name="Arguments.arguments"> <elementProp name="sections" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> - <stringProp name="Argument.value">banner</stringProp> + <stringProp name="Argument.value">customer</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> @@ -5767,7 +5767,7 @@ vars.put("loadType", "Customer");</stringProp> <hashTree> <ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Response Assertion" enabled="true"> <collectionProp name="Asserion.test_strings"> - <stringProp name="-1898134910">\"banner\":</stringProp> + <stringProp name="1393473040">\"customer\":</stringProp> </collectionProp> <stringProp name="Assertion.test_field">Assertion.response_data</stringProp> <boolProp name="Assertion.assume_success">false</boolProp> @@ -5839,7 +5839,7 @@ vars.put("loadType", "Customer");</stringProp> <collectionProp name="Arguments.arguments"> <elementProp name="sections" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> - <stringProp name="Argument.value">banner</stringProp> + <stringProp name="Argument.value">customer</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> @@ -5878,7 +5878,7 @@ vars.put("loadType", "Customer");</stringProp> <hashTree> <ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Response Assertion" enabled="true"> <collectionProp name="Asserion.test_strings"> - <stringProp name="-1898134910">\"banner\":</stringProp> + <stringProp name="1393473040">\"customer\":</stringProp> </collectionProp> <stringProp name="Assertion.test_field">Assertion.response_data</stringProp> <boolProp name="Assertion.assume_success">false</boolProp> @@ -5930,7 +5930,7 @@ vars.put("loadType", "Customer");</stringProp> <collectionProp name="Arguments.arguments"> <elementProp name="sections" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> - <stringProp name="Argument.value">banner</stringProp> + <stringProp name="Argument.value">customer</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> @@ -5969,7 +5969,7 @@ vars.put("loadType", "Customer");</stringProp> <hashTree> <ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Response Assertion" enabled="true"> <collectionProp name="Asserion.test_strings"> - <stringProp name="-1898134910">\"banner\":</stringProp> + <stringProp name="1393473040">\"customer\":</stringProp> </collectionProp> <stringProp name="Assertion.test_field">Assertion.response_data</stringProp> <boolProp name="Assertion.assume_success">false</boolProp> @@ -6081,7 +6081,7 @@ vars.put("loadType", "Customer");</stringProp> <collectionProp name="Arguments.arguments"> <elementProp name="sections" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> - <stringProp name="Argument.value">cart,banner,messages</stringProp> + <stringProp name="Argument.value">cart,messages</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> @@ -6200,7 +6200,7 @@ vars.put("loadType", "Customer");</stringProp> <collectionProp name="Arguments.arguments"> <elementProp name="sections" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> - <stringProp name="Argument.value">banner</stringProp> + <stringProp name="Argument.value">customer</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> @@ -6239,7 +6239,7 @@ vars.put("loadType", "Customer");</stringProp> <hashTree> <ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Response Assertion" enabled="true"> <collectionProp name="Asserion.test_strings"> - <stringProp name="-1898134910">\"banner\":</stringProp> + <stringProp name="1393473040">\"customer\":</stringProp> </collectionProp> <stringProp name="Assertion.test_field">Assertion.response_data</stringProp> <boolProp name="Assertion.assume_success">false</boolProp> @@ -6350,7 +6350,7 @@ vars.put("loadType", "Customer");</stringProp> <collectionProp name="Arguments.arguments"> <elementProp name="sections" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> - <stringProp name="Argument.value">cart,banner,messages</stringProp> + <stringProp name="Argument.value">cart,messages</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> @@ -6472,7 +6472,7 @@ vars.put("loadType", "Customer");</stringProp> <collectionProp name="Arguments.arguments"> <elementProp name="sections" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> - <stringProp name="Argument.value">banner</stringProp> + <stringProp name="Argument.value">customer</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> @@ -6511,7 +6511,7 @@ vars.put("loadType", "Customer");</stringProp> <hashTree> <ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Response Assertion" enabled="true"> <collectionProp name="Asserion.test_strings"> - <stringProp name="-1898134910">\"banner\":</stringProp> + <stringProp name="1393473040">\"customer\":</stringProp> </collectionProp> <stringProp name="Assertion.test_field">Assertion.response_data</stringProp> <boolProp name="Assertion.assume_success">false</boolProp> @@ -6629,7 +6629,7 @@ vars.put("loadType", "Customer");</stringProp> <collectionProp name="Arguments.arguments"> <elementProp name="sections" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> - <stringProp name="Argument.value">cart,banner,messages</stringProp> + <stringProp name="Argument.value">cart,messages</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> @@ -6839,7 +6839,7 @@ vars.put("loadType", "Customer");</stringProp> <collectionProp name="Arguments.arguments"> <elementProp name="sections" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> - <stringProp name="Argument.value">banner</stringProp> + <stringProp name="Argument.value">customer</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> @@ -6878,7 +6878,7 @@ vars.put("loadType", "Customer");</stringProp> <hashTree> <ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Response Assertion" enabled="true"> <collectionProp name="Asserion.test_strings"> - <stringProp name="-1898134910">\"banner\":</stringProp> + <stringProp name="1393473040">\"customer\":</stringProp> </collectionProp> <stringProp name="Assertion.test_field">Assertion.response_data</stringProp> <boolProp name="Assertion.assume_success">false</boolProp> @@ -6957,7 +6957,7 @@ vars.put("loadType", "Customer");</stringProp> <collectionProp name="Arguments.arguments"> <elementProp name="sections" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> - <stringProp name="Argument.value">banner</stringProp> + <stringProp name="Argument.value">customer</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> @@ -6996,7 +6996,7 @@ vars.put("loadType", "Customer");</stringProp> <hashTree> <ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Response Assertion" enabled="true"> <collectionProp name="Asserion.test_strings"> - <stringProp name="-1898134910">\"banner\":</stringProp> + <stringProp name="1393473040">\"customer\":</stringProp> </collectionProp> <stringProp name="Assertion.test_field">Assertion.response_data</stringProp> <boolProp name="Assertion.assume_success">false</boolProp> @@ -7113,7 +7113,7 @@ vars.put("loadType", "Customer");</stringProp> <collectionProp name="Arguments.arguments"> <elementProp name="sections" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> - <stringProp name="Argument.value">banner</stringProp> + <stringProp name="Argument.value">customer</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">sections</stringProp> @@ -7152,7 +7152,7 @@ vars.put("loadType", "Customer");</stringProp> <hashTree> <ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Response Assertion" enabled="true"> <collectionProp name="Asserion.test_strings"> - <stringProp name="-1898134910">\"banner\":</stringProp> + <stringProp name="1393473040">\"customer\":</stringProp> </collectionProp> <stringProp name="Assertion.test_field">Assertion.response_data</stringProp> <boolProp name="Assertion.assume_success">false</boolProp>