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..fcff173e7fcd4 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 @@ -118,7 +117,7 @@ define([ self.error(failed.message); }).always(function () { - fullScreenLoader.stopLoader(); + $('body').trigger('processStop'); }); }, diff --git a/app/code/Magento/Bundle/Pricing/Price/FinalPrice.php b/app/code/Magento/Bundle/Pricing/Price/FinalPrice.php index 5be2c55d04b2a..b6d7fc40d8c2f 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,22 @@ public function getMaximalPrice() return $this->maximalPrice; } + /** + * Return ProductCustomOptionRepository + * + * @return ProductCustomOptionRepositoryInterface + * @deprecated + */ + private function getProductOptionRepository() + { + if (!$this->productOptionRepository) { + $this->productOptionRepository = ObjectManager::getInstance()->get( + ProductCustomOptionRepositoryInterface::class + ); + } + return $this->productOptionRepository; + } + /** * Returns min price * @@ -101,6 +124,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 +134,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 * 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..9498a501e22bb 100644 --- a/app/code/Magento/Bundle/Test/Unit/Pricing/Price/FinalPriceTest.php +++ b/app/code/Magento/Bundle/Test/Unit/Pricing/Price/FinalPriceTest.php @@ -9,9 +9,13 @@ 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\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,10 +49,15 @@ 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; + /** + * @var ProductCustomOptionRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $productOptionRepositoryMock; + /** * @return void */ @@ -96,6 +105,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 +189,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') 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 @@ - + 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'] + ] + ]; + } }