Current File : /var/www/vinorea/modules/ps_checkout/ps_checkout.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
 */
require_once __DIR__ . '/vendor/autoload.php';

if (!defined('_PS_VERSION_')) {
    exit;
}

class Ps_checkout extends PaymentModule
{
    /**
     * Default hook to install
     * 1.6 and 1.7
     *
     * @var array
     */
    const HOOK_LIST = [
        'displayAdminAfterHeader',
        'displayOrderConfirmation',
        'displayAdminOrderLeft',
        'displayAdminOrderMainBottom',
        'actionObjectShopAddAfter',
        'actionObjectShopDeleteAfter',
        'actionAdminControllerSetMedia',
        'displayPaymentTop',
        'displayPaymentByBinaries',
        'actionFrontControllerSetMedia',
        'actionObjectOrderPaymentAddAfter',
        'actionObjectOrderPaymentUpdateAfter',
        'displayPaymentReturn',
        'displayOrderDetail',
        'moduleRoutes',
    ];

    /**
     * Hook to install for 1.7
     *
     * @var array
     */
    const HOOK_LIST_17 = [
        'paymentOptions',
        'actionCartUpdateQuantityBefore',
        'displayInvoiceLegalFreeText',
        'actionObjectProductInCartDeleteAfter',
    ];

    /**
     * Names of ModuleAdminController used
     */
    const MODULE_ADMIN_CONTROLLERS = [
        'AdminAjaxPrestashopCheckout',
        'AdminPaypalOnboardingPrestashopCheckout',
    ];

    /**
     * Hook to install for 1.6
     *
     * @var array
     */
    const HOOK_LIST_16 = [
        'actionBeforeCartUpdateQty',
        'actionAfterDeleteProductInCart',
        'displayPayment',
        'displayCartTotalPriceLabel',
    ];

    public $configurationList = [
        'PS_CHECKOUT_INTENT' => 'CAPTURE',
        'PS_CHECKOUT_MODE' => 'LIVE',
        'PS_CHECKOUT_PAYPAL_ID_MERCHANT' => '',
        'PS_CHECKOUT_PAYPAL_EMAIL_MERCHANT' => '',
        'PS_CHECKOUT_PAYPAL_EMAIL_STATUS' => '',
        'PS_CHECKOUT_PAYPAL_PAYMENT_STATUS' => '',
        'PS_CHECKOUT_CARD_PAYMENT_STATUS' => '',
        'PS_CHECKOUT_CARD_PAYMENT_ENABLED' => true,
        'PS_CHECKOUT_EC_ORDER_PAGE' => false,
        'PS_CHECKOUT_EC_CHECKOUT_PAGE' => false,
        'PS_CHECKOUT_EC_PRODUCT_PAGE' => false,
        'PS_CHECKOUT_PAY_IN_4X_PRODUCT_PAGE' => false,
        'PS_CHECKOUT_PAY_IN_4X_ORDER_PAGE' => false,
        'PS_CHECKOUT_PAYPAL_CB_INLINE' => false,
        'PS_CHECKOUT_LOGGER_MAX_FILES' => '15',
        'PS_CHECKOUT_LOGGER_LEVEL' => '400',
        'PS_CHECKOUT_LOGGER_HTTP' => '0',
        'PS_CHECKOUT_LOGGER_HTTP_FORMAT' => 'DEBUG',
        'PS_CHECKOUT_LIVE_STEP_VIEWED' => false,
        'PS_CHECKOUT_INTEGRATION_DATE' => self::INTEGRATION_DATE,
        'PS_CHECKOUT_WEBHOOK_SECRET' => '',
        'PS_CHECKOUT_LIABILITY_SHIFT_REQ' => '1',
        'PS_CHECKOUT_DISPLAY_LOGO_PRODUCT' => '1',
        'PS_CHECKOUT_DISPLAY_LOGO_CART' => '1',
        'PS_CHECKOUT_HOSTED_FIELDS_CONTINGENCIES' => 'SCA_WHEN_REQUIRED',
        'PS_CHECKOUT_DOMAIN_REGISTERED_SANDBOX' => false,
        'PS_CHECKOUT_DOMAIN_REGISTERED_LIVE' => false,
    ];

    public $confirmUninstall;
    public $bootstrap;

    // Needed in order to retrieve the module version easier (in api call headers) than instanciate
    // the module each time to get the version
    const VERSION = '8.4.4.0';

    const INTEGRATION_DATE = '2024-04-01';

    /** @var \Psr\Log\LoggerInterface */
    private $logger;

    /**
     * @var \PrestaShop\ModuleLibServiceContainer\DependencyInjection\ServiceContainer
     */
    private $serviceContainer;
    private static $merchantIsValid;
    private static $currencyIsAllowed;

    public function __construct()
    {
        $this->name = 'ps_checkout';
        $this->tab = 'payments_gateways';

        // We cannot use the const VERSION because the const is not computed by addons marketplace
        // when the zip is uploaded
        $this->version = '8.4.4.0';
        $this->author = 'PrestaShop';
        $this->currencies = true;
        $this->currencies_mode = 'checkbox';

        $this->module_key = '82bc76354cfef947e06f1cc78f5efe2e';

        $this->bootstrap = false;

        parent::__construct();

        $this->displayName = $this->l('PrestaShop Checkout');
        $this->description = $this->l('Provide the most commonly used payment methods to your customers in this all-in-one module, and manage all your sales in a centralized interface.');

        $this->confirmUninstall = $this->l('Are you sure you want to uninstall this module?');
        $this->ps_versions_compliancy = ['min' => '8.0.0', 'max' => _PS_VERSION_];

        // $this->disableSegment = false;
    }

    /**
     * Function executed at the install of the module
     *
     * @return bool
     */
    public function install()
    {
        // Force PrestaShop to install for all shop to avoid issues, install action is always for all shops
        $savedShopContext = Shop::getContext();
        $savedShopId = Shop::getContextShopID();
        $savedGroupShopId = Shop::getContextShopGroupID();
        Shop::setContext(Shop::CONTEXT_ALL);

        // Install for both 1.7 and 1.6
        $result = parent::install() &&
            $this->installConfiguration() &&
            $this->installHooks() &&
            (new PrestaShop\Module\PrestashopCheckout\Database\TableManager())->createTable() &&
            (new PrestaShop\Module\PrestashopCheckout\FundingSource\FundingSourceInstaller())->createFundingSourcesOnAllShops() &&
            $this->installTabs() &&
            $this->disableIncompatibleCountries() &&
            $this->disableIncompatibleCurrencies();

        (new \PrestaShop\Module\PrestashopCheckout\Order\State\OrderStateInstaller())->install();

        // Restore initial PrestaShop shop context
        if (Shop::CONTEXT_SHOP === $savedShopContext) {
            Shop::setContext($savedShopContext, $savedShopId);
        } elseif (Shop::CONTEXT_GROUP === $savedShopContext) {
            Shop::setContext($savedShopContext, $savedGroupShopId);
        } else {
            Shop::setContext($savedShopContext);
        }

        return (bool) $result;
    }

    public function installHooks()
    {
        $result = (bool) $this->registerHook(self::HOOK_LIST);
        /** @var \PrestaShop\Module\PrestashopCheckout\ShopContext $shopContext */
        $shopContext = $this->getService(\PrestaShop\Module\PrestashopCheckout\ShopContext::class);

        // Install specific to prestashop 1.6
        if (!$shopContext->isShop17()) {
            $result = $result && $this->registerHook(self::HOOK_LIST_16);
            $this->updatePosition(\Hook::getIdByName('payment'), false, 1);

            return $result;
        }

        // Install specific to prestashop 1.7
        if ($shopContext->isShop17()) {
            $result = $result && (bool) $this->registerHook(self::HOOK_LIST_17);
            $this->updatePosition(\Hook::getIdByName('paymentOptions'), false, 1);
        }

        return $result;
    }

    /**
     * Install configuration for each shop
     *
     * @return bool
     */
    public function installConfiguration()
    {
        $result = true;

        foreach (\Shop::getShops(false, null, true) as $shopId) {
            foreach ($this->configurationList as $name => $value) {
                if (false === Configuration::hasKey($name, null, null, (int) $shopId)) {
                    $result = $result && (bool) Configuration::updateValue(
                            $name,
                            $value,
                            false,
                            null,
                            (int) $shopId
                        );
                }
            }
        }

        return $result;
    }

    /**
     * This method is often use to create an ajax controller
     *
     * @return bool
     */
    public function installTabs()
    {
        $installTabCompleted = true;

        foreach (static::MODULE_ADMIN_CONTROLLERS as $controllerName) {
            if (Tab::getIdFromClassName($controllerName)) {
                continue;
            }

            $tab = new Tab();
            $tab->class_name = $controllerName;
            $tab->active = true;
            $tab->name = array_fill_keys(
                Language::getIDs(false),
                $this->displayName
            );
            $tab->id_parent = -1;
            $tab->module = $this->name;
            $installTabCompleted = $installTabCompleted && $tab->add();
        }

        return $installTabCompleted;
    }

    /**
     * Disable incompatible countries with PayPal for PrestaShop Checkout
     *
     * @return bool
     */
    public function disableIncompatibleCountries()
    {
        /** @var \PrestaShop\Module\PrestashopCheckout\PayPal\PayPalConfiguration $paypalConfiguration */
        $paypalConfiguration = $this->getService(\PrestaShop\Module\PrestashopCheckout\PayPal\PayPalConfiguration::class);
        $incompatibleCodes = $paypalConfiguration->getIncompatibleCountryCodes(false);
        $result = true;

        foreach ($incompatibleCodes as $incompatibleCode) {
            $db = \Db::getInstance();

            $result = $result && $db->execute('
                DELETE FROM ' . _DB_PREFIX_ . 'module_country
                WHERE id_country = (SELECT id_country FROM ' . _DB_PREFIX_ . 'country WHERE iso_code = "' . $incompatibleCode . '")
                AND id_module = ' . $this->id . '
                AND id_shop = ' . \Context::getContext()->shop->id
                );
        }

        return $result;
    }

    /**
     * Disable incompatible currencies with PayPal for PrestaShop Checkout
     *
     * @return bool
     */
    public function disableIncompatibleCurrencies()
    {
        /** @var \PrestaShop\Module\PrestashopCheckout\PayPal\PayPalConfiguration $paypalConfiguration */
        $paypalConfiguration = $this->getService(\PrestaShop\Module\PrestashopCheckout\PayPal\PayPalConfiguration::class);
        $incompatibleCodes = $paypalConfiguration->getIncompatibleCurrencyCodes(false);
        $result = true;

        foreach ($incompatibleCodes as $incompatibleCode) {
            $db = \Db::getInstance();

            $result = $result && $db->execute('
                DELETE FROM ' . _DB_PREFIX_ . 'module_currency
                WHERE id_currency = (SELECT id_currency FROM ' . _DB_PREFIX_ . 'currency WHERE iso_code = "' . $incompatibleCode . '")
                AND id_module = ' . $this->id . '
                AND id_shop = ' . \Context::getContext()->shop->id
                );
        }

        return $result;
    }

    /**
     * Function executed at the uninstall of the module
     *
     * @return bool
     */
    public function uninstall()
    {
        // Force PrestaShop to uninstall for all shop to avoid issues, uninstall action is always for all shops
        $savedShopContext = Shop::getContext();
        $savedShopId = Shop::getContextShopID();
        $savedGroupShopId = Shop::getContextShopGroupID();
        Shop::setContext(Shop::CONTEXT_ALL);

        foreach (array_keys($this->configurationList) as $name) {
            Configuration::deleteByName($name);
        }

        $result = parent::uninstall()
            && (new PrestaShop\Module\PrestashopCheckout\Database\TableManager())->dropTable()
            && $this->uninstallTabs();

        // Restore initial PrestaShop shop context
        if (Shop::CONTEXT_SHOP === $savedShopContext) {
            Shop::setContext($savedShopContext, $savedShopId);
        } elseif (Shop::CONTEXT_GROUP === $savedShopContext) {
            Shop::setContext($savedShopContext, $savedGroupShopId);
        } else {
            Shop::setContext($savedShopContext);
        }

        return $result;
    }

    /**
     * uninstall tabs
     *
     * @return bool
     */
    public function uninstallTabs()
    {
        $uninstallTabCompleted = true;

        foreach (static::MODULE_ADMIN_CONTROLLERS as $controllerName) {
            $id_tab = (int) Tab::getIdFromClassName($controllerName);
            $tab = new Tab($id_tab);
            if (Validate::isLoadedObject($tab)) {
                $uninstallTabCompleted = $uninstallTabCompleted && $tab->delete();
            }
        }

        return $uninstallTabCompleted;
    }

    public function getContent()
    {
        try {
            /** @var \PrestaShop\PsAccountsInstaller\Installer\Facade\PsAccounts $psAccountsFacade */
            $psAccountsFacade = $this->getService('ps_accounts.facade');
            /** @var \PrestaShop\PsAccountsInstaller\Installer\Presenter\InstallerPresenter $psAccountsPresenter */
            $psAccountsPresenter = $psAccountsFacade->getPsAccountsPresenter();
            // @phpstan-ignore-next-line
            $contextPsAccounts = $psAccountsPresenter->present($this->name);
        } catch (Exception $exception) {
            $contextPsAccounts = [];
            $this->getLogger()->error(
                'Failed to get PsAccounts context',
                [
                    'exception' => get_class($exception),
                    'exceptionCode' => $exception->getCode(),
                    'exceptionMessage' => $exception->getMessage(),
                ]
            );
        }

        /** @var \PrestaShop\Module\PrestashopCheckout\Presenter\Store\StorePresenter $storePresenter */
        $storePresenter = $this->getService(\PrestaShop\Module\PrestashopCheckout\Presenter\Store\StorePresenter::class);

        Media::addJsDef([
            'store' => $storePresenter->present(),
            'contextPsAccounts' => $contextPsAccounts,
        ]);

        /** @var \PrestaShop\Module\PrestashopCheckout\Environment\Env $env */
        $env = $this->getService(\PrestaShop\Module\PrestashopCheckout\Environment\Env::class);
        $boSdkUrl = $env->getEnv('CHECKOUT_BO_SDK_URL');
        if (substr($boSdkUrl, -3) !== '.js') {
            $boSdkVersion = $env->getEnv('CHECKOUT_BO_SDK_VERSION');
            if (empty($boSdkVersion)) {
                /** @var \PrestaShop\Module\PrestashopCheckout\Version\Version $version */
                $version = $this->getService('ps_checkout.module.version');
                $majorModuleVersion = explode('.', $version->getSemVersion())[0];
                $boSdkVersion = "$majorModuleVersion.X.X";
            }

            $boSdkUrl = $boSdkUrl . $boSdkVersion . '/sdk/ps_checkout-bo-sdk.umd.js';
        }

        $this->context->controller->addJS($boSdkUrl, false);
        $isShopContext = !(Shop::isFeatureActive() && Shop::getContext() !== Shop::CONTEXT_SHOP);
        $requiredDependencies = [];
        $hasRequiredDependencies = true;

        if ($isShopContext) {
            try {
                $mboInstaller = new \Prestashop\ModuleLibMboInstaller\DependencyBuilder($this);
                $requiredDependencies = $mboInstaller->handleDependencies();
                $hasRequiredDependencies = $mboInstaller->areDependenciesMet();
            } catch (Exception $exception) {
                $this->getLogger()->error(
                    'Failed to get required dependencies',
                    [
                        'exception' => get_class($exception),
                        'exceptionCode' => $exception->getCode(),
                        'exceptionMessage' => $exception->getMessage(),
                    ]
                );
            }
        }

        $this->context->smarty->assign([
            'requiredDependencies' => $requiredDependencies,
            'hasRequiredDependencies' => $hasRequiredDependencies,
        ]);

        return $this->display(__FILE__, 'views/templates/admin/configuration.tpl');
    }

    /**
     * This hook is called only since PrestaShop 1.7.0.0
     */
    public function hookActionObjectProductInCartDeleteAfter()
    {
        $this->hookActionCartUpdateQuantityBefore();
    }

    /**
     * This hook is called only in PrestaShop 1.6.1 to 1.6.1.24
     * Deprecated since PrestaShop 1.7.0.0
     */
    public function hookActionAfterDeleteProductInCart()
    {
        if (!$this->merchantIsValid()) {
            return;
        }

        /** @var \PrestaShop\Module\PrestashopCheckout\ShopContext $shopContext */
        $shopContext = $this->getService(\PrestaShop\Module\PrestashopCheckout\ShopContext::class);

        if ($shopContext->isShop17()) {
            return;
        }

        $this->hookActionCartUpdateQuantityBefore();
    }

    /**
     * This hook is called only since PrestaShop 1.7.0.0
     */
    public function hookActionCartUpdateQuantityBefore()
    {
        if (!$this->merchantIsValid()) {
            return;
        }

        if (false === Validate::isLoadedObject($this->context->cart)) {
            return;
        }

        /** @var \PrestaShop\Module\PrestashopCheckout\Repository\PsCheckoutCartRepository $psCheckoutCartRepository */
        $psCheckoutCartRepository = $this->getService(\PrestaShop\Module\PrestashopCheckout\Repository\PsCheckoutCartRepository::class);

        /** @var PsCheckoutCart|false $psCheckoutCart */
        $psCheckoutCart = $psCheckoutCartRepository->findOneByCartId((int) $this->context->cart->id);

        if (false === Validate::isLoadedObject($psCheckoutCart)) {
            return;
        }

        if ($psCheckoutCart->isExpressCheckout || !$psCheckoutCart->isOrderAvailable() || !$this->context->cart->nbProducts()) {
            $this->context->cookie->__unset('paypalEmail');
        }
    }

    /**
     * This hook is called only in PrestaShop 1.6.1 to 1.6.1.24
     * Deprecated since PrestaShop 1.7.0.0
     */
    public function hookActionBeforeCartUpdateQty()
    {
        if (!$this->merchantIsValid()) {
            return;
        }

        /** @var \PrestaShop\Module\PrestashopCheckout\ShopContext $shopContext */
        $shopContext = $this->getService(\PrestaShop\Module\PrestashopCheckout\ShopContext::class);

        if ($shopContext->isShop17()) {
            return;
        }

        $this->hookActionCartUpdateQuantityBefore();
    }

