Skip to content

Commit f4d574d

Browse files
committed
Merge remote-tracking branch 'origin/MAGETWO-71522' into 2.1-develop-pr36
2 parents 04c67ca + 3efe60d commit f4d574d

File tree

4 files changed

+274
-17
lines changed

4 files changed

+274
-17
lines changed
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?php
2+
/**
3+
* Copyright © 2013-2017 Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
namespace Magento\Paypal\Model\Express;
7+
8+
use Magento\Quote\Model\QuoteRepository\SaveHandler;
9+
use Magento\Quote\Api\Data\CartInterface;
10+
use Magento\Quote\Model\Quote\ProductOptionFactory;
11+
12+
/**
13+
* Plugin for Magento\Quote\Model\QuoteRepository\SaveHandler.
14+
*
15+
* Replaces cart item product options for disabled quote
16+
* which prevents it to be processed after placement of order
17+
* via PayPal Express payment solution.
18+
*/
19+
class QuotePlugin
20+
{
21+
/**
22+
* @var ProductOptionFactory
23+
*/
24+
private $productOptionFactory;
25+
26+
/**
27+
* @param ProductOptionFactory $productOptionFactory
28+
*/
29+
public function __construct(ProductOptionFactory $productOptionFactory)
30+
{
31+
$this->productOptionFactory = $productOptionFactory;
32+
}
33+
34+
/**
35+
* Replace cart item product options for disabled quote.
36+
*
37+
* @param SaveHandler $subject
38+
* @param CartInterface $quote
39+
* @return array
40+
*
41+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
42+
*/
43+
public function beforeSave(SaveHandler $subject, CartInterface $quote)
44+
{
45+
if (!$quote->getIsActive()) {
46+
$items = $quote->getItems();
47+
48+
if ($items) {
49+
foreach ($items as $item) {
50+
/** @var \Magento\Quote\Model\Quote\Item $item */
51+
if (!$item->isDeleted()) {
52+
$item->setProductOption($this->productOptionFactory->create());
53+
}
54+
}
55+
}
56+
}
57+
58+
return [$quote];
59+
}
60+
}

app/code/Magento/Paypal/etc/frontend/di.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,4 +112,7 @@
112112
</argument>
113113
</arguments>
114114
</type>
115+
<type name="Magento\Quote\Model\QuoteRepository\SaveHandler">
116+
<plugin name="paypal-cartitem" type="Magento\Paypal\Model\Express\QuotePlugin"/>
117+
</type>
115118
</config>

dev/tests/integration/testsuite/Magento/Paypal/Controller/ExpressTest.php

Lines changed: 148 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,32 @@
55
*/
66
namespace Magento\Paypal\Controller;
77

