✅ 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:
159
backend/prisma/seed-fase4.ts
Normal file
159
backend/prisma/seed-fase4.ts
Normal 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();
|
||||
});
|
||||
Reference in New Issue
Block a user