Files
booking/booking.paypal.inc
2014-12-01 23:06:39 +11:00

282 lines
10 KiB
PHP

<?php
function _booking_paypal_post($data = array()) {
$post = '';
foreach ($data as $key => $value) {
$post .= $key. '='. urlencode($value). '&';
}
$post .= 'cmd=_notify-validate';
return $post;
}
function _booking_paypal_ipn_verify($vars = array()) {
if (variable_get('booking_paypal_sandbox', 0)) {
watchdog('booking', 'Setting IPN verify to true, running in sandbox mode');
// PayPal sandbox requires login in order to even access, so for sandbox mode, simply return true.
return TRUE;
}
$ch = curl_init(BOOKING_PAYPAL_SUBMIT_URL);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, _booking_paypal_post($vars));
ob_start();
if (curl_exec($ch)) {
$info = ob_get_contents();
curl_close($ch);
ob_end_clean();
if (preg_match('/VERIFIED/i', $info)) {
watchdog('booking', 'Payment verification completed successfully: @info', array('@info' => $info));
return TRUE;
}
else {
watchdog('booking', 'Payment verification not successful: @info', array('@info' => $info));
return FALSE;
}
}
else {
watchdog('booking_paypal', 'Call to curl_exec() failed. url=@url vars=@vars', array(
'@vars' => print_r($vars, TRUE)
), WATCHDOG_ERROR);
return FALSE;
}
}
/**
* Handles an incoming PayPal IPN.
*/
function booking_paypal_ipn() {
$ipn = $_POST;
watchdog('booking', 'Payment notification received: @info', array('@info' => var_export($ipn, TRUE)));
if(!_booking_paypal_ipn_verify($ipn))
return;
/*
if ($ipn['payment_status'] != 'Pending' && variable_get('booking_paypal_sandbox', 0) == 1) {
watchdog('booking', 'Running in sandbox mode but type is not pending');
return;
}
*/
if (empty($ipn['payment_status']) || ($ipn['payment_status'] != 'Completed' && variable_get('booking_paypal_sandbox', 0) == 0))
return;
//if (strcasecmp($ipn['receiver_email'], variable_get('booking_paypal_account', '') <> 0))
if ($ipn['receiver_email'] !== variable_get('booking_paypal_account', ''))
{
watchdog('booking_paypal', 'Receiving address "!receiver" for paypal payment doesnt match configured address "!configured". Full POST: !id',
array('!id' => var_export($ipn, TRUE), '!receiver' => $ipn['receiver_email'], '!configured' => variable_get('booking_paypal_account', '')), WATCHDOG_ERROR);
}
//Insert record into database and remove temporary booking id field from user
_booking_process_payment($ipn);
}
function _booking_process_payment($data) {
global $event;
$balance_payment = false;
$amount_owing = 0;
//extract the person node id from the invoice
$pos = strpos($data['invoice'], "_");
if (($pos === false) || ($pos == 0))
{
watchdog('booking', 'Unable to process payment with invalid invoice information: !id', array('!id' => $data['invoice']), WATCHDOG_ERROR);
return;
}
//get the part of the invoice up to the first underscore
$nid = substr($data['invoice'], 0, $pos);
//get the data between the first and second underscore
$eid = substr($data['invoice'], $pos + 1, strrpos($data['invoice'], "_") - $pos - 1);
if (substr($eid,0,3) == "bal")
{
$balance_payment = true;
watchdog('booking', 'Balance payment for user with node id: !id', array('!id' => $nid));
}
//verify paypal hasn't already sent through a notification for this payment
$duplicate_check = db_query("SELECT payid, booking_person_nid FROM {booking_payment} where booking_ipn_track_id = :ipn_id ",
array(':ipn_id' => $data['ipn_track_id']))
->fetchObject();
if ($duplicate_check)
{
watchdog('booking', 'Detected duplicate paypal notifications for transaction id !id, registration id !nid', array('!id' => $data['ipn_track_id'], '!nid' => $nid), WATCHDOG_ERROR);
return;
}
//watchdog('booking', 'Adding payment for user with node id: !id; event id: !eid', array('!id' => $nid, '!eid' => $eid));
$result = db_insert('booking_payment')
->fields(array(
'booking_person_nid' => $nid,
'booking_eventid' => $event->eid,
'booking_mc_gross' => $data['mc_gross'],
'booking_mc_currency' => $data['mc_currency'],
'booking_mc_fee' => $data['mc_fee'],
'booking_quantity' => $data['quantity'],
'booking_invoice' => $data['invoice'],
'booking_payer_id' => $data['payer_id'],
'booking_payment_date' => strtotime($data['payment_date']),
'booking_payment_status' => $data['payment_status'],
'booking_first_name' => $data['first_name'],
'booking_last_name' => $data['last_name'],
'booking_buyer_email' => $data['payer_email'],
'booking_payer_status' => $data['payer_status'],
'booking_item_name' => $data['item_name'],
'booking_ipn_track_id' => $data['ipn_track_id'],
))
->execute();
//Get the person's info
/*
$payment = db_select('booking_person', 'p')
->condition('p.nid', $nid, '=')
->fields('p', array('booking_amount_paid', 'booking_status', 'booking_total_pay_reqd', 'booking_partner_id'))
->execute()
->fetchObject();
*/
$person = node_load($nid);
//check if we found a person matching this payment
if ($person)
{
watchdog('booking', 'Found matching user with node id: !id; event id: !eid; existing payment !payment', array('!id' => $nid, '!eid' => $eid,
'!payment' => $person->booking_amount_paid));
//if successful, update their total payment amount
$total = $person->booking_amount_paid + $data['mc_gross'];
//only recalculate their booking status if this is the initial payment, not a payment of the outstanding balance
if ($balance_payment == FALSE)
{
watchdog('booking', 'Processing an initial payment. Booking status is currently ' . $person->booking_status);
if ($person->booking_status == 1)
{
watchdog('booking', 'This registration has been manually assigned to the booked-in list.');
$status = 1;
}
elseif (_booking_check_bookings_full() == True || $person->booking_status == 2)
{
watchdog('booking', 'This registration belongs on the waiting list.');
$status = 2;
}
else
{
watchdog('booking', 'This registration made it to the booked-in list.');
$status = 1;
}
}
else //this is a balance payment
{
watchdog('booking', 'Processing a balance payment.');
//if this is a payment of outstanding balance, keep the booking_status the same
$status = $person->booking_status;
//$status = $person->booking_status == 2 ? 2 : 1;
}
//update the database for this person
db_update('booking_person')
->fields(array(
'booking_amount_paid' => $total,
'booking_status' => $status,
))
->condition('nid', $nid)
->execute();
//If there is no outstanding balance, send a payment complete email
$amount_owing = _booking_amount_owing($person);
//if ($total >= $person->booking_total_pay_reqd)
if ($amount_owing == 0)
{
//set the payment complete flag
db_update('booking_person')
->fields(array(
'booking_payment_complete' => 'Y',
))
->condition('nid', $nid)
->execute();
//this should always be a balance payment type email, since that tells the user that their payment is completed
_booking_registration_email($nid, TRUE);
//if we are combining payments, and this person has a linked spouse
if ((variable_get('booking_enable_combined_pricing', 0) == 1) && ($person->booking_partner_id > 0))
{
//check spouse booking_status and payment info
$spouse = db_select('booking_person', 'p')
->condition('p.nid', $person->booking_partner_id,'=')
->fields('p', array('booking_amount_paid', 'booking_status', 'booking_total_pay_reqd'))
->execute()
->fetchObject();
//update the spouse's status from "not paid" if required
$spouse_status = $spouse->booking_status == 0 ? 1 : $spouse->booking_status;
watchdog('booking', 'Setting status for spouse id !id to !new from !status', array('!id' => $person->booking_partner_id,
'!new' => $spouse_status, '!status' => $spouse->booking_status));
//set the spouse's payment required to be zero or equal to their previous payment total
$spouse_new_amount_reqd = $spouse->booking_amount_paid > 0 ? $spouse->booking_amount_paid : 0;
watchdog('booking', 'Setting amount owing for spouse id !id to !new from !old.', array('!id' => $person->booking_partner_id,
'!new' => $spouse_new_amount_reqd, '!old' => $spouse->booking_total_pay_reqd));
//update the database for this person
db_update('booking_person')
->fields(array(
'booking_total_pay_reqd' => $spouse_new_amount_reqd,
'booking_status' => $spouse_status,
'booking_payment_complete' => 'Y',
))
->condition('nid', $person->booking_partner_id)
->execute();
//send an email to the spouse
_booking_registration_email($person->booking_partner_id, TRUE);
}
/*
elseif (variable_get('booking_enable_combined_pricing', 0) == 1)
{
watchdog('booking', 'Combined pricing is enabled, but this person has a partner id of !id.', array('!id' => $person->booking_partner_id));
} //end spouse check
*/
}
//if this was an initial payment we might need to send a notification
elseif ($balance_payment == FALSE)
{
//send a notification email if we didn't automatically send one earlier
if (variable_get('booking_auto_confirm_email', 0) == 0)
{
_booking_registration_email($nid, FALSE);
}
}
else //this person still has an outstanding balance so just send a confirmation email
{
watchdog('booking', 'This balance payment of !payment was insufficient for !id to completely pay the total outstanding of !outstanding.',
array('!id' => $nid, '!payment' => $data['mc_gross'], '!outstanding' => $amount_owing));
//send the person an email thanking them for their partial payment
_booking_partialbalance_payment_email($nid);
//TODO: create an email specifically for partial-balance payments
//_booking_registration_email($nid, $balance_payment);
}
}
else //couldn't find a matching nid for this invoice
{
watchdog('booking', "Unable to process payment for user with node id: '!id'", array('!id' => $nid), WATCHDOG_ERROR);
//db_query("UPDATE {booking_person} SET booking_tempid='' WHERE nid = %d", $nid);
}
}