Functional Weave
Code in TypeScript

hospitality.gross-profit-menu@1.0.0

impl/rust/menu_price_for_gp.rs

1,963 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::finance_markup_price::markup_price;  ← from finance.markup-price ^1.0.0 · built alongside by fune
use super::finance_tax_add_vat::add_vat;  ← from finance.tax.add-vat ^1.0.0 · built alongside by fune
use super::hospitality_gross_profit_menu_menu_gross_profit::{menu_gross_profit, menu_gross_profit_to_value};  ← menuGrossProfit, another function of this group · built into the same file, even by a slim install
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};  ← from money.amount ^1.0.0 · built alongside by fune

/// The menu price that reaches a target GP.
///
/// The net price is the smallest that makes the target on the VAT-exclusive
/// price (finance.markup-price, rounded up), VAT goes on top, and the menu
/// price is rounded up to the step a menu is printed in. Rounding only ever
/// goes up, so the GP returned is never below the target.
///
/// # Panics
/// Panics on a target outside 0 to 9999, a step below 1, a negative cost, or
/// no VAT rule.
pub fn menu_price_for_gp(
    cost: &Money,
    target_gp_basis_points: i64,
    price_step: i64,
    jurisdiction: &str,
    category: &str,
    on_date: &str,
) -> MenuGrossProfit {
    if !(0..=9999).contains(&target_gp_basis_points) {
        panic!(
            "targetGpBasisPoints must be a whole number from 0 to 9999, received {}",
            target_gp_basis_points
        );
    }
    if price_step < 1 {
        panic!("priceStep must be at least 1, received {}", price_step);
    }
    if cost.minor < 0 {
        panic!("cost must not be negative, received {}", cost.minor);
    }
    let net = markup_price(cost, target_gp_basis_points, "margin", "up");
    let gross = add_vat(&net, jurisdiction, category, on_date).gross;
    let menu_price = money(round_div(gross.minor, price_step, "up") * price_step, &gross.currency);
    menu_gross_profit(cost, &menu_price, jurisdiction, category, on_date)
}

pub fn fune_vector(args: &[Value]) -> Value {
    menu_gross_profit_to_value(&menu_price_for_gp(
        &money_from_value(&args[0]),
        args[1].as_i64(),
        args[2].as_i64(),
        args[3].as_str(),
        args[4].as_str(),
        args[5].as_str(),
    ))
}