diff options
| author | Yaroslav <contact@yaroslavps.com> | 2020-10-05 21:20:59 +0300 | 
|---|---|---|
| committer | Yaroslav <contact@yaroslavps.com> | 2020-10-05 21:20:59 +0300 | 
| commit | 408b0ac993496b108ec1e479151d549e9535051a (patch) | |
| tree | 6f19aa190a7f5707cc037f3f9590a89187582254 /src | |
| download | finbudg-0.1.0.tar.gz finbudg-0.1.0.zip | |
initial commitv0.1.0
Diffstat (limited to 'src')
| -rw-r--r-- | src/main.rs | 244 | 
1 files changed, 244 insertions, 0 deletions
| diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..d091965 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,244 @@ +use clap::{ +    Arg,  +    App,  +    ArgMatches, +    crate_version,  +    crate_authors,  +    crate_description +}; +use chrono::Duration; +use colored::*; + +use budget::*; + +fn main() { +    let matches = get_cli_matches(); + +    let no_color = matches.occurrences_of("plain") > 0; +    let force_color = matches.occurrences_of("force-color") > 0; +    let input = matches.value_of("INPUT").unwrap(); + +    let account = match budget::parse_account(input) { +        Ok(data) => data, +        Err(error) => { +            match error { +                ParseError::IOError(kind) => { +                    println!("IO error while parsing: {:?}", kind); +                }, +                ParseError::DeserializerError(_) => { +                    println!("Can't parse the file, invalid syntax"); +                }, +            } + +            ::std::process::exit(1); +        } +    }; +    let calculated = budget::calculate(&account); + +    if no_color && !force_color { +        colored::control::set_override(false); +    } else if force_color { +        colored::control::set_override(true); +    } + +    output(account, calculated); +} + +fn get_cli_matches() -> ArgMatches<'static> { +    App::new("finbudg") +        .version(crate_version!()) +        .author(crate_authors!()) +        .about(crate_description!()) +        .arg(Arg::with_name("plain") +            .short("p") +            .long("plain") +            .help("Don't colorize the output. Can also be set \ +            with the NO_COLOR environment variable.") +            .takes_value(false)) +        .arg(Arg::with_name("force-color") +            .long("force-color") +            .help("Forces colorized output even when piping. Takes \ +            precedence over --plain flag and NO_COLOR environment \ +            variable") +            .takes_value(false)) +        .arg(Arg::with_name("INPUT") +            .help("Expenses file in toml format to calculate from.") +            .required(true) +            .index(1)) +        .get_matches() +} + +fn output(account: Account, calculated: Calculated) { +    println!( +        "{}", +        format!( +            "Your expenses for the period of {} - {}", +            account.start_date.format("%Y-%m-%d"), +            account.end_date.format("%Y-%m-%d"), +        ).cyan(), +    ); + +    let last_day = match account.days.last() { +        Some(day) => day, +        None => { +            println!("{}", "Your expenses are empty...".italic()); + +            ::std::process::exit(0); +        } +    }; + +    let days_until_end = account.end_date - last_day.date; + +    println!( +        "{}",  +        format!( +            "Last day on entry: {}", +            last_day.date.format("%Y-%m-%d"), +        ).cyan(), +    ); + +    println!( +        "{}",  +        format!( +            "Days until period end: {}", +            days_until_end.num_days(), +        ).cyan(), +    ); + +    if days_until_end < Duration::zero() { +        println!(); +        println!( +            "{}",  +            "Your last day on entry is set after the last date of the period!" +            .yellow(), +        ); +        println!(); +    } + +    println!( +        "{}", +        format!( +            "Budget: {:.2}", +            account.budget, +        ).cyan(), +    ); + +    println!(); + +    for (category, expenses) in calculated.categories_day_average.iter() { +        println!( +            "Average per day in {}: {:.2}", +            category, +            expenses, +        ); +    } + +    println!( +        "Average per day in essential expenses: {:.2}", +        calculated.essential_day_average, +    ); + +    println!( +        "Average per day: {:.2}", +        calculated.all_day_average, +    ); + +    println!(); + +    for (category, expenses) in calculated.categories_subtotal.iter() { +        println!( +            "Total in {}: {:.2}", +            category, +            expenses, +        ); +    } + +    println!( +        "Total in essential expenses: {:.2}", +        calculated.essential_subtotal, +    ); + +    println!( +        "Total: {:.2}", +        calculated.total, +    ); + +    println!(); + +    let balance_output = format!("{:.2}", calculated.balance); +    let balance_output = if calculated.balance > 0.0 { +        if account.budget / calculated.balance < 10.0 { +            balance_output.green() +        } else { +            balance_output.yellow() +        } +    } else { +        balance_output.red() +    }; + +    println!("Left on balance: {}", balance_output); + +    println!(); + +    println!("Days until balance runs out:"); + +    let days_left_output = format!( +        "{:.2}", +        calculated.days_left, +    ); +    let days_left_essential_output = format!( +        "{:.2}", +        calculated.days_left_essential, +    ); + +    let mut all_are_healthy = true; +    let mut essential_are_healthy = true; + +    let days_left_output =  +        if days_until_end.num_days() as f64 <= calculated.days_left { +            days_left_output.green() +        } else { +            all_are_healthy = false; + +            days_left_output.red() +        }; +    let days_left_essential_output =  +        if days_until_end.num_days() as f64 <= calculated.days_left_essential { +            days_left_essential_output.green() +        } else { +            essential_are_healthy = false; + +            days_left_essential_output.red() +        }; + +    println!( +        "..taking into account all expenses: {}", +        days_left_output, +    ); +    println!( +        "..taking into account only essential expenses: {}", +        days_left_essential_output, +    ); +    println!(); + +    if all_are_healthy { +        println!( +            "{}", +            "Your expenses are healthy, they should last you from your last \ +            day on entry through your last day of the period.".green(), +        ); +    } else { +        println!( +            "{}", +            "You are spending more than you can afford with your current \ +            budget. Try minimizing your expenses".red(), +        ); +        if essential_are_healthy { +            println!( +                "{}", +                "On the other hand, if you only spend money on essentials, \ +                you should be able keep within your budget.".yellow(), +            ); +        } +    } +} | 
