← Volver al catálogo

💰 P&L Daily — Pérdidas y Ganancias diario/semanal/mensual

Archivo: agentes/finanzas/pl-daily.ts · Plist: com.rifai.pl-daily · Horario: todos los días a las 21:05 (StartCalendarInterval Hour 21, Minute 5)

Qué hace

Genera el reporte ejecutivo de Pérdidas y Ganancias leyendo la BD SQLite finanzas.db que llena el cost-tracker. Agrega ingresos, costes (producto, envío, pago) y profit en tres ventanas: hoy, últimos 7 días y últimos 30 días, distinguiendo pedidos totales de los ya cobrados (paid). Calcula además la tasa de cobro real de COD (cobrados/totales). Manda el informe formateado en HTML a Fernando (finanzas) a las 21:00 vía el router. Solo envía dentro de la ventana 21:00-21:59 (o con FORCE=1); fuera de esa hora solo calcula y sale.

Cómo funciona

1. Parsea .env. Si data/finanzas.db no existe, avisa y sale (hay que correr cost-tracker primero).

2. query() ejecuta SQL contra SQLite vía sqlite3 -separator "||" (execSync) y parsea filas.

3. period(days) calcula sumatorios (COUNT, SUM(revenue/cost_*/profit), AVG(margin_pct)) para todos los pedidos y para los financial_status='paid'.

4. Calcula dia (1d), semana (7d) y mes (30d).

5. Comprueba la hora en Europe/Madrid. Si no es la franja 21:00 y no hay FORCE=1, solo loguea y termina sin enviar.

6. Construye el reporte HTML (escapando &&) con bloques HOY / 7 DÍAS / 30 DÍAS, marcando profit con ✅/🔴, y añade la tasa de cobro real COD (paid/total %).

7. Envía con notify({ event: 'finance_pl_daily', level: 'info' }) → solo Fernando.

Datos/APIs

  • SQLite local data/finanzas.db (tabla order_costs, generada por cost-tracker) vía CLI sqlite3.
  • notify-router (tools/notify-router.ts) → evento finance_pl_daily → Fernando (TELEGRAM_FINANCE_TOKEN), sin copia a Sec (regla de routing finanzas).
  • .env: TELEGRAM_REPORTS_TOKEN, TELEGRAM_CHAT_ID (leídos pero el envío real lo hace el router con el token finance). No usa Shopify directamente.

Cómo probarlo

cd /Users/user/rifai-agents && FORCE=1 npx tsx agentes/finanzas/pl-daily.ts

Con FORCE=1 ignora la ventana horaria y envía el P&L a Fernando. Sin FORCE y fuera de las 21:xx solo verás Hora H:M fuera ventana 21:00. Solo calculé, no envío.. Esperado: logs Hoy: N órdenes, profit €X, Semana: ... y, si envía, 📤 P&L enviado vía router (solo Fernando). Si la BD no existe, sale con Sin BD finanzas todavía.

Si se rompe / recuperar

  • Recargar el plist:
  launchctl unload ~/Library/LaunchAgents/com.rifai.pl-daily.plist
  launchctl load   ~/Library/LaunchAgents/com.rifai.pl-daily.plist
  • Logs: /Users/user/rifai-agents/logs/pl-daily.log
  • Si el reporte sale en cero, comprobar que cost-tracker está rellenando data/finanzas.db (corre cada hora). Verificar con sqlite3 data/finanzas.db "SELECT COUNT(*) FROM order_costs".

Cómo replicarlo

  • Snippet de carga de .env.
  • BD data/finanzas.db ya poblada por cost-tracker (dependencia upstream).
  • sqlite3 instalado para las queries de agregación.
  • Conversión de hora a Europe/Madrid + gate de ventana 21:00 con bypass FORCE=1.
  • Formato HTML con escape de entidades y marcadores ✅/🔴.
  • tools/notify-router.ts con el evento finance_pl_daily (solo Fernando).
  • Plist launchd con StartCalendarInterval Hour 21 / Minute 5.