8+
use Magento\Checkout\Model\Session;
9+
use Magento\Framework\Session\Generic as GenericSession;
10+
use Magento\Paypal\Model\Api\Nvp;
11+
use Magento\Paypal\Model\Api\Type\Factory as ApiFactory;
12+
use Magento\Paypal\Model\Session as PaypalSession;
13+
use Magento\Quote\Model\Quote;
14+
use Magento\TestFramework\Helper\Bootstrap;
15+
16+
/**
17+
* Tests of Paypal Express actions.
18+
*
19+
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
20+
*/
821
class ExpressTest extends \Magento\TestFramework\TestCase\AbstractController
922
{
1023
/**
1124
* @magentoDataFixture Magento/Sales/_files/quote.php
1225
* @magentoDataFixture Magento/Paypal/_files/quote_payment.php
26+
* @return void
1327
*/
1428
public function testReviewAction()
1529
{
16-
$quote = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create('Magento\Quote\Model\Quote');
30+
$quote = Bootstrap::getObjectManager()->create(Quote::class);
1731
$quote->load('test01', 'reserved_order_id');
18-
\Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(
19-
'Magento\Checkout\Model\Session'
32+
Bootstrap::getObjectManager()->get(
33+
Session::class
2034
)->setQuoteId(
2135
$quote->getId()
2236
);
@@ -30,16 +44,17 @@ public function testReviewAction()
3044
}
3145

3246
/**
33-
* @magentoDataFixture Magento/Paypal/_files/quote_payment_express.php
47+
* @magentoDataFixture Magento/Paypal/_files/quote_payment_express.php
3448
* @magentoConfigFixture current_store paypal/general/business_account merchant_2012050718_biz@example.com
49+
* @return void
3550
*/
3651
public function testCancelAction()
3752
{
38-
$quote = $this->_objectManager->create('Magento\Quote\Model\Quote');
53+
$quote = $this->_objectManager->create(Quote::class);
3954
$quote->load('100000002', 'reserved_order_id');
40-
$order = $this->_objectManager->create('Magento\Sales\Model\Order');
55+
$order = $this->_objectManager->create(\Magento\Sales\Model\Order::class);
4156
$order->load('100000002', 'increment_id');
42-
$session = $this->_objectManager->get('Magento\Checkout\Model\Session');
57+
$session = $this->_objectManager->get(Session::class);
4358
$session->setLoadInactive(true);
4459
$session->setLastRealOrderId(
4560
$order->getRealOrderId()
@@ -50,8 +65,8 @@ public function testCancelAction()
5065
)->setQuoteId(
5166
$order->getQuoteId()
5267
);
53-
/** @var $paypalSession \Magento\Framework\Session\Generic */
54-
$paypalSession = $this->_objectManager->get('Magento\Paypal\Model\Session');
68+
/** @var GenericSession $paypalSession */
69+
$paypalSession = $this->_objectManager->get(PaypalSession::class);
5570
$paypalSession->setExpressCheckoutToken('token');
5671

5772
$this->dispatch('paypal/express/cancel');
@@ -69,6 +84,7 @@ public function testCancelAction()
6984
*
7085
* @magentoDataFixture Magento/Sales/_files/quote.php
7186
* @magentoDataFixture Magento/Customer/_files/customer.php
87+
* @return void
7288
*/
7389
public function testStartActionCustomerToQuote()
7490
{
@@ -79,18 +95,18 @@ public function testStartActionCustomerToQuote()
7995

8096
/** Preconditions */
8197
/** @var \Magento\Customer\Model\Session $customerSession */
82-
$customerSession = $this->_objectManager->get('Magento\Customer\Model\Session');
98+
$customerSession = $this->_objectManager->get(\Magento\Customer\Model\Session::class);
8399
/** @var \Magento\Customer\Api\CustomerRepositoryInterface $customerRepository */
84-
$customerRepository = $this->_objectManager->get('Magento\Customer\Api\CustomerRepositoryInterface');
100+
$customerRepository = $this->_objectManager->get(\Magento\Customer\Api\CustomerRepositoryInterface::class);
85101
$customerData = $customerRepository->getById($fixtureCustomerId);
86102
$customerSession->setCustomerDataObject($customerData);
87103

88-
/** @var \Magento\Quote\Model\Quote $quote */
89-
$quote = $this->_objectManager->create('Magento\Quote\Model\Quote');
104+
/** @var Quote $quote */
105+
$quote = $this->_objectManager->create(Quote::class);
90106
$quote->load($fixtureQuoteReserveId, 'reserved_order_id');
91107

92-
/** @var \Magento\Checkout\Model\Session $checkoutSession */
93-
$checkoutSession = $this->_objectManager->get('Magento\Checkout\Model\Session');
108+
/** @var Session $checkoutSession */
109+
$checkoutSession = $this->_objectManager->get(Session::class);
94110
$checkoutSession->setQuoteId($quote->getId());
95111

96112
/** Preconditions check */
@@ -109,8 +125,8 @@ public function testStartActionCustomerToQuote()
109125
$this->dispatch('paypal/express/start');
110126

111127
/** Check if customer data was copied to quote correctly */
112-
/** @var \Magento\Quote\Model\Quote $updatedQuote */
113-
$updatedQuote = $this->_objectManager->create('Magento\Quote\Model\Quote');
128+
/** @var Quote $updatedQuote */
129+
$updatedQuote = $this->_objectManager->create(Quote::class);
114130
$updatedQuote->load($fixtureQuoteReserveId, 'reserved_order_id');
115131
$this->assertEquals(
116132
$fixtureCustomerEmail,
@@ -123,4 +139,119 @@ public function testStartActionCustomerToQuote()
123139
"Customer first name in quote is invalid."
124140
);
125141
}
142+
143+
/**
144+
* Test return action with configurable product.
145+
*
146+
* @magentoDataFixture Magento/Paypal/_files/quote_express_configurable.php
147+
* @magentoDbIsolation enabled
148+
* @magentoAppIsolation enabled
149+
* @return void
150+
*/
151+
public function testReturnAction()
152+
{
153+
/** @var Quote $quote */
154+
$quote = $this->_objectManager->create(Quote::class);
155+
$quote->load('test_cart_with_configurable', 'reserved_order_id');
156+
157+
$payment = $quote->getPayment();
158+
$payment->setMethod(\Magento\Paypal\Model\Config::METHOD_WPP_EXPRESS)
159+
->setAdditionalInformation(\Magento\Paypal\Model\Express\Checkout::PAYMENT_INFO_TRANSPORT_PAYER_ID, 123);
160+
161+
$quote->save();
162+
163+
$this->_objectManager->removeSharedInstance(Session::class);
164+
$session = $this->_objectManager->get(Session::class);
165+
$session->setQuoteId($quote->getId());
166+
167+
$nvpMethods = [
168+
'setToken',
169+
'setPayerId',
170+
'setAmount',
171+
'setPaymentAction',
172+
'setNotifyUrl',
173+
'setInvNum',
174+
'setCurrencyCode',
175+
'setPaypalCart',
176+
'setIsLineItemsEnabled',
177+
'setAddress',
178+
'setBillingAddress',
179+
'callDoExpressCheckoutPayment',
180+
'callGetExpressCheckoutDetails',
181+
];
182+
183+
$nvpMock = $this->getMockBuilder(Nvp::class)
184+
->setMethods($nvpMethods)
185+
->disableOriginalConstructor()
186+
->getMock();
187+
188+
foreach ($nvpMethods as $method) {
189+
$nvpMock->method($method)
190+
->willReturnSelf();
191+
}
192+
193+
$exportedBillingAddress = $this->getExportedAddressFixture($quote->getBillingAddress()->toArray());
194+
$nvpMock->setData('exported_billing_address', $exportedBillingAddress);
195+
196+
$apiFactoryMock = $this->getMockBuilder(ApiFactory::class)
197+
->disableOriginalConstructor()
198+
->setMethods(['create'])
199+
->getMock();
200+
201+
$apiFactoryMock->method('create')
202+
->with(Nvp::class)
203+
->willReturn($nvpMock);
204+
205+
$this->_objectManager->addSharedInstance($apiFactoryMock, ApiFactory::class);
206+
207+
$sessionMock = $this->getMockBuilder(GenericSession::class)
208+
->setMethods(['getExpressCheckoutToken'])
209+
->setConstructorArgs(
210+
[
211+
$this->_objectManager->get(\Magento\Framework\App\Request\Http::class),
212+
$this->_objectManager->get(\Magento\Framework\Session\SidResolverInterface::class),
213+
$this->_objectManager->get(\Magento\Framework\Session\Config\ConfigInterface::class),
214+
$this->_objectManager->get(\Magento\Framework\Session\SaveHandlerInterface::class),
215+
$this->_objectManager->get(\Magento\Framework\Session\ValidatorInterface::class),
216+
$this->_objectManager->get(\Magento\Framework\Session\StorageInterface::class),
217+
$this->_objectManager->get(\Magento\Framework\Stdlib\CookieManagerInterface::class),
218+
$this->_objectManager->get(\Magento\Framework\Stdlib\Cookie\CookieMetadataFactory::class),
219+
$this->_objectManager->get(\Magento\Framework\App\State::class),
220+
]
221+
)
222+
->getMock();
223+
224+
$sessionMock->method('getExpressCheckoutToken')
225+
->willReturn(true);
226+
227+
$this->_objectManager->addSharedInstance($sessionMock, PaypalSession::class);
228+
229+
$this->dispatch('paypal/express/returnAction');
230+
$this->assertRedirect($this->stringContains('checkout/onepage/success'));
231+
232+
$this->_objectManager->removeSharedInstance(ApiFactory::class);
233+
$this->_objectManager->removeSharedInstance(PaypalSession::class);
234+
}
235+
236+
/**
237+
* Prepare fixture for exported address.
238+
*
239+
* @param array $addressData
240+
* @return \Magento\Framework\DataObject
241+
*/
242+
private function getExportedAddressFixture(array $addressData)
243+
{
244+
$addressDataKeys = ['firstname', 'lastname', 'street', 'city', 'telephone'];
245+
$result = [];
246+
foreach ($addressDataKeys as $key) {
247+
if (isset($addressData[$key])) {
248+
$result[$key] = 'exported' . $addressData[$key];
249+
}
250+
}
251+
$fixture = new \Magento\Framework\DataObject($result);
252+
$fixture->setExportedKeys($addressDataKeys);
253+
$fixture->setData('note', 'note');
254+
255+
return $fixture;
256+
}
126257
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<?php
2+
/**
3+
* Copyright © 2013-2017 Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
use Magento\Catalog\Api\ProductRepositoryInterface;
8+
use Magento\Checkout\Model\Cart;
9+
use Magento\Eav\Model\ResourceModel\Entity\Attribute\Option\Collection;
10+
use Magento\Quote\Model\Quote\Address;
11+
use Magento\Quote\Model\Quote\Address\Rate;
12+
use Magento\TestFramework\Helper\Bootstrap;
13+
14+
require __DIR__ . '/../../../Magento/ConfigurableProduct/_files/product_configurable.php';
15+
16+
/** @var \Magento\TestFramework\ObjectManager $objectManager */
17+
$objectManager = Bootstrap::getObjectManager();
18+
19+
/** @var \Magento\Catalog\Model\Product $product */
20+
/** @var \Magento\Catalog\Model\ResourceModel\Eav\Attribute $attribute */
21+
$productRepository = $objectManager->create(ProductRepositoryInterface::class);
22+
$product = $productRepository->get('configurable');
23+
24+
/** @var Collection $options */
25+
$options = $objectManager->create(Collection::class);
26+
$option = $options->setAttributeFilter($attribute->getId())->getFirstItem();
27+
28+
$requestInfo = new \Magento\Framework\DataObject(
29+
[
30+
'product' => 1,
31+
'selected_configurable_option' => 1,
32+
'qty' => 100,
33+
'super_attribute' => [
34+
$attribute->getId() => $option->getId(),
35+
],
36+
]
37+
);
38+
39+
/** @var Cart $cart */
40+
$cart = $objectManager->create(Cart::class);
41+
$cart->addProduct($product, $requestInfo);
42+
43+
/** @var Rate $rate */
44+
$rate = $objectManager->create(Rate::class);
45+
$rate->setCode('flatrate_flatrate');
46+
$rate->setPrice(1);
47+
48+
$addressData = include __DIR__ . '/address_data.php';
49+
$billingAddress = $objectManager->create(Address::class, ['data' => $addressData]);
50+
$billingAddress->setAddressType('billing');
51+
52+
$shippingAddress = clone $billingAddress;
53+
$shippingAddress->setId(null)
54+
->setAddressType('shipping')
55+
->setShippingMethod('flatrate_flatrate')
56+
->addShippingRate($rate);
57+
58+
$cart->getQuote()
59+
->setReservedOrderId('test_cart_with_configurable')
60+
->setBillingAddress($billingAddress)
61+
->setShippingAddress($shippingAddress);
62+
63+
$cart->save();

0 commit comments

Comments
 (0)