Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
Checkout.php
Go to the documentation of this file.
1 <?php
6 declare(strict_types=1);
7 
9 
10 use Magento\Customer\Api\Data\CustomerInterface as CustomerDataObject;
13 use Magento\Paypal\Model\Cart as PaypalCart;
17 
25 class Checkout
26 {
32  const PAL_CACHE_ID = 'paypal_express_checkout_pal';
33 
38  const PAYMENT_INFO_TRANSPORT_TOKEN = 'paypal_express_checkout_token';
39  const PAYMENT_INFO_TRANSPORT_SHIPPING_OVERRIDDEN = 'paypal_express_checkout_shipping_overridden';
40  const PAYMENT_INFO_TRANSPORT_SHIPPING_METHOD = 'paypal_express_checkout_shipping_method';
41  const PAYMENT_INFO_TRANSPORT_PAYER_ID = 'paypal_express_checkout_payer_id';
42  const PAYMENT_INFO_TRANSPORT_REDIRECT = 'paypal_express_checkout_redirect_required';
43  const PAYMENT_INFO_TRANSPORT_BILLING_AGREEMENT = 'paypal_ec_create_ba';
44 
50  const PAYMENT_INFO_BUTTON = 'button';
51 
55  protected $_quote;
56 
62  protected $_config;
63 
69  protected $_api;
70 
76  protected $_apiType = \Magento\Paypal\Model\Api\Nvp::class;
77 
83  protected $_methodType = PaypalConfig::METHOD_WPP_EXPRESS;
84 
90  protected $_redirectUrl = '';
91 
97  protected $_pendingPaymentMessage = '';
98 
104  protected $_checkoutRedirectUrl = '';
105 
109  protected $_customerSession;
110 
116  protected $_giropayUrls = [];
117 
123  protected $_isBARequested = false;
124 
130  protected $_isBml = false;
131 
137  protected $_customerId;
138 
145 
151  protected $_order;
152 
156  protected $_configCacheType;
157 
163  protected $_checkoutData;
164 
170  protected $_taxData;
171 
177  protected $_customerUrl;
178 
182  protected $_logger;
183 
187  protected $_localeResolver;
188 
192  protected $_paypalInfo;
193 
197  protected $_storeManager;
198 
202  protected $_coreUrl;
203 
207  protected $_cartFactory;
208 
213 
218 
222  protected $_apiTypeFactory;
223 
228 
232  protected $_checkoutSession;
233 
238 
243 
247  protected $_encryptor;
248 
252  protected $_messageManager;
253 
257  protected $orderSender;
258 
262  protected $quoteRepository;
263 
267  protected $quoteManagement;
268 
272  protected $totalsCollector;
273 
303  public function __construct(
304  \Psr\Log\LoggerInterface $logger,
305  \Magento\Customer\Model\Url $customerUrl,
306  \Magento\Tax\Helper\Data $taxData,
307  \Magento\Checkout\Helper\Data $checkoutData,
308  \Magento\Customer\Model\Session $customerSession,
309  \Magento\Framework\App\Cache\Type\Config $configCacheType,
310  \Magento\Framework\Locale\ResolverInterface $localeResolver,
311  \Magento\Paypal\Model\Info $paypalInfo,
313  \Magento\Framework\UrlInterface $coreUrl,
314  \Magento\Paypal\Model\CartFactory $cartFactory,
315  \Magento\Checkout\Model\Type\OnepageFactory $onepageFactory,
316  \Magento\Quote\Api\CartManagementInterface $quoteManagement,
317  \Magento\Paypal\Model\Billing\AgreementFactory $agreementFactory,
318  \Magento\Paypal\Model\Api\Type\Factory $apiTypeFactory,
319  \Magento\Framework\DataObject\Copy $objectCopyService,
320  \Magento\Checkout\Model\Session $checkoutSession,
321  \Magento\Framework\Encryption\EncryptorInterface $encryptor,
322  \Magento\Framework\Message\ManagerInterface $messageManager,
326  \Magento\Quote\Api\CartRepositoryInterface $quoteRepository,
328  $params = []
329  ) {
330  $this->quoteManagement = $quoteManagement;
331  $this->_customerUrl = $customerUrl;
332  $this->_taxData = $taxData;
333  $this->_checkoutData = $checkoutData;
334  $this->_configCacheType = $configCacheType;
335  $this->_logger = $logger;
336  $this->_localeResolver = $localeResolver;
337  $this->_paypalInfo = $paypalInfo;
338  $this->_storeManager = $storeManager;
339  $this->_coreUrl = $coreUrl;
340  $this->_cartFactory = $cartFactory;
341  $this->_checkoutOnepageFactory = $onepageFactory;
342  $this->_agreementFactory = $agreementFactory;
343  $this->_apiTypeFactory = $apiTypeFactory;
344  $this->_objectCopyService = $objectCopyService;
345  $this->_checkoutSession = $checkoutSession;
346  $this->_customerRepository = $customerRepository;
347  $this->_encryptor = $encryptor;
348  $this->_messageManager = $messageManager;
349  $this->orderSender = $orderSender;
350  $this->_accountManagement = $accountManagement;
351  $this->quoteRepository = $quoteRepository;
352  $this->totalsCollector = $totalsCollector;
353  $this->_customerSession = isset($params['session'])
354  && $params['session'] instanceof \Magento\Customer\Model\Session ? $params['session'] : $customerSession;
355 
356  if (isset($params['config']) && $params['config'] instanceof PaypalConfig) {
357  $this->_config = $params['config'];
358  } else {
359  throw new \Exception('Config instance is required.');
360  }
361 
362  if (isset($params['quote']) && $params['quote'] instanceof \Magento\Quote\Model\Quote) {
363  $this->_quote = $params['quote'];
364  } else {
365  throw new \Exception('Quote instance is required.');
366  }
367  }
368 
376  public function getCheckoutShortcutImageUrl()
377  {
378  // get "pal" thing from cache or lookup it via API
379  $pal = null;
380  if ($this->_config->areButtonsDynamic()) {
381  $cacheId = self::PAL_CACHE_ID . $this->_storeManager->getStore()->getId();
382  $pal = $this->_configCacheType->load($cacheId);
383  if (self::PAL_CACHE_ID == $pal) {
384  $pal = null;
385  } elseif (!$pal) {
386  $pal = null;
387  try {
388  $this->_getApi()->callGetPalDetails();
389  $pal = $this->_getApi()->getPal();
390  $this->_configCacheType->save($pal, $cacheId);
391  } catch (\Exception $e) {
392  $this->_configCacheType->save(self::PAL_CACHE_ID, $cacheId);
393  $this->_logger->critical($e);
394  }
395  }
396  }
397 
398  return $this->_config->getExpressCheckoutShortcutImageUrl(
399  $this->_localeResolver->getLocale(),
400  $this->_quote->getBaseGrandTotal(),
401  $pal
402  );
403  }
404 
413  public function prepareGiropayUrls($successUrl, $cancelUrl, $pendingUrl)
414  {
415  $this->_giropayUrls = [$successUrl, $cancelUrl, $pendingUrl];
416  return $this;
417  }
418 
425  public function setIsBillingAgreementRequested($flag)
426  {
427  $this->_isBARequested = $flag;
428  return $this;
429  }
430 
437  public function setIsBml($isBml)
438  {
439  $this->_isBml = $isBml;
440  return $this;
441  }
442 
449  public function setCustomerData(CustomerDataObject $customerData)
450  {
451  $this->_quote->assignCustomer($customerData);
452  $this->_customerId = $customerData->getId();
453  return $this;
454  }
455 
465  CustomerDataObject $customerData,
466  $billingAddress = null,
467  $shippingAddress = null
468  ) {
469  $this->_quote->assignCustomerWithAddressChange($customerData, $billingAddress, $shippingAddress);
470  $this->_customerId = $customerData->getId();
471  return $this;
472  }
473 
486  public function start($returnUrl, $cancelUrl, $button = null)
487  {
488  $this->_quote->collectTotals();
489 
490  if (!$this->_quote->getGrandTotal()) {
491  throw new \Magento\Framework\Exception\LocalizedException(
492  __(
493  'PayPal can\'t process orders with a zero balance due. '
494  . 'To finish your purchase, please go through the standard checkout process.'
495  )
496  );
497  }
498 
499  $this->_quote->reserveOrderId();
500  $this->quoteRepository->save($this->_quote);
501  // prepare API
502  $solutionType = $this->_config->getMerchantCountry() == 'DE'
504  : $this->_config->getValue('solutionType');
505  $totalAmount = round($this->_quote->getBaseGrandTotal(), 2);
506  $this->_getApi()->setAmount($totalAmount)
507  ->setCurrencyCode($this->_quote->getBaseCurrencyCode())
508  ->setInvNum($this->_quote->getReservedOrderId())
509  ->setReturnUrl($returnUrl)
510  ->setCancelUrl($cancelUrl)
511  ->setSolutionType($solutionType)
512  ->setPaymentAction($this->_config->getValue('paymentAction'));
513  if ($this->_giropayUrls) {
514  list($successUrl, $cancelUrl, $pendingUrl) = $this->_giropayUrls;
515  $this->_getApi()->addData(
516  [
517  'giropay_cancel_url' => $cancelUrl,
518  'giropay_success_url' => $successUrl,
519  'giropay_bank_txn_pending_url' => $pendingUrl,
520  ]
521  );
522  }
523 
524  if ($this->_isBml) {
525  $this->_getApi()->setFundingSource('BML');
526  }
527 
529 
530  if ($this->_config->getValue('requireBillingAddress') == PaypalConfig::REQUIRE_BILLING_ADDRESS_ALL) {
531  $this->_getApi()->setRequireBillingAddress(1);
532  }
533 
534  // suppress or export shipping address
535  $address = null;
536  if ($this->_quote->getIsVirtual()) {
537  if ($this->_config->getValue('requireBillingAddress')
538  == PaypalConfig::REQUIRE_BILLING_ADDRESS_VIRTUAL
539  ) {
540  $this->_getApi()->setRequireBillingAddress(1);
541  }
542  $this->_getApi()->setSuppressShipping(true);
543  } else {
544  $this->_getApi()->setBillingAddress($this->_quote->getBillingAddress());
545 
546  $address = $this->_quote->getShippingAddress();
547  $isOverridden = 0;
548  if (true === $address->validate()) {
549  $isOverridden = 1;
550  $this->_getApi()->setAddress($address);
551  }
552  $this->_quote->getPayment()->setAdditionalInformation(
553  self::PAYMENT_INFO_TRANSPORT_SHIPPING_OVERRIDDEN,
554  $isOverridden
555  );
556  $this->_quote->getPayment()->save();
557  }
558 
560  $cart = $this->_cartFactory->create(['salesModel' => $this->_quote]);
561 
562  $this->_getApi()->setPaypalCart($cart);
563 
564  if (!$this->_taxData->getConfig()->priceIncludesTax()) {
565  $this->setShippingOptions($cart, $address);
566  }
567 
568  $this->_config->exportExpressCheckoutStyleSettings($this->_getApi());
569 
570  /* Temporary solution. @TODO: do not pass quote into Nvp model */
571  $this->_getApi()->setQuote($this->_quote);
572  $this->_getApi()->callSetExpressCheckout();
573 
574  $token = $this->_getApi()->getToken();
575 
576  $this->_setRedirectUrl($button, $token);
577 
578  $payment = $this->_quote->getPayment();
579  $payment->unsAdditionalInformation(self::PAYMENT_INFO_TRANSPORT_BILLING_AGREEMENT);
580  // Set flag that we came from Express Checkout button
581  if (!empty($button)) {
582  $payment->setAdditionalInformation(self::PAYMENT_INFO_BUTTON, 1);
583  } elseif ($payment->hasAdditionalInformation(self::PAYMENT_INFO_BUTTON)) {
584  $payment->unsAdditionalInformation(self::PAYMENT_INFO_BUTTON);
585  }
586  $payment->save();
587 
588  return $token;
589  }
590 
596  public function canSkipOrderReviewStep()
597  {
598  $isOnepageCheckout = !$this->_quote->getPayment()->getAdditionalInformation(self::PAYMENT_INFO_BUTTON);
599  return $this->_config->isOrderReviewStepDisabled() && $isOnepageCheckout;
600  }
601 
612  public function returnFromPaypal($token)
613  {
614  $this->_getApi()
615  ->setToken($token)
616  ->callGetExpressCheckoutDetails();
618 
619  $this->ignoreAddressValidation();
620 
621  // check if we came from the Express Checkout button
622  $isButton = (bool)$quote->getPayment()->getAdditionalInformation(self::PAYMENT_INFO_BUTTON);
623 
624  // import shipping address
625  $exportedShippingAddress = $this->_getApi()->getExportedShippingAddress();
626  if (!$quote->getIsVirtual()) {
627  $shippingAddress = $quote->getShippingAddress();
628  if ($shippingAddress) {
629  if ($exportedShippingAddress && $isButton) {
630  $this->_setExportedAddressData($shippingAddress, $exportedShippingAddress);
631  // PayPal doesn't provide detailed shipping info: prefix, middlename, lastname, suffix
632  $shippingAddress->setPrefix(null);
633  $shippingAddress->setMiddlename(null);
634  $shippingAddress->setLastname(null);
635  $shippingAddress->setSuffix(null);
636  $shippingAddress->setCollectShippingRates(true);
637  $shippingAddress->setSameAsBilling(0);
638  }
639 
640  // import shipping method
641  $code = '';
642  if ($this->_getApi()->getShippingRateCode()) {
643  $code = $this->_matchShippingMethodCode($shippingAddress, $this->_getApi()->getShippingRateCode());
644  if ($code) {
645  // possible bug of double collecting rates :-/
646  $shippingAddress->setShippingMethod($code)->setCollectShippingRates(true);
647  }
648  }
649  $quote->getPayment()->setAdditionalInformation(
650  self::PAYMENT_INFO_TRANSPORT_SHIPPING_METHOD,
651  $code
652  );
653  }
654  }
655 
656  // import billing address
657  $requireBillingAddress = (int)$this->_config->getValue(
658  'requireBillingAddress'
660 
661  if ($isButton && !$requireBillingAddress && !$quote->isVirtual()) {
663  $billingAddress->unsAddressId()->unsAddressType()->setCustomerAddressId(null);
664  $data = $billingAddress->getData();
665  $data['save_in_address_book'] = 0;
666  $quote->getBillingAddress()->addData($data);
667  $quote->getShippingAddress()->setSameAsBilling(1);
668  } else {
669  $billingAddress = $quote->getBillingAddress()->setCustomerAddressId(null);
670  }
671  $exportedBillingAddress = $this->_getApi()->getExportedBillingAddress();
672 
673  // Since country is required field for billing and shipping address,
674  // we consider the address information to be empty if country is empty.
675  $isEmptyAddress = ($billingAddress->getCountryId() === null);
676 
677  if ($requireBillingAddress || $isEmptyAddress) {
678  $this->_setExportedAddressData($billingAddress, $exportedBillingAddress);
679  }
680  $billingAddress->setCustomerNote($exportedBillingAddress->getData('note'));
681  $quote->setBillingAddress($billingAddress);
682  $quote->setCheckoutMethod($this->getCheckoutMethod());
683 
684  // import payment info
685  $payment = $quote->getPayment();
686  $payment->setMethod($this->_methodType);
687  $this->_paypalInfo->importToPayment($this->_getApi(), $payment);
688  $payment->setAdditionalInformation(self::PAYMENT_INFO_TRANSPORT_PAYER_ID, $this->_getApi()->getPayerId())
689  ->setAdditionalInformation(self::PAYMENT_INFO_TRANSPORT_TOKEN, $token);
690  $quote->collectTotals();
691  $this->quoteRepository->save($quote);
692  }
693 
702  public function prepareOrderReview($token = null)
703  {
704  $payment = $this->_quote->getPayment();
705  if (!$payment || !$payment->getAdditionalInformation(self::PAYMENT_INFO_TRANSPORT_PAYER_ID)) {
706  throw new \Magento\Framework\Exception\LocalizedException(__('A payer is not identified.'));
707  }
708  $this->_quote->setMayEditShippingAddress(
709  1 != $this->_quote->getPayment()->getAdditionalInformation(self::PAYMENT_INFO_TRANSPORT_SHIPPING_OVERRIDDEN)
710  );
711  $this->_quote->setMayEditShippingMethod(
712  '' == $this->_quote->getPayment()->getAdditionalInformation(self::PAYMENT_INFO_TRANSPORT_SHIPPING_METHOD)
713  );
714  $this->ignoreAddressValidation();
715  $this->_quote->collectTotals();
716  $this->quoteRepository->save($this->_quote);
717  }
718 
727  {
728  $debugData = ['request' => $request, 'response' => []];
729 
730  try {
731  // obtain addresses
732  $address = $this->_getApi()->prepareShippingOptionsCallbackAddress($request);
733  $quoteAddress = $this->_quote->getShippingAddress();
734 
735  // compare addresses, calculate shipping rates and prepare response
736  $options = [];
737  if ($address && $quoteAddress && !$this->_quote->getIsVirtual()) {
738  foreach ($address->getExportedKeys() as $key) {
739  $quoteAddress->setDataUsingMethod($key, $address->getData($key));
740  }
741  $quoteAddress->setCollectShippingRates(true);
742  $this->totalsCollector->collectAddressTotals($this->_quote, $quoteAddress);
743  $options = $this->_prepareShippingOptions($quoteAddress, false, true);
744  }
745  $response = $this->_getApi()->setShippingOptions($options)->formatShippingOptionsCallback();
746 
747  // log request and response
748  $debugData['response'] = $response;
749  $this->_logger->debug(var_export($debugData, true));
750  return $response;
751  } catch (\Exception $e) {
752  $this->_logger->debug(var_export($debugData, true));
753  throw $e;
754  }
755  }
756 
764  {
765  $shippingAddress = $this->_quote->getShippingAddress();
766  if (!$this->_quote->getIsVirtual() && $shippingAddress) {
767  if ($methodCode != $shippingAddress->getShippingMethod()) {
768  $this->ignoreAddressValidation();
769  $shippingAddress->setShippingMethod($methodCode)->setCollectShippingRates(true);
770  $cartExtension = $this->_quote->getExtensionAttributes();
771  if ($cartExtension && $cartExtension->getShippingAssignments()) {
772  $cartExtension->getShippingAssignments()[0]
773  ->getShipping()
774  ->setMethod($methodCode);
775  }
776  $this->_quote->collectTotals();
777  $this->quoteRepository->save($this->_quote);
778  }
779  }
780  }
781 
791  public function place($token, $shippingMethodCode = null)
792  {
793  if ($shippingMethodCode) {
794  $this->updateShippingMethod($shippingMethodCode);
795  }
796 
797  if ($this->getCheckoutMethod() == \Magento\Checkout\Model\Type\Onepage::METHOD_GUEST) {
798  $this->prepareGuestQuote();
799  }
800 
801  $this->ignoreAddressValidation();
802  $this->_quote->collectTotals();
803  $order = $this->quoteManagement->submit($this->_quote);
804 
805  if (!$order) {
806  return;
807  }
808 
809  // commence redirecting to finish payment, if paypal requires it
810  if ($order->getPayment()->getAdditionalInformation(self::PAYMENT_INFO_TRANSPORT_REDIRECT)) {
811  $this->_redirectUrl = $this->_config->getExpressCheckoutCompleteUrl($token);
812  }
813 
814  switch ($order->getState()) {
815  // even after placement paypal can disallow to authorize/capture, but will wait until bank transfers money
816  case \Magento\Sales\Model\Order::STATE_PENDING_PAYMENT:
817  // TODO
818  break;
819  // regular placement, when everything is ok
820  case \Magento\Sales\Model\Order::STATE_PROCESSING:
821  case \Magento\Sales\Model\Order::STATE_COMPLETE:
822  case \Magento\Sales\Model\Order::STATE_PAYMENT_REVIEW:
823  try {
824  if (!$order->getEmailSent()) {
825  $this->orderSender->send($order);
826  }
827  } catch (\Exception $e) {
828  $this->_logger->critical($e);
829  }
830  $this->_checkoutSession->start();
831  break;
832  default:
833  break;
834  }
835  $this->_order = $order;
836  }
837 
843  private function ignoreAddressValidation()
844  {
845  $this->_quote->getBillingAddress()->setShouldIgnoreValidation(true);
846  if (!$this->_quote->getIsVirtual()) {
847  $this->_quote->getShippingAddress()->setShouldIgnoreValidation(true);
848  if (!$this->_config->getValue('requireBillingAddress')
849  && !$this->_quote->getBillingAddress()->getEmail()
850  ) {
851  $this->_quote->getBillingAddress()->setSameAsBilling(1);
852  }
853  }
854  }
855 
861  public function getRedirectUrl()
862  {
863  return $this->_redirectUrl;
864  }
865 
871  public function getBillingAgreement()
872  {
874  }
875 
881  public function getOrder()
882  {
883  return $this->_order;
884  }
885 
891  public function getCheckoutMethod()
892  {
893  if ($this->getCustomerSession()->isLoggedIn()) {
894  return \Magento\Checkout\Model\Type\Onepage::METHOD_CUSTOMER;
895  }
896  if (!$this->_quote->getCheckoutMethod()) {
897  if ($this->_checkoutData->isAllowedGuestCheckout($this->_quote)) {
898  $this->_quote->setCheckoutMethod(\Magento\Checkout\Model\Type\Onepage::METHOD_GUEST);
899  } else {
900  $this->_quote->setCheckoutMethod(\Magento\Checkout\Model\Type\Onepage::METHOD_REGISTER);
901  }
902  }
903  return $this->_quote->getCheckoutMethod();
904  }
905 
913  protected function _setExportedAddressData($address, $exportedAddress)
914  {
915  foreach ($exportedAddress->getExportedKeys() as $key) {
916  $data = $exportedAddress->getData($key);
917  if (!empty($data)) {
918  $address->setDataUsingMethod($key, $data);
919  }
920  }
921  }
922 
928  protected function _setBillingAgreementRequest()
929  {
930  if (!$this->_customerId) {
931  return $this;
932  }
933 
934  $isRequested = $this->_isBARequested || $this->_quote->getPayment()
935  ->getAdditionalInformation(self::PAYMENT_INFO_TRANSPORT_BILLING_AGREEMENT);
936 
937  if (!($this->_config->getValue('allow_ba_signup') == PaypalConfig::EC_BA_SIGNUP_AUTO
938  || $isRequested && $this->_config->shouldAskToCreateBillingAgreement())
939  ) {
940  return $this;
941  }
942 
943  if (!$this->_agreementFactory->create()->needToCreateForCustomer($this->_customerId)) {
944  return $this;
945  }
946  $this->_getApi()->setBillingType($this->_getApi()->getBillingAgreementType());
947  return $this;
948  }
949 
955  protected function _getApi()
956  {
957  if (null === $this->_api) {
958  $this->_api = $this->_apiTypeFactory->create($this->_apiType)->setConfigObject($this->_config);
959  }
960  return $this->_api;
961  }
962 
976  protected function _prepareShippingOptions(Address $address, $mayReturnEmpty = false, $calculateTax = false)
977  {
978  $options = [];
979  $i = 0;
980  $iMin = false;
981  $min = false;
982  $userSelectedOption = null;
983 
984  foreach ($address->getGroupedAllShippingRates() as $group) {
985  foreach ($group as $rate) {
986  $amount = (double)$rate->getPrice();
987  if ($rate->getErrorMessage()) {
988  continue;
989  }
990  $isDefault = $address->getShippingMethod() === $rate->getCode();
991  $amountExclTax = $this->_taxData->getShippingPrice($amount, false, $address);
992  $amountInclTax = $this->_taxData->getShippingPrice($amount, true, $address);
993 
994  $options[$i] = new \Magento\Framework\DataObject(
995  [
996  'is_default' => $isDefault,
997  'name' => trim("{$rate->getCarrierTitle()} - {$rate->getMethodTitle()}", ' -'),
998  'code' => $rate->getCode(),
999  'amount' => $amountExclTax,
1000  ]
1001  );
1002  if ($calculateTax) {
1003  $options[$i]->setTaxAmount(
1004  $amountInclTax - $amountExclTax + $address->getTaxAmount() - $address->getShippingTaxAmount()
1005  );
1006  }
1007  if ($isDefault) {
1008  $userSelectedOption = $options[$i];
1009  }
1010  if (false === $min || $amountInclTax < $min) {
1011  $min = $amountInclTax;
1012  $iMin = $i;
1013  }
1014  $i++;
1015  }
1016  }
1017 
1018  if ($mayReturnEmpty && $userSelectedOption === null) {
1019  $options[] = new \Magento\Framework\DataObject(
1020  [
1021  'is_default' => true,
1022  'name' => __('N/A'),
1023  'code' => 'no_rate',
1024  'amount' => 0.00,
1025  ]
1026  );
1027  if ($calculateTax) {
1028  $options[$i]->setTaxAmount($address->getTaxAmount());
1029  }
1030  } elseif ($userSelectedOption === null && isset($options[$iMin])) {
1031  $options[$iMin]->setIsDefault(true);
1032  }
1033 
1034  // Magento will transfer only first 10 cheapest shipping options if there are more than 10 available.
1035  if (count($options) > 10) {
1036  usort($options, [get_class($this), 'cmpShippingOptions']);
1037  array_splice($options, 10);
1038  // User selected option will be always included in options list
1039  if ($userSelectedOption !== null && !in_array($userSelectedOption, $options)) {
1040  $options[9] = $userSelectedOption;
1041  }
1042  }
1043 
1044  return $options;
1045  }
1046 
1057  protected static function cmpShippingOptions(DataObject $option1, DataObject $option2)
1058  {
1059  if ($option1->getAmount() == $option2->getAmount()) {
1060  return 0;
1061  }
1062  return ($option1->getAmount() < $option2->getAmount()) ? -1 : 1;
1063  }
1064 
1076  protected function _matchShippingMethodCode(Address $address, $selectedCode)
1077  {
1078  $options = $this->_prepareShippingOptions($address, false);
1079  foreach ($options as $option) {
1080  if ($selectedCode === $option['code'] // the proper case as outlined in documentation
1081  || $selectedCode === $option['name'] // workaround: PayPal may return name instead of the code
1082  // workaround: PayPal may concatenate code and name, and return it instead of the code:
1083  || $selectedCode === "{$option['code']} {$option['name']}"
1084  ) {
1085  return $option['code'];
1086  }
1087  }
1088  return '';
1089  }
1090 
1098  protected function _setRedirectUrl($button, $token)
1099  {
1100  $this->_redirectUrl = ($button && !$this->_taxData->getConfig()->priceIncludesTax())
1101  ? $this->_config->getExpressCheckoutStartUrl($token)
1102  : $this->_config->getPayPalBasicStartUrl($token);
1103  }
1104 
1110  public function getCustomerSession()
1111  {
1112  return $this->_customerSession;
1113  }
1114 
1122  private function setShippingOptions(PaypalCart $cart, Address $address = null)
1123  {
1124  // for included tax always disable line items (related to paypal amount rounding problem)
1125  $this->_getApi()->setIsLineItemsEnabled($this->_config->getValue(PaypalConfig::TRANSFER_CART_LINE_ITEMS));
1126 
1127  // add shipping options if needed and line items are available
1128  $cartItems = $cart->getAllItems();
1129  if ($this->_config->getValue(PaypalConfig::TRANSFER_CART_LINE_ITEMS)
1130  && $this->_config->getValue(PaypalConfig::TRANSFER_SHIPPING_OPTIONS)
1131  && !empty($cartItems)
1132  ) {
1133  if (!$this->_quote->getIsVirtual()) {
1134  $options = $this->_prepareShippingOptions($address, true);
1135  if ($options) {
1136  $this->_getApi()->setShippingOptionsCallbackUrl(
1137  $this->_coreUrl->getUrl(
1138  '*/*/shippingOptionsCallback',
1139  ['quote_id' => $this->_quote->getId()]
1140  )
1141  )->setShippingOptions($options);
1142  }
1143  }
1144  }
1145  }
1146 
1152  protected function prepareGuestQuote()
1153  {
1155  $quote->setCustomerId(null)
1156  ->setCustomerEmail($quote->getBillingAddress()->getEmail())
1157  ->setCustomerIsGuest(true)
1158  ->setCustomerGroupId(\Magento\Customer\Model\Group::NOT_LOGGED_IN_ID);
1159  return $this;
1160  }
1161 }
$response
Definition: 404.php:11
_prepareShippingOptions(Address $address, $mayReturnEmpty=false, $calculateTax=false)
Definition: Checkout.php:976
$customerData
setCustomerData(CustomerDataObject $customerData)
Definition: Checkout.php:449
elseif(isset( $params[ 'redirect_parent']))
Definition: iframe.phtml:17
$billingAddress
Definition: order.php:25
$customerUrl
Definition: info.phtml:28
getShippingOptionsCallbackResponse(array $request)
Definition: Checkout.php:726
$quote
$shippingAddress
Definition: order.php:40
setCustomerWithAddressChange(CustomerDataObject $customerData, $billingAddress=null, $shippingAddress=null)
Definition: Checkout.php:464
$group
Definition: sections.phtml:16
$order
Definition: order.php:55
$storeManager
__()
Definition: __.php:13
$customerRepository
$address
Definition: customer.php:38
$amount
Definition: order.php:14
$payment
Definition: order.php:17
$accountManagement
__construct(\Psr\Log\LoggerInterface $logger, \Magento\Customer\Model\Url $customerUrl, \Magento\Tax\Helper\Data $taxData, \Magento\Checkout\Helper\Data $checkoutData, \Magento\Customer\Model\Session $customerSession, \Magento\Framework\App\Cache\Type\Config $configCacheType, \Magento\Framework\Locale\ResolverInterface $localeResolver, \Magento\Paypal\Model\Info $paypalInfo, \Magento\Store\Model\StoreManagerInterface $storeManager, \Magento\Framework\UrlInterface $coreUrl, \Magento\Paypal\Model\CartFactory $cartFactory, \Magento\Checkout\Model\Type\OnepageFactory $onepageFactory, \Magento\Quote\Api\CartManagementInterface $quoteManagement, \Magento\Paypal\Model\Billing\AgreementFactory $agreementFactory, \Magento\Paypal\Model\Api\Type\Factory $apiTypeFactory, \Magento\Framework\DataObject\Copy $objectCopyService, \Magento\Checkout\Model\Session $checkoutSession, \Magento\Framework\Encryption\EncryptorInterface $encryptor, \Magento\Framework\Message\ManagerInterface $messageManager, \Magento\Customer\Api\CustomerRepositoryInterface $customerRepository, AccountManagement $accountManagement, OrderSender $orderSender, \Magento\Quote\Api\CartRepositoryInterface $quoteRepository, \Magento\Quote\Model\Quote\TotalsCollector $totalsCollector, $params=[])
Definition: Checkout.php:303
prepareGiropayUrls($successUrl, $cancelUrl, $pendingUrl)
Definition: Checkout.php:413
static cmpShippingOptions(DataObject $option1, DataObject $option2)
Definition: Checkout.php:1057
_matchShippingMethodCode(Address $address, $selectedCode)
Definition: Checkout.php:1076
_setExportedAddressData($address, $exportedAddress)
Definition: Checkout.php:913
$params[\Magento\Store\Model\StoreManager::PARAM_RUN_CODE]
Definition: website.php:18
place($token, $shippingMethodCode=null)
Definition: Checkout.php:791
$i
Definition: gallery.phtml:31
$code
Definition: info.phtml:12