diff --git a/backend/src/lib/newbook.js b/backend/src/lib/newbook.js index 7dabbeb..7f7cb06 100644 --- a/backend/src/lib/newbook.js +++ b/backend/src/lib/newbook.js @@ -58,14 +58,13 @@ export async function fetchSites() { return res?.data ?? [] } -// Fetch bookings whose stay overlaps the date window. -// list_type 'staying' returns bookings where arrival <= period_to AND departure >= period_from, -// so a booking arriving on period_to is included. This matches the original plugin behaviour. +// Fetch bookings spanning a date range. +// list_type 'all' includes arrived, confirmed, unconfirmed, departed, blocked. export async function fetchBookings(fromDate, toDate) { const res = await callApi('bookings_list', { period_from: `${fromDate} 00:00:00`, period_to: `${toDate} 23:59:59`, - list_type: 'staying', + list_type: 'all', }) return res?.data ?? [] } diff --git a/backend/src/routes/rooms.js b/backend/src/routes/rooms.js index e8efcfc..f10b541 100644 --- a/backend/src/routes/rooms.js +++ b/backend/src/routes/rooms.js @@ -47,82 +47,6 @@ function filterBookingData(booking, canSeeGuest, canSeeRate, canSeeAllNotes, vis export async function roomRoutes(app) { app.addHook('preHandler', requireAuth) - // GET /api/rooms/debug-room?room=101&date=YYYY-MM-DD - // Returns raw NewBook data for a single room — use to diagnose bracket/booking issues. - app.get('/api/rooms/debug-room', async (req, reply) => { - if (!hasCap(req, 'settings')) return reply.status(403).send({ error: 'Forbidden' }) - - const viewDate = req.query.date || new Date().toISOString().slice(0, 10) - const roomName = req.query.room - const yesterday = dateOffset(viewDate, -1) - const tomorrow = dateOffset(viewDate, +1) - - const [sites, bookings] = await Promise.all([ - fetchSites(), - fetchBookings(yesterday, tomorrow), - ]) - - if (!roomName) { - const sample = bookings[0] || {} - return { - hint: 'Pass ?room= to inspect a specific room', - view_date: viewDate, - total_sites: sites.length, - total_bookings: bookings.length, - booking_field_names: Object.keys(sample), - site_field_names: sites.length ? Object.keys(sites[0]) : [], - site_list: sites.map(s => ({ id: s.site_id, name: s.site_name })), - } - } - - const site = sites.find(s => s.site_name === roomName) - if (!site) return { error: `Room "${roomName}" not found`, available: sites.map(s => s.site_name) } - - const siteId = String(site.site_id) - const idFields = bookings.length - ? Object.keys(bookings[0]).filter(k => - k.toLowerCase().includes('site') || k.toLowerCase().includes('room') || - k.toLowerCase().includes('unit') || k.toLowerCase().includes('location') - ) - : [] - - const matchFn = b => - idFields.some(f => String(b[f] || '') === siteId) || - String(b.site_id || '') === siteId || - String(b.booking_site_id || '') === siteId || - (b.site_name && b.site_name === roomName) - - const siteBookings = bookings.filter(matchFn) - - const classified = classifyRoom(site, bookings, viewDate, yesterday, tomorrow) - - return { - view_date: viewDate, yesterday, tomorrow, - site: { id: siteId, name: site.site_name, fields: Object.keys(site) }, - booking_id_fields: idFields, - total_bookings_fetched: bookings.length, - matching_bookings: siteBookings.map(b => { - const out = {} - for (const f of ['booking_id', 'booking_status', 'booking_arrival', 'booking_departure', ...idFields]) { - out[f] = b[f] - } - return out - }), - classified: { - flow_type: classified.flow_type, - spans_previous: classified.spans_previous, - spans_next: classified.spans_next, - previous_status: classified.previous_status, - next_status: classified.next_status, - booking_id: classified.booking?.booking_id, - booking_arrival: classified.booking?.booking_arrival, - booking_departure: classified.booking?.booking_departure, - next_booking_id: classified.next_booking?.booking_id, - next_booking_arrival: classified.next_booking?.booking_arrival, - }, - } - }) - // GET /api/rooms?date=YYYY-MM-DD app.get('/api/rooms', async (req, reply) => { if (!hasCap(req, 'view')) return reply.status(403).send({ error: 'Missing capability: view' }) @@ -150,11 +74,12 @@ export async function roomRoutes(app) { // Fetch from NewBook in parallel let sites, bookings, tasks try { - // list_type 'staying' includes bookings with arrival <= period_to, - // so fetching yesterday→tomorrow captures all adjacent-day brackets. + // 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([ fetchSites(), - fetchBookings(yesterday, tomorrow), + fetchBookings(yesterday, dayAfterTomorrow), fetchTasks(yesterday, tomorrow), ]) } catch (err) { @@ -178,7 +103,7 @@ export async function roomRoutes(app) { // Classify each site const rooms = [] for (const site of sites) { - const catId = String(site.site_category_id ?? site.category_id ?? site.category?.id ?? '') + const catId = String(site.site_category_id || '') const isExcluded = excludedCategories.includes(catId) if (isExcluded && hideExcluded) continue diff --git a/frontend/src/components/RoomCard.tsx b/frontend/src/components/RoomCard.tsx index 74acb71..f5a6008 100644 --- a/frontend/src/components/RoomCard.tsx +++ b/frontend/src/components/RoomCard.tsx @@ -104,8 +104,8 @@ function RoomCard({ room, viewDate, config, onClick }: Props) { } if (room.spans_next) { dataAttrs['data-spans-next'] = 'true' - } else if (room.next_status != null) { - dataAttrs['data-next-status'] = room.next_status || 'unknown' + } else if (room.next_status) { + dataAttrs['data-next-status'] = room.next_status.toLowerCase() } // Task status pill