By aliensun on
I am in the process of reworking the Linkpoint API for Drupal 5. Im new to drupal and have run into a problem with the module. I keep coming up with Invalid XML. Here is the code:
<?php
// $Id: linkpoint_api.module
define('LINKPOINT_ERROR_SHORT_VIEW', 0);
define('LINKPOINT_ERROR_MEDIUM_VIEW', 1);
define('LINKPOINT_ERROR_LARGE_VIEW', 2);
/********************************************************************
* Drupal Hooks
********************************************************************/
/**
* Implementation of hook_menu().
*/
function linkpoint_api_menu($may_cache) {
$items = array();
if ($may_cache) {
$items[] = array(
'path' => 'store/payment/linkpoint_api/form',
'title' => t('Credit Card Payment'),
'callback' => 'drupal_get_form',
'callback arguments' => array('linkpoint_api_form'),
'access' => true,
'type' => MENU_CALLBACK);
}
$items[] = array(
'path' => 'admin/ecsettings/linkpoint_api',
'title' => 'Linkpoint API',
'callback' => 'drupal_get_form',
'callback arguments' => array('linkpoint_api_ec_settings'),
'access' => user_access('administer store'),
'type' => MENU_NORMAL_ITEM,
'description' => t('Configure Linkpoint API payment gateway'),
);
return $items;
}
/**
* Implementation of hook_help().
*/
function linkpoint_api_help($section = 'admin/help#linkpoint_api') {
switch ($section) {
case 'admin/ecsettings/linkpoint_api':
return t("You need to have a linkpoint merchant account in order to use this module.");
case 'linkpoint_api/form_submit_guidlines':
return t("Do not submit this form twice, or you may be double billed!");
}
}
function linkpoint_api_ec_settings() {
$form = array(
'linkpoint_api_help' => array(
'#type' => 'textarea',
'#title' => t('Explanation or submission guidelines'),
'#description' => t('This text will be displayed at the top of the credit card submission form.'),
'#rows' => 5,
'#required' => TRUE,
'#default_value' => variable_get('linkpoint_api_help', linkpoint_api_help('linkpoint_api/form_submit_guidlines')),
),
'linkpoint_api_login' => array(
'#type' => 'textfield',
'#title' => t('Store ID'),
'#description' => t("Enter your merchant Store ID."),
'#required' => TRUE,
'#maxlength' => 70,
'#default_value' => variable_get('linkpoint_api_login', ''),
),
'linkpoint_api_ssl_certificate' => array(
'#type' => 'textfield',
'#title' => t('SSL Certificate'),
'#description' => t("Enter your merchant SSL certificate (.pem). It is preferred that you enter full server path (like /home/smb/1234567.pem, not ./1234567.pem) "),
'#required' => TRUE,
'#maxlength' => 255,
'#default_value' => variable_get('linkpoint_api_ssl_certificate', ''),
),
'linkpoint_api_url' => array(
'#type' => 'textfield',
'#title' => t('Linkpoint processing URL'),
'#description' => t('URL of the secure payment processing page, including the port number.'),
'#required' => TRUE,
'#maxlength' => 70,
'#default_value' => variable_get('linkpoint_api_url', 'https://secure.linkpt.net:1129/LSGSXML'),
),
'linkpoint_api_success_url' => array(
'#type' => 'textfield',
'#title' => t('Successful payment URL'),
'#description' => t("This is the destination to which you would like to send your customers when their payment has been successfully completed. The URL must be a Drupal system path (without leading slash), e.g. 'product'. If not set, user will see invoice (recommended)."),
'#required' => FALSE,
'#maxlength' => 70,
'#default_value' => variable_get('linkpoint_api_success_url', ''),
),
'linkpoint_api_debug' => array(
'#type' => 'radios',
'#title' => t('Test mode'),
'#options' => array(t('Disabled'), t('Enabled')),
'#description' => t('If enabled, transactions will be sent in "GOOD" mode - any card numbers will be approved and cards will not be charged. Also, in test mode full connection error description is shown instead of "Sorry - Could not connect to payment gateway."'),
'#default_value' => variable_get('linkpoint_api_debug', 1),
),
'linkpoint_api_format_not_accepted' => array(
'#type' => 'radios',
'#title' => t('How to format error message if card is not accepted'),
'#options' => array(
LINKPOINT_ERROR_SHORT_VIEW => t('Simply Accepted, Declined or Duplicate'),
LINKPOINT_ERROR_MEDIUM_VIEW => t('Linkpoint\'s error message without code (e.g. "The order already exists in the database")'),
LINKPOINT_ERROR_LARGE_VIEW => t('Full Linkpoint\'s error message (e.g. "SGS-005003: The order already exists in the database.")'),
),
'#default_value' => variable_get('linkpoint_api_format_not_accepted', 0),
),
);
return system_settings_form($form);
}
/**
* Implementation of hook_paymentapi().
*/
function linkpoint_api_paymentapi(&$txn, $op) {
switch ($op) {
case 'display name':
return t('Pay with credit card');
case 'payment page':
return linkpoint_api_goto($txn);
}
}
/**
* Implementation of hook_ec_transactionapi().
*/
function linkpoint_api_ec_transactionapi(&$txn, $op, $a3 = NULL, $a4 = NULL) {
if ($txn->payment_method != 'linkpoint_api') return NULL;
switch ($op) {
case 'load':
$txn->payment = db_fetch_object(db_query("SELECT * FROM {ec_linkpoint_api} WHERE txnid = %d", $txn->txnid));
break;
case 'insert':
case 'update':
linkpoint_api_save($txn);
break;
case 'delete':
linkpoint_api_delete($txn);
break;
}
}
function linkpoint_api_save($txn) {
if (is_numeric($txn->txnid) && is_numeric($txn->anid)) {
if (db_result(db_query("SELECT COUNT(txnid) FROM {ec_linkpoint_api} WHERE txnid = '%s'", $txn->txnid))) {
db_query("UPDATE {ec_linkpoint_api} SET anid = '%s', amount = '%f' WHERE txnid = %d", $txn->anid, $txn->amount, $txn->txnid);
}
else {
db_query("INSERT INTO {ec_linkpoint_api} (txnid, anid, amount) VALUES (%d, '%s', '%f')", $txn->txnid, $txn->anid, $txn->amount);
}
}
}
function linkpoint_api_delete($txn) {
db_query('DELETE FROM {ec_linkpoint_api} WHERE txnid = %d', $txn->txnid);
}
function linkpoint_api_goto($txn) {
global $base_url;
$payment_url = str_replace('http://', 'https://', url('store/payment/linkpoint_api/form/'. $txn->txnid, NULL, NULL, TRUE));
drupal_goto($payment_url);
exit();
}
/**
* Controller for collecting and processing credit card data.
*/
function linkpoint_api_page($txnid = null) {
$output = linkpoint_api_form($txnid);
print theme('page', $output);
}
/**
* Build the credit card form.
*/
function linkpoint_api_form($txnid) {
global $user, $base_url;
$t = store_transaction_load($txnid);
// Make sure the user owns the transaction or is an admin.
if ($user->uid != $t->uid && $user->uid != 1 && !user_access('administer store')) {
return drupal_access_denied();
}
// Make sure the user is connected via SSL
if (!$_SERVER['HTTPS']) {
drupal_access_denied();
return;
}
if ($t->items) {
foreach ($t->items as $p) {
$product = product_load($p);
$subtotal += $p->qty * $p->price;
$items[] = t('%order of <b>%title</b> at %price each', array('%order' => format_plural($p->qty, '1 order', '@count orders'), '%title' => $p->title, '%price' => payment_format($product->price))). "\n";
}
}
$form['help'] = array('#value' => t('<div class="help">%linkpoint_api_help</div>', array('%linkpoint_api_help' => variable_get('linkpoint_api_help', linkpoint_api_help('linkpoint_api/form_submit_guidlines')))));
$form['items'] = array('#value' => theme('item_list', $items, t('Your items')). '</p>');
// Prepare the values of the form fields.
$years = drupal_map_assoc(range(2007, 2021));
$months = drupal_map_assoc(array('01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'));
$form['expiry_date'] = array(
'#type' => 'fieldset',
'#title' => t('Expiration Date'),
);
$form['expiry_date']['cc_month'] = array(
'#type' => 'select',
'#title' => t('Month'),
'#default_value' => ($month ? $month : date('m')),
'#options' => $months,
'#description' => null,
'#extra' => 0,
'#multiple' => false,
'#required' => true,
);
$form['expiry_date']['cc_year'] = array(
'#type' => 'select',
'#title' => t('Year'),
'#default_value' => ($year ? $year : date('Y')),
'#options' => $years,
'#description' => null,
'#extra' => 0,
'#multiple' => false,
'#required' => true,
);
$form['details'] = array(
'#type' => 'fieldset',
'#title' => t('Card details'),
);
$form['details']['cc_firstname'] = array(
'#type' => 'textfield',
'#title' => t('Cardholder\'s first name'),
'#default_value' => $t->address['billing']->firstname,
'#size' => 50,
'#maxlength' => 50,
);
$form['details']['cc_lastname'] = array(
'#type' => 'textfield',
'#title' => t('Cardholder\'s last name'),
'#default_value' => $t->address['billing']->lastname,
'#size' => 50,
'#maxlength' => 50,
);
$form['details']['cc_number'] = array(
'#type' => 'textfield',
'#title' => t('Credit Card Number'),
'#default_value' => '',
'#size' => 21,
'#maxlength' => 21,
'#description' => null,
'#attributes' => null,
'#required' => true,
);
$form['details']['cc_ccv'] = array(
'#type' => 'textfield',
'#title' => t('CCV Security Code'),
'#description' => t('Three digit number on back of card'),
'#size' => 3,
'#maxlength' => 3,
'#required' => true,
);
$form['txnid'] = array(
'#type' => 'value',
'#value' => $txnid,
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Place your order'),
);
$form['#method'] = 'POST';
$form['#action'] = str_replace('http://', 'https://', url("store/payment/linkpoint_api/form/$txnid", NULL, NULL, TRUE));
return $form;
}
/**
* Ensure the integrity of the user-submitted data.
*/
function linkpoint_api_form_validate($form_id, $edit) {
$errors = array();
if (!$edit['cc_number']) {
$errors['cc_number'] = t('You must enter a credit card number.');
}
elseif (!is_numeric($edit['cc_number'])) {
$errors['cc_number'] = t('Error in credit card number. Please make sure it is typed correctly.');
}
foreach ($errors as $name => $message) {
form_set_error($name, $message);
}
return count($errors) == 0;
}
/**
* Send the HTTPS POST request and process the returned data.
*/
function linkpoint_api_form_submit($form_id, $form_values) {
global $user;
global $base_url;
$t = store_transaction_load($form_values['txnid']);
// include_once './includes/dBug.php';
// new dBug($t);
//Make sure the user owns the transaction or is admin.
if ($user->uid != $t->uid && $user->uid != 1) {
drupal_access_denied();
}
//Make sure the user is connected via SSL
if (!$_SERVER['HTTPS']) {
drupal_access_denied();
}
$d['configfile'] = variable_get('linkpoint_api_login', '');
$d['result'] = 'LIVE';
if (variable_get('linkpoint_api_debug', 1)) {
$d['result'] = 'GOOD';
}
$d['cert'] = variable_get('linkpoint_api_ssl_certificate', '');
$xml ="<order>";
$xml .="<billing>";
$xml .="<name>" . $t->address['billing']->firstname . " " . $t->address['billing']->lastname ."</name>";
$xml .="<address1>" . $t->address['billing']->street1 . "</address1>";
$xml .="<city>" . $t->address['billing']->city . "</city>";
$xml .="<state>" . $t->address['billing']->state . "</state>";
$xml .="<zip>" . $t->address['billing']->zip . "</zip>";
$xml .="<country>" . store_get_country($t->address['billing']->country) . "</country>";
$xml .="<email>" . $t->mail . "</email>";
$xml .="</billing>";
$xml .="<shipping>";
$xml .="<name>" . $t->address['shipping']->firstname . " " . $t->address['shipping']->lastname ."</name>";
$xml .="<address1>" . $t->address['shipping']->street1 . "</address1>";
$xml .="<city>" . $t->address['shipping']->city . "</city>";
$xml .="<state>" . $t->address['shipping']->state . "</state>";
$xml .="<zip>" . $t->address['shipping']->zip . "</zip>";
$xml .="<country>" . store_get_country($t->address['shipping']->country) . "</country>";
$xml .="</shipping>";
$xml .="<orderoptions>";
$xml .="<result>" . $d['result'] . "</result>";
$xml .="<ordertype>SALE</ordertype>";
$xml .="</orderoptions>";
$xml .="<merchantinfo>";
$xml .="<configfile>" . $d['configfile'] . "</configfile>";
$xml .="</merchantinfo>";
$xml .="<creditcard>";
$xml .="<cardnumber>" . $form_values['details']['cc_number'] . "</cardnumber>";
$xml .="<cardexpmonth>" . $form_values['exp_date']['cc_month'] . "</cardexpmonth>";
$xml .="<cardexpyear>" . substr($form_values['exp_date']['cc_year'],2,2) . "</cardexpyear>";
$xml .="<cvmvalue>" . $form_values['details']['cc_cvv'] . "</cvmvalue>";
$xml .="<cvmindicator>provided</cvmindicator>";
$xml .="</creditcard>";
$xml .="<payment>";
$xml .="<chargetotal>" . $t->gross . "</chargetotal>";
$xml .="</payment>";
$xml .="<transactiondetails>";
$xml .="<transactionorigin>ECI</transactionorigin>";
$xml .="<oid>" . $form_values['txnid'] . "</oid>";
$xml .="<ip>" . $_SERVER['REMOTE_ADDR'] . "</ip>";
$xml .="</transactiondetails>";
$xml .="</order>";
// Start CURL session
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, variable_get('linkpoint_api_url', 'https://secure.linkpt.net:1129/LSGSXML'));
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
curl_setopt($ch, CURLOPT_SSLCERT, $d['cert']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)");
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); // this line is used to fix errors on some systems
$buffer = curl_exec($ch);
if (curl_errno($ch)) {
if (variable_get('linkpoint_api_debug', 1)) {
drupal_set_message(curl_error($ch),'error');
} else {
drupal_set_message(t('Sorry - Could not connect to payment gateway.'),'error');
}
return str_replace('http://', 'https://', $base_url) . url('../store/payment/linkpoint_api/form/'. $form_values['txnid']);
} else {
curl_close($ch);
}
preg_match_all ("/<(.*?)>(.*?)\</", $buffer, $outarr, PREG_SET_ORDER);
$n = 0;
while (isset($outarr[$n])) {
$retarr[$outarr[$n][1]] = strip_tags($outarr[$n][0]);
$n++;
}
switch ($retarr['r_approved']) {
case "APPROVED": // Credit card successfully charged
if ((!$retarr['r_ordernum']) && (!variable_get('linkpoint_api_debug', 1))) {
drupal_set_message(t('No ordernumber received from Linkpoint'),'error');
}
$t->anid = $retarr['r_ordernum'];
$t->amount = $t->gross;
$t->payment_status = payment_get_status_id('completed');
$t->payment_method = 'linkpoint_api';
unset($form_values['details']['cc_number']); // will prevent from saving cc_number in the case if some module will save entire transaction data
$is_new = (db_result(db_query('SELECT COUNT(txnid) FROM {ec_linkpoint_api} WHERE txnid = %d', $form_values['txnid']))) ? false : true;
$txnid = store_transaction_save((array)$t);
if ($is_new && $txnid) {
// Compose and send confirmation email to the user
store_send_invoice_email($txnid);
}
drupal_set_message("Thank you ! Your credit card has been accepted. You will receive confirmation by email shortly.");
$url=trim(variable_get('linkpoint_api_success_url', ''));
if ($url) {
// We want to go to a http, not https.
return str_replace('https://', 'http://', $base_url). '/' . $url;
} else {
return str_replace('https://', 'http://', $base_url). '/store/transaction/view/' . $form_values['txnid'];
}
break;
default: // Credit card error: card was not charged.
switch (variable_get('linkpoint_api_format_not_accepted',0)) {
case 0:
$error=$retarr['r_approved'];
break;
case 1:
$error=preg_replace('/^(.*?: )/','',$retarr['r_error']);
break;
case 2:
$error=$retarr['r_error'];
break;
}
drupal_set_message(t('Your card was not billed for the following reason:<br><strong>%linkpoint_api_error</strong>', array('%linkpoint_api_error' => t($error))), 'error');
return str_replace('http://', 'https://', $base_url) . url('../store/payment/linkpoint_api/form/'. $form_values['txnid']);
break;
}
}
If anyone can help, it would be appreciated.
Comments
did you ever get linkpoint working?
did you ever get this working? I also need linkpoint fora client...
working for 5.0?
Did you get this code working for Ecommerce 5.0? I'm interested in using (or helping with) this code for a current client.
Thanks,
Bjorn
This could help
Also, check your form_value variables, 'cause I think you dont have to use form_value['details'] as prefix.
I have checked generated XML and found out that it doesn contain ccard data.
Good work.
http://www.error1002.com/sgs_errors.php#installments
SGS-020003: Invalid XML
There are a couple different things that will cause this error.
1. Make sure the amount for chargetotal is not blank.
2. Make sure expiration year is only 2 digits
3. Make sure there is no dollar sign for the amount.
4. Make sure there are no symbols like an ampersand, apostrophe, or letters with accents
5. If there is no shipping make sure you pass zero for the amount
6. Make sure there are no commas in the amount for chargetotal
SGS-020003: Invalid XML - invalid tag installments
At the moment you can only set installments from 1-99 or -1 for an infinite amount of times.
a year later...
it is a year later, did you get this to work? if not is the above the last try at it?
How about making it a separate module, ec_linkpoint
And change prefixing from linkpoint_api to ec_linkpoint
Then maybe.... the install could be
????
revisiting this module need
I dusted off my notes and I am hacking on this.
I have a module that is working.. At least partially - I will upload it somewhere and ask drupal to allow me to post, cvs.
Linkpoint api Module posted and ready for trying.
Okay It seems to be working, Till I get permission to post as a project here is a page with it for download,
Nov. 17, 2008:
https://www.cocoavillagepublishing.com/development/drupal/e-commerce/lin...
Drupal Project
OK, it is now a drupal project!
http://drupal.org/project/ec_linkpoint