added refunds
This commit is contained in:
362
hutko.php
362
hutko.php
@@ -10,6 +10,7 @@
|
|||||||
* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
|
* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
use PrestaShop\PrestaShop\Core\Payment\PaymentOption;
|
use PrestaShop\PrestaShop\Core\Payment\PaymentOption;
|
||||||
|
|
||||||
if (!defined('_PS_VERSION_')) {
|
if (!defined('_PS_VERSION_')) {
|
||||||
@@ -22,6 +23,9 @@ class Hutko extends PaymentModule
|
|||||||
public $order_separator = '#';
|
public $order_separator = '#';
|
||||||
|
|
||||||
public $checkout_url = 'https://pay.hutko.org/api/checkout/redirect/';
|
public $checkout_url = 'https://pay.hutko.org/api/checkout/redirect/';
|
||||||
|
public $refund_url = 'https://pay.hutko.org/api/reverse/order_id';
|
||||||
|
public $status_url = 'https://pay.hutko.org/api/status/order_id';
|
||||||
|
|
||||||
|
|
||||||
private $settingsList = [
|
private $settingsList = [
|
||||||
'HUTKO_MERCHANT',
|
'HUTKO_MERCHANT',
|
||||||
@@ -39,19 +43,19 @@ class Hutko extends PaymentModule
|
|||||||
$this->version = '1.1.0';
|
$this->version = '1.1.0';
|
||||||
$this->author = 'Hutko';
|
$this->author = 'Hutko';
|
||||||
$this->bootstrap = true;
|
$this->bootstrap = true;
|
||||||
$this->ps_versions_compliancy = array('min' => '1.7', 'max' => _PS_VERSION_);
|
|
||||||
$this->is_eu_compatible = 1;
|
|
||||||
|
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
$this->displayName = $this->trans('Hutko Payments', array(), 'Modules.Hutko.Admin');
|
$this->ps_versions_compliancy = array('min' => '1.7', 'max' => _PS_VERSION_);
|
||||||
$this->description = $this->trans('Hutko is a payment platform whose main function is to provide internet acquiring.
|
//Do not translate displayName as it is used for payment identification
|
||||||
Payment gateway supports EUR, USD, PLN, GBP, UAH, RUB and +100 other currencies.', array(), 'Modules.Hutko.Admin');
|
$this->displayName = 'Hutko Payments';
|
||||||
|
$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()
|
||||||
{
|
{
|
||||||
return parent::install()
|
return parent::install()
|
||||||
&& $this->registerHook('paymentOptions');
|
&& $this->registerHook('paymentOptions')
|
||||||
|
&& $this->registerHook('displayAdminOrderContentOrder')
|
||||||
|
&& $this->registerHook('actionAdminControllerSetMedia');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function uninstall()
|
public function uninstall()
|
||||||
@@ -213,6 +217,7 @@ class Hutko extends PaymentModule
|
|||||||
*/
|
*/
|
||||||
protected function postProcess()
|
protected function postProcess()
|
||||||
{
|
{
|
||||||
|
|
||||||
$form_values = $this->getConfigFormValues();
|
$form_values = $this->getConfigFormValues();
|
||||||
foreach (array_keys($form_values) as $key) {
|
foreach (array_keys($form_values) as $key) {
|
||||||
Configuration::updateValue($key, Tools::getValue($key));
|
Configuration::updateValue($key, Tools::getValue($key));
|
||||||
@@ -329,7 +334,7 @@ class Hutko extends PaymentModule
|
|||||||
// 3. Create a description for the order.
|
// 3. Create a description for the order.
|
||||||
$orderDescription = $this->trans('Cart pay №', [], 'Modules.Hutko.Admin') . $this->context->cart->id;
|
$orderDescription = $this->trans('Cart pay №', [], 'Modules.Hutko.Admin') . $this->context->cart->id;
|
||||||
// 4. Calculate the order amount in the smallest currency unit.
|
// 4. Calculate the order amount in the smallest currency unit.
|
||||||
$amount = round($this->context->cart->getOrderTotal() * 100);
|
$amount = round($this->context->cart->getOrderTotal(true, CART::ONLY_PRODUCTS) * 100);
|
||||||
|
|
||||||
// 5. Get the currency ISO code of the current cart.
|
// 5. Get the currency ISO code of the current cart.
|
||||||
$currency = $this->context->currency->iso_code;
|
$currency = $this->context->currency->iso_code;
|
||||||
@@ -360,7 +365,7 @@ class Hutko extends PaymentModule
|
|||||||
];
|
];
|
||||||
|
|
||||||
// 11. Generate the signature for the data array using the merchant's secret key.
|
// 11. Generate the signature for the data array using the merchant's secret key.
|
||||||
$data['signature'] = $this->getSignature($data, Configuration::get('HUTKO_SECRET_KEY'));
|
$data['signature'] = $this->getSignature($data);
|
||||||
|
|
||||||
// 12. Return the complete data array including the signature.
|
// 12. Return the complete data array including the signature.
|
||||||
return $data;
|
return $data;
|
||||||
@@ -397,7 +402,7 @@ class Hutko extends PaymentModule
|
|||||||
"cms_version" => _PS_VERSION_,
|
"cms_version" => _PS_VERSION_,
|
||||||
"shop_domain" => Tools::getShopDomainSsl(),
|
"shop_domain" => Tools::getShopDomainSsl(),
|
||||||
"path" => 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'],
|
"path" => 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'],
|
||||||
"phonemobile" => $address->phone_mobile ?? $address->phone,
|
"phonemobile" => empty($address->phone_mobile) ? $address->phone : $address->phone_mobile,
|
||||||
"customer_address" => $this->getSlug($address->address1),
|
"customer_address" => $this->getSlug($address->address1),
|
||||||
"customer_country" => $this->getSlug($address->country),
|
"customer_country" => $this->getSlug($address->country),
|
||||||
"customer_state" => $this->getSlug($customerState),
|
"customer_state" => $this->getSlug($customerState),
|
||||||
@@ -561,8 +566,12 @@ class Hutko extends PaymentModule
|
|||||||
* or the raw string before encoding (false).
|
* or the raw string before encoding (false).
|
||||||
* @return string The generated signature (SHA1 hash by default) or the raw string.
|
* @return string The generated signature (SHA1 hash by default) or the raw string.
|
||||||
*/
|
*/
|
||||||
public function getSignature(array $data, string $password, bool $encoded = true): string
|
public function getSignature(array $data, bool $encoded = true): string
|
||||||
{
|
{
|
||||||
|
$password = Configuration::get('HUTKO_SECRET_KEY');
|
||||||
|
if (!$password || empty($password)) {
|
||||||
|
throw new PrestaShopException('Merchant secret not set');
|
||||||
|
}
|
||||||
// 1. Filter out empty and null values from the data array.
|
// 1. Filter out empty and null values from the data array.
|
||||||
$filteredData = array_filter($data, function ($value) {
|
$filteredData = array_filter($data, function ($value) {
|
||||||
return $value !== '' && $value !== null;
|
return $value !== '' && $value !== null;
|
||||||
@@ -617,7 +626,7 @@ class Hutko extends PaymentModule
|
|||||||
unset($response['response_signature_string'], $response['signature']);
|
unset($response['response_signature_string'], $response['signature']);
|
||||||
|
|
||||||
// 3. Calculate and Compare Signatures
|
// 3. Calculate and Compare Signatures
|
||||||
$calculatedSignature = $this->getSignature($response, Configuration::get('HUTKO_SECRET_KEY'));
|
$calculatedSignature = $this->getSignature($response);
|
||||||
|
|
||||||
return hash_equals($calculatedSignature, $responseSignature);
|
return hash_equals($calculatedSignature, $responseSignature);
|
||||||
}
|
}
|
||||||
@@ -670,7 +679,7 @@ class Hutko extends PaymentModule
|
|||||||
* @param string $message A message to log with the status change.
|
* @param string $message A message to log with the status change.
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function updateOrderStatus(int $orderId, int $newStateId, string $message = ''): void
|
public function updateOrderStatus(int $orderId, int $newStateId): void
|
||||||
{
|
{
|
||||||
$order = new Order($orderId);
|
$order = new Order($orderId);
|
||||||
// Only update if the order is loaded and the current state is different from the new state.
|
// Only update if the order is loaded and the current state is different from the new state.
|
||||||
@@ -678,11 +687,328 @@ class Hutko extends PaymentModule
|
|||||||
$history = new OrderHistory();
|
$history = new OrderHistory();
|
||||||
$history->id_order = $orderId;
|
$history->id_order = $orderId;
|
||||||
$history->changeIdOrderState($newStateId, $orderId);
|
$history->changeIdOrderState($newStateId, $orderId);
|
||||||
$history->addWithemail(true, ['order_name' => $orderId]);
|
$history->addWithemail();
|
||||||
// PrestaShopLogger::addLog('Hutko Callback: Order ' . $orderId . ' status changed to ' . $newStateId . '. Message: ' . $message, 1, null, 'Order', $orderId, true);
|
|
||||||
} else {
|
|
||||||
// Log if the order was not loaded or already in the target state.
|
|
||||||
// PrestaShopLogger::addLog('Hutko Callback: Attempted to update order ' . $orderId . ' to state ' . $newStateId . ' but order not loaded or already in target state. Message: ' . $message, 2, null, 'Order', $orderId, true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook to display content in the admin order page tabs.
|
||||||
|
* This will add a new tab for "Hutko Payments" or similar.
|
||||||
|
*
|
||||||
|
* @param array $params Contains Order 'order'
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function hookdisplayAdminOrderContentOrder(array $params): string
|
||||||
|
{
|
||||||
|
if (Tools::isSubmit('hutkoRefundsubmit')) {
|
||||||
|
$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.
|
||||||
|
|
||||||
|
$order = $params['order'];
|
||||||
|
|
||||||
|
|
||||||
|
// Fetch payments made via Hutko for this order
|
||||||
|
$hutkoPayments = new PrestaShopCollection('OrderPayment');
|
||||||
|
$hutkoPayments->where('order_reference', '=', $order->reference);
|
||||||
|
$hutkoPayments->where('payment_method', '=', $this->displayName);
|
||||||
|
|
||||||
|
$this->context->smarty->assign([
|
||||||
|
'hutkoPayments' => $hutkoPayments->getAll(),
|
||||||
|
'id_order' => $order->id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $this->display(__FILE__, 'views/templates/admin/order_payment_refund.tpl');
|
||||||
|
}
|
||||||
|
public function processOrderStatus(string $order_id): void
|
||||||
|
{
|
||||||
|
$data = [
|
||||||
|
'order_id' => $order_id,
|
||||||
|
'merchant_id' => Configuration::get('HUTKO_MERCHANT', null),
|
||||||
|
'version' => '1.0',
|
||||||
|
];
|
||||||
|
$data['signature'] = $this->getSignature($data);
|
||||||
|
|
||||||
|
$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);
|
||||||
|
if ($result->error) {
|
||||||
|
$this->context->controller->errors[] = $result->description;
|
||||||
|
}
|
||||||
|
if ($result->success) {
|
||||||
|
$this->context->controller->informations[] = $result->description;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes a payment refund via the Hutko gateway and updates PrestaShop order.
|
||||||
|
*
|
||||||
|
* This method initiates a refund request to the Hutko payment gateway for a specific
|
||||||
|
* order payment. Upon successful refund from Hutko, it creates an OrderSlip (if partial),
|
||||||
|
* updates the order history, and logs the action.
|
||||||
|
*
|
||||||
|
* @param int $orderPaymentId The ID of the OrderPayment record to refund.
|
||||||
|
* @param int $orderId The ID of the Order to refund.
|
||||||
|
* @param float $amount The amount to refund.
|
||||||
|
* @param string $comment A comment or reason for the refund.
|
||||||
|
* @return stdClass Result description.
|
||||||
|
* @throws Exception If the OrderPayment is not found, invalid, or refund fails.
|
||||||
|
*/
|
||||||
|
public function processRefund(int $orderPaymentId, int $orderId, float $amount, string $comment = ''): stdClass
|
||||||
|
{
|
||||||
|
$result = new stdClass();
|
||||||
|
$result->error = false;
|
||||||
|
// 1. Load the OrderPayment object.
|
||||||
|
$orderPayment = new OrderPayment($orderPaymentId);
|
||||||
|
$currency = new Currency($orderPayment->id_currency);
|
||||||
|
if (!Validate::isLoadedObject($orderPayment)) {
|
||||||
|
PrestaShopLogger::addLog(
|
||||||
|
'Hutko Refund: OrderPayment object not found for ID: ' . $orderPaymentId,
|
||||||
|
3, // Error
|
||||||
|
null,
|
||||||
|
'OrderPayment',
|
||||||
|
$orderPaymentId,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
throw new Exception($this->trans('Order payment not found.', [], 'Modules.Hutko.Admin'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Validate the transaction_id format and extract cart ID.
|
||||||
|
// Assuming transaction_id is in the format "cartID|timestamp" or "cartID-timestamp"
|
||||||
|
$transactionIdParts = explode($this->order_separator, $orderPayment->transaction_id);
|
||||||
|
$cartId = (int)$transactionIdParts[0];
|
||||||
|
|
||||||
|
if (!$cartId) {
|
||||||
|
PrestaShopLogger::addLog(
|
||||||
|
'Hutko Refund: Invalid transaction ID format for OrderPayment ID: ' . $orderPaymentId . ' Transaction ID: ' . $orderPayment->transaction_id,
|
||||||
|
3, // Error
|
||||||
|
null,
|
||||||
|
'OrderPayment',
|
||||||
|
$orderPaymentId,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
throw new Exception($this->trans('Invalid transaction ID format.', [], 'Modules.Hutko.Admin'));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$response = $this->refundAPICall($orderPayment->transaction_id, $amount, $currency->iso_code, $comment);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if ($response['response']['response_status'] === 'failure') {
|
||||||
|
$result->error = true;
|
||||||
|
$result->description = $response['response']['error_message'];
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
if ($response['response']['response_status'] === 'success') {
|
||||||
|
$result->success = true;
|
||||||
|
$result->description = $this->trans('Refund success.', [], 'Modules.Hutko.Admin');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$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
|
||||||
|
$this->displayName,
|
||||||
|
$orderPayment->transaction_id
|
||||||
|
);
|
||||||
|
|
||||||
|
PrestaShopLogger::addLog(
|
||||||
|
'Hutko Refund: Successfully processed refund for Order: ' . $orderId . ', Amount: ' . $amount . ', Comment: ' . $comment,
|
||||||
|
1, // Info
|
||||||
|
null,
|
||||||
|
'OrderPayment',
|
||||||
|
$orderPaymentId,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Initiates a refund (reverse) request via Hutko API.
|
||||||
|
*
|
||||||
|
* @param string $order_id The gateway's order ID to refund.
|
||||||
|
* @param float $amount The amount to refund (in base units, e.g., 100.50).
|
||||||
|
* @param string $currency The currency code (e.g., 'UAH').
|
||||||
|
* @param string $comment Optional comment for the refund.
|
||||||
|
* @return array Decoded API response array. Returns an error structure on failure.
|
||||||
|
*/
|
||||||
|
public function refundAPICall(string $order_id, float $amount, string $currency, string $comment = ''): array
|
||||||
|
{
|
||||||
|
// 1. Prepare the data payload
|
||||||
|
$data = [
|
||||||
|
'order_id' => $order_id,
|
||||||
|
// Assuming Configuration::get is available to fetch the merchant ID
|
||||||
|
'merchant_id' => Configuration::get('HUTKO_MERCHANT', null),
|
||||||
|
'version' => '1.0',
|
||||||
|
// Amount should be in minor units (cents, kopecks) and converted to string as per API example
|
||||||
|
'amount' => (string)round($amount * 100),
|
||||||
|
'currency' => $currency,
|
||||||
|
];
|
||||||
|
|
||||||
|
if (!empty($comment)) {
|
||||||
|
$data['comment'] = $comment;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Calculate the signature based on the data array *before* wrapping in 'request'
|
||||||
|
$data['signature'] = $this->getSignature($data);
|
||||||
|
return $this->sendAPICall($this->refund_url, $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initiates a request via Hutko API.
|
||||||
|
*
|
||||||
|
* @param string $url The gateway's url.
|
||||||
|
* @param array $data The data.
|
||||||
|
* @return array Decoded API response array. Returns an error structure on failure.
|
||||||
|
*/
|
||||||
|
public function sendAPICall(string $url, array $data, int $timeout = 60): array
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
// Wrap the prepared data inside the 'request' key as required by the API
|
||||||
|
$requestPayload = ['request' => $data];
|
||||||
|
|
||||||
|
// Convert the payload to JSON string
|
||||||
|
$jsonPayload = json_encode($requestPayload);
|
||||||
|
|
||||||
|
if ($jsonPayload === false) {
|
||||||
|
// Handle JSON encoding error
|
||||||
|
return [
|
||||||
|
'response' => [
|
||||||
|
'response_status' => 'failure',
|
||||||
|
'error_message' => 'Failed to encode request data to JSON: ' . json_last_error_msg(),
|
||||||
|
'error_code' => 'JSON_ENCODE_ERROR'
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize CURL
|
||||||
|
$ch = curl_init();
|
||||||
|
|
||||||
|
// 4. Set CURL options
|
||||||
|
curl_setopt($ch, CURLOPT_URL, $url);
|
||||||
|
curl_setopt($ch, CURLOPT_POST, true); // Use POST method
|
||||||
|
curl_setopt($ch, CURLOPT_POSTFIELDS, $jsonPayload); // Set the JSON body
|
||||||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // Return the response as a string
|
||||||
|
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
||||||
|
'Content-Type: application/json',
|
||||||
|
'Content-Length: ' . strlen($jsonPayload), // Good practice
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Recommended for production: Verify SSL certificate
|
||||||
|
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
|
||||||
|
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); // Verify hostname against certificate
|
||||||
|
|
||||||
|
|
||||||
|
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); // Timeout in seconds
|
||||||
|
|
||||||
|
// Execute the CURL request
|
||||||
|
$response = curl_exec($ch);
|
||||||
|
|
||||||
|
// Check for CURL errors
|
||||||
|
$curl_error = curl_error($ch);
|
||||||
|
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||||
|
|
||||||
|
if ($curl_error) {
|
||||||
|
// Log the error or handle it appropriately
|
||||||
|
curl_close($ch);
|
||||||
|
return [
|
||||||
|
'response' => [
|
||||||
|
'response_status' => 'failure',
|
||||||
|
'error_message' => 'CURL Error: ' . $curl_error,
|
||||||
|
'error_code' => 'CURL_' . curl_errno($ch),
|
||||||
|
'http_code' => $http_code // Include http code for context
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close CURL handle
|
||||||
|
curl_close($ch);
|
||||||
|
|
||||||
|
// Process the response
|
||||||
|
// Decode the JSON response into a PHP array
|
||||||
|
$responseData = json_decode($response, true);
|
||||||
|
|
||||||
|
// Check if JSON decoding failed
|
||||||
|
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||||
|
// Log the error or handle it appropriately
|
||||||
|
return [
|
||||||
|
'response' => [
|
||||||
|
'response_status' => 'failure',
|
||||||
|
'error_message' => 'Invalid JSON response from API: ' . json_last_error_msg(),
|
||||||
|
'error_code' => 'JSON_DECODE_ERROR',
|
||||||
|
'http_code' => $http_code,
|
||||||
|
'raw_response' => $response // Include raw response for debugging
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return $responseData;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays an array's contents in a PrestaShop notification box.
|
||||||
|
*
|
||||||
|
* This function is intended for debugging or displaying API responses/structured data
|
||||||
|
* in the PrestaShop back office notifications.
|
||||||
|
*
|
||||||
|
* @param array $data The array to display.
|
||||||
|
*/
|
||||||
|
protected function displayArrayInNotification(array $data): string
|
||||||
|
{
|
||||||
|
if (isset($data['response_signature_string'])) {
|
||||||
|
unset($data['response_signature_string']);
|
||||||
|
}
|
||||||
|
if (isset($data['additional_info'])) {
|
||||||
|
$data['additional_info_decoded'] = json_decode($data['additional_info'], true);
|
||||||
|
if (isset($data['additional_info_decoded']['reservation_data'])) {
|
||||||
|
$data['additional_info_decoded']['reservation_data_decoded'] = json_decode($data['additional_info_decoded']['reservation_data'], true);
|
||||||
|
unset($data['additional_info_decoded']['reservation_data']);
|
||||||
|
}
|
||||||
|
unset($data['additional_info']);
|
||||||
|
}
|
||||||
|
$retStr = '<ul>';
|
||||||
|
if (is_array($data)) {
|
||||||
|
foreach ($data as $key => $val) {
|
||||||
|
if (is_array($val)) {
|
||||||
|
$retStr .= '<li>' . $key . ' => ' . $this->displayArrayInNotification($val) . '</li>';
|
||||||
|
} else {
|
||||||
|
$retStr .= '<li>' . $key . ' => ' . $val . '</li>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$retStr .= '</ul>';
|
||||||
|
return $retStr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
logo.png
BIN
logo.png
Binary file not shown.
|
Before Width: | Height: | Size: 7.7 KiB After Width: | Height: | Size: 1.4 KiB |
123
views/templates/admin/order_payment_refund.tpl
Normal file
123
views/templates/admin/order_payment_refund.tpl
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
{*
|
||||||
|
* Hutko PrestaShop Module
|
||||||
|
*
|
||||||
|
* This template is used to display the Hutko payment refund tab content
|
||||||
|
* on the PrestaShop admin order details page.
|
||||||
|
* It lists all Hutko payments for the order and provides a refund button
|
||||||
|
* which opens a modal for amount and comment input.
|
||||||
|
*}
|
||||||
|
{if $hutkoPayments->count()}
|
||||||
|
|
||||||
|
|
||||||
|
<div class="panel">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<i class="icon-dollar"></i> {l s='Hutko Payments & Refunds' mod='hutko'}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="panel-body">
|
||||||
|
<div id="hutko_payments_list">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<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>
|
||||||
|
</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}
|
||||||
|
</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'}
|
||||||
|
|
||||||
|
</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>
|
||||||
|
<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-dialog" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal"
|
||||||
|
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>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<form id="hutkoRefundForm-{$payment->id|intval}" 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>
|
||||||
|
<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"
|
||||||
|
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>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label
|
||||||
|
for="refund_comment">{l s='Refund Reason/Comment' mod='hutko'}</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>
|
||||||
|
</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>
|
||||||
|
<button class="btn btn-primary" name="hutkoRefundsubmit"
|
||||||
|
form="hutkoRefundForm-{$payment->id|intval}"
|
||||||
|
type="submit">{l s='Process Refund' mod='hutko'}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{/foreach}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
Reference in New Issue
Block a user