AGPLv2 # # This remake preserves every original SQL query verbatim against the # Vicidial DB (vicidial_users, vicidial_agent_log[_archive], vicidial_campaigns, # vicidial_user_groups, vicidial_live_agents, system_settings, vicidial_webservers, # vicidial_report_log) and only replaces the presentation layer. # # Drops the original ASCII
output, vicidial_stylesheet.php, admin_header.php,
# chart_button.php, graphcanvas.inc, graph_color_schemas.inc, calendar_db.js, help.js,
# horizontalbargraph.css and the bundled chart/Chart.js. Uses Chart.js via CDN.
$startMS = microtime();
require("dbconnect_mysqli.php");
require("functions.php");
# ─────────────────────────────────────────────────────────────────────────────
# Parameter intake (preserved from original)
# ─────────────────────────────────────────────────────────────────────────────
$PHP_AUTH_USER = $_SERVER['PHP_AUTH_USER'];
$PHP_AUTH_PW = $_SERVER['PHP_AUTH_PW'];
$PHP_SELF = $_SERVER['PHP_SELF'];
$PHP_SELF = preg_replace('/\.php.*/i', '.php', $PHP_SELF);
if (isset($_GET["query_date"])) {$query_date=$_GET["query_date"];}
elseif (isset($_POST["query_date"])) {$query_date=$_POST["query_date"];}
if (isset($_GET["end_date"])) {$end_date=$_GET["end_date"];}
elseif (isset($_POST["end_date"])) {$end_date=$_POST["end_date"];}
if (isset($_GET["query_time"])) {$query_time=$_GET["query_time"];}
elseif (isset($_POST["query_time"])) {$query_time=$_POST["query_time"];}
if (isset($_GET["end_time"])) {$end_time=$_GET["end_time"];}
elseif (isset($_POST["end_time"])) {$end_time=$_POST["end_time"];}
if (isset($_GET["group"])) {$group=$_GET["group"];}
elseif (isset($_POST["group"])) {$group=$_POST["group"];}
if (isset($_GET["user_group"])) {$user_group=$_GET["user_group"];}
elseif (isset($_POST["user_group"])) {$user_group=$_POST["user_group"];}
if (isset($_GET["users"])) {$users=$_GET["users"];}
elseif (isset($_POST["users"])) {$users=$_POST["users"];}
if (isset($_GET["shift"])) {$shift=$_GET["shift"];}
elseif (isset($_POST["shift"])) {$shift=$_POST["shift"];}
if (isset($_GET["stage"])) {$stage=$_GET["stage"];}
elseif (isset($_POST["stage"])) {$stage=$_POST["stage"];}
if (isset($_GET["DB"])) {$DB=$_GET["DB"];}
elseif (isset($_POST["DB"])) {$DB=$_POST["DB"];}
if (isset($_GET["SUBMIT"])) {$SUBMIT=$_GET["SUBMIT"];}
elseif (isset($_POST["SUBMIT"])) {$SUBMIT=$_POST["SUBMIT"];}
if (isset($_GET["file_download"])) {$file_download=$_GET["file_download"];}
elseif (isset($_POST["file_download"])){$file_download=$_POST["file_download"];}
if (isset($_GET["live_agents"])) {$live_agents=$_GET["live_agents"];}
elseif (isset($_POST["live_agents"])) {$live_agents=$_POST["live_agents"];}
if (isset($_GET["show_percentages"])) {$show_percentages=$_GET["show_percentages"];}
elseif (isset($_POST["show_percentages"])){$show_percentages=$_POST["show_percentages"];}
if (isset($_GET["time_in_sec"])) {$time_in_sec=$_GET["time_in_sec"];}
elseif (isset($_POST["time_in_sec"])) {$time_in_sec=$_POST["time_in_sec"];}
if (isset($_GET["breakdown_by_date"])) {$breakdown_by_date=$_GET["breakdown_by_date"];}
elseif (isset($_POST["breakdown_by_date"])){$breakdown_by_date=$_POST["breakdown_by_date"];}
if (isset($_GET["search_archived_data"])) {$search_archived_data=$_GET["search_archived_data"];}
elseif (isset($_POST["search_archived_data"])){$search_archived_data=$_POST["search_archived_data"];}
if (isset($_GET["show_defunct_users"])) {$show_defunct_users=$_GET["show_defunct_users"];}
elseif (isset($_POST["show_defunct_users"])){$show_defunct_users=$_POST["show_defunct_users"];}
$DB = preg_replace("/[^0-9a-zA-Z]/", "", $DB);
$NOW_DATE = date("Y-m-d");
$NOW_TIME = date("Y-m-d H:i:s");
if (!is_array($group)) {$group = array();}
if (!is_array($user_group)) {$user_group = array();}
if (!is_array($users)) {$users = array();}
if (!isset($query_date)) {$query_date = $NOW_DATE;}
if (!isset($end_date)) {$end_date = $NOW_DATE;}
if (!isset($query_time)) {$query_time = "00:00:00";}
if (!isset($end_time)) {$end_time = "23:59:59";}
if (strlen($shift) < 2) {$shift = '--';}
$report_name = 'Agent Performance Detail';
$db_source = 'M';
# ─────────────────────────────────────────────────────────────────────────────
# system_settings lookup (verbatim)
# ─────────────────────────────────────────────────────────────────────────────
$stmt = "SELECT use_non_latin,outbound_autodial_active,slave_db_server,reports_use_slave_db,enable_languages,language_method,report_default_format,allow_web_debug FROM system_settings;";
$rslt = mysql_to_mysqli($stmt, $link);
if (mysqli_num_rows($rslt) > 0) {
$row = mysqli_fetch_row($rslt);
$non_latin = $row[0];
$outbound_autodial_active = $row[1];
$slave_db_server = $row[2];
$reports_use_slave_db = $row[3];
$SSenable_languages = $row[4];
$SSlanguage_method = $row[5];
$SSreport_default_format= $row[6];
$SSallow_web_debug = $row[7];
}
if ($SSallow_web_debug < 1) {$DB = 0;}
# Sanitization (verbatim)
$query_date = preg_replace('/[^- \:\_0-9a-zA-Z]/', '', $query_date);
$end_date = preg_replace('/[^- \:\_0-9a-zA-Z]/', '', $end_date);
$query_time = preg_replace('/[^- \:\_0-9a-zA-Z]/', '', $query_time);
$end_time = preg_replace('/[^- \:\_0-9a-zA-Z]/', '', $end_time);
$SUBMIT = preg_replace('/[^-_0-9a-zA-Z]/', '', $SUBMIT);
$file_download = preg_replace('/[^-_0-9a-zA-Z]/', '', $file_download);
$search_archived_data = preg_replace('/[^-_0-9a-zA-Z]/', '', $search_archived_data);
$stage = preg_replace('/[^-_0-9a-zA-Z]/', '', $stage);
$show_percentages = preg_replace('/[^-_0-9a-zA-Z]/', '', $show_percentages);
$time_in_sec = preg_replace('/[^-_0-9a-zA-Z]/', '', $time_in_sec);
$live_agents = preg_replace('/[^-_0-9a-zA-Z]/', '', $live_agents);
$breakdown_by_date = preg_replace('/[^-_0-9a-zA-Z]/', '', $breakdown_by_date);
$show_defunct_users = preg_replace('/[^-_0-9a-zA-Z]/', '', $show_defunct_users);
if ($non_latin < 1) {
$PHP_AUTH_USER = preg_replace('/[^-_0-9a-zA-Z]/', '', $PHP_AUTH_USER);
$PHP_AUTH_PW = preg_replace('/[^-_0-9a-zA-Z]/', '', $PHP_AUTH_PW);
$shift = preg_replace('/[^-_0-9a-zA-Z]/', '', $shift);
} else {
$PHP_AUTH_USER = preg_replace('/[^-_0-9\p{L}]/u', '', $PHP_AUTH_USER);
$PHP_AUTH_PW = preg_replace('/[^-_0-9\p{L}]/u', '', $PHP_AUTH_PW);
$shift = preg_replace('/[^-_0-9\p{L}]/u', '', $shift);
}
# Time format flag for sec_convert (preserved)
$TIME_H_apd = 'H';
$TIME_M_apd = 'M';
if ($file_download == 1 || $file_download == 2) {
$TIME_H_apd = 'HF';
$TIME_M_apd = 'HF';
}
if ($time_in_sec) {
$TIME_H_apd = 'S';
$TIME_M_apd = 'S';
}
$agent_log_table = ($search_archived_data == "checked") ? "vicidial_agent_log_archive" : "vicidial_agent_log";
# ─────────────────────────────────────────────────────────────────────────────
# Auth (verbatim)
# ─────────────────────────────────────────────────────────────────────────────
$auth = 0; $reports_auth = 0; $admin_auth = 0;
$auth_message = user_authorization($PHP_AUTH_USER, $PHP_AUTH_PW, 'REPORTS', 1, 0);
if ($auth_message == 'GOOD') {$auth = 1;}
if ($auth > 0) {
$stmt = "SELECT count(*) from vicidial_users where user='$PHP_AUTH_USER' and user_level > 7 and view_reports='1';";
$rslt = mysql_to_mysqli($stmt, $link);
$row = mysqli_fetch_row($rslt); $admin_auth = $row[0];
$stmt = "SELECT count(*) from vicidial_users where user='$PHP_AUTH_USER' and user_level > 6 and view_reports='1';";
$rslt = mysql_to_mysqli($stmt, $link);
$row = mysqli_fetch_row($rslt); $reports_auth = $row[0];
if ($reports_auth < 1) {
Header("Content-type: text/html; charset=utf-8");
echo "You are not allowed to view reports: |$PHP_AUTH_USER|$auth_message|\n";
exit;
}
} else {
if ($auth_message == 'LOCK') {
Header("Content-type: text/html; charset=utf-8");
echo "Too many login attempts, try again in 15 minutes: |$PHP_AUTH_USER|$auth_message|\n";
exit;
}
if ($auth_message == 'IPBLOCK') {
Header("Content-type: text/html; charset=utf-8");
echo "Your IP Address is not allowed: |$PHP_AUTH_USER|$auth_message|\n";
exit;
}
Header("WWW-Authenticate: Basic realm=\"CONTACT-CENTER-ADMIN\"");
Header("HTTP/1.0 401 Unauthorized");
echo "Login incorrect, please try again: |$PHP_AUTH_USER|$PHP_AUTH_PW|$auth_message|\n";
exit;
}
# ─────────────────────────────────────────────────────────────────────────────
# Report log entry (verbatim)
# ─────────────────────────────────────────────────────────────────────────────
$LOGip = getenv("REMOTE_ADDR");
$LOGbrowser = getenv("HTTP_USER_AGENT");
$LOGscript_name = getenv("SCRIPT_NAME");
$LOGserver_name = getenv("SERVER_NAME");
$LOGserver_port = getenv("SERVER_PORT");
$LOGrequest_uri = getenv("REQUEST_URI");
$LOGhttp_referer= getenv("HTTP_REFERER");
$LOGbrowser = preg_replace("/<|>|\'|\"|\\\\/", "", $LOGbrowser);
$LOGrequest_uri = preg_replace("/<|>|\'|\"|\\\\/", "", $LOGrequest_uri);
$LOGhttp_referer= preg_replace("/<|>|\'|\"|\\\\/", "", $LOGhttp_referer);
$HTTPprotocol = preg_match("/443/i", $LOGserver_port) ? 'https://' : 'http://';
$portStr = (($LOGserver_port == '80') || ($LOGserver_port == '443')) ? '' : ":$LOGserver_port";
$LOGfull_url = "$HTTPprotocol$LOGserver_name$portStr$LOGrequest_uri";
$LOGhostname = php_uname('n');
if (strlen($LOGhostname) < 1) {$LOGhostname = 'X';}
if (strlen($LOGserver_name) < 1) {$LOGserver_name = 'X';}
$stmt = "SELECT webserver_id FROM vicidial_webservers where webserver='$LOGserver_name' and hostname='$LOGhostname' LIMIT 1;";
$rslt = mysql_to_mysqli($stmt, $link);
if (mysqli_num_rows($rslt) > 0) {
$row = mysqli_fetch_row($rslt); $webserver_id = $row[0];
} else {
$stmt = "INSERT INTO vicidial_webservers (webserver,hostname) values('$LOGserver_name','$LOGhostname');";
mysql_to_mysqli($stmt, $link);
$webserver_id = mysqli_insert_id($link);
}
$stmt = "INSERT INTO vicidial_report_log set event_date=NOW(), user='$PHP_AUTH_USER', ip_address='$LOGip', report_name='$report_name', browser='$LOGbrowser', referer='$LOGhttp_referer', notes='$LOGserver_name:$LOGserver_port $LOGscript_name |$query_date, $end_date, $shift, $file_download|', url='$LOGfull_url', webserver='$webserver_id';";
mysql_to_mysqli($stmt, $link);
$report_log_id = mysqli_insert_id($link);
# Slave DB switch (verbatim)
if ((strlen($slave_db_server) > 5) && (preg_match("/$report_name/", $reports_use_slave_db))) {
mysqli_close($link);
$use_slave_server = 1;
$db_source = 'S';
require("dbconnect_mysqli.php");
}
# User group / campaign access (verbatim)
$stmt = "SELECT user_group from vicidial_users where user='$PHP_AUTH_USER';";
$rslt = mysql_to_mysqli($stmt, $link);
$row = mysqli_fetch_row($rslt);
$LOGuser_group = $row[0];
$stmt = "SELECT allowed_campaigns,allowed_reports,admin_viewable_groups,admin_viewable_call_times from vicidial_user_groups where user_group='$LOGuser_group';";
$rslt = mysql_to_mysqli($stmt, $link);
$row = mysqli_fetch_row($rslt);
$LOGallowed_campaigns = $row[0];
$LOGallowed_reports = $row[1];
$LOGadmin_viewable_groups = $row[2];
$LOGadmin_viewable_call_times= $row[3];
if ((!preg_match("/$report_name/", $LOGallowed_reports)) && (!preg_match("/ALL REPORTS/", $LOGallowed_reports))) {
Header("WWW-Authenticate: Basic realm=\"CONTACT-CENTER-ADMIN\"");
Header("HTTP/1.0 401 Unauthorized");
echo "You are not allowed to view this report: |$PHP_AUTH_USER|$report_name|\n";
exit;
}
$LOGallowed_campaignsSQL = ''; $whereLOGallowed_campaignsSQL = '';
if (!preg_match('/\-ALL/i', $LOGallowed_campaigns)) {
$rawLOGallowed_campaignsSQL = preg_replace("/ -/", '', $LOGallowed_campaigns);
$rawLOGallowed_campaignsSQL = preg_replace("/ /", "','", $rawLOGallowed_campaignsSQL);
$LOGallowed_campaignsSQL = "and campaign_id IN('$rawLOGallowed_campaignsSQL')";
$whereLOGallowed_campaignsSQL = "where campaign_id IN('$rawLOGallowed_campaignsSQL')";
}
$regexLOGallowed_campaigns = " $LOGallowed_campaigns ";
$LOGadmin_viewable_groupsSQL = ''; $whereLOGadmin_viewable_groupsSQL = '';
if ((!preg_match('/\-\-ALL\-\-/i', $LOGadmin_viewable_groups)) && (strlen($LOGadmin_viewable_groups) > 3)) {
$rawLOGadmin_viewable_groupsSQL = preg_replace("/ -/", '', $LOGadmin_viewable_groups);
$rawLOGadmin_viewable_groupsSQL = preg_replace("/ /", "','", $rawLOGadmin_viewable_groupsSQL);
$LOGadmin_viewable_groupsSQL = "and user_group IN('---ALL---','$rawLOGadmin_viewable_groupsSQL')";
$whereLOGadmin_viewable_groupsSQL = "where user_group IN('---ALL---','$rawLOGadmin_viewable_groupsSQL')";
}
# Build group/user filter strings (verbatim logic)
$group_string = '|'; $group_ct = count($group);
for ($i = 0; $i < $group_ct; $i++) {
$group[$i] = preg_replace('/[^-_0-9\p{L}]/u', '', $group[$i]);
$group_string .= "$group[$i]|";
}
$users_string = '|'; $users_ct = count($users);
for ($i = 0; $i < $users_ct; $i++) {
$users[$i] = preg_replace('/[^-_0-9\p{L}]/u', '', $users[$i]);
$users_string .= "$users[$i]|";
}
# Populate selectors (verbatim queries)
$stmt = "SELECT campaign_id from vicidial_campaigns $whereLOGallowed_campaignsSQL order by campaign_id;";
$rslt = mysql_to_mysqli($stmt, $link);
$campaigns_to_print = mysqli_num_rows($rslt);
$groups = array();
for ($i = 0; $i < $campaigns_to_print; $i++) {
$row = mysqli_fetch_row($rslt);
$groups[$i] = $row[0];
if (preg_match('/\-ALL/', $group_string)) {$group[$i] = $groups[$i];}
}
$stmt = "SELECT user_group from vicidial_user_groups $whereLOGadmin_viewable_groupsSQL order by user_group;";
$rslt = mysql_to_mysqli($stmt, $link);
$user_groups_to_print = mysqli_num_rows($rslt);
$allowed_user_groups = array(); $all_user_groups = 0;
for ($i = 0; $i < count($user_group); $i++) {
if (preg_match('/\-\-ALL\-\-/', $user_group[$i])) {$all_user_groups = 1;}
}
for ($i = 0; $i < $user_groups_to_print; $i++) {
$row = mysqli_fetch_row($rslt);
$allowed_user_groups[$i] = $row[0];
if ($all_user_groups) {$user_group[$i] = $row[0];}
}
$stmt = "SELECT user, full_name from vicidial_users $whereLOGadmin_viewable_groupsSQL order by user";
$rslt = mysql_to_mysqli($stmt, $link);
$users_to_print = mysqli_num_rows($rslt);
$user_list = array(); $user_names = array();
for ($i = 0; $i < $users_to_print; $i++) {
$row = mysqli_fetch_row($rslt);
$user_list[$i] = $row[0];
$user_names[$i] = $row[1];
}
# Resolve campaign/user-group/user SQL clauses (verbatim)
$group_string = '|'; $group_SQL = ''; $groupQS = '';
for ($i = 0; $i < $group_ct; $i++) {
$group[$i] = preg_replace('/[^-_0-9\p{L}]/u', '', $group[$i]);
if ((preg_match("/ $group[$i] /", $regexLOGallowed_campaigns)) || (preg_match("/-ALL/", $LOGallowed_campaigns))) {
$group_string .= "$group[$i]|";
$group_SQL .= "'$group[$i]',";
$groupQS .= "&group[]=$group[$i]";
}
}
if ((preg_match('/\-\-ALL\-\-/', $group_string)) || ($group_ct < 1)) {
$group_SQL = "";
} else {
$group_SQL = preg_replace('/,$/i', '', $group_SQL);
$group_SQL = "and campaign_id IN($group_SQL)";
}
$user_group_string = '|'; $user_group_SQL = ''; $user_groupQS = '';
$user_group_ct = count($user_group);
for ($i = 0; $i < $user_group_ct; $i++) {
$user_group[$i] = preg_replace('/[^-_0-9\p{L}]/u', '', $user_group[$i]);
$user_group_string .= "$user_group[$i]|";
$user_group_SQL .= "'$user_group[$i]',";
$user_groupQS .= "&user_group[]=$user_group[$i]";
}
if ((preg_match('/\-\-ALL\-\-/', $user_group_string)) || ($user_group_ct < 1)) {
$user_group_SQL = ""; $user_groupQS = "";
$user_groups_ct = count($allowed_user_groups);
for ($i = 0; $i < $user_groups_ct; $i++) {
$user_group_SQL .= "'$allowed_user_groups[$i]',";
$user_groupQS .= "&user_group[]=$allowed_user_groups[$i]";
}
$user_group_SQL = preg_replace('/,$/i', '', $user_group_SQL);
$user_group_agent_log_SQL = "and ".$agent_log_table.".user_group IN($user_group_SQL)";
$user_group_SQL = "and vicidial_users.user_group IN($user_group_SQL)";
} else {
$user_group_SQL = preg_replace('/,$/i', '', $user_group_SQL);
$user_group_agent_log_SQL = "and ".$agent_log_table.".user_group IN($user_group_SQL)";
$user_group_SQL = "and vicidial_users.user_group IN($user_group_SQL)";
}
$user_string = '|'; $user_SQL = ''; $userQS = '';
$user_ct = count($users);
for ($i = 0; $i < $user_ct; $i++) {
$users[$i] = preg_replace('/[^-_0-9\p{L}]/u', '', $users[$i]);
$user_string .= "$users[$i]|";
$user_SQL .= "'$users[$i]',";
$userQS .= "&users[]=$users[$i]";
}
if ((preg_match('/\-\-ALL\-\-/', $user_string)) || ($user_ct < 1)) {
$user_SQL = ""; $user_agent_log_SQL = "";
} else {
$user_SQL = preg_replace('/,$/i', '', $user_SQL);
$user_agent_log_SQL = "and ".$agent_log_table.".user IN($user_SQL)";
$user_SQL = "and vicidial_users.user IN($user_SQL)";
}
# Shift time resolution (verbatim, with screen_colors providing $AM_shift_BEGIN etc.)
@require("screen_colors.php");
$time_BEGIN = $query_time;
$time_END = $end_time;
if ($shift == 'AM') {
$time_BEGIN = $AM_shift_BEGIN; $time_END = $AM_shift_END;
if (strlen($time_BEGIN) < 6) {$time_BEGIN = "03:45:00";}
if (strlen($time_END) < 6) {$time_END = "15:14:59";}
}
if ($shift == 'PM') {
$time_BEGIN = $PM_shift_BEGIN; $time_END = $PM_shift_END;
if (strlen($time_BEGIN) < 6) {$time_BEGIN = "15:15:00";}
if (strlen($time_END) < 6) {$time_END = "23:15:00";}
}
if ($shift == 'ALL') {$time_BEGIN = "00:00:00"; $time_END = "23:59:59";}
$query_date_BEGIN = "$query_date $time_BEGIN";
$query_date_END = "$end_date $time_END";
# ─────────────────────────────────────────────────────────────────────────────
# Data collection — only when a campaign is selected
# ─────────────────────────────────────────────────────────────────────────────
$has_data = !empty($group);
# Initialize accumulators that will populate the UI
$report_rows = array(); # Per-agent rows (Section 1)
$status_codes = array(); # Distinct statuses encountered (sorted)
$daily_breakdown = array(); # [user][date] = aggregates (when breakdown_by_date)
$pause_rows = array(); # Per-agent rows (Section 2)
$pause_codes = array(); # Distinct pause sub_statuses
$TOTcalls = 0; $TOTtime = 0;
$TOTtotTALK = 0; $TOTtotWAIT = 0; $TOTtotPAUSE = 0;
$TOTtotDISPO = 0; $TOTtotDEAD = 0; $TOTtotCUSTOMER = 0;
$status_totals = array(); # status => total calls
$pcode_totals = array(); # sub_status => total pause sec
$TOTtotNONPAUSE = 0; $TOTtotTOTAL = 0; $TOTtotPAUSE_pcs = 0;
if ($has_data) {
# Live agents filter (verbatim)
$live_agents_ary = array();
$live_user_SQL = ""; $live_user_SQLvu = "";
if ($live_agents) {
$active_stmt = "SELECT user from vicidial_live_agents";
$active_rslt = mysql_to_mysqli($active_stmt, $link);
while ($active_row = mysqli_fetch_row($active_rslt)) {
$live_agents_ary[] = $active_row[0];
}
if (!empty($live_agents_ary)) {
$live_user_SQL = " and user in ('".implode("','", $live_agents_ary)."') ";
$live_user_SQLvu = " and vicidial_users.user in ('".implode("','", $live_agents_ary)."') ";
}
}
# Most recent user_group per agent (verbatim)
$recent_UG_stmt = "SELECT max(agent_log_id), user from ".$agent_log_table." where event_time <= '$query_date_END' and event_time >= '$query_date_BEGIN' and pause_sec<65000 and wait_sec<65000 and talk_sec<65000 and dispo_sec<65000 $group_SQL $user_group_agent_log_SQL $user_agent_log_SQL group by user";
$recent_UG_rslt = mysql_to_mysqli($recent_UG_stmt, $link);
$recent_user_groups = array();
while ($UG_row = mysqli_fetch_row($recent_UG_rslt)) {
$agent_log_id = $UG_row[0];
$al_stmt = "SELECT user_group from ".$agent_log_table." where agent_log_id='$agent_log_id'";
$al_rslt = mysql_to_mysqli($al_stmt, $link);
$Ugrp_row = mysqli_fetch_row($al_rslt);
$recent_user_groups[$UG_row[1]] = $Ugrp_row[0];
}
# Distinct users (verbatim)
if ($show_defunct_users == "checked") {
$user_stmt = "SELECT distinct '' as full_name, user from ".$agent_log_table." where event_time <= '$query_date_END' and event_time >= '$query_date_BEGIN' $live_user_SQL $group_SQL $user_agent_log_SQL order by user asc";
} else {
$user_stmt = "SELECT distinct full_name,vicidial_users.user,vicidial_users.user_group from vicidial_users,".$agent_log_table." where event_time <= '$query_date_END' and event_time >= '$query_date_BEGIN' and vicidial_users.user=".$agent_log_table.".user $live_user_SQLvu $group_SQL $user_group_SQL $user_agent_log_SQL order by full_name asc";
}
$user_rslt = mysql_to_mysqli($user_stmt, $link);
$usersARY = array(); $user_namesARY = array(); $user_groupsARY = array();
$seen_users = '-';
while ($user_row = mysqli_fetch_row($user_rslt)) {
if ($show_defunct_users == "checked") {
$du_rslt = mysql_to_mysqli("SELECT full_name, user_group from vicidial_users where user='$user_row[1]'", $link);
if (mysqli_num_rows($du_rslt) > 0) {
$du_row = mysqli_fetch_row($du_rslt);
$full_name_val = $du_row[0]; $user_group_val = $du_row[1];
} else {
$full_name_val = $user_row[1]; $user_group_val = "** NONE **";
}
} else {
$full_name_val = $user_row[0];
$user_group_val = $user_row[2];
}
$u = $user_row[1];
if (!preg_match("/\-$u\-/i", $seen_users)) {
$seen_users .= "$u-";
$usersARY[] = $u;
$user_namesARY[]= $full_name_val;
$user_groupsARY[]= $user_group_val;
}
}
# Distinct statuses (verbatim)
if ($show_defunct_users == "checked") {
$stat_stmt = "SELECT distinct status from ".$agent_log_table." where event_time <= '$query_date_END' and event_time >= '$query_date_BEGIN' and pause_sec<65000 and wait_sec<65000 and talk_sec<65000 and dispo_sec<65000 $live_user_SQL $group_SQL $user_agent_log_SQL order by status asc";
} else {
$stat_stmt = "SELECT distinct status from vicidial_users,".$agent_log_table." where event_time <= '$query_date_END' and event_time >= '$query_date_BEGIN' and vicidial_users.user=".$agent_log_table.".user and pause_sec<65000 and wait_sec<65000 and talk_sec<65000 and dispo_sec<65000 $live_user_SQLvu $group_SQL $user_group_SQL $user_SQL order by status asc";
}
$stat_rslt = mysql_to_mysqli($stat_stmt, $link);
# Per-status aggregate query (verbatim) — collected into flat row list
$statRows = array(); # one entry per (user, status) combo
while ($stat_row = mysqli_fetch_row($stat_rslt)) {
$current_status = $stat_row[0];
if (strlen($current_status) > 0 && !in_array($current_status, $status_codes)) {
$status_codes[] = $current_status;
}
if ($show_defunct_users == "checked") {
$stmt = "SELECT count(*) as calls,sum(talk_sec) as talk,'' as full_name,user,sum(pause_sec),sum(wait_sec),sum(dispo_sec),status,sum(dead_sec), '' as user_group,date(event_time) as call_date from ".$agent_log_table." where event_time <= '$query_date_END' and event_time >= '$query_date_BEGIN' and pause_sec<65000 and wait_sec<65000 and talk_sec<65000 and dispo_sec<65000 and status='$current_status' $live_user_SQL $group_SQL $user_agent_log_SQL group by user,full_name,user_group,status,call_date order by full_name,user,status desc limit 500000;";
} else {
$stmt = "SELECT count(*) as calls,sum(talk_sec) as talk,full_name,vicidial_users.user,sum(pause_sec),sum(wait_sec),sum(dispo_sec),status,sum(dead_sec), vicidial_users.user_group,date(event_time) as call_date from vicidial_users,".$agent_log_table." where event_time <= '$query_date_END' and event_time >= '$query_date_BEGIN' and vicidial_users.user=".$agent_log_table.".user and pause_sec<65000 and wait_sec<65000 and talk_sec<65000 and dispo_sec<65000 and status='$current_status' $live_user_SQLvu $group_SQL $user_group_SQL $user_SQL group by user,full_name,user_group,status order by full_name,user,status desc limit 500000;";
}
$rslt = mysql_to_mysqli($stmt, $link);
while ($row = mysqli_fetch_row($rslt)) {
$statRows[] = array(
'calls' => (int)$row[0],
'talk_sec' => (int)$row[1],
'full_name' => $row[2],
'user' => $row[3],
'pause_sec' => (int)$row[4],
'wait_sec' => (int)$row[5],
'dispo_sec' => (int)$row[6],
'status' => strtoupper($row[7]),
'dead_sec' => (int)$row[8],
'user_group' => $row[9],
'call_date' => $row[10],
'customer_sec' => max(0, ((int)$row[1] - (int)$row[8])),
);
}
}
sort($status_codes); # Alphabetical statuses
# Aggregate per agent — feeds Section 1 table + KPIs + charts
foreach ($usersARY as $idx => $u) {
$row = array(
'user' => $u,
'full_name' => $user_namesARY[$idx],
'user_group' => $user_groupsARY[$idx],
'last_user_group' => isset($recent_user_groups[$u]) ? $recent_user_groups[$u] : '',
'calls' => 0,
'talk_sec' => 0,
'pause_sec' => 0,
'wait_sec' => 0,
'dispo_sec' => 0,
'dead_sec' => 0,
'customer_sec' => 0,
'status_calls' => array(),
);
foreach ($status_codes as $s) {$row['status_calls'][$s] = 0;}
foreach ($statRows as $sr) {
if ($sr['user'] !== $u) continue;
$row['calls'] += $sr['calls'];
$row['talk_sec'] += $sr['talk_sec'];
$row['pause_sec'] += $sr['pause_sec'];
$row['wait_sec'] += $sr['wait_sec'];
$row['dispo_sec'] += $sr['dispo_sec'];
$row['dead_sec'] += $sr['dead_sec'];
$row['customer_sec'] += $sr['customer_sec'];
if (isset($row['status_calls'][$sr['status']])) {
$row['status_calls'][$sr['status']] += $sr['calls'];
}
}
$row['login_sec'] = $row['talk_sec'] + $row['pause_sec'] + $row['wait_sec'] + $row['dispo_sec'];
$report_rows[] = $row;
$TOTcalls += $row['calls'];
$TOTtime += $row['login_sec'];
$TOTtotTALK += $row['talk_sec'];
$TOTtotWAIT += $row['wait_sec'];
$TOTtotPAUSE += $row['pause_sec'];
$TOTtotDISPO += $row['dispo_sec'];
$TOTtotDEAD += $row['dead_sec'];
$TOTtotCUSTOMER += $row['customer_sec'];
}
# Status totals across all agents
foreach ($status_codes as $s) {
$tot = 0;
foreach ($report_rows as $r) {$tot += $r['status_calls'][$s];}
$status_totals[$s] = $tot;
}
# Optional per-date breakdown (verbatim queries inside loop)
if ($breakdown_by_date) {
foreach ($report_rows as $rr) {
$Suser = $rr['user'];
$date_stmt = "select date(event_time) as call_date, sum(if(lead_id is null, 0, 1)) as calls from ".$agent_log_table." where event_time <= '$query_date_END' and event_time >= '$query_date_BEGIN' and user='$Suser' and pause_sec<65000 and wait_sec<65000 and talk_sec<65000 and dispo_sec<65000 $group_SQL $user_group_agent_log_SQL $user_agent_log_SQL group by call_date order by call_date asc limit 500000;";
$date_rslt = mysql_to_mysqli($date_stmt, $link);
while ($date_row = mysqli_fetch_row($date_rslt)) {
$cdate = $date_row[0];
if ($show_defunct_users == "checked") {
$cd_stmt = "SELECT count(*) as calls,sum(talk_sec) as talk,'' as full_name,user,sum(pause_sec),sum(wait_sec),sum(dispo_sec),status,sum(dead_sec), '' as user_group from ".$agent_log_table." where date(event_time)='$cdate' and pause_sec<65000 and wait_sec<65000 and talk_sec<65000 and dispo_sec<65000 and user='$Suser' $group_SQL $user_agent_log_SQL group by user,full_name,user_group,status order by full_name,user,status desc limit 500000;";
} else {
$cd_stmt = "SELECT count(*) as calls,sum(talk_sec) as talk,full_name,vicidial_users.user,sum(pause_sec),sum(wait_sec),sum(dispo_sec),status,sum(dead_sec), vicidial_users.user_group from vicidial_users,".$agent_log_table." where date(event_time)='$cdate' and vicidial_users.user=".$agent_log_table.".user and pause_sec<65000 and wait_sec<65000 and talk_sec<65000 and dispo_sec<65000 and user='$Suser' $live_user_SQLvu $group_SQL $user_group_SQL group by user,full_name,user_group,status order by full_name,user,status desc limit 500000;";
}
$cd_rslt = mysql_to_mysqli($cd_stmt, $link);
$agg = array('calls'=>0,'talk_sec'=>0,'pause_sec'=>0,'wait_sec'=>0,'dispo_sec'=>0,'dead_sec'=>0,'customer_sec'=>0,'status_calls'=>array());
foreach ($status_codes as $s) {$agg['status_calls'][$s] = 0;}
while ($cdr = mysqli_fetch_row($cd_rslt)) {
$agg['calls'] += (int)$cdr[0];
$agg['talk_sec'] += (int)$cdr[1];
$agg['pause_sec'] += (int)$cdr[4];
$agg['wait_sec'] += (int)$cdr[5];
$agg['dispo_sec'] += (int)$cdr[6];
$agg['dead_sec'] += (int)$cdr[8];
$agg['customer_sec'] += max(0, ((int)$cdr[1] - (int)$cdr[8]));
$st = strtoupper($cdr[7]);
if (isset($agg['status_calls'][$st])) {$agg['status_calls'][$st] += (int)$cdr[0];}
}
$agg['login_sec'] = $agg['talk_sec'] + $agg['pause_sec'] + $agg['wait_sec'] + $agg['dispo_sec'];
$daily_breakdown[$Suser][$cdate] = $agg;
}
}
}
# Sorting (verbatim semantics)
if ($stage == 'ID') {usort($report_rows, function($a,$b){return strcmp($a['user'],$b['user']);});}
if ($stage == 'LEADS') {usort($report_rows, function($a,$b){return $b['calls']-$a['calls'];});}
if ($stage == 'TIME') {usort($report_rows, function($a,$b){return $b['login_sec']-$a['login_sec'];});}
# ── Section 2: pause-code breakdown (verbatim queries)
$sub_status_stmt = "SELECT distinct if(sub_status is null, '*', sub_status) as all_subs from ".$agent_log_table." where event_time <= '$query_date_END' and event_time >= '$query_date_BEGIN' and pause_sec >= 0 and pause_sec < 65000 $group_SQL $user_agent_log_SQL order by all_subs asc limit 10000000;";
$sub_status_rslt = mysql_to_mysqli($sub_status_stmt, $link);
$pcRows = array();
while ($ss_row = mysqli_fetch_row($sub_status_rslt)) {
$current_ss = $ss_row[0];
$sub_status_clause = ($current_ss == "*") ? "and sub_status is null" : "and sub_status='$current_ss'";
if ($show_defunct_users == "checked") {
$stmt = "SELECT '' as full_name,user,sum(pause_sec),sub_status,sum(wait_sec + talk_sec + dispo_sec), '' as user_group from ".$agent_log_table." where event_time <= '$query_date_END' and event_time >= '$query_date_BEGIN' $sub_status_clause and pause_sec<65000 $live_user_SQL $group_SQL $user_group_agent_log_SQL group by user,full_name,sub_status order by user,full_name,sub_status desc limit 100000;";
} else {
$stmt = "SELECT full_name,vicidial_users.user,sum(pause_sec),sub_status,sum(wait_sec + talk_sec + dispo_sec), vicidial_users.user_group from vicidial_users,".$agent_log_table." where event_time <= '$query_date_END' and event_time >= '$query_date_BEGIN' $sub_status_clause and vicidial_users.user=".$agent_log_table.".user and pause_sec<65000 $live_user_SQLvu $group_SQL $user_group_SQL $user_SQL group by user,full_name,sub_status order by user,full_name,sub_status desc limit 100000;";
}
$rslt = mysql_to_mysqli($stmt, $link);
while ($r = mysqli_fetch_row($rslt)) {
if ($show_defunct_users == "checked") {
$du = mysql_to_mysqli("SELECT full_name,user_group from vicidial_users where user='$r[1]'", $link);
if (mysqli_num_rows($du) > 0) {
$du_row = mysqli_fetch_row($du);
$fn_val = $du_row[0]; $ug_val = $du_row[1];
} else {
$fn_val = $r[1]; $ug_val = "**NONE**";
}
} else {
$fn_val = $r[0]; $ug_val = $r[5];
}
$pcRows[] = array(
'full_name' => $fn_val,
'user' => $r[1],
'pause_sec' => (int)$r[2],
'sub_status' => $r[3],
'non_pause_sec'=> (int)$r[4],
'user_group' => $ug_val,
);
if (!in_array($r[3], $pause_codes, true)) {$pause_codes[] = $r[3];}
}
}
sort($pause_codes); # Alphabetical
# Aggregate pause-code rows per user
$pcUsers = array();
foreach ($pcRows as $pr) {
$u = $pr['user'];
if (!isset($pcUsers[$u])) {
$pcUsers[$u] = array(
'user' => $u,
'full_name' => $pr['full_name'],
'user_group' => $pr['user_group'],
'last_user_group' => isset($recent_user_groups[$u]) ? $recent_user_groups[$u] : '',
'pause_sec' => 0,
'non_pause_sec' => 0,
'total_sec' => 0,
'pcode_sec' => array(),
);
foreach ($pause_codes as $pc) {$pcUsers[$u]['pcode_sec'][$pc] = 0;}
}
$pcUsers[$u]['pause_sec'] += $pr['pause_sec'];
$pcUsers[$u]['non_pause_sec'] += $pr['non_pause_sec'];
$pcUsers[$u]['total_sec'] += ($pr['pause_sec'] + $pr['non_pause_sec']);
if (isset($pcUsers[$u]['pcode_sec'][$pr['sub_status']])) {
$pcUsers[$u]['pcode_sec'][$pr['sub_status']] += $pr['pause_sec'];
}
}
$pause_rows = array_values($pcUsers);
foreach ($pause_codes as $pc) {
$t = 0; foreach ($pause_rows as $pu) {$t += $pu['pcode_sec'][$pc];}
$pcode_totals[$pc] = $t;
}
foreach ($pause_rows as $pu) {
$TOTtotPAUSE_pcs += $pu['pause_sec'];
$TOTtotNONPAUSE += $pu['non_pause_sec'];
$TOTtotTOTAL += $pu['total_sec'];
}
}
# ─────────────────────────────────────────────────────────────────────────────
# CSV download paths (verbatim output structure)
# ─────────────────────────────────────────────────────────────────────────────
function csv_quote($v) {return '"'.str_replace('"','""',(string)$v).'"';}
if ($file_download == 1 && $has_data) {
header('Content-type: application/octet-stream');
header('Content-Disposition: attachment; filename="AGENT_PERFORMANCE_DETAIL_'.date("Ymd-His").'.csv"');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
echo csv_quote("Agent Performance Detail $NOW_TIME")."\n";
echo csv_quote("Time range: $query_date_BEGIN to $query_date_END")."\n\n";
$head = array("USER NAME","ID","CURRENT USER GROUP","MOST RECENT USER GROUP","CALLS","LOGIN TIME","PAUSE","PAUSAVG","WAIT","WAITAVG","TALK","TALKAVG","DISPO","DISPAVG","DEAD","DEADAVG","CUSTOMER","CUSTAVG");
foreach ($status_codes as $s) {$head[] = $s;}
echo implode(",", array_map('csv_quote', $head))."\n";
foreach ($report_rows as $r) {
$line = array(
$r['full_name'], $r['user'], $r['user_group'], $r['last_user_group'],
$r['calls'],
sec_convert($r['login_sec'], 'HF'),
sec_convert($r['pause_sec'], 'HF'), sec_convert(MathZDC($r['pause_sec'], $r['calls']), 'HF'),
sec_convert($r['wait_sec'], 'HF'), sec_convert(MathZDC($r['wait_sec'], $r['calls']), 'HF'),
sec_convert($r['talk_sec'], 'HF'), sec_convert(MathZDC($r['talk_sec'], $r['calls']), 'HF'),
sec_convert($r['dispo_sec'], 'HF'), sec_convert(MathZDC($r['dispo_sec'], $r['calls']), 'HF'),
sec_convert($r['dead_sec'], 'HF'), sec_convert(MathZDC($r['dead_sec'], $r['calls']), 'HF'),
sec_convert($r['customer_sec'],'HF'), sec_convert(MathZDC($r['customer_sec'],$r['calls']), 'HF'),
);
foreach ($status_codes as $s) {$line[] = $r['status_calls'][$s];}
echo implode(",", array_map('csv_quote', $line))."\n";
}
$endMS = microtime();
$sa = explode(" ", $startMS); $ea = explode(" ", $endMS);
$TOTALrun = ($ea[0] - $sa[0]) + ($ea[1] - $sa[1]);
mysql_to_mysqli("UPDATE vicidial_report_log set run_time='$TOTALrun' where report_log_id='$report_log_id';", $link);
exit;
}
if ($file_download == 2 && $has_data) {
header('Content-type: application/octet-stream');
header('Content-Disposition: attachment; filename="AST_PAUSE_CODE_BREAKDOWN_'.date("Ymd-His").'.csv"');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
echo csv_quote("Agent Performance Detail $NOW_TIME")."\n";
echo csv_quote("Time range: $query_date_BEGIN to $query_date_END")."\n\n";
echo csv_quote("PAUSE CODE BREAKDOWN")."\n";
$head = array("USER NAME","ID","CURRENT USER GROUP","MOST RECENT USER GROUP","TOTAL","NONPAUSE","PAUSE");
foreach ($pause_codes as $pc) {$head[] = $pc;}
echo implode(",", array_map('csv_quote', $head))."\n";
foreach ($pause_rows as $pu) {
$line = array(
$pu['full_name'], $pu['user'], $pu['user_group'], $pu['last_user_group'],
sec_convert($pu['total_sec'], 'HF'),
sec_convert($pu['non_pause_sec'], 'HF'),
sec_convert($pu['pause_sec'], 'HF'),
);
foreach ($pause_codes as $pc) {$line[] = sec_convert($pu['pcode_sec'][$pc], 'HF');}
echo implode(",", array_map('csv_quote', $line))."\n";
}
$endMS = microtime();
$sa = explode(" ", $startMS); $ea = explode(" ", $endMS);
$TOTALrun = ($ea[0] - $sa[0]) + ($ea[1] - $sa[1]);
mysql_to_mysqli("UPDATE vicidial_report_log set run_time='$TOTALrun' where report_log_id='$report_log_id';", $link);
exit;
}
# ─────────────────────────────────────────────────────────────────────────────
# Helpers for the modern UI
# ─────────────────────────────────────────────────────────────────────────────
function fmt_int($n) {return number_format((int)$n);}
function fmt_pct($num, $den) {
if ($den == 0) return '0.00';
return number_format(($num * 100) / $den, 2);
}
function fmt_time($sec, $mode) {
$sec = (int)$sec;
if ($mode == 'S') return number_format($sec);
if ($mode == 'HF') {
$h = floor($sec / 3600); $m = floor(($sec % 3600) / 60); $s = $sec % 60;
return sprintf("%d:%02d:%02d", $h, $m, $s);
}
if ($mode == 'M') {
$m = floor($sec / 60); $s = $sec % 60;
return sprintf("%d:%02d", $m, $s);
}
$h = floor($sec / 3600); $m = floor(($sec % 3600) / 60);
return sprintf("%d:%02d", $h, $m);
}
# Smart-indicator thresholds — derived from data, not hardcoded magic numbers
$avg_pause_pct = 0.0; $avg_talk_pct = 0.0;
if ($has_data && $TOTtime > 0) {
$avg_pause_pct = ($TOTtotPAUSE * 100) / $TOTtime;
$avg_talk_pct = ($TOTtotTALK * 100) / $TOTtime;
}
# Data for charts
$chart_labels = array();
$chart_calls = array();
$chart_talk = array();
$chart_pause = array();
foreach ($report_rows as $r) {
$chart_labels[] = $r['full_name'] !== '' ? $r['full_name'] : $r['user'];
$chart_calls[] = (int)$r['calls'];
$chart_talk[] = (int)$r['talk_sec'];
$chart_pause[] = (int)$r['pause_sec'];
}
$status_chart_labels = $status_codes;
$status_chart_data = array();
foreach ($status_codes as $s) {$status_chart_data[] = (int)$status_totals[$s];}
$pcode_chart_labels = array();
$pcode_chart_data = array();
foreach ($pause_codes as $pc) {
$pcode_chart_labels[] = ($pc === null || $pc === '' || $pc === '*') ? '(none)' : $pc;
$pcode_chart_data[] = (int)$pcode_totals[$pc];
}
# Querystring used by sortable column headers
$LINKbase = "$PHP_SELF?query_date=".urlencode($query_date)
. "&end_date=".urlencode($end_date)
. "&query_time=".urlencode($query_time)
. "&end_time=".urlencode($end_time)
. $groupQS . $user_groupQS . $userQS
. "&shift=".urlencode($shift)
. "&show_percentages=$show_percentages"
. "&live_agents=$live_agents"
. "&time_in_sec=$time_in_sec"
. "&search_archived_data=$search_archived_data"
. "&show_defunct_users=$show_defunct_users"
. "&breakdown_by_date=$breakdown_by_date";
?>
Agent Performance Detail
Agent Performance Detail
Filters
Select at least one campaign and click Run Report.
Stats are taken from the date/time range and shift specified.
= 30 ? 'is-danger' : ($avg_pause_pct >= 20 ? 'is-warning' : '');
$talk_class = $avg_talk_pct >= 50 ? '' : ($avg_talk_pct >= 30 ? 'is-warning' : 'is-danger');
?>
Agents
in selected range
Total Calls
avg per agent
Total Login Time
all agents combined
Talk Time
% of login
Pause Time
% of login
Avg Talk / Call
avg wait
Customer Time
talk minus dead air
Dead Time
% of talk
Time Distribution
Calls by Agent
Talk vs Pause Time by Agent
Disposition Status Breakdown
Call Stats Breakdown
Agent
User
User Group
Recent Group
Call Date
Calls
Login
Pause Pause % Avg
Wait Wait % Avg
Talk Talk % Avg
Dispo Dispo % Avg
Dead Dead % Avg
Cust Cust % Avg
%
0) {
$pause_pct_num = ($r['pause_sec']*100)/$login;
if ($pause_pct_num >= 35) $pause_badge = 'high pause';
elseif ($pause_pct_num <= 10 && $login > 600) $pause_badge = 'low pause';
}
?>
—
=35?'bad':($p>=25?'warn':''); ?>%
%
%
%
%
%
%
$agg):
$dcalls = $agg['calls']; $dlogin = $agg['login_sec']; ?>
%
%
%
%
%
%
%
TOTALS — agent
%
%
%
%
%
%
%
Pause Code Breakdown