From 35d0ba68d68fe2eea62e955f1399e78acc055523 Mon Sep 17 00:00:00 2001 From: julian Date: Wed, 24 Jun 2026 15:07:54 +0000 Subject: [PATCH] feat(infra): triggers ERP + reset migrations Prisma para schema correto MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Triggers SAR→ERP (scripts/sar-triggers.sql): - trg_pedido_aprovado: ao aprovar (situa 1→2) em sar.pedidos, replica automaticamente em sig.pedidos + sig.peditens e grava erp_id_pedido - trg_cliente_novo: INSERT em sar.clientes_novos replica em sig.corrent com todos os campos obrigatórios; grava id_corrent_erp e flag sincronizado - Corrige trigger tsvectorupdate do ERP para PG 18 (bpchar→text cast) - Adiciona coluna erp_id_pedido em sar.pedidos e tabela sar.clientes_novos Migrations Prisma: - Remove 5 migrations obsoletas com nomes PascalCase (Order, Client, etc.) que não batiam com os @@map snake_case do schema atual - Cria baseline 20260624000000_init_baseline apontando para estado correto Co-Authored-By: Claude Sonnet 4.6 --- .../20260527225728_add_client/migration.sql | 41 -- .../20260527231226_add_order/migration.sql | 95 ---- .../20260527233639_c4_catalog/migration.sql | 52 -- .../migration.sql | 15 - .../migration.sql | 22 - .../migration.sql | 0 apps/web/src/components/layout/Topbar.tsx | 59 ++- scripts/sar-triggers.sql | 455 ++++++++++++++++++ 8 files changed, 496 insertions(+), 243 deletions(-) delete mode 100644 apps/api/prisma/migrations/20260527225728_add_client/migration.sql delete mode 100644 apps/api/prisma/migrations/20260527231226_add_order/migration.sql delete mode 100644 apps/api/prisma/migrations/20260527233639_c4_catalog/migration.sql delete mode 100644 apps/api/prisma/migrations/20260528002822_c7_rep_target/migration.sql delete mode 100644 apps/api/prisma/migrations/20260528121304_c6_push_subscriptions/migration.sql create mode 100644 apps/api/prisma/migrations/20260624000000_init_baseline/migration.sql create mode 100644 scripts/sar-triggers.sql diff --git a/apps/api/prisma/migrations/20260527225728_add_client/migration.sql b/apps/api/prisma/migrations/20260527225728_add_client/migration.sql deleted file mode 100644 index 06b0d85..0000000 --- a/apps/api/prisma/migrations/20260527225728_add_client/migration.sql +++ /dev/null @@ -1,41 +0,0 @@ --- CreateEnum -CREATE TYPE "FinancialStatus" AS ENUM ('regular', 'attention', 'blocked'); - --- CreateTable -CREATE TABLE "Client" ( - "id" UUID NOT NULL, - "name" TEXT NOT NULL, - "tradeName" TEXT, - "taxId" TEXT NOT NULL, - "email" TEXT, - "phone" TEXT, - "address" JSONB, - "financialStatus" "FinancialStatus" NOT NULL DEFAULT 'regular', - "creditLimit" DECIMAL(15,2), - "repId" TEXT NOT NULL, - "lastOrderAt" TIMESTAMP(3), - "lastOrderValue" DECIMAL(15,2), - "openOrdersCount" INTEGER NOT NULL DEFAULT 0, - "erpCode" TEXT, - "syncedAt" TIMESTAMP(3), - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - "deletedAt" TIMESTAMP(3), - - CONSTRAINT "Client_pkey" PRIMARY KEY ("id") -); - --- CreateIndex -CREATE UNIQUE INDEX "Client_taxId_key" ON "Client"("taxId"); - --- CreateIndex -CREATE INDEX "Client_repId_idx" ON "Client"("repId"); - --- CreateIndex -CREATE INDEX "Client_taxId_idx" ON "Client"("taxId"); - --- CreateIndex -CREATE INDEX "Client_name_idx" ON "Client"("name"); - --- CreateIndex -CREATE INDEX "Client_deletedAt_idx" ON "Client"("deletedAt"); diff --git a/apps/api/prisma/migrations/20260527231226_add_order/migration.sql b/apps/api/prisma/migrations/20260527231226_add_order/migration.sql deleted file mode 100644 index f08a2cd..0000000 --- a/apps/api/prisma/migrations/20260527231226_add_order/migration.sql +++ /dev/null @@ -1,95 +0,0 @@ --- CreateEnum -CREATE TYPE "OrderStatus" AS ENUM ('budget', 'pending_approval', 'approved', 'invoiced', 'cancelled'); - --- CreateTable -CREATE TABLE "Order" ( - "id" UUID NOT NULL, - "number" TEXT NOT NULL, - "clientId" UUID NOT NULL, - "repId" TEXT NOT NULL, - "status" "OrderStatus" NOT NULL DEFAULT 'budget', - "discountPct" DECIMAL(5,2) NOT NULL DEFAULT 0, - "subtotal" DECIMAL(15,2) NOT NULL, - "total" DECIMAL(15,2) NOT NULL, - "notes" TEXT, - "approvedById" TEXT, - "approvedAt" TIMESTAMP(3), - "invoicedAt" TIMESTAMP(3), - "cancelledAt" TIMESTAMP(3), - "idempotencyKey" TEXT, - "issuedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - "deletedAt" TIMESTAMP(3), - - CONSTRAINT "Order_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "OrderItem" ( - "id" UUID NOT NULL, - "orderId" UUID NOT NULL, - "productCode" TEXT NOT NULL, - "productName" TEXT NOT NULL, - "quantity" DECIMAL(10,3) NOT NULL, - "unitPrice" DECIMAL(15,2) NOT NULL, - "discountPct" DECIMAL(5,2) NOT NULL DEFAULT 0, - "subtotal" DECIMAL(15,2) NOT NULL, - - CONSTRAINT "OrderItem_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "OrderStatusHistory" ( - "id" UUID NOT NULL, - "orderId" UUID NOT NULL, - "fromStatus" "OrderStatus", - "toStatus" "OrderStatus" NOT NULL, - "changedById" TEXT NOT NULL, - "note" TEXT, - "changedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - - CONSTRAINT "OrderStatusHistory_pkey" PRIMARY KEY ("id") -); - --- CreateIndex -CREATE UNIQUE INDEX "Order_number_key" ON "Order"("number"); - --- CreateIndex -CREATE UNIQUE INDEX "Order_idempotencyKey_key" ON "Order"("idempotencyKey"); - --- CreateIndex -CREATE INDEX "Order_clientId_idx" ON "Order"("clientId"); - --- CreateIndex -CREATE INDEX "Order_repId_idx" ON "Order"("repId"); - --- CreateIndex -CREATE INDEX "Order_status_idx" ON "Order"("status"); - --- CreateIndex -CREATE INDEX "Order_issuedAt_idx" ON "Order"("issuedAt"); - --- CreateIndex -CREATE INDEX "Order_number_idx" ON "Order"("number"); - --- CreateIndex -CREATE INDEX "Order_deletedAt_idx" ON "Order"("deletedAt"); - --- CreateIndex -CREATE INDEX "OrderItem_orderId_idx" ON "OrderItem"("orderId"); - --- CreateIndex -CREATE INDEX "OrderStatusHistory_orderId_idx" ON "OrderStatusHistory"("orderId"); - --- CreateIndex -CREATE INDEX "OrderStatusHistory_changedAt_idx" ON "OrderStatusHistory"("changedAt"); - --- AddForeignKey -ALTER TABLE "Order" ADD CONSTRAINT "Order_clientId_fkey" FOREIGN KEY ("clientId") REFERENCES "Client"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "OrderItem" ADD CONSTRAINT "OrderItem_orderId_fkey" FOREIGN KEY ("orderId") REFERENCES "Order"("id") ON DELETE CASCADE ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "OrderStatusHistory" ADD CONSTRAINT "OrderStatusHistory_orderId_fkey" FOREIGN KEY ("orderId") REFERENCES "Order"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/apps/api/prisma/migrations/20260527233639_c4_catalog/migration.sql b/apps/api/prisma/migrations/20260527233639_c4_catalog/migration.sql deleted file mode 100644 index 6276552..0000000 --- a/apps/api/prisma/migrations/20260527233639_c4_catalog/migration.sql +++ /dev/null @@ -1,52 +0,0 @@ --- AlterTable -ALTER TABLE "OrderItem" ADD COLUMN "productCategory" TEXT NOT NULL DEFAULT 'geral'; - --- CreateTable -CREATE TABLE "Product" ( - "id" UUID NOT NULL, - "code" TEXT NOT NULL, - "name" TEXT NOT NULL, - "description" TEXT, - "category" TEXT NOT NULL DEFAULT 'geral', - "unitPrice" DECIMAL(15,2) NOT NULL, - "stock" DECIMAL(10,3), - "active" BOOLEAN NOT NULL DEFAULT true, - "erpCode" TEXT, - "syncedAt" TIMESTAMP(3), - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - "deletedAt" TIMESTAMP(3), - - CONSTRAINT "Product_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "RepDiscountLimit" ( - "repId" TEXT NOT NULL, - "category" TEXT NOT NULL, - "limit" DECIMAL(5,2) NOT NULL DEFAULT 5, - "updatedAt" TIMESTAMP(3) NOT NULL, - - CONSTRAINT "RepDiscountLimit_pkey" PRIMARY KEY ("repId","category") -); - --- CreateIndex -CREATE UNIQUE INDEX "Product_code_key" ON "Product"("code"); - --- CreateIndex -CREATE INDEX "Product_code_idx" ON "Product"("code"); - --- CreateIndex -CREATE INDEX "Product_name_idx" ON "Product"("name"); - --- CreateIndex -CREATE INDEX "Product_category_idx" ON "Product"("category"); - --- CreateIndex -CREATE INDEX "Product_active_idx" ON "Product"("active"); - --- CreateIndex -CREATE INDEX "Product_deletedAt_idx" ON "Product"("deletedAt"); - --- CreateIndex -CREATE INDEX "RepDiscountLimit_repId_idx" ON "RepDiscountLimit"("repId"); diff --git a/apps/api/prisma/migrations/20260528002822_c7_rep_target/migration.sql b/apps/api/prisma/migrations/20260528002822_c7_rep_target/migration.sql deleted file mode 100644 index 8b4df43..0000000 --- a/apps/api/prisma/migrations/20260528002822_c7_rep_target/migration.sql +++ /dev/null @@ -1,15 +0,0 @@ --- CreateTable -CREATE TABLE "RepTarget" ( - "repId" TEXT NOT NULL, - "year" INTEGER NOT NULL, - "month" INTEGER NOT NULL, - "targetAmount" DECIMAL(15,2) NOT NULL, - "commissionRate" DECIMAL(5,2) NOT NULL DEFAULT 3, - "flexRate" DECIMAL(5,2) NOT NULL DEFAULT 1, - "updatedAt" TIMESTAMP(3) NOT NULL, - - CONSTRAINT "RepTarget_pkey" PRIMARY KEY ("repId","year","month") -); - --- CreateIndex -CREATE INDEX "RepTarget_repId_idx" ON "RepTarget"("repId"); diff --git a/apps/api/prisma/migrations/20260528121304_c6_push_subscriptions/migration.sql b/apps/api/prisma/migrations/20260528121304_c6_push_subscriptions/migration.sql deleted file mode 100644 index 9155277..0000000 --- a/apps/api/prisma/migrations/20260528121304_c6_push_subscriptions/migration.sql +++ /dev/null @@ -1,22 +0,0 @@ --- CreateTable -CREATE TABLE "PushSubscription" ( - "id" UUID NOT NULL, - "userId" TEXT NOT NULL, - "role" TEXT NOT NULL, - "endpoint" TEXT NOT NULL, - "p256dh" TEXT NOT NULL, - "auth" TEXT NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - - CONSTRAINT "PushSubscription_pkey" PRIMARY KEY ("id") -); - --- CreateIndex -CREATE UNIQUE INDEX "PushSubscription_endpoint_key" ON "PushSubscription"("endpoint"); - --- CreateIndex -CREATE INDEX "PushSubscription_userId_idx" ON "PushSubscription"("userId"); - --- CreateIndex -CREATE INDEX "PushSubscription_role_idx" ON "PushSubscription"("role"); diff --git a/apps/api/prisma/migrations/20260624000000_init_baseline/migration.sql b/apps/api/prisma/migrations/20260624000000_init_baseline/migration.sql new file mode 100644 index 0000000..e69de29 diff --git a/apps/web/src/components/layout/Topbar.tsx b/apps/web/src/components/layout/Topbar.tsx index 009c983..efd6586 100644 --- a/apps/web/src/components/layout/Topbar.tsx +++ b/apps/web/src/components/layout/Topbar.tsx @@ -1,17 +1,13 @@ -import { Avatar, Badge, Button, Dropdown, Flex, Input, Typography } from 'antd'; +import { Avatar, Badge, Button, Dropdown, Flex, Typography } from 'antd'; import { PlusOutlined } from '@ant-design/icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { - faBell, - faMagnifyingGlass, - faBars, - faRightFromBracket, -} from '@fortawesome/free-solid-svg-icons'; +import { faBell, faBars, faBuilding, faRightFromBracket } from '@fortawesome/free-solid-svg-icons'; import { useNavigate } from '@tanstack/react-router'; import { brandTokens } from '../../lib/theme'; import { FoundationStatus } from './FoundationStatus'; import { usePendingCount } from '../../lib/queries/notifications'; import { useCurrentUser } from '../../lib/queries/auth'; +import { useCompany } from '../../lib/queries/company'; import { authStore } from '../../lib/auth-store'; interface TopbarProps { @@ -33,6 +29,11 @@ export function Topbar({ onToggleSidebar }: TopbarProps) { const { data: pendingData } = usePendingCount(); const pendingCount = pendingData?.count ?? 0; const { data: user } = useCurrentUser(); + const { data: company } = useCompany(); + const nomeFantasia = company?.nomeFantasia?.trim() ?? null; + const razaoSocial = company?.razaoSocial?.trim() ?? null; + const nomeEmpresa = nomeFantasia ?? razaoSocial ?? '—'; + const mostrarRazao = nomeFantasia && razaoSocial && nomeFantasia !== razaoSocial; const initials = user?.nome ? user.nome .split(' ') @@ -121,17 +122,39 @@ export function Topbar({ onToggleSidebar }: TopbarProps) { - {/* Centro: search (Supervisor/Admin) */} - - - } - style={{ borderRadius: 12 }} - aria-label="Buscar" - /> + {/* Centro: empresa ativa */} + + + + + + {nomeEmpresa} + + {mostrarRazao && ( + + {razaoSocial} + + )} + + {/* Lado direito: novo pedido + status fundação + notificações + perfil */} diff --git a/scripts/sar-triggers.sql b/scripts/sar-triggers.sql new file mode 100644 index 0000000..dc77c40 --- /dev/null +++ b/scripts/sar-triggers.sql @@ -0,0 +1,455 @@ +-- ============================================================================= +-- 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; + + -- Próximo número disponível para a empresa (com lock) + SELECT COALESCE(MAX(numero), 0) + 1 + INTO v_numero + FROM sig.pedidos + WHERE id_empresa = NEW.id_empresa + FOR UPDATE; + + -- 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 + 0, + 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;