309 lines
11 KiB
PHP
309 lines
11 KiB
PHP
<?php
|
|
|
|
/**
|
|
* Helper function to calculate paypal fees
|
|
*/
|
|
function _booking_add_paypal_fees($amount, $country)
|
|
{
|
|
//add the 30 cent fixed cost
|
|
$result = '0.00';
|
|
$result = (float) ($amount + (float) variable_get('booking_paypal_transaction_fee_fixedcost', '0.3'));
|
|
|
|
//and the 2.6 percent transaction fee for australian transaction with no currency conversion
|
|
if ($country == variable_get('booking_default_country', 'Australia')) {
|
|
$percentage = (float) variable_get('booking_paypal_transaction_fee_percentage', '2.6');
|
|
} else {
|
|
$percentage = (float) variable_get('booking_paypal_transaction_fee_percentage_intl', '3.6');
|
|
//watchdog('booking', "Calculating paypal fees for a currency conversion transaction which adds $percentage percent.");
|
|
}
|
|
|
|
//apply the percentage
|
|
$percentage = (float) $percentage / 100;
|
|
//watchdog('booking', "Paypal percentage transaction fee works out to $percentage.");
|
|
$result = $result / (1 - $percentage);
|
|
|
|
//return result
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Helper function to generate string to post to paypal to verify a successful IPN
|
|
*/
|
|
function _booking_paypal_post($data = array()) {
|
|
$post = '';
|
|
foreach ($data as $key => $value) {
|
|
$post .= $key. '='. urlencode($value). '&';
|
|
}
|
|
$post .= 'cmd=_notify-validate';
|
|
|
|
return $post;
|
|
}
|
|
|
|
/**
|
|
* Helper function to verify a successful IPN from Paypal
|
|
* @see https://github.com/paypal/ipn-code-samples/blob/master/paypal_ipn.php
|
|
*/
|
|
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 with error @error. vars=@vars', array(
|
|
'@vars' => print_r($vars, TRUE), '@error' => curl_error($ch)), 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)));
|
|
|
|
//verify the notification with paypal
|
|
if(!_booking_paypal_ipn_verify($ipn)) {
|
|
watchdog('booking_paypal', 'Payment verification did not succeed. Retrying...');
|
|
|
|
//retry the attempt to verify the payment 5 times, sleeping in between each attempt
|
|
$continue = TRUE;
|
|
$i = 1;
|
|
while ($continue && $i < 5)
|
|
{
|
|
if(!_booking_paypal_ipn_verify($ipn)) {
|
|
watchdog('booking_paypal', "Payment verification did not succeed on attempt $i.");
|
|
$i++;
|
|
sleep(3);
|
|
} else {
|
|
$continue = FALSE;
|
|
watchdog('booking_paypal', "Payment verification succeeded on attempt $i.");
|
|
}
|
|
}
|
|
|
|
//exited the loop above with an unsuccessful verification, so return from the function now
|
|
if ($continue)
|
|
{
|
|
watchdog('booking_paypal', 'Payment verification was unsuccessful.');
|
|
return;
|
|
}
|
|
}
|
|
//verification was successful if we reach this point
|
|
|
|
/*
|
|
if ($ipn['payment_status'] != 'Pending' && variable_get('booking_paypal_sandbox', 0) == 1) {
|
|
watchdog('booking', 'Running in sandbox mode but type is not pending');
|
|
return;
|
|
}
|
|
*/
|
|
|
|
//@todo Handle refund and payment dispute IPNs
|
|
|
|
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_store_paypal_payment($ipn);
|
|
|
|
}
|
|
|
|
function _booking_store_paypal_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 so we can update their total amount paid and booking status
|
|
$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));
|
|
_booking_process_person_payment($person, $data['mc_gross'], $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);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Landing page after returning from paypal
|
|
*/
|
|
function booking_payment_completed_page() {
|
|
//get some configuration information
|
|
global $event;
|
|
$output = "";
|
|
$return_array = array();
|
|
/*
|
|
$parameters = drupal_get_query_parameters();
|
|
|
|
//check if we got a transaction token from paypal
|
|
if (isset($parameters['token'])) {
|
|
//check to make sure the value is something we're expecting
|
|
$paypal_token = $parameters['token'];
|
|
if (! preg_match('/^[0-9A-Fa-f\-]+$/', $paypal_token)) {
|
|
//parameter from url is not what we were expecting so ignore it and just use the site-wide tokens for this page
|
|
$tokens = booking_define_tokens();
|
|
}
|
|
else {
|
|
//query the payments table to find the attendee that this paypal token belongs to
|
|
|
|
}
|
|
}
|
|
*/
|
|
//set the page title
|
|
$bookingTitle = !empty($event->booking_eventname) ? $event->booking_eventname : 'Event';
|
|
drupal_set_title($bookingTitle . ' Registration Completed');
|
|
$input = variable_get('booking_regn_completed_page');
|
|
//watchdog('booking_debug', "<pre>Paypal landing page token:\n@info</pre>", array('@info' => print_r($input['value'] , true)));
|
|
|
|
$output = token_replace($input['value'], booking_define_tokens());
|
|
$return_array[] = array(
|
|
'paragraph' => array(
|
|
'#type' => 'markup',
|
|
'#markup' => $output
|
|
)
|
|
);
|
|
|
|
return $return_array;
|
|
}
|
|
|
|
/**
|
|
* Helper function to generate paypal form for payments
|
|
*/
|
|
function _booking_paypal_form($person, $invoiceid, $amount_owing, $button_text) {
|
|
$form = drupal_get_form('_booking_paypal_form_builder', $person, $invoiceid, $amount_owing, $button_text);
|
|
return drupal_render($form);
|
|
}
|
|
|
|
/**
|
|
* Helper function to generate form elements for paypal form
|
|
*/
|
|
function _booking_paypal_form_builder($node, &$form_state, $person, $invoiceid, $amount_owing, $button_text) {
|
|
global $event;
|
|
|
|
//get our current path so we can send the user back here if they cancel
|
|
$path = isset($_GET['q']) ? $_GET['q'] : '<front>';
|
|
|
|
//paypal specific settings
|
|
$vars = array(
|
|
'module' => 'Booking System',
|
|
'type' => $event->booking_eventname,
|
|
//'custom' => $data,
|
|
'item_name' => $event->booking_eventname . ' ' . $person->booking_price_descrip,
|
|
'invoice' => $invoiceid,
|
|
'no_shipping' => TRUE,
|
|
'no_note' => TRUE,
|
|
'currency_code' => 'AUD',
|
|
'return' => url('bookingfinal', array('absolute' => TRUE)),
|
|
'cancel_return' => url($path, array('absolute' => TRUE)),
|
|
'rm' => '2',
|
|
'amount' => $amount_owing,
|
|
'last_name' => $person->booking_lastname,
|
|
'first_name' => $person->booking_firstname,
|
|
'cmd' => '_xclick',
|
|
'notify_url' => url(BOOKING_PAYPAL_IPN_PATH, array('absolute' => TRUE)),
|
|
'business' => variable_get('booking_paypal_account', '')
|
|
);
|
|
|
|
$form['#action'] = url(variable_get('booking_paypal_sandbox', 0) ? BOOKING_PAYPAL_SUBMIT_URL_SANDBOX : BOOKING_PAYPAL_SUBMIT_URL, array('absolute' => TRUE));
|
|
|
|
//turn the array into a form
|
|
foreach($vars as $name => $value) {
|
|
$form[$name] = array(
|
|
'#type' => 'hidden',
|
|
'#value' => $value,
|
|
);
|
|
}
|
|
|
|
$form['submit'] = array(
|
|
'#type' => 'button',
|
|
'#value' => t($button_text),
|
|
);
|
|
|
|
//watchdog('booking', 'Booking Balance payment: @info', array ('@info' => var_export($form, TRUE)));
|
|
return $form;
|
|
}
|