diff --git a/CRM/Core/Payment/Stripe.php b/CRM/Core/Payment/Stripe.php index 27676a38a6b7f42828de831da5afbc11a6c63112..3a517a25c09351bf0aad956e455d80c93e1d4c86 100644 --- a/CRM/Core/Payment/Stripe.php +++ b/CRM/Core/Payment/Stripe.php @@ -6,11 +6,7 @@ class CRM_Core_Payment_Stripe extends CRM_Core_Payment { - /** - * - * @var string - */ - protected $_stripeAPIVersion = '2018-11-08'; + use CRM_Core_Payment_StripeTrait; /** * We only need one instance of this object. So we use the singleton @@ -449,8 +445,8 @@ class CRM_Core_Payment_Stripe extends CRM_Core_Payment { Civi::log()->debug('Stripe.js token was not passed! Report this message to the site administrator. $params: ' . print_r($params, TRUE)); } - $contactId = self::getContactId($params); - $email = self::getBillingEmail($params, $contactId); + $contactId = $this->getContactId($params); + $email = $this->getBillingEmail($params, $contactId); // See if we already have a stripe customer $customerParams = [ @@ -546,7 +542,7 @@ class CRM_Core_Payment_Stripe extends CRM_Core_Payment { if ($e instanceof \Stripe\Error\Card) { civicrm_api3('Note', 'create', [ 'entity_id' => $params['contributionID'], - 'contact_id' => self::getContactId($params), + 'contact_id' => $this->getContactId($params), 'subject' => $err['type'], 'note' => $err['code'], 'entity_table' => 'civicrm_contribution', @@ -876,185 +872,4 @@ class CRM_Core_Payment_Stripe extends CRM_Core_Payment { } } - - /******************************************************************* - * THE FOLLOWING FUNCTIONS SHOULD BE REMOVED ONCE THEY ARE IN CORE - * getBillingEmail - * getContactId - ******************************************************************/ - - /** - * Get the billing email address - * - * @param array $params - * @param int $contactId - * - * @return string|NULL - */ - protected static function getBillingEmail($params, $contactId) { - $billingLocationId = CRM_Core_BAO_LocationType::getBilling(); - - $emailAddress = CRM_Utils_Array::value("email-{$billingLocationId}", $params, - CRM_Utils_Array::value('email-Primary', $params, - CRM_Utils_Array::value('email', $params, NULL))); - - if (empty($emailAddress) && !empty($contactId)) { - // Try and retrieve an email address from Contact ID - try { - $emailAddress = civicrm_api3('Email', 'getvalue', array( - 'contact_id' => $contactId, - 'return' => ['email'], - )); - } - catch (CiviCRM_API3_Exception $e) { - return NULL; - } - } - return $emailAddress; - } - - /** - * Get the contact id - * - * @param array $params - * - * @return int ContactID - */ - protected static function getContactId($params) { - $contactId = CRM_Utils_Array::value('contactID', $params, - CRM_Utils_Array::value('contact_id', $params, - CRM_Utils_Array::value('cms_contactID', $params, - CRM_Utils_Array::value('cid', $params, NULL - )))); - if (!empty($contactId)) { - return $contactId; - } - // FIXME: Ref: https://lab.civicrm.org/extensions/stripe/issues/16 - // The problem is that when registering for a paid event, civicrm does not pass in the - // contact id to the payment processor (civicrm version 5.3). So, I had to patch your - // getContactId to check the session for a contact id. It's a hack and probably should be fixed in core. - // The code below is exactly what CiviEvent does, but does not pass it through to the next function. - $session = CRM_Core_Session::singleton(); - return $session->get('transaction.userID', NULL); - } - - /** - * Get url for users to manage this recurring contribution for this processor. - * FIXME: Remove and increment min version once https://github.com/civicrm/civicrm-core/pull/13215 is merged. - * - * @param int $entityID - * @param null $entity - * @param string $action - * - * @return string - */ - public function subscriptionURL($entityID = NULL, $entity = NULL, $action = 'cancel') { - // Set URL - switch ($action) { - case 'cancel': - if (!$this->supports('cancelRecurring')) { - return NULL; - } - $url = 'civicrm/contribute/unsubscribe'; - break; - - case 'billing': - //in notify mode don't return the update billing url - if (!$this->supports('updateSubscriptionBillingInfo')) { - return NULL; - } - $url = 'civicrm/contribute/updatebilling'; - break; - - case 'update': - if (!$this->supports('changeSubscriptionAmount') && !$this->supports('editRecurringContribution')) { - return NULL; - } - $url = 'civicrm/contribute/updaterecur'; - break; - } - - $userId = CRM_Core_Session::singleton()->get('userID'); - $contactID = 0; - $checksumValue = ''; - $entityArg = ''; - - // Find related Contact - if ($entityID) { - switch ($entity) { - case 'membership': - $contactID = CRM_Core_DAO::getFieldValue("CRM_Member_DAO_Membership", $entityID, "contact_id"); - $entityArg = 'mid'; - break; - - case 'contribution': - $contactID = CRM_Core_DAO::getFieldValue("CRM_Contribute_DAO_Contribution", $entityID, "contact_id"); - $entityArg = 'coid'; - break; - - case 'recur': - $sql = " - SELECT DISTINCT con.contact_id - FROM civicrm_contribution_recur rec -INNER JOIN civicrm_contribution con ON ( con.contribution_recur_id = rec.id ) - WHERE rec.id = %1"; - $contactID = CRM_Core_DAO::singleValueQuery($sql, array(1 => array($entityID, 'Integer'))); - $entityArg = 'crid'; - break; - } - } - - // Add entity arguments - if ($entityArg != '') { - // Add checksum argument - if ($contactID != 0 && $userId != $contactID) { - $checksumValue = '&cs=' . CRM_Contact_BAO_Contact_Utils::generateChecksum($contactID, NULL, 'inf'); - } - return CRM_Utils_System::url($url, "reset=1&{$entityArg}={$entityID}{$checksumValue}", TRUE, NULL, FALSE, TRUE); - } - - // Else login URL - if ($this->supports('accountLoginURL')) { - return $this->accountLoginURL(); - } - - // Else default - return isset($this->_paymentProcessor['url_recur']) ? $this->_paymentProcessor['url_recur'] : ''; - } - - /** - * Get the recurring contribution ID from parameters passed in to cancelSubscription - * Historical the data passed to cancelSubscription is pretty poor and doesn't include much! - * - * @param array $params - * - * @return int|null - */ - protected function getRecurringContributionId($params) { - // Not yet passed, but could be added via core PR - $contributionRecurId = CRM_Utils_Array::value('contribution_recur_id', $params); - if (!empty($contributionRecurId)) { - return $contributionRecurId; - } - - // Not yet passed, but could be added via core PR - $contributionId = CRM_Utils_Array::value('contribution_id', $params); - try { - return civicrm_api3('Contribution', 'getvalue', ['id' => $contributionId, 'return' => 'contribution_recur_id']); - } - catch (Exception $e) { - $subscriptionId = CRM_Utils_Array::value('subscriptionId', $params); - if (!empty($subscriptionId)) { - try { - return civicrm_api3('ContributionRecur', 'getvalue', ['processor_id' => $subscriptionId, 'return' => 'id']); - } - catch (Exception $e) { - return NULL; - } - } - return NULL; - } - } - } - diff --git a/CRM/Core/Payment/StripeTrait.php b/CRM/Core/Payment/StripeTrait.php new file mode 100644 index 0000000000000000000000000000000000000000..e437a4c1942155fbb16c114a4826cbedc3676afe --- /dev/null +++ b/CRM/Core/Payment/StripeTrait.php @@ -0,0 +1,161 @@ +<?php +/** + * Shared payment functions that should one day be migrated to CiviCRM core + * Version 1.0 + */ + +trait CRM_Core_Payment_StripeTrait { + /** + * Get the billing email address + * + * @param array $params + * @param int $contactId + * + * @return string|NULL + */ + protected function getBillingEmail($params, $contactId) { + $billingLocationId = CRM_Core_BAO_LocationType::getBilling(); + + $emailAddress = CRM_Utils_Array::value("email-{$billingLocationId}", $params, + CRM_Utils_Array::value('email-Primary', $params, + CRM_Utils_Array::value('email', $params, NULL))); + + if (empty($emailAddress) && !empty($contactId)) { + // Try and retrieve an email address from Contact ID + try { + $emailAddress = civicrm_api3('Email', 'getvalue', array( + 'contact_id' => $contactId, + 'return' => ['email'], + )); + } + catch (CiviCRM_API3_Exception $e) { + return NULL; + } + } + return $emailAddress; + } + + /** + * Get the contact id + * + * @param array $params + * + * @return int ContactID + */ + protected function getContactId($params) { + $contactId = CRM_Utils_Array::value('contactID', $params, + CRM_Utils_Array::value('contact_id', $params, + CRM_Utils_Array::value('cms_contactID', $params, + CRM_Utils_Array::value('cid', $params, NULL + )))); + if (!empty($contactId)) { + return $contactId; + } + // FIXME: Ref: https://lab.civicrm.org/extensions/stripe/issues/16 + // The problem is that when registering for a paid event, civicrm does not pass in the + // contact id to the payment processor (civicrm version 5.3). So, I had to patch your + // getContactId to check the session for a contact id. It's a hack and probably should be fixed in core. + // The code below is exactly what CiviEvent does, but does not pass it through to the next function. + $session = CRM_Core_Session::singleton(); + return $session->get('transaction.userID', NULL); + } + + /** + * Get the contribution ID + * + * @param $params + * + * @return mixed + */ + protected function getContributionId($params) { + return $params['contributionID']; + } + + /** + * Get the recurring contribution ID from parameters passed in to cancelSubscription + * Historical the data passed to cancelSubscription is pretty poor and doesn't include much! + * + * @param array $params + * + * @return int|null + */ + protected function getRecurringContributionId($params) { + // Not yet passed, but could be added via core PR + $contributionRecurId = CRM_Utils_Array::value('contribution_recur_id', $params); + if (!empty($contributionRecurId)) { + return $contributionRecurId; + } + + // Not yet passed, but could be added via core PR + $contributionId = CRM_Utils_Array::value('contribution_id', $params); + try { + return civicrm_api3('Contribution', 'getvalue', ['id' => $contributionId, 'return' => 'contribution_recur_id']); + } + catch (Exception $e) { + $subscriptionId = CRM_Utils_Array::value('subscriptionId', $params); + if (!empty($subscriptionId)) { + try { + return civicrm_api3('ContributionRecur', 'getvalue', ['processor_id' => $subscriptionId, 'return' => 'id']); + } + catch (Exception $e) { + return NULL; + } + } + return NULL; + } + } + + /** + * + * @param array $params ['name' => payment instrument name] + * + * @return int|null + * @throws \CiviCRM_API3_Exception + */ + public static function createPaymentInstrument($params) { + $mandatoryParams = ['name']; + foreach ($mandatoryParams as $value) { + if (empty($params[$value])) { + Civi::log()->error('createPaymentInstrument: Missing mandatory parameter: ' . $value); + return NULL; + } + } + + // Create a Payment Instrument + // See if we already have this type + $paymentInstrument = civicrm_api3('OptionValue', 'get', array( + 'option_group_id' => "payment_instrument", + 'name' => $params['name'], + )); + if (empty($paymentInstrument['count'])) { + // Otherwise create it + try { + $financialAccount = civicrm_api3('FinancialAccount', 'getsingle', [ + 'financial_account_type_id' => "Asset", + 'name' => "Payment Processor Account", + ]); + } + catch (Exception $e) { + $financialAccount = civicrm_api3('FinancialAccount', 'getsingle', [ + 'financial_account_type_id' => "Asset", + 'name' => "Payment Processor Account", + 'options' => ['limit' => 1, 'sort' => "id ASC"], + ]); + } + + $paymentParams = [ + 'option_group_id' => "payment_instrument", + 'name' => $params['name'], + 'description' => $params['name'], + 'financial_account_id' => $financialAccount['id'], + ]; + $paymentInstrument = civicrm_api3('OptionValue', 'create', $paymentParams); + $paymentInstrumentId = $paymentInstrument['values'][$paymentInstrument['id']]['value']; + } + else { + $paymentInstrumentId = $paymentInstrument['id']; + } + return $paymentInstrumentId; + } + +}