+transaction into own file, pretty printing of results I

This commit is contained in:
Erik Zscheile 2019-12-23 00:21:09 +01:00
parent 685538982d
commit 1d8eb970c6
4 changed files with 556 additions and 125 deletions

335
Cargo.lock generated
View file

@ -1,11 +1,81 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "arrayref"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee"
[[package]]
name = "arrayvec"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
[[package]]
name = "atty"
version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90"
dependencies = [
"libc",
"winapi",
]
[[package]]
name = "autocfg"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
[[package]]
name = "backtrace"
version = "0.3.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "924c76597f0d9ca25d762c25a4d369d51267536465dc5064bdf0eb073ed477ea"
dependencies = [
"backtrace-sys",
"cfg-if",
"libc",
"rustc-demangle",
]
[[package]]
name = "backtrace-sys"
version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d6575f128516de27e3ce99689419835fce9643a9b215a14d2b5b685be018491"
dependencies = [
"cc",
"libc",
]
[[package]]
name = "base64"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e"
dependencies = [
"byteorder",
]
[[package]]
name = "bitflags"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
name = "blake2b_simd"
version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b83b7baab1e671718d78204225800d6b170e648188ac7dc992e9d6bddf87d0c0"
dependencies = [
"arrayref",
"arrayvec",
"constant_time_eq",
]
[[package]]
name = "bstr"
version = "0.2.8"
@ -24,6 +94,18 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
[[package]]
name = "cc"
version = "1.0.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f52a465a666ca3d838ebbf08b241383421412fe7ebb463527bba275526d89f76"
[[package]]
name = "cfg-if"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
name = "chrono"
version = "0.4.10"
@ -35,6 +117,31 @@ dependencies = [
"time",
]
[[package]]
name = "cloudabi"
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
dependencies = [
"bitflags",
]
[[package]]
name = "constant_time_eq"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "995a44c877f9212528ccc74b21a232f66ad69001e40ede5bcee2ac9ef2657120"
[[package]]
name = "crossbeam-utils"
version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6"
dependencies = [
"cfg-if",
"lazy_static",
]
[[package]]
name = "csv"
version = "1.1.1"
@ -63,11 +170,28 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf5caf67ecbe612af35e1a9511e7959ecbc42b05f2c5145dbbf5f8fe817b1289"
dependencies = [
"proc-macro2",
"quote",
"syn",
"proc-macro2 0.4.30",
"quote 0.6.13",
"syn 0.15.44",
]
[[package]]
name = "dirs"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901"
dependencies = [
"libc",
"redox_users",
"winapi",
]
[[package]]
name = "encode_unicode"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
[[package]]
name = "encoding"
version = "0.2.33"
@ -132,6 +256,28 @@ version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a246d82be1c9d791c5dfde9a2bd045fc3cbba3fa2b11ad558f27d01712f00569"
[[package]]
name = "failure"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8273f13c977665c5db7eb2b99ae520952fe5ac831ae4cd09d80c4c7042b5ed9"
dependencies = [
"backtrace",
"failure_derive",
]
[[package]]
name = "failure_derive"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bc225b78e0391e4b8683440bf2e63c2deeeb2ce5189eab46e2b68c6d3725d08"
dependencies = [
"proc-macro2 1.0.6",
"quote 1.0.2",
"syn 1.0.11",
"synstructure",
]
[[package]]
name = "fixed"
version = "0.5.0"
@ -141,6 +287,12 @@ dependencies = [
"typenum",
]
[[package]]
name = "fuchsia-cprng"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
[[package]]
name = "itoa"
version = "0.4.4"
@ -218,13 +370,36 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
[[package]]
name = "prettytable-rs"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fd04b170004fa2daccf418a7f8253aaf033c27760b5f225889024cf66d7ac2e"
dependencies = [
"atty",
"csv",
"encode_unicode",
"lazy_static",
"term",
"unicode-width",
]
[[package]]
name = "proc-macro2"
version = "0.4.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
dependencies = [
"unicode-xid",
"unicode-xid 0.1.0",
]
[[package]]
name = "proc-macro2"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27"
dependencies = [
"unicode-xid 0.2.0",
]
[[package]]
@ -233,7 +408,45 @@ version = "0.6.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
dependencies = [
"proc-macro2",
"proc-macro2 0.4.30",
]
[[package]]
name = "quote"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
dependencies = [
"proc-macro2 1.0.6",
]
[[package]]
name = "rand_core"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
dependencies = [
"rand_core 0.4.2",
]
[[package]]
name = "rand_core"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
[[package]]
name = "rand_os"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
dependencies = [
"cloudabi",
"fuchsia-cprng",
"libc",
"rand_core 0.4.2",
"rdrand",
"winapi",
]
[[package]]
@ -244,8 +457,19 @@ dependencies = [
"csv",
"encoding",
"fixed",
"prettytable-rs",
"readfilez",
"string_cache",
"thiserror",
]
[[package]]
name = "rdrand"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
dependencies = [
"rand_core 0.3.1",
]
[[package]]
@ -264,6 +488,18 @@ version = "0.1.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
[[package]]
name = "redox_users"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ecedbca3bf205f8d8f5c2b44d83cd0690e39ee84b951ed649e9f1841132b66d"
dependencies = [
"failure",
"rand_os",
"redox_syscall",
"rust-argon2",
]
[[package]]
name = "regex-automata"
version = "0.1.8"
@ -273,6 +509,23 @@ dependencies = [
"byteorder",
]
[[package]]
name = "rust-argon2"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ca4eaef519b494d1f2848fc602d18816fed808a981aedf4f1f00ceb7c9d32cf"
dependencies = [
"base64",
"blake2b_simd",
"crossbeam-utils",
]
[[package]]
name = "rustc-demangle"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783"
[[package]]
name = "ryu"
version = "1.0.2"
@ -310,9 +563,63 @@ version = "0.15.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
"proc-macro2 0.4.30",
"quote 0.6.13",
"unicode-xid 0.1.0",
]
[[package]]
name = "syn"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dff0acdb207ae2fe6d5976617f887eb1e35a2ba52c13c7234c790960cdad9238"
dependencies = [
"proc-macro2 1.0.6",
"quote 1.0.2",
"unicode-xid 0.2.0",
]
[[package]]
name = "synstructure"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545"
dependencies = [
"proc-macro2 1.0.6",
"quote 1.0.2",
"syn 1.0.11",
"unicode-xid 0.2.0",
]
[[package]]
name = "term"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edd106a334b7657c10b7c540a0106114feadeb4dc314513e97df481d5d966f42"
dependencies = [
"byteorder",
"dirs",
"winapi",
]
[[package]]
name = "thiserror"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f357d1814b33bc2dc221243f8424104bfe72dbe911d5b71b3816a2dff1c977e"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb2e25d25307eb8436894f727aba8f65d07adf02e5b35a13cebed48bd282bfef"
dependencies = [
"proc-macro2 1.0.6",
"quote 1.0.2",
"syn 1.0.11",
]
[[package]]
@ -332,12 +639,24 @@ version = "1.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9"
[[package]]
name = "unicode-width"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479"
[[package]]
name = "unicode-xid"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
[[package]]
name = "unicode-xid"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
[[package]]
name = "winapi"
version = "0.3.8"

