diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index e120918..4c57e3e 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -1,17 +1,17 @@ /* DrCr: Web-based double-entry bookkeeping framework - Copyright (C) 2022–2024 Lee Yingtong Li (RunasSudo) - + Copyright (C) 2022-2025 Lee Yingtong Li (RunasSudo) + This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - + You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ @@ -33,20 +33,26 @@ struct AppState { // Filename state #[tauri::command] -async fn get_open_filename(state: State<'_, Mutex>) -> Result, tauri_plugin_sql::Error> { +async fn get_open_filename( + state: State<'_, Mutex>, +) -> Result, tauri_plugin_sql::Error> { let state = state.lock().await; Ok(state.db_filename.clone()) } #[tauri::command] -async fn set_open_filename(state: State<'_, Mutex>, app: AppHandle, filename: Option) -> Result<(), tauri_plugin_sql::Error> { +async fn set_open_filename( + state: State<'_, Mutex>, + app: AppHandle, + filename: Option, +) -> Result<(), tauri_plugin_sql::Error> { let mut state = state.lock().await; state.db_filename = filename.clone(); - + // Persist in store let store = app.store("store.json").expect("Error opening store"); store.set("db_filename", filename); - + Ok(()) } @@ -66,15 +72,15 @@ pub fn run() { } else { None } - }, - _ => panic!("Unexpected db_filename in store") + } + _ => panic!("Unexpected db_filename in store"), }; - + app.manage(Mutex::new(AppState { db_filename: db_filename, sql_transactions: Vec::new(), })); - + Ok(()) }) .plugin(tauri_plugin_dialog::init()) @@ -82,9 +88,15 @@ pub fn run() { .plugin(tauri_plugin_sql::Builder::new().build()) .plugin(tauri_plugin_store::Builder::new().build()) .invoke_handler(tauri::generate_handler![ - get_open_filename, set_open_filename, + get_open_filename, + set_open_filename, libdrcr_bridge::get_balance_sheet, - sql::sql_transaction_begin, sql::sql_transaction_execute, sql::sql_transaction_select, sql::sql_transaction_rollback, sql::sql_transaction_commit + libdrcr_bridge::get_income_statement, + sql::sql_transaction_begin, + sql::sql_transaction_execute, + sql::sql_transaction_select, + sql::sql_transaction_rollback, + sql::sql_transaction_commit ]) .run(tauri::generate_context!()) .expect("Error while running tauri application"); diff --git a/src-tauri/src/libdrcr_bridge.rs b/src-tauri/src/libdrcr_bridge.rs index 1541ae2..ead5a20 100644 --- a/src-tauri/src/libdrcr_bridge.rs +++ b/src-tauri/src/libdrcr_bridge.rs @@ -23,8 +23,8 @@ use libdrcr::reporting::dynamic_report::DynamicReport; use libdrcr::reporting::generate_report; use libdrcr::reporting::steps::register_lookup_fns; use libdrcr::reporting::types::{ - DateArgs, MultipleDateArgs, ReportingContext, ReportingProductId, ReportingProductKind, - VoidArgs, + DateArgs, DateStartDateEndArgs, MultipleDateArgs, MultipleDateStartDateEndArgs, + ReportingContext, ReportingProductId, ReportingProductKind, VoidArgs, }; use tauri::State; use tokio::sync::Mutex; @@ -94,3 +94,67 @@ pub(crate) async fn get_balance_sheet( .await .unwrap() } + +#[tauri::command] +pub(crate) async fn get_income_statement( + state: State<'_, Mutex>, + eofy_date: String, + dates: Vec<(String, String)>, +) -> Result { + let state = state.lock().await; + let db_filename = state.db_filename.clone().unwrap(); + + spawn_blocking(move || { + // Connect to database + let db_connection = + DbConnection::connect(format!("sqlite:{}", db_filename.as_str()).as_str()); + + // Initialise ReportingContext + let mut context = ReportingContext::new( + db_connection, + NaiveDate::parse_from_str(eofy_date.as_str(), "%Y-%m-%d").unwrap(), + "$".to_string(), + ); + register_lookup_fns(&mut context); + register_dynamic_builders(&mut context); + + // Get income statement + let mut date_args = Vec::new(); + for (date_start, date_end) in dates.iter() { + date_args.push(DateStartDateEndArgs { + date_start: NaiveDate::parse_from_str(date_start, "%Y-%m-%d").unwrap(), + date_end: NaiveDate::parse_from_str(date_end, "%Y-%m-%d").unwrap(), + }) + } + let targets = vec![ + ReportingProductId { + name: "CalculateIncomeTax", + kind: ReportingProductKind::Transactions, + args: Box::new(VoidArgs {}), + }, + ReportingProductId { + name: "IncomeStatement", + kind: ReportingProductKind::Generic, + args: Box::new(MultipleDateStartDateEndArgs { + dates: date_args.clone(), + }), + }, + ]; + + // Run report + let products = generate_report(targets, &context).unwrap(); + let result = products + .get_or_err(&ReportingProductId { + name: "IncomeStatement", + kind: ReportingProductKind::Generic, + args: Box::new(MultipleDateStartDateEndArgs { dates: date_args }), + }) + .unwrap(); + + let income_statement = result.downcast_ref::().unwrap().to_json(); + + Ok(income_statement) + }) + .await + .unwrap() +} diff --git a/src/reports/IncomeStatementReport.vue b/src/reports/IncomeStatementReport.vue index e363ff7..9482490 100644 --- a/src/reports/IncomeStatementReport.vue +++ b/src/reports/IncomeStatementReport.vue @@ -1,6 +1,6 @@ - - - -