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

Add StripeSubscription import api

parent c04aefe2
No related branches found
No related tags found
1 merge request!33Implement StripeSubscription.import API
......@@ -151,102 +151,7 @@ class CRM_Core_Payment_StripeIPN extends CRM_Core_Payment_BaseIPN {
* @throws \CRM_Core_Exception
*/
public function retrieve($name, $type, $abort = TRUE) {
$className = get_class($this->_inputParameters->data->object);
$value = NULL;
switch ($className) {
case 'Stripe\Charge':
switch ($name) {
case 'charge_id':
$value = $this->_inputParameters->data->object->id;
break;
case 'failure_code':
$value = $this->_inputParameters->data->object->failure_code;
break;
case 'failure_message':
$value = $this->_inputParameters->data->object->failure_message;
break;
case 'refunded':
$value = $this->_inputParameters->data->object->refunded;
break;
case 'amount_refunded':
$value = $this->_inputParameters->data->object->amount_refunded;
break;
}
break;
case 'Stripe\Invoice':
switch ($name) {
case 'charge_id':
$value = $this->_inputParameters->data->object->charge;
break;
case 'invoice_id':
$value = $this->_inputParameters->data->object->id;
break;
case 'receive_date':
$value = date("Y-m-d H:i:s", $this->_inputParameters->data->object->date);
break;
case 'subscription_id':
$value = $this->_inputParameters->data->object->subscription;
break;
}
break;
case 'Stripe\Subscription':
switch ($name) {
case 'frequency_interval':
$value = $this->_inputParameters->data->object->plan->interval_count;
break;
case 'frequency_unit':
$value = $this->_inputParameters->data->object->plan->interval;
break;
case 'plan_amount':
$value = $this->_inputParameters->data->object->plan->amount / 100;
break;
case 'plan_id':
$value = $this->_inputParameters->data->object->plan->id;
break;
case 'plan_name':
$value = $this->_inputParameters->data->object->plan->name;
break;
case 'plan_start':
$value = date("Y-m-d H:i:s", $this->_inputParameters->data->object->start);
break;
case 'subscription_id':
$value = $this->_inputParameters->data->object->id;
break;
}
break;
}
// Common parameters
switch ($name) {
case 'customer_id':
$value = $this->_inputParameters->data->object->customer;
break;
case 'event_type':
$value = $this->_inputParameters->type;
break;
case 'previous_plan_id':
if (preg_match('/\.updated$/', $this->_inputParameters->type)) {
$value = $this->_inputParameters->data->previous_attributes->plan->id;
}
break;
}
$value = CRM_Stripe_Api::getObjectParam($name, $type, $this->_inputParameters->data->object);
$value = CRM_Utils_Type::validate($value, $type, FALSE);
if ($abort && $value === NULL) {
......@@ -262,7 +167,7 @@ class CRM_Core_Payment_StripeIPN extends CRM_Core_Payment_BaseIPN {
*/
public function main() {
// Collect and determine all data about this event.
$this->event_type = $this->retrieve('event_type', 'String');
$this->event_type = CRM_Stripe_Api::getParam('event_type', $this->_inputParameters);
$pendingStatusId = CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Pending');
......@@ -454,13 +359,17 @@ class CRM_Core_Payment_StripeIPN extends CRM_Core_Payment_BaseIPN {
*/
public function setInfo() {
$abort = FALSE;
$this->customer_id = $this->retrieve('customer_id', 'String');
$this->customer_id = CRM_Stripe_Api::getParam('customer_id', $this->_inputParameters);
if (empty($this->customer_id)) {
$this->exception('Missing customer_id!');
}
$this->previous_plan_id = CRM_Stripe_Api::getParam('previous_plan_id', $this->_inputParameters);
$this->subscription_id = $this->retrieve('subscription_id', 'String', $abort);
$this->invoice_id = $this->retrieve('invoice_id', 'String', $abort);
$this->receive_date = $this->retrieve('receive_date', 'String', $abort);
$this->charge_id = $this->retrieve('charge_id', 'String', $abort);
$this->plan_id = $this->retrieve('plan_id', 'String', $abort);
$this->previous_plan_id = $this->retrieve('previous_plan_id', 'String', $abort);
$this->plan_amount = $this->retrieve('plan_amount', 'String', $abort);
$this->frequency_interval = $this->retrieve('frequency_interval', 'String', $abort);
$this->frequency_unit = $this->retrieve('frequency_unit', 'String', $abort);
......
<?php
class CRM_Stripe_Api {
public static function getObjectParam($name, $stripeObject) {
$className = get_class($stripeObject);
switch ($className) {
case 'Stripe\Charge':
switch ($name) {
case 'charge_id':
return (string) $stripeObject->id;
case 'failure_code':
return (string) $stripeObject->failure_code;
case 'failure_message':
return (string) $stripeObject->failure_message;
case 'refunded':
return (bool) $stripeObject->refunded;
case 'amount_refunded':
return (int) $stripeObject->amount_refunded / 100;
}
break;
case 'Stripe\Invoice':
switch ($name) {
case 'charge_id':
return (string) $stripeObject->charge;
case 'invoice_id':
return (string) $stripeObject->id;
case 'receive_date':
return date("Y-m-d H:i:s", $stripeObject->date);
case 'subscription_id':
return (string) $stripeObject->subscription;
case 'amount':
return (string) $stripeObject->amount_due / 100;
case 'amount_paid':
return (string) $stripeObject->amount_paid / 100;
case 'amount_remaining':
return (string) $stripeObject->amount_remaining / 100;
case 'currency':
return (string) mb_strtoupper($stripeObject->currency);
case 'status_id':
if ((bool)$stripeObject->paid) {
return 'Completed';
}
else {
return 'Pending';
}
case 'description':
return (string) $stripeObject->description;
}
break;
case 'Stripe\Subscription':
switch ($name) {
case 'frequency_interval':
return (string) $stripeObject->plan->interval_count;
case 'frequency_unit':
return (string) $stripeObject->plan->interval;
case 'plan_amount':
return (string) $stripeObject->plan->amount / 100;
case 'currency':
return (string) mb_strtoupper($stripeObject->plan->currency);
case 'plan_id':
return (string) $stripeObject->plan->id;
case 'plan_name':
return (string) $stripeObject->plan->name;
case 'plan_start':
return date("Y-m-d H:i:s", $stripeObject->start);
case 'cycle_day':
return date("d", $stripeObject->billing_cycle_anchor);
case 'subscription_id':
return (string) $stripeObject->id;
case 'status_id':
switch ($stripeObject->status) {
case \Stripe\Subscription::STATUS_ACTIVE:
return CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'In Progress');
case \Stripe\Subscription::STATUS_CANCELED:
return CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Cancelled');
}
case 'customer_id':
return (string) $stripeObject->customer;
}
break;
}
return NULL;
}
public static function getParam($name, $stripeObject) {
// Common parameters
switch ($name) {
case 'customer_id':
return (string) $stripeObject->customer;
case 'event_type':
return (string) $stripeObject->type;
case 'previous_plan_id':
if (preg_match('/\.updated$/', $stripeObject->type)) {
return (string) $stripeObject->data->previous_attributes->plan->id;
}
break;
}
return NULL;
}
}
......@@ -109,13 +109,12 @@ class CRM_Stripe_Customer {
/**
* @param $params
* @param $paymentProcessor
*
* @return \Stripe\ApiResource
* @throws \CiviCRM_API3_Exception
* @throws \Civi\Payment\Exception\PaymentProcessorException
*/
public static function create($params, $paymentProcessor) {
public static function create($params) {
$requiredParams = ['contact_id', 'card_token', 'processor_id'];
// $optionalParams = ['email'];
foreach ($requiredParams as $required) {
......
......@@ -74,7 +74,7 @@ function civicrm_api3_stripe_customer_get($params) {
}
/**
* StripeCustomer.Get API specification
* StripeCustomer.delete API specification
*
* @param array $spec description of fields supported by this API call
* @return void
......@@ -105,6 +105,41 @@ function civicrm_api3_stripe_customer_delete($params) {
return civicrm_api3_create_success([]);
}
/**
* StripeCustomer.create 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_create_spec(&$spec) {
$spec['id']['title'] = ts("Stripe Customer ID");
$spec['id']['type'] = CRM_Utils_Type::T_STRING;
$spec['id']['api.required'] = TRUE;
$spec['contact_id']['title'] = ts("CiviCRM Contact ID");
$spec['contact_id']['type'] = CRM_Utils_Type::T_INT;
$spec['contact_id']['api.required'] = TRUE;
$spec['processor_id']['title'] = ts("Payment Processor ID");
$spec['processor_id']['type'] = CRM_Utils_Type::T_INT;
$spec['processor_id']['api.required'] = TRUE;
}
/**
* StripeCustomer.create API
* This api will add a stripe customer to CiviCRM
*
* @param array $params
* @see civicrm_api3_create_success
*
* @throws \Civi\Payment\Exception\PaymentProcessorException
* @return array
*/
function civicrm_api3_stripe_customer_create($params) {
CRM_Stripe_Customer::add($params);
return civicrm_api3_create_success([]);
}
/**
* Stripe.Customer.Updatecontactids API
* This api will update the civicrm_stripe_customers table and add contact IDs for all known email addresses
......
......@@ -132,3 +132,153 @@ WHERE trxn_id=%1;";
}
return civicrm_api3_create_success($counts);
}
/**
* API to import a stripe subscription, create a customer, recur, contribution and optionally link to membership
* You run it once for each subscription and it creates/updates a recurring contribution in civicrm (and optionally links it to a membership).
*
* @param array $params
*
* @return array
* @throws \API_Exception
* @throws \CiviCRM_API3_Exception
* @throws \Stripe\Error\Api
*/
function civicrm_api3_stripe_subscription_import($params) {
civicrm_api3_verify_mandatory($params, NULL, ['subscription_id', 'contact_id', 'payment_processor_id']);
$paymentProcessor = \Civi\Payment\System::singleton()->getById($params['payment_processor_id'])->getPaymentProcessor();
// Now re-retrieve the data from Stripe to ensure it's legit.
\Stripe\Stripe::setApiKey($paymentProcessor['user_name']);
$stripeSubscription = \Stripe\Subscription::retrieve($params['subscription_id']);
// Create the stripe customer in CiviCRM
$customerParams = [
'id' => CRM_Stripe_Api::getObjectParam('customer_id', $stripeSubscription),
'contact_id' => $params['contact_id'],
'processor_id' => (int) $params['payment_processor_id'],
];
$customer = civicrm_api3('StripeCustomer', 'get', $customerParams);
if (empty($customer['count'])) {
civicrm_api3('StripeCustomer', 'create', $customerParams);
}
// Create the recur record in CiviCRM
$contributionRecurParams = [
'contact_id' => $params['contact_id'],
'amount' => CRM_Stripe_Api::getObjectParam('plan_amount', $stripeSubscription),
'currency' => CRM_Stripe_Api::getObjectParam('currency', $stripeSubscription),
'frequency_unit' => CRM_Stripe_Api::getObjectParam('frequency_unit', $stripeSubscription),
'frequency_interval' => CRM_Stripe_Api::getObjectParam('frequency_interval', $stripeSubscription),
'start_date' => CRM_Stripe_Api::getObjectParam('plan_start', $stripeSubscription),
'processor_id' => $params['subscription_id'],
'trxn_id' => $params['subscription_id'],
'contribution_status_id' => CRM_Stripe_Api::getObjectParam('status_id', $stripeSubscription),
'cycle_day' => CRM_Stripe_Api::getObjectParam('cycle_day', $stripeSubscription),
'auto_renew' => 1,
'payment_processor_id' => $params['payment_processor_id'],
'payment_instrument_id' => !empty($params['payment_instrument_id']) ? $params['payment_instrument_id'] : 'Credit Card',
'financial_type_id' => !empty($params['financial_type_id']) ? $params['financial_type_id'] : 'Donation',
'is_email_receipt' => !empty($params['is_email_receipt']) ? 1 : 0,
'is_test' => isset($paymentProcessor['is_test']) && $paymentProcessor['is_test'] ? 1 : 0,
];
if ($params['recur_id']) {
$contributionRecurParams['id'] = $params['recur_id'];
}
$contributionRecur = civicrm_api3('ContributionRecur', 'create', $contributionRecurParams);
// Get the invoices for the subscription
$invoiceParams = [
'customer' => CRM_Stripe_Api::getObjectParam('customer_id', $stripeSubscription),
'limit' => 10,
//'due_date[lte]' => time(),
];
$stripeInvoices = \Stripe\Invoice::all($invoiceParams);
foreach ($stripeInvoices->data as $stripeInvoice) {
if (CRM_Stripe_Api::getObjectParam('subscription_id', $stripeInvoice) === $params['subscription_id']) {
$contributionParams = [
'contact_id' => $params['contact_id'],
'total_amount' => CRM_Stripe_Api::getObjectParam('amount', $stripeInvoice),
'currency' => CRM_Stripe_Api::getObjectParam('currency', $stripeInvoice),
'receive_date' => CRM_Stripe_Api::getObjectParam('receive_date', $stripeInvoice),
'trxn_id' => CRM_Stripe_Api::getObjectParam('charge_id', $stripeInvoice),
'contribution_status_id' => CRM_Stripe_Api::getObjectParam('status_id', $stripeInvoice),
'payment_instrument_id' => !empty($params['payment_instrument_id']) ? $params['payment_instrument_id'] : 'Credit Card',
'financial_type_id' => !empty($params['financial_type_id']) ? $params['financial_type_id'] : 'Donation',
'is_test' => isset($paymentProcessor['is_test']) && $paymentProcessor['is_test'] ? 1 : 0,
'contribution_source' => CRM_Stripe_Api::getObjectParam('description', $stripeInvoice),
'contribution_recur_id' => $contributionRecur['id'],
];
$existingContribution = civicrm_api3('Contribution', 'get',
[
'contribution_test' => '',
'trxn_id' => $contributionParams['trxn_id']
]);
if (!empty($existingContribution['id'])) {
$contributionParams['id'] = $existingContribution['id'];
}
elseif ($params['contribution_id']) {
$contributionParams['id'] = $params['contribution_id'];
}
$contribution = civicrm_api3('Contribution', 'create', $contributionParams);
break;
}
}
// Link to membership record
if (!empty($params['membership_id'])) {
$membershipParams = [
'id' => $params['membership_id'],
'contribution_recur_id' => $contributionRecur['id'],
];
$membership = civicrm_api3('Membership', 'create', $membershipParams);
}
$results = [
'subscription_id' => $params['subscription_id'],
'customer_id' => CRM_Stripe_Api::getObjectParam('customer_id', $stripeSubscription),
'recur_id' => $contributionRecur['id'],
'contribution_id' => !empty($contribution['id'])? $contribution['id'] : NULL,
'membership_id' => !empty($membership['id']) ? $membership['id'] : NULL,
];
return civicrm_api3_create_success($results, $params, 'StripeSubscription', 'import');
}
function _civicrm_api3_stripe_subscription_import_spec(&$spec) {
$spec['subscription_id']['title'] = ts("Stripe Subscription ID");
$spec['subscription_id']['type'] = CRM_Utils_Type::T_STRING;
$spec['subscription_id']['api.required'] = TRUE;
$spec['contact_id']['title'] = ts("Contact ID");
$spec['contact_id']['type'] = CRM_Utils_Type::T_INT;
$spec['contact_id']['api.required'] = TRUE;
$spec['payment_processor_id']['title'] = ts("Payment Processor ID");
$spec['payment_processor_id']['type'] = CRM_Utils_Type::T_INT;
$spec['payment_processor_id']['api.required'] = TRUE;
$spec['recur_id']['title'] = ts("Contribution Recur ID");
$spec['recur_id']['type'] = CRM_Utils_Type::T_INT;
$spec['contribution_id']['title'] = ts("Contribution ID");
$spec['contribution_id']['type'] = CRM_Utils_Type::T_INT;
$spec['membership_id']['title'] = ts("Membership ID");
$spec['membership_id']['type'] = CRM_Utils_Type::T_INT;
$spec['financial_type_id'] = [
'title' => 'Financial ID (ignored if more than one line item)',
'name' => 'financial_type_id',
'type' => CRM_Utils_Type::T_INT,
'pseudoconstant' => [
'table' => 'civicrm_financial_type',
'keyColumn' => 'id',
'labelColumn' => 'name',
],
];
$spec['payment_instrument_id']['api.aliases'] = ['payment_instrument'];
}
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