    /**
     * Add payment option at the checkout in the front office (prestashop 1.6)
     */
    public function hookDisplayPayment()
    {
        if (false === Validate::isLoadedObject($this->context->cart)
            || false === $this->checkCurrency($this->context->cart)
            || false === $this->merchantIsValid()
        ) {
            return '';
        }

        /** @var \PrestaShop\Module\PrestashopCheckout\FundingSource\FundingSourceProvider $fundingSourceProvider */
        $fundingSourceProvider = $this->getService(\PrestaShop\Module\PrestashopCheckout\FundingSource\FundingSourceProvider::class);
        $paymentOptions = [];

        foreach ($fundingSourceProvider->getAll() as $fundingSource) {
            $paymentOptions[$fundingSource->name] = $fundingSource->label;
        }

        /** @var \PrestaShop\Module\PrestashopCheckout\ShopContext $shopContext */
        $shopContext = $this->getService(\PrestaShop\Module\PrestashopCheckout\ShopContext::class);

        /** @var \PrestaShop\Module\PrestashopCheckout\Repository\PsCheckoutCartRepository $psCheckoutCartRepository */
        $psCheckoutCartRepository = $this->getService(\PrestaShop\Module\PrestashopCheckout\Repository\PsCheckoutCartRepository::class);

        /** @var PsCheckoutCart|false $psCheckoutCart */
        $psCheckoutCart = $psCheckoutCartRepository->findOneByCartId((int) $this->context->cart->id);

        /** @var \PrestaShop\Module\PrestashopCheckout\PayPal\PayPalConfiguration $configurationPayPal */
        $configurationPayPal = $this->getService(\PrestaShop\Module\PrestashopCheckout\PayPal\PayPalConfiguration::class);

        $isExpressCheckout = false !== $psCheckoutCart && $psCheckoutCart->isExpressCheckout && $psCheckoutCart->isOrderAvailable();

        $this->context->smarty->assign([
            'cancelTranslatedText' => $this->l('Choose another payment method'),
            'is17' => $shopContext->isShop17(),
            'isExpressCheckout' => $isExpressCheckout,
            'modulePath' => $this->getPathUri(),
            'paymentOptions' => $paymentOptions,
            'isHostedFieldsAvailable' => $configurationPayPal->isHostedFieldsEnabled() && in_array($configurationPayPal->getCardHostedFieldsStatus(), ['SUBSCRIBED', 'LIMITED'], true),
            'isOnePageCheckout16' => !$shopContext->isShop17() && (bool) Configuration::get('PS_ORDER_PROCESS_TYPE'),
            'spinnerPath' => $this->getPathUri() . 'views/img/tail-spin.svg',
            'loaderTranslatedText' => $this->l('Please wait, loading additional payment methods.'),
            'paypalLogoPath' => $this->getPathUri() . 'views/img/paypal_express.png',
            'translatedText' => strtr(
                $this->l('You have selected your [PAYPAL_ACCOUNT] PayPal account to proceed to the payment.'),
                [
                    '[PAYPAL_ACCOUNT]' => $this->context->cookie->__get('paypalEmail') ? $this->context->cookie->__get('paypalEmail') : '',
                ]
            ),
            'shoppingCartWarningPath' => $this->getPathUri() . 'views/img/shopping-cart-warning.svg',
            'warningTranslatedText' => $this->l('Warning'),
        ]);

        return $this->display(__FILE__, 'views/templates/hook/displayPayment.tpl');
    }

    /**
     * Add payment option at the checkout in the front office (prestashop 1.7)
     *
     * @param array{cookie: Cookie, cart: Cart, altern: int} $params
     *
     * @return array
     */
    public function hookPaymentOptions(array $params)
    {
        /** @var Cart $cart */
        $cart = $params['cart'];

        if (false === Validate::isLoadedObject($cart)
            || false === $this->checkCurrency($cart)
            || false === $this->merchantIsValid()
        ) {
            return [];
        }

        /** @var \PrestaShop\Module\PrestashopCheckout\FundingSource\FundingSourceProvider $fundingSourceProvider */
        $fundingSourceProvider = $this->getService(\PrestaShop\Module\PrestashopCheckout\FundingSource\FundingSourceProvider::class);

        /** @var \PrestaShop\Module\PrestashopCheckout\PayPal\PayPalConfiguration $configurationPayPal */
        $configurationPayPal = $this->getService(\PrestaShop\Module\PrestashopCheckout\PayPal\PayPalConfiguration::class);

        $paymentOptions = [];

        $vaultingEnabled = $configurationPayPal->isVaultingEnabled()
            && $this->context->customer->isLogged();

        $this->context->smarty->assign('lockIcon', Media::getMediaPath(_PS_MODULE_DIR_ . $this->name . '/views/img/icons/lock_fill.svg'));
        $vaultedPayPal = [];

        if ($vaultingEnabled) {
            foreach ($fundingSourceProvider->getSavedTokens($cart->id_customer) as $fundingSource) {
                if ($fundingSource->paymentSource === 'paypal') {
                    $vaultedPayPal = [
                        'paymentIdentifier' => $fundingSource->name,
                        'fundingSource' => $fundingSource->paymentSource,
                        'isFavorite' => $fundingSource->isFavorite,
                        'label' => $fundingSource->label,
                        'vaultId' => explode('-', $fundingSource->name)[1],
                    ];
                    continue;
                }
                $paymentOption = new PrestaShop\PrestaShop\Core\Payment\PaymentOption();
                $paymentOption->setModuleName($this->name . '-' . $fundingSource->name);
                $paymentOption->setCallToActionText($fundingSource->label);
                $paymentOption->setBinary(true);

                $this->context->smarty->assign([
                    'paymentIdentifier' => $fundingSource->name,
                    'fundingSource' => $fundingSource->paymentSource,
                    'isFavorite' => $fundingSource->isFavorite,
                    'label' => $fundingSource->label,
                    'vaultId' => explode('-', $fundingSource->name)[1],
                ]);
                $paymentOption->setForm($this->context->smarty->fetch('module:ps_checkout/views/templates/hook/partials/vaultTokenForm.tpl'));

                $paymentOptions[] = $paymentOption;
            }
        }

        foreach ($fundingSourceProvider->getAll() as $fundingSource) {
            $paymentOption = new PrestaShop\PrestaShop\Core\Payment\PaymentOption();
            $paymentOption->setModuleName($this->name . '-' . $fundingSource->name);
            $paymentOption->setCallToActionText($fundingSource->label);
            $paymentOption->setBinary(true);
            $this->context->smarty->assign([
                'vaultingEnabled' => $vaultingEnabled,
                'paymentIdentifier' => $fundingSource->name,
            ]);

            if ('card' === $fundingSource->name && $configurationPayPal->isHostedFieldsEnabled() && in_array($configurationPayPal->getCardHostedFieldsStatus(), ['SUBSCRIBED', 'LIMITED'], true)) {
                $this->context->smarty->assign('modulePath', $this->getPathUri());
                $paymentOption->setForm($this->context->smarty->fetch('module:ps_checkout/views/templates/hook/partials/cardFields.tpl'));
            } elseif ($fundingSource->name === 'paypal' && empty($vaultedPayPal)) {
                $paymentOption->setForm($this->context->smarty->fetch('module:ps_checkout/views/templates/hook/partials/vaultPaymentForm.tpl'));
            } elseif ($fundingSource->name === 'paypal' && $vaultedPayPal) {
                $this->context->smarty->assign($vaultedPayPal);
                $paymentOption->setForm($this->context->smarty->fetch('module:ps_checkout/views/templates/hook/partials/vaultTokenForm.tpl'));
            }

            $paymentOptions[] = $paymentOption;
        }

        return $paymentOptions;
    }

    /**
     * Hook executed at the order confirmation
     *
     * @param array{cookie: Cookie, cart: Cart, altern: int, order: Order, objOrder: Order} $params
     *
     * @return string
     */
    public function hookDisplayOrderConfirmation(array $params)
    {
        if (!$this->merchantIsValid()) {
            return '';
        }

        /** @var Order $order */
        $order = (isset($params['objOrder'])) ? $params['objOrder'] : $params['order'];

        if (!Validate::isLoadedObject($order) || $order->module !== $this->name) {
            return '';
        }

        /** @var \PrestaShop\Module\PrestashopCheckout\PayPal\Order\PayPalOrderSummaryViewBuilder $orderSummaryViewBuilder */
        $orderSummaryViewBuilder = $this->getService(\PrestaShop\Module\PrestashopCheckout\PayPal\Order\PayPalOrderSummaryViewBuilder::class);

        try {
            $orderSummaryView = $orderSummaryViewBuilder->build($order);
        } catch (Exception $e) {
            return '';
        }

        $this->context->smarty->assign($orderSummaryView->getTemplateVars());

        return $this->display(__FILE__, 'views/templates/hook/displayOrderConfirmation.tpl');
    }

    /**
     * Check if the module can process to a payment with the
     * current currency
     *
     * @param Cart $cart
     *
     * @return bool
     */
    public function checkCurrency($cart)
    {
        if (isset(static::$currencyIsAllowed[$cart->id_currency])) {
            return static::$currencyIsAllowed[$cart->id_currency];
        }

        /** @var \PrestaShop\Module\PrestashopCheckout\Repository\PayPalCodeRepository $codeRepository */
        $codeRepository = $this->getService(\PrestaShop\Module\PrestashopCheckout\Repository\PayPalCodeRepository::class);
        $currency_order = Currency::getCurrencyInstance($cart->id_currency);
        $isCurrencySupported = false;

        foreach (array_keys($codeRepository->getCurrencyCodes()) as $supportedCurrencyCode) {
            if (strcasecmp($supportedCurrencyCode, $currency_order->iso_code) === 0) {
                $isCurrencySupported = true;
            }
        }

        if (!$isCurrencySupported) {
            static::$currencyIsAllowed[$cart->id_currency] = false;

            return false;
        }

        /** @var array $currencies_module */
        $currencies_module = $this->getCurrency($cart->id_currency);

        if (empty($currencies_module)) {
            static::$currencyIsAllowed[$cart->id_currency] = false;

            return false;
        }

        foreach ($currencies_module as $currency_module) {
            if ($currency_order->id == $currency_module['id_currency']) {
                static::$currencyIsAllowed[$cart->id_currency] = true;

                return true;
            }
        }

        static::$currencyIsAllowed[$cart->id_currency] = false;

        return false;
    }

