dashboard

This commit is contained in:
Lucas Tettamanti
2026-01-27 02:41:39 -03:00
parent 493f26af17
commit df9420b954
19 changed files with 2105 additions and 111 deletions

View File

@@ -1,19 +1,32 @@
import {
handleListRecentOrders,
handleListOrders,
handleGetProductsWithStock,
handleCreateTestOrder,
handleCreatePaymentLink,
handleSimulateMpWebhook,
} from "../handlers/testing.js";
import { handleGetOrderStats } from "../handlers/stats.js";
export const makeListRecentOrders = (tenantIdOrFn) => async (req, res) => {
export const makeListOrders = (tenantIdOrFn) => async (req, res) => {
try {
const tenantId = typeof tenantIdOrFn === "function" ? tenantIdOrFn() : tenantIdOrFn;
const limit = parseInt(req.query.limit) || 20;
const result = await handleListRecentOrders({ tenantId, limit });
const page = parseInt(req.query.page) || 1;
const limit = parseInt(req.query.limit) || 50;
const result = await handleListOrders({ tenantId, page, limit });
res.json(result);
} catch (err) {
console.error("[testing] listRecentOrders error:", err);
console.error("[testing] listOrders error:", err);
res.status(500).json({ ok: false, error: err.message || "internal_error" });
}
};
export const makeGetOrderStats = (tenantIdOrFn) => async (req, res) => {
try {
const tenantId = typeof tenantIdOrFn === "function" ? tenantIdOrFn() : tenantIdOrFn;
const result = await handleGetOrderStats({ tenantId });
res.json(result);
} catch (err) {
console.error("[stats] getOrderStats error:", err);
res.status(500).json({ ok: false, error: err.message || "internal_error" });
}
};

View File

@@ -0,0 +1,43 @@
import { syncOrdersIncremental } from "../../4-woo-orders/wooOrders.js";
import * as ordersRepo from "../../4-woo-orders/ordersRepo.js";
/**
* Obtiene estadísticas de pedidos para el dashboard
*/
export async function handleGetOrderStats({ tenantId }) {
// 1. Sincronizar pedidos nuevos de Woo
const syncResult = await syncOrdersIncremental({ tenantId });
// 2. Obtener todas las estadísticas en paralelo
const [monthlyStats, productStats, yoyStats, totals] = await Promise.all([
ordersRepo.getMonthlyStats({ tenantId }),
ordersRepo.getProductStats({ tenantId }),
ordersRepo.getYoyStats({ tenantId }),
ordersRepo.getTotals({ tenantId }),
]);
return {
// Stats mensuales (para gráficas de barras/líneas)
months: monthlyStats.months,
totals: monthlyStats.totals,
order_counts: monthlyStats.order_counts,
by_source: monthlyStats.by_source,
by_shipping: monthlyStats.by_shipping,
by_payment: monthlyStats.by_payment,
// Totales agregados (para donuts)
totals_aggregated: totals,
// Stats por producto
top_products_revenue: productStats.by_revenue,
top_products_kg: productStats.by_kg,
top_products_units: productStats.by_units,
// YoY
yoy: yoyStats,
// Info de sync
synced: syncResult.synced,
total_in_cache: syncResult.total,
};
}

View File

@@ -1,13 +1,28 @@
import { createOrder, listRecentOrders } from "../../4-woo-orders/wooOrders.js";
import { createOrder, syncOrdersIncremental } from "../../4-woo-orders/wooOrders.js";
import { createPreference, reconcilePayment } from "../../6-mercadopago/mercadoPago.js";
import { listProducts } from "../db/repo.js";
import * as ordersRepo from "../../4-woo-orders/ordersRepo.js";
/**
* Lista pedidos recientes de WooCommerce
* Lista pedidos desde cache local (con sync incremental)
*/
export async function handleListRecentOrders({ tenantId, limit = 20 }) {
const orders = await listRecentOrders({ tenantId, limit });
return { items: orders };
export async function handleListOrders({ tenantId, page = 1, limit = 50 }) {
// 1. Sincronizar pedidos nuevos de Woo
await syncOrdersIncremental({ tenantId });
// 2. Obtener pedidos paginados desde cache
const orders = await ordersRepo.listOrders({ tenantId, page, limit });
const total = await ordersRepo.countOrders({ tenantId });
return {
items: orders,
pagination: {
page,
limit,
total,
pages: Math.ceil(total / limit),
},
};
}
/**