diff --git a/project/src/app.rs b/project/src/app.rs index ae16be0..73a8187 100644 --- a/project/src/app.rs +++ b/project/src/app.rs @@ -86,7 +86,7 @@ impl App { // Making the Backend Calculate This let calculation = backend - .calculate( + .calculator_start( current_membership.into(), new_membership.into(), last_billing.into(), diff --git a/project/src/backend.rs b/project/src/backend.rs index e1b0e71..99c5352 100644 --- a/project/src/backend.rs +++ b/project/src/backend.rs @@ -1,55 +1,13 @@ // Libraries -use chrono::{self, Datelike, Local, NaiveDate}; -use regex::Regex; -use std::io::{Error, ErrorKind, Result}; +mod calculator; +use std::io::Result; -// Functions -fn extract_price(input: String) -> Option { - let re = Regex::new(r"\$?(\d+\.\d+)").unwrap(); - re.captures(&input).and_then(|caps| { - caps.get(1).and_then(|m| { - let num_str = m.as_str().replace(',', ""); - num_str.parse::().ok() - }) - }) -} -fn add_months(date: &NaiveDate, months: i32) -> NaiveDate { - // Getting all required dates for our addition - let mut year = date.year(); - let mut month = date.month() as i32 + months; - let day = date.day(); - - // Adjust year and month to correct values - if month > 12 { - year += (month - 1) / 12; - month = (month - 1) % 12 + 1; - } else if month < 1 { - year -= (12 - month) / 12 + 1; - month = 12 - ((12 - month) % 12); - } - - // Trying to build date on target year/month/day - if invalid (e.g. 31st Feb), fallback: - // We first try creating date with the original day - if let Some(new_date) = NaiveDate::from_ymd_opt(year, month as u32, day) { - new_date - } else { - // If invalid day, set day to last day of previous month by setting day = 0 on next month - // Since NaiveDate::from_ymd_opt(year, month + 1, 0) is last day of month - NaiveDate::from_ymd_opt(year, month as u32 + 1, 0).expect("Invalid date calculation") - } -} +use calculator::{CalculationResult, Calculator}; // Structures pub struct Backend { memberships: Vec, -} -pub struct CalculationResult { - pub change_reg: f32, - pub change_abs: f32, - pub date_str: String, - pub date_num: i32, - pub reversed: bool, - pub invalid: bool, + calculator: Calculator, } // Implementations @@ -80,7 +38,10 @@ impl Backend { }; // Return Self - Ok(Self { memberships }) + Ok(Self { + memberships, + calculator: Calculator::new(), + }) } // Functions @@ -93,110 +54,13 @@ impl Backend { pub fn get_memberships(&self) -> Vec { self.memberships.clone() } - /// Calculates the Prorate with the given parameters - /// - /// # Arguments - /// - /// # Examples - pub fn calculate( + pub fn calculator_start( &self, current_membership: String, new_membership: String, last_billing: String, ) -> Result { - // Extracting the Prices from our Memberships - let current_membership = match extract_price(current_membership) { - Some(m) => m, - None => { - return Err(Error::new( - ErrorKind::InvalidData, - "No Price Found (Current).", - )) - } - }; - let new_membership = match extract_price(new_membership) { - Some(m) => m, - None => return Err(Error::new(ErrorKind::InvalidData, "No Price Found (New).")), - }; - - // Getting the Dates - let last_billing = match NaiveDate::parse_from_str(&last_billing, "%m/%d/%Y") { - Ok(date) => date, - Err(_) => return Err(Error::new(ErrorKind::InvalidData, "Date Format Incorrect.")), - }; - let current_date = Local::now().date_naive(); - - // Getting the amount of Months that have passed - let mut months_passed = (current_date.year() - last_billing.year()) * 12 - + (current_date.month() as i32 - last_billing.month() as i32); - - // Saftey Check - if current_date.day() < last_billing.day() { - months_passed -= 1; - } - - // Are the amount of months that have passed less than 0? - if months_passed < 0 { - months_passed = 0; - } - - // Getting the Cost Difference - let cost_difference = new_membership - current_membership; - - // Stop if there's no price difference - if cost_difference == 0.0 { - return Ok(CalculationResult { - change_reg: 0.0, - change_abs: 0.0, - date_str: String::new(), - date_num: 0, - reversed: false, - invalid: true, - }); - } - - // Getting the billing Start & End - let billing_start = add_months(&last_billing, months_passed); - let billing_end = add_months(&last_billing, months_passed + 1); - - // Getting the days left in our billing cycle - let days_in_cycle = (billing_end - billing_start).num_days() as f32; - - // Getting our daily rate in our plan - let current_daily_rate = current_membership / days_in_cycle; - - // Reversing the adjustment logic here - let adjustment_days = (-cost_difference / current_daily_rate * 10.0).round() / 10.0; - - // Getting the Billing Dates - let billing_date_normal = add_months(&last_billing, months_passed + 1); - let adjustment_days_int = adjustment_days.round() as i64; - let billing_date_adjusted = if adjustment_days_int >= 0 { - billing_date_normal.checked_add_signed(chrono::Duration::days(adjustment_days_int)) - } else { - billing_date_normal.checked_add_signed(chrono::Duration::days(-adjustment_days_int)) - } - .unwrap(); - - // Getting the Adjustment Days - let adjustment_days_f32 = adjustment_days.abs(); - - // Getting the Adjustment Days String - let adjusted_date_string = billing_date_adjusted.format("%m/%d/%Y").to_string(); - let date_number = billing_date_adjusted - .format("%d") - .to_string() - .parse::() - .unwrap_or(0); - - // Ok!! - Ok(CalculationResult { - change_abs: adjustment_days_f32, - change_reg: adjustment_days, - date_str: adjusted_date_string, - date_num: date_number, - reversed: adjustment_days <= 0.0, - invalid: false, - }) + self.calculator + .start(current_membership, new_membership, last_billing) } }