441 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			PHP
		
	
	
		
			Executable File
		
	
	
			
		
		
	
	
			441 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			PHP
		
	
	
		
			Executable File
		
	
	
<?php
 | 
						|
/**
 | 
						|
 * Copyright © Magento, Inc. All rights reserved.
 | 
						|
 * See COPYING.txt for license details.
 | 
						|
 */
 | 
						|
declare(strict_types=1);
 | 
						|
 | 
						|
namespace Magento\Quote\Model;
 | 
						|
 | 
						|
use Magento\Catalog\Api\ProductRepositoryInterface;
 | 
						|
use Magento\Catalog\Model\Product\Type;
 | 
						|
use Magento\Checkout\Api\PaymentInformationManagementInterface;
 | 
						|
use Magento\Customer\Api\CustomerRepositoryInterface;
 | 
						|
use Magento\Customer\Model\Vat;
 | 
						|
use Magento\Framework\App\Config\ScopeConfigInterface;
 | 
						|
use Magento\Framework\DataObject;
 | 
						|
use Magento\Framework\Exception\CouldNotSaveException;
 | 
						|
use Magento\Framework\Exception\LocalizedException;
 | 
						|
use Magento\Framework\Exception\StateException;
 | 
						|
use Magento\Framework\ObjectManagerInterface;
 | 
						|
use Magento\Quote\Api\CartManagementInterface;
 | 
						|
use Magento\Quote\Api\Data\AddressInterface;
 | 
						|
use Magento\Quote\Api\Data\PaymentInterface;
 | 
						|
use Magento\Quote\Observer\Frontend\Quote\Address\CollectTotalsObserver;
 | 
						|
use Magento\Quote\Observer\Frontend\Quote\Address\VatValidator;
 | 
						|
use Magento\Sales\Api\OrderManagementInterface;
 | 
						|
use Magento\Sales\Api\OrderRepositoryInterface;
 | 
						|
use Magento\Store\Model\StoreManagerInterface;
 | 
						|
use Magento\TestFramework\Helper\Bootstrap;
 | 
						|
use Magento\TestFramework\Quote\Model\GetQuoteByReservedOrderId;
 | 
						|
use PHPUnit\Framework\ExpectationFailedException;
 | 
						|
use PHPUnit\Framework\TestCase;
 | 
						|
use Psr\Log\LoggerInterface;
 | 
						|
 | 
						|
/**
 | 
						|
 * Class for testing QuoteManagement model
 | 
						|
 *
 | 
						|
 * @see \Magento\Quote\Model\QuoteManagement
 | 
						|
 * @magentoDbIsolation enabled
 | 
						|
 * @magentoAppIsolation enabled
 | 
						|
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
 | 
						|
 */
 | 
						|
