Commit bffaa990 authored by Mathieu Lutfy's avatar Mathieu Lutfy Committed by Aegir user

Update Stripe to 5.2

parent d4a5f7b1
<?php
class CRM_Stripe_Customer {
/**
* Find an existing Stripe customer in the CiviCRM database
*
* @param $params
*
* @return null|string
* @throws \Civi\Payment\Exception\PaymentProcessorException
*/
public static function find($params) {
$requiredParams = ['is_live', 'processor_id'];
foreach ($requiredParams as $required) {
if (empty($required)) {
throw new \Civi\Payment\Exception\PaymentProcessorException('Stripe Customer (find): Missing required parameter: ' . $required);
}
}
if (empty($params['contact_id'])) {
throw new \Civi\Payment\Exception\PaymentProcessorException('Stripe Customer (find): contact_id is required');
}
$queryParams = [
1 => [$params['contact_id'], 'String'],
2 => [$params['is_live'], 'Boolean'],
3 => [$params['processor_id'], 'Positive'],
];
return CRM_Core_DAO::singleValueQuery("SELECT id
FROM civicrm_stripe_customers
WHERE contact_id = %1 AND is_live = %2 AND processor_id = %3", $queryParams);
}
/**
* Add a new Stripe customer to the CiviCRM database
*
* @param $params
*
* @throws \Civi\Payment\Exception\PaymentProcessorException
*/
public static function add($params) {
$requiredParams = ['contact_id', 'customer_id', 'is_live', 'processor_id'];
foreach ($requiredParams as $required) {
if (empty($required)) {
throw new \Civi\Payment\Exception\PaymentProcessorException('Stripe Customer (add): Missing required parameter: ' . $required);
}
}
$queryParams = [
1 => [$params['contact_id'], 'String'],
2 => [$params['customer_id'], 'String'],
3 => [$params['is_live'], 'Boolean'],
4 => [$params['processor_id'], 'Integer'],
];
CRM_Core_DAO::executeQuery("INSERT INTO civicrm_stripe_customers
(contact_id, id, is_live, processor_id) VALUES (%1, %2, %3, %4)", $queryParams);
}
/**
* @param $params
* @param $paymentProcessor
*
* @return \Stripe\ApiResource
* @throws \CiviCRM_API3_Exception
* @throws \Civi\Payment\Exception\PaymentProcessorException
*/
public static function create($params, $paymentProcessor) {
$requiredParams = ['contact_id', 'card_token', 'is_live', 'processor_id'];
// $optionalParams = ['email'];
foreach ($requiredParams as $required) {
if (empty($required)) {
throw new \Civi\Payment\Exception\PaymentProcessorException('Stripe Customer (create): Missing required parameter: ' . $required);
}
}
$contactDisplayName = civicrm_api3('Contact', 'getvalue', [
'return' => 'display_name',
'id' => $params['contact_id'],
]);
$stripeCustomerParams = [
'description' => $contactDisplayName . ' (CiviCRM)',
'card' => $params['card_token'],
'email' => CRM_Utils_Array::value('email', $params),
'metadata' => ['civicrm_contact_id' => $params['contact_id']],
];
try {
$stripeCustomer = \Stripe\Customer::create($stripeCustomerParams);
}
catch (Exception $e) {
$err = CRM_Core_Payment_Stripe::parseStripeException('create_customer', $e, FALSE);
$errorMessage = CRM_Core_Payment_Stripe::handleErrorNotification($err, $params['stripe_error_url']);
throw new \Civi\Payment\Exception\PaymentProcessorException('Failed to create Stripe Customer: ' . $errorMessage);
}
// Store the relationship between CiviCRM's email address for the Contact & Stripe's Customer ID.
$params = [
'contact_id' => $params['contact_id'],
'customer_id' => $stripeCustomer->id,
'is_live' => $params['is_live'],
'processor_id' => $params['processor_id'],
];
self::add($params);
return $stripeCustomer;
}
/**
* Delete a Stripe customer from the CiviCRM database
*
* @param array $params
*
* @throws \Civi\Payment\Exception\PaymentProcessorException
*/
public static function delete($params) {
$requiredParams = ['contact_id', 'is_live', 'processor_id'];
foreach ($requiredParams as $required) {
if (empty($required)) {
throw new \Civi\Payment\Exception\PaymentProcessorException('Stripe Customer (delete): Missing required parameter: ' . $required);
}
}
$queryParams = [
1 => [$params['contact_id'], 'String'],
2 => [$params['is_live'], 'Boolean'],
3 => [$params['processor_id'], 'Integer'],
];
$sql = "DELETE FROM civicrm_stripe_customers
WHERE contact_id = %1 AND is_live = %2 AND processor_id = %3";
CRM_Core_DAO::executeQuery($sql, $queryParams);
}
}
<?php
/*--------------------------------------------------------------------+
| CiviCRM version 5.0 |
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC (c) 2004-2017 |
+--------------------------------------------------------------------+
| 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 |
+-------------------------------------------------------------------*/
/**
* This class implements hooks for Stripe
*/
class CRM_Stripe_Hook {
/**
* This hook allows modifying recurring contribution parameters
*
* @param array $recurContributionParams Recurring contribution params (ContributionRecur.create API parameters)
*
* @return mixed
*/
public static function updateRecurringContribution(&$recurContributionParams) {
return CRM_Utils_Hook::singleton()
->invoke(1, $recurContributionParams, CRM_Utils_Hook::$_nullObject, CRM_Utils_Hook::$_nullObject, CRM_Utils_Hook::$_nullObject,
CRM_Utils_Hook::$_nullObject, CRM_Utils_Hook::$_nullObject, 'civicrm_stripe_updateRecurringContribution');
}
}
......@@ -10,18 +10,6 @@ class CRM_Stripe_Upgrader extends CRM_Stripe_Upgrader_Base {
// By convention, functions that look like "function upgrade_NNNN()" are
// upgrade tasks. They are executed in order (like Drupal's hook_update_N).
/**
* Standard: run an install sql script
*/
public function install() {
}
/**
* Standard: run an uninstall script
*/
public function uninstall() {
}
/**
* Add is_live column to civicrm_stripe_plans and civicrm_stripe_customers tables.
*
......@@ -379,4 +367,34 @@ class CRM_Stripe_Upgrader extends CRM_Stripe_Upgrader_Base {
}
return TRUE;
}
public function upgrade_5010() {
$this->ctx->log->info('Applying Stripe update 5010. Adding contact_id to civicrm_stripe_customers.');
if (!CRM_Core_BAO_SchemaHandler::checkIfFieldExists('civicrm_stripe_customers', 'contact_id', FALSE)) {
CRM_Core_DAO::executeQuery('ALTER TABLE `civicrm_stripe_customers`
ADD COLUMN `contact_id` int(10) UNSIGNED DEFAULT NULL COMMENT "FK ID from civicrm_contact"');
CRM_Core_DAO::executeQuery('ALTER TABLE `civicrm_stripe_customers`
ADD CONSTRAINT `FK_civicrm_stripe_customers_contact_id` FOREIGN KEY (`contact_id`) REFERENCES `civicrm_contact` (`id`) ON DELETE CASCADE;');
}
$this->ctx->log->info('Applying Stripe update 5010. Getting Contact IDs for civicrm_stripe_customers.');
civicrm_api3('StripeCustomer', 'updatecontactids', []);
return TRUE;
}
public function upgrade_5020() {
$this->ctx->log->info('Applying Stripe update 5020. Migrate civicrm_stripe_subscriptions data to recurring contributions.');
civicrm_api3('StripeSubscription', 'updatetransactionids', []);
return TRUE;
}
public function upgrade_5021() {
$this->ctx->log->info('Applying Stripe update 5021. Copy trxn_id to processor_id so we can cancel recurring contributions.');
civicrm_api3('StripeSubscription', 'copytrxnidtoprocessorid', []);
return TRUE;
}
}
<?php
/**
* Stripe Customer API
*
*/
/**
* StripeCustomer.Get API specification
*
* @param array $spec description of fields supported by this API call
* @return void
* @see http://wiki.civicrm.org/confluence/display/CRMDOC/API+Architecture+Standards
*/
function _civicrm_api3_stripe_customer_get_spec(&$spec) {
$spec['id']['title'] = ts("Stripe Customer ID");
$spec['id']['type'] = CRM_Utils_Type::T_STRING;
$spec['contact_id']['title'] = ts("CiviCRM Contact ID");
$spec['contact_id']['type'] = CRM_Utils_Type::T_INT;
$spec['is_live']['title'] = ts("Is live processor");
$spec['is_live']['type'] = CRM_Utils_Type::T_BOOLEAN;
$spec['processor_id']['title'] = ts("Payment Processor ID");
$spec['processor_id']['type'] = CRM_Utils_Type::T_INT;
}
/**
* StripeCustomer.Get API
* This api will update the civicrm_stripe_customers table and add contact IDs for all known email addresses
*
* @param array $params
* @see civicrm_api3_create_success
*
* @return array
*/
function civicrm_api3_stripe_customer_get($params) {
foreach ($params as $key => $value) {
$index = 1;
switch ($key) {
case 'id':
$where[$index] = "{$key}=%{$index}";
$whereParam[$index] = [$value, 'String'];
$index++;
break;
case 'contact_id':
case 'processor_id':
$where[$index] = "{$key}=%{$index}";
$whereParam[$index] = [$value, 'Integer'];
$index++;
break;
case 'is_live':
$where[$index] = "{$key}=%{$index}";
$whereParam[$index] = [$value, 'Boolean'];
$index++;
break;
}
}
$query = "SELECT * FROM civicrm_stripe_customers ";
if (count($where)) {
$whereClause = implode(' AND ', $where);
$query .= "WHERE {$whereClause}";
}
$dao = CRM_Core_DAO::executeQuery($query, $whereParam);
while ($dao->fetch()) {
$result = [
'id' => $dao->id,
'contact_id' => $dao->contact_id,
'is_live' => $dao->is_live,
'processor_id' => $dao->processor_id,
];
if ($dao->email) {
$result['email'] = $dao->email;
}
$results[] = $result;
}
return civicrm_api3_create_success($results);
}
/**
* Stripe.Customer.Updatecontactids API
* This api will update the civicrm_stripe_customers table and add contact IDs for all known email addresses
*
* @param array $params
* @see civicrm_api3_create_success
*
* @return array
*/
function civicrm_api3_stripe_customer_updatecontactids($params) {
$dao = CRM_Core_DAO::executeQuery('SELECT email, id FROM civicrm_stripe_customers WHERE contact_id IS NULL');
$counts = [
'updated' => 0,
'failed' => 0,
];
while ($dao->fetch()) {
$contactId = NULL;
try {
$contactId = civicrm_api3('Contact', 'getvalue', [
'return' => "id",
'email' => $dao->email,
]);
}
catch (Exception $e) {
// Most common problem is duplicates.
if(preg_match("/Expected one Contact but found/", $e->getMessage())) {
// If we find more than one, first try to find it via a related subscription record
// using the customer id.
$sql = "SELECT c.id
FROM civicrm_contribution_recur rc
JOIN civicrm_stripe_subscriptions sc ON
rc.id = sc.contribution_recur_id
JOIN civicrm_contact c ON c.id = rc.contact_id
WHERE c.is_deleted = 0 AND customer_id = %0
ORDER BY start_date DESC LIMIT 1";
$dao_contribution = CRM_Core_DAO::executeQuery($sql, [0 => [$dao->id, 'String']]);
$dao_contribution->fetch();
if ($dao_contribution->id) {
$contactId = $dao_contribution->id;
}
if (empty($contactId)) {
// Still no luck. Now get desperate.
$sql = "SELECT c.id
FROM civicrm_contact c JOIN civicrm_email e ON c.id = e.contact_id
JOIN civicrm_contribution cc ON c.id = cc.contact_id
WHERE e.email = %0 AND c.is_deleted = 0 AND is_test = 0 AND
trxn_id LIKE 'ch_%' AND contribution_status_id = 1
ORDER BY receive_date DESC LIMIT 1";
$dao_contribution = CRM_Core_DAO::executeQuery($sql, [0 => [$dao->email, 'String']]);
$dao_contribution->fetch();
if ($dao_contribution->id) {
$contactId = $dao_contribution->id;
}
}
}
if (empty($contactId)) {
// Still no luck. Log it and move on.
Civi::log()->debug('Stripe Upgrader: No contact ID found for stripe customer with email: ' . $dao->email);
$counts['failed']++;
continue;
}
}
$sqlParams = [
1 => [$contactId, 'Integer'],
2 => [$dao->email, 'String'],
];
$sql = 'UPDATE civicrm_stripe_customers SET contact_id=%1 WHERE email=%2';
CRM_Core_DAO::executeQuery($sql, $sqlParams);
$counts['updated']++;
}
return civicrm_api3_create_success($counts);
}
<?php
/**
* Stripe Subscription API
*
*/
/**
* StripeSubscription.Get API specification
*
* @param array $spec description of fields supported by this API call
* @return void
* @see http://wiki.civicrm.org/confluence/display/CRMDOC/API+Architecture+Standards
*/
function _civicrm_api3_stripe_subscription_get_spec(&$spec) {
$spec['subscription_id']['title'] = ts("Stripe Subscription ID");
$spec['subscription_id']['type'] = CRM_Utils_Type::T_STRING;
$spec['customer_id']['title'] = ts("Stripe Customer ID");
$spec['customer_id']['type'] = CRM_Utils_Type::T_STRING;
$spec['contribution_recur_id']['title'] = ts("Contribution Recur ID");
$spec['contribution_recur_id']['type'] = CRM_Utils_Type::T_INT;
$spec['is_live']['title'] = ts("Is live processor");
$spec['is_live']['type'] = CRM_Utils_Type::T_BOOLEAN;
$spec['processor_id']['title'] = ts("Payment Processor ID");
$spec['processor_id']['type'] = CRM_Utils_Type::T_INT;
$spec['end_time_id']['title'] = ts("End Time");
$spec['end_time_id']['type'] = CRM_Utils_Type::T_INT;
}
/**
* @deprecated This StripeSubscription.get is deprecated as of 5.2 as we now using recurring contribution instead of civicrm_stripe_subscriptions
*
* StripeSubscription.Get API
* This api will get entries from the civicrm_stripe_subscriptions table
*
* @param array $params
* @see civicrm_api3_create_success
*
* @return array
*/
function civicrm_api3_stripe_subscription_get($params) {
foreach ($params as $key => $value) {
$index = 1;
switch ($key) {
case 'subscription_id':
case 'customer_id':
$where[$index] = "{$key}=%{$index}";
$whereParam[$index] = [$value, 'String'];
$index++;
break;
case 'contribution_recur_id':
case 'processor_id':
case 'end_time':
$where[$index] = "{$key}=%{$index}";
$whereParam[$index] = [$value, 'Integer'];
$index++;
break;
case 'is_live':
$where[$index] = "{$key}=%{$index}";
$whereParam[$index] = [$value, 'Boolean'];
$index++;
break;
}
}
$query = "SELECT * FROM civicrm_stripe_subscriptions ";
if (count($where)) {
$whereClause = implode(' AND ', $where);
$query .= "WHERE {$whereClause}";
}
$dao = CRM_Core_DAO::executeQuery($query, $whereParam);
while ($dao->fetch()) {
$result = [
'subscription_id' => $dao->subscription_id,
'customer_id' => $dao->customer_id,
'contribution_recur_id' => $dao->contribution_recur_id,
'is_live' => $dao->is_live,
'processor_id' => $dao->processor_id,
'end_time' => $dao->end_time,
];
$results[] = $result;
}
return civicrm_api3_create_success($results);
}
function civicrm_api3_stripe_subscription_updatetransactionids() {
if (!CRM_Core_DAO::checkTableExists('civicrm_stripe_subscriptions')) {
throw new CiviCRM_API3_Exception('Table civicrm_stripe_subscriptions is not used in Stripe >=5.2 and does not exist on your install. This API will be removed in a future release.');
}
$sql = "SELECT subscription_id, contribution_recur_id FROM civicrm_stripe_subscriptions";
$dao = CRM_Core_DAO::executeQuery($sql);
$counts = [
'success' => 0,
'failed' => 0
];
while ($dao->fetch()) {
if (!empty($dao->subscription_id) && !empty($dao->contribution_recur_id)) {
try {
civicrm_api3('ContributionRecur', 'create', ['id' => $dao->contribution_recur_id, 'trxn_id' => $dao->subscription_id]);
$counts['success']++;
}
catch (Exception $e) {
Civi::log()->debug('Error updating trxn_id for recur: ' . $dao->contribution_recur_id . ' trxn_id: ' . $dao->subscription_id);
$counts['failed']++;
}
}
}
return civicrm_api3_create_success($counts);
}
/**
* API function (used in 5021 upgrader) to copy trxn_id to processor_id in civicrm_contribution_recur table
* processor_id (named subscriptionId) is the only value available to cancelSubscription in 5.9 (and earlier).
* It is not ideal as processor_id is not guaranteed to be unique in the CiviCRM database (trxn_id is unique).
*
* @return array
*/
function civicrm_api3_stripe_subscription_copytrxnidtoprocessorid() {
$sql = "SELECT cr.trxn_id, cr.processor_id, cr.payment_processor_id, cpp.class_name FROM civicrm_contribution_recur cr
LEFT JOIN civicrm_payment_processor AS cpp ON cr.payment_processor_id = cpp.id
WHERE cpp.class_name = 'Payment_Stripe'";
$dao = CRM_Core_DAO::executeQuery($sql);
$counts = [
'updated' => 0,
];
while ($dao->fetch()) {
if (!empty($dao->trxn_id) && empty($dao->processor_id)) {
$updateSQL = "UPDATE civicrm_contribution_recur
SET processor_id=%1
WHERE trxn_id=%1;";
$updateParams = [1 => [$dao->trxn_id, 'String']];
CRM_Core_DAO::executeQuery($updateSQL, $updateParams);
$counts['updated']++;
}
}
return civicrm_api3_create_success($counts);
}
{
"require": {
"stripe/stripe-php": "^5.2"
"stripe/stripe-php": "^6.19"
}
}
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "2c17a82c0fb79b31818993eeb2df574d",
"content-hash": "dbdee644ee846739bbb5a9313746d072",
"packages": [
{
"name": "stripe/stripe-php",
"version": "v5.2.3",
"version": "v6.19.5",
"source": {
"type": "git",
"url": "https://github.com/stripe/stripe-php.git",
"reference": "9e8d565e991ca82c91d708b281063cefd69d7b2c"
"reference": "1ab5c54fae4c16e9cc47d60c7454e6c3b6bbcb85"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/stripe/stripe-php/zipball/9e8d565e991ca82c91d708b281063cefd69d7b2c",
"reference": "9e8d565e991ca82c91d708b281063cefd69d7b2c",
"url": "https://api.github.com/repos/stripe/stripe-php/zipball/1ab5c54fae4c16e9cc47d60c7454e6c3b6bbcb85",
"reference": "1ab5c54fae4c16e9cc47d60c7454e6c3b6bbcb85",
"shasum": ""
},
"require": {
"ext-curl": "*",
"ext-json": "*",
"ext-mbstring": "*",
"php": ">=5.3.3"
"php": ">=5.4.0"