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(); } ?>