diff --git a/pages/payment.php b/pages/payment.php index e9e2295..1173847 100644 --- a/pages/payment.php +++ b/pages/payment.php @@ -1,56 +1,122 @@ load('dolipesa@dolipesa'); -// Retrieve M-Pesa callback data -$callbackData = json_decode(file_get_contents('php://input'), true); +// Security check +$invoiceId = GETPOST('invoice_id', 'int'); +$token = GETPOST('token', 'alpha'); -if (!$callbackData) { - http_response_code(400); - echo json_encode(["error" => "Invalid callback data"]); - exit; +if (!$invoiceId || !$token) { + accessforbidden($langs->trans('MissingParameters')); } -// Extract data from callback -$invoiceId = $callbackData['AccountReference'] ?? null; -$transactionId = $callbackData['MpesaReceiptNumber'] ?? null; -$resultCode = $callbackData['ResultCode'] ?? 1; -$resultDesc = $callbackData['ResultDesc'] ?? "Unknown error"; - -if (!$invoiceId || !$transactionId) { - http_response_code(400); - echo json_encode(["error" => "Missing invoice or transaction ID"]); - exit; +// Validate token (simple example; enhance for production) +$expectedToken = md5($invoiceId . $conf->global->MAIN_SECURITY_SALT); +if ($token !== $expectedToken) { + accessforbidden($langs->trans('InvalidToken')); } -// Handle successful transaction -if ($resultCode == 0) { - $sql = "UPDATE ".MAIN_DB_PREFIX."facture SET transaction_number = '$transactionId', paye = 1 WHERE rowid = $invoiceId"; - $db->query($sql); - - // Log payment in Dolibarr - $sqlPayment = "INSERT INTO ".MAIN_DB_PREFIX."paiement (facid, amount, datep, num_payment) VALUES ($invoiceId, (SELECT total FROM ".MAIN_DB_PREFIX."facture WHERE rowid = $invoiceId), NOW(), '$transactionId')"; - $db->query($sqlPayment); - - // Update invoice status - $sqlUpdateInvoice = "UPDATE ".MAIN_DB_PREFIX."facture SET statut = 2 WHERE rowid = $invoiceId"; // Paid status - $db->query($sqlUpdateInvoice); - - http_response_code(200); - echo json_encode(["success" => "Payment successful", "transaction_id" => $transactionId]); -} else { - // Handle failed transaction - http_response_code(400); - echo json_encode(["error" => $resultDesc]); +// Load invoice +$invoice = new Facture($db); +if ($invoice->fetch($invoiceId) <= 0 || $invoice->statut != 1) { // Validated status + accessforbidden($langs->trans('InvoiceNotFoundOrNotValidated')); } +// Process payment submission +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $phoneNumber = GETPOST('phone_number', 'alpha'); + $amount = floatval($invoice->total_ttc); // Use invoice total including tax + + // Validate phone number (Kenyan format: 2547XXXXXXXX) + if (!preg_match('/^254[0-9]{9}$/', $phoneNumber)) { + setEventMessages($langs->trans('InvalidPhoneNumber'), null, 'errors'); + } else { + // Load M-Pesa credentials + $consumerKey = $conf->global->MPESAPAY_CONSUMER_KEY; + $consumerSecret = dol_decrypt($conf->global->MPESAPAY_CONSUMER_SECRET); + $shortcode = $conf->global->MPESAPAY_SHORTCODE; + $passkey = dol_decrypt($conf->global->MPESAPAY_PASSKEY); + $callbackUrl = $conf->global->MPESAPAY_CALLBACK_URL ?: DOL_MAIN_URL_ROOT . '/custom/dolipesa/callback.php'; + + if (empty($consumerKey) || empty($consumerSecret) || empty($shortcode) || empty($passkey)) { + setEventMessages($langs->trans('ModuleNotConfigured'), null, 'errors'); + } else { + // Generate OAuth token + $credentials = base64_encode($consumerKey . ':' . $consumerSecret); + $tokenResponse = dol_http_get('https://sandbox.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials', [ + 'Authorization: Basic ' . $credentials + ]); + $tokenData = json_decode($tokenResponse, true); + $accessToken = $tokenData['access_token'] ?? null; + + if (!$accessToken) { + setEventMessages($langs->trans('FailedToGetMpesaToken'), null, 'errors'); + } else { + // Prepare STK Push payload + $timestamp = date('YmdHis'); + $password = base64_encode($shortcode . $passkey . $timestamp); + $payload = [ + 'BusinessShortCode' => $shortcode, + 'Password' => $password, + 'Timestamp' => $timestamp, + 'TransactionType' => 'CustomerPayBillOnline', + 'Amount' => $amount, + 'PartyA' => $phoneNumber, + 'PartyB' => $shortcode, + 'PhoneNumber' => $phoneNumber, + 'CallBackURL' => $callbackUrl, + 'AccountReference' => $invoice->ref, + 'TransactionDesc' => $langs->trans('PaymentForInvoice', $invoice->ref) + ]; + + // Send STK Push request + $response = dol_http_post('https://sandbox.safaricom.co.ke/mpesa/stkpush/v1/processrequest', json_encode($payload), [ + 'Authorization: Bearer ' . $accessToken, + 'Content-Type: application/json' + ]); + $responseData = json_decode($response, true); + + if ($responseData && $responseData['ResponseCode'] == '0') { + // Store CheckoutRequestID for callback mapping + $checkoutRequestID = $responseData['CheckoutRequestID']; + $sql = "INSERT INTO " . MAIN_DB_PREFIX . "dolipesa_transactions (checkout_request_id, fk_invoice, datec) "; + $sql .= "VALUES ('" . $db->escape($checkoutRequestID) . "', " . $invoice->id . ", NOW())"; + $db->query($sql); + + setEventMessages($langs->trans('PaymentInitiated'), null, 'mesgs'); + } else { + setEventMessages($langs->trans('PaymentInitiationFailed') . ': ' . ($responseData['errorMessage'] ?? 'Unknown error'), null, 'errors'); + } + } + } + } +} + +// Display payment form +print load_fiche_titre($langs->trans('PayInvoice', $invoice->ref)); +print '
'; +print ''; +print ''; +print ''; +print ''; +print ''; +print '
'; +print '
'; +print ''; +print '
'; +print '
'; + +llxFooter(); $db->close(); -?> +?> \ No newline at end of file