#[cfg(feature = "telegram")] use crate::categories::get_top_category; use crate::categories::CatStats; use crate::receipt; use crate::user::User; use chrono::{DateTime, Utc}; use qif_generator::{account::Account, split::Split, transaction::Transaction}; use std::fs; /// Read json file with receipt and convert it into `receipt::Purchase` pub fn read_file(f: &str) -> receipt::Purchase { let json = fs::read_to_string(f).expect(format!("Can't read file {}", f).as_str()); receipt::parse_purchase(&json) } #[cfg(test)] mod tests { use super::*; use std::path::PathBuf; #[test] fn test_read_receipt() { let mut p = PathBuf::from(env!("CARGO_MANIFEST_DIR")); p.push("tests/resources/test.json"); let full_path = p.to_string_lossy(); let result = read_file(&full_path).items; assert_eq!(result[0].name, "СИДР 0.5 MAGNERS APP"); assert_eq!(result[0].sum, 17713); } } /// Generate set of QIF Splits from a Purchase items pub fn gen_splits( items: &[receipt::Item], cs: &mut CatStats, accounts: &[String], filter: F, categorizer: C, ) -> Vec where C: Fn(&str, &mut CatStats, &[String]) -> String, F: Fn(&str) -> &str, { let mut result: Vec = Vec::new(); for i in items.iter() { let t = Split::new() .memo(filter(i.name.as_str())) .amount(-i.sum) .category(&categorizer(i.name.as_str(), cs, accounts)) .build(); result.push(t); } result } /// Generate QIF transaction from `splits` pub fn gen_trans<'a>( acc: &'a Account, date: DateTime, sum: i64, memo: &str, splits: &[Split], ) -> Result, String> { let t = Transaction::new(acc) .date(date) .memo(memo) .splits(splits) .build(); match t { Ok(t) => { if t.sum() == -sum { Ok(t) } else { Err(format!( "Total sum is wrong. Expected: {} Got: {}", sum, t.sum() )) } } Err(e) => Err(e), } } /// Check if all items in `filename` do have a category assigned by `user` #[cfg(feature = "telegram")] pub fn non_cat_items(filename: &str, user: &User) -> Vec { let file = read_file(filename); let mut result: Vec = Vec::new(); for i in file.items { match get_top_category(i.name.as_str(), &user.catmap) { Some(_) => (), None => result.push(String::from(i.name.as_str())), } } result } /// Convert `filename` into a QIF transaction pub fn convert<'a, F, C>( filename: &'a str, memo: &str, user: &'a mut User, acc: &'a Account, filter: F, categorizer: C, ) -> Result, String> where F: Fn(&str) -> &str, C: Fn(&str, &mut CatStats, &[String]) -> String, { let purchase = &read_file(filename); let splits = &gen_splits( &purchase.items, &mut user.catmap, &user.accounts, &filter, &categorizer, ); gen_trans(acc, purchase.date(), purchase.total_sum(), memo, splits) }