a59884a75a28ccb790f048815887ac477096a24a
3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.5 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2014 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the Affero General Public License Version 1, |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the Affero General Public License for more details. |
19 | You should have received a copy of the Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
32 * @copyright CiviCRM LLC (c) 2004-2014
36 class CRM_Core_Payment_IATS
extends CRM_Core_Payment
{
37 # (not used, implicit in the API, might need to convert?)
38 CONST CHARSET
= 'UFT-8';
39 /* check IATS website for additional supported currencies */
40 CONST CURRENCIES
= 'CAD,USD,AUD,GBP,EUR,NZD';
43 * We only need one instance of this object. So we use the singleton
44 * pattern and cache the instance in this variable
49 static private $_singleton = NULL;
54 * @param string $mode the mode of operation: live or test
56 * @param $paymentProcessor
58 * @return \CRM_Core_Payment_IATS
60 function __construct($mode, &$paymentProcessor) {
61 $this->_paymentProcessor
= $paymentProcessor;
62 $this->_processorName
= ts('IATS');
64 // get merchant data from config
65 $config = CRM_Core_Config
::singleton();
67 $this->_profile
['mode'] = $mode;
68 $this->_profile
['webserver'] = parse_url($this->_paymentProcessor
['url_site'], PHP_URL_HOST
);
69 $currencyID = $config->defaultCurrency
;
71 if (!in_array($currencyID, explode(',', self
::CURRENCIES
))) {
72 // Configuration error: default currency must be in CURRENCIES const
73 return self
::error('Invalid configuration:' . $currencyID . ', you must use one of ' . self
::CURRENCIES
. ' with IATS');
77 static function &singleton($mode, &$paymentProcessor) {
78 $processorName = $paymentProcessor['name'];
79 if (self
::$_singleton[$processorName] === NULL) {
80 self
::$_singleton[$processorName] = new CRM_Core_Payment_IATS($mode, $paymentProcessor);
82 return self
::$_singleton[$processorName];
86 * This function collects all the information from a web/api form and invokes
87 * the relevant payment processor specific functions to perform the transaction
89 * @param array $params assoc array of input parameters for this transaction
91 * @return array the result in an nice formatted array (or an error object)
94 function doDirectPayment(&$params) {
96 // foreach($params as $key => $value) {
97 // $result .= "<strong>$key</strong>: $value<br />";
99 // return self::error($result);
100 // make sure i've been called correctly ...
102 if (!$this->_profile
) {
103 return self
::error('Unexpected error, missing profile');
105 if (!in_array($params['currencyID'], explode(',', self
::CURRENCIES
))) {
106 return self
::error('Invalid currency selection, must be one of ' . self
::CURRENCIES
);
108 $isRecur = CRM_Utils_Array
::value('is_recur', $params, FALSE);
109 // AgentCode = $this->_paymentProcessor['signature'];
110 // Password = $this->_paymentProcessor['password' ];
111 // beginning of modified sample code from IATS php api include IATS supplied api library
114 include_once ('Services/IATS/iats_reoccur.php');
115 $iatslink1 = new iatslinkReoccur
;
118 include_once ('Services/IATS/iatslink.php');
119 $iatslink1 = new iatslink
;
122 $iatslink1->setTestMode($this->_profile
['mode'] != 'live');
123 $iatslink1->setWebServer($this->_profile
['webserver']);
125 // return self::error($this->_profile['webserver']);
127 // Put your invoice here
128 $iatslink1->setInvoiceNumber($params['invoiceID']);
130 // $iatslink1->setCardType("VISA");
131 // If CardType is not set, iatslink will find the cardType
132 // CardType not set because IATS uses different names!
133 // $iatslink1->setCardType($params['credit_card_type']);
135 $iatslink1->setCardNumber($params['credit_card_number']);
136 $expiry_string = sprintf('%02d/%02d', $params['month'], ($params['year'] %
100));
137 $iatslink1->setCardExpiry($expiry_string);
138 $amount = sprintf('%01.2f', $params['amount']);
140 $iatslink1->setDollarAmount($amount);
142 //$iatslink1->setDollarAmount(-1.15);
144 $AgentCode = $this->_paymentProcessor
['signature'];
145 $Password = $this->_paymentProcessor
['password'];
146 $iatslink1->setAgentCode($AgentCode);
147 $iatslink1->setPassword($Password);
148 // send IATS my invoiceID to match things up later
149 $iatslink1->setInvoiceNumber($params['invoiceID']);
151 // Set billing fields
152 $iatslink1->setFirstName($params['billing_first_name']);
153 $iatslink1->setLastName($params['billing_last_name']);
154 $iatslink1->setStreetAddress($params['street_address']);
155 $iatslink1->setCity($params['city']);
156 $iatslink1->setState($params['state_province']);
157 $iatslink1->setZipCode($params['postal_code']);
158 // and now go! ... uses curl to post and retrieve values
159 // after various data integrity tests
162 // cvv2 only seems to get set for this!
163 $iatslink1->setCVV2($params['cvv2']);
165 // Allow further manipulation of the arguments via custom hooks,
166 // before initiating processCreditCard()
167 CRM_Utils_Hook
::alterPaymentProcessorParams($this, $params, $iatslink1);
169 $iatslink1->processCreditCard();
170 // extra fields for recurring donations
173 // implicit - test?: 1 == $params['frequency_interval'];
174 $scheduleType = NULL;
175 if ($params['installments']) {
176 $paymentsRecur = $params['installments'] - 1;
178 // handle unspecified installments by setting to 10 years, IATS doesn't allow indefinitely recurring contributions
180 switch ($params['frequency_unit']) {
182 $paymentsRecur = 520;
184 $paymentsRecur = 120;
187 // IATS requires end date, calculated here
189 // to be converted to date format later
191 $date = getdate($startTime);
193 switch ($params['frequency_unit']) {
195 $scheduleType = 'WEEKLY';
196 $scheduleDate = $date['wday'] +
1;
197 $endTime = $startTime +
($paymentsRecur * 7 * 24 * 60 * 60);
201 $scheduleType = 'MONTHLY';
202 $scheduleDate = $date['mday'];
203 $date['mon'] +
= $paymentsRecur;
204 while ($date['mon'] > 12) {
208 $endTime = mktime($date['hours'], $date['minutes'], $date['seconds'], $date['mon'], $date['mday'], $date['year']);
212 die('Invalid frequency unit!');
215 $endDate = date('Y-m-d', $endTime);
216 $startDate = date('Y-m-d', $startTime);
217 $iatslink1->setReoccuringStatus("ON");
218 $iatslink1->setBeginDate($startDate);
219 $iatslink1->setEndDate($endDate);
220 $iatslink1->setScheduleType($scheduleType);
221 $iatslink1->setScheduleDate($scheduleDate);
223 // Allow further manipulation of the arguments via custom hooks,
224 // before initiating the curl process
225 CRM_Utils_Hook
::alterPaymentProcessorParams($this, $params, $iatslink1);
227 // this next line is the reoccc equiv of processCreditCard
228 $iatslink1->createReoccCustomer();
231 if ($iatslink1->getStatus() == 1) {
232 // this just means we got some kind of answer, not necessarily approved
233 $result = $iatslink1->getAuthorizationResult();
234 //return self::error($result);
235 $result = explode(':', $result, 2);
236 $trxn_result = trim($result[0]);
237 $trxn_id = trim($result[1]);
238 if ($trxn_result == 'OK') {
239 $params['trxn_id'] = $trxn_id . ':' . time();
240 $params['gross_amount'] = $amount;
243 // createReoccCustomer() may return other, valid result codes...
244 elseif (preg_match('/A\d+/', $trxn_result)) {
245 $params['trxn_id'] = $trxn_result;
246 $params['gross_amount'] = $amount;
250 return self
::error($trxn_id);
254 return self
::error($iatslink1->getError());
258 function &error($error = NULL) {
259 $e = CRM_Core_Error
::singleton();
260 if (is_object($error)) {
261 $e->push($error->getResponseCode(),
266 elseif ($error && is_numeric($error)) {
269 $this->errorString($error)
272 elseif (is_string($error)) {
279 $e->push(9001, 0, NULL, "Unknown System Error.");
284 function errorString($error_id) {
286 1 => 'Agent Code has not been set up on the authorization system.',
287 2 => 'Unable to process transaction. Verify and re-enter credit card information.',
288 3 => 'Charge card expired.',
289 4 => 'Incorrect expiration date.',
290 5 => 'Invalid transaction. Verify and re-enter credit card information.',
291 6 => 'Transaction not supported by institution.',
292 7 => 'Lost or stolen card.',
293 8 => 'Invalid card status.',
294 9 => 'Restricted card status. Usually on corporate cards restricted to specific sales.',
295 10 => 'Error. Please verify and re-enter credit card information.',
296 11 => 'General decline code, may have different reasons for each card type. Please have your client call customer service.',
297 14 => 'This means that the credit card is over the limit.',
298 15 => 'Decline code, may have different reasons for each card type. Please have your client call customer service.',
299 16 => 'Invalid charge card number. Verify and re-enter credit card information.',
300 17 => 'Unable to authorize transaction. Verify card information with customer and re-enter. Could be invalid name or expiry date.',
301 18 => 'Card not supported by institution.',
302 19 => 'Incorrect CVV2.',
303 22 => 'Bank Timeout. Bank lines may be down or busy. Re-try transaction later.',
304 23 => 'System error. Re-try transaction later.',
305 24 => 'Charge card expired.',
306 25 => 'Capture card. Reported lost or stolen.',
307 27 => 'System error, please re-enter transaction.',
308 29 => 'Rejected by Ticketmaster.',
309 31 => 'Manual reject code ',
310 39 => 'Contact Ticketmaster 1-888-955-5455 ',
311 40 => 'Card not supported by Ticketmaster. Invalid cc number.',
312 41 => 'Invalid Expiry date ',
313 100 => 'Authorization system down. DO NOT REPROCESS.',
315 return ' <strong>' . $errors[(integer) $error_id] . '</strong>';
319 * This function checks to see if we have the right config values
321 * @internal param string $mode the mode we are operating in (live or test)
323 * @return string the error message if any
326 function checkConfig() {
329 if (empty($this->_paymentProcessor
['signature'])) {
330 $error[] = ts('Agent Code is not set in the Administer CiviCRM » System Settings » Payment Processors.');
333 if (empty($this->_paymentProcessor
['password'])) {
334 $error[] = ts('Password is not set in the Administer CiviCRM » System Settings » Payment Processors.');
337 if (!empty($error)) {
338 return implode('<p>', $error);