add landing and subscription plans
Signed-off-by: Omar Sánchez Pizarro <omar.sanchez@pistacero.net>
This commit is contained in:
208
web/backend/routes/subscription.js
Normal file
208
web/backend/routes/subscription.js
Normal file
@@ -0,0 +1,208 @@
|
||||
import express from 'express';
|
||||
import { basicAuthMiddleware } from '../middlewares/auth.js';
|
||||
import { adminAuthMiddleware } from '../middlewares/adminAuth.js';
|
||||
import { getUser, getUserSubscription, updateUserSubscription, getWorkerCount } from '../services/mongodb.js';
|
||||
import { SUBSCRIPTION_PLANS, getPlan } from '../config/subscriptionPlans.js';
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
// Obtener planes disponibles (público)
|
||||
router.get('/plans', (req, res) => {
|
||||
try {
|
||||
const plans = Object.values(SUBSCRIPTION_PLANS).map(plan => ({
|
||||
id: plan.id,
|
||||
name: plan.name,
|
||||
description: plan.description,
|
||||
price: plan.price,
|
||||
limits: {
|
||||
maxWorkers: plan.limits.maxWorkers,
|
||||
maxNotificationsPerDay: plan.limits.maxNotificationsPerDay,
|
||||
platforms: plan.limits.platforms,
|
||||
},
|
||||
features: plan.features,
|
||||
}));
|
||||
|
||||
res.json({ plans });
|
||||
} catch (error) {
|
||||
console.error('Error obteniendo planes:', error);
|
||||
res.status(500).json({ error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
// Obtener suscripción del usuario actual
|
||||
router.get('/me', basicAuthMiddleware, async (req, res) => {
|
||||
try {
|
||||
const username = req.user.username;
|
||||
const subscription = await getUserSubscription(username);
|
||||
const user = await getUser(username);
|
||||
const workerCount = await getWorkerCount(username);
|
||||
|
||||
const planId = subscription?.planId || 'free';
|
||||
const plan = getPlan(planId);
|
||||
|
||||
res.json({
|
||||
subscription: {
|
||||
planId,
|
||||
plan: {
|
||||
id: plan.id,
|
||||
name: plan.name,
|
||||
description: plan.description,
|
||||
price: plan.price,
|
||||
limits: plan.limits,
|
||||
features: plan.features,
|
||||
},
|
||||
status: subscription?.status || 'active',
|
||||
currentPeriodStart: subscription?.currentPeriodStart || user?.createdAt,
|
||||
currentPeriodEnd: subscription?.currentPeriodEnd || null,
|
||||
cancelAtPeriodEnd: subscription?.cancelAtPeriodEnd || false,
|
||||
},
|
||||
usage: {
|
||||
workers: workerCount,
|
||||
maxWorkers: plan.limits.maxWorkers === -1 ? 'Ilimitado' : plan.limits.maxWorkers,
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error obteniendo suscripción:', error);
|
||||
res.status(500).json({ error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
// Actualizar suscripción (requiere admin o para el propio usuario en caso de cancelación)
|
||||
router.put('/me', basicAuthMiddleware, async (req, res) => {
|
||||
try {
|
||||
const username = req.user.username;
|
||||
const { planId, status, cancelAtPeriodEnd } = req.body;
|
||||
|
||||
if (!planId) {
|
||||
return res.status(400).json({ error: 'planId es requerido' });
|
||||
}
|
||||
|
||||
// Verificar que el plan existe
|
||||
const plan = getPlan(planId);
|
||||
if (!plan) {
|
||||
return res.status(400).json({ error: 'Plan no válido' });
|
||||
}
|
||||
|
||||
// Solo permitir actualizar a plan gratuito o cancelar suscripción
|
||||
// Para actualizar a planes de pago, se requiere integración con pasarela de pago
|
||||
if (planId !== 'free' && !req.user.role === 'admin') {
|
||||
return res.status(403).json({
|
||||
error: 'Para actualizar a un plan de pago, contacta con soporte o usa la pasarela de pago'
|
||||
});
|
||||
}
|
||||
|
||||
const subscription = await getUserSubscription(username);
|
||||
|
||||
// Calcular fechas del período
|
||||
const now = new Date();
|
||||
let currentPeriodStart = subscription?.currentPeriodStart || now;
|
||||
let currentPeriodEnd = null;
|
||||
|
||||
if (planId !== 'free') {
|
||||
// Para planes de pago, establecer período mensual o anual según corresponda
|
||||
// Por ahora, asumimos mensual (30 días)
|
||||
currentPeriodEnd = new Date(now);
|
||||
currentPeriodEnd.setMonth(currentPeriodEnd.getMonth() + 1);
|
||||
}
|
||||
|
||||
await updateUserSubscription(username, {
|
||||
planId,
|
||||
status: status || 'active',
|
||||
currentPeriodStart,
|
||||
currentPeriodEnd,
|
||||
cancelAtPeriodEnd: cancelAtPeriodEnd || false,
|
||||
});
|
||||
|
||||
console.log(`✅ Suscripción actualizada para ${username}: ${planId}`);
|
||||
res.json({
|
||||
success: true,
|
||||
message: 'Suscripción actualizada correctamente',
|
||||
subscription: {
|
||||
planId,
|
||||
status: status || 'active',
|
||||
currentPeriodStart,
|
||||
currentPeriodEnd,
|
||||
cancelAtPeriodEnd: cancelAtPeriodEnd || false,
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error actualizando suscripción:', error);
|
||||
res.status(500).json({ error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
// Obtener suscripción de cualquier usuario (solo admin)
|
||||
router.get('/:username', basicAuthMiddleware, adminAuthMiddleware, async (req, res) => {
|
||||
try {
|
||||
const { username } = req.params;
|
||||
const subscription = await getUserSubscription(username);
|
||||
const user = await getUser(username);
|
||||
const workerCount = await getWorkerCount(username);
|
||||
|
||||
const planId = subscription?.planId || 'free';
|
||||
const plan = getPlan(planId);
|
||||
|
||||
res.json({
|
||||
subscription: {
|
||||
planId,
|
||||
plan: {
|
||||
id: plan.id,
|
||||
name: plan.name,
|
||||
description: plan.description,
|
||||
price: plan.price,
|
||||
limits: plan.limits,
|
||||
features: plan.features,
|
||||
},
|
||||
status: subscription?.status || 'active',
|
||||
currentPeriodStart: subscription?.currentPeriodStart || user?.createdAt,
|
||||
currentPeriodEnd: subscription?.currentPeriodEnd || null,
|
||||
cancelAtPeriodEnd: subscription?.cancelAtPeriodEnd || false,
|
||||
},
|
||||
usage: {
|
||||
workers: workerCount,
|
||||
maxWorkers: plan.limits.maxWorkers === -1 ? 'Ilimitado' : plan.limits.maxWorkers,
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error obteniendo suscripción:', error);
|
||||
res.status(500).json({ error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
// Actualizar suscripción de cualquier usuario (solo admin)
|
||||
router.put('/:username', basicAuthMiddleware, adminAuthMiddleware, async (req, res) => {
|
||||
try {
|
||||
const { username } = req.params;
|
||||
const { planId, status, currentPeriodStart, currentPeriodEnd, cancelAtPeriodEnd } = req.body;
|
||||
|
||||
if (!planId) {
|
||||
return res.status(400).json({ error: 'planId es requerido' });
|
||||
}
|
||||
|
||||
// Verificar que el plan existe
|
||||
const plan = getPlan(planId);
|
||||
if (!plan) {
|
||||
return res.status(400).json({ error: 'Plan no válido' });
|
||||
}
|
||||
|
||||
await updateUserSubscription(username, {
|
||||
planId,
|
||||
status: status || 'active',
|
||||
currentPeriodStart: currentPeriodStart ? new Date(currentPeriodStart) : new Date(),
|
||||
currentPeriodEnd: currentPeriodEnd ? new Date(currentPeriodEnd) : null,
|
||||
cancelAtPeriodEnd: cancelAtPeriodEnd || false,
|
||||
});
|
||||
|
||||
console.log(`✅ Suscripción actualizada para ${username}: ${planId} por admin ${req.user.username}`);
|
||||
res.json({
|
||||
success: true,
|
||||
message: `Suscripción de ${username} actualizada correctamente`,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error actualizando suscripción:', error);
|
||||
res.status(500).json({ error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
|
||||
Reference in New Issue
Block a user