feat: add TCO API endpoint (refs #15)
- Add GET /api/vehicles/:id/tco route - Add getTCO controller method with error handling - Returns 200 with TCO data, 404 for not found, 403 for unauthorized 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -166,20 +166,20 @@ export class VehiclesController {
|
|||||||
try {
|
try {
|
||||||
const userId = (request as any).user.sub;
|
const userId = (request as any).user.sub;
|
||||||
const { id } = request.params;
|
const { id } = request.params;
|
||||||
|
|
||||||
await this.vehiclesService.deleteVehicle(id, userId);
|
await this.vehiclesService.deleteVehicle(id, userId);
|
||||||
|
|
||||||
return reply.code(204).send();
|
return reply.code(204).send();
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
logger.error('Error deleting vehicle', { error, vehicleId: request.params.id, userId: (request as any).user?.sub });
|
logger.error('Error deleting vehicle', { error, vehicleId: request.params.id, userId: (request as any).user?.sub });
|
||||||
|
|
||||||
if (error.message === 'Vehicle not found' || error.message === 'Unauthorized') {
|
if (error.message === 'Vehicle not found' || error.message === 'Unauthorized') {
|
||||||
return reply.code(404).send({
|
return reply.code(404).send({
|
||||||
error: 'Not Found',
|
error: 'Not Found',
|
||||||
message: 'Vehicle not found'
|
message: 'Vehicle not found'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return reply.code(500).send({
|
return reply.code(500).send({
|
||||||
error: 'Internal server error',
|
error: 'Internal server error',
|
||||||
message: 'Failed to delete vehicle'
|
message: 'Failed to delete vehicle'
|
||||||
@@ -187,6 +187,37 @@ export class VehiclesController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getTCO(request: FastifyRequest<{ Params: VehicleParams }>, reply: FastifyReply) {
|
||||||
|
try {
|
||||||
|
const userId = (request as any).user.sub;
|
||||||
|
const { id } = request.params;
|
||||||
|
|
||||||
|
const tco = await this.vehiclesService.getTCO(id, userId);
|
||||||
|
return reply.code(200).send(tco);
|
||||||
|
} catch (error: any) {
|
||||||
|
logger.error('Error getting vehicle TCO', { error, vehicleId: request.params.id, userId: (request as any).user?.sub });
|
||||||
|
|
||||||
|
if (error.statusCode === 404 || error.message === 'Vehicle not found') {
|
||||||
|
return reply.code(404).send({
|
||||||
|
error: 'Not Found',
|
||||||
|
message: 'Vehicle not found'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error.statusCode === 403 || error.message === 'Unauthorized') {
|
||||||
|
return reply.code(403).send({
|
||||||
|
error: 'Forbidden',
|
||||||
|
message: 'Not authorized to access this vehicle'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return reply.code(500).send({
|
||||||
|
error: 'Internal server error',
|
||||||
|
message: 'Failed to calculate TCO'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async getDropdownMakes(request: FastifyRequest<{ Querystring: { year: number } }>, reply: FastifyReply) {
|
async getDropdownMakes(request: FastifyRequest<{ Querystring: { year: number } }>, reply: FastifyReply) {
|
||||||
try {
|
try {
|
||||||
const { year } = request.query;
|
const { year } = request.query;
|
||||||
|
|||||||
@@ -100,6 +100,12 @@ export const vehiclesRoutes: FastifyPluginAsync = async (
|
|||||||
handler: vehiclesController.deleteImage.bind(vehiclesController)
|
handler: vehiclesController.deleteImage.bind(vehiclesController)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// GET /api/vehicles/:id/tco - Get vehicle Total Cost of Ownership
|
||||||
|
fastify.get<{ Params: VehicleParams }>('/vehicles/:id/tco', {
|
||||||
|
preHandler: [fastify.authenticate],
|
||||||
|
handler: vehiclesController.getTCO.bind(vehiclesController)
|
||||||
|
});
|
||||||
|
|
||||||
// Dynamic :id routes MUST come last to avoid matching specific paths like "dropdown"
|
// Dynamic :id routes MUST come last to avoid matching specific paths like "dropdown"
|
||||||
// GET /api/vehicles/:id - Get specific vehicle
|
// GET /api/vehicles/:id - Get specific vehicle
|
||||||
fastify.get<{ Params: VehicleParams }>('/vehicles/:id', {
|
fastify.get<{ Params: VehicleParams }>('/vehicles/:id', {
|
||||||
|
|||||||
Reference in New Issue
Block a user