use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
#[serde(rename_all = "snake_case")]
pub enum AccountLifecyclePhase {
New,
RampUp,
#[default]
Steady,
Decline,
Dormant,
}
impl AccountLifecyclePhase {
pub fn typical_duration_days(&self) -> u32 {
match self {
Self::New => 30,
Self::RampUp => 60,
Self::Steady => 365, Self::Decline => 60,
Self::Dormant => 0, }
}
pub fn activity_multiplier(&self, days_in_phase: u32) -> f64 {
match self {
Self::New => 0.2,
Self::RampUp => {
let progress = (days_in_phase as f64 / 60.0).min(1.0);
0.3 + 0.7 * progress
}
Self::Steady => 1.0,
Self::Decline => {
let progress = (days_in_phase as f64 / 60.0).min(1.0);
0.5 - 0.2 * progress }
Self::Dormant => 0.0,
}
}
pub fn amount_multiplier(&self, days_in_phase: u32) -> f64 {
match self {
Self::New => 0.3,
Self::RampUp => {
let progress = (days_in_phase as f64 / 60.0).min(1.0);
0.4 + 0.6 * progress
}
Self::Steady => 1.0,
Self::Decline => 0.6,
Self::Dormant => 0.0,
}
}
pub fn from_account_age(age_days: u32, days_since_last_activity: u32) -> Self {
if days_since_last_activity >= 90 {
Self::Dormant
} else if age_days <= 30 {
Self::New
} else if age_days <= 90 {
Self::RampUp
} else {
Self::Steady
}
}
}
#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod tests {
use super::*;
#[test]
fn test_new_phase_low_activity() {
assert!(AccountLifecyclePhase::New.activity_multiplier(0) < 0.3);
}
#[test]
fn test_rampup_increases() {
let early = AccountLifecyclePhase::RampUp.activity_multiplier(5);
let late = AccountLifecyclePhase::RampUp.activity_multiplier(55);
assert!(late > early);
assert!(late > 0.9);
}
#[test]
fn test_steady_is_full() {
assert!(
(AccountLifecyclePhase::Steady.activity_multiplier(100) - 1.0).abs() < f64::EPSILON
);
}
#[test]
fn test_dormant_is_zero() {
assert!((AccountLifecyclePhase::Dormant.activity_multiplier(0)).abs() < f64::EPSILON);
}
#[test]
fn test_from_account_age() {
assert_eq!(
AccountLifecyclePhase::from_account_age(5, 0),
AccountLifecyclePhase::New
);
assert_eq!(
AccountLifecyclePhase::from_account_age(50, 0),
AccountLifecyclePhase::RampUp
);
assert_eq!(
AccountLifecyclePhase::from_account_age(200, 0),
AccountLifecyclePhase::Steady
);
assert_eq!(
AccountLifecyclePhase::from_account_age(200, 100),
AccountLifecyclePhase::Dormant
);
}
}