додано переклади
This commit is contained in:
11
config_uk.xml
Normal file
11
config_uk.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<module>
|
||||
<name>hutko</name>
|
||||
<displayName><![CDATA[Hutko Payments]]></displayName>
|
||||
<version><![CDATA[1.2.0]]></version>
|
||||
<description><![CDATA[Hutko is a payment platform whose main function is to provide internet acquiring.]]></description>
|
||||
<author><![CDATA[Hutko]]></author>
|
||||
<tab><![CDATA[payments_gateways]]></tab>
|
||||
<is_configurable>1</is_configurable>
|
||||
<need_instance>1</need_instance>
|
||||
</module>
|
||||
@@ -29,24 +29,7 @@ if (!defined('_PS_VERSION_')) {
|
||||
*/
|
||||
class HutkoCallbackModuleFrontController extends ModuleFrontController
|
||||
{
|
||||
/**
|
||||
* Handles the post-processing of the payment gateway callback.
|
||||
*
|
||||
* This method is the entry point for Hutko's server-to-server notifications.
|
||||
* It performs the following steps:
|
||||
* 1. Parses the incoming request body (from POST or raw input).
|
||||
* 2. Validates the integrity of the request using the module's signature validation.
|
||||
* 3. Extracts the cart ID and loads the corresponding cart.
|
||||
* 4. Checks if the order already exists for the cart. If not, it attempts to validate
|
||||
* and create the order, using `postponeCallback` to manage potential race conditions.
|
||||
* 5. Based on the `order_status` received in the callback, it updates the PrestaShop
|
||||
* order's status (e.g., to success, error, or processing).
|
||||
* 6. Logs all significant events and errors using PrestaShopLogger.
|
||||
* 7. Exits with a simple string response ('OK' or an error message) as expected by
|
||||
* payment gateways.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
public function postProcess(): void
|
||||
{
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
@@ -61,72 +44,18 @@ class HutkoCallbackModuleFrontController extends ModuleFrontController
|
||||
PrestaShopLogger::addLog('Hutko Callback: Empty request body received.', 2, null, 'Cart', null, true);
|
||||
exit('Empty request');
|
||||
}
|
||||
|
||||
// 2. Validate the request signature and required fields.
|
||||
// Ensure all expected fields are present before proceeding with validation.
|
||||
$requiredFields = ['order_id', 'amount', 'order_status', 'signature', 'merchant_id'];
|
||||
foreach ($requiredFields as $field) {
|
||||
if (!isset($requestBody[$field])) {
|
||||
PrestaShopLogger::addLog('Hutko Callback: Missing required field in request: ' . $field, 2, null, 'Cart', null, true);
|
||||
exit('Missing parameter: ' . $field);
|
||||
}
|
||||
}
|
||||
|
||||
// Assuming validateResponse returns true on success, or a string error message on failure.
|
||||
$isSignatureValid = $this->module->validateResponse($requestBody);
|
||||
if ($isSignatureValid !== true) {
|
||||
PrestaShopLogger::addLog('Hutko Callback: Invalid signature. Error: ' . $isSignatureValid, 2, null, 'Cart', null, true);
|
||||
exit('Invalid signature');
|
||||
}
|
||||
// PrestaShopLogger::addLog('Hutko Callback: ' . json_encode($requestBody), 1);
|
||||
|
||||
|
||||
// 3. Extract cart ID and load the cart.
|
||||
// The order_id is expected to be in the format "cartID|timestamp".
|
||||
$transaction_id = $requestBody['order_id'];
|
||||
$orderIdParamParts = explode($this->module->order_separator, $transaction_id);
|
||||
$cartId = (int)$orderIdParamParts[0]; // Ensure it's an integer
|
||||
|
||||
$cart = new Cart($cartId);
|
||||
|
||||
// Validate cart object.
|
||||
if (!Validate::isLoadedObject($cart)) {
|
||||
PrestaShopLogger::addLog('Hutko Callback: Cart not found for ID: ' . $cartId, 3, null, 'Cart', $cartId, true);
|
||||
exit('Cart not found');
|
||||
}
|
||||
|
||||
// 4. Determine the amount received from the callback.
|
||||
$amountReceived = round((float)$requestBody['amount'] / 100, 2);
|
||||
|
||||
// 5. Check if the order already exists for this cart.
|
||||
$orderId = Order::getIdByCartId($cart->id);
|
||||
$orderExists = (bool)$orderId;
|
||||
|
||||
// 6. If the order doesn't exist, attempt to validate it using postponeCallback.
|
||||
// This handles the scenario where the callback arrives before the customer returns to the site.
|
||||
if (!$orderExists) {
|
||||
// The callback function will check for order existence again right before validation
|
||||
// to handle potential race conditions.
|
||||
$validationCallback = function () use ($cart, $amountReceived, $transaction_id) {
|
||||
// Re-check if the order exists right before validation in case the result controller
|
||||
// created it in the interim while we were waiting for the second digit.
|
||||
if (Order::getIdByCartId($cart->id)) {
|
||||
return true; // Order already exists, no need to validate again.
|
||||
}
|
||||
// If order still doesn't exist, proceed with validation.
|
||||
$idState = (int)Configuration::get('HUTKO_SUCCESS_STATUS_ID');
|
||||
return $this->module->validateOrderFromCart((int)$cart->id, $amountReceived, $transaction_id, $idState, true);
|
||||
};
|
||||
|
||||
// Postpone validation to seconds ending in 8 to avoid collision with result controller (ending in 3).
|
||||
$validationResult = $this->module->postponeCallback($validationCallback, 8);
|
||||
|
||||
// Re-fetch order ID after potential validation.
|
||||
$orderId = Order::getIdByCartId($cart->id);
|
||||
|
||||
if (!$orderId || !$validationResult) {
|
||||
PrestaShopLogger::addLog('Hutko Callback: Order validation failed for cart ID: ' . $cart->id, 2, null, 'Cart', $cart->id, true);
|
||||
exit('Order validation failed');
|
||||
}
|
||||
}
|
||||
$orderId = (int)$orderIdParamParts[0]; // Ensure it's an integer
|
||||
|
||||
// If we reached here, an order should exist. Load it.
|
||||
$order = new Order($orderId);
|
||||
@@ -141,11 +70,17 @@ class HutkoCallbackModuleFrontController extends ModuleFrontController
|
||||
|
||||
switch ($orderStatusCallback) {
|
||||
case 'approved':
|
||||
$expectedState = (int)Configuration::get('HUTKO_SUCCESS_STATUS_ID');
|
||||
// Only change state if it's not already the success state or "Payment accepted".
|
||||
// "Payment accepted" (PS_OS_PAYMENT) might be set by validateOrderFromCart.
|
||||
if ($currentOrderState !== $expectedState && $currentOrderState !== (int)Configuration::get('PS_OS_PAYMENT')) {
|
||||
$this->module->updateOrderStatus($orderId, $expectedState, 'Payment approved by Hutko.');
|
||||
// Only success state if no refunds was done.
|
||||
if ($requestBody['response_status'] == 'success' && (int)$requestBody['reversal_amount'] === 0) {
|
||||
$expectedState = (int)Configuration::get('HUTKO_SUCCESS_STATUS_ID', null, null, null, Configuration::get('PS_OS_PAYMENT'));
|
||||
// Only change state if it's not already the success state or "Payment accepted".
|
||||
|
||||
if ($currentOrderState !== $expectedState) {
|
||||
$this->module->addPayment($requestBody, $order);
|
||||
$order->setCurrentState($expectedState);
|
||||
}
|
||||
} else {
|
||||
PrestaShopLogger::addLog('Hutko Callback: Unhandled response_status: ' . $requestBody['response_status']);
|
||||
}
|
||||
exit('OK');
|
||||
break;
|
||||
@@ -154,7 +89,7 @@ class HutkoCallbackModuleFrontController extends ModuleFrontController
|
||||
$expectedState = (int)Configuration::get('PS_OS_ERROR');
|
||||
// Only change state if it's not already the error state.
|
||||
if ($currentOrderState !== $expectedState) {
|
||||
$this->module->updateOrderStatus($orderId, $expectedState, 'Payment ' . $orderStatusCallback . ' by Hutko.');
|
||||
$order->setCurrentState($expectedState);
|
||||
}
|
||||
exit('Order ' . $orderStatusCallback);
|
||||
break;
|
||||
@@ -162,7 +97,7 @@ class HutkoCallbackModuleFrontController extends ModuleFrontController
|
||||
$expectedState = (int)Configuration::get('PS_OS_ERROR');
|
||||
// Only change state if it's not already the error state.
|
||||
if ($currentOrderState !== $expectedState) {
|
||||
$this->module->updateOrderStatus($orderId, $expectedState, 'Payment ' . $orderStatusCallback . ' by Hutko.');
|
||||
$order->setCurrentState($expectedState);
|
||||
}
|
||||
exit('Order ' . $orderStatusCallback);
|
||||
break;
|
||||
@@ -173,7 +108,7 @@ class HutkoCallbackModuleFrontController extends ModuleFrontController
|
||||
// For now, if it's not already in a success/error state, set it to 'processing'.
|
||||
$processingState = (int)Configuration::get('PS_OS_PAYMENT'); // Or a custom 'processing' state
|
||||
if ($currentOrderState !== $processingState && $currentOrderState !== (int)Configuration::get('HUTKO_SUCCESS_STATUS_ID') && $currentOrderState !== (int)Configuration::get('PS_OS_ERROR')) {
|
||||
$this->module->updateOrderStatus($orderId, $processingState, 'Payment processing by Hutko.');
|
||||
$order->setCurrentState($processingState);
|
||||
}
|
||||
exit('Processing');
|
||||
break;
|
||||
@@ -198,13 +133,8 @@ class HutkoCallbackModuleFrontController extends ModuleFrontController
|
||||
*/
|
||||
private function getRequestBody(): array
|
||||
{
|
||||
// Prioritize $_POST for form data.
|
||||
if (!empty($_POST)) {
|
||||
return $_POST;
|
||||
}
|
||||
|
||||
// Fallback to raw input for JSON payloads, common for callbacks.
|
||||
$jsonBody = json_decode(Tools::file_get_contents("php://input"), true);
|
||||
$jsonBody = json_decode(file_get_contents("php://input"), true);
|
||||
if (is_array($jsonBody)) {
|
||||
return $jsonBody;
|
||||
}
|
||||
|
||||
@@ -32,16 +32,32 @@ class HutkoRedirectModuleFrontController extends ModuleFrontController
|
||||
*/
|
||||
public function initContent()
|
||||
{
|
||||
// Call the parent class's initContent method to perform default initializations.
|
||||
parent::initContent();
|
||||
|
||||
// Assign Smarty variables to be used in the redirect template.
|
||||
$this->context->smarty->assign([
|
||||
'hutko_url' => $this->module->checkout_url, // The URL of the Hutko payment gateway.
|
||||
'hutko_inputs' => $this->module->buildInputs(), // An array of input parameters required by Hutko.
|
||||
]);
|
||||
|
||||
// Set the template to be used for displaying the redirection form.
|
||||
$this->setTemplate('module:' . $this->module->name . '/views/templates/front/redirect.tpl');
|
||||
// Call the parent class's initContent method to perform default initializations.
|
||||
parent::initContent();
|
||||
$idState = (int) Configuration::get('HUTKO_NEW_ORDER_STATUS_ID', null, null, null, Configuration::get('PS_OS_PREPARATION'));
|
||||
$validationResult = $this->module->validateOrder($this->context->cart->id, $idState, 0, $this->module->displayName);
|
||||
|
||||
if ($validationResult) {
|
||||
$order = new Order((int)$this->module->currentOrder);
|
||||
$requestData = $this->module->buildPaymentRequestData($order, null, null, null);
|
||||
$responseData = $this->module->sendAPICall($this->module->checkout_url, $requestData);
|
||||
if (isset($responseData['response']['response_status']) && $responseData['response']['response_status'] === 'success') {
|
||||
$orderPayment = new OrderPayment();
|
||||
$orderPayment->order_reference = $order->reference;
|
||||
$orderPayment->id_currency = $order->id_currency;
|
||||
$orderPayment->amount = 0;
|
||||
$orderPayment->payment_method = $this->module->displayName;
|
||||
$orderPayment->transaction_id = $requestData['order_id'];
|
||||
$orderPayment->card_holder = $responseData['response']['checkout_url'];
|
||||
$orderPayment->add();
|
||||
Tools::redirect($responseData['response']['checkout_url']);
|
||||
return;
|
||||
}
|
||||
$this->context->smarty->assign([
|
||||
'hutko_response' => $responseData['response'], // The URL of the Hutko payment gateway.
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,185 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Hutko - Платіжний сервіс, який рухає бізнеси вперед.
|
||||
*
|
||||
* Запускайтесь, набирайте темп, масштабуйтесь – ми підстрахуємо всюди.
|
||||
*
|
||||
* @author panariga
|
||||
* @copyright 2025 Hutko
|
||||
* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
|
||||
*/
|
||||
|
||||
|
||||
if (!defined('_PS_VERSION_')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Class HutkoResultModuleFrontController
|
||||
* Front Controller for handling the result of a Hutko payment.
|
||||
*
|
||||
* This class processes the response from the Hutko payment gateway after a customer
|
||||
* has attempted a payment. It validates the incoming parameters, handles different
|
||||
* payment statuses (approved, declined, processing, expired), and redirects the
|
||||
* customer accordingly to the order confirmation page, order history, or back
|
||||
* to the order page with relevant notifications.
|
||||
*
|
||||
* @property Hutko $module An instance of the Hutko module.
|
||||
*/
|
||||
class HutkoResultModuleFrontController extends ModuleFrontController
|
||||
{
|
||||
/**
|
||||
* Handles the post-processing of the payment gateway response.
|
||||
*
|
||||
* This method retrieves payment status and order details from the request,
|
||||
* performs necessary validations, and then takes action based on the
|
||||
* payment status:
|
||||
* - 'declined' or 'expired': Adds an error and redirects to the order page.
|
||||
* - 'processing': Periodically checks for order creation (up to PHP execution timeout)
|
||||
* and redirects to confirmation if found, or adds an error if not.
|
||||
* - 'approved': Validates the order (if not already created) and redirects
|
||||
* to the order confirmation page.
|
||||
* - Any other status: Redirects to the order history or order page with errors.
|
||||
*/
|
||||
public function postProcess(): void
|
||||
{
|
||||
// Retrieve essential parameters from the request.
|
||||
$orderStatus = Tools::getValue('order_status');
|
||||
$transaction_id = Tools::getValue('order_id'); // This is the combined cart_id|timestamp
|
||||
$amountReceived = round((float)Tools::getValue('actual_amount', Tools::getValue('amount', 0)) / 100, 2);
|
||||
|
||||
// Basic validation: If critical parameters are missing, redirect to home.
|
||||
if (!$transaction_id || !$orderStatus || !$amountReceived) {
|
||||
Tools::redirect('/');
|
||||
}
|
||||
|
||||
// Extract cart ID from the combined order_id parameter.
|
||||
// The order_id is expected to be in the format "cartID|timestamp".
|
||||
$cartIdParts = explode($this->module->order_separator, $transaction_id);
|
||||
$cartId = (int)$cartIdParts[0];
|
||||
|
||||
// Validate extracted cart ID. It must be a numeric value.
|
||||
if (!is_numeric($cartId)) {
|
||||
$this->errors[] = Tools::displayError($this->trans('Invalid cart ID received.', [], 'Modules.Hutko.Shop'));
|
||||
$this->redirectWithNotifications($this->context->link->getPageLink('order', true, $this->context->language->id));
|
||||
return; // Stop execution after redirection
|
||||
}
|
||||
|
||||
// Load the cart object.
|
||||
$cart = new Cart($cartId);
|
||||
|
||||
// Verify that the cart belongs to the current customer to prevent unauthorized access.
|
||||
if (!Validate::isLoadedObject($cart) || $cart->id_customer != $this->context->customer->id) {
|
||||
$this->errors[] = Tools::displayError($this->trans('Access denied to this order.', [], 'Modules.Hutko.Shop'));
|
||||
Tools::redirect('/'); // Redirect to home or a more appropriate error page
|
||||
}
|
||||
|
||||
// Handle different payment statuses.
|
||||
switch ($orderStatus) {
|
||||
case 'declined':
|
||||
$this->errors[] = Tools::displayError($this->trans('Your payment was declined. Please try again or use a different payment method.', [], 'Modules.Hutko.Shop'));
|
||||
$this->redirectWithNotifications($this->context->link->getPageLink('order', true, $this->context->language->id));
|
||||
break;
|
||||
|
||||
case 'expired':
|
||||
$this->errors[] = Tools::displayError($this->trans('Your payment has expired. Please try again.', [], 'Modules.Hutko.Shop'));
|
||||
$this->redirectWithNotifications($this->context->link->getPageLink('order', true, $this->context->language->id));
|
||||
break;
|
||||
|
||||
case 'processing':
|
||||
// For 'processing' status, we need to poll for order creation.
|
||||
// This loop will try to find the order for a limited time to avoid
|
||||
// exceeding PHP execution limits.
|
||||
$maxAttempts = 10; // Max 10 attempts
|
||||
$sleepTime = 5; // Sleep 5 seconds between attempts (total max 50 seconds)
|
||||
$orderFound = false;
|
||||
$orderId = 0;
|
||||
|
||||
for ($i = 0; $i < $maxAttempts; $i++) {
|
||||
$orderId = Order::getIdByCartId($cart->id);
|
||||
if ($orderId) {
|
||||
$orderFound = true;
|
||||
break; // Order found, exit loop
|
||||
}
|
||||
// If not found, wait for a few seconds before retrying.
|
||||
sleep($sleepTime);
|
||||
}
|
||||
|
||||
if ($orderFound) {
|
||||
// Order found, redirect to confirmation page.
|
||||
Tools::redirect($this->context->link->getPageLink('order-confirmation', true, $this->context->language->id, [
|
||||
'id_cart' => $cart->id,
|
||||
'id_module' => $this->module->id,
|
||||
'id_order' => $orderId,
|
||||
'key' => $this->context->customer->secure_key,
|
||||
]));
|
||||
} else {
|
||||
// Order not found after multiple attempts, assume it's still processing or failed silently.
|
||||
$this->errors[] = Tools::displayError($this->trans('Your payment is still processing. Please check your order history later.', [], 'Modules.Hutko.Shop'));
|
||||
$this->redirectWithNotifications($this->context->link->getPageLink('order-history', true, $this->context->language->id));
|
||||
}
|
||||
break;
|
||||
|
||||
case 'approved':
|
||||
$orderId = Order::getIdByCartId($cart->id);
|
||||
|
||||
// If the order doesn't exist yet, validate it.
|
||||
// The postponeCallback is used here to avoid race conditions with the callback controller
|
||||
// (which might be trying to validate the order on seconds ending in 8, while this
|
||||
// controller tries on seconds ending in 3).
|
||||
if (!$orderId) {
|
||||
// Define the validation logic to be executed by postponeCallback.
|
||||
// This callback will first check if the order exists, and only
|
||||
// validate if it doesn't, to avoid race conditions.
|
||||
$validationCallback = function () use ($cart, $amountReceived, $transaction_id) {
|
||||
// Re-check if the order exists right before validation in case the callback
|
||||
// controller created it in the interim while we were waiting for the second digit.
|
||||
if (Order::getIdByCartId($cart->id)) {
|
||||
return true; // Order already exists, no need to validate again.
|
||||
}
|
||||
$idState = (int)Configuration::get('HUTKO_SUCCESS_STATUS_ID');
|
||||
// If order still doesn't exist, proceed with validation.
|
||||
return $this->module->validateOrderFromCart((int)$cart->id, $amountReceived, $transaction_id, $idState);
|
||||
};
|
||||
|
||||
// Postpone the execution of the validation callback until the second ends in 3.
|
||||
$validationResult = $this->module->postponeCallback($validationCallback, 3);
|
||||
|
||||
// After the postponed callback has run, try to get the order ID again.
|
||||
$orderId = Order::getIdByCartId($cart->id);
|
||||
|
||||
// If validation failed or order still not found, add an error.
|
||||
if (!$orderId || !$validationResult) {
|
||||
$this->errors[] = Tools::displayError($this->trans('Payment approved but order could not be created. Please contact support.', [], 'Modules.Hutko.Shop'));
|
||||
$this->redirectWithNotifications($this->context->link->getPageLink('order', true, $this->context->language->id));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If order exists (either found initially or created by validation), redirect to confirmation.
|
||||
Tools::redirect($this->context->link->getPageLink('order-confirmation', true, $this->context->language->id, [
|
||||
'id_cart' => $cart->id,
|
||||
'id_module' => $this->module->id,
|
||||
'id_order' => $orderId,
|
||||
'key' => $this->context->customer->secure_key,
|
||||
]));
|
||||
break;
|
||||
|
||||
default:
|
||||
// For any unexpected status, redirect to order history with a generic error.
|
||||
$this->errors[] = Tools::displayError($this->trans('An unexpected payment status was received. Please check your order history.', [], 'Modules.Hutko.Shop'));
|
||||
$this->redirectWithNotifications($this->context->link->getPageLink('order-history', true, $this->context->language->id));
|
||||
break;
|
||||
}
|
||||
|
||||
// This part should ideally not be reached if all cases are handled with redirects.
|
||||
// However, as a fallback, if any errors were accumulated without a specific redirect,
|
||||
// redirect to the order page.
|
||||
if (count($this->errors)) {
|
||||
$this->redirectWithNotifications($this->context->link->getPageLink('order', true, $this->context->language->id));
|
||||
}
|
||||
}
|
||||
}
|
||||
426
hutko.php
426
hutko.php
@@ -21,26 +21,29 @@ class Hutko extends PaymentModule
|
||||
{
|
||||
|
||||
public $order_separator = '#';
|
||||
|
||||
public $checkout_url = 'https://pay.hutko.org/api/checkout/redirect/';
|
||||
public $redirect_url = 'https://pay.hutko.org/api/checkout/redirect/';
|
||||
public $checkout_url = 'https://pay.hutko.org/api/checkout/url/';
|
||||
public $refund_url = 'https://pay.hutko.org/api/reverse/order_id';
|
||||
public $status_url = 'https://pay.hutko.org/api/status/order_id';
|
||||
|
||||
|
||||
private $settingsList = [
|
||||
public $settingsList = [
|
||||
'HUTKO_MERCHANT',
|
||||
'HUTKO_SECRET_KEY',
|
||||
'HUTKO_BACK_REF',
|
||||
'HUTKO_SHIPPING_INCLUDE',
|
||||
'HUTKO_SHIPPING_PRODUCT_NAME',
|
||||
'HUTKO_SHIPPING_PRODUCT_CODE',
|
||||
'HUTKO_NEW_ORDER_STATUS_ID',
|
||||
'HUTKO_SUCCESS_STATUS_ID',
|
||||
'HUTKO_SHOW_CARDS_LOGO'
|
||||
];
|
||||
private $postErrors = [];
|
||||
public $postErrors = [];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->name = 'hutko';
|
||||
$this->tab = 'payments_gateways';
|
||||
$this->version = '1.1.1';
|
||||
$this->version = '1.2.0';
|
||||
$this->author = 'Hutko';
|
||||
$this->bootstrap = true;
|
||||
parent::__construct();
|
||||
@@ -50,12 +53,36 @@ class Hutko extends PaymentModule
|
||||
$this->description = $this->trans('Hutko is a payment platform whose main function is to provide internet acquiring.', array(), 'Modules.Hutko.Admin');
|
||||
}
|
||||
|
||||
public function install()
|
||||
public function install(): bool
|
||||
{
|
||||
return parent::install()
|
||||
$success = parent::install()
|
||||
&& $this->registerHook('paymentOptions')
|
||||
&& $this->registerHook('displayAdminOrderContentOrder')
|
||||
&& $this->registerHook('actionAdminControllerSetMedia');
|
||||
|
||||
// If the initial mandatory hooks failed, stop here.
|
||||
if (!$success) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now, conditionally register the order content/tab hook based on PS version.
|
||||
// We only need to check if the *required* hook for this version was successfully registered.
|
||||
$conditionalHookSuccess = true; // Assume success until we try to register one and it fails
|
||||
|
||||
// Check if PrestaShop version is 1.7.x (>= 1.7 and < 8.0)
|
||||
if (version_compare(_PS_VERSION_, '1.7', '>=') && version_compare(_PS_VERSION_, '8.0', '<')) {
|
||||
// Register the 1.7 hook
|
||||
$conditionalHookSuccess = $this->registerHook('displayAdminOrderContentOrder');
|
||||
}
|
||||
// Check if PrestaShop version is 8.x or 9.x (>= 8.0 and < 10.0)
|
||||
elseif (version_compare(_PS_VERSION_, '8.0', '>=') && version_compare(_PS_VERSION_, '10.0', '<')) {
|
||||
// Register the 8.x/9.x hook
|
||||
$conditionalHookSuccess = $this->registerHook('displayAdminOrderTabContent');
|
||||
}
|
||||
// Note: If it's a different version (e.g., 1.6, 10.0+), neither of these specific hooks will be registered,
|
||||
// and $conditionalHookSuccess remains true, which is the desired behavior based on the requirement.
|
||||
|
||||
// The module installation is successful only if the initial hooks passed AND the conditional hook (if attempted) passed.
|
||||
return $success && $conditionalHookSuccess;
|
||||
}
|
||||
|
||||
public function uninstall()
|
||||
@@ -98,7 +125,7 @@ class Hutko extends PaymentModule
|
||||
/**
|
||||
* Create the form that will be displayed in the configuration of your module.
|
||||
*/
|
||||
protected function renderForm()
|
||||
public function renderForm()
|
||||
{
|
||||
$helper = new HelperForm();
|
||||
|
||||
@@ -126,13 +153,13 @@ class Hutko extends PaymentModule
|
||||
/**
|
||||
* Create the structure of your form.
|
||||
*/
|
||||
protected function getConfigForm()
|
||||
public function getConfigForm()
|
||||
{
|
||||
global $cookie;
|
||||
|
||||
|
||||
$options = [];
|
||||
|
||||
foreach (OrderState::getOrderStates($cookie->id_lang) as $state) { // getting all Prestashop statuses
|
||||
foreach (OrderState::getOrderStates($this->context->language->id) as $state) { // getting all Prestashop statuses
|
||||
if (empty($state['module_name'])) {
|
||||
$options[] = ['status_id' => $state['id_order_state'], 'name' => $state['name'] . " [ID: $state[id_order_state]]"];
|
||||
}
|
||||
@@ -149,16 +176,16 @@ class Hutko extends PaymentModule
|
||||
'col' => 4,
|
||||
'type' => 'text',
|
||||
'prefix' => '<i class="icon icon-user"></i>',
|
||||
'desc' => $this->trans('Enter a merchant id', array(), 'Modules.Hutko.Admin'),
|
||||
'desc' => $this->trans('Enter a merchant id. Use 1700002 for test setup.', array(), 'Modules.Hutko.Admin'),
|
||||
'name' => 'HUTKO_MERCHANT',
|
||||
'label' => $this->trans('Merchant ID', array(), 'Modules.Hutko.Admin'),
|
||||
'label' => $this->trans('Merchant ID.', array(), 'Modules.Hutko.Admin'),
|
||||
),
|
||||
array(
|
||||
'col' => 4,
|
||||
'type' => 'text',
|
||||
'prefix' => '<i class="icon icon-key"></i>',
|
||||
'name' => 'HUTKO_SECRET_KEY',
|
||||
'desc' => $this->trans('Enter a secret key', array(), 'Modules.Hutko.Admin'),
|
||||
'desc' => $this->trans('Enter a secret key. Use "test" for test setup', array(), 'Modules.Hutko.Admin'),
|
||||
'label' => $this->trans('Secret key', array(), 'Modules.Hutko.Admin'),
|
||||
),
|
||||
array(
|
||||
@@ -172,6 +199,49 @@ class Hutko extends PaymentModule
|
||||
'name' => 'name'
|
||||
)
|
||||
),
|
||||
array(
|
||||
'type' => 'select',
|
||||
'prefix' => '<i class="icon icon-key"></i>',
|
||||
'name' => 'HUTKO_NEW_ORDER_STATUS_ID',
|
||||
'label' => $this->trans('Status for new orders before payment', array(), 'Modules.Hutko.Admin'),
|
||||
'options' => array(
|
||||
'query' => $options,
|
||||
'id' => 'status_id',
|
||||
'name' => 'name'
|
||||
)
|
||||
),
|
||||
array(
|
||||
'type' => 'radio',
|
||||
'name' => 'HUTKO_SHIPPING_INCLUDE',
|
||||
'label' => $this->trans('Include shipping cost to payment', array(), 'Modules.Hutko.Admin'),
|
||||
'is_bool' => true,
|
||||
'values' => array(
|
||||
array(
|
||||
'id' => 'show_cards',
|
||||
'value' => 1,
|
||||
'label' => $this->trans('Yes', array(), 'Modules.Hutko.Admin')
|
||||
),
|
||||
array(
|
||||
'id' => 'hide_cards',
|
||||
'value' => 0,
|
||||
'label' => $this->trans('No', array(), 'Modules.Hutko.Admin')
|
||||
)
|
||||
),
|
||||
),
|
||||
array(
|
||||
'type' => 'text',
|
||||
'name' => 'HUTKO_SHIPPING_PRODUCT_NAME',
|
||||
'label' => $this->trans('Shipping Name', array(), 'Modules.Hutko.Admin'),
|
||||
'desc' => $this->trans('Name of product/service to use in fiscalization for shipping amount', array(), 'Modules.Hutko.Admin'),
|
||||
|
||||
),
|
||||
array(
|
||||
'type' => 'text',
|
||||
'name' => 'HUTKO_SHIPPING_PRODUCT_CODE',
|
||||
'label' => $this->trans('Shipping Code', array(), 'Modules.Hutko.Admin'),
|
||||
'desc' => $this->trans('Code of product/service to use in fiscalization for shipping amount', array(), 'Modules.Hutko.Admin'),
|
||||
|
||||
),
|
||||
array(
|
||||
'type' => 'radio',
|
||||
'label' => $this->trans('Show Visa/MasterCard logo', array(), 'Modules.Hutko.Admin'),
|
||||
@@ -191,6 +261,7 @@ class Hutko extends PaymentModule
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
'submit' => array(
|
||||
'title' => $this->trans('Save', array(), 'Modules.Hutko.Admin'),
|
||||
'class' => 'btn btn-default pull-right'
|
||||
@@ -202,25 +273,21 @@ class Hutko extends PaymentModule
|
||||
/**
|
||||
* Set values for the inputs.
|
||||
*/
|
||||
protected function getConfigFormValues()
|
||||
public function getConfigFormValues(): array
|
||||
{
|
||||
return array(
|
||||
'HUTKO_MERCHANT' => Configuration::get('HUTKO_MERCHANT', null),
|
||||
'HUTKO_SECRET_KEY' => Configuration::get('HUTKO_SECRET_KEY', null),
|
||||
'HUTKO_SUCCESS_STATUS_ID' => Configuration::get('HUTKO_SUCCESS_STATUS_ID', null),
|
||||
'HUTKO_SHOW_CARDS_LOGO' => Configuration::get('HUTKO_SHOW_CARDS_LOGO', null),
|
||||
);
|
||||
foreach ($this->settingsList as $settingName) {
|
||||
$list[$settingName] = Configuration::get($settingName);
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save form data.
|
||||
*/
|
||||
protected function postProcess()
|
||||
public function postProcess()
|
||||
{
|
||||
|
||||
$form_values = $this->getConfigFormValues();
|
||||
foreach (array_keys($form_values) as $key) {
|
||||
Configuration::updateValue($key, Tools::getValue($key));
|
||||
foreach ($this->settingsList as $settingName) {
|
||||
Configuration::updateValue($settingName, Tools::getValue($settingName));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -231,7 +298,7 @@ class Hutko extends PaymentModule
|
||||
* Merchant ID and Secret Key provided by the user. It adds error messages
|
||||
* to the `$this->postErrors` array if any of the validation rules fail.
|
||||
*/
|
||||
private function postValidation(): void
|
||||
public function postValidation(): void
|
||||
{
|
||||
// Check if the module's configuration form has been submitted.
|
||||
if (Tools::isSubmit('submitHutkoModule')) {
|
||||
@@ -323,41 +390,60 @@ class Hutko extends PaymentModule
|
||||
* @return array An associative array containing the input parameters for the
|
||||
* payment gateway. This array includes the generated signature.
|
||||
*/
|
||||
public function buildInputs(): array
|
||||
public function buildPaymentRequestData(Order $order, ?float $amount, ?Currency $currency, ?Customer $customer): array
|
||||
{
|
||||
// 1. Generate a unique order ID combining the cart ID and current timestamp.
|
||||
$orderId = $this->context->cart->id . $this->order_separator . time();
|
||||
$orderId = $order->id . $this->order_separator . time();
|
||||
|
||||
// 2. Retrieve the merchant ID from the module's configuration.
|
||||
$merchantId = Configuration::get('HUTKO_MERCHANT');
|
||||
|
||||
// 3. Create a description for the order.
|
||||
$orderDescription = $this->trans('Cart pay №', [], 'Modules.Hutko.Admin') . $this->context->cart->id;
|
||||
$orderDescription = $this->trans('Order payment #', [], 'Modules.Hutko.Admin') . $order->reference;
|
||||
// 4. Calculate the order amount in the smallest currency unit.
|
||||
$amount = round($this->context->cart->getOrderTotal(true, CART::ONLY_PRODUCTS) * 100);
|
||||
if (!$amount) {
|
||||
if (Configuration::get('HUTKO_SHIPPING_INCLUDE') && $order->total_shipping_tax_incl > 0) {
|
||||
$amount = $order->total_products_wt + $order->total_shipping_tax_incl;
|
||||
} else {
|
||||
$amount = $order->total_products;
|
||||
}
|
||||
}
|
||||
|
||||
$amountInt = round($amount * 100);
|
||||
// 5. Get the currency ISO code of the current cart.
|
||||
$currency = $this->context->currency->iso_code;
|
||||
if (!$currency) {
|
||||
$currency = new Currency($order->id_currency);
|
||||
}
|
||||
$currencyISO = $currency->iso_code;
|
||||
|
||||
// 6. Generate the server callback URL.
|
||||
$serverCallbackUrl = $this->context->link->getModuleLink($this->name, 'callback', [], true);
|
||||
// 7. Retrieve the customer's email address.
|
||||
if (!$customer) {
|
||||
$customer = new Customer($order->id_customer);
|
||||
}
|
||||
$customerEmail = $customer->email;
|
||||
|
||||
// 8. Generate the customer redirection URL after payment.
|
||||
$responseUrl = $this->context->link->getPageLink('order-confirmation', true, $order->id_lang, [
|
||||
'id_cart' => $order->id_cart,
|
||||
'id_module' => $this->id,
|
||||
'id_order' => $order->id,
|
||||
'key' => $customer->secure_key,
|
||||
]);
|
||||
|
||||
// 7. Generate the customer redirection URL after payment.
|
||||
$responseUrl = $this->context->link->getModuleLink($this->name, 'result', [], true);
|
||||
|
||||
// 8. Retrieve the customer's email address.
|
||||
$customerEmail = $this->context->customer->email;
|
||||
|
||||
// 9. Build the reservation data as a base64 encoded JSON string.
|
||||
$reservationData = $this->buildReservationData();
|
||||
$reservationData = $this->buildReservationData($order);
|
||||
|
||||
// 10. Construct the data array with all the collected parameters.
|
||||
$data = [
|
||||
'order_id' => $orderId,
|
||||
'merchant_id' => $merchantId,
|
||||
'order_desc' => $orderDescription,
|
||||
'amount' => $amount,
|
||||
'currency' => $currency,
|
||||
'amount' => $amountInt,
|
||||
'currency' => $currencyISO,
|
||||
'server_callback_url' => $serverCallbackUrl,
|
||||
'response_url' => $responseUrl,
|
||||
'sender_email' => $customerEmail,
|
||||
@@ -384,15 +470,15 @@ class Hutko extends PaymentModule
|
||||
*
|
||||
* @return string A base64 encoded JSON string containing the reservation data.
|
||||
*/
|
||||
public function buildReservationData(): string
|
||||
public function buildReservationData(Order $order): string
|
||||
{
|
||||
// 1. Retrieve the delivery address for the current cart.
|
||||
$address = new Address((int)$this->context->cart->id_address_delivery, $this->context->language->id);
|
||||
$address = new Address((int)$order->id_address_delivery, $order->id_lang);
|
||||
|
||||
// 2. Fetch the customer's state name, if available.
|
||||
$customerState = '';
|
||||
if ($address->id_state) {
|
||||
$state = new State((int) $address->id_state, $this->context->language->id);
|
||||
$state = new State((int) $address->id_state, $order->id_lang);
|
||||
$customerState = $state->name;
|
||||
}
|
||||
|
||||
@@ -409,16 +495,15 @@ class Hutko extends PaymentModule
|
||||
"customer_name" => $this->getSlug($address->lastname . ' ' . $address->firstname),
|
||||
"customer_city" => $this->getSlug($address->city),
|
||||
"customer_zip" => $address->postcode,
|
||||
"account" => $this->context->customer->id,
|
||||
"account" => $order->id_customer,
|
||||
"uuid" => hash('sha256', _COOKIE_KEY_ . Tools::getShopDomainSsl()),
|
||||
"products" => $this->getProducts(),
|
||||
"products" => $this->getProducts($order),
|
||||
];
|
||||
|
||||
// 4. Encode the data array as a JSON string.
|
||||
$jsonData = json_encode($data);
|
||||
|
||||
// 5. Base64 encode the JSON string.
|
||||
return base64_encode($jsonData);
|
||||
|
||||
|
||||
return base64_encode(json_encode($data));
|
||||
}
|
||||
|
||||
|
||||
@@ -438,16 +523,26 @@ class Hutko extends PaymentModule
|
||||
* - 'total_amount': The total price of the product in the cart (price * quantity), rounded to two decimal places.
|
||||
* - 'quantity': The quantity of the product in the cart.
|
||||
*/
|
||||
public function getProducts(): array
|
||||
public function getProducts(Order $order): array
|
||||
{
|
||||
$products = [];
|
||||
foreach ($this->context->cart->getProducts() as $cartProduct) {
|
||||
foreach ($order->getProductsDetail() as $productDetail) {
|
||||
$products[] = [
|
||||
"id" => (int)$cartProduct['id_product'],
|
||||
"name" => $cartProduct['name'],
|
||||
"price" => round((float)$cartProduct['price_with_reduction'], 2),
|
||||
"total_amount" => round((float) $cartProduct['price'] * (int)$cartProduct['quantity'], 2),
|
||||
"quantity" => (int)$cartProduct['quantity'],
|
||||
"id" => $productDetail['product_id'] . '_' . $productDetail['product_attribute_id'] . '_' . $productDetail['id_customization'],
|
||||
"name" => $productDetail['product_name'],
|
||||
"price" => round((float)$productDetail['unit_price_tax_incl'], 2),
|
||||
"total_amount" => round((float) $productDetail['total_price_tax_incl'], 2),
|
||||
"quantity" => (int)$productDetail['product_quantity'],
|
||||
];
|
||||
}
|
||||
|
||||
if (Configuration::get('HUTKO_SHIPPING_INCLUDE') && $order->total_shipping_tax_incl > 0) {
|
||||
$products[] = [
|
||||
"id" => Configuration::get('HUTKO_SHIPPING_PRODUCT_CODE', null, null, null, '0_0_1'),
|
||||
"name" => Configuration::get('HUTKO_SHIPPING_PRODUCT_NAME', null, null, null, 'Service Fee'),
|
||||
"price" => round((float)$order->total_shipping_tax_incl, 2),
|
||||
"total_amount" => round((float) $order->total_shipping_tax_incl, 2),
|
||||
"quantity" => 1,
|
||||
];
|
||||
}
|
||||
return $products;
|
||||
@@ -455,31 +550,6 @@ class Hutko extends PaymentModule
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Validates an order based on the provided cart ID and expected amount,
|
||||
* setting the order status to "preparation".
|
||||
*
|
||||
* This method serves as a convenience wrapper around the `validateOrder` method,
|
||||
* pre-filling the order status with the configured "preparation" status.
|
||||
*
|
||||
* @param int $id_cart The ID of the cart associated with the order to be validated.
|
||||
* @param float $amount The expected total amount of the order. This value will be
|
||||
* compared against the cart's total.
|
||||
* @return bool True if the order validation was successful, false otherwise.
|
||||
* @see PaymentModule::validateOrder()
|
||||
*/
|
||||
public function validateOrderFromCart(int $id_cart, float $amount, string $transaction_id = '', int $idState = 0, bool $fromCallBack = false): bool
|
||||
{
|
||||
if (!$idState) {
|
||||
$idState = (int) Configuration::get('PS_OS_PREPARATION');
|
||||
}
|
||||
if ($fromCallBack) {
|
||||
$this->context->cart = new Cart($id_cart);
|
||||
$this->context->customer = new Customer($this->context->cart->id_customer);
|
||||
}
|
||||
// Call the parent validateOrder method with the "preparation" status.
|
||||
return $this->validateOrder($id_cart, $idState, $amount, $this->displayName, null, ['transaction_id' => $transaction_id], null, false, $this->context->customer->secure_key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a URL-friendly slug from a given text.
|
||||
@@ -618,7 +688,7 @@ class Hutko extends PaymentModule
|
||||
public function validateResponse(array $response): bool
|
||||
{
|
||||
// 1. Verify the Merchant ID
|
||||
if (Configuration::get('HUTKO_MERCHANT') !== $response['merchant_id']) {
|
||||
if ((string)Configuration::get('HUTKO_MERCHANT') != (string)$response['merchant_id']) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -636,43 +706,6 @@ class Hutko extends PaymentModule
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Postpones the execution of a callback function until the last digit of the current second
|
||||
* matches a specified target digit, and returns the result of the callback.
|
||||
*
|
||||
* @param callable $callback The callback function to execute.
|
||||
* @param int $targetDigit An integer from 0 to 9, representing the desired last digit of the second.
|
||||
* return the result of the callback function execution.
|
||||
* @throws InvalidArgumentException If $targetDigit is not an integer between 0 and 9.
|
||||
*/
|
||||
function postponeCallback(callable $callback, int $targetDigit)
|
||||
{
|
||||
// Validate the target digit to ensure it's within the valid range (0-9)
|
||||
if ($targetDigit < 0 || $targetDigit > 9) {
|
||||
throw new InvalidArgumentException("The target digit must be an integer between 0 and 9.");
|
||||
}
|
||||
|
||||
// Loop indefinitely until the condition is met
|
||||
while (true) {
|
||||
// Get the current second as a two-digit string (e.g., '05', '12', '59')
|
||||
$currentSecond = (int)date('s');
|
||||
|
||||
// Extract the last digit of the current second
|
||||
$lastDigitOfSecond = $currentSecond % 10;
|
||||
|
||||
// Check if the last digit matches the target digit
|
||||
if ($lastDigitOfSecond === $targetDigit) {
|
||||
echo "Condition met! Current second is {$currentSecond}, last digit is {$lastDigitOfSecond}.\n";
|
||||
// If the condition is met, execute the callback and return its result
|
||||
return $callback(); // Capture and return the callback's result
|
||||
} else {
|
||||
// If the condition is not met, print the current status and wait for a short period
|
||||
echo "Current second: {$currentSecond}, last digit: {$lastDigitOfSecond}. Still waiting...\n";
|
||||
// Wait for 100 milliseconds (0.1 seconds) to avoid busy-waiting and reduce CPU usage
|
||||
usleep(100000); // 100000 microseconds = 100 milliseconds
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -687,49 +720,131 @@ class Hutko extends PaymentModule
|
||||
{
|
||||
$order = new Order($orderId);
|
||||
// Only update if the order is loaded and the current state is different from the new state.
|
||||
if (Validate::isLoadedObject($order) && (int)$order->getCurrentState() !== $newStateId) {
|
||||
if (Validate::isLoadedObject($order) && (int)$order->getCurrentState() != $newStateId) {
|
||||
$history = new OrderHistory();
|
||||
$history->id_order = $orderId;
|
||||
$history->changeIdOrderState($newStateId, $orderId);
|
||||
$history->addWithemail();
|
||||
}
|
||||
}
|
||||
public function addPayment(array $callback, Order $order): void
|
||||
{
|
||||
$callbackAmount = $callback['actual_amount'] ?? $callback['amount'];
|
||||
$amountFloat = round($callbackAmount / 100, 2);
|
||||
|
||||
$order->addOrderPayment($amountFloat, $this->displayName, $callback['order_id'], $order->id_currency);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Hook to display content in the admin order page tabs.
|
||||
* This will add a new tab for "Hutko Payments" or similar.
|
||||
* Hook implementation for PrestaShop 1.7.x to display content in the admin order page.
|
||||
*
|
||||
* @param array $params Contains Order 'order'
|
||||
* @return string
|
||||
* This hook is typically used to add content *below* the main order details
|
||||
* but before the tabbed section. It's often used for specific sections
|
||||
* rather than entire tabs in 1.7. However, in this case, it's likely
|
||||
* being used as a fallback or alternative for displaying the payment content
|
||||
* depending on the module's design or compatibility needs for 1.7.
|
||||
*
|
||||
* @param array $params Contains context information, including the 'order' object.
|
||||
* @return string The HTML content to be displayed in the admin order page.
|
||||
*/
|
||||
public function hookdisplayAdminOrderContentOrder(array $params): string
|
||||
public function hookdisplayAdminOrderContentOrder(array $params)
|
||||
{
|
||||
// Delegate the actual content generation to a shared function
|
||||
// to avoid code duplication.
|
||||
return $this->displayAdminOrderContent($params);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Hook implementation for PrestaShop 8.x and 9.x to display content
|
||||
* within a specific tab on the admin order page.
|
||||
*
|
||||
* This hook is the standard way in newer PS versions to add a custom tab
|
||||
* and populate its content on the order detail page.
|
||||
*
|
||||
* @param array $params Contains context information, including the 'order' object.
|
||||
* @return string The HTML content to be displayed within the module's custom tab.
|
||||
*/
|
||||
public function hookdisplayAdminOrderTabContent(array $params)
|
||||
{
|
||||
$params['order'] = new Order((int) $params['id_order']);
|
||||
// Delegate the actual content generation to a shared function
|
||||
// to avoid code duplication.
|
||||
return $this->displayAdminOrderContent($params);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Common function to display content related to Hutko payments on the admin order page.
|
||||
*
|
||||
* This function handles the logic for processing potential form submissions (like refunds
|
||||
* or status updates) and preparing data to be displayed in a template.
|
||||
*
|
||||
* It is called by different hooks depending on the PrestaShop version
|
||||
* (displayAdminOrderContentOrder for 1.7.x, displayAdminOrderTabContent for 8.x/9.x).
|
||||
*
|
||||
* @param array $params Contains context information from the hook, typically including the 'order' object.
|
||||
* @return string The rendered HTML content from the template.
|
||||
*/
|
||||
public function displayAdminOrderContent(array $params): string
|
||||
{
|
||||
// Check if a refund form has been submitted
|
||||
if (Tools::isSubmit('hutkoRefundsubmit')) {
|
||||
// Process the refund logic.
|
||||
$this->processRefundForm();
|
||||
}
|
||||
if (Tools::getValue('hutkoOrderStatus')) {
|
||||
$this->processOrderStatus(Tools::getValue('hutkoOrderStatus'));
|
||||
}
|
||||
// This hook is used to render the content of the new tab on the order page.
|
||||
// We will fetch the payments for this order and pass them to the template.
|
||||
|
||||
// Check payment status
|
||||
if (Tools::getValue('hutkoOrderPaymentStatus')) {
|
||||
// Process the requested order status check.
|
||||
$this->processOrderPaymentStatus(Tools::getValue('hutkoOrderPaymentStatus'));
|
||||
}
|
||||
|
||||
// Ensure the 'order' object is present in the parameters
|
||||
if (!isset($params['order']) || !$params['order'] instanceof Order) {
|
||||
// Log an error or return an empty string if the order object is missing
|
||||
// depending on how critical it is. Returning empty string is safer
|
||||
// to avoid crashing the admin page.
|
||||
PrestaShopLogger::addLog(
|
||||
'Hutko Module: Order object missing in displayAdminOrderContent hook.',
|
||||
1, // Error level
|
||||
null,
|
||||
'Module',
|
||||
(int)$this->id
|
||||
);
|
||||
return '';
|
||||
}
|
||||
|
||||
// Get the Order object from the parameters
|
||||
$order = $params['order'];
|
||||
|
||||
|
||||
// Fetch payments made via Hutko for this order
|
||||
// Fetch all OrderPayment records associated with this order
|
||||
// that were processed specifically by this payment module (based on display name)
|
||||
// and have a transaction ID matching a specific pattern (order ID prefix).
|
||||
// The transaction_id pattern suggests it's linked to the order ID for easy lookup.
|
||||
$hutkoPayments = new PrestaShopCollection('OrderPayment');
|
||||
$hutkoPayments->where('order_reference', '=', $order->reference);
|
||||
$hutkoPayments->where('payment_method', '=', $this->displayName);
|
||||
$hutkoPayments->where('order_reference', '=', $order->reference); // Filter by order reference
|
||||
$hutkoPayments->where('payment_method', '=', $this->displayName); // Filter by this module's payment method name
|
||||
// Filter by transaction ID pattern: Starts with the order ID followed by the configured separator.
|
||||
// This assumes transaction IDs generated by this module follow this format.
|
||||
$hutkoPayments->where('transaction_id', 'like', '' . $order->id . $this->order_separator . '%');
|
||||
|
||||
// Assign data to Smarty to be used in the template
|
||||
$this->context->smarty->assign([
|
||||
'hutkoPayments' => $hutkoPayments->getAll(),
|
||||
// Pass the fetched Hutko payment records to the template as an array
|
||||
'hutkoPayments' => $hutkoPayments,
|
||||
// Pass the order ID to the template
|
||||
'id_order' => $order->id,
|
||||
'currency' => new Currency($order->id_currency),
|
||||
]);
|
||||
|
||||
// Render the template located at 'views/templates/admin/order_payment_refund.tpl'
|
||||
// This template will display the fetched payment information and potentially refund/status forms.
|
||||
return $this->display(__FILE__, 'views/templates/admin/order_payment_refund.tpl');
|
||||
}
|
||||
public function processOrderStatus(string $order_id): void
|
||||
|
||||
public function processOrderPaymentStatus(string $order_id): void
|
||||
{
|
||||
$data = [
|
||||
'order_id' => $order_id,
|
||||
@@ -741,32 +856,22 @@ class Hutko extends PaymentModule
|
||||
$response = $this->sendAPICall($this->status_url, $data);
|
||||
$this->context->controller->informations[] = $this->displayArrayInNotification($response['response']);
|
||||
}
|
||||
/**
|
||||
* Hook to set media (JS/CSS) for admin controllers.
|
||||
* Used to load our custom JavaScript for the refund modal.
|
||||
*
|
||||
* @param array $params
|
||||
* @return void
|
||||
*/
|
||||
public function hookActionAdminControllerSetMedia(array $params): void
|
||||
{
|
||||
// Only load our JS on the AdminOrders controller page
|
||||
if ($this->context->controller->controller_name === 'AdminOrders') {
|
||||
}
|
||||
}
|
||||
|
||||
public function processRefundForm()
|
||||
{
|
||||
$orderPaymentId = (int) Tools::getValue('orderPaymentId');
|
||||
$amount = (float) Tools::getValue('refund_amount');
|
||||
$comment = mb_substr(Tools::getValue('orderPaymentId', ''), 0, 1024);
|
||||
$orderId = (int) Tools::getValue('id_order');
|
||||
$result = $this->processRefund($orderPaymentId, $orderId, $amount, $comment);
|
||||
$id_order = (int) Tools::getValue('id_order');
|
||||
$result = $this->processRefund($orderPaymentId, $id_order, $amount, $comment);
|
||||
$link = $this->context->link->getAdminLink('AdminOrders', true, [], ['id_order' => $id_order, 'vieworder' => true]);
|
||||
if ($result->error) {
|
||||
$this->context->controller->errors[] = $result->description;
|
||||
}
|
||||
if ($result->success) {
|
||||
$this->context->controller->informations[] = $result->description;
|
||||
}
|
||||
// Tools::redirectAdmin($link);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -836,9 +941,6 @@ class Hutko extends PaymentModule
|
||||
|
||||
$order = new Order($orderId);
|
||||
|
||||
// Add a note to the order history.
|
||||
$this->updateOrderStatus($order->id, (int)Configuration::get('PS_OS_REFUND'));
|
||||
|
||||
// Add a private message to the order for tracking.
|
||||
$order->addOrderPayment(
|
||||
-$amount, // Negative amount for refund
|
||||
@@ -846,6 +948,8 @@ class Hutko extends PaymentModule
|
||||
$orderPayment->transaction_id
|
||||
);
|
||||
|
||||
$order->setCurrentState((int)Configuration::get('PS_OS_REFUND'), $this->context->employee->id);
|
||||
|
||||
PrestaShopLogger::addLog(
|
||||
'Hutko Refund: Successfully processed refund for Order: ' . $orderId . ', Amount: ' . $amount . ', Comment: ' . $comment,
|
||||
1, // Info
|
||||
@@ -1014,4 +1118,16 @@ class Hutko extends PaymentModule
|
||||
$retStr .= '</ul>';
|
||||
return $retStr;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if the module uses the new translation system.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isUsingNewTranslationSystem()
|
||||
{
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
212
translations/ru-RU/ModulesHutkoAdmin.ru-RU.xlf
Normal file
212
translations/ru-RU/ModulesHutkoAdmin.ru-RU.xlf
Normal file
@@ -0,0 +1,212 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
|
||||
<file original="admin105hcnvdgjnh2pvlogh" source-language="uk-UA" target-language="uk-UA" datatype="plaintext">
|
||||
<body>
|
||||
<trans-unit id="c95fbd80950d3a4e360c5ae79fa93ca5">
|
||||
<source>Hutko is a payment platform whose main function is to provide internet acquiring.</source>
|
||||
<target>Hutko — це платіжна платформа, основною функцією якої є забезпечення інтернет-еквайрингу.</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="90c65a6cb64f590f26b4fbdb319fc896">
|
||||
<source>Довідка specify the Hutko account details for customers</source>
|
||||
<target>Пожалуйста, уточніть реквізити акаунту Hutko для клієнтів</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="6462e4d033501dde8eb84cd52d8a5573">
|
||||
<source>Enter merchant id. Use 1700002 for test setup.</source>
|
||||
<target>Введіть ідентифікатор продавця. Використовуйте 1700002 для тестового налаштування.</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="73c6484e3e3c1dbd17e6598c40c150f5">
|
||||
<source>Merchant ID.</source>
|
||||
<target>Merchant ID.</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="7beba75bd51b2d96fb8d79d34912de1b">
|
||||
<source>Enter a secret key. use "test" for test setup</source>
|
||||
<target>Введіть секретний ключ. Використовуйте тест для налаштування тесту.</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="952bf87c967660b7bbd4e1eb08cefc92">
|
||||
<source>Secret key</source>
|
||||
<target>Секретний ключ</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="7548bac714d635c3d0a331e4aca1db72">
|
||||
<source>Status after success payment</source>
|
||||
<target>Статус після успішної оплати</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="76f18bb270498e4bdfbaf71f35cc84dd">
|
||||
<source>Status for new orders before payment</source>
|
||||
<target>Статус нових замовлень до оплати</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="7ea50bc7d053b09d9627771600b149e4">
|
||||
<source>Include shipping cost to payment</source>
|
||||
<target>Включити вартість доставки до оплати</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="93cba07454f06a4a960172bbd6e2a435">
|
||||
<source>Yes</source>
|
||||
<target>Так</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="bafd7322c6e97d25b6299b5d6fe8920b">
|
||||
<source>No</source>
|
||||
<target>Ні</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="3f16b64626ca0cc193b0013217a78726">
|
||||
<source>Shipping Name</source>
|
||||
<target>Назва для доставки</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="2c154e95e7ee1d753dd3ea4e1b0c8857">
|
||||
<source>Назва продукту/сервісу для використання в fiscalization for shipping amount</source>
|
||||
<target>Назва продукту/послуги для використання у фіскалізації для суми доставки</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="32de1d30aa06d42f43863e7cd71c1b4c">
|
||||
<source>Shipping Code</source>
|
||||
<target>Код доставки</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="8a6d12c2cbdd17f109a1685372a54fee">
|
||||
<source>Code product/service для використання в fiscalization for shipping amount</source>
|
||||
<target>Код товару/послуги для використання у фіскалізації для суми доставки</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="dbecc121e4f3f58940d7be4a57444526">
|
||||
<source>Show Visa/MasterCard logo</source>
|
||||
<target>Показати логотип Visa/MasterCard</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="c9cc8cce247e49bae79f15173ce97354">
|
||||
<source>Save</source>
|
||||
<target>Зберегти</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="2e70d995f0032b8859dd5ef37162087f">
|
||||
<source>Merchant ID is required.</source>
|
||||
<target>Потрібен ідентифікатор продавця (Merchant ID).</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="66a500cd593b25ebc543c002b345b579">
|
||||
<source>Merchant ID must be numeric.</source>
|
||||
<target>Ідентифікатор продавця має бути числовим.</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="1c2eee355024adcde515449347201000">
|
||||
<source>Secret key is required.</source>
|
||||
<target>Потрібен секретний ключ.</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="40bf93e3dcf907a8aad77d1b0f2a2921">
|
||||
<source>Секрет key must be at least 10 characters long and cannot be entirely numeric.</source>
|
||||
<target>Секретний ключ повинен містити щонайменше 10 символів і не може бути повністю числовим.</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="23638e456c7b83bd1953dbc0996620be">
|
||||
<source>Pay via payment system Hutko</source>
|
||||
<target>Оплата через платіжну систему Hutko</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="223e639daf07b520427aa6c80e36fffb">
|
||||
<source>Pay via Hutko</source>
|
||||
<target>Оплата через Hutko</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="feed0d2100a232322a28616d350029e6">
|
||||
<source>Order payment #</source>
|
||||
<target>Оплата замовлення #</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="789b043f02dbe86d80a6916a31553d0b">
|
||||
<source>Order payment not found.</source>
|
||||
<target>Оплата замовлення не знайдена.</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="5b475e4412cc0a11f089e0c6279220fb">
|
||||
<source>Invalid transaction ID format.</source>
|
||||
<target>Недійсний формат ідентифікатора транзакції.</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="272d77ac6ed0ef79325c3dae71b2a780">
|
||||
<source>Refund success.</source>
|
||||
<target>Повернення коштів успішне.</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="9f5daba4b8de3a0f6cdfab206a08f211">
|
||||
<source><![CDATA[Hutko Payments & Refunds]]></source>
|
||||
<target>Платежі та повернення коштів Hutko</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="88427ec035734b45aae9f7d8859a5008">
|
||||
<source>Transaction ID</source>
|
||||
<target>Transaction ID</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="b2f40690858b404ed10e62bdf422c704">
|
||||
<source>Amount</source>
|
||||
<target>Сума</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="31738cd694667ccdfa2cbc65249de5cc">
|
||||
<source>Payment Date</source>
|
||||
<target>Дата платежу</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="06df33001c1d7187fdd81ea1f5b277aa">
|
||||
<source>Actions</source>
|
||||
<target>Дії</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="76f0ed934de85cc7131910b32ede7714">
|
||||
<source>Refund</source>
|
||||
<target>Повернення коштів</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="ec53a8c4f07baed5d8825072c89799be">
|
||||
<source>Status</source>
|
||||
<target>Статус</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="88b6563ca5cac4845361c28959c5612e">
|
||||
<source>Initiate Refund</source>
|
||||
<target>Ініціювати повернення коштів</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="b782d4ff61550d7e8cdee4cf70a03788">
|
||||
<source>Refund Amount</source>
|
||||
<target>Сума відшкодування</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="7bdf5ab3a17ec2dce33865622b238bd1">
|
||||
<source>Виберіть гроші для того, щоб скористатися цим платежом.</source>
|
||||
<target>Введіть суму для повернення коштів за цей платіж.</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="a48f878efa7beadc6bab76f96fce6b62">
|
||||
<source>Refund Reason/Comment</source>
|
||||
<target>Причина/коментар повернення коштів</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="a331a1c920188f766c73334a17774dec">
|
||||
<source>Optional: A brief reason for the refund.</source>
|
||||
<target>Необов'язково: Коротка причина повернення коштів.</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="ea4788705e6873b424c65e91c2846b19">
|
||||
<source>Cancel</source>
|
||||
<target>Скасувати</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="968d5d0a76be35f96b91b808a39744cd">
|
||||
<source>Process Refund</source>
|
||||
<target>Виконати повернення коштів</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
||||
22
translations/ru-RU/ModulesHutkoShop.ru-RU.xlf
Normal file
22
translations/ru-RU/ModulesHutkoShop.ru-RU.xlf
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
|
||||
<file original="admin105hcnvdgjnh2pvlogh" source-language="ru-UA" target-language="ru-UA" datatype="plaintext">
|
||||
<body>
|
||||
<trans-unit id="22af22c7d772e149e295809344fe5522">
|
||||
<source>Payment failure. </source>
|
||||
<target>Сбой оплаты.</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="82e50c727674f251464fc7520f5bde26">
|
||||
<source>Допустить попытку</source>
|
||||
<target>Попробуйте еще раз</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="4be36be30fde5361b25b121a6c9e631e">
|
||||
<source>Order validation failure</source>
|
||||
<target>Ошибка проверки заказа</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
||||
212
translations/uk-UA/ModulesHutkoAdmin.uk-UA.xlf
Normal file
212
translations/uk-UA/ModulesHutkoAdmin.uk-UA.xlf
Normal file
@@ -0,0 +1,212 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
|
||||
<file original="admin105hcnvdgjnh2pvlogh" source-language="ru-UA" target-language="ru-UA" datatype="plaintext">
|
||||
<body>
|
||||
<trans-unit id="c95fbd80950d3a4e360c5ae79fa93ca5">
|
||||
<source>Hutko is a payment platform whose main function is to provide internet acquiring.</source>
|
||||
<target>Hutko – это платежная платформа, основной функцией которой является обеспечение интернет-эквайринга.</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="90c65a6cb64f590f26b4fbdb319fc896">
|
||||
<source>Связать specify the Hutko account details for customers</source>
|
||||
<target>Пожалуйста, уточните реквизиты учетной записи Hutko для клиентов</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="6462e4d033501dde8eb84cd52d8a5573">
|
||||
<source>Enter для merchant id.
|
||||
<target>Введите идентификатор продавца. Используйте 1700002 для тестовой настройки.</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="73c6484e3e3c1dbd17e6598c40c150f5">
|
||||
<source>Merchant ID.</source>
|
||||
<target>Merchant ID.</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="7beba75bd51b2d96fb8d79d34912de1b">
|
||||
<source>Enter a secret key.
|
||||
<target>Введите секретный ключ.
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="952bf87c967660b7bbd4e1eb08cefc92">
|
||||
<source>Secret key</source>
|
||||
<target>Секретный ключ</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="7548bac714d635c3d0a331e4aca1db72">
|
||||
<source>Status after success payment</source>
|
||||
<target>Статус после успешной оплаты</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="76f18bb270498e4bdfbaf71f35cc84dd">
|
||||
<source>Status for new orders before payment</source>
|
||||
<target>Статус новых заказов к оплате</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="7ea50bc7d053b09d9627771600b149e4">
|
||||
<source>Включая плату за выплату</source>
|
||||
<target>Включить стоимость доставки в оплату</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="93cba07454f06a4a960172bbd6e2a435">
|
||||
<source>Yes</source>
|
||||
<target>Да</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="bafd7322c6e97d25b6299b5d6fe8920b">
|
||||
<source>No</source>
|
||||
<target>Нет</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="3f16b64626ca0cc193b0013217a78726">
|
||||
<source>Shipping Name</source>
|
||||
<target>Название для доставки</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="2c154e95e7ee1d753dd3ea4e1b0c8857">
|
||||
<source>Имя продукта/сервиса для использования в fiscalization for shipping amount</source>
|
||||
<target>Имя продукта/услуги для использования в фискализации для суммы доставки</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="32de1d30aa06d42f43863e7cd71c1b4c">
|
||||
<source>Shipping Code</source>
|
||||
<target>Код доставки</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="8a6d12c2cbdd17f109a1685372a54fee">
|
||||
<source>Code Product/Service для использования в fiscalization for shipping amount</source>
|
||||
<target>Код товара/услуги для использования в фискализации для суммы доставки</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="dbecc121e4f3f58940d7be4a57444526">
|
||||
<source>Show Visa/MasterCard logo</source>
|
||||
<target>Показать логотип Visa/MasterCard</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="c9cc8cce247e49bae79f15173ce97354">
|
||||
<source>Save</source>
|
||||
<target>Сохранить</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="2e70d995f0032b8859dd5ef37162087f">
|
||||
<source>Информационный идентификатор не требуется.</source>
|
||||
<target>Требуется идентификатор продавца (Merchant ID).</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="66a500cd593b25ebc543c002b345b579">
|
||||
<source>Merchant ID должен быть нумерен.</source>
|
||||
<target>Идентификатор продавца должен быть числовым.</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="1c2eee355024adcde515449347201000">
|
||||
<source>Неверный key не требуется.</source>
|
||||
<target>Требуется секретный ключ.</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="40bf93e3dcf907a8aad77d1b0f2a2921">
|
||||
<source>Секрет key должен быть в пределах 10 characters long and cannot be entirely numeric.</source>
|
||||
<target>Секретный ключ должен содержать не менее 10 символов и не может быть полностью числовым.</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="23638e456c7b83bd1953dbc0996620be">
|
||||
<source>Pay via payment system Hutko</source>
|
||||
<target>Оплата через платежную систему Hutko</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="223e639daf07b520427aa6c80e36fffb">
|
||||
<source>Pay via Hutko</source>
|
||||
<target>Оплата через Hutko</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="feed0d2100a232322a28616d350029e6">
|
||||
<source>Order payment #</source>
|
||||
<target>Оплата заказа #</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="789b043f02dbe86d80a6916a31553d0b">
|
||||
<source>Order payment not found.</source>
|
||||
<target>Оплата заказа не найдена.</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="5b475e4412cc0a11f089e0c6279220fb">
|
||||
<source>Invalid transaction ID format.</source>
|
||||
<target>Недействительный формат идентификатора транзакции.</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="272d77ac6ed0ef79325c3dae71b2a780">
|
||||
<source>Refund success.</source>
|
||||
<target>Восстановление средств успешно.</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="9f5daba4b8de3a0f6cdfab206a08f211">
|
||||
<source><![CDATA[Hutko Payments & Refunds]]></source>
|
||||
<target>Платежи и возврат средств Hutko</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="88427ec035734b45aae9f7d8859a5008">
|
||||
<source>Transaction ID</source>
|
||||
<target>Transaction ID</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="b2f40690858b404ed10e62bdf422c704">
|
||||
<source>Amount</source>
|
||||
<target>Сумма</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="31738cd694667ccdfa2cbc65249de5cc">
|
||||
<source>Payment Date</source>
|
||||
<target>Дата платежа</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="06df33001c1d7187fdd81ea1f5b277aa">
|
||||
<source>Actions</source>
|
||||
<target>Действия</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="76f0ed934de85cc7131910b32ede7714">
|
||||
<source>Refund</source>
|
||||
<target>Возврат средств</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="ec53a8c4f07baed5d8825072c89799be">
|
||||
<source>Status</source>
|
||||
<target>Статус</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="88b6563ca5cac4845361c28959c5612e">
|
||||
<source>Initiate Refund</source>
|
||||
<target>Инициировать возврат средств</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="b782d4ff61550d7e8cdee4cf70a03788">
|
||||
<source>Refund Amount</source>
|
||||
<target>Сумма возмещения</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="7bdf5ab3a17ec2dce33865622b238bd1">
|
||||
<source>Воспользуйтесь темой для оплаты этого платежа.</source>
|
||||
<target>Введите сумму для возврата средств за этот платеж.</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="a48f878efa7beadc6bab76f96fce6b62">
|
||||
<source>Refund Reason/Comment</source>
|
||||
<target>Причина/комментарий возврата средств</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="a331a1c920188f766c73334a17774dec">
|
||||
<source>Optional: A brief reason for the refund.</source>
|
||||
<target>Необязательно: краткая причина возврата средств.</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="ea4788705e6873b424c65e91c2846b19">
|
||||
<source>Cancel</source>
|
||||
<target>Отменить</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="968d5d0a76be35f96b91b808a39744cd">
|
||||
<source>Process Refund</source>
|
||||
<target>Выполнить возврат средств</target>
|
||||
<note>Line:</note>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
||||
22
translations/uk-UA/ModulesHutkoShop.uk-UA.xlf
Normal file
22
translations/uk-UA/ModulesHutkoShop.uk-UA.xlf
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
|
||||
<file original="admin105hcnvdgjnh2pvlogh" source-language="uk-UA" target-language="uk-UA" datatype="plaintext">
|
||||
<body>
|
||||
<trans-unit id="22af22c7d772e149e295809344fe5522">
|
||||
<source>Payment failure. </source>
|
||||
<target>Збій оплати.</target>
|
||||
<note>Line: </note>
|
||||
</trans-unit>
|
||||
<trans-unit id="82e50c727674f251464fc7520f5bde26">
|
||||
<source>Please try again</source>
|
||||
<target>Будь ласка, спробуйте ще раз</target>
|
||||
<note>Line: </note>
|
||||
</trans-unit>
|
||||
<trans-unit id="4be36be30fde5361b25b121a6c9e631e">
|
||||
<source>Order validation failure</source>
|
||||
<target>Помилка перевірки замовлення</target>
|
||||
<note>Line: </note>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
<div class="panel">
|
||||
<div class="panel-heading">
|
||||
<i class="icon-dollar"></i> {l s='Hutko Payments & Refunds' mod='hutko'}
|
||||
<i class="icon-dollar"></i> {l s='Hutko Payments & Refunds' d='Modules.Hutko.Admin'}
|
||||
</div>
|
||||
|
||||
<div class="panel-body">
|
||||
@@ -20,39 +20,37 @@
|
||||
<table class="table" id="hutko_payments_table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{l s='Transaction ID' mod='hutko'}</th>
|
||||
<th>{l s='Amount' mod='hutko'}</th>
|
||||
<th>{l s='Payment Date' mod='hutko'}</th>
|
||||
<th>{l s='Actions' mod='hutko'}</th>
|
||||
<th>{l s='Transaction ID' d='Modules.Hutko.Admin'}</th>
|
||||
<th>{l s='Amount' d='Modules.Hutko.Admin'}</th>
|
||||
<th>{l s='Payment Date' d='Modules.Hutko.Admin'}</th>
|
||||
<th>{l s='Actions' d='Modules.Hutko.Admin'}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{foreach from=$hutkoPayments item='payment'}
|
||||
<form method="post" id="hutkoStatusForm-{$payment->id|intval}"></form>
|
||||
<tr data-payment-id="{$payment->id|intval}" data-payment-amount="{$payment->amount|floatval}">
|
||||
<td>{$payment->transaction_id|escape:'htmlall':'UTF-8'}</td>
|
||||
<td>{displayPrice price=Tools::ps_round($payment->amount, 2) currency=$currency->id|floatval}
|
||||
<form method="post" id="hutkoStatusForm-{$payment->id}"></form>
|
||||
<tr data-payment-id="{$payment->id}" data-payment-amount="{$payment->amount}">
|
||||
<td>{$payment->transaction_id}</td>
|
||||
<td>{displayPrice price=Tools::ps_round($payment->amount, 2) currency=$currency->id}
|
||||
</td>
|
||||
<td>{$payment->date_add|date_format:'%Y-%m-%d %H:%M:%S'}</td>
|
||||
<td>
|
||||
{if $payment->amount > 0}
|
||||
<button type="button" class="btn btn-default btn-sm hutko-refund-btn"
|
||||
data-toggle="modal" data-target="#hutkoRefundModal-{$payment->id|intval}"
|
||||
data-payment-id="{$payment->id|intval}"
|
||||
data-payment-amount="{$payment->amount|floatval}">
|
||||
<i class="icon-undo"></i> {l s='Refund' mod='hutko'}
|
||||
data-toggle="modal" data-target="#hutkoRefundModal-{$payment->id}"
|
||||
data-payment-id="{$payment->id}" data-payment-amount="{$payment->amount}">
|
||||
<i class="icon-undo"></i> {l s='Refund' d='Modules.Hutko.Admin'}
|
||||
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
<button type="submit" form="hutkoStatusForm-{$payment->id|intval}"
|
||||
class="btn btn-default btn-sm hutko-status-btn" name="hutkoOrderStatus"
|
||||
value="{$payment->transaction_id|escape:'htmlall':'UTF-8'}">
|
||||
<i class="icon-info"></i> {l s='Status' mod='hutko'}
|
||||
<button type="submit" form="hutkoStatusForm-{$payment->id}"
|
||||
class="btn btn-default btn-sm hutko-status-btn" name="hutkoOrderPaymentStatus"
|
||||
value="{$payment->transaction_id}">
|
||||
<i class="icon-info"></i> {l s='Status' d='Modules.Hutko.Admin'}
|
||||
</button>
|
||||
<div class="modal fade" id="hutkoRefundModal-{$payment->id|intval}" tabindex="-1"
|
||||
role="dialog" aria-labelledby="hutkoRefundModalLabel-{$payment->id|intval}"
|
||||
aria-hidden="true">
|
||||
<div class="modal fade" id="hutkoRefundModal-{$payment->id}" tabindex="-1" role="dialog"
|
||||
aria-labelledby="hutkoRefundModalLabel-{$payment->id}" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
@@ -60,49 +58,46 @@
|
||||
aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
<h4 class="modal-title"
|
||||
id="hutkoRefundModalLabel-{$payment->id|intval}">
|
||||
{l s='Initiate Refund' mod='hutko'}</h4>
|
||||
<h4 class="modal-title" id="hutkoRefundModalLabel-{$payment->id}">
|
||||
{l s='Initiate Refund' d='Modules.Hutko.Admin'}</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="hutkoRefundForm-{$payment->id|intval}" method="post">
|
||||
<form id="hutkoRefundForm-{$payment->id}" method="post">
|
||||
<input type="hidden" name="id_order" value="{$id_order}">
|
||||
<input type="hidden" name="action" value="process_refund">
|
||||
<input type="hidden" name="orderPaymentId" value="{$payment->id}">
|
||||
|
||||
<div class="form-group">
|
||||
<label
|
||||
for="refund_amount">{l s='Refund Amount' mod='hutko'}</label>
|
||||
for="refund_amount">{l s='Refund Amount' d='Modules.Hutko.Admin'}</label>
|
||||
<div class="input-group">
|
||||
<span
|
||||
class="input-group-addon">{$currency->sign|escape:'htmlall':'UTF-8'}</span>
|
||||
<input type="number" value="{$payment->amount|floatval}"
|
||||
step="0.01" min="0.01" max="{$payment->amount|floatval}"
|
||||
class="form-control" id="refund_amount"
|
||||
name="refund_amount" required>
|
||||
<span class="input-group-addon">{$currency->sign}</span>
|
||||
<input type="number" value="{$payment->amount}" step="0.01"
|
||||
min="0.01" max="{$payment->amount}" class="form-control"
|
||||
id="refund_amount" name="refund_amount" required>
|
||||
<span class="input-group-addon"
|
||||
id="max_refund_amount_display"></span>
|
||||
</div>
|
||||
<small
|
||||
class="form-text text-muted">{l s='Enter the amount to refund for this payment.' mod='hutko'}</small>
|
||||
class="form-text text-muted">{l s='Enter the amount to refund for this payment.' d='Modules.Hutko.Admin'}</small>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label
|
||||
for="refund_comment">{l s='Refund Reason/Comment' mod='hutko'}</label>
|
||||
for="refund_comment">{l s='Refund Reason/Comment' d='Modules.Hutko.Admin'}</label>
|
||||
<textarea class="form-control" id="refund_comment"
|
||||
maxlength="1024" name="comment" rows="3"></textarea>
|
||||
<small
|
||||
class="form-text text-muted">{l s='Optional: A brief reason for the refund.' mod='hutko'}</small>
|
||||
class="form-text text-muted">{l s='Optional: A brief reason for the refund.' d='Modules.Hutko.Admin'}</small>
|
||||
</div>
|
||||
</form>
|
||||
<div id="hutko_refund_message" class="alert hidden" role="alert"></div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default"
|
||||
data-dismiss="modal">{l s='Cancel' mod='hutko'}</button>
|
||||
data-dismiss="modal">{l s='Cancel' d='Modules.Hutko.Admin'}</button>
|
||||
<button class="btn btn-primary" name="hutkoRefundsubmit"
|
||||
form="hutkoRefundForm-{$payment->id|intval}"
|
||||
type="submit">{l s='Process Refund' mod='hutko'}</button>
|
||||
form="hutkoRefundForm-{$payment->id}"
|
||||
type="submit">{l s='Process Refund' d='Modules.Hutko.Admin'}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -11,19 +11,16 @@
|
||||
{extends "$layout"}
|
||||
|
||||
{block name="content"}
|
||||
{if isset($hutko_response)}
|
||||
|
||||
{l s='You will be redirected to the website in a few seconds.' d='Modules.Hutko.Shop'}
|
||||
<div class="form-group">
|
||||
<form id="hutko_redirect" method="POST" action="{$hutko_url}" accept-charset="utf-8">
|
||||
<h5>{l s='Payment failure. ' d='Modules.Hutko.Shop'}</h5>
|
||||
<a class="btn btn-primary"
|
||||
href="{$link->getPageLink('order-history')}">{l s='Please try again' d='Modules.Hutko.Shop'}</a>
|
||||
|
||||
|
||||
{else}
|
||||
<h5>{l s='Order validation failure' d='Modules.Hutko.Shop'}</h5>
|
||||
<a class="btn btn-primary" href="{$link->getPageLink('order')}">{l s='Please try again' d='Modules.Hutko.Shop'}</a>
|
||||
{/if}
|
||||
|
||||
{foreach from=$hutko_inputs item=item key=key name=name}
|
||||
<input type="hidden" name="{$key|escape:'htmlall'}" value="{$item|escape:'htmlall'}" />
|
||||
{/foreach}
|
||||
<button class="btn btn-primary"
|
||||
type="submit">{l s='Go to payment (if auto redirect doesn`t work)' d='Modules.Hutko.Shop'}</button>
|
||||
</form>
|
||||
<div>
|
||||
<script>
|
||||
document.getElementById("hutko_redirect").submit();
|
||||
</script>
|
||||
{/block}
|
||||
Reference in New Issue
Block a user