use crate::gnucash::{GCTransaction, GCTransactionBuffer};
use serde::Deserialize;
use std::error::Error;
#[derive(Debug, Deserialize)]
#[serde(rename_all = "PascalCase")]
struct IcaTransaction {
datum: String,
text: String,
typ: String,
budgetgrupp: String,
belopp: String,
saldo: Option<String>,
}
pub fn parse_csv(args: Vec<String>) -> Result<(), Box<dyn Error>> {
let input_file = &args[1];
let output_file = &args[2];
let utdrag_entry_order = !&args[3].is_empty();
#[cfg(not(feature = "pipe"))]
let mut rdr = csv::ReaderBuilder::new()
.has_headers(true)
.delimiter(b';')
.trim(csv::Trim::All)
.from_path(input_file)?;
#[cfg(feature = "pipe")]
let mut rdr = csv::ReaderBuilder::new()
.has_headers(true)
.delimiter(b';')
.trim(csv::Trim::All)
.from_reader(io::stdin());
#[cfg(not(feature = "pipe"))]
let mut wtr = csv::Writer::from_path(output_file)?;
#[cfg(feature = "pipe")]
let mut wtr = csv::Writer::from_writer(io::stdout());
wtr.write_record(GCTransaction::headers())?;
let mut last_seen_date = "".to_string();
let mut transaction_buffer = GCTransactionBuffer::new();
for result in rdr.deserialize() {
let record: IcaTransaction = result?;
let account_name = match record.typ.as_str() {
"E-faktura" => "Tillgångar:Likvida Medel:Brukskonto",
"Pg-bg" => "Tillgångar:Likvida Medel:Brukskonto",
"Autogiro" => "Tillgångar:Likvida Medel:Brukskonto",
"Korttransaktion" => "Tillgångar:Likvida Medel:Brukskonto",
"Uttag" => "Tillgångar:Likvida Medel:Brukskonto",
"Utlandsbetalning" => "Tillgångar:Likvida Medel:Brukskonto",
"Försäkring" => "Tillgångar:Likvida Medel:Brukskonto",
"Fritid" => "Tillgångar:Likvida Medel:Brukskonto",
"Övrigt" => "Tillgångar:Likvida Medel:Brukskonto",
"Reserverat Belopp" => "Tillgångar:Likvida Medel:Brukskonto",
"Insättning" => "Tillgångar:Likvida Medel:Brukskonto",
_ => "Tillgångar:Likvida Medel:Brukskonto",
};
let value_num = record
.belopp
.replace(" kr", "")
.replace(',', ".")
.chars()
.filter(|c| c.is_ascii())
.filter(|c| !c.is_whitespace())
.collect::<String>()
.parse::<f32>()
.unwrap();
let amount_balance = record.saldo.map(|saldo| {
saldo
.replace(" kr", "")
.replace(',', ".")
.chars()
.filter(|c| c.is_ascii())
.filter(|c| !c.is_whitespace())
.collect::<String>()
.parse::<f32>()
.unwrap()
});
if last_seen_date == record.datum {
} else {
write_csv(&mut wtr, &mut transaction_buffer, utdrag_entry_order)?;
last_seen_date = record.datum.clone();
}
transaction_buffer.push_back(GCTransaction {
date: record.datum,
transaction_id: "".into(),
number: 1.to_string(),
description: Some(record.text.to_owned()),
notes: amount_balance.map(|value| value.to_string().replace('.', ",")),
commodity_currency: Some("CURRENCY::SEK".into()),
void_reason: None,
action: Some(record.typ),
memo: Some(record.budgetgrupp),
full_account_name: Some(account_name.to_owned()),
account_name: None,
amount_with_sym: None,
amount_num: Some(value_num),
value_with_sym: None,
value_num: Some(value_num),
reconcile: Some("n".to_owned()),
reconcile_date: None,
rate_price: Some("1".to_string()),
});
}
write_csv(&mut wtr, &mut transaction_buffer, utdrag_entry_order)?;
Ok(())
}
fn write_csv(
wtr: &mut csv::Writer<std::fs::File>,
buf: &mut GCTransactionBuffer,
utdrag_entry_order: bool,
) -> Result<(), Box<dyn Error>> {
if utdrag_entry_order {
for (counter, row) in buf.iter_mut().enumerate() {
row.set_number((counter + 1).to_string());
}
while let Some(row) = buf.pop_front() {
wtr.write_record(row.output())?;
}
} else {
for (counter, row) in buf.iter_mut().rev().enumerate() {
row.set_number((counter + 1).to_string());
}
while let Some(row) = buf.pop_front() {
wtr.write_record(row.output())?;
}
}
Ok(())
}