View file

@ -11,3 +11,5 @@ encoding = "0.2"
fixed = "0.5"
readfilez = "0.2"
string_cache = "0.8"
thiserror = "1.0"
prettytable = { version = "0.8", package = "prettytable-rs" }

View file

@ -1,78 +1,12 @@
use chrono::naive::NaiveDate;
use std::collections::HashSet;
use string_cache::DefaultAtom;
/// simple typed helper enums
mod simple_enums;
use simple_enums::*;
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
enum KontoDaten {
None,
Old { knr: u64, blz: u32 },
New { iban: String, bic: String },
}
type TransactionValue = fixed::types::U21F11;
#[derive(Clone, Debug, Eq, PartialEq)]
struct TransactionLine {
d_buchungs: NaiveDate,
d_valuta: NaiveDate,
// ignore 3. column = "Auftraggeber/Zahlungsempfänger",
// because that should be nearly equivalent for every row
p_other: DefaultAtom,
konto_data: KontoDaten,
verwendungszw: String,
kref: String,
waehrung: Waehrung,
umsatz: TransactionValue,
direction: TransactionDirection,
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
struct Transactions {
pothc: HashSet<DefaultAtom>,
elems: Vec<TransactionLine>,
}
impl std::ops::Deref for Transactions {
type Target = [TransactionLine];
#[inline]
fn deref(&self) -> &[TransactionLine] {
&self.elems[..]
}
}
impl Transactions {
#[inline]
pub fn new() -> Self {
Default::default()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.elems.is_empty()
}
#[inline]
pub fn len(&self) -> usize {
self.elems.len()
}
pub fn push(&mut self, mut tl: TransactionLine) {
if let Some(x) = self.pothc.get(&tl.p_other) {
tl.p_other = x.clone();
} else {
self.pothc.insert(tl.p_other.clone());
}
self.elems.push(tl);
}
}
mod transaction;
fn main() {
use encoding::types::Encoding;
use prettytable::{cell, format, row, Cell, Row, Table};
use std::collections::HashMap;
for i in std::env::args().skip(1) {
println!("F = {}", i);
@ -112,57 +46,72 @@ fn main() {
]
);
println!("\nData:");
let mut tmp = transaction::TransactionColl::new();
for result in recsit {
let record = result.expect("got invalid line");
assert_eq!(record.len(), 13);
if record[1].is_empty() {
// finalizer line -> ignore
break;
let record_bak = record.clone();
let pres: Result<transaction::TransactionLine, _> =
std::convert::TryInto::try_into(record);
match pres {
Ok(tl) => tmp.push(tl),
Err(transaction::ParseError::Finalizer) => break,
Err(x) => panic!("got error '{}' @ {:?}", x, record_bak),
}
// decode KontoDaten
let r_e: &[u8] = &[
record[4].is_empty() as u8,
record[5].is_empty() as u8,
record[6].is_empty() as u8,
record[7].is_empty() as u8,
];
let konto_data = match &*r_e {
&[0, 1, 0, 1] => KontoDaten::Old {
knr: record[4].parse().expect("invalid Konto-Nr."),
blz: record[6].parse().expect("invalid BLZ"),
},
&[1, 0, 1, 0] => KontoDaten::New {
iban: record[5].to_string(),
bic: record[7].to_string(),
},
&[1, 1, 1, 1] => KontoDaten::None,
_ => unimplemented!(
"unsupported KontoData encoding: {:?} :in: {:?}",
&r_e,
&record
),
};
let tl = TransactionLine {
d_buchungs: NaiveDate::parse_from_str(&record[0], "%d.%m.%Y")
.expect("invalid date format"),
d_valuta: NaiveDate::parse_from_str(&record[1], "%d.%m.%Y")
.expect("invalid date format"),
p_other: DefaultAtom::from(&record[3]),
konto_data,
verwendungszw: record[8].to_string(),
kref: record[9].to_string(),
waehrung: record[10].parse().unwrap(),
umsatz: record[11]
.replace('.', "")
.replace(',', ".")
.parse()
.expect("invalid Umsatz"),
direction: record[12].parse().unwrap(),
};
println!("{:?}", tl);
}
let dat = tmp.finish();
let mut accu =
HashMap::<string_cache::DefaultAtom, (usize, transaction::TransactionValue)>::new();
let mut i_skipped = 0usize;
for i in dat {
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.p_other.clone()).or_default();
ent.0 += 1;
ent.1 += i.umsatz;
}
println!("skipped {} entries", i_skipped);
if accu.is_empty() {
continue;
}
let mut table = Table::new();
table.set_format(
format::FormatBuilder::new()
.column_separator('│')
.borders('│')
.separator(
format::LinePosition::Top,
format::LineSeparator::new('─', '┬', '┌', '┐'),
)
.separator(
format::LinePosition::Bottom,
format::LineSeparator::new('─', '┴', '└', '┘'),
)
.padding(1, 1)
.build(),
);
table.add_row(row!["Einzahler", "Zahlungen", "Summe"]);
for (k, v) in accu {
table.add_row(Row::new(vec![
Cell::new(&*k),
Cell::new(&v.0.to_string()),
Cell::new(&v.1.to_string()),
]));
}
table.printstd();
}
}

