From 4c6f28ddcd357ee14c34d2b5f2e0d4131bd4cc07 Mon Sep 17 00:00:00 2001
From: drastik <jwjoshuawalker@gmail.com>
Date: Sat, 11 Aug 2012 13:46:28 -0700
Subject: [PATCH] Cron ready.  Branched for source vs extension installs

---
 README.txt                                    |  67 +++-
 .../CRM/Core/BillingBlock.tpl                 |   0
 .../info.xml                                  |  36 +++
 .../stripe.php                                | 287 ++++++++++++++++++
 .../extern/civicrm_stripe_cron_live.php       |  36 +++
 .../extern/civicrm_stripe_cron_test.php       |  36 +++
 {CRM => source/CRM}/Core/Payment/Stripe.php   |   0
 .../civicrm_stripe.sql                        |   0
 .../CRM/Core/BillingBlock.tpl                 | 221 ++++++++++++++
 source/extern/civicrm_stripe_cron_live.php    |  36 +++
 source/extern/civicrm_stripe_cron_test.php    |  36 +++
 11 files changed, 742 insertions(+), 13 deletions(-)
 rename {civicrm_templates => extension-4.1/civicrm_templates}/CRM/Core/BillingBlock.tpl (100%)
 create mode 100644 extension-4.1/com.drastikbydesign.payment.stripe/info.xml
 create mode 100644 extension-4.1/com.drastikbydesign.payment.stripe/stripe.php
 create mode 100644 extension-4.1/extern/civicrm_stripe_cron_live.php
 create mode 100644 extension-4.1/extern/civicrm_stripe_cron_test.php
 rename {CRM => source/CRM}/Core/Payment/Stripe.php (100%)
 rename civicrm_stripe.sql => source/civicrm_stripe.sql (100%)
 create mode 100644 source/civicrm_templates/CRM/Core/BillingBlock.tpl
 create mode 100644 source/extern/civicrm_stripe_cron_live.php
 create mode 100644 source/extern/civicrm_stripe_cron_test.php

diff --git a/README.txt b/README.txt
index 1fab60f0..8858f02c 100644
--- a/README.txt
+++ b/README.txt
@@ -1,24 +1,71 @@
 ------------
-Important Note:
+Please Read:
+
+There are 3 versions included by directory.  Installation instructions for each further below:
+extension-4.1:  Extension for CiviCRM 4.1 and earlier.
+extension-4.2:  Extension for CiviCRM 4.2 and earlier.
+source:  Pre-extension method, folder structure is in tact, place files accordingly.
 
-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 
+WordPress:  TBD
+
+IMPORTANT:
+It appears in CiviCRM 4.1, extensions aren't properly running their install() function so until further notice,
+you will need to run the .sql file to make sure the database tables get created.  This can be found in the 'source' folder.
+
+In all versions except extension-4.2, you will need to create a cron job in order for recurring contributions to be properly ended.
+The cron files are the files in the 'extern' folder.  There is one file each for live & test mode and files are named accordingly.
+In CiviCRM 4.2, just make sure you have the correct "Job Scheduler" cron entry.
+
+------------
+
+Installation Instructions:
+
+------------
+
+For CiviCRM 4.2
+extension-4.2 instructions:
+
+Install extension
+
+Place civicrm_templates folder anywhere and inform CiviCRM of your "Custom Templates" location in this admin page:  site.com/civicrm/admin/setting/path
+(custom template soon to be removed as a requirement)
+
+Make sure you have a cron entry for CiviCRM's Job Scheduler!
+
+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
 
 ------------
 
-Installing Stripe as a payment processor in CiviCRM 4.x
+For CiviCRM 4.1
+extension-4.1 instructions:
+
+Install extension
+
+Place civicrm_templates folder anywhere and inform CiviCRM of your "Custom Templates" location in this admin page:  site.com/civicrm/admin/setting/path
+
+Copy files in extern to your CiviCRM extern folder  "civicrm/extern"
+Make cron entry to hit the file(s) (daily preferred).
+
+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
 
-Folder structure is left in tact.  
+------------
+
+Pre-extension instructions:
+
+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 files in extern to your CiviCRM extern folder  "civicrm/extern"
+Make cron entry to hit the file(s) (daily preferred). 
+
 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
 
