2019-08-26 00:53:18 +00:00
|
|
|
// Copyright (c) 2017-2019, scoobybejesus
|
2019-08-26 03:42:33 +00:00
|
|
|
// Redistributions must include the license: https://github.com/scoobybejesus/cryptools-rs/blob/master/LEGAL.txt
|
2019-08-26 00:53:18 +00:00
|
|
|
|
|
|
|
use std::error::Error;
|
|
|
|
use std::io::{self, BufRead};
|
|
|
|
use std::process;
|
|
|
|
use std::path::PathBuf;
|
|
|
|
|
|
|
|
use chrono::NaiveDate;
|
|
|
|
use rustyline::completion::{Completer, FilenameCompleter, Pair};
|
|
|
|
use rustyline::{CompletionType, Config, Context, EditMode, Editor, Helper};
|
|
|
|
use rustyline::config::OutputStreamType;
|
|
|
|
use rustyline::hint::{Hinter};
|
|
|
|
use rustyline::error::ReadlineError;
|
|
|
|
use rustyline::highlight::{Highlighter};
|
|
|
|
use crate::core_functions::InventoryCostingMethod;
|
|
|
|
|
2019-08-26 03:29:22 +00:00
|
|
|
use crate::string_utils;
|
2019-08-26 00:53:18 +00:00
|
|
|
|
|
|
|
|
2019-08-30 22:25:14 +00:00
|
|
|
pub fn choose_file_for_import() -> Result<PathBuf, Box<dyn Error>> {
|
2019-08-26 00:53:18 +00:00
|
|
|
|
|
|
|
println!("Please input a file (absolute or relative path) to import: ");
|
|
|
|
|
2019-09-02 00:10:23 +00:00
|
|
|
let (file_string, has_tilde) = _get_path()?;
|
2019-09-01 18:37:00 +00:00
|
|
|
|
|
|
|
if has_tilde {
|
|
|
|
choose_file_for_import()
|
|
|
|
} else {
|
2019-09-02 00:10:23 +00:00
|
|
|
Ok( PathBuf::from(file_string) )
|
2019-09-01 18:37:00 +00:00
|
|
|
}
|
2019-08-26 00:53:18 +00:00
|
|
|
}
|
|
|
|
|
2019-08-30 22:25:14 +00:00
|
|
|
pub fn choose_export_dir() -> Result<PathBuf, Box<dyn Error>> {
|
2019-08-26 00:53:18 +00:00
|
|
|
|
|
|
|
println!("Please input a file path for exports: ");
|
|
|
|
|
2019-09-02 00:10:23 +00:00
|
|
|
let (file_string, has_tilde) = _get_path()?;
|
2019-09-01 18:37:00 +00:00
|
|
|
|
|
|
|
if has_tilde {
|
|
|
|
choose_export_dir()
|
|
|
|
} else {
|
2019-09-02 00:10:23 +00:00
|
|
|
Ok( PathBuf::from(file_string) )
|
2019-09-01 18:37:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-02 00:10:23 +00:00
|
|
|
fn _get_path() -> Result<(String, bool), Box<dyn Error>> {
|
2019-08-26 00:53:18 +00:00
|
|
|
|
|
|
|
struct MyHelper {
|
|
|
|
completer: FilenameCompleter,
|
|
|
|
colored_prompt: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Completer for MyHelper {
|
|
|
|
|
|
|
|
type Candidate = Pair;
|
|
|
|
|
|
|
|
fn complete(
|
|
|
|
&self,
|
|
|
|
line: &str,
|
|
|
|
pos: usize,
|
|
|
|
ctx: &Context<'_>,
|
|
|
|
) -> Result<(usize, Vec<Pair>), ReadlineError> {
|
|
|
|
self.completer.complete(line, pos, ctx)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Hinter for MyHelper {}
|
|
|
|
impl Highlighter for MyHelper {}
|
|
|
|
impl Helper for MyHelper {}
|
|
|
|
|
|
|
|
let h = MyHelper {
|
|
|
|
completer: FilenameCompleter::new(),
|
|
|
|
colored_prompt: "".to_owned(),
|
|
|
|
};
|
|
|
|
|
|
|
|
let config = Config::builder()
|
|
|
|
.history_ignore_space(true)
|
|
|
|
.completion_type(CompletionType::Circular)
|
|
|
|
.edit_mode(EditMode::Vi)
|
|
|
|
.output_stream(OutputStreamType::Stdout)
|
|
|
|
.build();
|
|
|
|
|
|
|
|
let count = 1;
|
|
|
|
let mut rl = Editor::with_config(config);
|
|
|
|
let p = format!("{}> ", count);
|
|
|
|
rl.set_helper(Some(h));
|
|
|
|
rl.helper_mut().unwrap().colored_prompt = format!("\x1b[1;32m{}\x1b[0m", p);
|
|
|
|
let readline = rl.readline(">> ");
|
|
|
|
|
2019-09-02 00:10:23 +00:00
|
|
|
fn begins_with_tilde(unchecked_path: &String) -> bool {
|
|
|
|
match unchecked_path.find("~") {
|
|
|
|
Some(0) => return true,
|
|
|
|
_ => return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-26 00:53:18 +00:00
|
|
|
match readline {
|
|
|
|
Ok(line) => {
|
|
|
|
println!("");
|
2019-09-02 00:10:23 +00:00
|
|
|
let has_tilde = begins_with_tilde(&line);
|
|
|
|
if has_tilde {
|
|
|
|
println!("Unfortunately, the tilde '~' cannot be used as a shortcut for your home directory.\n");
|
|
|
|
}
|
|
|
|
Ok((line, has_tilde))
|
2019-08-26 00:53:18 +00:00
|
|
|
},
|
|
|
|
Err(err) => {
|
|
|
|
println!("Error during Rustyline: {:?}", err);
|
|
|
|
process::exit(1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// impl std::convert::From<OsStr> for InventoryCostingMethod {
|
|
|
|
// fn from(osstr: OsStr) -> InventoryCostingMethod {
|
|
|
|
// let osstring1 = OsString::from(Box::<osstr>);
|
|
|
|
// let new_string = osstr.into_string().expect("Invalid input. Could not convert to string.");
|
|
|
|
// let method = match new_string.trim() {
|
|
|
|
// "1" => InventoryCostingMethod::LIFObyLotCreationDate,
|
|
|
|
// "2" => InventoryCostingMethod::LIFObyLotBasisDate,
|
|
|
|
// "3" => InventoryCostingMethod::FIFObyLotCreationDate,
|
|
|
|
// "4" => InventoryCostingMethod::FIFObyLotBasisDate,
|
|
|
|
// _ => { println!("Invalid choice. Could not convert."); process::exit(1)
|
|
|
|
// }
|
|
|
|
// };
|
|
|
|
// method
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
|
2019-08-30 22:25:14 +00:00
|
|
|
pub fn choose_inventory_costing_method() -> Result<InventoryCostingMethod, Box<dyn Error>> {
|
2019-08-26 00:53:18 +00:00
|
|
|
|
|
|
|
println!("Choose the lot inventory costing method. [Default: 1]");
|
|
|
|
println!("1. LIFO according to the order the lot was created.");
|
|
|
|
println!("2. LIFO according to the basis date of the lot.");
|
|
|
|
println!("3. FIFO according to the order the lot was created.");
|
|
|
|
println!("4. FIFO according to the basis date of the lot.");
|
|
|
|
|
2019-08-29 03:22:48 +00:00
|
|
|
let method = _costing_method()?;
|
2019-08-26 00:53:18 +00:00
|
|
|
|
2019-08-30 22:25:14 +00:00
|
|
|
fn _costing_method() -> Result<InventoryCostingMethod, Box<dyn Error>> {
|
2019-08-26 00:53:18 +00:00
|
|
|
|
|
|
|
let mut input = String::new();
|
|
|
|
let stdin = io::stdin();
|
|
|
|
stdin.lock().read_line(&mut input).expect("Failed to read stdin");
|
|
|
|
|
|
|
|
match input.trim() { // Without .trim(), there's a hidden \n or something preventing the match
|
|
|
|
"1" | "" => Ok(InventoryCostingMethod::LIFObyLotCreationDate),
|
|
|
|
"2" => Ok(InventoryCostingMethod::LIFObyLotBasisDate),
|
|
|
|
"3" => Ok(InventoryCostingMethod::FIFObyLotCreationDate),
|
|
|
|
"4" => Ok(InventoryCostingMethod::FIFObyLotBasisDate),
|
|
|
|
_ => { println!("Invalid choice. Please enter a valid number."); _costing_method() }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-29 03:22:48 +00:00
|
|
|
Ok(method)
|
2019-08-26 00:53:18 +00:00
|
|
|
}
|
2019-08-26 03:15:33 +00:00
|
|
|
pub fn inv_costing_from_cmd_arg(arg: String) -> Result<InventoryCostingMethod, &'static str> {
|
2019-08-26 02:42:14 +00:00
|
|
|
|
|
|
|
match arg.trim() { // Without .trim(), there's a hidden \n or something preventing the match
|
|
|
|
"1" => Ok(InventoryCostingMethod::LIFObyLotCreationDate),
|
|
|
|
"2" => Ok(InventoryCostingMethod::LIFObyLotBasisDate),
|
|
|
|
"3" => Ok(InventoryCostingMethod::FIFObyLotCreationDate),
|
|
|
|
"4" => Ok(InventoryCostingMethod::FIFObyLotBasisDate),
|
|
|
|
_ => {
|
|
|
|
println!("Invalid choice. Please enter a valid number.");
|
|
|
|
return Err("Invalid choice");
|
2019-08-26 00:53:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-08-29 03:22:48 +00:00
|
|
|
|
2019-08-30 22:25:14 +00:00
|
|
|
pub fn elect_like_kind_treatment(cutoff_date_arg: &Option<String>) -> Result<(bool, String), Box<dyn Error>> {
|
2019-08-29 03:22:48 +00:00
|
|
|
|
2019-09-03 03:49:18 +00:00
|
|
|
match cutoff_date_arg {
|
|
|
|
|
|
|
|
Some(cutoff_date_arg) => {
|
|
|
|
let provided_date = NaiveDate::parse_from_str(&cutoff_date_arg, "%y-%m-%d")
|
|
|
|
.unwrap_or(NaiveDate::parse_from_str(&cutoff_date_arg, "%Y-%m-%d")
|
|
|
|
.expect("Date entered as -c command line arg has an incorrect format."));
|
|
|
|
|
|
|
|
println!("\nUse like-kind exchange treatment through {}? [Y/n/c] ('c' to 'change') ", provided_date);
|
|
|
|
|
|
|
|
let (election, date) = _elect_like_kind_arg(&cutoff_date_arg, provided_date)?;
|
|
|
|
|
|
|
|
fn _elect_like_kind_arg(cutoff_date_arg: &String, provided_date: NaiveDate) -> Result<(bool, String), Box<dyn Error>> {
|
|
|
|
|
|
|
|
let mut input = String::new();
|
|
|
|
let stdin = io::stdin();
|
|
|
|
stdin.lock().read_line(&mut input)?;
|
|
|
|
|
|
|
|
|
|
|
|
match input.trim().to_ascii_lowercase().as_str() {
|
|
|
|
"y" | "ye" | "yes" | "" => {
|
|
|
|
println!(" Using like-kind treatment through {}.\n", provided_date);
|
|
|
|
Ok( (true, cutoff_date_arg.to_string()) )
|
|
|
|
},
|
|
|
|
"n" | "no" => {
|
|
|
|
println!(" Proceeding without like-kind treatment.\n");
|
|
|
|
Ok( (false, "1-1-1".to_string()) )
|
|
|
|
},
|
|
|
|
"c" | "change" => {
|
|
|
|
println!("Please enter your desired like-kind exchange treatment cutoff date.");
|
|
|
|
println!(" You must use the format %y-%m-%d (e.g., 2017-12-31, 17-12-31, and 9-6-1 are all acceptable).\n");
|
|
|
|
|
|
|
|
let mut input = String::new();
|
|
|
|
let stdin = io::stdin();
|
|
|
|
stdin.lock().read_line(&mut input)?;
|
|
|
|
string_utils::trim_newline(&mut input);
|
|
|
|
|
|
|
|
let newly_chosen_date = NaiveDate::parse_from_str(&input, "%y-%m-%d")
|
|
|
|
.unwrap_or(NaiveDate::parse_from_str(&input, "%Y-%m-%d")
|
|
|
|
.expect("Date entered has an incorrect format. Program must abort."));
|
|
|
|
// TODO: figure out how to make this fail gracefully and let the user input the date again
|
|
|
|
println!(" Using like-kind treatment through {}.\n", newly_chosen_date);
|
|
|
|
Ok( (true, input) )
|
|
|
|
},
|
|
|
|
_ => {
|
|
|
|
println!("Please respond with 'y', 'n', or 'c' (or 'yes' or 'no' or 'change').");
|
|
|
|
_elect_like_kind_arg(&cutoff_date_arg, provided_date)
|
|
|
|
}
|
2019-08-26 00:53:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-03 03:49:18 +00:00
|
|
|
return Ok((election, date))
|
|
|
|
}
|
2019-08-26 00:53:18 +00:00
|
|
|
|
2019-09-03 03:49:18 +00:00
|
|
|
None => {
|
|
|
|
println!("\nContinue without like-kind exchange treatment? [Y/n] ");
|
|
|
|
|
|
|
|
let (election, date) = _no_elect_like_kind_arg()?;
|
|
|
|
|
|
|
|
fn _no_elect_like_kind_arg() -> Result<(bool, String), Box<dyn Error>> {
|
|
|
|
|
|
|
|
let mut input = String::new();
|
|
|
|
let stdin = io::stdin();
|
|
|
|
stdin.lock().read_line(&mut input)?;
|
|
|
|
|
|
|
|
match input.trim().to_ascii_lowercase().as_str() {
|
|
|
|
"y" | "ye" | "yes" | "" => {
|
|
|
|
println!(" Proceeding without like-kind treatment.\n");
|
|
|
|
Ok( (false, "1-1-1".to_string()) )
|
|
|
|
},
|
|
|
|
"n" | "no" => {
|
|
|
|
println!("Please enter your desired like-kind exchange treatment cutoff date.");
|
|
|
|
println!(" You must use the format %y-%m-%d (e.g., 2017-12-31, 17-12-31, and 9-6-1 are all acceptable).\n");
|
|
|
|
let mut input = String::new();
|
|
|
|
let stdin = io::stdin();
|
|
|
|
stdin.lock().read_line(&mut input)?;
|
|
|
|
string_utils::trim_newline(&mut input);
|
|
|
|
|
|
|
|
let newly_chosen_date = NaiveDate::parse_from_str(&input, "%y-%m-%d")
|
|
|
|
.unwrap_or(NaiveDate::parse_from_str(&input, "%Y-%m-%d")
|
|
|
|
.expect("Date entered has an incorrect format. Program must abort."));
|
|
|
|
// TODO: figure out how to make this fail gracefully and let the user input the date again
|
|
|
|
println!(" Using like-kind treatment through {}.\n", newly_chosen_date);
|
|
|
|
|
|
|
|
Ok( (true, input) )
|
|
|
|
},
|
|
|
|
_ => { println!("Please respond with 'y' or 'n' (or 'yes' or 'no')."); _no_elect_like_kind_arg() }
|
|
|
|
}
|
2019-08-26 00:53:18 +00:00
|
|
|
}
|
|
|
|
|
2019-09-03 03:49:18 +00:00
|
|
|
return Ok((election, date))
|
|
|
|
}
|
2019-08-26 00:53:18 +00:00
|
|
|
}
|
|
|
|
}
|