167 lines
4.8 KiB
Rust
167 lines
4.8 KiB
Rust
/// simple typed helper enums
|
|
mod simple_enums;
|
|
|
|
mod transaction;
|
|
|
|
fn main() {
|
|
let mut args: Vec<_> = std::env::args().skip(1).collect();
|
|
|
|
if args.is_empty() {
|
|
return;
|
|
}
|
|
|
|
use chrono::Datelike;
|
|
use encoding::types::Encoding;
|
|
use prettytable::{cell, format, row, Table};
|
|
use std::{
|
|
collections::{BTreeMap, HashSet},
|
|
io::Write,
|
|
};
|
|
use itertools::Itertools;
|
|
|
|
let mut highlight = HashSet::new();
|
|
|
|
if args[0] == "--highlight" {
|
|
args.remove(0);
|
|
let eo_selst = args.iter().take_while(|i| *i != ";").count();
|
|
highlight = args
|
|
.drain(..std::cmp::min(eo_selst + 1, args.len()))
|
|
.collect();
|
|
highlight.remove(";");
|
|
}
|
|
|
|
let mut dat: Vec<_> = args.into_iter().flat_map(|i| {
|
|
let fh = readfilez::read_from_file(std::fs::File::open(i)).expect("unable to open file");
|
|
|
|
let tmp = encoding::all::ISO_8859_1
|
|
.decode(&*fh, encoding::types::DecoderTrap::Replace)
|
|
.expect("got invalid latin-1 data");
|
|
|
|
std::mem::drop(fh);
|
|
|
|
let mut rdr = csv::ReaderBuilder::new()
|
|
.delimiter(b';')
|
|
.flexible(true)
|
|
.has_headers(false)
|
|
.from_reader(tmp.as_bytes());
|
|
|
|
let mut recsit = rdr.records().skip(8);
|
|
|
|
assert_eq!(
|
|
recsit.next().unwrap().unwrap(),
|
|
vec![
|
|
"Buchungstag",
|
|
"Valuta",
|
|
"Auftraggeber/Zahlungsempfänger",
|
|
"Empfänger/Zahlungspflichtiger",
|
|
"Konto-Nr.",
|
|
"IBAN",
|
|
"BLZ",
|
|
"BIC",
|
|
"Vorgang/Verwendungszweck",
|
|
"Kundenreferenz",
|
|
"Währung",
|
|
"Umsatz",
|
|
" "
|
|
]
|
|
);
|
|
|
|
let mut idat = Vec::new();
|
|
for result in recsit {
|
|
let record = result.expect("got invalid line");
|
|
let record_bak = record.clone();
|
|
let pres: Result<transaction::TransactionLine, _> =
|
|
std::convert::TryInto::try_into(record);
|
|
|
|
match pres {
|
|
Ok(tl) => idat.push(tl),
|
|
Err(transaction::ParseError::Finalizer) => break,
|
|
Err(x) => panic!("got error '{}' @ {:?}", x, record_bak),
|
|
}
|
|
}
|
|
idat
|
|
}).collect();
|
|
|
|
let mut stdout = term::stdout().unwrap();
|
|
|
|
dat.sort();
|
|
let oldlen = dat.len();
|
|
|
|
let mut accu = BTreeMap::<
|
|
(i32, bool, String),
|
|
(usize, transaction::TransactionValue, String, usize),
|
|
>::new();
|
|
|
|
let mut i_skipped = 0usize;
|
|
let mut newlen = 0usize;
|
|
for i in dat.into_iter().dedup() {
|
|
newlen += 1;
|
|
if i.direction != simple_enums::TransactionDirection::Haben
|
|
|| i.waehrung != simple_enums::Waehrung::EUR
|
|
|| i.p_other.is_empty()
|
|
|| i.p_other.find(" ZINS BIS ").is_some()
|
|
{
|
|
i_skipped += 1;
|
|
continue;
|
|
}
|
|
let mut ent = accu
|
|
.entry((
|
|
i.d_buchungs.year(),
|
|
i.d_buchungs.month() > 6,
|
|
i.p_other.clone(),
|
|
))
|
|
.or_default();
|
|
ent.0 += 1;
|
|
ent.1 += i.umsatz;
|
|
}
|
|
|
|
writeln!(&mut stdout, "skipped {} duplicates and {} misc entries", oldlen - newlen, i_skipped).unwrap();
|
|
|
|
if accu.is_empty() {
|
|
return;
|
|
}
|
|
|
|
let mut pdsp = 0;
|
|
for i in accu.values_mut() {
|
|
i.2 = i.1.to_string();
|
|
i.3 = i.2.find('.').map(|x| i.2.len() - x).unwrap_or(0);
|
|
pdsp = std::cmp::max(pdsp, i.3);
|
|
}
|
|
|
|
let mut table = Table::new();
|
|
table.set_format(
|
|
format::FormatBuilder::new()
|
|
.column_separator('│')
|
|
.borders('│')
|
|
.separator(
|
|
format::LinePosition::Top,
|
|
format::LineSeparator::new('─', '┬', '┌', '┐'),
|
|
)
|
|
.separator(
|
|
format::LinePosition::Title,
|
|
format::LineSeparator::new('─', '┼', '├', '┤'),
|
|
)
|
|
.separator(
|
|
format::LinePosition::Bottom,
|
|
format::LineSeparator::new('─', '┴', '└', '┘'),
|
|
)
|
|
.padding(1, 1)
|
|
.build(),
|
|
);
|
|
|
|
table.set_titles(row!["Jahr", "Einzahler", "Zahlungen", "Summe"]);
|
|
for (k, v) in accu.iter_mut() {
|
|
let yearuhj = format!("{} {}", k.0, if k.1 { "II" } else { "I" });
|
|
v.2 += &std::iter::repeat(' ').take(pdsp - v.3).collect::<String>();
|
|
table.add_row(if highlight.contains(&*k.2) {
|
|
row![yearuhj, FYBdb-> k.2, r-> v.0.to_string(), Fgbr-> v.2]
|
|
} else {
|
|
row![yearuhj, k.2, r-> v.0.to_string(), r-> v.2]
|
|
});
|
|
}
|
|
|
|
table
|
|
.print_term(&mut *stdout)
|
|
.expect("unable to print table");
|
|
}
|