agenda: Fase 5 (status change/edit cobrada) + indicadores visuais + UX convenio

DB
- drop agenda_excecoes (substituida por financial_exceptions + lock-edit
  baseado em financial_records)
- financial_records.payment_link (Asaas + link compartilhavel)
- financial_exceptions.consume_on_miss (rotular nao-show consome ou nao)
- billing_contracts.charging_style (upfront/saldo/per_session)

Payment refactor
- paymentSettlement -> paymentMethod (string) + markPaidNow (bool).
  Handler aplica payment_method sempre; status='paid'+paid_at apenas
  quando markPaidNow=true && method != 'link'. Asaas (link) sempre
  liquida via webhook, nunca nasce paid.
- create_financial_record_for_session com pos-RPC patch pra payment_method
  e (opcional) status='paid' quando user marca "ja recebi".

Indicadores visuais (3 canais distintos por estado)
- Paid: barra esquerda emerald-500 4px na agenda (MelissaAgenda),
  pi-check-circle no popover/Resumo.
- Pending: badge \$ amber canto direito (mantido); linha amber no popover/
  Resumo "A receber R\$ X (cobranca pendente)".
- Neutro: sem badge nem barra (compromisso pessoal, bloqueio, ou
  ocorrencia virtual de pacote upfront/saldo).
- Bulk-load de paymentState em _reloadRange etapa 4 (1 query unica em
  financial_records mapeada por agenda_evento_id).
- AgendaEventDialog Resumo lateral ganha linha entre pi-clock e
  pi-map-marker via novo sessionPaymentRecord (sem guard de
  occurrenceMode, contrario ao occFinancialRecord que continua so pra
  Rail/Clinica). 5 estados: paid+paid_at, overdue+venceu, pending+vence,
  sem cobranca c/ valor, sem cobranca s/ valor.

UX de convenio
- InsurancePlanServiceQuickCreateDialog novo: cadastra procedimento
  POR CIMA do AgendaEventDialog sem sair da agenda. Auto-seleciona
  novo procedimento so quando nada estava selecionado antes.
- Caixa cinza "Cadastrar procedimento" sempre visivel quando convenio
  selecionado, com copy variavel (0 procedimentos: chamada urgente;
  1+: "se quiser adicionar mais").
- "+ Novo convenio" toolbar em ConfiguracoesConveniosPage (botao
  estava faltando, empty state mandava clicar em botao inexistente).
- Hint contextual abaixo do card Sessao/Honorarios: convenio = "N da
  guia eh opcional", gratuito = "sem cobranca", particular = sem hint.
  Label "N da Guia" tambem ganhou "(opcional)" no service-picker dialog.

Bug fixes
- pickDbFields whitelist faltando 'modalidade' (useMelissaAgenda.js:74)
  — sessoes avulsas eram salvas como presencial independente da
  escolha visual. Adicionado.
