Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support 'Update billing details' for Faps CC donation #371

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
200 changes: 166 additions & 34 deletions CRM/Core/Payment/Faps.php
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ public function buildForm(&$form) {
$markup = '<link type="text/css" rel="stylesheet" href="'.$cryptoCss.'" media="all" />'; // <script type="text/javascript" src="'.$cryptojs.'"></script>';
CRM_Core_Region::instance('billing-block')->add(array(
'markup' => $markup,
));
));
// the cryptojs above is the one on the 1pay server, now I load and invoke the extension's crypto.js
$myCryptoJs = $resources->getUrl('com.iatspayments.civicrm', 'js/crypto.js');
// after manually doing what addVars('iats', $jsVariables) would normally do
Expand Down Expand Up @@ -462,6 +462,95 @@ public function getRecurringScheduleUpdateHelpText() {
return 'Use this form to change the amount or number of installments for this recurring contribution.<ul><li>You can not change the contribution frequency.</li><li>You can also modify the next scheduled contribution date.</li><li>You can change whether the contributor is sent an email receipt for each contribution.<li>You have an option to notify the contributor of these changes.</li></ul>';
}

/*
* Implement the ability to update the billing info for recurring contributions,
* This functionality will apply to back-end and front-end,
* so it's only enabled when configured as on via the iATS admin settings.
* The default isSupported method is overridden above to achieve this.
*
* Return TRUE on success or an error.
*/
public function updateSubscriptionBillingInfo(&$message = '', $params = array()) {
// Fix billing form update bug https://github.com/iATSPayments/com.iatspayments.civicrm/issues/252 by getting crid from _POST
if (empty($params['crid'])) {
$params['crid'] = !empty($_POST['crid']) ? (int) $_POST['crid'] : (!empty($_GET['crid']) ? (int) $_GET['crid'] : 0);
if (empty($params['crid']) && !empty($params['entryURL'])) {
$components = parse_url($params['entryURL']);
parse_str(html_entity_decode($components['query']), $entryURLquery);
$params['crid'] = $entryURLquery['crid'];
}
}
// updatedBillingInfo array changed sometime after 4.7.27
$crid = !empty($params['crid']) ? $params['crid'] : $params['recur_id'];
if (empty($crid)) {
$alert = ts('This system is unable to perform self-service updates to credit cards. Please contact the administrator of this site.');
throw new Exception($alert);
}
$contribution_recur = civicrm_api3('ContributionRecur', 'getsingle', ['id' => $crid]);
$payment_token = civicrm_api3('PaymentToken', 'getsingle', ['id' => $contribution_recur['payment_token_id']]);
$params['token'] = $payment_token['token'];
$params['defaultAccount'] = true;
$result = CRM_Iats_FapsRequest::credentials($contribution_recur['payment_processor_id']);
$credentials = [
'merchantKey' => $result['signature'],
'processorId' => $result['user_name'],
];
// Generate token from creditcardcryptogram
$options = array(
'action' => 'GenerateTokenFromCreditCard',
);
$token_request = new CRM_Iats_FapsRequest($options);
$request = $this->convertParams($params, $options['action']);
// Make the request.
// CRM_Core_Error::debug_var('token request', $request);
$result = $token_request->request($credentials, $request);
// CRM_Core_Error::debug_var('token result', $result);
// unset the cryptogram request values, we can't use the cryptogram again and don't want to return it anyway.
unset($params['cryptogram']);
unset($request['creditCardCryptogram']);
unset($token_request);
if (!empty($result['isSuccess'])) {
// some of the result[data] is not useful, we're assuming it's not harmful to include in future requests here.
$params = array_merge($params, $result['data']);
}
else {
return self::error($result);
}

// construct the array of data that I'll submit to the iATS Payments server.
$options = [
'action' => 'VaultCreateCCRecord',
];
$vault_request = new CRM_Iats_FapsRequest($options);

$request = $this->convertParams($params, $options['action']);

// Make the soap request.
try {
$response = $vault_request->request($credentials, $request);
// note: don't log this to the iats_response table.
// CRM_Core_Error::debug_var('faps result', $response);
if (empty($response['isError'])) {
if (!empty($response['data']['id'])) {
// We update the payment token.
$newToken = $request['vaultKey'] . ":" . $response['data']['id'];
civicrm_api3('PaymentToken', 'create', [
'id' => $contribution_recur['payment_token_id'],
'token' => $newToken,
]);
}
return TRUE;
}
else {
return self::error($response);
}
}
catch (Exception $error) { // what could go wrong?
$message = $error->getMessage();
throw new PaymentProcessorException($message, '9002');
}
}

