💰 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(tablaorder_costs, generada por cost-tracker) vía CLIsqlite3. - notify-router (
tools/notify-router.ts) → eventofinance_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 consqlite3 data/finanzas.db "SELECT COUNT(*) FROM order_costs".
Cómo replicarlo
- Snippet de carga de
.env. - BD
data/finanzas.dbya poblada por cost-tracker (dependencia upstream). sqlite3instalado para las queries de agregación.- Conversión de hora a
Europe/Madrid+ gate de ventana 21:00 con bypassFORCE=1. - Formato HTML con escape de entidades y marcadores ✅/🔴.
tools/notify-router.tscon el eventofinance_pl_daily(solo Fernando).- Plist launchd con
StartCalendarIntervalHour 21 / Minute 5.