feat(financeiro+salas): motor financeiro V1/V2, glosas, GTO→financeiro, contratos de convênio e redesenho de Salas

Financeiro V1 (Épicos 1–4):
- FKs de origem no lançamento (paciente/profissional/procedimento/agendamento/contrato/realizado), soft delete e cron "Atrasado"
- prontuário de procedimentos realizados (fotos antes/depois) + regra sem-comissão (garantia/reabertura do mesmo profissional)
- normalizeFinanceiro: corrige CHECK capitalizado vs enforceUppercase (lançamentos não salvavam pela UI)
- baixa de pagamento (pago_em), despesas (fornecedor/centro de custo/recorrente), competência por data de conclusão
- relatório financeiro (período, paciente, profissional, forma, convênio, glosa)
- orçamento Assinado -> contas a receber; contrato vigente -> cobrança recorrente; renovação automática de contrato

Financeiro V2 (Comissão/Repasse):
- regras de % (padrão/procedimento/override por profissional) + custo de laboratório
- base selecionável (recebido/produção), fechamento persistido, pagar (gera despesa) + comprovante + estorno

Glosas de convênio: por item de GTO, recurso/protocolo/prazo, recuperar/estornar, impacto no relatório

GTO -> Financeiro: finalizar gera RECEITA (convênio a receber); LancarGTO passa a persistir; convênios reais (planos)

Contratos: modelo "Atendimento a Convênios / Repasse (Dentista Credenciado)" + variáveis de convênio

Salas (redesenho): perfil "Dono de Sala"; locação sempre ativa; menus MINHAS/ALUGAR SALAS;
sala como workspace isolado (seletor agrupado Clínicas x Salas, tenantGuard por dono); financeiro de
locação (reserva confirmada -> recebível); Painel da Sala (KPIs, agenda visual, recebíveis, relatório por sala)

Docs: BACKLOG-FINANCEIRO-V1, AUDITORIA-FUNCIONAL-SCOREODONTO, CHECKLIST-DEPLOY-PRODUCAO

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
VPS 4 Builder
2026-06-16 00:28:07 +02:00
parent 92a0ec3917
commit 3e64514b08
62 changed files with 6528 additions and 1035 deletions
+5 -1
View File
@@ -6,6 +6,7 @@ import {
} from 'lucide-react';
import { HybridBackend } from '../services/backend.ts';
import { useToast } from '../contexts/ToastContext.tsx';
import { useConfirm } from '../contexts/ConfirmContext.tsx';
import { PageHeader } from '../components/PageHeader.tsx';
// ─── Status ───────────────────────────────────────────────────────
@@ -28,6 +29,7 @@ const TITULACAO_BADGE: Record<string, string> = {
const CandidaturaCard: React.FC<{ c: any; onAction: () => void }> = ({ c, onAction }) => {
const toast = useToast();
const confirm = useConfirm();
const [open, setOpen] = useState(false);
const [obs, setObs] = useState('');
const [loading, setLoading] = useState(false);
@@ -155,6 +157,7 @@ const CandidaturaCard: React.FC<{ c: any; onAction: () => void }> = ({ c, onActi
const ConfigTab: React.FC = () => {
const toast = useToast();
const confirm = useConfirm();
const [cfg, setCfg] = useState({ taxa_inscricao: '', chave_pix: '', instrucoes_pagamento: '', mp_access_token: '', mp_public_key: '', comissao_pct: '20', texto_responsabilidade: '' });
const [loading, setLoading] = useState(true);
const [salvando, setSalvando] = useState(false);
@@ -282,6 +285,7 @@ const ConfigTab: React.FC = () => {
const FinanceiroTab: React.FC = () => {
const toast = useToast();
const confirm = useConfirm();
const [repasses, setRepasses] = useState<any[]>([]);
const [loading, setLoading] = useState(true);
@@ -297,7 +301,7 @@ const FinanceiroTab: React.FC = () => {
useEffect(() => { load(); }, []);
const confirmar = async (id: string, tutor: string, valor: number) => {
if (!window.confirm(`CONFIRMAR REPASSE DE R$ ${valor.toLocaleString('pt-BR', { minimumFractionDigits: 2 })} PARA ${tutor}?`)) return;
if (!await confirm(`CONFIRMAR REPASSE DE R$ ${valor.toLocaleString('pt-BR', { minimumFractionDigits: 2 })} PARA ${tutor}?`)) return;
const res = await HybridBackend.confirmarRepasse(id);
if (!res.success) { toast.error('ERRO.'); return; }
toast.success('REPASSE CONFIRMADO!');