Compare commits

..

No commits in common. "9a28bfbf64c5e8003696467ff25938c23d36815f" and "999b46a904364c71ad48e36db30bdcf14567c88c" have entirely different histories.

6 changed files with 48 additions and 86 deletions

View File

@ -1,6 +1,6 @@
[package]
name = "cryptools"
version = "0.9.2"
version = "0.9.1"
authors = ["scoobybejesus <scoobybejesus@users.noreply.github.com>"]
edition = "2018"
description = "Command-line utility for processing cryptocurrency transactions into 'lots' and 'movements'."

View File

@ -24,7 +24,6 @@
import csv
import re
import os
import sys
unedited = "DigiTrnx.csv" # To be replaced with a launch arg, presumably
@ -48,13 +47,6 @@ with open(unedited) as fin, open(stage1, 'a') as fout:
wtr.writerow(header3)
wtr.writerow(header4)
# First, double check there are no account number duplicates
for i, val in enumerate(header):
if val != "":
if header.count(val) > 1:
print("### There is a duplicate account number (" + val +"). Please fix and re-run. ###")
sys.exit()
for row in rdr:
if row[0] == "" or row[1] == "":
pass

View File

@ -242,12 +242,6 @@ pub(crate) fn create_lots_and_movements(
wrap_mvmt_and_push(whole_mvmt, &ar, &lot, &chosen_home_currency, &raw_acct_map, &acct_map);
continue
} else {
if acct.list_of_lots.borrow().len() == 0 {
println!("FATAL: There are zero lots to spend from in transaction:\n{:#?}",txn);
std::process::exit(1);
}
let list_of_lots_to_use = acct.list_of_lots.clone();
// the following returns vec to be iterated from beginning to end, which provides the index for the correct lot
@ -563,8 +557,7 @@ pub(crate) fn create_lots_and_movements(
}
TxType::ToSelf => {
if raw_acct.is_margin {
println!("FATAL: Consult developer. Found margin actionrecord in ToSelf transaction:\n{:#?}", txn);
std::process::exit(1);
{ println!("\n Found margin actionrecord in toself txn # {} \n", txn.tx_number); use std::process::exit; exit(1) };
} else {
process_multiple_incoming_lots_and_mvmts(
txn_num,
@ -736,7 +729,7 @@ fn fit_into_lots(
&chosen_home_currency,
&ar_map,
&raw_acct_map,
&acct_map,
&acct_map
);
return;
}
@ -784,14 +777,6 @@ fn fit_into_lots(
wrap_mvmt_and_push(mvmt_that_fits_in_lot, &spawning_ar, &lot, &chosen_home_currency, &raw_acct_map, &acct_map);
let remainder_amt_to_recurse = remainder_amt + sum_of_mvmts_in_lot;
// println!("Remainder amount to recurse: {}", remainder_amt_to_recurse);
if vec_of_ordered_index_values.len() == current_index_position + 1 {
println!("FATAL: Txn {} on {} spending {} {} has run out of lots to spend from.",
txn_num, lot.date_as_string, ar.amount, raw_acct.ticker);
println!("Account balance is only: {}", acct.get_sum_of_amts_in_lots());
std::process::exit(1);
}
current_index_position += 1;
let lot_index = vec_of_ordered_index_values[current_index_position];
let newly_chosen_lot = list_of_lots_to_use.borrow()[lot_index].clone();
@ -821,7 +806,7 @@ fn fit_into_lots(
&chosen_home_currency,
&ar_map,
&raw_acct_map,
&acct_map,
&acct_map
);
}

View File

@ -51,63 +51,67 @@ fn import_accounts(
) -> Result<(), Box<dyn Error>> {
let header1 = rdr.headers()?.clone(); // account_num
let mut header2: csv::StringRecord = csv::StringRecord::new(); // name
let mut header3: csv::StringRecord = csv::StringRecord::new(); // ticker
let mut header2: Option<csv::StringRecord> = None; // name
let mut header3: Option<csv::StringRecord> = None; // ticker
let header4: csv::StringRecord; // is_margin
// Account Creation loop. With rdr.has_headers() set to true above, the first record here is the second row of the CSV
// A StringRecord doesn't accept the same range indexing we need below, so we create our own
let mut headerstrings: Vec<String> = Vec::with_capacity(header1.len());
for element in header1.into_iter() {
headerstrings.push(element.to_string())
}
// Account Creation loop. We set hasheaders() to true above, so the first record here is the second row of the CSV
for result in rdr.records() {
// This initial iteration through records will break after the 4th row, after accounts have been created
let record = result?;
if header2.len() == 0 {
header2 = record.clone();
if header2 == None {
header2 = Some(record.clone());
continue // After header2 is set, continue to next record
}
else if header3.len() == 0 {
header3 = record.clone();
else if header3 == None {
header3 = Some(record.clone());
continue // After header3 is set, continue to next record
}
else {
header4 = record.clone();
// println!("Assigned last header, record: {:?}", record);
// A StringRecord doesn't accept the same range indexing needed below, so a Vec of Strings will be used
let mut headerstrings: Vec<String> = Vec::with_capacity(header1.len());
for field in header1.into_iter() {
headerstrings.push(field.to_string())
}
let acct_num_warn = "Transactions will not import correctly if account numbers in the CSV import file aren't
let warn = "FATAL: Transactions will not import correctly if account numbers in the CSV import file aren't
ordered chronologically (i.e., beginning in column 4 - the 1st account column - the value should be 1.
The next column's value should be 2, then 3, etc, until the final account).";
// Header row variables have been set. It's now time to set up the accounts.
// We've got all our header rows. It's now that we set up the accounts.
println!("Attempting to create accounts...");
let mut no_dup_acct_nums = HashMap::new();
let length = &headerstrings.len();
for (idx, field) in headerstrings[3..*length].iter().enumerate() {
for num in headerstrings[3..*length].iter().enumerate() {
let counter = no_dup_acct_nums.entry(num).or_insert(0);
*counter += 1;
}
// Parse account numbers.
let account_num = field.parse::<u16>().expect("Header row account number should parse into u16.");
// For now, their columns aren't remembered. Instead, they must have a particular index. 0th idx is the 1st account, and so on.
if account_num != ((idx + 1) as u16) {
println!("FATAL: CSV Import: {}", acct_num_warn);
std::process::exit(1);
}
for acct_num in no_dup_acct_nums.keys() {
assert_eq!(no_dup_acct_nums[acct_num], 1, "Found accounts with duplicate numbers during import.");
}
for (idx, item) in headerstrings[3..*length].iter().enumerate() {
// println!("Headerstrings value: {:?}", item);
let ind = idx+3; // Add three because the idx skips the first three 'key' columns
let name:String = header2[ind].trim().to_string();
let ticker:String = header3[ind].trim().to_string(); // no .to_uppercase() b/c margin...
let account_num = item.parse::<u16>()?;
assert_eq!((idx + 1) as u16, account_num, "Found improper Account Number usage: {}", warn);
let name:String = header2.clone().unwrap()[ind].trim().to_string();
let ticker:String = header3.clone().unwrap()[ind].trim().to_string(); // no .to_uppercase() b/c margin...
let margin_string = &header4.clone()[ind];
let is_margin:bool = match margin_string.trim().to_lowercase().as_str() {
"no" | "non" | "false" => false,
"yes" | "margin" | "true" => true,
_ => {
println!("\n FATAL: CSV Import: Couldn't parse margin value for account {} {} \n",account_num, name);
process::exit(1)
}
_ => { println!("\n Couldn't parse margin value for acct {} {} \n",account_num, name); process::exit(1) }
};
let just_account: RawAccount = RawAccount {

View File

@ -52,8 +52,7 @@ impl Transaction {
let ar2_ticker = ar2_ticker_comp[0];
if first_ar.direction() == second_ar.direction() {
println!("FATAL: TxType: Found transaction with two actionRecords with the same polarity: \n{:#?}", self);
process::exit(1);
println!("Program exiting. Found transaction with two actionRecords with the same polarity: {:?}", self); process::exit(1);
}
if ar1_ticker == ar2_ticker {
if ar1_raw_acct.is_margin != ar2_raw_acct.is_margin {
@ -68,12 +67,10 @@ impl Transaction {
}
}
else if self.action_record_idx_vec.len() > 2 {
println!("FATAL: TxType: Found transaction with too many actionRecords: \n{:#?}", self);
process::exit(1);
println!("Program exiting. Found transaction with too many actionRecords: {:?}", self); process::exit(1);
}
else {
println!("FATAL: TxType: Found transaction with no actionRecords: \n{:#?}", self);
process::exit(1);
println!("Program exiting. Found transaction with no actionRecords: {:?}", self); process::exit(1);
}
}
@ -95,23 +92,11 @@ impl Transaction {
}
} else {
if self.action_record_idx_vec.len() != 2 {
println!("FATAL: Each transaction may have up to two actionrecords, and there are {} actionrecords in transaction:\n{:#?}",
self.action_record_idx_vec.len(), self);
}
assert_eq!(self.action_record_idx_vec.len(),2,
"Each txn can only have one or two ARs. Txn has {} ARs.", self.action_record_idx_vec.len());
let first_ar = match ars.get(&self.action_record_idx_vec[0]) {
Some(x) => x,
None => {
println!("FATAL: ActionRecord not found for: \n{:#?}", self);
process::exit(1)}
};
let second_ar = match ars.get(&self.action_record_idx_vec[1]) {
Some(x) => x,
None => {
println!("FATAL: ActionRecord not found for: \n{:#?}", self);
process::exit(1)}
};
let first_ar = ars.get(&self.action_record_idx_vec[0]).unwrap();
let second_ar = ars.get(&self.action_record_idx_vec[1]).unwrap();
let first_acct = acct_map.get(&first_ar.account_key).unwrap();
let second_acct = acct_map.get(&second_ar.account_key).unwrap();
@ -159,8 +144,7 @@ impl Transaction {
quote = second_acct_raw_key;
Ok((base, quote))
} else {
println!("FATAL: {}", VariousErrors::MarginNoUnderbar);
std::process::exit(1);
println!("{}", VariousErrors::MarginNoUnderbar); use std::process::exit; exit(1)
}
}

View File

@ -94,10 +94,7 @@ pub (crate) fn run_setup(cmd_args: super::Cli, cfg: super::Cfg) -> Result<(PathB
"h" => { "-" }
"s" => { "/" }
"p" => { "." }
_ => {
println!("\nFATAL: ENV: The date-separator arg requires either an 'h', an 's', or a 'p'.\n");
process::exit(1)
}
_ => { println!("\nFATAL: The date-separator arg requires either an 'h', an 's', or a 'p'.\n"); process::exit(1) }
};
let input_file_path = match cmd_args.file_to_import {