76 lines
2.1 KiB
Rust
76 lines
2.1 KiB
Rust
use crate::db::Database;
|
|
use crate::models::{NewTransaction, TransactionType};
|
|
use std::path::Path;
|
|
|
|
pub fn import_csv(db: &Database, path: &Path, merge: bool) -> Result<usize, Box<dyn std::error::Error>> {
|
|
if !merge {
|
|
db.reset_all_data()?;
|
|
}
|
|
|
|
let mut reader = csv::Reader::from_path(path)?;
|
|
let mut count = 0;
|
|
|
|
for result in reader.records() {
|
|
let record = result?;
|
|
if record.len() < 6 {
|
|
continue;
|
|
}
|
|
let date_str = &record[0];
|
|
let type_str = &record[1];
|
|
let category_name = &record[2];
|
|
let amount: f64 = match record[3].parse() {
|
|
Ok(v) => v,
|
|
Err(_) => continue,
|
|
};
|
|
let currency = &record[4];
|
|
let exchange_rate: f64 = match record[5].parse() {
|
|
Ok(v) => v,
|
|
Err(_) => 1.0,
|
|
};
|
|
let note = if record.len() > 6 && !record[6].is_empty() {
|
|
Some(record[6].to_string())
|
|
} else {
|
|
None
|
|
};
|
|
let payee = if record.len() > 7 && !record[7].is_empty() {
|
|
Some(record[7].to_string())
|
|
} else {
|
|
None
|
|
};
|
|
|
|
let txn_type = match type_str.to_lowercase().as_str() {
|
|
"expense" => TransactionType::Expense,
|
|
"income" => TransactionType::Income,
|
|
_ => continue,
|
|
};
|
|
|
|
let categories = db.list_categories(Some(txn_type))?;
|
|
let category_id = match categories.iter().find(|c| c.name == category_name) {
|
|
Some(c) => c.id,
|
|
None => continue,
|
|
};
|
|
|
|
let date = chrono::NaiveDate::parse_from_str(date_str, "%Y-%m-%d")?;
|
|
|
|
if merge && db.find_duplicate_transaction(amount, txn_type, category_id, date)? {
|
|
continue;
|
|
}
|
|
|
|
let new_txn = NewTransaction {
|
|
amount,
|
|
transaction_type: txn_type,
|
|
category_id,
|
|
currency: currency.to_string(),
|
|
exchange_rate,
|
|
note,
|
|
date,
|
|
recurring_id: None,
|
|
payee,
|
|
};
|
|
db.insert_transaction(&new_txn)?;
|
|
count += 1;
|
|
}
|
|
|
|
Ok(count)
|
|
}
|