first commit

This commit is contained in:
dev-chiefworks
2022-05-31 16:21:53 -04:00
commit f76abffdcd
5978 changed files with 1078901 additions and 0 deletions
+133
View File
@@ -0,0 +1,133 @@
#--------------------------------------------------------------------
# Example Environment Configuration file
#
# This file can be used as a starting point for your own
# custom .env files, and contains most of the possible settings
# available in a default install.
#
# By default, all of the settings are commented out. If you want
# to override the setting, you must un-comment it by removing the '#'
# at the beginning of the line.
#--------------------------------------------------------------------
UID=1100
#--------------------------------------------------------------------
# ENVIRONMENT
#--------------------------------------------------------------------
CI_ENVIRONMENT = development
#--------------------------------------------------------------------
# APP
#--------------------------------------------------------------------
# app.baseURL = ''
# app.forceGlobalSecureRequests = false
# app.sessionDriver = 'CodeIgniter\Session\Handlers\FileHandler'
# app.sessionCookieName = 'ci_session'
# app.sessionExpiration = 7200
# app.sessionSavePath = null
# app.sessionMatchIP = false
# app.sessionTimeToUpdate = 300
# app.sessionRegenerateDestroy = false
# app.CSPEnabled = false
#--------------------------------------------------------------------
# DATABASE
#--------------------------------------------------------------------
# database.default.hostname = localhost
# database.default.database = ci4
# database.default.username = root
# database.default.password = root
# database.default.DBDriver = MySQLi
# database.default.DBPrefix =
# database.tests.hostname = localhost
# database.tests.database = ci4
# database.tests.username = root
# database.tests.password = root
# database.tests.DBDriver = MySQLi
# database.tests.DBPrefix =
#--------------------------------------------------------------------
# CONTENT SECURITY POLICY
#--------------------------------------------------------------------
# contentsecuritypolicy.reportOnly = false
# contentsecuritypolicy.defaultSrc = 'none'
# contentsecuritypolicy.scriptSrc = 'self'
# contentsecuritypolicy.styleSrc = 'self'
# contentsecuritypolicy.imageSrc = 'self'
# contentsecuritypolicy.base_uri = null
# contentsecuritypolicy.childSrc = null
# contentsecuritypolicy.connectSrc = 'self'
# contentsecuritypolicy.fontSrc = null
# contentsecuritypolicy.formAction = null
# contentsecuritypolicy.frameAncestors = null
# contentsecuritypolicy.frameSrc = null
# contentsecuritypolicy.mediaSrc = null
# contentsecuritypolicy.objectSrc = null
# contentsecuritypolicy.pluginTypes = null
# contentsecuritypolicy.reportURI = null
# contentsecuritypolicy.sandbox = false
# contentsecuritypolicy.upgradeInsecureRequests = false
#--------------------------------------------------------------------
# COOKIE
#--------------------------------------------------------------------
# cookie.prefix = ''
# cookie.expires = 0
# cookie.path = '/'
# cookie.domain = ''
# cookie.secure = false
# cookie.httponly = false
# cookie.samesite = 'Lax'
# cookie.raw = false
#--------------------------------------------------------------------
# ENCRYPTION
#--------------------------------------------------------------------
# encryption.key =
# encryption.driver = OpenSSL
# encryption.blockSize = 16
# encryption.digest = SHA512
#--------------------------------------------------------------------
# HONEYPOT
#--------------------------------------------------------------------
# honeypot.hidden = 'true'
# honeypot.label = 'Fill This Field'
# honeypot.name = 'honeypot'
# honeypot.template = '<label>{label}</label><input type="text" name="{name}" value=""/>'
# honeypot.container = '<div style="display:none">{template}</div>'
#--------------------------------------------------------------------
# SECURITY
#--------------------------------------------------------------------
# security.csrfProtection = 'cookie'
# security.tokenRandomize = false
# security.tokenName = 'csrf_token_name'
# security.headerName = 'X-CSRF-TOKEN'
# security.cookieName = 'csrf_cookie_name'
# security.expires = 7200
# security.regenerate = true
# security.redirect = true
# security.samesite = 'Lax'
#--------------------------------------------------------------------
# LOGGER
#--------------------------------------------------------------------
# logger.threshold = 4
#--------------------------------------------------------------------
# CURLRequest
#--------------------------------------------------------------------
# curlrequest.shareOptions = true
+38
View File
@@ -0,0 +1,38 @@
.DS_Store
application/cache/*
!application/cache/index.html
application/logs/*
!application/logs/index.html
!application/*/.htaccess
composer.lock
user_guide_src/build/*
user_guide_src/cilexer/build/*
user_guide_src/cilexer/dist/*
user_guide_src/cilexer/pycilexer.egg-info/*
/vendor/
# IDE Files
#-------------------------
/nbproject/
.idea/*
## Sublime Text cache files
*.tmlanguage.cache
*.tmPreferences.cache
*.stTheme.cache
*.sublime-workspace
*.sublime-project
/tests/tests/
/tests/results/
SAVVY/user/log/GPS.log
vendor
*.log
*.bak
+35
View File
@@ -0,0 +1,35 @@
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
#Removes access to the system folder by users.
#Additionally this will allow you to create a System.php controller,
#previously this would not have been possible.
#'system' can be replaced if you have renamed your system folder.
RewriteCond %{REQUEST_URI} ^system.*
RewriteRule ^(.*)$ /index.php?/$1 [L]
#When your application folder isn't in the system folder
#This snippet prevents user access to the application folder
#Submitted by: Fabdrol
#Rename 'application' to your applications folder name.
RewriteCond %{REQUEST_URI} ^application.*
RewriteRule ^(.*)$ /index.php?/$1 [L]
#Checks to
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?/$1 [L]
</IfModule>
<IfModule !mod_rewrite.c>
# If we don't have mod_rewrite installed, all 404's
# can be sent to index.php, and everything works as normal.
# Submitted by: ElliotHaughin
ErrorDocument 404 /index.php
</IfModule>
Binary file not shown.
+209290
View File
File diff suppressed because it is too large Load Diff
+28
View File
@@ -0,0 +1,28 @@
<?php
echo "[" . date("Y-m-d H:i:s") . "] Account Audit job is starting.\n";
include '../backend.php';
define("FLOAT_SYSTEM_ACCOUNT_AUDIT", 92015);
function Fextension_call($in, &$out) {
// logToFl("Merchant_Name count->" . $in["merchant_name"]);
global $savvyext;
$out = $savvyext->savvyext_api($in);
$ret = $out["retval"];
return $ret;
}
$inX["limit"] = 100;
$inX["pid"] = 0;
$inX["action"] = FLOAT_SYSTEM_ACCOUNT_AUDIT;
$outX = array();
$extension_call = true;
if ($extension_call == true) {
// logToFl("merchant_name count->" . $res->merchant_name);
Fextension_call($inX, $outX);
}
+154
View File
@@ -0,0 +1,154 @@
<?php
/*
* members account imports
*/
include '../backend.php';
define("FLOAT_SYSTEM_IMPORT_ACCONTTYPES", 91010);
function Fextension_call($in, &$out) {
// logToFl("Merchant_Name count->" . $in["merchant_name"]);
global $savvyext;
$out = $savvyext->savvyext_api($in);
$ret = $out["retval"];
return $ret;
}
$inX["limit"] = 250;
$inX["offset"] = 0;
$inX["intel_imported"] = 'false';
$outX = array();
accounts_benefits_importing($inX, $outX);
logToFl("Total count->" . $outX->count);
if ($outX->count > 0) {
foreach ($outX->results as $res) {
// logToFl("API Result ->".$res);
echo "Yes ---------------------------------------------- <br>";
$in = array();
$in = (array) $res;
// print_r( $in );
$in["pid"] = 100;
$in["import_id"] = $in["id"];
$out = array();
$in["action"] = FLOAT_SYSTEM_IMPORT_ACCONTTYPES;
$extension_call = true;
if ($extension_call == true && $in["member_id"] != '') {
// logToFl("merchant_name count->" . $res->merchant_name);
// echo "Here " .rand(1000,9999);
Fextension_call($in, $out);
if ($out["result_import_id"] != '' && $out["result_import_id"] > 0) {
makedimported_accounts_types($in, $out); // call back to merk transaction imported
}
}
//
} // end for each
} // if records avilable
function makedimported_accounts_types($in, &$out) {
global $savvyext;
$target_url = $savvyext->cfgReadChar('microservices.account') . "/api/v1/accounts/" . $in["import_id"] . "/"; //
$fields_string = "";
//url-ify the data for the POST
foreach ($in as $key => $value) {
$fields_string .= $key . '=' . $value . '&';
}
rtrim($fields_string, '&');
// $target_url = $target_url . "/?" . $fields_string;
$returnData = json_encode(["intel_imported" => date("Y-m-d H:i:s")]);
//open connection
$ch = curl_init();
//set the url, number of POST vars, POST data
curl_setopt($ch, CURLOPT_URL, $target_url);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'Connection: Keep-Alive',
'Authorization: Server-Token ' . $savvyext->cfgReadChar('system.bank_token'),
'Accept: application/json'
));
// curl_setopt($ch, CURLOPT_POST, count($in));
curl_setopt($ch, CURLOPT_POSTFIELDS, $returnData);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
//execute post
$result = curl_exec($ch);
//close connection
curl_close($ch);
//logToFl("API Result ->".$result);
$out = json_decode($result);
}
function accounts_benefits_importing($in, &$out) {
global $savvyext;
$target_url = $savvyext->cfgReadChar('microservices.account') . "/api/v1/accounts/?intel_imported=false"; // 
$fields_string = "";
//url-ify the data for the POST
foreach ($in as $key => $value) {
$fields_string .= $key . '=' . $value . '&';
}
rtrim($fields_string, '&');
$target_url = $target_url . "/?" . $fields_string;
logToFl("API URL ->" . $target_url);
//open connection
$ch = curl_init();
//set the url, number of POST vars, POST data
curl_setopt($ch, CURLOPT_URL, $target_url);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'Connection: Keep-Alive',
'Authorization: Server-Token ' . $savvyext->cfgReadChar('system.bank_token'),
'Accept: application/json'
));
// curl_setopt($ch, CURLOPT_POST, count($in));
// curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
//execute post
$result = curl_exec($ch);
//close connection
curl_close($ch);
//logToFl("API Result ->".$result);
$out = json_decode($result);
// print_r( $out );
}
function logToFl($lg_strr) {
/* $myfile = fopen("LOG/logf_benefit.txt", "a+");
$txt = $lg_strr . "\n";
fwrite($myfile, $txt);
fclose($myfile);
*
*/
}
+28
View File
@@ -0,0 +1,28 @@
<?php
echo "[" . date("Y-m-d H:i:s") . "] Account Audit job is starting.\n";
include '../backend.php';
define("SAVVY_BKO_INITLOCATION_AUDIT", 100045);
function Fextension_call($in, &$out) {
// logToFl("Merchant_Name count->" . $in["merchant_name"]);
global $savvyext;
$out = $savvyext->savvyext_api($in);
$ret = $out["retval"];
return $ret;
}
$inX["limit"] = 30;
$inX["pid"] = 0;
$inX["action"] = SAVVY_BKO_INITLOCATION_AUDIT;
$outX = array();
$extension_call = true;
if ($extension_call == true) {
// logToFl("merchant_name count->" . $res->merchant_name);
Fextension_call($inX, $outX);
}
+165
View File
@@ -0,0 +1,165 @@
<?php
echo "[" . date("Y-m-d H:i:s") . "] account_process_subscription job is starting.\n";
require('../backend.php');
// We will not limit the SQL we will exhaust the allowed memory
// we will process data in ${hard_limit} batches and hopefully catch up
$hard_limit = 550;
$span_limit = 30;
$db_host = $savvyext->cfgReadChar('database.host');
$db_name = $savvyext->cfgReadChar('database.name');
$db_user = $savvyext->cfgReadChar('database.user');
$db_pass = $savvyext->cfgReadChar('database.pass');
$db_port = $savvyext->cfgReadLong('database.port');
$connstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$conn = pg_connect($connstr);
$db_host = $savvyext->cfgReadChar('database_replica.host');
$db_name = $savvyext->cfgReadChar('database_replica.name');
$db_user = $savvyext->cfgReadChar('database_replica.user');
$db_pass = $savvyext->cfgReadChar('database_replica.pass');
$db_port = $savvyext->cfgReadLong('database_replica.port');
$readOnlyReplicaConnstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$readOnlyReplicaConn = pg_connect($readOnlyReplicaConnstr);
// Expire any late subscription here
// Processing the transactions now
$mysql = "SELECT ma.id AS assign_id, ma.*,mc.card_reciept AS providers FROM members_card_assign ma "
. " LEFT JOIN main_cards mc ON mc.id = ma.card_id "
. " WHERE ma.subscribe IS NOT NULL AND ma.completed IS NULL AND ma.reciept_count =0 "
. " AND mc.card_reciept IS NOT NULL AND mc.button1_action IN ('GOOFFERS') "
. " ORDER BY ma.updated ASC LIMIT $hard_limit";
//echo $mysql;
$r0 = pg_query($readOnlyReplicaConn, $mysql);
if ($r0 && pg_num_rows($r0)) {
while ($f0 = pg_fetch_assoc($r0)) {
$member_id = $f0["member_id"];
$assign_id = $f0["assign_id"];
$providers = $f0["providers"];
$subscribe_date = $f0["subscribe"];
$provider_name = "";
// let just mar trhis so that w dont over procss same trasaction
$mysql_up = "UPDATE members_card_assign SET updated = now() WHERE id = $assign_id AND member_id = $member_id";
pg_query($conn, $mysql_up);
if ($providers != '' && $providers > 0) {
// get the provider name
// We have to visist this again to improve the srach string
$mysql_find = "SELECT id, LOWER(name) , LOWER(name_alias) FROM transport_providers WHERE id = $providers";
$alias_extra = "";
$rf = pg_query($readOnlyReplicaConn, $mysql_find);
if ($rf && pg_num_rows($rf)) {
$r = pg_fetch_row($rf);
$provider_name = $r[1]; // may be an array
$alias_string = $r[2];
// $alias_string = "AA,BB,CC,";
if (strlen($alias_string) > 0) {
$pieces = explode(",", $alias_string);
$count_item = count($pieces);
for ($ii = 0; $ii < $count_item; $ii++) {
$this_element = trim(strtolower($pieces[$ii]));
if (strlen($this_element) > 0) {
$itm_str = "'" . $this_element . "'";
if ($ii > 0) {
$alias_extra .= ",";
}
$alias_extra .= $itm_str;
}
}
}
}
// echo $provider_name;
if ($provider_name != '') {
$total_bank_recipts = countAccountReciepts($readOnlyReplicaConn, $member_id, $provider_name, $subscribe_date, $span_limit,$alias_extra);
$total_email_recipts = countPearsedReciepts($readOnlyReplicaConn, $member_id, $providers, $subscribe_date, $span_limit);
$total_bank_extra_recipts = countOtherAccountReciepts($readOnlyReplicaConn, $member_id, $provider_name, $subscribe_date, $span_limit,$alias_extra);
$total_email_extra_recipts = countOtherPearsedReciepts($readOnlyReplicaConn, $member_id, $providers, $subscribe_date, $span_limit);
$total_recipts = $total_bank_recipts + $total_email_recipts + $total_bank_extra_recipts + $total_email_extra_recipts;
if ($total_recipts > 0) {
$mysql_up1 = "UPDATE members_card_assign SET updated = now(),reciept_count=$total_recipts WHERE id = $assign_id AND member_id = $member_id";
pg_query($conn, $mysql_up1);
}
}
}
}
}
function countAccountReciepts($readOnlyReplicaConn, $member_id, $provider_name, $subscribe_date, $span_limit,$alias_extra) {
$total_rec = 0;
$provider_total = "'".$provider_name."'";
if ( strlen($alias_extra) > 0 ){
$provider_total= $provider_total.",".$alias_extra;
}
$mysql = "SELECT count(id) AS total_rec FROM members_bankimport WHERE member_id=$member_id AND lower(merchant_name) IN ($provider_total) AND time >= '$subscribe_date'";
$rf = pg_query($readOnlyReplicaConn, $mysql);
if ($rf && pg_num_rows($rf)) {
$r = pg_fetch_row($rf);
$total_rec = $r[0];
}
return $total_rec;
}
function countPearsedReciepts($readOnlyReplicaConn, $member_id, $provider, $subscribe_date, $span_limit) {
$total_rec = 0;
$mysql = "SELECT count(pi.id) AS total_rec FROM parsedemail_item pi LEFT JOIN trackedemail_item ti ON ti.id=pi.trackedemail_item_id WHERE ti.member_id=$member_id AND pi.transport_provider_id=$provider AND pi.travel_date >= '$subscribe_date'";
$rf = pg_query($readOnlyReplicaConn, $mysql);
if ($rf && pg_num_rows($rf)) {
$r = pg_fetch_row($rf);
$total_rec = $r[0];
}
return $total_rec;
}
function countOtherAccountReciepts($conn, $member_id, $provider_name, $subscribe_date, $span_limit,$alias_extra) {
$total_rec = 0;
$provider_total = "'".$provider_name."'";
if ( strlen($alias_extra) > 0 ){
$provider_total= $provider_total.",".$alias_extra;
}
$mysql = "SELECT count(id) AS total_rec FROM members_transactions_import_raw WHERE member_id=$member_id AND LOWER(merchant_name) IN ($provider_total) AND time >= '$subscribe_date'";
//echo $mysql;
$rf = pg_query($conn, $mysql);
if ($rf && pg_num_rows($rf)) {
$r = pg_fetch_row($rf);
$total_rec = $r[0];
}
return $total_rec;
}
function countOtherPearsedReciepts($conn, $member_id, $provider, $subscribe_date, $span_limit) {
$total_rec = 0;
$mysql = "SELECT count(id) AS total_rec FROM parsedemail_item_payment WHERE member_id=$member_id AND transport_provider_id=$provider AND receipt_datetime >= '$subscribe_date'";
//echo $mysql;
$rf = pg_query($conn, $mysql);
if ($rf && pg_num_rows($rf)) {
$r = pg_fetch_row($rf);
$total_rec = $r[0];
}
return $total_rec;
}
pg_close($conn);
pg_close($readOnlyReplicaConn);
echo "[" . date("Y-m-d H:i:s") . "] account_process_subscription job complete.\n";
?>
+201
View File
@@ -0,0 +1,201 @@
<?php
include '../backend.php';
define("FLOAT_SYSTEM_IMPORT_TRANSACTIONS", 91000);
function Fextension_call($in, &$out) {
// logToFl("Merchant_Name count->" . $in["merchant_name"]);
global $savvyext;
$out = $savvyext->savvyext_api($in);
$ret = $out["retval"];
return $ret;
}
$inX["limit"] = 250;
$inX["offset"] = 0;
$inX["intel_imported"] = 'false';
$outX=array();
import_accounts_transactions($inX, $outX);
// test_import_accounts_transactions($inX, $outX); // just for testing -- to be removed
logToFl("Total count->".$outX->count);
if ($outX->count > 0) {
foreach ($outX->results as $res) {
$in = array();
$in["pid"] =100;
$in["import_id"] = $res->id;
$in["account"] = $res->account;
$in["member_id"] = $res->member_id;
$in["amount"] = (int)(100.0*$res->amount);
$in["currency"] = $res->currency;
$in["description"] = $res->description;
$in["time"] = $res->time;
$in["category"] = $res->category;
$in["provider_category"] = $res->provider_category;
$in["intel_imported"] = $res->intel_imported;
$in["merchant_provider_id"] = $res->merchant_provider_id;
$in["merchant_name"] = $res->merchant_name;
$in["status"] = isset($res->status) ? $res->status : "0";
$in["fake"] = isset($res->extra->fake) ? $res->extra->fake : false;
$in["mode"] = isset($res->extra->mode) ? $res->extra->mode : "";
$in["duplicated"] = isset($res->extra->duplicated) ? $res->extra->duplicated : false;
$out = array();
$in["action"] = FLOAT_SYSTEM_IMPORT_TRANSACTIONS;
$extension_call = true;
if ($extension_call == true && $in["member_id"] !='') {
// logToFl("merchant_name count->" . $res->merchant_name);
Fextension_call($in, $out);
}
makedimported_accounts_transactions($in, $out); // call back to merk transaction imported
} // end for each
} // if records avilable
function makedimported_accounts_transactions($in, &$out) {
global $savvyext;
$target_url = $savvyext->cfgReadChar('microservices.account') . "/api/v1/transactions/".$in["import_id"]."/"; //
$fields_string = "";
//url-ify the data for the POST
foreach ($in as $key => $value) {
$fields_string .= $key . '=' . $value . '&';
}
rtrim($fields_string, '&');
// $target_url = $target_url . "/?" . $fields_string;
$returnData = json_encode( [ "intel_imported"=> date("Y-m-d H:i:s") ] );
//open connection
$ch = curl_init();
//set the url, number of POST vars, POST data
curl_setopt($ch, CURLOPT_URL, $target_url);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'Connection: Keep-Alive',
'Authorization: Server-Token ' . $savvyext->cfgReadChar('system.bank_token'),
'Accept: application/json'
));
// curl_setopt($ch, CURLOPT_POST, count($in));
curl_setopt($ch, CURLOPT_POSTFIELDS, $returnData);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
//execute post
$result = curl_exec($ch);
//close connection
curl_close($ch);
//logToFl("API Result ->".$result);
$out = json_decode($result);
}
function import_accounts_transactions($in, &$out) {
global $savvyext;
$target_url = $savvyext->cfgReadChar('microservices.account') . "/api/v1/transactions"; //
$fields_string = "";
//url-ify the data for the POST
foreach ($in as $key => $value) {
$fields_string .= $key . '=' . $value . '&';
}
rtrim($fields_string, '&');
$target_url = $target_url . "/?" . $fields_string;
logToFl("API URL ->".$target_url);
//open connection
$ch = curl_init();
//set the url, number of POST vars, POST data
curl_setopt($ch, CURLOPT_URL, $target_url);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'Connection: Keep-Alive',
'Authorization: Server-Token ' . $savvyext->cfgReadChar('system.bank_token'),
'Accept: application/json'
));
// curl_setopt($ch, CURLOPT_POST, count($in));
// curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
//execute post
$result = curl_exec($ch);
//close connection
curl_close($ch);
//logToFl("API Result ->".$result);
$out = json_decode($result);
}
function test_import_accounts_transactions($in, &$out) {
$target_url = "http://chiefsoft.net/DATA/transactions.php"; //
$fields_string = "";
//url-ify the data for the POST
foreach ($in as $key => $value) {
$fields_string .= $key . '=' . $value . '&';
}
rtrim($fields_string, '&');
$target_url = $target_url . "/?" . $fields_string;
//open connection
$ch = curl_init();
//set the url, number of POST vars, POST data
curl_setopt($ch, CURLOPT_URL, $target_url);
// curl_setopt($ch, CURLOPT_POST, count($in));
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
//execute post
$result = curl_exec($ch);
//close connection
curl_close($ch);
//logToFl("Result ->".$result);
$out = json_decode($result);
// Parse result
/* foreach (explode("\n", $result) as $line) {
if ($line == "" || strpos($line, "=") === false)
continue;
$key = trim(strtok($line, "="));
if ($key != "") {
$out[$key] = base64_decode(substr($line, 1 + strlen($key)));
}
}
* */
}
function logToFl($lg_strr) {
$myfile = fopen("LOG/logf.txt", "a+");
$txt = $lg_strr."\n";
fwrite($myfile, $txt);
fclose($myfile);
}
@@ -0,0 +1,170 @@
<?php
// require_once( '/Users/osx/Sites/Float/adminsavvy/backend.php' );
include '../backend.php';
require_once('../vendor/autoload.php');
require_once('common/Logger.php');
use \SendGrid\Mail\Mail;
/**
* Send email Float App sign up emails last 24 hours daily report
*/
class EmailLast24hrsReport
{
public $conn;
public $repConn;
public $sendgrid_api;
public $sender;
public $sender_name;
public $receivers;
protected $hard_limit = 550;
function __construct()
{
global $savvyext;
$this->conn = self::__cnn($savvyext);
$this->repConn = self::__repCnn($savvyext);
$this->sendgrid_api = $savvyext->cfgReadChar('mailsend.api_key');
$this->sender = $savvyext->cfgReadChar('mailsend.from');
$this->sender_name = $savvyext->cfgReadChar('mailsend.name');
$this->receivers = array(
'jervis@float.sg' => 'Jervis',
'tnguyen@float.sg' => 'Tri Nguyen',
//'charlie.nguyen.goldenowl@gmail.com' => 'Charlie Nguyen',
);
}
private static function __cnn($savvyext)
{
$db_host = $savvyext->cfgReadChar('database.host');
$db_name = $savvyext->cfgReadChar('database.name');
$db_user = $savvyext->cfgReadChar('database.user');
$db_pass = $savvyext->cfgReadChar('database.pass');
$db_port = $savvyext->cfgReadLong('database.port');
$connstr = sprintf('host=%s port=%s dbname=%s user=%s password=%s', $db_host, $db_port, $db_name, $db_user, $db_pass);
$conn = pg_connect($connstr);
return $conn;
}
private static function __repCnn($savvyext)
{
$db_host = $savvyext->cfgReadChar('database_replica.host');
$db_name = $savvyext->cfgReadChar('database_replica.name');
$db_user = $savvyext->cfgReadChar('database_replica.user');
$db_pass = $savvyext->cfgReadChar('database_replica.pass');
$db_port = $savvyext->cfgReadLong('database_replica.port');
$connstr = sprintf('host=%s port=%s dbname=%s user=%s password=%s', $db_host, $db_port, $db_name, $db_user, $db_pass);
$conn = pg_connect($connstr);
return $conn;
}
private function array2csv($data, $delimiter = ',', $enclosure = '"', $escape_char = "\\")
{
$f = fopen('php://memory', 'r+');
foreach ($data as $item) {
fputcsv($f, $item, $delimiter, $enclosure, $escape_char);
}
rewind($f);
return stream_get_contents($f);
}
/**
* Send email report via SendGrid
* @param array $data list email fail
* @return mixed
*/
protected function send($data)
{
$short_date = (new \DateTime())->format('Y-M-d');
// create email layout
ob_start();
require_once(__DIR__ . '/email/sign_up_email_last_24hrs.php');
$layout = ob_get_clean();
// create sendgrid instance
$sendgrid = new \SendGrid\Mail\Mail;
$sendgrid->setFrom($this->sender, $this->sender_name);
$sendgrid->setSubject('Float App sign up emails last 24 hours daily report');
$sendgrid->addTos($this->receivers);
$sendgrid->addContent('text/html', $layout);
//HEADER of csv files
array_unshift($data,[
'Date','Email name', 'Total emails'
]);
$att1 = new \SendGrid\Mail\Attachment();
//$att1->setContent( file_get_contents("test_files/1/1.txt") );
$att1->setContent( $this->array2csv($data) );
$att1->setType("text/csv");
$att1->setFilename("sign-up-emails-last-24-hrs-report-".$short_date.".csv");
$att1->setDisposition("attachment");
$sendgrid->addAttachment( $att1 );
// send
$send = new \SendGrid($this->sendgrid_api);
$response = $send->send($sendgrid);
if ($response->statusCode() !== 202) {
throw new Exception('Send email via Sendgrid get errors!');
}
}
public function getemails()
{
try {
// HH24:MI
$sql = sprintf("
SELECT to_char(added::DATE,'YYYY-Mon-DD') as date,'Welcome to Float' as email_name, count(id) as total FROM members
WHERE added >= NOW() - INTERVAL '24 HOURS'
GROUP BY added::DATE
ORDER BY added::DATE ASC;
");
$results = pg_query($this->repConn, $sql);
if ($error = pg_last_error($this->repConn)) {
throw new Exception($error);
}
return pg_fetch_all($results);
} catch (Exception $e) {
Logger::debug($e->getMessage());
}
}
private function getEmptyData(){
return [
'date' => (new \DateTime())->modify('-24 hours')->format('Y-M-d'), // H:i
'email_name' => 'Welcome to Float',
'total' => '0',
];
}
/**
* Excute jobs
* @return mixed
*/
public function excute()
{
try {
$data = $this->getemails();
if (!$data) {
$data = [$this->getEmptyData()];
//throw new Exception('No Email Receipt which parsed failed!');
}
$send = $this->send($data);
} catch (Exception $e) {
Logger::debug($e->getMessage());
}
}
}
$instace = new EmailLast24hrsReport;
$instace->excute();
+423
View File
@@ -0,0 +1,423 @@
<?php
include '../backend.php';
require_once('../vendor/autoload.php');
require_once(__DIR__ . '/lock.php');
use \SendGrid\Mail\Mail;
/**
* Get Sendgrid Report
*/
class Custom_Report {
// curl setup private
private $curl;
protected $api_url;
protected $key;
protected $replica_conn;
protected $sendgrid_api;
protected $sendgrid_from;
protected $sendgrid_name;
public function __construct() {
global $savvyext;
$this->api_url = $savvyext->cfgReadChar('sendgrid.api_url');
$this->key = $savvyext->cfgReadChar('sendgrid.api_key');
// connect replica database
$db_host = $savvyext->cfgReadChar('database_replica.host');
$db_name = $savvyext->cfgReadChar('database_replica.name');
$db_user = $savvyext->cfgReadChar('database_replica.user');
$db_pass = $savvyext->cfgReadChar('database_replica.pass');
$db_port = $savvyext->cfgReadLong('database_replica.port');
$db_conn = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$this->replica_conn = pg_connect($db_conn);
// get range of days to retrieve data
$this->_2week = self::getDaysOfWeek( $week = -2 );
$this->_1week = self::getDaysOfWeek( $week = -1 );
// sendgrid api
$this->sendgrid_api = $savvyext->cfgReadChar('mailsend.api_key');
$this->sendgrid_from = $savvyext->cfgReadChar('mailsend.from');
$this->sendgrid_name = $savvyext->cfgReadChar('mailsend.name');
}
/**
* Write errors log
* @param string $action action name
* @param string $message error message
* @return
*/
private static function logs( $message ) {
$log = 'Date: ' .date("F j, Y, g:i a").PHP_EOL.
'Attempt: '.PHP_EOL.
sprintf('%s', is_array($message) ? json_encode($message): $message).PHP_EOL.
'-------------------------'.PHP_EOL;
file_put_contents( './logs/log_'.date('j.n.Y').'log', $log, FILE_APPEND );
}
/**
* Return range days from monday to sunday of week
* @param number $weekOffset number of week
* @return array
*/
private static function getDaysOfWeek( $weekOffset ) {
$date = new DateTime();
$date->setIsoDate( $date->format('o'), $date->format('W') + $weekOffset );
return array(
'monday' => $date->format('Y-m-d'),
'sunday' => $date->modify('+6 day')->format('Y-m-d')
);
}
/**
* Separation array by range of dates
* @param array $datas list data need to be separation
* @param string $start start date
* @param string $end end date
* @return array new arrays
*/
private static function separationByDates( $datas, $start, $end ) {
$new_array = array();
foreach ( $datas as $key => $data ) {
if ( $start <= $data['dates'] and $data['dates'] <= $end ) {
array_push( $new_array, $data );
unset( $datas[$key] );
}
}
return array( 'old_array' => $datas, 'new_array' => $new_array );
}
/**
* Check the time to run the cronjob
* @return bool
*/
private static function check_weekly_time() {
$timestamp = time();
if ( date( 'D', $timestamp ) === 'Mon' ) {
return true;
}
exit();
}
/**
* Prepare cURL to call SendGrid API
* @param string|null $endpoint api endpoint
* @param array $params api params
* @return mixed
*/
protected function getSendgrid(string $endpoint = null, $params = array()) {
// prepare url api
$api_call = sprintf( '%s%s?%s', $this->api_url, $endpoint, http_build_query($params) );
$ch = curl_init($api_call);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_VERBOSE, false);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'Authorization: ' . $this->key
));
// check cURL error
$error = curl_error($ch);
if ($error) {
throw new Exception('Response with errors: ' . is_array($error) ? json_decode($error) : $error );
}
$response = json_decode( curl_exec($ch), true );
if (isset($response['errors'])) {
$message = is_array($response['errors']) ? json_decode($response['errors']) : response['errors'];
throw new Exception('Response with errors: ' . $message);
}
if (isset($results['results']) && !count($results['results'])) {
throw new Exception('Response with empty data');
}
return $response;
}
/**
* execute pg query
* @param string $query sql query
* @return array results
*/
protected function execute_pg_query( $query ) {
try {
$do = pg_query( $this->replica_conn, $query );
if ( $errors = pg_last_error( $this->replica_conn ) ) {
throw new Exception( $errors );
}
$results = pg_fetch_all( $do );
if ( ! $results ) {
throw new Exception( 'Results not found!' );
}
// Separation results by dates
$results = self::separationByDates( $results, $this->_1week['monday'], $this->_1week['sunday'] );
return $results;
} catch (Exception $e) {
self::logs('Errors', $e->getMessage());
return;
}
}
/**
* Generate chart image
* @return string image src
*/
protected function generate_chart_images( $chartLabels, $chartValues ) {
$chartConfig = array(
'type' => 'line',
'backgroundColor' => 'transparent',
'data' => array(
'labels' => $chartLabels,
'datasets' => array(
array(
'label' => sprintf( 'from %s - to %s', $this->_2week['monday'], $this->_2week['sunday'] ),
'backgroundColor' => '#36A2EB',
'borderColor' => '#36A2EB',
'borderDash' => [5, 5],
'fill' => false,
'data' => array_values( $chartValues['old_value'] )
),
array(
'label' => sprintf( 'from %s - to %s', $this->_1week['monday'], $this->_1week['sunday'] ),
'backgroundColor' => '#F93784',
'borderColor' => '#F93784',
'fill' => false,
'data' => array_values( $chartValues['new_value'] )
)
)
),
'options' => array(
'responsive' => true,
'plugins' => array(
'datalabels' => array(
'display' => true,
'align' => 'top',
'backgroundColor' => '#FFFFFF',
'borderRadius' => 3,
'borderWidth' => 1,
'borderColor' => '#B8B8B8',
'font' => array(
'size' => 8
)
)
)
)
);
$chartConfig = json_encode( $chartConfig );
$result = preg_replace( '/(")(function.*?})(")/m', '$2', $chartConfig);
$imageUrl = 'https://quickchart.io/chart?w=500&h=200&c=' . urlencode($result);
return $imageUrl;
}
/**
* Get tracking installed os
* @return array
*/
public function get_tracking_installed() {
// prepare sql to retrieve data
// by range days
$query = sprintf("
SELECT md.created as dates,
SUM(case when mdp.platform = 'Android' then 1 else 0 end) as Android,
SUM(case when mdp.platform = 'iOS' then 1 else 0 end) as iOS
FROM members_devices md
LEFT JOIN members_device_platforms mdp ON md.platform_id = mdp.id
WHERE md.created BETWEEN '%s' AND '%s'
AND md.member_id IN (SELECT id FROM members WHERE status = 1)
GROUP BY dates
", $this->_2week['monday'], $this->_1week['sunday']);
// run query
$results = $this->execute_pg_query( $query );
return $results;
}
/**
* Get number users who subscribed the deals
* @return int numbers
*/
public function get_subscribe_deals() {
$query = sprintf("
SELECT mca.subscribe as dates, count(DISTINCT m.email)
FROM members_card_assign mca
LEFT JOIN main_cards mc ON mca.card_id = mc.id
LEFT JOIN members m ON mca.member_id = m.id
WHERE mca.subscribe IS NOT NULL AND mc.button1_action IN ('GOOFFERS')
AND mca.subscribe BETWEEN '%s' AND '%s'
GROUP BY dates
", $this->_2week['monday'], $this->_1week['sunday']);
// run query
$results = $this->execute_pg_query( $query );
return $results;
}
/**
* Get number user who filled profile
* @return int numbers
*/
public function get_user_filled_profile() {
$query = sprintf("
SELECT greatest(m.added, mba.added, ot.created, md.created) as Dates, count(DISTINCT m.email)
FROM members m
INNER JOIN members_bank_accounts mba ON m.id = mba.member_id
INNER JOIN oauth2_tokens ot ON m.id = ot.member_id
INNER JOIN members_devices md on m.id = md.member_id
WHERE ((m.max_budget <> 0) IS NOT FALSE AND mba.status = 1 AND md.player_id is not null)
AND (greatest(m.added, mba.added, ot.created, md.created) BETWEEN '%s' AND '%s')
GROUP BY Dates
", $this->_2week['monday'], $this->_1week['sunday'] );
// run query
$results = $this->execute_pg_query( $query );
return $results;
}
/**
* Get sendgrid tracking data
* @return array properties of data
*/
public function get_sendgrid_tracking() {
try {
$params = array(
'aggregated_by' => 'week',
'start_date' => $this->_2week['monday'],
'end_date' => $this->_1week['sunday']
);
$results = $this->getSendgrid( $endpoint = 'stats', $params );
// check error api call
if ( isset( $results['errors'] ) ) {
$message = $results['errors'][0]['message'];
throw new Exception( $message );
}
$combineResults = array();
foreach ( $results as $key => $value ) {
$combineResults[] = array(
'dates' => $value['date'],
'data' => $value['stats'][0]['metrics']
);
}
$results = self::separationByDates( $combineResults, $this->_1week['monday'], $this->_1week['sunday'] );
return $results;
} catch (Exception $e) {
self::logs($action_name, $e->getMessage());
return;
}
}
/**
* BKO tracking data
* @return string chart image
*/
public function bko_tracking() {
// tracking install device
$install = $this->get_tracking_installed();
// tracking user subscribe deals
$subscribe = $this->get_subscribe_deals();
// tracking user filled profile
$profile = $this->get_user_filled_profile();
$data = array(
'old_value' => array(
'android' => count( array_filter( $install['old_array'], function($e) {return $e['android'] > 0; } ) ),
'ios' => count( array_filter( $install['old_array'], function($e) {return $e['ios'] > 0; } ) ),
'subs' => count( $subscribe['old_array'] ),
'profile' => count( $profile['old_array'] )
),
'new_value' => array(
'android' => count( array_filter( $install['new_array'], function($e) {return $e['android'] > 0; } ) ),
'ios' => count( array_filter( $install['new_array'], function($e) {return $e['ios'] > 0; } ) ),
'subs' => count( $subscribe['new_array'] ),
'profile' => count( $profile['new_array'] )
)
);
$labels = array( 'Android install', 'iOS install', 'Subscribe deals', 'Filled profile' );
// get chart image
$imgSrc = $this->generate_chart_images( $labels, $data );
return $imgSrc;
}
/**
* SendGrid tracking data
* @return string chart image
*/
public function sendgrid_tracking() {
$tracking = $this->get_sendgrid_tracking();
if ( ! $tracking ) {
return;
}
$data = array();
foreach ( $tracking as $key => $item ) {
$data[ $key ] = array(
'delivered' => array_sum( array_column( $item[0], 'delivered') ),
'processed' => array_sum( array_column( $item[0], 'processed') ),
'unique_clicks' => array_sum( array_column( $item[0], 'unique_clicks') ),
'unique_opens' => array_sum( array_column( $item[0], 'unique_opens') ),
);
}
$data = array(
'old_value' => $data['old_array'],
'new_value' => $data['new_array']
);
$labels = array( 'Delivered', 'Processed', 'Unique Clicks', 'Unique Opens' );
// get chart image
$imgSrc = $this->generate_chart_images( $labels, $data );
return $imgSrc;
}
/**
* Send custom email report
* @return mixed
*/
public function sendEmail() {
// check weekly report time
self::check_weekly_time();
$bko_tracking = $this->bko_tracking();
$sendgrid_tracking = $this->sendgrid_tracking();
// include email template
ob_start();
require_once('./email/custom-report.php');
$mail_html = ob_get_clean();
try {
$email = new \SendGrid\Mail\Mail();
$email->setFrom( $this->sendgrid_from, $this->sendgrid_name );
$email->setSubject( 'Float Weekly Report' );
$toEmails = array(
'stew@float.sg' => 'Stew',
'olu@float.sg' => 'Olu',
'valeriy@float.sg' => 'Valeriy',
'tokslaw@float.sg' => 'Tokslaw',
'jeff@float.sg' => 'Jeff',
'chelsea@float.sg' => 'Chelsea'
);
$email->addTos( $toEmails );
$email->addContent( 'text/html', $mail_html );
$sendgrid = new \SendGrid( $this->sendgrid_api );
$response = $sendgrid->send( $email );
if ( $response->statusCode() !== 202 ) {
throw new Exception( 'Send custom report get errors' );
}
echo 'Success';
} catch (Exception $e) {
echo 'Custom report could not be sent. Mailer Error: ', $e->getMessage();
self::logs( 'Custom report could not be sent. Mailer Error: ', $e->getMessage() );
exit();
}
}
}
$api = new Custom_Report();
$api->sendEmail();
+119
View File
@@ -0,0 +1,119 @@
<?php
$job_name = pathinfo(__FILE__, PATHINFO_FILENAME);
echo "[".date("Y-m-d H:i:s")."] ".$job_name." job is starting.\n";
require('lock.php');
$lock_file = lock_pid_file();
set_time_limit(0); // No limit!
require('../backend.php');
require('common/Logger.php');
$httpAuthToken = $savvyext->cfgReadChar('system.oauth2_token');
$encryptionAlg = $savvyext->cfgReadChar('encryption.algorithm');
$encryptionKey = $savvyext->cfgReadChar('encryption.key');
$encryptionIV = $savvyext->cfgReadChar('encryption.iv');
$baseURL = $savvyext->cfgReadChar('system.api_url');
$db_host = $savvyext->cfgReadChar('database_replica.host');
$db_name = $savvyext->cfgReadChar('database_replica.name');
$db_user = $savvyext->cfgReadChar('database_replica.user');
$db_pass = $savvyext->cfgReadChar('database_replica.pass');
$db_port = $savvyext->cfgReadLong('database_replica.port');
$connstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$conn = pg_connect($connstr);
$q = "SELECT * FROM quotes WHERE completed IS NULL or travel_date IS NULL";
//$q.= " AND transport_provider_id=2 "; // DEBUG
$q.= " ORDER BY created DESC";
$r = pg_query($conn, $q);
if ($r && pg_num_rows($r)) {
while ($f=pg_fetch_assoc($r)) {
list($res,$cost) = check_quote($f["id"]);
if ($res>0) {
if ($res==2) {
echo "[".date("Y-m-d H:i:s")."] Quote ${cost} for ID#".$f["id"].".\n";
} else {
echo "[".date("Y-m-d H:i:s")."] Unexpected result for ID#".$f["id"].".\n";
}
} else {
if ($res==-1) {
echo "[".date("Y-m-d H:i:s")."] Final quote failure for ID#".$f["id"].".\n";
} else {
echo "[".date("Y-m-d H:i:s")."] check_quote failed(${res}) for ID#".$f["id"].".\n";
}
}
}
}
function check_quote($id) {
global $job_name;
if ($id>0) { // minimal sanity
list($payload,$decrypted,$result,$body) = main_api_get("/trips/api/quote/",$id);
$log = [
'job_name' => $job_name,
'function' => __FUNCTION__,
'request' => "/trips/api/quote/".$id,
'input_data' => $id,
'response_data' => $payload,
];
Logger::debug($log);
if (is_array($payload) && array_key_exists('id',$payload) && $payload['id']>0) {
if (array_key_exists('cost',$payload) && $payload['cost']>0) {
return [2,$payload['cost']];
}
if (array_key_exists('travel_date',$payload) && $payload['travel_date']!='') {
return [-1, NULL];
}
} else {
return [-2, NULL];
}
}
return [-3, NULL];
}
function main_api_get($endpoint,$input) {
global $baseURL, $encryptionAlg, $encryptionKey, $encryptionIV, $httpAuthToken;
if ($endpoint!="" && $input!="") { // minimal sanity
sleep(1);
$url = $baseURL . $endpoint . $input;
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_VERBOSE, false);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'Authorization: Server-Token ' . $httpAuthToken,
"client_id: BATCH"
)
);
$body = curl_exec($ch);
$result = json_decode($body,true);
$decrypted = openssl_decrypt(
hex2bin(
$result['payload']
),
$encryptionAlg,
$encryptionKey,
OPENSSL_RAW_DATA,
$encryptionIV
);
$payload = json_decode($decrypted, true);
return [$payload,$decrypted,$result,$body];
}
return [NULL,NULL,NULL,NULL];
}
unlock_pid_file($lock_file);
echo "[".date("Y-m-d H:i:s")."] ".$job_name." job complete.\n";
@@ -0,0 +1,216 @@
<?php
$job_name = pathinfo(__FILE__, PATHINFO_FILENAME);
echo "[".date("Y-m-d H:i:s")."] ".$job_name." job is starting.\n";
require('../lock.php');
$lock_file = lock_pid_file();
set_time_limit(0); // No limit!
require('../../backend.php');
require('../common/QuoteApi.php');
$httpAuthToken = $savvyext->cfgReadChar('system.oauth2_token');
$encryptionAlg = $savvyext->cfgReadChar('encryption.algorithm');
$encryptionKey = $savvyext->cfgReadChar('encryption.key');
$encryptionIV = $savvyext->cfgReadChar('encryption.iv');
$baseURL = $savvyext->cfgReadChar('system.api_url');
$db_host = $savvyext->cfgReadChar('database.host');
$db_name = $savvyext->cfgReadChar('database.name');
$db_user = $savvyext->cfgReadChar('database.user');
$db_pass = $savvyext->cfgReadChar('database.pass');
$db_port = $savvyext->cfgReadLong('database.port');
$connstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$conn = pg_connect($connstr);
$member_id = 0;
$country = 'SG';
$timezone = 'UTC';
$distance = 1.2; // km
$city_id = 1; // Singapore
$pool = 1; // Main pool - does not matter (we do not have pools here...)
$areas_count = 28;
$transport_providers = [3,4,5];
CONST SELECT_DISTINCT_AREAS = <<< EOS
WITH whole_hours AS (
SELECT hour, area_start_id, area_end_id, transport_provider_id
FROM generate_series(0, 23) hour,
generate_series(1, $1) area_start_id,
generate_series(1, $1) area_end_id,
unnest(ARRAY[3,4,5]) transport_provider_id
ORDER BY transport_provider_id, area_start_id, area_end_id, hour
)
SELECT DISTINCT ah.area_start_id as area_id FROM whole_hours ah
LEFT JOIN geofence_area_average_quotes gaaq ON ah.hour = gaaq.hour
AND ah.area_start_id = gaaq.area_start_id AND ah.area_end_id = gaaq.area_end_id AND ah.transport_provider_id =gaaq.transport_provider_id
WHERE gaaq.hour IS NULL
AND ah.hour = date_part('hour', timezone($2, now()))
UNION
SELECT DISTINCT ah.area_end_id as area_id FROM whole_hours ah
LEFT JOIN geofence_area_average_quotes gaaq ON ah.hour = gaaq.hour
AND ah.area_start_id = gaaq.area_start_id AND ah.area_end_id = gaaq.area_end_id AND ah.transport_provider_id =gaaq.transport_provider_id
WHERE gaaq.hour IS NULL
AND ah.hour = date_part('hour', timezone($2, now()))
ORDER BY area_id
EOS;
CONST SELECT_MISSED_AREAS = <<< EOS
WITH whole_hours AS (
SELECT hour, area_start_id, area_end_id, transport_provider_id
FROM generate_series(0, 23) hour,
generate_series(1, $1) area_start_id,
generate_series(1, $1) area_end_id,
unnest(ARRAY[3,4,5]) transport_provider_id
ORDER BY transport_provider_id, area_start_id, area_end_id, hour
)
SELECT DISTINCT ah.* FROM whole_hours ah
LEFT JOIN geofence_area_average_quotes gaaq ON ah.hour = gaaq.hour
AND ah.area_start_id = gaaq.area_start_id AND ah.area_end_id = gaaq.area_end_id AND ah.transport_provider_id =gaaq.transport_provider_id
WHERE gaaq.hour IS NULL
AND ah.hour = date_part('hour', timezone($2, now()))
ORDER BY ah.transport_provider_id, ah.area_start_id, ah.area_end_id, ah.hour
EOS;
$transport_providers_param = "{".implode(",", $transport_providers). "}";
$area_ids = [];
$resp = pg_query_params($conn, SELECT_DISTINCT_AREAS, [
$areas_count,
$timezone,
// $transport_providers_param
]);
if ($resp && pg_num_rows($resp)) {
while ($row=pg_fetch_row($resp)) {
$area_ids[] = $row[0];
}
}
QuoteApi::$job_name=$job_name;
if (count($area_ids)) {
// Step 1 & 2: area locations
$locations_start = [];
$locations_end = [];
$area_locations = [];
$q = "SELECT id, latitude, longitude, name, boundaries FROM geofence_area WHERE country='${country}' AND city_id=${city_id} AND district='t' AND id IN (".implode (", ", $area_ids).") ORDER BY id";
$r = pg_query($conn, $q);
if ($r && pg_num_rows($r)) {
$q1 = "select * from address where country='${country}' AND (%s) order by random() limit 2";
while ($f=pg_fetch_row($r)) {
// Singapore areas are postal!
$b = json_decode($f[4],true); // {"postal_code":["60","61","62","63","64"]}
$q2 = [];
foreach ($b["postal_code"] as $code) {
$q2[] = "LEFT(postal,".strlen($code).")='${code}'";
}
$r1 = pg_query($conn, sprintf($q1,implode(" OR ",$q2)));
if ($r1 && pg_num_rows($r1)>1 && $f1=pg_fetch_assoc($r1)) {
$locations_start[$f[0]] = $f1;
$f1 = pg_fetch_assoc($r1);
$locations_end[$f[0]] = $f1;
}
}
}
$providers_areas = [];
$resp = pg_query_params($conn, SELECT_MISSED_AREAS, [
$areas_count,
$timezone,
]);
if ($resp && pg_num_rows($resp)) {
while ($row=pg_fetch_row($resp)) {
$star_area_id = $row[1];
$end_area_id = $row[2];
$transport_provider = $row[3];
if (!array_key_exists($transport_provider,$providers_areas)) {
$providers_areas[$transport_provider] = [];
}
$d = distanceBetweenTwoGpsCoordinates(
$locations_start[$star_area_id]["latitude"], $locations_start[$star_area_id]["longitude"],
$locations_end[$end_area_id]["latitude"], $locations_end[$end_area_id]["longitude"],
"K"
);
if ($locations_start[$star_area_id]["id"] != $locations_end[$end_area_id]["id"]
&& $d > $distance || $star_area_id == $end_area_id ) {
array_push($providers_areas[$transport_provider],
[
"start_area" => $locations_start[$star_area_id],
"end_area" => $locations_end[$end_area_id]
]
);
}
}
// echo json_encode($providers_areas, JSON_PRETTY_PRINT) .PHP_EOL;
}
if (count($providers_areas) > 0) {
// Step 4: Schedule quotes
$checkQuotes = [];
foreach ($providers_areas as $provider_id => $provider_areas) {
foreach ($provider_areas as $areas) {
$origin_id = $areas["start_area"]["id"];
$destination_id = $areas["end_area"]["id"];
$origin = $areas["start_area"]["address"];
$destination = $areas["end_area"]["address"];
$pool = $provider_id == 3 ? 2 : 1;
$q = "SELECT * FROM quotes ";
$q.= " WHERE location_start_id=${origin_id} AND location_end_id=${destination_id} ";
$q.= " AND transport_provider_id=${provider_id} AND cost>0 AND pool=${pool} ";
$q.= " AND completed > (now() - '1 hour'::interval) ";
$q.= " ORDER BY completed DESC LIMIT 1";
$r = pg_query($conn, $q);
if ($r && pg_num_rows($r) && $f=pg_fetch_assoc($r)) {
echo "[".date("Y-m-d H:i:s")."] Quote ".$f["cost"]." already exists ID #".$f["id"]."\n";
continue;
}
list($res,$id) = QuoteApi::schedule_quote($origin,$destination,$country,$member_id,$provider_id, 0,'t', $pool);
if ($res>0) {
if ($res==2) {
echo "[".date("Y-m-d H:i:s")."] Quote complete! ID #${id}\n";
} else if ($res==1) {
echo "[".date("Y-m-d H:i:s")."] Scheduled quote ID #${id}\n";
$checkQuotes[] = $id;
} else {
echo "[".date("Y-m-d H:i:s")."] Unexpected result for ID #${id} ($res)\n";
}
} else {
echo "[".date("Y-m-d H:i:s")."] schedule_quote failed: ${res}.\n";
echo "[".date("Y-m-d H:i:s")."] $origin,$destination,$country,$member_id,$provider_id\n";
}
}
}
// Step 5: Check quotes
foreach ($checkQuotes as $id) {
list($res,$cost) = QuoteApi::check_quote($id);
echo "[".date("Y-m-d H:i:s")."] Checking quote ID #${id} ($res) cost=${cost}\n";
}
}
}
function distanceBetweenTwoGpsCoordinates($lat1,$lon1,$lat2,$lon2,$unit) {
//error_log("public function distanceBetweenTwoGpsCoordinates($lat1,$lon1,$lat2,$lon2,$unit)");
if (($lat1 == $lat2) && ($lon1 == $lon2)) {
return 0;
}
$theta = $lon1 - $lon2;
$dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta));
$dist = acos($dist);
$dist = rad2deg($dist);
$miles = $dist * 60 * 1.1515;
$unit = strtoupper($unit);
if ($unit == "K") {
return ($miles * 1.609344);
}
if ($unit == "N") {
($miles * 0.8684);
}
return $miles;
}
unlock_pid_file($lock_file);
echo "[".date("Y-m-d H:i:s")."] ".$job_name." job complete.\n";
+144
View File
@@ -0,0 +1,144 @@
<?php
$job_name = pathinfo(__FILE__, PATHINFO_FILENAME);
echo "[".date("Y-m-d H:i:s")."] ".$job_name." job is starting.\n";
set_time_limit(0); // No limit!
require('../../backend.php');
require('../common/QuoteApi.php');
$httpAuthToken = $savvyext->cfgReadChar('system.oauth2_token');
$encryptionAlg = $savvyext->cfgReadChar('encryption.algorithm');
$encryptionKey = $savvyext->cfgReadChar('encryption.key');
$encryptionIV = $savvyext->cfgReadChar('encryption.iv');
$baseURL = $savvyext->cfgReadChar('system.api_url');
$db_host = $savvyext->cfgReadChar('database.host');
$db_name = $savvyext->cfgReadChar('database.name');
$db_user = $savvyext->cfgReadChar('database.user');
$db_pass = $savvyext->cfgReadChar('database.pass');
$db_port = $savvyext->cfgReadLong('database.port');
$connstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$conn = pg_connect($connstr);
$country = 'SG';
$member_id = 0;
// ComfortDelGro & Gojek
$transport_providers = [4,5];
// Grab
//$transport_providers = [3];
// Step 1: Load batch files
$origins = load_batch_file("batch_quote_file_origins.txt");
$destinations = load_batch_file("batch_quote_file_destinations.txt");
// Step 2: Geocode addresses
$newOrigins = geocode_addresses($origins);
$newDestinations = geocode_addresses($destinations);
// Step 3: Schedule quotes
$checkQuotes = [];
QuoteApi::$job_name = $job_name;
foreach ($newOrigins as $origin_id=>$origin) {
foreach ($newDestinations as $destination_id=>$destination) {
foreach ($transport_providers as $transport_provider) {
$q = "SELECT * FROM quotes ";
$q.= " WHERE location_start_id=${origin_id} AND location_end_id=${destination_id} ";
$q.= " AND transport_provider_id=${transport_provider} AND cost>0 ";
$q.= " ORDER BY completed DESC LIMIT 1";
$r = pg_query($conn, $q);
if ($r && pg_num_rows($r) && $f=pg_fetch_assoc($r)) {
echo "[".date("Y-m-d H:i:s")."] Quote ".$f["cost"]." already exists ID #".$f["id"]."\n";
continue;
}
list($res,$id) = QuoteApi::schedule_quote($origin,$destination,$country,$member_id,$transport_provider);
if ($res>0) {
if ($res==2) {
echo "[".date("Y-m-d H:i:s")."] Quote complete! ID #${id}\n";
} else if ($res==1) {
echo "[".date("Y-m-d H:i:s")."] Scheduled quote ID #${id}\n";
$checkQuotes[] = $id;
} else {
echo "[".date("Y-m-d H:i:s")."] Unexpected result for ID #${id} ($res)\n";
}
} else {
echo "[".date("Y-m-d H:i:s")."] schedule_quote failed: ${res}.\n";
echo "[".date("Y-m-d H:i:s")."] $origin,$destination,$country,$member_id,$transport_provider\n";
}
}
}
}
// Step 4: Check quotes
foreach ($checkQuotes as $id) {
list($res,$cost) = QuoteApi::check_quote($id);
echo "[".date("Y-m-d H:i:s")."] Checking quote ID #${id} ($res) cost=${cost}\n";
}
function load_batch_file($filename) {
$results = [];
$fn = fopen($filename,"r");
while(! feof($fn)) {
$result = fgets($fn);
$results[] = trim($result);
}
fclose($fn);
return $results;
}
function geocode_addresses($addresses) {
$geocodedAddresses = [];
foreach ($addresses as $address) {
$params = [
"address" => $address,
"member_id" => 0,
"country" => "SG"
];
$input = http_build_query($params);
list($payload,$decrypted,$result,$body) = main_api_get('/trips/api/geocode/?',$input);
if (is_array($payload) && array_key_exists('geocode',$payload) && is_array($payload['geocode'])
&& array_key_exists('id',$payload['geocode']) && $payload['geocode']['id']>0) {
$geocodedAddresses[$payload['geocode']['id']] = $payload['geocode']['address'];
}
}
return $geocodedAddresses;
}
function main_api_get($endpoint,$input) {
global $baseURL, $encryptionAlg, $encryptionKey, $encryptionIV, $httpAuthToken;
if ($endpoint!="" && $input!="") { // minimal sanity
sleep(1);
$url = $baseURL . $endpoint . $input;
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_VERBOSE, false);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'Authorization: Server-Token ' . $httpAuthToken,
"client_id: BATCH"
)
);
$body = curl_exec($ch);
$result = json_decode($body,true);
$decrypted = openssl_decrypt(
hex2bin(
$result['payload']
),
$encryptionAlg,
$encryptionKey,
OPENSSL_RAW_DATA,
$encryptionIV
);
$payload = json_decode($decrypted, true);
return [$payload,$decrypted,$result,$body];
}
return [NULL,NULL,NULL,NULL];
}
echo "[".date("Y-m-d H:i:s")."] ".$job_name." job complete.\n";
+43
View File
@@ -0,0 +1,43 @@
<?php
$job_name = pathinfo(__FILE__, PATHINFO_FILENAME);
echo "[".date("Y-m-d H:i:s")."] ".$job_name." job is starting.\n";
set_time_limit(0); // No limit!
require('../../backend.php');
require('../common/QuoteApi.php');
$httpAuthToken = $savvyext->cfgReadChar('system.oauth2_token');
$encryptionAlg = $savvyext->cfgReadChar('encryption.algorithm');
$encryptionKey = $savvyext->cfgReadChar('encryption.key');
$encryptionIV = $savvyext->cfgReadChar('encryption.iv');
$baseURL = $savvyext->cfgReadChar('system.api_url');
$db_host = $savvyext->cfgReadChar('database.host');
$db_name = $savvyext->cfgReadChar('database.name');
$db_user = $savvyext->cfgReadChar('database.user');
$db_pass = $savvyext->cfgReadChar('database.pass');
$db_port = $savvyext->cfgReadLong('database.port');
$connstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$conn = pg_connect($connstr);
$country = 'SG';
$member_id = 0;
// ComfortDelGro & Gojek
$transport_providers = [4,5];
// Grab
$transport_providers = [3];
QuoteApi::$job_name = $job_name;
$q = "select id,automation_id from quotes where id>=11462 and id<=13761 and (cost<1 or cost is null)";
$q = "select id,automation_id from quotes where id>=11462 and id<=13761 and (cost<1 or cost is null)";
$r = pg_query($conn,$q);
while ($f=pg_fetch_assoc($r)) {
list($res,$cost) = QuoteApi::check_quote($f["id"]);
echo "[".date("Y-m-d H:i:s")."] ".$f["id"]."/".$f["automation_id"]." => ".$cost."\n";
}
echo "[".date("Y-m-d H:i:s")."] ".$job_name." job complete.\n";
@@ -0,0 +1,84 @@
Dempsey Hill, Dempsey Rd, #03-01 Blk 8D, Singapore 249679
Botanic Gardens Mansion, 18 Taman Serasi, Singapore 257722
Bandstand - Singapore Botanic Gardens, 6 Cluny Rd, Singapore 259573
Palm Valley Gate, Tyersall Rd, Singapore
Botanic Gardens Nassim Gate, 1B Cluny Rd, Singapore 259598
IKEA Alexandra, 317 Alexandra Rd, Singapore 159965
Anchorpoint Shopping Centre, 370 Alexandra Rd, Singapore 159953
ABC Brickworks, 6 Jalan Bukit Merah, Singapore 150006
Depot Road Zhen Shan Mei Claypot Laksa, 119 Bukit Merah Lane 1, #01-75 Fine Taste Eating House, Singapore 151119
Alexandra Village, 1009 Bukit Merah Lane 3, Singapore 159723
Haw Par Villa, 262 Pasir Panjang Rd, Singapore 118628
TeleTech Park, 20 Science Park Rd, Singapore 117674
Kopitiam, 1 Wholesale Centre #01-02 Blk, 1 Pasir Panjang Rd, Singapore 110001
Zenxin Organic Food Singapore @ Pasir Panjang, 14 Pasir Panjang, #01-25, Wholesale Centre, Singapore 110014
Queenstown MRT, 301 Commonwealth Ave, Singapore 149729
Mr Bean, 301 Commonwealth Ave, #02-05, Singapore 149729
Mei Ling Market & Food Centre, 159 Mei Ling St, Singapore 140159
Vivarch Enrichment Group, Cendex Centre, 120 Lower Delta Rd, #12-13, Singapore 169208
Connection One, 169 Bukit Merah Central, Singapore
Redhill Market, 81 Redhill Ln, Singapore 150081
Tiong Bahru MRT Station, 300 Tiong Bahru Rd, Singapore 168731
SAFRA Mount Faber, 2 Telok Blangah Way, Singapore 098803
LifestyleMart, 2 Telok Blangah Way, #02-07 SAFRA Mount Faber, Singapore 098803
Giant Express Telok Blangah 8, #01-171 Telok Blangah Cres, Block 8, Singapore 090008
Vivo City, 1 Harbourfront Walk, Singapore 098585
HarbourFront Centre, 2 Maritime Square, Singapore 099255
Seah Im Food Centre, 2 Seah Im Rd, Singapore 099114
Harbourlights, 66 Telok Blangah Rd, Singapore 098830
85 Redhill Ln, Singapore 150085
SIME DARBY BUSINESS CENTRE, 315 Alexandra Rd
Alexandra Hospital, 378 Alexandra Rd, Singapore 159964
Everlast @ Queensway Shopping Centre, Queensway Shopping Center #01-23, 1 Queensway, Singapore 149053
Block 79, 79 Ayer Rajah Crescent
MDIS Campus, 501 Stirling Rd, Singapore 148951
The Cheese Ark, 49 Stirling Rd, #01-489, Singapore 141049
Tanglin Halt Neighbourhood Centre Historical Marker
Sheng Siong, 88 Tanglin Halt Rd, Singapore 141088
One North Station, 9 Ayer Rajah Avenue Singapore 138647 Ayer Rajah Ave, Singapore 138647
Timbre+, 73A Ayer Rajah Crescent, JTC Launchpad, Singapore 139957
Two Chefs Eating Place, 116 Commonwealth Cres, #01-129
Dempsey Hill, Dempsey Rd, #03-01 Blk 8D, Singapore 249679
Morsels, 25, #01-04 Dempsey Rd, Singapore 249670
Huber's Butchery, 22 Dempsey Rd, Singapore 249679
Raffles Holland V Mall, 118 Holland Ave, Singapore 278973
The Nailist - Holland Road Shopping Centre, 211 Holland Avenue, Holland Rd, #03-31/32 Shopping centre, Singapore 278967
Holland Village MRT Station, 200 Holland Avenue Singapore 278995 Holland Avenue, Singapore 278995
Kai Life, Holland Avenue, 211 Holland Rd, #02-04 Shopping Centre, Singapore 278967
Sunday Folks, 44 Jln Merah Saga, #01-52 Chip Bee Gardens, Singapore 278116
Daily Scoop @ Chip Bee Garden, 70 Jln Merah Saga, 80, Singapore 278129
Holland Drive Market and Food Centre, 44 Holland Dr, Singapore 270044
Chip Bee Gardens, 43 Jln Merah Saga, Singapore 278115
My Cosy Corner, 587 Bukit Timah Rd, #02-02 Coronation Plaza, Singapore 269707
Singapore University of Social Sciences, 463 Clementi Rd, Blk C, Singapore 599494
The Grandstand, 200 Turf Club Rd, Singapore 287994
Premier Pitch Indoor, 200 Turf Club Road, Plot 9, Singapore 287994
SkyPark Arena @ King Albert Park, 896 Dunearn Rd, #05-03 Tuan Sing Holdings, Singapore 589472
Watsons Singapore, 1 Jalan Anak Bukit, Bukit Timah West, #B1-57, Singapore 588996
Anytime Fitness Bukit Timah, Upper Bukit Timah Rd, #B1-01 Shopping Centre, Singapore 588179
EQUIP, 78 Rifle Range Rd, Singapore 588384
Sime Darby Centre, 896 Dunearn Rd, Singapore 589472
Chin Huat, #01 Clementi Street 12, 30 zhizu massage centre, Singapore 120105
West Coast Plaza, 154 West Coast Rd, Singapore 127371
Sheng Siong, #01-144 Clementi West Street 2, Blk 720, Singapore 120720
McDonalds West Coast Park, 71 W Coast Ave, Singapore 126844
Ayer Rajah Food Centre, W Coast Dr, Blk 503, Singapore 120503
West Bowl Bowling, 12 W Coast Walk, Singapore 127157
The Clementi Mall, 3155 Commonwealth Ave W, Singapore 129588
Popular Bookstore, 2 Jurong East Street 21, #02-36 IMM Building, Singapore 609601
Books Kinokuniya Jurong Store, 50 Jurong Gateway Rd, #04-23 JEM, Singapore 608549
Westgate, 3 Gateway Dr, Singapore 608532
Beng Hiang Restaurant, 135 Jurong Gateway Rd, #02-337, Singapore 600135
Science Centre Singapore, 15 Science Centre Rd, Singapore 609081
IMM, 2 Jurong East Street 21, Singapore 609601
Sofzsleep, 21 Bukit Batok Cres, #24-82 Wecga Tower, Singapore 658065
1345 Mookata, 25 Bukit Batok Crescent, Singapore 658077
CopyPrinter Pte Ltd, Bukit Batok Cres, #09-04 Enterprise Center, No 20, Singapore 658080
Unity Centre, 51 Bukit Batok Cres, Singapore 658077
Acacia Lodge, 530-540 Bukit Batok Street 23, Singapore 659548
West Mall, 1 Bukit Batok Central Link, Singapore 658713
Bukit Batok MRT, 10 Bukit Batok Central, Singapore 659958
Singapore Pools (Bukit Batok Central Branch), 642 Bukit Batok Central, #01-56, Singapore 188994
McDonald's, 256 Jurong East Street 24, Singapore 600256
Yuhua Village Market and Food Centre, 254 Jurong East Street 24, Singapore 600254
Zai Shun Curry Fish Head, 253 Jurong East Street 24, #01-205, Singapore 600253
+30
View File
@@ -0,0 +1,30 @@
3 Conservatory Drive, Singapore 117376
9 Engineering Drive 1, #07-26 EA, Singapore 117575
4 Engineering Drive 3, Singapore 117583
2 Engineering Drive 4, NUS Information Technology, Singapore 117584
4 Architecture Dr, Singapore 117566 Architecture Dr, Singapore 117566
4 Engineering Drive 4, Blk E5 #02-09, Singapore 117585 Engineering Drive 4, Singapore 117585
12 Kent Ridge Cres, Singapore 119275
11 Arts Link, #03-06 AS1, Singapore 117573
3 Arts Link, Level 4 AS3, Singapore 117569
5 Arts Link Block AS7, Level 5 The, Shaw Foundation Building, Singapore 117570
9 Kent Ridge Dr, Singapore 119241
15 Computing Dr, Singapore 117418
3 Research Link, Singapore 117602
15 Kent Ridge Dr, Singapore 119245
21 Heng Mui Keng Terrace, Singapore 119613
30 Heng Mui Keng Terrace, Singapore 119614
29 Heng Mui Keng Terrace, Block D & E, Singapore 119620
11 Science Park Rd, Singapore 117685
27 Prince George's Park, National University of Singapore, Singapore 118425
15 Prince George's Park, Singapore 118414
1 Research Link, Singapore 117604
31 Lower Kent Ridge Rd, Singapore 119078
50 Kent Ridge Cres, Singapore 119279
30 Lower Kent Ridge Rd, Singapore 119075
21 Lower Kent Ridge Rd, Singapore 119077
12 Science Drive 2, Singapore 117549
10 Lower Kent Ridge Rd, Singapore 119076
28 Medical Dr, Singapore 117456
1E Kent Ridge Rd, Singapore 119228
70 South Buona Vista Rd, Singapore 118176
+147
View File
@@ -0,0 +1,147 @@
<?php
$job_name = pathinfo(__FILE__, PATHINFO_FILENAME);
echo "[".date("Y-m-d H:i:s")."] ".$job_name." job is starting.\n";
set_time_limit(0); // No limit!
require('../../backend.php');
require('../common/QuoteApi.php');
$httpAuthToken = $savvyext->cfgReadChar('system.oauth2_token');
$encryptionAlg = $savvyext->cfgReadChar('encryption.algorithm');
$encryptionKey = $savvyext->cfgReadChar('encryption.key');
$encryptionIV = $savvyext->cfgReadChar('encryption.iv');
$baseURL = $savvyext->cfgReadChar('system.api_url');
$db_host = $savvyext->cfgReadChar('database.host');
$db_name = $savvyext->cfgReadChar('database.name');
$db_user = $savvyext->cfgReadChar('database.user');
$db_pass = $savvyext->cfgReadChar('database.pass');
$db_port = $savvyext->cfgReadLong('database.port');
$connstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$conn = pg_connect($connstr);
$member_id = 0;
$country = 'SG';
$timezone = 1; // Asia/Singapore
$distance = 2; // km
$top_count = 15;
#Grab, ComfortDelGro, GOJEK
$transport_providers = [3,4,5];
$transport_providers = [4,5];
// Step 1: top 15 start locations
$locations_start = [];
$q = "SELECT COUNT(*) AS num, ROUND(b.latitude,2) AS lat, ROUND(b.longitude,2) AS lng ";
$q.= " FROM parsedemail_item a LEFT JOIN address b ON b.id=a.location_start_id ";
$q.= " WHERE b.timezone=${timezone} AND a.private='f' AND dup_id IS NULL ";
$q.= " GROUP BY b.latitude, b.longitude ORDER BY num DESC LIMIT ${top_count}";
$r = pg_query($conn, $q);
if ($r && pg_num_rows($r)) {
$q1 = "select * from address where round(latitude,2)=%0.02f and round(longitude,2)=%0.02f order by random() limit 1";
while ($f=pg_fetch_row($r)) {
$r1 = pg_query($conn, sprintf($q1,$f[1],$f[2]));
if ($r1 && pg_num_rows($r1) && $f1=pg_fetch_assoc($r1)) {
$locations_start[] = $f1;
}
}
}
// Step 2: top 15 end locations
$locations_end = [];
$q = "SELECT COUNT(*) AS num, ROUND(b.latitude,2) AS lat, ROUND(b.longitude,2) AS lng ";
$q.= " FROM parsedemail_item a LEFT JOIN address b ON b.id=a.location_end_id ";
$q.= " WHERE b.timezone=${timezone} AND a.private='f' AND dup_id IS NULL ";
$q.= " GROUP BY b.latitude, b.longitude ORDER BY num DESC LIMIT ${top_count}";
$r = pg_query($conn, $q);
if ($r && pg_num_rows($r)) {
$q1 = "select * from address where round(latitude,2)=%0.02f and round(longitude,2)=%0.02f order by random() limit 1";
while ($f=pg_fetch_row($r)) {
$r1 = pg_query($conn, sprintf($q1,$f[1],$f[2]));
if ($r1 && pg_num_rows($r1) && $f1=pg_fetch_assoc($r1)) {
$locations_end[] = $f1;
}
}
}
// Step 3: distance between locations (if makes sense to quote)
$pairs = [];
foreach ($locations_start as $location_start) {
foreach ($locations_end as $location_end) {
// Spheroid function in PHP to speed up
$d = distanceBetweenTwoGpsCoordinates(
$location_start["latitude"], $location_start["longitude"],
$location_end["latitude"], $location_end["longitude"],
"K"
);
if ($d>$distance) {
$pairs[] = [$location_start, $location_end];
}
}
}
// Step 4: Schedule quotes
$checkQuotes = [];
QuoteApi::$job_name = $job_name;
foreach ($pairs as list($location_start, $location_end)) {
$origin_id = $location_start["id"];
$destination_id = $location_end["id"];
$origin = $location_start["address"];
$destination = $location_end["address"];
foreach ($transport_providers as $transport_provider) {
$q = "SELECT * FROM quotes ";
$q.= " WHERE location_start_id=${origin_id} AND location_end_id=${destination_id} ";
$q.= " AND transport_provider_id=${transport_provider} AND cost>0 ";
$q.= " AND completed>(current_date-1) ";
$q.= " ORDER BY completed DESC LIMIT 1";
$r = pg_query($conn, $q);
if ($r && pg_num_rows($r) && $f=pg_fetch_assoc($r)) {
echo "[".date("Y-m-d H:i:s")."] Quote ".$f["cost"]." already exists ID #".$f["id"]."\n";
continue;
}
list($res,$id) = QuoteApi::schedule_quote($origin,$destination,$country,$member_id,$transport_provider);
if ($res>0) {
if ($res==2) {
echo "[".date("Y-m-d H:i:s")."] Quote complete! ID #${id}\n";
} else if ($res==1) {
echo "[".date("Y-m-d H:i:s")."] Scheduled quote ID #${id}\n";
$checkQuotes[] = $id;
} else {
echo "[".date("Y-m-d H:i:s")."] Unexpected result for ID #${id} ($res)\n";
}
} else {
echo "[".date("Y-m-d H:i:s")."] schedule_quote failed: ${res}.\n";
echo "[".date("Y-m-d H:i:s")."] $origin,$destination,$country,$member_id,$transport_provider\n";
}
}
}
// Step 5: Check quotes
foreach ($checkQuotes as $id) {
list($res,$cost) = QuoteApi::check_quote($id);
echo "[".date("Y-m-d H:i:s")."] Checking quote ID #${id} ($res) cost=${cost}\n";
}
function distanceBetweenTwoGpsCoordinates($lat1,$lon1,$lat2,$lon2,$unit) {
//error_log("public function distanceBetweenTwoGpsCoordinates($lat1,$lon1,$lat2,$lon2,$unit)");
if (($lat1 == $lat2) && ($lon1 == $lon2)) {
return 0;
}
$theta = $lon1 - $lon2;
$dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta));
$dist = acos($dist);
$dist = rad2deg($dist);
$miles = $dist * 60 * 1.1515;
$unit = strtoupper($unit);
if ($unit == "K") {
return ($miles * 1.609344);
}
if ($unit == "N") {
($miles * 0.8684);
}
return $miles;
}
echo "[".date("Y-m-d H:i:s")."] ".$job_name." job complete.\n";
@@ -0,0 +1,138 @@
<?php
$job_name = pathinfo(__FILE__, PATHINFO_FILENAME);
echo "[".date("Y-m-d H:i:s")."] ".$job_name." job is starting.\n";
require('../lock.php');
$lock_file = lock_pid_file();
set_time_limit(0); // No limit!
require('../../backend.php');
require('../common/QuoteApi.php');
$httpAuthToken = $savvyext->cfgReadChar('system.oauth2_token');
$encryptionAlg = $savvyext->cfgReadChar('encryption.algorithm');
$encryptionKey = $savvyext->cfgReadChar('encryption.key');
$encryptionIV = $savvyext->cfgReadChar('encryption.iv');
$baseURL = $savvyext->cfgReadChar('system.api_url');
$db_host = $savvyext->cfgReadChar('database.host');
$db_name = $savvyext->cfgReadChar('database.name');
$db_user = $savvyext->cfgReadChar('database.user');
$db_pass = $savvyext->cfgReadChar('database.pass');
$db_port = $savvyext->cfgReadLong('database.port');
$connstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$conn = pg_connect($connstr);
$member_id = 0;
$country = 'US';
$timezone = 2; // America/Los_Angeles
$distance = 2; // km
$city_id = 1096; // San Francisco
$pool = 2; // Dedicated pool
$transport_providers = [1,2]; // Uber, Lyft
// Step 1: start locations
$locations_start = [];
$q = "SELECT id,latitude,longitude,name FROM geofence_area WHERE country='${country}' AND city_id=${city_id} AND district='t' ORDER BY id";
$r = pg_query($conn, $q);
if ($r && pg_num_rows($r)) {
$q1 = "select * from address where round(latitude,2)=%0.02f and round(longitude,2)=%0.02f order by random() limit 1";
while ($f=pg_fetch_row($r)) {
$r1 = pg_query($conn, sprintf($q1,$f[1],$f[2]));
if ($r1 && pg_num_rows($r1) && $f1=pg_fetch_assoc($r1)) {
$locations_start[$f[0].'_'.$f[3]] = $f1;
}
}
}
// Step 2: end locations
$locations_end = $locations_start;
// Step 3: distance between locations (if makes sense to quote)
$pairs = [];
foreach ($locations_start as $location_start) {
foreach ($locations_end as $location_end) {
// Spheroid function in PHP to speed up
$d = distanceBetweenTwoGpsCoordinates(
$location_start["latitude"], $location_start["longitude"],
$location_end["latitude"], $location_end["longitude"],
"K"
);
/* if ($d>$distance) {
$pairs[] = [$location_start, $location_end];
}//*/
if ($location_start["id"]!=$location_end["id"]) {
$pairs[] = [$location_start, $location_end];
}
}
}
// Step 4: Schedule quotes
$checkQuotes = [];
QuoteApi::$job_name=$job_name;
foreach ($pairs as list($location_start, $location_end)) {
$origin_id = $location_start["id"];
$destination_id = $location_end["id"];
$origin = $location_start["address"];
$destination = $location_end["address"];
foreach ($transport_providers as $transport_provider) {
$q = "SELECT * FROM quotes ";
$q.= " WHERE location_start_id=${origin_id} AND location_end_id=${destination_id} ";
$q.= " AND transport_provider_id=${transport_provider} AND cost>0 AND pool=${pool}";
//$q.= " AND completed>(current_date-1) ";
$q.= " AND completed>(now() - '1 hour'::interval) ";
$q.= " ORDER BY completed DESC LIMIT 1";
$r = pg_query($conn, $q);
if ($r && pg_num_rows($r) && $f=pg_fetch_assoc($r)) {
echo "[".date("Y-m-d H:i:s")."] Quote ".$f["cost"]." already exists ID #".$f["id"]."\n";
continue;
}
list($res,$id) = QuoteApi::schedule_quote($origin,$destination,$country,$member_id,$transport_provider, 0,'t',$pool);
if ($res>0) {
if ($res==2) {
echo "[".date("Y-m-d H:i:s")."] Quote complete! ID #${id}\n";
} else if ($res==1) {
echo "[".date("Y-m-d H:i:s")."] Scheduled quote ID #${id}\n";
$checkQuotes[] = $id;
} else {
echo "[".date("Y-m-d H:i:s")."] Unexpected result for ID #${id} ($res)\n";
}
} else {
echo "[".date("Y-m-d H:i:s")."] schedule_quote failed: ${res}.\n";
echo "[".date("Y-m-d H:i:s")."] $origin,$destination,$country,$member_id,$transport_provider\n";
}
}
}
// Step 5: Check quotes
foreach ($checkQuotes as $id) {
list($res,$cost) = QuoteApi::check_quote($id);
echo "[".date("Y-m-d H:i:s")."] Checking quote ID #${id} ($res) cost=${cost}\n";
}
function distanceBetweenTwoGpsCoordinates($lat1,$lon1,$lat2,$lon2,$unit) {
//error_log("public function distanceBetweenTwoGpsCoordinates($lat1,$lon1,$lat2,$lon2,$unit)");
if (($lat1 == $lat2) && ($lon1 == $lon2)) {
return 0;
}
$theta = $lon1 - $lon2;
$dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta));
$dist = acos($dist);
$dist = rad2deg($dist);
$miles = $dist * 60 * 1.1515;
$unit = strtoupper($unit);
if ($unit == "K") {
return ($miles * 1.609344);
}
if ($unit == "N") {
($miles * 0.8684);
}
return $miles;
}
unlock_pid_file($lock_file);
echo "[".date("Y-m-d H:i:s")."] ".$job_name." job complete.\n";
@@ -0,0 +1,138 @@
<?php
$job_name = pathinfo(__FILE__, PATHINFO_FILENAME);
echo "[".date("Y-m-d H:i:s")."] ".$job_name." job is starting.\n";
require('../lock.php');
$lock_file = lock_pid_file();
set_time_limit(0); // No limit!
require('../../backend.php');
require('../common/QuoteApi.php');
$httpAuthToken = $savvyext->cfgReadChar('system.oauth2_token');
$encryptionAlg = $savvyext->cfgReadChar('encryption.algorithm');
$encryptionKey = $savvyext->cfgReadChar('encryption.key');
$encryptionIV = $savvyext->cfgReadChar('encryption.iv');
$baseURL = $savvyext->cfgReadChar('system.api_url');
$db_host = $savvyext->cfgReadChar('database.host');
$db_name = $savvyext->cfgReadChar('database.name');
$db_user = $savvyext->cfgReadChar('database.user');
$db_pass = $savvyext->cfgReadChar('database.pass');
$db_port = $savvyext->cfgReadLong('database.port');
$connstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$conn = pg_connect($connstr);
$member_id = 0;
$country = 'US';
$timezone = 2; // America/Los_Angeles
$distance = 2; // km
$city_id = 1096; // San Francisco
$pool = 2; // Dedicated pool
$transport_providers = [8]; // Autocab
// Step 1: start locations
$locations_start = [];
$q = "SELECT id,latitude,longitude,name FROM geofence_area WHERE country='${country}' AND city_id=${city_id} AND district='t' ORDER BY id";
$r = pg_query($conn, $q);
if ($r && pg_num_rows($r)) {
$q1 = "select * from address where round(latitude,2)=%0.02f and round(longitude,2)=%0.02f order by random() limit 1";
while ($f=pg_fetch_row($r)) {
$r1 = pg_query($conn, sprintf($q1,$f[1],$f[2]));
if ($r1 && pg_num_rows($r1) && $f1=pg_fetch_assoc($r1)) {
$locations_start[$f[0].'_'.$f[3]] = $f1;
}
}
}
// Step 2: end locations
$locations_end = $locations_start;
// Step 3: distance between locations (if makes sense to quote)
$pairs = [];
foreach ($locations_start as $location_start) {
foreach ($locations_end as $location_end) {
// Spheroid function in PHP to speed up
$d = distanceBetweenTwoGpsCoordinates(
$location_start["latitude"], $location_start["longitude"],
$location_end["latitude"], $location_end["longitude"],
"K"
);
/* if ($d>$distance) {
$pairs[] = [$location_start, $location_end];
}//*/
if ($location_start["id"]!=$location_end["id"]) {
$pairs[] = [$location_start, $location_end];
}
}
}
// Step 4: Schedule quotes
$checkQuotes = [];
QuoteApi::$job_name=$job_name;
foreach ($pairs as list($location_start, $location_end)) {
$origin_id = $location_start["id"];
$destination_id = $location_end["id"];
$origin = $location_start["address"];
$destination = $location_end["address"];
foreach ($transport_providers as $transport_provider) {
$q = "SELECT * FROM quotes ";
$q.= " WHERE location_start_id=${origin_id} AND location_end_id=${destination_id} ";
$q.= " AND transport_provider_id=${transport_provider} AND cost>0 AND pool=${pool}";
//$q.= " AND completed>(current_date-1) ";
$q.= " AND completed>(now() - '1 hour'::interval) ";
$q.= " ORDER BY completed DESC LIMIT 1";
$r = pg_query($conn, $q);
if ($r && pg_num_rows($r) && $f=pg_fetch_assoc($r)) {
echo "[".date("Y-m-d H:i:s")."] Quote ".$f["cost"]." already exists ID #".$f["id"]."\n";
continue;
}
list($res,$id) = QuoteApi::schedule_quote($origin,$destination,$country,$member_id,$transport_provider, 0,'t',$pool);
if ($res>0) {
if ($res==2) {
echo "[".date("Y-m-d H:i:s")."] Quote complete! ID #${id}\n";
} else if ($res==1) {
echo "[".date("Y-m-d H:i:s")."] Scheduled quote ID #${id}\n";
$checkQuotes[] = $id;
} else {
echo "[".date("Y-m-d H:i:s")."] Unexpected result for ID #${id} ($res)\n";
}
} else {
echo "[".date("Y-m-d H:i:s")."] schedule_quote failed: ${res}.\n";
echo "[".date("Y-m-d H:i:s")."] $origin,$destination,$country,$member_id,$transport_provider\n";
}
}
}
// Step 5: Check quotes
foreach ($checkQuotes as $id) {
list($res,$cost) = QuoteApi::check_quote($id);
echo "[".date("Y-m-d H:i:s")."] Checking quote ID #${id} ($res) cost=${cost}\n";
}
function distanceBetweenTwoGpsCoordinates($lat1,$lon1,$lat2,$lon2,$unit) {
//error_log("public function distanceBetweenTwoGpsCoordinates($lat1,$lon1,$lat2,$lon2,$unit)");
if (($lat1 == $lat2) && ($lon1 == $lon2)) {
return 0;
}
$theta = $lon1 - $lon2;
$dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta));
$dist = acos($dist);
$dist = rad2deg($dist);
$miles = $dist * 60 * 1.1515;
$unit = strtoupper($unit);
if ($unit == "K") {
return ($miles * 1.609344);
}
if ($unit == "N") {
($miles * 0.8684);
}
return $miles;
}
unlock_pid_file($lock_file);
echo "[".date("Y-m-d H:i:s")."] ".$job_name." job complete.\n";
@@ -0,0 +1,142 @@
<?php
$job_name = pathinfo(__FILE__, PATHINFO_FILENAME);
echo "[".date("Y-m-d H:i:s")."] ".$job_name." job is starting.\n";
require('../lock.php');
$lock_file = lock_pid_file();
set_time_limit(0); // No limit!
require('../../backend.php');
require('../common/QuoteApi.php');
$httpAuthToken = $savvyext->cfgReadChar('system.oauth2_token');
$encryptionAlg = $savvyext->cfgReadChar('encryption.algorithm');
$encryptionKey = $savvyext->cfgReadChar('encryption.key');
$encryptionIV = $savvyext->cfgReadChar('encryption.iv');
$baseURL = $savvyext->cfgReadChar('system.api_url');
$db_host = $savvyext->cfgReadChar('database.host');
$db_name = $savvyext->cfgReadChar('database.name');
$db_user = $savvyext->cfgReadChar('database.user');
$db_pass = $savvyext->cfgReadChar('database.pass');
$db_port = $savvyext->cfgReadLong('database.port');
$connstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$conn = pg_connect($connstr);
$member_id = 0;
$country = 'SG';
$timezone = 1; // Asia/Singapore
$distance = 1.2; // km
$city_id = 1; // Singapore
$pool = 1; // Main pool - does not matter (we do not have pools here...)
//$transport_providers = [3,4,5]; // Grab, ComfortDelGro, Gojek
$transport_providers = [4,5]; // ComfortDelGro, Gojek
// Step 1 & 2: start & end locations
$locations_start = [];
$locations_end = [];
$q = "SELECT id,latitude,longitude,name,boundaries FROM geofence_area WHERE country='${country}' AND city_id=${city_id} AND district='t' ORDER BY id";
$r = pg_query($conn, $q);
if ($r && pg_num_rows($r)) {
$q1 = "select * from address where country='${country}' AND (%s) order by random() limit 2";
while ($f=pg_fetch_row($r)) {
// Singapore areas are postal!
$b = json_decode($f[4],true); // {"postal_code":["60","61","62","63","64"]}
$q2 = [];
foreach ($b["postal_code"] as $code) {
$q2[] = "LEFT(postal,".strlen($code).")='${code}'";
}
$r1 = pg_query($conn, sprintf($q1,implode(" OR ",$q2)));
if ($r1 && pg_num_rows($r1)>1 && $f1=pg_fetch_assoc($r1)) {
$locations_start[$f[0].'_'.$f[3]] = $f1;
$f1 = pg_fetch_assoc($r1);
$locations_end[$f[0].'_'.$f[3]] = $f1;
}
}
}
// Step 3: distance between locations (if makes sense to quote)
$pairs = [];
foreach ($locations_start as $location_start) {
foreach ($locations_end as $location_end) {
// Spheroid function in PHP to speed up
$d = distanceBetweenTwoGpsCoordinates(
$location_start["latitude"], $location_start["longitude"],
$location_end["latitude"], $location_end["longitude"],
"K"
);
/* if ($d>$distance) {
$pairs[] = [$location_start, $location_end];
}//*/
if ($location_start["id"]!=$location_end["id"] && $d>$distance) {
$pairs[] = [$location_start, $location_end];
}
}
}
// Step 4: Schedule quotes
$checkQuotes = [];
QuoteApi::$job_name = $job_name;
foreach ($pairs as list($location_start, $location_end)) {
$origin_id = $location_start["id"];
$destination_id = $location_end["id"];
$origin = $location_start["address"];
$destination = $location_end["address"];
foreach ($transport_providers as $transport_provider) {
$q = "SELECT * FROM quotes ";
$q.= " WHERE location_start_id=${origin_id} AND location_end_id=${destination_id} ";
$q.= " AND transport_provider_id=${transport_provider} AND cost>0 AND pool=${pool}";
//$q.= " AND completed>(current_date-1) ";
$q.= " AND completed>(now() - '1 hour'::interval) ";
$q.= " ORDER BY completed DESC LIMIT 1";
$r = pg_query($conn, $q);
if ($r && pg_num_rows($r) && $f=pg_fetch_assoc($r)) {
echo "[".date("Y-m-d H:i:s")."] Quote ".$f["cost"]." already exists ID #".$f["id"]."\n";
continue;
}
list($res,$id) = QuoteApi::schedule_quote($origin,$destination,$country,$member_id,$transport_provider, 0,'t', $pool);
if ($res>0) {
if ($res==2) {
echo "[".date("Y-m-d H:i:s")."] Quote complete! ID #${id}\n";
} else if ($res==1) {
echo "[".date("Y-m-d H:i:s")."] Scheduled quote ID #${id}\n";
$checkQuotes[] = $id;
} else {
echo "[".date("Y-m-d H:i:s")."] Unexpected result for ID #${id} ($res)\n";
}
} else {
echo "[".date("Y-m-d H:i:s")."] schedule_quote failed: ${res}.\n";
echo "[".date("Y-m-d H:i:s")."] $origin,$destination,$country,$member_id,$transport_provider\n";
}
}
}
// Step 5: Check quotes
foreach ($checkQuotes as $id) {
list($res,$cost) = QuoteApi::check_quote($id);
echo "[".date("Y-m-d H:i:s")."] Checking quote ID #${id} ($res) cost=${cost}\n";
}
function distanceBetweenTwoGpsCoordinates($lat1,$lon1,$lat2,$lon2,$unit) {
//error_log("public function distanceBetweenTwoGpsCoordinates($lat1,$lon1,$lat2,$lon2,$unit)");
if (($lat1 == $lat2) && ($lon1 == $lon2)) {
return 0;
}
$theta = $lon1 - $lon2;
$dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta));
$dist = acos($dist);
$dist = rad2deg($dist);
$miles = $dist * 60 * 1.1515;
$unit = strtoupper($unit);
if ($unit == "K") {
return ($miles * 1.609344);
}
if ($unit == "N") {
($miles * 0.8684);
}
return $miles;
}
unlock_pid_file($lock_file);
echo "[".date("Y-m-d H:i:s")."] ".$job_name." job complete.\n";
@@ -0,0 +1,145 @@
<?php
$job_name = pathinfo(__FILE__, PATHINFO_FILENAME);
echo "[".date("Y-m-d H:i:s")."] ".$job_name." job is starting.\n";
require('../lock.php');
$lock_file = lock_pid_file();
set_time_limit(0); // No limit!
require('../../backend.php');
require('../common/QuoteApi.php');
$httpAuthToken = $savvyext->cfgReadChar('system.oauth2_token');
$encryptionAlg = $savvyext->cfgReadChar('encryption.algorithm');
$encryptionKey = $savvyext->cfgReadChar('encryption.key');
$encryptionIV = $savvyext->cfgReadChar('encryption.iv');
$baseURL = $savvyext->cfgReadChar('system.api_url');
$db_host = $savvyext->cfgReadChar('database.host');
$db_name = $savvyext->cfgReadChar('database.name');
$db_user = $savvyext->cfgReadChar('database.user');
$db_pass = $savvyext->cfgReadChar('database.pass');
$db_port = $savvyext->cfgReadLong('database.port');
$connstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$conn = pg_connect($connstr);
$member_id = 0;
$country = 'SG';
$timezone = 1; // Asia/Singapore
$distance = 1.2; // km
$city_id = 1; // Singapore
$pool = 2; // Second pool
$transport_providers = [3]; // Grab
// Step 1 & 2: start & end locations
$locations_start = [];
$locations_end = [];
$q = "SELECT id,latitude,longitude,name,boundaries FROM geofence_area WHERE country='${country}' AND city_id=${city_id} AND district='t' ORDER BY id";
$r = pg_query($conn, $q);
if ($r && pg_num_rows($r)) {
$q1 = "select * from address where country='${country}' AND (%s) order by random() limit 2";
while ($f=pg_fetch_row($r)) {
// Singapore areas are postal!
$b = json_decode($f[4],true); // {"postal_code":["60","61","62","63","64"]}
$q2 = [];
foreach ($b["postal_code"] as $code) {
$q2[] = "LEFT(postal,".strlen($code).")='${code}'";
}
$r1 = pg_query($conn, sprintf($q1,implode(" OR ",$q2)));
if ($r1 && pg_num_rows($r1)>1 && $f1=pg_fetch_assoc($r1)) {
$locations_start[$f[0].'_'.$f[3]] = $f1;
$f1 = pg_fetch_assoc($r1);
$locations_end[$f[0].'_'.$f[3]] = $f1;
}
}
}
// Step 3: distance between locations (if makes sense to quote)
$pairs = [];
foreach ($locations_start as $location_start) {
foreach ($locations_end as $location_end) {
// Spheroid function in PHP to speed up
$d = distanceBetweenTwoGpsCoordinates(
$location_start["latitude"], $location_start["longitude"],
$location_end["latitude"], $location_end["longitude"],
"K"
);
/* if ($d>$distance) {
$pairs[] = [$location_start, $location_end];
}//*/
if ($location_start["id"]!=$location_end["id"] && $d>$distance) {
$pairs[] = [$location_start, $location_end];
}
}
}
// Step 4: Schedule quotes
$checkQuotes = [];
QuoteApi::$job_name=$job_name;
foreach ($pairs as list($location_start, $location_end)) {
$origin_id = $location_start["id"];
$destination_id = $location_end["id"];
$origin = $location_start["address"];
$destination = $location_end["address"];
foreach ($transport_providers as $transport_provider) {
$q = "SELECT * FROM quotes ";
$q.= " WHERE location_start_id=${origin_id} AND location_end_id=${destination_id} ";
$q.= " AND transport_provider_id=${transport_provider} AND cost>0 AND pool=${pool}";
//$q.= " AND completed>(current_date-1) ";
$q.= " AND completed>(now() - '1 hour'::interval) ";
$q.= " ORDER BY completed DESC LIMIT 1";
$r = pg_query($conn, $q);
if ($r && pg_num_rows($r) && $f=pg_fetch_assoc($r)) {
echo "[".date("Y-m-d H:i:s")."] Quote ".$f["cost"]." already exists ID #".$f["id"]."\n";
continue;
}
list($res,$id) = QuoteApi::schedule_quote($origin,$destination,$country,$member_id,$transport_provider,0,'t',$pool);
if ($res>0) {
if ($res==2) {
echo "[".date("Y-m-d H:i:s")."] Quote complete! ID #${id}\n";
} else if ($res==1) {
echo "[".date("Y-m-d H:i:s")."] Scheduled quote ID #${id}\n";
$checkQuotes[] = $id;
} else {
echo "[".date("Y-m-d H:i:s")."] Unexpected result for ID #${id} ($res)\n";
}
} else {
echo "[".date("Y-m-d H:i:s")."] schedule_quote failed: ${res}.\n";
echo "[".date("Y-m-d H:i:s")."] $origin,$destination,$country,$member_id,$transport_provider\n";
}
}
}
// Step 5: Check quotes
foreach ($checkQuotes as $id) {
list($res,$cost) = QuoteApi::check_quote($id);
echo "[".date("Y-m-d H:i:s")."] Checking quote ID #${id} ($res) cost=${cost}\n";
}
function distanceBetweenTwoGpsCoordinates($lat1,$lon1,$lat2,$lon2,$unit) {
//error_log("public function distanceBetweenTwoGpsCoordinates($lat1,$lon1,$lat2,$lon2,$unit)");
if (($lat1 == $lat2) && ($lon1 == $lon2)) {
return 0;
}
$theta = $lon1 - $lon2;
$dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta));
$dist = acos($dist);
$dist = rad2deg($dist);
$miles = $dist * 60 * 1.1515;
$unit = strtoupper($unit);
if ($unit == "K") {
return ($miles * 1.609344);
}
if ($unit == "N") {
($miles * 0.8684);
}
return $miles;
}
unlock_pid_file($lock_file);
echo "[".date("Y-m-d H:i:s")."] batch_quote_singapore_districts job complete.\n";
+89
View File
@@ -0,0 +1,89 @@
<?php
$job_name = pathinfo(__FILE__, PATHINFO_FILENAME);
echo "[".date("Y-m-d H:i:s")."] ".$job_name." job is starting.\n";
set_time_limit(0); // No limit!
require('../../backend.php');
require('../common/QuoteApi.php');
$httpAuthToken = $savvyext->cfgReadChar('system.oauth2_token');
$encryptionAlg = $savvyext->cfgReadChar('encryption.algorithm');
$encryptionKey = $savvyext->cfgReadChar('encryption.key');
$encryptionIV = $savvyext->cfgReadChar('encryption.iv');
$baseURL = $savvyext->cfgReadChar('system.api_url');
$db_host = $savvyext->cfgReadChar('database.host');
$db_name = $savvyext->cfgReadChar('database.name');
$db_user = $savvyext->cfgReadChar('database.user');
$db_pass = $savvyext->cfgReadChar('database.pass');
$db_port = $savvyext->cfgReadLong('database.port');
$connstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$conn = pg_connect($connstr);
$country = 'SG';
$member_id = 0;
// Grab, ComfortDelGro & Gojek
$transport_providers = [/*3,*/4,5];
// Step 1: Load trips
$q = "select b.*,c.address AS origin, d.address AS destination ";
$q.= " from (select root_id,count(*) as count from trip_price_comparison where root_type=1 group by root_id) as a, ";
$q.= " parsedemail_item b, address c, address d ";
$q.= " where a.count=1 and b.id=a.root_id and b.private='f' and c.id=b.location_start_id and d.id=b.location_end_id and c.country='${country}' ";
$q.= " and b.dup_id is null ";
$q.= " order by b.travel_date desc";
echo $q."\n";
//exit();
$r = pg_query($conn, $q);
// Step 3: Schedule quotes
$checkQuotes = [];
QuoteApi::$job_name=$job_name;
if ($r && pg_num_rows($r)) {
$n = pg_num_rows($r);
echo "[".date("Y-m-d H:i:s")."] Processing ".$n." trips.\n";
$i = 0;
while ($f = pg_fetch_assoc($r)) {
$i++;
echo "[".date("Y-m-d H:i:s")."] Processing ${i}/${n} (".sprintf("%0.02f",100.0*$i/$n).") trip id=".$f["id"].".\n";
if ($f["location_start_id"]==$f["location_end_id"]) continue;
$location_start_id=$f["location_start_id"];
$location_end_id=$f["location_end_id"];
foreach ($transport_providers as $transport_provider) {
$q = "SELECT * FROM quotes ";
$q.= " WHERE location_start_id=${location_start_id} AND location_end_id=${location_end_id} ";
$q.= " AND transport_provider_id=${transport_provider} AND cost>0 ";
$q.= " AND completed>(current_date-1) ORDER BY completed DESC LIMIT 1";
$quotes = pg_query($conn, $q);
if ($quotes && pg_num_rows($quotes) && $quote=pg_fetch_assoc($quotes)) {
echo "[".date("Y-m-d H:i:s")."] Quote ".$quote["cost"]." already exists ID #".$quote["id"]."\n";
continue;
}
list($res,$id) = QuoteApi::schedule_quote($f["origin"],$f["destination"],$country,$member_id,$transport_provider);
if ($res>0) {
if ($res==2) {
echo "[".date("Y-m-d H:i:s")."] Quote complete! ID #${id}\n";
} else if ($res==1) {
echo "[".date("Y-m-d H:i:s")."] Scheduled quote ID #${id}\n";
$checkQuotes[] = $id;
} else {
echo "[".date("Y-m-d H:i:s")."] Unexpected result for ID #${id} ($res)\n";
}
} else {
echo "[".date("Y-m-d H:i:s")."] schedule_quote failed: ${res}.\n";
echo "[".date("Y-m-d H:i:s")."] $origin,$destination,$country,$member_id,$transport_provider\n";
}
}
}
}
// Step 4: Check quotes
foreach ($checkQuotes as $id) {
list($res,$cost) = QuoteApi::check_quote($id);
echo "[".date("Y-m-d H:i:s")."] Checking quote ID #${id} ($res) cost=${cost}\n";
}
echo "[".date("Y-m-d H:i:s")."] ".$job_name." job complete.\n";
+86
View File
@@ -0,0 +1,86 @@
<?php
$job_name = pathinfo(__FILE__, PATHINFO_FILENAME);
echo "[".date("Y-m-d H:i:s")."] ".$job_name." job is starting.\n";
set_time_limit(0); // No limit!
require('../../backend.php');
require('../common/QuoteApi.php');
$httpAuthToken = $savvyext->cfgReadChar('system.oauth2_token');
$encryptionAlg = $savvyext->cfgReadChar('encryption.algorithm');
$encryptionKey = $savvyext->cfgReadChar('encryption.key');
$encryptionIV = $savvyext->cfgReadChar('encryption.iv');
$baseURL = $savvyext->cfgReadChar('system.api_url');
$db_host = $savvyext->cfgReadChar('database.host');
$db_name = $savvyext->cfgReadChar('database.name');
$db_user = $savvyext->cfgReadChar('database.user');
$db_pass = $savvyext->cfgReadChar('database.pass');
$db_port = $savvyext->cfgReadLong('database.port');
$connstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$conn = pg_connect($connstr);
$country = 'US';
$member_id = 0;
// Uber & Lyft
$transport_providers = [1,2];
// Step 1: Load trips
$q = "select b.*,c.address AS origin, d.address AS destination ";
$q.= " from (select root_id,count(*) as count from trip_price_comparison where root_type=1 group by root_id) as a, ";
$q.= " parsedemail_item b, address c, address d ";
$q.= " where a.count=1 and b.id=a.root_id and b.private='f' and c.id=b.location_start_id and d.id=b.location_end_id and c.country='${country}' ";
$q.= " and b.dup_id is null ";
$q.= " order by b.travel_date desc";
$r = pg_query($conn, $q);
// Step 3: Schedule quotes
$checkQuotes = [];
QuoteApi::$job_name = $job_name;
if ($r && pg_num_rows($r)) {
$n = pg_num_rows($r);
echo "[".date("Y-m-d H:i:s")."] Processing ".$n." trips.\n";
$i = 0;
while ($f = pg_fetch_assoc($r)) {
$i++;
echo "[".date("Y-m-d H:i:s")."] Processing ${i}/${n} (".sprintf("%0.02f",100.0*$i/$n).") trip id=".$f["id"].".\n";
if ($f["location_start_id"]==$f["location_end_id"]) continue;
$location_start_id=$f["location_start_id"];
$location_end_id=$f["location_end_id"];
foreach ($transport_providers as $transport_provider) {
$q = "SELECT * FROM quotes ";
$q.= " WHERE location_start_id=${location_start_id} AND location_end_id=${location_end_id} ";
$q.= " AND transport_provider_id=${transport_provider} AND cost>0 ";
$q.= " AND completed>(current_date-1) ORDER BY completed DESC LIMIT 1";
$quotes = pg_query($conn, $q);
if ($quotes && pg_num_rows($quotes) && $quote=pg_fetch_assoc($quotes)) {
echo "[".date("Y-m-d H:i:s")."] Quote ".$quote["cost"]." already exists ID #".$quote["id"]."\n";
continue;
}
list($res,$id) = QuoteApi::schedule_quote($f["origin"],$f["destination"],$country,$member_id,$transport_provider);
if ($res>0) {
if ($res==2) {
echo "[".date("Y-m-d H:i:s")."] Quote complete! ID #${id}\n";
} else if ($res==1) {
echo "[".date("Y-m-d H:i:s")."] Scheduled quote ID #${id}\n";
$checkQuotes[] = $id;
} else {
echo "[".date("Y-m-d H:i:s")."] Unexpected result for ID #${id} ($res)\n";
}
} else {
echo "[".date("Y-m-d H:i:s")."] schedule_quote failed: ${res}.\n";
echo "[".date("Y-m-d H:i:s")."] $origin,$destination,$country,$member_id,$transport_provider\n";
}
}
}
}
// Step 4: Check quotes
foreach ($checkQuotes as $id) {
list($res,$cost) = QuoteApi::check_quote($id);
echo "[".date("Y-m-d H:i:s")."] Checking quote ID #${id} ($res) cost=${cost}\n";
}
echo "[".date("Y-m-d H:i:s")."] ".$job_name." job complete.\n";
@@ -0,0 +1,145 @@
<?php
$job_name = pathinfo(__FILE__, PATHINFO_FILENAME);
echo "[".date("Y-m-d H:i:s")."] ".$job_name." job is starting.\n";
set_time_limit(0); // No limit!
require('../../backend.php');
require('../common/QuoteApi.php');
$httpAuthToken = $savvyext->cfgReadChar('system.oauth2_token');
$encryptionAlg = $savvyext->cfgReadChar('encryption.algorithm');
$encryptionKey = $savvyext->cfgReadChar('encryption.key');
$encryptionIV = $savvyext->cfgReadChar('encryption.iv');
$baseURL = $savvyext->cfgReadChar('system.api_url');
$db_host = $savvyext->cfgReadChar('database.host');
$db_name = $savvyext->cfgReadChar('database.name');
$db_user = $savvyext->cfgReadChar('database.user');
$db_pass = $savvyext->cfgReadChar('database.pass');
$db_port = $savvyext->cfgReadLong('database.port');
$connstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$conn = pg_connect($connstr);
$country = 'SG';
$member_id = 0;
// Grab, ComfortDelGro & Gojek
$transport_providers = [/*3,*/4,5];
// Step 1: Load batch file
$attractions = load_batch_file("batch_quote_tourist_attractions.txt");
// Step 2: Geocode addresses
$newOrigins = geocode_addresses($attractions);
// Step 3: Schedule quotes
$checkQuotes = [];
QuoteApi::$job_name = $job_name;
foreach ($newOrigins as $origin_id=>$origin) {
foreach ($newOrigins as $destination_id=>$destination) {
if ($origin_id==$destination_id) continue;
foreach ($transport_providers as $transport_provider) {
$q = "SELECT * FROM quotes ";
$q.= " WHERE location_start_id=${origin_id} AND location_end_id=${destination_id} ";
$q.= " AND transport_provider_id=${transport_provider} AND cost>0 ";
$q.= " AND completed>(current_date-1) ORDER BY completed DESC LIMIT 1";
$r = pg_query($conn, $q);
if ($r && pg_num_rows($r) && $f=pg_fetch_assoc($r)) {
echo "[".date("Y-m-d H:i:s")."] Quote ".$f["cost"]." already exists ID #".$f["id"]."\n";
continue;
}
list($res,$id) = QuoteApi::schedule_quote($origin,$destination,$country,$member_id,$transport_provider);
if ($res>0) {
if ($res==2) {
echo "[".date("Y-m-d H:i:s")."] Quote complete! ID #${id}\n";
} else if ($res==1) {
echo "[".date("Y-m-d H:i:s")."] Scheduled quote ID #${id}\n";
$checkQuotes[] = $id;
} else {
echo "[".date("Y-m-d H:i:s")."] Unexpected result for ID #${id} ($res)\n";
}
} else {
echo "[".date("Y-m-d H:i:s")."] schedule_quote failed: ${res}.\n";
echo "[".date("Y-m-d H:i:s")."] $origin,$destination,$country,$member_id,$transport_provider\n";
}
}
}
}
// Step 4: Check quotes
foreach ($checkQuotes as $id) {
list($res,$cost) = QuoteApi::check_quote($id);
echo "[".date("Y-m-d H:i:s")."] Checking quote ID #${id} ($res) cost=${cost}\n";
}
function load_batch_file($filename) {
$results = [];
$fn = fopen($filename,"r");
while(! feof($fn)) {
$result = fgets($fn);
$results[strtok($result,"\t")] = trim(strtok("\t"));
}
fclose($fn);
return $results;
}
function geocode_addresses($addresses) {
global $conn;
$geocodedAddresses = [];
foreach ($addresses as $desc=>$address) {
$params = [
"address" => $address,
"member_id" => 0,
"country" => "SG"
];
$input = http_build_query($params);
list($payload,$decrypted,$result,$body) = main_api_get('/trips/api/geocode/?',$input);
if (is_array($payload) && array_key_exists('geocode',$payload) && is_array($payload['geocode'])
&& array_key_exists('id',$payload['geocode']) && $payload['geocode']['id']>0) {
$geocodedAddresses[$payload['geocode']['id']] = $payload['geocode']['address'];
$q = "INSERT INTO tourist_attraction (attraction,address_id) VALUES('".pg_escape_string($desc)."',".$payload["geocode"]["id"].")";
$r = pg_query($conn,$q);
}
}
return $geocodedAddresses;
}
function main_api_get($endpoint,$input) {
global $baseURL, $encryptionAlg, $encryptionKey, $encryptionIV, $httpAuthToken;
if ($endpoint!="" && $input!="") { // minimal sanity
sleep(1);
$url = $baseURL . $endpoint . $input;
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_VERBOSE, false);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'Authorization: Server-Token ' . $httpAuthToken,
"client_id: BATCH"
)
);
$body = curl_exec($ch);
$result = json_decode($body,true);
$decrypted = openssl_decrypt(
hex2bin(
$result['payload']
),
$encryptionAlg,
$encryptionKey,
OPENSSL_RAW_DATA,
$encryptionIV
);
$payload = json_decode($decrypted, true);
return [$payload,$decrypted,$result,$body];
}
return [NULL,NULL,NULL,NULL];
}
echo "[".date("Y-m-d H:i:s")."] ".$job_name." job complete.\n";
@@ -0,0 +1,18 @@
ArtScience Museum 6 Bayfront Ave, Singapore, 18974
National Gallery Singapore 1 St Andrew's Rd, Singapore, 178957
National Museum of Singapore 93 Stamford Rd, Singapore, 178897
Haw Par Villa 262 Pasir Panjang Rd, Singapore, 118628
Singapore Botanic Gardens 1 Cluny Rd, Singapore, 259569
Chinese and Japanese Gardens 1 Chinese Garden Rd, Singapore, 619795
Gardens by the Bay 18 Marina Gardens Dr, Singapore, 018953
Fort Canning River Valley Rd, Singapore, 179037
Singapore Zoo 80 Mandai Lake Rd, 729826
River Safari 80 Mandai Lake Rd, Singapore, 729826
Little India #02, 48 Serangoon Rd, 16, Little India Arcade, 217959
Chinatown 133 New Bridge Rd, Singapore 059413
Kampong Glam 18 Kandahar St, Singapore 198884
Universal Studios Singapore 8 Sentosa Gateway, 098269
Siloso Beach Siloso Beach 7R47+42 Southern Islands, SingaporeWalk, Singapore
Adventure Cove Waterpark 8 Sentosa Gateway, 098269
Marina Bay Sands Rooftop 10 Bayfront Ave, Singapore 018956
1-Altitude 1 Raffles Place, #B1-12, Singapore, 048616
@@ -0,0 +1,145 @@
<?php
$job_name = pathinfo(__FILE__, PATHINFO_FILENAME);
echo "[".date("Y-m-d H:i:s")."] ".$job_name." job is starting.\n";
set_time_limit(0); // No limit!
require('../../backend.php');
require('../common/QuoteApi.php');
$httpAuthToken = $savvyext->cfgReadChar('system.oauth2_token');
$encryptionAlg = $savvyext->cfgReadChar('encryption.algorithm');
$encryptionKey = $savvyext->cfgReadChar('encryption.key');
$encryptionIV = $savvyext->cfgReadChar('encryption.iv');
$baseURL = $savvyext->cfgReadChar('system.api_url');
$db_host = $savvyext->cfgReadChar('database.host');
$db_name = $savvyext->cfgReadChar('database.name');
$db_user = $savvyext->cfgReadChar('database.user');
$db_pass = $savvyext->cfgReadChar('database.pass');
$db_port = $savvyext->cfgReadLong('database.port');
$connstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$conn = pg_connect($connstr);
$country = 'US';
$member_id = 0;
// Uber, Lyft
$transport_providers = [1,2];
// Step 1: Load batch file
$attractions = load_batch_file("batch_quote_tourist_attractions_atl.txt");
// Step 2: Geocode addresses
$newOrigins = geocode_addresses($attractions);
QuoteApi::$job_name=$job_name;
// Step 3: Schedule quotes
$checkQuotes = [];
foreach ($newOrigins as $origin_id=>$origin) {
foreach ($newOrigins as $destination_id=>$destination) {
if ($origin_id==$destination_id) continue;
foreach ($transport_providers as $transport_provider) {
$q = "SELECT * FROM quotes ";
$q.= " WHERE location_start_id=${origin_id} AND location_end_id=${destination_id} ";
$q.= " AND transport_provider_id=${transport_provider} AND cost>0 ";
$q.= " AND completed>(current_date-1) ORDER BY completed DESC LIMIT 1";
$r = pg_query($conn, $q);
if ($r && pg_num_rows($r) && $f=pg_fetch_assoc($r)) {
echo "[".date("Y-m-d H:i:s")."] Quote ".$f["cost"]." already exists ID #".$f["id"]."\n";
continue;
}
list($res,$id) = QuoteApi::schedule_quote($origin,$destination,$country,$member_id,$transport_provider);
if ($res>0) {
if ($res==2) {
echo "[".date("Y-m-d H:i:s")."] Quote complete! ID #${id}\n";
} else if ($res==1) {
echo "[".date("Y-m-d H:i:s")."] Scheduled quote ID #${id}\n";
$checkQuotes[] = $id;
} else {
echo "[".date("Y-m-d H:i:s")."] Unexpected result for ID #${id} ($res)\n";
}
} else {
echo "[".date("Y-m-d H:i:s")."] schedule_quote failed: ${res}.\n";
echo "[".date("Y-m-d H:i:s")."] $origin,$destination,$country,$member_id,$transport_provider\n";
}
}
}
}
// Step 4: Check quotes
foreach ($checkQuotes as $id) {
list($res,$cost) = QuoteApi::check_quote($id);
echo "[".date("Y-m-d H:i:s")."] Checking quote ID #${id} ($res) cost=${cost}\n";
}
function load_batch_file($filename) {
$results = [];
$fn = fopen($filename,"r");
while(! feof($fn)) {
$result = fgets($fn);
$results[strtok($result,"\t")] = trim(strtok("\t"));
}
fclose($fn);
return $results;
}
function geocode_addresses($addresses) {
global $conn;
$geocodedAddresses = [];
foreach ($addresses as $desc=>$address) {
$params = [
"address" => $address,
"member_id" => 0,
"country" => "US"
];
$input = http_build_query($params);
list($payload,$decrypted,$result,$body) = main_api_get('/trips/api/geocode/?',$input);
if (is_array($payload) && array_key_exists('geocode',$payload) && is_array($payload['geocode'])
&& array_key_exists('id',$payload['geocode']) && $payload['geocode']['id']>0) {
$geocodedAddresses[$payload['geocode']['id']] = $payload['geocode']['address'];
$q = "INSERT INTO tourist_attraction (attraction,address_id) VALUES('".pg_escape_string($desc)."',".$payload["geocode"]["id"].")";
$r = pg_query($conn,$q);
}
}
return $geocodedAddresses;
}
function main_api_get($endpoint,$input) {
global $baseURL, $encryptionAlg, $encryptionKey, $encryptionIV, $httpAuthToken;
if ($endpoint!="" && $input!="") { // minimal sanity
sleep(1);
$url = $baseURL . $endpoint . $input;
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_VERBOSE, false);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'Authorization: Server-Token ' . $httpAuthToken,
"client_id: BATCH"
)
);
$body = curl_exec($ch);
$result = json_decode($body,true);
$decrypted = openssl_decrypt(
hex2bin(
$result['payload']
),
$encryptionAlg,
$encryptionKey,
OPENSSL_RAW_DATA,
$encryptionIV
);
$payload = json_decode($decrypted, true);
return [$payload,$decrypted,$result,$body];
}
return [NULL,NULL,NULL,NULL];
}
echo "[".date("Y-m-d H:i:s")."] ".$job_name." job complete.\n";
@@ -0,0 +1,5 @@
Mercedes-Benz Stadium 1 AMB Dr NW, Atlanta, GA 30313
Cumberland Mall 2860 Cumberland Mall, Atlanta, GA 30339
SunTrust Park 755 Battery Ave SE, Atlanta, GA 30339
Georgia Aquarium 225 Baker St NW, Atlanta, GA 30313
CNN Studio 190 Marietta St NW, Atlanta, GA 30303
@@ -0,0 +1,144 @@
<?php
$job_name = pathinfo(__FILE__, PATHINFO_FILENAME);
echo "[".date("Y-m-d H:i:s")."] ".$job_name." job is starting.\n";
set_time_limit(0); // No limit!
require('../../backend.php');
require('../common/QuoteApi.php');
$httpAuthToken = $savvyext->cfgReadChar('system.oauth2_token');
$encryptionAlg = $savvyext->cfgReadChar('encryption.algorithm');
$encryptionKey = $savvyext->cfgReadChar('encryption.key');
$encryptionIV = $savvyext->cfgReadChar('encryption.iv');
$baseURL = $savvyext->cfgReadChar('system.api_url');
$db_host = $savvyext->cfgReadChar('database.host');
$db_name = $savvyext->cfgReadChar('database.name');
$db_user = $savvyext->cfgReadChar('database.user');
$db_pass = $savvyext->cfgReadChar('database.pass');
$db_port = $savvyext->cfgReadLong('database.port');
$connstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$conn = pg_connect($connstr);
$country = 'US';
$member_id = 0;
// Uber, Lyft
$transport_providers = [1,2];
// Step 1: Load batch file
$attractions = load_batch_file("batch_quote_tourist_attractions_sf.txt");
// Step 2: Geocode addresses
$newOrigins = geocode_addresses($attractions);
// Step 3: Schedule quotes
$checkQuotes = [];
QuoteApi::$job_name = $job_name;
foreach ($newOrigins as $origin_id=>$origin) {
foreach ($newOrigins as $destination_id=>$destination) {
if ($origin_id==$destination_id) continue;
foreach ($transport_providers as $transport_provider) {
$q = "SELECT * FROM quotes ";
$q.= " WHERE location_start_id=${origin_id} AND location_end_id=${destination_id} ";
$q.= " AND transport_provider_id=${transport_provider} AND cost>0 ";
$q.= " AND completed>(current_date-1) ORDER BY completed DESC LIMIT 1";
$r = pg_query($conn, $q);
if ($r && pg_num_rows($r) && $f=pg_fetch_assoc($r)) {
echo "[".date("Y-m-d H:i:s")."] Quote ".$f["cost"]." already exists ID #".$f["id"]."\n";
continue;
}
list($res,$id) = QuoteApi::schedule_quote($origin,$destination,$country,$member_id,$transport_provider);
if ($res>0) {
if ($res==2) {
echo "[".date("Y-m-d H:i:s")."] Quote complete! ID #${id}\n";
} else if ($res==1) {
echo "[".date("Y-m-d H:i:s")."] Scheduled quote ID #${id}\n";
$checkQuotes[] = $id;
} else {
echo "[".date("Y-m-d H:i:s")."] Unexpected result for ID #${id} ($res)\n";
}
} else {
echo "[".date("Y-m-d H:i:s")."] schedule_quote failed: ${res}.\n";
echo "[".date("Y-m-d H:i:s")."] $origin,$destination,$country,$member_id,$transport_provider\n";
}
}
}
}
// Step 4: Check quotes
foreach ($checkQuotes as $id) {
list($res,$cost) = QuoteApi::check_quote($id);
echo "[".date("Y-m-d H:i:s")."] Checking quote ID #${id} ($res) cost=${cost}\n";
}
function load_batch_file($filename) {
$results = [];
$fn = fopen($filename,"r");
while(! feof($fn)) {
$result = fgets($fn);
$results[strtok($result,"\t")] = trim(strtok("\t"));
}
fclose($fn);
return $results;
}
function geocode_addresses($addresses) {
global $conn;
$geocodedAddresses = [];
foreach ($addresses as $desc=>$address) {
$params = [
"address" => $address,
"member_id" => 0,
"country" => "US"
];
$input = http_build_query($params);
list($payload,$decrypted,$result,$body) = main_api_get('/trips/api/geocode/?',$input);
if (is_array($payload) && array_key_exists('geocode',$payload) && is_array($payload['geocode'])
&& array_key_exists('id',$payload['geocode']) && $payload['geocode']['id']>0) {
$geocodedAddresses[$payload['geocode']['id']] = $payload['geocode']['address'];
$q = "INSERT INTO tourist_attraction (attraction,address_id) VALUES('".pg_escape_string($desc)."',".$payload["geocode"]["id"].")";
$r = pg_query($conn,$q);
}
}
return $geocodedAddresses;
}
function main_api_get($endpoint,$input) {
global $baseURL, $encryptionAlg, $encryptionKey, $encryptionIV, $httpAuthToken;
if ($endpoint!="" && $input!="") { // minimal sanity
sleep(1);
$url = $baseURL . $endpoint . $input;
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_VERBOSE, false);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'Authorization: Server-Token ' . $httpAuthToken,
"client_id: BATCH"
)
);
$body = curl_exec($ch);
$result = json_decode($body,true);
$decrypted = openssl_decrypt(
hex2bin(
$result['payload']
),
$encryptionAlg,
$encryptionKey,
OPENSSL_RAW_DATA,
$encryptionIV
);
$payload = json_decode($decrypted, true);
return [$payload,$decrypted,$result,$body];
}
return [NULL,NULL,NULL,NULL];
}
echo "[".date("Y-m-d H:i:s")."] ".$job_name." job complete.\n";
@@ -0,0 +1,27 @@
Golden Gate Post Card Viewpoint Golden Gate Bridge, Coastal Trail, San Francisco, CA 94129, USA
Battery Spencer RGH7+FH Sausalito, California, USA
Madame Tussauds San Francisco 145 Jefferson St, San Francisco, CA 94133, USA
Ghirardelli Square 900 North Point St Suite 52, San Francisco, CA 94109, USA
Ferry Building 1 Ferry Building, San Francisco, CA 94111, USA
Nob Hill 1621 Polk St, San Francisco, CA 94109, USA
Lombard Street 2139 Lombard St, San Francisco, CA 94123, USA
Chinatown 826 Grant Ave, San Francisco, CA 94108, USA
Golden Gate Park 50 Stow Lake Dr E, San Francisco, CA 94118, USA
San Francisco Botanical Garden 1199 9th Ave, San Francisco, CA 94122, USA
California Palace of the Legion of Honor 100 34th Ave, San Francisco, CA 94121, USA
The Palace Of Fine Arts 3601 Lyon St, San Francisco, CA 94123, USA
California Academy of Sciences 55 Music Concourse Dr, San Francisco, CA 94118, USA
San Francisco Museum of Modern Art 151 3rd St, San Francisco, CA 94103, USA
de Young Fine Arts Museum of San Francisco 50 Hagiwara Tea Garden Dr, San Francisco, CA 94118, USA
Twin Peaks 501 Twin Peaks Blvd, San Francisco, CA 94114, USA
Asian Art Museum 200 Larkin St, San Francisco, CA 94102, USA
Exploratorium Pier 15, The Embarcadero, San Francisco, CA 94111, USA
High Tea at a Historic Hotel 2 New Montgomery St, San Francisco, CA 94105, USA
AT&T Park 24 Willie Mays Plaza, San Francisco, CA 94107, USA
Walt Disney Family Museum 104 Montgomery St, San Francisco, CA 94129, USA
Yerba Buena Gardens 750 Howard St, San Francisco, CA 94103, USA
San Francisco Symphony 201 Van Ness Ave, San Francisco, CA 94102, USA
San Francisco Zoo and Gardens Sloat Blvd & Great Highway, San Francisco, CA 94132, USA
Union Square 333 Post St, San Francisco, CA 94108, USA
Baker Beach Gibson Rd, San Francisco, CA 94129, USA
Japantown 1610 Geary Blvd, San Francisco, CA 94115, USA
+1
View File
@@ -0,0 +1 @@
HERE
+61
View File
@@ -0,0 +1,61 @@
<?php
echo "[" . date("Y-m-d H:i:s") . "] blog_rotattion job is starting.\n";
require('../backend.php');
define('EMAIL_PENDING', 1);
define('EMAIL_SENT', 5);
// We will not limit the SQL we will exhaust the allowed memory
// we will process data in ${hard_limit} batches and hopefully catch up
$hard_limit = 500000;
// GPS coordinate precision to assume the same location
$precision = 3;
$tag_message = false;
$email_templates_dir = $savvyext->cfgReadChar('mailsend.templates_dir');
$template_name = "DealTemplate.html"; // This is test template.
$db_host = $savvyext->cfgReadChar('database.host');
$db_name = $savvyext->cfgReadChar('database.name');
$db_user = $savvyext->cfgReadChar('database.user');
$db_pass = $savvyext->cfgReadChar('database.pass');
$db_port = $savvyext->cfgReadLong('database.port');
$connstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$conn = pg_connect($connstr);
$db_host = $savvyext->cfgReadChar('database_replica.host');
$db_name = $savvyext->cfgReadChar('database_replica.name');
$db_user = $savvyext->cfgReadChar('database_replica.user');
$db_pass = $savvyext->cfgReadChar('database_replica.pass');
$db_port = $savvyext->cfgReadLong('database_replica.port');
$readOnlyReplicaConnstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$readOnlyReplicaConn = pg_connect($readOnlyReplicaConnstr);
$mysql = "SELECT *,id AS member_id FROM members LIMIT 10";
$r = pg_query($readOnlyReplicaConn, $mysql);
$acc = array();
if ($r && pg_num_rows($r)) {
// Load Email template
$htm_template = file_get_contents($email_templates_dir . "/" . $template_name);
while ($f = pg_fetch_assoc($r)) {
$member_id = $f["member_id"];
$notify_id = $f["notify_id"];
$reciever_email = $f["reciever_email"];
$notice_type = $f["notice_type"];
$category = $f["category"];
}
}
+117
View File
@@ -0,0 +1,117 @@
<?php
class Api
{
private static $instance;
private static $httpAuthToken;
private static $encryptionAlg;
private static $encryptionKey;
private static $encryptionIV;
private static $baseURL;
public function __construct()
{
}
public static function initConfig()
{
global $savvyext;
self::$httpAuthToken = $savvyext->cfgReadChar('system.oauth2_token');
self::$encryptionAlg = $savvyext->cfgReadChar('encryption.algorithm');
self::$encryptionKey = $savvyext->cfgReadChar('encryption.key');
self::$encryptionIV = $savvyext->cfgReadChar('encryption.iv');
self::$baseURL = $savvyext->cfgReadChar('system.api_url');
}
public static function getInstance()
{
if (null === static::$instance) {
static::$instance = new static;
self::initConfig();
return static::$instance;
}
return static::$instance;
}
public static function postData($endpoint, $payload)
{
self::getInstance();
$encrypted_payload = bin2hex(
openssl_encrypt(
$payload,
self::$encryptionAlg,
self::$encryptionKey,
OPENSSL_RAW_DATA,
self::$encryptionIV
));
$postdata = "{\"encrypted_payload\": \"${encrypted_payload}\"}";
$url = self::$baseURL . $endpoint;
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_VERBOSE, false);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'Content-Length: ' . strlen($postdata),
'Authorization: Server-Token ' . self::$httpAuthToken,
"client_id: BATCH"
)
);
$body = curl_exec($ch);
$result = json_decode($body, true);
$decrypted = openssl_decrypt(
hex2bin(
$result['payload']
),
self::$encryptionAlg,
self::$encryptionKey,
OPENSSL_RAW_DATA,
self::$encryptionIV
);
$payload = json_decode($decrypted, true);
return $payload;
}
public static function getData($endpoint)
{
self::getInstance();
if ($endpoint != "") { // minimal sanity
sleep(1);
$url = self::$baseURL . $endpoint;
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_VERBOSE, false);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'Authorization: Server-Token ' . self::$httpAuthToken,
"client_id: BATCH"
)
);
$body = curl_exec($ch);
$result = json_decode($body, true);
$decrypted = openssl_decrypt(
hex2bin(
$result['payload']
),
self::$encryptionAlg,
self::$encryptionKey,
OPENSSL_RAW_DATA,
self::$encryptionIV
);
$payload = json_decode($decrypted, true);
return [$payload, $decrypted, $result, $body];
}
return [null, null, null, null];
}
}
+121
View File
@@ -0,0 +1,121 @@
<?php
class Geocode
{
public static function geocodeAddress($address)
{
global $httpAuthToken, $oauth_api;
if (!empty($address)) {
$data = http_build_query(
array(
'address' => $address,
)
);
$url = $oauth_api . "geocode?" . $data;
$opts = array(
'http' => array(
'method' => "GET",
'timeout' => 60, /* 1 minute */
'header' =>
"Content-Type: application/x-www-form-urlencoded\r\n" .
"Accept: application/json\r\n" .
"Authorization: Server-Token ${httpAuthToken}\r\n",
),
);
$context = stream_context_create($opts);
$body = file_get_contents($url, false, $context);
$geocoded = json_decode($body, true);
if (is_array($geocoded) && isset($geocoded["data"]) && !isset($geocoded["error"])) {
return $geocoded["data"];
}
}
return null;
}
public static function reverseGPS($latitude, $longitude)
{
global $httpAuthToken, $oauth_api;
$body = null;
if (!empty($latitude && !empty($longitude))) {
$data = http_build_query(
array(
'lat' => $latitude,
'lng' => $longitude,
)
);
$url = $oauth_api . "reverse?" . $data;
$opts = array(
'http' => array(
'method' => "GET",
'timeout' => 60, /* 1 minute */
'header' =>
"Content-Type: application/x-www-form-urlencoded\r\n" .
"Accept: application/json\r\n" .
"Authorization: Server-Token ${httpAuthToken}\r\n",
),
);
$context = stream_context_create($opts);
$body = file_get_contents($url, false, $context);
$geocoded = json_decode($body, true);
if (is_array($geocoded) && isset($geocoded["data"]) && !isset($geocoded["error"])) {
return $geocoded["data"];
}
}
return null;
}
public function getTimeZone($lat, $lng)
{
global $googleKey;
$result = array("message" => "Unexpected error", "dstOffset" => 0, "rawOffset" => 0, "status" => "Error", "timeZoneId" => "", "timeZoneName" => "");
$url = "https://maps.googleapis.com/maps/api/timezone/json?location=${lat},${lng}&timestamp=" . time() . "&key=" . $googleKey;
$resp_json = file_get_contents($url);
$resp = json_decode($resp_json, true);
if ($resp["status"] == 'OK') {
$result = $resp;
if ($resp["timeZoneId"] != "") {
$result["message"] = "";
} else {
$result["message"] = "Failed to get timezone offset for: ${lat},${lng}\n";
}
} else {
$result["message"] = "Invalid service response code\n";
}
return $result;
}
public static function getGeoInfoBigDataCloud($latitude, $longitude)
{
global $city_keywords;
$url = "https://api.bigdatacloud.net/data/reverse-geocode-client?latitude=" . $latitude . "&longitude=" . $longitude . "&localityLanguage=en";
$opts = array(
'http' => array(
'method' => "GET",
),
);
$context = stream_context_create($opts);
$body = file_get_contents($url, false, $context);
$geoinfo = json_decode($body, true);
if (count($geoinfo) > 0 && isset($geoinfo['localityInfo'])) {
$localities = $geoinfo['localityInfo']['administrative'];
foreach ($localities as $k => $v) {
$name = isset($v['name']) ? $v['name'] : "";
$description = isset($v['description']) ? $v['description'] : "";
$info = strtolower($name . $description);
foreach ($city_keywords as $key) {
if (strpos($info, $key) !== false) {
return $v['name'];
}
}
}
}
return null;
}
}
+103
View File
@@ -0,0 +1,103 @@
<?php
require __DIR__ . '../../../vendor/autoload.php';
class Logger
{
protected static $instance;
private static $logger;
const ERROR = 0;
const WARNING = 1;
const INFO = 2;
const DEBUG = 3;
const DEBUG1 = 4;
const DEBUG2 = 5;
const DEBUG3 = 6;
const DEBUG4 = 7;
const SQL = 8;
const FLOG_MAX = 9;
const LEVELS = [
'ERROR', 'WARNING', 'INFO', 'DEBUG', 'DEBUG1', 'DEBUG2', 'DEBUG3', 'DEBUG4', 'SQL', 'FLOG_MAX'
];
public function __construct()
{
}
public static function getLogger()
{
if (!self::$instance) {
self::initLogger();
}
return self::$instance;
}
public static function initLogger()
{
global $savvyext;
$fluent_host = $savvyext->cfgReadChar('phplogger.host');
$fluent_port = $savvyext->cfgReadLong('phplogger.port');
$log_enabled = $savvyext->cfgReadLong('phplogger.enabled');
if ($log_enabled == 1) {
self::$logger = new Fluent\Logger\FluentLogger($fluent_host, $fluent_port);
}
self::$instance = self::$logger;
}
public static function __callStatic($name, $arguments){
if(is_array($arguments) && count($arguments)>0 && in_array(strtoupper($name), Logger::LEVELS)) {
$data = $arguments[0];
$name = NULL;
$tag = NULL;
if (count($arguments)>1) {
$name = $arguments[1];
}
if (count($arguments)>2) {
$tag = $arguments[2];
}
$level = Logger::levelByName($name);
return Logger::log($level, $data, $name, $tag);
}
error_log("Logger::__callStatic($name, \$arguments) => Invalid method name!");
}
public static function levelByName($name) {
$val = strtoupper($name);
if(in_array($val, Logger::LEVELS)) {
return array_search($val, Logger::LEVELS, false);
} else {
return Logger::FLOG_MAX;
}
}
public static function nameByLevel($level) {
$level = (int)$level;
return Logger::ERROR < $level || $level > Logger::FLOG_MAX ? Logger::LEVELS[Logger::FLOG_MAX] : Logger::LEVELS[$level];
}
public static function log($level, $data = [], $name = NULL, $tag = NULL)
{
global $savvyext;
$clevel = $savvyext->cfgReadLong('phplogger.level');
$ilevel = (int)$level;
if ($ilevel > $clevel) {
error_log("Logger::log() invalid log level! '$level' => '$ilevel' > '$clevel'");
return;
}
$tag = $tag ?? $savvyext->cfgReadChar('phplogger.tag');
$name = $name ?? $savvyext->cfgReadChar('phplogger.name');
$data = [
"log" => $name,
"level" => Logger::nameByLevel($level),
"pid" => getmypid(),
"zz" => is_array($data) || is_object($data) ? json_encode($data) : $data,
];
if (self::getLogger()) {
self::getLogger()->post($tag, $data);
}
}
}
+74
View File
@@ -0,0 +1,74 @@
<?php
require_once('../common/Api.php');
require_once('../common/Logger.php');
class QuoteApi
{
public static $job_name="";
public static function schedule_quote($origin, $destination, $country, $member_id, $transport_provider, $trackedemail_item_id = 0, $prefill = 't', $pool = 1)
{
if ($origin != "" && $destination != "" && $transport_provider > 0) { // minimal sanity
$payload = "{
\"origin\":\"${origin}\",
\"destination\":\"${destination}\",
\"member_id\":${member_id},
\"transport_provider_id\":${transport_provider},
\"trackedemail_item_id\":${trackedemail_item_id},
\"country\":\"${country}\",
\"group_quote_id\":0,
\"prefill\":\"${prefill}\",
\"pool\":${pool}
}";
$input_data = $payload;
$endpoint = "/trips/api/quote";
$payload = Api::postData($endpoint, $input_data);
$log = [
'job_name' => self::$job_name,
'function' => __FUNCTION__,
'request' => $endpoint,
'input_data' => $input_data,
'response_data' => $payload,
];
Logger::debug($log);
if (is_array($payload) && array_key_exists('id', $payload) && $payload['id'] > 0) {
if (array_key_exists('cost', $payload) && $payload['cost'] > 0) {
return [2, $payload['id']];//completed
}
if (array_key_exists('travel_date', $payload) && $payload['travel_date'] != '') {
return [-1, $payload['id']];
}
return [1, $payload['id']];
} else {
return [-2, null];
}
}
return [-3, null];
}
public static function check_quote($id)
{
if ($id > 0) { // minimal sanity
list($payload, $decrypted, $result, $body) = Api::getData("/trips/api/quote/" . $id);
$log = [
'job_name' => self::$job_name,
'function' => __FUNCTION__,
'request' => "/trips/api/quote/" . $id,
'input_data' => $id,
'response_data' => $payload,
];
Logger::debug($log);
if (is_array($payload) && array_key_exists('id', $payload) && $payload['id'] > 0) {
if (array_key_exists('cost', $payload) && $payload['cost'] > 0) {
return [2, $payload['cost']];//completed
}
if (array_key_exists('travel_date', $payload) && $payload['travel_date'] != '') {
return [-1, null];
}
} else {
return [-2, null];
}
}
return [-3, null];
}
}
+142
View File
@@ -0,0 +1,142 @@
<?php
/***
* Class SVY21
* todo: convert SVY21 Singapore TM to Lat Long
*/
class SVY21
{
const ELLIPSOID_SEMIMAJORAXIS = 6378137.0;
const ELLIPSOID_ECCENTRICITY = 0.0818191908426215;
const ELLIPSOID_FLATTENING = 0.00335281066474746;
const PROJ_NATURALORIGINLATITUDE = 1.36666666666667;
const PROJ_NATURALORIGINLONGITUDE = 103.833333333333;
const PROJ_SCALEFACTOR = 1.0;
const PROJ_FALSEEASTINGS = 28001.642;
const PROJ_FALSENORTHINGS = 38744.572;
function __construct()
{
}
/***
* @param $N of svy21
* @param $E of svy21
* @return float[]|int[] return [lat, long]
*/
public function CnvEN2LL($N, $E)
{
$l = $this->SecondEccentricity();
$a = $this->calc_e1();
$b = $this->calc_M1($E);
$c = $this->calc_u1($b);
$d = $this->calc_lat1($c, $a);
$e = $this->calc_T1($d);
$f = $this->calc_c1($d);
$g = $this->calc_v1($d);
$h = $this->calc_p1($d);
$i = ($N - self::PROJ_FALSEEASTINGS) / ($g * self::PROJ_SCALEFACTOR);
$j = ($i * $i / 2.0) - (5.0 + 3.0 * $e + 10.0 * $f - 4.0 * $f * $f - 9.0 * pow($l, 2)) * (pow($i, 4) / 24.0) + (61.0 + 90.0 * $e + 298.0 * $f + 45.0 * $e * $e - 252.0 * pow($l, 2) - 3.0 * $f * $f) * (pow($i, 6) / 720.0);
$j = $d - $g * tan($d) * $j / $h;
$lat = $this->CnvRadToDeg($j);
$k = ($i - (1.0 + 2.0 * $e + $f) * pow($i, 3) / 6.0 + (5.0 - 2.0 * $f + 28.0 * $e - 3.0 * $f * $f + 8.0 * pow($l, 2) + 24.0 * $e * $e) * pow($i, 5) / 120.0) / cos($d);
$k = $this->CnvDegToRad(self::PROJ_NATURALORIGINLONGITUDE) + $k;
$long = $this->CnvRadToDeg($k);
$r1 = floor($lat);
$r2 = floor(($lat - $r1) * 60);
$r3 = (round(((($lat - $r1) - ($r2 / 60)) * 60 * 60) * 100) / 100);
$r3 = $this->roundNumber($r3, 4);
$r4 = floor($long);
$r4 = floor(($long - $r4) * 60);
$r5 = (round(((($long - $r4) - ($r4 / 60)) * 60 * 60) * 100) / 100);
$r5 = $this->roundNumber($r5, 4);
return [$lat, $long];
}
private function SecondEccentricity()
{
return (sqrt(self::ELLIPSOID_ECCENTRICITY * self::ELLIPSOID_ECCENTRICITY / (1.0 - self::ELLIPSOID_ECCENTRICITY * self::ELLIPSOID_ECCENTRICITY)));
}
private function roundNumber($a, $b)
{
return round($a * pow(10, $b)) / pow(10, $b);
}
private function CnvRadToDeg($a)
{
return (180.0 * $a / pi());
}
private function CnvDegToRad($a)
{
return (pi() * $a) / 180.0;
}
private function calc_M($a)
{
$c = self::ELLIPSOID_ECCENTRICITY;
$d = 1.0 - (pow($c, 2) / 4.0) - (3.0 * pow($c, 4) / 64.0) - (5.0 * pow($c, 6) / 256);
$e = (3.0 * pow($c, 2) / 8.0) + (3.0 * pow($c, 4) / 32.0) + (45.0 * pow($c, 6) / 1024.0);
$f = (15.0 * pow($c, 4.0) / 256.0) + (45.0 * pow($c, 6) / 1024.0);
$g = (35.0 * pow($c, 6) / 3072);
$b = $d * $a - $e * sin(2.0 * $a) + $f * sin(4.0 * $a) - $g * sin(6 * $a);
return $b * self::ELLIPSOID_SEMIMAJORAXIS;
}
private function calc_T1($a)
{
$b = tan($a);
return $b * $b;
}
private function calc_v1($a)
{
$b = self::ELLIPSOID_ECCENTRICITY * sin($a);
$b = sqrt(1.0 - $b * $b);
return self::ELLIPSOID_SEMIMAJORAXIS / $b;
}
private function calc_p1($a)
{
$c = self::ELLIPSOID_ECCENTRICITY;
$b = 1.0 - $c * $c * pow(sin($a), 2);
$b = pow($b, 3.0 / 2.0);
return self::ELLIPSOID_SEMIMAJORAXIS * (1.0 - $c * $c) / $b;
}
private function calc_c1($a)
{
$b = $this->SecondEccentricity();
$b = $b * cos($a);
return $b * $b;
}
private function calc_e1()
{
$a = 1.0 - sqrt(1.0 - pow(self::ELLIPSOID_ECCENTRICITY, 2));
return $a / (1.0 + sqrt(1.0 - pow(self::ELLIPSOID_ECCENTRICITY, 2)));
}
private function calc_M1($a)
{
$c = $this->calc_M($this->CnvDegToRad(self::PROJ_NATURALORIGINLATITUDE));
return ($c + ($a - self::PROJ_FALSENORTHINGS) / self::PROJ_SCALEFACTOR);
}
private function calc_u1($a)
{
$c = self::ELLIPSOID_ECCENTRICITY;
$b = self::ELLIPSOID_SEMIMAJORAXIS * (1.0 - ($c * $c / 4.0) - (3.0 * pow($c, 4) / 64.0) - (5.0 * pow($c, 6) / 256.0));
return $a / $b;
}
private function calc_lat1($a, $b)
{
$c = $a + ((3.0 * $b / 2.0) - 27.0 * $b * $b / 32.0) * sin(2.0 * $a);
$c = $c + ((21.0 * $b * $b / 16.0) - 55.0 * pow($b, 4.0) / 32.0) * sin(4.0 * $a);
$c = $c + (151.0 * pow($b, 3) / 96.0) * sin(6.0 * $a);
$c = $c + (1097.0 * pow($b, 4) / 512.0) * sin(8.0 * $a);
return $c;
}
}
+449
View File
@@ -0,0 +1,449 @@
<?php
function getAddressId($address)
{
global $googleKey, $readOnlyReplicaConn;
// Check the address exsts
$q = "SELECT id FROM address WHERE lower(address)=lower('${address}') ";
$q .= "AND latitude<>0 AND longitude<>0 AND geocoding_date IS NOT NULL ";
$q .= "ORDER BY geocoding_date DESC LIMIT 1";
error_log($q);
$r = pg_query($readOnlyReplicaConn, $q);
if ($r && pg_num_rows($r) && $f = pg_fetch_row($r)) {
return $f[0];
}
return null;
}
/* save data to table address */
function saveAddress($result)
{
global $conn;
syslog(LOG_WARNING, 'MessageDataSaver::saveAddress($result)');
$db_lat = floatval($result["lat"]);
$db_lng = floatval($result["lng"]);
$db_address = pg_escape_string($result["address"]);
$db_postal = pg_escape_string($result["postal"]);
$db_city = pg_escape_string($result["city"]);
$db_city_lat = floatval($result["city_lat"]);
$db_city_lng = floatval($result["city_lng"]);
$db_country = pg_escape_string($result["country"]);
$db_tz = getTimeZoneID($result["timeZoneId"]);
$city_id = getCityId($db_city, $db_country, $db_city_lat, $db_city_lng);
if (empty($db_postal)) {
$db_postal = getPostalCode($db_lat, $db_lng, $db_country);
}
$q = "INSERT INTO address (address,latitude,longitude,timezone,geocoding_date,postal,country,geometry, city_id) VALUES (";
$q .= "'${db_address}',${db_lat},${db_lng}," . ($db_tz == null ? "NULL" : $db_tz) . ",now(),'${db_postal}','${db_country}',ST_SetSRID(ST_MakePoint(${db_lng},${db_lat}), 4326),'${city_id}')";
$q .= " RETURNING id";
error_log($q);
$r = pg_query($conn, $q);
if ($r && pg_num_rows($r) && $f = pg_fetch_row($r)) {
return $f[0];
}
return null;
}
function getTzByAddressId($id)
{
global $readOnlyReplicaConn;
$q = "SELECT timezone FROM address_timezone WHERE id=(SELECT timezone FROM address WHERE id=" . ((int) $id) . ")";
$r = pg_query($readOnlyReplicaConn, $q);
if ($r && pg_num_rows($r) && $f = pg_fetch_row($r)) {
return $f[0];
}
return 'America/Los_Angeles'; // 2
}
function getTimeZoneID($name)
{
global $readOnlyReplicaConn, $conn;
$q = "SELECT id FROM address_timezone WHERE timezone='" . pg_escape_string($name) . "'";
$r = pg_query($readOnlyReplicaConn, $q);
if ($r && pg_num_rows($r) && $f = pg_fetch_row($r)) {
return $f[0];
}
$q = "INSERT INTO address_timezone (timezone) VALUES('" . pg_escape_string($name) . "') RETURNING id";
$r = pg_query($conn, $q);
if ($r && pg_num_rows($r) && $f = pg_fetch_row($r)) {
return $f[0];
}
return null;
}
function getCityId($city, $country_code, $latitude, $longitude)
{
global $readOnlyReplicaConn, $conn;
$q = "SELECT id FROM geofence_area_city WHERE LOWER(city) ILIKE '" . strtolower(pg_escape_string($city)) . "' AND country='" . $country_code . "' OR (latitude='" . $latitude . "' AND longitude='" . $longitude . "') LIMIT 1";
$r = pg_query($readOnlyReplicaConn, $q);
if ($r && pg_num_rows($r) && $f = pg_fetch_assoc($r)) {
return $f['id'];
}
$i = "INSERT INTO geofence_area_city (city,country,latitude,longitude,location) VALUES ('" . pg_escape_string($city) . "','${country_code}',${latitude},${longitude},ST_SetSRID(ST_MakePoint(${longitude},${latitude}), 4326)) RETURNING id";
$r = pg_query($conn, $i);
if ($r && pg_num_rows($r) && $f = pg_fetch_row($r)) {
return $f[0];
}
return null;
}
function deleteCities($ids)
{
global $conn;
if (is_array($ids) && count($ids) > 0) {
$q1 = "DELETE FROM geofence_area_city WHERE id IN (" . implode(",", $ids) . ")";
$r1 = pg_query($conn, $q1);
if ($r1 && pg_affected_rows($r1)) {
return true;
}
}
return false;
}
function deleteDataTable($table_name, $condition = "")
{
global $conn;
if (!empty($condition)) {
$q1 = "DELETE FROM " . $table_name . " WHERE " . $condition;
$r1 = pg_query($conn, $q1);
if ($r1 && pg_affected_rows($r1)) {
return true;
}
}
return false;
}
function updateDataTable($table_name, $condition, $data)
{
global $conn, $readOnlyReplicaConn;
$q = "select column_name, data_type, character_maximum_length from INFORMATION_SCHEMA.COLUMNS where table_name = '" . $table_name . "'";
$r = pg_query($readOnlyReplicaConn, $q);
while ($f = pg_fetch_assoc($r)) {
$columns[$f['column_name']] = $f['data_type'];
}
$q = "UPDATE " . $table_name . " SET id=id";
foreach ($data as $key => $val) {
if ($key == "id") {
continue;
}
if (array_key_exists($key, $data) && !in_array($columns[$key], ['character varying', 'date', 'timestamp with time zone', 'timestamp without time zone'])) {
$q .= ", ${key} = " . ($val == "" ? "NULL" : $val);
} else {
$q .= ", ${key} = '" . pg_escape_string($val) . "'";
}
}
$q .= " WHERE " . $condition . "";
echo $q . "\n";
$r = pg_query($conn, $q);
$updated = pg_affected_rows($r);
echo "[" . date("Y-m-d H:i:s") . "] update {$updated} rows of {$table_name} with {$condition} .\n";
return $updated;
}
function getForeignTables($table_name)
{
global $readOnlyReplicaConn;
$q = "SELECT
tc.table_name, kcu.column_name,
ccu.table_name AS foreign_table_name,
ccu.column_name AS foreign_column_name
FROM
information_schema.table_constraints AS tc
JOIN information_schema.key_column_usage AS kcu
ON tc.constraint_name = kcu.constraint_name
JOIN information_schema.constraint_column_usage AS ccu
ON ccu.constraint_name = tc.constraint_name
WHERE constraint_type = 'FOREIGN KEY' AND ccu.table_name='" . $table_name . "'";
$r = pg_query($readOnlyReplicaConn, $q);
$result = [];
while ($f = pg_fetch_assoc($r)) {
$result[] = $f;
}
return $result;
}
function getGeoName($city, $country_code)
{
global $readOnlyReplicaConn;
$q = "SELECT name,country,latitude,longitude,location FROM geoname WHERE LOWER(name) ILIKE '" . strtolower(pg_escape_string($city)) . "' AND country='" . $country_code . "' LIMIT 1";
$r = pg_query($readOnlyReplicaConn, $q);
if ($r && pg_num_rows($r) && $f = pg_fetch_assoc($r)) {
return $f;
} else {
return null;
}
}
function insertPostalCode($geoname, $postal, $latitude, $longitude, $country)
{
global $conn, $readOnlyReplicaConn;
if (strlen($geoname) > 100) {
$geoname = substr($geoname, 0, 99);
}
$q = "SELECT id FROM geoname_postal_code WHERE postal ILIKE '" . pg_escape_string($postal) . "' AND latitude='" . $latitude . "' AND longitude='" . $longitude . "' LIMIT 1";
$r = pg_query($readOnlyReplicaConn, $q);
if ($r && pg_num_rows($r) && $f = pg_fetch_assoc($r)) {
return $f['id'];
}
$i = "INSERT INTO geoname_postal_code (geoname, postal, latitude,longitude, country, geometry) VALUES ('" . pg_escape_string($geoname) . "','" . pg_escape_string($postal) . "',${latitude},${longitude},'" . pg_escape_string($country) . "',ST_SetSRID(ST_MakePoint(${longitude},${latitude}), 4326)) RETURNING id";
$r = pg_query($conn, $i);
if ($r && pg_num_rows($r) && $f = pg_fetch_row($r)) {
return $f[0];
}
return null;
}
function getPostalCode($latitude, $longitude, $country, $distance = 50000)
{
global $readOnlyReplicaConn;
$q = "SELECT postal,
ST_DistanceSphere(geometry::geometry, ST_SetSRID(ST_MakePoint(" . $longitude . ", " . $latitude . "),4326)) AS distance
FROM geoname_postal_code
WHERE ST_DistanceSphere(geometry::geometry, ST_SetSRID(ST_MakePoint(" . $longitude . ", " . $latitude . "),4326)) BETWEEN 0 AND " . $distance . " AND country='" . $country . "'
ORDER BY distance
LIMIT 1;";
$r = pg_query($readOnlyReplicaConn, $q);
if ($r && pg_num_rows($r) && $f = pg_fetch_assoc($r)) {
return $f['postal'];
}
return null;
}
/**
* get postal array from latitude, longitude
*/
function getPostalFromLatLng($latitude, $longitude, int $distance_in_km)
{
global $conn, $readOnlyReplicaConn;
$earth_radius = 6371;
$km_per_degree_lat = 111.2;
$pi = 3.14 / 180;
$query = " SELECT postal FROM (
SELECT (
$earth_radius * acos(
cos( radians( {$latitude}) )
* cos( radians( latitude ) )
* cos( radians( longitude ) - radians( {$longitude} ) )
+ sin( radians( {$latitude}) )
* sin( radians( latitude ) )
)
) AS distance
, *
FROM postal_code
WHERE
postal IS NOT NULL
AND latitude BETWEEN " . ($latitude - ($distance_in_km / $km_per_degree_lat)) .
" AND " . ($latitude + ($distance_in_km / $km_per_degree_lat));
$delta = round($distance_in_km / ($km_per_degree_lat * COS(deg2rad($longitude))), 10);
// Bounding box for speed - latitude within range (longtitude to km not linear)
if (cos($longitude * $pi) > 0) {
$from = $longitude - $delta;
$to = $longitude + $delta;
$query .=
" AND address.longitude" .
" BETWEEN " . $from .
" AND " . $to;
} else {
$from = $longitude + $delta;
$to = $longitude - $delta;
$query .=
" AND address.longitude" .
" BETWEEN " . $from .
" AND " . $to;
}
// distance limit for circle
$query .= " ) address
WHERE distance < " . $distance_in_km;
$rs = pg_query($readOnlyReplicaConn, $query) or die("Cannot execute query: $query\n");
if (!$rs) {
echo "An error occurred.\n";
exit;
}
return array_column(pg_fetch_all($rs), 'postal');
}
function insertActionLog($table_name="quotes",$operation="",$input_data="", $response_data="", $url="")
{
global $conn;
$input_data = is_array($input_data) || is_object($input_data) ? json_encode($input_data) : $input_data;
$response_data = is_array($response_data) || is_object($response_data) ? json_encode($response_data) : $response_data;
$q = "INSERT INTO action_logs (created,table_name,operation,input_data,response_data, url) ";
$q.= " VALUES(NOW(),'".$table_name."','".$operation."',";
$q.= "'".pg_escape_string($input_data)."','".pg_escape_string($response_data)."','".$url."') RETURNING id";
$r = pg_query($conn, $q);
if ($r && pg_num_rows($r) && $f=pg_fetch_assoc($r)) {
return true;
}
return null;
}
function parseAddressByCountry($address = "", $country_code = "")
{
$city = $state = $country = "";
if ($country_code == "AE") { //United Arab Emirates
$address_info = explode("-", $address);
} else {
$address_info = explode(",", $address);
}
switch ($country_code) {
case "AU": //Australia
$country = trim(array_pop($address_info));
$state_city = explode(" ", trim(array_pop($address_info)));
$postal = trim(array_pop($state_city));
$state = trim(array_pop($state_city));
$city = trim(array_pop($state_city));
break;
case "BR": //Brazil
$country = trim(array_pop($address_info));
$state = trim(array_pop($address_info));
$city = array_pop($address_info);
$city = explode('-', $city);
$city = trim($city[0]);
break;
case "SG":
$country = $city = "Singapore";
break;
case "HK":
$country = $city = "Hong Kong";
break;
case "US":
$country = trim(array_pop($address_info));
$state = trim(array_pop($address_info));
$city = $state;
if (preg_replace('/[^0-9]/', '', $state) != "") {
$city = trim(array_pop($address_info));
}
break;
case "CA": //Canada
case "IN": //India
case "ZA": //South Africa
case "MY": //Malaysia
case "PH": //Philippines
$country = trim(array_pop($address_info));
$state = trim(array_pop($address_info));
$city = trim(array_pop($address_info));
if ($country_code == "MY") {
$city = parseName($city);
}
break;
case "ID": //Indonesia
$country = trim(array_pop($address_info));
$city = trim(array_pop($address_info));
$city = parseName($city);
$city_info = explode(" ", $city);
$city = trim(array_pop($city_info));
break;
case "AT": //Autria
case "FI": //Finland
case "SE": //Sweden
case "BE": //Belgium
case "DE": //Germany
case "FR": //France
case "TH": //Thailand
case "NP": //Nepal
$country = trim(array_pop($address_info));
$city = trim(array_pop($address_info));
$city = parseName($city);
break;
case "NZ": //New Zealand
$country = trim(array_pop($address_info));
$city = trim(array_pop($address_info));
$city = parseName($city);
if ($city == "") {
$city = trim(array_pop($address_info));
}
break;
case "NL": //Netherlands
$country = trim(array_pop($address_info));
$city = trim(array_pop($address_info));
$city = parseName($city);
$city = explode(' ', $city);
$city = trim(array_pop($city));
break;
/*case "TR"://Turkey
$country = trim(array_pop($address_info));
$city = array_pop($address_info);
$city = explode('/', $city);
$city = trim(array_pop($city));
break;*/
case "UA": //Ukraina
$count_address = count($address_info);
if ($count_address < 5) {
$country = trim(array_pop($address_info));
$city = trim(array_pop($address_info));
} else {
if ($count_address == 5) {
$country = $address_info[$count_address - 2];
$city = $address_info[$count_address - 3];
} else {
$country = $address_info[$count_address - 2];
$city = $address_info[$count_address - 4];
}
}
$city = parseName($city);
break;
case "GB": //Great Britain
$country = trim(array_pop($address_info));
$city = trim(array_pop($address_info));
$city = explode(' ', $city);
$city = trim($city[0]);
break;
case "UA": //Ukraina
case "TR": //Turkey
case "PL": //Poland
case "RO": //Romania
$city = "";
break;
case "TW": //Taiwan
$country = trim(array_pop($address_info));
$city = array_pop($address_info);
break;
default:
$country = trim(array_pop($address_info));
$city = trim(array_pop($address_info));
}
return [
"address" => $address,
"city" => $city,
"state" => $state,
"country_code" => $country_code,
"country" => $country,
];
}
function parseName($name)
{
$name = trim(preg_replace('/[0-9]+/', '', $name));
return $name;
}
+25
View File
@@ -0,0 +1,25 @@
<?php
require '../backend.php';
$httpAuthToken = $savvyext->cfgReadChar('system.oauth2_token');
$oauth_api = $savvyext->cfgReadChar('system.oauth2_url');
$db_host = $savvyext->cfgReadChar('database.host');
$db_name = $savvyext->cfgReadChar('database.name');
$db_user = $savvyext->cfgReadChar('database.user');
$db_pass = $savvyext->cfgReadChar('database.pass');
$db_port = $savvyext->cfgReadLong('database.port');
$connstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$conn = pg_connect($connstr);
// Create readOnlyReplicaConn for readonly database
$db_read_only_host = $savvyext->cfgReadChar('database_replica.host');
$db_read_only_name = $savvyext->cfgReadChar('database_replica.name');
$db_read_only_user = $savvyext->cfgReadChar('database_replica.user');
$db_read_only_pass = $savvyext->cfgReadChar('database_replica.pass');
$db_read_only_port = $savvyext->cfgReadLong('database_replica.port');
$readonlyconnstr = "host=${db_read_only_host} port=${db_read_only_port} dbname=${db_read_only_name} user=${db_read_only_user} password=${db_read_only_pass}";
$readOnlyReplicaConn = pg_connect($readonlyconnstr);
$city_keywords = ["city", "province", "capital", "town"];
+38
View File
@@ -0,0 +1,38 @@
<?php
function parseEmail($email_id)
{
global $httpAuthToken,$oauth_api;
$url = $oauth_api."parse/" . $email_id;
$opts = array(
'http' => array(
'method' => "GET",
'timeout' => 60, /* 1 minute */
'header' =>
"Content-Type: application/x-www-form-urlencoded\r\n" .
"Accept: application/json\r\n" .
"Authorization: Server-Token ${httpAuthToken}\r\n",
),
);
$context = stream_context_create($opts);
$body = file_get_contents($url, false, $context);
$geocoded = json_decode($body, true);
if (is_array($geocoded) && is_array($geocoded["data"]) && !isset($geocoded["error"])) {
return $geocoded["data"];
}
return null;
}
function updateParsedEmail($id, $location_start_id, $location_end_id)
{
global $conn;
$q = "UPDATE parsedemail_item SET updated=NOW(), location_start_id=" . $location_start_id . ", location_end_id=" . $location_end_id . "
WHERE id = " . $id . "";
$r = pg_query($conn, $q);
if ($r && pg_num_rows($r) && $f = pg_fetch_assoc($r)) {
return [$f, null];
}
return [null, pg_last_error($conn)];
}
+33
View File
@@ -0,0 +1,33 @@
<?php
function d($value, $exit = 0)
{
if (is_array($value)) {
print_r($value);
} else if (is_object($value)) {
var_dump($value);
} else {
echo $value;
}
echo "<br/>";
if ($exit) {
exit;
}
}
function convertUtcToLocal($datetime, $timezone = '', $format = 'Y-m-d H:i:s')
{
if (!empty($datetime) && !empty($timezone)) {
$datetime = date($format, strtotime($datetime));
$utc_date = DateTime::createFromFormat(
$format,
$datetime,
new DateTimeZone('UTC')
);
if ($utc_date) {
$utc_date->setTimeZone(new DateTimeZone($timezone));
return $utc_date->format($format);
}
}
return $datetime;
}
+34
View File
@@ -0,0 +1,34 @@
# use /bin/bash to run commands, no matter what /etc/passwd says
SHELL=/bin/bash
# mail any output to `paul', no matter whose crontab this is
MAILTO=olu@float.sg
# run five minutes after midnight, every day
5 0 * * * /home/savvy/backup.sh
*/2 * * * * (cd /home/savvy/FloatWeb/adminsavvy/CRONS/ && php -f account_record_import.php)
*/5 * * * * (cd /home/savvy/FloatWeb/adminsavvy/CRONS/ && php -f transactions_record_import.php)
#*/60 * * * * (cd /home/savvy/FloatWeb/adminsavvy/CRONS/batch && php -f batch_quote_popular.php > batch_quote_popular.log 2>&1)
##*/60 * * * * (cd /home/savvy/FloatWeb/adminsavvy/CRONS/batch && php -f batch_quote_sanfrancisco_districts.php > batch_quote_sanfrancisco_districts.log 2>&1)
##*/30 * * * * (cd /home/savvy/FloatWeb/adminsavvy/CRONS/ && php -f background_quote_check.php > background_quote_check.log 2>&1)
*/5 * * * * (cd /home/savvy/FloatWeb/adminsavvy/CRONS/ && php -f member_notification.php)
*/5 * * * * (cd /home/savvy/FloatWeb/adminsavvy/CRONS/ && php -f member_prepare_notification.php)
*/5 * * * * (cd /home/savvy/FloatWeb/adminsavvy/CRONS/ && php -f member_lifecyle_emails.php)
*/5 * * * * (cd /home/savvy/FloatWeb/adminsavvy/CRONS/ && php -f account_benefit_import.php)
*/35 * * * * (cd /home/savvy/FloatWeb/adminsavvy/CRONS/ && php -f account_process_subscription.php)
## */5 * * * * (cd /home/savvy/FloatWeb/adminsavvy/CRONS/ && php -f account_benefit_import.php)
# run five minutes after 4am (12 pm Singapore), every day
##5 4 * * * (cd /home/savvy/FloatWeb/adminsavvy/CRONS/batch && php -f batch_quote_tourist_attractions.php > batch_quote_tourist_attractions.log 2>&1)
*/4 * * * * (cd /home/savvy/FloatWeb/adminsavvy/CRONS/ && php -f decision_generator.php > decisison_generator.log 2>&1)
#*/60 * * * * (cd /home/savvy/FloatWeb/adminsavvy/CRONS/ && php -f member_tracking_duration.php)
*/15 * * * * (cd /home/savvy/FloatWeb/adminsavvy/CRONS/ && php -f geocode_address.php)
*/5 * * * * (cd /home/savvy/FloatWeb/adminsavvy/CRONS/ && php -f account_audit.php)
*/5 * * * * (cd /home/savvy/FloatWeb/adminsavvy/CRONS/ && php -f points_audit.php)
*/6 * * * * (cd /home/savvy/FloatWeb/adminsavvy/CRONS/ && php -f update_address_data.php)
*/20 * * * * (cd /home/savvy/FloatWeb/adminsavvy/CRONS/ && php -f update_cheapest_data.php > update_cheapest_data.log 2>&1)
*/5 * * * * (cd /home/savvy/FloatWeb/adminsavvy/CRONS/ && php -f gps_parsedemail_item_sync.php)
*/60 * * * * (cd /home/savvy/FloatWeb/adminsavvy/CRONS/ && php -f gps_parsedemail_item_sync_skipped.php)
*/5 * * * * (cd /home/savvy/FloatWeb/adminsavvy/CRONS/ && php -f account_location_audit.php)
*/60 * * * * (cd /home/savvy/FloatWeb/adminsavvy/CRONS/ && php -f members_devices_check.php)
#45 10 * * * /usr/local/bin/report
3 1 * * * /usr/bin/supervisorctl restart worker_weather:
1 1 * * * /bin/systemctl restart supervisord.service
+40
View File
@@ -0,0 +1,40 @@
# use /bin/bash to run commands, no matter what /etc/passwd says
SHELL=/bin/bash
# mail any output to `paul', no matter whose crontab this is
MAILTO=olu@float.sg
# run five minutes after midnight, every day
5 0 * * * /home/savvy/backup.sh
*/2 * * * * (cd /home/savvy/FloatWeb/adminsavvy/CRONS/ && php -f account_record_import.php)
#*/60 * * * * (cd /home/savvy/FloatWeb/adminsavvy/CRONS/batch && php -f batch_quote_popular.php > batch_quote_popular.log 2>&1)
##*/60 * * * * (cd /home/savvy/FloatWeb/adminsavvy/CRONS/batch && php -f batch_quote_sanfrancisco_districts.php > batch_quote_sanfrancisco_districts.log 2>&1)
##*/30 * * * * (cd /home/savvy/FloatWeb/adminsavvy/CRONS/ && php -f background_quote_check.php > background_quote_check.log 2>&1)
*/30 * * * * (cd /home/savvy/FloatWeb/adminsavvy/CRONS/batch && php -f batch_absent_quote_singapore_districts.php > batch_absent_quote_singapore_districts.log 2>&1)
*/5 * * * * (cd /home/savvy/FloatWeb/adminsavvy/CRONS/ && php -f member_notification.php)
*/5 * * * * (cd /home/savvy/FloatWeb/adminsavvy/CRONS/ && php -f member_prepare_notification.php)
*/5 * * * * (cd /home/savvy/FloatWeb/adminsavvy/CRONS/ && php -f member_lifecyle_emails.php)
*/5 * * * * (cd /home/savvy/FloatWeb/adminsavvy/CRONS/ && php -f account_benefit_import.php)
*/5 * * * * (cd /home/savvy/FloatWeb/adminsavvy/CRONS/ && php -f transactions_record_import.php)
*/5 * * * * (cd /home/savvy/FloatWeb/adminsavvy/CRONS/ && php -f subscribed_summary.php)
# run 6:00 pm Singapore, every day
0 14 * * MON (cd /home/savvy/FloatWeb/adminsavvy/CRONS/ && php -f send_email_parse_fail_report.php)
# run five minutes after 4am (12 pm Singapore), every day
##5 4 * * * (cd /home/savvy/FloatWeb/adminsavvy/CRONS/batch && php -f batch_quote_tourist_attractions.php > batch_quote_tourist_attractions.log 2>&1)
*/4 * * * * (cd /home/savvy/FloatWeb/adminsavvy/CRONS/ && php -f decision_generator.php > decisison_generator.log 2>&1)
#*/60 * * * * (cd /home/savvy/FloatWeb/adminsavvy/CRONS/ && php -f member_tracking_duration.php)
*/15 * * * * (cd /home/savvy/FloatWeb/adminsavvy/CRONS/ && php -f geocode_address.php)
*/5 * * * * (cd /home/savvy/FloatWeb/adminsavvy/CRONS/ && php -f account_audit.php)
*/5 * * * * (cd /home/savvy/FloatWeb/adminsavvy/CRONS/ && php -f points_audit.php)
*/6 * * * * (cd /home/savvy/FloatWeb/adminsavvy/CRONS/ && php -f update_address_data.php)
*/20 * * * * (cd /home/savvy/FloatWeb/adminsavvy/CRONS/ && php -f update_cheapest_data.php > update_cheapest_data.log 2>&1)
*/5 * * * * (cd /home/savvy/FloatWeb/adminsavvy/CRONS/ && php -f gps_parsedemail_item_sync.php)
*/60 * * * * (cd /home/savvy/FloatWeb/adminsavvy/CRONS/ && php -f gps_parsedemail_item_sync_skipped.php)
*/5 * * * * (cd /home/savvy/FloatWeb/adminsavvy/CRONS/ && php -f account_location_audit.php)
*/60 * * * * (cd /home/savvy/FloatWeb/adminsavvy/CRONS/ && php -f members_devices_check.php)
0 1 * * 1 (cd /home/savvy/FloatWeb/adminsavvy/CRONS/ && php -f automation_report.php)
0 0 1 * * (cd /home/savvy/FloatWeb/adminsavvy/CRONS/ && php -f parking_lot.php)
#45 10 * * * /usr/local/bin/report
3 1 * * * /usr/bin/supervisorctl restart worker_weather:
1 1 * * * /bin/systemctl restart supervisord.service
# run At 18:00 NZST ~ 14:00 SG
0 14 * * * (cd /home/savvy/FloatWeb/adminsavvy/CRONS/ && php -f app_report_sign_up_emails_last_24hrs.php)
0 14 * * MON (cd /home/savvy/FloatWeb/adminsavvy/CRONS/ && php -f email_lists_for_customer_journey_emails.php)
+24
View File
@@ -0,0 +1,24 @@
<?php
echo "[".date("Y-m-d H:i:s")."] Daily Report job is starting.\n";
include '../backend.php';
define("FLOAT_SYSTEM_DAILY_REPORT", 91011);
function Fextension_call($in, &$out) {
// logToFl("Merchant_Name count->" . $in["merchant_name"]);
global $savvyext;
$out = $savvyext->savvyext_api($in);
$ret = $out["retval"];
return $ret;
}
$inX["limit"] = 750;
$inX["offset"] = 0;
$outX=array();
$extension_call = true;
if ($extension_call == true ) {
// logToFl("merchant_name count->" . $res->merchant_name);
Fextension_call($inX, $outX);
}
+25
View File
@@ -0,0 +1,25 @@
<?php
echo "[".date("Y-m-d H:i:s")."] Decision Generator job is starting.\n";
include '../backend.php';
define("FLOAT_SYSTEM_DESCISION_GENERATOR", 92012);
function Fextension_call($in, &$out) {
global $savvyext;
$out = $savvyext->savvyext_api($in);
$ret = $out["retval"];
return $ret;
}
$inX["limit"] = 50;
$inX["pid"] = 0;
$inX["action"] = FLOAT_SYSTEM_DESCISION_GENERATOR;
$outX=array();
$extension_call = true;
if ($extension_call == true ) {
Fextension_call($inX, $outX);
}
+236
View File
@@ -0,0 +1,236 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional //EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:v="urn:schemas-microsoft-com:vml">
<head>
<!--[if gte mso 9]><xml><o:OfficeDocumentSettings><o:AllowPNG/><o:PixelsPerInch>96</o:PixelsPerInch></o:OfficeDocumentSettings></xml><![endif]-->
<meta content="text/html; charset=utf-8" http-equiv="Content-Type"/>
<meta content="width=device-width" name="viewport"/>
<!--[if !mso]><!-->
<meta content="IE=edge" http-equiv="X-UA-Compatible"/>
<!--<![endif]-->
<title></title>
<!--[if !mso]><!-->
<!--<![endif]-->
<style type="text/css">
body {
margin: 0;
padding: 0;
}
table,
td,
tr {
vertical-align: top;
border-collapse: collapse;
}
* {
line-height: inherit;
}
a[x-apple-data-detectors=true] {
color: inherit !important;
text-decoration: none !important;
}
</style>
<style id="media-query" type="text/css">
@media (max-width: 660px) {
.block-grid,
.col {
min-width: 320px !important;
max-width: 100% !important;
display: block !important;
}
.block-grid {
width: 100% !important;
}
.col {
width: 100% !important;
}
.col>div {
margin: 0 auto;
}
img.fullwidth,
img.fullwidthOnMobile {
max-width: 100% !important;
}
.no-stack .col {
min-width: 0 !important;
display: table-cell !important;
}
.no-stack.two-up .col {
width: 50% !important;
}
.no-stack .col.num4 {
width: 33% !important;
}
.no-stack .col.num8 {
width: 66% !important;
}
.no-stack .col.num4 {
width: 33% !important;
}
.no-stack .col.num3 {
width: 25% !important;
}
.no-stack .col.num6 {
width: 50% !important;
}
.no-stack .col.num9 {
width: 75% !important;
}
.video-block {
max-width: none !important;
}
.mobile_hide {
min-height: 0px;
max-height: 0px;
max-width: 0px;
display: none;
overflow: hidden;
font-size: 0px;
}
.desktop_hide {
display: block !important;
max-height: none !important;
}
}
</style>
</head>
<body class="clean-body" style="margin: 0; padding: 0; -webkit-text-size-adjust: 100%; background-color: #FFFFFF;">
<!--[if IE]><div class="ie-browser"><![endif]-->
<table bgcolor="#FFFFFF" cellpadding="0" cellspacing="0" class="nl-container" role="presentation" style="table-layout: fixed; vertical-align: top; min-width: 320px; Margin: 0 auto; border-spacing: 0; border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; background-color: #FFFFFF; width: 100%;" valign="top" width="100%">
<tbody>
<tr style="vertical-align: top;" valign="top">
<td style="word-break: break-word; vertical-align: top;" valign="top">
<!--[if (mso)|(IE)]><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td align="center" style="background-color:#FFFFFF"><![endif]-->
<div style="background-color:transparent;">
<div class="block-grid" style="Margin: 0 auto; min-width: 320px; max-width: 640px; overflow-wrap: break-word; word-wrap: break-word; word-break: break-word; background-color: transparent;">
<div style="border-collapse: collapse;display: table;width: 100%;background-color:transparent;">
<!--[if (mso)|(IE)]><table width="100%" cellpadding="0" cellspacing="0" border="0" style="background-color:transparent;"><tr><td align="center"><table cellpadding="0" cellspacing="0" border="0" style="width:740px"><tr class="layout-full-width" style="background-color:transparent"><![endif]-->
<!--[if (mso)|(IE)]><td align="center" width="740" style="background-color:transparent;width:740px; border-top: 0px solid transparent; border-left: 0px solid transparent; border-bottom: 0px solid transparent; border-right: 0px solid transparent;" valign="top"><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="padding-right: 0px; padding-left: 0px; padding-top:5px; padding-bottom:5px;"><![endif]-->
<div class="col num12" style="min-width: 320px; max-width: 640px; display: table-cell; vertical-align: top; width: 740px;">
<div style="width:100% !important;">
<!--[if (!mso)&(!IE)]><!-->
<div style="border-top:0px solid transparent; border-left:0px solid transparent; border-bottom:0px solid transparent; border-right:0px solid transparent; padding-top:5px; padding-bottom:5px; padding-right: 0px; padding-left: 0px;">
<!--<![endif]-->
<table border="0" cellpadding="0" cellspacing="0" class="divider" role="presentation" style="table-layout: fixed; vertical-align: top; border-spacing: 0; border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; min-width: 100%; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%;" valign="top" width="100%">
<tbody>
<tr style="vertical-align: top;" valign="top">
<td class="divider_inner" style="word-break: break-word; vertical-align: top; min-width: 100%; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%; padding-top: 10px; padding-right: 10px; padding-bottom: 10px; padding-left: 10px;" valign="top">
<table align="center" border="0" cellpadding="0" cellspacing="0" class="divider_content" role="presentation" style="table-layout: fixed; vertical-align: top; border-spacing: 0; border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; border-top: 0px solid #FFFFFF; width: 100%;" valign="top" width="100%">
<tbody>
<tr style="vertical-align: top;" valign="top">
<td style="word-break: break-word; vertical-align: top; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%;" valign="top"><span></span></td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<!--[if (!mso)&(!IE)]><!-->
</div>
<!--<![endif]-->
</div>
</div>
<!--[if (mso)|(IE)]></td></tr></table><![endif]-->
<!--[if (mso)|(IE)]></td></tr></table></td></tr></table><![endif]-->
</div>
</div>
</div>
<?php $job_name = pathinfo(__FILE__, PATHINFO_FILENAME); ?>
<div style="background-color:transparent;">
<div class="block-grid mixed-two-up" style="Margin: 0 auto; min-width: 320px; max-width: 640px; overflow-wrap: break-word; word-wrap: break-word; word-break: break-word; background-color: #5c98c7;">
<div style="border-collapse: collapse;display: table;width: 100%;background-color:#5c98c7;">
<!--[if (mso)|(IE)]><table width="100%" cellpadding="0" cellspacing="0" border="0" style="background-color:transparent;"><tr><td align="center"><table cellpadding="0" cellspacing="0" border="0" style="width:740px"><tr class="layout-full-width" style="background-color:#5c98c7"><![endif]-->
<!--[if (mso)|(IE)]><td align="center" width="426" style="background-color:#5c98c7;width:426px; border-top: 0px solid transparent; border-left: 0px solid transparent; border-bottom: 0px solid transparent; border-right: 0px solid transparent;" valign="top"><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="padding-right: 30px; padding-left: 30px; padding-top:20px; padding-bottom:20px;"><![endif]-->
<div class="col num8" style="display: table-cell; vertical-align: top; min-width: 320px; max-width: 424px; width: 426px;">
<div style="width:100% !important;">
<!--[if (!mso)&(!IE)]><!-->
<div style="border-top:0px solid transparent; border-left:0px solid transparent; border-bottom:0px solid transparent; border-right:0px solid transparent; padding-top:20px; padding-bottom:20px; padding-right: 30px; padding-left: 30px;">
<!--<![endif]-->
<!--[if mso]><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="padding-right: 10px; padding-left: 10px; padding-top: 10px; padding-bottom: 0px; font-family: Tahoma, Verdana, sans-serif"><![endif]-->
<div style="color:#ffffff;font-family:Lato, Tahoma, Verdana, Segoe, sans-serif;line-height:1.2;padding-top:10px;padding-right:10px;padding-bottom:0px;padding-left:10px;">
<div style="font-size: 14px; line-height: 1.2; color: #ffffff; font-family: Lato, Tahoma, Verdana, Segoe, sans-serif; mso-line-height-alt: 17px;">
<p style="font-size: 20px; line-height: 1.2; word-break: break-word; text-align: left; mso-line-height-alt: 24px; margin: 0;"><span style="font-size: 20px;"><strong><?php echo "[" . date("Y-m-d H:i:s") . "] " . $job_name . " job is starting.\n"; ?></strong></span></p>
</div>
</div>
<!--[if mso]></td></tr></table><![endif]-->
<!--[if mso]><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="padding-right: 10px; padding-left: 10px; padding-top: 0px; padding-bottom: 10px; font-family: Tahoma, Verdana, sans-serif"><![endif]-->
<!-- <div style="color:#ffffff;font-family:Lato, Tahoma, Verdana, Segoe, sans-serif;line-height:1.5;padding-top:0px;padding-right:10px;padding-bottom:10px;padding-left:10px;">
<div style="font-size: 14px; line-height: 1.5; color: #ffffff; font-family: Lato, Tahoma, Verdana, Segoe, sans-serif; mso-line-height-alt: 21px;">
<p style="font-size: 14px; line-height: 1.5; word-break: break-word; text-align: left; mso-line-height-alt: 21px; margin: 0;">Company Name LLC, represented by John Doe,</p>
<p style="font-size: 14px; line-height: 1.5; word-break: break-word; text-align: left; mso-line-height-alt: 21px; margin: 0;">ID: 020 5793 9378, Prairie Drive Far,</p>
<p style="font-size: 14px; line-height: 1.5; word-break: break-word; text-align: left; mso-line-height-alt: 21px; margin: 0;">Rockaway, Y 11691, US</p>
</div>
</div>
--> <!--[if mso]></td></tr></table><![endif]-->
<!--[if (!mso)&(!IE)]><!-->
</div>
<!--<![endif]-->
</div>
</div>
</div>
</div>
</div>
<!-- Start Automations Table -->
<div style="background-color:transparent;">
<div class="block-grid four-up no-stack" style="Margin: 0 auto; min-width: 320px; max-width: 640px; overflow-wrap: break-word; word-wrap: break-word; word-break: break-word; background-color: #5c98c7; text-align: center; color: #ffffff; padding-bottom: 10px; font-size: 22px;">
<strong>SendGrid Tracking Report</strong>
</div>
<div align="center" class="img-container center autowidth" style="padding-right: 0px;padding-left: 0px;">
<!--[if mso]><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr style="line-height:0px"><td style="padding-right: 0px;padding-left: 0px;" align="center"><![endif]--><img align="center" alt="Image" border="0" class="center autowidth" src="<?php echo $sendgrid_tracking; ?>" style="text-decoration: none; -ms-interpolation-mode: bicubic; height: auto; border: 0; width: 100%; max-width: 640px; display: block;" title="Image" width="481"/>
<!--[if mso]></td></tr></table><![endif]-->
</div>
</div>
<!-- Start Installed OS -->
<div style="background-color:transparent;">
<div class="block-grid four-up no-stack" style="Margin: 0 auto; min-width: 320px; max-width: 640px; overflow-wrap: break-word; word-wrap: break-word; word-break: break-word; background-color: #5c98c7; text-align: center; color: #ffffff; padding-bottom: 10px; font-size: 22px; padding-top: 20px;">
<strong>BKO Tracking Report</strong>
</div>
</div>
<div align="center" class="img-container center autowidth" style="padding-right: 0px;padding-left: 0px;">
<!--[if mso]><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr style="line-height:0px"><td style="padding-right: 0px;padding-left: 0px;" align="center"><![endif]--><img align="center" alt="Image" border="0" class="center autowidth" src="<?php echo $bko_tracking; ?>" style="text-decoration: none; -ms-interpolation-mode: bicubic; height: auto; border: 0; width: 100%; max-width: 640px; display: block;" title="Image" width="481"/>
<!--[if mso]></td></tr></table><![endif]-->
</div>
<!-- End Installed OS -->
<div style="background-color:transparent;">
<div class="block-grid" style="Margin: 0 auto; min-width: 320px; max-width: 640px; overflow-wrap: break-word; word-wrap: break-word; word-break: break-word; background-color: #5c98c7;">
<div style="border-collapse: collapse;display: table;width: 100%;background-color:#5c98c7;">
<!--[if (mso)|(IE)]><table width="100%" cellpadding="0" cellspacing="0" border="0" style="background-color:transparent;"><tr><td align="center"><table cellpadding="0" cellspacing="0" border="0" style="width:740px"><tr class="layout-full-width" style="background-color:#5c98c7"><![endif]-->
<!--[if (mso)|(IE)]><td align="center" width="740" style="background-color:#5c98c7;width:740px; border-top: 0px solid transparent; border-left: 0px solid transparent; border-bottom: 0px solid transparent; border-right: 0px solid transparent;" valign="top"><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="padding-right: 0px; padding-left: 0px; padding-top:0px; padding-bottom:0px;"><![endif]-->
<div class="col num12" style="min-width: 320px; max-width: 640px; display: table-cell; vertical-align: top; width: 740px;">
</div>
<!--[if (mso)|(IE)]></td></tr></table><![endif]-->
<!--[if (mso)|(IE)]></td></tr></table></td></tr></table><![endif]-->
</div>
</div>
</div>
<!--[if (mso)|(IE)]></td></tr></table><![endif]-->
</td>
</tr>
</tbody>
</table>
<!--[if (IE)]></div><![endif]-->
</body>
</html>
+179
View File
@@ -0,0 +1,179 @@
<mjml>
<mj-head>
<mj-font name="Open Sans" href="https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,800" />
<mj-attributes>
<mj-all font-family="Open Sans, sans-serif" color="#fff" />
</mj-attributes>
<mj-style>
</mj-style>
</mj-head>
<mj-body width="1000px">
<mj-wrapper padding="0">
<mj-section padding="0" background-color="#6da3cd">
<mj-column width="20%">
<mj-text font-weight="bold" align="center">
Merchant Name
</mj-text>
</mj-column>
<mj-column width="20%">
<mj-text font-weight="bold" align="center">
Transport
</mj-text>
</mj-column>
<mj-column width="20%">
<mj-text font-weight="bold" align="center">
Total Emails
</mj-text>
</mj-column>
<mj-column width="20%">
<mj-text font-weight="bold" align="center">
Success
</mj-text>
</mj-column>
<mj-column width="20%">
<mj-text font-weight="bold" align="center">
Fail
</mj-text>
</mj-column>
</mj-section>
<mj-section padding="0" background-color="#5c98c7" border-bottom="1px solid #6da3cd">
<mj-raw>
<?php if ( isset( $data['summary'] ) and ! empty( $data['summary'] ) ): ?>
<?php foreach ( $data['summary'] as $key => $item ): ?>
</mj-raw>
<mj-column width="20%">
<mj-text align="center">
<mj-raw>
<?php echo $item['name']; ?>
</mj-raw>
</mj-text>
</mj-column>
<mj-column width="20%">
<mj-text align="center">
<mj-raw>
<?php echo $item['transport']; ?>
</mj-raw>
</mj-text>
</mj-column>
<mj-column width="20%">
<mj-text align="center">
<mj-raw>
<?php echo $item['total']; ?>
</mj-raw>
</mj-text>
</mj-column>
<mj-column width="20%">
<mj-text align="center">
<mj-raw>
<?php echo $item['success']; ?>
</mj-raw>
</mj-text>
</mj-column>
<mj-column width="20%">
<mj-text align="center">
<mj-raw>
<?php echo $item['fail']; ?>
</mj-raw>
</mj-text>
</mj-column>
<mj-raw>
<?php endforeach ?>
<?php endif ?>
</mj-raw>
</mj-section>
</mj-wrapper>
<mj-wrapper padding-top="30px">
<mj-section padding="0" background-color="#6da3cd">
<mj-column width="17%">
<mj-text font-weight="bold" align="center">
Merchant Name
</mj-text>
</mj-column>
<mj-column width="15%">
<mj-text font-weight="bold" align="center">
Email ID
</mj-text>
</mj-column>
<mj-column width="20%">
<mj-text font-weight="bold" align="center">
User
</mj-text>
</mj-column>
<mj-column width="20%">
<mj-text font-weight="bold" align="center">
Subject
</mj-text>
</mj-column>
<mj-column width="15%">
<mj-text font-weight="bold" align="center">
Send Date
</mj-text>
</mj-column>
<mj-column width="13%">
<mj-text font-weight="bold" align="center">
Reported
</mj-text>
</mj-column>
</mj-section>
<mj-section padding="0" background-color="#5c98c7" border-bottom="1px solid #6da3cd">
<mj-raw>
<?php if ( isset( $data['emails'] ) and ! empty( $data['emails'] ) ): ?>
<?php foreach ( $data['emails'] as $key => $item ): ?>
</mj-raw>
<mj-column width="17%">
<mj-text align="center">
<mj-raw>
<?php echo $item['merchant_name']; ?>
</mj-raw>
</mj-text>
</mj-column>
<mj-column width="15%">
<mj-text align="center">
<mj-raw>
<?php echo $item['trackedemail_item_id']; ?>
</mj-raw>
</mj-text>
</mj-column>
<mj-column width="20%">
<mj-text align="center">
<mj-raw>
<?php echo $item['email']; ?> (ID: <?php echo $item['user_id']; ?>)
</mj-raw>
</mj-text>
</mj-column>
<mj-column width="20%">
<mj-text align="center">
<mj-raw>
<?php echo $item['subject']; ?>
</mj-raw>
</mj-text>
</mj-column>
<mj-column width="15%">
<mj-text align="center">
<mj-raw>
<?php echo $item['message_date']; ?>
</mj-raw>
</mj-text>
</mj-column>
<mj-column width="13%">
<mj-text align="center">
<?php echo $item['reported']; ?>
</mj-text>
</mj-column>
<mj-raw>
<?php endforeach ?>
<?php endif ?>
</mj-raw>
</mj-section>
</mj-wrapper>
</mj-body>
</mjml>
+695
View File
@@ -0,0 +1,695 @@
<!doctype html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
<head>
<title> </title>
<!--[if !mso]><!-- -->
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!--<![endif]-->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style type="text/css">
#outlook a {
padding: 0;
}
body {
margin: 0;
padding: 0;
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
}
table,
td {
border-collapse: collapse;
mso-table-lspace: 0pt;
mso-table-rspace: 0pt;
}
img {
border: 0;
height: auto;
line-height: 100%;
outline: none;
text-decoration: none;
-ms-interpolation-mode: bicubic;
}
p {
display: block;
margin: 13px 0;
}
</style>
<!--[if mso]>
<xml>
<o:OfficeDocumentSettings>
<o:AllowPNG/>
<o:PixelsPerInch>96</o:PixelsPerInch>
</o:OfficeDocumentSettings>
</xml>
<![endif]-->
<!--[if lte mso 11]>
<style type="text/css">
.mj-outlook-group-fix { width:100% !important; }
</style>
<![endif]-->
<!--[if !mso]><!-->
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,800" rel="stylesheet" type="text/css">
<style type="text/css">
@import url(https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,800);
</style>
<!--<![endif]-->
<style type="text/css">
@media only screen and (min-width:480px) {
.mj-column-per-20 {
width: 20% !important;
max-width: 20%;
}
.mj-column-per-17 {
width: 17% !important;
max-width: 17%;
}
.mj-column-per-15 {
width: 15% !important;
max-width: 15%;
}
.mj-column-per-13 {
width: 13% !important;
max-width: 13%;
}
}
</style>
<style type="text/css">
</style>
<style type="text/css"></style>
</head>
<body>
<div style="">
<!--[if mso | IE]>
<table
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:1000px;" width="1000"
>
<tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div style="margin:0px auto;max-width:1000px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
<tbody>
<tr>
<td style="direction:ltr;font-size:0px;padding:0;text-align:center;">
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td
class="" width="1000px"
>
<table
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:1000px;" width="1000"
>
<tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div style="background:#6da3cd;background-color:#6da3cd;margin:0px auto;max-width:1000px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="background:#6da3cd;background-color:#6da3cd;width:100%;">
<tbody>
<tr>
<td style="direction:ltr;font-size:0px;padding:0;text-align:center;">
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td
class="" style="vertical-align:top;width:200px;"
>
<![endif]-->
<div class="mj-column-per-20 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<tr>
<td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Open Sans, sans-serif;font-size:13px;font-weight:bold;line-height:1;text-align:center;color:#ffffff;">Merchant Name</div>
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
<td
class="" style="vertical-align:top;width:200px;"
>
<![endif]-->
<div class="mj-column-per-20 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<tr>
<td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Open Sans, sans-serif;font-size:13px;font-weight:bold;line-height:1;text-align:center;color:#ffffff;">Transport</div>
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
<td
class="" style="vertical-align:top;width:200px;"
>
<![endif]-->
<div class="mj-column-per-20 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<tr>
<td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Open Sans, sans-serif;font-size:13px;font-weight:bold;line-height:1;text-align:center;color:#ffffff;">Total Emails</div>
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
<td
class="" style="vertical-align:top;width:200px;"
>
<![endif]-->
<div class="mj-column-per-20 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<tr>
<td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Open Sans, sans-serif;font-size:13px;font-weight:bold;line-height:1;text-align:center;color:#ffffff;">Success</div>
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
<td
class="" style="vertical-align:top;width:200px;"
>
<![endif]-->
<div class="mj-column-per-20 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<tr>
<td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Open Sans, sans-serif;font-size:13px;font-weight:bold;line-height:1;text-align:center;color:#ffffff;">Fail</div>
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td
class="" width="1000px"
>
<table
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:1000px;" width="1000"
>
<tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div style="background:#5c98c7;background-color:#5c98c7;margin:0px auto;max-width:1000px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="background:#5c98c7;background-color:#5c98c7;width:100%;">
<tbody>
<tr>
<td style="border-bottom:1px solid #6da3cd;direction:ltr;font-size:0px;padding:0;text-align:center;">
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<![endif]-->
<?php if ( isset( $data['summary'] ) and ! empty( $data['summary'] ) ): ?>
<?php foreach ( $data['summary'] as $key => $item ): ?>
<!--[if mso | IE]>
<td
class="" style="vertical-align:top;width:200px;"
>
<![endif]-->
<div class="mj-column-per-20 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<tr>
<td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Open Sans, sans-serif;font-size:13px;line-height:1;text-align:center;color:#ffffff;">
<mj-raw>
<?php echo $item['name']; ?> </mj-raw>
</div>
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
<td
class="" style="vertical-align:top;width:200px;"
>
<![endif]-->
<div class="mj-column-per-20 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<tr>
<td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Open Sans, sans-serif;font-size:13px;line-height:1;text-align:center;color:#ffffff;">
<mj-raw>
<?php echo $item['transport']; ?> </mj-raw>
</div>
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
<td
class="" style="vertical-align:top;width:200px;"
>
<![endif]-->
<div class="mj-column-per-20 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<tr>
<td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Open Sans, sans-serif;font-size:13px;line-height:1;text-align:center;color:#ffffff;">
<mj-raw>
<?php echo $item['total']; ?> </mj-raw>
</div>
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
<td
class="" style="vertical-align:top;width:200px;"
>
<![endif]-->
<div class="mj-column-per-20 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<tr>
<td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Open Sans, sans-serif;font-size:13px;line-height:1;text-align:center;color:#ffffff;">
<mj-raw>
<?php echo $item['success']; ?> </mj-raw>
</div>
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
<td
class="" style="vertical-align:top;width:200px;"
>
<![endif]-->
<div class="mj-column-per-20 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<tr>
<td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Open Sans, sans-serif;font-size:13px;line-height:1;text-align:center;color:#ffffff;">
<mj-raw>
<?php echo $item['fail']; ?> </mj-raw>
</div>
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
<![endif]-->
<?php endforeach ?>
<?php endif ?>
<!--[if mso | IE]>
</tr>
</table>
<![endif]-->
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<table
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:1000px;" width="1000"
>
<tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div style="margin:0px auto;max-width:1000px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
<tbody>
<tr>
<td style="direction:ltr;font-size:0px;padding:20px 0;padding-top:30px;text-align:center;">
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td
class="" width="1000px"
>
<table
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:1000px;" width="1000"
>
<tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div style="background:#6da3cd;background-color:#6da3cd;margin:0px auto;max-width:1000px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="background:#6da3cd;background-color:#6da3cd;width:100%;">
<tbody>
<tr>
<td style="direction:ltr;font-size:0px;padding:0;text-align:center;">
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td
class="" style="vertical-align:top;width:170px;"
>
<![endif]-->
<div class="mj-column-per-17 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<tr>
<td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Open Sans, sans-serif;font-size:13px;font-weight:bold;line-height:1;text-align:center;color:#ffffff;">Merchant Name</div>
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
<td
class="" style="vertical-align:top;width:150px;"
>
<![endif]-->
<div class="mj-column-per-15 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<tr>
<td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Open Sans, sans-serif;font-size:13px;font-weight:bold;line-height:1;text-align:center;color:#ffffff;">Email ID</div>
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
<td
class="" style="vertical-align:top;width:200px;"
>
<![endif]-->
<div class="mj-column-per-20 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<tr>
<td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Open Sans, sans-serif;font-size:13px;font-weight:bold;line-height:1;text-align:center;color:#ffffff;">User</div>
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
<td
class="" style="vertical-align:top;width:200px;"
>
<![endif]-->
<div class="mj-column-per-20 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<tr>
<td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Open Sans, sans-serif;font-size:13px;font-weight:bold;line-height:1;text-align:center;color:#ffffff;">Subject</div>
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
<td
class="" style="vertical-align:top;width:150px;"
>
<![endif]-->
<div class="mj-column-per-15 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<tr>
<td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Open Sans, sans-serif;font-size:13px;font-weight:bold;line-height:1;text-align:center;color:#ffffff;">Send Date</div>
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
<td
class="" style="vertical-align:top;width:130px;"
>
<![endif]-->
<div class="mj-column-per-13 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<tr>
<td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Open Sans, sans-serif;font-size:13px;font-weight:bold;line-height:1;text-align:center;color:#ffffff;">Reported</div>
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td
class="" width="1000px"
>
<table
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:1000px;" width="1000"
>
<tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div style="background:#5c98c7;background-color:#5c98c7;margin:0px auto;max-width:1000px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="background:#5c98c7;background-color:#5c98c7;width:100%;">
<tbody>
<tr>
<td style="border-bottom:1px solid #6da3cd;direction:ltr;font-size:0px;padding:0;text-align:center;">
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<![endif]-->
<?php if ( isset( $data['emails'] ) and ! empty( $data['emails'] ) ): ?>
<?php foreach ( $data['emails'] as $key => $item ): ?>
<!--[if mso | IE]>
<td
class="" style="vertical-align:top;width:170px;"
>
<![endif]-->
<div class="mj-column-per-17 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<tr>
<td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Open Sans, sans-serif;font-size:13px;line-height:1;text-align:center;color:#ffffff;">
<mj-raw>
<?php echo $item['merchant_name']; ?> </mj-raw>
</div>
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
<td
class="" style="vertical-align:top;width:150px;"
>
<![endif]-->
<div class="mj-column-per-15 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<tr>
<td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Open Sans, sans-serif;font-size:13px;line-height:1;text-align:center;color:#ffffff;">
<mj-raw>
<?php echo $item['trackedemail_item_id']; ?> </mj-raw>
</div>
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
<td
class="" style="vertical-align:top;width:200px;"
>
<![endif]-->
<div class="mj-column-per-20 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<tr>
<td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Open Sans, sans-serif;font-size:13px;line-height:1;text-align:center;color:#ffffff;">
<mj-raw>
<?php echo $item['email']; ?> (ID:
<?php echo $item['user_id']; ?>) </mj-raw>
</div>
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
<td
class="" style="vertical-align:top;width:200px;"
>
<![endif]-->
<div class="mj-column-per-20 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<tr>
<td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Open Sans, sans-serif;font-size:13px;line-height:1;text-align:center;color:#ffffff;">
<mj-raw>
<?php echo $item['subject']; ?> </mj-raw>
</div>
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
<td
class="" style="vertical-align:top;width:150px;"
>
<![endif]-->
<div class="mj-column-per-15 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<tr>
<td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Open Sans, sans-serif;font-size:13px;line-height:1;text-align:center;color:#ffffff;">
<mj-raw>
<?php echo $item['message_date']; ?> </mj-raw>
</div>
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
<td
class="" style="vertical-align:top;width:130px;"
>
<![endif]-->
<div class="mj-column-per-13 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<tr>
<td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Open Sans, sans-serif;font-size:13px;line-height:1;text-align:center;color:#ffffff;">
<?php echo $item['reported']; ?>
</div>
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
<![endif]-->
<?php endforeach ?>
<?php endif ?>
<!--[if mso | IE]>
</tr>
</table>
<![endif]-->
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</div>
</body>
</html>
@@ -0,0 +1,395 @@
<!doctype html>
<html>
<head>
<meta name="viewport" content="width=device-width"/>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>Simple Transactional Email</title>
<style>
/* -------------------------------------
GLOBAL RESETS
------------------------------------- */
/*All the styling goes here*/
img {
border: none;
-ms-interpolation-mode: bicubic;
max-width: 100%;
}
body {
background-color: #f6f6f6;
font-family: sans-serif;
-webkit-font-smoothing: antialiased;
font-size: 14px;
line-height: 1.4;
margin: 0;
padding: 0;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
}
table {
border-collapse: separate;
mso-table-lspace: 0pt;
mso-table-rspace: 0pt;
width: 100%;
}
table td {
font-family: sans-serif;
font-size: 14px;
vertical-align: top;
}
/* -------------------------------------
BODY & CONTAINER
------------------------------------- */
.body {
background-color: #f6f6f6;
width: 100%;
}
/* Set a max-width, and make it display as block so it will automatically stretch to that width, but will also shrink down on a phone or something */
.container {
display: block;
margin: 0 auto !important;
/* makes it centered */
max-width: 580px;
padding: 10px;
width: 580px;
}
/* This should also be a block element, so that it will fill 100% of the .container */
.content {
box-sizing: border-box;
display: block;
margin: 0 auto;
max-width: 580px;
padding: 10px;
}
/* -------------------------------------
HEADER, FOOTER, MAIN
------------------------------------- */
.main {
background: #ffffff;
border-radius: 3px;
width: 100%;
}
.wrapper {
box-sizing: border-box;
padding: 20px;
}
.content-block {
padding-bottom: 10px;
padding-top: 10px;
}
.footer {
clear: both;
margin-top: 10px;
text-align: center;
width: 100%;
}
.footer td,
.footer p,
.footer span,
.footer a {
color: #999999;
font-size: 12px;
text-align: center;
}
/* -------------------------------------
TYPOGRAPHY
------------------------------------- */
h1,
h2,
h3,
h4 {
color: #000000;
font-family: sans-serif;
font-weight: 400;
line-height: 1.4;
margin: 0;
margin-bottom: 30px;
}
h1 {
font-size: 35px;
font-weight: 300;
text-align: center;
text-transform: capitalize;
}
p,
ul,
ol {
font-family: sans-serif;
font-size: 14px;
font-weight: normal;
margin: 0;
margin-bottom: 15px;
}
p li,
ul li,
ol li {
list-style-position: inside;
margin-left: 5px;
}
a {
color: #3498db;
text-decoration: underline;
}
/* -------------------------------------
BUTTONS
------------------------------------- */
.btn {
box-sizing: border-box;
width: 100%;
}
.btn > tbody > tr > td {
padding-bottom: 15px;
}
.btn table {
width: auto;
}
.btn table td {
background-color: #ffffff;
border-radius: 5px;
text-align: center;
}
.btn a {
background-color: #ffffff;
border: solid 1px #3498db;
border-radius: 5px;
box-sizing: border-box;
color: #3498db;
cursor: pointer;
display: inline-block;
font-size: 14px;
font-weight: bold;
margin: 0;
padding: 12px 25px;
text-decoration: none;
text-transform: capitalize;
}
.btn-primary table td {
background-color: #3498db;
}
.btn-primary a {
background-color: #3498db;
border-color: #3498db;
color: #ffffff;
}
/* -------------------------------------
OTHER STYLES THAT MIGHT BE USEFUL
------------------------------------- */
.last {
margin-bottom: 0;
}
.first {
margin-top: 0;
}
.align-center {
text-align: center;
}
.align-right {
text-align: right;
}
.align-left {
text-align: left;
}
.clear {
clear: both;
}
.mt0 {
margin-top: 0;
}
.mb0 {
margin-bottom: 0;
}
.preheader {
color: transparent;
display: none;
height: 0;
max-height: 0;
max-width: 0;
opacity: 0;
overflow: hidden;
mso-hide: all;
visibility: hidden;
width: 0;
}
.powered-by a {
text-decoration: none;
}
hr {
border: 0;
border-bottom: 1px solid #f6f6f6;
margin: 20px 0;
}
/* -------------------------------------
RESPONSIVE AND MOBILE FRIENDLY STYLES
------------------------------------- */
@media only screen and (max-width: 620px) {
table[class=body] h1 {
font-size: 28px !important;
margin-bottom: 10px !important;
}
table[class=body] p,
table[class=body] ul,
table[class=body] ol,
table[class=body] td,
table[class=body] span,
table[class=body] a {
font-size: 16px !important;
}
table[class=body] .wrapper,
table[class=body] .article {
padding: 10px !important;
}
table[class=body] .content {
padding: 0 !important;
}
table[class=body] .container {
padding: 0 !important;
width: 100% !important;
}
table[class=body] .main {
border-left-width: 0 !important;
border-radius: 0 !important;
border-right-width: 0 !important;
}
table[class=body] .btn table {
width: 100% !important;
}
table[class=body] .btn a {
width: 100% !important;
}
table[class=body] .img-responsive {
height: auto !important;
max-width: 100% !important;
width: auto !important;
}
}
/* -------------------------------------
PRESERVE THESE STYLES IN THE HEAD
------------------------------------- */
@media all {
.ExternalClass {
width: 100%;
}
.ExternalClass,
.ExternalClass p,
.ExternalClass span,
.ExternalClass font,
.ExternalClass td,
.ExternalClass div {
line-height: 100%;
}
.apple-link a {
color: inherit !important;
font-family: inherit !important;
font-size: inherit !important;
font-weight: inherit !important;
line-height: inherit !important;
text-decoration: none !important;
}
#MessageViewBody a {
color: inherit;
text-decoration: none;
font-size: inherit;
font-family: inherit;
font-weight: inherit;
line-height: inherit;
}
.btn-primary table td:hover {
background-color: #34495e !important;
}
.btn-primary a:hover {
background-color: #34495e !important;
border-color: #34495e !important;
}
}
</style>
</head>
<body class="">
<span class="preheader">Email lists for customer journey emails weekly report <?= $short_date ?? '' ?></span>
<table role="presentation" border="0" cellpadding="0" cellspacing="0" class="body">
<tr>
<td>&nbsp;</td>
<td class="container">
<div class="content">
<!-- START CENTERED WHITE CONTAINER -->
<table role="presentation" class="main">
<!-- START MAIN CONTENT AREA -->
<tr>
<td class="wrapper">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td>
<p><?= $short_date ?? '' ?></p>
<p>Hi there,</p>
<p>Here is the weekly report of Email lists for customer journey emails</p>
<p>Please, find the report attached.</p>
<p>Good luck!</p>
</td>
</tr>
</table>
</td>
</tr>
<!-- END MAIN CONTENT AREA -->
</table>
<!-- END CENTERED WHITE CONTAINER -->
</div>
</td>
<td>&nbsp;</td>
</tr>
</table>
</body>
</html>
+395
View File
@@ -0,0 +1,395 @@
<!doctype html>
<html>
<head>
<meta name="viewport" content="width=device-width"/>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>Simple Transactional Email</title>
<style>
/* -------------------------------------
GLOBAL RESETS
------------------------------------- */
/*All the styling goes here*/
img {
border: none;
-ms-interpolation-mode: bicubic;
max-width: 100%;
}
body {
background-color: #f6f6f6;
font-family: sans-serif;
-webkit-font-smoothing: antialiased;
font-size: 14px;
line-height: 1.4;
margin: 0;
padding: 0;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
}
table {
border-collapse: separate;
mso-table-lspace: 0pt;
mso-table-rspace: 0pt;
width: 100%;
}
table td {
font-family: sans-serif;
font-size: 14px;
vertical-align: top;
}
/* -------------------------------------
BODY & CONTAINER
------------------------------------- */
.body {
background-color: #f6f6f6;
width: 100%;
}
/* Set a max-width, and make it display as block so it will automatically stretch to that width, but will also shrink down on a phone or something */
.container {
display: block;
margin: 0 auto !important;
/* makes it centered */
max-width: 580px;
padding: 10px;
width: 580px;
}
/* This should also be a block element, so that it will fill 100% of the .container */
.content {
box-sizing: border-box;
display: block;
margin: 0 auto;
max-width: 580px;
padding: 10px;
}
/* -------------------------------------
HEADER, FOOTER, MAIN
------------------------------------- */
.main {
background: #ffffff;
border-radius: 3px;
width: 100%;
}
.wrapper {
box-sizing: border-box;
padding: 20px;
}
.content-block {
padding-bottom: 10px;
padding-top: 10px;
}
.footer {
clear: both;
margin-top: 10px;
text-align: center;
width: 100%;
}
.footer td,
.footer p,
.footer span,
.footer a {
color: #999999;
font-size: 12px;
text-align: center;
}
/* -------------------------------------
TYPOGRAPHY
------------------------------------- */
h1,
h2,
h3,
h4 {
color: #000000;
font-family: sans-serif;
font-weight: 400;
line-height: 1.4;
margin: 0;
margin-bottom: 30px;
}
h1 {
font-size: 35px;
font-weight: 300;
text-align: center;
text-transform: capitalize;
}
p,
ul,
ol {
font-family: sans-serif;
font-size: 14px;
font-weight: normal;
margin: 0;
margin-bottom: 15px;
}
p li,
ul li,
ol li {
list-style-position: inside;
margin-left: 5px;
}
a {
color: #3498db;
text-decoration: underline;
}
/* -------------------------------------
BUTTONS
------------------------------------- */
.btn {
box-sizing: border-box;
width: 100%;
}
.btn > tbody > tr > td {
padding-bottom: 15px;
}
.btn table {
width: auto;
}
.btn table td {
background-color: #ffffff;
border-radius: 5px;
text-align: center;
}
.btn a {
background-color: #ffffff;
border: solid 1px #3498db;
border-radius: 5px;
box-sizing: border-box;
color: #3498db;
cursor: pointer;
display: inline-block;
font-size: 14px;
font-weight: bold;
margin: 0;
padding: 12px 25px;
text-decoration: none;
text-transform: capitalize;
}
.btn-primary table td {
background-color: #3498db;
}
.btn-primary a {
background-color: #3498db;
border-color: #3498db;
color: #ffffff;
}
/* -------------------------------------
OTHER STYLES THAT MIGHT BE USEFUL
------------------------------------- */
.last {
margin-bottom: 0;
}
.first {
margin-top: 0;
}
.align-center {
text-align: center;
}
.align-right {
text-align: right;
}
.align-left {
text-align: left;
}
.clear {
clear: both;
}
.mt0 {
margin-top: 0;
}
.mb0 {
margin-bottom: 0;
}
.preheader {
color: transparent;
display: none;
height: 0;
max-height: 0;
max-width: 0;
opacity: 0;
overflow: hidden;
mso-hide: all;
visibility: hidden;
width: 0;
}
.powered-by a {
text-decoration: none;
}
hr {
border: 0;
border-bottom: 1px solid #f6f6f6;
margin: 20px 0;
}
/* -------------------------------------
RESPONSIVE AND MOBILE FRIENDLY STYLES
------------------------------------- */
@media only screen and (max-width: 620px) {
table[class=body] h1 {
font-size: 28px !important;
margin-bottom: 10px !important;
}
table[class=body] p,
table[class=body] ul,
table[class=body] ol,
table[class=body] td,
table[class=body] span,
table[class=body] a {
font-size: 16px !important;
}
table[class=body] .wrapper,
table[class=body] .article {
padding: 10px !important;
}
table[class=body] .content {
padding: 0 !important;
}
table[class=body] .container {
padding: 0 !important;
width: 100% !important;
}
table[class=body] .main {
border-left-width: 0 !important;
border-radius: 0 !important;
border-right-width: 0 !important;
}
table[class=body] .btn table {
width: 100% !important;
}
table[class=body] .btn a {
width: 100% !important;
}
table[class=body] .img-responsive {
height: auto !important;
max-width: 100% !important;
width: auto !important;
}
}
/* -------------------------------------
PRESERVE THESE STYLES IN THE HEAD
------------------------------------- */
@media all {
.ExternalClass {
width: 100%;
}
.ExternalClass,
.ExternalClass p,
.ExternalClass span,
.ExternalClass font,
.ExternalClass td,
.ExternalClass div {
line-height: 100%;
}
.apple-link a {
color: inherit !important;
font-family: inherit !important;
font-size: inherit !important;
font-weight: inherit !important;
line-height: inherit !important;
text-decoration: none !important;
}
#MessageViewBody a {
color: inherit;
text-decoration: none;
font-size: inherit;
font-family: inherit;
font-weight: inherit;
line-height: inherit;
}
.btn-primary table td:hover {
background-color: #34495e !important;
}
.btn-primary a:hover {
background-color: #34495e !important;
border-color: #34495e !important;
}
}
</style>
</head>
<body class="">
<span class="preheader">Float App sign up emails last 24 hours daily report <?= $short_date ?? '' ?></span>
<table role="presentation" border="0" cellpadding="0" cellspacing="0" class="body">
<tr>
<td>&nbsp;</td>
<td class="container">
<div class="content">
<!-- START CENTERED WHITE CONTAINER -->
<table role="presentation" class="main">
<!-- START MAIN CONTENT AREA -->
<tr>
<td class="wrapper">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td>
<p><?= $short_date ?? '' ?></p>
<p>Hi there,</p>
<p>Here is the report of Float App Sign up emails last 24 hours</p>
<p>Please, find the report attached.</p>
<p>Good luck!</p>
</td>
</tr>
</table>
</td>
</tr>
<!-- END MAIN CONTENT AREA -->
</table>
<!-- END CENTERED WHITE CONTAINER -->
</div>
</td>
<td>&nbsp;</td>
</tr>
</table>
</body>
</html>
@@ -0,0 +1,212 @@
<?php
// require_once( '/Users/osx/Sites/Float/adminsavvy/backend.php' );
include '../backend.php';
require_once('../vendor/autoload.php');
require_once('common/Logger.php');
use \SendGrid\Mail\Mail;
/**
* Send email Float App sign up emails last 24 hours daily report
*/
class EmailLast24hrsReport
{
public $conn;
public $repConn;
public $sendgrid_api;
public $sender;
public $sender_name;
public $receivers;
protected $hard_limit = 550;
function __construct()
{
global $savvyext;
$this->conn = self::__cnn($savvyext);
$this->repConn = self::__repCnn($savvyext);
$this->sendgrid_api = $savvyext->cfgReadChar('mailsend.api_key');
$this->sender = $savvyext->cfgReadChar('mailsend.from');
$this->sender_name = $savvyext->cfgReadChar('mailsend.name');
$this->receivers = array(
'jervis@float.sg' => 'Jervis',
'tnguyen@float.sg' => 'Tri Nguyen',
);
}
private static function __cnn($savvyext)
{
$db_host = $savvyext->cfgReadChar('database.host');
$db_name = $savvyext->cfgReadChar('database.name');
$db_user = $savvyext->cfgReadChar('database.user');
$db_pass = $savvyext->cfgReadChar('database.pass');
$db_port = $savvyext->cfgReadLong('database.port');
$connstr = sprintf('host=%s port=%s dbname=%s user=%s password=%s', $db_host, $db_port, $db_name, $db_user, $db_pass);
$conn = pg_connect($connstr);
return $conn;
}
private static function __repCnn($savvyext)
{
$db_host = $savvyext->cfgReadChar('database_replica.host');
$db_name = $savvyext->cfgReadChar('database_replica.name');
$db_user = $savvyext->cfgReadChar('database_replica.user');
$db_pass = $savvyext->cfgReadChar('database_replica.pass');
$db_port = $savvyext->cfgReadLong('database_replica.port');
$connstr = sprintf('host=%s port=%s dbname=%s user=%s password=%s', $db_host, $db_port, $db_name, $db_user, $db_pass);
$conn = pg_connect($connstr);
return $conn;
}
private function array2csv($data, $delimiter = ',', $enclosure = '"', $escape_char = "\\")
{
$f = fopen('php://memory', 'r+');
foreach ($data as $item) {
fputcsv($f, $item, $delimiter, $enclosure, $escape_char);
}
rewind($f);
return stream_get_contents($f);
}
/**
* Send email report via SendGrid
* @param array $data list email fail
* @return mixed
*/
protected function send($data)
{
$short_date = (new \DateTime())->format('Y-M-d');
// create email layout
ob_start();
require_once(__DIR__ . '/email/email_lists_for_customer_journey_emails.php');
$layout = ob_get_clean();
// create sendgrid instance
$sendgrid = new \SendGrid\Mail\Mail;
$sendgrid->setFrom($this->sender, $this->sender_name);
$sendgrid->setSubject('Email lists for customer journey emails weekly report');
$sendgrid->addTos($this->receivers);
$sendgrid->addContent('text/html', $layout);
//HEADER of csv files
array_unshift($data,[
'First name', 'Last name', 'Email address', 'Sync email', 'Latest account activity', 'Made trip', 'Latest trip made', 'Sync bank account', 'Latest bank activity'
]);
$att1 = new \SendGrid\Mail\Attachment();
//$att1->setContent( file_get_contents("test_files/1/1.txt") );
$att1->setContent( $this->array2csv($data) );
$att1->setType("text/csv");
$att1->setFilename("email_lists_for_customer_journey_emails-weekly-report-".$short_date.".csv");
$att1->setDisposition("attachment");
$sendgrid->addAttachment( $att1 );
// send
$send = new \SendGrid($this->sendgrid_api);
$response = $send->send($sendgrid);
if ($response->statusCode() !== 202) {
throw new Exception('Send email via Sendgrid get errors!');
}
}
public function getemails()
{
try {
$sql = "
SELECT id, firstname, lastname, email,
CASE WHEN email_connected = 1 THEN 'TRUE' ELSE 'FALSE' END AS email_connected,
updated as latest_account_activity
FROM members
WHERE id > 0
ORDER BY id ASC
LIMIT 5000 OFFSET 0";
$query = pg_query($this->repConn, $sql);
$users = pg_fetch_all($query);
$sql = "
SELECT member_id, MAX(added) as latest_trip_made
FROM members_trips
GROUP BY member_id
ORDER BY member_id ASC";
$query = pg_query($this->repConn, $sql);
$usersMadeTrip = pg_fetch_all($query);
$sql = "
SELECT member_id, MAX(added) as latest_bank_activity
FROM members_bank_accounts
WHERE bank_login_status = 'active'
GROUP BY member_id
ORDER BY member_id ASC";
$query = pg_query($this->repConn, $sql);
$usersSyncBank = pg_fetch_all($query);
if ($error = pg_last_error($this->repConn)) {
throw new Exception($error);
}
foreach ($users as &$user) {
foreach ($usersMadeTrip as $tempUser) {
if ($tempUser['member_id'] == $user['id']) {
$user['made_trip'] = 'TRUE';
$user['latest_trip_made'] = $tempUser['latest_trip_made'];
break;
}
}
foreach ($usersSyncBank as $tempUser) {
if ($tempUser['member_id'] == $user['id']) {
$user['sync_bank'] = 'TRUE';
$user['latest_bank_activity'] = $tempUser['latest_bank_activity'];
break;
}
}
if (!isset($user['made_trip'])) {
$user['made_trip'] = 'FALSE';
$user['latest_trip_made'] = '';
}
if (!isset($user['sync_bank'])) {
$user['sync_bank'] = 'FALSE';
$user['latest_bank_activity'] = '';
}
}
foreach ($users as &$user) {
array_shift($user);
}
return $users;
} catch (Exception $e) {
Logger::debug($e->getMessage());
}
}
/**
* Excute jobs
* @return mixed
*/
public function excute()
{
try {
$data = $this->getemails();
$send = $this->send($data);
} catch (Exception $e) {
Logger::debug($e->getMessage());
}
}
}
$instace = new EmailLast24hrsReport;
$instace->excute();
+140
View File
@@ -0,0 +1,140 @@
<?php
echo "[".date("Y-m-d H:i:s")."] GPS geocode_address job is starting.\n";
exit();
require('../backend.php');
$httpAuthToken = $savvyext->cfgReadChar('system.oauth2_token');
$db_host = $savvyext->cfgReadChar('database.host');
$db_name = $savvyext->cfgReadChar('database.name');
$db_user = $savvyext->cfgReadChar('database.user');
$db_pass = $savvyext->cfgReadChar('database.pass');
$db_port = $savvyext->cfgReadLong('database.port');
$connstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$conn = pg_connect($connstr);
$db_host = $savvyext->cfgReadChar('database_replica.host');
$db_name = $savvyext->cfgReadChar('database_replica.name');
$db_user = $savvyext->cfgReadChar('database_replica.user');
$db_pass = $savvyext->cfgReadChar('database_replica.pass');
$db_port = $savvyext->cfgReadLong('database_replica.port');
$readOnlyReplicaConnstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$readOnlyReplicaConn = pg_connect($readOnlyReplicaConnstr);
$q = "SELECT * FROM address WHERE geocoding_date IS NULL OR country IS NULL";
$r = pg_query($readOnlyReplicaConn, $q);
while ($f=pg_fetch_assoc($r)) {
if ($f["address"]=="") continue;
$q0 = "SELECT * FROM address WHERE lower(address)=lower('".pg_escape_string($f["address"])."') AND id<>".$f["id"];
$q0.= " AND latitude!=0 AND longitude!=0 AND geocoding_date IS NOT NULL ORDER BY geocoding_date DESC LIMIT 1";
$r0 = pg_query($readOnlyReplicaConn, $q0);
if ($r0 && pg_num_rows($r0) && $f0=pg_fetch_assoc($r0) && $f0["country"]!="") {
echo "[".date("Y-m-d H:i:s")."] Already geocoded: ".$f["id"]." => ".$f0["id"].".\n";
unset($f0["id"]);
list($res,$err) = updateAddress($f["id"], $f0);
if ($err && $err!="") {
echo "[".date("Y-m-d H:i:s")."] Failure: ${err} (".$f["id"].")\n";
} else {
echo "[".date("Y-m-d H:i:s")."] Complete: ".$f["id"]."\n";
}
} else {
// Geocode
list($res,$err) = geocodeAddress($f["address"]);
if ($res && $err==NULL) {
if (array_key_exists("lat",$res) && array_key_exists("lng",$res)) {
$tz = $res["timeZoneId"];
if ($tz=="" || !is_int($tz)) {
$q1 = "SELECT id FROM address_timezone WHERE lower(timezone)=lower('".pg_escape_string($tz)."')";
$r1 = pg_query($readOnlyReplicaConn, $q1);
if ($r1 && pg_num_rows($r1) && $f1=pg_fetch_row($r1)) {
$tz = $f1[0];
} else {
echo "[".date("Y-m-d H:i:s")."] Invalid timezone: '${tz}' (".$f["id"].")\n";
$tz = 1;
}
}
$data = [
"latitude" => $res["lat"],
"longitude" => $res["lng"],
/*"address" => $res["address"],*/
"postal" => $res["postal"],
"country" => $res["country"],
"timezone" => $tz,
"geocoding_date" => date("Y-m-d"),
"geometry" => "ST_SetSRID(ST_MakePoint(".$res["lng"].",".$res["lat"]."), 4326)"
];
list($res,$err) = updateAddress($f["id"], $data);
if ($err && $err!="") {
echo "[".date("Y-m-d H:i:s")."] Failure: ${err} (".$f["id"].")\n";
} else {
echo "[".date("Y-m-d H:i:s")."] Complete: ".$f["id"]."\n";
}
} else {
echo "[".date("Y-m-d H:i:s")."] Invalid result: ".json_encode($res)." (".$f["id"].")\n";
}
} else {
echo "[".date("Y-m-d H:i:s")."] Failure: ${err} (".$f["id"].")\n";
}
}
}
function updateAddress($id, $data) {
global $conn, $readOnlyReplicaConn;
$columns = [];
$q = "select column_name, data_type, character_maximum_length from INFORMATION_SCHEMA.COLUMNS where table_name = 'address'";
$r = pg_query($readOnlyReplicaConn, $q);
while ($f=pg_fetch_assoc($r)) {
$columns[$f['column_name']] = $f['data_type'];
}
$q = "UPDATE address SET id=${id}";
foreach ($data as $key=>$val) {
if ($key=="id") continue;
if (array_key_exists($key,$columns) && $columns[$key]!='character varying' && $columns[$key]!='date') {
$q.= ", ${key} = ".($val==""?"NULL":$val);
} else {
$q.= ", ${key} = '".pg_escape_string($val)."'";
}
}
$q.= " WHERE id=${id} RETURNING *";
$r = pg_query($conn, $q);
if ($r && pg_num_rows($r) && $f=pg_fetch_assoc($r)) {
return [$f, NULL];
}
return [NULL, pg_last_error($conn)];
}
function geocodeAddress($address) {
global $httpAuthToken;
// Call geocoding service
$data = http_build_query(
array(
'address' => $address,
)
);
$url = "http://oauth2.service/api/v1/geocode?" . $data;
$opts = array(
'http' => array(
'method' => "GET",
'timeout' => 60, /* 1 minute */
'header' =>
"Content-Type: application/x-www-form-urlencoded\r\n" .
"Accept: application/json\r\n" .
"Authorization: Server-Token ${httpAuthToken}\r\n",
)
);
$context = stream_context_create($opts);
$body = file_get_contents($url, false, $context);
$geocoded = json_decode($body,true);
if (is_array($geocoded) && is_array($geocoded["data"]) && !isset($geocoded["error"])) {
// Cache the result in DB
return array($geocoded["data"], NULL);
} else if (is_array($geocoded) && isset($geocoded["error"])) {
$body = $geocoded["error"];
}
return array(NULL, "Geocoding service call error: ".$body);
}
echo "[".date("Y-m-d H:i:s")."] GPS geocode_address job complete.\n";
+179
View File
@@ -0,0 +1,179 @@
<?php
echo "[" . date("Y-m-d H:i:s") . "] GPS geocode_fix_address job is starting.\n";
require 'common/utils.php';
require 'common/config.php';
require 'common/address_city.php';
require 'common/Geocode.php';
$tables = getForeignTables('address');
$address_conditions = [
"POSITION('Your driver' in address)>0",
];
foreach ($address_conditions as $condition) {
$r = getAddressesByCondition($condition);
while ($fa = pg_fetch_assoc($r)) {
$address_id = $fa['id'];
$address = $fa['address'];
echo $address;
$pos_driver = strpos(strtolower($address),'your driver');
if($pos_driver!=false){
$address = substr($address,0, $pos_driver);
}
$update_address = [
'address' => $address
];
updateDataTable('address', 'id=' . $address_id, $update_address);
}
}
$duplicates = getDuplicatedAddresses();
while ($f = pg_fetch_assoc($duplicates)) {
$latitude = $f['latitude'];
$longitude = $f['longitude'];
$condition = 'latitude = ' . $latitude . ' AND longitude=' . $longitude;
$addresses = getAddressesByCondition($condition);
$ids = [];
while ($fa = pg_fetch_assoc($addresses)) {
$ids[] = $fa['id'];
}
$id_keep = array_shift($ids);
if (count($ids) > 0) {
$sql = '';
foreach($ids as $foreign_id){
foreach ($tables as $ft) {
$table_name = $ft['table_name'];
$field = $ft['column_name'];
if ($table_name == 'tourist_attraction') {
continue;
}
$data_update = [
$field => $id_keep,
];
$condition_update_foreigns = "{$field} = " . $foreign_id;
updateDataTable($table_name, $condition_update_foreigns, $data_update);
}
deleteDataTable('tourist_attraction', ' address_id =' . $foreign_id);
deleteDataTable('address', ' id =' . $foreign_id);
}
}
}
//
$empty_time_zones = getAddressEmptyTimezone();
while ($fe = pg_fetch_assoc($empty_time_zones)) {
$address_id = $fe['id'];
$address = $fe['address'];
$timezone_id = $fe['timezone_id'];
$geoinfo = Geocode::geocodeAddress($address);
if (isset($geoinfo) && is_array($geoinfo)) {
$postal = $geoinfo['postal'];
$timezoneID = getTimeZoneID($geoinfo['timeZoneId']);
$update_address = [
'timezone' => $timezoneID
];
updateDataTable('address', 'id=' . $address_id, $update_address);
if ($timezoneID == $timezone_id) {
$timezoneName = $geoinfo['timeZoneId'];
$update_address_timezone = [
'timezone' => $timezoneName,
];
updateDataTable('address_timezone', 'id=' . $timezone_id, $update_address_timezone);
}
}
}
//get invalid address by condition
$address_conditions = [
#"address NOT ILIKE '%singap%' and country='SG'",
];
foreach ($address_conditions as $condition) {
$r = getAddressesByCondition($condition);
while ($fa = pg_fetch_assoc($r)) {
$address_id = $fa['id'];
$address = $fa['address'];
$latitude = $fa['latitude'];
$longitude = $fa['longitude'];
$geoinfo = Geocode::reverseGPS($latitude,$longitude);
if (isset($geoinfo) && is_array($geoinfo)) {
$postal = $geoinfo['postal'];
$timezone = getTimeZoneID($geoinfo['timeZoneId']);
$country = $geoinfo['country'];
$update_address = [
'postal' => $postal,
'timezone' => $timezone,
'country' => $country
];
updateDataTable('address', 'id=' . $address_id, $update_address);
}
}
}
//invalid postal
$address_conditions = [
#"postal<>'Singapore' and left(postal,1)<>'0' and left(postal,1)<>'1' and left(postal,1)<>'2' and left(postal,1)<>'3' and left(postal,1)<>'4' and left(postal,1)<>'5' and left(postal,1)<>'6' and left(postal,1)<>'7' and left(postal,1)<>'8' and left(postal,1)<>'9' and country<>'GB' and country<>'CA' and country<>'IE'",
#"postal is NULL or postal=''"
];
foreach ($address_conditions as $condition) {
$r = getAddressesByCondition($condition);
while ($fa = pg_fetch_assoc($r)) {
$address_id = $fa['id'];
$address = $fa['address'];
$latitude = $fa['latitude'];
$longitude = $fa['longitude'];
$geoinfo = Geocode::reverseGPS($latitude,$longitude);
if (isset($geoinfo) && is_array($geoinfo)) {
$postal = $geoinfo['postal'];
$country = isset($geoinfo['country'])?$geoinfo['country']:$fa['country'];
if(empty($postal)){
$postal = getPostalCode($latitude,$longitude,$country);
}
$timezone = getTimeZoneID($geoinfo['timeZoneId']);
$update_address = [
'postal' => $postal,
'timezone' => $timezone,
'country' => $country
];
updateDataTable('address', 'id=' . $address_id, $update_address);
}
}
}
echo "[" . date("Y-m-d H:i:s") . "] GPS geocode_fix_address job complete.\n";
function getDuplicatedAddresses()
{
global $readOnlyReplicaConn;
$q = "SELECT latitude, longitude, count(*)
FROM address
GROUP BY latitude, longitude
HAVING count(*) >1
ORDER BY count(*) DESC";
$r = pg_query($readOnlyReplicaConn, $q);
return $r;
}
function getAddressEmptyTimezone()
{
global $readOnlyReplicaConn;
$q = "SELECT a.id, a.address, a.latitude, a.longitude, b.id as timezone_id
FROM address a
LEFT JOIN address_timezone b ON a.timezone=b.id
WHERE b.timezone ='' OR b.timezone IS NULL";
$r = pg_query($readOnlyReplicaConn, $q);
return $r;
}
function getAddressesByCondition($condition)
{
global $readOnlyReplicaConn;
$q = "SELECT *
FROM address
WHERE " . $condition;
$r = pg_query($readOnlyReplicaConn, $q);
return $r;
}
+52
View File
@@ -0,0 +1,52 @@
<?php
echo "[" . date("Y-m-d H:i:s") . "] GPS geocode_fix_address job is starting.\n";
require 'common/utils.php';
require 'common/config.php';
require 'common/address_city.php';
require 'common/Geocode.php';
$conditions = [
"address ilike '%123 Yishun Street 11, Singapore%'",
];
$tables = getForeignTables('address');
foreach ($conditions as $condition) {
$addresses = getAddressesByCondition($condition);
$ids = [];
while ($fa = pg_fetch_assoc($addresses)) {
$ids[] = $fa['id'];
}
$id_keep = array_shift($ids);
if (count($ids) > 0) {
$sql = '';
foreach ($tables as $ft) {
$table_name = $ft['table_name'];
$field = $ft['column_name'];
if ($table_name == 'tourist_attraction') {
continue;
}
$data_update = [
$field => $id_keep,
];
$condition_update_foreigns = "{$field} IN (" . implode(",", $ids) . ")";
updateDataTable($table_name, $condition_update_foreigns, $data_update);
}
deleteDataTable('tourist_attraction', ' address_id IN(' . implode(",", $ids) . ')');
deleteDataTable('address', ' id IN(' . implode(",", $ids) . ')');
}
}
echo "[" . date("Y-m-d H:i:s") . "] GPS geocode_fix_address job complete.\n";
function getAddressesByCondition($condition)
{
global $readOnlyReplicaConn;
$q = "SELECT *
FROM address
WHERE " . $condition."
ORDER BY id desc";
$r = pg_query($readOnlyReplicaConn, $q);
return $r;
}
+175
View File
@@ -0,0 +1,175 @@
<?php
echo "[".date("Y-m-d H:i:s")."] GPS geocode_address job is starting.\n";
require('../backend.php');
$httpAuthToken = $savvyext->cfgReadChar('system.oauth2_token');
$db_host = $savvyext->cfgReadChar('database.host');
$db_name = $savvyext->cfgReadChar('database.name');
$db_user = $savvyext->cfgReadChar('database.user');
$db_pass = $savvyext->cfgReadChar('database.pass');
$db_port = $savvyext->cfgReadLong('database.port');
$connstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$conn = pg_connect($connstr);
$db_host = $savvyext->cfgReadChar('database_replica.host');
$db_name = $savvyext->cfgReadChar('database_replica.name');
$db_user = $savvyext->cfgReadChar('database_replica.user');
$db_pass = $savvyext->cfgReadChar('database_replica.pass');
$db_port = $savvyext->cfgReadLong('database_replica.port');
$readOnlyReplicaConnstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$readOnlyReplicaConn = pg_connect($readOnlyReplicaConnstr);
$q = "SELECT * FROM address WHERE country='SG' AND (LOWER(postal)='singapore' ";
$q.= " OR (postal='' AND address ILIKE '%singapore'))";
$r = pg_query($readOnlyReplicaConn, $q);
while ($f=pg_fetch_assoc($r)) {
if ($f["address"]=="") continue;
$q0 = "SELECT * FROM address WHERE lower(address)=lower('".pg_escape_string($f["address"])."') AND id<>".$f["id"];
$q0.= " AND postal<>'' AND LOWER(postal)<>'singapore' ORDER BY geocoding_date DESC LIMIT 1";
$r0 = pg_query($readOnlyReplicaConn, $q0);
if ($r0 && pg_num_rows($r0) && $f0=pg_fetch_assoc($r0) && $f0["country"]!="") {
echo "[".date("Y-m-d H:i:s")."] Already geocoded: ".$f["id"]." => ".$f0["id"].".\n";
unset($f0["id"]);
list($res,$err) = updateAddress($f["id"], $f0);
if ($err && $err!="") {
echo "[".date("Y-m-d H:i:s")."] Failure: ${err} (".$f["id"].")\n";
} else {
echo "[".date("Y-m-d H:i:s")."] Complete: ".$f["id"]."\n";
}
} else {
// Geocode
list($res,$err) = geocodeAddress($f["address"]);
if ($res && $err==NULL) {
if (array_key_exists("lat",$res) && array_key_exists("lng",$res)) {
$tz = $res["timeZoneId"];
if ($tz=="" || !is_int($tz)) {
$q1 = "SELECT id FROM address_timezone WHERE lower(timezone)=lower('".pg_escape_string($tz)."')";
$r1 = pg_query($readOnlyReplicaConn, $q1);
if ($r1 && pg_num_rows($r1) && $f1=pg_fetch_row($r1)) {
$tz = $f1[0];
} else {
echo "[".date("Y-m-d H:i:s")."] Invalid timezone: '${tz}' (".$f["id"].")\n";
$tz = 1;
}
} else {
echo "[".date("Y-m-d H:i:s")."] Timezone is OK: tz=${tz}\n";
}
if ($res["postal"]==="" || $res["postal"]=='Singapore') {
list($res1,$err1) = geocodeReverse($res["lat"],$res["lng"]);
$res["postal"] = $res1["postal"];
}
echo "[".date("Y-m-d H:i:s")."] postal=".$res["postal"]."\n";
$data = [
"latitude" => $res["lat"],
"longitude" => $res["lng"],
/*"address" => $res["address"],*/
"postal" => $res["postal"],
"country" => $res["country"],
"timezone" => $tz,
"geocoding_date" => date("Y-m-d"),
"geometry" => "ST_SetSRID(ST_MakePoint(".$res["lng"].",".$res["lat"]."), 4326)"
];
//var_dump($data);
list($res,$err) = updateAddress($f["id"], $data);
if ($err && $err!="") {
echo "[".date("Y-m-d H:i:s")."] Failure: ${err} (".$f["id"].")\n";
} else {
echo "[".date("Y-m-d H:i:s")."] Complete: ".$f["id"]."\n";
}
} else {
echo "[".date("Y-m-d H:i:s")."] Invalid result: ".json_encode($res)." (".$f["id"].")\n";
}
} else {
echo "[".date("Y-m-d H:i:s")."] Failure: ${err} (".$f["id"].")\n";
}
}
}
function updateAddress($id, $data) {
global $conn, $readOnlyReplicaConn;
$columns = [];
$q = "select column_name, data_type, character_maximum_length from INFORMATION_SCHEMA.COLUMNS where table_name = 'address'";
$r = pg_query($readOnlyReplicaConn, $q);
while ($f=pg_fetch_assoc($r)) {
$columns[$f['column_name']] = $f['data_type'];
}
$q = "UPDATE address SET id=${id}";
foreach ($data as $key=>$val) {
if ($key!="postal") continue;
if (array_key_exists($key,$columns) && $columns[$key]!='character varying' && $columns[$key]!='date') {
$q.= ", ${key} = ".($val==""?"NULL":$val);
} else {
$q.= ", ${key} = '".pg_escape_string($val)."'";
}
}
$q.= " WHERE id=${id} RETURNING *";
$r = pg_query($conn, $q);
if ($r && pg_num_rows($r) && $f=pg_fetch_assoc($r)) {
return [$f, NULL];
}
return [NULL, pg_last_error($conn)];
}
function geocodeAddress($address) {
global $httpAuthToken;
// Call geocoding service
$data = http_build_query(
array(
'address' => $address,
)
);
$url = "http://oauth2.service/api/v1/geocode?" . $data;
$opts = array(
'http' => array(
'method' => "GET",
'timeout' => 60, /* 1 minute */
'header' =>
"Content-Type: application/x-www-form-urlencoded\r\n" .
"Accept: application/json\r\n" .
"Authorization: Server-Token ${httpAuthToken}\r\n",
)
);
$context = stream_context_create($opts);
$body = file_get_contents($url, false, $context);
$geocoded = json_decode($body,true);
if (is_array($geocoded) && is_array($geocoded["data"]) && !isset($geocoded["error"])) {
// Cache the result in DB
return array($geocoded["data"], NULL);
} else if (is_array($geocoded) && isset($geocoded["error"])) {
$body = $geocoded["error"];
}
return array(NULL, "Geocoding service call error: ".$body);
}
function geocodeReverse($latitude,$longitude) {
global $httpAuthToken;
// Call geocoding service
$url = "http://oauth2.service/api/v1/reverse/" . $latitude . ',' . $longitude;
$opts = array(
'http' => array(
'method' => "GET",
'timeout' => 60, /* 1 minute */
'header' =>
"Content-Type: application/x-www-form-urlencoded\r\n" .
"Accept: application/json\r\n" .
"Authorization: Server-Token ${httpAuthToken}\r\n",
)
);
$context = stream_context_create($opts);
$body = file_get_contents($url, false, $context);
$geocoded = json_decode($body,true);
if (is_array($geocoded) && is_array($geocoded["data"]) && !isset($geocoded["error"])) {
// Cache the result in DB
return array($geocoded["data"], NULL);
} else if (is_array($geocoded) && isset($geocoded["error"])) {
$body = $geocoded["error"];
}
return array(NULL, "Geocoding service call error: ".$body);
}
echo "[".date("Y-m-d H:i:s")."] GPS geocode_address job complete.\n";
+143
View File
@@ -0,0 +1,143 @@
<?php
echo "[".date("Y-m-d H:i:s")."] GPS geocode_address job is starting.\n";
require('../backend.php');
$httpAuthToken = $savvyext->cfgReadChar('system.oauth2_token');
$db_host = $savvyext->cfgReadChar('database.host');
$db_name = $savvyext->cfgReadChar('database.name');
$db_user = $savvyext->cfgReadChar('database.user');
$db_pass = $savvyext->cfgReadChar('database.pass');
$db_port = $savvyext->cfgReadLong('database.port');
$connstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$conn = pg_connect($connstr);
$db_host = $savvyext->cfgReadChar('database_replica.host');
$db_name = $savvyext->cfgReadChar('database_replica.name');
$db_user = $savvyext->cfgReadChar('database_replica.user');
$db_pass = $savvyext->cfgReadChar('database_replica.pass');
$db_port = $savvyext->cfgReadLong('database_replica.port');
$readOnlyReplicaConnstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$readOnlyReplicaConn = pg_connect($readOnlyReplicaConnstr);
$q = "SELECT * FROM address WHERE timezone IS NULL OR timezone<1";
$r = pg_query($readOnlyReplicaConn, $q);
while ($f=pg_fetch_assoc($r)) {
if ($f["address"]=="") continue;
$q0 = "SELECT * FROM address WHERE lower(address)=lower('".pg_escape_string($f["address"])."') AND id<>".$f["id"];
$q0.= " AND timezone>0 ORDER BY geocoding_date DESC LIMIT 1";
$r0 = pg_query($readOnlyReplicaConn, $q0);
if ($r0 && pg_num_rows($r0) && $f0=pg_fetch_assoc($r0) && $f0["country"]!="") {
echo "[".date("Y-m-d H:i:s")."] Already geocoded: ".$f["id"]." => ".$f0["id"].".\n";
unset($f0["id"]);
list($res,$err) = updateAddress($f["id"], $f0);
if ($err && $err!="") {
echo "[".date("Y-m-d H:i:s")."] Failure: ${err} (".$f["id"].")\n";
} else {
echo "[".date("Y-m-d H:i:s")."] Complete: ".$f["id"]."\n";
}
} else {
// Geocode
list($res,$err) = geocodeAddress($f["address"]);
if ($res && $err==NULL) {
if (array_key_exists("lat",$res) && array_key_exists("lng",$res)) {
$tz = $res["timeZoneId"];
if ($tz=="" || !is_int($tz)) {
$q1 = "SELECT id FROM address_timezone WHERE lower(timezone)=lower('".pg_escape_string($tz)."')";
$r1 = pg_query($readOnlyReplicaConn, $q1);
if ($r1 && pg_num_rows($r1) && $f1=pg_fetch_row($r1)) {
$tz = $f1[0];
} else {
echo "[".date("Y-m-d H:i:s")."] Invalid timezone: '${tz}' (".$f["id"].")\n";
$tz = 1;
}
} else {
echo "[".date("Y-m-d H:i:s")."] Timezone is OK: tz=${tz}\n";
}
echo "[".date("Y-m-d H:i:s")."] tz=${tz}\n";
$data = [
"latitude" => $res["lat"],
"longitude" => $res["lng"],
/*"address" => $res["address"],*/
"postal" => $res["postal"],
"country" => $res["country"],
"timezone" => $tz,
"geocoding_date" => date("Y-m-d"),
"geometry" => "ST_SetSRID(ST_MakePoint(".$res["lng"].",".$res["lat"]."), 4326)"
];
list($res,$err) = updateAddress($f["id"], $data);
if ($err && $err!="") {
echo "[".date("Y-m-d H:i:s")."] Failure: ${err} (".$f["id"].")\n";
} else {
echo "[".date("Y-m-d H:i:s")."] Complete: ".$f["id"]."\n";
}
} else {
echo "[".date("Y-m-d H:i:s")."] Invalid result: ".json_encode($res)." (".$f["id"].")\n";
}
} else {
echo "[".date("Y-m-d H:i:s")."] Failure: ${err} (".$f["id"].")\n";
}
}
}
function updateAddress($id, $data) {
global $conn, $readOnlyReplicaConn;
$columns = [];
$q = "select column_name, data_type, character_maximum_length from INFORMATION_SCHEMA.COLUMNS where table_name = 'address'";
$r = pg_query($readOnlyReplicaConn, $q);
while ($f=pg_fetch_assoc($r)) {
$columns[$f['column_name']] = $f['data_type'];
}
$q = "UPDATE address SET id=${id}";
foreach ($data as $key=>$val) {
if ($key!="timezone") continue;
if (array_key_exists($key,$columns) && $columns[$key]!='character varying' && $columns[$key]!='date') {
$q.= ", ${key} = ".($val==""?"NULL":$val);
} else {
$q.= ", ${key} = '".pg_escape_string($val)."'";
}
}
$q.= " WHERE id=${id} RETURNING *";
$r = pg_query($conn, $q);
if ($r && pg_num_rows($r) && $f=pg_fetch_assoc($r)) {
return [$f, NULL];
}
return [NULL, pg_last_error($conn)];
}
function geocodeAddress($address) {
global $httpAuthToken;
// Call geocoding service
$data = http_build_query(
array(
'address' => $address,
)
);
$url = "http://oauth2.service/api/v1/geocode?" . $data;
$opts = array(
'http' => array(
'method' => "GET",
'timeout' => 60, /* 1 minute */
'header' =>
"Content-Type: application/x-www-form-urlencoded\r\n" .
"Accept: application/json\r\n" .
"Authorization: Server-Token ${httpAuthToken}\r\n",
)
);
$context = stream_context_create($opts);
$body = file_get_contents($url, false, $context);
$geocoded = json_decode($body,true);
if (is_array($geocoded) && is_array($geocoded["data"]) && !isset($geocoded["error"])) {
// Cache the result in DB
return array($geocoded["data"], NULL);
} else if (is_array($geocoded) && isset($geocoded["error"])) {
$body = $geocoded["error"];
}
return array(NULL, "Geocoding service call error: ".$body);
}
echo "[".date("Y-m-d H:i:s")."] GPS geocode_address job complete.\n";
+17
View File
@@ -0,0 +1,17 @@
-- common
UPDATE address SET timezone=8 WHERE timezone IS NULL AND country='FR';
UPDATE address SET timezone=21 WHERE timezone IS NULL AND country='TH';
UPDATE address SET timezone=24 WHERE timezone IS NULL AND country='UA';
UPDATE address SET timezone=28 WHERE timezone IS NULL AND country='PL';
UPDATE address SET timezone=29 WHERE timezone IS NULL AND country='RO';
UPDATE address SET timezone=34 WHERE timezone IS NULL AND country='DE';
UPDATE address SET timezone=39 WHERE timezone IS NULL AND country='TW';
-- development
UPDATE address SET timezone=289 WHERE timezone IS NULL AND country='VN';
UPDATE address SET timezone=301 WHERE timezone IS NULL AND country='IN';
UPDATE address SET timezone=476 WHERE timezone IS NULL AND country='TR';
-- production
UPDATE address SET timezone=300 WHERE timezone IS NULL AND country='VN';
UPDATE address SET timezone=312 WHERE timezone IS NULL AND country='IN';
UPDATE address SET timezone=487 WHERE timezone IS NULL AND country='TR';
+341
View File
@@ -0,0 +1,341 @@
<?php
echo "[".date("Y-m-d H:i:s")."] geofence_area_average_quotes job is starting.\n";
require('./lock.php');
$lock_file = lock_pid_file();
require('../backend.php');
$httpAuthToken = $savvyext->cfgReadChar('system.oauth2_token');
$db_host = $savvyext->cfgReadChar('database.host');
$db_name = $savvyext->cfgReadChar('database.name');
$db_user = $savvyext->cfgReadChar('database.user');
$db_pass = $savvyext->cfgReadChar('database.pass');
$db_port = $savvyext->cfgReadLong('database.port');
$connstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$con = pg_connect($connstr);
$db_host = $savvyext->cfgReadChar('database_replica.host');
$db_name = $savvyext->cfgReadChar('database_replica.name');
$db_user = $savvyext->cfgReadChar('database_replica.user');
$db_pass = $savvyext->cfgReadChar('database_replica.pass');
$db_port = $savvyext->cfgReadLong('database_replica.port');
$readOnlyReplicaConnstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$readOnlyReplicaConn = pg_connect($readOnlyReplicaConnstr);
if ($con===FALSE || $readOnlyReplicaConn===FALSE) {
unlock_pid_file($lock_file);
die ("Could not connect to server\n");
}
$rate = 1.1;
$numberOfDays = 365; // This is handled by update cheapest data job now...
$city_id = 1;
$tz = 'Asia/Singapore';
$transport_providers = [3, 4, 5];
$min_distance = 0.1; //0.1km
$min_rate = 0.2; //20 cents
// Load max IDs
$q = "SELECT max(id) FROM parsedemail_item WHERE base_cost>0 AND dup_id IS NULL AND private='f' AND booking='f' AND transport_provider_id IS NOT NULL";
$r = pg_query($readOnlyReplicaConn, $q);
if ($r && pg_num_rows($r) && $f=pg_fetch_row($r)) {
$max_parsedemail_item_id = $f[0];
}
$q = "SELECT max(id) FROM quotes WHERE cost>0";
$r = pg_query($readOnlyReplicaConn, $q);
if ($r && pg_num_rows($r) && $f=pg_fetch_row($r)) {
$max_quote_id = $f[0];
}
// Load areas
$areas = [];
$q = "SELECT * FROM geofence_area WHERE city_id=${city_id}";
$r = pg_query($readOnlyReplicaConn, $q);
if ($r && pg_num_rows($r)) {
while ($f=pg_fetch_assoc($r)) {
$areas[$f["id"]] = $f;
}
}
// Load previous data
$average_quotes = [];
foreach ($areas as $f) {
$average_quotes[$f["id"]] = load_average_quotes_for_area($f,$areas,$transport_providers);
}
// Start processing
foreach ($average_quotes as $area_id=>$average_quote) {
echo "[".date("Y-m-d H:i:s")."] Processing area ID #${area_id}\n";
process_area_average_quotes($average_quote,$areas,$area_id, $min_distance,$min_rate);
}
/*********************************** Function ***********************************/
function load_average_quotes_for_area($area,$areas,$transport_providers) {
global $con, $readOnlyReplicaConn;
$average_quotes = [];
// Pre-fill the initial data
for ($i=0;$i<24;$i++) {
foreach ($areas as $item) {
foreach ($transport_providers as $transport_provider_id) {
// unique(area_start_id,area_end_id,transport_provider_id,hour)
$key = $area["id"]."_".$item["id"];
if (!array_key_exists($key,$average_quotes)) {
$average_quotes[$key] = []; // initialize
}
if (!array_key_exists($transport_provider_id,$average_quotes[$key])) {
$average_quotes[$key][$transport_provider_id] = [];
}
$average_quotes[$key][$transport_provider_id][$i] = [
"id" => 0,
"area_start_id" => $area["id"],
"area_end_id" => $item["id"],
"transport_provider_id" => $transport_provider_id,
"average_cost" => 0,
"average_total" => 0,
"average_count" => 0,
"hour" => $i,
/* "last_updated" => NULL, */
"last_quotes_id" => 0,
"last_parsedemail_item_id" => 0
];
}
}
}
// Load the existing data from the DB
$q = "SELECT * FROM geofence_area_average_quotes WHERE area_start_id=".$area["id"];
$r = pg_query($readOnlyReplicaConn, $q);
if ($r && pg_num_rows($r)) {
while ($f=pg_fetch_assoc($r)) {
// unique(area_start_id,area_end_id,transport_provider_id,hour)
$key = $f["area_start_id"]."_".$f["area_end_id"];
if (!array_key_exists($key,$average_quotes)) {
$average_quotes[$key] = [];
}
if (!array_key_exists($f["transport_provider_id"],$average_quotes[$key])) {
$average_quotes[$key][$f["transport_provider_id"]] = [];
}
$average_quotes[$key][$f["transport_provider_id"]][$f["hour"]] = $f;
}
}
return $average_quotes;
}
function process_area_average_quotes($average_quote,$areas,$area_id,$min_distance=0.1,$min_rate=0.2) {
global $con, $readOnlyReplicaConn, $max_parsedemail_item_id, $max_quote_id, $numberOfDays, $tz, $transport_providers;
// $average_quote[$key][$transport_provider_id][$hour]
foreach ($average_quote as $key=>$vals) {
echo "[".date("Y-m-d H:i:s")."] Processing key{from,to}=${key}\n";
// Get the first item
foreach ($vals as $val) {
break; // no matter which...
}
$item = $val[0]; // first entry
if ($max_parsedemail_item_id<=$item["last_parsedemail_item_id"] && $max_quote_id<=$item["last_quotes_id"]) {
echo "[".date("Y-m-d H:i:s")."] No new records to compare for the key=${key}\n";
continue;
}
$from_area = $areas[$item["area_start_id"]];
$to_area = $areas[$item["area_end_id"]];
try {
// We assume quotes has UTC timestamp without timezone
$q = "(SELECT a.cost, a.transport_provider_id, ";
$q.= " date_part('hour',(a.travel_date at time zone 'utc' at time zone '${tz}')) AS hour FROM quotes a ";
$q.= " JOIN address AS b ON (b.id = a.location_start_id) ";
$q.= " JOIN address AS c ON (c.id = a.location_end_id) ";
$q.= " WHERE a.cost>0 AND a.travel_date BETWEEN NOW() - INTERVAL '" . $numberOfDays . " days' AND NOW()";
$q.= " AND (b.country='".$from_area["country"]."' OR c.country='".$to_area["country"]."') ";
$q.= " AND a.transport_provider_id IN (".implode(",",$transport_providers).")";
//echo $q; unlock_pid_file($lock_file); exit();
$q.= " AND a.id>".$item["last_quotes_id"]." AND a.id<=".$max_quote_id;
$q.= process_area_filter($from_area,$to_area);
$q.= ") UNION ALL (";
// We assume parsedemail_item has local timestamp without timezone
$q.= "SELECT a.base_cost, a.transport_provider_id, date_part('hour', a.travel_date) AS hour FROM parsedemail_item a ";
$q.= " JOIN address AS b ON (b.id = a.location_start_id) ";
$q.= " JOIN address AS c ON (c.id = a.location_end_id) ";
$q.= " WHERE a.base_cost>0 AND a.travel_date BETWEEN NOW() - INTERVAL '" . $numberOfDays . " days' AND NOW()";
$q.= " AND a.dup_id IS NULL AND a.private='f' AND a.booking='f' AND a.transport_provider_id IS NOT NULL ";
$q.= " AND (b.country='".$from_area["country"]."' OR c.country='".$to_area["country"]."') ";
$q.= " AND a.transport_provider_id IN (".implode(",",$transport_providers).")";
$q.= " AND a.id>".$item["last_parsedemail_item_id"]." AND a.id<=".$max_parsedemail_item_id;
$q.= " AND (distance IS NULL OR distance<".$min_distance." OR base_cost/distance>".$min_rate.")";
$q.= process_area_filter($from_area,$to_area);
$q.= ")";
// Master query
$mq = "SELECT ROUND(AVG(a.cost), 2) as average_cost, ROUND(SUM(a.cost),2) AS average_total, COUNT(*) AS average_count, a.transport_provider_id, a.hour ";
$mq.= " FROM (${q}) AS a GROUP BY a.transport_provider_id,a.hour";
if ( ($item["area_start_id"]==23 and $item["area_end_id"]==9)
|| ($item["area_start_id"]==12 and $item["area_end_id"]==4)
|| ($item["area_start_id"]==14 and $item["area_end_id"]==16)
|| ($item["area_start_id"]== 9 and $item["area_end_id"]==14)
|| ($item["area_start_id"]==23 and $item["area_end_id"]==22)
|| ($item["area_start_id"]==17 and $item["area_end_id"]==7)
|| ($item["area_start_id"]==22 and $item["area_end_id"]==22)) {
echo "[".date("Y-m-d H:i:s")."] Area '".$item["area_start_id"]."' to area '".$item["area_end_id"]."' \n";
echo $mq.";\n\n";
}
$r = pg_query($readOnlyReplicaConn, $mq);
if ($r && pg_num_rows($r)) {
while ($f=pg_fetch_assoc($r)) {
// unique(area_start_id,area_end_id,transport_provider_id,hour)
$average_cost = $average_quote[$key][$f["transport_provider_id"]][$f["hour"]]["average_cost"];
$average_total = $average_quote[$key][$f["transport_provider_id"]][$f["hour"]]["average_total"];
$average_count = $average_quote[$key][$f["transport_provider_id"]][$f["hour"]]["average_count"];
$new_average_cost = $f["average_cost"];
$new_average_count = $average_count + $f["average_count"];
$new_average_total = $average_total + $f["average_total"];
if ($new_average_count>0) {
$new_average_cost = sprintf("%0.02f",$new_average_total/$new_average_count);
}
$average_quote[$key][$f["transport_provider_id"]][$f["hour"]]["average_cost"] = $new_average_cost;
$average_quote[$key][$f["transport_provider_id"]][$f["hour"]]["average_total"] = $new_average_total;
$average_quote[$key][$f["transport_provider_id"]][$f["hour"]]["average_count"] = $new_average_count;
$average_quote[$key][$f["transport_provider_id"]][$f["hour"]]["last_quotes_id"] = $max_quote_id;
$average_quote[$key][$f["transport_provider_id"]][$f["hour"]]["last_parsedemail_item_id"] = $max_parsedemail_item_id;
$average_quote[$key][$f["transport_provider_id"]][$f["hour"]]["id"] = save_or_update($average_quote[$key][$f["transport_provider_id"]][$f["hour"]]);
}
} else {
$err = pg_last_error();
if ($err === "") {
echo "[".date("Y-m-d H:i:s")."] WARNING(${key}): No trips found between areas?\n";
} else {
echo "[".date("Y-m-d H:i:s")."] ERROR(${key}): ${err}\n";
echo "[".date("Y-m-d H:i:s")."] ${q}\n";
}
}
} catch (Exception $e) {
echo "[".date("Y-m-d H:i:s")."] ERROR(${key}): ".$e->getMessage()."\n";
}
//unlock_pid_file($lock_file); exit(); // DEBUG
}
}
function save_or_update($data) {
global $con;
$qb = "average_cost=".sprintf("%0.02f",$data["average_cost"]);
$qb.= ",average_total=".sprintf("%0.02f",$data["average_total"]);
$qb.= ",average_count=".((int)$data["average_count"]);
$qb.= ",last_updated=NOW()";
$qb.= ",last_quotes_id=".((int)$data["last_quotes_id"]);
$qb.= ",last_parsedemail_item_id=".((int)$data["last_parsedemail_item_id"]);
if ($data["id"]>0) {
// Update
$q = "UPDATE geofence_area_average_quotes SET";
$q.= " ".$qb." ";
$q.= " WHERE id=".$data["id"]." RETURNING id";
} else {
// Save
$fields = ['area_start_id','area_end_id','transport_provider_id','average_cost','average_total','average_count','hour','last_quotes_id','last_parsedemail_item_id'];
$values = [];
foreach ($fields as $field) {
$values[] = $data[$field];
}
$q = "INSERT INTO geofence_area_average_quotes (".implode(",",$fields).") VALUES(".implode(",",$values).") ";
$q.= " ON CONFLICT (area_start_id, area_end_id, transport_provider_id, hour) DO UPDATE SET ${qb} RETURNING id";
}
//echo $q . "\n";
//*
$r = pg_query($con, $q);
if ($r && pg_num_rows($r) && $f=pg_fetch_row($r)) {
return $f[0]; // ID
} else {
echo "[".date("Y-m-d H:i:s")."] ERROR: ${q}\n";
}//*/
return NULL;
}
/*
CREATE TABLE geofence_area_average_quotes (
id bigserial,
area_start_id int references geofence_area(id),
area_end_id int references geofence_area(id),
transport_provider_id int references transport_providers(id),
average_cost numeric,
average_total numeric,
average_count int,
hour smallint not null,
last_updated timestamp default now(),
last_quotes_id bigint,
last_parsedemail_item_id bigint,
primary key(id),
unique(area_start_id,area_end_id,transport_provider_id,hour)
);
*/
function process_area_filter($from_area,$to_area) {
$from_boundaries = json_decode($from_area["boundaries"],true);
$to_boundaries = json_decode($to_area["boundaries"],true);
$q = "";
if ($from_area['type'] === 'radius') {
$q.= process_area_filter_radius('b',$from_area,$from_boundaries);
}
if ($to_area['type'] === 'radius') {
$q.= process_area_filter_radius('c',$to_area,$to_boundaries);
}
if ($from_area['type'] === 'postal') {
$q.= process_area_filter_postal('b',$from_area,$from_boundaries);
//$q.= process_area_filter_polygon('b',$from_area,$from_boundaries);
}
if ($to_area['type'] === 'postal') {
$q.= process_area_filter_postal('c',$to_area,$to_boundaries);
//$q.= process_area_filter_polygon('c',$to_area,$to_boundaries);
}
if ($from_area['type'] === 'polygon') {
$q.= process_area_filter_polygon('b',$from_area,$from_boundaries);
}
if ($to_area['type'] === 'polygon') {
$q.= process_area_filter_polygon('c',$to_area,$to_boundaries);
}
return $q;
}
function process_area_filter_radius($ref,$area,$boundaries) {
if (is_array($boundaries) && array_key_exists("radius",$boundaries) && $boundaries["radius"]>0) {
return " AND ST_DWithin('" . $area['location'] . "', ${ref}.geometry, " . $boundaries["radius"] . ")";
}
throw new Exception("Missing radius in boundaries field");
}
function process_area_filter_postal($ref,$area,$boundaries) {
if (is_array($boundaries) && array_key_exists("postal_code",$boundaries) && is_array($boundaries["postal_code"]) && count($boundaries["postal_code"])>0) {
$q = "";
foreach ($boundaries["postal_code"] as $code) {
if ($q!="") $q.= " OR ";
$q.= " LEFT(${ref}.postal,".strlen($code).")='${code}' ";
}
return " AND (".$q.")";
}
throw new Exception("Missing postal_code in boundaries field");
}
function process_area_filter_polygon($ref,$area,$boundaries) {
if (is_array($boundaries) && array_key_exists("polygon",$boundaries) && is_array($boundaries["polygon"]) and count($boundaries["polygon"])>0) {
$polygonCoords = [];
foreach ($boundaries["polygon"] as $coord) {
$polygonCoords[] = "$coord[0] $coord[1]";
}
$polygonCoordsString = implode(",", $polygonCoords);
return " AND ST_Contains(ST_GeomFromText('POLYGON((${polygonCoordsString}))', 4326), ${ref}.geometry::geometry) ";
}
throw new Exception("Missing radius in boundaries field");
}
pg_close($con);
pg_close($readOnlyReplicaConn);
unlock_pid_file($lock_file);
echo "[".date("Y-m-d H:i:s")."] geofence_area_average_quotes job complete.\n";
?>
+337
View File
@@ -0,0 +1,337 @@
<?php
echo "[".date("Y-m-d H:i:s")."] geofence_area_average_quotes job is starting.\n";
require('./lock.php');
$lock_file = lock_pid_file();
$profile = getenv("SAVVY_PROFILE");
if ($profile) {
require_once("../backend.${profile}.php");
} else {
require_once('../backend.php');
}
$httpAuthToken = $savvyext->cfgReadChar('system.oauth2_token');
$db_host = $savvyext->cfgReadChar('database.host');
$db_name = $savvyext->cfgReadChar('database.name');
$db_user = $savvyext->cfgReadChar('database.user');
$db_pass = $savvyext->cfgReadChar('database.pass');
$db_port = $savvyext->cfgReadLong('database.port');
$connstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$con = pg_connect($connstr);
$db_host = $savvyext->cfgReadChar('database_replica.host');
$db_name = $savvyext->cfgReadChar('database_replica.name');
$db_user = $savvyext->cfgReadChar('database_replica.user');
$db_pass = $savvyext->cfgReadChar('database_replica.pass');
$db_port = $savvyext->cfgReadLong('database_replica.port');
$readOnlyReplicaConnstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$readOnlyReplicaConn = pg_connect($readOnlyReplicaConnstr);
if ($con===FALSE || $readOnlyReplicaConn===FALSE) {
unlock_pid_file($lock_file);
die ("Could not connect to server\n");
}
$rate = 1.1;
$numberOfDays = 365; // This is handled by update cheapest data job now...
$city_id = 257;
$tz = 'America/Los_Angeles';
$transport_providers = [1, 2, 8];
$min_distance = 0.1; //0.1km
$min_rate = 0.2; //20 cents
// Load max IDs
$q = "SELECT max(id) FROM parsedemail_item WHERE base_cost>0 AND dup_id IS NULL AND private='f' AND booking='f' AND transport_provider_id IS NOT NULL";
$r = pg_query($readOnlyReplicaConn, $q);
if ($r && pg_num_rows($r) && $f=pg_fetch_row($r)) {
$max_parsedemail_item_id = $f[0];
}
$q = "SELECT max(id) FROM quotes WHERE cost>0";
$r = pg_query($readOnlyReplicaConn, $q);
if ($r && pg_num_rows($r) && $f=pg_fetch_row($r)) {
$max_quote_id = $f[0];
}
// Load areas
$areas = [];
$q = "SELECT * FROM geofence_area WHERE city_id=${city_id} AND id in (30,51)";
$r = pg_query($readOnlyReplicaConn, $q);
if ($r && pg_num_rows($r)) {
while ($f=pg_fetch_assoc($r)) {
$areas[$f["id"]] = $f;
}
}
// Load previous data
$average_quotes = [];
foreach ($areas as $f) {
$average_quotes[$f["id"]] = load_average_quotes_for_area($f,$areas,$transport_providers);
}
// Start processing
foreach ($average_quotes as $area_id=>$average_quote) {
echo "[".date("Y-m-d H:i:s")."] Processing area ID #${area_id}\n";
process_area_average_quotes($average_quote,$areas,$area_id, $min_distance,$min_rate);
}
/*********************************** Function ***********************************/
function load_average_quotes_for_area($area,$areas,$transport_providers) {
global $con, $readOnlyReplicaConn;
$average_quotes = [];
// Pre-fill the initial data
for ($i=0;$i<24;$i++) {
foreach ($areas as $item) {
foreach ($transport_providers as $transport_provider_id) {
// unique(area_start_id,area_end_id,transport_provider_id,hour)
$key = $area["id"]."_".$item["id"];
if (!array_key_exists($key,$average_quotes)) {
$average_quotes[$key] = []; // initialize
}
if (!array_key_exists($transport_provider_id,$average_quotes[$key])) {
$average_quotes[$key][$transport_provider_id] = [];
}
$average_quotes[$key][$transport_provider_id][$i] = [
"id" => 0,
"area_start_id" => $area["id"],
"area_end_id" => $item["id"],
"transport_provider_id" => $transport_provider_id,
"average_cost" => 0,
"average_total" => 0,
"average_count" => 0,
"hour" => $i,
/* "last_updated" => NULL, */
"last_quotes_id" => 0,
"last_parsedemail_item_id" => 0
];
}
}
}
// Load the existing data from the DB
$q = "SELECT * FROM geofence_area_average_quotes WHERE area_start_id=".$area["id"];
$r = pg_query($readOnlyReplicaConn, $q);
if ($r && pg_num_rows($r)) {
while ($f=pg_fetch_assoc($r)) {
// unique(area_start_id,area_end_id,transport_provider_id,hour)
$key = $f["area_start_id"]."_".$f["area_end_id"];
if (!array_key_exists($key,$average_quotes)) {
$average_quotes[$key] = [];
}
if (!array_key_exists($f["transport_provider_id"],$average_quotes[$key])) {
$average_quotes[$key][$f["transport_provider_id"]] = [];
}
$average_quotes[$key][$f["transport_provider_id"]][$f["hour"]] = $f;
}
}
return $average_quotes;
}
function process_area_average_quotes($average_quote,$areas,$area_id,$min_distance=0.1,$min_rate=0.2) {
global $con, $readOnlyReplicaConn, $max_parsedemail_item_id, $max_quote_id, $numberOfDays, $tz, $transport_providers;
// $average_quote[$key][$transport_provider_id][$hour]
foreach ($average_quote as $key=>$vals) {
echo "[".date("Y-m-d H:i:s")."] Processing key{from,to}=${key}\n";
// Get the first item
foreach ($vals as $val) {
break; // no matter which...
}
$item = $val[0]; // first entry
if ($max_parsedemail_item_id<=$item["last_parsedemail_item_id"] && $max_quote_id<=$item["last_quotes_id"]) {
echo "[".date("Y-m-d H:i:s")."] No new records to compare for the key=${key}\n";
continue;
}
$from_area = $areas[$item["area_start_id"]];
$to_area = $areas[$item["area_end_id"]];
try {
// We assume quotes has UTC timestamp without timezone
$q = "(SELECT a.cost, a.transport_provider_id, ";
$q.= " date_part('hour',(a.travel_date at time zone 'utc' at time zone '${tz}')) AS hour FROM quotes a ";
$q.= " JOIN address AS b ON (b.id = a.location_start_id) ";
$q.= " JOIN address AS c ON (c.id = a.location_end_id) ";
$q.= " WHERE a.cost>0 AND a.travel_date BETWEEN NOW() - INTERVAL '" . $numberOfDays . " days' AND NOW()";
$q.= " AND (b.country='".$from_area["country"]."' OR c.country='".$to_area["country"]."') ";
$q.= " AND a.transport_provider_id IN (".implode(",",$transport_providers).")";
//echo $q; unlock_pid_file($lock_file); exit();
$q.= " AND a.id>".$item["last_quotes_id"]." AND a.id<=".$max_quote_id;
$q.= process_area_filter($from_area,$to_area);
$q.= ") UNION ALL (";
// We assume parsedemail_item has local timestamp without timezone
$q.= "SELECT a.base_cost, a.transport_provider_id, date_part('hour', a.travel_date) AS hour FROM parsedemail_item a ";
$q.= " JOIN address AS b ON (b.id = a.location_start_id) ";
$q.= " JOIN address AS c ON (c.id = a.location_end_id) ";
$q.= " WHERE a.base_cost>0 AND a.travel_date BETWEEN NOW() - INTERVAL '" . $numberOfDays . " days' AND NOW()";
$q.= " AND a.dup_id IS NULL AND a.private='f' AND a.booking='f' AND a.transport_provider_id IS NOT NULL ";
$q.= " AND (b.country='".$from_area["country"]."' OR c.country='".$to_area["country"]."') ";
$q.= " AND a.transport_provider_id IN (".implode(",",$transport_providers).")";
$q.= " AND a.id>".$item["last_parsedemail_item_id"]." AND a.id<=".$max_parsedemail_item_id;
$q.= " AND (distance IS NULL OR distance<".$min_distance." OR base_cost/distance>".$min_rate.")";
$q.= process_area_filter($from_area,$to_area);
$q.= ")";
// Master query
$mq = "SELECT ROUND(AVG(a.cost), 2) as average_cost, ROUND(SUM(a.cost),2) AS average_total, COUNT(*) AS average_count, a.transport_provider_id, a.hour ";
$mq.= " FROM (${q}) AS a GROUP BY a.transport_provider_id,a.hour";
$r = pg_query($readOnlyReplicaConn, $mq);
if ($r && pg_num_rows($r)) {
while ($f=pg_fetch_assoc($r)) {
// unique(area_start_id,area_end_id,transport_provider_id,hour)
$average_cost = $average_quote[$key][$f["transport_provider_id"]][$f["hour"]]["average_cost"];
$average_total = $average_quote[$key][$f["transport_provider_id"]][$f["hour"]]["average_total"];
$average_count = $average_quote[$key][$f["transport_provider_id"]][$f["hour"]]["average_count"];
$new_average_cost = $f["average_cost"];
$new_average_count = $average_count + $f["average_count"];
$new_average_total = $average_total + $f["average_total"];
if ($new_average_count>0) {
$new_average_cost = sprintf("%0.02f",$new_average_total/$new_average_count);
}
$average_quote[$key][$f["transport_provider_id"]][$f["hour"]]["average_cost"] = $new_average_cost;
$average_quote[$key][$f["transport_provider_id"]][$f["hour"]]["average_total"] = $new_average_total;
$average_quote[$key][$f["transport_provider_id"]][$f["hour"]]["average_count"] = $new_average_count;
$average_quote[$key][$f["transport_provider_id"]][$f["hour"]]["last_quotes_id"] = $max_quote_id;
$average_quote[$key][$f["transport_provider_id"]][$f["hour"]]["last_parsedemail_item_id"] = $max_parsedemail_item_id;
$average_quote[$key][$f["transport_provider_id"]][$f["hour"]]["id"] = save_or_update($average_quote[$key][$f["transport_provider_id"]][$f["hour"]]);
}
} else {
$err = pg_last_error();
if ($err === "") {
echo "[".date("Y-m-d H:i:s")."] WARNING(${key}): No trips found between areas?\n";
} else {
echo "[".date("Y-m-d H:i:s")."] ERROR(${key}): ${err}\n";
echo "[".date("Y-m-d H:i:s")."] ${q}\n";
}
}
} catch (Exception $e) {
echo "[".date("Y-m-d H:i:s")."] ERROR(${key}): ".$e->getMessage()."\n";
}
//unlock_pid_file($lock_file); exit(); // DEBUG
}
}
function save_or_update($data) {
global $con;
$qb = "average_cost=".sprintf("%0.02f",$data["average_cost"]);
$qb.= ",average_total=".sprintf("%0.02f",$data["average_total"]);
$qb.= ",average_count=".((int)$data["average_count"]);
$qb.= ",last_updated=NOW()";
$qb.= ",last_quotes_id=".((int)$data["last_quotes_id"]);
$qb.= ",last_parsedemail_item_id=".((int)$data["last_parsedemail_item_id"]);
if ($data["id"]>0) {
// Update
$q = "UPDATE geofence_area_average_quotes SET";
$q.= " ".$qb." ";
$q.= " WHERE id=".$data["id"]." RETURNING id";
} else {
// Save
$fields = ['area_start_id','area_end_id','transport_provider_id','average_cost','average_total','average_count','hour','last_quotes_id','last_parsedemail_item_id'];
$values = [];
foreach ($fields as $field) {
$values[] = $data[$field];
}
$q = "INSERT INTO geofence_area_average_quotes (".implode(",",$fields).") VALUES(".implode(",",$values).") ";
$q.= " ON CONFLICT (area_start_id, area_end_id, transport_provider_id, hour) DO UPDATE SET ${qb} RETURNING id";
}
//echo $q . "\n";
//*
$r = pg_query($con, $q);
if ($r && pg_num_rows($r) && $f=pg_fetch_row($r)) {
return $f[0]; // ID
} else {
echo "[".date("Y-m-d H:i:s")."] ERROR: ${q}\n";
}//*/
return NULL;
}
/*
CREATE TABLE geofence_area_average_quotes (
id bigserial,
area_start_id int references geofence_area(id),
area_end_id int references geofence_area(id),
transport_provider_id int references transport_providers(id),
average_cost numeric,
average_total numeric,
average_count int,
hour smallint not null,
last_updated timestamp default now(),
last_quotes_id bigint,
last_parsedemail_item_id bigint,
primary key(id),
unique(area_start_id,area_end_id,transport_provider_id,hour)
);
*/
function process_area_filter($from_area,$to_area) {
$from_boundaries = json_decode($from_area["boundaries"],true);
$to_boundaries = json_decode($to_area["boundaries"],true);
$q = "";
if ($from_area['type'] === 'radius') {
$q.= process_area_filter_radius('b',$from_area,$from_boundaries);
}
if ($to_area['type'] === 'radius') {
$q.= process_area_filter_radius('c',$to_area,$to_boundaries);
}
if ($from_area['type'] === 'postal') {
$q.= process_area_filter_postal('b',$from_area,$from_boundaries);
//$q.= process_area_filter_polygon('b',$from_area,$from_boundaries);
}
if ($to_area['type'] === 'postal') {
$q.= process_area_filter_postal('c',$to_area,$to_boundaries);
//$q.= process_area_filter_polygon('c',$to_area,$to_boundaries);
}
if ($from_area['type'] === 'polygon') {
$q.= process_area_filter_polygon('b',$from_area,$from_boundaries);
}
if ($to_area['type'] === 'polygon') {
$q.= process_area_filter_polygon('c',$to_area,$to_boundaries);
}
return $q;
}
function process_area_filter_radius($ref,$area,$boundaries) {
if (is_array($boundaries) && array_key_exists("radius",$boundaries) && $boundaries["radius"]>0) {
return " AND ST_DWithin('" . $area['location'] . "', ${ref}.geometry, " . $boundaries["radius"] . ")";
}
throw new Exception("Missing radius in boundaries field");
}
function process_area_filter_postal($ref,$area,$boundaries) {
if (is_array($boundaries) && array_key_exists("postal_code",$boundaries) && is_array($boundaries["postal_code"]) && count($boundaries["postal_code"])>0) {
$q = "";
foreach ($boundaries["postal_code"] as $code) {
if ($q!="") $q.= " OR ";
$q.= " LEFT(${ref}.postal,".strlen($code).")='${code}' ";
}
return " AND (".$q.")";
}
throw new Exception("Missing postal_code in boundaries field");
}
function process_area_filter_polygon($ref,$area,$boundaries) {
if (is_array($boundaries) && array_key_exists("polygon",$boundaries) && is_array($boundaries["polygon"]) and count($boundaries["polygon"])>0) {
$polygonCoords = [];
foreach ($boundaries["polygon"] as $coord) {
$polygonCoords[] = "$coord[0] $coord[1]";
}
$polygonCoordsString = implode(",", $polygonCoords);
return " AND ST_Contains(ST_GeomFromText('POLYGON((${polygonCoordsString}))', 4326), ${ref}.geometry::geometry) ";
}
throw new Exception("Missing polygon in boundaries field");
}
pg_close($con);
pg_close($readOnlyReplicaConn);
unlock_pid_file($lock_file);
echo "[".date("Y-m-d H:i:s")."] geofence_area_average_quotes job complete.\n";
?>
+191
View File
@@ -0,0 +1,191 @@
<?php
$job_name = 'geofence_area_city_cleanup';
echo "[" . date("Y-m-d H:i:s") . "] {$job_name} job is starting.\n";
require 'common/config.php';
require 'common/address_city.php';
require 'common/Geocode.php';
$total = $success = $failed = 0;
/*
* 1. Get duplicated cities
* 2. Update one city in #1, and remove others
* 3. Update incorrect name
*/
$conditions = [
"city='' OR city IS NULL",
"country in ('TR','UA')",
"LENGTH(city)=2",
"city ~ '[0-9]+'"
//"city LIKE 'San F%' or city LIKE 'SFO%'"
];
foreach ($conditions as $condition) {
$r=getCitiesByCondition($condition);
while ($f = pg_fetch_assoc($r)) { //d($f,1);
$ok = false;
$total++;
$city_id = $f['id'];
$latitude = $f['latitude'];
$longitude = $f['longitude'];
$city_new_name="";
$data_reverse = Geocode::reverseGPS($latitude, $longitude);
if (!empty($data_reverse['city'])) {
$city_new_name = $data_reverse['city'];
} else {
$city_new_name = Geocode::getGeoInfoBigDataCloud($latitude, $longitude);
}
if (!empty($city_new_name)) {
$data_update_city = [
'city' => $city_new_name
];
$updated = updateDataTable('geofence_area_city', 'id=' . $city_id, $data_update_city);
}
}
}
$r = getAddressWithEmptyCity();
while ($f = pg_fetch_assoc($r)) {
$total++;
$city_name = $f['city'];
$country_code = $f['country'];
$city_id = $f['city_id'];
$address = $f['address'];
$latitude = $f['latitude'];
$longitude = $f['longitude'];
$address_info = parseAddressByCountry($address, $country_code);
$city_new_name = "";
if (!empty($address_info['city'])) {
$city_new_name = $address_info['city'];
} else {
$city_new_name = Geocode::getGeoInfoBigDataCloud($latitude, $longitude);
if (empty($city_new_name)) {
$data_reverse = Geocode::reverseGPS($latitude, $longitude);
if (!empty($data_reverse['city'])) {
$city_new_name = $data_reverse['city'];
}
}
}
if (!empty($city_new_name)) {
$city_new_id = getCityId($city_new_name, $country_code, $latitude, $longitude);
$city_id = $city_new_id;
$data_update = [
'city_id' => $city_new_id,
];
$updated = updateDataTable('address', 'id=' . $f['id'], $data_update);
if ($updated) {
$ok = true;
} else {
$ok = false;
}
}
if (empty($city_name)) {
$data_update_city = [
'city' => $city_new_name,
'country' => $country_code,
];
$updated = updateDataTable('geofence_area_city', 'id=' . $city_id, $data_update_city);
if ($updated) {
$ok = true;
} else {
$ok = false;
}
}
if (!empty($ok)) {
$success++;
} else {
$failed++;
}
}
//clean duplicated cities
$r = getDuplicatedCities();
while ($f = pg_fetch_assoc($r)) {
$city_name = $f['city'];
$country = $f['country'];
$citie_ids = getCities($city_name, $country);
$num = count($citie_ids);
if ($num > 0) {
$total += $num;
foreach ($citie_ids as $country => $ids) {
$city_id = $ids[0];
$data_update = [
'city_id' => $city_id,
];
$condition = "country='" . $country . "' AND city_id IN (" . implode(",", $ids) . ")";
$updated = updateDataTable("address", $condition, $data_update);
}
}
}
deleteUnusedCities();
echo "Total: " . $total . ".\n";
echo "Success: : " . $success . ".\n";
echo "Failed: : " . $failed . ".\n";
echo "[" . date("Y-m-d H:i:s") . "] {$job_name} job complete.\n";
function getCitiesByCondition($condition)
{
global $conn, $readOnlyReplicaConn;
$q = "SELECT id, latitude,longitude
FROM geofence_area_city
WHERE ".$condition;
$r = pg_query($readOnlyReplicaConn, $q);
return $r;
}
function getAddressWithEmptyCity()
{
global $conn, $readOnlyReplicaConn;
$q = "SELECT a.id, address, a.latitude, a.longitude, city_id, city, a.country as country
FROM address a
LEFT JOIN geofence_area_city b ON a.city_id=b.id
WHERE city_id IS NULL OR b.city='' OR a.country!=b.country;";
$r = pg_query($readOnlyReplicaConn, $q);
return $r;
}
function getDuplicatedCities()
{
global $conn, $readOnlyReplicaConn;
$q = "SELECT city, country, count(*)
FROM geofence_area_city
GROUP BY city,
country
HAVING count(*)>1
ORDER BY count(*) DESC";
$r = pg_query($readOnlyReplicaConn, $q);
return $r;
}
function deleteUnusedCities()
{
global $conn;
$q = "DELETE
FROM geofence_area_city
WHERE id NOT IN (SELECT DISTINCT city_id FROM address);";
$r = pg_query($conn, $q);
if ($r && pg_affected_rows($r)) {
return true;
}
return false;
}
function getCities($city, $country)
{
global $readOnlyReplicaConn;
$q = "SELECT id FROM geofence_area_city WHERE LOWER(city) ILIKE '" . strtolower(pg_escape_string($city)) . "' AND country='" . $country . "' ORDER BY id ASC";
$r = pg_query($readOnlyReplicaConn, $q);
$result = [];
while ($f = pg_fetch_assoc($r)) {
$result[$country][] = $f['id'];
}
return $result;
}
+65
View File
@@ -0,0 +1,65 @@
<?php
echo "[".date("Y-m-d H:i:s")."] GPS geometry_address job is starting.\n";
require('../backend.php');
$httpAuthToken = $savvyext->cfgReadChar('system.oauth2_token');
$db_host = $savvyext->cfgReadChar('database.host');
$db_name = $savvyext->cfgReadChar('database.name');
$db_user = $savvyext->cfgReadChar('database.user');
$db_pass = $savvyext->cfgReadChar('database.pass');
$db_port = $savvyext->cfgReadLong('database.port');
$connstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$conn = pg_connect($connstr);
$db_host = $savvyext->cfgReadChar('database_replica.host');
$db_name = $savvyext->cfgReadChar('database_replica.name');
$db_user = $savvyext->cfgReadChar('database_replica.user');
$db_pass = $savvyext->cfgReadChar('database_replica.pass');
$db_port = $savvyext->cfgReadLong('database_replica.port');
$readOnlyReplicaConnstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$readOnlyReplicaConn = pg_connect($readOnlyReplicaConnstr);
$q = "SELECT * FROM address WHERE geometry IS NULL AND latitude!=0 AND longitude!=0";
$r = pg_query($readOnlyReplicaConn, $q);
while ($f=pg_fetch_assoc($r)) {
$data = [
"geometry" => "ST_SetSRID(ST_MakePoint(".$f["longitude"].",".$f["latitude"]."), 4326)"
];
list($res,$err) = updateAddress($f["id"], $data);
if ($err && $err!="") {
echo "[".date("Y-m-d H:i:s")."] Failure: ${err} (".$f["id"].")\n";
} else {
echo "[".date("Y-m-d H:i:s")."] Complete: ".$f["id"]."\n";
}
}
function updateAddress($id, $data) {
global $conn, $readOnlyReplicaConn;
$columns = [];
$q = "select column_name, data_type, character_maximum_length from INFORMATION_SCHEMA.COLUMNS where table_name = 'address'";
$r = pg_query($readOnlyReplicaConn, $q);
while ($f=pg_fetch_assoc($r)) {
$columns[$f['column_name']] = $f['data_type'];
}
$q = "UPDATE address SET id=${id}";
foreach ($data as $key=>$val) {
if ($key=="id") continue;
if (array_key_exists($key,$columns) && $columns[$key]!='character varying' && $columns[$key]!='date') {
$q.= ", ${key} = ".($val==""?"NULL":$val);
} else {
$q.= ", ${key} = '".pg_escape_string($val)."'";
}
}
$q.= " WHERE id=${id} RETURNING *";
$r = pg_query($conn, $q);
if ($r && pg_num_rows($r) && $f=pg_fetch_assoc($r)) {
return [$f, NULL];
}
return [NULL, pg_last_error($conn)];
}
echo "[".date("Y-m-d H:i:s")."] GPS geometry_address job complete.\n";
+46
View File
@@ -0,0 +1,46 @@
<?php
require '../backend.php';
global $pgconn_gps, $readOnlyReplicaConn;
$gps_address_insert = <<< EOS
INSERT INTO address(id, address, latitude, longitude, location) VALUES ($1, $2, $3, $4, st_setsrid(st_point($4, $3),4326))
EOS;
$gps_db_host = $savvyext->cfgReadChar('gpsdatabase.host');
$gps_db_port = $savvyext->cfgReadLong('gpsdatabase.port');
$gps_db_name = $savvyext->cfgReadChar('gpsdatabase.name');
$gps_db_user = $savvyext->cfgReadChar('gpsdatabase.user');
$gps_db_pass = $savvyext->cfgReadChar('gpsdatabase.pass');
$conn_string_gps = "host=${gps_db_host} port=${gps_db_port} dbname=${gps_db_name} user=${gps_db_user} password=${gps_db_pass}";
$pgconn_gps = pg_connect($conn_string_gps);
$db_host = $savvyext->cfgReadChar('database_replica.host');
$db_name = $savvyext->cfgReadChar('database_replica.name');
$db_user = $savvyext->cfgReadChar('database_replica.user');
$db_pass = $savvyext->cfgReadChar('database_replica.pass');
$db_port = $savvyext->cfgReadLong('database_replica.port');
$readOnlyReplicaConnstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$readOnlyReplicaConn = pg_connect($readOnlyReplicaConnstr);
// Get max id from GPS DB
$q = "SELECT max(id) FROM address";
$r = pg_query($pgconn_gps, $q);
$id = 0;
if ($r && pg_num_rows($r) && $f=pg_fetch_row($r)) {
$id = (int)$f[0];
}
$q = "SELECT a.id, a.address, a.latitude, a.longitude FROM address as a WHERE a.id > ${id}";
$r = pg_query($readOnlyReplicaConn, $q);
while ($f=pg_fetch_assoc($r)) {
pg_query_params($pgconn_gps, $gps_address_insert, [
$f['id'],
$f['address'],
$f['latitude'],
$f['longitude']
]);
}
pg_close($readOnlyReplicaConn);
pg_close($pgconn_gps);
+48
View File
@@ -0,0 +1,48 @@
<?php
require '../backend.php';
global $readOnlyReplicaConn, $pgconn_gps;
//PostgreSQL
$gps_db_host = $savvyext->cfgReadChar('gpsdatabase.host');
$gps_db_port = $savvyext->cfgReadLong('gpsdatabase.port');
$gps_db_name = $savvyext->cfgReadChar('gpsdatabase.name');
$gps_db_user = $savvyext->cfgReadChar('gpsdatabase.user');
$gps_db_pass = $savvyext->cfgReadChar('gpsdatabase.pass');
$conn_string_gps = "host=${gps_db_host} port=${gps_db_port} dbname=${gps_db_name} user=${gps_db_user} password=${gps_db_pass}";
$pgconn_gps = pg_connect($conn_string_gps);
$db_host = $savvyext->cfgReadChar('database_replica.host');
$db_name = $savvyext->cfgReadChar('database_replica.name');
$db_user = $savvyext->cfgReadChar('database_replica.user');
$db_pass = $savvyext->cfgReadChar('database_replica.pass');
$db_port = $savvyext->cfgReadLong('database_replica.port');
$readOnlyReplicaConnstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$readOnlyReplicaConn = pg_connect($readOnlyReplicaConnstr);
// Get max id from GPS DB
$q = "SELECT max(id) FROM parsedemail_item";
$r = pg_query($pgconn_gps, $q);
$id = 0;
if ($r && pg_num_rows($r) && $f=pg_fetch_row($r)) {
$id = (int)$f[0];
}
// Get newer records from the main DB
$q = "SELECT a.id,b.latitude AS location_start_lat,b.longitude AS location_start_lng,c.latitude AS location_end_lat,c.longitude AS location_end_lng ";
$q.= " FROM parsedemail_item a, address b, address c WHERE b.id=a.location_start_id AND c.id=a.location_end_id AND a.id>${id} ORDER BY a.id";
$r = pg_query($readOnlyReplicaConn, $q);
while ($f=pg_fetch_assoc($r)) {
if ($f["location_start_lat"]==0 && $f["location_start_lng"]==0 && $f["location_end_lat"]==0 && $f["location_end_lng"]==0) {
continue; // Bad GPS coordinates - cannot work with it...
}
$q = "INSERT INTO parsedemail_item (id,location_start_lat,location_start_lng,location_start,location_end_lat,location_end_lng,location_end) VALUES(";
$q.= $f["id"].",".$f["location_start_lat"].",".$f["location_start_lng"].",st_setsrid(st_point(".$f["location_start_lng"].",".$f["location_start_lat"]."),4326),";
$q.= $f["location_end_lat"].",".$f["location_end_lng"].",st_setsrid(st_point(".$f["location_end_lng"].",".$f["location_end_lat"]."),4326)";
$q.= ")";
//echo "$q\n";
pg_query($pgconn_gps,$q);
}
pg_close($readOnlyReplicaConn);
pg_close($pgconn_gps);
@@ -0,0 +1,50 @@
<?php
require '../backend.php';
global $pgconn_gps, $readOnlyReplicaConn;
//PostgreSQL
$gps_db_host = $savvyext->cfgReadChar('gpsdatabase.host');
$gps_db_port = $savvyext->cfgReadLong('gpsdatabase.port');
$gps_db_name = $savvyext->cfgReadChar('gpsdatabase.name');
$gps_db_user = $savvyext->cfgReadChar('gpsdatabase.user');
$gps_db_pass = $savvyext->cfgReadChar('gpsdatabase.pass');
$conn_string_gps = "host=${gps_db_host} port=${gps_db_port} dbname=${gps_db_name} user=${gps_db_user} password=${gps_db_pass}";
$pgconn_gps = pg_connect($conn_string_gps);
$db_host = $savvyext->cfgReadChar('database_replica.host');
$db_name = $savvyext->cfgReadChar('database_replica.name');
$db_user = $savvyext->cfgReadChar('database_replica.user');
$db_pass = $savvyext->cfgReadChar('database_replica.pass');
$db_port = $savvyext->cfgReadLong('database_replica.port');
$readOnlyReplicaConnstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$readOnlyReplicaConn = pg_connect($readOnlyReplicaConnstr);
$id = 0;
// Get newer records from the main DB
$q = "SELECT a.id,b.latitude AS location_start_lat,b.longitude AS location_start_lng,c.latitude AS location_end_lat,c.longitude AS location_end_lng ";
$q.= " FROM parsedemail_item a, address b, address c WHERE b.id=a.location_start_id AND c.id=a.location_end_id AND a.id>${id} ORDER BY a.id";
$r = pg_query($readOnlyReplicaConn, $q);
while ($f=pg_fetch_assoc($r)) {
if ($f["location_start_lat"]==0 && $f["location_start_lng"]==0 && $f["location_end_lat"]==0 && $f["location_end_lng"]==0) {
continue; // Bad GPS coordinates - cannot work with it...
}
$q = "SELECT * FROM parsedemail_item WHERE id=".$f["id"];
$s = pg_query($pgconn_gps,$q);
if ($s && pg_num_rows($s)) {
continue; // We have this record already - do not update...
}
$q = "INSERT INTO parsedemail_item (id,location_start_lat,location_start_lng,location_start,location_end_lat,location_end_lng,location_end) VALUES(";
$q.= $f["id"].",".$f["location_start_lat"].",".$f["location_start_lng"].",st_setsrid(st_point(".$f["location_start_lng"].",".$f["location_start_lat"]."),4326),";
$q.= $f["location_end_lat"].",".$f["location_end_lng"].",st_setsrid(st_point(".$f["location_end_lng"].",".$f["location_end_lat"]."),4326)";
$q.= ")";
//echo "$q\n";
pg_query($pgconn_gps,$q);
}
// TODO: algorithm to make sure there is no "skipped" to nor comb the whole table
// Manual solution: increase $id variable once in a while...
pg_close($readOnlyReplicaConn);
pg_close($pgconn_gps);
+48
View File
@@ -0,0 +1,48 @@
<?php
require '../backend.php';
global $readOnlyReplicaConn, $pgconn_gps;
$gps_singapore_buildings_insert = <<< EOS
INSERT INTO singapore_buildings(id, address, latitude, longitude, location) VALUES ($1, $2, $3, $4, st_setsrid(st_point($4, $3),4326))
EOS;
//PostgreSQL
$gps_db_host = $savvyext->cfgReadChar('gpsdatabase.host');
$gps_db_port = $savvyext->cfgReadLong('gpsdatabase.port');
$gps_db_name = $savvyext->cfgReadChar('gpsdatabase.name');
$gps_db_user = $savvyext->cfgReadChar('gpsdatabase.user');
$gps_db_pass = $savvyext->cfgReadChar('gpsdatabase.pass');
$conn_string_gps = "host=${gps_db_host} port=${gps_db_port} dbname=${gps_db_name} user=${gps_db_user} password=${gps_db_pass}";
$pgconn_gps = pg_connect($conn_string_gps);
$db_host = $savvyext->cfgReadChar('database_replica.host');
$db_name = $savvyext->cfgReadChar('database_replica.name');
$db_user = $savvyext->cfgReadChar('database_replica.user');
$db_pass = $savvyext->cfgReadChar('database_replica.pass');
$db_port = $savvyext->cfgReadLong('database_replica.port');
$readOnlyReplicaConnstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$readOnlyReplicaConn = pg_connect($readOnlyReplicaConnstr);
// Get max id from GPS DB
$q = "SELECT max(id) FROM singapore_buildings";
$r = pg_query($pgconn_gps, $q);
$id = 0;
if ($r && pg_num_rows($r) && $f=pg_fetch_row($r)) {
$id = (int)$f[0];
}
$q = "SELECT a.id, a.address, a.latitude, a.longitude FROM singapore_buildings as a WHERE a.id > ${id}";
$r = pg_query($readOnlyReplicaConn, $q);
while ($f=pg_fetch_assoc($r)) {
pg_query_params($pgconn_gps, $gps_singapore_buildings_insert, [
$f['id'],
$f['address'],
$f['latitude'],
$f['longitude']
]);
}
pg_close($readOnlyReplicaConn);
pg_close($pgconn_gps);
+165
View File
@@ -0,0 +1,165 @@
<?php
echo "[".date("Y-m-d H:i:s")."] load_past_transit_quotes job is starting.\n";
require('../backend.php');
$httpAuthToken = $savvyext->cfgReadChar('system.oauth2_token');
$db_host = $savvyext->cfgReadChar('database.host');
$db_name = $savvyext->cfgReadChar('database.name');
$db_user = $savvyext->cfgReadChar('database.user');
$db_pass = $savvyext->cfgReadChar('database.pass');
$db_port = $savvyext->cfgReadLong('database.port');
$connstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$conn = pg_connect($connstr);
$db_host = $savvyext->cfgReadChar('database_replica.host');
$db_name = $savvyext->cfgReadChar('database_replica.name');
$db_user = $savvyext->cfgReadChar('database_replica.user');
$db_pass = $savvyext->cfgReadChar('database_replica.pass');
$db_port = $savvyext->cfgReadLong('database_replica.port');
$readOnlyReplicaConnstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$readOnlyReplicaConn = pg_connect($readOnlyReplicaConnstr);
$q = "SELECT a.fare_raw,a.distance_raw,a.distance,a.board,a.alight,a.service,b.distance as bdistance ";
$q.= " FROM leg_step_quote a, google_directions_leg_steps b WHERE a.fare_raw>0 AND b.id=a.google_directions_leg_step_id AND b.travel_mode='TRANSIT' ";
$q.= " AND (b.location_start_lat BETWEEN 1.207 AND 1.471) AND (b.location_start_lng BETWEEN 103.610 AND 104.060) ";
$q.= " AND (b.location_end_lat BETWEEN 1.207 AND 1.471) AND (b.location_end_lng BETWEEN 103.610 AND 104.060)";
echo $q;
$r = pg_query($readOnlyReplicaConn, $q);
while ($f=pg_fetch_assoc($r)) {
if ($f["service"]=="MRT/LRT") {
//process_past_transit_quote_mrtlrt($f);
}
if (substr($f["service"],0,8)=="Bus Svc ") {
process_past_transit_quote_bus($f);
}
}
/*
fare_raw | distance_raw | distance | board | alight | service | bdistance
----------+--------------+----------+-----------------------------------+------------------------------------+-------------+-----------
113 | 560 | 5.6 km | 41049 - Opp Coronation Plaza | 09179 - Royal Thai Embassy | Bus Svc 174 | 5492
100 | 200 | 2.0 km | 13029 - Bef Tyersall Ave | 14539 - Beach Station Bus Terminal | Bus Svc 123 | 14621
100 | 200 | 2.0 km | 13029 - Bef Tyersall Ave | 14539 - Beach Station Bus Terminal | Bus Svc 123 | 14621
83 | 170 | 1.7 km | 91061 - Bet Hse No. 767/767A | 92041 - Opp Parkway Parade | Bus Svc 196 | 1787
83 | 130 | 1.3 km | 82051 - Tg Katong Rd Sth P/G | 92041 - Opp Parkway Parade | Bus Svc 48 | 1437
83 | 240 | 2.4 km | 11209 - Opp Peirce Rd | 09179 - Royal Thai Embassy | Bus Svc 7 | 2465
135 | 860 | 8.6 km | Buona Vista (EW21 / CC22) | Raffles Place (NS26 / EW14) | MRT/LRT | 8585
135 | 910 | 9.1 km | Bishan (NS17 / CC15) | Raffles Place (NS26 / EW14) | MRT/LRT | 9765
*/
echo "[".date("Y-m-d H:i:s")."] load_past_transit_quotes complete.\n";
pg_close($conn);
/*
boarding_id | integer |
alight_id | integer |
fare | integer |
distance | integer |
*/
function process_past_transit_quote_mrtlrt($f) {
global $conn;
echo "[".date("Y-m-d H:i:s")."] process_past_transit_quote_mrtlrt()\n";
// singapore_mrtlrt_stop_fares
$boarding_id = get_mrtlrt_stop_id($f["board"]);
$alight_id = get_mrtlrt_stop_id($f["board"]);
if ($boarding_id>0 && $alight_id>0 && $f["fare_raw"]>0) {
$q = "SELECT * FROM singapore_mrtlrt_stop_fares WHERE boarding_id=${boarding_id} AND alight_id=${alight_id}";
$r = pg_query($readOnlyReplicaConn, $q);
if ($r && pg_num_rows($r) && $o=pg_fetch_assoc($r)) {
// UP?
if ($o["fare"]>0) {
$q = "";
} else {
$q = "UPDATE SET singapore_mrtlrt_stop_fares SET fare=%s,distance=%s WHERE id=".$o["id"];
}
} else {
$q = "INSERT INTO singapore_mrtlrt_stop_fares (boarding_id,alight_id,fare,distance) VALUES (";
$q.= "${boarding_id},${alight_id},%d,%d)";
}
if ($q!="") {
$d = $f["distance_raw"]>0?((int)(10*$f["distance_raw"])):$f["bdistance"];
$q = sprintf($q,(int)$f["fare_raw"],$d);
pg_query($conn,$q);
echo "q=${q}\n";
} else {
echo "Update is not required? fare=".$o["fare"]."\n";
}
} else {
echo "ERROR: board(${boarding_id})='".$f["board"]."', alight(${alight_id})='".$f["alight"]."'\n";
}
}
function process_past_transit_quote_bus($f) {
echo "[".date("Y-m-d H:i:s")."] process_past_transit_quote_bus()\n";
global $conn, $readOnlyReplicaConn;
// singapore_bus_stop_fares
$line = substr($f["service"],8);
$boarding_id = get_bus_stop_id($f["board"],$f["service"]);
$alight_id = get_bus_stop_id($f["alight"],$f["service"]);
if ($boarding_id>0 && $alight_id>0 && $f["fare_raw"]>0) {
if ($r && pg_num_rows($r) && $o=pg_fetch_assoc($r)) {
// UP?
if ($o["fare"]>0) {
$q = "";
} else {
$q = "UPDATE SET singapore_bus_stop_fares SET fare=%s,distance=%s WHERE id=".$o["id"];
}
} else {
$q = "INSERT INTO singapore_bus_stop_fares (boarding_id,alight_id,fare,distance) VALUES (";
$q.= "${boarding_id},${alight_id},%d,%d)";
}
if ($q!="") {
$d = $f["distance_raw"]>0?((int)(10*$f["distance_raw"])):$f["bdistance"];
$q = sprintf($q,(int)$f["fare_raw"],$d);
$r = pg_query($conn,$q);
echo "q=${q}\n";
} else {
echo "Update is not required? fare=".$o["fare"]."\n";
}
} else {
echo "ERROR: board(${boarding_id})='".$f["board"]."', alight(${alight_id})='".$f["alight"]."'\n";
}
}
function get_mrtlrt_stop_id($name) {
global $readOnlyReplicaConn;
$q = "select id from singapore_mrtlrt_stops_mytransport where name='${name}'";
$r = pg_query($readOnlyReplicaConn, $q);
if ($r && pg_num_rows($r) && $f=pg_fetch_row($r)) {
return $f[0];
}
return 0;
}
function get_bus_stop_id($str,$service) {
global $readOnlyReplicaConn;
echo "'${service}' => '${str}'\n";
$line = substr($service,8);
$pos = strpos($str,'-');
if ($pos!==false) {
$stop_code = trim(substr($str,0,$pos-1));
$name = trim(substr($str,$pos+1));
} else {
$name = $str; // Will not work most likely...
$stop_code = "";
}
$q = "select id from singapore_bus_stops where name='${name}' and stop_code='${stop_code}' and line='${line}'";
$r = pg_query($readOnlyReplicaConn, $q);
if ($r && pg_num_rows($r) && $f=pg_fetch_row($r)) {
return $f[0];
}
$q = "select id from singapore_bus_stops where stop_code='${stop_code}' and line='${line}'";
$r = pg_query($readOnlyReplicaConn, $q);
if ($r && pg_num_rows($r) && $f=pg_fetch_row($r)) {
return $f[0];
}
$q = "select id from singapore_bus_stops where name='${name}' and line='${line}'";
$r = pg_query($readOnlyReplicaConn, $q);
if ($r && pg_num_rows($r) && $f=pg_fetch_row($r)) {
return $f[0];
}
return 0;
}
+43
View File
@@ -0,0 +1,43 @@
<?php
// sudo mkdir /run/php
// sudo chmod a+rw /run/php
function lock_pid_file($fn=NULL) {
if ($fn==NULL) {
$fn = '/run/php/'.basename($_SERVER['PHP_SELF'], '.php').'.pid';
}
$lock_file = fopen($fn, 'c');
$got_lock = flock($lock_file, LOCK_EX | LOCK_NB, $wouldblock);
if ($lock_file === false || (!$got_lock && !$wouldblock)) {
throw new Exception(
"Unexpected error opening or locking lock file. Perhaps you " .
"don't have permission to write to the lock file or its " .
"containing directory?"
);
}
else if (!$got_lock && $wouldblock) {
exit("Another instance is already running; terminating.\n");
}
// Lock acquired; let's write our PID to the lock file for the convenience
// of humans who may wish to terminate the script.
ftruncate($lock_file, 0);
fwrite($lock_file, getmypid() . "\n");
/*
The main body of your script goes here.
*/
return $lock_file;
}
function unlock_pid_file($lock_file) {
// All done; we blank the PID file and explicitly release the lock
// (although this should be unnecessary) before terminating.
ftruncate($lock_file, 0);
flock($lock_file, LOCK_UN);
}
/*
vi:ts=2
*/
+247
View File
@@ -0,0 +1,247 @@
<?php
echo "[" . date("Y-m-d H:i:s") . "] member_notification job is starting.\n";
require('../backend.php');
define('EMAIL_PENDING', 1);
define('EMAIL_SENT', 5);
// We will not limit the SQL we will exhaust the allowed memory
// we will process data in ${hard_limit} batches and hopefully catch up
$hard_limit = 500000;
// GPS coordinate precision to assume the same location
$precision = 3;
$tag_message = false;
$email_templates_dir = $savvyext->cfgReadChar('mailsend.templates_dir');
$template_name = "DealTemplate.html"; // This is test template.
$db_host = $savvyext->cfgReadChar('database.host');
$db_name = $savvyext->cfgReadChar('database.name');
$db_user = $savvyext->cfgReadChar('database.user');
$db_pass = $savvyext->cfgReadChar('database.pass');
$db_port = $savvyext->cfgReadLong('database.port');
$connstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$conn = pg_connect($connstr);
$db_host = $savvyext->cfgReadChar('database_replica.host');
$db_name = $savvyext->cfgReadChar('database_replica.name');
$db_user = $savvyext->cfgReadChar('database_replica.user');
$db_pass = $savvyext->cfgReadChar('database_replica.pass');
$db_port = $savvyext->cfgReadLong('database_replica.port');
$readOnlyReplicaConnstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$readOnlyReplicaConn = pg_connect($readOnlyReplicaConnstr);
include 'notifications_functions.php';
function Fextension_call($in, &$out) {
// logToFl("Merchant_Name count->" . $in["merchant_name"]);
$in["pid"] = 100; // not used currenlty
global $savvyext;
$out = $savvyext->savvyext_api($in);
$ret = $out["retval"];
return $ret;
}
//exit();
$mysql = "SELECT value FROM global_settings WHERE key='tag_notififaction' AND value='1'";
$r = pg_query($readOnlyReplicaConn, $mysql);
if ($r && pg_num_rows($r)) {
$tag_message = true;
}
$mysql = "SELECT n.id AS notify_id,m.id AS m_id,m.email AS reciever_email, n.*, e.category, e.frequency, e.send_day, e.send_time
FROM members_notification n LEFT JOIN members m ON m.id = n.member_id
LEFT JOIN email_trigger e ON e.e_trigger = n.trigger_key
WHERE n.status IN (" . EMAIL_PENDING . ")
AND m.alert_notification = 1
AND n.notice_type = 'INSTANT'
ORDER BY n.ic ASC LIMIT 100";
//AND m.id IN (SELECT member_id FROM test_accounts WHERE status=1)
$r = pg_query($readOnlyReplicaConn, $mysql);
$acc = array();
if ($r && pg_num_rows($r)) {
// Load Email template
$htm_template = file_get_contents($email_templates_dir . "/" . $template_name);
while ($f = pg_fetch_assoc($r)) {
$member_id = $f["member_id"];
$notify_id = $f["notify_id"];
$reciever_email = $f["reciever_email"];
$notice_type = $f["notice_type"];
$trigger_key = $f["trigger_key"];
$category = $f["category"];
$frequency_day = $f["frequency"];//num of days
$send_day = $f["send_day"];
$send_time = $f["send_time"];
$current_day = strtolower(date('l', strtotime($date)));
$current_hour = date("H:00:00");
$message = $f["msg"];
$extension_call = false;
$x["pid"] = 0;
$x["member_id"] = $member_id;
$x["notify_id"] = $notify_id;
$extension_call = true;
$q_count = "UPDATE members_notification SET ic=ic+1 WHERE id = " . $notify_id;
pg_query($conn, $q_count);
$approve_send = true;
$send_count = 0;
if ( $notice_type == "INSTANT"){
$approve_send = true; // send instant immediatley;
}
if (false == $approve_send && $send_count < 4) {
}
// ANY MESSAGE IN THE LAST 12 HOURS =====================MOVE TO A FUNCTION
//
//
// SEND Notification if APPLICABLE
$data = []; // reset the data
$q = "SELECT * FROM members_devices WHERE status =1 AND member_id=${member_id} ";
//$r = $this->db->query($q);
$r1 = pg_query($readOnlyReplicaConn, $q);
while ($f1 = pg_fetch_assoc($r1)) {
$data["devices"][] = $f1["player_id"]; //$row->player_id;
$device_count++;
}
//print_r( $data["devices"] );
if ( $notice_type == 'INSTANT' ) {
$cat = $category; // "GOACTIVITY";
generateCard($notify_id, $member_id, $cat);
$arrayData = array("NEXTSCREEN" => $cat);
if (true == $approve_send) {
//upodate before sedning
$q_sent = "UPDATE members_notification SET status = " . EMAIL_SENT . ",date_sent=now() WHERE id = " . $notify_id;
pg_query($conn, $q_sent);
sendmemberMessage($member_id, $data["devices"], $message, $arrayData, $tag_message);
}
}
if ($notice_type == 'EMAILALERT') {
// sending email - IF APPLICABLE
if ($reciever_email != '' && $htm_template) {
$values = [
"to_emails" => "{" . $reciever_email . "}",
"subject" => "Float Deal",
"html_body" => pg_escape_string($htm_template),
"status" => "0",
"created_at" => (new DateTime())->format('c'),
"updated_at" => (new DateTime())->format('c')
];
$values = array_filter($values, 'strlen');
$q = "INSERT INTO emails ";
$q .= " (" . implode(", ", array_keys($values)) . ")";
$q .= " VALUES ('" . implode("', '", $values) . "') ";
$rs = pg_query($conn, $q);
if ($rs) {
$q = "UPDATE members_notification SET status = " . EMAIL_SENT . " WHERE id = " . $notify_id;
// $rs = pg_query($conn, $q);
}
}
} // if EMAIl ALERT IS NEEDED
// print_r($acc);
}
}
function sendmemberMessage($member_id, $player_id_array, $message, $arrayData, $tag_message = false) {
$ic = 0;
$player_id_string = "";
// print_r($player_id_array);
if (is_array($player_id_array) && $message != "" && count($player_id_array) > 0 && is_array($arrayData)) {
if (true == $tag_message) {
$message = $message . " - " . $member_id;
}
$one_success = false;
foreach ($player_id_array as $pl) {
$sprt = "";
if ($pl != '') {
$player_id_array = array($pl);
$result = postOneSignal($player_id_array, $message, $arrayData);
//var_dump($result);
// if result is true assign to one_success
}
}
// if one succeess, then call sendKochavaEvent
} else {
echo "Invalid PLAYER_ID and/or MESSAGE!";
}
}
function sendKochavaEvent(){
// send data here
}
function postOneSignal($player_id_array, $message, $arrayData) {
global $savvyext;
// $url = $savvyext->cfgReadChar('onesignal.url');
//echo $app_id = $savvyext->cfgReadChar('onesignal.app_id');
$url = "https://onesignal.com/api/v1/notifications";
$app_id = "e9a7bb38-0a27-4250-9fb7-9bd7871d7b63";
$data = [
'app_id' => $app_id,
'contents' => ['en' => $message],
'headings' => ['en' => 'Float Activities'],
'subtitle' => ['en' => 'Your account activities message from Float.'],
'content_available' => true,
'mutable_content' => true,
'include_player_ids' => $player_id_array,
'data' => $arrayData
];
$opts = array(
'http' => array(
'method' => "POST",
'header' =>
"Content-Type: application/json; charset=utf-8\r\n" .
"Accept: application/json\r\n",
'content' => json_encode($data)
)
);
// print_r($opts);
// print_r($data);
// echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \n <br>";
$context = stream_context_create($opts);
$body = file_get_contents($url, false, $context);
error_log($body);
$result = json_decode($body, true);
return $result;
}
pg_close($conn);
pg_close($readOnlyReplicaConn);
echo "[" . date("Y-m-d H:i:s") . "] member_notification job complete.\n";
?>
+135
View File
@@ -0,0 +1,135 @@
<?php
echo "[" . date("Y-m-d H:i:s") . "] member_lifecyle_emails job is starting.\n";
require('../backend.php');
define('EMAIL_PENDING', 1);
define('EMAIL_SENT', 5);
// We will not limit the SQL we will exhaust the allowed memory
// we will process data in ${hard_limit} batches and hopefully catch up
$hard_limit = 500000;
// GPS coordinate precision to assume the same location
$precision = 3;
echo $email_templates_dir = $savvyext->cfgReadChar('mailsend.templates_dir');
$template_name = "How_it_works.html"; // This is test template.
$db_host = $savvyext->cfgReadChar('database.host');
$db_name = $savvyext->cfgReadChar('database.name');
$db_user = $savvyext->cfgReadChar('database.user');
$db_pass = $savvyext->cfgReadChar('database.pass');
$db_port = $savvyext->cfgReadLong('database.port');
$connstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$conn = pg_connect($connstr);
$db_host = $savvyext->cfgReadChar('database_replica.host');
$db_name = $savvyext->cfgReadChar('database_replica.name');
$db_user = $savvyext->cfgReadChar('database_replica.user');
$db_pass = $savvyext->cfgReadChar('database_replica.pass');
$db_port = $savvyext->cfgReadLong('database_replica.port');
$readOnlyReplicaConnstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$readOnlyReplicaConn = pg_connect($readOnlyReplicaConnstr);
// send peding emsils
$notice_type = 'EMAILALERT';
//savvy=> SELECT l.id AS life_id,l.* FROM members_lifecycle_emails l LEFT JOIN members m ON m.id=l.member_id WHERE l.status = 1 ;
// life_id | id | member_id | cycle_type | subject | status | added | completed
$mysql = "SELECT l.id AS life_id,l.*,m.email AS reciever_email FROM members_lifecycle_emails l LEFT JOIN members m ON m.id=l.member_id WHERE l.status = 1";
$r0 = pg_query($readOnlyReplicaConn, $mysql);
if ($r0 && pg_num_rows($r0)) {
while ($f0 = pg_fetch_assoc($r0)) {
$member_id = $f0["member_id"];
$life_id = $f0["life_id"];
$reciever_email = $f0["reciever_email"];
$subject = $f0["subject"];
$qup = "UPDATE members_lifecycle_emails SET status = 4 WHERE id=$life_id";
pg_query($conn, $qup);
if ($notice_type == 'EMAILALERT') {
$htm_template = file_get_contents($email_templates_dir . "/lifecycle/" . $template_name); // note read evertime in case we need to change some parameters
if ($reciever_email != '' && $htm_template) {
$values = [
"to_emails" => "{" . $reciever_email . "}",
"member_id" => "" . $member_id . "",
"subject" => $subject,
"html_body" => pg_escape_string($htm_template),
"status" => "0",
"created_at" => (new DateTime())->format('c'),
"updated_at" => (new DateTime())->format('c')
];
$values = array_filter($values, 'strlen');
$q = "INSERT INTO emails ";
$q .= " (" . implode(", ", array_keys($values)) . ")";
$q .= " VALUES ('" . implode("', '", $values) . "') ";
$rs = pg_query($conn, $q);
if ($rs) {
$q = "UPDATE members_lifecycle_emails SET status = " . EMAIL_SENT . ", completed=now() WHERE id = " . $life_id;
$rs = pg_query($conn, $q);
}
}
} // if EMAIl ALERT IS NEEDED
}
}
//genedate new list of emails
$mysql = "SELECT *, id AS member_id FROM members WHERE id > 0 AND now() BETWEEN added+'1 minute' AND added+'2 day' AND id NOT IN (SELECT member_id FROM members_lifecycle_emails WHERE cycle_type ='HOWITWORKS' )";
// TEST echo
//$mysql = "SELECT *, id AS member_id FROM members WHERE id < 5 AND id> 0 AND id NOT IN (SELECT member_id FROM members_lifecycle_emails WHERE cycle_type ='HOWITWORKS' ) ORDER BY id ASC";
$r = pg_query($readOnlyReplicaConn, $mysql);
if ($r && pg_num_rows($r)) {
while ($f = pg_fetch_assoc($r)) {
$member_id = $f["member_id"];
$values = [
"member_id" => "" . $member_id . "",
"subject" => "Float - How it Works",
"cycle_type" => "HOWITWORKS"
];
$values = array_filter($values, 'strlen');
$q = "INSERT INTO members_lifecycle_emails ";
$q .= " (" . implode(", ", array_keys($values)) . ")";
echo $q .= " VALUES ('" . implode("', '", $values) . "') ";
$rs = pg_query($conn, $q);
}
}
/*
*
*
* CREATE TABLE members_lifecycle_emails (
id SERIAL,
member_id INT REFERENCES members(id),
cycle_type VARCHAR(15) NOT NULL REFERENCES email_cycle_types(cycle_type),
subject VARCHAR(100),
status integer DEFAULT 1,
added timestamp without time zone DEFAULT now(),
completed timestamp without time zone DEFAULT null
);
ALTER TABLE ONLY members_lifecycle_emails
ADD CONSTRAINT members_lifecycle_emails_id_key UNIQUE (id);
*/
pg_close($conn);
pg_close($readOnlyReplicaConn);
echo "[" . date("Y-m-d H:i:s") . "] member_lifecyle_emails job complete.\n";
?>
+292
View File
@@ -0,0 +1,292 @@
<?php
echo "[" . date("Y-m-d H:i:s") . "] member_notification job is starting.\n";
require('../backend.php');
define('EMAIL_PENDING', 1);
define('EMAIL_SENT', 5);
// We will not limit the SQL we will exhaust the allowed memory
// we will process data in ${hard_limit} batches and hopefully catch up
$hard_limit = 500000;
// GPS coordinate precision to assume the same location
$precision = 3;
$tag_message = false;
$email_templates_dir = $savvyext->cfgReadChar('mailsend.templates_dir');
$template_name = "DealTemplate.html"; // This is test template.
$db_host = $savvyext->cfgReadChar('database.host');
$db_name = $savvyext->cfgReadChar('database.name');
$db_user = $savvyext->cfgReadChar('database.user');
$db_pass = $savvyext->cfgReadChar('database.pass');
$db_port = $savvyext->cfgReadLong('database.port');
$connstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$conn = pg_connect($connstr);
$db_host = $savvyext->cfgReadChar('database_replica.host');
$db_name = $savvyext->cfgReadChar('database_replica.name');
$db_user = $savvyext->cfgReadChar('database_replica.user');
$db_pass = $savvyext->cfgReadChar('database_replica.pass');
$db_port = $savvyext->cfgReadLong('database_replica.port');
$readOnlyReplicaConnstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$readOnlyReplicaConn = pg_connect($readOnlyReplicaConnstr);
include 'notifications_functions.php';
function Fextension_call($in, &$out) {
// logToFl("Merchant_Name count->" . $in["merchant_name"]);
$in["pid"] = 100; // not used currenlty
global $savvyext;
$out = $savvyext->savvyext_api($in);
$ret = $out["retval"];
return $ret;
}
//exit();
$mysql = "SELECT value FROM global_settings WHERE key='tag_notififaction' AND value='1'";
$r = pg_query($readOnlyReplicaConn, $mysql);
if ($r && pg_num_rows($r)) {
$tag_message = true;
}
//===================================================================================================================
/*
* DEACTIVATE 24 hours expired cards
*/
$mysql_expired_cards = "SELECT mc.id FROM members_card_assign mc "
. "LEFT JOIN email_trigger et ON et.e_trigger=mc.trigger_key "
. "WHERE mc.trigger_key IS NOT NULL "
. "AND mc.status = 1 "
. "AND et.expiration = 'EXP00002' "
. "AND now() > mc.updated + '12 hours' LIMIT 500";
$mysql_del_list = "UPDATE members_card_assign SET status = 0 WHERE id IN ( $mysql_expired_cards ) AND trigger_key IS NOT NULL";
pg_query($conn, $mysql_del_list); // REAL UPDATE TO CARD STATUS
//======================================================================================================================
$mysql = "SELECT n.id AS notify_id,m.id AS m_id,m.email AS reciever_email, n.*, e.category, e.frequency, e.send_day, e.send_time
FROM members_notification n LEFT JOIN members m ON m.id = n.member_id
LEFT JOIN email_trigger e ON e.e_trigger = n.trigger_key
WHERE n.status IN (" . EMAIL_PENDING . ")
AND m.alert_notification = 1
ORDER BY n.ic ASC LIMIT 100";
//AND m.id IN (SELECT member_id FROM test_accounts WHERE status=1)
$r = pg_query($readOnlyReplicaConn, $mysql);
$acc = array();
if ($r && pg_num_rows($r)) {
// Load Email template
$htm_template = file_get_contents($email_templates_dir . "/" . $template_name);
while ($f = pg_fetch_assoc($r)) {
$member_id = $f["member_id"];
$notify_id = $f["notify_id"];
$reciever_email = $f["reciever_email"];
$notice_type = $f["notice_type"];
$category = $f["category"];
$trigger_key = $f["trigger_key"];
$frequency_day = $f["frequency"];//num of days
$send_day = $f["send_day"];
$send_time = $f["send_time"];
$current_day = strtolower(date('l'));//current day name
$current_hour = date("H:00:00");
$message = $f["msg"];
$extension_call = false;
$x["pid"] = 0;
$x["member_id"] = $member_id;
$x["notify_id"] = $notify_id;
$extension_call = true;
$q_count = "UPDATE members_notification SET ic=ic+1 WHERE id = " . $notify_id;
pg_query($conn, $q_count);
$approve_send = true;
$send_count = 0;
//CHECK FREQUENCY
if(!empty($frequency_day) && !empty($send_day) && !empty($send_time)){
$day_check = strtolower(date('l', strtotime(-$frequency_day." days")));
if($day_check != $send_day){
$approve_send = false;
}
if($send_time != $current_hour){
$approve_send = false;
}
}
if ($notice_type == "INSTANT") {
$approve_send = true; // send instant immediatley;
} else {
// ANY MESSAGE IN THE LAST 12 HOURS =====================MOVE TO A FUNCTION
$q_test = "SELECT count(id) AS send_count from members_notification WHERE member_id = $member_id AND status=5 AND date_sent IS NOT NULL AND now() < date_sent+'12 hour' AND trigger_key='".$trigger_key."'";
$r0 = pg_query($readOnlyReplicaConn, $q_test);
if ($r0 && pg_num_rows($r0) > 0) {
$f0 = pg_fetch_assoc($r0);
$send_count = $f0["send_count"];
if ($send_count > 0) {
$approve_send = false;
}
}
if(!empty($frequency_day)){
$q_test = "SELECT count(id) AS send_count from members_notification WHERE member_id = $member_id AND status=5 AND date_sent IS NOT NULL AND now() < date_sent+'".$frequency_day." days' AND trigger_key='".$trigger_key."'";
$r0 = pg_query($readOnlyReplicaConn, $q_test);
if ($r0 && pg_num_rows($r0) > 0) {
$f0 = pg_fetch_assoc($r0);
$send_count = $f0["send_count"];
if ($send_count > 0) {
$approve_send = false;
}
}
}
}
if (false == $approve_send && $send_count < 4) {
}
// ANY MESSAGE IN THE LAST 12 HOURS =====================MOVE TO A FUNCTION
//
//
// SEND Notification if APPLICABLE
$data = []; // reset the data
$q = "SELECT * FROM members_devices WHERE status =1 AND member_id=${member_id} ";
//$r = $this->db->query($q);
$r1 = pg_query($readOnlyReplicaConn, $q);
while ($f1 = pg_fetch_assoc($r1)) {
$data["devices"][] = $f1["player_id"]; //$row->player_id;
$device_count++;
}
//print_r( $data["devices"] );
// Let take a look at the last time the user get this trigger - see if we need to span the message
if ($notice_type == 'GENALERT' || $notice_type == 'INSTANT') {
$cat = $category; // "GOACTIVITY";
generateCard($notify_id, $member_id, $cat);
$arrayData = array("NEXTSCREEN" => $cat);
if (true == $approve_send) {
//upodate before sedning
$q_sent = "UPDATE members_notification SET status = " . EMAIL_SENT . ",date_sent=now() WHERE id = " . $notify_id;
pg_query($conn, $q_sent);
sendmemberMessage($member_id, $data["devices"], $message, $arrayData, $tag_message);
}
}
if ($notice_type == 'EMAILALERT') {
// sending email - IF APPLICABLE
if ($reciever_email != '' && $htm_template) {
$values = [
"to_emails" => "{" . $reciever_email . "}",
"subject" => "Float Deal",
"html_body" => pg_escape_string($htm_template),
"status" => "0",
"created_at" => (new DateTime())->format('c'),
"updated_at" => (new DateTime())->format('c')
];
$values = array_filter($values, 'strlen');
$q = "INSERT INTO emails ";
$q .= " (" . implode(", ", array_keys($values)) . ")";
$q .= " VALUES ('" . implode("', '", $values) . "') ";
$rs = pg_query($conn, $q);
if ($rs) {
$q = "UPDATE members_notification SET status = " . EMAIL_SENT . " WHERE id = " . $notify_id;
// $rs = pg_query($conn, $q);
}
}
} // if EMAIl ALERT IS NEEDED
// print_r($acc);
}
}
function sendmemberMessage($member_id, $player_id_array, $message, $arrayData, $tag_message = false) {
$ic = 0;
$player_id_string = "";
// print_r($player_id_array);
if (is_array($player_id_array) && $message != "" && count($player_id_array) > 0 && is_array($arrayData)) {
if (true == $tag_message) {
$message = $message . " - " . $member_id;
}
$one_success = false;
foreach ($player_id_array as $pl) {
$sprt = "";
if ($pl != '') {
$player_id_array = array($pl);
$result = postOneSignal($player_id_array, $message, $arrayData);
//var_dump($result);
// if result is true assign to one_success
}
}
// if one succeess, then call sendKochavaEvent
} else {
echo "Invalid PLAYER_ID and/or MESSAGE!";
}
}
function sendKochavaEvent() {
// send data here
}
function postOneSignal($player_id_array, $message, $arrayData) {
global $savvyext;
// $url = $savvyext->cfgReadChar('onesignal.url');
//echo $app_id = $savvyext->cfgReadChar('onesignal.app_id');
$url = "https://onesignal.com/api/v1/notifications";
$app_id = "e9a7bb38-0a27-4250-9fb7-9bd7871d7b63";
$data = [
'app_id' => $app_id,
'contents' => ['en' => $message],
'headings' => ['en' => 'Float Activities'],
'subtitle' => ['en' => 'Your account activities message from Float.'],
'content_available' => true,
'mutable_content' => true,
'include_player_ids' => $player_id_array,
'data' => $arrayData
];
$opts = array(
'http' => array(
'method' => "POST",
'header' =>
"Content-Type: application/json; charset=utf-8\r\n" .
"Accept: application/json\r\n",
'content' => json_encode($data)
)
);
// print_r($opts);
// print_r($data);
// echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \n <br>";
$context = stream_context_create($opts);
$body = file_get_contents($url, false, $context);
error_log($body);
$result = json_decode($body, true);
return $result;
}
pg_close($conn);
pg_close($readOnlyReplicaConn);
echo "[" . date("Y-m-d H:i:s") . "] member_notification job complete.\n";
?>
+510
View File
@@ -0,0 +1,510 @@
<?php
echo "[" . date("Y-m-d H:i:s") . "] member_prepare_notification job is starting.\n";
require('../backend.php');
// We will not limit the SQL we will exhaust the allowed memory
// we will process data in ${hard_limit} batches and hopefully catch up
$hard_limit = 500000;
// GPS coordinate precision to assume the same location
$precision = 3;
$db_host = $savvyext->cfgReadChar('database.host');
$db_name = $savvyext->cfgReadChar('database.name');
$db_user = $savvyext->cfgReadChar('database.user');
$db_pass = $savvyext->cfgReadChar('database.pass');
$db_port = $savvyext->cfgReadLong('database.port');
$connstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$conn = pg_connect($connstr);
$db_host = $savvyext->cfgReadChar('database_replica.host');
$db_name = $savvyext->cfgReadChar('database_replica.name');
$db_user = $savvyext->cfgReadChar('database_replica.user');
$db_pass = $savvyext->cfgReadChar('database_replica.pass');
$db_port = $savvyext->cfgReadLong('database_replica.port');
$readOnlyReplicaConnstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$readOnlyReplicaConn = pg_connect($readOnlyReplicaConnstr);
include 'notifications_functions.php';
/*
LEFT us refesh the triggertable
*/
foreach ($trigger_query AS $key => $lrow) {
$system_id = $key;
$mysql = $lrow["query"];
$message = $lrow["message"];
$active = $lrow["active"];
$category = $lrow["cat"];
$dynamic_key = $lrow["dynamic_key"];
$send_mail = $lrow["send_mail"];
$send_notification = $lrow["send_notification"];
$icon = $lrow["icon"];
$sq2 = "SELECT * FROM email_trigger WHERE e_trigger='$system_id'";
$r2 = pg_query($readOnlyReplicaConn, $sq2);
if ($r2 && pg_num_rows($r2) == 0) {
$template_name = trim(strtolower($system_id . ".html"));
$values = [
"e_trigger" => "" . $system_id . "",
"category" => "" . $category . "",
"message" => pg_escape_string($message),
"action_detail" => pg_escape_string($message),
"template_name" => $template_name,
"dynamic_key" => $dynamic_key,
"status" => $active,
"override_text" => "1",
"expiration" => "EXP00000",
"icon" => $icon,
];
$values = array_filter($values, 'strlen');
$q = "INSERT INTO email_trigger ";
$q .= " (" . implode(", ", array_keys($values)) . ")";
$q .= " VALUES ('" . implode("', '", $values) . "') ";
// echo $q;
$rs = pg_query($conn, $q);
} else {
$template_name = trim(strtolower($system_id . ".html"));
/* $values = [
"category" => "" . $category . "",
"message" => pg_escape_string($message),
"template_name" => $template_name,
"dynamic_key" => $dynamic_key,
"send_mail" => $send_mail,
"send_notification" => $send_notification,
"status" => $active
];
*/
$values = [
"message" => pg_escape_string($message),
"template_name" => $template_name,
"dynamic_key" => $dynamic_key
];
//echo "jcjcjcjcjjcc";
$msqUpdt = "";
$ick = 0;
foreach ($values as $key => $val) {
if ($ick > 0) {
$msqUpdt .= ",";
}
$msqUpdt .= " $key = '" . $val . "'";
$ick++;
}
if ($ick > 0) {
$q = "UPDATE email_trigger SET " . $msqUpdt;
$q .= " WHERE e_trigger ='$system_id' ";
// do not update all
// echo $q;
// $rs = pg_query($conn, $q);
}
}
}
//---------------------ATTEND TO THE CAR POOL NOTIFIFICATION ETRG0020 ----------------------------------------
/* savvy=> SELECT * FROM members_trips WHERE member_id =1 LIMIT 1;
id | member_id | trip_name | trip_from | trip_to | country | trip_date | status | added | color
----+-----------+------------+---------------------------------------------+-------------------------------------+---------+---------------------+--------+----------------------------+--------
1 | 1 | Trip 62236 | 4201 Defoors Fram Trail, Powder Springs, GA | 3500 Riverwood parkway, Atlanta, GA | US | 2019-12-12 11:30:00 | 1 | 2019-12-16 00:10:33.354752 | 6464e2
(1 row)
*/
$mysql_trip = "SELECT id AS trip_id, * FROM members_trips WHERE member_id > 0 AND now()+'15 minutes' < trip_date AND trip_date > now()+ '-30 minutes' AND notify = 0 LIMIT 10";
$r = pg_query($conn, $mysql_trip);
$acc = array();
if ($r && pg_num_rows($r)) {
while ($f = pg_fetch_assoc($r)) {
$member_id = $f["member_id"];
$trip_id = $f["trip_id"];
$trip_from = $f["trip_from"];
$trip_to = $f["trip_to"];
$trip_date = $f["trip_date"];
$trip_name = $f["trip_name"];
$sql_up = "UPDATE members_trips SET notify =notify + 1 WHERE id = $trip_id AND member_id = $member_id ";
pg_query($conn, $sql_up);
$extension_call = true;
if ($extension_call == true) {
$outX = array();
$x = array();
//$member_id = 1;
$x["pid"] = 0;
$x["member_id"] = $member_id;
$x["notice_type"] = "INSTANT";
$x["mmode"] = "AUTO";
$x["trigger_key"] = "ETRG0020";
$x["msg"] = "You have an upcoming trip $trip_name today at $trip_date to $trip_to";
$x["action"] = FLOAT_SYSTEM_CREATE_NOTIFICATION;
//print_r($x);
Fextension_call($x, $outX);
}
}
}
// ------------------------------------------------------------------- ----------------------------------------
/*
*
* "ETRG0007" => array(
"query" => "SELECT ma.*,m.min_budget,(ma.spend_14 - 2*ma.spend_7) AS week_increase from members_analysis ma LEFT JOIN members m ON m.id = ma.member_id WHERE m.decision_group IN('A1NUS25','USSF001') AND m.id NOT IN (SELECT member_id FROM members_carpool) ORDER BY m.notification_test ASC LIMIT 500",
"message" => "Deal Carpool Try carpooling and save $X and Y emissions this month",
* "html_body" => pg_escape_string($htm_template),
savvy=> select * from email_trigger;
id | e_trigger | category | action_detail | template_name | status | added | updated
----+-----------+------------+------------------------------------------+-----------------+--------+----------------------------+----------------------------
2 | ETRG0002 | GOACTIVITY | Put Details Here | dealtmp022.html | 1 | 2020-02-18 15:06:46.721542 | 2020-02-18 15:06:46.721542
3 | ETRG0003 | GOACTIVITY | Put Details Here | dealtmp033.html | 1 | 2020-02-18 15:06:46.725502 | 2020-02-18 15:06:46.725502
4 | ETRG0004 | GOACTIVITY | Put Details Here | dealtmp044.html | 1 | 2020-02-18 15:06:46.729315 | 2020-02-18 15:06:46.729315
5 | ETRG0005 | GOACTIVITY | Put Details Here | dealtmp055.html | 1 | 2020-02-18 15:06:46.733011 | 2020-02-18 15:06:46.733011
1 | ETRG0001 | GOACTIVITY | <p><strong>Put Details Here</strong></p>+| dealtmp011.html | 1 | 2020-02-18 15:06:46.716103 | 2020-02-18 15:06:46.716103
| | | | | | |
(5 rows)
$trigger_query = array(
"SURGESAVE" => array(
"query" => $mysql,
"message" => "You are spending too much. Let's save money",
"active" => 1,
"cat" => 'GOACTIVITY',
"dynamic_key" => "",
"start_save" => false
),
*/
function Fextension_call($in, &$out) {
// logToFl("Merchant_Name count->" . $in["merchant_name"]);
global $savvyext;
$out = $savvyext->savvyext_api($in);
$ret = $out["retval"];
return $ret;
}
// clear out the expired list first
$sq2 = "UPDATE members_notification SET status =2 WHERE status = 1 AND expire < now() AND notice_type!='INSTANT'";
$r2 = pg_query($conn, $sq2);
foreach ($trigger_query AS $key => $lrow) {
$system_id = $key;
$mysql = $lrow["query"];
$message = $lrow["message"];
$active = $lrow["active"];
$extension_call = $lrow["start_save"];
if (1 == $active && $system_id != '') {
// echo $system_id. " - <hr> - ".$mysql;
$mysql_up = "UPDATE email_trigger SET last_run = now() WHERE e_trigger = '$system_id'";
pg_query($conn, $mysql_up);
$r = pg_query($conn, $mysql);
$acc = array();
if ($r && pg_num_rows($r)) {
// echo $system_id. " - <hr> - ".$mysql;
// echo 'ddhdhdhd';
while ($f = pg_fetch_assoc($r)) {
$member_id = $f["member_id"];
$extension_call = false; // does not matter - dontset to send by =default.
if (array_key_exists($member_id, $acc)) {
// echo "here " . $member_id;
// nothing - we dont want duplicate
} else {
$sq2 = "SELECT * FROM members_notification WHERE member_id=$member_id AND trigger_key ='$system_id' AND status IN (1)";
$r2 = pg_query($readOnlyReplicaConn, $sq2);
$x["pid"] = 0;
$x["member_id"] = $member_id;
$x["notice_type"] = "GENALERT";
$acc[$member_id] = $member_id;
if ($r2 && pg_num_rows($r2) == 0) {
$x["msg"] = $message;
$extension_call = true;
// modify the message here
if ($system_id == "SURGESAVE") {
$extension_call = false; // turn message off
// print_r($x);
if ($f["surge_price"] > 0 && $f["cheaper_alternative"] > 0) {
$x["msg"] = "We have found a way to save time and money for you";
}
if ($f["surge_price"] > 0 && $f["cheaper_alternative"] == 0) {
$x["msg"] = "We have found a way to save time for you";
}
$extension_call = true;
}
if ($system_id == "ETRG0002") {
$percent_less = 100 - ($f["spend_7"] / $f["min_budget"]) * 100;
$x["msg"] = "Good Job, you're " . round($percent_less, 2) . "% below your budget. Let's save more.";
}
if ($system_id == "ETRG0004") {
$rideshare_30 = $f["rideshare_30"] * 0.01;
$extension_call = false; // turn message off
if ($rideshare_30 > 0) {
$x["msg"] = "We can see you spent $ $rideshare_30 on rideshare this month. Here's how Float can save you money";
$extension_call = true; // turn message off
}
}
if ($system_id == "ETRG0005") {
$extension_call = false;
$x["msg"] = getAccountBenefit($readOnlyReplicaConn, $member_id, $extension_confirm_call);
if ($x["msg"] != '' && $extension_confirm_call == true) {
$extension_call = $extension_confirm_call;
}
}
if ($system_id == "ETRG0006") {
$percent_increase = round($f["week_increase"] / $f["spend_7"]) * 100;
$extension_call = false;
if ($percent_increase > 0) {
$x["msg"] = "Your spending is up $percent_increase% this week. Would you like to create a budget?";
$extension_call = true; // turn message off
}
}
if ($system_id == "ETRG0007") {
//$percent_increase = round($f["week_increase"] / $f["spend_7"], 2) * 100;
$extension_call = false; // turn message off
$emmission_save = rand(100, 200);
$emmission_value = rand(100, 200);
$country = $f["country"];
$week_increase = $f["week_increase"] * 0.01;
if ($week_increase > 0) {
$emmission_save = round($week_increase, 2);
$emisson = getEmissionModel($week_increase, 1, $country);
$emmission_value = round($emisson[0], 2);
$x["msg"] = "Try carpooling and save $$emmission_save and $emmission_value grams of emissions this month";
$extension_call = true;
}
//"Your spending is up $percent_increase% this week. Let's create a budget together";
}
if ($system_id == "ETRG0014") {
$extension_call = false; // turn message off
/*
id | member_id | updated | spend_7 | rideshare_30 | spend_14 | gas_7 | gas_30 | gas_14 | min_budget | week_increase
-----+-----------+----------------------------+---------+--------------+----------+-------+--------+--------+------------+---------------
191 | 202 | 2020-05-06 11:20:04.339684 | 92989 | 75433 | 162604 | 42949 | 174047 | 77361 | 27500 | 23374
117 | 76 | 2020-05-06 11:05:05.830233 | 1995 | 0 | 1995 | 0 | 0 | 0 | 0 | 1995
*/
$week_increase = $f["week_increase"] * 0.01;
if ($week_increase >= 20) {
$emmission_inc = emissonIncrease($member_id, 7);
if ($emmission_inc > 0) {
$x["msg"] = "Your emissions output is $emmission_inc% higher this week, lets see how we can lower it";
$extension_call = true;
}
}
}
if ($system_id == "ETRG0015") {
$extension_call = false; // turn message off
/*
id | member_id | updated | spend_7 | rideshare_30 | spend_14 | gas_7 | gas_30 | gas_14 | min_budget | week_decrease
-----+-----------+----------------------------+---------+--------------+----------+-------+--------+--------+------------+---------------
194 | 186 | 2020-04-28 17:45:03.507661 | 172933 | 116230 | 315990 | 66650 | 215045 | 128172 | 0 | 29876
*/
$week_decrease = $f["week_decrease"] * 0.01;
if ($week_decrease >= 20) {
$less_minutes = getTripMinutes($member_id, 7);
if ($less_minutes > 0) {
$x["msg"] = "Hurray, you have spent $less_minutes minutes less on the road this week.";
$extension_call = true;
}
}
}
if ($system_id == "ETRG0019") {
$extension_call = false; // this is managed by another automation
}
}
}
pg_query($conn, "UPDATE members SET notification_test = now()+'1 day' WHERE id = $member_id");
if ($extension_call == true) {
$outX = array();
$x["mmode"] = "AUTO";
$x["trigger_key"] = $system_id;
$x["action"] = FLOAT_SYSTEM_CREATE_NOTIFICATION;
print_r($x);
Fextension_call($x, $outX);
}
// print_r($acc);
}
}
} // end if active
}
exit();
function emissonIncrease($member_id, $days_gap) {
$emmission_inc = rand(0, 28);
return $emmission_inc;
}
function getTripMinutes($member_id, $days_gap) {
$less_minutes = rand(12, 99);
return $less_minutes;
}
function getEmissionModel($gas_amount, $gas_number, $gas_country = 'US') {
// GAS MODEL ASSUMPTIONS
$average_car_CO2_emissions = 168;
$average_distance_travelled_pre_litre_of_petrol_km = 13;
$average_price_per_litre_USD = 1.07;
if ('SG' == $gas_country) {
$average_price_per_litre_USD = 1.39;
}
$estimated_litres_of_fuel_purchased_litres = $gas_amount / $average_price_per_litre_USD;
$estimated_distance_travelled_per_re_fuel_km = $estimated_litres_of_fuel_purchased_litres * $average_distance_travelled_pre_litre_of_petrol_km;
$estimated_total_CO2_emissions_per_refuel = $estimated_distance_travelled_per_re_fuel_km * $average_car_CO2_emissions;
$estimated_CO2_emissions_per_month = $estimated_total_CO2_emissions_per_refuel * $gas_number;
$estimated_CO2_emissions_per_week = $estimated_CO2_emissions_per_month * 12 / 52;
$data = [];
$data[0] = $estimated_total_CO2_emissions_per_refuel;
$data[1] = $estimated_CO2_emissions_per_month;
$data[2] = $estimated_CO2_emissions_per_week;
return $data;
}
function getAccountBenefit($conn, $member_id, &$extension_confirm_call) {
$msg_text = "";
$extension_confirm_call = false;
// $msql = "SELECT b.id AS bank_id,ccb.benefit from members_bank_accounts mb LEFT JOIN banks b ON b.bank_name = mb.bank_name LEFT JOIN credit_card_benefits ccb ON ccb.credit_card_id = b.id WHERE mb.member_id = $member_id AND ccb.benefit IS NOT NULL LIMIT 1";
$myqsl = "SELECT b.id AS bank_id,ccb.benefit from members_bank_accounts mb "
. " LEFT JOIN credit_cards b ON b.card_name= mb.description "
. " LEFT JOIN credit_card_benefits ccb ON ccb.credit_card_id = b.id "
. " WHERE mb.member_id = $member_id AND ccb.benefit IS NOT NULL "
. " ORDER BY random() LIMIT 1";
$r2 = pg_query($conn, $myqsl);
if ($r2 && pg_num_rows($r2) > 0) {
while ($row = pg_fetch_row($r2)) {
$msg_text = $row[1];
// echo 'HERE 22222->' . $msg_text;
$extension_confirm_call = true;
}
}
return $msg_text;
}
$r = pg_query($conn, $mysql);
$acc = array();
if ($r && pg_num_rows($r)) {
// echo 'ddhdhdhd';
while ($f = pg_fetch_assoc($r)) {
$member_id = $f["member_id"];
$extension_call = false;
if (array_key_exists($member_id, $acc)) {
// echo "here " . $member_id;
// nothing - we dont want duplicate
} else {
$sq2 = "SELECT * FROM members_notification WHERE member_id=$member_id AND status IN (1)";
$r2 = pg_query($readOnlyReplicaConn, $sq2);
$x["pid"] = 0;
$x["member_id"] = $member_id;
$x["notice_type"] = "GENALERT";
$acc[$member_id] = $member_id;
if ($r2 && pg_num_rows($r2) == 0) {
$x["msg"] = "We have found a way to save time for you";
// print_r($x);
if ($f["surge_price"] > 0 && $f["cheaper_alternative"] > 0) {
$x["msg"] = "We have found a way to save time and money for you";
}
if ($f["surge_price"] > 0 && $f["cheaper_alternative"] == 0) {
$x["msg"] = "We have found a way to save time for you";
}
$extension_call = true;
}
}
if ($extension_call == true) {
$outX = array();
$x["mmode"] = "AUTO";
$x["action"] = FLOAT_SYSTEM_CREATE_NOTIFICATION;
// Fextension_call($x, $outX);
}
print_r($acc);
}
}
/*
$q = "SELECT * FROM members_notification WHERE status = 1 LIMIT 5";
$r = pg_query($conn, $q);
if ($r && pg_num_rows($r)) {
while ($f = pg_fetch_row($r)) {
$member_id = $f[0];
echo "[" . date("Y-m-d H:i:s") . "] Processing member_id=" . $member_id . " (total member records: " . $f[1] . ")\n";
//if ($f[0]==22) continue; // Crash!
// $p = processMemberGPSDataPartition($member_id);
echo "[" . date("Y-m-d H:i:s") . "] Processed member_id=" . $member_id . " (processed records: " . $p . ")\n";
}
}
function processMemberGPSDataPartition($member_id) {
global $conn, $precision, $hard_limit;
}
*/
pg_close($conn);
pg_close($readOnlyReplicaConn);
echo "[" . date("Y-m-d H:i:s") . "] member_prepare_notification job complete.\n";
+140
View File
@@ -0,0 +1,140 @@
<?php
echo "[".date("Y-m-d H:i:s")."] GPS member_tracking_duration job is starting.\n";
require('../backend.php');
// We will not limit the SQL we will exhaust the allowed memory
// we will process data in ${hard_limit} batches and hopefully catch up
$hard_limit = 500000;
// GPS coordinate precision to assume the same location
$precision = 3;
$db_host = $savvyext->cfgReadChar('gpsdatabase.host');
$db_name = $savvyext->cfgReadChar('gpsdatabase.name');
$db_user = $savvyext->cfgReadChar('gpsdatabase.user');
$db_pass = $savvyext->cfgReadChar('gpsdatabase.pass');
$db_port = $savvyext->cfgReadLong('gpsdatabase.port');
$connstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$conn = pg_connect($connstr);
$db_host = $savvyext->cfgReadChar('database_replica.host');
$db_name = $savvyext->cfgReadChar('database_replica.name');
$db_user = $savvyext->cfgReadChar('database_replica.user');
$db_pass = $savvyext->cfgReadChar('database_replica.pass');
$db_port = $savvyext->cfgReadLong('database_replica.port');
$readOnlyReplicaConnstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$readOnlyReplicaConn = pg_connect($readOnlyReplicaConnstr);
$q = "select member_id,count(*) from members_tracking group by member_id";
$r = pg_query($readOnlyReplicaConn, $q);
if ($r && pg_num_rows($r)) {
while ($f=pg_fetch_row($r)) {
$member_id = $f[0];
echo "[".date("Y-m-d H:i:s")."] Processing member_id=".$member_id." (total member records: ".$f[1].")\n";
//if ($f[0]==22) continue; // Crash!
$p = processMemberGPSDataPartition($member_id);
echo "[".date("Y-m-d H:i:s")."] Processed member_id=".$member_id." (processed records: ".$p.")\n";
}
}
function processMemberGPSDataPartition($member_id) {
global $conn,$precision,$hard_limit,$readOnlyReplicaConn;
echo "[".date("Y-m-d H:i:s")."] processMemberGPSDataPartition($member_id)\n";
$id = 0;
$q = 'select max(last_id) from members_tracking_duration where member_id=' . $member_id;
$r = pg_query($readOnlyReplicaConn, $q);
if ($r && pg_num_rows($r) && $f=pg_fetch_row($r)) {
$id = (int)$f[0];
}
echo "[".date("Y-m-d H:i:s")."] Last processed ID is ${id}\n";
/*
0 - id
1 - lat
2 - lng
3 - ttime
4 - member_id
5 - device_id
6 - gps
*/
$q = "select id,round(lat,${precision}) as lat,round(lng,${precision}) as lng,ttime,member_id,device_id,gps ";
$q.= " from members_tracking where id>${id} ";
$q.= " and member_id=".$member_id;
$q.= " order by member_id,device_id,ttime limit ${hard_limit}";
echo "\n$q\n";
$r = pg_query($readOnlyReplicaConn, $q);
if ($r && pg_num_rows($r)) {
echo "[".date("Y-m-d H:i:s")."] Records to process: ".pg_num_rows($r)."\n";
} else {
echo "[".date("Y-m-d H:i:s")."] No new records to process. Stop.\n";
return 0;
}
echo "[".date("Y-m-d H:i:s")."] Processing";
$first_data = NULL;
$last_data = NULL;
$pool_data = [];
$processed = 0;
while ($f=pg_fetch_row($r)) {
//echo ".";
if ($last_data!=NULL) {
// member id
if ($last_data[4]!=$f[4] || $last_data[5]!=$f[5] || // device_id
$last_data[1]!=$f[1] || $last_data[2]!=$f[2]) { // gps coordinates
// Process
$clear_data = [];
foreach ($pool_data as $id) {
if ($id!=$first_data[0] && $id!=$last_data[0]) {
$clear_data[] = $id;
}
}
$first = $clear_data[0] ?? $first_data;
$n = count($pool_data);
$last = array_pop($pool_data) ?? $last_data;
$q = "INSERT INTO members_tracking_duration (member_id,lat,lng,gps,first_id,last_id,first_time,last_time,duration,device_id,inner_duration,total) VALUES(";
$q.= $last_data[4].",".$last_data[1].",".$last_data[2].","; // member_id,lat,lng
$q.= "ST_SetSRID(ST_MakePoint(".$last_data[1].",".$last_data[2]."), 4326)::geography"; // GPS
$q.= ",".$first_data[0].",".$last_data[0].",'".$first_data[3]."','".$last_data[3]."',"; // fist_id,last_id,first_time,last_time,duration
$q.= "'".$last_data[3]."'::timestamp - '".$first_data[3]."'::timestamp,".($f[5]>0?$f[5]:"NULL"); // duration, device_id
$q.= "EXTRACT(epoch FROM '".$last[3]."':timestamp-'".$first[3]."'::timestamp),".$n.")"; // inner_duration, total
pg_query($conn, $q);
//echo pg_last_error()."\n";
if (count($clear_data)>0) {
$q1 = "DELETE FROM members_tracking WHERE id IN (".implode(",",$clear_data).")";
$r1 = pg_query($conn, $q1);
if ($r1 && pg_affected_rows($r1)) {
$q2 = "UPDATE members_tracking SET previous_id=".$first_data[0].",";
$q2.= "distance=ST_Distance(gps,'".$first_data[6]."'::geometry),";
$q2.= "duration=EXTRACT(epoch FROM ttime-'".$first_data[3]."'::timestamp)";
$q2.= " WHERE previous_id IN (".implode(",",$clear_data).",".$last_data[0].")";
$r2 = pg_query($conn, $q2);
echo "\n${q2}\n";
//echo pg_last_error()."\n";
} else {
echo "\n";
echo "[".date("Y-m-d H:i:s")."] Failed - ".pg_last_error()."\n";
echo "${q1}\n";
}
}
$first_data = NULL;
}
}
if ($first_data==NULL) {
$first_data = $f;
unset($pool_data);
$pool_data = [];
}
$pool_data[] = $f[0]; // id
$last_data = $f;
$processed++;
}
pg_free_result($r);
echo "\n";
return $processed;
}
pg_close($conn);
pg_close($readOnlyReplicaConn);
echo "[".date("Y-m-d H:i:s")."] GPS member_tracking_duration job complete.\n";
+317
View File
@@ -0,0 +1,317 @@
<?php
echo "[".date("Y-m-d H:i:s")."] GPS members_tracking_trips job is starting.\n";
require('../backend.php');
// We will not limit the SQL we will exhaust the allowed memory
// we will process data in ${hard_limit} batches and hopefully catch up
$hard_limit = 500000;
// GPS coordinate precision to assume the same location
$precision = 3;
// How many seconds is a stop?
$stop_limit = 120;
$httpAuthToken = $savvyext->cfgReadChar('system.oauth2_token');
$db_host = $savvyext->cfgReadChar('database_replica.host');
$db_name = $savvyext->cfgReadChar('database_replica.name');
$db_user = $savvyext->cfgReadChar('database_replica.user');
$db_pass = $savvyext->cfgReadChar('database_replica.pass');
$db_port = $savvyext->cfgReadLong('database_replica.port');
$readOnlyReplicaConnstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$readOnlyReplicaConn = pg_connect($readOnlyReplicaConnstr);
$db_host = $savvyext->cfgReadChar('gpsdatabase.host');
$db_name = $savvyext->cfgReadChar('gpsdatabase.name');
$db_user = $savvyext->cfgReadChar('gpsdatabase.user');
$db_pass = $savvyext->cfgReadChar('gpsdatabase.pass');
$db_port = $savvyext->cfgReadLong('gpsdatabase.port');
$gpsconnstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$gpsconn = pg_connect($gpsconnstr);
$q = "select member_id,count(*) from members_tracking ";
//$q.= "where member_id=55 "; // DEBUG
$q.= "group by member_id";
$r = pg_query($gpsconn, $q);
if ($r && pg_num_rows($r)) {
while ($f=pg_fetch_row($r)) {
$member_id = $f[0];
echo "[".date("Y-m-d H:i:s")."] Processing member_id=".$member_id." (total member records: ".$f[1].")\n";
$p = processMemberGPSTrackingTrips($member_id);
echo "[".date("Y-m-d H:i:s")."] Processed member_id=".$member_id." (processed records: ".$p.")\n";
}
}
function processMemberGPSTrackingTrips($member_id) {
global $gpsconn,$precision,$hard_limit,$stop_limit;
echo "[".date("Y-m-d H:i:s")."] processMemberGPSDataPartition($member_id)\n";
$id = 0;
$q = 'select max(location_start),max(location_end) from members_tracking_trips where member_id=' . $member_id;
$r = pg_query($gpsconn, $q);
if ($r && pg_num_rows($r) && $f=pg_fetch_row($r)) {
$id = max((int)$f[0],(int)$f[1]);
}
echo "[".date("Y-m-d H:i:s")."] Last processed ID is ${id}\n";
$q = "select a.first_id,a.last_id,a.device_id,extract(milliseconds from a.duration) as ms, ";
$q.= "extract(epoch from a.duration) as seconds, c.speed, a.inner_duration, a.total, ";
$q.= "ST_Distance(c.gps,b.gps) AS distance, b.gps AS gps_start, c.gps AS gps_end,";
$q.= "EXTRACT(epoch FROM c.ttime-b.ttime) AS travel_time ";
$q.= "from members_tracking_duration a ";
$q.= "left join members_tracking b on (b.id=a.first_id) ";
$q.= "left join members_tracking c on (c.id=a.last_id) ";
$q.= "where a.member_id=${member_id} ";
$q.= "and a.first_id>${id} AND a.last_id>${id} "; // Limit ?
$q.= "order by a.device_id, a.first_time limit ${hard_limit}";
//echo "\n$q\n";
$r = pg_query($gpsconn, $q);
if ($r && pg_num_rows($r)) {
echo "[".date("Y-m-d H:i:s")."] Records to process: ".pg_num_rows($r)."\n";
} else {
echo "[".date("Y-m-d H:i:s")."] No new records to process. Stop.\n";
return 0;
}
echo "[".date("Y-m-d H:i:s")."] Processing";
$trip = [];
$trips = [];
$trip_data = ['distance'=>0,'duration'=>0,'total'=>0,'speed'=>0];
$trips_data = [];
$processed = 0;
$last_device_id = -1;
$r = pg_query($gpsconn, $q);
while ($f=pg_fetch_assoc($r)) {
//$res[] = $f;
//if ($f["seconds"]>=$stop_limit || ($last_device_id!=$f["device_id"] && count($trip)>0)) {
if ($f["inner_duration"]>=$stop_limit || ($last_device_id!=$f["device_id"] && count($trip)>0)) {
$trips[] = $trip;
$trips_data[] = $trip_data;
$n = count($trip)-1;
list ($res, $err) = processMemberGPSTrackingTripsSave(
$member_id,
$trip[0],
array_pop($trip),
$trip_data);
if ($res && $res["id"]>0) {
echo "[".date("Y-m-d H:i:s")."] New trip processed: ".$res["id"]." (member_id=${member_id})\n";
} else {
echo "[".date("Y-m-d H:i:s")."] Failed to process trip: ${err} (member_id=${member_id})\n";
var_dump($trip_data); // DEBUG
}
unset($trip);
unset($trip_data);
$trip = [];
$trip_data = ['distance'=>0,'duration'=>0,'total'=>0,'speed'=>0];
} else {
$trip[] = $f;
$trip_data['distance'] += $f["distance"];
$trip_data['duration'] += $f["ms"];
$trip_data['speed'] += $f["ms"]>0 ? (3600 * $f["distance"] / $f["ms"]) : 0; // km/h
$trip_data['total'] += 1;
}
$last_device_id = $f["device_id"];
$processed++;
}
pg_free_result($r);
return $processed;
}
function processMemberGPSTrackingTripsSave($member_id,$first,$last,$trip_data) {
global $gpsconn;
$distance = $trip_data['distance'];
$duration = $trip_data['duration']/1000;
if ($distance>0 && $duration>0) {
// OK
} else {
return [NULL, "Distance and/or duration are invalid!"];
}
$speed = 3600 * $trip_data['distance'] / $trip_data['duration'];
$avg_speed = $trip_data['speed'] / $trip_data['total'];
$device_id = ($first['device_id']>0 ? $first['device_id'] : "NULL");
$location_start = $first['last_id'];
$location_end = $last['last_id'];
$gps_start = $first['gps_end'];
$gps_end = $last['gps_end'];
$address_start = processMemberGPSTrackingTripsReverseGeocode($gps_start);
$address_end = processMemberGPSTrackingTripsReverseGeocode($gps_end);
$q = "SELECT * FROM members_tracking_trips WHERE member_id=${member_id} ";
$q.= "AND location_start=${location_start} AND location_end=${location_end} ";
$q.= "AND ".($device_id=="NULL"?"device_id IS NULL":"device_id=${device_id}");
$r = pg_query($gpsconn, $q);
if ($r && pg_num_rows($r) && $f=pg_fetch_assoc($r)) {
$q = "UPDATE members_tracking_trips SET distance=${distance},duration=${duration},";
$q.= "speed=${speed},avg_speed=${avg_speed},gps_start='${gps_start}',gps_end='${gps_end}',";
$q.= "address_start='${address_start}',address_end='${address_end}' WHERE member_id=${member_id} ";
$q.= "AND location_start=${location_start} AND location_end=${location_end} ";
$q.= "AND ".($device_id=="NULL"?"device_id IS NULL":"device_id=${device_id}");
$q.=" RETURNING *";
} else {
$q = "INSERT INTO members_tracking_trips (member_id,distance,duration,speed,avg_speed,location_start,location_end,device_id,gps_start,gps_end,address_start,address_end) VALUES(";
$q.= "${member_id},${distance},${duration},${speed},${avg_speed},${location_start},${location_end},${device_id},'${gps_start}','${gps_end}',${address_start},${address_end}";
$q.= ") RETURNING *";
}
$r = pg_query($gpsconn, $q);
if ($r && pg_num_rows($r) && $f=pg_fetch_assoc($r)) {
pg_free_result($r);
return [$f, NULL];
}
echo "\n$q\n";
return [NULL, pg_last_error($gpsconn)];
}
function processMemberGPSTrackingTripsReverseGeocode($gps) {
global $gpsconn, $readOnlyReplicaConn;
if ($gps==NULL || $gps=="") {
echo "[".date("Y-m-d H:i:s")."] Empty GPS string\n";
return "NULL";
}
$q = "SELECT ST_Y('${gps}') AS lat, ST_X('${gps}') AS lng";
$r = pg_query($gpsconn, $q);
if ($r && pg_num_rows($r) && $f=pg_fetch_row($r)) {
$lat = $f[0];
$lng = $f[1];
} else {
echo "[".date("Y-m-d H:i:s")."] Failed to decode GPS: '${gps}'\n";
return "NULL";
}
list ($address,$err) = reverseGeocode($readOnlyReplicaConn, $lat, $lng);
if (!$address && $err) {
echo "[".date("Y-m-d H:i:s")."] Failed to reverse geocode GPS: ${lat},${lng}\n";
return "NULL";
}
$q = "SELECT id FROM address WHERE lower(address)=lower('".pg_escape_string($address)."') ORDER BY geocoding_date DESC LIMIT 1";
//echo "\n\n${q}\n\n";
$r = pg_query($readOnlyReplicaConn, $q);
if ($r && pg_num_rows($r) && $f=pg_fetch_row($r)) {
return $f[0];
}
echo "[".date("Y-m-d H:i:s")."] Failed to load address: '${address}'\n";
return "NULL";
}
function reverseGeocode($db, $lat, $lng) {
// Reverse geocode using local DB
list($res,$err) = GeocodeReverseGeocode($db, $lat, $lng);
if (is_array($res) && isset($res["address"])) {
return [$res["address"],NULL];
}
// Reverse geocode service using Google Maps API
list($res,$err) = reverseGeocodeService($db, $lat, $lng);
if (is_array($res) && isset($res["address"]) && $res["address"]!="") {
reverseGeocodeServiceSave($db, $res);
return [$res["address"],NULL];
}
return [NULL, $err];
}
function GeocodeReverseGeocode($db, $lat, $lng) {
$db_lat = ((float)$lat);
$db_lng = ((float)$lng);
// Check our local address table with precisions 5 to 3
for ($i=5;$i>2;$i--) {
$q = "SELECT * FROM address WHERE round(latitude,${i})=round(${db_lat},${i}) AND round(longitude,${i})=round(${db_lng},${i})";
$r = pg_query($db, $q);
if ($r && pg_num_rows($r) && $f=pg_fetch_assoc($r)) {
return [$f, NULL];
}
}
// Check our local Singapore table with precisions 5 to 3
/* for ($i=5;$i>2;$i--) {
$q = "SELECT * FROM singapore_buildings WHERE round(latitude,${i})=round(${db_lat},${i}) AND round(longitude,${i})=round(${db_lng},${i})";
$r = pg_query($q);
if ($r && pg_num_rows($r) && $f=pg_fetch_assoc($r)) {
return [$f, NULL];
}
} //*/
return [NULL, pg_last_error($db)];
}
function reverseGeocodeServiceSave($db, $result) {
$db_lat = floatval($result["lat"]);
$db_lng = floatval($result["lng"]);
$db_address = pg_escape_string($result["address"]);
$db_postal = pg_escape_string($result["postal"]);
$db_tz = GeocodeGetTimezone($db, $result["timeZoneId"]);
// Check the address exists
$q = "SELECT id FROM address WHERE lower(address)=lower('${db_address}') ";
$q.= "AND latitude<>0 AND longitude<>0 AND geocoding_date IS NOT NULL ";
$q.= "ORDER BY geocoding_date DESC LIMIT 1";
//error_log($q);
$r = pg_query($db, $q);
if ($r && pg_num_rows($r) && $f=pg_fetch_row($r)) {
return $f[0];
}
$q = "INSERT INTO address (address,latitude,longitude,timezone,geocoding_date,postal) VALUES (";
$q.= "'${db_address}',${db_lat},${db_lng},".($db_tz==NULL?"NULL":$db_tz).",now(),'${db_postal}')";
$q.= " RETURNING id";
$r = pg_query($db, $q);
if ($r && pg_num_rows($r) && $f=pg_fetch_row($r)) {
return $f[0];
}
return NULL;
}
function GeocodeGetTimezone($db, $timezone) {
$db_timezone = pg_escape_string($timezone);
$q = "SELECT id FROM address_timezone WHERE timezone='${db_timezone}'";
$r = pg_query($db, $q);
if ($r && pg_num_rows($r) && $f=pg_fetch_row($r)) {
return $f[0];
}
$q = "INSERT INTO address_timezone (timezone) VALUES('${db_timezone}') RETURNING id";
$r = pg_query($db, $q);
if ($r && pg_num_rows($r) && $f=pg_fetch_row($r)) {
return $f[0];
}
return NULL;
}
function reverseGeocodeService($db, $lat, $lng) {
global $httpAuthToken;
$data = http_build_query(
array(
'lat' => $lat,
'lng' => $lng
)
);
$url = "http://oauth2.service/api/v1/reverse?" . $data;
//echo "\n\n${url}\n\n";
$opts = array(
'http' => array(
'method' => "GET",
'timeout' => 60, /* 1 minute */
'header' =>
"Content-Type: application/x-www-form-urlencoded\r\n" .
"Accept: application/json\r\n" .
"Authorization: Server-Token ${httpAuthToken}\r\n",
)
);
$context = stream_context_create($opts);
$body = file_get_contents($url, false, $context);
//error_log("BODY: ".$body);
$geocoded = json_decode($body,true);
if (is_array($geocoded) && is_array($geocoded["data"]) && !isset($geocoded["error"])) {
//error_log(json_encode($geocoded));
// Cache the result in DB
/*Geocode::saveDistanceCache(
$db->getConnect(), $fromLat, $fromLng, $toLat, $toLng, $geocoded["data"]);
*/
return [$geocoded["data"], NULL];
} else if (is_array($geocoded) && isset($geocoded["error"])) {
$body = $geocoded["error"];
}
return [NULL, "Reverse geocoding service call error: ".$body];
}
pg_close($readOnlyReplicaConn);
pg_close($gpsconn);
echo "[".date("Y-m-d H:i:s")."] GPS members_tracking_trips job complete.\n";
+32
View File
@@ -0,0 +1,32 @@
<?php
echo "[" . date( "Y-m-d H:i:s" ) . "] members_devices_check job is starting.\n";
require('lock.php');
$lock_file = lock_pid_file();
set_time_limit(0); // No limit!
require( '../backend.php' );
$inactivePeriod = 14400; // 240 hours in minutes
$db_host = $savvyext->cfgReadChar( 'database.host' );
$db_name = $savvyext->cfgReadChar( 'database.name' );
$db_user = $savvyext->cfgReadChar( 'database.user' );
$db_pass = $savvyext->cfgReadChar( 'database.pass' );
$db_port = $savvyext->cfgReadLong( 'database.port' );
$connstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$conn = pg_connect( $connstr );
$q = "UPDATE members_devices SET status = 0 WHERE status = 1 AND updated IS NOT NULL AND updated < (now() - interval '".$inactivePeriod." minutes') RETURNING *";
$r = pg_query( $conn, $q );
if ( $r && $count = pg_num_rows( $r ) ) {
echo "[" . date( "Y-m-d H:i:s" ) . "] Updated ${count} rows\n";
}
unlock_pid_file($lock_file);
echo "[".date("Y-m-d H:i:s")."] members_devices_check job complete.\n";
@@ -0,0 +1,335 @@
<?php
define("FLOAT_SYSTEM_CREATE_NOTIFICATION", 92025);
define("FLOAT_SYSTEM_EMAIL_NOTIFICATION", 92027);
define('FLOAT_SYSTEM_CREATE_DYNAMICCARD', 92026);
$mysql = " SELECT ";
$mysql .= " p.id,m.id AS member_id,m.email, p.travel_date,p.duration,p.cost_raw,p.trackedemail_item_id,p.cost,p.updated,p.distance, ";
$mysql .= " CASE WHEN e.id IS NULL THEN '0' ELSE '1' END AS surge_price, ";
$mysql .= " CASE WHEN (f.id IS NOT NULL AND f.cost>f.average) THEN ROUND(f.average/f.cost,2) ELSE 0 END AS cheaper_alternative ";
$mysql .= " FROM parsedemail_item p LEFT JOIN trackedemail_item t ON t.id=p.trackedemail_item_id ";
$mysql .= " LEFT JOIN trip_surge_price e ON (e.data_source_id=p.id AND e.data_source=1) ";
$mysql .= " LEFT JOIN trip_price_comparison f ON (f.data_source_id=p.id AND e.data_source=1) LEFT JOIN members m ON m.id=t.member_id ";
$mysql .= " WHERE e.id IS NOT NULL ORDER BY t.id DESC LIMIT 500";
$trigger_query = array(
"SURGESAVE" => array(
"query" => $mysql,
"message" => "You are spending too much. Let's save money",
"feed_msg" => "",
"active" => 1,
"cat" => 'GOACTIVITY',
"dynamic_key" => "",
"start_save" => false, "send_mail" => 0, "send_notification" => 1
),
"ETRG0001" => array(
"query" => "SELECT id AS member_id,last_acct,count_acct,last_email,count_email, min_budget,count_acct+count_email AS total_data FROM members WHERE min_budget =0 AND count_email =0 AND count_acct =0 AND id > 0 ORDER BY notification_test ASC LIMIT 500",
"message" => "Let's examine how much you spend on travel. We can save money.",
"feed_msg" => "",
"active" => 1,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0001KEY",
"start_save" => true
),
"ETRG0002" => array(
"query" => "SELECT ma.*,m.min_budget from members_analysis ma LEFT JOIN members m ON m.id = ma.member_id WHERE m.min_budget > 0 AND ma.spend_7 > 0 AND ma.spend_7/m.min_budget < 0.9 ORDER BY m.notification_test ASC LIMIT 500",
"message" => "Good Job, you're saving money",
"feed_msg" => "",
"active" => 1,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0002KEY",
"start_save" => false, "send_mail" => 0, "send_notification" => 1
),
"ETRG0003" => array(
"query" => "SELECT ma.*,m.min_budget from members_analysis ma LEFT JOIN members m ON m.id = ma.member_id WHERE m.min_budget > 0 AND ma.spend_7 > 0 AND ma.spend_7/m.min_budget > 1.1 ORDER BY m.notification_test ASC LIMIT 500",
"message" => "You are over budget. Let's see how we can save you money.",
"feed_msg" => "",
"active" => 1,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0003KEY",
"start_save" => false, "send_mail" => 0, "send_notification" => 1
),
"ETRG0004" => array(
"query" => "SELECT ma.*,m.min_budget from members_analysis ma LEFT JOIN members m ON m.id = ma.member_id WHERE ma.spend_7 > 4000 ORDER BY m.notification_test ASC LIMIT 500",
"message" => "We can see you spent $X on rideshare this month. Here's how Float can save you money",
"feed_msg" => "",
"active" => 1,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0004KEY",
"start_save" => false, "send_mail" => 0, "send_notification" => 1
),
"ETRG0005" => array(
"query" => "SELECT b.member_id FROM members_bank_accounts b LEFT JOIN members m ON m.id=b.member_id WHERE m.id>0 AND m.country IN ('US','SG','NZ') GROUP BY b.member_id,m.notification_test ORDER BY m.notification_test ASC LIMIT 500",
"message" => "You have a Chase Freedom credit card. You should take Lyft this month",
"feed_msg" => "",
"active" => 1,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0005KEY",
"start_save" => false, "send_mail" => 0, "send_notification" => 1
)
,
"ETRG0006" => array(
"query" => "SELECT ma.*,m.min_budget,(ma.spend_14 - 2*ma.spend_7) AS week_increase from members_analysis ma LEFT JOIN members m ON m.id = ma.member_id WHERE min_budget = 0 AND ma.spend_7 > 0 AND ma.spend_14 > 2*ma.spend_7 ORDER BY m.notification_test ASC LIMIT 500",
"message" => "Your spending is up 23% this week. Would you like to create a budget?",
"feed_msg" => "",
"active" => 1,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0006KEY",
"start_save" => false, "send_mail" => 0, "send_notification" => 1
),
"ETRG0007" => array(
"query" => "SELECT ma.*,m.min_budget,(ma.spend_14 - 2*ma.spend_7) AS week_increase,m.country AS country from members_analysis ma LEFT JOIN members m ON m.id = ma.member_id WHERE m.decision_group IN('A1NUS25','USSF001') AND m.id NOT IN (SELECT member_id FROM members_carpool) ORDER BY m.notification_test ASC LIMIT 500",
"message" => "Deal Carpool Try carpooling and save $X and Y emissions this month",
"feed_msg" => "",
"active" => 1,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0007KEY",
"start_save" => false, "send_mail" => 0, "send_notification" => 1
),
"ETRG0008" => array(
"query" => "SELECT ma.*,m.min_budget,(ma.spend_14 - 2*ma.spend_7) AS week_increase from members_analysis ma LEFT JOIN members m ON m.id = ma.member_id WHERE min_budget = 0 AND ma.spend_7 > 0 AND ma.spend_14 > 2*ma.spend_7 ORDER BY m.notification_test ASC LIMIT 500",
"message" => "We can save you $X by taxing (rideshare or taxi) at 5pm today.",
"feed_msg" => "",
"active" => 0,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0008KEY",
"start_save" => false, "send_mail" => 0, "send_notification" => 1
),
"ETRG0009" => array(
"query" => "SELECT ma.*,m.min_budget,(ma.spend_14 - 2*ma.spend_7) AS week_increase from members_analysis ma LEFT JOIN members m ON m.id = ma.member_id WHERE min_budget = 0 AND ma.spend_7 > 0 AND ma.spend_14 > 2*ma.spend_7 ORDER BY m.notification_test ASC LIMIT 500",
"message" => "We found that taking public transit and scooter is faster and cheaper for you.",
"feed_msg" => "",
"active" => 0,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0009KEY",
"start_save" => false, "send_mail" => 0, "send_notification" => 1
),
"ETRG0010" => array(
"query" => "SELECT ma.*,m.min_budget,(ma.spend_14 - 2*ma.spend_7) AS week_increase from members_analysis ma LEFT JOIN members m ON m.id = ma.member_id WHERE min_budget = 0 AND ma.spend_7 > 0 AND ma.spend_14 > 2*ma.spend_7 ORDER BY m.notification_test ASC LIMIT 500",
"message" => "Your spending is up 23% this week. Would you like to create a budget?",
"feed_msg" => "",
"active" => 0,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0010KEY",
"start_save" => false, "send_mail" => 0, "send_notification" => 1
),
"ETRG0011" => array(
"query" => "SELECT *, id AS member_id FROM members WHERE id > 0 AND id NOT IN (SELECT member_id FROM members_trips) ORDER BY notification_test ASC LIMIT 500",
"message" => "Float found a better way for you to get to work. See route, save it and Float will remind you going forward.",
"feed_msg" => "",
"active" => 1,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0011KEY",
"start_save" => false, "send_mail" => 0, "send_notification" => 1
),
"ETRG0012" => array(
"query" => "SELECT ma.*,m.min_budget,(ma.spend_14 - 2*ma.spend_7) AS week_increase from members_analysis ma LEFT JOIN members m ON m.id = ma.member_id WHERE min_budget = 0 AND ma.spend_7 > 0 AND ma.spend_14 > 2*ma.spend_7 ORDER BY m.notification_test ASC LIMIT 500",
"message" => "Your spending is up 23% this week. Would you like to create a budget?",
"feed_msg" => "",
"active" => 0,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0012KEY",
"start_save" => false, "send_mail" => 0, "send_notification" => 1
),
"ETRG0014" => array(
"query" => "SELECT ma.*,m.min_budget,(2*ma.spend_7- ma.spend_14) AS week_increase from members_analysis ma LEFT JOIN members m ON m.id = ma.member_id WHERE ma.spend_7 > 0 AND 2*ma.spend_7> ma.spend_14 ORDER BY m.notification_test ASC LIMIT 500",
"message" => "Your emissions output is 10% higher this week, lets see how we can lower it",
"feed_msg" => "",
"active" => 1,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0014KEY",
"start_save" => false, "send_mail" => 0, "send_notification" => 1
),
"ETRG0015" => array(
"query" => "SELECT ma.*,m.min_budget,(2*ma.spend_7 - ma.spend_14) AS week_decrease from members_analysis ma LEFT JOIN members m ON m.id = ma.member_id WHERE min_budget = 0 AND ma.spend_7 > 0 AND ma.spend_14 < 2*ma.spend_7 ORDER BY m.notification_test ASC LIMIT 500",
"message" => "Hurray, you have spent X minutes less on the road this week. Shop for rewards with Float.",
"feed_msg" => "",
"active" => 1,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0015KEY",
"start_save" => false, "send_mail" => 0, "send_notification" => 1
)
,
"ETRG0016" => array(
"query" => "SELECT ma.*,m.min_budget,(ma.spend_14 - 2*ma.spend_7) AS week_increase from members_analysis ma LEFT JOIN members m ON m.id = ma.member_id WHERE min_budget = 0 AND ma.spend_7 > 0 AND ma.spend_14 > 2*ma.spend_7 ORDER BY m.notification_test ASC LIMIT 500",
"message" => "Good Job, you're saving X% more money than your peers.",
"feed_msg" => "",
"active" => 0,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0012KEY",
"start_save" => false, "send_mail" => 0, "send_notification" => 1
)
,
"ETRG0017" => array(
"query" => "SELECT ma.*,m.min_budget,(ma.spend_14 - 2*ma.spend_7) AS week_increase from members_analysis ma LEFT JOIN members m ON m.id = ma.member_id WHERE min_budget = 0 AND ma.spend_7 > 0 AND ma.spend_14 > 2*ma.spend_7 ORDER BY m.notification_test ASC LIMIT 500",
"message" => "You are spending more X% money than your peers. Let's save money ",
"feed_msg" => "",
"active" => 0,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0017KEY",
"start_save" => false, "send_mail" => 0, "send_notification" => 1
)
,
"ETRG0019" => array(
"query" => "SELECT * FROM members LIMIT 1",
"message" => "THIS IS USED FOR THE POINTS SYSTEM ONLY - It is automatic",
"feed_msg" => "",
"active" => 1,
"cat" => 'GOPOINT',
"dynamic_key" => "ETRG0019KEY",
"start_save" => false, "send_mail" => 1, "send_notification" => 1
),
"ETRG0020" => array(
"query" => "SELECT * FROM members LIMIT 1",
"message" => "THIS IS USED FOR THE TRIPS SYSTEM ONLY - It is automatic",
"feed_msg" => "",
"active" => 1,
"cat" => 'GOPOINT',
"dynamic_key" => "ETRG0020KEY",
"start_save" => false, "send_mail" => 1, "send_notification" => 1
),
"ETRG0021" => array(
"query" => "SELECT ma.member_id,ma.status,ma.bank_login_status FROM members_bank_accounts ma LEFT JOIN members m ON m.id=ma.member_id WHERE m.country ='SG' AND ma.bank_login_status='inactive' ORDER BY m.notification_test ASC LIMIT 500",
"message" => "Your bank connection has expired, import your latest transactions to stay on top of your spending",
"feed_msg" => "",
"active" => 1,
"cat" => 'GOPROFILE',
"dynamic_key" => "ETRG0021KEY",
"start_save" => false, "send_mail" => 1, "send_notification" => 1
)
,
"ETRG0022" => array(
"query" => "SELECT b.member_id, count(b.id) AS total_rec,m.notification_test FROM members_bankimport b LEFT JOIN members m ON m.id=b.member_id WHERE lower(merchant_name)= LOWER('ComfortDelGro') GROUP BY b.member_id, m.notification_test ORDER BY m.notification_test ASC LIMIT 500",
"message" => "Be careful how you pay, credit and charge card payments get hit with a 10% surcharge in a Comfort Taxi",
"feed_msg" => "",
"active" => 1,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0022KEY",
"start_save" => false, "send_mail" => 0, "send_notification" => 0
)
);
$trigger_card = array(
"ETRG0001" => array(
"active" => 1,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0001KEY"
),
"ETRG0002" => array(
"active" => 1,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0002KEY"
),
"ETRG0003" => array(
"active" => 1,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0003KEY"
),
"ETRG0004" => array(
"active" => 1,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0004KEY"
),
"ETRG0005" => array(
"active" => 1,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0005KEY"
),
"ETRG0006" => array(
"active" => 1,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0006KEY"
),
"ETRG0011" => array(
"active" => 1,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0011KEY"
),
"ETRG0014" => array(
"active" => 1,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0014KEY"
),
"ETRG0015" => array(
"active" => 1,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0015KEY"
),
"ETRG0021" => array(
"active" => 1,
"cat" => 'GOPROFILE',
"dynamic_key" => "ETRG0021KEY"
)
);
function generateCard($notice_id, $member_id, $cat) {
$out = array();
global $trigger_card;
global $readOnlyReplicaConn;
// print_r($trigger_card);
//echo "\n ~~~~~56565656 ----------------------------->>>> ".rand(100,999);
$trigger_key = "";
$dynamic_key = "";
$status_msg = '';
if ($notice_id != '' && $member_id != '') {
// echo "\n ~~~~~38383838383 ----------------------------->>>> ".rand(100,999);
$mysql = "SELECT * FROM members_notification WHERE id=$notice_id AND member_id=$member_id";
$r = pg_query($readOnlyReplicaConn, $mysql);
if ($r && pg_num_rows($r)) {
$f = pg_fetch_assoc($r);
$trigger_key = $f["trigger_key"];
$message = $f["msg"];
}
// echo "\n<br> ~~~~~55555 -----------------------------=====>>==>> ".rand(100,999);
$card_allowded = false;
if (array_key_exists($trigger_key, $trigger_card)) {
$status_msg = "The $trigger_key is in the array";
// print_r( $trigger_card[$trigger_key] );
$dynamic_key = $trigger_card[$trigger_key]["dynamic_key"];
$card_allowded = true;
} else {
$status_msg = "The $trigger_key not set up for cards";
}
// echo "\n<br> ~~~~~66666 -----------------------------=====>>==>> ".rand(100,999);
if (true == $card_allowded && $message != '' && $trigger_key != '' && $dynamic_key != '') {
$in = array();
echo "~~~~~44444 -----------------------------";
$in["dynamic_key"] = $dynamic_key;
$in["member_id"] = $member_id;
$in["trigger_key"] = $trigger_key;
$in["message"] = $message;
$in["notice_id"] = $notice_id;
$in["cat"] = $cat;
$in['action'] = FLOAT_SYSTEM_CREATE_DYNAMICCARD;
print_r($in);
$ret = Fextension_call($in, $out);
print_r($out);
if ($ret == PHP_API_OK) {
$message = 'Completed!';
} else {
$message = 'Failed to Create';
}
}
}
echo $status_msg;
}
+340
View File
@@ -0,0 +1,340 @@
<?php
define("FLOAT_SYSTEM_CREATE_NOTIFICATION", 92025);
define("FLOAT_SYSTEM_EMAIL_NOTIFICATION", 92027);
define('FLOAT_SYSTEM_CREATE_DYNAMICCARD', 92026);
$mysql = " SELECT ";
$mysql .= " p.id,m.id AS member_id,m.email, p.travel_date,p.duration,p.cost_raw,p.trackedemail_item_id,p.cost,p.updated,p.distance, ";
$mysql .= " CASE WHEN e.id IS NULL THEN '0' ELSE '1' END AS surge_price, ";
$mysql .= " CASE WHEN (f.id IS NOT NULL AND f.cost>f.average) THEN ROUND(f.average/f.cost,2) ELSE 0 END AS cheaper_alternative ";
$mysql .= " FROM parsedemail_item p LEFT JOIN trackedemail_item t ON t.id=p.trackedemail_item_id ";
$mysql .= " LEFT JOIN trip_surge_price e ON (e.data_source_id=p.id AND e.data_source=1) ";
$mysql .= " LEFT JOIN trip_price_comparison f ON (f.data_source_id=p.id AND e.data_source=1) LEFT JOIN members m ON m.id=t.member_id ";
$mysql .= " WHERE e.id IS NOT NULL ORDER BY t.id DESC LIMIT 500";
$trigger_query = array(
"SURGESAVE" => array(
"query" => $mysql,
"message" => "You are spending too much. Let's save money",
"feed_msg" => "",
"active" => 1,
"cat" => 'GOACTIVITY',
"dynamic_key" => "",
"start_save" => false, "send_mail" => 0, "send_notification" => 1
),
"ETRG0001" => array(
"query" => "SELECT id AS member_id,last_acct,count_acct,last_email,count_email, min_budget,count_acct+count_email AS total_data FROM members WHERE min_budget =0 AND count_email =0 AND count_acct =0 AND id > 0 ORDER BY notification_test ASC LIMIT 500",
"message" => "Let's examine how much you spend on travel. We can save money.",
"feed_msg" => "",
"active" => 1,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0001KEY",
"start_save" => true
),
"ETRG0002" => array(
"query" => "SELECT ma.*,m.min_budget from members_analysis ma LEFT JOIN members m ON m.id = ma.member_id WHERE m.min_budget > 0 AND ma.spend_7 > 0 AND ma.spend_7/m.min_budget < 0.9 ORDER BY m.notification_test ASC LIMIT 500",
"message" => "Good Job, you're saving money",
"feed_msg" => "",
"active" => 1,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0002KEY",
"start_save" => false, "send_mail" => 0, "send_notification" => 1
),
"ETRG0003" => array(
"query" => "SELECT ma.*,m.min_budget from members_analysis ma LEFT JOIN members m ON m.id = ma.member_id WHERE m.min_budget > 0 AND ma.spend_7 > 0 AND ma.spend_7/m.min_budget > 1.1 ORDER BY m.notification_test ASC LIMIT 500",
"message" => "You are over budget. Let's see how we can save you money.",
"feed_msg" => "",
"active" => 1,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0003KEY",
"start_save" => false, "send_mail" => 0, "send_notification" => 1
),
"ETRG0004" => array(
"query" => "SELECT ma.*,m.min_budget from members_analysis ma LEFT JOIN members m ON m.id = ma.member_id WHERE ma.spend_7 > 4000 ORDER BY m.notification_test ASC LIMIT 500",
"message" => "We can see you spent $X on rideshare this month. Here's how Float can save you money",
"feed_msg" => "",
"active" => 1,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0004KEY",
"start_save" => false, "send_mail" => 0, "send_notification" => 1
),
"ETRG0005" => array(
"query" => "SELECT b.member_id FROM members_bank_accounts b LEFT JOIN members m ON m.id=b.member_id WHERE m.id>0 AND m.country IN ('US','SG','NZ') GROUP BY b.member_id,m.notification_test ORDER BY m.notification_test ASC LIMIT 500",
"message" => "You have a Chase Freedom credit card. You should take Lyft this month",
"feed_msg" => "",
"active" => 1,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0005KEY",
"start_save" => false, "send_mail" => 0, "send_notification" => 1
)
,
"ETRG0006" => array(
"query" => "SELECT ma.*,m.min_budget,(ma.spend_14 - 2*ma.spend_7) AS week_increase from members_analysis ma LEFT JOIN members m ON m.id = ma.member_id WHERE min_budget = 0 AND ma.spend_7 > 0 AND ma.spend_14 > 2*ma.spend_7 ORDER BY m.notification_test ASC LIMIT 500",
"message" => "Your spending is up 23% this week. Would you like to create a budget?",
"feed_msg" => "",
"active" => 1,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0006KEY",
"start_save" => false, "send_mail" => 0, "send_notification" => 1
),
"ETRG0007" => array(
"query" => "SELECT ma.*,m.min_budget,(ma.spend_14 - 2*ma.spend_7) AS week_increase,m.country AS country from members_analysis ma LEFT JOIN members m ON m.id = ma.member_id WHERE m.decision_group IN('A1NUS25','USSF001') AND m.id NOT IN (SELECT member_id FROM members_carpool) ORDER BY m.notification_test ASC LIMIT 500",
"message" => "Deal Carpool Try carpooling and save $X and Y emissions this month",
"feed_msg" => "",
"active" => 1,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0007KEY",
"start_save" => false, "send_mail" => 0, "send_notification" => 1
),
"ETRG0008" => array(
"query" => "SELECT ma.*,m.min_budget,(ma.spend_14 - 2*ma.spend_7) AS week_increase from members_analysis ma LEFT JOIN members m ON m.id = ma.member_id WHERE min_budget = 0 AND ma.spend_7 > 0 AND ma.spend_14 > 2*ma.spend_7 ORDER BY m.notification_test ASC LIMIT 500",
"message" => "We can save you $X by taxing (rideshare or taxi) at 5pm today.",
"feed_msg" => "",
"active" => 0,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0008KEY",
"start_save" => false, "send_mail" => 0, "send_notification" => 1
),
"ETRG0009" => array(
"query" => "SELECT ma.*,m.min_budget,(ma.spend_14 - 2*ma.spend_7) AS week_increase from members_analysis ma LEFT JOIN members m ON m.id = ma.member_id WHERE min_budget = 0 AND ma.spend_7 > 0 AND ma.spend_14 > 2*ma.spend_7 ORDER BY m.notification_test ASC LIMIT 500",
"message" => "We found that taking public transit and scooter is faster and cheaper for you.",
"feed_msg" => "",
"active" => 0,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0009KEY",
"start_save" => false, "send_mail" => 0, "send_notification" => 1
),
"ETRG0010" => array(
"query" => "SELECT ma.*,m.min_budget,(ma.spend_14 - 2*ma.spend_7) AS week_increase from members_analysis ma LEFT JOIN members m ON m.id = ma.member_id WHERE min_budget = 0 AND ma.spend_7 > 0 AND ma.spend_14 > 2*ma.spend_7 ORDER BY m.notification_test ASC LIMIT 500",
"message" => "Your spending is up 23% this week. Would you like to create a budget?",
"feed_msg" => "",
"active" => 0,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0010KEY",
"start_save" => false, "send_mail" => 0, "send_notification" => 1
),
"ETRG0011" => array(
"query" => "SELECT *, id AS member_id FROM members WHERE id > 0 AND id NOT IN (SELECT member_id FROM members_trips) ORDER BY notification_test ASC LIMIT 500",
"message" => "Float found a better way for you to get to work. See route, save it and Float will remind you going forward.",
"feed_msg" => "",
"active" => 1,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0011KEY",
"start_save" => false, "send_mail" => 0, "send_notification" => 1
),
"ETRG0012" => array(
"query" => "SELECT ma.*,m.min_budget,(ma.spend_14 - 2*ma.spend_7) AS week_increase from members_analysis ma LEFT JOIN members m ON m.id = ma.member_id WHERE min_budget = 0 AND ma.spend_7 > 0 AND ma.spend_14 > 2*ma.spend_7 ORDER BY m.notification_test ASC LIMIT 500",
"message" => "Your spending is up 23% this week. Would you like to create a budget?",
"feed_msg" => "",
"active" => 0,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0012KEY",
"start_save" => false, "send_mail" => 0, "send_notification" => 1
),
"ETRG0014" => array(
"query" => "SELECT ma.*,m.min_budget,(2*ma.spend_7- ma.spend_14) AS week_increase from members_analysis ma LEFT JOIN members m ON m.id = ma.member_id WHERE ma.spend_7 > 0 AND 2*ma.spend_7> ma.spend_14 ORDER BY m.notification_test ASC LIMIT 500",
"message" => "Your emissions output is 10% higher this week, lets see how we can lower it",
"feed_msg" => "",
"active" => 1,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0014KEY",
"start_save" => false, "send_mail" => 0, "send_notification" => 1
),
"ETRG0015" => array(
"query" => "SELECT ma.*,m.min_budget,(2*ma.spend_7 - ma.spend_14) AS week_decrease from members_analysis ma LEFT JOIN members m ON m.id = ma.member_id WHERE min_budget = 0 AND ma.spend_7 > 0 AND ma.spend_14 < 2*ma.spend_7 ORDER BY m.notification_test ASC LIMIT 500",
"message" => "Hurray, you have spent X minutes less on the road this week. Shop for rewards with Float.",
"feed_msg" => "",
"active" => 1,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0015KEY",
"start_save" => false, "send_mail" => 0, "send_notification" => 1
)
,
"ETRG0016" => array(
"query" => "SELECT ma.*,m.min_budget,(ma.spend_14 - 2*ma.spend_7) AS week_increase from members_analysis ma LEFT JOIN members m ON m.id = ma.member_id WHERE min_budget = 0 AND ma.spend_7 > 0 AND ma.spend_14 > 2*ma.spend_7 ORDER BY m.notification_test ASC LIMIT 500",
"message" => "Good Job, you're saving X% more money than your peers.",
"feed_msg" => "",
"active" => 0,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0012KEY",
"start_save" => false, "send_mail" => 0, "send_notification" => 1
)
,
"ETRG0017" => array(
"query" => "SELECT ma.*,m.min_budget,(ma.spend_14 - 2*ma.spend_7) AS week_increase from members_analysis ma LEFT JOIN members m ON m.id = ma.member_id WHERE min_budget = 0 AND ma.spend_7 > 0 AND ma.spend_14 > 2*ma.spend_7 ORDER BY m.notification_test ASC LIMIT 500",
"message" => "You are spending more X% money than your peers. Let's save money ",
"feed_msg" => "",
"active" => 0,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0017KEY",
"start_save" => false, "send_mail" => 0, "send_notification" => 1
)
,
"ETRG0019" => array(
"query" => "SELECT * FROM members LIMIT 1",
"message" => "THIS IS USED FOR THE POINTS SYSTEM ONLY - It is automatic",
"feed_msg" => "",
"active" => 1,
"cat" => 'GOPOINT',
"dynamic_key" => "ETRG0019KEY",
"start_save" => false, "send_mail" => 1, "send_notification" => 1
),
"ETRG0020" => array(
"query" => "SELECT * FROM members LIMIT 1",
"message" => "THIS IS USED FOR THE TRIPS SYSTEM ONLY - It is automatic",
"feed_msg" => "",
"active" => 1,
"cat" => 'GOPOINT',
"dynamic_key" => "ETRG0020KEY",
"start_save" => false, "send_mail" => 1, "send_notification" => 1
),
"ETRG0021" => array(
"query" => "SELECT ma.member_id,ma.status,ma.bank_login_status FROM members_bank_accounts ma LEFT JOIN members m ON m.id=ma.member_id WHERE m.country ='SG' AND ma.bank_login_status='inactive' ORDER BY m.notification_test ASC LIMIT 500",
"message" => "Your bank connection has expired, import your latest transactions to stay on top of your spending",
"feed_msg" => "",
"active" => 1,
"cat" => 'GOPROFILE',
"dynamic_key" => "ETRG0021KEY",
"start_save" => false, "send_mail" => 1, "send_notification" => 1
)
,
"ETRG0022" => array(
"query" => "SELECT b.member_id, count(b.id) AS total_rec,m.notification_test FROM members_bankimport b LEFT JOIN members m ON m.id=b.member_id WHERE lower(merchant_name)= LOWER('ComfortDelGro') GROUP BY b.member_id, m.notification_test ORDER BY m.notification_test ASC LIMIT 500",
"message" => "Be careful how you pay, credit and charge card payments get hit with a 10% surcharge in a Comfort Taxi",
"feed_msg" => "",
"active" => 1,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0022KEY",
"start_save" => false, "send_mail" => 0, "send_notification" => 0
)
);
$trigger_card = array(
"ETRG0001" => array(
"active" => 1,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0001KEY"
),
"ETRG0002" => array(
"active" => 1,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0002KEY"
),
"ETRG0003" => array(
"active" => 1,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0003KEY"
),
"ETRG0004" => array(
"active" => 1,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0004KEY"
),
"ETRG0005" => array(
"active" => 1,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0005KEY"
),
"ETRG0006" => array(
"active" => 1,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0006KEY"
),
"ETRG0011" => array(
"active" => 1,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0011KEY"
),
"ETRG0014" => array(
"active" => 1,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0014KEY"
),
"ETRG0015" => array(
"active" => 1,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0015KEY"
),
"ETRG0019" => array(
"active" => 1,
"cat" => 'GOACTIVITY',
"dynamic_key" => "ETRG0019KEY"
),
"ETRG0021" => array(
"active" => 1,
"cat" => 'GOPROFILE',
"dynamic_key" => "ETRG0021KEY"
)
);
function generateCard($notice_id, $member_id, $cat) {
$out = array();
global $trigger_card;
global $readOnlyReplicaConn;
// print_r($trigger_card);
//echo "\n ~~~~~56565656 ----------------------------->>>> ".rand(100,999);
$trigger_key = "";
$dynamic_key = "";
$status_msg = '';
if ($notice_id != '' && $member_id != '') {
// echo "\n ~~~~~38383838383 ----------------------------->>>> ".rand(100,999);
$mysql = "SELECT * FROM members_notification WHERE id=$notice_id AND member_id=$member_id";
$r = pg_query($readOnlyReplicaConn, $mysql);
if ($r && pg_num_rows($r)) {
$f = pg_fetch_assoc($r);
$trigger_key = $f["trigger_key"];
$message = $f["msg"];
}
// echo "\n<br> ~~~~~55555 -----------------------------=====>>==>> ".rand(100,999);
$card_allowded = false;
if (array_key_exists($trigger_key, $trigger_card)) {
$status_msg = "The $trigger_key is in the array";
// print_r( $trigger_card[$trigger_key] );
$dynamic_key = $trigger_card[$trigger_key]["dynamic_key"];
$card_allowded = true;
} else {
$status_msg = "The $trigger_key not set up for cards";
}
// echo "\n<br> ~~~~~66666 -----------------------------=====>>==>> ".rand(100,999);
if (true == $card_allowded && $message != '' && $trigger_key != '' && $dynamic_key != '') {
$in = array();
echo "~~~~~44444 -----------------------------";
$in["dynamic_key"] = $dynamic_key;
$in["member_id"] = $member_id;
$in["trigger_key"] = $trigger_key;
$in["message"] = $message;
$in["notice_id"] = $notice_id;
$in["cat"] = $cat;
$in['action'] = FLOAT_SYSTEM_CREATE_DYNAMICCARD;
print_r($in);
$ret = Fextension_call($in, $out);
print_r($out);
if ($ret == PHP_API_OK) {
$message = 'Completed!';
} else {
$message = 'Failed to Create';
}
}
}
echo $status_msg;
}
+96
View File
@@ -0,0 +1,96 @@
<?php
$job_name = "update packing_lot Job";
echo "[" . date("Y-m-d H:i:s") . "] $job_name is starting.\n";
require('./lock.php');
//$lock_file = lock_pid_file();
require('./../backend.php');
require('./common/SVY21.php');
set_time_limit(0); // No limit!
$httpAuthToken = $savvyext->cfgReadChar('system.oauth2_token');
$db_host = $savvyext->cfgReadChar('database.host');
$db_name = $savvyext->cfgReadChar('database.name');
$db_user = $savvyext->cfgReadChar('database.user');
$db_pass = $savvyext->cfgReadChar('database.pass');
$db_port = $savvyext->cfgReadLong('database.port');
$connstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$con = pg_connect($connstr); // or die ("Could not connect to server\n");
$db_host = $savvyext->cfgReadChar('database_replica.host');
$db_name = $savvyext->cfgReadChar('database_replica.name');
$db_user = $savvyext->cfgReadChar('database_replica.user');
$db_pass = $savvyext->cfgReadChar('database_replica.pass');
$db_port = $savvyext->cfgReadLong('database_replica.port');
$readOnlyReplicaConnstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$readOnlyReplicaConn = pg_connect($readOnlyReplicaConnstr);
// Step 1: get URA token
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "https://www.ura.gov.sg/uraDataService/insertNewToken.action",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 1000, //1000s
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => array(
"accesskey: support@float.sg",
"cache-control: no-cache",
),
));
$response = json_decode(curl_exec($curl), true);
$err = curl_error($curl);
curl_close($curl);
$token = $response['Result'] ?? '';
if ($err) {
echo "cURL Error #1: Cannot get URA token!!! - " . $err;
}
// Step2. get car parking
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "https://www.ura.gov.sg/uraDataService/invokeUraDS?service=Car_Park_Details",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 1000, //1000s
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => array(
"accesskey: support@float.sg",
"token: $token",
"cache-control: no-cache"
),
));
$response = json_decode(curl_exec($curl), true);
$err = curl_error($curl);
curl_close($curl);
$parking_lots = $response['Result'] ?? [];
if ($err) {
echo "cURL Error #2: Cannot get car parking - " . $err;
}
// Step 3. INSERT data to database
if (!empty($parking_lots)) {
$now = (new \DateTime())->format('Y-m-d H:i:s');
$svy21 = new SVY21();
pg_query($con, 'DELETE FROM parking_lot');
pg_query($con, 'ALTER SEQUENCE parking_lot_id_seq RESTART WITH 1');
foreach ($parking_lots as $key => $lot) {
foreach ($lot['geometries']??[] as $geo){
list($n, $e) = explode(',',$geo['coordinates']);
list($lat, $long) = $svy21->CnvEN2LL($n, $e);
$res = pg_insert($con, 'parking_lot', [
'ppcode' => $lot['ppCode'] ?? '',
'name' => $lot['ppName'] ?? '',
'address' => $lot['ppName'] ?? '',
'lat' => strval($lat),
'long' => strval($long),
'weekday_price' => (float)str_replace('$', '', $lot['weekdayRate']??0),
'sat_price' => (float)str_replace('$', '', $lot['satdayRate']??0),
'sun_price' => (float)str_replace('$', '', $lot['sunPHRate']??0),
'start_time' => $lot['startTime'] ?? '',
'end_time' => $lot['endTime'] ?? '',
'updated_time' => $now,
], PGSQL_DML_ASYNC);
}
}
}
//unlock_pid_file($lock_file);
echo "[" . date("Y-m-d H:i:s") . "] " . $job_name . " completed.\n";
?>
+44
View File
@@ -0,0 +1,44 @@
<?php
$job_name ='parsedemail_item_fix_missing email';
echo "[" . date("Y-m-d H:i:s") . "] ".$job_name." job is starting.\n";
require 'common/utils.php';
require 'common/config.php';
require 'common/address_city.php';
require 'common/parser.php';
require 'common/Geocode.php';
$total = $success = $failed = 0;
$q = "SELECT id FROM trackedemail_item WHERE id NOT IN (SELECT trackedemail_item_id FROM parsedemail_item_payment) ORDER BY id DESC;";
$q="select id from trackedemail_item where id not in (select trackedemail_item_id from parsedemail_item p INNER JOIN trackedemail_item t on p.trackedemail_item_id=t.id WHERE member_id=347) AND member_id=347 order by id desc;";
#$q = "SELECT id FROM trackedemail_item WHERE member_id=472 ORDER BY id DESC;";
$q="select id,subject,message_from, member_id, created from trackedemail_item where id not in (select trackedemail_item_id from parsedemail_item_payment) order by created desc limit 200;";
$q="select * from trackedemail_item where parsed_status=0 order by created desc";
$q="select id from trackedemail_item where parsed_status=0";
$r = pg_query($conn, $q);
while ($f = pg_fetch_assoc($r)) {
$total++;
$email_id = $f['id'];
if (!empty($email_id)) {
$data = parseEmail($email_id);
echo "raw:".json_encode($data);
if ( isset( $data['parsed_status'] ) && $data['parsed_status']==1 ) {
echo "[" . date("Y-m-d H:i:s") . "] email id: ".$email_id." is success.\n";
$success++;
}else{
echo "[" . date("Y-m-d H:i:s") . "] email id: ".$email_id." is failed.\n";
$failed++;
}
} else {
echo "[" . date("Y-m-d H:i:s") . "] email id: ".$email_id." is failed.\n";
$failed++;
}
}
echo "Total: " . $total . ".\n";
echo "Success: : " . $success . ".\n";
echo "Failed: : " . $failed . ".\n";
echo "[" . date("Y-m-d H:i:s") . "] ".$job_name." job complete.\n";
+38
View File
@@ -0,0 +1,38 @@
<?php
$job_name ='parsedemail_item_fix_missing email';
echo "[" . date("Y-m-d H:i:s") . "] ".$job_name." job is starting.\n";
require 'common/utils.php';
require 'common/config.php';
require 'common/address_city.php';
require 'common/parser.php';
require 'common/Geocode.php';
$total = $success = $failed = 0;
$q="SELECT trackedemail_item_id as id from parsedemail_item where duration > 600 and trackedemail_item_id is not null order by duration desc";
$r = pg_query($conn, $q);
while ($f = pg_fetch_assoc($r)) {
$total++;
$email_id = $f['id'];
if (!empty($email_id)) {
$data = parseEmail($email_id);
if ( isset( $data['parsed_status'] ) && $data['parsed_status']==1 ) {
echo "[" . date("Y-m-d H:i:s") . "] email id: ".$email_id." is success.\n";
$success++;
}else{
echo "[" . date("Y-m-d H:i:s") . "] email id: ".$email_id." is failed.\n";
$failed++;
}
} else {
echo "[" . date("Y-m-d H:i:s") . "] email id: ".$email_id." is failed.\n";
$failed++;
}
}
echo "Total: " . $total . ".\n";
echo "Success: : " . $success . ".\n";
echo "Failed: : " . $failed . ".\n";
echo "[" . date("Y-m-d H:i:s") . "] ".$job_name." job complete.\n";
+60
View File
@@ -0,0 +1,60 @@
<?php
echo "[".date("Y-m-d H:i:s")."] parsedemail_item_cleanup job is starting.\n";
require '../backend.php';
global $pgconn;
$db_host = $savvyext->cfgReadChar('database.host');
$db_port = $savvyext->cfgReadLong('database.port');
$db_name = $savvyext->cfgReadChar('database.name');
$db_user = $savvyext->cfgReadChar('database.user');
$db_pass = $savvyext->cfgReadChar('database.pass');
$conn_string = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$pgconn = pg_connect($conn_string);
$db_host = $savvyext->cfgReadChar('database_replica.host');
$db_name = $savvyext->cfgReadChar('database_replica.name');
$db_user = $savvyext->cfgReadChar('database_replica.user');
$db_pass = $savvyext->cfgReadChar('database_replica.pass');
$db_port = $savvyext->cfgReadLong('database_replica.port');
$readOnlyReplicaConnstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$readOnlyReplicaConn = pg_connect($readOnlyReplicaConnstr);
$q = "SELECT b.id FROM parsedemail_item b LEFT JOIN address c ON (c.id=b.location_start_id) LEFT JOIN address d ON (d.id=b.location_end_id) WHERE (c.country='US' AND d.country='SG') OR (c.country='SG' AND d.country='US')";
//$q = "SELECT id FROM parsedemail_item WHERE id>20209";
$r = pg_query($readOnlyReplicaConn, $q);
while ($f=pg_fetch_row($r)) {
echo "[".date("Y-m-d H:i:s")."] Cleaning up => ".$f[0]."\n";
$q = "DELETE FROM parsedemail_item_advice_schedule WHERE parsedemail_item_id=".$f[0];
$s = pg_query($pgconn, $q);
echo "\t\tparsedemail_item_advice_schedule => ".pg_affected_rows($s)."\n";
$q = "DELETE FROM google_directions_leg_step_details WHERE google_directions_leg_step_id IN (SELECT id FROM google_directions_leg_steps WHERE google_directions_leg_id IN (SELECT id FROM google_directions_legs WHERE parsedemail_item_advice_google_id IN (SELECT id FROM parsedemail_item_advice_google WHERE parsedemail_item_id=".$f[0].")))";
$s = pg_query($pgconn, $q);
echo "\t\tgoogle_directions_leg_step_details => ".pg_affected_rows($s)."\n";
$q = "DELETE FROM leg_step_quote WHERE google_directions_leg_step_id IN (SELECT id FROM google_directions_leg_steps WHERE google_directions_leg_id IN (SELECT id FROM google_directions_legs WHERE parsedemail_item_advice_google_id IN (SELECT id FROM parsedemail_item_advice_google WHERE parsedemail_item_id=".$f[0].")))";
$s = pg_query($pgconn, $q);
echo "\t\tleg_step_quote => ".pg_affected_rows($s)."\n";
$q = "DELETE FROM google_directions_leg_steps WHERE google_directions_leg_id IN (SELECT id FROM google_directions_legs WHERE parsedemail_item_advice_google_id IN (SELECT id FROM parsedemail_item_advice_google WHERE parsedemail_item_id=".$f[0]."))";
$s = pg_query($pgconn, $q);
echo "\t\tgoogle_directions_leg_stesp => ".pg_affected_rows($s)."\n";
$q = "DELETE FROM google_directions_legs WHERE parsedemail_item_advice_google_id IN (SELECT id FROM parsedemail_item_advice_google WHERE parsedemail_item_id=".$f[0].")";
$s = pg_query($pgconn, $q);
echo "\t\tgoogle_directions_legs => ".pg_affected_rows($s)."\n";
$q = "DELETE FROM parsedemail_item_advice_google WHERE parsedemail_item_id=".$f[0];
$s = pg_query($pgconn, $q);
echo "\t\tparsedemail_item_advice_google => ".pg_affected_rows($s)."\n";
$q = "DELETE FROM parsedemail_item_extra WHERE parsedemail_item_id=".$f[0];
$s = pg_query($pgconn, $q);
echo "\t\tparsedemail_item_extra => ".pg_affected_rows($s)."\n";
$q = "DELETE FROM parsedemail_item WHERE id=".$f[0];
$s = pg_query($pgconn, $q);
echo "\t\tparsedemail_item => ".pg_affected_rows($s)."\n";
echo pg_last_error($pgconn)."\n";
}
pg_close($pgconn);
pg_close($readOnlyReplicaConn);
echo "[".date("Y-m-d H:i:s")."] parsedemail_item_cleanup job complete.\n";
+53
View File
@@ -0,0 +1,53 @@
<?php
$job_name ='parsedemail_item_fix_address';
echo "[" . date("Y-m-d H:i:s") . "] ".$job_name." job is starting.\n";
require 'common/utils.php';
require 'common/config.php';
require 'common/address_city.php';
require 'common/parser.php';
require 'common/Geocode.php';
$total = $success = $failed = 0;
$q = "SELECT id, trackedemail_item_id
FROM parsedemail_item WHERE location_start_id = 22957 or location_end_id=22957;";
$r = pg_query($readOnlyReplicaConn, $q);
while ($f = pg_fetch_assoc($r)) {
$total++;
$email_id = $f['trackedemail_item_id'];
if (!empty($email_id)) {
$email_data = parseEmail($f['trackedemail_item_id']);
if (is_array($email_data) && !empty(trim($email_data['location_start_value'])) && !empty(trim($email_data['location_end_value']))) {
$id = $f['id'];
$location_start_value = $email_data['location_start_value'];
$location_end_value = $email_data['location_end_value'];
$location_start_id = getAddressId($location_start_value);
if(empty($location_start_id)){
$result = Geocode::geocodeAddress($location_start_value);
$result["address"] = $location_start_value;
$location_start_id= saveAddress($result);
}
$location_end_id = getAddressId($location_end_value);
if(empty($location_end_id)){
$result = Geocode::geocodeAddress($location_end_value);
$result["address"] = $location_end_value;
$location_end_id= saveAddress($result);
}
if ($location_start_id && $location_end_id) {
updateParsedEmail($id, $location_start_id, $location_end_id);
$success++;
}
}
} else {
$failed++;
}
}
echo "Total: " . $total . ".\n";
echo "Success: : " . $success . ".\n";
echo "Failed: : " . $failed . ".\n";
echo "[" . date("Y-m-d H:i:s") . "] ".$job_name." job complete.\n";
+78
View File
@@ -0,0 +1,78 @@
<?php
echo "[" . date("Y-m-d H:i:s") . "] parsedemail_item_fix_time_travel job is starting.\n";
require '../backend.php';
global $pgconn;
$db_host = $savvyext->cfgReadChar('database.host');
$db_port = $savvyext->cfgReadLong('database.port');
$db_name = $savvyext->cfgReadChar('database.name');
$db_user = $savvyext->cfgReadChar('database.user');
$db_pass = $savvyext->cfgReadChar('database.pass');
$conn_string = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$pgconn = pg_connect($conn_string);
$db_host = $savvyext->cfgReadChar('database_replica.host');
$db_name = $savvyext->cfgReadChar('database_replica.name');
$db_user = $savvyext->cfgReadChar('database_replica.user');
$db_pass = $savvyext->cfgReadChar('database_replica.pass');
$db_port = $savvyext->cfgReadLong('database_replica.port');
$readOnlyReplicaConnstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$readOnlyReplicaConn = pg_connect($readOnlyReplicaConnstr);
/*get travel_time is measured with seconds*/
$total = $success = $failed = 0;
$r = get_duration_in_seconds();
while ($f = pg_fetch_array($r, NULL, PGSQL_ASSOC)) {
$total++;
$id = $f['id'];
$condition = "id=".$id;
$duration = $f['new_duration'];
$data = [
"duration" => $duration
];
$updated = update_data($data, $condition);
if ($updated > 0) {
$success++;
} else {
$failed++;
}
}
echo "Total: " . $total . ".\n";
echo "Success: : " . $success . ".\n";
echo "Failed: : " . $failed . ".\n";
pg_close($pgconn);
echo "[" . date("Y-m-d H:i:s") . "] parsedemail_item_fix_time_travel job complete.\n";
function get_duration_in_seconds()
{
global $readOnlyReplicaConn;
$q = "SELECT id, DATE_PART('hour', travel_date_end - travel_date)*60+DATE_PART('minute', travel_date_end - travel_date) AS new_duration
FROM parsedemail_item
WHERE transport_provider_id IS NOT NULL
GROUP BY id, DATE_PART('hour', travel_date_end - travel_date)*60+DATE_PART('minute', travel_date_end - travel_date)
HAVING duration >DATE_PART('hour', travel_date_end - travel_date)*60+DATE_PART('minute', travel_date_end - travel_date)
AND DATE_PART('hour', travel_date_end - travel_date)*60+DATE_PART('minute', travel_date_end - travel_date)>0";
return pg_query($readOnlyReplicaConn, $q);
}
function update_data($data, $condition="1=1")
{
global $pgconn;
if (count($data)>0) {
$data_update="updated=NOW()";
foreach ($data as $field => $val) {
$data_update .= ", ${field}=" . ($val == 'NULL' ? "NULL" : "'${val}'");
}
$q = "UPDATE parsedemail_item SET " . $data_update . " WHERE " . $condition . "";
$r = pg_query($pgconn, $q);
if ($r) {
return pg_affected_rows($r);
}
}
return 0;
}
+111
View File
@@ -0,0 +1,111 @@
<?php
echo "[" . date("Y-m-d H:i:s") . "] parsedemail_item_fix_time_travel job is starting.\n";
require '../backend.php';
global $pgconn;
$db_host = $savvyext->cfgReadChar('database.host');
$db_port = $savvyext->cfgReadLong('database.port');
$db_name = $savvyext->cfgReadChar('database.name');
$db_user = $savvyext->cfgReadChar('database.user');
$db_pass = $savvyext->cfgReadChar('database.pass');
$conn_string = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$pgconn = pg_connect($conn_string);
$db_host = $savvyext->cfgReadChar('database_replica.host');
$db_name = $savvyext->cfgReadChar('database_replica.name');
$db_user = $savvyext->cfgReadChar('database_replica.user');
$db_pass = $savvyext->cfgReadChar('database_replica.pass');
$db_port = $savvyext->cfgReadLong('database_replica.port');
$readOnlyReplicaConnstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$readOnlyReplicaConn = pg_connect($readOnlyReplicaConnstr);
/*get travel_time is measured with seconds*/
$total = $success = $failed = 0;
$r=get_negative_durations();
while ($f = pg_fetch_array($r, NULL, PGSQL_ASSOC)) {
$total++;
$id = $f['id'];
$duration = $f['duration'];
$travel_date = $f['travel_date'];
$transport_provider_id = $f['transport_provider_id'];
if (in_array($transport_provider_id, [1,5])) {//Uber, GOJEK
$travel_date_end = $f['new_travel_date_end'];
if(empty($duration)){
$duration = $f['new_duration'];
}
} else {
$new_travel_date_end = (new DateTime($f['travel_date']))->modify('+'.$duration.' minutes');
$travel_date_end=$new_travel_date_end->format('Y-m-d H:i:s');
}
$condition = "id=".$id;
$data = [
"duration" => $duration,
"transport_provider_id" => $transport_provider_id,
"travel_date" => $travel_date,
"travel_date_end" => $travel_date_end
];
$updated = update_data($data, $condition);
if ($updated > 0) {
$success++;
} else {
$failed++;
}
}
echo "Total: " . $total . ".\n";
echo "Success: : " . $success . ".\n";
echo "Failed: : " . $failed . ".\n";
pg_close($pgconn);
echo "[" . date("Y-m-d H:i:s") . "] parsedemail_item_fix_time_travel job complete.\n";
function get_negative_durations(){
global $readOnlyReplicaConn;
$q = "SELECT p.id,
duration,
DATE_PART('hour', travel_date_end - travel_date)*60+DATE_PART('minute', travel_date_end - travel_date) AS new_duration,
travel_date,
travel_date_end,
travel_date_end + interval '1' day as new_travel_date_end,
transport_provider_id,
message,
message_date
FROM parsedemail_item p INNER JOIN trackedemail_item t on p.trackedemail_item_id=t.id
WHERE transport_provider_id IS NOT NULL
GROUP BY p.id,
duration,
DATE_PART('hour', travel_date_end - travel_date)*60+DATE_PART('minute', travel_date_end - travel_date),
travel_date,
travel_date_end,
travel_date_end + interval '1' day,
transport_provider_id,
message,
message_date
HAVING DATE_PART('hour', travel_date_end - travel_date)*60+DATE_PART('minute', travel_date_end - travel_date)<0
ORDER BY transport_provider_id ASC";
return pg_query($readOnlyReplicaConn, $q);
}
function update_data($data, $condition="1=1")
{
global $pgconn;
if (count($data)>0) {
$data_update="updated=NOW()";
foreach ($data as $field => $val) {
$data_update .= ", ${field}=" . ($val == 'NULL' ? "NULL" : "'${val}'");
}
$q = "UPDATE parsedemail_item SET " . $data_update . " WHERE " . $condition . "";
$r = pg_query($pgconn, $q);
if ($r) {
return pg_affected_rows($r);
}
}
return 0;
}
+59
View File
@@ -0,0 +1,59 @@
<?php
$job_name ='parsedemail_item_fix_address';
echo "[" . date("Y-m-d H:i:s") . "] ".$job_name." job is starting.\n";
require 'common/utils.php';
require 'common/config.php';
require 'common/address_city.php';
require 'common/parser.php';
require 'common/Geocode.php';
$total = $success = $failed = 0;
$q = "SELECT id, trackedemail_item_id
FROM parsedemail_item_payment WHERE member_id is null;";
$r = pg_query($readOnlyReplicaConn, $q);
while ($f = pg_fetch_assoc($r)) {
$total++;
$id = $f['id'];
$email_id = $f['trackedemail_item_id'];
if (!empty($email_id)) {
$member_id = getTrackedEmail($email_id);
if ($member_id) {
updateParsedPayment($id, $member_id);
$success++;
}
} else {
$failed++;
}
}
echo "Total: " . $total . ".\n";
echo "Success: : " . $success . ".\n";
echo "Failed: : " . $failed . ".\n";
echo "[" . date("Y-m-d H:i:s") . "] ".$job_name." job complete.\n";
function getTrackedEmail($id)
{
global $readOnlyReplicaConn;
$q = "SELECT member_id FROM trackedemail_item WHERE id = " . $id . "";
$r = pg_query($readOnlyReplicaConn, $q);
if ($r && pg_num_rows($r) && $f = pg_fetch_assoc($r)) {
return $f['member_id'];
} else {
return null;
}
}
function updateParsedPayment($id, $member_id)
{
global $conn;
$q = "UPDATE parsedemail_item_payment SET member_id='" . $member_id . "' WHERE id = " . $id . "";
$r = pg_query($conn, $q);
if ($r && pg_num_rows($r) && $f = pg_fetch_assoc($r)) {
return [$f, null];
}
return [null, pg_last_error($conn)];
}
@@ -0,0 +1,67 @@
<?php
echo "[".date("Y-m-d H:i:s")."] parsedemail_item_cleanup job is starting.\n";
require '../backend.php';
global $pgconn;
$db_host = $savvyext->cfgReadChar('database.host');
$db_port = $savvyext->cfgReadLong('database.port');
$db_name = $savvyext->cfgReadChar('database.name');
$db_user = $savvyext->cfgReadChar('database.user');
$db_pass = $savvyext->cfgReadChar('database.pass');
$conn_string = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$pgconn = pg_connect($conn_string);
$q = "SELECT t.member_id,travel_date ,transport_provider_id,location_start_id,location_end_id, duration, cost, count(*)
FROM parsedemail_item p INNER JOIN trackedemail_item t on p.trackedemail_item_id=t.id
WHERE cost > 0 and member_id>0 AND dup_id is NULL
GROUP BY t.member_id,travel_date ,transport_provider_id,location_start_id,location_end_id, duration, cost
HAVING count(*)>1
ORDER BY count(*) DESC,member_id ASC";
//$q = "SELECT id FROM parsedemail_item WHERE id>20209";
$r = pg_query($pgconn, $q);
while ($f=pg_fetch_assoc($r)) {
$condition = "travel_date ='".$f['travel_date']."' and duration=".$f['duration']." and cost=".$f['cost']." and transport_provider_id=".$f['transport_provider_id']." AND member_id=".$f['member_id'];
$keep = getKeepId($condition);
while ($k = pg_fetch_assoc($keep)) {
$id = $k['id'];
$conditionUpdate = $condition.=" AND p.id!=".$id;
updateDuplicate($conditionUpdate,$id);
//var_dump($k);exit;
}
}
pg_close($pgconn);
function getKeepId($condition)
{
global $pgconn;
$q = "SELECT p.id,member_id, t.id as trackedemail_item_id,travel_date, travel_date_end,transport_provider_id,location_start_id,location_end_id
FROM parsedemail_item p INNER JOIN trackedemail_item t on p.trackedemail_item_id=t.id
WHERE ".$condition."
ORDER BY p.id ASC LIMIT 1";echo $q."\n";
$r = pg_query($pgconn, $q);
return $r;
}
function updateDuplicate($condition,$dup_id){
global $pgconn;
$q="UPDATE
parsedemail_item p
SET
dup_id=".$dup_id."
FROM
trackedemail_item t
WHERE
p.trackedemail_item_id = t.id
AND ".$condition."";
echo $q."\n";
$r = pg_query($pgconn, $q);
return $r;
}
echo "[".date("Y-m-d H:i:s")."] parsedemail_item_cleanup job complete.\n";
@@ -0,0 +1,60 @@
<?php
echo "[" . date("Y-m-d H:i:s") . "] parsedemail_item_update_base_cost job is starting.\n";
require '../backend.php';
global $pgconn, $readOnlyReplicaConn;
$db_host = $savvyext->cfgReadChar('database.host');
$db_port = $savvyext->cfgReadLong('database.port');
$db_name = $savvyext->cfgReadChar('database.name');
$db_user = $savvyext->cfgReadChar('database.user');
$db_pass = $savvyext->cfgReadChar('database.pass');
$conn_string = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$pgconn = pg_connect($conn_string);
$db_host = $savvyext->cfgReadChar('database_replica.host');
$db_name = $savvyext->cfgReadChar('database_replica.name');
$db_user = $savvyext->cfgReadChar('database_replica.user');
$db_pass = $savvyext->cfgReadChar('database_replica.pass');
$db_port = $savvyext->cfgReadLong('database_replica.port');
$readOnlyReplicaConnstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$readOnlyReplicaConn = pg_connect($readOnlyReplicaConnstr);
/*get travel_time is measured with seconds*/
$q = "SELECT p.id, cost, promotions_credits
FROM parsedemail_item p LEFT JOIN parsedemail_item_extra pa ON p.id=pa.parsedemail_item_id";
$r = pg_query($readOnlyReplicaConn, $q);
$total = $success = $failed = 0;
while ($f = pg_fetch_row($r)) {
$total ++;
$id = $f[0];
$cost = $f[1];
$promotions_credits = $f[2];
//echo $cost,$promotions_credits;
$base_cost = $cost+abs($promotions_credits);
$updated = update_base_cost($id,$base_cost);
if($updated>0){
$success++;
}else{
$failed++;
}
}
echo "Total: ".$total.".\n";
echo "Success: : ".$success.".\n";
echo "Failed: : ".$failed.".\n";
pg_close($readOnlyReplicaConn);
echo "[" . date("Y-m-d H:i:s") . "] parsedemail_item_update_base_cost job complete.\n";
function update_base_cost($id, $base_cost) {
global $pgconn;
$q = "UPDATE parsedemail_item SET base_cost=" . $base_cost . " WHERE id=" . $id . "";
$r = pg_query($pgconn, $q);
if ($r) {
return pg_affected_rows($r);
}
return 0;
}
+27
View File
@@ -0,0 +1,27 @@
<?php
echo "[".date("Y-m-d H:i:s")."] Decision Generator job is starting.\n";
include '../backend.php';
define("FLOAT_SYSTEM_POINTS_GENERATOR", 92022);
function Fextension_call($in, &$out) {
// logToFl("Merchant_Name count->" . $in["merchant_name"]);
global $savvyext;
$out = $savvyext->savvyext_api($in);
$ret = $out["retval"];
return $ret;
}
$inX["limit"] = 25;
$inX["pid"] = 0;
$inX["action"] = FLOAT_SYSTEM_POINTS_GENERATOR;
$outX=array();
$extension_call = true;
if ($extension_call == true ) {
// logToFl("merchant_name count->" . $res->merchant_name);
Fextension_call($inX, $outX);
}
+92
View File
@@ -0,0 +1,92 @@
<?php
session_start();
echo "[" . date("Y-m-d H:i:s") . "] GPS quotes_update_travel_time job is starting.\n";
require 'common/utils.php';
require 'common/config.php';
require 'common/address_city.php';
$total = $success = $failed = 0;
$conditions = [
"completed is not null AND travel_date is null",//
];
$limit =100;
$arr_timezones = [
];//address_id, timezone
$start = floor(microtime(true)*1000);
foreach ($conditions as $condition) {
$total = getTotalQuotesByCondition($condition);
for($i=0; $i<$total;$i+=$limit){
$offset =$i;
$quotes = getQuotesByCondition($condition,$limit, $offset);
while ($f = pg_fetch_assoc($quotes)) {
$total++;
$id = $f['id'];
$completed = $f['completed'];
if (!array_key_exists($f['location_start_id'], $arr_timezones)) {
echo "query time zone==========================================\n";
$timezone = getTzByAddressId($f['location_start_id']);
$arr_timezones[$f['location_start_id']] = $timezone;
}
$timezone = $arr_timezones[$f['location_start_id']];
$travel_date = convertUtcToLocal($completed, $timezone);
$data_update = [
'travel_date' => $travel_date,
];
$condition_update = "id = " . $id . "";
$startu = floor(microtime(true)*1000);
$updated = updateDataTable('quotes', $condition_update, $data_update);
$endu = floor(microtime(true)*1000);
$durationu=$endu-$startu;
echo $durationu." miliseconds ********************************************\n";
if ($updated) {
$success++;
} else {
$failed++;
}
}
if($i==200){
break;
}
}
}
$end = floor(microtime(true)*1000);
$duration = $end -$start;
echo "start: " . $start . ".\n";
echo "end: " . $end . ".\n";
echo "duration: " . $duration . " miliseconds.\n";
echo "Total: " . $total . ".\n";
echo "Success: : " . $success . ".\n";
echo "Failed: : " . $failed . ".\n";
echo "[" . date("Y-m-d H:i:s") . "] quotes_update_travel_time job complete.\n";
function getQuotesByCondition($condition, $limit=10, $offset=0)
{
global $readOnlyReplicaConn;
$q = "SELECT id,created,completed,location_start_id, location_end_id, travel_date
FROM quotes
WHERE " . $condition . "
ORDER BY id DESC
LIMIT ".$limit." offset ". $offset."";
echo $q."\n";
$r = pg_query($readOnlyReplicaConn, $q);
return $r;
}
function getTotalQuotesByCondition($condition)
{
global $readOnlyReplicaConn;
$q = "SELECT count(*) as total
FROM quotes
WHERE " . $condition . "
";
$r = pg_query($readOnlyReplicaConn, $q);
while ($f=pg_fetch_array($r)) {
return $f['total'];
}
return 0;
}
+256
View File
@@ -0,0 +1,256 @@
<?php
// require_once( '/Users/osx/Sites/Float/adminsavvy/backend.php' );
include '../backend.php';
require_once('../vendor/autoload.php');
require_once( 'common/Logger.php' );
use \SendGrid\Mail\Mail;
/**
* Send list email parsed fail report
*/
class SendEmailReceiptFail {
public $conn;
public $repConn;
public $sendgrid_api;
public $sender;
public $sender_name;
public $receivers;
protected $hard_limit = 550;
function __construct() {
global $savvyext;
$this->conn = self::__cnn( $savvyext );
$this->repConn = self::__repCnn( $savvyext );
$this->sendgrid_api = $savvyext->cfgReadChar('mailsend.api_key');
$this->sender = $savvyext->cfgReadChar('mailsend.from');
$this->sender_name = $savvyext->cfgReadChar('mailsend.name');
$this->receivers = array(
'stew@float.sg' => 'Stew',
'olu@float.sg' => 'Olu',
'chelsea@float.sg' => 'Chelsea',
'cornel@float.sg' => 'Cornel',
'lviet@float.sg' => 'Le Viet',
'tnguyen@float.sg' => 'Tri Nguyen',
'helen@goldenowl.asia' => 'Helen',
'george@goldenowl.asia' => 'George',
);
}
private static function __cnn( $savvyext ) {
$db_host = $savvyext->cfgReadChar('database.host');
$db_name = $savvyext->cfgReadChar('database.name');
$db_user = $savvyext->cfgReadChar('database.user');
$db_pass = $savvyext->cfgReadChar('database.pass');
$db_port = $savvyext->cfgReadLong('database.port');
$connstr = sprintf( 'host=%s port=%s dbname=%s user=%s password=%s', $db_host, $db_port, $db_name, $db_user, $db_pass );
$conn = pg_connect($connstr);
return $conn;
}
private static function __repCnn( $savvyext ) {
$db_host = $savvyext->cfgReadChar('database_replica.host');
$db_name = $savvyext->cfgReadChar('database_replica.name');
$db_user = $savvyext->cfgReadChar('database_replica.user');
$db_pass = $savvyext->cfgReadChar('database_replica.pass');
$db_port = $savvyext->cfgReadLong('database_replica.port');
$connstr = sprintf( 'host=%s port=%s dbname=%s user=%s password=%s', $db_host, $db_port, $db_name, $db_user, $db_pass );
$conn = pg_connect($connstr);
return $conn;
}
/**
* Send email report via SendGrid
* @param array $data list email fail
* @return mixed
*/
protected function send( $data ) {
// create email layout
ob_start();
require_once( __DIR__ . '/email/email-parsed-fail.php' );
$layout = ob_get_clean();
// create sendgrid instance
$sendgrid = new \SendGrid\Mail\Mail;
$sendgrid->setFrom( $this->sender, $this->sender_name );
$currentDate = date('D M j G:i');
$last7days = date('D M j', strtotime('-7 days'));
$sendgrid->setSubject("Report: Failed email parsers last 7 days - From $last7days to $currentDate UTC");
$sendgrid->addTos( $this->receivers );
$sendgrid->addContent( 'text/html', $layout );
// send
$send = new \SendGrid( $this->sendgrid_api );
$response = $send->send( $sendgrid );
if ( $response->statusCode() !== 202 ) {
throw new Exception( 'Send email via Sendgrid get errors!' );
}
}
/**
* Get all email receipt parsed fail
* @return array
*/
public function getemails() {
try {
$sql = "
SELECT pf.name AS merchant_name, ti.id AS trackedemail_item_id, m.email, m.id AS user_id, ti.subject, ti.message_date,
CASE WHEN pf.reported_via_email IS TRUE THEN 'Yes' ELSE 'No' END AS reported
FROM trackedemail_item ti
INNER JOIN members m ON m.id = ti.member_id
INNER JOIN (
SELECT trackedemail_item_id, tp.name, reported_via_email
FROM parsedemail_item_failed pi
LEFT JOIN transport_providers tp ON tp.id = pi.transport_provider_id
WHERE pi.parsed_status = 0 AND pi.added > CURRENT_DATE - 7
) pf ON pf.trackedemail_item_id = ti.id
WHERE ti.parsed_status = 0 AND date_parsed IS NOT NULL";
$results = pg_query( $this->repConn, $sql );
if ( $error = pg_last_error( $this->repConn ) ) {
throw new Exception( $error );
}
$results = pg_fetch_all( $results );
if (!$results) {
return null;
}
$new_parsed_fail_email_arr = [];
foreach ($results as &$item) {
// Save trackedemail item id for updating col 'reported_via_email' in table 'parsedemail_item_failed'
if ($item['reported'] === 'No') {
array_push($new_parsed_fail_email_arr, $item['trackedemail_item_id']);
}
}
return [$results, $new_parsed_fail_email_arr];
} catch (Exception $e) {
Logger::debug( $e->getMessage() );
}
}
/**
* Excute jobs
* @return mixed
*/
public function excute() {
try {
list($data['emails'], $data['new_parsed_fail_email']) = $this->getemails();
$data['summary']= $this->getReportByMerchantName();
if (empty($data['emails']) && empty($data['summary'])) {
throw new Exception( 'No Email Receipt which parsed failed!' );
}
$send = $this->send( $data );
// After report email has been sent, we will change 'reported_via_email' status
if (!empty($data['new_parsed_fail_email'])) {
foreach ($data['new_parsed_fail_email'] ?? [] as $email_id) {
$sql = "UPDATE parsedemail_item_failed SET reported_via_email = TRUE WHERE trackedemail_item_id = $email_id";
pg_query( $this->repConn, $sql );
}
}
} catch (Exception $e) {
Logger::debug( $e->getMessage() );
}
}
public function getReportByMerchantName() {
$results = [];
$sql = "
SELECT count(*) AS success, tp.name, tp.category
FROM parsedemail_item pi
LEFT JOIN transport_providers tp ON tp.id = pi.transport_provider_id
WHERE pi.transport_provider_id IS NOT NULL AND pi.updated > CURRENT_DATE - 7
GROUP BY pi.transport_provider_id, tp.name, tp.category";
$q = pg_query($this->repConn, $sql);
$parsedSuccessSummary = pg_fetch_all($q);
if (!$parsedSuccessSummary) {
$parsedSuccessSummary = [];
}
$sql = "
SELECT count(*) AS fail, tp.name, tp.category
FROM parsedemail_item_failed pi
LEFT JOIN transport_providers tp ON tp.id = pi.transport_provider_id
WHERE pi.transport_provider_id IS NOT NULL AND pi.added > CURRENT_DATE - 7
GROUP BY pi.transport_provider_id, tp.name, tp.category";
$q = pg_query($this->repConn, $sql);
$parsedFailSummary = pg_fetch_all($q);
if (!$parsedFailSummary) {
$parsedFailSummary = [];
}
if (!$parsedSuccessSummary && !$parsedFailSummary) {
return null;
}
// Combine success and fail summary
foreach ($parsedFailSummary as $item) {
$isExistTranportProvider = false;
foreach ($parsedSuccessSummary as $item2) {
if ($item2['name'] === $item['name']) {
$isExistTranportProvider = true;
break;
}
}
if (!$isExistTranportProvider) {
array_push($parsedSuccessSummary, $item);
}
}
// Combine success and fail summary
foreach ($parsedSuccessSummary as $item) {
foreach ($parsedFailSummary as $item2) {
if ($item2['name'] === $item['name']) {
$item['fail'] = $item2['fail'];
}
}
$item['fail'] = $item['fail'] ?? 0;
$item['success'] = $item['success'] ?? 0;
// Set transport
if ($item['category'] !== 'Retail' && $item['category'] !== null) {
$item['transport'] = 'Yes';
} else {
$item['transport'] = 'No';
}
unset($item['category']);
array_push($results, $item);
}
// Calculate total for each merchant name
foreach ($results as &$result) {
$result['total'] = intval($result['success']) + intval($result['fail']);
}
return $results;
}
}
$instace = new SendEmailReceiptFail;
$instace->excute();
+184
View File
@@ -0,0 +1,184 @@
<?php
echo "[".date("Y-m-d H:i:s")."] GPS singaport_mrtlrt_stop_fares job is starting.\n";
require('../backend.php');
$httpAuthToken = $savvyext->cfgReadChar('system.oauth2_token');
$db_host = $savvyext->cfgReadChar('database.host');
$db_name = $savvyext->cfgReadChar('database.name');
$db_user = $savvyext->cfgReadChar('database.user');
$db_pass = $savvyext->cfgReadChar('database.pass');
$db_port = $savvyext->cfgReadLong('database.port');
$connstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$conn = pg_connect($connstr);
$db_host = $savvyext->cfgReadChar('database_replica.host');
$db_name = $savvyext->cfgReadChar('database_replica.name');
$db_user = $savvyext->cfgReadChar('database_replica.user');
$db_pass = $savvyext->cfgReadChar('database_replica.pass');
$db_port = $savvyext->cfgReadLong('database_replica.port');
$readOnlyReplicaConnstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$readOnlyReplicaConn = pg_connect($readOnlyReplicaConnstr);
$q = 'SELECT line,count(*) FROM singapore_bus_stops GROUP BY line';
$r = pg_query($readOnlyReplicaConn, $q);
while ($f=pg_fetch_row($r)) {
singapore_bus_stops_line($f[0]);
}
echo "[".date("Y-m-d H:i:s")."] GPS singaport_mrtlrt_stop_fares job complete.\n";
function singapore_bus_stops_line($id) {
global $readOnlyReplicaConn;
$q = "SELECT * FROM singapore_bus_stops WHERE line='${id}'";
$r = pg_query($readOnlyReplicaConn,$q);
while ($from=pg_fetch_assoc($r)) {
singapore_bus_stops_line_fares($id,$from);
}
}
function singapore_bus_stops_line_fares($id,$from) {
global $readOnlyReplicaConn;
$q = "SELECT * FROM singapore_bus_stops WHERE line='${id}' AND id<>".$from["id"]." ORDER BY RANDOM()";
$r = pg_query($readOnlyReplicaConn,$q);
while ($to=pg_fetch_assoc($r)) {
singapore_bus_stops_line_fare($id,$from,$to);
}
}
/*
CREATE TABLE singapore_bus_stop_fares (id serial, boarding_id int references singapore_bus_stops(id), alight_id int references singapore_bus_stops(id), fare int, distance int, primary key(id), unique(boarding_id,alight_id));
*/
function singapore_bus_stops_line_fare($line,$from,$to) {
global $conn, $readOnlyReplicaConn;
echo "from=".$from["code"].", to=".$to["code"]."\n";
$q = "SELECT * FROM singapore_bus_stop_fares WHERE boarding_id='".$from["id"]."'";
$q.= " AND alight_id='".$to["id"]."'";
$r = pg_query($readOnlyReplicaConn,$q);
if ($r && pg_num_rows($r) && $f=pg_fetch_assoc($r)) {
// Update
if ($f["fare"]>0) {
$q = "";
} else {
$q = "UPDATE singapore_bus_stop_fares SET fare=%d, distance=%d WHERE id=".$f["id"]." RETURNING id";
}
} else {
// Insert
$q = "INSERT INTO singapore_bus_stop_fares (boarding_id,alight_id,fare,distance) VALUES(";
$q.= $from["id"].",".$to["id"].",%d,%d) RETURNING id";
}
if ($q!="") {
$entryId = $from["code"];
$exitId = $to["code"];
list($res, $err) = getMyTransportSGQuote($line,$entryId,$exitId);
if (is_array($res) && array_key_exists('data',$res) && is_array($res['data']) && array_key_exists('fare_raw',$res['data']) && $res['data']['fare_raw']>0) {
$fare_raw = $res['data']['fare_raw'];
$distance = $res['data']['distance_raw'] * 10;
echo "--> ${fare_raw} (".$res['data']['distance']." => ${distance})\n";
$q = sprintf($q, $fare_raw, $distance);
//echo "$q\n";
$r = pg_query($conn, $q);
if ($r && pg_num_rows($r) && $f=pg_fetch_row($r)) {
echo "--> success: id=".$f[0]."\n";
} else {
echo "--> failure: ".pg_last_error($conn)."\n";
}
//var_dump($res);
//var_dump($err);
} else {
echo "ERROR: $err\n";
}
}
}
function getMyTransportSGQuote($line,$entryId,$exitId) {
$url = 'https://www.mytransport.sg/content/mytransport/home/commuting/busservices/jcr:content/par/mtp_generic_tab/mtp_generic_tab6/distancefare.busFare?busServiceId='.$line.'&entryMarkerId='.$entryId.'&exitMarkerId='.$exitId.'&ticketType=30&tripContextParameter=&tripId=1';
$ch = curl_init($url);
//Create And Save Cookies
/*
$tmpfname = dirname(__FILE__).'/cookie.txt';
curl_setopt($ch, CURLOPT_COOKIEJAR, $tmpfname);
curl_setopt($ch, CURLOPT_COOKIEFILE, $tmpfname);
*/
/*
Host: www.mytransport.sg
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:68.0) Gecko/20100101 Firefox/68.0
Accept: *//*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: https://www.mytransport.sg/content/mytransport/home/commuting/busservices.html
X-Requested-With: XMLHttpRequest
Connection: keep-alive
Cookie: mtp_last_visit=Fare Calculator|/content/mytransport/home/commuting/busservices.html#Fare_Calculator,Bus Arrival Time|/content/mytransport/home/commuting/busservices.html#Bus_Arrival_Time,Bus Services|/content/mytransport/home/commuting/busservices.html; s_fid=1A0D8455C75F0629-03AFA1ACC259519D; s_cc=true
*/
$cookies = 'mtp_last_visit=Fare Calculator|/content/mytransport/home/commuting/busservices.html#Fare_Calculator,Bus Arrival Time|/content/mytransport/home/commuting/busservices.html#Bus_Arrival_Time,Bus Services|/content/mytransport/home/commuting/busservices.html; s_fid=1A0D8455C75F0629-03AFA1ACC259519D; s_cc=true';
//'mtp_last_visit=Fare Calculator|/content/mytransport/home/commuting/busservices.html#Fare_Calculator,Bus Services|/content/mytransport/home/commuting/busservices.html';
$headers = [
'Accept: */*',
'Accept-Language: en-US,en;q=0.5',
'X-Requested-With: XMLHttpRequest',
'Accept-Encoding: gzip, deflate, br'
];
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
//curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_AUTOREFERER, true);
curl_setopt($ch, CURLOPT_REFERER, 'https://www.mytransport.sg/content/mytransport/home/commuting/busservices.html');
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:68.0) Gecko/20100101 Firefox/68.0');
//curl_setopt($ch, CURLINFO_HEADER_OUT, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
curl_setopt($ch, CURLOPT_COOKIE, $cookies);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
//https://stackoverflow.com/questions/310650/decode-gzipped-web-page-retrieved-via-curl-in-php
curl_setopt($ch, CURLOPT_ENCODING , "gzip");
// EXECUTE
sleep(1);
$html = curl_exec($ch);
//error_log($url);
//error_log($html);
//echo trim($html);
curl_close($ch);
$dom = new DOMDocument;
libxml_use_internal_errors(true);
$dom->loadHTML(trim($html));
$finder = new DomXPath($dom);
// distance_fare_result_nm => Trip 1
// distance_fare_result_sv => Bus Svc 41
// distance_fare_result_bd => 28641 - Blk 284
// distance_fare_result_al => 42209 - Aft Toh Tuck Rise
// distance_fare_result_dt => 7.7 km
// distance_fare_result_fr => $1.29
// fare_raw => 129
// distance_raw => 770
$data = array(
'name' => getItem($finder,'distance_fare_result_nm'),
'service' => getItem($finder,'distance_fare_result_sv'),
'board' => getItem($finder,'distance_fare_result_bd'),
'alight' => getItem($finder,'distance_fare_result_al'),
'distance' => getItem($finder,'distance_fare_result_dt'),
'fare' => getItem($finder,'distance_fare_result_fr'),
'fare_raw' => getItem($finder,'fare_raw'),
'distance_raw' => getItem($finder,'distance_raw')
);
return [['data'=>$data],$html];
}
function getItem($finder,$class,$default='') {
$nlist = $finder->query("//*[@class='${class}']");
if ($nlist->length>0) {
$item = $nlist->item(0);
return $item->textContent;
}
return $default;
}
+158
View File
@@ -0,0 +1,158 @@
<?php
echo "[".date("Y-m-d H:i:s")."] GPS singaport_mrtlrt_stop_fares job is starting.\n";
require('../backend.php');
$httpAuthToken = $savvyext->cfgReadChar('system.oauth2_token');
$db_host = $savvyext->cfgReadChar('database.host');
$db_name = $savvyext->cfgReadChar('database.name');
$db_user = $savvyext->cfgReadChar('database.user');
$db_pass = $savvyext->cfgReadChar('database.pass');
$db_port = $savvyext->cfgReadLong('database.port');
$connstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$conn = pg_connect($connstr);
$db_host = $savvyext->cfgReadChar('database_replica.host');
$db_name = $savvyext->cfgReadChar('database_replica.name');
$db_user = $savvyext->cfgReadChar('database_replica.user');
$db_pass = $savvyext->cfgReadChar('database_replica.pass');
$db_port = $savvyext->cfgReadLong('database_replica.port');
$readOnlyReplicaConnstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$readOnlyReplicaConn = pg_connect($readOnlyReplicaConnstr);
$q = "SELECT * FROM singapore_mrtlrt_stops_mytransport ORDER BY RANDOM()";
$r = pg_query($readOnlyReplicaConn, $q);
while ($f=pg_fetch_assoc($r)) {
singapore_mrtlrt_stop_fares($f);
}
echo "[".date("Y-m-d H:i:s")."] GPS singaport_mrtlrt_stop_fares job complete.\n";
function singapore_mrtlrt_stop_fares($from) {
global $readOnlyReplicaConn;
$q = "SELECT * FROM singapore_mrtlrt_stops_mytransport WHERE id<>".$from["id"]." ORDER BY RANDOM()";
$r = pg_query($readOnlyReplicaConn,$q);
while ($to=pg_fetch_assoc($r)) {
singapore_mrtlrt_stop_fare($from,$to);
}
}
function singapore_mrtlrt_stop_fare($from,$to) {
global $conn, $readOnlyReplicaConn;
echo "from=".$from["code1"]."_".$from["code2"].", to=".$to["code1"]."_".$to["code2"]."\n";
$q = "SELECT * FROM singapore_mrtlrt_stop_fares WHERE boarding_id='".$from["id"]."'";
$q.= " AND alight_id='".$to["id"]."'";
$r = pg_query($readOnlyReplicaConn,$q);
if ($r && pg_num_rows($r) && $f=pg_fetch_assoc($r)) {
// Update
if ($f["fare"]>0) {
$q = "";
} else {
$q = "UPDATE singapore_mrtlrt_stop_fares SET fare=%d, distance=%d WHERE id=".$f["id"]." RETURNING id";
}
} else {
// Insert
$q = "INSERT INTO singapore_mrtlrt_stop_fares (boarding_id,alight_id,fare,distance) VALUES(";
$q.= $from["id"].",".$to["id"].",%d,%d) RETURNING id";
}
if ($q!="") {
$entryId = $from["code1"] . "_" . $from["code2"];
$exitId = $to["code1"] . "_" . $to["code2"];
list($res, $err) = getMyTransportSGQuote($entryId,$exitId);
if (is_array($res) && array_key_exists('data',$res) && is_array($res['data']) && array_key_exists('fare_raw',$res['data']) && $res['data']['fare_raw']>0) {
$fare_raw = $res['data']['fare_raw'];
$distance = $res['data']['distance_raw'] * 10;
echo "--> ${fare_raw} (".$res['data']['distance']." => ${distance})\n";
$q = sprintf($q, $fare_raw, $distance);
//echo "$q\n";
$r = pg_query($conn, $q);
if ($r && pg_num_rows($r) && $f=pg_fetch_row($r)) {
echo "--> success: id=".$f[0]."\n";
} else {
echo "--> failure: ".pg_last_error($conn)."\n";
}
} else {
echo "ERROR: $err\n";
}
}
}
function getMyTransportSGQuote($entryId,$exitId) {
$url = 'https://www.mytransport.sg/content/mytransport/home/commuting/busservices/jcr:content/par/mtp_generic_tab/mtp_generic_tab6/distancefare.mrtFare?entryMarkerId='.$entryId.'&exitMarkerId='.$exitId.'&ticketType=30&tripContextParameter=&tripId=1';
$ch = curl_init($url);
//Create And Save Cookies
/*
$tmpfname = dirname(__FILE__).'/cookie.txt';
curl_setopt($ch, CURLOPT_COOKIEJAR, $tmpfname);
curl_setopt($ch, CURLOPT_COOKIEFILE, $tmpfname);
*/
$cookies = 'mtp_last_visit=Fare Calculator|/content/mytransport/home/commuting/busservices.html#Fare_Calculator,Bus Services|/content/mytransport/home/commuting/busservices.html';
$headers = [
'X-Requested-With: XMLHttpRequest',
'Sec-Fetch-Mode: cors',
'Sec-Fetch-Site: same-origin'
];
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
//curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_AUTOREFERER, true);
curl_setopt($ch, CURLOPT_REFERER, 'https://www.mytransport.sg/content/mytransport/home/commuting/busservices.html');
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36');
//curl_setopt($ch, CURLINFO_HEADER_OUT, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
curl_setopt($ch, CURLOPT_COOKIE, $cookies);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
//https://stackoverflow.com/questions/310650/decode-gzipped-web-page-retrieved-via-curl-in-php
curl_setopt($ch, CURLOPT_ENCODING , "gzip");
// EXECUTE
sleep(1);
$html = curl_exec($ch);
//error_log($url);
//error_log($html);
//echo trim($html);
curl_close($ch);
$dom = new DOMDocument;
libxml_use_internal_errors(true);
$dom->loadHTML(trim($html));
$finder = new DomXPath($dom);
// distance_fare_result_nm => Trip 1
// distance_fare_result_sv => Bus Svc 41
// distance_fare_result_bd => 28641 - Blk 284
// distance_fare_result_al => 42209 - Aft Toh Tuck Rise
// distance_fare_result_dt => 7.7 km
// distance_fare_result_fr => $1.29
// fare_raw => 129
// distance_raw => 770
$data = array(
'name' => getItem($finder,'distance_fare_result_nm'),
'service' => getItem($finder,'distance_fare_result_sv'),
'board' => getItem($finder,'distance_fare_result_bd'),
'alight' => getItem($finder,'distance_fare_result_al'),
'distance' => getItem($finder,'distance_fare_result_dt'),
'fare' => getItem($finder,'distance_fare_result_fr'),
'fare_raw' => getItem($finder,'fare_raw'),
'distance_raw' => getItem($finder,'distance_raw')
);
return [['data'=>$data],$html];
}
function getItem($finder,$class,$default='') {
$nlist = $finder->query("//*[@class='${class}']");
if ($nlist->length>0) {
$item = $nlist->item(0);
return $item->textContent;
}
return $default;
}
+257
View File
@@ -0,0 +1,257 @@
<?php
// require_once( '/Users/osx/Sites/Float/adminsavvy/backend.php' );
include '../backend.php';
require_once( 'common/Logger.php' );
/**
* Transfer Subscription Report
*/
class SubscribedSummary {
public $conn;
public $repConn;
protected $hard_limit = 550;
function __construct() {
global $savvyext;
$this->conn = self::__cnn( $savvyext );
$this->repConn = self::__repCnn( $savvyext );
}
private static function __cnn( $savvyext ) {
$db_host = $savvyext->cfgReadChar('database.host');
$db_name = $savvyext->cfgReadChar('database.name');
$db_user = $savvyext->cfgReadChar('database.user');
$db_pass = $savvyext->cfgReadChar('database.pass');
$db_port = $savvyext->cfgReadLong('database.port');
$connstr = sprintf( 'host=%s port=%s dbname=%s user=%s password=%s', $db_host, $db_port, $db_name, $db_user, $db_pass );
$conn = pg_connect($connstr);
return $conn;
}
private static function __repCnn( $savvyext ) {
$db_host = $savvyext->cfgReadChar('database_replica.host');
$db_name = $savvyext->cfgReadChar('database_replica.name');
$db_user = $savvyext->cfgReadChar('database_replica.user');
$db_pass = $savvyext->cfgReadChar('database_replica.pass');
$db_port = $savvyext->cfgReadLong('database_replica.port');
$connstr = sprintf( 'host=%s port=%s dbname=%s user=%s password=%s', $db_host, $db_port, $db_name, $db_user, $db_pass );
$conn = pg_connect($connstr);
return $conn;
}
/**
* Get all members_card_assign items
* @return array
*/
public function getDeals() {
try {
// get all deals card
$sql = sprintf( "
SELECT
mc.id as cardid,
case when mc.card_country is null then 'Worldwide' else mc.card_country end as country
from main_cards mc
where mc.button1_action in ('GOOFFERS')
and mc.status = 1
" );
$results = pg_query( $this->repConn, $sql );
if ( $error = pg_last_error( $this->repConn ) ) {
throw new Exception( $error );
}
$results = pg_fetch_all( $results );
return $results;
} catch (Exception $e) {
Logger::debug( $e->getMessage() );
}
}
/**
* Get total redeem by cards
* @param array $card_ids list card ids
* @return array
*/
private function getRedeem( $card_ids ) {
$redeem = sprintf("
SELECT
mca.card_id as cardid,
count( mca ) as redeem
from members_card_assign mca
left join main_cards mc ON mc.id = mca.card_id
where
mca.completed is not null
and mca.status = 1
and mca.card_id in (%s)
group by cardid
", $card_ids);
$results = pg_query( $this->repConn, $redeem );
if ( $error = pg_last_error( $this->repConn ) ) {
throw new Exception( $error );
}
$redeem = pg_fetch_all( $results );
return $redeem;
}
/**
* Get total report
* @param array $card_ids list card ids
* @return array
*/
private function getReport( $card_ids ) {
$report = sprintf( "
SELECT
mca.card_id as cardid,
sum( case when mca.added between now() - interval '24 hours' and now() then 1 else 0 end ) as last_24hours,
sum( case when mca.added between now() - interval '7 days' and now() then 1 else 0 end ) as last_7days,
sum( case when mca.added between now() - interval '14 days' and now() then 1 else 0 end ) as last_14days,
sum( case when mca.added between now() - interval '30 days' and now() then 1 else 0 end ) as last_30days,
count( mca.id ) as total_sub
from members_card_assign mca
left join main_cards mc ON mc.id = mca.card_id
where
mc.card_reciept is not null
and mca.subscribe is not null
and mca.completed is null
and mca.reciept_count = 0
and mca.card_id in (%s)
group by cardid
", $card_ids );
$results = pg_query( $this->repConn, $report );
if ( $error = pg_last_error( $this->repConn ) ) {
throw new Exception( $error );
}
$report = pg_fetch_all( $results );
return $report;
}
/**
* Get all subscribed report
* @return array
*/
public function getSubscripbed() {
$deals = $this->getDeals();
try {
if ( !$deals ) {
throw new Exception( 'Deals card not found!' );
}
$card_ids = implode( ', ', array_column( $deals, 'cardid' ) );
// get subscribed total redeem
$redeem = $this->getRedeem( $card_ids );
// get subscribed report
$report = $this->getReport( $card_ids );
// combine report and redeem
if ( $report ) {
foreach ( $report as $key => $value ) {
$report[ $key ]['total_redeem'] = 0;
if ( $redeem ) {
foreach ( $redeem as $subkey => $subvalue ) {
if ( $subvalue['cardid'] == $value['cardid'] ) {
$report[ $key ]['total_redeem'] = $subvalue['redeem'];
}
}
}
}
$results = array();
array_walk( $report, function( $value, $key ) use (&$results) {
$results[ $value['cardid'] ] = $value;
} );
foreach ( $deals as $key => $value ) {
$cardid = $value['cardid'];
$deals[ $key ]['last_24hours'] = isset( $results[ $cardid ] ) ? $results[ $cardid ]['last_24hours'] : 0;
$deals[ $key ]['last_7days'] = isset( $results[ $cardid ] ) ? $results[ $cardid ]['last_7days'] : 0;
$deals[ $key ]['last_14days'] = isset( $results[ $cardid ] ) ? $results[ $cardid ]['last_14days'] : 0;
$deals[ $key ]['last_30days'] = isset( $results[ $cardid ] ) ? $results[ $cardid ]['last_30days'] : 0;
$deals[ $key ]['total_sub'] = isset( $results[ $cardid ] ) ? $results[ $cardid ]['total_sub'] : 0;
$deals[ $key ]['total_redeem'] = isset( $results[ $cardid ] ) ? $results[ $cardid ]['total_redeem'] : 0;
}
}
return $deals;
} catch (Exception $e) {
Logger::debug( $e->getMessage() );
}
}
/**
* Update report after get all subscribed
* @return mixed
*/
public function updateSubscribedReport() {
$results = $this->getSubscripbed();
try {
if ( !$results ) {
throw new Exception( 'Subscribed not found!' );
}
$table_columns = array(
'card_id',
'country',
'last_24hours',
'last_7days',
'last_14days',
'last_30days',
'total_sub',
'total_redeem'
);
$table_results = array();
array_filter( $results, function( $var ) use ( &$table_results ) {
$content = array();
array_walk( $var, function( $value, $key ) use ( &$content ) {
$value = $value ?? 0;
array_push( $content, $value );
} );
$table_results[] = sprintf( '(%s)', implode( ', ', $content ) );
} );
$sql = sprintf( "
begin;
truncate table subscription_summary;
insert into subscription_summary (%s)
values %s;
commit;
rollback;
",
// insert
implode( ', ', $table_columns ),
preg_replace( '/([a-zA-Z]+)/m', '\'$0\'', implode( ', ', $table_results ) ) );
$results = pg_query( $this->conn, $sql );
if ( $error = pg_last_error( $this->repConn ) ) {
throw new Exception( $error );
}
return 'success';
} catch (Exception $e) {
Logger::debug( $e->getMessage() );
}
}
}
echo "[" . date("Y-m-d H:i:s") . "] subscribed_summary job is starting.\n";
$instance = new SubscribedSummary();
// $instance->getSubscripbed();
echo $instance->updateSubscribedReport() . PHP_EOL;
echo "[" . date("Y-m-d H:i:s") . "] subscribed_summary job is ending.\n";
+26
View File
@@ -0,0 +1,26 @@
<?php
echo "[".date("Y-m-d H:i:s")."] Account Audit job is starting.\n";
include '../backend.php';
define("FLOAT_SYSTEM_ACCOUNT_AUDIT", 92015);
function Fextension_call($in, &$out) {
// logToFl("Merchant_Name count->" . $in["merchant_name"]);
global $savvyext;
$out = $savvyext->savvyext_api($in);
$ret = $out["retval"];
return $ret;
}
$inX["member_id"] = 13;
$inX["pid"] = 0;
$inX["action"] = 999999999; // DEBUG
$outX=array();
$extension_call = true;
if ($extension_call == true ) {
// logToFl("merchant_name count->" . $res->merchant_name);
$ret = Fextension_call($inX, $outX);
}
+36
View File
@@ -0,0 +1,36 @@
<?php
$job_name ='parsedemail_item_fix_missing email';
echo "[" . date("Y-m-d H:i:s") . "] ".$job_name." job is starting.\n";
require 'common/utils.php';
require 'common/config.php';
require 'common/address_city.php';
require 'common/parser.php';
require 'common/Geocode.php';
$total = $success = $failed = 0;
$path = "/Users/admin/Work/FloatAdmin/adminsavvy/data/receipts/";
$prefix = "grab_";
$condition =" subject ilike '%your grab e-receipt%' and message_from ilike '%grab%' ";
$prefix = "uber_";
$condition =" subject ilike '%trip with uber%' OR subject ilike '%trip receipt%' OR subject ilike '%took an uber trip on%'";
$prefix = "gojek_";
$condition =" subject ilike '%your trip with gojek%' and message_from ilike '%go-jek%' ";
/* $prefix = "comfortdelgro_";
$condition =" subject ilike '%comfortdelgro taxi e-receipt%'";
$condition =" subject ilike '%your trip with gojek%'";
$prefix = "lyft_";
$condition =" subject ilike '%your ride with%'"; */
$q="SELECT DISTINCT ON (to_char(message_date,'YYYY-MM')) message, (to_char(message_date,'YYYY-MM')) as monthyear FROM trackedemail_item
WHERE ".$condition." AND message_date is not null
ORDER by monthyear DESC";
$r = pg_query($conn, $q);
while ($f = pg_fetch_assoc($r)) {
$total++;
$message = $f['message'];
$monthyear = $f['monthyear'];
$file_name = $path.$prefix.$monthyear.".html";
file_put_contents($file_name, $message);
}
echo "[" . date("Y-m-d H:i:s") . "] ".$job_name." job complete.\n";
+39
View File
@@ -0,0 +1,39 @@
<?php
$job_name ='parsedemail_item_fix_missing email';
echo "[" . date("Y-m-d H:i:s") . "] ".$job_name." job is starting.\n";
require 'common/utils.php';
require 'common/config.php';
require 'common/address_city.php';
require 'common/parser.php';
require 'common/Geocode.php';
$total = $success = $failed = 0;
$q = "SELECT id FROM trackedemail_item WHERE id NOT IN (SELECT trackedemail_item_id FROM parsedemail_item_payment) ORDER BY id DESC;";
$q="select id from trackedemail_item where id not in (select trackedemail_item_id from parsedemail_item p INNER JOIN trackedemail_item t on p.trackedemail_item_id=t.id WHERE member_id=347) AND member_id=347 order by id desc;";
$r = pg_query($conn, $q);
while ($f = pg_fetch_assoc($r)) {
$total++;
$email_id = $f['id'];
if (!empty($email_id)) {
$data = parseEmail($email_id);
if ( isset( $data['parsed_status'] ) && $data['parsed_status']==1 ) {
echo "[" . date("Y-m-d H:i:s") . "] email id: ".$email_id." is success.\n";
$success++;
}else{
echo "[" . date("Y-m-d H:i:s") . "] email id: ".$email_id." is failed.\n";
$failed++;
}
} else {
echo "[" . date("Y-m-d H:i:s") . "] email id: ".$email_id." is failed.\n";
$failed++;
}
}
echo "Total: " . $total . ".\n";
echo "Success: : " . $success . ".\n";
echo "Failed: : " . $failed . ".\n";
echo "[" . date("Y-m-d H:i:s") . "] ".$job_name." job complete.\n";
+318
View File
@@ -0,0 +1,318 @@
<?php
define('TRANSACTION_REMOVED', 'removed');
$job_name = pathinfo(__FILE__, PATHINFO_FILENAME);
echo "[" . date("Y-m-d H:i:s") . "] " . $job_name . " job is starting.\n";
include '../backend.php';
require_once('./lock.php');
require_once('./common/Logger.php');
$db_host = $savvyext->cfgReadChar('database.host');
$db_name = $savvyext->cfgReadChar('database.name');
$db_user = $savvyext->cfgReadChar('database.user');
$db_pass = $savvyext->cfgReadChar('database.pass');
$db_port = $savvyext->cfgReadLong('database.port');
$connstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$con = pg_connect($connstr) or die("Could not connect to server\n");
$db_host = $savvyext->cfgReadChar('database_replica.host');
$db_name = $savvyext->cfgReadChar('database_replica.name');
$db_user = $savvyext->cfgReadChar('database_replica.user');
$db_pass = $savvyext->cfgReadChar('database_replica.pass');
$db_port = $savvyext->cfgReadLong('database_replica.port');
$readOnlyReplicaConnstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$readOnlyReplicaConn = pg_connect($readOnlyReplicaConnstr);
if($readOnlyReplicaConn === FALSE){
$readOnlyReplicaConn = $con;
}
if ($con === FALSE || $readOnlyReplicaConn === FALSE) {
unlock_pid_file($lock_file);
die("Could not connect to server\n");
}
function execute($inX = [])
{
$outX = [];
// get transaction list
fetch_bank_transactions($inX, $outX);
if ($outX['count']) {
$response = $outX['results'];
remove_transaction($response);
// the rest of tranactions
$import_transactions = array_filter($response, function ($ele) {
return $ele['tstatus'] !== TRANSACTION_REMOVED;
});
update_transaction($import_transactions, $imported_ids);
insert_transaction($import_transactions, $imported_ids);
}
if (!empty($outX['next'])) {
parse_str(parse_url($outX['next'], PHP_URL_QUERY), $inX);
execute($inX);
} else {
return;
}
}
function generate_params($data) {
$value = [];
foreach ($data as $element) {
$value[] = [
'import_id' => $element['id'],
'account' => $element['account'],
'member_id' => $element['member_id'],
'amount' => $element['amount'],
'currency' => $element['currency'],
'status' => $element['status'],
'tstatus' => $element['tstatus'],
'description' => $element['description'],
'time' => $element['time'],
'category' => $element['category'],
'provider_category' => $element['provider_category'],
'merchant_provider_id' => $element['merchant_provider_id'],
'merchant_name' => $element['merchant_name'],
'extra' => json_encode($element['extra'])
];
}
return $value;
}
function fetch_bank_transactions($in, &$out) {
global $savvyext;
$target_url = str_replace("'", "", $savvyext->cfgReadChar('microservices.account'))
. "/api/v1/transactions/get_raw_transactions";
$target_url = $target_url . "/?" . http_build_query($in);
//open connection
$ch = curl_init();
//set the url, number of POST vars, POST data
curl_setopt($ch, CURLOPT_URL, $target_url);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'Connection: Keep-Alive',
'Authorization: Server-Token ' . $savvyext->cfgReadChar('system.bank_token'),
'Accept: application/json'
));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_FAILONERROR, true);
//execute post
$result = curl_exec($ch);
if (curl_errno($ch)) {
$error_msg = curl_error($ch);
}
//close connection
curl_close($ch);
if (isset($error_msg)) {
Logger::debug('transactions_record_import fetch_bank_transactions error:');
Logger::debug($error_msg);
}
$out = json_decode($result, true);
}
function get_import_id_list_in_table($import_ids) {
global $readOnlyReplicaConn;
$query =
'SELECT import_id
FROM members_transactions_import_raw
WHERE import_id IN (' . implode(',', $import_ids) . ')';
$result = pg_query($readOnlyReplicaConn, $query);
$imported_ids = [];
if ($result && pg_num_rows($result)) {
while ($row = pg_fetch_row($result)) {
$imported_ids[] = $row[0];
}
}
return $imported_ids;
}
function delete_tranasction($remove_ids) {
global $con;
$query = 'DELETE FROM members_transactions_import_raw
WHERE import_id IN (' . implode(',', $remove_ids) . ')';
if (!pg_query($con, $query)) {
echo pg_last_error();
Logger::debug('transactions_record_import delete_tranasction error:');
Logger::debug(pg_last_error());
return false;
}
return true;
}
function mark_transaction_as_imported($id) {
global $savvyext;
$target_url = str_replace("'", "", $savvyext->cfgReadChar('microservices.account'))
. "/api/v1/transactions/{$id}/";
//open connection
$ch = curl_init();
//set the url, number of POST vars, POST data
curl_setopt($ch, CURLOPT_URL, $target_url);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(
['points_imported' => date('Y-m-d\TH:i:s.Z\Z', time())]
));
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'Connection: Keep-Alive',
'Authorization: Server-Token ' . $savvyext->cfgReadChar('system.bank_token'),
'Accept: application/json'
));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_FAILONERROR, true);
//execute post
$result = curl_exec($ch);
if (curl_errno($ch)) {
$error_msg = curl_error($ch);
}
//close connection
curl_close($ch);
if (isset($error_msg)) {
Logger::debug('transactions_record_import mark_transaction_as_imported error:');
Logger::debug($error_msg);
}
$out = json_decode($result, true);
if (isset($out['error'])) echo implode("\n",$out['non_field_errors']);
}
function remove_transaction($data) {
// transactions removed
$remove_ids = array_column(array_filter($data, function ($ele) {
return $ele['tstatus'] === TRANSACTION_REMOVED;
}), 'id');
if ($remove_ids && delete_tranasction($remove_ids)) {
foreach ($remove_ids as $id) {
mark_transaction_as_imported($id);
}
}
}
function update_transaction($data, &$imported_ids) {
global $con;
// get transactions imported
$imported_ids = get_import_id_list_in_table(array_column($data, 'id'));
if ($imported_ids) {
$imported_transactions = array_filter($data, function ($ele) use ($imported_ids) {
return in_array($ele['id'], $imported_ids);
});
$params_update = generate_params($imported_transactions);
foreach ($params_update as $val) {
$rs = pg_query_params($con,
"UPDATE members_transactions_import_raw
SET
account = $2,
member_id = $3,
amount = $4,
currency = $5,
status = $6,
tstatus = $7,
description = $8,
time = $9,
category = $10,
provider_category = $11,
merchant_provider_id = $12,
merchant_name = $13,
extra = $14
WHERE import_id = $1
",
$val
);
if (!$rs) {
echo pg_last_error();
Logger::debug('transactions_record_import update_transaction error:');
Logger::debug(pg_last_error());
} else {
mark_transaction_as_imported($val['import_id']);
}
}
}
}
function insert_transaction($data, $imported_ids) {
global $con;
// get the transactions not importedimported_ids
$import_transactions = array_filter($data, function ($ele) use ($imported_ids) {
return !in_array($ele['id'], $imported_ids);
});
$params_insert = generate_params($import_transactions);
foreach ($params_insert as $val) {
$rs = pg_query_params($con,
"INSERT INTO members_transactions_import_raw
(
import_id,
account,
member_id,
amount,
currency,
status,
tstatus,
description,
time,
category,
provider_category,
merchant_provider_id,
merchant_name,
extra
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)
ON CONFLICT(import_id) DO NOTHING",
$val
);
if (!$rs) {
echo "Cannot execute query with import id:" . $val['id']; // import_id
Logger::debug('transactions_record_import insert_transaction error:');
Logger::debug(pg_last_error());
} else {
mark_transaction_as_imported($val['import_id']);
}
}
}
$lock_file = lock_pid_file();
execute();
unlock_pid_file($lock_file);
echo "[" . date("Y-m-d H:i:s") . "] " . $job_name . " job complete.\n";
@@ -0,0 +1,49 @@
<?php
/**
* documentation: https://docs.google.com/document/d/19tMnCzGgUF5UT__0AhbptLnCbBBVxX6uA4a_S0M4lFg/edit#
* Following up this model: https://drive.google.com/file/d/1iXlHDA4gD8UgFBBNGPeP6ypgN2YlLc9n/view
*/
echo "[" . date("Y-m-d H:i:s") . "] GPS trips job is starting.\n";
require __DIR__ . '/../../backend.php';
$db_host = $savvyext->cfgReadChar('gpsdatabase.host');
$db_name = $savvyext->cfgReadChar('gpsdatabase.name');
$db_user = $savvyext->cfgReadChar('gpsdatabase.user');
$db_pass = $savvyext->cfgReadChar('gpsdatabase.pass');
$db_port = $savvyext->cfgReadLong('gpsdatabase.port');
$gpsconnstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$gpsconn = pg_connect($gpsconnstr);
$gmclient = new GearmanClient();
$gmclient->addServer('127.0.0.1', 4730);
$q = "SELECT member_id, count(*) as count FROM members_tracking ";
$q .= "GROUP BY member_id";
$r = pg_query($gpsconn, $q);
if (!$r) {
echo pg_last_error($gpsconn);
}
if ($r && pg_num_rows($r) > 0) {
while ($row = pg_fetch_object($r)) {
$member_id = $row->member_id;
echo "[" . date("Y-m-d H:i:s") . "] Processing member_id = $member_id (total member records: $row->count )\n";
// dispatch jobs
echo "[" . date("Y-m-d H:i:s") . "] Dispatching jobs (member_id = $member_id) to gps_trips_worker.\n";
$gmclient->doBackground('gps_trips_worker', $member_id);
}
}
if ($gmclient->returnCode() != GEARMAN_SUCCESS) {
echo "bad return code\n";
exit;
}
pg_close($gpsconn);
echo "[" . date("Y-m-d H:i:s") . "] GPS trips job complete.\n";
@@ -0,0 +1,9 @@
[program:gps_trips_worker]
command=/usr/bin/php /home/savvy/FloatAdmin/adminsavvy/CRONS/transportation_mode_detection/gps_trips_worker.php
process_name=%(program_name)s_%(process_num)s
autostart=true
autorestart=true
numprocs=5
#add this setting to log error
stderr_logfile=/var/log/supervisor/%(program_name)s_p%(process_num)s.err.log
stdout_logfile=/var/log/supervisor/%(program_name)s_p%(process_num)s.out.log
@@ -0,0 +1,589 @@
<?php
/**
* documentation: https://docs.google.com/document/d/19tMnCzGgUF5UT__0AhbptLnCbBBVxX6uA4a_S0M4lFg/edit#
* Following up this model: https://drive.google.com/file/d/1iXlHDA4gD8UgFBBNGPeP6ypgN2YlLc9n/view
*/
echo "[" . date("Y-m-d H:i:s") . "] GPS trips job is starting.\n";
require __DIR__ . '/../../backend.php';
/***** connect database *****/
$db_host = $savvyext->cfgReadChar('gpsdatabase.host');
$db_name = $savvyext->cfgReadChar('gpsdatabase.name');
$db_user = $savvyext->cfgReadChar('gpsdatabase.user');
$db_pass = $savvyext->cfgReadChar('gpsdatabase.pass');
$db_port = $savvyext->cfgReadLong('gpsdatabase.port');
$gpsconnstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
$gpsconn = pg_connect($gpsconnstr);
/***** load configuration *****/
$httpAuthToken = $savvyext->cfgReadChar('system.oauth2_token');
$encryptionAlg = $savvyext->cfgReadChar('encryption.algorithm');
$encryptionKey = $savvyext->cfgReadChar('encryption.key');
$encryptionIV = $savvyext->cfgReadChar('encryption.iv');
$baseURL = $savvyext->cfgReadChar('system.api_url');
$googleApiKey = $savvyext->cfgReadChar('google.api_key');
/***** definition *****/
define('STOPPED', 'stopped');
define('WALKING', 'walking');
define('DRIVING_AND_PUBLIC_TRANSPORT', 'driving_and_public_tranport');
define('UNKNOWN', 'unknown');
$segment_duration_limit = 1; // min
$trip_limit = 20;
$needed_trip_limit = 18;
// km/h
$walking_low_avg_speed = 3;
$walking_high_avg_speed = 10;
$low_avg_speed = 10;
$high_avg_speed = 160;
/***** start worker to process a job *****/
$worker = new GearmanWorker();
$worker->addServer('127.0.0.1', 4730);
$worker->addFunction('gps_trips_worker', function (GearmanJob $job) {
$member_id = $job->workload();
processMemberGPSTrips($member_id);
echo "Waiting for job...\n";
});
while ($worker->work()) {
if ($worker->returnCode() != GEARMAN_SUCCESS) {
echo "return_code: " . $worker->returnCode() . "\n";
break;
}
}
pg_close($gpsconn);
echo "[" . date("Y-m-d H:i:s") . "] GPS trips job complete.\n";
/********************* Functions *********************/
function processMemberGPSTrips(int $member_id)
{
global $gpsconn, $high_avg_speed, $segment_duration_limit, $trip_limit;
$lastProcessedDatetime = getLastProcessedDatetime($member_id);
if ($lastProcessedDatetime === NULL) {
echo 'There something wrong with member_id = '.$member_id;
return;
}
$whereQuery = '';
if ($lastProcessedDatetime !== '') {
$whereQuery .= " AND ttime > '" . $lastProcessedDatetime . "' ";
}
// and take the data not newer than 24 hrs
$track_query = " SELECT
id as members_tracking_id,
member_id,
lat,
lng,
ttime as time
FROM
members_tracking
WHERE
member_id = $member_id
AND ttime <= (now() - INTERVAL '24 HOURS')
" . $whereQuery . "
ORDER BY
ttime ASC
";
$track_res = pg_query($gpsconn, $track_query);
if (!$track_res) {
echo pg_last_error($gpsconn);
}
if ($track_res && pg_num_rows($track_res) > 0) {
$first_data = NULL;
$last_data = NULL;
$dataset = [];
$rowCount = 0;
$i = 0;
$tripStartIndex = 'NONE';
echo "[" . date("Y-m-d H:i:s") . "] Processing member_id=" . $member_id . " . Waiting for a moment.\n";
while ($row = pg_fetch_array($track_res)) {
if ($first_data === NULL) {
$first_data = $row;
}
$last_data = $row;
$avg_speed_data = calculateAvgSpeed($first_data, $last_data);
$trip_segment = [
'members_tracking_id' => $last_data['members_tracking_id'],
'member_id' => $last_data['member_id'],
'lat' => $last_data['lat'],
'lng' => $last_data['lng'],
'geo' => calculateGeo($last_data['lat'], $last_data['lng']),
'time' => $last_data['time'],
'duration' => $avg_speed_data['duration'],
'distance' => $avg_speed_data['distance'],
'avg_speed' => $avg_speed_data['avg_speed'],
'trip_detection_1' => 'NO-TRIP', // initialize it as NO_TRIP, then we will update it later
'trip_detection_2' => 'NO-TRIP', // initialize it as NO_TRIP, then we will update it later
];
// calculate trip_detection_1 base on duration or avg speed
// if duration of a segement > $segment_duration_limit minute
// OR avg speed of a segment > $high_avg_speed km/h => segment may not belongs to a trip
if ($avg_speed_data['duration'] > $segment_duration_limit || $avg_speed_data['duration'] <= 0
|| $avg_speed_data['avg_speed'] > $high_avg_speed
) {
$trip_segment['trip_detection_1'] = 'NO-TRIP';
} else {
$trip_segment['trip_detection_1'] = 'TRIP';
}
$dataset[] = $trip_segment;
$rowCount++;
$first_data = $last_data;
// calculate trip_detection_2 base on trip_detection_1
if ($rowCount === $trip_limit) {
detectTrips($dataset, $tripStartIndex, $i);
$i++;
$rowCount--;
}
}
}
pg_free_result($track_res);
}
function getLastProcessedDatetime(int $member_id)
{
global $gpsconn;
$q = " SELECT
travel_date_end
FROM
gps_trips
WHERE
member_id = $member_id
ORDER BY
travel_date_end DESC
LIMIT 1
";
$lastProcessedDatetime = NULL;
$r = pg_query($gpsconn, $q);
if (!$r) {
echo pg_last_error($gpsconn);
}
if ($r && pg_num_rows($r) > 0) {
$data = pg_fetch_object($r, 0);
$lastProcessedDatetime = $data->travel_date_end;
} else {
$lastProcessedDatetime = '';
}
return $lastProcessedDatetime;
}
function detectTrips(array &$dataset, &$tripStartIndex, int &$i)
{
global $needed_trip_limit, $trip_limit;
// calculate trip_detection_2 base on trip_detection_1
$j = $i;
$segmentCount = 0;
while ($j < $i + $trip_limit) {
if ($dataset[$j]['trip_detection_1'] === 'TRIP') {
$segmentCount++;
}
$j++;
}
if ($segmentCount >= $needed_trip_limit) {
$dataset[$i]['trip_detection_2'] = 'TRIP';
}
// detect a trip based on trip_detection_2
if ($dataset[$i]['trip_detection_2'] === 'TRIP' && $tripStartIndex === 'NONE') {
$tripStartIndex = $i;
}
if ($tripStartIndex !== 'NONE' && $dataset[$i]['trip_detection_2'] !== 'TRIP') {
$trip_data = array_slice($dataset, $tripStartIndex, ($i - 1) - $tripStartIndex + 1);
processEachTrip($trip_data);
// remove rows that were calculated for a detected trip, reduce memory
array_splice($dataset, 0, ($i - 1) - 0 + 1);
$i = 0;
$tripStartIndex = 'NONE';
}
}
function processEachTrip(array $trip_data)
{
global $walking_low_avg_speed, $walking_high_avg_speed, $low_avg_speed, $high_avg_speed;
// detect legs of a trip
$cumulative_duration_total = 0;
$cumulative_distance_total = 0;
foreach ($trip_data as $key => $item) {
// note: in case first item, cumulative_duration and cumulative_distance will be 0
if ($key != 0) {
$cumulative_duration_total += $item['duration'];
$cumulative_distance_total += $item['distance'];
}
// km/h
$cumulative_avg_speed = $cumulative_duration_total > 0 ? round($cumulative_distance_total / $cumulative_duration_total * 60, 2) : 0;
$trip_data[$key]['cumulative_duration'] = $cumulative_duration_total;
$trip_data[$key]['cumulative_distance'] = $cumulative_distance_total;
$trip_data[$key]['cumulative_avg_speed'] = $cumulative_avg_speed;
$trip_data[$key]['transport_mode'] = '';
// how to detect transport mode
if ($cumulative_avg_speed < $walking_low_avg_speed) {
$trip_data[$key]['transport_mode'] = STOPPED;
} else if ($cumulative_avg_speed >= $walking_low_avg_speed && $cumulative_avg_speed <= $walking_high_avg_speed) {
$trip_data[$key]['transport_mode'] = WALKING;
} else if ($cumulative_avg_speed >= $low_avg_speed && $cumulative_avg_speed <= $high_avg_speed) {
$trip_data[$key]['transport_mode'] = DRIVING_AND_PUBLIC_TRANSPORT;
} else if ($cumulative_avg_speed > $high_avg_speed) {
$trip_data[$key]['transport_mode'] = UNKNOWN;
}
}
$gps_trip_id = insertATripIntoDatabase($trip_data);
splitLegsFromATrip($gps_trip_id, $trip_data);
}
function insertATripIntoDatabase(array $trip_data): int
{
global $gpsconn;
if (count($trip_data) <= 0) {
return 0;
}
$query = "
INSERT INTO gps_trips(member_id, travel_date, travel_date_end, duration,
distance, location_start_lat, location_start_lng, location_start,
location_start_id, location_end_lat, location_end_lng, location_end,
location_end_id, avg_speed, start_members_tracking_id, last_members_tracking_id)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16) RETURNING id;
";
$uniq = 'insert_gps_trips_' . uniqid(rand(), true);
pg_prepare($gpsconn, $uniq, $query);
$first_item = $trip_data[0];
$last_item = end($trip_data);
$avg_speed_data = calculateAvgSpeed($first_item, $last_item);
$duration_total = round($avg_speed_data['duration'], 2);
$distance_total = round($avg_speed_data['distance'], 2);
$avg_speed = round($avg_speed_data['avg_speed'], 2);
$res = pg_execute($gpsconn, $uniq, [
$first_item['member_id'],
$first_item['time'],
$last_item['time'],
$duration_total,
$distance_total,
$first_item['lat'],
$first_item['lng'],
$first_item['geo'],
getAddressId($first_item['lat'], $first_item['lng']),
$last_item['lat'],
$last_item['lng'],
$last_item['geo'],
getAddressId($last_item['lat'], $last_item['lng']),
$avg_speed,
$first_item['members_tracking_id'],
$last_item['members_tracking_id']
]);
if ($res) {
$id = (int) pg_fetch_result($res, 0);
return $id;
} else {
echo pg_last_error($gpsconn);
}
return 0;
}
function splitLegsFromATrip(int $gps_trip_id, array $trip_data)
{
$trip_data_count = count($trip_data);
if ($trip_data_count <= 0) {
return;
}
$transport_mode = '';
$change_point_index = 0;
$array_key_last = array_keys($trip_data)[$trip_data_count - 1];
foreach ($trip_data as $key => $item) {
$leg_last_index = $key;
if ((isset($trip_data[$leg_last_index + 1]['transport_mode']) && $trip_data[$leg_last_index]['transport_mode'] != $trip_data[$leg_last_index + 1]['transport_mode'])
|| ($array_key_last == $leg_last_index)
) {
// precess save for each leg
$leg_start_index = $change_point_index == 0 ? 0 : $change_point_index - 1;
$leg_data = array_slice($trip_data, $leg_start_index, $leg_last_index - $leg_start_index + 1);
insertALegIntoDatabase($gps_trip_id, $leg_data, $trip_data[$leg_last_index]['transport_mode']);
$change_point_index = $leg_last_index + 1;
}
}
}
function insertALegIntoDatabase(int $gps_trip_id, array $trip_data, string $transport_mode)
{
global $gpsconn;
if (count($trip_data) <= 0) {
return;
}
$query = "
INSERT INTO gps_trips_legs(member_id, gps_trip_id, travel_date, travel_date_end, duration,
distance, location_start_lat, location_start_lng, location_start,
location_start_id, location_end_lat, location_end_lng, location_end,
location_end_id, avg_speed, transport_mode, start_members_tracking_id, last_members_tracking_id)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18);
";
$uniq = 'insert_gps_trips_legs_' . uniqid(rand(), true);
pg_prepare($gpsconn, $uniq, $query);
$first_item = $trip_data[0];
$last_item = end($trip_data);
$avg_speed_data = calculateAvgSpeed($first_item, $last_item);
$duration_total = round($avg_speed_data['duration'], 2);
$distance_total = round($avg_speed_data['distance'], 2);
$avg_speed = round($avg_speed_data['avg_speed'], 2);
$res = pg_execute($gpsconn, $uniq, [
$first_item['member_id'],
$gps_trip_id,
$first_item['time'],
$last_item['time'],
$duration_total,
$distance_total,
$first_item['lat'],
$first_item['lng'],
$first_item['geo'],
getAddressId($first_item['lat'], $first_item['lng']),
$last_item['lat'],
$last_item['lng'],
$last_item['geo'],
getAddressId($last_item['lat'], $last_item['lng']),
$avg_speed,
$transport_mode,
$first_item['members_tracking_id'],
$last_item['members_tracking_id']
]);
if (!$res) {
echo pg_last_error($gpsconn);
}
}
function calculateGeo($lat, $lng)
{
global $gpsconn;
$q = "
SELECT ST_SetSRID(ST_MakePoint('" . $lng . "','" . $lat . "'), 4326)::geography as geo
";
$r = pg_query($gpsconn, $q);
if (!$r) {
echo pg_last_error($gpsconn);
}
if ($r && pg_num_rows($r) > 0) {
$data = pg_fetch_object($r, 0);
return $data->geo;
}
return null;
}
function calculateAvgSpeed(array $first_data, array $last_data): array
{
$start_date = strtotime($first_data['time']);
$end_date = strtotime($last_data['time']);
$duration = abs($start_date - $end_date);
$duration = $duration / 60; // convert sec to min
$distance = sqrt(pow(abs(($last_data['lng'] - $first_data['lng']) * 111), 2) + pow(abs(($last_data['lat'] - $first_data['lat']) * 111), 2));
$avg_speed = ($duration > 0) ? ($distance / $duration * 60) : 0; // convert km/m to km/h
return [
'duration' => $duration,
'distance' => $distance,
'avg_speed' => $avg_speed,
];
}
function getAddressId(float $lat, float $lng) : int {
$reverse_data = reverseGeocode($lat, $lng);
if (empty($reverse_data)) {
return 0;
}
list($fAddress, $err) = geocode($reverse_data['address_name'], $reverse_data['country_short_name']);
if (!is_array($fAddress) || !array_key_exists('geocode',$fAddress) || !is_array($fAddress['geocode'])
|| !array_key_exists('id',$fAddress['geocode']) || $fAddress['geocode']['id']<1) {
// Failed to geocode from address
return 0;
}
return $fAddress['geocode']['id'];
}
function geocode(string $address_name, string $country_code, int $member_id=0) : array{
global $encryptionAlg, $encryptionKey, $encryptionIV, $baseURL, $httpAuthToken;
$in = [
'address' => $address_name,
'member_id' => $member_id,
'country' => $country_code
];
$data = http_build_query($in);
$url = $baseURL . "/trips/api/geocode/?".$data;
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_VERBOSE, false);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'Authorization: Server-Token ' . $httpAuthToken,
"client_id: BATCH"
)
);
$body = curl_exec($ch);
$result = json_decode($body,true);
$payload = openssl_decrypt(
hex2bin(
$result['payload']
),
$encryptionAlg,
$encryptionKey,
OPENSSL_RAW_DATA,
$encryptionIV
);
return [json_decode($payload,true),$body];
}
function reverseGeocode(float $lat, float $lng) : array
{
// LINK: https://developers.google.com/maps/documentation/geocoding/start#reverse
global $googleApiKey;
$url = "https://maps.googleapis.com/maps/api/geocode/json?latlng=${lat},${lng}&key=${googleApiKey}";
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_VERBOSE, false);
$body = curl_exec($ch);
$res = json_decode($body);
$country_short_name = '';
$address_name = '';
if (isset($res->status) && $res->status === 'OK') {
$address_components = $res->results[0]->address_components;
$address_name = $res->results[0]->formatted_address;
for ($i = 0;$i < count($address_components);$i++) {
$cn = array($address_components[$i]->types[0]);
if (in_array("country", $cn)) {
$country_short_name = $address_components[$i]->short_name;
}
}
}
if (!empty($country_short_name) && !empty($address_name)) {
return [
'country_short_name' => $country_short_name,
'address_name' => $address_name,
];
}
return [];
}
// export for DEBUG
function exportCsv(array $data)
{
$fp = fopen('/Users/inmac/Sites/FloatAdmin/adminsavvy/CRONS/transportation_mode_detection/trip.csv', 'a+');
$data = array_map(function ($el) {
return [
$el['members_tracking_id'],
$el['lng'],
$el['lat'],
$el['time'],
round($el['duration'], 2),
round($el['distance'], 2),
round($el['avg_speed'], 2),
$el['trip_detection_1'],
$el['trip_detection_2'],
round($el['cumulative_duration'], 2),
round($el['cumulative_distance'], 2),
round($el['cumulative_avg_speed'], 2),
$el['transport_mode'],
];
}, $data);
array_unshift($data, [
'members_tracking_id',
'lng',
'lat',
'time',
'duration',
'distance',
'avg_speed',
'trip_detection_1',
'trip_detection_2',
'cumulative_duration',
'cumulative_distance',
'cumulative_avg_speed',
'transport_mode',
]);
foreach ($data as $row) {
fputcsv($fp, $row);
}
fclose($fp);
}

Some files were not shown because too many files have changed in this diff Show More