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
|
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
|
* 2.4
|
||||||
|
|
||||||
- Both "-$100.00" and "$-100.00" are now equivalent amounts.
|
- Both "-$100.00" and "$-100.00" are now equivalent amounts.
|
||||||
|
|
|
||||||
16
binary.cc
16
binary.cc
|
|
@ -11,7 +11,7 @@
|
||||||
namespace ledger {
|
namespace ledger {
|
||||||
|
|
||||||
static unsigned long binary_magic_number = 0xFFEED765;
|
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;
|
||||||
static account_t ** accounts_next;
|
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)
|
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];
|
xact->account = accounts[read_binary_number<account_t::ident_t>(data) - 1];
|
||||||
|
|
||||||
read_binary_amount(data, xact->amount);
|
read_binary_amount(data, xact->amount);
|
||||||
|
|
||||||
if (*data++ == 1) {
|
if (*data++ == 1) {
|
||||||
|
|
@ -188,6 +189,7 @@ inline void read_binary_transaction(char *& data, transaction_t * xact)
|
||||||
} else {
|
} else {
|
||||||
xact->cost = NULL;
|
xact->cost = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
read_binary_number(data, xact->state);
|
read_binary_number(data, xact->state);
|
||||||
read_binary_number(data, xact->flags);
|
read_binary_number(data, xact->flags);
|
||||||
xact->flags |= TRANSACTION_BULK_ALLOC;
|
xact->flags |= TRANSACTION_BULK_ALLOC;
|
||||||
|
|
@ -218,7 +220,8 @@ inline void read_binary_entry(char *& data, entry_t * entry,
|
||||||
transaction_t *& xact_pool)
|
transaction_t *& xact_pool)
|
||||||
{
|
{
|
||||||
read_binary_entry_base(data, entry, 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->code);
|
||||||
read_binary_string(data, &entry->payee);
|
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)
|
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_number(out, xact->account->ident);
|
||||||
write_binary_amount(out, xact->amount);
|
write_binary_amount(out, xact->amount);
|
||||||
|
|
||||||
if (xact->cost) {
|
if (xact->cost) {
|
||||||
write_binary_number<char>(out, 1);
|
write_binary_number<char>(out, 1);
|
||||||
write_binary_amount(out, *xact->cost);
|
write_binary_amount(out, *xact->cost);
|
||||||
} else {
|
} else {
|
||||||
write_binary_number<char>(out, 0);
|
write_binary_number<char>(out, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
write_binary_number(out, xact->state);
|
write_binary_number(out, xact->state);
|
||||||
write_binary_number(out, xact->flags);
|
write_binary_number(out, xact->flags);
|
||||||
write_binary_string(out, xact->note);
|
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)
|
void write_binary_entry(std::ostream& out, entry_t * entry)
|
||||||
{
|
{
|
||||||
write_binary_entry_base(out, 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->code);
|
||||||
write_binary_string(out, entry->payee);
|
write_binary_string(out, entry->payee);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,8 +36,8 @@ config_t::config_t()
|
||||||
"%48|%-.38A %22.108t %22.132T\n");
|
"%48|%-.38A %22.108t %22.132T\n");
|
||||||
plot_amount_format = "%D %(St)\n";
|
plot_amount_format = "%D %(St)\n";
|
||||||
plot_total_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";
|
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_hdr_format = "%d %Y%C%P\n";
|
||||||
write_xact_format = " %-34W %12o%n\n";
|
write_xact_format = " %-34W %12o%n\n";
|
||||||
equity_format = "\n%D %Y%C%P\n%/ %-34W %12t\n";
|
equity_format = "\n%D %Y%C%P\n%/ %-34W %12t\n";
|
||||||
#ifndef USE_BOOST_PYTHON
|
#ifndef USE_BOOST_PYTHON
|
||||||
|
|
@ -714,6 +714,10 @@ OPT_BEGIN(plot_amount_format, ":") {
|
||||||
|
|
||||||
OPT_BEGIN(plot_total_format, ":") {
|
OPT_BEGIN(plot_total_format, ":") {
|
||||||
config.plot_total_format = optarg;
|
config.plot_total_format = optarg;
|
||||||
|
|
||||||
|
OPT_BEGIN(effective, "") {
|
||||||
|
transaction_t::use_effective_date = true;
|
||||||
|
} OPT_END(effective);
|
||||||
} OPT_END(plot_total_format);
|
} OPT_END(plot_total_format);
|
||||||
|
|
||||||
OPT_BEGIN(print_format, ":") {
|
OPT_BEGIN(print_format, ":") {
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ entry_t * derive_new_entry(journal_t& journal,
|
||||||
|
|
||||||
entry_t * matching = NULL;
|
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'");
|
throw error("Bad date passed to 'entry'");
|
||||||
|
|
||||||
if (++i == end)
|
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 << (((unsigned long)entry.beg_pos) + 1) << " ";
|
||||||
|
|
||||||
out << "(" << (entry.date / 65536) << " "
|
std::time_t date = entry.date();
|
||||||
<< (entry.date % 65536) << " 0) ";
|
out << "(" << (date / 65536) << " " << (date % 65536) << " 0) ";
|
||||||
|
|
||||||
if (entry.code.empty())
|
if (entry.code.empty())
|
||||||
out << "nil ";
|
out << "nil ";
|
||||||
|
|
|
||||||
63
format.cc
63
format.cc
|
|
@ -206,6 +206,10 @@ element_t * format_t::parse_elements(const std::string& fmt)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 'd':
|
||||||
|
current->type = element_t::COMPLETE_DATE_STRING;
|
||||||
|
current->chars = format_t::date_format;
|
||||||
|
break;
|
||||||
case 'D':
|
case 'D':
|
||||||
current->type = element_t::DATE_STRING;
|
current->type = element_t::DATE_STRING;
|
||||||
current->chars = format_t::date_format;
|
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;
|
out << details.entry->end_line;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case element_t::DATE_STRING:
|
case element_t::DATE_STRING: {
|
||||||
if (details.entry && details.entry->date) {
|
std::time_t date = 0;
|
||||||
char buf[256];
|
if (details.xact)
|
||||||
std::strftime(buf, 255, elem->chars.c_str(),
|
date = details.xact->date();
|
||||||
std::localtime(&details.entry->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));
|
out << (elem->max_width == 0 ? buf : truncated(buf, elem->max_width));
|
||||||
} else {
|
} else {
|
||||||
out << " ";
|
out << (elem->max_width == 0 ? abuf : truncated(abuf, elem->max_width));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case element_t::CLEARED:
|
case element_t::CLEARED:
|
||||||
if (details.xact) {
|
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,
|
format_transactions::format_transactions(std::ostream& _output_stream,
|
||||||
const std::string& format)
|
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();
|
const char * f = format.c_str();
|
||||||
if (const char * p = std::strstr(f, "%/")) {
|
if (const char * p = std::strstr(f, "%/")) {
|
||||||
|
|
@ -594,10 +633,16 @@ void format_transactions::operator()(transaction_t& xact)
|
||||||
if (last_entry != xact.entry) {
|
if (last_entry != xact.entry) {
|
||||||
first_line_format.format(output_stream, details_t(xact));
|
first_line_format.format(output_stream, details_t(xact));
|
||||||
last_entry = xact.entry;
|
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));
|
next_lines_format.format(output_stream, details_t(xact));
|
||||||
}
|
}
|
||||||
|
|
||||||
transaction_xdata(xact).dflags |= TRANSACTION_DISPLAYED;
|
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;
|
entry_t header_entry;
|
||||||
header_entry.payee = "Opening Balances";
|
header_entry.payee = "Opening Balances";
|
||||||
header_entry.date = now;
|
header_entry._date = now;
|
||||||
first_line_format.format(output_stream, details_t(header_entry));
|
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_POS,
|
||||||
END_LINE,
|
END_LINE,
|
||||||
DATE_STRING,
|
DATE_STRING,
|
||||||
|
COMPLETE_DATE_STRING,
|
||||||
CLEARED,
|
CLEARED,
|
||||||
ENTRY_CLEARED,
|
ENTRY_CLEARED,
|
||||||
CODE,
|
CODE,
|
||||||
|
|
@ -97,10 +98,11 @@ struct format_t
|
||||||
class format_transactions : public item_handler<transaction_t>
|
class format_transactions : public item_handler<transaction_t>
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
std::ostream& output_stream;
|
std::ostream& output_stream;
|
||||||
format_t first_line_format;
|
format_t first_line_format;
|
||||||
format_t next_lines_format;
|
format_t next_lines_format;
|
||||||
entry_t * last_entry;
|
entry_t * last_entry;
|
||||||
|
transaction_t * last_xact;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
format_transactions(std::ostream& _output_stream,
|
format_transactions(std::ostream& _output_stream,
|
||||||
|
|
|
||||||
|
|
@ -236,7 +236,7 @@ static void dataHandler(void *userData, const char *s, int len)
|
||||||
case ENTRY_DATE: {
|
case ENTRY_DATE: {
|
||||||
struct tm when;
|
struct tm when;
|
||||||
strptime(std::string(s, len).c_str(), "%Y-%m-%d %H:%M:%S %z", &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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
27
journal.cc
27
journal.cc
|
|
@ -14,6 +14,26 @@ namespace ledger {
|
||||||
|
|
||||||
const std::string version = PACKAGE_VERSION;
|
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
|
bool transaction_t::valid() const
|
||||||
{
|
{
|
||||||
if (! entry)
|
if (! entry)
|
||||||
|
|
@ -201,7 +221,8 @@ bool entry_base_t::finalize()
|
||||||
}
|
}
|
||||||
|
|
||||||
entry_t::entry_t(const entry_t& e)
|
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");
|
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
|
bool entry_t::valid() const
|
||||||
{
|
{
|
||||||
if (! date || ! journal)
|
if (! _date || ! journal)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (transactions_list::const_iterator i = transactions.begin();
|
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 != entry->transactions.end();
|
||||||
i++)
|
i++)
|
||||||
if ((*i)->cost && (*i)->amount)
|
if ((*i)->cost && (*i)->amount)
|
||||||
(*i)->amount.commodity().add_price(entry->date,
|
(*i)->amount.commodity().add_price(entry->date(),
|
||||||
*(*i)->cost / (*i)->amount);
|
*(*i)->cost / (*i)->amount);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
40
journal.h
40
journal.h
|
|
@ -32,6 +32,8 @@ class transaction_t
|
||||||
enum state_t { UNCLEARED, CLEARED, PENDING };
|
enum state_t { UNCLEARED, CLEARED, PENDING };
|
||||||
|
|
||||||
entry_t * entry;
|
entry_t * entry;
|
||||||
|
std::time_t _date;
|
||||||
|
std::time_t _date_eff;
|
||||||
account_t * account;
|
account_t * account;
|
||||||
amount_t amount;
|
amount_t amount;
|
||||||
amount_t * cost;
|
amount_t * cost;
|
||||||
|
|
@ -40,8 +42,10 @@ class transaction_t
|
||||||
std::string note;
|
std::string note;
|
||||||
mutable void * data;
|
mutable void * data;
|
||||||
|
|
||||||
|
static bool use_effective_date;
|
||||||
|
|
||||||
transaction_t(account_t * _account = NULL)
|
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) {
|
state(UNCLEARED), flags(TRANSACTION_NORMAL), data(NULL) {
|
||||||
DEBUG_PRINT("ledger.memory.ctors", "ctor transaction_t");
|
DEBUG_PRINT("ledger.memory.ctors", "ctor transaction_t");
|
||||||
}
|
}
|
||||||
|
|
@ -50,14 +54,15 @@ class transaction_t
|
||||||
const amount_t& _amount,
|
const amount_t& _amount,
|
||||||
unsigned int _flags = TRANSACTION_NORMAL,
|
unsigned int _flags = TRANSACTION_NORMAL,
|
||||||
const std::string& _note = "")
|
const std::string& _note = "")
|
||||||
: entry(NULL), account(_account), amount(_amount),
|
: entry(NULL), _date(0), account(_account), amount(_amount),
|
||||||
cost(NULL), state(UNCLEARED), flags(_flags),
|
cost(NULL), state(UNCLEARED), flags(_flags),
|
||||||
note(_note), data(NULL) {
|
note(_note), data(NULL) {
|
||||||
DEBUG_PRINT("ledger.memory.ctors", "ctor transaction_t");
|
DEBUG_PRINT("ledger.memory.ctors", "ctor transaction_t");
|
||||||
}
|
}
|
||||||
|
|
||||||
transaction_t(const transaction_t& xact)
|
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),
|
cost(xact.cost ? new amount_t(*xact.cost) : NULL),
|
||||||
state(xact.state), flags(xact.flags), note(xact.note),
|
state(xact.state), flags(xact.flags), note(xact.note),
|
||||||
data(NULL) {
|
data(NULL) {
|
||||||
|
|
@ -70,6 +75,15 @@ class transaction_t
|
||||||
delete cost;
|
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) {
|
bool operator==(const transaction_t& xact) {
|
||||||
return this == &xact;
|
return this == &xact;
|
||||||
}
|
}
|
||||||
|
|
@ -133,11 +147,12 @@ class entry_base_t
|
||||||
class entry_t : public entry_base_t
|
class entry_t : public entry_base_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
std::time_t date;
|
std::time_t _date;
|
||||||
|
std::time_t _date_eff;
|
||||||
std::string code;
|
std::string code;
|
||||||
std::string payee;
|
std::string payee;
|
||||||
|
|
||||||
entry_t() : date(0) {
|
entry_t() : _date(0), _date_eff(0) {
|
||||||
DEBUG_PRINT("ledger.memory.ctors", "ctor entry_t");
|
DEBUG_PRINT("ledger.memory.ctors", "ctor entry_t");
|
||||||
}
|
}
|
||||||
entry_t(const entry_t& e);
|
entry_t(const entry_t& e);
|
||||||
|
|
@ -148,6 +163,21 @@ class entry_t : public entry_base_t
|
||||||
}
|
}
|
||||||
#endif
|
#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 void add_transaction(transaction_t * xact);
|
||||||
|
|
||||||
virtual bool valid() const;
|
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
|
Using @samp{%D} gives the user more control over the way dates are
|
||||||
output.
|
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
|
@item X
|
||||||
If a transaction has been cleared, this inserts @samp{*} followed by a
|
If a transaction has been cleared, this inserts @samp{*} followed by a
|
||||||
space; otherwise nothing is inserted.
|
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:
|
entry's account transactions. The format of the first line is:
|
||||||
|
|
||||||
@example
|
@example
|
||||||
DATE [*|!] [(CODE)] DESC
|
DATE[=EDATE] [*|!] [(CODE)] DESC
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
If @samp{*} appears after the date, it indicates that entry is
|
If @samp{*} appears after the date (with optional effective date), it
|
||||||
``cleared'', meaning it has been seen a bank statement, or otherwise
|
indicates the entry is ``cleared'', which can mean whatever the user
|
||||||
verified. If @samp{!} appears after the date, it indicates that the
|
wants it t omean. If @samp{!} appears after the date, it indicates d
|
||||||
entry is ``pending''; i.e., tentatively cleared from the user's point
|
the entry is ``pending''; i.e., tentatively cleared from the user's
|
||||||
of view, but not yet cleared with your financial institution. If a
|
point of view, but not yet actually cleared. If a @samp{CODE} appears
|
||||||
@samp{CODE} appears in parentheses, it may be used to indicate a check
|
in parentheses, it may be used to indicate a check number, or the type
|
||||||
number, or the type of the transaction. Following these is the payee,
|
of the transaction. Following these is the payee, or a description of
|
||||||
or a description of the transaction.
|
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 =
|
@item =
|
||||||
An automated entry. A value expression must appear after the equal
|
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':
|
case 'D':
|
||||||
SET_BEG_POS_AND_LINE();
|
SET_BEG_POS_AND_LINE();
|
||||||
get_line(in);
|
get_line(in);
|
||||||
if (! parse_date(line, &entry->date))
|
if (! parse_date(line, &entry->_date))
|
||||||
throw parse_error(path, linenum, "Failed to parse date");
|
throw parse_error(path, linenum, "Failed to parse date");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ void reconcile_transactions::flush()
|
||||||
for (transactions_list::iterator x = xacts.begin();
|
for (transactions_list::iterator x = xacts.begin();
|
||||||
x != xacts.end();
|
x != xacts.end();
|
||||||
x++) {
|
x++) {
|
||||||
if (! cutoff || std::difftime((*x)->entry->date, cutoff) < 0) {
|
if (! cutoff || std::difftime((*x)->date(), cutoff) < 0) {
|
||||||
switch ((*x)->state) {
|
switch ((*x)->state) {
|
||||||
case transaction_t::CLEARED:
|
case transaction_t::CLEARED:
|
||||||
cleared_balance += (*x)->amount;
|
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 (char * note_str = std::strchr(amount, ';')) {
|
||||||
if (amount == note_str)
|
if (amount == note_str)
|
||||||
amount = NULL;
|
amount = NULL;
|
||||||
|
|
||||||
*note_str++ = '\0';
|
*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);
|
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);
|
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");
|
throw parse_error(path, linenum, "Failed to parse date");
|
||||||
|
|
||||||
TIMER_STOP(entry_date);
|
TIMER_STOP(entry_date);
|
||||||
|
|
@ -439,11 +465,11 @@ static void clock_out_from_timelog(const std::time_t when,
|
||||||
journal_t * journal)
|
journal_t * journal)
|
||||||
{
|
{
|
||||||
std::auto_ptr<entry_t> curr(new entry_t);
|
std::auto_ptr<entry_t> curr(new entry_t);
|
||||||
curr->date = when;
|
curr->_date = when;
|
||||||
curr->code = "";
|
curr->code = "";
|
||||||
curr->payee = last_desc;
|
curr->payee = last_desc;
|
||||||
|
|
||||||
double diff = std::difftime(curr->date, time_in);
|
double diff = std::difftime(curr->_date, time_in);
|
||||||
char buf[32];
|
char buf[32];
|
||||||
std::sprintf(buf, "%lds", long(diff));
|
std::sprintf(buf, "%lds", long(diff));
|
||||||
amount_t amt;
|
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) &&
|
if (details.xact && transaction_has_xdata(*details.xact) &&
|
||||||
transaction_xdata_(*details.xact).date)
|
transaction_xdata_(*details.xact).date)
|
||||||
result = long(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)
|
else if (details.entry)
|
||||||
result = long(details.entry->date);
|
result = long(details.entry->date());
|
||||||
else
|
else
|
||||||
result = long(now);
|
result = long(now);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CLEARED:
|
case CLEARED:
|
||||||
if (details.xact)
|
if (details.xact)
|
||||||
result = details.xact->state == transaction_t::CLEARED;
|
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) &&
|
if (details.xact && transaction_has_xdata(*details.xact) &&
|
||||||
transaction_xdata_(*details.xact).date)
|
transaction_xdata_(*details.xact).date)
|
||||||
moment = transaction_xdata_(*details.xact).date;
|
moment = transaction_xdata_(*details.xact).date;
|
||||||
|
else if (details.xact)
|
||||||
|
moment = details.xact->date();
|
||||||
else if (details.entry)
|
else if (details.entry)
|
||||||
moment = details.entry->date;
|
moment = details.entry->date();
|
||||||
break;
|
break;
|
||||||
case CONSTANT_T:
|
case CONSTANT_T:
|
||||||
moment = right->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_temps.push_back(entry_t());
|
||||||
entry_t& entry = entry_temps.back();
|
entry_t& entry = entry_temps.back();
|
||||||
entry.payee = last_entry->payee;
|
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,
|
handle_value(subtotal, &totals_account, last_entry, 0, xact_temps,
|
||||||
*handler);
|
*handler);
|
||||||
|
|
@ -308,7 +308,7 @@ void changed_value_transactions::output_diff(const std::time_t current)
|
||||||
entry_temps.push_back(entry_t());
|
entry_temps.push_back(entry_t());
|
||||||
entry_t& entry = entry_temps.back();
|
entry_t& entry = entry_temps.back();
|
||||||
entry.payee = "Commodities revalued";
|
entry.payee = "Commodities revalued";
|
||||||
entry.date = current;
|
entry._date = current;
|
||||||
|
|
||||||
handle_value(diff, NULL, &entry, TRANSACTION_NO_TOTAL, xact_temps,
|
handle_value(diff, NULL, &entry, TRANSACTION_NO_TOTAL, xact_temps,
|
||||||
*handler);
|
*handler);
|
||||||
|
|
@ -321,8 +321,8 @@ void changed_value_transactions::operator()(transaction_t& xact)
|
||||||
std::time_t moment = 0;
|
std::time_t moment = 0;
|
||||||
if (transaction_has_xdata(*last_xact))
|
if (transaction_has_xdata(*last_xact))
|
||||||
moment = transaction_xdata_(*last_xact).date;
|
moment = transaction_xdata_(*last_xact).date;
|
||||||
if (! moment)
|
else
|
||||||
moment = xact.entry->date;
|
moment = xact.date();
|
||||||
output_diff(moment);
|
output_diff(moment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -352,7 +352,7 @@ void subtotal_transactions::report_subtotal(const char * spec_fmt)
|
||||||
entry_temps.push_back(entry_t());
|
entry_temps.push_back(entry_t());
|
||||||
entry_t& entry = entry_temps.back();
|
entry_t& entry = entry_temps.back();
|
||||||
entry.payee = buf;
|
entry.payee = buf;
|
||||||
entry.date = start;
|
entry._date = start;
|
||||||
|
|
||||||
for (values_map::iterator i = values.begin();
|
for (values_map::iterator i = values.begin();
|
||||||
i != values.end();
|
i != values.end();
|
||||||
|
|
@ -365,10 +365,10 @@ void subtotal_transactions::report_subtotal(const char * spec_fmt)
|
||||||
|
|
||||||
void subtotal_transactions::operator()(transaction_t& xact)
|
void subtotal_transactions::operator()(transaction_t& xact)
|
||||||
{
|
{
|
||||||
if (! start || std::difftime(xact.entry->date, start) < 0)
|
if (! start || std::difftime(xact.date(), start) < 0)
|
||||||
start = xact.entry->date;
|
start = xact.date();
|
||||||
if (! finish || std::difftime(xact.entry->date, finish) > 0)
|
if (! finish || std::difftime(xact.date(), finish) > 0)
|
||||||
finish = xact.entry->date;
|
finish = xact.date();
|
||||||
|
|
||||||
account_t * acct = xact.account;
|
account_t * acct = xact.account;
|
||||||
assert(acct);
|
assert(acct);
|
||||||
|
|
@ -400,7 +400,7 @@ void interval_transactions::report_subtotal(const std::time_t moment)
|
||||||
if (moment)
|
if (moment)
|
||||||
finish = moment - 86400;
|
finish = moment - 86400;
|
||||||
else
|
else
|
||||||
finish = last_xact->entry->date;
|
finish = last_xact->date();
|
||||||
|
|
||||||
subtotal_transactions::report_subtotal();
|
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)
|
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) ||
|
if ((interval.begin && std::difftime(date, interval.begin) < 0) ||
|
||||||
(interval.end && std::difftime(date, interval.end) >= 0))
|
(interval.end && std::difftime(date, interval.end) >= 0))
|
||||||
|
|
@ -483,8 +483,8 @@ void by_payee_transactions::operator()(transaction_t& xact)
|
||||||
i = result.first;
|
i = result.first;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (std::difftime(xact.entry->date, (*i).second->start) > 0)
|
if (std::difftime(xact.date(), (*i).second->start) > 0)
|
||||||
(*i).second->start = xact.entry->date;
|
(*i).second->start = xact.date();
|
||||||
|
|
||||||
(*(*i).second)(xact);
|
(*(*i).second)(xact);
|
||||||
}
|
}
|
||||||
|
|
@ -493,7 +493,7 @@ void set_comm_as_payee::operator()(transaction_t& xact)
|
||||||
{
|
{
|
||||||
entry_temps.push_back(*xact.entry);
|
entry_temps.push_back(*xact.entry);
|
||||||
entry_t& entry = entry_temps.back();
|
entry_t& entry = entry_temps.back();
|
||||||
entry.date = xact.entry->date;
|
entry._date = xact.date();
|
||||||
entry.code = xact.entry->code;
|
entry.code = xact.entry->code;
|
||||||
entry.payee = xact.amount.commodity().symbol;
|
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_temps.push_back(entry_t());
|
||||||
entry_t& entry = entry_temps.back();
|
entry_t& entry = entry_temps.back();
|
||||||
entry.payee = "Budget entry";
|
entry.payee = "Budget entry";
|
||||||
entry.date = begin;
|
entry._date = begin;
|
||||||
|
|
||||||
xact_temps.push_back(xact);
|
xact_temps.push_back(xact);
|
||||||
transaction_t& temp = xact_temps.back();
|
transaction_t& temp = xact_temps.back();
|
||||||
|
|
@ -611,7 +611,7 @@ void budget_transactions::operator()(transaction_t& xact)
|
||||||
|
|
||||||
handle:
|
handle:
|
||||||
if (xact_in_budget && flags & BUDGET_BUDGETED) {
|
if (xact_in_budget && flags & BUDGET_BUDGETED) {
|
||||||
report_budget_items(xact.entry->date);
|
report_budget_items(xact.date());
|
||||||
item_handler<transaction_t>::operator()(xact);
|
item_handler<transaction_t>::operator()(xact);
|
||||||
}
|
}
|
||||||
else if (! xact_in_budget && flags & BUDGET_UNBUDGETED) {
|
else if (! xact_in_budget && flags & BUDGET_UNBUDGETED) {
|
||||||
|
|
@ -661,7 +661,7 @@ void forecast_transactions::flush()
|
||||||
entry_temps.push_back(entry_t());
|
entry_temps.push_back(entry_t());
|
||||||
entry_t& entry = entry_temps.back();
|
entry_t& entry = entry_temps.back();
|
||||||
entry.payee = "Forecast entry";
|
entry.payee = "Forecast entry";
|
||||||
entry.date = begin;
|
entry._date = begin;
|
||||||
|
|
||||||
xact_temps.push_back(xact);
|
xact_temps.push_back(xact);
|
||||||
transaction_t& temp = xact_temps.back();
|
transaction_t& temp = xact_temps.back();
|
||||||
|
|
@ -682,7 +682,7 @@ void forecast_transactions::flush()
|
||||||
transaction_xdata_(temp).dflags & TRANSACTION_MATCHES) {
|
transaction_xdata_(temp).dflags & TRANSACTION_MATCHES) {
|
||||||
if (! pred(temp))
|
if (! pred(temp))
|
||||||
break;
|
break;
|
||||||
last = temp.entry->date;
|
last = temp.date();
|
||||||
passed.clear();
|
passed.clear();
|
||||||
} else {
|
} else {
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
|
@ -856,7 +856,7 @@ void walk_commodities(commodities_map& commodities,
|
||||||
for (history_map::iterator j = (*i).second->history->prices.begin();
|
for (history_map::iterator j = (*i).second->history->prices.begin();
|
||||||
j != (*i).second->history->prices.end();
|
j != (*i).second->history->prices.end();
|
||||||
j++) {
|
j++) {
|
||||||
entry_temps.back().date = (*j).first;
|
entry_temps.back()._date = (*j).first;
|
||||||
|
|
||||||
xact_temps.push_back(transaction_t(&acct_temps.back()));
|
xact_temps.push_back(transaction_t(&acct_temps.back()));
|
||||||
transaction_t& temp = xact_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 flush();
|
||||||
virtual void operator()(transaction_t& xact) {
|
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);
|
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;
|
curr_entry = NULL;
|
||||||
}
|
}
|
||||||
else if (std::strcmp(name, "en:date") == 0) {
|
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) {
|
else if (std::strcmp(name, "en:code") == 0) {
|
||||||
curr_entry->code = data;
|
curr_entry->code = data;
|
||||||
|
|
@ -331,11 +334,17 @@ void format_xml_entries::format_last_entry()
|
||||||
{
|
{
|
||||||
char buf[256];
|
char buf[256];
|
||||||
std::strftime(buf, 255, format_t::date_format.c_str(),
|
std::strftime(buf, 255, format_t::date_format.c_str(),
|
||||||
std::localtime(&last_entry->date));
|
std::localtime(&last_entry->_date));
|
||||||
|
|
||||||
output_stream << " <entry>\n"
|
output_stream << " <entry>\n"
|
||||||
<< " <en:date>" << buf << "</en:date>\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()) {
|
if (! last_entry->code.empty()) {
|
||||||
output_stream << " <en:code>";
|
output_stream << " <en:code>";
|
||||||
output_xml_string(output_stream, last_entry->code);
|
output_xml_string(output_stream, last_entry->code);
|
||||||
|
|
@ -361,6 +370,17 @@ void format_xml_entries::format_last_entry()
|
||||||
|
|
||||||
output_stream << " <transaction>\n";
|
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)
|
if ((*i)->state == transaction_t::CLEARED)
|
||||||
output_stream << " <tr:cleared/>\n";
|
output_stream << " <tr:cleared/>\n";
|
||||||
else if ((*i)->state == transaction_t::PENDING)
|
else if ((*i)->state == transaction_t::PENDING)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue