getCallbackContent(); $id_order_parts = explode($this->module->order_separator, $calbackContent['order_id']); $id_order = (int)$id_order_parts[0]; // Ensure it's an integer // If we reached here, an order should exist. Load it. $order = new Order($id_order); if (!Validate::isLoadedObject($order)) { PrestaShopLogger::addLog('Hutko Callback: Order could not be loaded for ID: ' . $id_order, 3, null, 'Order', $id_order, true); throw new Exception('Order not found after validation'); } $this->context->currency = new Currency($order->id_currency); $this->context->customer = new Customer($order->id_customer); $this->context->language = new Language($order->id_lang); // Handle payment status from the callback. $orderStatusCallback = $calbackContent['order_status']; $currentOrderState = (int)$order->getCurrentState(); switch ($orderStatusCallback) { case 'approved': // Only process success state if no refunds was done. if ($calbackContent['response_status'] == 'success' && (int)$calbackContent['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) { $callbackAmount = $calbackContent['actual_amount'] ?? $calbackContent['amount']; $amountFloat = round($callbackAmount / 100, 2); $order->addOrderPayment($amountFloat, $this->module->displayName, $calbackContent['order_id'], $this->context->currency); $order->setCurrentState($expectedState); $this->module->addOrderMessage($order, $this->trans('Pay via Hutko: ', [], 'Modules.Hutko.Admin') . ' ' . $calbackContent['currency'] . $amountFloat); } } exit('OK'); break; case 'declined': $expectedState = (int)Configuration::get('PS_OS_ERROR'); // Only change state if it's not already the error state. if ($currentOrderState !== $expectedState) { $order->setCurrentState($expectedState); } exit('Order ' . $orderStatusCallback); break; case 'expired': $expectedState = (int)Configuration::get('PS_OS_ERROR'); // Only change state if it's not already the error state. if ($currentOrderState !== $expectedState) { $order->setCurrentState($expectedState); } exit('Order ' . $orderStatusCallback); break; case 'processing': //no need to change status exit('Order ' . $orderStatusCallback); break; default: // Log unexpected status and exit with an error. PrestaShopLogger::addLog('Hutko Callback: Unexpected order status received: ' . $orderStatusCallback . ' for order ID: ' . $id_order, 3, null, 'Order', $id_order, true); throw new Exception('Unexpected status'); break; } } catch (Exception $e) { // Log any uncaught exceptions and exit with the error message. PrestaShopLogger::addLog('Hutko Callback Error: ' . $e->getMessage(), 3, null, 'HutkoCallbackModuleFrontController', null, true); throw new Exception('Unknown error'); } } /** * Helper method to parse the request body from raw input. * * @return array The parsed request body. */ private function getCallbackContent(): array { $calbackContent = json_decode(file_get_contents("php://input"), true); if (!is_array($calbackContent) || !count($calbackContent)) { PrestaShopLogger::addLog('Hutko Callback: Empty request body received.', 2); throw new Exception('Empty request'); } // Assuming validateResponse returns true on success, or a string error message on failure. $isSignatureValid = $this->module->validateResponse($calbackContent); if ($isSignatureValid !== true) { PrestaShopLogger::addLog('Hutko Callback: Invalid signature. Error: ' . $isSignatureValid, 2); throw new Exception('Invalid signature'); } if (Configuration::get('HUTKO_SAVE_LOGS')) { $this->module->log('CalbackContent: ' . json_encode($calbackContent)); } return $calbackContent; } }