|
@@ -2,11 +2,7 @@ use std::collections::BTreeSet;
|
|
|
|
|
|
use crate::prelude::*;
|
|
use crate::prelude::*;
|
|
|
|
|
|
-/*use crate::data::{
|
|
|
|
- AccountName, Datestamp, Decimal, UnitName,
|
|
|
|
- ledger::{Change, Transaction},
|
|
|
|
- spec::{AccountSpec, CsvColumnSpec, CsvImportSpec, ImportFileFormat},
|
|
|
|
-};*/
|
|
|
|
|
|
+use crate::data::Decimal;
|
|
|
|
|
|
#[derive(Debug)]
|
|
#[derive(Debug)]
|
|
pub enum ImportError {
|
|
pub enum ImportError {
|
|
@@ -54,10 +50,15 @@ fn import_from_csv(
|
|
csv_spec: &data::spec::CsvImportSpec,
|
|
csv_spec: &data::spec::CsvImportSpec,
|
|
aspec: &data::spec::AccountSpec,
|
|
aspec: &data::spec::AccountSpec,
|
|
account: data::AccountName,
|
|
account: data::AccountName,
|
|
- target: data::AccountName,
|
|
|
|
|
|
+ transaction_target: data::AccountName,
|
|
reader: impl std::io::Read,
|
|
reader: impl std::io::Read,
|
|
) -> Result<Vec<data::Transaction>, ImportError> {
|
|
) -> Result<Vec<data::Transaction>, ImportError> {
|
|
- let mut csv_reader = csv::Reader::from_reader(reader);
|
|
|
|
|
|
+ let mut csv_reader = csv::ReaderBuilder::new()
|
|
|
|
+ .has_headers(false)
|
|
|
|
+ .trim(csv::Trim::All)
|
|
|
|
+ .from_reader(reader);
|
|
|
|
+
|
|
|
|
+ // let mut csv_reader = csv::Reader::from_reader(reader);
|
|
|
|
|
|
// validate CSV spec
|
|
// validate CSV spec
|
|
if !csv_spec
|
|
if !csv_spec
|
|
@@ -84,7 +85,7 @@ fn import_from_csv(
|
|
|
|
|
|
let mut txns = vec![];
|
|
let mut txns = vec![];
|
|
|
|
|
|
- for record in csv_reader.records() {
|
|
|
|
|
|
+ for record in csv_reader.records().skip(csv_spec.skip_start.unwrap_or(0)) {
|
|
let record = record?;
|
|
let record = record?;
|
|
|
|
|
|
let mut txn_datestamp: Option<data::Datestamp> = None;
|
|
let mut txn_datestamp: Option<data::Datestamp> = None;
|
|
@@ -142,6 +143,15 @@ fn import_from_csv(
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if csv_spec.reverse {
|
|
|
|
+ if let Some(bal) = txn_balance.as_mut() {
|
|
|
|
+ *bal = Decimal::ZERO - *bal;
|
|
|
|
+ }
|
|
|
|
+ if let Some(amount) = txn_change.as_mut() {
|
|
|
|
+ *amount = Decimal::ZERO - *amount;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
txns.push(data::Transaction {
|
|
txns.push(data::Transaction {
|
|
datestamp: txn_datestamp.unwrap(),
|
|
datestamp: txn_datestamp.unwrap(),
|
|
title: txn_title,
|
|
title: txn_title,
|
|
@@ -155,7 +165,7 @@ fn import_from_csv(
|
|
source: None,
|
|
source: None,
|
|
},
|
|
},
|
|
data::Change {
|
|
data::Change {
|
|
- account: target.into(),
|
|
|
|
|
|
+ account: transaction_target.into(),
|
|
amount: data::Decimal::ZERO
|
|
amount: data::Decimal::ZERO
|
|
.checked_sub(txn_change.unwrap())
|
|
.checked_sub(txn_change.unwrap())
|
|
.unwrap()
|
|
.unwrap()
|
|
@@ -255,14 +265,14 @@ fn postprocess(account: data::AccountName, transactions: &mut Vec<data::Transact
|
|
pub fn import_from(
|
|
pub fn import_from(
|
|
aspec: &data::spec::AccountSpec,
|
|
aspec: &data::spec::AccountSpec,
|
|
account: data::AccountName,
|
|
account: data::AccountName,
|
|
- target: data::AccountName,
|
|
|
|
|
|
+ transaction_target: data::AccountName,
|
|
path: &std::path::Path,
|
|
path: &std::path::Path,
|
|
) -> Result<Vec<data::Transaction>, ImportError> {
|
|
) -> Result<Vec<data::Transaction>, ImportError> {
|
|
let reader = std::fs::File::open(path)?;
|
|
let reader = std::fs::File::open(path)?;
|
|
|
|
|
|
let mut output = match &aspec.import {
|
|
let mut output = match &aspec.import {
|
|
Some(data::spec::ImportFileFormat::Csv(csv)) => {
|
|
Some(data::spec::ImportFileFormat::Csv(csv)) => {
|
|
- import_from_csv(csv, aspec, account, target, reader)
|
|
|
|
|
|
+ import_from_csv(csv, aspec, account, transaction_target, reader)
|
|
}
|
|
}
|
|
None => Err(ImportError::ConfigError(format!(
|
|
None => Err(ImportError::ConfigError(format!(
|
|
"no import configuration for {account}"
|
|
"no import configuration for {account}"
|