- goToConveniosConfig removida — fazia router.push("/therapist/
  configuracoes/convenios") mas /configuracoes/* eh rota raiz, nao
  filha. Substituida pelo quick-create inline (#1).
- bloqueioCobrindo + dialogBlockOverlap passados via deps em
  _buildHandlers (refs do useMelissaAgenda nao sao acessiveis no
  escopo de _buildHandlers).

Fase 5 (status change + edit cobrada)
- AgendaStatusChangeConfirmDialog: confirm dialog quando user muda
  status pra realizada/faltou/cancelado, com opcoes de markPaid ou
  gerar cobranca conforme o caso.
- useAgendaBloqueios novo composable: extrai logica de bloqueios
  cinza (background events) do MelissaAgenda.

Doc viva
- src/docs/agenda-compromisso-financeiro-cenarios.html: 13 cenarios
  de teste manual. C1-C4 ja validados. Cada teste validado vira parte
  da doc final pra area de ajuda (pos-Fase 9).

Wiki/handoff
- agenda-compromisso-fluxo e agenda-billing-pesquisa-mercado (decisoes
  arquiteturais sobre billing).
- HANDOFF.md atualizado.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Leonardo
2026-05-19 08:31:18 -03:00
parent 41c44272a3
commit e95ed9b585
41 changed files with 8715 additions and 852 deletions
+259
View File
@@ -14,6 +14,142 @@ Chronological, append-only record of everything that's happened in this wiki.
---
## [2026-05-18 23:30] session | UX de convenio refinado (3 fixes) + hint contextual
Touched: none (sem nova wiki page; tudo em codigo + HANDOFF)
Detalhes: tarde inteira consumida em refinar UX de convenio antes do
save real do C5. User bateu em 3 problemas seguidos:
1) Botao "Cadastrar" do procedimento navegava pra /pages/notfound.
Root cause: goToConveniosConfig prefixava com /therapist|/admin mas
/configuracoes/* eh rota raiz sob AppLayout (sibling, nao filho). Em
Melissa, convenios mora via secao=cfg-convenios sem URL propria.
Fix descartado: user nao queria sair da agenda. Criamos quick-create
inline (#2). Removi goToConveniosConfig (dead code).
2) InsurancePlanServiceQuickCreateDialog (novo componente). Mesmo pattern
do InsurancePlanQuickCreateDialog. 2 campos: nome + valor que o
convenio paga. Wiring em useAgendaEventLifecycle: planServiceQuickDlgOpen
+ openPlanServiceQuickCreate + onPlanServiceCreated. Apos criar:
loadInsurancePlans + auto-seleciona SO se nada estava selecionado
antes. UI refatorada: caixa cinza com botao "Cadastrar" SEMPRE
visivel quando convenio selecionado, copy varia por contagem
(0 procedimentos = chamada urgente; 1+ = "se quiser adicionar mais").
3) Botao "+ Novo convenio" faltando em ConfiguracoesConveniosPage.vue.
addingNew=true sem botao pra setar. Empty state mandava clicar em
botao inexistente. Fix: toolbar topo com Button label="Novo convenio"
@click="addingNew = true". Empty state corrigida.
Hint contextual abaixo do card Sessao/Honorarios. User: "Nº da guia
eh obrigatorio?" — consegui salvar sem. Tentativa 1: coloquei em
v-if=occurrenceMode (errado, so Rail/Clinica). Tentativa 2: fluxo
principal Melissa (linha 2305). Copy: convenio = "Nº da guia eh
opcional…", gratuito = "Sessão gratuita…", particular = sem hint.
Label "Nº da Guia" tambem ganhou "(opcional)".
PROXIMO: rodar de fato o save do C5 (Sandor + Unimed + R$ 95). Tudo
preparado, agora eh testar end-to-end.
## [2026-05-18 21:45] session | Linha de cobranca no popover (3 estados) + Resumo do dialog
Touched: none (sem nova wiki page)
Detalhes: extensao do trabalho da sessao anterior (barra verde na agenda).
User pediu pra popover mostrar tambem o estado pago, nao so pendente.
Lembrava que "tinha algo assim mas talvez seja pra outra coisa" —
verifiquei: occFinancialRecord existia mas com guard de occurrenceMode,
servindo Fase 6 (lock-edit) em Rail/Clinica apenas. Decidi NAO unguardar
pra nao ativar lock prematuro em Melissa (isso eh C13).
MelissaEventoPanel.vue: showPaymentRow agora cobre paid tambem; novo
paymentVariant + paymentIcon (pi-check-circle quando pago, pi-dollar
nos outros); paymentLabel inclui "Pago · R$ X,XX"; CSS com 3
modificadores .evento-row--pay-{paid|pending|none} + dark mode.
AgendaEventDialog.vue + useAgendaEventLifecycle.js: novo ref
sessionPaymentRecord (independente do occFinancialRecord). Loader sem
guard, chamado no mesmo lifecycle. Computed paymentSummary cobre 5
estados (paid + verde + paid_at, overdue + vermelho + venceu, pending
+ amber + vence, sem cobranca c/ valor, sem cobranca s/ valor). Nova
linha summary-row entre pi-clock e pi-map-marker em ambas as copias do
Resumo (mobile inline + desktop floating). CSS com 4 classes
.aed-pay-summary-row--{paid|pending|overdue|none}.
@cobranca-atualizada do AgendaEventoFinanceiroPanel agora tambem
dispara loadSessionPaymentRecord pra a linha refrescar quando user
marca pago pelo panel inline.
PROXIMO: cenario 5 (Sandor + Unimed Nacional, R$ 95, convenio).
## [2026-05-18 21:00] session | Cenario 4 OK + barra esquerda verde pra sessao paga
Touched: none (decisao salva em memory/, doc HTML atualizado, sem nova wiki page)
Detalhes: cenario 4 (Joyce R$180 PIX "Ja recebi") testado e passou — toast,
record paid+pix+paid_at, badge $ removido. User pediu sinalizacao visual
pra sessao paga "olhar e saber". Brainstorm de 6 opcoes (check verde
canto, barra esquerda, fundo green-50, $ riscado, so popover, 3 canais
combinados). User escolheu #6 — 3 canais visuais distintos:
- pago: barra verde 4px borda esquerda (emerald-500)
- pendente: badge $ amber canto direito (como antes)
- neutro: nem um nem outro (sem cobranca / virtual)
Implementado em MelissaAgenda.vue (classe ma-evt--paid via classNames,
CSS forca border-left-color !important porque FC seta borderColor inline).
Doc HTML legenda "Indicadores visuais" expandida pros 3 estados (3 mocks
empilhados). Estado-alvo do C4 reescrito. Memoria persistida em
memory/project_agenda_payment_indicators.md (decisao + onde aplicar quando
replicar em Rail/Clinica). HANDOFF atualizado pra apontar C5 como
proximo.
## [2026-05-17 02:30] session | Testes C1-C3 + payment refactor + indicadores visuais + fix modalidade
Touched: agenda-compromisso-fluxo (implicit via HANDOFF.md, sem nova pagina)
Detalhes: rodada de testes manuais dos cenarios do doc viva
src/docs/agenda-compromisso-financeiro-cenarios.html. Cenarios 1, 2 e 3 ok.
CENARIO 1 (bloqueio):
- Fix `bloqueioCobrindo is not defined` em onSelectTime — funcao mora no
escopo de useMelissaAgenda mas onSelectTime esta em _buildHandlers.
Passada via deps, mesmo padrao do _openStatusDialog.
- Soft warn de bloqueio sobre slot agora vai DENTRO do dialog (Message
warn no topo do step 1) em vez de toast atras do overlay. Novo ref
dialogBlockOverlap no composable + nova prop blockOverlapWarning no
AgendaEventDialog. Reset nos outros openers.
- Doc HTML cenario 1 expandido em 1a (criar) + 1b (agendar sobre
bloqueio), com mock visual da Message + comparacao agendador publico.
CENARIO 2 (avulsa sem cobranca):
- Hint chargeMode fonte 0.72rem -> 0.8125rem.
- Card Frequencia avulsa refeito: era empty state convidando configurar,
agora renderiza como "selecionado" com .aed-pay-summary (Tipo: Avulsa
/ Sessao unica, sem repeticao / botao Editar). Visual identico ao
estado configurado de pacote.
CENARIO 3 (avulsa cobrar ao salvar):
- Refactor paymentSettlement -> paymentMethod + markPaidNow. UI antiga
misturava metodo e status num Select unico ("Ja recebi - PIX"). Agora
2 controles: Select forma (sem prefixo "Ja recebi") + SelectButton
status (pendente / ja recebi). SelectButton oculto quando metodo='link'.
Wire em 3 camadas (Dialog -> useAgendaEventActions -> useMelissaAgenda
handler avulsa + _createPackageContract).
- Indicadores visuais de pagamento: bulk-load 1x em _reloadRange etapa 4
(financial_records mapeado por agenda_evento_id -> paid|pending|none).
normalizeForMelissa injeta paymentState + price. Badge $ amber 16px no
canto superior direito do evento da agenda (so sessao+paciente+nao-
virtual+!paid). Linha "A receber" amber abaixo do horario no popover
(MelissaEventoPanel), texto adaptativo.
- BUG FIX pickDbFields whitelist faltando 'modalidade' — todas as sessoes
avulsas criadas no Melissa ate hoje foram salvas como presencial no DB
independente da escolha visual. Adicionado ao allowed[]. Gotcha durador
salvo em memory/project_pickdbfields_whitelist.md.
DOC HTML AMPLAMENTE ATUALIZADO:
- Nova secao topo "★ Indicadores visuais de pagamento" com mocks (badge
$ + linha popover) e link em violeta no TOC.
- Caixa violeta "Indicadores visuais" em cada cenario relevante (C2-C9)
descrevendo o que aparece em cada caso.
- C4 ganhou caixa verde "estado-alvo" (sem badge, sem linha — pago).
- Receitas dos C2-C4 atualizadas pros 3 controles novos.
PROXIMO: cenario 4 (Joyce, "Ja recebi (dar baixa)"). Apos passar, seguir
ate C13. Quando todos passarem, replicar em AgendaTerapeutaPage (Rail) e
AgendaClinicaPage (Clinica). HANDOFF.md reescrito com tudo.
## [2026-05-05 23:45] session | Blueprint tabular Melissa + restore pacientes
Touched: none (sem mudança de wiki — handoff em HANDOFF.md)
Detalhes: criou `blueprints/melissa-table-page-blueprint.md` (~530L, 18 seções);
@@ -601,3 +737,126 @@ ComponentCadastroRapido + PatientCadastroDialog pra uso in-flow.
Database backup gerado: backups/2026-05-11/ (138 tabelas, 141 FKs).
Dashboard regenerado.
## [2026-05-11 17:00] session | AgendaEventDialog redesign completo + 2º dialog WIP
Touched: HANDOFF.md (reescrito do zero)
Detalhes: sessao longa de refator visual + UX do AgendaEventDialog.
Headers dos 4 cards (Paciente, Data/Horario, Sessao/Honorarios, Frequencia)
com altura fixa 40px, label so mobile, acoes a direita. Card Paciente
ganhou toggle Presencial/Online com pi-pencil substituindo SelectButton;
mini-links Editar/Limpar no lugar dos botoes redondos. Card Data e
Horario com body em 2 linhas (Data · Duracao / Inicio → Termino). Card
Sessao/Honorarios (renomeado de Pagamento) com Select dropdown default
particular + 3 estados (gratuito/empty/configurado-resumo). Card Extras
renomeado, com botao ? abrindo popover educativo. Layout 50/50 via
.aed-row-50 (Paciente|Data e Sessao|Frequencia).
DIALOGS NOVOS:
- serviceDialogOpen: cada servico vira card individual com preco unit,
total, botoes colapsaveis (Aplicar desconto, Alterar quantidade);
desconto mostra calculo em vermelho; footer fixo com Valor desta
sessao em pill tracejada primary; hint educativo Unidades vs
Recorrencia
- freqDialogOpen: empty/resumo, 4 sub-cards (.aed-freq-section: Tipo,
Dias, Quantidade, Proximas), chips renovados (.freq-tab borda solida
+ variant 2-line com 1 mes/4 sessoes), proximas ocorrencias com
separador por mes + referencia relativa (em 2 semanas/em 1 mes).
"Como interpretar o valor" REMOVIDO.
CONCEITO PACOTE (recorrencia >= 2):
- isPacote computed: criando >=2 OU editando hasSerie
- pacoteTotal = totalFromItems × totalOcorrencias
- Header dialog adapta: "Pacote · 4 Sessoes" / "Sessao do Pacote · Sessao"
/ "Editar Sessao" / "Nova Sessao"
- Resumo: modalidade vira "Presencial · Pacote"; wallet mostra total
pacote; linha extra "4× R$ 40 = R$ 160"
- Status da Sessao escondido em pacote
- pluralCommitment PT-BR (Sessao→Sessoes, Analise→Analises, ão→ões)
MODO EDIÇAO:
- Cadastro Rapido NAO aparece
- Cadastro Completo + toggle Modalidade + Ajustar Horario: disabled
com tooltip explicativo
- time-hero ganha --readonly (sem cursor pointer)
OUTROS: animacao de Dialog + backdrop blur REMOVIDOS (so nativo
PrimeVue); DataTable picker paciente coluna Acao agora frozen
alignFrozen=right; lista Recorrencias Aplicadas com numeracao 1/2/3
em badge primary; badge "atual" → "selecionado".
2º DIALOG EMPILHADO (WIP — BLOQUEIO PRA AMANHA):
- useMelissaAgenda.js: refs novos occDialogOpen/EventRow/StartISO/EndISO
- onEditSeriesOccurrence agora abre 2º dialog (em vez de mutar
dialogEventRow in-place silenciosamente)
- _buildHandlers recebe occDialog* via deps (sem isso dava
ReferenceError em runtime)
- MelissaLayout.vue: 2º AgendaEventDialog mountado paralelo, refs
destruturados como agendaOccDialog* (refs aninhados nao auto-
unwrappam no template — pattern conhecido do projeto)
- Status: ABRE, mas user reportou "nao é essa janela que tem de
abrir" — investigar amanha. Provavelmente precisa de prop pra
esconder Frequencia + Recorrencias Aplicadas no 2º dialog e
ajustar titulo pra "Editar Ocorrencia"
- Pendente replicar em Rail (AgendaTerapeutaPage L1630 + L3080) e
Clinica (AgendaClinicaPage L1119 + L2398) DEPOIS de estabilizar
no Melissa
Mudancas NAO commitadas: 5 arquivos (AgendaEventDialog.vue + dois
QuickCreateDialog + MelissaLayout + useMelissaAgenda). HANDOFF.md
reescrito do zero documentando tudo.
## [2026-05-12 17:55] session | occurrenceMode no 2º dialog da agenda
Touched: recorrencia-agenda
## [2026-05-13 14:00] session | pesquisa fluxo agenda Cliniko SimplePractice TherapyNotes
Touched: none
nTouched: agenda-billing-pesquisa-mercado, index
## [2026-05-13 21:00] session | Pesquisa mercado agenda billing
Touched: agenda-billing-pesquisa-mercado, index
## [2026-05-14 sessao continua] session | AgendaEventDialog testes manuais + correcoes
Touched: none (apenas logs detalhados; sem nova pagina wiki)
Detalhes: User testou fluxo de criacao avulsa (Henrique Lima Souza) e
recorrente (Donald Winnicott, 4×R$40) passo-a-passo. Achados/correcoes:
(1) Bug badge financeiro "Despesa" — campo `type` faltava em BASE_SELECT
de useFinancialRecords.js (caia em else → "Despesa"). Fix: adicionar type
no SELECT. (2) E5 toggle Presencial/Online: removido :disabled="isEdit"
(habilitado em ediçao tambem). (3) E6 Ajustar Horario: trocado por
v-if="!isEdit || !hasSerie" — visivel em criacao E em avulsa em edicao;
escondido em série recorrente (politica "esconder em vez de disabled"
salva na memoria, vale apenas pra agenda). (4) Botao cog + popover sobre
horarios online no time picker — padrao espelhado do Card Extras, linka
pra /melissa/agenda-config (ou /configuracoes/agenda fora do Melissa).
(5) Bug visual: pill --current + --online-cfg perdia destaque selected
porque online-cfg !important ganhava da cascade. Fix: regra combo com
mais especificidade. (6) Time picker vazava dia/hora/duracao pro card
principal quando fechado sem confirmar — snapshot ao abrir + revert no
@hide se _tpCommitted=false (added Cancelar button no footer). (7)
Opção C1 implementada — checkbox bool gerarCobrancaAoSalvar substituido
por SelectButton chargeMode com opcoes dinamicas:
- Avulsa: Não / Gerar cobrança
- Recorrente: Não / Pacote único / 1 por sessão
Handler em useMelissaAgenda agora suporta 3 modos: 'session' (1
financial_record, igual Fase 1 original), 'package' (1 billing_contract
inline em vez de confirm.require pós-save), 'per_session' (materializa N
agenda_eventos + cria N financial_records via RPC, respeitando
recurrence_exceptions). _offerBillingContract removido (codigo morto).
useAgendaEventActions.gerarCobrancaAoSalvar → chargeMode. ESLint: 0
erros novos. Vitest useAgendaEventComposer.spec: 76/76 passed.
## [2026-05-13 22:00] session | Fase 1 — drop agenda_excecoes + render bloqueios cinza
Touched: agenda-compromisso-fluxo
Detalhes: Fase 1 da auditoria fase-a-fase concluida. Auditoria revelou
agenda_excecoes orfa (0 refs em src/, embora policies+trigger+enums
existissem) e bloqueios nunca renderizados no FullCalendar (so impediam
criacao). Aplicado: (1) migration 20260513000001_drop_agenda_excecoes.sql
dropa tabela+enums+trigger; (2) agendaMappers.buildBloqueioBackgroundEvents
renderiza dia-cheio/com-hora/recorrente como background event #6b728033;
(3) composable useAgendaBloqueios reusavel (load aceita owner unico OU
array); (4) wire nos 3 layouts (Melissa via useMelissaAgenda+MelissaAgenda,
Rail via AgendaTerapeutaPage, Clinica via AgendaClinicaPage com multi-owner);
(5) docs/schema_map.md e db.config.json limpos. ESLint 0 novos errors;
agendaMappers.spec 40/40 passed. Pendente: rodar migration no banco local
+ validacao visual nos 3 layouts. Plano de 8 fases salvo em
[[agenda-compromisso-fluxo]]; pesquisa de mercado em [[agenda-billing-pesquisa-mercado]].