See ChangeLog

This commit is contained in:
John Wiegley 2005-10-19 22:42:24 +00:00
parent a53f44ecda
commit eb0525e315
18 changed files with 331 additions and 70 deletions

81
NEWS
View file

@ -1,5 +1,86 @@
Ledger NEWS
* 2.5
- Effective dates may now be specified for entries:
2004/10/03=2004/09/30 Credit card company
Liabilities:MasterCard $100.00
Assets:Checking
This entry says that although the actual transactions occurred on
October 3rd, their effective date was September 30th. This is
especially useful for budgeting, in case you want the transactions
to show up in September instead of October.
To report using effective dates, use the --effective option.
- Actual and effective dates may now be specified for individual
transactions:
2004/10/03=2004/09/30 Credit card company
Liabilities:MasterCard $100.00
Assets:Checking ; [2004/10/10=2004/09/15]
This states that although the actual date of the entry is
2004/10/03, and the effective date of the entry is 2004/09/30, the
actual date of the Checking transaction itself is 2004/10/10, and
its effective date is 2004/09/15. The effective date is optional
(just specifying the actual date would have read "[2004/10/10]").
If no effective date is given for a transaction, the effective date
of the entry is assumed. If no actual date is given, the actual
date of the entry is assumed. The syntax of the latter is simply
[=2004/09/15].
- To support the above, there is a new formatting option: "%d". This
outputs only the date (like "%D") if there is no effective date, but
outputs "ADATE=EDATE" if there is one. The "print" report now uses
this.
- To support the above, the register report may now split up entries
whose component transactions have different dates. For example,
given the following entry:
2005/10/15=2005/09/01 iTunes
Expenses:Music $1.08 ; [2005/10/20=2005/08/01]
Liabilities:MasterCard
The command "ledger register" on this data file reports:
2005/10/20 iTunes Expenses:Music $1.08 $1.08
2005/10/15 iTunes Liabilities:MasterCard $-1.08 0
The command "ledger --effective register" reports:
2005/08/01 iTunes Expenses:Music $1.08 $1.08
2005/09/01 iTunes Liabilities:MasterCard $-1.08 0
Although it appears as though two entries are being reported, both
transactions belong to the same entry.
- Individual transactions may now be cleared separately. The old
syntax, which is still supported, clears all transactions in an
entry:
2004/05/27 * Book Store
Expenses:Dining $20.00
Liabilities:MasterCard
The new (and optional) syntax allows clearing just the MasterCard
transaction:
2004/05/27 Book Store
Expenses:Dining $20.00
* Liabilities:MasterCard
NOTE: This changes the output format of the "emacs" and "xml"
reports. ledger.el will use the new syntax unless the Lisp variable
`ledger-clear-whole-entries' is set to t.
- Added a new value expression regexp command:
C// compare against transaction amount's commodity symbol
* 2.4
- Both "-$100.00" and "$-100.00" are now equivalent amounts.

View file

@ -11,7 +11,7 @@
namespace ledger {
static unsigned long binary_magic_number = 0xFFEED765;
static unsigned long format_version = 0x00020042;
static unsigned long format_version = 0x00020044;
static account_t ** accounts;
static account_t ** accounts_next;
@ -178,8 +178,9 @@ inline void read_binary_amount(char *& data, amount_t& amt)
inline void read_binary_transaction(char *& data, transaction_t * xact)
{
read_binary_number(data, xact->_date);
read_binary_number(data, xact->_date_eff);
xact->account = accounts[read_binary_number<account_t::ident_t>(data) - 1];
read_binary_amount(data, xact->amount);
if (*data++ == 1) {
@ -188,6 +189,7 @@ inline void read_binary_transaction(char *& data, transaction_t * xact)
} else {
xact->cost = NULL;
}
read_binary_number(data, xact->state);
read_binary_number(data, xact->flags);
xact->flags |= TRANSACTION_BULK_ALLOC;
@ -218,7 +220,8 @@ inline void read_binary_entry(char *& data, entry_t * entry,
transaction_t *& xact_pool)
{
read_binary_entry_base(data, entry, xact_pool);
read_binary_number(data, entry->date);
read_binary_number(data, entry->_date);
read_binary_number(data, entry->_date_eff);
read_binary_string(data, &entry->code);
read_binary_string(data, &entry->payee);
}
@ -540,14 +543,18 @@ void write_binary_amount(std::ostream& out, const amount_t& amt)
void write_binary_transaction(std::ostream& out, transaction_t * xact)
{
write_binary_number(out, xact->_date);
write_binary_number(out, xact->_date_eff);
write_binary_number(out, xact->account->ident);
write_binary_amount(out, xact->amount);
if (xact->cost) {
write_binary_number<char>(out, 1);
write_binary_amount(out, *xact->cost);
} else {
write_binary_number<char>(out, 0);
}
write_binary_number(out, xact->state);
write_binary_number(out, xact->flags);
write_binary_string(out, xact->note);
@ -571,7 +578,8 @@ void write_binary_entry_base(std::ostream& out, entry_base_t * entry)
void write_binary_entry(std::ostream& out, entry_t * entry)
{
write_binary_entry_base(out, entry);
write_binary_number(out, entry->date);
write_binary_number(out, entry->_date);
write_binary_number(out, entry->_date_eff);
write_binary_string(out, entry->code);
write_binary_string(out, entry->payee);
}

View file

@ -36,8 +36,8 @@ config_t::config_t()
"%48|%-.38A %22.108t %22.132T\n");
plot_amount_format = "%D %(St)\n";
plot_total_format = "%D %(ST)\n";
print_format = "\n%D %Y%C%P\n %-34W %12o%n\n%/ %-34W %12o%n\n";
write_hdr_format = "%D %Y%C%P\n";
print_format = "\n%d %Y%C%P\n %-34W %12o%n\n%/ %-34W %12o%n\n";
write_hdr_format = "%d %Y%C%P\n";
write_xact_format = " %-34W %12o%n\n";
equity_format = "\n%D %Y%C%P\n%/ %-34W %12t\n";
#ifndef USE_BOOST_PYTHON
@ -714,6 +714,10 @@ OPT_BEGIN(plot_amount_format, ":") {
OPT_BEGIN(plot_total_format, ":") {
config.plot_total_format = optarg;
OPT_BEGIN(effective, "") {
transaction_t::use_effective_date = true;
} OPT_END(effective);
} OPT_END(plot_total_format);
OPT_BEGIN(print_format, ":") {

View file

@ -15,7 +15,7 @@ entry_t * derive_new_entry(journal_t& journal,
entry_t * matching = NULL;
if (! parse_date((*i).c_str(), &added->date))
if (! parse_date((*i).c_str(), &added->_date))
throw error("Bad date passed to 'entry'");
if (++i == end)

View file

@ -15,8 +15,8 @@ void format_emacs_transactions::write_entry(entry_t& entry)
out << (((unsigned long)entry.beg_pos) + 1) << " ";
out << "(" << (entry.date / 65536) << " "
<< (entry.date % 65536) << " 0) ";
std::time_t date = entry.date();
out << "(" << (date / 65536) << " " << (date % 65536) << " 0) ";
if (entry.code.empty())
out << "nil ";

View file

@ -206,6 +206,10 @@ element_t * format_t::parse_elements(const std::string& fmt)
break;
}
case 'd':
current->type = element_t::COMPLETE_DATE_STRING;
current->chars = format_t::date_format;
break;
case 'D':
current->type = element_t::DATE_STRING;
current->chars = format_t::date_format;
@ -420,16 +424,51 @@ void format_t::format(std::ostream& out_str, const details_t& details) const
out << details.entry->end_line;
break;
case element_t::DATE_STRING:
if (details.entry && details.entry->date) {
char buf[256];
std::strftime(buf, 255, elem->chars.c_str(),
std::localtime(&details.entry->date));
case element_t::DATE_STRING: {
std::time_t date = 0;
if (details.xact)
date = details.xact->date();
else if (details.entry)
date = details.entry->date();
char buf[256];
std::strftime(buf, 255, elem->chars.c_str(), std::localtime(&date));
out << (elem->max_width == 0 ? buf : truncated(buf, elem->max_width));
break;
}
case element_t::COMPLETE_DATE_STRING: {
std::time_t actual_date = 0;
std::time_t effective_date = 0;
if (details.xact) {
actual_date = details.xact->actual_date();
effective_date = details.xact->effective_date();
}
else if (details.entry) {
actual_date = details.entry->actual_date();
effective_date = details.entry->effective_date();
}
char abuf[256];
std::strftime(abuf, 255, elem->chars.c_str(),
std::localtime(&actual_date));
if (effective_date) {
char buf[512];
char ebuf[256];
std::strftime(ebuf, 255, elem->chars.c_str(),
std::localtime(&effective_date));
std::strcpy(buf, abuf);
std::strcat(buf, "=");
std::strcat(buf, ebuf);
out << (elem->max_width == 0 ? buf : truncated(buf, elem->max_width));
} else {
out << " ";
out << (elem->max_width == 0 ? abuf : truncated(abuf, elem->max_width));
}
break;
}
case element_t::CLEARED:
if (details.xact) {
@ -575,7 +614,7 @@ void format_t::format(std::ostream& out_str, const details_t& details) const
format_transactions::format_transactions(std::ostream& _output_stream,
const std::string& format)
: output_stream(_output_stream), last_entry(NULL)
: output_stream(_output_stream), last_entry(NULL), last_xact(NULL)
{
const char * f = format.c_str();
if (const char * p = std::strstr(f, "%/")) {
@ -594,10 +633,16 @@ void format_transactions::operator()(transaction_t& xact)
if (last_entry != xact.entry) {
first_line_format.format(output_stream, details_t(xact));
last_entry = xact.entry;
} else {
}
else if (last_xact->date() != xact.date()) {
first_line_format.format(output_stream, details_t(xact));
}
else {
next_lines_format.format(output_stream, details_t(xact));
}
transaction_xdata(xact).dflags |= TRANSACTION_DISPLAYED;
last_xact = &xact;
}
}
@ -729,7 +774,7 @@ format_equity::format_equity(std::ostream& _output_stream,
entry_t header_entry;
header_entry.payee = "Opening Balances";
header_entry.date = now;
header_entry._date = now;
first_line_format.format(output_stream, details_t(header_entry));
}

View file

@ -24,6 +24,7 @@ struct element_t
END_POS,
END_LINE,
DATE_STRING,
COMPLETE_DATE_STRING,
CLEARED,
ENTRY_CLEARED,
CODE,
@ -97,10 +98,11 @@ struct format_t
class format_transactions : public item_handler<transaction_t>
{
protected:
std::ostream& output_stream;
format_t first_line_format;
format_t next_lines_format;
entry_t * last_entry;
std::ostream& output_stream;
format_t first_line_format;
format_t next_lines_format;
entry_t * last_entry;
transaction_t * last_xact;
public:
format_transactions(std::ostream& _output_stream,

View file

@ -236,7 +236,7 @@ static void dataHandler(void *userData, const char *s, int len)
case ENTRY_DATE: {
struct tm when;
strptime(std::string(s, len).c_str(), "%Y-%m-%d %H:%M:%S %z", &when);
curr_entry->date = std::mktime(&when);
curr_entry->_date = std::mktime(&when);
break;
}

View file

@ -14,6 +14,26 @@ namespace ledger {
const std::string version = PACKAGE_VERSION;
bool transaction_t::use_effective_date = false;
std::time_t transaction_t::actual_date() const
{
if (_date == 0) {
assert(entry);
return entry->actual_date();
}
return _date;
}
std::time_t transaction_t::effective_date() const
{
if (_date_eff == 0) {
assert(entry);
return entry->effective_date();
}
return _date_eff;
}
bool transaction_t::valid() const
{
if (! entry)
@ -201,7 +221,8 @@ bool entry_base_t::finalize()
}
entry_t::entry_t(const entry_t& e)
: entry_base_t(e), date(e.date), code(e.code), payee(e.payee)
: entry_base_t(e), _date(e._date), _date_eff(e._date_eff),
code(e.code), payee(e.payee)
{
DEBUG_PRINT("ledger.memory.ctors", "ctor entry_t");
@ -219,7 +240,7 @@ void entry_t::add_transaction(transaction_t * xact)
bool entry_t::valid() const
{
if (! date || ! journal)
if (! _date || ! journal)
return false;
for (transactions_list::const_iterator i = transactions.begin();
@ -459,7 +480,7 @@ bool journal_t::add_entry(entry_t * entry)
i != entry->transactions.end();
i++)
if ((*i)->cost && (*i)->amount)
(*i)->amount.commodity().add_price(entry->date,
(*i)->amount.commodity().add_price(entry->date(),
*(*i)->cost / (*i)->amount);
return true;

View file

@ -32,6 +32,8 @@ class transaction_t
enum state_t { UNCLEARED, CLEARED, PENDING };
entry_t * entry;
std::time_t _date;
std::time_t _date_eff;
account_t * account;
amount_t amount;
amount_t * cost;
@ -40,8 +42,10 @@ class transaction_t
std::string note;
mutable void * data;
static bool use_effective_date;
transaction_t(account_t * _account = NULL)
: entry(NULL), account(_account), cost(NULL),
: entry(NULL), _date(0), account(_account), cost(NULL),
state(UNCLEARED), flags(TRANSACTION_NORMAL), data(NULL) {
DEBUG_PRINT("ledger.memory.ctors", "ctor transaction_t");
}
@ -50,14 +54,15 @@ class transaction_t
const amount_t& _amount,
unsigned int _flags = TRANSACTION_NORMAL,
const std::string& _note = "")
: entry(NULL), account(_account), amount(_amount),
: entry(NULL), _date(0), account(_account), amount(_amount),
cost(NULL), state(UNCLEARED), flags(_flags),
note(_note), data(NULL) {
DEBUG_PRINT("ledger.memory.ctors", "ctor transaction_t");
}
transaction_t(const transaction_t& xact)
: entry(xact.entry), account(xact.account), amount(xact.amount),
: entry(xact.entry), _date(0), account(xact.account),
amount(xact.amount),
cost(xact.cost ? new amount_t(*xact.cost) : NULL),
state(xact.state), flags(xact.flags), note(xact.note),
data(NULL) {
@ -70,6 +75,15 @@ class transaction_t
delete cost;
}
std::time_t actual_date() const;
std::time_t effective_date() const;
std::time_t date() const {
if (use_effective_date)
return effective_date();
else
return actual_date();
}
bool operator==(const transaction_t& xact) {
return this == &xact;
}
@ -133,11 +147,12 @@ class entry_base_t
class entry_t : public entry_base_t
{
public:
std::time_t date;
std::time_t _date;
std::time_t _date_eff;
std::string code;
std::string payee;
entry_t() : date(0) {
entry_t() : _date(0), _date_eff(0) {
DEBUG_PRINT("ledger.memory.ctors", "ctor entry_t");
}
entry_t(const entry_t& e);
@ -148,6 +163,21 @@ class entry_t : public entry_base_t
}
#endif
std::time_t actual_date() const {
return _date;
}
std::time_t effective_date() const {
if (_date_eff == 0)
return _date;
return _date_eff;
}
std::time_t date() const {
if (transaction_t::use_effective_date)
return effective_date();
else
return actual_date();
}
virtual void add_transaction(transaction_t * xact);
virtual bool valid() const;

View file

@ -1983,6 +1983,11 @@ used can be changed at any time with the @option{-y} flag, however.
Using @samp{%D} gives the user more control over the way dates are
output.
@item d
This is the same as the @samp{%D} option, unless the entry has an
effective date, in which case it prints
@samp{[ACTUAL_DATE=EFFECtIVE_DATE]}.
@item X
If a transaction has been cleared, this inserts @samp{*} followed by a
space; otherwise nothing is inserted.
@ -2369,17 +2374,32 @@ by any number of lines, each beginning with whitespace, to denote the
entry's account transactions. The format of the first line is:
@example
DATE [*|!] [(CODE)] DESC
DATE[=EDATE] [*|!] [(CODE)] DESC
@end example
If @samp{*} appears after the date, it indicates that entry is
``cleared'', meaning it has been seen a bank statement, or otherwise
verified. If @samp{!} appears after the date, it indicates that the
entry is ``pending''; i.e., tentatively cleared from the user's point
of view, but not yet cleared with your financial institution. If a
@samp{CODE} appears in parentheses, it may be used to indicate a check
number, or the type of the transaction. Following these is the payee,
or a description of the transaction.
If @samp{*} appears after the date (with optional effective date), it
indicates the entry is ``cleared'', which can mean whatever the user
wants it t omean. If @samp{!} appears after the date, it indicates d
the entry is ``pending''; i.e., tentatively cleared from the user's
point of view, but not yet actually cleared. If a @samp{CODE} appears
in parentheses, it may be used to indicate a check number, or the type
of the transaction. Following these is the payee, or a description of
the transaction.
The format of each following transaction is:
@example
ACCOUNT AMOUNT [; NOTE]
@end example
The @samp{ACCOUNT} may be surrounded by parentheses if it is a virtual
transactions, or square brackets if it is a virtual transactions that
must balance. The @samp{AMOUNT} can be followed by a per-unit
transaction cost, by specifying @samp{@ AMOUNT}, or a complete
transaction cost with @samp{@@ AMOUNT}. Lastly, the @samp{NOTE} may
specify an actual and/or effective date for the transaction by using
the syntax @samp{[ACTUAL_DATE]} or @samp{[=EFFECTIVE_DATE]} or
@samp{[ACTUAL_DATE=EFFECtIVE_DATE]}.
@item =
An automated entry. A value expression must appear after the equal

2
qif.cc
View file

@ -103,7 +103,7 @@ unsigned int qif_parser_t::parse(std::istream& in,
case 'D':
SET_BEG_POS_AND_LINE();
get_line(in);
if (! parse_date(line, &entry->date))
if (! parse_date(line, &entry->_date))
throw parse_error(path, linenum, "Failed to parse date");
break;

View file

@ -44,7 +44,7 @@ void reconcile_transactions::flush()
for (transactions_list::iterator x = xacts.begin();
x != xacts.end();
x++) {
if (! cutoff || std::difftime((*x)->entry->date, cutoff) < 0) {
if (! cutoff || std::difftime((*x)->date(), cutoff) < 0) {
switch ((*x)->state) {
case transaction_t::CLEARED:
cleared_balance += (*x)->amount;

View file

@ -205,7 +205,27 @@ transaction_t * parse_transaction(char * line, account_t * account)
if (char * note_str = std::strchr(amount, ';')) {
if (amount == note_str)
amount = NULL;
*note_str++ = '\0';
note_str = skip_ws(note_str);
if (char * b = std::strchr(note_str, '['))
if (char * e = std::strchr(note_str, ']')) {
char buf[256];
std::strncpy(buf, b + 1, e - b);
buf[e - b] = '\0';
if (char * p = std::strchr(buf, '=')) {
*p++ = '\0';
if (! quick_parse_date(p, &xact->_date_eff))
throw parse_error(path, linenum,
"Failed to parse effective date");
}
if (buf[0] && ! quick_parse_date(buf, &xact->_date))
throw parse_error(path, linenum, "Failed to parse date");
}
xact->note = skip_ws(note_str);
}
@ -313,7 +333,13 @@ entry_t * parse_entry(std::istream& in, char * line, account_t * master,
char * next = next_element(line);
if (! quick_parse_date(line, &curr->date))
if (char * p = std::strchr(line, '=')) {
*p++ = '\0';
if (! quick_parse_date(p, &curr->_date_eff))
throw parse_error(path, linenum, "Failed to parse effective date");
}
if (! quick_parse_date(line, &curr->_date))
throw parse_error(path, linenum, "Failed to parse date");
TIMER_STOP(entry_date);
@ -439,11 +465,11 @@ static void clock_out_from_timelog(const std::time_t when,
journal_t * journal)
{
std::auto_ptr<entry_t> curr(new entry_t);
curr->date = when;
curr->_date = when;
curr->code = "";
curr->payee = last_desc;
double diff = std::difftime(curr->date, time_in);
double diff = std::difftime(curr->_date, time_in);
char buf[32];
std::sprintf(buf, "%lds", long(diff));
amount_t amt;

View file

@ -107,12 +107,13 @@ void value_expr_t::compute(value_t& result, const details_t& details) const
if (details.xact && transaction_has_xdata(*details.xact) &&
transaction_xdata_(*details.xact).date)
result = long(transaction_xdata_(*details.xact).date);
else if (details.xact)
result = long(details.xact->date());
else if (details.entry)
result = long(details.entry->date);
result = long(details.entry->date());
else
result = long(now);
break;
case CLEARED:
if (details.xact)
result = details.xact->state == transaction_t::CLEARED;
@ -292,8 +293,10 @@ void value_expr_t::compute(value_t& result, const details_t& details) const
if (details.xact && transaction_has_xdata(*details.xact) &&
transaction_xdata_(*details.xact).date)
moment = transaction_xdata_(*details.xact).date;
else if (details.xact)
moment = details.xact->date();
else if (details.entry)
moment = details.entry->date;
moment = details.entry->date();
break;
case CONSTANT_T:
moment = right->constant_t;

38
walk.cc
View file

@ -232,7 +232,7 @@ void collapse_transactions::report_subtotal()
entry_temps.push_back(entry_t());
entry_t& entry = entry_temps.back();
entry.payee = last_entry->payee;
entry.date = last_entry->date;
entry._date = last_entry->_date;
handle_value(subtotal, &totals_account, last_entry, 0, xact_temps,
*handler);
@ -308,7 +308,7 @@ void changed_value_transactions::output_diff(const std::time_t current)
entry_temps.push_back(entry_t());
entry_t& entry = entry_temps.back();
entry.payee = "Commodities revalued";
entry.date = current;
entry._date = current;
handle_value(diff, NULL, &entry, TRANSACTION_NO_TOTAL, xact_temps,
*handler);
@ -321,8 +321,8 @@ void changed_value_transactions::operator()(transaction_t& xact)
std::time_t moment = 0;
if (transaction_has_xdata(*last_xact))
moment = transaction_xdata_(*last_xact).date;
if (! moment)
moment = xact.entry->date;
else
moment = xact.date();
output_diff(moment);
}
@ -352,7 +352,7 @@ void subtotal_transactions::report_subtotal(const char * spec_fmt)
entry_temps.push_back(entry_t());
entry_t& entry = entry_temps.back();
entry.payee = buf;
entry.date = start;
entry._date = start;
for (values_map::iterator i = values.begin();
i != values.end();
@ -365,10 +365,10 @@ void subtotal_transactions::report_subtotal(const char * spec_fmt)
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;
if (! start || std::difftime(xact.date(), start) < 0)
start = xact.date();
if (! finish || std::difftime(xact.date(), finish) > 0)
finish = xact.date();
account_t * acct = xact.account;
assert(acct);
@ -400,7 +400,7 @@ void interval_transactions::report_subtotal(const std::time_t moment)
if (moment)
finish = moment - 86400;
else
finish = last_xact->entry->date;
finish = last_xact->date();
subtotal_transactions::report_subtotal();
@ -412,7 +412,7 @@ void interval_transactions::report_subtotal(const std::time_t moment)
void interval_transactions::operator()(transaction_t& xact)
{
const std::time_t date = xact.entry->date;
const std::time_t date = xact.date();
if ((interval.begin && std::difftime(date, interval.begin) < 0) ||
(interval.end && std::difftime(date, interval.end) >= 0))
@ -483,8 +483,8 @@ void by_payee_transactions::operator()(transaction_t& xact)
i = result.first;
}
if (std::difftime(xact.entry->date, (*i).second->start) > 0)
(*i).second->start = xact.entry->date;
if (std::difftime(xact.date(), (*i).second->start) > 0)
(*i).second->start = xact.date();
(*(*i).second)(xact);
}
@ -493,7 +493,7 @@ 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._date = xact.date();
entry.code = xact.entry->code;
entry.payee = xact.amount.commodity().symbol;
@ -569,7 +569,7 @@ void budget_transactions::report_budget_items(const std::time_t moment)
entry_temps.push_back(entry_t());
entry_t& entry = entry_temps.back();
entry.payee = "Budget entry";
entry.date = begin;
entry._date = begin;
xact_temps.push_back(xact);
transaction_t& temp = xact_temps.back();
@ -611,7 +611,7 @@ void budget_transactions::operator()(transaction_t& xact)
handle:
if (xact_in_budget && flags & BUDGET_BUDGETED) {
report_budget_items(xact.entry->date);
report_budget_items(xact.date());
item_handler<transaction_t>::operator()(xact);
}
else if (! xact_in_budget && flags & BUDGET_UNBUDGETED) {
@ -661,7 +661,7 @@ void forecast_transactions::flush()
entry_temps.push_back(entry_t());
entry_t& entry = entry_temps.back();
entry.payee = "Forecast entry";
entry.date = begin;
entry._date = begin;
xact_temps.push_back(xact);
transaction_t& temp = xact_temps.back();
@ -682,7 +682,7 @@ void forecast_transactions::flush()
transaction_xdata_(temp).dflags & TRANSACTION_MATCHES) {
if (! pred(temp))
break;
last = temp.entry->date;
last = temp.date();
passed.clear();
} else {
bool found = false;
@ -856,7 +856,7 @@ void walk_commodities(commodities_map& commodities,
for (history_map::iterator j = (*i).second->history->prices.begin();
j != (*i).second->history->prices.end();
j++) {
entry_temps.back().date = (*j).first;
entry_temps.back()._date = (*j).first;
xact_temps.push_back(transaction_t(&acct_temps.back()));
transaction_t& temp = xact_temps.back();

3
walk.h
View file

@ -500,7 +500,8 @@ class dow_transactions : public subtotal_transactions
virtual void flush();
virtual void operator()(transaction_t& xact) {
struct std::tm * desc = std::localtime(&xact.entry->date);
std::time_t when = xact.date();
struct std::tm * desc = std::localtime(&when);
days_of_the_week[desc->tm_wday].push_back(&xact);
}
};

24
xml.cc
View file

@ -83,7 +83,10 @@ static void endElement(void *userData, const char *name)
curr_entry = NULL;
}
else if (std::strcmp(name, "en:date") == 0) {
quick_parse_date(data.c_str(), &curr_entry->date);
quick_parse_date(data.c_str(), &curr_entry->_date);
}
else if (std::strcmp(name, "en:date_eff") == 0) {
quick_parse_date(data.c_str(), &curr_entry->_date_eff);
}
else if (std::strcmp(name, "en:code") == 0) {
curr_entry->code = data;
@ -331,11 +334,17 @@ void format_xml_entries::format_last_entry()
{
char buf[256];
std::strftime(buf, 255, format_t::date_format.c_str(),
std::localtime(&last_entry->date));
std::localtime(&last_entry->_date));
output_stream << " <entry>\n"
<< " <en:date>" << buf << "</en:date>\n";
if (last_entry->_date_eff) {
std::strftime(buf, 255, format_t::date_format.c_str(),
std::localtime(&last_entry->_date_eff));
output_stream << " <en:date_eff>" << buf << "</en:date_eff>\n";
}
if (! last_entry->code.empty()) {
output_stream << " <en:code>";
output_xml_string(output_stream, last_entry->code);
@ -361,6 +370,17 @@ void format_xml_entries::format_last_entry()
output_stream << " <transaction>\n";
if ((*i)->_date) {
std::strftime(buf, 255, format_t::date_format.c_str(),
std::localtime(&(*i)->_date));
output_stream << " <tr:date>" << buf << "</tr:date>\n";
}
if ((*i)->_date_eff) {
std::strftime(buf, 255, format_t::date_format.c_str(),
std::localtime(&(*i)->_date_eff));
output_stream << " <tr:date_eff>" << buf << "</tr:date_eff>\n";
}
if ((*i)->state == transaction_t::CLEARED)
output_stream << " <tr:cleared/>\n";
else if ((*i)->state == transaction_t::PENDING)