309 lines
18 KiB
Markdown
309 lines
18 KiB
Markdown
# Modelo de Dominio: Billing (MGN-015)
|
|
|
|
**Módulo:** MGN-015 - Billing y Suscripciones SaaS
|
|
**Fecha:** 2025-12-06
|
|
**Estado:** ✅ Implementado
|
|
|
|
---
|
|
|
|
## Diagrama de Entidades
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────────────────┐
|
|
│ BILLING DOMAIN │
|
|
├─────────────────────────────────────────────────────────────────────────────┤
|
|
│ │
|
|
│ ┌──────────────────────┐ ┌──────────────────────┐ │
|
|
│ │ subscription_plans │ │ tenants │ │
|
|
│ │ (Global) │ │ (from auth) │ │
|
|
│ ├──────────────────────┤ ├──────────────────────┤ │
|
|
│ │ id │ │ id │ │
|
|
│ │ code │◄────────│ │ │
|
|
│ │ name │ └──────────┬───────────┘ │
|
|
│ │ price_monthly │ │ │
|
|
│ │ price_yearly │ │ 1 │
|
|
│ │ max_users │ │ │
|
|
│ │ max_companies │ ▼ │
|
|
│ │ features (JSONB) │ ┌──────────────────────┐ │
|
|
│ └──────────┬───────────┘ │ subscriptions │ │
|
|
│ │ ├──────────────────────┤ │
|
|
│ │ 1 │ id │ │
|
|
│ │ │ tenant_id │──┐ │
|
|
│ ▼ │ plan_id │ │ │
|
|
│ ┌──────────────────────┐ │ status │ │ │
|
|
│ │ subscriptions │◄────────│ billing_cycle │ │ │
|
|
│ │ │ │ current_period_start │ │ │
|
|
│ └──────────────────────┘ │ current_period_end │ │ │
|
|
│ │ stripe_subscription_id│ │ │
|
|
│ └──────────┬───────────┘ │ │
|
|
│ │ │ │
|
|
│ │ 1 │ │
|
|
│ ▼ │ │
|
|
│ ┌──────────────────────┐ │ │
|
|
│ │ subscription_history │ │ │
|
|
│ ├──────────────────────┤ │ │
|
|
│ │ id │ │ │
|
|
│ │ subscription_id │ │ │
|
|
│ │ event_type │ │ │
|
|
│ │ previous_plan_id │ │ │
|
|
│ │ new_plan_id │ │ │
|
|
│ │ metadata (JSONB) │ │ │
|
|
│ └──────────────────────┘ │ │
|
|
│ │ │
|
|
│ ┌──────────────────────┐ ┌──────────────────────┐ │ │
|
|
│ │ tenant_owners │ │ payment_methods │ │ │
|
|
│ ├──────────────────────┤ ├──────────────────────┤ │ │
|
|
│ │ id │ │ id │ │ │
|
|
│ │ tenant_id │◄────────│ tenant_id │◄─┤ │
|
|
│ │ user_id │ │ type │ │ │
|
|
│ │ ownership_type │ │ card_last_four │ │ │
|
|
│ │ billing_email │ │ card_brand │ │ │
|
|
│ └──────────────────────┘ │ is_default │ │ │
|
|
│ │ stripe_payment_method_id│ │ │
|
|
│ └──────────────────────┘ │ │
|
|
│ │ │
|
|
│ ┌──────────────────────┐ ┌──────────────────────┐ │ │
|
|
│ │ invoices │ │ payments │ │ │
|
|
│ ├──────────────────────┤ ├──────────────────────┤ │ │
|
|
│ │ id │◄────────│ id │ │ │
|
|
│ │ tenant_id │◄────────│ tenant_id │◄─┤ │
|
|
│ │ subscription_id │ │ invoice_id │ │ │
|
|
│ │ invoice_number │ │ payment_method_id │ │ │
|
|
│ │ status │ │ amount │ │ │
|
|
│ │ subtotal │ │ status │ │ │
|
|
│ │ tax_amount │ │ paid_at │ │ │
|
|
│ │ total │ │ stripe_payment_intent_id│ │ │
|
|
│ │ cfdi_uuid │ └──────────────────────┘ │ │
|
|
│ └──────────┬───────────┘ │ │
|
|
│ │ │ │
|
|
│ │ 1..* │ │
|
|
│ ▼ │ │
|
|
│ ┌──────────────────────┐ │ │
|
|
│ │ invoice_lines │ │ │
|
|
│ ├──────────────────────┤ │ │
|
|
│ │ id │ │ │
|
|
│ │ invoice_id │ │ │
|
|
│ │ description │ │ │
|
|
│ │ quantity │ │ │
|
|
│ │ unit_price │ │ │
|
|
│ │ amount │ │ │
|
|
│ └──────────────────────┘ │ │
|
|
│ │ │
|
|
│ ┌──────────────────────┐ ┌──────────────────────┐ │ │
|
|
│ │ coupons │ │ coupon_redemptions │ │ │
|
|
│ │ (Global) │ ├──────────────────────┤ │ │
|
|
│ ├──────────────────────┤ │ id │ │ │
|
|
│ │ id │◄────────│ coupon_id │ │ │
|
|
│ │ code │ │ tenant_id │◄─┤ │
|
|
│ │ discount_type │ │ subscription_id │ │ │
|
|
│ │ discount_value │ │ redeemed_at │ │ │
|
|
│ │ max_redemptions │ └──────────────────────┘ │ │
|
|
│ │ valid_from │ │ │
|
|
│ │ valid_until │ │ │
|
|
│ └──────────────────────┘ │ │
|
|
│ │ │
|
|
│ ┌──────────────────────┐ │ │
|
|
│ │ usage_records │ │ │
|
|
│ ├──────────────────────┤ │ │
|
|
│ │ id │ │ │
|
|
│ │ tenant_id │◄──────────────────────────────────┘ │
|
|
│ │ subscription_id │ │
|
|
│ │ metric_type │ │
|
|
│ │ quantity │ │
|
|
│ │ billing_period │ │
|
|
│ └──────────────────────┘ │
|
|
│ │
|
|
└─────────────────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## Entidades
|
|
|
|
### 1. subscription_plans (Planes de Suscripción)
|
|
**Propósito:** Define los planes disponibles para los tenants.
|
|
**Alcance:** Global (no tiene tenant_id)
|
|
|
|
| Atributo | Tipo | Descripción |
|
|
|----------|------|-------------|
|
|
| id | UUID | Identificador único |
|
|
| code | VARCHAR(50) | Código único (free, basic, professional, enterprise) |
|
|
| name | VARCHAR(100) | Nombre del plan |
|
|
| price_monthly | DECIMAL | Precio mensual |
|
|
| price_yearly | DECIMAL | Precio anual |
|
|
| max_users | INTEGER | Límite de usuarios (NULL = ilimitado) |
|
|
| max_companies | INTEGER | Límite de empresas |
|
|
| max_storage_gb | INTEGER | Límite de almacenamiento |
|
|
| features | JSONB | Features habilitadas |
|
|
| trial_days | INTEGER | Días de prueba |
|
|
| is_default | BOOLEAN | Plan por defecto |
|
|
|
|
### 2. subscriptions (Suscripciones)
|
|
**Propósito:** Suscripción activa de cada tenant.
|
|
**Restricción:** Solo 1 suscripción por tenant.
|
|
|
|
| Atributo | Tipo | Descripción |
|
|
|----------|------|-------------|
|
|
| id | UUID | Identificador único |
|
|
| tenant_id | UUID | FK a auth.tenants |
|
|
| plan_id | UUID | FK a subscription_plans |
|
|
| status | ENUM | trialing, active, past_due, paused, cancelled, suspended, expired |
|
|
| billing_cycle | ENUM | monthly, quarterly, semi_annual, annual |
|
|
| current_period_start | TIMESTAMP | Inicio del período actual |
|
|
| current_period_end | TIMESTAMP | Fin del período actual |
|
|
| stripe_subscription_id | VARCHAR | ID de Stripe |
|
|
|
|
### 3. tenant_owners (Propietarios)
|
|
**Propósito:** Usuarios que pueden gestionar billing del tenant.
|
|
|
|
| Atributo | Tipo | Descripción |
|
|
|----------|------|-------------|
|
|
| tenant_id | UUID | FK a auth.tenants |
|
|
| user_id | UUID | FK a auth.users |
|
|
| ownership_type | VARCHAR | owner, billing_admin |
|
|
| billing_email | VARCHAR | Email de facturación |
|
|
|
|
### 4. payment_methods (Métodos de Pago)
|
|
**Propósito:** Métodos de pago registrados por tenant.
|
|
|
|
| Atributo | Tipo | Descripción |
|
|
|----------|------|-------------|
|
|
| tenant_id | UUID | FK a auth.tenants |
|
|
| type | ENUM | card, bank_transfer, paypal, oxxo, spei |
|
|
| card_last_four | VARCHAR(4) | Últimos 4 dígitos |
|
|
| card_brand | VARCHAR | visa, mastercard, amex |
|
|
| is_default | BOOLEAN | Método por defecto |
|
|
| stripe_payment_method_id | VARCHAR | ID de Stripe |
|
|
|
|
### 5. invoices (Facturas)
|
|
**Propósito:** Facturas de suscripción.
|
|
|
|
| Atributo | Tipo | Descripción |
|
|
|----------|------|-------------|
|
|
| tenant_id | UUID | FK a auth.tenants |
|
|
| invoice_number | VARCHAR | Número de factura |
|
|
| status | ENUM | draft, open, paid, void, uncollectible |
|
|
| subtotal | DECIMAL | Subtotal |
|
|
| tax_amount | DECIMAL | Impuestos |
|
|
| total | DECIMAL | Total |
|
|
| cfdi_uuid | VARCHAR | UUID del CFDI (México) |
|
|
|
|
### 6. payments (Pagos)
|
|
**Propósito:** Pagos recibidos.
|
|
|
|
| Atributo | Tipo | Descripción |
|
|
|----------|------|-------------|
|
|
| tenant_id | UUID | FK a auth.tenants |
|
|
| invoice_id | UUID | FK a invoices |
|
|
| amount | DECIMAL | Monto pagado |
|
|
| status | ENUM | pending, processing, succeeded, failed, cancelled, refunded |
|
|
| stripe_payment_intent_id | VARCHAR | ID de Stripe |
|
|
|
|
### 7. coupons (Cupones)
|
|
**Propósito:** Cupones de descuento.
|
|
**Alcance:** Global
|
|
|
|
| Atributo | Tipo | Descripción |
|
|
|----------|------|-------------|
|
|
| code | VARCHAR | Código del cupón |
|
|
| discount_type | VARCHAR | percent, fixed |
|
|
| discount_value | DECIMAL | Valor del descuento |
|
|
| max_redemptions | INTEGER | Máximo de usos |
|
|
| valid_from | TIMESTAMP | Válido desde |
|
|
| valid_until | TIMESTAMP | Válido hasta |
|
|
|
|
### 8. usage_records (Registros de Uso)
|
|
**Propósito:** Tracking de uso para billing por consumo.
|
|
|
|
| Atributo | Tipo | Descripción |
|
|
|----------|------|-------------|
|
|
| tenant_id | UUID | FK a auth.tenants |
|
|
| metric_type | VARCHAR | users, storage_gb, api_calls |
|
|
| quantity | DECIMAL | Cantidad consumida |
|
|
| billing_period | DATE | Período de facturación |
|
|
|
|
---
|
|
|
|
## Estados de Suscripción
|
|
|
|
```
|
|
┌─────────┐
|
|
│ trialing│
|
|
└────┬────┘
|
|
│ (trial ends)
|
|
▼
|
|
┌─────────┐ ┌─────────┐ ┌─────────┐
|
|
│ paused │◄───│ active │───►│past_due │
|
|
└────┬────┘ └────┬────┘ └────┬────┘
|
|
│ │ │
|
|
│ │ │ (payment fails)
|
|
│ ▼ ▼
|
|
│ ┌─────────┐ ┌─────────┐
|
|
└───────►│cancelled│ │suspended│
|
|
└─────────┘ └────┬────┘
|
|
│
|
|
▼
|
|
┌─────────┐
|
|
│ expired │
|
|
└─────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## Funciones de Negocio
|
|
|
|
### get_tenant_plan(tenant_id)
|
|
```sql
|
|
SELECT plan_code, plan_name, max_users, features, subscription_status
|
|
FROM billing.get_tenant_plan(tenant_id);
|
|
```
|
|
|
|
### can_add_user(tenant_id)
|
|
```sql
|
|
SELECT billing.can_add_user(tenant_id);
|
|
-- Returns: true/false
|
|
```
|
|
|
|
### has_feature(tenant_id, feature)
|
|
```sql
|
|
SELECT billing.has_feature(tenant_id, 'crm');
|
|
-- Returns: true/false
|
|
```
|
|
|
|
---
|
|
|
|
## Integración con Stripe
|
|
|
|
| Campo | Propósito |
|
|
|-------|-----------|
|
|
| stripe_customer_id | ID del customer en Stripe |
|
|
| stripe_subscription_id | ID de la suscripción en Stripe |
|
|
| stripe_payment_method_id | ID del método de pago |
|
|
| stripe_payment_intent_id | ID del payment intent |
|
|
| stripe_invoice_id | ID de la factura en Stripe |
|
|
|
|
---
|
|
|
|
## Features JSONB Structure
|
|
|
|
```json
|
|
{
|
|
"inventory": true,
|
|
"sales": true,
|
|
"financial": true,
|
|
"purchase": true,
|
|
"crm": false,
|
|
"projects": false,
|
|
"reports_basic": true,
|
|
"reports_advanced": false,
|
|
"api_access": false,
|
|
"white_label": false,
|
|
"priority_support": false
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
**Generado por:** Requirements-Analyst
|
|
**Fecha:** 2025-12-06
|