Commit 13176d7e authored by jenlampton's avatar jenlampton

Add recurring billing option, and required fields.

parent 9aeeca47
......@@ -46,9 +46,24 @@ Installation
entered into the "Administer" -> "Site Configuration" -> "Authorize.net
Webform" section.
As the last entry in the Webform, add a hidden field 'Transaction ID'.
Select 'Transaction ID' as the Authorize.net key to map to. The transaction
ID must be mapped, or the module will not work correctly.
Special fields:
* As the first field in the Webform, you must have a field for transaction
type. If you do not want your site visitors to see this field make it either
a hidden, or a value. Transaction type will allow people to choose between a
one-time transaction, or a subscription.
- One time transactions are straightforward and need no additional fields.
- Recurring subscriptions must also specify a 'length' and 'interval'. The
length and unit elements together define the interval in between payments.
If specified in terms of days, the interval can be between seven (7) and
365 days. If specified in terms of months, the interval can be between
one (1) and twelve (12) months.
- Interval (1 to 365)
- unit (days or months)
* As the last field in the Webform, add a hidden field 'Transaction ID'.
Select 'Transaction ID' as the Authorize.net key to map to. The transaction
ID must be mapped, or the module will not work correctly.
Save the webform.
......
......@@ -164,14 +164,17 @@ function authorizenetwebform_form_webform_client_form_alter(&$form, &$form_state
'data' => $path . '/js/authorizenetwebform.js',
'type' => 'file'
);
$form['#attached']['js'][] = array(
'data' => array('authorizeNetWebform' => $settings),
'type' => 'setting'
);
$form['#attached']['js'][] = array(
'data' => $js_url,
'type' => 'external'
);
$form['#attached']['js'][] = array(
'data' => array('authorizeNetWebform' => $settings),
'type' => 'setting'
);
// Validate handler.
$form['#validate'][] = 'authorizenetwebform_validate';
// Note: removing name attribute will prevent values from posting to the server.
......@@ -180,6 +183,18 @@ function authorizenetwebform_form_webform_client_form_alter(&$form, &$form_state
array_unshift($form['#submit'], $first, 'authorizenetwebform_submit');
}
/**
* Webform validation handler.
*
* @see authorizenetwebform_form_webform_client_form_alter().
*/
function authorizenetwebform_validate($form, &$form_state) {
_authorizenetwebform_sanitize($form_state['values']['submitted']);
dpm('form values submitted');
dpm($form_state['values']['submitted']);
}
/**
* Webform submit handler.
*
......@@ -192,6 +207,7 @@ function authorizenetwebform_submit($form, &$form_state) {
}
$field_values = _authorizenetwebform_flatten_form_values($form_state['input']['submitted']);
//dpm($field_values);
// Get key mappings for this webform.
$nid = $form_state['values']['details']['nid']; // Nice shorthand.
......@@ -199,6 +215,7 @@ function authorizenetwebform_submit($form, &$form_state) {
$field_map = variable_get($variable_name, array());
// We also want to access keys in the other direction.
$flipped_map = array_flip($field_map);
//dpm($flipped_map);
// Get the amount.
$amount_key = $flipped_map['x_amount'];
......@@ -211,46 +228,109 @@ function authorizenetwebform_submit($form, &$form_state) {
$amount = ((double) $amount) * ((double) $quantity);
}
// Get the transaction nonce.
$transaction_key = $flipped_map['x_trans_id'];
// Get keys for the the transaction nonce, and required fields.
$trans_key = $flipped_map['x_trans_id'];
$type_key = $flipped_map['x_trans_type'];
$first_key = $flipped_map['x_first_name'];
$last_key = $flipped_map['x_last_name'];
// Establish data to send to AuthNet.
$data = array(
'createTransactionRequest' => array(
'merchantAuthentication' => array(
'name' => variable_get('authorizenetwebform_login', NULL),
'transactionKey' => variable_get('authorizenetwebform_transaction', NULL),
),
'refId' => $nid . '-' . time(),
'transactionRequest' => array(
'transactionType' => 'authCaptureTransaction',
'amount' => $amount,
'payment' => array(
'opaqueData' => array(
'dataDescriptor' => 'COMMON.ACCEPT.INAPP.PAYMENT',
'dataValue' => $field_values[$transaction_key],
if ($field_values[$type_key] == 'one-time') {
$top_key = 'createTransactionRequest';
$data = array(
'createTransactionRequest' => array(
'merchantAuthentication' => array(
'name' => variable_get('authorizenetwebform_login', NULL),
'transactionKey' => variable_get('authorizenetwebform_transaction', NULL),
),
'refId' => $nid . '-' . time(),
'transactionRequest' => array(
'transactionType' => 'authCaptureTransaction',
'amount' => $amount,
'payment' => array(
'opaqueData' => array(
'dataDescriptor' => 'COMMON.ACCEPT.INAPP.PAYMENT',
'dataValue' => $field_values[$trans_key],
),
),
'billTo' => array(
'firstName' => $field_values[$first_key],
'lastName' => $field_values[$last_key],
),
'customerIP' => $_SERVER['REMOTE_ADDR'],
),
)
);
}
elseif ($field_values[$type_key] == 'subscription') {
$top_key = 'ARBCreateSubscriptionRequest';
$data = array(
'ARBCreateSubscriptionRequest' => array(
'merchantAuthentication' => array(
'name' => variable_get('authorizenetwebform_login', NULL),
'transactionKey' => variable_get('authorizenetwebform_transaction', NULL),
),
'refId' => $nid . '-' . time(),
'subscription' => array(
'name' => 'Recurring donation',
'paymentSchedule' => array(
'interval' => array(
'length' => 1,
'unit' => 'months',
),
'startDate' => date('Y-m-d'),
'totalOccurrences' => 9999,
'trialOccurrences' => 1,
),
'amount' => $amount,
'trialAmount' => '0.00',
'payment' => array(
'opaqueData' => array(
'dataDescriptor' => 'COMMON.ACCEPT.INAPP.PAYMENT',
'dataValue' => $field_values[$trans_key],
),
),
'billTo' => array(
'firstName' => $field_values[$first_key],
'lastName' => $field_values[$last_key],
),
),
'customerIP' => $_SERVER['REMOTE_ADDR'],
),
)
);
);
}
if (FALSE) { // @todo
// Optionally add the customer's billing data.
$data['createTransactionRequest']['billTo'] = array(
'firstName' => '',
'lastName' => '',
'address' => '',
'city' => '',
'state' => '',
'country' => '',
);
if ($field_values[$type_key] == 'one-time') {
$second_key = 'transactionRequest';
}
elseif ($field_values[$type_key] == 'subscription') {
$second_key = 'subscription';
}
$data[$top_key][$second_key]['billTo']['company'] = '';
$data[$top_key][$second_key]['billTo']['address'] = '';
$data[$top_key][$second_key]['billTo']['city'] = '';
$data[$top_key][$second_key]['billTo']['state'] = '';
$data[$top_key][$second_key]['billTo']['country'] = '';
if (FALSE) { // @todo
// Optionally add the customer's shipping data.
$data[$top_key][$second_key]['shipTo'] = array(
'firstName' => '',
'lastName' => '',
'company' => '',
'address' => '',
'city' => '',
'state' => '',
'country' => '',
);
}
}
if (FALSE) { // @todo
// Optionally add additional custom fields.
$data['createTransactionRequest']['userFields'] = array(
$data[$top_key]['userFields'] = array(
'userField' => array(
'name' => '',
'value' => '',
......@@ -281,40 +361,40 @@ function authorizenetwebform_submit($form, &$form_state) {
// Fix brokenness in the AuthNet JSON API response -- END.
$response_array = json_decode(trim($post_response), TRUE);
dpm($response_array);
//dpm($response_array);
if ($response_array['messages']['resultCode'] == 'Ok') {
drupal_set_message('Your payment has been processed, thank you.');
}
else {
drupal_set_message('There was a problem with your payment. Please try again later.');
$code = $response_array['messages']['message']['code'];
$message = $response_array['messages']['message']['text'];
watchdog('authorizenetwebform', 'Error @code from Authorize.net: @message',
array('@code' => $code, '@message' => $message));
drupal_set_message(t('Your payment has been processed, thank you.'));
}
elseif ($response_array['messages']['resultCode'] == 'Error') {
foreach ($response_array['messages']['message'] as $info) {
$code = $info['code'];
$text = $info['text'];
watchdog('authorizenetwebform', 'Error @code from Authorize.net: @message',
array('@code' => $code, '@message' => $text));
// Sanitize form values. @todo
drupal_set_message($code . ': ' . $text, 'error');
form_set_error(NULL, $code . ': ' . $text);
/*
$replacements = array();
// Blank out all but the last 4 CC #'s
$replacements[$cids[$flipped_map['x_card_num']]] = $anon_cc;
// Blank out the expiration date as well.
$replacements[$cids[$flipped_map['x_exp_date']]] = 'xxxxxx';
// Stop the submission.
$form_state['rebuild'] = TRUE;
}
}
else {
foreach ($response_array['messages']['message'] as $info) {
$info = reset();
$code = $info['code'];
$text = $info['text'];
watchdog('authorizenetwebform', 'Error @code from Authorize.net: @message',
array('@code' => $code, '@message' => $text));
// Blank out the security code as well.
$replacements[$cids[$flipped_map['x_card_code']]] = 'xxx';
drupal_set_message($code . ': ' . $text, 'warning');
// Replace the old values with the new ones.
array_walk_recursive($form_values['submitted'], '_authorizenetwebform_replace_value_in_recursive', $replacements);
// Return our temporary values to the $form_state array
$form_state['values'] = $form_values;
*/
// Stop the submission.
$form_state['rebuild'] = TRUE;
}
}
}
/**
......@@ -456,6 +536,9 @@ function _authorizenetwebform_add_attributes(&$parent, &$attribute_map, $nid = F
// Update JS settings by adding the field mapping.
switch ($auth_net_key) {
// These first ones are required.
case 'x_trans_id':
$attribute_map['transactionID'] = 'data-authnet-field--' . $lower_form_key;
break;
case 'x_card_num':
$attribute_map['cardNumber'] = 'data-authnet-field--' . $lower_form_key;
break;
......@@ -465,9 +548,13 @@ function _authorizenetwebform_add_attributes(&$parent, &$attribute_map, $nid = F
case 'x_exp_year':
$attribute_map['year'] = 'data-authnet-field--' . $lower_form_key;
break;
case 'x_trans_id':
$attribute_map['transactionID'] = 'data-authnet-field--' . $lower_form_key;
case 'x_exp_date':
$attribute_map[$form_key] = 'data-authnet-field--' . $lower_form_key;
// @todo need some special magic here to have different data
// attributes on month vs year selects for date field.
break;
// The rest are optional.
case 'x_card_code':
$attribute_map['cardCode'] = 'data-authnet-field--' . $lower_form_key;
......@@ -478,6 +565,7 @@ function _authorizenetwebform_add_attributes(&$parent, &$attribute_map, $nid = F
case 'x_full_name':
$attribute_map['fullName'] = 'data-authnet-field--' . $lower_form_key;
break;
// Default to using the case-sensitive form key.
default:
$attribute_map[$form_key] = 'data-authnet-field--' . $lower_form_key;
......@@ -490,3 +578,31 @@ function _authorizenetwebform_add_attributes(&$parent, &$attribute_map, $nid = F
return $attribute_map;
}
/**
* Replaces credit card details with x.
*
* @param array $element
* A structured data element, like a form array.
*/
function _authorizenetwebform_sanitize(&$element) {
$replace_me = array('x_card_num', 'x_card_code', 'x_exp_month', 'x_exp_year');
foreach ($element as $key => $value) {
if (is_array($value)) {
// Recurse.
_authorizenetwebform_sanitize($value);
}
elseif (in_array($key, $replace_me)) {
$length = strlen($value);
if ($length <= 7) {
$element[$key] = str_repeat('x', $length);
}
else {
$last_4 = substr($value, 0, -4);
$new = str_repeat('x', $length-4) . $last_4;
$element[$key] = $new;
}
}
}
}
......@@ -16,25 +16,26 @@
*/
function authorizenetwebform_available_fields() {
return array(
//Special Field to block Processing
// Special Field to block Processing.
0 => '--Do Not Map to an Authorize.Net field--',
// Transaction Info.
'x_trans_id' => 'Transaction ID (Required)',
'x_trans_type' => 'Transaction type (Required)',
'x_card_num' => 'Card Number (Required)',
'x_card_code' => 'Card Security Code (Required)',
'x_exp_date' => 'Expiration Date (Date field)',
'x_exp_month' => 'Expiration Month (2 Digits)', // Needed for accept.js
'x_exp_year' => 'Expiration Year (2 Digits)', // Needed for accept.js
'x_trans_id' => 'Transaction ID (Required)',
//'x_exp_date' => 'Expiration Date (Date component)',
'x_exp_month' => 'Expiration Month (2 Digits)',
'x_exp_year' => 'Expiration Year (2 Digits)',
'x_amount' => 'Amount (Required)',
//
// Subscription info.
'anwf_quantity' => 'Quantity - Multiplies this number by Amount - 1 if not set',
'x_subscription' => 'Subscription',
// Cardholder Info.
'x_full_name' => 'Full Name', // Needed for accept.js
'x_first_name' => 'First Name',
'x_last_name' => 'Last Name',
'x_first_name' => 'First Name (Required)',
'x_last_name' => 'Last Name (Required)',
'x_address' => 'Address',
'x_city' => 'City',
'x_state' => 'State',
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment