Enhance deletion logic in Fleet and Schedules services to prevent deletion of records with active dependencies; update Seats and Stations pages to improve UI and remove unused fields.

This commit is contained in:
Stephanos A
2026-06-16 19:30:09 +03:00
parent eb60fc340d
commit ad83c87e2f
5 changed files with 156 additions and 45 deletions

View File

@@ -134,9 +134,28 @@ export class FleetService {
}
async deleteCoachType(id: string) {
const coachType = await this.prisma.coachType.findUnique({ where: { id } });
const coachType = await this.prisma.coachType.findUnique({
where: { id },
include: {
coaches: true,
seatClasses: true,
},
});
if (!coachType) throw new NotFoundException('Coach type not found');
// Check for related records
if (coachType.coaches.length > 0) {
throw new BadRequestException(
`Cannot delete coach type. ${coachType.coaches.length} coach(es) are still using this coach type. Please reassign or delete the coaches first.`
);
}
if (coachType.seatClasses.length > 0) {
throw new BadRequestException(
`Cannot delete coach type. ${coachType.seatClasses.length} seat class(es) are still using this coach type. Please reassign or delete the seat classes first.`
);
}
return this.prisma.coachType.delete({ where: { id } });
}
@@ -183,9 +202,29 @@ export class FleetService {
}
async deleteClass(id: string) {
const seatClass = await this.prisma.seatClass.findUnique({ where: { id } });
const seatClass = await this.prisma.seatClass.findUnique({
where: { id },
include: {
fareRules: true,
routeFareRules: true,
segmentFares: true,
},
});
if (!seatClass) throw new NotFoundException('Seat class not found');
// Check for related records
const relatedRecords = [
...seatClass.fareRules,
...seatClass.routeFareRules,
...seatClass.segmentFares,
];
if (relatedRecords.length > 0) {
throw new BadRequestException(
`Cannot delete seat class. ${relatedRecords.length} fare rule(s) are still using this seat class. Please delete the fare rules first.`
);
}
return this.prisma.seatClass.delete({ where: { id } });
}
@@ -220,8 +259,21 @@ export class FleetService {
}
async deleteTrain(id: string) {
const train = await this.prisma.train.findUnique({ where: { id } });
const train = await this.prisma.train.findUnique({
where: { id },
include: {
schedules: true,
},
});
if (!train) throw new NotFoundException('Train not found');
// Check for active schedules
if (train.schedules.length > 0) {
throw new BadRequestException(
`Cannot delete train. This train has ${train.schedules.length} schedule(s). Please delete the schedules first.`
);
}
return this.prisma.train.delete({ where: { id } });
}
@@ -305,10 +357,53 @@ export class FleetService {
}
async deleteCoach(id: string) {
const coach = await this.prisma.coach.findUnique({ where: { id } });
const coach = await this.prisma.coach.findUnique({
where: { id },
include: {
assignments: true,
seats: {
include: {
bookingSeats: true,
blocks: true,
ticketSeats: true,
},
},
},
});
if (!coach) throw new NotFoundException('Coach not found');
// Delete related seats first
// Check for active assignments
if (coach.assignments.length > 0) {
throw new BadRequestException(
`Cannot delete coach. This coach is assigned to ${coach.assignments.length} schedule(s). Please remove the assignments first.`
);
}
// Check for booked seats
const bookedSeats = coach.seats.filter(seat => seat.bookingSeats.length > 0);
if (bookedSeats.length > 0) {
throw new BadRequestException(
`Cannot delete coach. ${bookedSeats.length} seat(s) have active bookings. Please wait for bookings to complete or cancel them first.`
);
}
// Check for blocked seats
const blockedSeats = coach.seats.filter(seat => seat.blocks.length > 0);
if (blockedSeats.length > 0) {
throw new BadRequestException(
`Cannot delete coach. ${blockedSeats.length} seat(s) are blocked. Please unblock them first.`
);
}
// Check for tickets
const seatsWithTickets = coach.seats.filter(seat => seat.ticketSeats.length > 0);
if (seatsWithTickets.length > 0) {
throw new BadRequestException(
`Cannot delete coach. ${seatsWithTickets.length} seat(s) have issued tickets. Please wait for travel completion.`
);
}
// Delete related seats first (now safe to do)
await this.prisma.seat.deleteMany({ where: { coachId: id } });
return this.prisma.coach.delete({ where: { id } });

View File

@@ -545,8 +545,13 @@ export class SchedulesService {
});
}
if (dto.coaches && dto.coaches.length > 0) {
await this.assignCoaches(id, dto.coaches);
if (dto.coaches !== undefined) {
if (dto.coaches.length > 0) {
await this.assignCoaches(id, dto.coaches);
} else {
// Remove all coach assignments when empty array is sent
await this.prisma.coachAssignment.deleteMany({ where: { scheduleId: id } });
}
}
return this.getSchedule(id);