    /**
     * Hook used to display templates under BO header
     */
    public function hookDisplayAdminAfterHeader()
    {
        /** @var \PrestaShop\Module\PrestashopCheckout\PayPal\PayPalConfiguration $paypalConfiguration */
        $paypalConfiguration = $this->getService(\PrestaShop\Module\PrestashopCheckout\PayPal\PayPalConfiguration::class);
        /** @var \PrestaShop\Module\PrestashopCheckout\Repository\PsAccountRepository $psAccount */
        $psAccount = $this->getService(\PrestaShop\Module\PrestashopCheckout\Repository\PsAccountRepository::class);
        /** @var \PrestaShop\Module\PrestashopCheckout\ShopContext $shopContext */
        $shopContext = $this->getService(\PrestaShop\Module\PrestashopCheckout\ShopContext::class);
        /** @var \PrestaShop\Module\PrestashopCheckout\Presenter\Store\Modules\ContextModule $moduleContext */
        $moduleContext = $this->getService(\PrestaShop\Module\PrestashopCheckout\Presenter\Store\Modules\ContextModule::class);
        $isShop17 = $shopContext->isShop17();
        $isFullyOnboarded = $psAccount->onBoardingIsCompleted() && $paypalConfiguration->getMerchantId();

        if ('AdminPayment' === Tools::getValue('controller') && $isShop17) { // Display on PrestaShop 1.7.x.x only
            if (in_array($this->getShopDefaultCountryCode(), ['FR', 'IT'])
                && Module::isEnabled('ps_checkout')
                && Configuration::get('PS_CHECKOUT_PAYPAL_ID_MERCHANT')
            ) {
                return false;
            }

            $params = [
                'imgPath' => $this->_path . 'views/img/',
                'configureLink' => (new PrestaShop\Module\PrestashopCheckout\Adapter\LinkAdapter($this->context->link))->getAdminLink(
                    'AdminModules',
                    true,
                    [],
                    [
                        'configure' => 'ps_checkout',
                    ]
                ),
            ];
            $template = 'views/templates/hook/adminAfterHeader/promotionBlock.tpl';
        } elseif ('AdminCountries' === Tools::getValue('controller') && $isFullyOnboarded) {
            $params = [
                'isShop17' => $isShop17,
                'codesType' => 'countries',
                'incompatibleCodes' => $paypalConfiguration->getIncompatibleCountryCodes(),
                'paypalLink' => 'https://developer.paypal.com/docs/api/reference/country-codes/#',
                'paymentPreferencesLink' => $moduleContext->getGeneratedLink($isShop17 ? 'AdminPaymentPreferences' : 'AdminPayment'),
            ];
            $template = 'views/templates/hook/adminAfterHeader/incompatibleCodes.tpl';
        } elseif ('AdminCurrencies' === Tools::getValue('controller') && $isFullyOnboarded) {
            $params = [
                'isShop17' => $isShop17,
                'codesType' => 'currencies',
                'incompatibleCodes' => $paypalConfiguration->getIncompatibleCurrencyCodes(),
                'paypalLink' => 'https://developer.paypal.com/docs/api/reference/currency-codes/#',
                'paymentPreferencesLink' => $moduleContext->getGeneratedLink($isShop17 ? 'AdminPaymentPreferences' : 'AdminPayment'),
            ];
            $template = 'views/templates/hook/adminAfterHeader/incompatibleCodes.tpl';
        } else {
            return false;
        }

        $this->context->smarty->assign($params);

        return $this->display(__FILE__, $template);
    }

    /**
     * Load asset on the back office
     */
    public function hookActionAdminControllerSetMedia()
    {
        /** @var \PrestaShop\Module\PrestashopCheckout\Version\Version $version */
        $version = $this->getService('ps_checkout.module.version');

        if ('AdminModules' === Tools::getValue('controller') && 'ps_checkout' === Tools::getValue('configure')) {
            $this->context->controller->addCss(
                $this->_path . 'views/css/adminModules.css?version=' . $version->getSemVersion(),
                'all',
                null,
                false
            );
        }

        if ('AdminPayment' === Tools::getValue('controller')) {
            $this->context->controller->addCss(
                $this->_path . 'views/css/adminAfterHeader.css?version=' . $version->getSemVersion(),
                'all',
                null,
                false
            );
        }

        if ('AdminCountries' === Tools::getValue('controller')) {
            $this->context->controller->addCss(
                $this->_path . 'views/css/incompatible-banner.css?version=' . $version->getSemVersion(),
                'all',
                null,
                false
            );
        }

        if ('AdminCurrencies' === Tools::getValue('controller')) {
            $this->context->controller->addCss(
                $this->_path . 'views/css/incompatible-banner.css?version=' . $version->getSemVersion(),
                'all',
                null,
                false
            );
        }

        if ('AdminOrders' === Tools::getValue('controller') || 'AdminOrders' === Tools::getValue('tab')) {
            $this->context->controller->addJS(
                $this->getPathUri() . 'views/js/adminOrderView.js?version=' . $version->getSemVersion(),
                false
            );
            $this->context->controller->addCss(
                $this->_path . 'views/css/adminOrderView.css?version=' . $version->getSemVersion(),
                'all',
                null,
                false
            );
        }
    }

    /**
     * Check if paypal and ps account are valid
     *
     * @return bool
     */
    public function merchantIsValid()
    {
        if (static::$merchantIsValid === null) {
            /** @var \PrestaShop\Module\PrestashopCheckout\Validator\MerchantValidator $merchantValidator */
            $merchantValidator = $this->getService(\PrestaShop\Module\PrestashopCheckout\Validator\MerchantValidator::class);
            static::$merchantIsValid = $merchantValidator->merchantIsValid();
        }

        return static::$merchantIsValid;
    }

