1039 lines
42 KiB
PHP
1039 lines
42 KiB
PHP
<?php
|
|
$noSession = 1;
|
|
require("db.php");
|
|
include("include/school-functions.php");
|
|
include("include/logging-functions.php");
|
|
include("include/date-time.php");
|
|
include "table.php";
|
|
|
|
if (!is_array($_POST) || count($_POST) == 0) {
|
|
// $contents = file_get_contents("/m/data1/hotlunches.net/ppPayment.log");
|
|
// echo(nl2br(htmlentities($contents)));
|
|
// echo($contents);
|
|
echo("Permission denied");
|
|
exit();
|
|
}
|
|
|
|
|
|
$ptime = time();
|
|
$time = date("Y-m-d H:i:s",$ptime);
|
|
$ltime = date("Y-m-d.H.i.s",$ptime);
|
|
|
|
// start capturing output
|
|
//
|
|
// NOTE: logging here must never be fatal. This runs inside the ob_start()
|
|
// handler at script shutdown, so an error escaping this function kills the
|
|
// response and PayPal sees a 500 and retries the IPN - even though the
|
|
// payment itself was already processed successfully.
|
|
function ppWriteLog($path, $contents, $mode = "w") {
|
|
$dir = dirname($path);
|
|
if (!is_dir($dir)) @mkdir($dir, 0775, true);
|
|
$f = @fopen($path, $mode);
|
|
if ($f === false) {
|
|
error_log("ppPayment: unable to open log file $path");
|
|
return;
|
|
}
|
|
@fwrite($f, $contents);
|
|
@fclose($f);
|
|
}
|
|
|
|
function saveOutput($contents) {
|
|
global $ltime, $school_num;
|
|
|
|
// Log beside this script unless PPPAYMENT_LOGDIR overrides it, so the
|
|
// path follows the deployment instead of being pinned to one server.
|
|
$BASEDIR = getenv('PPPAYMENT_LOGDIR');
|
|
if (!$BASEDIR) $BASEDIR = __DIR__;
|
|
|
|
ppWriteLog("$BASEDIR/ppPayment.log", $contents, "w");
|
|
ppWriteLog("$BASEDIR/ppPayment.trx.log", $contents, "a");
|
|
ppWriteLog("$BASEDIR/logs/paypal/pp.$school_num.$ltime", $contents, "w");
|
|
|
|
return nl2br(htmlentities($contents));
|
|
}
|
|
|
|
// function to execute a mysql query after echoing the query statement and return result
|
|
function pp_query($query) {
|
|
echo("{$query}\n");
|
|
$r = db_query($query);
|
|
if (stripos($query,"update") !== false || stripos($query,"insert") !== false || stripos($query,"delete") !== false) {
|
|
$n = db_affected_rows();
|
|
echo("Affected Rows: $n\n");
|
|
}
|
|
return($r);
|
|
}
|
|
|
|
// function to execute a mysql query after echoing the query statement and return value
|
|
function pp_getVal($query) {
|
|
echo("{$query}\n");
|
|
$r = db_getVal($query);
|
|
return($r);
|
|
}
|
|
|
|
function ppCacertPath() {
|
|
$cacert = dirname(__FILE__) . '/cacert.pem';
|
|
return is_file($cacert) ? $cacert : '';
|
|
}
|
|
|
|
function ppAddResolvedIp(&$ips, $ip) {
|
|
$ip = trim($ip, "[] \t\r\n");
|
|
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
|
|
if (!in_array($ip, $ips['v4'], true)) $ips['v4'][] = $ip;
|
|
} elseif (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
|
|
if (!in_array($ip, $ips['v6'], true)) $ips['v6'][] = $ip;
|
|
}
|
|
}
|
|
|
|
function ppParseDohAnswers($json) {
|
|
$ips = array('v4' => array(), 'v6' => array());
|
|
$data = json_decode($json, true);
|
|
if (!is_array($data) || empty($data['Answer']) || !is_array($data['Answer'])) return $ips;
|
|
foreach ($data['Answer'] as $ans) {
|
|
if (empty($ans['data'])) continue;
|
|
$type = isset($ans['type']) ? intval($ans['type']) : 0;
|
|
if ($type === 1 || $type === 28) ppAddResolvedIp($ips, $ans['data']);
|
|
}
|
|
return $ips;
|
|
}
|
|
|
|
function ppMergeIps($into, $from) {
|
|
if (!is_array($from)) return $into;
|
|
foreach (array('v4', 'v6') as $k) {
|
|
if (empty($from[$k]) || !is_array($from[$k])) continue;
|
|
foreach ($from[$k] as $ip) ppAddResolvedIp($into, $ip);
|
|
}
|
|
return $into;
|
|
}
|
|
|
|
function ppCurlGetByIp($url, $headers = array(), $verifyTls = true) {
|
|
if (!function_exists('curl_init')) return false;
|
|
$ch = curl_init($url);
|
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
|
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 4);
|
|
curl_setopt($ch, CURLOPT_TIMEOUT, 6);
|
|
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
|
|
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
|
|
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verifyTls ? 1 : 0);
|
|
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $verifyTls ? 2 : 0);
|
|
$cacert = ppCacertPath();
|
|
if ($cacert) curl_setopt($ch, CURLOPT_CAINFO, $cacert);
|
|
$res = curl_exec($ch);
|
|
curl_close($ch);
|
|
return is_string($res) ? $res : false;
|
|
}
|
|
|
|
// Resolve PayPal hostnames without depending on the web server's DNS.
|
|
// Shared hosts often have a broken resolver (curl error: Could not resolve host)
|
|
// even though outbound HTTPS to public IPs still works.
|
|
function ppResolveHostIps($host) {
|
|
static $cache = array();
|
|
if (isset($cache[$host])) return $cache[$host];
|
|
|
|
$ips = array('v4' => array(), 'v6' => array());
|
|
|
|
// Bypass the local resolver first. This host already fails to resolve
|
|
// ipnpb.paypal.com / www.paypal.com through PHP cURL's DNS.
|
|
foreach (array('1.1.1.1', '8.8.8.8') as $ns) {
|
|
$ips = ppMergeIps($ips, ppDnsUdpA($host, $ns));
|
|
if (!empty($ips['v4'])) break;
|
|
}
|
|
|
|
if (empty($ips['v4']) && empty($ips['v6'])) {
|
|
$dohUrls = array(
|
|
'https://1.1.1.1/dns-query?name=' . rawurlencode($host) . '&type=A',
|
|
'https://8.8.8.8/resolve?name=' . rawurlencode($host) . '&type=A',
|
|
);
|
|
$dohHeaders = array('Accept: application/dns-json');
|
|
foreach (array(true, false) as $verifyTls) {
|
|
foreach ($dohUrls as $dohUrl) {
|
|
$json = ppCurlGetByIp($dohUrl, $dohHeaders, $verifyTls);
|
|
if ($json) $ips = ppMergeIps($ips, ppParseDohAnswers($json));
|
|
if (!empty($ips['v4']) || !empty($ips['v6'])) break 2;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (empty($ips['v4']) && empty($ips['v6'])) {
|
|
if (function_exists('dns_get_record')) {
|
|
foreach (array(DNS_A, DNS_AAAA) as $type) {
|
|
$recs = @dns_get_record($host, $type);
|
|
if (!is_array($recs)) continue;
|
|
foreach ($recs as $rec) {
|
|
if (!empty($rec['ip'])) ppAddResolvedIp($ips, $rec['ip']);
|
|
if (!empty($rec['ipv6'])) ppAddResolvedIp($ips, $rec['ipv6']);
|
|
}
|
|
}
|
|
}
|
|
$byName = @gethostbyname($host);
|
|
if (is_string($byName) && $byName !== $host) ppAddResolvedIp($ips, $byName);
|
|
}
|
|
|
|
$cache[$host] = $ips;
|
|
return $ips;
|
|
}
|
|
|
|
function ppDnsSkipName($resp, $offset) {
|
|
$len = strlen($resp);
|
|
$jumps = 0;
|
|
while ($offset < $len && $jumps < 10) {
|
|
$lab = ord($resp[$offset]);
|
|
if ($lab === 0) return $offset + 1;
|
|
if (($lab & 0xC0) === 0xC0) return $offset + 2;
|
|
$offset += $lab + 1;
|
|
$jumps++;
|
|
}
|
|
return $offset;
|
|
}
|
|
|
|
function ppDnsUdpA($host, $server, $timeout = 2) {
|
|
$ips = array('v4' => array(), 'v6' => array());
|
|
if (!function_exists('fsockopen')) return $ips;
|
|
$id = function_exists('random_int') ? random_int(0, 65535) : mt_rand(0, 65535);
|
|
$qname = '';
|
|
foreach (explode('.', $host) as $label) {
|
|
$qname .= chr(strlen($label)) . $label;
|
|
}
|
|
$query = pack('n', $id) . "\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00" . $qname . "\x00" . pack('nn', 1, 1);
|
|
$errno = 0;
|
|
$errstr = '';
|
|
$fp = @fsockopen('udp://' . $server, 53, $errno, $errstr, $timeout);
|
|
if (!$fp) return $ips;
|
|
stream_set_timeout($fp, $timeout);
|
|
fwrite($fp, $query);
|
|
$resp = fread($fp, 512);
|
|
fclose($fp);
|
|
if (!is_string($resp) || strlen($resp) < 12) return $ips;
|
|
$header = unpack('nid/nflags/nqdcount/nancount/nnscount/narcount', substr($resp, 0, 12));
|
|
if (!$header || $header['id'] !== $id || $header['ancount'] < 1) return $ips;
|
|
$offset = ppDnsSkipName($resp, 12) + 4;
|
|
for ($i = 0; $i < $header['ancount'] && $offset + 10 <= strlen($resp); $i++) {
|
|
$offset = ppDnsSkipName($resp, $offset);
|
|
if ($offset + 10 > strlen($resp)) break;
|
|
$rr = unpack('ntype/nclass/Nttl/nrdlength', substr($resp, $offset, 10));
|
|
$offset += 10;
|
|
if (!$rr) break;
|
|
$rdlen = $rr['rdlength'];
|
|
if ($offset + $rdlen > strlen($resp)) break;
|
|
if ($rr['type'] === 1 && $rdlen === 4) {
|
|
ppAddResolvedIp($ips, implode('.', unpack('C4', substr($resp, $offset, 4))));
|
|
}
|
|
$offset += $rdlen;
|
|
}
|
|
return $ips;
|
|
}
|
|
|
|
function ppApplyIpnCurlOpts($ch, $req) {
|
|
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
|
|
curl_setopt($ch, CURLOPT_POST, 1);
|
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
|
curl_setopt($ch, CURLOPT_POSTFIELDS, $req);
|
|
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
|
|
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
|
|
if (defined('CURL_SSLVERSION_TLSv1_2')) {
|
|
curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
|
|
} else {
|
|
curl_setopt($ch, CURLOPT_SSLVERSION, 6);
|
|
}
|
|
curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);
|
|
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 8);
|
|
curl_setopt($ch, CURLOPT_TIMEOUT, 20);
|
|
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
|
|
'User-Agent: PHP-IPN-VerificationScript',
|
|
'Connection: Close',
|
|
));
|
|
$cacert = ppCacertPath();
|
|
if ($cacert) curl_setopt($ch, CURLOPT_CAINFO, $cacert);
|
|
}
|
|
|
|
function ppIpnCurlPost($url, $req, $resolveRules = array(), $dnsServers = '', $ipresolve = 0) {
|
|
$ch = curl_init($url);
|
|
ppApplyIpnCurlOpts($ch, $req);
|
|
if ($resolveRules) curl_setopt($ch, CURLOPT_RESOLVE, $resolveRules);
|
|
if ($dnsServers !== '' && defined('CURLOPT_DNS_SERVERS')) {
|
|
@curl_setopt($ch, CURLOPT_DNS_SERVERS, $dnsServers);
|
|
}
|
|
if ($ipresolve && defined('CURL_IPRESOLVE_V4')) {
|
|
curl_setopt($ch, CURLOPT_IPRESOLVE, $ipresolve);
|
|
}
|
|
$res = curl_exec($ch);
|
|
$info = array(
|
|
'body' => $res,
|
|
'http' => curl_getinfo($ch, CURLINFO_HTTP_CODE),
|
|
'error' => ($res === false) ? curl_error($ch) : '',
|
|
'primary_ip' => curl_getinfo($ch, CURLINFO_PRIMARY_IP),
|
|
);
|
|
curl_close($ch);
|
|
return $info;
|
|
}
|
|
|
|
function ppIpnStreamPost($host, $req, $ip) {
|
|
$remote = filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) ? '[' . $ip . ']' : $ip;
|
|
$ssl = array(
|
|
'verify_peer' => true,
|
|
'verify_peer_name' => true,
|
|
'peer_name' => $host,
|
|
'SNI_enabled' => true,
|
|
);
|
|
$cacert = ppCacertPath();
|
|
if ($cacert) $ssl['cafile'] = $cacert;
|
|
$errno = 0;
|
|
$errstr = '';
|
|
$fp = @stream_socket_client(
|
|
'ssl://' . $remote . ':443',
|
|
$errno,
|
|
$errstr,
|
|
20,
|
|
STREAM_CLIENT_CONNECT,
|
|
stream_context_create(array('ssl' => $ssl))
|
|
);
|
|
if (!$fp) {
|
|
return array('body' => false, 'http' => 0, 'error' => "stream $ip: $errno $errstr", 'primary_ip' => $ip);
|
|
}
|
|
$out = "POST /cgi-bin/webscr HTTP/1.1\r\n"
|
|
. "Host: {$host}\r\n"
|
|
. "User-Agent: PHP-IPN-VerificationScript\r\n"
|
|
. "Content-Type: application/x-www-form-urlencoded\r\n"
|
|
. "Content-Length: " . strlen($req) . "\r\n"
|
|
. "Connection: close\r\n\r\n"
|
|
. $req;
|
|
fwrite($fp, $out);
|
|
stream_set_timeout($fp, 20);
|
|
$resp = '';
|
|
while (!feof($fp)) {
|
|
$chunk = fread($fp, 8192);
|
|
if ($chunk === false || $chunk === '') break;
|
|
$resp .= $chunk;
|
|
}
|
|
fclose($fp);
|
|
$headerEnd = strpos($resp, "\r\n\r\n");
|
|
$headers = $headerEnd === false ? $resp : substr($resp, 0, $headerEnd);
|
|
$body = $headerEnd === false ? '' : substr($resp, $headerEnd + 4);
|
|
$http = 0;
|
|
if (preg_match('/HTTP\/\d\.\d\s+(\d+)/', $headers, $m)) $http = intval($m[1]);
|
|
return array('body' => $body, 'http' => $http, 'error' => '', 'primary_ip' => $ip);
|
|
}
|
|
|
|
function ppIpnStatusFromBody($res) {
|
|
if (!is_string($res)) return '';
|
|
$body = trim($res);
|
|
if ($body === 'VERIFIED' || $body === 'INVALID') return $body;
|
|
if (preg_match('/^(VERIFIED|INVALID)\s*$/m', $body, $m)) return $m[1];
|
|
return '';
|
|
}
|
|
|
|
function ppFormatIpnAttempt($url, $info, $via) {
|
|
return $url
|
|
. " via=" . $via
|
|
. " ip=" . (isset($info['primary_ip']) ? $info['primary_ip'] : '')
|
|
. " http_code=" . $info['http']
|
|
. " curl_error='" . $info['error'] . "'"
|
|
. " response=" . var_export($info['body'], true);
|
|
}
|
|
|
|
// POST the IPN back to PayPal per
|
|
// https://developer.paypal.com/api/nvp-soap/ipn/IPNImplementation/
|
|
// Live: https://ipnpb.paypal.com/cgi-bin/webscr
|
|
// Sandbox: https://ipnpb.sandbox.paypal.com/cgi-bin/webscr
|
|
// www.paypal.com/cgi-bin/webscr remains a documented legacy fallback.
|
|
function ppVerifyIpnWithPaypal($req) {
|
|
$useSandbox = !empty($_POST['test_ipn']);
|
|
$endpoints = $useSandbox
|
|
? array(
|
|
'https://ipnpb.sandbox.paypal.com/cgi-bin/webscr',
|
|
'https://www.sandbox.paypal.com/cgi-bin/webscr',
|
|
)
|
|
: array(
|
|
'https://ipnpb.paypal.com/cgi-bin/webscr',
|
|
'https://www.paypal.com/cgi-bin/webscr',
|
|
);
|
|
|
|
$attempts = array();
|
|
foreach ($endpoints as $url) {
|
|
$host = parse_url($url, PHP_URL_HOST);
|
|
$ips = ppResolveHostIps($host);
|
|
$resolveRules = array();
|
|
$addrList = array();
|
|
foreach ($ips['v4'] as $ip) $addrList[] = $ip;
|
|
foreach ($ips['v6'] as $ip) $addrList[] = '[' . $ip . ']';
|
|
if ($addrList) $resolveRules[] = $host . ':443:' . implode(',', $addrList);
|
|
$attempts[] = $host . " resolved=" . ($addrList ? implode(',', $addrList) : '(none)');
|
|
|
|
$variants = array();
|
|
if ($resolveRules) {
|
|
$variants[] = array('rules' => $resolveRules, 'dns' => '', 'ipresolve' => 0, 'via' => 'curl+resolve');
|
|
} else {
|
|
$variants[] = array('rules' => array(), 'dns' => '', 'ipresolve' => 0, 'via' => 'curl');
|
|
$variants[] = array('rules' => array(), 'dns' => '1.1.1.1,8.8.8.8', 'ipresolve' => 0, 'via' => 'curl+dnsservers');
|
|
}
|
|
|
|
foreach ($variants as $variant) {
|
|
$info = ppIpnCurlPost($url, $req, $variant['rules'], $variant['dns'], $variant['ipresolve']);
|
|
$attempts[] = ppFormatIpnAttempt($url, $info, $variant['via']);
|
|
$status = ppIpnStatusFromBody($info['body']);
|
|
if ($status === 'VERIFIED' || $status === 'INVALID') {
|
|
return array('status' => $status, 'url' => $url, 'attempts' => $attempts);
|
|
}
|
|
}
|
|
|
|
$streamIps = array_slice(array_merge($ips['v4'], $ips['v6']), 0, 2);
|
|
foreach ($streamIps as $ip) {
|
|
$info = ppIpnStreamPost($host, $req, $ip);
|
|
$attempts[] = ppFormatIpnAttempt($url, $info, 'stream');
|
|
$status = ppIpnStatusFromBody($info['body']);
|
|
if ($status === 'VERIFIED' || $status === 'INVALID') {
|
|
return array('status' => $status, 'url' => $url, 'attempts' => $attempts);
|
|
}
|
|
}
|
|
}
|
|
|
|
return array('status' => 'ERROR', 'url' => '', 'attempts' => $attempts);
|
|
}
|
|
|
|
// Callback name must be a string. A bare constant was tolerated by older
|
|
// PHP (it fell back to the bareword as a string) but is a fatal Error in PHP 8.
|
|
ob_start('saveOutput');
|
|
|
|
date_default_timezone_set("Canada/Pacific");
|
|
|
|
// output date and POST-ed values
|
|
echo(date('r') . "\n\n");
|
|
$x = $_POST;
|
|
if (isset($x['callbackPW'])) unset($x['callbackPW']);
|
|
print_r($x);
|
|
echo("\n\n");
|
|
|
|
// Exit if there is no TRXnum
|
|
if (!array_key_exists('custom',$_POST) || !is_numeric($_POST['custom']) || $_POST['custom'] == 0) {
|
|
exit();
|
|
}
|
|
|
|
// ***************
|
|
// post back to PayPal system to validate
|
|
// ***************
|
|
/* $req = 'cmd=_notify-validate';
|
|
foreach ($_POST as $key => $value) {
|
|
$value = urlencode(stripslashes($value));
|
|
$req .= "&$key=$value";
|
|
}
|
|
$header .= "POST /cgi-bin/webscr HTTP/1.1\r\n";
|
|
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
|
|
$header .= "Content-Length: " . strlen($req) . "\r\n";
|
|
$header .= "Host: www.paypal.com\r\n";
|
|
$header .= "Connection: close\r\n";
|
|
$header .= "\r\n";*/
|
|
|
|
// connect to the server
|
|
/*if (array_key_exists('test_ipn',$_POST)) $server = "www.sandbox.paypal.com"; else $server = "www.paypal.com";
|
|
$fp = fsockopen($server, 80, $errno, $errstr, 30);
|
|
$unexpectedErrors = 0;
|
|
if ($fp === false) {
|
|
$errorMessage = "ERROR: Error connecting to PayPal server to validate IPN: $errno - $errstr";
|
|
echo("$errorMessage\n");
|
|
$unexpectedErrors = 1;
|
|
} else {
|
|
|
|
// post the data
|
|
fputs ($fp, $header . $req);
|
|
while (!feof($fp)) {
|
|
|
|
// get the return status
|
|
$res = trim(fgets($fp, 1024));
|
|
if ($res === "VERIFIED") {
|
|
echo("VERIFIED");
|
|
} elseif ($res === "INVALID") {
|
|
$errorMessage = "ERROR: The PayPal server could not validate the IPN";
|
|
echo("$errorMessage\n");
|
|
$unexpectedErrors = 1;
|
|
}
|
|
}
|
|
fclose ($fp);
|
|
}*/
|
|
echo("\n\n");
|
|
|
|
################## Start Post Back to PayPal #####################################
|
|
$unexpectedErrors = 0;
|
|
$raw_post_data = file_get_contents('php://input');
|
|
$myPost = array();
|
|
if (is_string($raw_post_data) && strlen($raw_post_data) > 0) {
|
|
$raw_post_array = explode('&', $raw_post_data);
|
|
foreach ($raw_post_array as $keyval)
|
|
{
|
|
$keyval = explode ('=', $keyval);
|
|
if (count($keyval) == 2) {
|
|
// Official PayPal sample: keep the timezone '+' in payment_date.
|
|
if ($keyval[0] === 'payment_date' && substr_count($keyval[1], '+') === 1) {
|
|
$keyval[1] = str_replace('+', '%2B', $keyval[1]);
|
|
}
|
|
$myPost[$keyval[0]] = urldecode($keyval[1]);
|
|
}
|
|
}
|
|
}
|
|
if (count($myPost) == 0 && is_array($_POST)) {
|
|
$myPost = $_POST;
|
|
}
|
|
|
|
// read the IPN message sent from PayPal and prepend 'cmd=_notify-validate'
|
|
$req = 'cmd=_notify-validate';
|
|
// get_magic_quotes_gpc() was removed in PHP 8, so this is always false there.
|
|
$get_magic_quotes_exists = function_exists('get_magic_quotes_gpc');
|
|
foreach ($myPost as $key => $value) {
|
|
if ($get_magic_quotes_exists && get_magic_quotes_gpc() == 1) {
|
|
$value = urlencode(stripslashes($value));
|
|
} else {
|
|
$value = urlencode($value);
|
|
}
|
|
$req .= "&$key=$value";
|
|
}
|
|
|
|
$verify = ppVerifyIpnWithPaypal($req);
|
|
echo("IPN verify attempts:\n" . implode("\n", $verify['attempts']) . "\n");
|
|
if ($verify['url']) echo("IPN " . $verify['status'] . " via " . $verify['url'] . "\n");
|
|
|
|
// Fail CLOSED: anything that is not an explicit "VERIFIED" must be treated
|
|
// as unverified. A curl failure (network/TLS/timeout) previously fell
|
|
// through both branches and the payment was credited as if PayPal had
|
|
// confirmed it, which would credit an account for money never received.
|
|
if ($verify['status'] === 'VERIFIED')
|
|
{
|
|
echo("VERIFIED\n");
|
|
}
|
|
elseif ($verify['status'] === 'INVALID')
|
|
{
|
|
// IPN invalid, log for manual investigation
|
|
$errorMessage = "ERROR: The PayPal server could not validate the IPN. The response from IPN was: INVALID";
|
|
echo("$errorMessage\n");
|
|
$unexpectedErrors = 1;
|
|
}
|
|
else
|
|
{
|
|
// curl failed, timed out, or returned an unexpected body.
|
|
// Do not insert a blocking transaction row: PayPal must be able to retry.
|
|
$errorMessage = "ERROR: Unable to verify IPN with PayPal. " . implode(" | ", $verify['attempts']);
|
|
echo("$errorMessage\n");
|
|
error_log("ppPayment: $errorMessage");
|
|
http_response_code(503);
|
|
exit();
|
|
}
|
|
|
|
################## End Post Back to PayPal #####################################
|
|
|
|
|
|
// Use the posted transaction number value to determine the school_num
|
|
$TRXnum = $_POST['custom'];
|
|
$query = "SELECT school_num FROM user_online_payments WHERE record_num = {$TRXnum} ORDER BY record_num DESC LIMIT 0,1";
|
|
$school_num = intval(pp_getVal($query));
|
|
if (!$school_num) {
|
|
$business = $_POST['business'];
|
|
$school_num = pp_getVal("SELECT record_num FROM schools WHERE paypal_code = '$business' LIMIT 0,1");
|
|
if (!$school_num) {
|
|
$business = $_POST['receiver_email'];
|
|
$school_num = pp_getVal("SELECT record_num FROM schools WHERE paypal_code = '$business' LIMIT 0,1");
|
|
if (!$school_num) $school_num = 0;
|
|
}
|
|
}
|
|
|
|
$curr_school_num = $school_num;
|
|
|
|
|
|
// Check if this entry is in the user_paypal_transactions table
|
|
$payment_type = '';
|
|
$payment_status = '';
|
|
if (array_key_exists('payment_type', $_POST)) $payment_type = $_POST['payment_type'];
|
|
if (array_key_exists('payment_status', $_POST)) $payment_status = $_POST['payment_status'];
|
|
$txn_id = $_POST['txn_id'];
|
|
$query = "SELECT * FROM user_paypal_transactions WHERE school_num = $school_num AND payment_type = '$payment_type' AND payment_status = '$payment_status' AND txn_id = '$txn_id' AND current_year != 'N'";
|
|
$r = pp_query($query);
|
|
$trxID = 0;
|
|
if (db_num_rows($r) > 0) {
|
|
$existing = db_fetch_assoc($r);
|
|
$existingResult = isset($existing['posting_result']) ? trim($existing['posting_result']) : '';
|
|
// Only skip IPNs that were already credited or fully handled. A previous
|
|
// verify/network Error must remain retryable or the payment stays stuck.
|
|
$alreadyHandled = in_array($existingResult, array('Posted', 'Reversed', 'Canceled Reversal', 'Pending'), true);
|
|
if ($alreadyHandled) {
|
|
$errorMessage = "Duplicate Posting - Transaction Has Already Been Processed: $txn_id";
|
|
echo("$errorMessage\n");
|
|
exit();
|
|
}
|
|
$trxID = intval($existing['record_num']);
|
|
echo("Reprocessing previous IPN attempt record_num=$trxID posting_result='$existingResult'\n");
|
|
}
|
|
|
|
if (!$trxID) {
|
|
// Create entry in user_paypal_transactions table
|
|
$trxFields = array('transaction_subject','payment_date','txn_type','first_name','last_name','payer_email','payer_status','item_name',
|
|
'business','receiver_email','mc_currency','mc_gross','mc_fee','reference','payment_type','payment_status',
|
|
'pending_reason','txn_id','receipt_id','current_year');
|
|
$trxInsert = "school_num,posting_time,ptime,error_handled";
|
|
$trxValues = "$school_num,'$time',$ptime,'N'";
|
|
$current_year = 'Y';
|
|
for ($i = 0; $i < count($trxFields); $i++) {
|
|
$fieldName = $trxFields[$i];
|
|
// Not every IPN carries every field (eg. reference, pending_reason,
|
|
// receipt_id), so default to '' rather than emitting undefined-key
|
|
// warnings and passing null into db_escape_string().
|
|
$fieldValue = '';
|
|
if (isset($$fieldName)) $fieldValue = $$fieldName;
|
|
if (array_key_exists($fieldName, $_POST)) $fieldValue = db_escape_string(isset($_POST[$fieldName]) ? $_POST[$fieldName] : '');
|
|
$trxInsert .= ",$fieldName";
|
|
$trxValues .= ",'$fieldValue'";
|
|
}
|
|
$trxSQL = "INSERT INTO user_paypal_transactions ($trxInsert) VALUES ($trxValues)";
|
|
// pp_query("START TRANSACTION");
|
|
pp_query($trxSQL);
|
|
$trxID = db_insert_id();
|
|
echo("Insert ID: $trxID\n");
|
|
}
|
|
|
|
|
|
extract($_POST,EXTR_PREFIX_ALL,'P');
|
|
$TRXnum = $P_custom;
|
|
|
|
if (isset($P_case_type) && $P_case_type == 'complaint') {
|
|
$errorMessage = "Non transaction Posting - Complaint Transaction: $txn_id";
|
|
echo("$errorMessage\n");
|
|
$query = "UPDATE user_paypal_transactions SET posting_result = 'Complaint', posting_message = '" . db_escape_string($errorMessage) . "' WHERE record_num = $trxID";
|
|
exit();
|
|
}
|
|
|
|
if (isset($P_case_type) && $P_case_type == 'dispute') {
|
|
$errorMessage = "Non transaction Posting - Dispute Transaction: $txn_id";
|
|
echo("$errorMessage\n");
|
|
$query = "UPDATE user_paypal_transactions SET posting_result = 'Dispute', posting_message = '" . db_escape_string($errorMessage) . "' WHERE record_num = $trxID";
|
|
exit();
|
|
}
|
|
|
|
if (isset($P_case_type) && $P_case_type == 'chargeback') {
|
|
$errorMessage = "Non transaction Posting - Chargeback Transaction: $txn_id";
|
|
echo("$errorMessage\n");
|
|
$query = "UPDATE user_paypal_transactions SET posting_result = 'Chargeback', posting_message = '" . db_escape_string($errorMessage) . "' WHERE record_num = $trxID";
|
|
exit();
|
|
}
|
|
|
|
|
|
|
|
// If we were unable to verify the transaction
|
|
if ($unexpectedErrors == 1) {
|
|
$query = "SELECT * FROM user_online_payments WHERE record_num = {$TRXnum} AND status = 'Pending'";
|
|
$r = pp_query($query);
|
|
if (db_num_rows($r) == 1) {
|
|
extract(db_fetch_assoc($r), EXTR_PREFIX_ALL, 'p');
|
|
if (isset($p_user_num)) {
|
|
pp_query("UPDATE user_paypal_transactions SET school_num = $p_school_num, user_num = $p_user_num, trx_num = $TRXnum WHERE record_num = $trxID");
|
|
}
|
|
}
|
|
|
|
// Update the log with the error message
|
|
$query = "UPDATE user_paypal_transactions SET posting_result = 'Error', posting_message = '" . db_escape_string($errorMessage) . "' WHERE record_num = $trxID";
|
|
pp_query($query);
|
|
exit();
|
|
}
|
|
|
|
|
|
// Load user information from the database
|
|
$query = "SELECT * FROM user_online_payments WHERE record_num = {$TRXnum}";
|
|
$r = pp_query($query);
|
|
if (db_num_rows($r) != 1) {
|
|
$errorMessage = "Invalid transaction number or status: $TRXnum";
|
|
echo("$errorMessage\n");
|
|
pp_query("UPDATE user_paypal_transactions SET posting_result = 'Error', posting_message = '" . db_escape_string($errorMessage) . "' WHERE record_num = $trxID");
|
|
} else {
|
|
extract(db_fetch_assoc($r), EXTR_PREFIX_ALL, 'p');
|
|
}
|
|
|
|
|
|
// Load school information from the database
|
|
if (!isset($p_school_num) || intval($p_school_num) == 0) $p_school_num = $school_num;
|
|
$r = pp_query("SELECT * FROM schools WHERE record_num = {$p_school_num}");
|
|
if (db_num_rows($r) != 1) {
|
|
echo("Invalid school.\n");
|
|
pp_query("UPDATE user_paypal_transactions SET posting_result = 'Error', posting_message = 'Invalid school' WHERE record_num = $trxID");
|
|
exit();
|
|
} else {
|
|
extract(db_fetch_assoc($r), EXTR_PREFIX_ALL, 's');
|
|
}
|
|
|
|
|
|
// Update user_paypal_transactions with school and user info
|
|
pp_query("UPDATE user_paypal_transactions SET school_num = {$p_school_num}, user_num = {$p_user_num}, trx_num = $TRXnum WHERE record_num = $trxID");
|
|
|
|
|
|
// Check for test/sandbox payments
|
|
if (isset($P_test_ipn) && $P_test_ipn==1 && $s_paypal_mode == 'Live') {
|
|
echo("Unexpected sandbox payment - we are not in testing mode.\n");
|
|
pp_query("UPDATE user_paypal_transactions SET posting_result = 'Error', posting_message = 'Unexpected sandbox payment - we are not in testing mode' WHERE record_num = $trxID");
|
|
exit();
|
|
}
|
|
|
|
// Check that the payment was made in Canadian funds
|
|
if (!$P_mc_currency || $P_mc_currency != $s_paypal_currency) {
|
|
echo("Unexpected currency - payment should be made in $s_paypal_currency\n");
|
|
pp_query("UPDATE user_paypal_transactions SET posting_result = 'Error', posting_message = 'Unexpected currency' WHERE record_num = $trxID");
|
|
// Stop here: crediting a different currency at face value would post the
|
|
// wrong amount to the user's account.
|
|
error_log("ppPayment: currency mismatch $P_mc_currency => $s_paypal_currency (trx $TRXnum)");
|
|
exit();
|
|
}
|
|
|
|
|
|
//
|
|
// Process Reversed payments
|
|
//
|
|
if ($P_payment_status == 'Reversed') {
|
|
pp_query("UPDATE user_paypal_transactions SET posting_result = 'Reversed', posting_message = 'Payment reversed' WHERE record_num = $trxID");
|
|
$results = pp_query("SELECT * FROM user_account WHERE payment_reference = '$P_parent_txn_id'");
|
|
$row = db_fetch_assoc($results);
|
|
$order_payments = $row['order_payments'];
|
|
$orders = explode("|",$order_payments);
|
|
|
|
// Flag each order
|
|
for ($i = 0; $i < count($orders); $i++) {
|
|
if (array_key_exists($i, $orders)) {
|
|
list($onum,$amt) = explode(":",preg_replace("/{(.*)}/","$1",$orders[$i]));
|
|
|
|
if (intval($onum) > 0) {
|
|
$query = "UPDATE hotlunch_order_header " .
|
|
"SET status = 'Unpaid', " .
|
|
"payment_method = '', " .
|
|
"paid_date = NULL, " .
|
|
"amount_paid = 0 " .
|
|
"WHERE record_num = {$onum}";
|
|
pp_query($query);
|
|
}
|
|
|
|
// logOrderChange($onum,"PAYMENT REVERSED","ppPayment.php");
|
|
}
|
|
}
|
|
|
|
// Check if there is a user_account entry already
|
|
$query = "SELECT * FROM user_account WHERE school_num = $p_school_num AND user_num = $p_user_num AND payment_reference = '$P_txn_id'";
|
|
$ua_entries = pp_query($query);
|
|
if (db_num_rows($ua_entries) > 0) {
|
|
echo("Duplicate: This transaction has been entered into user_account already: $P_txn_id\n");
|
|
exit();
|
|
}
|
|
|
|
// Post transaction to the user_account
|
|
date_default_timezone_set(mapTimeZone($s_timezone));
|
|
$entered_time = $ptime;
|
|
$trx_time = date("Y-m-d H:i:s",$entered_time);
|
|
|
|
$amount = $P_mc_gross * -1;
|
|
$query = "INSERT INTO user_account " .
|
|
"(school_num,user_num,schedule_num,transaction_datetime,transaction_type,note,transaction_amount,transaction_fee,payment_method,payment_reference,order_payments,deleted,entered_time,transaction_status) " .
|
|
"VALUES ($p_school_num,$p_user_num,0,'$trx_time','Reversed Payment','PayPal Reversed Payment',$amount,$P_mc_fee,'PayPal','$P_txn_id','$order_payments','N',$entered_time,'Closed')";
|
|
pp_query($query);
|
|
|
|
exit();
|
|
}
|
|
|
|
//
|
|
// Process Cancelled Reversed payments
|
|
//
|
|
if ($P_payment_status == 'Canceled_Reversal') {
|
|
pp_query("UPDATE user_paypal_transactions SET posting_result = 'Canceled Reversal', posting_message = 'PayPal Canceled Reversal' WHERE record_num = $trxID");
|
|
$results = pp_query("SELECT * FROM user_account WHERE payment_reference = '$P_parent_txn_id'");
|
|
$row = db_fetch_assoc($results);
|
|
$order_payments = $row['order_payments'];
|
|
$orders = explode("|",$order_payments);
|
|
|
|
// Flag each order
|
|
for ($i = 0; $i < count($orders); $i++) {
|
|
list($onum,$amt) = explode(":",preg_replace("/{(.*)}/","$1",$orders[$i]));
|
|
|
|
if (intval($onum) > 0) {
|
|
$query = "UPDATE hotlunch_order_header " .
|
|
"SET status = 'Paid', " .
|
|
"payment_method = 'PayPal', " .
|
|
"amount_paid = order_total " .
|
|
"WHERE record_num = {$onum}";
|
|
pp_query($query);
|
|
}
|
|
|
|
// logOrderChange($onum,"PAYMENT REVERSAL CANCELLED","ppPayment.php");
|
|
}
|
|
|
|
// Check if there is a user_account entry already
|
|
$query = "SELECT * FROM user_account WHERE school_num = $p_school_num AND user_num = $p_user_num AND payment_reference = '$P_txn_id'";
|
|
$ua_entries = pp_query($query);
|
|
if (db_num_rows($ua_entries) > 0) {
|
|
echo("Duplicate: This transaction has been entered into user_account already: $P_txn_id\n");
|
|
exit();
|
|
}
|
|
|
|
// Post transaction to the user_account
|
|
date_default_timezone_set(mapTimeZone($s_timezone));
|
|
$entered_time = $ptime;
|
|
$trx_time = date("Y-m-d H:i:s",$entered_time);
|
|
|
|
$amount = $P_mc_gross;
|
|
$query = "INSERT INTO user_account " .
|
|
"(school_num,user_num,schedule_num,transaction_datetime,transaction_type,note,transaction_amount,transaction_fee,payment_method,payment_reference,order_payments,deleted,entered_time,transaction_status) " .
|
|
"VALUES ($p_school_num,$p_user_num,0,'$trx_time','Cancelled Reversed Payment','PayPal Cancelled Reversed Payment',$amount,$P_mc_fee,'PayPal','$P_txn_id','$order_payments','N',$entered_time,'Closed')";
|
|
pp_query($query);
|
|
|
|
exit();
|
|
}
|
|
|
|
|
|
// Check the payment was sent to the correct account
|
|
if (strtolower(trim($P_receiver_email)) != strtolower(trim($s_paypal_code)) && strtolower(trim($P_business)) != strtolower(trim($s_paypal_code))) {
|
|
echo("Payment was sent to an unexpected account - $s_paypal_code.\n");
|
|
echo("$P_receiver_email => $s_paypal_code\n");
|
|
pp_query("UPDATE user_paypal_transactions SET posting_result = 'Error', posting_message = 'Payment was sent to an unexpected account' WHERE record_num = $trxID");
|
|
// Stop here: the money did not land in this school's account, so crediting
|
|
// the user would post funds that were never received.
|
|
error_log("ppPayment: receiver mismatch $P_receiver_email => $s_paypal_code (trx $TRXnum)");
|
|
exit();
|
|
}
|
|
|
|
// Update hotlunch_orders table
|
|
$query = "SELECT hloh.* FROM hotlunch_order_header as hloh, people as p " .
|
|
"WHERE hloh.school_num = {$p_school_num} " .
|
|
"AND ordered_by_num = p.record_num " .
|
|
"AND p.user_num = {$p_user_num} " .
|
|
"AND hloh.status NOT IN ('Paid','Complimentary','Concession')";
|
|
$orders = pp_query($query);
|
|
echo("Orders Found: " . db_num_rows($orders) . "\n\n");
|
|
|
|
// check for non-completed orders (ie. pending for some reason)
|
|
if ($P_payment_status != 'Completed') {
|
|
echo("Payment was not completed. $P_payment_status.\n");
|
|
|
|
if ($P_payment_status == 'Pending' && $P_payment_type == 'instant' && $P_pending_reason == 'paymentreview') {
|
|
echo(" - Pending - instant - paymentreview\n");
|
|
}
|
|
else {
|
|
|
|
// Process refunds
|
|
if ($P_payment_status == 'Refunded') {
|
|
// Post transaction to the user_account
|
|
date_default_timezone_set(mapTimeZone($s_timezone));
|
|
$entered_time = $ptime;
|
|
$trx_time = date("Y-m-d H:i:s",$entered_time);
|
|
// $snum = intval($snum);
|
|
|
|
$amount = $P_mc_gross * -1;
|
|
$query = "INSERT INTO user_account " .
|
|
"(school_num,user_num,schedule_num,transaction_datetime,transaction_type,note,transaction_amount,transaction_fee,payment_method,payment_reference,order_payments,deleted,entered_time) " .
|
|
"VALUES ($p_school_num,$p_user_num,0,'$trx_time','Refund','PayPal Refund',$amount,$P_mc_fee,'PayPal','$P_txn_id','','N',$entered_time)";
|
|
pp_query($query);
|
|
pp_query("UPDATE user_paypal_transactions SET posting_result = 'Posted', posting_message = 'Refund posted' WHERE record_num = $trxID");
|
|
echo("Refund Status: $P_payment_status\n");
|
|
exit();
|
|
}
|
|
|
|
// Process Pending transactions
|
|
if ($P_payment_status == 'Pending') {
|
|
pp_query("UPDATE user_paypal_transactions SET posting_result = 'Pending', posting_message = 'Payment not completed' WHERE record_num = $trxID");
|
|
|
|
// Flag each order
|
|
if (db_num_rows($orders) > 0) {
|
|
while ($row = db_fetch_array($orders)) {
|
|
$onum = $row['record_num'];
|
|
|
|
$query = "UPDATE hotlunch_order_header " .
|
|
"SET status = 'Pending' " .
|
|
"WHERE record_num = {$onum}";
|
|
pp_query($query);
|
|
|
|
// logOrderChange($onum,"PENDING PAYMENT","ppPayment.php");
|
|
}
|
|
}
|
|
|
|
// Update users record to indicate that there are pending transactions
|
|
$query = "update users set trx_status = 'Pending' where school_num = $p_school_num and record_num = $p_user_num";
|
|
pp_query($query);
|
|
echo("Pending Payment Status: $P_payment_status\n");
|
|
exit();
|
|
}
|
|
|
|
// Process Failed transactions
|
|
if ($P_payment_status == 'Failed') {
|
|
pp_query("UPDATE user_paypal_transactions SET posting_result = 'Error', posting_message = 'Payment failed' WHERE record_num = $trxID");
|
|
|
|
// Find Pending Orders and reset the status
|
|
$query = "SELECT hloh.* FROM hotlunch_order_header as hloh, people as p " .
|
|
"WHERE hloh.school_num = {$p_school_num} " .
|
|
"AND ordered_by_num = p.record_num " .
|
|
"AND p.user_num = {$p_user_num} " .
|
|
"AND hloh.status IN ('Pending')";
|
|
$orders = pp_query($query);
|
|
echo("Orders Found: " . db_num_rows($orders) . "\n\n");
|
|
|
|
// Flag each order
|
|
if (db_num_rows($orders) > 0) {
|
|
while ($row = db_fetch_array($orders)) {
|
|
$onum = $row['record_num'];
|
|
|
|
$query = "UPDATE hotlunch_order_header " .
|
|
"SET status = 'Unpaid' " .
|
|
"WHERE record_num = {$onum}";
|
|
pp_query($query);
|
|
|
|
// logOrderChange($onum,"PAYMENT FAILED","ppPayment.php");
|
|
}
|
|
}
|
|
|
|
// Update users record to clear the pending status
|
|
$query = "update users set trx_status = '' where school_num = $p_school_num and record_num = $p_user_num";
|
|
pp_query($query);
|
|
echo("Failed Payment Status: $P_payment_status\n");
|
|
exit();
|
|
}
|
|
|
|
$query = "UPDATE user_paypal_transactions SET posting_result = 'Error', posting_message = 'Payment not completed - $P_payment_status' WHERE record_num = $trxID";
|
|
pp_query($query);
|
|
echo("Incomplete Payment Status: $P_payment_status\n");
|
|
exit();
|
|
}
|
|
}
|
|
|
|
echo("Payment validated ok - updating database\n\n");
|
|
|
|
|
|
//
|
|
// Check if this transaction has been entered already
|
|
//
|
|
$query = "SELECT * FROM user_online_payments WHERE record_num = $TRXnum AND status = 'Paid'";
|
|
$paid_payments = pp_query($query);
|
|
if (db_num_rows($paid_payments) > 0) {
|
|
echo("Duplicate: This transaction has been posted to user_online_payments already: $TRXnum\n");
|
|
$row = db_fetch_assoc($paid_payments);
|
|
if ($row['reference'] == $P_txn_id) exit();
|
|
echo("New PayPal Reference ID: $P_txn_id\n\n");
|
|
}
|
|
|
|
|
|
// Update paypal_payments database table
|
|
$P_mc_fee = floatval($P_mc_fee);
|
|
$query = "UPDATE user_online_payments " .
|
|
"SET status = 'Paid', payment_amount = balance_owing, reference = '{$P_txn_id}', trx_fee = {$P_mc_fee}, completed_time = $ptime " .
|
|
"WHERE record_num = $TRXnum";
|
|
pp_query($query);
|
|
|
|
$today = date("Y-m-d",$ptime);
|
|
$order_payments = "";
|
|
$snum = 0;
|
|
if (db_num_rows($orders) > 0) {
|
|
while ($row = db_fetch_array($orders)) {
|
|
$onum = $row['record_num'];
|
|
$ototal = $row['order_total'];
|
|
$opaid = $row['amount_paid'];
|
|
$snum = $row['schedule_num'];
|
|
$amt = number_format($ototal - $opaid,2);
|
|
if (strlen($order_payments) > 0) $order_payments .= "|";
|
|
$order_payments .= "{" . $onum . ":" . $amt . "}";
|
|
|
|
$query = "UPDATE hotlunch_order_header " .
|
|
"SET amount_paid = order_total, " .
|
|
"status = 'Paid', " .
|
|
"paid_date = '$today', " .
|
|
"payment_method = 'PayPal' " .
|
|
"WHERE record_num = {$onum}";
|
|
pp_query($query);
|
|
|
|
// logOrderChange($onum,"PAYMENT COMPLETED","ppPayment.php");
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Check if there is a user_account entry already
|
|
//
|
|
$query = "SELECT * FROM user_account WHERE school_num = $p_school_num AND user_num = $p_user_num AND payment_reference = '$P_txn_id'";
|
|
$ua_entries = pp_query($query);
|
|
if (db_num_rows($ua_entries) > 0) {
|
|
echo("Duplicate: This transaction has been entered into user_account already: $P_txn_id\n");
|
|
exit();
|
|
}
|
|
|
|
|
|
// Post transaction to the user_account
|
|
date_default_timezone_set(mapTimeZone($s_timezone));
|
|
$entered_time = $ptime;
|
|
$trx_time = date("Y-m-d H:i:s",$entered_time);
|
|
|
|
// Post transaction fee if there is one
|
|
if ($p_transaction_fee != 0) {
|
|
if ($p_transaction_fee > 0) {
|
|
$query = "INSERT INTO user_account " .
|
|
"(school_num,user_num,schedule_num,transaction_datetime,transaction_type,transaction_status,note,transaction_amount,amount_paid,transaction_fee,payment_method,payment_reference,order_payments,deleted,entered_time) " .
|
|
"VALUES ($p_school_num,$p_user_num,$snum,'$trx_time','PayPal Transaction Fee','Closed','',$p_transaction_fee,$p_transaction_fee,0,'PayPal','$P_txn_id',NULL,'N',$entered_time)";
|
|
}
|
|
else {
|
|
$query = "INSERT INTO user_account " .
|
|
"(school_num,user_num,schedule_num,transaction_datetime,transaction_type,transaction_status,note,transaction_amount,amount_paid,transaction_fee,payment_method,payment_reference,order_payments,deleted,entered_time) " .
|
|
"VALUES ($p_school_num,$p_user_num,$snum,'$trx_time','PayPal Transaction Credit','Closed','',$p_transaction_fee,$p_transaction_fee,0,'PayPal','$P_txn_id',NULL,'N',$entered_time)";
|
|
}
|
|
pp_query($query);
|
|
$entered_time += 1;
|
|
$trx_time = date("Y-m-d H:i:s",$entered_time);
|
|
}
|
|
|
|
// Insert payment transaction
|
|
$amount = $P_mc_gross * -1;
|
|
$query = "INSERT INTO user_account " .
|
|
"(school_num,user_num,schedule_num,transaction_datetime,transaction_type,note,transaction_amount,transaction_fee,payment_method,payment_reference,order_payments,deleted,entered_time) " .
|
|
"VALUES ($p_school_num,$p_user_num,$snum,'$trx_time','Payment','PayPal Payment',$amount,$P_mc_fee,'PayPal','$P_txn_id','$order_payments','N',$entered_time)";
|
|
pp_query($query);
|
|
|
|
// Update any open charge transactions
|
|
$query = "SELECT * FROM user_account " .
|
|
"WHERE school_num = $school_num AND user_num = $p_user_num AND transaction_status = 'Open' AND transaction_amount > 0";
|
|
$results = pp_query($query);
|
|
while ($row = db_fetch_assoc($results)) {
|
|
$rnum = $row['record_num'];
|
|
$query = "UPDATE user_account SET payment_method = 'PayPal', payment_reference = '$P_txn_id', payment_time = $entered_time " .
|
|
"WHERE school_num = $school_num AND record_num = $rnum";
|
|
pp_query($query);
|
|
}
|
|
|
|
// Close all transactions
|
|
$query = "SELECT record_num FROM user_account WHERE school_num = $school_num AND user_num = $p_user_num AND transaction_status != 'Closed'";
|
|
$results = pp_query($query);
|
|
while ($row = db_fetch_assoc($results)) {
|
|
$rnum = $row['record_num'];
|
|
$query = "UPDATE user_account SET transaction_status = 'Closed' WHERE school_num = $school_num AND user_num = $p_user_num AND record_num = $rnum";
|
|
pp_query($query);
|
|
}
|
|
|
|
// Update all orders to set amount paid
|
|
$query = "SELECT * FROM user_account WHERE school_num = $school_num AND user_num = $p_user_num AND transaction_amount > 0";
|
|
$results = pp_query($query);
|
|
while ($row = db_fetch_assoc($results)) {
|
|
$rnum = $row['record_num'];
|
|
$query = "UPDATE user_account SET amount_paid = transaction_amount WHERE school_num = $school_num AND record_num = $rnum";
|
|
pp_query($query);
|
|
}
|
|
|
|
|
|
// Make activity_log entry
|
|
$username = pp_getVal("SELECT userid FROM users WHERE school_num = $p_school_num AND record_num = $p_user_num");
|
|
$activity = "PayPal Payment";
|
|
$additional_info = "TRX ID: $P_txn_id\nAmount: " . number_format(abs($amount),2) . "\n";
|
|
$curr_time = $ptime;
|
|
$activity_datetime = date("Y-m-d H:i:s",$curr_time);
|
|
$uname = db_escape_string($username);
|
|
$query = "insert into activity_log (school_num,userid,user_ip,activity_time,activity_datetime,activity,information) " .
|
|
"values($p_school_num,'$uname','0.0.0.0',$curr_time,'$activity_datetime','$activity','$additional_info')";
|
|
pp_query($query);
|
|
|
|
// Reset user transaction status
|
|
$query = "update users set trx_status = NULL where school_num = $p_school_num and record_num = $p_user_num";
|
|
pp_query($query);
|
|
|
|
// Reset user can_order flag
|
|
$query = "update users set can_order = 'Yes' where school_num = $p_school_num and can_order = 'Balance' and record_num = $p_user_num";
|
|
pp_query($query);
|
|
|
|
// Update user_paypal_transactions
|
|
pp_query("UPDATE user_paypal_transactions SET posting_message = 'Payment processed ok' WHERE record_num = $trxID");
|
|
pp_query("UPDATE user_paypal_transactions SET posting_result = 'Posted' WHERE school_num = $p_school_num AND trx_num = $TRXnum");
|
|
// pp_query("COMMIT");
|
|
|
|
adjustUserAccountDetails($p_user_num,$p_school_num);
|
|
|
|
echo("Payment processed ok\n\n\n");
|
|
?>
|