use crate::model::Transaction; use chrono::NaiveDate; pub fn parse(filename: &str) -> anyhow::Result> { let file = std::fs::File::open(filename)?; let mut reader = csv::ReaderBuilder::new() .has_headers(true) .from_reader(file); let mut transactions = Vec::new(); for result in reader.records() { let record = result?; if record.len() >= 5 { // Format: "date","transaction","description","amount","balance" if let (Ok(date), Some(description), Ok(amount)) = ( NaiveDate::parse_from_str(&record[0], "%Y-%m-%d"), record.get(2), record[3].parse::(), ) { let account = "Wise".to_string(); transactions.push(Transaction::new( date, description.to_string(), amount, account, )); } } } Ok(transactions) } #[cfg(test)] mod tests { use super::*; use std::io::Write; use tempfile::NamedTempFile; #[test] fn test_wise_parser() { let csv_content = "\"date\",\"transaction\",\"description\",\"amount\",\"balance\"\n\"2025-05-18\",\"TRFIN\",\"Money transfer into the account (executed at 2025-05-18), FX Rate: 1.3843\",\"112239.94\",\"112239.94\"\n\"2025-05-18\",\"TRFOUT\",\"Money transfer out of the account (executed at 2025-05-18)\",\"-100000.0\",\"12239.94\""; let mut temp_file = NamedTempFile::new().unwrap(); temp_file.write_all(csv_content.as_bytes()).unwrap(); temp_file.flush().unwrap(); let transactions = parse(temp_file.path().to_str().unwrap()).unwrap(); assert_eq!(transactions.len(), 2); let first_txn = &transactions[0]; assert_eq!(first_txn.date.format("%Y-%m-%d").to_string(), "2025-05-18"); assert_eq!( first_txn.description, "Money transfer into the account (executed at 2025-05-18), FX Rate: 1.3843" ); assert_eq!(first_txn.amount, 112239.94); assert_eq!(first_txn.account, "Wise"); assert_eq!(first_txn.category, Some("Transfer".to_string())); let second_txn = &transactions[1]; assert_eq!(second_txn.date.format("%Y-%m-%d").to_string(), "2025-05-18"); assert_eq!( second_txn.description, "Money transfer out of the account (executed at 2025-05-18)" ); assert_eq!(second_txn.amount, -100000.0); assert_eq!(second_txn.account, "Wise"); assert_eq!(second_txn.category, Some("Transfer".to_string())); } }