Room planner: fix next-bracket visibility and vacant room misdetection

Extend booking fetch window to day-after-tomorrow so tomorrow-arriving
bookings appear in nextBooking lookups (some NewBook regions exclude
arrivals exactly on period_to date, causing right brackets to not render).

Add booking_site_id fallback in site-ID matching so bookings are found
correctly even when NewBook returns booking_site_id instead of site_id in
the booking object (was causing some rooms to show as vacant).

Remove category debug logging (no longer needed).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
jtricerolph 2026-07-04 11:40:46 +00:00
parent cbfec7d591
commit 916dc50390
2 changed files with 12 additions and 12 deletions

View file

@ -23,12 +23,18 @@ export function toTimeStr(dt) {
return t || null return t || null
} }
// Match a booking to a site ID. NewBook sometimes uses booking_site_id instead of site_id.
function siteMatches(b, siteId) {
const bid = String(b.site_id || b.booking_site_id || '')
return bid === String(siteId)
}
// Find all bookings for a given site on a specific date. // Find all bookings for a given site on a specific date.
// A booking occupies a site on viewDate if: arrival <= viewDate < departure // A booking occupies a site on viewDate if: arrival <= viewDate < departure
// (departure date is the check-out day, so the room is vacated on that morning) // (departure date is the check-out day, so the room is vacated on that morning)
export function bookingsForSiteOnDate(bookings, siteId, viewDate) { export function bookingsForSiteOnDate(bookings, siteId, viewDate) {
return bookings.filter(b => { return bookings.filter(b => {
if (String(b.site_id) !== String(siteId)) return false if (!siteMatches(b, siteId)) return false
const arrival = toDateStr(b.booking_arrival) const arrival = toDateStr(b.booking_arrival)
const departure = toDateStr(b.booking_departure) const departure = toDateStr(b.booking_departure)
if (!arrival || !departure) return false if (!arrival || !departure) return false
@ -39,7 +45,7 @@ export function bookingsForSiteOnDate(bookings, siteId, viewDate) {
// Find the departing booking for a site on viewDate (departure_date === viewDate) // Find the departing booking for a site on viewDate (departure_date === viewDate)
export function departingBookingForSite(bookings, siteId, viewDate) { export function departingBookingForSite(bookings, siteId, viewDate) {
return bookings.find(b => return bookings.find(b =>
String(b.site_id) === String(siteId) && siteMatches(b, siteId) &&
toDateStr(b.booking_departure) === viewDate toDateStr(b.booking_departure) === viewDate
) ?? null ) ?? null
} }

View file

@ -74,24 +74,18 @@ export async function roomRoutes(app) {
// Fetch from NewBook in parallel // Fetch from NewBook in parallel
let sites, bookings, tasks let sites, bookings, tasks
try { try {
// Fetch bookings one day beyond tomorrow so tomorrow-arriving bookings appear
// in nextBooking lookups (some NewBook regions exclude period_to-date arrivals).
const dayAfterTomorrow = dateOffset(viewDate, +2)
;[sites, bookings, tasks] = await Promise.all([ ;[sites, bookings, tasks] = await Promise.all([
fetchSites(), fetchSites(),
fetchBookings(yesterday, tomorrow), fetchBookings(yesterday, dayAfterTomorrow),
fetchTasks(yesterday, tomorrow), fetchTasks(yesterday, tomorrow),
]) ])
} catch (err) { } catch (err) {
return reply.status(502).send({ error: `NewBook fetch failed: ${err.message}` }) return reply.status(502).send({ error: `NewBook fetch failed: ${err.message}` })
} }
// Derive category map from sites. Log first site keys to help diagnose field names.
if (sites.length > 0) {
const sample = sites[0]
console.log('[rooms] sample site keys:', Object.keys(sample))
console.log('[rooms] sample site_category_id:', sample.site_category_id,
'| category_id:', sample.category_id,
'| category:', JSON.stringify(sample.category))
}
const categoryMap = {} const categoryMap = {}
for (const site of sites) { for (const site of sites) {
const catId = String( const catId = String(