INFRA-132 comments to end with full stops
[civicrm-core.git] / CRM / Core / Payment / PayflowPro.php
1 <?php
2 /*
3 +----------------------------------------------------------------------------+
4 | PayflowPro Core Payment Module for CiviCRM version 4.6 |
5 +----------------------------------------------------------------------------+
6 | Licensed to CiviCRM under the Academic Free License version 3.0 |
7 | |
8 | Written & Contributed by Eileen McNaughton - 2009 |
9 +---------------------------------------------------------------------------+
10 */
11
12 /**
13 * Class CRM_Core_Payment_PayflowPro
14 */
15 class CRM_Core_Payment_PayflowPro extends CRM_Core_Payment {
16 // (not used, implicit in the API, might need to convert?)
17 const
18 CHARSET = 'UFT-8';
19
20 /**
21 * We only need one instance of this object. So we use the singleton
22 * pattern and cache the instance in this variable
23 *
24 * @var object
25 */
26 static private $_singleton = NULL;
27
28 /*
29 * Constructor
30 *
31 * @param string $mode
32 * The mode of operation: live or test.
33 *
34 * @return void
35 */
36 /**
37 * @param $mode
38 * @param $paymentProcessor
39 */
40 public function __construct($mode, &$paymentProcessor) {
41 // live or test
42 $this->_mode = $mode;
43 $this->_paymentProcessor = $paymentProcessor;
44 $this->_processorName = ts('Payflow Pro');
45 }
46
47 /*
48 * This function sends request and receives response from
49 * the processor. It is the main function for processing on-server
50 * credit card transactions
51 */
52 /**
53 * This function collects all the information from a web/api form and invokes
54 * the relevant payment processor specific functions to perform the transaction
55 *
56 * @param array $params
57 * Assoc array of input parameters for this transaction.
58 *
59 * @return array
60 * the result in an nice formatted array (or an error object)
61 * @abstract
62 */
63 public function doDirectPayment(&$params) {
64 if (!defined('CURLOPT_SSLCERT')) {
65 CRM_Core_Error::fatal(ts('PayFlowPro requires curl with SSL support'));
66 }
67
68 /*
69 * define variables for connecting with the gateway
70 */
71
72 // Are you using the Payflow Fraud Protection Service?
73 // Default is YES, change to NO or blank if not.
74 //This has not been investigated as part of writing this payment processor
75 $fraud = 'NO';
76 //if you have not set up a separate user account the vendor name is used as the username
77 if (!$this->_paymentProcessor['subject']) {
78 $user = $this->_paymentProcessor['user_name'];
79 }
80 else {
81 $user = $this->_paymentProcessor['subject'];
82 }
83
84 // ideally this id would be passed through into this class as
85 // part of the paymentProcessor
86 //object with the other variables. It seems inefficient to re-query to get it.
87 //$params['processor_id'] = CRM_Core_DAO::getFieldValue(
88 // 'CRM_Contribute_DAO_ContributionP
89 //age',$params['contributionPageID'], 'payment_processor_id' );
90
91 /*
92 *Create the array of variables to be sent to the processor from the $params array
93 * passed into this function
94 *
95 */
96
97 $payflow_query_array = array(
98 'USER' => $user,
99 'VENDOR' => $this->_paymentProcessor['user_name'],
100 'PARTNER' => $this->_paymentProcessor['signature'],
101 'PWD' => $this->_paymentProcessor['password'],
102 // C - Direct Payment using credit card
103 'TENDER' => 'C',
104 // A - Authorization, S - Sale
105 'TRXTYPE' => 'S',
106 'ACCT' => urlencode($params['credit_card_number']),
107 'CVV2' => $params['cvv2'],
108 'EXPDATE' => urlencode(sprintf('%02d', (int) $params['month']) . substr($params['year'], 2, 2)),
109 'ACCTTYPE' => urlencode($params['credit_card_type']),
110 'AMT' => urlencode($params['amount']),
111 'CURRENCY' => urlencode($params['currency']),
112 'FIRSTNAME' => $params['billing_first_name'],
113 //credit card name
114 'LASTNAME' => $params['billing_last_name'],
115 //credit card name
116 'STREET' => $params['street_address'],
117 'CITY' => urlencode($params['city']),
118 'STATE' => urlencode($params['state_province']),
119 'ZIP' => urlencode($params['postal_code']),
120 'COUNTRY' => urlencode($params['country']),
121 'EMAIL' => $params['email'],
122 'CUSTIP' => urlencode($params['ip_address']),
123 'COMMENT1' => urlencode($params['contributionType_accounting_code']),
124 'COMMENT2' => $mode,
125 'INVNUM' => urlencode($params['invoiceID']),
126 'ORDERDESC' => urlencode($params['description']),
127 'VERBOSITY' => 'MEDIUM',
128 'BILLTOCOUNTRY' => urlencode($params['country']),
129 );
130
131 if ($params['installments'] == 1) {
132 $params['is_recur'] == FALSE;
133 }
134
135 if ($params['is_recur'] == TRUE) {
136
137 $payflow_query_array['TRXTYPE'] = 'R';
138 $payflow_query_array['OPTIONALTRX'] = 'S';
139 $payflow_query_array['OPTIONALTRXAMT'] = $params['amount'];
140 //Amount of the initial Transaction. Required
141 $payflow_query_array['ACTION'] = 'A';
142 //A for add recurring (M-modify,C-cancel,R-reactivate,I-inquiry,P-payment
143 $payflow_query_array['PROFILENAME'] = urlencode('RegularContribution');
144 //A for add recurring (M-modify,C-cancel,R-reactivate,I-inquiry,P-payment
145 if ($params['installments'] > 0) {
146 $payflow_query_array['TERM'] = $params['installments'] - 1;
147 //ie. in addition to the one happening with this transaction
148 }
149 // $payflow_query_array['COMPANYNAME']
150 // $payflow_query_array['DESC'] = not set yet Optional
151 // description of the goods or
152 //services being purchased.
153 //This parameter applies only for ACH_CCD accounts.
154 // The
155 // $payflow_query_array['MAXFAILPAYMENTS'] = 0;
156 // number of payment periods (as s
157 //pecified by PAYPERIOD) for which the transaction is allowed
158 //to fail before PayPal cancels a profile. the default
159 // value of 0 (zero) specifies no
160 //limit. Retry
161 //attempts occur until the term is complete.
162 // $payflow_query_array['RETRYNUMDAYS'] = (not set as can't assume business rule
163
164 switch ($params['frequency_unit']) {
165 case '1 week':
166 $params['next_sched_contribution_date'] = mktime(0, 0, 0, date("m"), date("d") + 7,
167 date("Y")
168 );
169 $params['end_date'] = mktime(0, 0, 0, date("m"), date("d") + (7 * $payflow_query_array['TERM']),
170 date("Y")
171 );
172 $payflow_query_array['START'] = date('mdY', $params['next_sched_contribution_date']);
173 $payflow_query_array['PAYPERIOD'] = "WEEK";
174 $params['frequency_unit'] = "week";
175 $params['frequency_interval'] = 1;
176 break;
177
178 case '2 weeks':
179 $params['next_sched_contribution_date'] = mktime(0, 0, 0, date("m"), date("d") + 14, date("Y"));
180 $params['end_date'] = mktime(0, 0, 0, date("m"), date("d") + (14 * $payflow_query_array['TERM']), date("Y ")
181 );
182 $payflow_query_array['START'] = date('mdY', $params['next_sched_contribution_date']);
183 $payflow_query_array['PAYPERIOD'] = "BIWK";
184 $params['frequency_unit'] = "week";
185 $params['frequency_interval'] = 2;
186 break;
187
188 case '4 weeks':
189 $params['next_sched_contribution_date'] = mktime(0, 0, 0, date("m"), date("d") + 28, date("Y")
190 );
191 $params['end_date'] = mktime(0, 0, 0, date("m"), date("d") + (28 * $payflow_query_array['TERM']), date("Y")
192 );
193 $payflow_query_array['START'] = date('mdY', $params['next_sched_contribution_date']);
194 $payflow_query_array['PAYPERIOD'] = "FRWK";
195 $params['frequency_unit'] = "week";
196 $params['frequency_interval'] = 4;
197 break;
198
199 case '1 month':
200 $params['next_sched_contribution_date'] = mktime(0, 0, 0, date("m") + 1,
201 date("d"), date("Y")
202 );
203 $params['end_date'] = mktime(0, 0, 0, date("m") +
204 (1 * $payflow_query_array['TERM']),
205 date("d"), date("Y")
206 );
207 $payflow_query_array['START'] = date('mdY', $params['next_sched_contribution_date']);
208 $payflow_query_array['PAYPERIOD'] = "MONT";
209 $params['frequency_unit'] = "month";
210 $params['frequency_interval'] = 1;
211 break;
212
213 case '3 months':
214 $params['next_sched_contribution_date'] = mktime(0, 0, 0, date("m") + 3, date("d"), date("Y")
215 );
216 $params['end_date'] = mktime(0, 0, 0, date("m") +
217 (3 * $payflow_query_array['TERM']),
218 date("d"), date("Y")
219 );
220 $payflow_query_array['START'] = date('mdY', $params['next_sched_contribution_date']);
221 $payflow_query_array['PAYPERIOD'] = "QTER";
222 $params['frequency_unit'] = "month";
223 $params['frequency_interval'] = 3;
224 break;
225
226 case '6 months':
227 $params['next_sched_contribution_date'] = mktime(0, 0, 0, date("m") + 6, date("d"),
228 date("Y")
229 );
230 $params['end_date'] = mktime(0, 0, 0, date("m") +
231 (6 * $payflow_query_array['TERM']),
232 date("d"), date("Y")
233 );
234 $payflow_query_array['START'] = date('mdY', $params['next_sched_contribution_date']
235 );
236 $payflow_query_array['PAYPERIOD'] = "SMYR";
237 $params['frequency_unit'] = "month";
238 $params['frequency_interval'] = 6;
239 break;
240
241 case '1 year':
242 $params['next_sched_contribution_date'] = mktime(0, 0, 0, date("m"), date("d"),
243 date("Y") + 1
244 );
245 $params['end_date'] = mktime(0, 0, 0, date("m"), date("d"),
246 date("Y") +
247 (1 * $payflow_query_array['TEM'])
248 );
249 $payflow_query_array['START'] = date('mdY', $params['next_sched_contribution_date']);
250 $payflow_query_array['PAYPERIOD'] = "YEAR";
251 $params['frequency_unit'] = "year";
252 $params['frequency_interval'] = 1;
253 break;
254 }
255 }
256
257 CRM_Utils_Hook::alterPaymentProcessorParams($this, $params, $payflow_query_array);
258 $payflow_query = $this->convert_to_nvp($payflow_query_array);
259
260 /*
261 * Check to see if we have a duplicate before we send
262 */
263 if ($this->_checkDupe($params['invoiceID'])) {
264 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. 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.');
265 }
266
267 // ie. url at payment processor to submit to.
268 $submiturl = $this->_paymentProcessor['url_site'];
269
270 $responseData = self::submit_transaction($submiturl, $payflow_query);
271
272 /*
273 * Payment successfully sent to gateway - process the response now
274 */
275 $result = strstr($responseData, "RESULT");
276 $nvpArray = array();
277 while (strlen($result)) {
278 // name
279 $keypos = strpos($result, '=');
280 $keyval = substr($result, 0, $keypos);
281 // value
282 $valuepos = strpos($result, '&') ? strpos($result, '&') : strlen($result);
283 $valval = substr($result, $keypos + 1, $valuepos - $keypos - 1);
284 // decoding the respose
285 $nvpArray[$keyval] = $valval;
286 $result = substr($result, $valuepos + 1, strlen($result));
287 }
288 // get the result code to validate.
289 $result_code = $nvpArray['RESULT'];
290 /*debug
291 echo "<p>Params array</p><br>";
292 print_r($params);
293 echo "<p></p><br>";
294 echo "<p>Values to Payment Processor</p><br>";
295 print_r($payflow_query_array);
296 echo "<p></p><br>";
297 echo "<p>Results from Payment Processor</p><br>";
298 print_r($nvpArray);
299 echo "<p></p><br>";
300 */
301
302 switch ($result_code) {
303 case 0:
304
305 /*******************************************************
306 * Success !
307 * This is a successful transaction. PayFlow Pro does return further information
308 * about transactions to help you identify fraud including whether they pass
309 * the cvv check, the avs check. This is stored in
310 * CiviCRM as part of the transact
311 * but not further processing is done. Business rules would need to be defined
312 *******************************************************/
313 $params['trxn_id'] = $nvpArray['PNREF'] . $nvpArray['TRXPNREF'];
314 //'trxn_id' is varchar(255) field. returned value is length 12
315 $params['trxn_result_code'] = $nvpArray['AUTHCODE'] . "-Cvv2:" . $nvpArray['CVV2MATCH'] . "-avs:" . $nvpArray['AVSADDR'];
316
317 if ($params['is_recur'] == TRUE) {
318 $params['recur_trxn_id'] = $nvpArray['PROFILEID'];
319 //'trxn_id' is varchar(255) field. returned value is length 12
320 }
321 return $params;
322
323 case 1:
324 return self::errorExit(9008, "There is a payment processor configuration problem. This is usually due to invalid account information or ip restrictions on the account. You can verify ip restriction by logging // into Manager. See Service Settings >> Allowed IP Addresses. ");
325
326 case 12:
327 // Hard decline from bank.
328 return self::errorExit(9009, "Your transaction was declined ");
329
330 case 13:
331 // Voice authorization required.
332 return self::errorExit(9010, "Your Transaction is pending. Contact Customer Service to complete your order.");
333
334 case 23:
335 // Issue with credit card number or expiration date.
336 return self::errorExit(9011, "Invalid credit card information. Please re-enter.");
337
338 case 26:
339 return self::errorExit(9012, "You have not configured your payment processor with the correct credentials. Make sure you have provided both the <vendor> and the <user> variables ");
340
341 default:
342 return self::errorExit(9013, "Error - from payment processor: [" . $result_code . " " . $nvpArray['RESPMSG'] . "] ");
343 }
344
345 return self::errorExit(9014, "Check the code - all transactions should have been headed off before they got here. Something slipped through the net");
346 }
347
348 /**
349 * Checks to see if invoice_id already exists in db.
350 *
351 * @param int $invoiceId
352 * The ID to check.
353 *
354 * @return bool
355 * True if ID exists, else false
356 */
357 public function _checkDupe($invoiceId) {
358 //copied from Eway but not working and not really sure it should!
359 $contribution = new CRM_Contribute_DAO_Contribution();
360 $contribution->invoice_id = $invoiceId;
361 return $contribution->find();
362 }
363
364 /*
365 * Produces error message and returns from class
366 */
367 /**
368 * @param null $errorCode
369 * @param null $errorMessage
370 *
371 * @return object
372 */
373 public function &errorExit($errorCode = NULL, $errorMessage = NULL) {
374 $e = CRM_Core_Error::singleton();
375 if ($errorCode) {
376 $e->push($errorCode, 0, NULL, $errorMessage);
377 }
378 else {
379 $e->push(9000, 0, NULL, 'Unknown System Error.');
380 }
381 return $e;
382 }
383
384
385 /*
386 * NOTE: 'doTransferCheckout' not implemented
387 */
388 /**
389 * @param array $params
390 * @param $component
391 *
392 * @throws Exception
393 */
394 public function doTransferCheckout(&$params, $component) {
395 CRM_Core_Error::fatal(ts('This function is not implemented'));
396 }
397
398 /*
399 * This public function checks to see if we have the right processor config values set
400 *
401 * NOTE: Called by Events and Contribute to check config params are set prior to trying
402 * register any credit card details
403 *
404 * @param string $mode
405 * The mode we are operating in (live or test) - not used.
406 *
407 * returns string $errorMsg if any errors found - null if OK
408 */
409
410 // function checkConfig( $mode ) // CiviCRM V1.9 Declaration
411
412 /**
413 * CiviCRM V2.0 Declaration
414 * This function checks to see if we have the right config values
415 *
416 * @internal param string $mode the mode we are operating in (live or test)
417 *
418 * @return string
419 * the error message if any
420 */
421 public function checkConfig() {
422 $errorMsg = array();
423 if (empty($this->_paymentProcessor['user_name'])) {
424 $errorMsg[] = ' ' . ts('ssl_merchant_id is not set for this payment processor');
425 }
426
427 if (empty($this->_paymentProcessor['url_site'])) {
428 $errorMsg[] = ' ' . ts('URL is not set for %1', array(1 => $this->_paymentProcessor['name']));
429 }
430
431 if (!empty($errorMsg)) {
432 return implode('<p>', $errorMsg);
433 }
434 else {
435 return NULL;
436 }
437 }
438 //end check config
439
440 /*
441 * convert to a name/value pair (nvp) string
442 */
443 /**
444 * @param $payflow_query_array
445 *
446 * @return array|string
447 */
448 public function convert_to_nvp($payflow_query_array) {
449 foreach ($payflow_query_array as $key => $value) {
450 $payflow_query[] = $key . '[' . strlen($value) . ']=' . $value;
451 }
452 $payflow_query = implode('&', $payflow_query);
453
454 return $payflow_query;
455 }
456
457 /*
458 * Submit transaction using CuRL
459 * @submiturl string Url to direct HTTPS GET to
460 * @payflow_query value string to be posted
461 */
462 /**
463 * @param $submiturl
464 * @param $payflow_query
465 *
466 * @return mixed|object
467 */
468 public function submit_transaction($submiturl, $payflow_query) {
469 /*
470 * Submit transaction using CuRL
471 */
472
473 // get data ready for API
474 $user_agent = $_SERVER['HTTP_USER_AGENT'];
475 // Here's your custom headers; adjust appropriately for your setup:
476 $headers[] = "Content-Type: text/namevalue";
477 //or text/xml if using XMLPay.
478 $headers[] = "Content-Length : " . strlen($data);
479 // Length of data to be passed
480 // Here the server timeout value is set to 45, but notice
481 // below in the cURL section, the timeout
482 // for cURL is 90 seconds. You want to make sure the server
483 // timeout is less, then the connection.
484 $headers[] = "X-VPS-Timeout: 45";
485 //random unique number - the transaction is retried using this transaction ID
486 // in this function but if that doesn't work and it is re- submitted
487 // it is treated as a new attempt. PayflowPro doesn't allow
488 // you to change details (e.g. card no) when you re-submit
489 // you can only try the same details
490 $headers[] = "X-VPS-Request-ID: " . rand(1, 1000000000);
491 // optional header field
492 $headers[] = "X-VPS-VIT-Integration-Product: CiviCRM";
493 // other Optional Headers. If used adjust as necessary.
494 // Name of your OS
495 //$headers[] = "X-VPS-VIT-OS-Name: Linux";
496 // OS Version
497 //$headers[] = "X-VPS-VIT-OS-Version: RHEL 4";
498 // What you are using
499 //$headers[] = "X-VPS-VIT-Client-Type: PHP/cURL";
500 // For your info
501 //$headers[] = "X-VPS-VIT-Client-Version: 0.01";
502 // For your info
503 //$headers[] = "X-VPS-VIT-Client-Architecture: x86";
504 // Application version
505 //$headers[] = "X-VPS-VIT-Integration-Version: 0.01";
506 $ch = curl_init();
507 curl_setopt($ch, CURLOPT_URL, $submiturl);
508 curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
509 curl_setopt($ch, CURLOPT_USERAGENT, $user_agent);
510 curl_setopt($ch, CURLOPT_HEADER, 1);
511 // tells curl to include headers in response
512 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
513 // return into a variable
514 curl_setopt($ch, CURLOPT_TIMEOUT, 90);
515 // times out after 90 secs
516 if (ini_get('open_basedir') == '' && ini_get('safe_mode') == 'Off') {
517 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0);
518 }
519 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'verifySSL'));
520 // this line makes it work under https
521 curl_setopt($ch, CURLOPT_POSTFIELDS, $payflow_query);
522 //adding POST data
523 curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'verifySSL') ? 2 : 0);
524 //verifies ssl certificate
525 curl_setopt($ch, CURLOPT_FORBID_REUSE, TRUE);
526 //forces closure of connection when done
527 curl_setopt($ch, CURLOPT_POST, 1);
528 //data sent as POST
529
530 // Try to submit the transaction up to 3 times with 5 second delay. This can be used
531 // in case of network issues. The idea here is since you are posting via HTTPS there
532 // could be general network issues, so try a few times before you tell customer there
533 // is an issue.
534
535 $i = 1;
536 while ($i++ <= 3) {
537 $responseData = curl_exec($ch);
538 $responseHeaders = curl_getinfo($ch);
539 if ($responseHeaders['http_code'] != 200) {
540 // Let's wait 5 seconds to see if its a temporary network issue.
541 sleep(5);
542 }
543 elseif ($responseHeaders['http_code'] == 200) {
544 // we got a good response, drop out of loop.
545 break;
546 }
547 }
548
549 /*
550 * Transaction submitted -
551 * See if we had a curl error - if so tell 'em and bail out
552 *
553 * NOTE: curl_error does not return a logical value (see its documentation), but
554 * a string, which is empty when there was no error.
555 */
556 if ((curl_errno($ch) > 0) || (strlen(curl_error($ch)) > 0)) {
557 curl_close($ch);
558 $errorNum = curl_errno($ch);
559 $errorDesc = curl_error($ch);
560
561 //Paranoia - in the unlikley event that 'curl' errno fails
562 if ($errorNum == 0) {
563 $errorNum = 9005;
564 }
565
566 // Paranoia - in the unlikley event that 'curl' error fails
567 if (strlen($errorDesc) == 0) {
568 $errorDesc = "Connection to payment gateway failed";
569 }
570 if ($errorNum = 60) {
571 return self::errorExit($errorNum, "Curl error - " . $errorDesc .
572 " Try this link for more information http://curl.haxx.se/d
573 ocs/sslcerts.html"
574 );
575 }
576
577 return self::errorExit($errorNum, "Curl error - " . $errorDesc .
578 " processor response = " . $processorResponse
579 );
580 }
581
582 /*
583 * If null data returned - tell 'em and bail out
584 *
585 * NOTE: You will not necessarily get a string back, if the request failed for
586 * any reason, the return value will be the boolean false.
587 */
588 if (($responseData === FALSE) || (strlen($responseData) == 0)) {
589 curl_close($ch);
590 return self::errorExit(9006, "Error: Connection to payment gateway failed - no data
591 returned. Gateway url set to $submiturl");
592 }
593
594 /*
595 * If gateway returned no data - tell 'em and bail out
596 */
597 if (empty($responseData)) {
598 curl_close($ch);
599 return self::errorExit(9007, "Error: No data returned from payment gateway.");
600 }
601
602 /*
603 * Success so far - close the curl and check the data
604 */
605 curl_close($ch);
606 return $responseData;
607 }
608 //end submit_transaction
609
610 /**
611 * @param int $recurringProfileID
612 * @param int $processorID
613 *
614 * @throws Exception
615 */
616 public function getRecurringTransactionStatus($recurringProfileID, $processorID) {
617 if (!defined('CURLOPT_SSLCERT')) {
618 CRM_Core_Error::fatal(ts('PayFlowPro requires curl with SSL support'));
619 }
620
621 /*
622 * define variables for connecting with the gateway
623 */
624
625 //if you have not set up a separate user account the vendor name is used as the username
626 if (!$this->_paymentProcessor['subject']) {
627 $user = $this->_paymentProcessor['user_name'];
628 }
629 else {
630 $user = $this->_paymentProcessor['subject'];
631 }
632 //$recurringProfileID = "RT0000000001";
633 // c $trythis = $this->getRecurringTransactionStatus($recurringProfileID,17);
634
635 /*
636 *Create the array of variables to be sent to the processor from the $params array
637 * passed into this function
638 *
639 */
640
641 $payflow_query_array = array(
642 'USER' => $user,
643 'VENDOR' => $this->_paymentProcessor['user_name'],
644 'PARTNER' => $this->_paymentProcessor['signature'],
645 'PWD' => $this->_paymentProcessor['password'],
646 // C - Direct Payment using credit card
647 'TENDER' => 'C',
648 // A - Authorization, S - Sale
649 'TRXTYPE' => 'R',
650 'ACTION' => 'I',
651 //A for add recurring
652 //(M-modify,C-cancel,R-reactivate,
653 //I-inquiry,P-payment
654 'ORIGPROFILEID' => $recurringProfileID,
655 'PAYMENTHISTORY' => 'Y',
656 );
657
658 $payflow_query = $this->convert_to_nvp($payflow_query_array);
659 echo $payflow_query;
660 $submiturl = $this->_paymentProcessor['url_site'];
661 //ie. url at payment processor to submit to.
662 $responseData = self::submit_transaction($submiturl, $payflow_query);
663 /*
664 * Payment successfully sent to gateway - process the response now
665 */
666
667 $result = strstr($responseData, "RESULT");
668 $nvpArray = array();
669 while (strlen($result)) {
670 // name
671 $keypos = strpos($result, '=');
672 $keyval = substr($result, 0, $keypos);
673 // value
674 $valuepos = strpos($result, '&') ? strpos($result, '&') : strlen($result);
675 $valval = substr($result, $keypos + 1, $valuepos - $keypos - 1);
676 // decoding the respose
677 $nvpArray[$keyval] = $valval;
678 $result = substr($result, $valuepos + 1, strlen($result));
679 }
680 // get the result code to validate.
681 $result_code = $nvpArray['RESULT'];
682 print_r($responseData);
683
684 //RESPMSG=Invalid Profile ID: Invalid recurring profile ID
685 //RT0000000001
686 }
687
688 }