[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>
This commit is contained in:
parent
e441e9c626
commit
f14829d2ce
@ -6,7 +6,7 @@
|
||||
* @module Assets (MAE-015)
|
||||
*/
|
||||
|
||||
import { Router, Request, Response } from 'express';
|
||||
import { Router, Request, Response, NextFunction } from 'express';
|
||||
import { DataSource } from 'typeorm';
|
||||
import { AssetService } from '../services';
|
||||
|
||||
@ -20,10 +20,9 @@ export function createAssetController(dataSource: DataSource): Router {
|
||||
* GET /
|
||||
* Lista activos con filtros y paginación
|
||||
*/
|
||||
router.get('/', async (req: Request, res: Response) => {
|
||||
router.get('/', 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 filters = {
|
||||
assetType: req.query.assetType as any,
|
||||
@ -81,20 +80,21 @@ export function createAssetController(dataSource: DataSource): Router {
|
||||
* GET /search
|
||||
* Búsqueda de activos para autocomplete
|
||||
*/
|
||||
router.get('/search', async (req: Request, res: Response) => {
|
||||
router.get('/search', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
const query = req.query.q as string;
|
||||
const limit = parseInt(req.query.limit as string) || 10;
|
||||
|
||||
if (!query) {
|
||||
return res.status(400).json({ error: 'Se requiere parámetro de búsqueda (q)' });
|
||||
res.status(400).json({ error: 'Se requiere parámetro de búsqueda (q)' });
|
||||
return;
|
||||
}
|
||||
|
||||
const assets = await service.search(tenantId, query, limit);
|
||||
res.json(assets);
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: (error as Error).message });
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
@ -102,18 +102,19 @@ export function createAssetController(dataSource: DataSource): Router {
|
||||
* GET /by-code/:code
|
||||
* Obtiene un activo por código
|
||||
*/
|
||||
router.get('/by-code/:code', async (req: Request, res: Response) => {
|
||||
router.get('/by-code/:code', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
|
||||
const asset = await service.findByCode(tenantId, req.params.code);
|
||||
if (!asset) {
|
||||
return res.status(404).json({ error: 'Activo no encontrado' });
|
||||
res.status(404).json({ error: 'Activo no encontrado' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json(asset);
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: (error as Error).message });
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
@ -121,18 +122,19 @@ export function createAssetController(dataSource: DataSource): Router {
|
||||
* GET /:id
|
||||
* Obtiene un activo por ID
|
||||
*/
|
||||
router.get('/:id', async (req: Request, res: Response) => {
|
||||
router.get('/:id', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
|
||||
const asset = await service.findById(tenantId, req.params.id);
|
||||
if (!asset) {
|
||||
return res.status(404).json({ error: 'Activo no encontrado' });
|
||||
res.status(404).json({ error: 'Activo no encontrado' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json(asset);
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: (error as Error).message });
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
@ -156,19 +158,20 @@ export function createAssetController(dataSource: DataSource): Router {
|
||||
* PUT /:id
|
||||
* Actualiza un activo
|
||||
*/
|
||||
router.put('/:id', async (req: Request, res: Response) => {
|
||||
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 asset = await service.update(tenantId, req.params.id, req.body, userId);
|
||||
if (!asset) {
|
||||
return res.status(404).json({ error: 'Activo no encontrado' });
|
||||
res.status(404).json({ error: 'Activo no encontrado' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json(asset);
|
||||
} catch (error) {
|
||||
res.status(400).json({ error: (error as Error).message });
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
@ -176,24 +179,26 @@ export function createAssetController(dataSource: DataSource): Router {
|
||||
* PATCH /:id/status
|
||||
* Actualiza el estado de un activo
|
||||
*/
|
||||
router.patch('/:id/status', async (req: Request, res: Response) => {
|
||||
router.patch('/:id/status', 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 { status } = req.body;
|
||||
|
||||
if (!status) {
|
||||
return res.status(400).json({ error: 'Se requiere el nuevo estado' });
|
||||
res.status(400).json({ error: 'Se requiere el nuevo estado' });
|
||||
return;
|
||||
}
|
||||
|
||||
const asset = await service.updateStatus(tenantId, req.params.id, status, userId);
|
||||
if (!asset) {
|
||||
return res.status(404).json({ error: 'Activo no encontrado' });
|
||||
res.status(404).json({ error: 'Activo no encontrado' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json(asset);
|
||||
} catch (error) {
|
||||
res.status(400).json({ error: (error as Error).message });
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
@ -201,7 +206,7 @@ export function createAssetController(dataSource: DataSource): Router {
|
||||
* PATCH /:id/usage
|
||||
* Actualiza métricas de uso (horas/kilómetros)
|
||||
*/
|
||||
router.patch('/:id/usage', async (req: Request, res: Response) => {
|
||||
router.patch('/:id/usage', 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;
|
||||
@ -209,12 +214,13 @@ export function createAssetController(dataSource: DataSource): Router {
|
||||
|
||||
const asset = await service.updateUsage(tenantId, req.params.id, hours, kilometers, userId);
|
||||
if (!asset) {
|
||||
return res.status(404).json({ error: 'Activo no encontrado' });
|
||||
res.status(404).json({ error: 'Activo no encontrado' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json(asset);
|
||||
} catch (error) {
|
||||
res.status(400).json({ error: (error as Error).message });
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
@ -222,19 +228,20 @@ export function createAssetController(dataSource: DataSource): Router {
|
||||
* DELETE /:id
|
||||
* Elimina un activo (soft delete)
|
||||
*/
|
||||
router.delete('/:id', async (req: Request, res: Response) => {
|
||||
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) {
|
||||
return res.status(404).json({ error: 'Activo no encontrado' });
|
||||
res.status(404).json({ error: 'Activo no encontrado' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.status(204).send();
|
||||
} catch (error) {
|
||||
res.status(400).json({ error: (error as Error).message });
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
@ -300,7 +307,7 @@ export function createAssetController(dataSource: DataSource): Router {
|
||||
* POST /:id/return
|
||||
* Retorna un activo de un proyecto
|
||||
*/
|
||||
router.post('/:id/return', async (req: Request, res: Response) => {
|
||||
router.post('/:id/return', 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;
|
||||
@ -314,12 +321,13 @@ export function createAssetController(dataSource: DataSource): Router {
|
||||
);
|
||||
|
||||
if (!result) {
|
||||
return res.status(400).json({ error: 'No hay asignación activa para este activo' });
|
||||
res.status(400).json({ error: 'No hay asignación activa para este activo' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json({ success: true, message: 'Activo retornado exitosamente' });
|
||||
} catch (error) {
|
||||
res.status(400).json({ error: (error as Error).message });
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
* @module Assets (MAE-015)
|
||||
*/
|
||||
|
||||
import { Router, Request, Response } from 'express';
|
||||
import { Router, Request, Response, NextFunction } from 'express';
|
||||
import { DataSource } from 'typeorm';
|
||||
import { FuelLogService } from '../services';
|
||||
|
||||
@ -18,7 +18,7 @@ export function createFuelLogController(dataSource: DataSource): Router {
|
||||
* GET /
|
||||
* Lista registros de combustible con filtros
|
||||
*/
|
||||
router.get('/', async (req: Request, res: Response) => {
|
||||
router.get('/', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
|
||||
@ -38,7 +38,7 @@ export function createFuelLogController(dataSource: DataSource): Router {
|
||||
const result = await service.findAll(tenantId, filters, pagination);
|
||||
res.json(result);
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: (error as Error).message });
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
@ -46,7 +46,7 @@ export function createFuelLogController(dataSource: DataSource): Router {
|
||||
* GET /statistics/:assetId
|
||||
* Obtiene estadísticas de combustible para un activo
|
||||
*/
|
||||
router.get('/statistics/:assetId', async (req: Request, res: Response) => {
|
||||
router.get('/statistics/:assetId', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
|
||||
@ -56,7 +56,7 @@ export function createFuelLogController(dataSource: DataSource): Router {
|
||||
const stats = await service.getAssetStatistics(tenantId, req.params.assetId, fromDate, toDate);
|
||||
res.json(stats);
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: (error as Error).message });
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
@ -64,18 +64,19 @@ export function createFuelLogController(dataSource: DataSource): Router {
|
||||
* GET /:id
|
||||
* Obtiene un registro por ID
|
||||
*/
|
||||
router.get('/:id', async (req: Request, res: Response) => {
|
||||
router.get('/:id', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
|
||||
const fuelLog = await service.findById(tenantId, req.params.id);
|
||||
if (!fuelLog) {
|
||||
return res.status(404).json({ error: 'Registro de combustible no encontrado' });
|
||||
res.status(404).json({ error: 'Registro de combustible no encontrado' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json(fuelLog);
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: (error as Error).message });
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
@ -83,7 +84,7 @@ export function createFuelLogController(dataSource: DataSource): Router {
|
||||
* POST /
|
||||
* Crea un nuevo registro de combustible
|
||||
*/
|
||||
router.post('/', async (req: Request, res: Response) => {
|
||||
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;
|
||||
@ -91,7 +92,7 @@ export function createFuelLogController(dataSource: DataSource): Router {
|
||||
const fuelLog = await service.create(tenantId, req.body, userId);
|
||||
res.status(201).json(fuelLog);
|
||||
} catch (error) {
|
||||
res.status(400).json({ error: (error as Error).message });
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
@ -99,18 +100,19 @@ export function createFuelLogController(dataSource: DataSource): Router {
|
||||
* DELETE /:id
|
||||
* Elimina un registro de combustible
|
||||
*/
|
||||
router.delete('/:id', async (req: Request, res: Response) => {
|
||||
router.delete('/:id', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
|
||||
const deleted = await service.delete(tenantId, req.params.id);
|
||||
if (!deleted) {
|
||||
return res.status(404).json({ error: 'Registro de combustible no encontrado' });
|
||||
res.status(404).json({ error: 'Registro de combustible no encontrado' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.status(204).send();
|
||||
} catch (error) {
|
||||
res.status(400).json({ error: (error as Error).message });
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
* @module Assets (MAE-015)
|
||||
*/
|
||||
|
||||
import { Router, Request, Response } from 'express';
|
||||
import { Router, Request, Response, NextFunction } from 'express';
|
||||
import { DataSource } from 'typeorm';
|
||||
import { WorkOrderService } from '../services';
|
||||
|
||||
@ -20,7 +20,7 @@ export function createWorkOrderController(dataSource: DataSource): Router {
|
||||
* GET /
|
||||
* Lista órdenes de trabajo con filtros y paginación
|
||||
*/
|
||||
router.get('/', async (req: Request, res: Response) => {
|
||||
router.get('/', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
|
||||
try {
|
||||
const tenantId = req.headers['x-tenant-id'] as string;
|
||||
|
||||
@ -44,7 +44,7 @@ export function createWorkOrderController(dataSource: DataSource): Router {
|
||||
const result = await service.findAll(tenantId, filters, pagination);
|
||||
res.json(result);
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: (error as Error).message });
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
@ -52,14 +52,14 @@ export function createWorkOrderController(dataSource: DataSource): Router {
|
||||
* GET /statistics
|
||||
* Obtiene estadísticas de órdenes de trabajo
|
||||
*/
|
||||
router.get('/statistics', async (req: Request, res: Response) => {
|
||||
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) {
|
||||
res.status(500).json({ error: (error as Error).message });
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
@ -67,14 +67,14 @@ export function createWorkOrderController(dataSource: DataSource): Router {
|
||||
* GET /by-status
|
||||
* Obtiene órdenes agrupadas por estado
|
||||
*/
|
||||
router.get('/by-status', async (req: Request, res: Response) => {
|
||||
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) {
|
||||
res.status(500).json({ error: (error as Error).message });
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
@ -82,18 +82,19 @@ export function createWorkOrderController(dataSource: DataSource): Router {
|
||||
* GET /by-number/:orderNumber
|
||||
* Obtiene una orden por número
|
||||
*/
|
||||
router.get('/by-number/:orderNumber', async (req: Request, res: Response) => {
|
||||
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) {
|
||||
return res.status(404).json({ error: 'Orden de trabajo no encontrada' });
|
||||
res.status(404).json({ error: 'Orden de trabajo no encontrada' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json(workOrder);
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: (error as Error).message });
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
@ -101,14 +102,14 @@ export function createWorkOrderController(dataSource: DataSource): Router {
|
||||
* GET /overdue
|
||||
* Lista órdenes vencidas
|
||||
*/
|
||||
router.get('/overdue', async (req: Request, res: Response) => {
|
||||
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) {
|
||||
res.status(500).json({ error: (error as Error).message });
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
@ -116,18 +117,19 @@ export function createWorkOrderController(dataSource: DataSource): Router {
|
||||
* GET /:id
|
||||
* Obtiene una orden de trabajo por ID
|
||||
*/
|
||||
router.get('/:id', async (req: Request, res: Response) => {
|
||||
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) {
|
||||
return res.status(404).json({ error: 'Orden de trabajo no encontrada' });
|
||||
res.status(404).json({ error: 'Orden de trabajo no encontrada' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json(workOrder);
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: (error as Error).message });
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
@ -135,7 +137,7 @@ export function createWorkOrderController(dataSource: DataSource): Router {
|
||||
* POST /
|
||||
* Crea una nueva orden de trabajo
|
||||
*/
|
||||
router.post('/', async (req: Request, res: Response) => {
|
||||
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;
|
||||
@ -143,7 +145,7 @@ export function createWorkOrderController(dataSource: DataSource): Router {
|
||||
const workOrder = await service.create(tenantId, req.body, userId);
|
||||
res.status(201).json(workOrder);
|
||||
} catch (error) {
|
||||
res.status(400).json({ error: (error as Error).message });
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
@ -151,19 +153,20 @@ export function createWorkOrderController(dataSource: DataSource): Router {
|
||||
* PUT /:id
|
||||
* Actualiza una orden de trabajo
|
||||
*/
|
||||
router.put('/:id', async (req: Request, res: Response) => {
|
||||
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) {
|
||||
return res.status(404).json({ error: 'Orden de trabajo no encontrada' });
|
||||
res.status(404).json({ error: 'Orden de trabajo no encontrada' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json(workOrder);
|
||||
} catch (error) {
|
||||
res.status(400).json({ error: (error as Error).message });
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
@ -171,19 +174,20 @@ export function createWorkOrderController(dataSource: DataSource): Router {
|
||||
* DELETE /:id
|
||||
* Elimina una orden de trabajo (soft delete)
|
||||
*/
|
||||
router.delete('/:id', async (req: Request, res: Response) => {
|
||||
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) {
|
||||
return res.status(404).json({ error: 'Orden de trabajo no encontrada' });
|
||||
res.status(404).json({ error: 'Orden de trabajo no encontrada' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.status(204).send();
|
||||
} catch (error) {
|
||||
res.status(400).json({ error: (error as Error).message });
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
@ -193,19 +197,20 @@ export function createWorkOrderController(dataSource: DataSource): Router {
|
||||
* POST /:id/start
|
||||
* Inicia una orden de trabajo
|
||||
*/
|
||||
router.post('/:id/start', async (req: Request, res: Response) => {
|
||||
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) {
|
||||
return res.status(404).json({ error: 'Orden de trabajo no encontrada' });
|
||||
res.status(404).json({ error: 'Orden de trabajo no encontrada' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json(workOrder);
|
||||
} catch (error) {
|
||||
res.status(400).json({ error: (error as Error).message });
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
@ -213,7 +218,7 @@ export function createWorkOrderController(dataSource: DataSource): Router {
|
||||
* POST /:id/hold
|
||||
* Pone en espera una orden de trabajo
|
||||
*/
|
||||
router.post('/:id/hold', async (req: Request, res: Response) => {
|
||||
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;
|
||||
@ -221,12 +226,13 @@ export function createWorkOrderController(dataSource: DataSource): Router {
|
||||
|
||||
const workOrder = await service.hold(tenantId, req.params.id, reason, userId);
|
||||
if (!workOrder) {
|
||||
return res.status(404).json({ error: 'Orden de trabajo no encontrada' });
|
||||
res.status(404).json({ error: 'Orden de trabajo no encontrada' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json(workOrder);
|
||||
} catch (error) {
|
||||
res.status(400).json({ error: (error as Error).message });
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
@ -234,19 +240,20 @@ export function createWorkOrderController(dataSource: DataSource): Router {
|
||||
* POST /:id/resume
|
||||
* Reanuda una orden de trabajo en espera
|
||||
*/
|
||||
router.post('/:id/resume', async (req: Request, res: Response) => {
|
||||
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) {
|
||||
return res.status(404).json({ error: 'Orden de trabajo no encontrada' });
|
||||
res.status(404).json({ error: 'Orden de trabajo no encontrada' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json(workOrder);
|
||||
} catch (error) {
|
||||
res.status(400).json({ error: (error as Error).message });
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
@ -254,19 +261,20 @@ export function createWorkOrderController(dataSource: DataSource): Router {
|
||||
* POST /:id/complete
|
||||
* Completa una orden de trabajo
|
||||
*/
|
||||
router.post('/:id/complete', async (req: Request, res: Response) => {
|
||||
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) {
|
||||
return res.status(404).json({ error: 'Orden de trabajo no encontrada' });
|
||||
res.status(404).json({ error: 'Orden de trabajo no encontrada' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json(workOrder);
|
||||
} catch (error) {
|
||||
res.status(400).json({ error: (error as Error).message });
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
@ -274,7 +282,7 @@ export function createWorkOrderController(dataSource: DataSource): Router {
|
||||
* POST /:id/cancel
|
||||
* Cancela una orden de trabajo
|
||||
*/
|
||||
router.post('/:id/cancel', async (req: Request, res: Response) => {
|
||||
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;
|
||||
@ -282,12 +290,13 @@ export function createWorkOrderController(dataSource: DataSource): Router {
|
||||
|
||||
const workOrder = await service.cancel(tenantId, req.params.id, reason, userId);
|
||||
if (!workOrder) {
|
||||
return res.status(404).json({ error: 'Orden de trabajo no encontrada' });
|
||||
res.status(404).json({ error: 'Orden de trabajo no encontrada' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json(workOrder);
|
||||
} catch (error) {
|
||||
res.status(400).json({ error: (error as Error).message });
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
@ -297,14 +306,14 @@ export function createWorkOrderController(dataSource: DataSource): Router {
|
||||
* GET /:id/parts
|
||||
* Lista partes usadas en una orden de trabajo
|
||||
*/
|
||||
router.get('/:id/parts', async (req: Request, res: Response) => {
|
||||
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) {
|
||||
res.status(500).json({ error: (error as Error).message });
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
@ -312,7 +321,7 @@ export function createWorkOrderController(dataSource: DataSource): Router {
|
||||
* POST /:id/parts
|
||||
* Agrega una parte a la orden de trabajo
|
||||
*/
|
||||
router.post('/:id/parts', async (req: Request, res: Response) => {
|
||||
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;
|
||||
@ -320,7 +329,7 @@ export function createWorkOrderController(dataSource: DataSource): Router {
|
||||
const part = await service.addPart(tenantId, req.params.id, req.body, userId);
|
||||
res.status(201).json(part);
|
||||
} catch (error) {
|
||||
res.status(400).json({ error: (error as Error).message });
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
@ -328,19 +337,20 @@ export function createWorkOrderController(dataSource: DataSource): Router {
|
||||
* PUT /:id/parts/:partId
|
||||
* Actualiza una parte de la orden
|
||||
*/
|
||||
router.put('/:id/parts/:partId', async (req: Request, res: Response) => {
|
||||
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) {
|
||||
return res.status(404).json({ error: 'Parte no encontrada' });
|
||||
res.status(404).json({ error: 'Parte no encontrada' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json(part);
|
||||
} catch (error) {
|
||||
res.status(400).json({ error: (error as Error).message });
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
@ -348,19 +358,20 @@ export function createWorkOrderController(dataSource: DataSource): Router {
|
||||
* DELETE /:id/parts/:partId
|
||||
* Elimina una parte de la orden
|
||||
*/
|
||||
router.delete('/:id/parts/:partId', async (req: Request, res: Response) => {
|
||||
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) {
|
||||
return res.status(404).json({ error: 'Parte no encontrada' });
|
||||
res.status(404).json({ error: 'Parte no encontrada' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.status(204).send();
|
||||
} catch (error) {
|
||||
res.status(400).json({ error: (error as Error).message });
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
@ -370,7 +381,7 @@ export function createWorkOrderController(dataSource: DataSource): Router {
|
||||
* GET /plans
|
||||
* Lista planes de mantenimiento
|
||||
*/
|
||||
router.get('/plans/list', async (req: Request, res: Response) => {
|
||||
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;
|
||||
@ -378,7 +389,7 @@ export function createWorkOrderController(dataSource: DataSource): Router {
|
||||
const plans = await service.getMaintenancePlans(tenantId, assetId);
|
||||
res.json(plans);
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: (error as Error).message });
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
@ -386,7 +397,7 @@ export function createWorkOrderController(dataSource: DataSource): Router {
|
||||
* POST /plans
|
||||
* Crea un plan de mantenimiento
|
||||
*/
|
||||
router.post('/plans', async (req: Request, res: Response) => {
|
||||
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;
|
||||
@ -394,7 +405,7 @@ export function createWorkOrderController(dataSource: DataSource): Router {
|
||||
const plan = await service.createMaintenancePlan(tenantId, req.body, userId);
|
||||
res.status(201).json(plan);
|
||||
} catch (error) {
|
||||
res.status(400).json({ error: (error as Error).message });
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
@ -402,7 +413,7 @@ export function createWorkOrderController(dataSource: DataSource): Router {
|
||||
* POST /plans/:planId/generate
|
||||
* Genera órdenes de trabajo desde un plan
|
||||
*/
|
||||
router.post('/plans/:planId/generate', async (req: Request, res: Response) => {
|
||||
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;
|
||||
@ -410,7 +421,7 @@ export function createWorkOrderController(dataSource: DataSource): Router {
|
||||
const orders = await service.generateFromPlan(tenantId, req.params.planId, userId);
|
||||
res.status(201).json(orders);
|
||||
} catch (error) {
|
||||
res.status(400).json({ error: (error as Error).message });
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@ -24,6 +24,23 @@ export type MaintenanceType = 'preventive' | 'corrective' | 'predictive' | 'emer
|
||||
export type WorkOrderStatus = 'draft' | 'scheduled' | 'in_progress' | 'on_hold' | 'completed' | 'cancelled';
|
||||
export type WorkOrderPriority = 'low' | 'medium' | 'high' | 'critical';
|
||||
|
||||
// Const objects for runtime use
|
||||
export const WorkOrderStatusValues: Record<string, WorkOrderStatus> = {
|
||||
DRAFT: 'draft',
|
||||
SCHEDULED: 'scheduled',
|
||||
IN_PROGRESS: 'in_progress',
|
||||
ON_HOLD: 'on_hold',
|
||||
COMPLETED: 'completed',
|
||||
CANCELLED: 'cancelled',
|
||||
} as const;
|
||||
|
||||
export const WorkOrderPriorityValues: Record<string, WorkOrderPriority> = {
|
||||
LOW: 'low',
|
||||
MEDIUM: 'medium',
|
||||
HIGH: 'high',
|
||||
CRITICAL: 'critical',
|
||||
} as const;
|
||||
|
||||
@Entity('work_orders', { schema: 'assets' })
|
||||
@Index(['tenantId', 'workOrderNumber'], { unique: true })
|
||||
@Index(['tenantId', 'assetId'])
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
* Logica de negocio para gestion de activos fijos y maquinaria.
|
||||
*/
|
||||
|
||||
import { Repository, DataSource, ILike } from 'typeorm';
|
||||
import { Repository, DataSource, IsNull } from 'typeorm';
|
||||
import { Asset, AssetType, AssetStatus, OwnershipType } from '../entities/asset.entity';
|
||||
import { AssetCategory } from '../entities/asset-category.entity';
|
||||
import { AssetAssignment } from '../entities/asset-assignment.entity';
|
||||
@ -94,7 +94,7 @@ export class AssetService {
|
||||
private categoryRepository: Repository<AssetCategory>;
|
||||
private assignmentRepository: Repository<AssetAssignment>;
|
||||
|
||||
constructor(private dataSource: DataSource) {
|
||||
constructor(dataSource: DataSource) {
|
||||
this.assetRepository = dataSource.getRepository(Asset);
|
||||
this.categoryRepository = dataSource.getRepository(AssetCategory);
|
||||
this.assignmentRepository = dataSource.getRepository(AssetAssignment);
|
||||
@ -120,8 +120,8 @@ export class AssetService {
|
||||
const asset = this.assetRepository.create({
|
||||
tenantId,
|
||||
...dto,
|
||||
status: AssetStatus.AVAILABLE,
|
||||
ownershipType: dto.ownershipType || OwnershipType.OWNED,
|
||||
status: 'available' as AssetStatus,
|
||||
ownershipType: dto.ownershipType || ('owned' as OwnershipType),
|
||||
currentBookValue: dto.purchasePrice,
|
||||
createdBy: userId,
|
||||
});
|
||||
@ -263,7 +263,7 @@ export class AssetService {
|
||||
async delete(tenantId: string, id: string, userId?: string): Promise<boolean> {
|
||||
const result = await this.assetRepository.update(
|
||||
{ id, tenantId },
|
||||
{ deletedAt: new Date(), status: AssetStatus.RETIRED, updatedBy: userId }
|
||||
{ deletedAt: new Date(), status: 'retired' as AssetStatus, updatedBy: userId }
|
||||
);
|
||||
return (result.affected ?? 0) > 0;
|
||||
}
|
||||
@ -315,7 +315,7 @@ export class AssetService {
|
||||
// Update asset with new project
|
||||
await this.update(tenantId, dto.assetId, {
|
||||
currentProjectId: dto.projectId,
|
||||
status: AssetStatus.ASSIGNED,
|
||||
status: 'assigned' as AssetStatus,
|
||||
assignedOperatorId: dto.operatorId,
|
||||
}, userId);
|
||||
|
||||
@ -378,7 +378,7 @@ export class AssetService {
|
||||
// Update asset status
|
||||
await this.update(tenantId, assetId, {
|
||||
currentProjectId: undefined,
|
||||
status: AssetStatus.AVAILABLE,
|
||||
status: 'available' as AssetStatus,
|
||||
}, userId);
|
||||
|
||||
return true;
|
||||
@ -405,7 +405,7 @@ export class AssetService {
|
||||
*/
|
||||
async getCategories(tenantId: string): Promise<AssetCategory[]> {
|
||||
return this.categoryRepository.find({
|
||||
where: { tenantId, isActive: true, deletedAt: null },
|
||||
where: { tenantId, isActive: true, deletedAt: IsNull() },
|
||||
order: { level: 'ASC', name: 'ASC' },
|
||||
});
|
||||
}
|
||||
@ -425,7 +425,7 @@ export class AssetService {
|
||||
maintenanceDue: number;
|
||||
}> {
|
||||
const [total, byStatusRaw, byTypeRaw, valueResult, maintenanceDue] = await Promise.all([
|
||||
this.assetRepository.count({ where: { tenantId, deletedAt: null } }),
|
||||
this.assetRepository.count({ where: { tenantId, deletedAt: IsNull() } }),
|
||||
|
||||
this.assetRepository.createQueryBuilder('asset')
|
||||
.select('asset.status', 'status')
|
||||
@ -484,7 +484,7 @@ export class AssetService {
|
||||
return this.assetRepository.createQueryBuilder('asset')
|
||||
.where('asset.tenant_id = :tenantId', { tenantId })
|
||||
.andWhere('asset.deleted_at IS NULL')
|
||||
.andWhere('asset.status != :retired', { retired: AssetStatus.RETIRED })
|
||||
.andWhere('asset.status != :retired', { retired: 'retired' })
|
||||
.andWhere(
|
||||
'(asset.next_maintenance_date <= :today OR asset.current_hours >= asset.next_maintenance_hours OR asset.current_kilometers >= asset.next_maintenance_kilometers)',
|
||||
{ today }
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
* Logica de negocio para registro de combustible y calculo de rendimiento.
|
||||
*/
|
||||
|
||||
import { Repository, DataSource, Between } from 'typeorm';
|
||||
import { Repository, DataSource } from 'typeorm';
|
||||
import { FuelLog } from '../entities/fuel-log.entity';
|
||||
import { Asset } from '../entities/asset.entity';
|
||||
|
||||
@ -48,7 +48,7 @@ export class FuelLogService {
|
||||
private fuelLogRepository: Repository<FuelLog>;
|
||||
private assetRepository: Repository<Asset>;
|
||||
|
||||
constructor(private dataSource: DataSource) {
|
||||
constructor(dataSource: DataSource) {
|
||||
this.fuelLogRepository = dataSource.getRepository(FuelLog);
|
||||
this.assetRepository = dataSource.getRepository(Asset);
|
||||
}
|
||||
|
||||
@ -5,8 +5,8 @@
|
||||
* Logica de negocio para ordenes de trabajo de mantenimiento.
|
||||
*/
|
||||
|
||||
import { Repository, DataSource, LessThanOrEqual, In } from 'typeorm';
|
||||
import { WorkOrder, WorkOrderStatus, WorkOrderPriority, MaintenanceType } from '../entities/work-order.entity';
|
||||
import { Repository, DataSource, LessThanOrEqual, In, IsNull } from 'typeorm';
|
||||
import { WorkOrder, WorkOrderStatus, WorkOrderPriority, MaintenanceType, WorkOrderStatusValues, WorkOrderPriorityValues } from '../entities/work-order.entity';
|
||||
import { WorkOrderPart } from '../entities/work-order-part.entity';
|
||||
import { MaintenanceHistory } from '../entities/maintenance-history.entity';
|
||||
import { MaintenancePlan } from '../entities/maintenance-plan.entity';
|
||||
@ -102,7 +102,7 @@ export class WorkOrderService {
|
||||
private planRepository: Repository<MaintenancePlan>;
|
||||
private assetRepository: Repository<Asset>;
|
||||
|
||||
constructor(private dataSource: DataSource) {
|
||||
constructor(dataSource: DataSource) {
|
||||
this.workOrderRepository = dataSource.getRepository(WorkOrder);
|
||||
this.partRepository = dataSource.getRepository(WorkOrderPart);
|
||||
this.historyRepository = dataSource.getRepository(MaintenanceHistory);
|
||||
@ -153,8 +153,8 @@ export class WorkOrderService {
|
||||
assetCode: asset.assetCode,
|
||||
assetName: asset.name,
|
||||
maintenanceType: dto.maintenanceType,
|
||||
priority: dto.priority || WorkOrderPriority.MEDIUM,
|
||||
status: WorkOrderStatus.DRAFT,
|
||||
priority: dto.priority || WorkOrderPriorityValues.MEDIUM,
|
||||
status: WorkOrderStatusValues.DRAFT,
|
||||
title: dto.title,
|
||||
description: dto.description,
|
||||
problemReported: dto.problemReported,
|
||||
@ -290,15 +290,15 @@ export class WorkOrderService {
|
||||
*/
|
||||
private validateStatusTransition(from: WorkOrderStatus, to: WorkOrderStatus): void {
|
||||
const validTransitions: Record<WorkOrderStatus, WorkOrderStatus[]> = {
|
||||
[WorkOrderStatus.DRAFT]: [WorkOrderStatus.SCHEDULED, WorkOrderStatus.IN_PROGRESS, WorkOrderStatus.CANCELLED],
|
||||
[WorkOrderStatus.SCHEDULED]: [WorkOrderStatus.IN_PROGRESS, WorkOrderStatus.CANCELLED],
|
||||
[WorkOrderStatus.IN_PROGRESS]: [WorkOrderStatus.ON_HOLD, WorkOrderStatus.COMPLETED, WorkOrderStatus.CANCELLED],
|
||||
[WorkOrderStatus.ON_HOLD]: [WorkOrderStatus.IN_PROGRESS, WorkOrderStatus.CANCELLED],
|
||||
[WorkOrderStatus.COMPLETED]: [],
|
||||
[WorkOrderStatus.CANCELLED]: [],
|
||||
draft: ['scheduled', 'in_progress', 'cancelled'],
|
||||
scheduled: ['in_progress', 'cancelled'],
|
||||
in_progress: ['on_hold', 'completed', 'cancelled'],
|
||||
on_hold: ['in_progress', 'cancelled'],
|
||||
completed: [],
|
||||
cancelled: [],
|
||||
};
|
||||
|
||||
if (!validTransitions[from].includes(to)) {
|
||||
if (!validTransitions[from]?.includes(to)) {
|
||||
throw new Error(`Invalid status transition from ${from} to ${to}`);
|
||||
}
|
||||
}
|
||||
@ -310,12 +310,12 @@ export class WorkOrderService {
|
||||
const now = new Date();
|
||||
|
||||
switch (newStatus) {
|
||||
case WorkOrderStatus.IN_PROGRESS:
|
||||
case 'in_progress':
|
||||
if (!workOrder.actualStartDate) {
|
||||
workOrder.actualStartDate = now;
|
||||
}
|
||||
break;
|
||||
case WorkOrderStatus.COMPLETED:
|
||||
case 'completed':
|
||||
workOrder.actualEndDate = now;
|
||||
break;
|
||||
}
|
||||
@ -325,7 +325,7 @@ export class WorkOrderService {
|
||||
* Start work order (change to in_progress)
|
||||
*/
|
||||
async start(tenantId: string, id: string, userId?: string): Promise<WorkOrder | null> {
|
||||
return this.update(tenantId, id, { status: WorkOrderStatus.IN_PROGRESS }, userId);
|
||||
return this.update(tenantId, id, { status: 'in_progress' }, userId);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -336,7 +336,7 @@ export class WorkOrderService {
|
||||
if (!workOrder) return null;
|
||||
|
||||
// Update work order
|
||||
workOrder.status = WorkOrderStatus.COMPLETED;
|
||||
workOrder.status = 'completed';
|
||||
workOrder.actualEndDate = new Date();
|
||||
workOrder.workPerformed = dto.workPerformed;
|
||||
workOrder.findings = dto.findings;
|
||||
@ -454,7 +454,7 @@ export class WorkOrderService {
|
||||
|
||||
const [total, byStatusRaw, byTypeRaw, pendingCount, inProgressCount, completedThisMonth, costResult] =
|
||||
await Promise.all([
|
||||
this.workOrderRepository.count({ where: { tenantId, deletedAt: null } }),
|
||||
this.workOrderRepository.count({ where: { tenantId, deletedAt: IsNull() } }),
|
||||
|
||||
this.workOrderRepository.createQueryBuilder('wo')
|
||||
.select('wo.status', 'status')
|
||||
@ -473,23 +473,23 @@ export class WorkOrderService {
|
||||
.getRawMany(),
|
||||
|
||||
this.workOrderRepository.count({
|
||||
where: { tenantId, status: WorkOrderStatus.DRAFT, deletedAt: null },
|
||||
where: { tenantId, status: 'draft' as WorkOrderStatus, deletedAt: IsNull() },
|
||||
}),
|
||||
|
||||
this.workOrderRepository.count({
|
||||
where: { tenantId, status: WorkOrderStatus.IN_PROGRESS, deletedAt: null },
|
||||
where: { tenantId, status: 'in_progress' as WorkOrderStatus, deletedAt: IsNull() },
|
||||
}),
|
||||
|
||||
this.workOrderRepository.createQueryBuilder('wo')
|
||||
.where('wo.tenant_id = :tenantId', { tenantId })
|
||||
.andWhere('wo.status = :status', { status: WorkOrderStatus.COMPLETED })
|
||||
.andWhere('wo.status = :status', { status: 'completed' as WorkOrderStatus })
|
||||
.andWhere('wo.actual_end_date >= :startOfMonth', { startOfMonth })
|
||||
.getCount(),
|
||||
|
||||
this.workOrderRepository.createQueryBuilder('wo')
|
||||
.select('SUM(wo.total_cost)', 'total')
|
||||
.where('wo.tenant_id = :tenantId', { tenantId })
|
||||
.andWhere('wo.status = :status', { status: WorkOrderStatus.COMPLETED })
|
||||
.andWhere('wo.status = :status', { status: 'completed' as WorkOrderStatus })
|
||||
.andWhere('wo.actual_end_date >= :startOfMonth', { startOfMonth })
|
||||
.getRawOne(),
|
||||
]);
|
||||
@ -520,18 +520,18 @@ export class WorkOrderService {
|
||||
*/
|
||||
async getByStatus(tenantId: string): Promise<Record<WorkOrderStatus, WorkOrder[]>> {
|
||||
const workOrders = await this.workOrderRepository.find({
|
||||
where: { tenantId, deletedAt: null },
|
||||
where: { tenantId, deletedAt: IsNull() },
|
||||
relations: ['asset'],
|
||||
order: { requestedDate: 'DESC' },
|
||||
});
|
||||
|
||||
const grouped: Record<WorkOrderStatus, WorkOrder[]> = {
|
||||
[WorkOrderStatus.DRAFT]: [],
|
||||
[WorkOrderStatus.SCHEDULED]: [],
|
||||
[WorkOrderStatus.IN_PROGRESS]: [],
|
||||
[WorkOrderStatus.ON_HOLD]: [],
|
||||
[WorkOrderStatus.COMPLETED]: [],
|
||||
[WorkOrderStatus.CANCELLED]: [],
|
||||
draft: [],
|
||||
scheduled: [],
|
||||
in_progress: [],
|
||||
on_hold: [],
|
||||
completed: [],
|
||||
cancelled: [],
|
||||
};
|
||||
|
||||
for (const wo of workOrders) {
|
||||
@ -548,9 +548,9 @@ export class WorkOrderService {
|
||||
const workOrder = await this.findById(tenantId, id);
|
||||
if (!workOrder) return null;
|
||||
|
||||
this.validateStatusTransition(workOrder.status, WorkOrderStatus.ON_HOLD);
|
||||
this.validateStatusTransition(workOrder.status, 'on_hold' as WorkOrderStatus);
|
||||
|
||||
workOrder.status = WorkOrderStatus.ON_HOLD;
|
||||
workOrder.status = 'on_hold' as WorkOrderStatus;
|
||||
workOrder.notes = reason ? `${workOrder.notes || ''}\n[ON HOLD] ${reason}` : workOrder.notes;
|
||||
workOrder.updatedBy = userId;
|
||||
|
||||
@ -564,9 +564,9 @@ export class WorkOrderService {
|
||||
const workOrder = await this.findById(tenantId, id);
|
||||
if (!workOrder) return null;
|
||||
|
||||
this.validateStatusTransition(workOrder.status, WorkOrderStatus.IN_PROGRESS);
|
||||
this.validateStatusTransition(workOrder.status, 'in_progress' as WorkOrderStatus);
|
||||
|
||||
workOrder.status = WorkOrderStatus.IN_PROGRESS;
|
||||
workOrder.status = 'in_progress' as WorkOrderStatus;
|
||||
workOrder.updatedBy = userId;
|
||||
|
||||
return this.workOrderRepository.save(workOrder);
|
||||
@ -579,9 +579,9 @@ export class WorkOrderService {
|
||||
const workOrder = await this.findById(tenantId, id);
|
||||
if (!workOrder) return null;
|
||||
|
||||
this.validateStatusTransition(workOrder.status, WorkOrderStatus.CANCELLED);
|
||||
this.validateStatusTransition(workOrder.status, 'cancelled' as WorkOrderStatus);
|
||||
|
||||
workOrder.status = WorkOrderStatus.CANCELLED;
|
||||
workOrder.status = 'cancelled' as WorkOrderStatus;
|
||||
workOrder.notes = reason ? `${workOrder.notes || ''}\n[CANCELLED] ${reason}` : workOrder.notes;
|
||||
workOrder.updatedBy = userId;
|
||||
|
||||
@ -612,7 +612,7 @@ export class WorkOrderService {
|
||||
/**
|
||||
* Update a part
|
||||
*/
|
||||
async updatePart(tenantId: string, partId: string, dto: Partial<AddPartDto>, userId?: string): Promise<WorkOrderPart | null> {
|
||||
async updatePart(tenantId: string, partId: string, dto: Partial<AddPartDto>, _userId?: string): Promise<WorkOrderPart | null> {
|
||||
const part = await this.partRepository.findOne({ where: { id: partId, tenantId } });
|
||||
if (!part) return null;
|
||||
|
||||
@ -625,7 +625,6 @@ export class WorkOrderService {
|
||||
if (part.unitCost && part.quantityUsed) {
|
||||
part.totalCost = part.unitCost * part.quantityUsed;
|
||||
}
|
||||
part.updatedBy = userId;
|
||||
|
||||
const savedPart = await this.partRepository.save(part);
|
||||
await this.recalculatePartsCost(part.workOrderId);
|
||||
@ -636,7 +635,7 @@ export class WorkOrderService {
|
||||
/**
|
||||
* Remove a part from work order
|
||||
*/
|
||||
async removePart(tenantId: string, partId: string, userId?: string): Promise<boolean> {
|
||||
async removePart(tenantId: string, partId: string, _userId?: string): Promise<boolean> {
|
||||
const part = await this.partRepository.findOne({ where: { id: partId, tenantId } });
|
||||
if (!part) return false;
|
||||
|
||||
@ -657,7 +656,7 @@ export class WorkOrderService {
|
||||
where: {
|
||||
tenantId,
|
||||
deletedAt: undefined,
|
||||
status: In([WorkOrderStatus.DRAFT, WorkOrderStatus.SCHEDULED, WorkOrderStatus.IN_PROGRESS]),
|
||||
status: In(['draft' as WorkOrderStatus, 'scheduled' as WorkOrderStatus, 'in_progress' as WorkOrderStatus]),
|
||||
scheduledEndDate: LessThanOrEqual(now),
|
||||
},
|
||||
relations: ['asset'],
|
||||
|
||||
Loading…
Reference in New Issue
Block a user