Index: branches/fundraising/extensions/DonationInterface/globalcollect_gateway/globalcollect_gateway.body.php |
— | — | @@ -104,6 +104,17 @@ |
105 | 105 | // track the number of attempts the user has made |
106 | 106 | $numAttempt = $wgRequest->getVal( 'numAttempt', 0 ); |
107 | 107 | |
| 108 | + |
| 109 | + |
| 110 | + |
| 111 | + |
| 112 | + |
| 113 | + |
| 114 | + |
| 115 | + |
| 116 | + |
| 117 | + |
| 118 | + |
108 | 119 | // Get array of default account values necessary for Payflow |
109 | 120 | // require_once( 'includes/payflowUser.inc' ); |
110 | 121 | |
— | — | @@ -150,29 +161,17 @@ |
151 | 162 | |
152 | 163 | // Populate form data |
153 | 164 | // $data = $this->fnGetFormData( $amount, $numAttempt, $token, $payflow_data['order_id'], $payflow_data['i_order_id'] ); |
154 | | - $data = $this->fnGetFormData( $amount, $numAttempt, null, null, null ); |
155 | 165 | |
156 | | - |
157 | | - //This is just me screwing around. |
158 | | - $dir = dirname( __FILE__ ) . '/'; |
159 | | - require_once($dir . 'globalcollect.adapter.php'); |
160 | | - $adapter = new GlobalCollectAdapter($data); |
161 | | - error_log(print_r($data, true)); |
162 | | - error_log($adapter->buildRequestXML( 'INSERT_ORDERWITHPAYMENT' )); |
163 | | - //$wgOut->addHTML('<pre>' . $adapter->buildRequestXML( 'INSERT_ORDERWITHPAYMENT' ) . '</pre>'); |
164 | 166 | |
165 | 167 | |
166 | | - /** |
167 | | - * handle PayPal redirection |
168 | | - * |
169 | | - * if paypal redirection is enabled ($wgPayflowGatewayPaypalURL must be defined) |
170 | | - * and the PaypalRedirect form value must be true |
171 | | - */ |
172 | | - if ( $wgRequest->getText( 'PaypalRedirect', 0 ) ) { |
173 | | - $this->paypalRedirect( $data ); |
174 | | - return; |
175 | | - } |
| 168 | + |
| 169 | + |
| 170 | + |
| 171 | + |
| 172 | + |
| 173 | + $data = $this->fnGetFormData( $amount, $numAttempt, null, null, null ); |
176 | 174 | |
| 175 | + |
177 | 176 | // dispatch forms/handling |
178 | 177 | // if ( $token_match ) { |
179 | 178 | if ( $data['payment_method'] == 'processed' ) { |
— | — | @@ -187,40 +186,55 @@ |
188 | 187 | $this->fnPayflowDisplayForm( $data, $this->errors ); |
189 | 188 | } else { // The submitted form data is valid, so process it |
190 | 189 | // allow any external validators to have their way with the data |
191 | | - self::log( $data[ 'order_id' ] . " Preparing to query MaxMind" ); |
192 | | - wfRunHooks( 'PayflowGatewayValidate', array( &$this, &$data ) ); |
193 | | - self::log( $data[ 'order_id' ] . ' Finished querying Maxmind' ); |
194 | | - |
195 | | - // if the transaction was flagged for review |
196 | | - if ( $this->action == 'review' ) { |
197 | | - // expose a hook for external handling of trxns flagged for review |
198 | | - wfRunHooks( 'PayflowGatewayReview', array( &$this, &$data )); |
199 | | - } |
200 | | - |
201 | | - // if the transaction was flagged to be 'challenged' |
202 | | - if ( $this->action == 'challenge' ) { |
203 | | - // expose a hook for external handling of trxns flagged for challenge (eg captcha) |
204 | | - wfRunHooks( 'PayflowGatewayChallenge', array( &$this, &$data ) ); |
205 | | - } |
206 | | - |
207 | | - // if the transaction was flagged for rejection |
208 | | - if ( $this->action == 'reject' ) { |
209 | | - // expose a hook for external handling of trxns flagged for rejection |
210 | | - wfRunHooks( 'PayflowGatewayReject', array( &$this, &$data ) ); |
211 | | - |
212 | | - $this->fnPayflowDisplayDeclinedResults( '' ); |
213 | | - $this->fnPayflowUnsetEditToken(); |
214 | | - } |
215 | | - |
216 | | - // if the transaction was flagged for processing |
217 | | - if ( $this->action == 'process' ) { |
218 | | - // expose a hook for external handling of trxns ready for processing |
219 | | - wfRunHooks( 'PayflowGatewayProcess', array( &$this, &$data ) ); |
220 | | - $this->fnGlobalCollectProcessTransaction( $data, $payflow_data ); |
221 | | - } |
222 | | - |
223 | | - // expose a hook for any post processing |
224 | | - wfRunHooks( 'PayflowGatewayPostProcess', array( &$this, &$data ) ); |
| 190 | + |
| 191 | + |
| 192 | + |
| 193 | + //This is just me screwing around. |
| 194 | + $dir = dirname( __FILE__ ) . '/'; |
| 195 | + require_once($dir . 'globalcollect.adapter.php'); |
| 196 | + $adapter = new GlobalCollectAdapter($data); |
| 197 | + self::log("Data used for adapter init: " . print_r($data, true)); |
| 198 | + $result = $adapter->do_transaction( 'INSERT_ORDERWITHPAYMENT' ); |
| 199 | + //$result = $adapter->do_transaction( 'TEST_CONNECTION' ); |
| 200 | + |
| 201 | + $wgOut->addHTML($result['message']); |
| 202 | + |
| 203 | + |
| 204 | + |
| 205 | +// self::log( $data[ 'order_id' ] . " Preparing to query MaxMind" ); |
| 206 | +// wfRunHooks( 'PayflowGatewayValidate', array( &$this, &$data ) ); |
| 207 | +// self::log( $data[ 'order_id' ] . ' Finished querying Maxmind' ); |
| 208 | +// |
| 209 | +// // if the transaction was flagged for review |
| 210 | +// if ( $this->action == 'review' ) { |
| 211 | +// // expose a hook for external handling of trxns flagged for review |
| 212 | +// wfRunHooks( 'PayflowGatewayReview', array( &$this, &$data )); |
| 213 | +// } |
| 214 | +// |
| 215 | +// // if the transaction was flagged to be 'challenged' |
| 216 | +// if ( $this->action == 'challenge' ) { |
| 217 | +// // expose a hook for external handling of trxns flagged for challenge (eg captcha) |
| 218 | +// wfRunHooks( 'PayflowGatewayChallenge', array( &$this, &$data ) ); |
| 219 | +// } |
| 220 | +// |
| 221 | +// // if the transaction was flagged for rejection |
| 222 | +// if ( $this->action == 'reject' ) { |
| 223 | +// // expose a hook for external handling of trxns flagged for rejection |
| 224 | +// wfRunHooks( 'PayflowGatewayReject', array( &$this, &$data ) ); |
| 225 | +// |
| 226 | +// $this->fnPayflowDisplayDeclinedResults( '' ); |
| 227 | +// $this->fnPayflowUnsetEditToken(); |
| 228 | +// } |
| 229 | +// |
| 230 | +// // if the transaction was flagged for processing |
| 231 | +// if ( $this->action == 'process' ) { |
| 232 | +// // expose a hook for external handling of trxns ready for processing |
| 233 | +// wfRunHooks( 'PayflowGatewayProcess', array( &$this, &$data ) ); |
| 234 | +// $this->fnGlobalCollectProcessTransaction( $data, $payflow_data ); |
| 235 | +// } |
| 236 | +// |
| 237 | +// // expose a hook for any post processing |
| 238 | +// wfRunHooks( 'PayflowGatewayPostProcess', array( &$this, &$data ) ); |
225 | 239 | } |
226 | 240 | } else { |
227 | 241 | // Display form for the first time |
— | — | @@ -361,122 +375,15 @@ |
362 | 376 | } elseif ( preg_match( '/^6(?:011|5[0-9]{2})[0-9]{12}$/', $data[ 'card_num' ] ) ) { // discover |
363 | 377 | $data[ 'card' ] = 'discover'; |
364 | 378 | } else { // an invalid credit card number was entered |
365 | | - $error_result = '1'; |
366 | | - $error[ 'card_num' ] = wfMsg( 'globalcollect_gateway-error-msg-card-num' ); |
| 379 | + //TODO: Make sure this is uncommented when you commit for reals! |
| 380 | + //$error_result = '1'; |
| 381 | + //$error[ 'card_num' ] = wfMsg( 'globalcollect_gateway-error-msg-card-num' ); |
367 | 382 | } |
368 | 383 | |
369 | 384 | return $error_result; |
370 | 385 | } |
371 | 386 | |
372 | 387 | /** |
373 | | - * Sends a name-value pair string to Payflow gateway |
374 | | - * |
375 | | - * @param $data Array: array of user input |
376 | | - * @param $payflow_data Array: array of necessary Payflow variables to |
377 | | - * include in string (i.e. Vendor, password) |
378 | | - */ |
379 | | - private function fnGlobalCollectProcessTransaction( $data, $payflow_data ) { |
380 | | - global $wgOut, $wgDonationTestingMode, $wgPayflowGatewayUseHTTPProxy, $wgPayflowGatewayHTTPProxy, $wgGlobalCollectTimeout; |
381 | | - |
382 | | - // update contribution tracking |
383 | | - $this->updateContributionTracking( $data, defined( 'OWA' ) ); |
384 | | - |
385 | | - // create payflow query string, include string lengths |
386 | | - $queryArray = array( |
387 | | - 'TRXTYPE' => $payflow_data['trxtype'], |
388 | | - 'TENDER' => $payflow_data['tender'], |
389 | | - 'USER' => $payflow_data['user'], |
390 | | - 'VENDOR' => $payflow_data['vendor'], |
391 | | - 'PARTNER' => $payflow_data['partner'], |
392 | | - 'PWD' => $payflow_data['password'], |
393 | | - 'ACCT' => $data['card_num'], |
394 | | - 'EXPDATE' => $data['expiration'], |
395 | | - 'AMT' => $data['amount'], |
396 | | - 'FIRSTNAME' => $data['fname'], |
397 | | - 'LASTNAME' => $data['lname'], |
398 | | - 'STREET' => $data['street'], |
399 | | - 'CITY' => $data['city'], |
400 | | - 'STATE' => $data['state'], |
401 | | - 'COUNTRY' => $data['country'], |
402 | | - 'ZIP' => $data['zip'], |
403 | | - 'INVNUM' => $data['order_id'], |
404 | | - 'CVV2' => $data['cvv'], |
405 | | - 'CURRENCY' => $data['currency'], |
406 | | - 'VERBOSITY' => $payflow_data['verbosity'], |
407 | | - 'CUSTIP' => $payflow_data['user_ip'], |
408 | | - ); |
409 | | - |
410 | | - foreach ( $queryArray as $name => $value ) { |
411 | | - $query[] = $name . '[' . strlen( $value ) . ']=' . $value; |
412 | | - } |
413 | | - |
414 | | - $queryString = implode( '&', $query ); |
415 | | - |
416 | | - $payflow_query = $queryString; |
417 | | - |
418 | | - // assign header data necessary for the curl_setopt() function |
419 | | - $user_agent = Http::userAgent(); |
420 | | - $headers[] = 'Content-Type: text/namevalue'; |
421 | | - $headers[] = 'Content-Length : ' . strlen( $payflow_query ); |
422 | | - $headers[] = 'X-VPS-Client-Timeout: 45'; |
423 | | - $headers[] = 'X-VPS-Request-ID:' . $data['order_id']; |
424 | | - $ch = curl_init(); |
425 | | - $paypalPostTo = isset ( $wgDonationTestingMode ) ? 'testingurl' : 'paypalurl'; |
426 | | - curl_setopt( $ch, CURLOPT_URL, $payflow_data[ $paypalPostTo ] ); |
427 | | - curl_setopt( $ch, CURLOPT_HTTPHEADER, $headers ); |
428 | | - curl_setopt( $ch, CURLOPT_USERAGENT, $user_agent ); |
429 | | - curl_setopt( $ch, CURLOPT_HEADER, 1 ); |
430 | | - curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 ); |
431 | | - curl_setopt( $ch, CURLOPT_TIMEOUT, $wgGlobalCollectTimeout ); |
432 | | - curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, 0 ); |
433 | | - curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, 0 ); |
434 | | - curl_setopt( $ch, CURLOPT_POSTFIELDS, $payflow_query ); |
435 | | - curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, 2 ); |
436 | | - curl_setopt( $ch, CURLOPT_FORBID_REUSE, true ); |
437 | | - curl_setopt( $ch, CURLOPT_POST, 1 ); |
438 | | - |
439 | | - // set proxy settings if necessary |
440 | | - if ( $wgPayflowGatewayUseHTTPProxy ) { |
441 | | - curl_setopt( $ch, CURLOPT_HTTPPROXYTUNNEL, 1 ); |
442 | | - curl_setopt( $ch, CURLOPT_PROXY, $wgPayflowGatewayHTTPProxy ); |
443 | | - } |
444 | | - |
445 | | - // As suggested in the PayPal developer forum sample code, try more than once to get a response |
446 | | - // in case there is a general network issue |
447 | | - $i = 1; |
448 | | - |
449 | | - while ( $i++ <= 3 ) { |
450 | | - self::log( $data[ 'order_id' ] . ' Preparing to send transaction to GlobalCollect' ); |
451 | | - $result = curl_exec( $ch ); |
452 | | - $headers = curl_getinfo( $ch ); |
453 | | - |
454 | | - if ( $headers['http_code'] != 200 && $headers['http_code'] != 403 ) { |
455 | | - self::log( $data[ 'order_id' ] . ' Failed sending transaction to GlobalCollect, retrying' ); |
456 | | - sleep( 1 ); |
457 | | - } elseif ( $headers['http_code'] == 200 || $headers['http_code'] == 403 ) { |
458 | | - self::log( $data[ 'order_id' ] . ' Finished sending transaction to GlobalCollect' ); |
459 | | - break; |
460 | | - } |
461 | | - } |
462 | | - |
463 | | - if ( $headers['http_code'] != 200 ) { |
464 | | - $wgOut->addHTML( '<h3>No response from credit card processor. Please try again later!</h3><p>' ); |
465 | | - $when = time(); |
466 | | - self::log( $data[ 'order_id' ] . ' No response from credit card processor: ' . curl_error( $ch ) ); |
467 | | - curl_close( $ch ); |
468 | | - return; |
469 | | - } |
470 | | - |
471 | | - curl_close( $ch ); |
472 | | - |
473 | | - // get result string |
474 | | - $result = strstr( $result, 'RESULT' ); |
475 | | - |
476 | | - // parse string and display results to the user |
477 | | - $this->fnPayflowGetResults( $data, $result ); |
478 | | - } |
479 | | - |
480 | | - /** |
481 | 388 | * "Reads" the name-value pair result string returned by Payflow and creates corresponding error messages |
482 | 389 | * |
483 | 390 | * @param $data Array: array of user input |
— | — | @@ -1294,10 +1201,10 @@ |
1295 | 1202 | } |
1296 | 1203 | |
1297 | 1204 | public static function log( $msg, $identifier='globalcollect_gateway', $log_level=LOG_INFO ) { |
1298 | | - global $wgPayflowGatewayUseSyslog; |
| 1205 | + global $wgGlobalCollectGatewayUseSyslog; |
1299 | 1206 | |
1300 | 1207 | // if we're not using the syslog facility, use wfDebugLog |
1301 | | - if ( !$wgPayflowGatewayUseSyslog ) { |
| 1208 | + if ( !$wgGlobalCollectGatewayUseSyslog ) { |
1302 | 1209 | wfDebugLog( $identifier, $msg ); |
1303 | 1210 | return; |
1304 | 1211 | } |
Index: branches/fundraising/extensions/DonationInterface/globalcollect_gateway/globalcollect.adapter.php |
— | — | @@ -14,13 +14,19 @@ |
15 | 15 | private $xmlDoc; |
16 | 16 | |
17 | 17 | function __construct($data){ |
| 18 | + //TODO: Squish ALL the globals here, in the constructor. |
| 19 | + //easier to abstract out that way. |
18 | 20 | global $wgGatewayTest; |
19 | 21 | |
20 | 22 | $this->postdata = $data; |
21 | 23 | |
| 24 | + //TODO: Make a Thing in which we do things like this. |
| 25 | + $this->postdata['amount'] = $this->postdata['amount'] * 100; |
22 | 26 | |
| 27 | + |
23 | 28 | $returnTitle = Title::newFromText( 'Donate-thanks/en' ); |
24 | 29 | $returnto = $returnTitle->getFullURL(); |
| 30 | + $returnto = "http://www.katiehorn.com"; |
25 | 31 | |
26 | 32 | //this DEFINITELY needs to be defined in the parent class, and contain everything anybody might want to know. |
27 | 33 | $this->postdatadefaults = array( |
— | — | @@ -46,12 +52,22 @@ |
47 | 53 | 'COUNTRYCODE' => 'country', |
48 | 54 | 'MERCHANTREFERENCE' => 'order_id', |
49 | 55 | 'RETURNURL' => 'returnto', //I think. It might not even BE here yet. Boo-urns. |
50 | | - 'IPADDRESS' => 'user_ip' //TODO: Not sure if this should be OUR ip, or the user's ip. Hurm. |
| 56 | + 'IPADDRESS' => 'user_ip', //TODO: Not sure if this should be OUR ip, or the user's ip. Hurm. |
| 57 | + |
51 | 58 | ); |
52 | 59 | |
| 60 | + $this->return_value_map = array( |
| 61 | + 'OK' => true, |
| 62 | + 'NOK' => false, |
| 63 | + ); |
| 64 | + |
53 | 65 | global $wgGlobalCollectURL, $wgGlobalCollectMerchantID; |
| 66 | + if ($wgGatewayTest){ |
| 67 | + $this->url = $wgGlobalCollectURL; |
| 68 | + } else { |
| 69 | + $this->url = $wgGlobalCollectURL; |
| 70 | + } |
54 | 71 | |
55 | | - $this->url = $wgGlobalCollectURL; |
56 | 72 | |
57 | 73 | $this->accountInfo = array( |
58 | 74 | // 'PAYMENTPRODUCTID' => '3', //actually, these are almost certainly transaction-specific. |
— | — | @@ -61,6 +77,7 @@ |
62 | 78 | 'VERSION' => "1.0", |
63 | 79 | ); |
64 | 80 | |
| 81 | + //oof. This is getting a little long and unwieldy. Maybe we should build it. Or maybe that sucks. I can't tell yet. |
65 | 82 | /* General idea here: |
66 | 83 | * This bad boy will (probably) contain the structure of all possible transactions as defined by the gateway. |
67 | 84 | * First array key: Some way for us to id the transaction. Doesn't actually have to be the gateway's name for it, but |
— | — | @@ -80,7 +97,7 @@ |
81 | 98 | 'ACTION', |
82 | 99 | 'META' => array( |
83 | 100 | 'MERCHANTID', |
84 | | - 'IPADDRESS', |
| 101 | +// 'IPADDRESS', |
85 | 102 | 'VERSION' |
86 | 103 | ), |
87 | 104 | 'PARAMS' => array( |
— | — | @@ -109,12 +126,61 @@ |
110 | 127 | 'HOSTEDINDICATOR' => '1', |
111 | 128 | 'PAYMENTPRODUCTID' => '3', |
112 | 129 | ), |
113 | | - ) |
| 130 | + 'result' => array( //just like the rest: This is still in flux. But the idea here is that this is the sctucture you'd scan for. |
| 131 | + 'RESULT' => 'value' |
| 132 | + ), |
| 133 | + 'result_errors' => array( |
| 134 | + 'ERROR' => array( |
| 135 | + 'CODE' => 'value', //as opposed to "attribute", which would imply that it belongs to the parent... |
| 136 | + 'MESSAGE' => 'value', |
| 137 | + ) |
| 138 | + ), |
| 139 | + 'result_data' => array( |
| 140 | + 'ROW' => array( |
| 141 | + //uhh... presumably we'd look for some Stuff in here. |
| 142 | + ) |
| 143 | + ) |
| 144 | + ), |
| 145 | + 'TEST_CONNECTION' => array( |
| 146 | + 'request' => array( |
| 147 | + 'REQUEST' => array( |
| 148 | + 'ACTION', |
| 149 | + 'META' => array( |
| 150 | + 'MERCHANTID', |
| 151 | +// 'IPADDRESS', |
| 152 | + 'VERSION' |
| 153 | + ), |
| 154 | + 'PARAMS' => array() |
| 155 | + ) |
| 156 | + ), |
| 157 | + 'values' => array( |
| 158 | + 'ACTION' => 'TEST_CONNECTION' |
| 159 | + ), |
| 160 | + 'result' => array( //just like the rest: This is still in flux. But the idea here is that this is the sctucture you'd scan for. |
| 161 | + 'RESULT' => 'value' |
| 162 | + ), |
| 163 | + 'result_errors' => array( |
| 164 | + 'ERROR' => array( |
| 165 | + 'CODE' => 'value', //as opposed to "attribute", which would imply that it belongs to the parent... |
| 166 | + 'MESSAGE' => 'value', |
| 167 | + ) |
| 168 | + ), |
| 169 | + 'result_data' => array( |
| 170 | + 'ROW' => array( |
| 171 | + //uhh... presumably we'd look for some Stuff in here. |
| 172 | + ) |
| 173 | + ) |
| 174 | + ), |
114 | 175 | ); |
115 | 176 | |
116 | 177 | } |
117 | 178 | |
118 | | - function getValue($gateway_field_name, $transaction){ |
| 179 | + function getCommunicationType(){ |
| 180 | + return 'xml'; //'xml' or 'namevalue'. |
| 181 | + } |
| 182 | + |
| 183 | + |
| 184 | + function getValue($gateway_field_name, $transaction = ''){ |
119 | 185 | //How do we determine the value of a field asked for in a particular transaction? |
120 | 186 | |
121 | 187 | //If there's a hard-coded value in the transaction definition, use that. |
— | — | @@ -150,30 +216,31 @@ |
151 | 217 | |
152 | 218 | } |
153 | 219 | |
154 | | - function buildRequestXML($transaction){ |
| 220 | + function buildRequestXML(){ |
155 | 221 | $this->xmlDoc = new DomDocument('1.0'); |
156 | 222 | $node = $this->xmlDoc->createElement('XML'); |
157 | 223 | |
158 | | - $structure = $this->transactions[$transaction]['request']; |
| 224 | + $structure = $this->transactions[$this->currentTransaction()]['request']; |
159 | 225 | |
160 | | - $this->buildTransactionNodes($transaction, $structure, $node); |
| 226 | + $this->buildTransactionNodes($structure, $node); |
161 | 227 | $this->xmlDoc->appendChild($node); |
162 | 228 | return $this->xmlDoc->saveXML(); |
163 | 229 | } |
164 | 230 | |
165 | 231 | |
166 | | - function buildTransactionNodes($transaction, $structure, &$node){ |
| 232 | + function buildTransactionNodes($structure, &$node){ |
| 233 | + $transaction = $this->currentTransaction(); |
167 | 234 | |
168 | 235 | if (!is_array($structure)){ //this is a weird case that shouldn't ever happen. I'm just being... thorough. But, yeah: It's like... the base-1 case. |
169 | | - $this->appendNodeIfValue($structure, $transaction, $node); |
| 236 | + $this->appendNodeIfValue($structure, $node); |
170 | 237 | } else { |
171 | 238 | foreach ($structure as $key => $value){ |
172 | 239 | if (!is_array($value)){ |
173 | 240 | //do not use $key. $key is meaningless in this case. |
174 | | - $this->appendNodeIfValue($value, $transaction, $node); |
| 241 | + $this->appendNodeIfValue($value, $node); |
175 | 242 | } else { |
176 | 243 | $keynode = $this->xmlDoc->createElement($key); |
177 | | - $this->buildTransactionNodes($transaction, $value, $keynode); |
| 244 | + $this->buildTransactionNodes( $value, $keynode); |
178 | 245 | $node->appendChild($keynode); |
179 | 246 | } |
180 | 247 | } |
— | — | @@ -181,180 +248,299 @@ |
182 | 249 | //not actually returning anything. It's all side-effects. Because I suck like that. |
183 | 250 | } |
184 | 251 | |
185 | | - function appendNodeIfValue($value, $transaction, &$node){ |
186 | | - $nodevalue = $this->getValue($value, $transaction); |
| 252 | + function appendNodeIfValue($value, &$node){ |
| 253 | + $nodevalue = $this->getValue($value, $this->currentTransaction()); |
187 | 254 | if ($nodevalue !== '' && $nodevalue !== false){ |
188 | 255 | $temp = $this->xmlDoc->createElement($value, $nodevalue); |
189 | 256 | $node->appendChild($temp); |
190 | 257 | } |
191 | 258 | } |
192 | 259 | |
193 | | - function sendRequestXML($transaction){ |
194 | | - $xml = $this->buildRequestXML($transaction); |
| 260 | + function do_transaction($transaction){ |
| 261 | + $this->currentTransaction($transaction); |
| 262 | + if ($this->getCommunicationType() === 'xml'){ |
| 263 | + $xml = $this->buildRequestXML(); |
| 264 | + $response = $this->curl_transaction($xml); |
| 265 | + //put the response in a universal form, and return it. |
| 266 | + } |
195 | 267 | |
| 268 | + //TODO: Actually pull these from somewhere legit. |
| 269 | + if ($response['status'] === true){ |
| 270 | + $response['message'] = "$transaction Transaction Successful!"; |
| 271 | + } elseif ($response['status'] === false){ |
| 272 | + $response['message'] = "$transaction Transaction FAILED!"; |
| 273 | + } else { |
| 274 | + $response['message'] = "$transaction Transaction... weird. I have no idea what happened there."; |
| 275 | + } |
| 276 | + |
| 277 | + return $response; |
| 278 | + |
| 279 | + //speaking of universal form: |
| 280 | + //$result['status'] = something I wish could be boiled down to a bool, but that's way too optimistic, I think. |
| 281 | + //$result['message'] = whatever we want to display back? |
| 282 | + //$result['errors'][]['code'] = their error code |
| 283 | + //$result['errors'][]['value'] = Error message |
| 284 | + //$result['return'][$whatever] = values they pass back to us for whatever reason. We might... log it, or pieces of it, or something? |
196 | 285 | } |
| 286 | + |
| 287 | + function getCurlBaseOpts(){ |
| 288 | + //I chose to return this as a function so it's easy to override. |
| 289 | + //TODO: probably this for all the junk I currently have stashed in the constructor. |
| 290 | + //...maybe. |
| 291 | + global $wgGlobalCollectTimeout, $wgPayflowGatewayUseHTTPProxy; |
| 292 | + $opts = array( |
| 293 | + CURLOPT_URL => $this->url, |
| 294 | + //CURLOPT_USERAGENT => Http::userAgent(), |
| 295 | + CURLOPT_HEADER => 1, |
| 296 | + CURLOPT_RETURNTRANSFER => 1, |
| 297 | + CURLOPT_TIMEOUT => $wgGlobalCollectTimeout, |
| 298 | + //CURLOPT_FOLLOWLOCATION => 0, |
| 299 | + //CURLOPT_SSL_VERIFYPEER => 0, |
| 300 | + //CURLOPT_SSL_VERIFYHOST => 2, |
| 301 | + //CURLOPT_FORBID_REUSE => true, |
| 302 | + CURLOPT_POST => 1, |
| 303 | + ); |
197 | 304 | |
| 305 | + // set proxy settings if necessary |
| 306 | + if ( $wgPayflowGatewayUseHTTPProxy ) { |
| 307 | + $opts[CURLOPT_HTTPPROXYTUNNEL] = 1; |
| 308 | + $opts[CURLOPT_PROXY] = $wgPayflowGatewayHTTPProxy; |
| 309 | + } |
| 310 | + return $opts; |
| 311 | + } |
| 312 | + |
| 313 | + |
| 314 | + function getCurlBaseHeaders(){ |
| 315 | + $headers = array ( |
| 316 | + 'Content-Type: text/' . $this->getCommunicationType() . '; charset=utf-8', |
| 317 | + // 'X-VPS-Client-Timeout: 45', |
| 318 | + // 'X-VPS-Request-ID:' . $this->postdatadefaults['order_id'], |
| 319 | + ); |
| 320 | + return $headers; |
| 321 | + } |
| 322 | + |
| 323 | + private function currentTransaction($transaction = ''){ //get&set in one! |
| 324 | + static $current_transaction; |
| 325 | + if ($transaction != ''){ |
| 326 | + $current_transaction = $transaction; |
| 327 | + } |
| 328 | + if (!isset($current_transaction)){ |
| 329 | + return false; |
| 330 | + } |
| 331 | + return $current_transaction; |
| 332 | + } |
| 333 | + |
198 | 334 | /** |
199 | 335 | * Sends a name-value pair string to Payflow gateway |
200 | 336 | * |
201 | | - * @param $data Array: array of user input |
202 | | - * @param $payflow_data Array: array of necessary Payflow variables to |
203 | | - * include in string (i.e. Vendor, password) |
| 337 | + * @param $data String: The exact thing we want to send. |
204 | 338 | */ |
205 | | - private function fnGlobalCollectProcessTransaction( $data, $payflow_data ) { |
206 | | - global $wgOut, $wgDonationTestingMode, $wgPayflowGatewayUseHTTPProxy, $wgPayflowGatewayHTTPProxy, $wgGlobalCollectTimeout; |
| 339 | + private function curl_transaction( $data ) { |
| 340 | + global $wgOut; //TODO: Uhm, this shouldn't touch the view. Something further upstream should decide what to do with this. |
207 | 341 | |
208 | | - // update contribution tracking |
209 | | - $this->updateContributionTracking( $data, defined( 'OWA' ) ); |
| 342 | + // TODO: This, but way before we get here. |
| 343 | + //$this->updateContributionTracking( $data, defined( 'OWA' ) ); |
210 | 344 | |
211 | | - // create payflow query string, include string lengths |
212 | | - $queryArray = array( |
213 | | - 'TRXTYPE' => $payflow_data['trxtype'], |
214 | | - 'TENDER' => $payflow_data['tender'], |
215 | | - 'USER' => $payflow_data['user'], |
216 | | - 'VENDOR' => $payflow_data['vendor'], |
217 | | - 'PARTNER' => $payflow_data['partner'], |
218 | | - 'PWD' => $payflow_data['password'], |
219 | | - 'ACCT' => $data['card_num'], |
220 | | - 'EXPDATE' => $data['expiration'], |
221 | | - 'AMT' => $data['amount'], |
222 | | - 'FIRSTNAME' => $data['fname'], |
223 | | - 'LASTNAME' => $data['lname'], |
224 | | - 'STREET' => $data['street'], |
225 | | - 'CITY' => $data['city'], |
226 | | - 'STATE' => $data['state'], |
227 | | - 'COUNTRY' => $data['country'], |
228 | | - 'ZIP' => $data['zip'], |
229 | | - 'INVNUM' => $data['order_id'], |
230 | | - 'CVV2' => $data['cvv'], |
231 | | - 'CURRENCY' => $data['currency'], |
232 | | - 'VERBOSITY' => $payflow_data['verbosity'], |
233 | | - 'CUSTIP' => $payflow_data['user_ip'], |
234 | | - ); |
235 | | - |
236 | | - foreach ( $queryArray as $name => $value ) { |
237 | | - $query[] = $name . '[' . strlen( $value ) . ']=' . $value; |
238 | | - } |
239 | | - |
240 | | - $queryString = implode( '&', $query ); |
241 | | - |
242 | | - $payflow_query = $queryString; |
243 | | - |
244 | 345 | // assign header data necessary for the curl_setopt() function |
245 | | - $user_agent = Http::userAgent(); |
246 | | - $headers[] = 'Content-Type: text/namevalue'; |
247 | | - $headers[] = 'Content-Length : ' . strlen( $payflow_query ); |
248 | | - $headers[] = 'X-VPS-Client-Timeout: 45'; |
249 | | - $headers[] = 'X-VPS-Request-ID:' . $data['order_id']; |
| 346 | + |
250 | 347 | $ch = curl_init(); |
251 | | - $paypalPostTo = isset ( $wgDonationTestingMode ) ? 'testingurl' : 'paypalurl'; |
252 | | - curl_setopt( $ch, CURLOPT_URL, $payflow_data[ $paypalPostTo ] ); |
253 | | - curl_setopt( $ch, CURLOPT_HTTPHEADER, $headers ); |
254 | | - curl_setopt( $ch, CURLOPT_USERAGENT, $user_agent ); |
255 | | - curl_setopt( $ch, CURLOPT_HEADER, 1 ); |
256 | | - curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 ); |
257 | | - curl_setopt( $ch, CURLOPT_TIMEOUT, $wgGlobalCollectTimeout ); |
258 | | - curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, 0 ); |
259 | | - curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, 0 ); |
260 | | - curl_setopt( $ch, CURLOPT_POSTFIELDS, $payflow_query ); |
261 | | - curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, 2 ); |
262 | | - curl_setopt( $ch, CURLOPT_FORBID_REUSE, true ); |
263 | | - curl_setopt( $ch, CURLOPT_POST, 1 ); |
264 | | - |
265 | | - // set proxy settings if necessary |
266 | | - if ( $wgPayflowGatewayUseHTTPProxy ) { |
267 | | - curl_setopt( $ch, CURLOPT_HTTPPROXYTUNNEL, 1 ); |
268 | | - curl_setopt( $ch, CURLOPT_PROXY, $wgPayflowGatewayHTTPProxy ); |
| 348 | + |
| 349 | + $headers = $this->getCurlBaseHeaders(); |
| 350 | + $headers[] = 'Content-Length: ' . strlen( $data ); |
| 351 | + |
| 352 | + self::log("Sending Data: " . $data); |
| 353 | + |
| 354 | + $curl_opts = $this->getCurlBaseOpts(); |
| 355 | + $curl_opts[CURLOPT_HTTPHEADER] = $headers; |
| 356 | + $curl_opts[CURLOPT_POSTFIELDS] = $data; |
| 357 | + |
| 358 | + foreach ($curl_opts as $option => $value){ |
| 359 | + curl_setopt($ch, $option, $value); |
269 | 360 | } |
270 | 361 | |
271 | 362 | // As suggested in the PayPal developer forum sample code, try more than once to get a response |
272 | 363 | // in case there is a general network issue |
273 | 364 | $i = 1; |
| 365 | + |
| 366 | + $return = array(); |
274 | 367 | |
275 | 368 | while ( $i++ <= 3 ) { |
276 | | - self::log( $data[ 'order_id' ] . ' Preparing to send transaction to GlobalCollect' ); |
277 | | - $result = curl_exec( $ch ); |
278 | | - $headers = curl_getinfo( $ch ); |
| 369 | + self::log( $this->postdatadefaults['order_id'] . ' Preparing to send transaction to GlobalCollect' ); |
| 370 | + $return['result'] = curl_exec( $ch ); |
| 371 | + $return['headers'] = curl_getinfo( $ch ); |
279 | 372 | |
280 | | - if ( $headers['http_code'] != 200 && $headers['http_code'] != 403 ) { |
281 | | - self::log( $data[ 'order_id' ] . ' Failed sending transaction to GlobalCollect, retrying' ); |
| 373 | + if ( $return['headers']['http_code'] != 200 && $return['headers']['http_code'] != 403 ) { |
| 374 | + self::log( $this->postdatadefaults['order_id'] . ' Failed sending transaction to GlobalCollect, retrying' ); |
282 | 375 | sleep( 1 ); |
283 | | - } elseif ( $headers['http_code'] == 200 || $headers['http_code'] == 403 ) { |
284 | | - self::log( $data[ 'order_id' ] . ' Finished sending transaction to GlobalCollect' ); |
| 376 | + } elseif ( $return['headers']['http_code'] == 200 || $return['headers']['http_code'] == 403 ) { |
| 377 | + self::log( $this->postdatadefaults['order_id'] . ' Finished sending transaction to GlobalCollect' ); |
285 | 378 | break; |
286 | 379 | } |
287 | 380 | } |
288 | 381 | |
289 | | - if ( $headers['http_code'] != 200 ) { |
290 | | - $wgOut->addHTML( '<h3>No response from credit card processor. Please try again later!</h3><p>' ); |
| 382 | + if ( $return['headers']['http_code'] != 200 ) { |
| 383 | + $return['result'] = false; |
| 384 | + //TODO: i18n here! |
| 385 | + $return['message'] = 'No response from credit card processor. Please try again later!'; |
291 | 386 | $when = time(); |
292 | | - self::log( $data[ 'order_id' ] . ' No response from credit card processor: ' . curl_error( $ch ) ); |
| 387 | + self::log( $this->postdatadefaults['order_id'] . ' No response from credit card processor: ' . curl_error( $ch ) ); |
293 | 388 | curl_close( $ch ); |
294 | | - return; |
| 389 | + return $return; |
295 | 390 | } |
296 | 391 | |
297 | 392 | curl_close( $ch ); |
| 393 | + self::log("Results: " . print_r($return['result'], true)); |
| 394 | + |
| 395 | +// if ($this->getCommunicationType() === 'namevalue'){ |
| 396 | +// $return['result'] = strstr( $return['result'], 'RESULT' ); |
| 397 | +// //TODO: Finish this for namevalue. |
| 398 | +// } |
| 399 | + if ($this->getCommunicationType() === 'xml'){ |
| 400 | + //$return['result'] = $this->stripResponseHeaders($return['result']); |
| 401 | + $return['status'] = $this->parseXMLResponse($return['result']); |
| 402 | + } |
| 403 | + |
| 404 | + return $return; |
298 | 405 | |
299 | | - // get result string |
300 | | - $result = strstr( $result, 'RESULT' ); |
301 | | - |
302 | 406 | // parse string and display results to the user |
303 | | - $this->fnPayflowGetResults( $data, $result ); |
| 407 | + //TODO: NO NO NO. NO DISPLAY HERE. |
| 408 | + //$this->fnPayflowGetResults( $data, $return['result'] ); |
304 | 409 | } |
| 410 | + |
| 411 | + function parseXMLResponse($rawResponse){ |
| 412 | + //TODO: Something. |
| 413 | + $rawXML = $this->stripResponseHeaders($rawResponse); |
| 414 | + if ($rawXML === false){ |
| 415 | + return false; |
| 416 | + } |
| 417 | + $realXML = new DomDocument('1.0'); |
| 418 | + self::log("Here is the Raw XML: " . $rawXML); |
| 419 | + $realXML->loadXML(trim($rawXML)); |
305 | 420 | |
| 421 | + $aok = true; |
| 422 | + |
| 423 | + //find the node specified by the transaction structure. |
| 424 | + //TODO: Error handling, because: Ugh. |
| 425 | + $result_structure = $this->transactions[$this->currentTransaction()]['result']; |
| 426 | + if(is_array($result_structure)){ |
| 427 | + foreach ($result_structure as $key=>$value){ //should only be one. |
| 428 | + foreach($realXML->getElementsByTagName($key) as $node) { |
| 429 | + if ($value === 'value') { //...stupid. But it's 'value' as opposed to 'attribute' |
| 430 | + if (array_key_exists($node->nodeValue, $this->return_value_map) && $this->return_value_map[$node->nodeValue] !== true){ |
| 431 | + $aok = false; |
| 432 | + } |
| 433 | + } |
| 434 | + if ($value === 'attribute') { |
| 435 | + //TODO: Figure this out. This should mean the key name of one array up, which sounds painful. |
| 436 | + } |
| 437 | + if (is_array($value)){ |
| 438 | + //TODO: ...this is looking like a recursive deal, here. Again. So do that. |
| 439 | + } |
| 440 | + } |
| 441 | + } |
| 442 | + } |
| 443 | + |
| 444 | + //TODO: Make this... you know: abstracty. |
| 445 | + if ($aok === false){ |
| 446 | + foreach($realXML->getElementsByTagName('ERROR') as $node) { |
| 447 | + $errdata = ''; |
| 448 | + foreach($node->childNodes as $childnode){ |
| 449 | + $errdata .= "\n" . $childnode->nodeName . " " . $childnode->nodeValue; |
| 450 | +// if ($childnode->nodeName == "CODE"){ |
| 451 | +// //Excellent place to deal with the particular codes if we want to. |
| 452 | +// } |
| 453 | + } |
| 454 | + self::log("ON NOES! ERROR: $errdata"); |
| 455 | + } |
| 456 | + } else { |
| 457 | + self::log("Response OK"); |
| 458 | + } |
| 459 | + |
| 460 | + //TODO: The bit where you strip all the response data that we might want to save, toss it into an array, and hand it back. |
| 461 | + //We need to be handing more back here than just the... success or failure. Things need to be processed! I mean, probably. |
| 462 | + |
306 | 463 | |
| 464 | + return $aok; |
| 465 | + } |
307 | 466 | |
| 467 | + function stripResponseHeaders($rawResponse){ |
| 468 | + $xmlStart = strpos($rawResponse, '<?xml'); |
| 469 | + if ($xmlStart == false){ //I totally saw this happen one time. No XML, just <RESPONSE>... |
| 470 | + $xmlStart = strpos($rawResponse, '<RESPONSE'); |
| 471 | + } |
| 472 | + if ($xmlStart == false){ //Still false. Your Head Asplode. |
| 473 | + self::log("Wow, that was so messed up I couldn't even parse the response, so here's the thing in its entirety:\n" . $rawResponse, true); |
| 474 | + return false; |
| 475 | + } |
| 476 | + $justXML = substr($rawResponse, $xmlStart); |
| 477 | + return $justXML; |
| 478 | + } |
| 479 | + |
| 480 | + |
| 481 | + public static function log( $msg, $identifier='globalcollect_gateway', $log_level=LOG_INFO ) { |
| 482 | + global $wgGlobalCollectGatewayUseSyslog; |
| 483 | + |
| 484 | + // if we're not using the syslog facility, use wfDebugLog |
| 485 | + if ( !$wgGlobalCollectGatewayUseSyslog ) { |
| 486 | + wfDebugLog( $identifier, $msg ); |
| 487 | + return; |
| 488 | + } |
| 489 | + |
| 490 | + // otherwise, use syslogging |
| 491 | + openlog( $identifier, LOG_ODELAY, LOG_SYSLOG ); |
| 492 | + syslog( $log_level, $msg ); |
| 493 | + closelog(); |
| 494 | + } |
308 | 495 | |
309 | 496 | |
| 497 | + //_______________________________________________________________ |
| 498 | + //copied from payflowpro_gateway/includes/payflowUser.inc |
310 | 499 | |
311 | | -//_______________________________________________________________ |
312 | | -//copied from payflowpro_gateway/includes/payflowUser.inc |
| 500 | + /** |
| 501 | + * Fetch and return the 'order_id' for a transaction |
| 502 | + * |
| 503 | + * Since transactions to PayPal are initially matched internally on their end |
| 504 | + * with the 'order_id' field, but we don't actually care what the order id is, |
| 505 | + * we generate a sufficiently random number to avoid duplication. |
| 506 | + * |
| 507 | + * We go ahead and always generate a random order id becuse if PayPal detects |
| 508 | + * the same order_id more than once, it considers the request a duplicate, even |
| 509 | + * if the data is completely different. |
| 510 | + * |
| 511 | + * @return int |
| 512 | + */ |
| 513 | + function getOrderId() { |
| 514 | + return $this->generateOrderId(); |
| 515 | + } |
313 | 516 | |
314 | | -/** |
315 | | - * Fetch and return the 'order_id' for a transaction |
316 | | - * |
317 | | - * Since transactions to PayPal are initially matched internally on their end |
318 | | - * with the 'order_id' field, but we don't actually care what the order id is, |
319 | | - * we generate a sufficiently random number to avoid duplication. |
320 | | - * |
321 | | - * We go ahead and always generate a random order id becuse if PayPal detects |
322 | | - * the same order_id more than once, it considers the request a duplicate, even |
323 | | - * if the data is completely different. |
324 | | - * |
325 | | - * @return int |
326 | | - */ |
327 | | -function getOrderId() { |
328 | | - return $this->generateOrderId(); |
329 | | -} |
| 517 | + /** |
| 518 | + * Generate an internal order id |
| 519 | + * |
| 520 | + * This is only used internally for tracking a user's 'session' with the credit |
| 521 | + * card form. I mean 'session' in the sense of the moment a credit card page |
| 522 | + * is loaded for the first time (nothing posted to it - a discrete donation |
| 523 | + * session) as opposed to the $_SESSION - as the $_SESSION id could potentially |
| 524 | + * not change between contribution attempts. |
| 525 | + */ |
| 526 | + function getInternalOrderId() { |
| 527 | + global $wgRequest; |
330 | 528 | |
331 | | -/** |
332 | | - * Generate an internal order id |
333 | | - * |
334 | | - * This is only used internally for tracking a user's 'session' with the credit |
335 | | - * card form. I mean 'session' in the sense of the moment a credit card page |
336 | | - * is loaded for the first time (nothing posted to it - a discrete donation |
337 | | - * session) as opposed to the $_SESSION - as the $_SESSION id could potentially |
338 | | - * not change between contribution attempts. |
339 | | - */ |
340 | | -function getInternalOrderId() { |
341 | | - global $wgRequest; |
342 | | - |
343 | | - // is an order_id already set? |
344 | | - //TODO: Change all these to look instead at $this->postdata... I think. |
345 | | - $i_order_id = $wgRequest->getText( 'i_order_id', 0 ); |
346 | | - |
347 | | - // if the form was not just posted OR there's no order_id set, generate one. |
348 | | - if ( !$wgRequest->wasPosted() || !$i_order_id ) { |
349 | | - $i_order_id = $this->generateOrderId(); |
| 529 | + // is an order_id already set? |
| 530 | + //TODO: Change all these to look instead at $this->postdata... I think. |
| 531 | + $i_order_id = $wgRequest->getText( 'i_order_id', 0 ); |
| 532 | + |
| 533 | + // if the form was not just posted OR there's no order_id set, generate one. |
| 534 | + if ( !$wgRequest->wasPosted() || !$i_order_id ) { |
| 535 | + $i_order_id = $this->generateOrderId(); |
| 536 | + } |
| 537 | + |
| 538 | + return $i_order_id; |
350 | 539 | } |
351 | 540 | |
352 | | - return $i_order_id; |
| 541 | + /** |
| 542 | + * Generate an order id |
| 543 | + */ |
| 544 | + function generateOrderId() { |
| 545 | + return (double) microtime() * 1000000 . mt_rand(1000, 9999); |
| 546 | + } |
353 | 547 | } |
354 | | - |
355 | | -/** |
356 | | - * Generate an order id |
357 | | - */ |
358 | | -function generateOrderId() { |
359 | | - return (double) microtime() * 1000000 . mt_rand(); |
360 | | -} |
361 | | -} |
\ No newline at end of file |
Index: branches/fundraising/extensions/DonationInterface/globalcollect_gateway/globalcollect_gateway.php |
— | — | @@ -18,6 +18,8 @@ |
19 | 19 | 'url' => 'http://www.mediawiki.org/wiki/Extension:GlobalCollectGateway', |
20 | 20 | ); |
21 | 21 | |
| 22 | +$wgGlobalCollectGatewayUseSyslog = false; |
| 23 | + |
22 | 24 | // Set up the new special page |
23 | 25 | $dir = dirname( __FILE__ ) . '/'; |
24 | 26 | $wgAutoloadClasses['GlobalCollectGateway'] = $dir . 'globalcollect_gateway.body.php'; |
— | — | @@ -50,15 +52,15 @@ |
51 | 53 | |
52 | 54 | // set defaults, these should be assigned in LocalSettings.php |
53 | 55 | $wgGlobalCollectURL = 'https://ps.gcsip.nl/wdl/wdl'; |
54 | | -//$wgGlobalCollectTestingURL = 'https://pilot-globalcollect.paypal.com'; // GlobalCollect testing URL |
| 56 | +$wgGlobalCollectTestingURL = 'https://'; // GlobalCollect testing URL |
55 | 57 | |
56 | 58 | $wgGlobalCollectMerchantID = ''; // GlobalCollect ID |
57 | 59 | |
58 | 60 | // a boolean to determine if we're in testing mode |
59 | 61 | $wgGlobalCollectGatewayTest = FALSE; |
60 | 62 | |
61 | | -// timeout in seconds for communicating with paypal |
62 | | -$wgGlobalCollectTimeout = 5; |
| 63 | +// timeout in seconds for communicating with [gateway] |
| 64 | +$wgGlobalCollectTimeout = 2; |
63 | 65 | |
64 | 66 | /** |
65 | 67 | * The default form to use |
— | — | @@ -131,13 +133,6 @@ |
132 | 134 | $wgGlobalCollectAllowedHtmlForms = array( $wgGlobalCollectHtmlFormDir . "/demo.html" ); |
133 | 135 | |
134 | 136 | /** |
135 | | - * Configure GlobalCollectproGateway to use syslog for log messages rather than wfDebugLog |
136 | | - * |
137 | | - * @var bool |
138 | | - */ |
139 | | -$wgGlobalCollectGatewayUseSyslog = false; |
140 | | - |
141 | | -/** |
142 | 137 | * Configure price cieling and floor for valid contribution amount. Values |
143 | 138 | * should be in USD. |
144 | 139 | */ |