ledger/walk.cc

1173 lines
33 KiB
C++

#include "walk.h"
#include "format.h"
#include "textual.h"
#include "util.h"
#include <algorithm>
namespace ledger {
std::list<transaction_xdata_t> transactions_xdata;
std::list<void **> transactions_xdata_ptrs;
std::list<account_xdata_t> accounts_xdata;
std::list<void **> accounts_xdata_ptrs;
template <>
bool compare_items<transaction_t>::operator()(const transaction_t * left,
const transaction_t * right)
{
assert(left);
assert(right);
transaction_xdata_t& lxdata(transaction_xdata(*left));
if (! (lxdata.dflags & TRANSACTION_SORT_CALC)) {
sort_order->compute(lxdata.sort_value, details_t(*left));
lxdata.dflags |= TRANSACTION_SORT_CALC;
}
transaction_xdata_t& rxdata(transaction_xdata(*right));
if (! (rxdata.dflags & TRANSACTION_SORT_CALC)) {
sort_order->compute(rxdata.sort_value, details_t(*right));
rxdata.dflags |= TRANSACTION_SORT_CALC;
}
return lxdata.sort_value < rxdata.sort_value;
}
transaction_xdata_t& transaction_xdata(const transaction_t& xact)
{
if (! xact.data) {
transactions_xdata.push_back(transaction_xdata_t());
xact.data = &transactions_xdata.back();
transactions_xdata_ptrs.push_back(&xact.data);
}
return *((transaction_xdata_t *) xact.data);
}
void add_transaction_to(const transaction_t& xact, value_t& value)
{
if (transaction_has_xdata(xact) &&
transaction_xdata_(xact).dflags & TRANSACTION_COMPOSITE)
value += transaction_xdata_(xact).composite_amount;
else if (xact.cost || value)
value.add(xact.amount, xact.cost);
else
value = xact.amount;
}
void truncate_entries::flush()
{
if (! xacts.size())
return;
entry_t * last_entry = (*xacts.begin())->entry;
int l = 0;
for (transactions_list::iterator x = xacts.begin();
x != xacts.end();
x++)
if (last_entry != (*x)->entry) {
l++;
last_entry = (*x)->entry;
}
l++;
last_entry = (*xacts.begin())->entry;
int i = 0;
for (transactions_list::iterator x = xacts.begin();
x != xacts.end();
x++) {
if (last_entry != (*x)->entry) {
last_entry = (*x)->entry;
i++;
}
bool print = false;
if (head_count) {
if (head_count > 0 && i < head_count)
print = true;
else if (head_count < 0 && i >= - head_count)
print = true;
}
if (! print && tail_count) {
if (tail_count > 0 && l - i <= tail_count)
print = true;
else if (tail_count < 0 && l - i > - tail_count)
print = true;
}
if (print)
item_handler<transaction_t>::operator()(**x);
}
xacts.clear();
item_handler<transaction_t>::flush();
}
void set_account_value::operator()(transaction_t& xact)
{
account_xdata_t& xdata = account_xdata(*xact.account);
add_transaction_to(xact, xdata.value);
xdata.count++;
if (xact.flags & TRANSACTION_VIRTUAL)
xdata.virtuals++;
item_handler<transaction_t>::operator()(xact);
}
void sort_transactions::post_accumulated_xacts()
{
std::stable_sort(transactions.begin(), transactions.end(),
compare_items<transaction_t>(sort_order));
for (transactions_deque::iterator i = transactions.begin();
i != transactions.end();
i++) {
transaction_xdata(**i).dflags &= ~TRANSACTION_SORT_CALC;
item_handler<transaction_t>::operator()(**i);
}
transactions.clear();
}
void calc_transactions::operator()(transaction_t& xact)
{
transaction_xdata_t& xdata(transaction_xdata(xact));
if (last_xact && transaction_has_xdata(*last_xact)) {
xdata.total += transaction_xdata_(*last_xact).total;
xdata.index = transaction_xdata_(*last_xact).index + 1;
} else {
xdata.index = 0;
}
if (! (xdata.dflags & TRANSACTION_NO_TOTAL))
add_transaction_to(xact, xdata.total);
item_handler<transaction_t>::operator()(xact);
last_xact = &xact;
}
void invert_transactions::operator()(transaction_t& xact)
{
if (transaction_has_xdata(xact) &&
transaction_xdata_(xact).dflags & TRANSACTION_COMPOSITE) {
transaction_xdata_(xact).composite_amount.negate();
} else {
xact.amount.negate();
if (xact.cost)
xact.cost->negate();
}
item_handler<transaction_t>::operator()(xact);
}
static inline
void handle_value(const value_t& value,
account_t * account,
entry_t * entry,
unsigned int flags,
std::list<transaction_t>& temps,
item_handler<transaction_t>& handler,
const std::time_t date = 0)
{
temps.push_back(transaction_t(account));
transaction_t& xact(temps.back());
xact.entry = entry;
xact.flags |= TRANSACTION_BULK_ALLOC;
entry->add_transaction(&xact);
// If the account for this transaction is all virtual, then report
// the transaction as such. This allows subtotal reports to show
// "(Account)" for accounts that contain only virtual transactions.
if (account && account_has_xdata(*account))
if (! (account_xdata_(*account).dflags & ACCOUNT_HAS_NON_VIRTUALS)) {
xact.flags |= TRANSACTION_VIRTUAL;
if (! (account_xdata_(*account).dflags & ACCOUNT_HAS_UNB_VIRTUALS))
xact.flags |= TRANSACTION_BALANCE;
}
transaction_xdata_t& xdata(transaction_xdata(xact));
switch (value.type) {
case value_t::BOOLEAN:
xact.amount = *((bool *) value.data);
break;
case value_t::INTEGER:
xact.amount = *((long *) value.data);
break;
case value_t::AMOUNT:
xact.amount = *((amount_t *) value.data);
break;
case value_t::BALANCE:
case value_t::BALANCE_PAIR:
xdata.composite_amount = value;
flags |= TRANSACTION_COMPOSITE;
break;
}
if (date)
xdata.date = date;
if (flags)
xdata.dflags |= flags;
handler(xact);
}
void collapse_transactions::report_subtotal()
{
assert(count >= 1);
if (count == 1) {
item_handler<transaction_t>::operator()(*last_xact);
} else {
entry_temps.push_back(entry_t());
entry_t& entry = entry_temps.back();
entry.payee = last_entry->payee;
entry.date = last_entry->date;
handle_value(subtotal, &totals_account, last_entry, 0, xact_temps,
*handler);
}
last_entry = NULL;
last_xact = NULL;
subtotal = 0L;
count = 0;
}
void collapse_transactions::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 && count > 0)
report_subtotal();
add_transaction_to(xact, subtotal);
count++;
last_entry = xact.entry;
last_xact = &xact;
}
void related_transactions::flush()
{
if (transactions.size() > 0) {
for (transactions_list::iterator i = transactions.begin();
i != transactions.end();
i++) {
if ((*i)->entry) {
for (transactions_list::iterator j = (*i)->entry->transactions.begin();
j != (*i)->entry->transactions.end();
j++) {
transaction_xdata_t& xdata = transaction_xdata(**j);
if (! (xdata.dflags & TRANSACTION_HANDLED) &&
(! (xdata.dflags & TRANSACTION_RECEIVED) ?
! ((*j)->flags & (TRANSACTION_AUTO | TRANSACTION_VIRTUAL)) :
also_matching)) {
xdata.dflags |= TRANSACTION_HANDLED;
item_handler<transaction_t>::operator()(**j);
}
}
} else {
// This code should only be reachable from the "output"
// command, since that is the only command which attempts to
// output auto or period entries.
transaction_xdata_t& xdata = transaction_xdata(**i);
if (! (xdata.dflags & TRANSACTION_HANDLED) &&
! ((*i)->flags & TRANSACTION_AUTO)) {
xdata.dflags |= TRANSACTION_HANDLED;
item_handler<transaction_t>::operator()(**i);
}
}
}
}
item_handler<transaction_t>::flush();
}
void changed_value_transactions::output_diff(const std::time_t current)
{
value_t cur_bal;
transaction_xdata(*last_xact).date = current;
compute_total(cur_bal, details_t(*last_xact));
cur_bal.round();
transaction_xdata(*last_xact).date = 0;
if (value_t diff = cur_bal - last_balance) {
entry_temps.push_back(entry_t());
entry_t& entry = entry_temps.back();
entry.payee = "Commodities revalued";
entry.date = current;
handle_value(diff, NULL, &entry, TRANSACTION_NO_TOTAL, xact_temps,
*handler);
}
}
void changed_value_transactions::operator()(transaction_t& xact)
{
if (last_xact) {
std::time_t moment = 0;
if (transaction_has_xdata(*last_xact))
moment = transaction_xdata_(*last_xact).date;
if (! moment)
moment = xact.entry->date;
output_diff(moment);
}
if (changed_values_only)
transaction_xdata(xact).dflags |= TRANSACTION_DISPLAYED;
item_handler<transaction_t>::operator()(xact);
compute_total(last_balance, details_t(xact));
last_balance.round();
last_xact = &xact;
}
void subtotal_transactions::report_subtotal(const char * spec_fmt)
{
char buf[256];
if (! spec_fmt) {
std::string fmt = "- ";
fmt += format_t::date_format;
std::strftime(buf, 255, fmt.c_str(), std::localtime(&finish));
} else {
std::strftime(buf, 255, spec_fmt, std::localtime(&finish));
}
entry_temps.push_back(entry_t());
entry_t& entry = entry_temps.back();
entry.payee = buf;
entry.date = start;
for (values_map::iterator i = values.begin();
i != values.end();
i++)
handle_value((*i).second.value, (*i).second.account, &entry, 0,
xact_temps, *handler, finish);
values.clear();
}
void subtotal_transactions::operator()(transaction_t& xact)
{
if (! start || std::difftime(xact.entry->date, start) < 0)
start = xact.entry->date;
if (! finish || std::difftime(xact.entry->date, finish) > 0)
finish = xact.entry->date;
account_t * acct = xact.account;
assert(acct);
values_map::iterator i = values.find(acct->fullname());
if (i == values.end()) {
value_t temp;
add_transaction_to(xact, temp);
values.insert(values_pair(acct->fullname(), acct_value_t(acct, temp)));
} else {
add_transaction_to(xact, (*i).second.value);
}
// If the account for this transaction is all virtual, mark it as
// such, so that `handle_value' can show "(Account)" for accounts
// that contain only virtual transactions.
if (! (xact.flags & TRANSACTION_VIRTUAL))
account_xdata(*xact.account).dflags |= ACCOUNT_HAS_NON_VIRTUALS;
else if (! (xact.flags & TRANSACTION_BALANCE))
account_xdata(*xact.account).dflags |= ACCOUNT_HAS_UNB_VIRTUALS;
}
void interval_transactions::report_subtotal(const std::time_t moment)
{
assert(last_xact);
start = interval.begin;
if (moment)
finish = moment - 86400;
else
finish = last_xact->entry->date;
subtotal_transactions::report_subtotal();
if (sorter)
sorter->post_accumulated_xacts();
last_xact = NULL;
}
void interval_transactions::operator()(transaction_t& xact)
{
const std::time_t date = xact.entry->date;
if ((interval.begin && std::difftime(date, interval.begin) < 0) ||
(interval.end && std::difftime(date, interval.end) >= 0))
return;
if (interval) {
if (! started) {
if (! interval.begin)
interval.start(date);
start = interval.begin;
started = true;
}
std::time_t quant = interval.increment(interval.begin);
if (std::difftime(date, quant) >= 0) {
if (last_xact)
report_subtotal(quant);
std::time_t temp;
while (std::difftime(date, temp = interval.increment(quant)) >= 0) {
if (quant == temp)
break;
quant = temp;
}
start = interval.begin = quant;
}
subtotal_transactions::operator()(xact);
} else {
item_handler<transaction_t>::operator()(xact);
}
last_xact = &xact;
}
by_payee_transactions::~by_payee_transactions()
{
for (payee_subtotals_map::iterator i = payee_subtotals.begin();
i != payee_subtotals.end();
i++)
delete (*i).second;
}
void by_payee_transactions::flush()
{
for (payee_subtotals_map::iterator i = payee_subtotals.begin();
i != payee_subtotals.end();
i++)
(*i).second->report_subtotal((*i).first.c_str());
item_handler<transaction_t>::flush();
payee_subtotals.clear();
}
void by_payee_transactions::operator()(transaction_t& xact)
{
payee_subtotals_map::iterator i = payee_subtotals.find(xact.entry->payee);
if (i == payee_subtotals.end()) {
payee_subtotals_pair temp(xact.entry->payee,
new subtotal_transactions(handler));
std::pair<payee_subtotals_map::iterator, bool> result
= payee_subtotals.insert(temp);
assert(result.second);
if (! result.second)
return;
i = result.first;
}
if (std::difftime(xact.entry->date, (*i).second->start) > 0)
(*i).second->start = xact.entry->date;
(*(*i).second)(xact);
}
void set_comm_as_payee::operator()(transaction_t& xact)
{
entry_temps.push_back(*xact.entry);
entry_t& entry = entry_temps.back();
entry.date = xact.entry->date;
entry.state = xact.entry->state;
entry.code = xact.entry->code;
entry.payee = xact.amount.commodity().symbol;
xact_temps.push_back(xact);
transaction_t& temp = xact_temps.back();
temp.entry = &entry;
temp.flags |= TRANSACTION_BULK_ALLOC;
entry.add_transaction(&temp);
item_handler<transaction_t>::operator()(temp);
}
void dow_transactions::flush()
{
for (int i = 0; i < 7; i++) {
start = finish = 0;
for (transactions_list::iterator d = days_of_the_week[i].begin();
d != days_of_the_week[i].end();
d++)
subtotal_transactions::operator()(**d);
subtotal_transactions::report_subtotal("%As");
days_of_the_week[i].clear();
}
subtotal_transactions::flush();
}
void generate_transactions::add_period_entries
(period_entries_list& period_entries)
{
for (period_entries_list::iterator i = period_entries.begin();
i != period_entries.end();
i++)
for (transactions_list::iterator j = (*i)->transactions.begin();
j != (*i)->transactions.end();
j++)
add_transaction((*i)->period, **j);
}
void generate_transactions::add_transaction(const interval_t& period,
transaction_t& xact)
{
pending_xacts.push_back(pending_xacts_pair(period, &xact));
}
void budget_transactions::report_budget_items(const std::time_t moment)
{
if (pending_xacts.size() == 0)
return;
bool reported;
do {
reported = false;
for (pending_xacts_list::iterator i = pending_xacts.begin();
i != pending_xacts.end();
i++) {
std::time_t& begin = (*i).first.begin;
if (! begin) {
(*i).first.start(moment);
begin = (*i).first.begin;
}
if (std::difftime(begin, moment) < 0 &&
(! (*i).first.end || std::difftime(begin, (*i).first.end) < 0)) {
transaction_t& xact = *(*i).second;
DEBUG_PRINT("ledger.walk.budget", "Reporting budget for "
<< xact.account->fullname());
DEBUG_PRINT_TIME("ledger.walk.budget", begin);
DEBUG_PRINT_TIME("ledger.walk.budget", moment);
entry_temps.push_back(entry_t());
entry_t& entry = entry_temps.back();
entry.payee = "Budget entry";
entry.date = begin;
xact_temps.push_back(xact);
transaction_t& temp = xact_temps.back();
temp.entry = &entry;
temp.flags |= TRANSACTION_AUTO;
temp.amount.negate();
temp.flags |= TRANSACTION_BULK_ALLOC;
entry.add_transaction(&temp);
begin = (*i).first.increment(begin);
item_handler<transaction_t>::operator()(temp);
reported = true;
}
}
} while (reported);
}
void budget_transactions::operator()(transaction_t& xact)
{
bool xact_in_budget = false;
for (pending_xacts_list::iterator i = pending_xacts.begin();
i != pending_xacts.end();
i++)
for (account_t * acct = xact.account; acct; acct = acct->parent) {
if (acct == (*i).second->account) {
xact_in_budget = true;
// Report the transaction as if it had occurred in the parent
// account. jww (2005-07-13): Note that this assignment will
// irrevocably change the underlying transaction.
if (xact.account != acct)
xact.account = acct;
goto handle;
}
}
handle:
if (xact_in_budget && flags & BUDGET_BUDGETED) {
report_budget_items(xact.entry->date);
item_handler<transaction_t>::operator()(xact);
}
else if (! xact_in_budget && flags & BUDGET_UNBUDGETED) {
item_handler<transaction_t>::operator()(xact);
}
}
void forecast_transactions::add_transaction(const interval_t& period,
transaction_t& xact)
{
generate_transactions::add_transaction(period, xact);
interval_t& i = pending_xacts.back().first;
if (! i.begin) {
i.start(now);
i.begin = i.increment(i.begin);
} else {
while (std::difftime(i.begin, now) < 0)
i.begin = i.increment(i.begin);
}
}
void forecast_transactions::flush()
{
transactions_list passed;
std::time_t last = 0;
while (pending_xacts.size() > 0) {
pending_xacts_list::iterator least = pending_xacts.begin();
for (pending_xacts_list::iterator i = ++pending_xacts.begin();
i != pending_xacts.end();
i++)
if (std::difftime((*i).first.begin, (*least).first.begin) < 0)
least = i;
std::time_t& begin = (*least).first.begin;
if ((*least).first.end &&
std::difftime(begin, (*least).first.end) >= 0) {
pending_xacts.erase(least);
passed.remove((*least).second);
continue;
}
transaction_t& xact = *(*least).second;
entry_temps.push_back(entry_t());
entry_t& entry = entry_temps.back();
entry.payee = "Forecast entry";
entry.date = begin;
xact_temps.push_back(xact);
transaction_t& temp = xact_temps.back();
temp.entry = &entry;
temp.flags |= TRANSACTION_AUTO;
temp.flags |= TRANSACTION_BULK_ALLOC;
entry.add_transaction(&temp);
std::time_t next = (*least).first.increment(begin);
if (std::difftime(next, begin) < 0 || // wraparound
(last && std::difftime(next, last) > 5 * 365 * 24 * 60 * 60))
break;
begin = next;
item_handler<transaction_t>::operator()(temp);
if (transaction_has_xdata(temp) &&
transaction_xdata_(temp).dflags & TRANSACTION_MATCHES) {
if (! pred(temp))
break;
last = temp.entry->date;
passed.clear();
} else {
bool found = false;
for (transactions_list::iterator i = passed.begin();
i != passed.end();
i++)
if (*i == &xact) {
found = true;
break;
}
if (! found) {
passed.push_back(&xact);
if (passed.size() >= pending_xacts.size())
break;
}
}
}
item_handler<transaction_t>::flush();
}
void clear_transactions_xdata()
{
transactions_xdata.clear();
for (std::list<void **>::iterator i = transactions_xdata_ptrs.begin();
i != transactions_xdata_ptrs.end();
i++)
**i = NULL;
transactions_xdata_ptrs.clear();
}
template <>
bool compare_items<account_t>::operator()(const account_t * left,
const account_t * right)
{
assert(left);
assert(right);
account_xdata_t& lxdata(account_xdata(*left));
if (! (lxdata.dflags & ACCOUNT_SORT_CALC)) {
sort_order->compute(lxdata.sort_value, details_t(*left));
lxdata.dflags |= ACCOUNT_SORT_CALC;
}
account_xdata_t& rxdata(account_xdata(*right));
if (! (rxdata.dflags & ACCOUNT_SORT_CALC)) {
sort_order->compute(rxdata.sort_value, details_t(*right));
rxdata.dflags |= ACCOUNT_SORT_CALC;
}
return lxdata.sort_value < rxdata.sort_value;
}
account_xdata_t& account_xdata(const account_t& account)
{
if (! account.data) {
accounts_xdata.push_back(account_xdata_t());
account.data = &accounts_xdata.back();
accounts_xdata_ptrs.push_back(&account.data);
}
return *((account_xdata_t *) account.data);
}
void sum_accounts(account_t& account)
{
account_xdata_t& xdata(account_xdata(account));
for (accounts_map::iterator i = account.accounts.begin();
i != account.accounts.end();
i++) {
sum_accounts(*(*i).second);
xdata.total += account_xdata_(*(*i).second).total;
xdata.total_count += (account_xdata_(*(*i).second).total_count +
account_xdata_(*(*i).second).count);
}
value_t result;
compute_amount(result, details_t(account));
if (result)
xdata.total += result;
xdata.total_count += xdata.count;
}
void sort_accounts(account_t& account,
const value_expr_t * sort_order,
accounts_deque& accounts)
{
for (accounts_map::iterator i = account.accounts.begin();
i != account.accounts.end();
i++)
accounts.push_back((*i).second);
std::stable_sort(accounts.begin(), accounts.end(),
compare_items<account_t>(sort_order));
}
void walk_accounts(account_t& account,
item_handler<account_t>& handler,
const value_expr_t * sort_order)
{
handler(account);
if (sort_order) {
accounts_deque accounts;
sort_accounts(account, sort_order, accounts);
for (accounts_deque::const_iterator i = accounts.begin();
i != accounts.end();
i++) {
account_xdata(**i).dflags &= ~ACCOUNT_SORT_CALC;
walk_accounts(**i, handler, sort_order);
}
} else {
for (accounts_map::const_iterator i = account.accounts.begin();
i != account.accounts.end();
i++)
walk_accounts(*(*i).second, handler, NULL);
}
}
void walk_accounts(account_t& account,
item_handler<account_t>& handler,
const std::string& sort_string)
{
if (! sort_string.empty()) {
std::auto_ptr<value_expr_t> sort_order;
try {
sort_order.reset(parse_value_expr(sort_string));
}
catch (value_expr_error& err) {
throw error(std::string("In sort string '" + sort_string + "': " +
err.what()));
}
walk_accounts(account, handler, sort_order.get());
} else {
walk_accounts(account, handler);
}
}
void clear_accounts_xdata()
{
accounts_xdata.clear();
for (std::list<void **>::iterator i = accounts_xdata_ptrs.begin();
i != accounts_xdata_ptrs.end();
i++)
**i = NULL;
accounts_xdata_ptrs.clear();
}
void walk_commodities(commodities_map& commodities,
item_handler<transaction_t>& handler)
{
std::list<transaction_t> xact_temps;
std::list<entry_t> entry_temps;
std::list<account_t> acct_temps;
for (commodities_map::iterator i = commodities.begin();
i != commodities.end();
i++) {
if ((*i).second->flags & COMMODITY_STYLE_NOMARKET)
continue;
entry_temps.push_back(entry_t());
acct_temps.push_back(account_t(NULL, (*i).second->symbol));
if ((*i).second->history)
for (history_map::iterator j = (*i).second->history->prices.begin();
j != (*i).second->history->prices.end();
j++) {
entry_temps.back().date = (*j).first;
xact_temps.push_back(transaction_t(&acct_temps.back()));
transaction_t& temp = xact_temps.back();
temp.entry = &entry_temps.back();
temp.amount = (*j).second;
temp.flags |= TRANSACTION_BULK_ALLOC;
entry_temps.back().add_transaction(&temp);
handler(xact_temps.back());
}
}
handler.flush();
clear_entries_transactions(entry_temps);
}
} // namespace ledger
#ifdef USE_BOOST_PYTHON
#include <boost/python.hpp>
using namespace boost::python;
using namespace ledger;
template <typename T>
struct item_handler_wrap : public item_handler<T>
{
PyObject * self;
item_handler_wrap(PyObject * self_) : self(self_) {}
item_handler_wrap(PyObject * self_, const item_handler<T>& _handler)
: item_handler<T>(const_cast<item_handler<T> *>(&_handler)),
self(self_) {}
item_handler_wrap(PyObject * self_, item_handler<T> * _handler)
: item_handler<T>(_handler), self(self_) {}
virtual void flush() {
call_method<void>(self, "flush");
}
void default_flush() {
item_handler<T>::flush();
}
virtual void operator()(T& item) {
call_method<void>(self, "__call__", ptr(&item));
}
void default_call(T& item) {
item_handler<T>::operator()(item);
}
};
void (subtotal_transactions::*subtotal_transactions_flush)() =
&subtotal_transactions::flush;
void py_walk_entries(journal_t& journal,
item_handler<transaction_t>& handler) {
walk_entries(journal.entries, handler);
}
void py_walk_transactions(entry_t& entry,
item_handler<transaction_t>& handler) {
walk_transactions(entry.transactions, handler);
}
void py_walk_accounts_1(account_t& account,
item_handler<account_t>& handler) {
walk_accounts(account, handler);
}
void py_walk_accounts_2(account_t& account,
item_handler<account_t>& handler,
const value_expr_t * sort_order) {
walk_accounts(account, handler, sort_order);
}
void py_walk_accounts_3(account_t& account,
item_handler<account_t>& handler,
const std::string& sort_string) {
walk_accounts(account, handler, sort_string);
}
void py_walk_commodities(item_handler<transaction_t>& handler) {
walk_commodities(commodity_t::commodities, handler);
}
void py_add_period_entries(generate_transactions& handler,
journal_t * journal) {
handler.add_period_entries(journal->period_entries);
}
void export_walk()
{
typedef item_handler<transaction_t> xact_handler_t;
scope().attr("TRANSACTION_RECEIVED") = TRANSACTION_RECEIVED;
scope().attr("TRANSACTION_HANDLED") = TRANSACTION_HANDLED;
scope().attr("TRANSACTION_TO_DISPLAY") = TRANSACTION_TO_DISPLAY;
scope().attr("TRANSACTION_DISPLAYED") = TRANSACTION_DISPLAYED;
scope().attr("TRANSACTION_NO_TOTAL") = TRANSACTION_NO_TOTAL;
scope().attr("TRANSACTION_SORT_CALC") = TRANSACTION_SORT_CALC;
scope().attr("TRANSACTION_COMPOSITE") = TRANSACTION_COMPOSITE;
scope().attr("TRANSACTION_MATCHES") = TRANSACTION_MATCHES;
class_< transaction_xdata_t > ("TransactionXData")
.def_readwrite("total", &transaction_xdata_t::total)
.def_readwrite("sort_value", &transaction_xdata_t::sort_value)
.def_readwrite("composite_amount", &transaction_xdata_t::composite_amount)
.def_readwrite("index", &transaction_xdata_t::index)
.def_readwrite("dflags", &transaction_xdata_t::dflags)
;
def("transaction_has_xdata", transaction_has_xdata);
def("transaction_xdata", transaction_xdata, return_internal_reference<1>());
def("clear_transactions_xdata", clear_transactions_xdata);
def("add_transaction_to", add_transaction_to);
class_< xact_handler_t, item_handler_wrap<transaction_t> >
("TransactionHandler")
.def(init<xact_handler_t *>()[with_custodian_and_ward<1, 2>()])
.def("flush", &xact_handler_t::flush,
&item_handler_wrap<transaction_t>::default_flush)
.def("__call__", &xact_handler_t::operator(),
&item_handler_wrap<transaction_t>::default_call)
;
class_< ignore_transactions, bases<xact_handler_t> >
("IgnoreTransactions")
.def("flush", &xact_handler_t::flush)
.def("__call__", &ignore_transactions::operator());
;
class_< truncate_entries, bases<xact_handler_t> >
("TruncateEntries", init<xact_handler_t *, int, int>()
[with_custodian_and_ward<1, 2>()])
.def("flush", &truncate_entries::flush)
.def("__call__", &truncate_entries::operator());
;
class_< set_account_value, bases<xact_handler_t> > ("SetAccountValue")
.def(init<xact_handler_t *>()[with_custodian_and_ward<1, 2>()])
.def("flush", &xact_handler_t::flush)
.def("__call__", &set_account_value::operator());
;
class_< sort_transactions, bases<xact_handler_t> >
("SortTransactions", init<xact_handler_t *, const value_expr_t *>()
[with_custodian_and_ward<1, 2>()])
.def(init<xact_handler_t *, const std::string&>()
[with_custodian_and_ward<1, 2>()])
.def("flush", &sort_transactions::flush)
.def("__call__", &sort_transactions::operator());
;
class_< filter_transactions, bases<xact_handler_t> >
("FilterTransactions", init<xact_handler_t *, std::string>()
[with_custodian_and_ward<1, 2>()])
.def(init<xact_handler_t *, const std::string&>()
[with_custodian_and_ward<1, 2>()])
.def("flush", &xact_handler_t::flush)
.def("__call__", &filter_transactions::operator());
;
class_< calc_transactions, bases<xact_handler_t> >
("CalcTransactions", init<xact_handler_t *>()
[with_custodian_and_ward<1, 2>()])
.def("flush", &xact_handler_t::flush)
.def("__call__", &calc_transactions::operator());
;
class_< invert_transactions, bases<xact_handler_t> >
("InvertTransactions", init<xact_handler_t *>()
[with_custodian_and_ward<1, 2>()])
.def("flush", &xact_handler_t::flush)
.def("__call__", &invert_transactions::operator());
;
class_< collapse_transactions, bases<xact_handler_t> >
("CollapseTransactions", init<xact_handler_t *>()
[with_custodian_and_ward<1, 2>()])
.def("flush", &collapse_transactions::flush)
.def("__call__", &collapse_transactions::operator());
;
class_< related_transactions, bases<xact_handler_t> >
("RelatedTransactions", init<xact_handler_t *, optional<bool> >()
[with_custodian_and_ward<1, 2>()])
.def("flush", &xact_handler_t::flush)
.def("__call__", &related_transactions::operator());
;
class_< changed_value_transactions, bases<xact_handler_t> >
("ChangeValueTransactions", init<xact_handler_t *, bool>()
[with_custodian_and_ward<1, 2>()])
.def("flush", &changed_value_transactions::flush)
.def("__call__", &changed_value_transactions::operator());
;
class_< subtotal_transactions, bases<xact_handler_t> >
("SubtotalTransactions", init<xact_handler_t *>()
[with_custodian_and_ward<1, 2>()])
.def("flush", subtotal_transactions_flush)
.def("__call__", &subtotal_transactions::operator());
;
class_< interval_transactions, bases<xact_handler_t> >
("IntervalTransactions",
init<xact_handler_t *, interval_t, optional<value_expr_t *> >()
[with_custodian_and_ward<1, 2>()])
.def(init<xact_handler_t *, const std::string&,
optional<const std::string&> >()
[with_custodian_and_ward<1, 2>()])
.def("flush", &xact_handler_t::flush)
.def("__call__", &interval_transactions::operator());
;
class_< by_payee_transactions, bases<xact_handler_t> >
("ByPayeeTransactions", init<xact_handler_t *>()
[with_custodian_and_ward<1, 2>()])
.def("flush", &by_payee_transactions::flush)
.def("__call__", &by_payee_transactions::operator());
;
class_< set_comm_as_payee, bases<xact_handler_t> >
("SetCommAsPayee", init<xact_handler_t *>()
[with_custodian_and_ward<1, 2>()])
.def("flush", &xact_handler_t::flush)
.def("__call__", &xact_handler_t::operator());
;
class_< dow_transactions, bases<xact_handler_t> >
("DowTransactions", init<xact_handler_t *>()
[with_custodian_and_ward<1, 2>()])
.def("flush", &dow_transactions::flush)
.def("__call__", &dow_transactions::operator());
;
scope().attr("BUDGET_BUDGETED") = BUDGET_BUDGETED;
scope().attr("BUDGET_UNBUDGETED") = BUDGET_UNBUDGETED;
class_< generate_transactions, bases<xact_handler_t> >
("GenerateTransactions", init<xact_handler_t *>()
[with_custodian_and_ward<1, 2>()])
.def("add_transaction", &generate_transactions::add_transaction)
.def("add_period_entries", py_add_period_entries)
.def("flush", &xact_handler_t::flush)
.def("__call__", &xact_handler_t::operator());
;
class_< budget_transactions, bases<generate_transactions> >
("BudgetTransactions",
init<xact_handler_t *, unsigned long>()
[with_custodian_and_ward<1, 2>()])
.def("add_transaction", &generate_transactions::add_transaction)
.def("add_period_entries", py_add_period_entries)
.def("flush", &budget_transactions::flush)
.def("__call__", &xact_handler_t::operator());
;
class_< forecast_transactions, bases<generate_transactions> >
("ForecastTransactions",
init<xact_handler_t *, std::string>()
[with_custodian_and_ward<1, 2>()])
.def("add_transaction", &forecast_transactions::add_transaction)
.def("add_period_entries", py_add_period_entries)
.def("flush", &forecast_transactions::flush)
.def("__call__", &xact_handler_t::operator());
;
def("walk_entries", py_walk_entries);
def("walk_transactions", py_walk_transactions);
typedef item_handler<account_t> account_handler_t;
scope().attr("ACCOUNT_TO_DISPLAY") = ACCOUNT_TO_DISPLAY;
scope().attr("ACCOUNT_DISPLAYED") = ACCOUNT_DISPLAYED;
scope().attr("ACCOUNT_SORT_CALC") = ACCOUNT_SORT_CALC;
class_< account_xdata_t > ("AccountXData")
.def_readwrite("value", &account_xdata_t::value)
.def_readwrite("total", &account_xdata_t::total)
.def_readwrite("sort_value", &account_xdata_t::sort_value)
.def_readwrite("count", &account_xdata_t::count)
.def_readwrite("total_count", &account_xdata_t::total_count)
.def_readwrite("virtuals", &account_xdata_t::virtuals)
.def_readwrite("dflags", &account_xdata_t::dflags)
;
def("account_has_xdata", account_has_xdata);
def("account_xdata", account_xdata, return_internal_reference<1>());
def("clear_accounts_xdata", clear_accounts_xdata);
def("clear_all_xdata", clear_all_xdata);
class_< account_handler_t, item_handler_wrap<account_t> >
("AccountHandler")
.def(init<account_handler_t *>()[with_custodian_and_ward<1, 2>()])
.def("flush", &account_handler_t::flush,
&item_handler_wrap<account_t>::default_flush)
.def("__call__", &account_handler_t::operator(),
&item_handler_wrap<account_t>::default_call)
;
def("sum_accounts", sum_accounts);
def("walk_accounts", py_walk_accounts_1);
def("walk_accounts", py_walk_accounts_2);
def("walk_accounts", py_walk_accounts_3);
def("walk_commodities", py_walk_commodities);
}
#endif // USE_BOOST_PYTHON