    /**
     * Load asset on the front office
     */
    public function hookActionFrontControllerSetMedia()
    {
        $controller = (string) Tools::getValue('controller');

        if (empty($controller) && isset($this->context->controller->php_self)) {
            $controller = $this->context->controller->php_self;
        }

        /** @var \PrestaShop\Module\PrestashopCheckout\Validator\FrontControllerValidator $frontControllerValidator */
        $frontControllerValidator = $this->getService(\PrestaShop\Module\PrestashopCheckout\Validator\FrontControllerValidator::class);

        /** @var \PrestaShop\Module\PrestashopCheckout\Version\Version $version */
        $version = $this->getService('ps_checkout.module.version');

        if ($frontControllerValidator->shouldLoadFrontCss($controller)) {
            if (method_exists($this->context->controller, 'registerStylesheet')) {
                $this->context->controller->registerStylesheet(
                    'ps-checkout-css-paymentOptions',
                    $this->getPathUri() . 'views/css/payments.css?version=' . $version->getSemVersion(),
                    [
                        'server' => 'remote',
                    ]
                );
            } else {
                $this->context->controller->addCss(
                    $this->getPathUri() . 'views/css/payments16.css?version=' . $version->getSemVersion(),
                    'all',
                    null,
                    false
                );
            }
        }

        if (false === $frontControllerValidator->shouldLoadFrontJS($controller)) {
            return;
        }

        /** @var \PrestaShop\Module\PrestashopCheckout\PayPal\Sdk\PayPalSdkConfigurationBuilder $payPalSdkConfigurationBuilder */
        $payPalSdkConfigurationBuilder = $this->getService(\PrestaShop\Module\PrestashopCheckout\PayPal\Sdk\PayPalSdkConfigurationBuilder::class);

        /** @var \PrestaShop\Module\PrestashopCheckout\ExpressCheckout\ExpressCheckoutConfiguration $expressCheckoutConfiguration */
        $expressCheckoutConfiguration = $this->getService(\PrestaShop\Module\PrestashopCheckout\ExpressCheckout\ExpressCheckoutConfiguration::class);

        /** @var \PrestaShop\Module\PrestashopCheckout\PayPal\PayPalConfiguration $payPalConfiguration */
        $payPalConfiguration = $this->getService(\PrestaShop\Module\PrestashopCheckout\PayPal\PayPalConfiguration::class);

        /** @var \PrestaShop\Module\PrestashopCheckout\FundingSource\FundingSourceProvider $fundingSourceProvider */
        $fundingSourceProvider = $this->getService(\PrestaShop\Module\PrestashopCheckout\FundingSource\FundingSourceProvider::class);

        /** @var \PrestaShop\Module\PrestashopCheckout\PayPal\PayPalPayLaterConfiguration $payLaterConfiguration */
        $payLaterConfiguration = $this->getService(\PrestaShop\Module\PrestashopCheckout\PayPal\PayPalPayLaterConfiguration::class);

        /** @var \PrestaShop\Module\PrestashopCheckout\ShopContext $shopContext */
        $shopContext = $this->getService(\PrestaShop\Module\PrestashopCheckout\ShopContext::class);

        /** @var \PrestaShop\Module\PrestashopCheckout\Version\Version $version */
        $version = $this->getService('ps_checkout.module.version');

        $advancedCheckoutEligibility = new \PrestaShop\Module\PrestashopCheckout\PayPal\AdvancedCheckoutEligibility();
        $supportedCardBrands = $advancedCheckoutEligibility->getSupportedCardBrands();

        if (Validate::isLoadedObject($this->context->currency) && Validate::isLoadedObject($this->context->country)) {
            $supportedCardBrandsByContext = $advancedCheckoutEligibility->getSupportedCardBrandsByContext(
                $this->context->country->iso_code === 'GB' ? 'UK' : $this->context->country->iso_code,
                $this->context->currency->iso_code
            );
            $supportedCardBrands = $supportedCardBrandsByContext ? $supportedCardBrandsByContext : $supportedCardBrands;
        }

        $fundingSourcesSorted = [];
        $payWithTranslations = [];
        $isCardAvailable = false;
        $customMarks = [];

        foreach ($fundingSourceProvider->getSavedTokens($this->context->customer->id) as $fundingSource) {
            $fundingSourcesSorted[] = $fundingSource->name;
            $payWithTranslations[$fundingSource->name] = $fundingSource->label;
            $customMarks[$fundingSource->name] = $fundingSource->customMark;
        }

        foreach ($fundingSourceProvider->getAll() as $fundingSource) {
            $fundingSourcesSorted[] = $fundingSource->name;
            $payWithTranslations[$fundingSource->name] = $fundingSource->label;

            if ($fundingSource->customMark !== null) {
                $customMarks[$fundingSource->name] = $fundingSource->customMark;
            }

            if ('card' === $fundingSource->name) {
                $isCardAvailable = $fundingSource->isEnabled;
            }
        }

        // BEGIN To be refactored in services
        $payPalOrderId = '';
        $cartFundingSource = 'paypal';
        $psCheckoutCart = false;
        $cartProductCount = 0;

        // Sometimes we can be in Front Office without a cart...
        if (Validate::isLoadedObject($this->context->cart)) {
            $cartProductCount = (int) $this->context->cart->nbProducts();
            /** @var \PrestaShop\Module\PrestashopCheckout\Repository\PsCheckoutCartRepository $psCheckoutCartRepository */
            $psCheckoutCartRepository = $this->getService(\PrestaShop\Module\PrestashopCheckout\Repository\PsCheckoutCartRepository::class);

            /** @var PsCheckoutCart|false $psCheckoutCart */
            $psCheckoutCart = $psCheckoutCartRepository->findOneByCartId((int) $this->context->cart->id);
        }

        if (false !== $psCheckoutCart && $psCheckoutCart->isOrderAvailable()) {
            $payPalOrderId = $psCheckoutCart->getPaypalOrderId();
            $cartFundingSource = $psCheckoutCart->getPaypalFundingSource();
        }
        // END To be refactored in services

        Media::addJsDef([
            $this->name . 'Version' => $version->getSemVersion(),
            $this->name . 'LanguageIsoCode' => $this->context->language->iso_code,
            $this->name . 'AutoRenderDisabled' => (bool) Configuration::get('PS_CHECKOUT_AUTO_RENDER_DISABLED'),
            $this->name . 'LoaderImage' => $this->getPathUri() . 'views/img/loader.svg',
            $this->name . 'PayPalButtonConfiguration' => $payPalConfiguration->getButtonConfiguration(),
            $this->name . 'CardFundingSourceImg' => Media::getMediaPath(_PS_MODULE_DIR_ . $this->name . '/views/img/payment-cards.png'),
            $this->name . 'CustomMarks' => $customMarks,
            $this->name . 'CardLogos' => [
                'AMEX' => Media::getMediaPath(_PS_MODULE_DIR_ . $this->name . '/views/img/amex.svg'),
                'CB_NATIONALE' => Media::getMediaPath(_PS_MODULE_DIR_ . $this->name . '/views/img/cb.svg'),
                'DINERS' => Media::getMediaPath(_PS_MODULE_DIR_ . $this->name . '/views/img/diners.svg'),
                'DISCOVER' => Media::getMediaPath(_PS_MODULE_DIR_ . $this->name . '/views/img/discover.svg'),
                'JCB' => Media::getMediaPath(_PS_MODULE_DIR_ . $this->name . '/views/img/jcb.svg'),
                'MAESTRO' => Media::getMediaPath(_PS_MODULE_DIR_ . $this->name . '/views/img/maestro.svg'),
                'MASTERCARD' => Media::getMediaPath(_PS_MODULE_DIR_ . $this->name . '/views/img/mastercard.svg'),
                'UNIONPAY' => Media::getMediaPath(_PS_MODULE_DIR_ . $this->name . '/views/img/unionpay.svg'),
                'VISA' => Media::getMediaPath(_PS_MODULE_DIR_ . $this->name . '/views/img/visa.svg'),
            ],
            $this->name . 'CardBrands' => $supportedCardBrands,
            $this->name . 'PaymentMethodLogosTitleImg' => Media::getMediaPath(_PS_MODULE_DIR_ . $this->name . '/views/img/lock_checkout.svg'),
            $this->name . 'IconsPath' => Media::getMediaPath(_PS_MODULE_DIR_ . $this->name . '/views/img/icons/'),
            $this->name . 'CreateUrl' => $this->context->link->getModuleLink($this->name, 'create', [], true),
            $this->name . 'CheckUrl' => $this->context->link->getModuleLink($this->name, 'check', [], true),
            $this->name . 'ValidateUrl' => $this->context->link->getModuleLink($this->name, 'validate', [], true),
            $this->name . 'CancelUrl' => $this->context->link->getModuleLink($this->name, 'cancel', [], true),
            $this->name . 'ExpressCheckoutUrl' => $this->context->link->getModuleLink($this->name, 'ExpressCheckout', [], true),
            $this->name . 'VaultUrl' => $this->context->link->getModuleLink($this->name, 'vault', [], true),
            $this->name . 'PaymentUrl' => $this->context->link->getModuleLink($this->name, 'payment', [], true),
            $this->name . 'GooglePayUrl' => $this->context->link->getModuleLink($this->name, 'googlepay', [], true),
            $this->name . 'ApplePayUrl' => $this->context->link->getModuleLink($this->name, 'applepay', [], true),
            $this->name . 'CheckoutUrl' => $this->getCheckoutPageUrl(),
            $this->name . 'ConfirmUrl' => $this->context->link->getPageLink('order-confirmation', true, (int) $this->context->language->id),
            $this->name . 'PayPalSdkConfig' => $payPalSdkConfigurationBuilder->buildConfiguration(),
            $this->name . 'PayPalOrderId' => $payPalOrderId,
            $this->name . 'FundingSource' => $cartFundingSource,
            $this->name . 'HostedFieldsEnabled' => $isCardAvailable && $payPalConfiguration->isHostedFieldsEnabled() && in_array($payPalConfiguration->getCardHostedFieldsStatus(), ['SUBSCRIBED', 'LIMITED'], true),
            $this->name . 'HostedFieldsSelected' => false !== $psCheckoutCart && $psCheckoutCart->isHostedFields(),
            $this->name . 'HostedFieldsContingencies' => $payPalConfiguration->getHostedFieldsContingencies(),
            $this->name . 'PayPalEnvironment' => $payPalConfiguration->getPaymentMode(),
            $this->name . 'ExpressCheckoutSelected' => false !== $psCheckoutCart && $psCheckoutCart->isExpressCheckout(),
            $this->name . 'ExpressCheckoutProductEnabled' => $expressCheckoutConfiguration->isProductPageEnabled() && $payPalConfiguration->isPayPalPaymentsReceivable(),
            $this->name . 'ExpressCheckoutCartEnabled' => $expressCheckoutConfiguration->isOrderPageEnabled() && $payPalConfiguration->isPayPalPaymentsReceivable(),
            $this->name . 'ExpressCheckoutOrderEnabled' => $expressCheckoutConfiguration->isCheckoutPageEnabled() && $payPalConfiguration->isPayPalPaymentsReceivable(),
            $this->name . 'PayLaterProductPageMessageEnabled' => $payLaterConfiguration->isProductPageMessageActive() && $payPalConfiguration->isPayPalPaymentsReceivable(),
            $this->name . 'PayLaterOrderPageMessageEnabled' => $payLaterConfiguration->isOrderPageMessageActive() && $payPalConfiguration->isPayPalPaymentsReceivable(),
            $this->name . 'PayLaterHomePageBannerEnabled' => $payLaterConfiguration->isHomePageBannerActive() && $payPalConfiguration->isPayPalPaymentsReceivable(),
            $this->name . 'PayLaterCategoryPageBannerEnabled' => $payLaterConfiguration->isCategoryPageBannerActive() && $payPalConfiguration->isPayPalPaymentsReceivable(),
            $this->name . 'PayLaterProductPageBannerEnabled' => $payLaterConfiguration->isProductPageBannerActive() && $payPalConfiguration->isPayPalPaymentsReceivable(),
            $this->name . 'PayLaterOrderPageBannerEnabled' => $payLaterConfiguration->isOrderPageBannerActive() && $payPalConfiguration->isPayPalPaymentsReceivable(),
            $this->name . 'PayLaterProductPageButtonEnabled' => $payLaterConfiguration->isProductPageButtonActive() && $payPalConfiguration->isPayPalPaymentsReceivable(),
            $this->name . 'PayLaterCartPageButtonEnabled' => $payLaterConfiguration->isCartPageButtonActive() && $payPalConfiguration->isPayPalPaymentsReceivable(),
            $this->name . 'PayLaterOrderPageButtonEnabled' => $payLaterConfiguration->isOrderPageButtonActive() && $payPalConfiguration->isPayPalPaymentsReceivable(),
            $this->name . '3dsEnabled' => $payPalConfiguration->is3dSecureEnabled(),
            $this->name . 'CspNonce' => $payPalConfiguration->getCSPNonce(),
            $this->name . 'PartnerAttributionId' => $shopContext->getBnCode(),
            $this->name . 'CartProductCount' => $cartProductCount,
            $this->name . 'RenderPaymentMethodLogos' => $frontControllerValidator->shouldDisplayFundingLogo($controller),
            $this->name . 'FundingSourcesSorted' => $fundingSourcesSorted,
            $this->name . 'PayWithTranslations' => $payWithTranslations,
            $this->name . 'CheckoutTranslations' => [
                'checkout.go.back.link.title' => $this->l('Go back to the Checkout'),
                'checkout.go.back.label' => $this->l('Checkout'),
                'checkout.card.payment' => $this->l('Card payment'),
                'checkout.page.heading' => $this->l('Order summary'),
                'checkout.cart.empty' => $this->l('Your shopping cart is empty.'),
                'checkout.page.subheading.card' => $this->l('Card'),
                'checkout.page.subheading.paypal' => $this->l('PayPal'),
                'checkout.payment.by.card' => $this->l('You have chosen to pay by Card.'),
                'checkout.payment.by.paypal' => $this->l('You have chosen to pay by PayPal.'),
                'checkout.order.summary' => $this->l('Here is a short summary of your order:'),
                'checkout.order.amount.total' => $this->l('The total amount of your order comes to'),
                'checkout.order.included.tax' => $this->l('(tax incl.)'),
                'checkout.order.confirm.label' => $this->l('Please confirm your order by clicking "I confirm my order".'),
                'paypal.hosted-fields.label.card-name' => $this->l('Card holder name'),
                'paypal.hosted-fields.placeholder.card-name' => $this->l('Card holder name'),
                'paypal.hosted-fields.label.card-number' => $this->l('Card number'),
                'paypal.hosted-fields.placeholder.card-number' => $this->l('Card number'),
                'paypal.hosted-fields.label.expiration-date' => $this->l('Expiry date'),
                'paypal.hosted-fields.placeholder.expiration-date' => $this->l('MM/YY'),
                'paypal.hosted-fields.label.cvv' => $this->l('CVC'),
                'paypal.hosted-fields.placeholder.cvv' => $this->l('XXX'),
                'payment-method-logos.title' => $this->l('100% secure payments'),
                'express-button.cart.separator' => $this->l('or'),
                'express-button.checkout.express-checkout' => $this->l('Express Checkout'),
                'error.paypal-sdk' => $this->l('No PayPal Javascript SDK Instance'),
                'error.google-pay-sdk' => $this->l('No Google Pay Javascript SDK Instance'),
                'error.google-pay.transaction-info' => $this->l('An error occurred fetching Google Pay transaction info'),
                'error.apple-pay-sdk' => $this->l('No Apple Pay Javascript SDK Instance'),
                'error.apple-pay.payment-request' => $this->l('An error occurred fetching Apple Pay payment request'),
                'checkout.payment.others.link.label' => $this->l('Other payment methods'),
                'checkout.payment.others.confirm.button.label' => $this->l('I confirm my order'),
                'checkout.form.error.label' => $this->l('There was an error during the payment. Please try again or contact the support.'),
                'loader-component.label.header' => $this->l('Thanks for your purchase!'),
                'loader-component.label.body' => $this->l('Please wait, we are processing your payment'),
                'loader-component.label.body.longer' => $this->l('This is taking longer than expected. Please wait...'),
                'error.paypal-sdk.contingency.cancel' => $this->l('Card holder authentication canceled, please choose another payment method or try again.'),
                'error.paypal-sdk.contingency.error' => $this->l('An error occurred on card holder authentication, please choose another payment method or try again.'),
                'error.paypal-sdk.contingency.failure' => $this->l('Card holder authentication failed, please choose another payment method or try again.'),
                'error.paypal-sdk.contingency.unknown' => $this->l('Card holder authentication cannot be checked, please choose another payment method or try again.'),
                'ok' => $this->l('Ok'),
                'cancel' => $this->l('Cancel'),
                'checkout.payment.token.delete.modal.header' => $this->l('Delete this payment method?'),
                'checkout.payment.token.delete.modal.content' => $this->l('The following payment method will be deleted from your account:'),
                'checkout.payment.token.delete.modal.confirm-button' => $this->l('Delete payment method'),
                'checkout.payment.loader.processing-request' => $this->l('Please wait, we are processing your request'),
                'APPLE_PAY_MERCHANT_SESSION_VALIDATION_ERROR' => $this->l('We’re unable to process your Apple Pay payment at the moment. This could be due to an issue verifying the payment setup for this website. Please try again later or choose a different payment method.'),
                'APPROVE_APPLE_PAY_VALIDATION_ERROR' => $this->l('We encountered an issue while processing your Apple Pay payment. Please verify your order details and try again, or use a different payment method.'),
            ],
        ]);

        /** @var \PrestaShop\Module\PrestashopCheckout\Environment\Env $env */
        $env = $this->getService(\PrestaShop\Module\PrestashopCheckout\Environment\Env::class);

        $foSdkUrl = $env->getEnv('CHECKOUT_FO_SDK_URL');
        if (substr($foSdkUrl, -3) !== '.js') {
            $foSdkVersion = $env->getEnv('CHECKOUT_FO_SDK_VERSION');
            if (empty($foSdkVersion)) {
                /** @var \PrestaShop\Module\PrestashopCheckout\Version\Version $version */
                $version = $this->getService('ps_checkout.module.version');
                $majorModuleVersion = explode('.', $version->getSemVersion())[0];
                $foSdkVersion = "$majorModuleVersion.X.X";
            }

            $foSdkUrl = $foSdkUrl . $foSdkVersion . '/sdk/ps_checkout-fo-sdk.js';
        }

        if (method_exists($this->context->controller, 'registerJavascript')) {
            $this->context->controller->registerJavascript(
                $this->name . 'Front',
                $foSdkUrl,
                [
                    'position' => 'bottom',
                    'priority' => 201,
                    'server' => 'remote',
                ]
            );
        } else {
            $this->context->controller->addJS($foSdkUrl, false);
        }
    }

