- Backend NestJS con módulos de autenticación, inventario, créditos - Frontend React con dashboard y componentes UI - Base de datos PostgreSQL con migraciones - Tests E2E configurados - Configuración de Docker y deployment Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
255 lines
5.7 KiB
Markdown
255 lines
5.7 KiB
Markdown
# INT-001: Integracion Stripe (Tarjetas)
|
|
|
|
---
|
|
id: INT-001
|
|
type: Integration
|
|
status: Pendiente
|
|
version: "1.0.0"
|
|
created_date: 2026-01-10
|
|
updated_date: 2026-01-10
|
|
simco_version: "4.0.0"
|
|
---
|
|
|
|
## Metadata
|
|
|
|
| Campo | Valor |
|
|
|-------|-------|
|
|
| **ID** | INT-001 |
|
|
| **Servicio** | Stripe |
|
|
| **Proposito** | Pagos con tarjeta de credito/debito |
|
|
| **Criticidad** | P0 |
|
|
| **Estado** | Pendiente |
|
|
|
|
---
|
|
|
|
## 1. Descripcion
|
|
|
|
Integracion con Stripe para procesar pagos con tarjeta de credito y debito, con PCI compliance delegado y soporte para guardar metodos de pago.
|
|
|
|
---
|
|
|
|
## 2. Informacion del Servicio
|
|
|
|
| Campo | Valor |
|
|
|-------|-------|
|
|
| Proveedor | Stripe |
|
|
| Documentacion | https://stripe.com/docs |
|
|
| Dashboard | https://dashboard.stripe.com |
|
|
| SDK | @stripe/stripe-js, stripe (node) |
|
|
|
|
---
|
|
|
|
## 3. Configuracion
|
|
|
|
### Variables de Entorno
|
|
|
|
```env
|
|
STRIPE_SECRET_KEY=sk_test_...
|
|
STRIPE_PUBLISHABLE_KEY=pk_test_...
|
|
STRIPE_WEBHOOK_SECRET=whsec_...
|
|
```
|
|
|
|
### Instalacion
|
|
|
|
```bash
|
|
# Backend
|
|
npm install stripe
|
|
|
|
# Mobile
|
|
npm install @stripe/stripe-react-native
|
|
```
|
|
|
|
---
|
|
|
|
## 4. Flujo de Integracion
|
|
|
|
```
|
|
┌──────────┐ ┌──────────┐ ┌──────────┐
|
|
│ Mobile │───▶│ Backend │───▶│ Stripe │
|
|
└──────────┘ └──────────┘ └──────────┘
|
|
│ │ │
|
|
│ 1. Request │ │
|
|
│ Payment │ │
|
|
│──────────────▶│ │
|
|
│ │ 2. Create │
|
|
│ │ PaymentIntent │
|
|
│ │──────────────▶│
|
|
│ │◀──────────────│
|
|
│◀──────────────│ clientSecret │
|
|
│ │ │
|
|
│ 3. Confirm │ │
|
|
│ with Card │ │
|
|
│───────────────────────────────▶
|
|
│◀───────────────────────────────
|
|
│ │ │
|
|
│ │ 4. Webhook │
|
|
│ │◀──────────────│
|
|
│ │ │
|
|
```
|
|
|
|
---
|
|
|
|
## 5. Implementacion Backend
|
|
|
|
### Crear PaymentIntent
|
|
|
|
```typescript
|
|
import Stripe from 'stripe';
|
|
|
|
@Injectable()
|
|
export class StripeService {
|
|
private stripe: Stripe;
|
|
|
|
constructor() {
|
|
this.stripe = new Stripe(process.env.STRIPE_SECRET_KEY, {
|
|
apiVersion: '2023-10-16',
|
|
});
|
|
}
|
|
|
|
async createPaymentIntent(
|
|
amount: number,
|
|
currency: string,
|
|
customerId?: string,
|
|
metadata?: Record<string, string>
|
|
) {
|
|
return this.stripe.paymentIntents.create({
|
|
amount: Math.round(amount * 100), // centavos
|
|
currency,
|
|
customer: customerId,
|
|
metadata,
|
|
automatic_payment_methods: {
|
|
enabled: true,
|
|
},
|
|
});
|
|
}
|
|
}
|
|
```
|
|
|
|
### Webhook Handler
|
|
|
|
```typescript
|
|
@Post('webhook')
|
|
async handleWebhook(
|
|
@Headers('stripe-signature') signature: string,
|
|
@Req() req: RawBodyRequest
|
|
) {
|
|
const event = this.stripe.webhooks.constructEvent(
|
|
req.rawBody,
|
|
signature,
|
|
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 };
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 6. Implementacion Mobile
|
|
|
|
### Configuracion
|
|
|
|
```typescript
|
|
// App.tsx
|
|
import { StripeProvider } from '@stripe/stripe-react-native';
|
|
|
|
<StripeProvider
|
|
publishableKey={STRIPE_PUBLISHABLE_KEY}
|
|
merchantIdentifier="merchant.com.miinventario"
|
|
>
|
|
<App />
|
|
</StripeProvider>
|
|
```
|
|
|
|
### Componente de Pago
|
|
|
|
```typescript
|
|
import { useStripe, CardField } from '@stripe/stripe-react-native';
|
|
|
|
const PaymentScreen = () => {
|
|
const { confirmPayment } = useStripe();
|
|
|
|
const handlePayment = async () => {
|
|
const { clientSecret } = await api.createPaymentIntent(amount);
|
|
|
|
const { error, paymentIntent } = await confirmPayment(clientSecret, {
|
|
paymentMethodType: 'Card',
|
|
});
|
|
|
|
if (error) {
|
|
Alert.alert('Error', error.message);
|
|
} else if (paymentIntent) {
|
|
Alert.alert('Exito', 'Pago completado');
|
|
}
|
|
};
|
|
|
|
return (
|
|
<View>
|
|
<CardField style={styles.cardField} />
|
|
<Button title="Pagar" onPress={handlePayment} />
|
|
</View>
|
|
);
|
|
};
|
|
```
|
|
|
|
---
|
|
|
|
## 7. Eventos Webhook
|
|
|
|
| Evento | Descripcion | Accion |
|
|
|--------|-------------|--------|
|
|
| payment_intent.succeeded | Pago exitoso | Acreditar creditos |
|
|
| payment_intent.payment_failed | Pago fallido | Notificar usuario |
|
|
| customer.created | Cliente creado | Guardar ID |
|
|
| payment_method.attached | Tarjeta guardada | Actualizar lista |
|
|
|
|
---
|
|
|
|
## 8. Seguridad
|
|
|
|
| Aspecto | Implementacion |
|
|
|---------|----------------|
|
|
| PCI DSS | Delegado a Stripe |
|
|
| Webhook | Verificacion de firma |
|
|
| API Keys | Variables de entorno |
|
|
| 3D Secure | Automatico con SCA |
|
|
|
|
---
|
|
|
|
## 9. Testing
|
|
|
|
### Tarjetas de Prueba
|
|
|
|
| Numero | Resultado |
|
|
|--------|-----------|
|
|
| 4242 4242 4242 4242 | Exito |
|
|
| 4000 0000 0000 9995 | Fondos insuficientes |
|
|
| 4000 0000 0000 0002 | Rechazada |
|
|
|
|
### Webhook Local
|
|
|
|
```bash
|
|
stripe listen --forward-to localhost:3142/payments/webhook
|
|
```
|
|
|
|
---
|
|
|
|
## 10. Referencias
|
|
|
|
- [Stripe Docs](https://stripe.com/docs)
|
|
- [MII-011](../01-epicas/MII-011-pagos-tarjeta.md)
|
|
- [ADR-0004](../97-adr/ADR-0004-pagos-efectivo-mexico.md)
|
|
|
|
---
|
|
|
|
**Ultima Actualizacion:** 2026-01-10
|