use rust_decimal::Decimal;
use rust_decimal_macros::dec;
pub struct ValueEstimator {
min_margin: Decimal,
target_margin: Decimal,
}
impl ValueEstimator {
pub fn new() -> Self {
Self {
min_margin: dec!(0.1), target_margin: dec!(0.3), }
}
pub fn estimate(&self, _description: &str, estimated_cost: Decimal) -> Decimal {
let margin = estimated_cost * self.target_margin;
estimated_cost + margin
}
pub fn minimum_bid(&self, estimated_cost: Decimal) -> Decimal {
estimated_cost + (estimated_cost * self.min_margin)
}
pub fn ideal_bid(&self, estimated_cost: Decimal) -> Decimal {
estimated_cost + (estimated_cost * self.target_margin)
}
pub fn is_profitable(&self, price: Decimal, estimated_cost: Decimal) -> bool {
let margin = (price - estimated_cost) / price;
margin >= self.min_margin
}
pub fn calculate_profit(&self, earnings: Decimal, actual_cost: Decimal) -> Decimal {
earnings - actual_cost
}
pub fn calculate_margin(&self, earnings: Decimal, actual_cost: Decimal) -> Decimal {
if earnings.is_zero() {
return Decimal::ZERO;
}
(earnings - actual_cost) / earnings
}
pub fn set_min_margin(&mut self, margin: Decimal) {
self.min_margin = margin;
}
pub fn set_target_margin(&mut self, margin: Decimal) {
self.target_margin = margin;
}
}
impl Default for ValueEstimator {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_value_estimation() {
let estimator = ValueEstimator::new();
let cost = dec!(10.0);
let value = estimator.estimate("test job", cost);
assert!(value > cost);
}
#[test]
fn test_profitability() {
let estimator = ValueEstimator::new();
let cost = dec!(10.0);
assert!(estimator.is_profitable(dec!(15.0), cost));
assert!(!estimator.is_profitable(dec!(10.5), cost)); }
#[test]
fn test_margin_calculation() {
let estimator = ValueEstimator::new();
let margin = estimator.calculate_margin(dec!(100.0), dec!(70.0));
assert_eq!(margin, dec!(0.30)); }
}