Files
edr-platform/apps/edr-passenger-api/src/modules/search/search.service.ts
2026-05-13 16:58:49 +03:00

51 lines
2.9 KiB
TypeScript

import { Injectable, NotFoundException } from '@nestjs/common';
import { PrismaService } from '../../common/prisma.service';
import { SearchTripsDto, FareQuoteDto } from './search.dto';
const POINTS_TO_MINOR = 10;
@Injectable()
export class SearchService {
constructor(private prisma: PrismaService) {}
async searchTrips(dto: SearchTripsDto) {
const date = new Date(dto.date), nextDay = new Date(date.getTime() + 86400000);
const trips = await this.prisma.trip.findMany({
where: { originStationId: dto.originStationId, destinationStationId: dto.destinationStationId, departureAt: { gte: date, lt: nextDay }, status: { in: ['SCHEDULED', 'BOARDING'] } },
include: { service: true, originStation: true, destinationStation: true, coaches: { include: { seats: true } } },
});
return trips.map((trip) => {
const seatsByClass = (cls: string) => trip.coaches.filter((c) => c.serviceClass === cls).flatMap((c) => c.seats);
const avail = (cls: string) => seatsByClass(cls).filter((s) => s.status === 'AVAILABLE').length;
return {
id: trip.id,
number: trip.service.number,
origin: { id: trip.originStation.id, code: trip.originStation.code, name: trip.originStation.name, city: trip.originStation.city },
destination: { id: trip.destinationStation.id, code: trip.destinationStation.code, name: trip.destinationStation.name, city: trip.destinationStation.city },
departureAt: trip.departureAt, arrivalAt: trip.arrivalAt, status: trip.status,
availability: { ECONOMY: avail('ECONOMY'), BUSINESS: avail('BUSINESS'), FIRST: avail('FIRST') },
fares: { ECONOMY: this.defaultFare('ECONOMY') / 100, BUSINESS: this.defaultFare('BUSINESS') / 100, FIRST: this.defaultFare('FIRST') / 100 },
};
});
}
async getFareQuote(dto: FareQuoteDto) {
const trip = await this.prisma.trip.findUnique({ where: { id: dto.tripId } });
if (!trip) throw new NotFoundException('Trip not found');
const count = dto.passengerCount ?? 1;
const baseFareMinor = this.defaultFare(dto.serviceClass) * count;
let discountMinor = 0;
if (dto.promoCode) {
const promo = await this.prisma.promotion.findUnique({ where: { code: dto.promoCode } });
if (promo?.active && promo.validUntil > new Date()) discountMinor = promo.percentOff ? Math.round(baseFareMinor * promo.percentOff / 100) : (promo.amountOffMinor ?? 0);
}
const loyaltyMinor = (dto.loyaltyRedemptionPoints ?? 0) * POINTS_TO_MINOR;
const taxesMinor = Math.round(baseFareMinor * 0.05);
return { tripId: dto.tripId, serviceClass: dto.serviceClass, passengerCount: count, baseFareMinor, discountMinor, loyaltyRedemptionMinor: loyaltyMinor, taxesFeesMinor: taxesMinor, totalMinor: Math.max(0, baseFareMinor - discountMinor - loyaltyMinor + taxesMinor), currency: 'ETB' };
}
private defaultFare(serviceClass: string): number {
return ({ ECONOMY: 45000, BUSINESS: 90000, FIRST: 135000 } as any)[serviceClass] ?? 45000;
}
}