erp-construccion-backend-v2/src/modules/assets/controllers/work-order.controller.ts
Adrian Flores Cortes f14829d2ce [MAE-015] fix: Fix TypeScript errors in assets module
- Fix controllers to use Promise<void> return types
- Replace 'return res.status()' with 'res.status(); return;'
- Add NextFunction parameter to handlers
- Fix enum-style references with string literals
- Replace 'deletedAt: null' with 'IsNull()' for TypeORM
- Remove unused parameters and imports
- Fix grouped object initialization in getByStatus
- Remove non-existent 'updatedBy' property from WorkOrderPart

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

430 lines
12 KiB
TypeScript

/**
* WorkOrderController - Controlador de Órdenes de Trabajo
*
* Endpoints para gestión de órdenes de trabajo de mantenimiento.
*
* @module Assets (MAE-015)
*/
import { Router, Request, Response, NextFunction } from 'express';
import { DataSource } from 'typeorm';
import { WorkOrderService } from '../services';
export function createWorkOrderController(dataSource: DataSource): Router {
const router = Router();
const service = new WorkOrderService(dataSource);
// ==================== CRUD DE ÓRDENES ====================
/**
* GET /
* Lista órdenes de trabajo con filtros y paginación
*/
router.get('/', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
try {
const tenantId = req.headers['x-tenant-id'] as string;
const filters = {
assetId: req.query.assetId as string,
status: req.query.status as any,
priority: req.query.priority as any,
maintenanceType: req.query.maintenanceType as any,
technicianId: req.query.technicianId as string,
projectId: req.query.projectId as string,
dateFrom: req.query.dateFrom ? new Date(req.query.dateFrom as string) : undefined,
dateTo: req.query.dateTo ? new Date(req.query.dateTo as string) : undefined,
search: req.query.search as string,
};
const pagination = {
page: parseInt(req.query.page as string) || 1,
limit: parseInt(req.query.limit as string) || 20,
};
const result = await service.findAll(tenantId, filters, pagination);
res.json(result);
} catch (error) {
next(error);
}
});
/**
* GET /statistics
* Obtiene estadísticas de órdenes de trabajo
*/
router.get('/statistics', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
try {
const tenantId = req.headers['x-tenant-id'] as string;
const stats = await service.getStatistics(tenantId);
res.json(stats);
} catch (error) {
next(error);
}
});
/**
* GET /by-status
* Obtiene órdenes agrupadas por estado
*/
router.get('/by-status', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
try {
const tenantId = req.headers['x-tenant-id'] as string;
const grouped = await service.getByStatus(tenantId);
res.json(grouped);
} catch (error) {
next(error);
}
});
/**
* GET /by-number/:orderNumber
* Obtiene una orden por número
*/
router.get('/by-number/:orderNumber', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
try {
const tenantId = req.headers['x-tenant-id'] as string;
const workOrder = await service.findByNumber(tenantId, req.params.orderNumber);
if (!workOrder) {
res.status(404).json({ error: 'Orden de trabajo no encontrada' });
return;
}
res.json(workOrder);
} catch (error) {
next(error);
}
});
/**
* GET /overdue
* Lista órdenes vencidas
*/
router.get('/overdue', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
try {
const tenantId = req.headers['x-tenant-id'] as string;
const orders = await service.getOverdue(tenantId);
res.json(orders);
} catch (error) {
next(error);
}
});
/**
* GET /:id
* Obtiene una orden de trabajo por ID
*/
router.get('/:id', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
try {
const tenantId = req.headers['x-tenant-id'] as string;
const workOrder = await service.findById(tenantId, req.params.id);
if (!workOrder) {
res.status(404).json({ error: 'Orden de trabajo no encontrada' });
return;
}
res.json(workOrder);
} catch (error) {
next(error);
}
});
/**
* POST /
* Crea una nueva orden de trabajo
*/
router.post('/', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
try {
const tenantId = req.headers['x-tenant-id'] as string;
const userId = (req as any).user?.id;
const workOrder = await service.create(tenantId, req.body, userId);
res.status(201).json(workOrder);
} catch (error) {
next(error);
}
});
/**
* PUT /:id
* Actualiza una orden de trabajo
*/
router.put('/:id', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
try {
const tenantId = req.headers['x-tenant-id'] as string;
const userId = (req as any).user?.id;
const workOrder = await service.update(tenantId, req.params.id, req.body, userId);
if (!workOrder) {
res.status(404).json({ error: 'Orden de trabajo no encontrada' });
return;
}
res.json(workOrder);
} catch (error) {
next(error);
}
});
/**
* DELETE /:id
* Elimina una orden de trabajo (soft delete)
*/
router.delete('/:id', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
try {
const tenantId = req.headers['x-tenant-id'] as string;
const userId = (req as any).user?.id;
const deleted = await service.delete(tenantId, req.params.id, userId);
if (!deleted) {
res.status(404).json({ error: 'Orden de trabajo no encontrada' });
return;
}
res.status(204).send();
} catch (error) {
next(error);
}
});
// ==================== WORKFLOW ====================
/**
* POST /:id/start
* Inicia una orden de trabajo
*/
router.post('/:id/start', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
try {
const tenantId = req.headers['x-tenant-id'] as string;
const userId = (req as any).user?.id;
const workOrder = await service.start(tenantId, req.params.id, userId);
if (!workOrder) {
res.status(404).json({ error: 'Orden de trabajo no encontrada' });
return;
}
res.json(workOrder);
} catch (error) {
next(error);
}
});
/**
* POST /:id/hold
* Pone en espera una orden de trabajo
*/
router.post('/:id/hold', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
try {
const tenantId = req.headers['x-tenant-id'] as string;
const userId = (req as any).user?.id;
const { reason } = req.body;
const workOrder = await service.hold(tenantId, req.params.id, reason, userId);
if (!workOrder) {
res.status(404).json({ error: 'Orden de trabajo no encontrada' });
return;
}
res.json(workOrder);
} catch (error) {
next(error);
}
});
/**
* POST /:id/resume
* Reanuda una orden de trabajo en espera
*/
router.post('/:id/resume', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
try {
const tenantId = req.headers['x-tenant-id'] as string;
const userId = (req as any).user?.id;
const workOrder = await service.resume(tenantId, req.params.id, userId);
if (!workOrder) {
res.status(404).json({ error: 'Orden de trabajo no encontrada' });
return;
}
res.json(workOrder);
} catch (error) {
next(error);
}
});
/**
* POST /:id/complete
* Completa una orden de trabajo
*/
router.post('/:id/complete', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
try {
const tenantId = req.headers['x-tenant-id'] as string;
const userId = (req as any).user?.id;
const workOrder = await service.complete(tenantId, req.params.id, req.body, userId);
if (!workOrder) {
res.status(404).json({ error: 'Orden de trabajo no encontrada' });
return;
}
res.json(workOrder);
} catch (error) {
next(error);
}
});
/**
* POST /:id/cancel
* Cancela una orden de trabajo
*/
router.post('/:id/cancel', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
try {
const tenantId = req.headers['x-tenant-id'] as string;
const userId = (req as any).user?.id;
const { reason } = req.body;
const workOrder = await service.cancel(tenantId, req.params.id, reason, userId);
if (!workOrder) {
res.status(404).json({ error: 'Orden de trabajo no encontrada' });
return;
}
res.json(workOrder);
} catch (error) {
next(error);
}
});
// ==================== PARTES/REFACCIONES ====================
/**
* GET /:id/parts
* Lista partes usadas en una orden de trabajo
*/
router.get('/:id/parts', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
try {
const tenantId = req.headers['x-tenant-id'] as string;
const parts = await service.getParts(tenantId, req.params.id);
res.json(parts);
} catch (error) {
next(error);
}
});
/**
* POST /:id/parts
* Agrega una parte a la orden de trabajo
*/
router.post('/:id/parts', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
try {
const tenantId = req.headers['x-tenant-id'] as string;
const userId = (req as any).user?.id;
const part = await service.addPart(tenantId, req.params.id, req.body, userId);
res.status(201).json(part);
} catch (error) {
next(error);
}
});
/**
* PUT /:id/parts/:partId
* Actualiza una parte de la orden
*/
router.put('/:id/parts/:partId', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
try {
const tenantId = req.headers['x-tenant-id'] as string;
const userId = (req as any).user?.id;
const part = await service.updatePart(tenantId, req.params.partId, req.body, userId);
if (!part) {
res.status(404).json({ error: 'Parte no encontrada' });
return;
}
res.json(part);
} catch (error) {
next(error);
}
});
/**
* DELETE /:id/parts/:partId
* Elimina una parte de la orden
*/
router.delete('/:id/parts/:partId', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
try {
const tenantId = req.headers['x-tenant-id'] as string;
const userId = (req as any).user?.id;
const deleted = await service.removePart(tenantId, req.params.partId, userId);
if (!deleted) {
res.status(404).json({ error: 'Parte no encontrada' });
return;
}
res.status(204).send();
} catch (error) {
next(error);
}
});
// ==================== PLANES DE MANTENIMIENTO ====================
/**
* GET /plans
* Lista planes de mantenimiento
*/
router.get('/plans/list', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
try {
const tenantId = req.headers['x-tenant-id'] as string;
const assetId = req.query.assetId as string;
const plans = await service.getMaintenancePlans(tenantId, assetId);
res.json(plans);
} catch (error) {
next(error);
}
});
/**
* POST /plans
* Crea un plan de mantenimiento
*/
router.post('/plans', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
try {
const tenantId = req.headers['x-tenant-id'] as string;
const userId = (req as any).user?.id;
const plan = await service.createMaintenancePlan(tenantId, req.body, userId);
res.status(201).json(plan);
} catch (error) {
next(error);
}
});
/**
* POST /plans/:planId/generate
* Genera órdenes de trabajo desde un plan
*/
router.post('/plans/:planId/generate', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
try {
const tenantId = req.headers['x-tenant-id'] as string;
const userId = (req as any).user?.id;
const orders = await service.generateFromPlan(tenantId, req.params.planId, userId);
res.status(201).json(orders);
} catch (error) {
next(error);
}
});
return router;
}