diff --git a/src/messenger/webim/default.css b/src/messenger/webim/default.css index 6982313b..c1d5b5ea 100644 --- a/src/messenger/webim/default.css +++ b/src/messenger/webim/default.css @@ -1,5 +1,6 @@ /* * Copyright 2005-2013 Evgeny Gryaznov + * Copyright 2013 Simushev Dmitriy * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -484,9 +485,9 @@ table.list, table.translate, table.statistics { } table.list th, table.translate th, table.statistics th { - font-size: 1.2em; + font-size: 1em; font-weight: normal; - padding: 10px 8px; + padding: 10px 6px; border-bottom: 2px solid #2F7598; } diff --git a/src/messenger/webim/install/dbinfo.php b/src/messenger/webim/install/dbinfo.php index f1e38851..e92f18b5 100644 --- a/src/messenger/webim/install/dbinfo.php +++ b/src/messenger/webim/install/dbinfo.php @@ -62,6 +62,11 @@ $dbtables = array( "statid" => "int NOT NULL auto_increment PRIMARY KEY", "date" => "int NOT NULL DEFAULT 0", "threads" => "int NOT NULL DEFAULT 0", + "missedthreads" => "int NOT NULL DEFAULT 0", + "sentinvitations" => "int NOT NULL DEFAULT 0", + "acceptedinvitations" => "int NOT NULL DEFAULT 0", + "rejectedinvitations" => "int NOT NULL DEFAULT 0", + "ignoredinvitations" => "int NOT NULL DEFAULT 0", "operatormessages" => "int NOT NULL DEFAULT 0", "usermessages" => "int NOT NULL DEFAULT 0", "averagewaitingtime" => "FLOAT(10, 1) NOT NULL DEFAULT 0", @@ -232,7 +237,7 @@ $memtables = array(); $dbtables_can_update = array( "${mysqlprefix}chatthread" => array("agentId", "userTyping", "agentTyping", "messageCount", "nextagent", "shownmessageid", "userid", "userAgent", "groupid", "dtmchatstarted", "invitationstate"), - "${mysqlprefix}chatthreadstatistics" => array(), + "${mysqlprefix}chatthreadstatistics" => array("missedthreads", "sentinvitations", "acceptedinvitations", "rejectedinvitations", "ignoredinvitations"), "${mysqlprefix}requestbuffer" => array("requestid", "requestkey", "request"), "${mysqlprefix}chatmessage" => array("agentId"), "${mysqlprefix}indexedchatmessage" => array(), diff --git a/src/messenger/webim/install/dbperform.php b/src/messenger/webim/install/dbperform.php index 3831d667..3e3f933b 100644 --- a/src/messenger/webim/install/dbperform.php +++ b/src/messenger/webim/install/dbperform.php @@ -132,6 +132,26 @@ if ($act == "silentcreateall") { runsql("ALTER TABLE ${mysqlprefix}chatthread ADD invitationstate int NOT NULL DEFAULT 0 AFTER istate", $link); } + if (in_array("${mysqlprefix}chatthreadstatistics.missedthreads", $absent_columns)) { + runsql("ALTER TABLE ${mysqlprefix}chatthreadstatistics ADD missedthreads int NOT NULL DEFAULT 0 AFTER threads", $link); + } + + if (in_array("${mysqlprefix}chatthreadstatistics.sentinvitations", $absent_columns)) { + runsql("ALTER TABLE ${mysqlprefix}chatthreadstatistics ADD sentinvitations int NOT NULL DEFAULT 0 AFTER missedthreads", $link); + } + + if (in_array("${mysqlprefix}chatthreadstatistics.acceptedinvitations", $absent_columns)) { + runsql("ALTER TABLE ${mysqlprefix}chatthreadstatistics ADD acceptedinvitations int NOT NULL DEFAULT 0 AFTER sentinvitations", $link); + } + + if (in_array("${mysqlprefix}chatthreadstatistics.rejectedinvitations", $absent_columns)) { + runsql("ALTER TABLE ${mysqlprefix}chatthreadstatistics ADD rejectedinvitations int NOT NULL DEFAULT 0 AFTER acceptedinvitations", $link); + } + + if (in_array("${mysqlprefix}chatthreadstatistics.ignoredinvitations", $absent_columns)) { + runsql("ALTER TABLE ${mysqlprefix}chatthreadstatistics ADD ignoredinvitations int NOT NULL DEFAULT 0 AFTER rejectedinvitations", $link); + } + if (in_array("${mysqlprefix}chatoperator.iperm", $absent_columns)) { runsql("ALTER TABLE ${mysqlprefix}chatoperator ADD iperm int DEFAULT 65535", $link); } diff --git a/src/messenger/webim/libs/statistics.php b/src/messenger/webim/libs/statistics.php index ed225fd3..75e8f18d 100644 --- a/src/messenger/webim/libs/statistics.php +++ b/src/messenger/webim/libs/statistics.php @@ -62,45 +62,172 @@ function calculate_thread_statistics() { $today = floor(time() / (24*60*60)) * 24*60*60; // Calculate statistics - $db->query( - "INSERT INTO {chatthreadstatistics} ( " . - "date, threads, operatormessages, usermessages, " . - "averagewaitingtime, averagechattime " . - ") SELECT (FLOOR(t.dtmcreated / (24*60*60)) * 24*60*60) AS date, " . - "COUNT(distinct t.threadid) AS threads, " . - "SUM(m.ikind = :kind_agent) AS operators, " . - "SUM(m.ikind = :kind_user) AS users, " . - "ROUND(AVG(t.dtmchatstarted-t.dtmcreated),1) as avgwaitingtime, " . + // Get base threads info + $db_results = $db->query( + "SELECT (FLOOR(t.dtmcreated / (24*60*60)) * 24*60*60) AS date, " . + "COUNT(t.threadid) AS threads, " . + "tmp.operator_msgs AS operator_msgs, " . + "tmp.user_msgs AS user_msgs, " . // Prevent negative values of avgchattime field. // If avgchattime < 0 it becomes to zero. // For random value 'a' result of expression ((abs(a) + a) / 2) // equals to 'a' if 'a' more than zero // and equals to zero otherwise "ROUND(AVG( " . - "ABS(tmp.lastmsgtime-t.dtmchatstarted) + " . - "(tmp.lastmsgtime-t.dtmchatstarted) " . - ")/2,1) as avgchattime " . - "FROM {indexedchatmessage} m, " . - "{chatthread} t, " . - "(SELECT i.threadid, MAX(i.dtmcreated) AS lastmsgtime " . - "FROM {indexedchatmessage} i " . - "WHERE (ikind = :kind_user OR ikind = :kind_agent) " . - "GROUP BY i.threadid) tmp " . - "WHERE m.threadid = t.threadid " . - "AND tmp.threadid = t.threadid " . - "AND t.dtmchatstarted <> 0 " . - "AND (m.dtmcreated - :start) > 24*60*60 " . + "ABS(tmp.last_msg_time - t.dtmchatstarted) + " . + "(tmp.last_msg_time - t.dtmchatstarted) " . + ")/2,1) as avg_chat_time " . + "FROM {chatthread} t, " . + "(SELECT SUM(m.ikind = :kind_agent) AS operator_msgs, " . + "SUM(m.ikind = :kind_user) AS user_msgs, " . + "MAX(m.dtmcreated) as last_msg_time, " . + "threadid " . + "FROM {indexedchatmessage} m " . + // Calculate only users' and operators' messages + "WHERE m.ikind = :kind_user " . + "OR m.ikind = :kind_agent " . + "GROUP BY m.threadid) tmp " . + "WHERE t.threadid = tmp.threadid " . + "AND (t.dtmcreated - :start) > 24*60*60 " . // Calculate statistics only for threads that older than one day - "AND (:today - m.dtmcreated) > 24*60*60 " . - "GROUP BY date " . - "ORDER BY date", + "AND (:today - t.dtmcreated) > 24*60*60 " . + // Ignore threads when operator does not start chat + "AND t.dtmchatstarted <> 0 " . + // Ignore not accepted invitations + "AND (t.invitationstate = :not_invited " . + "OR t.invitationstate = :invitation_accepted) " . + "GROUP BY date", array( - ':kind_agent' => Thread::KIND_AGENT, - ':kind_user' => Thread::KIND_USER, ':start' => $start, - ':today' => $today - ) + ':today' => $today, + ':not_invited' => Thread::INVITATION_NOT_INVITED, + ':invitation_accepted' => Thread::INVITATION_ACCEPTED, + ':kind_agent' => Thread::KIND_AGENT, + ':kind_user' => Thread::KIND_USER + ), + array('return_rows' => Database::RETURN_ALL_ROWS) ); + + // Store statistics data + $statistics = extend_statistics_info(array(), $db_results); + + // Get info about missed threads + $db_results = $db->query( + "SELECT (FLOOR(dtmcreated / (24*60*60)) * 24*60*60) AS date, " . + "COUNT(*) as missed_threads " . + "FROM {chatthread} " . + "WHERE (dtmcreated - :start) > 24*60*60 " . + // Calculate statistics only for threads that older than one day + "AND (:today - dtmcreated) > 24*60*60 " . + // Ignore threads when operator does not start chat + "AND dtmchatstarted = 0 " . + // Ignore not accepted invitations + "AND invitationstate = :not_invited " . + "GROUP BY date ORDER BY date DESC", + array( + ':start' => $start, + ':today' => $today, + ':not_invited' => Thread::INVITATION_NOT_INVITED + ), + array('return_rows' => Database::RETURN_ALL_ROWS) + ); + + // Add average waiting time to statistics data + $statistics = extend_statistics_info($statistics, $db_results); + + // Get info about average chat time and missed threads count. + $db_results = $db->query( + "SELECT (FLOOR(dtmcreated / (24*60*60)) * 24*60*60) AS date, " . + "ROUND(AVG(dtmchatstarted-dtmcreated),1) AS avg_waiting_time, + SUM(dtmchatstarted = 0) AS missed_threads " . + "FROM {chatthread} " . + "WHERE (dtmcreated - :start) > 24*60*60 " . + // Calculate statistics only for threads that older than one day + "AND (:today - dtmcreated) > 24*60*60 " . + // Ignore threads when operator does not start chat + "AND dtmchatstarted <> 0 " . + // Ignore all invitations + "AND invitationstate = :not_invited " . + "GROUP BY date", + array( + ':start' => $start, + ':today' => $today, + ':not_invited' => Thread::INVITATION_NOT_INVITED + ), + array('return_rows' => Database::RETURN_ALL_ROWS) + ); + + // Add average waiting time to statistics data + $statistics = extend_statistics_info($statistics, $db_results); + + // Get invitation info + $db_results = $db->query( + "SELECT (FLOOR(dtmcreated / (24*60*60)) * 24*60*60) AS date, " . + "COUNT(*) AS invitation_sent, " . + "SUM(invitationstate = :invitation_accepted) AS invitation_accepted, " . + "SUM(invitationstate = :invitation_rejected) AS invitation_rejected, " . + "SUM(invitationstate = :invitation_ignored) AS invitation_ignored " . + "FROM {chatthread} " . + "WHERE (dtmcreated - :start) > 24*60*60 " . + // Calculate statistics only for threads that older than one day + "AND (:today - dtmcreated) > 24*60*60 " . + "AND (invitationstate = :invitation_accepted " . + "OR invitationstate = :invitation_rejected " . + "OR invitationstate = :invitation_ignored) " . + "GROUP BY date", + array( + ':start' => $start, + ':today' => $today, + ':invitation_accepted' => Thread::INVITATION_ACCEPTED, + ':invitation_rejected' => Thread::INVITATION_REJECTED, + ':invitation_ignored' => Thread::INVITATION_IGNORED + ), + array('return_rows' => Database::RETURN_ALL_ROWS) + ); + + // Add invitation info to statistics data + $statistics = extend_statistics_info($statistics, $db_results); + + // Sort statistics by date before save it in the database + ksort($statistics); + + foreach($statistics as $row) { + // Add default values + $row += array( + 'threads' => 0, + 'missed_threads' => 0, + 'operator_msgs' => 0, + 'user_msgs' => 0, + 'avg_chat_time' => 0, + 'avg_waiting_time' => 0, + 'invitation_sent' => 0, + 'invitation_accepted' => 0, + 'invitation_rejected' => 0, + 'invitation_ignored' => 0 + ); + + // Prepare data for insert + $insert_data = array(); + foreach($row as $field_name => $field_value) { + $insert_data[':' . $field_name] = $field_value; + } + + // Store data in database + $db->query( + "INSERT INTO {chatthreadstatistics} (" . + "date, threads, missedthreads, sentinvitations, " . + "acceptedinvitations, rejectedinvitations, " . + "ignoredinvitations, operatormessages, usermessages, " . + "averagewaitingtime, averagechattime " . + ") VALUES (" . + ":date, :threads, :missed_threads, :invitation_sent, " . + ":invitation_accepted, :invitation_rejected, " . + ":invitation_ignored, :operator_msgs, :user_msgs, " . + ":avg_waiting_time, :avg_chat_time " . + ")", + $insert_data + ); + } } catch(Exception $e) { // Something went wrong: warn and rollback transaction. trigger_error( @@ -263,4 +390,24 @@ function calculate_page_statistics() { $db->throwExeptions($db_throw_exceptions); } +/** + * Add info from $additional_info to $stat_info using value of 'date' item as + * a key. + * + * @param array $stat_info Statistics info + * @param array $additional_info Data that must be added to statistics info + * @return array Extended statistics info + */ +function extend_statistics_info($stat_info, $additional_info) { + $result = $stat_info; + foreach($additional_info as $row) { + $date = $row['date']; + if (empty($result[$date])) { + $result[$date] = array(); + } + $result[$date] += $row; + } + return $result; +} + ?> \ No newline at end of file diff --git a/src/messenger/webim/locales/en/properties b/src/messenger/webim/locales/en/properties index 996781f7..0012df46 100644 --- a/src/messenger/webim/locales/en/properties +++ b/src/messenger/webim/locales/en/properties @@ -452,6 +452,11 @@ report.bydate.3=Messages from operators report.bydate.4=Messages from visitors report.bydate.5=Average waiting time (in seconds) report.bydate.6=Average chat time (in seconds) +report.bydate.7=Missed threads +report.bydate.8=Invitations sent +report.bydate.9=Invitations accepted +report.bydate.10=Invitations rejected +report.bydate.11=Invitations ignored report.bydate.title=Usage statistics for each date report.byoperator.1=Operator report.byoperator.2=Chat Threads diff --git a/src/messenger/webim/locales/ru/properties b/src/messenger/webim/locales/ru/properties index 789ccd49..ad50eb1b 100644 --- a/src/messenger/webim/locales/ru/properties +++ b/src/messenger/webim/locales/ru/properties @@ -451,6 +451,11 @@ report.bydate.3= report.bydate.4=Сообщений посетителей report.bydate.5=Среднее время ожидания (в секундах) report.bydate.6=Среднее время диалога (в секундах) +report.bydate.7=Диалогов пропущено +report.bydate.8=Приглашений отправлено +report.bydate.9=Приглашений принято +report.bydate.10=Приглашений отклонено +report.bydate.11=Приглашений проигнорировано report.bydate.title=Использование мессенджера по дням report.byoperator.1=Оператор report.byoperator.2=Диалогов diff --git a/src/messenger/webim/operator/statistics.php b/src/messenger/webim/operator/statistics.php index fead6be9..873cd16d 100644 --- a/src/messenger/webim/operator/statistics.php +++ b/src/messenger/webim/operator/statistics.php @@ -40,6 +40,8 @@ $page['showbypage'] = ($statisticstype == 'bypage'); $page['cron_path'] = cron_get_uri(Settings::get('cron_key')); $page['last_cron_run'] = Settings::get('_last_cron_run'); +$page['show_invitations_info'] = (bool)Settings::get('enabletracking'); + $errors = array(); if (isset($_GET['startday'])) { @@ -81,6 +83,11 @@ if ($statisticstype == 'bydate') { $page['reportByDate'] = $db->query( "SELECT DATE(FROM_UNIXTIME(date)) AS date, " . "threads, " . + "missedthreads, " . + "sentinvitations, " . + "acceptedinvitations, " . + "rejectedinvitations, " . + "ignoredinvitations, " . "operatormessages AS agents, " . "usermessages AS users, " . "averagewaitingtime AS avgwaitingtime, " . @@ -99,6 +106,11 @@ if ($statisticstype == 'bydate') { $page['reportByDateTotal'] = $db->query( "SELECT DATE(FROM_UNIXTIME(date)) AS date, " . "SUM(threads) AS threads, " . + "SUM(missedthreads) AS missedthreads, " . + "SUM(sentinvitations) AS sentinvitations, " . + "SUM(acceptedinvitations) AS acceptedinvitations, " . + "SUM(rejectedinvitations) AS rejectedinvitations, " . + "SUM(ignoredinvitations) AS ignoredinvitations, " . "SUM(operatormessages) AS agents, " . "SUM(usermessages) AS users, " . "ROUND(SUM(averagewaitingtime * s.threads) / SUM(s.threads),1) AS avgwaitingtime, " . diff --git a/src/messenger/webim/view/statistics.php b/src/messenger/webim/view/statistics.php index 0a5eedca..70fe92cc 100644 --- a/src/messenger/webim/view/statistics.php +++ b/src/messenger/webim/view/statistics.php @@ -80,6 +80,8 @@ require_once('inc_errors.php'); + + @@ -88,7 +90,19 @@ require_once('inc_errors.php'); - + + + + + + + + + + + + + @@ -96,23 +110,37 @@ require_once('inc_errors.php'); + + + + + + + + + + + + + + - +