ML Engine Updates: - Updated BTCUSD with Polygon API data (2024-2025): 215,699 new records - Re-trained all ML models: Attention (R²: 0.223), Base, Metamodel (87.3% confidence) - Backtest results: +176.71R profit with aggressive_filter strategy Documentation Consolidation: - Created docs/99-analisis/_MAP.md index with 13 new analysis documents - Consolidated inventories: removed duplicates from orchestration/inventarios/ - Updated ML_INVENTORY.yml with BTCUSD metrics and training results - Added execution reports: FASE11-BTCUSD, correction issues, alignment validation Architecture & Integration: - Updated all module documentation with NEXUS v3.4 frontmatter - Fixed _MAP.md indexes across all folders - Updated orchestration plans and traces Files: 229 changed, 5064 insertions(+), 1872 deletions(-) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
652 lines
21 KiB
Markdown
652 lines
21 KiB
Markdown
---
|
|
id: "ET-PAY-001"
|
|
title: "Modelo de Datos Financial"
|
|
type: "Technical Specification"
|
|
status: "Done"
|
|
priority: "Alta"
|
|
epic: "OQI-005"
|
|
project: "trading-platform"
|
|
version: "1.0.0"
|
|
created_date: "2025-12-05"
|
|
updated_date: "2026-01-04"
|
|
---
|
|
|
|
# ET-PAY-001: Modelo de Datos Financial
|
|
|
|
**Epic:** OQI-005 Pagos y Stripe
|
|
**Versión:** 1.0
|
|
**Fecha:** 2025-12-05
|
|
**Responsable:** Requirements-Analyst
|
|
|
|
---
|
|
|
|
## 1. Descripción
|
|
|
|
Define el modelo de datos completo para el schema `financial` en PostgreSQL 15+, incluyendo:
|
|
- Pagos (one-time y recurrentes)
|
|
- Suscripciones
|
|
- Facturas
|
|
- Transacciones de wallet
|
|
- Reembolsos
|
|
- Métodos de pago
|
|
|
|
---
|
|
|
|
## 2. Arquitectura de Base de Datos
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|
│ SCHEMA: financial │
|
|
├─────────────────────────────────────────────────────────────────┤
|
|
│ │
|
|
│ ┌──────────────┐ ┌─────────────────┐ │
|
|
│ │ customers │◄────────│ payments │ │
|
|
│ └──────────────┘ └─────────────────┘ │
|
|
│ │ │ │
|
|
│ │ ▼ │
|
|
│ │ ┌─────────────────┐ │
|
|
│ │ │ refunds │ │
|
|
│ │ └─────────────────┘ │
|
|
│ │ │
|
|
│ ▼ │
|
|
│ ┌──────────────┐ ┌─────────────────┐ │
|
|
│ │subscriptions │────────►│ invoices │ │
|
|
│ └──────────────┘ └─────────────────┘ │
|
|
│ │ │
|
|
│ ▼ │
|
|
│ ┌──────────────┐ │
|
|
│ │payment_methods│ │
|
|
│ └──────────────┘ │
|
|
│ │
|
|
│ ┌──────────────┐ │
|
|
│ │wallet_transactions │
|
|
│ └──────────────┘ │
|
|
│ │
|
|
└─────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## 3. Especificación de Tablas
|
|
|
|
### 3.1 Tabla: `customers`
|
|
|
|
Datos de clientes en Stripe.
|
|
|
|
```sql
|
|
CREATE TABLE financial.customers (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
|
|
-- Relación con usuario
|
|
user_id UUID NOT NULL UNIQUE REFERENCES auth.users(id) ON DELETE CASCADE,
|
|
|
|
-- Stripe
|
|
stripe_customer_id VARCHAR(255) NOT NULL UNIQUE,
|
|
|
|
-- Información de facturación
|
|
email VARCHAR(255) NOT NULL,
|
|
name VARCHAR(255),
|
|
phone VARCHAR(50),
|
|
|
|
-- Dirección de facturación
|
|
billing_address JSONB, -- { "line1", "line2", "city", "state", "postal_code", "country" }
|
|
|
|
-- Configuración
|
|
default_payment_method_id UUID REFERENCES financial.payment_methods(id),
|
|
currency VARCHAR(3) DEFAULT 'usd',
|
|
|
|
-- Metadata
|
|
metadata JSONB,
|
|
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
|
|
|
|
-- Constraints
|
|
CONSTRAINT chk_currency CHECK (currency IN ('usd', 'eur', 'gbp'))
|
|
);
|
|
|
|
-- Índices
|
|
CREATE INDEX idx_customers_user_id ON financial.customers(user_id);
|
|
CREATE INDEX idx_customers_stripe_customer_id ON financial.customers(stripe_customer_id);
|
|
CREATE INDEX idx_customers_email ON financial.customers(email);
|
|
|
|
-- Trigger
|
|
CREATE TRIGGER update_customers_updated_at BEFORE UPDATE ON financial.customers
|
|
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
|
```
|
|
|
|
### 3.2 Tabla: `payment_methods`
|
|
|
|
Métodos de pago guardados del cliente.
|
|
|
|
```sql
|
|
CREATE TABLE financial.payment_methods (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
|
|
-- Relación
|
|
customer_id UUID NOT NULL REFERENCES financial.customers(id) ON DELETE CASCADE,
|
|
|
|
-- Stripe
|
|
stripe_payment_method_id VARCHAR(255) NOT NULL UNIQUE,
|
|
|
|
-- Tipo y detalles
|
|
type VARCHAR(50) NOT NULL, -- 'card', 'bank_account', 'paypal'
|
|
|
|
-- Para tarjetas
|
|
card_brand VARCHAR(50), -- 'visa', 'mastercard', 'amex'
|
|
card_last4 VARCHAR(4),
|
|
card_exp_month INTEGER,
|
|
card_exp_year INTEGER,
|
|
card_country VARCHAR(2),
|
|
|
|
-- Para cuentas bancarias
|
|
bank_name VARCHAR(255),
|
|
bank_last4 VARCHAR(4),
|
|
bank_account_type VARCHAR(20), -- 'checking', 'savings'
|
|
|
|
-- Estado
|
|
is_default BOOLEAN DEFAULT false,
|
|
is_active BOOLEAN DEFAULT true,
|
|
|
|
-- Metadata
|
|
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
|
|
|
|
-- Constraints
|
|
CONSTRAINT chk_payment_method_type CHECK (type IN ('card', 'bank_account', 'paypal'))
|
|
);
|
|
|
|
-- Índices
|
|
CREATE INDEX idx_payment_methods_customer_id ON financial.payment_methods(customer_id);
|
|
CREATE INDEX idx_payment_methods_stripe_id ON financial.payment_methods(stripe_payment_method_id);
|
|
CREATE INDEX idx_payment_methods_is_default ON financial.payment_methods(customer_id, is_default) WHERE is_default = true;
|
|
|
|
-- Trigger
|
|
CREATE TRIGGER update_payment_methods_updated_at BEFORE UPDATE ON financial.payment_methods
|
|
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
|
```
|
|
|
|
### 3.3 Tabla: `payments`
|
|
|
|
Registro de todos los pagos procesados.
|
|
|
|
```sql
|
|
CREATE TABLE financial.payments (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
|
|
-- Relaciones
|
|
user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
|
|
customer_id UUID REFERENCES financial.customers(id),
|
|
|
|
-- Stripe
|
|
stripe_payment_intent_id VARCHAR(255) UNIQUE,
|
|
stripe_charge_id VARCHAR(255),
|
|
|
|
-- Tipo de pago
|
|
payment_type VARCHAR(50) NOT NULL, -- 'one_time', 'subscription', 'invoice', 'investment_deposit'
|
|
|
|
-- Montos
|
|
amount DECIMAL(15, 2) NOT NULL,
|
|
currency VARCHAR(3) NOT NULL DEFAULT 'usd',
|
|
amount_refunded DECIMAL(15, 2) DEFAULT 0.00,
|
|
net_amount DECIMAL(15, 2), -- amount - fees - refunds
|
|
|
|
-- Fees
|
|
application_fee DECIMAL(15, 2),
|
|
stripe_fee DECIMAL(15, 2),
|
|
|
|
-- Estado
|
|
status VARCHAR(50) NOT NULL DEFAULT 'pending', -- 'pending', 'processing', 'succeeded', 'failed', 'canceled', 'refunded'
|
|
|
|
-- Método de pago
|
|
payment_method_id UUID REFERENCES financial.payment_methods(id),
|
|
payment_method_type VARCHAR(50),
|
|
|
|
-- Referencias
|
|
subscription_id UUID REFERENCES financial.subscriptions(id),
|
|
invoice_id UUID REFERENCES financial.invoices(id),
|
|
|
|
-- Metadata
|
|
description TEXT,
|
|
metadata JSONB,
|
|
failure_code VARCHAR(100),
|
|
failure_message TEXT,
|
|
|
|
-- Timestamps
|
|
paid_at TIMESTAMP WITH TIME ZONE,
|
|
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
|
|
|
|
-- Constraints
|
|
CONSTRAINT chk_amount_positive CHECK (amount > 0),
|
|
CONSTRAINT chk_payment_status CHECK (status IN ('pending', 'processing', 'succeeded', 'failed', 'canceled', 'refunded')),
|
|
CONSTRAINT chk_payment_type CHECK (payment_type IN ('one_time', 'subscription', 'invoice', 'investment_deposit'))
|
|
);
|
|
|
|
-- Índices
|
|
CREATE INDEX idx_payments_user_id ON financial.payments(user_id);
|
|
CREATE INDEX idx_payments_customer_id ON financial.payments(customer_id);
|
|
CREATE INDEX idx_payments_stripe_payment_intent ON financial.payments(stripe_payment_intent_id);
|
|
CREATE INDEX idx_payments_status ON financial.payments(status);
|
|
CREATE INDEX idx_payments_created_at ON financial.payments(created_at DESC);
|
|
CREATE INDEX idx_payments_subscription_id ON financial.payments(subscription_id);
|
|
CREATE INDEX idx_payments_invoice_id ON financial.payments(invoice_id);
|
|
|
|
-- Trigger
|
|
CREATE TRIGGER update_payments_updated_at BEFORE UPDATE ON financial.payments
|
|
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
|
```
|
|
|
|
### 3.4 Tabla: `subscriptions`
|
|
|
|
Suscripciones recurrentes de usuarios.
|
|
|
|
```sql
|
|
CREATE TABLE financial.subscriptions (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
|
|
-- Relaciones
|
|
user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
|
|
customer_id UUID NOT NULL REFERENCES financial.customers(id),
|
|
|
|
-- Stripe
|
|
stripe_subscription_id VARCHAR(255) NOT NULL UNIQUE,
|
|
stripe_price_id VARCHAR(255) NOT NULL,
|
|
stripe_product_id VARCHAR(255) NOT NULL,
|
|
|
|
-- Plan
|
|
plan_name VARCHAR(100) NOT NULL, -- 'basic', 'pro', 'enterprise'
|
|
plan_interval VARCHAR(20) NOT NULL, -- 'month', 'year'
|
|
|
|
-- Precio
|
|
amount DECIMAL(15, 2) NOT NULL,
|
|
currency VARCHAR(3) NOT NULL DEFAULT 'usd',
|
|
|
|
-- Estado
|
|
status VARCHAR(50) NOT NULL DEFAULT 'active', -- 'active', 'past_due', 'canceled', 'unpaid', 'trialing'
|
|
|
|
-- Fechas del ciclo
|
|
current_period_start TIMESTAMP WITH TIME ZONE NOT NULL,
|
|
current_period_end TIMESTAMP WITH TIME ZONE NOT NULL,
|
|
|
|
-- Trial
|
|
trial_start TIMESTAMP WITH TIME ZONE,
|
|
trial_end TIMESTAMP WITH TIME ZONE,
|
|
|
|
-- Cancelación
|
|
cancel_at_period_end BOOLEAN DEFAULT false,
|
|
canceled_at TIMESTAMP WITH TIME ZONE,
|
|
cancellation_reason TEXT,
|
|
|
|
-- Metadata
|
|
metadata JSONB,
|
|
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
|
|
|
|
-- Constraints
|
|
CONSTRAINT chk_subscription_status CHECK (status IN ('active', 'past_due', 'canceled', 'unpaid', 'trialing')),
|
|
CONSTRAINT chk_plan_interval CHECK (plan_interval IN ('month', 'year'))
|
|
);
|
|
|
|
-- Índices
|
|
CREATE INDEX idx_subscriptions_user_id ON financial.subscriptions(user_id);
|
|
CREATE INDEX idx_subscriptions_customer_id ON financial.subscriptions(customer_id);
|
|
CREATE INDEX idx_subscriptions_stripe_id ON financial.subscriptions(stripe_subscription_id);
|
|
CREATE INDEX idx_subscriptions_status ON financial.subscriptions(status);
|
|
CREATE INDEX idx_subscriptions_current_period_end ON financial.subscriptions(current_period_end);
|
|
|
|
-- Trigger
|
|
CREATE TRIGGER update_subscriptions_updated_at BEFORE UPDATE ON financial.subscriptions
|
|
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
|
```
|
|
|
|
### 3.5 Tabla: `invoices`
|
|
|
|
Facturas generadas para suscripciones y pagos.
|
|
|
|
```sql
|
|
CREATE TABLE financial.invoices (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
|
|
-- Relaciones
|
|
user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
|
|
customer_id UUID NOT NULL REFERENCES financial.customers(id),
|
|
subscription_id UUID REFERENCES financial.subscriptions(id),
|
|
|
|
-- Stripe
|
|
stripe_invoice_id VARCHAR(255) NOT NULL UNIQUE,
|
|
|
|
-- Número de factura
|
|
invoice_number VARCHAR(100),
|
|
|
|
-- Montos
|
|
subtotal DECIMAL(15, 2) NOT NULL,
|
|
tax DECIMAL(15, 2) DEFAULT 0.00,
|
|
discount DECIMAL(15, 2) DEFAULT 0.00,
|
|
total DECIMAL(15, 2) NOT NULL,
|
|
amount_paid DECIMAL(15, 2) DEFAULT 0.00,
|
|
amount_due DECIMAL(15, 2) NOT NULL,
|
|
|
|
currency VARCHAR(3) NOT NULL DEFAULT 'usd',
|
|
|
|
-- Estado
|
|
status VARCHAR(50) NOT NULL DEFAULT 'draft', -- 'draft', 'open', 'paid', 'void', 'uncollectible'
|
|
|
|
-- Fechas
|
|
due_date TIMESTAMP WITH TIME ZONE,
|
|
paid_at TIMESTAMP WITH TIME ZONE,
|
|
|
|
-- Items
|
|
line_items JSONB NOT NULL, -- Array de items de la factura
|
|
|
|
-- PDF
|
|
invoice_pdf_url TEXT,
|
|
hosted_invoice_url TEXT,
|
|
|
|
-- Metadata
|
|
metadata JSONB,
|
|
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
|
|
|
|
-- Constraints
|
|
CONSTRAINT chk_invoice_status CHECK (status IN ('draft', 'open', 'paid', 'void', 'uncollectible'))
|
|
);
|
|
|
|
-- Índices
|
|
CREATE INDEX idx_invoices_user_id ON financial.invoices(user_id);
|
|
CREATE INDEX idx_invoices_customer_id ON financial.invoices(customer_id);
|
|
CREATE INDEX idx_invoices_subscription_id ON financial.invoices(subscription_id);
|
|
CREATE INDEX idx_invoices_stripe_id ON financial.invoices(stripe_invoice_id);
|
|
CREATE INDEX idx_invoices_status ON financial.invoices(status);
|
|
CREATE INDEX idx_invoices_created_at ON financial.invoices(created_at DESC);
|
|
|
|
-- Trigger
|
|
CREATE TRIGGER update_invoices_updated_at BEFORE UPDATE ON financial.invoices
|
|
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
|
```
|
|
|
|
### 3.6 Tabla: `refunds`
|
|
|
|
Registro de reembolsos procesados.
|
|
|
|
```sql
|
|
CREATE TABLE financial.refunds (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
|
|
-- Relaciones
|
|
payment_id UUID NOT NULL REFERENCES financial.payments(id) ON DELETE CASCADE,
|
|
user_id UUID NOT NULL REFERENCES auth.users(id),
|
|
|
|
-- Stripe
|
|
stripe_refund_id VARCHAR(255) NOT NULL UNIQUE,
|
|
|
|
-- Monto
|
|
amount DECIMAL(15, 2) NOT NULL,
|
|
currency VARCHAR(3) NOT NULL DEFAULT 'usd',
|
|
|
|
-- Razón
|
|
reason VARCHAR(50), -- 'duplicate', 'fraudulent', 'requested_by_customer'
|
|
description TEXT,
|
|
|
|
-- Estado
|
|
status VARCHAR(50) NOT NULL DEFAULT 'pending', -- 'pending', 'succeeded', 'failed', 'canceled'
|
|
|
|
-- Metadata
|
|
metadata JSONB,
|
|
processed_at TIMESTAMP WITH TIME ZONE,
|
|
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
|
|
|
|
-- Constraints
|
|
CONSTRAINT chk_refund_amount_positive CHECK (amount > 0),
|
|
CONSTRAINT chk_refund_status CHECK (status IN ('pending', 'succeeded', 'failed', 'canceled')),
|
|
CONSTRAINT chk_refund_reason CHECK (reason IN ('duplicate', 'fraudulent', 'requested_by_customer', 'other'))
|
|
);
|
|
|
|
-- Índices
|
|
CREATE INDEX idx_refunds_payment_id ON financial.refunds(payment_id);
|
|
CREATE INDEX idx_refunds_user_id ON financial.refunds(user_id);
|
|
CREATE INDEX idx_refunds_stripe_id ON financial.refunds(stripe_refund_id);
|
|
CREATE INDEX idx_refunds_status ON financial.refunds(status);
|
|
|
|
```
|
|
|
|
### 3.7 Tabla: `wallet_transactions`
|
|
|
|
Transacciones de wallet interno (créditos, bonos).
|
|
|
|
```sql
|
|
CREATE TABLE financial.wallet_transactions (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
|
|
-- Relación
|
|
user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
|
|
|
|
-- Tipo
|
|
type VARCHAR(50) NOT NULL, -- 'credit', 'debit', 'bonus', 'refund'
|
|
|
|
-- Monto
|
|
amount DECIMAL(15, 2) NOT NULL,
|
|
currency VARCHAR(3) NOT NULL DEFAULT 'usd',
|
|
|
|
-- Balance
|
|
balance_before DECIMAL(15, 2) NOT NULL,
|
|
balance_after DECIMAL(15, 2) NOT NULL,
|
|
|
|
-- Referencia
|
|
reference_type VARCHAR(50), -- 'payment', 'refund', 'admin_credit'
|
|
reference_id UUID,
|
|
|
|
-- Descripción
|
|
description TEXT,
|
|
|
|
-- Metadata
|
|
metadata JSONB,
|
|
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
|
|
|
|
-- Constraints
|
|
CONSTRAINT chk_wallet_amount_positive CHECK (amount > 0),
|
|
CONSTRAINT chk_wallet_type CHECK (type IN ('credit', 'debit', 'bonus', 'refund'))
|
|
);
|
|
|
|
-- Índices
|
|
CREATE INDEX idx_wallet_transactions_user_id ON financial.wallet_transactions(user_id);
|
|
CREATE INDEX idx_wallet_transactions_type ON financial.wallet_transactions(type);
|
|
CREATE INDEX idx_wallet_transactions_created_at ON financial.wallet_transactions(created_at DESC);
|
|
```
|
|
|
|
---
|
|
|
|
## 4. Interfaces TypeScript
|
|
|
|
### 4.1 Types del Modelo
|
|
|
|
```typescript
|
|
// src/types/financial.types.ts
|
|
|
|
export type PaymentStatus = 'pending' | 'processing' | 'succeeded' | 'failed' | 'canceled' | 'refunded';
|
|
export type PaymentType = 'one_time' | 'subscription' | 'invoice' | 'investment_deposit';
|
|
export type SubscriptionStatus = 'active' | 'past_due' | 'canceled' | 'unpaid' | 'trialing';
|
|
export type InvoiceStatus = 'draft' | 'open' | 'paid' | 'void' | 'uncollectible';
|
|
export type RefundReason = 'duplicate' | 'fraudulent' | 'requested_by_customer' | 'other';
|
|
export type WalletTransactionType = 'credit' | 'debit' | 'bonus' | 'refund';
|
|
|
|
export interface Customer {
|
|
id: string;
|
|
user_id: string;
|
|
stripe_customer_id: string;
|
|
email: string;
|
|
name: string | null;
|
|
phone: string | null;
|
|
billing_address: Record<string, any> | null;
|
|
default_payment_method_id: string | null;
|
|
currency: string;
|
|
metadata: Record<string, any> | null;
|
|
created_at: string;
|
|
updated_at: string;
|
|
}
|
|
|
|
export interface PaymentMethod {
|
|
id: string;
|
|
customer_id: string;
|
|
stripe_payment_method_id: string;
|
|
type: string;
|
|
card_brand: string | null;
|
|
card_last4: string | null;
|
|
card_exp_month: number | null;
|
|
card_exp_year: number | null;
|
|
card_country: string | null;
|
|
bank_name: string | null;
|
|
bank_last4: string | null;
|
|
bank_account_type: string | null;
|
|
is_default: boolean;
|
|
is_active: boolean;
|
|
created_at: string;
|
|
updated_at: string;
|
|
}
|
|
|
|
export interface Payment {
|
|
id: string;
|
|
user_id: string;
|
|
customer_id: string | null;
|
|
stripe_payment_intent_id: string | null;
|
|
stripe_charge_id: string | null;
|
|
payment_type: PaymentType;
|
|
amount: number;
|
|
currency: string;
|
|
amount_refunded: number;
|
|
net_amount: number | null;
|
|
application_fee: number | null;
|
|
stripe_fee: number | null;
|
|
status: PaymentStatus;
|
|
payment_method_id: string | null;
|
|
payment_method_type: string | null;
|
|
subscription_id: string | null;
|
|
invoice_id: string | null;
|
|
description: string | null;
|
|
metadata: Record<string, any> | null;
|
|
failure_code: string | null;
|
|
failure_message: string | null;
|
|
paid_at: string | null;
|
|
created_at: string;
|
|
updated_at: string;
|
|
}
|
|
|
|
export interface Subscription {
|
|
id: string;
|
|
user_id: string;
|
|
customer_id: string;
|
|
stripe_subscription_id: string;
|
|
stripe_price_id: string;
|
|
stripe_product_id: string;
|
|
plan_name: string;
|
|
plan_interval: string;
|
|
amount: number;
|
|
currency: string;
|
|
status: SubscriptionStatus;
|
|
current_period_start: string;
|
|
current_period_end: string;
|
|
trial_start: string | null;
|
|
trial_end: string | null;
|
|
cancel_at_period_end: boolean;
|
|
canceled_at: string | null;
|
|
cancellation_reason: string | null;
|
|
metadata: Record<string, any> | null;
|
|
created_at: string;
|
|
updated_at: string;
|
|
}
|
|
|
|
export interface Invoice {
|
|
id: string;
|
|
user_id: string;
|
|
customer_id: string;
|
|
subscription_id: string | null;
|
|
stripe_invoice_id: string;
|
|
invoice_number: string | null;
|
|
subtotal: number;
|
|
tax: number;
|
|
discount: number;
|
|
total: number;
|
|
amount_paid: number;
|
|
amount_due: number;
|
|
currency: string;
|
|
status: InvoiceStatus;
|
|
due_date: string | null;
|
|
paid_at: string | null;
|
|
line_items: Record<string, any>[];
|
|
invoice_pdf_url: string | null;
|
|
hosted_invoice_url: string | null;
|
|
metadata: Record<string, any> | null;
|
|
created_at: string;
|
|
updated_at: string;
|
|
}
|
|
|
|
export interface Refund {
|
|
id: string;
|
|
payment_id: string;
|
|
user_id: string;
|
|
stripe_refund_id: string;
|
|
amount: number;
|
|
currency: string;
|
|
reason: RefundReason | null;
|
|
description: string | null;
|
|
status: PaymentStatus;
|
|
metadata: Record<string, any> | null;
|
|
processed_at: string | null;
|
|
created_at: string;
|
|
}
|
|
|
|
export interface WalletTransaction {
|
|
id: string;
|
|
user_id: string;
|
|
type: WalletTransactionType;
|
|
amount: number;
|
|
currency: string;
|
|
balance_before: number;
|
|
balance_after: number;
|
|
reference_type: string | null;
|
|
reference_id: string | null;
|
|
description: string | null;
|
|
metadata: Record<string, any> | null;
|
|
created_at: string;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 5. Views Útiles
|
|
|
|
### 5.1 Vista: Payment Summary por Usuario
|
|
|
|
```sql
|
|
CREATE VIEW financial.user_payment_summary AS
|
|
SELECT
|
|
user_id,
|
|
COUNT(*) as total_payments,
|
|
SUM(CASE WHEN status = 'succeeded' THEN 1 ELSE 0 END) as successful_payments,
|
|
SUM(CASE WHEN status = 'succeeded' THEN amount ELSE 0 END) as total_amount_paid,
|
|
MAX(created_at) as last_payment_date
|
|
FROM financial.payments
|
|
GROUP BY user_id;
|
|
```
|
|
|
|
---
|
|
|
|
## 6. Configuración
|
|
|
|
### 6.1 Variables de Entorno
|
|
|
|
```bash
|
|
# Database
|
|
DATABASE_URL=postgresql://user:password@localhost:5432/trading
|
|
|
|
# Financial Schema
|
|
FINANCIAL_DEFAULT_CURRENCY=usd
|
|
```
|
|
|
|
---
|
|
|
|
## 7. Referencias
|
|
|
|
- Stripe API Objects Documentation
|
|
- PostgreSQL JSONB Best Practices
|
|
- Payment Gateway Database Design
|