This commit is contained in:
natib21
2026-06-29 14:45:22 +00:00
parent 7dba546254
commit 6fa315db0f
28 changed files with 1227 additions and 8 deletions

View File

@@ -0,0 +1,8 @@
export class FirstMileContainerAllocationDto {
containerId!: string;
vehicleId!: string;
}
export class AllocateFirstMileContainersDto {
allocations!: FirstMileContainerAllocationDto[];
}

View File

@@ -0,0 +1,36 @@
import { BaseEntity } from '@edr/api-common';
import { Column, Entity, Index, JoinColumn, ManyToOne, OneToMany } from 'typeorm';
import { FirstMile } from './first-mile.entity';
import { Vehicle } from '../../vehicles/entities/vehicle.entity';
@Entity({ name: 'first_mile_container_allocations', schema: 'freight' })
@Index(['firstMileId'])
@Index(['vehicleId'])
export class FirstMileContainerAllocation extends BaseEntity {
@Column({ name: 'first_mile_id', type: 'uuid' })
firstMileId!: string;
@ManyToOne(() => FirstMile, (firstMile) => firstMile.containerAllocations, {
nullable: false,
eager: false,
})
@JoinColumn({ name: 'first_mile_id' })
firstMile?: FirstMile;
@Column({ name: 'container_id', type: 'uuid' })
containerId!: string;
@Column({ name: 'vehicle_id', type: 'uuid', nullable: true })
vehicleId?: string | null;
@ManyToOne(() => Vehicle, { nullable: true, eager: false })
@JoinColumn({ name: 'vehicle_id' })
vehicle?: Vehicle | null;
@Column({ name: 'container_type', type: 'text' })
containerType!: string;
@Column({ name: 'quantity', type: 'int', default: 1 })
quantity!: number;
}

View File

@@ -1,8 +1,9 @@
import { BaseEntity } from '@edr/api-common';
import { Column, Entity, Index, JoinColumn, ManyToOne } from 'typeorm';
import { Column, Entity, Index, JoinColumn, ManyToOne, OneToMany } from 'typeorm';
import { Booking } from '../../bookings/entities/booking.entity';
import { Vehicle } from '../../vehicles/entities/vehicle.entity';
import { FirstMileContainerAllocation } from './first-mile-container-allocation.entity';
export const FIRST_MILE_STATUSES = [
'PAYMENT_PENDING',
@@ -49,4 +50,11 @@ export class FirstMile extends BaseEntity {
@ManyToOne(() => Vehicle, { nullable: true, eager: false })
@JoinColumn({ name: 'vehicle_id' })
vehicle?: Vehicle | null;
@OneToMany(
() => FirstMileContainerAllocation,
(containerAllocation) => containerAllocation.firstMile,
{ eager: false },
)
containerAllocations!: FirstMileContainerAllocation[];
}

View File

@@ -17,6 +17,7 @@ import { TrainSchedulingManage, TrainSchedulingView } from '../../common/booking
import { CreateFirstMileDto } from './dto/create-first-mile.dto';
import { UpdateFirstMileDto } from './dto/update-first-mile.dto';
import { AllocateFirstMileContainersDto } from './dto/allocate-containers.dto';
import { FirstMileStatus } from './entities/first-mile.entity';
import { FirstMileService } from './first-mile.service';
@@ -83,4 +84,14 @@ export class FirstMileController {
remove(@Param('id', ParseUUIDPipe) id: string) {
return this.firstMileService.remove(id);
}
@Post(':firstMileId/allocate-containers')
@TrainSchedulingManage()
@ApiOperation({ summary: 'Allocate containers to vehicles for a first-mile leg' })
allocateContainers(
@Param('firstMileId', ParseUUIDPipe) firstMileId: string,
@Body() dto: AllocateFirstMileContainersDto,
) {
return this.firstMileService.allocateContainers(firstMileId, dto.allocations);
}
}

View File

@@ -6,13 +6,14 @@ import { DriversModule } from '../drivers/drivers.module';
import { NotificationsModule } from '../notifications/notifications.module';
import { VehiclesModule } from '../vehicles/vehicles.module';
import { FirstMile } from './entities/first-mile.entity';
import { FirstMileContainerAllocation } from './entities/first-mile-container-allocation.entity';
import { FirstMileController } from './first-mile.controller';
import { FirstMileRepository } from './first-mile.repository';
import { FirstMileService } from './first-mile.service';
@Module({
imports: [
TypeOrmModule.forFeature([FirstMile]),
TypeOrmModule.forFeature([FirstMile, FirstMileContainerAllocation]),
forwardRef(() => BookingsModule),
VehiclesModule,
DriversModule,

View File

@@ -1,5 +1,7 @@
import { BadRequestException, ConflictException, Injectable, Logger, NotFoundException } from '@nestjs/common';
import { FindOptionsWhere } from 'typeorm';
import { InjectDataSource } from '@nestjs/typeorm';
import { DataSource } from 'typeorm';
import { BookingsRepository } from '../bookings/bookings.repository';
import { DriversService } from '../drivers/drivers.service';
@@ -8,6 +10,7 @@ import { VehiclesService } from '../vehicles/vehicles.service';
import { CreateFirstMileDto } from './dto/create-first-mile.dto';
import { UpdateFirstMileDto } from './dto/update-first-mile.dto';
import { FirstMile, FirstMileStatus } from './entities/first-mile.entity';
import { FirstMileContainerAllocation } from './entities/first-mile-container-allocation.entity';
import { FirstMileRepository } from './first-mile.repository';
type FirstMileListFilter = {
@@ -32,6 +35,7 @@ export class FirstMileService {
private readonly logger = new Logger(FirstMileService.name);
constructor(
@InjectDataSource() private readonly dataSource: DataSource,
private readonly firstMileRepository: FirstMileRepository,
private readonly bookingsRepository: BookingsRepository,
private readonly vehiclesService: VehiclesService,
@@ -273,4 +277,35 @@ export class FirstMileService {
await this.findById(id);
await this.firstMileRepository.softDelete(id);
}
async allocateContainers(
firstMileId: string,
allocations: Array<{ containerId: string; vehicleId: string }>,
) {
const firstMile = await this.findById(firstMileId);
if (!firstMile) {
throw new NotFoundException(`First-mile record ${firstMileId} not found`);
}
await this.dataSource.transaction(async (manager) => {
for (const allocation of allocations) {
await manager.delete(FirstMileContainerAllocation, {
firstMileId,
containerId: allocation.containerId,
});
await manager.insert(FirstMileContainerAllocation, {
firstMileId,
containerId: allocation.containerId,
vehicleId: allocation.vehicleId,
containerType: 'CONTAINER',
quantity: 1,
});
}
});
return {
success: true,
allocated: allocations.length,
};
}
}