miinventario-v2/docs/01-epicas/MII-011-pagos-tarjeta.md
rckrdmrd c24f889f70
Some checks failed
Build / Build Backend (push) Has been cancelled
Build / Build Mobile (TypeScript Check) (push) Has been cancelled
Lint / Lint Backend (push) Has been cancelled
Lint / Lint Mobile (push) Has been cancelled
Test / Backend E2E Tests (push) Has been cancelled
Test / Mobile Unit Tests (push) Has been cancelled
Build / Build Docker Image (push) Has been cancelled
[MIINVENTARIO] feat: Add exports, reports, integrations modules and CI/CD pipeline
- Add exports module with PDF/CSV/Excel generation
- Add reports module for inventory analytics
- Add POS integrations module
- Add database migrations for exports, movements and integrations
- Add GitHub Actions CI/CD workflow with Docker support
- Add mobile export and reports screens with tests
- Update epic documentation with traceability
- Add deployment and security guides

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 06:06:34 -06:00

347 lines
9.5 KiB
Markdown

# MII-011: Pagos con Tarjeta
---
id: MII-011
type: Epic
status: Completado
priority: P0
phase: 3
story_points: 8
created_date: 2026-01-10
updated_date: 2026-01-13
simco_version: "4.0.0"
---
## Metadata
| Campo | Valor |
|-------|-------|
| **ID** | MII-011 |
| **Nombre** | Pagos con Tarjeta |
| **Fase** | 3 - Monetizacion |
| **Prioridad** | P0 |
| **Story Points** | 8 |
| **Estado** | Completado |
---
## 1. Descripcion
Implementar pagos con tarjeta de credito/debito usando Stripe, con PCI compliance delegado y experiencia de pago fluida.
### Objetivo
Permitir a los usuarios comprar creditos instantaneamente con tarjeta de manera segura.
---
## 2. Requerimientos Relacionados
| RF | Descripcion | Prioridad |
|----|-------------|-----------|
| FR-100 | Pago inmediato con tarjeta, PCI delegado (Stripe) | P0 |
| FR-103 | Confirmacion de pago via webhooks | P0 |
| FR-104 | Reconciliacion (CREATED/PENDING/PAID/EXPIRED/CANCELED) | P0 |
---
## 3. Criterios de Aceptacion
### AC-001: Pago con Tarjeta
```gherkin
DADO que seleccione un paquete
CUANDO ingreso mis datos de tarjeta
ENTONCES el pago se procesa inmediatamente
Y recibo confirmacion de exito o error
Y mis creditos se acreditan al instante
```
### AC-002: Formulario Seguro
```gherkin
DADO que estoy en el checkout
CUANDO ingreso datos de tarjeta
ENTONCES uso el componente Stripe Elements
Y los datos nunca tocan mi servidor
Y veo indicadores de seguridad
```
### AC-003: Tarjeta Guardada
```gherkin
DADO que pague con una tarjeta
CUANDO hago otra compra
ENTONCES puedo usar la tarjeta guardada
Y solo ingreso CVV
O puedo agregar otra tarjeta
```
### AC-004: Error de Pago
```gherkin
DADO que mi pago falla
CUANDO veo el error
ENTONCES el mensaje es claro (fondos, tarjeta invalida, etc)
Y puedo intentar de nuevo
Y no se cobran creditos
```
### AC-005: Webhook de Confirmacion
```gherkin
DADO que Stripe confirma el pago
CUANDO recibo el webhook
ENTONCES actualizo el estado de la orden
Y acredito los creditos
Y envio confirmacion al usuario
```
---
## 4. Tareas Tecnicas
| ID | Tarea | Estimacion | Estado |
|----|-------|------------|--------|
| T-001 | Configurar Stripe SDK backend | 1 SP | Completado |
| T-002 | Crear endpoints de pago | 2 SP | Completado |
| T-003 | Implementar webhook handler | 2 SP | Completado |
| T-004 | Integrar Stripe Elements en mobile | 2 SP | Completado |
| T-005 | Implementar guardado de tarjetas | 1 SP | Completado |
---
## 5. Modelo de Datos
### Tabla: payment_orders
```sql
CREATE TABLE payment_orders (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES users(id),
package_id UUID REFERENCES packages(id),
amount_mxn DECIMAL(10,2) NOT NULL,
credits_amount DECIMAL(12,4) NOT NULL,
payment_method VARCHAR(20), -- 'CARD', 'OXXO', 'SEVEN_ELEVEN'
status VARCHAR(20) DEFAULT 'CREATED',
stripe_payment_intent_id VARCHAR(100),
stripe_customer_id VARCHAR(100),
paid_at TIMESTAMP,
expires_at TIMESTAMP,
metadata JSONB,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
-- Status: CREATED, PENDING, PAID, FAILED, EXPIRED, CANCELED, REFUNDED
```
### Tabla: payment_methods
```sql
CREATE TABLE payment_methods (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES users(id),
type VARCHAR(20), -- 'CARD'
stripe_payment_method_id VARCHAR(100),
last_four VARCHAR(4),
brand VARCHAR(20),
exp_month INT,
exp_year INT,
is_default BOOLEAN DEFAULT false,
created_at TIMESTAMP DEFAULT NOW()
);
```
---
## 6. Flujo de Pago
```
┌─────────────────────────────────────────────────────────────────┐
│ FLUJO DE PAGO CON TARJETA │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Seleccionar │→│ Crear │→│ Pagar │→│ Confirmar│ │
│ │ Paquete │ │ Orden │ │ (Stripe) │ │(Webhook) │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ │ │ │ │ │
│ │ │ │ │ │
│ ▼ ▼ ▼ ▼ │
│ Mostrar CREATED PENDING PAID │
│ precios en DB PaymentIntent Acreditar │
│ creditos │
│ │
└─────────────────────────────────────────────────────────────────┘
```
---
## 7. Endpoints API
| Metodo | Endpoint | Descripcion | Auth |
|--------|----------|-------------|------|
| POST | /payments/card/intent | Crear PaymentIntent | JWT |
| POST | /payments/card/confirm | Confirmar pago | JWT |
| GET | /payments/methods | Listar tarjetas guardadas | JWT |
| POST | /payments/methods | Agregar tarjeta | JWT |
| DELETE | /payments/methods/:id | Eliminar tarjeta | JWT |
| POST | /payments/webhook/stripe | Webhook Stripe | Stripe Sig |
---
## 8. Integracion Stripe
### Backend - Crear PaymentIntent
```typescript
async createCardPayment(userId: string, packageId: string) {
const pkg = await this.packagesService.findOne(packageId);
const user = await this.usersService.findOne(userId);
// Crear o obtener Stripe Customer
let customerId = user.stripeCustomerId;
if (!customerId) {
const customer = await this.stripe.customers.create({
email: user.email,
phone: user.phone,
metadata: { userId }
});
customerId = customer.id;
await this.usersService.update(userId, { stripeCustomerId: customerId });
}
// Crear orden
const order = await this.ordersService.create({
userId,
packageId,
amountMxn: pkg.priceMxn,
creditsAmount: pkg.currentCredits,
paymentMethod: 'CARD',
status: 'CREATED'
});
// Crear PaymentIntent
const paymentIntent = await this.stripe.paymentIntents.create({
amount: Math.round(pkg.priceMxn * 100), // centavos
currency: 'mxn',
customer: customerId,
metadata: {
orderId: order.id,
userId,
packageId
}
});
await this.ordersService.update(order.id, {
stripePaymentIntentId: paymentIntent.id,
stripeCustomerId: customerId,
status: 'PENDING'
});
return {
orderId: order.id,
clientSecret: paymentIntent.client_secret
};
}
```
### Webhook Handler
```typescript
@Post('webhook/stripe')
async handleStripeWebhook(@Req() req: RawBodyRequest) {
const sig = req.headers['stripe-signature'];
const event = this.stripe.webhooks.constructEvent(
req.rawBody,
sig,
process.env.STRIPE_WEBHOOK_SECRET
);
switch (event.type) {
case 'payment_intent.succeeded':
await this.handlePaymentSuccess(event.data.object);
break;
case 'payment_intent.payment_failed':
await this.handlePaymentFailed(event.data.object);
break;
}
return { received: true };
}
async handlePaymentSuccess(paymentIntent: Stripe.PaymentIntent) {
const orderId = paymentIntent.metadata.orderId;
const order = await this.ordersService.findOne(orderId);
// Actualizar orden
await this.ordersService.update(orderId, {
status: 'PAID',
paidAt: new Date()
});
// Acreditar creditos
await this.creditsService.addCredits(
order.userId,
order.creditsAmount,
'PURCHASE',
orderId
);
// Notificar usuario
await this.notificationsService.send(order.userId, {
title: 'Pago exitoso',
body: `Se acreditaron ${order.creditsAmount} creditos a tu cuenta`
});
}
```
---
## 9. Pantallas Mobile
| Pantalla | Componentes |
|----------|-------------|
| **CheckoutScreen** | Resumen, Stripe Elements, confirmar |
| **SavedCardsScreen** | Lista tarjetas, agregar nueva |
| **PaymentSuccessScreen** | Confirmacion, creditos, continuar |
| **PaymentErrorScreen** | Error, reintentar, soporte |
---
## 10. Dependencias
### Entrada (Requiere)
- MII-009: Wallet y Creditos
- MII-010: Paquetes de Recarga
### Salida (Bloquea)
- Ninguna directa
---
## 11. Seguridad
| Aspecto | Implementacion |
|---------|----------------|
| PCI DSS | Delegado a Stripe |
| Datos tarjeta | Nunca tocan nuestro servidor |
| Webhooks | Verificacion de firma Stripe |
| Idempotencia | Payment Intent ID unico |
---
## 12. Riesgos
| Riesgo | Probabilidad | Impacto | Mitigacion |
|--------|--------------|---------|------------|
| Fraude | Media | Alto | Stripe Radar, 3D Secure |
| Webhook perdido | Baja | Alto | Retry, reconciliacion |
| Doble cobro | Baja | Alto | Idempotencia, locks |
---
## 13. Referencias
- [REQUERIMIENTOS-FUNCIONALES.md](../00-vision-general/REQUERIMIENTOS-FUNCIONALES.md) - Seccion 5.11
- [INT-001](../02-integraciones/INT-001-stripe.md) - Integracion Stripe
- [ADR-0004](../97-adr/ADR-0004-pagos-efectivo-mexico.md) - Estrategia de pagos
---
**Ultima Actualizacion:** 2026-01-10