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,
|
pub department: String,
|
||||||
#[serde(serialize_with = "round_serialize")]
|
#[serde(serialize_with = "round_serialize")]
|
||||||
pub value: f64,
|
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>
|
fn round_serialize<S>(x: &f64, s: S) -> Result<S::Ok, S::Error>
|
||||||
@@ -271,16 +280,15 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Then run move_money
|
// 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
|
if !flush_pass {
|
||||||
for money in moved {
|
// Ouput the final moneys
|
||||||
for (unit, value) in money.totals {
|
for (unit, value) in moved {
|
||||||
output.serialize(CsvCost {
|
output.serialize(CsvCost {
|
||||||
account: unit.account,
|
account: unit.account,
|
||||||
department: unit.department,
|
department: unit.department,
|
||||||
value,
|
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.
|
// Advantage of this approach is it can be easily extended to run on the gpu.
|
||||||
pub fn move_money_1() {}
|
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:
|
// Approach 2:
|
||||||
// Traditinoal/naive, total for each department is stored in an initial map (department -> total amount).
|
// 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
|
// 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.
|
// 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
|
// 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
|
// 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>,
|
initial_totals: HashMap<Unit, f64>,
|
||||||
rules: &Vec<MovementRule>,
|
rules: &Vec<MovementRule>,
|
||||||
flush_pass: bool,
|
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),
|
// 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
|
// 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
|
// 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
|
// to add a new line
|
||||||
let mut running_total = HashMap::from(initial_totals);
|
let mut running_total = HashMap::from(initial_totals);
|
||||||
let mut temp_total = running_total.clone();
|
let mut temp_total = running_total.clone();
|
||||||
let mut move_money_result: Vec<MoveMoneyResult> = vec![];
|
|
||||||
let mut current_pass = 0;
|
let mut current_pass = 0;
|
||||||
if flush_pass {
|
if flush_pass {
|
||||||
move_money_result.push(MoveMoneyResult {
|
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,
|
pass: current_pass,
|
||||||
totals: running_total.clone(),
|
|
||||||
})
|
})
|
||||||
|
.expect("Failed to write moved amount")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for rule in rules {
|
for rule in rules {
|
||||||
if rule.is_separator {
|
if rule.is_separator {
|
||||||
if flush_pass {
|
|
||||||
current_pass += 1;
|
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(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
running_total = temp_total.clone();
|
running_total = temp_total.clone();
|
||||||
} else {
|
} else {
|
||||||
for (unit, amount) in &running_total {
|
for (unit, amount) in &running_total {
|
||||||
@@ -399,6 +399,18 @@ pub fn move_money_2(
|
|||||||
} else {
|
} else {
|
||||||
unit.account.clone()
|
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
|
*temp_total
|
||||||
.entry(Unit {
|
.entry(Unit {
|
||||||
department,
|
department,
|
||||||
@@ -409,12 +421,7 @@ pub fn move_money_2(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
move_money_result.push(MoveMoneyResult {
|
temp_total
|
||||||
pass: current_pass,
|
|
||||||
totals: temp_total,
|
|
||||||
});
|
|
||||||
|
|
||||||
move_money_result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@@ -381,7 +381,6 @@ where
|
|||||||
account: cost.account.clone(),
|
account: cost.account.clone(),
|
||||||
department: department.department,
|
department: department.department,
|
||||||
value: department.value,
|
value: department.value,
|
||||||
pass: None,
|
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user