diff options
author | John Wiegley <johnw@newartisans.com> | 2010-06-18 02:26:50 -0400 |
---|---|---|
committer | John Wiegley <johnw@newartisans.com> | 2010-06-18 02:28:12 -0400 |
commit | 5da1e7756d2a4eb04753b8a97bc00063b4d3f687 (patch) | |
tree | 66798448f6a0cde13b434a28465c734d39a7a6cd | |
parent | 7e2547b1e4c5b6e940506ddff80e8871ada029ea (diff) | |
download | fork-ledger-5da1e7756d2a4eb04753b8a97bc00063b4d3f687.tar.gz fork-ledger-5da1e7756d2a4eb04753b8a97bc00063b4d3f687.tar.bz2 fork-ledger-5da1e7756d2a4eb04753b8a97bc00063b4d3f687.zip |
Added new option --inject=KEY[,KEY...]
If you have a typed metadata key which contains an amount, you can use
--inject=KEY to inject a posting with that amount wherever a match
occurs. There are two main forms of usage:
2010-06-18 Sample
; Key:: $100
Expenses:Food $100.00
Assets:Checking
The command would be:
ledger reg --inject=Key
In the above, transactional form, a posting under the account "Key" will
be injected before the first posting reported for this transaction.
It's amount will be $100. This only happens once for the whole
transaction.
It is also possible to associate the key with a posting:
2010-06-18 Sample
Expenses:Food $100.00
; Key:: $100
Assets:Checking
Now the injected posting is generated whenever that particular post is
reported.
-rw-r--r-- | doc/ledger.1 | 3 | ||||
-rw-r--r-- | src/chain.cc | 4 | ||||
-rw-r--r-- | src/filters.cc | 60 | ||||
-rw-r--r-- | src/filters.h | 20 | ||||
-rw-r--r-- | src/report.cc | 1 | ||||
-rw-r--r-- | src/report.h | 2 | ||||
-rw-r--r-- | test/baseline/opt-inject.test | 0 |
7 files changed, 89 insertions, 1 deletions
diff --git a/doc/ledger.1 b/doc/ledger.1 index 4e72c792..ba4317f9 100644 --- a/doc/ledger.1 +++ b/doc/ledger.1 @@ -1,4 +1,4 @@ -.Dd June 15, 2010 +.Dd June 18, 2010 .Dt ledger 1 .Sh NAME .Nm ledger @@ -336,6 +336,7 @@ See .It Fl \-help-disp .It Fl \-import Ar STR .It Fl \-init-file Ar FILE +.It Fl \-inject Ar STR .It Fl \-input-date-format Ar DATEFMT .It Fl \-invert .It Fl \-last Ar INT diff --git a/src/chain.cc b/src/chain.cc index 64550663..8010ba74 100644 --- a/src/chain.cc +++ b/src/chain.cc @@ -258,6 +258,10 @@ post_handler_ptr chain_post_handlers(post_handler_ptr base_handler, if (report.HANDLED(related)) handler.reset(new related_posts(handler, report.HANDLED(related_all))); + if (report.HANDLED(inject_)) + handler.reset(new inject_posts(handler, report.HANDLED(inject_).str(), + report.session.journal->master)); + return handler; } diff --git a/src/filters.cc b/src/filters.cc index 6e832149..33905856 100644 --- a/src/filters.cc +++ b/src/filters.cc @@ -1338,6 +1338,66 @@ void forecast_posts::flush() item_handler<post_t>::flush(); } +inject_posts::inject_posts(post_handler_ptr handler, + const string& tag_list, + account_t * master) + : item_handler<post_t>(handler) +{ + TRACE_CTOR(inject_posts, "post_handler_ptr, string"); + + scoped_array<char> buf(new char[tag_list.length() + 1]); + std::strcpy(buf.get(), tag_list.c_str()); + + for (char * q = std::strtok(buf.get(), ","); + q; + q = std::strtok(NULL, ",")) { + + std::list<string> account_names; + split_string(q, ':', account_names); + account_t * account = + create_temp_account_from_path(account_names, temps, master); + account->add_flags(ACCOUNT_GENERATED); + + tags_list.push_back + (tags_list_pair(q, tag_mapping_pair(account, tag_injected_set()))); + } +} + +void inject_posts::operator()(post_t& post) +{ + foreach (tags_list_pair& pair, tags_list) { + optional<value_t> tag_value = post.get_tag(pair.first, false); + if (! tag_value && + pair.second.second.find(post.xact) == pair.second.second.end()) { + // When checking if the transaction has the tag, only inject once + // per transaction. + pair.second.second.insert(post.xact); + tag_value = post.xact->get_tag(pair.first); + } + + if (tag_value) { + if (tag_value->is_amount()) { + xact_t& xact = temps.copy_xact(*post.xact); + xact._date = post.date(); + xact.add_flags(ITEM_GENERATED); + post_t& temp = temps.copy_post(post, xact); + + temp.account = pair.second.first; + temp.amount = tag_value->as_amount(); + temp.add_flags(ITEM_GENERATED); + + item_handler<post_t>::operator()(temp); + } else { + throw_(std::logic_error, + _("Attempt to inject a posting with non-amount %1 for tag %2") + << *tag_value << pair.first); + } + } + } + + item_handler<post_t>::operator()(post); +} + pass_down_accounts::pass_down_accounts(acct_handler_ptr handler, accounts_iterator& iter, const optional<predicate_t>& _pred, diff --git a/src/filters.h b/src/filters.h index 9102d4f1..180253d2 100644 --- a/src/filters.h +++ b/src/filters.h @@ -929,6 +929,26 @@ class forecast_posts : public generate_posts } }; +class inject_posts : public item_handler<post_t> +{ + typedef std::set<xact_t *> tag_injected_set; + typedef std::pair<account_t *, tag_injected_set> tag_mapping_pair; + typedef std::pair<string, tag_mapping_pair> tags_list_pair; + + std::list<tags_list_pair> tags_list; + temporaries_t temps; + + public: + inject_posts(post_handler_ptr handler, const string& tag_list, + account_t * master); + + virtual ~inject_posts() throw() { + TRACE_DTOR(inject_posts); + } + + virtual void operator()(post_t& post); +}; + ////////////////////////////////////////////////////////////////////// // // Account filters diff --git a/src/report.cc b/src/report.cc index 9626283a..da7c11f5 100644 --- a/src/report.cc +++ b/src/report.cc @@ -955,6 +955,7 @@ option_t<report_t> * report_t::lookup_option(const char * p) break; case 'i': OPT(invert); + else OPT(inject_); break; case 'j': OPT_CH(amount_data); diff --git a/src/report.h b/src/report.h index a453d351..7d725b8c 100644 --- a/src/report.h +++ b/src/report.h @@ -260,6 +260,7 @@ public: HANDLER(group_by_).report(out); HANDLER(group_title_format_).report(out); HANDLER(head_).report(out); + HANDLER(inject_).report(out); HANDLER(invert).report(out); HANDLER(limit_).report(out); HANDLER(lot_dates).report(out); @@ -616,6 +617,7 @@ public: }); OPTION(report_t, head_); + OPTION(report_t, inject_); OPTION_(report_t, invert, DO() { parent->HANDLER(amount_).set_expr(string("--invert"), "-amount"); diff --git a/test/baseline/opt-inject.test b/test/baseline/opt-inject.test new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/test/baseline/opt-inject.test |