From 3277f81ce7ef8cd36b8035025d733ea702358a1e Mon Sep 17 00:00:00 2001 From: Sidney Date: Sat, 18 Jul 2026 20:13:59 -0300 Subject: [PATCH] docs: update GEMINI.md and MEMORY.md and fix decimal places formatting in finance --- GEMINI.md | 2 ++ MEMORY.md | 4 +++ manager/components/Courses.tsx | 2 +- manager/components/Finance.tsx | 56 ++++++++++++++++----------------- manager/components/Students.tsx | 2 +- 5 files changed, 36 insertions(+), 30 deletions(-) diff --git a/GEMINI.md b/GEMINI.md index 80bbe7d..5fe9038 100644 --- a/GEMINI.md +++ b/GEMINI.md @@ -89,4 +89,6 @@ 55. **Migração Automática de Chaves de IA**: O sistema deve migrar automaticamente as configurações e chaves de IA legadas salvas no arquivo JSON para a tabela relacional `configuracoes_ia` do PostgreSQL para centralizar as credenciais. 56. **Geração Híbrida de Imagens Gemini/Imagen**: O backend deve suportar chamadas de imagem nativas (endpoint `:generateImages` do Imagen 3) para modelos `imagen-` e chamadas multimodais para modelos Gemini (`responseModalities`), aplicando fallbacks automáticos em cascata caso o modelo primário selecionado falhe. 57. **Correção de Autofill no Chrome**: Modais de IA devem desativar ou evitar elementos de formulário que induzam o Chrome a preencher incorretamente campos de texto irrelevantes (como busca de provas) com dados armazenados de login (ex: 'admin'). +58. **Limitação de Decimais em Formatação Financeira**: Todos os valores financeiros renderizados na tela (especialmente parcelas, multas e juros de atraso) devem ser limitados a exatamente duas casas decimais utilizando `toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 })` para garantir conformidade visual e evitar o arredondamento incorreto do navegador com 3 ou mais dígitos. +59. **Resiliência do Modelo de IA**: O backend em `server.selfhosted.js` implementa um filtro ativo contra modelos descontinuados da API Gemini (como `gemini-1.5-flash` e `gemini-2.5-flash-lite`) salvos no banco. O fallback forçado sob o capô deve ser sempre `gemini-2.0-flash`. diff --git a/MEMORY.md b/MEMORY.md index 0645212..52fd63f 100644 --- a/MEMORY.md +++ b/MEMORY.md @@ -107,3 +107,7 @@ Nesta sessão de trabalho, realizamos o "core" da transição do sistema EduMana - **Migração de Chaves de IA para o PostgreSQL**: Adicionada rotina de migração transparente que move as credenciais e configurações de IA do antigo cache JSON de configurações para a tabela relacional `configuracoes_ia`. - **Correção de Autofill no Chrome**: Corrigido bug onde o recurso de preenchimento automático do Chrome inseria o usuário 'admin' na barra de busca de provas ao carregar o modal de configuração de IA. +### Fase 14: Correção de Precisão Financeira e Fallback do Módulo de IA (Julho de 2026) +- **Exibição Estrita de Duas Casas Decimais**: Adicionado o parâmetro `maximumFractionDigits: 2` em todos os locais onde valores financeiros são formatados no painel Manager (arquivos `Finance.tsx`, `Students.tsx` e `Courses.tsx`). Isso corrige de forma definitiva a exibição de parcelas vencidas com 3 casas decimais (ex: R$ 175,871), aplicando o formato monetário padrão brasileiro de exatamente 2 casas decimais. +- **Fallback e Filtro de Modelos Gemini Descontinuados**: Atualizado o modelo padrão de IA nas camadas de banco (`database.js`), backend (`server.selfhosted.js`) e frontend (`Exams.tsx`) de `gemini-1.5-flash` para `gemini-2.0-flash`. Além disso, foi adicionado um filtro que intercepta modelos inexistentes ou inválidos configurados no banco (como `gemini-2.5-flash-lite`) e faz o redirecionamento automático sob o capô para o modelo estável `gemini-2.0-flash`, evitando erros 404. + diff --git a/manager/components/Courses.tsx b/manager/components/Courses.tsx index b863f1a..17b9db5 100644 --- a/manager/components/Courses.tsx +++ b/manager/components/Courses.tsx @@ -222,7 +222,7 @@ const Courses: React.FC = ({ data, updateData }) => {

