- Tabela sar.config_empresa (logo em data URL por empresa matriz) com migration idempotente, espelho no schema SQL e GRANT no provision - PUT /catalog/company/logo (gerente/admin) e logoBase64 no GET /catalog/company - vale para a impressao de todos os representantes - Nova tela /ger/config "Configuracoes" com upload/preview/remocao do logo (PNG/JPG/WebP ate 500KB) - Cabecalho da impressao redesenhado: logo a esquerda, dados da empresa condensados em 3 linhas, numero/status/data compactos a direita - ocupa ~metade da altura anterior no A4 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
301 lines
13 KiB
Plaintext
301 lines
13 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")
|
|
}
|
|
|
|
// ─── RegraDesconto (Políticas Comerciais) ────────────────────────────────────
|
|
//
|
|
// Regra de desconto criada pelo Gerente: percentual liberado por grupo e/ou
|
|
// subgrupo de produto e/ou representante, com vigência. Campos nulos = "todos".
|
|
|
|
model RegraDesconto {
|
|
id Int @id @default(autoincrement())
|
|
idEmpresa Int @map("id_empresa")
|
|
descricao String
|
|
codGrupo Int? @map("cod_grupo")
|
|
codSubgrupo Int? @map("cod_subgrupo")
|
|
codVendedor Int? @map("cod_vendedor")
|
|
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("regras_desconto")
|
|
}
|
|
|
|
// ─── ConfigEmpresa ───────────────────────────────────────────────────────────
|
|
//
|
|
// Configurações por empresa. logo_base64: data URL exibido no cabeçalho da
|
|
// impressão do pedido de todos os representantes.
|
|
|
|
model ConfigEmpresa {
|
|
idEmpresa Int @id @map("id_empresa")
|
|
logoBase64 String? @map("logo_base64")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
@@map("config_empresa")
|
|
}
|
|
|
|
// ─── Oportunidade (Funil de Vendas) ──────────────────────────────────────────
|
|
//
|
|
// Oportunidade de venda do representante. Pode referenciar cliente ERP (id_cliente)
|
|
// ou ser um prospect livre (nome_prospect / empresa_prospect).
|
|
// etapa: lead | proposta | negociacao | ganho | perdido
|
|
|
|
model Oportunidade {
|
|
id Int @id @default(autoincrement())
|
|
idEmpresa Int @map("id_empresa")
|
|
codVendedor Int @map("cod_vendedor")
|
|
idCliente Int? @map("id_cliente")
|
|
nomeProspect String? @map("nome_prospect") @db.VarChar(200)
|
|
empresaProspect String? @map("empresa_prospect") @db.VarChar(200)
|
|
titulo String @db.VarChar(200)
|
|
etapa String @default("lead") @db.VarChar(20)
|
|
valorEstimado Decimal? @db.Decimal(15, 2) @map("valor_estimado")
|
|
observacoes String?
|
|
idPedido String? @db.Uuid @map("id_pedido")
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
@@index([idEmpresa, codVendedor])
|
|
@@index([etapa])
|
|
@@map("oportunidades")
|
|
}
|
|
|
|
// ─── Chamados SAC ────────────────────────────────────────────────────────────
|
|
//
|
|
// Chamado aberto pelo representante vinculado a um pedido SAR.
|
|
// tipo: avaria | quantidade_divergente | produto_errado | prazo_entrega | outro
|
|
// status: aberto | em_analise | aguardando_rep | resolvido | cancelado
|
|
// resolucao: reposicao | desconto | cancelamento_item | sem_acao | outro
|
|
|
|
model Chamado {
|
|
id Int @id @default(autoincrement())
|
|
idEmpresa Int @map("id_empresa")
|
|
codVendedor Int @map("cod_vendedor")
|
|
idPedido String? @db.Uuid @map("id_pedido")
|
|
numPedSar Int? @map("num_ped_sar")
|
|
numPedErp Int? @map("num_ped_erp")
|
|
idCliente Int @map("id_cliente")
|
|
nomeCliente String? @db.VarChar(200) @map("nome_cliente")
|
|
tipo String @db.VarChar(50)
|
|
assunto String @db.VarChar(200)
|
|
descricao String
|
|
status String @default("aberto") @db.VarChar(30)
|
|
resolucao String? @db.VarChar(50)
|
|
notaResolucao String? @map("nota_resolucao")
|
|
itensAfetados Json? @map("itens_afetados")
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
mensagens ChamadoMensagem[]
|
|
|
|
@@index([idEmpresa, codVendedor])
|
|
@@index([idEmpresa, status])
|
|
@@map("chamados")
|
|
}
|
|
|
|
model ChamadoMensagem {
|
|
id Int @id @default(autoincrement())
|
|
idChamado Int @map("id_chamado")
|
|
autor String @db.VarChar(10)
|
|
texto String
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
chamado Chamado @relation(fields: [idChamado], references: [id], onDelete: Cascade)
|
|
|
|
@@index([idChamado])
|
|
@@map("chamado_mensagens")
|
|
}
|
|
|
|
// ─── 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")
|
|
}
|