Files
sar/apps/api/prisma/schema.prisma
julian a6cb1df2aa feat(web+api): cockpit rep — novo pedido v2, endereço de entrega e cancelamento de orçamento
- NewOrderPage: etapas 1-5 — merge de cards, busca de produto melhorada
  (autocomplete com estoque + modal catálogo), responsividade mobile (tabela →
  cards, footer compacto), histórico de compras do cliente e campo de
  endereço de entrega (cadastrado vs livre)
- endEntrega: campo TEXT adicionado em sar.pedidos; contrato CreatePedidoSchema
  e PedidoDetailSchema atualizados; aparece no detalhe (OrderDetailPage,
  OrderDetailModal) e no PDF (OrderPrintPage)
- Cancelamento de orçamento: PATCH /orders/:id/cancel — rep cancela seu
  próprio orçamento (situa 0); histórico registrado; UI com Modal.confirm
  substituindo alert() em OrderActionsMenu
- Fix: useClientDetail chamado para cliente selecionado manualmente, garantindo
  que clientEndStr seja preenchido mesmo sem clientIdParam na URL

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 14:25:24 +00:00

194 lines
8.2 KiB
Plaintext

// SAR — Schema no banco ERP da JCS (schema `sar` dentro do PostgreSQL do SIG/gestao)
// ADR 0006 revogado: banco separado por workspace → schema `sar` no ERP JCS.
// O isolamento multi-tenant é por `id_empresa` em todas as tabelas.
//
// CODING-RULES PGD-DB-004: moduleFormat = "cjs" (NestJS é CJS)
// CODING-RULES PGD-DB-001: MIGRATION_DATABASE_URL aponta direto ao PG (sem PgBouncer)
// A URL de runtime deve incluir ?schema=sar (injetado pelo JwtAuthGuard via WorkspacePrismaPool)
generator client {
provider = "prisma-client-js"
output = "../../../node_modules/.prisma/client"
moduleFormat = "cjs"
}
// Prisma 7: url removida do schema — conexão em prisma.config.ts (migrate)
// e no WorkspacePrismaPool via PrismaPg adapter (runtime).
// A URL de runtime inclui ?schema=sar para rotear ao schema correto.
datasource db {
provider = "postgresql"
}
// ─── Pedido (C3) ─────────────────────────────────────────────────────────────
//
// Pedido emitido pelo Rep. Situa: 1=Pendente, 2=Aprovado, 3=Cancelado, 4=Faturado.
// idEmpresa: tenant (empresa no ERP). codVendedor: gestao.vendedor.codigo.
// idCliente: sig.corrent.id_corrent. numPedSar: sequencial SAR (SAR-NNNNN).
model Pedido {
id String @id @default(uuid()) @db.Uuid
idEmpresa Int @map("id_empresa")
numPedSar String @unique @map("num_ped_sar")
idCliente Int @map("id_cliente")
codVendedor Int @map("cod_vendedor")
situa Int @default(1)
dtPedido DateTime @default(now()) @db.Date @map("dt_pedido")
idPauta Int? @map("id_pauta")
codFormapag Int? @map("cod_formapag")
totalProdutos Decimal @default(0) @db.Decimal(15, 2) @map("total_produtos")
totalIpi Decimal @default(0) @db.Decimal(15, 2) @map("total_ipi")
totalIcmsst Decimal @default(0) @db.Decimal(15, 2) @map("total_icmsst")
total Decimal @default(0) @db.Decimal(15, 2)
descontoPerc Decimal @default(0) @db.Decimal(5, 2) @map("desconto_perc")
descontoValor Decimal @default(0) @db.Decimal(15, 2) @map("desconto_valor")
acrescimo Decimal @default(0) @db.Decimal(15, 2)
comissao Decimal @default(0) @db.Decimal(15, 2)
pedFlex Decimal @default(0) @db.Decimal(15, 2) @map("ped_flex")
obs String?
endEntrega String? @map("end_entrega")
aprovadoPor Int? @map("aprovado_por")
aprovadoEm DateTime? @map("aprovado_em")
motivoRecusa String? @map("motivo_recusa")
idempotencyKey String? @unique @map("idempotency_key")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
itens PedidoItem[]
historico HistoricoPedido[]
@@index([idEmpresa])
@@index([codVendedor])
@@index([idCliente])
@@index([situa])
@@index([dtPedido])
@@map("pedidos")
}
// ─── PedidoItem (C3/C4) ──────────────────────────────────────────────────────
//
// Item do pedido. Produto desnormalizado via idProduto (vw_produtos).
model PedidoItem {
id String @id @default(uuid()) @db.Uuid
idPedido String @db.Uuid @map("id_pedido")
ordem Int
idProduto Int @map("id_produto")
codProduto String? @map("cod_produto")
descProduto String? @map("desc_produto")
qtd Decimal @db.Decimal(10, 3)
precoUnitario Decimal @db.Decimal(15, 2) @map("preco_unitario")
descontoPerc Decimal @default(0) @db.Decimal(5, 2) @map("desconto_perc")
descontoValor Decimal @default(0) @db.Decimal(15, 2) @map("desconto_valor")
precoPauta Decimal @default(0) @db.Decimal(15, 2) @map("preco_pauta")
comissao Decimal @default(0) @db.Decimal(15, 2)
vlFlex Decimal @default(0) @db.Decimal(15, 2) @map("vl_flex")
precoComIpi Decimal @default(0) @db.Decimal(15, 2) @map("preco_com_ipi")
vlIpi Decimal @default(0) @db.Decimal(15, 2) @map("vl_ipi")
vlIcmsst Decimal @default(0) @db.Decimal(15, 2) @map("vl_icmsst")
total Decimal @db.Decimal(15, 2)
pedido Pedido @relation(fields: [idPedido], references: [id], onDelete: Cascade)
@@index([idPedido])
@@map("pedido_itens")
}
// ─── HistoricoPedido (C3) ────────────────────────────────────────────────────
//
// Registro imutável de cada transição de situa. changedBy = cod_vendedor do ator.
model HistoricoPedido {
id String @id @default(uuid()) @db.Uuid
idPedido String @db.Uuid @map("id_pedido")
situaAnterior Int? @map("situa_anterior")
situaNova Int @map("situa_nova")
changedBy Int @map("changed_by")
nota String?
changedAt DateTime @default(now()) @map("changed_at")
pedido Pedido @relation(fields: [idPedido], references: [id], onDelete: Cascade)
@@index([idPedido])
@@map("historico_pedido")
}
// ─── AlcadaDesconto (C4) ─────────────────────────────────────────────────────
//
// Alçada de desconto por vendedor, empresa e grupo de produto.
// codGrupo = 0 → limite global/default do rep.
model AlcadaDesconto {
codVendedor Int @map("cod_vendedor")
idEmpresa Int @map("id_empresa")
codGrupo Int @default(0) @map("cod_grupo")
limitePerc Decimal @default(5) @db.Decimal(5, 2) @map("limite_perc")
updatedAt DateTime @updatedAt @map("updated_at")
@@id([codVendedor, idEmpresa, codGrupo])
@@index([codVendedor, idEmpresa])
@@map("alcada_desconto")
}
// ─── MetaRepresentante (C7) ──────────────────────────────────────────────────
//
// Meta mensal e taxas de comissão por rep. Uma linha por rep/empresa/mês.
model MetaRepresentante {
codVendedor Int @map("cod_vendedor")
idEmpresa Int @map("id_empresa")
ano Int
mes Int
metaValor Decimal @db.Decimal(15, 2) @map("meta_valor")
taxaComissao Decimal @default(3) @db.Decimal(5, 2) @map("taxa_comissao")
taxaFlex Decimal @default(1) @db.Decimal(5, 2) @map("taxa_flex")
updatedAt DateTime @updatedAt @map("updated_at")
@@id([codVendedor, idEmpresa, ano, mes])
@@index([codVendedor, idEmpresa])
@@map("meta_representante")
}
// ─── Promocao (C8) ───────────────────────────────────────────────────────────
//
// Promoção comercial com validade, criada pelo Gerente. Pode ser por produto
// ou por grupo de produto. descPct em % (ex.: 5.00 = 5%).
model Promocao {
id Int @id @default(autoincrement())
idEmpresa Int @map("id_empresa")
descricao String
codProduto String? @map("cod_produto")
grpProd String? @map("grp_prod")
descPct Decimal @db.Decimal(5, 2) @map("desc_pct")
dataInicio DateTime @db.Date @map("data_inicio")
dataFim DateTime @db.Date @map("data_fim")
ativa Boolean @default(true)
createdAt DateTime @default(now()) @map("created_at")
createdBy String @map("created_by")
@@index([idEmpresa])
@@index([idEmpresa, dataFim])
@@map("promocoes")
}
// ─── PushSubscription (C6) ───────────────────────────────────────────────────
//
// Subscription VAPID Web Push por usuário. endpoint é único por dispositivo/browser.
// codVendedor desnormalizado do JWT para filtrar destinatários.
model PushSubscription {
id String @id @default(uuid()) @db.Uuid
codVendedor Int? @map("cod_vendedor")
idEmpresa Int @map("id_empresa")
role String
endpoint String @unique
p256dh String
auth String
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@index([idEmpresa])
@@index([codVendedor])
@@map("push_subscription")
}