Coder Social home page Coder Social logo

goledger's Introduction

Command line accounting

talk on matrix Build Status GoDoc

Inspired by ledger-cli, goledger is a re-write of command line ledger in golang, with the stated goals.

  • Keeping it command line friendly, whether or not GUI / web interface are available.
  • Defaults to Locale en_IN, until the tool becomes smart enough to handle locale specific details automatically.
  • Targeted for personal, small and medium enterprises.
  • Keep to the spirit of ledger-cli as much as possible.

Basic Concepts

  • Credit the giver debit the receiver.
  • Commodity, based accounting, where currency is also a commodity.
  • Account, holding one or more commodities.
  • Posting, commodities can be posted to an account. Posting can be debit posting or credit posting, based on whether the account is the source account (credit the giver) or target account (debit the receiver)
  • Transaction, involving 2 or more postings, where the sum of credit postings should balance out the sum of debit postings.

Once comfortable with above concepts, we can start book-keeping with ledger.

Transactions and Directives

Book-keeping starts with the journal file, typically ending with .ldg. A ledger file can contain directives (sometimes called as declarations) or transaction entries.

There can be any number of directives and any number of transaction entries.

Transactions have the following format:

2011/03/15   Whole Food Market
    Expenses:Groceries   75.00
    Assets:Checking      -75

line1: Date and Payee
line2: Accountname, Amount
line3: Accountname, Amount

  • Each transaction is associated with a date, and it is always advised to enter transaction with older date before and newer date after.
  • Payee gives a name to the transaction, other than that no special meaning is attached to it.
  • Posting with positive amount are treated as debit transaction, and the posting's account is called target account.
  • Posting with negative amount are treated as credit transaction, and the posting's account is called source account.

To begin with, ledger tool expects one or more journal files to process. As mentioned earlier, a journal file typically contains directives and transactions. The format of journal file is plain text.

$ goledger -f journal.ldg

To process more than one journal files, supply them as -f journal1.ldg,journal2.lsg. Even if the journals are not in time order or transactions within a journal file is not in time order, goledger will sort them in time order before applying them.

Including journal files

If several journal files need to be processed, it is easier to create a new file and include other journal files within. For example consolidate.ldg can have:

include journal1.ldg
include journal2.ldg

Account-name

There are some conventions used in account naming. Account names can be composed of any character except:

  • Double spaces and tabs
  • Mathematical and logical operators: -+*/^&|=
  • Bracketing characters: <>[](){}
  • The at symbol: @
  • semicolon: ;

Commodity-name

Commodity can appear before or after the amount, and may or may not be separated from it by a space. Most characters are allowed in a commodity name, except for the following:

  • Any kind of white-space
  • Numerical digits
  • Punctuation: .,;:?!
  • Mathematical and logical operators: -+*/^&|=
  • Bracketing characters: <>[](){}
  • The at symbol: @

Standards, conventions and views

While the basic concept of accounting is not more that what is stated above, there are endless variations stipulated by accounting standards and conventions. Sometimes we may need different view of accounts for the same set of transactions. For example, let us take accrual accounting:

Accrual accounting

Cash (or commodities) are physical and to get a realistic picture of our accounts we book transactions that has already taken place physically. Now, we will look at three different scenarios demanding three different flavours of realism.

Scenario1: Income Tax filing

At least in India income tax department expects us to accrue all interest that are receivable on Bank deposits, as income, and pay tax. Although we might not have received the interest until the deposit matures. How to book this in goledger:

2016/Jun/21  FD savings ; Deposit for 1 year
    Asset:FD                        10000
    Asset:CurrentAccount

2017/Mar/31  Accrued interest on Bank FD
    Income:Interest:Receivable       800
    Income:FD-Interest

2017/Jun/22  FD Matures
    Asset:CurrentAccount            11000
    Income:Interest:Receivable       -800
    Income:FD-Interest               -200
    Asset:FD                       -10000

Scenario2: Distress sale of company

When a company is under distress and a valuation is to be done to attract potential buyers, it is normally expected that buyer would ask us to discount Receivables but include Payables.

Scenario3: Brokerage houses

If book keeping is done for a brokerage house, which buy commodity and sell them later, most often the actual payment will be deferred until actual sale has happened. For them, accrual accounting might have to be totally skipped while generating a report on operating-cost.

