Factored common parts of entry_t and xact_t into new item_t

This commit is contained in:
John Wiegley 2008-09-19 08:06:20 -04:00
parent 43ba0bb038
commit fdc7a4e4c5
24 changed files with 444 additions and 418 deletions

View file

@ -38,8 +38,9 @@ endif
libledger_la_CPPFLAGS = $(libamounts_la_CPPFLAGS) libledger_la_CPPFLAGS = $(libamounts_la_CPPFLAGS)
libledger_la_LDFLAGS = -release 3.0.0 libledger_la_LDFLAGS = -release 3.0.0
libledger_la_SOURCES = \ libledger_la_SOURCES = \
src/journal.cc \ src/journal.cc \
src/item.cc \
src/entry.cc \ src/entry.cc \
src/xact.cc \ src/xact.cc \
src/account.cc \ src/account.cc \
@ -102,6 +103,7 @@ pkginclude_HEADERS = \
src/option.h \ src/option.h \
\ \
src/journal.h \ src/journal.h \
src/item.h \
src/entry.h \ src/entry.h \
src/xact.h \ src/xact.h \
src/account.h \ src/account.h \

View file

@ -73,7 +73,7 @@ account_t * account_t::find_account(const string& name,
if (! auto_create) if (! auto_create)
return NULL; return NULL;
account = new account_t(owner, this, first); account = new account_t(this, first);
std::pair<accounts_map::iterator, bool> result std::pair<accounts_map::iterator, bool> result
= accounts.insert(accounts_map::value_type(first, account)); = accounts.insert(accounts_map::value_type(first, account));
assert(result.second); assert(result.second);
@ -190,8 +190,7 @@ expr_t::ptr_op_t account_t::lookup(const string& name)
break; break;
} }
assert(owner == session_t::current); return session_t::current->current_report->lookup(name);
return owner->current_report->lookup(name);
} }
bool account_t::valid() const bool account_t::valid() const
@ -234,7 +233,7 @@ void account_t::calculate_sums()
} }
call_scope_t args(*this); call_scope_t args(*this);
value_t amount(owner->current_report->get_amount_expr(args)); value_t amount(session_t::current->current_report->get_amount_expr(args));
if (! amount.is_null()) { if (! amount.is_null()) {
add_or_set_value(xd.total, amount); add_or_set_value(xd.total, amount);
xd.total_count += xd.count; xd.total_count += xd.count;

View file

@ -47,7 +47,6 @@ class account_t : public scope_t
public: public:
typedef unsigned long ident_t; typedef unsigned long ident_t;
session_t * owner;
account_t * parent; account_t * parent;
string name; string name;
optional<string> note; optional<string> note;
@ -58,17 +57,15 @@ class account_t : public scope_t
mutable ident_t ident; mutable ident_t ident;
mutable string _fullname; mutable string _fullname;
account_t(session_t * _owner, account_t(account_t * _parent = NULL,
account_t * _parent = NULL,
const string& _name = "", const string& _name = "",
const optional<string>& _note = none) const optional<string>& _note = none)
: scope_t(), owner(_owner), parent(_parent), name(_name), note(_note), : scope_t(), parent(_parent), name(_name), note(_note),
depth(parent ? parent->depth + 1 : 0), data(NULL), ident(0) { depth(parent ? parent->depth + 1 : 0), data(NULL), ident(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(), : scope_t(),
owner(other.owner),
parent(other.parent), parent(other.parent),
name(other.name), name(other.name),
note(other.note), note(other.note),

View file

@ -102,28 +102,15 @@ void format_csv_xacts::operator()(xact_t& xact)
} }
out << ','; out << ',';
switch (xact.state) { switch (xact.state()) {
case xact_t::CLEARED: case item_t::CLEARED:
write_escaped_string(out, "*"); write_escaped_string(out, "*");
break; break;
case xact_t::PENDING: case item_t::PENDING:
write_escaped_string(out, "!"); write_escaped_string(out, "!");
break; break;
default: { default:
xact_t::state_t state; break;
if (xact.entry->get_state(&state))
switch (state) {
case xact_t::CLEARED:
write_escaped_string(out, "*");
break;
case xact_t::PENDING:
write_escaped_string(out, "!");
break;
default:
write_escaped_string(out, "");
break;
}
}
} }
out << ','; out << ',';

View file

@ -45,7 +45,7 @@ void format_emacs_xacts::write_entry(entry_t& entry)
out << (static_cast<unsigned long>(entry.beg_line) + 1) << " "; out << (static_cast<unsigned long>(entry.beg_line) + 1) << " ";
tm when = gregorian::to_tm(entry.date()); tm when = gregorian::to_tm(*entry.date());
std::time_t date = std::mktime(&when); // jww (2008-04-20): Is this GMT or local? std::time_t date = std::mktime(&when); // jww (2008-04-20): Is this GMT or local?
out << "(" << (date / 65536) << " " << (date % 65536) << " 0) "; out << "(" << (date / 65536) << " " << (date % 65536) << " 0) ";
@ -83,11 +83,11 @@ void format_emacs_xacts::operator()(xact_t& xact)
out << "\"" << xact.reported_account()->fullname() << "\" \"" out << "\"" << xact.reported_account()->fullname() << "\" \""
<< xact.amount << "\""; << xact.amount << "\"";
switch (xact.state) { switch (xact.state()) {
case xact_t::CLEARED: case item_t::CLEARED:
out << " t"; out << " t";
break; break;
case xact_t::PENDING: case item_t::PENDING:
out << " pending"; out << " pending";
break; break;
default: default:

View file

@ -38,8 +38,7 @@
namespace ledger { namespace ledger {
entry_base_t::entry_base_t(const entry_base_t& e) entry_base_t::entry_base_t(const entry_base_t& e)
: supports_flags<>(), journal(NULL), : item_t(), journal(NULL)
beg_pos(0), beg_line(0), end_pos(0), end_line(0)
{ {
TRACE_CTOR(entry_base_t, "copy"); TRACE_CTOR(entry_base_t, "copy");
xacts.insert(xacts.end(), e.xacts.begin(), e.xacts.end()); xacts.insert(xacts.end(), e.xacts.begin(), e.xacts.end());
@ -53,8 +52,8 @@ entry_base_t::~entry_base_t()
// If the transaction is a temporary, it will be destructed when the // If the transaction is a temporary, it will be destructed when the
// temporary is. If it's from a binary cache, we can safely destruct it // temporary is. If it's from a binary cache, we can safely destruct it
// but its memory will be deallocated with the cache. // but its memory will be deallocated with the cache.
if (! xact->has_flags(XACT_TEMP)) { if (! xact->has_flags(ITEM_TEMP)) {
if (! xact->has_flags(XACT_IN_CACHE)) if (! xact->has_flags(ITEM_IN_CACHE))
checked_delete(xact); checked_delete(xact);
else else
xact->~xact_t(); xact->~xact_t();
@ -62,6 +61,20 @@ entry_base_t::~entry_base_t()
} }
} }
item_t::state_t entry_base_t::state() const
{
bool first = true;
state_t result = UNCLEARED;
foreach (xact_t * xact, xacts) {
if ((result == UNCLEARED && xact->_state != UNCLEARED) ||
(result == PENDING && xact->_state == CLEARED))
result = xact->_state;
}
return result;
}
void entry_base_t::add_xact(xact_t * xact) void entry_base_t::add_xact(xact_t * xact)
{ {
xacts.push_back(xact); xacts.push_back(xact);
@ -133,8 +146,8 @@ bool entry_base_t::finalize()
if (journal && journal->basket && xacts.size() == 1 && ! balance.is_null()) { if (journal && journal->basket && xacts.size() == 1 && ! balance.is_null()) {
// jww (2008-07-24): Need to make the rest of the code aware of what to do // jww (2008-07-24): Need to make the rest of the code aware of what to do
// when it sees a generated xact. // when it sees a generated xact.
null_xact = new xact_t(journal->basket, XACT_GENERATED); null_xact = new xact_t(journal->basket, ITEM_GENERATED);
null_xact->state = (*xacts.begin())->state; null_xact->_state = (*xacts.begin())->_state;
add_xact(null_xact); add_xact(null_xact);
} }
@ -170,7 +183,7 @@ bool entry_base_t::finalize()
first = false; first = false;
} else { } else {
add_xact(new xact_t(null_xact->account, pair.second.negate(), add_xact(new xact_t(null_xact->account, pair.second.negate(),
XACT_GENERATED)); ITEM_GENERATED));
} }
} }
} }
@ -279,7 +292,7 @@ bool entry_base_t::finalize()
amount_t basis_cost; amount_t basis_cost;
amount_t ann_amount = amount_t ann_amount =
commodity_t::exchange(x_amt, final_cost, basis_cost, xact->cost, none, commodity_t::exchange(x_amt, final_cost, basis_cost, xact->cost, none,
datetime_t(xact->actual_date(), datetime_t(*xact->actual_date(),
time_duration_t(0, 0, 0)), time_duration_t(0, 0, 0)),
entry ? entry->code : optional<string>()); entry ? entry->code : optional<string>());
@ -341,8 +354,7 @@ bool entry_base_t::finalize()
} }
entry_t::entry_t(const entry_t& e) entry_t::entry_t(const entry_t& e)
: entry_base_t(e), scope_t(), _date(e._date), _date_eff(e._date_eff), : entry_base_t(e), code(e.code), payee(e.payee)
code(e.code), payee(e.payee)
{ {
TRACE_CTOR(entry_t, "copy"); TRACE_CTOR(entry_t, "copy");
@ -350,27 +362,6 @@ entry_t::entry_t(const entry_t& e)
xact->entry = this; xact->entry = this;
} }
bool entry_t::get_state(xact_t::state_t * state) const
{
bool first = true;
bool hetero = false;
foreach (xact_t * xact, xacts) {
if (first ||
xact->state == xact_t::CLEARED ||
(xact->state == xact_t::PENDING && *state == xact_t::UNCLEARED)) {
*state = xact->state;
first = false;
}
else if (*state != xact->state) {
hetero = true;
break;
}
}
return ! hetero;
}
void entry_t::add_xact(xact_t * xact) void entry_t::add_xact(xact_t * xact)
{ {
xact->entry = this; xact->entry = this;
@ -378,26 +369,6 @@ void entry_t::add_xact(xact_t * xact)
} }
namespace { namespace {
value_t get_date(entry_t& entry) {
return entry.date();
}
value_t get_status(entry_t& entry) {
xact_t::state_t status;
entry.get_state(&status);
return long(status);
}
value_t get_cleared(entry_t& entry) {
xact_t::state_t status;
entry.get_state(&status);
return status == xact_t::CLEARED;
}
value_t get_pending(entry_t& entry) {
xact_t::state_t status;
entry.get_state(&status);
return status == xact_t::PENDING;
}
value_t get_code(entry_t& entry) { value_t get_code(entry_t& entry) {
if (entry.code) if (entry.code)
return string_value(*entry.code); return string_value(*entry.code);
@ -421,49 +392,20 @@ expr_t::ptr_op_t entry_t::lookup(const string& name)
case 'c': case 'c':
if (name == "code") if (name == "code")
return WRAP_FUNCTOR(get_wrapper<&get_code>); return WRAP_FUNCTOR(get_wrapper<&get_code>);
else if (name == "cleared")
return WRAP_FUNCTOR(get_wrapper<&get_cleared>);
break;
case 'd':
if (name[1] == '\0' || name == "date")
return WRAP_FUNCTOR(get_wrapper<&get_date>);
break; break;
case 'p': case 'p':
if (name[1] == '\0' || name == "payee") if (name[1] == '\0' || name == "payee")
return WRAP_FUNCTOR(get_wrapper<&get_payee>); return WRAP_FUNCTOR(get_wrapper<&get_payee>);
else if (name == "pending")
return WRAP_FUNCTOR(get_wrapper<&get_pending>);
break;
case 'u':
if (name == "uncleared")
return expr_t::op_t::wrap_value(1L);
break;
case 'X':
if (name[1] == '\0')
return WRAP_FUNCTOR(get_wrapper<&get_cleared>);
break;
case 'Y':
if (name[1] == '\0')
return WRAP_FUNCTOR(get_wrapper<&get_pending>);
break; break;
} }
if (journal) { return item_t::lookup(name);
assert(journal->owner == session_t::current);
return journal->owner->current_report->lookup(name);
} else {
return session_t::current->current_report->lookup(name);
}
} }
bool entry_t::valid() const bool entry_t::valid() const
{ {
if (! is_valid(_date) || ! journal) { if (! _date || ! journal) {
DEBUG("ledger.validate", "entry_t: ! _date || ! journal"); DEBUG("ledger.validate", "entry_t: ! _date || ! journal");
return false; return false;
} }
@ -514,19 +456,11 @@ void auto_entry_t::extend_entry(entry_base_t& entry, bool post)
if (fullname == "$account" || fullname == "@account") if (fullname == "$account" || fullname == "@account")
account = initial_xact->account; account = initial_xact->account;
xact_t * new_xact
= new xact_t(account, amt, xact->flags() | XACT_AUTO);
// Copy over details so that the resulting xact is a mirror of // Copy over details so that the resulting xact is a mirror of
// the automated entry's one. // the automated entry's one.
new_xact->state = xact->state; xact_t * new_xact = new xact_t(account, amt);
new_xact->_date = xact->_date; new_xact->copy_details(*xact);
new_xact->_date_eff = xact->_date_eff; new_xact->add_flags(XACT_AUTO);
new_xact->note = xact->note;
new_xact->beg_pos = xact->beg_pos;
new_xact->beg_line = xact->beg_line;
new_xact->end_pos = xact->end_pos;
new_xact->end_line = xact->end_line;
entry.add_xact(new_xact); entry.add_xact(new_xact);
} }

