'RideShare',
'Taxi' => 'Taxi',
//'ScooterRental' => 'Scooter',
'PublicTransport' => 'Bus',
'Subway' => 'Subway',
'Gas' => 'Gas'
];
protected function mergeWeeklySpending($result, $results) {
foreach ($results as $key => $val) {
if ($val['dow'] == $result['dow']) {
$val['spent'] += $result['spent'];
$val['total'] += $result['total'];
$results[$key] = $val;
break;
}
}
return $results;
}
public function weeklySpending($db, $gpsdb, $data) {
error_log('Report::weeklySpending($db, $data) ');
//$db_country = pg_escape_string($country); // is not used for now...
//$db_address = pg_escape_string($address);
$member_id = (int) $data['member_id'];
//$member_id = 3; // DEBUG
if ($member_id < 1)
return NULL;
$found = false;
/*
$results = [
['dow'=>0,'spent'=>0,'total'=>0],
['dow'=>1,'spent'=>0,'total'=>0],
['dow'=>2,'spent'=>0,'total'=>0],
['dow'=>3,'spent'=>0,'total'=>0],
['dow'=>4,'spent'=>0,'total'=>0],
['dow'=>5,'spent'=>0,'total'=>0],
['dow'=>6,'spent'=>0,'total'=>0]
];
*/
$results = [];
$now = new DateTime("7 days ago");
$interval = new DateInterval('P1D'); // 1 Day interval
$period = new DatePeriod($now, $interval, 6); // 7 Days
foreach ($period as $day) {
$results[] = array(
'date' => $day->format('Y-m-d'),
'spent' => 0,
'total' => 0,
'dow' => $day->format('w')
);
}
// Credit card transations
$q = "SELECT extract(dow from time) AS dow, round(0.01*sum(amount)/count(amount),2) AS spent, round(0.01*sum(amount),2) AS total ";
$q .= " FROM members_bankimport ";
$q .= " WHERE member_id=${member_id} AND LOWER(category) IN (SELECT LOWER(category) FROM activity_listcategory) AND date_trunc('day', time) > (current_date - 8) AND date_trunc('day', time) < current_date AND amount>0 ";
$q .= " GROUP BY dow ORDER BY dow";
error_log($q); // DEBUG
$r = pg_query($db, $q);
if ($r && pg_num_rows($r)) {
while ($f = pg_fetch_assoc($r)) {
$results = self::mergeWeeklySpending($f, $results);
}
$found = true;
}
// E-mail receipts
$q = "SELECT extract(dow from a.travel_date) AS dow, round(sum(a.cost)/count(a.cost),2) AS spent, round(sum(a.cost),2) AS total ";
$q .= " FROM parsedemail_item a, trackedemail_item b ";
$q .= " WHERE b.id=a.trackedemail_item_id AND b.member_id=${member_id} AND a.dup_id IS NULL AND ";
$q .= " date_trunc('day', a.travel_date) > (current_date - 8) AND date_trunc('day', a.travel_date) < current_date ";
$q .= " GROUP BY dow ORDER BY dow";
error_log($q); // DEBUG
$r = pg_query($db, $q);
if ($r && pg_num_rows($r)) {
while ($f = pg_fetch_assoc($r)) {
$results = self::mergeWeeklySpending($f, $results);
}
$found = true;
}
return [$found ? $results : NULL, []];
}
public function spendingByCategoryLastSevenDays($db, $gpsdb, $data) {
$member_id = (int) $data['member_id'];
$include_items = $data['include_items'] ?? false;
$include_items_values = $data['include_items_values'] ?? true;
// $member_id = 3;
$days = $data['days'] ?? 7;
$start_date = $data['start_date'] ?? "";
$end_date = !empty($data['end_date']) ? date("Y-m-d", strtotime($data['end_date'] . "+1 days")) : "";
$member_country = $data['member_country'] ?? "";
return Report::spendingByCategoryForDays($db, $member_id, $days, $include_items, $start_date, $end_date, $include_items_values, $member_country);
}
public function categoryItems($db, $gpsdb, $data) {
$member_id = (int) $data['member_id'];
$category = filter_var($data['category'], FILTER_SANITIZE_STRING);
$days = $data['days'] ?? 30;
$start_date = $data['start_date'] ?? "";
$end_date = !empty($data['end_date']) ? date("Y-m-d", strtotime($data['end_date'] . "+1 days")) : "";
$result = Report::getCategoryItems($db, $member_id, $days, $category);
return $result;
}
public function spendingByCategoryAllTime($db, $gpsdb, $data) {
$member_id = (int) $data['member_id'];
$include_items = $data['include_items'] ?? false;
$now = time(); // or your date as well
$your_date = strtotime("2010-01-31");
$datediff = $now - $your_date;
$days = round($datediff / (60 * 60 * 24));
return Report::spendingByCategoryForDays($db, $member_id, $days, $include_items);
}
public function spendingByWeekdayLastSevenDays($db, $gpsdb, $data) {
error_log('Report::spendingByWeekdayLastSevenDays($db, $data)');
//return ReportMock::spendingByWeekdayLastSevenDays($db, $data);
return Report::weeklySpending($db, $data);
}
public function emissionsByDays($db, $gpsdb, $data) {
$member_id = (int) $data['member_id'];
$days = $data['days'] ?? 30;
$start_date = $data['start_date'] ?? "";
$end_date = !empty($data['end_date']) ? date("Y-m-d", strtotime($data['end_date'] . "+1 days")) : "";
$member_country = $data['member_country'] ?? "";
// $member_id = 3;
return Report::emissionsByDaysData($db, $member_id, $days, $start_date, $end_date, $member_country);
}
public function travelTimeByDays($db, $gpsdb, $data) {
$member_id = (int) $data['member_id'];
$days = $data['days'] ?? 30;
$start_date = $data['start_date'] ?? "";
$end_date = !empty($data['end_date']) ? date("Y-m-d", strtotime($data['end_date'] . "+1 days")) : "";
$member_country = $data['member_country'] ?? "";
// $member_id = 3;
return Report::travelTimeByDaysData($db, $member_id, $days, $start_date, $end_date, $member_country);
}
/**
* Radar chart data
*
*/
public function travelTimeBreakdownVsAverage($db, $gpsdb, $data) {
error_log('Report::travelTimeBreakdownVsAverage($db, $data)');
$member_id = (int) $data['member_id'];
$member_country = $data['member_country']??"";
$count_total = 0;
// Walking SQL
$count_walking = 0;
$q = "select count(*) from members_tracking_trips where member_id=${member_id} and distance>" . self::TRIP_WALKING_DISTANCE . " and address_start<>address_end and avg_speed<" . self::SPEED_LIMIT_WALKING;
$r = pg_query($gpsdb, $q);
if ($r && pg_num_rows($r) && $f = pg_fetch_row($r)) {
$count_walking = $f[0];
$count_total += $f[0];
}
// Scooter/bike SQL
$count_bicycle = 0;
$q = "select count(*) from members_tracking_trips where member_id=${member_id} and distance>" . self::TRIP_DRIVING_DISTANCE . " and address_start<>address_end and avg_speed>=" . self::SPEED_LIMIT_WALKING . " and avg_speed<=" . self::SPEED_LIMIT_DRIVING;
$r = pg_query($gpsdb, $q);
if ($r && pg_num_rows($r) && $f = pg_fetch_row($r)) {
$count_bicycle = $f[0];
$count_total += $f[0];
}
// Driving SQL
$count_driving = 0;
$q = "select count(*) from members_tracking_trips where member_id=${member_id} and distance>" . self::TRIP_DRIVING_DISTANCE . " and address_start<>address_end and avg_speed>" . self::SPEED_LIMIT_DRIVING;
$r = pg_query($gpsdb, $q);
if ($r && pg_num_rows($r) && $f = pg_fetch_row($r)) {
$count_driving = $f[0];
$count_total += $f[0];
}
$count_scooter = 0;
$count_mycar = 0;
$count_bus = 0;
$count_train = 0;
$count_plane = 0;
// Credit card transations (user)
$q = "SELECT count(mbi.import_id), mbi.category ";
$q .= " FROM members_bankimport mbi ";
$q .= " inner join activity_listcategory alc on alc.category = mbi.category "; // get only travel related categories
$q .= " WHERE member_id=${member_id} ";
$q .= " GROUP BY mbi.category; ";
//error_log($q); // DEBUG
$r = pg_query($db, $q);
if ($r && pg_num_rows($r)) {
$mycar = [];
while ($f = pg_fetch_row($r)) {
switch ($f[1]) {
case 'ScooterRental': {
$count_bicycle += $f[0];
$count_total += $f[0];
break;
}
case 'BikeRental': {
$count_bicycle += $f[0];
$count_total += $f[0];
break;
}
case 'Parking': {
$mycar[] = $f[0];
break;
}
case 'Gas': {
$mycar[] = $f[0];
break;
}
case 'TollsFees': {
$mycar[] = $f[0];
break;
}
case 'CarRental': {
$mycar[] = $f[0];
break;
}
case 'CarShare': {
$mycar[] = $f[0];
break;
}
case 'CarInsurance': {
$mycar[] = $f[0];
break;
}
case 'BusTickets': {
$count_bus += $f[0];
$count_total += $f[0];
break;
}
case 'PublicTransport': {
$count_bus += $f[0];
$count_total += $f[0];
break;
}
case 'Transportation': {
$count_bus += $f[0];
$count_total += $f[0];
break;
}
case 'RideShare': {
$count_driving += $f[0];
$count_total += $f[0];
break;
}
case 'Taxi': {
$count_driving += $f[0];
$count_total += $f[0];
break;
}
default: $count_total += $f[0];
}
}
if (count($mycar)) {
$max_mycar = 0;
foreach ($mycar as $val) {
if ($val > $max_mycar) {
$max_mycar = $val;
}
}
$count_mycar += $max_mycar;
$count_total += $max_mycar;
}
}
//*/
/*
savvy=> SELECT count(*),category FROM members_bankimport WHERE member_id=3 GROUP BY category;
count | category
-------+-----------------
1 | ScooterRental
2 | Other
26 | PublicTransport
1111 | RideShare
55 | Taxi
83 | Parking
99 | Gas
1 | CarShare
31 | TollsFees
108 | CarRental
*/
// E-mail receipts (user)
$q = "SELECT count(*), c.category";
$q .= " FROM parsedemail_item a, trackedemail_item b, transport_providers c ";
$q .= " WHERE b.id=a.trackedemail_item_id AND b.member_id=${member_id} AND a.dup_id IS NULL ";
$q .= " AND c.id=a.transport_provider_id GROUP BY c.category";
error_log($q); // DEBUG
$r = pg_query($db, $q);
if ($r && pg_num_rows($r)) {
while ($f = pg_fetch_row($r)) {
switch ($f[1]) {
case 'CarShare': {
$count_mycar += $f[0];
$count_total += $f[0];
break;
}
case 'RideShare': {
$count_driving += $f[0];
$count_total += $f[0];
break;
}
case 'Taxi': {
$count_driving += $f[0];
$count_total += $f[0];
break;
}
default: $count_total += $f[0];
}
}
}
/*
SELECT count(*), c.category FROM parsedemail_item a, trackedemail_item b, transport_providers c WHERE b.id=a.trackedemail_item_id AND b.member_id=3 AND a.dup_id IS NULL AND c.id=a.transport_provider_id GROUP BY c.category;
count | category
-------+-----------
2 | Taxi
1800 | RideShare
? | CarShare
*/
// get the user here
$user_data = array();
$query = "SELECT id, country, state, city FROM members WHERE id = {$member_id};";
$r = pg_query($db, $query);
if ($r && pg_num_rows($r)) {
while ($f = pg_fetch_assoc($r)) {
$user_data['member_id'] = $f['id'];
$user_data['country'] = $f['country'];
$user_data['city'] = $f['city'];
$user_data['state'] = $f['state'];
}
}
$averages = self::getPersonalityAverages($db, $user_data['country'], $user_data['state'], $user_data['city']);
if (!empty($averages)) {
$radar_avrg = $averages[0];
$total_average = $averages[1];
$average_walking_p = $radar_avrg["EMWALK"] / $total_average;
$average_bicycle_p = $radar_avrg["EMBYCYCLE"] / $total_average;
$average_scooter_p = $radar_avrg["EMSCOTTER"] / $total_average;
$average_driving_p = $radar_avrg["EMRIDESH"] / $total_average;
$average_mycar_p = $radar_avrg["EMTAXICAR"] / $total_average;
$average_bus_p = $radar_avrg["EMPUBLIC"] / $total_average;
$average_train_p = $radar_avrg["EMTRAIN"] / $total_average;
} else {
$average_walking_p = 0;
$average_bicycle_p = 0;
$average_scooter_p = 0;
$average_driving_p = 0;
$average_mycar_p = 0;
$average_bus_p = 0;
$average_train_p = 0;
}
// not data available yet
$count_train_p = $count_total > 0 ? sprintf("%0.02f", $count_train / $count_total) : 0;
$count_plane_p = $count_total > 0 ? sprintf("%0.02f", $count_plane / $count_total) : 0;
//gps data source
$count_walking_p = $count_total > 0 ? sprintf("%0.02f", $count_walking / $count_total) : 0;
$count_bicycle_p = $count_total > 0 ? sprintf("%0.02f", $count_bicycle / $count_total) : 0;
// bank receipts
$count_scooter_p = $count_total > 0 ? sprintf("%0.02f", $count_scooter / $count_total) : 0;
$count_bus_p = $count_total > 0 ? sprintf("%0.02f", $count_bus / $count_total) : 0;
// email and bank receipts
$count_driving_p = $count_total > 0 ? sprintf("%0.02f", $count_driving / $count_total) : 0;
$count_mycar_p = $count_total > 0 ? sprintf("%0.02f", $count_mycar / $count_total) : 0;
$dataR = [
[// average
["axis" => "Walk", "value" => $average_walking_p],
["axis" => "Bicycle", "value" => $average_bicycle_p], // Scooter / bike
//["axis" => "Scooter/Bike", "value" => $average_bicycle_p], // New version
//["axis" => "Scooter","value" => $average_scooter_p],
["axis" => "Taxi", "value" => $average_driving_p], // Ridehare / Taxi
//["axis" => "Rideshare/Taxi", "value" => $average_driving_p], // New version
["axis" => "My Car", "value" => $average_mycar_p],
["axis" => "Bus", "value" => $average_bus_p], // Public transit
//["axis" => "Public Transit", "value" => $average_bus_p], // new version
],
[// current user
["axis" => "Walk", "value" => $count_walking_p],
["axis" => "Bicycle", "value" => $count_bicycle_p], // bike and scooter are merged
//["axis" => "Scooter/Bike", "value" => $count_bicycle_p], // new version
//["axis" => "Bicycle","value" => $count_scooter_p],
["axis" => "Taxi", "value" => $count_driving_p], // Ridesare/Taxi
//["axis" => "Rideshare/Taxi", "value" => $count_driving_p], // new version
["axis" => "My Car", "value" => $count_mycar_p],
["axis" => "Bus", "value" => $count_bus_p], // Public transit
//["axis" => "Public Transit", "value" => $count_bus_p], // new version
]
];
$cards = Report::GetPageCardData($db, $member_id, 'activity-personality', $member_country);
return [$dataR, ['cards' => $cards]];
}
private function getPersonalityAveragesQuery($country, $state, $city) {
if (empty($country)) {
// no country provided, get the US average
$query = "SELECT * FROM emission_avrg_commute WHERE country = 'US' and state = '' and city = '' ;";
} elseif (!empty($state) && !empty($city)) {
// try to get as acurate as possible
$query = "SELECT * FROM emission_avrg_commute WHERE country = '{$country}' and state = '{$state}' and city = '{$city}' ;";
} elseif (!empty($state)) {
// get the state wide average
$query = "SELECT * FROM emission_avrg_commute WHERE country = '{$country}' and state = '{$state}' and city = '' ;";
} else {
// we only have the country
$query = "SELECT * FROM emission_avrg_commute WHERE country = '{$country}' and state = '' and city = '' ;";
}
return $query;
}
private function processPersonalityAveragesData($res) {
$total_average = 0;
while ($f = pg_fetch_assoc($res)) {
$radar_avrg[$f["mkey"]] = $f["gramskm_perc"];
$total_average = $total_average + $f["gramskm_perc"]; // we know it is 100 but in case
}
return array($radar_avrg, $total_average);
}
private function getPersonalityAverages($db, $country, $state, $city) {
$query = self::getPersonalityAveragesQuery($country, $state, $city);
$r = pg_query($db, $query);
if ($r && pg_num_rows($r)) {
return self::processPersonalityAveragesData($r);
}
// no results found, try to "zoom out"
$query = self::getPersonalityAveragesQuery($country, $state, null);
$r = pg_query($db, $query);
if ($r && pg_num_rows($r)) {
return self::processPersonalityAveragesData($r);
}
// no results found, try to get the country wide averages
$query = self::getPersonalityAveragesQuery($country, null, null);
$r = pg_query($db, $query);
if ($r && pg_num_rows($r)) {
return self::processPersonalityAveragesData($r);
}
// no results found, try to get the global data
$query = self::getPersonalityAveragesQuery(null, null, null);
$r = pg_query($db, $query);
if ($r && pg_num_rows($r)) {
return self::processPersonalityAveragesData($r);
}
return false;
}
private function emissionsByDaysData($db, $member_id, $days, $start_date = "", $end_date = "", $member_country='') {
/*
* PREPARE THE GAS DATA
*/
$filter_date = " AND time between now()+'-$days days' AND now() ";
if (!empty($start_date) && !empty($end_date)) {
$filter_date = " AND time >= '$start_date' AND time < '$end_date' ";
}
$emiss_arr = [];
$mysql_e = "SELECT sum(amount) AS amount,time::date FROM members_bankimport "
. " WHERE member_id = $member_id AND LOWER(category) ='gas' AND amount>0 "
. $filter_date
. " GROUP by time::date ORDER BY time DESC";
$re = pg_query($db, $mysql_e);
if ($re && pg_num_rows($re)) {
$itm_e = 0;
while ($fe = pg_fetch_assoc($re)) {
$gas_emission_value = 0;
$gas_amount = $fe["amount"] * 0.01;
$gas_date = $fe["time"];
// $emiss_arr = array_fill_keys($gas_date, array("gas_date" => "$gas_date", "value" => $gas_emission_value, "gas" => $gas_amount));
//array_push($gas_emission, array("gas_date" => "$gas_date", "value" => $gas_emission_value, "gas" => $gas_amount));
// array_push($gas_emission, $emiss_arr);
$emiss_arr[$gas_date] = array("gas_date" => "$gas_date", "value" => $gas_emission_value, "gas" => $gas_amount);
}
}
$data = [];
$data_result = Report::travelTimeByDaysData($db, $member_id, $days, $start_date, $end_date, $member_country);
$total_value = 0;
$latest = 0;
if (!empty($start_date) && !empty($end_date)) {
$days = 1 + round((strtotime($end_date) - strtotime($start_date)) / 86400);
$latest = 1;
}
for ($ic = $latest; $ic < $days; $ic++) {
if (!empty($end_date)) {
$new_date = date("Y-m-d", strtotime($end_date . "-$ic days"));
} else {
$new_date = date("Y-m-d", strtotime("-$ic days"));
}
$emission_value = 0;
$gas_amount = 0;
$gas_emission = 0;
$merchant_name = "";
$amount = 0;
//$gas_emission
if (array_key_exists($new_date, $emiss_arr)) {
$gas_amount = $emiss_arr[$new_date]["gas"];
$gas_country = 'US';
$ems_data = Report::getEmissionModel($gas_amount, 1, $gas_country);
$gas_emission = $ems_data[0];
}
$emission_value = $gas_emission;
if (array_key_exists($new_date, $data_result[0])) {
$emission_value = $emission_value + $data_result[0][$new_date]["emission"];
$amount = $data_result[0][$new_date]["amount"];
$merchant_name = $data_result[0][$new_date][$new_date]["merchant_name"];
}
$total_value += $emission_value;
array_push($data, array("date" => "$new_date", "value" => $emission_value, "gas" => $gas_amount, "gas_emission" => $gas_emission, "amount" => $amount, "merchant_name" => $merchant_name));
}
$cards = Report::GetPageCardData($db, $member_id, 'activity-emissions', $member_country);
return [$data, ['total_value' => $total_value, 'cards' => $cards]];
}
/**
* Change the function to get card data for all screens
*/
private function GetPageCardData($db, $member_id, $screen_name, $member_country='') {
$optionalMessageArr = [];
$optionalMessageArr['message'] = '';
$optionalMessageArr['icon'] = '';
$optionalMessageArr['card_id'] = '0';
switch ($screen_name) {
case 'activity-emissions':
$activity_screen = 4;
break;
case 'activity-time-traveled':
$activity_screen = 3;
break;
case 'activity-monthly-spent':
$activity_screen = 2;
break;
case 'activity-personality':
$activity_screen = 5;
break;
default:
$activity_screen = 0;
break;
}
$cards = array();
//$screen_name = 'activity-emissions';
/*
$query = "SELECT mn.msg, mn.expire, mn.added, et.category, et.icon ";
$query .= " FROM members_notification mn ";
$query .= " inner join email_trigger et on et.e_trigger = mn.trigger_key ";
$query .= " inner join screen_cards sc on sc.trigger_id = mn.trigger_key ";
$query .= " where sc.screen_name = '{$screen_name}' and mn.member_id = {$member_id} ";
$query .= " and sc.status = 1 ";
$query .= " and expire > now() ";
$query .= " order by mn.added desc LIMIT 1; ";
$query = "SELECT 0 AS card_id, mn.msg, et.category AS action, et.icon AS card_icon ,0 AS blog_id, 0 AS assign_id";
$query .= " FROM members_notification mn ";
$query .= " inner join email_trigger et on et.e_trigger = mn.trigger_key ";
$query .= " inner join screen_cards sc on sc.trigger_id = mn.trigger_key ";
$query .= " where sc.screen_name = '{$screen_name}' and mn.member_id = {$member_id} ";
$query .= " and sc.status = 1 ";
$query .= " and expire > now() ";
$query .= " UNION ";
* TEST QUERY -------------------------------------------
$query .= "SELECT ma.card_id,mc.description AS msg,mc.button1_action AS action,'' AS card_icon,mc.blog_id, "
. " ma.id AS assign_id, mc.*, ca.type AS card_action_type, ca.data AS card_action_data, ma.subscribe, ma.message "
. " FROM members_card_assign ma "
. " LEFT JOIN main_cards mc ON mc.id=ma.card_id "
. " LEFT JOIN card_actions ca ON (ca.id=mc.card_action_id) "
. "WHERE mc.activity_screen= {$activity_screen} " // AND mc.button1_action == 'GOOFFERS'
. ""
. "AND ma.status = 1 AND mc.show_area = 2 "
. "AND mc.id=355;";
$query = "";
// END TEST QUERY ---------------------------------------------
*/
// do not need the union anymore
// Get user country
if($member_country==''){
$mysql_member_country = "SELECT country FROM members WHERE id = {$member_id}";
$rec = pg_query($db, $mysql_member_country);
if ($rec && pg_num_rows($rec)) {
$rowc = pg_fetch_assoc($rec);
$member_country= $rowc["country"];
}
}
$query = "";
$country_query = " AND mc.card_country = '' ";
if ($member_country !=''){
$country_query = " AND mc.card_country IN ('', '$member_country')";
}
$query .= "SELECT ma.card_id,mc.description AS msg,mc.button1_action AS action,'' AS card_icon,mc.blog_id, "
. " ma.id AS assign_id, mc.*, ca.type AS card_action_type, ca.data AS card_action_data, ma.subscribe, ma.message "
. " FROM members_card_assign ma "
. " LEFT JOIN main_cards mc ON mc.id=ma.card_id "
. " LEFT JOIN card_actions ca ON (ca.id=mc.card_action_id) "
. " WHERE mc.activity_screen= {$activity_screen} " // AND mc.button1_action == 'GOOFFERS'
. " AND ma.subscribe IS NULL "
. " AND ma.status = 1 AND mc.show_area = 2 $country_query "
. " AND ma.member_id= {$member_id} ORDER BY random() LIMIT 1 ";
// get the message, icon, and action ( category )
$re = pg_query($db, $query);
if ($re && pg_num_rows($re)) {
$row = pg_fetch_assoc($re);
// defalut values to avoid nulls
$default_to_string = array('msg', 'icon', 'category', 'card_action_type', 'card_action_data', 'message', 'subscribe');
foreach ($default_to_string as $col) {
if (empty($row[$col])) {
$row[$col] = "";
}
}
$cards[] = array(
'message' => $row["msg"],
'icon' => $row['card_icon'],
'action' => $row['action'],
'button1_action' => $row['action'],
'assign_id' => $row['assign_id'],
'card_id' => $row['card_id'],
'blog_id' => $row['blog_id'],
'detail_data' => $row
);
}
// old logic bellow
/*
*
* $message = $fe["msg"];
$icon = $fe["card_icon"];
$action = $fe["action"];
$card_id = $fe["card_id"];
*
*
$query = "SELECT * FROM members_notification WHERE trigger_key IN ('ETRG0014','ETRG0007') AND member_id = $member_id"
." AND added between now() + '-7 days' "
. " AND now() ORDER BY added DESC LIMIT 1";
$re = pg_query($db, $query);
if ($re && pg_num_rows($re)) {
//msg
$row = pg_fetch_assoc($re);
$optionalMessageArr['message'] = $row["msg"]; // "Sweet! You’ve spent almost 30 minutes less time on your commute this month!";
$optionalMessageArr['icon'] ="fast-moving";
}
*/
return $cards;
}
// end of emission page card
private 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;
}
/*
Note that the travelTimeByDaysData generates data for emission plot
*/
private function travelTimeByDaysData($db, $member_id, $days, $start_date = '', $end_date = '', $member_country) {
$available_countries = array(
'US' => array(
'taxi_avg_start' => 3.5,
'taxi_avg_fee_per_km' => 1.7,
'taxi_avg_time_per_km' => 1.71,
'scooter_avg_start' => 1,
'scooter_avg_min' => 0.24,
'gas_price_per_litre' => 1.07,
'time_traveled_per_litre' => 22,
),
'SG' => array(
'taxi_avg_start' => 2.66,
'taxi_avg_fee_per_km' => 0.47,
'taxi_avg_time_per_km' => 1.29,
'scooter_avg_start' => 1,
'scooter_avg_min' => 0.1,
'gas_price_per_litre' => 1.39,
'time_traveled_per_litre' => 17,
)
);
// get the user country
$user_country = "US";
$query = "select country from members where id = $1;";
$r = pg_query_params($db, $query, array($member_id));
if ($r && pg_num_rows($r)) {
while ($f = pg_fetch_assoc($r)) {
$user_country = $f['country'];
}
}
if (!array_key_exists($user_country, $available_countries)) {
$user_country = 'US';
}
//PREPARE THE MODEL ARRAY
$mysql = "SELECT mkey,substr(lower(transport_mode),0,5) AS transport_mode, grams_km,passengers FROM emission_model";
$model_data = [];
$r = pg_query($db, $mysql);
if ($r && pg_num_rows($r)) {
$itm_count = 0;
while ($f = pg_fetch_assoc($r)) {
$model_line = array("mkey" => $f["mkey"], "transport_mode" => $f["transport_mode"], "grams_km" => $f["grams_km"], "passengers" => $f["passengers"]);
$model_data[$f["transport_mode"]][] = $model_line;
}
}
$data_result = [];
$filter_date = " date_trunc('day', b.travel_date) > (current_date - ${days}) AND date_trunc('day', b.travel_date) < current_date AND ";
if (!empty($start_date) && !empty($end_date)) {
$filter_date = " travel_date >= '$start_date' AND travel_date < '$end_date' AND ";
}
// note we don travel everyday - i am modifying this to last 30 or 60 days - not just date diiference
$q = "SELECT b.travel_date::date, c.category, c.name as merchant_name, sum(b.cost) AS amount ,sum(b.duration) AS sum_duration , sum(b.distance) AS sum_distance
FROM trackedemail_item a, parsedemail_item b, transport_providers c
WHERE a.id=b.trackedemail_item_id AND a.member_id=${member_id} AND c.id=b.transport_provider_id AND b.dup_id IS NULL AND
" . $filter_date . "
b.transport_provider_id > 0
GROUP BY b.travel_date::date, c.category, c.name ORDER BY b.travel_date::date DESC "; // ${days}
//error_log($q);
$r = pg_query($db, $q);
if ($r && pg_num_rows($r)) {
$itm_count = 0;
while ($f = pg_fetch_assoc($r)) {
// pick the category
$category_substring = strtolower(substr($f["category"], 0, 4));
$model_read = $model_data[$category_substring][0];
$grams_km = $model_read["grams_km"];
$passengers = $model_read["passengers"];
//echo "
";
//print_r( $model_read );
$emission = $f["sum_distance"] * $grams_km / $passengers;
$detail_line = array("category" => $f["category"], "merchant_name" => $f["merchant_name"], "amount" => $f["amount"], "duration" => $f["sum_duration"], "distance" => $f["sum_distance"], "emission" => $emission);
$add_line = true;
if ($itm_count > 0) {
if (array_key_exists($f["travel_date"], $data_result)) {
$add_line = false; // dont add new line - modify the current one
$data_result[$f["travel_date"]]["value"] = $data_result[$f["travel_date"]]["value"] + $f["sum_duration"];
$data_result[$f["travel_date"]]["duration"] = $data_result[$f["travel_date"]]["duration"] + $f["sum_duration"];
$data_result[$f["travel_date"]]["amount"] = $data_result[$f["travel_date"]]["amount"] + $f["amount"];
$data_result[$f["travel_date"]]["distance"] = $data_result[$f["travel_date"]]["distance"] + $f["sum_distance"];
$data_result[$f["travel_date"]]["emission"] = $data_result[$f["travel_date"]]["emission"] + $emission;
$data_result[$f["travel_date"]][$f["travel_date"]][] = $detail_line;
}
}
if (true == $add_line) {
$data_line = array(
"date" => $f["travel_date"],
"value" => $f["sum_duration"],
"duration" => $f["sum_duration"],
"amount" => $f["amount"],
"distance" => $f["sum_distance"],
"emission" => $emission,
$f["travel_date"] => [$detail_line]
);
$data_result[$f["travel_date"]] = $data_line;
}
$itm_count++;
}
}
$gas_transactions = array();
$end_days = intval($days) + 1;
// extract taxi time spent from bank receipts
$filter_date = " date_trunc('day', time) > (current_date - ${end_days}) AND date_trunc('day', time) < current_date ";
if (!empty($start_date) && !empty($end_date)) {
$filter_date = " time >= '$start_date' AND time < '$end_date' ";
$days = round((strtotime($end_date) - strtotime($start_date)) / 86400);
}
$query = "SELECT time::date ,category, CASE WHEN merchant_name !='' THEN merchant_name ELSE description END AS merchant_name , sum(amount) as amount
FROM members_bankimport
WHERE category in ('Taxi', 'ScooterRental', 'RideShare', 'Gas') AND member_id = ${member_id} AND amount>0 AND
" . $filter_date . "
GROUP BY time::date, category, (CASE WHEN merchant_name !='' THEN merchant_name ELSE description END) ORDER BY time DESC;";//echo $query;exit;
error_log($query);
$r = pg_query($db, $query);
if ($r && pg_num_rows($r)) {
while ($f = pg_fetch_assoc($r)) {
if ($itm_count > 0 && $f['category'] == "RideShare") {
// we have email receipts, ignore rideshare transactions
continue;
}
$time_traveled = 0;
if ($f['amount'] > 0) {
if (in_array($f['category'], array('Taxi', 'RideShare'))) {
$time_traveled = (($f['amount'] / 100) - $available_countries[$user_country]['taxi_avg_start'] ) / $available_countries[$user_country]['taxi_avg_fee_per_km'] * $available_countries[$user_country]['taxi_avg_time_per_km'];
$distance = (($f['amount'] / 100) - $available_countries[$user_country]['taxi_avg_start'] ) / $available_countries[$user_country]['taxi_avg_fee_per_km'] * $available_countries[$user_country]['taxi_avg_time_per_km'];
} elseif ($f['category'] == 'ScooterRental') {
$time_traveled = ( ($f['amount'] / 100) - $available_countries[$user_country]['scooter_avg_start'] ) / $available_countries[$user_country]['scooter_avg_min'];
$distance = 0;
} elseif ($f['category'] == 'Gas') {
if (!array_key_exists($f['time'], $gas_transactions)) {
$gas_transactions[$f['time']] = 0;
}
$gas_transactions[$f['time']] += $f['amount'] / 100;
}
}
$detail_line = array("category" => $f["category"], "merchant_name" => $f["merchant_name"], "amount" => $f["amount"], "duration" => ceil($time_traveled), "distance" => 0, "emission" => 0);
if (!array_key_exists($f['time'], $data_result)) {
$data_result[$f['time']] = array(
"date" => $f["time"],
"value" => 0,
"amount" => 0,
"duration" => 0,
"distance" => 0,
"emission" => 0
);
}else{
$data_result[$f["time"]]["duration"] = $data_result[$f["time"]]["duration"] + ceil($time_traveled);
$data_result[$f["time"]]["value"] = $data_result[$f["time"]]["value"] + ceil($time_traveled);
$data_result[$f["time"]]["amount"] = $data_result[$f["time"]]["amount"] + $f["amount"];
$data_result[$f["time"]][$f["time"]][] = $detail_line;
}
}
}
if (count($gas_transactions) > 0) {
// calculate the time traveled based on gas transactions
if (count($gas_transactions) == 1) {
// we have gas refills only in one day, split the amount by total days
$time_per_day = reset($gas_transactions) / $available_countries[$user_country]['gas_price_per_litre'] * $available_countries[$user_country]['time_traveled_per_litre'] / $days;
} else {
// calculate the total gas purchased between first and last gas refill
// and create an average spent by day and use that for all days
error_log('gas_transactions' . json_encode($gas_transactions));
$first_date = reset(array_keys($gas_transactions));
$last_date = end(array_keys($gas_transactions));
$total_amount = 0;
foreach ($gas_transactions as $date => $amount) {
if ($date != $last_date) {
$total_amount += $amount;
}
}
// get the total minutes traveled
$total_travel = $total_amount / $available_countries[$user_country]['gas_price_per_litre'] * $available_countries[$user_country]['time_traveled_per_litre'];
// caluclate the the differece between refills
$f_first_date = new DateTime($first_date);
$f_last_date = new DateTime($last_date);
$interval = date_diff($f_last_date, $f_first_date);
$days_diff = $interval->format("%a");
$time_per_day = $total_travel / $days_diff;
}
// create or update the result array with daily gas data
for ($i = $days; $i > 0; $i--) {
if (!empty($end_date)) {
$dt = date("Y-m-d", strtotime($end_date . "-$i days"));
} else {
$dt = date("Y-m-d", strtotime("-$i days"));
}
if (!array_key_exists($dt, $data_result)) {
$data_result[$dt] = array(
"date" => $dt,
"value" => 0,
"amount" => 0,
"duration" => 0,
"distance" => 0,
"emission" => 0,
);
}
// set the value here
$data_result[$dt]['value'] += intval($time_per_day);
}
}
if (count($data_result) > 0) {
// add zero values for the chart
$total_value = 0;
for ($i = $days; $i > 0; $i--) {
if (!empty($end_date)) {
$dt = date("Y-m-d", strtotime($end_date . "-$i days"));
} else {
$dt = date("Y-m-d", strtotime("-$i days"));
}
if (!array_key_exists($dt, $data_result)) {
$data_result[$dt] = array(
"date" => $dt,
"value" => 0,
"duration" => 0,
"amount" => 0,
"distance" => 0,
"emission" => 0,
);
}
// add value for the new area chart model, increase the value of each day
$total_value += $data_result[$dt]['value'];
$data_result[$dt]['added_value'] = $total_value;
}
ksort($data_result);
}
$cards = Report::GetPageCardData($db, $member_id, 'activity-time-traveled', $member_country);
return [$data_result, ['cards' => $cards]];
}
/*
private function DELETEemissionsByDaysData2($db, $member_id, $days) {
$data = [];
for($ic=0; $ic<$days; $ic++){
$new_date = date('Y-m-d', strtotime("-$ic days"));
array_push($data,array("date" => "$new_date", "value" => rand(0,50)));
}
return [$data, []];
}
private function DELETEemissionsByDaysData1($db, $member_id, $days) {
$data = [
array("date" => "2007-8-10", "value" => 45),
array("date" => "2007-10-15", "value" => 35),
array("date" => "2007-11-13", "value" => 45),
array("date" => "2007-12-12", "value" => 45),
array("date" => "2008-1-13", "value" => 21),
array("date" => "2008-1-15", "value" => 20),
array("date" => "2008-3-24", "value" => 30),
array("date" => "2008-4-26", "value" => 22),
array("date" => "2008-5-27", "value" => 34),
array("date" => "2008-6-30", "value" => 45),
array("date" => "2008-7-1", "value" => 25),
array("date" => "2008-8-10", "value" => 24),
array("date" => "2008-10-15", "value" => 35),
array("date" => "2008-11-13", "value" => 45),
array("date" => "2008-12-12", "value" => 45),
];
return [$data, []];
}
private function DELETEtravelTimeByDaysData1($db, $member_id, $days) {
$data_result = [];
// note we don travel everyday - i am modifying this to last 30 or 60 days - not just date diiference
$q = "SELECT b.travel_date::date, c.category,count(*) AS count, sum(b.cost) AS amount ,sum(b.duration) AS sum_duration
FROM trackedemail_item a, parsedemail_item b, transport_providers c
WHERE a.id=b.trackedemail_item_id AND a.member_id=${member_id} AND c.id=b.transport_provider_id AND b.dup_id IS NULL AND
date_trunc('day', b.travel_date_end) > (current_date - ${days}) AND date_trunc('day', b.travel_date_end) < current_date AND
b.transport_provider_id > 0
GROUP BY b.travel_date::date, c.category ORDER BY b.travel_date::date DESC "; // ${days}
error_log($q);
$r = pg_query($db, $q);
if ($r && pg_num_rows($r)) {
$itm_count = 0;
while ($f = pg_fetch_assoc($r)) {
$detail_line = array("category" => $f["category"], "amount" => $f["amount"], "duration" => $f["sum_duration"]);
$add_line = true;
if ($itm_count > 0) {
if (array_key_exists($f["travel_date"], $data_result)) {
$add_line = false; // dont add new line - modify the current one
$data_result[$f["travel_date"]]["value"] = $data_result[$f["travel_date"]]["value"] + $f["sum_duration"];
$data_result[$f["travel_date"]]["amount"] = $data_result[$f["travel_date"]]["amount"] + $f["amount"];
$data_result[$f["travel_date"]][$f["travel_date"]][] = $detail_line;
}
}
if (true == $add_line) {
$data_line = array(
"date" => $f["travel_date"],
"value" => $f["sum_duration"],
"amount" => $f["amount"],
$f["travel_date"] => $detail_line
);
$data_result[$f["travel_date"]] = $data_line;
}
$itm_count++;
}
}
$optional_message = "Sweet! You’ve spent almost 30 minutes less time on your commute this month!";
$icon = "fast-moving";
$options_data = array('message' => $optional_message, 'icon' => $icon);
return [$data_result, $options_data];
}
*/
private function spendingByCategoryForDays($db, $member_id, $days, $include_items, $start_date = "", $end_date = "", $include_items_values = true, $member_country='') {
$result = [
'RideShare' => 0,
'Taxi' => 0,
//'Scooter' => 0,
'Bus' => 0,
'Subway' => 0,
'Gas' => 0,
'Other' => 0
];
$report_categories = self::REPORT_CATEGORIES;
//$member_id == 3 ||
if ($member_id == 13) {
$days = 90; // DEBUG
}
$fixDays = $days + 1;
$filter_date = " date_trunc('day', time) > (current_date - ${fixDays}) AND date_trunc('day', time) < current_date ";
if (!empty($start_date) && !empty($end_date)) {
$filter_date = " time >= '$start_date' time < '$end_date' ";
$days = round((strtotime($end_date) - strtotime($start_date)) / 86400);
}
// Credit card transations
$q = "SELECT category,count(*) AS count, sum(amount::decimal)/100 AS amount FROM members_bankimport ";
$q .= " WHERE member_id=${member_id} AND LOWER(category) IN (SELECT LOWER(category) FROM activity_listcategory) AND amount>0 AND ";
$q .= $filter_date;
$q .= " GROUP BY category";
$r = pg_query($db, $q);
if ($r && pg_num_rows($r)) {
while ($f = pg_fetch_assoc($r)) {
if (array_key_exists($f['category'], $report_categories)) {
$key = $report_categories[$f['category']];
$result[$key] += $f["amount"];
} else {
$result['Other'] += $f["amount"];
}
}
}
// E-mail receipts
$filter_date = " date_trunc('day', b.travel_date) > (current_date - ${fixDays}) AND date_trunc('day', b.travel_date) < current_date ";
if (!empty($start_date) && !empty($end_date)) {
$filter_date = " travel_date >= '$start_date' AND travel_date < '$end_date' ";
$days = round((strtotime($end_date) - strtotime($start_date)) / 86400);
}
$q = "SELECT c.category,count(*) AS count, sum(b.cost) AS amount ";
$q .= " FROM trackedemail_item a, parsedemail_item b, transport_providers c ";
$q .= " WHERE a.id=b.trackedemail_item_id AND a.member_id=" . $member_id . " AND c.id=b.transport_provider_id AND b.dup_id IS NULL AND";
$q .= $filter_date;
$q .= " GROUP BY c.category";
error_log($q);
$r = pg_query($db, $q);
if ($r && pg_num_rows($r)) {
while ($f = pg_fetch_assoc($r)) {
if (array_key_exists($f['category'], $report_categories)) {
$key = $report_categories[$f['category']];
$result[$key] += $f["amount"];
} else {
$result['Other'] += $f["amount"];
}
}
}
// We do not check for any duplicates!
$res = [
[
'type' => 'RideShare',
'spent' => sprintf("%0.2f", $result['RideShare'])
],
[
'type' => 'Taxi',
'spent' => sprintf("%0.2f", $result['Taxi'])
],
/*
[
'type' => 'Scooter',
'spent' => sprintf("%0.2f",$result['Scooter'])
],
*/
[
'type' => 'Bus',
'spent' => sprintf("%0.2f", $result['Bus'])
],
[
'type' => 'Subway',
'spent' => sprintf("%0.2f", $result['Subway'])
],
[
'type' => 'Gas',
'spent' => sprintf("%0.2f", $result['Gas'])
],
[
'type' => 'Other',
'spent' => sprintf("%0.2f", $result['Other'])
]
];
$options = [];
if ($include_items) {
list($res, $options) = Report::spendingByCategoryForDaysItems($db, $member_id, $days, $res, $report_categories, $start_date, $end_date, $include_items_values, $member_country);
}
return [$res, $options];
}
private function spendingByCategoryForDaysItems($db, $member_id, $days, $result, $report_categories, $start_date = "", $end_date = "", $include_items_values = true, $member_country='') {
$items = [];
$spent = [];
$latest_tip = [];
foreach ($report_categories as $key => $category) {
$items[$category] = [];
$spent[$category] = 0;
}
$spent['Other'] = 0;
$days++;
$items['Other'] = [];
$filter_date = " date_trunc('day', time) > (current_date - ${days}) AND date_trunc('day', time) < current_date ";
if (!empty($start_date) && !empty($end_date)) {
$filter_date = " time >= '$start_date' AND time < '$end_date' ";
$days = 1 + round((strtotime($end_date) - strtotime($start_date)) / 86400);
}
$q = "SELECT * FROM ";
// Credit card transations
$q .= "(SELECT mb.id,'0' AS trackedemail_item_id, import_id, date_trunc('seconds', time) AS travel_date,";
$q .= "'0' AS duration,round(amount::decimal/100,2) as cost,currency, description, '0' AS transport_provider_id,";
$q .= "merchant_name AS transport_provider_name,mb.category,provider_category, 'f' AS advice_processed, NULL as flag,";
$q .= "'0' AS surge_price, '0' AS cheaper_alternative ";
$q .= " FROM members_bankimport mb";
$q .= " inner join activity_listcategory alc on LOWER(alc.category) = lower(mb.category) ";
$q .= " WHERE member_id=${member_id} AND mb.amount>0 AND ";
$q .= $filter_date;
//$q.= " ORDER BY time DESC"; // LIMIT ?
$q .= " UNION ";
// E-mail receipts
$filter_date = " date_trunc('day', pi.travel_date) > (current_date - ${days}) AND date_trunc('day', pi.travel_date) < current_date ";
if (!empty($start_date) && !empty($end_date)) {
$filter_date = " pi.travel_date >= '$start_date' AND pi.travel_date < '$end_date' ";
$days = round((strtotime($end_date) - strtotime($start_date)) / 86400);
}
$q .= " SELECT pi.id, pi.trackedemail_item_id, null as import_id, pi.travel_date, pi.duration, ";
$q .= " pi.cost, pi.cost_raw as currency, tp.name as description, pi.transport_provider_id, ";
$q .= " tp.name AS transport_provider_name, tp.category, tp.category as provider_category, ";
$q .= " pi.advice_processed, ar.flag, ";
$q .= " CASE WHEN sp.id IS NULL THEN '0' ELSE '1' END AS surge_price, ";
$q .= " CASE WHEN (pc.id IS NOT NULL AND pc.cost>pc.average) THEN ROUND(pc.average/pc.cost,2) ELSE 0 END AS cheaper_alternative ";
$q .= " FROM parsedemail_item pi ";
$q .= " inner join trackedemail_item ti on ti.id = pi.trackedemail_item_id and ti.member_id = ${member_id} ";
$q .= " inner join transport_providers tp on tp.id = pi.transport_provider_id ";
$q .= " LEFT JOIN parsedemail_item_advice_result ar ON (ar.parsedemail_item_id=pi.id) ";
$q .= " LEFT JOIN trip_surge_price sp ON (sp.data_source_id=pi.id AND sp.data_source=1) ";
$q .= " LEFT JOIN trip_price_comparison pc ON (pc.data_source_id=pi.id AND pc.data_source=1) ";
$q .= " where pi.dup_id IS NULL AND ";
$q .= $filter_date;
// end email receipts
$q .= ") AS u ORDER BY u.travel_date DESC";
error_log($q);
$r = pg_query($db, $q);
if ($r && pg_num_rows($r)) {
while ($f = pg_fetch_assoc($r)) {
// get the transaction tips here
$f['inline_tips'] = Report::getTransactionTips($f);
if (count($f['inline_tips']) > 0) {
// check if this is the most recent transaction with inline tip
$trip_date = strtotime($f['travel_date']);
if (!isset($latest_tip[$f['category']])) {
$latest_tip[$f['category']] = $trip_date;
}
if ($latest_tip[$f['category']] < $trip_date) {
$latest_tip[$f['category']] == $trip_date;
}
}
if (array_key_exists($f['category'], $report_categories)) {
$key = $report_categories[$f['category']];
$items[$key][] = $f;
$spent[$key] += $f['cost'];
} else {
$items['Other'][] = $f;
$spent['Other'] += $f['cost'];
}
}
}
foreach ($items as $key => $val) {
for ($i = 0; $i < count($result); $i++) {
if ($result[$i]['type'] == $key) {
if ($include_items_values) {
$result[$i]['items'] = $val;
}
$result[$i]['spent'] = sprintf("%0.02f", $spent[$key]);
$result[$i]['latest_tip_time'] = $latest_tip[$key];
break;
}
}
}
/* 'advice_processed' => 'TODO',
'flag' => 'TODO', */
$options = [
'options' => [
'surge_price',
'cheaper_alternative'
],
'surge_price' => [
'text' => 'Surge pricing',
'style' => [
"color" => "#0000ff",
"font-weight" => "normal"
],
'popup' => [
'text' => 'Try to avoid travel during rush hour if possible, or maybe try a scooter.',
'icon' => 'piggy',
'style' => [
"color" => "#78849E",
"background-color" => "#000000",
"font-weight" => "normal"
]
]
],
'cheaper_alternative' => [
'text' => 'Cheaper alternative',
'style' => [
"color" => "#009900",
"font-weight" => "normal"
]
]
];
$options['cards'] = Report::GetPageCardData($db, $member_id, 'activity-monthly-spent', $member_country);
// 10% off with Float
return [$result, $options]; // This needs UI update
//return $result;
}
private function getCategoryItems($db, $member_id, $days, $category, $start_date = "", $end_date = "") {
$reversed_categories = [];
foreach (self::REPORT_CATEGORIES as $key => $val) {
$reversed_categories[$val] = $key;
}
if (array_key_exists($category, $reversed_categories)) {
$category = $reversed_categories[$category];
$category_filter = "LOWER(tp.category) = lower('${category}')";
} else {
$category = "other";
$exclude_values = array_values($reversed_categories);
$exclude_cats = [];
foreach ($exclude_values as $cat) {
$exclude_cats[] = strtolower($cat);
}
$exclude_cats = implode("','", $exclude_cats);
$category_filter = " LOWER(tp.category) NOT IN ( '${exclude_cats}' ) ";
}
$items = [];
$spent = 0;
$latest_tip = [];
$days++;
$filter_date = " date_trunc('day', time) > (current_date - ${days}) AND date_trunc('day', time) < current_date ";
if (!empty($start_date) && !empty($end_date)) {
$filter_date = " time >= '$start_date' AND time < '$end_date' ";
$days = round((strtotime($end_date) - strtotime($start_date)) / 86400);
}
$q = "SELECT * FROM ";
// Credit card transations
$q .= "(SELECT tp.id,'0' AS trackedemail_item_id, import_id, date_trunc('seconds', time) AS travel_date,";
$q .= "'0' AS duration,round(amount::decimal/100,2) as cost,currency, description, '0' AS transport_provider_id,";
$q .= "merchant_name AS transport_provider_name, tp.category,provider_category, 'f' AS advice_processed, NULL as flag,";
$q .= "'0' AS surge_price, '0' AS cheaper_alternative ";
$q .= " FROM members_bankimport tp";
$q .= " inner join activity_listcategory alc on LOWER(alc.category) = lower(tp.category) ";
$q .= " WHERE member_id=${member_id} AND ${category_filter} AND tp.amount>0 AND ";
$q .= $filter_date;
//$q.= " ORDER BY time DESC"; // LIMIT ?
$q .= " UNION ";
// E-mail receipts
$filter_date = " date_trunc('day', pi.travel_date) > (current_date - ${days}) AND date_trunc('day', pi.travel_date) < current_date ";
if (!empty($start_date) && !empty($end_date)) {
$filter_date = " pi.travel_date >= '$start_date' AND pi.travel_date < '$end_date' ";
$days = round((strtotime($end_date) - strtotime($start_date)) / 86400);
}
$q .= " SELECT pi.id, pi.trackedemail_item_id, null as import_id, pi.travel_date, pi.duration, ";
$q .= " pi.cost, pi.cost_raw as currency, tp.name as description, pi.transport_provider_id, ";
$q .= " tp.name AS transport_provider_name, tp.category, tp.category as provider_category, ";
$q .= " pi.advice_processed, ar.flag, ";
$q .= " CASE WHEN sp.id IS NULL THEN '0' ELSE '1' END AS surge_price, ";
$q .= " CASE WHEN (pc.id IS NOT NULL AND pc.cost>pc.average) THEN ROUND(pc.average/pc.cost,2) ELSE 0 END AS cheaper_alternative ";
$q .= " FROM parsedemail_item pi ";
$q .= " inner join trackedemail_item ti on ti.id = pi.trackedemail_item_id and ti.member_id = ${member_id} ";
$q .= " inner join transport_providers tp on tp.id = pi.transport_provider_id ";
$q .= " LEFT JOIN parsedemail_item_advice_result ar ON (ar.parsedemail_item_id=pi.id) ";
$q .= " LEFT JOIN trip_surge_price sp ON (sp.data_source_id=pi.id AND sp.data_source=1) ";
$q .= " LEFT JOIN trip_price_comparison pc ON (pc.data_source_id=pi.id AND pc.data_source=1) ";
$q .= " where pi.dup_id IS NULL AND ${category_filter} AND ";
$q .= $filter_date;
// end email receipts
$q .= ") AS u ORDER BY u.travel_date DESC";
error_log($q);
$r = pg_query($db, $q);
if ($r && pg_num_rows($r)) {
while ($f = pg_fetch_assoc($r)) {
// get the transaction tips here
$f['inline_tips'] = Report::getTransactionTips($f);
$items[] = $f;
$spent += $f['cost'];
}
}
$options = [
'options' => [
'surge_price',
'cheaper_alternative'
],
'surge_price' => [
'text' => 'Surge pricing',
'style' => [
"color" => "#0000ff",
"font-weight" => "normal"
],
'popup' => [
'text' => 'Try to avoid travel during rush hour if possible, or maybe try a scooter.',
'icon' => 'piggy',
'style' => [
"color" => "#78849E",
"background-color" => "#000000",
"font-weight" => "normal"
]
]
],
'cheaper_alternative' => [
'text' => 'Cheaper alternative',
'style' => [
"color" => "#009900",
"font-weight" => "normal"
]
]
];
return [$items, $spent];
}
private function getTransactionTips($transaction) {
$found_tips = array();
// list all the possible triggers here
// the key of the array is the transport provider id, -1 applies to all transactions
$triggers_list = array(
'-1' => array('SurgePriceInlineTip', 'CheaperAlternativeInlineTip'),
'GRAB' => array('GrabSmallTripInlineTip'),
'GOJEK' => array('GojekSmallTripInlineTip'),
'COMFORTDELGRO' => array('ComfortSmallTripInlineTip', 'ComfortLateNightInlineTip',
'ComfortEarlyMorningInlineTip', 'ComfortPeekPeriodInlineTip', 'ComfortCardPaySurgeInlineTip')
);
// get all possible triggers for this transaction
$triggers = $triggers_list['-1'];
if (array_key_exists(strtoupper($transaction['transport_provider_name']), $triggers_list)) {
$triggers = array_merge($triggers, $triggers_list[strtoupper($transaction['transport_provider_name'])]);
}
foreach ($triggers as $trigger) {
// get and instantiate the class for this trigger
$cond_class = new $trigger($transaction);
// apply the condition and get the message if required
if ($cond_class->applyCondition()) {
$found_tips[] = $cond_class->getMessage();
}
}
return $found_tips;
}
}
class InlineTipBase {
public $transaction;
public $title;
public $text;
function __construct($transaction) {
$this->transaction = $transaction;
}
public function getMessage() {
//TODO: improve here
return array(
'title' => $this->title,
'text' => $this->text,
);
}
public function applyCondition() {
return;
}
}
class SurgePriceInlineTip extends InlineTipBase {
public $title = "Surge pricing";
public $text = "Try to avoid travel during rush hour if possible, or maybe try a scooter.";
public function __construct($transaction) {
parent::__construct($transaction);
}
public function applyCondition() {
parent::applyCondition();
if ($this->transaction['surge_price'] == '1') {
return true;
}
return false;
}
}
class CheaperAlternativeInlineTip extends InlineTipBase {
public $title = "Cheaper Alternative";
public $text = "We found some cheaper options for your recent trip.";
public function __construct($transaction) {
parent::__construct($transaction);
}
public function applyCondition() {
parent::applyCondition();
if (floatval($this->transaction['cheaper_alternative']) > 0) {
// we can alter the text here to show a percentage of cheaper alternative
return true;
}
return false;
}
}
class GrabSmallTripInlineTip extends InlineTipBase {
public $title = "Money saving tip";
public $text = "Avoid short rideshare rides, you always get charged a minimum fee of $4 every time you jump in a Grab, no matter where you go.";
public function __construct($transaction) {
parent::__construct($transaction);
}
public function applyCondition() {
parent::applyCondition();
if (strtoupper($this->transaction['transport_provider_name']) == 'GRAB' && floatval($this->transaction['cost']) < 8) {
return true;
}
return false;
}
}
class GojekSmallTripInlineTip extends InlineTipBase {
public $title = "Money saving tip";
public $text = "Avoid short rideshare rides, you always get charged a minimum fee of $6 every time you jump in a GoJek, no matter where you go.";
public function __construct($transaction) {
parent::__construct($transaction);
}
public function applyCondition() {
parent::applyCondition();
if (strtoupper($this->transaction['transport_provider_name']) == 'GOJEK' && floatval($this->transaction['cost']) < 8) {
return true;
}
return false;
}
}
class ComfortSmallTripInlineTip extends InlineTipBase {
public $title = "Money saving tip";
public $text = "Avoid short taxi rides, you always get charged a minimum fee of $6 every time you jump in a Comfort Taxi, no matter where you go.";
public function __construct($transaction) {
parent::__construct($transaction);
}
public function applyCondition() {
parent::applyCondition();
if (strtoupper($this->transaction['transport_provider_name']) == 'COMFORTDELGRO' && floatval($this->transaction['cost']) < 8) {
return true;
}
return false;
}
}
class ComfortLateNightInlineTip extends InlineTipBase {
public $title = "Late night charge";
public $text = "Watch out for late night charges, between midnight and 5:59AM you’ll be stung with a surcharge of 50% of the metered fare with a Comfort Taxi.";
public function __construct($transaction) {
parent::__construct($transaction);
}
public function applyCondition() {
parent::applyCondition();
// check the transaction time
$time = date("H:i:s", strtotime($this->transaction['travel_date']));
$time = DateTime::createFromFormat('H:i:s', $time);
$start = DateTime::createFromFormat('H:i a', "12:00 am");
$end = DateTime::createFromFormat('H:i a', "5:59 am");
// only comfort email transactions between 12am and 6am
if (strtoupper($this->transaction['transport_provider_name']) == 'COMFORTDELGRO' && intval($this->transaction['trackedemail_item_id']) > 0 && $time > $start && $time < $end) {
return true;
}
return false;
}
}
class ComfortEarlyMorningInlineTip extends InlineTipBase {
public $title = "Late night charge";
public $text = "Watch out for peak period charges, between 6AM and 9:29AM you’ll be stung with a surcharge 25% of the metered fare with a Comfort Taxi";
public function __construct($transaction) {
parent::__construct($transaction);
}
public function applyCondition() {
parent::applyCondition();
// check the transaction time
$time = date("H:i:s", strtotime($this->transaction['travel_date']));
$time = DateTime::createFromFormat('H:i:s', $time);
$start = DateTime::createFromFormat('H:i a', "6:00 am");
$end = DateTime::createFromFormat('H:i a', "9:39 am");
// only comfort email transactions between 6am and 9:40 am
if (strtoupper($this->transaction['transport_provider_name']) == 'COMFORTDELGRO' && intval($this->transaction['trackedemail_item_id']) > 0 && $time > $start && $time < $end) {
return true;
}
return false;
}
}
class ComfortPeekPeriodInlineTip extends InlineTipBase {
public $title = "Late night charge";
public $text = "Watch out for peak period charges, between 6PM and 11:59PM you’ll be stung with a surcharge 25% of the metered fare with a Comfort Taxi";
public function __construct($transaction) {
parent::__construct($transaction);
}
public function applyCondition() {
parent::applyCondition();
// check the transaction time
$time = date("H:i:s", strtotime($this->transaction['travel_date']));
$time = DateTime::createFromFormat('H:i:s', $time);
$start = DateTime::createFromFormat('H:i a', "6:00 pm");
$end = DateTime::createFromFormat('H:i a', "11:59 pm");
// only comfort email transactions between 12am and 6am
if (strtoupper($this->transaction['transport_provider_name']) == 'COMFORTDELGRO' && intval($this->transaction['trackedemail_item_id']) > 0 && $time > $start && $time < $end) {
return true;
}
return false;
}
}
class ComfortCardPaySurgeInlineTip extends InlineTipBase {
public $title = "Surcharge Alert";
public $text = "Be careful how you pay, credit and charge card payments get hit with a 10% surcharge in a Comfort Taxi";
public function __construct($transaction) {
parent::__construct($transaction);
}
public function applyCondition() {
parent::applyCondition();
// only comfort email transactions between 12am and 6am
if (strtoupper($this->transaction['transport_provider_name']) == 'COMFORTDELGRO' && intval($this->transaction['trackedemail_item_id']) == 0) {
return true;
}
return false;
}
}
// vi:ts=2