Fix directors forecast report counting stale pickup for past days
The report endpoint's totalPickup/totalRooms summed every day's pickup override regardless of whether the day had already passed, even though a past day's actual accommodation revenue already supersedes it (fAccomm ignores pickup for those days). This overstated Probable Pickup and the month's rooms estimate. Also fixed pickup.accomm to sum each day's own rate instead of multiplying the total by a flat session rate.
This commit is contained in:
parent
9e9e1d7400
commit
932302ebe2
1 changed files with 15 additions and 7 deletions
|
|
@ -104,8 +104,10 @@ export async function directorsForecastRoutes(fastify) {
|
||||||
const actualDry = isPast ? (rev.dry?.otb ?? null) : null
|
const actualDry = isPast ? (rev.dry?.otb ?? null) : null
|
||||||
const actualWet = isPast ? (rev.wet?.otb ?? null) : null
|
const actualWet = isPast ? (rev.wet?.otb ?? null) : null
|
||||||
|
|
||||||
// User overrides
|
// User overrides — once a day is past and has an actual, a leftover
|
||||||
const pickupRooms = ovr.pickup_rooms != null ? parseInt(ovr.pickup_rooms) : 0
|
// pickup override from before the day arrived is stale and shouldn't count.
|
||||||
|
const pickupApplies = !(isPast && actualAccomm != null)
|
||||||
|
const pickupRooms = pickupApplies && ovr.pickup_rooms != null ? parseInt(ovr.pickup_rooms) : 0
|
||||||
const dayRate = ovr.pickup_avg_rate != null ? parseFloat(ovr.pickup_avg_rate) : rate
|
const dayRate = ovr.pickup_avg_rate != null ? parseFloat(ovr.pickup_avg_rate) : rate
|
||||||
|
|
||||||
// Forecast values
|
// Forecast values
|
||||||
|
|
@ -209,7 +211,7 @@ export async function directorsForecastRoutes(fastify) {
|
||||||
'29–end': { accomm: 0, dry: 0, wet: 0, rooms: 0 },
|
'29–end': { accomm: 0, dry: 0, wet: 0, rooms: 0 },
|
||||||
}
|
}
|
||||||
|
|
||||||
let totalAvailable = 0, totalOtbRooms = 0, totalOtbNetRev = 0, totalPickup = 0
|
let totalAvailable = 0, totalOtbRooms = 0, totalOtbNetRev = 0, totalPickup = 0, totalPickupRevenue = 0
|
||||||
let totalAccomm = 0, totalDry = 0, totalWet = 0
|
let totalAccomm = 0, totalDry = 0, totalWet = 0
|
||||||
let totalBudgetAccomm = 0, totalBudgetDry = 0, totalBudgetWet = 0
|
let totalBudgetAccomm = 0, totalBudgetDry = 0, totalBudgetWet = 0
|
||||||
let totalLyAccomm = 0, totalLyDry = 0, totalLyWet = 0, totalLyRooms = 0
|
let totalLyAccomm = 0, totalLyDry = 0, totalLyWet = 0, totalLyRooms = 0
|
||||||
|
|
@ -224,14 +226,19 @@ export async function directorsForecastRoutes(fastify) {
|
||||||
const available = rm.available_rooms ?? 0
|
const available = rm.available_rooms ?? 0
|
||||||
const otbRooms = rm.otb_rooms ?? 0
|
const otbRooms = rm.otb_rooms ?? 0
|
||||||
const otbNetRev = rev.accom?.otb ?? 0
|
const otbNetRev = rev.accom?.otb ?? 0
|
||||||
const pickupRooms = ovr.pickup_rooms != null ? parseInt(ovr.pickup_rooms) : 0
|
|
||||||
const dayRate = ovr.pickup_avg_rate != null ? parseFloat(ovr.pickup_avg_rate) : sessionRate
|
|
||||||
const totalRooms = otbRooms + pickupRooms
|
|
||||||
|
|
||||||
const actualAccomm = isPast ? (rev.accom?.otb ?? null) : null
|
const actualAccomm = isPast ? (rev.accom?.otb ?? null) : null
|
||||||
const actualDry = isPast ? (rev.dry?.otb ?? null) : null
|
const actualDry = isPast ? (rev.dry?.otb ?? null) : null
|
||||||
const actualWet = isPast ? (rev.wet?.otb ?? null) : null
|
const actualWet = isPast ? (rev.wet?.otb ?? null) : null
|
||||||
|
|
||||||
|
// Once a day is past and has an actual, it's realised — any leftover
|
||||||
|
// pickup override from before the day arrived is stale and must not
|
||||||
|
// still count as "probable" pickup (it never contributed to fAccomm below).
|
||||||
|
const pickupApplies = !(isPast && actualAccomm != null)
|
||||||
|
const pickupRooms = pickupApplies && ovr.pickup_rooms != null ? parseInt(ovr.pickup_rooms) : 0
|
||||||
|
const dayRate = ovr.pickup_avg_rate != null ? parseFloat(ovr.pickup_avg_rate) : sessionRate
|
||||||
|
const totalRooms = otbRooms + pickupRooms
|
||||||
|
|
||||||
const fAccomm = (isPast && actualAccomm != null) ? actualAccomm : otbNetRev + pickupRooms * dayRate
|
const fAccomm = (isPast && actualAccomm != null) ? actualAccomm : otbNetRev + pickupRooms * dayRate
|
||||||
const fDry = ovr.forecast_dry != null ? parseFloat(ovr.forecast_dry)
|
const fDry = ovr.forecast_dry != null ? parseFloat(ovr.forecast_dry)
|
||||||
: ovr.dry_override != null ? parseFloat(ovr.dry_override)
|
: ovr.dry_override != null ? parseFloat(ovr.dry_override)
|
||||||
|
|
@ -244,6 +251,7 @@ export async function directorsForecastRoutes(fastify) {
|
||||||
totalOtbRooms += otbRooms
|
totalOtbRooms += otbRooms
|
||||||
totalOtbNetRev += otbNetRev
|
totalOtbNetRev += otbNetRev
|
||||||
totalPickup += pickupRooms
|
totalPickup += pickupRooms
|
||||||
|
totalPickupRevenue += pickupRooms * dayRate
|
||||||
totalAccomm += fAccomm
|
totalAccomm += fAccomm
|
||||||
totalDry += fDry
|
totalDry += fDry
|
||||||
totalWet += fWet
|
totalWet += fWet
|
||||||
|
|
@ -312,7 +320,7 @@ export async function directorsForecastRoutes(fastify) {
|
||||||
arr: totalOtbRooms > 0 ? totalOtbNetRev / totalOtbRooms : null,
|
arr: totalOtbRooms > 0 ? totalOtbNetRev / totalOtbRooms : null,
|
||||||
revpar: totalAvailable > 0 ? totalOtbNetRev / totalAvailable : null,
|
revpar: totalAvailable > 0 ? totalOtbNetRev / totalAvailable : null,
|
||||||
},
|
},
|
||||||
pickup: { rooms: totalPickup, accomm: totalPickup * sessionRate, avg_rate: sessionRate },
|
pickup: { rooms: totalPickup, accomm: totalPickupRevenue, avg_rate: totalPickup > 0 ? totalPickupRevenue / totalPickup : sessionRate },
|
||||||
weekly: Object.entries(weekBands).map(([label, v]) => ({ label, ...v })),
|
weekly: Object.entries(weekBands).map(([label, v]) => ({ label, ...v })),
|
||||||
snapshots: snapshotsRes.rows,
|
snapshots: snapshotsRes.rows,
|
||||||
utilities,
|
utilities,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue