user permition

This commit is contained in:
natib21
2026-07-07 10:00:48 +00:00
parent 03043bde7a
commit b300fd1de5
7 changed files with 100 additions and 56 deletions

View File

@@ -13,7 +13,8 @@ import {
} from '@nestjs/common'; } from '@nestjs/common';
import { AnyFilesInterceptor } from '@nestjs/platform-express'; import { AnyFilesInterceptor } from '@nestjs/platform-express';
import { ApiBearerAuth, ApiConsumes, ApiOperation, ApiTags } from '@nestjs/swagger'; import { ApiBearerAuth, ApiConsumes, ApiOperation, ApiTags } from '@nestjs/swagger';
import { FleetManage, FleetView } from '../../common/booking-guards'; import { BookingStaff } from '../../common/booking-guards';
import { FREIGHT_PERMS } from '../../seed/freight-permissions.registry';
import { DriversService } from './drivers.service'; import { DriversService } from './drivers.service';
import { CreateDriverDto } from './dto/create-driver.dto'; import { CreateDriverDto } from './dto/create-driver.dto';
import { UpdateDriverDto } from './dto/update-driver.dto'; import { UpdateDriverDto } from './dto/update-driver.dto';
@@ -22,7 +23,7 @@ import { FleetHistoryService } from '../fleet-history/fleet-history.service';
@ApiTags('drivers') @ApiTags('drivers')
@ApiBearerAuth() @ApiBearerAuth()
@Controller('drivers') @Controller('drivers')
@FleetView() @BookingStaff(FREIGHT_PERMS.drivers.view)
export class DriversController { export class DriversController {
constructor( constructor(
private readonly driversService: DriversService, private readonly driversService: DriversService,
@@ -30,7 +31,7 @@ export class DriversController {
) {} ) {}
@Post() @Post()
@FleetManage() @BookingStaff(FREIGHT_PERMS.drivers.create)
@ApiOperation({ summary: 'Create a new driver' }) @ApiOperation({ summary: 'Create a new driver' })
create(@Body() createDriverDto: CreateDriverDto) { create(@Body() createDriverDto: CreateDriverDto) {
return this.driversService.create(createDriverDto); return this.driversService.create(createDriverDto);
@@ -69,7 +70,7 @@ export class DriversController {
} }
@Post(':id/documents') @Post(':id/documents')
@FleetManage() @BookingStaff(FREIGHT_PERMS.drivers.update)
@ApiConsumes('multipart/form-data') @ApiConsumes('multipart/form-data')
@UseInterceptors(AnyFilesInterceptor()) @UseInterceptors(AnyFilesInterceptor())
@ApiOperation({ summary: 'Upload driver documents (code driver_docs)' }) @ApiOperation({ summary: 'Upload driver documents (code driver_docs)' })
@@ -87,14 +88,14 @@ export class DriversController {
} }
@Delete(':id/documents/:fileId') @Delete(':id/documents/:fileId')
@FleetManage() @BookingStaff(FREIGHT_PERMS.drivers.update)
@ApiOperation({ summary: 'Delete a driver document' }) @ApiOperation({ summary: 'Delete a driver document' })
removeDocument(@Param('fileId', ParseUUIDPipe) fileId: string) { removeDocument(@Param('fileId', ParseUUIDPipe) fileId: string) {
return this.driversService.removeDocument(fileId); return this.driversService.removeDocument(fileId);
} }
@Patch(':id') @Patch(':id')
@FleetManage() @BookingStaff(FREIGHT_PERMS.drivers.update)
@ApiOperation({ summary: 'Update a driver' }) @ApiOperation({ summary: 'Update a driver' })
update( update(
@Param('id', ParseUUIDPipe) id: string, @Param('id', ParseUUIDPipe) id: string,
@@ -104,7 +105,7 @@ export class DriversController {
} }
@Delete(':id') @Delete(':id')
@FleetManage() @BookingStaff(FREIGHT_PERMS.drivers.delete)
@ApiOperation({ summary: 'Delete a driver' }) @ApiOperation({ summary: 'Delete a driver' })
remove(@Param('id', ParseUUIDPipe) id: string) { remove(@Param('id', ParseUUIDPipe) id: string) {
return this.driversService.remove(id); return this.driversService.remove(id);

View File

@@ -14,7 +14,8 @@ import {
} from '@nestjs/common'; } from '@nestjs/common';
import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger'; import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger';
import { TrainSchedulingManage, TrainSchedulingView } from '../../common/booking-guards'; import { BookingStaff } from '../../common/booking-guards';
import { FREIGHT_PERMS } from '../../seed/freight-permissions.registry';
import { CreateFirstMileDto } from './dto/create-first-mile.dto'; import { CreateFirstMileDto } from './dto/create-first-mile.dto';
import { UpdateFirstMileDto } from './dto/update-first-mile.dto'; import { UpdateFirstMileDto } from './dto/update-first-mile.dto';
@@ -27,7 +28,7 @@ import { FirstMileInvoiceService } from './first-mile-invoice.service';
@ApiTags('first-mile') @ApiTags('first-mile')
@ApiBearerAuth() @ApiBearerAuth()
@Controller('first-mile') @Controller('first-mile')
@TrainSchedulingView() @BookingStaff(FREIGHT_PERMS.firstMile.view)
export class FirstMileController { export class FirstMileController {
constructor( constructor(
private readonly firstMileService: FirstMileService, private readonly firstMileService: FirstMileService,
@@ -63,27 +64,28 @@ export class FirstMileController {
} }
@Get('acceptitem/:id') @Get('acceptitem/:id')
@BookingStaff(FREIGHT_PERMS.firstMile.accept)
@ApiOperation({ summary: 'Get a first-mile accep by ID' }) @ApiOperation({ summary: 'Get a first-mile accep by ID' })
acceptItem(@Param('id', ParseUUIDPipe) id: string) { acceptItem(@Param('id', ParseUUIDPipe) id: string) {
return this.firstMileService.acceptBooking(id); return this.firstMileService.acceptBooking(id);
} }
@Post('accept/:reference') @Post('accept/:reference')
@TrainSchedulingManage() @BookingStaff(FREIGHT_PERMS.firstMile.accept)
@ApiOperation({ summary: 'Accept a paid booking and create a first-mile leg' }) @ApiOperation({ summary: 'Accept a paid booking and create a first-mile leg' })
acceptBooking(@Param('reference') reference: string) { acceptBooking(@Param('reference') reference: string) {
return this.firstMileService.acceptBookingByReference(reference); return this.firstMileService.acceptBookingByReference(reference);
} }
@Post() @Post()
@TrainSchedulingManage() @BookingStaff(FREIGHT_PERMS.firstMile.create)
@ApiOperation({ summary: 'Create a first-mile leg' }) @ApiOperation({ summary: 'Create a first-mile leg' })
create(@Body() dto: CreateFirstMileDto) { create(@Body() dto: CreateFirstMileDto) {
return this.firstMileService.create(dto); return this.firstMileService.create(dto);
} }
@Patch(':id') @Patch(':id')
@TrainSchedulingManage() @BookingStaff(FREIGHT_PERMS.firstMile.update)
@ApiOperation({ summary: 'Update a first-mile leg' }) @ApiOperation({ summary: 'Update a first-mile leg' })
async update(@Param('id', ParseUUIDPipe) id: string, @Body() dto: UpdateFirstMileDto) { async update(@Param('id', ParseUUIDPipe) id: string, @Body() dto: UpdateFirstMileDto) {
// No invoice side-effects — invoices are generated only via the explicit // No invoice side-effects — invoices are generated only via the explicit
@@ -92,7 +94,7 @@ export class FirstMileController {
} }
@Post(':id/invoice') @Post(':id/invoice')
@TrainSchedulingManage() @BookingStaff(FREIGHT_PERMS.firstMile.generateInvoice)
@ApiOperation({ summary: 'Generate the first-mile delivery-fee invoice' }) @ApiOperation({ summary: 'Generate the first-mile delivery-fee invoice' })
async generateInvoice(@Param('id', ParseUUIDPipe) id: string) { async generateInvoice(@Param('id', ParseUUIDPipe) id: string) {
const record = await this.firstMileService.findById(id); const record = await this.firstMileService.findById(id);
@@ -106,7 +108,7 @@ export class FirstMileController {
} }
@Post(':id/vehicles') @Post(':id/vehicles')
@TrainSchedulingManage() @BookingStaff(FREIGHT_PERMS.firstMile.assignVehicles)
@ApiOperation({ summary: 'Set the vehicles assigned to a first-mile pickup (multi-truck)' }) @ApiOperation({ summary: 'Set the vehicles assigned to a first-mile pickup (multi-truck)' })
async setVehicles( async setVehicles(
@Param('id', ParseUUIDPipe) id: string, @Param('id', ParseUUIDPipe) id: string,
@@ -116,7 +118,7 @@ export class FirstMileController {
} }
@Post(':id/distances') @Post(':id/distances')
@TrainSchedulingManage() @BookingStaff(FREIGHT_PERMS.firstMile.setDistances)
@ApiOperation({ summary: 'Set per-vehicle actual distances (does not generate an invoice)' }) @ApiOperation({ summary: 'Set per-vehicle actual distances (does not generate an invoice)' })
async setDistances( async setDistances(
@Param('id', ParseUUIDPipe) id: string, @Param('id', ParseUUIDPipe) id: string,
@@ -126,7 +128,7 @@ export class FirstMileController {
} }
@Delete(':id') @Delete(':id')
@TrainSchedulingManage() @BookingStaff(FREIGHT_PERMS.firstMile.delete)
@HttpCode(HttpStatus.NO_CONTENT) @HttpCode(HttpStatus.NO_CONTENT)
@ApiOperation({ summary: 'Soft-delete a first-mile leg' }) @ApiOperation({ summary: 'Soft-delete a first-mile leg' })
remove(@Param('id', ParseUUIDPipe) id: string) { remove(@Param('id', ParseUUIDPipe) id: string) {

View File

@@ -1,26 +1,40 @@
import { Controller, Post, Get, Body, Param, Query } from '@nestjs/common'; import { Controller, Post, Get, Body, Param, Query } from '@nestjs/common';
import { ApiTags, ApiOperation } from '@nestjs/swagger'; import { ApiBearerAuth, ApiTags, ApiOperation } from '@nestjs/swagger';
import { BookingStaff } from '../../common/booking-guards';
import { FREIGHT_PERMS } from '../../seed/freight-permissions.registry';
import { FuelService } from './fuel.service'; import { FuelService } from './fuel.service';
import { CreateFuelPurchaseDto } from './dto/create-fuel-purchase.dto'; import { CreateFuelPurchaseDto } from './dto/create-fuel-purchase.dto';
// Stats feed the Financial Reports + Fleet Dashboard pages, so their viewers may
// read them without full fuel access.
const FUEL_STATS_PERMS = [
FREIGHT_PERMS.fuel.view,
FREIGHT_PERMS.fleetReports.view,
FREIGHT_PERMS.fleetDashboard.view,
];
@ApiTags('Fuel Management') @ApiTags('Fuel Management')
@ApiBearerAuth()
@Controller('fuel') @Controller('fuel')
export class FuelController { export class FuelController {
constructor(private readonly fuelService: FuelService) {} constructor(private readonly fuelService: FuelService) {}
@Post('purchases') @Post('purchases')
@BookingStaff(FREIGHT_PERMS.fuel.create)
@ApiOperation({ summary: 'Record fuel purchase' }) @ApiOperation({ summary: 'Record fuel purchase' })
async recordFuelPurchase(@Body() dto: CreateFuelPurchaseDto) { async recordFuelPurchase(@Body() dto: CreateFuelPurchaseDto) {
return this.fuelService.recordFuelPurchase(dto); return this.fuelService.recordFuelPurchase(dto);
} }
@Get('purchases') @Get('purchases')
@BookingStaff(FREIGHT_PERMS.fuel.view)
@ApiOperation({ summary: 'Get all fuel purchases' }) @ApiOperation({ summary: 'Get all fuel purchases' })
async getAllFuelPurchases() { async getAllFuelPurchases() {
return this.fuelService.getAllFuelPurchases(); return this.fuelService.getAllFuelPurchases();
} }
@Get('purchases/:vehicleId') @Get('purchases/:vehicleId')
@BookingStaff(FREIGHT_PERMS.fuel.view)
@ApiOperation({ summary: 'Get fuel purchases for vehicle' }) @ApiOperation({ summary: 'Get fuel purchases for vehicle' })
async getFuelPurchases( async getFuelPurchases(
@Param('vehicleId') vehicleId: string, @Param('vehicleId') vehicleId: string,
@@ -35,6 +49,7 @@ export class FuelController {
} }
@Get('consumption/:vehicleId/:month') @Get('consumption/:vehicleId/:month')
@BookingStaff(FREIGHT_PERMS.fuel.view)
@ApiOperation({ summary: 'Get monthly fuel consumption' }) @ApiOperation({ summary: 'Get monthly fuel consumption' })
async getMonthlyConsumption( async getMonthlyConsumption(
@Param('vehicleId') vehicleId: string, @Param('vehicleId') vehicleId: string,
@@ -44,12 +59,14 @@ export class FuelController {
} }
@Get('stats') @Get('stats')
@BookingStaff(FUEL_STATS_PERMS)
@ApiOperation({ summary: 'Get fleet-wide fuel statistics' }) @ApiOperation({ summary: 'Get fleet-wide fuel statistics' })
async getFleetFuelStats(@Query('months') months: number = 12) { async getFleetFuelStats(@Query('months') months: number = 12) {
return this.fuelService.getFleetFuelStats(months); return this.fuelService.getFleetFuelStats(months);
} }
@Get('stats/:vehicleId') @Get('stats/:vehicleId')
@BookingStaff(FUEL_STATS_PERMS)
@ApiOperation({ summary: 'Get fuel statistics for vehicle' }) @ApiOperation({ summary: 'Get fuel statistics for vehicle' })
async getVehicleFuelStats( async getVehicleFuelStats(
@Param('vehicleId') vehicleId: string, @Param('vehicleId') vehicleId: string,

View File

@@ -14,7 +14,8 @@ import {
} from '@nestjs/common'; } from '@nestjs/common';
import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger'; import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger';
import { TrainSchedulingManage, TrainSchedulingView } from '../../common/booking-guards'; import { BookingStaff } from '../../common/booking-guards';
import { FREIGHT_PERMS } from '../../seed/freight-permissions.registry';
import { CreateLastMileDto } from './dto/create-last-mile.dto'; import { CreateLastMileDto } from './dto/create-last-mile.dto';
import { UpdateLastMileDto } from './dto/update-last-mile.dto'; import { UpdateLastMileDto } from './dto/update-last-mile.dto';
@@ -27,7 +28,7 @@ import { LastMileInvoiceService } from './last-mile-invoice.service';
@ApiTags('last-mile') @ApiTags('last-mile')
@ApiBearerAuth() @ApiBearerAuth()
@Controller('last-mile') @Controller('last-mile')
@TrainSchedulingView() @BookingStaff(FREIGHT_PERMS.lastMile.view)
export class LastMileController { export class LastMileController {
constructor( constructor(
private readonly lastMileService: LastMileService, private readonly lastMileService: LastMileService,
@@ -63,21 +64,21 @@ export class LastMileController {
} }
@Post('accept/:reference') @Post('accept/:reference')
@TrainSchedulingManage() @BookingStaff(FREIGHT_PERMS.lastMile.accept)
@ApiOperation({ summary: 'Accept a paid booking and create a last-mile leg' }) @ApiOperation({ summary: 'Accept a paid booking and create a last-mile leg' })
acceptBooking(@Param('reference') reference: string) { acceptBooking(@Param('reference') reference: string) {
return this.lastMileService.acceptBookingByReference(reference); return this.lastMileService.acceptBookingByReference(reference);
} }
@Post() @Post()
@TrainSchedulingManage() @BookingStaff(FREIGHT_PERMS.lastMile.create)
@ApiOperation({ summary: 'Create a last-mile leg' }) @ApiOperation({ summary: 'Create a last-mile leg' })
create(@Body() dto: CreateLastMileDto) { create(@Body() dto: CreateLastMileDto) {
return this.lastMileService.create(dto); return this.lastMileService.create(dto);
} }
@Patch(':id') @Patch(':id')
@TrainSchedulingManage() @BookingStaff(FREIGHT_PERMS.lastMile.update)
@ApiOperation({ summary: 'Update a last-mile leg' }) @ApiOperation({ summary: 'Update a last-mile leg' })
async update(@Param('id', ParseUUIDPipe) id: string, @Body() dto: UpdateLastMileDto) { async update(@Param('id', ParseUUIDPipe) id: string, @Body() dto: UpdateLastMileDto) {
// No invoice side-effects here — invoices are generated only via the // No invoice side-effects here — invoices are generated only via the
@@ -86,7 +87,7 @@ export class LastMileController {
} }
@Delete(':id') @Delete(':id')
@TrainSchedulingManage() @BookingStaff(FREIGHT_PERMS.lastMile.delete)
@HttpCode(HttpStatus.NO_CONTENT) @HttpCode(HttpStatus.NO_CONTENT)
@ApiOperation({ summary: 'Soft-delete a last-mile leg' }) @ApiOperation({ summary: 'Soft-delete a last-mile leg' })
remove(@Param('id', ParseUUIDPipe) id: string) { remove(@Param('id', ParseUUIDPipe) id: string) {
@@ -95,7 +96,7 @@ export class LastMileController {
@Post(':id/vehicles') @Post(':id/vehicles')
@TrainSchedulingManage() @BookingStaff(FREIGHT_PERMS.lastMile.assignVehicles)
@ApiOperation({ summary: 'Set the vehicles assigned to a last-mile delivery (multi-truck)' }) @ApiOperation({ summary: 'Set the vehicles assigned to a last-mile delivery (multi-truck)' })
async setVehicles( async setVehicles(
@Param('id', ParseUUIDPipe) id: string, @Param('id', ParseUUIDPipe) id: string,
@@ -105,7 +106,7 @@ export class LastMileController {
} }
@Post(':id/distances') @Post(':id/distances')
@TrainSchedulingManage() @BookingStaff(FREIGHT_PERMS.lastMile.setDistances)
@ApiOperation({ summary: 'Set per-vehicle actual distances (does not generate an invoice)' }) @ApiOperation({ summary: 'Set per-vehicle actual distances (does not generate an invoice)' })
async setDistances( async setDistances(
@Param('id', ParseUUIDPipe) id: string, @Param('id', ParseUUIDPipe) id: string,
@@ -115,7 +116,7 @@ export class LastMileController {
} }
@Post(':id/invoice') @Post(':id/invoice')
@TrainSchedulingManage() @BookingStaff(FREIGHT_PERMS.lastMile.generateInvoice)
@ApiOperation({ summary: 'Generate the delivery-fee invoice for a last-mile leg' }) @ApiOperation({ summary: 'Generate the delivery-fee invoice for a last-mile leg' })
async generateInvoice(@Param('id', ParseUUIDPipe) id: string) { async generateInvoice(@Param('id', ParseUUIDPipe) id: string) {
const record = await this.lastMileService.findById(id); const record = await this.lastMileService.findById(id);

View File

@@ -1,5 +1,7 @@
import { Controller, Post, Get, Patch, Delete, Body, Param, Query } from '@nestjs/common'; import { Controller, Post, Get, Patch, Delete, Body, Param, Query } from '@nestjs/common';
import { ApiTags, ApiOperation } from '@nestjs/swagger'; import { ApiBearerAuth, ApiTags, ApiOperation } from '@nestjs/swagger';
import { BookingStaff } from '../../common/booking-guards';
import { FREIGHT_PERMS } from '../../seed/freight-permissions.registry';
import { MaintenanceService } from './maintenance.service'; import { MaintenanceService } from './maintenance.service';
import { MaintenanceDepthService } from './maintenance-depth.service'; import { MaintenanceDepthService } from './maintenance-depth.service';
import { CreateMaintenanceScheduleDto, CreateMaintenanceCostDto, UpdateMaintenanceScheduleDto } from './dto/create-maintenance.dto'; import { CreateMaintenanceScheduleDto, CreateMaintenanceCostDto, UpdateMaintenanceScheduleDto } from './dto/create-maintenance.dto';
@@ -13,6 +15,7 @@ import {
import { WorkOrderStatus } from './entities/work-order.entity'; import { WorkOrderStatus } from './entities/work-order.entity';
@ApiTags('Maintenance Management') @ApiTags('Maintenance Management')
@ApiBearerAuth()
@Controller('maintenance') @Controller('maintenance')
export class MaintenanceController { export class MaintenanceController {
constructor( constructor(
@@ -21,42 +24,49 @@ export class MaintenanceController {
) {} ) {}
@Post('schedules') @Post('schedules')
@BookingStaff(FREIGHT_PERMS.maintenance.create)
@ApiOperation({ summary: 'Schedule maintenance' }) @ApiOperation({ summary: 'Schedule maintenance' })
async scheduleMaintenanceAsync(@Body() dto: CreateMaintenanceScheduleDto) { async scheduleMaintenanceAsync(@Body() dto: CreateMaintenanceScheduleDto) {
return this.maintenanceService.scheduleMaintenanceAsync(dto); return this.maintenanceService.scheduleMaintenanceAsync(dto);
} }
@Post('costs') @Post('costs')
@BookingStaff(FREIGHT_PERMS.maintenance.create)
@ApiOperation({ summary: 'Record maintenance cost' }) @ApiOperation({ summary: 'Record maintenance cost' })
async recordCost(@Body() dto: CreateMaintenanceCostDto) { async recordCost(@Body() dto: CreateMaintenanceCostDto) {
return this.maintenanceService.recordMaintenanceCost(dto); return this.maintenanceService.recordMaintenanceCost(dto);
} }
@Patch('schedules/:id') @Patch('schedules/:id')
@BookingStaff(FREIGHT_PERMS.maintenance.update)
@ApiOperation({ summary: 'Update maintenance schedule' }) @ApiOperation({ summary: 'Update maintenance schedule' })
async updateSchedule(@Param('id') id: string, @Body() dto: UpdateMaintenanceScheduleDto) { async updateSchedule(@Param('id') id: string, @Body() dto: UpdateMaintenanceScheduleDto) {
return this.maintenanceService.updateMaintenanceSchedule(id, dto); return this.maintenanceService.updateMaintenanceSchedule(id, dto);
} }
@Get('upcoming/:vehicleId') @Get('upcoming/:vehicleId')
@BookingStaff(FREIGHT_PERMS.maintenance.view)
@ApiOperation({ summary: 'Get upcoming maintenance' }) @ApiOperation({ summary: 'Get upcoming maintenance' })
async getUpcoming(@Param('vehicleId') vehicleId: string) { async getUpcoming(@Param('vehicleId') vehicleId: string) {
return this.maintenanceService.getUpcomingMaintenance(vehicleId); return this.maintenanceService.getUpcomingMaintenance(vehicleId);
} }
@Get('history/:vehicleId') @Get('history/:vehicleId')
@BookingStaff(FREIGHT_PERMS.maintenance.view)
@ApiOperation({ summary: 'Get maintenance history' }) @ApiOperation({ summary: 'Get maintenance history' })
async getHistory(@Param('vehicleId') vehicleId: string) { async getHistory(@Param('vehicleId') vehicleId: string) {
return this.maintenanceService.getMaintenanceHistory(vehicleId); return this.maintenanceService.getMaintenanceHistory(vehicleId);
} }
@Get('stats') @Get('stats')
@BookingStaff([FREIGHT_PERMS.maintenance.view, FREIGHT_PERMS.fleetReports.view, FREIGHT_PERMS.fleetDashboard.view])
@ApiOperation({ summary: 'Get fleet-wide maintenance statistics' }) @ApiOperation({ summary: 'Get fleet-wide maintenance statistics' })
async getFleetStats() { async getFleetStats() {
return this.maintenanceService.getFleetMaintenanceStats(); return this.maintenanceService.getFleetMaintenanceStats();
} }
@Get('stats/:vehicleId') @Get('stats/:vehicleId')
@BookingStaff([FREIGHT_PERMS.maintenance.view, FREIGHT_PERMS.fleetReports.view, FREIGHT_PERMS.fleetDashboard.view])
@ApiOperation({ summary: 'Get maintenance statistics' }) @ApiOperation({ summary: 'Get maintenance statistics' })
async getStats(@Param('vehicleId') vehicleId: string) { async getStats(@Param('vehicleId') vehicleId: string) {
return this.maintenanceService.getVehicleMaintenanceStats(vehicleId); return this.maintenanceService.getVehicleMaintenanceStats(vehicleId);
@@ -65,12 +75,14 @@ export class MaintenanceController {
// ---- Work Orders ---- // ---- Work Orders ----
@Post('work-orders') @Post('work-orders')
@BookingStaff(FREIGHT_PERMS.maintenance.create)
@ApiOperation({ summary: 'Create work order' }) @ApiOperation({ summary: 'Create work order' })
async createWorkOrder(@Body() dto: CreateWorkOrderDto) { async createWorkOrder(@Body() dto: CreateWorkOrderDto) {
return this.maintenanceDepthService.createWorkOrder(dto); return this.maintenanceDepthService.createWorkOrder(dto);
} }
@Get('work-orders') @Get('work-orders')
@BookingStaff(FREIGHT_PERMS.maintenance.view)
@ApiOperation({ summary: 'List work orders' }) @ApiOperation({ summary: 'List work orders' })
async listWorkOrders( async listWorkOrders(
@Query('vehicleId') vehicleId?: string, @Query('vehicleId') vehicleId?: string,
@@ -80,18 +92,21 @@ export class MaintenanceController {
} }
@Get('work-orders/:id') @Get('work-orders/:id')
@BookingStaff(FREIGHT_PERMS.maintenance.view)
@ApiOperation({ summary: 'Get work order' }) @ApiOperation({ summary: 'Get work order' })
async getWorkOrder(@Param('id') id: string) { async getWorkOrder(@Param('id') id: string) {
return this.maintenanceDepthService.findWorkOrderById(id); return this.maintenanceDepthService.findWorkOrderById(id);
} }
@Patch('work-orders/:id') @Patch('work-orders/:id')
@BookingStaff(FREIGHT_PERMS.maintenance.update)
@ApiOperation({ summary: 'Update work order' }) @ApiOperation({ summary: 'Update work order' })
async updateWorkOrder(@Param('id') id: string, @Body() dto: UpdateWorkOrderDto) { async updateWorkOrder(@Param('id') id: string, @Body() dto: UpdateWorkOrderDto) {
return this.maintenanceDepthService.updateWorkOrder(id, dto); return this.maintenanceDepthService.updateWorkOrder(id, dto);
} }
@Delete('work-orders/:id') @Delete('work-orders/:id')
@BookingStaff(FREIGHT_PERMS.maintenance.delete)
@ApiOperation({ summary: 'Delete work order' }) @ApiOperation({ summary: 'Delete work order' })
async deleteWorkOrder(@Param('id') id: string) { async deleteWorkOrder(@Param('id') id: string) {
return this.maintenanceDepthService.deleteWorkOrder(id); return this.maintenanceDepthService.deleteWorkOrder(id);
@@ -100,12 +115,14 @@ export class MaintenanceController {
// ---- Parts / Tires ---- // ---- Parts / Tires ----
@Post('parts') @Post('parts')
@BookingStaff(FREIGHT_PERMS.maintenance.create)
@ApiOperation({ summary: 'Create part' }) @ApiOperation({ summary: 'Create part' })
async createPart(@Body() dto: CreatePartDto) { async createPart(@Body() dto: CreatePartDto) {
return this.maintenanceDepthService.createPart(dto); return this.maintenanceDepthService.createPart(dto);
} }
@Get('parts') @Get('parts')
@BookingStaff(FREIGHT_PERMS.maintenance.view)
@ApiOperation({ summary: 'List parts / tire inventory' }) @ApiOperation({ summary: 'List parts / tire inventory' })
async listParts( async listParts(
@Query('category') category?: string, @Query('category') category?: string,
@@ -118,12 +135,14 @@ export class MaintenanceController {
} }
@Patch('parts/:id') @Patch('parts/:id')
@BookingStaff(FREIGHT_PERMS.maintenance.update)
@ApiOperation({ summary: 'Update part' }) @ApiOperation({ summary: 'Update part' })
async updatePart(@Param('id') id: string, @Body() dto: UpdatePartDto) { async updatePart(@Param('id') id: string, @Body() dto: UpdatePartDto) {
return this.maintenanceDepthService.updatePart(id, dto); return this.maintenanceDepthService.updatePart(id, dto);
} }
@Delete('parts/:id') @Delete('parts/:id')
@BookingStaff(FREIGHT_PERMS.maintenance.delete)
@ApiOperation({ summary: 'Delete part' }) @ApiOperation({ summary: 'Delete part' })
async deletePart(@Param('id') id: string) { async deletePart(@Param('id') id: string) {
return this.maintenanceDepthService.deletePart(id); return this.maintenanceDepthService.deletePart(id);
@@ -132,18 +151,21 @@ export class MaintenanceController {
// ---- Warranties ---- // ---- Warranties ----
@Post('warranties') @Post('warranties')
@BookingStaff(FREIGHT_PERMS.maintenance.create)
@ApiOperation({ summary: 'Create warranty' }) @ApiOperation({ summary: 'Create warranty' })
async createWarranty(@Body() dto: CreateWarrantyDto) { async createWarranty(@Body() dto: CreateWarrantyDto) {
return this.maintenanceDepthService.createWarranty(dto); return this.maintenanceDepthService.createWarranty(dto);
} }
@Get('warranties') @Get('warranties')
@BookingStaff(FREIGHT_PERMS.maintenance.view)
@ApiOperation({ summary: 'List warranties' }) @ApiOperation({ summary: 'List warranties' })
async listWarranties(@Query('vehicleId') vehicleId?: string) { async listWarranties(@Query('vehicleId') vehicleId?: string) {
return this.maintenanceDepthService.findWarranties({ vehicleId }); return this.maintenanceDepthService.findWarranties({ vehicleId });
} }
@Delete('warranties/:id') @Delete('warranties/:id')
@BookingStaff(FREIGHT_PERMS.maintenance.delete)
@ApiOperation({ summary: 'Delete warranty' }) @ApiOperation({ summary: 'Delete warranty' })
async deleteWarranty(@Param('id') id: string) { async deleteWarranty(@Param('id') id: string) {
return this.maintenanceDepthService.deleteWarranty(id); return this.maintenanceDepthService.deleteWarranty(id);

View File

@@ -10,7 +10,8 @@ import {
ParseUUIDPipe, ParseUUIDPipe,
} from '@nestjs/common'; } from '@nestjs/common';
import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger'; import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger';
import { FleetManage, FleetView } from '../../common/booking-guards'; import { BookingStaff } from '../../common/booking-guards';
import { FREIGHT_PERMS } from '../../seed/freight-permissions.registry';
import { VehiclesService } from './vehicles.service'; import { VehiclesService } from './vehicles.service';
import { CreateVehicleDto } from './dto/create-vehicle.dto'; import { CreateVehicleDto } from './dto/create-vehicle.dto';
import { UpdateVehicleDto } from './dto/update-vehicle.dto'; import { UpdateVehicleDto } from './dto/update-vehicle.dto';
@@ -19,7 +20,7 @@ import { FleetHistoryService } from '../fleet-history/fleet-history.service';
@ApiTags('vehicles') @ApiTags('vehicles')
@ApiBearerAuth() @ApiBearerAuth()
@Controller('vehicles') @Controller('vehicles')
@FleetView() @BookingStaff(FREIGHT_PERMS.vehicles.view)
export class VehiclesController { export class VehiclesController {
constructor( constructor(
private readonly vehiclesService: VehiclesService, private readonly vehiclesService: VehiclesService,
@@ -27,7 +28,7 @@ export class VehiclesController {
) {} ) {}
@Post() @Post()
@FleetManage() @BookingStaff(FREIGHT_PERMS.vehicles.create)
@ApiOperation({ summary: 'Create a new vehicle' }) @ApiOperation({ summary: 'Create a new vehicle' })
create(@Body() createVehicleDto: CreateVehicleDto) { create(@Body() createVehicleDto: CreateVehicleDto) {
return this.vehiclesService.create(createVehicleDto); return this.vehiclesService.create(createVehicleDto);
@@ -68,7 +69,7 @@ export class VehiclesController {
} }
@Patch(':id') @Patch(':id')
@FleetManage() @BookingStaff(FREIGHT_PERMS.vehicles.update)
@ApiOperation({ summary: 'Update a vehicle' }) @ApiOperation({ summary: 'Update a vehicle' })
update( update(
@Param('id', ParseUUIDPipe) id: string, @Param('id', ParseUUIDPipe) id: string,
@@ -78,7 +79,7 @@ export class VehiclesController {
} }
@Delete(':id') @Delete(':id')
@FleetManage() @BookingStaff(FREIGHT_PERMS.vehicles.delete)
@ApiOperation({ summary: 'Delete a vehicle' }) @ApiOperation({ summary: 'Delete a vehicle' })
remove(@Param('id', ParseUUIDPipe) id: string) { remove(@Param('id', ParseUUIDPipe) id: string) {
return this.vehiclesService.remove(id); return this.vehiclesService.remove(id);

View File

@@ -216,13 +216,13 @@ const buildSidebarSections = (demoItems: SidebarItem[]): SidebarSection[] => [
label: "First Mile", label: "First Mile",
href: "/dashboard/operations/first-mile", href: "/dashboard/operations/first-mile",
icon: <Truck />, icon: <Truck />,
permission: FREIGHT_PERMS.trainScheduling.view, permission: FREIGHT_PERMS.firstMile.view,
}, },
{ {
label: "Last Mile", label: "Last Mile",
href: "/dashboard/operations/last-mile", href: "/dashboard/operations/last-mile",
icon: <Truck />, icon: <Truck />,
permission: FREIGHT_PERMS.trainScheduling.view, permission: FREIGHT_PERMS.lastMile.view,
}, },
], ],
}, },
@@ -233,7 +233,7 @@ const buildSidebarSections = (demoItems: SidebarItem[]): SidebarSection[] => [
label: "Fleet Dashboard", label: "Fleet Dashboard",
href: "/dashboard/fleet-dashboard", href: "/dashboard/fleet-dashboard",
icon: <LayoutDashboard />, icon: <LayoutDashboard />,
permission: FREIGHT_PERMS.fleet.view, permission: FREIGHT_PERMS.fleetDashboard.view,
}, },
{ {
label: "Routes", label: "Routes",
@@ -263,43 +263,43 @@ const buildSidebarSections = (demoItems: SidebarItem[]): SidebarSection[] => [
label: "Vehicles", label: "Vehicles",
href: "/dashboard/vehicles", href: "/dashboard/vehicles",
icon: <Truck />, icon: <Truck />,
permission: FREIGHT_PERMS.fleet.view, permission: FREIGHT_PERMS.vehicles.view,
}, },
{ {
label: "Drivers", label: "Drivers",
href: "/dashboard/drivers", href: "/dashboard/drivers",
icon: <Users />, icon: <Users />,
permission: FREIGHT_PERMS.fleet.view, permission: FREIGHT_PERMS.drivers.view,
}, },
{ {
label: "Track Vehicles", label: "Track Vehicles",
href: "/dashboard/tracking", href: "/dashboard/tracking",
icon: <MapPin />, icon: <MapPin />,
permission: FREIGHT_PERMS.fleet.view, permission: FREIGHT_PERMS.tracking.view,
}, },
{ {
label: "Fuel Purchases", label: "Fuel Purchases",
href: "/dashboard/fuel-purchases", href: "/dashboard/fuel-purchases",
icon: <Truck />, icon: <Truck />,
permission: FREIGHT_PERMS.fleet.view, permission: FREIGHT_PERMS.fuel.view,
}, },
{ {
label: "Fuel Analytics", label: "Fuel Analytics",
href: "/dashboard/fuel-stats", href: "/dashboard/fuel-stats",
icon: <Truck />, icon: <Truck />,
permission: FREIGHT_PERMS.fleet.view, permission: FREIGHT_PERMS.fuel.view,
}, },
{ {
label: "Maintenance", label: "Maintenance",
href: "/dashboard/maintenance", href: "/dashboard/maintenance",
icon: <Truck />, icon: <Truck />,
permission: FREIGHT_PERMS.fleet.view, permission: FREIGHT_PERMS.maintenance.view,
}, },
{ {
label: "Work Orders", label: "Work Orders",
href: "/dashboard/work-orders", href: "/dashboard/work-orders",
icon: <SlidersHorizontal />, icon: <SlidersHorizontal />,
permission: FREIGHT_PERMS.fleet.view, permission: FREIGHT_PERMS.maintenance.view,
}, },
{ {
label: "Compliance & Alerts", label: "Compliance & Alerts",
@@ -323,7 +323,7 @@ const buildSidebarSections = (demoItems: SidebarItem[]): SidebarSection[] => [
label: "Financial Reports", label: "Financial Reports",
href: "/dashboard/financial-reports", href: "/dashboard/financial-reports",
icon: <Wallet />, icon: <Wallet />,
permission: FREIGHT_PERMS.fleet.view, permission: FREIGHT_PERMS.fleetReports.view,
}, },
// { // {
// label: "Containers", // label: "Containers",
@@ -896,7 +896,7 @@ const App = () => {
<Route <Route
path="operations/first-mile" path="operations/first-mile"
element={ element={
<RequirePermission permission={FREIGHT_PERMS.trainScheduling.view}> <RequirePermission permission={FREIGHT_PERMS.firstMile.view}>
<FirstMilePage /> <FirstMilePage />
</RequirePermission> </RequirePermission>
} }
@@ -904,7 +904,7 @@ const App = () => {
<Route <Route
path="operations/last-mile" path="operations/last-mile"
element={ element={
<RequirePermission permission={FREIGHT_PERMS.trainScheduling.view}> <RequirePermission permission={FREIGHT_PERMS.lastMile.view}>
<LastMilePage /> <LastMilePage />
</RequirePermission> </RequirePermission>
} }
@@ -1000,7 +1000,7 @@ const App = () => {
<Route <Route
path="vehicles" path="vehicles"
element={ element={
<RequirePermission permission={FREIGHT_PERMS.fleet.view}> <RequirePermission permission={FREIGHT_PERMS.vehicles.view}>
<FleetResourcePage /> <FleetResourcePage />
</RequirePermission> </RequirePermission>
} }
@@ -1008,7 +1008,7 @@ const App = () => {
<Route <Route
path="vehicles/:id" path="vehicles/:id"
element={ element={
<RequirePermission permission={FREIGHT_PERMS.fleet.view}> <RequirePermission permission={FREIGHT_PERMS.vehicles.view}>
<VehicleDetailPage /> <VehicleDetailPage />
</RequirePermission> </RequirePermission>
} }
@@ -1016,7 +1016,7 @@ const App = () => {
<Route <Route
path="drivers" path="drivers"
element={ element={
<RequirePermission permission={FREIGHT_PERMS.fleet.view}> <RequirePermission permission={FREIGHT_PERMS.drivers.view}>
<FleetResourcePage /> <FleetResourcePage />
</RequirePermission> </RequirePermission>
} }
@@ -1024,7 +1024,7 @@ const App = () => {
<Route <Route
path="drivers/:id" path="drivers/:id"
element={ element={
<RequirePermission permission={FREIGHT_PERMS.fleet.view}> <RequirePermission permission={FREIGHT_PERMS.drivers.view}>
<DriverDetailPage /> <DriverDetailPage />
</RequirePermission> </RequirePermission>
} }
@@ -1086,7 +1086,7 @@ const App = () => {
<Route <Route
path="fuel-purchases" path="fuel-purchases"
element={ element={
<RequirePermission permission={FREIGHT_PERMS.fleet.view}> <RequirePermission permission={FREIGHT_PERMS.fuel.view}>
<FuelPurchasePage /> <FuelPurchasePage />
</RequirePermission> </RequirePermission>
} }
@@ -1094,7 +1094,7 @@ const App = () => {
<Route <Route
path="fuel-stats" path="fuel-stats"
element={ element={
<RequirePermission permission={FREIGHT_PERMS.fleet.view}> <RequirePermission permission={FREIGHT_PERMS.fuel.view}>
<FuelStatsPage /> <FuelStatsPage />
</RequirePermission> </RequirePermission>
} }
@@ -1102,7 +1102,7 @@ const App = () => {
<Route <Route
path="maintenance" path="maintenance"
element={ element={
<RequirePermission permission={FREIGHT_PERMS.fleet.view}> <RequirePermission permission={FREIGHT_PERMS.maintenance.view}>
<MaintenancePage /> <MaintenancePage />
</RequirePermission> </RequirePermission>
} }
@@ -1110,7 +1110,7 @@ const App = () => {
<Route <Route
path="financial-reports" path="financial-reports"
element={ element={
<RequirePermission permission={FREIGHT_PERMS.fleet.view}> <RequirePermission permission={FREIGHT_PERMS.fleetReports.view}>
<FinancialReportsPage /> <FinancialReportsPage />
</RequirePermission> </RequirePermission>
} }
@@ -1118,7 +1118,7 @@ const App = () => {
<Route <Route
path="fleet-dashboard" path="fleet-dashboard"
element={ element={
<RequirePermission permission={FREIGHT_PERMS.fleet.view}> <RequirePermission permission={FREIGHT_PERMS.fleetDashboard.view}>
<FleetDashboard /> <FleetDashboard />
</RequirePermission> </RequirePermission>
} }
@@ -1126,7 +1126,7 @@ const App = () => {
<Route <Route
path="tracking" path="tracking"
element={ element={
<RequirePermission permission={FREIGHT_PERMS.fleet.view}> <RequirePermission permission={FREIGHT_PERMS.tracking.view}>
<TrackingPage /> <TrackingPage />
</RequirePermission> </RequirePermission>
} }
@@ -1150,7 +1150,7 @@ const App = () => {
<Route <Route
path="work-orders" path="work-orders"
element={ element={
<RequirePermission permission={FREIGHT_PERMS.fleet.view}> <RequirePermission permission={FREIGHT_PERMS.maintenance.view}>
<WorkOrdersPage /> <WorkOrdersPage />
</RequirePermission> </RequirePermission>
} }