--- id: "US-PAY-005" title: "Comprar Curso con Pago Único" type: "User Story" status: "Done" priority: "Media" epic: "OQI-005" project: "trading-platform" story_points: 3 created_date: "2025-12-05" updated_date: "2026-01-04" --- # US-PAY-005: Comprar Curso con Pago Único **Version:** 1.0.0 **Fecha:** 2025-12-05 **Estado:** ✅ Implementado **Story Points:** 3 **Prioridad:** P1 (Alta) **Épica:** [OQI-005](../_MAP.md) --- ## Historia de Usuario **Como** usuario de Trading Platform (con o sin suscripción) **Quiero** comprar acceso a un curso específico con pago único **Para** aprender sobre trading sin compromiso de suscripción mensual --- ## Criterios de Aceptación ### AC-001: Ver Precio del Curso **Dado** que estoy viendo la página de un curso **Cuando** no tengo acceso al curso **Entonces** debería ver: - Precio del curso claramente visible (ej: $29.00 USD) - Botón "Comprar Curso" - Nota: "Acceso de por vida" - Si tengo suscripción que incluye curso → Badge "Incluido en tu plan Pro" ### AC-002: Iniciar Compra **Dado** que quiero comprar un curso **Cuando** hago click en "Comprar Curso" **Entonces** debería: - Si NO estoy logueado → Ir a login/registro - Si estoy logueado → Ir a checkout del curso ### AC-003: Checkout de Curso **Dado** que estoy en checkout del curso **Cuando** veo la página **Entonces** debería ver: - Resumen del curso (nombre, descripción breve, imagen) - Precio total - Opción de pago: - Wallet (si tengo saldo) - Tarjeta de crédito/débito - Combinación (wallet + tarjeta si saldo insuficiente) - Stripe Elements para ingresar tarjeta (si elijo tarjeta) - Botón "Completar Compra" ### AC-004: Pago con Wallet **Dado** que tengo $50 USD en mi wallet **Cuando** intento comprar curso de $29 USD **Entonces** debería: - Ver opción "Pagar con Wallet" preseleccionada - Ver balance actual: "$50.00 disponible" - Ver balance después de compra: "$21.00" - Poder confirmar compra con un click - NO ver formulario de tarjeta ### AC-005: Pago con Tarjeta **Dado** que elijo pagar con tarjeta **Cuando** ingreso datos de tarjeta válidos **Entonces** debería: - Ver Stripe Elements para tarjeta - Completar datos (número, vencimiento, CVC, nombre) - Confirmar pago - Ver indicador de procesamiento - Recibir confirmación después de 2-5 segundos ### AC-006: Pago Mixto (Wallet + Tarjeta) **Dado** que tengo $20 en wallet pero curso cuesta $29 **Cuando** selecciono "Usar wallet + tarjeta" **Entonces** debería: - Ver desglose: - "Wallet: $20.00" - "Tarjeta: $9.00" - "Total: $29.00" - Ingresar solo tarjeta para $9.00 - Confirmar compra - Ver ambos débitos aplicados correctamente ### AC-007: Confirmación de Compra **Dado** que completé el pago exitosamente **Cuando** se confirma la compra **Entonces** debería: - Ver página de confirmación: "¡Compra exitosa!" - Ver mensaje: "Ya tienes acceso a {nombre del curso}" - Ver botón "Comenzar Curso" - Recibir email con: - Confirmación de compra - Link directo al curso - Factura en PDF adjunta ### AC-008: Acceso Inmediato al Curso **Dado** que compré el curso exitosamente **Cuando** navego al curso **Entonces** debería: - Tener acceso completo inmediato - Ver botón "Continuar" o "Comenzar" en lugar de "Comprar" - Poder reproducir todos los videos - Poder descargar recursos del curso - Ver progreso guardado automáticamente ### AC-009: Ya Tengo Acceso al Curso **Dado** que ya compré el curso previamente **Cuando** intento comprarlo de nuevo **Entonces** debería: - Ver mensaje: "Ya tienes acceso a este curso" - Ver botón "Ir al Curso" en lugar de "Comprar" - NO permitir compra duplicada ### AC-010: Curso Incluido en Suscripción **Dado** que tengo suscripción Pro que incluye todos los cursos **Cuando** veo un curso **Entonces** debería: - Ver badge: "Incluido en tu plan Pro" - NO ver precio ni botón de compra - Ver botón "Comenzar Curso" - Tener acceso inmediato ### AC-011: Error de Pago **Dado** que mi pago falla (tarjeta rechazada) **Cuando** intento completar la compra **Entonces** debería: - Ver mensaje de error específico - Permanecer en checkout - Poder reintentar con otra tarjeta - NO tener acceso al curso - NO tener registro de compra en historial --- ## Mockup ``` ┌─────────────────────────────────────────────────────────────┐ │ │ │ Comprar: Trading Básico 101 │ │ │ ├─────────────────────────────────────────────────────────────┤ │ │ │ ┌────────────────┐ Trading Básico 101 │ │ │ │ Aprende los fundamentos del trading │ │ │ [Curso IMG] │ │ │ │ │ 4.8 ⭐ (234 reviews) │ │ └────────────────┘ 12 módulos • 8 horas │ │ │ │ ─────────────────────────────────────────────────────── │ │ │ │ 💰 Precio: $29.00 USD │ │ ✅ Acceso de por vida │ │ ✅ Certificado de finalización │ │ │ │ ─────────────────────────────────────────────────────── │ │ │ │ Método de Pago: │ │ │ │ ○ Wallet ($50.00 disponible) │ │ Balance después: $21.00 │ │ │ │ ● Tarjeta de Crédito/Débito │ │ │ │ ┌─────────────────────────────────────────────────┐ │ │ │ Número de tarjeta │ │ │ │ ┌─────────────────────────────────────────┐ │ │ │ │ │ 4242 4242 4242 4242 [Visa] │ │ │ │ │ └─────────────────────────────────────────┘ │ │ │ │ │ │ │ │ ┌──────────────┐ ┌──────────────┐ │ │ │ │ │ 12 / 25 │ │ 123 │ │ │ │ │ └──────────────┘ └──────────────┘ │ │ │ │ │ │ │ │ ┌─────────────────────────────────────────┐ │ │ │ │ │ Juan Pérez │ │ │ │ │ └─────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────┘ │ │ │ │ ○ Wallet + Tarjeta ($20 wallet + $9 tarjeta) │ │ │ │ ─────────────────────────────────────────────────────── │ │ │ │ Total a pagar: $29.00 USD │ │ │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ Completar Compra - $29.00 │ │ │ └─────────────────────────────────────────────────────┘ │ │ │ │ 🔒 Pago seguro con Stripe │ │ 📧 Recibirás factura por email │ │ │ └─────────────────────────────────────────────────────────────┘ ``` --- ## Flujo de Compra (Gherkin) ```gherkin Feature: Comprar Curso con Pago Único Scenario: Compra exitosa con tarjeta Given que soy usuario logueado "juan@example.com" And estoy viendo el curso "Trading Básico 101" que cuesta $29 USD And NO tengo acceso al curso When hago click en "Comprar Curso" Then debería ver página de checkout del curso When selecciono "Tarjeta de crédito/débito" And ingreso tarjeta "4242 4242 4242 4242" And completo datos de pago And hago click en "Completar Compra" Then debería ver indicador de procesamiento And después de 3 segundos debería ver "¡Compra exitosa!" And debería ver botón "Comenzar Curso" And debería recibir email con factura And debería tener acceso completo al curso And mi historial debería mostrar pago de $29 USD Scenario: Compra con wallet Given que tengo $50 en mi wallet And estoy en checkout de curso de $29 USD When selecciono "Pagar con Wallet" And hago click en "Completar Compra" Then la compra se completa instantáneamente And mi wallet debería tener $21.00 And debería ver "¡Compra exitosa!" Scenario: Intento comprar curso que ya tengo Given que ya compré el curso "Trading Básico 101" When intento acceder a checkout del mismo curso Then debería ver mensaje "Ya tienes acceso a este curso" And debería ver botón "Ir al Curso" And NO debería ver formulario de pago Scenario: Curso incluido en mi suscripción Given que tengo suscripción "Pro" And el plan Pro incluye todos los cursos When veo la página del curso "Trading Básico 101" Then debería ver badge "Incluido en tu plan Pro" And NO debería ver precio ni botón "Comprar" And debería ver botón "Comenzar Curso" ``` --- ## Notas Técnicas ### Frontend - Componente: `apps/frontend/src/pages/CourseCheckout.tsx` - Props: `courseId`, `price`, `courseName` - Integrar Stripe Elements (CardElement) - Verificar balance de wallet - Mostrar opciones de pago según disponibilidad ### Backend - Endpoint: `POST /api/v1/payments/create-payment-intent` - Request: ```json { "amount": 2900, "currency": "usd", "type": "course_purchase", "courseId": "uuid-curso", "description": "Trading Básico 101", "paymentMethod": "card" | "wallet" | "mixed" } ``` - Response: ```json { "clientSecret": "pi_xxx_secret_yyy", "paymentIntentId": "pi_xxx", "amount": 2900, "currency": "usd" } ``` ### Webhook Processing Cuando `payment_intent.succeeded`: 1. Verificar `metadata.type === 'course_purchase'` 2. Obtener `metadata.courseId` y `metadata.userId` 3. Otorgar acceso: `user_courses.create({ userId, courseId, purchasedAt })` 4. Actualizar payment status 5. Generar factura PDF 6. Enviar email de confirmación ### Database **Tablas afectadas:** ```sql -- Registro de pago billing.payments ( id, userId, type='course_purchase', status='succeeded', amount=29.00, courseId ) -- Acceso al curso education.user_courses ( id, userId, courseId, access_type='purchased', purchasedAt, expiresAt=null ) ``` ### Email Template **Subject:** Tu compra de "Trading Básico 101" ``` Hola Juan, ¡Gracias por tu compra! 🎉 Ya tienes acceso completo al curso: 📚 Trading Básico 101 [Comenzar Curso] Tu factura está adjunta a este email. Detalles de la compra: - Curso: Trading Básico 101 - Precio: $29.00 USD - Fecha: 05/12/2025 - Factura: INV-2025-000042 ¿Necesitas ayuda? Escríbenos a support@trading.com ¡Feliz aprendizaje! El equipo de Trading Platform ``` --- ## Dependencias - [US-PAY-006: Agregar Método de Pago](US-PAY-006-agregar-metodo-pago.md) - Módulo de educación (cursos) - Sistema de wallet (RF-PAY-003) --- ## Requerimientos Relacionados - [RF-PAY-002: Checkout con Stripe Elements](../requerimientos/RF-PAY-002-checkout.md) - [RF-PAY-003: Sistema de Wallet](../requerimientos/RF-PAY-003-wallet.md) - [RF-PAY-004: Sistema de Facturación](../requerimientos/RF-PAY-004-facturacion.md) --- ## Tareas Técnicas ### Frontend - [ ] Página `CourseCheckout.tsx` - [ ] Selector de método de pago (wallet/card/mixed) - [ ] Integración Stripe Elements - [ ] Cálculo dinámico de pago mixto - [ ] Página de confirmación - [ ] Manejo de errores ### Backend - [ ] Endpoint `POST /payments/create-payment-intent` - [ ] Validar que usuario NO tenga acceso ya - [ ] Validar balance de wallet si aplica - [ ] Crear PaymentIntent con metadata correcta - [ ] Webhook: Otorgar acceso al curso - [ ] Generar factura PDF - [ ] Enviar email de confirmación ### Testing - [ ] Test: Compra con tarjeta exitosa - [ ] Test: Compra con wallet exitosa - [ ] Test: Compra mixta wallet+tarjeta exitosa - [ ] Test: No permite comprar curso que ya tiene - [ ] Test: No permite comprar si incluido en suscripción - [ ] Test: Acceso se otorga inmediatamente - [ ] Test: Factura se genera correctamente