    /**
     * Override method to add "IGNORE" in the SQL Request to prevent duplicate entry and for getting All Carriers installed
     * Add checkbox carrier restrictions for a new module.
     *
     * @see PaymentModuleCore
     *
     * @param array $shopsList List of Shop identifier
     *
     * @return bool
     */
    public function addCheckboxCarrierRestrictionsForModule(array $shopsList = [])
    {
        /** @var \PrestaShop\Module\PrestashopCheckout\ShopContext $shopContext */
        $shopContext = $this->getService(\PrestaShop\Module\PrestashopCheckout\ShopContext::class);
        if (false === $shopContext->isShop17()) {
            return true;
        }

        $shopsList = empty($shopsList) ? Shop::getShops(true, null, true) : $shopsList;
        $carriersList = Carrier::getCarriers((int) Context::getContext()->language->id, false, false, false, null, Carrier::ALL_CARRIERS);
        $allCarriers = array_column($carriersList, 'id_reference');
        $dataToInsert = [];

        foreach ($shopsList as $idShop) {
            foreach ($allCarriers as $idCarrier) {
                $dataToInsert[] = [
                    'id_reference' => (int) $idCarrier,
                    'id_shop' => (int) $idShop,
                    'id_module' => (int) $this->id,
                ];
            }
        }

        return \Db::getInstance()->insert(
            'module_carrier',
            $dataToInsert,
            false,
            true,
            Db::INSERT_IGNORE
        );
    }

    /**
     * Override method to add "IGNORE" in the SQL Request to prevent duplicate entry.
     * Add checkbox country restrictions for a new module.
     * Associate with all countries allowed in geolocation management
     *
     * @see PaymentModuleCore
     *
     * @param array $shopsList List of Shop identifier
     *
     * @return bool
     */
    public function addCheckboxCountryRestrictionsForModule(array $shopsList = [])
    {
        parent::addCheckboxCountryRestrictionsForModule($shopsList);
        // Then add all countries allowed in geolocation management
        $db = \Db::getInstance();
        // Get active shop ids
        $shopsList = empty($shopsList) ? Shop::getShops(true, null, true) : $shopsList;
        // Get countries
        /** @var array $countries */
        $countries = $db->executeS('SELECT `id_country`, `iso_code` FROM `' . _DB_PREFIX_ . 'country`');
        $countryIdByIso = [];
        foreach ($countries as $country) {
            $countryIdByIso[$country['iso_code']] = $country['id_country'];
        }
        $dataToInsert = [];

        foreach ($shopsList as $idShop) {
            // Get countries allowed in geolocation management for this shop
            $activeCountries = \Configuration::get(
                'PS_ALLOWED_COUNTRIES',
                null,
                null,
                (int) $idShop
            );
            $explodedCountries = explode(';', $activeCountries);

            foreach ($explodedCountries as $isoCodeCountry) {
                if (isset($countryIdByIso[$isoCodeCountry])) {
                    $dataToInsert[] = [
                        'id_country' => (int) $countryIdByIso[$isoCodeCountry],
                        'id_shop' => (int) $idShop,
                        'id_module' => (int) $this->id,
                    ];
                }
            }
        }

        return $db->insert(
            'module_country',
            $dataToInsert,
            false,
            true,
            Db::INSERT_IGNORE
        );
    }

    /**
     * @return \Psr\Log\LoggerInterface
     */
    public function getLogger()
    {
        if (null === $this->logger) {
            $this->logger = $this->getService('ps_checkout.logger');
        }

        return $this->logger;
    }

