remove a couple of unrequired lines from test
[civicrm-core.git] / CRM / Core / Payment / IATS.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
232624b1 4 | CiviCRM version 4.4 |
6a488035
TO
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2013 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the Affero General Public License Version 1, |
12 | March 2002. |
13 | |
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. |
18 | |
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 +--------------------------------------------------------------------+
26*/
27
28/**
29 *
30 * @package CRM
31 * @author Alan Dixon
32 * @copyright CiviCRM LLC (c) 2004-2013
33 * $Id$
34 *
35 */
36class 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';
41
42 /**
43 * We only need one instance of this object. So we use the singleton
44 * pattern and cache the instance in this variable
45 *
46 * @var object
47 * @static
48 */
49 static private $_singleton = NULL;
50
51 /**
52 * Constructor
53 *
54 * @param string $mode the mode of operation: live or test
55 *
56 * @return void
57 */
58 function __construct($mode, &$paymentProcessor) {
59 $this->_paymentProcessor = $paymentProcessor;
60 $this->_processorName = ts('IATS');
61
62 // get merchant data from config
63 $config = CRM_Core_Config::singleton();
64 // live or test
65 $this->_profile['mode'] = $mode;
66 $this->_profile['webserver'] = parse_url($this->_paymentProcessor['url_site'], PHP_URL_HOST);
67 $currencyID = $config->defaultCurrency;
68
69 if (!in_array($currencyID, explode(',', self::CURRENCIES))) {
70 // Configuration error: default currency must be in CURRENCIES const
71 return self::error('Invalid configuration:' . $currencyID . ', you must use one of ' . self::CURRENCIES . ' with IATS');
72 }
73 }
74
75 static function &singleton($mode, &$paymentProcessor) {
76 $processorName = $paymentProcessor['name'];
77 if (self::$_singleton[$processorName] === NULL) {
78 self::$_singleton[$processorName] = new CRM_Core_Payment_IATS($mode, $paymentProcessor);
79 }
80 return self::$_singleton[$processorName];
81 }
82
83 function doDirectPayment(&$params) {
84 // $result = '';
85 // foreach($params as $key => $value) {
86 // $result .= "<strong>$key</strong>: $value<br />";
87 // }
88 // return self::error($result);
89 // make sure i've been called correctly ...
90
91 if (!$this->_profile) {
92 return self::error('Unexpected error, missing profile');
93 }
94 if (!in_array($params['currencyID'], explode(',', self::CURRENCIES))) {
95 return self::error('Invalid currency selection, must be one of ' . self::CURRENCIES);
96 }
97 $isRecur = $params['is_recur'];
98 // AgentCode = $this->_paymentProcessor['signature'];
99 // Password = $this->_paymentProcessor['password' ];
100 // beginning of modified sample code from IATS php api include IATS supplied api library
101
102 if ($isRecur) {
103 include_once ('Services/IATS/iats_reoccur.php');
104 $iatslink1 = new iatslinkReoccur;
105 }
106 else {
107 include_once ('Services/IATS/iatslink.php');
108 $iatslink1 = new iatslink;
109 }
110
111 $iatslink1->setTestMode($this->_profile['mode'] != 'live');
112 $iatslink1->setWebServer($this->_profile['webserver']);
113
114 // return self::error($this->_profile['webserver']);
115
116 // Put your invoice here
117 $iatslink1->setInvoiceNumber($params['invoiceID']);
118
119 // $iatslink1->setCardType("VISA");
120 // If CardType is not set, iatslink will find the cardType
121 // CardType not set because IATS uses different names!
122 // $iatslink1->setCardType($params['credit_card_type']);
123
124 $iatslink1->setCardNumber($params['credit_card_number']);
125 $expiry_string = sprintf('%02d/%02d', $params['month'], ($params['year'] % 100));
126 $iatslink1->setCardExpiry($expiry_string);
127 $amount = sprintf('%01.2f', $params['amount']);
128 // sell
129 $iatslink1->setDollarAmount($amount);
130 // refund
131 //$iatslink1->setDollarAmount(-1.15);
132
133 $AgentCode = $this->_paymentProcessor['signature'];
134 $Password = $this->_paymentProcessor['password'];
135 $iatslink1->setAgentCode($AgentCode);
136 $iatslink1->setPassword($Password);
137 // send IATS my invoiceID to match things up later
138 $iatslink1->setInvoiceNumber($params['invoiceID']);
139
140 // Set billing fields
141 $iatslink1->setFirstName($params['billing_first_name']);
142 $iatslink1->setLastName($params['billing_last_name']);
143 $iatslink1->setStreetAddress($params['street_address']);
144 $iatslink1->setCity($params['city']);
145 $iatslink1->setState($params['state_province']);
146 $iatslink1->setZipCode($params['postal_code']);
147 // and now go! ... uses curl to post and retrieve values
148 // after various data integrity tests
149 // simple version
150 if (!$isRecur) {
151 // cvv2 only seems to get set for this!
152 $iatslink1->setCVV2($params['cvv2']);
153
154 // Allow further manipulation of the arguments via custom hooks,
155 // before initiating processCreditCard()
156 CRM_Utils_Hook::alterPaymentProcessorParams($this, $params, $iatslink1);
157
158 $iatslink1->processCreditCard();
159 // extra fields for recurring donations
160 }
161 else {
162 // implicit - test?: 1 == $params['frequency_interval'];
163 $scheduleType = NULL;
164 if ($params['installments']) {
165 $paymentsRecur = $params['installments'] - 1;
166 }
167 // handle unspecified installments by setting to 10 years, IATS doesn't allow indefinitely recurring contributions
168 else {
169 switch ($params['frequency_unit']) {
170 case 'week':
171 $paymentsRecur = 520;
172 case 'month':
173 $paymentsRecur = 120;
174 }
175 }
176 // IATS requires end date, calculated here
177
178 // to be converted to date format later
179 $startTime = time();
180 $date = getdate($startTime);
181
182 switch ($params['frequency_unit']) {
183 case 'week':
184 $scheduleType = 'WEEKLY';
185 $scheduleDate = $date['wday'] + 1;
186 $endTime = $startTime + ($paymentsRecur * 7 * 24 * 60 * 60);
187 break;
188
189 case 'month':
190 $scheduleType = 'MONTHLY';
191 $scheduleDate = $date['mday'];
192 $date['mon'] += $paymentsRecur;
193 while ($date['mon'] > 12) {
194 $date['mon'] -= 12;
195 $date['year'] += 1;
196 }
197 $endTime = mktime($date['hours'], $date['minutes'], $date['seconds'], $date['mon'], $date['mday'], $date['year']);
198 break;
199
200 default:
201 die('Invalid frequency unit!');
202 break;
203 }
204 $endDate = date('Y-m-d', $endTime);
205 $startDate = date('Y-m-d', $startTime);
206 $iatslink1->setReoccuringStatus("ON");
207 $iatslink1->setBeginDate($startDate);
208 $iatslink1->setEndDate($endDate);
209 $iatslink1->setScheduleType($scheduleType);
210 $iatslink1->setScheduleDate($scheduleDate);
211
212 // Allow further manipulation of the arguments via custom hooks,
213 // before initiating the curl process
214 CRM_Utils_Hook::alterPaymentProcessorParams($this, $params, $iatslink1);
215
216 // this next line is the reoccc equiv of processCreditCard
217 $iatslink1->createReoccCustomer();
218 }
219
220 if ($iatslink1->getStatus() == 1) {
221 // this just means we got some kind of answer, not necessarily approved
222 $result = $iatslink1->getAuthorizationResult();
223 //return self::error($result);
224 $result = explode(':', $result, 2);
225 $trxn_result = trim($result[0]);
226 $trxn_id = trim($result[1]);
227 if ($trxn_result == 'OK') {
228 $params['trxn_id'] = $trxn_id . ':' . time();
229 $params['gross_amount'] = $amount;
230 return $params;
231 }
232 // createReoccCustomer() may return other, valid result codes...
233 elseif (preg_match('/A\d+/', $trxn_result)) {
234 $params['trxn_id'] = $trxn_result;
235 $params['gross_amount'] = $amount;
236 return $params;
237 }
238 else {
239 return self::error($trxn_id);
240 }
241 }
242 else {
243 return self::error($iatslink1->getError());
244 }
245 }
246
247 function &error($error = NULL) {
248 $e = CRM_Core_Error::singleton();
249 if (is_object($error)) {
250 $e->push($error->getResponseCode(),
251 0, NULL,
252 $error->getMessage()
253 );
254 }
255 elseif ($error && is_numeric($error)) {
256 $e->push($error,
257 0, NULL,
258 $this->errorString($error)
259 );
260 }
261 elseif (is_string($error)) {
262 $e->push(9002,
263 0, NULL,
264 $error
265 );
266 }
267 else {
268 $e->push(9001, 0, NULL, "Unknown System Error.");
269 }
270 return $e;
271 }
272
273 function errorString($error_id) {
274 $errors = array(
275 1 => 'Agent Code has not been set up on the authorization system.',
276 2 => 'Unable to process transaction. Verify and re-enter credit card information.',
277 3 => 'Charge card expired.',
278 4 => 'Incorrect expiration date.',
279 5 => 'Invalid transaction. Verify and re-enter credit card information.',
280 6 => 'Transaction not supported by institution.',
281 7 => 'Lost or stolen card.',
282 8 => 'Invalid card status.',
283 9 => 'Restricted card status. Usually on corporate cards restricted to specific sales.',
284 10 => 'Error. Please verify and re-enter credit card information.',
285 11 => 'General decline code, may have different reasons for each card type. Please have your client call customer service.',
286 14 => 'This means that the credit card is over the limit.',
287 15 => 'Decline code, may have different reasons for each card type. Please have your client call customer service.',
288 16 => 'Invalid charge card number. Verify and re-enter credit card information.',
289 17 => 'Unable to authorize transaction. Verify card information with customer and re-enter. Could be invalid name or expiry date.',
290 18 => 'Card not supported by institution.',
291 19 => 'Incorrect CVV2.',
292 22 => 'Bank Timeout. Bank lines may be down or busy. Re-try transaction later.',
293 23 => 'System error. Re-try transaction later.',
294 24 => 'Charge card expired.',
295 25 => 'Capture card. Reported lost or stolen.',
296 27 => 'System error, please re-enter transaction.',
297 29 => 'Rejected by Ticketmaster.',
298 31 => 'Manual reject code ',
299 39 => 'Contact Ticketmaster 1-888-955-5455 ',
300 40 => 'Card not supported by Ticketmaster. Invalid cc number.',
301 41 => 'Invalid Expiry date ',
302 100 => 'Authorization system down. DO NOT REPROCESS.',
303 );
304 return ' <strong>' . $errors[(integer) $error_id] . '</strong>';
305 }
306
307 /**
308 * This function checks to see if we have the right config values
309 *
310 * @param string $mode the mode we are operating in (live or test)
311 *
312 * @return string the error message if any
313 * @public
314 */
315 function checkConfig() {
316 $error = array();
317
318 if (empty($this->_paymentProcessor['signature'])) {
319 $error[] = ts('Agent Code is not set in the Administer CiviCRM &raquo; System Settings &raquo; Payment Processors.');
320 }
321
322 if (empty($this->_paymentProcessor['password'])) {
323 $error[] = ts('Password is not set in the Administer CiviCRM &raquo; System Settings &raquo; Payment Processors.');
324 }
325
326 if (!empty($error)) {
327 return implode('<p>', $error);
328 }
329 else {
330 return NULL;
331 }
332 }
333}
334