OTRS ( Open-source Ticket Request System) — открытая система обработки заявок. OTRS позволяет организациям, занимающимся технической поддержкой каких-либо проектов, совместно работать над решением проблем пользователей. Программа написана на языке Perl, поддерживает множество СУБД (MySQL, PostgreSQL и т. д.), может интегрироваться с LDAP каталогом, распространяется по лицензии — AGPL версии 3. Программный продукт протестирован на таких системах как: Linux, Solaris, AIX, FreeBSD, OpenBSD, Mac OS X и Windows.
Системы обработки заявок, такие как OTRS, обрабатывают заявки как обыкновенные почтовые сообщения (email). Когда клиент посылает по почте запрос, система создает новую заявку. Клиентам так-же доступен веб-интерфейс для создания новых заявок, проверки состояния существующих, написания ответов на старые заявки а также поиска их собственных заявок. Для интеграции собственных дополнений и приложений существует — OTRS API. Воспользуемся предоставленными возможностями для формирования заявки по телефону.
Задача: При входящем соединении на номер HelpDesk, происходит формирование заявки ( на основании определившегося номера) и вызов передается оператору. При ответе оператор открывая интерфейс работы с заявками уже имеет новую сформированную заявку и ему только необходимо ввести содержание.
Реализация: На стороне OTRS.
Для формирования заявки будем использовать протокол SOAP. SOAP ( Simple Object Access Protocol — простой протокол доступа к объектам) — протокол обмена структурированными сообщениями в распределённой вычислительной среде. Первоначально SOAP предназначался в основном для реализации удалённого вызова процедур (RPC). Сейчас протокол используется для обмена произвольными сообщениями в формате XML, а не только для вызова процедур. Официальная спецификация последней версии 1.2 протокола никак не расшифровывает название SOAP. SOAP является расширением протокола XML-RPC. SOAP может использоваться с любым протоколом прикладного уровня: SMTP, FTP, HTTP, HTTPS и др. Однако его взаимодействие с каждым из этих протоколов имеет свои особенности, которые должны быть определены отдельно. Чаще всего SOAP используется поверх HTTP. SOAP является одним из стандартов, на которых базируются технологии веб-служб.
Для использования данной возможности, необходимо задать имя пользователя и пароль. Следуем Администрирование -> Конфигурация системы. Выбираем модуль Core::SOAP и подтверждаем введенные данные.

Дальнейшие наши действия будут проходить на стороне Asterisk. Предположим номер на который приходит входящий вызов HelpDesk — 4509, а номер оператора — 4507. Отредактируем файл конфигурации vim /etc/asterisk/extensions_custom.conf следующим образом.
[otrs]
- exten => 4509,1,Answer
- exten => 4509,n,AGI(zayav.agi)
- exten => 4509,n,Dial(SIP/4507,300,tr)
Файл — zayav.agi, обычный скрипт AGI, с двумя добавленными последними строками, которыми мы получаем и передаем номер позвонившего абонента в скрипт формирования заявки (my $cid = $AGI{‘callerid’};system( «/opt/otrs/scripts/rpc_ast.pl $cid»);).
#!/usr/bin/perl
use strict;
$|=1;
# Setup some variables
my %AGI; my $tests = 0; my $fail = 0; my $pass = 0;
while() {
chomp;
last unless length($_);
if (/^agi_(\w+)\:\s+(.*)$/) {
$AGI{$1} = $2;
}
}
sub checkresult {
my ($res) = @_;
my $retval;
$tests++;
chomp $res;
if ($res =~ /^200/) {
$res =~ /result=(-?\d+)/;
if (!length($1)) {
print STDERR "FAIL ($res)\n";
$fail++;
} else {
print STDERR "PASS ($1)\n";
$pass++;
}
} else {
print STDERR "FAIL (unexpected result '$res')\n";
$fail++;
}
}
my $result = ;
&checkresult($result);
my $cid = $AGI{'callerid'};
system( "/opt/otrs/scripts/rpc_ast.pl $cid");
exit 0;
Скрипт — /opt/otrs/scripts/rpc_ast.pl выполняет две задачи. Первая — извлекает из базы OTRS на основании определенного номера телефона — имя пользователя и его ID (Имя пользователя и пароль для подключения к базе OTRS приведены по умолчанию). Необходимые данные находятся в таблице customer_user.

