See ChangeLog
This commit is contained in:
parent
a53f44ecda
commit
eb0525e315
18 changed files with 331 additions and 70 deletions
81
NEWS
81
NEWS
|
|
@ -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.
|
||||
|
|
|
|||
16
binary.cc
16
binary.cc
|
|
@ -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)
|
||||
|
|
|
|||
4
emacs.cc
4
emacs.cc
|
|
@ -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 ";
|
||||
|
|
|
|||
63
format.cc
63
format.cc
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
|||
10
format.h
10
format.h
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
27
journal.cc
27
journal.cc
|
|
@ -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;
|
||||
|
|
|
|||
40
journal.h
40
journal.h
|
|
@ -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;
|
||||
|
|
|
|||
38
ledger.texi
38
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, 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
2
qif.cc
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
32
textual.cc
32
textual.cc
|
|
@ -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;
|
||||
|
|
|
|||
38
walk.cc
38
walk.cc
|
|
@ -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
3
walk.h
|
|
@ -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
24
xml.cc
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue