This commit is contained in:
2025-04-01 00:38:54 +02:00
parent d4d4c0c09d
commit 87da06293a
22351 changed files with 5168854 additions and 7538 deletions

View File

@@ -0,0 +1,152 @@
<?php
/**
* NOTICE OF LICENSE
*
* This source file is subject to the MIT License (MIT)
* that is bundled with this package in the file LICENSE.md.
*
* @author mElements S.A.
* @copyright mElements S.A.
* @license MIT License
*/
class PaynowChargeBlikModuleFrontController extends PaynowFrontController
{
/**
* @var array
*/
private $translations;
public function initContent()
{
$this->translations = $this->module->getTranslationsArray();
parent::initContent();
$this->executePayment();
}
private function executePayment()
{
$response = [
'success' => false
];
if ($this->isTokenValid()) {
$cart = new Cart(Context::getContext()->cart->id);
if (empty($cart) || ! $cart->id) {
PaynowLogger::warning(
'Can\'t process charge BLIK payment due wrong cart {cartId={}}',
[
Context::getContext()->cart->id
]
);
$this->ajaxRender(json_encode($response));
exit;
}
if (method_exists($cart, 'checkQuantities') && !$cart->checkQuantities()) {
PaynowLogger::warning(
'Can\'t process charge BLIK payment due wrong cart quantities {cartId={}}',
[
Context::getContext()->cart->id
]
);
$response['message'] = $this->translations['An error occurred during the cart validation'];
$this->ajaxRender(json_encode($response));
exit;
}
$lockingHelper = new PaynowLockingHelper();
$paynowPaymentProcessor = new PaynowPaymentProcessor($this->context, $this->module);
$externalId = $paynowPaymentProcessor->getExternalId();
$lockingHelper->checkAndCreate($externalId);
try {
$payment_data = $paynowPaymentProcessor->process();
if ($payment_data['status'] && in_array($payment_data['status'], [
Paynow\Model\Payment\Status::STATUS_NEW,
Paynow\Model\Payment\Status::STATUS_PENDING
])) {
if (PaynowConfigurationHelper::CREATE_ORDER_BEFORE_PAYMENT === (int)Configuration::get('PAYNOW_CREATE_ORDER_STATE') &&
false === $cart->orderExists()) {
$order = (new PaynowOrderCreateProcessor($this->module))->process(
$cart,
$payment_data['external_id'],
$payment_data['payment_id']
);
}
$response = array_merge($response, [
'success' => true,
'payment_id' => $payment_data['payment_id'],
'order_id' => $order->id ?? null,
'redirect_url' => PaynowLinkHelper::getBlikConfirmUrl([
'external_id' => $payment_data['external_id'],
'paymentId' => $payment_data['payment_id'],
'paymentStatus' => $payment_data['status'],
'token' => Tools::encrypt($this->context->customer->secure_key)
])
]);
if (! empty($order) && $order->id) {
PaynowPaymentData::updateOrderIdAndOrderReferenceByPaymentId(
$order->id,
$order->reference,
$payment_data['payment_id']
);
}
} else {
$response['message'] = $this->translations['An error occurred during the payment process'];
}
} catch (PaynowPaymentAuthorizeException $exception) {
$errors = $exception->getPrevious()->getErrors();
if (! empty($errors)) {
foreach ($errors as $error) {
PaynowLogger::error(
'An error occurred during payment request process {code={}, errorType={}, externalId={}, message={}}',
[
$exception->getPrevious()->getCode(),
$error->getType(),
$exception->getExternalId(),
$error->getMessage()
]
);
}
/**
* @var \Paynow\Exception\Error $error
*/
$error = reset($errors);
if ($error) {
switch ($error->getType()) {
case 'AUTHORIZATION_CODE_INVALID':
$response['message'] = $this->translations['Wrong BLIK code'];
break;
case 'AUTHORIZATION_CODE_EXPIRED':
$response['message'] = $this->translations['BLIK code has expired'];
break;
case 'AUTHORIZATION_CODE_USED':
$response['message'] = $this->translations['BLIK code already used'];
break;
default:
$response['message'] = $this->translations['An error occurred during the payment process'];
}
}
} else {
PaynowLogger::error(
'An error occurred during sending payment request {code={}, externalId={}, message={},}',
[
$exception->getCode(),
$exception->getExternalId(),
$exception->getPrevious()->getMessage()
]
);
$response['message'] = $this->translations['An error occurred during the payment process'];
}
}
$lockingHelper->delete($externalId);
} else {
$response['message'] = $this->translations['An error occurred during the payment process'];
}
$this->ajaxRender(json_encode($response));
exit;
}
}

