File

src/lanes/lanes.controller.ts

Prefix

lanes

Index

Methods

Methods

Async addTariff
addTariff(orgId: string, id: string, dto: CreateTariffDto)
Decorators :
@Post(':id/tariffs')
@Roles(undefined)
@ApiOperation({summary: 'Add a tariff to a lane'})
Parameters :
Name Type Optional
orgId string No
id string No
dto CreateTariffDto No
Returns : unknown
Async bulkUpload
bulkUpload(orgId: string, file: Express.Multer.File)
Decorators :
@Post('upload')
@Roles(undefined)
@ApiOperation({summary: 'Bulk upload lanes from Excel/CSV'})
@ApiConsumes('multipart/form-data')
@UseInterceptors(undefined)
Parameters :
Name Type Optional
orgId string No
file Express.Multer.File No
Returns : unknown
Async create
create(orgId: string, dto: CreateLaneDto)
Decorators :
@Post()
@Roles(undefined)
@ApiOperation({summary: 'Create a new lane'})
Parameters :
Name Type Optional
orgId string No
dto CreateLaneDto No
Returns : unknown
Async findAll
findAll(orgId: string, query: PaginationParams)
Decorators :
@Get()
@ApiPagination()
@ApiOperation({summary: 'List all lanes (org-scoped)'})
Parameters :
Name Type Optional
orgId string No
query PaginationParams No
Returns : unknown
Async findOne
findOne(orgId: string, id: string)
Decorators :
@Get(':id')
@ApiOperation({summary: 'Get lane by ID (org-scoped, includes tariffs)'})
Parameters :
Name Type Optional
orgId string No
id string No
Returns : unknown
Async getTariffs
getTariffs(orgId: string, id: string, activeOnly?: string)
Decorators :
@Get(':id/tariffs')
@ApiOperation({summary: 'List tariffs for a lane (with isActive flag)'})
@ApiQuery({name: 'activeOnly', required: false, type: Boolean})
Parameters :
Name Type Optional
orgId string No
id string No
activeOnly string Yes
Returns : unknown
Async remove
remove(orgId: string, id: string)
Decorators :
@Delete(':id')
@Roles(undefined)
@ApiOperation({summary: 'Delete a lane (blocked when in use by trips/orders)'})
Parameters :
Name Type Optional
orgId string No
id string No
Returns : unknown
Async removeTariff
removeTariff(orgId: string, id: string, tariffId: string)
Decorators :
@Delete(':id/tariffs/:tariffId')
@Roles(undefined)
@ApiOperation({summary: 'Delete a tariff from a lane'})
Parameters :
Name Type Optional
orgId string No
id string No
tariffId string No
Returns : unknown
Async update
update(orgId: string, id: string, dto: UpdateLaneDto)
Decorators :
@Patch(':id')
@Roles(undefined)
@ApiOperation({summary: 'Update a lane (org-scoped)'})
Parameters :
Name Type Optional
orgId string No
id string No
dto UpdateLaneDto No
Returns : unknown
Async updateTariff
updateTariff(orgId: string, id: string, tariffId: string, dto: Partial<CreateTariffDto>)
Decorators :
@Patch(':id/tariffs/:tariffId')
@Roles(undefined)
@ApiOperation({summary: 'Update a tariff on a lane'})
Parameters :
Name Type Optional
orgId string No
id string No
tariffId string No
dto Partial<CreateTariffDto> No
Returns : unknown
import {
  Controller,
  Get,
  Post,
  Patch,
  Delete,
  Body,
  Param,
  Query,
  UseGuards,
  UseInterceptors,
  UploadedFile,
  BadRequestException,
} from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { ApiTags, ApiBearerAuth, ApiOperation, ApiConsumes, ApiQuery } from '@nestjs/swagger';
import { LanesService } from './lanes.service';
import { CreateLaneDto } from './dto/create-lane.dto';
import { UpdateLaneDto } from './dto/update-lane.dto';
import { CreateTariffDto } from './dto/create-tariff.dto';
import { CombinedAuthGuard } from '../auth/guards/combined-auth.guard';
import { RolesGuard } from '../auth/guards/roles.guard';
import { Roles } from '../auth/decorators/roles.decorator';
import { CurrentUser } from '../auth/decorators/current-user.decorator';
import { ApiPagination } from '../common/decorators/api-pagination.decorator';
import { PaginationParams } from '../common/utils/pagination.util';

/**
 * Lane geometry can be edited by ops staff (PLANNER builds routes daily).
 * Tariffs are commercial decisions, so they're locked tighter — only the
 * org admins / SUPER_ADMIN can touch rate cards.
 */
