Update catalog/controller/payment/hutko.php

This commit is contained in:
2025-12-14 11:46:46 +02:00
parent 71b0a98c3f
commit 2aac88f953

View File

@@ -10,7 +10,6 @@ class Hutko extends \Opencart\System\Engine\Controller {
} }
public function confirm(): void { public function confirm(): void {
// Load language here so 'text_redirecting_comment' is available
$this->load->language('extension/hutko/payment/hutko'); $this->load->language('extension/hutko/payment/hutko');
$this->load->model('checkout/order'); $this->load->model('checkout/order');
@@ -25,26 +24,59 @@ class Hutko extends \Opencart\System\Engine\Controller {
if (!$order_info) { if (!$order_info) {
$json['error'] = 'Order missing'; $json['error'] = 'Order missing';
} else { } else {
$request_data = $this->buildRequest($order_info); // 1. Generate unique Ref for THIS attempt
$timestamp = time();
$hutko_ref = $order_info['order_id'] . '#' . $timestamp;
$request_data = $this->buildRequest($order_info, $hutko_ref);
if (!$request_data) { if (!$request_data) {
$json['error'] = $this->language->get('error_payment_data_build'); $json['error'] = $this->language->get('error_payment_data_build');
} else { } else {
$this->load->model('extension/hutko/payment/hutko'); $this->load->model('extension/hutko/payment/hutko');
$this->model_extension_hutko_payment_hutko->addHutkoOrder($order_info['order_id'], $request_data['order_id']);
// 2. Call API
$response = $this->api($this->checkout_url, $request_data); $response = $this->api($this->checkout_url, $request_data);
if (($response['response']['response_status'] ?? '') === 'success' && !empty($response['response']['checkout_url'])) { if (($response['response']['response_status'] ?? '') === 'success' && !empty($response['response']['checkout_url'])) {
// Language keys are loaded now, so this will contain actual text $url = $response['response']['checkout_url'];
$comment = sprintf($this->language->get('text_redirecting_comment'), $request_data['order_id'], $response['response']['checkout_url']);
$this->model_checkout_order->addHistory($order_info['order_id'], $this->config->get('payment_hutko_new_order_status_id'), $comment, false);
$json['redirect'] = $response['response']['checkout_url']; // 3. Log to INTERNAL DB (Not Customer History)
$this->model_extension_hutko_payment_hutko->logTransaction(
$order_info['order_id'],
$hutko_ref,
'payment_request',
'created',
$request_data['amount'] / 100,
$request_data['currency'],
[
'request_data' => $request_data, // Store sent data (except signature if needed)
'checkout_url' => $url,
'user_agent' => $this->request->server['HTTP_USER_AGENT'] ?? ''
]
);
// 4. Update Order Status to "Pending" (or configured status) if not already
// Only add history if it's a fresh order, don't spam.
if ($order_info['order_status_id'] == 0) {
$this->model_checkout_order->addHistory($order_info['order_id'], $this->config->get('payment_hutko_new_order_status_id'), $this->language->get('text_initiated_payment'), false);
}
$json['redirect'] = $url;
} else { } else {
$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; $json['error'] = $err;
$this->logOC('Checkout Error: ' . $err);
// Log Failure
$this->model_extension_hutko_payment_hutko->logTransaction(
$order_info['order_id'],
$hutko_ref,
'payment_request',
'failed',
$request_data['amount'] / 100,
$request_data['currency'],
['error' => $err, 'api_response' => $response]
);
} }
} }
} }
@@ -55,56 +87,73 @@ class Hutko extends \Opencart\System\Engine\Controller {
} }
public function callback(): void { public function callback(): void {
// IMPORTANT: Load language for status translations (e.g. text_payment_approved)
$this->load->language('extension/hutko/payment/hutko'); $this->load->language('extension/hutko/payment/hutko');
$input = file_get_contents("php://input"); $input = file_get_contents("php://input");
$data = json_decode($input, true); $data = json_decode($input, true);
if ($this->config->get('payment_hutko_save_logs')) { // Basic Validation
$this->logOC('Callback: ' . $input); if (!$data || !isset($data['order_id'])) {
}
if (!$data || !$this->validate($data)) {
http_response_code(400); http_response_code(400);
exit('Invalid Request'); exit('Invalid Request');
} }
$parts = explode('#', $data['order_id']); // Verify Signature first
if (!$this->validate($data)) {
http_response_code(400);
exit('Invalid Signature');
}
$hutko_ref = $data['order_id']; // e.g., 55#17555555
$parts = explode('#', $hutko_ref);
$order_id = (int)$parts[0]; $order_id = (int)$parts[0];
$this->load->model('checkout/order'); $this->load->model('checkout/order');
$order_info = $this->model_checkout_order->getOrder($order_id); $order_info = $this->model_checkout_order->getOrder($order_id);
if ($order_info) { if ($order_info) {
$this->load->model('extension/hutko/payment/hutko');
$status = $data['order_status'] ?? ''; $status = $data['order_status'] ?? '';
$comment_details = "Hutko Order ID: " . $data['order_id'] . ". Status: " . $status . ". ";
$current_status_id = $order_info['order_status_id']; // 1. Log the RAW callback to our internal table
$this->model_extension_hutko_payment_hutko->logTransaction(
$order_id,
$hutko_ref,
'callback',
($status === 'approved') ? 'success' : 'failed',
isset($data['amount']) ? $data['amount'] / 100 : 0,
$data['currency'] ?? '',
$data // Save full payload
);
$current_status_id = (int)$order_info['order_status_id'];
// 2. Update OpenCart History (Clean Messages Only)
if ($status === 'approved') { if ($status === 'approved') {
if (isset($data['response_status']) && $data['response_status'] == 'success' && (!isset($data['reversal_amount']) || (int)$data['reversal_amount'] === 0)) { if (isset($data['response_status']) && $data['response_status'] == 'success') {
$target = (int)$this->config->get('payment_hutko_success_status_id'); $target_status_id = (int)$this->config->get('payment_hutko_success_status_id');
if ($current_status_id != $target) {
$msg = $this->language->get('text_payment_approved') . ' ' . $comment_details; // Avoid duplicates: Only update if status is different
$this->model_checkout_order->addHistory($order_id, $target, $msg, true); if ($current_status_id != $target_status_id) {
$this->model_checkout_order->addHistory($order_id, $target_status_id, $this->language->get('text_payment_approved'), true);
} }
echo "OK"; echo "OK";
} else { } else {
echo "Approved but invalid details"; echo "Approved but invalid details";
} }
} elseif ($status === 'declined') { } elseif ($status === 'declined') {
$target = (int)$this->config->get('payment_hutko_declined_status_id'); $target_status_id = (int)$this->config->get('payment_hutko_declined_status_id');
if ($current_status_id != $target) { if ($current_status_id != $target_status_id) {
$msg = $this->language->get('text_payment_declined') . ' ' . $comment_details; // Don't notify customer on decline to avoid spam if they retry
$this->model_checkout_order->addHistory($order_id, $target, $msg, true); $this->model_checkout_order->addHistory($order_id, $target_status_id, $this->language->get('text_payment_declined'), false);
} }
echo "Order declined"; echo "Order declined";
} elseif ($status === 'expired') { } elseif ($status === 'expired') {
$target = (int)$this->config->get('payment_hutko_expired_status_id'); // Often better not to change order status to "Expired" if you want to allow retries,
if ($current_status_id != $target) { // but if you do, don't notify customer.
$msg = $this->language->get('text_payment_expired') . ' ' . $comment_details; $target_status_id = (int)$this->config->get('payment_hutko_expired_status_id');
$this->model_checkout_order->addHistory($order_id, $target, $msg, true); if ($current_status_id != $target_status_id) {
$this->model_checkout_order->addHistory($order_id, $target_status_id, $this->language->get('text_payment_expired'), false);
} }
echo "Order expired"; echo "Order expired";
} else { } else {
@@ -116,9 +165,8 @@ class Hutko extends \Opencart\System\Engine\Controller {
} }
} }
private function buildRequest($order) { private function buildRequest($order, $hutko_ref) {
$ref = $order['order_id'] . '#' . time(); // Logic same as before, but using passed $hutko_ref
$products_data = $this->getProducts($order['order_id'], $order); $products_data = $this->getProducts($order['order_id'], $order);
$total_products_sum = 0; $total_products_sum = 0;
@@ -161,7 +209,7 @@ class Hutko extends \Opencart\System\Engine\Controller {
]; ];
$data = [ $data = [
'order_id' => $ref, 'order_id' => $hutko_ref,
'merchant_id' => $this->config->get('payment_hutko_merchant_id'), 'merchant_id' => $this->config->get('payment_hutko_merchant_id'),
'amount' => $total_cents, 'amount' => $total_cents,
'currency' => $order['currency_code'], 'currency' => $order['currency_code'],
@@ -176,6 +224,8 @@ class Hutko extends \Opencart\System\Engine\Controller {
return $data; return $data;
} }
// Helper functions (getProducts, sign, validate, api, logOC) remain the same...
// Just ensure logOC uses file log for debug, not DB log.
private function getProducts(int $order_id, array $order_info): array { private function getProducts(int $order_id, array $order_info): array {
$products_data = []; $products_data = [];
$query = $this->db->query("SELECT * FROM `" . DB_PREFIX . "order_product` WHERE `order_id` = '" . (int)$order_id . "'"); $query = $this->db->query("SELECT * FROM `" . DB_PREFIX . "order_product` WHERE `order_id` = '" . (int)$order_id . "'");