Fixed a problem in the 'entry' command
It was selecting virtual transactions during auto-posting lookup. Fixes 793F6BF0-9CDE-4741-967A-2CEA697476B4
This commit is contained in:
parent
ec9745161e
commit
3c692a94d4
2 changed files with 155 additions and 30 deletions
129
src/derive.cc
129
src/derive.cc
|
|
@ -240,28 +240,30 @@ namespace {
|
||||||
report_t& report)
|
report_t& report)
|
||||||
{
|
{
|
||||||
if (tmpl.payee_mask.empty())
|
if (tmpl.payee_mask.empty())
|
||||||
throw std::runtime_error(_("'xact' command requires at least a payee"));
|
throw std::runtime_error(_("xact' command requires at least a payee"));
|
||||||
|
|
||||||
xact_t * matching = NULL;
|
xact_t * matching = NULL;
|
||||||
journal_t& journal(*report.session.journal.get());
|
journal_t& journal(*report.session.journal.get());
|
||||||
|
|
||||||
std::auto_ptr<xact_t> added(new xact_t);
|
std::auto_ptr<xact_t> added(new xact_t);
|
||||||
|
|
||||||
xacts_list::reverse_iterator j;
|
for (xacts_list::reverse_iterator j = journal.xacts.rbegin();
|
||||||
|
|
||||||
for (j = journal.xacts.rbegin();
|
|
||||||
j != journal.xacts.rend();
|
j != journal.xacts.rend();
|
||||||
j++) {
|
j++) {
|
||||||
if (tmpl.payee_mask.match((*j)->payee)) {
|
if (tmpl.payee_mask.match((*j)->payee)) {
|
||||||
matching = *j;
|
matching = *j;
|
||||||
|
DEBUG("derive.xact",
|
||||||
|
"Found payee match: transaction on line " << (*j)->beg_line);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! tmpl.date)
|
if (! tmpl.date) {
|
||||||
added->_date = CURRENT_DATE();
|
added->_date = CURRENT_DATE();
|
||||||
else
|
DEBUG("derive.xact", "Setting date to current date");
|
||||||
|
} else {
|
||||||
added->_date = tmpl.date;
|
added->_date = tmpl.date;
|
||||||
|
DEBUG("derive.xact", "Setting date to template date: " << *tmpl.date);
|
||||||
|
}
|
||||||
|
|
||||||
added->set_state(item_t::UNCLEARED);
|
added->set_state(item_t::UNCLEARED);
|
||||||
|
|
||||||
|
|
@ -269,17 +271,30 @@ namespace {
|
||||||
added->payee = matching->payee;
|
added->payee = matching->payee;
|
||||||
added->code = matching->code;
|
added->code = matching->code;
|
||||||
added->note = matching->note;
|
added->note = matching->note;
|
||||||
|
|
||||||
|
DEBUG("derive.xact", "Setting payee from match: " << added->payee);
|
||||||
|
if (added->code)
|
||||||
|
DEBUG("derive.xact", "Setting code from match: " << *added->code);
|
||||||
|
if (added->note)
|
||||||
|
DEBUG("derive.xact", "Setting note from match: " << *added->note);
|
||||||
} else {
|
} else {
|
||||||
added->payee = tmpl.payee_mask.expr.str();
|
added->payee = tmpl.payee_mask.expr.str();
|
||||||
|
DEBUG("derive.xact", "Setting payee from template: " << added->payee);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tmpl.code)
|
if (tmpl.code) {
|
||||||
added->code = tmpl.code;
|
added->code = tmpl.code;
|
||||||
if (tmpl.note)
|
DEBUG("derive.xact", "Now setting code from template: " << *added->code);
|
||||||
|
}
|
||||||
|
if (tmpl.note) {
|
||||||
added->note = tmpl.note;
|
added->note = tmpl.note;
|
||||||
|
DEBUG("derive.xact", "Now setting note from template: " << *added->note);
|
||||||
|
}
|
||||||
|
|
||||||
if (tmpl.posts.empty()) {
|
if (tmpl.posts.empty()) {
|
||||||
if (matching) {
|
if (matching) {
|
||||||
|
DEBUG("derive.xact", "Template had no postings, copying from match");
|
||||||
|
|
||||||
foreach (post_t * post, matching->posts) {
|
foreach (post_t * post, matching->posts) {
|
||||||
added->add_post(new post_t(*post));
|
added->add_post(new post_t(*post));
|
||||||
added->posts.back()->set_state(item_t::UNCLEARED);
|
added->posts.back()->set_state(item_t::UNCLEARED);
|
||||||
|
|
@ -290,9 +305,12 @@ namespace {
|
||||||
<< tmpl.payee_mask);
|
<< tmpl.payee_mask);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
DEBUG("derive.xact", "Template had postings");
|
||||||
|
|
||||||
bool any_post_has_amount = false;
|
bool any_post_has_amount = false;
|
||||||
foreach (xact_template_t::post_template_t& post, tmpl.posts) {
|
foreach (xact_template_t::post_template_t& post, tmpl.posts) {
|
||||||
if (post.amount) {
|
if (post.amount) {
|
||||||
|
DEBUG("derive.xact", " and at least one has an amount specified");
|
||||||
any_post_has_amount = true;
|
any_post_has_amount = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -305,90 +323,145 @@ namespace {
|
||||||
|
|
||||||
if (matching) {
|
if (matching) {
|
||||||
if (post.account_mask) {
|
if (post.account_mask) {
|
||||||
|
DEBUG("derive.xact",
|
||||||
|
"Looking for matching posting based on account mask");
|
||||||
|
|
||||||
foreach (post_t * x, matching->posts) {
|
foreach (post_t * x, matching->posts) {
|
||||||
if (post.account_mask->match(x->account->fullname())) {
|
if (post.account_mask->match(x->account->fullname())) {
|
||||||
new_post.reset(new post_t(*x));
|
new_post.reset(new post_t(*x));
|
||||||
|
DEBUG("derive.xact",
|
||||||
|
"Founding posting from line " << x->beg_line);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (post.from)
|
if (post.from) {
|
||||||
new_post.reset(new post_t(*matching->posts.back()));
|
for (posts_list::reverse_iterator j = matching->posts.rbegin();
|
||||||
else
|
j != matching->posts.rend();
|
||||||
new_post.reset(new post_t(*matching->posts.front()));
|
j++) {
|
||||||
|
if ((*j)->must_balance()) {
|
||||||
|
new_post.reset(new post_t(**j));
|
||||||
|
DEBUG("derive.xact",
|
||||||
|
"Copied last real posting from matching");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (posts_list::iterator j = matching->posts.begin();
|
||||||
|
j != matching->posts.end();
|
||||||
|
j++) {
|
||||||
|
if ((*j)->must_balance()) {
|
||||||
|
new_post.reset(new post_t(**j));
|
||||||
|
DEBUG("derive.xact",
|
||||||
|
"Copied first real posting from matching");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! new_post.get())
|
if (! new_post.get()) {
|
||||||
new_post.reset(new post_t);
|
new_post.reset(new post_t);
|
||||||
|
DEBUG("derive.xact", "New posting was NULL, creating a blank one");
|
||||||
|
}
|
||||||
|
|
||||||
if (! new_post->account) {
|
if (! new_post->account) {
|
||||||
|
DEBUG("derive.xact", "New posting still needs an account");
|
||||||
|
|
||||||
if (post.account_mask) {
|
if (post.account_mask) {
|
||||||
|
DEBUG("derive.xact", "The template has an account mask");
|
||||||
|
|
||||||
account_t * acct = NULL;
|
account_t * acct = NULL;
|
||||||
if (! acct)
|
if (! acct) {
|
||||||
acct = journal.find_account_re(post.account_mask->expr.str());
|
acct = journal.find_account_re(post.account_mask->expr.str());
|
||||||
if (! acct)
|
if (acct)
|
||||||
|
DEBUG("derive.xact", "Found account as a regular expression");
|
||||||
|
}
|
||||||
|
if (! acct) {
|
||||||
acct = journal.find_account(post.account_mask->expr.str());
|
acct = journal.find_account(post.account_mask->expr.str());
|
||||||
|
if (acct)
|
||||||
|
DEBUG("derive.xact", "Found (or created) account by name");
|
||||||
|
}
|
||||||
|
|
||||||
// Find out the default commodity to use by looking at the last
|
// Find out the default commodity to use by looking at the last
|
||||||
// commodity used in that account
|
// commodity used in that account
|
||||||
xacts_list::reverse_iterator j;
|
for (xacts_list::reverse_iterator j = journal.xacts.rbegin();
|
||||||
|
|
||||||
for (j = journal.xacts.rbegin();
|
|
||||||
j != journal.xacts.rend();
|
j != journal.xacts.rend();
|
||||||
j++) {
|
j++) {
|
||||||
foreach (post_t * x, (*j)->posts) {
|
foreach (post_t * x, (*j)->posts) {
|
||||||
if (x->account == acct && ! x->amount.is_null()) {
|
if (x->account == acct && ! x->amount.is_null()) {
|
||||||
new_post.reset(new post_t(*x));
|
new_post.reset(new post_t(*x));
|
||||||
|
DEBUG("derive.xact",
|
||||||
|
"Found account in journal postings, setting new posting");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (! new_post.get())
|
|
||||||
new_post.reset(new post_t);
|
|
||||||
|
|
||||||
new_post->account = acct;
|
new_post->account = acct;
|
||||||
|
DEBUG("derive.xact",
|
||||||
|
"Set new posting's account to: " << acct->fullname());
|
||||||
} else {
|
} else {
|
||||||
|
if (post.from) {
|
||||||
if (post.from)
|
|
||||||
new_post->account = journal.find_account(_("Liabilities:Unknown"));
|
new_post->account = journal.find_account(_("Liabilities:Unknown"));
|
||||||
else
|
DEBUG("derive.xact",
|
||||||
|
"Set new posting's account to: Liabilities:Unknown");
|
||||||
|
} else {
|
||||||
new_post->account = journal.find_account(_("Expenses:Unknown"));
|
new_post->account = journal.find_account(_("Expenses:Unknown"));
|
||||||
|
DEBUG("derive.xact",
|
||||||
|
"Set new posting's account to: Expenses:Unknown");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (new_post.get() && ! new_post->amount.is_null()) {
|
if (new_post.get() && ! new_post->amount.is_null()) {
|
||||||
found_commodity = &new_post->amount.commodity();
|
found_commodity = &new_post->amount.commodity();
|
||||||
|
|
||||||
if (any_post_has_amount)
|
if (any_post_has_amount) {
|
||||||
new_post->amount = amount_t();
|
new_post->amount = amount_t();
|
||||||
else
|
DEBUG("derive.xact", "New posting has an amount, but we cleared it");
|
||||||
|
} else {
|
||||||
any_post_has_amount = true;
|
any_post_has_amount = true;
|
||||||
|
DEBUG("derive.xact", "New posting has an amount, and we're using it");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (post.amount) {
|
if (post.amount) {
|
||||||
new_post->amount = *post.amount;
|
new_post->amount = *post.amount;
|
||||||
if (post.from)
|
DEBUG("derive.xact", "Copied over posting amount");
|
||||||
|
|
||||||
|
if (post.from) {
|
||||||
new_post->amount.in_place_negate();
|
new_post->amount.in_place_negate();
|
||||||
|
DEBUG("derive.xact", "Negated new posting amount");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (found_commodity &&
|
if (found_commodity &&
|
||||||
! new_post->amount.is_null() &&
|
! new_post->amount.is_null() &&
|
||||||
! new_post->amount.has_commodity()) {
|
! new_post->amount.has_commodity()) {
|
||||||
new_post->amount.set_commodity(*found_commodity);
|
new_post->amount.set_commodity(*found_commodity);
|
||||||
|
DEBUG("derive.xact", "Set posting amount commodity to: "
|
||||||
|
<< new_post->amount.commodity());
|
||||||
|
|
||||||
new_post->amount = new_post->amount.rounded();
|
new_post->amount = new_post->amount.rounded();
|
||||||
|
DEBUG("derive.xact",
|
||||||
|
"Rounded posting amount to: " << new_post->amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
added->add_post(new_post.release());
|
added->add_post(new_post.release());
|
||||||
added->posts.back()->set_state(item_t::UNCLEARED);
|
added->posts.back()->set_state(item_t::UNCLEARED);
|
||||||
|
|
||||||
|
DEBUG("derive.xact", "Added new posting to derived entry");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! journal.xact_finalize_hooks.run_hooks(*added.get(), false) ||
|
if (! journal.xact_finalize_hooks.run_hooks(*added.get(), false) ||
|
||||||
! added->finalize() ||
|
! added->finalize() ||
|
||||||
! journal.xact_finalize_hooks.run_hooks(*added.get(), true))
|
! journal.xact_finalize_hooks.run_hooks(*added.get(), true)) {
|
||||||
throw_(std::runtime_error,
|
throw_(std::runtime_error,
|
||||||
_("Failed to finalize derived transaction (check commodities)"));
|
_("Failed to finalize derived transaction (check commodities)"));
|
||||||
|
}
|
||||||
|
|
||||||
return added.release();
|
return added.release();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
52
test/regress/793F6BF0.test
Normal file
52
test/regress/793F6BF0.test
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
entry 2009/03/15 book 10
|
||||||
|
<<<
|
||||||
|
N $
|
||||||
|
|
||||||
|
= account =~ /^Expenses:Books/
|
||||||
|
(Liabilities:Taxes) -0.10
|
||||||
|
|
||||||
|
~ Monthly
|
||||||
|
Assets:Bank:Checking $500.00
|
||||||
|
Income:Salary
|
||||||
|
|
||||||
|
2004/05/01 * Checking balance
|
||||||
|
Assets:Bank:Checking $1,000.00
|
||||||
|
Equity:Opening Balances
|
||||||
|
|
||||||
|
2004/05/03=2004/05/01 * Investment balance
|
||||||
|
Assets:Brokerage 50 AAPL @ $30.00
|
||||||
|
Equity:Opening Balances
|
||||||
|
|
||||||
|
2004/05/14 * Páy dày
|
||||||
|
Assets:Bank:Checking 500.00€
|
||||||
|
Income:Salary
|
||||||
|
|
||||||
|
2004/05/14 * Another dày in which there is Páying
|
||||||
|
Asséts:Bánk:Chécking:Asséts:Bánk:Chécking $500.00
|
||||||
|
Income:Salary
|
||||||
|
|
||||||
|
2004/05/14 * Another dày in which there is Páying
|
||||||
|
Русский язык:Русский язык:Русский язык:Русский язык $1000.00
|
||||||
|
Income:Salary
|
||||||
|
|
||||||
|
2004/05/27 Book Store
|
||||||
|
Expenses:Books $20.00
|
||||||
|
Expenses:Cards $40.00
|
||||||
|
Expenses:Docs $30.00
|
||||||
|
Liabilities:MasterCard
|
||||||
|
|
||||||
|
2004/05/27 (100) Credit card company
|
||||||
|
; This is an xact note!
|
||||||
|
; Sample: Value
|
||||||
|
Liabilities:MasterCard $20.00
|
||||||
|
; This is a posting note!
|
||||||
|
; Sample: Another Value
|
||||||
|
; :MyTag:
|
||||||
|
Assets:Bank:Checking
|
||||||
|
; :AnotherTag:
|
||||||
|
>>>1
|
||||||
|
2009/03/15 Book Store
|
||||||
|
Expenses:Books $10.00
|
||||||
|
Liabilities:MasterCard
|
||||||
|
>>>2
|
||||||
|
=== 0
|
||||||
Loading…
Add table
Reference in a new issue