mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
Package pricing issue resolution, passenger report updates
This commit is contained in:
@@ -18,8 +18,8 @@ export class ReportsController {
|
||||
return this.service.generateReport(dto);
|
||||
}
|
||||
|
||||
@Get('occupancy')
|
||||
@ApiOperation({ summary: 'Occupancy report for a specific schedule' })
|
||||
@Get('passengers')
|
||||
@ApiOperation({ summary: 'Passengers report for a specific schedule' })
|
||||
getOccupancyReport(@Query('scheduleId') scheduleId: string) {
|
||||
return this.service.getOccupancyBySchedule(scheduleId);
|
||||
}
|
||||
|
||||
@@ -949,10 +949,9 @@ export default function SeatsPage() {
|
||||
return;
|
||||
}
|
||||
|
||||
// No fare change — but for package bookings still sync the tier price to the
|
||||
// actual berth fare (handles the case where the first seat picked matches the
|
||||
// stored price but we still want it explicitly confirmed).
|
||||
if (isPackageBooking && packageId && newFare !== packageTierPriceMinor) {
|
||||
// No fare change — for package bookings still sync the tier price to the
|
||||
// actual berth fare so the correct amount is always stored.
|
||||
if (isPackageBooking && packageId) {
|
||||
setPackageContext(
|
||||
packageId,
|
||||
priceTierId ?? '',
|
||||
@@ -962,6 +961,8 @@ export default function SeatsPage() {
|
||||
packageDepartureStationName ?? undefined,
|
||||
);
|
||||
}
|
||||
} else if (isPackageBooking && packageId) {
|
||||
// newFare is null (seat class data unavailable) — leave stored price as-is.
|
||||
}
|
||||
|
||||
commitSeatAssignment(seatId);
|
||||
|
||||
@@ -401,7 +401,6 @@ const PKG_CHILDREN_PER_ADULT = 5;
|
||||
|
||||
function PassengerCountModal({
|
||||
tier,
|
||||
minPriceMinor,
|
||||
onClose,
|
||||
onConfirm,
|
||||
loading,
|
||||
@@ -410,7 +409,6 @@ function PassengerCountModal({
|
||||
stations,
|
||||
}: {
|
||||
tier: PriceTier;
|
||||
minPriceMinor: number;
|
||||
onClose: () => void;
|
||||
onConfirm: (adultCount: number, childCount: number, departureStationId: string, departureStationName: string) => void;
|
||||
loading: boolean;
|
||||
@@ -423,11 +421,9 @@ function PassengerCountModal({
|
||||
const [departureStationId, setDepartureStationId] = useState('');
|
||||
const [showStationError, setShowStationError] = useState(false);
|
||||
const remaining = tier.availableSeats - tier.bookedSeats;
|
||||
// First child per adult travels free (no seat); additional children pay full adult fare
|
||||
const freeChildren = Math.min(childCount, adultCount);
|
||||
const paidChildren = Math.max(0, childCount - adultCount);
|
||||
// Only paid children need seats; free children share with an adult
|
||||
const totalMinor = (adultCount * minPriceMinor + paidChildren * minPriceMinor) * priceMultiplier;
|
||||
const totalMinor = (adultCount * tier.priceMinor + paidChildren * tier.priceMinor) * priceMultiplier;
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -444,7 +440,7 @@ function PassengerCountModal({
|
||||
<div className="px-6 py-3 bg-primary/5 border-b border-primary/10">
|
||||
<p className="text-xs text-gray-400 uppercase tracking-wide font-semibold">Coach type</p>
|
||||
<p className="text-sm font-bold text-gray-900 dark:text-white mt-0.5">{tier.seatClass?.coachType?.name ?? tier.label.trim()}</p>
|
||||
<p className="text-xs text-gray-400 mt-0.5">{remaining} seats remaining · from {formatPrice(minPriceMinor * priceMultiplier, tier.currency)} per adult · 1st child per adult free (no seat)</p>
|
||||
<p className="text-xs text-gray-400 mt-0.5">{remaining} seats remaining · from {formatPrice(tier.priceMinor * priceMultiplier, tier.currency)} per adult · 1st child per adult free (no seat)</p>
|
||||
</div>
|
||||
|
||||
<div className="px-6 py-5 space-y-4">
|
||||
@@ -646,6 +642,8 @@ export default function PackageDetailPage() {
|
||||
);
|
||||
|
||||
// Store per-adult tier price (×1 leg); review page applies round-trip multiplier and child pricing
|
||||
// Store the group's cheapest tier price as a placeholder — the actual berth fare
|
||||
// (Upper/Middle/Lower) will be resolved and saved when the user picks a seat.
|
||||
setPackageContext(id, representativeTier.id, representativeTier.priceMinor, pkg.name, departureStationId, departureStationName);
|
||||
|
||||
router.push("/booking/passengers");
|
||||
@@ -696,7 +694,6 @@ export default function PackageDetailPage() {
|
||||
{passengerModalOpen && representativeTier && (
|
||||
<PassengerCountModal
|
||||
tier={representativeTier}
|
||||
minPriceMinor={selectedGroup?.minPrice ?? representativeTier.priceMinor}
|
||||
onClose={() => { setPassengerModalOpen(false); setBookingContextError(null); }}
|
||||
onConfirm={handleBookNow}
|
||||
loading={bookingContextLoading}
|
||||
@@ -896,7 +893,7 @@ export default function PackageDetailPage() {
|
||||
|
||||
{/* ── Sidebar — desktop ── */}
|
||||
<div className="hidden lg:block">
|
||||
<div className="sticky top-20">
|
||||
<div>
|
||||
<PriceTiersPanel
|
||||
tiers={pkg.priceTiers}
|
||||
onBookNow={(coachTypeId) => { setSelectedCoachTypeId(coachTypeId); setPassengerModalOpen(true); }}
|
||||
|
||||
Reference in New Issue
Block a user