As evident in above case, such variations are endless and hence, goledger doesn't try to be smart about them. Just Credit the giver and debit the receiver. If a particular feature or a nicety is required in booking a transaction or in generating a report, please file an issue and let us see whether or how to take it forward.

Ledger commands

Balance

The primary objective of consolidating all transactions is to make sure that all debits and all credits balance out each other. So there is a balance command.

$ goledger -f journal.ldg balance

It is also possible to filter out accounts listed in a balance report, for instance the below command will list only accounts containing Asset::

$ goledger -f journal.ldg balance Asset:

Passbook

A passbook implies transaction between one account, let us call this as third party account, and all other accounts. The third party many not be interested in all the other accounts, from his/her point of view the contra posting in a transaction to all the other accounts are irrelevant. In such cases we can generate a passbook and give it to them:

$ goledger -f journal.ldg passbook John

John is the third party for whom the passbook is generated.

equity

One way to organize journal file add all transactions in the same file year after year. But this can quickly get large and can become messy, it can also take goledger more time to process all the entries. To avoid this, we can split journals into separate files one for each financial-year. For this, equity can be very handy, which can report the year end balance as a transaction for next year's Opening balance.

goledger -f journal-2015.ldg equity > journal-2016.ldg

Now this come with the cost of information loss, that is, while processing the journal file for 2016, journal-2016.ldg goledger can't generate interesting reports from earlier transactions. To work around this:

goledger -f journal-2015.ldg,journal-2016.ldg -stitch register

use the -stitch that can skip all transactions with Payee as Opening balance.

Getting Started

There are plans to package ledger for different platforms, like windows, ubuntu, mac, raspberry-pi, debian etc.. Until then, goledger can be obtained via golang-tools. For mac or linux users, install Golang, and:

$ go get github.com/tn47/goledger
$ cd tn47/goledger
$ make test # sanity test.
$ make install

It is surprisingly easy!!

Gotchas

  • Account name should start with at least 2 character
  • Hard spaces (2 or more consecutive spaces or a single tab-space) have special meaning in ledger format. So avoid them in account names.

Ledger-likes

How to contribute

  • Pick an issue, or create an new issue. Provide adequate documentation for the issue.
  • Assign the issue or get it assigned.
  • Work on the code, once finished, raise a pull request.
  • Goledger is written in golang, hence expected to follow the global guidelines for writing go programs.
  • If the changeset is more than few lines, please generate a report card.

Happy Accounting !!

goledger's People

Contributors

gitter-badger avatar prataprc avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

goledger's Issues

Journal statistics.

This issue tracks the ledger statistics that can be dumped via command line.

$ ledger stats

Output should include:

  • Order in which journal files are processed, marked as "include" if they are included by other file.
  • Date of first and last transaction.
  • Number of transactions and postings.
  • Number of balanced, unbalanced, cleared, uncleared and pending transactions
  • Monthly, weekly, daily rate of transactions.
  • Number of payee descriptions.
  • Number of accounts, 1st level accounts, maximum depth.
  • List of commodities used.
  • Account-wise postings.
  • Commodity-wise postings.

Auto detection of journal files.

Journal files can be supplied to goledger as:

$ goledger -f myjournal.ldg bal

It is possible to specify more than one journal files as comma separated value:

$ goledger -f janjournal.ldg,febjournal.ldg bal

Optionally it also possible to pick all *.ldg files under the current working directory and all its subdirectories (recursively):

$ goledger -f all bal

Note: In all of the above forms, goledger will pick any ledger files , matching *.ldg, ledgerrc, or .ledgerrc, under ascending paths from current-working-directory. Say for instance if /Users/myname/accounts/books is the current path, then ledger files will be searched under, /Users/myname/account, /Users/myname, /Users directories.

Specifying date and time

By default the date and time format is expected as 1970/01/01 00:00:00,
where, the first part specify year/month/date while the second part, which
is optional, specify hour:minute:second. For the date component, it is
possible to use one of these delimiter, /, -, ..

Some variants of specifying date-time:

    1970/01/01 09:09:09
    1970/1/1 9:9:9
    2011/01/01

Shorter variants:

    1998/01/01
    98/01/01 09:09:09   ; interpreted as 1998/Jan/01 00:00:00
    98/Jan/01           ; interpreted as 1998/Jan/01 00:00:00
    01/01               ; interpreted as 1998/Jan/01 00:00:00
    Jan/01              ; same as above, with humanized month.

