From 9d0befb24b4dd81f1568155b23ec9451fea290b8 Mon Sep 17 00:00:00 2001 From: Jeroen van Leusden Date: Fri, 13 Oct 2017 13:46:00 +0200 Subject: [PATCH 01/32] Translate order getCreatedAtFormatted() to store locale --- app/code/Magento/Sales/Model/Order.php | 20 +++++++++-- .../Sales/Test/Unit/Model/OrderTest.php | 34 ++++++++++++++++++- 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Sales/Model/Order.php b/app/code/Magento/Sales/Model/Order.php index 250aa510eafc6..50497e8d47ba1 100644 --- a/app/code/Magento/Sales/Model/Order.php +++ b/app/code/Magento/Sales/Model/Order.php @@ -7,6 +7,8 @@ use Magento\Directory\Model\Currency; use Magento\Framework\Api\AttributeValueFactory; +use Magento\Framework\App\ObjectManager; +use Magento\Framework\Locale\ResolverInterface; use Magento\Framework\Pricing\PriceCurrencyInterface; use Magento\Sales\Api\Data\OrderInterface; use Magento\Sales\Api\Data\OrderStatusHistoryInterface; @@ -212,6 +214,11 @@ class Order extends AbstractModel implements EntityInterface, OrderInterface */ protected $_currencyFactory; + /** + * @var \Magento\Eav\Model\Config + */ + private $_eavConfig; + /** * @var \Magento\Sales\Model\Order\Status\HistoryFactory */ @@ -267,6 +274,11 @@ class Order extends AbstractModel implements EntityInterface, OrderInterface */ protected $timezone; + /** + * @var ResolverInterface + */ + private $localeResolver; + /** * @param \Magento\Framework\Model\Context $context * @param \Magento\Framework\Registry $registry @@ -295,6 +307,7 @@ class Order extends AbstractModel implements EntityInterface, OrderInterface * @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource * @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection * @param array $data + * @param ResolverInterface $localeResolver * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -324,7 +337,8 @@ public function __construct( \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $productListFactory, \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null, \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null, - array $data = [] + array $data = [], + ResolverInterface $localeResolver = null ) { $this->_storeManager = $storeManager; $this->_orderConfig = $orderConfig; @@ -346,6 +360,8 @@ public function __construct( $this->_trackCollectionFactory = $trackCollectionFactory; $this->salesOrderCollectionFactory = $salesOrderCollectionFactory; $this->priceCurrency = $priceCurrency; + $this->localeResolver = $localeResolver ?: ObjectManager::getInstance()->get(ResolverInterface::class); + parent::__construct( $context, $registry, @@ -1830,7 +1846,7 @@ public function getCreatedAtFormatted($format) new \DateTime($this->getCreatedAt()), $format, $format, - null, + $this->localeResolver->getDefaultLocale(), $this->timezone->getConfigTimezone('store', $this->getStore()) ); } diff --git a/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php b/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php index dab92632426fa..fb1970638753f 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php @@ -7,6 +7,8 @@ use Magento\Catalog\Api\Data\ProductInterface; use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory as ProductCollectionFactory; +use Magento\Framework\Locale\ResolverInterface; +use Magento\Framework\Stdlib\DateTime\TimezoneInterface; use Magento\Sales\Api\Data\OrderInterface; use Magento\Sales\Model\Order; use Magento\Sales\Model\ResourceModel\Order\Status\History\CollectionFactory as HistoryCollectionFactory; @@ -73,6 +75,16 @@ class OrderTest extends \PHPUnit\Framework\TestCase */ protected $productCollectionFactoryMock; + /** + * @var ResolverInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $localeResolver; + + /** + * @var TimezoneInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $timezone; + protected function setUp() { $helper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); @@ -124,6 +136,8 @@ protected function setUp() true, ['round'] ); + $this->localeResolver = $this->createMock(ResolverInterface::class); + $this->timezone = $this->createMock(TimezoneInterface::class); $this->incrementId = '#00000001'; $this->eventManager = $this->createMock(\Magento\Framework\Event\Manager::class); $context = $this->createPartialMock(\Magento\Framework\Model\Context::class, ['getEventDispatcher']); @@ -138,7 +152,9 @@ protected function setUp() 'historyCollectionFactory' => $this->historyCollectionFactoryMock, 'salesOrderCollectionFactory' => $this->salesOrderCollectionFactoryMock, 'priceCurrency' => $this->priceCurrency, - 'productListFactory' => $this->productCollectionFactoryMock + 'productListFactory' => $this->productCollectionFactoryMock, + 'localeResolver' => $this->localeResolver, + 'timezone' => $this->timezone, ] ); } @@ -1044,6 +1060,22 @@ public function testResetOrderWillResetPayment() ); } + public function testGetCreatedAtFormattedUsesCorrectLocale() + { + $localeCode = 'nl_NL'; + + $this->localeResolver->expects($this->once())->method('getDefaultLocale')->willReturn($localeCode); + $this->timezone->expects($this->once())->method('formatDateTime') + ->with( + $this->anything(), + $this->anything(), + $this->anything(), + $localeCode + ); + + $this->order->getCreatedAtFormatted(\IntlDateFormatter::SHORT); + } + public function notInvoicingStatesProvider() { return [ From 42072dd20ac633ce678946586de6d73b83e9a43b Mon Sep 17 00:00:00 2001 From: Marius Grad Date: Sun, 15 Oct 2017 21:21:59 +0300 Subject: [PATCH 02/32] solve the toolbar problem when this is removed from the layout, code format on construcor of the product list block class --- .../Catalog/Block/Product/ListProduct.php | 74 ++++++++++++++----- 1 file changed, 54 insertions(+), 20 deletions(-) diff --git a/app/code/Magento/Catalog/Block/Product/ListProduct.php b/app/code/Magento/Catalog/Block/Product/ListProduct.php index 7289aa85ea016..83065e81c7c50 100644 --- a/app/code/Magento/Catalog/Block/Product/ListProduct.php +++ b/app/code/Magento/Catalog/Block/Product/ListProduct.php @@ -7,13 +7,18 @@ namespace Magento\Catalog\Block\Product; use Magento\Catalog\Api\CategoryRepositoryInterface; +use Magento\Catalog\Block\Product\Context; use Magento\Catalog\Block\Product\ProductList\Toolbar; +use Magento\Catalog\Helper\Product\ProductList; use Magento\Catalog\Model\Category; +use Magento\Catalog\Model\Layer\Resolver; use Magento\Catalog\Model\Product; use Magento\Catalog\Model\ResourceModel\Product\Collection; use Magento\Eav\Model\Entity\Collection\AbstractCollection; +use Magento\Framework\Data\Helper\PostHelper; use Magento\Framework\DataObject\IdentityInterface; use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Framework\Url\Helper\Data; /** * Product list @@ -33,7 +38,7 @@ class ListProduct extends AbstractProduct implements IdentityInterface /** * Product Collection * - * @var AbstractCollection + * @var \Magento\Eav\Model\Entity\Collection\AbstractCollection */ protected $_productCollection; @@ -55,30 +60,39 @@ class ListProduct extends AbstractProduct implements IdentityInterface protected $urlHelper; /** - * @var CategoryRepositoryInterface + * @var \Magento\Catalog\Api\CategoryRepositoryInterface */ protected $categoryRepository; /** - * @param Context $context + * @var \Magento\Catalog\Helper\Product\ProductList + */ + protected $productListHelper; + + /** + * + * @param \Magento\Catalog\Helper\Product\ProductList $productListHelper + * @param \Magento\Catalog\Block\Product\Context $context * @param \Magento\Framework\Data\Helper\PostHelper $postDataHelper * @param \Magento\Catalog\Model\Layer\Resolver $layerResolver - * @param CategoryRepositoryInterface $categoryRepository + * @param \Magento\Catalog\Api\CategoryRepositoryInterface $categoryRepository * @param \Magento\Framework\Url\Helper\Data $urlHelper * @param array $data */ public function __construct( - \Magento\Catalog\Block\Product\Context $context, - \Magento\Framework\Data\Helper\PostHelper $postDataHelper, - \Magento\Catalog\Model\Layer\Resolver $layerResolver, + ProductList $productListHelper, + Context $context, + PostHelper $postDataHelper, + Resolver $layerResolver, CategoryRepositoryInterface $categoryRepository, - \Magento\Framework\Url\Helper\Data $urlHelper, + Data $urlHelper, array $data = [] ) { $this->_catalogLayer = $layerResolver->get(); $this->_postDataHelper = $postDataHelper; $this->categoryRepository = $categoryRepository; $this->urlHelper = $urlHelper; + $this->productListHelper = $productListHelper; parent::__construct( $context, $data @@ -137,7 +151,12 @@ public function getLoadedProductCollection() */ public function getMode() { - return $this->getChildBlock('toolbar')->getCurrentMode(); + if ($this->getChildBlock('toolbar')) { + return $this->getChildBlock('toolbar')->getCurrentMode(); + } + // if toolbar is removed from layout, use the general configuration for product list mode + // - config path catalog/frontend/list_mode + return $this->productListHelper->getDefaultViewMode($this->getModes()); } /** @@ -148,27 +167,43 @@ public function getMode() protected function _beforeToHtml() { $collection = $this->_getProductCollection(); - $this->configureToolbar($this->getToolbarBlock(), $collection); + + $this->addToobarBlock($collection); + $collection->load(); return parent::_beforeToHtml(); } + /** + * Add toolbar block to product listing + * + * @param \Magento\Catalog\Model\ResourceModel\Product\Collection $collection + */ + private function addToobarBlock(Collection $collection) + { + $toolbar = $this->getToolbarBlock(); + if ($toolbar) { + $this->configureToolbar($toolbar, $collection); + } + } + /** * Retrieve Toolbar block * - * @return Toolbar + * @return Toolbar|false */ public function getToolbarBlock() { + $block = false; + $blockName = $this->getToolbarBlockName(); - if ($blockName) { - $block = $this->getLayout()->getBlock($blockName); - if ($block) { - return $block; - } + if (!$blockName) { + return $block; } - $block = $this->getLayout()->createBlock($this->_defaultToolbarBlock, uniqid(microtime())); + + $block = $this->getLayout()->getBlock($blockName); + return $block; } @@ -386,9 +421,8 @@ private function initializeProductCollection() if ($origCategory) { $layer->setCurrentCategory($origCategory); } - - $toolbar = $this->getToolbarBlock(); - $this->configureToolbar($toolbar, $collection); + + $this->addToobarBlock($collection); $this->_eventManager->dispatch( 'catalog_block_product_list_collection', From 9dbe44493b92407c9b02217966224cb021175c48 Mon Sep 17 00:00:00 2001 From: Marius Grad Date: Mon, 16 Oct 2017 08:49:07 +0300 Subject: [PATCH 03/32] Remove the product list helper from constructor for backward compatibility. Use the default toolbar to get current listing mode. Refactor the code. --- .../Catalog/Block/Product/ListProduct.php | 74 ++++++++++++------- 1 file changed, 47 insertions(+), 27 deletions(-) diff --git a/app/code/Magento/Catalog/Block/Product/ListProduct.php b/app/code/Magento/Catalog/Block/Product/ListProduct.php index 83065e81c7c50..0b197f93d4d35 100644 --- a/app/code/Magento/Catalog/Block/Product/ListProduct.php +++ b/app/code/Magento/Catalog/Block/Product/ListProduct.php @@ -9,7 +9,6 @@ use Magento\Catalog\Api\CategoryRepositoryInterface; use Magento\Catalog\Block\Product\Context; use Magento\Catalog\Block\Product\ProductList\Toolbar; -use Magento\Catalog\Helper\Product\ProductList; use Magento\Catalog\Model\Category; use Magento\Catalog\Model\Layer\Resolver; use Magento\Catalog\Model\Product; @@ -65,13 +64,6 @@ class ListProduct extends AbstractProduct implements IdentityInterface protected $categoryRepository; /** - * @var \Magento\Catalog\Helper\Product\ProductList - */ - protected $productListHelper; - - /** - * - * @param \Magento\Catalog\Helper\Product\ProductList $productListHelper * @param \Magento\Catalog\Block\Product\Context $context * @param \Magento\Framework\Data\Helper\PostHelper $postDataHelper * @param \Magento\Catalog\Model\Layer\Resolver $layerResolver @@ -80,7 +72,6 @@ class ListProduct extends AbstractProduct implements IdentityInterface * @param array $data */ public function __construct( - ProductList $productListHelper, Context $context, PostHelper $postDataHelper, Resolver $layerResolver, @@ -92,7 +83,6 @@ public function __construct( $this->_postDataHelper = $postDataHelper; $this->categoryRepository = $categoryRepository; $this->urlHelper = $urlHelper; - $this->productListHelper = $productListHelper; parent::__construct( $context, $data @@ -154,9 +144,31 @@ public function getMode() if ($this->getChildBlock('toolbar')) { return $this->getChildBlock('toolbar')->getCurrentMode(); } - // if toolbar is removed from layout, use the general configuration for product list mode - // - config path catalog/frontend/list_mode - return $this->productListHelper->getDefaultViewMode($this->getModes()); + + return $this->getDefaultListingMode(); + } + + /** + * Get listing mode for products if toolbar is removed from layout. + * Use the general configuration for product list mode from config path catalog/frontend/list_mode as default value + // or mode data from block declaration from layout. + * + * @return string + */ + private function getDefaultListingMode() + { + // default Toolbar when the toolbar layout is not used + $defaultToolbar = $this->getToolbarBlock(); + $availableModes = $defaultToolbar->getModes(); + + // layout config mode + $mode = $this->getData('mode'); + if (!$mode && !isset($availableModes[$mode])) { + // default config mode + $mode = $defaultToolbar->getCurrentMode(); + } + + return $mode; } /** @@ -168,7 +180,7 @@ protected function _beforeToHtml() { $collection = $this->_getProductCollection(); - $this->addToobarBlock($collection); + $this->addToolbarBlock($collection); $collection->load(); @@ -176,33 +188,41 @@ protected function _beforeToHtml() } /** - * Add toolbar block to product listing + * Add toolbar block from product listing layout * * @param \Magento\Catalog\Model\ResourceModel\Product\Collection $collection */ - private function addToobarBlock(Collection $collection) + private function addToolbarBlock(Collection $collection) { - $toolbar = $this->getToolbarBlock(); - if ($toolbar) { - $this->configureToolbar($toolbar, $collection); + $toolbarLayout = false; + + $blockName = $this->getToolbarBlockName(); + + if ($blockName) { + $toolbarLayout = $this->getLayout()->getBlock($blockName); + } + + if ($toolbarLayout) { + $this->configureToolbar($toolbarLayout, $collection); } } /** - * Retrieve Toolbar block + * Retrieve Toolbar block from layout or a default Toolbar * - * @return Toolbar|false + * @return Toolbar */ public function getToolbarBlock() { - $block = false; - $blockName = $this->getToolbarBlockName(); - if (!$blockName) { - return $block; + + if ($blockName) { + $block = $this->getLayout()->getBlock($blockName); } - $block = $this->getLayout()->getBlock($blockName); + if (!$block) { + $block = $this->getLayout()->createBlock($this->_defaultToolbarBlock, uniqid(microtime())); + } return $block; } @@ -422,7 +442,7 @@ private function initializeProductCollection() $layer->setCurrentCategory($origCategory); } - $this->addToobarBlock($collection); + $this->addToolbarBlock($collection); $this->_eventManager->dispatch( 'catalog_block_product_list_collection', From 49fdfaee640a79ef6278e9df247a07217d9d597c Mon Sep 17 00:00:00 2001 From: Marius Grad Date: Mon, 16 Oct 2017 10:56:16 +0300 Subject: [PATCH 04/32] refactor the code on get toolbar block from layout, fix condition on using the mode layout configuration --- .../Catalog/Block/Product/ListProduct.php | 35 ++++++++++++------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/app/code/Magento/Catalog/Block/Product/ListProduct.php b/app/code/Magento/Catalog/Block/Product/ListProduct.php index 0b197f93d4d35..abcc106337617 100644 --- a/app/code/Magento/Catalog/Block/Product/ListProduct.php +++ b/app/code/Magento/Catalog/Block/Product/ListProduct.php @@ -163,7 +163,8 @@ private function getDefaultListingMode() // layout config mode $mode = $this->getData('mode'); - if (!$mode && !isset($availableModes[$mode])) { + + if (!$mode || !isset($availableModes[$mode])) { // default config mode $mode = $defaultToolbar->getCurrentMode(); } @@ -194,13 +195,7 @@ protected function _beforeToHtml() */ private function addToolbarBlock(Collection $collection) { - $toolbarLayout = false; - - $blockName = $this->getToolbarBlockName(); - - if ($blockName) { - $toolbarLayout = $this->getLayout()->getBlock($blockName); - } + $toolbarLayout = $this->getToolbarFromLayout(); if ($toolbarLayout) { $this->configureToolbar($toolbarLayout, $collection); @@ -214,11 +209,7 @@ private function addToolbarBlock(Collection $collection) */ public function getToolbarBlock() { - $blockName = $this->getToolbarBlockName(); - - if ($blockName) { - $block = $this->getLayout()->getBlock($blockName); - } + $block = $this->getToolbarFromLayout(); if (!$block) { $block = $this->getLayout()->createBlock($this->_defaultToolbarBlock, uniqid(microtime())); @@ -227,6 +218,24 @@ public function getToolbarBlock() return $block; } + /** + * Get toolbar block from layout + * + * @return bool|Toolbar + */ + private function getToolbarFromLayout() + { + $blockName = $this->getToolbarBlockName(); + + $toolbarLayout = false; + + if ($blockName) { + $toolbarLayout = $this->getLayout()->getBlock($blockName); + } + + return $toolbarLayout; + } + /** * Retrieve additional blocks html * From b6ed2d9b31de64b234540abfd28f55485c4556bd Mon Sep 17 00:00:00 2001 From: Marius Grad Date: Mon, 16 Oct 2017 13:03:51 +0300 Subject: [PATCH 05/32] Update the toolbar test with product list collection. The toolbar HTML depends on product collection. Because you can remove the toolbar from layout, there is no reason for parent class to add the product collection to default toolbar if the toolbar is never used. That is why the test toolbar coverage needs to include a product collection before checking the toolbar HTML. --- .../testsuite/Magento/Catalog/Block/Product/ListTest.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/ListTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/ListTest.php index 17c0f451f9083..43240824d43a5 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/ListTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/ListTest.php @@ -62,6 +62,9 @@ public function testToolbarCoverage() /* In order to initialize toolbar collection block toHtml should be called before toolbar toHtml */ $this->assertEmpty($parent->toHtml(), 'Block HTML'); /* Template not specified */ $this->assertEquals('grid', $parent->getMode(), 'Default Mode'); /* default mode */ + + /* In order to use toolbar html you need a collection to be set to toolbar block */ + $parent->getToolbarBlock()->setCollection($parent->getLoadedProductCollection()); $this->assertNotEmpty($parent->getToolbarHtml(), 'Toolbar HTML'); /* toolbar for one simple product */ } From 9cd20c03f9c4f3d7dd79865addf8dac9aa6139db Mon Sep 17 00:00:00 2001 From: Marius Grad Date: Mon, 16 Oct 2017 15:46:14 +0300 Subject: [PATCH 06/32] Update the toolbar coverage test to use the a layout toolbar declaration present in default layout. Remove the previews correction made because it's not solve the problem where is checking if the toolbar HTML is not empty. --- .../testsuite/Magento/Catalog/Block/Product/ListTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/ListTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/ListTest.php index 43240824d43a5..8773256b85785 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/ListTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/ListTest.php @@ -55,6 +55,9 @@ public function testToolbarCoverage() $parent = $this->_getLayout()->createBlock(\Magento\Catalog\Block\Product\ListProduct::class, 'parent'); /* Prepare toolbar block */ + $this->_getLayout()->createBlock(\Magento\Catalog\Block\Product\ProductList\Toolbar::class, 'product_list_toolbar'); + $parent->setToolbarBlockName('product_list_toolbar'); + $toolbar = $parent->getToolbarBlock(); $this->assertInstanceOf(\Magento\Catalog\Block\Product\ProductList\Toolbar::class, $toolbar, 'Default Toolbar'); @@ -62,9 +65,6 @@ public function testToolbarCoverage() /* In order to initialize toolbar collection block toHtml should be called before toolbar toHtml */ $this->assertEmpty($parent->toHtml(), 'Block HTML'); /* Template not specified */ $this->assertEquals('grid', $parent->getMode(), 'Default Mode'); /* default mode */ - - /* In order to use toolbar html you need a collection to be set to toolbar block */ - $parent->getToolbarBlock()->setCollection($parent->getLoadedProductCollection()); $this->assertNotEmpty($parent->getToolbarHtml(), 'Toolbar HTML'); /* toolbar for one simple product */ } From 2adefdff73c62d829d1969b3abc988992bd3da39 Mon Sep 17 00:00:00 2001 From: Marius Grad Date: Mon, 16 Oct 2017 19:26:15 +0300 Subject: [PATCH 07/32] fix static line limit test --- .../testsuite/Magento/Catalog/Block/Product/ListTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/ListTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/ListTest.php index 8773256b85785..f68e509e4a8dd 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/ListTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/ListTest.php @@ -55,7 +55,8 @@ public function testToolbarCoverage() $parent = $this->_getLayout()->createBlock(\Magento\Catalog\Block\Product\ListProduct::class, 'parent'); /* Prepare toolbar block */ - $this->_getLayout()->createBlock(\Magento\Catalog\Block\Product\ProductList\Toolbar::class, 'product_list_toolbar'); + $this->_getLayout() + ->createBlock(\Magento\Catalog\Block\Product\ProductList\Toolbar::class, 'product_list_toolbar'); $parent->setToolbarBlockName('product_list_toolbar'); $toolbar = $parent->getToolbarBlock(); From cfd92c4ff13bcd55d0ac6b06a820d74ee78f2558 Mon Sep 17 00:00:00 2001 From: Anton Evers Date: Tue, 24 Oct 2017 11:41:51 +0600 Subject: [PATCH 08/32] save invoice ID on credit memo when using API method salesRefundInvoiceV1 --- .../Magento/Sales/Model/Order/Creditmemo.php | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo.php b/app/code/Magento/Sales/Model/Order/Creditmemo.php index 68339e7db9390..771b8ea459aad 100644 --- a/app/code/Magento/Sales/Model/Order/Creditmemo.php +++ b/app/code/Magento/Sales/Model/Order/Creditmemo.php @@ -9,8 +9,10 @@ namespace Magento\Sales\Model\Order; use Magento\Framework\Api\AttributeValueFactory; +use Magento\Framework\App\ObjectManager; use Magento\Framework\Pricing\PriceCurrencyInterface; use Magento\Sales\Api\Data\CreditmemoInterface; +use Magento\Sales\Api\InvoiceRepositoryInterface; use Magento\Sales\Model\AbstractModel; use Magento\Sales\Model\EntityInterface; @@ -114,6 +116,11 @@ class Creditmemo extends AbstractModel implements EntityInterface, CreditmemoInt */ protected $priceCurrency; + /** + * @var InvoiceRepository + */ + private $invoiceRepository; + /** * @param \Magento\Framework\Model\Context $context * @param \Magento\Framework\Registry $registry @@ -130,6 +137,7 @@ class Creditmemo extends AbstractModel implements EntityInterface, CreditmemoInt * @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource * @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection * @param array $data + * @param InvoiceRepository $invoiceRepository * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -147,7 +155,8 @@ public function __construct( PriceCurrencyInterface $priceCurrency, \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null, \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null, - array $data = [] + array $data = [], + InvoiceRepository $invoiceRepository = null ) { $this->_creditmemoConfig = $creditmemoConfig; $this->_orderFactory = $orderFactory; @@ -157,6 +166,7 @@ public function __construct( $this->_commentFactory = $commentFactory; $this->_commentCollectionFactory = $commentCollectionFactory; $this->priceCurrency = $priceCurrency; + $this->invoiceRepository = $invoiceRepository; parent::__construct( $context, $registry, @@ -379,6 +389,9 @@ public function canRefund() */ public function getInvoice() { + if (!$this->getData('invoice') instanceof \Magento\Sales\Model\Order\Invoice && $this->getInvoiceId()) { + $this->setInvoice($this->getInvoiceRepository()->get($this->getInvoiceId())); + } return $this->getData('invoice'); } @@ -391,6 +404,7 @@ public function getInvoice() public function setInvoice(Invoice $invoice) { $this->setData('invoice', $invoice); + $this->setInvoiceId($invoice->getId()); return $this; } @@ -1525,5 +1539,12 @@ public function setExtensionAttributes(\Magento\Sales\Api\Data\CreditmemoExtensi return $this->_setExtensionAttributes($extensionAttributes); } + /** + * @return InvoiceRepositoryInterface|mixed + * @deprecated + */ + private function getInvoiceRepository() { + return $this->invoiceRepository ?: ObjectManager::getInstance()->get(InvoiceRepositoryInterface::class); + } //@codeCoverageIgnoreEnd } From 94ae23d423c1647e2d9722f6a5cdd42c9bb7902d Mon Sep 17 00:00:00 2001 From: Anton Evers Date: Tue, 24 Oct 2017 12:21:44 +0600 Subject: [PATCH 09/32] Move deprecated method logic to constructor --- app/code/Magento/Sales/Model/Order/Creditmemo.php | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo.php b/app/code/Magento/Sales/Model/Order/Creditmemo.php index 771b8ea459aad..cea854cae6cd2 100644 --- a/app/code/Magento/Sales/Model/Order/Creditmemo.php +++ b/app/code/Magento/Sales/Model/Order/Creditmemo.php @@ -166,7 +166,7 @@ public function __construct( $this->_commentFactory = $commentFactory; $this->_commentCollectionFactory = $commentCollectionFactory; $this->priceCurrency = $priceCurrency; - $this->invoiceRepository = $invoiceRepository; + $this->invoiceRepository = $invoiceRepository ?: ObjectManager::getInstance()->get(InvoiceRepositoryInterface::class); parent::__construct( $context, $registry, @@ -1538,13 +1538,5 @@ public function setExtensionAttributes(\Magento\Sales\Api\Data\CreditmemoExtensi { return $this->_setExtensionAttributes($extensionAttributes); } - - /** - * @return InvoiceRepositoryInterface|mixed - * @deprecated - */ - private function getInvoiceRepository() { - return $this->invoiceRepository ?: ObjectManager::getInstance()->get(InvoiceRepositoryInterface::class); - } //@codeCoverageIgnoreEnd } From 02bc89297aad77fbd68c6263d421a0d254af7a41 Mon Sep 17 00:00:00 2001 From: Jeroen van Leusden Date: Fri, 13 Oct 2017 15:38:45 +0200 Subject: [PATCH 10/32] Remove unused eavConfig in Order Model --- app/code/Magento/Sales/Model/Order.php | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/app/code/Magento/Sales/Model/Order.php b/app/code/Magento/Sales/Model/Order.php index 50497e8d47ba1..85443ee7f4f11 100644 --- a/app/code/Magento/Sales/Model/Order.php +++ b/app/code/Magento/Sales/Model/Order.php @@ -214,11 +214,6 @@ class Order extends AbstractModel implements EntityInterface, OrderInterface */ protected $_currencyFactory; - /** - * @var \Magento\Eav\Model\Config - */ - private $_eavConfig; - /** * @var \Magento\Sales\Model\Order\Status\HistoryFactory */ @@ -309,6 +304,7 @@ class Order extends AbstractModel implements EntityInterface, OrderInterface * @param array $data * @param ResolverInterface $localeResolver * @SuppressWarnings(PHPMD.ExcessiveParameterList) + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function __construct( \Magento\Framework\Model\Context $context, @@ -349,7 +345,6 @@ public function __construct( $this->_productVisibility = $productVisibility; $this->invoiceManagement = $invoiceManagement; $this->_currencyFactory = $currencyFactory; - $this->_eavConfig = $eavConfig; $this->_orderHistoryFactory = $orderHistoryFactory; $this->_addressCollectionFactory = $addressCollectionFactory; $this->_paymentCollectionFactory = $paymentCollectionFactory; From 914520985b2ed374a57dd74df8688fff46f06e5b Mon Sep 17 00:00:00 2001 From: Anton Evers Date: Tue, 24 Oct 2017 15:59:23 +0600 Subject: [PATCH 11/32] Replace call to removed method --- app/code/Magento/Sales/Model/Order/Creditmemo.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo.php b/app/code/Magento/Sales/Model/Order/Creditmemo.php index cea854cae6cd2..d29a4bc58d5fc 100644 --- a/app/code/Magento/Sales/Model/Order/Creditmemo.php +++ b/app/code/Magento/Sales/Model/Order/Creditmemo.php @@ -390,7 +390,7 @@ public function canRefund() public function getInvoice() { if (!$this->getData('invoice') instanceof \Magento\Sales\Model\Order\Invoice && $this->getInvoiceId()) { - $this->setInvoice($this->getInvoiceRepository()->get($this->getInvoiceId())); + $this->setInvoice($this->invoiceRepository->get($this->getInvoiceId())); } return $this->getData('invoice'); } From cbda7b821c976d82eb3c513c435cd941e4b287fb Mon Sep 17 00:00:00 2001 From: Marius Date: Tue, 24 Oct 2017 14:39:44 +0300 Subject: [PATCH 12/32] Remove FQCN Remove FQCN --- .../Magento/Catalog/Block/Product/ListProduct.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/Catalog/Block/Product/ListProduct.php b/app/code/Magento/Catalog/Block/Product/ListProduct.php index abcc106337617..5bb0b772f90de 100644 --- a/app/code/Magento/Catalog/Block/Product/ListProduct.php +++ b/app/code/Magento/Catalog/Block/Product/ListProduct.php @@ -37,29 +37,29 @@ class ListProduct extends AbstractProduct implements IdentityInterface /** * Product Collection * - * @var \Magento\Eav\Model\Entity\Collection\AbstractCollection + * @var AbstractCollection */ protected $_productCollection; /** * Catalog layer * - * @var \Magento\Catalog\Model\Layer + * @var Layer */ protected $_catalogLayer; /** - * @var \Magento\Framework\Data\Helper\PostHelper + * @var PostHelper */ protected $_postDataHelper; /** - * @var \Magento\Framework\Url\Helper\Data + * @var Data */ protected $urlHelper; /** - * @var \Magento\Catalog\Api\CategoryRepositoryInterface + * @var CategoryRepositoryInterface */ protected $categoryRepository; @@ -151,7 +151,7 @@ public function getMode() /** * Get listing mode for products if toolbar is removed from layout. * Use the general configuration for product list mode from config path catalog/frontend/list_mode as default value - // or mode data from block declaration from layout. + * or mode data from block declaration from layout. * * @return string */ From ce20c0a5a9b27ace8d9891e38e864ffecadb2eff Mon Sep 17 00:00:00 2001 From: Anton Evers Date: Wed, 25 Oct 2017 11:08:09 +0600 Subject: [PATCH 13/32] Refactor invoice id persistance and retrieval to be more like the get and setOrder --- app/code/Magento/Sales/Model/Order/Creditmemo.php | 15 +++++++-------- .../Model/ResourceModel/Order/Creditmemo.php | 4 ++++ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo.php b/app/code/Magento/Sales/Model/Order/Creditmemo.php index d29a4bc58d5fc..a516b52bcb3de 100644 --- a/app/code/Magento/Sales/Model/Order/Creditmemo.php +++ b/app/code/Magento/Sales/Model/Order/Creditmemo.php @@ -12,9 +12,9 @@ use Magento\Framework\App\ObjectManager; use Magento\Framework\Pricing\PriceCurrencyInterface; use Magento\Sales\Api\Data\CreditmemoInterface; -use Magento\Sales\Api\InvoiceRepositoryInterface; use Magento\Sales\Model\AbstractModel; use Magento\Sales\Model\EntityInterface; +use Magento\Sales\Model\InvoiceFactory; /** * Order creditmemo model @@ -117,9 +117,9 @@ class Creditmemo extends AbstractModel implements EntityInterface, CreditmemoInt protected $priceCurrency; /** - * @var InvoiceRepository + * @var InvoiceFactory */ - private $invoiceRepository; + private $invoiceFactory; /** * @param \Magento\Framework\Model\Context $context @@ -137,7 +137,7 @@ class Creditmemo extends AbstractModel implements EntityInterface, CreditmemoInt * @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource * @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection * @param array $data - * @param InvoiceRepository $invoiceRepository + * @param InvoiceFactory $invoiceFactory * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -156,7 +156,7 @@ public function __construct( \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null, \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null, array $data = [], - InvoiceRepository $invoiceRepository = null + InvoiceFactory $invoiceFactory = null ) { $this->_creditmemoConfig = $creditmemoConfig; $this->_orderFactory = $orderFactory; @@ -166,7 +166,7 @@ public function __construct( $this->_commentFactory = $commentFactory; $this->_commentCollectionFactory = $commentCollectionFactory; $this->priceCurrency = $priceCurrency; - $this->invoiceRepository = $invoiceRepository ?: ObjectManager::getInstance()->get(InvoiceRepositoryInterface::class); + $this->invoiceFactory = $invoiceFactory ?: ObjectManager::getInstance()->get(InvoiceFactory::class); parent::__construct( $context, $registry, @@ -390,7 +390,7 @@ public function canRefund() public function getInvoice() { if (!$this->getData('invoice') instanceof \Magento\Sales\Model\Order\Invoice && $this->getInvoiceId()) { - $this->setInvoice($this->invoiceRepository->get($this->getInvoiceId())); + $this->setInvoice($this->invoiceFactory->create()->load($this->getInvoiceId())); } return $this->getData('invoice'); } @@ -404,7 +404,6 @@ public function getInvoice() public function setInvoice(Invoice $invoice) { $this->setData('invoice', $invoice); - $this->setInvoiceId($invoice->getId()); return $this; } diff --git a/app/code/Magento/Sales/Model/ResourceModel/Order/Creditmemo.php b/app/code/Magento/Sales/Model/ResourceModel/Order/Creditmemo.php index f95a3206ce786..5ecbbd777a14e 100644 --- a/app/code/Magento/Sales/Model/ResourceModel/Order/Creditmemo.php +++ b/app/code/Magento/Sales/Model/ResourceModel/Order/Creditmemo.php @@ -50,6 +50,10 @@ protected function _beforeSave(\Magento\Framework\Model\AbstractModel $object) $object->setBillingAddressId($object->getOrder()->getBillingAddress()->getId()); } + if (!$object->getInvoiceId() && $object->getInvoice()) { + $object->setInvoiceId($object->getInvoice()->getId()); + } + return parent::_beforeSave($object); } } From 23f315c82601a3b89499b7a288833f5d36c798a2 Mon Sep 17 00:00:00 2001 From: Anton Evers Date: Wed, 25 Oct 2017 11:09:19 +0600 Subject: [PATCH 14/32] Fix IpnTest In the IpnTest creates a creditmemo for the invoice in $ipnModel->processIpnRequest() already So if Magento/Paypal/_files/order_express_with_invoice_and_creditmemo.php is used, the invoice is already refunded before the start of the test --- .../integration/testsuite/Magento/Paypal/Model/IpnTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Paypal/Model/IpnTest.php b/dev/tests/integration/testsuite/Magento/Paypal/Model/IpnTest.php index 2da602c52242d..1a22ea947f85a 100644 --- a/dev/tests/integration/testsuite/Magento/Paypal/Model/IpnTest.php +++ b/dev/tests/integration/testsuite/Magento/Paypal/Model/IpnTest.php @@ -123,7 +123,7 @@ public function testProcessIpnRequestPartialRefund() /** * Refund rest of order amount by Paypal Express IPN message service. * - * @magentoDataFixture Magento/Paypal/_files/order_express_with_invoice_and_creditmemo.php + * @magentoDataFixture Magento/Paypal/_files/order_express_with_invoice_and_shipping.php * @magentoConfigFixture current_store payment/paypal_express/active 1 * @magentoConfigFixture current_store paypal/general/merchant_country US */ @@ -147,7 +147,7 @@ public function testProcessIpnRequestRestRefund() $creditmemoItems = $order->getCreditmemosCollection()->getItems(); $this->assertEquals(Order::STATE_CLOSED, $order->getState()) ; - $this->assertEquals(2, count($creditmemoItems)); + $this->assertEquals(1, count($creditmemoItems)); $this->assertEquals(10, $order->getSubtotalRefunded()); $this->assertEquals(10, $order->getBaseSubtotalRefunded()); $this->assertEquals(20, $order->getShippingRefunded()); From 72533ad5801b3839398e1bd091495537a5429361 Mon Sep 17 00:00:00 2001 From: Anton Evers Date: Wed, 25 Oct 2017 11:15:10 +0600 Subject: [PATCH 15/32] specify the correct invoice factory --- app/code/Magento/Sales/Model/Order/Creditmemo.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo.php b/app/code/Magento/Sales/Model/Order/Creditmemo.php index a516b52bcb3de..3cf4d01727338 100644 --- a/app/code/Magento/Sales/Model/Order/Creditmemo.php +++ b/app/code/Magento/Sales/Model/Order/Creditmemo.php @@ -14,7 +14,7 @@ use Magento\Sales\Api\Data\CreditmemoInterface; use Magento\Sales\Model\AbstractModel; use Magento\Sales\Model\EntityInterface; -use Magento\Sales\Model\InvoiceFactory; +use Magento\Sales\Model\Order\InvoiceFactory; /** * Order creditmemo model From 9193745655b641d142d487c5e88f1a839cff821e Mon Sep 17 00:00:00 2001 From: RomanKis Date: Fri, 3 Nov 2017 12:50:34 +0200 Subject: [PATCH 16/32] 11740: Sending emails from Admin in Multi-Store Environment defaults to Primary Store --- .../Sales/Model/Order/Email/SenderBuilder.php | 5 ++- .../Model/Order/Email/SenderBuilderTest.php | 43 +++++++++++++++---- .../Mail/Template/TransportBuilder.php | 14 ++++++ .../Unit/Template/TransportBuilderTest.php | 20 +++++++++ 4 files changed, 73 insertions(+), 9 deletions(-) diff --git a/app/code/Magento/Sales/Model/Order/Email/SenderBuilder.php b/app/code/Magento/Sales/Model/Order/Email/SenderBuilder.php index 93c6f19b08690..af3ace9090834 100644 --- a/app/code/Magento/Sales/Model/Order/Email/SenderBuilder.php +++ b/app/code/Magento/Sales/Model/Order/Email/SenderBuilder.php @@ -98,6 +98,9 @@ protected function configureEmailTemplate() $this->transportBuilder->setTemplateIdentifier($this->templateContainer->getTemplateId()); $this->transportBuilder->setTemplateOptions($this->templateContainer->getTemplateOptions()); $this->transportBuilder->setTemplateVars($this->templateContainer->getTemplateVars()); - $this->transportBuilder->setFrom($this->identityContainer->getEmailIdentity()); + $this->transportBuilder->setFromByStore( + $this->identityContainer->getEmailIdentity(), + $this->identityContainer->getStore()->getId() + ); } } diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Email/SenderBuilderTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Email/SenderBuilderTest.php index 5319aa510bedf..d537cab8ff552 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Order/Email/SenderBuilderTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Email/SenderBuilderTest.php @@ -3,6 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\Sales\Test\Unit\Model\Order\Email; use Magento\Sales\Model\Order\Email\SenderBuilder; @@ -29,6 +30,11 @@ class SenderBuilderTest extends \PHPUnit\Framework\TestCase */ protected $transportBuilder; + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $storeMock; + protected function setUp() { $templateId = 'test_template_id'; @@ -42,7 +48,11 @@ protected function setUp() ['getTemplateVars', 'getTemplateOptions', 'getTemplateId'] ); - $this->storeMock = $this->createPartialMock(\Magento\Store\Model\Store::class, ['getStoreId', '__wakeup']); + $this->storeMock = $this->createPartialMock(\Magento\Store\Model\Store::class, [ + 'getStoreId', + '__wakeup', + 'getId', + ]); $this->identityContainerMock = $this->createPartialMock( \Magento\Sales\Model\Order\Email\Container\ShipmentIdentity::class, @@ -52,14 +62,20 @@ protected function setUp() 'getCustomerName', 'getTemplateOptions', 'getEmailCopyTo', - 'getCopyMethod' + 'getCopyMethod', + 'getStore', ] ); - $this->transportBuilder = $this->createPartialMock(\Magento\Framework\Mail\Template\TransportBuilder::class, [ - 'addTo', 'addBcc', 'getTransport', - 'setTemplateIdentifier', 'setTemplateOptions', 'setTemplateVars', - 'setFrom', + $this->transportBuilder = $this->createPartialMock(\Magento\Framework\Mail\Template\TransportBuilder::class, + [ + 'addTo', + 'addBcc', + 'getTransport', + 'setTemplateIdentifier', + 'setTemplateOptions', + 'setTemplateVars', + 'setFromByStore', ]); $this->templateContainerMock->expects($this->once()) @@ -85,7 +101,7 @@ protected function setUp() ->method('getEmailIdentity') ->will($this->returnValue($emailIdentity)); $this->transportBuilder->expects($this->once()) - ->method('setFrom') + ->method('setFromByStore') ->with($this->equalTo($emailIdentity)); $this->identityContainerMock->expects($this->once()) @@ -119,6 +135,12 @@ public function testSend() $this->identityContainerMock->expects($this->once()) ->method('getCustomerName') ->will($this->returnValue($customerName)); + $this->identityContainerMock->expects($this->once()) + ->method('getStore') + ->willReturn($this->storeMock); + $this->storeMock->expects($this->once()) + ->method('getId') + ->willReturn(1); $this->transportBuilder->expects($this->once()) ->method('addTo') ->with($this->equalTo($customerEmail), $this->equalTo($customerName)); @@ -145,7 +167,12 @@ public function testSendCopyTo() $this->transportBuilder->expects($this->once()) ->method('addTo') ->with($this->equalTo('example@mail.com')); - + $this->identityContainerMock->expects($this->once()) + ->method('getStore') + ->willReturn($this->storeMock); + $this->storeMock->expects($this->once()) + ->method('getId') + ->willReturn(1); $this->transportBuilder->expects($this->once()) ->method('getTransport') ->will($this->returnValue($transportMock)); diff --git a/lib/internal/Magento/Framework/Mail/Template/TransportBuilder.php b/lib/internal/Magento/Framework/Mail/Template/TransportBuilder.php index 18b241d77a426..8e474a58cdac8 100644 --- a/lib/internal/Magento/Framework/Mail/Template/TransportBuilder.php +++ b/lib/internal/Magento/Framework/Mail/Template/TransportBuilder.php @@ -171,6 +171,20 @@ public function setFrom($from) return $this; } + /** + * Set mail from address by store. + * + * @param string|array $from + * @param string|int $store + * @return $this + */ + public function setFromByStore($from, $store) + { + $result = $this->_senderResolver->resolve($from, $store); + $this->message->setFrom($result['email'], $result['name']); + return $this; + } + /** * Set template identifier * diff --git a/lib/internal/Magento/Framework/Mail/Test/Unit/Template/TransportBuilderTest.php b/lib/internal/Magento/Framework/Mail/Test/Unit/Template/TransportBuilderTest.php index 696e0a9f310d8..ab03be5ee844b 100644 --- a/lib/internal/Magento/Framework/Mail/Test/Unit/Template/TransportBuilderTest.php +++ b/lib/internal/Magento/Framework/Mail/Test/Unit/Template/TransportBuilderTest.php @@ -3,6 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\Framework\Mail\Test\Unit\Template; use Magento\Framework\App\TemplateTypesInterface; @@ -167,6 +168,25 @@ public function testSetFrom() $this->builder->setFrom($sender); } + /** + * @return void + */ + public function setFromByStore() + { + $sender = ['email' => 'from@example.com', 'name' => 'name']; + $store = 1; + $this->senderResolverMock->expects($this->once()) + ->method('resolve') + ->with($sender, $store) + ->willReturn($sender); + $this->messageMock->expects($this->once()) + ->method('setFrom') + ->with('from@example.com', 'name') + ->willReturnSelf(); + + $this->builder->setFromByStore($sender); + } + /** * @return void */ From ef03b523315c07c7cd26a5292885cf668a0b6e3d Mon Sep 17 00:00:00 2001 From: RomanKis Date: Fri, 3 Nov 2017 16:07:23 +0200 Subject: [PATCH 17/32] 11740: Sending emails from Admin in Multi-Store Environment defaults to Primary Store --- .../Sales/Test/Unit/Model/Order/Email/SenderBuilderTest.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Email/SenderBuilderTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Email/SenderBuilderTest.php index d537cab8ff552..00be3c10d6498 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Order/Email/SenderBuilderTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Email/SenderBuilderTest.php @@ -67,7 +67,8 @@ protected function setUp() ] ); - $this->transportBuilder = $this->createPartialMock(\Magento\Framework\Mail\Template\TransportBuilder::class, + $this->transportBuilder = $this->createPartialMock( + \Magento\Framework\Mail\Template\TransportBuilder::class, [ 'addTo', 'addBcc', @@ -76,7 +77,8 @@ protected function setUp() 'setTemplateOptions', 'setTemplateVars', 'setFromByStore', - ]); + ] + ); $this->templateContainerMock->expects($this->once()) ->method('getTemplateId') From 6d5c1f5414af9fc44868913ae484596c2fc04bc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20M=C3=A9ndez=20Calzada?= Date: Sun, 5 Nov 2017 12:32:57 +0100 Subject: [PATCH 18/32] add swatch option: prevent loosing data and default value if data is not populated via adminhtml --- .../Magento/Swatches/Model/Plugin/EavAttribute.php | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Swatches/Model/Plugin/EavAttribute.php b/app/code/Magento/Swatches/Model/Plugin/EavAttribute.php index f363ffe70e80e..599406f455281 100644 --- a/app/code/Magento/Swatches/Model/Plugin/EavAttribute.php +++ b/app/code/Magento/Swatches/Model/Plugin/EavAttribute.php @@ -130,9 +130,17 @@ protected function setProperOptionsArray(Attribute $attribute) $swatchesArray = $attribute->getData('swatchtext'); } if ($canReplace == true) { - $attribute->setData('option', $optionsArray); - $attribute->setData('default', $defaultValue); - $attribute->setData('swatch', $swatchesArray); + if (!empty($optionsArray)) { + $attribute->setData('option', $optionsArray); + } + if (!empty($defaultValue)) { + $attribute->setData('default', $defaultValue); + } else { + $attribute->setData('default', [0 => $attribute->getDefaultValue()]); + } + if (!empty($swatchesArray)) { + $attribute->setData('swatch', $swatchesArray); + } } } From 149268c5c30267a04d50f8cc63f2ea3df0b8708e Mon Sep 17 00:00:00 2001 From: Andrew Garside Date: Sun, 12 Nov 2017 14:24:12 +1000 Subject: [PATCH 19/32] Update the fixture and tests to reflect the functionality of getShippingMethod --- .../testsuite/Magento/Sales/Service/V1/OrderCreateTest.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderCreateTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderCreateTest.php index b61bfdabe25cd..a907faac98b72 100755 --- a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderCreateTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderCreateTest.php @@ -140,7 +140,7 @@ protected function prepareOrder() [ 'shipping' => [ 'address' => $address, - 'method' => 'Flat Rate - Fixed' + 'method' => 'flatrate_flatrate' ], 'items' => [$orderItem->getData()], 'stock_id' => null, @@ -232,6 +232,9 @@ public function testOrderCreate() $this->assertEquals($order['grand_total'], $model->getGrandTotal()); $this->assertNotNull($model->getShippingAddress()); $this->assertTrue((bool)$model->getShippingAddress()->getId()); - $this->assertEquals('Flat Rate - Fixed', $model->getShippingMethod()); + $this->assertEquals('Flat Rate - Fixed', $model->getShippingDescription()); + $shippingMethod = $model->getShippingMethod(true); + $this->assertEquals('flatrate', $shippingMethod['carrier_code']); + $this->assertEquals('flatrate', $shippingMethod['method']); } } From f2bfdd941c0c8c6c7c745156d1ce206e38c76820 Mon Sep 17 00:00:00 2001 From: RomanKis Date: Mon, 13 Nov 2017 17:43:17 +0200 Subject: [PATCH 20/32] 11740: Sending emails from Admin in Multi-Store Environment defaults to Primary Store --- .../Sales/Model/Order/Email/SenderBuilder.php | 16 ++++- .../Model/Order/Email/SenderBuilderTest.php | 14 +++- .../Mail/Template/TransportBuilder.php | 14 ---- .../Mail/Template/TransportBuilderByStore.php | 54 ++++++++++++++++ .../Template/TransportBuilderByStoreTest.php | 64 +++++++++++++++++++ .../Unit/Template/TransportBuilderTest.php | 19 ------ 6 files changed, 143 insertions(+), 38 deletions(-) create mode 100644 lib/internal/Magento/Framework/Mail/Template/TransportBuilderByStore.php create mode 100644 lib/internal/Magento/Framework/Mail/Test/Unit/Template/TransportBuilderByStoreTest.php diff --git a/app/code/Magento/Sales/Model/Order/Email/SenderBuilder.php b/app/code/Magento/Sales/Model/Order/Email/SenderBuilder.php index af3ace9090834..7ec089b882972 100644 --- a/app/code/Magento/Sales/Model/Order/Email/SenderBuilder.php +++ b/app/code/Magento/Sales/Model/Order/Email/SenderBuilder.php @@ -5,7 +5,9 @@ */ namespace Magento\Sales\Model\Order\Email; +use Magento\Framework\App\ObjectManager; use Magento\Framework\Mail\Template\TransportBuilder; +use Magento\Framework\Mail\Template\TransportBuilderByStore; use Magento\Sales\Model\Order\Email\Container\IdentityInterface; use Magento\Sales\Model\Order\Email\Container\Template; @@ -26,19 +28,29 @@ class SenderBuilder */ protected $transportBuilder; + /** + * @var TransportBuilderByStore + */ + private $transportBuilderByStore; + /** * @param Template $templateContainer * @param IdentityInterface $identityContainer * @param TransportBuilder $transportBuilder + * @param TransportBuilderByStore $transportBuilderByStore */ public function __construct( Template $templateContainer, IdentityInterface $identityContainer, - TransportBuilder $transportBuilder + TransportBuilder $transportBuilder, + TransportBuilderByStore $transportBuilderByStore = null ) { $this->templateContainer = $templateContainer; $this->identityContainer = $identityContainer; $this->transportBuilder = $transportBuilder; + $this->transportBuilderByStore = $transportBuilderByStore ?: ObjectManager::getInstance()->get( + TransportBuilderByStore::class + ); } /** @@ -98,7 +110,7 @@ protected function configureEmailTemplate() $this->transportBuilder->setTemplateIdentifier($this->templateContainer->getTemplateId()); $this->transportBuilder->setTemplateOptions($this->templateContainer->getTemplateOptions()); $this->transportBuilder->setTemplateVars($this->templateContainer->getTemplateVars()); - $this->transportBuilder->setFromByStore( + $this->transportBuilderByStore->setFromByStore( $this->identityContainer->getEmailIdentity(), $this->identityContainer->getStore()->getId() ); diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Email/SenderBuilderTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Email/SenderBuilderTest.php index 00be3c10d6498..38209bb22aef4 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Order/Email/SenderBuilderTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Email/SenderBuilderTest.php @@ -6,6 +6,7 @@ namespace Magento\Sales\Test\Unit\Model\Order\Email; +use Magento\Framework\Mail\Template\TransportBuilderByStore; use Magento\Sales\Model\Order\Email\SenderBuilder; class SenderBuilderTest extends \PHPUnit\Framework\TestCase @@ -35,6 +36,11 @@ class SenderBuilderTest extends \PHPUnit\Framework\TestCase */ private $storeMock; + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $transportBuilderByStore; + protected function setUp() { $templateId = 'test_template_id'; @@ -76,10 +82,11 @@ protected function setUp() 'setTemplateIdentifier', 'setTemplateOptions', 'setTemplateVars', - 'setFromByStore', ] ); + $this->transportBuilderByStore = $this->createMock(TransportBuilderByStore::class); + $this->templateContainerMock->expects($this->once()) ->method('getTemplateId') ->will($this->returnValue($templateId)); @@ -102,7 +109,7 @@ protected function setUp() $this->identityContainerMock->expects($this->once()) ->method('getEmailIdentity') ->will($this->returnValue($emailIdentity)); - $this->transportBuilder->expects($this->once()) + $this->transportBuilderByStore->expects($this->once()) ->method('setFromByStore') ->with($this->equalTo($emailIdentity)); @@ -113,7 +120,8 @@ protected function setUp() $this->senderBuilder = new SenderBuilder( $this->templateContainerMock, $this->identityContainerMock, - $this->transportBuilder + $this->transportBuilder, + $this->transportBuilderByStore ); } diff --git a/lib/internal/Magento/Framework/Mail/Template/TransportBuilder.php b/lib/internal/Magento/Framework/Mail/Template/TransportBuilder.php index 8e474a58cdac8..18b241d77a426 100644 --- a/lib/internal/Magento/Framework/Mail/Template/TransportBuilder.php +++ b/lib/internal/Magento/Framework/Mail/Template/TransportBuilder.php @@ -171,20 +171,6 @@ public function setFrom($from) return $this; } - /** - * Set mail from address by store. - * - * @param string|array $from - * @param string|int $store - * @return $this - */ - public function setFromByStore($from, $store) - { - $result = $this->_senderResolver->resolve($from, $store); - $this->message->setFrom($result['email'], $result['name']); - return $this; - } - /** * Set template identifier * diff --git a/lib/internal/Magento/Framework/Mail/Template/TransportBuilderByStore.php b/lib/internal/Magento/Framework/Mail/Template/TransportBuilderByStore.php new file mode 100644 index 0000000000000..785c93824a57d --- /dev/null +++ b/lib/internal/Magento/Framework/Mail/Template/TransportBuilderByStore.php @@ -0,0 +1,54 @@ +message = $message; + $this->senderResolver = $senderResolver; + } + + /** + * Set mail from address by store. + * + * @param string|array $from + * @param string|int $store + * + * @return $this + */ + public function setFromByStore($from, $store) + { + $result = $this->senderResolver->resolve($from, $store); + $this->message->setFrom($result['email'], $result['name']); + + return $this; + } +} diff --git a/lib/internal/Magento/Framework/Mail/Test/Unit/Template/TransportBuilderByStoreTest.php b/lib/internal/Magento/Framework/Mail/Test/Unit/Template/TransportBuilderByStoreTest.php new file mode 100644 index 0000000000000..d49cbfb1e2044 --- /dev/null +++ b/lib/internal/Magento/Framework/Mail/Test/Unit/Template/TransportBuilderByStoreTest.php @@ -0,0 +1,64 @@ +messageMock = $this->createMock(\Magento\Framework\Mail\Message::class); + $this->senderResolverMock = $this->createMock(\Magento\Framework\Mail\Template\SenderResolverInterface::class); + + $this->model = $objectManagerHelper->getObject( + TransportBuilderByStore::class, + [ + 'message' => $this->messageMock, + 'senderResolver' => $this->senderResolverMock, + ] + ); + } + + /** + * @return void + */ + public function setFromByStore() + { + $sender = ['email' => 'from@example.com', 'name' => 'name']; + $store = 1; + $this->senderResolverMock->expects($this->once()) + ->method('resolve') + ->with($sender, $store) + ->willReturn($sender); + $this->messageMock->expects($this->once()) + ->method('setFrom') + ->with('from@example.com', 'name') + ->willReturnSelf(); + + $this->model->setFromByStore($sender, $store); + } +} diff --git a/lib/internal/Magento/Framework/Mail/Test/Unit/Template/TransportBuilderTest.php b/lib/internal/Magento/Framework/Mail/Test/Unit/Template/TransportBuilderTest.php index ab03be5ee844b..927e17c824e33 100644 --- a/lib/internal/Magento/Framework/Mail/Test/Unit/Template/TransportBuilderTest.php +++ b/lib/internal/Magento/Framework/Mail/Test/Unit/Template/TransportBuilderTest.php @@ -168,25 +168,6 @@ public function testSetFrom() $this->builder->setFrom($sender); } - /** - * @return void - */ - public function setFromByStore() - { - $sender = ['email' => 'from@example.com', 'name' => 'name']; - $store = 1; - $this->senderResolverMock->expects($this->once()) - ->method('resolve') - ->with($sender, $store) - ->willReturn($sender); - $this->messageMock->expects($this->once()) - ->method('setFrom') - ->with('from@example.com', 'name') - ->willReturnSelf(); - - $this->builder->setFromByStore($sender); - } - /** * @return void */ From b3227183b97f6ba993e2ee64b504f0ab98262e8b Mon Sep 17 00:00:00 2001 From: RomanKis Date: Mon, 13 Nov 2017 17:51:04 +0200 Subject: [PATCH 21/32] 11740: Sending emails from Admin in Multi-Store Environment defaults to Primary Store --- .../Mail/Test/Unit/Template/TransportBuilderByStoreTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/internal/Magento/Framework/Mail/Test/Unit/Template/TransportBuilderByStoreTest.php b/lib/internal/Magento/Framework/Mail/Test/Unit/Template/TransportBuilderByStoreTest.php index d49cbfb1e2044..80df2887a3a93 100644 --- a/lib/internal/Magento/Framework/Mail/Test/Unit/Template/TransportBuilderByStoreTest.php +++ b/lib/internal/Magento/Framework/Mail/Test/Unit/Template/TransportBuilderByStoreTest.php @@ -46,7 +46,7 @@ protected function setUp() /** * @return void */ - public function setFromByStore() + public function testSetFromByStore() { $sender = ['email' => 'from@example.com', 'name' => 'name']; $store = 1; From 1d341efa8875779b266c00bee84c9d88f2037c59 Mon Sep 17 00:00:00 2001 From: Anton Evers Date: Tue, 14 Nov 2017 09:22:10 +0100 Subject: [PATCH 22/32] use InvoiceInterface instead of Invoice model to check if an invoice is set on the credit memo --- app/code/Magento/Sales/Model/Order/Creditmemo.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo.php b/app/code/Magento/Sales/Model/Order/Creditmemo.php index 3cf4d01727338..64b903fe5b5c1 100644 --- a/app/code/Magento/Sales/Model/Order/Creditmemo.php +++ b/app/code/Magento/Sales/Model/Order/Creditmemo.php @@ -389,7 +389,7 @@ public function canRefund() */ public function getInvoice() { - if (!$this->getData('invoice') instanceof \Magento\Sales\Model\Order\Invoice && $this->getInvoiceId()) { + if (!$this->getData('invoice') instanceof \Magento\Sales\Api\Data\InvoiceInterface && $this->getInvoiceId()) { $this->setInvoice($this->invoiceFactory->create()->load($this->getInvoiceId())); } return $this->getData('invoice'); From ef165a2d3666d92a109252541c399e55695c830b Mon Sep 17 00:00:00 2001 From: RomanKis Date: Tue, 14 Nov 2017 14:42:29 +0200 Subject: [PATCH 23/32] 10128: New Orders not being saved to order grid --- .../Backend/Block/Dashboard/Orders/Grid.php | 2 +- .../Block/Dashboard/Orders/GridTest.php | 40 +++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 dev/tests/integration/testsuite/Magento/Backend/Block/Dashboard/Orders/GridTest.php diff --git a/app/code/Magento/Backend/Block/Dashboard/Orders/Grid.php b/app/code/Magento/Backend/Block/Dashboard/Orders/Grid.php index 9d9409fba093b..50279786c0a5b 100644 --- a/app/code/Magento/Backend/Block/Dashboard/Orders/Grid.php +++ b/app/code/Magento/Backend/Block/Dashboard/Orders/Grid.php @@ -92,7 +92,7 @@ protected function _prepareCollection() protected function _afterLoadCollection() { foreach ($this->getCollection() as $item) { - $item->getCustomer() ?: $item->setCustomer('Guest'); + $item->getCustomer() ?: $item->setCustomer($item->getBillingAddress()->getName()); } return $this; } diff --git a/dev/tests/integration/testsuite/Magento/Backend/Block/Dashboard/Orders/GridTest.php b/dev/tests/integration/testsuite/Magento/Backend/Block/Dashboard/Orders/GridTest.php new file mode 100644 index 0000000000000..859837d4af130 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Backend/Block/Dashboard/Orders/GridTest.php @@ -0,0 +1,40 @@ +createMock(\Magento\Backend\Block\Dashboard\Orders\Grid::class); + $layout = $this->createMock(\Magento\Framework\View\LayoutInterface::class); + $layout->expects($this->atLeastOnce())->method('getChildName')->willReturn('test'); + $layout->expects($this->atLeastOnce())->method('getBlock')->willReturn($block); + $context = $objectManager->create(Context::class, ['layout' => $layout]); + + $this->block = $objectManager->create(Grid::class, ['context' => $context]); + } + + /** + * @magentoDataFixture Magento/Sales/_files/order.php + */ + public function testGetPreparedCollection() + { + $collection = $this->block->getPreparedCollection(); + $this->assertEquals('firstname lastname', $collection->getItems()[1]->getCustomer()); + } +} From 1ebcd7add6e6bcb2f8deb62ba5754e3110b59f12 Mon Sep 17 00:00:00 2001 From: RomanKis Date: Tue, 14 Nov 2017 15:19:44 +0200 Subject: [PATCH 24/32] 10128: New Orders not being saved to order grid --- .../Magento/Backend/Block/Dashboard/Orders/GridTest.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dev/tests/integration/testsuite/Magento/Backend/Block/Dashboard/Orders/GridTest.php b/dev/tests/integration/testsuite/Magento/Backend/Block/Dashboard/Orders/GridTest.php index 859837d4af130..9572bf10618fc 100644 --- a/dev/tests/integration/testsuite/Magento/Backend/Block/Dashboard/Orders/GridTest.php +++ b/dev/tests/integration/testsuite/Magento/Backend/Block/Dashboard/Orders/GridTest.php @@ -8,6 +8,10 @@ use Magento\Backend\Block\Template\Context; +/** + * @magentoAppIsolation enabled + * @magentoDbIsolation enabled + */ class GridTest extends \PHPUnit\Framework\TestCase { /** From a933cf745b4e6cc82d07cefb00cd4af9874e034f Mon Sep 17 00:00:00 2001 From: RomanKis Date: Tue, 14 Nov 2017 15:46:34 +0200 Subject: [PATCH 25/32] 10128: New Orders not being saved to order grid --- .../Backend/Block/Dashboard/Orders/GridTest.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Backend/Block/Dashboard/Orders/GridTest.php b/dev/tests/integration/testsuite/Magento/Backend/Block/Dashboard/Orders/GridTest.php index 9572bf10618fc..6c91afb80fd4a 100644 --- a/dev/tests/integration/testsuite/Magento/Backend/Block/Dashboard/Orders/GridTest.php +++ b/dev/tests/integration/testsuite/Magento/Backend/Block/Dashboard/Orders/GridTest.php @@ -8,10 +8,6 @@ use Magento\Backend\Block\Template\Context; -/** - * @magentoAppIsolation enabled - * @magentoDbIsolation enabled - */ class GridTest extends \PHPUnit\Framework\TestCase { /** @@ -39,6 +35,10 @@ protected function setUp() public function testGetPreparedCollection() { $collection = $this->block->getPreparedCollection(); - $this->assertEquals('firstname lastname', $collection->getItems()[1]->getCustomer()); + foreach ($collection->getItems() as $item) { + if ($item->getIncrementId() == '100000001') { + $this->assertEquals('firstname lastname', $item->getCustomer()); + } + } } } From 992b3a10abfa7ad39a4f263f61d1b47f36113ae0 Mon Sep 17 00:00:00 2001 From: Marius Grad Date: Tue, 21 Nov 2017 09:25:43 +0200 Subject: [PATCH 26/32] use FQCN throughout the class --- .../Catalog/Block/Product/ListProduct.php | 45 ++++++++++--------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/app/code/Magento/Catalog/Block/Product/ListProduct.php b/app/code/Magento/Catalog/Block/Product/ListProduct.php index 5bb0b772f90de..df91488cf5f61 100644 --- a/app/code/Magento/Catalog/Block/Product/ListProduct.php +++ b/app/code/Magento/Catalog/Block/Product/ListProduct.php @@ -7,16 +7,19 @@ namespace Magento\Catalog\Block\Product; use Magento\Catalog\Api\CategoryRepositoryInterface; -use Magento\Catalog\Block\Product\Context; use Magento\Catalog\Block\Product\ProductList\Toolbar; use Magento\Catalog\Model\Category; +use Magento\Catalog\Model\Layer; use Magento\Catalog\Model\Layer\Resolver; use Magento\Catalog\Model\Product; use Magento\Catalog\Model\ResourceModel\Product\Collection; +use Magento\Catalog\Pricing\Price\FinalPrice; use Magento\Eav\Model\Entity\Collection\AbstractCollection; +use Magento\Framework\App\ActionInterface; use Magento\Framework\Data\Helper\PostHelper; use Magento\Framework\DataObject\IdentityInterface; use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Framework\Pricing\Render; use Magento\Framework\Url\Helper\Data; /** @@ -64,11 +67,11 @@ class ListProduct extends AbstractProduct implements IdentityInterface protected $categoryRepository; /** - * @param \Magento\Catalog\Block\Product\Context $context - * @param \Magento\Framework\Data\Helper\PostHelper $postDataHelper - * @param \Magento\Catalog\Model\Layer\Resolver $layerResolver - * @param \Magento\Catalog\Api\CategoryRepositoryInterface $categoryRepository - * @param \Magento\Framework\Url\Helper\Data $urlHelper + * @param Context $context + * @param PostHelper $postDataHelper + * @param Resolver $layerResolver + * @param CategoryRepositoryInterface $categoryRepository + * @param Data $urlHelper * @param array $data */ public function __construct( @@ -117,7 +120,7 @@ protected function _getProductCollection() /** * Get catalog layer model * - * @return \Magento\Catalog\Model\Layer + * @return Layer */ public function getLayer() { @@ -191,7 +194,7 @@ protected function _beforeToHtml() /** * Add toolbar block from product listing layout * - * @param \Magento\Catalog\Model\ResourceModel\Product\Collection $collection + * @param Collection $collection */ private function addToolbarBlock(Collection $collection) { @@ -267,7 +270,7 @@ public function setCollection($collection) } /** - * @param array|string|integer|\Magento\Framework\App\Config\Element $code + * @param array|string|integer|Element $code * @return $this */ public function addAttribute($code) @@ -287,7 +290,7 @@ public function getPriceBlockTemplate() /** * Retrieve Catalog Config object * - * @return \Magento\Catalog\Model\Config + * @return Config */ protected function _getConfig() { @@ -297,10 +300,10 @@ protected function _getConfig() /** * Prepare Sort By fields from Category Data * - * @param \Magento\Catalog\Model\Category $category - * @return \Magento\Catalog\Block\Product\ListProduct + * @param Category $category + * @return $this */ - public function prepareSortableFieldsByCategory($category) + public function prepareSortableFieldsByCategory(Category $category) { if (!$this->getAvailableOrders()) { $this->setAvailableOrders($category->getAvailableSortByOptions()); @@ -342,38 +345,38 @@ public function getIdentities() /** * Get post parameters * - * @param \Magento\Catalog\Model\Product $product + * @param Product $product * @return string */ - public function getAddToCartPostParams(\Magento\Catalog\Model\Product $product) + public function getAddToCartPostParams(Product $product) { $url = $this->getAddToCartUrl($product); return [ 'action' => $url, 'data' => [ 'product' => $product->getEntityId(), - \Magento\Framework\App\ActionInterface::PARAM_NAME_URL_ENCODED => $this->urlHelper->getEncodedUrl($url), + ActionInterface::PARAM_NAME_URL_ENCODED => $this->urlHelper->getEncodedUrl($url), ] ]; } /** - * @param \Magento\Catalog\Model\Product $product + * @param Product $product * @return string */ - public function getProductPrice(\Magento\Catalog\Model\Product $product) + public function getProductPrice(Product $product) { $priceRender = $this->getPriceRender(); $price = ''; if ($priceRender) { $price = $priceRender->render( - \Magento\Catalog\Pricing\Price\FinalPrice::PRICE_CODE, + FinalPrice::PRICE_CODE, $product, [ 'include_container' => true, 'display_minimal_price' => true, - 'zone' => \Magento\Framework\Pricing\Render::ZONE_ITEM_LIST, + 'zone' => Render::ZONE_ITEM_LIST, 'list_category_page' => true ] ); @@ -386,7 +389,7 @@ public function getProductPrice(\Magento\Catalog\Model\Product $product) * Specifies that price rendering should be done for the list of products * i.e. rendering happens in the scope of product list, but not single product * - * @return \Magento\Framework\Pricing\Render + * @return Render */ protected function getPriceRender() { From 4e937a39fa59a7cc0cefcd19691bc095accc1c9e Mon Sep 17 00:00:00 2001 From: Marius Grad Date: Tue, 21 Nov 2017 09:57:30 +0200 Subject: [PATCH 27/32] use FQCN, revert doc parameter namespace --- app/code/Magento/Catalog/Block/Product/ListProduct.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Catalog/Block/Product/ListProduct.php b/app/code/Magento/Catalog/Block/Product/ListProduct.php index df91488cf5f61..5c51429ce83d4 100644 --- a/app/code/Magento/Catalog/Block/Product/ListProduct.php +++ b/app/code/Magento/Catalog/Block/Product/ListProduct.php @@ -270,7 +270,7 @@ public function setCollection($collection) } /** - * @param array|string|integer|Element $code + * @param array|string|integer|\Magento\Framework\App\Config\Element $code * @return $this */ public function addAttribute($code) @@ -415,7 +415,7 @@ protected function getPriceRender() private function initializeProductCollection() { $layer = $this->getLayer(); - /* @var $layer \Magento\Catalog\Model\Layer */ + /* @var $layer Layer */ if ($this->getShowRootCategory()) { $this->setCategoryId($this->_storeManager->getStore()->getRootCategoryId()); } From c303e4dcbc0501a125e844d521d5fc57624b6b8b Mon Sep 17 00:00:00 2001 From: Marius Grad Date: Tue, 21 Nov 2017 10:43:01 +0200 Subject: [PATCH 28/32] import Config class --- app/code/Magento/Catalog/Block/Product/ListProduct.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Block/Product/ListProduct.php b/app/code/Magento/Catalog/Block/Product/ListProduct.php index 5c51429ce83d4..0d9a19ce6ae80 100644 --- a/app/code/Magento/Catalog/Block/Product/ListProduct.php +++ b/app/code/Magento/Catalog/Block/Product/ListProduct.php @@ -9,6 +9,7 @@ use Magento\Catalog\Api\CategoryRepositoryInterface; use Magento\Catalog\Block\Product\ProductList\Toolbar; use Magento\Catalog\Model\Category; +use Magento\Catalog\Model\Config; use Magento\Catalog\Model\Layer; use Magento\Catalog\Model\Layer\Resolver; use Magento\Catalog\Model\Product; @@ -16,6 +17,7 @@ use Magento\Catalog\Pricing\Price\FinalPrice; use Magento\Eav\Model\Entity\Collection\AbstractCollection; use Magento\Framework\App\ActionInterface; +use Magento\Framework\App\Config\Element; use Magento\Framework\Data\Helper\PostHelper; use Magento\Framework\DataObject\IdentityInterface; use Magento\Framework\Exception\NoSuchEntityException; @@ -270,7 +272,7 @@ public function setCollection($collection) } /** - * @param array|string|integer|\Magento\Framework\App\Config\Element $code + * @param array|string|integer| Element $code * @return $this */ public function addAttribute($code) From 1053d6c0b43ae8453b14ad678de19d8f02e9b76d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20M=C3=A9ndez=20Calzada?= Date: Tue, 21 Nov 2017 11:54:35 +0100 Subject: [PATCH 29/32] add static and api-funcional tests for swatches --- ...AttributeOptionManagementInterfaceTest.php | 85 +++++++++++++++++++ .../Attribute/_files/swatch_attribute.php | 48 +++++++++++ .../Model/SwatchAttributeOptionAddTest.php | 72 ++++++++++++++++ 3 files changed, 205 insertions(+) create mode 100644 dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductSwatchAttributeOptionManagementInterfaceTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/_files/swatch_attribute.php create mode 100644 dev/tests/integration/testsuite/Magento/Swatches/Model/SwatchAttributeOptionAddTest.php diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductSwatchAttributeOptionManagementInterfaceTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductSwatchAttributeOptionManagementInterfaceTest.php new file mode 100644 index 0000000000000..11dc3c9484a61 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductSwatchAttributeOptionManagementInterfaceTest.php @@ -0,0 +1,85 @@ + [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $testAttributeCode . '/options', + 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'add', + ], + ]; + + $response = $this->_webApiCall( + $serviceInfo, + [ + 'attributeCode' => $testAttributeCode, + 'option' => $optionData, + ] + ); + + $this->assertTrue($response); + $updatedData = $this->getAttributeOptions($testAttributeCode); + $lastOption = array_pop($updatedData); + $this->assertEquals( + $optionData[AttributeOptionInterface::STORE_LABELS][0][AttributeOptionLabelInterface::LABEL], + $lastOption['label'] + ); + } + + /** + * @return array + */ + public function addDataProvider() + { + $optionPayload = [ + AttributeOptionInterface::LABEL => 'new color', + AttributeOptionInterface::SORT_ORDER => 100, + AttributeOptionInterface::IS_DEFAULT => true, + AttributeOptionInterface::STORE_LABELS => [ + [ + AttributeOptionLabelInterface::LABEL => 'DE label', + AttributeOptionLabelInterface::STORE_ID => 1, + ], + ], + AttributeOptionInterface::VALUE => '' + ]; + + return [ + 'option_without_value_node' => [ + $optionPayload + ], + 'option_with_value_node_that_starts_with_text' => [ + array_merge($optionPayload, [AttributeOptionInterface::VALUE => 'some_text']) + ], + 'option_with_value_node_that_starts_with_a_number' => [ + array_merge($optionPayload, [AttributeOptionInterface::VALUE => '123_some_text']) + ], + + ]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/_files/swatch_attribute.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/_files/swatch_attribute.php new file mode 100644 index 0000000000000..4e51d4e16ee50 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/_files/swatch_attribute.php @@ -0,0 +1,48 @@ +create( + \Magento\Eav\Model\Entity\Type::class +); +$entityType->loadByCode('catalog_product'); +$defaultSetId = $entityType->getDefaultAttributeSetId(); +/** @var \Magento\Eav\Model\Entity\Attribute\Set $defaultSet */ +$defaultSet = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + \Magento\Eav\Model\Entity\Attribute\Set::class +); +$defaultSet->load($defaultSetId); +$defaultGroupId = $defaultSet->getDefaultGroupId(); +$optionData = ['value' => ['option_1' => [0 => 'Fixture Option']], 'order' => ['option_1' => 1]]; + +/** @var $attribute \Magento\Catalog\Model\ResourceModel\Eav\Attribute */ +$attribute = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + \Magento\Catalog\Model\ResourceModel\Eav\Attribute::class +); + +$attribute->setAttributeCode( + 'swatch_attribute' +)->setEntityTypeId( + $entityType->getEntityTypeId() +)->setAttributeGroupId( + $defaultGroupId +)->setAttributeSetId( + $defaultSetId +)->setFrontendInput( + 'media_image' +)->setFrontendLabel( + 'Swatch Attribute' +)->setBackendType( + 'varchar' +)->setFrontendModel( + \Magento\Catalog\Model\Product\Attribute\Frontend\Image::class +)->setIsUserDefined( + 1 +)->setOption( + $optionData +)->save(); diff --git a/dev/tests/integration/testsuite/Magento/Swatches/Model/SwatchAttributeOptionAddTest.php b/dev/tests/integration/testsuite/Magento/Swatches/Model/SwatchAttributeOptionAddTest.php new file mode 100644 index 0000000000000..4505cbd64c27b --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Swatches/Model/SwatchAttributeOptionAddTest.php @@ -0,0 +1,72 @@ +create(\Magento\Catalog\Model\ResourceModel\Eav\Attribute::class) + ->load('color_swatch', 'attribute_code'); + $optionsPerAttribute = 3; + + $data['options']['option'] = array_reduce( + range(10, $optionsPerAttribute), + function ($values, $index) use ($optionsPerAttribute) { + $values[] = [ + 'label' => 'option ' . $index, + 'value' => 'option_' . $index + ]; + return $values; + }, + [] + ); + + /** @var AttributeOptionInterface[] $options */ + $options = []; + foreach ($data['options']['option'] as $optionData) { + $options[] = $om->get(AttributeOptionInterfaceFactory::class)->create(['data' => $optionData]); + } + + /** @var ProductAttributeOptionManagementInterface $optionManagement */ + $optionManagement = $om->get(ProductAttributeOptionManagementInterface::class); + foreach ($options as $option) { + $optionManagement->add( + $attribute->getAttributeCode(), + $option + ); + } + + $items = $optionManagement->getItems($attribute->getAttributeCode()); + array_walk( + $items, + function (&$item) { + /** @var AttributeOptionInterface $item */ + $item = $item->getLabel(); + } + ); + foreach ($options as $option) { + $this->assertTrue(in_array($option->getLabel(), $items)); + } + } +} From cd7dc5652b56b62713808233b0220cc7c8741078 Mon Sep 17 00:00:00 2001 From: Marius Grad Date: Tue, 21 Nov 2017 13:33:44 +0200 Subject: [PATCH 30/32] revert type parameter on method prepareSortableFieldsByCategory --- app/code/Magento/Catalog/Block/Product/ListProduct.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Block/Product/ListProduct.php b/app/code/Magento/Catalog/Block/Product/ListProduct.php index 0d9a19ce6ae80..db592353da44a 100644 --- a/app/code/Magento/Catalog/Block/Product/ListProduct.php +++ b/app/code/Magento/Catalog/Block/Product/ListProduct.php @@ -305,7 +305,7 @@ protected function _getConfig() * @param Category $category * @return $this */ - public function prepareSortableFieldsByCategory(Category $category) + public function prepareSortableFieldsByCategory($category) { if (!$this->getAvailableOrders()) { $this->setAvailableOrders($category->getAvailableSortByOptions()); From 0599c8eb227536517ca3acbb4349695cb4f023b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20M=C3=A9ndez=20Calzada?= Date: Thu, 23 Nov 2017 20:21:15 +0100 Subject: [PATCH 31/32] drop useless fixture, fix tests --- ...AttributeOptionManagementInterfaceTest.php | 24 +++++++++- .../Attribute/_files/swatch_attribute.php | 48 ------------------- .../Model/SwatchAttributeOptionAddTest.php | 18 +++++-- 3 files changed, 35 insertions(+), 55 deletions(-) delete mode 100644 dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/_files/swatch_attribute.php diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductSwatchAttributeOptionManagementInterfaceTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductSwatchAttributeOptionManagementInterfaceTest.php index 11dc3c9484a61..63e5282c22104 100644 --- a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductSwatchAttributeOptionManagementInterfaceTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductSwatchAttributeOptionManagementInterfaceTest.php @@ -16,12 +16,12 @@ class ProductSwatchAttributeOptionManagementInterfaceTest extends WebapiAbstract const RESOURCE_PATH = '/V1/products/attributes'; /** - * @magentoApiDataFixture Magento/Catalog/Model/Product/Attribute/_files/swatch_attribute.php + * @magentoApiDataFixture Magento/Swatches/_files/swatch_attribute.php * @dataProvider addDataProvider */ public function testAdd($optionData) { - $testAttributeCode = 'swatch_attribute'; + $testAttributeCode = 'color_swatch'; $serviceInfo = [ 'rest' => [ 'resourcePath' => self::RESOURCE_PATH . '/' . $testAttributeCode . '/options', @@ -82,4 +82,24 @@ public function addDataProvider() ]; } + + /** + * @param $testAttributeCode + * @return array|bool|float|int|string + */ + private function getAttributeOptions($testAttributeCode) + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $testAttributeCode . '/options', + 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'getItems', + ], + ]; + return $this->_webApiCall($serviceInfo, ['attributeCode' => $testAttributeCode]); + } } diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/_files/swatch_attribute.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/_files/swatch_attribute.php deleted file mode 100644 index 4e51d4e16ee50..0000000000000 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/_files/swatch_attribute.php +++ /dev/null @@ -1,48 +0,0 @@ -create( - \Magento\Eav\Model\Entity\Type::class -); -$entityType->loadByCode('catalog_product'); -$defaultSetId = $entityType->getDefaultAttributeSetId(); -/** @var \Magento\Eav\Model\Entity\Attribute\Set $defaultSet */ -$defaultSet = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( - \Magento\Eav\Model\Entity\Attribute\Set::class -); -$defaultSet->load($defaultSetId); -$defaultGroupId = $defaultSet->getDefaultGroupId(); -$optionData = ['value' => ['option_1' => [0 => 'Fixture Option']], 'order' => ['option_1' => 1]]; - -/** @var $attribute \Magento\Catalog\Model\ResourceModel\Eav\Attribute */ -$attribute = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( - \Magento\Catalog\Model\ResourceModel\Eav\Attribute::class -); - -$attribute->setAttributeCode( - 'swatch_attribute' -)->setEntityTypeId( - $entityType->getEntityTypeId() -)->setAttributeGroupId( - $defaultGroupId -)->setAttributeSetId( - $defaultSetId -)->setFrontendInput( - 'media_image' -)->setFrontendLabel( - 'Swatch Attribute' -)->setBackendType( - 'varchar' -)->setFrontendModel( - \Magento\Catalog\Model\Product\Attribute\Frontend\Image::class -)->setIsUserDefined( - 1 -)->setOption( - $optionData -)->save(); diff --git a/dev/tests/integration/testsuite/Magento/Swatches/Model/SwatchAttributeOptionAddTest.php b/dev/tests/integration/testsuite/Magento/Swatches/Model/SwatchAttributeOptionAddTest.php index 4505cbd64c27b..5cfbc8e580e95 100644 --- a/dev/tests/integration/testsuite/Magento/Swatches/Model/SwatchAttributeOptionAddTest.php +++ b/dev/tests/integration/testsuite/Magento/Swatches/Model/SwatchAttributeOptionAddTest.php @@ -15,6 +15,16 @@ */ class SwatchAttributeOptionAddTest extends \PHPUnit\Framework\TestCase { + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + private $objectManager; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + /** * @magentoAppArea adminhtml * @magentoDbIsolation enabled @@ -22,10 +32,8 @@ class SwatchAttributeOptionAddTest extends \PHPUnit\Framework\TestCase */ public function testSwatchOptionAdd() { - $om = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); - /** @var \Magento\Catalog\Api\Data\ProductAttributeInterface $attribute */ - $attribute = $om + $attribute = $this->objectManager ->create(\Magento\Catalog\Model\ResourceModel\Eav\Attribute::class) ->load('color_swatch', 'attribute_code'); $optionsPerAttribute = 3; @@ -45,11 +53,11 @@ function ($values, $index) use ($optionsPerAttribute) { /** @var AttributeOptionInterface[] $options */ $options = []; foreach ($data['options']['option'] as $optionData) { - $options[] = $om->get(AttributeOptionInterfaceFactory::class)->create(['data' => $optionData]); + $options[] = $this->objectManager->get(AttributeOptionInterfaceFactory::class)->create(['data' => $optionData]); } /** @var ProductAttributeOptionManagementInterface $optionManagement */ - $optionManagement = $om->get(ProductAttributeOptionManagementInterface::class); + $optionManagement = $this->objectManager->get(ProductAttributeOptionManagementInterface::class); foreach ($options as $option) { $optionManagement->add( $attribute->getAttributeCode(), From 243dccba6ecde194f56c052ff91f2bdd641def09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20M=C3=A9ndez=20Calzada?= Date: Fri, 24 Nov 2017 09:24:20 +0100 Subject: [PATCH 32/32] codestyle fix --- .../Magento/Swatches/Model/SwatchAttributeOptionAddTest.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dev/tests/integration/testsuite/Magento/Swatches/Model/SwatchAttributeOptionAddTest.php b/dev/tests/integration/testsuite/Magento/Swatches/Model/SwatchAttributeOptionAddTest.php index 5cfbc8e580e95..84ba587f5e784 100644 --- a/dev/tests/integration/testsuite/Magento/Swatches/Model/SwatchAttributeOptionAddTest.php +++ b/dev/tests/integration/testsuite/Magento/Swatches/Model/SwatchAttributeOptionAddTest.php @@ -53,7 +53,9 @@ function ($values, $index) use ($optionsPerAttribute) { /** @var AttributeOptionInterface[] $options */ $options = []; foreach ($data['options']['option'] as $optionData) { - $options[] = $this->objectManager->get(AttributeOptionInterfaceFactory::class)->create(['data' => $optionData]); + $options[] = $this->objectManager + ->get(AttributeOptionInterfaceFactory::class) + ->create(['data' => $optionData]); } /** @var ProductAttributeOptionManagementInterface $optionManagement */