const LANE_WRITERS = ['SUPER_ADMIN', 'ADMIN', 'OPERATIONS_MANAGER', 'PLANNER'] as const;
const TARIFF_WRITERS = ['SUPER_ADMIN', 'ADMIN', 'OPERATIONS_MANAGER'] as const;

@ApiTags('Lanes')
@ApiBearerAuth()
@UseGuards(CombinedAuthGuard, RolesGuard)
@Controller('lanes')
export class LanesController {
  constructor(private readonly lanesService: LanesService) {}

  @Post()
  @Roles(...LANE_WRITERS)
  @ApiOperation({ summary: 'Create a new lane' })
  async create(
    @CurrentUser('organizationId') orgId: string,
    @Body() dto: CreateLaneDto,
  ) {
    return this.lanesService.create(orgId, dto);
  }

  @Get()
  @ApiPagination()
  @ApiOperation({ summary: 'List all lanes (org-scoped)' })
  async findAll(
    @CurrentUser('organizationId') orgId: string,
    @Query() query: PaginationParams,
  ) {
    return this.lanesService.findAll(orgId, query);
  }

  @Get(':id')
  @ApiOperation({ summary: 'Get lane by ID (org-scoped, includes tariffs)' })
  async findOne(
    @CurrentUser('organizationId') orgId: string,
    @Param('id') id: string,
  ) {
    return this.lanesService.findOne(orgId, id);
  }

  @Patch(':id')
  @Roles(...LANE_WRITERS)
  @ApiOperation({ summary: 'Update a lane (org-scoped)' })
  async update(
    @CurrentUser('organizationId') orgId: string,
    @Param('id') id: string,
    @Body() dto: UpdateLaneDto,
  ) {
    return this.lanesService.update(orgId, id, dto);
  }

  @Delete(':id')
  @Roles(...LANE_WRITERS)
  @ApiOperation({ summary: 'Delete a lane (blocked when in use by trips/orders)' })
  async remove(
    @CurrentUser('organizationId') orgId: string,
    @Param('id') id: string,
  ) {
    return this.lanesService.remove(orgId, id);
  }

  // ── Tariffs ──────────────────────────────────────────────────────

  @Post(':id/tariffs')
  @Roles(...TARIFF_WRITERS)
  @ApiOperation({ summary: 'Add a tariff to a lane' })
  async addTariff(
    @CurrentUser('organizationId') orgId: string,
    @Param('id') id: string,
    @Body() dto: CreateTariffDto,
  ) {
    return this.lanesService.addTariff(orgId, id, dto);
  }

  @Get(':id/tariffs')
  @ApiOperation({ summary: 'List tariffs for a lane (with isActive flag)' })
  @ApiQuery({ name: 'activeOnly', required: false, type: Boolean })
  async getTariffs(
    @CurrentUser('organizationId') orgId: string,
    @Param('id') id: string,
    @Query('activeOnly') activeOnly?: string,
  ) {
    return this.lanesService.getTariffs(orgId, id, {
      activeOnly: activeOnly === 'true' || activeOnly === '1',
    });
  }

  @Patch(':id/tariffs/:tariffId')
  @Roles(...TARIFF_WRITERS)
  @ApiOperation({ summary: 'Update a tariff on a lane' })
  async updateTariff(
    @CurrentUser('organizationId') orgId: string,
    @Param('id') id: string,
    @Param('tariffId') tariffId: string,
    @Body() dto: Partial<CreateTariffDto>,
  ) {
    return this.lanesService.updateTariff(orgId, id, tariffId, dto);
  }

  @Delete(':id/tariffs/:tariffId')
  @Roles(...TARIFF_WRITERS)
  @ApiOperation({ summary: 'Delete a tariff from a lane' })
  async removeTariff(
    @CurrentUser('organizationId') orgId: string,
    @Param('id') id: string,
    @Param('tariffId') tariffId: string,
  ) {
    return this.lanesService.removeTariff(orgId, id, tariffId);
  }

  // ── Bulk import ──────────────────────────────────────────────────

  @Post('upload')
  @Roles(...LANE_WRITERS)
  @ApiOperation({ summary: 'Bulk upload lanes from Excel/CSV' })
  @ApiConsumes('multipart/form-data')
  @UseInterceptors(FileInterceptor('file', { limits: { fileSize: 10 * 1024 * 1024 } }))
  async bulkUpload(
    @CurrentUser('organizationId') orgId: string,
    @UploadedFile() file: Express.Multer.File,
  ) {
    if (!file) throw new BadRequestException('No file uploaded');
    return this.lanesService.bulkUploadFromFile(orgId, file);
  }
}

results matching ""

    No results matching ""