feat(contratos): sistema completo de contratos odontológicos

- Tabelas contratos e contrato_itens com migrações automáticas
- Endpoints CRUD com itens em transação
- ContratosView: listagem, filtro por status, cards, stats
- ContratoModal: wizard 3 abas (Dados/Itens/Cláusulas), catálogo de
  procedimentos, DnD para reordenar, financeiro completo, print A4
- Sidebar: novo item CONTRATOS
- App.tsx: nova rota /contratos com permissões dentista/funcionario
- PatientsView: botão CONTRATOS no menu financeiro

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
VPS 4 Builder
2026-05-14 20:04:57 +02:00
parent d6d2bc1e78
commit d064aa9058
12 changed files with 2178 additions and 9 deletions
+24 -2
View File
@@ -1,4 +1,4 @@
import { Agendamento, Dentista, DentistaHorario, Especialidade, EvolucaoOrto, FinanceiroItem, Lead, Notificacao, Paciente, Plano, Procedimento, Settings, TratamentoOrto } from '../types.ts';
import { Agendamento, Contrato, Dentista, DentistaHorario, Especialidade, EvolucaoOrto, FinanceiroItem, Lead, Notificacao, Paciente, Plano, Procedimento, Settings, TratamentoOrto } from '../types.ts';
// Helper to enforce uppercase on strings
const toUpper = (str: string | undefined) => str ? str.toUpperCase() : '';
@@ -821,5 +821,27 @@ export const HybridBackend = {
} catch {
return [];
}
}
},
getContratos: async (pacienteId?: string): Promise<Contrato[]> => {
const q = pacienteId ? `?paciente_id=${pacienteId}` : '';
const res = await apiFetch(`${API_URL}/contratos${q}`);
return res.json();
},
saveContrato: async (c: Partial<Contrato> & { items: any[] }): Promise<{ id: string }> => {
const res = await apiFetch(`${API_URL}/contratos`, {
method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(c),
});
return res.json();
},
updateContrato: async (c: Contrato): Promise<void> => {
await apiFetch(`${API_URL}/contratos/${c.id}`, {
method: 'PUT', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(c),
});
},
deleteContrato: async (id: string): Promise<void> => {
await apiFetch(`${API_URL}/contratos/${id}`, { method: 'DELETE' });
},
};