ledger/src/xact.cc

331 lines
8.2 KiB
C++

/*
* Copyright (c) 2003-2009, John Wiegley. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of New Artisans LLC nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "xact.h"
#include "journal.h"
#include "account.h"
#include "format.h"
namespace ledger {
bool xact_t::has_tag(const string& tag) const
{
if (item_t::has_tag(tag))
return true;
if (entry)
return entry->has_tag(tag);
return false;
}
bool xact_t::has_tag(const mask_t& tag_mask,
const optional<mask_t>& value_mask) const
{
if (item_t::has_tag(tag_mask, value_mask))
return true;
if (entry)
return entry->has_tag(tag_mask, value_mask);
return false;
}
optional<string> xact_t::get_tag(const string& tag) const
{
if (optional<string> value = item_t::get_tag(tag))
return value;
if (entry)
return entry->get_tag(tag);
return none;
}
optional<string> xact_t::get_tag(const mask_t& tag_mask,
const optional<mask_t>& value_mask) const
{
if (optional<string> value = item_t::get_tag(tag_mask, value_mask))
return value;
if (entry)
return entry->get_tag(tag_mask, value_mask);
return none;
}
date_t xact_t::date() const
{
if (item_t::use_effective_date) {
if (_date_eff)
return *_date_eff;
else if (entry && entry->_date_eff)
return *entry->_date_eff;
}
if (! _date) {
assert(entry);
return entry->date();
}
return *_date;
}
optional<date_t> xact_t::effective_date() const
{
optional<date_t> date = item_t::effective_date();
if (! date && entry)
return entry->effective_date();
return date;
}
item_t::state_t xact_t::state() const
{
if (entry) {
state_t entry_state = entry->state();
if ((_state == UNCLEARED && entry_state != UNCLEARED) ||
(_state == PENDING && entry_state == CLEARED))
return entry_state;
}
return _state;
}
namespace {
value_t get_this(xact_t& xact) {
return value_t(static_cast<scope_t *>(&xact));
}
value_t get_is_calculated(xact_t& xact) {
return xact.has_flags(XACT_CALCULATED);
}
value_t get_virtual(xact_t& xact) {
return xact.has_flags(XACT_VIRTUAL);
}
value_t get_real(xact_t& xact) {
return ! xact.has_flags(XACT_VIRTUAL);
}
value_t get_actual(xact_t& xact) {
return ! xact.has_flags(XACT_AUTO);
}
value_t get_entry(xact_t& xact) {
return value_t(static_cast<scope_t *>(xact.entry));
}
value_t get_code(xact_t& xact) {
if (xact.entry->code)
return string_value(*xact.entry->code);
else
return string_value(empty_string);
}
value_t get_payee(xact_t& xact) {
return string_value(xact.entry->payee);
}
value_t get_amount(xact_t& xact) {
if (xact.has_xdata() &&
xact.xdata().has_flags(XACT_EXT_COMPOUND)) {
return xact.xdata().value;
} else {
return xact.amount;
}
}
value_t get_commodity(xact_t& xact) {
return string_value(xact.amount.commodity().symbol());
}
value_t get_cost(xact_t& xact) {
if (xact.has_xdata() &&
xact.xdata().has_flags(XACT_EXT_COMPOUND)) {
return xact.xdata().value;
} else {
if (xact.cost)
return *xact.cost;
else
return xact.amount;
}
}
value_t get_total(xact_t& xact) {
if (xact.xdata_ && ! xact.xdata_->total.is_null())
return xact.xdata_->total;
else
return xact.amount;
}
value_t get_count(xact_t& xact) {
if (xact.xdata_)
return xact.xdata_->count;
else
return 1L;
}
value_t get_account(call_scope_t& scope)
{
xact_t& xact(find_scope<xact_t>(scope));
var_t<long> max_width(scope, 0);
string name = xact.reported_account()->fullname();
if (max_width && *max_width > 2)
name = format_t::truncate(name, *max_width - 2, true);
if (xact.has_flags(XACT_VIRTUAL)) {
if (xact.must_balance())
name = string("[") + name + "]";
else
name = string("(") + name + ")";
}
return string_value(name);
}
value_t get_account_base(xact_t& xact) {
return string_value(xact.reported_account()->name);
}
value_t get_account_depth(xact_t& xact) {
return long(xact.reported_account()->depth);
}
template <value_t (*Func)(xact_t&)>
value_t get_wrapper(call_scope_t& scope) {
return (*Func)(find_scope<xact_t>(scope));
}
}
expr_t::ptr_op_t xact_t::lookup(const string& name)
{
switch (name[0]) {
case 'a':
if (name[1] == '\0' || name == "amount")
return WRAP_FUNCTOR(get_wrapper<&get_amount>);
else if (name == "account")
return WRAP_FUNCTOR(get_account);
else if (name == "account_base")
return WRAP_FUNCTOR(get_wrapper<&get_account_base>);
else if (name == "actual")
return WRAP_FUNCTOR(get_wrapper<&get_actual>);
break;
case 'c':
if (name == "code")
return WRAP_FUNCTOR(get_wrapper<&get_code>);
else if (name == "cost")
return WRAP_FUNCTOR(get_wrapper<&get_cost>);
else if (name == "count")
return WRAP_FUNCTOR(get_wrapper<&get_count>);
else if (name == "calculated")
return WRAP_FUNCTOR(get_wrapper<&get_is_calculated>);
else if (name == "commodity")
return WRAP_FUNCTOR(get_wrapper<&get_commodity>);
break;
case 'd':
if (name == "depth")
return WRAP_FUNCTOR(get_wrapper<&get_account_depth>);
break;
case 'e':
if (name == "entry")
return WRAP_FUNCTOR(get_wrapper<&get_entry>);
break;
case 'r':
if (name == "real")
return WRAP_FUNCTOR(get_wrapper<&get_real>);
break;
case 'p':
if (name == "payee")
return WRAP_FUNCTOR(get_wrapper<&get_payee>);
break;
case 't':
if (name[1] == '\0' || name == "total")
return WRAP_FUNCTOR(get_wrapper<&get_total>);
break;
case 'v':
if (name == "virtual")
return WRAP_FUNCTOR(get_wrapper<&get_virtual>);
break;
case 'x':
if (name == "xact")
return WRAP_FUNCTOR(get_wrapper<&get_this>);
break;
}
return item_t::lookup(name);
}
bool xact_t::valid() const
{
if (! entry) {
DEBUG("ledger.validate", "xact_t: ! entry");
return false;
}
xacts_list::const_iterator i =
std::find(entry->xacts.begin(),
entry->xacts.end(), this);
if (i == entry->xacts.end()) {
DEBUG("ledger.validate", "xact_t: ! found");
return false;
}
if (! account) {
DEBUG("ledger.validate", "xact_t: ! account");
return false;
}
if (! amount.valid()) {
DEBUG("ledger.validate", "xact_t: ! amount.valid()");
return false;
}
if (cost && ! cost->valid()) {
DEBUG("ledger.validate", "xact_t: cost && ! cost->valid()");
return false;
}
return true;
}
void xact_t::add_to_value(value_t& value, expr_t& expr)
{
if (xdata_ && xdata_->has_flags(XACT_EXT_COMPOUND)) {
add_or_set_value(value, xdata_->value);
}
else if (! xdata_ || ! xdata_->has_flags(XACT_EXT_NO_TOTAL)) {
bind_scope_t bound_scope(*expr.get_context(), *this);
add_or_set_value(value, expr.calc(bound_scope));
}
}
} // namespace ledger