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:
@@ -2,70 +2,57 @@ import { z } from 'zod';
|
||||
|
||||
// Contratos canônicos de C4 — Catálogo de Produtos.
|
||||
// Consumidos pela API (output tipado) e pela Web (TanStack Query + parse).
|
||||
// ADR 0006 revogado: produto lido diretamente de vw_produtos (ERP), sem sync.
|
||||
|
||||
// ─── Product Summary (lista) ──────────────────────────────────────────────────
|
||||
// ─── Produto Summary (lista) ──────────────────────────────────────────────────
|
||||
|
||||
export const ProductSummarySchema = z.object({
|
||||
id: z.string().uuid(),
|
||||
code: z.string(),
|
||||
name: z.string(),
|
||||
category: z.string(),
|
||||
unitPrice: z.string(), // Decimal serializado
|
||||
stock: z.string().nullable(),
|
||||
active: z.boolean(),
|
||||
export const ProdutoSummarySchema = z.object({
|
||||
idErp: z.number().int(),
|
||||
codigo: z.string(),
|
||||
descricao: z.string(),
|
||||
unidade: z.string().nullable(),
|
||||
vlPreco1: z.string(),
|
||||
codGrupo: z.number().int().nullable(),
|
||||
grupo: z.string().nullable(),
|
||||
codSubgrupo: z.number().int().nullable(),
|
||||
subgrupo: z.string().nullable(),
|
||||
marca: z.string().nullable(),
|
||||
ativo: z.number().int(),
|
||||
qtdEstoque: z.string().nullable(),
|
||||
listaParauta: z.number().int().nullable(),
|
||||
});
|
||||
export type ProductSummary = z.infer<typeof ProductSummarySchema>;
|
||||
export type ProdutoSummary = z.infer<typeof ProdutoSummarySchema>;
|
||||
|
||||
// ─── Product Detail ───────────────────────────────────────────────────────────
|
||||
// ─── Produto Detail ───────────────────────────────────────────────────────────
|
||||
|
||||
export const ProductDetailSchema = ProductSummarySchema.extend({
|
||||
description: z.string().nullable(),
|
||||
erpCode: z.string().nullable(),
|
||||
syncedAt: z.iso.datetime().nullable(),
|
||||
createdAt: z.iso.datetime(),
|
||||
updatedAt: z.iso.datetime(),
|
||||
export const ProdutoDetailSchema = ProdutoSummarySchema.extend({
|
||||
referencia: z.string().nullable(),
|
||||
descricaoDetalhada: z.string().nullable(),
|
||||
vlPreco2: z.string().nullable(),
|
||||
vlPreco3: z.string().nullable(),
|
||||
aliqIpi: z.string().nullable(),
|
||||
pesoLiquido: z.string().nullable(),
|
||||
qtdVolume: z.string().nullable(),
|
||||
loteMulVenda: z.number().int().nullable(),
|
||||
precoComIpi: z.string().nullable(),
|
||||
precoPromocional: z.string().nullable(),
|
||||
});
|
||||
export type ProductDetail = z.infer<typeof ProductDetailSchema>;
|
||||
export type ProdutoDetail = z.infer<typeof ProdutoDetailSchema>;
|
||||
|
||||
// ─── List query + response ────────────────────────────────────────────────────
|
||||
|
||||
export const ProductListQuerySchema = z.object({
|
||||
q: z.string().optional(), // busca nome/código
|
||||
category: z.string().optional(), // filtra por categoria
|
||||
export const ProdutoListQuerySchema = z.object({
|
||||
q: z.string().optional(),
|
||||
codGrupo: z.coerce.number().int().optional(),
|
||||
page: z.coerce.number().int().positive().default(1),
|
||||
limit: z.coerce.number().int().min(1).max(200).default(50),
|
||||
});
|
||||
export type ProductListQuery = z.infer<typeof ProductListQuerySchema>;
|
||||
export type ProdutoListQuery = z.infer<typeof ProdutoListQuerySchema>;
|
||||
|
||||
export const ProductListResponseSchema = z.object({
|
||||
data: z.array(ProductSummarySchema),
|
||||
export const ProdutoListResponseSchema = z.object({
|
||||
data: z.array(ProdutoSummarySchema),
|
||||
total: z.number().int().nonnegative(),
|
||||
page: z.number().int().positive(),
|
||||
limit: z.number().int().positive(),
|
||||
});
|
||||
export type ProductListResponse = z.infer<typeof ProductListResponseSchema>;
|
||||
|
||||
// ─── Sync (importação da view do ERP) ────────────────────────────────────────
|
||||
|
||||
export const ProductSyncItemSchema = z.object({
|
||||
code: z.string().min(1),
|
||||
name: z.string().min(1),
|
||||
description: z.string().optional(),
|
||||
category: z.string().default('geral'),
|
||||
unitPrice: z.number().positive(),
|
||||
stock: z.number().nonnegative().optional(),
|
||||
active: z.boolean().default(true),
|
||||
erpCode: z.string().optional(),
|
||||
});
|
||||
export type ProductSyncItem = z.infer<typeof ProductSyncItemSchema>;
|
||||
|
||||
export const ProductSyncRequestSchema = z.object({
|
||||
items: z.array(ProductSyncItemSchema).min(1).max(5000),
|
||||
});
|
||||
export type ProductSyncRequest = z.infer<typeof ProductSyncRequestSchema>;
|
||||
|
||||
export const ProductSyncResponseSchema = z.object({
|
||||
upserted: z.number().int().nonnegative(),
|
||||
syncedAt: z.iso.datetime(),
|
||||
});
|
||||
export type ProductSyncResponse = z.infer<typeof ProductSyncResponseSchema>;
|
||||
export type ProdutoListResponse = z.infer<typeof ProdutoListResponseSchema>;
|
||||
|
||||
Reference in New Issue
Block a user