|
Moodle
2.2.1
http://www.collinsharper.com
|
00001 <?php 00002 // This file is part of Moodle - http://moodle.org/ 00003 // 00004 // Moodle is free software: you can redistribute it and/or modify 00005 // it under the terms of the GNU General Public License as published by 00006 // the Free Software Foundation, either version 3 of the License, or 00007 // (at your option) any later version. 00008 // 00009 // Moodle is distributed in the hope that it will be useful, 00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 // GNU General Public License for more details. 00013 // 00014 // You should have received a copy of the GNU General Public License 00015 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 00016 00030 if (!defined('MOODLE_INTERNAL')) { 00031 die('Direct access to this script is forbidden.'); 00032 } 00033 00034 require_once($CFG->dirroot.'/enrol/authorize/const.php'); 00035 require_once($CFG->dirroot.'/enrol/authorize/localfuncs.php'); 00036 00037 class AuthorizeNet 00038 { 00039 const AN_DELIM = '|'; 00040 const AN_ENCAP = '"'; 00041 00042 const AN_REASON_NOCCTYPE = 17; 00043 const AN_REASON_NOCCTYPE2 = 28; 00044 const AN_REASON_NOACH = 18; 00045 const AN_REASON_ACHONLY = 56; 00046 const AN_REASON_NOACHTYPE = 245; 00047 const AN_REASON_NOACHTYPE2 = 246; 00048 00055 public static function getsettletime($time) 00056 { 00057 $mconfig = get_config('enrol_authorize'); 00058 00059 $cutoff_hour = intval($mconfig->an_cutoff_min); 00060 $cutoff_min = intval($mconfig->an_cutoff_hour); 00061 $cutofftime = strtotime("{$cutoff_hour}:{$cutoff_min}", $time); 00062 if ($cutofftime < $time) { 00063 $cutofftime = strtotime("{$cutoff_hour}:{$cutoff_min}", $time + (24 * 3600)); 00064 } 00065 return $cutofftime; 00066 } 00067 00074 public static function settled($order) 00075 { 00076 return ((AN_STATUS_AUTHCAPTURE == $order->status || AN_STATUS_CREDIT == $order->status) and ($order->settletime > 0) and ($order->settletime < time())); 00077 } 00078 00085 public static function expired(&$order) 00086 { 00087 global $DB; 00088 static $timediff30 = 0; 00089 00090 if ($order->status == AN_STATUS_EXPIRE) { 00091 return true; 00092 } 00093 elseif ($order->status != AN_STATUS_AUTH) { 00094 return false; 00095 } 00096 00097 if (0 == $timediff30) { 00098 $timediff30 = self::getsettletime(time()) - (30 * 24 * 3600); 00099 } 00100 00101 $expired = self::getsettletime($order->timecreated) < $timediff30; 00102 if ($expired) 00103 { 00104 $order->status = AN_STATUS_EXPIRE; 00105 $DB->update_record('enrol_authorize', $order); 00106 } 00107 return $expired; 00108 } 00109 00121 public static function process(&$order, &$message, &$extra, $action=AN_ACTION_NONE, $cctype=NULL) 00122 { 00123 global $CFG, $DB; 00124 static $constpd = array(); 00125 require_once($CFG->libdir.'/filelib.php'); 00126 00127 $mconfig = get_config('enrol_authorize'); 00128 00129 if (empty($constpd)) { 00130 $mconfig = get_config('enrol_authorize'); 00131 $constpd = array( 00132 'x_version' => '3.1', 00133 'x_delim_data' => 'True', 00134 'x_delim_char' => self::AN_DELIM, 00135 'x_encap_char' => self::AN_ENCAP, 00136 'x_relay_response' => 'FALSE', 00137 'x_login' => $mconfig->an_login 00138 ); 00139 00140 if (!empty($mconfig->an_tran_key)) { 00141 $constpd['x_tran_key'] = $mconfig->an_tran_key; 00142 } 00143 else { 00144 $constpd['x_password'] = $mconfig->an_password; 00145 } 00146 } 00147 00148 if (empty($order) or empty($order->id)) { 00149 $message = "Check order->id!"; 00150 return AN_RETURNZERO; 00151 } 00152 00153 $method = $order->paymentmethod; 00154 if (empty($method)) { 00155 $method = AN_METHOD_CC; 00156 } 00157 elseif ($method != AN_METHOD_CC && $method != AN_METHOD_ECHECK) { 00158 $message = "Invalid method: $method"; 00159 return AN_RETURNZERO; 00160 } 00161 00162 $action = intval($action); 00163 if ($method == AN_METHOD_ECHECK) { 00164 if ($action != AN_ACTION_AUTH_CAPTURE && $action != AN_ACTION_CREDIT) { 00165 $message = "Please perform AUTH_CAPTURE or CREDIT for echecks"; 00166 return AN_RETURNZERO; 00167 } 00168 } 00169 00170 $pd = $constpd; 00171 $pd['x_method'] = $method; 00172 $test = !empty($mconfig->an_test); 00173 $pd['x_test_request'] = ($test ? 'TRUE' : 'FALSE'); 00174 00175 switch ($action) { 00176 case AN_ACTION_AUTH_ONLY: 00177 case AN_ACTION_CAPTURE_ONLY: 00178 case AN_ACTION_AUTH_CAPTURE: 00179 { 00180 if ($order->status != AN_STATUS_NONE) { 00181 $message = "Order status must be AN_STATUS_NONE(0)!"; 00182 return AN_RETURNZERO; 00183 } 00184 elseif (empty($extra)) { 00185 $message = "Need extra fields!"; 00186 return AN_RETURNZERO; 00187 } 00188 elseif (($action == AN_ACTION_CAPTURE_ONLY) and empty($extra->x_auth_code)) { 00189 $message = "x_auth_code is required for capture only transactions!"; 00190 return AN_RETURNZERO; 00191 } 00192 00193 $ext = (array)$extra; 00194 $pd['x_type'] = (($action==AN_ACTION_AUTH_ONLY) 00195 ? 'AUTH_ONLY' :( ($action==AN_ACTION_CAPTURE_ONLY) 00196 ? 'CAPTURE_ONLY' : 'AUTH_CAPTURE')); 00197 foreach($ext as $k => $v) { 00198 $pd[$k] = $v; 00199 } 00200 } 00201 break; 00202 00203 case AN_ACTION_PRIOR_AUTH_CAPTURE: 00204 { 00205 if ($order->status != AN_STATUS_AUTH) { 00206 $message = "Order status must be authorized!"; 00207 return AN_RETURNZERO; 00208 } 00209 if (self::expired($order)) { 00210 $message = "Transaction must be captured within 30 days. EXPIRED!"; 00211 return AN_RETURNZERO; 00212 } 00213 $pd['x_type'] = 'PRIOR_AUTH_CAPTURE'; 00214 $pd['x_trans_id'] = $order->transid; 00215 } 00216 break; 00217 00218 case AN_ACTION_CREDIT: 00219 { 00220 if ($order->status != AN_STATUS_AUTHCAPTURE) { 00221 $message = "Order status must be authorized/captured!"; 00222 return AN_RETURNZERO; 00223 } 00224 if (!self::settled($order)) { 00225 $message = "Order must be settled. Try VOID, check Cut-Off time if it fails!"; 00226 return AN_RETURNZERO; 00227 } 00228 if (empty($extra->amount)) { 00229 $message = "No valid amount!"; 00230 return AN_RETURNZERO; 00231 } 00232 $timenowsettle = self::getsettletime(time()); 00233 $timediff = $timenowsettle - (120 * 3600 * 24); 00234 if ($order->settletime < $timediff) { 00235 $message = "Order must be credited within 120 days!"; 00236 return AN_RETURNZERO; 00237 } 00238 00239 $pd['x_type'] = 'CREDIT'; 00240 $pd['x_trans_id'] = $order->transid; 00241 $pd['x_currency_code'] = $order->currency; 00242 $pd['x_invoice_num'] = $extra->orderid; 00243 $pd['x_amount'] = $extra->amount; 00244 if ($method == AN_METHOD_CC) { 00245 $pd['x_card_num'] = sprintf("%04d", intval($order->refundinfo)); 00246 } 00247 elseif ($method == AN_METHOD_ECHECK && empty($order->refundinfo)) { 00248 $message = "Business checkings can be refunded only."; 00249 return AN_RETURNZERO; 00250 } 00251 } 00252 break; 00253 00254 case AN_ACTION_VOID: 00255 { 00256 if (self::expired($order) || self::settled($order)) { 00257 $message = "The transaction cannot be voided due to the fact that it is expired or settled."; 00258 return AN_RETURNZERO; 00259 } 00260 $pd['x_type'] = 'VOID'; 00261 $pd['x_trans_id'] = $order->transid; 00262 } 00263 break; 00264 00265 default: 00266 { 00267 $message = "Invalid action: $action"; 00268 return AN_RETURNZERO; 00269 } 00270 } 00271 00272 $headers = array('Connection' => 'close'); 00273 if (! (empty($mconfig->an_referer) || $mconfig->an_referer == "http://")) { 00274 $headers['Referer'] = $mconfig->an_referer; 00275 } 00276 00277 @ignore_user_abort(true); 00278 if (intval(ini_get('max_execution_time')) > 0) { 00279 @set_time_limit(300); 00280 } 00281 00282 $host = $test ? 'test.authorize.net' : 'secure.authorize.net'; 00283 $data = download_file_content("https://$host:443/gateway/transact.dll", $headers, $pd, false, 300, 60, true); 00284 if (!$data) { 00285 $message = "No connection to https://$host:443"; 00286 return AN_RETURNZERO; 00287 } 00288 $response = explode(self::AN_ENCAP.self::AN_DELIM.self::AN_ENCAP, $data); 00289 if ($response === false) { 00290 $message = "response error"; 00291 return AN_RETURNZERO; 00292 } 00293 $rcount = count($response) - 1; 00294 if ($response[0]{0} == self::AN_ENCAP) { 00295 $response[0] = substr($response[0], 1); 00296 } 00297 if (substr($response[$rcount], -1) == self::AN_ENCAP) { 00298 $response[$rcount] = substr($response[$rcount], 0, -1); 00299 } 00300 00301 $responsecode = intval($response[0]); 00302 if ($responsecode == AN_APPROVED || $responsecode == AN_REVIEW) 00303 { 00304 $transid = floatval($response[6]); 00305 if ($test || $transid == 0) { 00306 return $responsecode; // don't update original transaction in test mode. 00307 } 00308 switch ($action) { 00309 case AN_ACTION_AUTH_ONLY: 00310 case AN_ACTION_CAPTURE_ONLY: 00311 case AN_ACTION_AUTH_CAPTURE: 00312 case AN_ACTION_PRIOR_AUTH_CAPTURE: 00313 { 00314 $order->transid = $transid; 00315 00316 if ($method == AN_METHOD_CC) { 00317 if ($action == AN_ACTION_AUTH_ONLY || $responsecode == AN_REVIEW) { 00318 $order->status = AN_STATUS_AUTH; 00319 } else { 00320 $order->status = AN_STATUS_AUTHCAPTURE; 00321 $order->settletime = self::getsettletime(time()); 00322 } 00323 } 00324 elseif ($method == AN_METHOD_ECHECK) { 00325 $order->status = AN_STATUS_UNDERREVIEW; 00326 } 00327 00328 $DB->update_record('enrol_authorize', $order); 00329 } 00330 break; 00331 00332 case AN_ACTION_CREDIT: 00333 { 00334 // Credit generates new transaction id. 00335 // So, $extra must be updated, not $order. 00336 $extra->status = AN_STATUS_CREDIT; 00337 $extra->transid = $transid; 00338 $extra->settletime = self::getsettletime(time()); 00339 $extra->id = $DB->insert_record('enrol_authorize_refunds', $extra); 00340 } 00341 break; 00342 00343 case AN_ACTION_VOID: 00344 { 00345 $tableupdate = 'enrol_authorize'; 00346 if ($order->status == AN_STATUS_CREDIT) { 00347 $tableupdate = 'enrol_authorize_refunds'; 00348 unset($order->paymentmethod); 00349 } 00350 $order->status = AN_STATUS_VOID; 00351 $DB->update_record($tableupdate, $order); 00352 } 00353 break; 00354 } 00355 } 00356 else 00357 { 00358 $reasonno = $response[2]; 00359 $reasonstr = "reason" . $reasonno; 00360 $message = get_string($reasonstr, "enrol_authorize"); 00361 if ($message == '[[' . $reasonstr . ']]') { 00362 $message = isset($response[3]) ? $response[3] : 'unknown error'; 00363 } 00364 if ($method == AN_METHOD_CC && !empty($mconfig->an_avs) && $response[5] != "P") { 00365 $avs = "avs" . strtolower($response[5]); 00366 $stravs = get_string($avs, "enrol_authorize"); 00367 $message .= "<br />" . get_string("avsresult", "enrol_authorize", $stravs); 00368 } 00369 if (!$test) { // Autoconfigure :) 00370 switch($reasonno) { 00371 // Credit card type isn't accepted 00372 case self::AN_REASON_NOCCTYPE: 00373 case self::AN_REASON_NOCCTYPE2: 00374 { 00375 if (!empty($cctype)) { 00376 $ccaccepts = get_list_of_creditcards(); 00377 00378 unset($ccaccepts[$cctype]); 00379 set_config("an_acceptcc_{$cctype}", 0, 'enrol_authorize'); 00380 00381 foreach ($ccaccepts as $key=>$val) { 00382 set_config("an_acceptcc_{$key}", 1, 'enrol_authorize'); 00383 } 00384 message_to_admin("$message ($cctype) This is new config(an_acceptccs):", $ccaccepts); 00385 } 00386 break; 00387 } 00388 // Echecks only 00389 case self::AN_REASON_ACHONLY: 00390 { 00391 set_config("an_acceptmethod_".AN_METHOD_ECHECK, 1, 'enrol_authorize'); 00392 message_to_admin("$message This is new config(an_acceptmethods):", array(AN_METHOD_ECHECK)); 00393 break; 00394 } 00395 // Echecks aren't accepted 00396 case self::AN_REASON_NOACH: 00397 { 00398 set_config("an_acceptmethod_".AN_METHOD_CC, 1, 'enrol_authorize'); 00399 message_to_admin("$message This is new config(an_acceptmethods):", array(AN_METHOD_CC)); 00400 break; 00401 } 00402 // This echeck type isn't accepted 00403 case self::AN_REASON_NOACHTYPE: 00404 case self::AN_REASON_NOACHTYPE2: 00405 { 00406 if (!empty($extra->x_echeck_type)) { 00407 switch ($extra->x_echeck_type) { 00408 // CCD=BUSINESSCHECKING 00409 case 'CCD': 00410 { 00411 set_config('an_acceptecheck_CHECKING', 1, 'enrol_authorize'); 00412 set_config('an_acceptecheck_SAVINGS', 1, 'enrol_authorize'); 00413 message_to_admin("$message This is new config(an_acceptechecktypes):", array('CHECKING','SAVINGS')); 00414 } 00415 break; 00416 // WEB=CHECKING or SAVINGS 00417 case 'WEB': 00418 { 00419 set_config('an_acceptecheck_BUSINESSCHECKING', 1, 'enrol_authorize'); 00420 message_to_admin("$message This is new config(an_acceptechecktypes):", array('BUSINESSCHECKING')); 00421 } 00422 break; 00423 } 00424 } 00425 break; 00426 } 00427 } 00428 } 00429 } 00430 return $responsecode; 00431 } 00432 } 00433 00434