summaryrefslogtreecommitdiff
path: root/src/xact.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/xact.cc')
-rw-r--r--src/xact.cc468
1 files changed, 234 insertions, 234 deletions
diff --git a/src/xact.cc b/src/xact.cc
index d943e611..b4438b48 100644
--- a/src/xact.cc
+++ b/src/xact.cc
@@ -101,9 +101,9 @@ value_t xact_base_t::magnitude() const
foreach (const post_t * post, posts) {
if (post->amount.sign() > 0) {
if (post->cost)
- halfbal += *post->cost;
+ halfbal += *post->cost;
else
- halfbal += post->amount;
+ halfbal += post->amount;
}
}
return halfbal;
@@ -126,30 +126,30 @@ bool xact_base_t::finalize()
if (! p.is_null()) {
DEBUG("xact.finalize", "post must balance = " << p.reduced());
if (! post->cost && post->amount.has_annotation() &&
- post->amount.annotation().price) {
- // If the amount has no cost, but is annotated with a per-unit
- // price, use the price times the amount as the cost
- post->cost = (*post->amount.annotation().price *
- post->amount).unrounded();
- DEBUG("xact.finalize",
- "annotation price = " << *post->amount.annotation().price);
- DEBUG("xact.finalize", "amount = " << post->amount);
- DEBUG("xact.finalize", "priced cost = " << *post->cost);
- post->add_flags(POST_COST_CALCULATED);
- add_or_set_value(balance, post->cost->rounded().reduced());
+ post->amount.annotation().price) {
+ // If the amount has no cost, but is annotated with a per-unit
+ // price, use the price times the amount as the cost
+ post->cost = (*post->amount.annotation().price *
+ post->amount).unrounded();
+ DEBUG("xact.finalize",
+ "annotation price = " << *post->amount.annotation().price);
+ DEBUG("xact.finalize", "amount = " << post->amount);
+ DEBUG("xact.finalize", "priced cost = " << *post->cost);
+ post->add_flags(POST_COST_CALCULATED);
+ add_or_set_value(balance, post->cost->rounded().reduced());
} else {
- // If the amount was a cost, it very likely has the "keep_precision"
- // flag set, meaning commodity display precision is ignored when
- // displaying the amount. We never want this set for the balance,
- // so we must clear the flag in a temporary to avoid it propagating
- // into the balance.
- add_or_set_value(balance, p.keep_precision() ?
- p.rounded().reduced() : p.reduced());
+ // If the amount was a cost, it very likely has the "keep_precision"
+ // flag set, meaning commodity display precision is ignored when
+ // displaying the amount. We never want this set for the balance,
+ // so we must clear the flag in a temporary to avoid it propagating
+ // into the balance.
+ add_or_set_value(balance, p.keep_precision() ?
+ p.rounded().reduced() : p.reduced());
}
}
else if (null_post) {
throw_(std::logic_error,
- _("Only one posting with null amount allowed per transaction"));
+ _("Only one posting with null amount allowed per transaction"));
}
else {
null_post = post;
@@ -162,7 +162,7 @@ bool xact_base_t::finalize()
DEBUG("xact.finalize", "balance is " << balance.label());
if (balance.is_balance())
DEBUG("xact.finalize", "balance commodity count = "
- << balance.as_balance().amounts.size());
+ << balance.as_balance().amounts.size());
#endif
// If there is only one post, balance against the default account if one has
@@ -188,15 +188,15 @@ bool xact_base_t::finalize()
foreach (post_t * post, posts) {
if (! post->amount.is_null() && post->must_balance()) {
- if (post->amount.has_annotation())
- top_post = post;
- else if (! top_post)
- top_post = post;
+ if (post->amount.has_annotation())
+ top_post = post;
+ else if (! top_post)
+ top_post = post;
}
if (post->cost && ! post->has_flags(POST_COST_CALCULATED)) {
- saw_cost = true;
- break;
+ saw_cost = true;
+ break;
}
}
@@ -211,58 +211,58 @@ bool xact_base_t::finalize()
const amount_t * y = &(*a++).second;
if (x->commodity() != top_post->amount.commodity()) {
- const amount_t * t = x;
- x = y;
- y = t;
+ const amount_t * t = x;
+ x = y;
+ y = t;
}
if (*x && *y) {
- DEBUG("xact.finalize", "primary amount = " << *x);
- DEBUG("xact.finalize", "secondary amount = " << *y);
-
- commodity_t& comm(x->commodity());
- amount_t per_unit_cost;
- amount_t total_cost;
- const amount_t * prev_y = y;
-
- foreach (post_t * post, posts) {
- if (post != top_post && post->must_balance() &&
- ! post->amount.is_null() &&
- post->amount.has_annotation() &&
- post->amount.annotation().price) {
- amount_t temp = *post->amount.annotation().price * post->amount;
- if (total_cost.is_null()) {
- total_cost = temp;
- y = &total_cost;
- }
- else if (total_cost.commodity() == temp.commodity()) {
- total_cost += temp;
- }
- else {
- DEBUG("xact.finalize",
- "multiple price commodities, aborting price calc");
- y = prev_y;
- break;
- }
- DEBUG("xact.finalize", "total_cost = " << total_cost);
- }
- }
- per_unit_cost = (*y / *x).abs().unrounded();
-
- DEBUG("xact.finalize", "per_unit_cost = " << per_unit_cost);
-
- foreach (post_t * post, posts) {
- const amount_t& amt(post->amount);
-
- if (post->must_balance() && amt.commodity() == comm) {
- balance -= amt;
- post->cost = per_unit_cost * amt;
- post->add_flags(POST_COST_CALCULATED);
- balance += *post->cost;
-
- DEBUG("xact.finalize", "set post->cost to = " << *post->cost);
- }
- }
+ DEBUG("xact.finalize", "primary amount = " << *x);
+ DEBUG("xact.finalize", "secondary amount = " << *y);
+
+ commodity_t& comm(x->commodity());
+ amount_t per_unit_cost;
+ amount_t total_cost;
+ const amount_t * prev_y = y;
+
+ foreach (post_t * post, posts) {
+ if (post != top_post && post->must_balance() &&
+ ! post->amount.is_null() &&
+ post->amount.has_annotation() &&
+ post->amount.annotation().price) {
+ amount_t temp = *post->amount.annotation().price * post->amount;
+ if (total_cost.is_null()) {
+ total_cost = temp;
+ y = &total_cost;
+ }
+ else if (total_cost.commodity() == temp.commodity()) {
+ total_cost += temp;
+ }
+ else {
+ DEBUG("xact.finalize",
+ "multiple price commodities, aborting price calc");
+ y = prev_y;
+ break;
+ }
+ DEBUG("xact.finalize", "total_cost = " << total_cost);
+ }
+ }
+ per_unit_cost = (*y / *x).abs().unrounded();
+
+ DEBUG("xact.finalize", "per_unit_cost = " << per_unit_cost);
+
+ foreach (post_t * post, posts) {
+ const amount_t& amt(post->amount);
+
+ if (post->must_balance() && amt.commodity() == comm) {
+ balance -= amt;
+ post->cost = per_unit_cost * amt;
+ post->add_flags(POST_COST_CALCULATED);
+ balance += *post->cost;
+
+ DEBUG("xact.finalize", "set post->cost to = " << *post->cost);
+ }
+ }
}
}
}
@@ -275,39 +275,39 @@ bool xact_base_t::finalize()
if (post->amount.commodity() == post->cost->commodity())
throw_(balance_error,
- _("A posting's cost must be of a different commodity than its amount"));
+ _("A posting's cost must be of a different commodity than its amount"));
cost_breakdown_t breakdown =
commodity_pool_t::current_pool->exchange
(post->amount, *post->cost, false,
- datetime_t(date(), time_duration(0, 0, 0, 0)));
+ datetime_t(date(), time_duration(0, 0, 0, 0)));
if (post->amount.has_annotation() &&
- breakdown.basis_cost.commodity() == breakdown.final_cost.commodity()) {
+ breakdown.basis_cost.commodity() == breakdown.final_cost.commodity()) {
if (amount_t gain_loss = breakdown.basis_cost - breakdown.final_cost) {
- DEBUG("xact.finalize", "gain_loss = " << gain_loss);
- gain_loss.in_place_round();
- DEBUG("xact.finalize", "gain_loss rounds to = " << gain_loss);
-
- if (post->must_balance())
- add_or_set_value(balance, gain_loss.reduced());
-
- account_t * account;
- if (gain_loss.sign() > 0)
- account = journal->find_account(_("Equity:Capital Gains"));
- else
- account = journal->find_account(_("Equity:Capital Losses"));
-
- post_t * p = new post_t(account, gain_loss, ITEM_GENERATED);
- p->set_state(post->state());
- if (post->has_flags(POST_VIRTUAL)) {
- DEBUG("xact.finalize", "gain_loss came from a virtual post");
- p->add_flags(post->flags() & (POST_VIRTUAL | POST_MUST_BALANCE));
- }
- add_post(p);
- DEBUG("xact.finalize", "added gain_loss, balance = " << balance);
+ DEBUG("xact.finalize", "gain_loss = " << gain_loss);
+ gain_loss.in_place_round();
+ DEBUG("xact.finalize", "gain_loss rounds to = " << gain_loss);
+
+ if (post->must_balance())
+ add_or_set_value(balance, gain_loss.reduced());
+
+ account_t * account;
+ if (gain_loss.sign() > 0)
+ account = journal->find_account(_("Equity:Capital Gains"));
+ else
+ account = journal->find_account(_("Equity:Capital Losses"));
+
+ post_t * p = new post_t(account, gain_loss, ITEM_GENERATED);
+ p->set_state(post->state());
+ if (post->has_flags(POST_VIRTUAL)) {
+ DEBUG("xact.finalize", "gain_loss came from a virtual post");
+ p->add_flags(post->flags() & (POST_VIRTUAL | POST_MUST_BALANCE));
+ }
+ add_post(p);
+ DEBUG("xact.finalize", "added gain_loss, balance = " << balance);
} else {
- DEBUG("xact.finalize", "gain_loss would have display as zero");
+ DEBUG("xact.finalize", "gain_loss would have display as zero");
}
} else {
post->amount = breakdown.amount;
@@ -315,7 +315,7 @@ bool xact_base_t::finalize()
}
if (post->has_flags(POST_COST_FIXATED) &&
- post->amount.has_annotation() && post->amount.annotation().price) {
+ post->amount.has_annotation() && post->amount.annotation().price) {
DEBUG("xact.finalize", "fixating annotation price");
post->amount.annotation().add_flags(ANNOTATION_PRICE_FIXATED);
}
@@ -332,16 +332,16 @@ bool xact_base_t::finalize()
bool first = true;
const balance_t& bal(balance.as_balance());
foreach (const balance_t::amounts_map::value_type& pair, bal.amounts) {
- if (first) {
- null_post->amount = pair.second.negated();
- null_post->add_flags(POST_CALCULATED);
- first = false;
- } else {
- post_t * p = new post_t(null_post->account, pair.second.negated(),
- ITEM_GENERATED | POST_CALCULATED);
- p->set_state(null_post->state());
- add_post(p);
- }
+ if (first) {
+ null_post->amount = pair.second.negated();
+ null_post->add_flags(POST_CALCULATED);
+ first = false;
+ } else {
+ post_t * p = new post_t(null_post->account, pair.second.negated(),
+ ITEM_GENERATED | POST_CALCULATED);
+ p->set_state(null_post->state());
+ add_post(p);
+ }
}
}
else if (balance.is_amount()) {
@@ -377,10 +377,10 @@ bool xact_base_t::finalize()
foreach (post_t * post, posts) {
if (! post->amount.is_null()) {
- all_null = false;
- post->amount.in_place_reduce();
+ all_null = false;
+ post->amount.in_place_reduce();
} else {
- some_null = true;
+ some_null = true;
}
post->account->add_post(post);
@@ -390,10 +390,10 @@ bool xact_base_t::finalize()
}
if (all_null)
- return false; // ignore this xact completely
+ return false; // ignore this xact completely
else if (some_null)
throw_(balance_error,
- _("There cannot be null amounts after balancing a transaction"));
+ _("There cannot be null amounts after balancing a transaction"));
}
VERIFY(valid());
@@ -419,7 +419,7 @@ bool xact_base_t::verify()
// amount. We never want this set for the balance, so we must clear the
// flag in a temporary to avoid it propagating into the balance.
add_or_set_value(balance, p.keep_precision() ?
- p.rounded().reduced() : p.reduced());
+ p.rounded().reduced() : p.reduced());
}
VERIFY(balance.valid());
@@ -433,7 +433,7 @@ bool xact_base_t::verify()
if (post->amount.commodity() == post->cost->commodity())
throw_(amount_error,
- _("A posting's cost must be of a different commodity than its amount"));
+ _("A posting's cost must be of a different commodity than its amount"));
}
if (! balance.is_null() && ! balance.is_zero()) {
@@ -513,7 +513,7 @@ namespace {
foreach (post_t * p, post.xact->posts) {
bind_scope_t bound_scope(scope, *p);
if (expr.calc(bound_scope).to_boolean())
- return true;
+ return true;
}
return false;
}
@@ -528,14 +528,14 @@ namespace {
foreach (post_t * p, post.xact->posts) {
bind_scope_t bound_scope(scope, *p);
if (! expr.calc(bound_scope).to_boolean())
- return false;
+ return false;
}
return true;
}
}
expr_t::ptr_op_t xact_t::lookup(const symbol_t::kind_t kind,
- const string& name)
+ const string& name)
{
if (kind != symbol_t::FUNCTION)
return item_t::lookup(kind, name);
@@ -601,13 +601,13 @@ namespace {
case expr_t::op_t::O_MATCH:
if (op->left()->kind == expr_t::op_t::IDENT &&
- op->left()->as_ident() == "account" &&
- op->right()->kind == expr_t::op_t::VALUE &&
- op->right()->as_value().is_mask())
- return op->right()->as_value().as_mask()
- .match(post.reported_account()->fullname());
+ op->left()->as_ident() == "account" &&
+ op->right()->kind == expr_t::op_t::VALUE &&
+ op->right()->as_value().is_mask())
+ return op->right()->as_value().as_mask()
+ .match(post.reported_account()->fullname());
else
- break;
+ break;
case expr_t::op_t::O_NOT:
return ! post_pred(op->left(), post);
@@ -620,9 +620,9 @@ namespace {
case expr_t::op_t::O_QUERY:
if (post_pred(op->left(), post))
- return post_pred(op->right()->left(), post);
+ return post_pred(op->right()->left(), post);
else
- return post_pred(op->right()->right(), post);
+ return post_pred(op->right()->right(), post);
default:
break;
@@ -649,109 +649,109 @@ void auto_xact_t::extend_xact(xact_base_t& xact)
bool matches_predicate = false;
if (try_quick_match) {
try {
- bool found_memoized_result = false;
- if (! memoized_results.empty()) {
- std::map<string, bool>::iterator i =
- memoized_results.find(initial_post->account->fullname());
- if (i != memoized_results.end()) {
- found_memoized_result = true;
- matches_predicate = (*i).second;
- }
- }
-
- // Since the majority of people who use automated transactions simply
- // match against account names, try using a *much* faster version of
- // the predicate evaluator.
- if (! found_memoized_result) {
- matches_predicate = post_pred(predicate.get_op(), *initial_post);
- memoized_results.insert
- (std::pair<string, bool>(initial_post->account->fullname(),
- matches_predicate));
- }
+ bool found_memoized_result = false;
+ if (! memoized_results.empty()) {
+ std::map<string, bool>::iterator i =
+ memoized_results.find(initial_post->account->fullname());
+ if (i != memoized_results.end()) {
+ found_memoized_result = true;
+ matches_predicate = (*i).second;
+ }
+ }
+
+ // Since the majority of people who use automated transactions simply
+ // match against account names, try using a *much* faster version of
+ // the predicate evaluator.
+ if (! found_memoized_result) {
+ matches_predicate = post_pred(predicate.get_op(), *initial_post);
+ memoized_results.insert
+ (std::pair<string, bool>(initial_post->account->fullname(),
+ matches_predicate));
+ }
}
catch (...) {
- DEBUG("xact.extend.fail",
- "The quick matcher failed, going back to regular eval");
- try_quick_match = false;
- matches_predicate = predicate(*initial_post);
+ DEBUG("xact.extend.fail",
+ "The quick matcher failed, going back to regular eval");
+ try_quick_match = false;
+ matches_predicate = predicate(*initial_post);
}
} else {
matches_predicate = predicate(*initial_post);
}
if (matches_predicate) {
foreach (post_t * post, posts) {
- amount_t post_amount;
- if (post->amount.is_null()) {
- if (! post->amount_expr)
- 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();
- } else {
- if (! result.is_amount())
- throw_(amount_error,
- _("Amount expressions must result in a simple amount"));
- post_amount = result.as_amount();
- }
- } else {
- post_amount = post->amount;
- }
-
- amount_t amt;
- if (! post_amount.commodity())
- amt = initial_post->amount * post_amount;
- else
- amt = post_amount;
+ amount_t post_amount;
+ if (post->amount.is_null()) {
+ if (! post->amount_expr)
+ 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();
+ } else {
+ if (! result.is_amount())
+ throw_(amount_error,
+ _("Amount expressions must result in a simple amount"));
+ post_amount = result.as_amount();
+ }
+ } else {
+ post_amount = post->amount;
+ }
+
+ amount_t amt;
+ if (! post_amount.commodity())
+ amt = initial_post->amount * post_amount;
+ else
+ amt = post_amount;
#if defined(DEBUG_ON)
- IF_DEBUG("xact.extend") {
- DEBUG("xact.extend",
- "Initial post on line " << initial_post->pos->beg_line << ": "
- << "amount " << initial_post->amount << " (precision "
- << initial_post->amount.precision() << ")");
-
- if (initial_post->amount.keep_precision())
- DEBUG("xact.extend", " precision is kept");
-
- DEBUG("xact.extend",
- "Posting on line " << post->pos->beg_line << ": "
- << "amount " << post_amount << ", amt " << amt
- << " (precision " << post_amount.precision()
- << " != " << amt.precision() << ")");
-
- if (post_amount.keep_precision())
- DEBUG("xact.extend", " precision is kept");
- if (amt.keep_precision())
- DEBUG("xact.extend", " amt precision is kept");
- }
+ IF_DEBUG("xact.extend") {
+ DEBUG("xact.extend",
+ "Initial post on line " << initial_post->pos->beg_line << ": "
+ << "amount " << initial_post->amount << " (precision "
+ << initial_post->amount.precision() << ")");
+
+ if (initial_post->amount.keep_precision())
+ DEBUG("xact.extend", " precision is kept");
+
+ DEBUG("xact.extend",
+ "Posting on line " << post->pos->beg_line << ": "
+ << "amount " << post_amount << ", amt " << amt
+ << " (precision " << post_amount.precision()
+ << " != " << amt.precision() << ")");
+
+ if (post_amount.keep_precision())
+ DEBUG("xact.extend", " precision is kept");
+ if (amt.keep_precision())
+ DEBUG("xact.extend", " amt precision is kept");
+ }
#endif // defined(DEBUG_ON)
- account_t * account = post->account;
- string fullname = account->fullname();
- assert(! fullname.empty());
-
- if (contains(fullname, "$account")) {
- fullname = regex_replace(fullname, regex("\\$account\\>"),
- initial_post->account->fullname());
- while (account->parent)
- account = account->parent;
- account = account->find_account(fullname);
- }
-
- // Copy over details so that the resulting post is a mirror of
- // the automated xact's one.
- post_t * new_post = new post_t(account, amt);
- new_post->copy_details(*post);
- new_post->add_flags(ITEM_GENERATED);
-
- xact.add_post(new_post);
- new_post->account->add_post(new_post);
-
- if (new_post->must_balance())
- needs_further_verification = true;
+ account_t * account = post->account;
+ string fullname = account->fullname();
+ assert(! fullname.empty());
+
+ if (contains(fullname, "$account")) {
+ fullname = regex_replace(fullname, regex("\\$account\\>"),
+ initial_post->account->fullname());
+ while (account->parent)
+ account = account->parent;
+ account = account->find_account(fullname);
+ }
+
+ // Copy over details so that the resulting post is a mirror of
+ // the automated xact's one.
+ post_t * new_post = new post_t(account, amt);
+ new_post->copy_details(*post);
+ new_post->add_flags(ITEM_GENERATED);
+
+ xact.add_post(new_post);
+ new_post->account->add_post(new_post);
+
+ if (new_post->must_balance())
+ needs_further_verification = true;
}
}
}
@@ -768,7 +768,7 @@ void auto_xact_t::extend_xact(xact_base_t& xact)
}
void extend_xact_base(journal_t * journal,
- xact_base_t& base)
+ xact_base_t& base)
{
foreach (auto_xact_t * xact, journal->auto_xacts)
xact->extend_xact(base);
@@ -816,18 +816,18 @@ void to_xml(std::ostream& out, const xact_t& xact)
push_xml y(out, "metadata");
foreach (const item_t::string_map::value_type& pair, *xact.metadata) {
if (pair.second.first) {
- push_xml z(out, "variable");
- {
- push_xml w(out, "key");
- out << y.guard(pair.first);
- }
- {
- push_xml w(out, "value");
- out << y.guard(*pair.second.first);
- }
+ push_xml z(out, "variable");
+ {
+ push_xml w(out, "key");
+ out << y.guard(pair.first);
+ }
+ {
+ push_xml w(out, "value");
+ out << y.guard(*pair.second.first);
+ }
} else {
- push_xml z(out, "tag");
- out << y.guard(pair.first);
+ push_xml z(out, "tag");
+ out << y.guard(pair.first);
}
}
}