first draft
This commit is contained in:
28
src/classifier.rs
Normal file
28
src/classifier.rs
Normal file
@@ -0,0 +1,28 @@
|
||||
pub enum Category {
|
||||
Amazon,
|
||||
Transfer,
|
||||
}
|
||||
|
||||
pub fn cat(desc: &str) -> Category {
|
||||
if desc.starts_with("From") && desc.contains(" to ") {
|
||||
return Category::Transfer;
|
||||
}
|
||||
if desc == "Investing" {
|
||||
return Category::Transfer;
|
||||
}
|
||||
if desc == "Main Account" {
|
||||
return Category::Transfer;
|
||||
}
|
||||
if desc == "Backup" {
|
||||
return Category::Transfer;
|
||||
}
|
||||
if desc == "N26 Migration" {
|
||||
return Category::Transfer;
|
||||
}
|
||||
|
||||
if desc == "AMAZON PAYMENTS EUROPE S.C.A." {
|
||||
return Category::Amazon;
|
||||
}
|
||||
|
||||
todo!("Handle '{desc}'")
|
||||
}
|
11
src/lib.rs
Normal file
11
src/lib.rs
Normal file
@@ -0,0 +1,11 @@
|
||||
pub mod classifier;
|
||||
|
||||
use chrono::{DateTime, NaiveDate, Utc};
|
||||
use classifier::Category;
|
||||
|
||||
pub struct Transaction {
|
||||
pub date: NaiveDate,
|
||||
pub amount_in_cent: i64,
|
||||
pub desc: String,
|
||||
pub cat: Category,
|
||||
}
|
5
src/main.rs
Normal file
5
src/main.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
mod n26;
|
||||
|
||||
fn main() {
|
||||
n26::Transaction::from_file("./data/n26-2025-10-16.csv");
|
||||
}
|
73
src/n26.rs
Normal file
73
src/n26.rs
Normal file
@@ -0,0 +1,73 @@
|
||||
use chrono::{Date, DateTime, NaiveDate};
|
||||
use csv::Reader;
|
||||
use serde::Deserialize;
|
||||
use std::fs::File;
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Transaction {
|
||||
#[serde(rename = "Booking Date")]
|
||||
booking_date: String,
|
||||
#[serde(rename = "Value Date")]
|
||||
value_date: Option<String>,
|
||||
#[serde(rename = "Partner Name")]
|
||||
partner_name: Option<String>,
|
||||
#[serde(rename = "Partner Iban")]
|
||||
partner_iban: Option<String>,
|
||||
#[serde(rename = "Type")]
|
||||
type_: String,
|
||||
#[serde(rename = "Payment Reference")]
|
||||
payment_reference: String,
|
||||
#[serde(rename = "Account Name")]
|
||||
account_name: String,
|
||||
#[serde(rename = "Amount (EUR)")]
|
||||
amount_eur: f64,
|
||||
#[serde(rename = "Original Amount")]
|
||||
original_amount: Option<f64>,
|
||||
#[serde(rename = "Original Currency")]
|
||||
original_currency: Option<String>,
|
||||
#[serde(rename = "Exchange Rate")]
|
||||
exchange_rate: Option<f64>,
|
||||
}
|
||||
|
||||
impl From<Transaction> for fin::Transaction {
|
||||
fn from(value: Transaction) -> Self {
|
||||
let date = if let Some(date) = value.value_date {
|
||||
// If value_date exist, use this as it's earlier and closer to real date...
|
||||
date
|
||||
} else {
|
||||
// ... otherwise use booking date
|
||||
value.booking_date
|
||||
};
|
||||
let date = NaiveDate::parse_from_str(&date, "%Y-%m-%d").unwrap();
|
||||
let amount_in_cent = (value.amount_eur * 100.).round() as i64;
|
||||
let desc = if let Some(desc) = value.partner_name {
|
||||
desc.clone()
|
||||
} else {
|
||||
value.payment_reference
|
||||
};
|
||||
|
||||
let cat = fin::classifier::cat(&desc);
|
||||
|
||||
Self {
|
||||
date,
|
||||
amount_in_cent,
|
||||
desc,
|
||||
cat,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Transaction {
|
||||
pub fn from_file(path: &str) -> Vec<fin::Transaction> {
|
||||
let mut ret = Vec::new();
|
||||
let file = File::open(path).unwrap();
|
||||
let mut rdr = Reader::from_reader(file);
|
||||
|
||||
for result in rdr.deserialize::<Transaction>() {
|
||||
let tx: Transaction = result.unwrap();
|
||||
ret.push(tx.into());
|
||||
}
|
||||
|
||||
ret
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user