331 lines
12 KiB
PHP
331 lines
12 KiB
PHP
<?php
|
|
|
|
/**
|
|
* @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
|
|
*/
|
|
|
|
/**
|
|
* Get the current stripe api public key
|
|
*/
|
|
function _booking_get_stripe_public_key() {
|
|
if (variable_get('booking_stripe_testmode', 0) == 1) {
|
|
return variable_get('booking_stripe_test_public_key', '');
|
|
}
|
|
else {
|
|
return variable_get('booking_stripe_live_public_key', '');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the current stripe api private key
|
|
*/
|
|
function _booking_get_stripe_private_key() {
|
|
if (variable_get('booking_stripe_testmode', 0) == 1) {
|
|
return variable_get('booking_stripe_test_secret_key', '');
|
|
}
|
|
else {
|
|
return variable_get('booking_stripe_live_secret_key', '');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Helper function to calculate stripe transaction fees
|
|
*/
|
|
function _booking_add_stripe_fees($amount, $country) {
|
|
//add the 30 cent fixed cost
|
|
$result = '0.00';
|
|
$result = (float) ($amount + (float) variable_get('booking_stripe_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_stripe_transaction_fee_percentage', '1.75');
|
|
} else {
|
|
$percentage = (float) variable_get('booking_stripe_transaction_fee_percentage_intl', '2.9');
|
|
}
|
|
|
|
//apply the percentage
|
|
$percentage = (float) $percentage / 100;
|
|
$result = $result / (1 - $percentage);
|
|
|
|
//return result
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Helper function to generate paypal form for payments
|
|
*/
|
|
function _booking_stripe_form($person, $invoiceid, $net_amount_owing, $button_text) {
|
|
$payment_form = drupal_get_form('booking_stripe_form', $person, $invoiceid, $net_amount_owing, $button_text);
|
|
return drupal_render($payment_form);
|
|
}
|
|
|
|
function booking_stripe_form($node, &$form_state, $person, $invoiceid, $net_amount_owing, $button_text) {
|
|
global $event;
|
|
$settings = array();
|
|
$form = array();
|
|
|
|
//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_stripe'] = array(
|
|
'pubkey' => _booking_get_stripe_public_key(),
|
|
'form_selector' => str_replace('_', '-', __FUNCTION__),
|
|
'name' => $event->booking_eventname,
|
|
'image' => variable_get('booking_stripe_logo', ''),
|
|
'payment_button_label' => '{{amount}} (plus fees)',
|
|
);
|
|
|
|
//attach settings and javascript to the form
|
|
$form['#attached'] = array(
|
|
'js' => array(
|
|
array('data' => $setting, 'type' => 'setting'),
|
|
),
|
|
'library' => array(
|
|
array('booking', 'booking-stripe'),
|
|
),
|
|
);
|
|
|
|
//paypal specific settings
|
|
$vars = array(
|
|
'nid' => $person->nid,
|
|
'email' => $person->booking_email,
|
|
'description' => $event->booking_eventname . ' ' . $person->booking_price_descrip,
|
|
'invoice' => $invoiceid,
|
|
'amount' => $net_amount_owing,
|
|
'gross_amount' => number_format(_booking_add_stripe_fees($net_amount_owing, $person->booking_country), 2, '.', ''),
|
|
'foreign_gross_amount' => number_format(_booking_add_stripe_fees($net_amount_owing, 'FakeCountry'), 2, '.', ''),
|
|
'last_name' => $person->booking_lastname,
|
|
'first_name' => $person->booking_firstname,
|
|
'uuid' => $person->booking_tempid,
|
|
'token_id' => '',
|
|
'token_email' => '',
|
|
'token_client_ip' => '',
|
|
'card_brand' => '',
|
|
'card_cvc_check' => '',
|
|
'card_address_zip_check' => '',
|
|
);
|
|
|
|
//turn the array into a form
|
|
foreach($vars as $name => $value) {
|
|
$form[$name] = array(
|
|
'#type' => 'hidden',
|
|
'#value' => $value,
|
|
);
|
|
};
|
|
|
|
$form['submit'] = array(
|
|
'#id' => 'stripe-submit',
|
|
'#type' => 'button',
|
|
'#value' => t($button_text),
|
|
);
|
|
$form['#after_build'][] = 'booking_stripe_add_final_validation';
|
|
|
|
//watchdog('booking', 'Booking Balance payment: @info', array ('@info' => var_export($form, TRUE)));
|
|
return $form;
|
|
}
|
|
|
|
/**
|
|
* Tries to add final validation after all else has been added through alters.
|
|
*/
|
|
function booking_stripe_add_final_validation($form) {
|
|
$form['#validate'][] = 'booking_stripe_validate_form_payment';
|
|
return $form;
|
|
}
|
|
|
|
/**
|
|
* Form validation callback.
|
|
*/
|
|
function booking_stripe_checkout_form_validate($form, &$form_state) {
|
|
// Validate normal form elements as needed.
|
|
}
|
|
|
|
/**
|
|
* Processes the stripe payment.
|
|
*
|
|
* We do this here so that if the payment fails,
|
|
* we're still in a validation stage and can return
|
|
* early. If success, we'll pass the charge on
|
|
* to the submission callback.
|
|
*/
|
|
function booking_stripe_validate_form_payment($form, &$form_state) {
|
|
global $event;
|
|
|
|
if($errors = form_get_errors()) {
|
|
//@todo log an error via watchdog
|
|
return;
|
|
}
|
|
|
|
$path = libraries_get_path('stripe');
|
|
require_once($path . '/init.php');
|
|
\Stripe\Stripe::setApiKey(_booking_get_stripe_private_key());
|
|
|
|
//get values from original form
|
|
$token = (isset($form_state['input']['token_id']) ? $form_state['input']['token_id'] : '');
|
|
$amount = (isset($form_state['input']['gross_amount']) ? $form_state['input']['gross_amount'] : '');
|
|
$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 token:\n@info</pre>", array('@info' => print_r( $token, true)));
|
|
|
|
//if card type is american express then the rate charged should be different
|
|
$card_type = (isset($form_state['input']['card_brand']) ? $form_state['input']['card_brand'] : '');
|
|
if ($card_type == 'American Express') {
|
|
//amount charged should be the international rate not the domestic rate
|
|
//@todo verify that nid is correct format
|
|
//@todo debug log to indicate price change
|
|
$person = node_load($nid);
|
|
$amount = (isset($form_state['input']['foreign_gross_amount']) ? $form_state['input']['foreign_gross_amount'] : $amount);
|
|
}
|
|
|
|
// Create the charge on Stripe's servers - this will charge the user's card
|
|
try {
|
|
$charge = \Stripe\Charge::create(array(
|
|
"amount" => $amount * 100,
|
|
"currency" => "aud",
|
|
"card" => $token,
|
|
"statement_descriptor" => substr($event->booking_eventname, 0, 21), //this field is limited to 22 characters
|
|
"expand" => array('balance_transaction'),
|
|
"description" => $form_state['input']['description'],
|
|
"receipt_email" => $form_state['input']['email'],
|
|
"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');
|
|
_booking_process_stripe_payment($charge, $token);
|
|
//$form_state['stripeform_charge'] = $charge;
|
|
// @todo call _booking_process_stripe_payment to store payment
|
|
drupal_goto('bookingfinal/' . $tempid);
|
|
}
|
|
else {
|
|
watchdog('booking', 'Charge was not created successfully');
|
|
drupal_set_message('Card does not seem to have been charged successfully. Please try again', 'error');
|
|
}
|
|
}
|
|
catch(\Stripe\Error\Card $e) {
|
|
$e_json = $e->getJsonBody();
|
|
$error = $e_json['error'];
|
|
watchdog('booking', $e->getMessage());
|
|
drupal_set_message($error['message'], 'error');
|
|
}
|
|
catch (\Stripe\Error\ApiConnection $e) {
|
|
watchdog('booking', $e->getMessage());
|
|
drupal_set_message($error['message'], 'error');
|
|
}
|
|
catch (\Stripe\Error\Api $e) {
|
|
watchdog('booking', $e->getMessage());
|
|
drupal_set_message($error['message'], 'error');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Form submission handler.
|
|
*/
|
|
function booking_stripeform_form_submit($form, &$form_state) {
|
|
drupal_set_message('Charge successful!');
|
|
}
|
|
|
|
/**
|
|
* FAPI #pre_render callback.
|
|
*
|
|
* Removes the name field form a form element.
|
|
*/
|
|
function booking_stripeform_remove_name($element) {
|
|
unset($element['#name']);
|
|
return $element;
|
|
}
|
|
|
|
|
|
function _booking_process_stripe_payment($charge, $token) {
|
|
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' => $charge->description,
|
|
'booking_ipn_track_id' => $charge->id,
|
|
'booking_stripe_token' => $token,
|
|
))
|
|
->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, $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);
|
|
}
|
|
} |