diff options
author | John Wiegley <johnw@newartisans.com> | 2010-06-12 21:39:28 -0400 |
---|---|---|
committer | John Wiegley <johnw@newartisans.com> | 2010-06-13 01:03:48 -0400 |
commit | 8d2fce1ae8a1b8c3cce4e22d807421915a0001ce (patch) | |
tree | 6d71920ff303e3a70b6a2ae89b21a8c8e8372913 /src | |
parent | 5ec85538d9690634a2b1ee7c422e109700eb0627 (diff) | |
download | fork-ledger-8d2fce1ae8a1b8c3cce4e22d807421915a0001ce.tar.gz fork-ledger-8d2fce1ae8a1b8c3cce4e22d807421915a0001ce.tar.bz2 fork-ledger-8d2fce1ae8a1b8c3cce4e22d807421915a0001ce.zip |
Automated xacts may now contain "deferred tags"
For example, consider the following automated transaction:
= /Food/
; Next Date:: date + 10
(Expenses:Tax) 1.00
; Next Date:: date + 20
This will add a metadata field named 'Next Date' to the _matching
posting_, with a value that is 10 days later than that posting. It will
also generate a new posting for that transaction, whose amount is the
same as the matching posting. Further, it will add a 'Next Date'
metadata tag to the _generated posting_ whose value is 20 days later
than the date of the matching posting.
Diffstat (limited to 'src')
-rw-r--r-- | src/journal.cc | 10 | ||||
-rw-r--r-- | src/journal.h | 6 | ||||
-rw-r--r-- | src/textual.cc | 6 | ||||
-rw-r--r-- | src/xact.cc | 26 | ||||
-rw-r--r-- | src/xact.h | 28 |
5 files changed, 64 insertions, 12 deletions
diff --git a/src/journal.cc b/src/journal.cc index fd6d3eac..ed1e26be 100644 --- a/src/journal.cc +++ b/src/journal.cc @@ -105,7 +105,8 @@ account_t * journal_t::find_account_re(const string& regexp) return master->find_account_re(regexp); } -bool journal_t::add_xact(xact_t * xact) +bool journal_t::add_xact(xact_t * xact, + optional<date_t::year_type> current_year) { xact->journal = this; @@ -114,16 +115,17 @@ bool journal_t::add_xact(xact_t * xact) return false; } - extend_xact(xact); + extend_xact(xact, current_year); xacts.push_back(xact); return true; } -void journal_t::extend_xact(xact_base_t * xact) +void journal_t::extend_xact(xact_base_t * xact, + optional<date_t::year_type> current_year) { foreach (auto_xact_t * auto_xact, auto_xacts) - auto_xact->extend_xact(*xact); + auto_xact->extend_xact(*xact, current_year); } bool journal_t::remove_xact(xact_t * xact) diff --git a/src/journal.h b/src/journal.h index ca6b6e4f..183d074d 100644 --- a/src/journal.h +++ b/src/journal.h @@ -140,8 +140,10 @@ public: account_t * find_account(const string& name, bool auto_create = true); account_t * find_account_re(const string& regexp); - bool add_xact(xact_t * xact); - void extend_xact(xact_base_t * xact); + bool add_xact(xact_t * xact, + optional<date_t::year_type> current_year = none); + void extend_xact(xact_base_t * xact, + optional<date_t::year_type> current_year = none); bool remove_xact(xact_t * xact); xacts_list::iterator xacts_begin() { diff --git a/src/textual.cc b/src/textual.cc index 2e8b011f..4d133302 100644 --- a/src/textual.cc +++ b/src/textual.cc @@ -577,7 +577,7 @@ void instance_t::period_xact_directive(char * line) pe->journal = &context.journal; if (pe->finalize()) { - context.journal.extend_xact(pe.get()); + context.journal.extend_xact(pe.get(), current_year); context.journal.period_xacts.push_back(pe.get()); pe->pos->end_pos = curr_pos; @@ -1254,7 +1254,7 @@ post_t * instance_t::parse_post(char * line, foreach (const state_t& state, context.state_stack) if (state.type() == typeid(string)) post->parse_tags(boost::get<string>(state).c_str(), context.scope, - true); + true, current_year); } TRACE_STOP(post_details, 1); @@ -1426,7 +1426,7 @@ xact_t * instance_t::parse_xact(char * line, foreach (const state_t& state, context.state_stack) if (state.type() == typeid(string)) xact->parse_tags(boost::get<string>(state).c_str(), context.scope, - false); + false, current_year); } TRACE_STOP(xact_details, 1); diff --git a/src/xact.cc b/src/xact.cc index 3b66598c..77d87ae9 100644 --- a/src/xact.cc +++ b/src/xact.cc @@ -634,7 +634,8 @@ namespace { } // unnamed namespace -void auto_xact_t::extend_xact(xact_base_t& xact) +void auto_xact_t::extend_xact(xact_base_t& xact, + optional<date_t::year_type> current_year) { posts_list initial_posts(xact.posts.begin(), xact.posts.end()); @@ -679,6 +680,18 @@ void auto_xact_t::extend_xact(xact_base_t& xact) matches_predicate = predicate(*initial_post); } if (matches_predicate) { + bind_scope_t bound_scope(*scope_t::default_scope, *initial_post); + + if (deferred_notes) { + foreach (deferred_tag_data_t& data, *deferred_notes) { + if (data.apply_to_post == NULL) + initial_post->parse_tags(data.tag_data.c_str(), + bound_scope, + data.overwrite_existing, + current_year); + } + } + foreach (post_t * post, posts) { amount_t post_amount; if (post->amount.is_null()) { @@ -686,7 +699,6 @@ void auto_xact_t::extend_xact(xact_base_t& xact) throw_(amount_error, _("Automated transaction's posting has no amount")); - bind_scope_t bound_scope(*scope_t::default_scope, *initial_post); value_t result(post->amount_expr->calc(bound_scope)); if (result.is_long()) { post_amount = result.to_amount(); @@ -752,6 +764,16 @@ void auto_xact_t::extend_xact(xact_base_t& xact) if (new_post->must_balance()) needs_further_verification = true; + + if (deferred_notes) { + foreach (deferred_tag_data_t& data, *deferred_notes) { + if (data.apply_to_post == post) + new_post->parse_tags(data.tag_data.c_str(), + bound_scope, + data.overwrite_existing, + current_year); + } + } } } } @@ -150,6 +150,21 @@ public: std::map<string, bool> memoized_results; + struct deferred_tag_data_t { + string tag_data; + bool overwrite_existing; + post_t * apply_to_post; + + deferred_tag_data_t(string _tag_data, + bool _overwrite_existing) + : tag_data(_tag_data), overwrite_existing(_overwrite_existing), + apply_to_post(NULL) {} + }; + + typedef std::list<deferred_tag_data_t> deferred_notes_list; + + optional<deferred_notes_list> deferred_notes; + auto_xact_t() : try_quick_match(true) { TRACE_CTOR(auto_xact_t, ""); } @@ -168,7 +183,17 @@ public: TRACE_DTOR(auto_xact_t); } - virtual void extend_xact(xact_base_t& xact); + virtual void parse_tags(const char * p, + scope_t&, + bool overwrite_existing = true, + optional<date_t::year_type> = none) { + if (! deferred_notes) + deferred_notes = deferred_notes_list(); + deferred_notes->push_back(deferred_tag_data_t(p, overwrite_existing)); + } + + virtual void extend_xact(xact_base_t& xact, + optional<date_t::year_type> current_year); #if defined(HAVE_BOOST_SERIALIZATION) private: @@ -180,6 +205,7 @@ private: void serialize(Archive& ar, const unsigned int /* version */) { ar & boost::serialization::base_object<xact_base_t>(*this); ar & predicate; + ar & deferred_notes; } #endif // HAVE_BOOST_SERIALIZATION }; |