/**
* Convert the values in the civicrm params to the request array with keys as expected by FAPS
*
Expand All @@ -471,15 +560,50 @@ public function getRecurringScheduleUpdateHelpText() {
* @return array
*/
protected function convertParams($params, $method) {
$convert = array(
'ownerEmail' => 'email',
'ownerStreet' => 'street_address',
'ownerCity' => 'city',
'ownerState' => 'state_province',
'ownerZip' => 'postal_code',
'ownerCountry' => 'country',
'orderId' => 'invoiceID',
'cardNumber' => 'credit_card_number',
'cardExpYear' => 'year',
'cardExpMonth' => 'month',
'cVV' => 'cvv2',
'transactionAmount' => 'amount',
'creditCardCryptogram' => 'cryptogram',
'ownerName' => [
'billing_first_name',
'billing_last_name',
],
);
if ($method == 'VaultCreateCCRecord') {
$convert = array_merge($convert, [
'cardType' => 'cardtype',
'creditCardToken' => 'creditCardToken',
'cardExpMonth' => 'cardExpMonth',
'cardExpYear' => 'cardExpYear',
'ownerName' => [
'first_name',
'middle_name',
'last_name',
],
'defaultAccount' => 'defaultAccount',
'vaultKey' => 'token',
]);
}

if (empty($params['country']) && !empty($params['country_id'])) {
try {
$result = civicrm_api3('Country', 'get', [
'sequential' => 1,
'return' => ['name'],
'id' => $params['country_id'],
'id' => $params['country_id'],
'options' => ['limit' => 1],
]);
$params['country'] = $result['values'][0]['name'];
$params['country'] = $result['values'][0]['name'];
}
catch (CiviCRM_API3_Exception $e) {
Civi::log()->info('Unexpected error from api3 looking up countries/states/provinces');
Expand All @@ -490,32 +614,53 @@ protected function convertParams($params, $method) {
$result = civicrm_api3('StateProvince', 'get', [
'sequential' => 1,
'return' => ['name'],
'id' => $params['state_province_id'],
'id' => $params['state_province_id'],
'options' => ['limit' => 1],
]);
$params['state_province'] = $result['values'][0]['name'];
$params['state_province'] = $result['values'][0]['name'];
}
catch (CiviCRM_API3_Exception $e) {
Civi::log()->info('Unexpected error from api3 looking up countries/states/provinces');
}
}
$request = array();
$convert = array(
'ownerEmail' => 'email',
'ownerStreet' => 'street_address',
'ownerCity' => 'city',
'ownerState' => 'state_province',
'ownerZip' => 'postal_code',
'ownerCountry' => 'country',
'orderId' => 'invoiceID',
'cardNumber' => 'credit_card_number',
// 'cardtype' => 'credit_card_type',
'cVV' => 'cvv2',
'creditCardCryptogram' => 'cryptogram',
);
foreach ($convert as $r => $p) {
if ($r == 'ownerName') {
$request[$r] = '';
foreach ($p as $namePart) {
$request[$r] .= !empty($params[$namePart]) ? $params[$namePart] . ' ' : '';
}
continue;
}
if (isset($params[$p])) {
$request[$r] = htmlspecialchars($params[$p]);
if ($r == 'transactionAmount') {
$request[$r] = sprintf('%01.2f', CRM_Utils_Rule::cleanMoney($params[$p]));
}
elseif ($r == 'cardExpYear') {
$request[$r] = sprintf('%02d', $params[$p] % 100);
}
elseif ($r == 'cardExpMonth') {
$request[$r] = sprintf('%02d', $params[$p]);
}
elseif ($r == 'cardtype') {
$mop = [
'Visa' => 'VISA',
'MasterCard' => 'MC',
'Amex' => 'AMX',
'Discover' => 'DSC',
];
$request[$r] = $mop[$params[$p]];
}
elseif($r == 'defaultAccount') {
$request[$r] = true;
}
elseif ($r == 'vaultKey') {
$matches = explode(':', $params[$p]);
$request[$r] = $matches[0];
}
else {
$request[$r] = htmlspecialchars($params[$p]);
}
}
}
if (empty($params['email'])) {
Expand All @@ -526,14 +671,7 @@ protected function convertParams($params, $method) {
$request['ownerEmail'] = $params['email-Primary'];
}
}
$request['ownerName'] = $params['billing_first_name'].' '.$params['billing_last_name'];
if (!empty($params['month'])) {
$request['cardExpMonth'] = sprintf('%02d', $params['month']);
}
if (!empty($params['year'])) {
$request['cardExpYear'] = sprintf('%02d', $params['year'] % 100);
}
$request['transactionAmount'] = sprintf('%01.2f', CRM_Utils_Rule::cleanMoney($params['amount']));

// additional method-specific values (none!)
//CRM_Core_Error::debug_var('params for conversion', $params);
//CRM_Core_Error::debug_var('method', $method);
Expand All @@ -550,9 +688,6 @@ public function &error($error = NULL) {
if (is_object($error)) {
throw new PaymentProcessorException(ts('Error %1', [1 => $error->getMessage()]), $error_code);
}
elseif ($error && is_numeric($error)) {
throw new PaymentProcessorException(ts('Error %1', [1 => $this->errorString($error)]), $error_code);
}
elseif (is_array($error)) {
$errors = array();
if ($error['isError']) {
Expand All @@ -572,7 +707,7 @@ public function &error($error = NULL) {
else { /* in the event I'm handling an unexpected argument */
throw new PaymentProcessorException(ts('Unknown System Error.'), 'process_1stpay_extension');
}
return $e;
return $error;
}

/*
Expand Down Expand Up @@ -654,6 +789,3 @@ protected function updateContribution($params, $update = array()) {


}



10 changes: 10 additions & 0 deletions CRM/Iats/FapsRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -130,4 +130,14 @@ public function request($credentials, $request_params, $log_failure = TRUE) {
return $e->getMessage();
}
}

public static function credentials($payment_processor_id) {
static $credentials = [];
if (empty($credentials[$payment_processor_id])) {
$credentials[$payment_processor_id] = civicrm_api3('PaymentProcessor', 'get', [
'id' => $payment_processor_id,
])['values'][$payment_processor_id];
}
return $credentials[$payment_processor_id];
}
}
Loading