feat(infra): triggers ERP + reset migrations Prisma para schema correto
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 <noreply@anthropic.com>
This commit is contained in:
@@ -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");
|
||||
@@ -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;
|
||||
@@ -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");
|
||||
@@ -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");
|
||||
@@ -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");
|
||||
@@ -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) {
|
||||
</Flex>
|
||||
</Flex>
|
||||
|
||||
{/* Centro: search (Supervisor/Admin) */}
|
||||
<Flex flex={1} justify="center" style={{ maxWidth: 480, margin: '0 var(--space-2xl)' }}>
|
||||
<Input
|
||||
size="large"
|
||||
placeholder="Buscar cliente, pedido, produto..."
|
||||
prefix={
|
||||
<FontAwesomeIcon icon={faMagnifyingGlass} style={{ color: 'var(--text-muted)' }} />
|
||||
}
|
||||
style={{ borderRadius: 12 }}
|
||||
aria-label="Buscar"
|
||||
{/* Centro: empresa ativa */}
|
||||
<Flex flex={1} justify="center" style={{ margin: '0 var(--space-2xl)' }}>
|
||||
<Flex align="center" gap={10}>
|
||||
<FontAwesomeIcon
|
||||
icon={faBuilding}
|
||||
style={{ color: 'var(--text-muted)', fontSize: 16, flexShrink: 0 }}
|
||||
/>
|
||||
<Flex vertical gap={0}>
|
||||
<Typography.Text
|
||||
style={{
|
||||
fontSize: 'var(--text-xl)',
|
||||
fontWeight: 'var(--font-weight-semibold)',
|
||||
color: 'var(--text-main)',
|
||||
lineHeight: 1.2,
|
||||
whiteSpace: 'nowrap',
|
||||
}}
|
||||
>
|
||||
{nomeEmpresa}
|
||||
</Typography.Text>
|
||||
{mostrarRazao && (
|
||||
<Typography.Text
|
||||
style={{
|
||||
fontSize: 'var(--text-2xs)',
|
||||
color: 'var(--text-muted)',
|
||||
lineHeight: 1.3,
|
||||
whiteSpace: 'nowrap',
|
||||
}}
|
||||
>
|
||||
{razaoSocial}
|
||||
</Typography.Text>
|
||||
)}
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Flex>
|
||||
|
||||
{/* Lado direito: novo pedido + status fundação + notificações + perfil */}
|
||||
|
||||
455
scripts/sar-triggers.sql
Normal file
455
scripts/sar-triggers.sql
Normal file
@@ -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;
|
||||
Reference in New Issue
Block a user