artem
22.11.2018
7665

Доработка выборки записей по временному диапазону в модуле UCP FreePBX

В этой статье добавим возможность фильтра по временному диапазону в модуле User Control Panel (сокращённо UCP).

Данная доработка применима для FreePBX 13 версии и модуля UCP версии 13.0.42.2. Функционирование данной доработки на других версиях модуля UCP не тестировалось. Для других версий FreePBX потребуется доработка.

Выборка записей по временному диапазону в модуле UCP FreePBX

Постановка задачи

Откроем FreePBX и перейдём в модуль UCP. Подробнее о том, как работать с UCP можно прочесть в статье: Настройка и использование модуля UCP (User Control Panel) во FreePBX 13

Перейдём на интересующую нас вкладку истории звонков для текущего номера — Call History. В данный момент она будет выглядеть, как представлено на скриншоте ниже:

UCP.Call History

Задача: организовать фильтр по временному диапазону из поля Date. Конечный результат представлен на скриншоте:

Обновлённый UCP.Calls History

Как видим, появились поля, для заполнения даты и времени. Единственный нюанс — необходимо, после изменения значений данных полей, перезагрузить таблицу. Это можно сделать специальной reload-кнопкой, расположенной вверху таблицы. Эта кнопка является частью управляющей конструкции таблицы, генерируемой при помощи Bootstrap.

Пример работы изменённых скриптов представим в конце статьи, а пока перейдём к написанию кода.

Реализация

В начале реализуем часть, связанную с отображением элементов поиска на форме. Для этого открываем для редактирования файл …/admin/modules/cdr/ucp/views/view.php. В этот файл вставим формы для выбора дат. Сделаем это до открытия таблицы, то есть до открывающегося тэга <table>:

<label>С &nbsp;&nbsp;&nbsp;</label>

<input type=»date» id=»day_start» value=»<?php echo date(‘Y-m-01’); ?>» min=»2000-01-01″/>

&nbsp;&nbsp;

<input type=»time» id=»time_start» value=»00:00″/>

&nbsp;&nbsp;

<label>По &nbsp;</label>

<input type=»date» id=»day_end» value=»<?php echo date(‘Y-m-d’); ?>»/>

&nbsp;&nbsp;

<input type=»time» id=»time_end» value=»23:59″/>

Можно использовать свой стиль форматирования здесь, так как это пример реализации работы и основной упор здесь делается на саму работу, то есть на, так называемый, back end.

Теперь коротко рассмотрим, что означает весь этот написанный код. Выбираем стандартные типы для input’ов — date и time. Обязательно указываем id для каждого элемента — впоследствии, будем осуществлять выбор значений именно по нему. В качестве значения по умолчанию для времени берём: старт в 00:00 и окончание в 23:59, для удобства выборки, чтобы сразу захватывался весь день. Со значением по умолчанию для дат несколько сложнее. В качестве стартовой даты берём первый день текущего месяца. А в качестве даты окончания поиска — текущий день. Код для этого модем увидеть в приведённом скрипте.

Первый результат можем уже увидеть, если обновим страницу модуля UCP на вкладке Call History.


Первые шаги

Теперь перейдём к созданию кода функционала выборки.

На данном этапе стоит задача, чтобы при обновлении таблицы считались наши введённые данные в формы дат и их можно было бы передать для дальнейшей обработки. Так как вся таблица построена с использованием Bootstrap, то будем редактировать обращение к серверу, написанное на javascript в Bootstrap.

Открываем файл …/admin/modules/ucp/htdocs/assets/js/bootstrap-table-1.9.0.js.

В нём находим функцию, отвечающую за инициализацию всех параметров, перед отправкой запроса на сервер. Это функция BootstrapTable.prototype.initServer. При объявлении происходит инициализация params. В неё сразу помещаются такие значения, как строка поиска, тип сортировки, номер текущей страницы и т.д.

Для получения текущих значений из форм, в которых указаны дата и время, воспользуемся функцией js: getElementById. Данная функция вернёт NULL в случае, если такой элемент не будет найден на текущей странице. Так как к этой странице идёт обращение ещё и со страницы Call Event Logs (на которой мы не устанавливали дополнительных форм времени), воспользуемся тернарным оператором для проверки существования элементов.

 