Подразумевается что данный пользователь есть в Базе OTRS и имеет необходимые атрибуты (в частности номер телефона).
$database="otrs";
$hostname="localhost";
$user="otrs";
$password='hot';
$myquery= "SELECT login,customer_id FROM customer_user where phone='$cid'";
$dbh = DBI->connect("DBI:mysql:database=$database;host=$hostname",
$user, $password) || die print "Can't connect";
$sth = $dbh->prepare( $myquery )
|| die "Can't prepare statement: $DBI::errstr";
$sth->execute;
while ( @result = $sth->fetchrow_array)
{
$rez1=$result[0];
$rez2=$result[1];
}
$dbh->disconnect;
Вторая — формирует заявку и ее атрибуты.
use strict;
use warnings;
use SOAP::Lite( 'autodispatch', proxy => 'http://127.0.0.1/otrs/rpc.pl' );
my $User = 'admin';
my $Pw = 'user';
my $RPC = Core->new();
my $TicketNumber = $RPC->Dispatch( $User, $Pw, 'TicketObject', 'TicketCreateNumber' );
my %Ticket = $RPC->Dispatch( $User, $Pw, 'TicketObject', 'TicketGet', TicketID => 1 );
my %TicketData = (
Title => "Заявка с номера $cid",
Queue => 'Raw',
Lock => 'unlock',
Priority => '2 low',
State => 'new',
CustomerID => $rez2,
CustomerUser => $rez1,
OwnerID => 2,
UserID => 'admin',
);
my $TicketID = $RPC->Dispatch( $User, $Pw, 'TicketObject', 'TicketCreate', %TicketData => 1 )
|| die "Failed to create ticket: $!";
my $ArticleID =$RPC->Dispatch($User, $Pw, 'TicketObject', 'ArticleCreate',
TicketID => $TicketID,
ArticleType => 'webrequest',
SenderType => 'customer',
From => '
you@firma.com',
To => '
firma@firma.com',
Subject => "Заявка с номера $cid",
Body => "Заявка с номера $cid .... получите",
ContentType => 'text/plain',
Charset => 'ISO-8859-1',
HistoryType => 'WebRequestCustomer',
HistoryComment => '....Текст.....',
UserID => 2,
Loop => 0,
);
exit 0;
Проверяем работу — пробуем набрать на настроенный для выполнения agi скрипта номер. Для контроля выполнения, включим режим отладки — agi set debug on.
AGI Tx >> agi_channel: SIP/84956693308-0000039a
AGI Tx >> agi_language: en
AGI Tx >> agi_type: SIP
AGI Tx >> agi_uniqueid: 1314075508.1094
AGI Tx >> agi_version: 1.6.2.17.3
AGI Tx >> agi_callerid: 89161229624
AGI Tx >> agi_calleridname: 89161229624
AGI Tx >> agi_callingpres: 0
AGI Tx >> agi_callingani2: 0
AGI Tx >> agi_callington: 0
AGI Tx >> agi_callingtns: 1
AGI Tx >> agi_dnid: 84956693308
AGI Tx >> agi_rdnis: unknown
AGI Tx >> agi_context: otrs
AGI Tx >> agi_extension: 4509
AGI Tx >> agi_priority: 2
AGI Tx >> agi_enhanced: 0.0
AGI Tx >> agi_accountcode:
AGI Tx >> agi_threadid: -1251619952
AGI Tx >>
AGI Tx >> 200 result=0 endpos=3520
-- AGI Script zayav.agi completed, returning 0
и — voilà.

заявка сформирована. Отвечаем на входящий вызов, открываем сформированную заявку и вводим «жалобу» клиента. Конечно рекомендуется использовать несколько больше атрибутов из базы клиента для формирования более «правильной» заявки.
