Further improvements to lot pricing.

This commit is contained in:
John Wiegley 2006-02-28 00:53:47 +00:00
parent 7901598f1d
commit a597b0fb5e
9 changed files with 214 additions and 142 deletions

View file

@ -73,7 +73,8 @@ class amount_t
void clear_commodity() {
commodity_ = NULL;
}
amount_t base_amount() const;
amount_t base() const;
amount_t price() const;
bool null() const {
return ! quantity && ! commodity_;
@ -274,6 +275,9 @@ inline amount_t abs(const amount_t& amt) {
return amt < 0 ? amt.negated() : amt;
}
#define base_amount(amt) \
((! show_lots && amt.commodity().price) ? amt.base() : amt)
std::ostream& operator<<(std::ostream& out, const amount_t& amt);
inline std::istream& operator>>(std::istream& in, amount_t& amt) {
@ -445,7 +449,7 @@ inline commodity_t& amount_t::commodity() const {
return *commodity_;
}
inline amount_t amount_t::base_amount() const {
inline amount_t amount_t::base() const {
if (commodity_ && commodity_->price) {
amount_t temp(*this);
assert(commodity_->base);
@ -456,6 +460,16 @@ inline amount_t amount_t::base_amount() const {
}
}
inline amount_t amount_t::price() const {
if (commodity_ && commodity_->price) {
amount_t temp(*commodity_->price);
temp *= *this;
return temp;
} else {
return 0L;
}
}
class amount_error : public std::exception {
std::string reason;
public:

View file

@ -34,18 +34,14 @@ balance_t balance_t::value(const std::time_t moment) const
return temp;
}
balance_t balance_t::factor_price() const
balance_t balance_t::price() const
{
balance_t temp;
for (amounts_map::const_iterator i = amounts.begin();
i != amounts.end();
i++) {
if ((*i).second.commodity().price)
temp += *((*i).second.commodity().price) * (*i).second;
else
temp += (*i).second;
}
i++)
temp += (*i).second.price();
return temp;
}

164
balance.h
View file

@ -426,7 +426,7 @@ class balance_t
amount_t amount(const commodity_t& commodity) const;
balance_t value(const std::time_t moment) const;
balance_t factor_price() const;
balance_t price() const;
void write(std::ostream& out,
const int first_width,
@ -463,44 +463,57 @@ inline std::ostream& operator<<(std::ostream& out, const balance_t& bal) {
class balance_pair_t
{
public:
balance_t quantity;
balance_t quantity;
balance_t * price;
balance_t * cost;
// constructors
balance_pair_t() : cost(NULL) {}
balance_pair_t() : price(NULL), cost(NULL) {}
balance_pair_t(const balance_pair_t& bal_pair)
: quantity(bal_pair.quantity), cost(NULL) {
: quantity(bal_pair.quantity), price(NULL), cost(NULL) {
if (bal_pair.price)
price = new balance_t(*bal_pair.price);
if (bal_pair.cost)
cost = new balance_t(*bal_pair.cost);
}
balance_pair_t(const balance_t& _quantity)
: quantity(_quantity), cost(NULL) {}
: quantity(_quantity), price(NULL), cost(NULL) {}
balance_pair_t(const amount_t& _quantity)
: quantity(_quantity), cost(NULL) {}
: quantity(_quantity), price(NULL), cost(NULL) {}
template <typename T>
balance_pair_t(T value) : quantity(value), cost(NULL) {}
balance_pair_t(T value) : quantity(value), price(NULL), cost(NULL) {}
// destructor
~balance_pair_t() {
if (cost)
delete cost;
if (price) delete price;
if (cost) delete cost;
}
// assignment operator
balance_pair_t& operator=(const balance_pair_t& bal_pair) {
if (this != &bal_pair) {
if (price) {
delete price;
price = NULL;
}
if (cost) {
delete cost;
cost = NULL;
}
quantity = bal_pair.quantity;
if (bal_pair.price)
price = new balance_t(*bal_pair.price);
if (bal_pair.cost)
cost = new balance_t(*bal_pair.cost);
}
return *this;
}
balance_pair_t& operator=(const balance_t& bal) {
if (price) {
delete price;
price = NULL;
}
if (cost) {
delete cost;
cost = NULL;
@ -509,6 +522,10 @@ class balance_pair_t
return *this;
}
balance_pair_t& operator=(const amount_t& amt) {
if (price) {
delete price;
price = NULL;
}
if (cost) {
delete cost;
cost = NULL;
@ -518,6 +535,10 @@ class balance_pair_t
}
template <typename T>
balance_pair_t& operator=(T value) {
if (price) {
delete price;
price = NULL;
}
if (cost) {
delete cost;
cost = NULL;
@ -528,26 +549,29 @@ class balance_pair_t
// in-place arithmetic
balance_pair_t& operator+=(const balance_pair_t& bal_pair) {
if (bal_pair.cost && ! cost)
cost = new balance_t(quantity);
quantity += bal_pair.quantity;
if (cost)
*cost += bal_pair.cost ? *bal_pair.cost : bal_pair.quantity;
if (bal_pair.price) {
if (price)
*price += *bal_pair.price;
else
price = new balance_t(*bal_pair.price);
}
if (bal_pair.cost) {
if (cost)
*cost += *bal_pair.cost;
else
cost = new balance_t(*bal_pair.cost);
}
return *this;
}
balance_pair_t& operator+=(const balance_t& bal) {
quantity += bal;
if (cost)
*cost += bal;
return *this;
}
balance_pair_t& operator+=(const amount_t& amt) {
quantity += amt;
if (cost)
*cost += amt;
return *this;
}
template <typename T>
@ -556,26 +580,29 @@ class balance_pair_t
}
balance_pair_t& operator-=(const balance_pair_t& bal_pair) {
if (bal_pair.cost && ! cost)
cost = new balance_t(quantity);
quantity -= bal_pair.quantity;
if (cost)
*cost -= bal_pair.cost ? *bal_pair.cost : bal_pair.quantity;
if (bal_pair.price) {
if (price)
*price -= *bal_pair.price;
else
price = new balance_t(- *bal_pair.price);
}
if (bal_pair.cost) {
if (cost)
*cost -= *bal_pair.cost;
else
cost = new balance_t(- *bal_pair.cost);
}
return *this;
}
balance_pair_t& operator-=(const balance_t& bal) {
quantity -= bal;
if (cost)
*cost -= bal;
return *this;
}
balance_pair_t& operator-=(const amount_t& amt) {
quantity -= amt;
if (cost)
*cost -= amt;
return *this;
}
template <typename T>
@ -630,25 +657,35 @@ class balance_pair_t
// multiplication and division
balance_pair_t& operator*=(const balance_pair_t& bal_pair) {
if (bal_pair.cost && ! cost)
cost = new balance_t(quantity);
quantity *= bal_pair.quantity;
if (cost)
*cost *= bal_pair.cost ? *bal_pair.cost : bal_pair.quantity;
if (bal_pair.price) {
if (price)
*price *= *bal_pair.price;
} else {
if (price) {
delete price;
price = NULL;
}
}
if (bal_pair.cost) {
if (cost)
*cost *= *bal_pair.cost;
} else {
if (cost) {
delete cost;
cost = NULL;
}
}
return *this;
}
balance_pair_t& operator*=(const balance_t& bal) {
quantity *= bal;
if (cost)
*cost *= bal;
return *this;
}
balance_pair_t& operator*=(const amount_t& amt) {
quantity *= amt;
if (cost)
*cost *= amt;
return *this;
}
template <typename T>
@ -657,25 +694,29 @@ class balance_pair_t
}
balance_pair_t& operator/=(const balance_pair_t& bal_pair) {
if (bal_pair.cost && ! cost)
cost = new balance_t(quantity);
quantity /= bal_pair.quantity;
if (cost)
*cost /= bal_pair.cost ? *bal_pair.cost : bal_pair.quantity;
if (bal_pair.price) {
if (price)
*price /= *bal_pair.price;
} else {
throw amount_error("Attempt to divide by zero");
}
if (bal_pair.cost) {
if (cost)
*cost /= *bal_pair.cost;
} else {
throw amount_error("Attempt to divide by zero");
}
return *this;
}
balance_pair_t& operator/=(const balance_t& bal) {
quantity /= bal;
if (cost)
*cost /= bal;
return *this;
}
balance_pair_t& operator/=(const amount_t& amt) {
quantity /= amt;
if (cost)
*cost /= amt;
return *this;
}
template <typename T>
@ -815,8 +856,8 @@ class balance_pair_t
// unary negation
void negate() {
quantity.negate();
if (cost)
cost->negate();
if (price) price->negate();
if (cost) cost->negate();
}
balance_pair_t negated() const {
balance_pair_t temp = *this;
@ -840,8 +881,8 @@ class balance_pair_t
void abs() {
quantity.abs();
if (cost)
cost->abs();
if (price) price->abs();
if (cost) cost->abs();
}
amount_t amount(const commodity_t& commodity) const {
@ -857,19 +898,30 @@ class balance_pair_t
}
balance_pair_t& add(const amount_t& amount,
const amount_t * a_cost = NULL) {
if (a_cost && ! cost)
cost = new balance_t(quantity);
const amount_t * a_price = NULL,
const amount_t * a_cost = NULL)
{
quantity += amount;
if (cost)
*cost += a_cost ? *a_cost : amount;
if (a_price) {
if (price)
*price += *a_price;
else
price = new balance_t(*a_price);
}
if (a_cost) {
if (cost)
*cost += *a_cost;
else
cost = new balance_t(*a_cost);
}
return *this;
}
bool valid() {
return quantity.valid() && (! cost || cost->valid());
return (quantity.valid() &&
(! price || price->valid()) && (! cost || cost->valid()));
}
void round() {

View file

@ -1041,7 +1041,6 @@ OPT_BEGIN(basis, "B") {
} OPT_END(basis);
OPT_BEGIN(price, "I") {
show_lots = true; // don't show them, but use in calculations
config->amount_expr = "i";
config->total_expr = "I";
} OPT_END(price);

View file

@ -158,13 +158,12 @@ void value_expr_t::compute(value_t& result, const details_t& details,
break;
case AMOUNT:
case PRICE:
if (details.xact) {
if (transaction_has_xdata(*details.xact) &&
transaction_xdata_(*details.xact).dflags & TRANSACTION_COMPOSITE)
result = transaction_xdata_(*details.xact).composite_amount;
else
result = translate_amount(details.xact->amount);
result = base_amount(details.xact->amount);
}
else if (details.account && account_has_xdata(*details.account)) {
result = account_xdata(*details.account).value;
@ -172,8 +171,27 @@ void value_expr_t::compute(value_t& result, const details_t& details,
else {
result = 0L;
}
if (kind == PRICE)
result = result.factor_price();
break;
case PRICE:
if (details.xact) {
bool set = false;
if (transaction_has_xdata(*details.xact)) {
transaction_xdata_t& xdata(transaction_xdata_(*details.xact));
if (xdata.dflags & TRANSACTION_COMPOSITE) {
result = xdata.composite_amount.price();
set = true;
}
}
if (! set)
result = details.xact->amount.price();
}
else if (details.account && account_has_xdata(*details.account)) {
result = account_xdata(*details.account).value.price();
}
else {
result = 0L;
}
break;
case COST:
@ -182,11 +200,7 @@ void value_expr_t::compute(value_t& result, const details_t& details,
if (transaction_has_xdata(*details.xact)) {
transaction_xdata_t& xdata(transaction_xdata_(*details.xact));
if (xdata.dflags & TRANSACTION_COMPOSITE) {
if (xdata.composite_amount.type == value_t::BALANCE_PAIR &&
((balance_pair_t *) xdata.composite_amount.data)->cost)
result = *((balance_pair_t *) xdata.composite_amount.data)->cost;
else
result = xdata.composite_amount;
result = xdata.composite_amount.cost();
set = true;
}
}
@ -195,7 +209,7 @@ void value_expr_t::compute(value_t& result, const details_t& details,
if (details.xact->cost)
result = *details.xact->cost;
else
result = translate_amount(details.xact->amount);
result = base_amount(details.xact->amount);
}
}
else if (details.account && account_has_xdata(*details.account)) {
@ -207,15 +221,20 @@ void value_expr_t::compute(value_t& result, const details_t& details,
break;
case TOTAL:
case PRICE_TOTAL:
if (details.xact && transaction_has_xdata(*details.xact))
result = transaction_xdata_(*details.xact).total;
else if (details.account && account_has_xdata(*details.account))
result = account_xdata(*details.account).total;
else
result = 0L;
if (kind == PRICE_TOTAL)
result = result.factor_price();
break;
case PRICE_TOTAL:
if (details.xact && transaction_has_xdata(*details.xact))
result = transaction_xdata_(*details.xact).total.price();
else if (details.account && account_has_xdata(*details.account))
result = account_xdata(*details.account).total.price();
else
result = 0L;
break;
case COST_TOTAL:
if (details.xact && transaction_has_xdata(*details.xact))
@ -1140,14 +1159,14 @@ void init_value_expr()
globals->define("a", node);
globals->define("amount", node);
node = new value_expr_t(value_expr_t::COST);
globals->define("b", node);
globals->define("cost", node);
node = new value_expr_t(value_expr_t::PRICE);
globals->define("i", node);
globals->define("price", node);
node = new value_expr_t(value_expr_t::COST);
globals->define("b", node);
globals->define("cost", node);
node = new value_expr_t(value_expr_t::DATE);
globals->define("d", node);
globals->define("date", node);
@ -1184,14 +1203,14 @@ void init_value_expr()
globals->define("O", node);
globals->define("total", node);
node = new value_expr_t(value_expr_t::COST_TOTAL);
globals->define("B", node);
globals->define("cost_total", node);
node = new value_expr_t(value_expr_t::PRICE_TOTAL);
globals->define("I", node);
globals->define("price_total", node);
node = new value_expr_t(value_expr_t::COST_TOTAL);
globals->define("B", node);
globals->define("cost_total", node);
// Relating to format_t
globals->define("t", new value_expr_t(value_expr_t::VALUE_EXPR));
globals->define("T", new value_expr_t(value_expr_t::TOTAL_EXPR));
@ -1340,8 +1359,8 @@ void dump_value_expr(std::ostream& out, const value_expr_t * node,
break;
case value_expr_t::AMOUNT: out << "AMOUNT"; break;
case value_expr_t::COST: out << "COST"; break;
case value_expr_t::PRICE: out << "PRICE"; break;
case value_expr_t::COST: out << "COST"; break;
case value_expr_t::DATE: out << "DATE"; break;
case value_expr_t::CLEARED: out << "CLEARED"; break;
case value_expr_t::PENDING: out << "PENDING"; break;
@ -1351,8 +1370,8 @@ void dump_value_expr(std::ostream& out, const value_expr_t * node,
case value_expr_t::COUNT: out << "COUNT"; break;
case value_expr_t::DEPTH: out << "DEPTH"; break;
case value_expr_t::TOTAL: out << "TOTAL"; break;
case value_expr_t::COST_TOTAL: out << "COST_TOTAL"; break;
case value_expr_t::PRICE_TOTAL: out << "PRICE_TOTAL"; break;
case value_expr_t::COST_TOTAL: out << "COST_TOTAL"; break;
case value_expr_t::F_NOW: out << "F_NOW"; break;
case value_expr_t::F_ARITH_MEAN: out << "F_ARITH_MEAN"; break;

View file

@ -723,6 +723,30 @@ void value_t::abs()
}
}
value_t value_t::price() const
{
switch (type) {
case BOOLEAN:
case INTEGER:
case AMOUNT:
case BALANCE:
return *this;
case BALANCE_PAIR:
assert(((balance_pair_t *) data)->price);
if (((balance_pair_t *) data)->price)
return *(((balance_pair_t *) data)->price);
else
return ((balance_pair_t *) data)->quantity;
default:
assert(0);
break;
}
assert(0);
return value_t();
}
value_t value_t::cost() const
{
switch (type) {
@ -747,53 +771,22 @@ value_t value_t::cost() const
return value_t();
}
value_t value_t::factor_price() const
{
switch (type) {
case BOOLEAN:
case INTEGER:
return *this;
case AMOUNT: {
commodity_t& comm = ((amount_t *) data)->commodity();
if (comm.price != NULL)
return value_t(*comm.price * *((amount_t *) data));
return *this;
}
case BALANCE:
return ((balance_t *) data)->factor_price();
case BALANCE_PAIR: {
balance_pair_t temp(((balance_pair_t *) data)->quantity.factor_price());
if (((balance_pair_t *) data)->cost)
temp.cost = new balance_t(((balance_pair_t *) data)->cost);
return temp;
}
default:
assert(0);
break;
}
assert(0);
return value_t();
}
value_t& value_t::add(const amount_t& amount, const amount_t * cost)
value_t& value_t::add(const amount_t& amount,
const amount_t * price, const amount_t * cost)
{
switch (type) {
case BOOLEAN:
case INTEGER:
case AMOUNT:
if (cost) {
if (price || cost) {
cast(BALANCE_PAIR);
return add(amount, cost);
return add(amount, price, cost);
}
else if ((type == AMOUNT &&
((amount_t *) data)->commodity() != amount.commodity()) ||
(type != AMOUNT && amount.commodity())) {
cast(BALANCE);
return add(amount, cost);
return add(amount, price, cost);
}
else if (type != AMOUNT) {
cast(AMOUNT);
@ -802,15 +795,15 @@ value_t& value_t::add(const amount_t& amount, const amount_t * cost)
break;
case BALANCE:
if (cost) {
if (price || cost) {
cast(BALANCE_PAIR);
return add(amount, cost);
return add(amount, price, cost);
}
*((balance_t *) data) += amount;
break;
case BALANCE_PAIR:
((balance_pair_t *) data)->add(amount, cost);
((balance_pair_t *) data)->add(amount, price, cost);
break;
default:

View file

@ -145,7 +145,7 @@ class value_t
}
value_t& operator=(const balance_pair_t& value) {
if ((balance_pair_t *) data != &value) {
if (! value.cost) {
if (! value.price && ! value.cost) {
return *this = value.quantity;
} else {
destroy();
@ -266,8 +266,10 @@ class value_t
void abs();
void cast(type_t cast_type);
value_t cost() const;
value_t factor_price() const;
value_t& add(const amount_t& amount, const amount_t * cost = NULL);
value_t price() const;
value_t& add(const amount_t& amount,
const amount_t * price = NULL,
const amount_t * cost = NULL);
value_t value(const std::time_t moment) const {
switch (type) {

16
walk.cc
View file

@ -44,16 +44,16 @@ void add_transaction_to(const transaction_t& xact, value_t& value)
transaction_xdata_(xact).dflags & TRANSACTION_COMPOSITE) {
value += transaction_xdata_(xact).composite_amount;
}
else if (xact.cost || value) {
amount_t * cost = xact.cost;
if (cost && cost->commodity().price)
cost = new amount_t(cost->base_amount());
value.add(translate_amount(xact.amount), cost);
if (cost != xact.cost)
delete cost;
else if (xact.cost || xact.amount.commodity().price || value) {
std::auto_ptr<amount_t> price;
amount_t * cost = xact.cost;
if (xact.amount.commodity().price)
price.reset(new amount_t(*xact.amount.commodity().price *
xact.amount));
value.add(base_amount(xact.amount), price.get(), cost);
}
else {
value = translate_amount(xact.amount);
value = xact.amount;
}
}

3
walk.h
View file

@ -122,9 +122,6 @@ inline const account_t * xact_account(const transaction_t& xact) {
extern bool show_lots;
#define translate_amount(amt) \
((! show_lots && amt.commodity().price) ? amt.base_amount() : amt)
//////////////////////////////////////////////////////////////////////
inline void walk_transactions(transactions_list::iterator begin,