FASE 4 COMPLETADA: Pagos y Monetización con MercadoPago

Implementados 4 módulos con agent swarm:

1. MERCADOPAGO INTEGRADO
   - SDK oficial de MercadoPago
   - Crear preferencias de pago
   - Webhooks para notificaciones
   - Reembolsos y cancelaciones
   - Estados: PENDING, PROCESSING, COMPLETED, REFUNDED

2. SISTEMA DE BONOS Y PACKS
   - Pack 5, Pack 10, Pack Mensual
   - Compra online con MP
   - Uso FIFO automático
   - Control de expiración
   - Aplicación en reservas

3. SUSCRIPCIONES/MEMBRESÍAS
   - Planes: Básico, Premium, Anual VIP
   - Beneficios: descuentos, reservas gratis, prioridad
   - Cobro recurrente vía MP
   - Estados: ACTIVE, PAUSED, CANCELLED
   - Aplicación automática en reservas

4. CLASES CON PROFESORES
   - Registro de coaches con verificación
   - Tipos: Individual, Grupal, Clínica
   - Horarios y disponibilidad
   - Reservas con pago integrado
   - Sistema de reseñas

Endpoints nuevos:
- /payments/* - Pagos MercadoPago
- /bonus-packs/*, /bonuses/* - Bonos
- /subscription-plans/*, /subscriptions/* - Suscripciones
- /coaches/* - Profesores
- /classes/*, /class-enrollments/* - Clases

Variables de entorno:
- MERCADOPAGO_ACCESS_TOKEN
- MERCADOPAGO_PUBLIC_KEY
- MERCADOPAGO_WEBHOOK_SECRET

Datos de prueba:
- 3 Bonus Packs
- 3 Planes de suscripción
- 1 Coach verificado (admin)
- 3 Clases disponibles
This commit is contained in:
2026-01-31 09:02:25 +00:00
parent 6494e2b38b
commit b8a964dc2c
44 changed files with 7084 additions and 9 deletions

View File

@@ -0,0 +1,159 @@
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
async function main() {
console.log('🌱 Seeding Fase 4 - Pagos y Monetización...\n');
const admin = await prisma.user.findUnique({ where: { email: 'admin@padel.com' } });
const user = await prisma.user.findUnique({ where: { email: 'user@padel.com' } });
if (!admin || !user) {
console.log('❌ Usuarios no encontrados. Ejecuta seed.ts primero.');
return;
}
// Crear Bonus Packs
const bonusPacks = [
{ name: 'Pack 5 Clases', bookings: 5, price: 9000, validity: 90 },
{ name: 'Pack 10 Clases', bookings: 10, price: 16000, validity: 180 },
{ name: 'Pack Mensual', bookings: 30, price: 40000, validity: 30 },
];
for (const pack of bonusPacks) {
await prisma.bonusPack.upsert({
where: { id: `bonus-${pack.bookings}` },
update: {},
create: {
id: `bonus-${pack.bookings}`,
name: pack.name,
description: `${pack.bookings} reservas de 1 hora cada una`,
numberOfBookings: pack.bookings,
price: pack.price,
validityDays: pack.validity,
isActive: true,
},
});
console.log(`✅ Bonus Pack creado: ${pack.name}`);
}
// Crear planes de suscripción
const plans = [
{
name: 'Básico',
type: 'MONTHLY',
price: 15000,
benefits: { discountPercentage: 10, freeBookingsPerMonth: 2, priorityBooking: false, tournamentDiscount: 5 },
desc: '10% off en reservas, 2 reservas gratis/mes'
},
{
name: 'Premium',
type: 'MONTHLY',
price: 25000,
benefits: { discountPercentage: 20, freeBookingsPerMonth: 5, priorityBooking: true, tournamentDiscount: 10 },
desc: '20% off en reservas, 5 reservas gratis/mes, prioridad'
},
{
name: 'Anual VIP',
type: 'YEARLY',
price: 250000,
benefits: { discountPercentage: 30, freeBookingsPerMonth: 10, priorityBooking: true, tournamentDiscount: 15 },
desc: '30% off en reservas, 10 reservas gratis/mes'
},
];
for (const plan of plans) {
await prisma.subscriptionPlan.upsert({
where: { id: `plan-${plan.name.toLowerCase().replace(/ /g, '-')}` },
update: {},
create: {
id: `plan-${plan.name.toLowerCase().replace(/ /g, '-')}`,
name: plan.name,
description: plan.desc,
type: plan.type,
price: plan.price,
benefits: JSON.stringify(plan.benefits),
features: JSON.stringify([`${plan.benefits.discountPercentage}% descuento`, `${plan.benefits.freeBookingsPerMonth} reservas gratis`, plan.benefits.priorityBooking ? 'Prioridad de reserva' : 'Sin prioridad']),
isActive: true,
},
});
console.log(`✅ Plan de suscripción creado: ${plan.name}`);
}
// Registrar usuario como coach
const coach = await prisma.coach.upsert({
where: { id: 'coach-1' },
update: {},
create: {
id: 'coach-1',
userId: admin.id,
bio: 'Profesor de pádel con 10 años de experiencia. Especialista en técnica y táctica.',
specialties: JSON.stringify(['Técnica', 'Táctica', 'Volea', 'Smash']),
certifications: 'Entrenador Nacional Nivel 3',
yearsExperience: 10,
hourlyRate: 5000,
isActive: true,
isVerified: true,
},
});
console.log(`✅ Coach creado: ${coach.id}`);
// Crear disponibilidad del coach
for (let day = 1; day <= 5; day++) { // Lunes a Viernes
await prisma.coachAvailability.upsert({
where: { id: `avail-${coach.id}-${day}` },
update: {},
create: {
id: `avail-${coach.id}-${day}`,
coachId: coach.id,
dayOfWeek: day,
startTime: '09:00',
endTime: '18:00',
isAvailable: true,
},
});
}
console.log('✅ Disponibilidad del coach creada');
// Crear clases
const classes = [
{ name: 'Clase Individual', type: 'INDIVIDUAL', max: 1, price: 5000, duration: 60 },
{ name: 'Clase en Pareja', type: 'GROUP', max: 2, price: 3500, duration: 60 },
{ name: 'Clínica de Volea', type: 'CLINIC', max: 8, price: 2000, duration: 90 },
];
for (const cls of classes) {
await prisma.class.upsert({
where: { id: `class-${cls.name.toLowerCase().replace(/ /g, '-')}` },
update: {},
create: {
id: `class-${cls.name.toLowerCase().replace(/ /g, '-')}`,
coachId: coach.id,
title: cls.name,
description: `Clase especializada de ${cls.name.toLowerCase()}`,
type: cls.type,
maxStudents: cls.max,
price: cls.price,
duration: cls.duration,
isActive: true,
},
});
console.log(`✅ Clase creada: ${cls.name}`);
}
console.log('\n🎾 Fase 4 seed completado!');
console.log('\nDatos creados:');
console.log(` - 3 Bonus Packs`);
console.log(` - 3 Planes de suscripción`);
console.log(` - 1 Coach verificado`);
console.log(` - 3 Clases disponibles`);
}
main()
.catch((e) => {
console.error(e);
process.exit(1);
})
.finally(async () => {
await prisma.$disconnect();
});