@@ -29,10 +76,4 @@ 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
diff --git a/civicrm_templates/CRM/Core/BillingBlock.tpl b/extension-4.1/civicrm_templates/CRM/Core/BillingBlock.tpl
similarity index 100%
rename from civicrm_templates/CRM/Core/BillingBlock.tpl
rename to extension-4.1/civicrm_templates/CRM/Core/BillingBlock.tpl
diff --git a/extension-4.1/com.drastikbydesign.payment.stripe/info.xml b/extension-4.1/com.drastikbydesign.payment.stripe/info.xml
new file mode 100644
index 00000000..78b4ae19
--- /dev/null
+++ b/extension-4.1/com.drastikbydesign.payment.stripe/info.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<extension key="com.drastikbydesign.payment.stripe" type="payment">
+  <file>stripe</file>
+  <name>Stripe</name>
+  <description>Stripe Payment Processor</description>
+  <urls>
+    <url desc="Main Extension Page">http://drastikbydesign.com</url>
+  </urls>
+  <license>AGPL</license>
+  <maintainer>
+    <author>Joshua Walker (drastik) - Drastik by Design</author>
+    <email>admin (at) drastikbydesign.com</email>
+  </maintainer>
+  <releaseDate>2012-08-11</releaseDate>
+  <version>1.0</version>
+  <develStage>stable</develStage>
+  <compatibility><ver>4.1</ver></compatibility>
+  <comments></comments>
+  <typeInfo>
+   <userNameLabel>Secret Key</userNameLabel>
+   <passwordLabel>Publishable Key</passwordLabel>
+   <signatureLabel></signatureLabel>
+   <subjectLabel></subjectLabel>
+   <urlSiteDefault>https://api.stripe.com/v1</urlSiteDefault>
+   <urlApiDefault></urlApiDefault>
+   <urlRecurDefault>https://api.stripe.com/v1</urlRecurDefault>
+   <urlSiteTestDefault>https://api.stripe.com/v1</urlSiteTestDefault>
+   <urlApiTestDefault></urlApiTestDefault>
+   <urlRecurTestDefault>https://api.stripe.com/v1</urlRecurTestDefault>
+   <urlButtonDefault></urlButtonDefault>
+   <urlButtonTestDefault></urlButtonTestDefault>
+   <billingMode>notify</billingMode>
+   <isRecur>1</isRecur>
+   <paymentType>1</paymentType>
+  </typeInfo>
+</extension>
\ No newline at end of file
diff --git a/extension-4.1/com.drastikbydesign.payment.stripe/stripe.php b/extension-4.1/com.drastikbydesign.payment.stripe/stripe.php
new file mode 100644
index 00000000..3a5c27d5
--- /dev/null
+++ b/extension-4.1/com.drastikbydesign.payment.stripe/stripe.php
@@ -0,0 +1,287 @@
+<?php
+ 
+require_once 'CRM/Core/Payment.php';
+ 
+class com_drastikbydesign_payment_stripe extends CRM_Core_Payment {
+  /**
+   * We only need one instance of this object. So we use the singleton
+   * pattern and cache the instance in this variable
+   *
+   * @var object
+   * @static
+   */
+  static private $_singleton = null;
+ 
+  /**
+   * mode of operation: live or test
+   *
+   * @var object
+   * @static
+   */
+  static protected $_mode = null;
+ 
+  /**
+   * Constructor
+   *
+   * @param string $mode the mode of operation: live or test
+   *
+   * @return void
+   */
+  function __construct($mode, &$paymentProcessor) {
+    $this->_mode             = $mode;
+    $this->_paymentProcessor = $paymentProcessor;
+    $this->_processorName    = ts('Stripe');
+  }
+ 
+  /**
+   * Singleton function used to manage this object
+   *
+   * @param string $mode the mode of operation: live or test
+   *
+   * @return object
+   * @static
+   *
+   */
+  static function &singleton($mode, &$paymentProcessor) {
+      $processorName = $paymentProcessor['name'];
+      if (self::$_singleton[$processorName] === NULL ) {
+          self::$_singleton[$processorName] = new com_drastikbydesign_payment_stripe($mode, $paymentProcessor);
+      } 
+      return self::$_singleton[$processorName];
+  }
+ 
+  /**
+   * This function checks to see if we have the right config values
+   *
+   * @return string the error message if any
+   * @public
+   */
+  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);
+    }
+    else {
+      return NULL;
+    }
+  }
+ 
+  /*
+   * CiviCRM extension install()
+   */
+  public function install() {
+    //Create required tables for Stripe
+    require_once "CRM/Core/DAO.php";
+    CRM_Core_DAO::executeQuery("
+		CREATE TABLE IF NOT EXISTS `civicrm_stripe_customers` (
+  			`email` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,
+  			`id` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
+  			UNIQUE KEY `email` (`email`)
+			) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+
+		CREATE TABLE IF NOT EXISTS `civicrm_stripe_plans` (
+  			`plan_id` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
+  			UNIQUE KEY `plan_id` (`plan_id`)
+			) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+
+		CREATE TABLE IF NOT EXISTS `civicrm_stripe_subscriptions` (
+  			`customer_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`)
+			) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+    ");
+  }
+  
+  /*
+   * CiviCRM extension uninstall()
+   */
+  public function uninstall() {
+    //Remove Stripe tables on uninstall
+    require_once "CRM/Core/DAO.php";
+    CRM_Core_DAO::executeQuery("DROP TABLE civicrm_stripe_customers");
+    CRM_Core_DAO::executeQuery("DROP TABLE civicrm_stripe_plans");
+    CRM_Core_DAO::executeQuery("DROP TABLE civicrm_stripe_subscriptions");
+  }
+  
+  /**
+   * Submit a payment using Stripe's PHP API:
+   * https://stripe.com/docs/api?lang=php
+   *
+   * @param  array $params assoc array of input parameters for this transaction
+   *
+   * @return array the result in a nice formatted array (or an error object)
+   * @public
+   */
+  function doDirectPayment(&$params) {
+    //Include Stripe library & Set API credentials.
+    require_once("stripe-php/lib/Stripe.php");
+    Stripe::setApiKey($this->_paymentProcessor['user_name']);
+
+    //Stripe amount required in cents.
+    $amount = $params['amount'] * 100;
+    //It would require 3 digits after the decimal for one to make it this far, CiviCRM prevents this, but let's be redundant.
+    $amount = number_format($amount, 0, '', '');
+
+    //Check for existing customer, create new otherwise.
+    $email = $params['email'];
+    $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'], 
+  	  'exp_year' => $params['year'],
+      'cvc' => $params['cvv2'],
+      'name' => $cc_name,
+      'address_line1' => $params['street_address'],
+      'address_state' => $params['state_province'],
+      'address_zip' => $params['postal_code'],
+    );
+    */
+    
+    //Create a new Customer in Stripe
+    if(!isset($customer_query)) {
+      $stripe_customer = Stripe_Customer::create(array(
+  		'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)) {
+        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);
+      if(!empty($stripe_customer)) {
+        $stripe_customer->card = $card_details;
+        $stripe_customer->save();
+      } else {
+        $stripe_customer = Stripe_Customer::create(array(
+  		  'description' => 'Donor from CiviCRM',
+  		  'card' => $card_details,
+          'email' => $email,
+        ));
+        
+        //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)) {
+          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')");
+        } else {
+          CRM_Core_Error::fatal(ts('There was an error saving new customer within Stripe.  Is Stripe down?'));
+        }
+      }
+    }
+    
+    //Prepare the charge array, minus Customer/Card details.
+    $stripe_charge = array(
+      'amount' => $amount, 
+      'currency' => 'usd',
+      'description' => '# CiviCRM Donation Page # ' . $params['description'] .  ' # Invoice ID # ' . $params['invoiceID'],
+    );
+
+    //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;
+    } 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);
+    }
+       
+    //Fire away!
+    $stripe_response = Stripe_Charge::create($stripe_charge);
+    $params['trxn_id'] = $stripe_response->id;
+
+    return $params;
+  }
+  
+  function doRecurPayment(&$params, $amount, $stripe_customer) {
+    $frequency = $params['frequency_unit'];
+    $installments = $params['installments'];
+    $plan_id = "$frequency-$amount";
+    
+    $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( 
+      	"amount" => $amount,
+      	"interval" => $frequency,
+      	"name" => "CiviCRM $frequency" . 'ly ' . $formatted_amount,
+      	"currency" => "usd",
+      	"id" => $plan_id));
+      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));
+    
+    $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");
+    $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')");
+    
+    $trxn_id = $stripe_customer->id . '-' . $end_time;
+    $params['trxn_id'] = $trxn_id;
+    
+    return $params;
+  }
+ 
+  /**
+   * Transfer method not in use
+   *
+   * @param array $params  name value pair of contribution data
+   *
+   * @return void
+   * @access public
+   *
+   */
+  function doTransferCheckout(&$params, $component) {
+    CRM_Core_Error::fatal(ts('Use direct billing instead of Transfer method.'));
+  }
+}
\ No newline at end of file
diff --git a/extension-4.1/extern/civicrm_stripe_cron_live.php b/extension-4.1/extern/civicrm_stripe_cron_live.php
new file mode 100644
index 00000000..2f45723c
--- /dev/null
+++ b/extension-4.1/extern/civicrm_stripe_cron_live.php
@@ -0,0 +1,36 @@
+<?php 
+/*
+ * Cron function for CiviCRM 4.1 and below to cancel recurring contributions.
+ */
+
+session_start( );
+
+require_once '../civicrm.config.php';
+require_once 'CRM/Core/Config.php';
+
+$config =& CRM_Core_Config::singleton();
+
+$stripe_key = CRM_Core_DAO::singleValueQuery("SELECT user_name FROM civicrm_payment_processor WHERE payment_processor_type = 'Stripe' AND is_test = '0'");
+require_once("packages/stripe-php/lib/Stripe.php");
+Stripe::setApiKey($stripe_key);
+
+$time = time();
+print $time;
+$query = "
+SELECT  customer_id, invoice_id 
+FROM    civicrm_stripe_subscriptions 
+WHERE   end_time <= '$time' 
+";
+
+$end_recur_query = CRM_Core_DAO::executeQuery($query);
+
+while($end_recur_query->fetch()) {
+  $end_date = date("Y-m-d H:i:s");
+  $stripe_customer = Stripe_Customer::retrieve($end_recur_query->customer_id);
+  if(isset($stripe_customer)) {
+    $stripe_customer->cancelSubscription();
+    CRM_Core_DAO::executeQuery("UPDATE civicrm_contribution_recur SET end_date = '$end_date', contribution_status_id = '1' WHERE invoice_id = '$end_recur_query->invoice_id'");
+    //Delete the Stripe Subscription from our cron watch list.
+    CRM_Core_DAO::executeQuery("DELETE FROM civicrm_stripe_subscriptions WHERE invoice_id = '$end_recur_query->invoice_id'");
+  }
+}
diff --git a/extension-4.1/extern/civicrm_stripe_cron_test.php b/extension-4.1/extern/civicrm_stripe_cron_test.php
new file mode 100644
index 00000000..64638938
--- /dev/null
+++ b/extension-4.1/extern/civicrm_stripe_cron_test.php
@@ -0,0 +1,36 @@
+<?php 
+/*
+ * Cron function for CiviCRM 4.1 and below to cancel recurring contributions.
+ */
+
+session_start( );
+
+require_once '../civicrm.config.php';
+require_once 'CRM/Core/Config.php';
+
+$config =& CRM_Core_Config::singleton();
+
+$stripe_key = CRM_Core_DAO::singleValueQuery("SELECT user_name FROM civicrm_payment_processor WHERE payment_processor_type = 'Stripe' AND is_test = '1'");
+require_once("packages/stripe-php/lib/Stripe.php");
+Stripe::setApiKey($stripe_key);
+
+$time = time();
+print $time;
+$query = "
+SELECT  customer_id, invoice_id 
+FROM    civicrm_stripe_subscriptions 
+WHERE   end_time <= '$time' 
+";
+
+$end_recur_query = CRM_Core_DAO::executeQuery($query);
+
+while($end_recur_query->fetch()) {
+  $end_date = date("Y-m-d H:i:s");
+  $stripe_customer = Stripe_Customer::retrieve($end_recur_query->customer_id);
+  if(isset($stripe_customer)) {
+    $stripe_customer->cancelSubscription();
+    CRM_Core_DAO::executeQuery("UPDATE civicrm_contribution_recur SET end_date = '$end_date', contribution_status_id = '1' WHERE invoice_id = '$end_recur_query->invoice_id'");
+    //Delete the Stripe Subscription from our cron watch list.
+    CRM_Core_DAO::executeQuery("DELETE FROM civicrm_stripe_subscriptions WHERE invoice_id = '$end_recur_query->invoice_id'");
+  }
+}
diff --git a/CRM/Core/Payment/Stripe.php b/source/CRM/Core/Payment/Stripe.php
similarity index 100%
rename from CRM/Core/Payment/Stripe.php
rename to source/CRM/Core/Payment/Stripe.php
diff --git a/civicrm_stripe.sql b/source/civicrm_stripe.sql
similarity index 100%
rename from civicrm_stripe.sql
rename to source/civicrm_stripe.sql
diff --git a/source/civicrm_templates/CRM/Core/BillingBlock.tpl b/source/civicrm_templates/CRM/Core/BillingBlock.tpl
new file mode 100644
index 00000000..96a007b2
--- /dev/null
+++ b/source/civicrm_templates/CRM/Core/BillingBlock.tpl
@@ -0,0 +1,221 @@
+{*
+ +--------------------------------------------------------------------+
+ | 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
diff --git a/source/extern/civicrm_stripe_cron_live.php b/source/extern/civicrm_stripe_cron_live.php
new file mode 100644
index 00000000..2f45723c
--- /dev/null
+++ b/source/extern/civicrm_stripe_cron_live.php
@@ -0,0 +1,36 @@
+<?php 
+/*
+ * Cron function for CiviCRM 4.1 and below to cancel recurring contributions.
+ */
+
+session_start( );
+
+require_once '../civicrm.config.php';
+require_once 'CRM/Core/Config.php';
+
+$config =& CRM_Core_Config::singleton();
+
+$stripe_key = CRM_Core_DAO::singleValueQuery("SELECT user_name FROM civicrm_payment_processor WHERE payment_processor_type = 'Stripe' AND is_test = '0'");
+require_once("packages/stripe-php/lib/Stripe.php");
+Stripe::setApiKey($stripe_key);
+
+$time = time();
+print $time;
+$query = "
+SELECT  customer_id, invoice_id 
+FROM    civicrm_stripe_subscriptions 
+WHERE   end_time <= '$time' 
+";
+
+$end_recur_query = CRM_Core_DAO::executeQuery($query);
+
+while($end_recur_query->fetch()) {
+  $end_date = date("Y-m-d H:i:s");
+  $stripe_customer = Stripe_Customer::retrieve($end_recur_query->customer_id);
+  if(isset($stripe_customer)) {
+    $stripe_customer->cancelSubscription();
+    CRM_Core_DAO::executeQuery("UPDATE civicrm_contribution_recur SET end_date = '$end_date', contribution_status_id = '1' WHERE invoice_id = '$end_recur_query->invoice_id'");
+    //Delete the Stripe Subscription from our cron watch list.
+    CRM_Core_DAO::executeQuery("DELETE FROM civicrm_stripe_subscriptions WHERE invoice_id = '$end_recur_query->invoice_id'");
+  }
+}
diff --git a/source/extern/civicrm_stripe_cron_test.php b/source/extern/civicrm_stripe_cron_test.php
new file mode 100644
index 00000000..64638938
--- /dev/null
+++ b/source/extern/civicrm_stripe_cron_test.php
@@ -0,0 +1,36 @@
+<?php 
+/*
+ * Cron function for CiviCRM 4.1 and below to cancel recurring contributions.
+ */
+
+session_start( );
+
+require_once '../civicrm.config.php';
+require_once 'CRM/Core/Config.php';
+
+$config =& CRM_Core_Config::singleton();
+
+$stripe_key = CRM_Core_DAO::singleValueQuery("SELECT user_name FROM civicrm_payment_processor WHERE payment_processor_type = 'Stripe' AND is_test = '1'");
+require_once("packages/stripe-php/lib/Stripe.php");
+Stripe::setApiKey($stripe_key);
+
+$time = time();
+print $time;
+$query = "
+SELECT  customer_id, invoice_id 
+FROM    civicrm_stripe_subscriptions 
+WHERE   end_time <= '$time' 
+";
+
+$end_recur_query = CRM_Core_DAO::executeQuery($query);
+
+while($end_recur_query->fetch()) {
+  $end_date = date("Y-m-d H:i:s");
+  $stripe_customer = Stripe_Customer::retrieve($end_recur_query->customer_id);
+  if(isset($stripe_customer)) {
+    $stripe_customer->cancelSubscription();
+    CRM_Core_DAO::executeQuery("UPDATE civicrm_contribution_recur SET end_date = '$end_date', contribution_status_id = '1' WHERE invoice_id = '$end_recur_query->invoice_id'");
+    //Delete the Stripe Subscription from our cron watch list.
+    CRM_Core_DAO::executeQuery("DELETE FROM civicrm_stripe_subscriptions WHERE invoice_id = '$end_recur_query->invoice_id'");
+  }
+}
-- 
GitLab