TimeTrex Community Edition v16.2.0
This commit is contained in:
506
classes/pear/Payment/Process/BeanstreamEFT.php
Normal file
506
classes/pear/Payment/Process/BeanstreamEFT.php
Normal file
@@ -0,0 +1,506 @@
|
||||
<?php
|
||||
|
||||
/* vim: set expandtab tabstop=4 shiftwidth=4: */
|
||||
|
||||
/**
|
||||
* Beanstream Batch EFT processor
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* LICENSE: This source file is subject to version 3.0 of the PHP license
|
||||
* that is available through the world-wide-web at the following URI:
|
||||
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
|
||||
* the PHP License and are unable to obtain it through the web, please
|
||||
* send a note to license@php.net so we can mail you a copy immediately.
|
||||
*
|
||||
* @category Payment
|
||||
* @package Payment_Process
|
||||
* @author Mike Benoit <ipso@snappymail.ca> |
|
||||
* @copyright 1997-2005 The PHP Group
|
||||
* @license http://www.php.net/license/3_0.txt PHP License 3.0
|
||||
* @version CVS: $Id: Beanstream.php,v 1.33 2005/11/01 18:55:29 jausions Exp $
|
||||
* @link http://pear.php.net/package/Payment_Process
|
||||
*/
|
||||
|
||||
require_once 'Payment/Process.php';
|
||||
require_once 'Payment/Process/Common.php';
|
||||
require_once 'Net/Curl.php';
|
||||
|
||||
/**
|
||||
* Defines global variables
|
||||
*/
|
||||
$GLOBALS['_Payment_Process_BeanstreamEFT'] = array(
|
||||
PAYMENT_PROCESS_ACTION_NORMAL => 'D',
|
||||
PAYMENT_PROCESS_ACTION_AUTHONLY => NULL,
|
||||
PAYMENT_PROCESS_ACTION_POSTAUTH => NULL,
|
||||
PAYMENT_PROCESS_ACTION_VOID => 'VD'
|
||||
);
|
||||
|
||||
/**
|
||||
* Payment_Process_Beanstream
|
||||
*
|
||||
* This is a processor for Beanstream's merchant payment gateway.
|
||||
* (http://www.beanstream.com/)
|
||||
*
|
||||
* @package Payment_Process
|
||||
* @author Mike Benoit <ipso@snappymail.ca>
|
||||
* @version @version@
|
||||
* @link http://www.beanstream.com/
|
||||
*/
|
||||
class Payment_Process_BeanstreamEFT extends Payment_Process_Common
|
||||
{
|
||||
/**
|
||||
* Front-end -> back-end field map.
|
||||
*
|
||||
* This array contains the mapping from front-end fields (defined in
|
||||
* the Payment_Process class) to the field names Beanstream requires.
|
||||
*
|
||||
* @see _prepare()
|
||||
* @access private
|
||||
*/
|
||||
var $_fieldMap = array(
|
||||
// Required
|
||||
'customerId' => 'loginCompany',
|
||||
//'login' => 'loginUser',
|
||||
//'password' => 'loginPass',
|
||||
'password' => 'passCode',
|
||||
'action' => 'trnType',
|
||||
'invoiceNumber' => 'trnOrderNumber',
|
||||
'amount' => 'trnAmount',
|
||||
'processDate' => 'processDate',
|
||||
'batchFile' => 'batchFile',
|
||||
//'name' => 'name',
|
||||
//'address' => '',
|
||||
//'city' => '',
|
||||
//'state' => '',
|
||||
//'country' => '',
|
||||
//'postalCode' => '',
|
||||
//'zip' => '',
|
||||
//'phone' => '',
|
||||
//'email' => '',
|
||||
//'errorPage' => 'errorPage',
|
||||
);
|
||||
|
||||
/**
|
||||
* $_typeFieldMap
|
||||
*
|
||||
* @author Joe Stump <joe@joestump.net>
|
||||
* @access protected
|
||||
*/
|
||||
var $_typeFieldMap = array(
|
||||
'ACH' => array(
|
||||
'routingCode' => 'routingNumber',
|
||||
'accountNumber' => 'accountNumber',
|
||||
'accountCode' => 'accountCode',
|
||||
'name' => 'ordName'
|
||||
),
|
||||
'EFT' => array(
|
||||
'institutionCode' => 'institutionId',
|
||||
'routingCode' => 'transitNumber',
|
||||
'accountNumber' => 'accountNumber',
|
||||
'name' => 'ordName'
|
||||
),
|
||||
);
|
||||
|
||||
/**
|
||||
* Default options for this processor.
|
||||
*
|
||||
* @see Payment_Process::setOptions()
|
||||
* @access private
|
||||
*/
|
||||
var $_defaultOptions = array(
|
||||
'authorizeUri' => 'https://www.beanstream.com/scripts/batch_upload.asp',
|
||||
//'requestType' => 'BACKEND',
|
||||
//'cavEnabled' => 0,
|
||||
'ServiceVersion' => '1.1',
|
||||
);
|
||||
|
||||
/**
|
||||
* List of possible encapsulation characters
|
||||
*
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
var $_encapChars = '|~#$^*_=+-`{}![]:";<>?/&';
|
||||
|
||||
/**
|
||||
* Has the transaction been processed?
|
||||
*
|
||||
* @type boolean
|
||||
* @access private
|
||||
*/
|
||||
var $_processed = false;
|
||||
|
||||
/**
|
||||
* The response body sent back from the gateway.
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
var $_responseBody = '';
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $options Class options to set.
|
||||
* @see Payment_Process::setOptions()
|
||||
* @return void
|
||||
*/
|
||||
function __construct($options = false)
|
||||
{
|
||||
parent::__construct($options);
|
||||
$this->_driver = 'BeanstreamEFT';
|
||||
//$this->_makeRequired('customerId','login', 'password', 'action', 'invoiceNumber');
|
||||
$this->_makeRequired('customerId','password', 'action', 'invoiceNumber');
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the batch data.
|
||||
*
|
||||
* This function handles the 'testTransaction' option, which is specific to
|
||||
* this processor.
|
||||
*/
|
||||
function _prepare()
|
||||
{
|
||||
$result = parent::_prepare();
|
||||
if ( $result !== TRUE ) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
//Build batch file for each type of transaction type.
|
||||
if ($this->_payment->getType() == 'EFT') {
|
||||
$batch_fields = array('trnType', 'institutionId', 'transitNumber', 'accountNumber', 'trnAmount', 'trnOrderNumber', 'ordName' );
|
||||
if ( is_array($batch_fields) ) {
|
||||
$batch_data[] = substr( $this->_payment->getType(), 0, 1);
|
||||
foreach( $batch_fields as $batch_field ) {
|
||||
$batch_data[] = $this->_data[$batch_field];
|
||||
}
|
||||
}
|
||||
} elseif ($this->_payment->getType() == 'ACH') {
|
||||
$batch_fields = array('trnType', 'routingNumber', 'accountNumber', 'accountCode', 'trnAmount', 'trnOrderNumber', 'ordName' );
|
||||
if ( is_array($batch_fields) ) {
|
||||
$batch_data[] = substr( $this->_payment->getType(), 0, 1);
|
||||
foreach( $batch_fields as $batch_field ) {
|
||||
if ( $batch_field == 'accountCode' ) {
|
||||
$batch_data[] = 'CC';
|
||||
} else {
|
||||
$batch_data[] = $this->_data[$batch_field];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( is_array($batch_data) ) {
|
||||
$this->batchFile = implode(',', $batch_data);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the transaction.
|
||||
*
|
||||
* Success here doesn't mean the transaction was approved. It means
|
||||
* the transaction was sent and processed without technical difficulties.
|
||||
*
|
||||
* @return mixed Payment_Process_Result on success, PEAR_Error on failure
|
||||
* @access public
|
||||
*/
|
||||
function &process()
|
||||
{
|
||||
// Sanity check
|
||||
$result = $this->validate();
|
||||
if (PEAR::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Prepare the data
|
||||
$result = $this->_prepare();
|
||||
if (PEAR::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$fields = $this->_prepareQueryString();
|
||||
if (PEAR::isError($fields)) {
|
||||
return $fields;
|
||||
}
|
||||
|
||||
// Don't die partway through
|
||||
PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
|
||||
|
||||
//Must use GET for login information.
|
||||
$curl = new Net_Curl($this->_options['authorizeUri'].'?'.$fields);
|
||||
$curl->timeout = 300;
|
||||
if (PEAR::isError($curl)) {
|
||||
PEAR::popErrorHandling();
|
||||
return $curl;
|
||||
}
|
||||
|
||||
$temp_file_prefix = 'eft_';
|
||||
if ( isset($this->_data['trnOrderNumber']) AND preg_match( '/^[A-Z0-9_\-]+$/i', $this->_data['trnOrderNumber'] ) ) {
|
||||
$temp_file_prefix .= $this->_data['trnOrderNumber'].'_';
|
||||
}
|
||||
$temp_file = tempnam( sys_get_temp_dir(), $temp_file_prefix ).'.csv';
|
||||
file_put_contents( $temp_file, $this->batchFile);
|
||||
|
||||
if ( class_exists('\CURLFile') ) {
|
||||
$curl->fields = array('batchFile' => new \CURLFile( $temp_file ) ); //PHP v5.5+ method.
|
||||
} else {
|
||||
$curl->fields = array('batchFile' => '@'.$temp_file); //Pre PHP v5.5 method.
|
||||
}
|
||||
|
||||
$curl->userAgent = 'PEAR Payment_Process_Beanstream 0.1';
|
||||
|
||||
//$curl->verboseAll();
|
||||
|
||||
$result = $curl->execute();
|
||||
unlink($temp_file);
|
||||
|
||||
if (PEAR::isError($result)) {
|
||||
PEAR::popErrorHandling();
|
||||
return $result;
|
||||
} else {
|
||||
$curl->close();
|
||||
}
|
||||
|
||||
$this->_responseBody = trim($result);
|
||||
$this->_processed = true;
|
||||
|
||||
// Restore error handling
|
||||
PEAR::popErrorHandling();
|
||||
|
||||
$response = Payment_Process_Result::factory($this->_driver,
|
||||
$this->_responseBody,
|
||||
$this);
|
||||
|
||||
if (!PEAR::isError($response)) {
|
||||
$response->parse();
|
||||
}
|
||||
$response->action = $this->action;
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a callback from payment gateway
|
||||
*
|
||||
* Success here doesn't mean the transaction was approved. It means
|
||||
* the callback was received and processed without technical difficulties.
|
||||
*
|
||||
* @return mixed Payment_Process_Result on success, PEAR_Error on failure
|
||||
*/
|
||||
function &processCallback()
|
||||
{
|
||||
$this->_responseBody = $_POST;
|
||||
$this->_processed = true;
|
||||
|
||||
$response = &Payment_Process_Result::factory($this->_driver,
|
||||
$this->_responseBody);
|
||||
if (!PEAR::isError($response)) {
|
||||
$response->_request = $this;
|
||||
$response->parseCallback();
|
||||
|
||||
$r = $response->isLegitimate();
|
||||
if (PEAR::isError($r)) {
|
||||
return $r;
|
||||
|
||||
} elseif ($r === false) {
|
||||
return PEAR::raiseError('Illegitimate callback from gateway.');
|
||||
}
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get (completed) transaction status.
|
||||
*
|
||||
* @return string Two-digit status returned from gateway.
|
||||
*/
|
||||
function getStatus()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the POST query string.
|
||||
*
|
||||
* You will need PHP_Compat::str_split() if you run this processor
|
||||
* under PHP 4.
|
||||
*
|
||||
* @access private
|
||||
* @return string The query string
|
||||
*/
|
||||
function _prepareQueryString()
|
||||
{
|
||||
//$url_fields = array('ServiceVersion', 'loginCompany', 'loginUser', 'loginPass', 'processDate' );
|
||||
$url_fields = array('ServiceVersion', 'loginCompany', 'passCode', 'processDate' );
|
||||
|
||||
$data = array_merge($this->_options, $this->_data);
|
||||
|
||||
foreach ($data as $key => $val) {
|
||||
if ( in_array($key, $url_fields) AND strlen($val) > 0 ) {
|
||||
//if ( strlen($val) > 0 ) {
|
||||
$return[] = $key.'='.urlencode($val);
|
||||
}
|
||||
}
|
||||
|
||||
$retval = implode('&', $return);
|
||||
|
||||
return $retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the charge amount.
|
||||
*
|
||||
* Charge amount must be 8 characters long, double-precision.
|
||||
* Current min/max are rather arbitrarily set to $0.01 and $99999.99,
|
||||
* respectively.
|
||||
*
|
||||
* @return boolean true on success, false otherwise
|
||||
*/
|
||||
function _validateAmount()
|
||||
{
|
||||
return Validate::number($this->amount, array(
|
||||
'decimal' => '.',
|
||||
'dec_prec' => 2,
|
||||
'min' => 0.01,
|
||||
'max' => 99999.99
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* _handleAmount
|
||||
*
|
||||
* Amounts must always be in pennies.
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
function _handleAmount()
|
||||
{
|
||||
$this->_data['trnAmount'] = $this->amount = $this->amount*100;
|
||||
}
|
||||
|
||||
/**
|
||||
* _handleProcessDate
|
||||
*
|
||||
* We need to make sure process date is in format YYYYMMDD and if its after 11AM it must be the next day.
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
function _handleProcessDate()
|
||||
{
|
||||
if ( isset($this->processDate) ) {
|
||||
$epoch = (int)$this->processDate;
|
||||
} else {
|
||||
$this->processDate = FALSE;
|
||||
$epoch = time();
|
||||
}
|
||||
|
||||
if ( $epoch < time() ) {
|
||||
$epoch = time();
|
||||
}
|
||||
|
||||
$cutoff_hour = date('G', $epoch );
|
||||
if ( $cutoff_hour > 10 ) { // 11AM
|
||||
//Process date is next day
|
||||
$epoch += 86400;
|
||||
} else {
|
||||
//Process date can be today.
|
||||
}
|
||||
|
||||
$this->processDate = $this->_data['processDate'] = date('Ymd', $epoch );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Payment_Process_Result_BeanstreamEFT extends Payment_Process_Result {
|
||||
|
||||
var $_statusCodeMap = array('1' => PAYMENT_PROCESS_RESULT_APPROVED,
|
||||
'2' => PAYMENT_PROCESS_RESULT_OTHER,
|
||||
'3' => PAYMENT_PROCESS_RESULT_OTHER,
|
||||
'4' => PAYMENT_PROCESS_RESULT_REVIEW,
|
||||
'5' => PAYMENT_PROCESS_RESULT_REVIEW,
|
||||
'6' => PAYMENT_PROCESS_RESULT_REVIEW,
|
||||
'7' => PAYMENT_PROCESS_RESULT_DECLINED,
|
||||
'8' => PAYMENT_PROCESS_RESULT_REVIEW,
|
||||
'9' => PAYMENT_PROCESS_RESULT_REVIEW,
|
||||
'10' => PAYMENT_PROCESS_RESULT_REVIEW,
|
||||
'11' => PAYMENT_PROCESS_RESULT_REVIEW,
|
||||
'12' => PAYMENT_PROCESS_RESULT_REVIEW,
|
||||
'13' => PAYMENT_PROCESS_RESULT_REVIEW,
|
||||
);
|
||||
|
||||
var $_statusCodeMessages = array(
|
||||
'1' => 'File successfully received',
|
||||
'2' => 'Secure connection required',
|
||||
'3' => 'Service version not supported',
|
||||
'4' => 'Invalid login credentials',
|
||||
'5' => 'Insufficient user permissions',
|
||||
'6' => 'Batch Processing service not enabled',
|
||||
'7' => 'Invalid processing date',
|
||||
'8' => 'Service is busy importing another file. Try again later',
|
||||
'9' => 'File greater than maximum allowable size',
|
||||
'10' => 'Unexpected error',
|
||||
'11' => 'No batch file received in request',
|
||||
'12' => 'Merchant account status cannot be Disabled or Closed for operation',
|
||||
'13' => 'Upload rejected. File name is limited to 32 characters in length, including file type extension',
|
||||
);
|
||||
|
||||
var $_fieldMap = array('0' => 'code',
|
||||
'2' => 'messageCode',
|
||||
'3' => 'message',
|
||||
'4' => 'approvalCode',
|
||||
'5' => 'avsCode',
|
||||
'6' => 'transactionId',
|
||||
'7' => 'invoiceNumber',
|
||||
'8' => 'description',
|
||||
'9' => 'amount',
|
||||
'12' => 'customerId',
|
||||
'37' => 'md5Hash',
|
||||
'38' => 'cvvCode'
|
||||
);
|
||||
|
||||
function Payment_Process_Response_BeanstreamEFT($rawResponse)
|
||||
{
|
||||
$this->Payment_Process_Response($rawResponse);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the data received from the payment gateway
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
function parse()
|
||||
{
|
||||
if ( preg_match('/<code>([\d]+)<\/code>/i', $this->_rawResponse, $code_match ) ) {
|
||||
if ( isset($code_match[1]) ) {
|
||||
$code = (int)$code_match[1];
|
||||
|
||||
$this->code = $code;
|
||||
$this->messageCode = $code;
|
||||
|
||||
if ( $code == 1 ) {
|
||||
$this->_returnCode = PAYMENT_PROCESS_RESULT_APPROVED;
|
||||
|
||||
if ( preg_match('/<batch_id>(.*)<\/batch_id>/i', $this->_rawResponse, $batch_id_match ) ) {
|
||||
$this->approvalCode = $this->transactionId = $batch_id_match[1];
|
||||
}
|
||||
} else {
|
||||
$this->_returnCode = PAYMENT_PROCESS_RESULT_DECLINED;
|
||||
}
|
||||
|
||||
if ( preg_match('/<message>(.*)<\/message>/i', $this->_rawResponse, $message_match ) ) {
|
||||
$this->message = $message_match[1] .' (Code: '. $code .')';
|
||||
}
|
||||
|
||||
} else {
|
||||
$this->_returnCode = PAYMENT_PROCESS_RESULT_OTHER;
|
||||
$this->message = 'Error parsing response.';
|
||||
}
|
||||
} else {
|
||||
$this->_returnCode = PAYMENT_PROCESS_RESULT_OTHER;
|
||||
$this->message = 'Error parsing response.';
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
Reference in New Issue
Block a user