///|
pub struct CostItem {
name : String
quantity : Float
unit_cost : Float
category : String
} derive(Debug, Eq)
///|
pub fn cost_item(
name : String,
quantity : Float,
unit_cost : Float,
category : String,
) -> CostItem {
{ name, quantity, unit_cost, category }
}
///|
pub fn CostItem::total(self : CostItem) -> Float {
self.quantity * self.unit_cost
}
///|
pub fn CostItem::is_valid(self : CostItem) -> Bool {
self.name.trim().length() > 0 && self.quantity >= 0.0 && self.unit_cost >= 0.0
}
///|
pub struct CostModel {
items : Array[CostItem]
currency : String
period : String
} derive(Debug, Eq)
///|
pub fn cost_model(
items : Array[CostItem],
currency : String,
period : String,
) -> CostModel {
{ items, currency, period }
}
///|
pub fn CostModel::total(self : CostModel) -> Float {
let mut total : Float = 0.0
for item in self.items {
total = total + item.total()
}
total
}
///|
pub fn CostModel::count(self : CostModel) -> Int {
self.items.length()
}
///|
pub fn CostModel::valid(self : CostModel) -> Bool {
for item in self.items {
if !item.is_valid() {
return false
}
}
true
}
///|
pub fn CostModel::by_category(self : CostModel, category : String) -> Float {
let mut total : Float = 0.0
for item in self.items {
if item.category == category {
total = total + item.total()
}
}
total
}
///|
pub fn CostModel::categories(self : CostModel) -> Array[String] {
let result : Array[String] = []
for item in self.items {
if !result.contains(item.category) {
result.push(item.category)
}
}
result
}
///|
pub fn CostModel::category_table(self : CostModel) -> ReportTable {
let rows : Array[Array[String]] = []
for category in self.categories() {
rows.push([
category,
"{self.by_category(category)}",
self.currency,
self.period,
])
}
table(["category", "total", "currency", "period"], rows)
}
///|
pub fn CostModel::item_table(self : CostModel) -> ReportTable {
let rows : Array[Array[String]] = []
for item in self.items {
rows.push([
item.name,
item.category,
"{item.quantity}",
"{item.unit_cost}",
"{item.total()}",
])
}
table(["item", "category", "quantity", "unit cost", "total"], rows)
}
///|
pub fn CostModel::add(self : CostModel, item : CostItem) -> CostModel {
let items = self.items.copy()
items.push(item)
{ ..self, items, }
}
///|
pub fn CostModel::scale(self : CostModel, factor : Float) -> CostModel {
{
..self,
items: self.items.map(fn(item) {
{ ..item, quantity: item.quantity * factor }
}),
}
}
///|
pub struct EnergyCost {
energy : Float
rate : Float
demand_charge : Float
fixed_charge : Float
} derive(Debug, Eq)
///|
pub fn energy_cost(
energy : Float,
rate : Float,
demand_charge : Float,
fixed_charge : Float,
) -> EnergyCost {
{ energy, rate, demand_charge, fixed_charge }
}
///|
pub fn EnergyCost::variable(self : EnergyCost) -> Float {
self.energy * self.rate
}
///|
pub fn EnergyCost::total(self : EnergyCost) -> Float {
self.variable() + self.demand_charge + self.fixed_charge
}
///|
pub fn EnergyCost::average_rate(self : EnergyCost) -> Float {
if self.energy <= 0.0 {
0.0
} else {
self.total() / self.energy
}
}
///|
pub struct ProductionEconomics {
revenue : Float
operating_cost : Float
capital_cost : Float
production : Float
lifetime : Int
} derive(Debug, Eq)
///|
pub fn production_economics(
revenue : Float,
operating_cost : Float,
capital_cost : Float,
production : Float,
lifetime : Int,
) -> ProductionEconomics {
{ revenue, operating_cost, capital_cost, production, lifetime }
}
///|
pub fn ProductionEconomics::gross_margin(self : ProductionEconomics) -> Float {
self.revenue - self.operating_cost
}
///|
pub fn ProductionEconomics::net_margin(self : ProductionEconomics) -> Float {
self.gross_margin() - self.capital_cost
}
///|
pub fn ProductionEconomics::margin_rate(self : ProductionEconomics) -> Float {
if self.revenue == 0.0 {
0.0
} else {
self.gross_margin() / self.revenue
}
}
///|
pub fn ProductionEconomics::unit_cost(self : ProductionEconomics) -> Float {
if self.production <= 0.0 {
0.0
} else {
self.operating_cost / self.production
}
}
///|
pub fn ProductionEconomics::payback_period(self : ProductionEconomics) -> Float {
let annual = self.gross_margin()
if annual <= 0.0 {
0.0
} else {
self.capital_cost / annual
}
}
///|
pub fn ProductionEconomics::simple_roi(self : ProductionEconomics) -> Float {
if self.capital_cost <= 0.0 {
0.0
} else {
self.net_margin() / self.capital_cost
}
}
///|
pub fn ProductionEconomics::is_viable(
self : ProductionEconomics,
maximum_payback : Float,
) -> Bool {
self.gross_margin() > 0.0 &&
self.payback_period() <= maximum_payback &&
self.lifetime > 0
}
///|
pub fn annual_cost(model : CostModel, periods : Int) -> Float {
model.total() * Float::from_int(periods)
}
///|
pub fn unit_revenue(price : Float, quantity : Float) -> Float {
price * quantity
}
///|
pub fn contribution_margin(price : Float, variable_cost : Float) -> Float {
price - variable_cost
}
///|
pub fn break_even_quantity(
fixed_cost : Float,
price : Float,
variable_cost : Float,
) -> Float {
let margin = contribution_margin(price, variable_cost)
if margin <= 0.0 {
0.0
} else {
fixed_cost / margin
}
}
///|
pub fn escalation(value : Float, annual_rate : Float, years : Int) -> Float {
let mut result = value
for _ in 0.. Float {
let mut denominator : Float = 1.0
for _ in 0.. Float {
let mut total : Float = 0.0
for period, cashflow in cashflows {
total = total + cashflow * discount_factor(rate, period)
}
total
}
///|
pub fn net_present_value(
initial : Float,
cashflows : Array[Float],
rate : Float,
) -> Float {
present_value(cashflows, rate) - initial
}
///|
pub fn cost_quality_gate(model : CostModel) -> Bool {
model.valid() && model.total() >= 0.0
}