diff options
author | John Wiegley <johnw@newartisans.com> | 2005-10-19 22:42:24 +0000 |
---|---|---|
committer | John Wiegley <johnw@newartisans.com> | 2008-04-13 02:41:19 -0400 |
commit | eb0525e3157b579d45aab568e3ee06432fbaa338 (patch) | |
tree | 308ada59d939b363afd3791ef5f26406cedcebe1 | |
parent | a53f44ecdaf9051c9e7f64993787c88d98b5348a (diff) | |
download | fork-ledger-eb0525e3157b579d45aab568e3ee06432fbaa338.tar.gz fork-ledger-eb0525e3157b579d45aab568e3ee06432fbaa338.tar.bz2 fork-ledger-eb0525e3157b579d45aab568e3ee06432fbaa338.zip |
See ChangeLog
-rw-r--r-- | NEWS | 81 | ||||
-rw-r--r-- | binary.cc | 16 | ||||
-rw-r--r-- | config.cc | 8 | ||||
-rw-r--r-- | derive.cc | 2 | ||||
-rw-r--r-- | emacs.cc | 4 | ||||
-rw-r--r-- | format.cc | 63 | ||||
-rw-r--r-- | format.h | 10 | ||||
-rw-r--r-- | gnucash.cc | 2 | ||||
-rw-r--r-- | journal.cc | 27 | ||||
-rw-r--r-- | journal.h | 40 | ||||
-rw-r--r-- | ledger.texi | 38 | ||||
-rw-r--r-- | qif.cc | 2 | ||||
-rw-r--r-- | reconcile.cc | 2 | ||||
-rw-r--r-- | textual.cc | 32 | ||||
-rw-r--r-- | valexpr.cc | 9 | ||||
-rw-r--r-- | walk.cc | 38 | ||||
-rw-r--r-- | walk.h | 3 | ||||
-rw-r--r-- | xml.cc | 24 |
18 files changed, 331 insertions, 70 deletions
@@ -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. @@ -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); } @@ -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, ":") { @@ -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) @@ -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 "; @@ -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)); } @@ -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, @@ -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; } @@ -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; @@ -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; diff --git a/ledger.texi b/ledger.texi index bf756c1a..b8da037a 100644 --- a/ledger.texi +++ b/ledger.texi @@ -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 (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 -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. +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 @@ -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; diff --git a/reconcile.cc b/reconcile.cc index 07e2125d..b28718ee 100644 --- a/reconcile.cc +++ b/reconcile.cc @@ -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; @@ -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; @@ -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; @@ -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(); @@ -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); } }; @@ -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) |