View File

@@ -0,0 +1,71 @@
<?php
/**
* NOTICE OF LICENSE
*
* This source file is subject to the MIT License (MIT)
* that is bundled with this package in the file LICENSE.md.
*
* @author mElements S.A.
* @copyright mElements S.A.
* @license MIT License
*/
class PaynowConfirmBlikModuleFrontController extends PaynowFrontController
{
public function initContent()
{
parent::initContent();
$external_id = Tools::getValue('external_id');
if (!$external_id || !$this->isTokenValid()) {
$this->redirectToOrderHistory();
}
$this->payment = PaynowPaymentData::findLastByExternalId($external_id);
if (!$this->payment) {
$this->redirectToOrderHistory();
}
$this->order = new Order($this->payment->id_order);
$payment_status_from_api = $this->getPaymentStatus($this->payment->id_payment);
$statusToProcess = [
'status' => $payment_status_from_api,
'externalId' => $this->payment->external_id,
'paymentId' => $this->payment->id_payment
];
try {
PaynowLogger::debug('confirmBlik: status processing started', $statusToProcess);
(new PaynowOrderStateProcessor($this->module))->processNotification($statusToProcess);
PaynowLogger::debug('confirmBlik: status processing ended', $statusToProcess);
} catch (Exception $e) {
$statusToProcess['exception'] = $e->getMessage();
if (isset($e->logContext)) {
$statusToProcess['notificationContext'] = $e->logContext;
}
PaynowLogger::debug('confirmBlik: status processing failed', $statusToProcess);
}
if (version_compare(_PS_VERSION_, '1.7', 'gt')) {
$this->registerJavascript(
'paynow-confirm-blik',
'modules/'.$this->module->name.'/views/js/confirm-blik.js',
array(
'position' => 'bottom',
'priority' => 100
)
);
} else {
$this->addJS('modules/'.$this->module->name.'/views/js/confirm-blik.js');
}
$this->context->smarty->assign([
'module_dir' => $this->module->getPathUri(),
'order_status' => $this->getOrderCurrentState($this->order),
'order_reference' => $this->order->reference
]);
$this->renderTemplate('confirm_blik.tpl');
}
}

View File