View file

@ -39,35 +39,20 @@ namespace ledger {
class journal_t; class journal_t;
class entry_base_t : public supports_flags<> class entry_base_t : public item_t
{ {
public: public:
#define ENTRY_IN_CACHE 0x1 journal_t * journal;
xacts_list xacts;
journal_t * journal; entry_base_t() : journal(NULL) {
string note;
unsigned long src_idx;
istream_pos_type beg_pos;
unsigned long beg_line;
istream_pos_type end_pos;
unsigned long end_line;
xacts_list xacts;
entry_base_t() : journal(NULL),
beg_pos(0), beg_line(0), end_pos(0), end_line(0)
{
TRACE_CTOR(entry_base_t, ""); TRACE_CTOR(entry_base_t, "");
} }
entry_base_t(const entry_base_t& e); entry_base_t(const entry_base_t& e);
virtual ~entry_base_t(); virtual ~entry_base_t();
bool operator==(const entry_base_t& entry) { virtual state_t state() const;
return this == &entry;
}
bool operator!=(const entry_base_t& entry) {
return ! (*this == entry);
}
virtual void add_xact(xact_t * xact); virtual void add_xact(xact_t * xact);
virtual bool remove_xact(xact_t * xact); virtual bool remove_xact(xact_t * xact);
@ -76,11 +61,9 @@ public:
virtual bool valid() const = 0; virtual bool valid() const = 0;
}; };
class entry_t : public entry_base_t, public scope_t class entry_t : public entry_base_t
{ {
public: public:
date_t _date;
optional<date_t> _date_eff;
optional<string> code; optional<string> code;
string payee; string payee;
@ -93,23 +76,6 @@ public:
TRACE_DTOR(entry_t); TRACE_DTOR(entry_t);
} }
date_t actual_date() const {
return _date;
}
date_t effective_date() const {
if (! _date_eff)
return _date;
return *_date_eff;
}
date_t date() const {
if (xact_t::use_effective_date)
return effective_date();
else
return actual_date();
}
bool get_state(xact_t::state_t * state) const;
virtual void add_xact(xact_t * xact); virtual void add_xact(xact_t * xact);
virtual expr_t::ptr_op_t lookup(const string& name); virtual expr_t::ptr_op_t lookup(const string& name);

View file

@ -180,7 +180,7 @@ void handle_value(const value_t& value,
temps.push_back(xact_t(account)); temps.push_back(xact_t(account));
xact_t& xact(temps.back()); xact_t& xact(temps.back());
xact.entry = entry; xact.entry = entry;
xact.add_flags(XACT_TEMP); xact.add_flags(ITEM_TEMP);
entry->add_xact(&xact); entry->add_xact(&xact);
// If there are component xacts to associate with this // If there are component xacts to associate with this
@ -390,9 +390,9 @@ void subtotal_xacts::report_subtotal(const char * spec_fmt)
void subtotal_xacts::operator()(xact_t& xact) void subtotal_xacts::operator()(xact_t& xact)
{ {
if (! is_valid(start) || xact.date() < start) if (! is_valid(start) || xact.date() < start)
start = xact.date(); start = *xact.date();
if (! is_valid(finish) || xact.date() > finish) if (! is_valid(finish) || xact.date() > finish)
finish = xact.date(); finish = *xact.date();
account_t * acct = xact.reported_account(); account_t * acct = xact.reported_account();
assert(acct); assert(acct);
@ -432,7 +432,7 @@ void interval_xacts::report_subtotal(const date_t& date)
if (is_valid(date)) if (is_valid(date))
finish = date - gregorian::days(1); finish = date - gregorian::days(1);
else else
finish = last_xact->date(); finish = *last_xact->date();
subtotal_xacts::report_subtotal(); subtotal_xacts::report_subtotal();
@ -441,7 +441,7 @@ void interval_xacts::report_subtotal(const date_t& date)
void interval_xacts::operator()(xact_t& xact) void interval_xacts::operator()(xact_t& xact)
{ {
const date_t& date(xact.date()); const date_t& date(*xact.date());
if ((is_valid(interval.begin) && date < interval.begin) || if ((is_valid(interval.begin) && date < interval.begin) ||
(is_valid(interval.end) && date >= interval.end)) (is_valid(interval.end) && date >= interval.end))
@ -512,7 +512,7 @@ void by_payee_xacts::operator()(xact_t& xact)
} }
if (xact.date() > (*i).second->start) if (xact.date() > (*i).second->start)
(*i).second->start = xact.date(); (*i).second->start = *xact.date();
(*(*i).second)(xact); (*(*i).second)(xact);
} }
@ -532,8 +532,8 @@ void set_comm_as_payee::operator()(xact_t& xact)
xact_temps.push_back(xact); xact_temps.push_back(xact);
xact_t& temp = xact_temps.back(); xact_t& temp = xact_temps.back();
temp.entry = &entry; temp.entry = &entry;
temp.state = xact.state; temp.set_state(xact.state());
temp.add_flags(XACT_TEMP); temp.add_flags(ITEM_TEMP);
entry.add_xact(&temp); entry.add_xact(&temp);
@ -554,8 +554,8 @@ void set_code_as_payee::operator()(xact_t& xact)
xact_temps.push_back(xact); xact_temps.push_back(xact);
xact_t& temp = xact_temps.back(); xact_t& temp = xact_temps.back();
temp.entry = &entry; temp.entry = &entry;
temp.state = xact.state; temp.set_state(xact.state());
temp.add_flags(XACT_TEMP); temp.add_flags(ITEM_TEMP);
entry.add_xact(&temp); entry.add_xact(&temp);
@ -619,7 +619,7 @@ void budget_xacts::report_budget_items(const date_t& date)
xact_temps.push_back(xact); xact_temps.push_back(xact);
xact_t& temp = xact_temps.back(); xact_t& temp = xact_temps.back();
temp.entry = &entry; temp.entry = &entry;
temp.add_flags(XACT_AUTO | XACT_TEMP); temp.add_flags(XACT_AUTO | ITEM_TEMP);
temp.amount.negate(); temp.amount.negate();
entry.add_xact(&temp); entry.add_xact(&temp);
@ -653,7 +653,7 @@ void budget_xacts::operator()(xact_t& xact)
handle: handle:
if (xact_in_budget && flags & BUDGET_BUDGETED) { if (xact_in_budget && flags & BUDGET_BUDGETED) {
report_budget_items(xact.date()); report_budget_items(*xact.date());
item_handler<xact_t>::operator()(xact); item_handler<xact_t>::operator()(xact);
} }
else if (! xact_in_budget && flags & BUDGET_UNBUDGETED) { else if (! xact_in_budget && flags & BUDGET_UNBUDGETED) {
@ -706,7 +706,7 @@ void forecast_xacts::flush()
xact_temps.push_back(xact); xact_temps.push_back(xact);
xact_t& temp = xact_temps.back(); xact_t& temp = xact_temps.back();
temp.entry = &entry; temp.entry = &entry;
temp.add_flags(XACT_AUTO | XACT_TEMP); temp.add_flags(XACT_AUTO | ITEM_TEMP);
entry.add_xact(&temp); entry.add_xact(&temp);
date_t next = (*least).first.increment(begin); date_t next = (*least).first.increment(begin);
@ -720,7 +720,7 @@ void forecast_xacts::flush()
temp.xdata().has_flags(XACT_EXT_MATCHES)) { temp.xdata().has_flags(XACT_EXT_MATCHES)) {
if (! pred(temp)) if (! pred(temp))
break; break;
last = temp.date(); last = *temp.date();
passed.clear(); passed.clear();
} else { } else {
bool found = false; bool found = false;

View file

@ -290,7 +290,7 @@ public:
collapse_xacts(xact_handler_ptr handler, session_t& session) collapse_xacts(xact_handler_ptr handler, session_t& session)
: item_handler<xact_t>(handler), count(0), : item_handler<xact_t>(handler), count(0),
last_entry(NULL), last_xact(NULL), last_entry(NULL), last_xact(NULL),
totals_account(&session, NULL, "<Total>") { totals_account(NULL, "<Total>") {
TRACE_CTOR(collapse_xacts, "xact_handler_ptr"); TRACE_CTOR(collapse_xacts, "xact_handler_ptr");
} }
virtual ~collapse_xacts() { virtual ~collapse_xacts() {
@ -588,7 +588,7 @@ public:
virtual void flush(); virtual void flush();
virtual void operator()(xact_t& xact) { virtual void operator()(xact_t& xact) {
days_of_the_week[xact.date().day_of_week()].push_back(&xact); days_of_the_week[xact.date()->day_of_week()].push_back(&xact);
} }
}; };

View file

@ -89,7 +89,7 @@ static enum action_t {
static void startElement(void *, const char *name, const char **) static void startElement(void *, const char *name, const char **)
{ {
if (std::strcmp(name, "gnc:account") == 0) { if (std::strcmp(name, "gnc:account") == 0) {
curr_account = new account_t(master_account->owner, master_account); curr_account = new account_t(master_account);
} }
else if (std::strcmp(name, "act:name") == 0) else if (std::strcmp(name, "act:name") == 0)
action = ACCOUNT_NAME; action = ACCOUNT_NAME;
@ -193,7 +193,7 @@ static void endElement(void *, const char *name)
value = curr_quant; value = curr_quant;
} }
xact->state = curr_state; xact->set_state(curr_state);
xact->amount = value; xact->amount = value;
if (value != curr_value) if (value != curr_value)
xact->cost = curr_value; xact->cost = curr_value;

141
src/item.cc Normal file
View file

@ -0,0 +1,141 @@
/*
* Copyright (c) 2003-2008, 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 "item.h"
#include "session.h"
#include "report.h"
namespace ledger {
bool item_t::use_effective_date = false;
namespace {
value_t get_status(item_t& item) {
return long(item.state());
}
value_t get_cleared(item_t& item) {
return item.state() == item_t::CLEARED;
}
value_t get_pending(item_t& item) {
return item.state() == item_t::PENDING;
}
value_t get_date(item_t& item) {
if (optional<date_t> date = item.date())
return *date;
else
return 0L;
}
value_t get_note(item_t& item) {
return string_value(item.note ? *item.note : empty_string);
}
value_t get_beg_pos(item_t& item) {
return long(item.beg_pos);
}
value_t get_beg_line(item_t& item) {
return long(item.beg_line);
}
value_t get_end_pos(item_t& item) {
return long(item.end_pos);
}
value_t get_end_line(item_t& item) {
return long(item.end_line);
}
template <value_t (*Func)(item_t&)>
value_t get_wrapper(call_scope_t& scope) {
return (*Func)(find_scope<item_t>(scope));
}
}
expr_t::ptr_op_t item_t::lookup(const string& name)
{
switch (name[0]) {
case 'c':
if (name == "cleared")
return WRAP_FUNCTOR(get_wrapper<&get_cleared>);
break;
case 'd':
if (name[1] == '\0' || name == "date")
return WRAP_FUNCTOR(get_wrapper<&get_date>);
break;
case 'n':
if (name == "note")
return WRAP_FUNCTOR(get_wrapper<&get_note>);
break;
case 'p':
if (name == "pending")
return WRAP_FUNCTOR(get_wrapper<&get_pending>);
break;
case 's':
if (name == "status")
return WRAP_FUNCTOR(get_wrapper<&get_status>);
break;
case 'u':
if (name == "uncleared")
return expr_t::op_t::wrap_value(1L);
break;
case 'X':
if (name[1] == '\0')
return WRAP_FUNCTOR(get_wrapper<&get_cleared>);
break;
case 'Y':
if (name[1] == '\0')
return WRAP_FUNCTOR(get_wrapper<&get_pending>);
break;
}
return session_t::current->current_report->lookup(name);
}
bool item_t::valid() const
{
if (_state != UNCLEARED && _state != CLEARED && _state != PENDING) {
DEBUG("ledger.validate", "item_t: state is bad");
return false;
}
return true;
}
} // namespace ledger

135
src/item.h Normal file
View file

@ -0,0 +1,135 @@
/*
* Copyright (c) 2003-2008, 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.
*/
#ifndef _ITEM_H
#define _ITEM_H
#include "utils.h"
#include "scope.h"
namespace ledger {
class entry_t;
class account_t;
class item_t;
typedef std::list<item_t *> items_list;
class item_t : public supports_flags<>, public scope_t
{
public:
#define ITEM_NORMAL 0x0000 // no flags at all, a basic transaction
#define ITEM_IN_CACHE 0x0001 // transaction allocated by the binary cache
#define ITEM_GENERATED 0x0002 // transaction was not found in a journal
#define ITEM_TEMP 0x0004 // transaction is a temporary object
enum state_t { UNCLEARED = 0, CLEARED, PENDING };
state_t _state;
optional<date_t> _date;
optional<date_t> _date_eff;
optional<string> note;
unsigned short src_idx;
istream_pos_type beg_pos;
unsigned long beg_line;
istream_pos_type end_pos;
unsigned long end_line;
static bool use_effective_date;
item_t(flags_t _flags = ITEM_NORMAL, const optional<string>& _note = none)
: supports_flags<>(_flags), _state(UNCLEARED), note(_note),
beg_pos(0), beg_line(0), end_pos(0), end_line(0)
{
TRACE_CTOR(item_t, "flags_t, const string&");
}
item_t(const item_t& item) : supports_flags<>(), scope_t()
{
TRACE_CTOR(item_t, "copy");
copy_details(item);
}
virtual ~item_t() {
TRACE_DTOR(item_t);
}
void copy_details(const item_t& item)
{
set_flags(item.flags());
set_state(item.state());
_date = item._date;
_date_eff = item._date_eff;
note = item.note;
beg_pos = item.beg_pos;
beg_line = item.beg_line;
end_pos = item.end_pos;
end_line = item.end_line;
}
virtual bool operator==(const item_t& entry) {
return this == &entry;
}
virtual bool operator!=(const item_t& entry) {
return ! (*this == entry);
}
virtual optional<date_t> actual_date() const {
return _date;
}
virtual optional<date_t> effective_date() const {
return _date_eff;
}
optional<date_t> date() const {
if (use_effective_date && _date_eff)
return effective_date();
else
return actual_date();
}
void set_state(state_t new_state) {
_state = new_state;
}
virtual state_t state() const {
return _state;
}
virtual expr_t::ptr_op_t lookup(const string& name);
bool valid() const;
};
} // namespace ledger
#endif // _ITEM_H

View file

@ -36,11 +36,10 @@ namespace ledger {
const string version = PACKAGE_VERSION; const string version = PACKAGE_VERSION;
journal_t::journal_t(session_t * _owner) journal_t::journal_t() : basket(NULL)
: owner(_owner), basket(NULL)
{ {
TRACE_CTOR(journal_t, ""); TRACE_CTOR(journal_t, "");
master = owner->master.get(); master = session_t::current->master.get();
} }
journal_t::~journal_t() journal_t::~journal_t()
@ -51,19 +50,19 @@ journal_t::~journal_t()
// accounts they refer to, because all accounts are about to // accounts they refer to, because all accounts are about to
// be deleted. // be deleted.
foreach (entry_t * entry, entries) foreach (entry_t * entry, entries)
if (! entry->has_flags(ENTRY_IN_CACHE)) if (! entry->has_flags(ITEM_IN_CACHE))
checked_delete(entry); checked_delete(entry);
else else
entry->~entry_t(); entry->~entry_t();
foreach (auto_entry_t * entry, auto_entries) foreach (auto_entry_t * entry, auto_entries)
if (! entry->has_flags(ENTRY_IN_CACHE)) if (! entry->has_flags(ITEM_IN_CACHE))
checked_delete(entry); checked_delete(entry);
else else
entry->~auto_entry_t(); entry->~auto_entry_t();
foreach (period_entry_t * entry, period_entries) foreach (period_entry_t * entry, period_entries)
if (! entry->has_flags(ENTRY_IN_CACHE)) if (! entry->has_flags(ITEM_IN_CACHE))
checked_delete(entry); checked_delete(entry);
else else
entry->~period_entry_t(); entry->~period_entry_t();
@ -71,22 +70,22 @@ journal_t::~journal_t()
void journal_t::add_account(account_t * acct) void journal_t::add_account(account_t * acct)
{ {
owner->add_account(acct); session_t::current->add_account(acct);
} }
bool journal_t::remove_account(account_t * acct) bool journal_t::remove_account(account_t * acct)
{ {
return owner->remove_account(acct); return session_t::current->remove_account(acct);
} }
account_t * journal_t::find_account(const string& name, bool auto_create) account_t * journal_t::find_account(const string& name, bool auto_create)
{ {
return owner->find_account(name, auto_create); return session_t::current->find_account(name, auto_create);
} }
account_t * journal_t::find_account_re(const string& regexp) account_t * journal_t::find_account_re(const string& regexp)
{ {
return owner->find_account_re(regexp); return session_t::current->find_account_re(regexp);
} }
bool journal_t::add_entry(entry_t * entry) bool journal_t::add_entry(entry_t * entry)
@ -105,7 +104,7 @@ bool journal_t::add_entry(entry_t * entry)
foreach (const xact_t * xact, entry->xacts) foreach (const xact_t * xact, entry->xacts)
if (xact->cost) { if (xact->cost) {
assert(xact->amount); assert(xact->amount);
xact->amount.commodity().add_price(datetime_t(entry->date(), xact->amount.commodity().add_price(datetime_t(*entry->date(),
time_duration_t(0, 0, 0)), time_duration_t(0, 0, 0)),
*xact->cost / xact->amount.number()); *xact->cost / xact->amount.number());
} }

View file

@ -46,7 +46,6 @@ class account_t;
class journal_t : public noncopyable class journal_t : public noncopyable
{ {
public: public:
session_t * owner;
account_t * master; account_t * master;
account_t * basket; account_t * basket;
entries_list entries; entries_list entries;
@ -58,11 +57,11 @@ public:
hooks_t<entry_finalizer_t, entry_t> entry_finalize_hooks; hooks_t<entry_finalizer_t, entry_t> entry_finalize_hooks;
journal_t(session_t * _owner); journal_t();
~journal_t(); ~journal_t();
// These four methods are delegated to 'owner', since all accounts processed // These four methods are delegated to the current session, since all
// are gathered together at the session level. // accounts processed are gathered together at the session level.
void add_account(account_t * acct); void add_account(account_t * acct);
bool remove_account(account_t * acct); bool remove_account(account_t * acct);
account_t * find_account(const string& name, bool auto_create = true); account_t * find_account(const string& name, bool auto_create = true);

View file

@ -61,8 +61,7 @@ int ofx_proc_account_cb(struct OfxAccountData data, void *)
return -1; return -1;
DEBUG("ledger.ofx.parse", "account " << data.account_name); DEBUG("ledger.ofx.parse", "account " << data.account_name);
account_t * account = new account_t(master_account->owner, master_account, account_t * account = new account_t(master_account, data.account_name);
data.account_name);
curr_journal->add_account(account); curr_journal->add_account(account);
ofx_accounts.insert(accounts_pair(data.account_id, account)); ofx_accounts.insert(accounts_pair(data.account_id, account));

View file

@ -253,7 +253,7 @@ format_equity::format_equity(report_t& _report, const string& _format)
void format_equity::flush() void format_equity::flush()
{ {
account_t summary(&report.session, NULL, "Equity:Opening Balances"); account_t summary(NULL, "Equity:Opening Balances");
account_t::xdata_t& xdata(summary.xdata()); account_t::xdata_t& xdata(summary.xdata());
std::ostream& out(*report.output_stream); std::ostream& out(*report.output_stream);

View file

@ -166,7 +166,7 @@ unsigned int qif_parser_t::parse(std::istream& in,
c = in.peek(); c = in.peek();
if (c == '*' || c == 'X') { if (c == '*' || c == 'X') {
in.get(c); in.get(c);
xact->state = xact_t::CLEARED; xact->set_state(item_t::CLEARED);
} }
break; break;

View file

@ -72,12 +72,12 @@ void reconcile_xacts::flush()
foreach (xact_t * xact, xacts) { foreach (xact_t * xact, xacts) {
if (! is_valid(cutoff) || xact->date() < cutoff) { if (! is_valid(cutoff) || xact->date() < cutoff) {
switch (xact->state) { switch (xact->state()) {
case xact_t::CLEARED: case item_t::CLEARED:
cleared_balance += xact->amount; cleared_balance += xact->amount;
break; break;
case xact_t::UNCLEARED: case item_t::UNCLEARED:
case xact_t::PENDING: case item_t::PENDING:
pending_balance += xact->amount; pending_balance += xact->amount;
*last_ptr = xact; *last_ptr = xact;
last_ptr = xact_next_ptr(xact); last_ptr = xact_next_ptr(xact);

View file

@ -113,7 +113,7 @@ session_t::session_t()
ansi_codes(false), ansi_codes(false),
ansi_invert(false), ansi_invert(false),
master(new account_t(this, NULL, "")) master(new account_t(NULL, ""))
{ {
TRACE_CTOR(session_t, ""); TRACE_CTOR(session_t, "");
} }
@ -161,7 +161,7 @@ void session_t::read_init()
ifstream init(*init_file); ifstream init(*init_file);
journal_t temp(this); journal_t temp;
if (read_journal(temp, *init_file) > 0 || if (read_journal(temp, *init_file) > 0 ||
temp.auto_entries.size() > 0 || temp.auto_entries.size() > 0 ||
temp.period_entries.size() > 0) temp.period_entries.size() > 0)

View file

@ -96,7 +96,7 @@ public:
virtual ~session_t(); virtual ~session_t();
journal_t * create_journal() { journal_t * create_journal() {
journal_t * journal = new journal_t(this); journal_t * journal = new journal_t;
journals.push_back(journal); journals.push_back(journal);
return journal; return journal;
} }

View file

@ -127,14 +127,14 @@ xact_t * parse_xact(char * line, account_t * account, entry_t * entry = NULL)
char p = peek_next_nonws(in); char p = peek_next_nonws(in);
switch (p) { switch (p) {
case '*': case '*':
xact->state = xact_t::CLEARED; xact->set_state(item_t::CLEARED);
in.get(p); in.get(p);
p = peek_next_nonws(in); p = peek_next_nonws(in);
DEBUG("ledger.textual.parse", "line " << linenum << ": " << DEBUG("ledger.textual.parse", "line " << linenum << ": " <<
"Parsed the CLEARED flag"); "Parsed the CLEARED flag");
break; break;
case '!': case '!':
xact->state = xact_t::PENDING; xact->set_state(item_t::PENDING);
in.get(p); in.get(p);
p = peek_next_nonws(in); p = peek_next_nonws(in);
DEBUG("ledger.textual.parse", "line " << linenum << ": " << DEBUG("ledger.textual.parse", "line " << linenum << ": " <<
@ -160,15 +160,17 @@ xact_t * parse_xact(char * line, account_t * account, entry_t * entry = NULL)
char * b = &line[long(account_beg)]; char * b = &line[long(account_beg)];
char * e = &line[long(account_end)]; char * e = &line[long(account_end)];
if ((*b == '[' && *(e - 1) == ']') || if ((*b == '[' && *(e - 1) == ']') ||
(*b == '(' && *(e - 1) == ')')) { (*b == '(' && *(e - 1) == ')')) {
xact->add_flags(XACT_VIRTUAL); xact->add_flags(XACT_VIRTUAL);
DEBUG("ledger.textual.parse", "line " << linenum << ": " << DEBUG("ledger.textual.parse",
"Parsed a virtual account name"); "line " << linenum << ": " << "Parsed a virtual account name");
if (*b == '[') { if (*b == '[') {
xact->add_flags(XACT_BALANCE); xact->add_flags(XACT_BALANCE);
DEBUG("ledger.textual.parse", "line " << linenum << ": " << DEBUG("ledger.textual.parse",
"Parsed a balanced virtual account name"); "line " << linenum << ": " << "Transaction must balance");
} }
b++; e--; b++; e--;
} }
@ -374,7 +376,7 @@ xact_t * parse_xact(char * line, account_t * account, entry_t * entry = NULL)
diff -= xact->amount; diff -= xact->amount;
if (! diff.is_zero()) { if (! diff.is_zero()) {
xact_t * temp = new xact_t(xact->account, diff, xact_t * temp = new xact_t(xact->account, diff,
XACT_GENERATED | XACT_CALCULATED); ITEM_GENERATED | XACT_CALCULATED);
entry->add_xact(temp); entry->add_xact(temp);
DEBUG("ledger.textual.parse", "line " << linenum << ": " << DEBUG("ledger.textual.parse", "line " << linenum << ": " <<
@ -496,15 +498,15 @@ entry_t * parse_entry(std::istream& in, char * line, account_t * master,
// Parse the optional cleared flag: * // Parse the optional cleared flag: *
xact_t::state_t state = xact_t::UNCLEARED; item_t::state_t state = item_t::UNCLEARED;
if (next) { if (next) {
switch (*next) { switch (*next) {
case '*': case '*':
state = xact_t::CLEARED; state = item_t::CLEARED;
next = skip_ws(++next); next = skip_ws(++next);
break; break;
case '!': case '!':
state = xact_t::PENDING; state = item_t::PENDING;
next = skip_ws(++next); next = skip_ws(++next);
break; break;
} }
@ -556,14 +558,13 @@ entry_t * parse_entry(std::istream& in, char * line, account_t * master,
} }
if (xact_t * xact = parse_xact(line, master, curr.get())) { if (xact_t * xact = parse_xact(line, master, curr.get())) {
if (state != xact_t::UNCLEARED && xact->set_state(state);
xact->state == xact_t::UNCLEARED)
xact->state = state;
xact->beg_pos = beg_pos; xact->beg_pos = beg_pos;
xact->beg_line = beg_line; xact->beg_line = beg_line;
xact->end_pos = end_pos; xact->end_pos = end_pos;
xact->end_line = linenum; xact->end_line = linenum;
pos = end_pos; pos = end_pos;
curr->add_xact(xact); curr->add_xact(xact);
@ -674,9 +675,8 @@ static void clock_out_from_timelog(std::list<time_entry_t>& time_entries,
amt.parse(buf); amt.parse(buf);
assert(amt.valid()); assert(amt.valid());
xact_t * xact xact_t * xact = new xact_t(event.account, amt, XACT_VIRTUAL);
= new xact_t(event.account, amt, XACT_VIRTUAL); xact->set_state(item_t::CLEARED);
xact->state = xact_t::CLEARED;
curr->add_xact(xact); curr->add_xact(xact);
if (! journal.add_entry(curr.get())) if (! journal.add_entry(curr.get()))

View file

@ -36,48 +36,32 @@
namespace ledger { namespace ledger {
bool xact_t::use_effective_date = false; optional<date_t> xact_t::actual_date() const
xact_t::~xact_t()
{ {
TRACE_DTOR(xact_t); optional<date_t> date = item_t::actual_date();
} if (! date && entry)
date_t xact_t::actual_date() const
{
if (! _date && entry)
return entry->actual_date(); return entry->actual_date();
return *_date; return date;
} }
date_t xact_t::effective_date() const optional<date_t> xact_t::effective_date() const
{ {
if (! _date_eff && entry) optional<date_t> date = item_t::effective_date();
if (! date && entry)
return entry->effective_date(); return entry->effective_date();
return *_date_eff; return date;
}
item_t::state_t xact_t::state() const
{
state_t entry_state = entry->state();
if ((_state == UNCLEARED && entry_state != UNCLEARED) ||
(_state == PENDING && entry_state == CLEARED))
return entry_state;
return _state;
} }
namespace { namespace {
value_t get_state(xact_t& xact) {
return long(xact.state);
}
value_t state_uncleared(call_scope_t&) {
return 0L;
}
value_t state_cleared(call_scope_t&) {
return 1L;
}
value_t state_pending(call_scope_t&) {
return 2L;
}
value_t get_date(xact_t& xact) {
return xact.date();
}
value_t get_code(xact_t& xact) { value_t get_code(xact_t& xact) {
if (xact.entry->code) if (xact.entry->code)
return string_value(*xact.entry->code); return string_value(*xact.entry->code);
@ -85,22 +69,6 @@ namespace {
return string_value(empty_string); return string_value(empty_string);
} }
value_t get_status(xact_t& xact) {
xact_t::state_t status;
xact.entry->get_state(&status);
return long(status);
}
value_t get_cleared(xact_t& xact) {
xact_t::state_t status;
xact.entry->get_state(&status);
return status == xact_t::CLEARED;
}
value_t get_pending(xact_t& xact) {
xact_t::state_t status;
xact.entry->get_state(&status);
return status == xact_t::PENDING;
}
value_t get_payee(xact_t& xact) { value_t get_payee(xact_t& xact) {
return string_value(xact.entry->payee); return string_value(xact.entry->payee);
} }
@ -125,10 +93,6 @@ namespace {
return xact.cost ? *xact.cost : xact.amount; return xact.cost ? *xact.cost : xact.amount;
} }
value_t get_note(xact_t& xact) {
return string_value(xact.note ? *xact.note : empty_string);
}
value_t get_account(call_scope_t& scope) value_t get_account(call_scope_t& scope)
{ {
xact_t& xact(downcast<xact_t>(*scope.parent)); xact_t& xact(downcast<xact_t>(*scope.parent));
@ -153,22 +117,6 @@ namespace {
return string_value(xact.reported_account()->name); return string_value(xact.reported_account()->name);
} }
value_t get_beg_pos(xact_t& xact) {
return long(xact.beg_pos);
}
value_t get_beg_line(xact_t& xact) {
return long(xact.beg_line);
}
value_t get_end_pos(xact_t& xact) {
return long(xact.end_pos);
}
value_t get_end_line(xact_t& xact) {
return long(xact.end_line);
}
template <value_t (*Func)(xact_t&)> template <value_t (*Func)(xact_t&)>
value_t get_wrapper(call_scope_t& scope) { value_t get_wrapper(call_scope_t& scope) {
return (*Func)(find_scope<xact_t>(scope)); return (*Func)(find_scope<xact_t>(scope));
@ -188,68 +136,29 @@ expr_t::ptr_op_t xact_t::lookup(const string& name)
break; break;
case 'c': case 'c':
if (name == "cleared") if (name == "code")
return WRAP_FUNCTOR(get_wrapper<&get_cleared>);
else if (name == "code")
return WRAP_FUNCTOR(get_wrapper<&get_code>); return WRAP_FUNCTOR(get_wrapper<&get_code>);
break; break;
case 'd':
if (name[1] == '\0' || name == "date")
return WRAP_FUNCTOR(get_wrapper<&get_date>);
break;
case 'f':
if (name.find("fmt_") == 0) {
switch (name[4]) {
case 'A':
return WRAP_FUNCTOR(get_account);
case 'D':
return WRAP_FUNCTOR(get_wrapper<&get_date>);
case 'P':
return WRAP_FUNCTOR(get_wrapper<&get_payee>);
}
}
break;
case 'n':
if (name == "note")
return WRAP_FUNCTOR(get_wrapper<&get_note>);
break;
case 'p': case 'p':
if (name == "pending") if (name == "payee")
return WRAP_FUNCTOR(get_wrapper<&get_pending>);
else if (name == "payee")
return WRAP_FUNCTOR(get_wrapper<&get_payee>); return WRAP_FUNCTOR(get_wrapper<&get_payee>);
break; break;
case 's':
if (name == "status")
return WRAP_FUNCTOR(get_wrapper<&get_status>);
break;
case 't': case 't':
if (name[1] == '\0' || name == "total") if (name[1] == '\0' || name == "total")
return WRAP_FUNCTOR(get_wrapper<&get_total>); return WRAP_FUNCTOR(get_wrapper<&get_total>);
break; break;
case 'u':
if (name == "uncleared")
return expr_t::op_t::wrap_value(1L);
break;
case 'X':
if (name[1] == '\0')
return WRAP_FUNCTOR(get_wrapper<&get_cleared>);
break;
case 'Y':
if (name[1] == '\0')
return WRAP_FUNCTOR(get_wrapper<&get_pending>);
break;
} }
#if 0
// jww (2008-09-19): I don't think we can lookup in entry, because
// that means the functor returned would be expecting an entry to be
// passed to it, rather than a transaction.
return entry->lookup(name); return entry->lookup(name);
#else
return item_t::lookup(name);
#endif
} }
bool xact_t::valid() const bool xact_t::valid() const
@ -259,11 +168,6 @@ bool xact_t::valid() const
return false; return false;
} }
if (state != UNCLEARED && state != CLEARED && state != PENDING) {
DEBUG("ledger.validate", "xact_t: state is bad");
return false;
}
xacts_list::const_iterator i = xacts_list::const_iterator i =
std::find(entry->xacts.begin(), std::find(entry->xacts.begin(),
entry->xacts.end(), this); entry->xacts.end(), this);
@ -287,11 +191,6 @@ bool xact_t::valid() const
return false; return false;
} }
if (flags() & ~0x003f) {
DEBUG("ledger.validate", "xact_t: flags are bad");
return false;
}
return true; return true;
} }

View file

@ -32,8 +32,7 @@
#ifndef _XACT_H #ifndef _XACT_H
#define _XACT_H #define _XACT_H
#include "utils.h" #include "item.h"
#include "scope.h"
namespace ledger { namespace ledger {
@ -43,90 +42,59 @@ class account_t;
class xact_t; class xact_t;
typedef std::list<xact_t *> xacts_list; typedef std::list<xact_t *> xacts_list;
class xact_t : public supports_flags<>, public scope_t class xact_t : public item_t
{ {
public: public:
#define XACT_NORMAL 0x0000 // no flags at all, a basic transaction #define XACT_VIRTUAL 0x0100 // the account was specified with (parens)
#define XACT_VIRTUAL 0x0001 // the account was specified with (parens) #define XACT_BALANCE 0x0200 // the account was specified with [brackets]
#define XACT_BALANCE 0x0002 // the account was specified with [brackets] #define XACT_AUTO 0x0400 // transaction created by automated entry
#define XACT_AUTO 0x0004 // transaction created by automated entry #define XACT_CALCULATED 0x0800 // transaction's amount was auto-calculated
#define XACT_IN_CACHE 0x0008 // transaction allocated by the binary cache
#define XACT_CALCULATED 0x0010 // transaction's amount was auto-calculated
#define XACT_GENERATED 0x0020 // transaction was not found in a journal
#define XACT_TEMP 0x0040 // transaction is a temporary object
enum state_t { UNCLEARED = 0, CLEARED, PENDING }; entry_t * entry; // only set for xacts of regular entries
entry_t * entry;
account_t * account; account_t * account;
state_t state;
optional<date_t> _date; amount_t amount; // can be null until finalization
optional<date_t> _date_eff;
optional<string> note;
amount_t amount;
optional<expr_t> amount_expr; optional<expr_t> amount_expr;
optional<amount_t> cost; optional<amount_t> cost;
optional<expr_t> cost_expr; optional<expr_t> cost_expr;
optional<amount_t> assigned_amount; optional<amount_t> assigned_amount;
optional<expr_t> assigned_amount_expr; optional<expr_t> assigned_amount_expr;
istream_pos_type beg_pos;
unsigned long beg_line;
istream_pos_type end_pos;
unsigned long end_line;
static bool use_effective_date;
xact_t(account_t * _account = NULL, xact_t(account_t * _account = NULL,
flags_t _flags = XACT_NORMAL) flags_t _flags = ITEM_NORMAL)
: supports_flags<>(_flags), entry(NULL), account(_account), : item_t(_flags),
state(UNCLEARED), beg_pos(0), beg_line(0), end_pos(0), end_line(0) entry(NULL), account(_account)
{ {
TRACE_CTOR(xact_t, "account_t *, flags_t"); TRACE_CTOR(xact_t, "account_t *, flags_t");
} }
xact_t(account_t * _account, xact_t(account_t * _account,
const amount_t& _amount, const amount_t& _amount,
flags_t _flags = XACT_NORMAL, flags_t _flags = ITEM_NORMAL,
const optional<string>& _note = none) const optional<string>& _note = none)
: supports_flags<>(_flags), entry(NULL), account(_account), : item_t(_flags, _note),
state(UNCLEARED), note(_note), amount(_amount), entry(NULL), account(_account), amount(_amount)
beg_pos(0), beg_line(0), end_pos(0), end_line(0)
{ {
TRACE_CTOR(xact_t, TRACE_CTOR(xact_t, "account_t *, const amount_t&, flags_t, const optional<string>&");
"account_t *, const amount_t&, flags_t, const string&");
} }
xact_t(const xact_t& xact) xact_t(const xact_t& xact)
: supports_flags<>(xact), : item_t(xact),
scope_t(),
entry(xact.entry), entry(xact.entry),
account(xact.account), account(xact.account),
state(xact.state),
_date(xact._date),
_date_eff(xact._date_eff),
note(xact.note),
amount(xact.amount), amount(xact.amount),
cost(xact.cost), cost(xact.cost),
beg_pos(xact.beg_pos),
beg_line(xact.beg_line),
end_pos(xact.end_pos),
end_line(xact.end_line),
xdata_(xact.xdata_) // jww (2008-07-19): What are the copy semantics? xdata_(xact.xdata_) // jww (2008-07-19): What are the copy semantics?
{ {
TRACE_CTOR(xact_t, "copy"); TRACE_CTOR(xact_t, "copy");
} }
~xact_t(); ~xact_t() {
TRACE_DTOR(xact_t);
date_t actual_date() const;
date_t effective_date() const;
date_t date() const {
if (use_effective_date)
return effective_date();
else
return actual_date();
} }
virtual optional<date_t> actual_date() const;
virtual optional<date_t> effective_date() const;
virtual state_t state() const;
bool must_balance() const { bool must_balance() const {
return ! has_flags(XACT_VIRTUAL) || has_flags(XACT_BALANCE); return ! has_flags(XACT_VIRTUAL) || has_flags(XACT_BALANCE);
} }
@ -221,8 +189,7 @@ public:
date_t reported_date() const { date_t reported_date() const {
if (xdata_ && is_valid(xdata_->date)) if (xdata_ && is_valid(xdata_->date))
return xdata_->date; return xdata_->date;
return return *date();
date();
} }
account_t * reported_account() { account_t * reported_account() {
@ -235,6 +202,8 @@ public:
const account_t * reported_account() const { const account_t * reported_account() const {
return const_cast<xact_t *>(this)->reported_account(); return const_cast<xact_t *>(this)->reported_account();
} }
friend class entry_t;
}; };
} // namespace ledger } // namespace ledger

View file

@ -64,8 +64,8 @@ static void startElement(void *userData, const char *name, const char **attrs)
else if (std::strcmp(name, "xact") == 0) { else if (std::strcmp(name, "xact") == 0) {
assert(curr_entry); assert(curr_entry);
curr_entry->add_xact(new xact_t); curr_entry->add_xact(new xact_t);
if (curr_state != xact_t::UNCLEARED) if (curr_state != item_t::UNCLEARED)
curr_entry->xacts.back()->state = curr_state; curr_entry->xacts.back()->set_state(curr_state);
} }
else if (std::strcmp(name, "commodity") == 0) { else if (std::strcmp(name, "commodity") == 0) {
if (string(attrs[0]) == "flags") if (string(attrs[0]) == "flags")
@ -122,10 +122,10 @@ static void endElement(void *userData, const char *name)
curr_entry->xacts.back()->account = curr_journal->find_account(data); curr_entry->xacts.back()->account = curr_journal->find_account(data);
} }
else if (std::strcmp(name, "tr:cleared") == 0) { else if (std::strcmp(name, "tr:cleared") == 0) {
curr_entry->xacts.back()->state = xact_t::CLEARED; curr_entry->xacts.back()->set_state(item_t::CLEARED);
} }
else if (std::strcmp(name, "tr:pending") == 0) { else if (std::strcmp(name, "tr:pending") == 0) {
curr_entry->xacts.back()->state = xact_t::PENDING; curr_entry->xacts.back()->set_state(item_t::PENDING);
} }
else if (std::strcmp(name, "tr:virtual") == 0) { else if (std::strcmp(name, "tr:virtual") == 0) {
curr_entry->xacts.back()->add_flags(XACT_VIRTUAL); curr_entry->xacts.back()->add_flags(XACT_VIRTUAL);
@ -437,9 +437,9 @@ void format_xml_entries::format_last_entry()
<< "</tr:date_eff>\n"; << "</tr:date_eff>\n";
#endif #endif
if (xact->state == xact_t::CLEARED) if (xact->state() == item_t::CLEARED)
out << " <tr:cleared/>\n"; out << " <tr:cleared/>\n";
else if (xact->state == xact_t::PENDING) else if (xact->state() == xact_t::PENDING)
out << " <tr:pending/>\n"; out << " <tr:pending/>\n";
if (xact->has_flags(XACT_VIRTUAL)) if (xact->has_flags(XACT_VIRTUAL))