1use std::{
2 fmt::{Display, Formatter},
3 fs,
4 path::PathBuf,
5};
6
7use anyhow::{anyhow, Result};
8use chrono::DateTime;
9use colored::Colorize;
10use rusqlite::{params, Connection};
11
12#[derive(Debug)]
13pub struct Tx {
14 date: String,
15 net_amount: f64,
16 dividend: f64,
17 tax: f64,
18 remainder: f64,
19}
20
21impl Tx {
22 pub fn new(date: String, net_amount: f64, dividend: f64, tax: f64, remainder: f64) -> Tx {
23 Tx {
24 date,
25 net_amount,
26 dividend,
27 tax,
28 remainder,
29 }
30 }
31}
32
33impl Display for Tx {
34 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
35 let date =
36 DateTime::parse_from_rfc3339(&self.date).expect("string to date conversion error");
37
38 write!(
39 f,
40 "| {0: <15} | {1:<15.2} | {2:<15.2} | {3:<15.2} | {4:<15.2}",
41 date.format("%d-%b-%y").to_string().bright_green(),
42 self.net_amount,
43 self.dividend,
44 self.tax,
45 self.remainder
46 )
47 }
48}
49
50pub fn db_connect() -> Result<Connection> {
51 let mut db_file: PathBuf = dirs::home_dir().ok_or(anyhow!("Couldn't get home directory"))?;
52 db_file.push(".vztools");
53
54 if !db_file.exists() {
55 println!("Creating db file: {}", db_file.to_str().unwrap());
56 fs::create_dir_all(&db_file)?;
57 }
58
59 db_file.push("db.db3");
60
61 let db_file_path = db_file
62 .to_str()
63 .expect("Couldn't convert db path to string");
64
65 let conn = Connection::open(db_file_path)?;
66
67 conn.execute(
68 "CREATE TABLE if not exists txs (
69 id INTEGER PRIMARY KEY AUTOINCREMENT,
70 date TEXT NOT NULL,
71 net_amount REAL NOT NULL,
72 dividend REAL NOT NULL,
73 tax REAL NOT NULL,
74 remainder REAL NOT NULL
75 )",
76 (), )?;
78
79 return Ok(conn);
80}
81
82pub fn insert_tx(conn: &Connection, tx: &Tx) -> Result<()> {
83 conn.execute(
84 "INSERT INTO txs (date, net_amount, dividend, tax, remainder) VALUES (?1, ?2, ?3, ?4, ?5)",
85 params![tx.date, tx.net_amount, tx.dividend, tx.tax, tx.remainder],
86 )?;
87
88 return Ok(());
89}
90
91pub fn find_latest_tx(conn: &Connection) -> Result<Tx> {
92 let mut stmt = conn.prepare(
93 "SELECT id, date, net_amount, dividend, tax, remainder FROM txs ORDER BY id DESC LIMIT 1",
94 )?;
95 let person_iter = stmt.query_map([], |row| {
96 Ok(Tx {
97 date: row.get(1)?,
98 net_amount: row.get(2)?,
99 dividend: row.get(3)?,
100 tax: row.get(4)?,
101 remainder: row.get(5)?,
102 })
103 })?;
104
105 for person in person_iter {
106 return Ok(person?);
107 }
108
109 return Err(anyhow!("No tx found"));
110}
111
112pub fn find_all_tx(conn: &Connection) -> Result<Vec<Tx>> {
113 let mut stmt = conn.prepare(
114 "SELECT id, date, net_amount, dividend, tax, remainder FROM txs ORDER BY id DESC LIMIT 20",
115 )?;
116 let person_iter = stmt.query_map([], |row| {
117 Ok(Tx {
118 date: row.get(1)?,
119 net_amount: row.get(2)?,
120 dividend: row.get(3)?,
121 tax: row.get(4)?,
122 remainder: row.get(5)?,
123 })
124 })?;
125
126 let mut people = Vec::new();
127 for person in person_iter {
128 people.push(person?);
129 }
130
131 return Ok(people);
132}