Skip to content

Commit

Permalink
Improve support for recurring billing & tokens
Browse files Browse the repository at this point in the history
  • Loading branch information
eileenmcnaughton committed Oct 1, 2017
1 parent 38d5650 commit 5639f37
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 16 deletions.
93 changes: 78 additions & 15 deletions CRM/Core/Payment/OmnipayMultiProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -140,21 +140,44 @@ public function doPayment(&$params, $component = 'contribute') {
$this->saveBillingAddressIfRequired($params);

try {
if (!empty($params['is_recur'])) {
$response = $this->gateway->createCard($this->getCreditCardOptions(array_merge($params, array('action' => 'Purchase')), $component))->send();
}
elseif (!empty($params['token'])) {
if (!empty($params['token'])) {
// If it is not recurring we will have succeeded in an Authorize so we should capture.
// The only recurring currently working with is_recur + pre-authorize is eWay rapid
// and, at least in that case, the createCreditCard call ignores any attempt to authorise.
// that is likely to be a pattern.
$action = CRM_Utils_Array::value('payment_action', $params, empty($params['is_recur']) ? 'capture' : 'purchase');
$params['transactionReference'] = ($params['token']);
$response = $this->gateway->capture($this->getCreditCardOptions($params, $component))
$response = $this->gateway->$action($this->getCreditCardOptions($params))
->send();
}
elseif (!empty($params['is_recur'])) {
$response = $this->gateway->createCard($this->getCreditCardOptions(array_merge($params, array('action' => 'Purchase')), $component))->send();
}
else {
$response = $this->gateway->purchase($this->getCreditCardOptions($params, $component))
$response = $this->gateway->purchase($this->getCreditCardOptions($params))
->send();
}
if ($response->isSuccessful()) {
// mark order as complete
if (!empty($params['is_recur'])) {
$paymentToken = civicrm_api3('PaymentToken', 'create', array(
'contact_id' => $params['contactID'],
'token' => $params['token'],
'payment_processor_id' => $this->_paymentProcessor['id'],
'created_id' => CRM_Core_Session::getLoggedInContactID(),
'email' => $params['email'],
'billing_first_name' => $params['billing_first_name'],
'billing_middle_name' => $params['billing_middle_name'],
'billing_last_name' => $params['billing_last_name'],
'expiry_date' => date("Y-m-t", strtotime($params['credit_card_exp_date']['Y'] . '-' . $params['credit_card_exp_date']['M'])),
'masked_account_number' => $this->getMaskedCreditCardNumber($params),
'ip_address' => CRM_Utils_System::ipAddress(),
));
civicrm_api3('ContributionRecur', 'create', array('id' => $params['contributionRecurID'], 'payment_token_id' => $paymentToken['id']));
}
$params['trxn_id'] = $response->getTransactionReference();
$params['payment_status_id'] = 1;
// @todo fetch masked card, card type, card expiry from params. Eway def provides these.
//gross_amount ? fee_amount?
return $params;
}
Expand Down Expand Up @@ -343,6 +366,10 @@ private function getCreditCardObjectParams($params) {
$cardFields[$cardField] = isset($params[$civicrmField]) ? $params[$civicrmField] : '';
}

// Compensate for some unreliability in calling function, especially from pre-Approval.
if (empty($cardFields['billingCountry']) && isset($params['billing_country_id-' . $billingID])) {
$cardFields['billingCountry'] = $params['billing_country_id-' . $billingID];
}
if (empty($cardFields['email'])) {
if (!empty($params['email-' . $billingID])) {
$cardFields['email'] = $params['email-' . $billingID];
Expand Down Expand Up @@ -394,11 +421,10 @@ private function getSensitiveCreditCardObjectOptions($params) {
* Get options for credit card.
*
* @param array $params
* @param string $component
*
* @return array
*/
private function getCreditCardOptions($params, $component) {
private function getCreditCardOptions($params) {
// Contribution page in 4.4 passes amount - not sure which passes total_amount if any.
if (isset($params['total_amount'])) {
$amount = (float) CRM_Utils_Rule::cleanMoney($params['total_amount']);
Expand Down Expand Up @@ -628,6 +654,10 @@ private function getCorePaymentFields() {
* @return array
*/
public function getBillingAddressFields($billingLocationID = NULL) {
$fields = $this->getProcessorTypeMetadata('fields');
if (isset ($fields['billing_fields'])) {
return $fields['billing_fields'];
}
if (!$this->isTransparentRedirect()) {
return parent::getBillingAddressFields($billingLocationID);
}
Expand Down Expand Up @@ -896,8 +926,7 @@ protected function supportsFutureRecurStartDate() {
* @return bool
*/
protected function supportsPreApproval() {
$this->getProcessorTypeMetadata('supports_preapproval');
return FALSE;
return $this->getProcessorTypeMetadata('supports_preapproval');
}

/**
Expand All @@ -913,7 +942,7 @@ protected function supportsPreApproval() {
* @return array
*/
public function doPreApproval(&$params) {
$this->_component = 'contribute';
$this->_component = $params['component'];
$this->ensurePaymentProcessorTypeIsSet();
$this->gateway = Omnipay::create(str_replace('omnipay_', '', $this->_paymentProcessor['payment_processor_type']));
$this->setProcessorFields();
Expand All @@ -922,11 +951,20 @@ public function doPreApproval(&$params) {
$this->saveBillingAddressIfRequired($params);

try {
$response = $this->gateway->authorize($this->getCreditCardOptions($params, 'contribute'))
->send();
if (!empty($params['is_recur'])) {
$response = $this->gateway->createCard($this->getCreditCardOptions(array_merge($params, array('action' => 'Authorize'))))->send();
}
else {
$response = $this->gateway->authorize($this->getCreditCardOptions($params))
->send();
}
if ($response->isSuccessful()) {
$params['trxn_id'] = $params['token'] = $response->getTransactionReference();
$creditCardPan = '************' . substr($params['credit_card_number'], -4);
if (!empty($params['is_recur'])) {
$params['token'] = $response->getCardReference();
}

$creditCardPan = $this->getMaskedCreditCardNumber($params);
foreach ($_SESSION as $key => $value) {
if (isset($value['values'])) {
foreach ($value['values'] as $pageName => $pageValues) {
Expand All @@ -941,7 +979,7 @@ public function doPreApproval(&$params) {
unset($params['credit_card_number']);
unset($params['cvv2']);
return array(
'pre_approval_parameters' => array('token' => $response->getTransactionReference())
'pre_approval_parameters' => array('token' => $params['token'])
);
}
else {
Expand Down Expand Up @@ -1076,5 +1114,30 @@ protected function getProcessorTypeMetadata($parameter) {
return FALSE;
}

/**
* @param $params
* @return string
*/
protected function getMaskedCreditCardNumber(&$params) {
$creditCardPan = '************' . substr($params['credit_card_number'], -4);
return $creditCardPan;
}

/**
* Default payment instrument validation.
*
* Implement the usual Luhn algorithm via a static function in the CRM_Core_Payment_Form if it's a credit card
* Not a static function, because I need to check for payment_type.
*
* @param array $values
* @param array $errors
*/
public function validatePaymentInstrument($values, &$errors) {
CRM_Core_Form::validateMandatoryFields($this->getMandatoryFields(), $values, $errors);
if ($this->_paymentProcessor['payment_type'] == 1) {
CRM_Core_Payment_Form::validateCreditCard($values, $errors, $this->_paymentProcessor['id']);
}
}

}

1 change: 1 addition & 0 deletions api/v3/Job/ProcessRecurring.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ function civicrm_api3_job_process_recurring($params) {
'return' => 'token',
)),
));
$payment = reset($payment['values']);

civicrm_api3('Contribution', 'completetransaction', array(
'id' => $pending['id'],
Expand Down
5 changes: 4 additions & 1 deletion api/v3/PaymentProcessor/Pay.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ function civicrm_api3_payment_processor_pay($params) {
if (is_a($result, 'CRM_Core_Error')) {
throw API_Exception('Payment failed');
}
return civicrm_api3_create_success($result, $params);
return civicrm_api3_create_success(array($result), $params);
}

/**
Expand All @@ -28,4 +28,7 @@ function civicrm_api3_payment_processor_pay($params) {
function _civicrm_api3_payment_processor_pay_spec(&$params) {
$params['payment_processor_id']['api.required'] = 1;
$params['amount']['api.required'] = 1;
$params['payment_action'] = array(
'api.default' => 'purchase',
);
}

0 comments on commit 5639f37

Please sign in to comment.