Added error handling. Started with impl Transaction TxType, but it would have been quite verbose to not return more result types in other parts of the code, so did that as well. Resolves #18.

This commit is contained in:
scoobybejesus 2019-08-28 10:05:42 -04:00
parent 71a51e83a7
commit ff52fac130
6 changed files with 46 additions and 41 deletions

View File

@ -5,6 +5,7 @@ use std::rc::{Rc, Weak};
use std::cell::{Cell, RefCell}; use std::cell::{Cell, RefCell};
use std::fmt; use std::fmt;
use std::collections::{HashMap}; use std::collections::{HashMap};
use std::error::Error;
use chrono::{NaiveDate, NaiveTime, NaiveDateTime, DateTime, Utc, TimeZone}; use chrono::{NaiveDate, NaiveTime, NaiveDateTime, DateTime, Utc, TimeZone};
use chrono_tz::US::Eastern; use chrono_tz::US::Eastern;
@ -178,19 +179,19 @@ impl Movement {
raw_accts: &HashMap<u16, RawAccount>, raw_accts: &HashMap<u16, RawAccount>,
acct_map: &HashMap<u16, Account>, acct_map: &HashMap<u16, Account>,
txns_map: &HashMap<u32, Transaction>, txns_map: &HashMap<u32, Transaction>,
)-> d128 { )-> Result<d128, Box<Error>> {
let txn = txns_map.get(&self.transaction_key).expect("Couldn't get txn. Tx num invalid?"); let txn = txns_map.get(&self.transaction_key).expect("Couldn't get txn. Tx num invalid?");
match txn.transaction_type(ar_map, raw_accts, acct_map) { match txn.transaction_type(ar_map, raw_accts, acct_map)? {
TxType::Flow => { TxType::Flow => {
let ar = ar_map.get(&self.action_record_key).unwrap(); let ar = ar_map.get(&self.action_record_key).unwrap();
if ar.direction() == Polarity::Incoming { if ar.direction() == Polarity::Incoming {
self.proceeds.get() Ok(self.proceeds.get())
} }
else { d128!(0) } else { Ok(d128!(0)) }
} }
TxType::Exchange => { d128!(0) } TxType::Exchange => { Ok(d128!(0)) }
TxType::ToSelf => { d128!(0) } TxType::ToSelf => { Ok(d128!(0)) }
} }
} }
@ -200,19 +201,19 @@ impl Movement {
raw_accts: &HashMap<u16, RawAccount>, raw_accts: &HashMap<u16, RawAccount>,
acct_map: &HashMap<u16, Account>, acct_map: &HashMap<u16, Account>,
txns_map: &HashMap<u32, Transaction>, txns_map: &HashMap<u32, Transaction>,
)-> d128 { )-> Result<d128, Box<Error>> {
let txn = txns_map.get(&self.transaction_key).expect("Couldn't get txn. Tx num invalid?"); let txn = txns_map.get(&self.transaction_key).expect("Couldn't get txn. Tx num invalid?");
match txn.transaction_type(ar_map, raw_accts, acct_map) { match txn.transaction_type(ar_map, raw_accts, acct_map)? {
TxType::Flow => { TxType::Flow => {
let ar = ar_map.get(&self.action_record_key).unwrap(); let ar = ar_map.get(&self.action_record_key).unwrap();
if ar.direction() == Polarity::Outgoing { if ar.direction() == Polarity::Outgoing {
self.proceeds.get() Ok(self.proceeds.get())
} }
else { d128!(0) } else { Ok(d128!(0)) }
} }
TxType::Exchange => { d128!(0) } TxType::Exchange => { Ok(d128!(0)) }
TxType::ToSelf => { d128!(0) } TxType::ToSelf => { Ok(d128!(0)) }
} }
} }

View File

