217 lines
6.4 KiB
TypeScript
217 lines
6.4 KiB
TypeScript
/**
|
|
* Service Order Controller
|
|
* Mecánicas Diesel - ERP Suite
|
|
*
|
|
* REST API endpoints for service orders.
|
|
*/
|
|
|
|
import { Router, Request, Response, NextFunction } from 'express';
|
|
import { DataSource } from 'typeorm';
|
|
import { ServiceOrderService, ServiceOrderFilters } from '../services/service-order.service';
|
|
import { ServiceOrderStatus, ServiceOrderPriority } from '../entities/service-order.entity';
|
|
import { OrderItemType } from '../entities/order-item.entity';
|
|
|
|
// Middleware type for tenant extraction
|
|
interface TenantRequest extends Request {
|
|
tenantId?: string;
|
|
userId?: string;
|
|
}
|
|
|
|
export function createServiceOrderController(dataSource: DataSource): Router {
|
|
const router = Router();
|
|
const service = new ServiceOrderService(dataSource);
|
|
|
|
// Middleware to extract tenant from request
|
|
const extractTenant = (req: TenantRequest, res: Response, next: NextFunction) => {
|
|
const tenantId = req.headers['x-tenant-id'] as string;
|
|
if (!tenantId) {
|
|
return res.status(400).json({ error: 'Tenant ID is required' });
|
|
}
|
|
req.tenantId = tenantId;
|
|
req.userId = req.headers['x-user-id'] as string;
|
|
next();
|
|
};
|
|
|
|
router.use(extractTenant);
|
|
|
|
/**
|
|
* Create a new service order
|
|
* POST /api/service-orders
|
|
*/
|
|
router.post('/', async (req: TenantRequest, res: Response) => {
|
|
try {
|
|
const order = await service.create(req.tenantId!, req.body, req.userId);
|
|
res.status(201).json(order);
|
|
} catch (error) {
|
|
res.status(400).json({ error: (error as Error).message });
|
|
}
|
|
});
|
|
|
|
/**
|
|
* List service orders with filters
|
|
* GET /api/service-orders
|
|
*/
|
|
router.get('/', async (req: TenantRequest, res: Response) => {
|
|
try {
|
|
const filters: ServiceOrderFilters = {
|
|
status: req.query.status as ServiceOrderStatus,
|
|
priority: req.query.priority as ServiceOrderPriority,
|
|
customerId: req.query.customerId as string,
|
|
vehicleId: req.query.vehicleId as string,
|
|
assignedTo: req.query.assignedTo as string,
|
|
bayId: req.query.bayId as string,
|
|
search: req.query.search as string,
|
|
fromDate: req.query.fromDate ? new Date(req.query.fromDate as string) : undefined,
|
|
toDate: req.query.toDate ? new Date(req.query.toDate as string) : undefined,
|
|
};
|
|
|
|
const pagination = {
|
|
page: parseInt(req.query.page as string, 10) || 1,
|
|
limit: Math.min(parseInt(req.query.limit as string, 10) || 20, 100),
|
|
};
|
|
|
|
const result = await service.findAll(req.tenantId!, filters, pagination);
|
|
res.json(result);
|
|
} catch (error) {
|
|
res.status(500).json({ error: (error as Error).message });
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Get orders grouped by status (Kanban)
|
|
* GET /api/service-orders/kanban
|
|
*/
|
|
router.get('/kanban', async (req: TenantRequest, res: Response) => {
|
|
try {
|
|
const result = await service.getOrdersByStatus(req.tenantId!);
|
|
res.json(result);
|
|
} catch (error) {
|
|
res.status(500).json({ error: (error as Error).message });
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Get dashboard statistics
|
|
* GET /api/service-orders/stats
|
|
*/
|
|
router.get('/stats', async (req: TenantRequest, res: Response) => {
|
|
try {
|
|
const stats = await service.getDashboardStats(req.tenantId!);
|
|
res.json(stats);
|
|
} catch (error) {
|
|
res.status(500).json({ error: (error as Error).message });
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Get a single service order
|
|
* GET /api/service-orders/:id
|
|
*/
|
|
router.get('/:id', async (req: TenantRequest, res: Response) => {
|
|
try {
|
|
const order = await service.findById(req.tenantId!, req.params.id);
|
|
if (!order) {
|
|
return res.status(404).json({ error: 'Service order not found' });
|
|
}
|
|
res.json(order);
|
|
} catch (error) {
|
|
res.status(500).json({ error: (error as Error).message });
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Get by order number
|
|
* GET /api/service-orders/number/:orderNumber
|
|
*/
|
|
router.get('/number/:orderNumber', async (req: TenantRequest, res: Response) => {
|
|
try {
|
|
const order = await service.findByOrderNumber(req.tenantId!, req.params.orderNumber);
|
|
if (!order) {
|
|
return res.status(404).json({ error: 'Service order not found' });
|
|
}
|
|
res.json(order);
|
|
} catch (error) {
|
|
res.status(500).json({ error: (error as Error).message });
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Update service order
|
|
* PATCH /api/service-orders/:id
|
|
*/
|
|
router.patch('/:id', async (req: TenantRequest, res: Response) => {
|
|
try {
|
|
const order = await service.update(req.tenantId!, req.params.id, req.body);
|
|
if (!order) {
|
|
return res.status(404).json({ error: 'Service order not found' });
|
|
}
|
|
res.json(order);
|
|
} catch (error) {
|
|
res.status(400).json({ error: (error as Error).message });
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Add item to order
|
|
* POST /api/service-orders/:id/items
|
|
*/
|
|
router.post('/:id/items', async (req: TenantRequest, res: Response) => {
|
|
try {
|
|
const item = await service.addItem(req.tenantId!, req.params.id, req.body);
|
|
if (!item) {
|
|
return res.status(404).json({ error: 'Service order not found' });
|
|
}
|
|
res.status(201).json(item);
|
|
} catch (error) {
|
|
res.status(400).json({ error: (error as Error).message });
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Get order items
|
|
* GET /api/service-orders/:id/items
|
|
*/
|
|
router.get('/:id/items', async (req: TenantRequest, res: Response) => {
|
|
try {
|
|
const items = await service.getItems(req.params.id);
|
|
res.json(items);
|
|
} catch (error) {
|
|
res.status(500).json({ error: (error as Error).message });
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Update order item
|
|
* PATCH /api/service-orders/:id/items/:itemId
|
|
*/
|
|
router.patch('/:id/items/:itemId', async (req: TenantRequest, res: Response) => {
|
|
try {
|
|
const item = await service.updateItem(req.params.itemId, req.body);
|
|
if (!item) {
|
|
return res.status(404).json({ error: 'Item not found' });
|
|
}
|
|
res.json(item);
|
|
} catch (error) {
|
|
res.status(400).json({ error: (error as Error).message });
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Remove order item
|
|
* DELETE /api/service-orders/:id/items/:itemId
|
|
*/
|
|
router.delete('/:id/items/:itemId', async (req: TenantRequest, res: Response) => {
|
|
try {
|
|
const success = await service.removeItem(req.params.itemId);
|
|
if (!success) {
|
|
return res.status(404).json({ error: 'Item not found' });
|
|
}
|
|
res.status(204).send();
|
|
} catch (error) {
|
|
res.status(500).json({ error: (error as Error).message });
|
|
}
|
|
});
|
|
|
|
return router;
|
|
}
|