From 80a987a942ee40213d42ebe7159fa4fa6380ca67 Mon Sep 17 00:00:00 2001 From: Viktor Tymchynskyi Date: Mon, 25 Apr 2016 18:55:35 +0300 Subject: [PATCH 1/8] MAGETWO-48048: Bundle product price on category view isn't included custom option price - Add loading product custom options if not loaded --- .../Bundle/Pricing/Price/FinalPrice.php | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/app/code/Magento/Bundle/Pricing/Price/FinalPrice.php b/app/code/Magento/Bundle/Pricing/Price/FinalPrice.php index 5be2c55d04b2a..3ba37ba7718d2 100644 --- a/app/code/Magento/Bundle/Pricing/Price/FinalPrice.php +++ b/app/code/Magento/Bundle/Pricing/Price/FinalPrice.php @@ -10,6 +10,8 @@ use Magento\Framework\Pricing\Adjustment\CalculatorInterface; use Magento\Catalog\Pricing\Price\CustomOptionPrice; use Magento\Bundle\Model\Product\Price; +use Magento\Framework\App\ObjectManager; +use Magento\Catalog\Api\ProductCustomOptionRepositoryInterface; /** * Final price model @@ -36,6 +38,11 @@ class FinalPrice extends \Magento\Catalog\Pricing\Price\FinalPrice implements Fi */ protected $bundleOptionPrice; + /** + * @var \Magento\Catalog\Api\ProductCustomOptionRepositoryInterface + */ + private $productOptionRepository; + /** * @param Product $saleableItem * @param float $quantity @@ -81,6 +88,16 @@ public function getMaximalPrice() return $this->maximalPrice; } + private function getProductOptionRepository() + { + if (!$this->productOptionRepository) { + $this->productOptionRepository = ObjectManager::getInstance()->get( + ProductCustomOptionRepositoryInterface::class + ); + } + return $this->productOptionRepository; + } + /** * Returns min price * @@ -101,6 +118,7 @@ public function getAmount() if (!$this->minimalPrice) { $price = parent::getValue(); if ($this->product->getPriceType() == Price::PRICE_TYPE_FIXED) { + $this->loadProductCustomOptions(); /** @var \Magento\Catalog\Pricing\Price\CustomOptionPrice $customOptionPrice */ $customOptionPrice = $this->priceInfo->getPrice(CustomOptionPrice::PRICE_CODE); $price += $customOptionPrice->getCustomOptionRange(true); @@ -110,6 +128,23 @@ public function getAmount() return $this->minimalPrice; } + /** + * Load product custom options + * + * return @void + */ + private function loadProductCustomOptions() + { + if (!$this->product->getOptions()) { + $options = []; + foreach ($this->getProductOptionRepository()->getProductOptions($this->product) as $option) { + $option->setProduct($this->product); + $options[] = $option; + } + $this->product->setOptions($options); + } + } + /** * get bundle product price without any option * From f68f31102b2ec3a0f916a0ee63ae4921b984f6cc Mon Sep 17 00:00:00 2001 From: Viktor Tymchynskyi Date: Tue, 26 Apr 2016 12:25:39 +0300 Subject: [PATCH 2/8] MAGETWO-48048: Bundle product price on category view isn't included custom option price - Fix static tests --- .../Bundle/Pricing/Price/FinalPrice.php | 7 ++++- .../Unit/Pricing/Price/FinalPriceTest.php | 29 +++++++++++++++++-- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Bundle/Pricing/Price/FinalPrice.php b/app/code/Magento/Bundle/Pricing/Price/FinalPrice.php index 3ba37ba7718d2..d9821064c236d 100644 --- a/app/code/Magento/Bundle/Pricing/Price/FinalPrice.php +++ b/app/code/Magento/Bundle/Pricing/Price/FinalPrice.php @@ -88,6 +88,11 @@ public function getMaximalPrice() return $this->maximalPrice; } + /** + * Return ProductCustomOptionRepository + * + * @return ProductCustomOptionRepositoryInterface + */ private function getProductOptionRepository() { if (!$this->productOptionRepository) { @@ -131,7 +136,7 @@ public function getAmount() /** * Load product custom options * - * return @void + * @return void */ private function loadProductCustomOptions() { diff --git a/app/code/Magento/Bundle/Test/Unit/Pricing/Price/FinalPriceTest.php b/app/code/Magento/Bundle/Test/Unit/Pricing/Price/FinalPriceTest.php index 7c27e48366315..8ba428476a02c 100644 --- a/app/code/Magento/Bundle/Test/Unit/Pricing/Price/FinalPriceTest.php +++ b/app/code/Magento/Bundle/Test/Unit/Pricing/Price/FinalPriceTest.php @@ -9,7 +9,7 @@ use Magento\Bundle\Pricing\Price\BundleOptionPrice; use Magento\Catalog\Pricing\Price\CustomOptionPrice; use Magento\Bundle\Model\Product\Price; - +use Magento\Catalog\Api\ProductCustomOptionRepositoryInterface; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; class FinalPriceTest extends \PHPUnit_Framework_TestCase @@ -45,10 +45,15 @@ class FinalPriceTest extends \PHPUnit_Framework_TestCase protected $customOptionPriceMock; /** - * @var \Magento\Framework\Pricing\PriceCurrencyInterface|\PHPUnit_Framework_MockObject_MockObject - */ + * @var \Magento\Framework\Pricing\PriceCurrencyInterface|\PHPUnit_Framework_MockObject_MockObject + */ protected $priceCurrencyMock; + /** + * @var ProductCustomOptionRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $productOptionRepositoryMock; + /** * @return void */ @@ -96,6 +101,14 @@ protected function prepareMock() $this->bundleCalculatorMock, $this->priceCurrencyMock ); + + $this->productOptionRepositoryMock = $this->getMockForAbstractClass( + ProductCustomOptionRepositoryInterface::class + ); + $reflection = new \ReflectionClass(get_class($this->finalPrice)); + $reflectionProperty = $reflection->getProperty('productOptionRepository'); + $reflectionProperty->setAccessible(true); + $reflectionProperty->setValue($this->finalPrice, $this->productOptionRepositoryMock); } /** @@ -172,6 +185,16 @@ public function testGetMinimalPriceFixedBundleWithOption() $this->baseAmount = 5; $result = 7; $this->prepareMock(); + $customOptions = [ + $this->getMockBuilder(\Magento\Catalog\Api\Data\ProductCustomOptionInterface::class) + ->setMethods(['setProduct']) + ->getMockForAbstractClass() + ]; + + $this->productOptionRepositoryMock->expects(static::once()) + ->method('getProductOptions') + ->with($this->saleableInterfaceMock) + ->willReturn($customOptions); $this->saleableInterfaceMock->expects($this->once()) ->method('getPriceType') From 6bb084067f07952bf4dab35317f184d15f8444e7 Mon Sep 17 00:00:00 2001 From: Viktor Tymchynskyi Date: Tue, 26 Apr 2016 13:10:22 +0300 Subject: [PATCH 3/8] MAGETWO-48048: Bundle product price on category view isn't included custom option price - Fix static tests --- .../Bundle/Test/Unit/Pricing/Price/FinalPriceTest.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Bundle/Test/Unit/Pricing/Price/FinalPriceTest.php b/app/code/Magento/Bundle/Test/Unit/Pricing/Price/FinalPriceTest.php index 8ba428476a02c..9498a501e22bb 100644 --- a/app/code/Magento/Bundle/Test/Unit/Pricing/Price/FinalPriceTest.php +++ b/app/code/Magento/Bundle/Test/Unit/Pricing/Price/FinalPriceTest.php @@ -10,8 +10,12 @@ use Magento\Catalog\Pricing\Price\CustomOptionPrice; use Magento\Bundle\Model\Product\Price; use Magento\Catalog\Api\ProductCustomOptionRepositoryInterface; +use Magento\Framework\Pricing\PriceCurrencyInterface; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; +/** + * @SuppressWarnings(PHPMD) + */ class FinalPriceTest extends \PHPUnit_Framework_TestCase { /** @var \Magento\Bundle\Pricing\Price\FinalPrice */ @@ -45,8 +49,8 @@ class FinalPriceTest extends \PHPUnit_Framework_TestCase protected $customOptionPriceMock; /** - * @var \Magento\Framework\Pricing\PriceCurrencyInterface|\PHPUnit_Framework_MockObject_MockObject - */ + * @var PriceCurrencyInterface|\PHPUnit_Framework_MockObject_MockObject + */ protected $priceCurrencyMock; /** From 52a7a6f6a2ed9a745f97c7cd5d8aff3c78884adf Mon Sep 17 00:00:00 2001 From: Roman Liukshyn Date: Tue, 26 Apr 2016 17:06:52 +0000 Subject: [PATCH 4/8] MAGETWO-52337: Layout is broken after searching related orders for billing agreement in Admin --- .../Adminhtml/Billing/Agreement/View/Tab/Orders.php | 10 ++++++++++ .../layout/paypal_billing_agreement_ordersgrid.xml | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Paypal/Block/Adminhtml/Billing/Agreement/View/Tab/Orders.php b/app/code/Magento/Paypal/Block/Adminhtml/Billing/Agreement/View/Tab/Orders.php index 465c6c5593642..0d59e9890db2c 100644 --- a/app/code/Magento/Paypal/Block/Adminhtml/Billing/Agreement/View/Tab/Orders.php +++ b/app/code/Magento/Paypal/Block/Adminhtml/Billing/Agreement/View/Tab/Orders.php @@ -100,6 +100,16 @@ protected function _construct() $this->setUseAjax(true); } + /** + * Get grid url + * + * @return string + */ + public function getGridUrl() + { + return $this->getUrl('paypal/billing_agreement/ordersGrid', ['_current' => true]); + } + /** * Apply various selection filters to prepare the sales order grid collection. * diff --git a/app/code/Magento/Paypal/view/adminhtml/layout/paypal_billing_agreement_ordersgrid.xml b/app/code/Magento/Paypal/view/adminhtml/layout/paypal_billing_agreement_ordersgrid.xml index f892e023996d3..e32876475f824 100644 --- a/app/code/Magento/Paypal/view/adminhtml/layout/paypal_billing_agreement_ordersgrid.xml +++ b/app/code/Magento/Paypal/view/adminhtml/layout/paypal_billing_agreement_ordersgrid.xml @@ -18,6 +18,6 @@ - + From 412c11bf68e44e5d16e0ce692d28aadea6aaeb8c Mon Sep 17 00:00:00 2001 From: Dmytro Kvashnin Date: Wed, 4 May 2016 17:20:16 +0300 Subject: [PATCH 5/8] MAGETWO-52359: Order cannot be placed via online payments in Admin --- .../Magento/Quote/Model/Quote/Payment.php | 34 +++- .../Test/Unit/Model/Quote/PaymentTest.php | 168 +++++++++++++++++- 2 files changed, 199 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Quote/Model/Quote/Payment.php b/app/code/Magento/Quote/Model/Quote/Payment.php index cdd295114c3d5..3ef26146e6ff0 100644 --- a/app/code/Magento/Quote/Model/Quote/Payment.php +++ b/app/code/Magento/Quote/Model/Quote/Payment.php @@ -145,6 +145,7 @@ public function getQuote() */ public function importData(array $data) { + $data = $this->convertPaymentData($data); $data = new \Magento\Framework\DataObject($data); $this->_eventManager->dispatch( $this->_eventPrefix . '_import_data_before', @@ -177,6 +178,37 @@ public function importData(array $data) return $this; } + /** + * Converts request to payment data + * + * @param array $rawData + * @return array + */ + private function convertPaymentData(array $rawData) + { + $paymentData = [ + PaymentInterface::KEY_METHOD => null, + PaymentInterface::KEY_PO_NUMBER => null, + PaymentInterface::KEY_ADDITIONAL_DATA => [], + 'checks' => [] + ]; + + foreach (array_keys($rawData) as $requestKey) { + if (!array_key_exists($requestKey, $paymentData)) { + $paymentData[PaymentInterface::KEY_ADDITIONAL_DATA][$requestKey] = $rawData[$requestKey]; + } elseif ($requestKey === PaymentInterface::KEY_ADDITIONAL_DATA) { + $paymentData[PaymentInterface::KEY_ADDITIONAL_DATA] = array_merge( + $paymentData[PaymentInterface::KEY_ADDITIONAL_DATA], + (array) $rawData[$requestKey] + ); + } else { + $paymentData[$requestKey] = $rawData[$requestKey]; + } + } + + return $paymentData; + } + /** * Prepare object for save * @@ -226,7 +258,7 @@ public function getOrderPlaceRedirectUrl() public function getMethodInstance() { $method = parent::getMethodInstance(); - $method->setStore($this->getQuote()->getStore()->getStoreId()); + $method->setStore($this->getQuote()->getStoreId()); return $method; } diff --git a/app/code/Magento/Quote/Test/Unit/Model/Quote/PaymentTest.php b/app/code/Magento/Quote/Test/Unit/Model/Quote/PaymentTest.php index 53d95bda04ed3..849f45764abdc 100644 --- a/app/code/Magento/Quote/Test/Unit/Model/Quote/PaymentTest.php +++ b/app/code/Magento/Quote/Test/Unit/Model/Quote/PaymentTest.php @@ -5,6 +5,13 @@ */ namespace Magento\Quote\Test\Unit\Model\Quote; +use Magento\Framework\DataObject; +use Magento\Framework\Event\ManagerInterface; +use Magento\Payment\Model\Checks\Composite; +use Magento\Payment\Model\Checks\SpecificationFactory; +use Magento\Payment\Model\MethodInterface; +use Magento\Quote\Api\Data\PaymentInterface; +use Magento\Quote\Model\Quote; use \Magento\Quote\Model\Quote\Payment; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; @@ -16,11 +23,31 @@ class PaymentTest extends \PHPUnit_Framework_TestCase */ private $model; + /** + * @var \PHPUnit_Framework_MockObject_MockObject|SpecificationFactory + */ + private $specificationFactory; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject|ManagerInterface + */ + private $eventManager; + protected function setUp() { $objectManager = new ObjectManager($this); + $this->specificationFactory = $this->getMockBuilder( + SpecificationFactory::class + )->disableOriginalConstructor() + ->getMock(); + $this->eventManager = $this->getMock(ManagerInterface::class); + $this->model = $objectManager->getObject( - '\Magento\Quote\Model\Quote\Payment' + Payment::class, + [ + 'methodSpecificationFactory' => $this->specificationFactory, + 'eventDispatcher' => $this->eventManager + ] ); } @@ -32,7 +59,7 @@ protected function setUp() public function testGetCcExpYearReturnsValidValue($databaseValue, $expectedValue) { $this->model->setData('cc_exp_year', $databaseValue); - $this->assertEquals($expectedValue, $this->model->getCcExpYear()); + static::assertEquals($expectedValue, $this->model->getCcExpYear()); } /** @@ -47,4 +74,141 @@ public function yearValueDataProvider() [1939, 1939], ]; } + + /** + * @param array $data + * @param array $convertedData + * @param array $dataToAssign + * @param array $checks + * @dataProvider importDataPositiveCheckDataProvider + */ + public function testImportDataPositiveCheck( + array $data, + array $convertedData, + array $dataToAssign, + array $checks + ) { + $quoteId = 1; + $storeId = 1; + + $paymentMethod = $this->getMock(MethodInterface::class); + $quote = $this->getMockBuilder(Quote::class) + ->disableOriginalConstructor() + ->getMock(); + $methodSpecification = $this->getMockBuilder(Composite::class) + ->disableOriginalConstructor() + ->getMock(); + + $quote->expects(static::once()) + ->method('getId') + ->willReturn($quoteId); + + $this->model->setQuote($quote); + $this->model->setMethodInstance($paymentMethod); + $this->eventManager->expects(static::once()) + ->method('dispatch') + ->with( + 'sales_quote_payment_import_data_before', + [ + 'payment' => $this->model, + 'input' => new DataObject($convertedData) + ] + ); + $quote->expects(static::once()) + ->method('getStoreId') + ->willReturn($storeId); + + $quote->expects(static::once()) + ->method('collectTotals'); + + $this->specificationFactory->expects(static::once()) + ->method('create') + ->with($checks) + ->willReturn($methodSpecification); + + $paymentMethod->expects(static::once()) + ->method('isAvailable') + ->with($quote) + ->willReturn(true); + $methodSpecification->expects(static::once()) + ->method('isApplicable') + ->with($paymentMethod, $quote) + ->willReturn(true); + + $paymentMethod->expects(static::once()) + ->method('assignData') + ->with(new DataObject($dataToAssign)); + $paymentMethod->expects(static::once()) + ->method('validate'); + + $this->model->importData($data); + } + + /** + * @return array + */ + public function importDataPositiveCheckDataProvider() + { + return [ + [ + [ + PaymentInterface::KEY_METHOD => 'payment_method_code', + 'cc_number' => '1111', + 'cc_type' => 'VI', + 'cc_owner' => 'John Doe' + ], + [ + PaymentInterface::KEY_METHOD => 'payment_method_code', + PaymentInterface::KEY_PO_NUMBER => null, + PaymentInterface::KEY_ADDITIONAL_DATA => [ + 'cc_number' => '1111', + 'cc_type' => 'VI', + 'cc_owner' => 'John Doe' + ], + 'checks' => [] + ], + [ + PaymentInterface::KEY_METHOD => 'payment_method_code', + PaymentInterface::KEY_PO_NUMBER => null, + PaymentInterface::KEY_ADDITIONAL_DATA => [ + 'cc_number' => '1111', + 'cc_type' => 'VI', + 'cc_owner' => 'John Doe' + ], + 'checks' => [] + ], + [] + ], + [ + [ + PaymentInterface::KEY_METHOD => 'payment_method_code', + 'cc_number' => '1111', + 'cc_type' => 'VI', + 'cc_owner' => 'John Doe', + 'checks' => ['check_code1', 'check_code2'] + ], + [ + PaymentInterface::KEY_METHOD => 'payment_method_code', + PaymentInterface::KEY_PO_NUMBER => null, + PaymentInterface::KEY_ADDITIONAL_DATA => [ + 'cc_number' => '1111', + 'cc_type' => 'VI', + 'cc_owner' => 'John Doe' + ], + 'checks' => ['check_code1', 'check_code2'] + ], + [ + PaymentInterface::KEY_METHOD => 'payment_method_code', + PaymentInterface::KEY_PO_NUMBER => null, + PaymentInterface::KEY_ADDITIONAL_DATA => [ + 'cc_number' => '1111', + 'cc_type' => 'VI', + 'cc_owner' => 'John Doe' + ], + 'checks' => ['check_code1', 'check_code2'] + ], + ['check_code1', 'check_code2'] + ] + ]; + } } From f42c8c7816082aef413a69a62b6a133445698fb3 Mon Sep 17 00:00:00 2001 From: Dmytro Kvashnin Date: Fri, 6 May 2016 16:35:28 +0300 Subject: [PATCH 6/8] MAGETWO-52560: Impossible to use Stored Cards via Braintree on Admin side --- .../Magento/Braintree/view/adminhtml/web/js/vault.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/app/code/Magento/Braintree/view/adminhtml/web/js/vault.js b/app/code/Magento/Braintree/view/adminhtml/web/js/vault.js index 22f8a2f6865f5..28346499d7fd9 100644 --- a/app/code/Magento/Braintree/view/adminhtml/web/js/vault.js +++ b/app/code/Magento/Braintree/view/adminhtml/web/js/vault.js @@ -7,9 +7,8 @@ define([ 'jquery', 'uiComponent', - 'Magento_Ui/js/modal/alert', - 'Magento_Checkout/js/model/full-screen-loader' -], function ($, Class, alert, fullScreenLoader) { + 'Magento_Ui/js/modal/alert' +], function ($, Class, alert) { 'use strict'; return Class.extend({ @@ -84,7 +83,7 @@ define([ submitOrder: function () { this.$selector.validate().form(); this.$selector.trigger('afterValidate.beforeSubmit'); - fullScreenLoader.stopLoader(); + $('body').trigger('processStop'); // validate parent form if (this.$selector.validate().errorList.length) { @@ -106,7 +105,7 @@ define([ getPaymentMethodNonce: function () { var self = this; - fullScreenLoader.startLoader(); + $('body').trigger('processStart'); $.get(self.nonceUrl, { 'public_hash': self.publicHash @@ -115,10 +114,9 @@ define([ self.placeOrder(); }).fail(function (response) { var failed = JSON.parse(response.responseText); - self.error(failed.message); }).always(function () { - fullScreenLoader.stopLoader(); + $('body').trigger('processStop'); }); }, From 56db8b86ea98402d2ff91f7e1c2e84872391a247 Mon Sep 17 00:00:00 2001 From: Ievgen Sentiabov Date: Thu, 12 May 2016 11:00:45 +0300 Subject: [PATCH 7/8] MAGETWO-52560: Impossible to use Stored Cards via Braintree on Admin side - Fixed failed static js test --- app/code/Magento/Braintree/view/adminhtml/web/js/vault.js | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Braintree/view/adminhtml/web/js/vault.js b/app/code/Magento/Braintree/view/adminhtml/web/js/vault.js index 28346499d7fd9..fcff173e7fcd4 100644 --- a/app/code/Magento/Braintree/view/adminhtml/web/js/vault.js +++ b/app/code/Magento/Braintree/view/adminhtml/web/js/vault.js @@ -114,6 +114,7 @@ define([ self.placeOrder(); }).fail(function (response) { var failed = JSON.parse(response.responseText); + self.error(failed.message); }).always(function () { $('body').trigger('processStop'); From b8b52ad186b81888a68ca0242591d9f4dee6e541 Mon Sep 17 00:00:00 2001 From: Ievgen Sentiabov Date: Thu, 12 May 2016 14:57:05 +0300 Subject: [PATCH 8/8] MAGETWO-48048: Bundle product price on category view isn't included custom option price - Marked method as deprecated --- app/code/Magento/Bundle/Pricing/Price/FinalPrice.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Bundle/Pricing/Price/FinalPrice.php b/app/code/Magento/Bundle/Pricing/Price/FinalPrice.php index d9821064c236d..b6d7fc40d8c2f 100644 --- a/app/code/Magento/Bundle/Pricing/Price/FinalPrice.php +++ b/app/code/Magento/Bundle/Pricing/Price/FinalPrice.php @@ -92,6 +92,7 @@ public function getMaximalPrice() * Return ProductCustomOptionRepository * * @return ProductCustomOptionRepositoryInterface + * @deprecated */ private function getProductOptionRepository() {