psdn-tacsvs/src/transaction.rs
2022-10-14 12:15:13 +02:00

70 lines
2.2 KiB
Rust

use crate::simple_enums::{TransactionDirection, Waehrung};
use chrono::naive::NaiveDate;
use serde::{Deserialize, Serialize};
use thiserror::Error;
pub type TransactionValue = fixed::types::U53F11;
#[derive(Clone, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
pub struct TransactionLine {
pub d_buchungs: NaiveDate,
pub d_valuta: NaiveDate,
// ignore 3. column = "Auftraggeber/Zahlungsempfänger",
// because that should be nearly equivalent for every row
pub p_other: String,
// ignore KontoData, it's unreliable
pub verwendungszw: String,
// ignore 10. column = "Kundenreferenz"
// should be almost always empty
pub waehrung: Waehrung,
pub umsatz: TransactionValue,
pub direction: TransactionDirection,
}
#[derive(Clone, Debug, Error)]
pub enum ParseError {
#[error("invalid date")]
Chrono(#[from] chrono::format::ParseError),
#[error("invalid H/S")]
Direction(#[from] crate::simple_enums::parser_error::TransactionDirection),
#[error("finalizer line")]
Finalizer,
#[error("invalid fixed-point number")]
Fixed(#[from] fixed::ParseFixedError),
#[error("invalid integer")]
Integer(#[from] std::num::ParseIntError),
#[error("invalid currency")]
Waehrung(#[from] crate::simple_enums::parser_error::Waehrung),
}
impl std::convert::TryFrom<csv::StringRecord> for TransactionLine {
type Error = ParseError;
fn try_from(record: csv::StringRecord) -> Result<Self, ParseError> {
assert_eq!(record.len(), 13);
if record[1].is_empty() {
// finalizer line
return Err(ParseError::Finalizer);
}
// no "Kundenreferenz"
assert!(record[9].is_empty());
// assemble
Ok(TransactionLine {
d_buchungs: NaiveDate::parse_from_str(&record[0], "%d.%m.%Y")?,
d_valuta: NaiveDate::parse_from_str(&record[1], "%d.%m.%Y")?,
p_other: record[3].to_string(),
verwendungszw: record[8].to_string(),
waehrung: record[10].parse()?,
umsatz: record[11].replace('.', "").replace(',', ".").parse()?,
direction: record[12].parse()?,
})
}
}