alguma coisa ai

This commit is contained in:
Gabriel 2026-08-18 16:35:55 -03:00
parent c08b38f91b
commit 5d5f224dff
7 changed files with 80 additions and 9 deletions

View File

@ -550,7 +550,7 @@ Substituiu o antigo par de botões "Exportar regra"/"Importar regra" (baixava/li
- **Campos**: `nome` (obrigatório), `operadora` (opcional — a `key` de `planos_saude.pipeline.OPERADORAS`, não o label; só usada pra pré-selecionar o `<select>` de operadora ao aplicar a regra, nunca bloqueia aplicar uma regra com uma operadora diferente da atual), `tipos_lancamento`/`custeio_por_tipo` (exatamente o mesmo formato dos campos homônimos de `ImportacaoPlanoSaude`, ver acima) e `observacoes` (texto livre).
- **Validação reaproveitada, não duplicada**: `RegraCusteioPlanoSaudeSerializer.validate()` e `ImportacaoPlanoSaudeCreateSerializer.validate()` chamam a mesma função módulo-level `_monta_regra_custeio()` (`serializers.py`) pra validar/parsear cada combinação tipo×pessoa — sem isso, a regra de negócio de custeio (parsing BR, faixa 0–100 do percentual, "ao menos um de limite/percentual") viveria duplicada em dois serializers e podia divergir com o tempo. A única diferença entre os dois pontos de entrada é o formato de payload: `ImportacaoPlanoSaudeCreateSerializer` recebe campos multipart achatados (`custeio_mensalidade_titular`, `limite_valor_mensalidade_titular`...), `RegraCusteioPlanoSaudeSerializer` recebe o `custeio_por_tipo` já aninhado como JSON puro.
- **`limite_valor`/`percentual` sempre em texto BR na entrada, float|None persistido**: igual ao resto do módulo, esses dois campos chegam como string BR (`"150,00"`) tanto no create de uma importação quanto no banco de regras — mas uma regra salva, uma vez lida de volta pelo `GET`, já vem com esses valores como `float` (formato final persistido). Pra `RegraCusteioPlanoSaudeSerializer` aceitar os dois formatos sem corromper o valor (`"150.0"` seria lido errado como 15000 por `parse_valor_br`, que só entende separador de milhar `.`/decimal `,`), `_valor_custeio_para_texto_br()` normaliza um float de volta pra texto BR (`formata_valor_br`) antes de repassar pro parser — isso é o que permite reenviar uma regra sem edição (ex.: só mudando o nome) sem precisar reformatar nada no frontend.
- **Frontend** (`importacao-plano-saude.js`, seção "Regra de custeio salva" — **primeiro** campo do formulário de Nova Importação, antes até de "Operadora": decisão explícita do usuário, já que aplicar uma regra já preenche a operadora junto, então escolher a regra é o primeiro passo natural do fluxo, não um apêndice no final): um combobox pesquisável (`#ips-regra-combo` — `<input>` `#ips-regra-search` + lista flutuante `#ips-regra-combo-list`, filtra por nome a cada tecla; era um `<select>` simples, trocado quando o banco de regras cresceu o bastante pra não caber numa lista sem busca) + "Aplicar" preenche o formulário inteiro (tipos de lançamento + custeio de cada combinação + operadora, se ainda existir na lista) a partir de uma regra salva — os campos continuam 100% editáveis depois, é só um preenchimento em massa (`aplicarCusteio()`/`aplicarRegraNoFormulario()`), mesmo espírito do antigo "Importar regra". `regraSelecionadaId` (JS) rastreia o que está de fato escolhido no combobox — digitar de novo no campo invalida a seleção anterior até o usuário clicar numa regra da lista, pra "Aplicar" nunca usar uma regra desatualizada em relação ao texto exibido. "Salvar regra atual..." (`#ips-regra-salvar-btn`) abre um modal (`#ips-regra-save-modal`) pra nomear/descrever a configuração atualmente preenchida (validada antes com a mesma `mensagemErroCusteio()` usada pelo botão "Processar", reaproveitada pelas duas ações) — **editar uma regra existente é literalmente aplicá-la, ajustar o que quiser no formulário, e salvar de novo**: o modal nasce em modo "atualizar a regra selecionada" sempre que a regra atualmente refletida no formulário (`regraAplicadaId`) ainda existir, com uma checkbox pra optar por "criar uma nova regra" em vez de sobrescrever. "Ver regras salvas" (`#ips-regras-modal`) lista todas as regras (nome, operadora, tipos, observações) com ações de Aplicar/Excluir — não duplica a grade de custeio num modal separado, de propósito, pra não manter dois lugares editáveis da mesma coisa.
- **Frontend** (`importacao-plano-saude.js`, seção "Regra de custeio salva" — **primeiro** campo do formulário de Nova Importação, antes até de "Operadora": decisão explícita do usuário, já que aplicar uma regra já preenche a operadora junto, então escolher a regra é o primeiro passo natural do fluxo, não um apêndice no final): um combobox pesquisável (`#ips-regra-combo` — `<input>` `#ips-regra-search` + lista flutuante `#ips-regra-combo-list`, filtra por nome a cada tecla; era um `<select>` simples, trocado quando o banco de regras cresceu o bastante pra não caber numa lista sem busca) + "Aplicar" preenche o formulário inteiro (tipos de lançamento + custeio de cada combinação + operadora, se ainda existir na lista) a partir de uma regra salva — os campos continuam 100% editáveis depois, é só um preenchimento em massa (`aplicarCusteio()`/`aplicarRegraNoFormulario()`), mesmo espírito do antigo "Importar regra". `regraSelecionadaId` (JS) rastreia o que está de fato escolhido no combobox — digitar de novo no campo invalida a seleção anterior até o usuário clicar numa regra da lista, pra "Aplicar" nunca usar uma regra desatualizada em relação ao texto exibido. **"Limpar seleção"** (`#ips-regra-limpar-btn`, ao lado de "Aplicar" — adicionado pro caso de aplicar a regra errada por engano) chama `limparRegraSelecionada()` (zera o rastreamento — combobox, `regraSelecionadaId`/`regraAplicadaId`, observações) **e** `limparCusteioForm()` (desfaz o que a regra preencheu: desmarca tipos de lançamento, radios de custeio e campos de limite/percentual de cada combinação tipo×pessoa) — as duas funções foram extraídas de dentro de `resetForm()` justamente pra serem reaproveitadas aqui; não mexe em Operadora nem nos arquivos já anexados, só no que uma regra aplicada de fato preenche em massa. **"Ver regras salvas"** (`#ips-regras-modal`) continua no topo, junto de Aplicar/Limpar; **"Salvar regra atual..."** (`#ips-regra-salvar-btn`) foi movido pro **final do formulário** (depois de "Tipo de importação", antes do botão "Processar" — `.ips-regra-salvar-field` em `importacao-plano-saude.css`), decisão explícita do usuário: salvar só faz sentido depois de parametrizar o custeio, é o último passo do fluxo de criar/editar uma regra, não algo que deveria ficar ao lado de Aplicar/Ver regras salvas no topo. Continua abrindo o mesmo modal (`#ips-regra-save-modal`) pra nomear/descrever a configuração atualmente preenchida (validada antes com a mesma `mensagemErroCusteio()` usada pelo botão "Processar", reaproveitada pelas duas ações) — **editar uma regra existente é literalmente aplicá-la, ajustar o que quiser no formulário, e salvar de novo**: o modal nasce em modo "atualizar a regra selecionada" sempre que a regra atualmente refletida no formulário (`regraAplicadaId`) ainda existir, com uma checkbox pra optar por "criar uma nova regra" em vez de sobrescrever. "Ver regras salvas" lista todas as regras (nome, operadora, tipos, observações) com ações de Aplicar/Excluir — não duplica a grade de custeio num modal separado, de propósito, pra não manter dois lugares editáveis da mesma coisa.
## CSS — organização entre arquivos

View File

@ -0,0 +1,25 @@
CODIGOEMPRESA;NOMEFUNC;CPFFUNC;CODIGOOUTEMP;DATAINICIAL;NOMEDEPENDENTE;CPFDEPENDENTE;VALOREMPRESA;VALOR;DESCRICAO
221;DIEGO RODRIGO DA FONSECA;007.377.729-30;3755;01/12/2023;;;0;0;
221;ZAIRA DAVID BARBOSA;007.396.889-79;3755;01/12/2023;;;0;0;
221;ADRIANA OLIVEIRA DOS SANTOS CODO;022.366.869-94;3755;01/12/2023;;;0;0;
221;ADRIANA OLIVEIRA DOS SANTOS CODO;022.366.869-94;3755;01/12/2023;RAFHAEL HENRIQUE CODO;133.710.699-23;0;0;
221;LEANDRA SPEROTTO;022.795.359-20;3755;01/12/2023;LUCAS SPEROTTO SCHIRMANN;125.709.619-22;0;0;
221;LEANDRA SPEROTTO;022.795.359-20;3755;01/12/2023;;;0;0;
221;JANE MARILIA BEKER;025.273.319-39;3755;01/12/2023;;;0;0;
221;ANELISA CLAUDIA TOLEDO;028.627.449-30;3755;01/12/2023;;;0;0;
221;ANELISA CLAUDIA TOLEDO;028.627.449-30;3755;01/12/2023;MURILO AUGUSTO TOLEDO SILVA;140.796.419-40;0;0;
221;VANESSA JUIF TRINDADE;032.476.309-37;3755;01/12/2023;;;0;0;
221;FERNANDO BERLATTO;040.875.749-38;3755;01/12/2023;;;0;0;
221;JOAO VICTOR DE OLIVEIRA EGIDIO;051.271.009-08;3755;01/12/2023;;;0;0;
221;MARCOS PAULO GOBBO;057.539.659-89;3755;01/12/2023;;;0;0;
221;ELIANA KARPSAK LOPES;064.896.469-86;3755;01/12/2023;;;0;0;
221;ELIANA KARPSAK LOPES;064.896.469-86;3755;01/12/2023;LUCAS ANTONIO DE OLIVEIRA;066.200.469-83;0;0;
221;PAULA MICHELLI DA SILVA;073.516.259-05;3755;01/12/2023;;;0;0;
221;PAULA MICHELLI DA SILVA;073.516.259-05;3755;01/12/2023;EMANUELLY FERREIRA DA SILVA;152.794.939-70;0;0;
221;CAROLINE DAYANE DE ALMEIDA;091.247.879-90;3755;01/12/2023;;;0;0;
221;JESSICA DE FATIMA CATTANI DE PAULA;092.879.749-00;3755;01/12/2023;;;0;0;
221;LUCAS DE SOUZA;093.861.469-08;3755;01/12/2023;;;0;0;
221;APARECIDA DOBNER;389.259.312-49;3755;01/12/2023;ANNA CAROLINA DOBNER WILLMBRINK;097.280.639-38;0;0;
221;APARECIDA DOBNER;389.259.312-49;3755;01/12/2023;;;0;0;
221;MARIZA KARPSAK LOPES;726.088.899-72;3755;01/12/2023;EDUARDO KARPSAK LOPES;096.771.579-22;0;0;
221;MARIZA KARPSAK LOPES;726.088.899-72;3755;01/12/2023;;;0;0;
1 CODIGOEMPRESA NOMEFUNC CPFFUNC CODIGOOUTEMP DATAINICIAL NOMEDEPENDENTE CPFDEPENDENTE VALOREMPRESA VALOR DESCRICAO
2 221 DIEGO RODRIGO DA FONSECA 007.377.729-30 3755 01/12/2023 0 0
3 221 ZAIRA DAVID BARBOSA 007.396.889-79 3755 01/12/2023 0 0
4 221 ADRIANA OLIVEIRA DOS SANTOS CODO 022.366.869-94 3755 01/12/2023 0 0
5 221 ADRIANA OLIVEIRA DOS SANTOS CODO 022.366.869-94 3755 01/12/2023 RAFHAEL HENRIQUE CODO 133.710.699-23 0 0
6 221 LEANDRA SPEROTTO 022.795.359-20 3755 01/12/2023 LUCAS SPEROTTO SCHIRMANN 125.709.619-22 0 0
7 221 LEANDRA SPEROTTO 022.795.359-20 3755 01/12/2023 0 0
8 221 JANE MARILIA BEKER 025.273.319-39 3755 01/12/2023 0 0
9 221 ANELISA CLAUDIA TOLEDO 028.627.449-30 3755 01/12/2023 0 0
10 221 ANELISA CLAUDIA TOLEDO 028.627.449-30 3755 01/12/2023 MURILO AUGUSTO TOLEDO SILVA 140.796.419-40 0 0
11 221 VANESSA JUIF TRINDADE 032.476.309-37 3755 01/12/2023 0 0
12 221 FERNANDO BERLATTO 040.875.749-38 3755 01/12/2023 0 0
13 221 JOAO VICTOR DE OLIVEIRA EGIDIO 051.271.009-08 3755 01/12/2023 0 0
14 221 MARCOS PAULO GOBBO 057.539.659-89 3755 01/12/2023 0 0
15 221 ELIANA KARPSAK LOPES 064.896.469-86 3755 01/12/2023 0 0
16 221 ELIANA KARPSAK LOPES 064.896.469-86 3755 01/12/2023 LUCAS ANTONIO DE OLIVEIRA 066.200.469-83 0 0
17 221 PAULA MICHELLI DA SILVA 073.516.259-05 3755 01/12/2023 0 0
18 221 PAULA MICHELLI DA SILVA 073.516.259-05 3755 01/12/2023 EMANUELLY FERREIRA DA SILVA 152.794.939-70 0 0
19 221 CAROLINE DAYANE DE ALMEIDA 091.247.879-90 3755 01/12/2023 0 0
20 221 JESSICA DE FATIMA CATTANI DE PAULA 092.879.749-00 3755 01/12/2023 0 0
21 221 LUCAS DE SOUZA 093.861.469-08 3755 01/12/2023 0 0
22 221 APARECIDA DOBNER 389.259.312-49 3755 01/12/2023 ANNA CAROLINA DOBNER WILLMBRINK 097.280.639-38 0 0
23 221 APARECIDA DOBNER 389.259.312-49 3755 01/12/2023 0 0
24 221 MARIZA KARPSAK LOPES 726.088.899-72 3755 01/12/2023 EDUARDO KARPSAK LOPES 096.771.579-22 0 0
25 221 MARIZA KARPSAK LOPES 726.088.899-72 3755 01/12/2023 0 0

View File

@ -834,6 +834,12 @@ Adicionada mais uma opção de tema de cor (`--accent`) ao seletor de swatches d
Como `--danger` (usado em feriados/selos de ausente etc.) já era um tom de vermelho (`#e5484d`) escolhido antes de "vermelho" existir como cor de tema selecionável, agora há uma sobreposição visual esperada quando o usuário escolhe o tema "Vermelho": elementos que usam `--accent` (ex.: pill "somente_eu" do Calendário Individual) ficam bem parecidos com elementos de erro/alerta que usam `--danger`. Diferente de `--gold`/`--teal`/`--slate`/`--coral` (rodada 35, escolhidos deliberadamente fora das cores de tema pra nunca colidir com `--accent`), `--danger` não foi criado pensando nisso — é uma coincidência aceita ao adicionar "Vermelho" à lista, não um bug. Se isso incomodar na prática, ajustar `--danger` para um tom fora da família "vermelho" é a correção futura, não mudar a cor do tema.
### 55. Regra de custeio salva: "Salvar regra atual..." movido pro final do formulário + botão "Limpar seleção"
Ajuste de usabilidade pedido pelo usuário na seção "Regra de custeio salva" do formulário de Nova Importação: "Salvar regra atual..." saiu de junto de Aplicar/Ver regras salvas (topo do formulário) e passou pro **final** (depois de "Tipo de importação", antes do botão "Processar") — salvar só faz sentido depois de parametrizar o custeio, é o último passo do fluxo, não um botão que deveria ficar ao lado de Aplicar. Aplicar/Limpar seleção/Ver regras salvas continuam no topo, já que aplicar uma regra continua sendo o primeiro passo natural (preenche operadora + custeio de uma vez).
Novo botão "Limpar seleção" (`#ips-regra-limpar-btn`, ao lado de Aplicar) resolve o caso de aplicar a regra errada por engano: desfaz tanto o rastreamento (`regraSelecionadaId`/`regraAplicadaId`, texto do combobox, observações) quanto o próprio custeio que a regra preencheu (tipos de lançamento, radios de custeio, limite/percentual de cada combinação tipo×pessoa) — as duas partes de `resetForm()` que faziam isso foram extraídas em `limparCusteioForm()`/`limparRegraSelecionada()` pra serem reaproveitadas aqui. De propósito não mexe em Operadora nem nos arquivos já anexados — só desfaz o que uma regra aplicada de fato preenche em massa.
## Roadmap / próximos passos
Nenhuma pendência explícita em aberto no momento, exceto a limitação conhecida

View File

@ -292,6 +292,16 @@
white-space: pre-wrap;
}
/* "Salvar regra atual..." fica no final do formulário (não mais junto de
Aplicar/Limpar/Ver regras salvas no topo) — salvar só faz sentido depois
de parametrizar o custeio abaixo, é o último passo do fluxo de
parametrização de uma regra nova. */
.ips-regra-salvar-field {
margin-top: var(--space-5);
padding-top: var(--space-5);
border-top: 1px solid var(--border-subtle);
}
/* Lista de regras salvas (#ips-regras-modal) — reaproveita .checklist-box
como moldura rolável, mas cada linha tem seus próprios botões de ação em
vez do checkbox usado pelos outros consumidores de .checklist-box. */