@ -49,10 +49,10 @@ pub fn create_lots_and_movements(
let txn_num = num as u32; let txn_num = num as u32;
let txn = txns_map.get(&(txn_num)).expect("Couldn't get txn. Tx num invalid?"); let txn = txns_map.get(&(txn_num)).expect("Couldn't get txn. Tx num invalid?");
if txn.marginness(&ar_map, &raw_acct_map, &acct_map) == TxHasMargin::TwoARs { if txn.marginness(&ar_map, &raw_acct_map, &acct_map) == TxHasMargin::TwoARs {
assert_eq!(txn.transaction_type(&ar_map, &raw_acct_map, &acct_map), TxType::Exchange); assert_eq!(txn.transaction_type(&ar_map, &raw_acct_map, &acct_map)?, TxType::Exchange);
assert_eq!(txn.action_record_idx_vec.len(), 2); assert_eq!(txn.action_record_idx_vec.len(), 2);
let the_raw_pair_keys = txn.get_base_and_quote_raw_acct_keys(&ar_map, &raw_acct_map, &acct_map); let the_raw_pair_keys = txn.get_base_and_quote_raw_acct_keys(&ar_map, &raw_acct_map, &acct_map)?;
let base_acct = acct_map.get(&the_raw_pair_keys.0).expect("Couldn't get acct. Raw pair keys invalid?"); let base_acct = acct_map.get(&the_raw_pair_keys.0).expect("Couldn't get acct. Raw pair keys invalid?");
let quote_acct = acct_map.get(&the_raw_pair_keys.1).expect("Couldn't get acct. Raw pair keys invalid?"); let quote_acct = acct_map.get(&the_raw_pair_keys.1).expect("Couldn't get acct. Raw pair keys invalid?");
@ -217,7 +217,7 @@ pub fn create_lots_and_movements(
} }
// Note: a_r is not in home currency if here or below // Note: a_r is not in home currency if here or below
let polarity = ar.direction(); let polarity = ar.direction();
let tx_type = txn.transaction_type(&ar_map, &raw_acct_map, &acct_map); let tx_type = txn.transaction_type(&ar_map, &raw_acct_map, &acct_map)?;
match polarity { match polarity {
Polarity::Outgoing => { Polarity::Outgoing => {
@ -409,7 +409,7 @@ pub fn create_lots_and_movements(
&raw_acct_map, &raw_acct_map,
&acct_map, &acct_map,
&txns_map, &txns_map,
); )?;
let base_acct = acct_map.get(&base_acct_key).unwrap(); let base_acct = acct_map.get(&base_acct_key).unwrap();
let base_acct_lot = base_acct.list_of_lots.borrow().last().unwrap().clone(); let base_acct_lot = base_acct.list_of_lots.borrow().last().unwrap().clone();
@ -579,7 +579,7 @@ fn get_base_and_quote_acct_for_dual_actionrecord_flow_tx(
raw_acct_map: &HashMap<u16, RawAccount>, raw_acct_map: &HashMap<u16, RawAccount>,
acct_map: &HashMap<u16, Account>, acct_map: &HashMap<u16, Account>,
txns_map: &HashMap<u32, Transaction>, txns_map: &HashMap<u32, Transaction>,
) -> (u16, u16) { ) -> Result<(u16, u16), Box<Error>> {
let txn = txns_map.get(&txn_num).expect("Couldn't get txn. Tx num invalid?"); let txn = txns_map.get(&txn_num).expect("Couldn't get txn. Tx num invalid?");
let og_flow_ar = ar_map.get(txn.action_record_idx_vec.first().unwrap()).unwrap(); let og_flow_ar = ar_map.get(txn.action_record_idx_vec.first().unwrap()).unwrap();
@ -597,8 +597,8 @@ fn get_base_and_quote_acct_for_dual_actionrecord_flow_tx(
let (base_key,quote_key) = txn_of_og_mvmt_lot_first_mvmt.get_base_and_quote_raw_acct_keys( let (base_key,quote_key) = txn_of_og_mvmt_lot_first_mvmt.get_base_and_quote_raw_acct_keys(
ar_map, ar_map,
&raw_acct_map, &raw_acct_map,
&acct_map); // TODO: should this panic on margin loss? &acct_map)?; // TODO: should this panic on margin loss?
(base_key, quote_key) Ok((base_key, quote_key))
} }
fn get_base_and_quote_ar_idxs( fn get_base_and_quote_ar_idxs(

View File

@ -4,6 +4,7 @@
use std::fs::File; use std::fs::File;
use std::collections::{HashMap}; use std::collections::{HashMap};
use std::path::PathBuf; use std::path::PathBuf;
use std::error::Error;
use decimal::d128; use decimal::d128;
@ -201,7 +202,7 @@ pub fn _5_transaction_mvmt_summaries_to_csv(
raw_acct_map: &HashMap<u16, RawAccount>, raw_acct_map: &HashMap<u16, RawAccount>,
acct_map: &HashMap<u16, Account>, acct_map: &HashMap<u16, Account>,
txns_map: &HashMap<u32, Transaction>, txns_map: &HashMap<u32, Transaction>,
) { ) -> Result<(), Box<Error>> {
let mut rows: Vec<Vec<String>> = [].to_vec(); let mut rows: Vec<Vec<String>> = [].to_vec();
let mut header: Vec<String> = [].to_vec(); let mut header: Vec<String> = [].to_vec();
@ -230,7 +231,7 @@ pub fn _5_transaction_mvmt_summaries_to_csv(
let txn = txns_map.get(&(txn_num)).unwrap(); let txn = txns_map.get(&(txn_num)).unwrap();
let txn_date_string = txn.date.format("%Y/%m/%d").to_string(); let txn_date_string = txn.date.format("%Y/%m/%d").to_string();
let tx_num_string = txn.tx_number.to_string(); let tx_num_string = txn.tx_number.to_string();
let tx_type_string = txn.transaction_type(ars, &raw_acct_map, &acct_map).to_string(); let tx_type_string = txn.transaction_type(ars, &raw_acct_map, &acct_map)?.to_string();
let tx_memo_string = txn.memo.to_string(); let tx_memo_string = txn.memo.to_string();
let mut term_st: Option<Term> = None; let mut term_st: Option<Term> = None;
let mut term_lt: Option<Term> = None; let mut term_lt: Option<Term> = None;
@ -257,7 +258,7 @@ pub fn _5_transaction_mvmt_summaries_to_csv(
raw_acct_map, raw_acct_map,
acct_map, acct_map,
txns_map txns_map
); )?;
for mvmt in flow_or_outgoing_exchange_movements.iter() { for mvmt in flow_or_outgoing_exchange_movements.iter() {
let lot = mvmt.get_lot(acct_map, ars); let lot = mvmt.get_lot(acct_map, ars);
@ -294,7 +295,7 @@ pub fn _5_transaction_mvmt_summaries_to_csv(
} }
} }
if (txn.transaction_type(ars, &raw_acct_map, &acct_map) == TxType::Flow) & (polarity == Some(Polarity::Incoming)) { if (txn.transaction_type(ars, &raw_acct_map, &acct_map)? == TxType::Flow) & (polarity == Some(Polarity::Incoming)) {
// println!("Incoming flow {}", txn.tx_number); // println!("Incoming flow {}", txn.tx_number);
income_st = proceeds_st; income_st = proceeds_st;
proceeds_st = d128!(0); proceeds_st = d128!(0);
@ -304,7 +305,7 @@ pub fn _5_transaction_mvmt_summaries_to_csv(
cost_basis_lt = d128!(0); cost_basis_lt = d128!(0);
} }
if (txn.transaction_type(ars, &raw_acct_map, &acct_map) == TxType::Flow) & (polarity == Some(Polarity::Outgoing)) { if (txn.transaction_type(ars, &raw_acct_map, &acct_map)? == TxType::Flow) & (polarity == Some(Polarity::Outgoing)) {
// println!("Outgoing flow {}, proceeds_st {}, proceeds_lt {}", txn.tx_number, proceeds_st, proceeds_lt); // println!("Outgoing flow {}, proceeds_st {}, proceeds_lt {}", txn.tx_number, proceeds_st, proceeds_lt);
expense_st -= proceeds_st; expense_st -= proceeds_st;
expense_lt -= proceeds_lt; expense_lt -= proceeds_lt;
@ -361,6 +362,8 @@ pub fn _5_transaction_mvmt_summaries_to_csv(
wtr.write_record(row).expect("Could not write row to CSV file"); wtr.write_record(row).expect("Could not write row to CSV file");
} }
wtr.flush().expect("Could not flush Writer, though file should exist and be complete"); wtr.flush().expect("Could not flush Writer, though file should exist and be complete");
Ok(())
} }
// pub fn accounts_to_csv( // pub fn accounts_to_csv(

View File

@ -37,7 +37,7 @@ pub fn add_cost_basis_to_movements(
for mvmt in movements.iter() { for mvmt in movements.iter() {
let polarity = ar.direction(); let polarity = ar.direction();
let tx_type = txn.transaction_type(ars, raw_acct_map, acct_map); let tx_type = txn.transaction_type(ars, raw_acct_map, acct_map)?;
let is_home_curr = raw_acct.is_home_currency(&settings.home_currency); let is_home_curr = raw_acct.is_home_currency(&settings.home_currency);
let mvmt_copy = mvmt.clone(); let mvmt_copy = mvmt.clone();
let borrowed_mvmt = mvmt_copy.clone(); let borrowed_mvmt = mvmt_copy.clone();
@ -169,7 +169,7 @@ pub fn add_proceeds_to_movements(
for mvmt in movements.iter() { for mvmt in movements.iter() {
let polarity = ar.direction(); let polarity = ar.direction();
let tx_type = txn.transaction_type(ars, raw_acct_map, acct_map); let tx_type = txn.transaction_type(ars, raw_acct_map, acct_map)?;
let mvmt_copy = mvmt.clone(); let mvmt_copy = mvmt.clone();
let borrowed_mvmt = mvmt_copy.clone(); let borrowed_mvmt = mvmt_copy.clone();
@ -249,7 +249,7 @@ fn update_current_txn_for_prior_likekind_treatment(
for mvmt in movements.iter() { for mvmt in movements.iter() {
let polarity = ar.direction(); let polarity = ar.direction();
let tx_type = txn.transaction_type(ars, raw_acct_map, acct_map); let tx_type = txn.transaction_type(ars, raw_acct_map, acct_map)?;
let is_home_curr = raw_acct.is_home_currency(&settings.home_currency); let is_home_curr = raw_acct.is_home_currency(&settings.home_currency);
let mvmt_copy = mvmt.clone(); let mvmt_copy = mvmt.clone();
@ -303,7 +303,7 @@ fn perform_likekind_treatment_on_txn(
) -> Result<(), Box<Error>> { ) -> Result<(), Box<Error>> {
let txn = txns_map.get(&txn_num).unwrap(); let txn = txns_map.get(&txn_num).unwrap();
let tx_type = txn.transaction_type(ars, raw_acct_map, acct_map); let tx_type = txn.transaction_type(ars, raw_acct_map, acct_map)?;
let og_ar = ars.get(&txn.action_record_idx_vec.first().unwrap()).unwrap(); let og_ar = ars.get(&txn.action_record_idx_vec.first().unwrap()).unwrap();
let ic_ar = ars.get(&txn.action_record_idx_vec.last().unwrap()).unwrap(); let ic_ar = ars.get(&txn.action_record_idx_vec.last().unwrap()).unwrap();

View File

@ -291,7 +291,7 @@ fn main() -> Result<(), Box<dyn Error>> {
&raw_acct_map, &raw_acct_map,
&account_map, &account_map,
&transactions_map &transactions_map
); )?;
} }

View File

@ -6,6 +6,7 @@ use std::cell::{RefCell};
use std::process::exit; use std::process::exit;
use std::fmt; use std::fmt;
use std::collections::{HashMap}; use std::collections::{HashMap};
use std::error::Error;
use decimal::d128; use decimal::d128;
use chrono::NaiveDate; use chrono::NaiveDate;
@ -30,10 +31,10 @@ impl Transaction {
ars: &HashMap<u32, ActionRecord>, ars: &HashMap<u32, ActionRecord>,
raw_acct_map: &HashMap<u16, RawAccount>, raw_acct_map: &HashMap<u16, RawAccount>,
acct_map: &HashMap<u16, Account>, acct_map: &HashMap<u16, Account>,
) -> TxType { ) -> Result<TxType, Box<Error>> {
if self.action_record_idx_vec.len() == 1 { if self.action_record_idx_vec.len() == 1 {
TxType::Flow Ok(TxType::Flow)
} }
else if self.action_record_idx_vec.len() == 2 { else if self.action_record_idx_vec.len() == 2 {
// This exercise of splitting the strings is because of margin accounts, where BTC borrowed to buy XMR would reflect as BTC_xmr // This exercise of splitting the strings is because of margin accounts, where BTC borrowed to buy XMR would reflect as BTC_xmr
@ -55,14 +56,14 @@ impl Transaction {
} }
if ar1_ticker == ar2_ticker { if ar1_ticker == ar2_ticker {
if ar1_raw_acct.is_margin != ar2_raw_acct.is_margin { if ar1_raw_acct.is_margin != ar2_raw_acct.is_margin {
TxType::Flow Ok(TxType::Flow)
} }
else { else {
TxType::ToSelf Ok(TxType::ToSelf)
} }
} }
else { else {
TxType::Exchange Ok(TxType::Exchange)
} }
} }
else if self.action_record_idx_vec.len() > 2 { else if self.action_record_idx_vec.len() > 2 {
@ -111,9 +112,9 @@ impl Transaction {
ars: &HashMap<u32, ActionRecord>, ars: &HashMap<u32, ActionRecord>,
raw_accts: &HashMap<u16, RawAccount>, raw_accts: &HashMap<u16, RawAccount>,
acct_map: &HashMap<u16, Account> acct_map: &HashMap<u16, Account>
) -> (u16, u16) { ) -> Result<(u16, u16), Box<Error>> {
assert_eq!(self.transaction_type(ars, raw_accts, acct_map), TxType::Exchange, assert_eq!(self.transaction_type(ars, raw_accts, acct_map)?, TxType::Exchange,
"This can only be called on exchange transactions."); "This can only be called on exchange transactions.");
let first_ar = ars.get(&self.action_record_idx_vec[0]).unwrap(); let first_ar = ars.get(&self.action_record_idx_vec[0]).unwrap();
@ -134,11 +135,11 @@ impl Transaction {
if first_raw_acct.ticker.contains('_') { if first_raw_acct.ticker.contains('_') {
quote = first_acct_raw_key; quote = first_acct_raw_key;
base = second_acct_raw_key; base = second_acct_raw_key;
(base, quote) Ok((base, quote))
} else if second_raw_acct.ticker.contains('_') { } else if second_raw_acct.ticker.contains('_') {
base = first_acct_raw_key; base = first_acct_raw_key;
quote = second_acct_raw_key; quote = second_acct_raw_key;
(base, quote) Ok((base, quote))
} else { } else {
println!("{}", VariousErrors::MarginNoUnderbar); use std::process::exit; exit(1) println!("{}", VariousErrors::MarginNoUnderbar); use std::process::exit; exit(1)
} }
@ -151,7 +152,7 @@ impl Transaction {
raw_acct_map: &HashMap<u16, RawAccount>, raw_acct_map: &HashMap<u16, RawAccount>,
acct_map: &HashMap<u16, Account>, acct_map: &HashMap<u16, Account>,
txns_map: &HashMap<u32, Transaction>, txns_map: &HashMap<u32, Transaction>,
) -> Vec<Rc<Movement>> { ) -> Result<Vec<Rc<Movement>>, Box<Error>> {
let mut flow_or_outgoing_exchange_movements = [].to_vec(); let mut flow_or_outgoing_exchange_movements = [].to_vec();
@ -165,7 +166,7 @@ impl Transaction {
let movements = ar.get_mvmts_in_ar(acct_map, txns_map); let movements = ar.get_mvmts_in_ar(acct_map, txns_map);
match self.transaction_type(ars, raw_acct_map, acct_map) { match self.transaction_type(ars, raw_acct_map, acct_map)? {
TxType::Exchange => { TxType::Exchange => {
if Polarity::Outgoing == ar.direction() { if Polarity::Outgoing == ar.direction() {
for mvmt in movements.iter() { for mvmt in movements.iter() {
@ -182,7 +183,7 @@ impl Transaction {
} }
} }
} }
flow_or_outgoing_exchange_movements Ok(flow_or_outgoing_exchange_movements)
} }
} }