Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
QuoteManagement.php
Go to the documentation of this file.
1 <?php
7 namespace Magento\Quote\Model;
8 
16 use Magento\Quote\Model\Quote\Address\ToOrder as ToOrderConverter;
17 use Magento\Quote\Model\Quote\Address\ToOrderAddress as ToOrderAddressConverter;
19 use Magento\Quote\Model\Quote\Item\ToOrderItem as ToOrderItemConverter;
20 use Magento\Quote\Model\Quote\Payment\ToOrderPayment as ToOrderPaymentConverter;
21 use Magento\Sales\Api\Data\OrderInterfaceFactory as OrderFactory;
22 use Magento\Sales\Api\OrderManagementInterface as OrderManagement;
24 
32 {
36  protected $eventManager;
37 
41  protected $quoteValidator;
42 
46  protected $orderFactory;
47 
51  protected $orderManagement;
52 
57 
62 
67 
72 
77 
81  protected $userContext;
82 
86  protected $quoteRepository;
87 
92 
97 
102 
106  protected $dataObjectHelper;
107 
111  protected $storeManager;
112 
116  protected $checkoutSession;
117 
121  protected $customerSession;
122 
127 
131  protected $quoteFactory;
132 
136  private $quoteIdMaskFactory;
137 
141  private $addressRepository;
142 
146  private $addressesToSync = [];
147 
173  public function __construct(
174  EventManager $eventManager,
176  OrderFactory $orderFactory,
177  OrderManagement $orderManagement,
179  ToOrderConverter $quoteAddressToOrder,
180  ToOrderAddressConverter $quoteAddressToOrderAddress,
181  ToOrderItemConverter $quoteItemToOrderItem,
182  ToOrderPaymentConverter $quotePaymentToOrderPayment,
186  \Magento\Customer\Model\CustomerFactory $customerModelFactory,
187  \Magento\Quote\Model\Quote\AddressFactory $quoteAddressFactory,
188  \Magento\Framework\Api\DataObjectHelper $dataObjectHelper,
190  \Magento\Checkout\Model\Session $checkoutSession,
191  \Magento\Customer\Model\Session $customerSession,
192  \Magento\Customer\Api\AccountManagementInterface $accountManagement,
193  \Magento\Quote\Model\QuoteFactory $quoteFactory,
194  \Magento\Quote\Model\QuoteIdMaskFactory $quoteIdMaskFactory = null,
195  \Magento\Customer\Api\AddressRepositoryInterface $addressRepository = null
196  ) {
197  $this->eventManager = $eventManager;
198  $this->quoteValidator = $quoteValidator;
199  $this->orderFactory = $orderFactory;
200  $this->orderManagement = $orderManagement;
201  $this->customerManagement = $customerManagement;
202  $this->quoteAddressToOrder = $quoteAddressToOrder;
203  $this->quoteAddressToOrderAddress = $quoteAddressToOrderAddress;
204  $this->quoteItemToOrderItem = $quoteItemToOrderItem;
205  $this->quotePaymentToOrderPayment = $quotePaymentToOrderPayment;
206  $this->userContext = $userContext;
207  $this->quoteRepository = $quoteRepository;
208  $this->customerRepository = $customerRepository;
209  $this->customerModelFactory = $customerModelFactory;
210  $this->quoteAddressFactory = $quoteAddressFactory;
211  $this->dataObjectHelper = $dataObjectHelper;
212  $this->storeManager = $storeManager;
213  $this->checkoutSession = $checkoutSession;
214  $this->accountManagement = $accountManagement;
215  $this->customerSession = $customerSession;
216  $this->quoteFactory = $quoteFactory;
217  $this->quoteIdMaskFactory = $quoteIdMaskFactory ?: ObjectManager::getInstance()
218  ->get(\Magento\Quote\Model\QuoteIdMaskFactory::class);
219  $this->addressRepository = $addressRepository ?: ObjectManager::getInstance()
220  ->get(\Magento\Customer\Api\AddressRepositoryInterface::class);
221  }
222 
226  public function createEmptyCart()
227  {
228  $storeId = $this->storeManager->getStore()->getStoreId();
229  $quote = $this->createAnonymousCart($storeId);
230 
231  $quote->setBillingAddress($this->quoteAddressFactory->create());
232  $quote->setShippingAddress($this->quoteAddressFactory->create());
233 
234  try {
235  $quote->getShippingAddress()->setCollectShippingRates(true);
236  $this->quoteRepository->save($quote);
237  } catch (\Exception $e) {
238  throw new CouldNotSaveException(__("The quote can't be created."));
239  }
240  return $quote->getId();
241  }
242 
247  {
248  $storeId = $this->storeManager->getStore()->getStoreId();
249  $quote = $this->createCustomerCart($customerId, $storeId);
250 
251  try {
252  $this->quoteRepository->save($quote);
253  } catch (\Exception $e) {
254  throw new CouldNotSaveException(__("The quote can't be created."));
255  }
256  return (int)$quote->getId();
257  }
258 
262  public function assignCustomer($cartId, $customerId, $storeId)
263  {
264  $quote = $this->quoteRepository->getActive($cartId);
265  $customer = $this->customerRepository->getById($customerId);
266  $customerModel = $this->customerModelFactory->create();
267 
268  if (!in_array($storeId, $customerModel->load($customerId)->getSharedStoreIds())) {
269  throw new StateException(
270  __("The customer can't be assigned to the cart. The cart belongs to a different store.")
271  );
272  }
273  if ($quote->getCustomerId()) {
274  throw new StateException(
275  __("The customer can't be assigned to the cart because the cart isn't anonymous.")
276  );
277  }
278  try {
279  $this->quoteRepository->getForCustomer($customerId);
280  throw new StateException(
281  __("The customer can't be assigned to the cart because the customer already has an active cart.")
282  );
283  } catch (\Magento\Framework\Exception\NoSuchEntityException $e) {
284  }
285 
286  $quote->setCustomer($customer);
287  $quote->setCustomerIsGuest(0);
289  $quoteIdMask = $this->quoteIdMaskFactory->create()->load($cartId, 'quote_id');
290  if ($quoteIdMask->getId()) {
291  $quoteIdMask->delete();
292  }
293  $this->quoteRepository->save($quote);
294  return true;
295  }
296 
303  protected function createAnonymousCart($storeId)
304  {
306  $quote = $this->quoteFactory->create();
307  $quote->setStoreId($storeId);
308  return $quote;
309  }
310 
319  protected function createCustomerCart($customerId, $storeId)
320  {
321  try {
322  $quote = $this->quoteRepository->getActiveForCustomer($customerId);
323  } catch (\Magento\Framework\Exception\NoSuchEntityException $e) {
324  $customer = $this->customerRepository->getById($customerId);
326  $quote = $this->quoteFactory->create();
327  $quote->setStoreId($storeId);
328  $quote->setCustomer($customer);
329  $quote->setCustomerIsGuest(0);
330  }
331  return $quote;
332  }
333 
337  public function placeOrder($cartId, PaymentInterface $paymentMethod = null)
338  {
339  $quote = $this->quoteRepository->getActive($cartId);
340  if ($paymentMethod) {
341  $paymentMethod->setChecks([
342  \Magento\Payment\Model\Method\AbstractMethod::CHECK_USE_CHECKOUT,
343  \Magento\Payment\Model\Method\AbstractMethod::CHECK_USE_FOR_COUNTRY,
344  \Magento\Payment\Model\Method\AbstractMethod::CHECK_USE_FOR_CURRENCY,
345  \Magento\Payment\Model\Method\AbstractMethod::CHECK_ORDER_TOTAL_MIN_MAX,
346  \Magento\Payment\Model\Method\AbstractMethod::CHECK_ZERO_TOTAL,
347  ]);
348  $quote->getPayment()->setQuote($quote);
349 
350  $data = $paymentMethod->getData();
351  $quote->getPayment()->importData($data);
352  }
353 
354  if ($quote->getCheckoutMethod() === self::METHOD_GUEST) {
355  $quote->setCustomerId(null);
356  $quote->setCustomerEmail($quote->getBillingAddress()->getEmail());
357  $quote->setCustomerIsGuest(true);
358  $quote->setCustomerGroupId(\Magento\Customer\Api\Data\GroupInterface::NOT_LOGGED_IN_ID);
359  }
360 
361  $this->eventManager->dispatch('checkout_submit_before', ['quote' => $quote]);
362 
363  $order = $this->submit($quote);
364 
365  if (null == $order) {
366  throw new LocalizedException(
367  __('A server error stopped your order from being placed. Please try to place your order again.')
368  );
369  }
370 
371  $this->checkoutSession->setLastQuoteId($quote->getId());
372  $this->checkoutSession->setLastSuccessQuoteId($quote->getId());
373  $this->checkoutSession->setLastOrderId($order->getId());
374  $this->checkoutSession->setLastRealOrderId($order->getIncrementId());
375  $this->checkoutSession->setLastOrderStatus($order->getStatus());
376 
377  $this->eventManager->dispatch('checkout_submit_all_after', ['order' => $order, 'quote' => $quote]);
378  return $order->getId();
379  }
380 
385  {
386  return $this->quoteRepository->getActiveForCustomer($customerId);
387  }
388 
398  public function submit(QuoteEntity $quote, $orderData = [])
399  {
400  if (!$quote->getAllVisibleItems()) {
401  $quote->setIsActive(false);
402  return null;
403  }
404 
405  return $this->submitQuote($quote, $orderData);
406  }
407 
412  protected function resolveItems(QuoteEntity $quote)
413  {
414  $orderItems = [];
415  foreach ($quote->getAllItems() as $quoteItem) {
416  $itemId = $quoteItem->getId();
417 
418  if (!empty($orderItems[$itemId])) {
419  continue;
420  }
421 
422  $parentItemId = $quoteItem->getParentItemId();
424  if ($parentItemId && !isset($orderItems[$parentItemId])) {
425  $orderItems[$parentItemId] = $this->quoteItemToOrderItem->convert(
426  $quoteItem->getParentItem(),
427  ['parent_item' => null]
428  );
429  }
430  $parentItem = isset($orderItems[$parentItemId]) ? $orderItems[$parentItemId] : null;
431  $orderItems[$itemId] = $this->quoteItemToOrderItem->convert($quoteItem, ['parent_item' => $parentItem]);
432  }
433  return array_values($orderItems);
434  }
435 
445  protected function submitQuote(QuoteEntity $quote, $orderData = [])
446  {
447  $order = $this->orderFactory->create();
448  $this->quoteValidator->validateBeforeSubmit($quote);
449  if (!$quote->getCustomerIsGuest()) {
450  if ($quote->getCustomerId()) {
451  $this->_prepareCustomerQuote($quote);
452  $this->customerManagement->validateAddresses($quote);
453  }
454  $this->customerManagement->populateCustomerInfo($quote);
455  }
456  $addresses = [];
457  $quote->reserveOrderId();
458  if ($quote->isVirtual()) {
459  $this->dataObjectHelper->mergeDataObjects(
460  \Magento\Sales\Api\Data\OrderInterface::class,
461  $order,
462  $this->quoteAddressToOrder->convert($quote->getBillingAddress(), $orderData)
463  );
464  } else {
465  $this->dataObjectHelper->mergeDataObjects(
466  \Magento\Sales\Api\Data\OrderInterface::class,
467  $order,
468  $this->quoteAddressToOrder->convert($quote->getShippingAddress(), $orderData)
469  );
470  $shippingAddress = $this->quoteAddressToOrderAddress->convert(
471  $quote->getShippingAddress(),
472  [
473  'address_type' => 'shipping',
474  'email' => $quote->getCustomerEmail()
475  ]
476  );
477  $shippingAddress->setData('quote_address_id', $quote->getShippingAddress()->getId());
479  $order->setShippingAddress($shippingAddress);
480  $order->setShippingMethod($quote->getShippingAddress()->getShippingMethod());
481  }
482  $billingAddress = $this->quoteAddressToOrderAddress->convert(
483  $quote->getBillingAddress(),
484  [
485  'address_type' => 'billing',
486  'email' => $quote->getCustomerEmail()
487  ]
488  );
489  $billingAddress->setData('quote_address_id', $quote->getBillingAddress()->getId());
491  $order->setBillingAddress($billingAddress);
492  $order->setAddresses($addresses);
493  $order->setPayment($this->quotePaymentToOrderPayment->convert($quote->getPayment()));
494  $order->setItems($this->resolveItems($quote));
495  if ($quote->getCustomer()) {
496  $order->setCustomerId($quote->getCustomer()->getId());
497  }
498  $order->setQuoteId($quote->getId());
499  $order->setCustomerEmail($quote->getCustomerEmail());
500  $order->setCustomerFirstname($quote->getCustomerFirstname());
501  $order->setCustomerMiddlename($quote->getCustomerMiddlename());
502  $order->setCustomerLastname($quote->getCustomerLastname());
503 
504  $this->eventManager->dispatch(
505  'sales_model_service_quote_submit_before',
506  [
507  'order' => $order,
508  'quote' => $quote
509  ]
510  );
511  try {
512  $order = $this->orderManagement->place($order);
513  $quote->setIsActive(false);
514  $this->eventManager->dispatch(
515  'sales_model_service_quote_submit_success',
516  [
517  'order' => $order,
518  'quote' => $quote
519  ]
520  );
521  $this->quoteRepository->save($quote);
522  } catch (\Exception $e) {
523  if (!empty($this->addressesToSync)) {
524  foreach ($this->addressesToSync as $addressId) {
525  $this->addressRepository->deleteById($addressId);
526  }
527  }
528  $this->eventManager->dispatch(
529  'sales_model_service_quote_submit_failure',
530  [
531  'order' => $order,
532  'quote' => $quote,
533  'exception' => $e
534  ]
535  );
536  throw $e;
537  }
538  return $order;
539  }
540 
549  protected function _prepareCustomerQuote($quote)
550  {
552  $billing = $quote->getBillingAddress();
553  $shipping = $quote->isVirtual() ? null : $quote->getShippingAddress();
554 
555  $customer = $this->customerRepository->getById($quote->getCustomerId());
556  $hasDefaultBilling = (bool)$customer->getDefaultBilling();
557  $hasDefaultShipping = (bool)$customer->getDefaultShipping();
558 
559  if ($shipping && !$shipping->getSameAsBilling()
560  && (!$shipping->getCustomerId() || $shipping->getSaveInAddressBook())
561  ) {
562  $shippingAddress = $shipping->exportCustomerAddress();
563  if (!$hasDefaultShipping) {
564  //Make provided address as default shipping address
565  $shippingAddress->setIsDefaultShipping(true);
566  $hasDefaultShipping = true;
567  if (!$hasDefaultBilling && !$billing->getSaveInAddressBook()) {
568  $shippingAddress->setIsDefaultBilling(true);
569  $hasDefaultBilling = true;
570  }
571  }
572  //save here new customer address
573  $shippingAddress->setCustomerId($quote->getCustomerId());
574  $this->addressRepository->save($shippingAddress);
575  $quote->addCustomerAddress($shippingAddress);
576  $shipping->setCustomerAddressData($shippingAddress);
577  $this->addressesToSync[] = $shippingAddress->getId();
578  $shipping->setCustomerAddressId($shippingAddress->getId());
579  }
580 
581  if (!$billing->getCustomerId() || $billing->getSaveInAddressBook()) {
582  $billingAddress = $billing->exportCustomerAddress();
583  if (!$hasDefaultBilling) {
584  //Make provided address as default shipping address
585  if (!$hasDefaultShipping) {
586  //Make provided address as default shipping address
587  $billingAddress->setIsDefaultShipping(true);
588  }
589  $billingAddress->setIsDefaultBilling(true);
590  }
591  $billingAddress->setCustomerId($quote->getCustomerId());
592  $this->addressRepository->save($billingAddress);
593  $quote->addCustomerAddress($billingAddress);
594  $billing->setCustomerAddressData($billingAddress);
595  $this->addressesToSync[] = $billingAddress->getId();
596  $billing->setCustomerAddressId($billingAddress->getId());
597  }
598  if ($shipping && !$shipping->getCustomerId() && !$hasDefaultBilling) {
599  $shipping->setIsDefaultBilling(true);
600  }
601  }
602 }
$billingAddress
Definition: order.php:25
$customer
Definition: customers.php:11
$addresses
Definition: address_list.php:7
$quote
$shippingAddress
Definition: order.php:40
$order
Definition: order.php:55
__()
Definition: __.php:13
submit(QuoteEntity $quote, $orderData=[])
assignCustomer($cartId, $customerId, $storeId)
placeOrder($cartId, PaymentInterface $paymentMethod=null)
__construct(EventManager $eventManager, QuoteValidator $quoteValidator, OrderFactory $orderFactory, OrderManagement $orderManagement, CustomerManagement $customerManagement, ToOrderConverter $quoteAddressToOrder, ToOrderAddressConverter $quoteAddressToOrderAddress, ToOrderItemConverter $quoteItemToOrderItem, ToOrderPaymentConverter $quotePaymentToOrderPayment, UserContextInterface $userContext, \Magento\Quote\Api\CartRepositoryInterface $quoteRepository, \Magento\Customer\Api\CustomerRepositoryInterface $customerRepository, \Magento\Customer\Model\CustomerFactory $customerModelFactory, \Magento\Quote\Model\Quote\AddressFactory $quoteAddressFactory, \Magento\Framework\Api\DataObjectHelper $dataObjectHelper, StoreManagerInterface $storeManager, \Magento\Checkout\Model\Session $checkoutSession, \Magento\Customer\Model\Session $customerSession, \Magento\Customer\Api\AccountManagementInterface $accountManagement, \Magento\Quote\Model\QuoteFactory $quoteFactory, \Magento\Quote\Model\QuoteIdMaskFactory $quoteIdMaskFactory=null, \Magento\Customer\Api\AddressRepositoryInterface $addressRepository=null)
$cartId
Definition: quote.php:22
$quoteItem
Definition: quote.php:38
submitQuote(QuoteEntity $quote, $orderData=[])