Como Criar um Script de Processamento de Chamadas
- Introdução
- Chamada de um Script de Processamento de Chamadas
- Visão Geral da API de Processamento de Chamadas
- Grupo de método Task
RouteToAsync(this ActiveConnection ac, ) - Grupo de método Task
DivertAsync(this ActiveConnection ac, ) - Grupo de método Task
ReplaceWithAsync(this ActiveConnection ac, ) - Exemplo de Script de Processamento de Chamadas
- Como executá-lo
- Comentários sobre o código
- Amostra de Código
- Veja Também
Introdução
Os scripts de processamento de chamadas, também chamados de Route Point, são um novo e poderoso recurso da V20. Eles permitem que você capture chamadas e as processe usando o código C# padrão, o que basicamente lhe dá possibilidades ilimitadas de analisar uma chamada e aplicar lógica personalizada. Aqui estão alguns exemplos:
- Analisar a ID do autor da chamada e atribuir agentes específicos
- Fazer pesquisas de clientes com base na ID do autor da chamada e encaminhar de acordo
- Verificar a hora e a data e processar uma chamada de acordo.
- Verificar a data e reproduzir um prompt com base na data.
Chamada de um Script de Processamento de Chamadas
Antes de escrever um script, você deve pensar onde e como deseja que esse script seja acionado. Você pode configurar um código de discagem para ele ou encaminhar chamadas para ele atribuindo-lhe um DID ou encaminhando-as para o script com base em uma determinada variável.
Na atualização 2, você poderá acionar a chamada em cada chamada de entrada que chegar a um tronco SIP!
Depois de decidir como o script será acionado, você precisará filtrar as chamadas e escrever sua lógica de processamento de chamadas.
Visão Geral da API de Processamento de Chamadas
A API consiste em três métodos principais que estão passando chamadas para o novo destino.
Grupo de método Task<CallControlResult> RouteToAsync(this ActiveConnection ac,<Destino>)
Esse método cria uma rota que está vinculada à conexão especificada ac
- ac - a conexão ativa de propriedade da RoutePoint. Quando o novo destino responde, sua conexão substitui ac. (participação do RoutePoint).
- O script deve lidar com falhas na tarefa. O script pode simplesmente chamar MyCall.Return para encerrar sua própria conexão com o chamador.
- O script pode tentar criar quantas rotas forem necessárias, mas a primeira rota respondida cancelará todas as outras e substituirá a participação do RoutePoint na chamada (encerrará a chamada para o RoutePoint).
- O RouteToAsync pode ser executado em qualquer estado da conexão com o RoutePoint. Portanto, o RoutePoint pode executar o roteamento em segundo plano ao se comunicar com o chamador (reproduzir prompts, manipular DTMFs etc.).
- Quando a tarefa é bem-sucedida, a chamada é revogada do RoutePoint (MyCall é desconectada) e o novo destino continua a ser tratado.
Grupo de método Task<CallControlResult> DivertAsync(this ActiveConnection ac,<Destino>)
Esse método desvia a chamada para o novo destino sem estabelecer (atender) a conexão (toque no RoutePoint).
- Se uma chamada já estiver estabelecida com o RoutePoint, o método falhará e o RouteToAsyc/ReplaceWithAsync deverá ser usado
- A conexão ativa (em estado de toque) pertencente ao RoutePoint será substituída por um novo destino e o RoutePoint será desconectado da chamada.
- Esse método é útil se o ponto de rota não precisar interagir com o chamador.
- Se uma tarefa tiver falhado, o script poderá continuar a lidar com a conexão com o chamador.
- Quando a tarefa é bem-sucedida, a chamada é revogada do RoutePoint (a conexão MyCall é encerrada) e o novo destino inicia o tratamento da chamada. O script do RoutePoint é alternado para o modo Wrap Up e precisa concluir seu próprio trabalho.
Grupo de método Task<CallControlResult> ReplaceWithAsync(this ActiveConnection ac,<Destino>)
Também conhecido como método de "transferência cega".
- Permitido somente no modo conectado (o RoutePoint aceitou a chamada e interage com o usado).
- O autor da chamada será colocado em espera.
- A tarefa falhará se o destino não puder ser alcançado.
- O script pode continuar processando a chamada após a falha da tarefa (se o chamador ainda estiver conectado ao RoutePoint).
- Quando uma tarefa é bem-sucedida, a conexão do script (ICallHandler.MyCall) é encerrada e o script é separado do tratamento da chamada (o novo participante cuidará do chamador).
Exemplo de Script de Processamento de Chamadas
Este exemplo demonstra como criar um ponto de rota personalizado e como programá-lo:
- Estrutura básica do código C# fornecido à RoutePoint
- Uso básico dos métodos de extensão TCX.PBXAPI.CallControlAPI para a interface ActiveConnection (ICall)
- Trabalho básico com o objeto MyCall fornecido pelo CallFlowScriptingCore
- Trabalho básico com a configuração (parâmetros do PABX)
- Uso do método de extensão RouteToAsyc do objeto ActiveConnection
Um exemplo da funcionalidade do RoutePoint:
- O ponto de rota está aceitando apenas chamadas enviadas por meio de transferência cega do telefone (Ramal). As chamadas diretas são rejeitadas.
- Chamadas ilimitadas podem ser transferidas para esse RoutePoint por qualquer ramal simultaneamente (cada chamada é tratada separadamente)
- A chamada é retornada após 15 segundos para o transferidor (ramal) diretamente (sem encaminhamento aplicado). Se a chamada retornada não for atendida em 15 segundos, a chamada será cancelada e repetida novamente em 15 segundos.
- O chamador ouve música em espera, conforme configurado para Parking no PABX.
Como executá-lo
- Crie um RoutingPoint com qualquer número - por exemplo, 101 - e defina a propriedade RoutePoint.ScriptCode como o texto abaixo (a interface do usuário ainda não permite criar um ponto de roteamento com código personalizado (escrito à mão); é necessário algum tipo de arquivo zip, que não é realmente necessário para um script simples)
- O RoutePoint deve aparecer na lista correspondente ("aplicativos CFD" neste momento) com um ponto verde [a compilação não deve falhar para esse código])
- Em seguida:
- Se algum ramal transferir sua chamada para o número #101, a chamada será retornada em 15 segundos.
- O chamador ouvirá música em espera, pois ela está configurada para estacionamento. (O script usa essa configuração, mas o código pode ser modificado para gerar outro conteúdo para o chamador).
- Se a chamada retornada não for atendida, o RoutePoint tentará novamente (e novamente) 15 segundos após a tentativa anterior até que o chamador não abandone a chamada ou o transferidor original atenda (ou sua chamada seja capturada).
Comentários sobre o código
- O código do objeto "com script" é baseado em (usa, implementa e/ou herda)
- Espaço de Nome CallFlow
- CallFlow.ICall
- CallFlow.ICallHandler
- CallFlow.ICallHandlerEx
- CallFlow.ScriptBase<T>
- A classe "Objeto de Script" deve herdar CallFlow.ScriptBase<T> e implementar todos os métodos abstratos necessários para sua instância.
- O objeto está em execução quando o ScriptingHost executa o manipulador de chamadas usando o método ICallHandler.Start.
- O script deve ser encerrado explicitamente com ICall.Return.
- A implementação preferencial do método ICall.Start é "async void", que executa uma tarefa separada (deve capturar todas as exceções).
- A implementação do script deve controlar apenas o objeto MyCall exposto pelo Scripting Host. Ele é o único objeto da sessão do script de chamada.
- Quando o MyCall (participação do ponto de rota na chamada) for encerrado, a implementação do script deverá encerrar e terminar sua sessão.
- O script de fluxo de chamadas não é uma forma de monitorar a configuração do sistema ou quaisquer recursos externos.
- Não se trata de uma forma de monitorar todas as chamadas no sistema.
- É apenas uma lógica do RoutePoint, que pode ser integrada a outros fluxos de chamadas.
- Em outras palavras: o script lida com uma das chamadas que estão conectadas ao RoutePoint, mas nunca inicia uma nova chamada.
- A API de encaminhamento é encapsulada na classe estática TCX.PBXAPI.CallControlAPI, que expõe métodos de extensão para
- TCX.Configuration.ActiveCannection
- TCX.Configuration.DN
- TCX.Configuration.RegistrarRecord
Amostra de Código
#nullable disable
using CallFlow;
using System;
using System.Threading;
using System.Threading.Tasks;
using TCX.Configuration;
using TCX.PBXAPI;
namespace dummy
{
public class ParkingRoutePointSample : ScriptBase<ParkingRoutePointSample>
{
async Task<CallControlResult> ProcessAutoPickup(RoutePoint sp, DestinationStruct returnTo, CancellationToken token)
{
while (true)
try
{
return await Task.Delay(TimeSpan.FromSeconds(15), token).ContinueWith(x =>
{
MyCall.Trace("{0} - automatic redirection of the call from {1}.{2} to '{3}'", MyCall.DN, MyCall.Caller?.CallerID, MyCall.Caller?.DN, returnTo);
return MyCall.RouteToAsync(new RouteRequest
{
RouteTarget = returnTo,
TimeOut = TimeSpan.FromSeconds(15) //will ring until failure
}
);
}
, TaskContinuationOptions.NotOnCanceled).Unwrap();
}
catch (OperationFailed ex)
{
MyCall.Trace("Automatic redirection failed: {0}", ex.TheResult);
MyCall.Trace("Continue hold call from {0}({1}) on {2}", MyCall.Caller?.CallerID, MyCall.Caller?.DN, MyCall.DN);
continue;
}
}
PhoneSystem ps = null;
/// <summary>
///
/// </summary>
public override async void Start()
{
await Task.Run(async () =>
{
try
{
MyCall.Debug($"Script start delay: {DateTime.UtcNow - MyCall.LastChangeStatus}");
MyCall.Debug($"Incoming connection {MyCall}");
ps = MyCall.PS as PhoneSystem;
CallControlResult lastresult = null;
DN referredBy = null;
RoutePoint thisPark = null;
string callerID = "";
DN callerDN = null;
bool scriptCompleted = true;
try
{
referredBy = MyCall.ReferredByDN?.GetFullSnapshot() as Extension;
thisPark = MyCall.DN?.Clone() as RoutePoint;
callerID = MyCall.Caller?.CallerID;
callerDN = MyCall.Caller?.DN?.Clone() as DN;
MyCall.Trace(
"Parked call from {0}({1}) on {2}", callerID, callerDN, thisPark
);
if (referredBy == null)
{
MyCall.Trace("{0} rejects call from {1}. Reason: No referrer specified", thisPark, callerDN);
return;
}
var cancelationToken = new CancellationTokenSource();
MyCall.OnTerminated += () =>
{
cancelationToken.Cancel();
};
lastresult = await MyCall.AssureMedia().ContinueWith(
x =>
{
if(!string.IsNullOrWhiteSpace(ps.GetParameterValue("PARK_MOH_SOURCE")))
MyCall.SetBackgroundAudio(true, new string[] { ps.GetParameterValue("PARK_MOH_SOURCE") });
else
MyCall.SetBackgroundAudio(true, new string[] { ps.GetParameterValue("MUSICONHOLDFILE") });
return ProcessAutoPickup(thisPark, new DestinationStruct(referredBy), cancelationToken.Token);
}, TaskContinuationOptions.OnlyOnRanToCompletion).Unwrap();
}
catch (PBXIsNotConnected ex)
{
MyCall.Error($"Call control API is not available:\n{ex}");
scriptCompleted = false;
}
catch (TaskCanceledException)
{
MyCall.Trace($"Call was disconnected from parking place");
}
catch (Exception ex)
{
MyCall.Error($"Parking failure:\n{ex}");
scriptCompleted = false;
}
finally
{
try
{
MyCall.Info("Call from {0}({1}) parked by {2} on {3} finished with result={4}", callerID, callerDN, referredBy, thisPark, lastresult?.ToString() ?? "terminated");
}
catch (Exception ex)
{
MyCall.Error($"SharedParkingFlow finalize exception {ex}");
}
MyCall.Return(scriptCompleted);
}
}
catch
{
MyCall.Return(false);
}
});
}
}
}
Veja Também
- API de Controle de Chamadas para Linux
- API de Controle de Chamadas para Windows
- Google Cloud Storage & Speech API
- Script de Processamento de Chamadas para Entrada de DTMF
Última Atualização
Este documento foi atualizado pela última vez em 5 de março de 2024
https://www.3cx.com.br/docs/manual/script-processamento-chamadas/