class QuoteManagementTest extends TestCase
 | 
						|
{
 | 
						|
    /**
 | 
						|
     * @var ObjectManagerInterface
 | 
						|
     */
 | 
						|
    private $objectManager;
 | 
						|
 | 
						|
    /**
 | 
						|
     * @var CartManagementInterface
 | 
						|
     */
 | 
						|
    private $cartManagement;
 | 
						|
 | 
						|
    /**
 | 
						|
     * @var OrderRepositoryInterface
 | 
						|
     */
 | 
						|
    private $orderRepository;
 | 
						|
 | 
						|
    /**
 | 
						|
     * @var GetQuoteByReservedOrderId
 | 
						|
     */
 | 
						|
    private $getQuoteByReservedOrderId;
 | 
						|
 | 
						|
    /**
 | 
						|
     * @var ProductRepositoryInterface
 | 
						|
     */
 | 
						|
    private $productRepository;
 | 
						|
 | 
						|
    /**
 | 
						|
     * @var CustomerRepositoryInterface
 | 
						|
     */
 | 
						|
    private $customerRepository;
 | 
						|
 | 
						|
    /**
 | 
						|
     * @var StoreManagerInterface
 | 
						|
     */
 | 
						|
    private $storeManager;
 | 
						|
 | 
						|
    /**
 | 
						|
     * @var PaymentInformationManagementInterface
 | 
						|
     */
 | 
						|
    private $paymentManagement;
 | 
						|
 | 
						|
    /**
 | 
						|
     * @var PaymentInterface
 | 
						|
     */
 | 
						|
    private $payment;
 | 
						|
 | 
						|
    /**
 | 
						|
     * @var AddressInterface
 | 
						|
     */
 | 
						|
    private $address;
 | 
						|
 | 
						|
    /**
 | 
						|
     * @inheritdoc
 | 
						|
     */
 | 
						|
    protected function setUp(): void
 | 
						|
    {
 | 
						|
        parent::setUp();
 | 
						|
 | 
						|
        $this->objectManager = Bootstrap::getObjectManager();
 | 
						|
        $this->cartManagement = $this->objectManager->get(CartManagementInterface::class);
 | 
						|
        $this->orderRepository = $this->objectManager->get(OrderRepositoryInterface::class);
 | 
						|
        $this->getQuoteByReservedOrderId = $this->objectManager->get(GetQuoteByReservedOrderId::class);
 | 
						|
        $this->productRepository = $this->objectManager->get(ProductRepositoryInterface::class);
 | 
						|
        $this->productRepository->cleanCache();
 | 
						|
        $this->customerRepository = $this->objectManager->get(CustomerRepositoryInterface::class);
 | 
						|
        $this->storeManager = $this->objectManager->get(StoreManagerInterface::class);
 | 
						|
        $this->paymentManagement = $this->objectManager->get(PaymentInformationManagementInterface::class);
 | 
						|
        $this->payment = $this->objectManager->get(PaymentInterface::class);
 | 
						|
        $this->address = $this->objectManager->get(AddressInterface::class);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Creates order with product that has child items.
 | 
						|
     *
 | 
						|
     * @magentoAppIsolation enabled
 | 
						|
     * @magentoDataFixture Magento/Sales/_files/quote_with_bundle.php
 | 
						|
     *
 | 
						|
     * @return void
 | 
						|
     */
 | 
						|
    public function testSubmit(): void
 | 
						|
    {
 | 
						|
        $quote = $this->getQuoteByReservedOrderId->execute('test01');
 | 
						|
        $orderId = $this->cartManagement->placeOrder($quote->getId());
 | 
						|
        $order = $this->orderRepository->get($orderId);
 | 
						|
        $orderItems = $order->getItems();
 | 
						|
        $this->assertCount(3, $orderItems);
 | 
						|
        foreach ($orderItems as $orderItem) {
 | 
						|
            if ($orderItem->getProductType() == Type::TYPE_SIMPLE) {
 | 
						|
                $this->assertNotEmpty($orderItem->getParentItem(), 'Parent is not set for child product');
 | 
						|
                $this->assertNotEmpty($orderItem->getParentItemId(), 'Parent is not set for child product');
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Verify guest customer place order with auto-group assigment.
 | 
						|
     *
 | 
						|
     * @magentoDataFixture Magento/Sales/_files/guest_quote_with_addresses.php
 | 
						|
     *
 | 
						|
     * @magentoConfigFixture default_store customer/create_account/auto_group_assign 1
 | 
						|
     * @magentoConfigFixture default_store customer/create_account/tax_calculation_address_type shipping
 | 
						|
     * @magentoConfigFixture default_store customer/create_account/viv_intra_union_group 2
 | 
						|
     * @magentoConfigFixture default_store customer/create_account/viv_on_each_transaction 1
 | 
						|
     *
 | 
						|
     * @return void
 | 
						|
     */
 | 
						|
    public function testSubmitGuestCustomer(): void
 | 
						|
    {
 | 
						|
        $this->mockVatValidation();
 | 
						|
        $quote = $this->getQuoteByReservedOrderId->execute('guest_quote');
 | 
						|
        $this->cartManagement->placeOrder($quote->getId());
 | 
						|
        $quoteAfterOrderPlaced = $this->getQuoteByReservedOrderId->execute('guest_quote');
 | 
						|
        self::assertEquals(0, $quoteAfterOrderPlaced->getCustomerGroupId());
 | 
						|
        self::assertEquals(3, $quoteAfterOrderPlaced->getCustomerTaxClassId());
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Creates order with purchase_order payment method
 | 
						|
     *
 | 
						|
     * @magentoAppIsolation enabled
 | 
						|
     * @magentoDataFixture Magento/Sales/_files/quote_with_purchase_order.php
 | 
						|
     *
 | 
						|
     * @return void
 | 
						|
     * @throws CouldNotSaveException
 | 
						|
     */
 | 
						|
    public function testSubmitWithPurchaseOrder(): void
 | 
						|
    {
 | 
						|
        $paymentMethodName = 'purchaseorder';
 | 
						|
        $poNumber = '12345678';
 | 
						|
        $quote = $this->getQuoteByReservedOrderId->execute('test_order_1');
 | 
						|
        $quote->getPayment()->setPoNumber($poNumber);
 | 
						|
        $quote->collectTotals()->save();
 | 
						|
        $orderId = $this->cartManagement->placeOrder($quote->getId());
 | 
						|
        $order = $this->orderRepository->get($orderId);
 | 
						|
        $orderItems = $order->getItems();
 | 
						|
        $this->assertCount(1, $orderItems);
 | 
						|
        $payment = $order->getPayment();
 | 
						|
        $this->assertEquals($paymentMethodName, $payment->getMethod());
 | 
						|
        $this->assertEquals($poNumber, $payment->getPoNumber());
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Creates order with purchase_order payment method without po_number
 | 
						|
     *
 | 
						|
     * @magentoAppIsolation enabled
 | 
						|
     * @magentoDataFixture Magento/Sales/_files/quote_with_purchase_order.php
 | 
						|
     *
 | 
						|
     * @return void
 | 
						|
     * @throws CouldNotSaveException
 | 
						|
     */
 | 
						|
    public function testSubmitWithPurchaseOrderWithException(): void
 | 
						|
    {
 | 
						|
        $this->expectException(LocalizedException::class);
 | 
						|
        $this->expectExceptionMessage('Purchase order number is a required field.');
 | 
						|
 | 
						|
        $quote = $this->getQuoteByReservedOrderId->execute('test_order_1');
 | 
						|
        $this->cartManagement->placeOrder($quote->getId());
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Tries to create order with product that has child items and one of them was deleted.
 | 
						|
     *
 | 
						|
     * @magentoConfigFixture cataloginventory/options/enable_inventory_check 1
 | 
						|
     * @magentoAppArea adminhtml
 | 
						|
     * @magentoAppIsolation enabled
 | 
						|
     * @magentoDataFixture Magento/Sales/_files/quote_with_bundle.php
 | 
						|
     */
 | 
						|
    public function testSubmitWithDeletedItem(): void
 | 
						|
    {
 | 
						|
        $this->productRepository->deleteById('simple-2');
 | 
						|
        $quote = $this->getQuoteByReservedOrderId->execute('test01');
 | 
						|
        $this->expectExceptionObject(
 | 
						|
            new LocalizedException(__('Some of the products below do not have all the required options.'))
 | 
						|
        );
 | 
						|
        $this->cartManagement->placeOrder($quote->getId());
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Tries to create order with product that has child items and one of them
 | 
						|
     * was deleted when item data check is disabled on quote load.
 | 
						|
     * @magentoConfigFixture cataloginventory/options/enable_inventory_check 0
 | 
						|
     * @magentoAppArea adminhtml
 | 
						|
     * @magentoAppIsolation enabled
 | 
						|
     * @magentoDataFixture Magento/Sales/_files/quote_with_bundle.php
 | 
						|
     */
 | 
						|
    public function testSubmitWithDeletedItemWithDisabledInventoryCheck(): void
 | 
						|
    {
 | 
						|
        $this->productRepository->deleteById('simple-2');
 | 
						|
        $quote = $this->getQuoteByReservedOrderId->execute('test01');
 | 
						|
        $this->cartManagement->placeOrder($quote->getId());
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Tries to create order with item of stock during checkout.
 | 
						|
     * @magentoConfigFixture cataloginventory/options/enable_inventory_check 1
 | 
						|
     * @magentoDataFixture Magento/Sales/_files/quote.php
 | 
						|
     * @magentoDbIsolation enabled
 | 
						|
     */
 | 
						|
    public function testSubmitWithItemOutOfStock(): void
 | 
						|
    {
 | 
						|
        $this->makeProductOutOfStock('simple');
 | 
						|
        $quote = $this->getQuoteByReservedOrderId->execute('test01');
 | 
						|
        $this->expectExceptionObject(new LocalizedException(__('Some of the products are out of stock.')));
 | 
						|
        $this->cartManagement->placeOrder($quote->getId());
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Tries to create order with item of stock during checkout
 | 
						|
     * when item data check is disabled on quote load.
 | 
						|
     * @magentoConfigFixture cataloginventory/options/enable_inventory_check 0
 | 
						|
     * @magentoDataFixture Magento/Sales/_files/quote.php
 | 
						|
     * @magentoDbIsolation enabled
 | 
						|
     */
 | 
						|
    public function testSubmitWithItemOutOfStockWithDisabledInventoryCheck(): void
 | 
						|
    {
 | 
						|
        $this->makeProductOutOfStock('simple');
 | 
						|
        $quote = $this->getQuoteByReservedOrderId->execute('test01');
 | 
						|
        $this->expectExceptionObject(
 | 
						|
            new LocalizedException(
 | 
						|
                __('The shipping method is missing. Select the shipping method and try again.')
 | 
						|
            )
 | 
						|
        );
 | 
						|
        $this->cartManagement->placeOrder($quote->getId());
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Tries to create an order using quote with empty customer email.
 | 
						|
     *
 | 
						|
     * Order should not start placing if order validation is failed.
 | 
						|
     *
 | 
						|
     * @magentoDataFixture Magento/Quote/Fixtures/quote_without_customer_email.php
 | 
						|
     *
 | 
						|
     * @return void
 | 
						|
     */
 | 
						|
    public function testSubmitWithEmptyCustomerEmail(): void
 | 
						|
    {
 | 
						|
        $quote = $this->getQuoteByReservedOrderId->execute('test01');
 | 
						|
        $orderManagement = $this->createMock(OrderManagementInterface::class);
 | 
						|
        $orderManagement->expects($this->never())
 | 
						|
            ->method('place');
 | 
						|
        $cartManagement = $this->objectManager->create(
 | 
						|
            CartManagementInterface::class,
 | 
						|
            ['orderManagement' => $orderManagement]
 | 
						|
        );
 | 
						|
        $this->expectExceptionObject(new LocalizedException(__('Email has a wrong format')));
 | 
						|
        try {
 | 
						|
            $cartManagement->placeOrder($quote->getId());
 | 
						|
        } catch (ExpectationFailedException $e) {
 | 
						|
            $this->fail('Place order method was not expected to be called if order validation is failed');
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @magentoDataFixture Magento/Checkout/_files/quote_with_simple_product_saved.php
 | 
						|
     * @magentoDataFixture Magento/Customer/_files/customer.php
 | 
						|
     *
 | 
						|
     * @return void
 | 
						|
     */
 | 
						|
    public function testAssignCustomerToQuote(): void
 | 
						|
    {
 | 
						|
        $customer = $this->customerRepository->get('customer@example.com');
 | 
						|
        $quote = $this->getQuoteByReservedOrderId->execute('test_order_with_simple_product_without_address');
 | 
						|
        $result = $this->cartManagement->assignCustomer($quote->getId(), $customer->getId(), $customer->getStoreId());
 | 
						|
        $this->assertTrue($result);
 | 
						|
        $customerQuote = $this->cartManagement->getCartForCustomer($customer->getId());
 | 
						|
        $this->assertEquals($quote->getId(), $customerQuote->getId());
 | 
						|
        $this->assertEquals($customer->getId(), $customerQuote->getCustomerId());
 | 
						|
        $this->assertEquals($customer->getEmail(), $customerQuote->getCustomerEmail());
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @magentoDataFixture Magento/Checkout/_files/quote_with_simple_product_saved.php
 | 
						|
     * @magentoDataFixture Magento/Customer/_files/customer_for_second_website.php
 | 
						|
     *
 | 
						|
     * @return void
 | 
						|
     */
 | 
						|
    public function testAssignCustomerFromAnotherWebsiteToQuote(): void
 | 
						|
    {
 | 
						|
        $websiteId = $this->storeManager->getWebsite('test')->getId();
 | 
						|
        $customer = $this->customerRepository->get('customer@example.com', $websiteId);
 | 
						|
        $quote = $this->getQuoteByReservedOrderId->execute('test_order_with_simple_product_without_address');
 | 
						|
        $this->expectExceptionObject(
 | 
						|
            new StateException(
 | 
						|
                __('The customer can\'t be assigned to the cart. The cart belongs to a different store.')
 | 
						|
            )
 | 
						|
        );
 | 
						|
        $this->cartManagement->assignCustomer($quote->getId(), $customer->getId(), $quote->getStoreId());
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @magentoDataFixture Magento/Checkout/_files/quote_with_customer_without_address.php
 | 
						|
     * @magentoDataFixture Magento/Customer/_files/customer_with_uk_address.php
 | 
						|
     *
 | 
						|
     * @return void
 | 
						|
     */
 | 
						|
    public function testAssignCustomerToQuoteAlreadyHaveCustomer(): void
 | 
						|
    {
 | 
						|
        $customer = $this->customerRepository->get('customer_uk_address@test.com');
 | 
						|
        $quote = $this->getQuoteByReservedOrderId->execute('test_order_with_customer_without_address');
 | 
						|
        $this->expectExceptionObject(
 | 
						|
            new StateException(__('The customer can\'t be assigned to the cart because the cart isn\'t anonymous.'))
 | 
						|
        );
 | 
						|
        $this->cartManagement->assignCustomer($quote->getId(), $customer->getId(), $quote->getStoreId());
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Makes provided product as out of stock.
 | 
						|
     *
 | 
						|
     * @param string $sku
 | 
						|
     * @return void
 | 
						|
     */
 | 
						|
    private function makeProductOutOfStock(string $sku): void
 | 
						|
    {
 | 
						|
        $product = $this->productRepository->get($sku);
 | 
						|
        $extensionAttributes = $product->getExtensionAttributes();
 | 
						|
        $stockItem = $extensionAttributes->getStockItem();
 | 
						|
        $stockItem->setIsInStock(false);
 | 
						|
        $this->productRepository->save($product);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Makes customer vat validator 'check vat number' response successful.
 | 
						|
     *
 | 
						|
     * @return void
 | 
						|
     */
 | 
						|
    private function mockVatValidation(): void
 | 
						|
    {
 | 
						|
        $vatMock = $this->getMockBuilder(Vat::class)
 | 
						|
            ->setConstructorArgs(
 | 
						|
                [
 | 
						|
                    'scopeConfig' => $this->objectManager->get(ScopeConfigInterface::class),
 | 
						|
                    'logger' => $this->objectManager->get(LoggerInterface::class),
 | 
						|
                ]
 | 
						|
            )
 | 
						|
            ->onlyMethods(['checkVatNumber'])
 | 
						|
            ->getMock();
 | 
						|
        $gatewayResponse = new DataObject([
 | 
						|
            'is_valid' => true,
 | 
						|
            'request_date' => 'testData',
 | 
						|
            'request_identifier' => 'testRequestIdentifier',
 | 
						|
            'request_success' => true,
 | 
						|
        ]);
 | 
						|
        $vatMock->method('checkVatNumber')->willReturn($gatewayResponse);
 | 
						|
        $this->objectManager->removeSharedInstance(CollectTotalsObserver::class);
 | 
						|
        $this->objectManager->removeSharedInstance(VatValidator::class);
 | 
						|
        $this->objectManager->removeSharedInstance(Vat::class);
 | 
						|
        $this->objectManager->addSharedInstance($vatMock, Vat::class);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Creates order with purchase_order payment method
 | 
						|
     *
 | 
						|
     * @magentoDataFixture Magento/Sales/_files/quote_with_customer.php
 | 
						|
     * @magentoDbIsolation disabled
 | 
						|
     * @return void
 | 
						|
     * @throws CouldNotSaveException
 | 
						|
     */
 | 
						|
    public function testCustomerAddressIdAfterPlacingOrder(): void
 | 
						|
    {
 | 
						|
        $quote = $this->getQuoteByReservedOrderId->execute('test01');
 | 
						|
        $quote->getBillingAddress()->setSaveInAddressBook(null);
 | 
						|
        $quote->getBillingAddress()->setCustomerAddressId(null);
 | 
						|
 | 
						|
        $this->address->setFirstname($quote->getBillingAddress()->getFirstname());
 | 
						|
        $this->address->setLastname($quote->getBillingAddress()->getLastname());
 | 
						|
        $this->address->setCity($quote->getBillingAddress()->getCity());
 | 
						|
        $this->address->setCompany($quote->getBillingAddress()->getCompany());
 | 
						|
        $this->address->setCountryId($quote->getBillingAddress()->getCountryId());
 | 
						|
        $this->address->setRegionId($quote->getBillingAddress()->getRegionId());
 | 
						|
        $this->address->setCustomerId($quote->getBillingAddress()->getCustomerId());
 | 
						|
        $this->address->setPostcode($quote->getBillingAddress()->getPostcode());
 | 
						|
        $this->address->setTelephone($quote->getBillingAddress()->getTelephone());
 | 
						|
        $this->address->setStreet($quote->getBillingAddress()->getStreet());
 | 
						|
        $this->address->setSameAsBilling($quote->getBillingAddress()->getSameAsBilling());
 | 
						|
        $this->address->setCustomerAddressId($quote->getBillingAddress()->getCustomerAddressId());
 | 
						|
        $this->address->setSaveInAddressBook($quote->getBillingAddress()->getSaveInAddressBook());
 | 
						|
 | 
						|
        $quote->getShippingAddress()
 | 
						|
            ->setShippingMethod('flatrate_flatrate')
 | 
						|
            ->setCollectShippingRates(true);
 | 
						|
        $quote->getShippingAddress()->setSameAsBilling(1);
 | 
						|
        $quote->getShippingAddress()->setSaveInAddressBook(1);
 | 
						|
        $this->payment->setMethod('checkmo');
 | 
						|
        $quote->save();
 | 
						|
        $orderId = $this->paymentManagement->savePaymentInformationAndPlaceOrder(
 | 
						|
            $quote->getId(),
 | 
						|
            $this->payment,
 | 
						|
            $this->address
 | 
						|
        );
 | 
						|
        $order = $this->orderRepository->get($orderId);
 | 
						|
        $billingAddress = $order->getBillingAddress();
 | 
						|
        $shippingAddress = $order->getShippingAddress();
 | 
						|
        $this->assertNotNull($billingAddress->getCustomerAddressId());
 | 
						|
        $this->assertNotNull($shippingAddress->getCustomerAddressId());
 | 
						|
        $this->assertEquals($billingAddress->getCustomerAddressId(), $shippingAddress->getCustomerAddressId());
 | 
						|
    }
 | 
						|
}
 |