Functional Weave
Code in Rust

hospitality.occupancy-adr-revpar@1.0.0

impl/typescript.ts

1,632 bytes · the TypeScript implementation · view raw

Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.

import { roundDiv } from "./math_round_div.ts";  ← from math.round-div ^1.0.0 · built alongside by fune
import { type Money, money } from "./money_amount.ts";  ← from money.amount ^1.0.0 · built alongside by fune
import { type HotelPerformance } from "./hospitality_occupancy_adr_revpar_types.ts";

/**
 * Occupancy, ADR and RevPAR for a period.
 *
 * Each figure is divided out of the raw totals and rounded half-up once.
 * RevPAR is revenue over available rooms, not ADR times occupancy: multiplying
 * two figures that were each rounded already can be a penny out.
 */
export function occupancyAdrRevpar(roomNightsAvailable: number, roomNightsSold: number, roomRevenue: Money): HotelPerformance {
  if (!Number.isInteger(roomNightsAvailable) || roomNightsAvailable < 1) {
    throw new RangeError(`roomNightsAvailable must be at least 1, received ${roomNightsAvailable}`);
  }
  if (!Number.isInteger(roomNightsSold) || roomNightsSold < 0) {
    throw new RangeError(`roomNightsSold must not be negative, received ${roomNightsSold}`);
  }
  if (roomNightsSold > roomNightsAvailable) {
    throw new RangeError(`roomNightsSold (${roomNightsSold}) cannot exceed roomNightsAvailable (${roomNightsAvailable})`);
  }
  if (roomRevenue.minor < 0) {
    throw new RangeError(`roomRevenue must not be negative, received ${roomRevenue.minor}`);
  }
  return {
    roomNightsAvailable,
    roomNightsSold,
    roomRevenue,
    occupancyBasisPoints: roundDiv(roomNightsSold * 10000, roomNightsAvailable, "half-up"),
    adr: roomNightsSold === 0 ? null : money(roundDiv(roomRevenue.minor, roomNightsSold, "half-up"), roomRevenue.currency),
    revpar: money(roundDiv(roomRevenue.minor, roomNightsAvailable, "half-up"), roomRevenue.currency),
  };
}