further implementation work for stripe integration

This commit is contained in:
Nathan Coad
2016-07-22 09:01:39 +10:00
parent 6172866bf4
commit c0d2e11172
6 changed files with 188 additions and 221 deletions

View File

@@ -253,8 +253,8 @@ function booking_admin() {
$form['features']['booking_payment_processor'] = array (
'#type' => 'radios',
'#title' => t('Select Payment Processor to use'),
'#description' => t('Select between Paypal and Stripe to use for integrated payment methods. Has no impact if manual payments are being used.'),
'#options' => array (0 => t('Paypal'), t('Stripe')),
'#description' => t('Select between Paypal, Stripe or Manaul Payment to use for processing payments.'),
'#options' => array (0 => t('Paypal'), t('Stripe'), t('Manual Payments')),
'#default_value' => variable_get('booking_payment_processor', 0),
);
$form['features']['booking_enable_roomallocations'] = array(

View File

@@ -871,13 +871,11 @@ function _booking_deposit_amount($person, $include_fees = TRUE)
/**
* Calculate exactly how much a person has already paid
*/
function _booking_amount_paid($nid, $person = NULL)
{
function _booking_amount_paid($nid, $person = NULL) {
$amount_paid = 0;
//fetch details about the person if we don't already have them
if ($person == NULL)
{
if ($person == NULL) {
$person = db_query("SELECT price.booking_price, price.booking_late_price, person.booking_payment_id, " .
"person.booking_total_pay_reqd, person.booking_amount_paid, person.booking_partner_id " .
"FROM {booking_person} person, {booking_price} price " .
@@ -888,15 +886,13 @@ function _booking_amount_paid($nid, $person = NULL)
}
//check for a spouse
if ($person->booking_partner_id > 0)
{
if ($person->booking_partner_id > 0) {
//watchdog('booking', "Checking total paid for married person");
//look for payments in the payment transaction table
//if we're combining the payment for married couples
if (variable_get('booking_enable_combined_pricing', 0) == 1)
{
if (variable_get('booking_enable_combined_pricing', 0) == 1) {
//check for payments in the paypal transaction table from either spouse
$query = db_query("SELECT booking_mc_gross, booking_mc_fee FROM booking_payment " .
"WHERE booking_person_nid = :nid OR booking_person_nid = :spousenid",
@@ -910,17 +906,16 @@ function _booking_amount_paid($nid, $person = NULL)
}
//add up all the payments
foreach ($query as $payment)
foreach ($query as $payment) {
$amount_paid += ($payment->booking_mc_gross - $payment->booking_mc_fee);
}
//watchdog('booking', "Total amount paid according to paypal payments table is " . $amount_paid);
//there were no payment transactions, so rely on what the amount is set to in the individual registration records
if ($amount_paid == 0)
{
//if we're combining the payment for married couples
if (variable_get('booking_enable_combined_pricing', 0) == 1)
{
if ($amount_paid == 0) {
//if we're combining the payment for married couples
if (variable_get('booking_enable_combined_pricing', 0) == 1) {
$spouse = db_query("SELECT person.booking_amount_paid " .
"FROM {booking_person} person " .
"WHERE person.nid = :nid ",
@@ -929,17 +924,15 @@ function _booking_amount_paid($nid, $person = NULL)
$amount_paid = $person->booking_amount_paid + $spouse->booking_amount_paid;
//watchdog('booking', "Total combined payments for couple based on totals in booking_person table is " . $amount_paid);
}
else
{
$amount_paid = $person->booking_amount_paid;
else {
$amount_paid = $person->booking_amount_paid;
//watchdog('booking', "Total amount paid for individual based on totals in booking_person table is " . $amount_paid);
}
//end combined payments check
}
}
//no spouse found
else
{
else {
//Check if there are payment records in the paypal transaction table for this unmarried person
//if so, base their payments on the gross amount in there rather than what the person booking_person database says
$query = db_query("SELECT booking_mc_gross, booking_mc_fee FROM booking_payment " .
@@ -951,8 +944,9 @@ function _booking_amount_paid($nid, $person = NULL)
//watchdog('booking', "Total amount paid according to paypal payments table is " . $amount_paid);
//if there were no results, $amount_paid will still be 0
if ($amount_paid == 0)
if ($amount_paid == 0) {
$amount_paid = $person->booking_amount_paid;
}
//in case there has been some manual adjustment
//elseif ($amount_paid < $person->booking_amount_paid)
// $amount_paid = $person->booking_amount_paid;
@@ -1021,26 +1015,11 @@ function _booking_total_due($person)
*
* @param $person - the object relating to the registration node
* @param $amount_paid - if we have previously calculated the amount paid, this can be passed as a value
* @param $include_paypal_fees - boolean to indicate whether we want the net amount or the amount owing including paypal fees
* @param $include_fees - boolean to indicate whether we want the net amount or the amount owing including paypal fees
* @return amount owing as a decimal value
*/
function _booking_amount_owing($person, $amount_paid = 0, $include_paypal_fees = TRUE)
{
//$amount_paid = 0;
//$total_due = 0;
//fetch details about the person
/*
$person = db_query("SELECT price.booking_price, price.booking_late_price, person.booking_payment_id, " .
"person.booking_total_pay_reqd, person.booking_amount_paid, person.booking_partner_id, person.booking_country, person.booking_welfare_required, person.booking_committee_member " .
"FROM {booking_person} person, {booking_price} price " .
"WHERE person.nid = :nid " .
"AND person.booking_payment_id = price.pid",
array(':nid' => $nid))
->fetchObject();
//$person = node_load($nid);
*/
function _booking_amount_owing($person, $amount_paid = 0, $include_fees = TRUE) {
global $event;
//quick sanity check
if (! $person->nid) {
watchdog('booking', "Unable to find matching person relating to registration id. Details were '" . var_export($person, TRUE) . "' .");
@@ -1050,43 +1029,80 @@ function _booking_amount_owing($person, $amount_paid = 0, $include_paypal_fees =
$total_due = _booking_total_due($person);
//if we didn't get the amount paid as a command line parameter, check it now
if ($amount_paid == 0)
{
if ($amount_paid == 0) {
$amount_paid = _booking_amount_paid($person->nid, $person);
}
//check if there is anything outstanding
//use the original total amount required rather than the late-rate, to cater for people that paid before the late rate
if ($amount_paid >= $person->booking_total_pay_reqd)
{
if ($amount_paid >= $person->booking_total_pay_reqd) {
//watchdog('booking', "This person doesn't owe any money: @info", array('@info' => var_export($person, TRUE)));
return 0;
}
//@todo - use booking_payment_processor instead. 0 is paypal, 1 is stripe, 2 is manual
//if we're using paypal, add the transaction fee
if (variable_get('booking_use_paypal', 0) == 1 && $include_paypal_fees == TRUE)
{
if (variable_get('booking_use_paypal', 0) == 1 && $include_fees == TRUE) {
$amount_owing = _booking_add_paypal_fees($total_due - $amount_paid, $person->booking_country);
/*
//add the 30 cent fixed cost
$amount_owing = $total_due - $amount_paid + 0.3;
//and the 2.4 percent transaction fee
if ($person->booking_country === "Australia")
$amount_owing = $amount_owing / (1 - 0.026);
//paypal charges 3.4 percent if they're doing a currency conversion
//assume that everyone not based in Australia will be doing a currency conversion
else
{
$amount_owing = $amount_owing / (1 - 0.036);
//watchdog('booking', "This is an international registration.");
}
*/
}
else
else {
$amount_owing = $total_due - $amount_paid;
}
return number_format($amount_owing, 2, '.', '');
}
/**
* Function to update the person object when a payment has been made
* payment details should be inserted into booking_payment prior to calling this function
*
* @param $person - the populated node object representing this person including related price information
* @param $payment_amount - the gross payment amount that is being processed
* @param $balance_payment - boolean to indicate if this transaction was to complete a payment
* @return nothing
*/
function _booking_process_payment($person, $payment_amount, $balance_payment) {
global $event;
//calculate their total payment amount
$total = $person->booking_amount_paid + $payment_amount;
//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;
}
//update the database for this person
db_update('booking_person')
->fields(array(
'booking_amount_paid' => $total,
'booking_status' => $status,
))
->condition('nid', $nid)
->execute();
//handle workflow emails and spouse payment updates
_booking_postpayment_trigger($nid, $person, $balance_payment);
}
/**
* Function to handle any post-payment notification emails for either paypal or manual payment
* still a WIP

View File

@@ -605,6 +605,16 @@ function booking_update_7239() {
_booking_node_create_mysqlview();
}
/**
* Add stripe token field to booking_payments table
*/
function booking_update_7240() {
$spec = array('type' => 'varchar', 'length' => '200', 'not null' => FALSE);
db_add_field('booking_payment', 'booking_stripe_token', $spec);
//update the view to match the new table definition
_booking_node_create_mysqlview();
}
/**
* Implementation of hook_install().
*/
@@ -624,8 +634,8 @@ function booking_install() {
//earlybird close is 31st Jan 2012 at 13:59:59 UTC
$result = db_insert('booking_event')
->fields(array(
'booking_eventname' => 'Sample Event',
'booking_event_active' => 1,
'booking_eventname' => 'Sample Event',
'booking_event_active' => 1,
'booking_register_open' => 1312207199,
'booking_register_close' => 1340459999,
'booking_earlybird_close' => 1328018399,

View File

@@ -91,7 +91,7 @@ function booking_paypal_ipn() {
}
*/
//TODO: Handle refund and payment dispute IPNs
//@todo Handle refund and payment dispute IPNs
if (empty($ipn['payment_status']) || ($ipn['payment_status'] != 'Completed' && variable_get('booking_paypal_sandbox', 0) == 0))
return;
@@ -131,8 +131,7 @@ function _booking_process_payment($data) {
//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();
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;
@@ -166,45 +165,9 @@ function _booking_process_payment($data) {
//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;
}
//update the database for this person
db_update('booking_person')
->fields(array(
'booking_amount_paid' => $total,
'booking_status' => $status,
))
->condition('nid', $nid)
->execute();
//handle workflow emails and spouse payment updates
_booking_postpayment_trigger($nid, $person, $balance_payment);
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_payment($person, $data['mc_gross'], $balance_payment);
}
else {
//couldn't find a matching nid for this invoice
@@ -216,8 +179,7 @@ function _booking_process_payment($data) {
/**
* Landing page after returning from paypal
*/
function booking_payment_completed_page()
{
function booking_payment_completed_page() {
//get some configuration information
global $event;
$output = "";

View File

@@ -4,6 +4,7 @@
* @file
* Functions for stripe payment integration
* @see https://github.com/ericthelast/drupal-stripe-form and https://www.webomelette.com/drupal-stripe-integration
* Australian test number is 4000000360000006
*/
/**
@@ -43,9 +44,6 @@ function booking_stripe_form($node, &$form_state, $person, $invoiceid, $amount_o
$settings = array();
$form = array();
//get our current path so we can send the user back here if they cancel
//$path = isset($_GET['q']) ? $_GET['q'] : '<front>';
//set some values for our internal stripe library to help process the form
//these will be used by the attached js from booking-strip library to identify which parts of the form to process
@@ -116,116 +114,6 @@ function booking_stripe_form($node, &$form_state, $person, $invoiceid, $amount_o
return $form;
}
/*
function booking_stripe_form($form, &$form_state, $person, $invoiceid, $amount_owing, $button_text) {
global $event;
$setting = array();
$form = array();
// Try to load the library and check if that worked.
if (($library = libraries_load('stripe')) && !empty($library['loaded'])) {
// Do something with the library here.
}
else {
//library can be downloaded from https://stripe.com/docs/libraries
form_set_error('form', t('The required stripe library is not installed. Please contact your site adaministrator'));
}
//set some values for our internal stripe library to help process the form
//these will be used by the attached js from booking-strip library to identify which parts of the form to process
$setting['booking_stripeform'] = array(
'pubkey' => _booking_get_stripe_public_key(),
'form_selector' => str_replace('_', '-', __FUNCTION__),
);
$form['#attached'] = array(
'js' => array(
array('data' => $setting, 'type' => 'setting'),
),
'library' => array(
array('booking', 'booking-stripe'),
),
);
$form['stripeToken'] = array(
'#type' => 'hidden',
'#value' => !empty($form_state['input']['stripeToken']) ? $form_state['input']['stripeToken'] : NULL,
);
$form['amount'] = array(
'#type' => 'hidden',
'#value' => $amount_owing,
);
$form['credit_card'] = array(
'#type' => 'fieldset',
'#title' => t('Credit Card Information'),
'#description' => t('<p>This credit card information is securely processed via <a href="https://stripe.com">stripe.com</a>. No credit card information is stored or processed on our server.</p>');
);
$cc = &$form['credit_card'];
$cc['card_number'] = array(
'#type' => 'textfield',
'#title' => t('Credit Card Number'),
'#pre_render' => array('booking_stripeform_remove_name'),
'#attributes' => array(
'size' => 20,
'data-stripe' => 'number',
),
);
$cc['exp_month'] = array(
'#type' => 'select',
'#title' => t('Expiration Month'),
'#options' => drupal_map_assoc(array(1,2,3,4,5,6,7,8,9,10,11,12)),
'#pre_render' => array('booking_stripeform_remove_name'),
'#attributes' => array(
'data-stripe' => 'exp-month',
),
'#empty_option' => t('- Select -'),
);
$cc['exp_year'] = array(
'#type' => 'select',
'#title' => t('Expiration Year'),
'#options' => array(),
'#pre_render' => array('booking_stripeform_remove_name'),
'#attributes' => array(
'data-stripe' => 'exp-year',
),
'#empty_option' => t('- Select -'),
);
$year = date('Y');
for($i = $year; $i <= ($year + 10); $i++) {
$cc['exp_year']['#options'][$i] = $i;
}
$cc['cvc'] = array(
'#type' => 'textfield',
'#title' => t('CVC Number'),
'#pre_render' => array('booking_stripeform_remove_name'),
'#attributes' => array(
'size' => 4,
'data-stripe' => 'cvc',
),
);
$cc['submit'] = array(
'#type' => 'submit',
'#value' => t('Charge It'),
'#attributes' => array(
'class' => array('btn', 'btn-large', 'btn-primary'),
),
);
// Adds our validation at the end of the build process.
$form['#after_build'][] = 'booking_stripe_add_final_validation';
return $form;
}
*/
/**
* Tries to add final validation after all else has been added through alters.
*/
@@ -267,6 +155,8 @@ function booking_stripe_validate_form_payment($form, &$form_state) {
$invoice = (isset($form_state['input']['invoice']) ? $form_state['input']['invoice'] : '');
$nid = (isset($form_state['input']['nid']) ? $form_state['input']['nid'] : '');
$tempid= (isset($form_state['input']['uuid']) ? $form_state['input']['uuid'] : '');
$last_name = (isset($form_state['input']['last_name']) ? $form_state['input']['last_name'] : '');
$first_name = (isset($form_state['input']['first_name']) ? $form_state['input']['first_name'] : '');
watchdog('booking_debug', "<pre>Stripe payment form :\n@info</pre>", array('@info' => print_r( $form_state, true)));
// Create the charge on Stripe's servers - this will charge the user's card
@@ -282,12 +172,15 @@ function booking_stripe_validate_form_payment($form, &$form_state) {
"metadata" => array(
"invoice" => $invoice,
"nid" => $nid,
"last_name" => $last_name,
"first_name" => $first_name,
),
));
watchdog('booking_debug', "<pre>Stripe payment charge results:\n@info</pre>", array('@info' => print_r( $charge, true)));
if ($charge && $charge->paid) {
watchdog('booking', 'Charge created successfully');
$form_state['stripeform_charge'] = $charge;
_booking_process_stripe_payment($charge);
//$form_state['stripeform_charge'] = $charge;
// @todo call _booking_process_stripe_payment to store payment
drupal_goto('bookingfinal/' . $tempid);
}
@@ -327,4 +220,89 @@ function booking_stripeform_form_submit($form, &$form_state) {
function booking_stripeform_remove_name($element) {
unset($element['#name']);
return $element;
}
function _booking_process_stripe_payment($charge) {
global $event;
$balance_payment = false;
$amount_owing = 0;
//$invoice = $data->metadata;
//verify the status of the charge
if (empty($charge->status) || ($charge->status != 'succeeded')) {
$successful = FALSE;
}
else {
$successful = TRUE;
}
//extract the person node id from the invoice
$pos = strpos($charge->metadata->invoice, "_");
if (($pos === false) || ($pos == 0)) {
watchdog('booking', 'Unable to process payment with invalid invoice information: !id', array('!id' => $charge->metadata->invoice), WATCHDOG_ERROR);
return;
}
//get the part of the invoice up to the first underscore
$nid = substr($charge->metadata->invoice, 0, $pos);
//get the data between the first and second underscore
$eid = substr($charge->metadata->invoice, $pos + 1, strrpos($charge->metadata->invoice, "_") - $pos - 1);
if (substr($eid,0,3) == "bal") {
$balance_payment = true;
watchdog('booking_debug', 'Balance payment via stripe for user with node id: !id and status !status.',
array('!id' => $nid, '!status' => $charge->status));
}
else {
watchdog('booking_debug', 'Initial payment via stripe for user with node id: !id and status !status.',
array('!id' => $nid, '!status' => $charge->status));
}
//this shouldn't ever happen, since stripe is sending this notification synchronously
//but just in case, check for an existing transaction that matches this one
$duplicate_check = db_query("SELECT payid, booking_person_nid FROM {booking_payment} where booking_ipn_track_id = :ipn_id ",
array(':ipn_id' => $charge->id))->fetchObject();
if ($duplicate_check) {
watchdog('booking', 'Detected duplicate stripe transaction notifications for transaction id !id, registration id !nid',
array('!id' => $charge->id, '!nid' => $nid), WATCHDOG_ERROR);
return;
}
$gross_amount = $charge->amount / 100;
$result = db_insert('booking_payment')
->fields(array(
'booking_person_nid' => $nid,
'booking_eventid' => $event->eid,
'booking_mc_gross' => $gross_amount,
'booking_mc_currency' => $charge->balance_transaction->currency,
'booking_mc_fee' => $charge->balance_transaction->fee / 100,
'booking_invoice' => $charge->metadata->invoice,
'booking_payer_id' => $charge->source->id,
'booking_payment_date' => $charge->created,
'booking_payment_status' => $charge->status,
'booking_first_name' => $charge->metadata->first_name,
'booking_last_name' => $charge->metadata->last_name,
'booking_buyer_email' => $charge->receipt_email,
//'booking_payer_status' => $data['payer_status'],
'booking_item_name' => $data->description,
'booking_ipn_track_id' => $data->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_payment($person, $gross_amount, $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);
}
}

View File

@@ -27,6 +27,7 @@ jQuery(document).ready(function($) {
email: currentForm.find('input[name="email"]').val(),
currency: "aud",
amount: currentForm.find('input[name="amount"]').val() * 100,
zipCode: true,
closed: function() {
//document.getElementById("booking_stripe_form").submit();
}