UAT fixes and enhancements

This commit is contained in:
Stephanos A
2026-07-10 10:33:36 +03:00
parent cec544fc12
commit acc93aeffc
16 changed files with 371 additions and 489 deletions

View File

@@ -24,6 +24,14 @@ type IamUserRow = {
verified_by: string | null;
};
function resolvePreferredCurrency(nationality: string | null | undefined, faydaVerified: boolean): string {
if (faydaVerified) return 'ETB';
const n = (nationality ?? '').toLowerCase();
if (n.includes('ethiopi')) return 'ETB';
if (n.includes('djibout')) return 'DJF';
return 'USD';
}
@Injectable()
export class PassengerAuthService {
private readonly logger = new Logger(PassengerAuthService.name);
@@ -250,6 +258,8 @@ export class PassengerAuthService {
if (!passenger) throw new Error('Passenger not found');
const iam = iamRows[0];
const faydaVerified = iam?.verified_by === 'fayda';
const nationality = iam?.metadata?.nationality ?? null;
return {
iamUserId,
@@ -259,7 +269,9 @@ export class PassengerAuthService {
email: iam?.email ?? null,
phone: iam?.phone_number ?? null,
fullName: iam?.name?.en ?? iam?.name?.am ?? null,
faydaVerified: iam?.verified_by === 'fayda',
nationality,
faydaVerified,
preferredCurrency: resolvePreferredCurrency(nationality, faydaVerified),
createdAt: passenger.createdAt,
passenger: {
id: passenger.id,

View File

@@ -10,6 +10,7 @@ import { VerifaydaService } from '../verifayda/verifayda.service';
import { CurrencyService } from '../currency/currency.service';
import { FareEngineService } from '../fare-engine/fare-engine.service';
import { Currency, PassengerCategory, IdDocumentType } from '@prisma/client';
import { resolveCurrencyFromNationality } from '../fare-engine/fare-engine.dto';
import { DeleteOperationException } from '../../common/exceptions/delete-operation.exception';
function generateRef(): string {
@@ -396,7 +397,7 @@ export class BookingsService {
orderBy: { createdAt: 'desc' },
include: {
passenger: { select: { id: true, iamUserId: true } },
schedule: { include: { originStation: true, destinationStation: true, train: true } },
schedule: { include: { originStation: true, destinationStation: true, train: true, stopTimes: { include: { station: true } } } },
paymentIntent: true,
seats: { include: { seat: true } },
package: { select: { id: true, name: true, code: true } },
@@ -453,13 +454,18 @@ export class BookingsService {
adultCount: booking.adultCount,
childCount: booking.childCount,
createdAt: booking.createdAt,
originStationId: (booking as any).originStationId ?? null,
passenger: iam ? { fullName: iam.name?.en ?? iam.name?.am ?? null, email: iam.email, phone: iam.phone_number } : null,
passengerNames: [...new Set(booking.seats.map((s: any) => s.passengerName))],
passengers: uniquePassengers,
schedule: {
train: booking.schedule.train,
originStation: booking.schedule.originStation,
destinationStation: booking.schedule.destinationStation,
originStation: (booking as any).originStationId
? ((booking.schedule as any).stopTimes?.find((s: any) => s.stationId === (booking as any).originStationId)?.station ?? booking.schedule.originStation)
: booking.schedule.originStation,
destinationStation: (booking as any).destinationStationId
? ((booking.schedule as any).stopTimes?.find((s: any) => s.stationId === (booking as any).destinationStationId)?.station ?? booking.schedule.destinationStation)
: booking.schedule.destinationStation,
departureAt: booking.schedule.departureAt,
},
paymentIntent: booking.paymentIntent,
@@ -547,7 +553,7 @@ export class BookingsService {
? await this.calculatePackageFare(dto.priceTierId, adultCount, childCount)
: await this.calculateFare(dto.scheduleId, dto.seatClassId, originStop, destStop, passengersData[0]?.nationality, adultCount, childCount, dto.promoCode, dto.loyaltyRedemptionPoints);
const displayCurrency = dto.displayCurrency || Currency.ETB;
const displayCurrency = dto.displayCurrency || resolveCurrencyFromNationality(passengersData[0]?.nationality);
// Track per-seat fare. Use the client-supplied seatFareMinor when present (berth-specific
// pricing for Upper/Middle/Lower beds). Fall back to the fare engine's baseFareMinor.
@@ -589,6 +595,8 @@ export class BookingsService {
bookingRef: generateRef(),
passengerId: dto.passengerId,
scheduleId: dto.scheduleId,
originStationId: dto.originStationId,
destinationStationId: dto.destinationStationId,
status: 'PENDING_PAYMENT',
bookingType: 'ONE_WAY',
totalMinor: resolvedTotalMinor / 100,
@@ -705,7 +713,7 @@ export class BookingsService {
}
const taxesMinor = 0;
const displayCurrency = dto.displayCurrency || Currency.ETB;
const displayCurrency = dto.displayCurrency || resolveCurrencyFromNationality(passengersData[0]?.nationality);
let displayTotalMinor = totalMinor;
if (displayCurrency !== Currency.ETB) {
displayTotalMinor = await this.currencyService.convertAmount(totalMinor, Currency.ETB, displayCurrency);
@@ -759,6 +767,8 @@ export class BookingsService {
bookingRef: generateRef(),
passengerId: dto.passengerId,
scheduleId: dto.scheduleId,
originStationId: dto.originStationId,
destinationStationId: dto.destinationStationId,
status: 'PENDING_PAYMENT',
bookingType: 'ROUND_TRIP',
totalMinor,
@@ -901,7 +911,7 @@ export class BookingsService {
const loyaltyMinor = (dto.loyaltyRedemptionPoints ?? 0) * 10;
const taxesMinor = 0;
const totalMinor = Math.max(0, combinedBase - discountMinor - loyaltyMinor);
const displayCurrency = dto.displayCurrency || Currency.ETB;
const displayCurrency = dto.displayCurrency || resolveCurrencyFromNationality(passengersData[0]?.nationality);
const displayTotalMinor = displayCurrency !== Currency.ETB
? await this.currencyService.convertAmount(totalMinor, Currency.ETB, displayCurrency)
: totalMinor;
@@ -943,6 +953,8 @@ export class BookingsService {
bookingRef: generateRef(),
passengerId: dto.passengerId,
scheduleId: dto.scheduleId,
originStationId: dto.originStationId,
destinationStationId: dto.transitStationId,
status: 'PENDING_PAYMENT',
bookingType: 'TRANSIT',
totalMinor,
@@ -1095,7 +1107,7 @@ export class BookingsService {
const loyaltyMinor = (dto.loyaltyRedemptionPoints ?? 0) * 10;
const taxesMinor = 0;
const totalMinor = Math.max(0, combinedBase - discountMinor - loyaltyMinor);
const displayCurrency = dto.displayCurrency || Currency.ETB;
const displayCurrency = dto.displayCurrency || resolveCurrencyFromNationality(nat);
const displayTotalMinor = displayCurrency !== Currency.ETB
? await this.currencyService.convertAmount(totalMinor, Currency.ETB, displayCurrency)
: totalMinor;
@@ -1146,6 +1158,8 @@ export class BookingsService {
bookingRef: generateRef(),
passengerId: dto.passengerId,
scheduleId: dto.scheduleId,
originStationId: dto.originStationId,
destinationStationId: dto.leg2DestinationStationId,
status: 'PENDING_PAYMENT',
bookingType: 'ROUND_TRIP_TRANSIT',
totalMinor, adultCount, childCount, displayCurrency, displayTotalMinor,

View File

@@ -249,6 +249,8 @@ export class GuestBookingService {
bookingRef: generateRef(),
passengerId: guestPassengerId,
scheduleId: dto.scheduleId,
originStationId: dto.originStationId,
destinationStationId: dto.destinationStationId,
status: 'PENDING_PAYMENT',
totalMinor: resolvedTotalMinor,
adultCount,
@@ -506,6 +508,8 @@ export class GuestBookingService {
bookingRef: generateRef(),
passengerId: guestPassengerId,
scheduleId: dto.scheduleId,
originStationId: dto.originStationId,
destinationStationId: dto.destinationStationId,
status: 'PENDING_PAYMENT',
bookingType: 'ROUND_TRIP',
totalMinor,
@@ -707,6 +711,8 @@ export class GuestBookingService {
bookingRef: generateRef(),
passengerId: guestPassengerId,
scheduleId: dto.scheduleId,
originStationId: dto.originStationId,
destinationStationId: dto.leg2DestinationStationId,
status: 'PENDING_PAYMENT',
bookingType: 'TRANSIT',
totalMinor,
@@ -921,6 +927,8 @@ export class GuestBookingService {
bookingRef: generateRef(),
passengerId: guestPassengerId,
scheduleId: dto.scheduleId,
originStationId: dto.originStationId,
destinationStationId: dto.returnLeg2DestinationStationId,
status: 'PENDING_PAYMENT',
bookingType: 'ROUND_TRIP_TRANSIT',
totalMinor, adultCount, childCount, displayCurrency, displayTotalMinor,

View File

@@ -16,7 +16,19 @@ export class CurrenciesService {
orderBy: { toCurrency: 'asc' },
});
return rates.map(rate => ({
const base = {
id: 'etb-base',
code: 'ETB',
name: 'Ethiopian Birr',
symbol: 'Br',
baseCurrencyCode: 'ETB',
exchangeRate: 1,
isActive: true,
createdAt: new Date(),
updatedAt: new Date(),
};
return [base, ...rates.map(rate => ({
id: rate.id,
code: rate.toCurrency,
name: this.getCurrencyName(rate.toCurrency),
@@ -26,7 +38,7 @@ export class CurrenciesService {
isActive: true,
createdAt: rate.createdAt,
updatedAt: rate.createdAt,
}));
}))];
}
async createCurrency(dto: CreateCurrencyDto) {

View File

@@ -491,7 +491,7 @@ export class SearchService {
const totalMinor = Math.max(0, fare.totalMinor - loyaltyMinor);
const segmentRoute = `${originStop.station.code}-${destStop.station.code}`;
const displayCurrency = dto.displayCurrency ?? (fare.billingCurrency as Currency);
const displayCurrency = dto.displayCurrency ?? resolveCurrencyFromNationality(dto.nationality);
const displayTotalMinor = displayCurrency !== Currency.ETB
? await this.currencyService.convertAmount(totalMinor, Currency.ETB, displayCurrency)
: totalMinor;