Update pages/payment.php
Signed-off-by: kevinowino869 <kevinowino869@www.codelab.nestict.africa>
This commit is contained in:
parent
e0b07cbfd7
commit
8cc6a82807
@ -1,56 +1,122 @@
|
||||
<?php
|
||||
/**
|
||||
* M-Pesa Payment Module - Callback Handler
|
||||
* Dolipesa - M-Pesa Payment Module Payment Initiation
|
||||
* Author: NESTICT INFOTECH
|
||||
* Version: 1.0.0
|
||||
* Version: 1.0.1
|
||||
* License: GNU General Public License v3.0
|
||||
*/
|
||||
|
||||
require '../../main.inc.php';
|
||||
require_once DOL_DOCUMENT_ROOT . "/core/lib/admin.lib.php";
|
||||
require_once DOL_DOCUMENT_ROOT . '/core/lib/admin.lib.php';
|
||||
require_once DOL_DOCUMENT_ROOT . '/compta/facture/class/facture.class.php';
|
||||
|
||||
header('Content-Type: application/json');
|
||||
// Load translations
|
||||
$langs->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";
|
||||
// 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);
|
||||
|
||||
// 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]);
|
||||
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 '<form method="POST" action="' . $_SERVER['PHP_SELF'] . '?invoice_id=' . $invoiceId . '&token=' . $token . '">';
|
||||
print '<table class="noborder centpercent">';
|
||||
print '<tr class="oddeven"><td><label for="phone_number">' . $langs->trans('PhoneNumber') . ' (254...):</label></td>';
|
||||
print '<td><input type="text" name="phone_number" id="phone_number" pattern="^254[0-9]{9}$" value="254" required></td></tr>';
|
||||
print '<tr class="oddeven"><td><label for="amount">' . $langs->trans('Amount') . ' (KES):</label></td>';
|
||||
print '<td><input type="number" name="amount" id="amount" value="' . price($invoice->total_ttc, 0, '', 1, -1, -1, 'KES') . '" readonly></td></tr>';
|
||||
print '</table>';
|
||||
print '<div class="center" style="margin-top: 20px;">';
|
||||
print '<input type="submit" class="button" value="' . $langs->trans('PayNow') . '">';
|
||||
print '</div>';
|
||||
print '</form>';
|
||||
|
||||
llxFooter();
|
||||
$db->close();
|
||||
?>
|
Loading…
x
Reference in New Issue
Block a user