Как известно, Asterisk может хранить детализацию звонков, она же CDR (Call Detail Records). CDR может храниться разными способами, это и обычный csv-файл и практически любая база данных. У нас, например это обычная база на MySQL, с одной единственной табличкой — cdr. Была поставлена цель: написать скрипт который бы считал стоимость звонков.
Нам интересны поля:
Этап 2: Создаём свои таблицы.
price_russia – таблица с кодами регионов россии и ценами.
price_international – таблица с кодами стран и ценами.
clients — таблица с клиентами.
* поле rate позволяет давать скидку или ставить наценку для клиента (пишем 90 – даём скидку в 10 процентов, ставим 110 – получаем наценку в 10 процентов).
clients_ext – сопоставление клиентов и экстеншенов.
сalls – таблица с обработанными звонками.
*type – тип звонка (входящий/исходящий).
Предполагается что данный скрипт будет запускаться по расписанию, и что бы ничего не пропустить, в начале выполнения скрипта мы помечаем необработанные строки, для того что бы обрабатывать только их, и не трогать те которые могут появится пока выполняется скрипт:
Первое что мы делаем – это загружаем в массив информацию о:
1. Клиентах, их экстеншенах, группах и множителе.
2. Коды регионов, описание и цены по России.
3. Коды стран, описание и цены по миру.
Соответственно делаем мы вот что:
Теперь можем выбрать из базы, отмеченные строки и начать обработку.
Собственно обработка
Определяем направление звонка:
Теперь нам нужно определить экстеншен, по которому мы сможем определить клиента. Экстеншен можно извлечь из канала, в таблице cdr — это поля «channel» при исходящем вызове и «dstchannel» при входящим.
* знаю что тут лучше использовать регулярные выражения, но…
Теперь определяем какому клиенту принадлежит экстеншен.
и множитель
Округляем секунды до минут:
Если звонок внутренний или входящий, цену можно установить в ноль, а описание оставить пустым. А в противном случае нужно определить куда ушёл звонок.
Определяем цену звонка:
Теперь мы имеем всё что бы, записать информацию о звонке в таблицу.
И в самом конце, пометить строки как полностью в обработанные:
Вышенаписанное писалось под Москву, но легко может быть переделано под другой город или страну.
Ссылка на исходники: 77.108.85.102/habr/import.php.txt, 77.108.85.102/habr/functions.php.txt,
Этап 1: изучаем структуру таблицы cdr и что в ней хранится
Нам интересны поля:
- src- источник;
- dst – назначение;
- billsec – тарифицируемые секунды (секунды после снятия трубки);
- channel — используемый канал;
- dstchannel – канал направления;
- calldate – дата и время;
- uniqueid – уникальный идентификатор;
- disposition — что случилось с вызовом: ANSWERED, NO ANSWER, BUSY, FAILED.
- userfield – свободное поле.
Этап 2: Создаём свои таблицы.
price_russia – таблица с кодами регионов россии и ценами.
CREATE TABLE IF NOT EXISTS `price_russia ` (
`code` int(10) NOT NULL COMMENT 'Код области',
`cost` varchar(10) NOT NULL COMMENT 'Цена',
`region` varchar(100) NOT NULL COMMENT 'Регион',
UNIQUE KEY `code` (`code`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
price_international – таблица с кодами стран и ценами.
CREATE TABLE IF NOT EXISTS ` price_international` (
`code` int(10) NOT NULL COMMENT 'Код страны',
`price` varchar(10) NOT NULL COMMENT 'Цена',
`country` varchar(100) NOT NULL COMMENT 'Страна',
UNIQUE KEY `code` (`code`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
clients — таблица с клиентами.
CREATE TABLE IF NOT EXISTS `clients` (
`login` varchar(32) NOT NULL COMMENT 'Логин',
`password` varchar(32) NOT NULL COMMENT 'Пароль',
`email` varchar(40) NOT NULL COMMENT 'Email',
`rate` smallint(4) NOT NULL COMMENT 'Множитель',
UNIQUE KEY `login` (`login`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
* поле rate позволяет давать скидку или ставить наценку для клиента (пишем 90 – даём скидку в 10 процентов, ставим 110 – получаем наценку в 10 процентов).
clients_ext – сопоставление клиентов и экстеншенов.
CREATE TABLE IF NOT EXISTS `clients_ext` (
`login` varchar(32) NOT NULL,
`ext` int(6) NOT NULL,
UNIQUE KEY `ext` (`ext`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
сalls – таблица с обработанными звонками.
CREATE TABLE IF NOT EXISTS `calls` (
`uniqueid` varchar(32) NOT NULL,
`date` datetime NOT NULL,
`login` varchar(32) NOT NULL,
`rate` bigint(10) NOT NULL,
`ext` bigint(10) NOT NULL,
`dst` bigint(20) NOT NULL,
`src` bigint(20) NOT NULL,
`type` varchar(20) NOT NULL,
`minutes` int(10) NOT NULL,
`seconds` int(100) NOT NULL,
`cost` int(10) NOT NULL,
`description` varchar(100) NOT NULL,
UNIQUE KEY `uniqueid` (`uniqueid`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
*type – тип звонка (входящий/исходящий).
Этап 3: Обработка данных.
Предполагается что данный скрипт будет запускаться по расписанию, и что бы ничего не пропустить, в начале выполнения скрипта мы помечаем необработанные строки, для того что бы обрабатывать только их, и не трогать те которые могут появится пока выполняется скрипт:
mysql_query("UPDATE cdr SET userfield=`step1` WHERE userfield=``;");
Первое что мы делаем – это загружаем в массив информацию о:
1. Клиентах, их экстеншенах, группах и множителе.
function get_clients(){ // На выходе получаем массив с экстеншенами, кому они принадлежат и какой там множитель.
$query=mysql_query("SELECT rate,ext,login FROM clients, clients_ext WHERE clients_ext.login = clients.login");
while($row=mysql_fetch_assoc($query)){
$clients[$row['ext']]['rate']=$row['rate'];
$clients[$row['ext']]['user']=$row['login'];
}
return $clients;
}
2. Коды регионов, описание и цены по России.
function get_price_russia(){ // Получаем массив с ценами по России
$query=mysql_query("SELECT * FROM price_russia");
while($row=mysql_fetch_assoc($query)){
$price[$row['code']]['cost']=$row['price'];
$price[$row['code']]['description']=$row['region'];
}
return $price;
}
3. Коды стран, описание и цены по миру.
function get_price_international(){ //Получаем массив с ценами по миру.
$query=mysql_query("SELECT * FROM price_international");
while($row=mysql_fetch_assoc($query)){
$price[$row['code']]['cost']=$row['price'];
$price[$row['code']]['description']=$row['country'];
}
return $price;
}
Соответственно делаем мы вот что:
$clients=get_clients();
$price['russia']=get_price_russia();
$price['international']=get_price_international();
Теперь можем выбрать из базы, отмеченные строки и начать обработку.
$query=mysql_query("SELECT * FROM cdr WHERE userfield=`step1`");
while($row=mysql_fetch_assoc($row)){
//обработка
}
Собственно обработка
(перед первым вызовом функции я привожу это функцию, хотя естественно они должны располагаться или в начале файла или в соседнем файле.)
:Определяем направление звонка:
function get_call_type($dst,$src){
$dst=strlen($dst);
$src=strlen($src);
if($scr<7 && $dst<7)$type='internal'; //Внутренний вызов.
if($src<7 && $dst>=7)$type='outcoming'; // Исходящий
if($src>=7 && $dst<7)$type='incoming'; //Входящий
return $type;
}
$type=get_call_type($row['dst'],$row['src']);
Теперь нам нужно определить экстеншен, по которому мы сможем определить клиента. Экстеншен можно извлечь из канала, в таблице cdr — это поля «channel» при исходящем вызове и «dstchannel» при входящим.
function get_ext_from_channel($channel){ // Достаём ext из channel
$channel=split("/",$channel);
$channel=split("-",$channel[1]);
return($channel[0]);
}
switch ($type) {
case 'internal':
$ext=$row['src'];
break;
case 'incoming':
$ext=get_ext_from_channel($row['dstchannel']);
break;
case 'outcoming':
$ext=get_ext_from_channel($row['channel']);
break;
}
* знаю что тут лучше использовать регулярные выражения, но…
Теперь определяем какому клиенту принадлежит экстеншен.
$login=$clients[$ext]['login']
и множитель
$rate=$clients[$ext]['rate']
Округляем секунды до минут:
$minutes=ceil($row['billsec']/60);
Если звонок внутренний или входящий, цену можно установить в ноль, а описание оставить пустым. А в противном случае нужно определить куда ушёл звонок.
if($type=='outcoming'){
//Определени звонка.
}else{
$cost=0;
$description=0;
}
Определяем цену звонка:
//Дописываем 8495 если в номере только 7 цифр.
function check_for_moscow($num){
if(strlen($num)==7)$num='8495'.$num;
return $num;
}
$dst=check_for_moscow($row['dst']);
//Теперь определим какой применять прайс, российский или международный. Мы применили в настройках атс стандартную схему: что вход на международку через 10. Поэтому номера в которых 11 и меньше цифр - российские, а больше - международные.
function get_country_type($number){
if(strlen($number)<=11){
$return='russia';
}else{
$return='international';
}
return $return;
}
$country=get_country_type($dst);
$cost='';
$description='';
$i=1;
//Если Россия - то код региона начинается со второга символа (8xxx), если международный то с 4 (810xxx)
if($country=='international'){$s=3;}else{$s=1;}
//В коде города от трёх цифр, кроме тех у которых код начинается с 9 - это сотовые. Международные коды 2-3 цифры.
while($cost==''){
$code=substr($dst,$s,$i);
$cost=$price[$country][$code]['cost'];
$description=$price[$country][$code]['description'];
$i++;
}
Теперь мы имеем всё что бы, записать информацию о звонке в таблицу.
mysql_query("INSERT INTO calls(uniqueid, date, login, rate, ext, dst, src, type, minutes, seconds, cost, description)
VALUES
('$row[uniqueid]', '$row[calldate]', '$login', '$rate', '$ext', '$dst', '$row[src]', '$type', '$minutes', '$row[billsec]', '$cost', '$description')");
И в самом конце, пометить строки как полностью в обработанные:
mysql_query("UPDATE cdr SET userfield=`done` WHERE userfield=`step1`");
Вышенаписанное писалось под Москву, но легко может быть переделано под другой город или страну.
Ссылка на исходники: 77.108.85.102/habr/import.php.txt, 77.108.85.102/habr/functions.php.txt,