Investimento Mensal

-

R$ {course.monthlyFee.toLocaleString('pt-BR', { minimumFractionDigits: 2 })}

+

R$ {course.monthlyFee.toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}

diff --git a/manager/components/Finance.tsx b/manager/components/Finance.tsx index df21551..619c5cb 100644 --- a/manager/components/Finance.tsx +++ b/manager/components/Finance.tsx @@ -1130,9 +1130,9 @@ const Finance: React.FC = ({ data, updateData }) => { )} -
R$ {group.totalAmount.toLocaleString('pt-BR', { minimumFractionDigits: 2 })}
+
R$ {group.totalAmount.toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
{group.totalReceived > 0 && ( -
PAGO: R$ {group.totalReceived.toLocaleString('pt-BR', { minimumFractionDigits: 2 })}
+
PAGO: R$ {group.totalReceived.toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
)}
Total do Carnê
@@ -1229,28 +1229,28 @@ const Finance: React.FC = ({ data, updateData }) => { const displayValue = valorPago > 0 ? valorPago : (payment.amount - discount); return (
- R$ {displayValue.toLocaleString('pt-BR', { minimumFractionDigits: 2 })} + R$ {displayValue.toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 })} +
+ ); + } else { + return ( + <> +
+ R$ {(payment.amount + additions).toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 })} +
+ {activeDiscount > 0 && ( +
+ - R$ {activeDiscount.toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
- ); - } else { - return ( - <> -
- R$ {(payment.amount + additions).toLocaleString('pt-BR', { minimumFractionDigits: 2 })} -
- {activeDiscount > 0 && ( -
- - R$ {activeDiscount.toLocaleString('pt-BR', { minimumFractionDigits: 2 })} -
- )} - {additions > 0 && ( -
- + R$ {additions.toLocaleString('pt-BR', { minimumFractionDigits: 2 })} (Juros/Multa) -
- )} - - ); - } + )} + {additions > 0 && ( +
+ + R$ {additions.toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 })} (Juros/Multa) +
+ )} + + ); + } })()} {getStatusBadge(payment)} @@ -1368,23 +1368,23 @@ const Finance: React.FC = ({ data, updateData }) => { const displayValue = valorPago > 0 ? valorPago : (payment.amount - discount); return (
- R$ {displayValue.toLocaleString('pt-BR', { minimumFractionDigits: 2 })} + R$ {displayValue.toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
); } else { return ( <>
- R$ {(payment.amount + additions).toLocaleString('pt-BR', { minimumFractionDigits: 2 })} + R$ {(payment.amount + additions).toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
{activeDiscount > 0 && (
- - R$ {activeDiscount.toLocaleString('pt-BR', { minimumFractionDigits: 2 })} + - R$ {activeDiscount.toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
)} {additions > 0 && (
- + R$ {additions.toLocaleString('pt-BR', { minimumFractionDigits: 2 })} (Multa/Juros) + + R$ {additions.toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 })} (Multa/Juros)
)} @@ -1701,7 +1701,7 @@ const Finance: React.FC = ({ data, updateData }) => {
Parcela {parcela.numero}
-
R$ {parcela.valor.toLocaleString('pt-BR', { minimumFractionDigits: 2 })}
+
R$ {parcela.valor.toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
Vencimento
diff --git a/manager/components/Students.tsx b/manager/components/Students.tsx index 4c53f51..b1687a4 100644 --- a/manager/components/Students.tsx +++ b/manager/components/Students.tsx @@ -2540,7 +2540,7 @@ const Students: React.FC = ({ data, updateData, deepLinkStudentId
Parcela {parcela.numero}
-
R$ {parcela.valor.toLocaleString('pt-BR', { minimumFractionDigits: 2 })}
+
R$ {parcela.valor.toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
Vencimento