diff options
author | John Wiegley <johnw@newartisans.com> | 2009-02-23 19:07:30 -0400 |
---|---|---|
committer | John Wiegley <johnw@newartisans.com> | 2009-02-23 19:07:30 -0400 |
commit | 944c63e6f26d1f05ba6f63c60f510d3796872f3e (patch) | |
tree | e1fc54319c2c42c16a64e95930acaca063658863 | |
parent | 057506ab6dddbfb75d1bb29289602f375ca57df5 (diff) | |
download | fork-ledger-944c63e6f26d1f05ba6f63c60f510d3796872f3e.tar.gz fork-ledger-944c63e6f26d1f05ba6f63c60f510d3796872f3e.tar.bz2 fork-ledger-944c63e6f26d1f05ba6f63c60f510d3796872f3e.zip |
The Great Renaming, Part II
The last commit did not contain the majority of changes because of a
slight mishap. This contains the real changeset.
58 files changed, 3159 insertions, 3164 deletions
diff --git a/Makefile.am b/Makefile.am index 565b1bfb..fdb2a219 100644 --- a/Makefile.am +++ b/Makefile.am @@ -56,8 +56,8 @@ libledger_data_la_SOURCES = \ src/textual.cc \ src/journal.cc \ src/account.cc \ - src/entry.cc \ src/xact.cc \ + src/post.cc \ src/item.cc libledger_data_la_CPPFLAGS = $(lib_cppflags) @@ -107,8 +107,8 @@ pkginclude_HEADERS = \ src/option.h \ \ src/item.h \ + src/post.h \ src/xact.h \ - src/entry.h \ src/account.h \ src/journal.h \ src/timelog.h \ @@ -199,7 +199,7 @@ libledger_python_la_SOURCES = \ python/pyfstream.h \ python/py_chain.cc \ python/py_commodity.cc \ - python/py_entry.cc \ + python/py_xact.cc \ python/py_expr.cc \ python/py_flags.cc \ python/py_format.cc \ @@ -213,7 +213,7 @@ libledger_python_la_SOURCES = \ python/py_times.cc \ python/py_utils.cc \ python/py_value.cc \ - python/py_xact.cc \ + python/py_post.cc \ python/pyinterp.cc \ python/setup.py diff --git a/contrib/ParseCcStmt.cs b/contrib/ParseCcStmt.cs index f6b2f20b..c9ad1d55 100644 --- a/contrib/ParseCcStmt.cs +++ b/contrib/ParseCcStmt.cs @@ -41,7 +41,7 @@ using CSVReader; /** * @file ParseCcStmt.cs * - * @brief Provides a .NET way to turn a CSV report into Ledger entries. + * @brief Provides a .NET way to turn a CSV report into Ledger transactions. * * I use this code for converting the statements from my own credit card * issuer. I realize it's strange for this to be in C#, but I wrote it @@ -52,7 +52,7 @@ using CSVReader; namespace JohnWiegley { - public class Transaction + public class Posting { public DateTime Date; public DateTime PostedDate; @@ -63,90 +63,90 @@ namespace JohnWiegley public interface IStatementConverter { - List<Transaction> ConvertRecords(Stream s); + List<Posting> ConvertRecords(Stream s); } public class ConvertGoldMasterCardStatement : IStatementConverter { - public List<Transaction> ConvertRecords(Stream s) + public List<Posting> ConvertRecords(Stream s) { - List<Transaction> xacts = new List<Transaction>(); + List<Posting> posts = new List<Posting>(); using (CSVReader.CSVReader csv = new CSVReader.CSVReader(s)) { string[] fields; while ((fields = csv.GetCSVLine()) != null) { - if (fields[0] == "TRANSACTION DATE") + if (fields[0] == "POSTING DATE") continue; - Transaction xact = new Transaction(); + Posting post = new Posting(); - xact.Date = DateTime.ParseExact(fields[0], "mm/dd/yy", null); - xact.PostedDate = DateTime.ParseExact(fields[1], "mm/dd/yy", null); - xact.Payee = fields[2].Trim(); - xact.Code = fields[3].Trim(); - xact.Amount = Convert.ToDecimal(fields[4].Trim()); + post.Date = DateTime.ParseEpost(fields[0], "mm/dd/yy", null); + post.PostedDate = DateTime.ParseEpost(fields[1], "mm/dd/yy", null); + post.Payee = fields[2].Trim(); + post.Code = fields[3].Trim(); + post.Amount = Convert.ToDecimal(fields[4].Trim()); - if (xact.Code.Length == 0) - xact.Code = null; + if (post.Code.Length == 0) + post.Code = null; - xacts.Add(xact); + posts.Add(post); } } - return xacts; + return posts; } } public class ConvertMastercardStatement : IStatementConverter { - public List<Transaction> ConvertRecords(Stream s) + public List<Posting> ConvertRecords(Stream s) { - List<Transaction> xacts = new List<Transaction>(); + List<Posting> posts = new List<Posting>(); using (CSVReader.CSVReader csv = new CSVReader.CSVReader(s)) { string[] fields; while ((fields = csv.GetCSVLine()) != null) { - Transaction xact = new Transaction(); + Posting post = new Posting(); - xact.Date = DateTime.ParseExact(fields[0], "m/dd/yyyy", null); - xact.Payee = fields[2].Trim(); - xact.Code = fields[3].Trim(); - xact.Amount = - Convert.ToDecimal(fields[4].Trim()); + post.Date = DateTime.ParseEpost(fields[0], "m/dd/yyyy", null); + post.Payee = fields[2].Trim(); + post.Code = fields[3].Trim(); + post.Amount = - Convert.ToDecimal(fields[4].Trim()); - if (xact.Code.Length == 0) - xact.Code = null; + if (post.Code.Length == 0) + post.Code = null; - xacts.Add(xact); + posts.Add(post); } } - return xacts; + return posts; } } - public class PrintTransactions + public class PrintPostings { - public string DefaultAccount(Transaction xact) { - if (Regex.IsMatch(xact.Payee, "IGA")) + public string DefaultAccount(Posting post) { + if (Regex.IsMatch(post.Payee, "IGA")) return "Expenses:Food"; return "Expenses:Food"; } public void Print(string AccountName, string PayAccountName, - List<Transaction> xacts) + List<Posting> posts) { - foreach (Transaction xact in xacts) { - if (xact.Amount < 0) { - Console.WriteLine("{0} * {1}{2}", xact.Date.ToString("yyyy/mm/dd"), - xact.Code != null ? "(" + xact.Code + ") " : "", - xact.Payee); + foreach (Posting post in posts) { + if (post.Amount < 0) { + Console.WriteLine("{0} * {1}{2}", post.Date.ToString("yyyy/mm/dd"), + post.Code != null ? "(" + post.Code + ") " : "", + post.Payee); Console.WriteLine(" {0,-36}{1,12}", AccountName, - "$" + (- xact.Amount).ToString()); + "$" + (- post.Amount).ToString()); Console.WriteLine(" {0}", PayAccountName); } else { - Console.WriteLine("{0} {1}{2}", xact.Date.ToString("yyyy/mm/dd"), - xact.Code != null ? "(" + xact.Code + ") " : "", - xact.Payee); - Console.WriteLine(" {0,-36}{1,12}", DefaultAccount(xact), - "$" + xact.Amount.ToString()); + Console.WriteLine("{0} {1}{2}", post.Date.ToString("yyyy/mm/dd"), + post.Code != null ? "(" + post.Code + ") " : "", + post.Payee); + Console.WriteLine(" {0,-36}{1,12}", DefaultAccount(post), + "$" + post.Amount.ToString()); Console.WriteLine(" * {0}", AccountName); } Console.WriteLine(); @@ -166,17 +166,17 @@ namespace JohnWiegley IStatementConverter converter; - if (firstLine.StartsWith("TRANSACTION DATE")) { + if (firstLine.StartsWith("POSTING DATE")) { converter = new ConvertGoldMasterCardStatement(); } else { converter = new ConvertMastercardStatement(); } reader = new StreamReader(args[0]); - List<Transaction> xacts = converter.ConvertRecords(reader.BaseStream); + List<Posting> posts = converter.ConvertRecords(reader.BaseStream); - PrintTransactions printer = new PrintTransactions(); - printer.Print(CardAccount, BankAccount, xacts); + PrintPostings printer = new PrintPostings(); + printer.Print(CardAccount, BankAccount, posts); return 0; } diff --git a/contrib/entry b/contrib/entry index cc030d8e..ef1869da 100755 --- a/contrib/entry +++ b/contrib/entry @@ -6,11 +6,11 @@ fi line=`wc -l $LEDGER | awk '{print $1}'` -if ledger entry "$@" > /tmp/entry; then - cat /tmp/entry >> $LEDGER +if ledger xact "$@" > /tmp/xact; then + cat /tmp/xact >> $LEDGER else echo "$@" >> $LEDGER fi -rm /tmp/entry +rm /tmp/xact vi +$line $LEDGER diff --git a/contrib/ledger-du b/contrib/ledger-du index f5d7dd7d..580e916e 100755 --- a/contrib/ledger-du +++ b/contrib/ledger-du @@ -23,14 +23,14 @@ def report_file(path): print def find_files(path): - entries = os.listdir(path) - for entry in entries: - entry = join(path, entry) - if not islink(entry): - if isdir(entry) and entry != "/proc": - find_files(entry) + xacts = os.listdir(path) + for xact in xacts: + xact = join(path, xact) + if not islink(xact): + if isdir(xact) and xact != "/proc": + find_files(xact) else: - report_file(entry) + report_file(xact) args = sys.argv[1:] if len(args): diff --git a/contrib/ledger.vim b/contrib/ledger.vim index 2efce5be..fd61f71e 100644 --- a/contrib/ledger.vim +++ b/contrib/ledger.vim @@ -6,7 +6,7 @@ " Revision history " 2009-01-28 S.Karrmann: minor fixes " 2009-01-27 third version by S.Karrmann. -" better extraction of the amount of the transaction +" better extraction of the amount of the posting " decimal separator can be one of '.' and ','. " 2005-02-05 first version (partly copied from ledger.vim 0.0.1) @@ -19,7 +19,7 @@ endif " for debugging syntax clear -" region: a normal transaction +" region: a normal posting syn region transNorm start=/^\d/ skip=/^\s/ end=/^/ fold keepend transparent contains=transDate syn match transDate /^\d\S\+/ contained syn match Comment /^;.*$/ @@ -27,7 +27,7 @@ syn match Comment /^;.*$/ highlight default link Comment SpecialKey highlight default link transDate Question -" folding: how to represent a transaction in one line. +" folding: how to represent a posting in one line. function! LedgerFoldText() let line = strpart(getline(v:foldstart), 0, 99) " get the amount at the end of the second line @@ -48,7 +48,7 @@ endfunction set foldtext=LedgerFoldText() set foldmethod=syntax -" syncinc is easy: search for the first transaction. +" syncinc is easy: search for the first posting. syn sync clear syn sync match ledgerSync grouphere transNorm "^\d" @@ -6,47 +6,44 @@ Introduction ============ -Ledger is an accounting program which is invoked from the command-line -using a textual ledger file. To start using Ledger, you will need to -create such a file containing your financial transactions. A sample -has been provided in the file "sample.dat". See the documentation -(ledger.pdf, or ledger.info) for full documentation on creating a -ledger file and using Ledger to generate reports. +Ledger is an accounting program which is invoked from the command-line using a +textual ledger file. To start using Ledger, you will need to create such a +file containing your financial postings. A sample has been provided in the +file "sample.dat". See the documentation (ledger.pdf, or ledger.info) for +full documentation on creating a ledger file and using Ledger to generate +reports. -Once you have such a file -- you might call it "ledger.dat" -- you can -start looking at balances and account registers using commands like -the following: +Once you have such a file -- you might call it "ledger.dat" -- you can start +looking at balances and account registers using commands like the following: ledger -f ledger.dat balance assets:checking ledger -f ledger.dat register expenses:food -This assumes, of course, that like the sample file you use account -names such as "Assets:Checking" and "Expenses:Food". If you use other -account names, you will need to vary the reporting commands you use -accordingly. +This assumes, of course, that like the sample file you use account names such +as "Assets:Checking" and "Expenses:Food". If you use other account names, you +will need to vary the reporting commands you use accordingly. Building ======== -To build Ledger, you will need a fairly modern C++ compiler (gcc 2.95 -will not work), and at least these two libraries installed: +To build Ledger, you will need a fairly modern C++ compiler (gcc 2.95 will not +work), and at least these two libraries installed: gmp GNU multi-precision library pcre Perl regular expression library -(On some GNU/Linux systems, the packages you need to install are -called "gmp-dev" and "pcre-dev"). +(On some GNU/Linux systems, the packages you need to install are called +"gmp-dev" and "pcre-dev"). Once you have determined where the headers and libraries for the above -packages are installed, run the script "configure", passing those -paths. If you installed everything under /usr/local, you can probably -just type "./configure". Otherwise, do this: +packages are installed, run the script "configure", passing those paths. If +you installed everything under /usr/local, you can probably just type +"./configure". Otherwise, do this: ./configure CPPFLAGS=-I<INCLUDE-PATH> LDFLAGS=-L<LIBRARY-PATH> -If you need to specify multiple include or library paths, then do -this: +If you need to specify multiple include or library paths, then do this: ./configure CPPFLAGS="-I<PATH1> -I<PATH2>" LDFLAGS="-L<PATH1> -L<PATH2>" @@ -58,8 +55,8 @@ Once configure is done running, just type: Mailing List and IRC ==================== -If you need help on how to use Ledger, or run into problems, you can -join the Ledger mailing list at the following Web address: +If you need help on how to use Ledger, or run into problems, you can join the +Ledger mailing list at the following Web address: http://groups.google.com/group/ledger-cli diff --git a/doc/grammar.y b/doc/grammar.y index fd58cd01..018e7391 100644 --- a/doc/grammar.y +++ b/doc/grammar.y @@ -24,7 +24,7 @@ * INT1 -- a one digit wide number * * Except for 1) the 'spacer' production (see below), 2) EOL, and 3) the - * WHITESPACE required to begin a transaction, whitespace is otherwise + * WHITESPACE required to begin a posting, whitespace is otherwise * ignored. * * Yes, this grammar is confusing and not so happy for machine readers, @@ -36,7 +36,7 @@ /* * Journals * - * A journal is a file which primarily contains entries, among other elements. + * A journal is a file which primarily contains xacts, among other elements. */ journal: @@ -47,7 +47,7 @@ journal: journal_item: whitespace directive | - entry | + xact | ; whitespace: @@ -83,7 +83,7 @@ char_directive: 'D' amount | /* sets display parameters for a commodity */ 'A' TEXT | /* sets the "default balancing account" */ 'C' commodity '=' amount | /* specifies a commodity conversion */ - 'P' date time commodity amount | /* a pricing history entry */ + 'P' date time commodity amount | /* a pricing history xact */ 'N' commodity | /* commodity's price is never downloaded */ 'Y' INT4 | /* sets the default year for date parsing */ '-' '-' STRING TEXT | /* specify command-line options in the file */ @@ -100,20 +100,20 @@ commodity: STRING ; /* - * Entries + * Xacts * - * Entries are the atomic units of accounting, which are composed of - * multiple transactions between accounts, so long as it all balances in + * Xacts are the atomic units of accounting, which are composed of + * multiple postings between accounts, so long as it all balances in * the end. */ -entry: plain_entry | - periodic_entry | - automated_entry ; +xact: plain_xact | + periodic_xact | + automated_xact ; -plain_entry: +plain_xact: date date_opt status_opt code_opt FULLSTRING note_opt EOL - transactions ; + postings ; status_opt: status | /* epsilon */ ; status: '*' | '!' | /* epsilon */ ; @@ -128,9 +128,9 @@ note: ';' TEXT ; /* ---------------------------------------------------------------------- */ -periodic_entry: +periodic_xact: '~' period_expr note_opt EOL - transaction transactions ; + posting postings ; /* * A period expression has its own sub-grammar, which I don't quite have @@ -142,9 +142,9 @@ period_expr: FULLSTRING ; /* ---------------------------------------------------------------------- */ -automated_entry: +automated_xact: '=' value_expr note_opt EOL - transaction transactions ; + posting postings ; /* * Value expressions are a algebraic math expressions very similar to @@ -183,21 +183,21 @@ amount: amount_expr: amount | value_expr ; /* - * Transactions + * Postings * - * Transactions are the fundamental unit of accounting, and represent + * Postings are the fundamental unit of accounting, and represent * the movement of commodities to or from an account. Thus, paying off - * your credit card consists of two balancing transactions: one that + * your credit card consists of two balancing postings: one that * withdraws money from your checking account, and another which pays * money to your credit institution. */ -transactions: - transaction transactions | +postings: + posting postings | /* epsilon */ ; -transaction: +posting: WHITESPACE status_opt account values_opt note_opt EOL; account_name: FULLSTRING ; diff --git a/doc/ledger.1 b/doc/ledger.1 index 5598ee8e..8e9e42ff 100644 --- a/doc/ledger.1 +++ b/doc/ledger.1 @@ -60,7 +60,6 @@ are also accepted. The synonym .Nm lisp is also accepted. -.It Nm entry Oo Ar date Oc .It Nm equity Oo Ar query Oc .It Nm prices Oo Ar query Oc .It Nm pricesdb Oo Ar query Oc @@ -73,6 +72,10 @@ and are also accepted. .It Nm reload Used solely by the +.It Nm xact Oo Ar date Oc +The synonym +.Nm entry +is also accepted. .Tn REPL , and causes an immediate reloading of all journal files in the session. .It Nm stats Oo Ar query Oc @@ -190,7 +193,7 @@ appeared in the original journal file. .It Fl \-set-price Ar EXPR .It Fl \-sort Ar EXPR Pq Fl S .It Fl \-sort-all -.It Fl \-sort-entries +.It Fl \-sort-xacts .It Fl \-start-of-week Ar STR .It Fl \-strict .It Fl \-subtotal Pq Fl s @@ -238,7 +241,7 @@ Query on the payee, rather than the account. .It Nm note Ar regex Pq \&= Ns Ar regex Query on anything found in an item's note. .It Nm code Ar regex Pq \&# Ns Ar regex -Query on the entry's optional code (which can be any string the user wishes). +Query on the xact's optional code (which can be any string the user wishes). .It Ar term Nm and Ar term Query terms are joined by an implicit OR operator. You can change this to AND by using that keyword. For example, to show food expenditures occurring at @@ -294,7 +297,6 @@ for example: .It Nm display_total .It Nm end_line .It Nm end_pos -.It Nm entry .It Nm filename .It Nm format_date .It Nm has_meta @@ -307,6 +309,7 @@ for example: .It Nm partial_account .It Nm payee .It Nm pending +.It Nm post .It Nm print .It Nm quantity .It Nm quoted diff --git a/doc/ledger.texi b/doc/ledger.texi index 8279f4c9..a95a381b 100644 --- a/doc/ledger.texi +++ b/doc/ledger.texi @@ -95,7 +95,7 @@ company's name. The ultimate aim of keeping a checkbook ledger is to know how much money is available to spend. That's really the aim of all ledgers. -What computers add is the ability to walk through these transactions, +What computers add is the ability to walk through these postings, and tell you things about your spending habits; to let you devise budgets and get control over your spending; to squirrel away money into virtual savings account without having to physically move money @@ -109,7 +109,7 @@ of all your accounts, not just checking. In such a ledger, you record not only who gets paid---in the case of a debit---but where the money came from. In a checkbook ledger, its assumed that all the money comes from your checking account. But in a general ledger, you write -transaction two-lines: the source account and target account. +posting two-lines: the source account and target account. @emph{There must always be a debit from at least one account for every credit made to another account}. This is what is meant by ``double-entry'' accounting: the ledger must always balance to zero, @@ -122,7 +122,7 @@ general ledger you need to record a payment to Pacific Bell for your monthly phone bill. The cost is $23.00, let's say, and you want to pay it from your checking account. In the general ledger you need to say where the money came from, in addition to where it's going to. -The entry might look like this: +The transaction might look like this: @smallexample 9/29 BAL Pacific Bell $-200.00 $-200.00 @@ -137,17 +137,17 @@ The first line shows a payment to Pacific Bell for $23.00. Because there is no ``balance'' in a general ledger---it's always zero---we write in the total balance of all payments to ``Pacific Bell'', which now is $223.00 (previously the balance was $200.00). This is done by -looking at the last entry for ``Pacific Bell'' in the ledger, adding +looking at the last transaction for ``Pacific Bell'' in the ledger, adding $23.00 to that amount, and writing the total in the balance column. And the money came from ``Checking''---a withdrawal of $23.00---which leaves the ending balance in ``Checking'' at $77.00. This is a very manual procedure; but that's where computers come in... -The transaction must balance to $0: $23 went to Pacific Bell, $23 came +The posting must balance to $0: $23 went to Pacific Bell, $23 came from Checking. There is nothing left over to be accounted for, since the money has simply moved from one account to another. This is the basis of double-entry accounting: that money never pops in or out of -existence; it is always a transaction from one account to another. +existence; it is always a posting from one account to another. Keeping a general ledger is the same as keeping two separate ledgers: One for Pacific Bell and one for Checking. In that case, each time a @@ -160,16 +160,16 @@ deal with multiple accounts. Enter the beauty of computerized accounting. The purpose of the Ledger program is to make general ledger accounting simple, by keeping track of the balances for you. Your only job is to enter the -transactions. If a transaction does not balance, Ledger displays an -error and indicates the incorrect transaction.@footnote{In some -special cases, it automatically balances this entry for you.} +postings. If a posting does not balance, Ledger displays an +error and indicates the incorrect posting.@footnote{In some +special cases, it automatically balances this transaction for you.} In summary, there are two aspects of Ledger use: updating the ledger data file, and using the Ledger tool to view the summarized result of -your entries. +your transactions. And just for the sake of example---as a starting point for those who -want to dive in head-first---here are the ledger entries from above, +want to dive in head-first---here are the ledger transactions from above, formatting as the ledger program wishes to see them: @smallexample @@ -203,7 +203,7 @@ mathematically tricks you need to better understand your spending patterns. Without a good ledger, no tool, however smart, can help you. -The Ledger program aims at making ledger entry as simple as possible. +The Ledger program aims at making ledger transaction as simple as possible. Since it is a command-line tool, it does not provide a user interface for keeping a ledger. If you like, you may use GnuCash to maintain your ledger, in which case the Ledger program will read GnuCash's data @@ -211,21 +211,21 @@ files directly. In that case, read the GnuCash manual now, and skip to the next chapter. If you are not using GnuCash, but a text editor to maintain your -ledger, read on. Ledger has been designed to make data entry as +ledger, read on. Ledger has been designed to make data transaction as simple as possible, by keeping the ledger format easy, and also by automagically determining as much information as possible based on the -nature of your entries. +nature of your transactions. For example, you do not need to tell Ledger about the accounts you -use. Any time Ledger sees a transaction involving an account it knows +use. Any time Ledger sees a posting involving an account it knows nothing about, it will create it. If you use a commodity that is new to Ledger, it will create that commodity, and determine its display characteristics (placement of the symbol before or after the amount, display precision, etc) based on how you used the commodity in the -transaction. +posting. Here is the Pacific Bell example from above, given as a Ledger -transaction: +posting: @smallexample 9/29 (100) Pacific Bell @@ -245,8 +245,8 @@ amount, if it is the same as the first line: Assets:Checking @end smallexample -For this entry, Ledger will figure out that $-23.00 must come from -@samp{Assets:Checking} in order to balance the entry. +For this transaction, Ledger will figure out that $-23.00 must come from +@samp{Assets:Checking} in order to balance the transaction. @section Building the program @@ -293,12 +293,12 @@ ledger [OPTIONS...] COMMAND [ARGS...] Command options must always precede the command word. After the command word there may appear any number of arguments. For most commands, these arguments are regular expressions that cause the -output to relate only to transactions matching those regular -expressions. For the @command{entry} command, the arguments have a +output to relate only to postings matching those regular +expressions. For the @command{transaction} command, the arguments have a special meaning, described below. The regular expressions arguments always match the account name that a -transaction refers to. To match on the payee of the entry instead, +posting refers to. To match on the payee of the transaction instead, precede the regular expression with @samp{--}. For example, the following balance command reports account totals for rent, food and movies, but only those whose payee matches Freddie: @@ -334,12 +334,12 @@ separately. @subsection register -The @command{register} command displays all the transactions occurring +The @command{register} command displays all the postings occurring in a single account, line by line. The account regexp must be specified as the only argument to this command. If any regexps occur after the required account name, the register will contain only those -transactions that match. Very useful for hunting down a particular -transaction. +postings that match. Very useful for hunting down a particular +posting. The output from @command{register} is very close to what a typical checkbook, or single-account ledger, would look like. It also shows a @@ -354,11 +354,11 @@ order to plot either the amount or total column, respectively. @subsection print -The @command{print} command prints out ledger entries in a textual +The @command{print} command prints out ledger transactions in a textual format that can be parsed by Ledger. They will be properly formatted, and output in the most economic form possible. The ``print'' command also takes a list of optional regexps, which will cause only those -transactions which match in some way to be printed. +postings which match in some way to be printed. The @command{print} command can be a handy way to clean up a ledger file whose formatting has gotten out of hand. @@ -367,15 +367,15 @@ file whose formatting has gotten out of hand. The @command{output} command is very similar to the @command{print} command, except that it attempts to replicate the specified ledger -file exactly. The format of the command is: +file epostly. The format of the command is: @example ledger -f FILENAME output FILENAME @end example Where @file{FILENAME} is the name of the ledger file to output. The -reason for specifying this command is that only entries contained -within that file will be output, and not an included entries (as can +reason for specifying this command is that only transactions contained +within that file will be output, and not an included transactions (as can happen with the @command{print} command). @subsection xml @@ -384,7 +384,7 @@ The @command{xml} command outputs results similar to what @command{print} and @command{register} display, but as an XML form. This data can then be read in and processed. Use the @option{--totals} option to include the running total with each -transaction. +posting. @subsection emacs @@ -393,14 +393,14 @@ directly by Emacs Lisp. The format of the sexp is: @example ((BEG-POS CLEARED DATE CODE PAYEE - (ACCOUNT AMOUNT)...) ; list of transactions - ...) ; list of entries + (ACCOUNT AMOUNT)...) ; list of postings + ...) ; list of transactions @end example @subsection equity The @command{equity} command prints out accounts balances as if they -were entries. This makes it easy to establish the starting balances +were transactions. This makes it easy to establish the starting balances for an account, such as when @ref{Archiving previous years}. @subsection prices @@ -414,13 +414,13 @@ There is also a @command{pricesdb} command which outputs the same information as @command{prices}, but does in a format that can be parsed by Ledger. -@subsection entry +@subsection xact -The @command{entry} commands simplifies the creation of new entries. -It works on the principle that 80% of all transactions are variants of -earlier transactions. Here's how it works: +The @command{xact} commands simplifies the creation of new transactions. +It works on the principle that 80% of all postings are variants of +earlier postings. Here's how it works: -Say you currently have this transaction in your ledger file: +Say you currently have this posting in your ledger file: @smallexample 2004/03/15 * Viva Italiano @@ -430,11 +430,11 @@ Say you currently have this transaction in your ledger file: @end smallexample Now it's @samp{2004/4/9}, and you've just eating at @samp{Viva -Italiano} again. The exact amounts are different, but the overall -form is the same. With the @command{entry} command you can type: +Italiano} again. The epost amounts are different, but the overall +form is the same. With the @command{xact} command you can type: @example -ledger entry 2004/4/9 viva food 11 tips 2.50 +ledger xact 2004/4/9 viva food 11 tips 2.50 @end example This produces the following output: @@ -446,27 +446,27 @@ This produces the following output: Liabilities:MasterCard $-13.50 @end smallexample -It works by finding a past transaction matching the regular expression +It works by finding a past posting matching the regular expression @samp{viva}, and assuming that any accounts or amounts specified will -be similar to that earlier transaction. If Ledger does not succeed in -generating a new entry, an error is printed and the exit code is set +be similar to that earlier posting. If Ledger does not succeed in +generating a new transaction, an error is printed and the exit code is set to @samp{1}. There is a shell script in the distribution's @file{scripts} directory -called @file{entry}, which simplifies the task of adding a new entry -to your ledger. It launches @command{vi} to confirm that the entry +called @file{xact}, which simplifies the task of adding a new transaction +to your ledger. It launches @command{vi} to confirm that the transaction looks appropriate. -Here are a few more examples of the @command{entry} command, assuming -the above journal entry: +Here are a few more examples of the @command{xact} command, assuming +the above journal transaction: @example -ledger entry 4/9 viva 11.50 -ledger entry 4/9 viva 11.50 checking # (from `checking') -ledger entry 4/9 viva food 11.50 tips 8 -ledger entry 4/9 viva food 11.50 tips 8 cash -ledger entry 4/9 viva food $11.50 tips $8 cash -ledger entry 4/9 viva dining "DM 11.50" +ledger xact 4/9 viva 11.50 +ledger xact 4/9 viva 11.50 checking # (from `checking') +ledger xact 4/9 viva food 11.50 tips 8 +ledger xact 4/9 viva food 11.50 tips 8 cash +ledger xact 4/9 viva food $11.50 tips $8 cash +ledger xact 4/9 viva dining "DM 11.50" @end example @node Options, Period expressions, Commands, Quick Reference @@ -513,7 +513,7 @@ output. @option{--init-file FILE} (@option{-i FILE}) causes FILE to be read by ledger before any other ledger file. This file may not contain any -transactions, but it may contain option settings. To specify options +postings, but it may contain option settings. To specify options in the init file, use the same syntax as the command-line. Here's an example init file: @@ -536,36 +536,36 @@ putting the option into your init file. The @option{--no-cache} option causes Ledger to always ignore the binary cache. @option{--account NAME} (@option{-a NAME}) specifies the default -account which QIF file transactions are assumed to relate to. +account which QIF file postings are assumed to relate to. @subsection Report filtering -These options change which transactions affect the outcome of a +These options change which postings affect the outcome of a report, in ways other than just using regular expressions: -@option{--current}(@option{-c}) displays only entries occurring on or +@option{--current}(@option{-c}) displays only transactions occurring on or before the current date. @option{--begin DATE} (@option{-b DATE}) constrains the report to -entries on or after @var{DATE}. Only entries after that date will be +transactions on or after @var{DATE}. Only transactions after that date will be calculated, which means that the running total in the balance report -will always start at zero with the first matching entry. (Note: This +will always start at zero with the first matching transaction. (Note: This is different from using @option{--display} to constrain what is displayed). @option{--end DATE} (@option{-e DATE}) constrains the report so that -entries on or after @var{DATE} are not considered. The ending date +transactions on or after @var{DATE} are not considered. The ending date is inclusive. @option{--period STR} (@option{-p STR}) sets the reporting period -to @var{STR}. This will subtotal all matching entries within each +to @var{STR}. This will subtotal all matching transactions within each period separately, making it easy to see weekly, monthly, quarterly, -etc., transaction totals. A period string can even specify the +etc., posting totals. A period string can even specify the beginning and end of the report range, using simple terms like ``last june'' or ``next month''. For more using period expressions, see @ref{Period expressions}. -@option{--period-sort EXPR} sorts the transactions within each +@option{--period-sort EXPR} sorts the postings within each reporting period using the value expression @var{EXPR}. This is most often useful when reporting monthly expenses, in order to view the highest expense categories at the top of each month: @@ -574,28 +574,28 @@ highest expense categories at the top of each month: ledger -M --period-sort -At reg ^Expenses @end example -@option{--cleared} (@option{-C}) displays only transactions whose entry +@option{--cleared} (@option{-C}) displays only postings whose transaction has been marked ``cleared'' (by placing an asterix to the right of the date). -@option{--uncleared} (@option{-U}) displays only transactions whose -entry has not been marked ``cleared'' (i.e., if there is no asterix to +@option{--uncleared} (@option{-U}) displays only postings whose +transaction has not been marked ``cleared'' (i.e., if there is no asterix to the right of the date). -@option{--real} (@option{-R}) displays only real transactions, not -virtual. (A virtual transaction is indicated by surrounding the +@option{--real} (@option{-R}) displays only real postings, not +virtual. (A virtual posting is indicated by surrounding the account name with parentheses or brackets; see the section on using -virtual transactions for more information). +virtual postings for more information). -@option{--actual} (@option{-L}) displays only actual transactions, and -not those created due to automated transactions. +@option{--actual} (@option{-L}) displays only actual postings, and +not those created due to automated postings. -@option{--related} (@option{-r}) displays transactions that are -related to whichever transactions would otherwise have matched the +@option{--related} (@option{-r}) displays postings that are +related to whichever postings would otherwise have matched the filtering criteria. In the register report, this shows where money went to, or the account it came from. In the balance report, it shows -all the accounts affected by entries having a related transaction. -For example, if a file had this entry: +all the accounts affected by transactions having a related posting. +For example, if a file had this transaction: @smallexample 2004/03/20 Safeway @@ -610,22 +610,22 @@ And the register command was: ledger -r register food @end example -The following would be output, showing the transactions related to the -transaction that matched: +The following would be output, showing the postings related to the +posting that matched: @smallexample 2004/03/20 Safeway Expenses:Cash $-20.00 $-20.00 Assets:Checking $85.00 $65.00 @end smallexample -@option{--budget} is useful for displaying how close your transactions +@option{--budget} is useful for displaying how close your postings meet your budget. @option{--add-budget} also shows unbudgeted -transactions, while @option{--unbudgeted} shows only those. +postings, while @option{--unbudgeted} shows only those. @option{--forecast} is a related option that projects your budget into the future, showing how it will affect future balances. @xref{Budgeting and forecasting}. -@option{--limit EXPR} (@option{-l EXPR}) limits which transactions +@option{--limit EXPR} (@option{-l EXPR}) limits which postings take part in the calculations of a report. @option{--amount EXPR} (@option{-t EXPR}) changes the value expression @@ -640,35 +640,35 @@ used for the ``totals'' column in the @command{register} and @subsection Output customization -These options affect only the output, but not which transactions are +These options affect only the output, but not which postings are used to create it: -@option{--collapse} (@option{-n}) causes entries in a -@command{register} report with multiple transactions to be collapsed -into a single, subtotaled entry. +@option{--collapse} (@option{-n}) causes transactions in a +@command{register} report with multiple postings to be collapsed +into a single, subtotaled transaction. -@option{--subtotal} (@option{-s}) causes all entries in a +@option{--subtotal} (@option{-s}) causes all transactions in a @command{register} report to be collapsed into a single, subtotaled -entry. +transaction. @option{--by-payee} (@option{-P}) reports subtotals by payee. @option{--comm-as-payee} (@option{-x}) changes the payee of every -transaction to be the commodity used in that transaction. This can be +posting to be the commodity used in that posting. This can be useful when combined with other options, such as @option{-s}. @option{--empty} (@option{-E}) includes even empty accounts in the @command{balance} report. -@option{--weekly} (@option{-W}) reports transaction totals by the +@option{--weekly} (@option{-W}) reports posting totals by the week. The week begins on whichever day of the week begins the month -containing that transaction. To set a specific begin date, use a +containing that posting. To set a specific begin date, use a period string, such as @samp{weekly from DATE}. @option{--monthly} -(@option{-M}) reports transaction totals by month; @option{--yearly} -(@option{-Y}) reports transaction totals by year. For more complex +(@option{-M}) reports posting totals by month; @option{--yearly} +(@option{-Y}) reports posting totals by year. For more complex period, using the @option{--period} option described above. -@option{--dow} reports transactions totals for each day of the week. +@option{--dow} reports postings totals for each day of the week. This is an easy way to see if weekend spending is more than on weekdays. @@ -682,12 +682,12 @@ expressions}. @option{--wide} (@option{-w}) causes the default @command{register} report to assume 132 columns instead of 80. -@option{--head} causes only the first N entries to be printed. This +@option{--head} causes only the first N transactions to be printed. This is different from using the command-line utility @command{head}, which -would limit to the first N transactions. @option{--tail} outputs only -the last N entries. Both options may be used simultaneously. If a +would limit to the first N postings. @option{--tail} outputs only +the last N transactions. Both options may be used simultaneously. If a negative amount is given, it will invert the meaning of the flag -(instead of the first five entries being printed, for example, it +(instead of the first five transactions being printed, for example, it would print all but the first five). @option{--pager} tells Ledger to pass its output to the given pager @@ -695,10 +695,10 @@ program---very useful when the output is especially long. This behavior can be made the default by setting the @env{LEDGER_PAGER} environment variable. -@option{--average} (@option{-A}) reports the average transaction +@option{--average} (@option{-A}) reports the average posting value. -@option{--deviation} (@option{-D}) reports each transaction's +@option{--deviation} (@option{-D}) reports each posting's deviation from the average. It is only meaningful in the @command{register} and @command{prices} reports. @@ -718,19 +718,19 @@ programs, which could plot the date, analyze it, etc. report so that it output nothing but the date and totals column, without commodities. -@option{--display EXPR} (@option{-d EXPR}) limits which transactions +@option{--display EXPR} (@option{-d EXPR}) limits which postings or accounts or actually displayed in a report. They might still be calculated, and be part of the running total of a register report, for example, but they will not be displayed. This is useful for seeing -last month's checking transactions, against a running balance which -includes all transaction values: +last month's checking postings, against a running balance which +includes all posting values: @example ledger -d "d>=[last month]" reg checking @end example The output from this command is very different from the following, -whose running total includes only transactions from the last month +whose running total includes only postings from the last month onward: @example @@ -805,13 +805,13 @@ users basic reporting needs: Reports commodity totals (this is the default) @item -B, --basis -Reports the cost basis for all transactions. +Reports the cost basis for all postings. @item -V, --market Reports the last known market value for all commodities. @item -g, --performance -Reports the net gain/loss for each transaction in a @command{register} +Reports the net gain/loss for each posting in a @command{register} report. @item -G --gain @@ -929,7 +929,7 @@ Format strings may be used to change the output format of reports. They are specified by passing a formatting string to the @option{--format} (@option{-F}) option. Within that string, constructs are allowed which make it possible to display the various -parts of an account or transaction in custom ways. +parts of an account or posting in custom ways. Within a format strings, a substitution is specified using a percent character (@samp{%}). The basic format of all substitutions is: @@ -946,7 +946,7 @@ width is given, the substituted text will never be wider than this, and will be truncated to fit. Here are some examples: @example -%-P An entry's payee, left justified +%-P a transaction's payee, left justified %20P The same, right justified, at least 20 chars wide %.20P The same, no more than 20 chars wide %-.20P Left justified, maximum twenty chars wide @@ -989,24 +989,24 @@ the five first in that expression, so that the commodity doesn't get stripped from the total. @item [DATEFMT] -Inserts the result of formatting a transaction's date with a date -format string, exactly like those supported by @code{strftime}. For +Inserts the result of formatting a posting's date with a date +format string, epostly like those supported by @code{strftime}. For example: @samp{%[%Y/%m/%d %H:%M:%S]}. @item S -Insert the pathname of the file from which the entry's data was read. +Insert the pathname of the file from which the transaction's data was read. @item B -Inserts the beginning character position of that entry within the file. +Inserts the beginning character position of that transaction within the file. @item b -Inserts the beginning line of that entry within the file. +Inserts the beginning line of that transaction within the file. @item E -Inserts the ending character position of that entry within the file. +Inserts the ending character position of that transaction within the file. @item e -Inserts the ending line of that entry within the file. +Inserts the ending line of that transaction within the file. @item D By default, this is the same as @samp{%[%Y/%m%/d]}. The date format @@ -1015,24 +1015,24 @@ 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 +This is the same as the @samp{%D} option, unless the transaction 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 +If a posting has been cleared, this inserts @samp{*} followed by a space; otherwise nothing is inserted. @item Y This is the same as @samp{%X}, except that it only displays a state -character if all of the member transactions have the same state. +character if all of the member postings have the same state. @item C -Inserts the checking number for an entry, in parentheses, followed by +Inserts the checking number for a transaction, in parentheses, followed by a space; if none was specified, nothing is inserted. @item P -Inserts the payee related to a transaction. +Inserts the payee related to a posting. @item a Inserts the optimal short name for an account. This is normally used @@ -1044,30 +1044,30 @@ Inserts the full name of an account. @item W This is the same as @samp{%A}, except that it first displays the -transaction's state @emph{if the entry's transaction states are not +posting's state @emph{if the transaction's posting states are not all the same}, followed by the full account name. This is offered as a printing optimization, so that combined with @samp{%Y}, only the minimum amount of state detail is printed. @item o -Inserts the ``optimized'' form of a transaction's amount. This is +Inserts the ``optimized'' form of a posting's amount. This is used by the print report. In some cases, this inserts nothing; in -others, it inserts the transaction amount and its cost. It's use is +others, it inserts the posting amount and its cost. It's use is not recommend unless you are modifying the print report. @item n -Inserts the note associated with a transaction, preceded by two spaces +Inserts the note associated with a posting, preceded by two spaces and a semi-colon, if it exists. Thus, no none becomes an empty string, while the note @samp{foo} is substituted as @samp{ ; foo}. @item N -Inserts the note associated with a transaction, if one exists. +Inserts the note associated with a posting, if one exists. @item / The @samp{%/} construct is special. It separates a format string -between what is printed for the first transaction of an entry, and -what is printed for all subsequent transactions. If not used, the -same format string is used for all transactions. +between what is printed for the first posting of a transaction, and +what is printed for all subsequent postings. If not used, the +same format string is used for all postings. @end table @node Value expressions, File format, Format strings, Quick Reference @@ -1081,11 +1081,11 @@ calculate values used by the program for many different purposes: The values displayed in reports @item For predicates (where truth is anything non-zero), to determine which -transactions are calculated (@option{-l}) or displayed (@option{-d}). +postings are calculated (@option{-l}) or displayed (@option{-d}). @item For sorting criteria, to yield the sort key. @item -In the matching criteria used by automated transactions. +In the matching criteria used by automated postings. @end enumerate Value expressions support most simple math and logic operators, in @@ -1104,18 +1104,18 @@ contains. If it contains multiple commodities, only one of them must exceed 100 units. Display predicates are also very handy with register reports, to -constrain which entries are printed. For example, the following -command shows only entries from the beginning of the current month, -while still calculating the running balance based on all entries: +constrain which transactions are printed. For example, the following +command shows only transactions from the beginning of the current month, +while still calculating the running balance based on all transactions: @example ledger -d "d>[this month]" register checking @end example This advantage to this command's complexity is that it prints the -running total in terms of all entries in the register. The following, +running total in terms of all transactions in the register. The following, simpler command is similar, but totals only the displayed -transactions: +postings: @example ledger -b "this month" register checking @@ -1125,8 +1125,8 @@ ledger -b "this month" register checking Below are the one letter variables available in any value expression. For the register and print commands, these variables relate to -individual transactions, and sometimes the account affected by a -transaction. For the balance command, these variables relate to +individual postings, and sometimes the account affected by a +posting. For the balance command, these variables relate to accounts---often with a subtle difference in meaning. The use of each variable for both is specified. @@ -1147,26 +1147,26 @@ not specified, the current report style's value expression is used. This is always the present moment/date. @end table -@subsubsection Transaction/account details +@subsubsection Posting/account details @table @code @item d -A transaction's date, as the number of seconds past the epoch. This +A posting's date, as the number of seconds past the epoch. This is always ``today'' for an account. @item a -The transaction's amount; the balance of an account, without +The posting's amount; the balance of an account, without considering children. @item b -The cost of a transaction; the cost of an account, without its +The cost of a posting; the cost of an account, without its children. @item v -The market value of a transaction, or an account without its children. +The market value of a posting, or an account without its children. @item g -The net gain (market value minus cost basis), for a transaction or an +The net gain (market value minus cost basis), for a posting or an account without its children. It is the same as @samp{v-b}. @item l @@ -1174,41 +1174,41 @@ The depth (``level'') of an account. If an account has one parent, it's depth is one. @item n -The index of a transaction, or the count of transactions affecting an +The index of a posting, or the count of postings affecting an account. @item X -1 if a transaction's entry has been cleared, 0 otherwise. +1 if a posting's transaction has been cleared, 0 otherwise. @item R -1 if a transaction is not virtual, 0 otherwise. +1 if a posting is not virtual, 0 otherwise. @item Z -1 if a transaction is not automated, 0 otherwise. +1 if a posting is not automated, 0 otherwise. @end table @subsubsection Calculated totals @table @code @item O -The total of all transactions seen so far, or the total of an account +The total of all postings seen so far, or the total of an account and all its children. @item N -The total count of transactions affecting an account and all its +The total count of postings affecting an account and all its children. @item B -The total cost of all transactions seen so far; the total cost of an +The total cost of all postings seen so far; the total cost of an account and all its children. @item V -The market value of all transactions seen so far, or of an account and +The market value of all postings seen so far, or of an account and all its children. @item G The total net gain (market value minus cost basis), for a series of -transactions, or an account and its children. It is the same as +postings, or an account and its children. It is the same as @samp{V-B}. @end table @@ -1262,25 +1262,25 @@ with or without a commodity. Use this for decimal values. @item /REGEXP/ @item W/REGEXP/ A regular expression that matches against an account's full name. If -a transaction, this will match against the account affected by the -transaction. +a posting, this will match against the account affected by the +posting. @item //REGEXP/ @item p/REGEXP/ -A regular expression that matches against an entry's payee name. +A regular expression that matches against a transaction's payee name. @item ///REGEXP/ @item w/REGEXP/ A regular expression that matches against an account's base name. If -a transaction, this will match against the account affected by the -transaction. +a posting, this will match against the account affected by the +posting. @item c/REGEXP/ -A regular expression that matches against the entry code (the text +A regular expression that matches against the transaction code (the text that occurs between parentheses before the payee name). @item e/REGEXP/ -A regular expression that matches against a transaction's note, or +A regular expression that matches against a posting's note, or comment field. @item (EXPR) @@ -1305,52 +1305,52 @@ how it should be interpreted. Allowable initial characters are: @table @code @item NUMBER -A line beginning with a number denotes an entry. It may be followed +A line beginning with a number denotes a transaction. It may be followed by any number of lines, each beginning with whitespace, to denote the -entry's account transactions. The format of the first line is: +transaction's account postings. The format of the first line is: @example 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 +indicates the transaction 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 +the transaction 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. +of the posting. Following these is the payee, or a description of +the posting. -The format of each following transaction is: +The format of each following posting 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 +postings, or square brackets if it is a virtual postings 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 +posting cost, by specifying @samp{@@ AMOUNT}, or a complete +posting cost with @samp{@@@@ AMOUNT}. Lastly, the @samp{NOTE} may +specify an actual and/or effective date for the posting 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 +An automated transaction. A value expression must appear after the equal sign. After this initial line there should be a set of one or more -transactions, just as if it were normal entry. If the amounts of the -transactions have no commodity, they will be applied as modifiers to -whichever real transaction is matched by the value expression. +postings, just as if it were normal transaction. If the amounts of the +postings have no commodity, they will be applied as modifiers to +whichever real posting is matched by the value expression. @item ~ -A period entry. A period expression must appear after the tilde. +A period transaction. A period expression must appear after the tilde. After this initial line there should be a set of one or more -transactions, just as if it were normal entry. +postings, just as if it were normal transaction. @item ! A line beginning with an exclamation mark denotes a command directive. @@ -1363,7 +1363,7 @@ Include the stated ledger file. @item !account The account name is given is taken to be the parent of all -transactions that follow, until @samp{!end} is seen. +postings that follow, until @samp{!end} is seen. @item !end Ends an account block. @@ -1374,10 +1374,10 @@ A line beginning with a colon indicates a comment, and is ignored. @item Y If a line begins with a capital Y, it denotes the year used for all -subsequent entries that give a date without a year. The year should +subsequent transactions that give a date without a year. The year should appear immediately after the Y, for example: @samp{Y2004}. This is useful at the beginning of a file, to specify the year for that file. -If all entries specify a year, however, this command has no effect. +If all transactions specify a year, however, this command has no effect. @item P Specifies a historical price for a commodity. These are usually found @@ -1399,7 +1399,7 @@ N SYMBOL @item D AMOUNT Specifies the default commodity to use, by specifying an amount in the -expected format. The @command{entry} command will use this commodity +expected format. The @command{transaction} command will use this commodity as the default when none other can be determined. This command may be used multiple times, to set the default flags for different commodities; whichever is seen last is used as the default commodity. @@ -1498,13 +1498,13 @@ We can see that in @samp{Assets} there is $1,480.00, and 50 shares of Apple stock. There is also a negative grand total. Usually the grand total is zero, which means that all accounts balance@footnote{It is impossible for accounts not to balance in ledger; it reports an error -if a transaction does not balance}. In this case, since the 50 shares +if a posting does not balance}. In this case, since the 50 shares of Apple stock cost $1,500.00 dollars, then these two amounts balance each other in the grand total. The extra $2.00 comes from a virtual -transaction being added by the automatic entry at the top of the file. -The entry is virtual because the account name was surrounded by -parentheses in an automatic entry. Automatic entries will be -discussed later, but first let's remove the virtual transaction from +posting being added by the automatic transaction at the top of the file. +The transaction is virtual because the account name was surrounded by +parentheses in an automatic transaction. Automatic transactions will be +discussed later, but first let's remove the virtual posting from the balance report by using the @option{--real} option: @example @@ -1524,7 +1524,7 @@ Now the report is: 50 AAPL @end smallexample -Since the liability was a virtual transaction, it has dropped from the +Since the liability was a virtual posting, it has dropped from the report and we see that final total is balanced. But we only know that it balances because @file{sample.dat} is quite @@ -1550,7 +1550,7 @@ With the basis cost option, the grand total has disappeared, as it is now zero. The confirms that the cost of everything balances to zero, @emph{which must always be true}. Reporting the real basis cost should never yield a remainder@footnote{If it ever does, then -generated transactions are involved, which can be removed using +generated postings are involved, which can be removed using @option{--actual}}. @subsection Sub-account balances @@ -1664,10 +1664,10 @@ account totals, by far the most powerful of Ledger's reporting tools is the @command{register} command. In fact, internally both commands use the same logic, but report the results differently: @command{balance} shows the summary totals, while @command{register} -reports each transaction and how it contributes to that total. +reports each posting and how it contributes to that total. Paradoxically, the most basic form of @command{register} is almost -never used, since it displays every transaction: +never used, since it displays every posting: @example ledger reg @@ -1698,7 +1698,7 @@ reports: 50 AAPL @end smallexample -This rather verbose output shows every account transaction in +This rather verbose output shows every account posting in @file{sample.dat}, and how it affects the running total. The final total is identical to what we saw with the plain @command{balance} command. To see how things really balance, we can use @samp{--real @@ -1728,7 +1728,7 @@ Here we see that everything balances to zero in the end, as it must. @subsection Specific register queries The most common use of the register command is to summarize -transactions based on the account(s) they affect. Using +postings based on the account(s) they affect. Using @file{sample.dat} as as example, we could look at all book purchases using: @@ -1756,39 +1756,39 @@ Reports: 2004/05/29 Credit card company Liabilities:MasterCard $20.00 $20.00 @end smallexample -There are many reporting options for tailoring which transactions are +There are many reporting options for tailoring which postings are found, and also how to summarize the various amounts and totals that result. These are plumbed in greater depth below. -@section Selecting transactions +@section Selecting postings Although the easiest way to use the register is to report all the -transactions affecting a set of accounts, it can often result in more +postings affecting a set of accounts, it can often result in more information than you want. To cope with an ever-growing amount of data, there are several options which can help you pinpoint your -report to exactly the transactions that interest you most. This is +report to epostly the postings that interest you most. This is called the ``calculation'' phase of Ledger. All of its related options are documented under @option{--help-calc}. @subsection By date -@c -c, --current show only current and past entries (not future) +@c -c, --current show only current and past transactions (not future) -@option{--current}(@option{-c}) displays entries occurring on or -before the current date. Any entry recorded for a future date will be +@option{--current}(@option{-c}) displays transactions occurring on or +before the current date. Any transaction recorded for a future date will be ignored, as if it had not been seen. This is useful if you happen to -pre-record entries, but still wish to view your balances in terms of +pre-record transactions, but still wish to view your balances in terms of what is available today. @c -b, --begin DATE set report begin date @c -e, --end DATE set report end date @option{--begin DATE} (@option{-b DATE}) limits the report to only -those entries occurring on or after @var{DATE}. The running total in -the register will start at zero with the first transaction, even if -there are earlier entries. +those transactions occurring on or after @var{DATE}. The running total in +the register will start at zero with the first posting, even if +there are earlier transactions. -To limit the display only, but still add earlier transactions to the +To limit the display only, but still add earlier postings to the running total, use the display expression @samp{-d 'd>=[DATE]'}): @example @@ -1802,7 +1802,7 @@ Reports: 2004/05/27 Credit card company Assets:Bank:Checking $-20.00 $2,980.00 @end smallexample -In this example, the displayed transactions start from @samp{5/14}, +In this example, the displayed postings start from @samp{5/14}, but the calculated total starts from the beginning of @samp{may}. @option{--end DATE} (@option{-e DATE}) states when reporting should @@ -1822,7 +1822,7 @@ ledger -b "last month" bal @end example @c -p, --period STR report using the given period -@c --period-sort EXPR sort each report period's entries by EXPR +@c --period-sort EXPR sort each report period's transactions by EXPR To constrain the report to a specific time period, use @option{--period} (@option{-p}). A time period may have both a @@ -1855,61 +1855,61 @@ This command is identical to: ledger -p "monthly in 2004" reg ^expenses @end example -The transactions within a period may be sorted using +The postings within a period may be sorted using @option{--period-sort}, which takes a value expression. This is similar to the @option{--sort} option, except that it sorts within -each period entry, rather than sorting all transactions in the report. +each period transaction, rather than sorting all postings in the report. See the documentation on @option{--sort} below for more details. @subsection By status -By default, all regular transactions are included in each report. To -limit the report to certain kinds of transactions, use one or more of +By default, all regular postings are included in each report. To +limit the report to certain kinds of postings, use one or more of the following options: @table @option @item -C, --cleared -Consider only cleared transactions. +Consider only cleared postings. @item -U, --uncleared -Consider only uncleared and pending transactions. +Consider only uncleared and pending postings. @item -R, --real -Consider only real (non-virtual) transactions. +Consider only real (non-virtual) postings. @item -L, --actual -Consider only actual (non-automated) transactions. +Consider only actual (non-automated) postings. @end table -Cleared transactions are indicated by an asterix placed just before -the payee name in a transaction. The meaning of this flag is up to -the user, but typically it means that an entry has been seen on a -financial statement. Pending transactions use an exclamation mark in +Cleared postings are indicated by an asterix placed just before +the payee name in a posting. The meaning of this flag is up to +the user, but typically it means that a transaction has been seen on a +financial statement. Pending postings use an exclamation mark in the same position, but are mainly used only by reconciling software. -Uncleared transactions are for things like uncashed checks, credit +Uncleared postings are for things like uncashed checks, credit charges that haven't appeared on a statement yet, etc. -Real transactions are all non-virtual transactions, where the account +Real postings are all non-virtual postings, where the account name is not surrounded by parentheses or square brackets. Virtual -transactions are useful for showing a transfer of money that never +postings are useful for showing a transfer of money that never really happened, like money set aside for savings without actually transferring it from the parent account. -Actual transactions are those not generated, either as part of an -automated entry, or a budget or forecast report. A useful of when you -might like to filter out generated transactions is with a budget: +Actual postings are those not generated, either as part of an +automated transaction, or a budget or forecast report. A useful of when you +might like to filter out generated postings is with a budget: @example ledger --budget --actual reg ^expenses @end example -This command outputs all transactions affecting a budgeted account, +This command outputs all postings affecting a budgeted account, but without subtracting the budget amount (because the generated -transactions are suppressed with @option{--actual}). The report shows +postings are suppressed with @option{--actual}). The report shows how much you actually spent on budgeted items. @subsection By relationship -@c -r, --related calculate report using related transactions +@c -r, --related calculate report using related postings -Normally, a register report includes only the transactions that match +Normally, a register report includes only the postings that match the regular expressions specified after the command word. For example, to report all expenses: @@ -1923,8 +1923,8 @@ This reports: 2004/05/29 Book Store Expenses:Books $20.00 $20.00 @end smallexample -Using @option{--related} (@option{-r}) reports the transactions that -did not match your query, but only in entries that otherwise would +Using @option{--related} (@option{-r}) reports the postings that +did not match your query, but only in transactions that otherwise would have matched. This has the effect of indicating where money came from, or when to: @@ -1940,12 +1940,12 @@ Reports: @subsection By budget -@c --budget generate budget entries based on FILE +@c --budget generate budget transactions based on FILE There is more information about budgeting and forecasting in @ref{Budgeting and forecasting}. Basically, if you have any period -entries in your ledger file, you can use these options. A period -entry looks like: +transactions in your ledger file, you can use these options. A period +transaction looks like: @example ~ Monthly @@ -1953,13 +1953,13 @@ entry looks like: Income:Salary @end example -The difference from a regular entry is that the first line begins with +The difference from a regular transaction is that the first line begins with a tilde (~), and instead of a payee there's a period expression -(@ref{Period expressions}). Otherwise, a period entry is in every -other way the same as a regular entry. +(@ref{Period expressions}). Otherwise, a period transaction is in every +other way the same as a regular transaction. -With such an entry in your ledger file, the @option{--budget} option -will report only transactions that match a budgeted account. Using +With such a transaction in your ledger file, the @option{--budget} option +will report only postings that match a budgeted account. Using @file{sample.dat} from above: @example @@ -1969,36 +1969,36 @@ ledger --budget reg ^income Reports: @smallexample -2004/05/01 Budget entry Income:Salary $500.00 $500.00 +2004/05/01 Budget transaction Income:Salary $500.00 $500.00 2004/05/14 Pay day Income:Salary $-500.00 0 @end smallexample -The final total is zero, indicating that the budget matched exactly +The final total is zero, indicating that the budget matched epostly for the reported period. Budgeting is most often helpful with period reporting; for example, to show monthly budget results use @option{--budget -p monthly}. -@c --add-budget show all transactions plus the budget -@c --unbudgeted show only unbudgeted transactions +@c --add-budget show all postings plus the budget +@c --unbudgeted show only unbudgeted postings -The @option{--add-budget} option reports all matching transactions in -addition to budget transactions; while @option{--unbudgeted} shows +The @option{--add-budget} option reports all matching postings in +addition to budget postings; while @option{--unbudgeted} shows only those that don't match a budgeted account. To summarize: @table @option @item --budget -Show transactions matching budgeted accounts. +Show postings matching budgeted accounts. @item --unbudgeted -Show transactions matching unbudgeted accounts. +Show postings matching unbudgeted accounts. @item --add-budget -Show both budgeted and unbudgeted transactions together (i.e., add the -generated budget transactions to the regular report). +Show both budgeted and unbudgeted postings together (i.e., add the +generated budget postings to the regular report). @end table -@c --forecast EXPR generate forecast entries while EXPR is true +@c --forecast EXPR generate forecast transactions while EXPR is true A report with the @option{--forecast} option will add budgeted -transactions while the specified value expression is true. For +postings while the specified value expression is true. For example: @example @@ -2009,14 +2009,14 @@ Reports: @smallexample 2004/05/14 Pay day Income:Salary $-500.00 $-500.00 -2004/12/01 Forecast entry Income:Salary $-500.00 $-1,000.00 -2005/01/01 Forecast entry Income:Salary $-500.00 $-1,500.00 +2004/12/01 Forecast transaction Income:Salary $-500.00 $-1,000.00 +2005/01/01 Forecast transaction Income:Salary $-500.00 $-1,500.00 @end smallexample The date this report was made was November 5, 2004; the reason the -first forecast entry is in december is that forecast entries are only +first forecast transaction is in december is that forecast transactions are only added for the future, and they only stop after the value expression -has matched at least once, which is why the January entry appears. A +has matched at least once, which is why the January transaction appears. A forecast report can be very useful for determining when money will run out in an account, or for projecting future cash flow: @@ -2040,7 +2040,7 @@ of the above command (in November 2004) is: @subsection By value expression -@c -l, --limit EXPR calculate only transactions matching EXPR +@c -l, --limit EXPR calculate only postings matching EXPR Value expressions can be quite complex, and are treated more fully in @ref{Value expressions}. They can be used for limiting a report with @@ -2054,8 +2054,8 @@ ledger -l '(/income/&d>=[aug])|(/expenses/&d>=[oct])' reg The basic form of this value expression is @samp{(A&B)|(A&B)}. The @samp{A} in each part matches against an account name with @samp{/name/}, while each @samp{B} part compares the date of the -transaction (@samp{d}) with a specified month. The resulting report -will contain only transactions which match the value expression. +posting (@samp{d}) with a specified month. The resulting report +will contain only postings which match the value expression. @c -t, --amount EXPR use EXPR to calculate the displayed amount @c -T, --total EXPR use EXPR to calculate the displayed total @@ -2063,14 +2063,14 @@ will contain only transactions which match the value expression. Another use of value expressions is to calculate the amount reported for each line of a register report, or for computing the subtotal of each account shown in a balance report. This example divides each -transaction amount by two: +posting amount by two: @example ledger -t 'a/2' reg ^exp @end example The @option{-t} option doesn't affect the running total, only how the -transaction amount is displayed. To change the running total, use +posting amount is displayed. To change the running total, use @option{-T}. In that case, you will likely want to use the total (@samp{O}) instead of the amount (@samp{a}): @@ -2080,8 +2080,8 @@ ledger -T 'O/2' reg ^exp @section Massaging register output -Even after filtering down your data to just the transactions you're -interested in, the default reporting method of one transaction per +Even after filtering down your data to just the postings you're +interested in, the default reporting method of one posting per line is often still too much. To combat this complexity, it is possible to ask Ledger to report the details to you in many different forms, summarized in various ways. This is the ``display'' phase of @@ -2089,10 +2089,10 @@ Ledger, and is documented under @option{--help-disp}. @subsection Summarizing -@c -n, --collapse register: collapse entries with multiple transactions +@c -n, --collapse register: collapse transactions with multiple postings -When multiple transactions relate to a single entry, they are reported -as part of that entry. For example, in the case of @file{sample.dat}: +When multiple postings relate to a single transaction, they are reported +as part of that transaction. For example, in the case of @file{sample.dat}: @example ledger reg -- book @@ -2106,9 +2106,9 @@ Reports: (Liabilities:Taxes) $-2.00 $-2.00 @end smallexample -All three transactions are part of one entry, and as such the entry -details are printed only once. To report every entry on a single -line, use @option{-n} to collapse entries with multiple transactions: +All three postings are part of one transaction, and as such the transaction +details are printed only once. To report every transaction on a single +line, use @option{-n} to collapse transactions with multiple postings: @example ledger -n reg -- book @@ -2149,18 +2149,18 @@ But if the @option{-s} option is added, the result becomes: Assets:Brokerage $1,500.00 $2,980.00 @end smallexample -When account subtotaling is used, only one entry is printed, and the -date and name reflect the range of the combined transactions. +When account subtotaling is used, only one transaction is printed, and the +date and name reflect the range of the combined postings. @c -P, --by-payee show summarized totals by payee -With @option{-P}, transactions relating to the same payee are -combined. In this case, the date of the combined entry is that of the -latest transaction. +With @option{-P}, postings relating to the same payee are +combined. In this case, the date of the combined transaction is that of the +latest posting. @c -x, --comm-as-payee set commodity name as the payee, for reporting -@option{-x} changes the payee name for each transaction to be the same +@option{-x} changes the payee name for each posting to be the same as the commodity it uses. This can be especially useful combined with other options, like @option{-P}. For example: @@ -2230,7 +2230,7 @@ Reports: @c -S, --sort EXPR sort report according to the value expression EXPR -The transactions displayed in a report are shown in the same order as +The postings displayed in a report are shown in the same order as they appear in the ledger file. To change the order and sort a report, use the @option{--sort} option. @option{--sort} takes a value expression to determine the value to sort against, making it possible @@ -2253,7 +2253,7 @@ ledger --sort -T reg ^exp # reverse sort by amount total ledger --sort UT reg ^exp # sort by abs amount total @end example -The @option{--sort} options sorts all transactions in a report. If +The @option{--sort} options sorts all postings in a report. If periods are used (such as @option{--monthly}), this can get somewhat confusing. In that case, you'll probably want to sort within periods using @option{--period-sort} instead of @option{--sort}. @@ -2266,10 +2266,10 @@ acolumns, instead of 80. You are more likely then to see full payee and account names, as well as properly formatted totals when long-named commodities are used. -If you want only the first or last N entries to be printed---which can -be very useful for viewing the last 10 entries in your checking +If you want only the first or last N transactions to be printed---which can +be very useful for viewing the last 10 transactions in your checking account, while also showing the cumulative balance from all -entries---use the @option{--head} and/or @option{--tail} options. The +transactions---use the @option{--head} and/or @option{--tail} options. The two options may be used simultaneously, for example: @example @@ -2285,11 +2285,11 @@ ledger --pager /usr/bin/less reg checking @subsection Averages and percentages -@c -A, --average report average transaction amount +@c -A, --average report average posting amount To see the running total changed to a running average, use -@option{-A}. The final transaction's total will be the overall -average of all displayed transactions. The works in conjunction with +@option{-A}. The final posting's total will be the overall +average of all displayed postings. The works in conjunction with period reporting, so that you can see your monthly average expenses with: @@ -2332,7 +2332,7 @@ ledger -%s -S T bal ^expenses @c --totals in the "xml" report, include running total -Normally in the @command{xml} report, only transaction amounts are +Normally in the @command{xml} report, only posting amounts are printed. To include the running total under a @samp{<total>} tag, use @option{--totals}. This does not affect any other report. @@ -2347,9 +2347,9 @@ to Gnuplot. To show only the date and running total, use @option{-J}. @subsection Display by value expression -@c -d, --display EXPR display only transactions matching EXPR +@c -d, --display EXPR display only postings matching EXPR -With @option{-d} you can decide which transactions (or accounts in the +With @option{-d} you can decide which postings (or accounts in the balance report) are displayed, according to a value expression. The computed total is not affected, only the display. This can be very useful for shortening a report without changing the running total: @@ -2512,7 +2512,7 @@ ledger balance expenses -food @section Reporting percentages -There is no built-in way to report transaction amounts or account +There is no built-in way to report posting amounts or account balances in terms of percentages @node Ledger in Practice, , Ledger Tutorial, Top @@ -2529,8 +2529,8 @@ balances in terms of percentages * Dealing with Petty Cash:: * Working with multiple funds and accounts:: * Archiving previous years:: -* Virtual transactions:: -* Automated transactions:: +* Virtual postings:: +* Automated postings:: * Using Emacs to Keep Your Ledger:: * Using GnuCash to Keep Your Ledger:: * Using timeclock to record billable time:: @@ -2545,12 +2545,12 @@ is often different from the layman's understanding. To avoid confusion, Ledger uses only subtractions and additions, although the underlying intent is the same as standard accounting principles. -Recall that every transaction will involve two or more accounts. +Recall that every posting will involve two or more accounts. Money is transferred from one or more accounts to one or more other -accounts. To record the transaction, an amount is @emph{subtracted} +accounts. To record the posting, an amount is @emph{subtracted} from the source accounts, and @emph{added} to the target accounts. -In order to write a Ledger entry correctly, you must determine where +In order to write a Ledger transaction correctly, you must determine where the money comes from and where it goes to. For example, when you are paid a salary, you must add money to your bank account and also subtract it from an income account: @@ -2594,7 +2594,7 @@ Assets are money that you have, and Liabilities are money that you owe. ``Liabilities'' is just a more inclusive name for Debts. An Asset is typically increased by transferring money from an Income -account, such as when you get paid. Here is a typical entry: +account, such as when you get paid. Here is a typical transaction: @smallexample 2004/09/29 My Employer @@ -2692,11 +2692,11 @@ need to track two separate things: 1) The fact that the money should be reimbursed to you, and 2) What the expense account was, so that you can later determine where your company is spending its money. -This kind of transaction is best handled with mirrored transactions in +This kind of posting is best handled with mirrored postings in two different files, one for your personal accounts, and one for your company accounts. But keeping them in one file involves the same -kinds of transactions, so those are what is shown here. First, the -personal entry, which shows the need for reimbursement: +kinds of postings, so those are what is shown here. First, the +personal transaction, which shows the need for reimbursement: @smallexample 2004/09/29 Circuit City @@ -2705,8 +2705,8 @@ personal entry, which shows the need for reimbursement: @end smallexample This is the same as above, except that you own Company XYZ, and are -keeping track of its expenses in the same ledger file. This entry -should be immediately followed by an equivalent entry, which shows the +keeping track of its expenses in the same ledger file. This transaction +should be immediately followed by an equivalent transaction, which shows the kind of expense, and also notes the fact that $100.00 is now payable to you: @@ -2716,11 +2716,11 @@ to you: Company XYZ:Accounts Payable:Your Name @end smallexample -This second entry shows that Company XYZ has just spent $100.00 on +This second transaction shows that Company XYZ has just spent $100.00 on software, and that this $100.00 came from Your Name, which must be paid back. -These two entries can also be merged, to make things a little clearer. +These two transactions can also be merged, to make things a little clearer. Note that all amounts must be specified now: @smallexample @@ -2759,12 +2759,12 @@ generate accurate reports of your company's expenditures. It is more verbose than just paying for things with your personal assets, but it gives you a very accurate information trail. -The advantage to keep these doubled entries together is that they +The advantage to keep these doubled transactions together is that they always stay in sync. The advantage to keeping them apart is that it -clarifies the transfer's point of view. To keep the transactions in -separate files, just separate the two entries that were joined above. +clarifies the transfer's point of view. To keep the postings in +separate files, just separate the two transactions that were joined above. For example, for both the expense and the pay-back shown above, the -following four entries would be created. Two in your personal ledger +following four transactions would be created. Two in your personal ledger file: @smallexample @@ -2797,7 +2797,7 @@ And two in your company ledger file: the file are children of that account. In this case it means that all activity in the file relates to Company XYZ). -After creating these entries, you will always know that $100.00 was +After creating these transactions, you will always know that $100.00 was spent using your MasterCard on behalf of Company XYZ, and that Company XYZ spent the money on computer software and paid it back about two weeks later. @@ -2812,7 +2812,7 @@ October, sorted by total: ledger -b "last oct" -s -S T bal ^expenses @end example -From left to right the options mean: Show entries since October, 2003; +From left to right the options mean: Show transactions since October, 2003; show all sub-accounts; sort by the absolute value of the total; and report the balance for all expenses. @@ -2827,7 +2827,7 @@ ledger -M --period-sort t reg ^expenses Now, you might wonder where the money came from to pay for these things. To see that report, add @option{-r}, which shows the -``related account'' transactions: +``related account'' postings: @example ledger -M --period-sort t -r reg ^expenses @@ -2835,8 +2835,8 @@ ledger -M --period-sort t -r reg ^expenses But maybe this prints too much information. You might just want to see how much you're spending with your MasterCard. That kind of query -requires the use of a display predicate, since the transactions -calculated must match @samp{^expenses}, while the transactions +requires the use of a display predicate, since the postings +calculated must match @samp{^expenses}, while the postings displayed must match @samp{mastercard}. The command would be: @example @@ -2844,9 +2844,9 @@ ledger -M -r -d /mastercard/ reg ^expenses @end example This query says: Report monthly subtotals; report the ``related -account'' transactions; display only related transactions whose +account'' postings; display only related postings whose account matches @samp{mastercard}, and base the calculation on -transactions matching @samp{^expenses}. +postings matching @samp{^expenses}. This works just as well for report the overall total, too: @@ -2854,7 +2854,7 @@ This works just as well for report the overall total, too: ledger -s -r -d /mastercard/ reg ^expenses @end example -The @option{-s} option subtotals all transactions, just as @option{-M} +The @option{-s} option subtotals all postings, just as @option{-M} subtotaled by the month. The running total in both cases is off, however, since a display expression is being used. @@ -2888,7 +2888,7 @@ report -j -M reg ^expenses # monthly expenses report -J reg checking # checking account balance report -J reg ^income ^expenses # cash flow report -# net worth report, ignoring non-$ transactions +# net worth report, ignoring non-$ postings report -J -l "Ua>=@{\$0.01@}" reg ^assets ^liab @@ -2901,10 +2901,10 @@ report -J -l "Ua>=@{\$0.01@}" -d "d>=[last feb]" reg ^assets ^liab The last report uses both a calculation predicate (@option{-l}) and a display predicate (@option{-d}). The calculation predicates limits -the report to transactions whose amount is greater than $1 (which can -only happen if the transaction amount is in dollars). The display -predicate limits the entries @emph{displayed} to just those since last -February, even those entries from before then will be computed as part +the report to postings whose amount is greater than $1 (which can +only happen if the posting amount is in dollars). The display +predicate limits the transactions @emph{displayed} to just those since last +February, even those transactions from before then will be computed as part of the balance. @node Budgeting and forecasting, Commodities and Currencies, Typical queries, Ledger in Practice @@ -2916,8 +2916,8 @@ Keeping a budget allows you to pay closer attention to your income and expenses, by reporting how far your actual financial activity is from your expectations. -To start keeping a budget, put some period entries at the top of your -ledger file. A period entry is almost identical to a regular entry, +To start keeping a budget, put some period transactions at the top of your +ledger file. A period transaction is almost identical to a regular transaction, except that it begins with a tilde and has a period expression in place of a payee. For example: @@ -2938,7 +2938,7 @@ place of a payee. For example: Assets @end smallexample -These two period entries give the usual monthly expenses, as well as +These two period transactions give the usual monthly expenses, as well as one typical yearly expense. For help on finding out what your average monthly expense is for any category, use a command like: @@ -2948,7 +2948,7 @@ ledger -p "this year" -MAs bal ^expenses The reported totals are the current year's average for each account. -Once these period entries are defined, creating a budget report is as +Once these period transactions are defined, creating a budget report is as easy as adding @option{--budget} to the command-line. For example, a typical monthly expense report would be: @@ -2977,15 +2977,15 @@ You can also use these flags with the @command{balance} command. Sometimes it's useful to know what your finances will look like in the future, such as determining when an account will reach zero. Ledger -makes this easy to do, using the same period entries as are used for +makes this easy to do, using the same period transactions as are used for budgeting. An example forecast report can be generated with: @example ledger --forecast "T>@{\$-500.00@}" register ^assets ^liabilities @end example -This report continues outputting transactions until the running total -is greater than $-500.00. A final transaction is always output, to +This report continues outputting postings until the running total +is greater than $-500.00. A final posting is always output, to show you what the total afterwards would be. Forecasting can also be used with the balance report, but by date @@ -3093,7 +3093,7 @@ Whenever a commodity is purchased using a different commodity (such as a share of common stock using dollars), it establishes a price for that commodity on that day. It is also possible, by recording price details in a ledger file, to specify other prices for commodities at -any given time. Such price entries might look like those below: +any given time. Such price transactions might look like those below: @smallexample P 2004/06/21 02:17:58 TWCUX $27.76 @@ -3115,7 +3115,7 @@ example of this is time. Whether tracked in terms of minutes, hours or days, it should be possible to convert between the various forms. Doing this requires the use of commodity equivalencies. -For example, you might have the following two transactions, one which +For example, you might have the following two postings, one which transfers an hour of time into a @samp{Billable} account, and another which decreases the same account by ten minutes. The resulting report will indicate that fifty minutes remain: @@ -3187,7 +3187,7 @@ acquired them online. The only purpose for choosing one kind of source account over another is for generate more informative reports later on. The more you know, the better analysis you can perform. -If you later sell some of these items to another player, the entry +If you later sell some of these items to another player, the transaction would look like: @smallexample @@ -3202,12 +3202,12 @@ Sturm Brightblade. @node Understanding Equity, Dealing with Petty Cash, Accounts and Inventories, Ledger in Practice @section Understanding Equity -The most confusing entry in any ledger will be your equity account--- +The most confusing transaction in any ledger will be your equity account--- because starting balances can't come out of nowhere. When you first start your ledger, you will likely already have money in some of your accounts. Let's say there's $100 in your checking -account; then add an entry to your ledger to reflect this amount. +account; then add a transaction to your ledger to reflect this amount. Where will money come from? The answer: your equity. @smallexample @@ -3243,7 +3243,7 @@ confusing figure from the total. Something that stops many people from keeping a ledger at all is the insanity of tracking small cash expenses. They rarely generate a -receipt, and there are often a lot of small transactions, rather than +receipt, and there are often a lot of small postings, rather than a few large ones, as with checks. One solution is: don't bother. Move your spending to a debit card, @@ -3308,7 +3308,7 @@ should reflect the same overall expenses and cash flow. It's simply where the money resides that differs. This situation can be handled one of two ways. The first is using -virtual transactions to represent the fact that money is moving to and +virtual postings to represent the fact that money is moving to and from two kind of accounts at the same time: @smallexample @@ -3322,8 +3322,8 @@ from two kind of accounts at the same time: [Assets:Checking] $-500.00 @end smallexample -The use of square brackets in the second entry ensures that the -virtual transactions balance to zero. Now money can be spent directly +The use of square brackets in the second transaction ensures that the +virtual postings balance to zero. Now money can be spent directly from a fund at the same time as money is drawn from a physical account: @@ -3350,7 +3350,7 @@ the real accounts: ledger --real bal @end example -If more asset accounts are needed as the source of a transaction, just +If more asset accounts are needed as the source of a posting, just list them as you would normally, for example: @smallexample @@ -3361,10 +3361,10 @@ list them as you would normally, for example: (Funds:School) $-100.00 @end smallexample -The second way of tracking funds is to use entry codes. In this +The second way of tracking funds is to use transaction codes. In this respect the codes become like virtual accounts that embrace the entire -set of transactions. Basically, we are associating an entry with a -fund by setting its code. Here are two entries that desposit money +set of postings. Basically, we are associating a transaction with a +fund by setting its code. Here are two transactions that desposit money into, and spend money from, the @samp{Funds:School} fund: @smallexample @@ -3378,15 +3378,15 @@ into, and spend money from, the @samp{Funds:School} fund: @end smallexample Note how the accounts now relate only to the real accounts, and any -balance or registers reports will reflect this. That the entries +balance or registers reports will reflect this. That the transactions relate to a particular fund is kept only in the code. How does this become a fund report? By using the @option{--code-as-payee} option, you can generate a register report -where the payee for each transaction shows the code. Alone, this is +where the payee for each posting shows the code. Alone, this is not terribly interesting; but when combined with the @option{--by-payee} option, you will now see account subtotals for any -transactions related to a specific fund. So, to see the current +postings related to a specific fund. So, to see the current monetary balances of all funds, the command would be: @smallexample @@ -3402,10 +3402,10 @@ ledger --code-as-payee -P reg ^Expenses -- School Both approaches yield different kinds of flexibility, depending on how you prefer to think of your funds: as virtual accounts, or as tags -associated with particular entries. Your own tastes will decide which +associated with particular transactions. Your own tastes will decide which is best for your situation. -@node Archiving previous years, Virtual transactions, Working with multiple funds and accounts, Ledger in Practice +@node Archiving previous years, Virtual postings, Working with multiple funds and accounts, Ledger in Practice @section Archiving previous years After a while, your ledger can get to be pretty large. While this @@ -3422,7 +3422,7 @@ that make it very simple: @command{print}, and @command{equity}. Let's take an example file, with data ranging from year 2000 until 2004. We want to archive years 2000 and 2001 to their own file, leaving just 2003 and 2004 in the current file. So, use -@command{print} to output all the earlier entries to a file called +@command{print} to output all the earlier transactions to a file called @file{ledger-old.dat}: @smallexample @@ -3437,7 +3437,7 @@ ledger -f ledger.dat -b 2002 print > x mv x ledger.dat @end example -However, now the current file contains @emph{only} transactions from +However, now the current file contains @emph{only} postings from 2002 onward, which will not yield accurate present-day balances, because the net income from previous years is no longer being tallied. To compensate for this, we must append an equity report for the old @@ -3465,18 +3465,18 @@ any electronic statements received during the year. In the arena of organization, just keep in mind this maxim: Do whatever keeps you doing it. -@node Virtual transactions, Automated transactions, Archiving previous years, Ledger in Practice -@section Virtual transactions +@node Virtual postings, Automated postings, Archiving previous years, Ledger in Practice +@section Virtual postings -A virtual transaction is when you, in your mind, see money as moving +A virtual posting is when you, in your mind, see money as moving to a certain place, when in reality that money has not moved at all. There are several scenarios in which this type of tracking comes in handy, and each of them will be discussed in detail. -To enter a virtual transaction, surround the account name in +To enter a virtual posting, surround the account name in parentheses. This form of usage does not need to balance. However, -if you want to ensure the virtual transaction balances with other -virtual transactions in the same entry, use square brackets. For +if you want to ensure the virtual posting balances with other +virtual postings in the same transaction, use square brackets. For example: @smallexample @@ -3502,40 +3502,40 @@ for a trip. It will appear as though the money has been moved from the account into @samp{Savings:Trip}, although no money has actually moved anywhere. -When balances are displayed, virtual transactions will be factored in. +When balances are displayed, virtual postings will be factored in. To view balances without any virtual balances factored in, using the @option{-R} flag, for ``reality''. -@node Automated transactions, Using Emacs to Keep Your Ledger, Virtual transactions, Ledger in Practice -@section Automated transactions +@node Automated postings, Using Emacs to Keep Your Ledger, Virtual postings, Ledger in Practice +@section Automated postings As a Bahá'Ã, I need to compute Huqúqu'lláh whenever I acquire assets. It is similar to tithing for Jews and Christians, or to Zakát for -Muslims. The exact details of computing Huqúqu'lláh are somewhat +Muslims. The epost details of computing Huqúqu'lláh are somewhat complex, but if you have further interest, please consult the Web. Ledger makes this otherwise difficult law very easy. Just set up an -automated transaction at the top of your ledger file: +automated posting at the top of your ledger file: @smallexample -; This automated entry will compute Huqúqu'lláh based on this -; journal's transactions. Any that match will affect the +; This automated transaction will compute Huqúqu'lláh based on this +; journal's postings. Any that match will affect the ; Liabilities:Huququ'llah account by 19% of the value of that -; transaction. +; posting. = /^(?:Income:|Expenses:(?:Business|Rent$|Furnishings|Taxes|Insurance))/ (Liabilities:Huququ'llah) 0.19 @end smallexample -This automated transaction works by looking at each transaction in the +This automated posting works by looking at each posting in the ledger file. If any match the given value expression, 19% of the -transaction's value is applied to the @samp{Liabilities:Huququ'llah} +posting's value is applied to the @samp{Liabilities:Huququ'llah} account. So, if $1000 is earned from @samp{Income:Salary}, $190 is added to @samp{Liabilities:Huqúqu'lláh}; if $1000 is spent on Rent, $190 is subtracted. The ultimate balance of Huqúqu'lláh reflects how much is owed in order to fulfill one's obligation to Huqúqu'lláh. When ready to pay, just write a check to cover the amount shown in -@samp{Liabilities:Huququ'llah}. That entry would look like: +@samp{Liabilities:Huququ'llah}. That transaction would look like: @smallexample 2003/01/01 (101) Baha'i Huqúqu'lláh Trust @@ -3544,7 +3544,7 @@ When ready to pay, just write a check to cover the amount shown in @end smallexample That's it. To see how much Huqúq is currently owed based on your -ledger entries, use: +ledger transactions, use: @example ledger balance Liabilities:Huquq @@ -3571,7 +3571,7 @@ ledger -Q -T "/Liab.*Huquq/?(O/P@{2.22 AU@}<=@{-1.0@}&O):O" -s bal liab @end smallexample In some cases, you may wish to refer to the account of whichever -transaction matched your automated entry's value expression. To do +posting matched your automated transaction's value expression. To do this, use the special account name @samp{$account}: @smallexample @@ -3581,10 +3581,10 @@ this, use the special account name @samp{$account}: @end smallexample This example causes 10% of the matching account's total to be deferred -to the @samp{Savings} account---as a balanced virtual transaction, +to the @samp{Savings} account---as a balanced virtual posting, which may be excluded from reports by using @option{--real}. -@node Using Emacs to Keep Your Ledger, Using GnuCash to Keep Your Ledger, Automated transactions, Ledger in Practice +@node Using Emacs to Keep Your Ledger, Using GnuCash to Keep Your Ledger, Automated postings, Ledger in Practice @section Using Emacs to Keep Your Ledger In the Ledger tarball is an Emacs module, @file{ledger.el}. This @@ -3607,31 +3607,31 @@ Now when you edit your ledger file, it will be in @table @strong @item C-c C-a -For quickly adding new entries based on the form of older ones (see +For quickly adding new transactions based on the form of older ones (see previous section). @item C-c C-c -Toggles the ``cleared'' flag of the transaction under point. +Toggles the ``cleared'' flag of the posting under point. @item C-c C-d -Delete the entry under point. +Delete the transaction under point. @item C-c C-r -Reconciles an account by displaying the transactions in another +Reconciles an account by displaying the postings in another buffer, where simply hitting the spacebar will toggle the pending flag -of the transaction in the ledger. Once all the appropriate -transactions have been marked, press C-c C-c in the reconcile buffer -to ``commit'' the reconciliation, which will mark all of the entries +of the posting in the ledger. Once all the appropriate +postings have been marked, press C-c C-c in the reconcile buffer +to ``commit'' the reconciliation, which will mark all of the transactions as cleared, and display the new cleared balance in the minibuffer. @item C-c C-m -Set the default month for new entries added with C-c C-a. This is -handy if you have a large number of transactions to enter from a +Set the default month for new transactions added with C-c C-a. This is +handy if you have a large number of postings to enter from a previous month. @item C-c C-y -Set the default year for new entries added with C-c C-a. This is -handy if you have a large number of transactions to enter from a +Set the default year for new transactions added with C-c C-a. This is +handy if you have a large number of postings to enter from a previous year. @end table @@ -3640,28 +3640,28 @@ available: @table @strong @item RET -Visit the ledger file entry corresponding to the reconcile entry. +Visit the ledger file transaction corresponding to the reconcile transaction. @item C-c C-c -Commit the reconcialation. This marks all of the marked transactions +Commit the reconcialation. This marks all of the marked postings as ``cleared'', saves the ledger file, and then displays the new cleared balance. @item C-l -Refresh the reconcile buffer by re-reading transactions from the +Refresh the reconcile buffer by re-reading postings from the ledger data file. @item SPC -Toggle the transaction under point as cleared. +Toggle the posting under point as cleared. @item a -Add a new entry to the ledger data file, and refresh the reconcile -buffer to include its transactions (if the entry is added to the same +Add a new transaction to the ledger data file, and refresh the reconcile +buffer to include its postings (if the transaction is added to the same account as the one being reconciled). @item d -Delete the entry related to the transaction under point. Note: This -may result in multiple transactions being deleted. +Delete the transaction related to the posting under point. Note: This +may result in multiple postings being deleted. @item n Move to the next line. @@ -3671,8 +3671,8 @@ Move to the previous line. @item C-c C-r @item r -Attempt to auto-reconcile the transactions to the entered balance. If -it can do so, it will mark all those transactions as pending that +Attempt to auto-reconcile the postings to the entered balance. If +it can do so, it will mark all those postings as pending that would yield the specified balance. @item C-x C-s @@ -3713,7 +3713,7 @@ timelog file. Each in/out event may have an optional description. If the ``in'' description is a ledger account name, these in/out pairs may be viewed -as virtual transactions, adding time commodities (hours) to that +as virtual postings, adding time commodities (hours) to that account. For example, the command-line version of the timeclock tool could be @@ -3733,7 +3733,7 @@ i 2004/10/06 15:21:00 ClientOne category o 2004/10/06 15:21:10 waited for ten seconds @end smallexample -Ledger parses this directly, as if it had seen the following entry: +Ledger parses this directly, as if it had seen the following transaction: @smallexample 2004/10/06 category @@ -3751,7 +3751,7 @@ to accounts receivable: ClientOne -0.00277h @@ $35.00 @end smallexample -The above transaction converts the clocked time into an invoice for +The above posting converts the clocked time into an invoice for the time spent, at an hourly rate of $35. Once the invoice is paid, the money is deposited from the receivable account into a checking account: @@ -3766,7 +3766,7 @@ And now the time spent has been turned into hard cash in the checking account. The advantage to using timeclock and invoicing to bill time is that -you will always know, by looking at the balance report, exactly how +you will always know, by looking at the balance report, epostly how much unbilled and unpaid time you've spent working for any particular client. @@ -3784,7 +3784,7 @@ accounting ledger, with the attached prefix @samp{Billable}: !include /home/johnw/.timelog !end -; Here follows this fiscal year's transactions for the company. +; Here follows this fiscal year's postings for the company. 2004/11/01 (INV#1) ClientOne, Inc. Receivable:ClientOne $0.10 @@ -3808,47 +3808,47 @@ The general format used for Ledger data is: @smallexample <?xml version="1.0"?> <ledger> - <entry>...</entry> - <entry>...</entry> - <entry>...</entry>... + <xact>...</xact> + <xact>...</xact> + <xact>...</xact>... </ledger> @end smallexample The data stream is enclosed in a @samp{ledger} tag, which contains a -series of one or more entries. Each @samp{entry} describes the entry -and contains a series of one or more transactions: +series of one or more transactions. Each @samp{xact} describes the transaction +and contains a series of one or more postings: @smallexample -<entry> +<xact> <en:date>2004/03/01</en:date> <en:cleared/> <en:code>100</en:code> <en:payee>John Wiegley</en:payee> - <en:transactions> - <transaction>...</transaction> - <transaction>...</transaction> - <transaction>...</transaction>... - </en:transactions> -</entry> + <en:postings> + <posting>...</posting> + <posting>...</posting> + <posting>...</posting>... + </en:postings> +</xact> @end smallexample The date format for @samp{en:date} is always @samp{YYYY/MM/DD}. The @samp{en:cleared} tag is optional, and indicates whether the -transaction has been cleared or not. There is also an -@samp{en:pending} tag, for marking pending transactions. The +posting has been cleared or not. There is also an +@samp{en:pending} tag, for marking pending postings. The @samp{en:code} and @samp{en:payee} tags both contain whatever text the user wishes. -After the initial entry data, there must follow a set of transactions -marked with @samp{en:transactions}. Typically these transactions will +After the initial transaction data, there must follow a set of postings +marked with @samp{en:postings}. Typically these postings will all balance each other, but if not they will be automatically balanced into an account named @samp{<Unknown>}. -Within the @samp{en:transactions} tag is a series of one or more -@samp{transaction}'s, which have the following form: +Within the @samp{en:postings} tag is a series of one or more +@samp{posting}'s, which have the following form: @smallexample -<transaction> +<posting> <tr:account>Expenses:Computer:Hardware</tr:account> <tr:amount> <value type="amount"> @@ -3858,16 +3858,16 @@ Within the @samp{en:transactions} tag is a series of one or more </amount> </value> </tr:amount> -</transaction> +</posting> @end smallexample -This is a basic transaction. It may also be begin with +This is a basic posting. It may also be begin with @samp{tr:virtual} and/or @samp{tr:generated} tags, to indicate virtual -and auto-generated transactions. Then follows the @samp{tr:account} -tag, which contains the full name of the account the transaction is +and auto-generated postings. Then follows the @samp{tr:account} +tag, which contains the full name of the account the posting is related to. Colons separate parent from child in an account name. -Lastly follows the amount of the transaction, indicated by +Lastly follows the amount of the posting, indicated by @samp{tr:amount}. Within this tag is a @samp{value} tag, of which there are four different kinds, each with its own format: @@ -3950,8 +3950,8 @@ the same data. Everything begins with a journal file---the anatomy of which is covered in detail in chapter one. To review: a @emph{journal} contains one or -more @emph{entries}, each of which refers to two or more -@emph{transactions}. A @emph{transaction} specifies that a given +more @emph{transactions}, each of which refers to two or more +@emph{postings}. A @emph{posting} specifies that a given @emph{amount} is added to, or subtracted from, an @emph{account}. (@emph{Accounts} may be nested hierarchically by separating the elements using a colon). Lastly, an @emph{amount} is a figure representing a @@ -3960,17 +3960,17 @@ these terms, which are all used extensively throughout this chapter: @table @emph @item journal -A journal is a data file containing a series of entries. - -@item entry -An entry relates a group of two or more transactions, with the absolute -constraint that the total sum of an entry's transactions must equal -zero. That is, every entry in a journal must @emph{balance} to zero. +A journal is a data file containing a series of transactions. @item transaction -Transactions record how commodities are moved between accounts. If you -spent money on a movie ticket, for example, such an entry would have two -transactions: One to show how the money was taken from your wallet, and +a transaction relates a group of two or more postings, with the absolute +constraint that the total sum of a transaction's postings must equal +zero. That is, every transaction in a journal must @emph{balance} to zero. + +@item posting +Postings record how commodities are moved between accounts. If you +spent money on a movie ticket, for example, such a transaction would have two +postings: One to show how the money was taken from your wallet, and another to show how it was applied to your movie expenses. @item account @@ -3999,7 +3999,7 @@ difficult one. All that's required is a proper understanding of how Ledger views your data, and how it prepares it for reporting. After Ledger reads a journal file, it creates an in-memory -representation reflecting the order and composition of those entries. +representation reflecting the order and composition of those transactions. @chapter Value expressions @@ -4023,7 +4023,7 @@ reporting data to the user: @end enumerate The calculations in step two are specified by the user, such as when a -transaction's value might contain mathematical operators. The +posting's value might contain mathematical operators. The calculations in step four are implied in the transformations, for example when the @option{--average} option is used. @@ -4062,8 +4062,8 @@ mask_t journal_t account_t -entry_t -transaction_t +xact_t +post_t parser_t @section Reporting diff --git a/doc/sample.dat b/doc/sample.dat index 5fdc98d1..002d20ee 100644 --- a/doc/sample.dat +++ b/doc/sample.dat @@ -34,10 +34,10 @@ N $ Liabilities:MasterCard 2004/05/27 (100) Credit card company - ; This is an entry note! + ; This is an xact note! ; Sample: Value Liabilities:MasterCard $20.00 - ; This is a transaction note! + ; This is a posting note! ; Sample: Another Value ; :MyTag: Assets:Bank:Checking diff --git a/lisp/ledger.el b/lisp/ledger.el index 61a9cd12..33d77926 100644 --- a/lisp/ledger.el +++ b/lisp/ledger.el @@ -35,11 +35,11 @@ ;; To use this module: Load this file, open a ledger data file, and ;; type M-x ledger-mode. Once this is done, you can type: ;; -;; C-c C-a add a new transaction, based on previous transactions -;; C-c C-e toggle cleared status of an transaction -;; C-c C-y set default year for transaction mode -;; C-c C-m set default month for transaction mode -;; C-c C-r reconcile uncleared transactions related to an account +;; C-c C-a add a new entry, based on previous entries +;; C-c C-e toggle cleared status of an entry +;; C-c C-y set default year for entry mode +;; C-c C-m set default month for entry mode +;; C-c C-r reconcile uncleared entries related to an account ;; C-c C-o C-r run a ledger report ;; C-C C-o C-g goto the ledger report buffer ;; C-c C-o C-e edit the defined ledger reports @@ -48,7 +48,7 @@ ;; C-c C-o C-k kill the ledger report buffer ;; ;; In the reconcile buffer, use SPACE to toggle the cleared status of -;; a posting, C-x C-s to save changes (to the ledger file as +;; a transaction, C-x C-s to save changes (to the ledger file as ;; well). ;; ;; The ledger reports command asks the user to select a report to run @@ -85,8 +85,8 @@ :type 'file :group 'ledger) -(defcustom ledger-clear-whole-transactions nil - "If non-nil, clear whole transactions, not individual postings." +(defcustom ledger-clear-whole-entries nil + "If non-nil, clear whole entries, not individual transactions." :type 'boolean :group 'ledger) @@ -121,8 +121,8 @@ text that should replace the format specifier." :type 'alist :group 'ledger) -(defcustom ledger-default-acct-posting-indent " " - "Default indentation for account postings in an transaction." +(defcustom ledger-default-acct-transaction-indent " " + "Default indentation for account transactions in an entry." :type 'string :group 'ledger) @@ -147,12 +147,12 @@ text that should replace the format specifier." (defvar ledger-year (ledger-current-year) "Start a ledger session with the current year, but make it -customizable to ease retro-transaction.") +customizable to ease retro-entry.") (defvar ledger-month (ledger-current-month) "Start a ledger session with the current month, but make it -customizable to ease retro-transaction.") +customizable to ease retro-entry.") -(defun ledger-iterate-transactions (callback) +(defun ledger-iterate-entries (callback) (goto-char (point-min)) (let* ((now (current-time)) (current-year (nth 5 (decode-time now)))) @@ -194,18 +194,18 @@ Return the difference in the format of a time value." (defun ledger-find-slot (moment) (catch 'found - (ledger-iterate-transactions + (ledger-iterate-entries (function (lambda (start date mark desc) (if (ledger-time-less-p moment date) (throw 'found t))))))) -(defun ledger-add-transaction (transaction-text &optional insert-at-point) +(defun ledger-add-entry (entry-text &optional insert-at-point) (interactive (list - (read-string "Transaction: " (concat ledger-year "/" ledger-month "/")))) + (read-string "Entry: " (concat ledger-year "/" ledger-month "/")))) (let* ((args (with-temp-buffer - (insert transaction-text) + (insert entry-text) (eshell-parse-arguments (point-min) (point-max)))) (ledger-buf (current-buffer)) exit-code) @@ -221,7 +221,7 @@ Return the difference in the format of a time value." (insert (with-temp-buffer (setq exit-code - (apply #'ledger-run-ledger ledger-buf "xact" + (apply #'ledger-run-ledger ledger-buf "entry" (mapcar 'eval args))) (goto-char (point-min)) (if (looking-at "Error: ") @@ -231,7 +231,7 @@ Return the difference in the format of a time value." (buffer-string))) "\n")))) -(defun ledger-current-transaction-bounds () +(defun ledger-current-entry-bounds () (save-excursion (when (or (looking-at "^[0-9]") (re-search-backward "^[0-9]" nil t)) @@ -240,12 +240,12 @@ Return the difference in the format of a time value." (forward-line)) (cons (copy-marker beg) (point-marker)))))) -(defun ledger-delete-current-transaction () +(defun ledger-delete-current-entry () (interactive) - (let ((bounds (ledger-current-transaction-bounds))) + (let ((bounds (ledger-current-entry-bounds))) (delete-region (car bounds) (cdr bounds)))) -(defun ledger-toggle-current-transaction (&optional style) +(defun ledger-toggle-current-entry (&optional style) (interactive) (let (clear) (save-excursion @@ -275,7 +275,7 @@ Return the difference in the format of a time value." 'pending 'cleared))) -(defun ledger-transaction-state () +(defun ledger-entry-state () (save-excursion (when (or (looking-at "^[0-9]") (re-search-backward "^[0-9]" nil t)) @@ -285,30 +285,30 @@ Return the difference in the format of a time value." ((looking-at "\\*\\s-*") 'cleared) (t nil))))) -(defun ledger-posting-state () +(defun ledger-transaction-state () (save-excursion (goto-char (line-beginning-position)) (skip-syntax-forward " ") (cond ((looking-at "!\\s-*") 'pending) ((looking-at "\\*\\s-*") 'cleared) - (t (ledger-transaction-state))))) + (t (ledger-entry-state))))) -(defun ledger-toggle-current-posting (&optional style) - "Toggle the cleared status of the posting under point. +(defun ledger-toggle-current-transaction (&optional style) + "Toggle the cleared status of the transaction under point. Optional argument STYLE may be `pending' or `cleared', depending on which type of status the caller wishes to indicate (default is `cleared'). This function is rather complicated because it must preserve both -the overall formatting of the ledger transaction, as well as ensuring +the overall formatting of the ledger entry, as well as ensuring that the most minimal display format is used. This could be -achieved more certainly by passing the transaction to ledger for +achieved more certainly by passing the entry to ledger for formatting, but doing so causes inline math expressions to be dropped." (interactive) - (let ((bounds (ledger-current-transaction-bounds)) + (let ((bounds (ledger-current-entry-bounds)) clear cleared) - ;; Uncompact the transaction, to make it easier to toggle the - ;; posting + ;; Uncompact the entry, to make it easier to toggle the + ;; transaction (save-excursion (goto-char (car bounds)) (skip-chars-forward "0-9./= \t") @@ -329,7 +329,7 @@ dropped." (if (search-forward " " (line-end-position) t) (delete-char 2)) (forward-line)))) - ;; Toggle the individual posting + ;; Toggle the individual transaction (save-excursion (goto-char (line-beginning-position)) (when (looking-at "[ \t]") @@ -367,7 +367,7 @@ dropped." ((looking-at " ") (delete-char 1)))) (setq clear inserted))))) - ;; Clean up the transaction so that it displays minimally + ;; Clean up the entry so that it displays minimally (save-excursion (goto-char (car bounds)) (forward-line) @@ -415,9 +415,9 @@ dropped." (defun ledger-toggle-current (&optional style) (interactive) - (if ledger-clear-whole-transactions - (ledger-toggle-current-transaction style) - (ledger-toggle-current-posting style))) + (if ledger-clear-whole-entries + (ledger-toggle-current-entry style) + (ledger-toggle-current-transaction style))) (defvar ledger-mode-abbrev-table) @@ -439,18 +439,18 @@ dropped." (set (make-local-variable 'pcomplete-termination-string) "") (let ((map (current-local-map))) - (define-key map [(control ?c) (control ?a)] 'ledger-add-transaction) - (define-key map [(control ?c) (control ?d)] 'ledger-delete-current-transaction) + (define-key map [(control ?c) (control ?a)] 'ledger-add-entry) + (define-key map [(control ?c) (control ?d)] 'ledger-delete-current-entry) (define-key map [(control ?c) (control ?y)] 'ledger-set-year) (define-key map [(control ?c) (control ?m)] 'ledger-set-month) (define-key map [(control ?c) (control ?c)] 'ledger-toggle-current) - (define-key map [(control ?c) (control ?e)] 'ledger-toggle-current-transaction) + (define-key map [(control ?c) (control ?e)] 'ledger-toggle-current-entry) (define-key map [(control ?c) (control ?r)] 'ledger-reconcile) (define-key map [(control ?c) (control ?s)] 'ledger-sort) (define-key map [tab] 'pcomplete) (define-key map [(control ?i)] 'pcomplete) - (define-key map [(control ?c) tab] 'ledger-fully-complete-transaction) - (define-key map [(control ?c) (control ?i)] 'ledger-fully-complete-transaction) + (define-key map [(control ?c) tab] 'ledger-fully-complete-entry) + (define-key map [(control ?c) (control ?i)] 'ledger-fully-complete-entry) (define-key map [(control ?c) (control ?o) (control ?r)] 'ledger-report) (define-key map [(control ?c) (control ?o) (control ?g)] 'ledger-report-goto) (define-key map [(control ?c) (control ?o) (control ?a)] 'ledger-report-redo) @@ -516,7 +516,7 @@ dropped." (defun ledger-reconcile-add () (interactive) (with-current-buffer ledger-buf - (call-interactively #'ledger-add-transaction)) + (call-interactively #'ledger-add-entry)) (ledger-reconcile-refresh)) (defun ledger-reconcile-delete () @@ -525,7 +525,7 @@ dropped." (when (equal (car where) "<stdin>") (with-current-buffer ledger-buf (goto-char (cdr where)) - (ledger-delete-current-transaction)) + (ledger-delete-current-entry)) (let ((inhibit-read-only t)) (goto-char (line-beginning-position)) (delete-region (point) (1+ (line-end-position))) @@ -579,23 +579,23 @@ dropped." (read (current-buffer)))))))) (dolist (item items) (let ((index 1)) - (dolist (post (nthcdr 5 item)) + (dolist (xact (nthcdr 5 item)) (let ((beg (point)) (where (with-current-buffer buf (cons (nth 0 item) - (if ledger-clear-whole-transactions + (if ledger-clear-whole-entries (save-excursion (goto-line (nth 1 item)) (point-marker)) (save-excursion - (goto-line (nth 0 post)) + (goto-line (nth 0 xact)) (point-marker))))))) (insert (format "%s %-30s %-25s %15s\n" (format-time-string "%m/%d" (nth 2 item)) - (nth 4 item) (nth 1 post) (nth 2 post))) - (if (nth 3 post) + (nth 4 item) (nth 1 xact) (nth 2 xact))) + (if (nth 3 xact) (set-text-properties beg (1- (point)) (list 'face 'bold 'where where)) @@ -623,7 +623,7 @@ dropped." (defvar ledger-reconcile-mode-abbrev-table) (define-derived-mode ledger-reconcile-mode text-mode "Reconcile" - "A mode for reconciling ledger transactions." + "A mode for reconciling ledger entries." (let ((map (make-sparse-keymap))) (define-key map [(control ?m)] 'ledger-reconcile-visit) (define-key map [return] 'ledger-reconcile-visit) @@ -642,12 +642,12 @@ dropped." ;; Context sensitivity (defconst ledger-line-config - '((transaction + '((entry (("^\\(\\([0-9][0-9][0-9][0-9]/\\)?[01]?[0-9]/[0123]?[0-9]\\)[ \t]+\\(\\([!*]\\)[ \t]\\)?[ \t]*\\((\\(.*\\))\\)?[ \t]*\\(.*?\\)[ \t]*;\\(.*\\)[ \t]*$" (date nil status nil nil code payee comment)) ("^\\(\\([0-9][0-9][0-9][0-9]/\\)?[01]?[0-9]/[0123]?[0-9]\\)[ \t]+\\(\\([!*]\\)[ \t]\\)?[ \t]*\\((\\(.*\\))\\)?[ \t]*\\(.*\\)[ \t]*$" (date nil status nil nil code payee)))) - (acct-posting + (acct-transaction (("\\(^[ \t]+\\)\\(.*?\\)[ \t]+\\([$]\\)\\(-?[0-9]*\\(\\.[0-9]*\\)?\\)[ \t]*;[ \t]*\\(.*?\\)[ \t]*$" (indent account commodity amount nil comment)) ("\\(^[ \t]+\\)\\(.*?\\)[ \t]+\\([$]\\)\\(-?[0-9]*\\(\\.[0-9]*\\)?\\)[ \t]*$" @@ -704,13 +704,13 @@ the fields in the line in a association list." (cond ((equal (point) (line-end-position)) '(empty-line nil nil)) ((memq first-char '(?\ ?\t)) - (ledger-extract-context-info 'acct-posting pos)) + (ledger-extract-context-info 'acct-transaction pos)) ((memq first-char '(?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9)) - (ledger-extract-context-info 'transaction pos)) + (ledger-extract-context-info 'entry pos)) ((equal first-char ?\=) - '(automated-transaction nil nil)) + '(automated-entry nil nil)) ((equal first-char ?\~) - '(period-transaction nil nil)) + '(period-entry nil nil)) ((equal first-char ?\!) '(command-directive)) ((equal first-char ?\;) @@ -775,13 +775,13 @@ specified line, returns nil." (defun ledger-context-goto-field-end (context-info field-name) (goto-char (ledger-context-field-end-position context-info field-name))) -(defun ledger-transaction-payee () - "Returns the payee of the transaction containing point or nil." +(defun ledger-entry-payee () + "Returns the payee of the entry containing point or nil." (let ((i 0)) - (while (eq (ledger-context-line-type (ledger-context-other-line i)) 'acct-posting) + (while (eq (ledger-context-line-type (ledger-context-other-line i)) 'acct-transaction) (setq i (- i 1))) (let ((context-info (ledger-context-other-line i))) - (if (eq (ledger-context-line-type context-info) 'transaction) + (if (eq (ledger-context-line-type context-info) 'entry) (ledger-context-field-value context-info 'payee) nil)))) @@ -904,25 +904,25 @@ otherwise the current buffer file is used." "Substitute a payee name The user is prompted to enter a payee and that is substitued. If -point is in an transaction, the payee for that transaction is used as the +point is in an entry, the payee for that entry is used as the default." ;; It is intended copmletion should be available on existing ;; payees, but the list of possible completions needs to be ;; developed to allow this. - (ledger-read-string-with-default "Payee" (regexp-quote (ledger-transaction-payee)))) + (ledger-read-string-with-default "Payee" (regexp-quote (ledger-entry-payee)))) (defun ledger-report-account-format-specifier () "Substitute an account name The user is prompted to enter an account name, which can be any regular expression identifying an account. If point is on an account -posting line for an transaction, the full account name on that line is +transaction line for an entry, the full account name on that line is the default." ;; It is intended completion should be available on existing account ;; names, but it remains to be implemented. (let* ((context (ledger-context-at-point)) (default - (if (eq (ledger-context-line-type context) 'acct-posting) + (if (eq (ledger-context-line-type context) 'acct-transaction) (regexp-quote (ledger-context-field-value context 'account)) nil))) (ledger-read-string-with-default "Account" default))) @@ -1037,13 +1037,13 @@ the default." (goto-char (line-beginning-position)) (cond ((looking-at "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.+?)\\)?\\s-+") (goto-char (match-end 0)) - 'transaction) + 'entry) ((looking-at "^\\s-+\\([*!]\\s-+\\)?[[(]?\\(.\\)") (goto-char (match-beginning 2)) - 'posting) + 'transaction) ((looking-at "^\\(sun\\|mon\\|tue\\|wed\\|thu\\|fri\\|sat\\)\\s-+") (goto-char (match-end 0)) - 'transaction) + 'entry) (t (ignore (goto-char here)))))) @@ -1064,9 +1064,9 @@ the default." args))) (cons (reverse args) (reverse begins))))) -(defun ledger-transactions () +(defun ledger-entries () (let ((origin (point)) - transactions-list) + entries-list) (save-excursion (goto-char (point-min)) (while (re-search-forward @@ -1074,9 +1074,9 @@ the default." "\\(.+?\\)\\(\t\\|\n\\| [ \t]\\)") nil t) (unless (and (>= origin (match-beginning 0)) (< origin (match-end 0))) - (setq transactions-list (cons (match-string-no-properties 3) - transactions-list))))) - (pcomplete-uniqify-list (nreverse transactions-list)))) + (setq entries-list (cons (match-string-no-properties 3) + entries-list))))) + (pcomplete-uniqify-list (nreverse entries-list)))) (defvar ledger-account-tree nil) @@ -1093,12 +1093,12 @@ the default." (setq elements (split-string account-path ":")) (let ((root ledger-account-tree)) (while elements - (let ((transaction (assoc (car elements) root))) - (if transaction - (setq root (cdr transaction)) - (setq transaction (cons (car elements) (list t))) - (nconc root (list transaction)) - (setq root (cdr transaction)))) + (let ((entry (assoc (car elements) root))) + (if entry + (setq root (cdr entry)) + (setq entry (cons (car elements) (list t))) + (nconc root (list entry)) + (setq root (cdr entry)))) (setq elements (cdr elements))))))))) (defun ledger-accounts () @@ -1108,11 +1108,11 @@ the default." (root ledger-account-tree) (prefix nil)) (while (cdr elements) - (let ((transaction (assoc (car elements) root))) - (if transaction + (let ((entry (assoc (car elements) root))) + (if entry (setq prefix (concat prefix (and prefix ":") (car elements)) - root (cdr transaction)) + root (cdr entry)) (setq root nil elements nil))) (setq elements (cdr elements))) (and root @@ -1133,16 +1133,16 @@ the default." (interactive) (while (pcomplete-here (if (eq (save-excursion - (ledger-thing-at-point)) 'transaction) + (ledger-thing-at-point)) 'entry) (if (null current-prefix-arg) - (ledger-transactions) ; this completes against transaction names + (ledger-entries) ; this completes against entry names (progn (let ((text (buffer-substring (line-beginning-position) (line-end-position)))) (delete-region (line-beginning-position) (line-end-position)) (condition-case err - (ledger-add-transaction text t) + (ledger-add-entry text t) ((error) (insert text)))) (forward-line) @@ -1152,30 +1152,30 @@ the default." (throw 'pcompleted t))) (ledger-accounts))))) -(defun ledger-fully-complete-transaction () +(defun ledger-fully-complete-entry () "Do appropriate completion for the thing at point" (interactive) (let ((name (caar (ledger-parse-arguments))) - posts) + xacts) (save-excursion - (when (eq 'transaction (ledger-thing-at-point)) + (when (eq 'entry (ledger-thing-at-point)) (when (re-search-backward (concat "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.*?)\\)?\\s-+" (regexp-quote name) "\\(\t\\|\n\\| [ \t]\\)") nil t) (forward-line) (while (looking-at "^\\s-+") - (setq posts (cons (buffer-substring-no-properties + (setq xacts (cons (buffer-substring-no-properties (line-beginning-position) (line-end-position)) - posts)) + xacts)) (forward-line)) - (setq posts (nreverse posts))))) - (when posts + (setq xacts (nreverse xacts))))) + (when xacts (save-excursion (insert ?\n) - (while posts - (insert (car posts) ?\n) - (setq posts (cdr posts)))) + (while xacts + (insert (car xacts) ?\n) + (setq xacts (cdr xacts)))) (forward-line) (goto-char (line-end-position)) (if (re-search-backward "\\(\t\\| [ \t]\\)" nil t) @@ -1219,7 +1219,7 @@ This is done so that the last digit falls in COLUMN, which defaults to 52." (defalias 'ledger-align-dollars 'ledger-align-amounts) -;; A sample transaction sorting function, which works if transaction dates are of +;; A sample entry sorting function, which works if entry dates are of ;; the form YYYY/mm/dd. (defun ledger-sort () diff --git a/python/py_journal.cc b/python/py_journal.cc index 7f8d76c6..b0328844 100644 --- a/python/py_journal.cc +++ b/python/py_journal.cc @@ -64,57 +64,57 @@ void export_journal() } // namespace ledger #if 0 -entry_t& transaction_entry(const transaction_t& xact) +xact_t& post_xact(const post_t& post) { - return *xact.entry; + return *post.xact; } -unsigned int transactions_len(entry_base_t& entry) +unsigned int posts_len(xact_base_t& xact) { - return entry.transactions.size(); + return xact.posts.size(); } -transaction_t& transactions_getitem(entry_base_t& entry, int i) +post_t& posts_getitem(xact_base_t& xact, int i) { static int last_index = 0; - static entry_base_t * last_entry = NULL; - static transactions_list::iterator elem; + static xact_base_t * last_xact = NULL; + static posts_list::iterator elem; - std::size_t len = entry.transactions.size(); + std::size_t len = xact.posts.size(); if (abs(i) >= len) { PyErr_SetString(PyExc_IndexError, "Index out of range"); throw_error_already_set(); } - if (&entry == last_entry && i == last_index + 1) { + if (&xact == last_xact && i == last_index + 1) { last_index = i; return **++elem; } int x = i < 0 ? len + i : i; - elem = entry.transactions.begin(); + elem = xact.posts.begin(); while (--x >= 0) elem++; - last_entry = &entry; + last_xact = &xact; last_index = i; return **elem; } -unsigned int entries_len(journal_t& journal) +unsigned int xacts_len(journal_t& journal) { - return journal.entries.size(); + return journal.xacts.size(); } -entry_t& entries_getitem(journal_t& journal, int i) +xact_t& xacts_getitem(journal_t& journal, int i) { static int last_index = 0; static journal_t * last_journal = NULL; - static entries_list::iterator elem; + static xacts_list::iterator elem; - std::size_t len = journal.entries.size(); + std::size_t len = journal.xacts.size(); if (abs(i) >= len) { PyErr_SetString(PyExc_IndexError, "Index out of range"); @@ -127,7 +127,7 @@ entry_t& entries_getitem(journal_t& journal, int i) } int x = i < 0 ? len + i : i; - elem = journal.entries.begin(); + elem = journal.xacts.begin(); while (--x >= 0) elem++; @@ -192,58 +192,58 @@ account_t * py_find_account_2(journal_t& journal, const string& name, return journal.find_account(name, auto_create); } -bool py_add_entry(journal_t& journal, entry_t * entry) { - return journal.add_entry(new entry_t(*entry)); +bool py_add_xact(journal_t& journal, xact_t * xact) { + return journal.add_xact(new xact_t(*xact)); } -void py_add_transaction(entry_base_t& entry, transaction_t * xact) { - return entry.add_transaction(new transaction_t(*xact)); +void py_add_post(xact_base_t& xact, post_t * post) { + return xact.add_post(new post_t(*post)); } -struct entry_base_wrap : public entry_base_t +struct xact_base_wrap : public xact_base_t { PyObject * self; - entry_base_wrap(PyObject * self_) : self(self_) {} + xact_base_wrap(PyObject * self_) : self(self_) {} virtual bool valid() const { return call_method<bool>(self, "valid"); } }; -struct py_entry_finalizer_t : public entry_finalizer_t { +struct py_xact_finalizer_t : public xact_finalizer_t { object pyobj; - py_entry_finalizer_t() {} - py_entry_finalizer_t(object obj) : pyobj(obj) {} - py_entry_finalizer_t(const py_entry_finalizer_t& other) + py_xact_finalizer_t() {} + py_xact_finalizer_t(object obj) : pyobj(obj) {} + py_xact_finalizer_t(const py_xact_finalizer_t& other) : pyobj(other.pyobj) {} - virtual bool operator()(entry_t& entry, bool post) { - return call<bool>(pyobj.ptr(), entry, post); + virtual bool operator()(xact_t& xact, bool post) { + return call<bool>(pyobj.ptr(), xact, post); } }; -std::list<py_entry_finalizer_t> py_finalizers; +std::list<py_xact_finalizer_t> py_finalizers; -void py_add_entry_finalizer(journal_t& journal, object x) +void py_add_xact_finalizer(journal_t& journal, object x) { - py_finalizers.push_back(py_entry_finalizer_t(x)); - journal.add_entry_finalizer(&py_finalizers.back()); + py_finalizers.push_back(py_xact_finalizer_t(x)); + journal.add_xact_finalizer(&py_finalizers.back()); } -void py_remove_entry_finalizer(journal_t& journal, object x) +void py_remove_xact_finalizer(journal_t& journal, object x) { - for (std::list<py_entry_finalizer_t>::iterator i = py_finalizers.begin(); + for (std::list<py_xact_finalizer_t>::iterator i = py_finalizers.begin(); i != py_finalizers.end(); i++) if ((*i).pyobj == x) { - journal.remove_entry_finalizer(&(*i)); + journal.remove_xact_finalizer(&(*i)); py_finalizers.erase(i); return; } } -void py_run_entry_finalizers(journal_t& journal, entry_t& entry, bool post) +void py_run_xact_finalizers(journal_t& journal, xact_t& xact, bool post) { - run_hooks(journal.entry_finalize_hooks, entry, post); + run_hooks(journal.xact_finalize_hooks, xact, post); } #define EXC_TRANSLATOR(type) \ @@ -256,70 +256,70 @@ EXC_TRANSLATOR(interval_expr_error) EXC_TRANSLATOR(format_error) EXC_TRANSLATOR(parse_error) -value_t py_transaction_amount(transaction_t * xact) { - return value_t(xact->amount); +value_t py_post_amount(post_t * post) { + return value_t(post->amount); } -transaction_t::state_t py_entry_state(entry_t * entry) { - transaction_t::state_t state; - if (entry->get_state(&state)) +post_t::state_t py_xact_state(xact_t * xact) { + post_t::state_t state; + if (xact->get_state(&state)) return state; else - return transaction_t::UNCLEARED; + return post_t::UNCLEARED; } void export_journal() { - scope().attr("TRANSACTION_NORMAL") = TRANSACTION_NORMAL; - scope().attr("TRANSACTION_VIRTUAL") = TRANSACTION_VIRTUAL; - scope().attr("TRANSACTION_BALANCE") = TRANSACTION_BALANCE; - scope().attr("TRANSACTION_AUTO") = TRANSACTION_AUTO; - scope().attr("TRANSACTION_BULK_ALLOC") = TRANSACTION_BULK_ALLOC; - scope().attr("TRANSACTION_CALCULATED") = TRANSACTION_CALCULATED; - - enum_< transaction_t::state_t > ("State") - .value("Uncleared", transaction_t::UNCLEARED) - .value("Cleared", transaction_t::CLEARED) - .value("Pending", transaction_t::PENDING) + scope().attr("POST_NORMAL") = POST_NORMAL; + scope().attr("POST_VIRTUAL") = POST_VIRTUAL; + scope().attr("POST_BALANCE") = POST_BALANCE; + scope().attr("POST_AUTO") = POST_AUTO; + scope().attr("POST_BULK_ALLOC") = POST_BULK_ALLOC; + scope().attr("POST_CALCULATED") = POST_CALCULATED; + + enum_< post_t::state_t > ("State") + .value("Uncleared", post_t::UNCLEARED) + .value("Cleared", post_t::CLEARED) + .value("Pending", post_t::PENDING) ; - class_< transaction_t > ("Transaction") + class_< post_t > ("Post") .def(init<optional<account_t *> >()) .def(init<account_t *, amount_t, optional<unsigned int, const string&> >()) .def(self == self) .def(self != self) - .add_property("entry", - make_getter(&transaction_t::entry, + .add_property("xact", + make_getter(&post_t::xact, return_value_policy<reference_existing_object>())) .add_property("account", - make_getter(&transaction_t::account, + make_getter(&post_t::account, return_value_policy<reference_existing_object>())) - .add_property("amount", &py_transaction_amount) - .def_readonly("amount_expr", &transaction_t::amount_expr) + .add_property("amount", &py_post_amount) + .def_readonly("amount_expr", &post_t::amount_expr) .add_property("cost", - make_getter(&transaction_t::cost, + make_getter(&post_t::cost, return_internal_reference<1>())) - .def_readonly("cost_expr", &transaction_t::cost_expr) + .def_readonly("cost_expr", &post_t::cost_expr) - .def_readwrite("state", &transaction_t::state) - .def_readwrite("flags", &transaction_t::flags) - .def_readwrite("note", &transaction_t::note) + .def_readwrite("state", &post_t::state) + .def_readwrite("flags", &post_t::flags) + .def_readwrite("note", &post_t::note) - .def_readonly("beg_pos", &transaction_t::beg_pos) - .def_readonly("beg_line", &transaction_t::beg_line) - .def_readonly("end_pos", &transaction_t::end_pos) - .def_readonly("end_line", &transaction_t::end_line) + .def_readonly("beg_pos", &post_t::beg_pos) + .def_readonly("beg_line", &post_t::beg_line) + .def_readonly("end_pos", &post_t::end_pos) + .def_readonly("end_line", &post_t::end_line) - .def("actual_date", &transaction_t::actual_date) - .def("effective_date", &transaction_t::effective_date) - .def("date", &transaction_t::date) + .def("actual_date", &post_t::actual_date) + .def("effective_date", &post_t::effective_date) + .def("date", &post_t::date) - .def("use_effective_date", &transaction_t::use_effective_date) + .def("use_effective_date", &post_t::use_effective_date) - .def("valid", &transaction_t::valid) + .def("valid", &post_t::valid) ; class_< account_t > @@ -360,8 +360,8 @@ void export_journal() .def(self == self) .def(self != self) - .def("__len__", entries_len) - .def("__getitem__", entries_getitem, return_internal_reference<1>()) + .def("__len__", xacts_len) + .def("__getitem__", xacts_getitem, return_internal_reference<1>()) .add_property("master", make_getter(&journal_t::master, return_internal_reference<1>())) @@ -380,50 +380,50 @@ void export_journal() .def("find_account_re", &journal_t::find_account_re, return_internal_reference<1>()) - .def("add_entry", py_add_entry) - .def("remove_entry", &journal_t::remove_entry) + .def("add_xact", py_add_xact) + .def("remove_xact", &journal_t::remove_xact) - .def("add_entry_finalizer", py_add_entry_finalizer) - .def("remove_entry_finalizer", py_remove_entry_finalizer) - .def("run_entry_finalizers", py_run_entry_finalizers) + .def("add_xact_finalizer", py_add_xact_finalizer) + .def("remove_xact_finalizer", py_remove_xact_finalizer) + .def("run_xact_finalizers", py_run_xact_finalizers) .def("valid", &journal_t::valid) ; - class_< entry_base_t, entry_base_wrap, boost::noncopyable > ("EntryBase") - .def("__len__", transactions_len) - .def("__getitem__", transactions_getitem, + class_< xact_base_t, xact_base_wrap, boost::noncopyable > ("XactBase") + .def("__len__", posts_len) + .def("__getitem__", posts_getitem, return_internal_reference<1>()) - .def_readonly("journal", &entry_base_t::journal) + .def_readonly("journal", &xact_base_t::journal) - .def_readonly("src_idx", &entry_base_t::src_idx) - .def_readonly("beg_pos", &entry_base_t::beg_pos) - .def_readonly("beg_line", &entry_base_t::beg_line) - .def_readonly("end_pos", &entry_base_t::end_pos) - .def_readonly("end_line", &entry_base_t::end_line) + .def_readonly("src_idx", &xact_base_t::src_idx) + .def_readonly("beg_pos", &xact_base_t::beg_pos) + .def_readonly("beg_line", &xact_base_t::beg_line) + .def_readonly("end_pos", &xact_base_t::end_pos) + .def_readonly("end_line", &xact_base_t::end_line) - .def("add_transaction", py_add_transaction) - .def("remove_transaction", &entry_base_t::remove_transaction) + .def("add_post", py_add_post) + .def("remove_post", &xact_base_t::remove_post) .def(self == self) .def(self != self) - .def("finalize", &entry_base_t::finalize) - .def("valid", &entry_base_t::valid) + .def("finalize", &xact_base_t::finalize) + .def("valid", &xact_base_t::valid) ; - class_< entry_t, bases<entry_base_t> > ("Entry") - .add_property("date", &entry_t::date) - .add_property("effective_date", &entry_t::effective_date) - .add_property("actual_date", &entry_t::actual_date) + class_< xact_t, bases<xact_base_t> > ("Xact") + .add_property("date", &xact_t::date) + .add_property("effective_date", &xact_t::effective_date) + .add_property("actual_date", &xact_t::actual_date) - .def_readwrite("code", &entry_t::code) - .def_readwrite("payee", &entry_t::payee) + .def_readwrite("code", &xact_t::code) + .def_readwrite("payee", &xact_t::payee) - .add_property("state", &py_entry_state) + .add_property("state", &py_xact_state) - .def("valid", &entry_t::valid) + .def("valid", &xact_t::valid) ; #define EXC_TRANSLATE(type) \ diff --git a/python/py_entry.cc b/python/py_post.cc index 8743886e..a60b79f9 100644 --- a/python/py_entry.cc +++ b/python/py_post.cc @@ -31,7 +31,7 @@ #include "pyinterp.h" #include "pyutils.h" -#include "entry.h" +#include "post.h" namespace ledger { @@ -42,24 +42,12 @@ using namespace boost::python; PyErr_SetString(PyExc_ArithmeticError, err.what()); \ } -//EXC_TRANSLATOR(entry_error) +//EXC_TRANSLATOR(post_error) -void export_entry() +void export_post() { #if 0 - class_< entry_base_t > ("EntryBase") - ; - class_< entry_t > ("Entry") - ; - struct_< entry_finalizer_t > ("EntryFinalizer") - ; - class_< auto_entry_t > ("AutoEntry") - ; - struct_< auto_entry_finalizer_t > ("AutoEntryFinalizer") - ; - class_< period_entry_t > ("PeriodEntry") - ; - class_< func_finalizer_t > ("FuncFinalizer") + class_< post_t > ("Post") ; #endif @@ -70,7 +58,7 @@ void export_entry() #define EXC_TRANSLATE(type) \ register_exception_translator<type>(&exc_translate_ ## type); - //EXC_TRANSLATE(entry_error); + //EXC_TRANSLATE(post_error); } } // namespace ledger diff --git a/python/py_timelog.cc b/python/py_timelog.cc index 127bf641..03416ec2 100644 --- a/python/py_timelog.cc +++ b/python/py_timelog.cc @@ -47,7 +47,7 @@ using namespace boost::python; void export_timelog() { #if 0 - class_< time_entry_t > ("TimeEntry") + class_< time_xact_t > ("TimeXact") ; class_< time_log_t > ("TimeLog") ; diff --git a/python/py_xact.cc b/python/py_xact.cc index fb5dbf8e..441d5741 100644 --- a/python/py_xact.cc +++ b/python/py_xact.cc @@ -47,8 +47,20 @@ using namespace boost::python; void export_xact() { #if 0 + class_< xact_base_t > ("XactBase") + ; class_< xact_t > ("Xact") ; + struct_< xact_finalizer_t > ("XactFinalizer") + ; + class_< auto_xact_t > ("AutoXact") + ; + struct_< auto_xact_finalizer_t > ("AutoXactFinalizer") + ; + class_< period_xact_t > ("PeriodXact") + ; + class_< func_finalizer_t > ("FuncFinalizer") + ; #endif //register_optional_to_python<amount_t>(); diff --git a/python/pyinterp.cc b/python/pyinterp.cc index cc6a5688..cd877f80 100644 --- a/python/pyinterp.cc +++ b/python/pyinterp.cc @@ -39,7 +39,7 @@ shared_ptr<python_interpreter_t> python_session; void export_chain(); void export_commodity(); -void export_entry(); +void export_xact(); void export_expr(); void export_flags(); void export_format(); @@ -53,13 +53,13 @@ void export_timelog(); void export_times(); void export_utils(); void export_value(); -void export_xact(); +void export_post(); void initialize_for_python() { export_chain(); export_commodity(); - export_entry(); + export_xact(); export_expr(); export_flags(); export_format(); @@ -73,7 +73,7 @@ void initialize_for_python() export_times(); export_utils(); export_value(); - export_xact(); + export_post(); } struct python_run @@ -132,7 +132,7 @@ object python_interpreter_t::import(const string& str) if (! mod) throw_(std::logic_error, "Failed to import Python module " << str); - // Import all top-level entries directly into the main namespace + // Import all top-level xacts directly into the main namespace main_nspace.update(mod.attr("__dict__")); TRACE_FINISH(python_import, 1); diff --git a/src/account.h b/src/account.h index 8b485ec2..29b3c682 100644 --- a/src/account.h +++ b/src/account.h @@ -130,8 +130,8 @@ class account_t : public scope_t value_t value; value_t total; - std::size_t count; // xacts counted toward amount - std::size_t total_count; // xacts counted toward total + std::size_t count; // posts counted toward amount + std::size_t total_count; // posts counted toward total std::size_t virtuals; std::list<sort_value_t> sort_values; @@ -158,7 +158,7 @@ class account_t : public scope_t }; // This variable holds optional "extended data" which is usually produced - // only during reporting, and only for the transaction set being reported. + // only during reporting, and only for the posting set being reported. // It's a memory-saving measure to delay allocation until the last possible // moment. mutable optional<xdata_t> xdata_; diff --git a/src/chain.cc b/src/chain.cc index 950afc32..0ad1709f 100644 --- a/src/chain.cc +++ b/src/chain.cc @@ -35,11 +35,11 @@ namespace ledger { -xact_handler_ptr chain_xact_handlers(report_t& report, - xact_handler_ptr base_handler, +post_handler_ptr chain_post_handlers(report_t& report, + post_handler_ptr base_handler, bool only_preliminaries) { - xact_handler_ptr handler(base_handler); + post_handler_ptr handler(base_handler); item_predicate display_predicate; item_predicate only_predicate; @@ -48,159 +48,159 @@ xact_handler_ptr chain_xact_handlers(report_t& report, expr.set_context(&report); if (! only_preliminaries) { - // Make sure only forecast transactions which match are allowed through + // Make sure only forecast postings which match are allowed through if (report.HANDLED(forecast_while_)) { - handler.reset(new filter_xacts + handler.reset(new filter_posts (handler, item_predicate(report.HANDLER(forecast_while_).str(), report.what_to_keep()), report)); } - // truncate_entries cuts off a certain number of _entries_ from being + // truncate_xacts cuts off a certain number of _xacts_ from being // displayed. It does not affect calculation. if (report.HANDLED(head_) || report.HANDLED(tail_)) handler.reset - (new truncate_entries(handler, + (new truncate_xacts(handler, report.HANDLED(head_) ? report.HANDLER(head_).value.to_long() : 0, report.HANDLED(tail_) ? report.HANDLER(tail_).value.to_long() : 0)); - // filter_xacts will only pass through xacts matching the + // filter_posts will only pass through posts matching the // `display_predicate'. if (report.HANDLED(display_)) { display_predicate = item_predicate(report.HANDLER(display_).str(), report.what_to_keep()); - handler.reset(new filter_xacts(handler, display_predicate, report)); + handler.reset(new filter_posts(handler, display_predicate, report)); } - // changed_value_xacts adds virtual xacts to the list to account for + // changed_value_posts adds virtual posts to the list to account for // changes in market value of commodities, which otherwise would affect // the running total unpredictably. if (report.HANDLED(revalued)) - handler.reset(new changed_value_xacts + handler.reset(new changed_value_posts (handler, report.HANDLED(revalued_total_) ? report.HANDLER(revalued_total_).expr : report.HANDLER(display_total_).expr, report, report.HANDLED(revalued_only))); - // calc_xacts computes the running total. When this appears will - // determine, for example, whether filtered xacts are included or excluded + // calc_posts computes the running total. When this appears will + // determine, for example, whether filtered posts are included or excluded // from the running total. - handler.reset(new calc_xacts(handler, expr)); + handler.reset(new calc_posts(handler, expr)); } - // filter_xacts will only pass through xacts matching the + // filter_posts will only pass through posts matching the // `secondary_predicate'. if (report.HANDLED(only_)) { only_predicate = item_predicate(report.HANDLER(only_).str(), report.what_to_keep()); - handler.reset(new filter_xacts(handler, only_predicate, report)); + handler.reset(new filter_posts(handler, only_predicate, report)); } if (! only_preliminaries) { - // sort_xacts will sort all the xacts it sees, based on the `sort_order' + // sort_posts will sort all the posts it sees, based on the `sort_order' // value expression. if (report.HANDLED(sort_)) { - if (report.HANDLED(sort_entries_)) - handler.reset(new sort_entries(handler, report.HANDLER(sort_).str())); - else + if (report.HANDLED(sort_xacts_)) handler.reset(new sort_xacts(handler, report.HANDLER(sort_).str())); + else + handler.reset(new sort_posts(handler, report.HANDLER(sort_).str())); } - // collapse_xacts causes entries with multiple xacts to appear as entries - // with a subtotaled xact for each commodity used. + // collapse_posts causes xacts with multiple posts to appear as xacts + // with a subtotaled post for each commodity used. if (report.HANDLED(collapse)) - handler.reset(new collapse_xacts(handler, expr, + handler.reset(new collapse_posts(handler, expr, display_predicate, only_predicate, report.HANDLED(collapse_if_zero))); - // subtotal_xacts combines all the xacts it receives into one subtotal - // entry, which has one xact for each commodity in each account. + // subtotal_posts combines all the posts it receives into one subtotal + // xact, which has one post for each commodity in each account. // - // period_xacts is like subtotal_xacts, but it subtotals according to time + // period_posts is like subtotal_posts, but it subtotals according to time // periods rather than totalling everything. // - // dow_xacts is like period_xacts, except that it reports all the xacts + // dow_posts is like period_posts, except that it reports all the posts // that fall on each subsequent day of the week. if (report.HANDLED(equity)) - handler.reset(new xacts_as_equity(handler, expr)); + handler.reset(new posts_as_equity(handler, expr)); else if (report.HANDLED(subtotal)) - handler.reset(new subtotal_xacts(handler, expr)); + handler.reset(new subtotal_posts(handler, expr)); } if (report.HANDLED(dow)) - handler.reset(new dow_xacts(handler, expr)); + handler.reset(new dow_posts(handler, expr)); else if (report.HANDLED(by_payee)) - handler.reset(new by_payee_xacts(handler, expr)); + handler.reset(new by_payee_posts(handler, expr)); - // interval_xacts groups xacts together based on a time period, such as + // interval_posts groups posts together based on a time period, such as // weekly or monthly. if (report.HANDLED(period_)) { - handler.reset(new interval_xacts(handler, expr, + handler.reset(new interval_posts(handler, expr, report.HANDLER(period_).str(), report.HANDLED(exact), report.HANDLED(empty))); - handler.reset(new sort_xacts(handler, "date")); + handler.reset(new sort_posts(handler, "date")); } - // related_xacts will pass along all xacts related to the xact received. If - // the `related_all' handler is on, then all the entry's xacts are passed; - // meaning that if one xact of an entry is to be printed, all the xact for - // that entry will be printed. + // related_posts will pass along all posts related to the post received. If + // the `related_all' handler is on, then all the xact's posts are passed; + // meaning that if one post of an xact is to be printed, all the post for + // that xact will be printed. if (report.HANDLED(related)) - handler.reset(new related_xacts(handler, report.HANDLED(related_all))); + handler.reset(new related_posts(handler, report.HANDLED(related_all))); - // anonymize_xacts removes all meaningful information from entry payee's and + // anonymize_posts removes all meaningful information from xact payee's and // account names, for the sake of creating useful bug reports. if (report.HANDLED(anon)) - handler.reset(new anonymize_xacts(handler)); + handler.reset(new anonymize_posts(handler)); - // This filter_xacts will only pass through xacts matching the `predicate'. + // This filter_posts will only pass through posts matching the `predicate'. if (report.HANDLED(limit_)) { DEBUG("report.predicate", "Report predicate expression = " << report.HANDLER(limit_).str()); - handler.reset(new filter_xacts + handler.reset(new filter_posts (handler, item_predicate(report.HANDLER(limit_).str(), report.what_to_keep()), report)); } - // budget_xacts takes a set of xacts from a data file and uses them to - // generate "budget xacts" which balance against the reported xacts. + // budget_posts takes a set of posts from a data file and uses them to + // generate "budget posts" which balance against the reported posts. // - // forecast_xacts is a lot like budget_xacts, except that it adds entries + // forecast_posts is a lot like budget_posts, except that it adds xacts // only for the future, and does not balance them against anything but the // future balance. if (report.budget_flags != BUDGET_NO_BUDGET) { - budget_xacts * budget_handler = new budget_xacts(handler, + budget_posts * budget_handler = new budget_posts(handler, report.budget_flags); - budget_handler->add_period_entries(report.session.journal->period_entries); + budget_handler->add_period_xacts(report.session.journal->period_xacts); handler.reset(budget_handler); - // Apply this before the budget handler, so that only matching xacts are - // calculated toward the budget. The use of filter_xacts above will - // further clean the results so that no automated xacts that don't match + // Apply this before the budget handler, so that only matching posts are + // calculated toward the budget. The use of filter_posts above will + // further clean the results so that no automated posts that don't match // the filter get reported. if (report.HANDLED(limit_)) - handler.reset(new filter_xacts + handler.reset(new filter_posts (handler, item_predicate(report.HANDLER(limit_).str(), report.what_to_keep()), report)); } else if (report.HANDLED(forecast_while_)) { - forecast_xacts * forecast_handler - = new forecast_xacts(handler, + forecast_posts * forecast_handler + = new forecast_posts(handler, item_predicate(report.HANDLER(forecast_while_).str(), report.what_to_keep()), report); - forecast_handler->add_period_entries(report.session.journal->period_entries); + forecast_handler->add_period_xacts(report.session.journal->period_xacts); handler.reset(forecast_handler); - // See above, under budget_xacts. + // See above, under budget_posts. if (report.HANDLED(limit_)) - handler.reset(new filter_xacts + handler.reset(new filter_posts (handler, item_predicate(report.HANDLER(limit_).str(), report.what_to_keep()), report)); diff --git a/src/chain.h b/src/chain.h index b064c4ed..89f4ab6e 100644 --- a/src/chain.h +++ b/src/chain.h @@ -46,7 +46,7 @@ #ifndef _CHAIN_H #define _CHAIN_H -#include "xact.h" +#include "post.h" #include "account.h" namespace ledger { @@ -84,13 +84,13 @@ public: } }; -typedef shared_ptr<item_handler<xact_t> > xact_handler_ptr; +typedef shared_ptr<item_handler<post_t> > post_handler_ptr; typedef shared_ptr<item_handler<account_t> > acct_handler_ptr; class report_t; -xact_handler_ptr -chain_xact_handlers(report_t& report, - xact_handler_ptr base_handler, +post_handler_ptr +chain_post_handlers(report_t& report, + post_handler_ptr base_handler, bool only_preliminaries = false); } // namespace ledger diff --git a/src/compare.cc b/src/compare.cc index 79e49461..d716bcda 100644 --- a/src/compare.cc +++ b/src/compare.cc @@ -71,21 +71,21 @@ void compare_items<T>::find_sort_values(std::list<sort_value_t>& sort_values, } template <> -bool compare_items<xact_t>::operator()(xact_t * left, xact_t * right) +bool compare_items<post_t>::operator()(post_t * left, post_t * right) { assert(left); assert(right); - xact_t::xdata_t& lxdata(left->xdata()); - if (! lxdata.has_flags(XACT_EXT_SORT_CALC)) { + post_t::xdata_t& lxdata(left->xdata()); + if (! lxdata.has_flags(POST_EXT_SORT_CALC)) { find_sort_values(lxdata.sort_values, left); - lxdata.add_flags(XACT_EXT_SORT_CALC); + lxdata.add_flags(POST_EXT_SORT_CALC); } - xact_t::xdata_t& rxdata(right->xdata()); - if (! rxdata.has_flags(XACT_EXT_SORT_CALC)) { + post_t::xdata_t& rxdata(right->xdata()); + if (! rxdata.has_flags(POST_EXT_SORT_CALC)) { find_sort_values(rxdata.sort_values, right); - rxdata.add_flags(XACT_EXT_SORT_CALC); + rxdata.add_flags(POST_EXT_SORT_CALC); } return sort_value_is_less_than(lxdata.sort_values, rxdata.sort_values); diff --git a/src/compare.h b/src/compare.h index bf85e1c7..92cee665 100644 --- a/src/compare.h +++ b/src/compare.h @@ -47,7 +47,7 @@ #define _COMPARE_H #include "expr.h" -#include "xact.h" +#include "post.h" #include "account.h" namespace ledger { @@ -91,7 +91,7 @@ bool compare_items<T>::operator()(T * left, T * right) } template <> -bool compare_items<xact_t>::operator()(xact_t * left, xact_t * right); +bool compare_items<post_t>::operator()(post_t * left, post_t * right); template <> bool compare_items<account_t>::operator()(account_t * left, account_t * right); diff --git a/src/derive.cc b/src/derive.cc index 8ea07c87..f6b594e0 100644 --- a/src/derive.cc +++ b/src/derive.cc @@ -35,7 +35,7 @@ namespace ledger { namespace { - struct entry_template_t + struct xact_template_t { optional<date_t> date; optional<date_t> eff_date; @@ -43,17 +43,17 @@ namespace { optional<string> note; mask_t payee_mask; - struct xact_template_t { + struct post_template_t { bool from; optional<mask_t> account_mask; optional<amount_t> amount; - xact_template_t() : from(false) {} + post_template_t() : from(false) {} }; - std::list<xact_template_t> xacts; + std::list<post_template_t> posts; - entry_template_t() {} + xact_template_t() {} void dump(std::ostream& out) const { @@ -76,52 +76,52 @@ namespace { else out << "Payee mask: " << payee_mask << std::endl; - if (xacts.empty()) { + if (posts.empty()) { out << std::endl - << "<Transaction copied from last related entry>" + << "<Posting copied from last related transaction>" << std::endl; } else { bool has_only_from = true; bool has_only_to = true; - foreach (const xact_template_t& xact, xacts) { - if (xact.from) + foreach (const post_template_t& post, posts) { + if (post.from) has_only_to = false; else has_only_from = false; } - foreach (const xact_template_t& xact, xacts) { + foreach (const post_template_t& post, posts) { out << std::endl - << "[Transaction \"" << (xact.from ? "from" : "to") + << "[Posting \"" << (post.from ? "from" : "to") << "\"]" << std::endl; - if (xact.account_mask) - out << " Account mask: " << *xact.account_mask << std::endl; - else if (xact.from) + if (post.account_mask) + out << " Account mask: " << *post.account_mask << std::endl; + else if (post.from) out << " Account mask: <use last of last related accounts>" << std::endl; else out << " Account mask: <use first of last related accounts>" << std::endl; - if (xact.amount) - out << " Amount: " << *xact.amount << std::endl; + if (post.amount) + out << " Amount: " << *post.amount << std::endl; } } } }; - entry_template_t - args_to_entry_template(value_t::sequence_t::const_iterator begin, + xact_template_t + args_to_xact_template(value_t::sequence_t::const_iterator begin, value_t::sequence_t::const_iterator end) { regex date_mask("([0-9]+(?:[-/.][0-9]+)?(?:[-/.][0-9]+))?(?:=.*)?"); regex dow_mask("(sun|mon|tue|wed|thu|fri|sat)"); smatch what; - entry_template_t tmpl; + xact_template_t tmpl; bool check_for_date = true; - entry_template_t::xact_template_t * xact = NULL; + xact_template_t::post_template_t * post = NULL; for (; begin != end; begin++) { if (check_for_date && @@ -147,12 +147,12 @@ namespace { tmpl.payee_mask = (*++begin).to_string(); } else if (arg == "to" || arg == "from") { - if (! xact || xact->account_mask) { - tmpl.xacts.push_back(entry_template_t::xact_template_t()); - xact = &tmpl.xacts.back(); + if (! post || post->account_mask) { + tmpl.posts.push_back(xact_template_t::post_template_t()); + post = &tmpl.posts.back(); } - xact->account_mask = mask_t((*++begin).to_string()); - xact->from = arg == "from"; + post->account_mask = mask_t((*++begin).to_string()); + post->from = arg == "from"; } else if (arg == "on") { tmpl.date = parse_date((*++begin).to_string()); @@ -186,62 +186,62 @@ namespace { amount_t::PARSE_NO_MIGRATE)) account = mask_t(arg); - if (! xact || - (account && xact->account_mask) || - (! account && xact->amount)) { - tmpl.xacts.push_back(entry_template_t::xact_template_t()); - xact = &tmpl.xacts.back(); + if (! post || + (account && post->account_mask) || + (! account && post->amount)) { + tmpl.posts.push_back(xact_template_t::post_template_t()); + post = &tmpl.posts.back(); } if (account) { - xact->from = false; - xact->account_mask = account; + post->from = false; + post->account_mask = account; } else { - xact->amount = amt; + post->amount = amt; } } } } } - if (! tmpl.xacts.empty()) { + if (! tmpl.posts.empty()) { bool has_only_from = true; bool has_only_to = true; - foreach (entry_template_t::xact_template_t& xact, tmpl.xacts) { - if (xact.from) + foreach (xact_template_t::post_template_t& post, tmpl.posts) { + if (post.from) has_only_to = false; else has_only_from = false; } if (has_only_from) { - tmpl.xacts.push_front(entry_template_t::xact_template_t()); + tmpl.posts.push_front(xact_template_t::post_template_t()); } else if (has_only_to) { - tmpl.xacts.push_back(entry_template_t::xact_template_t()); - tmpl.xacts.back().from = true; + tmpl.posts.push_back(xact_template_t::post_template_t()); + tmpl.posts.back().from = true; } } return tmpl; } - entry_t * derive_entry_from_template(entry_template_t& tmpl, + xact_t * derive_xact_from_template(xact_template_t& tmpl, report_t& report) { if (tmpl.payee_mask.empty()) - throw std::runtime_error("'entry' command requires at least a payee"); + throw std::runtime_error("'xact' command requires at least a payee"); - entry_t * matching = NULL; + xact_t * matching = NULL; journal_t& journal(*report.session.journal.get()); - std::auto_ptr<entry_t> added(new entry_t); + std::auto_ptr<xact_t> added(new xact_t); - entries_list::reverse_iterator j; + xacts_list::reverse_iterator j; - for (j = journal.entries.rbegin(); - j != journal.entries.rend(); + for (j = journal.xacts.rbegin(); + j != journal.xacts.rend(); j++) { if (tmpl.payee_mask.match((*j)->payee)) { matching = *j; @@ -270,112 +270,114 @@ namespace { if (tmpl.note) added->note = tmpl.note; - if (tmpl.xacts.empty()) { + if (tmpl.posts.empty()) { if (matching) { - foreach (xact_t * xact, matching->xacts) - added->add_xact(new xact_t(*xact)); + foreach (post_t * post, matching->posts) + added->add_post(new post_t(*post)); } else { throw_(std::runtime_error, - "No accounts, and no past entry matching '" << tmpl.payee_mask <<"'"); + "No accounts, and no past transaction matching '" + << tmpl.payee_mask <<"'"); } } else { - bool any_xact_has_amount = false; - foreach (entry_template_t::xact_template_t& xact, tmpl.xacts) { - if (xact.amount) { - any_xact_has_amount = true; + bool any_post_has_amount = false; + foreach (xact_template_t::post_template_t& post, tmpl.posts) { + if (post.amount) { + any_post_has_amount = true; break; } } - foreach (entry_template_t::xact_template_t& xact, tmpl.xacts) { - std::auto_ptr<xact_t> new_xact; + foreach (xact_template_t::post_template_t& post, tmpl.posts) { + std::auto_ptr<post_t> new_post; commodity_t * found_commodity = NULL; if (matching) { - if (xact.account_mask) { - foreach (xact_t * x, matching->xacts) { - if (xact.account_mask->match(x->account->fullname())) { - new_xact.reset(new xact_t(*x)); + if (post.account_mask) { + foreach (post_t * x, matching->posts) { + if (post.account_mask->match(x->account->fullname())) { + new_post.reset(new post_t(*x)); break; } } } else { - if (xact.from) - new_xact.reset(new xact_t(*matching->xacts.back())); + if (post.from) + new_post.reset(new post_t(*matching->posts.back())); else - new_xact.reset(new xact_t(*matching->xacts.front())); + new_post.reset(new post_t(*matching->posts.front())); } } - if (! new_xact.get()) - new_xact.reset(new xact_t); + if (! new_post.get()) + new_post.reset(new post_t); - if (! new_xact->account) { - if (xact.account_mask) { + if (! new_post->account) { + if (post.account_mask) { account_t * acct = NULL; if (! acct) - acct = journal.find_account_re(xact.account_mask->expr.str()); + acct = journal.find_account_re(post.account_mask->expr.str()); if (! acct) - acct = journal.find_account(xact.account_mask->expr.str()); + acct = journal.find_account(post.account_mask->expr.str()); // Find out the default commodity to use by looking at the last // commodity used in that account - entries_list::reverse_iterator j; + xacts_list::reverse_iterator j; - for (j = journal.entries.rbegin(); - j != journal.entries.rend(); + for (j = journal.xacts.rbegin(); + j != journal.xacts.rend(); j++) { - foreach (xact_t * x, (*j)->xacts) { + foreach (post_t * x, (*j)->posts) { if (x->account == acct && ! x->amount.is_null()) { - new_xact.reset(new xact_t(*x)); + new_post.reset(new post_t(*x)); break; } } } - if (! new_xact.get()) - new_xact.reset(new xact_t); + if (! new_post.get()) + new_post.reset(new post_t); - new_xact->account = acct; + new_post->account = acct; } else { - if (xact.from) - new_xact->account = journal.find_account("Liabilities:Unknown"); + if (post.from) + new_post->account = journal.find_account("Liabilities:Unknown"); else - new_xact->account = journal.find_account("Expenses:Unknown"); + new_post->account = journal.find_account("Expenses:Unknown"); } } - if (new_xact.get() && ! new_xact->amount.is_null()) { - found_commodity = &new_xact->amount.commodity(); + if (new_post.get() && ! new_post->amount.is_null()) { + found_commodity = &new_post->amount.commodity(); - if (any_xact_has_amount) - new_xact->amount = amount_t(); + if (any_post_has_amount) + new_post->amount = amount_t(); else - any_xact_has_amount = true; + any_post_has_amount = true; } - if (xact.amount) { - new_xact->amount = *xact.amount; - if (xact.from) - new_xact->amount.in_place_negate(); + if (post.amount) { + new_post->amount = *post.amount; + if (post.from) + new_post->amount.in_place_negate(); } if (found_commodity && - ! new_xact->amount.is_null() && - ! new_xact->amount.has_commodity()) { - new_xact->amount.set_commodity(*found_commodity); - new_xact->amount = new_xact->amount.rounded(); + ! new_post->amount.is_null() && + ! new_post->amount.has_commodity()) { + new_post->amount.set_commodity(*found_commodity); + new_post->amount = new_post->amount.rounded(); } - added->add_xact(new_xact.release()); + added->add_post(new_post.release()); } } - if (! journal.entry_finalize_hooks.run_hooks(*added.get(), false) || + if (! journal.xact_finalize_hooks.run_hooks(*added.get(), false) || ! added->finalize() || - ! journal.entry_finalize_hooks.run_hooks(*added.get(), true)) - throw std::runtime_error("Failed to finalize derived entry (check commodities)"); + ! journal.xact_finalize_hooks.run_hooks(*added.get(), true)) + throw_(std::runtime_error, + "Failed to finalize derived transaction (check commodities)"); return added.release(); } @@ -393,27 +395,27 @@ value_t template_command(call_scope_t& args) args.value().dump(out); out << std::endl << std::endl; - entry_template_t tmpl = args_to_entry_template(begin, end); + xact_template_t tmpl = args_to_xact_template(begin, end); - out << "--- Entry template ---" << std::endl; + out << "--- Transaction template ---" << std::endl; tmpl.dump(out); return true; } -value_t entry_command(call_scope_t& args) +value_t xact_command(call_scope_t& args) { value_t::sequence_t::const_iterator begin = args.value().begin(); value_t::sequence_t::const_iterator end = args.value().end(); report_t& report(find_scope<report_t>(args)); - entry_template_t tmpl = args_to_entry_template(begin, end); - std::auto_ptr<entry_t> new_entry(derive_entry_from_template(tmpl, report)); + xact_template_t tmpl = args_to_xact_template(begin, end); + std::auto_ptr<xact_t> new_xact(derive_xact_from_template(tmpl, report)); - report.entry_report(xact_handler_ptr - (new format_xacts(report, + report.xact_report(post_handler_ptr + (new format_posts(report, report.HANDLER(print_format_).str())), - *new_entry.get()); + *new_xact.get()); return true; } diff --git a/src/derive.h b/src/derive.h index 2cefc3bf..9825d496 100644 --- a/src/derive.h +++ b/src/derive.h @@ -50,12 +50,12 @@ namespace ledger { -value_t entry_command(call_scope_t& args); +value_t xact_command(call_scope_t& args); value_t template_command(call_scope_t& args); -class entry_t; +class xact_t; class report_t; -entry_t * derive_new_entry(report_t& report, +xact_t * derive_new_xact(report_t& report, value_t::sequence_t::const_iterator i, value_t::sequence_t::const_iterator end); diff --git a/src/emacs.cc b/src/emacs.cc index 3c3c1b7b..fb54783b 100644 --- a/src/emacs.cc +++ b/src/emacs.cc @@ -34,50 +34,50 @@ namespace ledger { -void format_emacs_xacts::write_entry(entry_t& entry) +void format_emacs_posts::write_xact(xact_t& xact) { - out << "\"" << entry.pathname << "\" " - << (static_cast<std::size_t>(entry.beg_line) + 1) << " "; + out << "\"" << xact.pathname << "\" " + << (static_cast<std::size_t>(xact.beg_line) + 1) << " "; - tm when = gregorian::to_tm(entry.date()); + tm when = gregorian::to_tm(xact.date()); std::time_t date = std::mktime(&when); // jww (2008-04-20): Is this GMT or local? out << "(" << (date / 65536) << " " << (date % 65536) << " 0) "; - if (! entry.code) + if (! xact.code) out << "nil "; else - out << "\"" << *entry.code << "\" "; + out << "\"" << *xact.code << "\" "; - if (entry.payee.empty()) + if (xact.payee.empty()) out << "nil"; else - out << "\"" << entry.payee << "\""; + out << "\"" << xact.payee << "\""; out << "\n"; } -void format_emacs_xacts::operator()(xact_t& xact) +void format_emacs_posts::operator()(post_t& post) { - if (! xact.has_xdata() || - ! xact.xdata().has_flags(XACT_EXT_DISPLAYED)) { - if (! last_entry) { + if (! post.has_xdata() || + ! post.xdata().has_flags(POST_EXT_DISPLAYED)) { + if (! last_xact) { out << "(("; - write_entry(*xact.entry); + write_xact(*post.xact); } - else if (xact.entry != last_entry) { + else if (post.xact != last_xact) { out << ")\n ("; - write_entry(*xact.entry); + write_xact(*post.xact); } else { out << "\n"; } - out << " (" << (static_cast<std::size_t>(xact.beg_line) + 1) << " "; - out << "\"" << xact.reported_account()->fullname() << "\" \"" - << xact.amount << "\""; + out << " (" << (static_cast<std::size_t>(post.beg_line) + 1) << " "; + out << "\"" << post.reported_account()->fullname() << "\" \"" + << post.amount << "\""; - switch (xact.state()) { + switch (post.state()) { case item_t::CLEARED: out << " t"; break; @@ -89,15 +89,15 @@ void format_emacs_xacts::operator()(xact_t& xact) break; } - if (xact.cost) - out << " \"" << *xact.cost << "\""; - if (xact.note) - out << " \"" << *xact.note << "\""; + if (post.cost) + out << " \"" << *post.cost << "\""; + if (post.note) + out << " \"" << *post.note << "\""; out << ")"; - last_entry = xact.entry; + last_xact = post.xact; - xact.xdata().add_flags(XACT_EXT_DISPLAYED); + post.xdata().add_flags(POST_EXT_DISPLAYED); } } diff --git a/src/emacs.h b/src/emacs.h index 868a899b..dec7d183 100644 --- a/src/emacs.h +++ b/src/emacs.h @@ -55,30 +55,30 @@ namespace ledger { * * Long. */ -class format_emacs_xacts : public item_handler<xact_t> +class format_emacs_posts : public item_handler<post_t> { - format_emacs_xacts(); + format_emacs_posts(); protected: std::ostream& out; - entry_t * last_entry; + xact_t * last_xact; public: - format_emacs_xacts(std::ostream& _out) - : out(_out), last_entry(NULL) { - TRACE_CTOR(format_emacs_xacts, "std::ostream&"); + format_emacs_posts(std::ostream& _out) + : out(_out), last_xact(NULL) { + TRACE_CTOR(format_emacs_posts, "std::ostream&"); } - ~format_emacs_xacts() { - TRACE_DTOR(format_emacs_xacts); + ~format_emacs_posts() { + TRACE_DTOR(format_emacs_posts); } - virtual void write_entry(entry_t& entry); + virtual void write_xact(xact_t& xact); virtual void flush() { - if (last_entry) + if (last_xact) out << "))\n"; out.flush(); } - virtual void operator()(xact_t& xact); + virtual void operator()(post_t& post); }; } // namespace ledger diff --git a/src/entry.cc b/src/entry.cc deleted file mode 100644 index eceec5f7..00000000 --- a/src/entry.cc +++ /dev/null @@ -1,425 +0,0 @@ -/* - * Copyright (c) 2003-2009, John Wiegley. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of New Artisans LLC nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "entry.h" -#include "journal.h" -#include "account.h" -#include "format.h" - -namespace ledger { - -entry_base_t::entry_base_t(const entry_base_t&) - : item_t(), journal(NULL) -{ - TRACE_CTOR(entry_base_t, "copy"); -} - -entry_base_t::~entry_base_t() -{ - TRACE_DTOR(entry_base_t); - - foreach (xact_t * xact, xacts) { - // If the transaction is a temporary, it will be destructed when the - // temporary is. - if (! xact->has_flags(ITEM_TEMP)) - checked_delete(xact); - } -} - -item_t::state_t entry_base_t::state() const -{ - state_t result = CLEARED; - - foreach (xact_t * xact, xacts) { - if (xact->_state == UNCLEARED) - return UNCLEARED; - else if (xact->_state == PENDING) - result = PENDING; - } - return result; -} - -void entry_base_t::add_xact(xact_t * xact) -{ - xacts.push_back(xact); -} - -bool entry_base_t::remove_xact(xact_t * xact) -{ - xacts.remove(xact); - xact->entry = NULL; - return true; -} - -bool entry_base_t::finalize() -{ - // Scan through and compute the total balance for the entry. This is used - // for auto-calculating the value of entries with no cost, and the per-unit - // price of unpriced commodities. - - value_t balance; - xact_t * null_xact = NULL; - - foreach (xact_t * xact, xacts) { - if (xact->must_balance()) { - amount_t& p(xact->cost ? *xact->cost : xact->amount); - DEBUG("entry.finalize", "xact must balance = " << p); - if (! p.is_null()) { - if (p.keep_precision()) { - // If the amount was a cost, it very likely has the "keep_precision" - // flag set, meaning commodity display precision is ignored when - // displaying the amount. We never want this set for the balance, - // so we must clear the flag in a temporary to avoid it propagating - // into the balance. - add_or_set_value(balance, p.rounded()); - } else { - add_or_set_value(balance, p); - } - } else { - if (null_xact) - throw_(std::logic_error, - "Only one xact with null amount allowed per entry"); - else - null_xact = xact; - } - } - } - assert(balance.valid()); - - DEBUG("entry.finalize", "initial balance = " << balance); - - // If there is only one xact, balance against the default account if one has - // been set. - - if (journal && journal->basket && xacts.size() == 1 && ! balance.is_null()) { - // jww (2008-07-24): Need to make the rest of the code aware of what to do - // when it sees a generated xact. - null_xact = new xact_t(journal->basket, ITEM_GENERATED); - null_xact->_state = (*xacts.begin())->_state; - add_xact(null_xact); - } - - if (null_xact != NULL) { - // If one xact has no value at all, its value will become the inverse of - // the rest. If multiple commodities are involved, multiple xacts are - // generated to balance them all. - - if (balance.is_balance()) { - bool first = true; - const balance_t& bal(balance.as_balance()); - foreach (const balance_t::amounts_map::value_type& pair, bal.amounts) { - if (first) { - null_xact->amount = pair.second.negated(); - first = false; - } else { - add_xact(new xact_t(null_xact->account, pair.second.negated(), - ITEM_GENERATED)); - } - } - } - else if (balance.is_amount()) { - null_xact->amount = balance.as_amount().negated(); - null_xact->add_flags(XACT_CALCULATED); - } - else if (! balance.is_null() && ! balance.is_realzero()) { - throw_(balance_error, "Entry does not balance"); - } - balance = NULL_VALUE; - - } - else if (balance.is_balance() && - balance.as_balance().amounts.size() == 2) { - // When an entry involves two different commodities (regardless of how - // many xacts there are) determine the conversion ratio by dividing the - // total value of one commodity by the total value of the other. This - // establishes the per-unit cost for this xact for both commodities. - - DEBUG("entry.finalize", "there were exactly two commodities"); - - bool saw_cost = false; - xact_t * top_xact = NULL; - - foreach (xact_t * xact, xacts) { - if (! xact->amount.is_null()) - if (xact->amount.is_annotated()) - top_xact = xact; - else if (! top_xact) - top_xact = xact; - - if (xact->cost) { - saw_cost = true; - break; - } - } - - if (! saw_cost && top_xact) { - const balance_t& bal(balance.as_balance()); - - DEBUG("entry.finalize", "there were no costs, and a valid top_xact"); - - balance_t::amounts_map::const_iterator a = bal.amounts.begin(); - - const amount_t * x = &(*a++).second; - const amount_t * y = &(*a++).second; - - if (x->commodity() != top_xact->amount.commodity()) { - const amount_t * t = x; - x = y; - y = t; - } - - DEBUG("entry.finalize", "primary amount = " << *y); - DEBUG("entry.finalize", "secondary amount = " << *x); - - commodity_t& comm(x->commodity()); - amount_t per_unit_cost; - amount_t total_cost; - - foreach (xact_t * xact, xacts) { - if (xact != top_xact && xact->must_balance() && - ! xact->amount.is_null() && - xact->amount.is_annotated() && - xact->amount.annotation().price) { - amount_t temp = *xact->amount.annotation().price * xact->amount; - if (total_cost.is_null()) { - total_cost = temp; - y = &total_cost; - } else { - total_cost += temp; - } - DEBUG("entry.finalize", "total_cost = " << total_cost); - } - } - per_unit_cost = (*y / *x).abs(); - - DEBUG("entry.finalize", "per_unit_cost = " << per_unit_cost); - - foreach (xact_t * xact, xacts) { - const amount_t& amt(xact->amount); - - if (xact->must_balance() && amt.commodity() == comm) { - balance -= amt; - xact->cost = per_unit_cost * amt; - balance += *xact->cost; - - DEBUG("entry.finalize", "set xact->cost to = " << *xact->cost); - } - } - } - - DEBUG("entry.finalize", "resolved balance = " << balance); - } - - // Now that the xact list has its final form, calculate the balance once - // more in terms of total cost, accounting for any possible gain/loss - // amounts. - - foreach (xact_t * xact, xacts) { - if (xact->cost) { - if (xact->amount.commodity() == xact->cost->commodity()) - throw_(balance_error, "Transaction's cost must be of a different commodity"); - - commodity_t::cost_breakdown_t breakdown = - commodity_t::exchange(xact->amount, *xact->cost, false, - datetime_t(date(), time_duration(0, 0, 0, 0))); - - if (xact->amount.is_annotated() && - breakdown.basis_cost.commodity() == - breakdown.final_cost.commodity()) - add_or_set_value(balance, (breakdown.basis_cost - - breakdown.final_cost).rounded()); - else - xact->amount = breakdown.amount; - } - } - - DEBUG("entry.finalize", "final balance = " << balance); - - if (! balance.is_null() && ! balance.is_zero()) { - add_error_context(item_context(*this, "While balancing entry")); - add_error_context("Unbalanced remainder is:"); - add_error_context(value_context(balance)); - throw_(balance_error, "Entry does not balance"); - } - - // Add the final calculated totals each to their related account - - if (dynamic_cast<entry_t *>(this)) { - bool all_null = true; - foreach (xact_t * xact, xacts) { - if (! xact->amount.is_null()) { - all_null = false; - - // jww (2008-08-09): For now, this feature only works for non-specific - // commodities. - add_or_set_value(xact->account->xdata().value, xact->amount); - - DEBUG("entry.finalize.totals", - "Total for " << xact->account->fullname() << " + " - << xact->amount << ": " << xact->account->xdata().value); - } - } - if (all_null) - return false; // ignore this entry completely - } - - return true; -} - -entry_t::entry_t(const entry_t& e) - : entry_base_t(e), code(e.code), payee(e.payee) -{ - TRACE_CTOR(entry_t, "copy"); -} - -void entry_t::add_xact(xact_t * xact) -{ - xact->entry = this; - entry_base_t::add_xact(xact); -} - -namespace { - value_t get_code(entry_t& entry) { - if (entry.code) - return string_value(*entry.code); - else - return string_value(empty_string); - } - - value_t get_payee(entry_t& entry) { - return string_value(entry.payee); - } - - template <value_t (*Func)(entry_t&)> - value_t get_wrapper(call_scope_t& scope) { - return (*Func)(find_scope<entry_t>(scope)); - } -} - -expr_t::ptr_op_t entry_t::lookup(const string& name) -{ - switch (name[0]) { - case 'c': - if (name == "code") - return WRAP_FUNCTOR(get_wrapper<&get_code>); - break; - - case 'p': - if (name[1] == '\0' || name == "payee") - return WRAP_FUNCTOR(get_wrapper<&get_payee>); - break; - } - - return item_t::lookup(name); -} - -bool entry_t::valid() const -{ - if (! _date || ! journal) { - DEBUG("ledger.validate", "entry_t: ! _date || ! journal"); - return false; - } - - foreach (xact_t * xact, xacts) - if (xact->entry != this || ! xact->valid()) { - DEBUG("ledger.validate", "entry_t: xact not valid"); - return false; - } - - return true; -} - -void auto_entry_t::extend_entry(entry_base_t& entry, bool post) -{ - xacts_list initial_xacts(entry.xacts.begin(), entry.xacts.end()); - - foreach (xact_t * initial_xact, initial_xacts) { - if (! initial_xact->has_flags(XACT_AUTO) && predicate(*initial_xact)) { - foreach (xact_t * xact, xacts) { - amount_t amt; - assert(xact->amount); - if (! xact->amount.commodity()) { - if (! post) - continue; - assert(initial_xact->amount); - amt = initial_xact->amount * xact->amount; - } else { - if (post) - continue; - amt = xact->amount; - } - - IF_DEBUG("entry.extend") { - DEBUG("entry.extend", - "Initial xact on line " << initial_xact->beg_line << ": " - << "amount " << initial_xact->amount << " (precision " - << initial_xact->amount.precision() << ")"); - - if (initial_xact->amount.keep_precision()) - DEBUG("entry.extend", " precision is kept"); - - DEBUG("entry.extend", - "Transaction on line " << xact->beg_line << ": " - << "amount " << xact->amount << ", amt " << amt - << " (precision " << xact->amount.precision() - << " != " << amt.precision() << ")"); - - if (xact->amount.keep_precision()) - DEBUG("entry.extend", " precision is kept"); - if (amt.keep_precision()) - DEBUG("entry.extend", " amt precision is kept"); - } - - account_t * account = xact->account; - string fullname = account->fullname(); - assert(! fullname.empty()); - if (fullname == "$account" || fullname == "@account") - account = initial_xact->account; - - // Copy over details so that the resulting xact is a mirror of - // the automated entry's one. - xact_t * new_xact = new xact_t(account, amt); - new_xact->copy_details(*xact); - new_xact->add_flags(XACT_AUTO); - - entry.add_xact(new_xact); - } - } - } -} - -void extend_entry_base(journal_t * journal, entry_base_t& base, bool post) -{ - foreach (auto_entry_t * entry, journal->auto_entries) - entry->extend_entry(base, post); -} - -} // namespace ledger diff --git a/src/entry.h b/src/entry.h deleted file mode 100644 index 726b0c51..00000000 --- a/src/entry.h +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Copyright (c) 2003-2009, John Wiegley. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of New Artisans LLC nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @addtogroup data - */ - -/** - * @file entry.h - * @author John Wiegley - * - * @ingroup data - * - * @brief Brief - * - * Long. - */ -#ifndef _ENTRY_H -#define _ENTRY_H - -#include "xact.h" -#include "predicate.h" - -namespace ledger { - -class journal_t; - -/** - * @brief Brief - * - * Long. - */ -class entry_base_t : public item_t -{ -public: - journal_t * journal; - - xacts_list xacts; - - entry_base_t() : item_t(), journal(NULL) { - TRACE_CTOR(entry_base_t, ""); - } - entry_base_t(const entry_base_t& e); - - virtual ~entry_base_t(); - - virtual state_t state() const; - - virtual void add_xact(xact_t * xact); - virtual bool remove_xact(xact_t * xact); - - virtual bool finalize(); - virtual bool valid() const = 0; -}; - -/** - * @brief Brief - * - * Long. - */ -class entry_t : public entry_base_t -{ -public: - optional<string> code; - string payee; - - entry_t() { - TRACE_CTOR(entry_t, ""); - } - entry_t(const entry_t& e); - - virtual ~entry_t() { - TRACE_DTOR(entry_t); - } - - virtual void add_xact(xact_t * xact); - - virtual expr_t::ptr_op_t lookup(const string& name); - - virtual bool valid() const; -}; - -/** - * @brief Brief - * - * Long. - */ -struct entry_finalizer_t { - virtual ~entry_finalizer_t() {} - virtual bool operator()(entry_t& entry, bool post) = 0; -}; - -/** - * @brief Brief - * - * Long. - */ -class auto_entry_t : public entry_base_t -{ -public: - item_predicate predicate; - - auto_entry_t() { - TRACE_CTOR(auto_entry_t, ""); - } - auto_entry_t(const auto_entry_t& other) - : entry_base_t(), predicate(other.predicate) { - TRACE_CTOR(auto_entry_t, "copy"); - } - auto_entry_t(const item_predicate& _predicate) - : predicate(_predicate) - { - TRACE_CTOR(auto_entry_t, "const item_predicate<xact_t>&"); - } - - virtual ~auto_entry_t() { - TRACE_DTOR(auto_entry_t); - } - - virtual void extend_entry(entry_base_t& entry, bool post); - virtual bool valid() const { - return true; - } -}; - -/** - * @brief Brief - * - * Long. - */ -struct auto_entry_finalizer_t : public entry_finalizer_t -{ - journal_t * journal; - - auto_entry_finalizer_t() : journal(NULL) { - TRACE_CTOR(auto_entry_finalizer_t, ""); - } - auto_entry_finalizer_t(const auto_entry_finalizer_t& other) - : entry_finalizer_t(), journal(other.journal) { - TRACE_CTOR(auto_entry_finalizer_t, "copy"); - } - auto_entry_finalizer_t(journal_t * _journal) : journal(_journal) { - TRACE_CTOR(auto_entry_finalizer_t, "journal_t *"); - } - ~auto_entry_finalizer_t() throw() { - TRACE_DTOR(auto_entry_finalizer_t); - } - - virtual bool operator()(entry_t& entry, bool post); -}; - -/** - * @brief Brief - * - * Long. - */ -class period_entry_t : public entry_base_t -{ - public: - interval_t period; - string period_string; - - period_entry_t() { - TRACE_CTOR(period_entry_t, ""); - } - period_entry_t(const period_entry_t& e) - : entry_base_t(e), period(e.period), period_string(e.period_string) { - TRACE_CTOR(period_entry_t, "copy"); - } - period_entry_t(const string& _period) - : period(_period), period_string(_period) { - TRACE_CTOR(period_entry_t, "const string&"); - } - - virtual ~period_entry_t() throw() { - TRACE_DTOR(period_entry_t); - } - - virtual bool valid() const { - return period; - } -}; - -/** - * @brief Brief - * - * Long. - */ -class func_finalizer_t : public entry_finalizer_t -{ - func_finalizer_t(); - -public: - typedef function<bool (entry_t& entry, bool post)> func_t; - - func_t func; - - func_finalizer_t(func_t _func) : func(_func) { - TRACE_CTOR(func_finalizer_t, "func_t"); - } - func_finalizer_t(const func_finalizer_t& other) : - entry_finalizer_t(), func(other.func) { - TRACE_CTOR(func_finalizer_t, "copy"); - } - ~func_finalizer_t() throw() { - TRACE_DTOR(func_finalizer_t); - } - - virtual bool operator()(entry_t& entry, bool post) { - return func(entry, post); - } -}; - -void extend_entry_base(journal_t * journal, entry_base_t& entry, bool post); - -inline bool auto_entry_finalizer_t::operator()(entry_t& entry, bool post) { - extend_entry_base(journal, entry, post); - return true; -} - -typedef std::list<entry_t *> entries_list; -typedef std::list<auto_entry_t *> auto_entries_list; -typedef std::list<period_entry_t *> period_entries_list; - -} // namespace ledger - -#endif // _ENTRY_H diff --git a/src/filters.cc b/src/filters.cc index e0c67024..ade349bd 100644 --- a/src/filters.cc +++ b/src/filters.cc @@ -37,46 +37,46 @@ namespace ledger { -pass_down_xacts::pass_down_xacts(xact_handler_ptr handler, - xacts_iterator& iter) - : item_handler<xact_t>(handler) +pass_down_posts::pass_down_posts(post_handler_ptr handler, + posts_iterator& iter) + : item_handler<post_t>(handler) { - TRACE_CTOR(pass_down_xacts, "xact_handler_ptr, xacts_iterator"); + TRACE_CTOR(pass_down_posts, "post_handler_ptr, posts_iterator"); - for (xact_t * xact = iter(); xact; xact = iter()) { + for (post_t * post = iter(); post; post = iter()) { try { - item_handler<xact_t>::operator()(*xact); + item_handler<post_t>::operator()(*post); } catch (const std::exception& err) { - add_error_context(item_context(*xact, "While handling transaction")); + add_error_context(item_context(*post, "While handling posting")); throw; } } - item_handler<xact_t>::flush(); + item_handler<post_t>::flush(); } -void truncate_entries::flush() +void truncate_xacts::flush() { - if (! xacts.size()) + if (! posts.size()) return; - entry_t * last_entry = (*xacts.begin())->entry; + xact_t * last_xact = (*posts.begin())->xact; int l = 0; - foreach (xact_t * xact, xacts) - if (last_entry != xact->entry) { + foreach (post_t * post, posts) + if (last_xact != post->xact) { l++; - last_entry = xact->entry; + last_xact = post->xact; } l++; - last_entry = (*xacts.begin())->entry; + last_xact = (*posts.begin())->xact; int i = 0; - foreach (xact_t * xact, xacts) { - if (last_entry != xact->entry) { - last_entry = xact->entry; + foreach (post_t * post, posts) { + if (last_xact != post->xact) { + last_xact = post->xact; i++; } @@ -96,44 +96,44 @@ void truncate_entries::flush() } if (print) - item_handler<xact_t>::operator()(*xact); + item_handler<post_t>::operator()(*post); } - xacts.clear(); + posts.clear(); - item_handler<xact_t>::flush(); + item_handler<post_t>::flush(); } -void set_account_value::operator()(xact_t& xact) +void set_account_value::operator()(post_t& post) { - account_t * acct = xact.reported_account(); + account_t * acct = post.reported_account(); account_t::xdata_t& xdata(acct->xdata()); DEBUG("account.sums", "Account value was = " << xdata.value); - xact.add_to_value(xdata.value, amount_expr); + post.add_to_value(xdata.value, amount_expr); DEBUG("account.sums", "Account value is = " << xdata.value); xdata.count++; - if (xact.has_flags(XACT_VIRTUAL)) + if (post.has_flags(POST_VIRTUAL)) xdata.virtuals++; DEBUG("account.display", - "Visiting account: " << xact.account->fullname()); - xact.account->xdata().add_flags(ACCOUNT_EXT_VISITED); + "Visiting account: " << post.account->fullname()); + post.account->xdata().add_flags(ACCOUNT_EXT_VISITED); - item_handler<xact_t>::operator()(xact); + item_handler<post_t>::operator()(post); } -void sort_xacts::post_accumulated_xacts() +void sort_posts::post_accumulated_posts() { - std::stable_sort(xacts.begin(), xacts.end(), - compare_items<xact_t>(sort_order)); + std::stable_sort(posts.begin(), posts.end(), + compare_items<post_t>(sort_order)); - foreach (xact_t * xact, xacts) { - xact->xdata().drop_flags(XACT_EXT_SORT_CALC); - item_handler<xact_t>::operator()(*xact); + foreach (post_t * post, posts) { + post->xdata().drop_flags(POST_EXT_SORT_CALC); + item_handler<post_t>::operator()(*post); } - xacts.clear(); + posts.clear(); } namespace { @@ -150,96 +150,96 @@ namespace { } } -void anonymize_xacts::operator()(xact_t& xact) +void anonymize_posts::operator()(post_t& post) { SHA1 sha; uint_least32_t message_digest[5]; - bool copy_entry_details = false; + bool copy_xact_details = false; - if (last_entry != xact.entry) { - entry_temps.push_back(*xact.entry); - last_entry = xact.entry; - copy_entry_details = true; + if (last_xact != post.xact) { + xact_temps.push_back(*post.xact); + last_xact = post.xact; + copy_xact_details = true; } - entry_t& entry = entry_temps.back(); + xact_t& xact = xact_temps.back(); - if (copy_entry_details) { - entry.copy_details(*xact.entry); + if (copy_xact_details) { + xact.copy_details(*post.xact); sha.Reset(); - sha << xact.entry->payee.c_str(); + sha << post.xact->payee.c_str(); sha.Result(message_digest); - entry.payee = to_hex(message_digest); - entry.note = none; + xact.payee = to_hex(message_digest); + xact.note = none; } - xact_temps.push_back(xact); - xact_t& temp = xact_temps.back(); - temp.entry = &entry; + post_temps.push_back(post); + post_t& temp = post_temps.back(); + temp.xact = &xact; sha.Reset(); - sha << xact.account->fullname().c_str(); + sha << post.account->fullname().c_str(); sha.Result(message_digest); - temp.copy_details(xact); + temp.copy_details(post); - temp.account = xact.entry->journal->find_account(to_hex(message_digest)); + temp.account = post.xact->journal->find_account(to_hex(message_digest)); temp.note = none; temp.add_flags(ITEM_TEMP); - entry.add_xact(&temp); + xact.add_post(&temp); (*handler)(temp); } -void calc_xacts::operator()(xact_t& xact) +void calc_posts::operator()(post_t& post) { - xact_t::xdata_t& xdata(xact.xdata()); + post_t::xdata_t& xdata(post.xdata()); - if (last_xact) { - assert(last_xact->has_xdata()); - add_or_set_value(xdata.total, last_xact->xdata().total); - xdata.count = last_xact->xdata().count + 1; + if (last_post) { + assert(last_post->has_xdata()); + add_or_set_value(xdata.total, last_post->xdata().total); + xdata.count = last_post->xdata().count + 1; } else { xdata.count = 1; } - xact.add_to_value(xdata.total, amount_expr); + post.add_to_value(xdata.total, amount_expr); - item_handler<xact_t>::operator()(xact); + item_handler<post_t>::operator()(post); - last_xact = &xact; + last_post = &post; } namespace { void handle_value(const value_t& value, account_t * account, - entry_t * entry, + xact_t * xact, unsigned int flags, - std::list<xact_t>& temps, - item_handler<xact_t>& handler, + std::list<post_t>& temps, + item_handler<post_t>& handler, const date_t& date = date_t(), const value_t& total = value_t()) { - temps.push_back(xact_t(account)); - xact_t& xact(temps.back()); - xact.entry = entry; - xact.add_flags(ITEM_TEMP); - entry->add_xact(&xact); + temps.push_back(post_t(account)); + post_t& post(temps.back()); + post.xact = xact; + post.add_flags(ITEM_TEMP); + xact->add_post(&post); - // If the account for this xact is all virtual, then report the xact as + // If the account for this post is all virtual, then report the post as // such. This allows subtotal reports to show "(Account)" for accounts - // that contain only virtual xacts. + // that contain only virtual posts. if (account && account->has_xdata()) { if (! account->xdata().has_flags(ACCOUNT_EXT_HAS_NON_VIRTUALS)) { - xact.add_flags(XACT_VIRTUAL); + post.add_flags(POST_VIRTUAL); if (! account->xdata().has_flags(ACCOUNT_EXT_HAS_UNB_VIRTUALS)) - xact.add_flags(XACT_MUST_BALANCE); + post.add_flags(POST_MUST_BALANCE); } } - xact_t::xdata_t& xdata(xact.xdata()); + post_t::xdata_t& xdata(post.xdata()); if (is_valid(date)) xdata.date = date; @@ -253,13 +253,13 @@ namespace { // fall through... case value_t::AMOUNT: - xact.amount = temp.as_amount(); + post.amount = temp.as_amount(); break; case value_t::BALANCE: case value_t::SEQUENCE: xdata.value = temp; - flags |= XACT_EXT_COMPOUND; + flags |= POST_EXT_COMPOUND; break; case value_t::DATETIME: @@ -275,120 +275,120 @@ namespace { if (flags) xdata.add_flags(flags); - handler(xact); + handler(post); } } -void collapse_xacts::report_subtotal() +void collapse_posts::report_subtotal() { if (! count) return; std::size_t displayed_count = 0; - foreach (xact_t * xact, component_xacts) { - if (only_predicate(*xact) && display_predicate(*xact)) + foreach (post_t * post, component_posts) { + if (only_predicate(*post) && display_predicate(*post)) displayed_count++; } if (displayed_count == 1) { - item_handler<xact_t>::operator()(*last_xact); + item_handler<post_t>::operator()(*last_post); } else if (only_collapse_if_zero && ! subtotal.is_zero()) { - foreach (xact_t * xact, component_xacts) - item_handler<xact_t>::operator()(*xact); + foreach (post_t * post, component_posts) + item_handler<post_t>::operator()(*post); } else { date_t earliest_date; - foreach (xact_t * xact, component_xacts) { - date_t reported = xact->date(); + foreach (post_t * post, component_posts) { + date_t reported = post->date(); if (! is_valid(earliest_date) || reported < earliest_date) earliest_date = reported; } - entry_temps.push_back(entry_t()); - entry_t& entry = entry_temps.back(); - entry.payee = last_entry->payee; - entry._date = (is_valid(earliest_date) ? - earliest_date : last_entry->_date); - DEBUG("filter.collapse", "Pseudo-entry date = " << *entry._date); + xact_temps.push_back(xact_t()); + xact_t& xact = xact_temps.back(); + xact.payee = last_xact->payee; + xact._date = (is_valid(earliest_date) ? + earliest_date : last_xact->_date); + DEBUG("filter.collapse", "Pseudo-xact date = " << *xact._date); - handle_value(subtotal, &totals_account, &entry, 0, xact_temps, *handler); + handle_value(subtotal, &totals_account, &xact, 0, post_temps, *handler); } - component_xacts.clear(); + component_posts.clear(); - last_entry = NULL; - last_xact = NULL; + last_xact = NULL; + last_post = NULL; subtotal = 0L; count = 0; } -void collapse_xacts::operator()(xact_t& xact) +void collapse_posts::operator()(post_t& post) { - // If we've reached a new entry, report on the subtotal + // If we've reached a new xact, report on the subtotal // accumulated thus far. - if (last_entry != xact.entry && count > 0) + if (last_xact != post.xact && count > 0) report_subtotal(); - xact.add_to_value(subtotal, amount_expr); + post.add_to_value(subtotal, amount_expr); count++; - component_xacts.push_back(&xact); + component_posts.push_back(&post); - last_entry = xact.entry; - last_xact = &xact; + last_xact = post.xact; + last_post = &post; } -void related_xacts::flush() +void related_posts::flush() { - if (xacts.size() > 0) { - foreach (xact_t * xact, xacts) { - if (xact->entry) { - foreach (xact_t * r_xact, xact->entry->xacts) { - xact_t::xdata_t& xdata(r_xact->xdata()); - if (! xdata.has_flags(XACT_EXT_HANDLED) && - (! xdata.has_flags(XACT_EXT_RECEIVED) ? - ! r_xact->has_flags(XACT_AUTO | XACT_VIRTUAL) : + if (posts.size() > 0) { + foreach (post_t * post, posts) { + if (post->xact) { + foreach (post_t * r_post, post->xact->posts) { + post_t::xdata_t& xdata(r_post->xdata()); + if (! xdata.has_flags(POST_EXT_HANDLED) && + (! xdata.has_flags(POST_EXT_RECEIVED) ? + ! r_post->has_flags(POST_AUTO | POST_VIRTUAL) : also_matching)) { - xdata.add_flags(XACT_EXT_HANDLED); - item_handler<xact_t>::operator()(*r_xact); + xdata.add_flags(POST_EXT_HANDLED); + item_handler<post_t>::operator()(*r_post); } } } else { // This code should only be reachable from the "output" // command, since that is the only command which attempts to - // output auto or period entries. - xact_t::xdata_t& xdata(xact->xdata()); - if (! xdata.has_flags(XACT_EXT_HANDLED) && - ! xact->has_flags(XACT_AUTO)) { - xdata.add_flags(XACT_EXT_HANDLED); - item_handler<xact_t>::operator()(*xact); + // output auto or period xacts. + post_t::xdata_t& xdata(post->xdata()); + if (! xdata.has_flags(POST_EXT_HANDLED) && + ! post->has_flags(POST_AUTO)) { + xdata.add_flags(POST_EXT_HANDLED); + item_handler<post_t>::operator()(*post); } } } } - item_handler<xact_t>::flush(); + item_handler<post_t>::flush(); } -void changed_value_xacts::output_diff(xact_t * xact, const date_t& date) +void changed_value_posts::output_diff(post_t * post, const date_t& date) { if (is_valid(date)) - xact->xdata().date = date; + post->xdata().date = date; value_t repriced_total; try { - bind_scope_t bound_scope(report, *xact); + bind_scope_t bound_scope(report, *post); repriced_total = total_expr.calc(bound_scope); } catch (...) { - xact->xdata().date = date_t(); + post->xdata().date = date_t(); throw; } - xact->xdata().date = date_t(); + post->xdata().date = date_t(); DEBUG("filter.changed_value", "output_diff(last_balance) = " << last_balance); @@ -399,49 +399,49 @@ void changed_value_xacts::output_diff(xact_t * xact, const date_t& date) DEBUG("filter.changed_value", "output_diff(strip(diff)) = " << diff.strip_annotations(report.what_to_keep())); - entry_temps.push_back(entry_t()); - entry_t& entry = entry_temps.back(); - entry.payee = "Commodities revalued"; - entry._date = is_valid(date) ? date : xact->date(); + xact_temps.push_back(xact_t()); + xact_t& xact = xact_temps.back(); + xact.payee = "Commodities revalued"; + xact._date = is_valid(date) ? date : post->date(); - handle_value(diff, &revalued_account, &entry, XACT_EXT_NO_TOTAL, - xact_temps, *handler, *entry._date, repriced_total); + handle_value(diff, &revalued_account, &xact, POST_EXT_NO_TOTAL, + post_temps, *handler, *xact._date, repriced_total); } } -void changed_value_xacts::operator()(xact_t& xact) +void changed_value_posts::operator()(post_t& post) { - if (last_xact) - output_diff(last_xact, xact.date()); + if (last_post) + output_diff(last_post, post.date()); if (changed_values_only) - xact.xdata().add_flags(XACT_EXT_DISPLAYED); + post.xdata().add_flags(POST_EXT_DISPLAYED); - item_handler<xact_t>::operator()(xact); + item_handler<post_t>::operator()(post); - bind_scope_t bound_scope(report, xact); + bind_scope_t bound_scope(report, post); last_balance = total_expr.calc(bound_scope); - last_xact = &xact; + last_post = &post; } -void subtotal_xacts::report_subtotal(const char * spec_fmt, +void subtotal_posts::report_subtotal(const char * spec_fmt, const date_t& start, const date_t& finish) { - if (component_xacts.empty()) + if (component_posts.empty()) return; date_t range_start = start; date_t range_finish = finish; - foreach (xact_t * xact, component_xacts) { - date_t date = xact->date(); + foreach (post_t * post, component_posts) { + date_t date = post->date(); if (! is_valid(range_start) || date < range_start) range_start = date; if (! is_valid(range_finish) || date > range_finish) range_finish = date; } - component_xacts.clear(); + component_posts.clear(); std::ostringstream out_date; if (spec_fmt) { @@ -456,61 +456,61 @@ void subtotal_xacts::report_subtotal(const char * spec_fmt, out_date << format_date(range_finish, std::string("- ") + output_date_format); } - entry_temps.push_back(entry_t()); - entry_t& entry = entry_temps.back(); - entry.payee = out_date.str(); - entry._date = range_start; + xact_temps.push_back(xact_t()); + xact_t& xact = xact_temps.back(); + xact.payee = out_date.str(); + xact._date = range_start; foreach (values_map::value_type& pair, values) - handle_value(pair.second.value, pair.second.account, &entry, 0, - xact_temps, *handler); + handle_value(pair.second.value, pair.second.account, &xact, 0, + post_temps, *handler); values.clear(); } -void subtotal_xacts::operator()(xact_t& xact) +void subtotal_posts::operator()(post_t& post) { - component_xacts.push_back(&xact); + component_posts.push_back(&post); - account_t * acct = xact.reported_account(); + account_t * acct = post.reported_account(); assert(acct); values_map::iterator i = values.find(acct->fullname()); if (i == values.end()) { value_t temp; - xact.add_to_value(temp, amount_expr); + post.add_to_value(temp, amount_expr); std::pair<values_map::iterator, bool> result = values.insert(values_pair(acct->fullname(), acct_value_t(acct, temp))); assert(result.second); } else { - xact.add_to_value((*i).second.value, amount_expr); + post.add_to_value((*i).second.value, amount_expr); } - // If the account for this xact is all virtual, mark it as + // If the account for this post is all virtual, mark it as // such, so that `handle_value' can show "(Account)" for accounts - // that contain only virtual xacts. + // that contain only virtual posts. - if (! xact.has_flags(XACT_VIRTUAL)) - xact.reported_account()->xdata().add_flags(ACCOUNT_EXT_HAS_NON_VIRTUALS); - else if (! xact.has_flags(XACT_MUST_BALANCE)) - xact.reported_account()->xdata().add_flags(ACCOUNT_EXT_HAS_UNB_VIRTUALS); + if (! post.has_flags(POST_VIRTUAL)) + post.reported_account()->xdata().add_flags(ACCOUNT_EXT_HAS_NON_VIRTUALS); + else if (! post.has_flags(POST_MUST_BALANCE)) + post.reported_account()->xdata().add_flags(ACCOUNT_EXT_HAS_UNB_VIRTUALS); } -void interval_xacts::report_subtotal(const date_t& finish) +void interval_posts::report_subtotal(const date_t& finish) { - if (last_xact && interval) { + if (last_post && interval) { if (exact_periods) - subtotal_xacts::report_subtotal(); + subtotal_posts::report_subtotal(); else - subtotal_xacts::report_subtotal(NULL, interval.begin, finish); + subtotal_posts::report_subtotal(NULL, interval.begin, finish); } - last_xact = NULL; + last_post = NULL; } -void interval_xacts::operator()(xact_t& xact) +void interval_posts::operator()(post_t& post) { - date_t date = xact.date(); + date_t date = post.date(); if ((is_valid(interval.begin) && date < interval.begin) || (is_valid(interval.end) && date >= interval.end)) @@ -523,7 +523,7 @@ void interval_xacts::operator()(xact_t& xact) date_t quant = interval.increment(interval.begin); if (date >= quant) { - if (last_xact) + if (last_post) report_subtotal(quant - gregorian::days(1)); date_t temp; @@ -533,56 +533,56 @@ void interval_xacts::operator()(xact_t& xact) interval.begin = quant; quant = temp; - if (generate_empty_xacts) { - // Generate a null transaction, so the intervening periods can be + if (generate_empty_posts) { + // Generate a null posting, so the intervening periods can be // seen when -E is used, or if the calculated amount ends up being // non-zero - entry_temps.push_back(entry_t()); - entry_t& null_entry = entry_temps.back(); - null_entry.add_flags(ITEM_TEMP); - null_entry._date = quant - gregorian::days(1); - - xact_temps.push_back(xact_t(&empty_account)); + xact_temps.push_back(xact_t()); xact_t& null_xact = xact_temps.back(); - null_xact.add_flags(ITEM_TEMP | XACT_CALCULATED); - null_xact.amount = 0L; - null_entry.add_xact(&null_xact); + null_xact.add_flags(ITEM_TEMP); + null_xact._date = quant - gregorian::days(1); + + post_temps.push_back(post_t(&empty_account)); + post_t& null_post = post_temps.back(); + null_post.add_flags(ITEM_TEMP | POST_CALCULATED); + null_post.amount = 0L; + null_xact.add_post(&null_post); - last_xact = &null_xact; - subtotal_xacts::operator()(null_xact); + last_post = &null_post; + subtotal_posts::operator()(null_post); report_subtotal(quant - gregorian::days(1)); } } start = interval.begin = quant; } - subtotal_xacts::operator()(xact); + subtotal_posts::operator()(post); } else { - item_handler<xact_t>::operator()(xact); + item_handler<post_t>::operator()(post); } - last_xact = &xact; + last_post = &post; } -void xacts_as_equity::report_subtotal() +void posts_as_equity::report_subtotal() { date_t finish; - foreach (xact_t * xact, component_xacts) { - date_t date = xact->date(); + foreach (post_t * post, component_posts) { + date_t date = post->date(); if (! is_valid(finish) || date > finish) finish = date; } - component_xacts.clear(); + component_posts.clear(); - entry_temps.push_back(entry_t()); - entry_t& entry = entry_temps.back(); - entry.payee = "Opening Balances"; - entry._date = finish; + xact_temps.push_back(xact_t()); + xact_t& xact = xact_temps.back(); + xact.payee = "Opening Balances"; + xact._date = finish; value_t total = 0L; foreach (values_map::value_type& pair, values) { - handle_value(pair.second.value, pair.second.account, &entry, 0, - xact_temps, *handler); + handle_value(pair.second.value, pair.second.account, &xact, 0, + post_temps, *handler); total += pair.second.value; } values.clear(); @@ -590,40 +590,40 @@ void xacts_as_equity::report_subtotal() if (total.is_balance()) { foreach (balance_t::amounts_map::value_type pair, total.as_balance().amounts) { - xact_temps.push_back(xact_t(balance_account)); - xact_t& balance_xact = xact_temps.back(); - balance_xact.add_flags(ITEM_TEMP); - balance_xact.amount = - pair.second; - entry.add_xact(&balance_xact); - (*handler)(balance_xact); + post_temps.push_back(post_t(balance_account)); + post_t& balance_post = post_temps.back(); + balance_post.add_flags(ITEM_TEMP); + balance_post.amount = - pair.second; + xact.add_post(&balance_post); + (*handler)(balance_post); } } else { - xact_temps.push_back(xact_t(balance_account)); - xact_t& balance_xact = xact_temps.back(); - balance_xact.add_flags(ITEM_TEMP); - balance_xact.amount = - total.to_amount(); - entry.add_xact(&balance_xact); - (*handler)(balance_xact); + post_temps.push_back(post_t(balance_account)); + post_t& balance_post = post_temps.back(); + balance_post.add_flags(ITEM_TEMP); + balance_post.amount = - total.to_amount(); + xact.add_post(&balance_post); + (*handler)(balance_post); } } -void by_payee_xacts::flush() +void by_payee_posts::flush() { foreach (payee_subtotals_map::value_type& pair, payee_subtotals) pair.second->report_subtotal(pair.first.c_str()); - item_handler<xact_t>::flush(); + item_handler<post_t>::flush(); payee_subtotals.clear(); } -void by_payee_xacts::operator()(xact_t& xact) +void by_payee_posts::operator()(post_t& post) { - payee_subtotals_map::iterator i = payee_subtotals.find(xact.entry->payee); + payee_subtotals_map::iterator i = payee_subtotals.find(post.xact->payee); if (i == payee_subtotals.end()) { payee_subtotals_pair - temp(xact.entry->payee, - shared_ptr<subtotal_xacts>(new subtotal_xacts(handler, amount_expr))); + temp(post.xact->payee, + shared_ptr<subtotal_posts>(new subtotal_posts(handler, amount_expr))); std::pair<payee_subtotals_map::iterator, bool> result = payee_subtotals.insert(temp); @@ -633,27 +633,27 @@ void by_payee_xacts::operator()(xact_t& xact) i = result.first; } - (*(*i).second)(xact); + (*(*i).second)(post); } -void transfer_details::operator()(xact_t& xact) +void transfer_details::operator()(post_t& post) { - entry_temps.push_back(*xact.entry); - entry_t& entry = entry_temps.back(); - entry._date = xact.date(); - - xact_temps.push_back(xact); - xact_t& temp = xact_temps.back(); - temp.entry = &entry; - temp.set_state(xact.state()); + xact_temps.push_back(*post.xact); + xact_t& xact = xact_temps.back(); + xact._date = post.date(); + + post_temps.push_back(post); + post_t& temp = post_temps.back(); + temp.xact = &xact; + temp.set_state(post.state()); temp.add_flags(ITEM_TEMP); - entry.add_xact(&temp); + xact.add_post(&temp); bind_scope_t bound_scope(scope, temp); switch (which_element) { case SET_PAYEE: - entry.payee = expr.calc(bound_scope).to_string(); + xact.payee = expr.calc(bound_scope).to_string(); break; case SET_ACCOUNT: temp.account = master->find_account(expr.calc(bound_scope).to_string()); @@ -663,42 +663,42 @@ void transfer_details::operator()(xact_t& xact) break; } - item_handler<xact_t>::operator()(temp); + item_handler<post_t>::operator()(temp); } -void dow_xacts::flush() +void dow_posts::flush() { for (int i = 0; i < 7; i++) { - foreach (xact_t * xact, days_of_the_week[i]) - subtotal_xacts::operator()(*xact); - subtotal_xacts::report_subtotal("%As"); + foreach (post_t * post, days_of_the_week[i]) + subtotal_posts::operator()(*post); + subtotal_posts::report_subtotal("%As"); days_of_the_week[i].clear(); } - subtotal_xacts::flush(); + subtotal_posts::flush(); } -void generate_xacts::add_period_entries(period_entries_list& period_entries) +void generate_posts::add_period_xacts(period_xacts_list& period_xacts) { - foreach (period_entry_t * entry, period_entries) - foreach (xact_t * xact, entry->xacts) - add_xact(entry->period, *xact); + foreach (period_xact_t * xact, period_xacts) + foreach (post_t * post, xact->posts) + add_post(xact->period, *post); } -void generate_xacts::add_xact(const interval_t& period, xact_t& xact) +void generate_posts::add_post(const interval_t& period, post_t& post) { - pending_xacts.push_back(pending_xacts_pair(period, &xact)); + pending_posts.push_back(pending_posts_pair(period, &post)); } -void budget_xacts::report_budget_items(const date_t& date) +void budget_posts::report_budget_items(const date_t& date) { - if (pending_xacts.size() == 0) + if (pending_posts.size() == 0) return; bool reported; do { reported = false; - foreach (pending_xacts_list::value_type& pair, pending_xacts) { + foreach (pending_posts_list::value_type& pair, pending_posts) { date_t& begin = pair.first.begin; if (! is_valid(begin)) { pair.first.set_start(date); @@ -707,26 +707,26 @@ void budget_xacts::report_budget_items(const date_t& date) if (begin < date && (! is_valid(pair.first.end) || begin < pair.first.end)) { - xact_t& xact = *pair.second; + post_t& post = *pair.second; DEBUG("ledger.walk.budget", "Reporting budget for " - << xact.reported_account()->fullname()); + << post.reported_account()->fullname()); - entry_temps.push_back(entry_t()); - entry_t& entry = entry_temps.back(); - entry.payee = "Budget entry"; - entry._date = begin; + xact_temps.push_back(xact_t()); + xact_t& xact = xact_temps.back(); + xact.payee = "Budget transaction"; + xact._date = begin; - xact_temps.push_back(xact); - xact_t& temp = xact_temps.back(); - temp.entry = &entry; - temp.add_flags(XACT_AUTO | ITEM_TEMP); + post_temps.push_back(post); + post_t& temp = post_temps.back(); + temp.xact = &xact; + temp.add_flags(POST_AUTO | ITEM_TEMP); temp.amount.in_place_negate(); - entry.add_xact(&temp); + xact.add_post(&temp); begin = pair.first.increment(begin); - item_handler<xact_t>::operator()(temp); + item_handler<post_t>::operator()(temp); reported = true; } @@ -734,40 +734,40 @@ void budget_xacts::report_budget_items(const date_t& date) } while (reported); } -void budget_xacts::operator()(xact_t& xact) +void budget_posts::operator()(post_t& post) { - bool xact_in_budget = false; + bool post_in_budget = false; - foreach (pending_xacts_list::value_type& pair, pending_xacts) { - for (account_t * acct = xact.reported_account(); + foreach (pending_posts_list::value_type& pair, pending_posts) { + for (account_t * acct = post.reported_account(); acct; acct = acct->parent) { if (acct == (*pair.second).reported_account()) { - xact_in_budget = true; - // Report the xact as if it had occurred in the parent + post_in_budget = true; + // Report the post as if it had occurred in the parent // account. - if (xact.reported_account() != acct) - xact.xdata().account = acct; + if (post.reported_account() != acct) + post.xdata().account = acct; goto handle; } } } handle: - if (xact_in_budget && flags & BUDGET_BUDGETED) { - report_budget_items(xact.date()); - item_handler<xact_t>::operator()(xact); + if (post_in_budget && flags & BUDGET_BUDGETED) { + report_budget_items(post.date()); + item_handler<post_t>::operator()(post); } - else if (! xact_in_budget && flags & BUDGET_UNBUDGETED) { - item_handler<xact_t>::operator()(xact); + else if (! post_in_budget && flags & BUDGET_UNBUDGETED) { + item_handler<post_t>::operator()(post); } } -void forecast_xacts::add_xact(const interval_t& period, xact_t& xact) +void forecast_posts::add_post(const interval_t& period, post_t& post) { - generate_xacts::add_xact(period, xact); + generate_posts::add_post(period, post); - interval_t& i = pending_xacts.back().first; + interval_t& i = pending_posts.back().first; if (! is_valid(i.begin)) { i.set_start(CURRENT_DATE()); i.begin = i.increment(i.begin); @@ -777,15 +777,15 @@ void forecast_xacts::add_xact(const interval_t& period, xact_t& xact) } } -void forecast_xacts::flush() +void forecast_posts::flush() { - xacts_list passed; + posts_list passed; date_t last; - while (pending_xacts.size() > 0) { - pending_xacts_list::iterator least = pending_xacts.begin(); - for (pending_xacts_list::iterator i = ++pending_xacts.begin(); - i != pending_xacts.end(); + while (pending_posts.size() > 0) { + pending_posts_list::iterator least = pending_posts.begin(); + for (pending_posts_list::iterator i = ++pending_posts.begin(); + i != pending_posts.end(); i++) if ((*i).first.begin < (*least).first.begin) least = i; @@ -793,33 +793,33 @@ void forecast_xacts::flush() date_t& begin = (*least).first.begin; if (is_valid((*least).first.end) && begin >= (*least).first.end) { - pending_xacts.erase(least); + pending_posts.erase(least); passed.remove((*least).second); continue; } - xact_t& xact = *(*least).second; + post_t& post = *(*least).second; - entry_temps.push_back(entry_t()); - entry_t& entry = entry_temps.back(); - entry.payee = "Forecast entry"; - entry._date = begin; + xact_temps.push_back(xact_t()); + xact_t& xact = xact_temps.back(); + xact.payee = "Forecast transaction"; + xact._date = begin; - xact_temps.push_back(xact); - xact_t& temp = xact_temps.back(); - temp.entry = &entry; - temp.add_flags(XACT_AUTO | ITEM_TEMP); - entry.add_xact(&temp); + post_temps.push_back(post); + post_t& temp = post_temps.back(); + temp.xact = &xact; + temp.add_flags(POST_AUTO | ITEM_TEMP); + xact.add_post(&temp); date_t next = (*least).first.increment(begin); if (next < begin || (is_valid(last) && (next - last).days() > 365 * 5)) break; begin = next; - item_handler<xact_t>::operator()(temp); + item_handler<post_t>::operator()(temp); if (temp.has_xdata() && - temp.xdata().has_flags(XACT_EXT_MATCHES)) { + temp.xdata().has_flags(POST_EXT_MATCHES)) { bind_scope_t bound_scope(context, temp); if (! pred(bound_scope)) break; @@ -827,21 +827,21 @@ void forecast_xacts::flush() passed.clear(); } else { bool found = false; - foreach (xact_t * x, passed) - if (x == &xact) { + foreach (post_t * x, passed) + if (x == &post) { found = true; break; } if (! found) { - passed.push_back(&xact); - if (passed.size() >= pending_xacts.size()) + passed.push_back(&post); + if (passed.size() >= pending_posts.size()) break; } } } - item_handler<xact_t>::flush(); + item_handler<post_t>::flush(); } pass_down_accounts::pass_down_accounts(acct_handler_ptr handler, diff --git a/src/filters.h b/src/filters.h index 3a8a5ab5..a2ab5aec 100644 --- a/src/filters.h +++ b/src/filters.h @@ -48,15 +48,15 @@ #include "chain.h" #include "predicate.h" -#include "entry.h" #include "xact.h" +#include "post.h" #include "account.h" namespace ledger { ////////////////////////////////////////////////////////////////////// // -// Transaction filters +// Posting filters // /** @@ -64,10 +64,10 @@ namespace ledger { * * Long. */ -class ignore_xacts : public item_handler<xact_t> +class ignore_posts : public item_handler<post_t> { public: - virtual void operator()(xact_t&) {} + virtual void operator()(post_t&) {} }; /** @@ -75,30 +75,30 @@ public: * * Long. */ -class clear_xact_xdata : public item_handler<xact_t> +class clear_post_xdata : public item_handler<post_t> { public: - virtual void operator()(xact_t& xact) { - xact.clear_xdata(); + virtual void operator()(post_t& post) { + post.clear_xdata(); } }; -class xacts_iterator; +class posts_iterator; /** * @brief Brief * * Long. */ -class pass_down_xacts : public item_handler<xact_t> +class pass_down_posts : public item_handler<post_t> { - pass_down_xacts(); + pass_down_posts(); public: - pass_down_xacts(xact_handler_ptr handler, xacts_iterator& iter); + pass_down_posts(post_handler_ptr handler, posts_iterator& iter); - virtual ~pass_down_xacts() { - TRACE_DTOR(pass_down_xacts); + virtual ~pass_down_posts() { + TRACE_DTOR(pass_down_posts); } }; @@ -107,22 +107,22 @@ public: * * Long. */ -class push_to_xacts_list : public item_handler<xact_t> +class push_to_posts_list : public item_handler<post_t> { - push_to_xacts_list(); + push_to_posts_list(); public: - xacts_list& xacts; + posts_list& posts; - push_to_xacts_list(xacts_list& _xacts) : xacts(_xacts) { - TRACE_CTOR(push_to_xacts_list, "xacts_list&"); + push_to_posts_list(posts_list& _posts) : posts(_posts) { + TRACE_CTOR(push_to_posts_list, "posts_list&"); } - virtual ~push_to_xacts_list() { - TRACE_DTOR(push_to_xacts_list); + virtual ~push_to_posts_list() { + TRACE_DTOR(push_to_posts_list); } - virtual void operator()(xact_t& xact) { - xacts.push_back(&xact); + virtual void operator()(post_t& post) { + posts.push_back(&post); } }; @@ -131,32 +131,32 @@ public: * * Long. */ -class truncate_entries : public item_handler<xact_t> +class truncate_xacts : public item_handler<post_t> { int head_count; int tail_count; - xacts_list xacts; + posts_list posts; - truncate_entries(); + truncate_xacts(); public: - truncate_entries(xact_handler_ptr handler, + truncate_xacts(post_handler_ptr handler, int _head_count, int _tail_count) - : item_handler<xact_t>(handler), + : item_handler<post_t>(handler), head_count(_head_count), tail_count(_tail_count) { - TRACE_CTOR(truncate_entries, "xact_handler_ptr, int, int"); + TRACE_CTOR(truncate_xacts, "post_handler_ptr, int, int"); } - virtual ~truncate_entries() { - TRACE_DTOR(truncate_entries); + virtual ~truncate_xacts() { + TRACE_DTOR(truncate_xacts); } virtual void flush(); - virtual void operator()(xact_t& xact) { + virtual void operator()(post_t& post) { if (! (tail_count == 0 && head_count > 0 && - static_cast<int>(xacts.size()) >= head_count)) - xacts.push_back(&xact); + static_cast<int>(posts.size()) >= head_count)) + posts.push_back(&post); } }; @@ -165,15 +165,15 @@ public: * * Long. */ -class set_account_value : public item_handler<xact_t> +class set_account_value : public item_handler<post_t> { expr_t& amount_expr; public: set_account_value(expr_t& _amount_expr) - : item_handler<xact_t>(), amount_expr(_amount_expr) {} + : item_handler<post_t>(), amount_expr(_amount_expr) {} - virtual void operator()(xact_t& xact); + virtual void operator()(post_t& post); }; /** @@ -181,43 +181,43 @@ public: * * Long. */ -class sort_xacts : public item_handler<xact_t> +class sort_posts : public item_handler<post_t> { - typedef std::deque<xact_t *> xacts_deque; + typedef std::deque<post_t *> posts_deque; - xacts_deque xacts; + posts_deque posts; const expr_t sort_order; - sort_xacts(); + sort_posts(); public: - sort_xacts(xact_handler_ptr handler, + sort_posts(post_handler_ptr handler, const expr_t& _sort_order) - : item_handler<xact_t>(handler), + : item_handler<post_t>(handler), sort_order(_sort_order) { - TRACE_CTOR(sort_xacts, - "xact_handler_ptr, const value_expr&"); + TRACE_CTOR(sort_posts, + "post_handler_ptr, const value_expr&"); } - sort_xacts(xact_handler_ptr handler, + sort_posts(post_handler_ptr handler, const string& _sort_order) - : item_handler<xact_t>(handler), + : item_handler<post_t>(handler), sort_order(_sort_order) { - TRACE_CTOR(sort_xacts, - "xact_handler_ptr, const string&"); + TRACE_CTOR(sort_posts, + "post_handler_ptr, const string&"); } - virtual ~sort_xacts() { - TRACE_DTOR(sort_xacts); + virtual ~sort_posts() { + TRACE_DTOR(sort_posts); } - virtual void post_accumulated_xacts(); + virtual void post_accumulated_posts(); virtual void flush() { - post_accumulated_xacts(); - item_handler<xact_t>::flush(); + post_accumulated_posts(); + item_handler<post_t>::flush(); } - virtual void operator()(xact_t& xact) { - xacts.push_back(&xact); + virtual void operator()(post_t& post) { + posts.push_back(&post); } }; @@ -226,42 +226,42 @@ public: * * Long. */ -class sort_entries : public item_handler<xact_t> +class sort_xacts : public item_handler<post_t> { - sort_xacts sorter; - entry_t * last_entry; + sort_posts sorter; + xact_t * last_xact; - sort_entries(); + sort_xacts(); public: - sort_entries(xact_handler_ptr handler, + sort_xacts(post_handler_ptr handler, const expr_t& _sort_order) : sorter(handler, _sort_order) { - TRACE_CTOR(sort_entries, - "xact_handler_ptr, const value_expr&"); + TRACE_CTOR(sort_xacts, + "post_handler_ptr, const value_expr&"); } - sort_entries(xact_handler_ptr handler, + sort_xacts(post_handler_ptr handler, const string& _sort_order) : sorter(handler, _sort_order) { - TRACE_CTOR(sort_entries, - "xact_handler_ptr, const string&"); + TRACE_CTOR(sort_xacts, + "post_handler_ptr, const string&"); } - virtual ~sort_entries() { - TRACE_DTOR(sort_entries); + virtual ~sort_xacts() { + TRACE_DTOR(sort_xacts); } virtual void flush() { sorter.flush(); - item_handler<xact_t>::flush(); + item_handler<post_t>::flush(); } - virtual void operator()(xact_t& xact) { - if (last_entry && xact.entry != last_entry) - sorter.post_accumulated_xacts(); + virtual void operator()(post_t& post) { + if (last_xact && post.xact != last_xact) + sorter.post_accumulated_posts(); - sorter(xact); + sorter(post); - last_entry = xact.entry; + last_xact = post.xact; } }; @@ -270,37 +270,37 @@ public: * * Long. */ -class filter_xacts : public item_handler<xact_t> +class filter_posts : public item_handler<post_t> { item_predicate pred; scope_t& context; - filter_xacts(); + filter_posts(); public: - filter_xacts(xact_handler_ptr handler, + filter_posts(post_handler_ptr handler, const item_predicate& predicate, scope_t& _context) - : item_handler<xact_t>(handler), pred(predicate), context(_context) { - TRACE_CTOR(filter_xacts, - "xact_handler_ptr, const item_predicate&, scope_t&"); + : item_handler<post_t>(handler), pred(predicate), context(_context) { + TRACE_CTOR(filter_posts, + "post_handler_ptr, const item_predicate&, scope_t&"); } - virtual ~filter_xacts() { - TRACE_DTOR(filter_xacts); + virtual ~filter_posts() { + TRACE_DTOR(filter_posts); } - virtual void operator()(xact_t& xact) { - bind_scope_t bound_scope(context, xact); + virtual void operator()(post_t& post) { + bind_scope_t bound_scope(context, post); if (pred(bound_scope)) { - xact.xdata().add_flags(XACT_EXT_MATCHES); - (*handler)(xact); + post.xdata().add_flags(POST_EXT_MATCHES); + (*handler)(post); } } }; -inline void clear_entries_xacts(std::list<entry_t>& entries_list) { - foreach (entry_t& entry, entries_list) - entry.xacts.clear(); +inline void clear_xacts_posts(std::list<xact_t>& xacts_list) { + foreach (xact_t& xact, xacts_list) + xact.posts.clear(); } /** @@ -308,26 +308,26 @@ inline void clear_entries_xacts(std::list<entry_t>& entries_list) { * * Long. */ -class anonymize_xacts : public item_handler<xact_t> +class anonymize_posts : public item_handler<post_t> { - std::list<entry_t> entry_temps; - std::list<xact_t> xact_temps; + std::list<xact_t> xact_temps; + std::list<post_t> post_temps; - entry_t * last_entry; + xact_t * last_xact; - anonymize_xacts(); + anonymize_posts(); public: - anonymize_xacts(xact_handler_ptr handler) - : item_handler<xact_t>(handler), last_entry(NULL) { - TRACE_CTOR(anonymize_xacts, "xact_handler_ptr"); + anonymize_posts(post_handler_ptr handler) + : item_handler<post_t>(handler), last_xact(NULL) { + TRACE_CTOR(anonymize_posts, "post_handler_ptr"); } - virtual ~anonymize_xacts() { - TRACE_DTOR(anonymize_xacts); - clear_entries_xacts(entry_temps); + virtual ~anonymize_posts() { + TRACE_DTOR(anonymize_posts); + clear_xacts_posts(xact_temps); } - virtual void operator()(xact_t& xact); + virtual void operator()(post_t& post); }; /** @@ -335,25 +335,25 @@ public: * * Long. */ -class calc_xacts : public item_handler<xact_t> +class calc_posts : public item_handler<post_t> { - xact_t * last_xact; + post_t * last_post; expr_t& amount_expr; - calc_xacts(); + calc_posts(); public: - calc_xacts(xact_handler_ptr handler, + calc_posts(post_handler_ptr handler, expr_t& _amount_expr) - : item_handler<xact_t>(handler), - last_xact(NULL), amount_expr(_amount_expr) { - TRACE_CTOR(calc_xacts, "xact_handler_ptr, expr_t&"); + : item_handler<post_t>(handler), + last_post(NULL), amount_expr(_amount_expr) { + TRACE_CTOR(calc_posts, "post_handler_ptr, expr_t&"); } - virtual ~calc_xacts() { - TRACE_DTOR(calc_xacts); + virtual ~calc_posts() { + TRACE_DTOR(calc_posts); } - virtual void operator()(xact_t& xact); + virtual void operator()(post_t& post); }; /** @@ -361,51 +361,51 @@ public: * * Long. */ -class collapse_xacts : public item_handler<xact_t> +class collapse_posts : public item_handler<post_t> { expr_t& amount_expr; item_predicate display_predicate; item_predicate only_predicate; value_t subtotal; std::size_t count; - entry_t * last_entry; xact_t * last_xact; + post_t * last_post; account_t totals_account; bool only_collapse_if_zero; - std::list<entry_t> entry_temps; - std::list<xact_t> xact_temps; - std::list<xact_t *> component_xacts; + std::list<xact_t> xact_temps; + std::list<post_t> post_temps; + std::list<post_t *> component_posts; - collapse_xacts(); + collapse_posts(); public: - collapse_xacts(xact_handler_ptr handler, + collapse_posts(post_handler_ptr handler, expr_t& _amount_expr, item_predicate _display_predicate, item_predicate _only_predicate, bool _only_collapse_if_zero = false) - : item_handler<xact_t>(handler), amount_expr(_amount_expr), + : item_handler<post_t>(handler), amount_expr(_amount_expr), display_predicate(_display_predicate), only_predicate(_only_predicate), count(0), - last_entry(NULL), last_xact(NULL), + last_xact(NULL), last_post(NULL), totals_account(NULL, "<Total>"), only_collapse_if_zero(_only_collapse_if_zero) { - TRACE_CTOR(collapse_xacts, "xact_handler_ptr"); + TRACE_CTOR(collapse_posts, "post_handler_ptr"); } - virtual ~collapse_xacts() { - TRACE_DTOR(collapse_xacts); - clear_entries_xacts(entry_temps); + virtual ~collapse_posts() { + TRACE_DTOR(collapse_posts); + clear_xacts_posts(xact_temps); } virtual void flush() { report_subtotal(); - item_handler<xact_t>::flush(); + item_handler<post_t>::flush(); } void report_subtotal(); - virtual void operator()(xact_t& xact); + virtual void operator()(post_t& post); }; /** @@ -413,29 +413,29 @@ public: * * Long. */ -class related_xacts : public item_handler<xact_t> +class related_posts : public item_handler<post_t> { - xacts_list xacts; + posts_list posts; bool also_matching; - related_xacts(); + related_posts(); public: - related_xacts(xact_handler_ptr handler, + related_posts(post_handler_ptr handler, const bool _also_matching = false) - : item_handler<xact_t>(handler), + : item_handler<post_t>(handler), also_matching(_also_matching) { - TRACE_CTOR(related_xacts, - "xact_handler_ptr, const bool"); + TRACE_CTOR(related_posts, + "post_handler_ptr, const bool"); } - virtual ~related_xacts() throw() { - TRACE_DTOR(related_xacts); + virtual ~related_posts() throw() { + TRACE_DTOR(related_posts); } virtual void flush(); - virtual void operator()(xact_t& xact) { - xact.xdata().add_flags(XACT_EXT_RECEIVED); - xacts.push_back(&xact); + virtual void operator()(post_t& post) { + post.xdata().add_flags(POST_EXT_RECEIVED); + posts.push_back(&post); } }; @@ -444,50 +444,50 @@ public: * * Long. */ -class changed_value_xacts : public item_handler<xact_t> +class changed_value_posts : public item_handler<post_t> { - // This filter requires that calc_xacts be used at some point + // This filter requires that calc_posts be used at some point // later in the chain. expr_t total_expr; report_t& report; bool changed_values_only; - xact_t * last_xact; + post_t * last_post; value_t last_balance; account_t revalued_account; - std::list<entry_t> entry_temps; - std::list<xact_t> xact_temps; + std::list<xact_t> xact_temps; + std::list<post_t> post_temps; - changed_value_xacts(); + changed_value_posts(); public: - changed_value_xacts(xact_handler_ptr handler, + changed_value_posts(post_handler_ptr handler, const expr_t& _total_expr, report_t& _report, bool _changed_values_only) - : item_handler<xact_t>(handler), total_expr(_total_expr), + : item_handler<post_t>(handler), total_expr(_total_expr), report(_report), changed_values_only(_changed_values_only), - last_xact(NULL), revalued_account(NULL, "<Revalued>") { - TRACE_CTOR(changed_value_xacts, - "xact_handler_ptr, const expr_t&, report_t&, bool"); + last_post(NULL), revalued_account(NULL, "<Revalued>") { + TRACE_CTOR(changed_value_posts, + "post_handler_ptr, const expr_t&, report_t&, bool"); } - virtual ~changed_value_xacts() { - TRACE_DTOR(changed_value_xacts); - clear_entries_xacts(entry_temps); + virtual ~changed_value_posts() { + TRACE_DTOR(changed_value_posts); + clear_xacts_posts(xact_temps); } virtual void flush() { - if (last_xact && last_xact->date() <= CURRENT_DATE()) { - output_diff(last_xact, CURRENT_DATE()); - last_xact = NULL; + if (last_post && last_post->date() <= CURRENT_DATE()) { + output_diff(last_post, CURRENT_DATE()); + last_post = NULL; } - item_handler<xact_t>::flush(); + item_handler<post_t>::flush(); } - void output_diff(xact_t * xact, const date_t& current); + void output_diff(post_t * post, const date_t& current); - virtual void operator()(xact_t& xact); + virtual void operator()(post_t& post); }; /** @@ -495,9 +495,9 @@ public: * * Long. */ -class subtotal_xacts : public item_handler<xact_t> +class subtotal_posts : public item_handler<post_t> { - subtotal_xacts(); + subtotal_posts(); protected: class acct_value_t @@ -530,21 +530,21 @@ protected: expr_t& amount_expr; values_map values; optional<string> date_format; - std::list<entry_t> entry_temps; - std::list<xact_t> xact_temps; - std::list<xact_t *> component_xacts; + std::list<xact_t> xact_temps; + std::list<post_t> post_temps; + std::list<post_t *> component_posts; public: - subtotal_xacts(xact_handler_ptr handler, expr_t& _amount_expr, + subtotal_posts(post_handler_ptr handler, expr_t& _amount_expr, const optional<string>& _date_format = none) - : item_handler<xact_t>(handler), amount_expr(_amount_expr), + : item_handler<post_t>(handler), amount_expr(_amount_expr), date_format(_date_format) { - TRACE_CTOR(subtotal_xacts, - "xact_handler_ptr, expr_t&, const optional<string>&"); + TRACE_CTOR(subtotal_posts, + "post_handler_ptr, expr_t&, const optional<string>&"); } - virtual ~subtotal_xacts() { - TRACE_DTOR(subtotal_xacts); - clear_entries_xacts(entry_temps); + virtual ~subtotal_posts() { + TRACE_DTOR(subtotal_posts); + clear_xacts_posts(xact_temps); } void report_subtotal(const char * spec_fmt = NULL, @@ -554,9 +554,9 @@ public: virtual void flush() { if (values.size() > 0) report_subtotal(); - item_handler<xact_t>::flush(); + item_handler<post_t>::flush(); } - virtual void operator()(xact_t& xact); + virtual void operator()(post_t& post); }; /** @@ -564,70 +564,70 @@ public: * * Long. */ -class interval_xacts : public subtotal_xacts +class interval_posts : public subtotal_posts { interval_t interval; - xact_t * last_xact; + post_t * last_post; account_t empty_account; bool exact_periods; - bool generate_empty_xacts; + bool generate_empty_posts; date_t start; - interval_xacts(); + interval_posts(); public: - interval_xacts(xact_handler_ptr _handler, + interval_posts(post_handler_ptr _handler, expr_t& amount_expr, const interval_t& _interval, bool _exact_periods = false, - bool _generate_empty_xacts = false) - : subtotal_xacts(_handler, amount_expr), interval(_interval), - last_xact(NULL), empty_account(NULL, "<None>"), + bool _generate_empty_posts = false) + : subtotal_posts(_handler, amount_expr), interval(_interval), + last_post(NULL), empty_account(NULL, "<None>"), exact_periods(_exact_periods), - generate_empty_xacts(_generate_empty_xacts) { - TRACE_CTOR(interval_xacts, - "xact_handler_ptr, expr_t&, interval_t, account_t *, bool, bool"); + generate_empty_posts(_generate_empty_posts) { + TRACE_CTOR(interval_posts, + "post_handler_ptr, expr_t&, interval_t, account_t *, bool, bool"); } - virtual ~interval_xacts() throw() { - TRACE_DTOR(interval_xacts); + virtual ~interval_posts() throw() { + TRACE_DTOR(interval_posts); } void report_subtotal(const date_t& finish); virtual void flush() { - if (last_xact && interval) + if (last_post && interval) report_subtotal(interval.increment(interval.begin) - gregorian::days(1)); - subtotal_xacts::flush(); + subtotal_posts::flush(); } - virtual void operator()(xact_t& xact); + virtual void operator()(post_t& post); }; -class xacts_as_equity : public subtotal_xacts +class posts_as_equity : public subtotal_posts { interval_t interval; - xact_t * last_xact; + post_t * last_post; account_t equity_account; account_t * balance_account; - xacts_as_equity(); + posts_as_equity(); public: - xacts_as_equity(xact_handler_ptr _handler, expr_t& amount_expr) - : subtotal_xacts(_handler, amount_expr), + posts_as_equity(post_handler_ptr _handler, expr_t& amount_expr) + : subtotal_posts(_handler, amount_expr), equity_account(NULL, "Equity") { - TRACE_CTOR(xacts_as_equity, "xact_handler_ptr, expr_t&"); + TRACE_CTOR(posts_as_equity, "post_handler_ptr, expr_t&"); balance_account = equity_account.find_account("Opening Balances"); } - virtual ~xacts_as_equity() throw() { - TRACE_DTOR(xacts_as_equity); + virtual ~posts_as_equity() throw() { + TRACE_DTOR(posts_as_equity); } void report_subtotal(); virtual void flush() { report_subtotal(); - subtotal_xacts::flush(); + subtotal_posts::flush(); } }; @@ -636,27 +636,27 @@ public: * * Long. */ -class by_payee_xacts : public item_handler<xact_t> +class by_payee_posts : public item_handler<post_t> { - typedef std::map<string, shared_ptr<subtotal_xacts> > payee_subtotals_map; - typedef std::pair<string, shared_ptr<subtotal_xacts> > payee_subtotals_pair; + typedef std::map<string, shared_ptr<subtotal_posts> > payee_subtotals_map; + typedef std::pair<string, shared_ptr<subtotal_posts> > payee_subtotals_pair; expr_t& amount_expr; payee_subtotals_map payee_subtotals; - by_payee_xacts(); + by_payee_posts(); public: - by_payee_xacts(xact_handler_ptr handler, expr_t& _amount_expr) - : item_handler<xact_t>(handler), amount_expr(_amount_expr) { - TRACE_CTOR(by_payee_xacts, "xact_handler_ptr, expr_t&"); + by_payee_posts(post_handler_ptr handler, expr_t& _amount_expr) + : item_handler<post_t>(handler), amount_expr(_amount_expr) { + TRACE_CTOR(by_payee_posts, "post_handler_ptr, expr_t&"); } - virtual ~by_payee_xacts() { - TRACE_DTOR(by_payee_xacts); + virtual ~by_payee_posts() { + TRACE_DTOR(by_payee_posts); } virtual void flush(); - virtual void operator()(xact_t& xact); + virtual void operator()(post_t& post); }; /** @@ -664,10 +664,10 @@ class by_payee_xacts : public item_handler<xact_t> * * Long. */ -class transfer_details : public item_handler<xact_t> +class transfer_details : public item_handler<post_t> { - std::list<entry_t> entry_temps; - std::list<xact_t> xact_temps; + std::list<xact_t> xact_temps; + std::list<post_t> post_temps; account_t * master; expr_t expr; scope_t& scope; @@ -680,22 +680,22 @@ public: SET_ACCOUNT } which_element; - transfer_details(xact_handler_ptr handler, + transfer_details(post_handler_ptr handler, element_t _which_element, account_t * _master, const expr_t& _expr, scope_t& _scope) - : item_handler<xact_t>(handler), master(_master), + : item_handler<post_t>(handler), master(_master), expr(_expr), scope(_scope), which_element(_which_element) { TRACE_CTOR(transfer_details, - "xact_handler_ptr, element_t, account_t *, expr_t, scope_t&"); + "post_handler_ptr, element_t, account_t *, expr_t, scope_t&"); } virtual ~transfer_details() { TRACE_DTOR(transfer_details); - clear_entries_xacts(entry_temps); + clear_xacts_posts(xact_temps); } - virtual void operator()(xact_t& xact); + virtual void operator()(post_t& post); }; /** @@ -703,24 +703,24 @@ public: * * Long. */ -class dow_xacts : public subtotal_xacts +class dow_posts : public subtotal_posts { - xacts_list days_of_the_week[7]; + posts_list days_of_the_week[7]; - dow_xacts(); + dow_posts(); public: - dow_xacts(xact_handler_ptr handler, expr_t& amount_expr) - : subtotal_xacts(handler, amount_expr) { - TRACE_CTOR(dow_xacts, "xact_handler_ptr, bool"); + dow_posts(post_handler_ptr handler, expr_t& amount_expr) + : subtotal_posts(handler, amount_expr) { + TRACE_CTOR(dow_posts, "post_handler_ptr, bool"); } - virtual ~dow_xacts() throw() { - TRACE_DTOR(dow_xacts); + virtual ~dow_posts() throw() { + TRACE_DTOR(dow_posts); } virtual void flush(); - virtual void operator()(xact_t& xact) { - days_of_the_week[xact.date().day_of_week()].push_back(&xact); + virtual void operator()(post_t& post) { + days_of_the_week[post.date().day_of_week()].push_back(&post); } }; @@ -729,32 +729,32 @@ public: * * Long. */ -class generate_xacts : public item_handler<xact_t> +class generate_posts : public item_handler<post_t> { - generate_xacts(); + generate_posts(); protected: - typedef std::pair<interval_t, xact_t *> pending_xacts_pair; - typedef std::list<pending_xacts_pair> pending_xacts_list; + typedef std::pair<interval_t, post_t *> pending_posts_pair; + typedef std::list<pending_posts_pair> pending_posts_list; - pending_xacts_list pending_xacts; - std::list<entry_t> entry_temps; - std::list<xact_t> xact_temps; + pending_posts_list pending_posts; + std::list<xact_t> xact_temps; + std::list<post_t> post_temps; public: - generate_xacts(xact_handler_ptr handler) - : item_handler<xact_t>(handler) { - TRACE_CTOR(generate_xacts, "xact_handler_ptr"); + generate_posts(post_handler_ptr handler) + : item_handler<post_t>(handler) { + TRACE_CTOR(generate_posts, "post_handler_ptr"); } - virtual ~generate_xacts() { - TRACE_DTOR(generate_xacts); - clear_entries_xacts(entry_temps); + virtual ~generate_posts() { + TRACE_DTOR(generate_posts); + clear_xacts_posts(xact_temps); } - void add_period_entries(period_entries_list& period_entries); + void add_period_xacts(period_xacts_list& period_xacts); - virtual void add_xact(const interval_t& period, xact_t& xact); + virtual void add_post(const interval_t& period, post_t& post); }; /** @@ -762,7 +762,7 @@ public: * * Long. */ -class budget_xacts : public generate_xacts +class budget_posts : public generate_posts { #define BUDGET_NO_BUDGET 0x00 #define BUDGET_BUDGETED 0x01 @@ -770,21 +770,21 @@ class budget_xacts : public generate_xacts uint_least8_t flags; - budget_xacts(); + budget_posts(); public: - budget_xacts(xact_handler_ptr handler, + budget_posts(post_handler_ptr handler, uint_least8_t _flags = BUDGET_BUDGETED) - : generate_xacts(handler), flags(_flags) { - TRACE_CTOR(budget_xacts, "xact_handler_ptr, uint_least8_t"); + : generate_posts(handler), flags(_flags) { + TRACE_CTOR(budget_posts, "post_handler_ptr, uint_least8_t"); } - virtual ~budget_xacts() throw() { - TRACE_DTOR(budget_xacts); + virtual ~budget_posts() throw() { + TRACE_DTOR(budget_posts); } void report_budget_items(const date_t& date); - virtual void operator()(xact_t& xact); + virtual void operator()(post_t& post); }; /** @@ -792,24 +792,24 @@ public: * * Long. */ -class forecast_xacts : public generate_xacts +class forecast_posts : public generate_posts { item_predicate pred; scope_t& context; public: - forecast_xacts(xact_handler_ptr handler, + forecast_posts(post_handler_ptr handler, const item_predicate& predicate, scope_t& _context) - : generate_xacts(handler), pred(predicate), context(_context) { - TRACE_CTOR(forecast_xacts, - "xact_handler_ptr, const item_predicate&, scope_t&"); + : generate_posts(handler), pred(predicate), context(_context) { + TRACE_CTOR(forecast_posts, + "post_handler_ptr, const item_predicate&, scope_t&"); } - virtual ~forecast_xacts() throw() { - TRACE_DTOR(forecast_xacts); + virtual ~forecast_posts() throw() { + TRACE_DTOR(forecast_posts); } - virtual void add_xact(const interval_t& period, xact_t& xact); + virtual void add_post(const interval_t& period, post_t& post); virtual void flush(); }; diff --git a/src/format.cc b/src/format.cc index 5b813ee6..b4541a59 100644 --- a/src/format.cc +++ b/src/format.cc @@ -73,12 +73,12 @@ format_t::element_t * format_t::parse_elements(const string& fmt) // d: COMPLETE_DATE_STRING // D: DATE_STRING // S: SOURCE; break - // B: ENTRY_BEG_POS - // b: ENTRY_BEG_LINE - // E: ENTRY_END_POS - // e: ENTRY_END_LINE + // B: XACT_BEG_POS + // b: XACT_BEG_LINE + // E: XACT_END_POS + // e: XACT_END_LINE // X: CLEARED - // Y: ENTRY_CLEARED + // Y: XACT_CLEARED // C: CODE // P: PAYEE // W: OPT_ACCOUNT @@ -91,10 +91,10 @@ format_t::element_t * format_t::parse_elements(const string& fmt) // n: OPT_NOTE // _: DEPTH_SPACER // - // xB: XACT_BEG_POS - // xb: XACT_BEG_LINE - // xE: XACT_END_POS - // xe: XACT_END_LINE + // xB: POST_BEG_POS + // xb: POST_BEG_LINE + // xE: POST_END_POS + // xe: POST_END_LINE for (const char * p = fmt.c_str(); *p; p++) { if (*p != '%' && *p != '\\') { diff --git a/src/global.cc b/src/global.cc index 3416a3d4..e3969481 100644 --- a/src/global.cc +++ b/src/global.cc @@ -100,10 +100,10 @@ void global_scope_t::read_init() ifstream init(init_file); if (session().read_journal(init_file) > 0 || - session().journal->auto_entries.size() > 0 || - session().journal->period_entries.size() > 0) { - throw_(parse_error, - "Entries found in initialization file '" << init_file << "'"); + session().journal->auto_xacts.size() > 0 || + session().journal->period_xacts.size() > 0) { + throw_(parse_error, "Transactions found in initialization file '" + << init_file << "'"); } TRACE_FINISH(init, 1); @@ -385,7 +385,7 @@ void global_scope_t::normalize_report_options(const string& verb) // jww (2008-08-14): This code really needs to be rationalized away for 3.0. // I might be able to do it with command objects, like register_t, which // each know how to adjust the report based on its current option settings. - if (verb == "print" || verb == "entry" || verb == "dump") { + if (verb == "print" || verb == "xact" || verb == "dump") { rep.HANDLER(related).on_only(); rep.HANDLER(related_all).on_only(); } @@ -402,13 +402,13 @@ void global_scope_t::normalize_report_options(const string& verb) } if (! rep.HANDLED(empty)) - rep.HANDLER(display_).on("amount|(!xact&total)"); + rep.HANDLER(display_).on("amount|(!post&total)"); if (verb[0] != 'b' && verb[0] != 'r') rep.HANDLER(base).on_only(); if (rep.HANDLED(period_) && ! rep.HANDLED(sort_all_)) - rep.HANDLER(sort_entries_).on_only(); + rep.HANDLER(sort_xacts_).on_only(); long cols = 0; if (rep.HANDLED(columns_)) @@ -59,9 +59,9 @@ namespace ledger { class item_t : public supports_flags<>, public scope_t { public: -#define ITEM_NORMAL 0x00 // no flags at all, a basic transaction -#define ITEM_GENERATED 0x01 // transaction was not found in a journal -#define ITEM_TEMP 0x02 // transaction is a temporary object +#define ITEM_NORMAL 0x00 // no flags at all, a basic posting +#define ITEM_GENERATED 0x01 // posting was not found in a journal +#define ITEM_TEMP 0x02 // posting is a temporary object enum state_t { UNCLEARED = 0, CLEARED, PENDING }; @@ -112,11 +112,11 @@ public: end_line = item.end_line; } - virtual bool operator==(const item_t& entry) { - return this == &entry; + virtual bool operator==(const item_t& xact) { + return this == &xact; } - virtual bool operator!=(const item_t& entry) { - return ! (*this == entry); + virtual bool operator!=(const item_t& xact) { + return ! (*this == xact); } virtual bool has_tag(const string& tag) const; diff --git a/src/iterators.cc b/src/iterators.cc index 835fec9d..6a022772 100644 --- a/src/iterators.cc +++ b/src/iterators.cc @@ -35,57 +35,57 @@ namespace ledger { -void entries_iterator::reset(journal_t& journal) +void xacts_iterator::reset(journal_t& journal) { - entries_i = journal.entries.begin(); - entries_end = journal.entries.end(); - entries_uninitialized = false; + xacts_i = journal.xacts.begin(); + xacts_end = journal.xacts.end(); + xacts_uninitialized = false; } -entry_t * entries_iterator::operator()() +xact_t * xacts_iterator::operator()() { - if (entries_i != entries_end) - return *entries_i++; + if (xacts_i != xacts_end) + return *xacts_i++; else return NULL; } -void journal_xacts_iterator::reset(journal_t& journal) +void journal_posts_iterator::reset(journal_t& journal) { - entries.reset(journal); + xacts.reset(journal); - entry_t * entry = entries(); - if (entry != NULL) - xacts.reset(*entry); + xact_t * xact = xacts(); + if (xact != NULL) + posts.reset(*xact); } -xact_t * journal_xacts_iterator::operator()() +post_t * journal_posts_iterator::operator()() { - xact_t * xact = xacts(); - if (xact == NULL) { - entry_t * entry = entries(); - if (entry != NULL) { - xacts.reset(*entry); - xact = xacts(); + post_t * post = posts(); + if (post == NULL) { + xact_t * xact = xacts(); + if (xact != NULL) { + posts.reset(*xact); + post = posts(); } } - return xact; + return post; } -void xacts_commodities_iterator::reset(journal_t& journal) +void posts_commodities_iterator::reset(journal_t& journal) { - journal_xacts.reset(journal); + journal_posts.reset(journal); std::set<commodity_t *> commodities; - for (xact_t * xact = journal_xacts(); xact; xact = journal_xacts()) { - commodity_t& comm(xact->amount.commodity()); + for (post_t * post = journal_posts(); post; post = journal_posts()) { + commodity_t& comm(post->amount.commodity()); if (comm.flags() & COMMODITY_NOMARKET) continue; commodities.insert(&comm); } - std::map<string, entry_t *> entries_by_commodity; + std::map<string, xact_t *> xacts_by_commodity; foreach (commodity_t * comm, commodities) { optional<commodity_t::varied_history_t&> history = comm->varied_history(); @@ -98,55 +98,55 @@ void xacts_commodities_iterator::reset(journal_t& journal) history->histories) { foreach (commodity_t::base_t::history_map::value_type hpair, pair.second.prices) { - entry_t * entry; + xact_t * xact; string symbol = hpair.second.commodity().symbol(); - std::map<string, entry_t *>::iterator i = - entries_by_commodity.find(symbol); - if (i != entries_by_commodity.end()) { - entry = (*i).second; + std::map<string, xact_t *>::iterator i = + xacts_by_commodity.find(symbol); + if (i != xacts_by_commodity.end()) { + xact = (*i).second; } else { - entry_temps.push_back(new entry_t); - entry = entry_temps.back(); - entry->payee = symbol; - entry->_date = hpair.first.date(); - entries_by_commodity.insert - (std::pair<string, entry_t *>(symbol, entry)); + xact_temps.push_back(new xact_t); + xact = xact_temps.back(); + xact->payee = symbol; + xact->_date = hpair.first.date(); + xacts_by_commodity.insert + (std::pair<string, xact_t *>(symbol, xact)); } - xact_temps.push_back(xact_t(account)); - xact_t& temp = xact_temps.back(); + post_temps.push_back(post_t(account)); + post_t& temp = post_temps.back(); temp._date = hpair.first.date(); - temp.entry = entry; + temp.xact = xact; temp.amount = hpair.second; temp.set_flags(ITEM_GENERATED | ITEM_TEMP); - entry->add_xact(&temp); + xact->add_post(&temp); } } } - entries.entries_i = entry_temps.begin(); - entries.entries_end = entry_temps.end(); + xacts.xacts_i = xact_temps.begin(); + xacts.xacts_end = xact_temps.end(); - entries.entries_uninitialized = false; + xacts.xacts_uninitialized = false; - entry_t * entry = entries(); - if (entry != NULL) - xacts.reset(*entry); + xact_t * xact = xacts(); + if (xact != NULL) + posts.reset(*xact); } -xact_t * xacts_commodities_iterator::operator()() +post_t * posts_commodities_iterator::operator()() { - xact_t * xact = xacts(); - if (xact == NULL) { - entry_t * entry = entries(); - if (entry != NULL) { - xacts.reset(*entry); - xact = xacts(); + post_t * post = posts(); + if (post == NULL) { + xact_t * xact = xacts(); + if (xact != NULL) { + posts.reset(*xact); + post = posts(); } } - return xact; + return post; } account_t * basic_accounts_iterator::operator()() diff --git a/src/iterators.h b/src/iterators.h index 92f887d0..d4c99fbf 100644 --- a/src/iterators.h +++ b/src/iterators.h @@ -47,7 +47,7 @@ #define _ITERATORS_H #include "journal.h" -#include "entry.h" +#include "xact.h" #include "account.h" namespace ledger { @@ -57,11 +57,11 @@ namespace ledger { * * Long. */ -class xacts_iterator : public noncopyable +class posts_iterator : public noncopyable { public: - virtual ~xacts_iterator() throw() {} - virtual xact_t * operator()() = 0; + virtual ~posts_iterator() throw() {} + virtual post_t * operator()() = 0; }; /** @@ -69,37 +69,37 @@ public: * * Long. */ -class entry_xacts_iterator : public xacts_iterator +class xact_posts_iterator : public posts_iterator { - xacts_list::iterator xacts_i; - xacts_list::iterator xacts_end; + posts_list::iterator posts_i; + posts_list::iterator posts_end; - bool xacts_uninitialized; + bool posts_uninitialized; public: - entry_xacts_iterator() : xacts_uninitialized(true) { - TRACE_CTOR(entry_xacts_iterator, ""); + xact_posts_iterator() : posts_uninitialized(true) { + TRACE_CTOR(xact_posts_iterator, ""); } - entry_xacts_iterator(entry_t& entry) - : xacts_uninitialized(true) { - TRACE_CTOR(entry_xacts_iterator, "entry_t&"); - reset(entry); + xact_posts_iterator(xact_t& xact) + : posts_uninitialized(true) { + TRACE_CTOR(xact_posts_iterator, "xact_t&"); + reset(xact); } - virtual ~entry_xacts_iterator() throw() { - TRACE_DTOR(entry_xacts_iterator); + virtual ~xact_posts_iterator() throw() { + TRACE_DTOR(xact_posts_iterator); } - void reset(entry_t& entry) { - xacts_i = entry.xacts.begin(); - xacts_end = entry.xacts.end(); + void reset(xact_t& xact) { + posts_i = xact.posts.begin(); + posts_end = xact.posts.end(); - xacts_uninitialized = false; + posts_uninitialized = false; } - virtual xact_t * operator()() { - if (xacts_i == xacts_end || xacts_uninitialized) + virtual post_t * operator()() { + if (posts_i == posts_end || posts_uninitialized) return NULL; - return *xacts_i++; + return *posts_i++; } }; @@ -108,28 +108,28 @@ public: * * Long. */ -class entries_iterator : public noncopyable +class xacts_iterator : public noncopyable { public: - entries_list::iterator entries_i; - entries_list::iterator entries_end; + xacts_list::iterator xacts_i; + xacts_list::iterator xacts_end; - bool entries_uninitialized; + bool xacts_uninitialized; - entries_iterator() : entries_uninitialized(true) { - TRACE_CTOR(entries_iterator, ""); + xacts_iterator() : xacts_uninitialized(true) { + TRACE_CTOR(xacts_iterator, ""); } - entries_iterator(journal_t& journal) : entries_uninitialized(true) { - TRACE_CTOR(entries_iterator, "journal_t&"); + xacts_iterator(journal_t& journal) : xacts_uninitialized(true) { + TRACE_CTOR(xacts_iterator, "journal_t&"); reset(journal); } - virtual ~entries_iterator() throw() { - TRACE_DTOR(entries_iterator); + virtual ~xacts_iterator() throw() { + TRACE_DTOR(xacts_iterator); } void reset(journal_t& journal); - entry_t * operator()(); + xact_t * operator()(); }; /** @@ -137,26 +137,26 @@ public: * * Long. */ -class journal_xacts_iterator : public xacts_iterator +class journal_posts_iterator : public posts_iterator { - entries_iterator entries; - entry_xacts_iterator xacts; + xacts_iterator xacts; + xact_posts_iterator posts; public: - journal_xacts_iterator() { - TRACE_CTOR(journal_xacts_iterator, ""); + journal_posts_iterator() { + TRACE_CTOR(journal_posts_iterator, ""); } - journal_xacts_iterator(journal_t& journal) { - TRACE_CTOR(journal_xacts_iterator, "journal_t&"); + journal_posts_iterator(journal_t& journal) { + TRACE_CTOR(journal_posts_iterator, "journal_t&"); reset(journal); } - virtual ~journal_xacts_iterator() throw() { - TRACE_DTOR(journal_xacts_iterator); + virtual ~journal_posts_iterator() throw() { + TRACE_DTOR(journal_posts_iterator); } void reset(journal_t& journal); - virtual xact_t * operator()(); + virtual post_t * operator()(); }; /** @@ -164,34 +164,34 @@ public: * * Long. */ -class xacts_commodities_iterator : public xacts_iterator +class posts_commodities_iterator : public posts_iterator { protected: - journal_xacts_iterator journal_xacts; - entries_iterator entries; - entry_xacts_iterator xacts; + journal_posts_iterator journal_posts; + xacts_iterator xacts; + xact_posts_iterator posts; - std::list<xact_t> xact_temps; + std::list<post_t> post_temps; std::list<account_t> acct_temps; - entries_list entry_temps; + xacts_list xact_temps; public: - xacts_commodities_iterator() { - TRACE_CTOR(xacts_commodities_iterator, ""); + posts_commodities_iterator() { + TRACE_CTOR(posts_commodities_iterator, ""); } - xacts_commodities_iterator(journal_t& journal) { - TRACE_CTOR(xacts_commodities_iterator, "journal_t&"); + posts_commodities_iterator(journal_t& journal) { + TRACE_CTOR(posts_commodities_iterator, "journal_t&"); reset(journal); } - virtual ~xacts_commodities_iterator() throw() { - TRACE_DTOR(xacts_commodities_iterator); - foreach (entry_t * entry, entry_temps) - checked_delete(entry); + virtual ~posts_commodities_iterator() throw() { + TRACE_DTOR(posts_commodities_iterator); + foreach (xact_t * xact, xact_temps) + checked_delete(xact); } void reset(journal_t& journal); - virtual xact_t * operator()(); + virtual post_t * operator()(); }; /** diff --git a/src/journal.cc b/src/journal.cc index 823b31d0..d455939b 100644 --- a/src/journal.cc +++ b/src/journal.cc @@ -40,17 +40,17 @@ journal_t::~journal_t() { TRACE_DTOR(journal_t); - // Don't bother unhooking each entry's xacts from the + // Don't bother unhooking each xact's posts from the // accounts they refer to, because all accounts are about to // be deleted. - foreach (entry_t * entry, entries) - checked_delete(entry); + foreach (xact_t * xact, xacts) + checked_delete(xact); - foreach (auto_entry_t * entry, auto_entries) - checked_delete(entry); + foreach (auto_xact_t * xact, auto_xacts) + checked_delete(xact); - foreach (period_entry_t * entry, period_entries) - checked_delete(entry); + foreach (period_xact_t * xact, period_xacts) + checked_delete(xact); } void journal_t::add_account(account_t * acct) @@ -73,36 +73,36 @@ account_t * journal_t::find_account_re(const string& regexp) return master->find_account_re(regexp); } -bool journal_t::add_entry(entry_t * entry) +bool journal_t::add_xact(xact_t * xact) { - entry->journal = this; + xact->journal = this; - if (! entry_finalize_hooks.run_hooks(*entry, false) || - ! entry->finalize() || - ! entry_finalize_hooks.run_hooks(*entry, true)) { - entry->journal = NULL; + if (! xact_finalize_hooks.run_hooks(*xact, false) || + ! xact->finalize() || + ! xact_finalize_hooks.run_hooks(*xact, true)) { + xact->journal = NULL; return false; } - entries.push_back(entry); + xacts.push_back(xact); return true; } -bool journal_t::remove_entry(entry_t * entry) +bool journal_t::remove_xact(xact_t * xact) { bool found = false; - entries_list::iterator i; - for (i = entries.begin(); i != entries.end(); i++) - if (*i == entry) { + xacts_list::iterator i; + for (i = xacts.begin(); i != xacts.end(); i++) + if (*i == xact) { found = true; break; } if (! found) return false; - entries.erase(i); - entry->journal = NULL; + xacts.erase(i); + xact->journal = NULL; return true; } @@ -114,9 +114,9 @@ bool journal_t::valid() const return false; } - foreach (const entry_t * entry, entries) - if (! entry->valid()) { - DEBUG("ledger.validate", "journal_t: entry not valid"); + foreach (const xact_t * xact, xacts) + if (! xact->valid()) { + DEBUG("ledger.validate", "journal_t: xact not valid"); return false; } diff --git a/src/journal.h b/src/journal.h index b0d61c98..b8af8b00 100644 --- a/src/journal.h +++ b/src/journal.h @@ -48,7 +48,7 @@ #include "utils.h" #include "hooks.h" -#include "entry.h" +#include "xact.h" namespace ledger { @@ -66,12 +66,12 @@ class journal_t : public noncopyable public: account_t * master; account_t * basket; - entries_list entries; + xacts_list xacts; - auto_entries_list auto_entries; - period_entries_list period_entries; + auto_xacts_list auto_xacts; + period_xacts_list period_xacts; - hooks_t<entry_finalizer_t, entry_t> entry_finalize_hooks; + hooks_t<xact_finalizer_t, xact_t> xact_finalize_hooks; journal_t(account_t * _master = NULL) : master(_master) { TRACE_CTOR(journal_t, ""); @@ -85,14 +85,14 @@ public: account_t * find_account(const string& name, bool auto_create = true); account_t * find_account_re(const string& regexp); - bool add_entry(entry_t * entry); - bool remove_entry(entry_t * entry); + bool add_xact(xact_t * xact); + bool remove_xact(xact_t * xact); - void add_entry_finalizer(entry_finalizer_t * finalizer) { - entry_finalize_hooks.add_hook(finalizer); + void add_xact_finalizer(xact_finalizer_t * finalizer) { + xact_finalize_hooks.add_hook(finalizer); } - void remove_entry_finalizer(entry_finalizer_t * finalizer) { - entry_finalize_hooks.remove_hook(finalizer); + void remove_xact_finalizer(xact_finalizer_t * finalizer) { + xact_finalize_hooks.remove_hook(finalizer); } std::size_t parse(std::istream& in, diff --git a/src/output.cc b/src/output.cc index e33ae627..7daae417 100644 --- a/src/output.cc +++ b/src/output.cc @@ -33,13 +33,13 @@ namespace ledger { -format_xacts::format_xacts(report_t& _report, +format_posts::format_posts(report_t& _report, const string& format, bool _print_raw) - : report(_report), last_entry(NULL), last_xact(NULL), + : report(_report), last_xact(NULL), last_post(NULL), print_raw(_print_raw) { - TRACE_CTOR(format_xacts, "report&, const string&"); + TRACE_CTOR(format_posts, "report&, const string&"); const char * f = format.c_str(); @@ -58,46 +58,46 @@ format_xacts::format_xacts(report_t& _report, } } -void format_xacts::operator()(xact_t& xact) +void format_posts::operator()(post_t& post) { std::ostream& out(report.output_stream); if (print_raw) { - if (! xact.has_xdata() || - ! xact.xdata().has_flags(XACT_EXT_DISPLAYED)) { - if (last_entry != xact.entry) { - if (last_entry) { - bind_scope_t entry_scope(report, *last_entry); - between_format.format(out, entry_scope); + if (! post.has_xdata() || + ! post.xdata().has_flags(POST_EXT_DISPLAYED)) { + if (last_xact != post.xact) { + if (last_xact) { + bind_scope_t xact_scope(report, *last_xact); + between_format.format(out, xact_scope); } - print_item(out, *xact.entry); + print_item(out, *post.xact); out << '\n'; - last_entry = xact.entry; + last_xact = post.xact; } - xact.xdata().add_flags(XACT_EXT_DISPLAYED); - last_xact = &xact; + post.xdata().add_flags(POST_EXT_DISPLAYED); + last_post = &post; } } - else if (! xact.has_xdata() || - ! xact.xdata().has_flags(XACT_EXT_DISPLAYED)) { - bind_scope_t bound_scope(report, xact); - if (last_entry != xact.entry) { - if (last_entry) { - bind_scope_t entry_scope(report, *last_entry); - between_format.format(out, entry_scope); + else if (! post.has_xdata() || + ! post.xdata().has_flags(POST_EXT_DISPLAYED)) { + bind_scope_t bound_scope(report, post); + if (last_xact != post.xact) { + if (last_xact) { + bind_scope_t xact_scope(report, *last_xact); + between_format.format(out, xact_scope); } first_line_format.format(out, bound_scope); - last_entry = xact.entry; + last_xact = post.xact; } - else if (last_xact && last_xact->date() != xact.date()) { + else if (last_post && last_post->date() != post.date()) { first_line_format.format(out, bound_scope); } else { next_lines_format.format(out, bound_scope); } - xact.xdata().add_flags(XACT_EXT_DISPLAYED); - last_xact = &xact; + post.xdata().add_flags(POST_EXT_DISPLAYED); + last_post = &post; } } @@ -105,10 +105,10 @@ void gather_statistics::flush() { std::ostream& out(report.output_stream); - out << "Time period: " << statistics.earliest_xact << " to " - << statistics.latest_xact << std::endl << std::endl; + out << "Time period: " << statistics.earliest_post << " to " + << statistics.latest_post << std::endl << std::endl; - out << " Files these transactions came from:" << std::endl; + out << " Files these postings came from:" << std::endl; foreach (const path& pathname, statistics.filenames) if (! pathname.empty()) @@ -123,54 +123,54 @@ void gather_statistics::flush() out.width(8); out << std::right << statistics.accounts_referenced.size() << std::endl; - out << " Number of entries: " ; + out << " Number of transactions: " ; out.width(8); - out << std::right << statistics.total_entries << std::endl; + out << std::right << statistics.total_xacts << std::endl; - out << " Number of transactions: "; + out << " Number of postings: "; out.width(8); - out << std::right << statistics.total_xacts; + out << std::right << statistics.total_posts; out << " ("; out.precision(2); - out << (double((statistics.latest_xact - statistics.earliest_xact).days()) / - double(statistics.total_xacts)) << " per day)" << std::endl; + out << (double((statistics.latest_post - statistics.earliest_post).days()) / + double(statistics.total_posts)) << " per day)" << std::endl; - out << " Days since last xact: "; + out << " Days since last post: "; out.width(8); - out << std::right << (CURRENT_DATE() - statistics.latest_xact).days() + out << std::right << (CURRENT_DATE() - statistics.latest_post).days() << std::endl; - out << " Xacts in last 7 days: "; + out << " Posts in last 7 days: "; out.width(8); out << std::right << statistics.total_last_7_days << std::endl; - out << " Xacts in last 30 days: "; + out << " Posts in last 30 days: "; out.width(8); out << std::right << statistics.total_last_30_days << std::endl; - out << " Xacts seen this month: "; + out << " Posts seen this month: "; out.width(8); out << std::right << statistics.total_this_month << std::endl; - out << " Uncleared transactions: "; + out << " Uncleared postings: "; out.width(8); - out << std::right << statistics.total_uncleared_xacts << std::endl; + out << std::right << statistics.total_uncleared_posts << std::endl; out.flush(); } -void gather_statistics::operator()(xact_t& xact) +void gather_statistics::operator()(post_t& post) { - if (last_entry != xact.entry) { - statistics.total_entries++; - last_entry = xact.entry; - } - if (last_xact != &xact) { + if (last_xact != post.xact) { statistics.total_xacts++; - last_xact = &xact; + last_xact = post.xact; + } + if (last_post != &post) { + statistics.total_posts++; + last_post = &post; - statistics.filenames.insert(xact.pathname); + statistics.filenames.insert(post.pathname); - date_t date = xact.date(); + date_t date = post.date(); if (date.year() == CURRENT_DATE().year() && date.month() == CURRENT_DATE().month()) @@ -181,18 +181,18 @@ void gather_statistics::operator()(xact_t& xact) if ((CURRENT_DATE() - date).days() <= 7) statistics.total_last_7_days++; - if (xact.state() != item_t::CLEARED) - statistics.total_uncleared_xacts++; + if (post.state() != item_t::CLEARED) + statistics.total_uncleared_posts++; - if (! is_valid(statistics.earliest_xact) || - xact.date() < statistics.earliest_xact) - statistics.earliest_xact = xact.date(); - if (! is_valid(statistics.latest_xact) || - xact.date() > statistics.latest_xact) - statistics.latest_xact = xact.date(); + if (! is_valid(statistics.earliest_post) || + post.date() < statistics.earliest_post) + statistics.earliest_post = post.date(); + if (! is_valid(statistics.latest_post) || + post.date() > statistics.latest_post) + statistics.latest_post = post.date(); - statistics.accounts_referenced.insert(xact.account->fullname()); - statistics.payees_referenced.insert(xact.entry->payee); + statistics.accounts_referenced.insert(post.account->fullname()); + statistics.payees_referenced.insert(post.xact->payee); } } diff --git a/src/output.h b/src/output.h index fe007d42..93fd1d53 100644 --- a/src/output.h +++ b/src/output.h @@ -56,28 +56,28 @@ namespace ledger { * * Long. */ -class format_xacts : public item_handler<xact_t> +class format_posts : public item_handler<post_t> { protected: report_t& report; format_t first_line_format; format_t next_lines_format; format_t between_format; - entry_t * last_entry; - xact_t * last_xact; + xact_t * last_xact; + post_t * last_post; bool print_raw; public: - format_xacts(report_t& _report, const string& format, + format_posts(report_t& _report, const string& format, bool _print_raw = false); - virtual ~format_xacts() { - TRACE_DTOR(format_xacts); + virtual ~format_posts() { + TRACE_DTOR(format_posts); } virtual void flush() { report.output_stream.flush(); } - virtual void operator()(xact_t& xact); + virtual void operator()(post_t& post); }; /** @@ -85,37 +85,37 @@ public: * * Long. */ -class gather_statistics : public item_handler<xact_t> +class gather_statistics : public item_handler<post_t> { protected: report_t& report; - entry_t * last_entry; - xact_t * last_xact; + xact_t * last_xact; + post_t * last_post; struct statistics_t { std::set<path> filenames; - std::size_t total_entries; std::size_t total_xacts; - std::size_t total_uncleared_xacts; + std::size_t total_posts; + std::size_t total_uncleared_posts; std::size_t total_last_7_days; std::size_t total_last_30_days; std::size_t total_this_month; - date_t earliest_xact; - date_t latest_xact; + date_t earliest_post; + date_t latest_post; std::set<string> accounts_referenced; std::set<string> payees_referenced; statistics_t() - : total_entries(0), total_xacts(0), total_uncleared_xacts(0), + : total_xacts(0), total_posts(0), total_uncleared_posts(0), total_last_7_days(0), total_last_30_days(0), total_this_month(0) {} } statistics; public: gather_statistics(report_t& _report) - : report(_report), last_entry(NULL), last_xact(NULL) { + : report(_report), last_xact(NULL), last_post(NULL) { TRACE_CTOR(gather_statistics, "report&"); } virtual ~gather_statistics() { @@ -123,7 +123,7 @@ public: } virtual void flush(); - virtual void operator()(xact_t& xact); + virtual void operator()(post_t& post); }; /** diff --git a/src/post.cc b/src/post.cc new file mode 100644 index 00000000..e87a1cbc --- /dev/null +++ b/src/post.cc @@ -0,0 +1,336 @@ +/* + * Copyright (c) 2003-2009, John Wiegley. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of New Artisans LLC nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "post.h" +#include "journal.h" +#include "account.h" +#include "interactive.h" +#include "format.h" + +namespace ledger { + +bool post_t::has_tag(const string& tag) const +{ + if (item_t::has_tag(tag)) + return true; + if (xact) + return xact->has_tag(tag); + return false; +} + +bool post_t::has_tag(const mask_t& tag_mask, + const optional<mask_t>& value_mask) const +{ + if (item_t::has_tag(tag_mask, value_mask)) + return true; + if (xact) + return xact->has_tag(tag_mask, value_mask); + return false; +} + +optional<string> post_t::get_tag(const string& tag) const +{ + if (optional<string> value = item_t::get_tag(tag)) + return value; + if (xact) + return xact->get_tag(tag); + return none; +} + +optional<string> post_t::get_tag(const mask_t& tag_mask, + const optional<mask_t>& value_mask) const +{ + if (optional<string> value = item_t::get_tag(tag_mask, value_mask)) + return value; + if (xact) + return xact->get_tag(tag_mask, value_mask); + return none; +} + +date_t post_t::date() const +{ + if (xdata_ && is_valid(xdata_->date)) + return xdata_->date; + + if (item_t::use_effective_date) { + if (_date_eff) + return *_date_eff; + else if (xact && xact->_date_eff) + return *xact->_date_eff; + } + + if (! _date) { + assert(xact); + return xact->date(); + } + return *_date; +} + +optional<date_t> post_t::effective_date() const +{ + optional<date_t> date = item_t::effective_date(); + if (! date && xact) + return xact->effective_date(); + return date; +} + +item_t::state_t post_t::state() const +{ + if (xact) { + state_t xact_state = xact->state(); + if ((_state == UNCLEARED && xact_state != UNCLEARED) || + (_state == PENDING && xact_state == CLEARED)) + return xact_state; + } + return _state; +} + +namespace { + value_t get_this(post_t& post) { + return value_t(static_cast<scope_t *>(&post)); + } + + value_t get_is_calculated(post_t& post) { + return post.has_flags(POST_CALCULATED); + } + + value_t get_virtual(post_t& post) { + return post.has_flags(POST_VIRTUAL); + } + + value_t get_real(post_t& post) { + return ! post.has_flags(POST_VIRTUAL); + } + + value_t get_actual(post_t& post) { + return ! post.has_flags(POST_AUTO); + } + + value_t get_xact(post_t& post) { + return value_t(static_cast<scope_t *>(post.xact)); + } + + value_t get_code(post_t& post) { + if (post.xact->code) + return string_value(*post.xact->code); + else + return string_value(empty_string); + } + + value_t get_payee(post_t& post) { + return string_value(post.xact->payee); + } + + value_t get_amount(post_t& post) { + if (post.has_xdata() && + post.xdata().has_flags(POST_EXT_COMPOUND)) { + return post.xdata().value; + } else { + return post.amount; + } + } + + value_t get_commodity(post_t& post) { + return string_value(post.amount.commodity().symbol()); + } + + value_t get_commodity_is_primary(post_t& post) { + return post.amount.commodity().has_flags(COMMODITY_PRIMARY); + } + + value_t get_cost(post_t& post) { + if (post.has_xdata() && + post.xdata().has_flags(POST_EXT_COMPOUND)) { + return post.xdata().value; + } else { + if (post.cost) + return *post.cost; + else + return post.amount; + } + } + + value_t get_total(post_t& post) { + if (post.xdata_ && ! post.xdata_->total.is_null()) + return post.xdata_->total; + else + return post.amount; + } + + value_t get_count(post_t& post) { + if (post.xdata_) + return post.xdata_->count; + else + return 1L; + } + + value_t get_account(call_scope_t& scope) + { + in_context_t<post_t> env(scope, "&l"); + + string name = env->reported_account()->fullname(); + + if (env.has(0) && env.get<long>(0) > 2) + name = format_t::truncate(name, env.get<long>(0) - 2, true); + + if (env->has_flags(POST_VIRTUAL)) { + if (env->must_balance()) + name = string("[") + name + "]"; + else + name = string("(") + name + ")"; + } + return string_value(name); + } + + value_t get_account_base(post_t& post) { + return string_value(post.reported_account()->name); + } + + value_t get_account_depth(post_t& post) { + return long(post.reported_account()->depth); + } + + template <value_t (*Func)(post_t&)> + value_t get_wrapper(call_scope_t& scope) { + return (*Func)(find_scope<post_t>(scope)); + } +} + +expr_t::ptr_op_t post_t::lookup(const string& name) +{ + switch (name[0]) { + case 'a': + if (name[1] == '\0' || name == "amount") + return WRAP_FUNCTOR(get_wrapper<&get_amount>); + else if (name == "account") + return WRAP_FUNCTOR(get_account); + else if (name == "account_base") + return WRAP_FUNCTOR(get_wrapper<&get_account_base>); + else if (name == "actual") + return WRAP_FUNCTOR(get_wrapper<&get_actual>); + break; + + case 'c': + if (name == "code") + return WRAP_FUNCTOR(get_wrapper<&get_code>); + else if (name == "cost") + return WRAP_FUNCTOR(get_wrapper<&get_cost>); + else if (name == "count") + return WRAP_FUNCTOR(get_wrapper<&get_count>); + else if (name == "calculated") + return WRAP_FUNCTOR(get_wrapper<&get_is_calculated>); + else if (name == "commodity") + return WRAP_FUNCTOR(get_wrapper<&get_commodity>); + break; + + case 'd': + if (name == "depth") + return WRAP_FUNCTOR(get_wrapper<&get_account_depth>); + break; + + case 'r': + if (name == "real") + return WRAP_FUNCTOR(get_wrapper<&get_real>); + break; + + case 'p': + if (name == "post") + return WRAP_FUNCTOR(get_wrapper<&get_this>); + else if (name == "payee") + return WRAP_FUNCTOR(get_wrapper<&get_payee>); + else if (name == "primary") + return WRAP_FUNCTOR(get_wrapper<&get_commodity_is_primary>); + break; + + case 't': + if (name[1] == '\0' || name == "total") + return WRAP_FUNCTOR(get_wrapper<&get_total>); + break; + + case 'v': + if (name == "virtual") + return WRAP_FUNCTOR(get_wrapper<&get_virtual>); + break; + + case 'x': + if (name == "xact") + return WRAP_FUNCTOR(get_wrapper<&get_xact>); + break; + } + + return item_t::lookup(name); +} + +bool post_t::valid() const +{ + if (! xact) { + DEBUG("ledger.validate", "post_t: ! xact"); + return false; + } + + posts_list::const_iterator i = + std::find(xact->posts.begin(), + xact->posts.end(), this); + if (i == xact->posts.end()) { + DEBUG("ledger.validate", "post_t: ! found"); + return false; + } + + if (! account) { + DEBUG("ledger.validate", "post_t: ! account"); + return false; + } + + if (! amount.valid()) { + DEBUG("ledger.validate", "post_t: ! amount.valid()"); + return false; + } + + if (cost && ! cost->valid()) { + DEBUG("ledger.validate", "post_t: cost && ! cost->valid()"); + return false; + } + + return true; +} + +void post_t::add_to_value(value_t& value, expr_t& expr) +{ + if (xdata_ && xdata_->has_flags(POST_EXT_COMPOUND)) { + add_or_set_value(value, xdata_->value); + } + else if (! xdata_ || ! xdata_->has_flags(POST_EXT_NO_TOTAL)) { + bind_scope_t bound_scope(*expr.get_context(), *this); + add_or_set_value(value, expr.calc(bound_scope)); + } +} + +} // namespace ledger diff --git a/src/post.h b/src/post.h new file mode 100644 index 00000000..84c0d929 --- /dev/null +++ b/src/post.h @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2003-2009, John Wiegley. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of New Artisans LLC nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @addtogroup data + */ + +/** + * @file post.h + * @author John Wiegley + * + * @ingroup data + * + * @brief Brief + * + * Long. + */ +#ifndef _POST_H +#define _POST_H + +#include "item.h" + +namespace ledger { + +class xact_t; +class account_t; + +class post_t; +typedef std::list<post_t *> posts_list; + +/** + * @brief Brief + * + * Long. + */ +class post_t : public item_t +{ +public: +#define POST_VIRTUAL 0x10 // the account was specified with (parens) +#define POST_MUST_BALANCE 0x20 // the account was specified with [brackets] +#define POST_AUTO 0x40 // posting created by automated xact +#define POST_CALCULATED 0x80 // posting's amount was auto-calculated + + xact_t * xact; // only set for posts of regular xacts + account_t * account; + + amount_t amount; // can be null until finalization + optional<amount_t> cost; + optional<amount_t> assigned_amount; + + post_t(account_t * _account = NULL, + flags_t _flags = ITEM_NORMAL) + : item_t(_flags), + xact(NULL), account(_account) + { + TRACE_CTOR(post_t, "account_t *, flags_t"); + } + post_t(account_t * _account, + const amount_t& _amount, + flags_t _flags = ITEM_NORMAL, + const optional<string>& _note = none) + : item_t(_flags, _note), + xact(NULL), account(_account), amount(_amount) + { + TRACE_CTOR(post_t, "account_t *, const amount_t&, flags_t, const optional<string>&"); + } + post_t(const post_t& post) + : item_t(post), + xact(post.xact), + account(post.account), + amount(post.amount), + cost(post.cost), + assigned_amount(post.assigned_amount), + xdata_(post.xdata_) + { + TRACE_CTOR(post_t, "copy"); + } + ~post_t() { + TRACE_DTOR(post_t); + } + + virtual bool has_tag(const string& tag) const; + virtual bool has_tag(const mask_t& tag_mask, + const optional<mask_t>& value_mask = none) const; + + virtual optional<string> get_tag(const string& tag) const; + virtual optional<string> get_tag(const mask_t& tag_mask, + const optional<mask_t>& value_mask = none) const; + + virtual date_t date() const; + virtual optional<date_t> effective_date() const; + + virtual state_t state() const; + + bool must_balance() const { + return ! has_flags(POST_VIRTUAL) || has_flags(POST_MUST_BALANCE); + } + + virtual expr_t::ptr_op_t lookup(const string& name); + + bool valid() const; + + struct xdata_t : public supports_flags<> + { +#define POST_EXT_RECEIVED 0x01 +#define POST_EXT_HANDLED 0x02 +#define POST_EXT_TO_DISPLAY 0x04 +#define POST_EXT_DISPLAYED 0x08 +#define POST_EXT_NO_TOTAL 0x10 +#define POST_EXT_SORT_CALC 0x20 +#define POST_EXT_COMPOUND 0x40 +#define POST_EXT_MATCHES 0x80 + + value_t total; + std::size_t count; + value_t value; + date_t date; + account_t * account; + void * ptr; + + std::list<sort_value_t> sort_values; + + xdata_t() + : supports_flags<>(), count(0), account(NULL), ptr(NULL) { + TRACE_CTOR(post_t::xdata_t, ""); + } + xdata_t(const xdata_t& other) + : supports_flags<>(other.flags()), + total(other.total), + count(other.count), + value(other.value), + date(other.date), + account(other.account), + ptr(NULL), + sort_values(other.sort_values) + { + TRACE_CTOR(post_t::xdata_t, "copy"); + } + ~xdata_t() throw() { + TRACE_DTOR(post_t::xdata_t); + } + }; + + // This variable holds optional "extended data" which is usually produced + // only during reporting, and only for the posting set being reported. + // It's a memory-saving measure to delay allocation until the last possible + // moment. + mutable optional<xdata_t> xdata_; + + bool has_xdata() const { + return xdata_; + } + void clear_xdata() { + xdata_ = none; + } + xdata_t& xdata() { + if (! xdata_) + xdata_ = xdata_t(); + return *xdata_; + } + + void add_to_value(value_t& value, expr_t& expr); + + account_t * reported_account() { + if (xdata_) + if (account_t * acct = xdata_->account) + return acct; + return account; + } + + const account_t * reported_account() const { + return const_cast<post_t *>(this)->reported_account(); + } + + friend class xact_t; +}; + +} // namespace ledger + +#endif // _POST_H diff --git a/src/precmd.cc b/src/precmd.cc index 4b623904..e890e2f5 100644 --- a/src/precmd.cc +++ b/src/precmd.cc @@ -36,7 +36,7 @@ namespace ledger { namespace { - xact_t * get_sample_xact(report_t& report) + post_t * get_sample_post(report_t& report) { { string str; @@ -52,7 +52,7 @@ namespace { std::ostream& out(report.output_stream); - out << "--- Context is first transaction of the following entry ---" + out << "--- Context is first posting of the following transaction ---" << std::endl << str << std::endl; { std::istringstream in(str); @@ -60,8 +60,8 @@ namespace { report.session.clean_accounts(); } } - entry_t * first = report.session.journal->entries.front(); - return first->xacts.front(); + xact_t * first = report.session.journal->xacts.front(); + return first->posts.front(); } } @@ -76,7 +76,7 @@ value_t parse_command(call_scope_t& args) report_t& report(find_scope<report_t>(args)); std::ostream& out(report.output_stream); - xact_t * xact = get_sample_xact(report); + post_t * post = get_sample_post(report); out << "--- Input expression ---" << std::endl; out << arg << std::endl; @@ -89,7 +89,7 @@ value_t parse_command(call_scope_t& args) out << std::endl << "--- Expression tree ---" << std::endl; expr.dump(out); - bind_scope_t bound_scope(args, *xact); + bind_scope_t bound_scope(args, *post); expr.compile(bound_scope); out << std::endl << "--- Compiled tree ---" << std::endl; expr.dump(out); @@ -125,7 +125,7 @@ value_t format_command(call_scope_t& args) report_t& report(find_scope<report_t>(args)); std::ostream& out(report.output_stream); - xact_t * xact = get_sample_xact(report); + post_t * post = get_sample_post(report); out << "--- Input format string ---" << std::endl; out << arg << std::endl << std::endl; @@ -135,7 +135,7 @@ value_t format_command(call_scope_t& args) fmt.dump(out); out << std::endl << "--- Formatted string ---" << std::endl; - bind_scope_t bound_scope(args, *xact); + bind_scope_t bound_scope(args, *post); out << '"'; fmt.format(out, bound_scope); out << "\"\n"; diff --git a/src/report.cc b/src/report.cc index 92fc2b34..316aa89b 100644 --- a/src/report.cc +++ b/src/report.cc @@ -41,18 +41,18 @@ namespace ledger { -void report_t::xacts_report(xact_handler_ptr handler) +void report_t::posts_report(post_handler_ptr handler) { - journal_xacts_iterator walker(*session.journal.get()); - pass_down_xacts(chain_xact_handlers(*this, handler), walker); - session.clean_xacts(); + journal_posts_iterator walker(*session.journal.get()); + pass_down_posts(chain_post_handlers(*this, handler), walker); + session.clean_posts(); } -void report_t::entry_report(xact_handler_ptr handler, entry_t& entry) +void report_t::xact_report(post_handler_ptr handler, xact_t& xact) { - entry_xacts_iterator walker(entry); - pass_down_xacts(chain_xact_handlers(*this, handler), walker); - session.clean_xacts(entry); + xact_posts_iterator walker(xact); + pass_down_posts(chain_post_handlers(*this, handler), walker); + session.clean_posts(xact); } void report_t::sum_all_accounts() @@ -60,9 +60,9 @@ void report_t::sum_all_accounts() expr_t& amount_expr(HANDLER(amount_).expr); amount_expr.set_context(this); - journal_xacts_iterator walker(*session.journal.get()); - pass_down_xacts(chain_xact_handlers - (*this, xact_handler_ptr(new set_account_value(amount_expr)), + journal_posts_iterator walker(*session.journal.get()); + pass_down_posts(chain_post_handlers + (*this, post_handler_ptr(new set_account_value(amount_expr)), true), walker); expr_t& account_amount_expr(HANDLER(account_amount_).expr); @@ -89,15 +89,15 @@ void report_t::accounts_report(acct_handler_ptr handler) else pass_down_accounts(handler, *iter.get()); - session.clean_xacts(); + session.clean_posts(); session.clean_accounts(); } -void report_t::commodities_report(xact_handler_ptr handler) +void report_t::commodities_report(post_handler_ptr handler) { - xacts_commodities_iterator walker(*session.journal.get()); - pass_down_xacts(chain_xact_handlers(*this, handler), walker); - session.clean_xacts(); + posts_commodities_iterator walker(*session.journal.get()); + pass_down_posts(chain_post_handlers(*this, handler), walker); + session.clean_posts(); } value_t report_t::fn_amount_expr(call_scope_t& scope) @@ -286,10 +286,10 @@ value_t report_t::fn_ansify_if(call_scope_t& scope) } namespace { - template <class Type = xact_t, - class handler_ptr = xact_handler_ptr, + template <class Type = post_t, + class handler_ptr = post_handler_ptr, void (report_t::*report_method)(handler_ptr) = - &report_t::xacts_report> + &report_t::posts_report> class reporter { shared_ptr<item_handler<Type> > handler; @@ -516,7 +516,7 @@ option_t<report_t> * report_t::lookup_option(const char * p) else OPT(set_price_); else OPT(sort_); else OPT(sort_all_); - else OPT(sort_entries_); + else OPT(sort_xacts_); else OPT_(subtotal); else OPT(start_of_week_); break; @@ -576,7 +576,7 @@ expr_t::ptr_op_t report_t::lookup(const string& name) if (is_eq(q, "csv")) return WRAP_FUNCTOR (reporter<> - (new format_xacts(*this, report_format(HANDLER(csv_format_))), + (new format_posts(*this, report_format(HANDLER(csv_format_))), *this)); break; @@ -584,30 +584,30 @@ expr_t::ptr_op_t report_t::lookup(const string& name) if (is_eq(q, "equity")) return WRAP_FUNCTOR (reporter<> - (new format_xacts(*this, report_format(HANDLER(print_format_))), + (new format_posts(*this, report_format(HANDLER(print_format_))), *this)); - else if (is_eq(q, "entry")) - return WRAP_FUNCTOR(entry_command); + else if (is_eq(q, "xact") || is_eq(q, "entry")) + return WRAP_FUNCTOR(xact_command); else if (is_eq(q, "emacs")) return WRAP_FUNCTOR - (reporter<>(new format_emacs_xacts(output_stream), *this)); + (reporter<>(new format_emacs_posts(output_stream), *this)); break; case 'p': if (*(q + 1) == '\0' || is_eq(q, "print")) return WRAP_FUNCTOR (reporter<> - (new format_xacts(*this, report_format(HANDLER(print_format_)), + (new format_posts(*this, report_format(HANDLER(print_format_)), HANDLED(raw)), *this)); else if (is_eq(q, "prices")) return expr_t::op_t::wrap_functor - (reporter<xact_t, xact_handler_ptr, &report_t::commodities_report> - (new format_xacts(*this, report_format(HANDLER(prices_format_))), + (reporter<post_t, post_handler_ptr, &report_t::commodities_report> + (new format_posts(*this, report_format(HANDLER(prices_format_))), *this)); else if (is_eq(q, "pricesdb")) return expr_t::op_t::wrap_functor - (reporter<xact_t, xact_handler_ptr, &report_t::commodities_report> - (new format_xacts(*this, report_format(HANDLER(pricesdb_format_))), + (reporter<post_t, post_handler_ptr, &report_t::commodities_report> + (new format_posts(*this, report_format(HANDLER(pricesdb_format_))), *this)); break; @@ -615,7 +615,7 @@ expr_t::ptr_op_t report_t::lookup(const string& name) if (*(q + 1) == '\0' || is_eq(q, "reg") || is_eq(q, "register")) return WRAP_FUNCTOR (reporter<> - (new format_xacts(*this, report_format(HANDLER(register_format_))), + (new format_posts(*this, report_format(HANDLER(register_format_))), *this)); else if (is_eq(q, "reload")) return MAKE_FUNCTOR(report_t::reload_command); @@ -700,6 +700,8 @@ expr_t::ptr_op_t report_t::lookup(const string& name) break; } } + else if (is_eq(p, "post")) + return MAKE_FUNCTOR(report_t::fn_false); break; case 'q': @@ -727,11 +729,6 @@ expr_t::ptr_op_t report_t::lookup(const string& name) else if (is_eq(p, "total_expr")) return MAKE_FUNCTOR(report_t::fn_total_expr); break; - - case 'x': - if (is_eq(p, "xact")) - return MAKE_FUNCTOR(report_t::fn_false); - break; } // Check if they are trying to access an option's setting or value. diff --git a/src/report.h b/src/report.h index 4f53e8ec..8fd28ff9 100644 --- a/src/report.h +++ b/src/report.h @@ -63,10 +63,10 @@ namespace ledger { // // 3. Mode of the report. Currently there are four modes: // -// a. Transaction or commodity iteration. In this mode, all the journal's -// entries, the transactions of a specific entry, or all the journal's +// a. Posting or commodity iteration. In this mode, all the journal's +// xacts, the postings of a specific xact, or all the journal's // commodities are walked. In the first two cases, it's the underlying -// transactions which are passed to #2; in the second case, each +// postings which are passed to #2; in the second case, each // commodity is passed to #2. // // b. Account iteration. This employs step 'a', but add a prologue and @@ -79,7 +79,7 @@ namespace ledger { // // c. Write journal. In this mode, a single function is called that output // the journal object as a textual file. #2 is used to print out each -// transaction in the journal. +// posting in the journal. // // d. Dump binary file. This is just like 'c', except that it dumps out a // binary file and #2 is completely ignored. @@ -87,8 +87,8 @@ namespace ledger { // 4. For 'a' and 'b' in #3, there is a different iteration function called, // depending on whether we're iterating: // -// a. The transactions of an entry: walk_transactions. -// b. The entries of a journal: walk_entries. +// a. The postings of an xact: walk_postings. +// b. The xacts of a journal: walk_xacts. // c. The commodities of a journal: walk_commodities. // // 5. Finally, for the 'a' and 'b' reporting modes, there is a variant which @@ -121,10 +121,10 @@ public: output_stream.close(); } - void xacts_report(xact_handler_ptr handler); - void entry_report(xact_handler_ptr handler, entry_t& entry); + void posts_report(post_handler_ptr handler); + void xact_report(post_handler_ptr handler, xact_t& xact); void accounts_report(acct_handler_ptr handler); - void commodities_report(xact_handler_ptr handler); + void commodities_report(post_handler_ptr handler); void sum_all_accounts(); @@ -277,8 +277,8 @@ public: OPTION_(report_t, collapse, DO() { // -n // Make sure that balance reports are collapsed too, but only apply it - // to account entries - parent->HANDLER(display_).on("xact|depth<=1"); + // to account xacts + parent->HANDLER(display_).on("post|depth<=1"); }); OPTION_(report_t, collapse_if_zero, DO() { @@ -292,8 +292,8 @@ public: "%(quoted(payee))," "%(quoted(account))," "%(quoted(scrub(display_amount)))," - "%(quoted((cleared or entry.cleared) ?" - " \"*\" : ((pending or entry.pending) ? \"!\" : \"\")))," + "%(quoted((cleared or xact.cleared) ?" + " \"*\" : ((pending or xact.pending) ? \"!\" : \"\")))," "%(quoted(code))," "%(quoted(join(note)))\n"); }); @@ -390,7 +390,7 @@ public: OPTION_(report_t, gain, DO() { // -G parent->HANDLER(revalued).on_only(); parent->HANDLER(amount_).set_expr("(amount, cost)"); - // Since we are displaying the amounts of revalued transactions, they + // Since we are displaying the amounts of revalued postings, they // will end up being composite totals, and hence a pair of pairs. parent->HANDLER(display_amount_) .set_expr("is_seq(get_at(amount_expr, 0)) ?" @@ -499,14 +499,14 @@ public: }); OPTION__(report_t, print_format_, CTOR(report_t, print_format_) { - on("%(format_date(entry.date, \"%Y/%m/%d\"))" - "%(entry.cleared ? \" *\" : (entry.pending ? \" !\" : \"\"))" - "%(code ? \" (\" + code + \")\" : \"\") %(payee)%(entry.comment | \"\")\n" - " %(entry.uncleared ? (cleared ? \"* \" : (pending ? \"! \" : \"\")) : \"\")" + on("%(format_date(xact.date, \"%Y/%m/%d\"))" + "%(xact.cleared ? \" *\" : (xact.pending ? \" !\" : \"\"))" + "%(code ? \" (\" + code + \")\" : \"\") %(payee)%(xact.comment | \"\")\n" + " %(xact.uncleared ? (cleared ? \"* \" : (pending ? \"! \" : \"\")) : \"\")" "%-34(account)" " %12(calculated ? \"\" : justify(scrub(amount), 12, -1, true))" "%(comment | \"\")\n%/" - " %(entry.uncleared ? (cleared ? \"* \" : (pending ? \"! \" : \"\")) : \"\")" + " %(xact.uncleared ? (cleared ? \"* \" : (pending ? \"! \" : \"\")) : \"\")" "%-34(account)" " %12(calculated ? \"\" : justify(scrub(amount), 12, -1, true))" "%(comment | \"\")\n%/\n"); @@ -574,16 +574,16 @@ public: OPTION_(report_t, sort_, DO_(args) { // -S on_with(args[0]); - parent->HANDLER(sort_entries_).off(); + parent->HANDLER(sort_xacts_).off(); parent->HANDLER(sort_all_).off(); }); OPTION_(report_t, sort_all_, DO_(args) { parent->HANDLER(sort_).on_with(args[0]); - parent->HANDLER(sort_entries_).off(); + parent->HANDLER(sort_xacts_).off(); }); - OPTION_(report_t, sort_entries_, DO_(args) { + OPTION_(report_t, sort_xacts_, DO_(args) { parent->HANDLER(sort_).on_with(args[0]); parent->HANDLER(sort_all_).off(); }); diff --git a/src/session.cc b/src/session.cc index 54fd8e4e..6fa07664 100644 --- a/src/session.cc +++ b/src/session.cc @@ -105,7 +105,7 @@ std::size_t session_t::read_data(const string& master_account) if (HANDLER(file_).data_files.empty()) throw_(parse_error, "No journal file was specified (please use -f)"); - std::size_t entry_count = 0; + std::size_t xact_count = 0; account_t * acct = journal->master; if (! master_account.empty()) @@ -114,7 +114,7 @@ std::size_t session_t::read_data(const string& master_account) if (HANDLED(price_db_)) { path price_db_path = resolve_path(HANDLER(price_db_).str()); if (exists(price_db_path) && read_journal(price_db_path) > 0) - throw_(parse_error, "Entries not allowed in price history file"); + throw_(parse_error, "Transactions not allowed in price history file"); } foreach (const path& pathname, HANDLER(file_).data_files) { @@ -135,10 +135,10 @@ std::size_t session_t::read_data(const string& master_account) std::istringstream buf_in(buffer.str()); - entry_count += read_journal(buf_in, "/dev/stdin", acct); + xact_count += read_journal(buf_in, "/dev/stdin", acct); } else if (exists(filename)) { - entry_count += read_journal(filename, acct); + xact_count += read_journal(filename, acct); } else { throw_(parse_error, "Could not read journal file '" << filename << "'"); @@ -147,7 +147,7 @@ std::size_t session_t::read_data(const string& master_account) VERIFY(journal->valid()); - return entry_count; + return xact_count; } void session_t::read_journal_files() @@ -160,12 +160,12 @@ void session_t::read_journal_files() std::size_t count = read_data(master_account); if (count == 0) - throw_(parse_error, "Failed to locate any journal entries; " + throw_(parse_error, "Failed to locate any transactions; " "did you specify a valid file with -f?"); INFO_FINISH(journal); - INFO("Found " << count << " entries"); + INFO("Found " << count << " transactions"); } void session_t::close_journal_files() @@ -181,16 +181,16 @@ void session_t::close_journal_files() journal.reset(new journal_t(master.get())); } -void session_t::clean_xacts() +void session_t::clean_posts() { - journal_xacts_iterator walker(*journal.get()); - pass_down_xacts(xact_handler_ptr(new clear_xact_xdata), walker); + journal_posts_iterator walker(*journal.get()); + pass_down_posts(post_handler_ptr(new clear_post_xdata), walker); } -void session_t::clean_xacts(entry_t& entry) +void session_t::clean_posts(xact_t& xact) { - entry_xacts_iterator walker(entry); - pass_down_xacts(xact_handler_ptr(new clear_xact_xdata), walker); + xact_posts_iterator walker(xact); + pass_down_posts(post_handler_ptr(new clear_post_xdata), walker); } void session_t::clean_accounts() diff --git a/src/session.h b/src/session.h index 280f8c3e..37c694fa 100644 --- a/src/session.h +++ b/src/session.h @@ -90,11 +90,11 @@ public: void read_journal_files(); void close_journal_files(); - void clean_xacts(); - void clean_xacts(entry_t& entry); + void clean_posts(); + void clean_posts(xact_t& xact); void clean_accounts(); void clean_all() { - clean_xacts(); + clean_posts(); clean_accounts(); } diff --git a/src/textual.cc b/src/textual.cc index 6803c78a..d53b4670 100644 --- a/src/textual.cc +++ b/src/textual.cc @@ -68,7 +68,7 @@ namespace { std::size_t count; std::size_t errors; - scoped_ptr<auto_entry_finalizer_t> auto_entry_finalizer; + scoped_ptr<auto_xact_finalizer_t> auto_xact_finalizer; instance_t(std::list<account_t *>& _account_stack, #if defined(TIMELOG_SUPPORT) @@ -100,13 +100,13 @@ namespace { void default_commodity_directive(char * line); void default_account_directive(char * line); void price_conversion_directive(char * line); - void price_entry_directive(char * line); + void price_xact_directive(char * line); void nomarket_directive(char * line); void year_directive(char * line); void option_directive(char * line); - void automated_entry_directive(char * line); - void period_entry_directive(char * line); - void entry_directive(char * line, std::streamsize len); + void automated_xact_directive(char * line); + void period_xact_directive(char * line); + void xact_directive(char * line, std::streamsize len); void include_directive(char * line); void account_directive(char * line); void end_directive(char * line); @@ -114,16 +114,16 @@ namespace { void define_directive(char * line); void general_directive(char * line); - xact_t * parse_xact(char * line, + post_t * parse_post(char * line, std::streamsize len, account_t * account, - entry_t * entry, + xact_t * xact, bool honor_strict = true); - bool parse_xacts(account_t * account, - entry_base_t& entry); + bool parse_posts(account_t * account, + xact_base_t& xact); - entry_t * parse_entry(char * line, + xact_t * parse_xact(char * line, std::streamsize len, account_t * account); @@ -133,7 +133,7 @@ namespace { void parse_amount_expr(scope_t& session_scope, std::istream& in, amount_t& amount, - xact_t * xact, + post_t * post, uint_least8_t flags = 0) { expr_t expr(in, flags | static_cast<uint_least8_t>(expr_t::PARSE_PARTIAL)); @@ -150,14 +150,14 @@ namespace { #endif if (expr) { - bind_scope_t bound_scope(session_scope, *xact); + bind_scope_t bound_scope(session_scope, *post); value_t result(expr.calc(bound_scope)); if (! result.is_amount()) - throw_(parse_error, "Transactions may only specify simple amounts"); + throw_(parse_error, "Postings may only specify simple amounts"); amount = result.as_amount(); - DEBUG("textual.parse", "The transaction amount is " << amount); + DEBUG("textual.parse", "The posting amount is " << amount); } } } @@ -199,8 +199,8 @@ instance_t::~instance_t() account_stack.pop_front(); - if (auto_entry_finalizer.get()) - journal.remove_entry_finalizer(auto_entry_finalizer.get()); + if (auto_xact_finalizer.get()) + journal.remove_xact_finalizer(auto_xact_finalizer.get()); } void instance_t::parse() @@ -331,13 +331,13 @@ void instance_t::read_next_directive() case '7': case '8': case '9': - entry_directive(line, len); + xact_directive(line, len); break; - case '=': // automated entry - automated_entry_directive(line); + case '=': // automated xact + automated_xact_directive(line); break; - case '~': // period entry - period_entry_directive(line); + case '~': // period xact + period_xact_directive(line); break; #if defined(TIMELOG_SUPPORT) @@ -360,20 +360,20 @@ void instance_t::read_next_directive() break; #endif // TIMELOG_SUPPORT - case 'A': // a default account for unbalanced xacts + case 'A': // a default account for unbalanced posts default_account_directive(line); break; case 'C': // a set of conversions price_conversion_directive(line); break; - case 'D': // a default commodity for "entry" + case 'D': // a default commodity for "xact" default_commodity_directive(line); break; case 'N': // don't download prices nomarket_directive(line); break; - case 'P': // a pricing entry - price_entry_directive(line); + case 'P': // a pricing xact + price_xact_directive(line); break; case 'Y': // set the current year year_directive(line); @@ -465,7 +465,7 @@ namespace { } } -void instance_t::price_entry_directive(char * line) +void instance_t::price_xact_directive(char * line) { char * date_field_ptr = skip_ws(line + 1); char * time_field_ptr = next_element(date_field_ptr); @@ -526,22 +526,22 @@ void instance_t::option_directive(char * line) process_option(line + 2, session_scope, p, line); } -void instance_t::automated_entry_directive(char * line) +void instance_t::automated_xact_directive(char * line) { - if (! auto_entry_finalizer.get()) { - auto_entry_finalizer.reset(new auto_entry_finalizer_t(&journal)); - journal.add_entry_finalizer(auto_entry_finalizer.get()); + if (! auto_xact_finalizer.get()) { + auto_xact_finalizer.reset(new auto_xact_finalizer_t(&journal)); + journal.add_xact_finalizer(auto_xact_finalizer.get()); } istream_pos_type pos = curr_pos; std::size_t lnum = linenum; - std::auto_ptr<auto_entry_t> ae - (new auto_entry_t(item_predicate(skip_ws(line + 1), + std::auto_ptr<auto_xact_t> ae + (new auto_xact_t(item_predicate(skip_ws(line + 1), keep_details_t(true, true, true)))); - if (parse_xacts(account_stack.front(), *ae.get())) { - journal.auto_entries.push_back(ae.get()); + if (parse_posts(account_stack.front(), *ae.get())) { + journal.auto_xacts.push_back(ae.get()); ae->pathname = pathname; ae->beg_pos = pos; @@ -553,20 +553,20 @@ void instance_t::automated_entry_directive(char * line) } } -void instance_t::period_entry_directive(char * line) +void instance_t::period_xact_directive(char * line) { - std::auto_ptr<period_entry_t> pe(new period_entry_t(skip_ws(line + 1))); + std::auto_ptr<period_xact_t> pe(new period_xact_t(skip_ws(line + 1))); if (! pe->period) throw_(parse_error, "Parsing time period '" << line << "'"); istream_pos_type pos = curr_pos; std::size_t lnum = linenum; - if (parse_xacts(account_stack.front(), *pe.get())) { + if (parse_posts(account_stack.front(), *pe.get())) { if (pe->finalize()) { - extend_entry_base(&journal, *pe.get(), true); + extend_xact_base(&journal, *pe.get(), true); - journal.period_entries.push_back(pe.get()); + journal.period_xacts.push_back(pe.get()); pe->pathname = pathname; pe->beg_pos = pos; @@ -576,30 +576,30 @@ void instance_t::period_entry_directive(char * line) pe.release(); } else { - throw parse_error("Period entry failed to balance"); + throw parse_error("Period transaction failed to balance"); } } } -void instance_t::entry_directive(char * line, std::streamsize len) +void instance_t::xact_directive(char * line, std::streamsize len) { - TRACE_START(entries, 1, "Time spent handling entries:"); + TRACE_START(xacts, 1, "Time spent handling transactions:"); - if (entry_t * entry = parse_entry(line, len, account_stack.front())) { - std::auto_ptr<entry_t> manager(entry); + if (xact_t * xact = parse_xact(line, len, account_stack.front())) { + std::auto_ptr<xact_t> manager(xact); - if (journal.add_entry(entry)) { + if (journal.add_xact(xact)) { manager.release(); // it's owned by the journal now count++; } - // It's perfectly valid for the journal to reject the entry, which it will - // do if the entry has no substantive effect (for example, a checking - // entry, all of whose transactions have null amounts). + // It's perfectly valid for the journal to reject the xact, which it will + // do if the xact has no substantive effect (for example, a checking + // xact, all of whose postings have null amounts). } else { - throw parse_error("Failed to parse entry"); + throw parse_error("Failed to parse transaction"); } - TRACE_STOP(entries, 1); + TRACE_STOP(xacts, 1); } void instance_t::include_directive(char * line) @@ -660,7 +660,7 @@ void instance_t::alias_directive(char * line) // Once we have an alias name (b) and the target account // name (e), add a reference to the account in the - // `account_aliases' map, which is used by the xact + // `account_aliases' map, which is used by the post // parser to resolve alias references. account_t * acct = account_stack.front()->find_account(e); std::pair<accounts_map::iterator, bool> result @@ -730,20 +730,20 @@ void instance_t::general_directive(char * line) } } -xact_t * instance_t::parse_xact(char * line, +post_t * instance_t::parse_post(char * line, std::streamsize len, account_t * account, - entry_t * entry, + xact_t * xact, bool honor_strict) { - TRACE_START(xact_details, 1, "Time spent parsing transactions:"); + TRACE_START(post_details, 1, "Time spent parsing postings:"); - std::auto_ptr<xact_t> xact(new xact_t); + std::auto_ptr<post_t> post(new post_t); - xact->entry = entry; // this could be NULL - xact->pathname = pathname; - xact->beg_pos = line_beg_pos; - xact->beg_line = linenum; + post->xact = xact; // this could be NULL + post->pathname = pathname; + post->beg_pos = line_beg_pos; + post->beg_line = linenum; char buf[MAX_LINE + 1]; std::strcpy(buf, line); @@ -760,42 +760,42 @@ xact_t * instance_t::parse_xact(char * line, switch (*p) { case '*': - xact->set_state(item_t::CLEARED); + post->set_state(item_t::CLEARED); p = skip_ws(p + 1); DEBUG("textual.parse", "line " << linenum << ": " << "Parsed the CLEARED flag"); break; case '!': - xact->set_state(item_t::PENDING); + post->set_state(item_t::PENDING); p = skip_ws(p + 1); DEBUG("textual.parse", "line " << linenum << ": " << "Parsed the PENDING flag"); break; } - if (entry && - ((entry->_state == item_t::CLEARED && xact->_state != item_t::CLEARED) || - (entry->_state == item_t::PENDING && xact->_state == item_t::UNCLEARED))) - xact->set_state(entry->_state); + if (xact && + ((xact->_state == item_t::CLEARED && post->_state != item_t::CLEARED) || + (xact->_state == item_t::PENDING && post->_state == item_t::UNCLEARED))) + post->set_state(xact->_state); // Parse the account name if (! *p) - throw parse_error("Transaction has no account"); + throw parse_error("Posting has no account"); char * next = next_element(p, true); char * e = p + std::strlen(p); if ((*p == '[' && *(e - 1) == ']') || (*p == '(' && *(e - 1) == ')')) { - xact->add_flags(XACT_VIRTUAL); + post->add_flags(POST_VIRTUAL); DEBUG("textual.parse", "line " << linenum << ": " << "Parsed a virtual account name"); if (*p == '[') { - xact->add_flags(XACT_MUST_BALANCE); + post->add_flags(POST_MUST_BALANCE); DEBUG("textual.parse", "line " << linenum << ": " - << "Transaction must balance"); + << "Posting must balance"); } p++; e--; } @@ -807,17 +807,17 @@ xact_t * instance_t::parse_xact(char * line, if (account_aliases.size() > 0) { accounts_map::const_iterator i = account_aliases.find(name); if (i != account_aliases.end()) - xact->account = (*i).second; + post->account = (*i).second; } - if (! xact->account) - xact->account = account->find_account(name); + if (! post->account) + post->account = account->find_account(name); - if (honor_strict && strict && ! xact->account->known) { - if (xact->_state == item_t::UNCLEARED) + if (honor_strict && strict && ! post->account->known) { + if (post->_state == item_t::UNCLEARED) std::cerr << "Warning: \"" << pathname << "\", line " << linenum - << ": Unknown account '" << xact->account->fullname() + << ": Unknown account '" << post->account->fullname() << "'" << std::endl; - xact->account->known = true; + post->account->known = true; } // Parse the optional amount @@ -831,31 +831,31 @@ xact_t * instance_t::parse_xact(char * line, ptristream stream(next, len - beg); if (*next != '(') // indicates a value expression - xact->amount.parse(stream, amount_t::PARSE_NO_REDUCE); + post->amount.parse(stream, amount_t::PARSE_NO_REDUCE); else - parse_amount_expr(session_scope, stream, xact->amount, xact.get(), + parse_amount_expr(session_scope, stream, post->amount, post.get(), static_cast<uint_least8_t>(expr_t::PARSE_NO_REDUCE) | static_cast<uint_least8_t>(expr_t::PARSE_NO_ASSIGN)); - if (! xact->amount.is_null() && honor_strict && strict && - xact->amount.has_commodity() && - ! xact->amount.commodity().has_flags(COMMODITY_KNOWN)) { - if (xact->_state == item_t::UNCLEARED) + if (! post->amount.is_null() && honor_strict && strict && + post->amount.has_commodity() && + ! post->amount.commodity().has_flags(COMMODITY_KNOWN)) { + if (post->_state == item_t::UNCLEARED) std::cerr << "Warning: \"" << pathname << "\", line " << linenum - << ": Unknown commodity '" << xact->amount.commodity() + << ": Unknown commodity '" << post->amount.commodity() << "'" << std::endl; - xact->amount.commodity().add_flags(COMMODITY_KNOWN); + post->amount.commodity().add_flags(COMMODITY_KNOWN); } #if 0 // jww (2009-02-12): This isn't quite working yet; it causes cost computes // to skyrocket, since the per-unit price isn't also being reduced by the // same factor. - if (! xact->amount.is_null()) - xact->amount.in_place_reduce(); + if (! post->amount.is_null()) + post->amount.in_place_reduce(); #endif DEBUG("textual.parse", "line " << linenum << ": " - << "xact amount = " << xact->amount); + << "post amount = " << post->amount); if (stream.eof()) { next = NULL; @@ -880,28 +880,28 @@ xact_t * instance_t::parse_xact(char * line, p = skip_ws(next); if (*p) { - xact->cost = amount_t(); + post->cost = amount_t(); beg = p - line; ptristream cstream(p, len - beg); if (*p != '(') // indicates a value expression - xact->cost->parse(cstream, amount_t::PARSE_NO_MIGRATE); + post->cost->parse(cstream, amount_t::PARSE_NO_MIGRATE); else - parse_amount_expr(session_scope, cstream, *xact->cost, xact.get(), + parse_amount_expr(session_scope, cstream, *post->cost, post.get(), static_cast<uint_least8_t>(expr_t::PARSE_NO_MIGRATE) | static_cast<uint_least8_t>(expr_t::PARSE_NO_ASSIGN)); - if (xact->cost->sign() < 0) - throw parse_error("A transaction's cost may not be negative"); + if (post->cost->sign() < 0) + throw parse_error("A posting's cost may not be negative"); if (per_unit) - *xact->cost *= xact->amount; + *post->cost *= post->amount; DEBUG("textual.parse", "line " << linenum << ": " - << "Total cost is " << *xact->cost); + << "Total cost is " << *post->cost); DEBUG("textual.parse", "line " << linenum << ": " - << "Annotated amount is " << xact->amount); + << "Annotated amount is " << post->amount); if (cstream.eof()) next = NULL; @@ -916,7 +916,7 @@ xact_t * instance_t::parse_xact(char * line, // Parse the optional balance assignment - if (entry && next && *next == '=') { + if (xact && next && *next == '=') { DEBUG("textual.parse", "line " << linenum << ": " << "Found a balance assignment indicator"); @@ -924,30 +924,30 @@ xact_t * instance_t::parse_xact(char * line, p = skip_ws(next); if (*p) { - xact->assigned_amount = amount_t(); + post->assigned_amount = amount_t(); beg = p - line; ptristream stream(p, len - beg); if (*p != '(') // indicates a value expression - xact->assigned_amount->parse(stream, amount_t::PARSE_NO_MIGRATE); + post->assigned_amount->parse(stream, amount_t::PARSE_NO_MIGRATE); else - parse_amount_expr(session_scope, stream, *xact->assigned_amount, xact.get(), + parse_amount_expr(session_scope, stream, *post->assigned_amount, post.get(), static_cast<uint_least8_t>(expr_t::PARSE_NO_MIGRATE)); - if (xact->assigned_amount->is_null()) + if (post->assigned_amount->is_null()) throw parse_error("An assigned balance must evaluate to a constant value"); DEBUG("textual.parse", "line " << linenum << ": " - << "XACT assign: parsed amt = " << *xact->assigned_amount); + << "POST assign: parsed amt = " << *post->assigned_amount); - account_t::xdata_t& xdata(xact->account->xdata()); - amount_t& amt(*xact->assigned_amount); + account_t::xdata_t& xdata(post->account->xdata()); + amount_t& amt(*post->assigned_amount); - DEBUG("xact.assign", "line " << linenum << ": " + DEBUG("post.assign", "line " << linenum << ": " "account balance = " << xdata.value); - DEBUG("xact.assign", "line " << linenum << ": " - "xact amount = " << amt); + DEBUG("post.assign", "line " << linenum << ": " + "post amount = " << amt); amount_t diff; @@ -969,26 +969,26 @@ xact_t * instance_t::parse_xact(char * line, break; } - DEBUG("xact.assign", "line " << linenum << ": " + DEBUG("post.assign", "line " << linenum << ": " << "diff = " << diff); DEBUG("textual.parse", "line " << linenum << ": " - << "XACT assign: diff = " << diff); + << "POST assign: diff = " << diff); if (! diff.is_zero()) { - if (! xact->amount.is_null()) { - diff -= xact->amount; + if (! post->amount.is_null()) { + diff -= post->amount; if (! diff.is_zero()) { - xact_t * temp = new xact_t(xact->account, diff, - ITEM_GENERATED | XACT_CALCULATED); - entry->add_xact(temp); + post_t * temp = new post_t(post->account, diff, + ITEM_GENERATED | POST_CALCULATED); + xact->add_post(temp); DEBUG("textual.parse", "line " << linenum << ": " - << "Created balancing transaction"); + << "Created balancing posting"); } } else { - xact->amount = diff; + post->amount = diff; DEBUG("textual.parse", "line " << linenum << ": " - << "Overwrite null transaction"); + << "Overwrite null posting"); } } @@ -1004,10 +1004,10 @@ xact_t * instance_t::parse_xact(char * line, // Parse the optional note if (next && *next == ';') { - xact->append_note(++next, current_year); + post->append_note(++next, current_year); next = line + len; DEBUG("textual.parse", "line " << linenum << ": " - << "Parsed a transaction note"); + << "Parsed a posting note"); } // There should be nothing more to read @@ -1016,25 +1016,25 @@ xact_t * instance_t::parse_xact(char * line, throw_(parse_error, "Unexpected char '" << *next << "' (Note: inline math requires parentheses)"); - xact->end_pos = curr_pos; - xact->end_line = linenum; + post->end_pos = curr_pos; + post->end_line = linenum; - TRACE_STOP(xact_details, 1); + TRACE_STOP(post_details, 1); - return xact.release(); + return post.release(); } catch (const std::exception& err) { - add_error_context("While parsing transaction:"); + add_error_context("While parsing posting:"); add_error_context(line_context(buf, beg, len)); throw; } } -bool instance_t::parse_xacts(account_t * account, - entry_base_t& entry) +bool instance_t::parse_posts(account_t * account, + xact_base_t& xact) { - TRACE_START(entry_xacts, 1, "Time spent parsing transactions:"); + TRACE_START(xact_posts, 1, "Time spent parsing postings:"); bool added = false; @@ -1043,24 +1043,24 @@ bool instance_t::parse_xacts(account_t * account, std::streamsize len = read_line(line); assert(len > 0); - if (xact_t * xact = parse_xact(line, len, account, NULL, false)) { - entry.add_xact(xact); + if (post_t * post = parse_post(line, len, account, NULL, false)) { + xact.add_post(post); added = true; } } - TRACE_STOP(entry_xacts, 1); + TRACE_STOP(xact_posts, 1); return added; } -entry_t * instance_t::parse_entry(char * line, +xact_t * instance_t::parse_xact(char * line, std::streamsize len, account_t * account) { - TRACE_START(entry_text, 1, "Time spent parsing entry text:"); + TRACE_START(xact_text, 1, "Time spent parsing transaction text:"); - std::auto_ptr<entry_t> curr(new entry_t); + std::auto_ptr<xact_t> curr(new xact_t); curr->pathname = pathname; curr->beg_pos = line_beg_pos; @@ -1110,18 +1110,18 @@ entry_t * instance_t::parse_entry(char * line, curr->payee = "<Unspecified payee>"; } - // Parse the entry note + // Parse the xact note if (next && *next == ';') curr->append_note(next, current_year); - TRACE_STOP(entry_text, 1); + TRACE_STOP(xact_text, 1); - // Parse all of the xacts associated with this entry + // Parse all of the posts associated with this xact - TRACE_START(entry_details, 1, "Time spent parsing entry details:"); + TRACE_START(xact_details, 1, "Time spent parsing transaction details:"); - xact_t * last_xact = NULL; + post_t * last_post = NULL; while (peek_whitespace_line()) { len = read_line(line); @@ -1132,8 +1132,8 @@ entry_t * instance_t::parse_entry(char * line, if (*p == ';') { item_t * item; - if (last_xact) - item = last_xact; + if (last_post) + item = last_post; else item = curr.get(); @@ -1142,17 +1142,17 @@ entry_t * instance_t::parse_entry(char * line, item->end_pos = curr_pos; item->end_line++; } - else if (xact_t * xact = parse_xact(p, len - (p - line), account, + else if (post_t * post = parse_post(p, len - (p - line), account, curr.get())) { - curr->add_xact(xact); - last_xact = xact; + curr->add_post(post); + last_post = post; } } curr->end_pos = curr_pos; curr->end_line = linenum; - TRACE_STOP(entry_details, 1); + TRACE_STOP(xact_details, 1); return curr.release(); } @@ -1186,10 +1186,10 @@ std::size_t journal_t::parse(std::istream& in, TRACE_STOP(parsing_total, 1); // These tracers were started in textual.cc - TRACE_FINISH(entry_text, 1); - TRACE_FINISH(entry_details, 1); - TRACE_FINISH(entry_xacts, 1); - TRACE_FINISH(entries, 1); + TRACE_FINISH(xact_text, 1); + TRACE_FINISH(xact_details, 1); + TRACE_FINISH(xact_posts, 1); + TRACE_FINISH(xacts, 1); TRACE_FINISH(instance_parse, 1); // report per-instance timers TRACE_FINISH(parsing_total, 1); diff --git a/src/timelog.cc b/src/timelog.cc index d52bccb0..6e3a8457 100644 --- a/src/timelog.cc +++ b/src/timelog.cc @@ -34,19 +34,19 @@ namespace ledger { namespace { - void clock_out_from_timelog(std::list<time_entry_t>& time_entries, + void clock_out_from_timelog(std::list<time_xact_t>& time_xacts, const datetime_t& when, account_t * account, const char * desc, journal_t& journal) { - time_entry_t event; + time_xact_t event; - if (time_entries.size() == 1) { - event = time_entries.back(); - time_entries.clear(); + if (time_xacts.size() == 1) { + event = time_xacts.back(); + time_xacts.clear(); } - else if (time_entries.empty()) { + else if (time_xacts.empty()) { throw parse_error("Timelog check-out event without a check-in"); } else if (! account) { @@ -56,13 +56,13 @@ namespace { else { bool found = false; - for (std::list<time_entry_t>::iterator i = time_entries.begin(); - i != time_entries.end(); + for (std::list<time_xact_t>::iterator i = time_xacts.begin(); + i != time_xacts.end(); i++) if (account == (*i).account) { event = *i; found = true; - time_entries.erase(i); + time_xacts.erase(i); break; } @@ -76,7 +76,7 @@ namespace { desc = NULL; } - std::auto_ptr<entry_t> curr(new entry_t); + std::auto_ptr<xact_t> curr(new xact_t); curr->_date = when.date(); curr->code = desc ? desc : ""; curr->payee = event.desc; @@ -91,12 +91,12 @@ namespace { amt.parse(buf); assert(amt.valid()); - xact_t * xact = new xact_t(event.account, amt, XACT_VIRTUAL); - xact->set_state(item_t::CLEARED); - curr->add_xact(xact); + post_t * post = new post_t(event.account, amt, POST_VIRTUAL); + post->set_state(item_t::CLEARED); + curr->add_post(post); - if (! journal.add_entry(curr.get())) - throw parse_error("Failed to record 'out' timelog entry"); + if (! journal.add_xact(curr.get())) + throw parse_error("Failed to record 'out' timelog transaction"); else curr.release(); } @@ -106,17 +106,17 @@ time_log_t::~time_log_t() { TRACE_DTOR(time_log_t); - if (! time_entries.empty()) { + if (! time_xacts.empty()) { std::list<account_t *> accounts; - foreach (time_entry_t& time_entry, time_entries) - accounts.push_back(time_entry.account); + foreach (time_xact_t& time_xact, time_xacts) + accounts.push_back(time_xact.account); foreach (account_t * account, accounts) - clock_out_from_timelog(time_entries, CURRENT_TIME(), account, NULL, + clock_out_from_timelog(time_xacts, CURRENT_TIME(), account, NULL, journal); - assert(time_entries.empty()); + assert(time_xacts.empty()); } } @@ -124,26 +124,26 @@ void time_log_t::clock_in(const datetime_t& checkin, account_t * account, const string& desc) { - time_entry_t event(checkin, account, desc); + time_xact_t event(checkin, account, desc); - if (! time_entries.empty()) { - foreach (time_entry_t& time_entry, time_entries) { - if (event.account == time_entry.account) + if (! time_xacts.empty()) { + foreach (time_xact_t& time_xact, time_xacts) { + if (event.account == time_xact.account) throw parse_error("Cannot double check-in to the same account"); } } - time_entries.push_back(event); + time_xacts.push_back(event); } void time_log_t::clock_out(const datetime_t& checkin, account_t * account, const string& desc) { - if (time_entries.empty()) + if (time_xacts.empty()) throw std::logic_error("Timelog check-out event without a check-in"); - clock_out_from_timelog(time_entries, checkin, account, desc.c_str(), + clock_out_from_timelog(time_xacts, checkin, account, desc.c_str(), journal); } diff --git a/src/timelog.h b/src/timelog.h index 9e69cd65..a704743c 100644 --- a/src/timelog.h +++ b/src/timelog.h @@ -55,29 +55,29 @@ namespace ledger { * * Long. */ -class time_entry_t +class time_xact_t { public: datetime_t checkin; account_t * account; string desc; - time_entry_t() : account(NULL) { - TRACE_CTOR(time_entry_t, ""); + time_xact_t() : account(NULL) { + TRACE_CTOR(time_xact_t, ""); } - time_entry_t(const datetime_t& _checkin, + time_xact_t(const datetime_t& _checkin, account_t * _account = NULL, const string& _desc = "") : checkin(_checkin), account(_account), desc(_desc) { - TRACE_CTOR(time_entry_t, "const datetime_t&, account_t *, const string&"); + TRACE_CTOR(time_xact_t, "const datetime_t&, account_t *, const string&"); } - time_entry_t(const time_entry_t& entry) - : checkin(entry.checkin), account(entry.account), - desc(entry.desc) { - TRACE_CTOR(time_entry_t, "copy"); + time_xact_t(const time_xact_t& xact) + : checkin(xact.checkin), account(xact.account), + desc(xact.desc) { + TRACE_CTOR(time_xact_t, "copy"); } - ~time_entry_t() throw() { - TRACE_DTOR(time_entry_t); + ~time_xact_t() throw() { + TRACE_DTOR(time_xact_t); } }; @@ -88,7 +88,7 @@ public: */ class time_log_t { - std::list<time_entry_t> time_entries; + std::list<time_xact_t> time_xacts; journal_t& journal; public: diff --git a/src/utils.cc b/src/utils.cc index 5f42eae5..70c6d5f8 100644 --- a/src/utils.cc +++ b/src/utils.cc @@ -529,7 +529,7 @@ struct __maybe_enable_debugging { /********************************************************************** * - * Timers (allows log entries to specify cumulative time spent) + * Timers (allows log xacts to specify cumulative time spent) */ #if defined(LOGGING_ON) && defined(TIMERS_ON) diff --git a/src/utils.h b/src/utils.h index 38fd2439..3da0a429 100644 --- a/src/utils.h +++ b/src/utils.h @@ -380,7 +380,7 @@ inline bool category_matches(const char * cat) { /** * @name Timers - * This allows log entries to specify cumulative time spent. + * This allows log xacts to specify cumulative time spent. */ /*@{*/ diff --git a/src/xact.cc b/src/xact.cc index 14464c6f..f62f8c09 100644 --- a/src/xact.cc +++ b/src/xact.cc @@ -32,190 +32,290 @@ #include "xact.h" #include "journal.h" #include "account.h" -#include "interactive.h" #include "format.h" namespace ledger { -bool xact_t::has_tag(const string& tag) const +xact_base_t::xact_base_t(const xact_base_t&) + : item_t(), journal(NULL) { - if (item_t::has_tag(tag)) - return true; - if (entry) - return entry->has_tag(tag); - return false; + TRACE_CTOR(xact_base_t, "copy"); } -bool xact_t::has_tag(const mask_t& tag_mask, - const optional<mask_t>& value_mask) const +xact_base_t::~xact_base_t() { - if (item_t::has_tag(tag_mask, value_mask)) - return true; - if (entry) - return entry->has_tag(tag_mask, value_mask); - return false; -} + TRACE_DTOR(xact_base_t); -optional<string> xact_t::get_tag(const string& tag) const -{ - if (optional<string> value = item_t::get_tag(tag)) - return value; - if (entry) - return entry->get_tag(tag); - return none; -} - -optional<string> xact_t::get_tag(const mask_t& tag_mask, - const optional<mask_t>& value_mask) const -{ - if (optional<string> value = item_t::get_tag(tag_mask, value_mask)) - return value; - if (entry) - return entry->get_tag(tag_mask, value_mask); - return none; + foreach (post_t * post, posts) { + // If the posting is a temporary, it will be destructed when the + // temporary is. + if (! post->has_flags(ITEM_TEMP)) + checked_delete(post); + } } -date_t xact_t::date() const +item_t::state_t xact_base_t::state() const { - if (xdata_ && is_valid(xdata_->date)) - return xdata_->date; - - if (item_t::use_effective_date) { - if (_date_eff) - return *_date_eff; - else if (entry && entry->_date_eff) - return *entry->_date_eff; - } + state_t result = CLEARED; - if (! _date) { - assert(entry); - return entry->date(); + foreach (post_t * post, posts) { + if (post->_state == UNCLEARED) + return UNCLEARED; + else if (post->_state == PENDING) + result = PENDING; } - return *_date; + return result; } -optional<date_t> xact_t::effective_date() const +void xact_base_t::add_post(post_t * post) { - optional<date_t> date = item_t::effective_date(); - if (! date && entry) - return entry->effective_date(); - return date; + posts.push_back(post); } -item_t::state_t xact_t::state() const +bool xact_base_t::remove_post(post_t * post) { - if (entry) { - state_t entry_state = entry->state(); - if ((_state == UNCLEARED && entry_state != UNCLEARED) || - (_state == PENDING && entry_state == CLEARED)) - return entry_state; - } - return _state; + posts.remove(post); + post->xact = NULL; + return true; } -namespace { - value_t get_this(xact_t& xact) { - return value_t(static_cast<scope_t *>(&xact)); +bool xact_base_t::finalize() +{ + // Scan through and compute the total balance for the xact. This is used + // for auto-calculating the value of xacts with no cost, and the per-unit + // price of unpriced commodities. + + value_t balance; + post_t * null_post = NULL; + + foreach (post_t * post, posts) { + if (post->must_balance()) { + amount_t& p(post->cost ? *post->cost : post->amount); + DEBUG("xact.finalize", "post must balance = " << p); + if (! p.is_null()) { + if (p.keep_precision()) { + // If the amount was a cost, it very likely has the "keep_precision" + // flag set, meaning commodity display precision is ignored when + // displaying the amount. We never want this set for the balance, + // so we must clear the flag in a temporary to avoid it propagating + // into the balance. + add_or_set_value(balance, p.rounded()); + } else { + add_or_set_value(balance, p); + } + } else { + if (null_post) + throw_(std::logic_error, + "Only one posting with null amount allowed per transaction"); + else + null_post = post; + } + } } + assert(balance.valid()); - value_t get_is_calculated(xact_t& xact) { - return xact.has_flags(XACT_CALCULATED); - } + DEBUG("xact.finalize", "initial balance = " << balance); - value_t get_virtual(xact_t& xact) { - return xact.has_flags(XACT_VIRTUAL); - } + // If there is only one post, balance against the default account if one has + // been set. - value_t get_real(xact_t& xact) { - return ! xact.has_flags(XACT_VIRTUAL); + if (journal && journal->basket && posts.size() == 1 && ! balance.is_null()) { + // jww (2008-07-24): Need to make the rest of the code aware of what to do + // when it sees a generated post. + null_post = new post_t(journal->basket, ITEM_GENERATED); + null_post->_state = (*posts.begin())->_state; + add_post(null_post); } - value_t get_actual(xact_t& xact) { - return ! xact.has_flags(XACT_AUTO); - } + if (null_post != NULL) { + // If one post has no value at all, its value will become the inverse of + // the rest. If multiple commodities are involved, multiple posts are + // generated to balance them all. + + if (balance.is_balance()) { + bool first = true; + const balance_t& bal(balance.as_balance()); + foreach (const balance_t::amounts_map::value_type& pair, bal.amounts) { + if (first) { + null_post->amount = pair.second.negated(); + first = false; + } else { + add_post(new post_t(null_post->account, pair.second.negated(), + ITEM_GENERATED)); + } + } + } + else if (balance.is_amount()) { + null_post->amount = balance.as_amount().negated(); + null_post->add_flags(POST_CALCULATED); + } + else if (! balance.is_null() && ! balance.is_realzero()) { + throw_(balance_error, "Transaction does not balance"); + } + balance = NULL_VALUE; - value_t get_entry(xact_t& xact) { - return value_t(static_cast<scope_t *>(xact.entry)); } + else if (balance.is_balance() && + balance.as_balance().amounts.size() == 2) { + // When an xact involves two different commodities (regardless of how + // many posts there are) determine the conversion ratio by dividing the + // total value of one commodity by the total value of the other. This + // establishes the per-unit cost for this post for both commodities. + + DEBUG("xact.finalize", "there were exactly two commodities"); + + bool saw_cost = false; + post_t * top_post = NULL; + + foreach (post_t * post, posts) { + if (! post->amount.is_null()) + if (post->amount.is_annotated()) + top_post = post; + else if (! top_post) + top_post = post; + + if (post->cost) { + saw_cost = true; + break; + } + } - value_t get_code(xact_t& xact) { - if (xact.entry->code) - return string_value(*xact.entry->code); - else - return string_value(empty_string); - } + if (! saw_cost && top_post) { + const balance_t& bal(balance.as_balance()); + + DEBUG("xact.finalize", "there were no costs, and a valid top_post"); + + balance_t::amounts_map::const_iterator a = bal.amounts.begin(); + + const amount_t * x = &(*a++).second; + const amount_t * y = &(*a++).second; + + if (x->commodity() != top_post->amount.commodity()) { + const amount_t * t = x; + x = y; + y = t; + } + + DEBUG("xact.finalize", "primary amount = " << *y); + DEBUG("xact.finalize", "secondary amount = " << *x); + + commodity_t& comm(x->commodity()); + amount_t per_unit_cost; + amount_t total_cost; + + foreach (post_t * post, posts) { + if (post != top_post && post->must_balance() && + ! post->amount.is_null() && + post->amount.is_annotated() && + post->amount.annotation().price) { + amount_t temp = *post->amount.annotation().price * post->amount; + if (total_cost.is_null()) { + total_cost = temp; + y = &total_cost; + } else { + total_cost += temp; + } + DEBUG("xact.finalize", "total_cost = " << total_cost); + } + } + per_unit_cost = (*y / *x).abs(); + + DEBUG("xact.finalize", "per_unit_cost = " << per_unit_cost); + + foreach (post_t * post, posts) { + const amount_t& amt(post->amount); + + if (post->must_balance() && amt.commodity() == comm) { + balance -= amt; + post->cost = per_unit_cost * amt; + balance += *post->cost; + + DEBUG("xact.finalize", "set post->cost to = " << *post->cost); + } + } + } - value_t get_payee(xact_t& xact) { - return string_value(xact.entry->payee); + DEBUG("xact.finalize", "resolved balance = " << balance); } - value_t get_amount(xact_t& xact) { - if (xact.has_xdata() && - xact.xdata().has_flags(XACT_EXT_COMPOUND)) { - return xact.xdata().value; - } else { - return xact.amount; - } - } + // Now that the post list has its final form, calculate the balance once + // more in terms of total cost, accounting for any possible gain/loss + // amounts. - value_t get_commodity(xact_t& xact) { - return string_value(xact.amount.commodity().symbol()); - } + foreach (post_t * post, posts) { + if (post->cost) { + if (post->amount.commodity() == post->cost->commodity()) + throw_(balance_error, "Posting's cost must be of a different commodity"); - value_t get_commodity_is_primary(xact_t& xact) { - return xact.amount.commodity().has_flags(COMMODITY_PRIMARY); - } + commodity_t::cost_breakdown_t breakdown = + commodity_t::exchange(post->amount, *post->cost, false, + datetime_t(date(), time_duration(0, 0, 0, 0))); - value_t get_cost(xact_t& xact) { - if (xact.has_xdata() && - xact.xdata().has_flags(XACT_EXT_COMPOUND)) { - return xact.xdata().value; - } else { - if (xact.cost) - return *xact.cost; + if (post->amount.is_annotated() && + breakdown.basis_cost.commodity() == + breakdown.final_cost.commodity()) + add_or_set_value(balance, (breakdown.basis_cost - + breakdown.final_cost).rounded()); else - return xact.amount; + post->amount = breakdown.amount; } } - value_t get_total(xact_t& xact) { - if (xact.xdata_ && ! xact.xdata_->total.is_null()) - return xact.xdata_->total; - else - return xact.amount; - } + DEBUG("xact.finalize", "final balance = " << balance); - value_t get_count(xact_t& xact) { - if (xact.xdata_) - return xact.xdata_->count; - else - return 1L; + if (! balance.is_null() && ! balance.is_zero()) { + add_error_context(item_context(*this, "While balancing transaction")); + add_error_context("Unbalanced remainder is:"); + add_error_context(value_context(balance)); + throw_(balance_error, "Transaction does not balance"); } - value_t get_account(call_scope_t& scope) - { - in_context_t<xact_t> env(scope, "&l"); + // Add the final calculated totals each to their related account - string name = env->reported_account()->fullname(); + if (dynamic_cast<xact_t *>(this)) { + bool all_null = true; + foreach (post_t * post, posts) { + if (! post->amount.is_null()) { + all_null = false; - if (env.has(0) && env.get<long>(0) > 2) - name = format_t::truncate(name, env.get<long>(0) - 2, true); + // jww (2008-08-09): For now, this feature only works for non-specific + // commodities. + add_or_set_value(post->account->xdata().value, post->amount); - if (env->has_flags(XACT_VIRTUAL)) { - if (env->must_balance()) - name = string("[") + name + "]"; - else - name = string("(") + name + ")"; + DEBUG("xact.finalize.totals", + "Total for " << post->account->fullname() << " + " + << post->amount << ": " << post->account->xdata().value); + } } - return string_value(name); + if (all_null) + return false; // ignore this xact completely } - value_t get_account_base(xact_t& xact) { - return string_value(xact.reported_account()->name); + return true; +} + +xact_t::xact_t(const xact_t& e) + : xact_base_t(e), code(e.code), payee(e.payee) +{ + TRACE_CTOR(xact_t, "copy"); +} + +void xact_t::add_post(post_t * post) +{ + post->xact = this; + xact_base_t::add_post(post); +} + +namespace { + value_t get_code(xact_t& xact) { + if (xact.code) + return string_value(*xact.code); + else + return string_value(empty_string); } - value_t get_account_depth(xact_t& xact) { - return long(xact.reported_account()->depth); + value_t get_payee(xact_t& xact) { + return string_value(xact.payee); } template <value_t (*Func)(xact_t&)> @@ -227,65 +327,14 @@ namespace { expr_t::ptr_op_t xact_t::lookup(const string& name) { switch (name[0]) { - case 'a': - if (name[1] == '\0' || name == "amount") - return WRAP_FUNCTOR(get_wrapper<&get_amount>); - else if (name == "account") - return WRAP_FUNCTOR(get_account); - else if (name == "account_base") - return WRAP_FUNCTOR(get_wrapper<&get_account_base>); - else if (name == "actual") - return WRAP_FUNCTOR(get_wrapper<&get_actual>); - break; - case 'c': if (name == "code") return WRAP_FUNCTOR(get_wrapper<&get_code>); - else if (name == "cost") - return WRAP_FUNCTOR(get_wrapper<&get_cost>); - else if (name == "count") - return WRAP_FUNCTOR(get_wrapper<&get_count>); - else if (name == "calculated") - return WRAP_FUNCTOR(get_wrapper<&get_is_calculated>); - else if (name == "commodity") - return WRAP_FUNCTOR(get_wrapper<&get_commodity>); - break; - - case 'd': - if (name == "depth") - return WRAP_FUNCTOR(get_wrapper<&get_account_depth>); - break; - - case 'e': - if (name == "entry") - return WRAP_FUNCTOR(get_wrapper<&get_entry>); - break; - - case 'r': - if (name == "real") - return WRAP_FUNCTOR(get_wrapper<&get_real>); break; case 'p': - if (name == "payee") + if (name[1] == '\0' || name == "payee") return WRAP_FUNCTOR(get_wrapper<&get_payee>); - else if (name == "primary") - return WRAP_FUNCTOR(get_wrapper<&get_commodity_is_primary>); - break; - - case 't': - if (name[1] == '\0' || name == "total") - return WRAP_FUNCTOR(get_wrapper<&get_total>); - break; - - case 'v': - if (name == "virtual") - return WRAP_FUNCTOR(get_wrapper<&get_virtual>); - break; - - case 'x': - if (name == "xact") - return WRAP_FUNCTOR(get_wrapper<&get_this>); break; } @@ -294,46 +343,85 @@ expr_t::ptr_op_t xact_t::lookup(const string& name) bool xact_t::valid() const { - if (! entry) { - DEBUG("ledger.validate", "xact_t: ! entry"); - return false; - } - - xacts_list::const_iterator i = - std::find(entry->xacts.begin(), - entry->xacts.end(), this); - if (i == entry->xacts.end()) { - DEBUG("ledger.validate", "xact_t: ! found"); + if (! _date || ! journal) { + DEBUG("ledger.validate", "xact_t: ! _date || ! journal"); return false; } - if (! account) { - DEBUG("ledger.validate", "xact_t: ! account"); - return false; - } - - if (! amount.valid()) { - DEBUG("ledger.validate", "xact_t: ! amount.valid()"); - return false; - } - - if (cost && ! cost->valid()) { - DEBUG("ledger.validate", "xact_t: cost && ! cost->valid()"); - return false; - } + foreach (post_t * post, posts) + if (post->xact != this || ! post->valid()) { + DEBUG("ledger.validate", "xact_t: post not valid"); + return false; + } return true; } -void xact_t::add_to_value(value_t& value, expr_t& expr) +void auto_xact_t::extend_xact(xact_base_t& xact, bool post_handler) { - if (xdata_ && xdata_->has_flags(XACT_EXT_COMPOUND)) { - add_or_set_value(value, xdata_->value); - } - else if (! xdata_ || ! xdata_->has_flags(XACT_EXT_NO_TOTAL)) { - bind_scope_t bound_scope(*expr.get_context(), *this); - add_or_set_value(value, expr.calc(bound_scope)); + posts_list initial_posts(xact.posts.begin(), xact.posts.end()); + + foreach (post_t * initial_post, initial_posts) { + if (! initial_post->has_flags(POST_AUTO) && predicate(*initial_post)) { + foreach (post_t * post, posts) { + amount_t amt; + assert(post->amount); + if (! post->amount.commodity()) { + if (! post_handler) + continue; + assert(initial_post->amount); + amt = initial_post->amount * post->amount; + } else { + if (post_handler) + continue; + amt = post->amount; + } + + IF_DEBUG("xact.extend") { + DEBUG("xact.extend", + "Initial post on line " << initial_post->beg_line << ": " + << "amount " << initial_post->amount << " (precision " + << initial_post->amount.precision() << ")"); + + if (initial_post->amount.keep_precision()) + DEBUG("xact.extend", " precision is kept"); + + DEBUG("xact.extend", + "Posting on line " << post->beg_line << ": " + << "amount " << post->amount << ", amt " << amt + << " (precision " << post->amount.precision() + << " != " << amt.precision() << ")"); + + if (post->amount.keep_precision()) + DEBUG("xact.extend", " precision is kept"); + if (amt.keep_precision()) + DEBUG("xact.extend", " amt precision is kept"); + } + + account_t * account = post->account; + string fullname = account->fullname(); + assert(! fullname.empty()); + if (fullname == "$account" || fullname == "@account") + account = initial_post->account; + + // Copy over details so that the resulting post is a mirror of + // the automated xact's one. + post_t * new_post = new post_t(account, amt); + new_post->copy_details(*post); + new_post->add_flags(POST_AUTO); + + xact.add_post(new_post); + } + } } } +void extend_xact_base(journal_t * journal, + xact_base_t& base, + bool post_handler) +{ + foreach (auto_xact_t * xact, journal->auto_xacts) + xact->extend_xact(base, post_handler); +} + } // namespace ledger @@ -46,163 +46,210 @@ #ifndef _XACT_H #define _XACT_H -#include "item.h" +#include "post.h" +#include "predicate.h" namespace ledger { -class entry_t; -class account_t; +class journal_t; -class xact_t; -typedef std::list<xact_t *> xacts_list; +/** + * @brief Brief + * + * Long. + */ +class xact_base_t : public item_t +{ +public: + journal_t * journal; + + posts_list posts; + + xact_base_t() : item_t(), journal(NULL) { + TRACE_CTOR(xact_base_t, ""); + } + xact_base_t(const xact_base_t& e); + + virtual ~xact_base_t(); + + virtual state_t state() const; + + virtual void add_post(post_t * post); + virtual bool remove_post(post_t * post); + + virtual bool finalize(); + virtual bool valid() const = 0; +}; /** * @brief Brief * * Long. */ -class xact_t : public item_t +class xact_t : public xact_base_t { public: -#define XACT_VIRTUAL 0x10 // the account was specified with (parens) -#define XACT_MUST_BALANCE 0x20 // the account was specified with [brackets] -#define XACT_AUTO 0x40 // transaction created by automated entry -#define XACT_CALCULATED 0x80 // transaction's amount was auto-calculated - - entry_t * entry; // only set for xacts of regular entries - account_t * account; - - amount_t amount; // can be null until finalization - optional<amount_t> cost; - optional<amount_t> assigned_amount; - - xact_t(account_t * _account = NULL, - flags_t _flags = ITEM_NORMAL) - : item_t(_flags), - entry(NULL), account(_account) - { - TRACE_CTOR(xact_t, "account_t *, flags_t"); - } - xact_t(account_t * _account, - const amount_t& _amount, - flags_t _flags = ITEM_NORMAL, - const optional<string>& _note = none) - : item_t(_flags, _note), - entry(NULL), account(_account), amount(_amount) - { - TRACE_CTOR(xact_t, "account_t *, const amount_t&, flags_t, const optional<string>&"); - } - xact_t(const xact_t& xact) - : item_t(xact), - entry(xact.entry), - account(xact.account), - amount(xact.amount), - cost(xact.cost), - assigned_amount(xact.assigned_amount), - xdata_(xact.xdata_) - { - TRACE_CTOR(xact_t, "copy"); + optional<string> code; + string payee; + + xact_t() { + TRACE_CTOR(xact_t, ""); } - ~xact_t() { + xact_t(const xact_t& e); + + virtual ~xact_t() { TRACE_DTOR(xact_t); } - virtual bool has_tag(const string& tag) const; - virtual bool has_tag(const mask_t& tag_mask, - const optional<mask_t>& value_mask = none) const; + virtual void add_post(post_t * post); - virtual optional<string> get_tag(const string& tag) const; - virtual optional<string> get_tag(const mask_t& tag_mask, - const optional<mask_t>& value_mask = none) const; + virtual expr_t::ptr_op_t lookup(const string& name); - virtual date_t date() const; - virtual optional<date_t> effective_date() const; + virtual bool valid() const; +}; - virtual state_t state() const; +/** + * @brief Brief + * + * Long. + */ +struct xact_finalizer_t { + virtual ~xact_finalizer_t() {} + virtual bool operator()(xact_t& xact, bool post) = 0; +}; - bool must_balance() const { - return ! has_flags(XACT_VIRTUAL) || has_flags(XACT_MUST_BALANCE); +/** + * @brief Brief + * + * Long. + */ +class auto_xact_t : public xact_base_t +{ +public: + item_predicate predicate; + + auto_xact_t() { + TRACE_CTOR(auto_xact_t, ""); + } + auto_xact_t(const auto_xact_t& other) + : xact_base_t(), predicate(other.predicate) { + TRACE_CTOR(auto_xact_t, "copy"); + } + auto_xact_t(const item_predicate& _predicate) + : predicate(_predicate) + { + TRACE_CTOR(auto_xact_t, "const item_predicate<post_t>&"); } - virtual expr_t::ptr_op_t lookup(const string& name); + virtual ~auto_xact_t() { + TRACE_DTOR(auto_xact_t); + } - bool valid() const; + virtual void extend_xact(xact_base_t& xact, bool post); + virtual bool valid() const { + return true; + } +}; - struct xdata_t : public supports_flags<> - { -#define XACT_EXT_RECEIVED 0x01 -#define XACT_EXT_HANDLED 0x02 -#define XACT_EXT_TO_DISPLAY 0x04 -#define XACT_EXT_DISPLAYED 0x08 -#define XACT_EXT_NO_TOTAL 0x10 -#define XACT_EXT_SORT_CALC 0x20 -#define XACT_EXT_COMPOUND 0x40 -#define XACT_EXT_MATCHES 0x80 - - value_t total; - std::size_t count; - value_t value; - date_t date; - account_t * account; - void * ptr; - - std::list<sort_value_t> sort_values; - - xdata_t() - : supports_flags<>(), count(0), account(NULL), ptr(NULL) { - TRACE_CTOR(xact_t::xdata_t, ""); - } - xdata_t(const xdata_t& other) - : supports_flags<>(other.flags()), - total(other.total), - count(other.count), - value(other.value), - date(other.date), - account(other.account), - ptr(NULL), - sort_values(other.sort_values) - { - TRACE_CTOR(xact_t::xdata_t, "copy"); - } - ~xdata_t() throw() { - TRACE_DTOR(xact_t::xdata_t); - } - }; - - // This variable holds optional "extended data" which is usually produced - // only during reporting, and only for the transaction set being reported. - // It's a memory-saving measure to delay allocation until the last possible - // moment. - mutable optional<xdata_t> xdata_; - - bool has_xdata() const { - return xdata_; - } - void clear_xdata() { - xdata_ = none; - } - xdata_t& xdata() { - if (! xdata_) - xdata_ = xdata_t(); - return *xdata_; - } - - void add_to_value(value_t& value, expr_t& expr); - - account_t * reported_account() { - if (xdata_) - if (account_t * acct = xdata_->account) - return acct; - return account; - } - - const account_t * reported_account() const { - return const_cast<xact_t *>(this)->reported_account(); - } - - friend class entry_t; +/** + * @brief Brief + * + * Long. + */ +struct auto_xact_finalizer_t : public xact_finalizer_t +{ + journal_t * journal; + + auto_xact_finalizer_t() : journal(NULL) { + TRACE_CTOR(auto_xact_finalizer_t, ""); + } + auto_xact_finalizer_t(const auto_xact_finalizer_t& other) + : xact_finalizer_t(), journal(other.journal) { + TRACE_CTOR(auto_xact_finalizer_t, "copy"); + } + auto_xact_finalizer_t(journal_t * _journal) : journal(_journal) { + TRACE_CTOR(auto_xact_finalizer_t, "journal_t *"); + } + ~auto_xact_finalizer_t() throw() { + TRACE_DTOR(auto_xact_finalizer_t); + } + + virtual bool operator()(xact_t& xact, bool post); }; +/** + * @brief Brief + * + * Long. + */ +class period_xact_t : public xact_base_t +{ + public: + interval_t period; + string period_string; + + period_xact_t() { + TRACE_CTOR(period_xact_t, ""); + } + period_xact_t(const period_xact_t& e) + : xact_base_t(e), period(e.period), period_string(e.period_string) { + TRACE_CTOR(period_xact_t, "copy"); + } + period_xact_t(const string& _period) + : period(_period), period_string(_period) { + TRACE_CTOR(period_xact_t, "const string&"); + } + + virtual ~period_xact_t() throw() { + TRACE_DTOR(period_xact_t); + } + + virtual bool valid() const { + return period; + } +}; + +/** + * @brief Brief + * + * Long. + */ +class func_finalizer_t : public xact_finalizer_t +{ + func_finalizer_t(); + +public: + typedef function<bool (xact_t& xact, bool post)> func_t; + + func_t func; + + func_finalizer_t(func_t _func) : func(_func) { + TRACE_CTOR(func_finalizer_t, "func_t"); + } + func_finalizer_t(const func_finalizer_t& other) : + xact_finalizer_t(), func(other.func) { + TRACE_CTOR(func_finalizer_t, "copy"); + } + ~func_finalizer_t() throw() { + TRACE_DTOR(func_finalizer_t); + } + + virtual bool operator()(xact_t& xact, bool post) { + return func(xact, post); + } +}; + +void extend_xact_base(journal_t * journal, xact_base_t& xact, bool post); + +inline bool auto_xact_finalizer_t::operator()(xact_t& xact, bool post) { + extend_xact_base(journal, xact, post); + return true; +} + +typedef std::list<xact_t *> xacts_list; +typedef std::list<auto_xact_t *> auto_xacts_list; +typedef std::list<period_xact_t *> period_xacts_list; + } // namespace ledger #endif // _XACT_H diff --git a/test/baseline/opt-add-budget.test b/test/baseline/opt-add-budget.test index 338706e4..20dfd320 100644 --- a/test/baseline/opt-add-budget.test +++ b/test/baseline/opt-add-budget.test @@ -246,122 +246,122 @@ reg --add-budget books cards >>>1 08-Jan-01 January Expenses:Books $10.00 $10.00 Liabilities:Cards $10.00 $20.00 -08-Jan-01 Budget entry Expenses:Books $-10.00 $10.00 +08-Jan-01 Budget transaction Expenses:Books $-10.00 $10.00 08-Jan-31 End of January Expenses:Books $10.00 $20.00 Liabilities:Cards $10.00 $30.00 08-Feb-01 February Expenses:Books $20.00 $50.00 Liabilities:Cards $20.00 $70.00 -08-Feb-01 Budget entry Expenses:Books $-10.00 $60.00 +08-Feb-01 Budget transaction Expenses:Books $-10.00 $60.00 08-Feb-28 End of February Expenses:Books $20.00 $80.00 Liabilities:Cards $20.00 $100.00 08-Mar-01 March Expenses:Books $30.00 $130.00 Liabilities:Cards $30.00 $160.00 -08-Mar-01 Budget entry Expenses:Books $-10.00 $150.00 +08-Mar-01 Budget transaction Expenses:Books $-10.00 $150.00 08-Mar-31 End of March Expenses:Books $30.00 $180.00 Liabilities:Cards $30.00 $210.00 08-Apr-01 April Expenses:Books $40.00 $250.00 Liabilities:Cards $40.00 $290.00 -08-Apr-01 Budget entry Expenses:Books $-10.00 $280.00 +08-Apr-01 Budget transaction Expenses:Books $-10.00 $280.00 08-Apr-30 End of April Expenses:Books $40.00 $320.00 Liabilities:Cards $40.00 $360.00 08-May-01 May Expenses:Books $50.00 $410.00 Liabilities:Cards $50.00 $460.00 -08-May-01 Budget entry Expenses:Books $-10.00 $450.00 +08-May-01 Budget transaction Expenses:Books $-10.00 $450.00 08-May-31 End of May Expenses:Books $50.00 $500.00 Liabilities:Cards $50.00 $550.00 08-Jun-01 June Expenses:Books $60.00 $610.00 Liabilities:Cards $60.00 $670.00 -08-Jun-01 Budget entry Expenses:Books $-10.00 $660.00 +08-Jun-01 Budget transaction Expenses:Books $-10.00 $660.00 08-Jun-30 End of June Expenses:Books $60.00 $720.00 Liabilities:Cards $60.00 $780.00 08-Jul-01 July Expenses:Books $70.00 $850.00 Liabilities:Cards $70.00 $920.00 -08-Jul-01 Budget entry Expenses:Books $-10.00 $910.00 +08-Jul-01 Budget transaction Expenses:Books $-10.00 $910.00 08-Jul-31 End of July Expenses:Books $70.00 $980.00 Liabilities:Cards $70.00 $1050.00 08-Aug-01 August Expenses:Books $80.00 $1130.00 Liabilities:Cards $80.00 $1210.00 -08-Aug-01 Budget entry Expenses:Books $-10.00 $1200.00 +08-Aug-01 Budget transaction Expenses:Books $-10.00 $1200.00 08-Aug-31 End of August Expenses:Books $80.00 $1280.00 Liabilities:Cards $80.00 $1360.00 08-Sep-01 September Expenses:Books $90.00 $1450.00 Liabilities:Cards $90.00 $1540.00 -08-Sep-01 Budget entry Expenses:Books $-10.00 $1530.00 +08-Sep-01 Budget transaction Expenses:Books $-10.00 $1530.00 08-Sep-30 End of September Expenses:Books $90.00 $1620.00 Liabilities:Cards $90.00 $1710.00 08-Oct-01 October Expenses:Books $100.00 $1810.00 Liabilities:Cards $100.00 $1910.00 -08-Oct-01 Budget entry Expenses:Books $-10.00 $1900.00 +08-Oct-01 Budget transaction Expenses:Books $-10.00 $1900.00 08-Oct-31 End of October Expenses:Books $100.00 $2000.00 Liabilities:Cards $100.00 $2100.00 08-Nov-01 November Expenses:Books $110.00 $2210.00 Liabilities:Cards $110.00 $2320.00 -08-Nov-01 Budget entry Expenses:Books $-10.00 $2310.00 +08-Nov-01 Budget transaction Expenses:Books $-10.00 $2310.00 08-Nov-30 End of November Expenses:Books $110.00 $2420.00 Liabilities:Cards $110.00 $2530.00 08-Dec-01 December Expenses:Books $120.00 $2650.00 Liabilities:Cards $120.00 $2770.00 -08-Dec-01 Budget entry Expenses:Books $-10.00 $2760.00 +08-Dec-01 Budget transaction Expenses:Books $-10.00 $2760.00 08-Dec-31 End of December Expenses:Books $120.00 $2880.00 Liabilities:Cards $120.00 $3000.00 09-Jan-01 January Expenses:Books $10.00 $3010.00 Liabilities:Cards $10.00 $3020.00 -09-Jan-01 Budget entry Expenses:Books $-10.00 $3010.00 +09-Jan-01 Budget transaction Expenses:Books $-10.00 $3010.00 09-Jan-31 End of January Expenses:Books $10.00 $3020.00 Liabilities:Cards $10.00 $3030.00 09-Feb-01 February Expenses:Books $20.00 $3050.00 Liabilities:Cards $20.00 $3070.00 -09-Feb-01 Budget entry Expenses:Books $-10.00 $3060.00 +09-Feb-01 Budget transaction Expenses:Books $-10.00 $3060.00 09-Feb-28 End of February Expenses:Books $20.00 $3080.00 Liabilities:Cards $20.00 $3100.00 09-Mar-01 March Expenses:Books $30.00 $3130.00 Liabilities:Cards $30.00 $3160.00 -09-Mar-01 Budget entry Expenses:Books $-10.00 $3150.00 +09-Mar-01 Budget transaction Expenses:Books $-10.00 $3150.00 09-Mar-31 End of March Expenses:Books $30.00 $3180.00 Liabilities:Cards $30.00 $3210.00 09-Apr-01 April Expenses:Books $40.00 $3250.00 Liabilities:Cards $40.00 $3290.00 -09-Apr-01 Budget entry Expenses:Books $-10.00 $3280.00 +09-Apr-01 Budget transaction Expenses:Books $-10.00 $3280.00 09-Apr-30 End of April Expenses:Books $40.00 $3320.00 Liabilities:Cards $40.00 $3360.00 09-May-01 May Expenses:Books $50.00 $3410.00 Liabilities:Cards $50.00 $3460.00 -09-May-01 Budget entry Expenses:Books $-10.00 $3450.00 +09-May-01 Budget transaction Expenses:Books $-10.00 $3450.00 09-May-31 End of May Expenses:Books $50.00 $3500.00 Liabilities:Cards $50.00 $3550.00 09-Jun-01 June Expenses:Books $60.00 $3610.00 Liabilities:Cards $60.00 $3670.00 -09-Jun-01 Budget entry Expenses:Books $-10.00 $3660.00 +09-Jun-01 Budget transaction Expenses:Books $-10.00 $3660.00 09-Jun-30 End of June Expenses:Books $60.00 $3720.00 Liabilities:Cards $60.00 $3780.00 09-Jul-01 July Expenses:Books $70.00 $3850.00 Liabilities:Cards $70.00 $3920.00 -09-Jul-01 Budget entry Expenses:Books $-10.00 $3910.00 +09-Jul-01 Budget transaction Expenses:Books $-10.00 $3910.00 09-Jul-31 End of July Expenses:Books $70.00 $3980.00 Liabilities:Cards $70.00 $4050.00 09-Aug-01 August Expenses:Books $80.00 $4130.00 Liabilities:Cards $80.00 $4210.00 -09-Aug-01 Budget entry Expenses:Books $-10.00 $4200.00 +09-Aug-01 Budget transaction Expenses:Books $-10.00 $4200.00 09-Aug-31 End of August Expenses:Books $80.00 $4280.00 Liabilities:Cards $80.00 $4360.00 09-Sep-01 September Expenses:Books $90.00 $4450.00 Liabilities:Cards $90.00 $4540.00 -09-Sep-01 Budget entry Expenses:Books $-10.00 $4530.00 +09-Sep-01 Budget transaction Expenses:Books $-10.00 $4530.00 09-Sep-30 End of September Expenses:Books $90.00 $4620.00 Liabilities:Cards $90.00 $4710.00 09-Oct-01 October Expenses:Books $100.00 $4810.00 Liabilities:Cards $100.00 $4910.00 -09-Oct-01 Budget entry Expenses:Books $-10.00 $4900.00 +09-Oct-01 Budget transaction Expenses:Books $-10.00 $4900.00 09-Oct-31 End of October Expenses:Books $100.00 $5000.00 Liabilities:Cards $100.00 $5100.00 09-Nov-01 November Expenses:Books $110.00 $5210.00 Liabilities:Cards $110.00 $5320.00 -09-Nov-01 Budget entry Expenses:Books $-10.00 $5310.00 +09-Nov-01 Budget transaction Expenses:Books $-10.00 $5310.00 09-Nov-30 End of November Expenses:Books $110.00 $5420.00 Liabilities:Cards $110.00 $5530.00 09-Dec-01 December Expenses:Books $120.00 $5650.00 Liabilities:Cards $120.00 $5770.00 -09-Dec-01 Budget entry Expenses:Books $-10.00 $5760.00 +09-Dec-01 Budget transaction Expenses:Books $-10.00 $5760.00 09-Dec-31 End of December Expenses:Books $120.00 $5880.00 Liabilities:Cards $120.00 $6000.00 >>>2 diff --git a/test/baseline/opt-budget.test b/test/baseline/opt-budget.test index e18d2fca..097d19d8 100644 --- a/test/baseline/opt-budget.test +++ b/test/baseline/opt-budget.test @@ -246,76 +246,76 @@ reg --budget books Assets:Cash >>>1 08-Jan-01 January Expenses:Books $10.00 $10.00 -08-Jan-01 Budget entry Expenses:Books $-10.00 0 +08-Jan-01 Budget transaction Expenses:Books $-10.00 0 08-Jan-31 End of January Expenses:Books $10.00 $10.00 08-Feb-01 February Expenses:Books $20.00 $30.00 -08-Feb-01 Budget entry Expenses:Books $-10.00 $20.00 +08-Feb-01 Budget transaction Expenses:Books $-10.00 $20.00 08-Feb-28 End of February Expenses:Books $20.00 $40.00 08-Mar-01 March Expenses:Books $30.00 $70.00 -08-Mar-01 Budget entry Expenses:Books $-10.00 $60.00 +08-Mar-01 Budget transaction Expenses:Books $-10.00 $60.00 08-Mar-31 End of March Expenses:Books $30.00 $90.00 08-Apr-01 April Expenses:Books $40.00 $130.00 -08-Apr-01 Budget entry Expenses:Books $-10.00 $120.00 +08-Apr-01 Budget transaction Expenses:Books $-10.00 $120.00 08-Apr-30 End of April Expenses:Books $40.00 $160.00 08-May-01 May Expenses:Books $50.00 $210.00 -08-May-01 Budget entry Expenses:Books $-10.00 $200.00 +08-May-01 Budget transaction Expenses:Books $-10.00 $200.00 08-May-31 End of May Expenses:Books $50.00 $250.00 08-Jun-01 June Expenses:Books $60.00 $310.00 -08-Jun-01 Budget entry Expenses:Books $-10.00 $300.00 +08-Jun-01 Budget transaction Expenses:Books $-10.00 $300.00 08-Jun-30 End of June Expenses:Books $60.00 $360.00 08-Jul-01 July Expenses:Books $70.00 $430.00 -08-Jul-01 Budget entry Expenses:Books $-10.00 $420.00 +08-Jul-01 Budget transaction Expenses:Books $-10.00 $420.00 08-Jul-31 End of July Expenses:Books $70.00 $490.00 08-Aug-01 August Expenses:Books $80.00 $570.00 -08-Aug-01 Budget entry Expenses:Books $-10.00 $560.00 +08-Aug-01 Budget transaction Expenses:Books $-10.00 $560.00 08-Aug-31 End of August Expenses:Books $80.00 $640.00 08-Sep-01 September Expenses:Books $90.00 $730.00 -08-Sep-01 Budget entry Expenses:Books $-10.00 $720.00 +08-Sep-01 Budget transaction Expenses:Books $-10.00 $720.00 08-Sep-30 End of September Expenses:Books $90.00 $810.00 08-Oct-01 October Expenses:Books $100.00 $910.00 -08-Oct-01 Budget entry Expenses:Books $-10.00 $900.00 +08-Oct-01 Budget transaction Expenses:Books $-10.00 $900.00 08-Oct-31 End of October Expenses:Books $100.00 $1000.00 08-Nov-01 November Expenses:Books $110.00 $1110.00 -08-Nov-01 Budget entry Expenses:Books $-10.00 $1100.00 +08-Nov-01 Budget transaction Expenses:Books $-10.00 $1100.00 08-Nov-30 End of November Expenses:Books $110.00 $1210.00 08-Dec-01 December Expenses:Books $120.00 $1330.00 -08-Dec-01 Budget entry Expenses:Books $-10.00 $1320.00 +08-Dec-01 Budget transaction Expenses:Books $-10.00 $1320.00 08-Dec-31 End of December Expenses:Books $120.00 $1440.00 09-Jan-01 January Expenses:Books $10.00 $1450.00 -09-Jan-01 Budget entry Expenses:Books $-10.00 $1440.00 +09-Jan-01 Budget transaction Expenses:Books $-10.00 $1440.00 09-Jan-31 End of January Expenses:Books $10.00 $1450.00 09-Feb-01 February Expenses:Books $20.00 $1470.00 -09-Feb-01 Budget entry Expenses:Books $-10.00 $1460.00 +09-Feb-01 Budget transaction Expenses:Books $-10.00 $1460.00 09-Feb-28 End of February Expenses:Books $20.00 $1480.00 09-Mar-01 March Expenses:Books $30.00 $1510.00 -09-Mar-01 Budget entry Expenses:Books $-10.00 $1500.00 +09-Mar-01 Budget transaction Expenses:Books $-10.00 $1500.00 09-Mar-31 End of March Expenses:Books $30.00 $1530.00 09-Apr-01 April Expenses:Books $40.00 $1570.00 -09-Apr-01 Budget entry Expenses:Books $-10.00 $1560.00 +09-Apr-01 Budget transaction Expenses:Books $-10.00 $1560.00 09-Apr-30 End of April Expenses:Books $40.00 $1600.00 09-May-01 May Expenses:Books $50.00 $1650.00 -09-May-01 Budget entry Expenses:Books $-10.00 $1640.00 +09-May-01 Budget transaction Expenses:Books $-10.00 $1640.00 09-May-31 End of May Expenses:Books $50.00 $1690.00 09-Jun-01 June Expenses:Books $60.00 $1750.00 -09-Jun-01 Budget entry Expenses:Books $-10.00 $1740.00 +09-Jun-01 Budget transaction Expenses:Books $-10.00 $1740.00 09-Jun-30 End of June Expenses:Books $60.00 $1800.00 09-Jul-01 July Expenses:Books $70.00 $1870.00 -09-Jul-01 Budget entry Expenses:Books $-10.00 $1860.00 +09-Jul-01 Budget transaction Expenses:Books $-10.00 $1860.00 09-Jul-31 End of July Expenses:Books $70.00 $1930.00 09-Aug-01 August Expenses:Books $80.00 $2010.00 -09-Aug-01 Budget entry Expenses:Books $-10.00 $2000.00 +09-Aug-01 Budget transaction Expenses:Books $-10.00 $2000.00 09-Aug-31 End of August Expenses:Books $80.00 $2080.00 09-Sep-01 September Expenses:Books $90.00 $2170.00 -09-Sep-01 Budget entry Expenses:Books $-10.00 $2160.00 +09-Sep-01 Budget transaction Expenses:Books $-10.00 $2160.00 09-Sep-30 End of September Expenses:Books $90.00 $2250.00 09-Oct-01 October Expenses:Books $100.00 $2350.00 -09-Oct-01 Budget entry Expenses:Books $-10.00 $2340.00 +09-Oct-01 Budget transaction Expenses:Books $-10.00 $2340.00 09-Oct-31 End of October Expenses:Books $100.00 $2440.00 09-Nov-01 November Expenses:Books $110.00 $2550.00 -09-Nov-01 Budget entry Expenses:Books $-10.00 $2540.00 +09-Nov-01 Budget transaction Expenses:Books $-10.00 $2540.00 09-Nov-30 End of November Expenses:Books $110.00 $2650.00 09-Dec-01 December Expenses:Books $120.00 $2770.00 -09-Dec-01 Budget entry Expenses:Books $-10.00 $2760.00 +09-Dec-01 Budget transaction Expenses:Books $-10.00 $2760.00 09-Dec-31 End of December Expenses:Books $120.00 $2880.00 >>>2 === 0 diff --git a/test/baseline/opt-forecast-while.test b/test/baseline/opt-forecast-while.test index a4f25ac2..a2bed037 100644 --- a/test/baseline/opt-forecast-while.test +++ b/test/baseline/opt-forecast-while.test @@ -244,42 +244,42 @@ reg --forecast-while='total < $3500' books 09-Nov-30 End of November Expenses:Books $110.00 $2880.00 09-Dec-01 December Expenses:Books $120.00 $3000.00 09-Dec-31 End of December Expenses:Books $120.00 $3120.00 -09-Mar-01 Forecast entry Expenses:Books $10.00 $3130.00 -09-Apr-01 Forecast entry Expenses:Books $10.00 $3140.00 -09-May-01 Forecast entry Expenses:Books $10.00 $3150.00 -09-Jun-01 Forecast entry Expenses:Books $10.00 $3160.00 -09-Jul-01 Forecast entry Expenses:Books $10.00 $3170.00 -09-Aug-01 Forecast entry Expenses:Books $10.00 $3180.00 -09-Sep-01 Forecast entry Expenses:Books $10.00 $3190.00 -09-Oct-01 Forecast entry Expenses:Books $10.00 $3200.00 -09-Nov-01 Forecast entry Expenses:Books $10.00 $3210.00 -09-Dec-01 Forecast entry Expenses:Books $10.00 $3220.00 -10-Jan-01 Forecast entry Expenses:Books $10.00 $3230.00 -10-Feb-01 Forecast entry Expenses:Books $10.00 $3240.00 -10-Mar-01 Forecast entry Expenses:Books $10.00 $3250.00 -10-Apr-01 Forecast entry Expenses:Books $10.00 $3260.00 -10-May-01 Forecast entry Expenses:Books $10.00 $3270.00 -10-Jun-01 Forecast entry Expenses:Books $10.00 $3280.00 -10-Jul-01 Forecast entry Expenses:Books $10.00 $3290.00 -10-Aug-01 Forecast entry Expenses:Books $10.00 $3300.00 -10-Sep-01 Forecast entry Expenses:Books $10.00 $3310.00 -10-Oct-01 Forecast entry Expenses:Books $10.00 $3320.00 -10-Nov-01 Forecast entry Expenses:Books $10.00 $3330.00 -10-Dec-01 Forecast entry Expenses:Books $10.00 $3340.00 -11-Jan-01 Forecast entry Expenses:Books $10.00 $3350.00 -11-Feb-01 Forecast entry Expenses:Books $10.00 $3360.00 -11-Mar-01 Forecast entry Expenses:Books $10.00 $3370.00 -11-Apr-01 Forecast entry Expenses:Books $10.00 $3380.00 -11-May-01 Forecast entry Expenses:Books $10.00 $3390.00 -11-Jun-01 Forecast entry Expenses:Books $10.00 $3400.00 -11-Jul-01 Forecast entry Expenses:Books $10.00 $3410.00 -11-Aug-01 Forecast entry Expenses:Books $10.00 $3420.00 -11-Sep-01 Forecast entry Expenses:Books $10.00 $3430.00 -11-Oct-01 Forecast entry Expenses:Books $10.00 $3440.00 -11-Nov-01 Forecast entry Expenses:Books $10.00 $3450.00 -11-Dec-01 Forecast entry Expenses:Books $10.00 $3460.00 -12-Jan-01 Forecast entry Expenses:Books $10.00 $3470.00 -12-Feb-01 Forecast entry Expenses:Books $10.00 $3480.00 -12-Mar-01 Forecast entry Expenses:Books $10.00 $3490.00 +09-Mar-01 Forecast transaction Expenses:Books $10.00 $3130.00 +09-Apr-01 Forecast transaction Expenses:Books $10.00 $3140.00 +09-May-01 Forecast transaction Expenses:Books $10.00 $3150.00 +09-Jun-01 Forecast transaction Expenses:Books $10.00 $3160.00 +09-Jul-01 Forecast transaction Expenses:Books $10.00 $3170.00 +09-Aug-01 Forecast transaction Expenses:Books $10.00 $3180.00 +09-Sep-01 Forecast transaction Expenses:Books $10.00 $3190.00 +09-Oct-01 Forecast transaction Expenses:Books $10.00 $3200.00 +09-Nov-01 Forecast transaction Expenses:Books $10.00 $3210.00 +09-Dec-01 Forecast transaction Expenses:Books $10.00 $3220.00 +10-Jan-01 Forecast transaction Expenses:Books $10.00 $3230.00 +10-Feb-01 Forecast transaction Expenses:Books $10.00 $3240.00 +10-Mar-01 Forecast transaction Expenses:Books $10.00 $3250.00 +10-Apr-01 Forecast transaction Expenses:Books $10.00 $3260.00 +10-May-01 Forecast transaction Expenses:Books $10.00 $3270.00 +10-Jun-01 Forecast transaction Expenses:Books $10.00 $3280.00 +10-Jul-01 Forecast transaction Expenses:Books $10.00 $3290.00 +10-Aug-01 Forecast transaction Expenses:Books $10.00 $3300.00 +10-Sep-01 Forecast transaction Expenses:Books $10.00 $3310.00 +10-Oct-01 Forecast transaction Expenses:Books $10.00 $3320.00 +10-Nov-01 Forecast transaction Expenses:Books $10.00 $3330.00 +10-Dec-01 Forecast transaction Expenses:Books $10.00 $3340.00 +11-Jan-01 Forecast transaction Expenses:Books $10.00 $3350.00 +11-Feb-01 Forecast transaction Expenses:Books $10.00 $3360.00 +11-Mar-01 Forecast transaction Expenses:Books $10.00 $3370.00 +11-Apr-01 Forecast transaction Expenses:Books $10.00 $3380.00 +11-May-01 Forecast transaction Expenses:Books $10.00 $3390.00 +11-Jun-01 Forecast transaction Expenses:Books $10.00 $3400.00 +11-Jul-01 Forecast transaction Expenses:Books $10.00 $3410.00 +11-Aug-01 Forecast transaction Expenses:Books $10.00 $3420.00 +11-Sep-01 Forecast transaction Expenses:Books $10.00 $3430.00 +11-Oct-01 Forecast transaction Expenses:Books $10.00 $3440.00 +11-Nov-01 Forecast transaction Expenses:Books $10.00 $3450.00 +11-Dec-01 Forecast transaction Expenses:Books $10.00 $3460.00 +12-Jan-01 Forecast transaction Expenses:Books $10.00 $3470.00 +12-Feb-01 Forecast transaction Expenses:Books $10.00 $3480.00 +12-Mar-01 Forecast transaction Expenses:Books $10.00 $3490.00 >>>2 === 0 diff --git a/test/regress/2E3496BD.test b/test/regress/2E3496BD.test index 9ed0237b..f4226bb5 100644 --- a/test/regress/2E3496BD.test +++ b/test/regress/2E3496BD.test @@ -8,11 +8,11 @@ D 1,000.00 USD >>>1 >>>2 While parsing file "$FILE", line 5: -While balancing entry from "$FILE", lines 3-5: +While balancing transaction from "$FILE", lines 3-5: > 2007-12-31 * Start of year / Opening balances. > Account1 1000 EUR @ 1.6 USD > Account2 -1000 EUR @ 1.5 USD Unbalanced remainder is: 100.00 USD -Error: Entry does not balance +Error: Transaction does not balance === 1 diff --git a/tools/runtests.py b/tools/runtests.py index b242fa6d..9afbd25d 100755 --- a/tools/runtests.py +++ b/tools/runtests.py @@ -89,9 +89,6 @@ options = [ #"--version", "--weekly", "--wide", - #"--wide-register-format", - #"--write-hdr-format", - #"--write-xact-format", "--yearly", ] diff --git a/tools/sample.sh b/tools/sample.sh index b5b0c3c6..284b3108 100755 --- a/tools/sample.sh +++ b/tools/sample.sh @@ -3,5 +3,5 @@ ~/Products/ledger/ledger \ --import ~/src/ledger/tools/sample.py \ -f ~/src/ledger/doc/sample.dat \ - --amount 'get_amount(entry)' \ + --amount 'get_amount(xact)' \ register |