    /**
     * This hook allows to add PayPal OrderId and TransactionId on PDF invoice
     *
     * @param array{cookie: Cookie, cart: Cart, altern: int, order: Order} $params
     *
     * @return string HTML is not allowed in this hook
     */
    public function hookDisplayInvoiceLegalFreeText(array $params)
    {
        if (!$this->merchantIsValid()) {
            return '';
        }

        /** @var \Order $order */
        $order = $params['order'];

        // This order has not been paid with this module
        if (false === Validate::isLoadedObject($order)
            || $this->name !== $order->module
        ) {
            return '';
        }

        /** @var \PrestaShop\Module\PrestashopCheckout\Repository\PsCheckoutCartRepository $psCheckoutCartRepository */
        $psCheckoutCartRepository = $this->getService(\PrestaShop\Module\PrestashopCheckout\Repository\PsCheckoutCartRepository::class);

        /** @var PsCheckoutCart|false $psCheckoutCart */
        $psCheckoutCart = $psCheckoutCartRepository->findOneByCartId((int) $order->id_cart);

        /** @var \PrestaShop\Module\PrestashopCheckout\Configuration\PrestaShopConfiguration $psConfiguration */
        $psConfiguration = $this->getService(\PrestaShop\Module\PrestashopCheckout\Configuration\PrestaShopConfiguration::class);

        // No PayPal Order found for this Order
        if (false === $psCheckoutCart) {
            return '';
        }

        $legalFreeText = $psConfiguration->get(
            'PS_INVOICE_LEGAL_FREE_TEXT',
            [
                'id_lang' => (int) $order->id_lang,
                'id_shop' => (int) $order->id_shop,
                'default' => '',
            ]
        );

        // If a legal free text is found, we add blank lines after
        if (false === empty($legalFreeText)) {
            $legalFreeText .= PHP_EOL . PHP_EOL;
        }

        /** @var \PrestaShop\Module\PrestashopCheckout\PayPal\Order\PayPalOrderTranslationProvider $translationService */
        $translationService = $this->getService(\PrestaShop\Module\PrestashopCheckout\PayPal\Order\PayPalOrderTranslationProvider::class);
        $translations = $translationService->getSummaryTranslations();

        $legalFreeText .= $translations['blockTitle'] . PHP_EOL;
        $legalFreeText .= $translations['orderIdentifier'] . ' ' . $psCheckoutCart->getPaypalOrderId() . PHP_EOL;
        $legalFreeText .= $translations['orderStatus'] . ' ' . $psCheckoutCart->getPaypalStatus() . PHP_EOL;

        /** @var \OrderPayment[] $orderPayments */
        $orderPayments = $order->getOrderPaymentCollection();

        foreach ($orderPayments as $orderPayment) {
            if (false === empty($orderPayment->transaction_id)) {
                $legalFreeText .= $translations['transactionIdentifier'] . ' ' . $orderPayment->transaction_id . PHP_EOL;
            }
        }

        return $legalFreeText;
    }

    /**
     * This hook called after a new Shop is created
     *
     * @param array{cookie: Cookie, cart: Cart, altern: int, object: Shop} $params
     */
    public function hookActionObjectShopAddAfter(array $params)
    {
        /** @var Shop $shop */
        $shop = $params['object'];
        $now = date('Y-m-d H:i:s');

        $toggleShopConfigurationCommandHandler = new \PrestaShop\Module\PrestashopCheckout\Configuration\ToggleShopConfigurationCommandHandler();
        $toggleShopConfigurationCommandHandler->handle(
            new \PrestaShop\Module\PrestashopCheckout\Configuration\ToggleShopConfigurationCommand(
                (int) Configuration::get('PS_SHOP_DEFAULT'),
                (bool) Shop::isFeatureActive()
            )
        );

        foreach ($this->configurationList as $name => $value) {
            if (Configuration::hasKey($name, null, (int) $shop->id_shop_group, (int) $shop->id)) {
                Db::getInstance()->update(
                    'configuration',
                    [
                        'name' => pSQL($name),
                        'value' => pSQL($value),
                        'date_add' => pSQL($now),
                        'date_upd' => pSQL($now),
                        'id_shop' => (int) $shop->id,
                        'id_shop_group' => (int) $shop->id_shop_group,
                    ],
                    'name = \'' . pSQL($name) . '\', id_shop = ' . (int) $shop->id . ', id_shop_group = ' . (int) $shop->id_shop_group,
                    1,
                    true,
                    false
                );
            } else {
                Db::getInstance()->insert(
                    'configuration',
                    [
                        'name' => pSQL($name),
                        'value' => pSQL($value),
                        'date_add' => pSQL($now),
                        'date_upd' => pSQL($now),
                        'id_shop' => (int) $shop->id,
                        'id_shop_group' => (int) $shop->id_shop_group,
                    ],
                    true,
                    false
                );
            }

            Configuration::set($name, $value, (int) $shop->id_shop_group, (int) $shop->id);
        }

        (new PrestaShop\Module\PrestashopCheckout\FundingSource\FundingSourceInstaller())->createFundingSources((int) $shop->id);
        $this->addCheckboxCarrierRestrictionsForModule([(int) $shop->id]);
        $this->addCheckboxCountryRestrictionsForModule([(int) $shop->id]);

        if ($this->currencies_mode === 'checkbox') {
            $this->addCheckboxCurrencyRestrictionsForModule([(int) $shop->id]);
        } elseif ($this->currencies_mode === 'radio') {
            $this->addRadioCurrencyRestrictionsForModule([(int) $shop->id]);
        }
    }

    /**
     * This hook called on BO Order view page before 1.7.7
     *
     * @param array{cookie: Cookie, cart: Cart, altern: int, id_order: int} $params
     *
     * @return string
     */
    public function hookDisplayAdminOrderLeft(array $params)
    {
        $order = new Order((int) $params['id_order']);

        if ($order->module !== $this->name) {
            return '';
        }

        $this->context->smarty->assign([
            'moduleLogoUri' => $this->getPathUri() . 'logo.png',
            'moduleName' => $this->displayName,
            'orderPrestaShopId' => $order->id,
            'orderPayPalBaseUrl' => $this->context->link->getAdminLink('AdminAjaxPrestashopCheckout'),
        ]);

        return $this->display(__FILE__, 'views/templates/hook/displayAdminOrderLeft.tpl');
    }

    /**
     * This hook called on BO Order view page after 1.7.7
     *
     * @param array{cookie: Cookie, cart: Cart, altern: int, id_order: int} $params
     *
     * @return string
     */
    public function hookDisplayAdminOrderMainBottom(array $params)
    {
        $order = new Order((int) $params['id_order']);

        if ($order->module !== $this->name) {
            return '';
        }

        $this->context->smarty->assign([
            'moduleLogoUri' => $this->getPathUri() . 'logo.png',
            'moduleName' => $this->displayName,
            'orderPrestaShopId' => $order->id,
            'orderPayPalBaseUrl' => $this->context->link->getAdminLink('AdminAjaxPrestashopCheckout'),
        ]);

        return $this->display(__FILE__, 'views/templates/hook/displayAdminOrderMainBottom.tpl');
    }

    /**
     * This hook display a block on top of PaymentOptions on PrestaShop 1.7
     *
     * @return string
     */
    public function hookDisplayPaymentTop()
    {
        if (false === Validate::isLoadedObject($this->context->cart)
            || false === $this->checkCurrency($this->context->cart)
            || false === $this->merchantIsValid()
        ) {
            return '';
        }

        /** @var \PrestaShop\Module\PrestashopCheckout\ShopContext $shopContext */
        $shopContext = $this->getService(\PrestaShop\Module\PrestashopCheckout\ShopContext::class);

        /** @var \PrestaShop\Module\PrestashopCheckout\Repository\PsCheckoutCartRepository $psCheckoutCartRepository */
        $psCheckoutCartRepository = $this->getService(\PrestaShop\Module\PrestashopCheckout\Repository\PsCheckoutCartRepository::class);

        /** @var PsCheckoutCart|false $psCheckoutCart */
        $psCheckoutCart = $psCheckoutCartRepository->findOneByCartId((int) $this->context->cart->id);

        $isExpressCheckout = false !== $psCheckoutCart && $psCheckoutCart->isExpressCheckout && $psCheckoutCart->isOrderAvailable();

        $this->context->smarty->assign([
            'cancelTranslatedText' => $this->l('Choose another payment method'),
            'is17' => $shopContext->isShop17(),
            'isExpressCheckout' => $isExpressCheckout,
            'isOnePageCheckout16' => !$shopContext->isShop17() && (bool) Configuration::get('PS_ORDER_PROCESS_TYPE'),
            'spinnerPath' => $this->getPathUri() . 'views/img/tail-spin.svg',
            'loaderTranslatedText' => $this->l('Please wait, loading additional payment methods.'),
            'paypalLogoPath' => $this->getPathUri() . 'views/img/paypal_express.png',
            'translatedText' => strtr(
                $this->l('You have selected your [PAYPAL_ACCOUNT] PayPal account to proceed to the payment.'),
                [
                    '[PAYPAL_ACCOUNT]' => $this->context->cookie->__get('paypalEmail') ? $this->context->cookie->__get('paypalEmail') : '',
                ]
            ),
            'shoppingCartWarningPath' => $this->getPathUri() . 'views/img/shopping-cart-warning.svg',
            'warningTranslatedText' => $this->l('Warning'),
        ]);

        return $this->display(__FILE__, 'views/templates/hook/displayPaymentTop.tpl');
    }

    /**
     * @param string $serviceName
     *
     * @return object|null
     */
    public function getService($serviceName)
    {
        if ($this->serviceContainer === null) {
            $this->serviceContainer = new \PrestaShop\ModuleLibServiceContainer\DependencyInjection\ServiceContainer(
                $this->name . str_replace(['.', '-', '+'], '', $this->version),
                $this->getLocalPath()
            );
        }

        return $this->serviceContainer->getService($serviceName);
    }

