artem
22.11.2018
8403

Доработка выборки записей по временному диапазону в модуле 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

Кейсы внедрения
Asterisk от VoxLink
Узнайте, какие крупные компании уже используют 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 сим-карты и настроить маршрутизацию вызовов по наиболее выгодному тарифу. Всё это позволяет экономить с первых минут пользования станцией.