Corner cases:

  • When parsing a journal entry, if year is missing or year is specified
    with 2-digits, goledger will try to use the year information from the first
    journal entry and use its year component or the century component to
    complete the current entry's date.
  • If the first entry in the journal has its year missing or has its year
    specified in 2-digit, goledger shall use the machine local year.

Directives:

It is possible to specify the current year by inserting the following directive in
the journal file.

year 2011

After this, all the entries in the journal file will assume current year as
2011, provided the year part is missing in the date component.

Detect transaction with mixed commodity

The purpose of detecting mixed commodity in a transaction is to avoid
autobalancing until a proper support for commodity equivalence and price
equivalance are established.

2011/10/2  Sturm Brightblade
    EverQuest:Inventory                     -2 Steaks
    EverQuest:Inventory                     10 Gold
    Asset:Checking

Above transaction cannot be autobalanced without knowing the price equivalence
between Gold and Steaks.

-nosubtotal switch

balance report on the following ledger entries:

2011/02/15   Withdrawal
    Asset:Cash   100.00
    Asset:FD     -100.00

2011/03/15   Deposit
    Asset:FD:KVB1   75.00
    Asset:Cash       -75.00

2011/03/15   Deposit
    Asset:FD:KVB2   75.00
    Asset:Cash       -75.00

shall be:


  By-date      Account   Balance

  2011/Mar/15  Asset       0.00
  2011/Mar/15    Cash    -50.00
  2011/Mar/15    FD       50.00
  2011/Mar/15      KVB1   75.00
  2011/Mar/15      KVB2   75.00
                         -------
  2011/Mar/15              0.00

To avoid aggregration of sub-ledger into parent ledger, whose report shall
reflect closely to actual entries we can add -nosubtotal switch, that will
generate the following report.

  By-date      Account         Balance

  2011/Mar/15  Asset:Cash      -50.00
  2011/Feb/15  Asset:FD       -100.00
  2011/Mar/15  Asset:FD:KVB1    75.00
  2011/Mar/15  Asset:FD:KVB2    75.00
                              --------
  2011/Mar/15                    0.00

NOTE: nosubtotal switch will be automatically enabled for equity
report.

Infinite-precision rational value

Ledger internally encourages to use infinite precision rational values to avoid rounding-off errors.

Explore golang's big/ package (types: Float, Rat) for goledger.

Filter expression.

Most commands take a list of regular expression after the command argument. Extend this to include and, or, not boolean expression.

goledger -f journal.ldg balance Expenses and Incomes

Commodity equivalences

Can be considered after implementing #4

Sometimes a commodity has several forms which are all equivalent. An
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 equivalences.

For example, you might have the following two postings, one which transfers
an hour of time into a 'Billable' account, and another which decreases the
same account by ten minutes. The resulting report will indicate that
fifty minutes remain:

2005/10/01 Work done for company
    Billable:Client                 1h
    Project:XYZ

2005/10/02 Return ten minutes to the project
    Project:XYZ                    10m
    Billable:Client

Reporting the balance for this ledger file produces:

$ ledger --no-total balance Billable Project
     50.0m  Billable:Client
    -50.0m  Project:XYZ

Defining other equivalences should be simple. The following is an example that
creates commodity equivalences, helpful for tracking bytes, kilobytes,
megabytes, and more:

C 1.00 Kb = 1024 b
C 1.00 Mb = 1024 Kb
C 1.00 Gb = 1024 Mb
C 1.00 Tb = 1024 Gb

Equivalence chains can be as long as desired. While rendering the commodity,
as text, it would report as a decimal amount (less than 1.00), the next
smallest commodity is used. If a commodity could be reported in terms of a
higher commodity without resulting to a partial fraction, then the larger
commodity is used.

Refer: ledger-cli:commodity-equivalence

Transaction codes.

A transaction can have a textual “code”. This has no meaning and is only displayed by the print command. Checking accounts often use codes like DEP, XFER, etc., as well as check numbers. This is to give you a place to put those codes:

2012-03-10 (#100) KFC
    Expenses:Food                $20.00
    Assets:Checking

Commodity price equivalence

Can be considered after implementing #5

Price equivalence is considered as a special variant of Commodity equivalence.
The main differences being:

  • Commodity equivalence are considered as invariants, while price equivalence
    are considered as variants.
  • Which means a price declaration shall include date:time information as well.
  • When defining price equivalence between two commodities, alteast one of
    them should be a currency.

Example price declarations:

P 2004/06/21 02:18:01 FEQTX $22.49
P 2004/06/21 02:18:01 BORL $6.20
P 2004/06/21 02:18:02 AAPL $32.91
P 2004/06/21 02:18:02 AU $400.00

And to list the current street value of commodity balance (-V):

$ ledger --price-db prices.db -V balance brokerage

Unlike commodity equivalence, price equivalence need to be more realtime, so
we may need to explore the option of fetching real-time data from the network,
and preferrably maintain a history of fetched data offline.

Refer: ledger-cli:price-equivalence

Transaction auxiliary date.

You can associate a second date with a transaction by following the primary date with an equals sign:

2012-03-10=2012-03-08 KFC
    Expenses:Food             $20.00
    Assets:Cash                 $-20.00

What this auxiliary date means is entirely up to you. The only use Ledger has for it is that if you specify --aux-date, then all reports and calculations (including pricing) will use the auxiliary date as if it were the primary date.

Validate date fields in transactions and directives.

#Date fields like 2011/02/29 are treated as valid, actually time.Date() treats them as spill over and return a 2011/03/01. Implement a check around all date fields and ensure that they are valid calendar dates.

Implement account types and restrictions.

Accounts can be classified as following types, based on their restrictions:

credit: shall always be the source account.
debit: shall always be the target account.
creditbalance: can either be source or targer account, but a net giver.
debitbalance: can either be source or targer account, but a net receiver.
overdraft: can either be source or targer account, and with +ve/-ve balance.
exchange: default account type, no restriction
deposit, holds currency as deposit, can receive interest on deposited amount.
advance, currency lendt out that can fetch interest.
emi, currency account that is credited periodically towards a repayment.

Prefix format for log-level.

At present console logging uses the prefix format [%v] for log level that emits the log message as:

[Warng] account "Income:Salary" not pre-declared

Would it be better to change it to:

Warng: account "Income:Salary" not pre-declared

Register command: Account balance or transaction balance.

For a ledger transaction example, that contain mixed commodities:

2012-03-10 KFC
    Expenses:Food                $20.00
    Expenses:Tips                 $2.00
    Assets:Cash              EUR -10.00
    Assets:Cash              GBP -10.00
    Liabilities:Credit

goledger emits:

By-date      Payee  Account                Amount    Balance

2012-Mar-10  KFC    Expenses:Food          $20.00     $20.00
                    Expenses:Tips           $2.00      $2.00
                    Assets:Cash         EUR-10.00  EUR-10.00
                                        GBP-10.00  GBP-10.00
                    Liabilities:Credit    $-22.00    $-22.00
                                         EUR10.00   EUR10.00
                                         GBP10.00   GBP10.00

whereas the reference ledger program emits:

12-Mar-10 KFC    Expenses:Food              $20.00       $20.00
                 Expenses:Tips               $2.00       $22.00
                 Assets:Cash            EUR -10.00       $22.00
                                                     EUR -10.00
                 Assets:Cash            GBP -10.00       $22.00
                                                     EUR -10.00
                                                     GBP -10.00
                 Liabilities:Credit        $-22.00   EUR -10.00
                                                     GBP -10.00
                 Liabilities:Credit      EUR 10.00   GBP -10.00
                 Liabilities:Credit      GBP 10.00            0

Note the balance, last column, which shows the transaction balance. As opposed
to goledger's account balance.

Passbook like register reporting.

At present register reporting ends with a balance amount that nets the
transactions final tally. For example:


  By-date      Payee               Account               Amount  Balance

  2011-Feb-28  My Employer         Assets:Checking      500.00   500.00
                                   Income:Salary       -500.00     0.00
  2011-Mar-15  Departmental store  Expenses:Groceries   100.00   100.00
                                   Assets:Checking     -100.00     0.00
  2011-Mar-15  KFC                 Expenses:Dinning      75.00    75.00
                                   Assets:Checking      -75.00     0.00
  2011-Mar-15  Chats               Expenses:Dinning      75.00    75.00
                                   Assets:Checking      -75.00     0.00

Alternately we can tell goledger to display the account's current balance
after applying the posting.

Payee matching account lookup within apply block.

Take for instance the following directive:

account MyCompany:Expense:Computer:Software
    payee Circuit City

and transactions under apply block:

apply account MyCompany

2004/09/29  Circuit City
    Expenses:Computer:Unknown            $100.00
    Liabilities:Payable:Myname            $-100.00

2004/10/15  MyCompany
    Liabilities:Payable:Myname           $100.00
    Assets:Checking                      $-100.00

end apply account

Now, what is the order of applying the root account. Should we first apply the
root account to Expenses:Computer:Unknown and transform it to,
MyCompany:Expenses:Computer:Unknown and then do a payee lookup to complete
MyCompany:Expenses:Computer:Unknown to
MyCompany:Expenses:Computer:Software

Fix approximation errors in floating point.

Floating point computations lead to approximations, leading to round off errors and even functional errors. Example in dblentry/transactions.go:340

if unbc.amount != 0.0 {
    unbcs = append(unbcs, unbc)
}

Support multiple commodity and currency types.

An account may contain multiple commodities, in which case it will have
separate totals for each. For example, if your brokerage account contains both
cash, gold, and several stock quantities, the balance might look like:

$200.00
100.00 AU
AAPL 40
BORL 100
FEQTX 50  Assets:Brokerage

Refer: ledger-cli:commodities

Value expression.

There are many places in ledger-cli where value expression is used. This issues tracks all such places in case we decide to implement:

  • --period-sort VEXPR Sort postings within each period according to VEXPR.
  • --limit EXPR Limit which postings are used in calculations by EXPR.
  • --amount EXPR Change value expression reported in register report.
  • --total VEXPR Change the value expression used for “totals” column in register and balance reports.
  • --sort VEXPR Sort a report using VEXPR.

Tokenizing issue with transaction posting line.

There is an issue with parsing the different components of transaction
posting, where: the current component gets parsed as suffix for the
preceding account name.

This is forcing us to implement couple of hacks in posting.go:Posting.Yledger()
method.

Budget and forecasting.

ledger-cli supports budgeting and forecasting. This issue is used to track the places whether it needs to be implemented:

  • --budget Display how close your postings meet your budget.
  • --add-budget Show unbudgeted postings.
  • --unbudgeted Show only unbudgeted postings.
  • --forecast Project balances into the future.

Foretell command.

Foretell command should be able generate future transactions based on account declaration and cleared transactions.

Begin date and end date period.

Will affect commands:

balance, balance will stop at end-date.
register, list journals from begin-date to end-date.
list, no effect
equity, similar to balance will stop at end-date.
passbook, similar to register, list postings from begin-date to end-date.
print, transactions from begin-date to end-date.

Implement grouping options.

-bypayee Group postings by common payee names.
-daily Group postings by day.
-weekly Group postings by week.
-monthly Group postings by month.
-quarterly Group postings by quarter.
-yearly Group postings by year.
-dow Group by day of weeks.
-subtotal Group postings together, similar to the balance report.

Resetting a balance.

Say your book-keeping has gotten a bit out of date, and your Ledger balance no longer matches your bank balance. You can create an adjustment transaction using balance assignments:

2012-03-10 Adjustment
    Assets:Cash                         = $500.00
    Equity:Adjustments

Since the second posting is also null, it’s value will become the inverse of whatever amount is generated for the first posting.

This is the only time in ledger when more than one posting’s amount may be empty—and then only because it’s not truly empty, it is indirectly provided by the balance assignment’s value.

init-file like ``ledgerrc``.

Either supplied as command line parameter or loaded from ~/.ledgerrc

This can be useful in setting up the ledger shell.

Include contra postings in ``passbook`` and ``register`` commands.

At present, the following command:

$ goledger -f journal.ldg register Capital

Shall render:

2014-Mar-26  Payee ; Journal  Capital  -252427.84   -252427.84
2014-Apr-01  Payee ; Journal  Capital   101795.89   -111367.43

add a -contra switch that will include the contra postings for transactions matching Capital.

Should alias directive update account directive's alias field.

For example, the following ldg file:

account Expenses:Entertainment:Dining
    note  Eating out once a week

alias Dining=Expenses:Entertainment:Dining

when listed via list accounts command does not include tha alias directive:

account Expenses:Entertainment:Dining
    note  Eating out once a week

At present we are leaving it to this default behaviour.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.