mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-09-07 22:25:42 +00:00
@@ -0,0 +1,18 @@
|
|||||||
|
-- Remove duplicate JourneySegment rows, keeping the one with the lowest id
|
||||||
|
-- (earliest created) per (scheduleId, seatId, departureStationId) group.
|
||||||
|
-- This cleans up any existing double-bookings before the unique index is applied.
|
||||||
|
DELETE FROM passenger."JourneySegment"
|
||||||
|
WHERE id NOT IN (
|
||||||
|
SELECT MIN(id)
|
||||||
|
FROM passenger."JourneySegment"
|
||||||
|
WHERE "seatId" IS NOT NULL
|
||||||
|
GROUP BY "scheduleId", "seatId", "departureStationId"
|
||||||
|
)
|
||||||
|
AND "seatId" IS NOT NULL;
|
||||||
|
|
||||||
|
-- Prevents two confirmed bookings from occupying the same seat on the same
|
||||||
|
-- schedule hop — the hard DB backstop against application-level race conditions.
|
||||||
|
-- Partial index: seatId IS NOT NULL excludes free-child rows that have no seat.
|
||||||
|
CREATE UNIQUE INDEX "JourneySegment_scheduleId_seatId_departureStationId_key"
|
||||||
|
ON passenger."JourneySegment" ("scheduleId", "seatId", "departureStationId")
|
||||||
|
WHERE "seatId" IS NOT NULL;
|
||||||
@@ -991,6 +991,10 @@ model JourneySegment {
|
|||||||
arrivalStationId String
|
arrivalStationId String
|
||||||
journey Journey @relation(fields: [journeyId], references: [id])
|
journey Journey @relation(fields: [journeyId], references: [id])
|
||||||
schedule TrainSchedule @relation(fields: [scheduleId], references: [id])
|
schedule TrainSchedule @relation(fields: [scheduleId], references: [id])
|
||||||
|
|
||||||
|
// Prevents two confirmed bookings from occupying the same seat on the same
|
||||||
|
// schedule hop — the hard DB backstop against application-level race conditions.
|
||||||
|
@@unique([scheduleId, seatId, departureStationId])
|
||||||
@@schema("passenger")
|
@@schema("passenger")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Body, Controller, Get, Param, Post, Query, UseGuards, Delete, Patch, Se
|
|||||||
import { ApiTags, ApiOperation, ApiBearerAuth, ApiBody, ApiQuery } from '@nestjs/swagger';
|
import { ApiTags, ApiOperation, ApiBearerAuth, ApiBody, ApiQuery } from '@nestjs/swagger';
|
||||||
import { TicketsService } from './tickets.service';
|
import { TicketsService } from './tickets.service';
|
||||||
import { JwtGuard } from '../../common/jwt.guard';
|
import { JwtGuard } from '../../common/jwt.guard';
|
||||||
import { PassengerStaff } from '../../common/passenger-guards';
|
import { PassengerStaff, PassengerAdmin } from '../../common/passenger-guards';
|
||||||
import { PASSENGER_PERMS } from '../../seed/passenger-permissions.registry';
|
import { PASSENGER_PERMS } from '../../seed/passenger-permissions.registry';
|
||||||
|
|
||||||
@ApiTags('Tickets')
|
@ApiTags('Tickets')
|
||||||
@@ -207,8 +207,8 @@ export class TicketsController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Delete(':id')
|
@Delete(':id')
|
||||||
@UseGuards(JwtGuard)
|
@PassengerAdmin()
|
||||||
@ApiBearerAuth('JWT-auth')
|
@ApiBearerAuth('IAM-auth')
|
||||||
@ApiOperation({
|
@ApiOperation({
|
||||||
summary: 'Delete ticket (admin only)',
|
summary: 'Delete ticket (admin only)',
|
||||||
description: 'Permanently deletes a ticket record and removes associated seat blocks'
|
description: 'Permanently deletes a ticket record and removes associated seat blocks'
|
||||||
|
|||||||
Reference in New Issue
Block a user