1use rusqlite::{Connection, Result as sqlResult};
2use std::collections::HashMap;
3
4use crate::utility::{
5 get_all_tx_methods, get_last_balance_id, get_last_balances, get_last_time_balance,
6 get_last_tx_id,
7};
8
9pub fn add_tx(
16 date: &str,
17 details: &str,
18 tx_method: &str,
19 amount: &str,
20 tx_type: &str,
21 tags: &str,
22 id_num: Option<&str>,
23 conn: &mut Connection,
24) -> sqlResult<()> {
25 let sp = conn.savepoint()?;
27
28 if let Some(id) = id_num {
37 let query = r#"INSERT INTO tx_all (date, details, "tx_method", amount, tx_type, id_num, tags) VALUES (?, ?, ?, ?, ?, ?, ?)"#;
38 sp.execute(query, [date, details, tx_method, amount, tx_type, id, tags])?;
39 } else {
40 let query = r#"INSERT INTO tx_all (date, details, "tx_method", amount, tx_type, tags) VALUES (?, ?, ?, ?, ?, ?)"#;
41 sp.execute(query, [date, details, tx_method, amount, tx_type, tags])?;
42 }
43
44 let split_date = date.split('-').collect::<Vec<&str>>();
49 let (year, month) = (
50 split_date[0].parse::<i32>().unwrap() - 2022,
51 split_date[1].parse::<i32>().unwrap(),
52 );
53
54 let mut from_method = String::new();
55 let mut to_method = String::new();
56
57 if tx_type == "Transfer" {
58 let split_method = tx_method.split(" to ").collect::<Vec<&str>>();
59 from_method = split_method[0].to_string();
60 to_method = split_method[1].to_string();
61 }
62
63 let target_id_num = month + (year * 12);
64
65 let mut last_id = get_last_tx_id(&sp)?;
68 if let Some(id) = id_num {
69 last_id = id.parse().unwrap();
70 }
71 let last_balance_id = get_last_balance_id(&sp)?;
72
73 let mut new_balance_data = Vec::new();
78 let mut new_changes_data = Vec::new();
79 let mut last_balance_data = HashMap::new();
80
81 let all_tx_methods = get_all_tx_methods(&sp);
82 let last_balance = get_last_balances(&sp);
83
84 let mut current_month_balance =
86 get_last_time_balance(month as usize, year as usize, &all_tx_methods, &sp);
87
88 let int_amount = amount.parse::<f64>().unwrap();
89
90 match tx_type {
92 "Transfer" => {
93 let new_balance_from = current_month_balance[&from_method] - int_amount;
94 let new_balance_to = current_month_balance[&to_method] + int_amount;
95
96 *current_month_balance.get_mut(&from_method).unwrap() = new_balance_from;
98 *current_month_balance.get_mut(&to_method).unwrap() = new_balance_to;
99 }
100 "Expense" => {
101 let new_balance = current_month_balance[tx_method] - int_amount;
102
103 *current_month_balance.get_mut(tx_method).unwrap() = new_balance;
105 }
106 "Income" => {
107 let new_balance = current_month_balance[tx_method] + int_amount;
108 *current_month_balance.get_mut(tx_method).unwrap() = new_balance;
110 }
111 _ => {}
112 }
113
114 for i in &all_tx_methods {
117 new_balance_data.push(format!("{:.2}", current_month_balance[i]));
118 }
119
120 for i in 0..all_tx_methods.len() {
122 let current_last_balance = last_balance[i].parse::<f64>().unwrap();
124 let mut current_change = format!("{:.2}", 0.0);
125
126 if tx_type == "Transfer" && all_tx_methods[i] == from_method {
128 current_change = format!("↓{:.2}", &int_amount);
129
130 let edited_balance = current_last_balance - int_amount;
131 last_balance_data.insert(&from_method, format!("{edited_balance:.2}"));
132 } else if tx_type == "Transfer" && all_tx_methods[i] == to_method {
133 current_change = format!("↑{:.2}", &int_amount);
134
135 let edited_balance = current_last_balance + int_amount;
136 last_balance_data.insert(&to_method, format!("{edited_balance:.2}"));
137 } else if tx_type != "Transfer" && all_tx_methods[i] == tx_method {
138 if tx_type == "Expense" {
139 current_change = format!("↓{:.2}", &int_amount);
140
141 let edited_balance = current_last_balance - int_amount;
142 last_balance_data.insert(&all_tx_methods[i], format!("{edited_balance:.2}"));
143 } else if tx_type == "Income" {
144 current_change = format!("↑{:.2}", &int_amount);
145
146 let edited_balance = current_last_balance + int_amount;
147 last_balance_data.insert(&all_tx_methods[i], format!("{edited_balance:.2}"));
148 }
149 }
150 new_changes_data.push(current_change);
151 }
152
153 let set_values = all_tx_methods
154 .iter()
155 .zip(new_balance_data.iter())
156 .map(|(method, value)| format!(r#""{method}" = "{value}""#,))
157 .collect::<Vec<_>>()
158 .join(", ");
159
160 let balance_query =
161 format!("UPDATE balance_all SET {set_values} WHERE id_num = {target_id_num}",);
162
163 let last_balance_query: String = if tx_type == "Transfer" {
164 format!(
165 r#"UPDATE balance_all SET "{from_method}" = "{}", "{to_method}" = "{}" WHERE id_num = {}"#,
166 last_balance_data[&from_method], last_balance_data[&to_method], last_balance_id
167 )
168 } else {
169 format!(
170 r#"UPDATE balance_all SET "{tx_method}" = "{}" WHERE id_num = {}"#,
171 last_balance_data[&tx_method.to_string()],
172 last_balance_id
173 )
174 };
175
176 let changes_query = format!(
177 "INSERT INTO changes_all (id_num, date, {}) VALUES ({}, ?, {})",
178 all_tx_methods
179 .iter()
180 .map(|s| format!(r#""{s}""#,))
181 .collect::<Vec<_>>()
182 .join(", "),
183 last_id,
184 new_changes_data
185 .iter()
186 .map(|s| format!(r#""{s}""#,))
187 .collect::<Vec<_>>()
188 .join(", ")
189 );
190
191 sp.execute(&balance_query, [])?;
192 sp.execute(&last_balance_query, [])?;
193 sp.execute(&changes_query, [date])?;
194 sp.commit()?;
195 Ok(())
196}