Fix flush pass to print to and from department/account
This commit is contained in:
@@ -91,7 +91,16 @@ pub struct CsvCost {
|
||||
pub department: String,
|
||||
#[serde(serialize_with = "round_serialize")]
|
||||
pub value: f64,
|
||||
pub pass: Option<i32>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct MovedMoneyAmount {
|
||||
pub account: String,
|
||||
pub department: String,
|
||||
pub value: f64,
|
||||
pub from_account: String,
|
||||
pub from_department: String,
|
||||
pub pass: i32,
|
||||
}
|
||||
|
||||
fn round_serialize<S>(x: &f64, s: S) -> Result<S::Ok, S::Error>
|
||||
@@ -271,16 +280,15 @@ where
|
||||
}
|
||||
|
||||
// Then run move_money
|
||||
let moved = move_money_2(lines, &rules, flush_pass);
|
||||
let moved = move_money_2(lines, &rules, flush_pass, output);
|
||||
|
||||
// Ouput the list moved moneys
|
||||
for money in moved {
|
||||
for (unit, value) in money.totals {
|
||||
if !flush_pass {
|
||||
// Ouput the final moneys
|
||||
for (unit, value) in moved {
|
||||
output.serialize(CsvCost {
|
||||
account: unit.account,
|
||||
department: unit.department,
|
||||
value,
|
||||
pass: if flush_pass { Some(money.pass) } else { None },
|
||||
})?;
|
||||
}
|
||||
}
|
||||
@@ -323,12 +331,6 @@ fn extract_range(from: String, to: String, options: &Vec<String>) -> HashSet<Str
|
||||
// Advantage of this approach is it can be easily extended to run on the gpu.
|
||||
pub fn move_money_1() {}
|
||||
|
||||
pub struct MoveMoneyResult {
|
||||
pass: i32,
|
||||
// TODO: We want the from account and the to account
|
||||
totals: HashMap<Unit, f64>,
|
||||
}
|
||||
|
||||
// Approach 2:
|
||||
// Traditinoal/naive, total for each department is stored in an initial map (department -> total amount).
|
||||
// Another map is built up for each rule, and each rule is processed based on the amount in the current total
|
||||
@@ -340,41 +342,39 @@ pub struct MoveMoneyResult {
|
||||
// to every. It's also much more memory efficient than approach 1.
|
||||
// TODO: Time both approaches to seee which is faster depending on the size of the input data/number of rules
|
||||
// Verdict: This is already pretty fast, at least much faster than ppm for BigDataset
|
||||
pub fn move_money_2(
|
||||
pub fn move_money_2<W>(
|
||||
initial_totals: HashMap<Unit, f64>,
|
||||
rules: &Vec<MovementRule>,
|
||||
flush_pass: bool,
|
||||
) -> Vec<MoveMoneyResult> {
|
||||
output: &mut csv::Writer<W>,
|
||||
) -> HashMap<Unit, f64>
|
||||
where
|
||||
W: std::io::Write,
|
||||
{
|
||||
// Note: It's potentially a bit more intensive to use cloned totals (rather than just update temp_total per rule),
|
||||
// but it's much simpler code and, and since we're only working line-by-line, it isn't really that much memory in practice
|
||||
// TODO: This is initial totals is problematic, as we may move into a cc that wasn't in the list of lines. In which case we'd need
|
||||
// to add a new line
|
||||
let mut running_total = HashMap::from(initial_totals);
|
||||
let mut temp_total = running_total.clone();
|
||||
let mut move_money_result: Vec<MoveMoneyResult> = vec![];
|
||||
let mut current_pass = 0;
|
||||
if flush_pass {
|
||||
move_money_result.push(MoveMoneyResult {
|
||||
pass: current_pass,
|
||||
totals: running_total.clone(),
|
||||
})
|
||||
for (unit, value) in running_total.iter() {
|
||||
output
|
||||
.serialize(MovedMoneyAmount {
|
||||
account: unit.account.clone(),
|
||||
department: unit.department.clone(),
|
||||
value: *value,
|
||||
from_account: unit.account.clone(),
|
||||
from_department: unit.department.clone(),
|
||||
pass: current_pass,
|
||||
})
|
||||
.expect("Failed to write moved amount")
|
||||
}
|
||||
}
|
||||
for rule in rules {
|
||||
if rule.is_separator {
|
||||
if flush_pass {
|
||||
current_pass += 1;
|
||||
// Flush the totals at the end of this pass (more specifically the change)
|
||||
move_money_result.push(MoveMoneyResult {
|
||||
pass: current_pass,
|
||||
totals: temp_total
|
||||
.iter()
|
||||
.map(|(unit, value)| {
|
||||
(unit.clone(), value - running_total.get(unit).unwrap_or(&0.))
|
||||
})
|
||||
.filter(|(_, value)| *value != 0.)
|
||||
.collect(),
|
||||
});
|
||||
}
|
||||
current_pass += 1;
|
||||
running_total = temp_total.clone();
|
||||
} else {
|
||||
for (unit, amount) in &running_total {
|
||||
@@ -399,6 +399,18 @@ pub fn move_money_2(
|
||||
} else {
|
||||
unit.account.clone()
|
||||
};
|
||||
if flush_pass {
|
||||
output
|
||||
.serialize(MovedMoneyAmount {
|
||||
department: department.clone(),
|
||||
account: department.clone(),
|
||||
value: added_amount,
|
||||
from_department: unit.department.clone(),
|
||||
from_account: unit.account.clone(),
|
||||
pass: current_pass,
|
||||
})
|
||||
.expect("Failed to write moved amount");
|
||||
}
|
||||
*temp_total
|
||||
.entry(Unit {
|
||||
department,
|
||||
@@ -409,12 +421,7 @@ pub fn move_money_2(
|
||||
}
|
||||
}
|
||||
}
|
||||
move_money_result.push(MoveMoneyResult {
|
||||
pass: current_pass,
|
||||
totals: temp_total,
|
||||
});
|
||||
|
||||
move_money_result
|
||||
temp_total
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
Reference in New Issue
Block a user