Migrate Eway(Single Currency) Payment Processor Type out into its own extension
[civicrm-core.git] / ext / ewaysingle / CRM / Core / Payment / eWAY.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
f452d72c 4 | Copyright CiviCRM LLC. All rights reserved. |
6a488035 5 | |
f452d72c
CW
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
6a488035 9 +--------------------------------------------------------------------+
d25dd0ee 10 */
6a488035 11
6a488035
TO
12/*
13 +--------------------------------------------------------------------+
775788cf 14 | eWAY Core Payment Module for CiviCRM version 5 & 1.9 |
6a488035
TO
15 +--------------------------------------------------------------------+
16 | Licensed to CiviCRM under the Academic Free License version 3.0 |
17 | |
18 | Written & Contributed by Dolphin Software P/L - March 2008 |
19 +--------------------------------------------------------------------+
20 | |
21 | This file is a part of CiviCRM. |
22 | |
23 | This code was initially based on the recent PayJunction module |
24 | contributed by Phase2 Technology, and then plundered bits from |
25 | the AuthorizeNet module contributed by Ideal Solution, and |
26 | referenced the eWAY code in Drupal 5.7's ecommerce-5.x-3.4 and |
27 | ecommerce-5.x-4.x-dev modules. |
28 | |
29 | Plus a bit of our own code of course - Peter Barwell |
30 | contact PB@DolphinSoftware.com.au if required. |
31 | |
b44e3f84 32 | NOTE: This initial eWAY module does not yet allow for recurring |
6a488035
TO
33 | payments - contact Peter Barwell or add yourself (or both) |
34 | |
35 | NOTE: The eWAY gateway only allows a single currency per account |
36 | (per eWAY CustomerID) ie you can only have one currency per |
37 | added Payment Processor. |
38 | The only way to add multi-currency is to code it so that a |
39 | different CustomerID is used per currency. |
40 | |
41 +--------------------------------------------------------------------+
e70a7fc0 42 */
6a488035
TO
43
44/**
353ffa53
TO
45 * -----------------------------------------------------------------------------------------------
46 * From the eWAY supplied 'Web.config' dated 25-Sep-2006 - check date and update links if required
47 * -----------------------------------------------------------------------------------------------
48 *
49 * LIVE gateway with CVN
50 * https://www.eway.com.au/gateway_cvn/xmlpayment.asp
51 *
52 * LIVE gateway without CVN
53 * https://www.eway.com.au/gateway/xmlpayment.asp
54 *
55 *
56 * Test gateway with CVN
57 * https://www.eway.com.au/gateway_cvn/xmltest/TestPage.asp
58 *
59 * Test gateway without CVN
60 * https://www.eway.com.au/gateway/xmltest/TestPage.asp
61 *
62 *
63 * LIVE gateway for Stored Transactions
64 * https://www.eway.com.au/gateway/xmlstored.asp
65 *
66 *
67 * -----------------------------------------------------------------------------------------------
68 * From the eWAY web-site - http://www.eway.com.au/Support/Developer/PaymentsRealTime.aspx
69 * -----------------------------------------------------------------------------------------------
70 * The test Customer ID is 87654321 - this is the only ID that will work on the test gateway.
71 * The test Credit Card number is 4444333322221111
72 * - this is the only credit card number that will work on the test gateway.
73 * The test Total Amount should end in 00 or 08 to get a successful response (e.g. $10.00 or $10.08)
74 * ie - all other amounts will return a failed response.
75 *
76 * -----------------------------------------------------------------------------------------------
c301f76e 77 */
404d48bf 78
1aaa2dcb 79use Civi\Payment\Exception\PaymentProcessorException;
ae1baeec 80use CRM_Ewaysingle_ExtensionUtil as E;
1aaa2dcb 81
404d48bf 82// require Standard eWAY API libraries
ae1baeec
SL
83require_once E::path('lib/eWAY/eWAY_GatewayRequest.php');
84require_once E::path('lib/eWAY/eWAY_GatewayResponse.php');
404d48bf 85
8246bca4 86/**
87 * Class CRM_Core_Payment_eWAY.
88 */
6a488035 89class CRM_Core_Payment_eWAY extends CRM_Core_Payment {
6a488035 90
c301f76e 91 /**
92 * *******************************************************
6a488035
TO
93 * Constructor
94 *
6a0b768e
TO
95 * @param string $mode
96 * The mode of operation: live or test.
6a488035 97 *
c301f76e 98 * @param int $paymentProcessor
dd244018 99 *
c301f76e 100 * *******************************************************
dd244018 101 */
00be9182 102 public function __construct($mode, &$paymentProcessor) {
6a488035
TO
103
104 // live or test
105 $this->_mode = $mode;
106 $this->_paymentProcessor = $paymentProcessor;
6a488035
TO
107 }
108
c301f76e 109 /**
ad37ac8e 110 * Sends request and receive response from eWAY payment process.
111 *
112 * @param array $params
113 *
114 * @return array|object
115 * @throws \Exception
c301f76e 116 */
00be9182 117 public function doDirectPayment(&$params) {
d597ad57 118 if (CRM_Utils_Array::value('is_recur', $params) == TRUE) {
2d296f18 119 throw new CRM_Core_Exception(ts('eWAY - recurring payments not implemented'));
6a488035
TO
120 }
121
122 if (!defined('CURLOPT_SSLCERT')) {
2d296f18 123 throw new CRM_Core_Exception(ts('eWAY - Gateway requires curl with SSL support'));
6a488035
TO
124 }
125
126 // eWAY Client ID
127 $ewayCustomerID = $this->_paymentProcessor['user_name'];
128 // eWAY Gateway URL
129 $gateway_URL = $this->_paymentProcessor['url_site'];
130
131 //------------------------------------
132 // create eWAY gateway objects
133 //------------------------------------
c301f76e 134 $eWAYRequest = new GatewayRequest();
6a488035
TO
135
136 if (($eWAYRequest == NULL) || (!($eWAYRequest instanceof GatewayRequest))) {
1aaa2dcb 137 throw new PaymentProcessorException('Error: Unable to create eWAY Request object.', 9001);
6a488035
TO
138 }
139
c301f76e 140 $eWAYResponse = new GatewayResponse();
6a488035
TO
141
142 if (($eWAYResponse == NULL) || (!($eWAYResponse instanceof GatewayResponse))) {
1aaa2dcb 143 throw new PaymentProcessorException(9002, 'Error: Unable to create eWAY Response object.', 9002);
6a488035
TO
144 }
145
146 /*
e70a7fc0
TO
147 //-------------------------------------------------------------
148 // NOTE: eWAY Doesn't use the following at the moment:
149 //-------------------------------------------------------------
150 $creditCardType = $params['credit_card_type'];
151 $currentcyID = $params['currencyID'];
152 $country = $params['country'];
153 */
6a488035 154
6a488035
TO
155 //-------------------------------------------------------------
156 // Prepare some composite data from _paymentProcessor fields
157 //-------------------------------------------------------------
158 $fullAddress = $params['street_address'] . ", " . $params['city'] . ", " . $params['state_province'] . ".";
353ffa53 159 $expireYear = substr($params['year'], 2, 2);
6a488035 160 $expireMonth = sprintf('%02d', (int) $params['month']);
6a488035
TO
161 $description = $params['description'];
162 $txtOptions = "";
163
164 $amountInCents = round(((float) $params['amount']) * 100);
165
166 $credit_card_name = $params['first_name'] . " ";
167 if (strlen($params['middle_name']) > 0) {
168 $credit_card_name .= $params['middle_name'] . " ";
169 }
170 $credit_card_name .= $params['last_name'];
171
172 //----------------------------------------------------------------------------------------------------
173 // We use CiviCRM's param's 'invoiceID' as the unique transaction token to feed to eWAY
174 // Trouble is that eWAY only accepts 16 chars for the token, while CiviCRM's invoiceID is an 32.
175 // As its made from a "$invoiceID = md5(uniqid(rand(), true));" then using the fierst 16 chars
176 // should be alright
177 //----------------------------------------------------------------------------------------------------
178 $uniqueTrnxNum = substr($params['invoiceID'], 0, 16);
179
180 //----------------------------------------------------------------------------------------------------
181 // OPTIONAL: If TEST Card Number force an Override of URL and CutomerID.
182 // During testing CiviCRM once used the LIVE URL.
183 // This code can be uncommented to override the LIVE URL that if CiviCRM does that again.
184 //----------------------------------------------------------------------------------------------------
185 // if ( ( $gateway_URL == "https://www.eway.com.au/gateway_cvn/xmlpayment.asp")
186 // && ( $params['credit_card_number'] == "4444333322221111" ) ) {
187 // $ewayCustomerID = "87654321";
188 // $gateway_URL = "https://www.eway.com.au/gateway_cvn/xmltest/testpage.asp";
189 // }
190
191 //----------------------------------------------------------------------------------------------------
192 // Now set the payment details - see http://www.eway.com.au/Support/Developer/PaymentsRealTime.aspx
193 //----------------------------------------------------------------------------------------------------
194 // 8 Chars - ewayCustomerID - Required
195 $eWAYRequest->EwayCustomerID($ewayCustomerID);
196 // 12 Chars - ewayTotalAmount (in cents) - Required
197 $eWAYRequest->InvoiceAmount($amountInCents);
198 // 50 Chars - ewayCustomerFirstName
199 $eWAYRequest->PurchaserFirstName($params['first_name']);
200 // 50 Chars - ewayCustomerLastName
201 $eWAYRequest->PurchaserLastName($params['last_name']);
202 // 50 Chars - ewayCustomerEmail
203 $eWAYRequest->PurchaserEmailAddress($params['email']);
204 // 255 Chars - ewayCustomerAddress
205 $eWAYRequest->PurchaserAddress($fullAddress);
206 // 6 Chars - ewayCustomerPostcode
207 $eWAYRequest->PurchaserPostalCode($params['postal_code']);
208 // 1000 Chars - ewayCustomerInvoiceDescription
209 $eWAYRequest->InvoiceDescription($description);
210 // 50 Chars - ewayCustomerInvoiceRef
211 $eWAYRequest->InvoiceReference($params['invoiceID']);
212 // 50 Chars - ewayCardHoldersName - Required
213 $eWAYRequest->CardHolderName($credit_card_name);
214 // 20 Chars - ewayCardNumber - Required
215 $eWAYRequest->CardNumber($params['credit_card_number']);
216 // 2 Chars - ewayCardExpiryMonth - Required
217 $eWAYRequest->CardExpiryMonth($expireMonth);
218 // 2 Chars - ewayCardExpiryYear - Required
219 $eWAYRequest->CardExpiryYear($expireYear);
220 // 4 Chars - ewayCVN - Required if CVN Gateway used
221 $eWAYRequest->CVN($params['cvv2']);
222 // 16 Chars - ewayTrxnNumber
223 $eWAYRequest->TransactionNumber($uniqueTrnxNum);
224 // 255 Chars - ewayOption1
225 $eWAYRequest->EwayOption1($txtOptions);
226 // 255 Chars - ewayOption2
227 $eWAYRequest->EwayOption2($txtOptions);
228 // 255 Chars - ewayOption3
229 $eWAYRequest->EwayOption3($txtOptions);
230
231 $eWAYRequest->CustomerIPAddress($params['ip_address']);
232 $eWAYRequest->CustomerBillingCountry($params['country']);
233
234 // Allow further manipulation of the arguments via custom hooks ..
235 CRM_Utils_Hook::alterPaymentProcessorParams($this, $params, $eWAYRequest);
236
237 //----------------------------------------------------------------------------------------------------
238 // Check to see if we have a duplicate before we send
239 //----------------------------------------------------------------------------------------------------
d253aeb8 240 if ($this->checkDupe($params['invoiceID'], CRM_Utils_Array::value('contributionID', $params))) {
1aaa2dcb 241 throw new PaymentProcessorException('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.', 9003);
6a488035
TO
242 }
243
244 //----------------------------------------------------------------------------------------------------
245 // Convert to XML and send the payment information
246 //----------------------------------------------------------------------------------------------------
247 $requestxml = $eWAYRequest->ToXML();
248
249 $submit = curl_init($gateway_URL);
250
251 if (!$submit) {
1aaa2dcb 252 throw new PaymentProcessorException('Could not initiate connection to payment gateway', 9004);
6a488035
TO
253 }
254
255 curl_setopt($submit, CURLOPT_POST, TRUE);
256 // return the result on success, FALSE on failure
257 curl_setopt($submit, CURLOPT_RETURNTRANSFER, TRUE);
258 curl_setopt($submit, CURLOPT_POSTFIELDS, $requestxml);
259 curl_setopt($submit, CURLOPT_TIMEOUT, 36000);
260 // if open_basedir or safe_mode are enabled in PHP settings CURLOPT_FOLLOWLOCATION won't work so don't apply it
261 // it's not really required CRM-5841
262 if (ini_get('open_basedir') == '' && ini_get('safe_mode' == 'Off')) {
263 // ensures any Location headers are followed
264 curl_setopt($submit, CURLOPT_FOLLOWLOCATION, 1);
265 }
266
267 // Send the data out over the wire
268 //--------------------------------
269 $responseData = curl_exec($submit);
270
271 //----------------------------------------------------------------------------------------------------
272 // See if we had a curl error - if so tell 'em and bail out
273 //
274 // NOTE: curl_error does not return a logical value (see its documentation), but
275 // a string, which is empty when there was no error.
276 //----------------------------------------------------------------------------------------------------
277 if ((curl_errno($submit) > 0) || (strlen(curl_error($submit)) > 0)) {
278 $errorNum = curl_errno($submit);
279 $errorDesc = curl_error($submit);
280
281 // Paranoia - in the unlikley event that 'curl' errno fails
2aa397bc
TO
282 if ($errorNum == 0) {
283 $errorNum = 9005;
284 }
6a488035
TO
285
286 // Paranoia - in the unlikley event that 'curl' error fails
2aa397bc 287 if (strlen($errorDesc) == 0) {
1aaa2dcb 288 $errorDesc = 'Connection to eWAY payment gateway failed';
2aa397bc 289 }
6a488035 290
1aaa2dcb 291 throw new PaymentProcessorException($errorDesc, $errorNum);
6a488035
TO
292 }
293
294 //----------------------------------------------------------------------------------------------------
295 // If null data returned - tell 'em and bail out
296 //
297 // NOTE: You will not necessarily get a string back, if the request failed for
298 // any reason, the return value will be the boolean false.
299 //----------------------------------------------------------------------------------------------------
300 if (($responseData === FALSE) || (strlen($responseData) == 0)) {
1aaa2dcb 301 throw new PaymentProcessorException('Error: Connection to payment gateway failed - no data returned.', 9006);
6a488035
TO
302 }
303
304 //----------------------------------------------------------------------------------------------------
305 // If gateway returned no data - tell 'em and bail out
306 //----------------------------------------------------------------------------------------------------
307 if (empty($responseData)) {
1aaa2dcb 308 throw new PaymentProcessorException('Error: No data returned from payment gateway.', 9007);
6a488035
TO
309 }
310
311 //----------------------------------------------------------------------------------------------------
312 // Success so far - close the curl and check the data
313 //----------------------------------------------------------------------------------------------------
314 curl_close($submit);
315
316 //----------------------------------------------------------------------------------------------------
ceb10dc7 317 // Payment successfully sent to gateway - process the response now
6a488035
TO
318 //----------------------------------------------------------------------------------------------------
319 $eWAYResponse->ProcessResponse($responseData);
320
321 //----------------------------------------------------------------------------------------------------
322 // See if we got an OK result - if not tell 'em and bail out
323 //----------------------------------------------------------------------------------------------------
324 if (self::isError($eWAYResponse)) {
325 $eWayTrxnError = $eWAYResponse->Error();
09e49db4 326 CRM_Core_Error::debug_var('eWay Error', $eWayTrxnError, TRUE, TRUE);
1aaa2dcb 327 if (substr($eWayTrxnError, 0, 6) === 'Error:') {
328 throw new PaymentProcessorException($eWayTrxnError, 9008);
6a488035
TO
329 }
330 $eWayErrorCode = substr($eWayTrxnError, 0, 2);
331 $eWayErrorDesc = substr($eWayTrxnError, 3);
332
1aaa2dcb 333 throw new PaymentProcessorException('Error: [' . $eWayErrorCode . "] - " . $eWayErrorDesc . '.', 9008);
e70a7fc0 334 }
6a488035 335
6a488035
TO
336 //=============
337 // Success !
338 //=============
339 $beaglestatus = $eWAYResponse->BeagleScore();
340 if (!empty($beaglestatus)) {
1aaa2dcb 341 $beaglestatus = ': ' . $beaglestatus;
6a488035
TO
342 }
343 $params['trxn_result_code'] = $eWAYResponse->Status() . $beaglestatus;
6a488035
TO
344 $params['trxn_id'] = $eWAYResponse->TransactionNumber();
345
346 return $params;
347 }
518fa0ee 348
c301f76e 349 /**
ad37ac8e 350 * Checks the eWAY response status - returning a boolean false if status != 'true'.
351 *
352 * @param object $response
353 *
354 * @return bool
c301f76e 355 */
00be9182 356 public function isError(&$response) {
6a488035
TO
357 $status = $response->Status();
358
1aaa2dcb 359 if ((stripos($status, 'true')) === FALSE) {
6a488035
TO
360 return TRUE;
361 }
362 return FALSE;
363 }
364
c301f76e 365 /**
6a488035
TO
366 * This public function checks to see if we have the right processor config values set
367 *
368 * NOTE: Called by Events and Contribute to check config params are set prior to trying
369 * register any credit card details
370 *
77b97be7 371 * @return null|string
1aaa2dcb 372 * returns string $errorMsg if any errors found - null if OK
77b97be7 373 */
00be9182 374 public function checkConfig() {
be2fb01f 375 $errorMsg = [];
6a488035
TO
376
377 if (empty($this->_paymentProcessor['user_name'])) {
378 $errorMsg[] = ts('eWAY CustomerID is not set for this payment processor');
379 }
380
381 if (empty($this->_paymentProcessor['url_site'])) {
382 $errorMsg[] = ts('eWAY Gateway URL is not set for this payment processor');
383 }
384
385 if (!empty($errorMsg)) {
386 return implode('<p>', $errorMsg);
387 }
1aaa2dcb 388 return NULL;
6a488035
TO
389 }
390
6a488035 391}