mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-28 16:00:56 +00:00
Dashboard, seats report, package pricing updates
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -2,7 +2,8 @@ import { Controller, Get, Param, SetMetadata, UseGuards } from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
|
||||
import { DashboardService } from './dashboard.service';
|
||||
import { JwtGuard } from '../../common/jwt.guard';
|
||||
import { PassengerAdmin } from '../../common/passenger-guards';
|
||||
import { PassengerAdmin, PassengerStaff } from '../../common/passenger-guards';
|
||||
import { PASSENGER_PERMS } from '../../seed/passenger-permissions.registry';
|
||||
|
||||
@ApiTags('Dashboard')
|
||||
@Controller('dashboard')
|
||||
@@ -10,7 +11,7 @@ export class DashboardController {
|
||||
constructor(private service: DashboardService) {}
|
||||
|
||||
@Get('backoffice-stats')
|
||||
@PassengerAdmin()
|
||||
@PassengerStaff([PASSENGER_PERMS.dashboard.view, PASSENGER_PERMS.admin])
|
||||
@ApiBearerAuth('IAM-auth')
|
||||
@ApiOperation({ summary: 'Backoffice summary: totals and revenue by currency' })
|
||||
getBackofficeStats() { return this.service.getBackofficeStats(); }
|
||||
|
||||
@@ -11,12 +11,13 @@ export class DashboardService {
|
||||
) {}
|
||||
|
||||
async getBackofficeStats() {
|
||||
const [totalBookings, totalPackageBookings, totalTickets, totalPassengers, revenueRows, packageRevenueRows] =
|
||||
const [totalBookings, totalPackageBookings, totalTickets, totalPassengers, blockedSeatsCount, revenueRows, packageRevenueRows] =
|
||||
await Promise.all([
|
||||
this.prisma.booking.count(),
|
||||
this.prisma.booking.count({ where: { packageId: { not: null } } }),
|
||||
this.prisma.ticket.count(),
|
||||
this.prisma.passenger.count(),
|
||||
this.prisma.seat.count({ where: { status: 'BLOCKED' } }),
|
||||
this.prisma.$queryRaw<{ currency: string; total: bigint }[]>`
|
||||
SELECT
|
||||
COALESCE("displayCurrency"::text, "currency"::text) AS currency,
|
||||
@@ -56,6 +57,7 @@ export class DashboardService {
|
||||
totalPackageTickets,
|
||||
totalNormalTickets: totalTickets - totalPackageTickets,
|
||||
totalPassengers,
|
||||
blockedSeatsCount,
|
||||
revenueByCurrency: toMap(revenueRows),
|
||||
packageRevenueByCurrency: toMap(packageRevenueRows),
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user