Current File : /var/www/prestashop/modules/ps_checkout/controllers/front/payment.php |
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
use PrestaShop\Module\PrestashopCheckout\CommandBus\CommandBusInterface;
use PrestaShop\Module\PrestashopCheckout\Controller\AbstractFrontController;
use PrestaShop\Module\PrestashopCheckout\Exception\PsCheckoutException;
use PrestaShop\Module\PrestashopCheckout\Order\Command\CreateOrderCommand;
use PrestaShop\Module\PrestashopCheckout\PayPal\Card3DSecure;
use PrestaShop\Module\PrestashopCheckout\PayPal\Order\Command\CapturePayPalOrderCommand;
use PrestaShop\Module\PrestashopCheckout\PayPal\Order\Entity\PayPalOrder;
use PrestaShop\Module\PrestashopCheckout\PayPal\Order\Exception\PayPalOrderException;
use PrestaShop\Module\PrestashopCheckout\PayPal\Order\ValueObject\PayPalOrderId;
use PrestaShop\Module\PrestashopCheckout\PayPal\PayPalOrderProvider;
use PrestaShop\Module\PrestashopCheckout\Repository\PaymentTokenRepository;
use PrestaShop\Module\PrestashopCheckout\Repository\PayPalOrderRepository;
class Ps_CheckoutPaymentModuleFrontController extends AbstractFrontController
{
public $ssl = true;
public $controller_type = 'front';
public $display_footer = false;
public $display_header = true;
private $orderPageUrl;
/**
* @var PayPalOrderId
*/
private $paypalOrderId;
public function checkAccess()
{
return $this->context->customer && $this->context->customer->isLogged() && $this->context->cart;
}
public function initContent()
{
$this->orderPageUrl = $this->context->link->getPageLink('order');
parent::initContent();
$this->setTemplate('module:ps_checkout/views/templates/front/payment.tpl');
$this->context->smarty->assign('css_url', $this->module->getPathUri() . 'views/css/payment.css');
$this->context->smarty->assign('order_url', $this->orderPageUrl);
}
public function setMedia()
{
$this->registerStylesheet('ps_checkout_payment', '/modules/ps_checkout/views/css/payment.css');
parent::setMedia();
}
public function postProcess()
{
$orderId = Tools::getValue('orderID');
if (!$orderId) {
$this->redirectToOrderPage();
}
try {
$this->paypalOrderId = new PayPalOrderId($orderId);
/** @var PayPalOrderRepository $payPalOrderRepository */
$payPalOrderRepository = $this->module->getService(PayPalOrderRepository::class);
/** @var PayPalOrderProvider $payPalOrderProvider */
$payPalOrderProvider = $this->module->getService(PayPalOrderProvider::class);
/** @var CommandBusInterface $commandBus */
$commandBus = $this->module->getService('ps_checkout.bus.command');
/** @var Psr\SimpleCache\CacheInterface $payPalOrderCache */
$payPalOrderCache = $this->module->getService('ps_checkout.cache.paypal.order');
$payPalOrder = $payPalOrderRepository->getPayPalOrderById($this->paypalOrderId);
if ($payPalOrder->getIdCart() !== $this->context->cart->id) {
throw new Exception('PayPal order does not belong to this customer');
}
$payPalOrderFromCache = $payPalOrderProvider->getById($payPalOrder->getId()->getValue());
if ($payPalOrderFromCache['status'] === 'COMPLETED') {
$this->createOrder($payPalOrderFromCache, $payPalOrder);
}
if ($payPalOrderFromCache['status'] === 'PAYER_ACTION_REQUIRED') {
// Delete from cache so when user is redirected from 3DS authentication page the order is fetched from PayPal
if ($payPalOrderCache->has($this->paypalOrderId->getValue())) {
$payPalOrderCache->delete($this->paypalOrderId->getValue());
}
$this->redirectTo3DSVerification($payPalOrderFromCache);
}
// WHEN 3DS fails
if ($payPalOrderFromCache['status'] === 'CREATED') {
$card3DSecure = new Card3DSecure();
switch ($card3DSecure->continueWithAuthorization($payPalOrderFromCache)) {
case Card3DSecure::RETRY:
$this->redirectTo3DSVerification($payPalOrderFromCache);
break;
case Card3DSecure::PROCEED:
$commandBus->handle(new CapturePayPalOrderCommand($this->paypalOrderId->getValue(), array_keys($payPalOrderFromCache['payment_source'])[0]));
$payPalOrderFromCache = $payPalOrderCache->get($this->paypalOrderId->getValue());
$this->createOrder($payPalOrderFromCache, $payPalOrder);
break;
case Card3DSecure::NO_DECISION:
default:
break;
}
}
} catch (Exception $exception) {
$this->context->smarty->assign('error', $exception->getMessage());
}
}
/**
* @param array $payPalOrderFromCache
* @param PayPalOrder$payPalOrder
*
* @return void
*
* @throws PrestaShopException
* @throws PsCheckoutException
* @throws PayPalOrderException
*/
private function createOrder($payPalOrderFromCache, $payPalOrder)
{
/** @var CommandBusInterface $commandBus */
$commandBus = $this->module->getService('ps_checkout.bus.command');
$capture = $payPalOrderFromCache['purchase_units'][0]['payments']['captures'][0];
if ($capture['status'] === 'COMPLETED') {
$commandBus->handle(new CreateOrderCommand($payPalOrder->getId()->getValue(), $capture));
if ($payPalOrder->getPaymentTokenId() && $payPalOrder->checkCustomerIntent(PayPalOrder::CUSTOMER_INTENT_FAVORITE)) {
/** @var PaymentTokenRepository $paymentTokenRepository */
$paymentTokenRepository = $this->module->getService(PaymentTokenRepository::class);
$paymentTokenRepository->setTokenFavorite($payPalOrder->getPaymentTokenId());
}
$this->redirectToOrderConfirmationPage($payPalOrder->getIdCart(), $capture['id'], $payPalOrderFromCache['status']);
}
}
/**
* @param array $order
*
* @return void
*/
private function redirectTo3DSVerification($order)
{
$payerActionLinks = array_filter($order['links'], function ($link) {
return $link['rel'] === 'payer-action';
});
if (!empty($payerActionLinks)) {
Tools::redirect(reset($payerActionLinks)['href'] . '&redirect_uri=' . urlencode($this->context->link->getModuleLink('ps_checkout', 'payment', ['orderID' => $this->paypalOrderId->getValue()])));
}
}
private function redirectToOrderPage()
{
Tools::redirect($this->orderPageUrl);
}
/**
* @param int $cartId
* @param string $captureId
* @param string $payPalOrderStatus
*
* @return void
*
* @throws PrestaShopException
*/
private function redirectToOrderConfirmationPage($cartId, $captureId, $payPalOrderStatus)
{
$orders = new PrestaShopCollection(Order::class);
$orders->where('id_cart', '=', $cartId);
if (!$orders->count()) {
return;
}
/** @var Order $order */
$order = $orders->getFirst();
$cart = new Cart($cartId);
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
Tools::redirect($this->context->link->getPageLink(
'order-confirmation',
true,
(int) $order->id_lang,
[
'paypal_status' => $payPalOrderStatus,
'paypal_order' => $this->paypalOrderId->getValue(),
'paypal_transaction' => $captureId,
'id_cart' => $cartId,
'id_module' => (int) $this->module->id,
'id_order' => (int) $order->id,
'key' => $cart->secure_key,
]
));
}
}
}