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),
};
}