diff --git a/Cargo.lock b/Cargo.lock index 078b723..8009667 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -393,7 +393,7 @@ dependencies = [ [[package]] name = "etradeTaxReturnHelper" -version = "0.3.1" +version = "0.3.2" dependencies = [ "calamine", "chrono", diff --git a/Cargo.toml b/Cargo.toml index c15e810..0b109a0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "etradeTaxReturnHelper" -version = "0.3.1" +version = "0.3.2" 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" diff --git a/src/de.rs b/src/de.rs index a755c19..7fba6bc 100644 --- a/src/de.rs +++ b/src/de.rs @@ -55,7 +55,7 @@ impl etradeTaxReturnHelper::Residency for DE { tax_div: f32, gross_sold: f32, cost_sold: f32, - ) -> Vec { + ) -> (Vec, Option) { let mut presentation: Vec = vec![]; presentation.push(format!("===> (DIVIDENDS) INCOME: {:.2} EUR", gross_div)); presentation.push(format!("===> (DIVIDENDS) TAX PAID: {:.2} EUR", tax_div)); @@ -64,7 +64,7 @@ impl etradeTaxReturnHelper::Residency for DE { "===> (SOLD STOCK) TAX DEDUCTIBLE COST: {:.2} EUR", cost_sold )); - presentation + (presentation, None) } } @@ -87,7 +87,7 @@ mod tests { "===> (SOLD STOCK) TAX DEDUCTIBLE COST: 10.00 EUR".to_string(), ]; - let results = rd.present_result(gross_div, tax_div, gross_sold, cost_sold); + let (results, _) = rd.present_result(gross_div, tax_div, gross_sold, cost_sold); results .iter() diff --git a/src/gui.rs b/src/gui.rs index 34b9ead..1ff0749 100644 --- a/src/gui.rs +++ b/src/gui.rs @@ -49,10 +49,31 @@ pub mod gui { docs.iter().for_each(|x| browser.add(x)); } - fn create_clear_documents(browser: Rc>, clear_button: &mut Button) { + fn create_clear_documents( + browser: Rc>, + tdisplay: Rc>, + sdisplay: Rc>, + ndisplay: Rc>, + clear_button: &mut Button, + ) { clear_button.set_callback(move |_| { + let mut buffer = sdisplay + .borrow() + .buffer() + .expect_and_log("Error: No buffer assigned to Summary TextDisplay"); + let mut nbuffer = ndisplay + .borrow() + .buffer() + .expect_and_log("Error: No buffer assigned to Notes TextDisplay"); + let mut tbuffer = tdisplay + .borrow() + .buffer() + .expect_and_log("Error: No buffer assigned to Transactions TextDisplay"); let mut filelist = browser.borrow_mut(); filelist.clear(); + buffer.set_text(""); + tbuffer.set_text(""); + nbuffer.set_text(""); }); } @@ -107,8 +128,11 @@ pub mod gui { panic!("Error: unable to perform taxation"); } }; - let presentation = rd.present_result(gross_div, tax_div, gross_sold, cost_sold); + let (presentation,warning) = rd.present_result(gross_div, tax_div, gross_sold, cost_sold); buffer.set_text(&presentation.join("\n")); + if let Some(warn_msg) = warning { + nbuffer.set_text(&warn_msg); + } let mut transactions_strings: Vec = vec![]; div_transactions .iter() @@ -260,7 +284,13 @@ pub mod gui { uberpack.end(); create_choose_documents_dialog(browser.clone(), &mut load_button); - create_clear_documents(browser.clone(), &mut clear_button); + create_clear_documents( + browser.clone(), + tdisplay.clone(), + sdisplay.clone(), + ndisplay.clone(), + &mut clear_button, + ); create_execute_documents( browser.clone(), tdisplay.clone(), diff --git a/src/lib.rs b/src/lib.rs index 930423e..e525650 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -70,7 +70,7 @@ pub trait Residency { tax_div: f32, gross_sold: f32, cost_sold: f32, - ) -> Vec; + ) -> (Vec, Option); fn get_exchange_rates( &self, dates: &mut std::collections::HashMap>, diff --git a/src/main.rs b/src/main.rs index 9f70805..86b5e92 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,7 +11,6 @@ mod gui; use etradeTaxReturnHelper::run_taxation; use logging::ResultExt; -// TODO: GUI : Error messages section (Redirecting to GUI the errors) // TODO: GUI : choosing residency // TODO: Drag&Drop to work on MultiBrowser field @@ -78,8 +77,12 @@ fn main() { Err(msg) => panic!("\nError: Unable to compute taxes. \n\nDetails: {msg}"), }; - let presentation = rd.present_result(gross_div, tax_div, gross_sold, cost_sold); + let (presentation, warning) = rd.present_result(gross_div, tax_div, gross_sold, cost_sold); presentation.iter().for_each(|x| println!("{x}")); + + if let Some(warn_msg) = warning { + println!("\n\nWARNING: {warn_msg}"); + } } #[cfg(test)] diff --git a/src/pl.rs b/src/pl.rs index 2edc594..2a97252 100644 --- a/src/pl.rs +++ b/src/pl.rs @@ -105,15 +105,16 @@ impl etradeTaxReturnHelper::Residency for PL { tax_div: f32, gross_sold: f32, cost_sold: f32, - ) -> Vec { + ) -> (Vec, Option) { let mut presentation: Vec = vec![]; + let tax_pl = 0.19 * gross_div; presentation.push(format!( "(DYWIDENDY) PRZYCHOD Z ZAGRANICY: {:.2} PLN", gross_div )); presentation.push(format!( "===> (DYWIDENDY) ZRYCZALTOWANY PODATEK: {:.2} PLN", - (0.19 * gross_div) + tax_pl )); presentation.push(format!( "===> (DYWIDENDY) PODATEK ZAPLACONY ZAGRANICA: {:.2} PLN", @@ -127,7 +128,11 @@ impl etradeTaxReturnHelper::Residency for PL { "===> (SPRZEDAZ AKCJI) KOSZT UZYSKANIA PRZYCHODU: {:.2} PLN", cost_sold )); - presentation + if tax_div > tax_pl { + (presentation,Some(format!("Warning: Tax paid in US({tax_div} PLN) is higher than the tax that you are to pay in Poland({tax_pl} PLN). This usually means that there was a problem with declaration of your residency to avoid double taxation"))) + } else { + (presentation, None) + } } } @@ -151,7 +156,7 @@ mod tests { "===> (SPRZEDAZ AKCJI) KOSZT UZYSKANIA PRZYCHODU: 10.00 PLN".to_string(), ]; - let results = rd.present_result(gross_div, tax_div, gross_sold, cost_sold); + let (results, _) = rd.present_result(gross_div, tax_div, gross_sold, cost_sold); results .iter() @@ -160,4 +165,38 @@ mod tests { Ok(()) } + + #[test] + fn test_present_result_double_taxation_warning_pl() -> Result<(), String> { + let rd: Box = Box::new(PL {}); + + let gross_div = 100.0f32; + let tax_div = 30.0f32; + let gross_sold = 1000.0f32; + let cost_sold = 10.0f32; + + let ref_results: Vec = vec![ + "(DYWIDENDY) PRZYCHOD Z ZAGRANICY: 100.00 PLN".to_string(), + "===> (DYWIDENDY) ZRYCZALTOWANY PODATEK: 19.00 PLN".to_string(), + "===> (DYWIDENDY) PODATEK ZAPLACONY ZAGRANICA: 30.00 PLN".to_string(), + "===> (SPRZEDAZ AKCJI) PRZYCHOD Z ZAGRANICY: 1000.00 PLN".to_string(), + "===> (SPRZEDAZ AKCJI) KOSZT UZYSKANIA PRZYCHODU: 10.00 PLN".to_string(), + ]; + + let (results, warning) = rd.present_result(gross_div, tax_div, gross_sold, cost_sold); + + results + .iter() + .zip(&ref_results) + .for_each(|(a, b)| assert_eq!(a, b)); + + let ref_msg = "Warning: Tax paid in US(30 PLN) is higher than the tax that you are to pay in Poland(19 PLN). This usually means that there was a problem with declaration of your residency to avoid double taxation".to_string(); + + match (warning) { + Some(msg) => assert_eq!(msg, ref_msg), + None => return Err("Error: expected information on to high tax".to_string()), + } + + Ok(()) + } } diff --git a/src/us.rs b/src/us.rs index b5d6294..0dcb571 100644 --- a/src/us.rs +++ b/src/us.rs @@ -16,7 +16,7 @@ impl etradeTaxReturnHelper::Residency for US { tax_div: f32, gross_sold: f32, cost_sold: f32, - ) -> Vec { + ) -> (Vec, Option) { let mut presentation: Vec = vec![]; presentation.push(format!("===> (DIVIDENDS) INCOME: ${:.2}", gross_div)); presentation.push(format!("===> (DIVIDENDS) TAX PAID: ${:.2}", tax_div)); @@ -25,7 +25,7 @@ impl etradeTaxReturnHelper::Residency for US { "===> (SOLD STOCK) TAX DEDUCTIBLE COST: ${:.2}", cost_sold )); - presentation + (presentation, None) } } @@ -48,7 +48,7 @@ mod tests { "===> (SOLD STOCK) TAX DEDUCTIBLE COST: $10.00".to_string(), ]; - let results = rd.present_result(gross_div, tax_div, gross_sold, cost_sold); + let (results, _) = rd.present_result(gross_div, tax_div, gross_sold, cost_sold); results .iter()