From 7002923a4ccf336acee2117529c82248451321dc Mon Sep 17 00:00:00 2001 From: scoobybejesus Date: Sun, 6 Oct 2019 15:05:45 -0400 Subject: [PATCH] Added Cli flag for indicating the input file date field uses ISO 8601 formatting. Also separated flattened Cli struct more. Resolves #48. --- src/core_functions.rs | 4 +++ src/csv_import_accts_txns.rs | 17 ++++++++--- src/main.rs | 56 ++++++++++++++++++++++-------------- src/skip_wizard.rs | 11 +++---- src/wizard.rs | 11 +++---- 5 files changed, 64 insertions(+), 35 deletions(-) diff --git a/src/core_functions.rs b/src/core_functions.rs index e258e25..8ee1cbf 100644 --- a/src/core_functions.rs +++ b/src/core_functions.rs @@ -53,6 +53,7 @@ pub struct ImportProcessParameters { pub costing_method: InventoryCostingMethod, pub lk_cutoff_date_string: String, pub date_separator: String, + pub iso_date_style: bool, } pub(crate) fn import_and_process_final( @@ -79,6 +80,7 @@ pub(crate) fn import_and_process_final( &mut raw_account_map, &mut account_map, &settings.date_separator, + settings.iso_date_style, ) { Ok(()) => { println!("Successfully imported csv file."); } Err(err) => { @@ -96,6 +98,7 @@ pub(crate) fn import_and_process_final( raw_acct_map: &mut HashMap, acct_map: &mut HashMap, date_separator: &str, + iso_date_style: bool, ) -> Result<(), Box> { let file = File::open(import_file_path)?; println!("CSV ledger file opened successfully.\n"); @@ -111,6 +114,7 @@ pub(crate) fn import_and_process_final( transactions_map, action_records, date_separator, + iso_date_style, )?; Ok(()) diff --git a/src/csv_import_accts_txns.rs b/src/csv_import_accts_txns.rs index 4fcee9b..e0b5293 100644 --- a/src/csv_import_accts_txns.rs +++ b/src/csv_import_accts_txns.rs @@ -112,6 +112,7 @@ pub(crate) fn import_transactions( txns_map: &mut HashMap, action_records: &mut HashMap, sep: &str, + iso: bool, ) -> Result<(), Box> { let mut this_tx_number = 0; @@ -200,11 +201,19 @@ pub(crate) fn import_transactions( None => {} } - let format_yy: &str = &("%m".to_owned() + sep + &"%d" + sep + "%y"); - let format_yyyy: &str = &("%m".to_owned() + sep + &"%d" + sep + "%Y"); + let format_yy: String; + let format_yyyy: String; - let tx_date = NaiveDate::parse_from_str(this_tx_date, format_yy) - .unwrap_or(NaiveDate::parse_from_str(this_tx_date, format_yyyy) + if iso { + format_yyyy = "%Y".to_owned() + sep + &"%d" + sep + "%m"; + format_yy = "%y".to_owned() + sep + &"%d" + sep + "%m"; + } else { + format_yyyy = "%m".to_owned() + sep + &"%d" + sep + "%Y"; + format_yy = "%m".to_owned() + sep + &"%d" + sep + "%y"; + } + + let tx_date = NaiveDate::parse_from_str(this_tx_date, &format_yy) + .unwrap_or(NaiveDate::parse_from_str(this_tx_date, &format_yyyy) .expect("\nFailed to parse date in input file. Check date separator character. Also %m/%d/%y (or %Y) format is required.\n") ); diff --git a/src/main.rs b/src/main.rs index 21a373d..ba050b8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -36,19 +36,48 @@ pub(crate) struct Cli { #[structopt(flatten)] flags: Flags, + #[structopt(flatten)] + opts: Options, + /// File to be imported. (Currently, the only supported date format is %m/%d/%y.) #[structopt(name = "file", parse(from_os_str))] file_to_import: Option, +} - /// Output directory for exported reports. - #[structopt(name = "output directory", short, long = "output", default_value = ".", parse(from_os_str))] - output_dir_path: PathBuf, +#[derive(StructOpt, Debug)] +pub(crate) struct Flags { + + /// User is instructing the program to skip the data entry wizard. + /// When set, program will error without required command-line args. + #[structopt(name = "accept args", short = "a", long = "accept")] + accept_args: bool, + + /// This will cause the program to expect the txDate field in the file_to_import to use the format + /// YYYY-MM-dd or YY-MM-dd (or YYYY/MM/dd or YY/MM/dd, depending on the date-separator option) + /// instead of the default US-style MM-dd-YYYY or MM-dd-YY (or MM/dd/YYYY or MM/dd/YY, depending on the + /// date separator option). + #[structopt(name = "date conforms to ISO 8601", short = "i", long = "iso")] + iso_date: bool, + + /// This will prevent the program from writing reports to files. + /// This will be ignored if -a is not set (the wizard will always ask to output). + #[structopt(name = "suppress reports", short, long = "suppress")] + suppress_reports: bool, +} + +#[derive(StructOpt, Debug)] +pub(crate) struct Options { /// Choose "h" or "s" for hyphen or slash (i.e., "-" or "/") to indicate the separator character used /// in the input file txDate column (i.e. 2017/12/31 or 2017-12-31). #[structopt(name = "date separator character", short, long = "date-separator", default_value = "h", parse(from_os_str))] date_separator: OsString, + /// Home currency (currency in which all resulting reports are denominated). + /// (Only available as a command line setting.) + #[structopt(name = "home currency", short = "c", long = "currency", default_value = "USD", parse(from_os_str))] + home_currency: OsString, + /// Cutoff date through which like-kind exchange treatment should be applied. /// Please use %y-%m-%d (or %Y-%m-%d) format for like-kind cutoff date entry. #[structopt(name = "like-kind cutoff date", short, long = "lk-cutoff", parse(from_os_str))] @@ -64,24 +93,9 @@ pub(crate) struct Cli { ")] inv_costing_method: OsString, - /// Home currency (currency in which all resulting reports are denominated). - /// (Only available as a command line setting.) - #[structopt(name = "home currency", short = "c", long = "currency", default_value = "USD", parse(from_os_str))] - home_currency: OsString, -} - -#[derive(StructOpt, Debug)] -pub(crate) struct Flags { - - /// User is instructing the program to skip the data entry wizard. - /// When set, program will error without required command-line args. - #[structopt(name = "accept args", short, long = "accept")] - accept_args: bool, - - /// This will prevent the program from writing reports to files. - /// This will be ignored if -a is not set (the wizard will always ask to output). - #[structopt(name = "suppress reports", short, long = "suppress")] - suppress_reports: bool, + /// Output directory for exported reports. + #[structopt(name = "output directory", short, long = "output", default_value = ".", parse(from_os_str))] + output_dir_path: PathBuf, } diff --git a/src/skip_wizard.rs b/src/skip_wizard.rs index 7ea9eb5..40e5d26 100644 --- a/src/skip_wizard.rs +++ b/src/skip_wizard.rs @@ -20,7 +20,7 @@ pub(crate) fn skip_wizard(args: super::Cli) -> Result<( bool ), Box> { - let date_separator = match args.date_separator.into_string().unwrap().as_str() { + let date_separator = match args.opts.date_separator.into_string().unwrap().as_str() { "h" => {"-"} "s" => {"/"} _ => { println!("\nFATAL: The date-separator arg requires either an 'h' or an 's'.\n"); process::exit(1) } @@ -35,16 +35,16 @@ pub(crate) fn skip_wizard(args: super::Cli) -> Result<( input_file_path = cli_user_choices::choose_file_for_import()?; } - let output_dir_path = args.output_dir_path; + let output_dir_path = args.opts.output_dir_path; - let costing_method_choice = cli_user_choices::inv_costing_from_cmd_arg(args.inv_costing_method)?; + let costing_method_choice = cli_user_choices::inv_costing_from_cmd_arg(args.opts.inv_costing_method)?; - let home_currency_choice = args.home_currency.into_string().unwrap().to_uppercase(); + let home_currency_choice = args.opts.home_currency.into_string().unwrap().to_uppercase(); let like_kind_election; let like_kind_cutoff_date_string: String; - if let Some(date) = args.lk_cutoff_date { + if let Some(date) = args.opts.lk_cutoff_date { like_kind_election = true; like_kind_cutoff_date_string = date.into_string().unwrap(); } else { @@ -59,6 +59,7 @@ pub(crate) fn skip_wizard(args: super::Cli) -> Result<( enable_like_kind_treatment: like_kind_election, lk_cutoff_date_string: like_kind_cutoff_date_string, date_separator: date_separator.to_string(), + iso_date_style: args.flags.iso_date }; let ( diff --git a/src/wizard.rs b/src/wizard.rs index a2374ee..9fe6e35 100644 --- a/src/wizard.rs +++ b/src/wizard.rs @@ -24,7 +24,7 @@ pub(crate) fn wizard(args: super::Cli) -> Result<( shall_we_proceed()?; - let date_separator = match args.date_separator.into_string().unwrap().as_str() { + let date_separator = match args.opts.date_separator.into_string().unwrap().as_str() { "h" => {"-"} "s" => {"/"} _ => { println!("\nFATAL: The date-separator arg requires either an 'h' or an 's'.\n"); process::exit(1) } @@ -38,15 +38,15 @@ pub(crate) fn wizard(args: super::Cli) -> Result<( input_file_path = cli_user_choices::choose_file_for_import()?; } - let output_dir_path = args.output_dir_path; + let output_dir_path = args.opts.output_dir_path; - let costing_method_choice = cli_user_choices::choose_inventory_costing_method(args.inv_costing_method)?; + let costing_method_choice = cli_user_choices::choose_inventory_costing_method(args.opts.inv_costing_method)?; - let home_currency_choice = args.home_currency.into_string().unwrap().to_uppercase(); + let home_currency_choice = args.opts.home_currency.into_string().unwrap().to_uppercase(); let lk_cutoff_date_opt_string; - if let Some(lk_cutoff) = args.lk_cutoff_date { + if let Some(lk_cutoff) = args.opts.lk_cutoff_date { lk_cutoff_date_opt_string = Some(lk_cutoff.into_string().unwrap()) } else { lk_cutoff_date_opt_string = None @@ -61,6 +61,7 @@ pub(crate) fn wizard(args: super::Cli) -> Result<( enable_like_kind_treatment: like_kind_election, lk_cutoff_date_string: like_kind_cutoff_date, date_separator: date_separator.to_string(), + iso_date_style: args.flags.iso_date }; let (