erp-transportistas-backend-v2/src/modules/billing-usage/controllers/subscription-plans.controller.ts
Adrian Flores Cortes 95c6b58449 feat: Add base modules from erp-core following SIMCO-REUSE directive
Phase 0 - Base modules (100% copy):
- shared/ (errors, middleware, services, utils, types)
- auth, users, tenants (multi-tenancy)
- ai, audit, notifications, mcp, payment-terminals
- billing-usage, branches, companies, core

Phase 1 - Modules to adapt (70-95%):
- partners (for shippers/consignees)
- inventory (for refacciones)
- financial (for transport costing)

Phase 2 - Pattern modules (50-70%):
- ordenes-transporte (from sales)
- gestion-flota (from products)
- viajes (from projects)

Phase 3 - New transport-specific modules:
- tracking (GPS, events, alerts)
- tarifas-transporte (pricing, surcharges)
- combustible-gastos (fuel, tolls, expenses)
- carta-porte (CFDI complement 3.1)

Estimated token savings: ~65% (~10,675 lines)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 10:10:19 -06:00

169 lines
4.5 KiB
TypeScript

/**
* Subscription Plans Controller
*
* REST API endpoints for subscription plan management
*/
import { Router, Request, Response, NextFunction } from 'express';
import { DataSource } from 'typeorm';
import { SubscriptionPlansService } from '../services';
import { CreateSubscriptionPlanDto, UpdateSubscriptionPlanDto } from '../dto';
export class SubscriptionPlansController {
public router: Router;
private service: SubscriptionPlansService;
constructor(dataSource: DataSource) {
this.router = Router();
this.service = new SubscriptionPlansService(dataSource);
this.initializeRoutes();
}
private initializeRoutes(): void {
// Public routes
this.router.get('/public', this.getPublicPlans.bind(this));
this.router.get('/:id/compare/:otherId', this.comparePlans.bind(this));
// Protected routes (require admin)
this.router.get('/', this.getAll.bind(this));
this.router.get('/:id', this.getById.bind(this));
this.router.post('/', this.create.bind(this));
this.router.put('/:id', this.update.bind(this));
this.router.delete('/:id', this.delete.bind(this));
this.router.patch('/:id/activate', this.activate.bind(this));
this.router.patch('/:id/deactivate', this.deactivate.bind(this));
}
/**
* GET /subscription-plans/public
* Get public plans for pricing page
*/
private async getPublicPlans(req: Request, res: Response, next: NextFunction): Promise<void> {
try {
const plans = await this.service.findPublicPlans();
res.json({ data: plans });
} catch (error) {
next(error);
}
}
/**
* GET /subscription-plans
* Get all plans (admin only)
*/
private async getAll(req: Request, res: Response, next: NextFunction): Promise<void> {
try {
const { isActive, isPublic, planType } = req.query;
const plans = await this.service.findAll({
isActive: isActive !== undefined ? isActive === 'true' : undefined,
isPublic: isPublic !== undefined ? isPublic === 'true' : undefined,
planType: planType as any,
});
res.json({ data: plans });
} catch (error) {
next(error);
}
}
/**
* GET /subscription-plans/:id
* Get plan by ID
*/
private async getById(req: Request, res: Response, next: NextFunction): Promise<void> {
try {
const plan = await this.service.findById(req.params.id);
if (!plan) {
res.status(404).json({ error: 'Plan not found' });
return;
}
res.json({ data: plan });
} catch (error) {
next(error);
}
}
/**
* POST /subscription-plans
* Create new plan
*/
private async create(req: Request, res: Response, next: NextFunction): Promise<void> {
try {
const dto: CreateSubscriptionPlanDto = req.body;
const plan = await this.service.create(dto);
res.status(201).json({ data: plan });
} catch (error) {
next(error);
}
}
/**
* PUT /subscription-plans/:id
* Update plan
*/
private async update(req: Request, res: Response, next: NextFunction): Promise<void> {
try {
const dto: UpdateSubscriptionPlanDto = req.body;
const plan = await this.service.update(req.params.id, dto);
res.json({ data: plan });
} catch (error) {
next(error);
}
}
/**
* DELETE /subscription-plans/:id
* Delete plan (soft delete)
*/
private async delete(req: Request, res: Response, next: NextFunction): Promise<void> {
try {
await this.service.delete(req.params.id);
res.status(204).send();
} catch (error) {
next(error);
}
}
/**
* PATCH /subscription-plans/:id/activate
* Activate plan
*/
private async activate(req: Request, res: Response, next: NextFunction): Promise<void> {
try {
const plan = await this.service.setActive(req.params.id, true);
res.json({ data: plan });
} catch (error) {
next(error);
}
}
/**
* PATCH /subscription-plans/:id/deactivate
* Deactivate plan
*/
private async deactivate(req: Request, res: Response, next: NextFunction): Promise<void> {
try {
const plan = await this.service.setActive(req.params.id, false);
res.json({ data: plan });
} catch (error) {
next(error);
}
}
/**
* GET /subscription-plans/:id/compare/:otherId
* Compare two plans
*/
private async comparePlans(req: Request, res: Response, next: NextFunction): Promise<void> {
try {
const comparison = await this.service.comparePlans(req.params.id, req.params.otherId);
res.json({ data: comparison });
} catch (error) {
next(error);
}
}
}