fixed cart clearance

This commit is contained in:
O K
2025-12-14 16:24:20 +02:00
parent b7425d3d6c
commit f90c8d5f81
2 changed files with 166 additions and 88 deletions

View File

@@ -1,12 +1,15 @@
<?php
namespace Opencart\Admin\Controller\Extension\Hutko\Payment;
class Hutko extends \Opencart\System\Engine\Controller {
class Hutko extends \Opencart\System\Engine\Controller
{
private $checkout_url = 'https://pay.hutko.org/api/checkout/url/';
private $refund_url = 'https://pay.hutko.org/api/reverse/order_id';
private $status_url = 'https://pay.hutko.org/api/status/order_id';
public function index(): void {
public function index(): void
{
$this->load->language('extension/hutko/payment/hutko');
$this->document->setTitle($this->language->get('heading_title'));
@@ -29,11 +32,22 @@ class Hutko extends \Opencart\System\Engine\Controller {
// Config fields
$fields = [
'payment_hutko_merchant_id', 'payment_hutko_secret_key', 'payment_hutko_shipping_include',
'payment_hutko_shipping_product_name', 'payment_hutko_shipping_product_code',
'payment_hutko_new_order_status_id', 'payment_hutko_success_status_id', 'payment_hutko_declined_status_id',
'payment_hutko_expired_status_id', 'payment_hutko_refunded_status_id', 'payment_hutko_include_discount_to_total',
'payment_hutko_status', 'payment_hutko_sort_order', 'payment_hutko_geo_zone_id', 'payment_hutko_total', 'payment_hutko_save_logs'
'payment_hutko_merchant_id',
'payment_hutko_secret_key',
'payment_hutko_shipping_include',
'payment_hutko_shipping_product_name',
'payment_hutko_shipping_product_code',
'payment_hutko_new_order_status_id',
'payment_hutko_success_status_id',
'payment_hutko_declined_status_id',
'payment_hutko_expired_status_id',
'payment_hutko_refunded_status_id',
'payment_hutko_include_discount_to_total',
'payment_hutko_status',
'payment_hutko_sort_order',
'payment_hutko_geo_zone_id',
'payment_hutko_total',
'payment_hutko_save_logs'
];
foreach ($fields as $field) {
@@ -62,7 +76,8 @@ class Hutko extends \Opencart\System\Engine\Controller {
$this->response->setOutput($this->load->view('extension/hutko/payment/hutko', $data));
}
public function save(): void {
public function save(): void
{
$this->load->language('extension/hutko/payment/hutko');
$json = [];
@@ -89,13 +104,15 @@ class Hutko extends \Opencart\System\Engine\Controller {
$this->response->setOutput(json_encode($json));
}
public function install(): void {
public function install(): void
{
$this->load->model('extension/hutko/payment/hutko');
$this->model_extension_hutko_payment_hutko->install();
// No event registration needed - we use the native 'order()' method now
}
public function uninstall(): void {
public function uninstall(): void
{
$this->load->model('setting/event');
$this->model_setting_event->deleteEventByCode('hutko_order_info'); // Cleanup old events if any
}
@@ -105,7 +122,8 @@ class Hutko extends \Opencart\System\Engine\Controller {
* OC4 calls this method automatically if the payment method is 'hutko'.
* It renders the content into a Tab in the Order Info page.
*/
public function order(): string {
public function order(): string
{
$this->load->language('extension/hutko/payment/hutko');
// In OC4, load->controller calls for order info don't always pass arguments,
@@ -119,12 +137,21 @@ class Hutko extends \Opencart\System\Engine\Controller {
$data['transactions'] = [];
foreach ($transactions as $t) {
$payload_arr = json_decode($t['payload'], true);
if (isset($payload_arr['request_data']['reservation_data'])) {
if (isset($payload_arr['request_data']['reservation_data'])) {
$inner = json_decode(base64_decode($payload_arr['request_data']['reservation_data']), true);
if ($inner) $payload_arr['request_data']['reservation_data'] = $inner;
}
// FIX: Pretty print with unescaped characters for better readability
if (isset($payload_arr['additional_info'])) {
$inner = json_decode($payload_arr['additional_info'], true);
if ($inner) $payload_arr['additional_info'] = $inner;
if (isset($payload_arr['additional_info']['reservation_data'])) {
$inner = json_decode($payload_arr['additional_info']['reservation_data'], true);
if ($inner) $payload_arr['additional_info']['reservation_data'] = $inner;
}
}
if (isset($payload_arr['response_signature_string'])) {
unset($payload_arr['response_signature_string']);
}
$pretty_payload = $payload_arr ? json_encode($payload_arr, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) : $t['payload'];
$data['transactions'][] = [
'date' => date($this->language->get('datetime_format'), strtotime($t['date_added'])),
@@ -133,7 +160,7 @@ class Hutko extends \Opencart\System\Engine\Controller {
'status' => $t['status'],
'amount' => $t['amount'] . ' ' . $t['currency'],
'payload' => $pretty_payload,
'can_refund'=> ($t['type'] == 'callback' && $t['status'] == 'success')
'can_refund' => ($t['type'] == 'callback' && $t['status'] == 'success')
];
}
@@ -160,7 +187,8 @@ class Hutko extends \Opencart\System\Engine\Controller {
return $this->load->view('extension/hutko/payment/hutko_order_info_panel', $data);
}
public function create_payment_link(): void {
public function create_payment_link(): void
{
$this->load->language('extension/hutko/payment/hutko');
$this->load->model('extension/hutko/payment/hutko');
$this->load->model('sale/order');
@@ -228,7 +256,8 @@ public function create_payment_link(): void {
$this->response->setOutput(json_encode($json));
}
public function refund(): void {
public function refund(): void
{
$this->load->language('extension/hutko/payment/hutko');
$this->load->model('extension/hutko/payment/hutko');
$this->load->model('sale/order');
@@ -242,7 +271,7 @@ public function create_payment_link(): void {
if (empty($hutko_ref)) {
// Find the successful payment if ref not provided
$transactions = $this->model_extension_hutko_payment_hutko->getTransactions($order_id);
foreach($transactions as $t) {
foreach ($transactions as $t) {
if ($t['type'] == 'callback' && $t['status'] == 'success') {
$hutko_ref = $t['hutko_ref'];
break;
@@ -277,9 +306,10 @@ public function create_payment_link(): void {
if (($response['response']['reverse_status'] ?? '') === 'approved') {
$json['success'] = $this->language->get('text_refund_success');
$rev_amt = isset($response['response']['reversal_amount']) ? $response['response']['reversal_amount']/100 : $amount;
$rev_amt = isset($response['response']['reversal_amount']) ? $response['response']['reversal_amount'] / 100 : $amount;
$msg = sprintf($this->language->get('text_refund_success_comment'),
$msg = sprintf(
$this->language->get('text_refund_success_comment'),
$hutko_ref,
$this->currency->format($rev_amt, $order_info['currency_code'], $order_info['currency_value']),
$comment
@@ -298,7 +328,8 @@ public function create_payment_link(): void {
$this->response->setOutput(json_encode($json));
}
public function status(): void {
public function status(): void
{
$this->load->language('extension/hutko/payment/hutko');
$json = [];
$ref = $this->request->post['hutko_transaction_ref'] ?? '';
@@ -326,7 +357,8 @@ public function create_payment_link(): void {
$this->response->setOutput(json_encode($json));
}
private function displayLastDayLog() {
private function displayLastDayLog()
{
if (!$this->config->get('payment_hutko_save_logs')) return $this->language->get('text_logs_disabled');
$file = DIR_LOGS . 'error.log';
if (!file_exists($file)) return sprintf($this->language->get('text_log_file_not_found'), 'error.log');
@@ -344,7 +376,8 @@ public function create_payment_link(): void {
// sign, api, logOC) must remain identical in Admin and Catalog controllers.
// =========================================================================
private function buildRequest($order, $hutko_ref) {
private function buildRequest($order, $hutko_ref)
{
$products_data = $this->getProducts($order['order_id'], $order);
$total_products_sum = 0;
@@ -408,7 +441,8 @@ public function create_payment_link(): void {
return $data;
}
private function getProducts(int $order_id, array $order_info): array {
private function getProducts(int $order_id, array $order_info): array
{
$products_data = [];
$query = $this->db->query("SELECT * FROM `" . DB_PREFIX . "order_product` WHERE `order_id` = '" . (int)$order_id . "'");
@@ -443,16 +477,20 @@ public function create_payment_link(): void {
return $products_data;
}
private function sign($data) {
private function sign($data)
{
$key = $this->config->get('payment_hutko_secret_key');
$arr = array_filter($data, function($v){ return $v !== '' && $v !== null; });
$arr = array_filter($data, function ($v) {
return $v !== '' && $v !== null;
});
ksort($arr);
$str = $key;
foreach($arr as $v) $str .= '|' . $v;
foreach ($arr as $v) $str .= '|' . $v;
return sha1($str);
}
private function api($url, $data) {
private function api($url, $data)
{
if ($this->config->get('payment_hutko_save_logs')) $this->logOC('Req: ' . json_encode($data));
$ch = curl_init($url);
@@ -475,7 +513,8 @@ public function create_payment_link(): void {
return json_decode($res, true) ?: [];
}
private function logOC($msg) {
private function logOC($msg)
{
$this->log->write("Hutko Payment: " . $msg);
}
// =========================================================================

View File

@@ -1,15 +1,19 @@
<?php
namespace Opencart\Catalog\Controller\Extension\Hutko\Payment;
class Hutko extends \Opencart\System\Engine\Controller {
class Hutko extends \Opencart\System\Engine\Controller
{
private $checkout_url = 'https://pay.hutko.org/api/checkout/url/';
public function index(): string {
public function index(): string
{
$this->load->language('extension/hutko/payment/hutko');
return $this->load->view('extension/hutko/payment/hutko', ['language' => $this->config->get('config_language')]);
}
public function confirm(): void {
public function confirm(): void
{
$this->load->language('extension/hutko/payment/hutko');
$this->load->model('checkout/order');
@@ -61,11 +65,24 @@ public function confirm(): void {
$this->model_checkout_order->addHistory($order_info['order_id'], $new_status_id, $this->language->get('text_initiated_payment'), false);
}
// Clear Cart and Session Data BEFORE redirecting to Gateway
// This ensures the cart is empty regardless of the return path/device.
$this->cart->clear();
unset($this->session->data['shipping_method']);
unset($this->session->data['shipping_methods']);
unset($this->session->data['payment_method']);
unset($this->session->data['payment_methods']);
unset($this->session->data['guest']);
unset($this->session->data['comment']);
unset($this->session->data['coupon']);
unset($this->session->data['reward']);
unset($this->session->data['voucher']);
unset($this->session->data['vouchers']);
unset($this->session->data['totals']);
// NOTE: Do NOT unset 'order_id' here, as checkout/success needs it to show the "Order #123 placed" page.
$json['redirect'] = $url;
} else {
// ... error handling (same as before) ...
$err = $response['response']['error_message'] ?? $this->language->get('error_api_communication');
$err = $response['response']['error_message'] ?? $this->language->get('error_api_communication');
$json['error'] = $err;
$this->model_extension_hutko_payment_hutko->logTransaction(
$order_info['order_id'],
@@ -84,7 +101,8 @@ public function confirm(): void {
$this->response->addHeader('Content-Type: application/json');
$this->response->setOutput(json_encode($json));
}
public function callback(): void {
public function callback(): void
{
$this->load->language('extension/hutko/payment/hutko');
$input = file_get_contents("php://input");
@@ -165,7 +183,8 @@ public function confirm(): void {
private function validate($data) {
private function validate($data)
{
$sig = $data['signature'] ?? '';
unset($data['signature'], $data['response_signature_string']);
return hash_equals($this->sign($data), $sig);
@@ -177,7 +196,8 @@ public function confirm(): void {
// MAINTENANCE WARNING: Keep synchronized with Admin Controller
// =========================================================================
private function buildRequest($order, $hutko_ref) {
private function buildRequest($order, $hutko_ref)
{
$products_data = $this->getProducts($order['order_id'], $order);
$total_products_sum = 0;
@@ -207,7 +227,8 @@ public function confirm(): void {
if ($amount_val < 0.01) $amount_val = 0.01;
$total_cents = (int)round($amount_val * 100);
// Catalog side URLs are simple
$response_url = $this->url->link('checkout/success', 'language=' . $this->config->get('config_language'), true);
$callback_url = $this->url->link('extension/hutko/payment/hutko.callback', '', true);
@@ -239,7 +260,20 @@ public function confirm(): void {
return $data;
}
private function getProducts(int $order_id, array $order_info): array {
public function response(): void
{
// Post-Redirect-Get pattern.
// Accepts the POST from Gateway, then redirects user via GET to restore Session/Cookies.
// This ensures the Cart is cleared and User is not logged out.
// If the gateway passes specific error flags in POST, you could check them here
// and redirect to checkout/failure instead. For now, we assume success flow.
$this->response->redirect($this->url->link('checkout/success', 'language=' . $this->config->get('config_language'), true));
}
private function getProducts(int $order_id, array $order_info): array
{
$products_data = [];
$query = $this->db->query("SELECT * FROM `" . DB_PREFIX . "order_product` WHERE `order_id` = '" . (int)$order_id . "'");
@@ -274,16 +308,20 @@ public function confirm(): void {
return $products_data;
}
private function sign($data) {
private function sign($data)
{
$key = $this->config->get('payment_hutko_secret_key');
$arr = array_filter($data, function($v){ return $v !== '' && $v !== null; });
$arr = array_filter($data, function ($v) {
return $v !== '' && $v !== null;
});
ksort($arr);
$str = $key;
foreach($arr as $v) $str .= '|' . $v;
foreach ($arr as $v) $str .= '|' . $v;
return sha1($str);
}
private function api($url, $data) {
private function api($url, $data)
{
if ($this->config->get('payment_hutko_save_logs')) $this->logOC('Req: ' . json_encode($data));
$ch = curl_init($url);
@@ -306,7 +344,8 @@ public function confirm(): void {
return json_decode($res, true) ?: [];
}
private function logOC($msg) {
private function logOC($msg)
{
$this->log->write("Hutko Payment: " . $msg);
}
// =========================================================================