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.
This commit is contained in:
parent
7e2547b1e4
commit
5da1e7756d
7 changed files with 89 additions and 1 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
0
test/baseline/opt-inject.test
Normal file
0
test/baseline/opt-inject.test
Normal file
Loading…
Add table
Reference in a new issue