diff --git a/.claude/settings.json b/.claude/settings.json index e001fcd..0c0ae79 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -70,7 +70,8 @@ "Bash(curl -s http://127.0.0.1:8000/static/css/layout.css)", "Bash(curl -s http://127.0.0.1:8000/static/css/halloween-cobweb.css)", "Bash(\"/c/Users/Depaula/Documents/Portal/.venv/Scripts/python.exe\" _scratch_insert_seasonal_toggle.py)", - "Bash(rm _scratch_insert_seasonal_toggle.py)" + "Bash(rm _scratch_insert_seasonal_toggle.py)", + "Bash(sort -t' ' -k2 -n -u)" ] } } diff --git a/portal_api/planos_saude/CHANGELOG.md b/portal_api/planos_saude/CHANGELOG.md index e367522..d6690d7 100644 --- a/portal_api/planos_saude/CHANGELOG.md +++ b/portal_api/planos_saude/CHANGELOG.md @@ -335,3 +335,12 @@ Pedido do usuário (2026-09-15): o nome do arquivo baixado em "Gerar Arquivo" er - **`ImportacaoPlanoSaudeViewSet.gerar()`**: o `.zip` (2 tipos) passou a se chamar `".zip"` em vez de `"importacao_plano_saude_.zip"`; o `.csv` único (1 tipo) passou a se chamar `" - .csv"` (ex.: `"1970 - 5060 - mensalidade.csv"`) em vez de só `".csv"` — mesma ambiguidade existia aí também (duas execuções da mesma empresa com operadoras diferentes e só 1 tipo cada geravam dois `mensalidade.csv` indistinguíveis). Os nomes dos arquivos **dentro** do `.zip` (`mensalidade.csv`/`coparticipacao.csv`) não mudaram, já estão desambiguados pelo nome do próprio zip. - **`ImportacaoPlanoSaudeDePaulaViewSet.gerar()`** recebeu o mesmo ajuste (`prefixo_fallback="importacao_plano_saude_de_paula"`, preservando o fallback distinto de antes) — os dois `gerar()` compartilham exatamente o mesmo código de geração de arquivo, então ficaria inconsistente resolver só um dos dois. - Sem migração, sem mudança de contrato de API — só o nome do arquivo no header `Content-Disposition` da resposta binária. + +### Rodada 108 — Resumo da regra de custeio na tela de Revisão (tipos cobertos + mensalidade/coparticipação) + +Pedido do usuário (2026-09-16), com print da tela de Revisão mostrando um espaço vazio abaixo do código/nome da operadora: até então, esse espaço só mostrava a **observação** da regra empresa/regra de custeio salva (`regra_empresa_observacoes`/`regra_custeio_salva_observacoes`, já existentes no `ImportacaoPlanoSaudeDetailSerializer` — nenhum campo novo no backend foi necessário) — sem o resumo de tipos cobertos e do próprio custeio por titular/dependente que "Nova Importação" já mostra (`#ips-imp-resumo`, ao resolver uma regra salva). O usuário queria os dois juntos na Revisão, "assim o usuário tem certeza que está conferindo com base na regra do cliente". + +- **`#ips-review-regra-empresa-obs`** (`importacao-plano-saude.html`) ganhou três `

` novos antes do label/texto de observação (`#ips-review-resumo-tipos`/`-mensalidade`/`-coparticipacao`, reaproveitando as classes `.ips-imp-resumo__tipos`/`.ips-imp-resumo__linha` já existentes) — mesmo bloco visual de sempre, só que agora mostra o resumo sempre (quando a importação tem algum `tipos_lancamento`, o que é sempre o caso) e a observação só quando existir uma. `.ips-regra-empresa-observacoes` (CSS) virou `display:flex; flex-direction:column; gap:var(--space-2)` pra espaçar as linhas novas do mesmo jeito que `.ips-imp-resumo` já fazia. +- **`renderReviewResumoCusteio(importacao)`** (`importacao-plano-saude.js`, nova) monta o resumo a partir dos campos já presentes na importação (`tipos_lancamento`/`custeio_por_tipo`/`regra_empresa`/`regra_empresa_label`) — **não** reaproveita `renderResumoRegra()`/`regrasEmpresaCache` de "Nova Importação" porque essa cache só é buscada ao abrir os modais de "Nova Importação"/"Cadastro de Regras", ficando vazia quando a Revisão é aberta direto do histórico. Em vez disso, `reviewResumoTextoTipo()` detecta cobertura por "regra especial da empresa" olhando se `custeio_por_tipo[tipo]` veio vazio (sem `titular`/`dependente`) com `regra_empresa` preenchido — o mesmo sinal que `ImportacaoPlanoSaudeCreateSerializer.validate()` já grava pra tipos cobertos por uma regra empresa (ver "zeram custeio_por_tipo[tipo] só pros tipos em regra_empresa_tipos" no `CLAUDE.md` deste pacote) — evitando uma segunda fonte de verdade sobre quais tipos a regra cobre. +- `abrirRevisao()` chama essa função e decide se o bloco inteiro fica visível (`temResumo || temObs`) — antes só aparecia com observação cadastrada, agora aparece por padrão em toda importação com tipo de lançamento selecionado. +- Sem migração, sem endpoint novo — só leitura de campos que a Revisão já carregava. diff --git a/portal_api/planos_saude/CLAUDE.md b/portal_api/planos_saude/CLAUDE.md index da07806..4932ff6 100644 --- a/portal_api/planos_saude/CLAUDE.md +++ b/portal_api/planos_saude/CLAUDE.md @@ -225,7 +225,7 @@ Cobre regras de custeio negociadas com uma empresa específica que não cabem no - No backend, `RegraCusteioPlanoSaudeSerializer.validate()`/`ImportacaoPlanoSaudeCreateSerializer.validate()` calculam `regra_empresa_tipos` (interseção entre `REGRAS_EMPRESA[chave]["tipos_lancamento"]` e os tipos selecionados — erro claro se vier vazia), conferem `chave_casamento_para_tipo(tipo) == REGRAS_EMPRESA[chave]["chave_casamento"]` pra cada tipo coberto (não mais um "exige nome" hardcoded) e zeram `custeio_por_tipo[tipo]` só pros tipos em `regra_empresa_tipos` (os demais tipos selecionados continuam com custeio manual normal). `regras_empresa.valida_regra_empresa(regra_empresa_key, chave_casamento_por_tipo, linhas_sistema, tipos_selecionados)` devolve `(aplica, tipos_cobertos)` — `pipeline.processa_importacao` passa `regra_empresa_fn` pra `casa_individuos_com_planilha` só quando `tipo_lancamento in tipos_cobertos`. - **`matcher._casa_por_cpf` passou a suportar `regra_empresa_fn`** (antes só `_casa_por_nome` suportava) — sem agrupar por família (essa estratégia não tem esse conceito): acumula `(linha, valor_total)` de todo indivíduo casado por CPF e chama `regra_empresa_fn(linhas_e_valores, tipo_lancamento)` uma vez só, no fim, com todos os pares do tipo de lançamento inteiro. `aplica(linhas_e_valores, tipo_lancamento)` é a assinatura de toda regra agora (segundo argumento novo) — permite uma mesma função se comportar diferente por tipo (ver Ottimizza abaixo); a Tecnomyl recebe o parâmetro mas ignora (só é chamada pra "mensalidade" mesmo, via `tipos_lancamento`). - **Registro** (`REGRAS_EMPRESA`): cada entrada tem `label`, `codigo_empresa` (código da empresa na planilha padrão pra qual a regra foi negociada), `operadora`, `chave_casamento`, `tipos_lancamento`, `aplica` (função que faz o cálculo) e `observacoes`. Pra cadastrar uma regra nova: escrever a função e registrar aqui — nada mais precisa mudar (`GET /api/importacoes-plano-saude/regras-empresa/` já reflete o registro, incluindo `tipos_lancamento`, consumido tanto pelo seletor dentro do Cadastro de Regras quanto pelo resumo só-leitura de "Nova Importação"). -- **Observações da regra, só-leitura na tela de Revisão** (`#ips-review-regra-empresa-obs`) — inalterado: `ImportacaoPlanoSaudeDetailSerializer.regra_empresa_observacoes` resolve `REGRAS_EMPRESA[obj.regra_empresa]["observacoes"]` a cada carregamento; o mesmo bloco cai pra `regra_custeio_salva_observacoes` quando não há regra empresa. +- **Resumo de custeio + observações, só-leitura na tela de Revisão** (`#ips-review-regra-empresa-obs`, entre o cabeçalho "Revisão" e as abas Mensalidade/Coparticipação/Auditoria/Alterações — pedido explícito do usuário, rodada 108, "assim o usuário tem certeza que está conferindo com base na regra do cliente"): mostra sempre "Tipos cobertos" + uma linha por tipo de lançamento (`Mensalidade`/`Coparticipação` — "Titular: .../Dependente: ..." ou "usa regra especial da empresa —