Skip to main content
The JS Mini Hotel system provides three powerful reporting functions to help you analyze hotel performance and guest behavior. This guide covers occupancy reports, revenue calculations, and guest history lookups.

Report Types Overview

Occupancy Report

View room occupancy for any specific date, including percentage and breakdown by room type.

Revenue Report

Calculate total revenue for a date range, including room charges and extras.

Guest History

Look up all reservations and spending for a specific guest by email.

Occupancy Reports

Generate a snapshot of hotel occupancy for any date (past, present, or future).

Using getOccupancyReport()

main.js:81
const report = getOccupancyReport(hotel, '2026-03-22')
console.log(report)

How It Works

The function analyzes all reservations (active and historical) to determine which rooms are occupied on a specific date:
main.js:241-277
function getOccupancyReport(hotel, date) {
  const reservationsPlusHistory = structuredClone([
    ...hotel.reservations,
    ...hotel.history
  ])

  // Find rooms occupied on this date
  const occupiedRooms = reservationsPlusHistory
    .map(reservation => {
      if (isDateInRange(date, reservation.checkIn, reservation.checkOut)) {
        return getRoomByNumber(hotel, reservation.roomNumber)
      }
    })
    .filter(room => room !== undefined)

  return {
    date: date.toString(),
    total: hotel.rooms.length,
    occupied: occupiedRooms.length,
    available: hotel.rooms.length - occupiedRooms.length,
    percentage: Math.floor((occupiedRooms.length / hotel.rooms.length) * 100),
    byType: {
      single: {
        total: getRoomsByType(hotel.rooms, ROOM_TYPE.SINGLE).length,
        occupied: getRoomsByType(occupiedRooms, ROOM_TYPE.SINGLE).length
      },
      double: {
        total: getRoomsByType(hotel.rooms, ROOM_TYPE.DOUBLE).length,
        occupied: getRoomsByType(occupiedRooms, ROOM_TYPE.DOUBLE).length
      },
      suite: {
        total: getRoomsByType(hotel.rooms, ROOM_TYPE.SUITE).length,
        occupied: getRoomsByType(occupiedRooms, ROOM_TYPE.SUITE).length
      }
    }
  }
}
A room is considered occupied on a date if:
checkIn <= date && date < checkOut
Note that the check-out date is exclusive - a guest checking out on March 22 does not occupy the room on March 22.

Expected Output Structure

const report = getOccupancyReport(hotel, '2026-03-22')

Use Cases

Check current day occupancy:
const today = Temporal.Now.plainDateISO().toString()
const todayReport = getOccupancyReport(hotel, today)

console.log(`Today's occupancy: ${todayReport.percentage}%`)
console.log(`Available rooms: ${todayReport.available}`)
The report includes both active reservations and historical data, so it can generate accurate reports for any date.

Revenue Reports

Calculate total revenue for a date range, including breakdowns for room charges and extras.

Using getRevenueReport()

main.js:84
const revenue = getRevenueReport(hotel, '2026-01-01', '2026-03-22')
console.log(revenue)

How It Works

The function finds all reservations that overlap with the date range and calculates revenue:
main.js:282-314
function getRevenueReport(hotel, startDate, endDate) {
  const reservationsPlusHistory = getReservationsPlusHistory(hotel)

  const reservationsInRange = reservationsPlusHistory.reduce(
    (acc, reservation) => {
      if (
        isRangeInRange(
          startDate,
          endDate,
          reservation.checkIn,
          reservation.checkOut
        ) &&
        reservation.status !== RESERVATION_STATUS.CANCELLED
      ) {
        acc.push(reservation)
      }
      return acc
    },
    []
  )

  return {
    period: `${startDate.toString()} to ${endDate.toString()}`,
    rooms: hotel.rooms.length,
    extras: reservationsInRange.reduce((acc, reservation) => {
      return (acc += getExtrasPrice(reservation.extras))
    }, 0),
    total: reservationsInRange.reduce((acc, reservation) => {
      return (acc += reservation.totalPrice)
    }, 0),
    reservations: reservationsInRange.length
  }
}
Cancelled reservations are excluded from revenue calculations, even if they had cancellation penalties.

Expected Output Structure

const revenue = getRevenueReport(hotel, '2026-01-01', '2026-01-31')

Revenue Calculation Examples

// Get revenue for January 2026
const januaryRevenue = getRevenueReport(
  hotel,
  '2026-01-01',
  '2026-01-31'
)

console.log(`January revenue: €${januaryRevenue.total}`)
console.log(`From extras: €${januaryRevenue.extras}`)
console.log(`Number of reservations: ${januaryRevenue.reservations}`)
// Q1 2026 revenue
const q1Revenue = getRevenueReport(
  hotel,
  '2026-01-01',
  '2026-03-31'
)

