![]() Server : Apache System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64 User : corals ( 1002) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /home/corals/cartforge.co/vendor/magento/module-quote/Model/ |
<?php /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ declare(strict_types=1); namespace Magento\Quote\Model; use Magento\Authorization\Model\UserContextInterface; use Magento\Checkout\Model\Session as CheckoutSession; use Magento\Customer\Api\AccountManagementInterface; use Magento\Customer\Api\AddressRepositoryInterface; use Magento\Customer\Api\CustomerRepositoryInterface; use Magento\Customer\Api\Data\GroupInterface; use Magento\Customer\Model\CustomerFactory; use Magento\Customer\Model\Session as CustomerSession; use Magento\Framework\Api\DataObjectHelper; use Magento\Framework\App\ObjectManager; use Magento\Framework\App\RequestInterface; use Magento\Framework\Event\ManagerInterface as EventManager; use Magento\Framework\Exception\CouldNotSaveException; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\Exception\StateException; use Magento\Framework\HTTP\PhpEnvironment\RemoteAddress; use Magento\Framework\Lock\LockManagerInterface; use Magento\Framework\Model\AbstractExtensibleModel; use Magento\Framework\Validator\Exception as ValidatorException; use Magento\Payment\Model\Method\AbstractMethod; use Magento\Quote\Api\CartManagementInterface; use Magento\Quote\Api\CartRepositoryInterface; use Magento\Quote\Api\Data\PaymentInterface; use Magento\Quote\Model\Quote\Address\ToOrder as ToOrderConverter; use Magento\Quote\Model\Quote\Address\ToOrderAddress as ToOrderAddressConverter; use Magento\Quote\Model\Quote\AddressFactory; use Magento\Quote\Model\Quote as QuoteEntity; use Magento\Quote\Model\Quote\Item\ToOrderItem as ToOrderItemConverter; use Magento\Quote\Model\Quote\Payment\ToOrderPayment as ToOrderPaymentConverter; use Magento\Quote\Model\ResourceModel\Quote\Item; use Magento\Sales\Api\Data\OrderInterface; use Magento\Sales\Api\Data\OrderInterfaceFactory as OrderFactory; use Magento\Sales\Api\OrderManagementInterface as OrderManagement; use Magento\Store\Model\StoreManagerInterface; /** * Class for managing quote * * @SuppressWarnings(PHPMD.CookieAndSessionMisuse) * @SuppressWarnings(PHPMD.CouplingBetweenObjects) * @SuppressWarnings(PHPMD.TooManyFields) */ class QuoteManagement implements CartManagementInterface { private const LOCK_PREFIX = 'PLACE_ORDER_'; private const LOCK_TIMEOUT = 10; /** * @var EventManager */ protected $eventManager; /** * @var SubmitQuoteValidator */ private $submitQuoteValidator; /** * @var OrderFactory */ protected $orderFactory; /** * @var OrderManagement */ protected $orderManagement; /** * @var CustomerManagement */ protected $customerManagement; /** * @var ToOrderConverter */ protected $quoteAddressToOrder; /** * @var ToOrderAddressConverter */ protected $quoteAddressToOrderAddress; /** * @var ToOrderItemConverter */ protected $quoteItemToOrderItem; /** * @var ToOrderPaymentConverter */ protected $quotePaymentToOrderPayment; /** * @var UserContextInterface */ protected $userContext; /** * @var CartRepositoryInterface */ protected $quoteRepository; /** * @var CustomerRepositoryInterface */ protected $customerRepository; /** * @var CustomerFactory */ protected $customerModelFactory; /** * @var AddressFactory */ protected $quoteAddressFactory; /** * @var DataObjectHelper */ protected $dataObjectHelper; /** * @var StoreManagerInterface */ protected $storeManager; /** * @var CheckoutSession */ protected $checkoutSession; /** * @var CustomerSession */ protected $customerSession; /** * @var AccountManagementInterface */ protected $accountManagement; /** * @var QuoteFactory */ protected $quoteFactory; /** * @var LockManagerInterface */ private $lockManager; /** * @var QuoteIdMaskFactory */ private $quoteIdMaskFactory; /** * @var AddressRepositoryInterface */ private $addressRepository; /** * @var array */ private $addressesToSync = []; /** * @var RequestInterface */ private $request; /** * @var RemoteAddress */ private $remoteAddress; /** * @param EventManager $eventManager * @param SubmitQuoteValidator $submitQuoteValidator * @param OrderFactory $orderFactory * @param OrderManagement $orderManagement * @param CustomerManagement $customerManagement * @param ToOrderConverter $quoteAddressToOrder * @param ToOrderAddressConverter $quoteAddressToOrderAddress * @param ToOrderItemConverter $quoteItemToOrderItem * @param ToOrderPaymentConverter $quotePaymentToOrderPayment * @param UserContextInterface $userContext * @param CartRepositoryInterface $quoteRepository * @param CustomerRepositoryInterface $customerRepository * @param CustomerFactory $customerModelFactory * @param AddressFactory $quoteAddressFactory * @param DataObjectHelper $dataObjectHelper * @param StoreManagerInterface $storeManager * @param CheckoutSession $checkoutSession * @param CustomerSession $customerSession * @param AccountManagementInterface $accountManagement * @param QuoteFactory $quoteFactory * @param QuoteIdMaskFactory|null $quoteIdMaskFactory * @param AddressRepositoryInterface|null $addressRepository * @param RequestInterface|null $request * @param RemoteAddress $remoteAddress * @param LockManagerInterface $lockManager * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( EventManager $eventManager, SubmitQuoteValidator $submitQuoteValidator, OrderFactory $orderFactory, OrderManagement $orderManagement, CustomerManagement $customerManagement, ToOrderConverter $quoteAddressToOrder, ToOrderAddressConverter $quoteAddressToOrderAddress, ToOrderItemConverter $quoteItemToOrderItem, ToOrderPaymentConverter $quotePaymentToOrderPayment, UserContextInterface $userContext, CartRepositoryInterface $quoteRepository, CustomerRepositoryInterface $customerRepository, CustomerFactory $customerModelFactory, AddressFactory $quoteAddressFactory, DataObjectHelper $dataObjectHelper, StoreManagerInterface $storeManager, CheckoutSession $checkoutSession, CustomerSession $customerSession, AccountManagementInterface $accountManagement, QuoteFactory $quoteFactory, QuoteIdMaskFactory $quoteIdMaskFactory = null, AddressRepositoryInterface $addressRepository = null, RequestInterface $request = null, RemoteAddress $remoteAddress = null, LockManagerInterface $lockManager = null ) { $this->eventManager = $eventManager; $this->submitQuoteValidator = $submitQuoteValidator; $this->orderFactory = $orderFactory; $this->orderManagement = $orderManagement; $this->customerManagement = $customerManagement; $this->quoteAddressToOrder = $quoteAddressToOrder; $this->quoteAddressToOrderAddress = $quoteAddressToOrderAddress; $this->quoteItemToOrderItem = $quoteItemToOrderItem; $this->quotePaymentToOrderPayment = $quotePaymentToOrderPayment; $this->userContext = $userContext; $this->quoteRepository = $quoteRepository; $this->customerRepository = $customerRepository; $this->customerModelFactory = $customerModelFactory; $this->quoteAddressFactory = $quoteAddressFactory; $this->dataObjectHelper = $dataObjectHelper; $this->storeManager = $storeManager; $this->checkoutSession = $checkoutSession; $this->accountManagement = $accountManagement; $this->customerSession = $customerSession; $this->quoteFactory = $quoteFactory; $this->quoteIdMaskFactory = $quoteIdMaskFactory ?: ObjectManager::getInstance() ->get(QuoteIdMaskFactory::class); $this->addressRepository = $addressRepository ?: ObjectManager::getInstance() ->get(AddressRepositoryInterface::class); $this->request = $request ?: ObjectManager::getInstance() ->get(RequestInterface::class); $this->remoteAddress = $remoteAddress ?: ObjectManager::getInstance() ->get(RemoteAddress::class); $this->lockManager = $lockManager ?: ObjectManager::getInstance() ->get(LockManagerInterface::class); } /** * @inheritdoc */ public function createEmptyCart() { $storeId = $this->storeManager->getStore()->getStoreId(); $quote = $this->createAnonymousCart($storeId); $quote->setBillingAddress($this->quoteAddressFactory->create()); $quote->setShippingAddress($this->quoteAddressFactory->create()); $quote->setCustomerIsGuest(1); try { $quote->getShippingAddress()->setCollectShippingRates(true); $this->quoteRepository->save($quote); } catch (\Exception $e) { throw new CouldNotSaveException(__("The quote can't be created.")); } return $quote->getId(); } /** * @inheritdoc */ public function createEmptyCartForCustomer($customerId) { $storeId = $this->storeManager->getStore()->getStoreId(); $quote = $this->createCustomerCart($customerId, $storeId); $this->_prepareCustomerQuote($quote); try { $this->quoteRepository->save($quote); } catch (\Exception $e) { throw new CouldNotSaveException(__("The quote can't be created.")); } return (int)$quote->getId(); } /** * @inheritdoc */ public function assignCustomer($cartId, $customerId, $storeId) { $quote = $this->quoteRepository->getActive($cartId); $customer = $this->customerRepository->getById($customerId); $customerModel = $this->customerModelFactory->create(); if (!in_array($storeId, $customerModel->load($customerId)->getSharedStoreIds())) { throw new StateException( __("The customer can't be assigned to the cart. The cart belongs to a different store.") ); } if ($quote->getCustomerId()) { throw new StateException( __("The customer can't be assigned to the cart because the cart isn't anonymous.") ); } try { $customerActiveQuote = $this->quoteRepository->getForCustomer($customerId); $quote->merge($customerActiveQuote); $customerActiveQuote->setIsActive(0); $this->quoteRepository->save($customerActiveQuote); // phpcs:ignore Magento2.CodeAnalysis.EmptyBlock } catch (NoSuchEntityException $e) { } $quote->setCustomer($customer); $quote->setCustomerIsGuest(0); $quote->setIsActive(1); /** @var QuoteIdMask $quoteIdMask */ $quoteIdMask = $this->quoteIdMaskFactory->create()->load($cartId, 'quote_id'); if ($quoteIdMask->getId()) { $quoteIdMask->delete(); } $this->quoteRepository->save($quote); return true; } /** * Creates an anonymous cart. * * @param int $storeId * @return Quote Cart object. */ protected function createAnonymousCart($storeId) { /** @var Quote $quote */ $quote = $this->quoteFactory->create(); $quote->setStoreId($storeId); return $quote; } /** * Creates a cart for the currently logged-in customer. * * @param int $customerId * @param int $storeId * @return Quote Cart object. * @throws CouldNotSaveException The cart could not be created. */ protected function createCustomerCart($customerId, $storeId) { try { $quote = $this->quoteRepository->getActiveForCustomer($customerId); } catch (NoSuchEntityException $e) { $customer = $this->customerRepository->getById($customerId); /** @var Quote $quote */ $quote = $this->quoteFactory->create(); $quote->setStoreId($storeId); $quote->setCustomer($customer); $quote->setCustomerIsGuest(0); } return $quote; } /** * @inheritdoc * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) */ public function placeOrder($cartId, PaymentInterface $paymentMethod = null) { $quote = $this->quoteRepository->getActive($cartId); $customer = $quote->getCustomer(); $customerId = $customer ? $customer->getId() : null; if ($paymentMethod) { $paymentMethod->setChecks( [ AbstractMethod::CHECK_USE_CHECKOUT, AbstractMethod::CHECK_USE_FOR_COUNTRY, AbstractMethod::CHECK_USE_FOR_CURRENCY, AbstractMethod::CHECK_ORDER_TOTAL_MIN_MAX, AbstractMethod::CHECK_ZERO_TOTAL ] ); $quote->getPayment()->setQuote($quote); $data = $paymentMethod->getData(); $quote->getPayment()->importData($data); } else { $quote->collectTotals(); } if ($quote->getCheckoutMethod() === self::METHOD_GUEST || !$customerId) { $quote->setCustomerId(null); $billingAddress = $quote->getBillingAddress(); if (!$quote->getCustomerEmail()) { $quote->setCustomerEmail($billingAddress ? $billingAddress->getEmail() : null); } if ($quote->getCustomerFirstname() === null && $quote->getCustomerLastname() === null && $billingAddress ) { $quote->setCustomerFirstname($billingAddress->getFirstname()); $quote->setCustomerLastname($billingAddress->getLastname()); if ($billingAddress->getMiddlename() === null) { $quote->setCustomerMiddlename($billingAddress->getMiddlename()); } } $quote->setCustomerIsGuest(true); $quote->setCustomerGroupId( $quote->getCustomerId() ? $customer->getGroupId() : GroupInterface::NOT_LOGGED_IN_ID ); } $remoteAddress = $this->remoteAddress->getRemoteAddress(); if ($remoteAddress !== false) { $quote->setRemoteIp($remoteAddress); $quote->setXForwardedFor( $this->request->getServer('HTTP_X_FORWARDED_FOR') ); } $this->eventManager->dispatch('checkout_submit_before', ['quote' => $quote]); $order = $this->submit($quote); if (null == $order) { throw new LocalizedException( __('A server error stopped your order from being placed. Please try to place your order again.') ); } $this->checkoutSession->setLastQuoteId($quote->getId()); $this->checkoutSession->setLastSuccessQuoteId($quote->getId()); $this->checkoutSession->setLastOrderId($order->getId()); $this->checkoutSession->setLastRealOrderId($order->getIncrementId()); $this->checkoutSession->setLastOrderStatus($order->getStatus()); $this->eventManager->dispatch('checkout_submit_all_after', ['order' => $order, 'quote' => $quote]); return $order->getId(); } /** * @inheritdoc */ public function getCartForCustomer($customerId) { return $this->quoteRepository->getActiveForCustomer($customerId); } /** * Submit quote * * @param Quote $quote * @param array $orderData * @return AbstractExtensibleModel|OrderInterface|object|null * @throws \Exception * @throws LocalizedException */ public function submit(QuoteEntity $quote, $orderData = []) { if (!$quote->getAllVisibleItems()) { $quote->setIsActive(false); return null; } return $this->submitQuote($quote, $orderData); } /** * Convert quote items to order items for quote * * @param Quote $quote * @return array */ protected function resolveItems(QuoteEntity $quote) { $orderItems = []; foreach ($quote->getAllItems() as $quoteItem) { $itemId = $quoteItem->getId(); if (!empty($orderItems[$itemId])) { continue; } $parentItemId = $quoteItem->getParentItemId(); /** @var Item $parentItem */ if ($parentItemId && !isset($orderItems[$parentItemId])) { $orderItems[$parentItemId] = $this->quoteItemToOrderItem->convert( $quoteItem->getParentItem(), ['parent_item' => null] ); } $parentItem = isset($orderItems[$parentItemId]) ? $orderItems[$parentItemId] : null; $orderItems[$itemId] = $this->quoteItemToOrderItem->convert($quoteItem, ['parent_item' => $parentItem]); } return array_values($orderItems); } /** * Submit quote * * @param Quote $quote * @param array $orderData * @return AbstractExtensibleModel|OrderInterface|object * @throws ValidatorException * @throws LocalizedException * @throws \Exception */ protected function submitQuote(QuoteEntity $quote, $orderData = []) { $order = $this->orderFactory->create(); $this->submitQuoteValidator->validateQuote($quote); if (!$quote->getCustomerIsGuest()) { if ($quote->getCustomerId()) { $this->_prepareCustomerQuote($quote); $this->customerManagement->validateAddresses($quote); } $this->customerManagement->populateCustomerInfo($quote); } $addresses = []; $quote->reserveOrderId(); if ($quote->isVirtual()) { $this->dataObjectHelper->mergeDataObjects( OrderInterface::class, $order, $this->quoteAddressToOrder->convert($quote->getBillingAddress(), $orderData) ); } else { $this->dataObjectHelper->mergeDataObjects( OrderInterface::class, $order, $this->quoteAddressToOrder->convert($quote->getShippingAddress(), $orderData) ); $shippingAddress = $this->quoteAddressToOrderAddress->convert( $quote->getShippingAddress(), [ 'address_type' => 'shipping', 'email' => $quote->getCustomerEmail() ] ); $shippingAddress->setData('quote_address_id', $quote->getShippingAddress()->getId()); $addresses[] = $shippingAddress; $order->setShippingAddress($shippingAddress); $order->setShippingMethod($quote->getShippingAddress()->getShippingMethod()); } $billingAddress = $this->quoteAddressToOrderAddress->convert( $quote->getBillingAddress(), [ 'address_type' => 'billing', 'email' => $quote->getCustomerEmail() ] ); $billingAddress->setData('quote_address_id', $quote->getBillingAddress()->getId()); $addresses[] = $billingAddress; $order->setBillingAddress($billingAddress); $order->setAddresses($addresses); $order->setPayment($this->quotePaymentToOrderPayment->convert($quote->getPayment())); $order->setItems($this->resolveItems($quote)); if ($quote->getCustomer()) { $order->setCustomerId($quote->getCustomer()->getId()); } $order->setQuoteId($quote->getId()); $order->setCustomerEmail($quote->getCustomerEmail()); $order->setCustomerFirstname($quote->getCustomerFirstname()); $order->setCustomerMiddlename($quote->getCustomerMiddlename()); $order->setCustomerLastname($quote->getCustomerLastname()); if ($quote->getOrigOrderId()) { $order->setEntityId($quote->getOrigOrderId()); } if ($quote->getReservedOrderId()) { $order->setIncrementId($quote->getReservedOrderId()); } $this->submitQuoteValidator->validateOrder($order); $this->eventManager->dispatch( 'sales_model_service_quote_submit_before', [ 'order' => $order, 'quote' => $quote ] ); $lockedName = self::LOCK_PREFIX . $quote->getId(); if ($this->lockManager->isLocked($lockedName)) { throw new LocalizedException(__( 'A server error stopped your order from being placed. Please try to place your order again.' )); } try { $this->lockManager->lock($lockedName, self::LOCK_TIMEOUT); $order = $this->orderManagement->place($order); $quote->setIsActive(false); $this->eventManager->dispatch( 'sales_model_service_quote_submit_success', [ 'order' => $order, 'quote' => $quote ] ); $this->quoteRepository->save($quote); $this->lockManager->unlock($lockedName); } catch (\Exception $e) { $this->lockManager->unlock($lockedName); $this->rollbackAddresses($quote, $order, $e); throw $e; } return $order; } /** * Prepare address for customer quote. * * @param Quote $quote * @return void * @throws LocalizedException * @throws NoSuchEntityException * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) */ protected function _prepareCustomerQuote($quote) { $billing = $quote->getBillingAddress(); $shipping = $quote->isVirtual() ? null : $quote->getShippingAddress(); $customer = $this->customerRepository->getById($quote->getCustomerId()); $hasDefaultBilling = (bool)$customer->getDefaultBilling(); $hasDefaultShipping = (bool)$customer->getDefaultShipping(); if ($shipping && !$shipping->getSameAsBilling() && (!$shipping->getCustomerId() || $shipping->getSaveInAddressBook()) ) { if ($shipping->getQuoteId()) { $shippingAddress = $shipping->exportCustomerAddress(); } else { $defaultShipping = $this->customerRepository->getById($customer->getId())->getDefaultShipping(); if ($defaultShipping) { try { $shippingAddress = $this->addressRepository->getById($defaultShipping); // phpcs:ignore Magento2.CodeAnalysis.EmptyBlock } catch (LocalizedException $e) { // no address } } } if (isset($shippingAddress)) { if (!$hasDefaultShipping) { //Make provided address as default shipping address $shippingAddress->setIsDefaultShipping(true); $hasDefaultShipping = true; if (!$hasDefaultBilling && !$billing->getSaveInAddressBook()) { $shippingAddress->setIsDefaultBilling(true); $hasDefaultBilling = true; } } //save here new customer address $shippingAddress->setCustomerId($quote->getCustomerId()); $this->addressRepository->save($shippingAddress); $quote->addCustomerAddress($shippingAddress); $shipping->setCustomerAddressData($shippingAddress); $this->addressesToSync[] = $shippingAddress->getId(); $shipping->setCustomerAddressId($shippingAddress->getId()); } } if (!$billing->getCustomerId() || $billing->getSaveInAddressBook()) { if ($billing->getQuoteId()) { $billingAddress = $billing->exportCustomerAddress(); } else { $defaultBilling = $this->customerRepository->getById($customer->getId())->getDefaultBilling(); if ($defaultBilling) { try { $billingAddress = $this->addressRepository->getById($defaultBilling); // phpcs:ignore Magento2.CodeAnalysis.EmptyBlock } catch (LocalizedException $e) { // no address } } } if (isset($billingAddress)) { if (!$hasDefaultBilling) { //Make provided address as default shipping address if (!$hasDefaultShipping) { //Make provided address as default shipping address $billingAddress->setIsDefaultShipping(true); } $billingAddress->setIsDefaultBilling(true); } $billingAddress->setCustomerId($quote->getCustomerId()); $this->addressRepository->save($billingAddress); $quote->addCustomerAddress($billingAddress); $billing->setCustomerAddressData($billingAddress); $this->addressesToSync[] = $billingAddress->getId(); $billing->setCustomerAddressId($billingAddress->getId()); // Admin order: `Same As Billing Address`- when new billing address saved in address book if ($shipping !== null && !$shipping->getCustomerAddressId() && $shipping->getSameAsBilling()) { $shipping->setCustomerAddressId($billingAddress->getId()); } } } if ($shipping && !$shipping->getCustomerId() && !$hasDefaultBilling) { $shipping->setIsDefaultBilling(true); } } /** * Remove related to order and quote addresses and submit exception to further processing. * * @param Quote $quote * @param OrderInterface $order * @param \Exception $e * @throws \Exception */ private function rollbackAddresses( QuoteEntity $quote, OrderInterface $order, \Exception $e ): void { try { if (!empty($this->addressesToSync)) { foreach ($this->addressesToSync as $addressId) { $this->addressRepository->deleteById($addressId); } } $this->eventManager->dispatch( 'sales_model_service_quote_submit_failure', [ 'order' => $order, 'quote' => $quote, 'exception' => $e, ] ); } catch (\Exception $consecutiveException) { $message = sprintf( "An exception occurred on 'sales_model_service_quote_submit_failure' event: %s", $consecutiveException->getMessage() ); // phpcs:ignore Magento2.Exceptions.DirectThrow throw new \Exception($message, 0, $e); } } }