CREDIT & VOID implementation.

TO DO:
- admin.php for course payment management.
- Transaction cut-off time
This commit is contained in:
ethem
2005-12-12 17:32:00 +00:00
parent dbe1f37949
commit d6ed7dae6a
5 changed files with 209 additions and 91 deletions
+118 -48
View File
@@ -3,37 +3,35 @@
/**
* No action.
*/
define('AN_ACTION_NONE', 0x0);
define('AN_ACTION_NONE', 0x00);
/**
* Authorize only. Don't capture.
*/
define('AN_ACTION_AUTH_ONLY', 0x1);
define('AN_ACTION_AUTH_ONLY', 0x01);
/**
* Authorized before, capture now.
*/
define('AN_ACTION_PRIOR_AUTH_CAPTURE', 0x2);
define('AN_ACTION_PRIOR_AUTH_CAPTURE', 0x02);
/**
* Authorize and capture
*/
define('AN_ACTION_AUTH_CAPTURE', 0x3);
/**
* Cancel transaction in status
* - authorized
* - auth_captured/pending settle
*
* @todo cut-off time
*/
define('AN_ACTION_VOID', 0x4);
define('AN_ACTION_AUTH_CAPTURE', 0x03);
/**
* Refund it.
* must be in 120 days after settled.
* auth_captured/settled.
* must be performed in 120 days after settled.
* status must be auth_captured/settled.
* can be credited up to original amount.
* -- generates new transid. SAVE IT.
*/
define('AN_ACTION_CREDIT', 0x8);
define('AN_ACTION_CREDIT', 0x04);
/**
* Cancel transaction in status
* - authorized: don't settle.
* - auth_captured/pending settle
* - credited mistakenly, void it.
* @todo cut-off time
*/
define('AN_ACTION_VOID', 0x08);
/**
* authorizenet_action
@@ -45,15 +43,15 @@ define('AN_ACTION_CREDIT', 0x8);
* @return bool true, transaction was successful, false otherwise
* @author Ethem Evlice <ethem a.t evlice d.o.t com>
* @uses $CFG
* @todo AN_ACTION_VOID and AN_ACTION_CREDIT
* @todo cut-off time
*/
function authorizenet_action(&$order, &$message, $action=AN_ACTION_NONE, $extra = null)
{
global $CFG;
static $conststring;
$an_test = !empty($CFG->an_test);
if (empty($conststring)) {
$consdata = array (
'x_version' => '3.1',
@@ -68,14 +66,14 @@ function authorizenet_action(&$order, &$message, $action=AN_ACTION_NONE, $extra
$str = '';
foreach($consdata as $ky => $vl) { $str .= $ky . '=' . urlencode($vl) . '&'; }
$str .= (!empty($CFG->an_tran_key)) ?
"x_tran_key" . "=" . urlencode($CFG->an_tran_key):
"x_tran_key" . "=" . urlencode($CFG->an_tran_key):
"x_password" . "=" . urlencode($CFG->an_password);
$conststring = $str;
$conststring = $str;
}
$action = intval($action);
// sanity check
if (empty($order) || empty($order->id)) {
$message = "check order->id!";
@@ -85,7 +83,7 @@ function authorizenet_action(&$order, &$message, $action=AN_ACTION_NONE, $extra
$message = "no action taken!";
return false;
}
$poststring = $conststring;
switch ($action) {
case AN_ACTION_AUTH_ONLY:
@@ -97,7 +95,7 @@ function authorizenet_action(&$order, &$message, $action=AN_ACTION_NONE, $extra
}
if (empty($extra)) {
$message = "need extra fields!";
return false;
return false;
}
$ext = (array)$extra;
$poststring .= "&" . "x_type=" . ($action==AN_ACTION_AUTH_ONLY ? "AUTH_ONLY" : "AUTH_CAPTURE");
@@ -113,16 +111,79 @@ function authorizenet_action(&$order, &$message, $action=AN_ACTION_NONE, $extra
$message = "order->status must be AN_STATUS_AUTH!";
return false;
}
// 30 days. +1 = cut-off time
$timediff = time() - (31 * 3600 * 24);
if ($order->timecreated < $timediff) {
$message = "Transaction must be captured within 30 days. EXPIRED!";
return false;
}
$poststring .= "&" . "x_type=PRIOR_AUTH_CAPTURE";
$poststring .= "&" . "x_trans_id=" . urlencode($order->transid);
break;
break;
}
case AN_ACTION_VOID: // 30 days
case AN_ACTION_CREDIT: // 120 days
case AN_ACTION_CREDIT:
{
$message = "not implemented yet!";
return false;
if ($order->status != (AN_STATUS_AUTH | AN_STATUS_CAPTURE)) {
$message = "order->status must be AN_STATUS_AUTH & AN_STATUS_CAPTURE!";
return false;
}
// 120 days
$timediff = time() - (120 * 3600 * 24);
if ($order->timecreated < $timediff) {
$message = "Order can be credited within 120 days!";
return false;
}
// up to original amount
$total = doubleval($extra->sum) + doubleval($extra->amount);
if ($total > $order->amount) {
$message = "Can be credited up to original amount.";
return false;
}
$poststring .= "&" . "x_type=CREDIT";
$poststring .= "&" . "x_trans_id=" . urlencode($order->transid);
$poststring .= "&" . "x_card_num=" . urlencode(sprintf("%04d", intval($order->cclastfour)));
$poststring .= "&" . "x_currency_code=" . urlencode($extra->currency);
$poststring .= "&" . "x_amount=" . urlencode($extra->amount);
break;
}
case AN_ACTION_VOID:
{
// only: authonly, authcapture, credit
if ($order->status != AN_STATUS_AUTH &&
$order->status != (AN_STATUS_AUTH | AN_STATUS_CAPTURE) &&
$order->status != AN_STATUS_CREDIT) {
$message = "order->status must be AUTH, AUTH_CAPTURE or CREDIT!";
return false;
}
if ($order->status == AN_STATUS_AUTH) {
// 30 days for authonly, make it expired (***********timeupdated)
$timediff = time() - (30 * 3600 * 24);
if ($order->timecreated < $timediff) {
$message = "Auth_only transaction can be voided within 30 days!";
$order->status = AN_STATUS_EXPIRED;
return false;
}
} elseif ($order->status == (AN_STATUS_AUTH | AN_STATUS_CAPTURE)) {
// 1 day. Cancel pending settlement.
$timediff = time() - (2 * 3600 * 24); // TO DO: Cut-off time
if ($order->timecreated < $timediff) {
$message = "Settled transaction cannot be voided. Try REFUND!";
return false;
}
} elseif ($order->status == AN_STATUS_CREDIT) {
// 120 days for credit
$timediff = time() - (120 * 3600 * 24);
if ($order->timecreated < $timediff) {
$message = "Ops! Settled transaction must be credited within 120 days!";
return false;
}
}
// OK.
$poststring .= "&" . "x_type=VOID";
$poststring .= "&" . "x_trans_id=" . urlencode($order->transid);
}
default: { // ???
@@ -130,13 +191,13 @@ function authorizenet_action(&$order, &$message, $action=AN_ACTION_NONE, $extra
return false;
}
}
// referer
$anrefererheader = '';
if (!(empty($CFG->an_referer) || $CFG->an_referer == "http://" || $CFG->an_referer == "https://")) {
$anrefererheader = "Referer: " . $CFG->an_referer . "\r\n";
}
$response = array();
$connect_host = $an_test ? AN_HOST_TEST : AN_HOST;
$fp = fsockopen("ssl://" . $connect_host, AN_PORT, $errno, $errstr, 60);
@@ -144,7 +205,7 @@ function authorizenet_action(&$order, &$message, $action=AN_ACTION_NONE, $extra
$message = "no connection: $errstr ($errno)";
return false;
}
fputs($fp,
"POST " . AN_PATH . " HTTP/1.0\r\n" .
"Host: $connect_host\r\n" . $anrefererheader .
@@ -153,7 +214,7 @@ function authorizenet_action(&$order, &$message, $action=AN_ACTION_NONE, $extra
"Content-length: " . strlen($poststring) . "\r\n\r\n" .
$poststring . "\r\n"
);
$tmpstr = '';
while(!feof($fp) && !stristr($tmpstr, 'content-length')) {
$tmpstr = fgets($fp, 4096);
@@ -179,26 +240,35 @@ function authorizenet_action(&$order, &$message, $action=AN_ACTION_NONE, $extra
if (substr($response[$rcount], -1) == AN_ENCAP) {
$response[$rcount] = substr($response[$rcount], 0, -1);
}
if ($response[0] == AN_APPROVED) {
$order->authcode = strval($response[4]); // Authorization or Approval code
$order->avscode = strval($response[5]); // Address Verification System code
$order->transid = strval($response[6]); // TransactionID
$order->transid = strval($response[6]); // TransactionID.
$order->timeupdated = time();
switch ($action) {
case AN_ACTION_AUTH_ONLY:
$order->status |= AN_STATUS_AUTH;
break;
case AN_ACTION_AUTH_CAPTURE:
$order->status = AN_STATUS_AUTH | AN_STATUS_CAPTURE;
$order->authcode = strval($response[4]); // Authorization or Approval code
$order->avscode = strval($response[5]); // Address Verification System code
if ($action == AN_ACTION_AUTH_ONLY) {
$order->status = AN_STATUS_AUTH;
}
else {
$order->status = AN_STATUS_AUTH | AN_STATUS_CAPTURE;
}
break;
case AN_ACTION_PRIOR_AUTH_CAPTURE:
$order->status |= AN_STATUS_CAPTURE;
$order->status = AN_STATUS_AUTH | AN_STATUS_CAPTURE;
break;
case AN_ACTION_CREDIT: // generates new TransactionID
$order->status = AN_STATUS_CREDIT;
break;
case AN_ACTION_VOID:
$order->status = AN_STATUS_VOID;
break;
}
return true;
}
else {
+24
View File
@@ -36,6 +36,30 @@ function authorize_upgrade($oldversion=0) {
execute_sql(" UPDATE {$CFG->prefix}enrol_authorize SET timecreated='$timenow', timeupdated='$timenow', status='$status' ", false);
}
if ($oldversion < 2005121200) {
// new fields for refund and sales reports.
$defaultcurrency = empty($CFG->enrol_currency) ? 'USD' : $CFG->enrol_currency;
table_column('enrol_authorize', '', 'amount', 'varchar', '10', '', '0', 'not null', 'timeupdated');
table_column('enrol_authorize', '', 'currency', 'char', '3', '', $defaultcurrency, 'not null', 'amount');
modify_database("","CREATE TABLE prefix_enrol_authorize_refunds (
`id` int(10) unsigned NOT NULL auto_increment,
`orderid` int(10) unsigned NOT NULL default 0,
`refundtype` int(1) unsigned NOT NULL default 0,
`amount` varchar(10) NOT NULL default '',
`transid` int(10) unsigned NULL default 0,
PRIMARY KEY (`id`),
KEY `orderid` (`orderid`)
);");
// defaults.
if ($courses = get_records_select('course', '', '', 'id, cost, currency')) {
foreach ($courses as $course) {
execute_sql("UPDATE {$CFG->prefix}enrol_authorize
SET amount = '$course->cost', currency = '$course->currency'
WHERE courseid = '$course->id'", false);
}
}
}
return $result;
}
+24 -1
View File
@@ -20,7 +20,7 @@ function authorize_upgrade($oldversion=0) {
modify_database('',"CREATE INDEX prefix_enrol_authorize_courseid_idx ON prefix_enrol_authorize (courseid);");
modify_database('',"CREATE INDEX prefix_enrol_authorize_userid_idx ON prefix_enrol_authorize (userid);");
}
if ($oldversion < 2005112100) {
include_once("$CFG->dirroot/enrol/authorize/enrol.php");
@@ -35,6 +35,29 @@ function authorize_upgrade($oldversion=0) {
$status = AN_STATUS_AUTH | AN_STATUS_CAPTURE;
execute_sql(" UPDATE {$CFG->prefix}enrol_authorize SET timecreated='$timenow', timeupdated='$timenow', status='$status' ", false);
}
if ($oldversion < 2005121200) {
// new fields for refund and sales reports.
$defaultcurrency = empty($CFG->enrol_currency) ? 'USD' : $CFG->enrol_currency;
table_column('enrol_authorize', '', 'amount', 'varchar', '10', '', '0', 'not null', 'timeupdated');
table_column('enrol_authorize', '', 'currency', 'char', '3', '', $defaultcurrency, 'not null', 'amount');
modify_database("","CREATE TABLE prefix_enrol_authorize_refunds (
id SERIAL PRIMARY KEY,
orderid INTEGER NOT NULL default 0,
refundtype INTEGER NOT NULL default 0,
amount varchar(10) NOT NULL default '',
transid INTEGER NULL default 0
);");
modify_database("","CREATE INDEX prefix_enrol_authorize_refunds_orderid_idx ON prefix_enrol_authorize_refunds (orderid);");
// defaults.
if ($courses = get_records_select('course', '', '', 'id, cost, currency')) {
foreach ($courses as $course) {
execute_sql("UPDATE {$CFG->prefix}enrol_authorize
SET amount = '$course->cost', currency = '$course->currency'
WHERE courseid = '$course->id'", false);
}
}
}
return $result;
}
+42 -41
View File
@@ -15,29 +15,29 @@ define('AN_ENCAP', '"');
* New order. No transaction was made.
*/
define('AN_STATUS_NONE', 0x00);
/**
* Authorized.
*/
define('AN_STATUS_AUTH', 0x01);
/**
* Captured.
*/
define('AN_STATUS_CAPTURE', 0x02);
/**
* Refunded.
*/
define('AN_STATUS_CREDIT', 0x04);
/**
* Voided.
*/
define('AN_STATUS_VOID', 0x08);
/**
* Expired.
*/
define('AN_STATUS_EXPIRED', 0x10);
define('AN_STATUS_EXPIRE', 0x10);
require_once("$CFG->dirroot/enrol/enrol.class.php");
/**
* enrolment_plugin_authorize
*
@@ -51,7 +51,7 @@ class enrolment_plugin extends enrolment_base
*/
var $ccerrormsg;
/**
* Shows a credit card form for registration.
*
@@ -128,7 +128,7 @@ class enrolment_plugin extends enrolment_base
}
}
/**
* Credit card number mode.
* Send to authorize.net.
@@ -149,9 +149,9 @@ class enrolment_plugin extends enrolment_base
$this->ccerrormsg = get_string("allfieldsrequired");
return;
}
$this->prevent_double_paid($course);
$exp_date = ($form->ccexpiremm < 10) ? strval('0'.$form->ccexpiremm) : strval($form->ccexpiremm);
$exp_date .= $form->ccexpireyyyy;
$valid_cc = CCVal($form->cc, $form->cctype, $exp_date);
@@ -162,7 +162,7 @@ class enrolment_plugin extends enrolment_base
$this->ccerrormsg = get_string( (($valid_cc===0) ? 'ccexpired' : 'ccinvalid'), 'enrol_authorize' );
return;
}
// NEW ORDER
$timenow = time();
$order = new stdClass();
@@ -182,7 +182,7 @@ class enrolment_plugin extends enrolment_base
$this->ccerrormsg = "Insert record error. Admin has been notified!";
return;
}
$extra = new stdClass();
$extra->x_first_name = $form->ccfirstname;
$extra->x_last_name = $form->cclastname;
@@ -204,10 +204,10 @@ class enrolment_plugin extends enrolment_base
$extra->x_fax = '';
$extra->x_invoice_num = $order->id;
$extra->x_description = $course->shortname;
$message = null;
$an_review = !empty($CFG->an_review);
$action = $an_review ? AN_ACTION_AUTH_ONLY : AN_ACTION_AUTH_CAPTURE;
$action = $an_review ? AN_ACTION_AUTH_ONLY : AN_ACTION_AUTH_CAPTURE;
$success = authorizenet_action($order, $message, $action, $extra);
if ($success) {
@@ -221,11 +221,11 @@ class enrolment_plugin extends enrolment_base
$this->email_to_admin("Error while trying to update data. Please edit manually this record: " .
"ID=$order->id in enrol_authorize table.", $order);
}
redirect($CFG->wwwroot, get_string("emailnotify", "enrol_authorize"), '60');
redirect($CFG->wwwroot, get_string("reviewnotify", "enrol_authorize"), '60');
return;
}
// credit card captured, ENROL...
// credit card captured, ENROL...
if (!update_record("enrol_authorize", $order)) {
$this->email_to_admin( "Error while trying to update data. Please edit manually this record: " .
"ID=$order->id in enrol_authorize table.", $order);
@@ -285,7 +285,7 @@ class enrolment_plugin extends enrolment_base
}
}
/**
* zero_cost
*
@@ -297,8 +297,8 @@ class enrolment_plugin extends enrolment_base
$curcost = $this->get_course_cost($course);
return (abs($curcost['cost']) < 0.01);
}
/**
* get_course_cost
*
@@ -309,7 +309,7 @@ class enrolment_plugin extends enrolment_base
function get_course_cost($course)
{
global $CFG;
$cost = (float)0;
$currency = (!empty($course->currency))
? $course->currency :( empty($CFG->enrol_currency)
@@ -318,7 +318,7 @@ class enrolment_plugin extends enrolment_base
if (!empty($course->cost)) {
$cost = (float)(((float)$course->cost) < 0) ? $CFG->enrol_cost : $course->cost;
}
$cost = format_float($cost, 2);
$ret = array('cost' => $cost, 'currency' => $currency);
@@ -358,7 +358,7 @@ class enrolment_plugin extends enrolment_base
return $str;
}
/**
* Shows config form & errors
*
@@ -384,7 +384,7 @@ class enrolment_plugin extends enrolment_base
if (empty($CFG->loginhttps)) {
notify("\$CFG->loginhttps must be ON");
}
// ******************* AUTOCAPTURE *******************
if (!(empty($frm->an_review) || $frm->an_review_day < 1)) {
// ++ENABLED++
@@ -412,7 +412,7 @@ class enrolment_plugin extends enrolment_base
include($CFG->dirroot.'/enrol/authorize/config.html');
}
/**
* process_config
*
@@ -423,7 +423,7 @@ class enrolment_plugin extends enrolment_base
function process_config($config)
{
global $CFG;
// ENROL config
set_config('enrol_cost', optional_param('enrol_cost', 5, PARAM_INT) );
set_config('enrol_currency', optional_param('enrol_currency', 'USD', PARAM_ALPHA) );
@@ -432,7 +432,7 @@ class enrolment_plugin extends enrolment_base
set_config('enrol_mailadmins', optional_param('enrol_mailadmins', '') );
// AUTHORIZE.NET config
// not required!
set_config('an_test', optional_param('an_test', '') );
set_config('an_referer', optional_param('an_referer', 'http://', PARAM_URL) );
@@ -473,11 +473,11 @@ class enrolment_plugin extends enrolment_base
set_config('an_review', $review_val);
set_config('an_review_day', $review_day_val);
}
return true;
}
/**
* email_to_admin
*
@@ -496,8 +496,8 @@ class enrolment_plugin extends enrolment_base
}
email_to_user($admin, $admin, "CC ERROR: ".$subject, $message);
}
/**
* prevent_double_paid
*
@@ -513,15 +513,15 @@ class enrolment_plugin extends enrolment_base
redirect($CFG->wwwroot . '/login/logout.php');
return;
}
if ($rec = get_record('enrol_authorize', 'userid',$USER->id, 'courseid',$course->id, 'status',AN_STATUS_AUTH, 'id')) {
$a->orderid = $rec->id;
redirect($CFG->wwwroot, get_string("paymentproggress", "enrol_authorize", $a), '20');
redirect($CFG->wwwroot, get_string("paymentpending", "enrol_authorize", $a), '20');
return;
}
}
/**
* check_openssl_loaded
*
@@ -532,7 +532,7 @@ class enrolment_plugin extends enrolment_base
return extension_loaded('openssl');
}
/**
* cron
* @access public
@@ -556,21 +556,22 @@ class enrolment_plugin extends enrolment_base
delete_records_select('enrol_authorize', $select);
}
}
if ($random100 > 80) { // EXPIRED: Transactions with auth_only will be expired 30 days later.
$select = "(status = '" .AN_STATUS_AUTH. "') AND (timeupdated = '0') AND (timecreated < '$timediff30')";
execute_sql("UPDATE {$CFG->prefix}enrol_authorize SET timeupdated = '$timenow', status = '" .AN_STATUS_EXPIRED. "' WHERE $select", false);
execute_sql("UPDATE {$CFG->prefix}enrol_authorize SET timeupdated = '$timenow', status = '" .AN_STATUS_EXPIRE. "' WHERE $select", false);
}
if (empty($CFG->an_review) || empty($CFG->an_review_day) || $CFG->an_review_day < 1) {
// AUTOCAPTURE disabled. admin, teacher review it manually
return;
return;
}
// AUTO-CAPTURE: it must be captured within 30 days. Otherwise it will expired.
$timediffcnf = $timenow - (intval($CFG->an_review_day) * 3600 * 24);
$select = "(status = '" . AN_STATUS_AUTH . "') AND (timeupdated = '0') AND (timecreated < '$timediffcnf') AND (timecreated > '$timediff30')";
if ($orders = get_records_select('enrol_authorize', $select)) {
set_time_limit(0);
require_once("$CFG->dirroot/enrol/authorize/action.php");
$this->log = "AUTHORIZE.NET AUTOCAPTURE CRON: " . userdate($timenow) . "\n";
$message = null;
+1 -1
View File
@@ -1,6 +1,6 @@
<?PHP // $Id$
$module->version = 2005112100;
$module->version = 2005121200;
$module->requires = 2005072200;
?>