This commit is contained in:
2026-02-02 15:18:51 +01:00
parent 7a26dd69a5
commit ae0ee002ec
170 changed files with 7446 additions and 1519 deletions

View File

@@ -18,6 +18,7 @@ include_once(dirname(__FILE__) . '/vendor/autoload.php');
include_once(dirname(__FILE__) . '/classes/PaynowFrontController.php');
include_once(dirname(__FILE__) . '/classes/PaynowLogger.php');
include_once(dirname(__FILE__) . '/classes/PaynowHelper.php');
include_once(dirname(__FILE__) . '/classes/PaynowKeysGenerator.php');
include_once(dirname(__FILE__) . '/classes/PaynowNotificationRetryProcessing.php');
include_once(dirname(__FILE__) . '/classes/PaynowNotificationStopProcessing.php');
include_once(dirname(__FILE__) . '/classes/PaynowConfigurationHelper.php');
@@ -31,11 +32,13 @@ include_once(dirname(__FILE__) . '/classes/PaynowAdminFormHelper.php');
include_once(dirname(__FILE__) . '/classes/PaynowOrderCreateProcessor.php');
include_once(dirname(__FILE__) . '/classes/PaynowOrderStateProcessor.php');
include_once(dirname(__FILE__) . '/models/PaynowPaymentData.php');
include_once(dirname(__FILE__) . '/models/PaynowPaymentLockData.php');
include_once(dirname(__FILE__) . '/classes/PaynowFrontController.php');
include_once(dirname(__FILE__) . '/classes/PaynowPaymentProcessor.php');
include_once(dirname(__FILE__) . '/classes/PaynowPaymentDataBuilder.php');
include_once(dirname(__FILE__) . '/classes/PaynowGithubClient.php');
include_once(dirname(__FILE__) . '/classes/PaynowLockingHelper.php');
include_once(dirname(__FILE__) . '/classes/PaynowSavedInstrumentHelper.php');
class Paynow extends PaymentModule
{
@@ -47,7 +50,7 @@ class Paynow extends PaymentModule
{
$this->name = 'paynow';
$this->tab = 'payments_gateways';
$this->version = '1.6.35';
$this->version = '1.7.12';
$this->ps_versions_compliancy = ['min' => '1.6.0', 'max' => _PS_VERSION_];
$this->author = 'mElements S.A.';
$this->is_eu_compatible = 1;
@@ -77,12 +80,14 @@ class Paynow extends PaymentModule
public function install()
{
if (!parent::install() ||
if (!parent::install() ||
!$this->createDbTables() ||
!$this->createModuleSettings() ||
!$this->registerHooks()) {
return false;
}
$this->saveShopPluginStatus(Paynow\Service\ShopConfiguration::STATUS_UPDATED);
return true;
}
@@ -91,29 +96,62 @@ class Paynow extends PaymentModule
if (!$this->unregisterHooks() || !$this->deleteModuleSettings() || !parent::uninstall()) {
return false;
}
$this->saveShopPluginStatus(Paynow\Service\ShopConfiguration::STATUS_UNINSTALLED);
return true;
}
public function enable($force_all = false)
{
if (!parent::enable($force_all)) {
return false;
}
$this->saveShopPluginStatus(Paynow\Service\ShopConfiguration::STATUS_ENABLED);
return true;
}
public function disable($force_all = false)
{
if (!parent::disable($force_all)) {
return false;
}
$this->saveShopPluginStatus(Paynow\Service\ShopConfiguration::STATUS_DISABLED);
return true;
}
private function createDbTables()
{
return Db::getInstance()->Execute('CREATE TABLE IF NOT EXISTS `' . _DB_PREFIX_ . 'paynow_payments` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`id_order` INT(10) UNSIGNED NOT NULL,
`id_cart` INT(10) UNSIGNED NOT NULL,
`id_payment` varchar(30) NOT NULL,
`order_reference` varchar(9) NOT NULL,
`external_id` varchar(50) NOT NULL,
`status` varchar(64) NOT NULL,
`total` DECIMAL(20,6) NOT NULL DEFAULT \'0.000000\',
`locked` TINYINT(1) NOT NULL DEFAULT 0,
`active` tinyint(1) NOT NULL DEFAULT 0,
`counter` tinyint(1) NOT NULL DEFAULT 0,
`sent_at` datetime DEFAULT NULL,
`created_at` datetime,
`modified_at` datetime,
UNIQUE (`id_payment`, `status`),
INDEX `index_order_cart_payment_reference` (`id_order`, `id_cart`, `id_payment`, `order_reference`)
)');
$result = Db::getInstance()->Execute('CREATE TABLE IF NOT EXISTS `' . _DB_PREFIX_ . 'paynow_payments` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`id_order` INT(10) UNSIGNED NOT NULL,
`id_cart` INT(10) UNSIGNED NOT NULL,
`id_payment` varchar(30) NOT NULL,
`order_reference` varchar(9) NOT NULL,
`external_id` varchar(50) NOT NULL,
`status` varchar(64) NOT NULL,
`total` DECIMAL(20,6) NOT NULL DEFAULT \'0.000000\',
`locked` TINYINT(1) NOT NULL DEFAULT 0,
`active` tinyint(1) NOT NULL DEFAULT 0,
`counter` tinyint(1) NOT NULL DEFAULT 0,
`sent_at` datetime DEFAULT NULL,
`created_at` datetime,
`modified_at` datetime,
UNIQUE (`id_payment`, `status`),
INDEX `index_order_cart_payment_reference` (`id_order`, `id_cart`, `id_payment`, `order_reference`)
)');
return $result && Db::getInstance()->Execute('CREATE TABLE IF NOT EXISTS `' . _DB_PREFIX_ . 'paynow_payment_locks` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`id_order` INT(10) UNSIGNED NOT NULL DEFAULT 0,
`id_cart` INT(10) UNSIGNED NOT NULL DEFAULT 0,
`counter` tinyint(1) NOT NULL DEFAULT 0,
`created_at` datetime,
`modified_at` datetime,
INDEX `index_payment_cart_reference` (`id_cart`),
INDEX `index_payment_order_reference` (`id_order`)
)');
}
private function registerHooks()
@@ -378,6 +416,12 @@ class Paynow extends PaymentModule
return $this->l('Pay by Google Pay');
case \Paynow\Model\PaymentMethods\Type::APPLE_PAY:
return $this->l('Pay by Apple Pay');
case 'DIGITAL_WALLETS':
return $this->l('Pay by digital wallets');
case \Paynow\Model\PaymentMethods\Type::PAYPO:
return $this->l('PayPo - buy now, pay later');
case \Paynow\Model\PaymentMethods\Type::CLICK_TO_PAY:
return $this->l('Click To Pay - pay with pre-saved card');
}
}
@@ -389,13 +433,13 @@ class Paynow extends PaymentModule
{
$total = number_format($this->context->cart->getOrderTotal() * 100, 0, '', '');
$currency = new Currency($this->context->cart->id_currency);
return (new PaynowPaymentMethodsHelper($this->getPaynowClient()))->getAvailable($currency->iso_code, $total);
return (new PaynowPaymentMethodsHelper($this->getPaynowClient()))->getAvailable($currency->iso_code, $total, $this->context, $this);
}
private function getGDPRNotices(): array
{
$locale = $this->context->language->locale ?? $this->context->language->language_code;
return (new PaynowGDPRHelper($this->getPaynowClient()))->getNotices($locale);
return (new PaynowGDPRHelper($this->getPaynowClient(), $this->context->cart))->getNotices($locale);
}
/** Returns is possible to show payment option
@@ -436,14 +480,22 @@ class Paynow extends PaymentModule
'cta_text' => $this->getCallToActionText(),
'logo' => $this->getLogo(),
'paynow_url' => PaynowLinkHelper::getPaymentUrl(),
'data_processing_notices' => $gdpr_notices ?? null
'data_processing_notices' => $gdpr_notices ?? null,
'data_paynow_plugin_version' => $this->version,
]);
$payment_options = [];
if ((int)Configuration::get('PAYNOW_SEPARATE_PAYMENT_METHODS') === 1) {
$payment_methods = $this->getPaymentMethods();
if (!empty($payment_methods)) {
$digital_wallets = [
Paynow\Model\PaymentMethods\Type::CLICK_TO_PAY => null,
Paynow\Model\PaymentMethods\Type::GOOGLE_PAY => null,
Paynow\Model\PaymentMethods\Type::APPLE_PAY => null,
];
$list = [];
$payment_options = [];
foreach ($payment_methods->getAll() as $payment_method) {
if (!isset($list[$payment_method->getType()])) {
if (Paynow\Model\PaymentMethods\Type::PBL == $payment_method->getType()) {
@@ -454,7 +506,13 @@ class Paynow extends PaymentModule
'authorization' => $payment_method->getAuthorizationType(),
'pbls' => $payment_methods->getOnlyPbls()
]);
} else {
} elseif (array_key_exists($payment_method->getType(), $digital_wallets)) {
if (!$payment_method->isEnabled()) {
continue;
}
$digital_wallets[$payment_method->getType()] = $payment_method;
} else {
if (Paynow\Model\PaymentMethods\Type::BLIK == $payment_method->getType()) {
$this->context->smarty->assign([
'action_blik' => Context::getContext()->link->getModuleLink(
@@ -467,22 +525,52 @@ class Paynow extends PaymentModule
'action_token' => Tools::encrypt($this->context->customer->secure_key),
'action_token_refresh' => Context::getContext()->link->getModuleLink('paynow', 'customerToken'),
'error_message' => $this->getTranslationsArray()['An error occurred during the payment process'],
'terms_message' => $this->getTranslationsArray()['You have to accept terms and conditions'],
'terms_message' => $this->getTranslationsArray()['First accept the terms of service, then click pay.'],
'blik_autofocus' => Configuration::get('PAYNOW_BLIK_AUTOFOCUS_ENABLED') === '0' ? '0' : '1',
]);
}
array_push($payment_options, [
$payment_option = [
'name' => $this->getPaymentMethodTitle($payment_method->getType()),
'image' => $payment_method->getImage(),
'id' => $payment_method->getId(),
'enabled' => $payment_method->isEnabled(),
'type' => $payment_method->getType(),
'authorization' => $payment_method->getAuthorizationType(),
]);
];
if (Paynow\Model\PaymentMethods\Type::CARD == $payment_method->getType()) {
$payment_option = array_merge($payment_option, [
'action_card' => PaynowLinkHelper::getPaymentUrl([
'paymentMethodId' => $payment_method->getId()
]),
'action_remove_saved_instrument' => Context::getContext()->link->getModuleLink(
'paynow',
'removeSavedInstrument'
),
'action_token' => Tools::encrypt($this->context->customer->secure_key),
'default_card_image' => Media::getMediaPath(_PS_MODULE_DIR_ . $this->name . '/views/img/card-default.svg'),
'instruments' => $payment_method->getSavedInstruments(),
]);
}
array_push($payment_options, $payment_option);
}
$list[$payment_method->getType()] = $payment_method->getId();
}
}
$digital_wallets = array_values(array_filter($digital_wallets));
if (!empty($digital_wallets)) {
$payment_options[] = [
'name' => $this->getPaymentMethodTitle('DIGITAL_WALLETS'),
'image' => $this->getDigitalWalletsLogo($digital_wallets),
'type' => 'DIGITAL_WALLETS',
'authorization' => '',
'pbls' => $digital_wallets
];
}
$this->context->smarty->assign([
'payment_options' => $payment_options
]);
@@ -535,8 +623,11 @@ class Paynow extends PaymentModule
*/
public function hookActionOrderSlipAdd($params)
{
if ((int)Configuration::get('PAYNOW_REFUNDS_ENABLED') === 1 && Tools::isSubmit('makeRefundViaPaynow') &&
$this->name == $params['order']->module) {
if ((int)Configuration::get('PAYNOW_REFUNDS_ENABLED') === 1
&& Tools::isSubmit('makeRefundViaPaynow')
&& $this->name == $params['order']->module
)
{
(new PaynowRefundProcessor($this->getPaynowClient(), $this->displayName))
->processFromOrderSlip($params['order']);
}
@@ -609,6 +700,8 @@ class Paynow extends PaymentModule
return $this->fetchTemplate('/views/templates/admin/_partials/upgrade.tpl');
}
$this->sendShopPluginStatus();
return null;
}
@@ -641,6 +734,22 @@ class Paynow extends PaymentModule
return false;
}
public function getDigitalWalletsLogo(array $wallets): string
{
if(count($wallets) === 1) {
return $wallets[0]->getImage();
}
$types = array_map(function($dw) {
return strtolower(substr($dw->getType(), 0, 1));
}, $wallets);
sort($types);
$types = implode('', $types);
return Media::getMediaPath(_PS_MODULE_DIR_ . $this->name . '/views/img/digital-wallets-' . $types . '.svg');
}
public function getLogo()
{
return Media::getMediaPath(_PS_MODULE_DIR_ . $this->name . '/views/img/logo-paynow.png');
@@ -743,6 +852,60 @@ class Paynow extends PaymentModule
}
}
private function saveShopPluginStatus($status)
{
$statuses = Configuration::get('PAYNOW_PLUGIN_STATUSES');
if (empty($statuses)) {
$statuses = [];
} else {
$statuses = json_decode($statuses, true);
}
date_default_timezone_set('UTC');
$statuses[] = [
'status' => $status,
'timestamp' => date('Y-m-d\TH:i:s.v\Z'),
];
Configuration::updateValue('PAYNOW_PLUGIN_STATUSES', json_encode($statuses));
}
private function sendShopPluginStatus()
{
if ( empty( $this->getApiKey() ) ) {
return;
}
$statuses = Configuration::get('PAYNOW_PLUGIN_STATUSES');
Configuration::updateValue('PAYNOW_PLUGIN_STATUSES', json_encode([]));
if (empty($statuses)) {
return;
} else {
$statuses = json_decode($statuses, true);
}
if (empty($statuses)) {
return;
}
$shop_configuration = new Paynow\Service\ShopConfiguration($this->getPaynowClient());
try {
$shop_configuration->status($statuses);
} catch (Paynow\Exception\PaynowException $exception) {
PaynowLogger::error(
'An error occurred during shop plugin status send {code={}, message={}}',
[
$exception->getCode(),
$exception->getPrevious()->getMessage()
]
);
foreach ($exception->getErrors() as $error) {
PaynowLogger::error('Error', ['mes' => $error->getMessage()]);
}
}
}
public function getContent()
{
if (Tools::isSubmit('submit' . $this->name)) {
@@ -819,7 +982,6 @@ class Paynow extends PaymentModule
'Wrong BLIK code' => $this->l('Wrong BLIK code'),
'BLIK code has expired' => $this->l('BLIK code has expired'),
'BLIK code already used' => $this->l('BLIK code already used'),
'You have to accept terms and conditions' => $this->l('You have to accept terms and conditions'),
'Moment of creating order' => $this->l('Moment of creating order'),
'On clicking the Place order' => $this->l('On clicking the Place order'),
'After the successful Paynow payment' => $this->l('After the successful Paynow payment'),
@@ -828,6 +990,9 @@ class Paynow extends PaymentModule
'Show retry payment button on selected statuses' => $this->l('Show retry payment button on selected statuses'),
'BLIK field autofocus' => $this->l('BLIK field autofocus'),
'Autofocus on checkout form field: BLIK code. Enabled by default. Disabling may be helpful when checkout page is visualy long (e.g. single-page checkout).' => $this->l('Autofocus on checkout form field: BLIK code. Enabled by default. Disabling may be helpful when checkout page is visualy long (e.g. single-page checkout).'),
'An error occurred while deleting the saved card.' => $this->l('An error occurred while deleting the saved card.'),
'First accept the terms of service, then click pay.' => $this->l('First accept the terms of service, then click pay.'),
'Digital wallets' => $this->l('Digital wallets'),
];
}
}