diff --git a/composer.json b/composer.json index 895fa0191..52f03552e 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,8 @@ "webmozart/assert": "^1.11", "symfony/http-client": "^4.4", "http-interop/http-factory-guzzle": "^1.1", - "php-http/message-factory": "^1.1" + "php-http/message-factory": "^1.1", + "prestashop/prestashop-accounts-installer": "^1.0.4" }, "require-dev": { "roave/security-advisories": "dev-latest", diff --git a/controllers/admin/AdminMollieSettingsController.php b/controllers/admin/AdminMollieSettingsController.php index d1c08af60..220454b89 100644 --- a/controllers/admin/AdminMollieSettingsController.php +++ b/controllers/admin/AdminMollieSettingsController.php @@ -2,8 +2,25 @@ declare(strict_types=1); +use Mollie\Adapter\ConfigurationAdapter; +use Mollie\Adapter\ToolsAdapter; +use Mollie\Builder\Content\BaseInfoBlock; +use Mollie\Builder\Content\UpdateMessageInfoBlock; +use Mollie\Config\Config; +use Mollie\Logger\PrestaLogger; +use Mollie\Repository\ModuleRepository; +use Mollie\Service\Content\TemplateParserInterface; +use Mollie\Service\SettingsSaveService; +use PrestaShop\Module\PsEventbus\Service\PresenterService; +use PrestaShop\PrestaShop\Core\Addon\Module\ModuleManagerBuilder; +use PrestaShop\PsAccountsInstaller\Installer\Exception\ModuleNotInstalledException; +use PrestaShop\PsAccountsInstaller\Installer\Facade\PsAccounts; +use PrestaShop\PsAccountsInstaller\Installer\Installer as PsAccountsInstaller; + class AdminMollieSettingsController extends ModuleAdminController { + private const FILE_NAME = 'AdminMollieSettingsController'; + /** @var Mollie */ public $module; @@ -13,49 +30,59 @@ public function __construct() $this->bootstrap = true; } - public function postProcess() + public function initContent(): void { - /** @var \Mollie\Repository\ModuleRepository $moduleRepository */ - $moduleRepository = $this->module->getService(\Mollie\Repository\ModuleRepository::class); - $moduleDatabaseVersion = $moduleRepository->getModuleDatabaseVersion($this->module->name); - $needsUpgrade = Tools::version_compare($this->module->version, $moduleDatabaseVersion, '>'); - if ($needsUpgrade) { - $this->context->controller->errors[] = $this->module->l('Please upgrade Mollie module'); + $this->setEnvironmentForAccounts(); + $this->setEnvironmentForCloudSync(); - return; - } + $this->content .= $this->context->smarty->fetch($this->module->getLocalPath() . '/views/templates/admin/_configure/configuration.tpl'); - $isShopContext = Shop::getContext() === Shop::CONTEXT_SHOP; + $this->content .= $this->displayModuleSettings(); - if (!$isShopContext) { - $this->context->controller->errors[] = $this->module->l('Select the shop that you want to configure'); + $this->addJs($this->module->getPathUri() . '/views/js/admin/_configure/configuration.js'); - return; - } + parent::initContent(); + } + + public function postProcess() + { + /** @var ConfigurationAdapter $configuration */ + $configuration = $this->module->getService(ConfigurationAdapter::class); - /** @var \Mollie\Service\Content\TemplateParserInterface $templateParser */ - $templateParser = $this->module->getService(\Mollie\Service\Content\TemplateParserInterface::class); + /** @var ToolsAdapter $tools */ + $tools = $this->module->getService(ToolsAdapter::class); - $isSubmitted = (bool) Tools::isSubmit("submit{$this->module->name}"); + $isSubmitted = $tools->isSubmit("submit{$this->module->name}"); /* @phpstan-ignore-next-line */ - if (false === Configuration::get(Mollie\Config\Config::MOLLIE_STATUS_AWAITING) && !$isSubmitted) { + if (!$isSubmitted && !$configuration->get(Config::MOLLIE_STATUS_AWAITING)) { $this->context->controller->errors[] = $this->module->l('Select an order status for \"Status for Awaiting payments\" in the \"Advanced settings\" tab'); } $errors = []; - if (Tools::isSubmit("submit{$this->module->name}")) { - /** @var \Mollie\Service\SettingsSaveService $saveSettingsService */ - $saveSettingsService = $this->module->getService(\Mollie\Service\SettingsSaveService::class); + if ($tools->isSubmit("submit{$this->module->name}")) { + /** @var SettingsSaveService $saveSettingsService */ + $saveSettingsService = $this->module->getService(SettingsSaveService::class); + $resultMessages = $saveSettingsService->saveSettings($errors); + if (!empty($errors)) { - $this->context->controller->errors = $resultMessages; + $this->context->controller->errors = array_merge( + $this->context->controller->errors, + $resultMessages + ); } else { - $this->context->controller->confirmations = $resultMessages; + $this->context->controller->confirmations = array_merge( + $this->context->controller->confirmations, + $resultMessages + ); } } + } + private function displayModuleSettings(): string + { Media::addJsDef([ 'description_message' => addslashes($this->module->l('Enter a description')), 'min_amount_message' => addslashes($this->l('You have entered incorrect min amount')), @@ -71,6 +98,29 @@ public function postProcess() 'not_valid_file_message' => addslashes($this->module->l('Invalid file: %s%')), ]); + /** @var ModuleRepository $moduleRepository */ + $moduleRepository = $this->module->getService(ModuleRepository::class); + + $moduleDatabaseVersion = $moduleRepository->getModuleDatabaseVersion($this->module->name); + $needsUpgrade = Tools::version_compare($this->module->version, $moduleDatabaseVersion, '>'); + + if ($needsUpgrade) { + $this->context->controller->errors[] = $this->module->l('Please upgrade Mollie module'); + + return ''; + } + + $isShopContext = Shop::getContext() === Shop::CONTEXT_SHOP; + + if (!$isShopContext) { + $this->context->controller->errors[] = $this->module->l('Select the shop that you want to configure'); + + return ''; + } + + /** @var TemplateParserInterface $templateParser */ + $templateParser = $this->module->getService(TemplateParserInterface::class); + $this->context->controller->addJS($this->module->getPathUri() . 'views/js/method_countries.js'); $this->context->controller->addJS($this->module->getPathUri() . 'views/js/validation.js'); $this->context->controller->addJS($this->module->getPathUri() . 'views/js/admin/settings.js'); @@ -87,8 +137,9 @@ public function postProcess() $this->module->getLocalPath() . 'views/templates/admin/logo.tpl' ); - /** @var \Mollie\Builder\Content\UpdateMessageInfoBlock $updateMessageInfoBlock */ - $updateMessageInfoBlock = $this->module->getService(\Mollie\Builder\Content\UpdateMessageInfoBlock::class); + /** @var UpdateMessageInfoBlock $updateMessageInfoBlock */ + $updateMessageInfoBlock = $this->module->getService(UpdateMessageInfoBlock::class); + $updateMessageInfoBlockData = $updateMessageInfoBlock->setAddons(false); $html .= $templateParser->parseTemplate( @@ -97,8 +148,9 @@ public function postProcess() $this->module->getLocalPath() . 'views/templates/admin/updateMessage.tpl' ); - /** @var \Mollie\Builder\Content\BaseInfoBlock $baseInfoBlock */ - $baseInfoBlock = $this->module->getService(\Mollie\Builder\Content\BaseInfoBlock::class); + /** @var BaseInfoBlock $baseInfoBlock */ + $baseInfoBlock = $this->module->getService(BaseInfoBlock::class); + $this->context->smarty->assign($baseInfoBlock->buildParams()); /** @var \Mollie\Builder\FormBuilder $settingsFormBuilder */ @@ -112,6 +164,83 @@ public function postProcess() $this->context->controller->errors[] = $this->module->l('The database tables are missing. Reset the module.'); } - $this->content .= $html; + return $html; + } + + private function setEnvironmentForAccounts(): void + { + /** @var PrestaLogger $logger */ + $logger = $this->module->getService(PrestaLogger::class); + + try { + /** @var PsAccounts $accountsFacade */ + $accountsFacade = $this->module->getService(PsAccounts::class); + + $psAccountsPresenter = $accountsFacade->getPsAccountsPresenter(); + $psAccountsService = $accountsFacade->getPsAccountsService(); + } catch (ModuleNotInstalledException $exception) { + try { + /** @var PsAccountsInstaller $prestashopAccountsInstaller */ + $prestashopAccountsInstaller = $this->module->getService(PsAccountsInstaller::class); + + if (!$prestashopAccountsInstaller->install()) { + $this->context->controller->errors[] = + $this->module->l('Failed to install Prestashop Accounts module. Please contact support.'); + + return; + } + } catch (\Throwable $exception) { + $this->context->controller->errors[] = + $this->module->l('Failed to install Prestashop Accounts module. Please contact support.'); + + return; + } + + $psAccountsPresenter = $accountsFacade->getPsAccountsPresenter(); + $psAccountsService = $accountsFacade->getPsAccountsService(); + } catch (\Throwable $exception) { + $logger->error('"PrestaShop Accounts" unknown error.', [ + 'Exception message' => $exception->getMessage(), + 'Exception code' => $exception->getCode(), + ]); + + $this->context->controller->errors[] = + $this->module->l('"PrestaShop Accounts" initialization failed.', self::FILE_NAME); + + return; + } + + Media::addJsDef([ + 'contextPsAccounts' => $psAccountsPresenter->present(), + ]); + + $this->context->smarty->assign([ + 'urlAccountsCdn' => $psAccountsService->getAccountsCdn(), + ]); + } + + private function setEnvironmentForCloudSync(): void + { + $moduleManager = ModuleManagerBuilder::getInstance()->build(); + + if (!$moduleManager->isInstalled('ps_eventbus')) { + return; + } + + /** @var \Ps_eventbus $eventbusModule */ + $eventbusModule = \Module::getInstanceByName('ps_eventbus'); + + if (version_compare($eventbusModule->version, '1.9.0', '>=')) { + /** @var PresenterService $eventbusPresenterService */ + $eventbusPresenterService = $eventbusModule->getService(PresenterService::class); + + Media::addJsDef([ + 'contextPsEventbus' => $eventbusPresenterService->expose($this->module, ['orders',]), + ]); + } + + $this->context->smarty->assign([ + 'cloudSyncPathCDC' => Config::PRESTASHOP_CLOUDSYNC_CDN, + ]); } } diff --git a/mollie.php b/mollie.php index 3ce85292f..789976403 100755 --- a/mollie.php +++ b/mollie.php @@ -39,7 +39,9 @@ use Mollie\Subscription\Verification\HasSubscriptionProductInCart; use Mollie\Utility\PsVersionUtility; use Mollie\Verification\IsPaymentInformationAvailable; +use PrestaShop\PrestaShop\Core\Addon\Module\ModuleManagerBuilder; use PrestaShop\PrestaShop\Core\Localization\Locale\Repository; +use PrestaShop\PsAccountsInstaller\Installer\Installer as PsAccountsInstaller; use Symfony\Component\Dotenv\Dotenv; use Symfony\Component\HttpFoundation\Response; @@ -81,7 +83,7 @@ public function __construct() { $this->name = 'mollie'; $this->tab = 'payments_gateways'; - $this->version = '6.0.4'; + $this->version = '6.0.5'; $this->author = 'Mollie B.V.'; $this->need_instance = 1; $this->bootstrap = true; @@ -165,6 +167,39 @@ public function install() return false; } + try { + /** @var PsAccountsInstaller $prestashopAccountsInstaller */ + $prestashopAccountsInstaller = $this->getService(PsAccountsInstaller::class); + + if (!$prestashopAccountsInstaller->install()) { + $this->_errors[] = $this->l('Failed to install Prestashop Accounts module. Please contact support.'); + + return false; + } + } catch (\Throwable $exception) { + $this->_errors[] = $this->l('Failed to install Prestashop Accounts module. Please contact support.'); + + return false; + } + + $moduleManager = ModuleManagerBuilder::getInstance()->build(); + + try { + if (!$moduleManager->isInstalled('ps_eventbus')) { + $moduleManager->install('ps_eventbus'); + } + + if (!$moduleManager->isEnabled('ps_eventbus')) { + $moduleManager->enable('ps_eventbus'); + } + + $moduleManager->upgrade('ps_eventbus'); + } catch (Exception $exception) { + $this->_errors[] = $this->l('Failed to install/upgrade Prestashop event bus module. Please contact support.'); + + return false; + } + // TODO inject base install and subscription services $coreInstaller = $this->getService(Mollie\Install\Installer::class); diff --git a/src/Config/Config.php b/src/Config/Config.php index 1509c77ba..07a0c2a57 100644 --- a/src/Config/Config.php +++ b/src/Config/Config.php @@ -312,6 +312,9 @@ class Config const MOLLIE_BUTTON_ORDER_TOTAL_REFRESH = 'MOLLIE_BUTTON_ORDER_TOTAL_REFRESH'; + public const PRESTASHOP_ACCOUNTS_INSTALLER_VERSION = '5.0.0'; + public const PRESTASHOP_CLOUDSYNC_CDN = 'https://integration-assets.prestashop3.com/ext/cloudsync-merchant-sync-consent/latest/cloudsync-cdc.js'; + // TODO migrate functions below to separate service public static function getStatuses() { diff --git a/src/ServiceProvider/BaseServiceProvider.php b/src/ServiceProvider/BaseServiceProvider.php index 44f50e108..e39be3fbc 100644 --- a/src/ServiceProvider/BaseServiceProvider.php +++ b/src/ServiceProvider/BaseServiceProvider.php @@ -7,6 +7,7 @@ use League\Container\Container; use Mollie; use Mollie\Builder\ApiTestFeedbackBuilder; +use Mollie\Config\Config; use Mollie\Factory\ModuleFactory; use Mollie\Handler\Api\OrderEndpointPaymentTypeHandler; use Mollie\Handler\Api\OrderEndpointPaymentTypeHandlerInterface; @@ -117,6 +118,8 @@ use Mollie\Verification\Shipment\CanSendShipment; use Mollie\Verification\Shipment\ShipmentVerificationInterface; use PrestaShop\PrestaShop\Core\Grid\Action\Row\AccessibilityChecker\AccessibilityCheckerInterface; +use PrestaShop\PsAccountsInstaller\Installer\Facade\PsAccounts; +use PrestaShop\PsAccountsInstaller\Installer\Installer as PsAccountsInstaller; /** * Load base services here which are usually required @@ -236,6 +239,12 @@ public function register(Container $container) $this->addService($container, ApiTestFeedbackBuilder::class, ApiTestFeedbackBuilder::class) ->withArgument($container->get(ModuleFactory::class)->getModuleVersion() ?? '') ->withArgument(ApiKeyService::class); + + $this->addService($container, PsAccountsInstaller::class, PsAccountsInstaller::class) + ->withArgument(Config::PRESTASHOP_ACCOUNTS_INSTALLER_VERSION); + + $this->addService($container, PsAccounts::class, PsAccounts::class) + ->withArgument(PsAccountsInstaller::class); } private function addService(Container $container, $className, $service) diff --git a/upgrade/Upgrade-6.0.5.php b/upgrade/Upgrade-6.0.5.php new file mode 100644 index 000000000..f9da84728 --- /dev/null +++ b/upgrade/Upgrade-6.0.5.php @@ -0,0 +1,80 @@ + + * @copyright Mollie B.V. + * @license https://github.com/mollie/PrestaShop/blob/master/LICENSE.md + * + * @see https://github.com/mollie/PrestaShop + */ + +use Mollie\Logger\PrestaLogger; +use PrestaShop\PrestaShop\Core\Addon\Module\ModuleManagerBuilder; +use PrestaShop\PsAccountsInstaller\Installer\Installer as PsAccountsInstaller; + +if (!defined('_PS_VERSION_')) { + exit; +} + +function upgrade_module_6_0_5(Mollie $module): bool +{ + return installPsAccounts605($module) + && installCloudSync605($module); +} + +function installPsAccounts605(Mollie $module): bool +{ + /** @var PrestaLogger $logger */ + $logger = $module->getService(PrestaLogger::class); + + try { + /** @var PsAccountsInstaller $prestashopAccountsInstaller */ + $prestashopAccountsInstaller = $module->getService(PsAccountsInstaller::class); + + if (!$prestashopAccountsInstaller->install()) { + $logger->error('Failed to install Prestashop Accounts module. Please contact support.'); + + return false; + } + } catch (\Throwable $exception) { + $logger->error('Failed to install Prestashop Accounts module. Please contact support.', [ + 'Exception message' => $exception->getMessage(), + 'Exception code' => $exception->getCode(), + ]); + + return false; + } + + return true; +} + +function installCloudSync605(Mollie $module): bool +{ + /** @var PrestaLogger $logger */ + $logger = $module->getService(PrestaLogger::class); + + $moduleManager = ModuleManagerBuilder::getInstance()->build(); + + try { + if (!$moduleManager->isInstalled('ps_eventbus')) { + $moduleManager->install('ps_eventbus'); + } + + if (!$moduleManager->isEnabled('ps_eventbus')) { + $moduleManager->enable('ps_eventbus'); + } + + $moduleManager->upgrade('ps_eventbus'); + } catch (Exception $exception) { + $logger->error('Failed to install/upgrade Prestashop event bus module. Please contact support.', [ + 'Exception message' => $exception->getMessage(), + 'Exception code' => $exception->getCode(), + ]); + + return false; + } + + return true; +} diff --git a/views/css/admin/logo_input.css b/views/css/admin/logo_input.css index 96c64bf7c..a185c69f5 100644 --- a/views/css/admin/logo_input.css +++ b/views/css/admin/logo_input.css @@ -1,3 +1,16 @@ +.header-logo { + width: 263px; + align-content: center; + text-align: left; + padding: 20px 0; +} + +.header-logo img { + max-width:100%; + height:auto; + margin: 0 auto; +} + .mollie-input-file { width: 0.1px; height: 0.1px; diff --git a/views/js/admin/_configure/configuration.js b/views/js/admin/_configure/configuration.js new file mode 100644 index 000000000..04bf48f4b --- /dev/null +++ b/views/js/admin/_configure/configuration.js @@ -0,0 +1,13 @@ +$(document).ready(function () { + window?.psaccountsVue?.init(); + // CloudSync + const cdc = window.cloudSyncSharingConsent; + + cdc.init('#prestashop-cloudsync'); + cdc.on('OnboardingCompleted', (isCompleted) => { + console.log('OnboardingCompleted', isCompleted); + }); + cdc.isOnboardingCompleted((isCompleted) => { + console.log('Onboarding is already Completed', isCompleted); + }); +}); diff --git a/views/templates/admin/_configure/configuration.tpl b/views/templates/admin/_configure/configuration.tpl new file mode 100644 index 000000000..39e0c3bc3 --- /dev/null +++ b/views/templates/admin/_configure/configuration.tpl @@ -0,0 +1,10 @@ +