"use client"; import { Icon } from "@iconify/react"; import { useMemo, useState } from "react"; import { iconBanknote, iconBox, iconCard, iconChart, iconDocumentText, iconUsersGroup, iconWalletMoney, } from "../../_core/icons"; import { cartProductsResource, cashSessionsResource, inventoriesResource, paymentsResource, productHistoryResource, productsResource, shopCartsResource, usersResource, warehousesResource, } from "../../_core/services/entities"; import { TableShell, tdClass, thClass } from "../../_core/components/table-shell"; const PAYMENT_LABELS: Record = { cash: "Efectivo", card: "Tarjeta", transfer: "Transferencia" }; const TABS = [ { id: "dia", label: "Ventas del día", icon: iconBanknote }, { id: "producto", label: "Ventas por producto", icon: iconBox }, { id: "empleado", label: "Ventas por empleado", icon: iconUsersGroup }, { id: "utilidad", label: "Utilidad", icon: iconChart }, { id: "inventario", label: "Inventario", icon: iconWalletMoney }, { id: "top", label: "Más vendidos", icon: iconBox }, { id: "pagos", label: "Métodos de pago", icon: iconCard }, { id: "cortes", label: "Cortes de caja", icon: iconDocumentText }, ] as const; type TabId = (typeof TABS)[number]["id"]; function money(value: number | string) { return Number(value).toLocaleString("es-AR", { style: "currency", currency: "USD" }); } function isToday(iso: string) { const d = new Date(iso); const now = new Date(); return d.getFullYear() === now.getFullYear() && d.getMonth() === now.getMonth() && d.getDate() === now.getDate(); } export default function AdminReportsPage() { const [tab, setTab] = useState("dia"); const { data: carts = [] } = shopCartsResource.useList(); const { data: cartProducts = [] } = cartProductsResource.useList(); const { data: history = [] } = productHistoryResource.useList(); const { data: products = [] } = productsResource.useList(); const { data: payments = [] } = paymentsResource.useList(); const { data: users = [] } = usersResource.useList(); const { data: warehouses = [] } = warehousesResource.useList(); const { data: inventories = [] } = inventoriesResource.useList(); const { data: sessions = [] } = cashSessionsResource.useList(); const paidCarts = useMemo(() => carts.filter((c) => c.status === "paid"), [carts]); function productName(id: number) { return products.find((p) => p.id === id)?.name ?? `Producto #${id}`; } function userName(id: number | null) { return users.find((u) => u.id === id)?.name ?? "—"; } const productAgg = useMemo(() => { const map = new Map(); for (const cp of cartProducts) { const cart = paidCarts.find((c) => c.id === cp.cartId); if (!cart) continue; const h = history.find((row) => row.id === cp.historyId); if (!h) continue; const entry = map.get(h.productId) ?? { productId: h.productId, quantity: 0, revenue: 0, profit: 0 }; entry.quantity += cp.quantity; entry.revenue += Number(h.unitPrice) * cp.quantity; entry.profit += (Number(h.unitPrice) - Number(h.costUnit)) * cp.quantity; map.set(h.productId, entry); } return Array.from(map.values()); }, [cartProducts, paidCarts, history]); const employeeAgg = useMemo(() => { const map = new Map(); for (const cart of paidCarts) { const key = cart.userId ?? 0; const entry = map.get(key) ?? { userId: key, count: 0, total: 0 }; entry.count += 1; entry.total += Number(cart.totalPrice); map.set(key, entry); } return Array.from(map.values()).sort((a, b) => b.total - a.total); }, [paidCarts]); const paymentAgg = useMemo(() => { const map = new Map(); for (const p of payments) { if (p.status !== "completed" || Number(p.amount) <= 0) continue; const entry = map.get(p.paymentMethod) ?? { method: p.paymentMethod, count: 0, total: 0 }; entry.count += 1; entry.total += Number(p.amount); map.set(p.paymentMethod, entry); } return Array.from(map.values()).sort((a, b) => b.total - a.total); }, [payments]); const todayCarts = useMemo(() => paidCarts.filter((c) => isToday(c.createdAt)), [paidCarts]); const todayTotal = todayCarts.reduce((sum, c) => sum + Number(c.totalPrice), 0); const totalProfit = productAgg.reduce((sum, p) => sum + p.profit, 0); const totalRevenue = productAgg.reduce((sum, p) => sum + p.revenue, 0); const topProducts = useMemo(() => [...productAgg].sort((a, b) => b.quantity - a.quantity).slice(0, 10), [productAgg]); const closedSessions = useMemo( () => sessions.filter((s) => s.status === "closed").sort((a, b) => (b.closedAt ?? "").localeCompare(a.closedAt ?? "")), [sessions], ); return (

Reportes

Ventas, utilidad, inventario y cortes de caja.

{tab === "dia" && (

Ventas de hoy

{todayCarts.length}

Total de hoy

{money(todayTotal)}

{todayCarts.length === 0 ? (

Todavía no hay ventas hoy.

) : ( Venta Cajero Total Hora {todayCarts.map((c) => ( #{c.id} {userName(c.userId)} {money(c.totalPrice)} {new Date(c.createdAt).toLocaleTimeString("es-AR", { hour: "2-digit", minute: "2-digit" })} ))} )}
)} {tab === "producto" && ( Producto Unidades vendidas Ingresos {productAgg.length === 0 ? ( Sin ventas registradas. ) : ( productAgg .sort((a, b) => b.revenue - a.revenue) .map((p) => ( {productName(p.productId)} {p.quantity} {money(p.revenue)} )) )} )} {tab === "empleado" && ( Empleado Ventas Total {employeeAgg.length === 0 ? ( Sin ventas registradas. ) : ( employeeAgg.map((e) => ( {userName(e.userId)} {e.count} {money(e.total)} )) )} )} {tab === "utilidad" && (

Ingresos totales

{money(totalRevenue)}

Utilidad total

{money(totalProfit)}

Producto Ingresos Utilidad {productAgg .sort((a, b) => b.profit - a.profit) .map((p) => ( {productName(p.productId)} {money(p.revenue)} {money(p.profit)} ))}
)} {tab === "inventario" && ( Producto Almacén Stock {warehouses.length === 0 ? ( No hay stock cargado. ) : ( warehouses.map((w) => { const product = products.find((p) => p.id === w.productId); const low = product && w.stock <= product.minStock; return ( {productName(w.productId)} {inventories.find((i) => i.id === w.inventoryId)?.name ?? "—"} {w.stock} ); }) )} )} {tab === "top" && ( # Producto Unidades vendidas {topProducts.length === 0 ? ( Sin ventas registradas. ) : ( topProducts.map((p, i) => ( {i + 1} {productName(p.productId)} {p.quantity} )) )} )} {tab === "pagos" && ( Método Cobros Total {paymentAgg.length === 0 ? ( Sin pagos registrados. ) : ( paymentAgg.map((p) => ( {PAYMENT_LABELS[p.method] ?? p.method} {p.count} {money(p.total)} )) )} )} {tab === "cortes" && ( Almacén Apertura Cierre Esperado Contado Diferencia {closedSessions.length === 0 ? ( No hay cortes de caja registrados. ) : ( closedSessions.map((s) => { const diff = Number(s.closingCash ?? 0) - Number(s.expectedCash ?? 0); return ( {inventories.find((i) => i.id === s.inventoryId)?.name ?? "—"} {new Date(s.openedAt).toLocaleString("es-AR")} {s.closedAt ? new Date(s.closedAt).toLocaleString("es-AR") : "—"} {money(s.expectedCash ?? 0)} {money(s.closingCash ?? 0)} 0 ? "text-success-soft-foreground" : "text-danger"}`}> {diff > 0 ? "+" : ""} {money(diff)} ); }) )} )}
); }