Merged dg2 branch which tracked changed related to preserving historical cost basis and proceeds that are changed as a result of like-kind treatment.
This commit is contained in:
parent
46b764df3a
commit
8c62211b64
116
src/account.rs
116
src/account.rs
|
@ -52,11 +52,21 @@ impl Account {
|
|||
total_amount
|
||||
}
|
||||
|
||||
pub fn get_sum_of_basis_in_lots(&self) -> d128 {
|
||||
pub fn get_sum_of_lk_basis_in_lots(&self) -> d128 {
|
||||
let lots = self.list_of_lots.borrow();
|
||||
let mut total_amount = d128!(0);
|
||||
for lot in lots.iter() {
|
||||
let sum = lot.get_sum_of_basis_in_lot();
|
||||
let sum = lot.get_sum_of_lk_basis_in_lot();
|
||||
total_amount += sum;
|
||||
}
|
||||
total_amount
|
||||
}
|
||||
|
||||
pub fn get_sum_of_orig_basis_in_lots(&self) -> d128 {
|
||||
let lots = self.list_of_lots.borrow();
|
||||
let mut total_amount = d128!(0);
|
||||
for lot in lots.iter() {
|
||||
let sum = lot.get_sum_of_orig_basis_in_lot();
|
||||
total_amount += sum;
|
||||
}
|
||||
total_amount
|
||||
|
@ -87,7 +97,13 @@ impl Lot {
|
|||
// d128!(0) == Self::get_sum_of_amts_in_lot(&self)
|
||||
// }
|
||||
|
||||
pub fn get_sum_of_basis_in_lot(&self) -> d128 {
|
||||
pub fn get_sum_of_lk_basis_in_lot(&self) -> d128 {
|
||||
let mut amts = d128!(0);
|
||||
self.movements.borrow().iter().for_each(|movement| amts += movement.cost_basis_lk.get());
|
||||
amts
|
||||
}
|
||||
|
||||
pub fn get_sum_of_orig_basis_in_lot(&self) -> d128 {
|
||||
let mut amts = d128!(0);
|
||||
self.movements.borrow().iter().for_each(|movement| amts += movement.cost_basis.get());
|
||||
amts
|
||||
|
@ -106,6 +122,8 @@ pub struct Movement {
|
|||
pub ratio_of_amt_to_outgoing_mvmts_in_a_r: Cell<d128>, // Set in wrap_mvmt_and_push()
|
||||
pub lot_num: u32,
|
||||
pub proceeds: Cell<d128>, // Initialized with 0. Set in add_proceeds_to_movements()
|
||||
pub proceeds_lk: Cell<d128>,
|
||||
pub cost_basis_lk: Cell<d128>,
|
||||
}
|
||||
|
||||
impl Movement {
|
||||
|
@ -126,17 +144,67 @@ impl Movement {
|
|||
acct_map: &HashMap<u16, Account>,
|
||||
ar_map: &HashMap<u32, ActionRecord>
|
||||
) -> d128 {
|
||||
// println!("Lot #: {}", self.lot.lot_number);
|
||||
let ar = ar_map.get(&self.action_record_key).unwrap();
|
||||
let acct = acct_map.get(&ar.account_key).unwrap();
|
||||
let lot = &acct.list_of_lots.borrow()[self.lot_num as usize - 1]; // lots start at 1 and indexes at 0
|
||||
let borrowed_mvmt_list = lot.movements.borrow();
|
||||
let ratio = self.amount / borrowed_mvmt_list.first().unwrap().amount;
|
||||
// println!("ratio_of_amt_to_lots_first_mvmt: {}", ratio.abs());
|
||||
// // println!("Lot #: {}", self.lot.lot_number);
|
||||
// let ar = ar_map.get(&self.action_record_key).unwrap();
|
||||
// let acct = acct_map.get(&ar.account_key).unwrap();
|
||||
// let lot = &acct.list_of_lots.borrow()[self.lot_num as usize - 1]; // lots start at 1 and indexes at 0
|
||||
let lot = self.get_lot(acct_map, ar_map);
|
||||
let list_of_lot_mvmts = lot.movements.borrow();
|
||||
let ratio = self.amount / list_of_lot_mvmts.first().unwrap().amount;
|
||||
|
||||
ratio.abs()
|
||||
}
|
||||
|
||||
pub fn get_gain_or_loss(&self) -> d128 {
|
||||
pub fn get_lk_cost_basis_of_lots_first_mvmt(
|
||||
&self,
|
||||
acct_map: &HashMap<u16, Account>,
|
||||
ar_map: &HashMap<u32, ActionRecord>
|
||||
) -> d128 {
|
||||
// let ar = ar_map.get(&self.action_record_key).unwrap();
|
||||
// let acct = acct_map.get(&ar.account_key).unwrap();
|
||||
// let lot = &acct.list_of_lots.borrow()[self.lot_num as usize - 1]; // lots start at 1 and indexes at 0
|
||||
let lot = self.get_lot(acct_map, ar_map);
|
||||
let list_of_lot_mvmts = lot.movements.borrow();
|
||||
let cost_basis_lk = list_of_lot_mvmts.first().unwrap().cost_basis_lk.get();
|
||||
|
||||
cost_basis_lk
|
||||
}
|
||||
|
||||
pub fn get_cost_basis_of_lots_first_mvmt(
|
||||
&self,
|
||||
acct_map: &HashMap<u16, Account>,
|
||||
ar_map: &HashMap<u32, ActionRecord>
|
||||
) -> d128 {
|
||||
// let ar = ar_map.get(&self.action_record_key).unwrap();
|
||||
// let acct = acct_map.get(&ar.account_key).unwrap();
|
||||
// let lot = &acct.list_of_lots.borrow()[self.lot_num as usize - 1]; // lots start at 1 and indexes at 0
|
||||
// let borrowed_mvmt_list = lot.movements.borrow();
|
||||
let lot = self.get_lot(acct_map, ar_map);
|
||||
let list_of_lot_mvmts = lot.movements.borrow();
|
||||
let cost_basis = list_of_lot_mvmts.first().unwrap().cost_basis.get();
|
||||
|
||||
cost_basis
|
||||
}
|
||||
|
||||
// pub fn get_lk_proceeds_of_lots_first_mvmt(
|
||||
// &self,
|
||||
// acct_map: &HashMap<u16, Account>,
|
||||
// ar_map: &HashMap<u32, ActionRecord>
|
||||
// ) -> d128 {
|
||||
// let ar = ar_map.get(&self.action_record_key).unwrap();
|
||||
// let acct = acct_map.get(&ar.account_key).unwrap();
|
||||
// let lot = &acct.list_of_lots.borrow()[self.lot_num as usize - 1]; // lots start at 1 and indexes at 0
|
||||
// let borrowed_mvmt_list = lot.movements.borrow();
|
||||
// let proceeds_lk = borrowed_mvmt_list.first().unwrap().proceeds_lk.get();
|
||||
|
||||
// proceeds_lk
|
||||
// }
|
||||
|
||||
pub fn get_lk_gain_or_loss(&self) -> d128 { // Returns proceeds*2 for Incoming+Flow txns
|
||||
self.proceeds_lk.get() + self.cost_basis_lk.get()
|
||||
}
|
||||
|
||||
pub fn get_orig_gain_or_loss(&self) -> d128 { // Returns proceeds*2 for Incoming+Flow txns
|
||||
self.proceeds.get() + self.cost_basis.get()
|
||||
}
|
||||
|
||||
|
@ -147,19 +215,27 @@ impl Movement {
|
|||
let lot = Self::get_lot(&self, acct_map, ar_map);
|
||||
|
||||
match ar.direction() {
|
||||
|
||||
Polarity::Incoming => {
|
||||
let today = Utc::now();
|
||||
let utc_lot_date = Self::create_date_time_from_atlantic(lot.date_for_basis_purposes, NaiveTime::from_hms_milli(12, 34, 56, 789));
|
||||
let utc_lot_date = Self::create_date_time_from_atlantic(
|
||||
lot.date_for_basis_purposes,
|
||||
NaiveTime::from_hms_milli(12, 34, 56, 789)
|
||||
);
|
||||
// if today.signed_duration_since(self.lot.date_for_basis_purposes) > 365
|
||||
if (today - utc_lot_date) > Duration::days(365) { // TODO: figure out how to instantiate today's date and convert it to compare to NaiveDate
|
||||
if (today - utc_lot_date) > Duration::days(365) {
|
||||
// TODO: figure out how to instantiate today's date and convert it to compare to NaiveDate
|
||||
Term::LT
|
||||
}
|
||||
else {
|
||||
Term::ST
|
||||
}
|
||||
}
|
||||
|
||||
Polarity::Outgoing => {
|
||||
|
||||
let lot_date_for_basis_purposes = lot.date_for_basis_purposes;
|
||||
|
||||
if self.date.signed_duration_since(lot_date_for_basis_purposes) > Duration::days(365) {
|
||||
return Term::LT
|
||||
}
|
||||
|
@ -169,8 +245,10 @@ impl Movement {
|
|||
}
|
||||
|
||||
pub fn create_date_time_from_atlantic(date: NaiveDate, time: NaiveTime) -> DateTime<Utc> {
|
||||
|
||||
let naive_datetime = NaiveDateTime::new(date, time);
|
||||
let east_time = Eastern.from_local_datetime(&naive_datetime).unwrap();
|
||||
|
||||
east_time.with_timezone(&Utc)
|
||||
}
|
||||
|
||||
|
@ -184,11 +262,15 @@ impl Movement {
|
|||
)-> Result<d128, Box<dyn Error>> { // Returns 0 or positive number
|
||||
|
||||
let txn = txns_map.get(&self.transaction_key).expect("Couldn't get txn. Tx num invalid?");
|
||||
|
||||
match txn.transaction_type(ar_map, raw_accts, acct_map)? {
|
||||
|
||||
TxType::Flow => {
|
||||
|
||||
let ar = ar_map.get(&self.action_record_key).unwrap();
|
||||
|
||||
if ar.direction() == Polarity::Incoming {
|
||||
Ok(self.proceeds.get())
|
||||
Ok(-self.proceeds_lk.get())
|
||||
}
|
||||
else { Ok(d128!(0)) }
|
||||
}
|
||||
|
@ -206,11 +288,15 @@ impl Movement {
|
|||
)-> Result<d128, Box<dyn Error>> { // Returns 0 or negative number
|
||||
|
||||
let txn = txns_map.get(&self.transaction_key).expect("Couldn't get txn. Tx num invalid?");
|
||||
|
||||
match txn.transaction_type(ar_map, raw_accts, acct_map)? {
|
||||
|
||||
TxType::Flow => {
|
||||
|
||||
let ar = ar_map.get(&self.action_record_key).unwrap();
|
||||
|
||||
if ar.direction() == Polarity::Outgoing {
|
||||
let expense = -self.proceeds.get();
|
||||
let expense = -self.proceeds_lk.get();
|
||||
Ok(expense)
|
||||
}
|
||||
else { Ok(d128!(0)) }
|
||||
|
|
|
@ -136,6 +136,8 @@ pub fn create_lots_and_movements(
|
|||
ratio_of_amt_to_outgoing_mvmts_in_a_r: Cell::new(d128!(1.0)),
|
||||
lot_num: base_lot.lot_number,
|
||||
proceeds: Cell::new(d128!(0.0)),
|
||||
proceeds_lk: Cell::new(d128!(0.0)),
|
||||
cost_basis_lk: Cell::new(d128!(0.0)),
|
||||
};
|
||||
wrap_mvmt_and_push(base_mvmt, &base_ar, &base_lot, &settings, &raw_acct_map, &acct_map);
|
||||
|
||||
|
@ -150,6 +152,8 @@ pub fn create_lots_and_movements(
|
|||
ratio_of_amt_to_outgoing_mvmts_in_a_r: Cell::new(d128!(1.0)),
|
||||
lot_num: quote_lot.lot_number,
|
||||
proceeds: Cell::new(d128!(0.0)),
|
||||
proceeds_lk: Cell::new(d128!(0.0)),
|
||||
cost_basis_lk: Cell::new(d128!(0.0)),
|
||||
};
|
||||
wrap_mvmt_and_push(quote_mvmt, "e_ar, "e_lot, &settings, &raw_acct_map, &acct_map);
|
||||
|
||||
|
@ -191,6 +195,8 @@ pub fn create_lots_and_movements(
|
|||
ratio_of_amt_to_outgoing_mvmts_in_a_r: Cell::new(d128!(1.0)),
|
||||
lot_num: lot.lot_number,
|
||||
proceeds: Cell::new(d128!(0.0)),
|
||||
proceeds_lk: Cell::new(d128!(0.0)),
|
||||
cost_basis_lk: Cell::new(d128!(0.0)),
|
||||
};
|
||||
wrap_mvmt_and_push(whole_mvmt, &ar, &lot, &settings, &raw_acct_map, &acct_map);
|
||||
acct.list_of_lots.borrow_mut().push(lot);
|
||||
|
@ -210,6 +216,8 @@ pub fn create_lots_and_movements(
|
|||
ratio_of_amt_to_outgoing_mvmts_in_a_r: Cell::new(d128!(1.0)),
|
||||
lot_num: lot.lot_number,
|
||||
proceeds: Cell::new(d128!(0.0)),
|
||||
proceeds_lk: Cell::new(d128!(0.0)),
|
||||
cost_basis_lk: Cell::new(d128!(0.0)),
|
||||
};
|
||||
wrap_mvmt_and_push(whole_mvmt, &ar, &lot, &settings, &raw_acct_map, &acct_map);
|
||||
continue
|
||||
|
@ -239,6 +247,8 @@ pub fn create_lots_and_movements(
|
|||
ratio_of_amt_to_outgoing_mvmts_in_a_r: Cell::new(d128!(1.0)),
|
||||
lot_num: lot.lot_number,
|
||||
proceeds: Cell::new(d128!(0.0)),
|
||||
proceeds_lk: Cell::new(d128!(0.0)),
|
||||
cost_basis_lk: Cell::new(d128!(0.0)),
|
||||
};
|
||||
wrap_mvmt_and_push(whole_mvmt, &ar, &lot, &settings, &raw_acct_map, &acct_map);
|
||||
continue
|
||||
|
@ -326,6 +336,8 @@ pub fn create_lots_and_movements(
|
|||
ratio_of_amt_to_outgoing_mvmts_in_a_r: Cell::new(d128!(1.0)),
|
||||
lot_num: lot_to_use.lot_number,
|
||||
proceeds: Cell::new(d128!(0.0)),
|
||||
proceeds_lk: Cell::new(d128!(0.0)),
|
||||
cost_basis_lk: Cell::new(d128!(0.0)),
|
||||
};
|
||||
|
||||
fit_into_lots(
|
||||
|
@ -365,6 +377,8 @@ pub fn create_lots_and_movements(
|
|||
ratio_of_amt_to_outgoing_mvmts_in_a_r: Cell::new(d128!(1.0)),
|
||||
lot_num: lot.lot_number,
|
||||
proceeds: Cell::new(d128!(0.0)),
|
||||
proceeds_lk: Cell::new(d128!(0.0)),
|
||||
cost_basis_lk: Cell::new(d128!(0.0)),
|
||||
};
|
||||
wrap_mvmt_and_push(mvmt, &ar, &lot, &settings, &raw_acct_map, &acct_map);
|
||||
continue
|
||||
|
@ -395,6 +409,8 @@ pub fn create_lots_and_movements(
|
|||
ratio_of_amt_to_outgoing_mvmts_in_a_r: Cell::new(d128!(1.0)),
|
||||
lot_num: lot.lot_number,
|
||||
proceeds: Cell::new(d128!(0.0)),
|
||||
proceeds_lk: Cell::new(d128!(0.0)),
|
||||
cost_basis_lk: Cell::new(d128!(0.0)),
|
||||
};
|
||||
} else {
|
||||
assert_eq!(txn.action_record_idx_vec.len(), 2);
|
||||
|
@ -451,6 +467,8 @@ pub fn create_lots_and_movements(
|
|||
ratio_of_amt_to_outgoing_mvmts_in_a_r: Cell::new(d128!(1.0)),
|
||||
lot_num: inner_lot.lot_number,
|
||||
proceeds: Cell::new(d128!(0.0)),
|
||||
proceeds_lk: Cell::new(d128!(0.0)),
|
||||
cost_basis_lk: Cell::new(d128!(0.0)),
|
||||
};
|
||||
wrap_mvmt_and_push(inner_mvmt, &ar, &inner_lot, &settings, &raw_acct_map, &acct_map);
|
||||
acct.list_of_lots.borrow_mut().push(inner_lot);
|
||||
|
@ -483,6 +501,8 @@ pub fn create_lots_and_movements(
|
|||
ratio_of_amt_to_outgoing_mvmts_in_a_r: Cell::new(d128!(1.0)),
|
||||
lot_num: lot.lot_number,
|
||||
proceeds: Cell::new(d128!(0.0)),
|
||||
proceeds_lk: Cell::new(d128!(0.0)),
|
||||
cost_basis_lk: Cell::new(d128!(0.0)),
|
||||
};
|
||||
}
|
||||
wrap_mvmt_and_push(mvmt, &ar, &lot, &settings, &raw_acct_map, &acct_map);
|
||||
|
@ -539,6 +559,8 @@ pub fn create_lots_and_movements(
|
|||
ratio_of_amt_to_outgoing_mvmts_in_a_r: Cell::new(d128!(1.0)),
|
||||
lot_num: lot.lot_number,
|
||||
proceeds: Cell::new(d128!(0.0)),
|
||||
proceeds_lk: Cell::new(d128!(0.0)),
|
||||
cost_basis_lk: Cell::new(d128!(0.0)),
|
||||
};
|
||||
wrap_mvmt_and_push(whole_mvmt, &ar, &lot, &settings, &raw_acct_map, &acct_map);
|
||||
acct.list_of_lots.borrow_mut().push(lot);
|
||||
|
@ -693,6 +715,8 @@ fn fit_into_lots(
|
|||
ratio_of_amt_to_outgoing_mvmts_in_a_r: Cell::new(d128!(1.0)),
|
||||
lot_num: newly_chosen_lot.lot_number,
|
||||
proceeds: Cell::new(d128!(0.0)),
|
||||
proceeds_lk: Cell::new(d128!(0.0)),
|
||||
cost_basis_lk: Cell::new(d128!(0.0)),
|
||||
};
|
||||
fit_into_lots(
|
||||
txn_num,
|
||||
|
@ -710,8 +734,6 @@ fn fit_into_lots(
|
|||
}
|
||||
assert!(sum_of_mvmts_in_lot > d128!(0.0));
|
||||
let remainder_amt = mvmt_to_fit.amount;
|
||||
// println!("Sum of mvmts in lot: {}; Remainder amount: {}; Net: {}",
|
||||
// sum_of_mvmts_in_lot, remainder_amt, sum_of_mvmts_in_lot + remainder_amt);
|
||||
|
||||
let does_remainder_fit: bool = (sum_of_mvmts_in_lot + remainder_amt) >= d128!(0.0);
|
||||
|
||||
|
@ -727,6 +749,8 @@ fn fit_into_lots(
|
|||
ratio_of_amt_to_outgoing_mvmts_in_a_r: Cell::new(d128!(1.0)),
|
||||
lot_num: lot.lot_number,
|
||||
proceeds: Cell::new(d128!(0.0)),
|
||||
proceeds_lk: Cell::new(d128!(0.0)),
|
||||
cost_basis_lk: Cell::new(d128!(0.0)),
|
||||
};
|
||||
wrap_mvmt_and_push(remainder_that_fits, &spawning_ar, &lot, &settings, &raw_acct_map, &acct_map);
|
||||
return // And we're done
|
||||
|
@ -746,6 +770,8 @@ fn fit_into_lots(
|
|||
ratio_of_amt_to_outgoing_mvmts_in_a_r: Cell::new(d128!(1.0)),
|
||||
lot_num: lot.lot_number,
|
||||
proceeds: Cell::new(d128!(0.0)),
|
||||
proceeds_lk: Cell::new(d128!(0.0)),
|
||||
cost_basis_lk: Cell::new(d128!(0.0)),
|
||||
};
|
||||
wrap_mvmt_and_push(mvmt_that_fits_in_lot, &spawning_ar, &lot, &settings, &raw_acct_map, &acct_map);
|
||||
let remainder_amt_to_recurse = remainder_amt + sum_of_mvmts_in_lot;
|
||||
|
@ -765,6 +791,8 @@ fn fit_into_lots(
|
|||
ratio_of_amt_to_outgoing_mvmts_in_a_r: Cell::new(d128!(1.0)), // This acts as a dummy value.
|
||||
lot_num: newly_chosen_lot.lot_number,
|
||||
proceeds: Cell::new(d128!(0.0)),
|
||||
proceeds_lk: Cell::new(d128!(0.0)),
|
||||
cost_basis_lk: Cell::new(d128!(0.0)),
|
||||
};
|
||||
assert!(current_index_position < vec_of_ordered_index_values.len());
|
||||
fit_into_lots(
|
||||
|
@ -841,6 +869,8 @@ fn process_multiple_incoming_lots_and_mvmts(
|
|||
ratio_of_amt_to_outgoing_mvmts_in_a_r: Cell::new(d128!(1.0)),
|
||||
lot_num: lot.lot_number,
|
||||
proceeds: Cell::new(d128!(0.0)),
|
||||
proceeds_lk: Cell::new(d128!(0.0)),
|
||||
cost_basis_lk: Cell::new(d128!(0.0)),
|
||||
};
|
||||
// println!("From first set of incoming movements, amount: {} {} to account: {}",
|
||||
// incoming_mvmt.amount, acct_incoming_ar.ticker, acct_incoming_ar.account_num);
|
||||
|
@ -878,6 +908,8 @@ fn process_multiple_incoming_lots_and_mvmts(
|
|||
ratio_of_amt_to_outgoing_mvmts_in_a_r: Cell::new(d128!(1.0)),
|
||||
lot_num: lot.lot_number,
|
||||
proceeds: Cell::new(d128!(0.0)),
|
||||
proceeds_lk: Cell::new(d128!(0.0)),
|
||||
cost_basis_lk: Cell::new(d128!(0.0)),
|
||||
};
|
||||
// println!("Final incoming mvmt for this actionrecord, amount: {} {} to account: {}",
|
||||
// incoming_mvmt.amount, acct_incoming_ar.ticker, acct_incoming_ar.account_num);
|
||||
|
|
|
@ -46,23 +46,23 @@ pub fn _1_account_sums_to_csv(
|
|||
} else { balance = tentative_balance.to_string() }
|
||||
|
||||
let raw_acct = raw_acct_map.get(&acct.raw_key).unwrap();
|
||||
let cost_basis: String;
|
||||
let lk_cost_basis: String;
|
||||
|
||||
if raw_acct.is_margin { cost_basis = "0.00".to_string() } else {
|
||||
let tentative_cost_basis = acct.get_sum_of_basis_in_lots();
|
||||
if tentative_cost_basis == d128!(0) {
|
||||
cost_basis = "0.00".to_string()
|
||||
} else { cost_basis = tentative_cost_basis.to_string() }
|
||||
if raw_acct.is_margin { lk_cost_basis = "0.00".to_string() } else {
|
||||
let tentative_lk_cost_basis = acct.get_sum_of_lk_basis_in_lots();
|
||||
if tentative_lk_cost_basis == d128!(0) {
|
||||
lk_cost_basis = "0.00".to_string()
|
||||
} else { lk_cost_basis = tentative_lk_cost_basis.to_string() }
|
||||
}
|
||||
|
||||
row.push(raw_acct.name.to_string());
|
||||
row.push(balance);
|
||||
row.push(raw_acct.ticker.to_string());
|
||||
row.push(cost_basis);
|
||||
row.push(lk_cost_basis);
|
||||
row.push(acct.list_of_lots.borrow().len().to_string());
|
||||
rows.push(row);
|
||||
}
|
||||
let file_name = PathBuf::from("1_Acct_Sum_with_cost_basis.csv");
|
||||
let file_name = PathBuf::from("C1_Acct_Sum_with_cost_basis.csv");
|
||||
let path = PathBuf::from(&settings.export_path.clone());
|
||||
|
||||
let full_path: PathBuf = [path, file_name].iter().collect();
|
||||
|
@ -111,26 +111,102 @@ pub fn _2_account_sums_nonzero_to_csv(
|
|||
balance = "0.00".to_string()
|
||||
} else { balance_d128 += tentative_balance; balance = tentative_balance.to_string() }
|
||||
|
||||
let cost_basis: String;
|
||||
let lk_cost_basis: String;
|
||||
|
||||
if raw_acct.is_margin { cost_basis = "0.00".to_string() } else {
|
||||
let tentative_cost_basis = acct.get_sum_of_basis_in_lots();
|
||||
if tentative_cost_basis == d128!(0) {
|
||||
cost_basis = "0.00".to_string()
|
||||
} else { cost_basis = tentative_cost_basis.to_string() }
|
||||
if raw_acct.is_margin { lk_cost_basis = "0.00".to_string() } else {
|
||||
let tentative_lk_cost_basis = acct.get_sum_of_lk_basis_in_lots();
|
||||
if tentative_lk_cost_basis == d128!(0) {
|
||||
lk_cost_basis = "0.00".to_string()
|
||||
} else { lk_cost_basis = tentative_lk_cost_basis.to_string() }
|
||||
}
|
||||
|
||||
if balance_d128 != d128!(0) {
|
||||
row.push(name);
|
||||
row.push(balance);
|
||||
row.push(raw_acct.ticker.to_string());
|
||||
row.push(cost_basis);
|
||||
row.push(lk_cost_basis);
|
||||
row.push(acct.list_of_lots.borrow().len().to_string());
|
||||
rows.push(row);
|
||||
}
|
||||
}
|
||||
|
||||
let file_name = PathBuf::from("2_Acct_Sum_with_nonzero_cost_basis.csv");
|
||||
let file_name = PathBuf::from("C2_Acct_Sum_with_nonzero_cost_basis.csv");
|
||||
let path = PathBuf::from(&settings.export_path.clone());
|
||||
|
||||
let full_path: PathBuf = [path, file_name].iter().collect();
|
||||
let buffer = File::create(full_path).unwrap();
|
||||
let mut wtr = csv::Writer::from_writer(buffer);
|
||||
|
||||
for row in rows.iter() {
|
||||
wtr.write_record(row).expect("Could not write row to CSV file");
|
||||
}
|
||||
wtr.flush().expect("Could not flush Writer, though file should exist and be complete");
|
||||
}
|
||||
|
||||
pub fn _3_account_sums_to_csv_with_orig_basis(
|
||||
settings: &ImportProcessParameters,
|
||||
raw_acct_map: &HashMap<u16, RawAccount>,
|
||||
acct_map: &HashMap<u16, Account>
|
||||
) {
|
||||
|
||||
let mut rows: Vec<Vec<String>> = [].to_vec();
|
||||
let mut header: Vec<String> = [].to_vec();
|
||||
|
||||
header.extend_from_slice(&[
|
||||
"Account".to_string(),
|
||||
"Balance".to_string(),
|
||||
"Ticker".to_string(),
|
||||
"Orig. Cost Basis".to_string(),
|
||||
"LK Cost Basis".to_string(),
|
||||
"Total lots".to_string(),
|
||||
]);
|
||||
rows.push(header);
|
||||
|
||||
let length = acct_map.len();
|
||||
|
||||
for j in 1..=length {
|
||||
|
||||
let acct = acct_map.get(&(j as u16)).unwrap();
|
||||
let mut row: Vec<String> = [].to_vec();
|
||||
|
||||
let balance: String;
|
||||
let tentative_balance = acct.get_sum_of_amts_in_lots();
|
||||
|
||||
if tentative_balance == d128!(0) {
|
||||
balance = "0.00".to_string()
|
||||
} else { balance = tentative_balance.to_string() }
|
||||
|
||||
let raw_acct = raw_acct_map.get(&acct.raw_key).unwrap();
|
||||
let lk_cost_basis: String;
|
||||
let orig_cost_basis: String;
|
||||
|
||||
if raw_acct.is_margin {
|
||||
|
||||
lk_cost_basis = "0.00".to_string();
|
||||
orig_cost_basis = "0.00".to_string();
|
||||
} else {
|
||||
|
||||
let tentative_lk_cost_basis = acct.get_sum_of_lk_basis_in_lots();
|
||||
let tentative_orig_cost_basis = acct.get_sum_of_orig_basis_in_lots();
|
||||
|
||||
if tentative_lk_cost_basis == d128!(0) {
|
||||
lk_cost_basis = "0.00".to_string()
|
||||
} else { lk_cost_basis = tentative_lk_cost_basis.to_string() }
|
||||
|
||||
if tentative_orig_cost_basis == d128!(0) {
|
||||
orig_cost_basis = "0.00".to_string()
|
||||
} else { orig_cost_basis = tentative_orig_cost_basis.to_string() }
|
||||
}
|
||||
|
||||
row.push(raw_acct.name.to_string());
|
||||
row.push(balance);
|
||||
row.push(raw_acct.ticker.to_string());
|
||||
row.push(orig_cost_basis);
|
||||
row.push(lk_cost_basis);
|
||||
row.push(acct.list_of_lots.borrow().len().to_string());
|
||||
rows.push(row);
|
||||
}
|
||||
let file_name = PathBuf::from("C3_Acct_Sum_with_orig_and_lk_cost_basis.csv");
|
||||
let path = PathBuf::from(&settings.export_path.clone());
|
||||
|
||||
let full_path: PathBuf = [path, file_name].iter().collect();
|
||||
|
@ -197,15 +273,15 @@ pub fn _4_transaction_mvmt_detail_to_csv(
|
|||
amount += mvmt.amount; // To prevent printing -5E+1 instead of 50, for example
|
||||
let ticker = raw_acct.ticker.to_string();
|
||||
let term = mvmt.get_term(acct_map, ars).to_string();
|
||||
let mut proceeds = mvmt.proceeds.get();
|
||||
let mut cost_basis = mvmt.cost_basis.get();
|
||||
let mut gain_loss = mvmt.get_gain_or_loss();
|
||||
let mut proceeds_lk = mvmt.proceeds_lk.get();
|
||||
let mut cost_basis_lk = mvmt.cost_basis_lk.get();
|
||||
let mut gain_loss = mvmt.get_lk_gain_or_loss();
|
||||
let income = mvmt.get_income(ars, &raw_acct_map, &acct_map, &txns_map)?;
|
||||
let expense = mvmt.get_expense(ars, &raw_acct_map, &acct_map, &txns_map)?;
|
||||
|
||||
if tx_type == TxType::Flow && amount > d128!(0) {
|
||||
proceeds = d128!(0);
|
||||
cost_basis = d128!(0);
|
||||
proceeds_lk = d128!(0);
|
||||
cost_basis_lk = d128!(0);
|
||||
gain_loss = d128!(0);
|
||||
}
|
||||
|
||||
|
@ -218,8 +294,8 @@ pub fn _4_transaction_mvmt_detail_to_csv(
|
|||
row.push(amount.to_string());
|
||||
row.push(ticker);
|
||||
row.push(term);
|
||||
row.push(proceeds.to_string());
|
||||
row.push(cost_basis.to_string());
|
||||
row.push(proceeds_lk.to_string());
|
||||
row.push(cost_basis_lk.to_string());
|
||||
row.push(gain_loss.to_string());
|
||||
row.push(income.to_string());
|
||||
row.push(expense.to_string());
|
||||
|
@ -227,7 +303,7 @@ pub fn _4_transaction_mvmt_detail_to_csv(
|
|||
}
|
||||
}
|
||||
|
||||
let file_name = PathBuf::from("4_Txns_mvmts_detail.csv");
|
||||
let file_name = PathBuf::from("C4_Txns_mvmts_detail.csv");
|
||||
let path = PathBuf::from(&settings.export_path);
|
||||
|
||||
let full_path: PathBuf = [path, file_name].iter().collect();
|
||||
|
@ -324,8 +400,8 @@ pub fn _5_transaction_mvmt_summaries_to_csv(
|
|||
|
||||
if term == Term::LT {
|
||||
amount_lt += mvmt.amount;
|
||||
proceeds_lt += mvmt.proceeds.get();
|
||||
cost_basis_lt += mvmt.cost_basis.get();
|
||||
proceeds_lt += mvmt.proceeds_lk.get();
|
||||
cost_basis_lt += mvmt.cost_basis_lk.get();
|
||||
match term_lt {
|
||||
None => { term_lt = Some(term)}
|
||||
_ => {}
|
||||
|
@ -333,8 +409,8 @@ pub fn _5_transaction_mvmt_summaries_to_csv(
|
|||
} else {
|
||||
assert_eq!(term, Term::ST);
|
||||
amount_st += mvmt.amount;
|
||||
proceeds_st += mvmt.proceeds.get();
|
||||
cost_basis_st += mvmt.cost_basis.get();
|
||||
proceeds_st += mvmt.proceeds_lk.get();
|
||||
cost_basis_st += mvmt.cost_basis_lk.get();
|
||||
if term_st == None {
|
||||
term_st = Some(term);
|
||||
}
|
||||
|
@ -346,10 +422,10 @@ pub fn _5_transaction_mvmt_summaries_to_csv(
|
|||
&raw_acct_map,
|
||||
&acct_map)? == TxType::Flow
|
||||
) & (polarity == Some(Polarity::Incoming)) {
|
||||
income_st = proceeds_st;
|
||||
income_st = -proceeds_st; // Proceeds are negative for incoming txns
|
||||
proceeds_st = d128!(0);
|
||||
cost_basis_st = d128!(0);
|
||||
income_lt = proceeds_lt;
|
||||
income_lt = -proceeds_lt; // Proceeds are negative for incoming txns
|
||||
proceeds_lt = d128!(0);
|
||||
cost_basis_lt = d128!(0);
|
||||
}
|
||||
|
@ -403,7 +479,118 @@ pub fn _5_transaction_mvmt_summaries_to_csv(
|
|||
}
|
||||
}
|
||||
|
||||
let file_name = PathBuf::from("5_Txns_mvmts_summary.csv");
|
||||
let file_name = PathBuf::from("C5_Txns_mvmts_summary.csv");
|
||||
let path = PathBuf::from(&settings.export_path);
|
||||
|
||||
let full_path: PathBuf = [path, file_name].iter().collect();
|
||||
let buffer = File::create(full_path).unwrap();
|
||||
let mut wtr = csv::Writer::from_writer(buffer);
|
||||
|
||||
for row in rows.iter() {
|
||||
wtr.write_record(row).expect("Could not write row to CSV file");
|
||||
}
|
||||
wtr.flush().expect("Could not flush Writer, though file should exist and be complete");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn _6_transaction_mvmt_detail_to_csv_w_orig(
|
||||
settings: &ImportProcessParameters,
|
||||
ars: &HashMap<u32, ActionRecord>,
|
||||
raw_acct_map: &HashMap<u16, RawAccount>,
|
||||
acct_map: &HashMap<u16, Account>,
|
||||
txns_map: &HashMap<u32, Transaction>,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
|
||||
let mut rows: Vec<Vec<String>> = [].to_vec();
|
||||
let mut header: Vec<String> = [].to_vec();
|
||||
header.extend_from_slice(&[
|
||||
"Date".to_string(),
|
||||
"Txn#".to_string(),
|
||||
"Type".to_string(),
|
||||
"Memo".to_string(),
|
||||
"Amount".to_string(),
|
||||
"Ticker".to_string(),
|
||||
"Term".to_string(),
|
||||
"Proceeds".to_string(),
|
||||
"Cost basis".to_string(),
|
||||
"Gain/loss".to_string(),
|
||||
"Income".to_string(),
|
||||
"Expense".to_string(),
|
||||
"Orig. Proceeds".to_string(),
|
||||
"Orig. Cost basis".to_string(),
|
||||
"Orig. Gain/loss".to_string(),
|
||||
]);
|
||||
rows.push(header);
|
||||
|
||||
let length = txns_map.len();
|
||||
|
||||
for txn_num in 1..=length {
|
||||
|
||||
let txn_num = txn_num as u32;
|
||||
let txn = txns_map.get(&(txn_num)).unwrap();
|
||||
|
||||
let flow_or_outgoing_exchange_movements = txn.get_outgoing_exchange_and_flow_mvmts(
|
||||
&settings.home_currency,
|
||||
ars,
|
||||
raw_acct_map,
|
||||
acct_map,
|
||||
txns_map
|
||||
)?;
|
||||
|
||||
for mvmt in flow_or_outgoing_exchange_movements.iter() {
|
||||
let lot = mvmt.get_lot(acct_map, ars);
|
||||
let acct = acct_map.get(&lot.account_key).unwrap();
|
||||
let raw_acct = raw_acct_map.get(&acct.raw_key).unwrap();
|
||||
|
||||
let date = txn.date.format("%Y/%m/%d").to_string();
|
||||
let tx_number = txn.tx_number.to_string();
|
||||
let tx_type = txn.transaction_type(&ars, &raw_acct_map, &acct_map)?;
|
||||
let memo = txn.memo.to_string();
|
||||
let mut amount = d128!(0);
|
||||
amount += mvmt.amount; // To prevent printing -5E+1 instead of 50, for example
|
||||
let ticker = raw_acct.ticker.to_string();
|
||||
let term = mvmt.get_term(acct_map, ars).to_string();
|
||||
let mut proceeds_lk = mvmt.proceeds_lk.get();
|
||||
let mut cost_basis_lk = mvmt.cost_basis_lk.get();
|
||||
let mut gain_loss = mvmt.get_lk_gain_or_loss();
|
||||
let income = mvmt.get_income(ars, &raw_acct_map, &acct_map, &txns_map)?;
|
||||
let expense = mvmt.get_expense(ars, &raw_acct_map, &acct_map, &txns_map)?;
|
||||
let mut orig_proc = mvmt.proceeds.get();
|
||||
let mut orig_cost = mvmt.cost_basis.get();
|
||||
let mut orig_gain_loss = mvmt.get_orig_gain_or_loss();
|
||||
|
||||
if tx_type == TxType::Flow && amount > d128!(0) {
|
||||
proceeds_lk = d128!(0);
|
||||
cost_basis_lk = d128!(0);
|
||||
gain_loss = d128!(0);
|
||||
orig_proc = d128!(0);
|
||||
orig_cost = d128!(0);
|
||||
orig_gain_loss = d128!(0);
|
||||
}
|
||||
|
||||
let mut row: Vec<String> = [].to_vec();
|
||||
|
||||
row.push(date);
|
||||
row.push(tx_number);
|
||||
row.push(tx_type.to_string());
|
||||
row.push(memo);
|
||||
row.push(amount.to_string());
|
||||
row.push(ticker);
|
||||
row.push(term);
|
||||
row.push(proceeds_lk.to_string());
|
||||
row.push(cost_basis_lk.to_string());
|
||||
row.push(gain_loss.to_string());
|
||||
row.push(income.to_string());
|
||||
row.push(expense.to_string());
|
||||
row.push(orig_proc.to_string());
|
||||
row.push(orig_cost.to_string());
|
||||
row.push(orig_gain_loss.to_string());
|
||||
rows.push(row);
|
||||
}
|
||||
}
|
||||
|
||||
let file_name = PathBuf::from("C6_Txns_mvmts_detail_w_orig.csv");
|
||||
let path = PathBuf::from(&settings.export_path);
|
||||
|
||||
let full_path: PathBuf = [path, file_name].iter().collect();
|
||||
|
@ -465,7 +652,7 @@ pub fn _5_transaction_mvmt_summaries_to_csv(
|
|||
// row.push(txn.transaction_type(ars, &raw_acct_map, &acct_map).to_string());
|
||||
// row.push(txn.memo.to_string());
|
||||
// row.push(mvmt.amount.to_string());
|
||||
// row.push(mvmt.proceeds.get().to_string());
|
||||
// row.push(mvmt.proceeds_lk.get().to_string());
|
||||
// row.push(mvmt.cost_basis.get().to_string());
|
||||
// row.push(mvmt.get_gain_or_loss().to_string());
|
||||
// row.push(mvmt.get_term(acct_map, ars).to_string());
|
||||
|
|
|
@ -137,6 +137,7 @@ pub fn import_transactions(
|
|||
let mut this_proceeds: &str = "";
|
||||
let mut this_memo: &str = "";
|
||||
let mut this: String;
|
||||
let mut proceeds_parsed = 0f32;
|
||||
|
||||
// Next, create action_records.
|
||||
let mut action_records_map_keys_vec: Vec<u32> = [].to_vec();
|
||||
|
@ -152,6 +153,7 @@ pub fn import_transactions(
|
|||
else if idx == 1 {
|
||||
this = field.replace(",", "");
|
||||
this_proceeds = this.as_str();
|
||||
proceeds_parsed = this_proceeds.parse::<f32>()?;
|
||||
}
|
||||
else if idx == 2 { this_memo = field; }
|
||||
|
||||
|
@ -213,7 +215,7 @@ pub fn import_transactions(
|
|||
date_as_string: this_tx_date.to_string(),
|
||||
date: tx_date,
|
||||
memo: this_memo.to_string(),
|
||||
proceeds: this_proceeds.parse::<f32>()?,
|
||||
proceeds: proceeds_parsed,
|
||||
action_record_idx_vec: action_records_map_keys_vec,
|
||||
};
|
||||
|
||||
|
|
|
@ -44,36 +44,52 @@ pub fn add_cost_basis_to_movements(
|
|||
// println!("Txn: {} on {} of type: {:?}",txn.tx_number,txn.date, txn.transaction_type());
|
||||
|
||||
if !raw_acct.is_margin {
|
||||
|
||||
match polarity {
|
||||
|
||||
Polarity::Outgoing => {
|
||||
|
||||
if is_home_curr {
|
||||
|
||||
let mvmts_amt = mvmt_copy.amount;
|
||||
|
||||
mvmt.cost_basis.set(mvmts_amt);
|
||||
mvmt.cost_basis_lk.set(mvmts_amt);
|
||||
|
||||
} else {
|
||||
let mvmt_lot = mvmt_copy.get_lot(acct_map, ars);
|
||||
let borrowed_mvmt_list = mvmt_lot.movements.borrow().clone();
|
||||
let lots_first_mvmt = borrowed_mvmt_list.first().unwrap().clone();
|
||||
let cb_of_lots_first_mvmt = lots_first_mvmt.cost_basis.get();
|
||||
|
||||
// let mvmt_lot = mvmt_copy.get_lot(acct_map, ars);
|
||||
// let borrowed_mvmt_list = mvmt_lot.movements.borrow().clone();
|
||||
// let lots_first_mvmt = borrowed_mvmt_list.first().unwrap().clone();
|
||||
// let cb_of_lots_first_mvmt = lots_first_mvmt.cost_basis.get();
|
||||
let cb_of_lots_first_mvmt = mvmt_copy.get_cost_basis_of_lots_first_mvmt(acct_map, ars);
|
||||
let ratio_of_amt_to_lots_first_mvmt = borrowed_mvmt.ratio_of_amt_to_lots_first_mvmt(acct_map, ars);
|
||||
let unrounded_basis = -(cb_of_lots_first_mvmt * ratio_of_amt_to_lots_first_mvmt);
|
||||
let rounded_basis = round_d128_1e2(&unrounded_basis);
|
||||
|
||||
mvmt.cost_basis.set(rounded_basis);
|
||||
// if txn.tx_number == 5 {
|
||||
// println!("Txn#: {}, ratio: {}, cb of lot's 1st mvmt: {}, cost basis: {}", txn.tx_number, ratio_of_amt_to_lots_first_mvmt, cb_of_lots_first_mvmt, cost_basis)
|
||||
// };
|
||||
mvmt.cost_basis_lk.set(rounded_basis);
|
||||
}
|
||||
// println!("Outgoing a_r from txn: {} of type: {:?}, with {} {} with cost basis: {}",
|
||||
// txn.tx_number, txn.transaction_type(), borrowed_mvmt.amount, ar.account.ticker, cost_basis);
|
||||
assert!(mvmt.cost_basis.get() <= d128!(0));
|
||||
// assert!(mvmt.cost_basis_lk.get() <= d128!(0)); // Same as above assert.
|
||||
continue
|
||||
}
|
||||
|
||||
Polarity::Incoming => {
|
||||
|
||||
if is_home_curr {
|
||||
|
||||
let mvmts_amt = mvmt_copy.amount;
|
||||
|
||||
mvmt.cost_basis.set(mvmts_amt);
|
||||
mvmt.cost_basis_lk.set(mvmts_amt);
|
||||
|
||||
} else {
|
||||
|
||||
match tx_type {
|
||||
|
||||
TxType::Exchange => {
|
||||
|
||||
let other_ar = ars.get(&txn.action_record_idx_vec[0]).unwrap();
|
||||
let other_acct = acct_map.get(&other_ar.account_key).unwrap();
|
||||
let raw_other_acct = raw_acct_map.get(&other_acct.raw_key).unwrap();
|
||||
|
@ -82,42 +98,66 @@ pub fn add_cost_basis_to_movements(
|
|||
|
||||
if other_ar_is_home_curr {
|
||||
mvmt.cost_basis.set(-(other_ar.amount));
|
||||
mvmt.cost_basis_lk.set(-(other_ar.amount));
|
||||
|
||||
} else {
|
||||
|
||||
let ratio_of_amt_to_incoming_mvmts_in_a_r =
|
||||
borrowed_mvmt.ratio_of_amt_to_incoming_mvmts_in_a_r;
|
||||
let txn_proceeds = txn.proceeds.to_string().parse::<d128>().unwrap();
|
||||
let unrounded_basis = txn_proceeds * ratio_of_amt_to_incoming_mvmts_in_a_r;
|
||||
let rounded_basis = round_d128_1e2(&unrounded_basis);
|
||||
mvmt.cost_basis.set(rounded_basis);
|
||||
}
|
||||
}
|
||||
TxType::ToSelf => {
|
||||
let cb_outgoing_ar = retrieve_cost_basis_from_corresponding_outgoing_toself(
|
||||
txn_num, &ars, txns_map, acct_map);
|
||||
let ratio_of_amt_to_incoming_mvmts_in_a_r = borrowed_mvmt.ratio_of_amt_to_incoming_mvmts_in_a_r;
|
||||
let this_ratio = (ratio_of_amt_to_incoming_mvmts_in_a_r)
|
||||
let txn_proceeds = txn.proceeds
|
||||
.to_string()
|
||||
.parse::<d128>()
|
||||
.unwrap();
|
||||
let unrounded_basis = cb_outgoing_ar * this_ratio;
|
||||
let unrounded_basis = txn_proceeds * ratio_of_amt_to_incoming_mvmts_in_a_r;
|
||||
let rounded_basis = round_d128_1e2(&unrounded_basis);
|
||||
|
||||
mvmt.cost_basis.set(rounded_basis);
|
||||
mvmt.cost_basis_lk.set(rounded_basis);
|
||||
}
|
||||
}
|
||||
|
||||
TxType::ToSelf => {
|
||||
|
||||
let ratio_of_amt_to_incoming_mvmts_in_a_r =
|
||||
borrowed_mvmt.ratio_of_amt_to_incoming_mvmts_in_a_r;
|
||||
let cb_outgoing_ar = retrieve_cost_basis_from_corresponding_outgoing_toself(
|
||||
txn_num,
|
||||
&ars,
|
||||
txns_map,
|
||||
acct_map
|
||||
);
|
||||
// let this_ratio = ratio_of_amt_to_incoming_mvmts_in_a_r
|
||||
// .to_string()
|
||||
// .parse::<d128>()
|
||||
// .unwrap(); // I don't recall why this was once needed in the next line.
|
||||
let unrounded_basis = cb_outgoing_ar * ratio_of_amt_to_incoming_mvmts_in_a_r;
|
||||
let rounded_basis = round_d128_1e2(&unrounded_basis);
|
||||
|
||||
mvmt.cost_basis.set(-rounded_basis);
|
||||
mvmt.cost_basis_lk.set(-rounded_basis);
|
||||
}
|
||||
|
||||
TxType::Flow => {
|
||||
|
||||
let txn_proceeds = txn.proceeds.to_string().parse::<d128>().unwrap();
|
||||
let mvmt_proceeds = round_d128_1e2(&(txn_proceeds *
|
||||
borrowed_mvmt.ratio_of_amt_to_incoming_mvmts_in_a_r));
|
||||
let mvmt_proceeds = round_d128_1e2(
|
||||
&(txn_proceeds *
|
||||
borrowed_mvmt.ratio_of_amt_to_incoming_mvmts_in_a_r)
|
||||
); // Ratio should always be 1.0, but we do the calc anyway, for future-proofing.
|
||||
|
||||
mvmt.cost_basis.set(mvmt_proceeds);
|
||||
mvmt.cost_basis_lk.set(mvmt_proceeds);
|
||||
}
|
||||
}
|
||||
}
|
||||
// println!("Incoming a_r from txn: {} of type: {:?}, with {} {} with cost basis: {}",
|
||||
// txn.tx_number, txn.transaction_type(), borrowed_mvmt.amount, ar.account.ticker, cost_basis);
|
||||
assert!(mvmt.cost_basis.get() >= d128!(0));
|
||||
// assert!(mvmt.cost_basis_lk.get() >= d128!(0)); // Same as above assert.
|
||||
continue
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Do nothing. Future changes can add a code path where margin txns "settle"
|
||||
// as they happen, though, if desired. Just need to write the code.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -174,27 +214,46 @@ pub fn add_proceeds_to_movements(
|
|||
let borrowed_mvmt = mvmt_copy.clone();
|
||||
|
||||
match tx_type {
|
||||
TxType::Exchange => {
|
||||
|
||||
TxType::Exchange | TxType::Flow => {
|
||||
|
||||
match polarity {
|
||||
|
||||
Polarity::Outgoing => {
|
||||
|
||||
let ratio = borrowed_mvmt.amount / ar.amount;
|
||||
let proceeds_unrounded = txn.proceeds.to_string().parse::<d128>().unwrap() * ratio;
|
||||
let proceeds_rounded = round_d128_1e2(&proceeds_unrounded);
|
||||
|
||||
mvmt.proceeds.set(proceeds_rounded);
|
||||
mvmt.proceeds_lk.set(proceeds_rounded);
|
||||
}
|
||||
Polarity::Incoming => {}
|
||||
|
||||
Polarity::Incoming => {
|
||||
// For a time, this was blank. As part of the commit(s) to add cost_basis_lk
|
||||
// and proceeds_lk, let's change this to reflect that incoming proceeds are now
|
||||
// negative, which net against the positive cost_basis to result in a gain of $0.
|
||||
// Additionally, we apply the same treatment to Flow txns.
|
||||
mvmt.proceeds.set(-mvmt.cost_basis.get());
|
||||
mvmt.proceeds_lk.set(-mvmt.cost_basis_lk.get());
|
||||
}
|
||||
}
|
||||
TxType::Flow => {
|
||||
let ratio = borrowed_mvmt.amount / ar.amount;
|
||||
let proceeds_unrounded = txn.proceeds.to_string().parse::<d128>().unwrap() * ratio;
|
||||
let proceeds_rounded = round_d128_1e2(&proceeds_unrounded);
|
||||
mvmt.proceeds.set(proceeds_rounded);
|
||||
}
|
||||
TxType::ToSelf => {}
|
||||
|
||||
// TxType::Flow => {
|
||||
// let ratio = borrowed_mvmt.amount / ar.amount;
|
||||
// let proceeds_unrounded = txn.proceeds.to_string().parse::<d128>().unwrap() * ratio;
|
||||
// let proceeds_rounded = round_d128_1e2(&proceeds_unrounded);
|
||||
// mvmt.proceeds.set(proceeds_rounded);
|
||||
// }
|
||||
|
||||
TxType::ToSelf => {
|
||||
// Originally did nothing. Now explicity creating a condition where a report containing
|
||||
// ToSelf txns would reflect a $0 gain/loss.
|
||||
mvmt.proceeds.set(-mvmt.cost_basis.get());
|
||||
mvmt.proceeds_lk.set(-mvmt.cost_basis_lk.get());
|
||||
}
|
||||
}
|
||||
// println!("Txn: {}, type: {:?} of {} {} w/ proceeds: {} & basis: {}",
|
||||
// txn.tx_number, txn.transaction_type(), borrowed_mvmt.amount, ar.account.ticker, proceeds, borrowed_mvmt.cost_basis);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -222,6 +281,9 @@ pub fn apply_like_kind_treatment(
|
|||
if txn.date <= cutoff_date {
|
||||
perform_likekind_treatment_on_txn(txn_num, &settings, &ars, &raw_acct_map, &acct_map, &txns_map)?;
|
||||
}
|
||||
// else {
|
||||
// // carry_forward_deferred_gains(txn_num, &settings, &ars, &raw_acct_map, &acct_map, &txns_map)?;
|
||||
// }
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -236,7 +298,7 @@ fn update_current_txn_for_prior_likekind_treatment(
|
|||
txns_map: &HashMap<u32, Transaction>,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
|
||||
let mut sum_of_outgoing_cost_basis_in_ar = d128!(0);
|
||||
let mut sum_of_outgoing_lk_cost_basis_in_ar = d128!(0);
|
||||
let txn = txns_map.get(&txn_num).unwrap();
|
||||
|
||||
for ar_num in txn.action_record_idx_vec.iter() {
|
||||
|
@ -256,31 +318,58 @@ fn update_current_txn_for_prior_likekind_treatment(
|
|||
let borrowed_mvmt = mvmt_copy.clone();
|
||||
|
||||
if !raw_acct.is_margin {
|
||||
|
||||
match polarity {
|
||||
|
||||
Polarity::Outgoing => {
|
||||
|
||||
if !is_home_curr {
|
||||
let borrowed_mvmt_lot = borrowed_mvmt.get_lot(acct_map, ars);
|
||||
let borrowed_mvmt_list = borrowed_mvmt_lot.movements.borrow();
|
||||
let cb_of_lots_first_mvmt = borrowed_mvmt_list.first().unwrap().cost_basis.get();
|
||||
|
||||
// let borrowed_mvmt_lot = borrowed_mvmt.get_lot(acct_map, ars);
|
||||
// let borrowed_mvmt_list = borrowed_mvmt_lot.movements.borrow();
|
||||
// let lk_cb_of_lots_first_mvmt = borrowed_mvmt_list.first().unwrap().cost_basis_lk.get();
|
||||
let lk_cb_of_lots_first_mvmt = borrowed_mvmt.get_lk_cost_basis_of_lots_first_mvmt(acct_map, ars);
|
||||
let ratio_of_amt_to_lots_first_mvmt = borrowed_mvmt.ratio_of_amt_to_lots_first_mvmt(acct_map, ars);
|
||||
let unrounded_basis = -(cb_of_lots_first_mvmt * ratio_of_amt_to_lots_first_mvmt);
|
||||
let rounded_basis = round_d128_1e2(&unrounded_basis);
|
||||
mvmt.cost_basis.set(rounded_basis);
|
||||
let unrounded_lk_basis = -(lk_cb_of_lots_first_mvmt * ratio_of_amt_to_lots_first_mvmt);
|
||||
let rounded_lk_basis = round_d128_1e2(&unrounded_lk_basis);
|
||||
|
||||
mvmt.cost_basis_lk.set(rounded_lk_basis);
|
||||
|
||||
if tx_type == TxType::ToSelf {
|
||||
mvmt.proceeds_lk.set(-rounded_lk_basis)
|
||||
}
|
||||
sum_of_outgoing_cost_basis_in_ar += mvmt.cost_basis.get()
|
||||
}
|
||||
sum_of_outgoing_lk_cost_basis_in_ar += mvmt.cost_basis_lk.get()
|
||||
}
|
||||
|
||||
Polarity::Incoming => {
|
||||
|
||||
match tx_type {
|
||||
TxType::Exchange => {}
|
||||
TxType::Flow => {}
|
||||
|
||||
TxType::Exchange => {
|
||||
// Do nothing.
|
||||
// If txn.date is after the LK treatment date, the incoming mvmt goes untreated.
|
||||
// If txn.date is before the LK date, incoming mvmt gets treatment in apply_lk_treatment next.
|
||||
}
|
||||
TxType::Flow => {
|
||||
if txn.action_record_idx_vec.len() == 2 {
|
||||
mvmt.cost_basis_lk.set(d128!(0));
|
||||
mvmt.proceeds_lk.set(d128!(0));
|
||||
}
|
||||
// Do nothing for non-margin txns.
|
||||
}
|
||||
TxType::ToSelf => {
|
||||
|
||||
if !is_home_curr {
|
||||
|
||||
let ratio_of_amt_to_incoming_mvmts_in_a_r =
|
||||
borrowed_mvmt.ratio_of_amt_to_incoming_mvmts_in_a_r;
|
||||
let unrounded_basis = sum_of_outgoing_cost_basis_in_ar *
|
||||
let unrounded_lk_basis = sum_of_outgoing_lk_cost_basis_in_ar *
|
||||
ratio_of_amt_to_incoming_mvmts_in_a_r;
|
||||
let rounded_basis = round_d128_1e2(&unrounded_basis);
|
||||
mvmt.cost_basis.set(-rounded_basis);
|
||||
let rounded_lk_basis = round_d128_1e2(&unrounded_lk_basis);
|
||||
|
||||
mvmt.cost_basis_lk.set(-rounded_lk_basis);
|
||||
mvmt.proceeds_lk.set(rounded_lk_basis);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -305,6 +394,10 @@ fn perform_likekind_treatment_on_txn(
|
|||
let txn = txns_map.get(&txn_num).unwrap();
|
||||
let tx_type = txn.transaction_type(ars, raw_acct_map, acct_map)?;
|
||||
|
||||
match tx_type {
|
||||
|
||||
TxType::Exchange => {
|
||||
|
||||
let og_ar = ars.get(&txn.action_record_idx_vec.first().unwrap()).unwrap();
|
||||
let ic_ar = ars.get(&txn.action_record_idx_vec.last().unwrap()).unwrap();
|
||||
let og_acct = acct_map.get(&og_ar.account_key).unwrap();
|
||||
|
@ -312,20 +405,15 @@ fn perform_likekind_treatment_on_txn(
|
|||
let raw_og_acct = raw_acct_map.get(&og_acct.raw_key).unwrap();
|
||||
let raw_ic_acct = raw_acct_map.get(&ic_acct.raw_key).unwrap();
|
||||
|
||||
fn both_are_non_home_curr(raw_og_acct: &RawAccount, raw_ic_acct: &RawAccount, settings: &ImportProcessParameters) -> bool {
|
||||
let og_is_home_curr = raw_og_acct.is_home_currency(&settings.home_currency);
|
||||
let ic_is_home_curr = raw_ic_acct.is_home_currency(&settings.home_currency);
|
||||
let both_are_non_home_curr = !ic_is_home_curr && !og_is_home_curr;
|
||||
both_are_non_home_curr
|
||||
}
|
||||
if _both_are_non_home_curr(raw_og_acct, raw_ic_acct, settings) {
|
||||
|
||||
let mut sum_of_outgoing_lk_cost_basis_in_ar = d128!(0);
|
||||
|
||||
match tx_type {
|
||||
TxType::Exchange => {
|
||||
if both_are_non_home_curr(raw_og_acct, raw_ic_acct, settings) {
|
||||
let mut sum_of_outgoing_cost_basis_in_ar = d128!(0);
|
||||
for ar_num in txn.action_record_idx_vec.iter() {
|
||||
|
||||
let ar = ars.get(ar_num).unwrap();
|
||||
let movements = ar.get_mvmts_in_ar(acct_map, txns_map);
|
||||
|
||||
for mvmt in movements.iter() {
|
||||
|
||||
let polarity = ar.direction();
|
||||
|
@ -334,26 +422,38 @@ fn perform_likekind_treatment_on_txn(
|
|||
let borrowed_mvmt = mvmt_copy.clone();
|
||||
|
||||
match polarity {
|
||||
|
||||
Polarity::Outgoing => {
|
||||
let cb = borrowed_mvmt.cost_basis.get();
|
||||
sum_of_outgoing_cost_basis_in_ar += cb;
|
||||
mvmt.proceeds.set(-cb);
|
||||
|
||||
let cb = borrowed_mvmt.cost_basis_lk.get();
|
||||
sum_of_outgoing_lk_cost_basis_in_ar += cb;
|
||||
|
||||
mvmt.proceeds_lk.set(-cb);
|
||||
}
|
||||
|
||||
Polarity::Incoming => {
|
||||
|
||||
let ratio_of_amt_to_incoming_mvmts_in_a_r =
|
||||
borrowed_mvmt.ratio_of_amt_to_incoming_mvmts_in_a_r;
|
||||
let unrounded_basis = sum_of_outgoing_cost_basis_in_ar *
|
||||
let unrounded_basis = sum_of_outgoing_lk_cost_basis_in_ar *
|
||||
ratio_of_amt_to_incoming_mvmts_in_a_r;
|
||||
let rounded_basis = round_d128_1e2(&unrounded_basis);
|
||||
mvmt.cost_basis.set(-rounded_basis);
|
||||
|
||||
mvmt.cost_basis_lk.set(-rounded_basis);
|
||||
mvmt.proceeds_lk.set(rounded_basis);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TxType::Flow => {
|
||||
|
||||
if txn.action_record_idx_vec.len() == 2 {
|
||||
|
||||
// Consider asserting TxHasMargin::OneAR
|
||||
|
||||
for ar_num in txn.action_record_idx_vec.iter() {
|
||||
|
||||
let ar = ars.get(ar_num).unwrap();
|
||||
|
@ -364,7 +464,13 @@ fn perform_likekind_treatment_on_txn(
|
|||
for mvmt in movements.iter() {
|
||||
|
||||
match polarity {
|
||||
Polarity::Outgoing => {}
|
||||
|
||||
Polarity::Outgoing => {
|
||||
// Do nothing.
|
||||
// If 'spot' acct outgoing, the loss nets to the basis in the spent coins.
|
||||
// If margin acct outgoing, no gain, and the incoming gets no cost basis.
|
||||
}
|
||||
|
||||
Polarity::Incoming => {
|
||||
// Reminder: May need extra logic here if margin exchange trades get cost_basis and proceeds
|
||||
mvmt.cost_basis.set(d128!(0));
|
||||
|
@ -375,7 +481,23 @@ fn perform_likekind_treatment_on_txn(
|
|||
}
|
||||
}
|
||||
}
|
||||
TxType::ToSelf => {}
|
||||
|
||||
TxType::ToSelf => {
|
||||
// Like-kind "exchange," so do nothing.
|
||||
}
|
||||
}
|
||||
|
||||
fn _both_are_non_home_curr(
|
||||
raw_og_acct: &RawAccount,
|
||||
raw_ic_acct: &RawAccount,
|
||||
settings: &ImportProcessParameters
|
||||
) -> bool {
|
||||
|
||||
let og_is_home_curr = raw_og_acct.is_home_currency(&settings.home_currency);
|
||||
let ic_is_home_curr = raw_ic_acct.is_home_currency(&settings.home_currency);
|
||||
let both_are_non_home_curr = !ic_is_home_curr && !og_is_home_curr;
|
||||
|
||||
both_are_non_home_curr
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
14
src/main.rs
14
src/main.rs
|
@ -275,6 +275,12 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||
&raw_acct_map
|
||||
);
|
||||
|
||||
csv_export::_3_account_sums_to_csv_with_orig_basis(
|
||||
&settings,
|
||||
&raw_acct_map,
|
||||
&account_map
|
||||
);
|
||||
|
||||
csv_export::_4_transaction_mvmt_detail_to_csv(
|
||||
&settings,
|
||||
&action_records_map,
|
||||
|
@ -291,6 +297,14 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||
&transactions_map
|
||||
)?;
|
||||
|
||||
csv_export::_6_transaction_mvmt_detail_to_csv_w_orig(
|
||||
&settings,
|
||||
&action_records_map,
|
||||
&raw_acct_map,
|
||||
&account_map,
|
||||
&transactions_map
|
||||
)?;
|
||||
|
||||
txt_export::_1_account_lot_detail_to_txt(
|
||||
&settings,
|
||||
&raw_acct_map,
|
||||
|
|
|
@ -9,7 +9,7 @@ use std::io::prelude::Write;
|
|||
|
||||
use decimal::d128;
|
||||
|
||||
use crate::transaction::{Transaction, ActionRecord, TxType};
|
||||
use crate::transaction::{Transaction, ActionRecord};
|
||||
use crate::account::{Account, RawAccount};
|
||||
use crate::core_functions::{ImportProcessParameters};
|
||||
|
||||
|
@ -60,7 +60,7 @@ pub fn _1_account_lot_detail_to_txt(
|
|||
|
||||
|
||||
|
||||
let file_name = PathBuf::from("1_Acct_lot_detail.txt");
|
||||
let file_name = PathBuf::from("T1_Acct_lot_detail.txt");
|
||||
let path = PathBuf::from(&settings.export_path.clone());
|
||||
let full_path: PathBuf = [path, file_name].iter().collect();
|
||||
|
||||
|
@ -99,14 +99,16 @@ Enable like-kind treatment: {}",
|
|||
writeln!(file, "Account balance: {} {}; Total cost basis: {}",
|
||||
acct.get_sum_of_amts_in_lots(),
|
||||
raw_acct.ticker,
|
||||
acct.get_sum_of_basis_in_lots()
|
||||
acct.get_sum_of_lk_basis_in_lots()
|
||||
)?;
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
if raw_acct.is_margin { writeln!(file, "Margin Account")?; }
|
||||
|
||||
for (lot_idx, lot) in acct.list_of_lots.borrow().iter().enumerate() {
|
||||
|
||||
let lot_basis = lot.get_sum_of_basis_in_lot();
|
||||
let lk_lot_basis = lot.get_sum_of_lk_basis_in_lot();
|
||||
let movements_sum = lot.get_sum_of_amts_in_lot();
|
||||
|
||||
if acct.list_of_lots.borrow().len() > 0 {
|
||||
|
@ -115,7 +117,7 @@ Enable like-kind treatment: {}",
|
|||
writeln!(file, " Lot {}", (lot_idx+1))?;
|
||||
writeln!(file, "\t• Σ: {}, with remaining cost basis of {} and basis date of {}",
|
||||
movements_sum,
|
||||
lot_basis,
|
||||
lk_lot_basis,
|
||||
lot.date_for_basis_purposes
|
||||
)?;
|
||||
writeln!(file, "\t Movements:")?;
|
||||
|
@ -137,26 +139,27 @@ Enable like-kind treatment: {}",
|
|||
|
||||
writeln!(file, "{}", description_str)?;
|
||||
|
||||
let proceeds = mvmt.proceeds.get();
|
||||
let cost_basis = mvmt.cost_basis.get();
|
||||
let lk_proceeds = mvmt.proceeds_lk.get();
|
||||
let lk_cost_basis = mvmt.cost_basis_lk.get();
|
||||
let gain_loss: d128;
|
||||
|
||||
if mvmt.amount > d128!(0) { // Can't have a gain on an incoming txn
|
||||
gain_loss = d128!(0)
|
||||
} else if raw_acct.is_home_currency(&settings.home_currency) { // Can't have a gain disposing home currency
|
||||
gain_loss = d128!(0)
|
||||
} else if tx_type == TxType::ToSelf { // Can't have a gain sending to yourself
|
||||
// if mvmt.amount > d128!(0) { // Can't have a gain on an incoming txn
|
||||
// gain_loss = d128!(0)
|
||||
// } else
|
||||
if raw_acct.is_home_currency(&settings.home_currency) { // Can't have a gain disposing home currency
|
||||
gain_loss = d128!(0)
|
||||
// } else if tx_type == TxType::ToSelf { // Can't have a gain sending to yourself
|
||||
// gain_loss = d128!(0)
|
||||
} else {
|
||||
gain_loss = proceeds + cost_basis
|
||||
gain_loss = lk_proceeds + lk_cost_basis;
|
||||
}
|
||||
|
||||
let income = mvmt.get_income(ars, raw_acct_map, acct_map, txns_map)?;
|
||||
let expense = mvmt.get_expense(ars, raw_acct_map, acct_map, txns_map)?;
|
||||
|
||||
let activity_str = format!("\t\t\tProceeds: {}; Cost basis: {}; for Gain/loss: {} {}; Inc.: {}; Exp.: {}.",
|
||||
proceeds,
|
||||
cost_basis,
|
||||
lk_proceeds,
|
||||
lk_cost_basis,
|
||||
mvmt.get_term(acct_map, ars),
|
||||
gain_loss,
|
||||
income,
|
||||
|
@ -166,8 +169,8 @@ Enable like-kind treatment: {}",
|
|||
writeln!(file, "{}", activity_str)?;
|
||||
|
||||
// if settings.enable_like_kind_treatment {
|
||||
// let dg_prev = mvmt.deferred_gain_prev.get();
|
||||
// let dg_curr = mvmt.deferred_gain_curr.get();
|
||||
// let dg_prev = mvmt.proceeds_lk.get();
|
||||
// let dg_curr = mvmt.cost_basis_lk.get();
|
||||
|
||||
// let activity_str = format!("\t\t\tGain deferred in this txn: {}; Accumulated in prior txns: {}",
|
||||
// dg_curr,
|
||||
|
@ -205,7 +208,7 @@ pub fn _2_account_lot_summary_to_txt(
|
|||
|
||||
|
||||
|
||||
let file_name = PathBuf::from("2_Acct_lot_summary.txt");
|
||||
let file_name = PathBuf::from("T2_Acct_lot_summary.txt");
|
||||
let path = PathBuf::from(&settings.export_path.clone());
|
||||
let full_path: PathBuf = [path, file_name].iter().collect();
|
||||
|
||||
|
@ -244,14 +247,14 @@ Enable like-kind treatment: {}",
|
|||
writeln!(file, "Account balance: {} {}; Total cost basis: {}",
|
||||
acct.get_sum_of_amts_in_lots(),
|
||||
raw_acct.ticker,
|
||||
acct.get_sum_of_basis_in_lots()
|
||||
acct.get_sum_of_lk_basis_in_lots()
|
||||
)?;
|
||||
}
|
||||
if raw_acct.is_margin { writeln!(file, "Margin Account")?; }
|
||||
|
||||
for (lot_idx, lot) in acct.list_of_lots.borrow().iter().enumerate() {
|
||||
|
||||
let lot_basis = lot.get_sum_of_basis_in_lot();
|
||||
let lk_lot_basis = lot.get_sum_of_lk_basis_in_lot();
|
||||
let movements_sum = lot.get_sum_of_amts_in_lot();
|
||||
|
||||
if acct.list_of_lots.borrow().len() > 0 {
|
||||
|
@ -259,7 +262,7 @@ Enable like-kind treatment: {}",
|
|||
writeln!(file, " Lot {} • Σ: {}, with remaining cost basis of {} and basis date of {}",
|
||||
(lot_idx+1),
|
||||
movements_sum,
|
||||
lot_basis,
|
||||
lk_lot_basis,
|
||||
lot.date_for_basis_purposes
|
||||
)?;
|
||||
}
|
||||
|
@ -287,7 +290,7 @@ pub fn _3_account_lot_summary_non_zero_to_txt(
|
|||
|
||||
|
||||
|
||||
let file_name = PathBuf::from("3_Acct_lot_summary_non_zero.txt");
|
||||
let file_name = PathBuf::from("T3_Acct_lot_summary_non_zero.txt");
|
||||
let path = PathBuf::from(&settings.export_path.clone());
|
||||
let full_path: PathBuf = [path, file_name].iter().collect();
|
||||
|
||||
|
@ -328,7 +331,7 @@ Enable like-kind treatment: {}",
|
|||
writeln!(file, "Account balance: {} {}; Total cost basis: {}",
|
||||
amt_in_acct,
|
||||
raw_acct.ticker,
|
||||
acct.get_sum_of_basis_in_lots()
|
||||
acct.get_sum_of_lk_basis_in_lots()
|
||||
)?;
|
||||
} else {
|
||||
continue
|
||||
|
@ -338,7 +341,7 @@ Enable like-kind treatment: {}",
|
|||
|
||||
for (lot_idx, lot) in acct.list_of_lots.borrow().iter().enumerate() {
|
||||
|
||||
let lot_basis = lot.get_sum_of_basis_in_lot();
|
||||
let lk_lot_basis = lot.get_sum_of_lk_basis_in_lot();
|
||||
let movements_sum = lot.get_sum_of_amts_in_lot();
|
||||
|
||||
if acct.list_of_lots.borrow().len() > 0 {
|
||||
|
@ -347,7 +350,7 @@ Enable like-kind treatment: {}",
|
|||
writeln!(file, " Lot {} • Σ: {}, with remaining cost basis of {} and basis date of {}",
|
||||
(lot_idx+1),
|
||||
movements_sum,
|
||||
lot_basis,
|
||||
lk_lot_basis,
|
||||
lot.date_for_basis_purposes
|
||||
)?;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue