Skip to content
Snippets Groups Projects
Commit 26f94f67 authored by mattwire's avatar mattwire Committed by mattwire
Browse files

Code cleanup

parent 1137a756
Branches
Tags
No related merge requests found
<?php
/*
* Form Class for Stripe
*/
class CRM_Core_Form_Stripe extends CRM_Core_Form {
/**
* Function to access protected payProcessors array in event registraion forms
*/
public static function get_ppids(&$form) {
$payprocessorIds = $form->_paymentProcessors;
return $payprocessorIds;
}
}
......@@ -208,7 +208,7 @@ class CRM_Core_Payment_Stripe extends CRM_Core_Payment {
* @param $form - reference to the form object
*/
public function buildForm(&$form) {
$stripe_ppid = self::get_stripe_ppid($form);
$stripe_ppid = CRM_Utils_Array::value('id', $form->_paymentProcessor);
// Add the ID to our form so our js can tell if Stripe has been selected.
$form->addElement('hidden', 'stripe_id', $stripe_ppid, array('id' => 'stripe-id'));
......@@ -221,59 +221,19 @@ class CRM_Core_Payment_Stripe extends CRM_Core_Payment {
if (!empty($params[0]['stripe_token'])) {
$params = $params[0];
}
$stripe_token = (empty($params['stripe_token']) ? NULL : $params['stripe_token']);
$stripeToken = (empty($params['stripetoken']) ? NULL : $params['stripetoken']);
// Add some hidden fields for Stripe.
if (!$form->elementExists('stripe_token')) {
$form->setAttribute('class', $form->getAttribute('class') . ' stripe-payment-form');
$form->addElement('hidden', 'stripe_token', $stripe_token, array('id' => 'stripe-token'));
if (!empty($stripeToken) && !$form->elementExists('stripetoken')) {
$form->addElement('hidden', 'stripetoken', $stripeToken, array('id' => 'stripe-token'));
}
// Add the Civi version so we can accommodate different versions in civicrm_stripe.js.
if (self::get_civi_version() <= '4.7.0') {
$ext_mode = 1;
}
else {
$ext_mode = 2;
}
$form->addElement('hidden', 'ext_mode', $ext_mode, array('id' => 'ext-mode'));
// Add email field as it would usually be found on donation forms.
if (!isset($form->_elementIndex['email']) && !empty($form->userEmail)) {
$form->addElement('hidden', 'email', $form->userEmail, array('id' => 'user-email'));
}
}
public static function get_stripe_ppid($form) {
if (empty($form->_paymentProcessor)) {
return;
}
// When called from admin backend (eg via CRM_Contribute_Form_Contribution, CRM_Member_Form_Membership)
// the isBackOffice flag will be set to true.
// But if called via webform in CiviCRM 4.7: isBackOffice=NULL and for is of class CRM_Financial_Form_Payment or CRM_Contribute_Form_Contribution
// Those don't have a _paymentProcessors array and only have one payprocesssor.
if (!empty($form->isBackOffice)
|| (in_array(get_class($form), array('CRM_Financial_Form_Payment', 'CRM_Contribute_Form_Contribution')))) {
return $stripe_ppid = $form->_paymentProcessor['id'];
}
else {
// Find a Stripe pay processor ascociated with this Civi form and find the ID.
// $payProcessors = $form->_paymentProcessors;
$payProcessors = CRM_Core_Form_Stripe::get_ppids($form);
foreach ($payProcessors as $payProcessor) {
if ($payProcessor['class_name'] == 'Payment_Stripe') {
return $stripe_ppid = $payProcessor['id'];
break;
}
}
}
// None of the payprocessors are Stripe.
if (empty($stripe_ppid)) {
return;
}
}
/**
* Given a payment processor id, return the pub key.
*/
......@@ -342,8 +302,9 @@ class CRM_Core_Payment_Stripe extends CRM_Core_Payment {
$amount = (int) preg_replace('/[^\d]/', '', strval($amount));
// Use Stripe.js instead of raw card details.
if (!empty($params['stripe_token'])) {
$card_details = $params['stripe_token'];
if (!empty($params['credit_card_number']) && (substr($params['credit_card_number'], 0, 4) === 'tok_')) {
$card_details = $params['credit_card_number'];
$params['credit_card_number'] = '';
}
else {
CRM_Core_Error::fatal(ts('Stripe.js token was not passed! Report this message to the site administrator.'));
......@@ -816,4 +777,21 @@ class CRM_Core_Payment_Stripe extends CRM_Core_Payment {
public function doTransferCheckout(&$params, $component) {
CRM_Core_Error::fatal(ts('Use direct billing instead of Transfer method.'));
}
/**
* Default payment instrument validation.
*
* Implement the usual Luhn algorithm via a static function in the CRM_Core_Payment_Form if it's a credit card
* Not a static function, because I need to check for payment_type.
*
* @param array $values
* @param array $errors
*/
public function validatePaymentInstrument($values, &$errors) {
CRM_Core_Form::validateMandatoryFields($this->getMandatoryFields(), $values, $errors);
if ($this->_paymentProcessor['payment_type'] == 1) {
// Don't validate credit card details as they are not passed (and stripe does this for us)
//CRM_Core_Payment_Form::validateCreditCard($values, $errors, $this->_paymentProcessor['id']);
}
}
}
......@@ -66,3 +66,11 @@ OTHER CREDITS
-------------
For bug fixes, new features, and documentiation, thanks to:
rgburton, Swingline0, BorislavZlatanov, agh1, & jmcclelland
TESTING
--------
1. Test webform submission with payment and user-select, single processor.
2. Test online contribution page with single processor, multi-processor (stripe default, stripe non-default).
3. Test offline contribution page with single processor, multi-processor (stripe default, stripe non-default).
4. Test event registration.
5. Test event registration (cart checkout).
......@@ -24,68 +24,73 @@
+ '</div>');
$submit.removeAttr('disabled').attr('value', buttonText);
}
else {
var token = response['id'];
// Update form with the token & submit.
$form.find("input#stripe-token").val(token);
$form.find("input#credit_card_number").removeAttr('name');
$form.find("input#cvv2").removeAttr('name');
$submit.prop('disabled', false);
removeCCDetails($form);
// We use the credit_card_number field to pass token as this is reliable.
// Inserting an input field is unreliable on ajax forms and often gets missed from POST request for some reason.
$form.find("input#credit_card_number").val(token);
// Disable unload event handler
window.onbeforeunload = null;
// This triggers submit without generating a submit event (so we don't run submit handler again)
$form.get(0).submit();
}
}
// Prepare the form.
$(document).ready(function() {
Stripe.setPublishableKey($('#stripe-pub-key').val());
loadStripeBillingBlock();
});
CRM.$('input[name="payment_processor_id"]').change(function() {
// On the frontend, we have a set of radio buttons. Trigger on change.
$('input[name="payment_processor_id"]').change(function() {
loadStripeBillingBlock();
});
// On the backend, we have a select. Trigger on change.
$('select#payment_processor_id').change(function() {
loadStripeBillingBlock();
});
function loadStripeBillingBlock() {
// Check for form marked as a stripe-payment-form by the server.
if (!($('form.stripe-payment-form').length)) {
// If there isn't one look for it.
if ($('.webform-client-form').length) {
isWebform = true;
$('form.webform-client-form').addClass('stripe-payment-form');
}
else if ($('#crm-container form').length) {
$('#crm-container form').addClass('stripe-payment-form');
}
else {
return;
var $stripePubKey = $('#stripe-pub-key');
if ($stripePubKey.length) {
if (!$().Stripe) {
$.getScript('https://js.stripe.com/v2/', function () {
Stripe.setPublishableKey($('#stripe-pub-key').val());
});
}
}
$form = $('form.stripe-payment-form');
if ($('.webform-client-form').length) {
isWebform = true;
}
// Get the form containing payment details
$form = CRM.$('input#stripe-pub-key').closest('form');
if (isWebform) {
$submit = $form.find('.button-primary');
}
else {
$submit = $form.find('input[type="submit"][formnovalidate!="1"]');
// If CiviDiscount button or field is submitted, flag the form.
$form.data('cividiscount-dont-handle', '0');
// This is an ugly hack. Really, the code should positively identify the
// "real" submit button(s) and only respond to them. Otherwise, we're
// chasing down a potentially endless number of exceptions. The problem
// is that it's unclear if CiviCRM consistently names its submit buttons.
// If another submit button on the form is pressed (eg. apply discount)
// add a flag that we can set to stop payment submission
$form.data('submit-dont-process', '0');
// Find submit buttons with formnovalidate=1 and add an onclick handler to set flag
$form.find('input[type="submit"][formnovalidate="1"], input[type="submit"].cancel').click( function() {
$form.data('cividiscount-dont-handle', 1);
$form.data('submit-dont-process', 1);
});
// Add a keypress handler to set flag if enter is pressed
$form.find('input#discountcode').keypress( function(e) {
if (e.which == 13) {
$form.data('cividiscount-dont-handle', 1);
if (e.which === 13) {
$form.data('submit-dont-process', 1);
}
});
$submit;
}
// For CiviCRM Webforms.
......@@ -94,9 +99,10 @@
$form.append('<input type="hidden" name="op" id="action" />');
}
$(document).keypress(function(event) {
if (event.which == 13) {
if (event.which === 13) {
// Enter was pressed
event.preventDefault();
$submit.click();
submit(event);
}
});
$(":submit").click(function() {
......@@ -108,49 +114,62 @@
var webformPrevious = $('input.webform-previous').first().val();
}
else {
// This is native civicrm form - check for existing token.
if ($form.find("input#stripe-token").val()) {
// CiviCRM form
// If we already have a token hide CC details
if ($form.find("input#credit_card_number").val()) {
$('.credit_card_info-group').hide();
$('#billing-payment-block').append('<input type="button" value="Edit CC details" id="ccButton" />');
$('#ccButton').click(function() {
// Clear token and show CC details if edit button was clicked
// As we use credit_card_number to pass token, make sure it is empty when shown
$form.find("input#credit_card_number").val('');
$('.credit_card_info-group').show();
$('#ccButton').hide();
$form.find('input#stripe-token').val('');
});
}
else {
// As we use credit_card_number to pass token, make sure it is empty when shown
$form.find("input#credit_card_number").val('');
}
}
$submit.removeAttr('onclick');
$form.unbind('submit');
// Intercept form submission.
$form.submit(function (event) {
event.preventDefault();
submit(event);
});
function submit(event) {
// Don't handle submits generated by non-stripe processors
if (!$('input#stripe-pub-key').length) {
debugging('submit missing stripe-pub-key element');
return true;
}
// Don't handle submits generated by the CiviDiscount button.
if ($form.data('cividiscount-dont-handle') == 1) {
if ($form.data('submit-dont-process') === 1) {
debugging('debug: pvjwy (Discount is in play)');
return true;
}
if (isWebform) {
var $processorFields = $('.civicrm-enabled[name$="civicrm_1_contribution_1_contribution_payment_processor_id]"]');
if ($('#action').attr('value') == webformPrevious) {
debugging('wmlfp');
if ($('#action').attr('value') === webformPrevious) {
// Don't submit if the webform back button was pressed
debugging('webform back button');
return true;
}
if ($('#wf-crm-billing-total').length) {
if ($('#wf-crm-billing-total').data('data-amount') == '0') {
debugging('qplfr');
if ($('#wf-crm-billing-total').data('data-amount') === '0') {
debugging('webform total is 0');
return true;
}
}
if ($processorFields.length) {
if ($processorFields.filter(':checked').val() == '0') {
debugging('evxyh');
return true;
}
if (!($form.find('input[name="stripe_token"]').length)) {
debugging('irjfg');
if ($processorFields.filter(':checked').val() === '0') {
debugging('no payment processor selected');
return true;
}
}
......@@ -159,68 +178,39 @@
buttonText = $submit.attr('value');
$submit.prop('disabled', true).attr('value', 'Processing');
// Hide payment if total is 0 and no more participants.
if ($('#priceset').length) {
additionalParticipants = cj("#additional_participants").val();
// The currentTotal is already being calculated in Form/Contribution/Main.tpl.
if(typeof currentTotal !== 'undefined') {
if (currentTotal == 0 && !additionalParticipants) {
// This is also hit when "Going back", but we already have stripe_token.
debugging('ozlkf');
// This should not happen on Confirm Contribution, but seems to on 4.6 for some reason.
//return true;
}
}
}
// Handle multiple payment options and Stripe not being chosen.
if ($form.find(".crm-section.payment_processor-section").length > 0) {
var extMode = $('#ext-mode').val();
var stripeProcessorId = $('#stripe-id').val();
// Support for CiviCRM 4.6 and 4.7 multiple payment options
if (extMode == 1) {
var chosenProcessorId = $form.find('input[name="payment_processor"]:checked').val();
}
else if (extMode == 2) {
var chosenProcessorId = $form.find('input[name="payment_processor_id"]:checked').val();
}
var chosenProcessorId = $form.find('input[name="payment_processor_id"]:checked').val();
// Bail if we're not using Stripe or are using pay later (option value '0' in payment_processor radio group).
if ((chosenProcessorId != stripeProcessorId) || (chosenProcessorId == 0)) {
debugging('debug: kfoej (Not a Stripe transaction, or pay-later)');
if ((chosenProcessorId !== stripeProcessorId) || (chosenProcessorId === 0)) {
debugging('debug: Not a Stripe transaction, or pay-later');
return true;
}
}
else {
debugging('debug: qlmvy (Stripe is the only payprocessor here)');
debugging('debug: Stripe is the selected payprocessor');
}
// Handle reuse of existing token
if ($form.find("input#stripe-token").val()) {
$form.find("input#credit_card_number").removeAttr('name');
$form.find("input#cvv2").removeAttr('name');
debugging('debug: zpqef (Re-using Stripe token)');
if ($form.find("input#credit_card_number").val()) {
removeCCDetails($form);
debugging('debug: Re-using Stripe token');
return true;
}
// If there's no credit card field, no use in continuing (probably wrong
// context anyway)
if (!$form.find('#credit_card_number').length) {
debugging('debug: gvzod (No credit card field)');
debugging('debug: No credit card field');
return true;
}
event.preventDefault();
event.stopPropagation();
var cc_month = $form.find('#credit_card_exp_date_M').val();
var cc_year = $form.find('#credit_card_exp_date_Y').val();
// Handle changes introduced in CiviCRM 4.3.
if ($form.find('#credit_card_exp_date_M').length > 0) {
var cc_month = $form.find('#credit_card_exp_date_M').val();
var cc_year = $form.find('#credit_card_exp_date_Y').val();
}
else {
var cc_month = $form.find('#credit_card_exp_date\\[M\\]').val();
var cc_year = $form.find('#credit_card_exp_date\\[Y\\]').val();
}
Stripe.card.createToken({
name: $form.find('#billing_first_name').val() + ' ' + $form.find('#billing_last_name').val(),
address_zip: $form.find('#billing_postal_code-5').val(),
......@@ -230,14 +220,20 @@
exp_year: cc_year
}, stripeResponseHandler);
debugging('debug: ywkvh (Getting Stripe token)');
debugging('debug: Getting Stripe token');
return false;
});
}
}
}(cj, CRM));
function removeCCDetails($form) {
// Remove the "name" attribute so params are not submitted
$form.find("input#credit_card_number").val('0000000000000000');
$form.find("input#cvv2").val('000');
}
function debugging (errorCode) {
// Uncomment the following to debug unexpected returns.
// console.log(errorCode);
console.log(errorCode);
}
......@@ -3,6 +3,8 @@
require_once 'stripe.civix.php';
require_once __DIR__.'/vendor/autoload.php';
use CRM_Stripe_ExtensionUtil as E;
/**
* Implementation of hook_civicrm_config().
*/
......@@ -194,7 +196,7 @@ function stripe_civicrm_managed(&$entities) {
* @return void
*/
function stripe_civicrm_alterContent( &$content, $context, $tplName, &$object ) {
if($context == 'form' && !empty($object->_paymentProcessor['class_name'])) {
if ($context == 'form' && !empty($object->_paymentProcessor['class_name'])) {
$stripeJSURL = CRM_Core_Resources::singleton()->getUrl('com.drastikbydesign.stripe', 'js/civicrm_stripe.js');
$content .= "<script src='{$stripeJSURL}'></script>";
}
......@@ -207,9 +209,9 @@ function stripe_civicrm_managed(&$entities) {
*/
function stripe_civicrm_buildForm($formName, &$form) {
if (!empty($form->_paymentProcessor['class_name'])) {
CRM_Core_Resources::singleton()->addScriptUrl('https://js.stripe.com/v2/');
//CRM_Core_Resources::singleton()->addScriptUrl('https://js.stripe.com/v2/', 10, 'page-body');
}
if (($formName == 'CRM_Member_Form_MembershipRenewal') && !empty($form->_paymentProcessor['class_name'])) {
if (/*$form->isBackOffice &&*/ !empty($form->_paymentProcessor['class_name'])) {
// civicrm_stripe.js is not included on backend form renewal unless we add it here.
CRM_Core_Resources::singleton()->addScriptFile('com.drastikbydesign.stripe', 'js/civicrm_stripe.js');
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment