mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-29 06:00:55 +00:00
Segment based seat assignement added
This commit is contained in:
@@ -1,132 +1,51 @@
|
||||
import { Controller, Post, Get, Body, Query, Param } from '@nestjs/common';
|
||||
import { Controller, Post, Get, Body, Query } from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger';
|
||||
import { EnhancedSeatsService } from './enhanced-seats.service';
|
||||
import { HoldSeatsDto, ConfirmBookingDto, SeatAvailabilityDto, ReleaseSeatsDto } from './segments.dto';
|
||||
import { ConfirmBookingDto, SeatAvailabilityDto, ReleaseSeatsDto } from './segments.dto';
|
||||
|
||||
@ApiTags('Segment-based Seats')
|
||||
@Controller('segments/seats')
|
||||
export class SegmentSeatsController {
|
||||
constructor(private enhancedSeatsService: EnhancedSeatsService) {}
|
||||
|
||||
@Post('hold')
|
||||
@ApiOperation({
|
||||
summary: 'Hold seats for specific journey segments',
|
||||
description: 'Reserve seats for a partial journey (e.g., Addis Ababa → Dire Dawa) with 10-minute expiry'
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 201,
|
||||
description: 'Seats held successfully',
|
||||
schema: {
|
||||
example: {
|
||||
holdId: 'hold_123',
|
||||
expiresAt: '2024-01-15T10:10:00Z',
|
||||
segments: [
|
||||
{ fromName: 'Addis Ababa', toName: 'Adama', fromSequence: 0, toSequence: 1 },
|
||||
{ fromName: 'Adama', toName: 'Awash', fromSequence: 1, toSequence: 2 },
|
||||
{ fromName: 'Awash', toName: 'Dire Dawa', fromSequence: 2, toSequence: 3 }
|
||||
],
|
||||
seats: ['seat_1', 'seat_2']
|
||||
}
|
||||
}
|
||||
})
|
||||
@ApiResponse({ status: 409, description: 'Seats not available for requested segments' })
|
||||
async holdSeats(@Body() dto: HoldSeatsDto) {
|
||||
return this.enhancedSeatsService.holdSeats({
|
||||
scheduleId: dto.scheduleId,
|
||||
seatIds: dto.seatIds,
|
||||
passengerId: dto.passengerId,
|
||||
originStationId: dto.originStationId,
|
||||
destinationStationId: dto.destinationStationId,
|
||||
fareQuoteId: dto.fareQuoteId,
|
||||
});
|
||||
}
|
||||
|
||||
@Post('confirm')
|
||||
@ApiOperation({
|
||||
summary: 'Confirm booking and convert hold to reservation',
|
||||
description: 'Convert seat hold to confirmed booking after payment success'
|
||||
@ApiOperation({
|
||||
summary: 'Confirm booking — convert hold to reservation',
|
||||
description: 'Call after payment succeeds. Converts the SeatHold (created via POST /seats/hold) into JourneySegment records scoped to the passenger\'s leg.',
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: 'Booking confirmed successfully',
|
||||
schema: {
|
||||
example: {
|
||||
bookingId: 'booking_123',
|
||||
confirmedSeats: ['seat_1', 'seat_2'],
|
||||
segments: [
|
||||
{ fromName: 'Addis Ababa', toName: 'Adama' },
|
||||
{ fromName: 'Adama', toName: 'Awash' },
|
||||
{ fromName: 'Awash', toName: 'Dire Dawa' }
|
||||
]
|
||||
}
|
||||
}
|
||||
})
|
||||
@ApiResponse({ status: 400, description: 'Hold expired or not found' })
|
||||
async confirmBooking(@Body() dto: ConfirmBookingDto) {
|
||||
@ApiResponse({ status: 200, description: 'Booking confirmed, JourneySegments created for the held leg' })
|
||||
@ApiResponse({ status: 400, description: 'Hold expired or booking not found' })
|
||||
confirmBooking(@Body() dto: ConfirmBookingDto) {
|
||||
return this.enhancedSeatsService.confirmBooking(dto);
|
||||
}
|
||||
|
||||
@Post('release')
|
||||
@ApiOperation({
|
||||
summary: 'Release seats when train reaches station',
|
||||
description: 'Automatically release seats for passengers who have reached their destination'
|
||||
@ApiOperation({
|
||||
summary: 'Release seats when train reaches a station',
|
||||
description: 'Called by the live tracking system when the train departs a station. Frees seats for passengers whose journey ended at that station.',
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: 'Seats released successfully',
|
||||
schema: {
|
||||
example: {
|
||||
releasedSeats: ['seat_1', 'seat_2'],
|
||||
stationId: 'st_DRE'
|
||||
}
|
||||
}
|
||||
})
|
||||
async releaseSeats(@Body() dto: ReleaseSeatsDto) {
|
||||
@ApiResponse({ status: 200, description: 'Seats released for passengers who reached their destination' })
|
||||
releaseSeats(@Body() dto: ReleaseSeatsDto) {
|
||||
return this.enhancedSeatsService.releaseSeats(dto.scheduleId, dto.currentStationId);
|
||||
}
|
||||
|
||||
@Get('availability')
|
||||
@ApiOperation({
|
||||
summary: 'Check seat availability for journey segments',
|
||||
description: 'Get available seats for a specific origin-destination pair'
|
||||
@ApiOperation({
|
||||
summary: 'Get available seats for a specific leg',
|
||||
description: 'Returns seats that have no overlapping reservation for the requested origin→destination leg. A seat booked A→B is shown as available for B→D.',
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: 'Seat availability retrieved',
|
||||
schema: {
|
||||
example: {
|
||||
segments: [
|
||||
{ fromName: 'Addis Ababa', toName: 'Adama', fromSequence: 0, toSequence: 1 },
|
||||
{ fromName: 'Adama', toName: 'Awash', fromSequence: 1, toSequence: 2 }
|
||||
],
|
||||
availableSeats: [
|
||||
{ id: 'seat_1', label: '1A', coach: 'A', seatClass: 'Economy Regular', row: 1, col: 'A' },
|
||||
{ id: 'seat_2', label: '1B', coach: 'A', seatClass: 'Economy Regular', row: 1, col: 'B' }
|
||||
],
|
||||
totalAvailable: 2
|
||||
}
|
||||
}
|
||||
})
|
||||
async getSeatAvailability(@Query() dto: SeatAvailabilityDto) {
|
||||
@ApiResponse({ status: 200, description: 'Available seats with coach, seat class, row, col, window/aisle/bed flags' })
|
||||
getSeatAvailability(@Query() dto: SeatAvailabilityDto) {
|
||||
return this.enhancedSeatsService.getSeatAvailability(dto.scheduleId, dto.originStationId, dto.destinationStationId);
|
||||
}
|
||||
|
||||
@Post('expire-holds')
|
||||
@ApiOperation({
|
||||
summary: 'Expire old seat holds (background job)',
|
||||
description: 'Release seats from expired holds and make them available'
|
||||
@ApiOperation({
|
||||
summary: 'Expire stale seat holds (background job)',
|
||||
description: 'Removes holds past their expiry time. Called by the scheduler every minute.',
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: 'Expired holds processed',
|
||||
schema: {
|
||||
example: {
|
||||
expiredHolds: 5,
|
||||
releasedSeats: ['seat_1', 'seat_2', 'seat_3']
|
||||
}
|
||||
}
|
||||
})
|
||||
async expireHolds() {
|
||||
@ApiResponse({ status: 200, description: 'Expired holds removed' })
|
||||
expireHolds() {
|
||||
return this.enhancedSeatsService.expireHolds();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user