added several kinds of transaction filters
This commit is contained in:
parent
ec73e300e8
commit
3edf298633
5 changed files with 427 additions and 236 deletions
93
format.cc
93
format.cc
|
|
@ -312,99 +312,6 @@ void format_t::format_elements(std::ostream& out,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef COLLAPSED_REGISTER
|
|
||||||
|
|
||||||
void format_transaction::report_cumulative_subtotal() const
|
|
||||||
{
|
|
||||||
if (count == 1) {
|
|
||||||
first_line_format.format_elements(output_stream, details_t(last_xact));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(count > 1);
|
|
||||||
|
|
||||||
account_t splits(NULL, "<Total>");
|
|
||||||
transaction_t splits_total(NULL, &splits);
|
|
||||||
splits_total.total = subtotal;
|
|
||||||
|
|
||||||
balance_t value;
|
|
||||||
format_t::compute_total(value, details_t(&splits_total));
|
|
||||||
|
|
||||||
splits_total.entry = last_entry;
|
|
||||||
splits_total.total = last_xact->total;
|
|
||||||
|
|
||||||
bool first = true;
|
|
||||||
for (amounts_map::const_iterator i = value.amounts.begin();
|
|
||||||
i != value.amounts.end();
|
|
||||||
i++) {
|
|
||||||
splits_total.amount = (*i).second;
|
|
||||||
splits_total.cost = (*i).second;
|
|
||||||
splits_total.total += (*i).second;
|
|
||||||
if (first) {
|
|
||||||
first_line_format.format_elements(output_stream,
|
|
||||||
details_t(&splits_total));
|
|
||||||
first = false;
|
|
||||||
} else {
|
|
||||||
next_lines_format.format_elements(output_stream,
|
|
||||||
details_t(&splits_total));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // COLLAPSED_REGISTER
|
|
||||||
|
|
||||||
void format_transaction::operator()(transaction_t * xact) const
|
|
||||||
{
|
|
||||||
if (last_xact)
|
|
||||||
xact->total += last_xact->total;
|
|
||||||
|
|
||||||
if (inverted) {
|
|
||||||
xact->amount.negate();
|
|
||||||
xact->cost.negate();
|
|
||||||
}
|
|
||||||
|
|
||||||
xact->total += *xact;
|
|
||||||
xact->index = last_xact ? last_xact->index + 1 : 0;
|
|
||||||
|
|
||||||
if (disp_pred(xact)) {
|
|
||||||
xact->dflags |= TRANSACTION_DISPLAYED;
|
|
||||||
|
|
||||||
// This makes the assumption that transactions from a single entry
|
|
||||||
// are always grouped together.
|
|
||||||
|
|
||||||
#ifdef COLLAPSED_REGISTER
|
|
||||||
if (collapsed) {
|
|
||||||
// If we've reached a new entry, report on the subtotal
|
|
||||||
// accumulated thus far.
|
|
||||||
|
|
||||||
if (last_entry && last_entry != xact->entry) {
|
|
||||||
report_cumulative_subtotal();
|
|
||||||
subtotal = 0;
|
|
||||||
count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
subtotal += *xact;
|
|
||||||
count++;
|
|
||||||
} else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
if (last_entry != xact->entry) {
|
|
||||||
first_line_format.format_elements(output_stream, details_t(xact));
|
|
||||||
} else {
|
|
||||||
next_lines_format.format_elements(output_stream, details_t(xact));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inverted) {
|
|
||||||
xact->amount.negate();
|
|
||||||
xact->cost.negate();
|
|
||||||
}
|
|
||||||
|
|
||||||
last_entry = xact->entry;
|
|
||||||
last_xact = xact;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool format_account::disp_subaccounts_p(const account_t * account,
|
bool format_account::disp_subaccounts_p(const account_t * account,
|
||||||
const item_predicate<account_t>&
|
const item_predicate<account_t>&
|
||||||
disp_pred,
|
disp_pred,
|
||||||
|
|
|
||||||
139
format.h
139
format.h
|
|
@ -83,133 +83,45 @@ struct format_t
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
class format_transactions : public item_handler<transaction_t>
|
||||||
struct item_formatter : public item_handler<T> {
|
|
||||||
virtual ~item_formatter() {}
|
|
||||||
virtual void flush() const = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define COLLAPSED_REGISTER 1 // support collapsed registers
|
|
||||||
|
|
||||||
class format_transaction : public item_formatter<transaction_t>
|
|
||||||
{
|
{
|
||||||
std::ostream& output_stream;
|
std::ostream& output_stream;
|
||||||
const format_t& first_line_format;
|
const format_t& first_line_format;
|
||||||
const format_t& next_lines_format;
|
const format_t& next_lines_format;
|
||||||
#ifdef COLLAPSED_REGISTER
|
entry_t * last_entry;
|
||||||
const bool collapsed;
|
|
||||||
#endif
|
|
||||||
const bool inverted;
|
|
||||||
|
|
||||||
item_predicate<transaction_t> disp_pred;
|
|
||||||
|
|
||||||
#ifdef COLLAPSED_REGISTER
|
|
||||||
mutable balance_pair_t subtotal;
|
|
||||||
mutable unsigned int count;
|
|
||||||
#endif
|
|
||||||
mutable entry_t * last_entry;
|
|
||||||
mutable transaction_t * last_xact;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
format_transaction(std::ostream& _output_stream,
|
format_transactions(std::ostream& _output_stream,
|
||||||
const format_t& _first_line_format,
|
const format_t& _first_line_format,
|
||||||
const format_t& _next_lines_format,
|
const format_t& _next_lines_format)
|
||||||
const std::string& display_predicate = NULL,
|
|
||||||
#ifdef COLLAPSED_REGISTER
|
|
||||||
const bool _collapsed = false,
|
|
||||||
#endif
|
|
||||||
const bool _inverted = false)
|
|
||||||
: output_stream(_output_stream),
|
: output_stream(_output_stream),
|
||||||
first_line_format(_first_line_format),
|
first_line_format(_first_line_format),
|
||||||
next_lines_format(_next_lines_format),
|
next_lines_format(_next_lines_format), last_entry(NULL) {}
|
||||||
#ifdef COLLAPSED_REGISTER
|
|
||||||
collapsed(_collapsed),
|
|
||||||
#endif
|
|
||||||
inverted(_inverted), disp_pred(display_predicate),
|
|
||||||
#ifdef COLLAPSED_REGISTER
|
|
||||||
count(0),
|
|
||||||
#endif
|
|
||||||
last_entry(NULL), last_xact(NULL) {}
|
|
||||||
|
|
||||||
#ifdef COLLAPSED_REGISTER
|
virtual ~format_transactions() {
|
||||||
virtual ~format_transaction() {
|
|
||||||
flush();
|
flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void flush() const {
|
virtual void flush() {
|
||||||
if (subtotal)
|
|
||||||
report_cumulative_subtotal();
|
|
||||||
output_stream.flush();
|
output_stream.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
void report_cumulative_subtotal() const;
|
virtual void operator()(transaction_t * xact) {
|
||||||
#endif
|
xact->dflags |= TRANSACTION_DISPLAYED;
|
||||||
|
|
||||||
virtual void operator()(transaction_t * xact) const;
|
// This makes the assumption that transactions from a single entry
|
||||||
};
|
// are always grouped together.
|
||||||
|
|
||||||
|
if (last_entry != xact->entry)
|
||||||
|
first_line_format.format_elements(output_stream, details_t(xact));
|
||||||
|
else
|
||||||
|
next_lines_format.format_elements(output_stream, details_t(xact));
|
||||||
|
|
||||||
class changed_value_filter : public item_formatter<transaction_t>
|
last_entry = xact->entry;
|
||||||
{
|
|
||||||
item_formatter<transaction_t> * handler;
|
|
||||||
|
|
||||||
mutable entry_t modified_entry;
|
|
||||||
mutable transaction_t modified_xact;
|
|
||||||
mutable transaction_t * last_xact;
|
|
||||||
|
|
||||||
public:
|
|
||||||
changed_value_filter(item_formatter<transaction_t> * _handler)
|
|
||||||
: handler(_handler), modified_xact(&modified_entry, NULL),
|
|
||||||
last_xact(NULL) {
|
|
||||||
assert(handler);
|
|
||||||
modified_entry.payee = "Commodities revalued";
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~changed_value_filter() {
|
|
||||||
flush();
|
|
||||||
handler->flush();
|
|
||||||
assert(handler);
|
|
||||||
delete handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void flush() const {
|
|
||||||
(*this)(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void operator()(transaction_t * xact) const {
|
|
||||||
if (last_xact) {
|
|
||||||
balance_t prev_bal, cur_bal;
|
|
||||||
|
|
||||||
format_t::compute_total(prev_bal, details_t(last_xact));
|
|
||||||
|
|
||||||
std::time_t current = xact ? xact->entry->date : std::time(NULL);
|
|
||||||
std::time_t prev_date = last_xact->entry->date;
|
|
||||||
last_xact->entry->date = current;
|
|
||||||
format_t::compute_total(cur_bal, details_t(last_xact));
|
|
||||||
last_xact->entry->date = prev_date;
|
|
||||||
|
|
||||||
if (balance_t diff = cur_bal - prev_bal) {
|
|
||||||
modified_entry.date = current;
|
|
||||||
|
|
||||||
// jww (2004-08-07): What if there are multiple commodities?
|
|
||||||
assert(diff.amounts.size() == 1);
|
|
||||||
modified_xact.amount = diff.amount();
|
|
||||||
modified_xact.total = diff;
|
|
||||||
modified_xact.total.negate();
|
|
||||||
|
|
||||||
(*handler)(&modified_xact);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (xact)
|
|
||||||
(*handler)(xact);
|
|
||||||
|
|
||||||
last_xact = xact;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class format_account : public item_handler<account_t>
|
||||||
class format_account : public item_formatter<account_t>
|
|
||||||
{
|
{
|
||||||
std::ostream& output_stream;
|
std::ostream& output_stream;
|
||||||
const format_t& format;
|
const format_t& format;
|
||||||
|
|
@ -222,10 +134,9 @@ class format_account : public item_formatter<account_t>
|
||||||
const std::string& display_predicate = NULL)
|
const std::string& display_predicate = NULL)
|
||||||
: output_stream(_output_stream), format(_format),
|
: output_stream(_output_stream), format(_format),
|
||||||
disp_pred(display_predicate) {}
|
disp_pred(display_predicate) {}
|
||||||
virtual ~format_account() {}
|
|
||||||
|
|
||||||
virtual void flush() const {
|
virtual ~format_account() {
|
||||||
output_stream.flush();
|
flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool disp_subaccounts_p(const account_t * account,
|
static bool disp_subaccounts_p(const account_t * account,
|
||||||
|
|
@ -239,7 +150,11 @@ class format_account : public item_formatter<account_t>
|
||||||
static bool display_account(const account_t * account,
|
static bool display_account(const account_t * account,
|
||||||
const item_predicate<account_t>& disp_pred);
|
const item_predicate<account_t>& disp_pred);
|
||||||
|
|
||||||
virtual void operator()(account_t * account) const {
|
virtual void flush() {
|
||||||
|
output_stream.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void operator()(account_t * account) {
|
||||||
if (display_account(account, disp_pred)) {
|
if (display_account(account, disp_pred)) {
|
||||||
format.format_elements(output_stream, details_t(account));
|
format.format_elements(output_stream, details_t(account));
|
||||||
account->dflags |= ACCOUNT_DISPLAYED;
|
account->dflags |= ACCOUNT_DISPLAYED;
|
||||||
|
|
@ -248,7 +163,7 @@ class format_account : public item_formatter<account_t>
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class format_equity : public item_formatter<account_t>
|
class format_equity : public item_handler<account_t>
|
||||||
{
|
{
|
||||||
std::ostream& output_stream;
|
std::ostream& output_stream;
|
||||||
const format_t& first_line_format;
|
const format_t& first_line_format;
|
||||||
|
|
@ -277,14 +192,14 @@ class format_equity : public item_formatter<account_t>
|
||||||
flush();
|
flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void flush() const {
|
virtual void flush() {
|
||||||
account_t summary(NULL, "Equity:Opening Balances");
|
account_t summary(NULL, "Equity:Opening Balances");
|
||||||
summary.value = - total;
|
summary.value = - total;
|
||||||
next_lines_format.format_elements(output_stream, details_t(&summary));
|
next_lines_format.format_elements(output_stream, details_t(&summary));
|
||||||
output_stream.flush();
|
output_stream.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void operator()(account_t * account) const {
|
virtual void operator()(account_t * account) {
|
||||||
if (format_account::display_account(account, disp_pred)) {
|
if (format_account::display_account(account, disp_pred)) {
|
||||||
next_lines_format.format_elements(output_stream, details_t(account));
|
next_lines_format.format_elements(output_stream, details_t(account));
|
||||||
account->dflags |= ACCOUNT_DISPLAYED;
|
account->dflags |= ACCOUNT_DISPLAYED;
|
||||||
|
|
|
||||||
28
main.cc
28
main.cc
|
|
@ -607,7 +607,7 @@ int main(int argc, char * argv[])
|
||||||
xact_display_flags, true, sort_order.get());
|
xact_display_flags, true, sort_order.get());
|
||||||
}
|
}
|
||||||
else if (command == "e") {
|
else if (command == "e") {
|
||||||
format_transaction formatter(std::cout, format, nformat);
|
format_transactions formatter(std::cout, format, nformat);
|
||||||
|
|
||||||
for (transactions_list::iterator i = new_entry->transactions.begin();
|
for (transactions_list::iterator i = new_entry->transactions.begin();
|
||||||
i != new_entry->transactions.end();
|
i != new_entry->transactions.end();
|
||||||
|
|
@ -615,24 +615,32 @@ int main(int argc, char * argv[])
|
||||||
handle_transaction(*i, formatter, xact_display_flags);
|
handle_transaction(*i, formatter, xact_display_flags);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
std::auto_ptr<item_formatter<transaction_t> >
|
std::auto_ptr<item_handler<transaction_t> >
|
||||||
formatter(new format_transaction(std::cout, format, nformat,
|
formatter(new format_transactions(std::cout, format, nformat));
|
||||||
display_predicate,
|
|
||||||
#ifdef COLLAPSED_REGISTER
|
formatter.reset(new filter_transactions(formatter.release(),
|
||||||
! show_subtotals,
|
display_predicate));
|
||||||
#endif
|
formatter.reset(new calc_transactions(formatter.release(),
|
||||||
show_inverted));
|
show_inverted));
|
||||||
|
if (! show_subtotals)
|
||||||
|
formatter.reset(new collapse_transactions(formatter.release()));
|
||||||
|
if (show_expanded)
|
||||||
|
formatter.reset(new subtotal_transactions(formatter.release()));
|
||||||
|
#if 0
|
||||||
|
formatter.reset(new interval_transactions(formatter.release(),
|
||||||
|
0, 0, 9676800));
|
||||||
|
#endif
|
||||||
if (show_commodities_revalued)
|
if (show_commodities_revalued)
|
||||||
formatter.reset(new changed_value_filter(formatter.release()));
|
formatter.reset(new changed_value_transactions(formatter.release()));
|
||||||
|
|
||||||
if (! sort_order.get()) {
|
if (! sort_order.get()) {
|
||||||
walk_entries(journal->entries.begin(), journal->entries.end(),
|
walk_entries(journal->entries.begin(), journal->entries.end(),
|
||||||
*formatter.get(), predicate, xact_display_flags);
|
*formatter.get(), predicate, xact_display_flags);
|
||||||
} else {
|
} else {
|
||||||
transactions_deque transactions_pool;
|
transactions_deque transactions_pool;
|
||||||
|
collect_transactions handler(transactions_pool);
|
||||||
walk_entries(journal->entries.begin(), journal->entries.end(),
|
walk_entries(journal->entries.begin(), journal->entries.end(),
|
||||||
collect_transactions(transactions_pool), predicate,
|
handler, predicate, xact_display_flags);
|
||||||
xact_display_flags);
|
|
||||||
std::stable_sort(transactions_pool.begin(), transactions_pool.end(),
|
std::stable_sort(transactions_pool.begin(), transactions_pool.end(),
|
||||||
compare_items<transaction_t>(sort_order.get()));
|
compare_items<transaction_t>(sort_order.get()));
|
||||||
walk_transactions(transactions_pool.begin(), transactions_pool.end(),
|
walk_transactions(transactions_pool.begin(), transactions_pool.end(),
|
||||||
|
|
|
||||||
146
walk.cc
146
walk.cc
|
|
@ -1,9 +1,151 @@
|
||||||
#include "walk.h"
|
#include "walk.h"
|
||||||
|
#include "format.h"
|
||||||
|
|
||||||
namespace ledger {
|
namespace ledger {
|
||||||
|
|
||||||
struct sum_in_account : public item_handler<transaction_t> {
|
void calc_transactions::operator()(transaction_t * xact)
|
||||||
virtual void operator()(transaction_t * xact) const {
|
{
|
||||||
|
if (last_xact)
|
||||||
|
xact->total += last_xact->total;
|
||||||
|
|
||||||
|
if (inverted) {
|
||||||
|
xact->amount.negate();
|
||||||
|
xact->cost.negate();
|
||||||
|
}
|
||||||
|
|
||||||
|
xact->total += *xact;
|
||||||
|
xact->index = last_xact ? last_xact->index + 1 : 0;
|
||||||
|
|
||||||
|
(*handler)(xact);
|
||||||
|
|
||||||
|
if (inverted) {
|
||||||
|
xact->amount.negate();
|
||||||
|
xact->cost.negate();
|
||||||
|
}
|
||||||
|
|
||||||
|
last_xact = xact;
|
||||||
|
}
|
||||||
|
|
||||||
|
void collapse_transactions::report_cumulative_subtotal()
|
||||||
|
{
|
||||||
|
if (count == 1) {
|
||||||
|
(*handler)(last_xact);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(count > 1);
|
||||||
|
|
||||||
|
transaction_t * total_xact = new transaction_t(NULL, totals_account);
|
||||||
|
|
||||||
|
balance_t value;
|
||||||
|
total_xact->total = subtotal;
|
||||||
|
format_t::compute_total(value, details_t(total_xact));
|
||||||
|
total_xact->total = 0;
|
||||||
|
|
||||||
|
total_xact->entry = last_entry;
|
||||||
|
|
||||||
|
for (amounts_map::const_iterator i = value.amounts.begin();
|
||||||
|
i != value.amounts.end();
|
||||||
|
i++) {
|
||||||
|
total_xact->amount = (*i).second;
|
||||||
|
total_xact->cost = (*i).second;
|
||||||
|
|
||||||
|
(*handler)(total_xact);
|
||||||
|
}
|
||||||
|
|
||||||
|
xact_temps.push_back(total_xact);
|
||||||
|
}
|
||||||
|
|
||||||
|
void changed_value_transactions::operator()(transaction_t * xact)
|
||||||
|
{
|
||||||
|
if (last_xact) {
|
||||||
|
balance_t prev_bal;
|
||||||
|
balance_t cur_bal;
|
||||||
|
std::time_t current = xact ? xact->entry->date : std::time(NULL);
|
||||||
|
std::time_t prev_date = last_xact->entry->date;
|
||||||
|
|
||||||
|
format_t::compute_total(prev_bal, details_t(last_xact));
|
||||||
|
|
||||||
|
last_xact->entry->date = current;
|
||||||
|
format_t::compute_total(cur_bal, details_t(last_xact));
|
||||||
|
last_xact->entry->date = prev_date;
|
||||||
|
|
||||||
|
if (balance_t diff = cur_bal - prev_bal) {
|
||||||
|
modified_entry.date = current;
|
||||||
|
|
||||||
|
// jww (2004-08-07): What if there are multiple commodities?
|
||||||
|
assert(diff.amounts.size() == 1);
|
||||||
|
modified_xact.amount = diff.amount();
|
||||||
|
modified_xact.total = diff;
|
||||||
|
modified_xact.total.negate();
|
||||||
|
|
||||||
|
(*handler)(&modified_xact);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xact)
|
||||||
|
(*handler)(xact);
|
||||||
|
|
||||||
|
last_xact = xact;
|
||||||
|
}
|
||||||
|
|
||||||
|
void subtotal_transactions::flush()
|
||||||
|
{
|
||||||
|
entry_t * entry = new entry_t;
|
||||||
|
entry->date = start;
|
||||||
|
|
||||||
|
char buf[256];
|
||||||
|
// jww (2004-08-10): allow for a format string here
|
||||||
|
std::strftime(buf, 255, "- %Y/%m/%d", std::gmtime(&finish));
|
||||||
|
entry->payee = buf;
|
||||||
|
|
||||||
|
entry_temps.push_back(entry);
|
||||||
|
|
||||||
|
for (balances_map::iterator i = balances.begin();
|
||||||
|
i != balances.end();
|
||||||
|
i++) {
|
||||||
|
transaction_t * xact = new transaction_t(entry, (*i).first);
|
||||||
|
xact->total = (*i).second;
|
||||||
|
balance_t result;
|
||||||
|
format_t::compute_total(result, details_t(xact));
|
||||||
|
xact->total = 0;
|
||||||
|
|
||||||
|
for (amounts_map::const_iterator j = result.amounts.begin();
|
||||||
|
j != result.amounts.end();
|
||||||
|
j++) {
|
||||||
|
xact->amount = (*j).second;
|
||||||
|
xact->cost = (*j).second;
|
||||||
|
|
||||||
|
(*handler)(xact);
|
||||||
|
}
|
||||||
|
|
||||||
|
xact_temps.push_back(xact);
|
||||||
|
}
|
||||||
|
|
||||||
|
balances.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void subtotal_transactions::operator()(transaction_t * xact)
|
||||||
|
{
|
||||||
|
if (balances.size() == 0) {
|
||||||
|
start = finish = xact->entry->date;
|
||||||
|
} else {
|
||||||
|
if (std::difftime(xact->entry->date, start) < 0)
|
||||||
|
start = xact->entry->date;
|
||||||
|
if (std::difftime(xact->entry->date, finish) > 0)
|
||||||
|
finish = xact->entry->date;
|
||||||
|
}
|
||||||
|
|
||||||
|
balances_map::iterator i = balances.find(xact->account);
|
||||||
|
if (i == balances.end())
|
||||||
|
balances.insert(balances_pair(xact->account, *xact));
|
||||||
|
else
|
||||||
|
(*i).second += *xact;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sum_in_account : public item_handler<transaction_t>
|
||||||
|
{
|
||||||
|
virtual void operator()(transaction_t * xact) {
|
||||||
xact->account->value += *xact;
|
xact->account->value += *xact;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
255
walk.h
255
walk.h
|
|
@ -13,7 +13,8 @@ namespace ledger {
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct item_handler {
|
struct item_handler {
|
||||||
virtual ~item_handler() {}
|
virtual ~item_handler() {}
|
||||||
virtual void operator()(T * item) const = 0;
|
virtual void flush() {}
|
||||||
|
virtual void operator()(T * item) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
|
@ -36,16 +37,28 @@ struct compare_items {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::deque<transaction_t *> transactions_deque;
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Several default handlers
|
||||||
|
//
|
||||||
|
|
||||||
class collect_transactions : public item_handler<transaction_t> {
|
typedef std::deque<transaction_t *> transactions_deque;
|
||||||
|
typedef std::deque<entry_t *> entries_deque;
|
||||||
|
|
||||||
|
struct ignore_transaction : public item_handler<transaction_t>
|
||||||
|
{
|
||||||
|
virtual void operator()(transaction_t * xact) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class collect_transactions : public item_handler<transaction_t>
|
||||||
|
{
|
||||||
transactions_deque& transactions;
|
transactions_deque& transactions;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
collect_transactions(transactions_deque& _transactions)
|
collect_transactions(transactions_deque& _transactions)
|
||||||
: transactions(_transactions) {}
|
: transactions(_transactions) {}
|
||||||
|
|
||||||
virtual void operator()(transaction_t * xact) const {
|
virtual void operator()(transaction_t * xact) {
|
||||||
transactions.push_back(xact);
|
transactions.push_back(xact);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -57,15 +70,219 @@ inline void sort_transactions(transactions_deque& transactions,
|
||||||
compare_items<transaction_t>(sort_order));
|
compare_items<transaction_t>(sort_order));
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ignore_transaction : public item_handler<transaction_t> {
|
class filter_transactions : public item_handler<transaction_t>
|
||||||
virtual void operator()(transaction_t * xact) const {}
|
{
|
||||||
|
item_predicate<transaction_t> pred;
|
||||||
|
|
||||||
|
item_handler<transaction_t> * handler;
|
||||||
|
|
||||||
|
public:
|
||||||
|
filter_transactions(item_handler<transaction_t> * _handler,
|
||||||
|
const std::string& predicate)
|
||||||
|
: pred(predicate), handler(_handler) {}
|
||||||
|
|
||||||
|
virtual ~filter_transactions() {
|
||||||
|
handler->flush();
|
||||||
|
delete handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void operator()(transaction_t * xact) {
|
||||||
|
if (pred(xact))
|
||||||
|
(*handler)(xact);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class calc_transactions : public item_handler<transaction_t>
|
||||||
|
{
|
||||||
|
transaction_t * last_xact;
|
||||||
|
const bool inverted;
|
||||||
|
|
||||||
|
item_handler<transaction_t> * handler;
|
||||||
|
|
||||||
|
public:
|
||||||
|
calc_transactions(item_handler<transaction_t> * _handler,
|
||||||
|
const bool _inverted = false)
|
||||||
|
: last_xact(NULL), inverted(_inverted), handler(_handler) {}
|
||||||
|
|
||||||
|
virtual ~calc_transactions() {
|
||||||
|
handler->flush();
|
||||||
|
delete handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void operator()(transaction_t * xact);
|
||||||
|
};
|
||||||
|
|
||||||
|
class collapse_transactions : public item_handler<transaction_t>
|
||||||
|
{
|
||||||
|
balance_pair_t subtotal;
|
||||||
|
unsigned int count;
|
||||||
|
entry_t * last_entry;
|
||||||
|
transaction_t * last_xact;
|
||||||
|
|
||||||
|
item_handler<transaction_t> * handler;
|
||||||
|
|
||||||
|
account_t * totals_account;
|
||||||
|
transactions_deque xact_temps;
|
||||||
|
|
||||||
|
public:
|
||||||
|
collapse_transactions(item_handler<transaction_t> * _handler)
|
||||||
|
: count(0), last_entry(NULL), last_xact(NULL),
|
||||||
|
handler(_handler) {
|
||||||
|
totals_account = new account_t(NULL, "<Total>");
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~collapse_transactions() {
|
||||||
|
flush();
|
||||||
|
handler->flush();
|
||||||
|
|
||||||
|
delete handler;
|
||||||
|
delete totals_account;
|
||||||
|
|
||||||
|
for (transactions_deque::iterator i = xact_temps.begin();
|
||||||
|
i != xact_temps.end();
|
||||||
|
i++)
|
||||||
|
delete *i;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void flush() {
|
||||||
|
if (subtotal)
|
||||||
|
report_cumulative_subtotal();
|
||||||
|
}
|
||||||
|
|
||||||
|
void report_cumulative_subtotal();
|
||||||
|
|
||||||
|
virtual void operator()(transaction_t * xact) {
|
||||||
|
// If we've reached a new entry, report on the subtotal
|
||||||
|
// accumulated thus far.
|
||||||
|
|
||||||
|
if (last_entry && last_entry != xact->entry) {
|
||||||
|
report_cumulative_subtotal();
|
||||||
|
subtotal = 0;
|
||||||
|
count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
subtotal += *xact;
|
||||||
|
count++;
|
||||||
|
|
||||||
|
last_entry = xact->entry;
|
||||||
|
last_xact = xact;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// This filter requires that calc_transactions be used.
|
||||||
|
|
||||||
|
class changed_value_transactions : public item_handler<transaction_t>
|
||||||
|
{
|
||||||
|
entry_t modified_entry;
|
||||||
|
transaction_t modified_xact;
|
||||||
|
transaction_t * last_xact;
|
||||||
|
|
||||||
|
item_handler<transaction_t> * handler;
|
||||||
|
|
||||||
|
public:
|
||||||
|
changed_value_transactions(item_handler<transaction_t> * _handler)
|
||||||
|
: modified_xact(&modified_entry, NULL), last_xact(NULL),
|
||||||
|
handler(_handler) {
|
||||||
|
assert(handler);
|
||||||
|
modified_entry.payee = "Commodities revalued";
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~changed_value_transactions() {
|
||||||
|
flush();
|
||||||
|
handler->flush();
|
||||||
|
delete handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void flush() {
|
||||||
|
(*this)(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void operator()(transaction_t * xact);
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::map<account_t *, balance_pair_t> balances_map;
|
||||||
|
typedef std::pair<account_t *, balance_pair_t> balances_pair;
|
||||||
|
|
||||||
|
class subtotal_transactions : public item_handler<transaction_t>
|
||||||
|
{
|
||||||
|
std::time_t start;
|
||||||
|
std::time_t finish;
|
||||||
|
balances_map balances;
|
||||||
|
|
||||||
|
item_handler<transaction_t> * handler;
|
||||||
|
|
||||||
|
entries_deque entry_temps;
|
||||||
|
transactions_deque xact_temps;
|
||||||
|
|
||||||
|
public:
|
||||||
|
subtotal_transactions(item_handler<transaction_t> * _handler)
|
||||||
|
: handler(_handler) {}
|
||||||
|
|
||||||
|
virtual ~subtotal_transactions() {
|
||||||
|
flush();
|
||||||
|
handler->flush();
|
||||||
|
delete handler;
|
||||||
|
|
||||||
|
for (entries_deque::iterator i = entry_temps.begin();
|
||||||
|
i != entry_temps.end();
|
||||||
|
i++)
|
||||||
|
delete *i;
|
||||||
|
|
||||||
|
for (transactions_deque::iterator i = xact_temps.begin();
|
||||||
|
i != xact_temps.end();
|
||||||
|
i++)
|
||||||
|
delete *i;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void flush();
|
||||||
|
virtual void operator()(transaction_t * xact);
|
||||||
|
};
|
||||||
|
|
||||||
|
class interval_transactions : public item_handler<transaction_t>
|
||||||
|
{
|
||||||
|
std::time_t start;
|
||||||
|
unsigned long months;
|
||||||
|
unsigned long seconds;
|
||||||
|
transaction_t * last_xact;
|
||||||
|
|
||||||
|
item_handler<transaction_t> * handler;
|
||||||
|
|
||||||
|
public:
|
||||||
|
interval_transactions(item_handler<transaction_t> * _handler,
|
||||||
|
std::time_t _start, unsigned long _months,
|
||||||
|
unsigned long _seconds)
|
||||||
|
: start(_start), months(_months), seconds(_seconds),
|
||||||
|
last_xact(NULL), handler(_handler) {}
|
||||||
|
|
||||||
|
virtual ~interval_transactions() {
|
||||||
|
flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void flush() {
|
||||||
|
handler->flush();
|
||||||
|
}
|
||||||
|
virtual void operator()(transaction_t * xact) {
|
||||||
|
if (std::difftime(xact->entry->date, start + seconds) > 0) {
|
||||||
|
if (last_xact)
|
||||||
|
handler->flush();
|
||||||
|
start += seconds;
|
||||||
|
while (std::difftime(xact->entry->date, start + seconds) > 0)
|
||||||
|
start += seconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
(*handler)(xact);
|
||||||
|
|
||||||
|
last_xact = xact;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#define MATCHING_TRANSACTIONS 0x01
|
#define MATCHING_TRANSACTIONS 0x01
|
||||||
#define OTHER_TRANSACTIONS 0x02
|
#define OTHER_TRANSACTIONS 0x02
|
||||||
|
|
||||||
inline void handle_transaction(transaction_t * xact,
|
inline void handle_transaction(transaction_t * xact,
|
||||||
const item_handler<transaction_t>& handler,
|
item_handler<transaction_t>& handler,
|
||||||
unsigned int flags)
|
unsigned int flags)
|
||||||
{
|
{
|
||||||
for (transactions_list::iterator i = xact->entry->transactions.begin();
|
for (transactions_list::iterator i = xact->entry->transactions.begin();
|
||||||
|
|
@ -83,7 +300,7 @@ inline void handle_transaction(transaction_t * xact,
|
||||||
|
|
||||||
inline void walk_entries(entries_list::iterator begin,
|
inline void walk_entries(entries_list::iterator begin,
|
||||||
entries_list::iterator end,
|
entries_list::iterator end,
|
||||||
const item_handler<transaction_t>& handler,
|
item_handler<transaction_t>& handler,
|
||||||
const std::string& predicate,
|
const std::string& predicate,
|
||||||
unsigned int flags)
|
unsigned int flags)
|
||||||
{
|
{
|
||||||
|
|
@ -99,7 +316,7 @@ inline void walk_entries(entries_list::iterator begin,
|
||||||
|
|
||||||
inline void walk_entries(entries_list::iterator begin,
|
inline void walk_entries(entries_list::iterator begin,
|
||||||
entries_list::iterator end,
|
entries_list::iterator end,
|
||||||
const item_handler<transaction_t>& handler)
|
item_handler<transaction_t>& handler)
|
||||||
{
|
{
|
||||||
for (entries_list::iterator i = begin; i != end; i++)
|
for (entries_list::iterator i = begin; i != end; i++)
|
||||||
for (transactions_list::iterator j = (*i)->transactions.begin();
|
for (transactions_list::iterator j = (*i)->transactions.begin();
|
||||||
|
|
@ -108,8 +325,9 @@ inline void walk_entries(entries_list::iterator begin,
|
||||||
handler(*j);
|
handler(*j);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct clear_flags : public item_handler<transaction_t> {
|
struct clear_flags : public item_handler<transaction_t>
|
||||||
virtual void operator()(transaction_t * xact) const {
|
{
|
||||||
|
virtual void operator()(transaction_t * xact) {
|
||||||
xact->dflags = 0;
|
xact->dflags = 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -117,12 +335,13 @@ struct clear_flags : public item_handler<transaction_t> {
|
||||||
inline void clear_transaction_display_flags(entries_list::iterator begin,
|
inline void clear_transaction_display_flags(entries_list::iterator begin,
|
||||||
entries_list::iterator end)
|
entries_list::iterator end)
|
||||||
{
|
{
|
||||||
walk_entries(begin, end, clear_flags());
|
clear_flags handler;
|
||||||
|
walk_entries(begin, end, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void walk_transactions(transactions_list::iterator begin,
|
inline void walk_transactions(transactions_list::iterator begin,
|
||||||
transactions_list::iterator end,
|
transactions_list::iterator end,
|
||||||
const item_handler<transaction_t>& handler)
|
item_handler<transaction_t>& handler)
|
||||||
{
|
{
|
||||||
for (transactions_list::iterator i = begin; i != end; i++)
|
for (transactions_list::iterator i = begin; i != end; i++)
|
||||||
handler(*i);
|
handler(*i);
|
||||||
|
|
@ -130,7 +349,7 @@ inline void walk_transactions(transactions_list::iterator begin,
|
||||||
|
|
||||||
inline void walk_transactions(transactions_deque::iterator begin,
|
inline void walk_transactions(transactions_deque::iterator begin,
|
||||||
transactions_deque::iterator end,
|
transactions_deque::iterator end,
|
||||||
const item_handler<transaction_t>& handler)
|
item_handler<transaction_t>& handler)
|
||||||
{
|
{
|
||||||
for (transactions_deque::iterator i = begin; i != end; i++)
|
for (transactions_deque::iterator i = begin; i != end; i++)
|
||||||
handler(*i);
|
handler(*i);
|
||||||
|
|
@ -152,7 +371,7 @@ inline void sort_accounts(account_t * account,
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void walk__accounts(account_t * account,
|
inline void walk__accounts(account_t * account,
|
||||||
const item_handler<account_t>& handler)
|
item_handler<account_t>& handler)
|
||||||
{
|
{
|
||||||
handler(account);
|
handler(account);
|
||||||
|
|
||||||
|
|
@ -163,7 +382,7 @@ inline void walk__accounts(account_t * account,
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void walk__accounts_sorted(account_t * account,
|
inline void walk__accounts_sorted(account_t * account,
|
||||||
const item_handler<account_t>& handler,
|
item_handler<account_t>& handler,
|
||||||
const node_t * sort_order)
|
const node_t * sort_order)
|
||||||
{
|
{
|
||||||
handler(account);
|
handler(account);
|
||||||
|
|
@ -185,7 +404,7 @@ inline void walk__accounts_sorted(account_t * account,
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void for_each_account(account_t * account,
|
inline void for_each_account(account_t * account,
|
||||||
const item_handler<account_t>& handler)
|
item_handler<account_t>& handler)
|
||||||
{
|
{
|
||||||
handler(account);
|
handler(account);
|
||||||
|
|
||||||
|
|
@ -211,7 +430,7 @@ inline void sum__accounts(account_t * account)
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void walk_accounts(account_t * account,
|
inline void walk_accounts(account_t * account,
|
||||||
const item_handler<account_t>& handler,
|
item_handler<account_t>& handler,
|
||||||
const std::string& predicate,
|
const std::string& predicate,
|
||||||
unsigned int flags,
|
unsigned int flags,
|
||||||
const bool calc_subtotals,
|
const bool calc_subtotals,
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue