feat(ivr): dropdown de destino (fila/outro IVR) numa opção de menu, com bloqueio de ciclo (PHASE 67)
Mesmo gap que Rotas de Entrada já tinha resolvido na PHASE 62: uma opção dentro de um menu de IVR só sabia apontar pra ramal (bridge fixo). Novo IvrMenuOption.destinationType (EXTENSION/QUEUE/IVR) decide a action de cada branch em buildIvrDialplanExtensions, mesmo padrão de buildInboundRouteXml — QUEUE vira answer+callcenter, IVR vira transfer pro IVR_ENTRY_DESTINATION do menu alvo (efetivamente um sub-menu). Sem CALL_GROUP aqui de propósito: diferente de InboundRoute (resolvido a cada chamada), o dialplan de um IVR é compilado uma vez ao salvar — "quem está no grupo agora" ficaria desatualizado até a próxima edição. "Outro IVR" cria a primeira forma de um menu apontar pra outro (uma InboundRoute nunca é ela mesma um menu, nunca formava ciclo antes). assertNoIvrCycle monta o grafo com todos os menus do tenant antes de compilar e rejeita qualquer save que criaria um ciclo, em create e update. Os dois editores de IVR (form clássico e o editor visual de nós) ganharam o mesmo par de dropdowns "Tipo"/"Destino" já usado em Rotas de Entrada. Testado ponta a ponta com Playwright, tenant/fila/2 menus de IVR reais criados na hora: menu com opção Fila e menu com opção Outro IVR apontando pro primeiro, os dois persistindo certo depois de reload completo. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BFaBaBSQGhyXGEgtTYZGV8
This commit is contained in:
39
TODO.md
39
TODO.md
@@ -2417,6 +2417,45 @@ já em produção] que depois vai vir via sip comum ao b2bcall")
|
||||
`sip-user`/`sip-domain`/`sip-server` corretos e a senha presente
|
||||
(não vazia) assim que o agente com ramal vinculado abre `/app`.
|
||||
|
||||
## PHASE 67 — Dropdown de destino (fila/outro IVR) numa opção de IVR
|
||||
(pedido do usuário: "dentro do IVR tem que dar a opção de eu colocar como
|
||||
destino não apenas os ramais mas tb as filas e outra IVR, como feito na
|
||||
rota de entrada")
|
||||
- [x] Mesmo gap que existia em Rotas de Entrada até a PHASE 62:
|
||||
`IvrMenuOption` só tinha `destinationNumber` (sempre interpretado
|
||||
como ramal), sem tipo nenhum. Novo enum próprio
|
||||
`IvrOptionDestinationType` (EXTENSION/QUEUE/IVR) — SEM
|
||||
`CALL_GROUP` de propósito: diferente de `InboundRoute` (resolvido
|
||||
por chamada, sempre fresco), o dialplan de um IVR é compilado UMA
|
||||
VEZ ao salvar o menu — "quem está no grupo agora" ficaria
|
||||
desatualizado até a próxima edição, comportamento silenciosamente
|
||||
stale que ninguém pediu.
|
||||
- [x] `buildIvrDialplanExtensions` (packages/telephony) — cada branch de
|
||||
dígito decide a action pelo `destinationType`, mesmo padrão de
|
||||
`buildInboundRouteXml`: EXTENSION continua `bridge` direto;
|
||||
QUEUE vira `answer` + `callcenter`; IVR vira `transfer` pro
|
||||
`IVR_ENTRY_DESTINATION` do contexto do menu alvo — reaproveita a
|
||||
MESMA entrada que uma `InboundRoute` usa pra entrar naquele menu.
|
||||
- [x] "Outro IVR" cria um grafo entre menus que nunca existia antes (uma
|
||||
`InboundRoute` não é ela mesma um menu, nunca podia formar ciclo).
|
||||
`assertNoIvrCycle` (novo, `ivr-menus.controller.ts`) monta o grafo
|
||||
com TODOS os menus do tenant antes de compilar e rejeita
|
||||
(409) qualquer combinação que criaria um ciclo — A→B→A ou até
|
||||
A→A — checado tanto em `create` quanto `update`.
|
||||
- [x] Frontend: os dois editores de IVR (form clássico `ivr-view.tsx` e
|
||||
o editor visual `ivr-flow-editor.tsx`, PHASE 60/61) ganharam o
|
||||
mesmo dropdown "Tipo" + "Destino" condicional já usado em Rotas de
|
||||
Entrada — precisou buscar `queues` na `page.tsx` do IVR (só
|
||||
`extensions` era buscado antes) e passar a lista de OUTROS menus
|
||||
(excluindo o próprio, de propósito, pra reduzir a chance de
|
||||
self-reference direto na UI — o backend segue sendo quem
|
||||
garante isso de verdade).
|
||||
- [x] Testado ponta a ponta com Playwright, tenant/fila/2 menus de IVR
|
||||
reais criados na hora: Menu A com opção tipo Fila (aponta pra
|
||||
"Fila QA"), Menu B com opção tipo Outro IVR (aponta pro Menu A) —
|
||||
os dois persistiram com o tipo certo, sobrevivendo a um reload
|
||||
completo da página.
|
||||
|
||||
---
|
||||
|
||||
## Riscos conhecidos
|
||||
|
||||
Reference in New Issue
Block a user