feat(rotas-entrada): dropdown de destino real (ramal/IVR/fila/grupo)
Pedido do usuário: "em vez de o campo de destino ser aberto tem que ter um dropdown listando todos os ramais do tennant e tb todas ivr e filas e grupos de ramais do tennant" — até aqui o destino era texto livre. Construir o dropdown revelou que fila e grupo NUNCA tinham sido implementados de verdade como destino possível — só ramal/IVR funcionavam. Oferecer as duas opções sem o mecanismo por trás seria mostrar um dropdown mentiroso, então: InboundRoute.destinationType (novo enum EXTENSION/IVR/QUEUE/CALL_GROUP) decide como buildInboundRouteXml interpreta o destino: - EXTENSION/IVR: inalterado, o mesmo transfer já testado (PHASE 56/58). - QUEUE: destinationNumber guarda o Queue.id; a resolução de entrada emite `answer` + `callcenter data="<queueId>@<domain>"` direto, sem tocar no dialplan "default". `callcenter` entrou no allowlist de applications com o mesmo risco zero de `pickup`. - CALL_GROUP: destinationNumber guarda o Extension.callGroup; a resolução consulta AGORA (nunca um snapshot salvo) todos os ramais com esse callGroup e emite um `bridge` multi-leg — toca todos ao mesmo tempo, quem atender primeiro cancela os outros. Trocar quem está no grupo depois de criar a rota já vale na próxima chamada. Testado ponta a ponta com chamadas reais nos 2 mecanismos novos: fila — softphone externo discou o DID, show channels confirmou a chamada dentro da application callcenter com o nome certo da fila; grupo — 2 ramais reais no mesmo callGroup, a chamada tocou nos DOIS ao mesmo tempo (mesmo call_uuid, ambas RINGING), atender em um cancelou o outro automaticamente — ring group de verdade. Tela: "Tipo de destino" + um segundo dropdown com as opções reais do tenant pra cada tipo (ramais, menus de IVR, filas, ou os valores distintos de callGroup já usados em algum ramal). Testado com Playwright: os 4 tipos aparecem, e trocar o tipo atualiza as opções do segundo dropdown corretamente. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BFaBaBSQGhyXGEgtTYZGV8
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
-- PHASE 62: dropdown de destino (ramal/IVR/fila/grupo) na rota de entrada
|
||||
CREATE TYPE "inbound_route_destination_type" AS ENUM ('EXTENSION', 'IVR', 'QUEUE', 'CALL_GROUP');
|
||||
|
||||
ALTER TABLE "inbound_routes" ADD COLUMN "destination_type" "inbound_route_destination_type" NOT NULL DEFAULT 'EXTENSION';
|
||||
@@ -445,6 +445,15 @@ model Trunk {
|
||||
@@map("trunks")
|
||||
}
|
||||
|
||||
enum InboundRouteDestinationType {
|
||||
EXTENSION
|
||||
IVR
|
||||
QUEUE
|
||||
CALL_GROUP
|
||||
|
||||
@@map("inbound_route_destination_type")
|
||||
}
|
||||
|
||||
// Rota de entrada por DID (PHASE 56) — achado real: nenhuma chamada que
|
||||
// chega por um tronco carrega `b2bcall_tenant_id` hoje (só ramal
|
||||
// registrado e discagem de saída setam essa variable), então uma chamada
|
||||
@@ -462,13 +471,25 @@ model InboundRoute {
|
||||
didNumber String @unique @map("did_number")
|
||||
description String?
|
||||
|
||||
// Contexto de dialplan do TENANT DONO que recebe a chamada depois da
|
||||
// resolução (ex.: "default" pra cair direto na discagem interna já
|
||||
// existente, ou um contexto de IVR dedicado) + o destination_number
|
||||
// sintético usado dentro dele (número de ramal real, ou um destino
|
||||
// reservado do menu de IVR).
|
||||
destinationContext String @default("default") @map("destination_context")
|
||||
destinationNumber String @map("destination_number")
|
||||
// PHASE 62 — achado real reportado pelo usuário: o destino de uma rota
|
||||
// de entrada era um campo de texto livre, sem dropdown de ramal/IVR/
|
||||
// fila/grupo. `destinationType` decide como `buildInboundRouteXml`
|
||||
// (packages/telephony) interpreta `destinationNumber`:
|
||||
// EXTENSION -> número do ramal (transfer pro contexto default, já
|
||||
// testado ponta a ponta na PHASE 56)
|
||||
// IVR -> sempre IVR_ENTRY_DESTINATION; `destinationContext`
|
||||
// é o `IvrMenu.context`
|
||||
// QUEUE -> `Queue.id` (o inbound route XML já emite `answer` +
|
||||
// `callcenter`, sem precisar de nenhuma regra nova em
|
||||
// "default" nem tocar no editor de dialplan)
|
||||
// CALL_GROUP -> o valor de `Extension.callGroup` — resolvido pra
|
||||
// lista de ramais TODA VEZ que a chamada entra (nunca
|
||||
// um snapshot: `apps/freeswitch-config` faz a query na
|
||||
// hora, então trocar quem está no grupo depois de criar
|
||||
// a rota já vale na PRÓXIMA chamada, sem re-salvar nada)
|
||||
destinationType InboundRouteDestinationType @default(EXTENSION) @map("destination_type")
|
||||
destinationContext String @default("default") @map("destination_context")
|
||||
destinationNumber String @map("destination_number")
|
||||
|
||||
enabled Boolean @default(true)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user