Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/

namespace Magento\Quote\Model\QuoteRepository\Plugin;

use Magento\Customer\Api\CustomerRepositoryInterface;
use Magento\Customer\Api\Data\CustomerInterface;
use Magento\Quote\Api\CartRepositoryInterface;
use Magento\Quote\Api\Data\CartInterface;
use Magento\Sales\Api\Data\OrderInterface;

/**
* Add to quote all necessary customer information.
*/
class AddCustomerInfo
{
/**
* List of necessary fields.
*
* @var array
*/
private $fields = [
OrderInterface::CUSTOMER_EMAIL,
OrderInterface::CUSTOMER_FIRSTNAME,
OrderInterface::CUSTOMER_LASTNAME,
];

/**
* @var CustomerRepositoryInterface
*/
private $customerRepository;

/**
* AddCustomerInfo constructor.
*
* @param CustomerRepositoryInterface $customerRepository
*/
public function __construct(CustomerRepositoryInterface $customerRepository)
{
$this->customerRepository = $customerRepository;
}

/**
* Add to quote customer necessary information, if needed.
*
* @param CartRepositoryInterface $subject
* @param CartInterface $quote
* @return null
*
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function beforeSave(CartRepositoryInterface $subject, CartInterface $quote)
{
if ($quote->getCustomerId() !== null) {
$customer = $this->customerRepository->getById($quote->getCustomerId());
foreach ($this->fields as $property) {
if ($quote->getData($property) === null) {
$value = $this->getCustomerData($customer, $property);
$quote->setData($property, $value);
}
}
$quote->setCustomerGroupId($customer->getGroupId());
$quote->setCustomerIsGuest(false);
}

return null;
}

/**
* @param CustomerInterface $customer
* @param string $property
*
* @return null|string
*/
private function getCustomerData(CustomerInterface $customer, string $property)
{
$result = '';
switch ($property) {
case OrderInterface::CUSTOMER_EMAIL:
$result = $customer->getEmail();
break;
case OrderInterface::CUSTOMER_FIRSTNAME:
$result = $customer->getFirstname();
break;
case OrderInterface::CUSTOMER_LASTNAME:
$result = $customer->getLastname();
break;
}

return $result;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/

namespace Magento\Quote\Test\Unit\Model\QuoteRepository\Plugin;

use Magento\Customer\Api\CustomerRepositoryInterface;
use Magento\Customer\Api\Data\CustomerInterface;
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
use Magento\Quote\Api\CartRepositoryInterface;
use Magento\Quote\Api\Data\CartInterface;
use Magento\Quote\Model\QuoteRepository\Plugin\AddCustomerInfo;
use Magento\Sales\Api\Data\OrderInterface;
use PHPUnit\Framework\TestCase;

/**
* Provide test for AddCustomerInfoPlugin.
*/
class AddCustomerInfoTest extends TestCase
{
/**
* @var AddCustomerInfo
*/
private $testSubject;

/**
* @var CustomerRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject
*/
private $customerRepository;

/**
* @inheritdoc
*/
protected function setUp()
{
$this->customerRepository = $this->getMockBuilder(CustomerRepositoryInterface::class)
->disableOriginalConstructor()
->setMethods(['getById'])
->getMockForAbstractClass();
$objectManager = new ObjectManager($this);
$this->testSubject = $objectManager->getObject(
AddCustomerInfo::class,
['customerRepository' => $this->customerRepository]
);
}

/**
* Test all necessary customer info will be added to cart, if absent.
*
* @return void
*/
public function testBeforeSave()
{
$customerId = '1';
$customerEmail = 'customer@exampel.com';
$customerFirstName = 'John';
$customerLastName = 'Doe';
$customerGroupId = 1;

/** @var CustomerInterface|\PHPUnit_Framework_MockObject_MockObject $customer */
$customer = $this->getMockBuilder(CustomerInterface::class)
->disableOriginalConstructor()
->getMockForAbstractClass();
$customer->expects(self::once())
->method('getEmail')
->willReturn($customerEmail);
$customer->expects(self::once())
->method('getFirstName')
->willReturn($customerFirstName);
$customer->expects(self::once())
->method('getLastName')
->willReturn($customerLastName);
$customer->expects(self::once())
->method('getGroupId')
->willReturn($customerGroupId);

$this->customerRepository->expects(self::once())
->method('getById')
->with(self::identicalTo($customerId))
->willReturn($customer);

/** @var CartRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject $cartRepository */
$cartRepository = $this->getMockBuilder(CartRepositoryInterface::class)
->disableOriginalConstructor()
->getMockForAbstractClass();

/** @var CartInterface|\PHPUnit_Framework_MockObject_MockObject $cart */
$cart = $this->getMockBuilder(CartInterface::class)
->disableOriginalConstructor()
->setMethods(['getCustomerId', 'getData', 'setCustomerIsGuest', 'setData', 'setCustomerGroupId'])
->getMockForAbstractClass();
$cart->expects(self::exactly(2))
->method('getCustomerId')
->willReturn($customerId);
$cart->expects(self::exactly(3))
->method('getData')
->withConsecutive(
self::identicalTo(OrderInterface::CUSTOMER_EMAIL),
self::identicalTo(OrderInterface::CUSTOMER_FIRSTNAME),
self::identicalTo(OrderInterface::CUSTOMER_LASTNAME)
)
->willReturn(null);
$cart->expects(self::exactly(3))
->method('setData')
->withConsecutive(
self::identicalTo(OrderInterface::CUSTOMER_EMAIL),
self::identicalTo(OrderInterface::CUSTOMER_FIRSTNAME),
self::identicalTo(OrderInterface::CUSTOMER_LASTNAME)
)
->willReturnSelf();
$cart->expects(self::once())
->method('setCustomerGroupId')
->with($customerGroupId)
->willReturnSelf();
$cart->expects(self::once())
->method('setCustomerIsGuest')
->with(self::identicalTo(false))
->willReturnSelf();

$this->testSubject->beforeSave($cartRepository, $cart);
}
}
1 change: 1 addition & 0 deletions app/code/Magento/Quote/etc/webapi_rest/di.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@
</type>
<type name="Magento\Quote\Model\QuoteRepository">
<plugin name="accessControl" type="Magento\Quote\Model\QuoteRepository\Plugin\AccessChangeQuoteControl" />
<plugin name="add_customer_info" type="Magento\Quote\Model\QuoteRepository\Plugin\AddCustomerInfo" />
</type>
</config>
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,50 @@ public function testSaveQuote()
$this->assertEquals($requestData["quote"]["customer"]["email"], $quote->getCustomerEmail());
}

/**
* Saving quote without full customer information, just customer id.
*
* @magentoApiDataFixture Magento/Sales/_files/quote.php
* @magentoApiDataFixture Magento/Customer/_files/customer.php
* @return void
*/
public function testSaveQuoteWithMinimalCustomerInfo()
{
//for SOAP all necessary fields for customer are mandatory.
$this->_markTestAsRestOnly();
$token = $this->getToken();
/** @var Quote $quote */
$quote = $this->getCart('test01');
$requestData['quote'] = [
'id' => $quote->getId(),
'customer' => [
'id' => 1,
],
];
$serviceInfo = [
'rest' => [
'resourcePath' => self::$mineCartUrl,
'httpMethod' => Request::HTTP_METHOD_PUT,
'token' => $token
]
];

$this->_webApiCall($serviceInfo, $requestData);

// Reload target quote
$quote = $this->getCart('test01');
/** @var $repository \Magento\Customer\Api\CustomerRepositoryInterface */
$repository = $this->objectManager->create(\Magento\Customer\Api\CustomerRepositoryInterface::class);
/** @var $customer \Magento\Customer\Api\Data\CustomerInterface */
$customer = $repository->get('customer@example.com');
$this->assertEquals(0, $quote->getCustomerIsGuest());
$this->assertEquals($customer->getId(), $quote->getCustomerId());
$this->assertEquals($customer->getFirstname(), $quote->getCustomerFirstname());
$this->assertEquals($customer->getLastname(), $quote->getCustomerLastname());
$this->assertEquals($customer->getEmail(), $quote->getCustomerEmail());
$this->assertEquals($customer->getGroupId(), $quote->getCustomerGroupId());
}

/**
* Request to api for the current user token.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/

namespace Magento\Quote\Model\QuoteRepository\Plugin;

use Magento\Authorization\Model\CompositeUserContext;
use Magento\Authorization\Model\UserContextInterface;
use Magento\Customer\Api\CustomerRepositoryInterface;
use Magento\Customer\Api\Data\CustomerInterface;
use Magento\Framework\App\Area;
use Magento\Quote\Model\QuoteRepository;
use Magento\TestFramework\App\State;
use Magento\TestFramework\Helper\Bootstrap;
use Magento\TestFramework\Interception\PluginList;
use PHPUnit\Framework\TestCase;

/**
* Provide tests for AddCustomerInfo plugin.
*/
class AddCustomerInfoTest extends TestCase
{
/**
* Test AddCustomerInfo plugin is registered for Rest Api area.
*/
public function testAddCustomerInfoIsRegistered()
{
/** @var State $state */
$state = Bootstrap::getObjectManager()->get(State::class);
$state->setAreaCode(Area::AREA_WEBAPI_REST);
$pluginInfo = Bootstrap::getObjectManager()->get(PluginList::class)->get(QuoteRepository::class, []);
self::assertSame(AddCustomerInfo::class, $pluginInfo['add_customer_info']['instance']);
}

/**
* Test AddCustomerInfo plugin adds all necessary customer information, if quote has customer id.
*
* @magentoDataFixture Magento/Sales/_files/quote.php
* @magentoDataFixture Magento/Customer/_files/customer.php
*/
public function testAfterSave()
{
/** @var State $state */
$state = Bootstrap::getObjectManager()->get(State::class);
$state->setAreaCode(Area::AREA_WEBAPI_REST);
/** @var CustomerRepositoryInterface $customerRepository */
$customerRepository = Bootstrap::getObjectManager()->get(CustomerRepositoryInterface::class);
/** @var CustomerInterface $customer */
$customer = $customerRepository->get('customer@example.com');
$this->mockUserContext($customer->getId());
/** @var QuoteRepository $quoteRepository */
$quoteRepository = Bootstrap::getObjectManager()->create(QuoteRepository::class);
$quote = $this->loadQuote();
$quote->setCustomerId($customer->getId());
$quoteRepository->save($quote);
$quote = $this->loadQuote();
self::assertEquals(0, $quote->getCustomerIsGuest());
self::assertEquals($customer->getId(), $quote->getCustomerId());
self::assertEquals($customer->getFirstname(), $quote->getCustomerFirstname());
self::assertEquals($customer->getLastname(), $quote->getCustomerLastname());
self::assertEquals($customer->getEmail(), $quote->getCustomerEmail());
self::assertEquals($customer->getGroupId(), $quote->getCustomerGroupId());
}

/**
* @return \Magento\Quote\Model\Quote
*/
private function loadQuote()
{
/** @var $quote \Magento\Quote\Model\Quote */
$quote = Bootstrap::getObjectManager()->get(\Magento\Quote\Model\Quote::class);
$quote->load('test01', 'reserved_order_id');

return $quote;
}

/**
* Mock User context to bypass AccessChangeQuoteControl plugin.
*
* @param string $customerId
* @return void
*/
private function mockUserContext(string $customerId)
{
Bootstrap::getObjectManager()->removeSharedInstance(CompositeUserContext::class);
/** @var UserContextInterface|\PHPUnit_Framework_MockObject_MockObject $userContext */
$userContext = $this->getMockBuilder(CompositeUserContext::class)
->setMethods(['getUserType', 'getUserId'])
->disableOriginalConstructor()
->getMockForAbstractClass();
$userContext->expects(self::any())
->method('getUserType')
->willReturn(UserContextInterface::USER_TYPE_CUSTOMER);
$userContext->expects(self::any())
->method('getUserId')
->willReturn($customerId);
Bootstrap::getObjectManager()->addSharedInstance($userContext, CompositeUserContext::class);
}
}