-- ============================================================================= -- sar-triggers.sql -- Triggers de integração SAR → ERP (schema sig/gestao no banco libreplast) -- -- Execução: psql -U postgres -d libreplast -f scripts/sar-triggers.sql -- -- CONTEÚDO: -- 1. ALTER TABLE sar.pedidos — adiciona erp_id_pedido para rastrear ref ERP -- 2. fn_sync_pedido_aprovado_to_erp — replica pedido aprovado em sig.pedidos -- 3. trg_pedido_aprovado — dispara fn acima ao aprovar (situa 1→2) -- 4. sar.clientes_novos — tabela staging de clientes criados pelo rep -- 5. fn_sync_cliente_to_erp — replica cliente em sig.corrent -- 6. trg_cliente_novo — dispara fn acima no INSERT em clientes_novos -- ============================================================================= -- --------------------------------------------------------------------------- -- 1. Coluna de referência ERP no pedido SAR -- --------------------------------------------------------------------------- ALTER TABLE sar.pedidos ADD COLUMN IF NOT EXISTS erp_id_pedido INTEGER; CREATE INDEX IF NOT EXISTS idx_sar_ped_erp_id ON sar.pedidos(erp_id_pedido) WHERE erp_id_pedido IS NOT NULL; -- --------------------------------------------------------------------------- -- 2. Função: replicar pedido aprovado → sig.pedidos + sig.peditens -- -- Dispara quando sar.pedidos.situa muda de qualquer valor para 2 (Aprovado). -- Insere em sig.pedidos com situa=1 (Pendente ERP) para que o operador -- da fábrica finalize o lançamento. Grava o id_pedido ERP de volta em -- sar.pedidos.erp_id_pedido. -- -- id_tes=48 (Venda de Produção) — padrão SAR. Mudar para 53 se for bonificação. -- numero: MAX+1 por empresa — mesmo padrão usado pelo SIG Desktop. -- --------------------------------------------------------------------------- CREATE OR REPLACE FUNCTION sar.fn_sync_pedido_aprovado_to_erp() RETURNS TRIGGER LANGUAGE plpgsql AS $$ DECLARE v_numero INTEGER; v_id_pedido_erp INTEGER; v_cod_pauta INTEGER; v_item RECORD; v_id_st INTEGER; v_endereco TEXT; v_bairro TEXT; v_municipio TEXT; v_estado TEXT; v_cep TEXT; BEGIN -- Só dispara na transição → 2 (Aprovado) e se ainda não sincronizado IF NEW.situa <> 2 OR OLD.situa = 2 OR NEW.erp_id_pedido IS NOT NULL THEN RETURN NEW; END IF; -- Lock por empresa para serializar geração do número (FOR UPDATE não -- é permitido com funções de agregação no PG 18) PERFORM pg_advisory_xact_lock(NEW.id_empresa::bigint); SELECT COALESCE(MAX(numero), 0) + 1 INTO v_numero FROM sig.pedidos WHERE id_empresa = NEW.id_empresa; -- Código da pauta (sig usa codigo, SAR armazena id_pauta) SELECT codigo INTO v_cod_pauta FROM gestao.pauta WHERE id_pauta = NEW.id_pauta LIMIT 1; -- Endereço de entrega do cliente (do ERP) SELECT COALESCE(c.endereco, ''), COALESCE(c.bairr, ''), COALESCE(m.nome, ''), COALESCE(m.estado, ''), COALESCE(c.cep, '') INTO v_endereco, v_bairro, v_municipio, v_estado, v_cep FROM sig.corrent c LEFT JOIN gestao.municipio m ON m.id_municipio = c.id_municipio WHERE c.id_corrent = NEW.id_cliente LIMIT 1; -- Inserir cabeçalho do pedido no ERP INSERT INTO sig.pedidos ( id_empresa, tipo, numero, data, data_emissao, num_ped_vendedor, id_tes, situa, id_local, clien, cod_vendedor, cod_pauta, cod_formapag, e_ender, e_bairr, e_munic, e_estad, e_cep, conta, totpr, ipi, vl_icms_subst, total, descp, descv, com_fat, com_rec, obs, prz_con, tx_acrescimo, num_ped_sar, inf_usuario, fconta, frete, cliente_retira, pesob, pesol, ordem, finalidade, vol_qtd, vol_especie, vol_marca, vol_numero, obs_nf1, obs_nf2, num_oc, usuario_credito, num_lacre, etiqueta_emitida, canc_saldo, rec_antecipado, guid_sarped, redesp_frete, prioridade, classificacao, enviar_email, tp_moeda, vl_cotacao ) VALUES ( NEW.id_empresa, 'P', v_numero, NEW.dt_pedido, NEW.dt_pedido, NEW.num_ped_sar, -- num_ped_vendedor = SAR ref 48, -- id_tes: Venda de Produção 1, -- situa ERP: Pendente (operador finaliza) 0, NEW.id_cliente, NEW.cod_vendedor, COALESCE(v_cod_pauta, 0), COALESCE(NEW.cod_formapag, 0), COALESCE(v_endereco, ''), COALESCE(v_bairro, ''), COALESCE(v_municipio, ''), COALESCE(v_estado, ''), COALESCE(v_cep, ''), '', NEW.total_produtos, NEW.total_ipi, NEW.total_icmsst, NEW.total, NEW.desconto_perc, NEW.desconto_valor, NEW.comissao, 0, COALESCE(LEFT(NEW.obs, 1024), ''), 0, COALESCE(NEW.acrescimo, 0), NEW.num_ped_sar, 1, -- inf_usuario=1: criado pelo SAR 1, -- fconta: CHECK (1,2,3,4,5,6,9) — 1=padrão 0, 0, 0, 0, 0, ' ', '', '', '', '', '', '', ' ', '', '', 0, 0, 0, '', 0, 2, ' ', 0, 0, 0 ) RETURNING id_pedido INTO v_id_pedido_erp; -- Inserir itens no ERP FOR v_item IN SELECT pi.* FROM sar.pedido_itens pi WHERE pi.id_pedido = NEW.id ORDER BY pi.ordem LOOP -- Situação tributária do produto SELECT s.id_st INTO v_id_st FROM gestao.produto p JOIN gestao.st s ON s.codigo = p.cod_st WHERE p.id_erp = v_item.id_produto AND p.id_empresa = CASE WHEN NEW.id_empresa > 9000 THEN NEW.id_empresa - 9000 ELSE NEW.id_empresa END LIMIT 1; INSERT INTO sig.peditens ( id_pedido, ordem, produ, id_grade, qtd, pruni, descp, descv, ipi, total, comis, obs, id_st, preco_pauta, qtd_vasilhame_dev, id_integrado, qtd_bonificacao, num_entrega, vl_comissao_und, id_acabamento, id_vidro, largura, altura, l1, l2, l3, l4, h1, h2, h3, h4, id_varprod, id_vista, num_op, status, vl_icmsst, tp_operacao, vl_acrescimo, tempo_prod_prev, preco_ipi, vl_flex ) VALUES ( v_id_pedido_erp, v_item.ordem, v_item.id_produto, NULL, v_item.qtd, v_item.preco_unitario, v_item.desconto_perc, v_item.desconto_valor, v_item.vl_ipi, v_item.total, v_item.comissao, '', COALESCE(v_id_st, 0), v_item.preco_pauta, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -- status=1: item ativo/normal v_item.vl_icmsst, 0, 0, 0, v_item.preco_com_ipi, v_item.vl_flex ); END LOOP; -- Gravar referência ERP de volta no pedido SAR UPDATE sar.pedidos SET erp_id_pedido = v_id_pedido_erp WHERE id = NEW.id; RETURN NEW; END; $$; -- Criar (ou recriar) o trigger DROP TRIGGER IF EXISTS trg_pedido_aprovado ON sar.pedidos; CREATE TRIGGER trg_pedido_aprovado AFTER UPDATE OF situa ON sar.pedidos FOR EACH ROW EXECUTE FUNCTION sar.fn_sync_pedido_aprovado_to_erp(); -- --------------------------------------------------------------------------- -- 4. Tabela staging de clientes novos criados pelo SAR -- -- O rep preenche os campos obrigatórios e o trigger replica em sig.corrent. -- Após a replicação, id_corrent_erp é preenchido com o id gerado pelo ERP. -- --------------------------------------------------------------------------- CREATE TABLE IF NOT EXISTS sar.clientes_novos ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), id_empresa INTEGER NOT NULL, cod_vendedor INTEGER NOT NULL, -- Dados principais nome VARCHAR(40) NOT NULL, razao VARCHAR(65) NOT NULL, pesso SMALLINT NOT NULL DEFAULT 1, -- 0=PJ 1=PF consfinal SMALLINT NOT NULL DEFAULT 0, cgcpf VARCHAR(18), suf_cgcpf VARCHAR(3) NOT NULL DEFAULT '', inscr VARCHAR(18) NOT NULL DEFAULT '', indicador_ie SMALLINT, -- 1=contribuinte 2=isento 9=não contribuinte -- Endereço endereco VARCHAR(60) NOT NULL DEFAULT '', num_endereco VARCHAR(10) NOT NULL DEFAULT '', bairro VARCHAR(60) NOT NULL DEFAULT '', id_municipio INTEGER NOT NULL, cep VARCHAR(9) NOT NULL DEFAULT '', -- Contato ddd VARCHAR(4) NOT NULL DEFAULT '', telefone VARCHAR(35) NOT NULL DEFAULT '', email VARCHAR(80) NOT NULL DEFAULT '', -- Comercial limite_credito NUMERIC(15,2) NOT NULL DEFAULT 0, cod_formapag INTEGER, cod_pauta INTEGER, -- Resultado após sync id_corrent_erp INTEGER, sincronizado BOOLEAN NOT NULL DEFAULT FALSE, erro_sync TEXT, created_at TIMESTAMP NOT NULL DEFAULT NOW() ); CREATE INDEX IF NOT EXISTS idx_sar_clinovos_empresa ON sar.clientes_novos(id_empresa); CREATE INDEX IF NOT EXISTS idx_sar_clinovos_vend ON sar.clientes_novos(cod_vendedor); CREATE INDEX IF NOT EXISTS idx_sar_clinovos_sync ON sar.clientes_novos(sincronizado); -- --------------------------------------------------------------------------- -- 5. Função: replicar cliente novo → sig.corrent -- -- Campos obrigatórios NOT NULL sem default em sig.corrent recebem '' (char) -- ou 0 (int). O ERP aceita esses defaults — é o mesmo padrão do SIG Desktop -- ao cadastrar cliente mínimo. -- --------------------------------------------------------------------------- CREATE OR REPLACE FUNCTION sar.fn_sync_cliente_to_erp() RETURNS TRIGGER LANGUAGE plpgsql AS $$ DECLARE v_id_corrent INTEGER; BEGIN BEGIN INSERT INTO sig.corrent ( ativo, pesso, consfinal, cgcpf, suf_cgcpf, inscr, nome, razao, endereco, cxpostal, compl, bairr, id_municipio, cep, e_ender, e_bairr, e_cep, c_ender, c_bairr, c_cep, e_mail, grupo_eco, no_reg, hor_descarga, fat_anul, cap_social, cap_realiz, cap_aberto, con_ac_privado, con_ac_nacional, ramo_ativ, cod_ativ_ir, no_empregados, importa, p_importa, exporta, p_exporta, princ_produ1, princ_produ2, princ_produ3, perc_vendas1, perc_vendas2, perc_vendas3, www, banc1, banc2, banc3, agen1, agen2, agen3, nagen1, nagen2, nagen3, ct_nu, ct_se, ci1, ci2, orgex, uf, ddd, telef, fax, data, cod_vendedor, conta, c_dm_nascto, c_fone, con_f, f_dm_nascto, f_fone, c_ctb, c_ctb_consig, -- campos pessoais (obrigatórios sem default) sexo, e_civ, pai, mae, conju, ocupa, c_spc, natur, t_ser, l_tra, t_end, inscr_pro, classe, tolatr, inscr_suframa, lei_livre, codigo, aviso_protesto, codigo_vend_prep, id_tipo, i_ban, i_com, obs, -- comercial limcred, indicador_ie, cod_formapag, cod_pauta ) VALUES ( 1, NEW.pesso, NEW.consfinal, COALESCE(NEW.cgcpf, ''), COALESCE(NEW.suf_cgcpf, ''), COALESCE(NEW.inscr, ''), COALESCE(LEFT(NEW.nome, 40), ''), LEFT(NEW.razao, 65), COALESCE(LEFT(NEW.endereco, 60), ''), 0, '', COALESCE(LEFT(NEW.bairro, 60), ''), NEW.id_municipio, COALESCE(NEW.cep, ''), COALESCE(LEFT(NEW.endereco, 60), ''), COALESCE(LEFT(NEW.bairro, 60), ''), COALESCE(NEW.cep, ''), COALESCE(LEFT(NEW.endereco, 60), ''), COALESCE(LEFT(NEW.bairro, 60), ''), COALESCE(NEW.cep, ''), COALESCE(LEFT(NEW.email, 80), ''), '', '', '', 0, 0, 0, 0, 0, 0, '', 0, 0, 0, 0, 0, 0, '', '', '', 0, 0, 0, '', 0, 0, 0, '', '', '', '', '', '', 0, 0, '', 0, '', '', COALESCE(NEW.ddd, ''), COALESCE(LEFT(NEW.telefone, 35), ''), '', CURRENT_DATE, NEW.cod_vendedor, '', NULL, '', '', NULL, '', 0, 0, -- campos pessoais com defaults neutros 0, 0, '', '', '', '', '', '', 0, '', 0, '', '', 0, '', '', '', 0, 0, 0, '', '', '', -- comercial COALESCE(NEW.limite_credito, 0), NEW.indicador_ie, NEW.cod_formapag, NEW.cod_pauta ) RETURNING id_corrent INTO v_id_corrent; UPDATE sar.clientes_novos SET id_corrent_erp = v_id_corrent, sincronizado = TRUE, erro_sync = NULL WHERE id = NEW.id; EXCEPTION WHEN OTHERS THEN -- Registra o erro sem abortar — rep vê o status na UI UPDATE sar.clientes_novos SET sincronizado = FALSE, erro_sync = SQLERRM WHERE id = NEW.id; END; RETURN NEW; END; $$; -- Criar (ou recriar) o trigger DROP TRIGGER IF EXISTS trg_cliente_novo ON sar.clientes_novos; CREATE TRIGGER trg_cliente_novo AFTER INSERT ON sar.clientes_novos FOR EACH ROW EXECUTE FUNCTION sar.fn_sync_cliente_to_erp(); -- --------------------------------------------------------------------------- -- Verificação final -- --------------------------------------------------------------------------- SELECT trigger_name, event_object_schema || '.' || event_object_table AS tabela, event_manipulation AS evento, action_timing AS timing FROM information_schema.triggers WHERE trigger_schema = 'sar' ORDER BY tabela, trigger_name;