161
src/transaction.rs Normal file
View file

@ -0,0 +1,161 @@
use crate::simple_enums::{TransactionDirection, Waehrung};
use chrono::naive::NaiveDate;
use std::collections::HashSet;
use string_cache::DefaultAtom;
use thiserror::Error;
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum KontoDaten {
None,
Old { knr: u64, blz: u32 },
New { iban: String, bic: String },
}
pub type TransactionValue = fixed::types::U21F11;
#[derive(Clone, Debug, Eq, PartialEq)]
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: DefaultAtom,
pub konto_data: KontoDaten,
pub verwendungszw: String,
pub kref: String,
pub waehrung: Waehrung,
pub umsatz: TransactionValue,
pub direction: TransactionDirection,
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct TransactionColl {
pothc: HashSet<DefaultAtom>,
elems: Vec<TransactionLine>,
}
impl std::ops::Deref for TransactionColl {
type Target = [TransactionLine];
#[inline]
fn deref(&self) -> &[TransactionLine] {
&self.elems[..]
}
}
impl TransactionColl {
#[inline]
pub fn new() -> Self {
Default::default()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.elems.is_empty()
}
#[inline]
pub fn len(&self) -> usize {
self.elems.len()
}
pub fn push(&mut self, mut tl: TransactionLine) {
if let Some(x) = self.pothc.get(&tl.p_other) {
tl.p_other = x.clone();
} else {
self.pothc.insert(tl.p_other.clone());
}
self.elems.push(tl);
}
#[inline]
pub fn finish(self) -> Vec<TransactionLine> {
self.elems
}
}
#[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(fixed::ParseFixedError),
#[error("invalid integer")]
Integer(#[from] std::num::ParseIntError),
#[error("unsupported KontoDaten encoding")]
KontoDaten([bool; 4]),
#[error("invalid currency")]
Waehrung(#[from] crate::simple_enums::parser_error::Waehrung),
}
/// This impl block can be dropped after
/// https://gitlab.com/tspiteri/fixed/issues/11
/// is fixed.
impl From<fixed::ParseFixedError> for ParseError {
#[inline]
fn from(x: fixed::ParseFixedError) -> ParseError {
ParseError::Fixed(x)
}
}
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);
}
// decode KontoDaten
let r_e: &[u8] = &[
record[4].is_empty() as u8,
record[5].is_empty() as u8,
record[6].is_empty() as u8,
record[7].is_empty() as u8,
];
let konto_data = match &*r_e {
&[0, 1, 0, 1] => KontoDaten::Old {
knr: record[4].parse()?,
blz: record[6].parse()?,
},
&[1, 0, 1, 0] => KontoDaten::New {
iban: record[5].to_string(),
bic: record[7].to_string(),
},
&[1, 1, 1, 1] => KontoDaten::None,
_ => {
return Err(ParseError::KontoDaten([
r_e[0] != 0,
r_e[1] != 0,
r_e[2] != 0,
r_e[3] != 0,
]))
}
};
// 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: DefaultAtom::from(&record[3]),
konto_data,
verwendungszw: record[8].to_string(),
kref: record[9].to_string(),
waehrung: record[10].parse()?,
umsatz: record[11].replace('.', "").replace(',', ".").parse()?,
direction: record[12].parse()?,
})
}
}