Métricas en tiempo real
MRR
6.847€
↑ +12,3% vs mayo
ARR proyectado
82.164€
↑ +8,1% YoY
Suscripciones activas
47
+3 este mes
En dunning
2
Requieren atención
Churn rate
1,8%
Objetivo <2%
Suscripciones activas — Junio 2026
47 total
| Cliente | Plan | Estado | Próxima factura | Importe |
|---|---|---|---|---|
|
TechCorp Madrid
cus_TC2024001
|
Growth Anual | Activo | 01/01/2027 | 1.490,00€ |
|
Rest. La Huerta
cus_LH2025047
|
Starter Mensual | Dunning #2 | Pendiente cobro | 59,29€ (IVA) |
|
Grupo Altur
cus_GA2025019
|
Enterprise Anual | 15/06/2026 | 4.990,00€ | |
|
Startup Edtech XYZ
cus_ET2026003
|
Starter Trial | Trial | 28/06/2026 | 0,00€ |
|
Clínica Salud360
cus_CS2025088
|
Growth Mensual | Activo | 01/07/2026 | 180,29€ (IVA) |
|
MiGym Pro
cus_MG2024055
|
Enterprise Mensual | Activo | 01/07/2026 | 603,79€ (IVA) |
Ciclo de vida
TRIAL
14-30 días
↓
ACTIVO
Pagando
↙ ↘
PAUSADO
Suspendido
VENCIDO
Pago fallido
↓
CANCELADO
Baja definitiva
Distribución actual
● Activos42 (89%)
● Trial3 (6%)
● Dunning2 (4%)
● Pausados0 (0%)
Ciclos activos
TechCorp — Anual
167 días
Salud360 — Mensual
15 días
Edtech XYZ — Trial
12 días
Distribución por ciclo
28
Mensuales
16
Anuales
3
Trials
Dunning — Rest. La Huerta
Intento 2/3
Pago fallido el 10/06/2026 · Tarjeta terminada en •••• 4521 · Motivo: insufficient_funds
✓
Intento 1
10/06
2
Intento 2
13/06
3
Intento 3
17/06
✕
Cancelación
24/06
Emails enviados
✉ Notif. pago fallido — 10/06
✉ Recordatorio urgente — 13/06
⏳ Último aviso — 17/06
⏳ Cuenta suspendida — 24/06
Acción automática
↓ Restringir export
↓ Bloquear nuevos usuarios
⏳ Suspender acceso
⏳ Archivar datos 30d
Próxima acción automática
17/06/2026 a las 09:00 UTC — Reintento de cargo (49 € + 10,29 € IVA = 59,29 €)
Prorrateo — Grupo Altur (Growth → Enterprise)
Calculado
Cambio de plan el 15/06/2026 a mitad del ciclo anual (180 días restantes de 365)
Plan actual
Growth
1.490€ / año
Días usados185 días
Crédito restante180 días
Tarifa diaria4,08€/día
Crédito a aplicar-734,52€
→
Nuevo plan
Enterprise
4.990€ / año
Enterprise (180d)2.460,82€
Crédito Growth-734,52€
Base imponible1.726,30€
IVA (21%)362,52€
Cobro HOY2.088,82€
Fórmula de prorrateo
credit = (remaining_days / cycle_days) × old_plan_price
charge = (remaining_days / cycle_days) × new_plan_price
net = charge − credit + IVA(21%)
charge = (remaining_days / cycle_days) × new_plan_price
net = charge − credit + IVA(21%)
Factura generada automáticamente
PAGADA
FACTURA #NT-2026-0847
CONCEPTO
UNID.
PRECIO
IMPORTE
NutriTrack Growth — Jun 2026
1
149,00€
149,00€
Periodo: 01/06/2026 – 30/06/2026
Ciclo mensual · 25 seats incluidos · Auto-renovación
Subtotal
149,00€
IVA 21%
31,29€
TOTAL
180,29€
Cobrado automáticamente el 01/06/2026 · Tarjeta •••• 7832
Referencia de pago: pi_3QhTwLKZ0pB82UkM1s5j9cDf · Estado: succeeded
Referencia de pago: pi_3QhTwLKZ0pB82UkM1s5j9cDf · Estado: succeeded
BillingEngine — Core Python
billing_engine.py
from datetime import datetime, timedelta
from decimal import Decimal
from enum import Enum
# Configuración NutriTrack España
VAT_RATE = Decimal('0.21') # IVA 21%
DUNNING_SCHEDULE = [0, 3, 7] # días tras fallo
class BillingEngine:
def process_billing_cycle(self, sub_id):
sub = self.get_subscription(sub_id)
if datetime.now() < sub.period_end:
return # Aún no vence
invoice = self.generate_invoice(sub)
result = self.charge_customer(sub, invoice.total)
if result.success:
invoice.mark_paid()
sub.advance_period()
self.send_invoice_email(invoice)
else:
sub.mark_past_due()
self.start_dunning(sub, invoice)
def calculate_proration(self, sub, new_plan):
cycle_days = (sub.period_end - sub.period_start).days
remaining = (sub.period_end - datetime.now()).days
ratio = Decimal(remaining) / Decimal(cycle_days)
credit = ratio * sub.plan.price
charge = ratio * new_plan.price
net = charge - credit
return {
'credit': credit,
'charge': charge,
'net_excl_vat': net,
'vat': net * VAT_RATE,
'total': net * (1 + VAT_RATE),
}
def start_dunning(self, sub, invoice):
for day_offset in DUNNING_SCHEDULE:
retry_at = datetime.now() + timedelta(days=day_offset)
self.schedule_retry(sub, invoice, retry_at)
# Cancelar si todos fallan (+7d)
cancel_at = datetime.now() + timedelta(days=14)
self.schedule_cancellation(sub, cancel_at)