Files
HotLunches/bamboraCcPayment.php
T
2026-10-19 15:22:52 -07:00

482 lines
20 KiB
PHP

<?php
$ValidAccess = 2010;
require_once("include/globals.php");
require_once("include/queuemail.php");
if (SessionActive() != 1 || ! UserLoggedIn()) {
header("Location: /");
exit();
}
$ptime = time();
$time = date("Y-m-d H:i:s",$ptime);
$ltime = date("Y-m-d.H.i.s",$ptime);
// start capturing output
function saveOutput($contents) {
global $ltime, $school_num;
$BASEDIR = "/m/data1/app.hotlunches.net";
$f = fopen("$BASEDIR/logs/bambora/bm.$school_num.$ltime", "w");
fwrite($f, $contents);
fclose($f);
return nl2br(htmlentities($contents));
}
if (!isset($sessionID)) $sessionID = session_id();
ini_set('display_errors', 1);
date_default_timezone_set("Canada/Pacific");
ob_start("saveOutput");
// function to execute a mysql query after echoing the query statement and return result
function pp_query($query) {
echo("{$query}\n");
$r = db_query($query);
if (stripos($query,"update") !== false || stripos($query,"insert") !== false || stripos($query,"delete") !== false) {
$n = db_affected_rows();
echo("Affected Rows: $n\n");
}
return($r);
}
// function to execute a mysql query after echoing the query statement and return value
function pp_getVal($query) {
echo("{$query}\n");
$r = db_getVal($query);
return($r);
}
if(!empty($_REQUEST['bamboraToken'])) {
require 'beanstream-php-master/vendor/autoload.php';
$merchant_id = '388200000'; // EZSsoftwareCAD Merchant ID
$merchant_id = '368740000'; // EZSsoftwareCAD Merchant ID
$api_key = '1B2763Ad45644d13a3e3e6E80A90593C'; //INSERT API ACCESS PASSCODE
if (strlen($school_record['bambora_parent_id']) > 3) $merchant_id = $school_record['bambora_parent_id'];
$submerchant_id = $school_record['bambora_merchant_id']; // Client MERCHANT ID (must be a 9 digit string)
if ($school_record['bambora_currency'] == 'USD') {
$merchant_id = '368760000'; // EZSsoftwareUSA Merchant ID
$api_key = '8c75316D69e44156A5290c63B3DdDC70';
}
$api_version = 'v1'; //default
$platform = 'api'; //default
echo("api_key: $api_key\n");
echo("merchant_id: $merchant_id\n");
echo("submerchant_id: $submerchant_id\n");
//Create Beanstream Gateway
$beanstream = new \Beanstream\Gateway($merchant_id, $api_key, $platform, $api_version, $submerchant_id);
$user_num = intval($_REQUEST['user_num']);
$amount = $_REQUEST['amount'];
// Sanitized copy of the amount used in SQL statements - decimal(12,2) columns
// reject an empty or non-numeric value when the server runs in strict mode
$amount_db = number_format(floatval($amount), 2, '.', '');
// $order_number = $_REQUEST['trxnum']."-$user_num";
// $order_number = $_REQUEST['trxnum'].'-'.rand();
$now = time();
$tnow = intval(($now + 15 * 60) / (60 * 30)) * 30 * 60;
$t = date("YmdHi",$tnow);
$order_number = $_REQUEST['trxnum']."-$user_num-$t";
$name = $_REQUEST['schoolName'] . " - " . getLanguageText('TEXT-ORDER');
if ($_SESSION['UserInfo']['type'] == 'Parent' || $_SESSION['UserInfo']['type'] == 'Guest') $name = $_SESSION['UserInfo']['first_name'].' '.$_SESSION['UserInfo']['last_name'];
$b_transaction_fee = floatval($_REQUEST['trx_fee']);
echo("order_number: $order_number\n");
echo("amount: $amount\n");
echo("name: $name\n");
echo("customer ip: ".$_SESSION['LoginIP']."\n");
echo("bamboraTransactionFee: " . $GLOBALS['bamboraTransactionFee'] . "\n");
echo("bamboraTransactionPercentage: " . $GLOBALS['bamboraTransactionPercentage'] . "\n");
$b_mc_fee = $GLOBALS['bamboraTransactionFee'] + intval($_REQUEST['amount'] * $GLOBALS['bamboraTransactionPercentage'])/100;
echo("b_mc_fee: $b_mc_fee\n");
$b_mc_fee_db = number_format(floatval($b_mc_fee), 2, '.', '');
$legato_payment_data = array(
'order_number' => $order_number,
'amount' => $amount,
'name' => $name,
'customer_ip' => $_SESSION['LoginIP']
);
$complete = TRUE; //set to FALSE for PA
$token = trim($_REQUEST['bamboraToken']);
$payment_status = '';
$txn_id = 0;
//Try to submit a Card Payment
try {
//make legato payment with above token
$result = $beanstream->payments()->makeLegatoTokenPayment($token, $legato_payment_data, $complete);
if($result['approved'] == 1) {
$payment_status = 'Completed';
$txn_id = $result['id'];
}
$merchant_response_message = $result['message'];
print_r($result);
// saveOutput(serialize($result));
/*
* Handle successful transaction, payment method returns
* transaction details as result, so $result contains that data
* in the form of associative array.
*/
} catch (\Beanstream\Exception $e) {
echo("Exception:\n");
echo("\$e\n");
print_r($e);
/*
* Handle transaction error, $e->code can be checked for a
* specific error, e.g. 211 corresponds to transaction being
* DECLINED, 314 - to missing or invalid payment information
* etc.
*/
$msg = $e->getMessage();
$code = $e->getCode();
$merchant_response_message = $e->getMessage();
if (!isset($payment_status) || strlen($payment_status) == 0) $payment_status = 'Failed';
}
// Use the posted transaction number value to determine the school_num
$TRXnum = intval($_REQUEST['trxnum']);
$query = "SELECT school_num FROM user_online_payments WHERE record_num = {$TRXnum} ORDER BY record_num DESC LIMIT 0,1";
$school_num = intval(pp_getVal($query));
// Never leave school_num empty - an empty value produces a broken SQL statement
// and the whole transaction goes unlogged
if ($school_num <= 0) {
if (isset($base_school_num) && intval($base_school_num) > 0) $school_num = intval($base_school_num);
else if (isset($school_record['record_num'])) $school_num = intval($school_record['record_num']);
echo("WARNING: no school found for transaction $TRXnum - falling back to school $school_num\n");
}
$curr_school_num = $school_num;
// Check if this entry is in the user_bambora_transactions table
if($txn_id>0) {
$query = "SELECT * FROM user_bambora_transactions WHERE school_num = $school_num AND txn_id = '$txn_id' AND current_year != 'N'";
$r = pp_query($query);
if (db_num_rows($r) > 0) {
$errorMessage = "Duplicate Posting - Transaction Has Already Been Processed: $txn_id";
echo("$errorMessage\n");
header('location:/?action=order-list&error_message=Payment Failed.'.$errorMessage);
exit();
}
}
$payment_date = date('Y-m-d');
$item_title = db_escape_string(normalizeString($name . " Order Payment", 'string'));
if (!isset($merchant_response_message)) $merchant_response_message = '';
// Keep the gateway request/response with the transaction for auditing
$post_data = array('request' => $legato_payment_data,
'response' => (isset($result) ? $result : array('error' => $merchant_response_message)));
$bambora_post_data = db_escape_string(json_encode($post_data));
// Every NOT NULL column without a default value (user_num, trx_num, current_year, ...)
// must be supplied here - if one is left out MySQL rejects the whole INSERT
// ("Field 'trx_num' doesn't have a default value") and the payment goes unlogged.
// user_num and trx_num are also what the bambora log screen joins on, so a row
// without them would be invisible even if it were inserted.
$trxInsert = "school_num, user_num, trx_num, current_year, bambora_post_data, posting_time, posting_result, posting_message, payment_status, merchant_response, txn_id, item_name, payment_date, payment_amount, payment_fee";
$trxValues = "$school_num,$user_num,'$TRXnum','Y','$bambora_post_data','$time','Pending','', '$payment_status', '".db_escape_string($merchant_response_message)."', '$txn_id','$item_title', '$payment_date', '$amount_db', '$b_mc_fee_db'";
$trxSQL = "INSERT INTO user_bambora_transactions ($trxInsert) VALUES ($trxValues)";
// pp_query("START TRANSACTION");
pp_query($trxSQL);
$trxID = intval(db_insert_id());
echo("Insert ID: $trxID\n");
if ($trxID <= 0) echo("WARNING: user_bambora_transactions INSERT returned no record number - transaction log entry is missing\n");
// Load user information from the database
$query = "SELECT * FROM user_online_payments WHERE record_num = {$TRXnum}";
$r = pp_query($query);
if (db_num_rows($r) != 1) {
$errorMessage = "Invalid transaction number or status: $TRXnum";
echo("$errorMessage\n");
pp_query("UPDATE user_bambora_transactions SET posting_result = 'Error', posting_message = '" . db_escape_string($errorMessage) . "' WHERE record_num = $trxID");
// pp_query("COMMIT");
exit();
} else {
extract(db_fetch_assoc($r), EXTR_PREFIX_ALL, 'p');
}
// Load school information from the database
$r = pp_query("SELECT * FROM schools WHERE record_num = {$school_num}");
if (db_num_rows($r) != 1) {
echo("Invalid school.\n");
pp_query("UPDATE user_bambora_transactions SET posting_result = 'Error', posting_message = 'Invalid school' WHERE record_num = $trxID");
// pp_query("COMMIT");
header('location:/?action=order-list&error_message=Invalid school.');
exit();
} else {
extract(db_fetch_assoc($r), EXTR_PREFIX_ALL, 's');
}
// Update user_bambora_transactions with school and user info
pp_query("UPDATE user_bambora_transactions SET school_num = {$school_num}, user_num = {$user_num}, trx_num = '{$TRXnum}' WHERE record_num = $trxID");
// Update hotlunch_orders table
$query = "SELECT hloh.* FROM hotlunch_order_header as hloh, people as p " .
"WHERE hloh.school_num = {$school_num} " .
"AND ordered_by_num = p.record_num " .
"AND p.user_num = {$user_num} " .
"AND hloh.status NOT IN ('Paid','Complimentary','Concession')";
$orders = pp_query($query);
echo("Orders Found: " . db_num_rows($orders) . "\n\n");
if($payment_status != 'Completed') {
// Process Failed transactions
if($payment_status == 'Failed') {
pp_query("UPDATE user_bambora_transactions SET posting_result = 'Error', posting_message = 'Payment failed' WHERE record_num = $trxID");
// Find Pending Orders and reset the status
$query = "SELECT hloh.* FROM hotlunch_order_header as hloh, people as p " .
"WHERE hloh.school_num = {$school_num} " .
"AND ordered_by_num = p.record_num " .
"AND p.user_num = {$user_num} " .
"AND hloh.status IN ('Pending')";
$orders = pp_query($query);
echo("Orders Found: " . db_num_rows($orders) . "\n\n");
// Flag each order
if (db_num_rows($orders) > 0) {
while ($row = db_fetch_array($orders)) {
$onum = $row['record_num'];
$query = "UPDATE hotlunch_order_header " .
"SET status = 'Unpaid' " .
"WHERE record_num = {$onum}";
pp_query($query);
logOrderChange($onum,"PAYMENT INCOMPLETE (Bambora)","bamboraCcPayment.php");
}
}
}
$query = "UPDATE user_bambora_transactions SET posting_result = 'Error', posting_message = 'Payment not completed - $payment_status' WHERE record_num = $trxID";
pp_query($query);
// pp_query("COMMIT");
header("location:/?action=order-list&error_message=Incomplete Payment - Status: $payment_status ".$code."-".$msg);
exit();
}
echo("Payment validated ok - updating database\n\n");
//
// Check if this transaction has been entered already
//
$query = "SELECT * FROM user_online_payments WHERE record_num = $TRXnum AND status = 'Paid'";
$paid_payments = pp_query($query);
if (db_num_rows($paid_payments) > 0) {
echo("Duplicate: This transaction has been posted to user_online_payments already: $TRXnum\n");
$row = db_fetch_assoc($paid_payments);
if ($row['reference'] == $txn_id) exit();
echo("New Bambora Reference ID: $txn_id\n\n");
}
// Update bambora_payments database table
$query = "UPDATE user_online_payments " .
"SET status = 'Paid', payment_amount = balance_owing, reference = '{$txn_id}', completed_time = $ptime " .
"WHERE record_num = $TRXnum";
pp_query($query);
$today = date("Y-m-d",$ptime);
$order_payments = "";
$snum = 0;
if (db_num_rows($orders) > 0) {
while ($row = db_fetch_array($orders)) {
$onum = $row['record_num'];
$ototal = $row['order_total'];
$opaid = $row['amount_paid'];
$snum = $row['schedule_num'];
$amt = number_format($ototal - $opaid,2);
if (strlen($order_payments) > 0) $order_payments .= "|";
$order_payments .= "{" . $onum . ":" . $amt . "}";
$query = "UPDATE hotlunch_order_header " .
"SET amount_paid = order_total, " .
"status = 'Paid', " .
"paid_date = '$today', " .
"payment_method = 'Bambora' " .
"WHERE record_num = {$onum}";
pp_query($query);
logOrderChange($onum,"PAYMENT COMPLETED (Bambora)","bamboraCcPayment.php");
}
}
//
// Check if there is a user_account entry already
//
$query = "SELECT * FROM user_account WHERE school_num = $school_num AND user_num = $user_num AND payment_reference = '$txn_id'";
$ua_entries = pp_query($query);
if (db_num_rows($ua_entries) > 0) {
echo("Duplicate: This transaction has been entered into user_account already: $txn_id\n");
header("location:/?action=order-list&error_message=Duplicate: This transaction has been entered into user_account already: $txn_id\n");
exit();
}
// Post transaction to the user_account
date_default_timezone_set(mapTimeZone($s_timezone));
$entered_time = $ptime;
$trx_time = date("Y-m-d H:i:s",$entered_time);
// Post transaction fee if there is one
if ($b_transaction_fee != 0) {
if ($b_transaction_fee > 0) {
$query = "INSERT INTO user_account " .
"(school_num,user_num,schedule_num,transaction_datetime,transaction_type,transaction_status,note,transaction_amount,amount_paid,transaction_fee,payment_method,payment_reference,order_payments,deleted,entered_time) " .
"VALUES ($school_num,$user_num,$snum,'$trx_time','Bambora Transaction Fee','Closed','',$b_transaction_fee,$b_transaction_fee,0,'Bambora','$txn_id',NULL,'N',$entered_time)";
}
else {
$query = "INSERT INTO user_account " .
"(school_num,user_num,schedule_num,transaction_datetime,transaction_type,transaction_status,note,transaction_amount,amount_paid,transaction_fee,payment_method,payment_reference,order_payments,deleted,entered_time) " .
"VALUES ($school_num,$user_num,$snum,'$trx_time','Bambora Transaction Credit','Closed','',$b_transaction_fee,$b_transaction_fee,0,'Bambora','$txn_id',NULL,'N',$entered_time)";
}
pp_query($query);
$entered_time += 1;
$trx_time = date("Y-m-d H:i:s",$entered_time);
}
// Insert payment transaction
$amount = floatval($amount_db) * -1;
$query = "INSERT INTO user_account " .
"(school_num,user_num,schedule_num,transaction_datetime,transaction_type,note,transaction_amount,transaction_fee,payment_method,payment_reference,order_payments,deleted,entered_time) " .
"VALUES ($school_num,$user_num,$snum,'$trx_time','Payment','Bambora Payment',$amount,$b_mc_fee,'Bambora','$txn_id','$order_payments','N',$entered_time)";
pp_query($query);
// pp_query("COMMIT");
// Get user balance
$balance = db_getVal("select sum(transaction_amount) as balance from user_account where school_num = $school_num and user_num = $user_num AND (deleted != 'Y' OR deleted IS NULL)");
if ($balance <= 0.00) {
// pp_query("START TRANSACTION");
// Update any open charge transactions
$query = "SELECT * FROM user_account " .
"WHERE school_num = $school_num " .
"AND user_num = $user_num " .
"AND transaction_status = 'Open' " .
"AND (payment_method IS NULL OR payment_method = '') " .
"AND transaction_amount > 0";
$results = pp_query($query);
while ($row = db_fetch_assoc($results)) {
$rnum = $row['record_num'];
$query = "UPDATE user_account SET payment_method = 'Bambora', payment_reference = '$txn_id', payment_time = $entered_time " .
"WHERE school_num = $school_num " .
"AND user_num = $user_num " .
"AND record_num = $rnum";
pp_query($query);
}
// Close all transactions
// $query = "UPDATE user_account SET transaction_status = 'Closed' WHERE school_num = $school_num AND user_num = $user_num";
// pp_query($query);
$query = "SELECT record_num FROM user_account WHERE school_num = $school_num AND user_num = $p_user_num AND transaction_status != 'Closed'";
$results = pp_query($query);
while ($row = db_fetch_assoc($results)) {
$rnum = $row['record_num'];
$query = "UPDATE user_account SET transaction_status = 'Closed' WHERE school_num = $school_num AND user_num = $p_user_num AND record_num = $rnum";
pp_query($query);
}
// Update all orders to set amount paid
$query = "SELECT * FROM user_account WHERE school_num = $school_num AND user_num = $user_num AND transaction_amount > 0";
$results = pp_query($query);
while ($row = db_fetch_assoc($results)) {
$rnum = $row['record_num'];
$query = "UPDATE user_account SET amount_paid = transaction_amount WHERE school_num = $school_num AND record_num = $rnum";
pp_query($query);
}
// pp_query("COMMIT");
}
// Make activity_log entry
$username = pp_getVal("SELECT userid FROM users WHERE school_num = $base_school_num AND record_num = $user_num");
$activity = "Bambora Payment";
$additional_info = "TRX ID: $txn_id\nAmount: " . number_format(abs($amount),2) . "\n";
$curr_time = $ptime;
$activity_datetime = date("Y-m-d H:i:s",$curr_time);
$uname = db_escape_string($username);
$user_ip = $_SERVER["REMOTE_ADDR"];
$query = "insert into activity_log (school_num,userid,user_ip,activity_time,activity_datetime,activity,information) " .
"values($school_num,'$uname','$user_ip',$curr_time,'$activity_datetime','$activity','$additional_info')";
pp_query($query);
// Reset user transaction status
$query = "update users set trx_status = NULL where school_num = $base_school_num and record_num = $user_num";
pp_query($query);
// Reset user can_order flag
$query = "update users set can_order = 'Yes' where school_num = $base_school_num and can_order = 'Balance' and record_num = $user_num";
pp_query($query);
// Update user_bambora_transactions
pp_query("UPDATE user_bambora_transactions SET posting_result = 'Posted', posting_message = 'Payment processed ok' WHERE record_num = $trxID");
adjustUserAccountDetails($user_num,$school_num);
$schoolName = $school_record['school_name'];
$amtPaid = '$'.number_format(abs($amount),2);
$emailTo = $_SESSION['UserInfo']['email'];
$emailFrom = "noreply@hotlunches.net";
$emailSubject = "$schoolName Payment - $payment_status";
$emailMessage = "Bambora Payment:\n\n" .
"$schoolName\n" .
"- $name\n" .
"- Paid: $amtPaid\n\n" .
"TRX ID: $txn_id\n" .
"User ID: $uname\n" .
"Time: $activity_datetime\n" .
"\n";
QueueEmail($emailTo,$emailFrom,$emailSubject,$emailMessage,"Bambora Payment");
// $emailTo = "mark@hotlunches.net";
// QueueEmail($emailTo,$emailFrom,$emailSubject,$emailMessage,"Bambora Payment");
// echo("Payment processed ok\n\n\n");
header('location:/?action=user-account&form_message=Payment Completed Successfully');
exit();
}
else
{
echo 'No Token data!';
header("location:/?action=order-list&error_message=No Token Data. Please try again.");
exit();
}
?>