Skip to content

Commit

Permalink
Reporting Errors to GUI (#85)
Browse files Browse the repository at this point in the history
* - Reporting first error to notes works

* - more errors to be reported to GUI

* - Added reporting of errors to GUI from transactions
  • Loading branch information
jczaja authored Nov 10, 2023
1 parent 790d293 commit 03b590f
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 47 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "etradeTaxReturnHelper"
version = "0.3.0"
version = "0.3.1"
edition = "2021"
description = "Parses etrade financial documents for transaction details (income, tax paid, cost basis) and compute total income and total tax paid according to chosen tax residency (currency)"
license = "BSD-3-Clause"
Expand Down
18 changes: 15 additions & 3 deletions src/gui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ pub mod gui {
let mut file_names: Vec<String> = vec![];
let list_names = browser.borrow();
log::info!("Processing {} files", list_names.size());
for i in 1..list_names.size() + 1 {
for i in 1..=list_names.size() {
let line_content = browser.borrow().text(i);
match line_content {
Some(text) => {
Expand All @@ -92,10 +92,16 @@ pub mod gui {
}
}
}
buffer.set_text("");
tbuffer.set_text("");
nbuffer.set_text("Running...");
let rd: Box<dyn etradeTaxReturnHelper::Residency> = Box::new(PL {});
let (gross_div, tax_div, gross_sold, cost_sold, div_transactions, sold_transactions) =
match run_taxation(&rd, file_names) {
Ok((gd, td, gs, cs, dts, sts)) => (gd, td, gs, cs, dts, sts),
Ok((gd, td, gs, cs, dts, sts)) => {
nbuffer.set_text("Finished.\n\n (Double check if generated tax data (Summary) makes sense and then copy it to your tax form)");
(gd, td, gs, cs, dts, sts)
}
Err(err) => {
nbuffer.set_text(&err);
panic!("Error: unable to perform taxation");
Expand Down Expand Up @@ -217,7 +223,13 @@ pub mod gui {

let mut pack3 = Pack::new(0, 0, SUMMARY_COL_WIDTH, 300, "");
pack3.set_type(fltk::group::PackType::Vertical);
let mut frame3 = Frame::new(0, 0, SUMMARY_COL_WIDTH, 30, "Summary");
let mut frame3 = Frame::new(
0,
0,
SUMMARY_COL_WIDTH,
30,
"Summary (Data for your Tax form)",
);
frame3.set_frame(FrameType::EngravedFrame);

let buffer = TextBuffer::default();
Expand Down
39 changes: 18 additions & 21 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,39 +109,43 @@ pub trait Residency {

let base_exchange_rate_url = "https://www.exchange-rates.org/Rate/";

dates.iter_mut().for_each(|(date, val)| {
let mut converted_date = chrono::NaiveDate::parse_from_str(&date, "%m/%d/%y").unwrap();
dates.iter_mut().try_for_each(|(date, val)| {
let mut converted_date = chrono::NaiveDate::parse_from_str(&date, "%m/%d/%y")
.map_err(|x| format!("Unable to convert date {x}"))?;

converted_date = converted_date
.checked_sub_signed(chrono::Duration::days(1))
.expect_and_log("Error traversing date");
.ok_or("Error traversing date")?;

let exchange_rate_url: String = base_exchange_rate_url.to_string()
+ &format!("{}/{}/{}", from, to, converted_date.format("%m-%d-%Y"))
+ "/?format=json";

let body = client.get(&(exchange_rate_url)).send();
let actual_body = body.expect_and_log(&format!(
"Getting Exchange Rate from Exchange-Rates.org ({}) failed",
exchange_rate_url
));
let actual_body = body.map_err(|_| {
format!(
"Getting Exchange Rate from Exchange-Rates.org ({}) failed",
exchange_rate_url
)
})?;
if actual_body.status().is_success() {
log::info!("RESPONSE {:#?}", actual_body);

let exchange_rates_response = actual_body
.text()
.expect_and_log("Error converting response to Text");
.map_err(|_| "Error converting response to Text")?;
log::info!("body of exchange_rate = {:#?}", &exchange_rates_response);
// parsing text response
if let Ok((exchange_rate, exchange_rate_date)) =
self.parse_exchange_rates(&exchange_rates_response)
{
*val = Some((exchange_rate_date, exchange_rate));
}
Ok(())
} else {
panic!("Error getting exchange rate");
return Err("Error getting exchange rate".to_string());
}
});
})?;

Ok(())
}
Expand Down Expand Up @@ -198,18 +202,12 @@ pub fn run_taxation(
}
});
// 2. Verify Transactions
match verify_dividends_transactions(&parsed_div_transactions) {
Ok(()) => log::info!("Dividends transactions are consistent"),
Err(msg) => {
println!("{}", msg);
log::warn!("{}", msg);
}
}
verify_dividends_transactions(&parsed_div_transactions)?;
log::info!("Dividends transactions are consistent");

// 3. Verify and create full sold transactions info needed for TAX purposes
let detailed_sold_transactions =
reconstruct_sold_transactions(&parsed_sold_transactions, &parsed_gain_and_losses)
.expect_and_log("Error reconstructing detailed sold transactions.");
reconstruct_sold_transactions(&parsed_sold_transactions, &parsed_gain_and_losses)?;

// 4. Get Exchange rates
// Gather all trade , settlement and transaction dates into hash map to be passed to
Expand Down Expand Up @@ -238,8 +236,7 @@ pub fn run_taxation(
},
);

rd.get_exchange_rates(&mut dates)
.expect_and_log("Error: unable to get exchange rates");
rd.get_exchange_rates(&mut dates).map_err(|x| "Error: unable to get exchange rates. Please check your internet connection or proxy settings\n\nDetails:".to_string()+&x)?;

// Make a detailed_div_transactions
let transactions = create_detailed_div_transactions(parsed_div_transactions, &dates);
Expand Down
9 changes: 7 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,12 @@ fn main() {

let pdfnames: Vec<String> = pdfnames.map(|x| x.to_string()).collect();

let (gross_div, tax_div, gross_sold, cost_sold, _, _) = run_taxation(&rd, pdfnames).unwrap();
let (gross_div, tax_div, gross_sold, cost_sold) = match run_taxation(&rd, pdfnames) {
Ok((gross_div, tax_div, gross_sold, cost_sold, _, _)) => {
(gross_div, tax_div, gross_sold, cost_sold)
}
Err(msg) => panic!("\nError: Unable to compute taxes. \n\nDetails: {msg}"),
};

let presentation = rd.present_result(gross_div, tax_div, gross_sold, cost_sold);
presentation.iter().for_each(|x| println!("{x}"));
Expand Down Expand Up @@ -242,7 +247,7 @@ mod tests {
);
Ok(())
}
Err(x) => panic!("Error in taxation process"),
Err(x) => panic!("Error in taxation process: {x}"),
}
}

Expand Down
33 changes: 20 additions & 13 deletions src/pl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,54 +41,61 @@ impl etradeTaxReturnHelper::Residency for PL {
// If there is proxy then pick first URL
let base_client = ReqwestClient::builder();
let client = match &http_proxy {
Ok(proxy) => base_client
.proxy(reqwest::Proxy::http(proxy).expect_and_log("Error setting HTTP proxy")),
Ok(proxy) => base_client.proxy(
reqwest::Proxy::http(proxy)
.map_err(|x| format!("Error setting HTTP proxy. \nDetails: {}", x))?,
),
Err(_) => base_client,
};
let client = match &https_proxy {
Ok(proxy) => client
.proxy(reqwest::Proxy::https(proxy).expect_and_log("Error setting HTTP proxy")),
Ok(proxy) => client.proxy(
reqwest::Proxy::https(proxy)
.map_err(|x| format!("Error setting HTTPS proxy. \nDetails: {}", x))?,
),
Err(_) => client,
};
let client = client
.build()
.expect_and_log("Could not create REST API client");
.map_err(|_| "Could not create REST API client")?;

let base_exchange_rate_url = "https://api.nbp.pl/api/exchangerates/rates/a/";

dates.iter_mut().for_each(|(date, val)| {
dates.iter_mut().try_for_each(|(date, val)| {
let mut converted_date = chrono::NaiveDate::parse_from_str(&date, "%m/%d/%y").unwrap();

// Try to get exchange rate going backwards with dates till success
let mut is_success = false;
while is_success == false {
converted_date = converted_date
.checked_sub_signed(chrono::Duration::days(1))
.expect_and_log("Error traversing date");
.ok_or("Error traversing date")?;

let exchange_rate_url: String = base_exchange_rate_url.to_string()
+ &format!("usd/{}", converted_date.format("%Y-%m-%d"))
+ "/?format=json";

let body = client.get(&(exchange_rate_url)).send();
let actual_body = body.expect_and_log(&format!(
"Getting Exchange Rate from NBP ({}) failed",
exchange_rate_url
));
let actual_body = body.map_err(|_| {
format!(
"Getting Exchange Rate from NBP ({}) failed",
exchange_rate_url
)
})?;
is_success = actual_body.status().is_success();
if is_success == true {
log::info!("RESPONSE {:#?}", actual_body);

let nbp_response = actual_body
.json::<NBPResponse<ExchangeRate>>()
.expect_and_log("Error converting response to JSON");
.map_err(|_| "Error: getting exchange rate from NBP")?;
log::info!("body of exchange_rate = {:#?}", nbp_response);
let exchange_rate = nbp_response.rates[0].mid;
let exchange_rate_date = format!("{}", converted_date.format("%Y-%m-%d"));
*val = Some((exchange_rate_date, exchange_rate));
};
}
});
Ok::<(), String>(())
})?;
Ok(())
}

Expand Down
13 changes: 7 additions & 6 deletions src/transactions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@ pub fn verify_dividends_transactions(
.unwrap()
.year();
if tr_year != transaction_year {
let msg: &str =
"WARNING! Brokerage statements are related to different years. Was it intentional?";
let msg: &str = "Error: Brokerage statements are related to different years!";
verification = Err(msg.to_owned());
}
});
Expand All @@ -51,8 +50,8 @@ pub fn reconstruct_sold_transactions(
let mut detailed_sold_transactions: Vec<(String, String, String, f32, f32)> = vec![];

if sold_transactions.len() > 0 && gains_and_losses.is_empty() {
panic!("\n\nERROR: Sold transaction detected, but corressponding Gain&Losses document is missing. Please download Gain&Losses XLSX document at:\n
https://us.etrade.com/etx/sp/stockplan#/myAccount/gainsLosses\n\n");
return Err("\n\nERROR: Sold transaction detected, but corressponding Gain&Losses document is missing. Please download Gain&Losses XLSX document at:\n
https://us.etrade.com/etx/sp/stockplan#/myAccount/gainsLosses\n\n".to_string());
}

// iterate through all sold transactions and update it with needed info
Expand Down Expand Up @@ -492,7 +491,6 @@ mod tests {
}

#[test]
#[should_panic]
fn test_sold_transaction_reconstruction_no_gains_fail() {
let parsed_sold_transactions: Vec<(String, String, i32, f32, f32)> = vec![
(
Expand All @@ -513,6 +511,9 @@ mod tests {

let parsed_gains_and_losses: Vec<(String, String, f32, f32, f32)> = vec![];

let _ = reconstruct_sold_transactions(&parsed_sold_transactions, &parsed_gains_and_losses);
let result =
reconstruct_sold_transactions(&parsed_sold_transactions, &parsed_gains_and_losses);
assert_eq!( result , Err("\n\nERROR: Sold transaction detected, but corressponding Gain&Losses document is missing. Please download Gain&Losses XLSX document at:\n
https://us.etrade.com/etx/sp/stockplan#/myAccount/gainsLosses\n\n".to_string()));
}
}

0 comments on commit 03b590f

Please sign in to comment.