Functional Weave
Code in Rust

hospitality.occupancy-adr-revpar@1.0.0

impl/rust.rs

2,639 bytes · the Rust 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.

use super::funejson::Value;  ← the fune runtime: the JSON value the test vectors use; fune build keeps it only where a signature takes one
use super::math_round_div::round_div;  ← from math.round-div ^1.0.0 · built alongside by fune
use super::money_amount::{money, money_from_value, money_to_value, Money};  ← from money.amount ^1.0.0 · built alongside by fune

/// 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.
///
/// # Panics
/// Panics when there are no rooms available, the counts are out of range or
/// the revenue is negative.
pub fn occupancy_adr_revpar(room_nights_available: i64, room_nights_sold: i64, room_revenue: &Money) -> HotelPerformance {
    if room_nights_available < 1 {
        panic!("roomNightsAvailable must be at least 1, received {}", room_nights_available);
    }
    if room_nights_sold < 0 {
        panic!("roomNightsSold must not be negative, received {}", room_nights_sold);
    }
    if room_nights_sold > room_nights_available {
        panic!(
            "roomNightsSold ({}) cannot exceed roomNightsAvailable ({})",
            room_nights_sold, room_nights_available
        );
    }
    if room_revenue.minor < 0 {
        panic!("roomRevenue must not be negative, received {}", room_revenue.minor);
    }
    HotelPerformance {
        room_nights_available,
        room_nights_sold,
        room_revenue: room_revenue.clone(),
        occupancy_basis_points: round_div(room_nights_sold * 10000, room_nights_available, "half-up"),
        adr: if room_nights_sold == 0 {
            None
        } else {
            Some(money(
                round_div(room_revenue.minor, room_nights_sold, "half-up"),
                &room_revenue.currency,
            ))
        },
        revpar: money(
            round_div(room_revenue.minor, room_nights_available, "half-up"),
            &room_revenue.currency,
        ),
    }
}

pub fn hotel_performance_to_value(p: &HotelPerformance) -> Value {
    Value::obj(vec![
        ("roomNightsAvailable", Value::Int(p.room_nights_available)),
        ("roomNightsSold", Value::Int(p.room_nights_sold)),
        ("roomRevenue", money_to_value(&p.room_revenue)),
        ("occupancyBasisPoints", Value::Int(p.occupancy_basis_points)),
        (
            "adr",
            match &p.adr {
                Some(a) => money_to_value(a),
                None => Value::Null,
            },
        ),
        ("revpar", money_to_value(&p.revpar)),
    ])
}

pub fn fune_vector(args: &[Value]) -> Value {
    hotel_performance_to_value(&occupancy_adr_revpar(
        args[0].as_i64(),
        args[1].as_i64(),
        &money_from_value(&args[2]),
    ))
}