refactor(erp): integração direta com banco ERP — schema sar

Revoga ADR 0006 (BD-por-workspace separado). O SAR agora conecta ao
banco PostgreSQL do ERP (módulo SIG) e usa o schema `sar` para tudo.

PRISMA
- Remove: Client, Product, Order, OrderItem, OrderStatusHistory,
  RepTarget, RepDiscountLimit, PushSubscription (modelos isolados)
- Adiciona: Pedido, PedidoItem, HistoricoPedido, AlcadaDesconto,
  MetaRepresentante, PushSubscription (mapeados para sar.*)
- IDs: id_cliente/cod_vendedor/id_empresa são INTEGER (ERP)
- situa: Int (1=Pendente 2=Aprovado 3=Cancelado 4=Faturado)
- JWT: workspace_id:string → id_empresa:number
- URL: inclui ?schema=sar para Prisma rotear ao schema ERP

SERVICES
- ClientsService: $queryRawUnsafe contra sar.vw_clientes + sar.pedidos
- CatalogService: $queryRawUnsafe contra sar.vw_produtos + sar.vw_estoque
- OrdersService: Prisma models Pedido/PedidoItem/HistoricoPedido/AlcadaDesconto
- DashboardService: MetaRepresentante + queries raw para inativos
- NotificationsService: PushSubscription com codVendedor + idEmpresa

CONTRATOS (api-interface)
- client.contract: campos ERP (idCliente, nome, cgcpf, cod_vendedor…)
- order.contract: PedidoSummary/PedidoDetail/CreatePedido + SITUA_LABEL
- product.contract: ProdutoSummary/ProdutoDetail (vw_produtos)
- auth.contract: workspaceId:string → idEmpresa:number

WEB
- Todos os cockpits e queries atualizados para os novos tipos

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-28 21:51:16 +00:00
parent 246eb28bb1
commit b0b60d7a14
39 changed files with 1433 additions and 1544 deletions

View File

@@ -11,14 +11,13 @@ import { apiFetch } from '../api-client';
export const CLIENT_KEYS = {
all: ['clients'] as const,
list: (params: Partial<ClientListQuery>) => ['clients', 'list', params] as const,
detail: (id: string) => ['clients', 'detail', id] as const,
detail: (id: number) => ['clients', 'detail', id] as const,
};
export function useClientList(params: Partial<ClientListQuery> = {}) {
const qs = new URLSearchParams();
if (params.q) qs.set('q', params.q);
if (params.status) qs.set('status', params.status);
if (params.financialStatus) qs.set('financialStatus', params.financialStatus);
if (params.page) qs.set('page', String(params.page));
if (params.limit) qs.set('limit', String(params.limit));
@@ -27,18 +26,20 @@ export function useClientList(params: Partial<ClientListQuery> = {}) {
return useQuery<ClientListResponse, Error>({
queryKey: CLIENT_KEYS.list(params),
queryFn: async () => {
const raw = await apiFetch(`/clients${query ? `?${query}` : ''}`);
return ClientListResponseSchema.parse(raw);
const res = await apiFetch(`/clients${query ? `?${query}` : ''}`);
if (!res.ok) throw new Error(`clients list error ${res.status}`);
return ClientListResponseSchema.parse(await res.json());
},
});
}
export function useClientDetail(id: string) {
export function useClientDetail(id: number | string | undefined) {
return useQuery<ClientDetail, Error>({
queryKey: CLIENT_KEYS.detail(id),
queryKey: CLIENT_KEYS.detail(Number(id)),
queryFn: async () => {
const raw = await apiFetch(`/clients/${id}`);
return ClientDetailSchema.parse(raw);
const res = await apiFetch(`/clients/${id}`);
if (!res.ok) throw new Error(`client detail error ${res.status}`);
return ClientDetailSchema.parse(await res.json());
},
enabled: !!id,
});