@@ -0,0 +1,24 @@
<?php
/**
* NOTICE OF LICENSE
*
* This source file is subject to the MIT License (MIT)
* that is bundled with this package in the file LICENSE.md.
*
* @author mElements S.A.
* @copyright mElements S.A.
* @license MIT License
*/
class PaynowCustomerTokenModuleFrontController extends PaynowFrontController
{
public function initContent()
{
parent::initContent();
$this->ajaxRender(json_encode([
'token' => $this->generateToken(),
]));
exit;
}
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../../../');
exit;

View File

@@ -0,0 +1,87 @@
<?php
use Paynow\Exception\SignatureVerificationException;
use Paynow\Notification;
/**
* NOTICE OF LICENSE
*
* This source file is subject to the MIT License (MIT)
* that is bundled with this package in the file LICENSE.md.
*
* @author mElements S.A.
* @copyright mElements S.A.
* @license MIT License
*/
class PaynowNotificationsModuleFrontController extends PaynowFrontController
{
public function process()
{
ob_start();
$payload = trim(Tools::file_get_contents('php://input'));
$notification_data = json_decode($payload, true);
PaynowLogger::debug('Notification: Incoming notification', $notification_data);
try {
new Notification(
$this->module->getSignatureKey(),
$payload,
$this->getRequestHeaders()
);
(new PaynowOrderStateProcessor($this->module))->processNotification($notification_data);
} catch (SignatureVerificationException | InvalidArgumentException $e) {
$notification_data['exception'] = $e->getMessage();
PaynowLogger::error('Notification: Signature verification failed', $notification_data);
header('HTTP/1.1 400 Bad Request', true, 400);
ob_clean();
exit;
} catch (PaynowNotificationStopProcessing $e) {
$e->logContext['responseCode'] = 202;
PaynowLogger::debug('Notification: ' . $e->logMessage, $e->logContext);
header('HTTP/1.1 202 OK', true, 202);
ob_clean();
exit;
} catch (PaynowNotificationRetryProcessing $e) {
$e->logContext['responseCode'] = 400;
PaynowLogger::debug('Notification: ' . $e->logMessage, $e->logContext);
header('HTTP/1.1 400 Bad Request', true, 400);
ob_clean();
exit;
} catch (Exception $e) {
$notification_data['responseCode'] = 400;
$notification_data['exception'] = $e->getMessage();
$notification_data['file'] = $e->getFile();
$notification_data['line'] = $e->getLine();
PaynowLogger::error('Notification: unknown error', $notification_data);
header('Content-Type: application/json');
header('HTTP/1.1 400 Bad Request', true, 400);
ob_clean();
echo json_encode(
array(
'message' => 'An error occurred during processing notification',
'reason' => $e->getMessage(),
)
);
ob_flush();
exit;
}
header("HTTP/1.1 200 OK", true, 200);
ob_clean();
exit;
}
private function getRequestHeaders(): array
{
$headers = [];
foreach ($_SERVER as $key => $value) {
if (Tools::substr($key, 0, 5) == 'HTTP_') {
$subject = str_replace('_', ' ', Tools::strtolower(Tools::substr($key, 5)));
$headers[str_replace(' ', '-', ucwords($subject))] = $value;
}
}
return $headers;
}
}

View File

@@ -0,0 +1,191 @@
<?php
/**
* NOTICE OF LICENSE
*
* This source file is subject to the MIT License (MIT)
* that is bundled with this package in the file LICENSE.md.
*
* @author mElements S.A.
* @copyright mElements S.A.
* @license MIT License
*/
use Paynow\Exception\ConfigurationException;
class PaynowPaymentModuleFrontController extends PaynowFrontController
{
protected $order;
public function initContent()
{
parent::initContent();
if ($this->isRetryPayment()) {
$this->processRetryPayment();
} else {
$this->processNewPayment();
}
}
private function isRetryPayment(): bool
{
return Tools::getValue('id_order') !== false &&
Tools::getValue('order_reference') !== false &&
$this->module->canOrderPaymentBeRetried(new Order((int)Tools::getValue('id_order')));
}
/**
* @throws ConfigurationException
*/
private function processRetryPayment()
{
$id_order = (int)Tools::getValue('id_order');
$order_reference = Tools::getValue('order_reference');
if (!$id_order || !Validate::isUnsignedId($id_order)) {
Tools::redirect('index.php?controller=history');
}
$this->order = new Order($id_order);
$this->module->currentOrder = $this->order->id;
if (! Validate::isLoadedObject($this->order) || $this->order->reference !== $order_reference) {
Tools::redirect('index.php?controller=history');
}
$this->validateCustomer($this->order->id_customer);
$this->sendPaymentRequest();
}
/**
* @throws ConfigurationException
* @throws Exception
*/
private function processNewPayment()
{
$this->validateCart();
if (PaynowConfigurationHelper::CREATE_ORDER_BEFORE_PAYMENT === (int)Configuration::get('PAYNOW_CREATE_ORDER_STATE') &&
false === $this->context->cart->orderExists()) {
$this->order = (new PaynowOrderCreateProcessor($this->module))->process($this->context->cart, null);
}
$this->sendPaymentRequest();
}
/**
* @throws ConfigurationException|Exception
*/
private function sendPaymentRequest()
{
try {
$payment_data = (new PaynowPaymentProcessor($this->context, $this->module))->process();
Tools::redirect($this->getRedirectUrl($payment_data));
} catch (PaynowPaymentAuthorizeException $exception) {
$errors = $exception->getPrevious()->getErrors();
if (! empty($errors)) {
foreach ($errors as $error) {
PaynowLogger::error(
'An error occurred during sending payment request {errorType={}, externalId={}, message={}}',
[
$error->getType(),
$exception->getExternalId(),
$error->getMessage()
]
);
}
} else {
PaynowLogger::error(
$exception->getMessage() . ' {code={}, externalId={}, message={}}',
[
$exception->getCode(),
$exception->getExternalId(),
$exception->getMessage(),
]
);
}
$this->displayError();
}
}
/**
* Validate cart
*/
private function validateCart()
{
if (! $this->context->cart->id) {
PaynowLogger::warning('Empty cart');
Tools::redirect('index.php?controller=cart');
}
if ($this->context->cart->id_customer == 0 ||
$this->context->cart->id_address_delivery == 0 ||
$this->context->cart->id_address_invoice == 0) {
Tools::redirect('index.php?controller=order&step=1');
}
$this->validateCustomer($this->context->cart->id_customer);
}
/**
* Validate customer
*/
private function validateCustomer($id_customer)
{
if ($id_customer != $this->context->customer->id) {
Tools::redirect('index.php?controller=order&step=1');
}
$customer = new Customer($id_customer);
if (!Validate::isLoadedObject($customer)) {
Tools::redirect('index.php?controller=order&step=1');
}
}
/**
* @param array $payment_data
*
* @return string
*/
private function getRedirectUrl(array $payment_data): string
{
if (! in_array($payment_data['status'], [
Paynow\Model\Payment\Status::STATUS_NEW,
Paynow\Model\Payment\Status::STATUS_PENDING
])) {
return PaynowLinkHelper::getReturnUrl(
$payment_data['external_id'],
Tools::encrypt($payment_data['external_id'])
);
}
if (! $payment_data['redirect_url']) {
return PaynowLinkHelper::getContinueUrl(
$this->context->cart->id_cart,
$this->module->id,
$this->context->cart->secure_key,
$payment_data['external_id']
);
}
return $payment_data['redirect_url'];
}
private function displayError()
{
$currency = new Currency($this->context->cart->id_currency);
$this->context->smarty->assign([
'total_to_pay' => Tools::displayPrice($this->order->total_paid, $currency),
'button_action' => PaynowLinkHelper::getPaymentUrl(
!empty($this->order) ?
[
'id_order' => $this->order->id,
'order_reference' => $this->order->reference
]: null
),
'cta_text' => $this->module->getCallToActionText()
]);
$this->renderTemplate('error.tpl');
}
}

View File

@@ -0,0 +1,58 @@
<?php
/**
* NOTICE OF LICENSE
*
* This source file is subject to the MIT License (MIT)
* that is bundled with this package in the file LICENSE.md.
*
* @author mElements S.A.
* @copyright mElements S.A.
* @license MIT License
*/
class PaynowRemoveSavedInstrumentModuleFrontController extends PaynowFrontController
{
/**
* @var array
*/
private $translations;
public function initContent()
{
$this->translations = $this->module->getTranslationsArray();
parent::initContent();
$this->removeSavedInstrument();
}
private function removeSavedInstrument()
{
$response = [
'success' => false
];
if ($this->isTokenValid()) {
try {
$savedInstrumentToken = Tools::getValue('savedInstrumentToken');
(new PaynowSavedInstrumentHelper($this->context, $this->module))->remove($savedInstrumentToken);
$response = [
'success' => true,
];
} catch (Exception $e) {
$response['error'] = $this->translations['An error occurred while deleting the saved card.'];
PaynowLogger::error(
'An error occurred during saved instrument removal {code={}, message={}}',
[
$e->getCode(),
$e->getMessage()
]
);
}
}
$this->ajaxRender(json_encode($response));
exit;
}
}

View File

@@ -0,0 +1,113 @@
<?php
/**
* NOTICE OF LICENSE
*
* This source file is subject to the MIT License (MIT)
* that is bundled with this package in the file LICENSE.md.
*
* @author mElements S.A.
* @copyright mElements S.A.
* @license MIT License
*/
/**
* @property PaynowPaymentData $payment
*/
class PaynowReturnModuleFrontController extends PaynowFrontController
{
public function initContent()
{
parent::initContent();
$order_reference = Tools::getValue('order_reference');
$id_cart = Tools::getValue('id_cart');
$external_id = Tools::getValue('external_id');
if ((! $order_reference || ! $id_cart) && !$this->isTokenValid()) {
$this->redirectToOrderHistory();
}
if ($order_reference) {
$this->payment = PaynowPaymentData::findLastByOrderReference($order_reference);
}
if ($id_cart) {
$this->payment = PaynowPaymentData::findLastByCartId($id_cart);
}
if ($external_id) {
$this->payment = PaynowPaymentData::findLastByExternalId($external_id);
}
if (!$this->payment) {
$this->redirectToOrderHistory();
}
$this->order = new Order($this->payment->id_order);
if (!Validate::isLoadedObject($this->order) && PaynowConfigurationHelper::CREATE_ORDER_BEFORE_PAYMENT === (int)Configuration::get('PAYNOW_CREATE_ORDER_STATE')) {
$this->redirectToOrderHistory();
}
if (Tools::getValue('paymentId')) {
$payment_status_from_api = $this->getPaymentStatus($this->payment->id_payment);
$statusToProcess = [
'status' => $payment_status_from_api,
'externalId' => $this->payment->external_id,
'paymentId' => $this->payment->id_payment
];
try {
PaynowLogger::debug('Return: status processing started', $statusToProcess);
(new PaynowOrderStateProcessor($this->module))->processNotification($statusToProcess);
PaynowLogger::debug('Return: status processing ended', $statusToProcess);
$this->payment = PaynowPaymentData::findByPaymentId($this->payment->id_payment);
} catch (Exception $e) {
$statusToProcess['exception'] = $e->getMessage();
PaynowLogger::debug('Return: status processing failed', $statusToProcess);
}
Tools::redirectLink(PaynowLinkHelper::getContinueUrl(
$this->order->id_cart,
$this->module->id,
$this->order->secure_key,
$this->payment->external_id
));
}
$currentState = $this->order->getCurrentStateFull($this->context->language->id);
$this->context->smarty->assign([
'logo' => $this->module->getLogo(),
'details_url' => PaynowLinkHelper::getOrderUrl($this->order),
'payment_status' => $this->payment->status,
'order_status' => $currentState['name'],
'order_reference' => $this->order->reference,
'show_details_button' => $this->isTokenValid(),
'show_retry_button' => $this->module->canOrderPaymentBeRetried($this->order),
'HOOK_ORDER_CONFIRMATION' => $this->displayOrderConfirmation(),
'retry_url' => PaynowLinkHelper::getPaymentUrl([
'id_order' => $this->order->id,
'order_reference' => $this->order->reference
])
]);
$this->renderTemplate('return.tpl');
}
private function displayOrderConfirmation()
{
return Hook::exec('displayOrderConfirmation', $this->hookParams());
}
private function hookParams(): array
{
$currency = new Currency((int)$this->order->id_currency);
return [
'objOrder' => $this->order,
'order' => $this->order,
'currencyObj' => $currency,
'currency' => $currency->sign,
'total_to_pay' => $this->order->getOrdersTotalPaid()
];
}
}

View File

@@ -0,0 +1,74 @@
<?php
/**
* NOTICE OF LICENSE
*
* This source file is subject to the MIT License (MIT)
* that is bundled with this package in the file LICENSE.md.
*
* @author mElements S.A.
* @copyright mElements S.A.
* @license MIT License
*/
use Paynow\Model\Payment\Status;
class PaynowStatusModuleFrontController extends PaynowFrontController
{
public function initContent()
{
parent::initContent();
$this->ajax = true;
}
public function displayAjax()
{
if (Tools::getValue('external_id') && $this->isTokenValid()) {
$external_id = Tools::getValue('external_id');
PaynowLogger::info(
'Checking order\'s payment status {externalId={}}',
[
$external_id
]
);
$payment = PaynowPaymentData::findLastByExternalId($external_id);
$payment_status = $payment->status;
if (Status::STATUS_CONFIRMED !== $payment->status) {
$payment_status_from_api = $this->getPaymentStatus($payment->id_payment);
$statusToProcess = [
'status' => $payment_status_from_api,
'externalId' => $payment->external_id,
'paymentId' => $payment->id_payment
];
try {
PaynowLogger::debug('Status: status processing started', $statusToProcess);
(new PaynowOrderStateProcessor($this->module))
->processNotification($statusToProcess);
PaynowLogger::debug('Status: status processing ended', $statusToProcess);
$payment_status = $payment_status_from_api;
} catch (Exception $e) {
$statusToProcess['exception'] = $e->getMessage();
PaynowLogger::debug('Status: status processing failed', $statusToProcess);
}
$this->order = new Order($payment->id_order);
}
$response = [
'order_status' => $this->getOrderCurrentState($this->order),
'payment_status' => $payment_status
];
if (Status::STATUS_PENDING !== $payment_status) {
$response['redirect_url'] = PaynowLinkHelper::getContinueUrl(
$payment->id_cart,
$this->module->id,
$this->context->customer->secure_key,
$payment->external_id
);
}
$this->ajaxRender(json_encode($response));
exit;
}
}
}