diff --git a/changelog.md b/changelog.md index 608e9478..3ffb1c8d 100755 --- a/changelog.md +++ b/changelog.md @@ -169,3 +169,10 @@ - FO : AccountToAccount Pay payment method added - BO : Security improvements - BO : Bug fixes and improvements + +## [1.2.4] +- Fixed credit card saving +- Implemented code logging +- Requiring card holder name when entering card details +- Removed depreciated feature for custom CSS +- Compatibility with most popular OPC modules (The Checkout, Super Checkout, One Page Checkout PS) \ No newline at end of file diff --git a/composer.json b/composer.json index cd10dd9a..27aa2a13 100755 --- a/composer.json +++ b/composer.json @@ -21,13 +21,17 @@ "php": "5.6" } }, - "repositories": [ - { + "repositories": { + "knapsack": { + "type": "vcs", + "url": "https://github.com/Invertus/Knapsack.git" + }, + "lock": { "type": "vcs", "url": "https://github.com/Invertus/lock.git", "no-api": true } - ], + }, "require": { "vlucas/phpdotenv": "^3.6", "symfony/expression-language": "^3.4", @@ -37,7 +41,8 @@ "apimatic/unirest-php": "^2.3", "symfony/yaml": "^3.4", "league/container": "2.5.0", - "invertus/lock": "^1.0.0" + "invertus/lock": "^1.0.0", + "invertus/knapsack": "^10.0" }, "require-dev": { "friendsofphp/php-cs-fixer": "*", diff --git a/controllers/admin/AdminSaferPayOfficialFieldsController.php b/controllers/admin/AdminSaferPayOfficialFieldsController.php index 4ce49b59..9343021e 100755 --- a/controllers/admin/AdminSaferPayOfficialFieldsController.php +++ b/controllers/admin/AdminSaferPayOfficialFieldsController.php @@ -23,6 +23,8 @@ use Invertus\SaferPay\Config\SaferPayConfig; +require_once dirname(__FILE__) . '/../../vendor/autoload.php'; + if (!defined('_PS_VERSION_')) { exit; } diff --git a/controllers/admin/AdminSaferPayOfficialLogsController.php b/controllers/admin/AdminSaferPayOfficialLogsController.php index e20dcbb8..bbda32fe 100755 --- a/controllers/admin/AdminSaferPayOfficialLogsController.php +++ b/controllers/admin/AdminSaferPayOfficialLogsController.php @@ -21,20 +21,64 @@ *@license SIX Payment Services */ +use Invertus\SaferPay\Adapter\LegacyContext; +use Invertus\SaferPay\Config\SaferPayConfig; +use Invertus\Saferpay\Context\GlobalShopContext; +use Invertus\SaferPay\Controller\AbstractAdminSaferPayController; +use Invertus\SaferPay\Enum\PermissionType; +use Invertus\SaferPay\Logger\Formatter\LogFormatter; +use Invertus\SaferPay\Logger\LoggerInterface; +use Invertus\SaferPay\Repository\SaferPayLogRepository; +use Invertus\SaferPay\Utility\ExceptionUtility; +use Invertus\SaferPay\Utility\VersionUtility; +use Invertus\SaferPay\Logger\Logger; +use Invertus\SaferPay\Adapter\Tools; + +require_once dirname(__FILE__) . '/../../vendor/autoload.php'; + if (!defined('_PS_VERSION_')) { exit; } -class AdminSaferPayOfficialLogsController extends ModuleAdminController +class AdminSaferPayOfficialLogsController extends AbstractAdminSaferPayController { + const FILE_NAME = 'AdminSaferPayOfficialLogsController'; + + const LOG_INFORMATION_TYPE_REQUEST = 'request'; + + const LOG_INFORMATION_TYPE_RESPONSE = 'response'; + + const LOG_INFORMATION_TYPE_CONTEXT = 'context'; + public function __construct() { - parent::__construct(); - $this->className = SaferPayLog::class; - $this->table = SaferPayLog::$definition['table']; + $this->table = 'log'; + $this->className = 'PrestaShopLogger'; $this->bootstrap = true; - $this->list_no_link = true; + $this->lang = false; + $this->noLink = true; + $this->allow_export = true; + + parent::__construct(); + + $this->toolbar_btn = []; + $this->initList(); + + $this->_select .= ' + REPLACE(a.`message`, "' . LogFormatter::SAFERPAY_LOG_PREFIX . '", "") as message, + spl.request, spl.response, spl.context + '; + + $shopIdCheck = ''; + + if (VersionUtility::isPsVersionGreaterOrEqualTo('1.7.8.0')) { + $shopIdCheck = ' AND spl.id_shop = a.id_shop'; + } + + $this->_join .= ' JOIN ' . _DB_PREFIX_ . SaferPayLog::$definition['table'] . ' spl ON (spl.id_log = a.id_log' . $shopIdCheck . ' AND a.object_type = "' . pSQL(Logger::LOG_OBJECT_TYPE) . '")'; + $this->_use_found_rows = false; + $this->list_no_link = true; } public function initContent() @@ -42,29 +86,58 @@ public function initContent() if ($this->module instanceof SaferPayOfficial) { $this->content .= $this->module->displayNavigationTop(); } + + $this->content .= $this->displaySeverityInformation(); + parent::initContent(); } public function initList() { $this->fields_list = [ - 'id_saferpay_log' => [ - 'title' => $this->l('ID'), - 'align' => 'center', + 'id_log' => [ + 'title' => $this->module->l('ID', self::FILE_NAME), + 'align' => 'text-center', + 'class' => 'fixed-width-xs', ], - 'payload' => [ - 'title' => $this->l('Payload'), - 'align' => 'center', - 'class' => 'saferpay-text-break', + 'severity' => [ + 'title' => $this->module->l('Severity (1-4)', self::FILE_NAME), + 'align' => 'text-center', + 'class' => 'fixed-width-xs', + 'callback' => 'printSeverityLevel', + ], + 'request' => [ + 'title' => $this->module->l('Request', self::FILE_NAME), + 'align' => 'text-center', + 'callback' => 'printRequestButton', + 'orderby' => false, + 'search' => false, + 'remove_onclick' => true, + ], + 'response' => [ + 'title' => $this->module->l('Response', self::FILE_NAME), + 'align' => 'text-center', + 'callback' => 'printResponseButton', + 'orderby' => false, + 'search' => false, + 'remove_onclick' => true, ], 'message' => [ - 'align' => 'center', - 'title' => $this->l('Message'), - 'class' => 'saferpay-text-break', + 'title' => $this->module->l('Message', self::FILE_NAME), + ], + 'context' => [ + 'title' => $this->module->l('Context', self::FILE_NAME), + 'align' => 'text-center', + 'callback' => 'printContextButton', + 'orderby' => false, + 'search' => false, + 'remove_onclick' => true, ], 'date_add' => [ - 'title' => $this->l('Date'), + 'title' => $this->module->l('Date', self::FILE_NAME), + 'align' => 'right', 'type' => 'datetime', + 'filter_key' => 'a!date_add', ], ]; @@ -77,12 +150,254 @@ public function initList() public function renderList() { unset($this->toolbar_btn['new']); + return parent::renderList(); } public function setMedia($isNewTheme = false) { - $this->addCSS("{$this->module->getPathUri()}views/css/admin/logs_tab.css"); parent::setMedia($isNewTheme); + + /** @var LegacyContext $context */ + $context = $this->module->getService(LegacyContext::class); + + Media::addJsDef([ + 'saferpayofficial' => [ + 'logsUrl' => $context->getAdminLink(SaferPayOfficial::ADMIN_LOGS_CONTROLLER), + ], + ]); + + $this->addCSS("{$this->module->getPathUri()}views/css/admin/logs_tab.css"); + $this->addJS($this->module->getPathUri() . 'views/js/admin/log.js', false); + } + + public function displaySeverityInformation() + { + return $this->context->smarty->fetch( + "{$this->module->getLocalPath()}views/templates/admin/logs/severity_levels.tpl" + ); + } + + public function printSeverityLevel($level) + { + $this->context->smarty->assign([ + 'log_severity_level' => $level, + 'log_severity_level_informative' => defined('\PrestaShopLogger::LOG_SEVERITY_LEVEL_INFORMATIVE') ? + PrestaShopLogger::LOG_SEVERITY_LEVEL_INFORMATIVE : + SaferPayConfig::LOG_SEVERITY_LEVEL_INFORMATIVE, + 'log_severity_level_warning' => defined('\PrestaShopLogger::LOG_SEVERITY_LEVEL_WARNING') ? + PrestaShopLogger::LOG_SEVERITY_LEVEL_WARNING : + SaferPayConfig::LOG_SEVERITY_LEVEL_WARNING, + 'log_severity_level_error' => defined('\PrestaShopLogger::LOG_SEVERITY_LEVEL_ERROR') ? + PrestaShopLogger::LOG_SEVERITY_LEVEL_ERROR : + SaferPayConfig::LOG_SEVERITY_LEVEL_ERROR, + 'log_severity_level_major' => defined('\PrestaShopLogger::LOG_SEVERITY_LEVEL_MAJOR') ? + PrestaShopLogger::LOG_SEVERITY_LEVEL_MAJOR : + SaferPayConfig::LOG_SEVERITY_LEVEL_MAJOR, + ]); + + return $this->context->smarty->fetch( + "{$this->module->getLocalPath()}views/templates/admin/logs/severity_level_column.tpl" + ); + } + + public function getDisplayButton($logId, $data, $logInformationType) + { + $unserializedData = json_decode($data); + + if (empty($unserializedData)) { + return '--'; + } + + $this->context->smarty->assign([ + 'log_id' => $logId, + 'log_information_type' => $logInformationType, + ]); + + return $this->context->smarty->fetch( + "{$this->module->getLocalPath()}views/templates/admin/logs/log_modal.tpl" + ); + } + + /** + * @param string $request + * @param array $data + * + * @return false|string + * + * @throws SmartyException + */ + public function printRequestButton($request, $data) + { + return $this->getDisplayButton($data['id_log'], $request, self::LOG_INFORMATION_TYPE_REQUEST); + } + + public function printResponseButton($response, $data) + { + return $this->getDisplayButton($data['id_log'], $response, self::LOG_INFORMATION_TYPE_RESPONSE); + } + + public function printContextButton($context, $data) + { + return $this->getDisplayButton($data['id_log'], $context, self::LOG_INFORMATION_TYPE_CONTEXT); + } + + public function displayAjaxGetLog() + { + /** @var Invertus\SaferPay\Adapter\Tools $tools */ + $tools = $this->module->getService(Tools::class); + + /** @var Invertus\SaferPay\Repository\SaferPayLogRepository $logRepository */ + $logRepository = $this->module->getService(SaferPayLogRepository::class); + + /** @var Invertus\SaferPay\Context\GlobalShopContext $shopContext */ + $globalShopContext = $this->module->getService(GlobalShopContext::class); + + $logId = $tools->getValueAsInt('log_id'); + + /** @var LoggerInterface $logger */ + $logger = $this->module->getService(LoggerInterface::class); + + try { + /** @var \SaferPayLog|null $log */ + $log = $logRepository->findOneBy([ + 'id_log' => $logId, + 'id_shop' => $globalShopContext->getShopId(), + ]); + } catch (Exception $exception) { + $logger->error($exception->getMessage(), [ + 'context' => [ + 'id_log' => $logId, + 'id_shop' => $globalShopContext->getShopId(), + ], + 'exceptions' => ExceptionUtility::getExceptions($exception), + ]); + + $this->ajaxResponse(json_encode([ + 'error' => true, + 'message' => $this->module->l('Failed to find log.', self::FILE_NAME), + ])); + } + + if (!isset($log)) { + $logger->error('No log information found.', [ + 'context' => [ + 'id_log' => $logId, + 'id_shop' => $globalShopContext->getShopId(), + ], + 'exceptions' => [], + ]); + + $this->ajaxRender(json_encode([ + 'error' => true, + 'message' => $this->module->l('No log information found.', self::FILE_NAME), + ])); + } + + $this->ajaxResponse(json_encode([ + 'error' => false, + 'log' => [ + self::LOG_INFORMATION_TYPE_REQUEST => $log->request, + self::LOG_INFORMATION_TYPE_RESPONSE => $log->response, + self::LOG_INFORMATION_TYPE_CONTEXT => $log->context, + ], + ])); + } + + public function processExport($textDelimiter = '"') + { + // clean buffer + if (ob_get_level() && ob_get_length() > 0) { + ob_clean(); + } + + header('Content-type: text/csv'); + header('Content-Type: application/force-download; charset=UTF-8'); + header('Cache-Control: no-store, no-cache'); + header('Content-disposition: attachment; filename="' . $this->table . '_' . date('Y-m-d_His') . '.csv"'); + + $fd = fopen('php://output', 'wb'); + + /** @var Configuration $configuration */ + $configuration = $this->module->getService(Configuration::class); + + /** @var LegacyContext $context */ + $context = $this->module->getService(LegacyContext::class); + + $storeInfo = [ + 'PrestaShop Version' => _PS_VERSION_, + 'PHP Version' => phpversion(), + 'Module Version' => $this->module->version, + 'MySQL Version' => \Db::getInstance()->getVersion(), + 'Shop URL' => $context->getShopDomain(), + 'Shop Name' => $context->getShopName(), + ]; + + $moduleConfigurations = [ + 'Test mode' => SaferPayConfig::isTestMode() ? 'Yes' : 'No', + ]; + + $psSettings = [ + 'Default country' => $configuration->get('PS_COUNTRY_DEFAULT'), + 'Default currency' => $configuration->get('PS_CURRENCY_DEFAULT'), + 'Default language' => $configuration->get('PS_LANG_DEFAULT'), + 'Round mode' => $configuration->get('PS_PRICE_ROUND_MODE'), + 'Round type' => $configuration->get('PS_ROUND_TYPE'), + 'Current theme name' => $context->getShopThemeName(), + 'PHP memory limit' => ini_get('memory_limit'), + ]; + + $moduleConfigurationsInfo = "**Module configurations:**\n"; + foreach ($moduleConfigurations as $key => $value) { + $moduleConfigurationsInfo .= "- $key: $value\n"; + } + + $psSettingsInfo = "**Prestashop settings:**\n"; + foreach ($psSettings as $key => $value) { + $psSettingsInfo .= "- $key: $value\n"; + } + + fputcsv($fd, array_keys($storeInfo), ';', $textDelimiter); + fputcsv($fd, $storeInfo, ';', $textDelimiter); + fputcsv($fd, [], ';', $textDelimiter); + + fputcsv($fd, [$moduleConfigurationsInfo], ';', $textDelimiter); + fputcsv($fd, [$psSettingsInfo], ';', $textDelimiter); + + $query = new \DbQuery(); + + $query + ->select('spl.id_log, l.severity, l.message, spl.request, spl.response, spl.context, spl.date_add') + ->from('saferpay_log', 'spl') + ->leftJoin('log', 'l', 'spl.id_log = l.id_log') + ->orderBy('spl.id_log DESC') + ->limit(1000); + + $result = \Db::getInstance()->executeS($query); + + $firstRow = $result[0]; + $headers = []; + + foreach ($firstRow as $key => $value) { + $headers[] = strtoupper($key); + } + + $fd = fopen('php://output', 'wb'); + + fputcsv($fd, $headers, ';', $textDelimiter); + + $content = !empty($result) ? $result : []; + + foreach ($content as $row) { + $rowValues = []; + foreach ($row as $key => $value) { + $rowValues[] = $value; + } + + fputcsv($fd, $rowValues, ';', $textDelimiter); + } + + @fclose($fd); + die; } } diff --git a/controllers/admin/AdminSaferPayOfficialModuleController.php b/controllers/admin/AdminSaferPayOfficialModuleController.php index 31f09937..45a4cd7d 100755 --- a/controllers/admin/AdminSaferPayOfficialModuleController.php +++ b/controllers/admin/AdminSaferPayOfficialModuleController.php @@ -21,6 +21,8 @@ *@license SIX Payment Services */ +require_once dirname(__FILE__) . '/../../vendor/autoload.php'; + if (!defined('_PS_VERSION_')) { exit; } diff --git a/controllers/admin/AdminSaferPayOfficialOrderController.php b/controllers/admin/AdminSaferPayOfficialOrderController.php index 2facdb02..f7a157f7 100755 --- a/controllers/admin/AdminSaferPayOfficialOrderController.php +++ b/controllers/admin/AdminSaferPayOfficialOrderController.php @@ -21,6 +21,8 @@ *@license SIX Payment Services */ +require_once dirname(__FILE__) . '/../../vendor/autoload.php'; + if (!defined('_PS_VERSION_')) { exit; } diff --git a/controllers/admin/AdminSaferPayOfficialPaymentController.php b/controllers/admin/AdminSaferPayOfficialPaymentController.php index 5a85cc65..8b9ac801 100755 --- a/controllers/admin/AdminSaferPayOfficialPaymentController.php +++ b/controllers/admin/AdminSaferPayOfficialPaymentController.php @@ -21,6 +21,8 @@ *@license SIX Payment Services */ +require_once dirname(__FILE__) . '/../../vendor/autoload.php'; + if (!defined('_PS_VERSION_')) { exit; } @@ -51,6 +53,7 @@ public function __construct() public function setMedia($isNewTheme = false) { parent::setMedia($isNewTheme); + $this->addCSS("{$this->module->getPathUri()}views/css/admin/payment_method.css"); $this->addJS("{$this->module->getPathUri()}views/js/admin/chosen_countries.js"); $this->addJS("{$this->module->getPathUri()}views/js/admin/payment_method_all.js"); diff --git a/controllers/admin/AdminSaferPayOfficialSettingsController.php b/controllers/admin/AdminSaferPayOfficialSettingsController.php index fdd33062..0cf1b1b7 100755 --- a/controllers/admin/AdminSaferPayOfficialSettingsController.php +++ b/controllers/admin/AdminSaferPayOfficialSettingsController.php @@ -24,6 +24,8 @@ use Invertus\SaferPay\Config\SaferPayConfig; use Invertus\SaferPay\Repository\SaferPaySavedCreditCardRepository; +require_once dirname(__FILE__) . '/../../vendor/autoload.php'; + if (!defined('_PS_VERSION_')) { exit; } @@ -54,18 +56,42 @@ public function postProcess() { parent::postProcess(); - $isCreditCardSaveEnabled = Configuration::get(SaferPayConfig::CREDIT_CARD_SAVE); + /** @var \Invertus\SaferPay\Adapter\Configuration $configuration */ + $configuration = $this->module->getService(\Invertus\SaferPay\Adapter\Configuration::class); + + $isCreditCardSaveEnabled = $configuration->get(SaferPayConfig::CREDIT_CARD_SAVE); + if (!$isCreditCardSaveEnabled) { /** @var SaferPaySavedCreditCardRepository $cardRepo */ $cardRepo = $this->module->getService(SaferPaySavedCreditCardRepository::class); $cardRepo->deleteAllSavedCreditCards(); } + + $haveFieldToken = $configuration->get(SaferPayConfig::FIELDS_ACCESS_TOKEN . SaferPayConfig::getConfigSuffix()); + $haveBusinessLicense = $configuration->get(SaferPayConfig::BUSINESS_LICENSE . SaferPayConfig::getConfigSuffix()); + + if (!$haveFieldToken && $haveBusinessLicense) { + $configuration->set(SaferPayConfig::BUSINESS_LICENSE . SaferPayConfig::getConfigSuffix(), 0); + $this->errors[] = $this->module->l('Field Access Token is required to use business license'); + } } public function initOptions() { $this->context->smarty->assign(SaferPayConfig::PASSWORD, SaferPayConfig::WEB_SERVICE_PASSWORD_PLACEHOLDER); + $savedCardSetting = SaferPayConfig::isVersion17() ? [ + 'type' => 'radio', + 'title' => $this->l('Credit card saving for customers'), + 'validation' => 'isInt', + 'choices' => [ + 1 => $this->l('Enable'), + 0 => $this->l('Disable'), + ], + 'desc' => $this->l('Allow customers to save credit card for faster purchase'), + 'form_group_class' => 'thumbs_chose', + ] : null; + $this->fields_options = [ 'login_configurations' => [ 'title' => $this->l('TEST MODE'), @@ -247,17 +273,7 @@ public function initOptions() 'desc' => $this->l('Default payment behavior for payment without 3-D Secure'), 'form_group_class' => 'thumbs_chose', ], - SaferPayConfig::CREDIT_CARD_SAVE => [ - 'type' => 'radio', - 'title' => $this->l('Credit card saving for customers'), - 'validation' => 'isInt', - 'choices' => [ - 1 => $this->l('Enable'), - 0 => $this->l('Disable'), - ], - 'desc' => $this->l('Allow customers to save credit card for faster purchase'), - 'form_group_class' => 'thumbs_chose', - ], + SaferPayConfig::CREDIT_CARD_SAVE => $savedCardSetting, SaferPayConfig::RESTRICT_REFUND_AMOUNT_TO_CAPTURED_AMOUNT => [ 'type' => 'radio', 'title' => $this->l('Restrict RefundAmount To Captured Amount'), @@ -299,11 +315,6 @@ public function initOptions() 'type' => 'text', 'class' => 'fixed-width-xl', ], - SaferPayConfig::CSS_FILE => [ - 'title' => $this->l('CSS url'), - 'type' => 'text', - 'class' => 'fixed-width-xl', - ], ], 'buttons' => [ 'save_and_connect' => [ @@ -400,7 +411,14 @@ private function displayConfigurationSettings() 'title' => $this->module->l('Description', self::FILE_NAME), 'type' => 'text', 'desc' => 'This description is visible in payment page also in payment confirmation email', - 'class' => 'fixed-width-xxl' + 'class' => 'fixed-width-xxl', + ], + SaferPayConfig::SAFERPAY_DEBUG_MODE => [ + 'title' => $this->module->l('Debug mode', self::FILE_NAME), + 'validation' => 'isBool', + 'cast' => 'intval', + 'type' => 'bool', + 'desc' => $this->module->l('Enable debug mode to see more information in logs', self::FILE_NAME), ], ], 'buttons' => [ diff --git a/controllers/front/ajax.php b/controllers/front/ajax.php index f221d68e..d3beb143 100755 --- a/controllers/front/ajax.php +++ b/controllers/front/ajax.php @@ -25,7 +25,13 @@ use Invertus\SaferPay\Controller\Front\CheckoutController; use Invertus\SaferPay\Core\Payment\DTO\CheckoutData; use Invertus\SaferPay\Enum\ControllerName; +use Invertus\SaferPay\Exception\Restriction\UnauthenticatedCardUserException; +use Invertus\SaferPay\Exception\SaferPayException; +use Invertus\SaferPay\Logger\LoggerInterface; +use Invertus\SaferPay\Repository\SaferPayCardAliasRepository; use Invertus\SaferPay\Repository\SaferPayOrderRepository; +use Invertus\SaferPay\Utility\ExceptionUtility; +use Invertus\SaferPay\Validation\CustomerCreditCardValidation; if (!defined('_PS_VERSION_')) { exit; @@ -40,6 +46,11 @@ class SaferPayOfficialAjaxModuleFrontController extends ModuleFrontController public function postProcess() { + /** @var LoggerInterface $logger */ + $logger = $this->module->getService(LoggerInterface::class); + + $logger->debug(sprintf('%s - Controller called', self::FILE_NAME)); + switch (Tools::getValue('action')) { case 'submitHostedFields': $this->submitHostedFields(); @@ -71,10 +82,22 @@ protected function processGetStatus() if (!$saferPayOrder->id || $saferPayOrder->canceled) { $this->ajaxDie(json_encode([ 'isFinished' => true, - 'href' => $this->getFailControllerLink($cartId, $secureKey, $moduleId) + 'href' => $this->getFailControllerLink($cartId, $secureKey, $moduleId), ])); } + /** @var LoggerInterface $logger */ + $logger = $this->module->getService(LoggerInterface::class); + $logger->debug(sprintf('%s - Controller action ended', self::FILE_NAME), [ + 'context' => [ + 'cart_id' => $cartId, + 'safer_pay_order_id' => $saferPayOrderId, + 'is_authorized' => $saferPayOrder->authorized, + 'is_captured' => $saferPayOrder->captured, + 'is_pending' => $saferPayOrder->pending, + ], + ]); + $this->ajaxDie(json_encode([ 'saferpayOrder' => json_encode($saferPayOrder), 'isFinished' => $saferPayOrder->authorized || $saferPayOrder->captured || $saferPayOrder->pending, @@ -88,7 +111,7 @@ protected function processGetStatus() 'secureKey' => $secureKey, 'selectedCard' => $selectedCard, ] - ) + ), ])); } @@ -123,6 +146,40 @@ private function getSuccessControllerName($isBusinessLicence, $fieldToken) private function submitHostedFields() { + /** @var LoggerInterface $logger */ + $logger = $this->module->getService(LoggerInterface::class); + + /** @var CustomerCreditCardValidation $cardValidation */ + $cardValidation = $this->module->getService(CustomerCreditCardValidation::class); + + try { + $cardValidation->validate(Tools::getValue('selectedCard'), $this->context->customer->id); + } catch (UnauthenticatedCardUserException $e) { + $logger->error($e->getMessage(), [ + 'context' => [], + 'id_customer' => $this->context->customer->id, + 'id_card' => Tools::getValue('selectedCard'), + 'exceptions' => ExceptionUtility::getExceptions($e), + ]); + + $this->ajaxDie(json_encode([ + 'error' => true, + 'message' => $e->getMessage(), + 'url' => $this->getRedirectionToControllerUrl('fail'), + ])); + } catch (SaferPayException $e) { + $logger->error($e->getMessage(), [ + 'context' => [], + 'exceptions' => ExceptionUtility::getExceptions($e), + ]); + + $this->ajaxDie(json_encode([ + 'error' => true, + 'message' => $e->getMessage(), + 'url' => $this->getRedirectionToControllerUrl('fail'), + ])); + } + try { if (Order::getOrderByCartId($this->context->cart->id)) { $this->ajaxDie(json_encode([ @@ -151,11 +208,18 @@ private function submitHostedFields() $redirectUrl = $this->getRedirectionToControllerUrl('successHosted'); } + $logger->debug(sprintf('%s - Controller action ended', self::FILE_NAME)); + $this->ajaxDie(json_encode([ 'error' => false, 'url' => $redirectUrl, ])); } catch (Exception $e) { + $logger->error($e->getMessage(), [ + 'context' => [], + 'exceptions' => ExceptionUtility::getExceptions($e), + ]); + $this->ajaxDie(json_encode([ 'error' => true, 'message' => $e->getMessage(), diff --git a/controllers/front/creditCards.php b/controllers/front/creditCards.php index 3d1a5d58..fa2a1d6e 100755 --- a/controllers/front/creditCards.php +++ b/controllers/front/creditCards.php @@ -23,6 +23,7 @@ use Invertus\SaferPay\Config\SaferPayConfig; use Invertus\SaferPay\Controller\AbstractSaferPayController; +use Invertus\SaferPay\Logger\LoggerInterface; use Invertus\SaferPay\Repository\SaferPayCardAliasRepository; if (!defined('_PS_VERSION_')) { @@ -31,7 +32,7 @@ class SaferPayOfficialCreditCardsModuleFrontController extends AbstractSaferPayController { - const FILENAME = 'creditCards'; + const FILE_NAME = 'creditCards'; public function display() { @@ -54,6 +55,7 @@ public function display() private function initCardList() { $customerId = $this->context->customer->id; + /** @var SaferPayCardAliasRepository $cardAliasRep */ $cardAliasRep = $this->module->getService(SaferPayCardAliasRepository::class); $savedCustomerCards = $cardAliasRep->getSavedCardsByCustomerId($customerId); @@ -70,7 +72,7 @@ private function initCardList() 'payment_method' => $savedCard['payment_method'], 'date_add' => $savedCard['date_add'], 'card_img' => "{$this->module->getPathUri()}views/img/{$savedCard['payment_method']}.png", - 'controller' => self::FILENAME, + 'controller' => self::FILE_NAME, ]); $rows[] = $this->context->smarty->fetch( $this->module->getLocalPath() . 'views/templates/front/credit_card.tpl' @@ -83,15 +85,23 @@ private function initCardList() public function postProcess() { + /** @var LoggerInterface $logger */ + $logger = $this->module->getService(LoggerInterface::class); + + $logger->debug(sprintf('%s - Controller called', self::FILE_NAME)); + $selectedCard = Tools::getValue('saved_card_id'); if ($selectedCard) { $cardAlias = new SaferPayCardAlias($selectedCard); if ($cardAlias->delete()) { - $this->success[] = $this->module->l('Successfully removed credit card', self::FILENAME); + $this->success[] = $this->module->l('Successfully removed credit card', self::FILE_NAME); return; } - $this->errors[] = $this->module->l('Failed to removed credit card', self::FILENAME); + $this->errors[] = $this->module->l('Failed to removed credit card', self::FILE_NAME); } + + $logger->debug(sprintf('%s - Controller action ended', self::FILE_NAME)); + parent::postProcess(); } @@ -100,7 +110,7 @@ private function setBreadcrumb() $breadcrumb = $this->getBreadcrumbLinks(); $breadcrumb['links'][] = [ - 'title' => $this->module->l('Your account', self::FILENAME), + 'title' => $this->module->l('Your account', self::FILE_NAME), 'url' => $this->context->link->getPageLink('my-account'), ]; diff --git a/controllers/front/creditCards16.php b/controllers/front/creditCards16.php index 5463e470..1236641d 100755 --- a/controllers/front/creditCards16.php +++ b/controllers/front/creditCards16.php @@ -23,6 +23,7 @@ use Invertus\SaferPay\Config\SaferPayConfig; use Invertus\SaferPay\Controller\AbstractSaferPayController; +use Invertus\SaferPay\Logger\LoggerInterface; use Invertus\SaferPay\Repository\SaferPayCardAliasRepository; if (!defined('_PS_VERSION_')) { @@ -31,7 +32,7 @@ class SaferPayOfficialCreditCards16ModuleFrontController extends AbstractSaferPayController { - const FILENAME = 'creditCards16'; + const FILE_NAME = 'creditCards16'; public $display_column_left = false; public $display_column_right = false; @@ -78,7 +79,7 @@ private function initCardList() 'payment_method' => $savedCard['payment_method'], 'date_add' => $savedCard['date_add'], 'card_img' => "{$this->module->getPathUri()}views/img/{$savedCard['payment_method']}.png", - 'controller' => self::FILENAME, + 'controller' => self::FILE_NAME, ]); $rows[] = $this->context->smarty->fetch( $this->module->getLocalPath() . 'views/templates/front/credit_card.tpl' @@ -91,15 +92,23 @@ private function initCardList() public function postProcess() { + /** @var LoggerInterface $logger */ + $logger = $this->module->getService(LoggerInterface::class); + + $logger->debug(sprintf('%s - Controller called', self::FILE_NAME)); + $selectedCard = Tools::getValue('saved_card_id'); if ($selectedCard) { $cardAlias = new SaferPayCardAlias($selectedCard); if ($cardAlias->delete()) { - $this->success[] = $this->module->l('Successfully removed credit card', self::FILENAME); + $this->success[] = $this->module->l('Successfully removed credit card', self::FILE_NAME); return; } - $this->errors[] = $this->module->l('Failed to removed credit card', self::FILENAME); + $this->errors[] = $this->module->l('Failed to removed credit card', self::FILE_NAME); } + + $logger->debug(sprintf('%s - Controller action ended', self::FILE_NAME)); + parent::postProcess(); } @@ -108,7 +117,7 @@ private function setBreadcrumb() $breadcrumb = $this->getBreadcrumbLinks(); $breadcrumb['links'][] = [ - 'title' => $this->module->l('Your account', self::FILENAME), + 'title' => $this->module->l('Your account', self::FILE_NAME), 'url' => $this->context->link->getPageLink('my-account'), ]; diff --git a/controllers/front/fail.php b/controllers/front/fail.php index 19530f8b..081034cc 100755 --- a/controllers/front/fail.php +++ b/controllers/front/fail.php @@ -24,6 +24,7 @@ use Invertus\SaferPay\Config\SaferPayConfig; use Invertus\SaferPay\Controller\AbstractSaferPayController; use Invertus\SaferPay\Service\CartDuplicationService; +use Invertus\SaferPay\Logger\LoggerInterface; use PrestaShop\PrestaShop\Adapter\Order\OrderPresenter; if (!defined('_PS_VERSION_')) { @@ -32,7 +33,7 @@ class SaferPayOfficialFailModuleFrontController extends AbstractSaferPayController { - const FILENAME = 'fail'; + const FILE_NAME = 'fail'; /** * Security Key Variable Declaration. @@ -93,12 +94,19 @@ public function initContent() { parent::initContent(); + /** @var LoggerInterface $logger */ + $logger = $this->module->getService(LoggerInterface::class); + + $logger->debug(sprintf('%s - Controller called', self::FILE_NAME)); + $orderLink = $this->context->link->getPageLink( 'order', true, null ); - $this->warning[] = $this->module->l('We couldn\'t authorize your payment. Please try again.', self::FILENAME); + $this->warning[] = $this->module->l('We couldn\'t authorize your payment. Please try again.', self::FILE_NAME); + + $logger->debug(sprintf('%s - Controller action ended', self::FILE_NAME)); if (!SaferPayConfig::isVersion17()) { $this->redirectWithNotifications($orderLink); diff --git a/controllers/front/failIFrame.php b/controllers/front/failIFrame.php index c96b44a6..e1193835 100755 --- a/controllers/front/failIFrame.php +++ b/controllers/front/failIFrame.php @@ -24,6 +24,7 @@ use Invertus\SaferPay\Config\SaferPayConfig; use Invertus\SaferPay\Controller\AbstractSaferPayController; use Invertus\SaferPay\Enum\ControllerName; +use Invertus\SaferPay\Logger\LoggerInterface; if (!defined('_PS_VERSION_')) { exit; @@ -31,7 +32,7 @@ class SaferPayOfficialFailIFrameModuleFrontController extends AbstractSaferPayController { - const FILENAME = 'failIFrame'; + const FILE_NAME = 'failIFrame'; protected $display_header = false; protected $display_footer = false; @@ -48,22 +49,39 @@ public function initContent() { parent::initContent(); + $cart = new \Cart(Tools::getValue('cartId')); + + /** + * Note: deleting cart prevents + * from further failing when creating order with same cart + */ + $cart->delete(); + + /** @var LoggerInterface $logger */ + $logger = $this->module->getService(LoggerInterface::class); + + $logger->debug(sprintf('%s - Controller called', self::FILE_NAME)); + $orderLink = $this->context->link->getPageLink( 'order', true, null ); + $logger->debug(sprintf('%s - Controller action ended', self::FILE_NAME)); + if (SaferPayConfig::isVersion17()) { $this->setTemplate(SaferPayConfig::SAFERPAY_TEMPLATE_LOCATION . '/front/loading.tpl'); return; } + $this->context->smarty->assign([ 'cssUrl' => "{$this->module->getPathUri()}views/css/front/loading.css", 'jsUrl' => "{$this->module->getPathUri()}views/js/front/saferpay_iframe.js", 'redirectUrl' => $orderLink, ]); $this->setTemplate('loading_16.tpl'); + } public function setMedia() diff --git a/controllers/front/failValidation.php b/controllers/front/failValidation.php index 90951a60..d00ea2b0 100755 --- a/controllers/front/failValidation.php +++ b/controllers/front/failValidation.php @@ -22,6 +22,7 @@ */ use Invertus\SaferPay\Controller\AbstractSaferPayController; +use Invertus\SaferPay\Logger\LoggerInterface; use Invertus\SaferPay\Repository\SaferPayOrderRepository; use Invertus\SaferPay\Service\CartDuplicationService; @@ -31,10 +32,15 @@ class SaferPayOfficialFailValidationModuleFrontController extends AbstractSaferPayController { - const FILENAME = 'failValidation'; + const FILE_NAME = 'failValidation'; public function postProcess() { + /** @var LoggerInterface $logger */ + $logger = $this->module->getService(LoggerInterface::class); + + $logger->debug(sprintf('%s - Controller called', self::FILE_NAME)); + $cartId = Tools::getValue('cartId'); $orderId = Tools::getValue('orderId'); $secureKey = Tools::getValue('secureKey'); @@ -86,6 +92,8 @@ public function postProcess() true ); + $logger->debug(sprintf('%s - Controller action ended', self::FILE_NAME)); + Tools::redirect($failUrl); } } diff --git a/controllers/front/hostedIframe.php b/controllers/front/hostedIframe.php index b0330637..28b80e8a 100755 --- a/controllers/front/hostedIframe.php +++ b/controllers/front/hostedIframe.php @@ -22,6 +22,7 @@ */ use Invertus\SaferPay\Config\SaferPayConfig; +use Invertus\SaferPay\Logger\LoggerInterface; use PrestaShop\PrestaShop\Core\Checkout\TermsAndConditions; if (!defined('_PS_VERSION_')) { @@ -30,10 +31,15 @@ class SaferPayOfficialHostedIframeModuleFrontController extends ModuleFrontController { - const FILENAME = 'hostedIframe'; + const FILE_NAME = 'hostedIframe'; public function initContent() { + /** @var LoggerInterface $logger */ + $logger = $this->module->getService(LoggerInterface::class); + + $logger->debug(sprintf('%s - Controller called', self::FILE_NAME)); + parent::initContent(); $paymentMethod = Tools::getValue('saved_card_method'); @@ -49,6 +55,8 @@ public function initContent() 'saferpay_selected_card' => $selectedCard, ]); + $logger->debug(sprintf('%s - Controller action ended', self::FILE_NAME)); + if (SaferPayConfig::isVersion17()) { $this->setTemplate( SaferPayConfig::SAFERPAY_HOSTED_TEMPLATE_LOCATION . @@ -63,6 +71,7 @@ public function initContent() '_16.tpl' ); } + } public function setMedia() @@ -72,7 +81,7 @@ public function setMedia() Media::addJsDef([ 'saferpay_field_access_token' => SaferPayConfig::getFieldAccessToken(), 'saferpay_field_url' => SaferPayConfig::getFieldUrl(), - 'holder_name' => $this->module->l('Holder name', self::FILENAME), + 'holder_name' => $this->module->l('Holder name', self::FILE_NAME), 'saferpay_official_ajax_url' => $this->context->link->getModuleLink('saferpayofficial', 'ajax'), 'saved_card_method' => Tools::getValue('saved_card_method'), 'isBusinessLicence' => Tools::getValue('isBusinessLicence'), diff --git a/controllers/front/iframe.php b/controllers/front/iframe.php index 7fb34709..b455d0e2 100755 --- a/controllers/front/iframe.php +++ b/controllers/front/iframe.php @@ -26,6 +26,7 @@ use Invertus\SaferPay\Controller\Front\CheckoutController; use Invertus\SaferPay\Core\Payment\DTO\CheckoutData; use Invertus\SaferPay\Enum\ControllerName; +use Invertus\SaferPay\Logger\LoggerInterface; if (!defined('_PS_VERSION_')) { exit; @@ -33,12 +34,17 @@ class SaferPayOfficialIFrameModuleFrontController extends AbstractSaferPayController { - const FILENAME = 'iframe'; + const FILE_NAME = 'iframe'; public $display_column_left = false; public function postProcess() { + /** @var LoggerInterface $logger */ + $logger = $this->module->getService(LoggerInterface::class); + + $logger->debug(sprintf('%s - Controller called', self::FILE_NAME)); + $cart = $this->context->cart; $redirectLink = $this->context->link->getPageLink( 'order', @@ -65,13 +71,20 @@ public function postProcess() } if (!$authorized) { $this->errors[] = - $this->module->l('This payment method is not available.', self::FILENAME); + $this->module->l('This payment method is not available.', self::FILE_NAME); $this->redirectWithNotifications($redirectLink); } $customer = new Customer($cart->id_customer); if (!Validate::isLoadedObject($customer)) { + $logger->error(sprintf('%s - Customer not found', self::FILE_NAME), [ + 'context' => [], + 'exceptions' => [], + ]); + Tools::redirect($redirectLink); } + + $logger->debug(sprintf('%s - Controller action ended', self::FILE_NAME)); } public function initContent() @@ -98,7 +111,6 @@ public function initContent() ); $redirectUrl = $checkoutController->execute($checkoutData); - } catch (\Exception $exception) { $redirectUrl = $this->context->link->getModuleLink( $this->module->name, diff --git a/controllers/front/notify.php b/controllers/front/notify.php index d9fcaf5a..547e3b9b 100755 --- a/controllers/front/notify.php +++ b/controllers/front/notify.php @@ -25,10 +25,12 @@ use Invertus\SaferPay\Config\SaferPayConfig; use Invertus\SaferPay\Controller\AbstractSaferPayController; use Invertus\SaferPay\Core\Payment\DTO\CheckoutData; +use Invertus\SaferPay\Logger\LoggerInterface; use Invertus\SaferPay\Processor\CheckoutProcessor; use Invertus\SaferPay\Repository\SaferPayOrderRepository; use Invertus\SaferPay\Service\SaferPayOrderStatusService; use Invertus\SaferPay\Service\TransactionFlow\SaferPayTransactionAssertion; +use Invertus\SaferPay\Utility\ExceptionUtility; if (!defined('_PS_VERSION_')) { exit; @@ -36,7 +38,7 @@ class SaferPayOfficialNotifyModuleFrontController extends AbstractSaferPayController { - const FILENAME = 'notify'; + const FILE_NAME = 'notify'; /** * This code is being called by SaferPay by using NotifyUrl in InitializeRequest. @@ -45,19 +47,39 @@ class SaferPayOfficialNotifyModuleFrontController extends AbstractSaferPayContro */ public function postProcess() { + /** @var LoggerInterface $logger */ + $logger = $this->module->getService(LoggerInterface::class); + + $logger->debug(sprintf('%s - Controller called', self::FILE_NAME), [ + 'context' => [], + 'HTTP_STATUS_CODE' => http_response_code(), + ]); + $cartId = Tools::getValue('cartId'); $secureKey = Tools::getValue('secureKey'); $cart = new Cart($cartId); if (!Validate::isLoadedObject($cart)) { + $logger->error(sprintf('%s - Cart not found', self::FILE_NAME), [ + 'context' => [], + 'exceptions' => [], + ]); + $this->ajaxDie(json_encode([ 'error_type' => 'unknown_error', - 'error_text' => $this->module->l('An unknown error error occurred. Please contact support', self::FILENAME), + 'error_text' => $this->module->l('An unknown error error occurred. Please contact support', self::FILE_NAME), ])); } if ($cart->secure_key !== $secureKey) { - die($this->module->l('Error. Insecure cart', self::FILENAME)); + $logger->error(sprintf('%s - Insecure cart', self::FILE_NAME), [ + 'context' => [ + 'cart_id' => $cartId, + ], + 'exceptions' => [], + ]); + + die($this->module->l('Error. Insecure cart', self::FILE_NAME)); } $lockResult = $this->applyLock(sprintf( @@ -68,20 +90,30 @@ public function postProcess() if (!SaferPayConfig::isVersion17()) { if ($lockResult > 200) { - die($this->module->l('Lock already exists', self::FILENAME)); + die($this->module->l('Lock already exists', self::FILE_NAME)); } } else { if (!$lockResult->isSuccessful()) { - die($this->module->l('Lock already exists', self::FILENAME)); + die($this->module->l('Lock already exists', self::FILE_NAME)); } } - if ($cart->orderExists()) { + /** @var \Invertus\SaferPay\Adapter\Cart $cartAdaoter */ + $cartAdapter = $this->module->getService(\Invertus\SaferPay\Adapter\Cart::class); + + if ($cartAdapter->orderExists($cartId)) { $order = new Order($this->getOrderId($cartId)); $completed = (int) Configuration::get(SaferPayConfig::SAFERPAY_PAYMENT_COMPLETED); if ((int) $order->current_state === $completed) { - die($this->module->l('Order already complete', self::FILENAME)); + $logger->debug(sprintf('%s - Order already complete. Dying.', self::FILE_NAME), [ + 'context' => [ + 'id_order' => $order->id, + 'current_state' => $order->current_state, + ], + ]); + + die($this->module->l('Order already complete', self::FILE_NAME)); } } @@ -117,7 +149,19 @@ public function postProcess() $orderStatusService = $this->module->getService(SaferPayOrderStatusService::class); $orderStatusService->cancel($order); - die($this->module->l('Liability shift is false', self::FILENAME)); + $logger->debug(sprintf('%s - Liability shift is false', self::FILE_NAME), [ + 'context' => [ + 'id_order' => $order->id, + ], + ]); + + $logger->debug(sprintf('%s - liability shift is false', self::FILE_NAME), [ + 'context' => [ + 'id_order' => $order->id, + ], + ]); + + die($this->module->l('Liability shift is false', self::FILE_NAME)); } //NOTE to get latest information possible and not override new information. @@ -129,6 +173,12 @@ public function postProcess() if (!SaferPayConfig::supportsOrderCapture($paymentMethod) && $transactionStatus === TransactionStatus::CAPTURED ) { + $logger->debug(sprintf('%s - order completed', self::FILE_NAME), [ + 'context' => [ + 'id_order' => $order->id, + ], + ]); + /** @var SaferPayOrderStatusService $orderStatusService */ $orderStatusService = $this->module->getService(SaferPayOrderStatusService::class); $orderStatusService->setComplete($order); @@ -140,11 +190,22 @@ public function postProcess() (int) Configuration::get(SaferPayConfig::PAYMENT_BEHAVIOR) === SaferPayConfig::DEFAULT_PAYMENT_BEHAVIOR_CAPTURE && $transactionStatus !== TransactionStatus::CAPTURED ) { + $logger->debug(sprintf('%s - order captured', self::FILE_NAME), [ + 'context' => [ + 'id_order' => $order->id, + ], + ]); + /** @var SaferPayOrderStatusService $orderStatusService */ $orderStatusService = $this->module->getService(SaferPayOrderStatusService::class); $orderStatusService->capture($order); } } catch (Exception $e) { + $logger->debug($e->getMessage(), [ + 'context' => [], + 'exceptions' => ExceptionUtility::getExceptions($e), + ]); + // this might be executed after pending transaction is declined (e.g. with accountToAccount payment) if (!isset($order)) { $order = new Order($this->getOrderId($cartId)); @@ -156,7 +217,7 @@ public function postProcess() $saferPayCapturedStatus = (int) Configuration::get(\Invertus\SaferPay\Config\SaferPayConfig::SAFERPAY_PAYMENT_COMPLETED); if ((int) $order->current_state === $saferPayCapturedStatus) { - die($this->module->l('Order already created', self::FILENAME)); + die($this->module->l('Order already created', self::FILE_NAME)); } // assuming order transaction was declined @@ -181,27 +242,27 @@ public function postProcess() die('canceled'); } - PrestaShopLogger::addLog( - sprintf( - '%s has caught an error: %s', - __CLASS__, - $e->getMessage() - ), - 1, - null, - null, - null, - true - ); + /** @var LoggerInterface $logger */ + $logger = $this->module->getService(LoggerInterface::class); + $logger->error(sprintf('%s - AccountToAccount order is declined', self::FILE_NAME), [ + 'context' => [ + 'orderId' => $orderId, + ], + 'exceptions' => ExceptionUtility::getExceptions($e), + ]); + $this->releaseLock(); - die($this->module->l($e->getMessage(), self::FILENAME)); + die($this->module->l($e->getMessage(), self::FILE_NAME)); } - die($this->module->l('Success', self::FILENAME)); + $logger->debug(sprintf('%s - Controller action ended', self::FILE_NAME)); + + die($this->module->l('Success', self::FILE_NAME)); } - private function assertTransaction($cartId) { + private function assertTransaction($cartId) + { /** @var SaferPayTransactionAssertion $transactionAssert */ $transactionAssert = $this->module->getService(SaferPayTransactionAssertion::class); @@ -217,10 +278,9 @@ private function getOrderId($cartId) { if (method_exists('Order', 'getIdByCartId')) { return Order::getIdByCartId($cartId); - } else { - // For PrestaShop 1.6 use the alternative method - return Order::getOrderByCartId($cartId); } + // For PrestaShop 1.6 use the alternative method + return Order::getOrderByCartId($cartId); } protected function displayMaintenancePage() diff --git a/controllers/front/pendingNotify.php b/controllers/front/pendingNotify.php index cf25f56d..4d929600 100755 --- a/controllers/front/pendingNotify.php +++ b/controllers/front/pendingNotify.php @@ -24,6 +24,7 @@ use Invertus\SaferPay\Api\Enum\TransactionStatus; use Invertus\SaferPay\Controller\AbstractSaferPayController; use Invertus\SaferPay\DTO\Response\AssertRefund\AssertRefundBody; +use Invertus\SaferPay\Logger\LoggerInterface; use Invertus\SaferPay\Repository\SaferPayOrderRepository; use Invertus\SaferPay\Service\TransactionFlow\SaferPayTransactionRefundAssertion; @@ -33,7 +34,7 @@ class SaferPayOfficialPendingNotifyModuleFrontController extends AbstractSaferPayController { - const FILENAME = 'pendingNotify'; + const FILE_NAME = 'pendingNotify'; /** * This code is being called by SaferPay by using NotifyUrl in InitializeRequest. @@ -42,13 +43,18 @@ class SaferPayOfficialPendingNotifyModuleFrontController extends AbstractSaferPa */ public function postProcess() { + /** @var LoggerInterface $logger */ + $logger = $this->module->getService(LoggerInterface::class); + + $logger->debug(sprintf('%s - Controller called', self::FILE_NAME)); + $cartId = Tools::getValue('cartId'); $secureKey = Tools::getValue('secureKey'); $cart = new Cart($cartId); if ($cart->secure_key !== $secureKey) { - die($this->module->l('Error. Insecure cart', self::FILENAME)); + die($this->module->l('Error. Insecure cart', self::FILE_NAME)); } /** @var SaferPayOrderRepository $saferPayOrderRepository */ @@ -67,7 +73,9 @@ public function postProcess() } } - die($this->module->l('Success', self::FILENAME)); + $logger->debug(sprintf('%s - Controller action ended', self::FILE_NAME)); + + die($this->module->l('Success', self::FILE_NAME)); } /** @@ -89,6 +97,14 @@ private function handleCapturedRefund($orderRefundId) /** @var SaferPayOrderRepository $saferPayOrderRepository */ $saferPayOrderRepository = $this->module->getService(SaferPayOrderRepository::class); + /** @var LoggerInterface $logger */ + $logger = $this->module->getService(LoggerInterface::class); + $logger->debug(sprintf('%s - Capture refund', self::FILE_NAME), [ + 'context' => [ + 'order_refund_id' => $orderRefundId, + ], + ]); + $orderRefund = new SaferPayOrderRefund($orderRefundId); $orderRefund->status = TransactionStatus::CAPTURED; $orderRefund->update(); diff --git a/controllers/front/return.php b/controllers/front/return.php index 1ce79fd0..3f557fa3 100755 --- a/controllers/front/return.php +++ b/controllers/front/return.php @@ -24,12 +24,18 @@ use Invertus\SaferPay\Api\Enum\TransactionStatus; use Invertus\SaferPay\Config\SaferPayConfig; use Invertus\SaferPay\Controller\AbstractSaferPayController; +use Invertus\SaferPay\Core\Payment\DTO\CheckoutData; use Invertus\SaferPay\DTO\Response\Assert\AssertBody; use Invertus\SaferPay\Enum\ControllerName; +use Invertus\SaferPay\Enum\PaymentType; use Invertus\SaferPay\Exception\Api\SaferPayApiException; +use Invertus\SaferPay\Logger\LoggerInterface; +use Invertus\SaferPay\Processor\CheckoutProcessor; +use Invertus\SaferPay\Repository\SaferPayFieldRepository; use Invertus\SaferPay\Service\SaferPayOrderStatusService; use Invertus\SaferPay\Service\TransactionFlow\SaferPayTransactionAssertion; use Invertus\SaferPay\Service\TransactionFlow\SaferPayTransactionAuthorization; +use Invertus\SaferPay\Utility\ExceptionUtility; if (!defined('_PS_VERSION_')) { exit; @@ -37,37 +43,109 @@ class SaferPayOfficialReturnModuleFrontController extends AbstractSaferPayController { - const FILENAME = 'return'; + const FILE_NAME = 'return'; public function postProcess() { + /** @var LoggerInterface $logger */ + $logger = $this->module->getService(LoggerInterface::class); + + $logger->debug(sprintf('%s - Controller called', self::FILE_NAME)); + $cartId = (int) Tools::getValue('cartId'); $order = new Order($this->getOrderId($cartId)); + $secureKey = Tools::getValue('secureKey'); + $selectedCard = Tools::getValue('selectedCard'); + $paymentMethod = $order->id ? $order->payment : Tools::getValue('paymentMethod'); + $cart = new Cart($cartId); + $failController = $this->getFailController($paymentMethod); - if (!$order->id) { - return; + if (!Validate::isLoadedObject($cart)) { + $this->warning[] = $this->module->l('An unknown error error occurred. Please contact support', self::FILE_NAME); + $this->redirectWithNotifications($this->getRedirectionToControllerUrl($failController)); + } + + if ($cart->secure_key !== $secureKey) { + $this->warning[] = $this->module->l('Error. Insecure cart', self::FILE_NAME); + $this->redirectWithNotifications($this->getRedirectionToControllerUrl($failController)); } + /** @var SaferPayTransactionAssertion $transactionAssert */ + $transactionAssert = $this->module->getService(SaferPayTransactionAssertion::class); + try { - /** @var SaferPayTransactionAssertion $transactionAssert */ - $transactionAssert = $this->module->getService(SaferPayTransactionAssertion::class); - $transactionResponse = $transactionAssert->assert($cartId, false); + $assertResponseBody = $transactionAssert->assert( + $cartId, + (int) $selectedCard === SaferPayConfig::CREDIT_CARD_OPTION_SAVE, + $selectedCard, + (int) Tools::getValue(SaferPayConfig::IS_BUSINESS_LICENCE) + ); + $transactionStatus = $assertResponseBody->getTransaction()->getStatus(); + } catch (Exception $e) { + $logger->error($e->getMessage(), [ + 'context' => [], + 'exceptions' => ExceptionUtility::getExceptions($e), + ]); + + $this->warning[] = $this->module->l('An error occurred. Please contact support', self::FILE_NAME); + $this->redirectWithNotifications($this->getRedirectionToControllerUrl($failController)); + } + + $orderPayment = $assertResponseBody->getPaymentMeans()->getBrand()->getPaymentMethod(); + + if (!empty($assertResponseBody->getPaymentMeans()->getWallet())) { + $orderPayment = $assertResponseBody->getPaymentMeans()->getWallet(); + } + + /** @var SaferPayFieldRepository $saferPayFieldRepository */ + $saferPayFieldRepository = $this->module->getService(SaferPayFieldRepository::class); + + /** + * NOTE: This flow is for hosted iframe payment method + */ + if (Configuration::get(SaferPayConfig::BUSINESS_LICENSE . SaferPayConfig::getConfigSuffix()) + || Configuration::get(SaferPayConfig::FIELDS_ACCESS_TOKEN . SaferPayConfig::getConfigSuffix()) + || $saferPayFieldRepository->isActiveByName($orderPayment)) + { + $order = new Order($this->getOrderId($cartId)); + + try { + $this->createAndValidateOrder($assertResponseBody, $transactionStatus, $cartId, $orderPayment); + } catch (Exception $e) { + $logger->debug($e->getMessage(), [ + 'context' => [], + 'exceptions' => ExceptionUtility::getExceptions($e), + ]); + + $this->warning[] = $this->module->l('An error occurred. Please contact support', self::FILE_NAME); + $this->redirectWithNotifications($this->getRedirectionToControllerUrl('fail')); + } + } + try { /** @var SaferPayOrderStatusService $orderStatusService */ $orderStatusService = $this->module->getService(SaferPayOrderStatusService::class); - if ($transactionResponse->getTransaction()->getStatus() === TransactionStatus::PENDING) { + if ($assertResponseBody->getTransaction()->getStatus() === TransactionStatus::PENDING) { $orderStatusService->setPending($order); } } catch (SaferPayApiException $e) { - \PrestaShopLogger::addLog($e->getMessage()); + $logger->debug($e->getMessage(), [ + 'context' => [], + 'exceptions' => ExceptionUtility::getExceptions($e), + ]); // we only care if we have a response with pending status, else we skip further actions } + + $logger->debug(sprintf('%s - Controller action ended', self::FILE_NAME)); } /** * @throws PrestaShopException */ public function initContent() { + /** @var LoggerInterface $logger */ + $logger = $this->module->getService(LoggerInterface::class); + $cartId = Tools::getValue('cartId'); $secureKey = Tools::getValue('secureKey'); $isBusinessLicence = (int) Tools::getValue(SaferPayConfig::IS_BUSINESS_LICENCE); @@ -77,20 +155,34 @@ public function initContent() $cart = new Cart($cartId); if (!Validate::isLoadedObject($cart)) { + $logger->error(sprintf('%s - Cart not found', self::FILE_NAME), [ + 'context' => [], + 'exceptions' => [], + ]); + $this->ajaxDie(json_encode([ 'error_type' => 'unknown_error', - 'error_text' => $this->module->l('An unknown error error occurred. Please contact support', self::FILENAME), + 'error_text' => $this->module->l('An unknown error error occurred. Please contact support', self::FILE_NAME), ])); } if ($cart->secure_key !== $secureKey) { + $logger->error(sprintf('%s - Secure key does not match', self::FILE_NAME), [ + 'context' => [ + 'cartId' => $cartId, + ], + ]); + $this->ajaxDie(json_encode([ 'error_type' => 'unknown_error', - 'error_text' => $this->module->l('An unknown error error occurred. Please contact support', self::FILENAME), + 'error_text' => $this->module->l('An unknown error error occurred. Please contact support', self::FILE_NAME), ])); } - if ($cart->orderExists()) { + /** @var \Invertus\SaferPay\Adapter\Cart $cart */ + $cartAdapter = $this->module->getService(\Invertus\SaferPay\Adapter\Cart::class); + + if ($cartAdapter->orderExists($cart->id)) { if (method_exists('Order', 'getIdByCartId')) { $orderId = Order::getIdByCartId($cartId); } else { @@ -103,10 +195,12 @@ public function initContent() $saferPayAuthorizedStatus = (int) Configuration::get(SaferPayConfig::SAFERPAY_PAYMENT_AUTHORIZED); $saferPayCapturedStatus = (int) Configuration::get(SaferPayConfig::SAFERPAY_PAYMENT_COMPLETED); + $usingSavedCard = $selectedCard > 0; + if ((int) $order->current_state === $saferPayAuthorizedStatus || (int) $order->current_state === $saferPayCapturedStatus) { Tools::redirect($this->context->link->getModuleLink( $this->module->name, - $this->getSuccessControllerName($isBusinessLicence, $fieldToken), + $this->getSuccessControllerName($isBusinessLicence, $fieldToken, $usingSavedCard), [ 'cartId' => $cartId, 'orderId' => $orderId, @@ -141,7 +235,7 @@ public function initContent() $this->setTemplate('saferpay_wait_16.tpl'); } - private function getSuccessControllerName($isBusinessLicence, $fieldToken) + private function getSuccessControllerName($isBusinessLicence, $fieldToken, $usingSavedCard) { $successController = ControllerName::SUCCESS; @@ -149,7 +243,7 @@ private function getSuccessControllerName($isBusinessLicence, $fieldToken) $successController = ControllerName::SUCCESS_IFRAME; } - if ($fieldToken) { + if ($fieldToken || $usingSavedCard) { $successController = ControllerName::SUCCESS_HOSTED; } @@ -184,9 +278,140 @@ private function getOrderId($cartId) { if (method_exists('Order', 'getIdByCartId')) { return Order::getIdByCartId($cartId); - } else { - // For PrestaShop 1.6 use the alternative method - return Order::getOrderByCartId($cartId); } + // For PrestaShop 1.6 use the alternative method + return Order::getOrderByCartId($cartId); + } + + /** + * @param string $controllerName + * + * @return string + */ + private function getRedirectionToControllerUrl($controllerName) + { + $cartId = $this->context->cart->id ? $this->context->cart->id : Tools::getValue('cartId'); + return $this->context->link->getModuleLink( + $this->module->name, + $controllerName, + [ + 'cartId' => $cartId, + 'orderId' => Order::getOrderByCartId($cartId), + 'secureKey' => $this->context->cart->secure_key, + 'moduleId' => $this->module->id, + ] + ); + } + + private function createAndValidateOrder($assertResponseBody, $transactionStatus, $cartId, $orderPayment) + { + /** @var LoggerInterface $logger */ + $logger = $this->module->getService(LoggerInterface::class); + + if (SaferPayConfig::isRedirectPayment($orderPayment)) { + $logger->debug('Redirect payment selected, skipping order creation', [ + 'context' => [], + 'controller' => self::FILE_NAME, + 'order_payment' => $orderPayment, + ]); + return; + } + + $logger->debug('Not redirect payment selected, creating order', [ + 'context' => [], + 'controller' => self::FILE_NAME, + 'order_payment' => $orderPayment, + ]); + + /** @var CheckoutProcessor $checkoutProcessor * */ + $checkoutProcessor = $this->module->getService(CheckoutProcessor::class); + + $checkoutData = CheckoutData::create( + (int)$cartId, + $assertResponseBody->getPaymentMeans()->getBrand()->getPaymentMethod(), + (int)Configuration::get(SaferPayConfig::IS_BUSINESS_LICENCE) + ); + $checkoutData->setOrderStatus($transactionStatus); + + /** + * NOTE: This check is needed because ACCOUNTTOACCOUNT payment method + * is always being created before initialize API request + */ + if ($orderPayment !== SaferPayConfig::PAYMENT_ACCOUNTTOACCOUNT) { + $checkoutProcessor->run($checkoutData); + } + + $orderId = $this->getOrderId($cartId); + + $order = new Order($orderId); + if (!$assertResponseBody->getLiability()->getLiabilityShift() && + in_array($order->payment, SaferPayConfig::SUPPORTED_3DS_PAYMENT_METHODS) && + (int) Configuration::get(SaferPayConfig::PAYMENT_BEHAVIOR_WITHOUT_3D) === SaferPayConfig::PAYMENT_BEHAVIOR_WITHOUT_3D_CANCEL + ) { + /** @var SaferPayOrderStatusService $orderStatusService */ + $orderStatusService = $this->module->getService(SaferPayOrderStatusService::class); + $orderStatusService->cancel($order); + } + + //NOTE to get latest information possible and not override new information. + + $paymentMethod = $assertResponseBody->getPaymentMeans()->getBrand()->getPaymentMethod();// if payment does not support order capture, it means it always auto-captures it (at least with accountToAccount payment), + + // so in this case if status comes back "captured" we just update the order state accordingly + if (!SaferPayConfig::supportsOrderCapture($paymentMethod) && + $transactionStatus === TransactionStatus::CAPTURED + ) { + /** @var SaferPayOrderStatusService $orderStatusService */ + $orderStatusService = $this->module->getService(SaferPayOrderStatusService::class); + $orderStatusService->setComplete($order); + + return; + } + + if (SaferPayConfig::supportsOrderCapture($paymentMethod) && + (int) Configuration::get(SaferPayConfig::PAYMENT_BEHAVIOR) === SaferPayConfig::DEFAULT_PAYMENT_BEHAVIOR_CAPTURE && + $transactionStatus !== TransactionStatus::CAPTURED + ) { + /** @var SaferPayOrderStatusService $orderStatusService */ + $orderStatusService = $this->module->getService(SaferPayOrderStatusService::class); + $orderStatusService->capture($order); + + return; + } + } + + private function getFailController($orderPayment) + { + /** @var \Invertus\SaferPay\Provider\PaymentTypeProvider $paymentTypeProvider */ + $paymentTypeProvider = $this->module->getService(\Invertus\SaferPay\Provider\PaymentTypeProvider::class); + + /** @var LoggerInterface $logger */ + $logger = $this->module->getService(LoggerInterface::class); + + $logger->debug('Getting fail controller', [ + 'context' => [], + 'controller' => self::FILE_NAME, + 'order_payment' => $orderPayment, + ]); + + $paymentRedirectType = $paymentTypeProvider->get($orderPayment); + + if ($paymentRedirectType === PaymentType::IFRAME) { + $logger->debug('Fail controller is FAIL_IFRAME', [ + 'context' => [], + 'controller' => self::FILE_NAME, + 'order_payment' => $orderPayment, + ]); + + return ControllerName::FAIL_IFRAME; + } + + $logger->debug('Fail controller is FAIL', [ + 'context' => [], + 'controller' => self::FILE_NAME, + 'order_payment' => $orderPayment, + ]); + + return ControllerName::FAIL; } } diff --git a/controllers/front/success.php b/controllers/front/success.php index fc74b240..f41c8ccd 100755 --- a/controllers/front/success.php +++ b/controllers/front/success.php @@ -22,6 +22,7 @@ */ use Invertus\SaferPay\Controller\AbstractSaferPayController; +use Invertus\SaferPay\Logger\LoggerInterface; if (!defined('_PS_VERSION_')) { exit; @@ -29,10 +30,15 @@ class SaferPayOfficialSuccessModuleFrontController extends AbstractSaferPayController { - const FILENAME = 'success'; + const FILE_NAME = 'success'; public function postProcess() { + /** @var LoggerInterface $logger */ + $logger = $this->module->getService(LoggerInterface::class); + + $logger->debug(sprintf('%s - Controller called', self::FILE_NAME)); + $cartId = Tools::getValue('cartId'); $moduleId = Tools::getValue('moduleId'); $orderId = Tools::getValue('orderId'); @@ -41,6 +47,12 @@ public function postProcess() $cart = new Cart($cartId); if ($cart->secure_key !== $secureKey) { + $logger->error(sprintf('%s - Secure key does not match', self::FILE_NAME), [ + 'context' => [ + 'cartId' => $cartId, + ] + ]); + $redirectLink = $this->context->link->getPageLink( 'order', true, @@ -53,6 +65,8 @@ public function postProcess() Tools::redirect($redirectLink); } + $logger->debug(sprintf('%s - Controller action ended', self::FILE_NAME)); + Tools::redirect($this->context->link->getPageLink( 'order-confirmation', true, diff --git a/controllers/front/successHosted.php b/controllers/front/successHosted.php index 9998633d..fb26d493 100755 --- a/controllers/front/successHosted.php +++ b/controllers/front/successHosted.php @@ -21,12 +21,11 @@ *@license SIX Payment Services */ -use Invertus\SaferPay\Api\Enum\TransactionStatus; use Invertus\SaferPay\Config\SaferPayConfig; use Invertus\SaferPay\Controller\AbstractSaferPayController; use Invertus\SaferPay\Enum\ControllerName; -use Invertus\SaferPay\Service\SaferPayOrderStatusService; -use Invertus\SaferPay\Service\TransactionFlow\SaferPayTransactionAuthorization; +use Invertus\SaferPay\Logger\LoggerInterface; +use Invertus\SaferPay\Utility\ExceptionUtility; if (!defined('_PS_VERSION_')) { exit; @@ -49,6 +48,11 @@ public function init() public function postProcess() { + /** @var LoggerInterface $logger */ + $logger = $this->module->getService(LoggerInterface::class); + + $logger->debug(sprintf('%s - Controller called', self::FILE_NAME)); + $cartId = Tools::getValue('cartId'); $orderId = Tools::getValue('orderId'); $secureKey = Tools::getValue('secureKey'); @@ -62,20 +66,17 @@ public function postProcess() } try { + $logger->debug(sprintf('%s - Controller action ended', self::FILE_NAME)); + Tools::redirect($this->getOrderConfirmationLink($cartId, $moduleId, $orderId, $secureKey)); } catch (Exception $e) { - PrestaShopLogger::addLog( - sprintf( - '%s has caught an error: %s', - __CLASS__, - $e->getMessage() - ), - 1, - null, - null, - null, - true - ); + $logger->error($e->getMessage(), [ + 'context' => [ + 'cartId' => $cartId, + 'orderId' => $orderId, + ], + 'exceptions' => ExceptionUtility::getExceptions($e), + ]); Tools::redirect( $this->context->link->getModuleLink( diff --git a/controllers/front/successIFrame.php b/controllers/front/successIFrame.php index a7ce3b5d..22d8e591 100755 --- a/controllers/front/successIFrame.php +++ b/controllers/front/successIFrame.php @@ -21,13 +21,11 @@ *@license SIX Payment Services */ -use Invertus\SaferPay\Api\Enum\TransactionStatus; use Invertus\SaferPay\Config\SaferPayConfig; use Invertus\SaferPay\Controller\AbstractSaferPayController; use Invertus\SaferPay\Enum\ControllerName; -use Invertus\SaferPay\Exception\Api\SaferPayApiException; -use Invertus\SaferPay\Service\SaferPayOrderStatusService; -use Invertus\SaferPay\Service\TransactionFlow\SaferPayTransactionAuthorization; +use Invertus\SaferPay\Logger\LoggerInterface; +use Invertus\SaferPay\Utility\ExceptionUtility; if (!defined('_PS_VERSION_')) { exit; @@ -50,6 +48,11 @@ public function init() public function postProcess() // todo refactor this by the logic provided { + /** @var LoggerInterface $logger */ + $logger = $this->module->getService(LoggerInterface::class); + + $logger->debug(sprintf('%s - Controller called', self::FILE_NAME)); + $cartId = Tools::getValue('cartId'); $orderId = Tools::getValue('orderId'); $secureKey = Tools::getValue('secureKey'); @@ -63,21 +66,20 @@ public function postProcess() // todo refactor this by the logic provided $this->redirectWithNotifications($this->getOrderLink()); } + /** Purchase is made with card that needs to be saved */ + if (Tools::getValue('selectedCard') <= 0) { + return; + } + try { + $logger->debug(sprintf('%s - Controller action ended', self::FILE_NAME)); + Tools::redirect($this->getOrderConfirmationLink($cartId, $moduleId, $orderId, $secureKey)); } catch (Exception $e) { - PrestaShopLogger::addLog( - sprintf( - '%s has caught an error: %s', - __CLASS__, - $e->getMessage() - ), - 1, - null, - null, - null, - true - ); + $logger->error($e->getMessage(), [ + 'context' => [], + 'exceptions' => ExceptionUtility::getExceptions($e), + ]); Tools::redirect( $this->context->link->getModuleLink( @@ -124,9 +126,16 @@ public function initContent() $this->setTemplate(SaferPayConfig::SAFERPAY_TEMPLATE_LOCATION . '/front/loading.tpl'); return; } + + $jsUrl = "{$this->module->getPathUri()}views/js/front/saferpay_iframe_16.js"; + + if (SaferPayConfig::isVersion17()) { + $jsUrl = "{$this->module->getPathUri()}views/js/front/saferpay_iframe.js"; + } + $this->context->smarty->assign([ 'cssUrl' => "{$this->module->getPathUri()}views/css/front/loading.css", - 'jsUrl' => "{$this->module->getPathUri()}views/js/front/saferpay_iframe.js", + 'jsUrl' => $jsUrl, 'redirectUrl' => $orderLink, ]); $this->setTemplate('loading_16.tpl'); diff --git a/controllers/front/validation.php b/controllers/front/validation.php index de8d1cf2..ecb4bf77 100755 --- a/controllers/front/validation.php +++ b/controllers/front/validation.php @@ -24,6 +24,7 @@ use Invertus\SaferPay\Config\SaferPayConfig; use Invertus\SaferPay\Controller\AbstractSaferPayController; use Invertus\SaferPay\Core\Payment\DTO\CheckoutData; +use Invertus\SaferPay\Logger\LoggerInterface; use Invertus\SaferPay\Service\SaferPayExceptionService; use Invertus\SaferPay\Controller\Front\CheckoutController; @@ -33,7 +34,7 @@ class SaferPayOfficialValidationModuleFrontController extends AbstractSaferPayController { - const FILENAME = 'validation'; + const FILE_NAME = 'validation'; /** @var SaferPayOfficial */ public $module; @@ -43,6 +44,11 @@ class SaferPayOfficialValidationModuleFrontController extends AbstractSaferPayCo */ public function postProcess() { + /** @var LoggerInterface $logger */ + $logger = $this->module->getService(LoggerInterface::class); + + $logger->debug(sprintf('%s - Controller called', self::FILE_NAME)); + $paymentMethod = Tools::getValue('saved_card_method'); $cart = $this->context->cart; $redirectLink = $this->context->link->getPageLink( @@ -69,12 +75,12 @@ public function postProcess() } } if (!$authorized) { - $this->errors[] = $this->module->l('This payment method is not available.', self::FILENAME); + $this->errors[] = $this->module->l('This payment method is not available.', self::FILE_NAME); $this->redirectWithNotifications($redirectLink); } if (Order::getOrderByCartId($this->context->cart->id)) { - $this->errors[] = $this->module->l('Order already exists.', self::FILENAME); + $this->errors[] = $this->module->l('Order already exists.', self::FILE_NAME); $this->redirectWithNotifications($redirectLink); } @@ -90,6 +96,8 @@ public function postProcess() $redirectLink = $checkoutController->execute($checkoutData); + $logger->debug(sprintf('%s - Controller action ended', self::FILE_NAME)); + Tools::redirect($redirectLink); } catch (\Exception $exception) { /** @var SaferPayExceptionService $exceptionService */ diff --git a/saferpayofficial.php b/saferpayofficial.php index a4a4e230..c467a61a 100755 --- a/saferpayofficial.php +++ b/saferpayofficial.php @@ -40,7 +40,7 @@ public function __construct($name = null) { $this->name = 'saferpayofficial'; $this->author = 'Invertus'; - $this->version = '1.2.3'; + $this->version = '1.2.4'; $this->module_key = '3d3506c3e184a1fe63b936b82bda1bdf'; $this->displayName = 'SaferpayOfficial'; $this->description = 'Saferpay Payment module'; @@ -179,10 +179,10 @@ public function hookActionObjectOrderPaymentAddAfter($params) public function hookPaymentOptions($params) { - /** @var Invertus\SaferPay\Service\SaferPayCartService $assertService */ + /** @var Invertus\SaferPay\Service\SaferPayCartService $cartService */ $cartService = $this->getService(\Invertus\SaferPay\Service\SaferPayCartService::class); if (!$cartService->isCurrencyAvailable($params['cart'])) { - return; + return []; } /** @var \Invertus\SaferPay\Provider\PaymentTypeProvider $paymentTypeProvider */ @@ -206,15 +206,29 @@ public function hookPaymentOptions($params) \Invertus\SaferPay\Service\PaymentRestrictionValidation::class ); + $logosEnabled = $paymentRepository->getAllActiveLogosNames(); + $logosEnabled = array_column($logosEnabled, 'name'); + + $activePaymentMethods = $paymentRepository->getActivePaymentMethodsNames(); + $activePaymentMethods = array_column($activePaymentMethods, 'name'); + foreach ($paymentMethods as $paymentMethod) { $paymentMethod['paymentMethod'] = str_replace(' ', '', $paymentMethod['paymentMethod']); + if (!in_array($paymentMethod['paymentMethod'], $activePaymentMethods)) { + continue; + } + + if (!in_array($this->context->currency->iso_code, $paymentMethods[$paymentMethod['paymentMethod']]['currencies'])) { + continue; + } + if (!$paymentRestrictionValidation->isPaymentMethodValid($paymentMethod['paymentMethod'])) { continue; } - $imageUrl = ($paymentRepository->isLogoEnabledByName($paymentMethod['paymentMethod'])) + $imageUrl = (in_array($paymentMethod['paymentMethod'], $logosEnabled)) ? $paymentMethod['logoUrl'] : ''; $isCreditCard = in_array( @@ -330,31 +344,19 @@ public function hookDisplayAdminOrder(array $params) public function hookActionFrontControllerSetMedia() { + /** @var \Invertus\SaferPay\Validation\ValidateIsAssetsRequired $validateIsAssetsRequired */ + $validateIsAssetsRequired = $this->getService(\Invertus\SaferPay\Validation\ValidateIsAssetsRequired::class); + + if (!$validateIsAssetsRequired->run($this->context->controller)) { + return; + } + /** @var \Invertus\SaferPay\Presentation\Loader\PaymentFormAssetLoader $paymentFormAssetsLoader */ $paymentFormAssetsLoader = $this->getService(\Invertus\SaferPay\Presentation\Loader\PaymentFormAssetLoader::class); $paymentFormAssetsLoader->register($this->context->controller); - if ($this->context->controller instanceof OrderController) { - if (\Invertus\SaferPay\Config\SaferPayConfig::isVersion17()) { - $this->context->controller->registerJavascript( - 'saved-card', - 'modules/' . $this->name . '/views/js/front/saferpay_saved_card.js' - ); - - $this->context->controller->addCSS("{$this->getPathUri()}views/css/front/saferpay_checkout.css"); - } else { - $this->context->controller->addCSS("{$this->getPathUri()}views/css/front/saferpay_checkout_16.css"); - $this->context->controller->addJS("{$this->getPathUri()}views/js/front/saferpay_saved_card_16.js"); - $fieldsLibrary = \Invertus\SaferPay\Config\SaferPayConfig::FIELDS_LIBRARY; - $configSuffix = \Invertus\SaferPay\Config\SaferPayConfig::getConfigSuffix(); - $this->context->controller->addJs(Configuration::get($fieldsLibrary . $configSuffix)); - } - - /** @var \Invertus\SaferPay\Service\SaferPayErrorDisplayService $errorDisplayService */ - $errorDisplayService = $this->getService(\Invertus\SaferPay\Service\SaferPayErrorDisplayService::class); - $errorDisplayService->showCookieError('saferpay_payment_canceled_error'); - } + $paymentFormAssetsLoader->registerErrorBags(); } public function hookDisplayCustomerAccount() @@ -365,14 +367,10 @@ public function hookDisplayCustomerAccount() return; } if (\Invertus\SaferPay\Config\SaferPayConfig::isVersion17()) { - return $this->context->smarty->fetch( - $this->getLocalPath() . 'views/templates/hook/front/MyAccount.tpl' - ); + return $this->display(__FILE__, 'front/MyAccount.tpl'); } - return $this->context->smarty->fetch( - $this->getLocalPath() . 'views/templates/hook/front/MyAccount_16.tpl' - ); + return $this->display(__FILE__, 'front/MyAccount_16.tpl'); } public function displayNavigationTop() @@ -472,6 +470,10 @@ public function hookDisplayPayment($params) continue; } + if (!in_array($this->context->currency->iso_code, $paymentMethods[$paymentMethod['paymentMethod']]['currencies'])) { + continue; + } + $imageUrl = ($paymentRepository->isLogoEnabledByName($paymentMethod['paymentMethod'])) ? $paymentMethod['logoUrl'] : ''; $isCreditCard = in_array($paymentMethod['paymentMethod'], \Invertus\SaferPay\Config\SaferPayConfig::TRANSACTION_METHODS); @@ -679,8 +681,8 @@ private function displayInAdminOrderPage(array $params) ); } else { $action = $this->context->link->getAdminLink( - self::ADMIN_ORDER_CONTROLLER - ) . '&id_order=' . (int) $orderId; + self::ADMIN_ORDER_CONTROLLER + ) . '&id_order=' . (int) $orderId; } $assertId = $orderRepo->getAssertIdBySaferPayOrderId($saferPayOrderId); diff --git a/src/Adapter/Cart.php b/src/Adapter/Cart.php new file mode 100644 index 00000000..b0aa490f --- /dev/null +++ b/src/Adapter/Cart.php @@ -0,0 +1,41 @@ + + *@copyright SIX Payment Services + *@license SIX Payment Services + */ + +namespace Invertus\SaferPay\Adapter; + +class Cart +{ + /** + * Check if order exists by cart id + * From PS 8.x + * + * @return bool + */ + public function orderExists($idCart) + { + return (bool) \Db::getInstance()->getValue( + 'SELECT count(*) FROM `' . _DB_PREFIX_ . 'orders` WHERE `id_cart` = ' . (int) $idCart, + false + ); + } +} \ No newline at end of file diff --git a/src/Adapter/LegacyContext.php b/src/Adapter/LegacyContext.php index 618d21cf..91434eec 100755 --- a/src/Adapter/LegacyContext.php +++ b/src/Adapter/LegacyContext.php @@ -38,7 +38,17 @@ public function getContext() public function getShopId() { - return $this->getContext()->shop->id; + return (int) $this->getContext()->shop->id; + } + + public function getLanguageId() + { + return (int) $this->getContext()->language->id; + } + + public function getLanguageIso() + { + return (string) $this->getContext()->language->iso_code ?: 'en'; } public function getCurrencyIsoCode() @@ -78,4 +88,133 @@ public function getDeviceDetect() { return (int) $this->getContext()->getDevice(); } + + public function getAdminLink($controllerName, array $params = []) + { + /* @noinspection PhpMethodParametersCountMismatchInspection - its valid for PS1.7 */ + return (string) Context::getContext()->link->getAdminLink($controllerName, true, [], $params); + } + + public function getLanguageCode() + { + return (string) $this->getContext()->language->language_code ?: 'en-us'; + } + + public function getCurrencyIso() + { + if (!$this->getContext()->currency) { + return ''; + } + + return (string) $this->getContext()->currency->iso_code; + } + + public function getCountryIso() + { + if (!$this->getContext()->country) { + return ''; + } + + return (string) $this->getContext()->country->iso_code; + } + + public function getCurrency() + { + return $this->getContext()->currency; + } + + public function getCustomerId() + { + if (!$this->getContext()->customer) { + return 0; + } + + return (int) $this->getContext()->customer->id; + } + + public function isCustomerLoggedIn() + { + if (!$this->getContext()->customer) { + return false; + } + + return (bool) $this->getContext()->customer->isLogged(); + } + + public function getCustomerEmail() + { + if (!$this->getContext()->customer) { + return ''; + } + + return $this->getContext()->customer->email; + } + + public function getShopDomain() + { + return (string) $this->getContext()->shop->domain; + } + + public function getShopName() + { + return (string) $this->getContext()->shop->name; + } + + public function getController() + { + return $this->getContext()->controller; + } + + /** + * @throws \Throwable + */ + public function setCurrentCart(\Cart $cart) + { + $this->getContext()->cart = $cart; + $this->getContext()->cart->update(); + + $this->getContext()->cookie->__set('id_cart', (int) $cart->id); + $this->getContext()->cookie->write(); + } + + public function setCountry(\Country $country) + { + $this->getContext()->country = $country; + } + + public function setCurrency(\Currency $currency) + { + $this->getContext()->currency = $currency; + } + + public function getBaseLink($shopId = null, $ssl = null) + { + return (string) $this->getContext()->link->getBaseLink($shopId, $ssl); + } + + public function getCartProducts() + { + $cart = $this->getContext()->cart; + + if (!$cart) { + return []; + } + + return $cart->getProducts(); + } + + public function getCart() + { + return isset($this->getContext()->cart) ? $this->getContext()->cart : null; + } + + public function getShopThemeName() + { + return $this->getContext()->shop->theme_name; + } + + public function updateCustomer(\Customer $customer) + { + $this->getContext()->updateCustomer($customer); + } } diff --git a/src/Adapter/Tools.php b/src/Adapter/Tools.php new file mode 100644 index 00000000..0c2911b7 --- /dev/null +++ b/src/Adapter/Tools.php @@ -0,0 +1,171 @@ + + *@copyright SIX Payment Services + *@license SIX Payment Services + */ + +namespace Invertus\SaferPay\Adapter; + +use Context as PrestashopContext; +use Tools as PrestashopTools; + +if (!defined('_PS_VERSION_')) { + exit; +} + +class Tools +{ + public function linkRewrite($str) + { + return PrestashopTools::str2url($str); + } + + public function redirectAdmin($controller) + { + PrestashopTools::redirectAdmin($controller); + } + + public function redirect($url) + { + PrestashopTools::redirect($url); + } + + public function isSubmit($form) + { + return PrestashopTools::isSubmit($form); + } + + public function strtoupper($string) + { + return PrestashopTools::strtoupper($string); + } + + public function strtolower($string) + { + return PrestashopTools::strtolower($string); + } + + public function encrypt($string) + { + return PrestashopTools::encrypt($string); + } + + public function passwdGen($length = 8, $flag = 'ALPHANUMERIC') + { + return PrestashopTools::passwdGen($length, $flag); + } + + public function fileGetContents( + $url, + $useIncludePath = false, + $steamContext = null, + $curlTimeout = 5, + $fallback = false + ) { + return PrestashopTools::file_get_contents($url, $useIncludePath, $steamContext, $curlTimeout, $fallback); + } + + public static function replaceAccentedChars($string) + { + return PrestashopTools::replaceAccentedChars($string); + } + + /** + * @param string $value + * @param string|false $defaultValue + * + * @return mixed Value + */ + public function getValue($value, $defaultValue = false) + { + $toolsValue = PrestashopTools::getValue($value, $defaultValue); + + return is_null($toolsValue) || $toolsValue === '' || $toolsValue === 'null' ? null : $toolsValue; + } + + /** + * @param string $value + * @param string|false $defaultValue + * + * @return bool + */ + public function getValueAsBoolean($value, $defaultValue = false) + { + $result = $this->getValue($value, $defaultValue); + + if (in_array($result, ['false', '0', null, false, 0], true)) { + return false; + } + + return (bool) $result; + } + + /** + * @param string $value + * @param string|false $defaultValue + * + * @return bool + */ + public function getValueAsInteger($value, $defaultValue = false) + { + $result = $this->getValue($value, $defaultValue); + + if (in_array($result, ['false', '0', null, false, 0], true)) { + return 0; + } + + return (int) $result; + } + + public function getAllValues() + { + return PrestashopTools::getAllValues(); + } + + public function getValueAsInt($value, $defaultValue = 0) + { + return (int) PrestashopTools::getValue($value, $defaultValue); + } + + public function getShopDomain() + { + return PrestashopTools::getShopDomain(); + } + + public function displayPrice($price, $currency = null, $no_utf8 = false, PrestashopContext $context = null) + { + return PrestashopTools::displayPrice($price, $currency, $no_utf8, $context); + } + + public function ps_round($value, $precision = 0, $round_mode = null) + { + return PrestashopTools::ps_round($value, $precision, $round_mode); + } + + public function getToken($page = true, PrestashopContext $context = null) + { + return PrestashopTools::getToken($page, $context); + } + + public function convertPriceFull($amount, \Currency $currency_from = null, \Currency $currency_to = null) + { + return PrestashopTools::convertPriceFull($amount, $currency_from, $currency_to); + } +} diff --git a/src/Api/ApiRequest.php b/src/Api/ApiRequest.php index a005d7e9..27fe1af9 100755 --- a/src/Api/ApiRequest.php +++ b/src/Api/ApiRequest.php @@ -27,6 +27,8 @@ use Exception; use Invertus\SaferPay\Config\SaferPayConfig; use Invertus\SaferPay\Exception\Api\SaferPayApiException; +use Invertus\SaferPay\Logger\LoggerInterface; +use Invertus\SaferPay\Utility\ExceptionUtility; use SaferPayLog; use Unirest\Request; use Unirest\Response; @@ -37,6 +39,15 @@ class ApiRequest { + const FILE_NAME = 'ApiRequest'; + /** @var LoggerInterface */ + private $logger; + + public function __construct(LoggerInterface $logger) + { + $this->logger = $logger; + } + /** * API Request Post Method. * @@ -54,15 +65,24 @@ public function post($url, $params = []) json_encode($params) ); + $this->logger->debug(sprintf('%s - POST response: %d', self::FILE_NAME, $response->code), [ + 'context' => [ + 'uri' => $this->getBaseUrl() . $url, + 'headers' => $this->getHeaders(), + ], + 'request' => $params, + 'response' => $response->body, + ]); $this->isValidResponse($response); return json_decode($response->raw_body); } catch (Exception $exception) { - $logs = new SaferPayLog(); - $logs->message = $exception->getMessage() ?: "missing response"; - $logs->payload = json_encode($params); - $logs->add(); + $this->logger->error($exception->getMessage(), [ + 'context' => [], + 'exceptions' => ExceptionUtility::getExceptions($exception) + ]); + throw $exception; } } @@ -81,17 +101,31 @@ public function get($url, $params = []) $response = Request::get( $this->getBaseUrl() . $url, $this->getHeaders(), - json_encode($params) + $params ); + $this->logger->debug(sprintf('%s - GET response: %d', self::FILE_NAME, $response->code), [ + 'context' => [ + 'uri' => $this->getBaseUrl() . $url, + 'headers' => $this->getHeaders(), + ], + 'request' => $params, + 'response' => $response->body, + ]); + $this->isValidResponse($response); return json_decode($response->raw_body); } catch (Exception $exception) { - $logs = new SaferPayLog(); - $logs->message = $exception->getMessage() ?: "missing response"; - $logs->payload = json_encode($params); - $logs->add(); + $this->logger->error($exception->getMessage(), [ + 'context' => [ + 'headers' => $this->getHeaders(), + ], + 'request' => $params, + 'response' => json_decode($response->raw_body), + 'exceptions' => ExceptionUtility::getExceptions($exception) + ]); + throw $exception; } } @@ -118,7 +152,20 @@ private function getBaseUrl() private function isValidResponse(Response $response) { + if (isset($response->body->ErrorName) && $response->body->ErrorName === SaferPayConfig::TRANSACTION_ALREADY_CAPTURED) { + $this->logger->debug('Tried to apply state CAPTURED to already captured order', [ + 'context' => [] + ]); + + return; + } + if ($response->code >= 300) { + $this->logger->error(sprintf('%s - API thrown code: %d', self::FILE_NAME, $response->code), [ + 'context' => [], + 'response' => $response->body, + ]); + throw new SaferPayApiException(sprintf('Initialize API failed: %s', $response->raw_body), SaferPayApiException::INITIALIZE); } } diff --git a/src/Api/Request/AssertService.php b/src/Api/Request/AssertService.php index d1297a41..4ae3d511 100755 --- a/src/Api/Request/AssertService.php +++ b/src/Api/Request/AssertService.php @@ -24,12 +24,15 @@ namespace Invertus\SaferPay\Api\Request; use Exception; +use Invertus\SaferPay\Adapter\Configuration; use Invertus\SaferPay\Api\ApiRequest; +use Invertus\SaferPay\Config\SaferPayConfig; +use Invertus\SaferPay\Core\Payment\DTO\CheckoutData; use Invertus\SaferPay\DTO\Request\Assert\AssertRequest; use Invertus\SaferPay\DTO\Response\Assert\AssertBody; use Invertus\SaferPay\EntityBuilder\SaferPayAssertBuilder; +use Invertus\SaferPay\EntityBuilder\SaferPayCardAliasBuilder; use Invertus\SaferPay\Exception\Api\SaferPayApiException; -use Invertus\SaferPay\Exception\Api\TransactionDeclinedException; use Invertus\SaferPay\Service\Response\AssertResponseObjectCreator; use SaferPayOrder; @@ -55,15 +58,18 @@ class AssertService * @var SaferPayAssertBuilder */ private $assertBuilder; + private $aliasBuilder; public function __construct( ApiRequest $apiRequest, AssertResponseObjectCreator $assertResponseObjectCreator, - SaferPayAssertBuilder $assertBuilder + SaferPayAssertBuilder $assertBuilder, + SaferPayCardAliasBuilder $aliasBuilder ) { $this->apiRequest = $apiRequest; $this->assertResponseObjectCreator = $assertResponseObjectCreator; $this->assertBuilder = $assertBuilder; + $this->aliasBuilder = $aliasBuilder; } /** @@ -73,18 +79,14 @@ public function __construct( * @return object|null * @throws \Exception */ - public function assert(AssertRequest $assertRequest, $saferPayOrderId) + public function assert(AssertRequest $assertRequest, $isBusiness) { - $saferPayOrder = new SaferPayOrder($saferPayOrderId); - $assertApi = self::ASSERT_API_PAYMENT; - //TODO: refactor this to use authorize request. - // naming is weird. With transaction, we do a request to an authorize endpoint but name it assert ? - // also we call authorize method in some of the success controllers, so if we leave the logic here, - // we get an error with TRANSACTION_IN_WRONG_STATE - if ($saferPayOrder->is_transaction) { - $assertApi = self::ASSERT_API_TRANSACTION; + $isBusinessLicense = \Configuration::get(SaferPayConfig::BUSINESS_LICENSE . SaferPayConfig::getConfigSuffix()); + + if ($isBusiness) { + $assertApi = self::ASSERT_API_TRANSACTION; } try { @@ -104,10 +106,15 @@ public function assert(AssertRequest $assertRequest, $saferPayOrderId) * @return AssertBody * @throws Exception */ - public function createObjectsFromAssertResponse($responseBody, $saferPayOrderId) + public function createObjectsFromAssertResponse($responseBody, $saferPayOrderId, $customerId, $selectedCardOption) { $assertBody = $this->assertResponseObjectCreator->createAssertObject($responseBody); $this->assertBuilder->createAssert($assertBody, $saferPayOrderId); + $isPaymentSafe = $assertBody->getLiability()->getLiabilityShift(); + + if ((int) $selectedCardOption === SaferPayConfig::CREDIT_CARD_OPTION_SAVE && $isPaymentSafe) { + $this->aliasBuilder->createCardAlias($assertBody, $customerId); + } return $assertBody; } diff --git a/src/Config/SaferPayConfig.php b/src/Config/SaferPayConfig.php index 5685688b..d1e6b359 100755 --- a/src/Config/SaferPayConfig.php +++ b/src/Config/SaferPayConfig.php @@ -48,7 +48,6 @@ class SaferPayConfig const CREDIT_CARD_SAVE = 'SAFERPAY_CREDIT_CARD_SAVE'; const RESTRICT_REFUND_AMOUNT_TO_CAPTURED_AMOUNT = 'SAFERPAY_RESTRICT_REFUND_AMOUNT_TO_CAPTURED_AMOUNT'; const CONFIGURATION_NAME = 'SAFERPAY_CONFIGURATION_NAME'; - const CSS_FILE = 'SAFERPAY_CSS_FILE'; const TEST_SUFFIX = '_TEST'; const API_VERSION = '1.40'; const PAYMENT_METHODS = [ @@ -156,7 +155,6 @@ class SaferPayConfig self::PAYMENT_DINERS, self::PAYMENT_JCB, self::PAYMENT_MYONE, - self::PAYMENT_WECHATPAY, ]; const WLCRYPTOPAYMENTS_SUPPORTED_CURRENCIES = [ @@ -263,7 +261,28 @@ class SaferPayConfig const PAYMENT_BEHAVIOR_WITHOUT_3D_CANCEL = 0; const PAYMENT_BEHAVIOR_WITHOUT_3D_AUTHORIZE = 1; - public static function supportsOrderCapture(string $paymentMethod) + const SAFERPAY_CARDFORM_HOLDERNAME_REQUIRENCE = 'MANDATORY'; + const SAFERPAY_DEBUG_MODE = 'SAFERPAY_DEBUG_MODE'; + + const LOG_SEVERITY_LEVEL_INFORMATIVE = 1; + + const LOG_SEVERITY_LEVEL_WARNING = 2; + + const LOG_SEVERITY_LEVEL_ERROR = 3; + + const LOG_SEVERITY_LEVEL_MAJOR = 4; + const TRANSACTION_ALREADY_CAPTURED = 'TRANSACTION_ALREADY_CAPTURED'; + + const ONE_PAGE_CHECKOUT_MODULE = 'onepagecheckoutps'; + const THE_CHECKOUT_MODULE = 'thecheckout'; + const SUPER_CHECKOUT_MODULE = 'supercheckout'; + const OPC_MODULE_LIST = [ + self::ONE_PAGE_CHECKOUT_MODULE, + self::THE_CHECKOUT_MODULE, + self::SUPER_CHECKOUT_MODULE, + ]; + + public static function supportsOrderCapture($paymentMethod) { //payments that DOES NOT SUPPORT capture $unsupportedCapturePayments = [ @@ -274,7 +293,7 @@ public static function supportsOrderCapture(string $paymentMethod) return !in_array($paymentMethod, $unsupportedCapturePayments); } - public static function supportsOrderCancel(string $paymentMethod) + public static function supportsOrderCancel($paymentMethod) { //payments that DOES NOT SUPPORT order cancel $unsupportedCancelPayments = [ @@ -285,6 +304,23 @@ public static function supportsOrderCancel(string $paymentMethod) return !in_array($paymentMethod, $unsupportedCancelPayments); } + public static function isRedirectPayment($paymentMethod) + { + $paymentsAlwaysRedirect = [ + self::PAYMENT_WECHATPAY, + self::PAYMENT_ACCOUNTTOACCOUNT, + self::PAYMENT_APPLEPAY, + self::PAYMENT_GOOGLEPAY, + self::PAYMENT_TWINT, + self::PAYMENT_POSTFINANCE_PAY, + self::PAYMENT_DIRECTDEBIT, + self::PAYMENT_SOFORT, + self::PAYMENT_PAYPAL + ]; + + return in_array($paymentMethod, $paymentsAlwaysRedirect); + } + public static function getConfigSuffix() { @@ -398,7 +434,6 @@ public static function getUninstallConfiguration() self::BUSINESS_LICENSE . self::TEST_SUFFIX, self::PAYMENT_BEHAVIOR, self::CONFIGURATION_NAME, - self::CSS_FILE, self::PAYMENT_BEHAVIOR_WITHOUT_3D, self::CREDIT_CARD_SAVE, self::FIELDS_ACCESS_TOKEN, @@ -414,6 +449,11 @@ public static function isTestMode() return (bool) Configuration::get(self::TEST_MODE); } + public static function isDebugMode() + { + return (bool) Configuration::get(self::SAFERPAY_DEBUG_MODE); + } + public static function isVersion17() { return (bool) version_compare(_PS_VERSION_, '1.7', '>='); diff --git a/src/Context/GlobalShopContext.php b/src/Context/GlobalShopContext.php new file mode 100644 index 00000000..77c45368 --- /dev/null +++ b/src/Context/GlobalShopContext.php @@ -0,0 +1,83 @@ + + *@copyright SIX Payment Services + *@license SIX Payment Services + */ + +namespace Invertus\SaferPay\Context; + +use Invertus\SaferPay\Adapter\LegacyContext; + +if (!defined('_PS_VERSION_')) { + exit; +} +/** + * Gets shop context data + * NOTE: Done without interface because throwing error in the module + */ +class GlobalShopContext implements GlobalShopContextInterface +{ + private $context; + + public function __construct(LegacyContext $context) + { + $this->context = $context; + } + + public function getShopId() + { + return $this->context->getShopId(); + } + + public function getLanguageId() + { + return $this->context->getLanguageId(); + } + + public function getLanguageIso() + { + return $this->context->getLanguageIso(); + } + + public function getCurrencyIso() + { + return $this->context->getCurrencyIso(); + } + + public function getCurrency() + { + return $this->context->getCurrency(); + } + + public function getShopDomain() + { + return $this->context->getShopDomain(); + } + + public function getShopName() + { + return $this->context->getShopName(); + } + + public function isShopSingleShopContext() + { + return \Shop::getContext() === \Shop::CONTEXT_SHOP; + } +} diff --git a/src/Context/GlobalShopContextInterface.php b/src/Context/GlobalShopContextInterface.php new file mode 100644 index 00000000..b8f6e41a --- /dev/null +++ b/src/Context/GlobalShopContextInterface.php @@ -0,0 +1,50 @@ + + *@copyright SIX Payment Services + *@license SIX Payment Services + */ + +namespace Invertus\SaferPay\Context; + +if (!defined('_PS_VERSION_')) { + exit; +} + +/** + * Gets shop context data + */ +interface GlobalShopContextInterface +{ + public function getShopId(); + + public function getLanguageId(); + + public function getLanguageIso(); + + public function getCurrencyIso(); + + public function getCurrency(); + + public function getShopDomain(); + + public function getShopName(); + + public function isShopSingleShopContext(); +} diff --git a/src/Controller/AbstractAdminSaferPayController.php b/src/Controller/AbstractAdminSaferPayController.php new file mode 100644 index 00000000..9cc6521f --- /dev/null +++ b/src/Controller/AbstractAdminSaferPayController.php @@ -0,0 +1,94 @@ + + *@copyright SIX Payment Services + *@license SIX Payment Services + */ + +namespace Invertus\SaferPay\Controller; + +use Invertus\SaferPay\Logger\LoggerInterface; +use Invertus\SaferPay\Response\JsonResponse; +use Invertus\SaferPay\Utility\ExceptionUtility; + +class AbstractAdminSaferPayController extends \ModuleAdminController +{ + const FILE_NAME = 'AbstractAdminSaferPayController'; + + protected function ajaxResponse($value = null, $controller = null, $method = null) + { + /** @var LoggerInterface $logger */ + $logger = $this->module->getService(LoggerInterface::class); + + if ($value instanceof JsonResponse) { + if ($value->getStatusCode() === JsonResponse::HTTP_INTERNAL_SERVER_ERROR) { + $logger->error('Failed to return valid response', [ + 'context' => [ + 'response' => $value->getContent(), + ], + ]); + } + + http_response_code($value->getStatusCode()); + + $value = $value->getContent(); + } + + try { + if (method_exists(\ControllerCore::class, 'ajaxRender')) { + $this->ajaxRender($value, $controller, $method); + + exit; + } + + $this->ajaxDie($value, $controller, $method); + } catch (\Exception $exception) { + $logger->error($exception->getMessage(), [ + 'context' => [], + 'response' => json_encode($value ?: []), + 'exceptions' => ExceptionUtility::getExceptions($exception), + ]); + } + + exit; + } + + public function ensureHasPermissions($permissions, $ajax = false) + { + foreach ($permissions as $permission) { + if (!$this->access($permission)) { + if ($ajax) { + $this->ajaxResponse(json_encode([ + 'error' => true, + 'message' => $this->module->l('Unauthorized.', self::FILE_NAME), + ]), JsonResponse::HTTP_UNAUTHORIZED); + } else { + $this->errors[] = $this->module->l( + 'You do not have permission to view this.', + self::FILE_NAME + ); + } + + return false; + } + } + + return true; + } +} diff --git a/src/Controller/AbstractSaferPayController.php b/src/Controller/AbstractSaferPayController.php index cac8b4a2..f6bfc003 100755 --- a/src/Controller/AbstractSaferPayController.php +++ b/src/Controller/AbstractSaferPayController.php @@ -82,7 +82,6 @@ protected function applyLock($resource) $this->lock->create($resource); if (!$this->lock->acquire()) { - if (!SaferPayConfig::isVersion17()) { return http_response_code(409); } diff --git a/src/Controller/Front/index.php b/src/Controller/Front/index.php index 7487f261..6b778722 100644 --- a/src/Controller/Front/index.php +++ b/src/Controller/Front/index.php @@ -21,7 +21,7 @@ *@license SIX Payment Services */ header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); -header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); +header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); header("Cache-Control: no-store, no-cache, must-revalidate"); header("Cache-Control: post-check=0, pre-check=0", false); diff --git a/src/Core/Order/Action/UpdateOrderStatusAction.php b/src/Core/Order/Action/UpdateOrderStatusAction.php index 000ce93b..983c5fcf 100644 --- a/src/Core/Order/Action/UpdateOrderStatusAction.php +++ b/src/Core/Order/Action/UpdateOrderStatusAction.php @@ -60,6 +60,5 @@ public function run($orderId, $orderStatusId) } catch (\Exception $exception) { throw CouldNotChangeOrderStatus::unknownError(); } - } } diff --git a/src/Core/Payment/DTO/CheckoutData.php b/src/Core/Payment/DTO/CheckoutData.php index 7a48165d..a5cf6336 100644 --- a/src/Core/Payment/DTO/CheckoutData.php +++ b/src/Core/Payment/DTO/CheckoutData.php @@ -44,15 +44,14 @@ class CheckoutData private $status; public function __construct( - $cartId, - $paymentMethod, - $isBusinessLicense, - $selectedCard = -1, - $fieldToken = null, - $successController = null, - $isTransaction = false - ) - { + $cartId, + $paymentMethod, + $isBusinessLicense, + $selectedCard = -1, + $fieldToken = null, + $successController = null, + $isTransaction = false + ) { $this->cartId = $cartId; $this->paymentMethod = $paymentMethod; $this->isBusinessLicense = $isBusinessLicense; @@ -65,15 +64,14 @@ public function __construct( } public static function create( - $cartId, - $paymentMethod, - $isBusinessLicense, - $selectedCard = -1, - $fieldToken = null, - $successController = null, - $isTransaction = false - ) - { + $cartId, + $paymentMethod, + $isBusinessLicense, + $selectedCard = -1, + $fieldToken = null, + $successController = null, + $isTransaction = false + ) { return new self( $cartId, $paymentMethod, diff --git a/src/DTO/Request/Assert/AssertRequest.php b/src/DTO/Request/Assert/AssertRequest.php index 0ed01f54..3caa6884 100755 --- a/src/DTO/Request/Assert/AssertRequest.php +++ b/src/DTO/Request/Assert/AssertRequest.php @@ -43,13 +43,16 @@ class AssertRequest * @var string */ private $token; + private $saveCard; public function __construct( RequestHeader $requestHeader, - $token + $token, + $saveCard ) { $this->requestHeader = $requestHeader; $this->token = $token; + $this->saveCard = $saveCard; } public function getAsArray() @@ -65,6 +68,10 @@ public function getAsArray() 'Token' => $this->token, ]; + if ($this->saveCard) { + $return['RegisterAlias'] = [ 'IdGenerator' => 'RANDOM_UNIQUE']; + } + return $return; } } diff --git a/src/DTO/Request/Initialize/InitializeRequest.php b/src/DTO/Request/Initialize/InitializeRequest.php index 90d9d05f..4b96a984 100755 --- a/src/DTO/Request/Initialize/InitializeRequest.php +++ b/src/DTO/Request/Initialize/InitializeRequest.php @@ -86,11 +86,6 @@ class InitializeRequest */ private $configSet; - /** - * @var string - */ - private $cssUrl; - /** * @var Address */ @@ -131,7 +126,6 @@ public function __construct( $notification, DeliveryAddressForm $deliveryAddressForm, $configSet, - $cssUrl, Address $deliveryAddress, Address $billingAddress, $alias, @@ -148,7 +142,6 @@ public function __construct( $this->notification = $notification; $this->deliveryAddressForm = $deliveryAddressForm; $this->configSet = $configSet; - $this->cssUrl = $cssUrl; $this->deliveryAddress = $deliveryAddress; $this->billingAddress = $billingAddress; $this->alias = $alias; @@ -224,6 +217,12 @@ public function getAsArray() ], ]; + if ($this->getPaymentMeansField() === []) { + $return['CardForm'] = [ + 'HolderName' => SaferPayConfig::SAFERPAY_CARDFORM_HOLDERNAME_REQUIRENCE, + ]; + } + if ($this->notification !== null) { $return['Notification'] = [ 'MerchantEmails' => [$this->notification->getMerchantEmail()], @@ -240,13 +239,6 @@ public function getAsArray() $return['ConfigSet'] = $this->configSet; } - if ($this->cssUrl) { - $return['Styling'] = [ - 'CssUrl' => $this->cssUrl, - 'ContentSecurityEnabled' => true, - ]; - } - if ($this->alias || $this->fieldToken) { unset($return['PaymentMethods']); } diff --git a/src/DTO/Response/PaymentMeans.php b/src/DTO/Response/PaymentMeans.php index c80990e7..21bdc750 100755 --- a/src/DTO/Response/PaymentMeans.php +++ b/src/DTO/Response/PaymentMeans.php @@ -43,6 +43,10 @@ class PaymentMeans * @var Card */ private $card; + /** + * @var string + */ + private $wallet; /** * PaymentMeans constructor. @@ -50,11 +54,12 @@ class PaymentMeans * @param string $displayText * @param Card|null $card */ - public function __construct(Brand $brand = null, $displayText = null, Card $card = null) + public function __construct(Brand $brand = null, $displayText = null, Card $card = null, $wallet = null) { $this->brand = $brand; $this->displayText = $displayText; $this->card = $card; + $this->wallet = $wallet; } /** @@ -97,6 +102,14 @@ public function getCard() return $this->card; } + /** + * @return string + */ + public function getWallet() + { + return $this->wallet; + } + /** * @param Card $card */ @@ -104,4 +117,9 @@ public function setCard($card) { $this->card = $card; } + + public function setWallet($wallet) + { + $this->wallet = $wallet; + } } diff --git a/src/Entity/SaferPayLog.php b/src/Entity/SaferPayLog.php index c5842965..0b801462 100755 --- a/src/Entity/SaferPayLog.php +++ b/src/Entity/SaferPayLog.php @@ -27,18 +27,29 @@ class SaferPayLog extends ObjectModel { - public $message; + public $id_saferpay_log; - public $date_add; + public $id_log; + + public $id_shop; + + public $request; - public $payload; + public $response; + + public $context; + + public $date_add; public static $definition = [ 'table' => 'saferpay_log', 'primary' => 'id_saferpay_log', 'fields' => [ - 'message' => ['type' => self::TYPE_STRING, 'validate' => 'isString'], - 'payload' => ['type' => self::TYPE_STRING, 'validate' => 'isString'], + 'id_log' => ['type' => self::TYPE_INT, 'validate' => 'isInt'], + 'id_shop' => ['type' => self::TYPE_INT, 'validate' => 'isInt'], + 'request' => ['type' => self::TYPE_STRING, 'validate' => 'isString'], + 'response' => ['type' => self::TYPE_STRING, 'validate' => 'isString'], + 'context' => ['type' => self::TYPE_STRING, 'validate' => 'isString'], 'date_add' => ['type' => self::TYPE_DATE, 'validate' => 'isDate'], ], ]; diff --git a/src/EntityManager/EntityManagerInterface.php b/src/EntityManager/EntityManagerInterface.php new file mode 100644 index 00000000..ed7bbd7c --- /dev/null +++ b/src/EntityManager/EntityManagerInterface.php @@ -0,0 +1,51 @@ + + *@copyright SIX Payment Services + *@license SIX Payment Services + */ + +namespace Invertus\SaferPay\EntityManager; + +if (!defined('_PS_VERSION_')) { + exit; +} + +interface EntityManagerInterface +{ + /** + * @param \ObjectModel $model + * @param string $unitOfWorkType - @see ObjectModelUnitOfWork + * @param string|null $specificKey + * + * @return EntityManagerInterface + */ + public function persist( + \ObjectModel $model, + $unitOfWorkType, + $specificKey = null + ); + + /** + * @return array<\ObjectModel> + * + * @throws \PrestaShopException + */ + public function flush(); +} diff --git a/src/EntityManager/ObjectModelEntityManager.php b/src/EntityManager/ObjectModelEntityManager.php new file mode 100644 index 00000000..0ab073ab --- /dev/null +++ b/src/EntityManager/ObjectModelEntityManager.php @@ -0,0 +1,86 @@ + + *@copyright SIX Payment Services + *@license SIX Payment Services + */ + +namespace Invertus\SaferPay\EntityManager; + +if (!defined('_PS_VERSION_')) { + exit; +} + +class ObjectModelEntityManager implements EntityManagerInterface +{ + private $unitOfWork; + + public function __construct(ObjectModelUnitOfWork $unitOfWork) + { + $this->unitOfWork = $unitOfWork; + } + + /** + * @param \ObjectModel $model + * @param string $unitOfWorkType + * @param string|null $specificKey + * for example external_id key to make it easier to keep + * track of which object model is related to which external_id + */ + public function persist( + \ObjectModel $model, + $unitOfWorkType, + $specificKey = null + ) { + $this->unitOfWork->setWork($model, $unitOfWorkType, $specificKey); + + return $this; + } + + /** + * @return array<\ObjectModel> + * + * @throws \PrestaShopDatabaseException + * @throws \PrestaShopException + */ + public function flush() + { + $persistenceModels = $this->unitOfWork->getWork(); + $persistedModels = []; + + foreach ($persistenceModels as $externalId => $persistenceModel) { + if ($persistenceModel['unit_of_work_type'] === ObjectModelUnitOfWork::UNIT_OF_WORK_SAVE) { + $persistenceModel['object']->save(); + } + + if ($persistenceModel['unit_of_work_type'] === ObjectModelUnitOfWork::UNIT_OF_WORK_DELETE) { + $persistenceModel['object']->delete(); + } + + if (!empty($externalId)) { + $persistedModels[$externalId] = $persistenceModel['object']; + } else { + $persistedModels[] = $persistenceModel['object']; + } + } + $this->unitOfWork->clearWork(); + + return $persistedModels; + } +} diff --git a/src/EntityManager/ObjectModelUnitOfWork.php b/src/EntityManager/ObjectModelUnitOfWork.php new file mode 100644 index 00000000..7a969693 --- /dev/null +++ b/src/EntityManager/ObjectModelUnitOfWork.php @@ -0,0 +1,64 @@ + + *@copyright SIX Payment Services + *@license SIX Payment Services + */ + +namespace Invertus\SaferPay\EntityManager; + +if (!defined('_PS_VERSION_')) { + exit; +} + +/** In memory entity manager object model unit of work */ +class ObjectModelUnitOfWork +{ + const UNIT_OF_WORK_SAVE = 'UNIT_OF_WORK_SAVE'; + const UNIT_OF_WORK_DELETE = 'UNIT_OF_WORK_DELETE'; + + private $work = []; + + public function setWork(\ObjectModel $objectModel, $unitOfWorkType, $specificKey) + { + $work = [ + 'unit_of_work_type' => $unitOfWorkType, + 'object' => $objectModel, + ]; + + if (!is_null($specificKey)) { + $this->work[$specificKey] = $work; + } else { + $this->work[] = $work; + } + } + + /** + * @return array + */ + public function getWork() + { + return $this->work; + } + + public function clearWork() + { + $this->work = []; + } +} diff --git a/src/Enum/PermissionType.php b/src/Enum/PermissionType.php new file mode 100644 index 00000000..afcf34c3 --- /dev/null +++ b/src/Enum/PermissionType.php @@ -0,0 +1,34 @@ + + *@copyright SIX Payment Services + *@license SIX Payment Services + */ + +namespace Invertus\SaferPay\Enum; + +if (!defined('_PS_VERSION_')) { + exit; +} + +class PermissionType +{ + const VIEW = 'view'; + const EDIT = 'edit'; +} diff --git a/src/Exception/CouldNotProcessCheckout.php b/src/Exception/CouldNotProcessCheckout.php index b8b19281..e495daa4 100644 --- a/src/Exception/CouldNotProcessCheckout.php +++ b/src/Exception/CouldNotProcessCheckout.php @@ -75,4 +75,4 @@ public static function failedToCreateSaferPayOrder($cartId) ] ); } -} \ No newline at end of file +} diff --git a/src/Exception/ExceptionCode.php b/src/Exception/ExceptionCode.php index aabe86ec..d7a0a14d 100644 --- a/src/Exception/ExceptionCode.php +++ b/src/Exception/ExceptionCode.php @@ -33,6 +33,7 @@ class ExceptionCode // Payment related codes starts from 5*** const PAYMENT_FAILED_TO_FIND_CART = 5001; const PAYMENT_FAILED_TO_CREATE_ORDER = 5002; + const CANNOT_USE_CARD = 5003; // Order related codes starts from 7*** const ORDER_FAILED_TO_FIND_ORDER = 7001; diff --git a/src/Exception/Restriction/UnauthenticatedCardUserException.php b/src/Exception/Restriction/UnauthenticatedCardUserException.php new file mode 100644 index 00000000..bb8c396e --- /dev/null +++ b/src/Exception/Restriction/UnauthenticatedCardUserException.php @@ -0,0 +1,35 @@ + + *@copyright SIX Payment Services + *@license SIX Payment Services + */ + +namespace Invertus\SaferPay\Exception\Restriction; + +use Invertus\SaferPay\Exception\SaferPayException; +use RuntimeException; + +if (!defined('_PS_VERSION_')) { + exit; +} + +class UnauthenticatedCardUserException extends SaferPayException +{ +} diff --git a/src/Exception/SaferPayException.php b/src/Exception/SaferPayException.php index 41906751..c2d107a1 100644 --- a/src/Exception/SaferPayException.php +++ b/src/Exception/SaferPayException.php @@ -35,8 +35,7 @@ final public function __construct( $internalMessage, $code, array $context = [] - ) - { + ) { parent::__construct($internalMessage, $code); $this->context = $context; } @@ -53,4 +52,15 @@ public static function unknownError() ExceptionCode::UNKNOWN_ERROR ); } -} \ No newline at end of file + + public static function unauthenticatedCard($idCardOwner) + { + return new static( + 'Customer cannot use current saved card at this moment.', + ExceptionCode::CANNOT_USE_CARD, + [ + 'id_card_owner' => $idCardOwner, + ] + ); + } +} diff --git a/src/Install/Installer.php b/src/Install/Installer.php index d005c53b..5073382b 100755 --- a/src/Install/Installer.php +++ b/src/Install/Installer.php @@ -94,7 +94,6 @@ private function registerHooks() $this->module->registerHook('actionEmailSendBefore'); $this->module->registerHook('displayAdminOrderTabContent'); $this->module->registerHook('actionAdminControllerSetMedia'); - $this->module->registerHook('actionOrderHistoryAddAfter'); $this->module->registerHook('actionObjectOrderPaymentAddAfter'); $this->module->registerHook('displayOrderConfirmation'); } @@ -299,12 +298,17 @@ private function installSaferPayCardAlias() private function installSaferPayLog() { return Db::getInstance()->execute( - 'CREATE TABLE IF NOT EXISTS ' . _DB_PREFIX_ . 'saferpay_log' . '( - `id_saferpay_log` INTEGER(10) UNSIGNED AUTO_INCREMENT PRIMARY KEY, - `message` TEXT NOT NULL, - `payload` TEXT NOT NULL, - `date_add` datetime NOT NULL - ) ENGINE=' . _MYSQL_ENGINE_ . ' DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci' + 'CREATE TABLE IF NOT EXISTS ' . _DB_PREFIX_ . pSQL(\SaferPayLog::$definition['table']) . '( + `id_saferpay_log` INTEGER(10) unsigned NOT NULL AUTO_INCREMENT, + `id_log` INT(10) NOT NULL, + `id_shop` INT(10) NOT NULL DEFAULT ' . (int) Configuration::get('PS_SHOP_DEFAULT') . ', + `request` MEDIUMTEXT DEFAULT NULL, + `response` MEDIUMTEXT DEFAULT NULL, + `context` TEXT DEFAULT NULL, + `date_add` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY(`id_saferpay_log`, `id_log`, `id_shop`), + INDEX(`id_log`) + ) ENGINE=' . _MYSQL_ENGINE_ . ' DEFAULT CHARSET=utf8;' ); } diff --git a/src/Logger/Formatter/LogFormatter.php b/src/Logger/Formatter/LogFormatter.php new file mode 100644 index 00000000..cfb3a915 --- /dev/null +++ b/src/Logger/Formatter/LogFormatter.php @@ -0,0 +1,38 @@ + + *@copyright SIX Payment Services + *@license SIX Payment Services + */ + +namespace Invertus\SaferPay\Logger\Formatter; + +if (!defined('_PS_VERSION_')) { + exit; +} + +class LogFormatter implements LogFormatterInterface +{ + const SAFERPAY_LOG_PREFIX = 'SAFERPAY_MODULE_LOG:'; + + public function getMessage($message) + { + return self::SAFERPAY_LOG_PREFIX . ' ' . $message; + } +} diff --git a/src/Logger/Formatter/LogFormatterInterface.php b/src/Logger/Formatter/LogFormatterInterface.php new file mode 100644 index 00000000..f31c872b --- /dev/null +++ b/src/Logger/Formatter/LogFormatterInterface.php @@ -0,0 +1,38 @@ + + *@copyright SIX Payment Services + *@license SIX Payment Services + */ + +namespace Invertus\SaferPay\Logger\Formatter; + +if (!defined('_PS_VERSION_')) { + exit; +} + +interface LogFormatterInterface +{ + /** + * @param string $message - an actual error message + * + * @return string + */ + public function getMessage($message); +} diff --git a/src/Logger/Logger.php b/src/Logger/Logger.php new file mode 100644 index 00000000..4d6e8887 --- /dev/null +++ b/src/Logger/Logger.php @@ -0,0 +1,194 @@ + + *@copyright SIX Payment Services + *@license SIX Payment Services + */ + +namespace Invertus\SaferPay\Logger; + +use Invertus\SaferPay\Adapter\Configuration; +use Invertus\SaferPay\Adapter\LegacyContext; +use Invertus\SaferPay\Config\SaferPayConfig; +use Invertus\SaferPay\Context\GlobalShopContext; +use Invertus\SaferPay\EntityManager\ObjectModelEntityManager; +use Invertus\SaferPay\EntityManager\ObjectModelUnitOfWork; +use Invertus\SaferPay\Logger\Formatter\LogFormatterInterface; +use Invertus\SaferPay\Provider\BasicIdempotencyProvider; +use Invertus\SaferPay\Repository\PrestashopLoggerRepositoryInterface; + +class Logger implements LoggerInterface +{ + const FILE_NAME = 'Logger'; + + const LOG_OBJECT_TYPE = 'saferpayLog'; + + const SEVERITY_INFO = 1; + const SEVERITY_WARNING = 2; + const SEVERITY_ERROR = 3; + + private $logFormatter; + private $globalShopContext; + private $configuration; + private $context; + private $entityManager; + private $idempotencyProvider; + private $prestashopLoggerRepository; + + public function __construct( + LogFormatterInterface $logFormatter, + GlobalShopContext $globalShopContext, + Configuration $configuration, + LegacyContext $context, + ObjectModelEntityManager $entityManager, + BasicIdempotencyProvider $idempotencyProvider, + PrestashopLoggerRepositoryInterface $prestashopLoggerRepository + ) { + $this->logFormatter = $logFormatter; + $this->globalShopContext = $globalShopContext; + $this->configuration = $configuration; + $this->context = $context; + $this->entityManager = $entityManager; + $this->idempotencyProvider = $idempotencyProvider; + $this->prestashopLoggerRepository = $prestashopLoggerRepository; + } + + public function emergency($message, array $context = []) + { + $this->log( + $this->configuration->getAsInteger( + 'PS_LOGS_BY_EMAIL', + $this->globalShopContext->getShopId() + ), + $message, + $context + ); + } + + public function alert($message, array $context = []) + { + $this->log(self::SEVERITY_WARNING, $message, $context); + } + + public function critical($message, array $context = []) + { + $this->log( + $this->configuration->getAsInteger( + 'PS_LOGS_BY_EMAIL', + $this->globalShopContext->getShopId() + ), + $message, + $context + ); + } + + public function error($message, array $context = []) + { + $this->log(self::SEVERITY_ERROR, $message, $context); + } + + public function warning($message, array $context = []) + { + $this->log(self::SEVERITY_WARNING, $message, $context); + } + + public function notice($message, array $context = []) + { + $this->log(self::SEVERITY_INFO, $message, $context); + } + + public function info($message, array $context = []) + { + $this->log(self::SEVERITY_INFO, $message, $context); + } + + public function debug($message, array $context = []) + { + if (!SaferPayConfig::isDebugMode()) { + return; + } + + $this->log(self::SEVERITY_INFO, $message, $context); + } + + public function log($level, $message, array $context = []) + { + $idempotencyKey = $this->idempotencyProvider->getIdempotencyKey(true); + + \PrestaShopLogger::addLog( + $this->logFormatter->getMessage($message), + $level, + null, + self::LOG_OBJECT_TYPE, + $idempotencyKey + ); + + $logId = $this->prestashopLoggerRepository->getLogIdByObjectId( + $idempotencyKey, + $this->globalShopContext->getShopId() + ); + + if (!$logId) { + return; + } + + $this->logContext($logId, $context); + } + + private function logContext($logId, array $context) + { + $request = ''; + $response = ''; + + if (isset($context['request'])) { + $request = $context['request']; + unset($context['request']); + } + + if (isset($context['response'])) { + $response = $context['response']; + unset($context['response']); + } + + if (isset($context['correlation-id'])) { + $correlationId = $context['correlation-id']; + unset($context['correlation-id']); + } + + $log = new \SaferPayLog(); + $log->id_log = $logId; + $log->id_shop = $this->globalShopContext->getShopId(); + $log->context = json_encode($this->getFilledContextWithShopData($context)); + $log->request = json_encode($request); + $log->response = json_encode($response); + + $this->entityManager->persist($log, ObjectModelUnitOfWork::UNIT_OF_WORK_SAVE); + $this->entityManager->flush(); + } + + private function getFilledContextWithShopData(array $context = []) + { + $context['context_id_customer'] = $this->context->getCustomerId(); + $context['id_shop'] = $this->globalShopContext->getShopId(); + $context['currency'] = $this->globalShopContext->getCurrencyIso(); + $context['id_language'] = $this->globalShopContext->getLanguageId(); + + return $context; + } +} diff --git a/src/Logger/LoggerInterface.php b/src/Logger/LoggerInterface.php new file mode 100644 index 00000000..9c3073cb --- /dev/null +++ b/src/Logger/LoggerInterface.php @@ -0,0 +1,32 @@ + + *@copyright SIX Payment Services + *@license SIX Payment Services + */ + +namespace Invertus\SaferPay\Logger; + +if (!defined('_PS_VERSION_')) { + exit; +} + +interface LoggerInterface extends \Psr\Log\LoggerInterface +{ +} diff --git a/src/Presentation/Loader/PaymentFormAssetLoader.php b/src/Presentation/Loader/PaymentFormAssetLoader.php index 84f6f12c..69cd7dd4 100755 --- a/src/Presentation/Loader/PaymentFormAssetLoader.php +++ b/src/Presentation/Loader/PaymentFormAssetLoader.php @@ -23,10 +23,14 @@ namespace Invertus\SaferPay\Presentation\Loader; +use Configuration; use Invertus\SaferPay\Adapter\LegacyContext; +use Invertus\SaferPay\Config\SaferPayConfig; +use Invertus\SaferPay\DTO\Request\Order; use Invertus\SaferPay\Enum\ControllerName; use Invertus\SaferPay\Enum\PaymentType; use Invertus\SaferPay\Factory\ModuleFactory; +use Invertus\SaferPay\Provider\OpcModulesProvider; use Media; use OrderControllerCore; use SaferPayOfficial; @@ -41,19 +45,18 @@ class PaymentFormAssetLoader private $module; /** @var LegacyContext */ private $context; + /** @var OpcModulesProvider $opcModuleProvider */ + private $opcModulesProvider; - public function __construct(ModuleFactory $module, LegacyContext $context) + public function __construct(ModuleFactory $module, LegacyContext $context, OpcModulesProvider $opcModulesProvider) { $this->module = $module->getModule(); $this->context = $context; + $this->opcModulesProvider = $opcModulesProvider; } public function register($controller) { - if (!$controller instanceof OrderControllerCore) { - return; - } - Media::addJsDef([ 'saferpay_official_ajax_url' => $this->context->getLink()->getModuleLink('saferpayofficial', ControllerName::AJAX), 'saferpay_payment_types' => [ @@ -63,17 +66,117 @@ public function register($controller) ], ]); + $opcModule = $this->opcModulesProvider->get(); + + switch ($opcModule) { + case SaferPayConfig::ONE_PAGE_CHECKOUT_MODULE: + $this->registerOnePageCheckoutAssets($controller); + break; + case SaferPayConfig::THE_CHECKOUT_MODULE: + $this->registerTheCheckoutAssets($controller); + break; + case SaferPayConfig::SUPER_CHECKOUT_MODULE: + $this->registerSuperCheckoutAssets($controller); + break; + default: + $this->registerDefaultCheckoutAssets($controller); + } + } + + private function registerOnePageCheckoutAssets($controller) + { + if (!$controller instanceof \OrderControllerCore) { + return; + } + + $controller->addCSS("{$this->module->getPathUri()}views/css/front/saferpay_checkout.css"); + + if (method_exists($controller, 'registerJavascript')) { + $controller->registerJavascript( + 'saved_card_hosted_fields_opc', + "modules/saferpayofficial/views/js/front/opc/onepagecheckoutps/hosted_fields.js" + ); + } else { + $controller->addJs( + $this->module->getPathUri() . 'views/js/front/opc/onepagecheckoutps/hosted_fields.js', + false + ); + } + } + + private function registerTheCheckoutAssets($controller) + { + if (!$controller instanceof \TheCheckoutModuleFrontController) { + return; + } + + $controller->addCSS("{$this->module->getPathUri()}views/css/front/saferpay_checkout.css"); + + if (method_exists($controller, 'registerJavascript')) { + $controller->registerJavascript( + 'saved_card_hosted_fields_opc', + "modules/saferpayofficial/views/js/front/opc/thecheckout/hosted_fields.js" + ); + } else { + $controller->addJs( + $this->module->getPathUri() . 'views/js/front/opc/thecheckout/hosted_fields.js', + false + ); + } + } + + private function registerSuperCheckoutAssets($controller) + { + if (!$controller instanceof \SupercheckoutSupercheckoutModuleFrontController) { + return; + } + + $controller->addCSS("{$this->module->getPathUri()}views/css/front/saferpay_checkout.css"); + + if (method_exists($controller, 'registerJavascript')) { + $controller->registerJavascript( + 'saved_card_hosted_fields_opc', + "modules/saferpayofficial/views/js/front/opc/supercheckout/hosted_fields.js" + ); + } else { + $controller->addJs( + $this->module->getPathUri() . 'views/js/front/opc/supercheckout/hosted_fields.js', + false + ); + } + } + + private function registerDefaultCheckoutAssets($controller) + { + if (!$controller instanceof OrderControllerCore) { + return; + } + if (method_exists($controller, 'registerJavascript')) { if (\Invertus\SaferPay\Config\SaferPayConfig::isVersion17()) { $controller->registerJavascript( 'saved_card_hosted_fields', "modules/saferpayofficial/views/js/front/hosted-templates/hosted_fields.js" ); + + $controller->registerJavascript( + 'saved-card', + 'modules/' . $this->module->name . '/views/js/front/saferpay_saved_card.js' + ); + + $controller->registerStylesheet("", + "{$this->module->getPathUri()}views/css/front/saferpay_checkout.css"); } else { $controller->registerJavascript( 'saved_card_hosted_fields', "modules/saferpayofficial/views/js/front/hosted-templates/hosted_fields_16.js" ); + + $controller->addCSS("{$this->module->getPathUri()}views/css/front/saferpay_checkout_16.css"); + $controller->addJS("{$this->module->getPathUri()}views/js/front/saferpay_saved_card_16.js"); + $fieldsLibrary = \Invertus\SaferPay\Config\SaferPayConfig::FIELDS_LIBRARY; + $configSuffix = \Invertus\SaferPay\Config\SaferPayConfig::getConfigSuffix(); + $controller->addJs(Configuration::get($fieldsLibrary . $configSuffix)); } } else { if (\Invertus\SaferPay\Config\SaferPayConfig::isVersion17()) { @@ -86,7 +189,17 @@ public function register($controller) $this->module->getPathUri() . 'views/js/front/hosted-templates/hosted_fields_16.js', false ); + $controller->addCSS("{$this->module->getPathUri()}views/css/front/saferpay_checkout_16.css"); + $controller->addJS("{$this->module->getPathUri()}views/js/front/saferpay_saved_card_16.js"); } } } + + public function registerErrorBags() + { + /** @var \Invertus\SaferPay\Service\SaferPayErrorDisplayService $errorDisplayService */ + $errorDisplayService = $this->module->getService(\Invertus\SaferPay\Service\SaferPayErrorDisplayService::class); + + $errorDisplayService->showCookieError('saferpay_payment_canceled_error'); + } } diff --git a/src/Processor/CheckoutProcessor.php b/src/Processor/CheckoutProcessor.php index 41826f57..9807e569 100644 --- a/src/Processor/CheckoutProcessor.php +++ b/src/Processor/CheckoutProcessor.php @@ -35,15 +35,18 @@ use Invertus\SaferPay\Exception\Api\SaferPayApiException; use Invertus\SaferPay\Exception\CouldNotProcessCheckout; use Invertus\SaferPay\Factory\ModuleFactory; +use Invertus\SaferPay\Logger\LoggerInterface; use Invertus\SaferPay\Repository\SaferPayOrderRepository; use Invertus\SaferPay\Service\SaferPayInitialize; +use Invertus\SaferPay\Utility\ExceptionUtility; use Order; use PrestaShopException; use SaferPayOrder; -use Validate; class CheckoutProcessor { + const FILE_NAME = 'CheckoutProcessor'; + /** @var \SaferPayOfficial */ private $module; @@ -68,10 +71,20 @@ public function __construct( $this->saferPayOrderRepository = $saferPayOrderRepository; } - public function run(CheckoutData $data) { + public function run(CheckoutData $data) + { $cart = new Cart($data->getCartId()); + /** @var LoggerInterface $logger */ + $logger = $this->module->getService(LoggerInterface::class); + if (!$cart) { + $logger->debug(sprintf('%s - Cart not found', self::FILE_NAME), [ + 'context' => [ + 'cartId' => $data->getCartId(), + ], + ]); + throw CouldNotProcessCheckout::failedToFindCart($data->getCartId()); } @@ -109,6 +122,13 @@ public function run(CheckoutData $data) { $data->getIsTransaction() ); } catch (\Exception $exception) { + $logger->error($exception->getMessage(), [ + 'context' => [ + 'cartId' => $data->getCartId(), + ], + 'exceptions' => ExceptionUtility::getExceptions($exception) + ]); + throw CouldNotProcessCheckout::failedToCreateSaferPayOrder($data->getCartId()); } @@ -123,13 +143,31 @@ public function run(CheckoutData $data) { */ private function processCreateOrder(Cart $cart, $paymentMethod) { + /** @var \Invertus\SaferPay\Adapter\Cart $cartAdapter */ + $cartAdapter = $this->module->getService(\Invertus\SaferPay\Adapter\Cart::class); + + /** @var LoggerInterface $logger */ + $logger = $this->module->getService(LoggerInterface::class); + // Notify and return webhooks triggers together leading into order created previously - if ($cart->orderExists()) { + if ($cartAdapter->orderExists($cart->id)) { + $logger->debug(sprintf('%s - Order already exists, returning', self::FILE_NAME), [ + 'context' => [ + 'cartId' => $cart->id, + ], + ]); + return; } $customer = new \Customer($cart->id_customer); + $logger->debug(sprintf('%s - Creating order', self::FILE_NAME), [ + 'context' => [ + 'cartId' => $cart->id, + ], + ]); + $this->module->validateOrder( $cart->id, \Configuration::get(SaferPayConfig::SAFERPAY_ORDER_STATE_CHOICE_AWAITING_PAYMENT), @@ -188,22 +226,54 @@ private function processCreateSaferPayOrder($initializeBody, $cartId, $customerI private function processAuthorizedOrder(CheckoutData $data, Cart $cart) { + /** @var LoggerInterface $logger */ + $logger = $this->module->getService(LoggerInterface::class); + $logger->debug(sprintf('%s - Processing authorized order', self::FILE_NAME), [ + 'context' => [ + 'id_order' => $this->getOrder($cart->id)->id, + ], + ]); + try { $this->processCreateOrder($cart, $data->getPaymentMethod()); $order = $this->getOrder($cart->id); $saferPayOrder = new SaferPayOrder($this->saferPayOrderRepository->getIdByCartId($cart->id)); + if ( + $order->getCurrentState() == _SAFERPAY_PAYMENT_AUTHORIZED_ + || $order->getCurrentState() == _SAFERPAY_PAYMENT_COMPLETED_ + ) { + return; + } + if ($data->getOrderStatus() === TransactionStatus::AUTHORIZED) { + if ($order->getCurrentState() == (int) _SAFERPAY_PAYMENT_AUTHORIZED_) { + return; + } + $saferPayOrder->authorized = true; + $data->setIsAuthorizedOrder(true); $order->setCurrentState(_SAFERPAY_PAYMENT_AUTHORIZED_); } else { + if ($order->getCurrentState() == _SAFERPAY_PAYMENT_COMPLETED_) { + return; + } + $saferPayOrder->captured = true; + $logger->debug('Order set completed CheckoutProcessor.php'); $order->setCurrentState(_SAFERPAY_PAYMENT_COMPLETED_); } $saferPayOrder->id_order = $order->id; $saferPayOrder->update(); } catch (\Exception $exception) { + /** @var LoggerInterface $logger */ + $logger = $this->module->getService(LoggerInterface::class); + $logger->error($exception->getMessage(), [ + 'context' => [], + 'cartId' => $data->getCartId(), + ]); + throw CouldNotProcessCheckout::failedToCreateOrder($data->getCartId()); } } @@ -217,9 +287,8 @@ private function getOrder($cartId) { if (method_exists('Order', 'getIdByCartId')) { return new Order(Order::getIdByCartId($cartId)); - } else { - // For PrestaShop 1.6 use the alternative method - return new Order(Order::getOrderByCartId($cartId)); } + // For PrestaShop 1.6 use the alternative method + return new Order(Order::getOrderByCartId($cartId)); } } diff --git a/src/Processor/index.php b/src/Processor/index.php index 7487f261..6b778722 100644 --- a/src/Processor/index.php +++ b/src/Processor/index.php @@ -21,7 +21,7 @@ *@license SIX Payment Services */ header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); -header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); +header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); header("Cache-Control: no-store, no-cache, must-revalidate"); header("Cache-Control: post-check=0, pre-check=0", false); diff --git a/src/Provider/BasicIdempotencyProvider.php b/src/Provider/BasicIdempotencyProvider.php index a70d3047..c8ba533b 100644 --- a/src/Provider/BasicIdempotencyProvider.php +++ b/src/Provider/BasicIdempotencyProvider.php @@ -29,8 +29,12 @@ class BasicIdempotencyProvider implements IdempotencyProviderInterface { - public function getIdempotencyKey() + public function getIdempotencyKey($only_numbers = false) { + if ($only_numbers) { + return (string) mt_rand(); + } + $uniqueId = uniqid('ps-', true); $randomNum = rand(100000, 999999); diff --git a/src/Provider/OpcModulesProvider.php b/src/Provider/OpcModulesProvider.php new file mode 100644 index 00000000..9740cbe6 --- /dev/null +++ b/src/Provider/OpcModulesProvider.php @@ -0,0 +1,47 @@ + + *@copyright SIX Payment Services + *@license SIX Payment Services + */ + +namespace Invertus\SaferPay\Provider; + +use Invertus\SaferPay\Config\SaferPayConfig; + +if (!defined('_PS_VERSION_')) { + exit; +} + +class OpcModulesProvider +{ + /** + * @return string + */ + public function get() + { + foreach (SaferPayConfig::OPC_MODULE_LIST as $opcModule){ + if (\Module::isInstalled($opcModule) && \Module::isEnabled($opcModule)) { + return $opcModule; + } + } + + return ''; + } +} \ No newline at end of file diff --git a/src/Repository/CollectionRepository.php b/src/Repository/CollectionRepository.php new file mode 100644 index 00000000..0f18bad2 --- /dev/null +++ b/src/Repository/CollectionRepository.php @@ -0,0 +1,67 @@ + + *@copyright SIX Payment Services + *@license SIX Payment Services + */ + +namespace Invertus\SaferPay\Repository; + +if (!defined('_PS_VERSION_')) { + exit; +} + +class CollectionRepository implements ReadOnlyCollectionRepositoryInterface +{ + /** + * @var string + */ + private $fullyClassifiedClassName; + + public function __construct($fullyClassifiedClassName) + { + $this->fullyClassifiedClassName = $fullyClassifiedClassName; + } + + public function findAllInCollection($langId = null) + { + return new \PrestaShopCollection($this->fullyClassifiedClassName, $langId); + } + + /** + * @param array $keyValueCriteria + * @param int|null $langId + * + * @return \ObjectModel|null + * + * @throws \PrestaShopException + */ + public function findOneBy(array $keyValueCriteria, $langId = null) + { + $psCollection = new \PrestaShopCollection($this->fullyClassifiedClassName, $langId); + + foreach ($keyValueCriteria as $field => $value) { + $psCollection = $psCollection->where($field, '=', $value); + } + + $first = $psCollection->getFirst(); + + return false === $first ? null : $first; + } +} diff --git a/src/Repository/PrestashopLoggerRepository.php b/src/Repository/PrestashopLoggerRepository.php new file mode 100644 index 00000000..d7190a71 --- /dev/null +++ b/src/Repository/PrestashopLoggerRepository.php @@ -0,0 +1,73 @@ + + *@copyright SIX Payment Services + *@license SIX Payment Services + */ + +namespace Invertus\SaferPay\Repository; + +use Invertus\Knapsack\Collection; +use Invertus\SaferPay\Logger\Logger; +use Invertus\SaferPay\Utility\VersionUtility; + +if (!defined('_PS_VERSION_')) { + exit; +} + +class PrestashopLoggerRepository extends CollectionRepository implements PrestashopLoggerRepositoryInterface +{ + public function __construct() + { + parent::__construct(\PrestaShopLogger::class); + } + + /** {@inheritDoc} */ + public function getLogIdByObjectId($objectId, $shopId) + { + $query = new \DbQuery(); + + $query + ->select('l.id_log') + ->from('log', 'l') + ->where('l.object_id = "' . pSQL($objectId) . '"') + ->orderBy('l.id_log DESC'); + + if (VersionUtility::isPsVersionGreaterOrEqualTo('1.7.8.0')) { + $query->where('l.id_shop = ' . (int) $shopId); + } + + $logId = \Db::getInstance()->getValue($query); + + return (int) $logId ?: null; + } + + public function prune($daysToKeep) + { + Collection::from( + $this->findAllInCollection() + ->sqlWhere('DATEDIFF(NOW(),date_add) >= ' . $daysToKeep) + ->where('object_type', '=', Logger::LOG_OBJECT_TYPE) + ) + ->each(function (\PrestaShopLogger $log) { + $log->delete(); + }) + ->realize(); + } +} diff --git a/src/Repository/PrestashopLoggerRepositoryInterface.php b/src/Repository/PrestashopLoggerRepositoryInterface.php new file mode 100644 index 00000000..9acd2ff7 --- /dev/null +++ b/src/Repository/PrestashopLoggerRepositoryInterface.php @@ -0,0 +1,41 @@ + + *@copyright SIX Payment Services + *@license SIX Payment Services + */ + +namespace Invertus\SaferPay\Repository; + +if (!defined('_PS_VERSION_')) { + exit; +} + +interface PrestashopLoggerRepositoryInterface extends ReadOnlyCollectionRepositoryInterface +{ + /** + * @param string $objectId + * @param int $shopId + * + * @return int|null + */ + public function getLogIdByObjectId($objectId, $shopId); + + public function prune($daysToKeep); +} diff --git a/src/Repository/ReadOnlyCollectionRepositoryInterface.php b/src/Repository/ReadOnlyCollectionRepositoryInterface.php new file mode 100644 index 00000000..ad4c44ea --- /dev/null +++ b/src/Repository/ReadOnlyCollectionRepositoryInterface.php @@ -0,0 +1,50 @@ + + *@copyright SIX Payment Services + *@license SIX Payment Services + */ + +namespace Invertus\SaferPay\Repository; + +if (!defined('_PS_VERSION_')) { + exit; +} + +interface ReadOnlyCollectionRepositoryInterface +{ + /** + * @param int|null $langId - objects which ussualy are type of array will become strings. E.g + * $product->name is string instead of multidimensional array where key is id_language. + * Always pass language id + * unless there is a special need not to. Synchronization or smth. + * It saves quite a lot performance wise. + * + * @return \PrestaShopCollection + */ + public function findAllInCollection($langId = null); + + /** + * @param array $keyValueCriteria - e.g [ 'id_cart' => 5 ] + * @param int|null $langId + * + * @return \ObjectModel|null + */ + public function findOneBy(array $keyValueCriteria, $langId = null); +} diff --git a/src/Repository/SaferPayCardAliasRepository.php b/src/Repository/SaferPayCardAliasRepository.php index 5cf24362..d1664313 100755 --- a/src/Repository/SaferPayCardAliasRepository.php +++ b/src/Repository/SaferPayCardAliasRepository.php @@ -74,4 +74,15 @@ public function getSavedCardsByCustomerId($customerId) return Db::getInstance()->executeS($query); } + + public function getCustomerIdByReferenceId($cardAliasId, $idCustomer) + { + $query = new DbQuery(); + $query->select('`id_customer`'); + $query->from('saferpay_card_alias'); + $query->where('id_saferpay_card_alias = "' . pSQL($cardAliasId) . '"'); + $query->where('id_customer = "' . (int) $idCustomer . '"'); + + return Db::getInstance()->getValue($query); + } } diff --git a/src/Repository/SaferPayLogRepository.php b/src/Repository/SaferPayLogRepository.php new file mode 100644 index 00000000..af17438e --- /dev/null +++ b/src/Repository/SaferPayLogRepository.php @@ -0,0 +1,50 @@ + + *@copyright SIX Payment Services + *@license SIX Payment Services + */ + +namespace Invertus\SaferPay\Repository; + +use Invertus\Knapsack\Collection; + +if (!defined('_PS_VERSION_')) { + exit; +} + +class SaferPayLogRepository extends CollectionRepository implements SaferPayLogRepositoryInterface +{ + public function __construct() + { + parent::__construct(\SaferPayLog::class); + } + + public function prune($daysToKeep) + { + Collection::from( + $this->findAllInCollection() + ->sqlWhere('DATEDIFF(NOW(),date_add) >= ' . $daysToKeep) + ) + ->each(function (\KlarnaPaymentLog $log) { + $log->delete(); + }) + ->realize(); + } +} diff --git a/src/Repository/SaferPayLogRepositoryInterface.php b/src/Repository/SaferPayLogRepositoryInterface.php new file mode 100644 index 00000000..240907e3 --- /dev/null +++ b/src/Repository/SaferPayLogRepositoryInterface.php @@ -0,0 +1,33 @@ + + *@copyright SIX Payment Services + *@license SIX Payment Services + */ + +namespace Invertus\SaferPay\Repository; + +if (!defined('_PS_VERSION_')) { + exit; +} + +interface SaferPayLogRepositoryInterface extends ReadOnlyCollectionRepositoryInterface +{ + public function prune($daysToKeep); +} diff --git a/src/Repository/SaferPayPaymentRepository.php b/src/Repository/SaferPayPaymentRepository.php index 90852ec0..9b16e20c 100755 --- a/src/Repository/SaferPayPaymentRepository.php +++ b/src/Repository/SaferPayPaymentRepository.php @@ -62,6 +62,22 @@ public function isLogoEnabledByName($paymentName) return Db::getInstance()->getValue($query); } + public function getAllActiveLogosNames() + { + $query = new DbQuery(); + $query->select('name'); + $query->from('saferpay_logo'); + $query->where('active = "1"'); + + $result = Db::getInstance()->executeS($query); + + if (!$result) { + return []; + } + + return $result; + } + public function getActivePaymentMethods() { $query = new DbQuery(); @@ -69,7 +85,29 @@ public function getActivePaymentMethods() $query->from('saferpay_payment'); $query->where('active = "1"'); - return Db::getInstance()->executeS($query); + $result = Db::getInstance()->executeS($query); + + if (!$result) { + return []; + } + + return $result; + } + + public function getActivePaymentMethodsNames() + { + $query = new DbQuery(); + $query->select('name'); + $query->from('saferpay_payment'); + $query->where('active = "1"'); + + $result = Db::getInstance()->executeS($query); + + if (!$result) { + return []; + } + + return $result; } public function truncateTable() diff --git a/src/Response/JsonResponse.php b/src/Response/JsonResponse.php new file mode 100644 index 00000000..28936f9f --- /dev/null +++ b/src/Response/JsonResponse.php @@ -0,0 +1,76 @@ + + *@copyright SIX Payment Services + *@license SIX Payment Services + */ + +namespace Invertus\SaferPay\Response; + +use Symfony\Component\HttpFoundation\JsonResponse as BaseJsonResponse; + +if (!defined('_PS_VERSION_')) { + exit; +} + +class JsonResponse extends BaseJsonResponse +{ + /** + * @param mixed $data + */ + public function __construct($data = null, $status = 200, array $headers = []) + { + parent::__construct($data, $status, $headers); + } + + public static function success($data, $status = 200) + { + return new self([ + 'success' => true, + 'errors' => [], + 'data' => $data, + ], $status); + } + + /** + * @param string|array $error + * @param int $status + * + * @return static + */ + public static function error($error, $status = 400) + { + if ($status === JsonResponse::HTTP_UNPROCESSABLE_ENTITY) { + // NOTE: removing rule name. ['required' => 'message'] becomes [0 => 'message'] + foreach ($error as $key => $messages) { + $error[$key] = array_values($messages); + } + } + + if (!is_array($error)) { + $error = [$error]; + } + + return new self([ + 'success' => false, + 'errors' => $error, + 'data' => [], + ], $status); + } +} diff --git a/src/Service/PaymentRestrictionValidation/BasePaymentRestrictionValidation.php b/src/Service/PaymentRestrictionValidation/BasePaymentRestrictionValidation.php index b98b49dc..4a56dfb8 100755 --- a/src/Service/PaymentRestrictionValidation/BasePaymentRestrictionValidation.php +++ b/src/Service/PaymentRestrictionValidation/BasePaymentRestrictionValidation.php @@ -72,18 +72,10 @@ public function __construct( */ public function isValid($paymentName) { - if (!$this->paymentRepository->isActiveByName($paymentName)) { - return false; - } - if (!$this->isCountrySupportedByPaymentName($paymentName)) { return false; } - if (!$this->isCurrencySupportedByPaymentName($paymentName)) { - return false; - } - return true; } @@ -135,26 +127,4 @@ private function isCountrySupportedByPaymentName($paymentName) return $isCountryInList || $isAllCountries; } - - /** - * @param string $paymentName - * - * @return bool - */ - private function isCurrencySupportedByPaymentName($paymentName) - { - $enabledCurrencies = $this->getEnabledCurrenciesByPaymentName($paymentName); - - if (in_array('0', $enabledCurrencies)) { - $enabledCurrencies = []; - $currencyOptions = $this->obtainPaymentMethods->obtainPaymentMethods()[$paymentName]['currencies']; - foreach ($currencyOptions as $isoCode) { - $enabledCurrencies[$isoCode] = $isoCode; - } - - return in_array($this->legacyContext->getCurrencyIsoCode(), $enabledCurrencies); - } - - return in_array($this->legacyContext->getCurrencyId(), $enabledCurrencies); - } } diff --git a/src/Service/Request/AssertRequestObjectCreator.php b/src/Service/Request/AssertRequestObjectCreator.php index 34c1ef83..0689c19a 100755 --- a/src/Service/Request/AssertRequestObjectCreator.php +++ b/src/Service/Request/AssertRequestObjectCreator.php @@ -55,10 +55,10 @@ public function __construct( * * @return AssertRequest */ - public function create($token) + public function create($token, $saveCard) { $requestHeader = $this->requestObjectCreator->createRequestHeader(); - return new AssertRequest($requestHeader, $token); + return new AssertRequest($requestHeader, $token, $saveCard); } } diff --git a/src/Service/Request/InitializeRequestObjectCreator.php b/src/Service/Request/InitializeRequestObjectCreator.php index 0ca1e5e4..4278d9ed 100755 --- a/src/Service/Request/InitializeRequestObjectCreator.php +++ b/src/Service/Request/InitializeRequestObjectCreator.php @@ -27,10 +27,8 @@ use Configuration; use Customer; use Invertus\SaferPay\Config\SaferPayConfig; -use Invertus\SaferPay\DTO\Request\RequestHeader; use Invertus\SaferPay\DTO\Request\Initialize\InitializeRequest; use Invertus\SaferPay\DTO\Request\Payer; -use PrestaShop\PrestaShop\Adapter\Shop\Context; if (!defined('_PS_VERSION_')) { exit; @@ -79,7 +77,6 @@ public function create( $notification = $isBusinessLicence ? null : $this->requestObjectCreator->createNotification($customerEmail, $notifyUrl); $deliveryAddressForm = $this->requestObjectCreator->createDeliveryAddressForm(); $configSet = Configuration::get(SaferPayConfig::CONFIGURATION_NAME); - $cssUrl = Configuration::get(SaferPayConfig::CSS_FILE); $customer = new Customer($customerId); $deliveryAddress = new \Address($deliveryAddressId); @@ -102,7 +99,6 @@ public function create( $notification, $deliveryAddressForm, $configSet, - $cssUrl, $deliveryAddress, $invoiceAddress, $alias, diff --git a/src/Service/Response/ResponseObjectCreator.php b/src/Service/Response/ResponseObjectCreator.php index 6db2cd0e..38c4b882 100755 --- a/src/Service/Response/ResponseObjectCreator.php +++ b/src/Service/Response/ResponseObjectCreator.php @@ -89,6 +89,9 @@ protected function createPaymentMeans($paymentMeans) } $paymentMeansObj->setBrand($brandObj); $paymentMeansObj->setDisplayText($paymentMeans->DisplayText); + if (isset($paymentMeans->Wallet)) { + $paymentMeansObj->setWallet($paymentMeans->Wallet); + } return $paymentMeansObj; } diff --git a/src/Service/SaferPayInitialize.php b/src/Service/SaferPayInitialize.php index e1cb6300..9ab0fa2f 100755 --- a/src/Service/SaferPayInitialize.php +++ b/src/Service/SaferPayInitialize.php @@ -31,11 +31,11 @@ use Invertus\SaferPay\DTO\Request\Initialize\InitializeRequest; use Invertus\SaferPay\Enum\ControllerName; use Invertus\SaferPay\Exception\Api\SaferPayApiException; +use Invertus\SaferPay\Logger\LoggerInterface; use Invertus\SaferPay\Repository\SaferPayCardAliasRepository; use Invertus\SaferPay\Factory\ModuleFactory; use Invertus\SaferPay\Service\Request\InitializeRequestObjectCreator; -use Invertus\SaferPay\Config\SaferPayConfig; -use Order; +use Invertus\SaferPay\Utility\ExceptionUtility; use SaferPayOfficial; if (!defined('_PS_VERSION_')) { @@ -44,6 +44,7 @@ class SaferPayInitialize { + const FILE_NAME = 'SaferPayInitialize'; /** * @var SaferPayOfficial */ @@ -91,6 +92,13 @@ public function initialize(InitializeRequest $initializeRequest, $isBusinessLice try { $initialize = $this->initializeService->initialize($initializeRequest, $isBusinessLicence); } catch (Exception $e) { + /** @var LoggerInterface $logger */ + $logger = $this->module->getService(LoggerInterface::class); + $logger->error($e->getMessage(), [ + 'context' => [], + 'exceptions' => ExceptionUtility::getExceptions($e), + ]); + throw new SaferPayApiException('Initialize API failed', SaferPayApiException::INITIALIZE); } @@ -118,6 +126,7 @@ public function buildRequest( 'selectedCard' => $selectedCard, 'isBusinessLicence' => $isBusinessLicence, 'fieldToken' => $fieldToken, + 'paymentMethod' => $paymentMethod, ], true ); diff --git a/src/Service/SaferPayObtainPaymentMethods.php b/src/Service/SaferPayObtainPaymentMethods.php index c0635d25..27a00dbe 100755 --- a/src/Service/SaferPayObtainPaymentMethods.php +++ b/src/Service/SaferPayObtainPaymentMethods.php @@ -26,7 +26,9 @@ use Exception; use Invertus\SaferPay\Api\Request\ObtainPaymentMethodsService; use Invertus\SaferPay\Exception\Api\SaferPayApiException; +use Invertus\SaferPay\Logger\LoggerInterface; use Invertus\SaferPay\Service\Request\ObtainPaymentMethodsObjectCreator; +use function Invertus\Knapsack\toArray; if (!defined('_PS_VERSION_')) { exit; @@ -34,18 +36,22 @@ class SaferPayObtainPaymentMethods { + const FILE_NAME = 'SaferPayObtainPaymentMethods'; private $obtainPaymentMethodsService; private $obtainPaymentMethodsObjectCreator; private $saferPayPaymentNotation; + private $logger; public function __construct( ObtainPaymentMethodsService $obtainPaymentMethodsService, ObtainPaymentMethodsObjectCreator $obtainPaymentMethodsObjectCreator, - SaferPayPaymentNotation $saferPayPaymentNotation + SaferPayPaymentNotation $saferPayPaymentNotation, + LoggerInterface $logger ) { $this->obtainPaymentMethodsService = $obtainPaymentMethodsService; $this->obtainPaymentMethodsObjectCreator = $obtainPaymentMethodsObjectCreator; $this->saferPayPaymentNotation = $saferPayPaymentNotation; + $this->logger = $logger; } public function obtainPaymentMethods() @@ -57,6 +63,11 @@ public function obtainPaymentMethods() $this->obtainPaymentMethodsObjectCreator->create() ); } catch (Exception $e) { + $this->logger->debug(sprintf('%s - failed to get payment methods list', self::FILE_NAME), [ + 'context' => [], + 'exception' => $e + ]); + throw new SaferPayApiException('Initialize API failed', SaferPayApiException::INITIALIZE); } diff --git a/src/Service/SaferPayOrderStatusService.php b/src/Service/SaferPayOrderStatusService.php index 711b837c..6d12858f 100755 --- a/src/Service/SaferPayOrderStatusService.php +++ b/src/Service/SaferPayOrderStatusService.php @@ -36,10 +36,12 @@ use Invertus\SaferPay\Enum\ControllerName; use Invertus\SaferPay\Exception\Api\SaferPayApiException; use Invertus\SaferPay\Factory\ModuleFactory; +use Invertus\SaferPay\Logger\LoggerInterface; use Invertus\SaferPay\Repository\SaferPayOrderRepository; use Invertus\SaferPay\Service\Request\CancelRequestObjectCreator; use Invertus\SaferPay\Service\Request\CaptureRequestObjectCreator; use Invertus\SaferPay\Service\Request\RefundRequestObjectCreator; +use Invertus\SaferPay\Utility\ExceptionUtility; use Order; use SaferPayAssert; use SaferPayOfficial; @@ -51,6 +53,7 @@ class SaferPayOrderStatusService { + const FILE_NAME = 'SaferPayOrderStatusService'; /** * @var CaptureService */ @@ -89,6 +92,10 @@ class SaferPayOrderStatusService * @var SaferPayOfficial */ private $module; + /** + * @var LoggerInterface + */ + private $logger; public function __construct( CaptureService $captureService, @@ -99,7 +106,8 @@ public function __construct( RefundService $refundService, RefundRequestObjectCreator $refundRequestObjectCreator, LegacyContext $context, - ModuleFactory $module + ModuleFactory $module, + LoggerInterface $logger ) { $this->captureService = $captureService; $this->captureRequestObjectCreator = $captureRequestObjectCreator; @@ -110,6 +118,7 @@ public function __construct( $this->refundRequestObjectCreator = $refundRequestObjectCreator; $this->context = $context; $this->module = $module->getModule(); + $this->logger = $logger; } public function setPending(Order $order) @@ -129,10 +138,12 @@ public function setComplete(Order $order) $saferPayOrder->update(); //NOTE: Older PS versions does not handle same state change, so we need to check if state is already set - if ($order->getCurrentState() === _SAFERPAY_PAYMENT_COMPLETED_) { + if ($order->getCurrentState() == _SAFERPAY_PAYMENT_COMPLETED_) { return; } + $this->logger->debug('Order set completed (setComplete) SaferPayStatusService.php'); + $order->setCurrentState(_SAFERPAY_PAYMENT_COMPLETED_); } @@ -155,6 +166,11 @@ public function capture(Order $order, $refundedAmount = 0, $isRefund = false) try { $captureResponse = $this->captureService->capture($captureRequest); } catch (Exception $e) { + $this->logger->error($e->getMessage(), [ + 'context' => [], + 'exceptions' => ExceptionUtility::getExceptions($e), + ]); + throw new SaferPayApiException('Capture API failed', SaferPayApiException::CAPTURE); } @@ -175,6 +191,27 @@ public function capture(Order $order, $refundedAmount = 0, $isRefund = false) return; } + + if ((int) $order->getCurrentState() == (int) _SAFERPAY_PAYMENT_COMPLETED_ || (bool) $saferPayOrder->captured) { + $this->logger->debug(sprintf('%s - saferPayAssert object set captured', self::FILE_NAME), [ + 'context' => [ + 'orderId' => $order->id, + ], + 'message' => 'order is already have captured state', + ]); + + if (!$saferPayOrder->captured) { + $saferPayOrder->captured = 1; + $saferPayOrder->update(); + $saferPayAssert->status = $captureResponse->Status; + $saferPayAssert->update(); + } + + return; + } + + $this->logger->debug(sprintf('%s - saferPayAssert object set captured', self::FILE_NAME)); + $order->setCurrentState(_SAFERPAY_PAYMENT_COMPLETED_); $order->update(); $saferPayOrder->captured = 1; @@ -191,12 +228,24 @@ public function cancel(Order $order) try { $this->cancelService->cancel($cancelRequest); } catch (Exception $e) { + $this->logger->error($e->getMessage(), [ + 'context' => [ + 'orderId' => $order->id, + ], + 'exceptions' => ExceptionUtility::getExceptions($e), + ]); + throw new SaferPayApiException('Cancel API failed', SaferPayApiException::CANCEL); } $order->setCurrentState(_SAFERPAY_PAYMENT_CANCELED_); $order->update(); $saferPayOrder->canceled = 1; $saferPayOrder->update(); + + $assertId = $this->orderRepository->getAssertIdBySaferPayOrderId($saferPayOrder->id); + $saferPayAssert = new SaferPayAssert($assertId); + $saferPayAssert->status = TransactionStatus::CANCELED; + $saferPayAssert->update(); } public function refund(Order $order, $refundedAmount) @@ -243,6 +292,10 @@ public function refund(Order $order, $refundedAmount) try { $refundResponse = $this->refundService->refund($refundRequest); } catch (Exception $e) { + $this->logger->error($e->getMessage(), [ + 'exceptions' => ExceptionUtility::getExceptions($e), + ]); + throw new SaferPayApiException('Refund API failed', SaferPayApiException::REFUND); } $saferPayOrder->refund_id = $refundResponse->Transaction->Id; diff --git a/src/Service/SaferPayRefreshPaymentsService.php b/src/Service/SaferPayRefreshPaymentsService.php index 4940f74b..f52af9e1 100755 --- a/src/Service/SaferPayRefreshPaymentsService.php +++ b/src/Service/SaferPayRefreshPaymentsService.php @@ -25,6 +25,7 @@ use Invertus\SaferPay\Exception\Api\SaferPayApiException; use Exception; +use Invertus\SaferPay\Logger\LoggerInterface; use Invertus\SaferPay\Repository\SaferPayFieldRepository; use Invertus\SaferPay\Repository\SaferPayPaymentRepository; use Invertus\SaferPay\Repository\SaferPayRestrictionRepository; @@ -42,24 +43,32 @@ class SaferPayRefreshPaymentsService private $obtainPayments; private $restrictionRepository; private $fieldRepository; + private $logger; public function __construct( SaferPayPaymentRepository $paymentRepository, SaferPayObtainPaymentMethods $obtainPaymentMethods, SaferPayRestrictionRepository $restrictionRepository, - SaferPayFieldRepository $fieldRepository + SaferPayFieldRepository $fieldRepository, + LoggerInterface $logger ) { $this->paymentRepository = $paymentRepository; $this->obtainPayments = $obtainPaymentMethods; $this->restrictionRepository = $restrictionRepository; $this->fieldRepository = $fieldRepository; + $this->logger = $logger; } public function refreshPayments() { // Get enabled payments. $activePayments = $this->paymentRepository->getActivePaymentMethods(); + if (empty($activePayments)) { + $this->logger->info('No active payment options found', [ + 'context' => [], + ]); + return; } diff --git a/src/Service/TransactionFlow/SaferPayTransactionAssertion.php b/src/Service/TransactionFlow/SaferPayTransactionAssertion.php index 5fcc3549..bc1bee8f 100755 --- a/src/Service/TransactionFlow/SaferPayTransactionAssertion.php +++ b/src/Service/TransactionFlow/SaferPayTransactionAssertion.php @@ -24,7 +24,9 @@ namespace Invertus\SaferPay\Service\TransactionFlow; use Invertus\SaferPay\Api\Request\AssertService; +use Invertus\SaferPay\Config\SaferPayConfig; use Invertus\SaferPay\DTO\Response\Assert\AssertBody; +use Invertus\SaferPay\Logger\LoggerInterface; use Invertus\SaferPay\Repository\SaferPayOrderRepository; use Invertus\SaferPay\Service\Request\AssertRequestObjectCreator; use SaferPayOrder; @@ -35,6 +37,7 @@ class SaferPayTransactionAssertion { + const FILE_NAME = 'SaferPayTransactionAssertion'; /** * @var AssertRequestObjectCreator */ @@ -49,15 +52,21 @@ class SaferPayTransactionAssertion * @var AssertService */ private $assertionService; + /** + * @var LoggerInterface + */ + private $logger; public function __construct( AssertRequestObjectCreator $assertRequestCreator, SaferPayOrderRepository $orderRepository, - AssertService $assertionService + AssertService $assertionService, + LoggerInterface $logger ) { $this->assertRequestCreator = $assertRequestCreator; $this->orderRepository = $orderRepository; $this->assertionService = $assertionService; + $this->logger = $logger; } /** @@ -66,21 +75,46 @@ public function __construct( * @return AssertBody * @throws \Exception */ - public function assert($cartId, $update = true) + public function assert($cartId, $saveCard = null, $selectedCard = null, $isBusiness = 0, $update = true) { + $cart = new \Cart($cartId); + $saferPayOrder = new SaferPayOrder($this->orderRepository->getIdByCartId($cartId)); - \PrestaShopLogger::addLog('saferpayOrderId:' . $saferPayOrder->id); - $assertRequest = $this->assertRequestCreator->create($saferPayOrder->token); - $assertResponse = $this->assertionService->assert($assertRequest, $saferPayOrder->id); + $this->logger->debug(sprintf('%s - assert service called',self::FILE_NAME), [ + 'context' => [ + 'cart_id' => $cartId, + 'saferpay_order_id' => $saferPayOrder->id, + ], + ]); + + $assertRequest = $this->assertRequestCreator->create($saferPayOrder->token, $saveCard); + $assertResponse = $this->assertionService->assert($assertRequest, $isBusiness); if (empty($assertResponse)) { + $this->logger->debug(sprintf('%s - assert response is empty', self::FILE_NAME), [ + 'context' => [ + 'cart_id' => $cartId, + 'saferpay_order_id' => $saferPayOrder->id, + ], + ]); + return null; } + $this->logger->debug(sprintf('%s - adding assert response data into assertBody object', self::FILE_NAME), [ + 'context' => [ + 'cart_id' => $cartId, + 'saferpay_order_id' => $saferPayOrder->id, + ], + 'reponse' => get_object_vars($assertResponse), + ]); + $assertBody = $this->assertionService->createObjectsFromAssertResponse( $assertResponse, - $saferPayOrder->id + $saferPayOrder->id, + $cart->id_customer, + $selectedCard ); // assertion shouldn't update, this is quickfix for what seems to be a general flaw in structure @@ -90,6 +124,13 @@ public function assert($cartId, $update = true) $saferPayOrder->update(); } + $this->logger->debug(sprintf('%s - assert service ended',self::FILE_NAME), [ + 'context' => [ + 'cart_id' => $cartId, + 'saferpay_order_id' => $saferPayOrder->id, + ], + ]); + return $assertBody; } } diff --git a/src/Service/TransactionFlow/SaferPayTransactionAuthorization.php b/src/Service/TransactionFlow/SaferPayTransactionAuthorization.php index 92c1b2fa..b79bc354 100755 --- a/src/Service/TransactionFlow/SaferPayTransactionAuthorization.php +++ b/src/Service/TransactionFlow/SaferPayTransactionAuthorization.php @@ -30,7 +30,6 @@ use Invertus\SaferPay\Repository\SaferPayOrderRepository; use Invertus\SaferPay\Service\Request\AuthorizationRequestObjectCreator; use Invertus\SaferPay\Service\SaferPayOrderStatusService; -use Order; use SaferPayOrder; if (!defined('_PS_VERSION_')) { diff --git a/src/ServiceProvider/BaseServiceProvider.php b/src/ServiceProvider/BaseServiceProvider.php index fb547e64..e20df45a 100755 --- a/src/ServiceProvider/BaseServiceProvider.php +++ b/src/ServiceProvider/BaseServiceProvider.php @@ -23,10 +23,23 @@ namespace Invertus\SaferPay\ServiceProvider; +use Invertus\SaferPay\Context\GlobalShopContext; +use Invertus\SaferPay\EntityManager\EntityManagerInterface; +use Invertus\SaferPay\EntityManager\ObjectModelEntityManager; +use Invertus\SaferPay\Logger\Formatter\LogFormatter; +use Invertus\SaferPay\Logger\Formatter\LogFormatterInterface; +use Invertus\SaferPay\Logger\Logger; +use Invertus\SaferPay\Logger\LoggerInterface; use Invertus\SaferPay\Provider\BasicIdempotencyProvider; +use Invertus\SaferPay\Provider\CurrentPaymentTypeProvider; use Invertus\SaferPay\Provider\IdempotencyProviderInterface; use Invertus\SaferPay\Repository\OrderRepository; use Invertus\SaferPay\Repository\OrderRepositoryInterface; +use Invertus\SaferPay\Repository\PrestashopLoggerRepository; +use Invertus\SaferPay\Repository\PrestashopLoggerRepositoryInterface; +use Invertus\SaferPay\Repository\SaferPayLogRepository; +use Invertus\SaferPay\Repository\SaferPayLogRepositoryInterface; +use Invertus\SaferPay\Context\GlobalShopContextInterface; use League\Container\Container; if (!defined('_PS_VERSION_')) { @@ -48,7 +61,13 @@ public function __construct($extendedServices) public function register(Container $container) { $this->addService($container, IdempotencyProviderInterface::class, $container->get(BasicIdempotencyProvider::class)); + $this->addService($container, LogFormatterInterface::class, $container->get(LogFormatter::class)); + $this->addService($container, GlobalShopContextInterface::class, $container->get(GlobalShopContext::class)); $this->addService($container, OrderRepositoryInterface::class, $container->get(OrderRepository::class)); + $this->addService($container, SaferPayLogRepositoryInterface::class, $container->get(SaferPayLogRepository::class)); + $this->addService($container, PrestashopLoggerRepositoryInterface::class, $container->get(PrestashopLoggerRepository::class)); + $this->addService($container, LoggerInterface::class, $container->get(Logger::class)); + $this->addService($container, EntityManagerInterface::class, $container->get(ObjectModelEntityManager::class)); } private function addService(Container $container, $className, $service) diff --git a/src/Utility/ExceptionUtility.php b/src/Utility/ExceptionUtility.php new file mode 100644 index 00000000..2ee3495c --- /dev/null +++ b/src/Utility/ExceptionUtility.php @@ -0,0 +1,57 @@ + + *@copyright SIX Payment Services + *@license SIX Payment Services + */ + +namespace Invertus\SaferPay\Utility; + +if (!defined('_PS_VERSION_')) { + exit; +} + +class ExceptionUtility +{ + public static function getExceptions($exception) + { + if (method_exists($exception, 'getExceptions')) { + return $exception->getExceptions(); + } + + return [self::toArray($exception)]; + } + + public static function toArray($exception) + { + if (method_exists($exception, 'getContext')) { + $context = $exception->getContext(); + } else { + $context = []; + } + + return [ + 'message' => (string) $exception->getMessage(), + 'code' => (int) $exception->getCode(), + 'file' => (string) $exception->getFile(), + 'line' => (int) $exception->getLine(), + 'context' => $context, + ]; + } +} diff --git a/src/Utility/VersionUtility.php b/src/Utility/VersionUtility.php new file mode 100644 index 00000000..d19b7ac7 --- /dev/null +++ b/src/Utility/VersionUtility.php @@ -0,0 +1,61 @@ + + *@copyright SIX Payment Services + *@license SIX Payment Services + */ + +namespace Invertus\SaferPay\Utility; + +if (!defined('_PS_VERSION_')) { + exit; +} + +class VersionUtility +{ + public static function isPsVersionLessThan($version) + { + return version_compare(_PS_VERSION_, $version, '<'); + } + + public static function isPsVersionGreaterThan($version) + { + return version_compare(_PS_VERSION_, $version, '>'); + } + + public static function isPsVersionGreaterOrEqualTo($version) + { + return version_compare(_PS_VERSION_, $version, '>='); + } + + public static function isPsVersionLessThanOrEqualTo($version) + { + return version_compare(_PS_VERSION_, $version, '<='); + } + + public static function isPsVersionEqualTo($version) + { + return version_compare(_PS_VERSION_, $version, '='); + } + + public static function current() + { + return _PS_VERSION_; + } +} diff --git a/src/Validation/CustomerCreditCardValidation.php b/src/Validation/CustomerCreditCardValidation.php new file mode 100644 index 00000000..d487c6f1 --- /dev/null +++ b/src/Validation/CustomerCreditCardValidation.php @@ -0,0 +1,86 @@ + + *@copyright SIX Payment Services + *@license SIX Payment Services + */ + +namespace Invertus\SaferPay\Validation; + +use Exception; +use Invertus\SaferPay\Exception\Restriction\UnauthenticatedCardUserException; +use Invertus\SaferPay\Exception\SaferPayException; +use Invertus\SaferPay\Logger\LoggerInterface; +use Invertus\SaferPay\Repository\SaferPayCardAliasRepository; + +if (!defined('_PS_VERSION_')) { + exit; +} + +class CustomerCreditCardValidation +{ + /** + * @var SaferPayCardAliasRepository + */ + private $saferPayCardAliasRepository; + /** + * @var mixed + */ + private $logger; + + const FILE_NAME = 'CustomerCreditCardValidation'; + + public function __construct(SaferPayCardAliasRepository $saferPayCardAliasRepository, LoggerInterface $logger) + { + $this->saferPayCardAliasRepository = $saferPayCardAliasRepository; + $this->logger = $logger; + } + + /** + * @return true + * + * @throws UnauthenticatedCardUserException + * @throws SaferPayException + */ + public function validate($idSavedCard, $idCustomer) + { + if ($idSavedCard <= 0 || empty($idSavedCard)) { + return true; + } + + if (!is_numeric($idCustomer) || !is_numeric($idSavedCard)) + { + $this->logger->error(sprintf('%s - Invalid data or bad types', self::FILE_NAME), [ + 'context' => [], + 'id_saved_card' => $idSavedCard, + 'id_customer' => $idCustomer + ]); + + throw SaferPayException::unknownError(); + } + + $cardOwnerId = $this->saferPayCardAliasRepository->getCustomerIdByReferenceId(pSQL($idSavedCard), pSQL($idCustomer)); + + if (empty($cardOwnerId)) { + throw UnauthenticatedCardUserException::unauthenticatedCard($cardOwnerId); + } + + return true; + } +} \ No newline at end of file diff --git a/src/Validation/ValidateIsAssetsRequired.php b/src/Validation/ValidateIsAssetsRequired.php new file mode 100644 index 00000000..d62beff5 --- /dev/null +++ b/src/Validation/ValidateIsAssetsRequired.php @@ -0,0 +1,56 @@ + + *@copyright SIX Payment Services + *@license SIX Payment Services + */ + +namespace Invertus\SaferPay\Validation; + +use Invertus\SaferPay\Provider\OpcModulesProvider; +use FrontController; + +if (!defined('_PS_VERSION_')) { + exit; +} + +class ValidateIsAssetsRequired +{ + private $opcModulesProvider; + + public function __construct(OpcModulesProvider $opcModulesProvider) + { + $this->opcModulesProvider = $opcModulesProvider; + } + + /** + * It returns true if it's an OPC controller or an OrderController with products in the cart. Otherwise, it returns false. + */ + public function run(FrontController $controller) + { + $isOrderController = $controller instanceof \OrderControllerCore + || $controller instanceof \ModuleFrontController && isset($controller->php_self) && $controller->php_self === 'order'; + + if (!empty($this->opcModulesProvider->get($controller))) { + return $isOrderController && !empty(\Context::getContext()->cart->getProducts()); + } + + return true; + } +} \ No newline at end of file diff --git a/upgrade/install-1.1.8.php b/upgrade/install-1.1.8.php index d52c8914..636a4cb3 100644 --- a/upgrade/install-1.1.8.php +++ b/upgrade/install-1.1.8.php @@ -41,4 +41,4 @@ function upgrade_module_1_1_8(SaferPayOfficial $module) $module->registerHook('actionObjectOrderPaymentAddAfter'); return true; -} \ No newline at end of file +} diff --git a/upgrade/install-1.2.0.php b/upgrade/install-1.2.0.php index d127a4e6..66a8756a 100644 --- a/upgrade/install-1.2.0.php +++ b/upgrade/install-1.2.0.php @@ -22,7 +22,6 @@ */ use Invertus\SaferPay\Config\SaferPayConfig; -use Configuration; if (!defined('_PS_VERSION_')) { exit; diff --git a/upgrade/install-1.2.2.php b/upgrade/install-1.2.2.php index b0b04cc5..491651c4 100644 --- a/upgrade/install-1.2.2.php +++ b/upgrade/install-1.2.2.php @@ -21,6 +21,8 @@ *@license SIX Payment Services */ +use Invertus\SaferPay\Config\SaferPayConfig; + if (!defined('_PS_VERSION_')) { exit; } @@ -35,4 +37,3 @@ function upgrade_module_1_2_2($module) && $module->unregisterHook('actionOrderStatusUpdate') && Configuration::deleteByName('SAFERPAY_SEND_ORDER_CONFIRMATION'); } - diff --git a/upgrade/install-1.2.4.php b/upgrade/install-1.2.4.php new file mode 100644 index 00000000..ae422949 --- /dev/null +++ b/upgrade/install-1.2.4.php @@ -0,0 +1,42 @@ + + *@copyright SIX Payment Services + *@license SIX Payment Services + */ + +if (!defined('_PS_VERSION_')) { + exit; +} + +function upgrade_module_1_2_4(SaferPayOfficial $module) +{ + return Db::getInstance()->execute( + 'ALTER TABLE ' . _DB_PREFIX_ . pSQL(SaferPayLog::$definition['table']) . ' + ADD COLUMN `id_log` INT(10) DEFAULT 0, + ADD COLUMN `id_shop` INT(10) DEFAULT ' . (int) Configuration::get('PS_SHOP_DEFAULT') . ', + CHANGE `payload` `request` TEXT, + ADD COLUMN `response` MEDIUMTEXT DEFAULT NULL, + ADD COLUMN `context` MEDIUMTEXT DEFAULT NULL, + DROP COLUMN `message`, + DROP PRIMARY KEY, + ADD PRIMARY KEY (`id_saferpay_log`, `id_log`, `id_shop`), + ADD INDEX (`id_log`);' + ); +} diff --git a/var/cache/index.php b/var/cache/index.php old mode 100755 new mode 100644 index ee622726..9d92aad2 --- a/var/cache/index.php +++ b/var/cache/index.php @@ -28,4 +28,4 @@ header('Pragma: no-cache'); header('Location: ../'); -exit; +exit; \ No newline at end of file diff --git a/views/css/admin/logs_tab.css b/views/css/admin/logs_tab.css index f679c02c..5bb36a92 100755 --- a/views/css/admin/logs_tab.css +++ b/views/css/admin/logs_tab.css @@ -22,4 +22,92 @@ .saferpay-text-break { word-break: break-all; width: 700px; -} \ No newline at end of file +} + +.button { + cursor: pointer; +} + +.log-modal-overlay { + transition: opacity 0.2s ease-out; + pointer-events: none; + background: rgba(15, 23, 42, 0.8); + position: fixed; + opacity: 0; + bottom: 0; + right: 0; + left: 0; + top: 0; +} + +.modal.open .log-modal-overlay { + pointer-events: all; + opacity: 0.5; +} + +.log-modal-window { + position: relative; + width: 50%; + margin: 10% auto; + + background: #ffffff; + border-radius: 0.5em; + box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2); + pointer-events: all; + text-align: left; + max-height: 100vh; + min-height: 60vh; + display: flex; + flex-direction: column; + + overflow: auto; +} + +.open { + display: block; +} + +.log-modal-title { + color: #111827; + padding: 3px; + border-bottom: solid 1px grey; + pointer-events: all; + display: flex; + justify-content: center; + max-height: 10vh; +} + +.log-modal-content { + padding: 15px; + height: 50vh; +} + +.log-modal-content-spinner { + min-height: 50vh; +} + +.log-modal-content-spinner:not(.hidden) { + display: flex; + justify-content: center; + align-items: center; +} + +.log-modal-content-spinner::after { + content: ""; + width: 40px; + height: 40px; + border: 2px solid #f3f3f3; + border-top: 3px solid #f25a41; + border-radius: 100%; + will-change: transform; + animation: spin 1s infinite linear +} + +@keyframes spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} diff --git a/views/css/front/saferpay_checkout.css b/views/css/front/saferpay_checkout.css index 7a88f011..a100ae4c 100755 --- a/views/css/front/saferpay_checkout.css +++ b/views/css/front/saferpay_checkout.css @@ -26,3 +26,24 @@ .payment-option img { height: 24px; } + +.payment-logo { + max-width: 40px; +} + +.payment-logo { + max-width: 40px; +} + +input[type="radio"][name^="saved_card_"] { + opacity: 1 !important; + width: 15px !important; + position: relative !important; + vertical-align: middle !important; + margin: 0 !important; +} +.saved_credit_cards span { + padding-left: 3px !important; + vertical-align: middle !important; + margin: 0 !important; +} diff --git a/views/js/admin/log.js b/views/js/admin/log.js new file mode 100644 index 00000000..4a8eb769 --- /dev/null +++ b/views/js/admin/log.js @@ -0,0 +1,65 @@ +/** + *NOTICE OF LICENSE + * + *This source file is subject to the Open Software License (OSL 3.0) + *that is bundled with this package in the file LICENSE.txt. + *It is also available through the world-wide-web at this URL: + *http://opensource.org/licenses/osl-3.0.php + *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. + * + *DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade PrestaShop to newer + *versions in the future. If you wish to customize PrestaShop for your + *needs please refer to http://www.prestashop.com for more information. + * + *@author INVERTUS UAB www.invertus.eu + *@copyright SIX Payment Services + *@license SIX Payment Services + */ + +$(document).ready(function () { + $('.log-modal-overlay').on('click', function (event) { + $('.modal.open').removeClass('open'); + event.preventDefault(); + }); + + $('.js-log-button').on('click', function (event) { + var logId = $(this).data('log-id'); + var informationType = $(this).data('information-type'); + + // NOTE: opening modal + $('#' + $(this).data('target')).addClass('open'); + + // NOTE: if information has been set already we don't need to call ajax again. + if (!$('#log-modal-' + logId + '-' + informationType + ' .log-modal-content-data').hasClass('hidden')) { + return; + } + + $('.log-modal-content-spinner').removeClass('hidden'); + + $.ajax({ + type: 'POST', + url: saferpayofficial.logsUrl, + data: { + ajax: true, + action: 'getLog', + log_id: logId + } + }) + .then(response => jQuery.parseJSON(response)) + .then(data => { + $('.log-modal-content-spinner').addClass('hidden') + + $('#log-modal-' + logId + '-request .log-modal-content-data').removeClass('hidden').html(prettyJson(data.log.request)); + $('#log-modal-' + logId + '-response .log-modal-content-data').removeClass('hidden').html(prettyJson(data.log.response)); + $('#log-modal-' + logId + '-context .log-modal-content-data').removeClass('hidden').html(prettyJson(data.log.context)); + }) + }); +}); + +function prettyJson(json) { + return JSON.stringify(JSON.parse(json), null, 2) +} diff --git a/views/js/front/hosted-templates/hosted_fields.js b/views/js/front/hosted-templates/hosted_fields.js index 66324a49..2ee1e631 100755 --- a/views/js/front/hosted-templates/hosted_fields.js +++ b/views/js/front/hosted-templates/hosted_fields.js @@ -27,20 +27,10 @@ $(document).ready(function () { return; } - $('[id="payment-form"]').on('submit', function (event) { + $('body').on('submit', '[id^=pay-with-][id$=-form] form', function (event) { event.preventDefault(); - var paymentType = $(this).find("[name=saferpayPaymentType]").val(); - - //NOTE: if it's not a hosted iframe then we don't need to submitHostedFields. - if (paymentType !== saferpay_payment_types.hosted_iframe) { - event.target.submit(); - - return; - } - var selectedCardMethod = $(this).find("[name=saved_card_method]").val(); - var selectedCard = $(this).find("[name=selectedCreditCard_" + selectedCardMethod + "]").val(); //NOTE: not saved card chosen, continuing with normal procedures. diff --git a/views/js/front/opc/onepagecheckoutps/hosted_fields.js b/views/js/front/opc/onepagecheckoutps/hosted_fields.js new file mode 100644 index 00000000..2b8162f7 --- /dev/null +++ b/views/js/front/opc/onepagecheckoutps/hosted_fields.js @@ -0,0 +1,59 @@ +/** + *NOTICE OF LICENSE + * + *This source file is subject to the Open Software License (OSL 3.0) + *that is bundled with this package in the file LICENSE.txt. + *It is also available through the world-wide-web at this URL: + *http://opensource.org/licenses/osl-3.0.php + *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. + * + *DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade PrestaShop to newer + *versions in the future. If you wish to customize PrestaShop for your + *needs please refer to http://www.prestashop.com for more information. + * + *@author INVERTUS UAB www.invertus.eu + *@copyright SIX Payment Services + *@license SIX Payment Services + */ + +$(document).ready(function () { + $('body').on('change', "input[name^='saved_card_']", function () { + var $selectedCard = $(this); + var method = $selectedCard.closest('div.saved_cards').find('.saved_card_method').val(); + $("input[name='selectedCreditCard_" + method + "']").val($selectedCard.val()); + }); +}); + +$('body').on('submit', '[id^=pay-with-][id$=-form] form', function (event) { + event.preventDefault(); + + var selectedCardMethod = $(this).find("[name=saved_card_method]").val(); + var selectedCard = $(this).find("[name=selectedCreditCard_" + selectedCardMethod + "]").val(); + + //NOTE: not saved card chosen, continuing with normal procedures. + if (selectedCard <= 0) { + event.target.submit(); + + return; + } + + $.ajax(saferpay_official_ajax_url, { + method: 'POST', + data: { + action: 'submitHostedFields', + paymentMethod: selectedCardMethod, + selectedCard: selectedCard, + isBusinessLicence: 1, + ajax: 1 + }, + success: function (response) { + var data = jQuery.parseJSON(response); + + window.location = data.url; + }, + }); +}); \ No newline at end of file diff --git a/views/js/front/opc/supercheckout/hosted_fields.js b/views/js/front/opc/supercheckout/hosted_fields.js new file mode 100644 index 00000000..2b8162f7 --- /dev/null +++ b/views/js/front/opc/supercheckout/hosted_fields.js @@ -0,0 +1,59 @@ +/** + *NOTICE OF LICENSE + * + *This source file is subject to the Open Software License (OSL 3.0) + *that is bundled with this package in the file LICENSE.txt. + *It is also available through the world-wide-web at this URL: + *http://opensource.org/licenses/osl-3.0.php + *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. + * + *DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade PrestaShop to newer + *versions in the future. If you wish to customize PrestaShop for your + *needs please refer to http://www.prestashop.com for more information. + * + *@author INVERTUS UAB www.invertus.eu + *@copyright SIX Payment Services + *@license SIX Payment Services + */ + +$(document).ready(function () { + $('body').on('change', "input[name^='saved_card_']", function () { + var $selectedCard = $(this); + var method = $selectedCard.closest('div.saved_cards').find('.saved_card_method').val(); + $("input[name='selectedCreditCard_" + method + "']").val($selectedCard.val()); + }); +}); + +$('body').on('submit', '[id^=pay-with-][id$=-form] form', function (event) { + event.preventDefault(); + + var selectedCardMethod = $(this).find("[name=saved_card_method]").val(); + var selectedCard = $(this).find("[name=selectedCreditCard_" + selectedCardMethod + "]").val(); + + //NOTE: not saved card chosen, continuing with normal procedures. + if (selectedCard <= 0) { + event.target.submit(); + + return; + } + + $.ajax(saferpay_official_ajax_url, { + method: 'POST', + data: { + action: 'submitHostedFields', + paymentMethod: selectedCardMethod, + selectedCard: selectedCard, + isBusinessLicence: 1, + ajax: 1 + }, + success: function (response) { + var data = jQuery.parseJSON(response); + + window.location = data.url; + }, + }); +}); \ No newline at end of file diff --git a/views/js/front/opc/thecheckout/hosted_fields.js b/views/js/front/opc/thecheckout/hosted_fields.js new file mode 100644 index 00000000..ed2299f3 --- /dev/null +++ b/views/js/front/opc/thecheckout/hosted_fields.js @@ -0,0 +1,95 @@ +/** + *NOTICE OF LICENSE + * + *This source file is subject to the Open Software License (OSL 3.0) + *that is bundled with this package in the file LICENSE.txt. + *It is also available through the world-wide-web at this URL: + *http://opensource.org/licenses/osl-3.0.php + *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. + * + *DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade PrestaShop to newer + *versions in the future. If you wish to customize PrestaShop for your + *needs please refer to http://www.prestashop.com for more information. + * + *@author INVERTUS UAB www.invertus.eu + *@copyright SIX Payment Services + *@license SIX Payment Services + */ + +var selectedCard = null; + +$(document).ready(function () { + let savedCardMethod = $('input[name="saved_card_method"]'); + + if (!savedCardMethod.length) { + return; + } +}); + +$(document).on('change', 'input[name^="saved_card_"]', function () { + var method = $('[data-module-name*="saferpayofficial"]:checked').closest('div').find('.h6').text().toUpperCase(); + updateCheckedCardValue(); + $("input[name='selectedCreditCard_" + method + "']").val(selectedCard); +}); + +$('body').on('submit', '[id^=pay-with-][id$=-form] form', function (e) { + var idPayment = $(this).parent('div').attr('id').match(/\d+/)[0]; + handleSubmit(e, idPayment); +}); + +function handleSubmit(event, idPayment) { + event.preventDefault(); + + let selectedCardMethod = $('#' + "payment-option-" + idPayment + "-additional-information").find('input[type="hidden"]').val(); + let form = $(document).find("[name=selectedCreditCard_" + selectedCardMethod + "]").closest('form'); + let hiddenInput = form.find("input[name='selectedCreditCard_" + selectedCardMethod + "']"); + + /* + * NOTE: + * when user just press payment method + * but not touched what to do with card + */ + if (selectedCard === null) { + selectedCard = hiddenInput.val(); + } + + hiddenInput.val(selectedCard); + + /* + * NOTE: + * not saved card chosen, continuing with normal procedures. + */ + if (parseInt(selectedCard) <= 0 || selectedCard === null || selectedCard === undefined) { + event.target.submit(); + + return; + } + + $.ajax(saferpay_official_ajax_url, { + method: 'POST', + data: { + action: 'submitHostedFields', + paymentMethod: selectedCardMethod, + selectedCard: parseInt(selectedCard), + isBusinessLicence: 1, + ajax: 1 + }, + success: function (response) { + var data = jQuery.parseJSON(response); + + window.location = data.url; + }, + }); +} + +function updateCheckedCardValue() { + $('input[name^="saved_card_"]:checked').each(function() { + if ($(this).is(':visible')) { + selectedCard = $(this).val(); + } + }); +} \ No newline at end of file diff --git a/views/js/front/saferpay_iframe_16.js b/views/js/front/saferpay_iframe_16.js new file mode 100644 index 00000000..a555a0d1 --- /dev/null +++ b/views/js/front/saferpay_iframe_16.js @@ -0,0 +1,29 @@ +/** + *NOTICE OF LICENSE + * + *This source file is subject to the Open Software License (OSL 3.0) + *that is bundled with this package in the file LICENSE.txt. + *It is also available through the world-wide-web at this URL: + *http://opensource.org/licenses/osl-3.0.php + *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. + * + *DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade PrestaShop to newer + *versions in the future. If you wish to customize PrestaShop for your + *needs please refer to http://www.prestashop.com for more information. + * + *@author INVERTUS UAB www.invertus.eu + *@copyright SIX Payment Services + *@license SIX Payment Services + */ + +(function () { + // NOTE: Replacing because javascript gives "&" instead of "&" in the URL + redirectUrl = redirectUrl.replace(/&/g, "&"); + if (top.location !== window.location) { + top.location.href = redirectUrl; + } +})(); \ No newline at end of file diff --git a/views/templates/admin/logs/log_modal.tpl b/views/templates/admin/logs/log_modal.tpl new file mode 100644 index 00000000..62cb43dd --- /dev/null +++ b/views/templates/admin/logs/log_modal.tpl @@ -0,0 +1,53 @@ +{** + *NOTICE OF LICENSE + * + *This source file is subject to the Open Software License (OSL 3.0) + *that is bundled with this package in the file LICENSE.txt. + *It is also available through the world-wide-web at this URL: + *http://opensource.org/licenses/osl-3.0.php + *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. + * + *DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade PrestaShop to newer + *versions in the future. If you wish to customize PrestaShop for your + *needs please refer to http://www.prestashop.com for more information. + * + *@author INVERTUS UAB www.invertus.eu + *@copyright SIX Payment Services + *@license SIX Payment Services + *} +
+ {l s='View' mod='saferpayofficial'} +
+ + \ No newline at end of file diff --git a/views/templates/admin/logs/severity_level_column.tpl b/views/templates/admin/logs/severity_level_column.tpl new file mode 100644 index 00000000..1629dc07 --- /dev/null +++ b/views/templates/admin/logs/severity_level_column.tpl @@ -0,0 +1,32 @@ +{** + *NOTICE OF LICENSE + * + *This source file is subject to the Open Software License (OSL 3.0) + *that is bundled with this package in the file LICENSE.txt. + *It is also available through the world-wide-web at this URL: + *http://opensource.org/licenses/osl-3.0.php + *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. + * + *DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade PrestaShop to newer + *versions in the future. If you wish to customize PrestaShop for your + *needs please refer to http://www.prestashop.com for more information. + * + *@author INVERTUS UAB www.invertus.eu + *@copyright SIX Payment Services + *@license SIX Payment Services + *} +{if $log_severity_level == $log_severity_level_informative} + {l s='Informative only' mod='saferpayofficial'} ({$log_severity_level|intval}) +{elseif $log_severity_level == $log_severity_level_warning} + {l s='Warning' mod='saferpayofficial'} ({$log_severity_level|intval}) +{elseif $log_severity_level == $log_severity_level_error} + {l s='Error' mod='saferpayofficial'} ({$log_severity_level|intval}) +{elseif $log_severity_level == $log_severity_level_major} + {l s='Major issue (crash)!' mod='saferpayofficial'} ({$log_severity_level|intval}) +{else} + {$log_severity_level|escape:'htmlall':'UTF-8'} +{/if} \ No newline at end of file diff --git a/views/templates/admin/logs/severity_levels.tpl b/views/templates/admin/logs/severity_levels.tpl new file mode 100644 index 00000000..c6ab90fa --- /dev/null +++ b/views/templates/admin/logs/severity_levels.tpl @@ -0,0 +1,34 @@ +{** + *NOTICE OF LICENSE + * + *This source file is subject to the Open Software License (OSL 3.0) + *that is bundled with this package in the file LICENSE.txt. + *It is also available through the world-wide-web at this URL: + *http://opensource.org/licenses/osl-3.0.php + *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. + * + *DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade PrestaShop to newer + *versions in the future. If you wish to customize PrestaShop for your + *needs please refer to http://www.prestashop.com for more information. + * + *@author INVERTUS UAB www.invertus.eu + *@copyright SIX Payment Services + *@license SIX Payment Services + *} +
+

+ + {l s='Severity levels:' mod='saferpayofficial'} +

+

{l s='Meaning of severity levels:' mod='saferpayofficial'}

+
    +
  1. {l s='Info' mod='saferpayofficial'}
  2. +
  3. {l s='Warning' mod='saferpayofficial'}
  4. +
  5. {l s='Error' mod='saferpayofficial'}
  6. +
  7. {l s='Fatal' mod='saferpayofficial'}
  8. +
+
\ No newline at end of file diff --git a/views/templates/front/credit_cards.tpl b/views/templates/front/credit_cards.tpl index d042b193..16083a4b 100755 --- a/views/templates/front/credit_cards.tpl +++ b/views/templates/front/credit_cards.tpl @@ -51,7 +51,7 @@ {foreach $rows as $row} - {$row nofilter|escape:'htmlall':'UTF-8'} + {$row|cleanHtml nofilter} {/foreach} diff --git a/views/templates/front/credit_cards_16.tpl b/views/templates/front/credit_cards_16.tpl index ee8f2a0a..af1140bf 100755 --- a/views/templates/front/credit_cards_16.tpl +++ b/views/templates/front/credit_cards_16.tpl @@ -53,7 +53,7 @@ {foreach $rows as $row} - {$row nofilter|escape:'htmlall':'UTF-8'} + {$row|cleanHtml nofilter} {/foreach}