diff --git a/changelog.md b/changelog.md index 78048bcf8..eb2c90030 100644 --- a/changelog.md +++ b/changelog.md @@ -1,6 +1,11 @@ ![Mollie](https://www.mollie.nl/files/Mollie-Logo-Style-Small.png) # Changelog # +## Changes in release 6.2.3 ## ++ Multi shop improvements with order states ++ Logging improvements ++ Phone field validation improvements ++ Italian language compatibility ## Changes in release 6.2.2 ## + Error handling improvements diff --git a/composer.json b/composer.json index 6f4806454..4127a996b 100644 --- a/composer.json +++ b/composer.json @@ -2,6 +2,12 @@ "name": "mollie/prestashop", "license": "AFL-3.0", "description": "Mollie module for PrestaShop", + "repositories": [ + { + "type": "vcs", + "url": "https://github.com/Invertus/Knapsack.git" + } + ], "require": { "ext-curl": "*", "ext-json": "*", @@ -17,13 +23,15 @@ "http-interop/http-factory-guzzle": "^1.1", "php-http/message-factory": "^1.1", "prestashop/prestashop-accounts-installer": "^1.0.4", - "prestashop/module-lib-mbo-installer": "^2.0" + "prestashop/module-lib-mbo-installer": "^2.0", + "invertus/knapsack": "^10.0" }, "require-dev": { "roave/security-advisories": "dev-latest", "invertus/prestashop-models": "^1.0", "prestashop/php-dev-tools": "*", - "phpunit/phpunit": "~5.7" + "phpunit/phpunit": "~5.7", + "friendsofphp/php-cs-fixer": "^2.19" }, "autoload-dev": { "psr-4": { diff --git a/controllers/admin/AdminMollieLogsController.php b/controllers/admin/AdminMollieLogsController.php new file mode 100644 index 000000000..d44b2f114 --- /dev/null +++ b/controllers/admin/AdminMollieLogsController.php @@ -0,0 +1,443 @@ + + * @copyright Mollie B.V. + * @license https://github.com/mollie/PrestaShop/blob/master/LICENSE.md + * + * @see https://github.com/mollie/PrestaShop + * @codingStandardsIgnoreStart + */ + +use Mollie\Adapter\ConfigurationAdapter; +use Mollie\Adapter\Shop; +use Mollie\Config\Config; +use Mollie\Logger\LogFormatter; +use Mollie\Logger\Logger; +use Mollie\Logger\LoggerInterface; +use Mollie\Repository\MolLogRepositoryInterface; +use Mollie\Utility\ExceptionUtility; +use Mollie\Utility\VersionUtility; + +if (!defined('_PS_VERSION_')) { + exit; +} +class AdminMollieLogsController extends ModuleAdminController +{ + /** @var Mollie */ + public $module; + + const FILE_NAME = 'AdminMollieLogsController'; + + const LOG_INFORMATION_TYPE_REQUEST = 'request'; + const LOG_INFORMATION_TYPE_RESPONSE = 'response'; + const LOG_INFORMATION_TYPE_CONTEXT = 'context'; + + public function __construct() + { + $this->bootstrap = true; + $this->table = 'log'; + $this->className = 'PrestaShopLogger'; + $this->lang = false; + $this->noLink = true; + $this->allow_export = true; + + parent::__construct(); + + $this->toolbar_btn = []; + $this->fields_list = [ + 'id_log' => [ + 'title' => $this->module->l('ID', self::FILE_NAME), + 'align' => 'text-center', + 'class' => 'fixed-width-xs', + ], + 'severity' => [ + 'title' => $this->module->l('Severity (1-4)', self::FILE_NAME), + 'align' => 'text-center', + 'class' => 'fixed-width-xs', + 'callback' => 'printSeverityLevel', + ], + 'message' => [ + 'title' => $this->module->l('Message', self::FILE_NAME), + ], + '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, + ], + '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->module->l('Date', self::FILE_NAME), + 'align' => 'right', + 'type' => 'datetime', + 'filter_key' => 'a!date_add', + ], + ]; + + $this->_orderBy = 'id_log'; + $this->_orderWay = 'desc'; + + $this->_select .= ' + REPLACE(a.`message`, "' . LogFormatter::MOLLIE_LOG_PREFIX . '", "") as message, + ml.request, ml.response, ml.context + '; + + $shopIdCheck = ''; + + if (VersionUtility::isPsVersionGreaterOrEqualTo('1.7.8.0')) { + $shopIdCheck = ' AND ml.id_shop = a.id_shop'; + } + + $this->_join .= ' JOIN ' . _DB_PREFIX_ . 'mol_logs ml ON (ml.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; + } + + /** + * @return false|string + * + * @throws SmartyException + */ + public function displaySeverityInformation() + { + return $this->context->smarty->fetch( + "{$this->module->getLocalPath()}views/templates/admin/logs/severity_levels.tpl" + ); + } + + /** + * @throws SmartyException + */ + public function initContent(): void + { + // NOTE: we cannot add new logs here. + if (isset($this->toolbar_btn['new'])) { + unset($this->toolbar_btn['new']); + } + + $this->content .= $this->displaySeverityInformation(); + + parent::initContent(); + } + + public function setMedia($isNewTheme = false): void + { + parent::setMedia($isNewTheme); + + Media::addJsDef([ + 'mollie' => [ + 'logsUrl' => Context::getContext()->link->getAdminLink(Mollie::ADMIN_MOLLIE_LOGS_CONTROLLER), + ], + ]); + + $this->addJS($this->module->getPathUri() . 'views/js/admin/logs/log.js', false); + $this->addCss($this->module->getPathUri() . 'views/css/admin/logs/log.css'); + } + + /** + * @param string $request + * @param array $data + * + * @return false|string + * + * @throws SmartyException + */ + public function printRequestButton(string $request, array $data) + { + return $this->getDisplayButton($data['id_log'], $request, self::LOG_INFORMATION_TYPE_REQUEST); + } + + /** + * @param string $response + * @param array $data + * + * @return false|string + * + * @throws SmartyException + */ + public function printResponseButton(string $response, array $data) + { + return $this->getDisplayButton($data['id_log'], $response, self::LOG_INFORMATION_TYPE_RESPONSE); + } + + /** + * @param string $context + * @param array $data + * + * @return false|string + * + * @throws SmartyException + */ + public function printContextButton(string $context, array $data) + { + return $this->getDisplayButton($data['id_log'], $context, self::LOG_INFORMATION_TYPE_CONTEXT); + } + + /** + * @param int $level + * + * @return false|string + * + * @throws SmartyException + */ + public function printSeverityLevel(int $level) + { + $this->context->smarty->assign([ + 'log_severity_level' => $level, + 'log_severity_level_informative' => defined('\PrestaShopLogger::LOG_SEVERITY_LEVEL_INFORMATIVE') ? + PrestaShopLogger::LOG_SEVERITY_LEVEL_INFORMATIVE : + Config::LOG_SEVERITY_LEVEL_INFORMATIVE, + 'log_severity_level_warning' => defined('\PrestaShopLogger::LOG_SEVERITY_LEVEL_WARNING') ? + PrestaShopLogger::LOG_SEVERITY_LEVEL_WARNING : + Config::LOG_SEVERITY_LEVEL_WARNING, + 'log_severity_level_error' => defined('\PrestaShopLogger::LOG_SEVERITY_LEVEL_ERROR') ? + PrestaShopLogger::LOG_SEVERITY_LEVEL_ERROR : + Config::LOG_SEVERITY_LEVEL_ERROR, + 'log_severity_level_major' => defined('\PrestaShopLogger::LOG_SEVERITY_LEVEL_MAJOR') ? + PrestaShopLogger::LOG_SEVERITY_LEVEL_MAJOR : + Config::LOG_SEVERITY_LEVEL_MAJOR, + ]); + + return $this->context->smarty->fetch( + "{$this->module->getLocalPath()}views/templates/admin/logs/severity_level_column.tpl" + ); + } + + /** + * @param int $logId + * @param string $data + * @param string $logInformationType + * + * @return false|string + * + * @throws SmartyException + */ + public function getDisplayButton(int $logId, string $data, string $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" + ); + } + + public function displayAjaxGetLog() + { + /** @var \Mollie\Adapter\ToolsAdapter $tools */ + $tools = $this->module->getService(\Mollie\Adapter\ToolsAdapter::class); + + /** @var MolLogRepositoryInterface $logRepository */ + $logRepository = $this->module->getService(MolLogRepositoryInterface::class); + + /** @var Shop $shopContext */ + $shopContext = $this->module->getService(Shop::class); + + $logId = $tools->getValueAsInt('log_id'); + + /** @var LoggerInterface $logger */ + $logger = $this->module->getService(LoggerInterface::class); + $log = null; + + try { + /** @var \MolLog|null $log */ + $log = $logRepository->findOneBy([ + 'id_log' => $logId, + 'id_shop' => $shopContext->getShop()->id, + ]); + } catch (\Exception $exception) { + $logger->error('Failed to find log', [ + 'context' => [ + 'id_log' => $logId, + 'id_shop' => $shopContext->getShop()->id, + ], + 'exceptions' => ExceptionUtility::getExceptions($exception), + ]); + + $this->ajaxResponse(json_encode([ + 'error' => true, + 'message' => $this->module->l('Failed to find log.', self::FILE_NAME), + ])); + } + + if (!$log) { + $logger->error('No log information found.', [ + 'context' => [ + 'id_log' => $logId, + 'id_shop' => $shopContext->getShop()->id, + ], + 'exceptions' => [], + ]); + + $this->ajaxResponse(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, + ], + ])); + } + + /** + * @param string|false|null $value + * @param null $controller + * @param null $method + * + * @return void + * + * @throws \PrestaShopException + */ + protected function ajaxResponse($value = null, $controller = null, $method = null): void + { + /** @var LoggerInterface $logger */ + $logger = $this->module->getService(LoggerInterface::class); + + try { + $this->ajaxDie($value, $controller, $method); + } catch (\Exception $exception) { + $logger->error('Could not return ajax response', [ + 'context' => [ + 'response' => json_encode($value ?: []), + 'exceptions' => ExceptionUtility::getExceptions($exception), + ], + ]); + } + + exit; + } + + 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 ConfigurationAdapter $configuration */ + $configuration = $this->module->getService(ConfigurationAdapter::class); + + /** @var Mollie\Adapter\Context $context */ + $context = $this->module->getService(Mollie\Adapter\Context::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 = [ + 'Environment' => $configuration->get(Config::MOLLIE_ENVIRONMENT) ? 'Production' : 'Sandbox', + 'Components' => $configuration->get(Config::MOLLIE_IFRAME), + 'OCP' => $configuration->get(Config::MOLLIE_SINGLE_CLICK_PAYMENT), + 'Locale Webshop' => $configuration->get(Config::MOLLIE_PAYMENTSCREEN_LOCALE), + 'Subscriptions enabled' => $configuration->get(Config::MOLLIE_SUBSCRIPTION_ENABLED), + ]; + + $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('ml.id_log, l.severity, l.message, ml.request, ml.response, ml.context, ml.date_add') + ->from('mol_logs', 'ml') + ->leftJoin('log', 'l', 'ml.id_log = l.id_log') + ->orderBy('ml.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); + exit; + } +} diff --git a/controllers/admin/AdminMollieLogsParentController.php b/controllers/admin/AdminMollieLogsParentController.php new file mode 100644 index 000000000..c9d3d04d0 --- /dev/null +++ b/controllers/admin/AdminMollieLogsParentController.php @@ -0,0 +1,21 @@ + + * @copyright Mollie B.V. + * @license https://github.com/mollie/PrestaShop/blob/master/LICENSE.md + * + * @see https://github.com/mollie/PrestaShop + * @codingStandardsIgnoreStart + */ +if (!defined('_PS_VERSION_')) { + exit; +} +class AdminMollieLogsParentController extends ModuleAdminController +{ + public function init() + { + Tools::redirectAdmin($this->context->link->getAdminLink('AdminMollieLogs')); + } +} diff --git a/controllers/admin/AdminMollieSettingsController.php b/controllers/admin/AdminMollieSettingsController.php index 614bc18c7..f27d749ed 100644 --- a/controllers/admin/AdminMollieSettingsController.php +++ b/controllers/admin/AdminMollieSettingsController.php @@ -12,6 +12,10 @@ declare(strict_types=1); +use Mollie\Logger\Logger; +use Mollie\Logger\LoggerInterface; +use Mollie\Utility\ExceptionUtility; + if (!defined('_PS_VERSION_')) { exit; } @@ -43,10 +47,18 @@ private function initCloudSyncAndPsAccounts(): void $this->context->smarty->assign('module_dir', $this->module->getPathUri()); $moduleManager = PrestaShop\PrestaShop\Core\Addon\Module\ModuleManagerBuilder::getInstance()->build(); + /** @var Logger $logger * */ + $logger = $this->module->getService(LoggerInterface::class); + try { $accountsFacade = $this->module->getService('Mollie.PsAccountsFacade'); $accountsService = $accountsFacade->getPsAccountsService(); } catch (PrestaShop\PsAccountsInstaller\Installer\Exception\InstallerException $e) { + $logger->error('Failed to initiate ps_accounts', [ + 'context' => [], + 'exceptions' => ExceptionUtility::getExceptions($e), + ]); + try { $accountsInstaller = $this->module->getService('Mollie.PsAccountsInstaller'); $accountsInstaller->install(); @@ -55,9 +67,15 @@ private function initCloudSyncAndPsAccounts(): void } catch (Exception $e) { $this->context->controller->errors[] = $e->getMessage(); + $logger->error('Failed to install ps_accounts', [ + 'context' => [], + 'exceptions' => ExceptionUtility::getExceptions($e), + ]); + return; } } + try { Media::addJsDef([ 'contextPsAccounts' => $accountsFacade->getPsAccountsPresenter() @@ -68,6 +86,11 @@ private function initCloudSyncAndPsAccounts(): void $this->context->smarty->assign('urlAccountsCdn', $accountsService->getAccountsCdn()); } catch (Exception $e) { $this->context->controller->errors[] = $e->getMessage(); + + $logger->error('Failed to load ps accounts CDN', [ + 'context' => [], + 'exceptions' => ExceptionUtility::getExceptions($e), + ]); } if ($moduleManager->isInstalled('ps_eventbus')) { @@ -182,6 +205,9 @@ public function postProcess() /** @var \Mollie\Builder\FormBuilder $settingsFormBuilder */ $settingsFormBuilder = $this->module->getService(\Mollie\Builder\FormBuilder::class); + /** @var Logger $logger * */ + $logger = $this->module->getService(LoggerInterface::class); + try { $html .= $settingsFormBuilder->buildSettingsForm(); } catch (PrestaShopDatabaseException $e) { diff --git a/controllers/front/ajax.php b/controllers/front/ajax.php index 5e222be7d..7f91675e0 100644 --- a/controllers/front/ajax.php +++ b/controllers/front/ajax.php @@ -16,10 +16,13 @@ use Mollie\Errors\Http\HttpStatusCode; use Mollie\Exception\FailedToProvidePaymentFeeException; use Mollie\Infrastructure\Response\JsonResponse; +use Mollie\Logger\Logger; +use Mollie\Logger\LoggerInterface; use Mollie\Provider\PaymentFeeProviderInterface; use Mollie\Shared\Core\Shared\Repository\CurrencyRepositoryInterface; use Mollie\Subscription\Exception\ExceptionCode; use Mollie\Subscription\Validator\CanProductBeAddedToCartValidator; +use Mollie\Utility\ExceptionUtility; use Mollie\Utility\NumberUtility; if (!defined('_PS_VERSION_')) { @@ -35,6 +38,11 @@ class MollieAjaxModuleFrontController extends AbstractMollieController public function postProcess(): void { + /** @var Logger $logger * */ + $logger = $this->module->getService(LoggerInterface::class); + + $logger->debug(sprintf('%s - Controller called', self::FILE_NAME)); + $action = Tools::getValue('action'); switch ($action) { @@ -47,6 +55,8 @@ public function postProcess(): void case 'validateProduct': $this->validateProduct(); } + + $logger->debug(sprintf('%s - Controller action ended', self::FILE_NAME)); } private function getTotalCartPrice(): void @@ -92,6 +102,9 @@ private function getTotalCartPrice(): void /** @var ConfigurationAdapter $configuration */ $configuration = $this->module->getService(ConfigurationAdapter::class); + /** @var Logger $logger * */ + $logger = $this->module->getService(LoggerInterface::class); + try { $paymentFeeData = $paymentFeeProvider->getPaymentFee($molPaymentMethod, (float) $cart->getOrderTotal()); } catch (FailedToProvidePaymentFeeException $exception) { @@ -100,6 +113,11 @@ private function getTotalCartPrice(): void 'message' => 'Failed to get payment fee data.', ]; + $logger->error('Failed to get payment fee data.', [ + 'context' => [], + 'exceptions' => ExceptionUtility::getExceptions($exception), + ]); + $this->returnDefaultOrderSummaryBlock($cart, $errorData); exit; @@ -190,6 +208,9 @@ private function validateProduct(): void /** @var CanProductBeAddedToCartValidator $canProductBeAddedToCartValidator */ $canProductBeAddedToCartValidator = $this->module->getService(CanProductBeAddedToCartValidator::class); + /** @var Logger $logger * */ + $logger = $this->module->getService(LoggerInterface::class); + $product = Tools::getValue('product'); try { @@ -213,6 +234,11 @@ private function validateProduct(): void $this->module->l('Unknown error. Try again or change the attribute to Subscription: none.', self::FILE_NAME), HttpStatusCode::HTTP_BAD_REQUEST )); + + $logger->error('Unknown error.', [ + 'context' => [], + 'exceptions' => ExceptionUtility::getExceptions($exception), + ]); } $this->ajaxResponse(JsonResponse::success([])); diff --git a/controllers/front/applePayDirectAjax.php b/controllers/front/applePayDirectAjax.php index d561f469a..3890099ca 100644 --- a/controllers/front/applePayDirectAjax.php +++ b/controllers/front/applePayDirectAjax.php @@ -20,6 +20,10 @@ use Mollie\Application\CommandHandler\UpdateApplePayShippingMethodHandler; use Mollie\Builder\ApplePayDirect\ApplePayOrderBuilder; use Mollie\Builder\ApplePayDirect\ApplePayProductBuilder; +use Mollie\Exception\FailedToProvidePaymentFeeException; +use Mollie\Logger\Logger; +use Mollie\Logger\LoggerInterface; +use Mollie\Utility\ExceptionUtility; use Mollie\Utility\OrderRecoverUtility; if (!defined('_PS_VERSION_')) { @@ -28,11 +32,17 @@ class MollieApplePayDirectAjaxModuleFrontController extends ModuleFrontController { + private const FILE_NAME = 'applePayDirectAjax'; /** @var Mollie */ public $module; public function postProcess() { + /** @var Logger $logger * */ + $logger = $this->module->getService(LoggerInterface::class); + + $logger->debug(sprintf('%s - Controller called', self::FILE_NAME)); + $action = Tools::getValue('action'); switch ($action) { case 'mollie_apple_pay_validation': @@ -50,6 +60,8 @@ public function postProcess() case 'mollie_apple_pay_get_total_price': $this->getTotalApplePayCartPrice(); } + + $logger->debug(sprintf('%s - Controller action ended', self::FILE_NAME)); } private function getApplePaySession() @@ -91,6 +103,8 @@ private function updateAppleShippingContact() $handler = $this->module->getService(UpdateApplePayShippingContactHandler::class); /** @var ApplePayProductBuilder $productBuilder */ $productBuilder = $this->module->getService(ApplePayProductBuilder::class); + /** @var Logger $logger * */ + $logger = $this->module->getService(LoggerInterface::class); $simplifiedContent = Tools::getValue('simplifiedContact'); $cartId = (int) Tools::getValue('cartId'); @@ -110,7 +124,23 @@ private function updateAppleShippingContact() $simplifiedContent['locality'], $customerId ); - $result = $handler->handle($command); + + try { + $result = $handler->handle($command); + } catch (FailedToProvidePaymentFeeException $e) { + $logger->error('Failed to find apple pay address.', [ + 'context' => [ + 'cartId' => $cartId, + 'customerId' => $customerId, + ], + 'exceptions' => ExceptionUtility::getExceptions($e), + ]); + + $result = [ + 'success' => false, + 'message' => $this->module->l('Failed to find address. Please try again. CartId ' . $cartId, self::FILE_NAME), + ]; + } $this->ajaxDie(json_encode($result)); } diff --git a/controllers/front/bancontactAjax.php b/controllers/front/bancontactAjax.php index 3cfdb68bd..1fa1f1e6e 100644 --- a/controllers/front/bancontactAjax.php +++ b/controllers/front/bancontactAjax.php @@ -15,6 +15,8 @@ use Mollie\Exception\OrderCreationException; use Mollie\Exception\RetryOverException; use Mollie\Handler\RetryHandlerInterface; +use Mollie\Logger\Logger; +use Mollie\Logger\LoggerInterface; use Mollie\Repository\PaymentMethodRepositoryInterface; use Mollie\Service\PaymentMethodService; use Mollie\Utility\OrderNumberUtility; @@ -26,11 +28,18 @@ class MollieBancontactAjaxModuleFrontController extends ModuleFrontController { + private const FILE_NAME = 'bancontactAjax'; + /** @var Mollie */ public $module; public function postProcess() { + /** @var Logger $logger * */ + $logger = $this->module->getService(LoggerInterface::class); + + $logger->debug(sprintf('%s - Controller called', self::FILE_NAME)); + $action = Tools::getValue('action'); switch ($action) { case 'createTransaction': @@ -39,6 +48,8 @@ public function postProcess() case 'checkForPaidTransaction': $this->checkForPaidTransaction(); } + + $logger->debug(sprintf('%s - Controller action ended', self::FILE_NAME)); } private function createTransaction() diff --git a/controllers/front/fail.php b/controllers/front/fail.php index 291bfd6d5..89c1eb533 100644 --- a/controllers/front/fail.php +++ b/controllers/front/fail.php @@ -10,6 +10,8 @@ * @codingStandardsIgnoreStart */ +use Mollie\Logger\Logger; +use Mollie\Logger\LoggerInterface; use PrestaShop\PrestaShop\Adapter\Order\OrderPresenter; if (!defined('_PS_VERSION_')) { @@ -18,6 +20,8 @@ class MollieFailModuleFrontController extends ModuleFrontController { + public const FILE_NAME = 'fail'; + /** * ID Order Variable Declaration. * @@ -48,10 +52,18 @@ class MollieFailModuleFrontController extends ModuleFrontController */ private $order_presenter; + /** @var Mollie */ + public $module; + public function init() { parent::init(); + /** @var Logger $logger * */ + $logger = $this->module->getService(LoggerInterface::class); + + $logger->debug(sprintf('%s - Controller called', self::FILE_NAME)); + $this->id_cart = (int) Tools::getValue('cartId', 0); $redirectLink = 'index.php?controller=history'; @@ -78,6 +90,8 @@ public function init() } /* @phpstan-ignore-next-line */ $this->order_presenter = new OrderPresenter(); + + $logger->debug(sprintf('%s - Controller action ended', self::FILE_NAME)); } public function initContent() diff --git a/controllers/front/payScreen.php b/controllers/front/payScreen.php index ec651118c..7709f176e 100644 --- a/controllers/front/payScreen.php +++ b/controllers/front/payScreen.php @@ -11,6 +11,8 @@ */ use Mollie\Api\Types\PaymentMethod; +use Mollie\Logger\Logger; +use Mollie\Logger\LoggerInterface; use Mollie\Provider\ProfileIdProviderInterface; if (!defined('_PS_VERSION_')) { @@ -19,11 +21,18 @@ class MolliePayScreenModuleFrontController extends ModuleFrontController { + public const FILE_NAME = 'payScreen'; + /** @var Mollie */ public $module; public function postProcess() { + /** @var Logger $logger * */ + $logger = $this->module->getService(LoggerInterface::class); + + $logger->debug(sprintf('%s - Controller called', self::FILE_NAME)); + $cardToken = Tools::getValue('mollieCardToken'); $isSaveCard = (bool) Tools::getValue('mollieSaveCard'); $useSavedCard = (bool) Tools::getValue('mollieUseSavedCard'); @@ -41,6 +50,8 @@ public function postProcess() true ); + $logger->debug(sprintf('%s - Controller action ended', self::FILE_NAME)); + Tools::redirect($validateUrl); } diff --git a/controllers/front/payment.php b/controllers/front/payment.php index 3425c13fe..ad45cc624 100644 --- a/controllers/front/payment.php +++ b/controllers/front/payment.php @@ -13,11 +13,14 @@ use Mollie\Api\Types\PaymentMethod; use Mollie\Exception\OrderCreationException; use Mollie\Handler\Order\OrderCreationHandler; +use Mollie\Logger\Logger; +use Mollie\Logger\LoggerInterface; use Mollie\Repository\PaymentMethodRepositoryInterface; use Mollie\Service\ExceptionService; use Mollie\Service\MollieOrderCreationService; use Mollie\Service\PaymentMethodService; use Mollie\Subscription\Validator\SubscriptionOrderValidator; +use Mollie\Utility\ExceptionUtility; use Mollie\Utility\OrderNumberUtility; if (!defined('_PS_VERSION_')) { @@ -52,6 +55,12 @@ class MolliePaymentModuleFrontController extends ModuleFrontController public function initContent() { parent::initContent(); + + /** @var Logger $logger * */ + $logger = $this->module->getService(LoggerInterface::class); + + $logger->debug(sprintf('%s - Controller called', self::FILE_NAME)); + /** @var Cart $cart */ $cart = $this->context->cart; $customer = new Customer($cart->id_customer); @@ -133,6 +142,11 @@ public function initContent() } $this->errors[] = $message; + $logger->error('An error occurred when creating mollie payment', [ + 'context' => [], + 'exceptions' => ExceptionUtility::getExceptions($e), + ]); + return false; } catch (PrestaShopException $e) { $this->setTemplate('error.tpl'); @@ -140,6 +154,11 @@ public function initContent() ? $e->getMessage() . ' Cart Dump: ' . json_encode($paymentData, JSON_PRETTY_PRINT) : $this->module->l('An error occurred when creating your payment. Contact customer support.', self::FILE_NAME); + $logger->error('An error occurred when creating payment', [ + 'context' => [], + 'exceptions' => ExceptionUtility::getExceptions($e), + ]); + return false; } @@ -163,9 +182,16 @@ public function initContent() $this->setTemplate('error.tpl'); $this->errors[] = $this->module->l('Failed to save order information.', self::FILE_NAME); + $logger->error('Failed to save order information.', [ + 'context' => [], + 'exceptions' => ExceptionUtility::getExceptions($e), + ]); + return false; } + $logger->debug(sprintf('%s - Controller action ended', self::FILE_NAME)); + // Go to payment url if (null !== $apiPayment->getCheckoutUrl()) { Tools::redirect($apiPayment->getCheckoutUrl()); diff --git a/controllers/front/recurringOrderDetail.php b/controllers/front/recurringOrderDetail.php index 610f28a17..cd9163a57 100644 --- a/controllers/front/recurringOrderDetail.php +++ b/controllers/front/recurringOrderDetail.php @@ -11,11 +11,13 @@ */ use Mollie\Controller\AbstractMollieController; -use Mollie\Logger\PrestaLoggerInterface; +use Mollie\Logger\Logger; +use Mollie\Logger\LoggerInterface; use Mollie\Subscription\Handler\FreeOrderCreationHandler; use Mollie\Subscription\Handler\SubscriptionCancellationHandler; use Mollie\Subscription\Presenter\RecurringOrderPresenter; use Mollie\Subscription\Repository\RecurringOrderRepositoryInterface; +use Mollie\Utility\ExceptionUtility; if (!defined('_PS_VERSION_')) { exit; @@ -37,6 +39,11 @@ class MollieRecurringOrderDetailModuleFrontController extends AbstractMollieCont */ public function postProcess() { + /** @var Logger $logger * */ + $logger = $this->module->getService(LoggerInterface::class); + + $logger->debug(sprintf('%s - Controller called', self::FILE_NAME)); + if (Tools::isSubmit('submitUpdatePaymentMethod')) { $this->updatePaymentMethod(); } @@ -44,6 +51,8 @@ public function postProcess() if (Tools::isSubmit('submitCancelSubscriptionMethod')) { $this->cancelSubscription(); } + + $logger->debug(sprintf('%s - Controller action ended', self::FILE_NAME)); } /** @@ -53,6 +62,9 @@ public function postProcess() */ public function initContent() { + /** @var Logger $logger * */ + $logger = $this->module->getService(LoggerInterface::class); + $recurringOrderId = (int) Tools::getValue('id_mol_recurring_order'); $recurringOrderId = Validate::isUnsignedId($recurringOrderId) ? $recurringOrderId : false; @@ -67,7 +79,10 @@ public function initContent() 'id_mol_recurring_order' => $recurringOrderId, ]); } catch (\Throwable $exception) { - // TODO add notification about data retrieve failure + $logger->error('Data retrieve failure', [ + 'context' => [], + 'exceptions' => ExceptionUtility::getExceptions($exception), + ]); Tools::redirect($failureRedirectUrl); @@ -80,8 +95,8 @@ public function initContent() return; } - /** @var PrestaLoggerInterface $logger */ - $logger = $this->module->getService(PrestaLoggerInterface::class); + /** @var Logger $logger */ + $logger = $this->module->getService(LoggerInterface::class); /** @var RecurringOrderPresenter $recurringOrderPresenter */ $recurringOrderPresenter = $this->module->getService(RecurringOrderPresenter::class); @@ -93,8 +108,8 @@ public function initContent() ]); } catch (Throwable $exception) { $logger->error('Failed to present subscription order', [ - 'Exception message' => $exception->getMessage(), - 'Exception code' => $exception->getCode(), + 'context' => [], + 'exceptions' => ExceptionUtility::getExceptions($exception), ]); Tools::redirect($failureRedirectUrl); diff --git a/controllers/front/return.php b/controllers/front/return.php index 0fb44e7f6..d5c664310 100644 --- a/controllers/front/return.php +++ b/controllers/front/return.php @@ -15,6 +15,8 @@ use Mollie\Config\Config; use Mollie\Controller\AbstractMollieController; use Mollie\Factory\CustomerFactory; +use Mollie\Logger\Logger; +use Mollie\Logger\LoggerInterface; use Mollie\Repository\PaymentMethodRepository; use Mollie\Service\PaymentReturnService; use Mollie\Utility\ArrayUtility; @@ -48,6 +50,11 @@ class MollieReturnModuleFrontController extends AbstractMollieController */ public function initContent() { + /** @var Logger $logger * */ + $logger = $this->module->getService(LoggerInterface::class); + + $logger->debug(sprintf('%s - Controller called', self::FILE_NAME)); + $idCart = (int) Tools::getValue('cart_id'); $key = Tools::getValue('key'); $orderNumber = Tools::getValue('order_number'); @@ -139,6 +146,8 @@ public function initContent() } else { $this->setTemplate('mollie_return.tpl'); } + + $logger->debug(sprintf('%s - Controller action ended', self::FILE_NAME)); } /** diff --git a/controllers/front/subscriptionUpdateWebhook.php b/controllers/front/subscriptionUpdateWebhook.php index 704434d0a..e6a3ec1b8 100644 --- a/controllers/front/subscriptionUpdateWebhook.php +++ b/controllers/front/subscriptionUpdateWebhook.php @@ -15,7 +15,8 @@ use Mollie\Errors\Http\HttpStatusCode; use Mollie\Handler\ErrorHandler\ErrorHandler; use Mollie\Infrastructure\Response\JsonResponse; -use Mollie\Logger\PrestaLoggerInterface; +use Mollie\Logger\Logger; +use Mollie\Logger\LoggerInterface; use Mollie\Subscription\Handler\SubscriptionPaymentMethodUpdateHandler; if (!defined('_PS_VERSION_')) { @@ -46,8 +47,10 @@ protected function displayMaintenancePage() public function initContent() { - /** @var PrestaLoggerInterface $logger */ - $logger = $this->module->getService(PrestaLoggerInterface::class); + /** @var Logger $logger * */ + $logger = $this->module->getService(LoggerInterface::class); + + $logger->debug(sprintf('%s - Controller called', self::FILE_NAME)); /** @var ErrorHandler $errorHandler */ $errorHandler = $this->module->getService(ErrorHandler::class); @@ -110,11 +113,6 @@ public function initContent() try { $subscriptionPaymentMethodUpdateHandler->handle($transactionId, $subscriptionId); } catch (\Throwable $exception) { - $logger->error('Failed to handle subscription update', [ - 'Exception message' => $exception->getMessage(), - 'Exception code' => $exception->getCode(), - ]); - $errorHandler->handle($exception, null, false); $this->releaseLock(); @@ -127,7 +125,7 @@ public function initContent() $this->releaseLock(); - $logger->info(sprintf('%s - Controller action ended', self::FILE_NAME)); + $logger->debug(sprintf('%s - Controller action ended', self::FILE_NAME)); $this->ajaxResponse(JsonResponse::success([])); } diff --git a/controllers/front/subscriptionWebhook.php b/controllers/front/subscriptionWebhook.php index 1c524a507..15be1c3a9 100644 --- a/controllers/front/subscriptionWebhook.php +++ b/controllers/front/subscriptionWebhook.php @@ -15,7 +15,8 @@ use Mollie\Errors\Http\HttpStatusCode; use Mollie\Handler\ErrorHandler\ErrorHandler; use Mollie\Infrastructure\Response\JsonResponse; -use Mollie\Logger\PrestaLoggerInterface; +use Mollie\Logger\Logger; +use Mollie\Logger\LoggerInterface; use Mollie\Subscription\Handler\RecurringOrderHandler; if (!defined('_PS_VERSION_')) { @@ -46,8 +47,10 @@ protected function displayMaintenancePage() public function initContent() { - /** @var PrestaLoggerInterface $logger */ - $logger = $this->module->getService(PrestaLoggerInterface::class); + /** @var Logger $logger * */ + $logger = $this->module->getService(LoggerInterface::class); + + $logger->debug(sprintf('%s - Controller called', self::FILE_NAME)); /** @var ErrorHandler $errorHandler */ $errorHandler = $this->module->getService(ErrorHandler::class); @@ -98,11 +101,6 @@ public function initContent() try { $recurringOrderHandler->handle($transactionId); } catch (\Throwable $exception) { - $logger->error('Failed to handle recurring order', [ - 'Exception message' => $exception->getMessage(), - 'Exception code' => $exception->getCode(), - ]); - $errorHandler->handle($exception, null, false); $this->releaseLock(); @@ -115,7 +113,7 @@ public function initContent() $this->releaseLock(); - $logger->info(sprintf('%s - Controller action ended', self::FILE_NAME)); + $logger->debug(sprintf('%s - Controller action ended', self::FILE_NAME)); $this->ajaxResponse(JsonResponse::success([])); } diff --git a/controllers/front/subscriptions.php b/controllers/front/subscriptions.php index 3ad31e3fc..6dc1dcd34 100644 --- a/controllers/front/subscriptions.php +++ b/controllers/front/subscriptions.php @@ -10,6 +10,8 @@ * @codingStandardsIgnoreStart */ +use Mollie\Logger\Logger; +use Mollie\Logger\LoggerInterface; use Mollie\Repository\MolCustomerRepositoryInterface; use Mollie\Subscription\Presenter\RecurringOrdersPresenter; @@ -38,6 +40,8 @@ class mollieSubscriptionsModuleFrontController extends ModuleFrontController { + private const FILE_NAME = 'subscriptions'; + /** * @var Mollie */ @@ -54,6 +58,11 @@ class mollieSubscriptionsModuleFrontController extends ModuleFrontController public function initContent() { + /** @var Logger $logger * */ + $logger = $this->module->getService(LoggerInterface::class); + + $logger->debug(sprintf('%s - Controller called', self::FILE_NAME)); + $this->display_column_right = false; $this->display_column_left = false; @@ -75,6 +84,8 @@ public function initContent() $this->prepareTemplate( $molCustomer ? $recurringOrdersPresenter->present($molCustomer->customer_id) : [] ); + + $logger->debug(sprintf('%s - Controller action ended', self::FILE_NAME)); } public function setMedia() diff --git a/controllers/front/webhook.php b/controllers/front/webhook.php index abca3b115..b298395f0 100644 --- a/controllers/front/webhook.php +++ b/controllers/front/webhook.php @@ -17,7 +17,8 @@ use Mollie\Exception\TransactionException; use Mollie\Handler\ErrorHandler\ErrorHandler; use Mollie\Infrastructure\Response\JsonResponse; -use Mollie\Logger\PrestaLoggerInterface; +use Mollie\Logger\Logger; +use Mollie\Logger\LoggerInterface; use Mollie\Service\TransactionService; use Mollie\Utility\TransactionUtility; @@ -49,14 +50,14 @@ protected function displayMaintenancePage() public function initContent(): void { - /** @var PrestaLoggerInterface $logger */ - $logger = $this->module->getService(PrestaLoggerInterface::class); + /** @var Logger $logger * */ + $logger = $this->module->getService(LoggerInterface::class); + + $logger->debug(sprintf('%s - Controller called', self::FILE_NAME)); /** @var ToolsAdapter $tools */ $tools = $this->module->getService(ToolsAdapter::class); - $logger->info(sprintf('%s - Controller called', self::FILE_NAME)); - if (!$this->module->getApiClient()) { $logger->error(sprintf('Unauthorized in %s', self::FILE_NAME)); @@ -104,7 +105,7 @@ public function initContent(): void $this->releaseLock(); - $logger->info(sprintf('%s - Controller action ended', self::FILE_NAME)); + $logger->debug(sprintf('%s - Controller action ended', self::FILE_NAME)); $this->ajaxResponse(JsonResponse::success([])); } @@ -117,6 +118,9 @@ protected function executeWebhook(string $transactionId): void /** @var TransactionService $transactionService */ $transactionService = $this->module->getService(TransactionService::class); + /** @var Logger $logger * */ + $logger = $this->module->getService(LoggerInterface::class); + if (TransactionUtility::isOrderTransaction($transactionId)) { $transaction = $this->module->getApiClient()->orders->get($transactionId, ['embed' => 'payments']); } else { @@ -131,6 +135,7 @@ protected function executeWebhook(string $transactionId): void if (!$cartId) { // TODO webhook structure will change, no need to create custom exception for one time usage + $logger->error(sprintf('Missing Cart ID. Transaction ID: [%s]', $transactionId)); throw new \Exception(sprintf('Missing Cart ID. Transaction ID: [%s]', $transactionId), HttpStatusCode::HTTP_NOT_FOUND); } @@ -152,17 +157,9 @@ private function setContext(int $cartId): void private function handleException(Throwable $exception, int $httpStatusCode, string $logMessage): void { - /** @var PrestaLoggerInterface $logger */ - $logger = $this->module->getService(PrestaLoggerInterface::class); - /** @var ErrorHandler $errorHandler */ $errorHandler = $this->module->getService(ErrorHandler::class); - $logger->error($logMessage, [ - 'Exception message' => $exception->getMessage(), - 'Exception code' => $httpStatusCode, - ]); - $errorHandler->handle($exception, $httpStatusCode, false); $this->releaseLock(); $this->ajaxResponse(JsonResponse::error( diff --git a/mollie.php b/mollie.php index 21621619f..57969e2a2 100755 --- a/mollie.php +++ b/mollie.php @@ -74,6 +74,11 @@ class Mollie extends PaymentModule const ADMIN_MOLLIE_SUBSCRIPTION_ORDERS_CONTROLLER = 'AdminMollieSubscriptionOrders'; const ADMIN_MOLLIE_SUBSCRIPTION_FAQ_PARENT_CONTROLLER = 'AdminMollieSubscriptionFAQParent'; const ADMIN_MOLLIE_SUBSCRIPTION_FAQ_CONTROLLER = 'AdminMollieSubscriptionFAQ'; + + const ADMIN_MOLLIE_LOGS_CONTROLLER = 'AdminMollieLogs'; + + const ADMIN_MOLLIE_LOGS_PARENT_CONTROLLER = 'AdminMollieLogsParent'; + /** @var LeagueServiceContainerProvider */ private $containerProvider; @@ -84,7 +89,7 @@ public function __construct() { $this->name = 'mollie'; $this->tab = 'payments_gateways'; - $this->version = '6.2.2'; + $this->version = '6.2.3'; $this->author = 'Mollie B.V.'; $this->need_instance = 1; $this->bootstrap = true; @@ -865,6 +870,18 @@ public function getTabs() 'parent_class_name' => self::ADMIN_MOLLIE_TAB_CONTROLLER, 'module_tab' => true, ], + [ + 'name' => $this->l('Logs'), + 'class_name' => self::ADMIN_MOLLIE_LOGS_PARENT_CONTROLLER, + 'parent_class_name' => self::ADMIN_MOLLIE_CONTROLLER, + 'module_tab' => true, + ], + [ + 'name' => $this->l('Logs'), + 'class_name' => self::ADMIN_MOLLIE_LOGS_CONTROLLER, + 'parent_class_name' => self::ADMIN_MOLLIE_TAB_CONTROLLER, + 'module_tab' => true, + ], ]; } diff --git a/src/Adapter/ConfigurationAdapter.php b/src/Adapter/ConfigurationAdapter.php index 73cd185a7..bac043b55 100644 --- a/src/Adapter/ConfigurationAdapter.php +++ b/src/Adapter/ConfigurationAdapter.php @@ -74,6 +74,17 @@ public function delete($key): void \Configuration::deleteByName($this->parseKeyByEnvironment($key)); } + public function getAsInteger($id, ?int $shopId = null) + { + $result = $this->get($id, $shopId); + + if (in_array($result, ['null', 'false', '0', null, false, 0], true)) { + return 0; + } + + return (int) $result; + } + /** * @param string|array{production: string, sandbox: string} $key */ diff --git a/src/Adapter/Context.php b/src/Adapter/Context.php index a83249315..e9df2691b 100644 --- a/src/Adapter/Context.php +++ b/src/Adapter/Context.php @@ -135,6 +135,16 @@ public function getShopGroupId(): int return (int) PrestashopContext::getContext()->shop->id_shop_group; } + public function getShopThemeName(): string + { + return PrestashopContext::getContext()->shop->theme_name; + } + + public function getShopName(): string + { + return PrestashopContext::getContext()->shop->name; + } + public function formatPrice(float $price, string $isoCode): string { $locale = PrestashopContext::getContext()->getCurrentLocale(); diff --git a/src/Adapter/ToolsAdapter.php b/src/Adapter/ToolsAdapter.php index 436f5a315..91adbfc11 100644 --- a/src/Adapter/ToolsAdapter.php +++ b/src/Adapter/ToolsAdapter.php @@ -47,4 +47,9 @@ public function isSubmit(string $string): bool { return (bool) Tools::isSubmit($string); } + + public function getValueAsInt($value, $defaultValue = 0) + { + return (int) Tools::getValue($value, $defaultValue); + } } diff --git a/src/Application/CommandHandler/UpdateApplePayShippingContactHandler.php b/src/Application/CommandHandler/UpdateApplePayShippingContactHandler.php index e51f41424..1f0f64a0d 100644 --- a/src/Application/CommandHandler/UpdateApplePayShippingContactHandler.php +++ b/src/Application/CommandHandler/UpdateApplePayShippingContactHandler.php @@ -60,7 +60,7 @@ public function handle(UpdateApplePayShippingContact $command): array $invoiceAddress = $this->createAddress($customer->id, $command); $cart = $this->updateCart($customer, $deliveryAddress->id, $invoiceAddress->id, $command->getCartId()); $this->addProductToCart($cart, $command); - + $this->updateContext($cart, $customer); $country = new Country($deliveryAddress->id_country); $applePayCarriers = $this->applePayCarriersBuilder->build(Carrier::getCarriersForOrder($country->id_zone), $country->id_zone); @@ -142,4 +142,11 @@ private function addProductToCart(Cart $cart, UpdateApplePayShippingContact $com $cart->updateQty($product->getWantedQuantity(), $product->getProductId(), $product->getProductAttribute()); } } + + private function updateContext(Cart $cart, Customer $customer) + { + $context = \Context::getContext(); + $context->cart = $cart; + \Context::getContext()->updateCustomer($customer); + } } diff --git a/src/Config/Config.php b/src/Config/Config.php index 946946d57..7bb76294f 100644 --- a/src/Config/Config.php +++ b/src/Config/Config.php @@ -282,7 +282,6 @@ class Config ]; const PAYMENT_API_ONLY_METHODS = [ - PaymentMethod::ALMA, ]; const ROUTE_RESEND_SECOND_CHANCE_PAYMENT_MESSAGE = 'mollie_module_admin_resend_payment_message'; @@ -330,6 +329,11 @@ class Config 'trustly' => 'Trustly', ]; + public const LOG_SEVERITY_LEVEL_INFORMATIVE = 1; + public const LOG_SEVERITY_LEVEL_WARNING = 2; + public const LOG_SEVERITY_LEVEL_ERROR = 3; + public const LOG_SEVERITY_LEVEL_MAJOR = 4; + const MOLLIE_BUTTON_ORDER_TOTAL_REFRESH = 'MOLLIE_BUTTON_ORDER_TOTAL_REFRESH'; // TODO migrate functions below to separate service diff --git a/src/Controller/AbstractMollieController.php b/src/Controller/AbstractMollieController.php index d73234035..bec2c1547 100644 --- a/src/Controller/AbstractMollieController.php +++ b/src/Controller/AbstractMollieController.php @@ -16,7 +16,9 @@ use Mollie\Infrastructure\Adapter\Lock; use Mollie\Infrastructure\Response\JsonResponse; use Mollie\Infrastructure\Response\Response; -use Mollie\Logger\PrestaLoggerInterface; +use Mollie\Logger\Logger; +use Mollie\Logger\LoggerInterface; +use Mollie\Utility\ExceptionUtility; if (!defined('_PS_VERSION_')) { exit; @@ -62,8 +64,8 @@ protected function ajaxRender($value = null, $controller = null, $method = null) protected function ajaxResponse($value, $controller = null, $method = null): void { - /** @var PrestaLoggerInterface $logger */ - $logger = $this->module->getService(PrestaLoggerInterface::class); + /** @var Logger $logger */ + $logger = $this->module->getService(LoggerInterface::class); if ($value instanceof JsonResponse) { if ($value->getStatusCode() === JsonResponse::HTTP_INTERNAL_SERVER_ERROR) { @@ -83,9 +85,8 @@ protected function ajaxResponse($value, $controller = null, $method = null): voi $this->ajaxRender($value, $controller, $method); } catch (\Throwable $exception) { $logger->error('Could not return ajax response', [ - 'response' => json_encode($value ?: []), - 'Exception message' => $exception->getMessage(), - 'Exception code' => $exception->getCode(), + 'context' => [], + 'exceptions' => ExceptionUtility::getExceptions($exception), ]); } @@ -94,15 +95,15 @@ protected function ajaxResponse($value, $controller = null, $method = null): voi protected function applyLock(string $resource): Response { - /** @var PrestaLoggerInterface $logger */ - $logger = $this->module->getService(PrestaLoggerInterface::class); + /** @var Logger $logger */ + $logger = $this->module->getService(LoggerInterface::class); try { $this->lock->create($resource); if (!$this->lock->acquire()) { $logger->error('Lock resource conflict', [ - 'resource' => $resource, + 'context' => [], ]); return Response::respond( @@ -112,8 +113,8 @@ protected function applyLock(string $resource): Response } } catch (\Throwable $exception) { $logger->error('Failed to lock process', [ - 'Exception message' => $exception->getMessage(), - 'Exception code' => $exception->getCode(), + 'context' => [], + 'exceptions' => ExceptionUtility::getExceptions($exception), ]); return Response::respond( @@ -130,15 +131,15 @@ protected function applyLock(string $resource): Response protected function releaseLock(): void { - /** @var PrestaLoggerInterface $logger */ - $logger = $this->module->getService(PrestaLoggerInterface::class); + /** @var Logger $logger */ + $logger = $this->module->getService(LoggerInterface::class); try { $this->lock->release(); } catch (\Throwable $exception) { $logger->error('Failed to release process', [ - 'Exception message' => $exception->getMessage(), - 'Exception code' => $exception->getCode(), + 'context' => [], + 'exceptions' => ExceptionUtility::getExceptions($exception), ]); } } diff --git a/src/DTO/OrderData.php b/src/DTO/OrderData.php index ebb19ef8d..9c013bade 100644 --- a/src/DTO/OrderData.php +++ b/src/DTO/OrderData.php @@ -433,7 +433,7 @@ public function jsonSerialize() 'familyName' => $this->cleanUpInput($this->getBillingAddress()->lastname), 'email' => $this->cleanUpInput($this->getEmail()), 'title' => $this->cleanUpInput($this->getTitle()), - 'phone' => $this->cleanUpInput($this->getBillingPhoneNumber()), + 'phone' => $this->getBillingPhoneNumber(), ], 'shippingAddress' => [ 'organizationName' => $this->cleanUpInput($this->getShippingAddress()->company), @@ -446,7 +446,7 @@ public function jsonSerialize() 'familyName' => $this->cleanUpInput($this->getShippingAddress()->lastname), 'email' => $this->cleanUpInput($this->getEmail()), 'title' => $this->cleanUpInput($this->getTitle()), - 'phone' => $this->cleanUpInput($this->getDeliveryPhoneNumber()), + 'phone' => $this->getDeliveryPhoneNumber(), ], 'redirectUrl' => $this->getRedirectUrl(), 'webhookUrl' => $this->getWebhookUrl(), diff --git a/src/DTO/PaymentData.php b/src/DTO/PaymentData.php index 68d00f2d1..513f5dc42 100644 --- a/src/DTO/PaymentData.php +++ b/src/DTO/PaymentData.php @@ -101,6 +101,11 @@ class PaymentData implements JsonSerializable */ private $subscriptionOrder = false; + /** + * @var string + */ + private $email; + public function __construct( Amount $amount, $description, @@ -339,6 +344,22 @@ public function setSubscriptionOrder(bool $subscriptionOrder): void $this->subscriptionOrder = $subscriptionOrder; } + /** + * @return string + */ + public function getEmail() + { + return $this->email; + } + + /** + * @param string $email + */ + public function setEmail($email) + { + $this->email = $email; + } + public function jsonSerialize() { $result = [ @@ -347,6 +368,9 @@ public function jsonSerialize() 'value' => (string) $this->getAmount()->getValue(), ], 'billingAddress' => [ + 'givenName' => $this->cleanUpInput($this->getBillingAddress()->firstname), + 'familyName' => $this->cleanUpInput($this->getBillingAddress()->lastname), + 'email' => $this->cleanUpInput($this->getEmail()), 'streetAndNumber' => $this->cleanUpInput($this->getBillingAddress()->address1), 'streetAdditional' => $this->cleanUpInput($this->getBillingAddress()->address2, null), 'city' => $this->cleanUpInput($this->getBillingAddress()->city), @@ -354,6 +378,9 @@ public function jsonSerialize() 'country' => $this->cleanUpInput(Country::getIsoById($this->getBillingAddress()->id_country)), ], 'shippingAddress' => [ + 'givenName' => $this->cleanUpInput($this->getBillingAddress()->firstname), + 'familyName' => $this->cleanUpInput($this->getBillingAddress()->lastname), + 'email' => $this->cleanUpInput($this->getEmail()), 'streetAndNumber' => $this->cleanUpInput($this->getShippingAddress()->address1), 'streetAdditional' => $this->cleanUpInput($this->getShippingAddress()->address2, null), 'city' => $this->cleanUpInput($this->getShippingAddress()->city), diff --git a/src/Entity/MolLog.php b/src/Entity/MolLog.php new file mode 100644 index 000000000..4e6b6a362 --- /dev/null +++ b/src/Entity/MolLog.php @@ -0,0 +1,44 @@ + + * @copyright Mollie B.V. + * @license https://github.com/mollie/PrestaShop/blob/master/LICENSE.md + * + * @see https://github.com/mollie/PrestaShop + * @codingStandardsIgnoreStart + */ +if (!defined('_PS_VERSION_')) { + exit; +} + +class MolLog extends ObjectModel +{ + public $id_mollie_log; + + public $id_log; + + public $id_shop; + + public $request; + + public $response; + + public $context; + + public $date_add; + + public static $definition = [ + 'table' => 'mol_logs', + 'primary' => 'id_mollie_log', + 'fields' => [ + '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/Entity/ObjectModelEntityManager.php b/src/Entity/ObjectModelEntityManager.php new file mode 100644 index 000000000..02483b9c4 --- /dev/null +++ b/src/Entity/ObjectModelEntityManager.php @@ -0,0 +1,75 @@ + + * @copyright Mollie B.V. + * @license https://github.com/mollie/PrestaShop/blob/master/LICENSE.md + * + * @see https://github.com/mollie/PrestaShop + * @codingStandardsIgnoreStart + */ + +use Mollie\Service\EntityManager\EntityManagerInterface; + +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, + string $unitOfWorkType, + ?string $specificKey = null + ): EntityManagerInterface { + $this->unitOfWork->setWork($model, $unitOfWorkType, $specificKey); + + return $this; + } + + /** + * @return array<\ObjectModel> + * + * @throws \PrestaShopDatabaseException + * @throws \PrestaShopException + */ + public function flush(): array + { + $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/Entity/ObjectModelUnitOfWork.php b/src/Entity/ObjectModelUnitOfWork.php new file mode 100644 index 000000000..95a49cbe7 --- /dev/null +++ b/src/Entity/ObjectModelUnitOfWork.php @@ -0,0 +1,50 @@ + + * @copyright Mollie B.V. + * @license https://github.com/mollie/PrestaShop/blob/master/LICENSE.md + * + * @see https://github.com/mollie/PrestaShop + * @codingStandardsIgnoreStart + */ +if (!defined('_PS_VERSION_')) { + exit; +} + +/** In memory entity manager object model unit of work */ +class ObjectModelUnitOfWork +{ + public const UNIT_OF_WORK_SAVE = 'UNIT_OF_WORK_SAVE'; + public const UNIT_OF_WORK_DELETE = 'UNIT_OF_WORK_DELETE'; + + private $work = []; + + public function setWork(ObjectModel $objectModel, string $unitOfWorkType, ?string $specificKey = null): void + { + $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(): array + { + return $this->work; + } + + public function clearWork(): void + { + $this->work = []; + } +} diff --git a/src/Handler/ErrorHandler/ErrorHandler.php b/src/Handler/ErrorHandler/ErrorHandler.php index a8b1b8e0f..d9da002a7 100644 --- a/src/Handler/ErrorHandler/ErrorHandler.php +++ b/src/Handler/ErrorHandler/ErrorHandler.php @@ -17,6 +17,9 @@ use Mollie\Config\Config; use Mollie\Config\Env; use Mollie\Factory\ModuleFactory; +use Mollie\Logger\Logger; +use Mollie\Logger\LoggerInterface; +use Mollie\Utility\ExceptionUtility; use Sentry\ClientBuilder; use Sentry\ClientInterface; use Sentry\SentrySdk; @@ -39,9 +42,15 @@ class ErrorHandler /** @var Scope */ private $exceptionContext; + /** + * @var Mollie + */ + private $module; public function __construct(Mollie $module, Env $env = null) { + $this->module = $module; + /* We need to add this check and make env = null because when upgrading module the old constructor logic is called, and it breaks upgrade */ if (!$env || !class_exists('Sentry\ClientBuilder')) { return; @@ -101,6 +110,16 @@ public function __construct(Mollie $module, Env $env = null) */ public function handle(\Throwable $error, ?int $code = null, ?bool $throw = true): void { + if ((int) Configuration::get(Config::MOLLIE_DEBUG_LOG) === Config::DEBUG_LOG_ERRORS) { + /** @var Logger $logger * */ + $logger = $this->module->getService(LoggerInterface::class); + + $logger->error($error->getMessage(), [ + 'context' => [], + 'exceptions' => ExceptionUtility::getExceptions($error), + ]); + } + $this->client->captureException($error, $this->exceptionContext); if ($code && true === $throw) { diff --git a/src/Install/DatabaseTableInstaller.php b/src/Install/DatabaseTableInstaller.php index efeff8aae..6489402c9 100644 --- a/src/Install/DatabaseTableInstaller.php +++ b/src/Install/DatabaseTableInstaller.php @@ -138,6 +138,19 @@ private function getCommands() ) ENGINE=' . _MYSQL_ENGINE_ . ' DEFAULT CHARSET=utf8; '; + $sql[] = ' + CREATE TABLE IF NOT EXISTS `' . _DB_PREFIX_ . 'mol_logs` ( + `id_mollie_log` INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, + `id_log` INT(11), + `id_shop` INT(11), + `request` TEXT, + `response` TEXT, + `context` TEXT, + `date_add` DATETIME NOT NULL, + INDEX (`id_log`), + INDEX (`id_shop`) + ) ENGINE=' . _MYSQL_ENGINE_ . ' DEFAULT CHARSET=utf8;'; + return $sql; } diff --git a/src/Install/OrderStateInstaller.php b/src/Install/OrderStateInstaller.php index 5dd1e4c0a..58123f5be 100644 --- a/src/Install/OrderStateInstaller.php +++ b/src/Install/OrderStateInstaller.php @@ -155,6 +155,8 @@ private function enableState(string $key): void $existingStateId = (int) $this->configurationAdapter->get($key); $orderState = new OrderState($existingStateId); + $this->updateStateConfiguration($key, $orderState); + if ((bool) !$orderState->deleted) { return; } @@ -202,6 +204,9 @@ private function createOrderState(OrderStateData $orderStateInstallerData): Orde private function updateStateConfiguration(string $key, OrderState $orderState): void { - $this->configurationAdapter->updateValue($key, (int) $orderState->id); + $shops = \Shop::getShops(); + foreach ($shops as $shop) { + $this->configurationAdapter->updateValue($key, (int) $orderState->id, false, null, (int) $shop['id_shop']); + } } } diff --git a/src/Logger/LogFormatter.php b/src/Logger/LogFormatter.php new file mode 100644 index 000000000..e19009def --- /dev/null +++ b/src/Logger/LogFormatter.php @@ -0,0 +1,27 @@ + + * @copyright Mollie B.V. + * @license https://github.com/mollie/PrestaShop/blob/master/LICENSE.md + * + * @see https://github.com/mollie/PrestaShop + * @codingStandardsIgnoreStart + */ + +namespace Mollie\Logger; + +if (!defined('_PS_VERSION_')) { + exit; +} + +class LogFormatter implements LogFormatterInterface +{ + const MOLLIE_LOG_PREFIX = 'MOLLIE_MODULE_LOG:'; + + public function getMessage(string $message): string + { + return self::MOLLIE_LOG_PREFIX . ' ' . $message; + } +} diff --git a/src/Logger/LogFormatterInterface.php b/src/Logger/LogFormatterInterface.php new file mode 100644 index 000000000..ae2690e24 --- /dev/null +++ b/src/Logger/LogFormatterInterface.php @@ -0,0 +1,23 @@ + + * @copyright Mollie B.V. + * @license https://github.com/mollie/PrestaShop/blob/master/LICENSE.md + * + * @see https://github.com/mollie/PrestaShop + * @codingStandardsIgnoreStart + */ + +namespace Mollie\Logger; + +interface LogFormatterInterface +{ + /** + * @param string $message - an actual error message + * + * @return string + */ + public function getMessage(string $message): string; +} diff --git a/src/Logger/Logger.php b/src/Logger/Logger.php new file mode 100644 index 000000000..e8c6dd505 --- /dev/null +++ b/src/Logger/Logger.php @@ -0,0 +1,170 @@ + + * @copyright Mollie B.V. + * @license https://github.com/mollie/PrestaShop/blob/master/LICENSE.md + * + * @see https://github.com/mollie/PrestaShop + * @codingStandardsIgnoreStart + */ + +namespace Mollie\Logger; + +use Mollie\Adapter\ConfigurationAdapter; +use Mollie\Adapter\Context; +use Mollie\Config\Config; +use Mollie\Service\EntityManager\EntityManagerInterface; +use Mollie\Service\EntityManager\ObjectModelUnitOfWork; +use Mollie\Utility\NumberIdempotencyProvider; + +class Logger implements LoggerInterface +{ + public const FILE_NAME = 'Logger'; + + public const LOG_OBJECT_TYPE = 'mollieLog'; + + public const SEVERITY_INFO = 1; + public const SEVERITY_WARNING = 2; + public const SEVERITY_ERROR = 3; + + private $logFormatter; + private $configuration; + private $context; + private $entityManager; + private $idempotencyProvider; + private $prestashopLoggerRepository; + + public function __construct( + LogFormatterInterface $logFormatter, + ConfigurationAdapter $configuration, + Context $context, + EntityManagerInterface $entityManager, + NumberIdempotencyProvider $idempotencyProvider, + PrestashopLoggerRepositoryInterface $prestashopLoggerRepository + ) { + $this->logFormatter = $logFormatter; + $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->context->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->context->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 ((int) $this->configuration->get(Config::MOLLIE_DEBUG_LOG) === Config::DEBUG_LOG_ALL) { + $this->log(self::SEVERITY_INFO, $message, $context); + } + } + + public function log($level, $message, array $context = []) + { + $idempotencyKey = $this->idempotencyProvider->getIdempotencyKey(); + + \PrestaShopLogger::addLog( + $this->logFormatter->getMessage($message), + $level, + null, + self::LOG_OBJECT_TYPE, + $idempotencyKey + ); + + $logId = $this->prestashopLoggerRepository->getLogIdByObjectId( + $idempotencyKey, + $this->context->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']); + } + + $log = new \MolLog(); + $log->id_log = $logId; + $log->id_shop = $this->context->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->context->getShopId(); + $context['currency'] = $this->context->getCurrencyIso(); + $context['id_language'] = $this->context->getLanguageId(); + + return $context; + } +} diff --git a/src/Logger/LoggerInterface.php b/src/Logger/LoggerInterface.php new file mode 100644 index 000000000..d6230e177 --- /dev/null +++ b/src/Logger/LoggerInterface.php @@ -0,0 +1,17 @@ + + * @copyright Mollie B.V. + * @license https://github.com/mollie/PrestaShop/blob/master/LICENSE.md + * + * @see https://github.com/mollie/PrestaShop + * @codingStandardsIgnoreStart + */ + +namespace Mollie\Logger; + +interface LoggerInterface extends \Psr\Log\LoggerInterface +{ +} diff --git a/src/Logger/PrestashopLoggerRepositoryInterface.php b/src/Logger/PrestashopLoggerRepositoryInterface.php new file mode 100644 index 000000000..d7c19fbef --- /dev/null +++ b/src/Logger/PrestashopLoggerRepositoryInterface.php @@ -0,0 +1,32 @@ + + * @copyright Mollie B.V. + * @license https://github.com/mollie/PrestaShop/blob/master/LICENSE.md + * + * @see https://github.com/mollie/PrestaShop + * @codingStandardsIgnoreStart + */ + +namespace Mollie\Logger; + +use Mollie\Repository\ReadOnlyCollectionRepositoryInterface; + +if (!defined('_PS_VERSION_')) { + exit; +} + +interface PrestashopLoggerRepositoryInterface extends ReadOnlyCollectionRepositoryInterface +{ + /** + * @param string $objectId + * @param int $shopId + * + * @return int|null + */ + public function getLogIdByObjectId(string $objectId, ?int $shopId): ?int; + + public function prune(int $daysToKeep): void; +} diff --git a/src/Repository/CollectionRepository.php b/src/Repository/CollectionRepository.php new file mode 100644 index 000000000..b199168d0 --- /dev/null +++ b/src/Repository/CollectionRepository.php @@ -0,0 +1,56 @@ + + * @copyright Mollie B.V. + * @license https://github.com/mollie/PrestaShop/blob/master/LICENSE.md + * + * @see https://github.com/mollie/PrestaShop + * @codingStandardsIgnoreStart + */ + +namespace Mollie\Repository; + +if (!defined('_PS_VERSION_')) { + exit; +} + +class CollectionRepository implements ReadOnlyCollectionRepositoryInterface +{ + /** + * @var string + */ + private $fullyClassifiedClassName; + + public function __construct(string $fullyClassifiedClassName) + { + $this->fullyClassifiedClassName = $fullyClassifiedClassName; + } + + public function findAllInCollection($langId = null): \PrestaShopCollection + { + 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): ?\ObjectModel + { + $psCollection = new \PrestaShopCollection($this->fullyClassifiedClassName, $langId); + + foreach ($keyValueCriteria as $field => $value) { + $psCollection = $psCollection->where($field, '=', $value); + } + + $first = $psCollection->getFirst(); + + return $first == false ? null : $first; + } +} diff --git a/src/Repository/MolLogRepository.php b/src/Repository/MolLogRepository.php new file mode 100644 index 000000000..451c2dfaa --- /dev/null +++ b/src/Repository/MolLogRepository.php @@ -0,0 +1,45 @@ + + * @copyright Mollie B.V. + * @license https://github.com/mollie/PrestaShop/blob/master/LICENSE.md + * + * @see https://github.com/mollie/PrestaShop + * @codingStandardsIgnoreStart + */ + +namespace Mollie\Repository; + +use Invertus\Knapsack\Collection; +use Mollie\Subscription\Exception\NotImplementedException; + +if (!defined('_PS_VERSION_')) { + exit; +} + +class MolLogRepository extends CollectionRepository implements MolLogRepositoryInterface +{ + public function __construct() + { + parent::__construct(\MolLog::class); + } + + public function prune(int $daysToKeep): void + { + Collection::from( + $this->findAllInCollection() + ->sqlWhere('DATEDIFF(NOW(),date_add) >= ' . $daysToKeep) + ) + ->each(function (\MolLog $log) { + $log->delete(); + }) + ->realize(); + } + + public function findAll() + { + throw new NotImplementedException('Find all not implemented'); + } +} diff --git a/src/Repository/MolLogRepositoryInterface.php b/src/Repository/MolLogRepositoryInterface.php new file mode 100644 index 000000000..5e2c0d618 --- /dev/null +++ b/src/Repository/MolLogRepositoryInterface.php @@ -0,0 +1,22 @@ + + * @copyright Mollie B.V. + * @license https://github.com/mollie/PrestaShop/blob/master/LICENSE.md + * + * @see https://github.com/mollie/PrestaShop + * @codingStandardsIgnoreStart + */ + +namespace Mollie\Repository; + +if (!defined('_PS_VERSION_')) { + exit; +} + +interface MolLogRepositoryInterface extends ReadOnlyRepositoryInterface +{ + public function prune(int $daysToKeep): void; +} diff --git a/src/Repository/PrestashopLoggerRepository.php b/src/Repository/PrestashopLoggerRepository.php new file mode 100644 index 000000000..3a18d1c55 --- /dev/null +++ b/src/Repository/PrestashopLoggerRepository.php @@ -0,0 +1,63 @@ + + * @copyright Mollie B.V. + * @license https://github.com/mollie/PrestaShop/blob/master/LICENSE.md + * + * @see https://github.com/mollie/PrestaShop + * @codingStandardsIgnoreStart + */ + +namespace Mollie\Repository; + +use Invertus\Knapsack\Collection; +use Mollie\Logger\Logger; +use Mollie\Logger\PrestashopLoggerRepositoryInterface; +use Mollie\Utility\VersionUtility; + +if (!defined('_PS_VERSION_')) { + exit; +} + +class PrestashopLoggerRepository extends CollectionRepository implements PrestashopLoggerRepositoryInterface +{ + public function __construct() + { + parent::__construct(\PrestaShopLogger::class); + } + + /** {@inheritDoc} */ + public function getLogIdByObjectId(string $objectId, ?int $shopId): ?int + { + $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(int $daysToKeep): void + { + 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/ReadOnlyCollectionRepositoryInterface.php b/src/Repository/ReadOnlyCollectionRepositoryInterface.php new file mode 100644 index 000000000..6af7aed4b --- /dev/null +++ b/src/Repository/ReadOnlyCollectionRepositoryInterface.php @@ -0,0 +1,39 @@ + + * @copyright Mollie B.V. + * @license https://github.com/mollie/PrestaShop/blob/master/LICENSE.md + * + * @see https://github.com/mollie/PrestaShop + * @codingStandardsIgnoreStart + */ + +namespace Mollie\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): \PrestaShopCollection; + + /** + * @param array $keyValueCriteria - e.g [ 'id_cart' => 5 ] + * @param int|null $langId + * + * @return \ObjectModel|null + */ + public function findOneBy(array $keyValueCriteria, $langId = null): ?\ObjectModel; +} diff --git a/src/Repository/ReadOnlyRepositoryInterface.php b/src/Repository/ReadOnlyRepositoryInterface.php new file mode 100644 index 000000000..2597ebed9 --- /dev/null +++ b/src/Repository/ReadOnlyRepositoryInterface.php @@ -0,0 +1,35 @@ + + * @copyright Mollie B.V. + * @license https://github.com/mollie/PrestaShop/blob/master/LICENSE.md + * + * @see https://github.com/mollie/PrestaShop + * @codingStandardsIgnoreStart + */ + +namespace Mollie\Repository; + +use ObjectModel; +use PrestaShopCollection; + +if (!defined('_PS_VERSION_')) { + exit; +} + +interface ReadOnlyRepositoryInterface +{ + /** + * @return PrestaShopCollection + */ + public function findAll(); + + /** + * @param array $keyValueCriteria - e.g [ 'id_cart' => 5 ] + * + * @return ObjectModel|null + */ + public function findOneBy(array $keyValueCriteria); +} diff --git a/src/Service/EntityManager/EntityManagerInterface.php b/src/Service/EntityManager/EntityManagerInterface.php index cb4877180..3dbdd71de 100644 --- a/src/Service/EntityManager/EntityManagerInterface.php +++ b/src/Service/EntityManager/EntityManagerInterface.php @@ -12,9 +12,6 @@ namespace Mollie\Service\EntityManager; -use ObjectModel; -use PrestaShopException; - if (!defined('_PS_VERSION_')) { exit; } @@ -22,7 +19,9 @@ interface EntityManagerInterface { /** - * @throws PrestaShopException + * @return array<\ObjectModel> + * + * @throws \PrestaShopException */ - public function flush(ObjectModel $model); + public function flush(): array; } diff --git a/src/Service/EntityManager/ObjectModelEntityManager.php b/src/Service/EntityManager/ObjectModelEntityManager.php new file mode 100644 index 000000000..ad6c7c0e6 --- /dev/null +++ b/src/Service/EntityManager/ObjectModelEntityManager.php @@ -0,0 +1,75 @@ + + * @copyright Mollie B.V. + * @license https://github.com/mollie/PrestaShop/blob/master/LICENSE.md + * + * @see https://github.com/mollie/PrestaShop + * @codingStandardsIgnoreStart + */ + +namespace Mollie\Service\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, + string $unitOfWorkType, + ?string $specificKey = null + ): EntityManagerInterface { + $this->unitOfWork->setWork($model, $unitOfWorkType, $specificKey); + + return $this; + } + + /** + * @return array<\ObjectModel> + * + * @throws \PrestaShopDatabaseException + * @throws \PrestaShopException + */ + public function flush(): array + { + $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/Service/EntityManager/ObjectModelUnitOfWork.php b/src/Service/EntityManager/ObjectModelUnitOfWork.php new file mode 100644 index 000000000..50e6385c6 --- /dev/null +++ b/src/Service/EntityManager/ObjectModelUnitOfWork.php @@ -0,0 +1,53 @@ + + * @copyright Mollie B.V. + * @license https://github.com/mollie/PrestaShop/blob/master/LICENSE.md + * + * @see https://github.com/mollie/PrestaShop + * @codingStandardsIgnoreStart + */ + +namespace Mollie\Service\EntityManager; + +if (!defined('_PS_VERSION_')) { + exit; +} + +/** In memory entity manager object model unit of work */ +class ObjectModelUnitOfWork +{ + public const UNIT_OF_WORK_SAVE = 'UNIT_OF_WORK_SAVE'; + public const UNIT_OF_WORK_DELETE = 'UNIT_OF_WORK_DELETE'; + + private $work = []; + + public function setWork(\ObjectModel $objectModel, string $unitOfWorkType, ?string $specificKey = null): void + { + $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(): array + { + return $this->work; + } + + public function clearWork(): void + { + $this->work = []; + } +} diff --git a/src/Service/PaymentMethodService.php b/src/Service/PaymentMethodService.php index 411ea16e6..ecf936f67 100644 --- a/src/Service/PaymentMethodService.php +++ b/src/Service/PaymentMethodService.php @@ -335,6 +335,7 @@ public function getPaymentData( $paymentData->setMethod($molPaymentMethod->id_method); $paymentData->setDescription($orderReference); + $paymentData->setEmail($customer->email); if (isset($cart->id_address_invoice)) { $billingAddress = new Address((int) $cart->id_address_invoice); diff --git a/src/ServiceProvider/BaseServiceProvider.php b/src/ServiceProvider/BaseServiceProvider.php index 876fbf367..2fd5701bf 100644 --- a/src/ServiceProvider/BaseServiceProvider.php +++ b/src/ServiceProvider/BaseServiceProvider.php @@ -16,6 +16,9 @@ use League\Container\Container; use Mollie; +use Mollie\Adapter\ConfigurationAdapter; +use Mollie\Adapter\Context; +use Mollie\Adapter\Shop; use Mollie\Builder\ApiTestFeedbackBuilder; use Mollie\Factory\ModuleFactory; use Mollie\Handler\Api\OrderEndpointPaymentTypeHandler; @@ -33,8 +36,13 @@ use Mollie\Handler\Shipment\ShipmentSenderHandler; use Mollie\Handler\Shipment\ShipmentSenderHandlerInterface; use Mollie\Install\UninstallerInterface; +use Mollie\Logger\LogFormatter; +use Mollie\Logger\LogFormatterInterface; +use Mollie\Logger\Logger; +use Mollie\Logger\LoggerInterface; use Mollie\Logger\PrestaLogger; use Mollie\Logger\PrestaLoggerInterface; +use Mollie\Logger\PrestashopLoggerRepositoryInterface; use Mollie\Provider\CreditCardLogoProvider; use Mollie\Provider\CustomLogoProviderInterface; use Mollie\Provider\EnvironmentVersionProvider; @@ -51,6 +59,7 @@ use Mollie\Provider\ProfileIdProviderInterface; use Mollie\Provider\Shipment\AutomaticShipmentSenderStatusesProvider; use Mollie\Provider\Shipment\AutomaticShipmentSenderStatusesProviderInterface; +use Mollie\Provider\TaxCalculatorProvider; use Mollie\Provider\UpdateMessageProvider; use Mollie\Provider\UpdateMessageProviderInterface; use Mollie\Repository\AddressFormatRepository; @@ -71,6 +80,8 @@ use Mollie\Repository\GenderRepositoryInterface; use Mollie\Repository\MolCustomerRepository; use Mollie\Repository\MolCustomerRepositoryInterface; +use Mollie\Repository\MolLogRepository; +use Mollie\Repository\MolLogRepositoryInterface; use Mollie\Repository\MolOrderPaymentFeeRepository; use Mollie\Repository\MolOrderPaymentFeeRepositoryInterface; use Mollie\Repository\OrderRepository; @@ -79,6 +90,7 @@ use Mollie\Repository\PaymentMethodRepositoryInterface; use Mollie\Repository\PendingOrderCartRuleRepository; use Mollie\Repository\PendingOrderCartRuleRepositoryInterface; +use Mollie\Repository\PrestashopLoggerRepository; use Mollie\Repository\ProductRepository; use Mollie\Repository\ProductRepositoryInterface; use Mollie\Repository\TaxRepository; @@ -88,8 +100,13 @@ use Mollie\Repository\TaxRulesGroupRepository; use Mollie\Repository\TaxRulesGroupRepositoryInterface; use Mollie\Service\ApiKeyService; +use Mollie\Service\ApiService; +use Mollie\Service\ApiServiceInterface; use Mollie\Service\Content\SmartyTemplateParser; use Mollie\Service\Content\TemplateParserInterface; +use Mollie\Service\EntityManager\EntityManagerInterface; +use Mollie\Service\EntityManager\ObjectModelEntityManager; +use Mollie\Service\EntityManager\ObjectModelUnitOfWork; use Mollie\Service\PaymentMethod\PaymentMethodRestrictionValidation; use Mollie\Service\PaymentMethod\PaymentMethodRestrictionValidation\AmountPaymentMethodRestrictionValidator; use Mollie\Service\PaymentMethod\PaymentMethodRestrictionValidation\ApplePayPaymentMethodRestrictionValidator; @@ -104,6 +121,7 @@ use Mollie\Service\Shipment\ShipmentInformationSenderInterface; use Mollie\Service\ShipmentService; use Mollie\Service\ShipmentServiceInterface; +use Mollie\Service\TransactionService; use Mollie\Shared\Core\Shared\Repository\CurrencyRepository; use Mollie\Shared\Core\Shared\Repository\CurrencyRepositoryInterface; use Mollie\Subscription\Grid\Accessibility\SubscriptionCancelAccessibility; @@ -123,6 +141,7 @@ use Mollie\Subscription\Utility\ClockInterface; use Mollie\Utility\Decoder\DecoderInterface; use Mollie\Utility\Decoder\JsonDecoder; +use Mollie\Utility\NumberIdempotencyProvider; use Mollie\Verification\PaymentType\CanBeRegularPaymentType; use Mollie\Verification\PaymentType\PaymentTypeVerificationInterface; use Mollie\Verification\Shipment\CanSendShipment; @@ -252,6 +271,32 @@ public function register(Container $container) $service = $this->addService($container, ApiTestFeedbackBuilder::class, ApiTestFeedbackBuilder::class); $this->addServiceArgument($service, $container->get(ModuleFactory::class)->getModuleVersion() ?? ''); $this->addServiceArgument($service, ApiKeyService::class); + + $this->addService($container, PrestashopLoggerRepositoryInterface::class, PrestashopLoggerRepository::class); + $this->addService($container, MolLogRepositoryInterface::class, MolLogRepository::class); + + $service = $this->addService($container, LoggerInterface::class, Logger::class); + $this->addServiceArgument($service, LogFormatterInterface::class); + $this->addServiceArgument($service, ConfigurationAdapter::class); + $this->addServiceArgument($service, Context::class); + $this->addServiceArgument($service, EntityManagerInterface::class); + $this->addServiceArgument($service, NumberIdempotencyProvider::class); + $this->addServiceArgument($service, PrestashopLoggerRepositoryInterface::class); + + $this->addService($container, LogFormatterInterface::class, LogFormatter::class); + + $service = $this->addService($container, ApiServiceInterface::class, ApiService::class); + $this->addServiceArgument($service, PaymentMethodRepository::class); + $this->addServiceArgument($service, CountryRepository::class); + $this->addServiceArgument($service, PaymentMethodSortProviderInterface::class); + $this->addServiceArgument($service, ConfigurationAdapter::class); + $this->addServiceArgument($service, TransactionService::class); + $this->addServiceArgument($service, Shop::class); + $this->addServiceArgument($service, TaxCalculatorProvider::class); + $this->addServiceArgument($service, Context::class); + + $service = $this->addService($container, EntityManagerInterface::class, ObjectModelEntityManager::class); + $this->addServiceArgument($service, ObjectModelUnitOfWork::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 000000000..45978b8b3 --- /dev/null +++ b/src/Utility/ExceptionUtility.php @@ -0,0 +1,46 @@ + + * @copyright Mollie B.V. + * @license https://github.com/mollie/PrestaShop/blob/master/LICENSE.md + * + * @see https://github.com/mollie/PrestaShop + * @codingStandardsIgnoreStart + */ + +namespace Mollie\Utility; + +if (!defined('_PS_VERSION_')) { + exit; +} + +class ExceptionUtility +{ + public static function getExceptions(\Throwable $exception) + { + if (method_exists($exception, 'getExceptions')) { + return $exception->getExceptions(); + } + + return [self::toArray($exception)]; + } + + public static function toArray(\Throwable $exception): array + { + 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/Service/EntityManager/ObjectModelManager.php b/src/Utility/NumberIdempotencyProvider.php similarity index 59% rename from src/Service/EntityManager/ObjectModelManager.php rename to src/Utility/NumberIdempotencyProvider.php index 62b1c4e64..2af8db85b 100644 --- a/src/Service/EntityManager/ObjectModelManager.php +++ b/src/Utility/NumberIdempotencyProvider.php @@ -10,21 +10,16 @@ * @codingStandardsIgnoreStart */ -namespace Mollie\Service\EntityManager; - -use ObjectModel; +namespace Mollie\Utility; if (!defined('_PS_VERSION_')) { exit; } -class ObjectModelManager implements EntityManagerInterface +class NumberIdempotencyProvider { - /** - * @throws \PrestaShopException - */ - public function flush(ObjectModel $model) + public function getIdempotencyKey(): string { - $model->save(); + return (string) mt_rand(); } } diff --git a/src/Utility/NumberUtility.php b/src/Utility/NumberUtility.php index ca4babd47..24fba4584 100644 --- a/src/Utility/NumberUtility.php +++ b/src/Utility/NumberUtility.php @@ -13,7 +13,7 @@ namespace Mollie\Utility; use PrestaShop\Decimal\DecimalNumber; -use PrestaShop\Decimal\Number; +use PrestaShop\Decimal\Exception\DivisionByZeroException; use PrestaShop\Decimal\Operation\Rounding; if (!defined('_PS_VERSION_')) { @@ -24,14 +24,21 @@ class NumberUtility { public const DECIMAL_PRECISION = 2; public const FLOAT_PRECISION = 6; - private const ROUNDING = Rounding::ROUND_HALF_UP; - - // TODO make all methods consistent: either pass string/float as parameter or cast members to Number/DecimalNumber class beforehand. + private const ROUNDING_MODE = Rounding::ROUND_HALF_UP; + /** + * Converts a float number to a specified precision. + * + * @param float $number + * @param int $precision + * @param string $roundingMode + * + * @return float + */ public static function toPrecision( float $number, int $precision = self::DECIMAL_PRECISION, - string $roundingMode = self::ROUNDING + string $roundingMode = self::ROUNDING_MODE ): float { $decimalNumber = self::getNumber($number); @@ -39,142 +46,197 @@ public static function toPrecision( } /** - * Decreases number by its given percentage - * E.g 75/1.5 = 50. + * Decreases a number by a given percentage. * * @param float $number * @param float $percentage * * @return float * - * @throws \PrestaShop\Decimal\Exception\DivisionByZeroException + * @throws DivisionByZeroException */ - public static function decreaseByPercentage($number, $percentage) + public static function decreaseByPercentage(float $number, float $percentage): float { - if (!$percentage || $percentage <= 0) { + if ($percentage <= 0) { return $number; } + $numberTransformed = self::getNumber($number); - $totalDecrease = self::toPercentageIncrease($percentage); - $decrement = (string) $numberTransformed->dividedBy(self::getNumber($totalDecrease)); + $percentageIncrease = self::toPercentageIncrease($percentage); + $decrement = $numberTransformed->dividedBy(self::getNumber($percentageIncrease)); - return (float) $decrement; + return (float) $decrement->toPrecision(self::DECIMAL_PRECISION, self::ROUNDING_MODE); } - public static function increaseByPercentage($number, $percentage) + /** + * Increases a number by a given percentage. + * + * @param float $number + * @param float $percentage + * + * @return float + */ + public static function increaseByPercentage(float $number, float $percentage): float { - if (!$percentage || $percentage <= 0) { + if ($percentage <= 0) { return $number; } + $numberTransformed = self::getNumber($number); $percentageIncrease = self::toPercentageIncrease($percentage); - $percentageIncreaseTransformed = self::getNumber($percentageIncrease); - $result = (string) $numberTransformed->times($percentageIncreaseTransformed); + $result = $numberTransformed->times(self::getNumber($percentageIncrease)); - return (float) $result; + return (float) $result->toPrecision(self::DECIMAL_PRECISION, self::ROUNDING_MODE); } /** - * E.g 21% will become 1.21. + * Converts a percentage to its decimal increase (e.g., 21% becomes 1.21). * * @param float $percentage * * @return float */ - public static function toPercentageIncrease($percentage) + public static function toPercentageIncrease(float $percentage): float { $percentageNumber = self::getNumber($percentage); $smallerNumber = $percentageNumber->dividedBy(self::getNumber(100)); - $result = (string) $smallerNumber->plus(self::getNumber(1)); + $result = $smallerNumber->plus(self::getNumber(1)); - return (float) $result; + return (float) $result->toPrecision(self::FLOAT_PRECISION, self::ROUNDING_MODE); } + /** + * Multiplies two numbers with precision. + * + * @param float $target + * @param float $factor + * @param int $precision + * @param string $roundingMode + * + * @return float + */ public static function times( float $target, float $factor, int $precision = self::FLOAT_PRECISION, - string $roundingMode = self::ROUNDING + string $roundingMode = self::ROUNDING_MODE ): float { - $firstNumber = self::getNumber($target); - $secondNumber = self::getNumber($factor); - - $result = $firstNumber->times($secondNumber); + $result = self::getNumber($target)->times(self::getNumber($factor)); return (float) $result->toPrecision($precision, $roundingMode); } + /** + * Divides a number by another with precision. + * + * @param float $target + * @param float $divisor + * @param int $precision + * @param string $roundingMode + * + * @return float + * + * @throws DivisionByZeroException + */ public static function divide( float $target, float $divisor, int $precision = self::FLOAT_PRECISION, - string $roundingMode = self::ROUNDING + string $roundingMode = self::ROUNDING_MODE ): float { - $firstNumber = self::getNumber($target); - $secondNumber = self::getNumber($divisor); - - $result = $firstNumber->dividedBy($secondNumber, $precision); + $result = self::getNumber($target)->dividedBy(self::getNumber($divisor), $precision); return (float) $result->toPrecision($precision, $roundingMode); } + /** + * Checks if two numbers are equal. + * + * @param float $a + * @param float $b + * + * @return bool + */ public static function isEqual(float $a, float $b): bool { - $firstNumber = self::getNumber($a); - $secondNumber = self::getNumber($b); - - return $firstNumber->equals($secondNumber); + return self::getNumber($a)->equals(self::getNumber($b)); } - public static function isLowerThan($a, $b) + /** + * Checks if one number is lower than another. + * + * @param float $a + * @param float $b + * + * @return bool + */ + public static function isLowerThan(float $a, float $b): bool { - $firstNumber = self::getNumber($a); - $secondNumber = self::getNumber($b); - - return $firstNumber->isLowerThan($secondNumber); + return self::getNumber($a)->isLowerThan(self::getNumber($b)); } - public static function isLowerOrEqualThan($a, $b) + /** + * Checks if one number is lower than or equal to another. + * + * @param float $a + * @param float $b + * + * @return bool + */ + public static function isLowerOrEqualThan(float $a, float $b): bool { - $firstNumber = self::getNumber($a); - $secondNumber = self::getNumber($b); - - return $firstNumber->isLowerOrEqualThan($secondNumber); + return self::getNumber($a)->isLowerOrEqualThan(self::getNumber($b)); } + /** + * Checks if one number is greater than another. + * + * @param float $target + * @param float $comparison + * + * @return bool + */ public static function isGreaterThan(float $target, float $comparison): bool { - $firstNumber = self::getNumber($target); - $secondNumber = self::getNumber($comparison); - - return $firstNumber->isGreaterThan($secondNumber); + return self::getNumber($target)->isGreaterThan(self::getNumber($comparison)); } - public static function minus($a, $b) + /** + * Subtracts one number from another. + * + * @param float $a + * @param float $b + * + * @return float + */ + public static function minus(float $a, float $b): float { - $firstNumber = self::getNumber($a); - $secondNumber = self::getNumber($b); - - return (float) ((string) $firstNumber->minus($secondNumber)); + return (float) self::getNumber($a)->minus(self::getNumber($b))->toPrecision(self::FLOAT_PRECISION, self::ROUNDING_MODE); } - public static function plus($a, $b) + /** + * Adds two numbers together. + * + * @param float $a + * @param float $b + * + * @return float + */ + public static function plus(float $a, float $b): float { - $firstNumber = self::getNumber($a); - $secondNumber = self::getNumber($b); - - return (float) ((string) $firstNumber->plus($secondNumber)); + return (float) self::getNumber($a)->plus(self::getNumber($b))->toPrecision(self::FLOAT_PRECISION, self::ROUNDING_MODE); } /** - * @return Number|DecimalNumber + * Creates a Number or DecimalNumber instance from a float. + * + * @param float $number + * + * @return DecimalNumber */ - private static function getNumber(float $number) + private static function getNumber(float $number): DecimalNumber { - if (is_subclass_of(Number::class, DecimalNumber::class)) { - return new DecimalNumber((string) $number); - } - - return new Number((string) $number); + // Assuming DecimalNumber is the preferred class based on the use case. + return new DecimalNumber((string) $number); } } diff --git a/src/Utility/VersionUtility.php b/src/Utility/VersionUtility.php new file mode 100644 index 000000000..c3c27468f --- /dev/null +++ b/src/Utility/VersionUtility.php @@ -0,0 +1,46 @@ + + * @copyright Mollie B.V. + * @license https://github.com/mollie/PrestaShop/blob/master/LICENSE.md + * + * @see https://github.com/mollie/PrestaShop + * @codingStandardsIgnoreStart + */ + +namespace Mollie\Utility; + +class VersionUtility +{ + public static function isPsVersionLessThan($version): int + { + return (int) version_compare(_PS_VERSION_, $version, '<'); + } + + public static function isPsVersionGreaterThan($version): int + { + return (int) version_compare(_PS_VERSION_, $version, '>'); + } + + public static function isPsVersionGreaterOrEqualTo($version): int + { + return (int) version_compare(_PS_VERSION_, $version, '>='); + } + + public static function isPsVersionLessThanOrEqualTo($version): int + { + return (int) version_compare(_PS_VERSION_, $version, '<='); + } + + public static function isPsVersionEqualTo($version): int + { + return (int) version_compare(_PS_VERSION_, $version, '='); + } + + public static function current(): string + { + return _PS_VERSION_; + } +} diff --git a/subscription/Install/AttributeUninstaller.php b/subscription/Install/AttributeUninstaller.php index e5dd017a3..927016a05 100644 --- a/subscription/Install/AttributeUninstaller.php +++ b/subscription/Install/AttributeUninstaller.php @@ -17,7 +17,8 @@ use Mollie; use Mollie\Adapter\ConfigurationAdapter; use Mollie\Adapter\ProductAttributeAdapter; -use Mollie\Logger\PrestaLoggerInterface; +use Mollie\Logger\Logger; +use Mollie\Logger\LoggerInterface; use Mollie\Subscription\Config\Config; use PrestaShopException; use Psr\Log\LogLevel; @@ -36,13 +37,13 @@ class AttributeUninstaller extends AbstractUninstaller /** @var Mollie */ private $module; - /** @var PrestaLoggerInterface */ + /** @var LoggerInterface */ private $logger; /** @var ProductAttributeAdapter */ private $productAttributeAdapter; public function __construct( - PrestaLoggerInterface $logger, + Logger $logger, ConfigurationAdapter $configuration, Mollie $module, ProductAttributeAdapter $productAttributeAdapter diff --git a/subscription/Provider/SubscriptionStartDateProvider.php b/subscription/Provider/SubscriptionStartDateProvider.php index ba415d9f4..fb86fc060 100644 --- a/subscription/Provider/SubscriptionStartDateProvider.php +++ b/subscription/Provider/SubscriptionStartDateProvider.php @@ -62,15 +62,16 @@ public function getSubscriptionStartDate(Combination $combination) $interval = new DateInterval('P1Y'); break; default: - throw new SubscriptionIntervalException(sprintf('No interval exists for this %s attribute', $combination->id)); + $interval = null; } // Add the interval to the current time - $currentTime->add($interval); + if ($interval !== null) { + $currentTime->add($interval); - return $currentTime->format('Y-m-d'); + return $currentTime->format('Y-m-d'); + } } - throw new SubscriptionIntervalException(sprintf('No interval exists for this %s attribute', $combination->id)); } } diff --git a/tests/phpstan/phpstan_base.neon b/tests/phpstan/phpstan_base.neon index bde2361d4..e8bf24d4b 100644 --- a/tests/phpstan/phpstan_base.neon +++ b/tests/phpstan/phpstan_base.neon @@ -42,5 +42,10 @@ parameters: - '#Parameter \#1 \$value of method ControllerCore\:\:ajaxRender\(\) expects null, string\|false given.#' - '#Call to function is_subclass_of\(\) with.*will always evaluate to false.#' - '#Call to function is_array\(\) with.*will always evaluate to false.#' + - '#Property AdminControllerCore\:\:\$_use_found_rows \(string\) does not accept false.#' + - '#Access to undefined constant PrestaShopLogger::LOG_SEVERITY_LEVEL_INFORMATIVE.#' + - '#Access to undefined constant PrestaShopLogger::LOG_SEVERITY_LEVEL_WARNING.#' + - '#Access to undefined constant PrestaShopLogger::LOG_SEVERITY_LEVEL_ERROR.#' + - '#Access to undefined constant PrestaShopLogger::LOG_SEVERITY_LEVEL_MAJOR.#' level: 5 diff --git a/translations/it.php b/translations/it.php index 19bc68372..971f0fa00 100644 --- a/translations/it.php +++ b/translations/it.php @@ -12,11 +12,416 @@ global $_MODULE; $_MODULE = array(); -$_MODULE['<{mollie}prestashop>mollie_iframe_a4b29064de828b87f9f9b6fa145cb507'] = 'Inserisci le informazioni della tua carta'; -$_MODULE['<{mollie}prestashop>mollie_iframe_c2b63e85bd5e4dc9b6cf5a4693847e06'] = 'Intestatario della carta'; -$_MODULE['<{mollie}prestashop>mollie_iframe_a44217022190f5734b2f72ba1e4f8a79'] = 'Numero della carta'; +$_MODULE['ID'] = 'EN'; +$_MODULE['<{mollie}prestashop>mollie_7c478959c218087ffc4ad5d96e7f66a6'] = 'Mollie'; +$_MODULE['<{mollie}prestashop>mollie_95b3b272e06dcc3cc2aa62f6887aebc5'] = 'Mollie Payments'; +$_MODULE['<{mollie}prestashop>mollie_6bedf641eb10773a0069acb02fd7f8ac'] = 'Stai utilizzando una versione PHP non aggiornata. Aggiorna la versione di PHP per utilizzare questo modulo. Il modulo Mollie supporta le versioni PHP 7.2.0 e successive'; +$_MODULE['<{mollie}prestashop>mollie_46e2d06b80d816b2916f1f27492fbabd'] = 'Non è stato possibile installare il modulo'; +$_MODULE['<{mollie}prestashop>mollie_f51ae8e015ae0be2c4a8d5b9ee160ac2'] = 'Grazie. Abbiamo ricevuto il tuo pagamento'; +$_MODULE['<{mollie}prestashop>mollie_a34a6659bceae779f28185e757abfca5'] = 'AJAX'; +$_MODULE['<{mollie}prestashop>mollie_4ca2c509994c2776d0880357b4e8e5be'] = 'Abbonamenti'; +$_MODULE['<{mollie}prestashop>mollie_79b279ae50c49015bbc70cb91ed8e7c7'] = 'FAQ Abbonamenti'; +$_MODULE['<{mollie}prestashop>mollie_f9c43173e5db74a01dd11ce73fbbb237'] = 'Link di pagamento'; +$_MODULE['<{mollie}prestashop>mollie_da72870a79e82cbcbffe83612e5d7968'] = ' please contact Mollie support with this screenshot and they will guide through the next steps: info@mollie.com'; +$_MODULE['<{mollie}prestashop>mollie_ab552f085567bbe63872c10a3596cd27'] = 'Errore di pagamento:'; +$_MODULE['<{mollie}prestashop>mollie_76303c4f7c410bdc9ac636c63ce2dd57'] = 'Il cliente deve aver effettuato il login per acquistare articoli in abbonamento'; +$_MODULE['<{mollie}prestashop>mollie_44572b4daf09470411df1b114f34472c'] = 'Non puoi rimuovere l\'indirizzo associato all\'abbonamento'; +$_MODULE['<{mollie}prestashop>subscriptionfaqcontroller_38af3b4b766a41e7abd5a67b30aa3252'] = 'Creazione di abbonamento'; +$_MODULE['<{mollie}prestashop>subscriptionfaqcontroller_d24892cee2206a282f2da551c9b3a304'] = ' assign it a Mollie subscription attribute.'; +$_MODULE['<{mollie}prestashop>subscriptionfaqcontroller_81c97809c908ee9375f3e00fca33ef83'] = 'Punti IMPORTANTI'; +$_MODULE['<{mollie}prestashop>subscriptionfaqcontroller_3e069600ef900b2e98f23b727cd100cf'] = ' make sure you always include \'none\' as a fallback.'; +$_MODULE['<{mollie}prestashop>subscriptionfaqcontroller_c13d080743619c08b7490506b659d621'] = 'Punti IMPORTANTI sul vettore per l\'abbonamento '; +$_MODULE['<{mollie}prestashop>subscriptionfaqcontroller_eb0b4ddca36b363a427bf335c5c3550f'] = 'Assicurati di selezionare il vettore predefinito per gli ordini ricorrenti nelle impostazioni avanzate'; +$_MODULE['<{mollie}prestashop>subscriptionfaqcontroller_b9aefba8e2f89d7bffc685b64aa0d736'] = 'Il vettore dovrebbe coprire tutte le regioni supportate dal negozio.'; +$_MODULE['<{mollie}prestashop>subscriptionfaqcontroller_4c47d0a7f71225d19b24b78aac64902f'] = 'Il vettore non può essere cambiato dopo che è stato effettuato il primo ordine di abbonamento.'; +$_MODULE['<{mollie}prestashop>subscriptionfaqcontroller_0f6a3974ead9594357aab192664a7eb5'] = ' subscription orders must be cancelled and carrier re-selected in module settings.'; +$_MODULE['<{mollie}prestashop>subscriptionfaqcontroller_3b8c8bf8ab2226d5a44454a20ad7fafb'] = 'Regole del carrello'; +$_MODULE['<{mollie}prestashop>subscriptionfaqcontroller_77667491a6d007a7062b669917599bbc'] = 'Non utilizzare le regole del carrello con i prodotti in abbonamento'; +$_MODULE['<{mollie}prestashop>subscriptionfaqcontroller_484f5a79672cebe198ebdde45a1d672f'] = 'Confezioni regalo'; +$_MODULE['<{mollie}prestashop>subscriptionfaqcontroller_f5f883e559bd9ec0885fc6397a5aedcc'] = 'La funzione di confezione regalo non è supportata per gli ordini in abbonamento.'; +$_MODULE['<{mollie}prestashop>subscriptionfaqcontroller_ca1e79f242bd752219bcd277c81388c1'] = 'Creazione di ordini ricorrenti'; +$_MODULE['<{mollie}prestashop>subscriptionfaqcontroller_8d94b7e95d45f3794e5954d07096d1e6'] = 'Mollie for Prestashop crea automaticamente un nuovo ordine quando l\'ordine precedente viene pagato.'; +$_MODULE['<{mollie}prestashop>subscriptionfaqcontroller_fefdd14033551369993a8f0f381844b4'] = 'Gli ordini ricorrenti utilizzano sempre il prezzo del prodotto specificato al momento della creazione del relativo abbonamento.'; +$_MODULE['<{mollie}prestashop>subscriptionfaqcontroller_8fd39e0e481c4f296e74f28779c7aee1'] = 'L\'ordine ricorrente sovrascriverà l\'impostazione del ?Metodo? di pagamento e utilizzerà il Payments API di Mollie.'; +$_MODULE['<{mollie}prestashop>subscriptioncontroller_4a0df35e9183f634bdfda31938430cf4'] = 'Seleziona il negozio che vuoi configurare'; +$_MODULE['<{mollie}prestashop>subscriptioncontroller_d397e034dae1adee47e6d4a91df4aa88'] = 'Non è stato possibile salvare le opzioni. Riprova o contatta l\'assistenza'; +$_MODULE['<{mollie}prestashop>subscriptioncontroller_d52009581ee35883c8d5fb0fb6e87bbf'] = 'Opzioni salvate con successo.'; +$_MODULE['<{mollie}prestashop>subscriptioncontroller_6b7c88b7c128f8c430c993211ba24e06'] = 'Vettore non trovato'; +$_MODULE['<{mollie}prestashop>subscriptioncontroller_78a9815ae364d67deb2b8427ea6c6a95'] = 'Annullato con successo'; +$_MODULE['<{mollie}prestashop>subscriptioncontroller_0e1248f1d840e05ee74190cb30e23c51'] = 'Non è stato possibile annullare l\'abbonamento'; +$_MODULE['<{mollie}prestashop>subscriptiongriddefinitionfactory_4ca2c509994c2776d0880357b4e8e5be'] = 'Abbonamenti'; +$_MODULE['<{mollie}prestashop>subscriptiongriddefinitionfactory_b718adec73e04ce3ec720dd11a06a308'] = 'ID'; +$_MODULE['<{mollie}prestashop>subscriptiongriddefinitionfactory_9bf79c7f10eadd0b612b8c354ad19bdc'] = 'ID abbonamento'; +$_MODULE['<{mollie}prestashop>subscriptiongriddefinitionfactory_d37c2bf1bd3143847fca087b354f920e'] = 'ID cliente'; +$_MODULE['<{mollie}prestashop>subscriptiongriddefinitionfactory_f11b368cddfe37c47af9b9d91c6ba4f0'] = 'Nome e cognome'; +$_MODULE['<{mollie}prestashop>subscriptiongriddefinitionfactory_b5a7adde1af5c87d7fd797b6245c2a39'] = 'Descrizione'; +$_MODULE['<{mollie}prestashop>subscriptiongriddefinitionfactory_ec53a8c4f07baed5d8825072c89799be'] = 'Stato'; +$_MODULE['<{mollie}prestashop>subscriptiongriddefinitionfactory_0eede552438475bdfe820c13f24c9399'] = 'Prezzo totale'; +$_MODULE['<{mollie}prestashop>subscriptiongriddefinitionfactory_386c339d37e737a436499d423a77df0c'] = 'Valuta'; +$_MODULE['<{mollie}prestashop>subscriptiongriddefinitionfactory_06df33001c1d7187fdd81ea1f5b277aa'] = 'Azioni'; +$_MODULE['<{mollie}prestashop>subscriptiongriddefinitionfactory_ea4788705e6873b424c65e91c2846b19'] = 'Annulla'; +$_MODULE['<{mollie}prestashop>subscriptiongriddefinitionfactory_805a483e4f806eb7f6d44661b90e0d76'] = 'Annulla l\'abbonamento selezionato'; +$_MODULE['<{mollie}prestashop>subscriptionoptionstype_d27f3c2977da307854a974ade1316962'] = 'Seleziona il tuo vettore'; +$_MODULE['<{mollie}prestashop>attributeinstaller_142d1355d40f10a77bb020f57efb2205'] = 'Non è stato possibile aggiungere gli attributi'; +$_MODULE['<{mollie}prestashop>attributeuninstaller_90ff30630b1f92f3faab5e841e0743bf'] = 'Non è stato possibile cancellare degli attributi'; +$_MODULE['<{mollie}prestashop>abstractmolliecontroller_dbfd87145ffce60928d0790df013993d'] = 'Conflitto di risorse'; +$_MODULE['<{mollie}prestashop>abstractmolliecontroller_8f8913c1f755436db84ae169e37c61f9'] = 'Errore interno'; +$_MODULE['<{mollie}prestashop>formbuilder_c9cc8cce247e49bae79f15173ce97354'] = 'Salva'; +$_MODULE['<{mollie}prestashop>formbuilder_0ba29c6a1afacf586b03a26162c72274'] = 'Ambiente'; +$_MODULE['<{mollie}prestashop>formbuilder_0cbc6611f5540bd0809a388dc95a615b'] = 'Test'; +$_MODULE['<{mollie}prestashop>formbuilder_955ad3298db330b5ee880c2c9e6f23a0'] = 'Live'; +$_MODULE['<{mollie}prestashop>formbuilder_4960b33741696799508da451687efccd'] = 'Test della chiave API'; +$_MODULE['<{mollie}prestashop>formbuilder_0b9b6233430526f6e791aec72fea349e'] = 'Accedi al tuo [1]account Mollie[/1] per ottenere le chiavi API. Iniziano con test e live'; +$_MODULE['<{mollie}prestashop>formbuilder_1460d8f2c6a41fef185dfbf0e09bc83a'] = 'Chiave Live API'; +$_MODULE['<{mollie}prestashop>formbuilder_0408302fc36580b66e3417aa178c7f1c'] = 'Chiave Test API'; +$_MODULE['<{mollie}prestashop>formbuilder_48b55607a3eeefcff54c4ab448f97b19'] = 'Hai già un account Mollie?'; +$_MODULE['<{mollie}prestashop>formbuilder_00d23a76e43b46dae9ec7aa9dcbebb32'] = 'Abilitato'; +$_MODULE['<{mollie}prestashop>formbuilder_b9f5c797ebbf55adccdd8539a65a0241'] = 'Disabilitato'; +$_MODULE['<{mollie}prestashop>formbuilder_9170bcfedaabf0c63ac0c83ce5858dc6'] = 'Puoi trovare la tua chiave API nel tuo [1]Profilo Mollie[/1]'; +$_MODULE['<{mollie}prestashop>formbuilder_646135a12f4ae070d40da46430daaded'] = 'Chiave Live API'; +$_MODULE['<{mollie}prestashop>formbuilder_7d0c43b98588c17b05056fc083510ab9'] = 'Usa Mollie Components per le carte di credito'; +$_MODULE['<{mollie}prestashop>formbuilder_bfc84235d9d3895be4cfa0ee0412af57'] = 'Leggi di più su [1]Mollie Components[/1] e come migliorano la tua conversione'; +$_MODULE['<{mollie}prestashop>formbuilder_909af42213273854f58bea8d7808eb6b'] = 'Leggi di più su Mollie Components e come migliorano la tua conversione'; +$_MODULE['<{mollie}prestashop>formbuilder_9c9958bac135060c84f718c61923e6c5'] = 'Usa i pagamenti con un solo clic per le carte di credito'; +$_MODULE['<{mollie}prestashop>formbuilder_92968265b3faf1ec015af33113d500c0'] = 'Leggi di più sui [1]Pagamenti con un solo clic[/1] e come migliorano la tua conversione'; +$_MODULE['<{mollie}prestashop>formbuilder_0da8d9a75492046bea7f314521e07cae'] = 'Metodi di pagamento'; +$_MODULE['<{mollie}prestashop>formbuilder_74dbaca44b19c1c92febdedec6166a49'] = '[1]Scopri di più[/1] sulle differenze tra Payments API e Orders API.'; +$_MODULE['<{mollie}prestashop>formbuilder_f61403acdc1d08c30cbcf22c618ca269'] = 'Disponibile solo con la tua chiave Live API e Payments API. [1]Per saperne di più[/1] sui codici QR'; +$_MODULE['<{mollie}prestashop>formbuilder_32ab57c87500f2183d67824e6c87b47f'] = 'Usa il locale selezionato nel webshop'; +$_MODULE['<{mollie}prestashop>formbuilder_de0cfd39a173ec704a040cc290a8efe6'] = ' your shop uses the browser\'s locale. '; +$_MODULE['<{mollie}prestashop>formbuilder_038ad19c73f8b677ecbe6c6b20d7629f'] = 'Usa il locale del webshop'; +$_MODULE['<{mollie}prestashop>formbuilder_94ba578e5e5d9aa8a86254825c7e1419'] = 'Usa il locale del browser'; +$_MODULE['<{mollie}prestashop>formbuilder_92096d969b04d49647628839ec4f1135'] = 'Invia l\'e-mail di conferma dell\'ordine'; +$_MODULE['<{mollie}prestashop>formbuilder_14e89590ba118ac8104d558332f0dfcb'] = 'Quando l\'ordine è pagato'; +$_MODULE['<{mollie}prestashop>formbuilder_6e7b34fa59e1bd229b207892956dc41c'] = 'Mai'; +$_MODULE['<{mollie}prestashop>formbuilder_c661f63930e98aaa930c2e9210181844'] = 'Seleziona quando creare la fattura dell\'ordine'; +$_MODULE['<{mollie}prestashop>formbuilder_7a1920d61156abc05a60135aefe8bc67'] = 'Predefinito'; +$_MODULE['<{mollie}prestashop>formbuilder_feb60fbcfdaa2db807f0d1f9e48696b3'] = 'Autorizzato'; +$_MODULE['<{mollie}prestashop>formbuilder_747cf5c8587184b9e489ff897d97c20d'] = 'Spedito'; +$_MODULE['<{mollie}prestashop>formbuilder_7c4e7ada50c8572336f872fced4d1852'] = 'Stato per i pagamenti %s'; +$_MODULE['<{mollie}prestashop>formbuilder_e6bbc38dfcf7ef9277455126a3265ea2'] = 'I pagamenti di `%s` ottengono lo stato di `%s`.'; +$_MODULE['<{mollie}prestashop>formbuilder_c7b8fe7d300a1931137ed822ca0bc039'] = 'Invia un\'e-mail a %s'; +$_MODULE['<{mollie}prestashop>formbuilder_ca8c581b923a595b83808bb3abfe3a1c'] = ' self::FILE_NAME'; +$_MODULE['<{mollie}prestashop>formbuilder_7aace0dc23ee8b74744bdf79c98a2605'] = 'Salta questo stato'; +$_MODULE['<{mollie}prestashop>formbuilder_33af8066d3c83110d4bd897f687cedd2'] = 'Stati dell\'ordine'; +$_MODULE['<{mollie}prestashop>formbuilder_8bfe6d183da9aedb9d813187c08a0983'] = 'Impostazioni visive'; +$_MODULE['<{mollie}prestashop>formbuilder_fff0d600f8a0b5e19e88bfb821dd1157'] = 'Immagini'; +$_MODULE['<{mollie}prestashop>formbuilder_ba5bb6d9e1e2c29692a2a765d8e36219'] = ' normal'; +$_MODULE['<{mollie}prestashop>formbuilder_62a5e490880a92eef74f167d9dc6dca0'] = 'Nascondi'; +$_MODULE['<{mollie}prestashop>formbuilder_960b44c579bc2f6818d2daaf9e4c16f0'] = 'Normale'; +$_MODULE['<{mollie}prestashop>formbuilder_d491538da818a2ba11a3195ba035cfd3'] = 'Grande'; +$_MODULE['<{mollie}prestashop>formbuilder_1547ffc579d657d13fd5fedf12cbfae5'] = 'File CSS'; +$_MODULE['<{mollie}prestashop>formbuilder_13efb943fd692917410355eb926d24a2'] = ' [1]{THEME}[/1]'; +$_MODULE['<{mollie}prestashop>formbuilder_1191f888f0cc23f95aa77aacb094503b'] = 'Informazioni sulla spedizione'; +$_MODULE['<{mollie}prestashop>formbuilder_2526a2ff1547e6fe751081693d8631af'] = 'Spedisci automaticamente sugli stati contrassegnati'; +$_MODULE['<{mollie}prestashop>formbuilder_006a37d93d3c3fb1b097dcf477f84a99'] = 'Abilita per inviare automaticamente le informazioni sulla spedizione quando un ordine ottiene uno stato contrassegnato.'; +$_MODULE['<{mollie}prestashop>formbuilder_c1df8a5243557cbd8a7a31c11aab3db4'] = 'Spedisci automaticamente quando uno di questi stati è raggiunto'; +$_MODULE['<{mollie}prestashop>formbuilder_457407a27f479866bdc59408d4fdc988'] = ' the module automatically sends shipment information'; +$_MODULE['<{mollie}prestashop>formbuilder_498f79c4c5bbde77f1bceb6c86fd0f6d'] = 'Mostra'; +$_MODULE['<{mollie}prestashop>formbuilder_4695fd3a22023ab53a2151f797975ff8'] = 'Disattiva questo stato'; +$_MODULE['<{mollie}prestashop>formbuilder_dc6e4b439165a4e104c9f3cbfcfe2797'] = 'Livello di debug'; +$_MODULE['<{mollie}prestashop>formbuilder_500aa80d6aea3cc9701b566c5f92ed91'] = 'Mostra errori'; +$_MODULE['<{mollie}prestashop>formbuilder_cab709fdb87c17638983cc611a0bd2b9'] = 'Abilita per mostrare i messaggi di errore completi nel negozio online. Utilizza solo per il debugging'; +$_MODULE['<{mollie}prestashop>formbuilder_e5114c4b69585ba5883d456a74c1cd5d'] = 'Livello di log'; +$_MODULE['<{mollie}prestashop>formbuilder_921a6d905eef99631c9c73c317799e62'] = 'Livello raccomandato: Errori. Imposta su Tutto per monitorare le richieste webhook in arrivo. [1]Visualizza i log.[/1]'; +$_MODULE['<{mollie}prestashop>formbuilder_f80a4ad87fee7c9fdc19b7769495fdb5'] = 'Nessuno'; +$_MODULE['<{mollie}prestashop>formbuilder_5ef0c737746fae2ca90e66c39333f8f6'] = 'Errori'; +$_MODULE['<{mollie}prestashop>formbuilder_709468af25e91284821d1bdbfdded24c'] = 'Tutto'; +$_MODULE['<{mollie}prestashop>formbuilder_de62775a71fc2bf7a13d7530ae24a7ed'] = 'Impostazioni generali'; +$_MODULE['<{mollie}prestashop>formbuilder_fe4c6a5e7bd6793b37370e4e46daf998'] = 'Impostazioni avanzate'; +$_MODULE['<{mollie}prestashop>countryservice_b1c94ca2fbc3e78fc30069c8d0f01680'] = 'Tutto'; +$_MODULE['<{mollie}prestashop>mailservice_ed13b3693357ebed3751cb71cb639e65'] = 'Nessun vettore'; +$_MODULE['<{mollie}prestashop>mailservice_fca7e8d1c86db11246e429e40aa10c81'] = 'Nuovo buono per il tuo ordine %s'; +$_MODULE['<{mollie}prestashop>exceptionservice_c2f73af3130be4b4967a475ab846c546'] = 'Si è verificato un errore durante l\'inizializzazione del pagamento. Per favore contatta la nostra assistenza clienti'; +$_MODULE['<{mollie}prestashop>exceptionservice_8fd8f922a86b3622988898a8da551885'] = 'Sembra che hai inserito un formato di numero di telefono errato nel passaggio dell\'indirizzo di fatturazione. Per favore modifica il numero e riprova.'; +$_MODULE['<{mollie}prestashop>exceptionservice_68b9bbd9d890e51e2127e4e90b0b5b5f'] = 'Sembra che hai inserito un formato di numero di telefono errato nel passaggio dell\'indirizzo di spedizione. Per favore modifica il numero e riprova.'; +$_MODULE['<{mollie}prestashop>exceptionservice_108f5defcbead775ce45ff2a78e588e5'] = 'L\'opzione di pagamento scelta non è disponibile per l\'importo totale del tuo ordine. Si prega di considerare un\'altra opzione di pagamento e riprovare.'; +$_MODULE['<{mollie}prestashop>exceptionservice_937929bed64aacbd3993a735493efeef'] = 'Le informazioni sulla spedizione non possono essere inviate. L\'ordine di riferimento (%s) non contiene informazioni di spedizione.'; +$_MODULE['<{mollie}prestashop>exceptionservice_9a0534c60f4e5a21b1f454e768b88870'] = 'Le informazioni sulla spedizione non possono essere inviate. L\'ordine di riferimento (%s) non contiene informazioni di pagamento.'; +$_MODULE['<{mollie}prestashop>exceptionservice_297b3145aec456c3df61ac592533196d'] = 'Le informazioni sulla spedizione non possono essere inviate. L\'ordine di riferimento (%s) è un pagamento regolare.'; +$_MODULE['<{mollie}prestashop>exceptionservice_90d4e1683d6b1745120d0a254d58e4ea'] = 'Eccezione sconosciuta in Mollie'; +$_MODULE['<{mollie}prestashop>settingssaveservice_1f93fc361bfc627c89a46e1b6c28df2b'] = 'La chiave API deve iniziare con test o live.'; +$_MODULE['<{mollie}prestashop>settingssaveservice_3edebc882ca3c4ed5346f3daa6c60f45'] = 'Chiave API sbagliata!'; +$_MODULE['<{mollie}prestashop>settingssaveservice_d0fb18e6788aea02c962decbe15918ab'] = 'Qualcosa è andato storto. Non è stato possibile salvare i metodi di pagamento'; +$_MODULE['<{mollie}prestashop>settingssaveservice_1437630a92a84bc747757e3f1022ee04'] = 'Concedi i permessi per la cartella o visita [1]ApplePay[/1] per vedere come aggiungerli manualmente'; +$_MODULE['<{mollie}prestashop>settingssaveservice_342886361b594a2909b0e3b6bf9a5408'] = ' please try resetting Mollie module.'; +$_MODULE['<{mollie}prestashop>settingssaveservice_6ab1adfed768d989b47c908755fe677f'] = 'La configurazione è stata salvata!'; +$_MODULE['<{mollie}prestashop>refundservice_7d4272540fdafa5fad96a0a6ec5166df'] = 'L\'ordine non poteva essere rimborsato!'; +$_MODULE['<{mollie}prestashop>refundservice_ccb168b5a6a86eb100dc2dee754a316b'] = 'Motivo:'; +$_MODULE['<{mollie}prestashop>refundservice_e12682d2e0650f2783b22d956d2b947a'] = 'L\'ordine è stato rimborsato!'; +$_MODULE['<{mollie}prestashop>refundservice_88928f236ceccc4c2e0f2eb643d85341'] = 'Mollie trasferirà l\'importo al cliente il giorno lavorativo successivo.'; +$_MODULE['<{mollie}prestashop>refundservice_65718b7293759bcf2ca7257aba3d3179'] = 'Non è stato possibile rimborsare i prodotti!'; +$_MODULE['<{mollie}prestashop>languageservice_e0010a0a1a3259ab5c06a19bad532851'] = 'Pagato'; +$_MODULE['<{mollie}prestashop>languageservice_07ca5050e697392c9ed47e6453f1453f'] = 'Completato'; +$_MODULE['<{mollie}prestashop>languageservice_a206428462686af481cb072b8db11784'] = 'Autorizzato'; +$_MODULE['<{mollie}prestashop>languageservice_0e22fe7d45f8e5632a4abf369b24e29c'] = 'Annullato'; +$_MODULE['<{mollie}prestashop>languageservice_24fe48030f7d3097d5882535b04c3fa8'] = 'Scaduto'; +$_MODULE['<{mollie}prestashop>languageservice_cc61945cbbf46721a053467c395c666f'] = 'Rimborsato'; +$_MODULE['<{mollie}prestashop>languageservice_c3bf447eabe632720a3aa1a7ce401274'] = 'Aperto'; +$_MODULE['<{mollie}prestashop>languageservice_c7bece6685d4556fcb8dfdcd72d720f5'] = 'In attesa'; +$_MODULE['<{mollie}prestashop>languageservice_9f004157e4c148dac71da3ae5906351f'] = 'Parzialmente rimborsato'; +$_MODULE['<{mollie}prestashop>languageservice_a7b2273fe3a1293885769855e2f3e6ba'] = 'Chargeback'; +$_MODULE['<{mollie}prestashop>languageservice_020c2091aec3019d02193cef080bcf97'] = 'Commissione di pagamento'; +$_MODULE['<{mollie}prestashop>languageservice_ea9cf7e47ff33b2be14e6dd07cbcefc6'] = 'Spedizione'; +$_MODULE['<{mollie}prestashop>languageservice_484f5a79672cebe198ebdde45a1d672f'] = 'Confezioni regalo'; +$_MODULE['<{mollie}prestashop>languageservice_e2b7dec8fa4b498156dfee6e4c84b156'] = 'Questo metodo di pagamento non è disponibile.'; +$_MODULE['<{mollie}prestashop>cancelservice_324b178753a80ddbe85bc5c2bc64636c'] = 'Non è stato possibile annullare i prodotti!'; +$_MODULE['<{mollie}prestashop>shipservice_0f251428a8b2c8c90b0f8d8bbd6556cd'] = 'Non è stato possibile spedire i prodotti!'; +$_MODULE['<{mollie}prestashop>molliepaymentmailservice_4c35c2333b8091a076a4c2d1db8709e1'] = 'Non è stato possibile creare l\'email di seconda possibilità!'; +$_MODULE['<{mollie}prestashop>molliepaymentmailservice_0c278e7f327f2058a1b759691f838de2'] = 'Non è stato possibile creare un\'email di seconda possibilità - errore API'; +$_MODULE['<{mollie}prestashop>molliepaymentmailservice_f8347b8a83efc618a7d74089a58a351d'] = 'Non è stato possibile inviare l\'email di seconda possibilità! L\'ordine è già stato pagato!'; +$_MODULE['<{mollie}prestashop>molliepaymentmailservice_21ca2c7b403a7963dc174b3892a10bc7'] = 'L\'email di seconda possibilità è stata inviata con successo!'; +$_MODULE['<{mollie}prestashop>molliepaymentmailservice_7d4e9f222469e74d17fde11ca66e587e'] = 'Non è stato possibile inviare l\'email di seconda possibilità! L\'ordine è già stato pagato o è scaduto!'; +$_MODULE['<{mollie}prestashop>orderlistactionbuilder_5678cf484b844064515349752b1ccb18'] = 'Invierai nuovamente un\'email con il link di pagamento al cliente'; +$_MODULE['<{mollie}prestashop>updatemessageprovider_048ef1905ff33382d7660a68a6199305'] = 'Attenzione: Non è stato possibile recuperare il file xml di aggiornamento da github.'; +$_MODULE['<{mollie}prestashop>updatemessageprovider_711d42f319398490b32cd0e2f0b8ccb8'] = 'Attenzione: Il file xml di aggiornamento da github segue un formato inaspettato.'; +$_MODULE['<{mollie}prestashop>idealpaymentoptionprovider_0b135af05e690cf2fca288a143759716'] = 'Commissione di pagamento: %1s'; +$_MODULE['<{mollie}prestashop>bancontactpaymentoptionprovider_0b135af05e690cf2fca288a143759716'] = 'Commissione di pagamento: %1s'; +$_MODULE['<{mollie}prestashop>creditcardpaymentoptionprovider_0b135af05e690cf2fca288a143759716'] = 'Commissione di pagamento: %1s'; +$_MODULE['<{mollie}prestashop>creditcardsingleclickpaymentoptionprovider_0b135af05e690cf2fca288a143759716'] = 'Commissione di pagamento: %1s'; +$_MODULE['<{mollie}prestashop>basepaymentoptionprovider_0b135af05e690cf2fca288a143759716'] = 'Commissione di pagamento: %1s'; +$_MODULE['<{mollie}prestashop>createapplepayorderhandler_01d98a6c787e997dcb1c2e65935dcea2'] = 'Non è stato possibile creare una transazione Mollie.'; +$_MODULE['<{mollie}prestashop>createapplepayorderhandler_f551e100249d06979879b69762f7370e'] = 'Non è stato possibile trovare l\'ordine corrispondente al carrello.'; +$_MODULE['<{mollie}prestashop>installer_8aef54a7e234af543698d0eb818e576a'] = 'Non è stato possibile installare gli stati di Mollie'; +$_MODULE['<{mollie}prestashop>installer_2a1cc1f6a56903156703cf4f997a640f'] = 'Non è stato possibile installare config'; +$_MODULE['<{mollie}prestashop>installer_a473868cd56c59f4cee5d511a29ef3f8'] = 'Non è stato possibile installare gli stati predefiniti del vettore'; +$_MODULE['<{mollie}prestashop>installer_77240e73b3e9b64c47052880f87b6a8b'] = 'Non è stato possibile installare gli attributi del voucher'; +$_MODULE['<{mollie}prestashop>installer_407748408f99fed49e067dee67df619c'] = 'Non è stato possibile copiare i modelli di email:'; +$_MODULE['<{mollie}prestashop>applepaydirectcertificatehandler_5e3e4ef8f2ed24f34757f4bea44660d6'] = 'Non è stato possibile creare una directory per il certificato apple pay direct'; +$_MODULE['<{mollie}prestashop>applepaydirectcertificatehandler_6d1a1343d17c6e8aa72d0e4c7b0fe6a6'] = 'Non è stato possibile creare una cartella perché mancano i permessi di scrittura:'; +$_MODULE['<{mollie}prestashop>applepaydirectcertificatehandler_4b2c49344e2ee0dfb2fe0187e85006b5'] = 'Non è stato possibile copiare il certificato apple pay direct'; +$_MODULE['<{mollie}prestashop>adminmollieajaxcontroller_0753ca16446b5bbb04afc9e00a079415'] = 'Carica un file .jpg o .png.'; +$_MODULE['<{mollie}prestashop>adminmollieajaxcontroller_bfe103d948d5f7e7126aa1a13220d79e'] = 'Si è verificato un errore durante il caricamento del tuo logo.'; +$_MODULE['<{mollie}prestashop>adminmollieajaxcontroller_19db85bb27b89b6db9c3d46295710160'] = 'Nessuna commissione è stata inviata.'; +$_MODULE['<{mollie}prestashop>adminmollieajaxcontroller_038385a2334e67fa21ec3f7fcb08fa12'] = 'Commissione non valida'; +$_MODULE['<{mollie}prestashop>adminmollieajaxcontroller_2969822535b8feef4920d105ae37ec6a'] = 'ID gruppo regole fiscali mancante'; +$_MODULE['<{mollie}prestashop>adminmolliesettingscontroller_329d067eb590f966ceeaed2bacf99d8e'] = 'Per favore aggiorna il modulo Mollie'; +$_MODULE['<{mollie}prestashop>adminmolliesettingscontroller_4a0df35e9183f634bdfda31938430cf4'] = 'Seleziona il negozio che vuoi configurare'; +$_MODULE['<{mollie}prestashop>adminmolliesettingscontroller_56ce2a4e08c9d84441b90ab4c4b66f84'] = 'Selezionare lo stato dell\'ordine per "Stato in attesa di pagamento" nella scheda "Impostazioni avanzate".'; +$_MODULE['<{mollie}prestashop>adminmolliesettingscontroller_a50d3d131d9daa7a4bbc3dc0aa71eeec'] = 'Inserisci una descrizione.'; +$_MODULE['<{mollie}prestashop>adminmolliesettingscontroller_79e5e3c4ae741f839d9fba86491af0bd'] = 'L\'importo minimo inserito non è corretto.'; +$_MODULE['<{mollie}prestashop>adminmolliesettingscontroller_9f828c1c1bfd9a00710a62b9db1ae9f0'] = 'L\'importo massimo inserito non è corretto'; +$_MODULE['<{mollie}prestashop>adminmolliesettingscontroller_dc89c7013e3451362e42e6507e9495c5'] = 'Carica un\'immagine %s%x%s1%'; +$_MODULE['<{mollie}prestashop>adminmolliesettingscontroller_29c9f9173adc3f11dce098b8095234bc'] = 'File non valido: %s%'; +$_MODULE['<{mollie}prestashop>adminmolliesettingscontroller_6c8c16f8a394066a8f3f0a56597eb56a'] = 'Le tabelle del database sono mancanti. Reimposta il modulo.'; +$_MODULE['<{mollie}prestashop>ajax_96b0141273eabab320119c467cdcaf17'] = 'Totale'; +$_MODULE['<{mollie}prestashop>ajax_adc852563bca51fb6b10c7905010406d'] = 'Totale (tasse incluse)'; +$_MODULE['<{mollie}prestashop>ajax_8faf99e02e4d0ccb4dd933404f87a4ea'] = 'Totale (tasse escluse)'; +$_MODULE['<{mollie}prestashop>ajax_f6b587bf6c679ef85d87081927d93836'] = 'Attenzione: è possibile aggiungere al carrello un solo prodotto in abbonamento alla volta.'; +$_MODULE['<{mollie}prestashop>ajax_37978ed65eed73bebb3e77f81b3eb645'] = 'Il servizio di abbonamento è disattivato. Modifica l\'attributo a Abbonamento: nessuno.'; +$_MODULE['<{mollie}prestashop>ajax_95519f54dae99dd8640138bf750a2179'] = 'Errore sconosciuto. Riprova o modifica l\'attributo a Abbonamento: nessuno.'; +$_MODULE['<{mollie}prestashop>recurringorderdetail_719998bd6f56db26319fa391238b21ac'] = 'Errore: token non valido.'; +$_MODULE['<{mollie}prestashop>recurringorderdetail_d9db35b2599c7346411609d265ef48fe'] = 'Non è stato possibile ottenere il nuovo metodo di pagamento.'; +$_MODULE['<{mollie}prestashop>recurringorderdetail_669d84e5441cf94ef5ad7e454f862fc8'] = 'Non è stato possibile ottenere un ordine ricorrente.'; +$_MODULE['<{mollie}prestashop>recurringorderdetail_ace46baf149d2cd3e72e9e2d7e9030dd'] = 'L\'abbonamento è stato annullato con successo.'; +$_MODULE['<{mollie}prestashop>payment_70f9483ea2c46793fa11a5e1db1ba26f'] = 'Si è verificato un errore durante la creazione del pagamento. Contatta l\'assistenza clienti.'; +$_MODULE['<{mollie}prestashop>payment_e6147f750d52d1483872fd56ff219067'] = 'Non è stato possibile salvare le informazioni dell\'ordine.'; +$_MODULE['<{mollie}prestashop>return_4800c6edcc3810ee9c82cb22083c9f2e'] = 'Non esiste un ordine con questo ID.'; +$_MODULE['<{mollie}prestashop>return_56a6035a7e7c1e1afa8169517367462d'] = 'Il pagamento è ancora in fase di elaborazione. Riceverà una notifica quando la banca o il commerciante confermeranno il pagamento./commerciante.'; +$_MODULE['<{mollie}prestashop>return_5c9322dc182e8bea0b6c472495469227'] = 'Non sei autorizzato a visualizzare questa pagina.'; +$_MODULE['<{mollie}prestashop>return_4eb09eb8686ff437b3d31cd5aa2f5bbf'] = 'Il pagamento non è andato a buon fine. Riprova.'; +$_MODULE['<{mollie}prestashop>return_e854fe62ab224e46276912a3514ca2b0'] = 'Il pagamento non è riuscito perché gli importi dell\'ordine e del pagamento sono diversi. Riprova.'; +$_MODULE['<{mollie}prestashop>return_b34487c5f391f47b893ee3c61f8f9ab7'] = 'Non abbiamo ricevuto uno stato di pagamento definitivo. Riceverai una notifica non appena riceveremo la conferma dalla banca/commerciante.'; +$_MODULE['<{mollie}prestashop>api_test_results_7e3305352e66d78619cf51140c3d77a7'] = 'Chiave Test API: Fallita! La chiave deve iniziare con test_'; +$_MODULE['<{mollie}prestashop>api_test_results_8b4a27e207907c6eae2af4c520ed6847'] = 'Chiave Test API: Riuscita!'; +$_MODULE['<{mollie}prestashop>api_test_results_06c42c0313dd08aa55b929e9611e9180'] = 'Metodi abilitati:'; +$_MODULE['<{mollie}prestashop>api_test_results_d08f64a86a82229769819777bc1867a7'] = 'Chiave Test API: Fallita! La chiave non esiste.'; +$_MODULE['<{mollie}prestashop>api_test_results_a4f4ff12086e1ed2e2a08e44f40bee7e'] = 'Chiave Live API: Fallita! La chiave deve iniziare con live_.'; +$_MODULE['<{mollie}prestashop>api_test_results_2360a37494efa46ba19353f395759f61'] = 'Chiave Live API: Riuscita!'; +$_MODULE['<{mollie}prestashop>api_test_results_d8ee1e19be219a7bd9b234f04637e439'] = 'Chiave Live API: Fallita! La chiave non esiste.'; +$_MODULE['<{mollie}prestashop>invoice_description_c661f63930e98aaa930c2e9210181844'] = 'Seleziona quando creare la fattura dell\'ordine'; +$_MODULE['<{mollie}prestashop>invoice_description_5aa6fbc3548a8e2925de1e8e69897d34'] = 'Predefinito: La fattura viene creata in base alle Impostazioni dell\'ordine > Stati. Non viene creato uno stato personalizzato.'; +$_MODULE['<{mollie}prestashop>invoice_description_cd2e6d0dbf60a94bb38b522ac80ee9eb'] = 'Autorizzato: Crea una fattura completa quando l\'ordine è autorizzato. Viene creato uno stato personalizzato.'; +$_MODULE['<{mollie}prestashop>invoice_description_fc397a4bb3def49c285df7311261498d'] = 'Alla spedizione: Crea una fattura completa quando l\'ordine viene spedito. Viene creato uno stato personalizzato.'; +$_MODULE['<{mollie}prestashop>invoice_fee_020c2091aec3019d02193cef080bcf97'] = 'Commissione di pagamento'; +$_MODULE['<{mollie}prestashop>email_checkbox_b78daad7755ecce594af1e90afc0c2a9'] = 'Invia un\'e-mail di pagamento al cliente. (Verrà inviata dopo la creazione dell\'ordine)'; +$_MODULE['<{mollie}prestashop>new_release_584b9a7e2030fae4a7ddae4d5825bd99'] = 'Stai attualmente utilizzando la versione %s di questo modulo. L\'ultima versione è %s.'; +$_MODULE['<{mollie}prestashop>new_release_fcf6bb33e06a5cdf71a4a630ab9451f8'] = '[1]Aggiorna[/1] il modulo per usufruire delle ultime funzionalità.'; +$_MODULE['<{mollie}prestashop>create_new_account_link_936ccdb97115e9f35a11d35e3d5b5cad'] = 'Clicca qui'; +$_MODULE['<{mollie}prestashop>create_new_account_link_6e339c3dbc6cbc279b54ffb5e8292884'] = 'per creare un account'; +$_MODULE['<{mollie}prestashop>form_26ce015f99bef6d5de2142b2b774525f'] = 'Sviluppato da Invertus'; +$_MODULE['<{mollie}prestashop>form_1c04b154909c88cfc62b3362c88445af'] = '- l\'agenzia più avanzata tecnicamente dell\'ecosistema PrestaShop.'; +$_MODULE['<{mollie}prestashop>form_0f13aa29b5bc9e8a1b6597dc5987ea46'] = 'Vai al centro di assistenza Mollie'; +$_MODULE['<{mollie}prestashop>form_1c2e79c1715dbe3f3208a7991abc50f0'] = 'Contatta Mollie'; +$_MODULE['<{mollie}prestashop>form_2d059d2c499450d4e083d28f5f47f63d'] = 'Contatta Invertus'; +$_MODULE['<{mollie}prestashop>form_00d23a76e43b46dae9ec7aa9dcbebb32'] = 'Abilitato'; +$_MODULE['<{mollie}prestashop>form_bafd7322c6e97d25b6299b5d6fe8920b'] = 'No'; +$_MODULE['<{mollie}prestashop>form_93cba07454f06a4a960172bbd6e2a435'] = 'Sì'; +$_MODULE['<{mollie}prestashop>form_b61254f89b6f2ef061fb628f04a93fe8'] = 'Pagina del prodotto Apple Pay Direct'; +$_MODULE['<{mollie}prestashop>form_9fa70bd7cc082c6eafd9f6c04782de2c'] = 'Pagina del carrello Apple Pay Direct'; +$_MODULE['<{mollie}prestashop>form_020f1a50a78b13a12f304d64dda57020'] = 'Stile del pulsante Apple Pay Direct'; +$_MODULE['<{mollie}prestashop>form_9c12f952ca3695bb3043ddcc0ceaaf80'] = 'Codice QR'; +$_MODULE['<{mollie}prestashop>form_b78a3223503896721cca1303f776159b'] = 'Titolo'; +$_MODULE['<{mollie}prestashop>form_4c3880bb027f159e801041b1021e88e8'] = 'Metodo'; +$_MODULE['<{mollie}prestashop>form_8c2b4949d892b39b236545951f10bbd4'] = 'Payments API'; +$_MODULE['<{mollie}prestashop>form_a8b0255f70ecc140a1b5134ae5217e51'] = 'Orders API'; +$_MODULE['<{mollie}prestashop>form_cb6c048266284ce0a4036f435849e7d1'] = 'Descrizione della transazione'; +$_MODULE['<{mollie}prestashop>form_049068ab66bb1411469a8399aa624a29'] = 'Utilizza una delle seguenti variabili per creare una descrizione della transazione per i pagamenti che utilizzano questo metodo:'; +$_MODULE['<{mollie}prestashop>form_9e9e2ae89ca753fd8529d1af55867f2d'] = 'Accetta pagamenti da:'; +$_MODULE['<{mollie}prestashop>form_c3987e4cac14a8456515f0d200da04ee'] = 'Tutti i paesi'; +$_MODULE['<{mollie}prestashop>form_7c160ccb02560f1adb25fb6b86d9ebce'] = 'Paesi selezionati'; +$_MODULE['<{mollie}prestashop>form_82dae25b510c71eeeb41e72f005977fc'] = 'Accetta pagamenti da paesi specifici:'; +$_MODULE['<{mollie}prestashop>form_43c7d89bbf53d68bea0c63205848d87a'] = 'Escludi i pagamenti da paesi specifici:'; +$_MODULE['<{mollie}prestashop>form_020c2091aec3019d02193cef080bcf97'] = 'Commissione di pagamento'; +$_MODULE['<{mollie}prestashop>form_87ab78d85f4f0f5143ed2e549719bc45'] = 'Nessuna commissione'; +$_MODULE['<{mollie}prestashop>form_dc7d3d42b2b2b79bf2711799b38f2543'] = 'Commissione fissa'; +$_MODULE['<{mollie}prestashop>form_37be07209f53a5d636d5c904ca9ae64c'] = 'Percentuale'; +$_MODULE['<{mollie}prestashop>form_9e984321e77b6a6ce8ef2844df646085'] = 'Limite supplemento pagamento combinato'; +$_MODULE['<{mollie}prestashop>form_a6e220d6f8929d250e7637c45f4f781f'] = 'Aggiungere \(payment_fee}} nelle traduzioni e-mail per visualizzarle nel suo modello di e-mail. Per ulteriori informazioni'; +$_MODULE['<{mollie}prestashop>form_0b8d92bc19b720bb1065649535463409'] = 'Traduzioni'; +$_MODULE['<{mollie}prestashop>form_06c01c4462adf64483f4563530b5fea4'] = 'Includi le tasse nella commissione totale del pagamento'; +$_MODULE['<{mollie}prestashop>form_cc5aba4e257ea02c1f8b8b566eab0d81'] = 'Commissione fissa (tasse incluse)'; +$_MODULE['<{mollie}prestashop>form_3e2843c31ec8d64ed7731733c0a8776c'] = 'Commissione fissa (tasse escluse)'; +$_MODULE['<{mollie}prestashop>form_74dfbb3dcf80ca484183092d1ec4c6fc'] = 'Gruppo regole fiscali per commissione fissa'; +$_MODULE['<{mollie}prestashop>form_e457ab8b899c330b05e1bbe6539a50df'] = 'Quota percentuale'; +$_MODULE['<{mollie}prestashop>form_a1eeaac9cc0281aa432a7503fd79c340'] = 'Commissione massima'; +$_MODULE['<{mollie}prestashop>form_80a2645c681d607705f5baab7cf7d2cb'] = 'Importo minimo'; +$_MODULE['<{mollie}prestashop>form_a14ecf18ea57e0ae5ebcd930102d7cbd'] = 'L\'importo minimo predefinito in Mollie è:'; +$_MODULE['<{mollie}prestashop>form_7d48ddaff550ef9e47ed788f50d860e7'] = 'Importo massimo'; +$_MODULE['<{mollie}prestashop>form_8e680f4d04edd57a82330efe361bf3a6'] = 'L\'importo massimo predefinito non ha limitazioni'; +$_MODULE['<{mollie}prestashop>form_521c2e0375d1b1266cbb0418d5ff32a9'] = 'L\'importo massimo predefinito in Mollie è:'; +$_MODULE['<{mollie}prestashop>form_d91f2eea3f7396346614c62eac89544a'] = 'Usa un logo personalizzato'; +$_MODULE['<{mollie}prestashop>form_285cd00bd164be38b93c8a198155f12f'] = 'Carica un logo personalizzato'; +$_MODULE['<{mollie}prestashop>form_58be4de806253a6ee411b6c0c99296c7'] = 'Aggiungi file'; +$_MODULE['<{mollie}prestashop>form_4babe7767cf1639749b60d70ffaf6571'] = 'Utilizza un file .png o .jpg fino a 256x64 pixel.'; +$_MODULE['<{mollie}prestashop>form_37b9d37be8a47e970b04fe5c29ff77c7'] = 'Il tuo logo personalizzato'; +$_MODULE['<{mollie}prestashop>form_3adbdb3ac060038aa0e6e6c138ef9873'] = 'Categoria'; +$_MODULE['<{mollie}prestashop>form_6adf97f83acf6453d4a6a4b1070f3754'] = 'Nessuno'; +$_MODULE['<{mollie}prestashop>form_d9ed7694f0cdbc0ce83246bc1db2d789'] = 'pasto'; +$_MODULE['<{mollie}prestashop>form_a0ec3b461abf4bc16ad615481260140e'] = 'regalo'; +$_MODULE['<{mollie}prestashop>form_e434dd9c7f573fb03924e0c4d3d44d45'] = 'eco'; +$_MODULE['<{mollie}prestashop>form_8e7a0855b5c921c5172c41d27047b446'] = 'Seleziona una categoria da utilizzare per tutti i prodotti del suo webshop'; +$_MODULE['<{mollie}prestashop>form_f12cef06d777d5540450d316354948ae'] = 'Configura le informazioni sulla spedizione da inviare a Mollie'; +$_MODULE['<{mollie}prestashop>form_078436e14998fc6f6b6668ac2f523bbb'] = 'Puoi usare le seguenti variabili per gli URL del vettore'; +$_MODULE['<{mollie}prestashop>form_910d956cb2615e5739ac06c7f08fba26'] = 'Numero di spedizione'; +$_MODULE['<{mollie}prestashop>form_e7e862a02819a1610f271ffea15ed47d'] = 'Codice paese di fatturazione'; +$_MODULE['<{mollie}prestashop>form_5723a18d8a8a6052a57489df5be59a8f'] = 'Codice postale di fatturazione'; +$_MODULE['<{mollie}prestashop>form_0d12e3c554976ad1f76c5db2b6c127ad'] = 'Codice del paese di spedizione'; +$_MODULE['<{mollie}prestashop>form_c824a8b18f09dc7e58bacf446be6735c'] = 'Codice postale di spedizione'; +$_MODULE['<{mollie}prestashop>form_0a867177f4a701a9f33de5ab21c42593'] = 'Codice lingua a 2 lettere'; +$_MODULE['<{mollie}prestashop>form_49ee3087348e8d44e1feda1917443987'] = 'Nome'; +$_MODULE['<{mollie}prestashop>form_cefb9190a0a2b3301f3e4d44ad14e6c0'] = 'Fonte URL'; +$_MODULE['<{mollie}prestashop>form_812a48ba719daeda82e4da8e812d426c'] = 'URL personalizzato'; +$_MODULE['<{mollie}prestashop>form_962b59a5f12eabd9c05f11b5f0aada85'] = 'Non spedire automaticamente'; +$_MODULE['<{mollie}prestashop>form_703490ffd308d337cd5aac50567e9670'] = 'Nessuna informazione sulla tracciabilità'; +$_MODULE['<{mollie}prestashop>form_de28ef21a06f3978c05f3d808b15eaab'] = 'URL del vettore'; +$_MODULE['<{mollie}prestashop>form_e55f75a29310d7b60f7ac1d390c8ae42'] = 'Modulo'; +$_MODULE['<{mollie}prestashop>form_da93de158db2fbe49f35f6038711584a'] = 'Questa opzione non è necessaria per l\'API attualmente selezionato.'; +$_MODULE['<{mollie}prestashop>form_218fb15ca7f2db8aa36080323a038828'] = 'Questa opzione non è necessaria per l\'API selezionata'; +$_MODULE['<{mollie}prestashop>form_498f79c4c5bbde77f1bceb6c86fd0f6d'] = 'Mostra'; +$_MODULE['<{mollie}prestashop>form_62a5e490880a92eef74f167d9dc6dca0'] = 'Nascondi'; +$_MODULE['<{mollie}prestashop>form_c266b1bce5e949cf41b5951f747862a5'] = 'Nessun metodo di pagamento Mollie ancora abilitato'; +$_MODULE['<{mollie}prestashop>form_27079483c3ba47b2c7369723473c4950'] = 'Attiva i metodi di pagamento nel tuo account Mollie.'; +$_MODULE['<{mollie}prestashop>form_f1206f9fadc5ce41694f69129aecac26'] = 'Configura'; +$_MODULE['<{mollie}prestashop>form_20d053df791cc72594d141b24276597f'] = 'Scorri verso il basso e salva le modifiche apportate al tuo ambiente o alle chiavi API prima di configurare i metodi di pagamento.'; +$_MODULE['<{mollie}prestashop>order_info_729a51874fe901b092899e9e8b31c97a'] = 'Sei sicuro?'; +$_MODULE['<{mollie}prestashop>order_info_ccaf4ee393d094ecde7f21b15fdf8f1f'] = 'Sei sicuro di voler rimborsare questo ordine?'; +$_MODULE['<{mollie}prestashop>order_info_76f0ed934de85cc7131910b32ede7714'] = 'Rimborso'; +$_MODULE['<{mollie}prestashop>order_info_ea4788705e6873b424c65e91c2846b19'] = 'Annulla'; +$_MODULE['<{mollie}prestashop>order_info_88ba0dcbc82905637e98317e0302cfd8'] = 'Rimborsa ordine'; +$_MODULE['<{mollie}prestashop>order_info_e03ed4aabeff96ca7c80a6bae8ddfcc1'] = 'Rimborsabile'; +$_MODULE['<{mollie}prestashop>order_info_77fd2b4393b379bedd30efcd5df02090'] = 'Rimborso parziale'; +$_MODULE['<{mollie}prestashop>order_info_a9ced76f2dd6907220fa95b3a136b04a'] = 'Importo non valido'; +$_MODULE['<{mollie}prestashop>order_info_a0114b0c8ef3e187c610e4e56da55872'] = 'Inserisci un importo valido'; +$_MODULE['<{mollie}prestashop>order_info_3cc4859e502556d0d848c3bc38618782'] = 'Rimborso non riuscito'; +$_MODULE['<{mollie}prestashop>order_info_d5cfd0f69cd548e5d3b9edde5ff1b48f'] = 'Informazioni sul pagamento'; +$_MODULE['<{mollie}prestashop>order_info_88427ec035734b45aae9f7d8859a5008'] = 'ID transazione'; +$_MODULE['<{mollie}prestashop>order_info_782678f4ba02feb3e9ecd51e902cd16b'] = 'Cronologia dei rimborsi'; +$_MODULE['<{mollie}prestashop>order_info_c5b41ae59bd6585750f536615a6bc20b'] = 'Non ci sono rimborsi'; +$_MODULE['<{mollie}prestashop>order_info_b718adec73e04ce3ec720dd11a06a308'] = 'ID'; +$_MODULE['<{mollie}prestashop>order_info_44749712dbec183e983dcd78a7736c41'] = 'Data'; +$_MODULE['<{mollie}prestashop>order_info_b2f40690858b404ed10e62bdf422c704'] = 'Importo'; +$_MODULE['<{mollie}prestashop>order_info_53beb26d8bca00f56fbd295fdee83459'] = 'Rimborsi'; +$_MODULE['<{mollie}prestashop>order_info_daef64964ee3b9b904f5d467586e217f'] = 'Pagamenti'; +$_MODULE['<{mollie}prestashop>order_info_e25be354288565757726f3295e4f3ef9'] = 'Importo attuale'; +$_MODULE['<{mollie}prestashop>order_info_068f80c7519d0528fb08e82137a72131'] = 'Prodotti'; +$_MODULE['<{mollie}prestashop>order_info_ec53a8c4f07baed5d8825072c89799be'] = 'Stato'; +$_MODULE['<{mollie}prestashop>order_info_747cf5c8587184b9e489ff897d97c20d'] = 'Spedito'; +$_MODULE['<{mollie}prestashop>order_info_0e22fe7d45f8e5632a4abf369b24e29c'] = 'Annullato'; +$_MODULE['<{mollie}prestashop>order_info_cc61945cbbf46721a053467c395c666f'] = 'Rimborsato'; +$_MODULE['<{mollie}prestashop>order_info_6c957f72dc8cdacc75762f2cbdcdfaf2'] = 'Prezzo unitario'; +$_MODULE['<{mollie}prestashop>order_info_126b36c5eb7a576cd6ae15bbcf3a9459'] = 'Importo IVA'; +$_MODULE['<{mollie}prestashop>order_info_bc30768048a7bbfd2d158d722c140c6d'] = 'Importo totale'; +$_MODULE['<{mollie}prestashop>order_info_0387832795db3eb2e05f4365fba5ddac'] = 'Spedisci'; +$_MODULE['<{mollie}prestashop>order_info_55453aad10c96e452556a106447313bd'] = 'Rivedi spedizione'; +$_MODULE['<{mollie}prestashop>order_info_2d68a678f279a6a1fade94ef7bef9e67'] = 'Esamina i prodotti inclusi nella spedizione. Puoi rimuovere gli articoli o modificare la quantità'; +$_MODULE['<{mollie}prestashop>order_info_e29500a07ea67b3f9b48c85bccece022'] = 'Rivedi rimborso'; +$_MODULE['<{mollie}prestashop>order_info_63e6dc84e5605dc561a14e7f86643bbb'] = 'Esamina i prodotti inclusi nel rimborso. Se necessario'; +$_MODULE['<{mollie}prestashop>order_info_51de729ebc17bf6c37d2708ba317dd08'] = 'Rivedi annullamento'; +$_MODULE['<{mollie}prestashop>order_info_50317d996a7817c56aac958f4042680e'] = 'Esamina i prodotti inclusi nel annullamento. Se necessario'; +$_MODULE['<{mollie}prestashop>order_info_e0aa021e21dddbd6d8cecec71e9cf564'] = 'OK'; +$_MODULE['<{mollie}prestashop>order_info_163bcc6065b16c6369c7a4de44cff164'] = 'Spedisci prodotti'; +$_MODULE['<{mollie}prestashop>order_info_433557a938a920888445ce2c7df67d5a'] = 'Dettagli di tracciamento'; +$_MODULE['<{mollie}prestashop>order_info_50399bf464ce4b79ed9f58f63d9376e7'] = 'Aggiungi le informazioni di tracciamento per registrare la spedizione dei prodotti al cliente.'; +$_MODULE['<{mollie}prestashop>order_info_26b6254fefc06894825a50dfbe803937'] = 'Salta i dettagli di tracciamento'; +$_MODULE['<{mollie}prestashop>order_info_d57c24f3fe52d16e7169b912dd647f0d'] = 'opzionale'; +$_MODULE['<{mollie}prestashop>order_info_2df417909bda5f3ddc210a0abe65231f'] = 'Ad esempio FedEx'; +$_MODULE['<{mollie}prestashop>order_info_593ed3a37aa1a3ece4a4d796fb4e2e03'] = 'Queste informazioni sono necessarie'; +$_MODULE['<{mollie}prestashop>order_info_933292561b46133ff5348c7740874c56'] = 'Codice di tracciamento'; +$_MODULE['<{mollie}prestashop>order_info_e6b391a8d2c4d45902a23a8b6585703d'] = 'URL'; +$_MODULE['<{mollie}prestashop>order_info_914419aa32f04011357d3b604a86d7eb'] = 'Vettore'; +$_MODULE['<{mollie}prestashop>order_info_23a902ac637359fe67ceaccbe2c68283'] = 'Spedisci tutto'; +$_MODULE['<{mollie}prestashop>order_info_2a6e9f678c7267fe16f57bcd3285f1d7'] = 'Annulla tutto'; +$_MODULE['<{mollie}prestashop>order_info_05ced64413f9ff5d3602c3e257f36204'] = 'Rimborsa tutto'; +$_MODULE['<{mollie}prestashop>order_info_bfe005bff7ecacd6ecceacdd7fb79292'] = 'Informazioni sulla transazione'; +$_MODULE['<{mollie}prestashop>order_info_61066fef1e8173dc711f55bbedb8839c'] = 'Informazioni sul buono'; +$_MODULE['<{mollie}prestashop>order_info_1eefa98a18a384699fe611fbfd8ab0c9'] = 'Non ci sono prodotti'; +$_MODULE['<{mollie}prestashop>order_info_a25c753ee3e4be15ec0daa5a40deb7b8'] = 'Si è verificato un errore'; +$_MODULE['<{mollie}prestashop>order_info_2df3102f3fe061003dee820a72e1b1ed'] = 'Non è stato possibile spedire'; +$_MODULE['<{mollie}prestashop>order_info_3efc29552025b4e68de04f415b0b8806'] = 'Non è stato possibile rimborsare'; +$_MODULE['<{mollie}prestashop>order_info_468a92810b526750be9664461db6bf91'] = 'Non è stato possibile annullare'; +$_MODULE['<{mollie}prestashop>order_info_2427b479f15af44582dc151ef95a90d0'] = 'I rimborsi non sono attualmente disponibili'; +$_MODULE['<{mollie}prestashop>order_info_20c72bbfdf74d618a4b8a11100e864a0'] = 'Il rimborso è stato effettuato con successo!'; +$_MODULE['<{mollie}prestashop>order_info_c7eb2a728623db5eedf0e12d21ffa604'] = 'La spedizione è stata effettuata con successo!'; +$_MODULE['<{mollie}prestashop>order_info_fab41c52197c448eea0edde8951e4e59'] = 'L\'ordine è stato annullato con successo!'; +$_MODULE['<{mollie}prestashop>order_info_4c3880bb027f159e801041b1021e88e8'] = 'Metodo'; +$_MODULE['<{mollie}prestashop>order_info_51360304ea03557e79bdf5ff9cd2e234'] = 'Emittente'; +$_MODULE['<{mollie}prestashop>order_info_4e274e8865560b88192b72e486210cc6'] = 'Questo ordine è stato (parzialmente) pagato con un buono. Puoi rimborsare un massimo di %1s.'; +$_MODULE['<{mollie}prestashop>mollie_awaiting_order_status_error_56ce2a4e08c9d84441b90ab4c4b66f84'] = 'Seleziona uno stato d\'ordine per \Stato per in attesa di pagamento\ nella scheda \Impostazioni avanzate\.'; +$_MODULE['<{mollie}prestashop>mollie_single_click_ee2b8214cd8479d18e873181505b48ea'] = 'Usa la carta salvata'; +$_MODULE['<{mollie}prestashop>mollie_single_click_fc7775bdfa339217149389b7392af83b'] = 'Salva la carta'; +$_MODULE['<{mollie}prestashop>mollie_single_click_49753ba0559e716a708373951ea87d1c'] = 'Pagamenti sicuri forniti da'; +$_MODULE['<{mollie}prestashop>mollie_iframe_a4b29064de828b87f9f9b6fa145cb507'] = 'Inserisci i dati della tua carta'; +$_MODULE['<{mollie}prestashop>mollie_iframe_c2b63e85bd5e4dc9b6cf5a4693847e06'] = 'Nome sulla carta'; +$_MODULE['<{mollie}prestashop>mollie_iframe_a44217022190f5734b2f72ba1e4f8a79'] = 'Numero di carta'; $_MODULE['<{mollie}prestashop>mollie_iframe_95b16127e70e8a90220404fb48343182'] = 'Data di scadenza'; $_MODULE['<{mollie}prestashop>mollie_iframe_b2fddfad59392b3dba82cb9809712197'] = 'CVC/CVV'; $_MODULE['<{mollie}prestashop>mollie_iframe_fc7775bdfa339217149389b7392af83b'] = 'Salva la carta'; -$_MODULE['<{mollie}prestashop>mollie_iframe_ee2b8214cd8479d18e873181505b48ea'] = 'Utilizzare la carta salvata/registrata'; +$_MODULE['<{mollie}prestashop>mollie_iframe_ee2b8214cd8479d18e873181505b48ea'] = 'Usa la carta salvata'; $_MODULE['<{mollie}prestashop>mollie_iframe_49753ba0559e716a708373951ea87d1c'] = 'Pagamenti sicuri forniti da'; +$_MODULE['<{mollie}prestashop>payment_334721e5f1ee825da687fcaede010724'] = 'Commissione di pagamento:'; +$_MODULE['<{mollie}prestashop>qr_code_abf4a6b673b5166357317067cbeadee9'] = 'Scansiona codice QR'; +$_MODULE['<{mollie}prestashop>qr_code_9e8480dfad348fb6f83db31570d1decf'] = 'Apri l\'app Bancontact per scansionare il codice QR'; +$_MODULE['<{mollie}prestashop>qr_code_3a2d5fe857d8f9541136a124c2edec6c'] = 'O'; +$_MODULE['<{mollie}prestashop>qr_code_fc258b840545ee1ec431efe82bd4dcbd'] = 'Continua senza codice QR'; +$_MODULE['<{mollie}prestashop>qr_code_ea4788705e6873b424c65e91c2846b19'] = 'Annulla'; +$_MODULE['<{mollie}prestashop>order-confirmation-table_020c2091aec3019d02193cef080bcf97'] = 'Commissione di pagamento'; +$_MODULE['<{mollie}prestashop>17_error_47e1924c444fafe9fdfce444790f0ba9'] = 'Torna al carrello'; +$_MODULE['<{mollie}prestashop>error_c453a4b8e8d98e82f35b67f433e3b4da'] = 'Pagamento'; +$_MODULE['<{mollie}prestashop>error_1e97d97a923eaddd810e056c828e99ea'] = 'Errore di pagamento'; +$_MODULE['<{mollie}prestashop>error_a25c753ee3e4be15ec0daa5a40deb7b8'] = 'Si è verificato un errore'; +$_MODULE['<{mollie}prestashop>error_47e1924c444fafe9fdfce444790f0ba9'] = 'Torna al carrello'; +$_MODULE['<{mollie}prestashop>order_fail_28726b6ad52c9eae94be432666f93449'] = 'L\'ordine è stato annullato'; +$_MODULE['<{mollie}prestashop>mollie_return_ebdf0f490b617d7efa3025d3625cec85'] = 'Bentornato'; +$_MODULE['<{mollie}prestashop>mollie_return_300225ee958b6350abc51805dab83c24'] = 'Continua gli acquisti'; +$_MODULE['<{mollie}prestashop>mollie_wait_bc0dd919f9a70dbb62f3f7afd68d6d68'] = 'In attesa dello stato di pagamento'; +$_MODULE['<{mollie}prestashop>qr_done_92816c7248d010591f699db3aaf6287b'] = 'Mollie iDEAL QR'; +$_MODULE['<{mollie}prestashop>qr_done_ebdf0f490b617d7efa3025d3625cec85'] = 'Bentornato'; +$_MODULE['<{mollie}prestashop>qr_done_c3171108158ad72d80e4f5068d312572'] = 'Il pagamento è stato annullato'; +$_MODULE['<{mollie}prestashop>qr_done_47db50323146abe9d975fb6616cefa3b'] = 'Il pagamento è completo. Grazie per il tuo ordine!'; +$_MODULE['<{mollie}prestashop>customerrecurringorderdetailproduct_465d60b936c982d7b57674f30ba022d0'] = 'Prodotto:'; +$_MODULE['<{mollie}prestashop>customerrecurringorderdetailproduct_3d0d1f906e27800531e054a3b6787b7c'] = 'Quantità:'; +$_MODULE['<{mollie}prestashop>customerrecurringorderdetailproduct_bbc8c3f199c22b3951a52bc9821971ee'] = 'Prezzo unitario:'; +$_MODULE['<{mollie}prestashop>customerrecurringorderdetailproduct_66c4c5112f455a19afde47829df363fa'] = 'Totale:'; +$_MODULE['<{mollie}prestashop>customerrecurringorderdetailproduct_dfc1493d2a91fecbec8fc7b9621ea52c'] = 'Stato dell\'abbonamento:'; +$_MODULE['<{mollie}prestashop>customerrecurringorderdetailproduct_bc687e68cac6a434d614f732a6bb35a8'] = 'Data di inizio dell\'abbonamento:'; +$_MODULE['<{mollie}prestashop>customerrecurringorderdetailproduct_625b79d4b6d9f937623d7f4f68b4efcd'] = 'Prossima data di pagamento:'; +$_MODULE['<{mollie}prestashop>customerrecurringorderdetailproduct_d6eb8b047631f376e10e2db6a60da350'] = 'Data di annullamento:'; +$_MODULE['<{mollie}prestashop>customerrecurringorderdetail_dd73b66f5abedea1529fc619f07cc88d'] = 'Dettagli dell\'ordine di abbonamento'; +$_MODULE['<{mollie}prestashop>customerrecurringorderdetail_7a76bd4a08a9d06cac7b74942507dca3'] = 'Aggiorna il metodo di pagamento dell\'abbonamento'; +$_MODULE['<{mollie}prestashop>customerrecurringorderdetail_34120aa4b83400b21af7641b425d109b'] = ' you can select it here.'; +$_MODULE['<{mollie}prestashop>customerrecurringorderdetail_06933067aafd48425d67bcb01bba5cb6'] = 'Aggiorna'; +$_MODULE['<{mollie}prestashop>customerrecurringorderdetail_01660840b062884fd856f49c71246112'] = 'Annulla l\'abbonamento'; +$_MODULE['<{mollie}prestashop>customerrecurringorderdetail_ea4788705e6873b424c65e91c2846b19'] = 'Annulla'; +$_MODULE['<{mollie}prestashop>customeraccount_4ca2c509994c2776d0880357b4e8e5be'] = 'Abbonamenti'; +$_MODULE['<{mollie}prestashop>customersubscriptionsdata_4ca2c509994c2776d0880357b4e8e5be'] = 'Abbonamenti'; diff --git a/upgrade/Upgrade-6.2.3.php b/upgrade/Upgrade-6.2.3.php new file mode 100644 index 000000000..d230c4248 --- /dev/null +++ b/upgrade/Upgrade-6.2.3.php @@ -0,0 +1,59 @@ + + * @copyright Mollie B.V. + * @license https://github.com/mollie/PrestaShop/blob/master/LICENSE.md + * + * @see https://github.com/mollie/PrestaShop + */ + +use PrestaShop\PrestaShop\Adapter\Module\Tab\ModuleTabRegister; +use Symfony\Component\HttpFoundation\ParameterBag; + +if (!defined('_PS_VERSION_')) { + exit; +} + +function upgrade_module_6_2_3(Mollie $module): bool +{ + // Create the new mol_logs table + $sql = 'CREATE TABLE IF NOT EXISTS `' . _DB_PREFIX_ . 'mol_logs` ( + `id_mollie_log` INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, + `id_log` INT(11), + `id_shop` INT(11), + `request` TEXT, + `response` TEXT, + `context` TEXT, + `date_add` DATETIME NOT NULL, + INDEX (`id_log`), + INDEX (`id_shop`) + ) ENGINE=' . _MYSQL_ENGINE_ . ' DEFAULT CHARSET=utf8;'; + + $isTableCreated = Db::getInstance()->execute($sql); + if (!$isTableCreated) { + return false; // If the table creation fails, return false + } + + /** @var ModuleTabRegister $tabRegister */ + $tabRegister = $module->getService('prestashop.adapter.module.tab.register'); + + $moduleAdapter = new \PrestaShop\PrestaShop\Adapter\Module\Module(); + $moduleAdapter->instance = $module; + $moduleAdapter->disk = new ParameterBag( + [ + 'filemtype' => 0, + 'is_present' => 1, + 'is_valid' => 1, + 'version' => null, + 'path' => '', + ] + ); + + $moduleAdapter->attributes->set('name', $module->name); + + $tabRegister->registerTabs($moduleAdapter); + + return $isTableCreated; +} diff --git a/views/css/admin/logs/index.php b/views/css/admin/logs/index.php new file mode 100755 index 000000000..c005d9315 --- /dev/null +++ b/views/css/admin/logs/index.php @@ -0,0 +1,21 @@ + + * @copyright Mollie B.V. + * @license https://github.com/mollie/PrestaShop/blob/master/LICENSE.md + * + * @see https://github.com/mollie/PrestaShop + * @codingStandardsIgnoreStart + */ + +.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/js/admin/logs/index.php b/views/js/admin/logs/index.php new file mode 100755 index 000000000..c005d9315 --- /dev/null +++ b/views/js/admin/logs/index.php @@ -0,0 +1,21 @@ + + * @copyright Mollie B.V. + * @license https://github.com/mollie/PrestaShop/blob/master/LICENSE.md + * + * @see https://github.com/mollie/PrestaShop + * @codingStandardsIgnoreStart + */ + +$(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: mollie.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(jQuery.parseJSON(json), null, 2); +} diff --git a/views/js/front/applePayDirect/applePayDirectProduct.js b/views/js/front/applePayDirect/applePayDirectProduct.js index 03a900799..6bb3940a3 100644 --- a/views/js/front/applePayDirect/applePayDirectProduct.js +++ b/views/js/front/applePayDirect/applePayDirectProduct.js @@ -193,6 +193,9 @@ $(document).ready(function () { }, [] ); + } else { + console.warn(applePayShippingContactUpdate) + session.abort() } }, error: (jqXHR, textStatus, errorThrown) => { diff --git a/views/templates/admin/logs/index.php b/views/templates/admin/logs/index.php new file mode 100755 index 000000000..c005d9315 --- /dev/null +++ b/views/templates/admin/logs/index.php @@ -0,0 +1,21 @@ + + * @copyright Mollie B.V. + * @license https://github.com/mollie/PrestaShop/blob/master/LICENSE.md + * + * @see https://github.com/mollie/PrestaShop + * @codingStandardsIgnoreStart + * + *} + +
+ {l s='View' mod='mollie'} +
+ + + + diff --git a/views/templates/admin/logs/severity_level_column.tpl b/views/templates/admin/logs/severity_level_column.tpl new file mode 100755 index 000000000..3f5641935 --- /dev/null +++ b/views/templates/admin/logs/severity_level_column.tpl @@ -0,0 +1,24 @@ +{** + * Mollie https://www.mollie.nl + * + * @author Mollie B.V. + * @copyright Mollie B.V. + * @license https://github.com/mollie/PrestaShop/blob/master/LICENSE.md + * + * @see https://github.com/mollie/PrestaShop + * @codingStandardsIgnoreStart + * + *} + + +{if $log_severity_level == $log_severity_level_informative} + {l s='Informative only' mod='mollie'} ({$log_severity_level|intval}) +{elseif $log_severity_level == $log_severity_level_warning} + {l s='Warning' mod='mollie'} ({$log_severity_level|intval}) +{elseif $log_severity_level == $log_severity_level_error} + {l s='Error' mod='mollie'} ({$log_severity_level|intval}) +{elseif $log_severity_level == $log_severity_level_major} + {l s='Major issue (crash)!' mod='mollie'} ({$log_severity_level|intval}) +{else} + {$log_severity_level|escape:'htmlall':'UTF-8'} +{/if} diff --git a/views/templates/admin/logs/severity_levels.tpl b/views/templates/admin/logs/severity_levels.tpl new file mode 100755 index 000000000..3620ae32d --- /dev/null +++ b/views/templates/admin/logs/severity_levels.tpl @@ -0,0 +1,26 @@ +{** + * Mollie https://www.mollie.nl + * + * @author Mollie B.V. + * @copyright Mollie B.V. + * @license https://github.com/mollie/PrestaShop/blob/master/LICENSE.md + * + * @see https://github.com/mollie/PrestaShop + * @codingStandardsIgnoreStart + * + *} + + +
+

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

+

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

+
    +
  1. {l s='Info' mod='mollie'}
  2. +
  3. {l s='Warning' mod='mollie'}
  4. +
  5. {l s='Error' mod='mollie'}
  6. +
  7. {l s='Fatal' mod='mollie'}
  8. +
+