93 lines
3.8 KiB
TypeScript
93 lines
3.8 KiB
TypeScript
import type { Request, Response, NextFunction } from 'express';
|
|
import { z } from 'zod';
|
|
import * as planService from '../services/plan-catalogo.service.js';
|
|
import { prisma } from '../config/database.js';
|
|
import { invalidateDespachoPlanCache } from '../services/plan-catalogo.service.js';
|
|
import { canEditPrices } from '../utils/platform-admin.js';
|
|
import { AppError } from '../middlewares/error.middleware.js';
|
|
|
|
export async function getPlans(req: Request, res: Response, next: NextFunction) {
|
|
try {
|
|
const vertical = req.query.vertical as string | undefined;
|
|
const plans = await planService.listPlans(vertical);
|
|
return res.json({ data: plans });
|
|
} catch (err) { return next(err); }
|
|
}
|
|
|
|
export async function getAddons(req: Request, res: Response, next: NextFunction) {
|
|
try {
|
|
const vertical = req.query.vertical as string | undefined;
|
|
const addons = await planService.listAddons(vertical);
|
|
return res.json({ data: addons });
|
|
} catch (err) { return next(err); }
|
|
}
|
|
|
|
export async function getPlan(req: Request, res: Response, next: NextFunction) {
|
|
try {
|
|
const plan = await planService.getPlanByCodename(String(req.params.codename));
|
|
if (!plan) return res.status(404).json({ message: 'Plan no encontrado' });
|
|
return res.json(plan);
|
|
} catch (err) { return next(err); }
|
|
}
|
|
|
|
// ============================================================================
|
|
// Catálogo despacho — limits + precios editables por admin global
|
|
// ============================================================================
|
|
|
|
/** GET /api/planes/despacho — devuelve los 6 planes con limits + precios. */
|
|
export async function listDespachoCatalogo(_req: Request, res: Response, next: NextFunction) {
|
|
try {
|
|
const plans = await planService.getAllDespachoPlanLimits();
|
|
return res.json({ data: plans });
|
|
} catch (err) { return next(err); }
|
|
}
|
|
|
|
const updateSchema = z.object({
|
|
nombre: z.string().min(1).max(50).optional(),
|
|
monthly: z.number().nullable().optional(),
|
|
firstYear: z.number().nullable().optional(),
|
|
renewal: z.number().nullable().optional(),
|
|
permiteMonthly: z.boolean().optional(),
|
|
maxRfcs: z.number().int().optional(),
|
|
maxUsers: z.number().int().optional(),
|
|
timbresIncluidosMes: z.number().int().nonnegative().optional(),
|
|
dbMode: z.enum(['BYO', 'MANAGED']).optional(),
|
|
permiteServidorBackup: z.boolean().optional(),
|
|
permiteSatIncremental: z.boolean().optional(),
|
|
});
|
|
|
|
/** PATCH /api/planes/despacho/:plan — actualiza precios/limits. Solo admin con canEditPrices. */
|
|
export async function updateDespachoCatalogo(req: Request, res: Response, next: NextFunction) {
|
|
try {
|
|
if (!req.user || !(await canEditPrices(req.user.userId))) {
|
|
throw new AppError(403, 'Solo admin global puede editar el catálogo');
|
|
}
|
|
const plan = String(req.params.plan);
|
|
const data = updateSchema.parse(req.body);
|
|
|
|
const existing = await prisma.despachoPlanPrice.findUnique({ where: { plan } });
|
|
if (!existing) throw new AppError(404, `Plan '${plan}' no encontrado`);
|
|
|
|
const updated = await prisma.despachoPlanPrice.update({ where: { plan }, data });
|
|
invalidateDespachoPlanCache();
|
|
|
|
return res.json({
|
|
plan: updated.plan,
|
|
nombre: updated.nombre,
|
|
monthly: updated.monthly !== null ? Number(updated.monthly) : null,
|
|
firstYear: updated.firstYear !== null ? Number(updated.firstYear) : null,
|
|
renewal: updated.renewal !== null ? Number(updated.renewal) : null,
|
|
permiteMonthly: updated.permiteMonthly,
|
|
maxRfcs: updated.maxRfcs,
|
|
maxUsers: updated.maxUsers,
|
|
timbresIncluidosMes: updated.timbresIncluidosMes,
|
|
dbMode: updated.dbMode,
|
|
permiteServidorBackup: updated.permiteServidorBackup,
|
|
permiteSatIncremental: updated.permiteSatIncremental,
|
|
});
|
|
} catch (err) {
|
|
if (err instanceof z.ZodError) return next(new AppError(400, err.errors[0].message));
|
|
return next(err);
|
|
}
|
|
}
|