    /**
     * This hook displays form generated by binaries during the checkout
     *
     * @param array{cookie: Cookie, cart: Cart, altern: int} $params
     *
     * @return string
     */
    public function hookDisplayPaymentByBinaries(array $params)
    {
        /** @var Cart $cart */
        $cart = $params['cart'];

        if (false === Validate::isLoadedObject($cart)
            || false === $this->checkCurrency($cart)
            || false === $this->merchantIsValid()
        ) {
            return '';
        }

        /** @var \PrestaShop\Module\PrestashopCheckout\FundingSource\FundingSourceProvider $fundingSourceProvider */
        $fundingSourceProvider = $this->getService(\PrestaShop\Module\PrestashopCheckout\FundingSource\FundingSourceProvider::class);
        $paymentOptions = [];

        foreach ($fundingSourceProvider->getSavedTokens($cart->id_customer) as $fundingSource) {
            $paymentOptions[] = $fundingSource->name;
        }

        foreach ($fundingSourceProvider->getAll() as $fundingSource) {
            $paymentOptions[] = $fundingSource->name;
        }

        $this->context->smarty->assign([
            'paymentOptions' => $paymentOptions,
        ]);

        return $this->display(__FILE__, 'views/templates/hook/displayPaymentByBinaries.tpl');
    }

    /**
     * Provide checkout page link
     *
     * @return string
     */
    private function getCheckoutPageUrl()
    {
        /** @var \PrestaShop\Module\PrestashopCheckout\ShopContext $shopContext */
        $shopContext = $this->getService(\PrestaShop\Module\PrestashopCheckout\ShopContext::class);

        if ($shopContext->isShop17()) {
            return $this->context->link->getPageLink(
                'order',
                true,
                (int) $this->context->language->id
            );
        }

        // PrestaShop 1.6 legacy native one page checkout
        if (1 === (int) Configuration::get('PS_ORDER_PROCESS_TYPE')) {
            return $this->context->link->getPageLink(
                'order-opc',
                true,
                (int) $this->context->language->id
            );
        }

        // PrestaShop 1.6 standard checkout
        return $this->context->link->getPageLink(
            'order',
            true,
            (int) $this->context->language->id,
            [
                'step' => 1,
            ]
        );
    }

    /**
     * When an OrderPayment is created we should update fields payment_method and transaction_id
     *
     * @param array{cookie: Cookie, cart: Cart, altern: int, object: OrderPayment} $params
     */
    public function hookActionObjectOrderPaymentAddAfter(array $params)
    {
        $this->processHookActionObjectOrderPayment($params);
    }

    /**
     * When an OrderPayment is updated we should update fields payment_method and transaction_id
     *
     * @param array{cookie: Cookie, cart: Cart, altern: int, object: OrderPayment} $params
     */
    public function hookActionObjectOrderPaymentUpdateAfter(array $params)
    {
        $this->processHookActionObjectOrderPayment($params);
    }

    /**
     * When an OrderPayment is created or updated we should update fields payment_method and transaction_id
     *
     * @param array{cookie: Cookie, cart: Cart, altern: int, object: OrderPayment} $params
     *
     * @return void
     */
    private function processHookActionObjectOrderPayment($params)
    {
        if (!isset($params['object'])) {
            return;
        }

        /** @var \OrderPayment $orderPayment */
        $orderPayment = $params['object'];

        if (!Validate::isLoadedObject($orderPayment)
            || empty($orderPayment->order_reference)
            || !empty($orderPayment->transaction_id)
            || 1 !== count(OrderPayment::getByOrderReference($orderPayment->order_reference))
        ) {
            return;
        }

        /** @var Order[] $orderCollection */
        $orderCollection = Order::getByReference($orderPayment->order_reference);
        $id_cart = 0;

        foreach ($orderCollection as $order) {
            if ($this->name !== $order->module) {
                return;
            }
            $id_cart = (int) $order->id_cart;
        }

        if (!$id_cart) {
            return;
        }

        /** @var \PrestaShop\Module\PrestashopCheckout\Repository\PsCheckoutCartRepository $repository */
        $repository = $this->getService(\PrestaShop\Module\PrestashopCheckout\Repository\PsCheckoutCartRepository::class);

        $psCheckoutCart = $repository->findOneByCartId($id_cart);

        if (!$psCheckoutCart) {
            return;
        }

        /** @var \PrestaShop\Module\PrestashopCheckout\PayPal\PayPalOrderProvider $paypalOrderProvider */
        $paypalOrderProvider = $this->getService(\PrestaShop\Module\PrestashopCheckout\PayPal\PayPalOrderProvider::class);

        $paypalOrder = $paypalOrderProvider->getById($psCheckoutCart->paypal_order);

        if (!empty($paypalOrder['purchase_units'][0]['payments']['captures'])) {
            $transactionId = $paypalOrder['purchase_units'][0]['payments']['captures'][0]['id'];
        } elseif (!empty($paypalOrder['purchase_units'][0]['payments']['authorizations'])) {
            $transactionId = $paypalOrder['purchase_units'][0]['payments']['authorizations'][0]['id'];
        } else {
            return;
        }

        $cardNumber = '';
        $cardBrand = '';

        if (!empty($paypalOrder['payment_source']['card'])) {
            $cardNumber = sprintf('#### #### #### %d', $paypalOrder['payment_source']['card']['last_digits']);
            $cardBrand = $paypalOrder['payment_source']['card']['brand'];
        }

        /** @var \PrestaShop\Module\PrestashopCheckout\FundingSource\FundingSourceTranslationProvider $fundingSourceTranslationProvider */
        $fundingSourceTranslationProvider = $this->getService(\PrestaShop\Module\PrestashopCheckout\FundingSource\FundingSourceTranslationProvider::class);

        \Db::getInstance()->update(
            'order_payment',
            [
                'payment_method' => pSQL($fundingSourceTranslationProvider->getPaymentMethodName($psCheckoutCart->paypal_funding)),
                'transaction_id' => pSQL($transactionId),
                'card_number' => pSQL($cardNumber),
                'card_brand' => pSQL($cardBrand),
            ],
            'id_order_payment = ' . (int) $orderPayment->id
        );
    }

    /**
     * @return string
     */
    private function getShopDefaultCountryCode()
    {
        $defaultCountry = '';

        if (empty($defaultCountry) && Configuration::hasKey('PS_COUNTRY_DEFAULT')) {
            $defaultCountry = (new Country((int) Configuration::get('PS_COUNTRY_DEFAULT')))->iso_code;
        }

        return $defaultCountry ? strtoupper($defaultCountry) : '';
    }

    /**
     * @param array{cookie: Cookie, cart: Cart, altern: int, object: Shop} $params
     *
     * @return void
     */
    public function hookActionObjectShopDeleteAfter(array $params)
    {
        $toggleShopConfigurationCommandHandler = new \PrestaShop\Module\PrestashopCheckout\Configuration\ToggleShopConfigurationCommandHandler();
        $toggleShopConfigurationCommandHandler->handle(
            new \PrestaShop\Module\PrestashopCheckout\Configuration\ToggleShopConfigurationCommand(
                (int) Configuration::get('PS_SHOP_DEFAULT'),
                (bool) Shop::isFeatureActive()
            )
        );
    }

    /**
     * Display payment status on order confirmation page
     *
     * @param array{cookie: Cookie, cart: Cart, altern: int, order: Order, objOrder: Order} $params
     *
     * @return string
     */
    public function hookDisplayPaymentReturn(array $params)
    {
        if (!$this->merchantIsValid()) {
            return '';
        }

        /** @var Order $order */
        $order = (isset($params['objOrder'])) ? $params['objOrder'] : $params['order'];

        if (!Validate::isLoadedObject($order) || $order->module !== $this->name) {
            return '';
        }

        /** @var \PrestaShop\Module\PrestashopCheckout\PayPal\Order\PayPalOrderSummaryViewBuilder $orderSummaryViewBuilder */
        $orderSummaryViewBuilder = $this->getService(\PrestaShop\Module\PrestashopCheckout\PayPal\Order\PayPalOrderSummaryViewBuilder::class);

        try {
            $orderSummaryView = $orderSummaryViewBuilder->build($order);
        } catch (Exception $e) {
            return '';
        }

        $this->context->smarty->assign($orderSummaryView->getTemplateVars());

        return $this->display(__FILE__, 'views/templates/hook/displayPaymentReturn.tpl');
    }

    /**
     * Display payment status on order detail page
     *
     * @param array{cookie: Cookie, cart: Cart, altern: int, order: Order} $params
     *
     * @return string
     */
    public function hookDisplayOrderDetail(array $params)
    {
        if (!$this->merchantIsValid()) {
            return '';
        }

        /** @var Order $order */
        $order = $params['order'];

        if (!Validate::isLoadedObject($order) || $order->module !== $this->name) {
            return '';
        }

        /** @var \PrestaShop\Module\PrestashopCheckout\PayPal\Order\PayPalOrderSummaryViewBuilder $orderSummaryViewBuilder */
        $orderSummaryViewBuilder = $this->getService(\PrestaShop\Module\PrestashopCheckout\PayPal\Order\PayPalOrderSummaryViewBuilder::class);

        try {
            $orderSummaryView = $orderSummaryViewBuilder->build($order);
        } catch (Exception $exception) {
            return '';
        }

        $this->context->smarty->assign($orderSummaryView->getTemplateVars());

        return $this->display(__FILE__, 'views/templates/hook/displayOrderDetail.tpl');
    }

    public function hookModuleRoutes()
    {
        return [
            'ps_checkout_applepay' => [
                'rule' => '.well-known/apple-developer-merchantid-domain-association',
                'keywords' => [],
                'controller' => 'applepay',
                'params' => [
                    'fc' => 'module',
                    'module' => 'ps_checkout',
                    'action' => 'getDomainAssociation',
                ],
            ],
        ];
    }
}