Merge branch 'next'
This commit is contained in:
commit
027c255a4f
19 changed files with 524 additions and 214 deletions
|
|
@ -76,6 +76,7 @@ libledger_report_la_SOURCES = \
|
||||||
src/precmd.cc \
|
src/precmd.cc \
|
||||||
src/chain.cc \
|
src/chain.cc \
|
||||||
src/filters.cc \
|
src/filters.cc \
|
||||||
|
src/temps.cc \
|
||||||
src/report.cc \
|
src/report.cc \
|
||||||
src/session.cc
|
src/session.cc
|
||||||
|
|
||||||
|
|
@ -124,6 +125,7 @@ pkginclude_HEADERS = \
|
||||||
src/session.h \
|
src/session.h \
|
||||||
src/report.h \
|
src/report.h \
|
||||||
src/filters.h \
|
src/filters.h \
|
||||||
|
src/temps.h \
|
||||||
src/chain.h \
|
src/chain.h \
|
||||||
src/precmd.h \
|
src/precmd.h \
|
||||||
src/derive.h \
|
src/derive.h \
|
||||||
|
|
|
||||||
|
|
@ -110,6 +110,14 @@ account_t * account_t::find_account_re(const string& regexp)
|
||||||
return find_account_re_(this, mask_t(regexp));
|
return find_account_re_(this, mask_t(regexp));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool account_t::remove_post(post_t * post)
|
||||||
|
{
|
||||||
|
assert(! posts.empty());
|
||||||
|
posts.remove(post);
|
||||||
|
post->account = NULL;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
string account_t::fullname() const
|
string account_t::fullname() const
|
||||||
{
|
{
|
||||||
if (! _fullname.empty()) {
|
if (! _fullname.empty()) {
|
||||||
|
|
@ -140,7 +148,7 @@ string account_t::partial_name(bool flat) const
|
||||||
if (! flat) {
|
if (! flat) {
|
||||||
std::size_t count = acct->children_with_flags(ACCOUNT_EXT_TO_DISPLAY);
|
std::size_t count = acct->children_with_flags(ACCOUNT_EXT_TO_DISPLAY);
|
||||||
assert(count > 0);
|
assert(count > 0);
|
||||||
if (count > 1 || acct->has_flags(ACCOUNT_EXT_TO_DISPLAY))
|
if (count > 1 || acct->has_xflags(ACCOUNT_EXT_TO_DISPLAY))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
pname = acct->name + ":" + pname;
|
pname = acct->name + ":" + pname;
|
||||||
|
|
@ -206,7 +214,7 @@ namespace {
|
||||||
acct = acct->parent) {
|
acct = acct->parent) {
|
||||||
std::size_t count = acct->children_with_flags(ACCOUNT_EXT_TO_DISPLAY);
|
std::size_t count = acct->children_with_flags(ACCOUNT_EXT_TO_DISPLAY);
|
||||||
assert(count > 0);
|
assert(count > 0);
|
||||||
if (count > 1 || acct->has_flags(ACCOUNT_EXT_TO_DISPLAY))
|
if (count > 1 || acct->has_xflags(ACCOUNT_EXT_TO_DISPLAY))
|
||||||
depth++;
|
depth++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -217,6 +225,11 @@ namespace {
|
||||||
return string_value(out.str());
|
return string_value(out.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
value_t get_latest_cleared(account_t& account)
|
||||||
|
{
|
||||||
|
return account.self_details().latest_cleared_post;
|
||||||
|
}
|
||||||
|
|
||||||
template <value_t (*Func)(account_t&)>
|
template <value_t (*Func)(account_t&)>
|
||||||
value_t get_wrapper(call_scope_t& scope) {
|
value_t get_wrapper(call_scope_t& scope) {
|
||||||
return (*Func)(find_scope<account_t>(scope));
|
return (*Func)(find_scope<account_t>(scope));
|
||||||
|
|
@ -256,6 +269,11 @@ expr_t::ptr_op_t account_t::lookup(const string& name)
|
||||||
return WRAP_FUNCTOR(get_wrapper<&get_true>);
|
return WRAP_FUNCTOR(get_wrapper<&get_true>);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'l':
|
||||||
|
if (name == "latest_cleared")
|
||||||
|
return WRAP_FUNCTOR(get_wrapper<&get_latest_cleared>);
|
||||||
|
break;
|
||||||
|
|
||||||
case 'p':
|
case 'p':
|
||||||
if (name == "partial_account")
|
if (name == "partial_account")
|
||||||
return WRAP_FUNCTOR(get_partial_name);
|
return WRAP_FUNCTOR(get_partial_name);
|
||||||
|
|
@ -310,7 +328,7 @@ std::size_t account_t::children_with_flags(xdata_t::flags_t flags) const
|
||||||
bool grandchildren_visited = false;
|
bool grandchildren_visited = false;
|
||||||
|
|
||||||
foreach (const accounts_map::value_type& pair, accounts) {
|
foreach (const accounts_map::value_type& pair, accounts) {
|
||||||
if (pair.second->has_flags(flags) ||
|
if (pair.second->has_xflags(flags) ||
|
||||||
pair.second->children_with_flags(flags))
|
pair.second->children_with_flags(flags))
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
|
@ -362,20 +380,21 @@ account_t::xdata_t::details_t::operator+=(const details_t& other)
|
||||||
value_t account_t::self_total(const optional<expr_t&>& expr) const
|
value_t account_t::self_total(const optional<expr_t&>& expr) const
|
||||||
{
|
{
|
||||||
if (xdata_ && xdata_->has_flags(ACCOUNT_EXT_VISITED)) {
|
if (xdata_ && xdata_->has_flags(ACCOUNT_EXT_VISITED)) {
|
||||||
if (! xdata_) xdata_ = xdata_t();
|
posts_list::const_iterator i;
|
||||||
|
if (xdata_->self_details.last_post)
|
||||||
posts_deque::const_iterator i =
|
i = *xdata_->self_details.last_post;
|
||||||
posts.begin() + xdata_->self_details.last_size;
|
else
|
||||||
|
i = posts.begin();
|
||||||
|
|
||||||
for (; i != posts.end(); i++) {
|
for (; i != posts.end(); i++) {
|
||||||
if ((*i)->xdata().has_flags(POST_EXT_VISITED) &&
|
if ((*i)->xdata().has_flags(POST_EXT_VISITED)) {
|
||||||
! (*i)->xdata().has_flags(POST_EXT_CONSIDERED)) {
|
if (! (*i)->xdata().has_flags(POST_EXT_CONSIDERED)) {
|
||||||
(*i)->add_to_value(xdata_->self_details.total, expr);
|
(*i)->add_to_value(xdata_->self_details.total, expr);
|
||||||
(*i)->xdata().add_flags(POST_EXT_CONSIDERED);
|
(*i)->xdata().add_flags(POST_EXT_CONSIDERED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
xdata_->self_details.last_post = i;
|
||||||
xdata_->self_details.last_size = posts.size();
|
}
|
||||||
|
|
||||||
return xdata_->self_details.total;
|
return xdata_->self_details.total;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ class account_t;
|
||||||
class xact_t;
|
class xact_t;
|
||||||
class post_t;
|
class post_t;
|
||||||
|
|
||||||
typedef std::deque<post_t *> posts_deque;
|
typedef std::list<post_t *> posts_list;
|
||||||
typedef std::map<const string, account_t *> accounts_map;
|
typedef std::map<const string, account_t *> accounts_map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -63,35 +63,37 @@ typedef std::map<const string, account_t *> accounts_map;
|
||||||
*
|
*
|
||||||
* Long.
|
* Long.
|
||||||
*/
|
*/
|
||||||
class account_t : public scope_t
|
class account_t : public supports_flags<>, public scope_t
|
||||||
{
|
{
|
||||||
|
#define ACCOUNT_NORMAL 0x00 // no flags at all, a basic account
|
||||||
|
#define ACCOUNT_KNOWN 0x01
|
||||||
|
#define ACCOUNT_TEMP 0x02 // account is a temporary object
|
||||||
|
|
||||||
public:
|
public:
|
||||||
account_t * parent;
|
account_t * parent;
|
||||||
string name;
|
string name;
|
||||||
optional<string> note;
|
optional<string> note;
|
||||||
unsigned short depth;
|
unsigned short depth;
|
||||||
accounts_map accounts;
|
accounts_map accounts;
|
||||||
posts_deque posts;
|
posts_list posts;
|
||||||
bool known;
|
|
||||||
|
|
||||||
mutable string _fullname;
|
mutable string _fullname;
|
||||||
|
|
||||||
account_t(account_t * _parent = NULL,
|
account_t(account_t * _parent = NULL,
|
||||||
const string& _name = "",
|
const string& _name = "",
|
||||||
const optional<string>& _note = none)
|
const optional<string>& _note = none)
|
||||||
: scope_t(), parent(_parent), name(_name), note(_note),
|
: supports_flags<>(), scope_t(), parent(_parent),
|
||||||
depth(static_cast<unsigned short>(parent ? parent->depth + 1 : 0)),
|
name(_name), note(_note),
|
||||||
known(false) {
|
depth(static_cast<unsigned short>(parent ? parent->depth + 1 : 0)) {
|
||||||
TRACE_CTOR(account_t, "account_t *, const string&, const string&");
|
TRACE_CTOR(account_t, "account_t *, const string&, const string&");
|
||||||
}
|
}
|
||||||
account_t(const account_t& other)
|
account_t(const account_t& other)
|
||||||
: scope_t(),
|
: supports_flags<>(other.flags()), scope_t(),
|
||||||
parent(other.parent),
|
parent(other.parent),
|
||||||
name(other.name),
|
name(other.name),
|
||||||
note(other.note),
|
note(other.note),
|
||||||
depth(other.depth),
|
depth(other.depth),
|
||||||
accounts(other.accounts),
|
accounts(other.accounts) {
|
||||||
known(other.known) {
|
|
||||||
TRACE_CTOR(account_t, "copy");
|
TRACE_CTOR(account_t, "copy");
|
||||||
}
|
}
|
||||||
~account_t();
|
~account_t();
|
||||||
|
|
@ -116,6 +118,7 @@ class account_t : public scope_t
|
||||||
void add_post(post_t * post) {
|
void add_post(post_t * post) {
|
||||||
posts.push_back(post);
|
posts.push_back(post);
|
||||||
}
|
}
|
||||||
|
bool remove_post(post_t * post);
|
||||||
|
|
||||||
virtual expr_t::ptr_op_t lookup(const string& name);
|
virtual expr_t::ptr_op_t lookup(const string& name);
|
||||||
|
|
||||||
|
|
@ -140,7 +143,6 @@ class account_t : public scope_t
|
||||||
bool calculated;
|
bool calculated;
|
||||||
bool gathered;
|
bool gathered;
|
||||||
|
|
||||||
// The following are only calculated if --totals is enabled
|
|
||||||
std::size_t posts_count;
|
std::size_t posts_count;
|
||||||
std::size_t posts_virtuals_count;
|
std::size_t posts_virtuals_count;
|
||||||
std::size_t posts_cleared_count;
|
std::size_t posts_cleared_count;
|
||||||
|
|
@ -153,13 +155,12 @@ class account_t : public scope_t
|
||||||
date_t latest_post;
|
date_t latest_post;
|
||||||
date_t latest_cleared_post;
|
date_t latest_cleared_post;
|
||||||
|
|
||||||
std::size_t last_size;
|
|
||||||
|
|
||||||
// The following are only calculated if --gather is enabled
|
|
||||||
std::set<path> filenames;
|
std::set<path> filenames;
|
||||||
std::set<string> accounts_referenced;
|
std::set<string> accounts_referenced;
|
||||||
std::set<string> payees_referenced;
|
std::set<string> payees_referenced;
|
||||||
|
|
||||||
|
optional<posts_list::const_iterator> last_post;
|
||||||
|
|
||||||
details_t()
|
details_t()
|
||||||
: calculated(false),
|
: calculated(false),
|
||||||
gathered(false),
|
gathered(false),
|
||||||
|
|
@ -169,9 +170,7 @@ class account_t : public scope_t
|
||||||
posts_cleared_count(0),
|
posts_cleared_count(0),
|
||||||
posts_last_7_count(0),
|
posts_last_7_count(0),
|
||||||
posts_last_30_count(0),
|
posts_last_30_count(0),
|
||||||
posts_this_month_count(0),
|
posts_this_month_count(0) {}
|
||||||
|
|
||||||
last_size(0) {}
|
|
||||||
|
|
||||||
details_t& operator+=(const details_t& other);
|
details_t& operator+=(const details_t& other);
|
||||||
|
|
||||||
|
|
@ -229,7 +228,7 @@ class account_t : public scope_t
|
||||||
const xdata_t::details_t& self_details(bool gather_all = true) const;
|
const xdata_t::details_t& self_details(bool gather_all = true) const;
|
||||||
const xdata_t::details_t& family_details(bool gather_all = true) const;
|
const xdata_t::details_t& family_details(bool gather_all = true) const;
|
||||||
|
|
||||||
bool has_flags(xdata_t::flags_t flags) const {
|
bool has_xflags(xdata_t::flags_t flags) const {
|
||||||
return xdata_ && xdata_->has_flags(flags);
|
return xdata_ && xdata_->has_flags(flags);
|
||||||
}
|
}
|
||||||
std::size_t children_with_flags(xdata_t::flags_t flags) const;
|
std::size_t children_with_flags(xdata_t::flags_t flags) const;
|
||||||
|
|
|
||||||
|
|
@ -417,6 +417,9 @@ public:
|
||||||
bool is_empty() const {
|
bool is_empty() const {
|
||||||
return amounts.size() == 0;
|
return amounts.size() == 0;
|
||||||
}
|
}
|
||||||
|
bool single_amount() const {
|
||||||
|
return amounts.size() == 1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Conversion methods. A balance can be converted to an amount, but
|
* Conversion methods. A balance can be converted to an amount, but
|
||||||
|
|
|
||||||
111
src/filters.cc
111
src/filters.cc
|
|
@ -140,11 +140,11 @@ void anonymize_posts::operator()(post_t& post)
|
||||||
bool copy_xact_details = false;
|
bool copy_xact_details = false;
|
||||||
|
|
||||||
if (last_xact != post.xact) {
|
if (last_xact != post.xact) {
|
||||||
xact_temps.push_back(*post.xact);
|
temps.copy_xact(*post.xact);
|
||||||
last_xact = post.xact;
|
last_xact = post.xact;
|
||||||
copy_xact_details = true;
|
copy_xact_details = true;
|
||||||
}
|
}
|
||||||
xact_t& xact = xact_temps.back();
|
xact_t& xact = temps.last_xact();
|
||||||
|
|
||||||
if (copy_xact_details) {
|
if (copy_xact_details) {
|
||||||
xact.copy_details(*post.xact);
|
xact.copy_details(*post.xact);
|
||||||
|
|
@ -157,10 +157,6 @@ void anonymize_posts::operator()(post_t& post)
|
||||||
xact.note = none;
|
xact.note = none;
|
||||||
}
|
}
|
||||||
|
|
||||||
post_temps.push_back(post);
|
|
||||||
post_t& temp = post_temps.back();
|
|
||||||
temp.xact = &xact;
|
|
||||||
|
|
||||||
std::list<string> account_names;
|
std::list<string> account_names;
|
||||||
account_t * new_account = NULL;
|
account_t * new_account = NULL;
|
||||||
|
|
||||||
|
|
@ -183,13 +179,8 @@ void anonymize_posts::operator()(post_t& post)
|
||||||
foreach (const string& name, account_names)
|
foreach (const string& name, account_names)
|
||||||
new_account = new_account->find_account(name);
|
new_account = new_account->find_account(name);
|
||||||
|
|
||||||
temp.copy_details(post);
|
post_t& temp = temps.copy_post(post, xact, new_account);
|
||||||
|
|
||||||
temp.account = new_account;
|
|
||||||
temp.note = none;
|
temp.note = none;
|
||||||
temp.add_flags(ITEM_TEMP);
|
|
||||||
|
|
||||||
xact.add_post(&temp);
|
|
||||||
|
|
||||||
(*handler)(temp);
|
(*handler)(temp);
|
||||||
}
|
}
|
||||||
|
|
@ -227,18 +218,14 @@ namespace {
|
||||||
void handle_value(const value_t& value,
|
void handle_value(const value_t& value,
|
||||||
account_t * account,
|
account_t * account,
|
||||||
xact_t * xact,
|
xact_t * xact,
|
||||||
std::list<post_t>& temps,
|
temporaries_t& temps,
|
||||||
item_handler<post_t>& handler,
|
item_handler<post_t>& handler,
|
||||||
const date_t& date = date_t(),
|
const date_t& date = date_t(),
|
||||||
const value_t& total = value_t(),
|
const value_t& total = value_t(),
|
||||||
const bool direct_amount = false,
|
const bool direct_amount = false,
|
||||||
const optional<post_functor_t>& functor = none)
|
const optional<post_functor_t>& functor = none)
|
||||||
{
|
{
|
||||||
temps.push_back(post_t(account));
|
post_t& post = temps.create_post(*xact, account);
|
||||||
post_t& post(temps.back());
|
|
||||||
post.xact = xact;
|
|
||||||
post.add_flags(ITEM_TEMP);
|
|
||||||
xact->add_post(&post);
|
|
||||||
|
|
||||||
// If the account for this post is all virtual, then report the post as
|
// If the account for this post is all virtual, then report the post as
|
||||||
// such. This allows subtotal reports to show "(Account)" for accounts
|
// such. This allows subtotal reports to show "(Account)" for accounts
|
||||||
|
|
@ -325,14 +312,13 @@ void collapse_posts::report_subtotal()
|
||||||
earliest_date = reported;
|
earliest_date = reported;
|
||||||
}
|
}
|
||||||
|
|
||||||
xact_temps.push_back(xact_t());
|
xact_t& xact = temps.create_xact();
|
||||||
xact_t& xact = xact_temps.back();
|
|
||||||
xact.payee = last_xact->payee;
|
xact.payee = last_xact->payee;
|
||||||
xact._date = (is_valid(earliest_date) ?
|
xact._date = (is_valid(earliest_date) ?
|
||||||
earliest_date : last_xact->_date);
|
earliest_date : last_xact->_date);
|
||||||
DEBUG("filter.collapse", "Pseudo-xact date = " << *xact._date);
|
DEBUG("filter.collapse", "Pseudo-xact date = " << *xact._date);
|
||||||
|
|
||||||
handle_value(subtotal, &totals_account, &xact, post_temps, *handler);
|
handle_value(subtotal, &totals_account, &xact, temps, *handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
component_posts.clear();
|
component_posts.clear();
|
||||||
|
|
@ -427,12 +413,11 @@ void changed_value_posts::output_revaluation(post_t * post, const date_t& date)
|
||||||
DEBUG("filter.changed_value", "output_revaluation(strip(diff)) = "
|
DEBUG("filter.changed_value", "output_revaluation(strip(diff)) = "
|
||||||
<< diff.strip_annotations(report.what_to_keep()));
|
<< diff.strip_annotations(report.what_to_keep()));
|
||||||
|
|
||||||
xact_temps.push_back(xact_t());
|
xact_t& xact = temps.create_xact();
|
||||||
xact_t& xact = xact_temps.back();
|
|
||||||
xact.payee = _("Commodities revalued");
|
xact.payee = _("Commodities revalued");
|
||||||
xact._date = is_valid(date) ? date : post->date();
|
xact._date = is_valid(date) ? date : post->date();
|
||||||
|
|
||||||
handle_value(diff, &revalued_account, &xact, post_temps, *handler,
|
handle_value(diff, &revalued_account, &xact, temps, *handler,
|
||||||
*xact._date, repriced_total, false,
|
*xact._date, repriced_total, false,
|
||||||
optional<post_functor_t>
|
optional<post_functor_t>
|
||||||
(bind(&changed_value_posts::output_rounding, this, _1)));
|
(bind(&changed_value_posts::output_rounding, this, _1)));
|
||||||
|
|
@ -465,13 +450,12 @@ void changed_value_posts::output_rounding(post_t * post)
|
||||||
DEBUG("filter.changed_value.rounding",
|
DEBUG("filter.changed_value.rounding",
|
||||||
"rounding.diff = " << diff);
|
"rounding.diff = " << diff);
|
||||||
|
|
||||||
xact_temps.push_back(xact_t());
|
xact_t& xact = temps.create_xact();
|
||||||
xact_t& xact = xact_temps.back();
|
|
||||||
xact.payee = _("Commodity rounding");
|
xact.payee = _("Commodity rounding");
|
||||||
xact._date = post->date();
|
xact._date = post->date();
|
||||||
|
|
||||||
handle_value(diff, &rounding_account, &xact, post_temps,
|
handle_value(diff, &rounding_account, &xact, temps, *handler,
|
||||||
*handler, *xact._date, precise_display_total, true);
|
*xact._date, precise_display_total, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -526,13 +510,12 @@ void subtotal_posts::report_subtotal(const char * spec_fmt,
|
||||||
out_date << "- " << format_date(*range_finish);
|
out_date << "- " << format_date(*range_finish);
|
||||||
}
|
}
|
||||||
|
|
||||||
xact_temps.push_back(xact_t());
|
xact_t& xact = temps.create_xact();
|
||||||
xact_t& xact = xact_temps.back();
|
|
||||||
xact.payee = out_date.str();
|
xact.payee = out_date.str();
|
||||||
xact._date = *range_start;
|
xact._date = *range_start;
|
||||||
|
|
||||||
foreach (values_map::value_type& pair, values)
|
foreach (values_map::value_type& pair, values)
|
||||||
handle_value(pair.second.value, pair.second.account, &xact, post_temps,
|
handle_value(pair.second.value, pair.second.account, &xact, temps,
|
||||||
*handler);
|
*handler);
|
||||||
|
|
||||||
values.clear();
|
values.clear();
|
||||||
|
|
@ -596,16 +579,12 @@ void interval_posts::operator()(post_t& post)
|
||||||
// Generate a null posting, so the intervening periods can be
|
// Generate a null posting, so the intervening periods can be
|
||||||
// seen when -E is used, or if the calculated amount ends up being
|
// seen when -E is used, or if the calculated amount ends up being
|
||||||
// non-zero
|
// non-zero
|
||||||
xact_temps.push_back(xact_t());
|
xact_t& null_xact = temps.create_xact();
|
||||||
xact_t& null_xact = xact_temps.back();
|
|
||||||
null_xact.add_flags(ITEM_TEMP);
|
|
||||||
null_xact._date = last_interval.inclusive_end();
|
null_xact._date = last_interval.inclusive_end();
|
||||||
|
|
||||||
post_temps.push_back(post_t(&empty_account));
|
post_t& null_post = temps.create_post(null_xact, &empty_account);
|
||||||
post_t& null_post = post_temps.back();
|
null_post.add_flags(POST_CALCULATED);
|
||||||
null_post.add_flags(ITEM_TEMP | POST_CALCULATED);
|
|
||||||
null_post.amount = 0L;
|
null_post.amount = 0L;
|
||||||
null_xact.add_post(&null_post);
|
|
||||||
|
|
||||||
last_post = &null_post;
|
last_post = &null_post;
|
||||||
subtotal_posts::operator()(null_post);
|
subtotal_posts::operator()(null_post);
|
||||||
|
|
@ -637,14 +616,13 @@ void posts_as_equity::report_subtotal()
|
||||||
}
|
}
|
||||||
component_posts.clear();
|
component_posts.clear();
|
||||||
|
|
||||||
xact_temps.push_back(xact_t());
|
xact_t& xact = temps.create_xact();
|
||||||
xact_t& xact = xact_temps.back();
|
|
||||||
xact.payee = _("Opening Balances");
|
xact.payee = _("Opening Balances");
|
||||||
xact._date = finish;
|
xact._date = finish;
|
||||||
|
|
||||||
value_t total = 0L;
|
value_t total = 0L;
|
||||||
foreach (values_map::value_type& pair, values) {
|
foreach (values_map::value_type& pair, values) {
|
||||||
handle_value(pair.second.value, pair.second.account, &xact, post_temps,
|
handle_value(pair.second.value, pair.second.account, &xact, temps,
|
||||||
*handler);
|
*handler);
|
||||||
total += pair.second.value;
|
total += pair.second.value;
|
||||||
}
|
}
|
||||||
|
|
@ -653,19 +631,13 @@ void posts_as_equity::report_subtotal()
|
||||||
if (total.is_balance()) {
|
if (total.is_balance()) {
|
||||||
foreach (balance_t::amounts_map::value_type pair,
|
foreach (balance_t::amounts_map::value_type pair,
|
||||||
total.as_balance().amounts) {
|
total.as_balance().amounts) {
|
||||||
post_temps.push_back(post_t(balance_account));
|
post_t& balance_post = temps.create_post(xact, balance_account);
|
||||||
post_t& balance_post = post_temps.back();
|
|
||||||
balance_post.add_flags(ITEM_TEMP);
|
|
||||||
balance_post.amount = - pair.second;
|
balance_post.amount = - pair.second;
|
||||||
xact.add_post(&balance_post);
|
|
||||||
(*handler)(balance_post);
|
(*handler)(balance_post);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
post_temps.push_back(post_t(balance_account));
|
post_t& balance_post = temps.create_post(xact, balance_account);
|
||||||
post_t& balance_post = post_temps.back();
|
|
||||||
balance_post.add_flags(ITEM_TEMP);
|
|
||||||
balance_post.amount = - total.to_amount();
|
balance_post.amount = - total.to_amount();
|
||||||
xact.add_post(&balance_post);
|
|
||||||
(*handler)(balance_post);
|
(*handler)(balance_post);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -701,16 +673,11 @@ void by_payee_posts::operator()(post_t& post)
|
||||||
|
|
||||||
void transfer_details::operator()(post_t& post)
|
void transfer_details::operator()(post_t& post)
|
||||||
{
|
{
|
||||||
xact_temps.push_back(*post.xact);
|
xact_t& xact = temps.copy_xact(*post.xact);
|
||||||
xact_t& xact = xact_temps.back();
|
|
||||||
xact._date = post.date();
|
xact._date = post.date();
|
||||||
|
|
||||||
post_temps.push_back(post);
|
post_t& temp = temps.copy_post(post, xact);
|
||||||
post_t& temp = post_temps.back();
|
|
||||||
temp.xact = &xact;
|
|
||||||
temp.set_state(post.state());
|
temp.set_state(post.state());
|
||||||
temp.add_flags(ITEM_TEMP);
|
|
||||||
xact.add_post(&temp);
|
|
||||||
|
|
||||||
bind_scope_t bound_scope(scope, temp);
|
bind_scope_t bound_scope(scope, temp);
|
||||||
|
|
||||||
|
|
@ -720,6 +687,7 @@ void transfer_details::operator()(post_t& post)
|
||||||
break;
|
break;
|
||||||
case SET_ACCOUNT:
|
case SET_ACCOUNT:
|
||||||
temp.account = master->find_account(expr.calc(bound_scope).to_string());
|
temp.account = master->find_account(expr.calc(bound_scope).to_string());
|
||||||
|
temp.account->add_post(&temp);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
assert(false);
|
assert(false);
|
||||||
|
|
@ -777,17 +745,21 @@ void budget_posts::report_budget_items(const date_t& date)
|
||||||
DEBUG("ledger.walk.budget", "Reporting budget for "
|
DEBUG("ledger.walk.budget", "Reporting budget for "
|
||||||
<< post.reported_account()->fullname());
|
<< post.reported_account()->fullname());
|
||||||
|
|
||||||
xact_temps.push_back(xact_t());
|
xact_t& xact = temps.create_xact();
|
||||||
xact_t& xact = xact_temps.back();
|
|
||||||
xact.payee = _("Budget transaction");
|
xact.payee = _("Budget transaction");
|
||||||
xact._date = begin;
|
xact._date = begin;
|
||||||
|
|
||||||
post_temps.push_back(post);
|
post_t& temp = temps.copy_post(post, xact);
|
||||||
post_t& temp = post_temps.back();
|
|
||||||
temp.xact = &xact;
|
|
||||||
temp.add_flags(ITEM_TEMP);
|
|
||||||
temp.amount.in_place_negate();
|
temp.amount.in_place_negate();
|
||||||
xact.add_post(&temp);
|
|
||||||
|
if (flags & BUDGET_WRAP_VALUES) {
|
||||||
|
value_t seq;
|
||||||
|
seq.push_back(0L);
|
||||||
|
seq.push_back(temp.amount);
|
||||||
|
|
||||||
|
temp.xdata().compound_value = seq;
|
||||||
|
temp.xdata().add_flags(POST_EXT_COMPOUND);
|
||||||
|
}
|
||||||
|
|
||||||
++pair.first;
|
++pair.first;
|
||||||
begin = *pair.first.start;
|
begin = *pair.first.start;
|
||||||
|
|
@ -810,8 +782,8 @@ void budget_posts::operator()(post_t& post)
|
||||||
acct = acct->parent) {
|
acct = acct->parent) {
|
||||||
if (acct == (*pair.second).reported_account()) {
|
if (acct == (*pair.second).reported_account()) {
|
||||||
post_in_budget = true;
|
post_in_budget = true;
|
||||||
// Report the post as if it had occurred in the parent
|
// Report the post as if it had occurred in the parent account.
|
||||||
// account.
|
// jww (2009-10-27): What about calling add_post here?
|
||||||
if (post.reported_account() != acct)
|
if (post.reported_account() != acct)
|
||||||
post.xdata().account = acct;
|
post.xdata().account = acct;
|
||||||
goto handle;
|
goto handle;
|
||||||
|
|
@ -867,16 +839,11 @@ void forecast_posts::flush()
|
||||||
|
|
||||||
post_t& post = *(*least).second;
|
post_t& post = *(*least).second;
|
||||||
|
|
||||||
xact_temps.push_back(xact_t());
|
xact_t& xact = temps.create_xact();
|
||||||
xact_t& xact = xact_temps.back();
|
|
||||||
xact.payee = _("Forecast transaction");
|
xact.payee = _("Forecast transaction");
|
||||||
xact._date = begin;
|
xact._date = begin;
|
||||||
|
|
||||||
post_temps.push_back(post);
|
post_t& temp = temps.copy_post(post, xact);
|
||||||
post_t& temp = post_temps.back();
|
|
||||||
temp.xact = &xact;
|
|
||||||
temp.add_flags(ITEM_TEMP);
|
|
||||||
xact.add_post(&temp);
|
|
||||||
|
|
||||||
date_t next = *(*least).first.next;
|
date_t next = *(*least).first.next;
|
||||||
++(*least).first;
|
++(*least).first;
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,7 @@
|
||||||
#include "xact.h"
|
#include "xact.h"
|
||||||
#include "post.h"
|
#include "post.h"
|
||||||
#include "account.h"
|
#include "account.h"
|
||||||
|
#include "temps.h"
|
||||||
|
|
||||||
namespace ledger {
|
namespace ledger {
|
||||||
|
|
||||||
|
|
@ -279,11 +280,6 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
inline void clear_xacts_posts(std::list<xact_t>& xacts_list) {
|
|
||||||
foreach (xact_t& xact, xacts_list)
|
|
||||||
xact.posts.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Brief
|
* @brief Brief
|
||||||
*
|
*
|
||||||
|
|
@ -291,8 +287,7 @@ inline void clear_xacts_posts(std::list<xact_t>& xacts_list) {
|
||||||
*/
|
*/
|
||||||
class anonymize_posts : public item_handler<post_t>
|
class anonymize_posts : public item_handler<post_t>
|
||||||
{
|
{
|
||||||
std::list<xact_t> xact_temps;
|
temporaries_t temps;
|
||||||
std::list<post_t> post_temps;
|
|
||||||
|
|
||||||
xact_t * last_xact;
|
xact_t * last_xact;
|
||||||
|
|
||||||
|
|
@ -305,7 +300,6 @@ public:
|
||||||
}
|
}
|
||||||
virtual ~anonymize_posts() {
|
virtual ~anonymize_posts() {
|
||||||
TRACE_DTOR(anonymize_posts);
|
TRACE_DTOR(anonymize_posts);
|
||||||
clear_xacts_posts(xact_temps);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void operator()(post_t& post);
|
virtual void operator()(post_t& post);
|
||||||
|
|
@ -353,11 +347,9 @@ class collapse_posts : public item_handler<post_t>
|
||||||
std::size_t count;
|
std::size_t count;
|
||||||
xact_t * last_xact;
|
xact_t * last_xact;
|
||||||
post_t * last_post;
|
post_t * last_post;
|
||||||
account_t totals_account;
|
temporaries_t temps;
|
||||||
|
account_t& totals_account;
|
||||||
bool only_collapse_if_zero;
|
bool only_collapse_if_zero;
|
||||||
|
|
||||||
std::list<xact_t> xact_temps;
|
|
||||||
std::list<post_t> post_temps;
|
|
||||||
std::list<post_t *> component_posts;
|
std::list<post_t *> component_posts;
|
||||||
|
|
||||||
collapse_posts();
|
collapse_posts();
|
||||||
|
|
@ -372,13 +364,12 @@ public:
|
||||||
display_predicate(_display_predicate),
|
display_predicate(_display_predicate),
|
||||||
only_predicate(_only_predicate), count(0),
|
only_predicate(_only_predicate), count(0),
|
||||||
last_xact(NULL), last_post(NULL),
|
last_xact(NULL), last_post(NULL),
|
||||||
totals_account(NULL, _("<Total>")),
|
totals_account(temps.create_account(_("<Total>"))),
|
||||||
only_collapse_if_zero(_only_collapse_if_zero) {
|
only_collapse_if_zero(_only_collapse_if_zero) {
|
||||||
TRACE_CTOR(collapse_posts, "post_handler_ptr");
|
TRACE_CTOR(collapse_posts, "post_handler_ptr");
|
||||||
}
|
}
|
||||||
virtual ~collapse_posts() {
|
virtual ~collapse_posts() {
|
||||||
TRACE_DTOR(collapse_posts);
|
TRACE_DTOR(collapse_posts);
|
||||||
clear_xacts_posts(xact_temps);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void flush() {
|
virtual void flush() {
|
||||||
|
|
@ -440,11 +431,9 @@ class changed_value_posts : public item_handler<post_t>
|
||||||
post_t * last_post;
|
post_t * last_post;
|
||||||
value_t last_total;
|
value_t last_total;
|
||||||
value_t last_display_total;
|
value_t last_display_total;
|
||||||
account_t revalued_account;
|
temporaries_t temps;
|
||||||
account_t rounding_account;
|
account_t& revalued_account;
|
||||||
|
account_t& rounding_account;
|
||||||
std::list<xact_t> xact_temps;
|
|
||||||
std::list<post_t> post_temps;
|
|
||||||
|
|
||||||
changed_value_posts();
|
changed_value_posts();
|
||||||
|
|
||||||
|
|
@ -459,14 +448,13 @@ public:
|
||||||
display_amount_expr(_display_amount_expr), total_expr(_total_expr),
|
display_amount_expr(_display_amount_expr), total_expr(_total_expr),
|
||||||
display_total_expr(_display_total_expr), report(_report),
|
display_total_expr(_display_total_expr), report(_report),
|
||||||
changed_values_only(_changed_values_only), last_post(NULL),
|
changed_values_only(_changed_values_only), last_post(NULL),
|
||||||
revalued_account(NULL, _("<Revalued>")),
|
revalued_account(temps.create_account(_("<Revalued>"))),
|
||||||
rounding_account(NULL, _("<Rounding>")){
|
rounding_account(temps.create_account(_("<Rounding>"))) {
|
||||||
TRACE_CTOR(changed_value_posts,
|
TRACE_CTOR(changed_value_posts,
|
||||||
"post_handler_ptr, const expr_t&, const expr_t&, report_t&, bool");
|
"post_handler_ptr, const expr_t&, const expr_t&, report_t&, bool");
|
||||||
}
|
}
|
||||||
virtual ~changed_value_posts() {
|
virtual ~changed_value_posts() {
|
||||||
TRACE_DTOR(changed_value_posts);
|
TRACE_DTOR(changed_value_posts);
|
||||||
clear_xacts_posts(xact_temps);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void flush();
|
virtual void flush();
|
||||||
|
|
@ -517,8 +505,7 @@ protected:
|
||||||
expr_t& amount_expr;
|
expr_t& amount_expr;
|
||||||
values_map values;
|
values_map values;
|
||||||
optional<string> date_format;
|
optional<string> date_format;
|
||||||
std::list<xact_t> xact_temps;
|
temporaries_t temps;
|
||||||
std::list<post_t> post_temps;
|
|
||||||
std::list<post_t *> component_posts;
|
std::list<post_t *> component_posts;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -531,7 +518,6 @@ public:
|
||||||
}
|
}
|
||||||
virtual ~subtotal_posts() {
|
virtual ~subtotal_posts() {
|
||||||
TRACE_DTOR(subtotal_posts);
|
TRACE_DTOR(subtotal_posts);
|
||||||
clear_xacts_posts(xact_temps);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void report_subtotal(const char * spec_fmt = NULL,
|
void report_subtotal(const char * spec_fmt = NULL,
|
||||||
|
|
@ -555,7 +541,7 @@ class interval_posts : public subtotal_posts
|
||||||
date_interval_t interval;
|
date_interval_t interval;
|
||||||
date_interval_t last_interval;
|
date_interval_t last_interval;
|
||||||
post_t * last_post;
|
post_t * last_post;
|
||||||
account_t empty_account;
|
account_t& empty_account;
|
||||||
bool exact_periods;
|
bool exact_periods;
|
||||||
bool generate_empty_posts;
|
bool generate_empty_posts;
|
||||||
|
|
||||||
|
|
@ -569,11 +555,11 @@ public:
|
||||||
bool _exact_periods = false,
|
bool _exact_periods = false,
|
||||||
bool _generate_empty_posts = false)
|
bool _generate_empty_posts = false)
|
||||||
: subtotal_posts(_handler, amount_expr), interval(_interval),
|
: subtotal_posts(_handler, amount_expr), interval(_interval),
|
||||||
last_post(NULL), empty_account(NULL, _("<None>")),
|
last_post(NULL), empty_account(temps.create_account(_("<None>"))),
|
||||||
exact_periods(_exact_periods),
|
exact_periods(_exact_periods),
|
||||||
generate_empty_posts(_generate_empty_posts) {
|
generate_empty_posts(_generate_empty_posts) {
|
||||||
TRACE_CTOR(interval_posts,
|
TRACE_CTOR(interval_posts,
|
||||||
"post_handler_ptr, expr_t&, interval_t, account_t *, bool, bool");
|
"post_handler_ptr, expr_t&, date_interval_t, bool, bool");
|
||||||
}
|
}
|
||||||
virtual ~interval_posts() throw() {
|
virtual ~interval_posts() throw() {
|
||||||
TRACE_DTOR(interval_posts);
|
TRACE_DTOR(interval_posts);
|
||||||
|
|
@ -594,7 +580,7 @@ public:
|
||||||
class posts_as_equity : public subtotal_posts
|
class posts_as_equity : public subtotal_posts
|
||||||
{
|
{
|
||||||
post_t * last_post;
|
post_t * last_post;
|
||||||
account_t equity_account;
|
account_t& equity_account;
|
||||||
account_t * balance_account;
|
account_t * balance_account;
|
||||||
|
|
||||||
posts_as_equity();
|
posts_as_equity();
|
||||||
|
|
@ -602,7 +588,7 @@ class posts_as_equity : public subtotal_posts
|
||||||
public:
|
public:
|
||||||
posts_as_equity(post_handler_ptr _handler, expr_t& amount_expr)
|
posts_as_equity(post_handler_ptr _handler, expr_t& amount_expr)
|
||||||
: subtotal_posts(_handler, amount_expr),
|
: subtotal_posts(_handler, amount_expr),
|
||||||
equity_account(NULL, _("Equity")) {
|
equity_account(temps.create_account(_("Equity"))) {
|
||||||
TRACE_CTOR(posts_as_equity, "post_handler_ptr, expr_t&");
|
TRACE_CTOR(posts_as_equity, "post_handler_ptr, expr_t&");
|
||||||
balance_account = equity_account.find_account(_("Opening Balances"));
|
balance_account = equity_account.find_account(_("Opening Balances"));
|
||||||
}
|
}
|
||||||
|
|
@ -653,11 +639,10 @@ class by_payee_posts : public item_handler<post_t>
|
||||||
*/
|
*/
|
||||||
class transfer_details : public item_handler<post_t>
|
class transfer_details : public item_handler<post_t>
|
||||||
{
|
{
|
||||||
std::list<xact_t> xact_temps;
|
|
||||||
std::list<post_t> post_temps;
|
|
||||||
account_t * master;
|
account_t * master;
|
||||||
expr_t expr;
|
expr_t expr;
|
||||||
scope_t& scope;
|
scope_t& scope;
|
||||||
|
temporaries_t temps;
|
||||||
|
|
||||||
transfer_details();
|
transfer_details();
|
||||||
|
|
||||||
|
|
@ -679,7 +664,6 @@ public:
|
||||||
}
|
}
|
||||||
virtual ~transfer_details() {
|
virtual ~transfer_details() {
|
||||||
TRACE_DTOR(transfer_details);
|
TRACE_DTOR(transfer_details);
|
||||||
clear_xacts_posts(xact_temps);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void operator()(post_t& post);
|
virtual void operator()(post_t& post);
|
||||||
|
|
@ -725,8 +709,7 @@ protected:
|
||||||
typedef std::list<pending_posts_pair> pending_posts_list;
|
typedef std::list<pending_posts_pair> pending_posts_list;
|
||||||
|
|
||||||
pending_posts_list pending_posts;
|
pending_posts_list pending_posts;
|
||||||
std::list<xact_t> xact_temps;
|
temporaries_t temps;
|
||||||
std::list<post_t> post_temps;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
generate_posts(post_handler_ptr handler)
|
generate_posts(post_handler_ptr handler)
|
||||||
|
|
@ -736,7 +719,6 @@ public:
|
||||||
|
|
||||||
virtual ~generate_posts() {
|
virtual ~generate_posts() {
|
||||||
TRACE_DTOR(generate_posts);
|
TRACE_DTOR(generate_posts);
|
||||||
clear_xacts_posts(xact_temps);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_period_xacts(period_xacts_list& period_xacts);
|
void add_period_xacts(period_xacts_list& period_xacts);
|
||||||
|
|
@ -754,6 +736,7 @@ class budget_posts : public generate_posts
|
||||||
#define BUDGET_NO_BUDGET 0x00
|
#define BUDGET_NO_BUDGET 0x00
|
||||||
#define BUDGET_BUDGETED 0x01
|
#define BUDGET_BUDGETED 0x01
|
||||||
#define BUDGET_UNBUDGETED 0x02
|
#define BUDGET_UNBUDGETED 0x02
|
||||||
|
#define BUDGET_WRAP_VALUES 0x04
|
||||||
|
|
||||||
uint_least8_t flags;
|
uint_least8_t flags;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,7 @@ class item_t : public supports_flags<>, public scope_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
#define ITEM_NORMAL 0x00 // no flags at all, a basic posting
|
#define ITEM_NORMAL 0x00 // no flags at all, a basic posting
|
||||||
|
// jww (2009-10-27): I'm not consistent on the difference between these two.
|
||||||
#define ITEM_GENERATED 0x01 // posting was not found in a journal
|
#define ITEM_GENERATED 0x01 // posting was not found in a journal
|
||||||
#define ITEM_TEMP 0x02 // posting is a temporary object
|
#define ITEM_TEMP 0x02 // posting is a temporary object
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -637,7 +637,7 @@ bool expr_t::op_t::print(std::ostream& out, const context_t& context) const
|
||||||
void expr_t::op_t::dump(std::ostream& out, const int depth) const
|
void expr_t::op_t::dump(std::ostream& out, const int depth) const
|
||||||
{
|
{
|
||||||
out.setf(std::ios::left);
|
out.setf(std::ios::left);
|
||||||
out.width(10);
|
out.width((sizeof(void *) * 2) + 2);
|
||||||
out << this;
|
out << this;
|
||||||
|
|
||||||
for (int i = 0; i < depth; i++)
|
for (int i = 0; i < depth; i++)
|
||||||
|
|
|
||||||
|
|
@ -169,7 +169,7 @@ format_accounts::mark_accounts(account_t& account, const bool flat)
|
||||||
|
|
||||||
#if defined(DEBUG_ON)
|
#if defined(DEBUG_ON)
|
||||||
DEBUG("account.display", "Considering account: " << account.fullname());
|
DEBUG("account.display", "Considering account: " << account.fullname());
|
||||||
if (account.has_flags(ACCOUNT_EXT_VISITED))
|
if (account.has_xflags(ACCOUNT_EXT_VISITED))
|
||||||
DEBUG("account.display", " it was visited itself");
|
DEBUG("account.display", " it was visited itself");
|
||||||
DEBUG("account.display", " it has " << visited << " visited children");
|
DEBUG("account.display", " it has " << visited << " visited children");
|
||||||
DEBUG("account.display",
|
DEBUG("account.display",
|
||||||
|
|
@ -177,11 +177,11 @@ format_accounts::mark_accounts(account_t& account, const bool flat)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (account.parent &&
|
if (account.parent &&
|
||||||
(account.has_flags(ACCOUNT_EXT_VISITED) || (! flat && visited > 0))) {
|
(account.has_xflags(ACCOUNT_EXT_VISITED) || (! flat && visited > 0))) {
|
||||||
bind_scope_t bound_scope(report, account);
|
bind_scope_t bound_scope(report, account);
|
||||||
if ((! flat && to_display > 1) ||
|
if ((! flat && to_display > 1) ||
|
||||||
((flat || to_display != 1 ||
|
((flat || to_display != 1 ||
|
||||||
account.has_flags(ACCOUNT_EXT_VISITED)) &&
|
account.has_xflags(ACCOUNT_EXT_VISITED)) &&
|
||||||
disp_pred(bound_scope))) {
|
disp_pred(bound_scope))) {
|
||||||
account.xdata().add_flags(ACCOUNT_EXT_TO_DISPLAY);
|
account.xdata().add_flags(ACCOUNT_EXT_TO_DISPLAY);
|
||||||
DEBUG("account.display", "Marking account as TO_DISPLAY");
|
DEBUG("account.display", "Marking account as TO_DISPLAY");
|
||||||
|
|
|
||||||
22
src/post.cc
22
src/post.cc
|
|
@ -141,6 +141,16 @@ namespace {
|
||||||
return string_value(post.xact->payee);
|
return string_value(post.xact->payee);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
value_t get_magnitude(post_t& post) {
|
||||||
|
return post.xact->magnitude();
|
||||||
|
}
|
||||||
|
value_t get_idstring(post_t& post) {
|
||||||
|
return string_value(post.xact->idstring());
|
||||||
|
}
|
||||||
|
value_t get_id(post_t& post) {
|
||||||
|
return string_value(post.xact->id());
|
||||||
|
}
|
||||||
|
|
||||||
value_t get_amount(post_t& post) {
|
value_t get_amount(post_t& post) {
|
||||||
if (post.has_xdata() && post.xdata().has_flags(POST_EXT_COMPOUND))
|
if (post.has_xdata() && post.xdata().has_flags(POST_EXT_COMPOUND))
|
||||||
return post.xdata().compound_value;
|
return post.xdata().compound_value;
|
||||||
|
|
@ -296,6 +306,18 @@ expr_t::ptr_op_t post_t::lookup(const string& name)
|
||||||
return WRAP_FUNCTOR(get_wrapper<&get_has_cost>);
|
return WRAP_FUNCTOR(get_wrapper<&get_has_cost>);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'i':
|
||||||
|
if (name == "id")
|
||||||
|
return WRAP_FUNCTOR(get_wrapper<&get_id>);
|
||||||
|
else if (name == "idstring")
|
||||||
|
return WRAP_FUNCTOR(get_wrapper<&get_idstring>);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'm':
|
||||||
|
if (name == "magnitude")
|
||||||
|
return WRAP_FUNCTOR(get_wrapper<&get_magnitude>);
|
||||||
|
break;
|
||||||
|
|
||||||
case 'p':
|
case 'p':
|
||||||
if (name == "post")
|
if (name == "post")
|
||||||
return WRAP_FUNCTOR(get_wrapper<&get_this>);
|
return WRAP_FUNCTOR(get_wrapper<&get_this>);
|
||||||
|
|
|
||||||
|
|
@ -77,8 +77,13 @@ void report_t::xact_report(post_handler_ptr handler, xact_t& xact)
|
||||||
void report_t::accounts_report(acct_handler_ptr handler)
|
void report_t::accounts_report(acct_handler_ptr handler)
|
||||||
{
|
{
|
||||||
journal_posts_iterator walker(*session.journal.get());
|
journal_posts_iterator walker(*session.journal.get());
|
||||||
pass_down_posts(chain_post_handlers(*this, post_handler_ptr(new ignore_posts),
|
|
||||||
true), walker);
|
// The lifetime of the chain object controls the lifetime of all temporary
|
||||||
|
// objects created within it during the call to pass_down_posts, which will
|
||||||
|
// be needed later by the pass_down_accounts.
|
||||||
|
post_handler_ptr chain =
|
||||||
|
chain_post_handlers(*this, post_handler_ptr(new ignore_posts), true);
|
||||||
|
pass_down_posts(chain, walker);
|
||||||
|
|
||||||
scoped_ptr<accounts_iterator> iter;
|
scoped_ptr<accounts_iterator> iter;
|
||||||
if (! HANDLED(sort_)) {
|
if (! HANDLED(sort_)) {
|
||||||
|
|
@ -695,19 +700,42 @@ expr_t::ptr_op_t report_t::lookup(const string& name)
|
||||||
if (WANT_CMD()) { const char * q = p + CMD_PREFIX_LEN;
|
if (WANT_CMD()) { const char * q = p + CMD_PREFIX_LEN;
|
||||||
switch (*q) {
|
switch (*q) {
|
||||||
case 'b':
|
case 'b':
|
||||||
if (*(q + 1) == '\0' || is_eq(q, "bal") || is_eq(q, "balance"))
|
if (*(q + 1) == '\0' || is_eq(q, "bal") || is_eq(q, "balance")) {
|
||||||
return expr_t::op_t::wrap_functor
|
return expr_t::op_t::wrap_functor
|
||||||
(reporter<account_t, acct_handler_ptr, &report_t::accounts_report>
|
(reporter<account_t, acct_handler_ptr, &report_t::accounts_report>
|
||||||
(new format_accounts(*this, report_format(HANDLER(balance_format_))),
|
(new format_accounts(*this, report_format(HANDLER(balance_format_))),
|
||||||
*this, "#balance"));
|
*this, "#balance"));
|
||||||
|
}
|
||||||
|
else if (is_eq(q, "budget")) {
|
||||||
|
HANDLER(amount_).set_expr(string("#budget"), "(amount, 0)");
|
||||||
|
|
||||||
|
budget_flags |= BUDGET_WRAP_VALUES;
|
||||||
|
if (! (budget_flags & ~BUDGET_WRAP_VALUES))
|
||||||
|
budget_flags |= BUDGET_BUDGETED;
|
||||||
|
|
||||||
|
return expr_t::op_t::wrap_functor
|
||||||
|
(reporter<account_t, acct_handler_ptr, &report_t::accounts_report>
|
||||||
|
(new format_accounts(*this, report_format(HANDLER(budget_format_))),
|
||||||
|
*this, "#budget"));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'c':
|
case 'c':
|
||||||
if (is_eq(q, "csv"))
|
if (is_eq(q, "csv")) {
|
||||||
return WRAP_FUNCTOR
|
return WRAP_FUNCTOR
|
||||||
(reporter<>
|
(reporter<>
|
||||||
(new format_posts(*this, report_format(HANDLER(csv_format_))),
|
(new format_posts(*this, report_format(HANDLER(csv_format_))),
|
||||||
*this, "#csv"));
|
*this, "#csv"));
|
||||||
|
}
|
||||||
|
else if (is_eq(q, "cleared")) {
|
||||||
|
HANDLER(amount_).set_expr(string("#cleared"),
|
||||||
|
"(amount, cleared ? amount : 0)");
|
||||||
|
|
||||||
|
return expr_t::op_t::wrap_functor
|
||||||
|
(reporter<account_t, acct_handler_ptr, &report_t::accounts_report>
|
||||||
|
(new format_accounts(*this, report_format(HANDLER(cleared_format_))),
|
||||||
|
*this, "#cleared"));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'e':
|
case 'e':
|
||||||
|
|
|
||||||
38
src/report.h
38
src/report.h
|
|
@ -120,6 +120,7 @@ public:
|
||||||
#define BUDGET_NO_BUDGET 0x00
|
#define BUDGET_NO_BUDGET 0x00
|
||||||
#define BUDGET_BUDGETED 0x01
|
#define BUDGET_BUDGETED 0x01
|
||||||
#define BUDGET_UNBUDGETED 0x02
|
#define BUDGET_UNBUDGETED 0x02
|
||||||
|
#define BUDGET_WRAP_VALUES 0x04
|
||||||
|
|
||||||
datetime_t terminus;
|
datetime_t terminus;
|
||||||
uint_least8_t budget_flags;
|
uint_least8_t budget_flags;
|
||||||
|
|
@ -205,8 +206,10 @@ public:
|
||||||
HANDLER(basis).report(out);
|
HANDLER(basis).report(out);
|
||||||
HANDLER(begin_).report(out);
|
HANDLER(begin_).report(out);
|
||||||
HANDLER(budget).report(out);
|
HANDLER(budget).report(out);
|
||||||
|
HANDLER(budget_format_).report(out);
|
||||||
HANDLER(by_payee).report(out);
|
HANDLER(by_payee).report(out);
|
||||||
HANDLER(cleared).report(out);
|
HANDLER(cleared).report(out);
|
||||||
|
HANDLER(cleared_format_).report(out);
|
||||||
HANDLER(code_as_payee).report(out);
|
HANDLER(code_as_payee).report(out);
|
||||||
HANDLER(comm_as_payee).report(out);
|
HANDLER(comm_as_payee).report(out);
|
||||||
HANDLER(code_as_account).report(out);
|
HANDLER(code_as_account).report(out);
|
||||||
|
|
@ -314,7 +317,7 @@ public:
|
||||||
});
|
});
|
||||||
|
|
||||||
OPTION_(report_t, add_budget, DO() {
|
OPTION_(report_t, add_budget, DO() {
|
||||||
parent->budget_flags = BUDGET_BUDGETED | BUDGET_UNBUDGETED;
|
parent->budget_flags |= BUDGET_BUDGETED | BUDGET_UNBUDGETED;
|
||||||
});
|
});
|
||||||
|
|
||||||
OPTION__
|
OPTION__
|
||||||
|
|
@ -368,7 +371,23 @@ public:
|
||||||
});
|
});
|
||||||
|
|
||||||
OPTION_(report_t, budget, DO() {
|
OPTION_(report_t, budget, DO() {
|
||||||
parent->budget_flags = BUDGET_BUDGETED;
|
parent->budget_flags |= BUDGET_BUDGETED;
|
||||||
|
});
|
||||||
|
|
||||||
|
OPTION__(report_t, budget_format_, CTOR(report_t, budget_format_) {
|
||||||
|
on(none,
|
||||||
|
"%(justify(scrub(get_at(total_expr, 0)), 12, -1, true, color))"
|
||||||
|
" %(justify(scrub(- get_at(total_expr, 1)), 12, -1, true, color))"
|
||||||
|
" %(justify(scrub(get_at(total_expr, 1) + get_at(total_expr, 0)), 12, -1, true, color))"
|
||||||
|
" %(justify(scrub((100% * get_at(total_expr, 0)) / - get_at(total_expr, 1)), 5, -1, true, color))"
|
||||||
|
" %(!options.flat ? depth_spacer : \"\")"
|
||||||
|
"%-(ansify_if(partial_account(options.flat), blue if color))\n"
|
||||||
|
"%/"
|
||||||
|
"%(justify(scrub(get_at(total_expr, 0)), 12, -1, true, color))"
|
||||||
|
" %(justify(scrub(- get_at(total_expr, 1)), 12, -1, true, color))"
|
||||||
|
" %(justify(scrub(get_at(total_expr, 1) + get_at(total_expr, 0)), 12, -1, true, color))"
|
||||||
|
" %(justify(scrub((100% * get_at(total_expr, 0)) / - get_at(total_expr, 1)), 5, -1, true, color))\n%/"
|
||||||
|
"------------ ------------ ------------ -----\n");
|
||||||
});
|
});
|
||||||
|
|
||||||
OPTION(report_t, by_payee); // -P
|
OPTION(report_t, by_payee); // -P
|
||||||
|
|
@ -377,6 +396,19 @@ public:
|
||||||
parent->HANDLER(limit_).on(string("--cleared"), "cleared");
|
parent->HANDLER(limit_).on(string("--cleared"), "cleared");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
OPTION__(report_t, cleared_format_, CTOR(report_t, cleared_format_) {
|
||||||
|
on(none,
|
||||||
|
"%(justify(scrub(get_at(total_expr, 0)), 16, -1, true, color))"
|
||||||
|
" %(justify(scrub(get_at(total_expr, 1)), 16, -1, true, color))"
|
||||||
|
" %(latest_cleared ? format_date(latest_cleared) : \" \")"
|
||||||
|
" %(!options.flat ? depth_spacer : \"\")"
|
||||||
|
"%-(ansify_if(partial_account(options.flat), blue if color))\n%/"
|
||||||
|
"%(justify(scrub(get_at(total_expr, 0)), 16, -1, true, color))"
|
||||||
|
" %(justify(scrub(get_at(total_expr, 1)), 16, -1, true, color))"
|
||||||
|
" %(latest_cleared ? format_date(latest_cleared) : \" \")\n%/"
|
||||||
|
"---------------- ---------------- ---------\n");
|
||||||
|
});
|
||||||
|
|
||||||
OPTION(report_t, code_as_payee);
|
OPTION(report_t, code_as_payee);
|
||||||
OPTION(report_t, comm_as_payee);
|
OPTION(report_t, comm_as_payee);
|
||||||
OPTION(report_t, code_as_account);
|
OPTION(report_t, code_as_account);
|
||||||
|
|
@ -772,7 +804,7 @@ public:
|
||||||
});
|
});
|
||||||
|
|
||||||
OPTION_(report_t, unbudgeted, DO() {
|
OPTION_(report_t, unbudgeted, DO() {
|
||||||
parent->budget_flags = BUDGET_UNBUDGETED;
|
parent->budget_flags |= BUDGET_UNBUDGETED;
|
||||||
});
|
});
|
||||||
|
|
||||||
OPTION_(report_t, uncleared, DO() { // -U
|
OPTION_(report_t, uncleared, DO() { // -U
|
||||||
|
|
|
||||||
124
src/temps.cc
Normal file
124
src/temps.cc
Normal file
|
|
@ -0,0 +1,124 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2003-2009, John Wiegley. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* - Neither the name of New Artisans LLC nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <system.hh>
|
||||||
|
|
||||||
|
#include "temps.h"
|
||||||
|
|
||||||
|
namespace ledger {
|
||||||
|
|
||||||
|
temporaries_t::~temporaries_t()
|
||||||
|
{
|
||||||
|
if (post_temps) {
|
||||||
|
foreach (post_t& post, *post_temps) {
|
||||||
|
if (! post.xact->has_flags(ITEM_TEMP))
|
||||||
|
post.xact->remove_post(&post);
|
||||||
|
|
||||||
|
if (! post.account->has_flags(ACCOUNT_TEMP))
|
||||||
|
post.account->remove_post(&post);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
xact_t& temporaries_t::copy_xact(xact_t& origin)
|
||||||
|
{
|
||||||
|
if (! xact_temps)
|
||||||
|
xact_temps = std::list<xact_t>();
|
||||||
|
|
||||||
|
xact_temps->push_back(origin);
|
||||||
|
xact_t& temp(xact_temps->back());
|
||||||
|
|
||||||
|
temp.add_flags(ITEM_TEMP);
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
xact_t& temporaries_t::create_xact()
|
||||||
|
{
|
||||||
|
if (! xact_temps)
|
||||||
|
xact_temps = std::list<xact_t>();
|
||||||
|
|
||||||
|
xact_temps->push_back(xact_t());
|
||||||
|
xact_t& temp(xact_temps->back());
|
||||||
|
|
||||||
|
temp.add_flags(ITEM_TEMP);
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
post_t& temporaries_t::copy_post(post_t& origin, xact_t& xact,
|
||||||
|
account_t * account)
|
||||||
|
{
|
||||||
|
if (! post_temps)
|
||||||
|
post_temps = std::list<post_t>();
|
||||||
|
|
||||||
|
post_temps->push_back(origin);
|
||||||
|
post_t& temp(post_temps->back());
|
||||||
|
|
||||||
|
if (account)
|
||||||
|
temp.account = account;
|
||||||
|
temp.add_flags(ITEM_TEMP);
|
||||||
|
|
||||||
|
temp.account->add_post(&temp);
|
||||||
|
xact.add_post(&temp);
|
||||||
|
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
post_t& temporaries_t::create_post(xact_t& xact, account_t * account)
|
||||||
|
{
|
||||||
|
if (! post_temps)
|
||||||
|
post_temps = std::list<post_t>();
|
||||||
|
|
||||||
|
post_temps->push_back(post_t(account));
|
||||||
|
post_t& temp(post_temps->back());
|
||||||
|
|
||||||
|
temp.account = account;
|
||||||
|
temp.add_flags(ITEM_TEMP);
|
||||||
|
|
||||||
|
temp.account->add_post(&temp);
|
||||||
|
xact.add_post(&temp);
|
||||||
|
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
account_t& temporaries_t::create_account(const string& name,
|
||||||
|
account_t * parent)
|
||||||
|
{
|
||||||
|
if (! acct_temps)
|
||||||
|
acct_temps = std::list<account_t>();
|
||||||
|
|
||||||
|
acct_temps->push_back(account_t(parent, name));
|
||||||
|
account_t& temp(acct_temps->back());
|
||||||
|
|
||||||
|
temp.add_flags(ACCOUNT_TEMP);
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ledger
|
||||||
84
src/temps.h
Normal file
84
src/temps.h
Normal file
|
|
@ -0,0 +1,84 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2003-2009, John Wiegley. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* - Neither the name of New Artisans LLC nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup report
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file temps.h
|
||||||
|
* @author John Wiegley
|
||||||
|
*
|
||||||
|
* @ingroup report
|
||||||
|
*
|
||||||
|
* @brief Brief
|
||||||
|
*
|
||||||
|
* Long.
|
||||||
|
*/
|
||||||
|
#ifndef _TEMPS_H
|
||||||
|
#define _TEMPS_H
|
||||||
|
|
||||||
|
#include "xact.h"
|
||||||
|
#include "post.h"
|
||||||
|
#include "account.h"
|
||||||
|
|
||||||
|
namespace ledger {
|
||||||
|
|
||||||
|
class temporaries_t
|
||||||
|
{
|
||||||
|
optional<std::list<xact_t> > xact_temps;
|
||||||
|
optional<std::list<post_t> > post_temps;
|
||||||
|
optional<std::list<account_t> > acct_temps;
|
||||||
|
|
||||||
|
public:
|
||||||
|
~temporaries_t();
|
||||||
|
|
||||||
|
xact_t& copy_xact(xact_t& origin);
|
||||||
|
xact_t& create_xact();
|
||||||
|
xact_t& last_xact() {
|
||||||
|
return xact_temps->back();
|
||||||
|
}
|
||||||
|
post_t& copy_post(post_t& origin, xact_t& xact,
|
||||||
|
account_t * account = NULL);
|
||||||
|
post_t& create_post(xact_t& xact, account_t * account);
|
||||||
|
post_t& last_post() {
|
||||||
|
return post_temps->back();
|
||||||
|
}
|
||||||
|
account_t& create_account(const string& name,
|
||||||
|
account_t * parent = NULL);
|
||||||
|
account_t& last_account() {
|
||||||
|
return acct_temps->back();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ledger
|
||||||
|
|
||||||
|
#endif // _TEMPS_H
|
||||||
|
|
@ -446,7 +446,7 @@ void instance_t::default_commodity_directive(char * line)
|
||||||
void instance_t::default_account_directive(char * line)
|
void instance_t::default_account_directive(char * line)
|
||||||
{
|
{
|
||||||
journal.basket = account_stack.front()->find_account(skip_ws(line + 1));
|
journal.basket = account_stack.front()->find_account(skip_ws(line + 1));
|
||||||
journal.basket->known = true;
|
journal.basket->add_flags(ACCOUNT_KNOWN);
|
||||||
}
|
}
|
||||||
|
|
||||||
void instance_t::price_conversion_directive(char * line)
|
void instance_t::price_conversion_directive(char * line)
|
||||||
|
|
@ -845,11 +845,11 @@ post_t * instance_t::parse_post(char * line,
|
||||||
if (! post->account)
|
if (! post->account)
|
||||||
post->account = account->find_account(name);
|
post->account = account->find_account(name);
|
||||||
|
|
||||||
if (honor_strict && strict && ! post->account->known) {
|
if (honor_strict && strict && ! post->account->has_flags(ACCOUNT_KNOWN)) {
|
||||||
if (post->_state == item_t::UNCLEARED)
|
if (post->_state == item_t::UNCLEARED)
|
||||||
warning_(_("\"%1\", line %2: Unknown account '%3'")
|
warning_(_("\"%1\", line %2: Unknown account '%3'")
|
||||||
<< pathname << linenum << post->account->fullname());
|
<< pathname << linenum << post->account->fullname());
|
||||||
post->account->known = true;
|
post->account->add_flags(ACCOUNT_KNOWN);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse the optional amount
|
// Parse the optional amount
|
||||||
|
|
|
||||||
|
|
@ -596,7 +596,7 @@ inline char peek_next_nonws(std::istream& in) {
|
||||||
*_p = '\0'; \
|
*_p = '\0'; \
|
||||||
}
|
}
|
||||||
|
|
||||||
inline string to_hex(uint_least32_t * message_digest)
|
inline string to_hex(uint_least32_t * message_digest, const int len = 1)
|
||||||
{
|
{
|
||||||
std::ostringstream buf;
|
std::ostringstream buf;
|
||||||
|
|
||||||
|
|
@ -604,7 +604,8 @@ inline string to_hex(uint_least32_t * message_digest)
|
||||||
buf.width(8);
|
buf.width(8);
|
||||||
buf.fill('0');
|
buf.fill('0');
|
||||||
buf << std::hex << message_digest[i];
|
buf << std::hex << message_digest[i];
|
||||||
break; // only output the first dword
|
if (i + 1 >= len)
|
||||||
|
break; // only output the first LEN dwords
|
||||||
}
|
}
|
||||||
return buf.str();
|
return buf.str();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
38
src/value.cc
38
src/value.cc
|
|
@ -254,7 +254,7 @@ value_t::sequence_t value_t::to_sequence() const
|
||||||
void value_t::in_place_simplify()
|
void value_t::in_place_simplify()
|
||||||
{
|
{
|
||||||
#if defined(DEBUG_ON)
|
#if defined(DEBUG_ON)
|
||||||
LOGGER("amounts.values.simplify");
|
LOGGER("value.simplify");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (is_realzero()) {
|
if (is_realzero()) {
|
||||||
|
|
@ -263,11 +263,11 @@ void value_t::in_place_simplify()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_balance() && as_balance().amounts.size() == 1) {
|
if (is_balance() && as_balance().single_amount()) {
|
||||||
DEBUG_("Reducing balance to amount");
|
DEBUG_("Reducing balance to amount");
|
||||||
DEBUG("ledger.value.reduce", "as a balance it looks like: " << *this);
|
DEBUG_("as a balance it looks like: " << *this);
|
||||||
in_place_cast(AMOUNT);
|
in_place_cast(AMOUNT);
|
||||||
DEBUG("ledger.value.reduce", "as an amount it looks like: " << *this);
|
DEBUG_("as an amount it looks like: " << *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef REDUCE_TO_INTEGER // this is off by default
|
#ifdef REDUCE_TO_INTEGER // this is off by default
|
||||||
|
|
@ -585,11 +585,12 @@ value_t& value_t::operator*=(const value_t& val)
|
||||||
as_amount_lval() *= val.as_long();
|
as_amount_lval() *= val.as_long();
|
||||||
return *this;
|
return *this;
|
||||||
case AMOUNT:
|
case AMOUNT:
|
||||||
if (as_amount().commodity() == val.as_amount().commodity() ||
|
|
||||||
! as_amount().has_commodity() ||
|
|
||||||
! val.as_amount().has_commodity()) {
|
|
||||||
as_amount_lval() *= val.as_amount();
|
as_amount_lval() *= val.as_amount();
|
||||||
return *this;
|
return *this;
|
||||||
|
case BALANCE:
|
||||||
|
if (val.as_balance().single_amount()) {
|
||||||
|
as_amount_lval() *= val.simplified().as_amount();
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
@ -603,7 +604,12 @@ value_t& value_t::operator*=(const value_t& val)
|
||||||
as_balance_lval() *= val.as_long();
|
as_balance_lval() *= val.as_long();
|
||||||
return *this;
|
return *this;
|
||||||
case AMOUNT:
|
case AMOUNT:
|
||||||
if (! val.as_amount().has_commodity()) {
|
if (as_balance().single_amount()) {
|
||||||
|
in_place_simplify();
|
||||||
|
as_amount_lval() *= val.as_amount();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
else if (! val.as_amount().has_commodity()) {
|
||||||
as_balance_lval() *= val.as_amount();
|
as_balance_lval() *= val.as_amount();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
@ -617,6 +623,9 @@ value_t& value_t::operator*=(const value_t& val)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEBUG("value.multiply.error", "Left: " << *this);
|
||||||
|
DEBUG("value.multiply.error", "Right: " << val);
|
||||||
|
|
||||||
throw_(value_error, _("Cannot multiply %1 with %2") << label() << val.label());
|
throw_(value_error, _("Cannot multiply %1 with %2") << label() << val.label());
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
|
|
@ -647,6 +656,12 @@ value_t& value_t::operator/=(const value_t& val)
|
||||||
case AMOUNT:
|
case AMOUNT:
|
||||||
as_amount_lval() /= val.as_amount();
|
as_amount_lval() /= val.as_amount();
|
||||||
return *this;
|
return *this;
|
||||||
|
case BALANCE:
|
||||||
|
if (val.as_balance().single_amount()) {
|
||||||
|
as_amount_lval() /= val.simplified().as_amount();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -658,7 +673,12 @@ value_t& value_t::operator/=(const value_t& val)
|
||||||
as_balance_lval() /= val.as_long();
|
as_balance_lval() /= val.as_long();
|
||||||
return *this;
|
return *this;
|
||||||
case AMOUNT:
|
case AMOUNT:
|
||||||
if (! val.as_amount().has_commodity()) {
|
if (as_balance().single_amount()) {
|
||||||
|
in_place_simplify();
|
||||||
|
as_amount_lval() /= val.as_amount();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
else if (! val.as_amount().has_commodity()) {
|
||||||
as_balance_lval() /= val.as_amount();
|
as_balance_lval() /= val.as_amount();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
55
src/xact.cc
55
src/xact.cc
|
|
@ -163,11 +163,14 @@ bool xact_base_t::finalize()
|
||||||
null_post->amount = balance.as_amount().negated();
|
null_post->amount = balance.as_amount().negated();
|
||||||
null_post->add_flags(POST_CALCULATED);
|
null_post->add_flags(POST_CALCULATED);
|
||||||
}
|
}
|
||||||
|
else if (balance.is_long()) {
|
||||||
|
null_post->amount = amount_t(- balance.as_long());
|
||||||
|
null_post->add_flags(POST_CALCULATED);
|
||||||
|
}
|
||||||
else if (! balance.is_null() && ! balance.is_realzero()) {
|
else if (! balance.is_null() && ! balance.is_realzero()) {
|
||||||
throw_(balance_error, _("Transaction does not balance"));
|
throw_(balance_error, _("Transaction does not balance"));
|
||||||
}
|
}
|
||||||
balance = NULL_VALUE;
|
balance = NULL_VALUE;
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (balance.is_balance() &&
|
else if (balance.is_balance() &&
|
||||||
balance.as_balance().amounts.size() == 2) {
|
balance.as_balance().amounts.size() == 2) {
|
||||||
|
|
@ -314,6 +317,7 @@ bool xact_base_t::finalize()
|
||||||
if (dynamic_cast<xact_t *>(this)) {
|
if (dynamic_cast<xact_t *>(this)) {
|
||||||
bool all_null = true;
|
bool all_null = true;
|
||||||
bool some_null = false;
|
bool some_null = false;
|
||||||
|
|
||||||
foreach (post_t * post, posts) {
|
foreach (post_t * post, posts) {
|
||||||
if (! post->amount.is_null()) {
|
if (! post->amount.is_null()) {
|
||||||
all_null = false;
|
all_null = false;
|
||||||
|
|
@ -327,6 +331,7 @@ bool xact_base_t::finalize()
|
||||||
post->xdata().add_flags(POST_EXT_VISITED);
|
post->xdata().add_flags(POST_EXT_VISITED);
|
||||||
post->account->xdata().add_flags(ACCOUNT_EXT_VISITED);
|
post->account->xdata().add_flags(ACCOUNT_EXT_VISITED);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (all_null)
|
if (all_null)
|
||||||
return false; // ignore this xact completely
|
return false; // ignore this xact completely
|
||||||
else if (some_null)
|
else if (some_null)
|
||||||
|
|
@ -351,32 +356,48 @@ void xact_t::add_post(post_t * post)
|
||||||
xact_base_t::add_post(post);
|
xact_base_t::add_post(post);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
value_t xact_t::magnitude() const
|
||||||
value_t get_magnitude(xact_t& xact) {
|
{
|
||||||
balance_t halfbal;
|
value_t halfbal = 0L;
|
||||||
foreach (post_t * post, xact.posts)
|
foreach (const post_t * post, posts) {
|
||||||
if (post->amount.sign() > 0)
|
if (post->amount.sign() > 0) {
|
||||||
|
if (post->cost)
|
||||||
|
halfbal += post->cost->number();
|
||||||
|
else
|
||||||
halfbal += post->amount.number();
|
halfbal += post->amount.number();
|
||||||
|
}
|
||||||
|
}
|
||||||
return halfbal;
|
return halfbal;
|
||||||
}
|
}
|
||||||
|
|
||||||
value_t get_idstring(xact_t& xact) {
|
string xact_t::idstring() const
|
||||||
|
{
|
||||||
std::ostringstream buf;
|
std::ostringstream buf;
|
||||||
buf << *xact._date;
|
buf << format_date(*_date, FMT_WRITTEN);
|
||||||
buf << xact.payee;
|
buf << payee;
|
||||||
|
magnitude().print(buf);
|
||||||
get_magnitude(xact).print(buf);
|
return buf.str();
|
||||||
|
|
||||||
return string_value(buf.str());
|
|
||||||
}
|
}
|
||||||
value_t get_id(xact_t& xact) {
|
|
||||||
|
string xact_t::id() const
|
||||||
|
{
|
||||||
SHA1 sha;
|
SHA1 sha;
|
||||||
sha.Reset();
|
sha.Reset();
|
||||||
sha << get_idstring(xact).as_string().c_str();
|
sha << idstring().c_str();
|
||||||
|
|
||||||
uint_least32_t message_digest[5];
|
uint_least32_t message_digest[5];
|
||||||
sha.Result(message_digest);
|
sha.Result(message_digest);
|
||||||
return string_value(to_hex(message_digest));
|
return to_hex(message_digest, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
value_t get_magnitude(xact_t& xact) {
|
||||||
|
return xact.magnitude();
|
||||||
|
}
|
||||||
|
value_t get_idstring(xact_t& xact) {
|
||||||
|
return string_value(xact.idstring());
|
||||||
|
}
|
||||||
|
value_t get_id(xact_t& xact) {
|
||||||
|
return string_value(xact.id());
|
||||||
}
|
}
|
||||||
|
|
||||||
value_t get_code(xact_t& xact) {
|
value_t get_code(xact_t& xact) {
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,10 @@ public:
|
||||||
|
|
||||||
virtual void add_post(post_t * post);
|
virtual void add_post(post_t * post);
|
||||||
|
|
||||||
|
value_t magnitude() const;
|
||||||
|
string idstring() const;
|
||||||
|
string id() const;
|
||||||
|
|
||||||
virtual expr_t::ptr_op_t lookup(const string& name);
|
virtual expr_t::ptr_op_t lookup(const string& name);
|
||||||
|
|
||||||
virtual bool valid() const;
|
virtual bool valid() const;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue