Dashboard, seats report, package pricing updates

This commit is contained in:
Stephanos A
2026-07-18 00:34:12 +03:00
parent eee14a5051
commit 8eb0582e4e
8 changed files with 80 additions and 7 deletions

View File

@@ -866,6 +866,15 @@ export class BookingsService {
resolvedTotalMinor = displayCurrency !== Currency.ETB
? await this.currencyService.convertAmount(dto.reviewedTotalMinor, displayCurrency, Currency.ETB)
: dto.reviewedTotalMinor;
// For package bookings where per-seat fares weren't supplied, back-derive the
// per-seat fare from reviewedTotalMinor so BookingSeat.fareMinor reflects the
// actual berth price (Upper/Middle/Lower) rather than the tier's minimum price.
if (dto.packageId && seatedPassengers.length > 0) {
const perSeatFare = Math.round(dto.reviewedTotalMinor / seatedPassengers.length);
passengersWithFares.forEach(p => {
if (p.fareMinor > 0) p.fareMinor = p.seatFareMinor ?? perSeatFare;
});
}
} else if (allFaresProvided) {
// seatFareMinor is in display currency — sum is already the display total
displayTotalMinor = passengersWithFares.reduce((sum, p) => sum + p.fareMinor, 0);
@@ -1050,6 +1059,19 @@ export class BookingsService {
totalMinor = displayCurrency !== Currency.ETB
? await this.currencyService.convertAmount(dto.reviewedTotalMinor, displayCurrency, Currency.ETB)
: dto.reviewedTotalMinor;
// For package bookings where per-seat fares weren't supplied, back-derive the
// per-leg per-seat fare from reviewedTotalMinor so BookingSeat.fareMinor reflects
// the actual berth price (Upper/Middle/Lower) rather than the tier's minimum price.
if (dto.packageId) {
const seatedCount = passengersData.filter(p => p.outboundSeatId).length;
if (seatedCount > 0) {
const perSeatPerLeg = Math.round(dto.reviewedTotalMinor / (seatedCount * 2));
passengersWithFares.forEach(p => {
if (p.outboundFareMinor > 0) p.outboundFareMinor = p.seatFareMinor ?? perSeatPerLeg;
if (p.returnFareMinor > 0) p.returnFareMinor = p.returnSeatFareMinor ?? perSeatPerLeg;
});
}
}
} else if (allRTFaresProvided && !dto.packageId) {
// seatFareMinor/returnSeatFareMinor are in display currency — sum is already the display total
displayTotalMinor = passengersWithFares.reduce((sum, p) => sum + p.outboundFareMinor + p.returnFareMinor, 0);

View File

@@ -231,6 +231,14 @@ export class GuestBookingService {
let resolvedTotalMinor: number;
if (dto.reviewedTotalMinor != null) {
displayTotalMinor = dto.reviewedTotalMinor;
// For package bookings, back-derive per-seat fareMinor from reviewedTotalMinor
// so BookingSeat records store the actual berth price, not the tier minimum.
if (isPackageOneway && seatedPassengers.length > 0) {
const perSeatFare = Math.round(dto.reviewedTotalMinor / seatedPassengers.length);
passengersWithFares.forEach(p => {
if (p.fareMinor > 0) p.fareMinor = p.seatFareMinor ?? perSeatFare;
});
}
} else if (allFaresProvided) {
displayTotalMinor = passengersWithFares.reduce((sum, p) => sum + p.fareMinor, 0);
} else {
@@ -515,6 +523,17 @@ export class GuestBookingService {
totalMinor = displayCurrency !== Currency.ETB
? await this.currencyService.convertAmount(displayTotalMinor, displayCurrency, Currency.ETB)
: displayTotalMinor;
// For package bookings, back-derive per-leg per-seat fareMinor from reviewedTotalMinor.
if (isPackageRoundTrip) {
const seatedCount = passengersData.filter(p => p.seatId).length;
if (seatedCount > 0) {
const perSeatPerLeg = Math.round(dto.reviewedTotalMinor / (seatedCount * 2));
passengersWithFares.forEach(p => {
if (p.outboundFareMinor > 0) p.outboundFareMinor = p.seatFareMinor ?? perSeatPerLeg;
if (p.returnFareMinor > 0) p.returnFareMinor = p.returnSeatFareMinor ?? perSeatPerLeg;
});
}
}
} else if (allRTFaresProvided && !isPackageRoundTrip) {
// seatFareMinor/returnSeatFareMinor are display-currency — sum is already display total
displayTotalMinor = passengersWithFares.reduce((sum, p) => sum + p.outboundFareMinor + p.returnFareMinor, 0);