|
@@ -176,43 +176,67 @@ fn check_balances(root: &data::Hoard) -> Result<(), DataError> {
|
|
for group in date_groups.into_iter() {
|
|
for group in date_groups.into_iter() {
|
|
check_balance_group(account, &mut running_balance, group.1)?;
|
|
check_balance_group(account, &mut running_balance, group.1)?;
|
|
}
|
|
}
|
|
|
|
+ }
|
|
|
|
+ Ok(())
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+fn check_merge_groups(root: &data::Hoard) -> Result<(), DataError> {
|
|
|
|
+ log::trace!("Checking merge groups...");
|
|
|
|
+
|
|
|
|
+ for account in root.account_names() {
|
|
|
|
+ let Some(ledger) = root.ledger_data_for(account) else {
|
|
|
|
+ continue;
|
|
|
|
+ };
|
|
|
|
|
|
- /*
|
|
|
|
for txn_ref in ledger {
|
|
for txn_ref in ledger {
|
|
let txn = txn_ref.borrow();
|
|
let txn = txn_ref.borrow();
|
|
- let change = txn.change_for(account).unwrap();
|
|
|
|
- let bal = running_balance
|
|
|
|
- .entry(*change.unit)
|
|
|
|
- .or_insert_with(|| Spanned::new(data::Decimal::default(), io::Span::default()));
|
|
|
|
- let last_span = bal.span();
|
|
|
|
- bal.0 = bal.checked_add(*change.amount).unwrap();
|
|
|
|
- bal.1 = change.source.unwrap();
|
|
|
|
|
|
+ let Some(group_id) = txn.merge_group() else { continue };
|
|
|
|
+ let Some(group) = root.merge_group(group_id) else {
|
|
|
|
+ todo!()
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ let txn_changes = txn.changes.iter().map(|c| (c.account, c.amount, c.unit)).sorted().collect_vec();
|
|
|
|
|
|
- if let Some(sbal) = change.balance.as_ref() {
|
|
|
|
- if **sbal != bal.0 {
|
|
|
|
|
|
+ for placeholder_ref in group {
|
|
|
|
+ let placeholder = placeholder_ref.borrow();
|
|
|
|
+
|
|
|
|
+ if txn.datestamp != placeholder.datestamp {
|
|
let report = ariadne::Report::build(
|
|
let report = ariadne::Report::build(
|
|
ariadne::ReportKind::Error,
|
|
ariadne::ReportKind::Error,
|
|
- txn.source.unwrap_or_default(),
|
|
|
|
|
|
+ txn.source.unwrap()
|
|
)
|
|
)
|
|
- .with_label(ariadne::Label::new(sbal.span()).with_message(format!(
|
|
|
|
- "Calculated balance is {} {}, specified balance is {} {}",
|
|
|
|
- bal, change.unit, sbal, change.unit
|
|
|
|
- )));
|
|
|
|
- let report = if !last_span.is_empty() {
|
|
|
|
- report.with_label(
|
|
|
|
- ariadne::Label::new(last_span)
|
|
|
|
- .with_message("Last balance is from here"),
|
|
|
|
- )
|
|
|
|
- } else {
|
|
|
|
- report
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
- return Err(report.finish().into());
|
|
|
|
|
|
+ .with_label(ariadne::Label::new(txn.source.unwrap()).with_message("this transaction"))
|
|
|
|
+ .with_label(ariadne::Label::new(placeholder.source.unwrap()).with_message("and this transaction"))
|
|
|
|
+ .with_message("different datestamps despite being in one merge group")
|
|
|
|
+ .finish();
|
|
|
|
+
|
|
|
|
+ return Err(report.into())
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let placeholder_changes = placeholder.changes.iter().map(|c| (c.account, c.amount, c.unit)).sorted().collect_vec();
|
|
|
|
+
|
|
|
|
+ let mut different_changes = txn_changes.iter().zip(placeholder_changes.iter()).filter(|(t,p)| t != p);
|
|
|
|
+
|
|
|
|
+ if let Some((t,p)) = different_changes.next() {
|
|
|
|
+ let tspan = t.0.span().union(t.1.span()).union(t.2.span());
|
|
|
|
+ let pspan = p.0.span().union(p.1.span()).union(p.2.span());
|
|
|
|
+
|
|
|
|
+ let report = ariadne::Report::build(
|
|
|
|
+ ariadne::ReportKind::Error,
|
|
|
|
+ txn.source.unwrap()
|
|
|
|
+ )
|
|
|
|
+ .with_label(ariadne::Label::new(txn.source.unwrap()).with_message("in this transaction"))
|
|
|
|
+ .with_label(ariadne::Label::new(tspan).with_message("this change differs from"))
|
|
|
|
+ .with_label(ariadne::Label::new(placeholder.source.unwrap()).with_message("in this transaction"))
|
|
|
|
+ .with_label(ariadne::Label::new(pspan).with_message("this change"))
|
|
|
|
+ .with_message("merged transactions differ in at least one change")
|
|
|
|
+ .finish();
|
|
|
|
+ return Err(report.into())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- */
|
|
|
|
}
|
|
}
|
|
|
|
+
|
|
Ok(())
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
|
|
@@ -221,6 +245,7 @@ pub fn run_checks(root: &mut data::Hoard, level: CheckLevel) -> Result<(), DataE
|
|
log::debug!("Running transaction well-formedness checks...");
|
|
log::debug!("Running transaction well-formedness checks...");
|
|
check_precision(root)?;
|
|
check_precision(root)?;
|
|
check_equal_sum(root)?;
|
|
check_equal_sum(root)?;
|
|
|
|
+ check_merge_groups(root)?;
|
|
}
|
|
}
|
|
if level >= CheckLevel::Consistent {
|
|
if level >= CheckLevel::Consistent {
|
|
log::debug!("Running ledger consistency checks...");
|
|
log::debug!("Running ledger consistency checks...");
|