summaryrefslogtreecommitdiff
path: root/src/journal.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/journal.cc')
-rw-r--r--src/journal.cc67
1 files changed, 62 insertions, 5 deletions
diff --git a/src/journal.cc b/src/journal.cc
index 160abe06..804c9ee2 100644
--- a/src/journal.cc
+++ b/src/journal.cc
@@ -95,7 +95,7 @@ void journal_t::initialize()
force_checking = false;
check_payees = false;
day_break = false;
- checking_style = CHECK_PERMISSIVE;
+ checking_style = CHECK_NORMAL;
recursive_aliases = false;
}
@@ -363,6 +363,21 @@ namespace {
}
}
+bool lt_posting_account(post_t * left, post_t * right) {
+ return left->account < right->account;
+}
+
+bool is_equivalent_posting(post_t * left, post_t * right)
+{
+ if (left->account != right->account)
+ return false;
+
+ if (left->amount != right->amount)
+ return false;
+
+ return true;
+}
+
bool journal_t::add_xact(xact_t * xact)
{
xact->journal = this;
@@ -385,12 +400,54 @@ bool journal_t::add_xact(xact_t * xact)
// will have been performed by extend_xact, so asserts can still be
// applied to it.
if (optional<value_t> ref = xact->get_tag(_("UUID"))) {
+ std::string uuid = ref->to_string();
std::pair<checksum_map_t::iterator, bool> result
- = checksum_map.insert(checksum_map_t::value_type(ref->to_string(), xact));
+ = checksum_map.insert(checksum_map_t::value_type(uuid, xact));
if (! result.second) {
- // jww (2012-02-27): Confirm that the xact in
- // (*result.first).second is exact match in its significant
- // details to xact.
+ // This UUID has been seen before; apply any postings which the
+ // earlier version may have deferred.
+ foreach (post_t * post, xact->posts) {
+ account_t * acct = post->account;
+ if (acct->deferred_posts) {
+ auto i = acct->deferred_posts->find(uuid);
+ if (i != acct->deferred_posts->end()) {
+ for (post_t * rpost : (*i).second)
+ if (acct == rpost->account)
+ acct->add_post(rpost);
+ acct->deferred_posts->erase(i);
+ }
+ }
+ }
+
+ xact_t * other = (*result.first).second;
+
+ // Copy the two lists of postings (which should be relatively
+ // short), and make sure that the intersection is the empty set
+ // (i.e., that they are the same list).
+ std::vector<post_t *> this_posts(xact->posts.begin(),
+ xact->posts.end());
+ std::sort(this_posts.begin(), this_posts.end(),
+ lt_posting_account);
+ std::vector<post_t *> other_posts(other->posts.begin(),
+ other->posts.end());
+ std::sort(other_posts.begin(), other_posts.end(),
+ lt_posting_account);
+ bool match = std::equal(this_posts.begin(), this_posts.end(),
+ other_posts.begin(), is_equivalent_posting);
+
+ if (! match || this_posts.size() != other_posts.size()) {
+ add_error_context(_("While comparing this previously seen transaction:"));
+ add_error_context(source_context(other->pos->pathname,
+ other->pos->beg_pos,
+ other->pos->end_pos, "> "));
+ add_error_context(_("to this later transaction:"));
+ add_error_context(source_context(xact->pos->pathname,
+ xact->pos->beg_pos,
+ xact->pos->end_pos, "> "));
+ throw_(std::runtime_error,
+ _f("Transactions with the same UUID must have equivalent postings"));
+ }
+
xact->journal = NULL;
return false;
}