got more reports working again

This commit is contained in:
John Wiegley 2004-08-07 21:03:25 -04:00
parent 5db1e1165b
commit c6c0179545
7 changed files with 161 additions and 230 deletions

111
format.cc
View file

@ -14,18 +14,22 @@ std::string truncated(const std::string& str, unsigned int width)
return buf;
}
std::string partial_account_name(const account_t * account,
const unsigned int start_depth)
std::string partial_account_name(const account_t * account)
{
std::string name = account->name;
const account_t * acct = account->parent;
std::string name;
for (int i = account->depth - start_depth - 1;
--i >= 0 && acct->parent; ) {
assert(acct);
name = acct->name + ":" + name;
acct = acct->parent;
for (const account_t * acct = account;
acct && acct->parent;
acct = acct->parent) {
if (acct->flags & ACCOUNT_DISPLAYED)
break;
if (name.empty())
name = acct->name;
else
name = acct->name + ":" + name;
}
return name;
}
@ -206,8 +210,7 @@ void format_t::format_elements(std::ostream& out,
if (details.account) {
std::string name = (elem->type == element_t::ACCOUNT_FULLNAME ?
details.account->fullname() :
partial_account_name(details.account,
details.depth));
partial_account_name(details.account));
if (elem->max_width > 0)
name = truncated(name, elem->max_width);
@ -278,12 +281,15 @@ void format_t::format_elements(std::ostream& out,
}
case element_t::SPACER:
for (unsigned int i = 0; i < details.depth; i++) {
if (elem->min_width > 0 || elem->max_width > 0)
out.width(elem->min_width > elem->max_width ?
elem->min_width : elem->max_width);
out << " ";
}
for (const account_t * acct = details.account;
acct;
acct = acct->parent)
if (acct->flags & ACCOUNT_DISPLAYED) {
if (elem->min_width > 0 || elem->max_width > 0)
out.width(elem->min_width > elem->max_width ?
elem->min_width : elem->max_width);
out << " ";
}
break;
default:
@ -293,11 +299,12 @@ void format_t::format_elements(std::ostream& out,
}
}
#ifdef COLLAPSED_REGISTER
void format_transaction::report_cumulative_subtotal() const
{
if (count == 1) {
if (! intercept || ! intercept(last_xact))
first_line_format.format_elements(output_stream, details_t(last_xact));
first_line_format.format_elements(output_stream, details_t(last_xact));
return;
}
@ -321,9 +328,8 @@ void format_transaction::report_cumulative_subtotal() const
splits_total.cost = (*i).second;
splits_total.total += (*i).second;
if (first) {
if (! intercept || ! intercept(&splits_total))
first_line_format.format_elements(output_stream,
details_t(&splits_total));
first_line_format.format_elements(output_stream,
details_t(&splits_total));
first = false;
} else {
next_lines_format.format_elements(output_stream,
@ -332,10 +338,12 @@ void format_transaction::report_cumulative_subtotal() const
}
}
#endif // COLLAPSED_REGISTER
void format_transaction::operator()(transaction_t * xact) const
{
if (last_xact)
xact->total = last_xact->total;
xact->total += last_xact->total;
if (inverted) {
xact->amount.negate();
@ -353,6 +361,7 @@ void format_transaction::operator()(transaction_t * xact) const
// 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.
@ -365,10 +374,11 @@ void format_transaction::operator()(transaction_t * xact) const
subtotal += *xact;
count++;
} else {
} else
#endif
{
if (last_entry != xact->entry) {
if (! intercept || ! intercept(xact))
first_line_format.format_elements(output_stream, details_t(xact));
first_line_format.format_elements(output_stream, details_t(xact));
} else {
next_lines_format.format_elements(output_stream, details_t(xact));
}
@ -383,38 +393,8 @@ void format_transaction::operator()(transaction_t * xact) const
last_xact = xact;
}
#if 0
bool report_changed_values(transaction_t * xact)
{
static transaction_t * last_xact = NULL;
if (last_xact) {
balance_t prev_bal, cur_bal;
format_t::compute_total(prev_bal, details_t(last_xact));
format_t::compute_total(cur_bal, details_t(xact));
if (balance_t diff = cur_bal - prev_bal) {
entry_t modified_entry;
transaction_t new_xact(&modified_entry, NULL);
modified_entry.date = xact ? xact->entry->date : std::time(NULL);
modified_entry.payee = "Commodities revalued";
new_xact.amount = diff.amount();
format_t::compute_value(diff, details_t(xact));
new_xact.total = cur_bal - diff;
functor(&new_xact);
}
}
last_xact = xact;
}
#endif
void format_account::operator()(const account_t * account,
void format_account::operator()(account_t * account,
const unsigned int max_depth,
const bool report_top) const
{
@ -425,7 +405,8 @@ void format_account::operator()(const account_t * account,
// parent account and a lone displayed child, then don't display the
// parent."
if (bool output = report_top || account->parent != NULL) {
if (bool output = ((report_top || account->parent != NULL) &&
disp_pred_functor(account))) {
int counted = 0;
bool display = false;
@ -445,17 +426,9 @@ void format_account::operator()(const account_t * account,
if (counted == 1 && ! display)
output = false;
if (output) {
unsigned int depth = account->depth;
if (max_depth == 0 || depth <= max_depth) {
for (const account_t * acct = account;
depth > 0 && acct && acct != last_account;
acct = acct->parent)
depth--;
format.format_elements(output_stream, details_t(account, depth));
last_account = account;
}
if (output && (max_depth == 0 || account->depth <= max_depth)) {
format.format_elements(output_stream, details_t(account));
account->flags |= ACCOUNT_DISPLAYED;
}
}
}

View file

@ -87,17 +87,17 @@ class format_transaction
std::ostream& output_stream;
const format_t& first_line_format;
const format_t& next_lines_format;
#ifdef COLLAPSED_REGISTER
const bool collapsed;
#endif
const bool inverted;
item_predicate<transaction_t> disp_pred_functor;
typedef bool (*intercept_t)(transaction_t * xact);
intercept_t intercept;
#ifdef COLLAPSED_REGISTER
mutable balance_pair_t subtotal;
mutable unsigned int count;
#endif
mutable entry_t * last_entry;
mutable transaction_t * last_xact;
@ -106,29 +106,86 @@ class format_transaction
const format_t& _first_line_format,
const format_t& _next_lines_format,
const node_t * display_predicate,
#ifdef COLLAPSED_REGISTER
const bool _collapsed = false,
const bool _inverted = false,
intercept_t _intercept = NULL)
#endif
const bool _inverted = false)
: output_stream(_output_stream),
first_line_format(_first_line_format),
next_lines_format(_next_lines_format),
collapsed(_collapsed), inverted(_inverted),
disp_pred_functor(display_predicate),
intercept(_intercept), count(0),
#ifdef COLLAPSED_REGISTER
collapsed(_collapsed),
#endif
inverted(_inverted), disp_pred_functor(display_predicate),
#ifdef COLLAPSED_REGISTER
count(0),
#endif
last_entry(NULL), last_xact(NULL) {}
void start() const {}
void finish() const {
#ifdef COLLAPSED_REGISTER
~format_transaction() {
if (subtotal)
report_cumulative_subtotal();
}
void report_cumulative_subtotal() const;
#endif
void operator()(transaction_t * xact) const;
};
// An intercept that can be used to report changes in commodity value
bool report_changed_values(transaction_t * xact);
template <typename Function>
class changed_value_filter
{
const Function& functor;
mutable entry_t modified_entry;
mutable transaction_t modified_xact;
mutable transaction_t * last_xact;
public:
changed_value_filter(const Function& _functor)
: functor(_functor), modified_xact(&modified_entry, NULL),
last_xact(NULL) {
modified_entry.payee = "Commodities revalued";
}
~changed_value_filter() {
(*this)(NULL);
}
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();
functor(&modified_xact);
}
}
if (xact)
functor(xact);
last_xact = xact;
}
};
class format_account
@ -138,19 +195,14 @@ class format_account
item_predicate<account_t> disp_pred_functor;
mutable const account_t * last_account;
public:
format_account(std::ostream& _output_stream,
const format_t& _format,
const node_t * display_predicate = NULL)
: output_stream(_output_stream), format(_format),
disp_pred_functor(display_predicate), last_account(NULL) {}
disp_pred_functor(display_predicate) {}
void start() const {}
void finish() const {}
void operator()(const account_t * account,
void operator()(account_t * account,
const unsigned int max_depth = 1,
const bool report_top = false) const;
};

View file

@ -94,6 +94,8 @@ class entry_t
};
#define ACCOUNT_DISPLAYED 0x1
typedef std::map<const std::string, account_t *> accounts_map;
typedef std::pair<const std::string, account_t *> accounts_pair;
@ -109,6 +111,7 @@ class account_t
balance_pair_t value;
balance_pair_t total;
unsigned long ident;
unsigned long flags;
mutable std::string _fullname;
static unsigned long next_ident;
@ -117,7 +120,7 @@ class account_t
const std::string& _name = "",
const std::string& _note = "")
: parent(_parent), name(_name), note(_note),
depth(parent ? parent->depth + 1 : 0) {}
depth(parent ? parent->depth + 1 : 0), flags(0) {}
~account_t();

147
main.cc
View file

@ -11,19 +11,8 @@
namespace ledger {
//////////////////////////////////////////////////////////////////////
//
// The command-line balance report
//
static const std::string bal_fmt = "%20T %2_%-n\n";
//////////////////////////////////////////////////////////////////////
//
// The command-line register and print report
//
static const std::string reg_fmt
= "%10d %-.20p %-.22N %12.66t %12.80T\n\
%/ %-.22N %12.66t %12.80T\n";
@ -31,104 +20,6 @@ static const std::string reg_fmt
static const std::string print_fmt
= "\n%10d %X%C%p\n %-34N %12o\n%/ %-34N %12o\n";
#if 0
static void report_value_change(std::ostream& out,
const std::time_t date,
const balance_pair_t& balance,
const balance_pair_t& prev_balance,
const node_t * predicate,
const format_t& first_line_format,
const format_t& next_lines_format)
{
}
void register_report(std::ostream& out,
item_t * top,
const node_t * predicate,
const node_t * sort_order,
const format_t& first_line_format,
const format_t& next_lines_format,
const bool show_expanded)
{
if (sort_order)
top->sort(sort_order);
balance_pair_t balance;
balance_pair_t last_reported;
account_t splits(NULL, "<Total>");
value_predicate pred_obj(predicate);
for (items_deque::const_iterator i = top->subitems.begin();
i != top->subitems.end();
i++) {
bool first = true;
if ((*i)->subitems.size() > 1 && ! show_expanded) {
item_t summary(*i);
summary.parent = *i;
summary.account = &splits;
summary.value = 0;
for (items_deque::const_iterator j = (*i)->subitems.begin();
j != (*i)->subitems.end();
j++)
summary.value += (*j)->value;
summary.total = balance + summary.value;
bool show = pred_obj(&summary);
if (show && show_commodities_revalued)
report_value_change(out, summary.date, balance, last_reported,
predicate, first_line_format, next_lines_format);
balance += summary.value;
if (show) {
if (! show_commodities_revalued_only)
first_line_format.format_elements(out, &summary, top);
if (show_commodities_revalued)
last_reported = balance;
}
} else {
for (items_deque::const_iterator j = (*i)->subitems.begin();
j != (*i)->subitems.end();
j++) {
(*j)->total = balance + (*j)->value;
bool show = pred_obj(*j);
if (show && first && show_commodities_revalued) {
report_value_change(out, (*i)->date, balance, last_reported,
predicate, first_line_format, next_lines_format);
if (show_commodities_revalued_only)
first = false;
}
balance += (*j)->value;
if (show) {
if (! show_commodities_revalued_only) {
if (first) {
first = false;
first_line_format.format_elements(out, *j, *i);
} else {
next_lines_format.format_elements(out, *j, *i);
}
}
if (show_commodities_revalued)
last_reported = balance;
}
}
}
}
if (show_commodities_revalued)
report_value_change(out, -1, balance, last_reported, predicate,
first_line_format, next_lines_format);
}
#endif
void set_price_conversion(const std::string& setting)
{
@ -710,18 +601,17 @@ int main(int argc, char * argv[])
unsigned int xact_display_flags = MATCHING_TRANSACTIONS;
if (command == "p" || command == "e") {
if (command == "p" || command == "e" || command == "E") {
xact_display_flags |= OTHER_TRANSACTIONS;
show_expanded = true;
}
else if (command == "E") {
show_expanded = true;
}
else if (show_related && command == "r") {
xact_display_flags = OTHER_TRANSACTIONS;
show_inverted = true;
}
else if (show_related) {
xact_display_flags |= OTHER_TRANSACTIONS;
if (command == "r") {
xact_display_flags = OTHER_TRANSACTIONS;
show_inverted = true;
} else {
xact_display_flags |= OTHER_TRANSACTIONS;
}
}
const char * f;
@ -737,11 +627,9 @@ int main(int argc, char * argv[])
if (command == "b") {
format_t format(f);
format_account formatter(std::cout, format, display_predicate.get());
formatter.start();
walk_accounts(journal->master, formatter, predicate.get(),
xact_display_flags, show_subtotals, show_expanded ? 0 : 1,
sort_order.get());
formatter.finish();
if (! display_predicate.get() ||
item_predicate<account_t>(display_predicate.get())(journal->master)) {
@ -766,12 +654,20 @@ int main(int argc, char * argv[])
format_transaction formatter(std::cout, format, nformat,
display_predicate.get(),
! show_subtotals, show_inverted);
formatter.start();
#ifdef COLLAPSED_REGISTER
! show_subtotals,
#endif
show_inverted);
if (! sort_order.get()) {
walk_entries(journal->entries.begin(), journal->entries.end(),
formatter, predicate.get(), xact_display_flags);
if (show_commodities_revalued) {
changed_value_filter<format_transaction>
filtered_formatter(formatter);
walk_entries(journal->entries.begin(), journal->entries.end(),
filtered_formatter, predicate.get(), xact_display_flags);
} else {
walk_entries(journal->entries.begin(), journal->entries.end(),
formatter, predicate.get(), xact_display_flags);
}
} else {
transactions_deque transactions_pool;
walk_entries(journal->entries.begin(), journal->entries.end(),
@ -782,7 +678,6 @@ int main(int argc, char * argv[])
walk_transactions(transactions_pool.begin(), transactions_pool.end(),
formatter);
}
formatter.finish();
}
// Save the cache, if need be

View file

@ -153,6 +153,8 @@ void node_t::compute(balance_t& result, const details_t& details) const
case DATE:
if (details.entry)
result = (unsigned int) details.entry->date;
else
result = (unsigned int) std::time(NULL);
break;
case CLEARED:
@ -207,12 +209,20 @@ void node_t::compute(balance_t& result, const details_t& details) const
left->compute(result, details);
std::time_t moment = -1;
if (right && details.entry) {
if (right) {
switch (right->type) {
case DATE: moment = details.entry->date; break;
case DATE:
if (details.entry)
moment = details.entry->date;
else
moment = std::time(NULL);
break;
default:
throw compute_error("Invalid date passed to P(v,d)");
throw compute_error("Invalid date passed to P(value,date)");
}
} else {
moment = std::time(NULL);
}
result = result.value(moment);
break;

View file

@ -30,20 +30,18 @@ bool matches(const masks_list& regexps, const std::string& str,
struct details_t
{
const entry_t * entry;
const transaction_t * xact;
const account_t * account;
const unsigned int depth;
const entry_t * entry;
const transaction_t * xact;
const account_t * account;
details_t(const entry_t * _entry)
: entry(_entry), xact(NULL), account(NULL), depth(0) {}
: entry(_entry), xact(NULL), account(NULL) {}
details_t(const transaction_t * _xact)
: entry(_xact->entry), xact(_xact), account(_xact->account), depth(0) {}
: entry(_xact->entry), xact(_xact), account(_xact->account) {}
details_t(const account_t * _account,
const unsigned int _depth = 0)
: entry(NULL), xact(NULL), account(_account), depth(_depth) {}
details_t(const account_t * _account)
: entry(NULL), xact(NULL), account(_account) {}
};
struct node_t

4
walk.h
View file

@ -161,7 +161,7 @@ inline void sort_accounts(account_t * account,
}
template <typename Function>
void walk__accounts(const account_t * account,
void walk__accounts(account_t * account,
const Function& functor,
const unsigned int max_depth)
{
@ -174,7 +174,7 @@ void walk__accounts(const account_t * account,
}
template <typename Function>
void walk__accounts_sorted(const account_t * account,
void walk__accounts_sorted(account_t * account,
const Function& functor,
const unsigned int max_depth,
const node_t * sort_order)