View File

@ -202,6 +202,7 @@ document.addEventListener("DOMContentLoaded", async () => {
const ipsRegraSearch = document.getElementById("ips-regra-search");
const ipsRegraComboList = document.getElementById("ips-regra-combo-list");
const ipsRegraAplicarBtn = document.getElementById("ips-regra-aplicar-btn");
const ipsRegraLimparBtn = document.getElementById("ips-regra-limpar-btn");
const ipsRegraSalvarBtn = document.getElementById("ips-regra-salvar-btn");
const ipsRegraObservacoes = document.getElementById("ips-regra-observacoes");
const regrasGerenciarBtn = document.getElementById("ips-regras-gerenciar-btn");
@ -504,9 +505,11 @@ document.addEventListener("DOMContentLoaded", async () => {
renderList();
}
function resetForm() {
validadorPlanilha.limpar();
validadorArquivo.limpar();
// Zera só a parte de tipo/custeio do formulário (tipos_lancamento + modo de
// custeio/limite/percentual de cada combinação tipo×pessoa) — extraído de
// resetForm() pra ser reaproveitado por "Limpar seleção" (desfaz o que uma
// regra aplicada por engano preencheu, sem mexer nos arquivos já anexados).
function limparCusteioForm() {
formTipoMensalidade.checked = false;
formTipoCoparticipacao.checked = false;
custeioMensalidade.hidden = true;
@ -524,11 +527,24 @@ document.addEventListener("DOMContentLoaded", async () => {
if (percentualInput) percentualInput.value = "";
});
});
}
// Limpa só o rastreamento de "regra selecionada/aplicada" (combobox +
// observações), sem mexer no custeio do formulário — usado por resetForm()
// e sozinho pelo botão "Limpar seleção" (junto com limparCusteioForm()).
function limparRegraSelecionada() {
regraAplicadaId = null;
regraSelecionadaId = null;
if (ipsRegraSearch) ipsRegraSearch.value = "";
fecharRegraComboList();
mostrarObservacoesRegra(null);
}
function resetForm() {
validadorPlanilha.limpar();
validadorArquivo.limpar();
limparCusteioForm();
limparRegraSelecionada();
formError.textContent = "";
}
@ -1129,6 +1145,14 @@ document.addEventListener("DOMContentLoaded", async () => {
});
}
if (ipsRegraLimparBtn) {
ipsRegraLimparBtn.addEventListener("click", () => {
limparRegraSelecionada();
limparCusteioForm();
formError.textContent = "";
});
}
if (ipsRegraSalvarBtn) {
ipsRegraSalvarBtn.addEventListener("click", () => {
const { tipos_lancamento } = coletarCusteioAtual();

View File

@ -313,17 +313,14 @@
<div class="ips-form">
<div class="modal-field ips-regra-field">
<label>Regra de custeio salva</label>
<p class="ips-regra-actions__hint">Aplique uma regra salva pra preencher a operadora e o custeio abaixo automaticamente, ou salve a configuração atual como uma regra nova pra reaproveitar em importações futuras — os campos continuam editáveis normalmente depois.</p>
<p class="ips-regra-actions__hint">Aplique uma regra salva pra preencher a operadora e o custeio abaixo automaticamente — os campos continuam editáveis normalmente depois. Selecionou a regra errada? Use "Limpar seleção" pra desfazer.</p>
<div class="ips-regra-actions">
<div class="ips-regra-combo" id="ips-regra-combo">
<input type="text" id="ips-regra-search" class="ips-regra-combo__input" placeholder="Selecionar regra salva..." autocomplete="off" />
<div class="ips-regra-combo__list" id="ips-regra-combo-list" hidden></div>
</div>
<button type="button" class="btn-outline" id="ips-regra-aplicar-btn">Aplicar</button>
<button type="button" class="btn-outline" id="ips-regra-salvar-btn">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2Z" stroke-linejoin="round"/><path d="M17 21v-8H7v8M7 3v5h5" stroke-linejoin="round"/></svg>
Salvar regra atual...
</button>
<button type="button" class="btn-outline" id="ips-regra-limpar-btn">Limpar seleção</button>
<button type="button" class="btn-outline" id="ips-regras-gerenciar-btn">Ver regras salvas</button>
</div>
<p class="ips-regra-observacoes" id="ips-regra-observacoes" hidden></p>
@ -457,6 +454,15 @@
</div>
</div>
<div class="modal-field ips-regra-salvar-field">
<label>Salvar como regra de custeio</label>
<p class="ips-regra-actions__hint">Depois de parametrizar o custeio acima, salve como uma regra nova (ou atualize a regra aplicada) pra reaproveitar em importações futuras.</p>
<button type="button" class="btn-outline" id="ips-regra-salvar-btn">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2Z" stroke-linejoin="round"/><path d="M17 21v-8H7v8M7 3v5h5" stroke-linejoin="round"/></svg>
Salvar regra atual...
</button>
</div>
<p class="modal-error" id="ips-form-error"></p>
<div class="modal-actions">
<button type="button" class="btn-outline" id="ips-form-cancel-btn">Cancelar</button>