_mode = $mode; $this->_paymentProcessor = $paymentProcessor; } /** * singleton function used to manage this object * * @param string $mode the mode of operation: live or test * * @return object * @static * */ static function &singleton($mode, &$paymentProcessor) { $processorName = $paymentProcessor['name']; if (self::$_singleton[$processorName] === NULL) { self::$_singleton[$processorName] = new CRM_Core_Payment_FirstData($mode, $paymentProcessor); } return self::$_singleton[$processorName]; } /********************************************************** * This function is set up and put here to make the mapping of fields * from the params object as visually clear as possible for easy editing * * Comment out irrelevant fields **********************************************************/ function mapProcessorFieldstoParams($params) { /*concatenate full customer name first - code from EWAY gateway */ $credit_card_name = $params['first_name'] . " "; if (strlen($params['middle_name']) > 0) { $credit_card_name .= $params['middle_name'] . " "; } $credit_card_name .= $params['last_name']; //compile array /********************************************************** * Payment Processor field name **fields from $params array *** *******************************************************************/ $requestFields['cardnumber'] = $params['credit_card_number']; $requestFields['chargetotal'] = $params['amount']; $requestFields['cardexpmonth'] = sprintf('%02d', (int) $params['month']); $requestFields['cardexpyear'] = substr($params['year'], 2, 2); $requestFields['cvmvalue'] = $params['cvv2']; $requestFields['cvmindicator'] = "provided"; $requestFields['name'] = $credit_card_name; $requestFields['address1'] = $params['street_address']; $requestFields['city'] = $params['city']; $requestFields['state'] = $params['state_province']; $requestFields['zip'] = $params['postal_code']; $requestFields['country'] = $params['country']; $requestFields['email'] = $params['email']; $requestFields['ip'] = $params['ip_address']; $requestFields['transactionorigin'] = "Eci"; #32 character string $requestFields['invoice_number'] = $params['invoiceID']; $requestFields['ordertype'] = $params['payment_action']; $requestFields['comments'] = $params['description']; //**********************set 'result' for live testing ************************** // $requestFields[ 'result' ] = ""; #set to "Good", "Decline" or "Duplicate" // $requestFields[ '' ] = $params[ 'qfKey' ]; // $requestFields[ '' ] = $params[ 'amount_other' ]; // $requestFields[ '' ] = $params[ 'billing_first_name' ]; // $requestFields[ '' ] = $params[ 'billing_middle_name' ]; // $requestFields[ '' ] = $params[ 'billing_last_name' ]; // $requestFields[ '' ] = $params[ 'contributionType_name' ]; // $requestFields[ '' ] = $params[ 'contributionPageID' ]; // $requestFields[ '' ] = $params[ 'contributionType_accounting_code' ]; // $requestFields[ '' ] = $params['amount_level' ]; // $requestFields[ '' ] = $params['credit_card_type' ]; // $requestFields[ 'addrnum' ] = numeric portion of street address - not yet implemented // $requestFields[ 'taxexempt' ] taxexempt status (Y or N) - not implemented return $requestFields; } /********************************************************** * This function sends request and receives response from * the processor **********************************************************/ function doDirectPayment(&$params) { if ($params['is_recur'] == TRUE) { CRM_Core_Error::fatal(ts('%1 - recurring payments not implemented', array(1 => $paymentProcessor))); } if (!defined('CURLOPT_SSLCERT')) { CRM_Core_Error::fatal(ts('%1 - Gateway requires curl with SSL support', array(1 => $paymentProcessor))); } /********************************************************** * Create the array of variables to be sent to the processor from the $params array * passed into this function **********************************************************/ $requestFields = self::mapProcessorFieldstoParams($params); /********************************************************** * create FirstData request object **********************************************************/ require_once 'FirstData/lphp.php'; // $mylphp=new lphp; /********************************************************** * define variables for connecting with the gateway **********************************************************/ # Name and location of certificate file $key = $this->_paymentProcessor['password']; # Your store number $requestFields["configfile"] = $this->_paymentProcessor['user_name']; $port = "1129"; $host = $this->_paymentProcessor['url_site'] . ":" . $port . "/LSGSXML"; //---------------------------------------------------------------------------------------------------- // Check to see if we have a duplicate before we send //---------------------------------------------------------------------------------------------------- if ($this->_checkDupe($params['invoiceID'])) { return self::errorExit(9003, 'It appears that this transaction is a duplicate. Have you already submitted the form once? If so there may have been a connection problem. Check your email for a receipt from eWAY. If you do not receive a receipt within 2 hours you can try your transaction again. If you continue to have problems please contact the site administrator.'); } //---------------------------------------------------------------------------------------------------- // Convert to XML using function provided by payment processor //---------------------------------------------------------------------------------------------------- $requestxml = lphp::buildXML($requestFields); /*---------------------------------------------------------------------------------------------------- // Send to the payment information using cURL /---------------------------------------------------------------------------------------------------- */ $ch = curl_init($host); if (!$ch) { return self::errorExit(9004, 'Could not initiate connection to payment gateway'); } curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $requestxml); curl_setopt($ch, CURLOPT_SSLCERT, $key); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'verifySSL') ? 2 : 0); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'verifySSL')); // return the result on success, FALSE on failure curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_TIMEOUT, 36000); // ensures any Location headers are followed curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); // Send the data out over the wire //-------------------------------- $responseData = curl_exec($ch); //---------------------------------------------------------------------------------------------------- // See if we had a curl error - if so tell 'em and bail out // // NOTE: curl_error does not return a logical value (see its documentation), but // a string, which is empty when there was no error. //---------------------------------------------------------------------------------------------------- if ((curl_errno($ch) > 0) || (strlen(curl_error($ch)) > 0)) { $errorNum = curl_errno($ch); $errorDesc = curl_error($ch); // Paranoia - in the unlikley event that 'curl' errno fails if ($errorNum == 0) $errorNum = 9005; // Paranoia - in the unlikley event that 'curl' error fails if (strlen($errorDesc) == 0) $errorDesc = "Connection to payment gateway failed"; if ($errorNum == 60) { return self::errorExit($errorNum, "Curl error - " . $errorDesc . " Try this link for more information http://curl.haxx.se/docs/sslcerts.html"); } return self::errorExit($errorNum, "Curl error - " . $errorDesc . " your key is located at " . $key . " the url is " . $host . " xml is " . $requestxml . " processor response = " . $processorResponse); } //---------------------------------------------------------------------------------------------------- // If null data returned - tell 'em and bail out // // NOTE: You will not necessarily get a string back, if the request failed for // any reason, the return value will be the boolean false. //---------------------------------------------------------------------------------------------------- if (($responseData === FALSE) || (strlen($responseData) == 0)) { return self::errorExit(9006, "Error: Connection to payment gateway failed - no data returned."); } //---------------------------------------------------------------------------------------------------- // If gateway returned no data - tell 'em and bail out //---------------------------------------------------------------------------------------------------- if (empty($responseData)) { return self::errorExit(9007, "Error: No data returned from payment gateway."); } //---------------------------------------------------------------------------------------------------- // Success so far - close the curl and check the data //---------------------------------------------------------------------------------------------------- curl_close($ch); //---------------------------------------------------------------------------------------------------- // Payment successfully sent to gateway - process the response now //---------------------------------------------------------------------------------------------------- // $processorResponse = lphp::decodeXML($responseData); // transaction failed, print the reason if ($processorResponse["r_approved"] != "APPROVED") { return self::errorExit(9009, "Error: [" . $processorResponse['r_error'] . "] - from payment processor"); } else { //----------------------------------------------------------------------------------------------------- // Cross-Check - the unique 'TrxnReference' we sent out should match the just received 'TrxnReference' // // this section not used as the processor doesn't appear to pass back our invoice no. Code in eWay model if // used later //----------------------------------------------------------------------------------------------------- //============= // Success ! //============= $params['trxn_result_code'] = $processorResponse['r_message']; $params['trxn_id'] = $processorResponse['r_ref']; CRM_Core_Error::debug_log_message("r_authresponse " . $processorResponse['r_authresponse']); CRM_Core_Error::debug_log_message("r_code " . $processorResponse['r_code']); CRM_Core_Error::debug_log_message("r_tdate " . $processorResponse['r_tdate']); CRM_Core_Error::debug_log_message("r_avs " . $processorResponse['r_avs']); CRM_Core_Error::debug_log_message("r_ordernum " . $processorResponse['r_ordernum']); CRM_Core_Error::debug_log_message("r_error " . $processorResponse['r_error']); CRM_Core_Error::debug_log_message("csp " . $processorResponse['r_csp']); CRM_Core_Error::debug_log_message("r_message " . $processorResponse['r_message']); CRM_Core_Error::debug_log_message("r_ref " . $processorResponse['r_ref']); CRM_Core_Error::debug_log_message("r_time " . $processorResponse['r_time']); return $params; } } // end function doDirectPayment /** * Checks to see if invoice_id already exists in db * * @param int $invoiceId The ID to check * * @return bool True if ID exists, else false */ function _checkDupe($invoiceId) { $contribution = new CRM_Contribute_DAO_Contribution(); $contribution->invoice_id = $invoiceId; return $contribution->find(); } /************************************************** * Produces error message and returns from class **************************************************/ function &errorExit($errorCode = NULL, $errorMessage = NULL) { $e = CRM_Core_Error::singleton(); if ($errorCode) { $e->push($errorCode, 0, NULL, $errorMessage); } else { $e->push(9000, 0, NULL, 'Unknown System Error.'); } return $e; } /************************************************** * NOTE: 'doTransferCheckout' not implemented **************************************************/ function doTransferCheckout(&$params, $component) { CRM_Core_Error::fatal(ts('This function is not implemented')); } /******************************************************************************************** * This public function checks to see if we have the right processor config values set * * NOTE: Called by Events and Contribute to check config params are set prior to trying * register any credit card details * * @param string $mode the mode we are operating in (live or test) - not used * * returns string $errorMsg if any errors found - null if OK * ********************************************************************************************/ // function checkConfig( $mode ) // CiviCRM V1.9 Declaration // CiviCRM V2.0 Declaration function checkConfig() { $errorMsg = array(); if (empty($this->_paymentProcessor['user_name'])) { $errorMsg[] = ts(' Store Name is not set for this payment processor'); } if (empty($this->_paymentProcessor['url_site'])) { $errorMsg[] = ts(' URL is not set for this payment processor'); } if (!empty($errorMsg)) { return implode('
', $errorMsg); } else { return NULL; } } } // end class CRM_Core_Payment_FirstData