// Calculate average per reservation
const avgPerReservation = q1Revenue.total / q1Revenue.reservations
console.log(`Average per reservation: €${avgPerReservation.toFixed(2)}`)
const today = Temporal.Now.plainDateISO().toString()
const ytdRevenue = getRevenueReport(hotel, '2026-01-01', today)

console.log(`Year-to-date revenue: €${ytdRevenue.total}`)

Understanding the Total Field

The total field includes both room charges and extras:
total = (sum of all reservation.totalPrice values)

// Where each reservation.totalPrice already includes:
// - Room charges (nights × pricePerNight)
// - Extras charges (sum of extra.price × extra.quantity)

Guest History

Look up all reservations and total spending for a specific guest.

Using getGuestHistory()

main.js:87
const history = getGuestHistory(hotel, '[email protected]')
console.log(history)

How It Works

The function searches both active reservations and history by guest email:
main.js:319-353
function getGuestHistory(hotel, guestEmail) {
  const reservations = getReservationsPlusHistory(hotel)

  const reservationsOfGuest = reservations.filter(
    reservation => reservation.guest.email === guestEmail
  )

  const guest = reservationsOfGuest.reduce((acc, reservation) => {
    return (acc = reservation.guest)
  }, {})

  const totalSpent = reservationsOfGuest.reduce((acc, reservation) => {
    return (acc += reservation.totalPrice)
  }, 0)

  const totalExtras = reservationsOfGuest.reduce((acc, reservation) => {
    return (acc += getExtrasPrice(reservation.extras))
  }, 0)

  return {
    guestEmail,
    guestName: guest.name,
    totalReservations: reservationsOfGuest.length,
    totalSpent: totalSpent + totalExtras,
    reservations: reservationsOfGuest.map(reservation => {
      return {
        id: reservation.id,
        checkIn: reservation.checkIn,
        checkOut: reservation.checkOut,
        status: reservation.status,
        totalPrice: reservation.totalPrice
      }
    })
  }
}
The function calculates totalSpent by adding totalSpent + totalExtras. This appears to double-count extras since totalPrice already includes extras. This might be a bug in the source code.

Expected Output Structure

const history = getGuestHistory(hotel, '[email protected]')

Guest History Use Cases

Identify frequent guests:
const history = getGuestHistory(hotel, '[email protected]')

if (history.totalReservations >= 5) {
  console.log(`${history.guestName} is a VIP guest!`)
  console.log(`Total spent: €${history.totalSpent}`)
}

Combining Reports

You can combine different reports for comprehensive insights:
// Get all data for a month
const month = '2026-01'
const startDate = `${month}-01`
const endDate = `${month}-31`

// Revenue report
const revenue = getRevenueReport(hotel, startDate, endDate)

// Occupancy samples (first, middle, last day)
const day1 = getOccupancyReport(hotel, `${month}-01`)
const day15 = getOccupancyReport(hotel, `${month}-15`)
const day31 = getOccupancyReport(hotel, `${month}-31`)

// Calculate average occupancy
const avgOccupancy = Math.round(
  (day1.percentage + day15.percentage + day31.percentage) / 3
)

console.log('Monthly Report')
console.log('==============')
console.log(`Revenue: €${revenue.total}`)
console.log(`Reservations: ${revenue.reservations}`)
console.log(`Average occupancy: ${avgOccupancy}%`)
console.log(`Revenue per reservation: €${(revenue.total / revenue.reservations).toFixed(2)}`)

Best Practices

Always use ISO date format (YYYY-MM-DD):
// Good
getOccupancyReport(hotel, '2026-03-22')

// Bad
getOccupancyReport(hotel, '03/22/2026')
Check for empty guest history:
const history = getGuestHistory(hotel, '[email protected]')

if (history.totalReservations === 0) {
  console.log('Guest not found')
} else {
  console.log(`Found ${history.totalReservations} reservations`)
}
For frequently accessed reports, consider caching:
const reportCache = new Map()

function getCachedOccupancyReport(hotel, date) {
  const key = `occupancy-${date}`
  
  if (!reportCache.has(key)) {
    reportCache.set(key, getOccupancyReport(hotel, date))
  }
  
  return reportCache.get(key)
}

Performance Considerations

All report functions iterate through reservations and history. For hotels with thousands of reservations, consider:
  • Implementing pagination for guest history
  • Adding date range filters to limit data processing
  • Caching frequently accessed reports

Next Steps

Creating Reservations

Create new reservations that will appear in reports

Managing Extras

Add extras that contribute to revenue reports

Build docs developers (and LLMs) love