Files
sar/scripts/sar-erp-schema.sql
julian 2abe5e8697 feat(infra): conecta ao banco ERP libreplast e fixa rep 29 como usuário dev
- sar-erp-schema.sql: corrige grupo.nome (era descricao), tp_pauta inexistente
  em pauxpro, COALESCE(id_empresa,1) em vw_clientes para bancos single-tenant,
  e nome do cliente via COALESCE(NULLIF(TRIM(nome),''), TRIM(razao))
- WorkspacePrismaPool: PrismaPg({ schema: 'sar' }) + options search_path=sar
  para ORM e queries raw funcionarem no schema correto
- JwtAuthGuard: força DEV_REP_CODE/DEV_EMPRESA_ID em não-prod — filtro
  global sem tocar em nenhum service
- env.schema: adiciona DEV_REP_CODE e DEV_EMPRESA_ID com defaults 29 e 1

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-05-29 14:07:04 +00:00

651 lines
27 KiB
SQL

-- =============================================================================
-- sar-erp-schema.sql
-- Schema SAR — criado no banco PostgreSQL do ERP (módulo SIG + gestao)
--
-- Conteúdo:
-- PARTE 1 — Views de leitura (espelham dados do ERP, sem modificar nada)
-- PARTE 2 — Tabelas de escrita do SAR (pedidos, histórico, configurações)
--
-- Pré-requisito: schemas gestao e sig já existem no banco do ERP.
-- Execução: psql -U <user> -d <banco_erp> -f sar-erp-schema.sql
-- =============================================================================
CREATE SCHEMA IF NOT EXISTS sar;
-- =============================================================================
-- PARTE 1 — VIEWS DE LEITURA
-- Lêem dos schemas do ERP (gestao, sig). Somente SELECT — nunca escrevem.
-- =============================================================================
-- -----------------------------------------------------------------------------
-- 1. Regras de negócio por empresa (decodifica bitmask + sarconfig key-value)
--
-- Esta é a view mais importante para o SAR: controla o que o rep pode/não pode
-- fazer em cada empresa. O OrdersService lê esta view antes de processar qualquer
-- pedido para aplicar as restrições corretas.
--
-- Flags de bloq_preco_pedido (bitmask de gestao.sarcfg):
-- bit 0 → blog_preco pode alterar preço?
-- bit 1 → blog_desconto pode dar desconto?
-- bit 2 → blog_limite_credito bloqueia venda com crédito estourado?
-- bit 3 → blog_novo_cliente pode vender para cliente novo?
-- bit 4 → blog_preco_promocional acessa preço promocional?
-- bit 5 → blog_formapag_cliente força forma de pagto do cliente?
-- -----------------------------------------------------------------------------
CREATE OR REPLACE VIEW sar.vw_sarcfg AS
SELECT
a.id_empresa,
-- Flags decodificadas do bitmask
(a.bloq_preco_pedido >> 0)::integer & 1 AS blog_preco,
(a.bloq_preco_pedido >> 1)::integer & 1 AS blog_desconto,
(a.bloq_preco_pedido >> 2)::integer & 1 AS blog_limite_credito,
(a.bloq_preco_pedido >> 3)::integer & 1 AS blog_novo_cliente,
(a.bloq_preco_pedido >> 4)::integer & 1 AS blog_preco_promocional,
(a.bloq_preco_pedido >> 5)::integer & 1 AS blog_formapag_cliente,
-- Configurações gerais
COALESCE(a.ativar_prod_pauta::integer, 0) AS ativar_prod_pauta,
COALESCE(a.preco_padrao::integer, 0) AS preco_padrao,
COALESCE(a.preco_com_ipi::integer, 0) AS preco_com_ipi,
COALESCE(a.origem_descmax, 'P'::bpchar) AS origem_descmax,
COALESCE(a.cod_pauta1, 0) AS cod_pauta1,
COALESCE(a.cod_pauta2, 0) AS cod_pauta2,
COALESCE(a.cod_pauta3, 0) AS cod_pauta3,
-- Configs adicionais da tabela sarconfig (key-value)
(SELECT COALESCE(
(SELECT sc.valor::integer FROM gestao.sarconfig sc
WHERE sc.id_empresa = a.id_empresa
AND sc.nome = 'Bloqueio Alterar Pauta de Preços'), 0)
) AS bloq_pauta_preco,
(SELECT COALESCE(
(SELECT sc.valor::integer FROM gestao.sarconfig sc
WHERE sc.id_empresa = a.id_empresa
AND sc.nome = 'Dias Bloqueio Crédito'), 0)
) AS dias_bloq_credito,
(SELECT COALESCE(
(SELECT sc.valor::integer FROM gestao.sarconfig sc
WHERE sc.id_empresa = a.id_empresa
AND sc.nome = 'Dias Bloqueio Comunicação'), 0)
) AS dias_bloq_comunicacao,
(SELECT COALESCE(
(SELECT sc.valor FROM gestao.sarconfig sc
WHERE sc.id_empresa = a.id_empresa
AND sc.nome = 'Tipo Comunicação'), 'C')
) AS tipo_bloq_comunicacao
FROM gestao.sarcfg a;
-- -----------------------------------------------------------------------------
-- 2. Empresas / informações cadastrais
-- -----------------------------------------------------------------------------
CREATE OR REPLACE VIEW sar.vw_empresas AS
SELECT
e.id_empresa,
e.nome,
e.razao_social,
e.cnpj,
e.estado AS uf,
e.id_matriz,
e.id_portador_padrao,
s.origem_descmax,
s.tp_estoque,
s.bloq_preco_pedido,
s.ativar_prod_pauta,
s.preco_padrao,
s.preco_com_ipi
FROM gestao.empresa e
LEFT JOIN gestao.sarcfg s ON s.id_empresa = e.id_empresa;
-- -----------------------------------------------------------------------------
-- 3. Representantes / vendedores habilitados no SAR
-- -----------------------------------------------------------------------------
CREATE OR REPLACE VIEW sar.vw_representantes AS
SELECT
v.id_vendedor,
v.id_empresa,
v.codigo,
v.nome,
v.exp_sar AS habilitado_sar,
v.taxa_com,
v.forma_pag AS forma_pag_comissao,
v.cod_supervisor,
v.taxa_com_super,
v.forma_pag_super,
v.desconto_max,
v.permitir_flex,
COALESCE(f.saldo_flex, 0) AS saldo_flex,
v.vl_ped_minimo,
v.desc_rateio_com,
v.origem_com,
v.cod_pauta1,
v.cod_pauta2,
v.cod_pauta3,
v.cod_pauta4,
v.cod_pauta5,
v.cod_pauta6
FROM gestao.vendedor v
LEFT JOIN gestao.flex f ON f.id_vendedor = v.id_vendedor;
-- -----------------------------------------------------------------------------
-- 4. Metas de vendas por representante (gestao.metavenda)
--
-- tipo (char 2) define o escopo da meta — valores comuns do ERP JCS:
-- 'G' ou 'GE' → meta geral de valor (a que o dashboard usa para % atingido)
-- 'GR' → meta por grupo de produto
-- 'SG' → meta por subgrupo
-- 'MA' → meta por marca
-- 'PR' → meta por produto
-- 'AC' → meta por classe ABC
--
-- Comissão e flex vêm de vw_representantes (taxa_com, taxa_com_super, permitir_flex).
-- sar.meta_representante só guarda overrides que não existem no ERP (ex: taxa_flex SAR).
-- -----------------------------------------------------------------------------
CREATE OR REPLACE VIEW sar.vw_metas AS
SELECT
m.id_metavenda,
m.id_empresa,
m.mes_ano,
EXTRACT(YEAR FROM m.mes_ano)::integer AS ano,
EXTRACT(MONTH FROM m.mes_ano)::integer AS mes,
m.cod_vendedor,
v.nome AS nome_vendedor,
m.tipo,
m.qtdade,
m.valor,
m.peso,
m.vl_fator,
-- Filtros de segmento (opcionais — NULL = meta geral)
m.cod_grupo,
grp.nome AS desc_grupo,
m.cod_subgrupo,
sub.nome AS desc_subgrupo,
m.cod_produto,
m.cod_marca,
mrc.nome AS nome_marca,
m.classe_abc
FROM gestao.metavenda m
LEFT JOIN gestao.vendedor v ON v.codigo = m.cod_vendedor AND v.id_empresa = m.id_empresa
LEFT JOIN gestao.grupo grp ON grp.codigo = m.cod_grupo AND grp.id_empresa = m.id_empresa
LEFT JOIN gestao.grupo sub ON sub.codigo = m.cod_subgrupo AND sub.id_empresa = m.id_empresa
LEFT JOIN gestao.marca mrc ON mrc.codigo = m.cod_marca AND mrc.id_empresa = m.id_empresa;
-- -----------------------------------------------------------------------------
-- 5. Clientes (sig.corrent)
-- -----------------------------------------------------------------------------
CREATE OR REPLACE VIEW sar.vw_clientes AS
SELECT
COALESCE(c.id_empresa, 1) AS id_empresa,
c.id_corrent AS id_cliente,
c.ativo,
COALESCE(NULLIF(TRIM(c.nome), ''), TRIM(c.razao)) AS nome,
TRIM(c.razao) AS razao,
c.pesso AS pessoa, -- 0=PJ 1=PF
c.consfinal,
c.cgcpf,
c.suf_cgcpf,
c.inscr AS inscricao_estadual,
c.endereco,
COALESCE(c.num_endereco, '') AS num_endereco,
c.bairr AS bairro,
c.id_municipio,
c.cep,
c.ddd,
c.telef AS telefone,
c.e_mail AS email,
c.data AS dt_cadastro,
c.obs,
c.cod_formapag,
(
SELECT fp.id_formapag
FROM gestao.formapag fp
LEFT JOIN gestao.empresa e ON e.id_empresa = c.id_empresa
WHERE fp.id_empresa = COALESCE(e.id_matriz, c.id_empresa)
AND fp.codigo = c.cod_formapag
LIMIT 1
) AS id_formapag,
c.indicador_ie,
c.cod_pauta,
c.st_especifica,
COALESCE(c.limcred, 0) AS limite_credito,
c.cod_vendedor,
c.dt_atual
FROM sig.corrent c;
-- -----------------------------------------------------------------------------
-- 6. Municípios
-- -----------------------------------------------------------------------------
CREATE OR REPLACE VIEW sar.vw_municipios AS
SELECT
id_municipio,
nome,
estado AS uf,
codigo_ibge
FROM gestao.municipio;
-- -----------------------------------------------------------------------------
-- 7. Formas de Pagamento
-- -----------------------------------------------------------------------------
CREATE OR REPLACE VIEW sar.vw_formas_pagamento AS
SELECT
id_formapag,
id_empresa,
codigo,
descr AS descricao,
ativa,
numparc AS num_parcelas,
desco AS desconto_perc,
COALESCE(vl_ped_minimo, 0) AS vl_ped_minimo,
COALESCE(libera_credito, 0) AS libera_credito,
COALESCE(acresc, 0) AS tx_acrescimo,
integrar_sar,
dt_atual
FROM gestao.formapag;
-- -----------------------------------------------------------------------------
-- 8. Produtos (catálogo com grupo, subgrupo, marca, tributação)
-- -----------------------------------------------------------------------------
CREATE OR REPLACE VIEW sar.vw_produtos AS
SELECT
p.id_empresa,
p.id_erp,
p.codigo,
p.referencia,
p.descricao,
p.descr_det,
p.ativo,
p.cod_barra,
p.unidade,
p.tipo,
p.vl_preco1,
COALESCE(p.vl_preco2, 0) AS vl_preco2,
COALESCE(p.vl_preco3, 0) AS vl_preco3,
p.cod_grupo,
grp.nome AS grupo,
p.cod_subgrupo,
sub.nome AS subgrupo,
sub.desc_max,
COALESCE(p.grupo_st, '') AS grupo_st,
p.cod_marca,
COALESCE(mrc.nome, 'Sem Marca') AS marca,
p.classe_abc,
p.taxa_comissao,
p.cod_st,
st.aliq_ipi,
COALESCE(st.desc_ipi_bc, 0) AS desc_ipi_bc,
p.peso_liquido,
p.qtd_volume,
COALESCE(p.lote_mul_venda, 1) AS lote_mul_venda,
COALESCE(p.permitir_dif_lote, 0) AS permitir_dif_lote,
COALESCE(p.id_prodvinc, 0) AS id_prodvinc,
COALESCE(p.preco_promocional, 0) AS preco_promocional,
COALESCE(p.tx_desc_lote, 0) AS tx_desc_lote,
p.lista_pauta,
CASE WHEN p.dt_atual > sub.da THEN p.dt_atual ELSE sub.da END AS dt_atual
FROM gestao.produto p
LEFT JOIN gestao.grupo grp ON grp.codigo = p.cod_grupo AND grp.id_empresa = p.id_empresa
LEFT JOIN gestao.grupo sub ON sub.codigo = p.cod_subgrupo AND sub.id_empresa = p.id_empresa
LEFT JOIN gestao.marca mrc ON mrc.codigo = p.cod_marca AND mrc.id_empresa = p.id_empresa
LEFT JOIN gestao.st st ON st.codigo = p.cod_st
WHERE p.id_erp IS NOT NULL;
-- -----------------------------------------------------------------------------
-- 9. Estoque calculado (respeita tp_estoque da configuração SAR)
-- -----------------------------------------------------------------------------
CREATE OR REPLACE VIEW sar.vw_estoque AS
SELECT
p.id_empresa,
p.id_erp,
cfg.tp_estoque,
CASE cfg.tp_estoque
WHEN 'E' THEN COALESCE(e.qtdade, 0) - COALESCE(e.qtd_empenhada, 0)
WHEN 'P' THEN COALESCE(e.qtdade, 0) - COALESCE(e.qtd_empenhada, 0) - COALESCE(e.qtd_pedidos, 0)
WHEN 'Z' THEN 0
ELSE COALESCE(e.qtdade, 0)
END AS qtd_estoque,
COALESCE(e.qtdade, 0) AS qtd_fisico,
COALESCE(e.qtd_empenhada, 0) AS qtd_empenhada,
COALESCE(e.qtd_pedidos, 0) AS qtd_pedidos
FROM gestao.produto p
LEFT JOIN gestao.grupo grp ON grp.codigo = p.cod_grupo AND grp.id_empresa = p.id_empresa
LEFT JOIN gestao.grupo sub ON sub.codigo = p.cod_subgrupo AND sub.id_empresa = p.id_empresa
LEFT JOIN gestao.sarcfg cfg ON cfg.id_empresa = p.id_empresa
LEFT JOIN gestao.estsaldo e ON e.id_produto = p.id_erp
AND e.id_empresa = p.id_empresa
AND e.id_estlocal = p.cod_estlocal
WHERE p.id_erp IS NOT NULL
AND p.ativo = 1
AND p.lista_pauta = 1
AND grp.int_sar = 1
AND sub.int_sar = 1
AND (sub.produto_variacao = 0 OR p.id_prodvinc > 0);
-- -----------------------------------------------------------------------------
-- 10. Situação Tributária ICMS-ST
-- -----------------------------------------------------------------------------
CREATE OR REPLACE VIEW sar.vw_sticms AS
SELECT
st.id_empresa AS id_empresa_matriz,
si.id_sticms,
st.codigo AS cod_st,
si.uf,
si.st_especifica,
si.perc_bc_icms,
si.aliq_icms,
si.modal_bc_icmsst,
si.aliq_icmsst,
si.somar_icmsst_nf,
si.perc_marg_vl_icmsst,
si.contribuinte_icms
FROM gestao.sticms si
JOIN gestao.st st ON st.id_st = si.id_st;
-- -----------------------------------------------------------------------------
-- 11. Pautas de Preço
-- -----------------------------------------------------------------------------
CREATE OR REPLACE VIEW sar.vw_pautas AS
SELECT
p.id_pauta,
p.id_empresa,
p.codigo,
p.ativo,
p.num_pauta,
COALESCE(p.dt_cadast, '1900-01-01'::date) AS dt_cadastro,
p.descricao,
p.obs,
COALESCE(p.dt_ini, '1900-01-01'::date) AS dt_inicio,
COALESCE(p.dt_fim, '2100-01-01'::date) AS dt_fim,
p.pauta_exclusiva_cliente,
COALESCE(p.vl_pedido1, 0) AS vl_pedido1,
COALESCE(p.vl_pedido2, 0) AS vl_pedido2,
COALESCE(p.vl_pedido3, 0) AS vl_pedido3,
COALESCE(p.vl_pedido4, 0) AS vl_pedido4,
COALESCE(p.vl_pedido5, 0) AS vl_pedido5,
COALESCE(p.tx_desconto1, 0) AS tx_desconto1,
COALESCE(p.tx_desconto2, 0) AS tx_desconto2,
COALESCE(p.tx_desconto3, 0) AS tx_desconto3,
COALESCE(p.tx_desconto4, 0) AS tx_desconto4,
COALESCE(p.tx_desconto5, 0) AS tx_desconto5,
COALESCE(p.tp_desconto, 0) AS tp_desconto
FROM gestao.pauta p;
-- -----------------------------------------------------------------------------
-- 12. Produtos por Pauta (preços específicos por pauta)
-- -----------------------------------------------------------------------------
CREATE OR REPLACE VIEW sar.vw_pauta_produtos AS
SELECT
pp.id_pauta,
COALESCE(pp.id_varprod, 0) AS id_varprod,
pp.id_prod AS id_produto,
pp.preco1,
COALESCE(pp.preco2, 0) AS preco2,
COALESCE(pp.preco3, 0) AS preco3,
COALESCE(pp.valor_pauta_icms_st, 0) AS valor_pauta_icms_st,
NULL::integer AS tp_pauta
FROM gestao.pauxpro pp;
-- -----------------------------------------------------------------------------
-- 13. Pedidos históricos do ERP (sig.pedidos — somente leitura)
-- -----------------------------------------------------------------------------
CREATE OR REPLACE VIEW sar.vw_pedidos_erp AS
SELECT
p.id_empresa,
p.id_pedido,
p.num_ped_sar,
p.numero,
p.tipo,
p.situa,
CASE p.situa
WHEN 1 THEN 'Pendente'
WHEN 2 THEN 'Liberado'
WHEN 4 THEN 'Faturado'
WHEN 5 THEN 'Cancelado'
ELSE 'Enviado'
END AS status_descr,
p.data AS dt_pedido,
p.data_emissao AS dt_emissao,
p.clien AS id_cliente,
p.cod_vendedor,
p.cod_formapag,
fp.id_formapag,
fp.descr AS forma_pagamento,
pau.id_pauta,
COALESCE(p.obs, '') AS obs,
p.totpr AS total_produtos,
COALESCE(p.ipi, 0) AS total_ipi,
0 AS total_icmsst,
COALESCE(p.total, 0) AS total,
COALESCE(p.descp, 0) AS desconto_perc,
COALESCE(p.descv, 0) AS desconto_valor,
COALESCE(p.tx_acrescimo, 0) AS acrescimo,
COALESCE(p.com_fat, 0) AS comissao,
COALESCE(p.ped_flex, 0) AS ped_flex,
p.cod_vend2 AS cod_supervisor,
p.tx_com_vend2 AS taxa_com_super
FROM sig.pedidos p
LEFT JOIN gestao.formapag fp ON fp.codigo = p.cod_formapag
AND fp.id_empresa = CASE
WHEN p.id_empresa > 9000
THEN p.id_empresa - 9000
ELSE p.id_empresa
END
LEFT JOIN gestao.pauta pau ON pau.codigo = p.cod_pauta
AND pau.id_empresa = CASE
WHEN p.id_empresa > 9000
THEN p.id_empresa - 9000
ELSE p.id_empresa
END;
-- -----------------------------------------------------------------------------
-- 14. Itens dos Pedidos ERP (sig.peditens — somente leitura)
-- -----------------------------------------------------------------------------
CREATE OR REPLACE VIEW sar.vw_peditens_erp AS
SELECT
i.id_pedido,
i.ordem,
i.produ AS id_produto,
i.qtd,
i.pruni AS preco_unitario,
COALESCE(i.descp, 0) AS desconto_perc,
COALESCE(i.descv, 0) AS desconto_valor,
COALESCE(i.obs, '') AS obs,
COALESCE(i.preco_pauta, 0) AS preco_pauta,
COALESCE(i.vl_flex, 0) AS vl_flex,
COALESCE(i.comis, 0) AS comissao,
COALESCE(i.preco_ipi, 0) AS preco_com_ipi,
0 AS bc_ipi,
COALESCE(i.ipi, 0) AS vl_ipi,
0 AS bc_icmsst,
0 AS vl_icmsst,
COALESCE(i.total, 0) AS total
FROM sig.peditens i;
-- -----------------------------------------------------------------------------
-- 15. Contas a Receber (sig.ctr — situação financeira do cliente)
-- -----------------------------------------------------------------------------
CREATE OR REPLACE VIEW sar.vw_ctr AS
SELECT
c.id_empresa,
c.id_ctr,
c.prefixo,
c.numero,
c.docto AS documento,
c.deved AS id_cliente,
c.id_entrega AS id_pedido_erp,
c.emiss AS dt_emissao,
c.vecto AS dt_vencimento,
c.valor,
0 AS despesa_cartorio,
c.saldo,
c.situacao,
c.data_baixa AS dt_baixa,
c.cod_vendedor
FROM sig.ctr c;
-- -----------------------------------------------------------------------------
-- 16. Grupos de Produtos
-- -----------------------------------------------------------------------------
CREATE OR REPLACE VIEW sar.vw_grupos AS
SELECT
id_empresa,
codigo,
nome AS descricao,
int_sar,
produto_variacao,
desc_max,
da AS dt_atualizacao
FROM gestao.grupo;
-- -----------------------------------------------------------------------------
-- 17. Marcas
-- -----------------------------------------------------------------------------
CREATE OR REPLACE VIEW sar.vw_marcas AS
SELECT
id_empresa,
codigo,
nome
FROM gestao.marca;
-- =============================================================================
-- PARTE 2 — TABELAS DE ESCRITA DO SAR
-- Dados gerados pelo SAR — não existem no ERP.
-- =============================================================================
-- -----------------------------------------------------------------------------
-- Pedidos criados pelo SAR
-- situa: 1=Pendente aprovação 2=Aprovado 3=Cancelado 4=Faturado pelo ERP
-- -----------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS sar.pedidos (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
id_empresa INTEGER NOT NULL,
num_ped_sar VARCHAR(20) NOT NULL UNIQUE,
id_cliente INTEGER NOT NULL, -- sig.corrent.id_corrent
cod_vendedor INTEGER NOT NULL, -- gestao.vendedor.codigo
situa SMALLINT NOT NULL DEFAULT 1,
dt_pedido DATE NOT NULL DEFAULT CURRENT_DATE,
id_pauta INTEGER,
cod_formapag INTEGER,
total_produtos NUMERIC(15,2) NOT NULL DEFAULT 0,
total_ipi NUMERIC(15,2) NOT NULL DEFAULT 0,
total_icmsst NUMERIC(15,2) NOT NULL DEFAULT 0,
total NUMERIC(15,2) NOT NULL DEFAULT 0,
desconto_perc NUMERIC(5,2) NOT NULL DEFAULT 0,
desconto_valor NUMERIC(15,2) NOT NULL DEFAULT 0,
acrescimo NUMERIC(15,2) NOT NULL DEFAULT 0,
comissao NUMERIC(15,2) NOT NULL DEFAULT 0,
ped_flex NUMERIC(15,2) NOT NULL DEFAULT 0,
obs TEXT,
aprovado_por INTEGER, -- cod_vendedor do supervisor
aprovado_em TIMESTAMP,
motivo_recusa TEXT,
idempotency_key VARCHAR(100) UNIQUE,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
-- -----------------------------------------------------------------------------
-- Itens dos Pedidos SAR
-- -----------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS sar.pedido_itens (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
id_pedido UUID NOT NULL REFERENCES sar.pedidos(id) ON DELETE CASCADE,
ordem SMALLINT NOT NULL,
id_produto INTEGER NOT NULL, -- gestao.produto.id_erp
cod_produto VARCHAR(30),
desc_produto VARCHAR(200),
qtd NUMERIC(10,3) NOT NULL,
preco_unitario NUMERIC(15,2) NOT NULL,
desconto_perc NUMERIC(5,2) NOT NULL DEFAULT 0,
desconto_valor NUMERIC(15,2) NOT NULL DEFAULT 0,
preco_pauta NUMERIC(15,2) NOT NULL DEFAULT 0,
comissao NUMERIC(15,2) NOT NULL DEFAULT 0,
vl_flex NUMERIC(15,2) NOT NULL DEFAULT 0,
preco_com_ipi NUMERIC(15,2) NOT NULL DEFAULT 0,
vl_ipi NUMERIC(15,2) NOT NULL DEFAULT 0,
vl_icmsst NUMERIC(15,2) NOT NULL DEFAULT 0,
total NUMERIC(15,2) NOT NULL
);
-- -----------------------------------------------------------------------------
-- Histórico de transições de status dos Pedidos SAR
-- -----------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS sar.historico_pedido (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
id_pedido UUID NOT NULL REFERENCES sar.pedidos(id) ON DELETE CASCADE,
situa_anterior SMALLINT,
situa_nova SMALLINT NOT NULL,
changed_by INTEGER NOT NULL, -- cod_vendedor
nota TEXT,
changed_at TIMESTAMP NOT NULL DEFAULT NOW()
);
-- -----------------------------------------------------------------------------
-- Alçadas de desconto por vendedor / empresa / grupo de produto
-- cod_grupo = 0 → limite global do vendedor
-- -----------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS sar.alcada_desconto (
cod_vendedor INTEGER NOT NULL,
id_empresa INTEGER NOT NULL,
cod_grupo INTEGER NOT NULL DEFAULT 0,
limite_perc NUMERIC(5,2) NOT NULL DEFAULT 5,
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
PRIMARY KEY (cod_vendedor, id_empresa, cod_grupo)
);
-- -----------------------------------------------------------------------------
-- Metas mensais por representante
-- -----------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS sar.meta_representante (
cod_vendedor INTEGER NOT NULL,
id_empresa INTEGER NOT NULL,
ano SMALLINT NOT NULL,
mes SMALLINT NOT NULL,
meta_valor NUMERIC(15,2) NOT NULL,
taxa_comissao NUMERIC(5,2) NOT NULL DEFAULT 3,
taxa_flex NUMERIC(5,2) NOT NULL DEFAULT 1,
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
PRIMARY KEY (cod_vendedor, id_empresa, ano, mes)
);
-- -----------------------------------------------------------------------------
-- Web Push Subscriptions (C6 — VAPID)
-- -----------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS sar.push_subscription (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
cod_vendedor INTEGER, -- NULL se for admin não-vendedor
id_empresa INTEGER NOT NULL,
role VARCHAR(20) NOT NULL, -- rep | supervisor | admin
endpoint TEXT NOT NULL UNIQUE,
p256dh TEXT NOT NULL,
auth TEXT NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
-- =============================================================================
-- ÍNDICES
-- =============================================================================
CREATE INDEX IF NOT EXISTS idx_sar_ped_empresa ON sar.pedidos(id_empresa);
CREATE INDEX IF NOT EXISTS idx_sar_ped_vendedor ON sar.pedidos(cod_vendedor);
CREATE INDEX IF NOT EXISTS idx_sar_ped_cliente ON sar.pedidos(id_cliente);
CREATE INDEX IF NOT EXISTS idx_sar_ped_situa ON sar.pedidos(situa);
CREATE INDEX IF NOT EXISTS idx_sar_ped_dt ON sar.pedidos(dt_pedido);
CREATE INDEX IF NOT EXISTS idx_sar_itens_pedido ON sar.pedido_itens(id_pedido);
CREATE INDEX IF NOT EXISTS idx_sar_hist_pedido ON sar.historico_pedido(id_pedido);
CREATE INDEX IF NOT EXISTS idx_sar_push_empresa ON sar.push_subscription(id_empresa);
CREATE INDEX IF NOT EXISTS idx_sar_push_vend ON sar.push_subscription(cod_vendedor);
CREATE INDEX IF NOT EXISTS idx_sar_meta_vend ON sar.meta_representante(cod_vendedor, id_empresa);
CREATE INDEX IF NOT EXISTS idx_sar_alcada_vend ON sar.alcada_desconto(cod_vendedor, id_empresa);
-- =============================================================================
-- GRANTS (descomentar e ajustar o role conforme o ambiente)
-- =============================================================================
-- GRANT USAGE ON SCHEMA sar TO sar_app;
-- GRANT SELECT ON ALL TABLES IN SCHEMA sar TO sar_app;
-- GRANT INSERT, UPDATE, DELETE ON
-- sar.pedidos,
-- sar.pedido_itens,
-- sar.historico_pedido,
-- sar.alcada_desconto,
-- sar.meta_representante,
-- sar.push_subscription
-- TO sar_app;