From 241141f7945dd1ddfb3d0bf2102922e6a2006017 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alessandro=20Gon=C3=A7aalves?= Date: Tue, 21 Oct 2025 10:08:00 -0300 Subject: [PATCH] =?UTF-8?q?fix:=20Adi=C3=A7=C3=A3o=20da=20rela=C3=A7=C3=A3?= =?UTF-8?q?o=20sintetico=20x=20anal=C3=ADtico?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/DRE/analitico.tsx | 300 +++++++++++++++++++++----- src/app/DRE/teste.tsx | 4 +- src/app/api/analitico-oracle/route.ts | 61 ++++++ 3 files changed, 314 insertions(+), 51 deletions(-) create mode 100644 src/app/api/analitico-oracle/route.ts diff --git a/src/app/DRE/analitico.tsx b/src/app/DRE/analitico.tsx index 121c9ba..91bc38c 100644 --- a/src/app/DRE/analitico.tsx +++ b/src/app/DRE/analitico.tsx @@ -6,6 +6,7 @@ import { getCoreRowModel, getSortedRowModel, getFilteredRowModel, + ColumnFiltersState, } from "@tanstack/react-table"; import { useVirtualizer } from "@tanstack/react-virtual"; import { Input } from "@/components/ui/input"; @@ -47,6 +48,15 @@ interface AnaliticoItem { historico2: string; created_at: string; updated_at: string; + // Campos adicionais do Oracle + entidade?: string; + tipo_parceiro?: string; + valor_previsto?: number; + valor_confirmado?: number; + valor_pago?: number; + numero_lancamento?: number; + ano_mes_comp?: string; + codgrupo?: string; } interface AnaliticoProps { @@ -64,36 +74,67 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { const [data, setData] = React.useState([]); const [loading, setLoading] = React.useState(false); const [globalFilter, setGlobalFilter] = React.useState(""); - const [columnFilters, setColumnFilters] = React.useState([]); + const [columnFilters, setColumnFilters] = React.useState([]); const [open, setOpen] = React.useState(false); const [conditions, setConditions] = React.useState([ { column: "", operator: "contains", value: "" }, ]); + + // Estado para armazenar filtros externos (vindos do teste.tsx) + const [filtrosExternos, setFiltrosExternos] = React.useState(filtros); + + // Atualizar filtros externos quando os props mudarem, mas preservar filtros internos + React.useEffect(() => { + setFiltrosExternos(filtros); + }, [filtros]); const fetchData = React.useCallback(async () => { - // Só faz a requisição se tiver dataInicio e dataFim - if (!filtros.dataInicio || !filtros.dataFim) { + // Só faz a requisição se tiver dataInicio e dataFim nos filtros externos + if (!filtrosExternos.dataInicio || !filtrosExternos.dataFim) { setData([]); return; } setLoading(true); try { - const params = new URLSearchParams({ - dataInicio: filtros.dataInicio, - dataFim: filtros.dataFim, - ...(filtros.centroCusto && { centroCusto: filtros.centroCusto }), - ...(filtros.codigoGrupo && { codigoGrupo: filtros.codigoGrupo }), - ...(filtros.codigoSubgrupo && { - codigoSubgrupo: filtros.codigoSubgrupo, - }), - ...(filtros.codigoConta && { codigoConta: filtros.codigoConta }), - }); - - const response = await fetch(`/api/analitico?${params}`); + // Usar a nova API do Oracle + const response = await fetch("/api/analitico-oracle"); if (response.ok) { const result = await response.json(); - setData(result as AnaliticoItem[]); + + // Aplicar filtros externos (vindos do teste.tsx) nos dados retornados + let filteredData = result as AnaliticoItem[]; + + // Filtro por período se especificado nos filtros externos + if (filtrosExternos.dataInicio && filtrosExternos.dataFim) { + filteredData = filteredData.filter((item: AnaliticoItem) => { + const dataItem = item.data_competencia || item.ano_mes_comp; + return dataItem && dataItem >= filtrosExternos.dataInicio && dataItem <= filtrosExternos.dataFim; + }); + } + + // Filtro por centro de custo se especificado nos filtros externos + if (filtrosExternos.centroCusto) { + filteredData = filteredData.filter((item: AnaliticoItem) => + item.codigo_centrocusto === filtrosExternos.centroCusto + ); + } + + // Filtro por código do grupo se especificado nos filtros externos + if (filtrosExternos.codigoGrupo) { + filteredData = filteredData.filter((item: AnaliticoItem) => + item.codgrupo === filtrosExternos.codigoGrupo + ); + } + + // Filtro por código da conta se especificado nos filtros externos + if (filtrosExternos.codigoConta) { + filteredData = filteredData.filter((item: AnaliticoItem) => + item.codigo_conta === filtrosExternos.codigoConta + ); + } + + setData(filteredData); } else { console.error("Erro ao buscar dados:", await response.text()); } @@ -102,7 +143,7 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { } finally { setLoading(false); } - }, [filtros]); + }, [filtrosExternos]); React.useEffect(() => { fetchData(); @@ -132,7 +173,10 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { accessorKey: "entidade", header: "Entidade", filterFn: "advancedText", - cell: () => "-", + cell: ({ getValue }: { getValue: () => string }) => { + const value = getValue(); + return value || "-"; + }, }, { accessorKey: "codigo_fornecedor", @@ -181,19 +225,58 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { accessorKey: "valor_previsto", header: "Valor Previsto", filterFn: "advancedText", - cell: () => "-", + cell: ({ getValue }: { getValue: () => number }) => { + const value = getValue(); + if (!value || value === 0) return "-"; + const formatted = new Intl.NumberFormat("pt-BR", { + style: "currency", + currency: "BRL", + }).format(value); + const isNegative = value < 0; + return ( + + {formatted} + + ); + }, }, { accessorKey: "valor_confirmado", header: "Valor Confirmado", filterFn: "advancedText", - cell: () => "-", + cell: ({ getValue }: { getValue: () => number }) => { + const value = getValue(); + if (!value || value === 0) return "-"; + const formatted = new Intl.NumberFormat("pt-BR", { + style: "currency", + currency: "BRL", + }).format(value); + const isNegative = value < 0; + return ( + + {formatted} + + ); + }, }, { accessorKey: "valor_pago", header: "Valor Pago", filterFn: "advancedText", - cell: () => "-", + cell: ({ getValue }: { getValue: () => number }) => { + const value = getValue(); + if (!value || value === 0) return "-"; + const formatted = new Intl.NumberFormat("pt-BR", { + style: "currency", + currency: "BRL", + }).format(value); + const isNegative = value < 0; + return ( + + {formatted} + + ); + }, }, { accessorKey: "historico", @@ -209,7 +292,10 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { accessorKey: "numero_lancamento", header: "Número do Lançamento", filterFn: "advancedText", - cell: () => "-", + cell: ({ getValue }: { getValue: () => number }) => { + const value = getValue(); + return value || "-"; + }, }, ], [] @@ -217,7 +303,7 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { const filterFns = React.useMemo( () => ({ - advancedText: (row: any, columnId: string, filters: any[]) => { + advancedText: (row: any, columnId: string, filters: ColumnFiltersState) => { if (!filters || filters.length === 0) return true; // Se veio um único filtro (objeto), transforma em array @@ -256,7 +342,7 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { const table = useReactTable({ data, - columns, + columns: columns as any, state: { globalFilter, columnFilters }, onGlobalFilterChange: setGlobalFilter, onColumnFiltersChange: setColumnFilters, @@ -306,6 +392,7 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { setConditions([{ column: "", operator: "contains", value: "" }]); setColumnFilters([]); setGlobalFilter(""); + // Não limpar os filtros externos - eles vêm do teste.tsx }; const [totalValor, setTotalValor] = React.useState(0); @@ -314,7 +401,7 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { // Usar dados filtrados da tabela em vez dos dados originais const filteredData = table.getRowModel().rows.map((row) => row.original); const newTotal = filteredData.reduce((sum, item) => { - const valor = + const valor = typeof item.valor === "string" ? parseFloat(item.valor) : item.valor; return sum + (isNaN(valor) ? 0 : valor); }, 0); @@ -335,18 +422,32 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { // Usar EXATAMENTE a mesma lógica do totalValor const filteredData = table.getRowModel().rows.map((row) => row.original); const valorRealizado = filteredData.reduce((sum, item) => { - const valor = - typeof item.valor === "string" ? parseFloat(item.valor) : item.valor; + const valor = typeof item.valor === "string" ? parseFloat(item.valor) : item.valor; + return sum + (isNaN(valor) ? 0 : valor); + }, 0); + + const valorPrevisto = filteredData.reduce((sum, item) => { + const valor = typeof item.valor_previsto === "string" ? parseFloat(item.valor_previsto) : (item.valor_previsto || 0); + return sum + (isNaN(valor) ? 0 : valor); + }, 0); + + const valorConfirmado = filteredData.reduce((sum, item) => { + const valor = typeof item.valor_confirmado === "string" ? parseFloat(item.valor_confirmado) : (item.valor_confirmado || 0); + return sum + (isNaN(valor) ? 0 : valor); + }, 0); + + const valorPago = filteredData.reduce((sum, item) => { + const valor = typeof item.valor_pago === "string" ? parseFloat(item.valor_pago) : (item.valor_pago || 0); return sum + (isNaN(valor) ? 0 : valor); }, 0); return { valorRealizado, - valorPrevisto: 0, // Sempre 0 pois não há dados - valorConfirmado: 0, // Sempre 0 pois não há dados - valorPago: 0, // Sempre 0 pois não há dados + valorPrevisto, + valorConfirmado, + valorPago, }; - }, [table, data, columnFilters, globalFilter]); + }, [table]); const exportToExcel = () => { if (data.length === 0) return; @@ -442,6 +543,38 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { + {/* Filtros Externos Ativos */} + {(filtrosExternos.dataInicio || filtrosExternos.centroCusto || filtrosExternos.codigoGrupo || filtrosExternos.codigoConta) && ( +
+
+
+ Filtros aplicados pela tabela DRE Gerencial: +
+
+ {filtrosExternos.dataInicio && filtrosExternos.dataFim && ( + + Período: {filtrosExternos.dataInicio} a {filtrosExternos.dataFim} + + )} + {filtrosExternos.centroCusto && ( + + Centro: {filtrosExternos.centroCusto} + + )} + {filtrosExternos.codigoGrupo && ( + + Grupo: {filtrosExternos.codigoGrupo} + + )} + {filtrosExternos.codigoConta && ( + + Conta: {filtrosExternos.codigoConta} + + )} +
+
+ )} + {/* Controls */}
- Limpar Filtros + Limpar Filtros Avançados )} {data.length > 0 && ( @@ -590,7 +723,7 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { )}
- - + {row.original.entidade || "-"}
{row.original.codigo_fornecedor} @@ -625,21 +758,54 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { currency: "BRL", }).format(row.original.valor)}
-
- - +
+ {row.original.valor_previsto && row.original.valor_previsto !== 0 ? ( + + {new Intl.NumberFormat("pt-BR", { + style: "currency", + currency: "BRL", + }).format(row.original.valor_previsto)} + + ) : ( + - + )}
-
- - +
+ {row.original.valor_confirmado && row.original.valor_confirmado !== 0 ? ( + + {new Intl.NumberFormat("pt-BR", { + style: "currency", + currency: "BRL", + }).format(row.original.valor_confirmado)} + + ) : ( + - + )}
-
- - -
+
+ {row.original.valor_pago && row.original.valor_pago !== 0 ? ( + + {new Intl.NumberFormat("pt-BR", { + style: "currency", + currency: "BRL", + }).format(row.original.valor_pago)} + + ) : ( + - + )} +
{row.original.historico} -
+
- - + {row.original.numero_lancamento || "-"}
); @@ -682,14 +848,47 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { currency: "BRL", }).format(columnTotals.valorRealizado)}
-
- - +
+ {columnTotals.valorPrevisto !== 0 ? ( + + {new Intl.NumberFormat("pt-BR", { + style: "currency", + currency: "BRL", + }).format(columnTotals.valorPrevisto)} + + ) : ( + - + )}
-
- - +
+ {columnTotals.valorConfirmado !== 0 ? ( + + {new Intl.NumberFormat("pt-BR", { + style: "currency", + currency: "BRL", + }).format(columnTotals.valorConfirmado)} + + ) : ( + - + )}
-
- - +
+ {columnTotals.valorPago !== 0 ? ( + + {new Intl.NumberFormat("pt-BR", { + style: "currency", + currency: "BRL", + }).format(columnTotals.valorPago)} + + ) : ( + - + )}
@@ -748,6 +947,9 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { Filtros Avançados +

+ Estes filtros são aplicados sobre os dados já filtrados pela tabela DRE Gerencial. +

@@ -873,7 +1075,7 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { onClick={clearFilters} className="flex-1 border-gray-300 text-gray-700 hover:bg-gray-50" > - Limpar todos + Limpar filtros avançados + */} diff --git a/src/app/api/analitico-oracle/route.ts b/src/app/api/analitico-oracle/route.ts new file mode 100644 index 0000000..e22ddf7 --- /dev/null +++ b/src/app/api/analitico-oracle/route.ts @@ -0,0 +1,61 @@ +import { NextRequest, NextResponse } from 'next/server'; +import { executeOracleQuery } from '@/db/oracle'; + +export async function GET(request: NextRequest) { + try { + console.log('🔄 Buscando dados analíticos do Oracle...'); + + // Query para buscar dados da tabela DRE_RESULTADO_ANALITICO + const sql = `SELECT * FROM DRE_RESULTADO_ANALITICO ORDER BY DTVENC, CODFORNEC, CODCONTA`; + + const data = await executeOracleQuery(sql); + + console.log('✅ Query executada com sucesso:', data.length, 'registros encontrados'); + + // Transformar os dados do Oracle para o formato esperado pelo componente + const transformedData = data.map((item: any) => ({ + codigo_grupo: item.CODGRUPO || "", + codigo_subgrupo: "", // Não existe na tabela Oracle + codigo_fornecedor: item.CODFORNEC || "", + nome_fornecedor: item.FORNECEDOR || "", + id: item.NUMLANC || 0, + codfilial: "001", // Valor padrão + recnum: item.NUMLANC || 0, + data_competencia: item.ANOMESCOMP || "", + data_vencimento: item.DTVENC ? new Date(item.DTVENC).toISOString().split('T')[0] : "", + data_pagamento: "", // Não existe na tabela Oracle + data_caixa: item.DTCAIXA ? new Date(item.DTCAIXA).toISOString().split('T')[0] : "", + codigo_conta: item.CODCONTA || "", + conta: item.CONTA || "", + codigo_centrocusto: item.CODIGOCENTROCUSTO || "", + valor: item.VLREALIZADO || 0, + historico: item.HISTORICO || "", + historico2: item.HISTORICO2 || "", + created_at: new Date().toISOString(), + updated_at: new Date().toISOString(), + // Campos adicionais do Oracle + entidade: item.ENTIDADE || "", + tipo_parceiro: item.TIPOPARCEIRO || "", + valor_previsto: item.VLPREVISTO || 0, + valor_confirmado: item.VLCONFIRMADO || 0, + valor_pago: item.VLPAGO || 0, + numero_lancamento: item.NUMLANC || 0, + ano_mes_comp: item.ANOMESCOMP || "", + codgrupo: item.CODGRUPO || "" + })); + + return NextResponse.json(transformedData); + + } catch (error) { + console.error('❌ Erro ao buscar dados analíticos do Oracle:', error); + + return NextResponse.json( + { + success: false, + error: error instanceof Error ? error.message : 'Erro desconhecido', + details: error instanceof Error ? error.stack : undefined + }, + { status: 500 } + ); + } +}