Booking currency updates, audit logging updates

This commit is contained in:
Stephanos A
2026-07-15 00:39:53 +03:00
parent 5aa1892e19
commit 25fdf88a77
26 changed files with 169 additions and 64 deletions

View File

@@ -2,10 +2,11 @@ import { Injectable, NotFoundException, ConflictException, BadRequestException }
import { PrismaService } from '../../common/prisma.service';
import { CreateRouteDto, AddRouteStopDto, UpdateRouteDto, SetRouteCoachTemplateDto } from './routes.dto';
import { DeleteOperationException } from '../../common/exceptions/delete-operation.exception';
import { AuditService } from '../../common/audit.service';
@Injectable()
export class RoutesService {
constructor(private prisma: PrismaService) {}
constructor(private prisma: PrismaService, private auditService: AuditService) {}
// ── Route CRUD ─────────────────────────────────────────────────────────────
@@ -22,7 +23,7 @@ export class RoutesService {
const stations = await this.prisma.station.findMany({ where: { id: { in: stationIds } } });
if (stations.length !== stationIds.length) throw new BadRequestException('One or more station IDs not found');
return this.prisma.route.create({
const route = await this.prisma.route.create({
data: {
code: dto.code,
name: dto.name,
@@ -40,6 +41,8 @@ export class RoutesService {
},
include: { stops: { include: { route: false }, orderBy: { sequence: 'asc' } } },
});
await this.auditService.log({ action: 'CREATE', entityType: 'Route', entityId: route.id, newData: { code: route.code, name: route.name } });
return route;
}
async listRoutes(activeOnly = false) {
@@ -104,6 +107,7 @@ export class RoutesService {
});
}
await this.auditService.log({ action: 'UPDATE', entityType: 'Route', entityId: id, newData: { name: dto.name, active: dto.active } });
return this.prisma.route.findUnique({
where: { id },
include: { stops: { orderBy: { sequence: 'asc' } } },
@@ -192,6 +196,7 @@ export class RoutesService {
}
await this.prisma.route.delete({ where: { id } });
await this.auditService.log({ action: 'DELETE', entityType: 'Route', entityId: id, oldData: { code: route.code, name: route.name } });
return { deleted: true, id };
}

View File

@@ -4,9 +4,10 @@ import { SchedulesService } from './schedules.service';
import { RoutesController } from './routes.controller';
import { RoutesService } from './routes.service';
import { FareEngineModule } from '../fare-engine/fare-engine.module';
import { AuditModule } from '../../common/audit.module';
@Module({
imports: [FareEngineModule],
imports: [FareEngineModule, AuditModule],
controllers: [RoutesController, SchedulesController],
providers: [RoutesService, SchedulesService],
exports: [RoutesService, SchedulesService],

View File

@@ -5,6 +5,7 @@ import { FareEngineService } from '../fare-engine/fare-engine.service';
import { CreateScheduleDto, UpdateScheduleDto, CreateFareRuleDto, UpdateScheduleStatusDto, UpdateStopTimeDto, ListSchedulesDto, BulkCreateSchedulesDto } from './schedules.dto';
import { DeleteOperationException } from '../../common/exceptions/delete-operation.exception';
import { parseEthiopianTime, startOfDayEAT, startOfNextDayEAT } from '../../common/utils/timezone.utils';
import { AuditService } from '../../common/audit.service';
@Injectable()
export class SchedulesService {
@@ -12,6 +13,7 @@ export class SchedulesService {
private prisma: PrismaService,
private routesService: RoutesService,
private fareEngine: FareEngineService,
private auditService: AuditService,
) { }
async bulkGenerateSchedules(dto: BulkCreateSchedulesDto) {
@@ -191,7 +193,9 @@ export class SchedulesService {
);
}
return this.getSchedule(schedule.id);
const result = await this.getSchedule(schedule.id);
await this.auditService.log({ action: 'CREATE', entityType: 'Schedule', entityId: schedule.id, newData: { trainId: dto.trainId, routeId: dto.routeId, departureAt: dep } });
return result;
}
async getSchedule(id: string) {
@@ -325,10 +329,12 @@ export class SchedulesService {
const plannedTimesMap = Object.fromEntries(plannedTimes.map(t => [t.sequence, t]));
await this.routesService.applyRouteToSchedule(dto.routeId, id, plannedTimesMap);
return this.getSchedule(id);
const result = await this.getSchedule(id);
await this.auditService.log({ action: 'UPDATE', entityType: 'Schedule', entityId: id, newData: { trainId: dto.trainId, departureAt: dep } });
return result;
}
updateScheduleStatus(id: string, dto: UpdateScheduleStatusDto) {
async updateScheduleStatus(id: string, dto: UpdateScheduleStatusDto) {
return this.prisma.trainSchedule.update({ where: { id }, data: { status: dto.status } });
}
@@ -409,7 +415,9 @@ export class SchedulesService {
await this.prisma.packagePriceTier.deleteMany({ where: { packageId: { in: packageIds } } });
await this.prisma.travelPackage.deleteMany({ where: { id: { in: packageIds } } });
}
return this.prisma.trainSchedule.delete({ where: { id } });
await this.prisma.trainSchedule.delete({ where: { id } });
await this.auditService.log({ action: 'DELETE', entityType: 'Schedule', entityId: id });
return { deleted: true, id };
}
getStops(scheduleId: string) {
@@ -467,7 +475,7 @@ export class SchedulesService {
createFareRule(dto: CreateFareRuleDto) {
const { validFrom, validUntil, scheduleId, nationality, passengerCategory, ...rest } = dto;
return this.prisma.fareRule.create({
const result = this.prisma.fareRule.create({
data: {
...rest,
tripId: scheduleId,
@@ -477,6 +485,8 @@ export class SchedulesService {
},
include: { seatClass: true },
});
result.then(r => this.auditService.log({ action: 'CREATE', entityType: 'FareRule', entityId: r.id, newData: { seatClassId: r.seatClassId, baseFareMinor: r.baseFareMinor } }));
return result;
}
async updateFareRule(id: string, dto: Partial<CreateFareRuleDto>) {
@@ -501,6 +511,7 @@ export class SchedulesService {
const existing = await this.prisma.fareRule.findUnique({ where: { id } });
if (!existing) throw new NotFoundException('Fare rule not found');
await this.prisma.fareRule.delete({ where: { id } });
await this.auditService.log({ action: 'DELETE', entityType: 'FareRule', entityId: id });
return { deleted: true, id };
}
@@ -701,7 +712,7 @@ export class SchedulesService {
]);
if (!route) throw new NotFoundException('Route not found');
if (!seatClass) throw new NotFoundException('Seat class not found');
return this.prisma.routeFareRule.create({
const rule = await this.prisma.routeFareRule.create({
data: {
routeId: dto.routeId,
seatClassId: dto.seatClassId,
@@ -712,6 +723,8 @@ export class SchedulesService {
},
include: { seatClass: true, route: true },
});
await this.auditService.log({ action: 'CREATE', entityType: 'RouteFareRule', entityId: rule.id, newData: { routeId: dto.routeId, seatClassId: dto.seatClassId, baseFareMinor: dto.baseFareMinor } });
return rule;
}
async updateRouteFareRule(id: string, dto: { baseFareMinor?: number; surchargeMinor?: number; validFrom?: string; validUntil?: string }) {
@@ -733,6 +746,7 @@ export class SchedulesService {
const rule = await this.prisma.routeFareRule.findUnique({ where: { id } });
if (!rule) throw new NotFoundException('Route fare rule not found');
await this.prisma.routeFareRule.delete({ where: { id } });
await this.auditService.log({ action: 'DELETE', entityType: 'RouteFareRule', entityId: id });
return { deleted: true, id };
}
}