feat: Add controllers for gestion-flota, ordenes-transporte, tracking and viajes modules
- Added operadores.controller.ts for operator management - Added unidades.controller.ts for fleet unit management - Added ordenes-transporte.controller.ts for transport orders - Added tracking.controller.ts for GPS tracking - Added viajes controllers directory - Updated index.ts exports for each module Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
23ee6ce90e
commit
6f0324f21a
@ -1 +1,6 @@
|
||||
/**
|
||||
* Gestion Flota Controllers
|
||||
*/
|
||||
export { ProductsController, CategoriesController } from './products.controller';
|
||||
export * from './unidades.controller';
|
||||
export * from './operadores.controller';
|
||||
|
||||
266
src/modules/gestion-flota/controllers/operadores.controller.ts
Normal file
266
src/modules/gestion-flota/controllers/operadores.controller.ts
Normal file
@ -0,0 +1,266 @@
|
||||
import { Request, Response, NextFunction, Router } from 'express';
|
||||
import { OperadoresService, CreateOperadorDto, UpdateOperadorDto } from '../services/operadores.service';
|
||||
import { TipoLicencia, EstadoOperador } from '../entities';
|
||||
|
||||
export class OperadoresController {
|
||||
public router: Router;
|
||||
|
||||
constructor(private readonly operadoresService: OperadoresService) {
|
||||
this.router = Router();
|
||||
this.initializeRoutes();
|
||||
}
|
||||
|
||||
private initializeRoutes(): void {
|
||||
// CRUD básico
|
||||
this.router.get('/', this.findAll.bind(this));
|
||||
this.router.get('/disponibles', this.getOperadoresDisponibles.bind(this));
|
||||
this.router.get('/licencia-por-vencer', this.getOperadoresLicenciaPorVencer.bind(this));
|
||||
this.router.get('/licencia-vencida', this.getOperadoresLicenciaVencida.bind(this));
|
||||
this.router.get('/:id', this.findOne.bind(this));
|
||||
this.router.get('/empleado/:numeroEmpleado', this.findByNumeroEmpleado.bind(this));
|
||||
this.router.get('/licencia/:numeroLicencia', this.findByLicencia.bind(this));
|
||||
this.router.post('/', this.create.bind(this));
|
||||
this.router.patch('/:id', this.update.bind(this));
|
||||
this.router.delete('/:id', this.delete.bind(this));
|
||||
|
||||
// Operaciones específicas
|
||||
this.router.post('/:id/estado', this.cambiarEstado.bind(this));
|
||||
}
|
||||
|
||||
private async findAll(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { search, estado, estados, tipoLicencia, sucursalId, limit, offset } = req.query;
|
||||
|
||||
const result = await this.operadoresService.findAll({
|
||||
tenantId,
|
||||
search: search as string,
|
||||
estado: estado as EstadoOperador,
|
||||
estados: estados ? (estados as string).split(',') as EstadoOperador[] : undefined,
|
||||
tipoLicencia: tipoLicencia as TipoLicencia,
|
||||
sucursalId: sucursalId as string,
|
||||
limit: limit ? parseInt(limit as string, 10) : undefined,
|
||||
offset: offset ? parseInt(offset as string, 10) : undefined,
|
||||
});
|
||||
|
||||
res.json(result);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async findOne(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { id } = req.params;
|
||||
const operador = await this.operadoresService.findOne(id, tenantId);
|
||||
|
||||
if (!operador) {
|
||||
res.status(404).json({ error: 'Operador no encontrado' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json({ data: operador });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async findByNumeroEmpleado(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { numeroEmpleado } = req.params;
|
||||
const operador = await this.operadoresService.findByNumeroEmpleado(numeroEmpleado, tenantId);
|
||||
|
||||
if (!operador) {
|
||||
res.status(404).json({ error: 'Operador no encontrado' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json({ data: operador });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async findByLicencia(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { numeroLicencia } = req.params;
|
||||
const operador = await this.operadoresService.findByLicencia(numeroLicencia, tenantId);
|
||||
|
||||
if (!operador) {
|
||||
res.status(404).json({ error: 'Operador no encontrado' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json({ data: operador });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async create(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
const userId = req.headers['x-user-id'] as string;
|
||||
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const dto: CreateOperadorDto = req.body;
|
||||
const operador = await this.operadoresService.create(tenantId, dto, userId);
|
||||
res.status(201).json({ data: operador });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async update(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
const userId = req.headers['x-user-id'] as string;
|
||||
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { id } = req.params;
|
||||
const dto: UpdateOperadorDto = req.body;
|
||||
const operador = await this.operadoresService.update(id, tenantId, dto, userId);
|
||||
|
||||
if (!operador) {
|
||||
res.status(404).json({ error: 'Operador no encontrado' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json({ data: operador });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async delete(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { id } = req.params;
|
||||
const deleted = await this.operadoresService.delete(id, tenantId);
|
||||
|
||||
if (!deleted) {
|
||||
res.status(404).json({ error: 'Operador no encontrado' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.status(204).send();
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async cambiarEstado(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
const userId = req.headers['x-user-id'] as string;
|
||||
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { id } = req.params;
|
||||
const { estado } = req.body;
|
||||
|
||||
if (!estado) {
|
||||
res.status(400).json({ error: 'Estado es requerido' });
|
||||
return;
|
||||
}
|
||||
|
||||
const operador = await this.operadoresService.cambiarEstado(id, tenantId, estado, userId);
|
||||
|
||||
if (!operador) {
|
||||
res.status(404).json({ error: 'Operador no encontrado' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json({ data: operador });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async getOperadoresDisponibles(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const operadores = await this.operadoresService.getOperadoresDisponibles(tenantId);
|
||||
res.json({ data: operadores });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async getOperadoresLicenciaPorVencer(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { dias } = req.query;
|
||||
const diasAntelacion = dias ? parseInt(dias as string, 10) : 30;
|
||||
const operadores = await this.operadoresService.getOperadoresLicenciaPorVencer(tenantId, diasAntelacion);
|
||||
res.json({ data: operadores });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async getOperadoresLicenciaVencida(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const operadores = await this.operadoresService.getOperadoresLicenciaVencida(tenantId);
|
||||
res.json({ data: operadores });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
301
src/modules/gestion-flota/controllers/unidades.controller.ts
Normal file
301
src/modules/gestion-flota/controllers/unidades.controller.ts
Normal file
@ -0,0 +1,301 @@
|
||||
import { Request, Response, NextFunction, Router } from 'express';
|
||||
import { UnidadesService, CreateUnidadDto, UpdateUnidadDto } from '../services/unidades.service';
|
||||
import { TipoUnidad, EstadoUnidad } from '../entities';
|
||||
|
||||
export class UnidadesController {
|
||||
public router: Router;
|
||||
|
||||
constructor(private readonly unidadesService: UnidadesService) {
|
||||
this.router = Router();
|
||||
this.initializeRoutes();
|
||||
}
|
||||
|
||||
private initializeRoutes(): void {
|
||||
// CRUD básico
|
||||
this.router.get('/', this.findAll.bind(this));
|
||||
this.router.get('/disponibles', this.getUnidadesDisponibles.bind(this));
|
||||
this.router.get('/seguro-por-vencer', this.getUnidadesSeguroPorVencer.bind(this));
|
||||
this.router.get('/verificacion-por-vencer', this.getUnidadesVerificacionPorVencer.bind(this));
|
||||
this.router.get('/:id', this.findOne.bind(this));
|
||||
this.router.get('/numero-economico/:numeroEconomico', this.findByNumeroEconomico.bind(this));
|
||||
this.router.get('/placas/:placas', this.findByPlacas.bind(this));
|
||||
this.router.post('/', this.create.bind(this));
|
||||
this.router.patch('/:id', this.update.bind(this));
|
||||
this.router.delete('/:id', this.delete.bind(this));
|
||||
|
||||
// Operaciones específicas
|
||||
this.router.post('/:id/estado', this.cambiarEstado.bind(this));
|
||||
this.router.post('/:id/odometro', this.actualizarOdometro.bind(this));
|
||||
}
|
||||
|
||||
private async findAll(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { search, tipo, estado, estados, sucursalId, limit, offset } = req.query;
|
||||
|
||||
const result = await this.unidadesService.findAll({
|
||||
tenantId,
|
||||
search: search as string,
|
||||
tipo: tipo as TipoUnidad,
|
||||
estado: estado as EstadoUnidad,
|
||||
estados: estados ? (estados as string).split(',') as EstadoUnidad[] : undefined,
|
||||
sucursalId: sucursalId as string,
|
||||
limit: limit ? parseInt(limit as string, 10) : undefined,
|
||||
offset: offset ? parseInt(offset as string, 10) : undefined,
|
||||
});
|
||||
|
||||
res.json(result);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async findOne(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { id } = req.params;
|
||||
const unidad = await this.unidadesService.findOne(id, tenantId);
|
||||
|
||||
if (!unidad) {
|
||||
res.status(404).json({ error: 'Unidad no encontrada' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json({ data: unidad });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async findByNumeroEconomico(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { numeroEconomico } = req.params;
|
||||
const unidad = await this.unidadesService.findByNumeroEconomico(numeroEconomico, tenantId);
|
||||
|
||||
if (!unidad) {
|
||||
res.status(404).json({ error: 'Unidad no encontrada' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json({ data: unidad });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async findByPlacas(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { placas } = req.params;
|
||||
const unidad = await this.unidadesService.findByPlacas(placas, tenantId);
|
||||
|
||||
if (!unidad) {
|
||||
res.status(404).json({ error: 'Unidad no encontrada' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json({ data: unidad });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async create(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
const userId = req.headers['x-user-id'] as string;
|
||||
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const dto: CreateUnidadDto = req.body;
|
||||
const unidad = await this.unidadesService.create(tenantId, dto, userId);
|
||||
res.status(201).json({ data: unidad });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async update(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
const userId = req.headers['x-user-id'] as string;
|
||||
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { id } = req.params;
|
||||
const dto: UpdateUnidadDto = req.body;
|
||||
const unidad = await this.unidadesService.update(id, tenantId, dto, userId);
|
||||
|
||||
if (!unidad) {
|
||||
res.status(404).json({ error: 'Unidad no encontrada' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json({ data: unidad });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async delete(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { id } = req.params;
|
||||
const deleted = await this.unidadesService.delete(id, tenantId);
|
||||
|
||||
if (!deleted) {
|
||||
res.status(404).json({ error: 'Unidad no encontrada' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.status(204).send();
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async cambiarEstado(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
const userId = req.headers['x-user-id'] as string;
|
||||
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { id } = req.params;
|
||||
const { estado } = req.body;
|
||||
|
||||
if (!estado) {
|
||||
res.status(400).json({ error: 'Estado es requerido' });
|
||||
return;
|
||||
}
|
||||
|
||||
const unidad = await this.unidadesService.cambiarEstado(id, tenantId, estado, userId);
|
||||
|
||||
if (!unidad) {
|
||||
res.status(404).json({ error: 'Unidad no encontrada' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json({ data: unidad });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async actualizarOdometro(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
const userId = req.headers['x-user-id'] as string;
|
||||
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { id } = req.params;
|
||||
const { odometro } = req.body;
|
||||
|
||||
if (odometro === undefined) {
|
||||
res.status(400).json({ error: 'Odómetro es requerido' });
|
||||
return;
|
||||
}
|
||||
|
||||
const unidad = await this.unidadesService.actualizarOdometro(id, tenantId, odometro, userId);
|
||||
|
||||
if (!unidad) {
|
||||
res.status(404).json({ error: 'Unidad no encontrada' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json({ data: unidad });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async getUnidadesDisponibles(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { tipo } = req.query;
|
||||
const unidades = await this.unidadesService.getUnidadesDisponibles(tenantId, tipo as TipoUnidad);
|
||||
res.json({ data: unidades });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async getUnidadesSeguroPorVencer(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { dias } = req.query;
|
||||
const diasAntelacion = dias ? parseInt(dias as string, 10) : 30;
|
||||
const unidades = await this.unidadesService.getUnidadesSeguroPorVencer(tenantId, diasAntelacion);
|
||||
res.json({ data: unidades });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async getUnidadesVerificacionPorVencer(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { dias } = req.query;
|
||||
const diasAntelacion = dias ? parseInt(dias as string, 10) : 30;
|
||||
const unidades = await this.unidadesService.getUnidadesVerificacionPorVencer(tenantId, diasAntelacion);
|
||||
res.json({ data: unidades });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2,6 +2,9 @@ import { Request, Response, NextFunction, Router } from 'express';
|
||||
import { SalesService } from '../services';
|
||||
import { CreateQuotationDto, UpdateQuotationDto, CreateSalesOrderDto, UpdateSalesOrderDto } from '../dto';
|
||||
|
||||
// Export transport-specific controller
|
||||
export * from './ordenes-transporte.controller';
|
||||
|
||||
export class QuotationsController {
|
||||
public router: Router;
|
||||
constructor(private readonly salesService: SalesService) {
|
||||
|
||||
@ -0,0 +1,332 @@
|
||||
import { Request, Response, NextFunction, Router } from 'express';
|
||||
import { OrdenesTransporteService, CreateOrdenTransporteDto, UpdateOrdenTransporteDto } from '../services/ordenes-transporte.service';
|
||||
import { EstadoOrdenTransporte, ModalidadServicio } from '../entities';
|
||||
|
||||
export class OrdenesTransporteController {
|
||||
public router: Router;
|
||||
|
||||
constructor(private readonly otService: OrdenesTransporteService) {
|
||||
this.router = Router();
|
||||
this.initializeRoutes();
|
||||
}
|
||||
|
||||
private initializeRoutes(): void {
|
||||
// CRUD básico
|
||||
this.router.get('/', this.findAll.bind(this));
|
||||
this.router.get('/pendientes', this.getOtsPendientes.bind(this));
|
||||
this.router.get('/programacion', this.getOtsParaProgramacion.bind(this));
|
||||
this.router.get('/cliente/:clienteId', this.getOtsCliente.bind(this));
|
||||
this.router.get('/:id', this.findOne.bind(this));
|
||||
this.router.get('/numero/:numeroOt', this.findByNumeroOt.bind(this));
|
||||
this.router.post('/', this.create.bind(this));
|
||||
this.router.patch('/:id', this.update.bind(this));
|
||||
|
||||
// Operaciones de estado
|
||||
this.router.post('/:id/estado', this.cambiarEstado.bind(this));
|
||||
this.router.post('/:id/confirmar', this.confirmar.bind(this));
|
||||
this.router.post('/:id/asignar', this.asignar.bind(this));
|
||||
this.router.post('/:id/cancelar', this.cancelar.bind(this));
|
||||
}
|
||||
|
||||
private async findAll(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const {
|
||||
search,
|
||||
estado,
|
||||
estados,
|
||||
clienteId,
|
||||
modalidad,
|
||||
fechaDesde,
|
||||
fechaHasta,
|
||||
limit,
|
||||
offset,
|
||||
} = req.query;
|
||||
|
||||
const result = await this.otService.findAll({
|
||||
tenantId,
|
||||
search: search as string,
|
||||
estado: estado as EstadoOrdenTransporte,
|
||||
estados: estados ? (estados as string).split(',') as EstadoOrdenTransporte[] : undefined,
|
||||
clienteId: clienteId as string,
|
||||
modalidad: modalidad as ModalidadServicio,
|
||||
fechaDesde: fechaDesde ? new Date(fechaDesde as string) : undefined,
|
||||
fechaHasta: fechaHasta ? new Date(fechaHasta as string) : undefined,
|
||||
limit: limit ? parseInt(limit as string, 10) : undefined,
|
||||
offset: offset ? parseInt(offset as string, 10) : undefined,
|
||||
});
|
||||
|
||||
res.json(result);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async findOne(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { id } = req.params;
|
||||
const ot = await this.otService.findOne(id, tenantId);
|
||||
|
||||
if (!ot) {
|
||||
res.status(404).json({ error: 'Orden de transporte no encontrada' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json({ data: ot });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async findByNumeroOt(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { numeroOt } = req.params;
|
||||
const ot = await this.otService.findByNumeroOt(numeroOt, tenantId);
|
||||
|
||||
if (!ot) {
|
||||
res.status(404).json({ error: 'Orden de transporte no encontrada' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json({ data: ot });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async create(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
const userId = req.headers['x-user-id'] as string;
|
||||
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const dto: CreateOrdenTransporteDto = req.body;
|
||||
const ot = await this.otService.create(tenantId, dto, userId);
|
||||
res.status(201).json({ data: ot });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async update(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
const userId = req.headers['x-user-id'] as string;
|
||||
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { id } = req.params;
|
||||
const dto: UpdateOrdenTransporteDto = req.body;
|
||||
const ot = await this.otService.update(id, tenantId, dto, userId);
|
||||
|
||||
if (!ot) {
|
||||
res.status(404).json({ error: 'Orden de transporte no encontrada' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json({ data: ot });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async cambiarEstado(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
const userId = req.headers['x-user-id'] as string;
|
||||
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { id } = req.params;
|
||||
const { estado } = req.body;
|
||||
|
||||
if (!estado) {
|
||||
res.status(400).json({ error: 'Estado es requerido' });
|
||||
return;
|
||||
}
|
||||
|
||||
const ot = await this.otService.cambiarEstado(id, tenantId, estado, userId);
|
||||
|
||||
if (!ot) {
|
||||
res.status(404).json({ error: 'Orden de transporte no encontrada' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json({ data: ot });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async confirmar(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
const userId = req.headers['x-user-id'] as string;
|
||||
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { id } = req.params;
|
||||
const ot = await this.otService.confirmar(id, tenantId, userId);
|
||||
|
||||
if (!ot) {
|
||||
res.status(404).json({ error: 'Orden de transporte no encontrada' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json({ data: ot });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async asignar(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
const userId = req.headers['x-user-id'] as string;
|
||||
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { id } = req.params;
|
||||
const { viajeId } = req.body;
|
||||
|
||||
if (!viajeId) {
|
||||
res.status(400).json({ error: 'viajeId es requerido' });
|
||||
return;
|
||||
}
|
||||
|
||||
const ot = await this.otService.asignar(id, tenantId, viajeId, userId);
|
||||
|
||||
if (!ot) {
|
||||
res.status(404).json({ error: 'Orden de transporte no encontrada' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json({ data: ot });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async cancelar(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
const userId = req.headers['x-user-id'] as string;
|
||||
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { id } = req.params;
|
||||
const { motivo } = req.body;
|
||||
|
||||
if (!motivo) {
|
||||
res.status(400).json({ error: 'Motivo de cancelación es requerido' });
|
||||
return;
|
||||
}
|
||||
|
||||
const ot = await this.otService.cancelar(id, tenantId, motivo, userId);
|
||||
|
||||
if (!ot) {
|
||||
res.status(404).json({ error: 'Orden de transporte no encontrada' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json({ data: ot });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async getOtsPendientes(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const ots = await this.otService.getOtsPendientes(tenantId);
|
||||
res.json({ data: ots });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async getOtsCliente(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { clienteId } = req.params;
|
||||
const { limit } = req.query;
|
||||
|
||||
const ots = await this.otService.getOtsCliente(
|
||||
clienteId,
|
||||
tenantId,
|
||||
limit ? parseInt(limit as string, 10) : undefined
|
||||
);
|
||||
res.json({ data: ots });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async getOtsParaProgramacion(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { fecha } = req.query;
|
||||
|
||||
if (!fecha) {
|
||||
res.status(400).json({ error: 'Fecha es requerida' });
|
||||
return;
|
||||
}
|
||||
|
||||
const ots = await this.otService.getOtsParaProgramacion(tenantId, new Date(fecha as string));
|
||||
res.json({ data: ots });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,4 @@
|
||||
/**
|
||||
* Tracking Controllers
|
||||
*/
|
||||
// TODO: Implement controllers
|
||||
// - tracking.controller.ts
|
||||
export * from './tracking.controller';
|
||||
|
||||
323
src/modules/tracking/controllers/tracking.controller.ts
Normal file
323
src/modules/tracking/controllers/tracking.controller.ts
Normal file
@ -0,0 +1,323 @@
|
||||
import { Request, Response, NextFunction, Router } from 'express';
|
||||
import { TrackingService, CreateEventoDto, CreateGeocercaDto } from '../services/tracking.service';
|
||||
import { TipoEventoTracking, TipoGeocerca } from '../entities';
|
||||
|
||||
export class TrackingController {
|
||||
public router: Router;
|
||||
|
||||
constructor(private readonly trackingService: TrackingService) {
|
||||
this.router = Router();
|
||||
this.initializeRoutes();
|
||||
}
|
||||
|
||||
private initializeRoutes(): void {
|
||||
// Eventos/Posiciones
|
||||
this.router.get('/eventos', this.findEventos.bind(this));
|
||||
this.router.get('/posiciones-actuales', this.getPosicionesActuales.bind(this));
|
||||
this.router.get('/unidad/:unidadId/ultima-posicion', this.getUltimaPosicion.bind(this));
|
||||
this.router.get('/unidad/:unidadId/historial', this.getHistorialPosiciones.bind(this));
|
||||
this.router.get('/viaje/:viajeId/ruta', this.getRutaViaje.bind(this));
|
||||
this.router.get('/viaje/:viajeId/eventos', this.getEventosViaje.bind(this));
|
||||
this.router.post('/eventos', this.registrarEvento.bind(this));
|
||||
this.router.post('/posicion', this.registrarPosicion.bind(this));
|
||||
|
||||
// Geocercas
|
||||
this.router.get('/geocercas', this.findAllGeocercas.bind(this));
|
||||
this.router.get('/geocercas/:id', this.findGeocerca.bind(this));
|
||||
this.router.post('/geocercas', this.createGeocerca.bind(this));
|
||||
this.router.patch('/geocercas/:id', this.updateGeocerca.bind(this));
|
||||
this.router.delete('/geocercas/:id', this.deleteGeocerca.bind(this));
|
||||
}
|
||||
|
||||
// ==================== Eventos/Posiciones ====================
|
||||
|
||||
private async findEventos(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { unidadId, viajeId, tipoEvento, fechaDesde, fechaHasta, limit, offset } = req.query;
|
||||
|
||||
const result = await this.trackingService.findEventos({
|
||||
tenantId,
|
||||
unidadId: unidadId as string,
|
||||
viajeId: viajeId as string,
|
||||
tipoEvento: tipoEvento as TipoEventoTracking,
|
||||
fechaDesde: fechaDesde ? new Date(fechaDesde as string) : undefined,
|
||||
fechaHasta: fechaHasta ? new Date(fechaHasta as string) : undefined,
|
||||
limit: limit ? parseInt(limit as string, 10) : undefined,
|
||||
offset: offset ? parseInt(offset as string, 10) : undefined,
|
||||
});
|
||||
|
||||
res.json(result);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async registrarEvento(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const dto: CreateEventoDto = req.body;
|
||||
const evento = await this.trackingService.registrarEvento(tenantId, dto);
|
||||
res.status(201).json({ data: evento });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async registrarPosicion(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { unidadId, latitud, longitud, velocidad, rumbo, odometro, viajeId, operadorId } = req.body;
|
||||
|
||||
if (!unidadId || latitud === undefined || longitud === undefined) {
|
||||
res.status(400).json({ error: 'unidadId, latitud y longitud son requeridos' });
|
||||
return;
|
||||
}
|
||||
|
||||
const evento = await this.trackingService.registrarPosicion(tenantId, unidadId, {
|
||||
latitud,
|
||||
longitud,
|
||||
velocidad,
|
||||
rumbo,
|
||||
odometro,
|
||||
viajeId,
|
||||
operadorId,
|
||||
});
|
||||
|
||||
res.status(201).json({ data: evento });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async getUltimaPosicion(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { unidadId } = req.params;
|
||||
const posicion = await this.trackingService.getUltimaPosicion(unidadId, tenantId);
|
||||
|
||||
if (!posicion) {
|
||||
res.status(404).json({ error: 'No hay posiciones registradas para esta unidad' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json({ data: posicion });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async getHistorialPosiciones(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { unidadId } = req.params;
|
||||
const { fechaDesde, fechaHasta } = req.query;
|
||||
|
||||
if (!fechaDesde || !fechaHasta) {
|
||||
res.status(400).json({ error: 'fechaDesde y fechaHasta son requeridos' });
|
||||
return;
|
||||
}
|
||||
|
||||
const posiciones = await this.trackingService.getHistorialPosiciones(
|
||||
unidadId,
|
||||
tenantId,
|
||||
new Date(fechaDesde as string),
|
||||
new Date(fechaHasta as string)
|
||||
);
|
||||
|
||||
res.json({ data: posiciones });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async getRutaViaje(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { viajeId } = req.params;
|
||||
const ruta = await this.trackingService.getRutaViaje(viajeId, tenantId);
|
||||
res.json({ data: ruta });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async getEventosViaje(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { viajeId } = req.params;
|
||||
const eventos = await this.trackingService.getEventosViaje(viajeId, tenantId);
|
||||
res.json({ data: eventos });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async getPosicionesActuales(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { unidadIds } = req.query;
|
||||
const ids = unidadIds ? (unidadIds as string).split(',') : undefined;
|
||||
|
||||
const posiciones = await this.trackingService.getPosicionesActuales(tenantId, ids);
|
||||
res.json({ data: posiciones });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== Geocercas ====================
|
||||
|
||||
private async findAllGeocercas(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { tipo, activa, clienteId, limit, offset } = req.query;
|
||||
|
||||
const result = await this.trackingService.findAllGeocercas({
|
||||
tenantId,
|
||||
tipo: tipo as TipoGeocerca,
|
||||
activa: activa ? activa === 'true' : undefined,
|
||||
clienteId: clienteId as string,
|
||||
limit: limit ? parseInt(limit as string, 10) : undefined,
|
||||
offset: offset ? parseInt(offset as string, 10) : undefined,
|
||||
});
|
||||
|
||||
res.json(result);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async findGeocerca(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { id } = req.params;
|
||||
const geocerca = await this.trackingService.findGeocerca(id, tenantId);
|
||||
|
||||
if (!geocerca) {
|
||||
res.status(404).json({ error: 'Geocerca no encontrada' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json({ data: geocerca });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async createGeocerca(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
const userId = req.headers['x-user-id'] as string;
|
||||
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const dto: CreateGeocercaDto = req.body;
|
||||
const geocerca = await this.trackingService.createGeocerca(tenantId, dto, userId);
|
||||
res.status(201).json({ data: geocerca });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async updateGeocerca(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
const userId = req.headers['x-user-id'] as string;
|
||||
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { id } = req.params;
|
||||
const dto: Partial<CreateGeocercaDto> = req.body;
|
||||
const geocerca = await this.trackingService.updateGeocerca(id, tenantId, dto, userId);
|
||||
|
||||
if (!geocerca) {
|
||||
res.status(404).json({ error: 'Geocerca no encontrada' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json({ data: geocerca });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async deleteGeocerca(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { id } = req.params;
|
||||
const deleted = await this.trackingService.deleteGeocerca(id, tenantId);
|
||||
|
||||
if (!deleted) {
|
||||
res.status(404).json({ error: 'Geocerca no encontrada' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.status(204).send();
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
4
src/modules/viajes/controllers/index.ts
Normal file
4
src/modules/viajes/controllers/index.ts
Normal file
@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Viajes Controllers
|
||||
*/
|
||||
export * from './viajes.controller';
|
||||
339
src/modules/viajes/controllers/viajes.controller.ts
Normal file
339
src/modules/viajes/controllers/viajes.controller.ts
Normal file
@ -0,0 +1,339 @@
|
||||
import { Request, Response, NextFunction, Router } from 'express';
|
||||
import { ViajesService, CreateViajeDto, UpdateViajeDto } from '../services/viajes.service';
|
||||
import { EstadoViaje } from '../entities';
|
||||
|
||||
export class ViajesController {
|
||||
public router: Router;
|
||||
|
||||
constructor(private readonly viajesService: ViajesService) {
|
||||
this.router = Router();
|
||||
this.initializeRoutes();
|
||||
}
|
||||
|
||||
private initializeRoutes(): void {
|
||||
// CRUD básico
|
||||
this.router.get('/', this.findAll.bind(this));
|
||||
this.router.get('/en-progreso', this.getViajesEnProgreso.bind(this));
|
||||
this.router.get('/operador/:operadorId', this.getViajesOperador.bind(this));
|
||||
this.router.get('/unidad/:unidadId', this.getViajesUnidad.bind(this));
|
||||
this.router.get('/:id', this.findOne.bind(this));
|
||||
this.router.get('/numero/:numeroViaje', this.findByNumero.bind(this));
|
||||
this.router.post('/', this.create.bind(this));
|
||||
this.router.patch('/:id', this.update.bind(this));
|
||||
|
||||
// Operaciones de estado
|
||||
this.router.post('/:id/estado', this.cambiarEstado.bind(this));
|
||||
this.router.post('/:id/despachar', this.despachar.bind(this));
|
||||
this.router.post('/:id/iniciar-transito', this.iniciarTransito.bind(this));
|
||||
this.router.post('/:id/registrar-llegada', this.registrarLlegada.bind(this));
|
||||
this.router.post('/:id/registrar-entrega', this.registrarEntrega.bind(this));
|
||||
}
|
||||
|
||||
private async findAll(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const {
|
||||
search,
|
||||
estado,
|
||||
estados,
|
||||
unidadId,
|
||||
operadorId,
|
||||
clienteId,
|
||||
fechaDesde,
|
||||
fechaHasta,
|
||||
limit,
|
||||
offset,
|
||||
} = req.query;
|
||||
|
||||
const result = await this.viajesService.findAll({
|
||||
tenantId,
|
||||
search: search as string,
|
||||
estado: estado as EstadoViaje,
|
||||
estados: estados ? (estados as string).split(',') as EstadoViaje[] : undefined,
|
||||
unidadId: unidadId as string,
|
||||
operadorId: operadorId as string,
|
||||
clienteId: clienteId as string,
|
||||
fechaDesde: fechaDesde ? new Date(fechaDesde as string) : undefined,
|
||||
fechaHasta: fechaHasta ? new Date(fechaHasta as string) : undefined,
|
||||
limit: limit ? parseInt(limit as string, 10) : undefined,
|
||||
offset: offset ? parseInt(offset as string, 10) : undefined,
|
||||
});
|
||||
|
||||
res.json(result);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async findOne(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { id } = req.params;
|
||||
const viaje = await this.viajesService.findOne(id, tenantId);
|
||||
|
||||
if (!viaje) {
|
||||
res.status(404).json({ error: 'Viaje no encontrado' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json({ data: viaje });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async findByNumero(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { numeroViaje } = req.params;
|
||||
const viaje = await this.viajesService.findByNumero(numeroViaje, tenantId);
|
||||
|
||||
if (!viaje) {
|
||||
res.status(404).json({ error: 'Viaje no encontrado' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json({ data: viaje });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async create(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
const userId = req.headers['x-user-id'] as string;
|
||||
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const dto: CreateViajeDto = req.body;
|
||||
const viaje = await this.viajesService.create(tenantId, dto, userId);
|
||||
res.status(201).json({ data: viaje });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async update(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
const userId = req.headers['x-user-id'] as string;
|
||||
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { id } = req.params;
|
||||
const dto: UpdateViajeDto = req.body;
|
||||
const viaje = await this.viajesService.update(id, tenantId, dto, userId);
|
||||
|
||||
if (!viaje) {
|
||||
res.status(404).json({ error: 'Viaje no encontrado' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json({ data: viaje });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async cambiarEstado(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
const userId = req.headers['x-user-id'] as string;
|
||||
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { id } = req.params;
|
||||
const { estado } = req.body;
|
||||
|
||||
if (!estado) {
|
||||
res.status(400).json({ error: 'Estado es requerido' });
|
||||
return;
|
||||
}
|
||||
|
||||
const viaje = await this.viajesService.cambiarEstado(id, tenantId, estado, userId);
|
||||
|
||||
if (!viaje) {
|
||||
res.status(404).json({ error: 'Viaje no encontrado' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json({ data: viaje });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async despachar(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
const userId = req.headers['x-user-id'] as string;
|
||||
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { id } = req.params;
|
||||
const { kmInicial, sellos } = req.body;
|
||||
|
||||
const viaje = await this.viajesService.despachar(id, tenantId, { kmInicial, sellos }, userId);
|
||||
|
||||
if (!viaje) {
|
||||
res.status(404).json({ error: 'Viaje no encontrado' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json({ data: viaje });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async iniciarTransito(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
const userId = req.headers['x-user-id'] as string;
|
||||
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { id } = req.params;
|
||||
const viaje = await this.viajesService.iniciarTransito(id, tenantId, userId);
|
||||
|
||||
if (!viaje) {
|
||||
res.status(404).json({ error: 'Viaje no encontrado' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json({ data: viaje });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async registrarLlegada(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
const userId = req.headers['x-user-id'] as string;
|
||||
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { id } = req.params;
|
||||
const { kmFinal } = req.body;
|
||||
|
||||
const viaje = await this.viajesService.registrarLlegada(id, tenantId, { kmFinal }, userId);
|
||||
|
||||
if (!viaje) {
|
||||
res.status(404).json({ error: 'Viaje no encontrado' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json({ data: viaje });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async registrarEntrega(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
const userId = req.headers['x-user-id'] as string;
|
||||
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { id } = req.params;
|
||||
const { kmFinal, observaciones } = req.body;
|
||||
|
||||
const viaje = await this.viajesService.registrarEntrega(id, tenantId, { kmFinal, observaciones }, userId);
|
||||
|
||||
if (!viaje) {
|
||||
res.status(404).json({ error: 'Viaje no encontrado' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json({ data: viaje });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async getViajesEnProgreso(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const viajes = await this.viajesService.getViajesEnProgreso(tenantId);
|
||||
res.json({ data: viajes });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async getViajesOperador(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { operadorId } = req.params;
|
||||
const viajes = await this.viajesService.getViajesOperador(operadorId, tenantId);
|
||||
res.json({ data: viajes });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
private async getViajesUnidad(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
if (!tenantId) {
|
||||
res.status(400).json({ error: 'Tenant ID is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { unidadId } = req.params;
|
||||
const viajes = await this.viajesService.getViajesUnidad(unidadId, tenantId);
|
||||
res.json({ data: viajes });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user