Added CLI arg for indicating input file date separator character. Also cleaned up Cli struct. Takes care of one item from #48.

This commit is contained in:
scoobybejesus 2019-10-06 14:04:38 -04:00
parent 8dfb79ed9b
commit 8567dd04b0
5 changed files with 56 additions and 17 deletions

View File

@ -52,6 +52,7 @@ pub struct ImportProcessParameters {
pub enable_like_kind_treatment: bool, pub enable_like_kind_treatment: bool,
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(crate) fn import_and_process_final( pub(crate) fn import_and_process_final(
@ -62,7 +63,7 @@ pub(crate) fn import_and_process_final(
HashMap<u16, RawAccount>, HashMap<u16, RawAccount>,
HashMap<u32, ActionRecord>, HashMap<u32, ActionRecord>,
HashMap<u32, Transaction>, HashMap<u32, Transaction>,
Option<LikeKindSettings> Option<LikeKindSettings>,
), Box<dyn Error>> { ), Box<dyn Error>> {
let mut transactions_map: HashMap<u32, Transaction> = HashMap::new(); let mut transactions_map: HashMap<u32, Transaction> = HashMap::new();
@ -76,7 +77,8 @@ pub(crate) fn import_and_process_final(
&mut transactions_map, &mut transactions_map,
&mut action_records_map, &mut action_records_map,
&mut raw_account_map, &mut raw_account_map,
&mut account_map &mut account_map,
&settings.date_separator,
) { ) {
Ok(()) => { println!("Successfully imported csv file."); } Ok(()) => { println!("Successfully imported csv file."); }
Err(err) => { Err(err) => {
@ -93,6 +95,7 @@ pub(crate) fn import_and_process_final(
action_records: &mut HashMap<u32, ActionRecord>, action_records: &mut HashMap<u32, ActionRecord>,
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,
) -> 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");
@ -107,6 +110,7 @@ pub(crate) fn import_and_process_final(
&mut rdr, &mut rdr,
transactions_map, transactions_map,
action_records, action_records,
date_separator,
)?; )?;
Ok(()) Ok(())

View File

@ -111,6 +111,7 @@ pub(crate) fn import_transactions(
rdr: &mut csv::Reader<File>, rdr: &mut csv::Reader<File>,
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,
) -> Result<(), Box<dyn Error>> { ) -> Result<(), Box<dyn Error>> {
let mut this_tx_number = 0; let mut this_tx_number = 0;
@ -199,9 +200,12 @@ pub(crate) fn import_transactions(
None => {} None => {}
} }
let tx_date = NaiveDate::parse_from_str(this_tx_date, "%m/%d/%y") let format_yy: &str = &("%m".to_owned() + sep + &"%d" + sep + "%y");
.unwrap_or(NaiveDate::parse_from_str(this_tx_date, "%m/%d/%Y") let format_yyyy: &str = &("%m".to_owned() + sep + &"%d" + sep + "%Y");
.expect("%m/%d/%y (or %Y) format required for ledger import")
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")
); );
let transaction = Transaction { let transaction = Transaction {

View File

@ -33,6 +33,9 @@ mod skip_wizard;
#[structopt(name = "cryptools")] #[structopt(name = "cryptools")]
pub(crate) struct Cli { pub(crate) struct Cli {
#[structopt(flatten)]
flags: Flags,
/// 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>,
@ -41,16 +44,18 @@ pub(crate) struct Cli {
#[structopt(name = "output directory", short, long = "output", default_value = ".", parse(from_os_str))] #[structopt(name = "output directory", short, long = "output", default_value = ".", parse(from_os_str))]
output_dir_path: PathBuf, output_dir_path: PathBuf,
/// This will prevent the program from writing the CSV to file. This will be ignored if -a is not set (the wizard will always ask to output). /// Choose "h" or "s" for hyphen or slash (i.e., "-" or "/") to indicate the separator character used
#[structopt(name = "suppress reports", short, long = "suppress")] /// in the input file txDate column (i.e. 2017/12/31 or 2017-12-31).
suppress_reports: bool, #[structopt(name = "date separator character", short, long = "date-separator", default_value = "h", parse(from_os_str))]
date_separator: 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 = "cutoff", parse(from_os_str))] #[structopt(name = "like-kind cutoff date", short, long = "lk-cutoff", parse(from_os_str))]
cutoff_date: Option<OsString>, lk_cutoff_date: Option<OsString>,
/// Inventory costing method (in terms of lot selection, i.e., LIFO, FIFO, etc.). There are currently four options (1 through 4). /// Inventory costing method (in terms of lot selection, i.e., LIFO, FIFO, etc.).
/// There are currently four options (1 through 4).
#[structopt(name = "method", short, long, default_value = "1", parse(from_os_str), long_help = #[structopt(name = "method", short, long, default_value = "1", parse(from_os_str), long_help =
r" 1. LIFO according to the order the lot was created. r" 1. LIFO according to the order the lot was created.
2. LIFO according to the basis date of the lot. 2. LIFO according to the basis date of the lot.
@ -59,13 +64,24 @@ pub(crate) struct Cli {
")] ")]
inv_costing_method: OsString, inv_costing_method: OsString,
/// Home currency (currency in which all resulting reports are denominated). (Only available as a command line setting.) /// 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))] #[structopt(name = "home currency", short = "c", long = "currency", default_value = "USD", parse(from_os_str))]
home_currency: OsString, home_currency: OsString,
}
/// User is instructing the program to skip the data entry wizard. When set, program will error without required command-line args. #[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")] #[structopt(name = "accept args", short, long = "accept")]
accept_args: bool, 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,
} }
@ -92,7 +108,7 @@ fn main() -> Result<(), Box<dyn Error>> {
let like_kind_settings; let like_kind_settings;
let should_export; let should_export;
if !args.accept_args { if !args.flags.accept_args {
let ( let (
account_map1, account_map1,

View File

@ -3,6 +3,7 @@
use std::error::Error; use std::error::Error;
use std::collections::{HashMap}; use std::collections::{HashMap};
use std::process;
use crate::cli_user_choices; use crate::cli_user_choices;
use crate::core_functions::{self, LikeKindSettings, ImportProcessParameters}; use crate::core_functions::{self, LikeKindSettings, ImportProcessParameters};
@ -19,6 +20,12 @@ 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() {
"h" => {"-"}
"s" => {"/"}
_ => { println!("\nFATAL: The date-separator arg requires either an 'h' or an 's'.\n"); process::exit(1) }
};
let input_file_path; let input_file_path;
if let Some(file) = args.file_to_import { if let Some(file) = args.file_to_import {
@ -37,7 +44,7 @@ pub(crate) fn skip_wizard(args: super::Cli) -> Result<(
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.cutoff_date { if let Some(date) = args.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 {
@ -51,6 +58,7 @@ pub(crate) fn skip_wizard(args: super::Cli) -> Result<(
costing_method: costing_method_choice, costing_method: costing_method_choice,
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(),
}; };
let ( let (
@ -61,7 +69,7 @@ pub(crate) fn skip_wizard(args: super::Cli) -> Result<(
like_kind_settings1 like_kind_settings1
) = core_functions::import_and_process_final(input_file_path, &settings)?; ) = core_functions::import_and_process_final(input_file_path, &settings)?;
let should_export = !args.suppress_reports; let should_export = !args.flags.suppress_reports;
Ok((account_map1, raw_acct_map1, action_records_map1, transactions_map1, like_kind_settings1, settings, should_export)) Ok((account_map1, raw_acct_map1, action_records_map1, transactions_map1, like_kind_settings1, settings, should_export))
} }

View File

@ -24,6 +24,12 @@ 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() {
"h" => {"-"}
"s" => {"/"}
_ => { println!("\nFATAL: The date-separator arg requires either an 'h' or an 's'.\n"); process::exit(1) }
};
let input_file_path; let input_file_path;
if let Some(file) = args.file_to_import { if let Some(file) = args.file_to_import {
@ -40,7 +46,7 @@ pub(crate) fn wizard(args: super::Cli) -> Result<(
let lk_cutoff_date_opt_string; let lk_cutoff_date_opt_string;
if let Some(lk_cutoff) = args.cutoff_date { if let Some(lk_cutoff) = args.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
@ -54,6 +60,7 @@ pub(crate) fn wizard(args: super::Cli) -> Result<(
costing_method: costing_method_choice, costing_method: costing_method_choice,
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(),
}; };
let ( let (