Added Cli flag for indicating the input file date field uses ISO 8601 formatting. Also separated flattened Cli struct more. Resolves #48.

This commit is contained in:
scoobybejesus 2019-10-06 15:05:45 -04:00
parent 8567dd04b0
commit 7002923a4c
5 changed files with 64 additions and 35 deletions

View File

@ -53,6 +53,7 @@ pub struct ImportProcessParameters {
pub costing_method: InventoryCostingMethod, pub costing_method: InventoryCostingMethod,
pub lk_cutoff_date_string: String, pub lk_cutoff_date_string: String,
pub date_separator: String, pub date_separator: String,
pub iso_date_style: bool,
} }
pub(crate) fn import_and_process_final( pub(crate) fn import_and_process_final(
@ -79,6 +80,7 @@ pub(crate) fn import_and_process_final(
&mut raw_account_map, &mut raw_account_map,
&mut account_map, &mut account_map,
&settings.date_separator, &settings.date_separator,
settings.iso_date_style,
) { ) {
Ok(()) => { println!("Successfully imported csv file."); } Ok(()) => { println!("Successfully imported csv file."); }
Err(err) => { Err(err) => {
@ -96,6 +98,7 @@ pub(crate) fn import_and_process_final(
raw_acct_map: &mut HashMap<u16, RawAccount>, raw_acct_map: &mut HashMap<u16, RawAccount>,
acct_map: &mut HashMap<u16, Account>, acct_map: &mut HashMap<u16, Account>,
date_separator: &str, date_separator: &str,
iso_date_style: bool,
) -> Result<(), Box<dyn Error>> { ) -> Result<(), Box<dyn Error>> {
let file = File::open(import_file_path)?; println!("CSV ledger file opened successfully.\n"); 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, transactions_map,
action_records, action_records,
date_separator, date_separator,
iso_date_style,
)?; )?;
Ok(()) Ok(())

View File

@ -112,6 +112,7 @@ pub(crate) fn import_transactions(
txns_map: &mut HashMap<u32, Transaction>, txns_map: &mut HashMap<u32, Transaction>,
action_records: &mut HashMap<u32, ActionRecord>, action_records: &mut HashMap<u32, ActionRecord>,
sep: &str, sep: &str,
iso: bool,
) -> Result<(), Box<dyn Error>> { ) -> Result<(), Box<dyn Error>> {
let mut this_tx_number = 0; let mut this_tx_number = 0;
@ -200,11 +201,19 @@ pub(crate) fn import_transactions(
None => {} None => {}
} }
let format_yy: &str = &("%m".to_owned() + sep + &"%d" + sep + "%y"); let format_yy: String;
let format_yyyy: &str = &("%m".to_owned() + sep + &"%d" + sep + "%Y"); let format_yyyy: String;
let tx_date = NaiveDate::parse_from_str(this_tx_date, format_yy) if iso {
.unwrap_or(NaiveDate::parse_from_str(this_tx_date, format_yyyy) 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") .expect("\nFailed to parse date in input file. Check date separator character. Also %m/%d/%y (or %Y) format is required.\n")
); );

View File

@ -36,19 +36,48 @@ pub(crate) struct Cli {
#[structopt(flatten)] #[structopt(flatten)]
flags: Flags, flags: Flags,
#[structopt(flatten)]
opts: Options,
/// File to be imported. (Currently, the only supported date format is %m/%d/%y.) /// File to be imported. (Currently, the only supported date format is %m/%d/%y.)
#[structopt(name = "file", parse(from_os_str))] #[structopt(name = "file", parse(from_os_str))]
file_to_import: Option<PathBuf>, file_to_import: Option<PathBuf>,
}
/// Output directory for exported reports. #[derive(StructOpt, Debug)]
#[structopt(name = "output directory", short, long = "output", default_value = ".", parse(from_os_str))] pub(crate) struct Flags {
output_dir_path: PathBuf,
/// 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 /// 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). /// 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))] #[structopt(name = "date separator character", short, long = "date-separator", default_value = "h", parse(from_os_str))]
date_separator: OsString, 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. /// 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. /// 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))] #[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, inv_costing_method: OsString,
/// Home currency (currency in which all resulting reports are denominated). /// Output directory for exported reports.
/// (Only available as a command line setting.) #[structopt(name = "output directory", short, long = "output", default_value = ".", parse(from_os_str))]
#[structopt(name = "home currency", short = "c", long = "currency", default_value = "USD", parse(from_os_str))] output_dir_path: PathBuf,
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,
} }

View File

@ -20,7 +20,7 @@ pub(crate) fn skip_wizard(args: super::Cli) -> Result<(
bool bool
), Box<dyn Error>> { ), Box<dyn Error>> {
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" => {"-"} "h" => {"-"}
"s" => {"/"} "s" => {"/"}
_ => { println!("\nFATAL: The date-separator arg requires either an 'h' or an 's'.\n"); process::exit(1) } _ => { 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()?; 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_election;
let like_kind_cutoff_date_string: String; 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_election = true;
like_kind_cutoff_date_string = date.into_string().unwrap(); like_kind_cutoff_date_string = date.into_string().unwrap();
} else { } else {
@ -59,6 +59,7 @@ pub(crate) fn skip_wizard(args: super::Cli) -> Result<(
enable_like_kind_treatment: like_kind_election, enable_like_kind_treatment: like_kind_election,
lk_cutoff_date_string: like_kind_cutoff_date_string, lk_cutoff_date_string: like_kind_cutoff_date_string,
date_separator: date_separator.to_string(), date_separator: date_separator.to_string(),
iso_date_style: args.flags.iso_date
}; };
let ( let (

View File

@ -24,7 +24,7 @@ pub(crate) fn wizard(args: super::Cli) -> Result<(
shall_we_proceed()?; 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" => {"-"} "h" => {"-"}
"s" => {"/"} "s" => {"/"}
_ => { println!("\nFATAL: The date-separator arg requires either an 'h' or an 's'.\n"); process::exit(1) } _ => { 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()?; 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; 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()) lk_cutoff_date_opt_string = Some(lk_cutoff.into_string().unwrap())
} else { } else {
lk_cutoff_date_opt_string = None 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, enable_like_kind_treatment: like_kind_election,
lk_cutoff_date_string: like_kind_cutoff_date, lk_cutoff_date_string: like_kind_cutoff_date,
date_separator: date_separator.to_string(), date_separator: date_separator.to_string(),
iso_date_style: args.flags.iso_date
}; };
let ( let (