added refund logic
This commit is contained in:
@@ -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' && $requestBody['reversal_amount'] == '0') {
|
||||
$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->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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user