Сюда же поместим обработку своих переменных. Params примет вид:

params = {

pageSize: this.options.pageSize === this.options.formatAllRows() ?

this.options.totalRows : this.options.pageSize,

pageNumber: this.options.pageNumber,

searchText: this.searchText,

sortName: this.options.sortName,

sortOrder: this.options.sortOrder,

startDate: (document.getElementById(‘day_start’) != null && document.getElementById(‘time_start’) != null) ? document.getElementById(‘day_start’).value + ‘ ‘ + document.getElementById(‘time_start’).value + ‘:00’ : «»,

endDate: (document.getElementById(‘day_end’) != null && document.getElementById(‘time_end’) != null) ? document.getElementById(‘day_end’).value + ‘ ‘ + document.getElementById(‘time_end’).value + ‘:00’ : «»

},

request;

Для проверки того, что к этому шагу всё отрабатывает, можно воспользоваться выводом текущих значений startDate и endDate.

alert(«startDate = «+params.startDate+»n endDate = «+params.endDate);

Считывание параметров в Bootstrap

Если значения переменных равны тем, которые были выбраны в полях дат, то всё хорошо и можно двигаться дальше. Если данные по каким-то причинам не совпадают, то следует вернуться назад и просмотреть, всё ли сделано верно.

После того, как тест произведён, alert можно удалять.

Перейдём к отправке полученных данных в php скрипт. Для начала необходимо добавить к формируемым данным, полученные. Делается это в текущем скрипте bootstrap-table-1.9.0.js.

Модифицировать будем следующий фрагмент: if (this.options.queryParamsType === ‘limit’). В нём находится новый params, который будет передаваться в ajax-запросе. Добавив к нему полученные переменные, получим:

params = {

search: params.searchText,

sort: params.sortName,

order: params.sortOrder,

stdate: params.startDate,

enddate:params.endDate

};

Как видим, добавили, на основании предыдущих переменных, новые stdate и enddate.

На этом работа с файлом bootstrap-table-1.9.0.js завершена. Можем приступать к модификации файлов на php. И первый на очереди — один из классов Cdr, предназначенный для UCP. Располагается по адресу: …/admin/modules/cdr/ucp/Cdr.class.php.

Находим в нём функцию ajaxHandler(). Она отвечает за обработку ajax-запросов. Данная функция есть практически в каждом модуле FreePBX. Нас будет интересовать подраздел switch($_REQUEST[‘command’]). Это специальный подраздел переданных команд. Для построения таблицы в модуле UCP на странице Call History используется команда grid. Таким образом, находим следующий участок кода:

switch($_REQUEST[‘command’]) {

case «grid»:

Здесь производим инициализацию новых переменных, полученных из запроса:

$start_date = $_REQUEST[‘stdate’];

$end_date = $_REQUEST[‘enddate’];

Для проверки, что значения, после нашего запроса передаются верно, можно воспользоваться записью в файл.

Необходимо писать именно в файл лога, потому что использование «echo» будет ломать структуру отображения страницы.

Запись в файл производим следующим образом:

$fp = fopen(“ucp_log”,”w”);

fwrite($fp, “start_date = $start_datenend_date = $end_date”);

fclose($fp);

Сохраняем Cdr.class.php и перезагружаем страницу UCP -> Call History. Созданный файл будет находится по адресу: …/admin/modules/ucp/htdocs/. В случае успешной передачи значений через ajax-запрос, в файл будут выведены текущие выбранные дата и время. Если это верно, то данное логирование можно удалить/закомментировать.

Находим вызов функции getPages. Данная функция принадлежит классу CDR и отвечает за получение количества страниц для отображения, с текущими параметрами поиска. Если здесь не модифицировать запрос, то будет неправильно считаться количество страниц при использовании ограничения по времени. Передаём в вызов функции полученные параметры:

$pages = $this->cdr->getPages($ext,$search,$limit,$start_date,$end_date);

Находим чуть ниже вызов функции postProcessCalls, внутри которой производится вызов функции getCalls. Сама функция описана в другом файле и будет рассмотрена позднее. Добавим полученные переменные в данную функцию:

$data = $this->postProcessCalls($this->cdr->getCalls($ext,$page,$orderby,$order,$search,$limit,$start_date,$end_date),$ext);

На этом работа с данным файлом завершена.

Переходим к редактированию другого класса: …/admin/modules/cdr/Cdr.class.php. Именно в нём описывается функция getCalls. Найдём её и выполним получение ранее переданных параметров. Функция примет вид:

public function
getCalls($extension,$page=1,$orderby=’date’,$order=’desc’,$search=»,$limit=100,$start_date=»»,$end_date=»») {

По умолчанию, переменные $start_date и $end_date делаем пустыми, чтобы они не влияли на работу других модулей (если getCalls будет вызываться из других мест).

Формируем переменную для вставки в запрос:

$sqldate = ($start_date != «» && $end_date != «») ? «calldate BETWEEN ‘$start_date’ AND ‘$end_date’ AND» : «»;

Используем тернарный оператор, чтобы, в случае передачи пустых переменных, в строку запроса также добавлялась пустая строка.

Переходим к формированию самого запроса. Самих запросов будет два: если строка поиска пуста и не пуста. В оба запроса добавляем переменную $sqldate в раздел WHERE. Получим следующий фрагмент:

if(!empty($search)) {

      $sql = «SELECT *, UNIX_TIMESTAMP(calldate) As timestamp FROM «.$this->db_table.» WHERE $sqldate (dstchannel LIKE :chan OR channel LIKE :chan OR src = :extension OR dst = :extension OR src = :extensionv OR dst = :extensionv OR cnum = :extension OR cnum = :extensionv) AND (clid LIKE :search OR src LIKE :search OR dst LIKE :search) ORDER by $orderby $order LIMIT $start,$end»;

      $sth = $this->cdrdb->prepare($sql);

      $sth->execute(array(‘:chan’ => ‘%/’.$extension.’-%’, ‘:extension’ => $extension, ‘:search’ => ‘%’.$search.’%’, ‘:extensionv’ => ‘vmu’.$extension));

} else {

      $sql = «SELECT *, UNIX_TIMESTAMP(calldate) As timestamp FROM «.$this->db_table.» WHERE $sqldate (dstchannel LIKE :chan OR channel LIKE :chan OR src = :extension OR dst = :extension OR src = :extensionv OR dst = :extensionv OR cnum = :extension OR cnum = :extensionv) ORDER by $orderby $order LIMIT $start,$end»;

Теперь остаётся только поправить в этом же файле функцию getPages. Вызов будет изменён следующим образом:

public function getPages($extension,$search=»,$limit=100,$start_date=»»,$end_date=»») {

Видим, что, как и в предыдущей функции, добавились два параметра — start_date и end_date, которые пусты по умолчанию.

Формируем переменную для вставки в запрос:

$sqldate = ($start_date != «» && $end_date != «») ? «calldate BETWEEN ‘$start_date’ AND ‘$end_date’ AND» : «»;

Она аналогична переменной в функции getCalls.

И формируем сам запрос:

if(!empty($search)) {

      $sql = «SELECT count(*) as count FROM «.$this->db_table.» WHERE $sqldate (src = :extension OR dst = :extension OR src = :extensionv OR dst = :extensionv OR cnum = :extension) AND (clid LIKE :search OR src LIKE :search OR dst LIKE :search)»;

      $sth = $this->cdrdb->prepare($sql);
      $sth->execute(array(‘:extension’ => $extension, ‘:search’ => ‘%’.$search.’%’,’:extensionv’ => ‘vmu’.$extension));

} else {

      $sql = «SELECT count(*) as count FROM «.$this->db_table.» WHERE $sqldate (src = :extension OR dst = :extension OR src = :extensionv OR dst = :extensionv OR cnum = :extension)»;

      $sth = $this->cdrdb->prepare($sql);

      $sth->execute(array(‘:extension’ => $extension,’:extensionv’ => ‘vmu’.$extension));

}

Сохраняем файл, перезагружаем страницу UCP -> Call History. Если всё выполнено верно, то таблица будет отфильтрована по указанным датам.

Чтобы применить фильтрацию при изменении дат, необходимо нажать на кнопку обновления страницы, для отправки данных ajax-запросом.

Подробнее на скриншоте ниже:

Применение фильтра

На этом данная доработка по модулю UCP завершена.

В конце хотелось бы продемонстрировать пример работы:

Пример работы

Также могут быть интересны следующие статьи:

Обзор модуля User Control Panel во FreePBX 14

Создание внутренних номеров на IP АТС Asterisk

Настройка Интерактивного голосового меню (IVR)

Правила по времени во FreePBX

Книга 101 функция Asterisk
Познакомьтесь с возможностями Asterisk. Найдите инструменты, которые помогут вашей компании развиваться.
Скачать книгу
Подписаться
Уведомить о
guest
1 Комментарий
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
Александр
Александр
25.11.2020 11:03

нужная статья всегда попадается после того как сам всё сделал…
делал выбор периода с помощью daterangepicker — очень удобно оказалось.

Остались вопросы?

Я - Першин Артём, менеджер компании Voxlink. Хотите уточнить детали или готовы оставить заявку? Укажите номер телефона, я перезвоню в течение 3-х секунд.

VoIP оборудование


ближайшие курсы

10 доводов в пользу Asterisk

Распространяется бесплатно.

Asterisk – программное обеспечение с открытым исходным кодом, распространяется по лицензии GPL. Следовательно, установив один раз Asterisk вам не придется дополнительно платить за новых абонентов, подключение новых транков, расширение функционала и прочие лицензии. Это приближает стоимость владения станцией к нулю.

Безопасен в использовании.

Любое программное обеспечение может стать объектом интереса злоумышленников, в том числе телефонная станция. Однако, сам Asterisk, а также операционная система, на которой он работает, дают множество инструментов защиты от любых атак. При грамотной настройке безопасности у злоумышленников нет никаких шансов попасть на станцию.

Надежен в эксплуатации.

Время работы серверов некоторых наших клиентов исчисляется годами. Это значит, что Asterisk работает несколько лет, ему не требуются никакие перезагрузки или принудительные отключения. А еще это говорит о том, что в районе отличная ситуация с электроэнергией, но это уже не заслуга Asterisk.

Гибкий в настройке.

Зачастую возможности Asterisk ограничивает только фантазия пользователя. Ни один конструктор шаблонов не сравнится с Asterisk по гибкости настройки. Это позволяет решать с помощью Asterisk любые бизнес задачи, даже те, в которых выбор в его пользу не кажется изначально очевидным.

Имеет огромный функционал.

Во многом именно Asterisk показал какой должна быть современная телефонная станция. За многие годы развития функциональность Asterisk расширилась, а все основные возможности по-прежнему доступны бесплатно сразу после установки.

Интегрируется с любыми системами.

То, что Asterisk не умеет сам, он позволяет реализовать за счет интеграции. Это могут быть интеграции с коммерческими телефонными станциями, CRM, ERP системами, биллингом, сервисами колл-трекинга, колл-бэка и модулями статистики и аналитики.

Позволяет телефонизировать офис за считанные часы.

В нашей практике были проекты, реализованные за один рабочий день. Это значит, что утром к нам обращался клиент, а уже через несколько часов он пользовался новой IP-АТС. Безусловно, такая скорость редкость, ведь АТС – инструмент зарабатывания денег для многих компаний и спешка во внедрении не уместна. Но в случае острой необходимости Asterisk готов к быстрому старту.

Отличная масштабируемость.

Очень утомительно постоянно возвращаться к одному и тому же вопросу. Такое часто бывает в случае некачественного исполнения работ или выбора заведомо неподходящего бизнес-решения. С Asterisk точно не будет такой проблемы! Телефонная станция, построенная на Asterisk может быть масштабируема до немыслимых размеров. Главное – правильно подобрать оборудование.

Повышает управляемость бизнеса.

Asterisk дает не просто набор полезных функций, он повышает управляемость организации, качества и комфортности управления, а также увеличивает прозрачность бизнеса для руководства. Достичь этого можно, например, за счет автоматизации отчетов, подключения бота в Telegram, санкционированного доступа к станции из любой точки мира.

Снижает расходы на связь.

Связь между внутренними абонентами IP-АТС бесплатна всегда, независимо от их географического расположения. Также к Asterisk можно подключить любых операторов телефонии, в том числе GSM сим-карты и настроить маршрутизацию вызовов по наиболее выгодному тарифу. Всё это позволяет экономить с первых минут пользования станцией.