Skip to content
Snippets Groups Projects
Commit eb093d0c authored by drastik's avatar drastik
Browse files

Several changes. See README

parent dc106ebf
No related branches found
No related tags found
No related merge requests found
......@@ -59,10 +59,14 @@ class CRM_Core_Payment_Stripe extends CRM_Core_Payment {
function checkConfig() {
$config = CRM_Core_Config::singleton();
$error = array();
if (empty($this->_paymentProcessor['user_name'])) {
$error[] = ts('The "Secret Key" is not set in the Stripe Payment Processor settings.');
}
if (empty($this->_paymentProcessor['password'])) {
$error[] = ts('The "Publishable Key" is not set in the Stripe Payment Processor settings.');
}
if (!empty($error)) {
return implode('<p>', $error);
......@@ -85,12 +89,6 @@ class CRM_Core_Payment_Stripe extends CRM_Core_Payment {
//Include Stripe library & Set API credentials.
require_once("stripe-php/lib/Stripe.php");
Stripe::setApiKey($this->_paymentProcessor['user_name']);
$cc_name = $params['first_name'] . " ";
if (strlen($params['middle_name']) > 0) {
$cc_name .= $params['middle_name'] . " ";
}
$cc_name .= $params['last_name'];
//Stripe amount required in cents.
$amount = $params['amount'] * 100;
......@@ -98,12 +96,27 @@ class CRM_Core_Payment_Stripe extends CRM_Core_Payment {
$amount = number_format($amount, 0, '', '');
//Check for existing customer, create new otherwise.
$stripe_customer_id = "";
$email = $params['email'];
$customer_query = "SELECT id FROM civicrm_stripe_customers WHERE email = '$email'";
$customer_query_res = CRM_Core_DAO::singleValueQuery($customer_query);
$customer_query = CRM_Core_DAO::singleValueQuery("SELECT id FROM civicrm_stripe_customers WHERE email = '$email'");
//Use Stripe.js instead of raw card details.
if(isset($params['stripe_token'])) {
$card_details = $params['stripe_token'];
} else {
CRM_Core_Error::fatal(ts('Stripe.js token was not passed! Have you turned on the CiviCRM-Stripe CMS module?'));
}
/****
* If for some reason you cannot use Stripe.js and you are aware of PCI Compliance issues, here is the alternative to Stripe.js:
****/
//Prepare Card details in advance to use for new Stripe Customer object if we need.
/*
$cc_name = $params['first_name'] . " ";
if (strlen($params['middle_name']) > 0) {
$cc_name .= $params['middle_name'] . " ";
}
$cc_name .= $params['last_name'];
$card_details = array(
'number' => $params['credit_card_number'],
'exp_month' => $params['month'],
......@@ -113,28 +126,26 @@ class CRM_Core_Payment_Stripe extends CRM_Core_Payment {
'address_line1' => $params['street_address'],
'address_state' => $params['state_province'],
'address_zip' => $params['postal_code'],
//'address_country' => $params['country']
);
*/
//Create a new Customer in Stripe
if(!isset($customer_query_res)) {
if(!isset($customer_query)) {
$stripe_customer = Stripe_Customer::create(array(
'description' => 'Donor from CiviCRM',
'description' => 'Payment from CiviCRM',
'card' => $card_details,
'email' => $email,
));
//Store the relationship between CiviCRM's email address for the Contact & Stripe's Customer ID
if(isset($stripe_customer)) {
$stripe_customer_id = $stripe_customer->id;
CRM_Core_DAO::executeQuery("INSERT INTO civicrm_stripe_customers (email, id) VALUES ('$email', '$stripe_customer_id')");
CRM_Core_DAO::executeQuery("INSERT INTO civicrm_stripe_customers (email, id) VALUES ('$email', '$stripe_customer->id')");
} else {
CRM_Core_Error::fatal(ts('There was an error saving new customer within Stripe. Is Stripe down?'));
}
} else {
$stripe_customer = Stripe_Customer::retrieve($customer_query_res);
$stripe_customer = Stripe_Customer::retrieve($customer_query);
if(!empty($stripe_customer)) {
$stripe_customer_id = $customer_query_res;
$stripe_customer->card = $card_details;
$stripe_customer->save();
} else {
......@@ -147,9 +158,8 @@ class CRM_Core_Payment_Stripe extends CRM_Core_Payment {
//Somehow a customer ID saved in the system no longer pairs with a Customer within Stripe. (Perhaps deleted using Stripe interface?)
//Store the relationship between CiviCRM's email address for the Contact & Stripe's Customer ID
if(isset($stripe_customer)) {
$stripe_customer_id = $stripe_customer->id;
CRM_Core_DAO::executeQuery("DELETE FROM civicrm_stripe_customers WHERE email = '$email'");
CRM_Core_DAO::executeQuery("INSERT INTO civicrm_stripe_customers (email, id) VALUES ('$email', '$stripe_customer_id')");
CRM_Core_DAO::executeQuery("INSERT INTO civicrm_stripe_customers (email, id) VALUES ('$email', '$stripe_customer->id')");
} else {
CRM_Core_Error::fatal(ts('There was an error saving new customer within Stripe. Is Stripe down?'));
}
......@@ -164,15 +174,15 @@ class CRM_Core_Payment_Stripe extends CRM_Core_Payment {
);
//Use Stripe Customer if we have a valid one. Otherwise just use the card.
if(!empty($stripe_customer_id)) {
$stripe_charge['customer'] = $stripe_customer_id;
if(!empty($stripe_customer->id)) {
$stripe_charge['customer'] = $stripe_customer->id;
} else {
$stripe_charge['card'] = $card_details;
}
//Handle recurring payments in doRecurPayment().
if (CRM_Utils_Array::value('is_recur', $params) && $params['contributionRecurID']) {
return $this->doRecurPayment($params, $amount, $stripe_customer, $card_details);
return $this->doRecurPayment($params, $amount, $stripe_customer);
}
//Fire away!
......@@ -182,15 +192,14 @@ class CRM_Core_Payment_Stripe extends CRM_Core_Payment {
return $params;
}
function doRecurPayment(&$params, $amount, $stripe_customer, $card_details) {
function doRecurPayment(&$params, $amount, $stripe_customer) {
$frequency = $params['frequency_unit'];
$installments = $params['installments'];
$plan_id = "$frequency-$amount";
$stripe_plan_query = "SELECT plan_id FROM civicrm_stripe_plans WHERE plan_id = '$plan_id'";
$stripe_plan_query_res = CRM_Core_DAO::singleValueQuery($stripe_plan_query);
if(!isset($stripe_plan_query_res)) {
$stripe_plan_query = CRM_Core_DAO::singleValueQuery("SELECT plan_id FROM civicrm_stripe_plans WHERE plan_id = '$plan_id'");
if(!isset($stripe_plan_query)) {
$formatted_amount = "$" . number_format(($amount / 100), 2);
//Create a new Plan
$stripe_plan = Stripe_Plan::create(array(
......@@ -199,19 +208,28 @@ class CRM_Core_Payment_Stripe extends CRM_Core_Payment {
"name" => "CiviCRM $frequency" . 'ly ' . $formatted_amount,
"currency" => "usd",
"id" => $plan_id));
$new_plan_insert = "INSERT INTO civicrm_stripe_plans (plan_id) VALUES ('$plan_id')";
CRM_Core_DAO::executeQuery($new_plan_insert);
CRM_Core_DAO::executeQuery("INSERT INTO civicrm_stripe_plans (plan_id) VALUES ('$plan_id')");
}
//Attach the Subscription to the Stripe Customer
$stripe_response = $stripe_customer->updateSubscription(array('prorate' => FALSE, 'plan' => $plan_id, 'card' => $card_details));
$stripe_response = $stripe_customer->updateSubscription(array('prorate' => FALSE, 'plan' => $plan_id));
$existing_subscription_query = CRM_Core_DAO::singleValueQuery("SELECT invoice_id FROM civicrm_stripe_subscriptions WHERE customer_id = '$stripe_customer->id'");
if(!empty($existing_subscription_query)) {
//Cancel existing Recurring Contribution in CiviCRM
$cancel_date = date("Y-m-d H:i:s");
CRM_Core_DAO::executeQuery("UPDATE civicrm_contribution_recur SET cancel_date = '$cancel_date', contribution_status_id = '3' WHERE invoice_id = '$existing_subscription_query'");
//Delete the Stripe Subscription from our cron watch list.
CRM_Core_DAO::executeQuery("DELETE FROM civicrm_stripe_subscriptions WHERE invoice_id = '$existing_subscription_query'");
}
//Calculate timestamp for the last installment
$end_time = strtotime("+$installments $frequency");
$new_subscription_insert = "INSERT INTO civicrm_stripe_subscriptions (customer_id, plan_id, end_time) VALUES ('$stripe_customer->id', '$plan_id', '$end_time')";
CRM_Core_DAO::executeQuery($new_subscription_insert);
$invoice_id = $params['invoiceID'];
CRM_Core_DAO::executeQuery("INSERT INTO civicrm_stripe_subscriptions (customer_id, invoice_id, end_time) VALUES ('$stripe_customer->id', '$invoice_id', '$end_time')");
$params['trxn_id'] = $plan_id . ' ' . $stripe_response->start;
$trxn_id = $stripe_customer->id . '-' . $end_time;
$params['trxn_id'] = $trxn_id;
return $params;
}
......
------------
Important Note:
This version is for CiviCRM 4.1 and prior.
It will work for CiviCRM 4.2+ but there will be a new version to utilize all the new features surrounding Payment Processors in CiviCRM 4.2.
This currently includes everything you need minus a cron file to cancel recurring contributions. Do not allow recurring just yet!
You also need a corresponding module for your CMS. Here is where the modules can be found:
Drupal: git clone --recursive --branch master http://git.drupal.org/sandbox/drastik/1719796.git civicrm_stripe
Joomla: TBD
WordPress: TBD
------------
Installing Stripe as a payment processor in CiviCRM 4.x
Folder structure is left in tact, but there is only 1 file and this is where it goes:
Stripe.php in civicrm/CRM/Core/Payment/Stripe.php
Folder structure is left in tact.
Place Stripe.php in civicrm/CRM/Core/Payment/Stripe.php
Place civicrm_templates folder anywhere and inform CiviCRM of your "Custom Templates" location in this admin page: site.com/civicrm/admin/setting/path
Copy Stripe's PHP library folder 'stripe-php' to civicrm/packages/stripe-php
You can get Stripe's PHP library here: https://github.com/stripe/stripe-php
Run the included SQL file "civicrm_stripe.sql" to:
Run the included SQL file "civicrm_stripe.sql" to handle the DB-related needs. It will:
Insert Stripe into civicrm_payment_processor_type (makes it available as an option within CiviCRM's payment processor settings)
Create table civicrm_stripe_customers
Create table civicrm_stripe_plans
Create table civicrm_stripe_subscriptions
\ No newline at end of file
It will create the required tables:
civicrm_stripe_customers
civicrm_stripe_plans
civicrm_stripe_subscriptions
------------
Note:
This will be packaged as a "CiviCRM Extension" shortly for an alternative installation method.
In <CiviCRM 4.2, you will need to create a cron job in order for recurring contributions to be properly ended.
------------
\ No newline at end of file
......@@ -29,7 +29,7 @@ CREATE TABLE IF NOT EXISTS `civicrm_stripe_plans` (
CREATE TABLE IF NOT EXISTS `civicrm_stripe_subscriptions` (
`customer_id` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`plan_id` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`invoice_id` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`end_time` int(11) NOT NULL DEFAULT '0',
KEY `end_time` (`end_time`)
) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
{*
+--------------------------------------------------------------------+
| CiviCRM version 4.1 |
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC (c) 2004-2011 |
+--------------------------------------------------------------------+
| This file is a part of CiviCRM. |
| |
| CiviCRM is free software; you can copy, modify, and distribute it |
| under the terms of the GNU Affero General Public License |
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
| |
| CiviCRM is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| See the GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public |
| License and the CiviCRM Licensing Exception along |
| with this program; if not, contact CiviCRM LLC |
| at info[AT]civicrm[DOT]org. If you have questions about the |
| GNU Affero General Public License or the licensing of CiviCRM, |
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
+--------------------------------------------------------------------+
*}
{if $form.credit_card_number or $form.bank_account_number}
<!-- START Stripe -->
{if $paymentProcessor.payment_processor_type == 'Stripe'}
<script type="text/javascript" src="https://js.stripe.com/v1/"></script>
<script type="text/javascript">
var stripe_publishable_key = '{$paymentProcessor.password}';
{literal}
cj(function() {
cj(document).ready(function(){
//Identify the payment form. Don't reference by form#id since it changes between payment pages (Contribution / Event / etc).
cj("#crm-container>form").addClass('stripe-payment-form');
Stripe.setPublishableKey(stripe_publishable_key);
cj("form.stripe-payment-form").submit(function(event) {
// disable the submit button to prevent repeated clicks
cj('form.stripe-payment-form input.form-submit').attr("disabled", "disabled");
Stripe.createToken({
number: cj('#credit_card_number').val(),
cvc: cj('#cvv2').val(),
exp_month: cj('#credit_card_exp_date\\[M\\]').val(),
exp_year: cj('#credit_card_exp_date\\[Y\\]').val()
}, stripeResponseHandler);
// prevent the form from submitting with the default action
return false;
});
});
//Response from Stripe.createToken.
function stripeResponseHandler(status, response) {
if (response.error) {
// show the errors on the form
cj("form.stripe-payment-form").prepend('<div class="messages crm-error">'
+'<strong>Payment Error Response:</strong>'
+'<ul id="errorList">'
+'<li>Error: ' + response.error.message + '</li>'
+'</ul>'
+'</div>');
cj('form.stripe-payment-form input.form-submit').removeAttr("disabled");
} else {
var token = response['id'];
// Update form with the token & submit
cj("input#stripe-token").val(token);
cj("form.stripe-payment-form").get(0).submit();
}
}
});
{/literal}
</script>
{/if}
<!-- END Stripe -->
<div id="payment_information">
<fieldset class="billing_mode-group {if $paymentProcessor.payment_type & 2}direct_debit_info-group{else}credit_card_info-group{/if}">
<legend>
{if $paymentProcessor.payment_type & 2}
{ts}Direct Debit Information{/ts}
{else}
{ts}Credit Card Information{/ts}
{/if}
</legend>
{if $paymentProcessor.billing_mode & 2 and !$hidePayPalExpress }
<div class="crm-section no-label paypal_button_info-section">
<div class="content description">
{ts}If you have a PayPal account, you can click the PayPal button to continue. Otherwise, fill in the credit card and billing information on this form and click <strong>Continue</strong> at the bottom of the page.{/ts}
</div>
</div>
<div class="crm-section no-label {$form.$expressButtonName.name}-section">
<div class="content description">
{$form.$expressButtonName.html}
<div class="description">Save time. Checkout securely. Pay without sharing your financial information. </div>
</div>
</div>
{/if}
{if $paymentProcessor.billing_mode & 1}
<div class="crm-section billing_mode-section {if $paymentProcessor.payment_type & 2}direct_debit_info-section{else}credit_card_info-section{/if}">
{if $paymentProcessor.payment_type & 2}
<div class="crm-section {$form.account_holder.name}-section">
<div class="label">{$form.account_holder.label}</div>
<div class="content">{$form.account_holder.html}</div>
<div class="clear"></div>
</div>
<div class="crm-section {$form.bank_account_number.name}-section">
<div class="label">{$form.bank_account_number.label}</div>
<div class="content">{$form.bank_account_number.html}</div>
<div class="clear"></div>
</div>
<div class="crm-section {$form.bank_identification_number.name}-section">
<div class="label">{$form.bank_identification_number.label}</div>
<div class="content">{$form.bank_identification_number.html}</div>
<div class="clear"></div>
</div>
<div class="crm-section {$form.bank_name.name}-section">
<div class="label">{$form.bank_name.label}</div>
<div class="content">{$form.bank_name.html}</div>
<div class="clear"></div>
</div>
{else}
<div class="crm-section {$form.credit_card_type.name}-section">
<div class="label">{$form.credit_card_type.label}</div>
<div class="content">{$form.credit_card_type.html}</div>
<div class="clear"></div>
</div>
<div class="crm-section {$form.credit_card_number.name}-section">
<div class="label">{$form.credit_card_number.label}</div>
<div class="content">{$form.credit_card_number.html}
<div class="description">{ts}Enter numbers only, no spaces or dashes.{/ts}</div>
</div>
<div class="clear"></div>
</div>
<div class="crm-section {$form.cvv2.name}-section">
<div class="label">{$form.cvv2.label}</div>
<div class="content">
{$form.cvv2.html}
<img src="{$config->resourceBase}i/mini_cvv2.gif" alt="{ts}Security Code Location on Credit Card{/ts}" style="vertical-align: text-bottom;" />
<div class="description">{ts}Usually the last 3-4 digits in the signature area on the back of the card.{/ts}</div>
</div>
<div class="clear"></div>
</div>
<div class="crm-section {$form.credit_card_exp_date.name}-section">
<div class="label">{$form.credit_card_exp_date.label}</div>
<div class="content">{$form.credit_card_exp_date.html}</div>
<div class="clear"></div>
</div>
{/if}
</div>
</fieldset>
<fieldset class="billing_name_address-group">
<legend>{ts}Billing Name and Address{/ts}</legend>
<div class="crm-section billing_name_address-section">
<div class="crm-section billingNameInfo-section">
<div class="content description">
{if $paymentProcessor.payment_type & 2}
{ts}Enter the name of the account holder, and the corresponding billing address.{/ts}
{else}
{ts}Enter the name as shown on your credit or debit card, and the billing address for this card.{/ts}
{/if}
</div>
</div>
<div class="crm-section {$form.billing_first_name.name}-section">
<div class="label">{$form.billing_first_name.label}</div>
<div class="content">{$form.billing_first_name.html}</div>
<div class="clear"></div>
</div>
<div class="crm-section {$form.billing_middle_name.name}-section">
<div class="label">{$form.billing_middle_name.label}</div>
<div class="content">{$form.billing_middle_name.html}</div>
<div class="clear"></div>
</div>
<div class="crm-section {$form.billing_last_name.name}-section">
<div class="label">{$form.billing_last_name.label}</div>
<div class="content">{$form.billing_last_name.html}</div>
<div class="clear"></div>
</div>
{assign var=n value=billing_street_address-$bltID}
<div class="crm-section {$form.$n.name}-section">
<div class="label">{$form.$n.label}</div>
<div class="content">{$form.$n.html}</div>
<div class="clear"></div>
</div>
{assign var=n value=billing_city-$bltID}
<div class="crm-section {$form.$n.name}-section">
<div class="label">{$form.$n.label}</div>
<div class="content">{$form.$n.html}</div>
<div class="clear"></div>
</div>
{assign var=n value=billing_country_id-$bltID}
<div class="crm-section {$form.$n.name}-section">
<div class="label">{$form.$n.label}</div>
<div class="content">{$form.$n.html|crmReplace:class:big}</div>
<div class="clear"></div>
</div>
{assign var=n value=billing_state_province_id-$bltID}
<div class="crm-section {$form.$n.name}-section">
<div class="label">{$form.$n.label}</div>
<div class="content">{$form.$n.html|crmReplace:class:big}</div>
<div class="clear"></div>
</div>
{assign var=n value=billing_postal_code-$bltID}
<div class="crm-section {$form.$n.name}-section">
<div class="label">{$form.$n.label}</div>
<div class="content">{$form.$n.html}</div>
<div class="clear"></div>
</div>
</div>
</fieldset>
{else}
</fieldset>
{/if}
</div>
{/if}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment