A few-frills REST ledger server built to support Accountifie, but
also works as a standalone server.

Basic features:

stores ledgers for multiple companies.

stores transactions.

groups a transaction's balancing entries across multiple accounts.

generates balances for an account at a given date.

Special features:

balance caching for faster balance retrieval.

multi-day transactions for cases like depreciation.

fetching of transaction-list state at a given point in time. Useful for troubleshooting discrepencies.
in a report for a given date caused by back-dated or updated transactions.

filtering of balances to exclude transactions for selected counterparties or contra accounts.

Accountifie is a django frontend with advanced permission and reporting features. It provides a platform for you to create custom
objects for your business's domain that result in generated transactions, and tools for tailoring your own financial
reports with advanced export options. More information is available on github.

Ledgers and Accounts and Transactions, oh my!

A Transaction contains Lines, each with a balance and an Account. All a Transaction's Lines should balance to 0. A Line's
Contra Accounts are the Accounts of all other Lines for that transaction. A Transaction may occur on a single date
or, to avoid highly repetitive transactions like depreciation, may be spread across a period (referred to as a multi-date
transaction).

An Account contains references to all Transactions that have at least one Line for that Account. An Account also has a
Balance at any date. The Balance is calculated by summing the Account's Line amounts up to that date.

The models also contain references to Counterparties and Business Model Objects (BMOs) which are stored and
returned for convenience, but not really used by the service (except for filtering).

How it works

The service's focus has been on operational speed, especially when calculating balances. All objects are kept in
memory, sometimes at the cost of startup time. Changes are persisted to mongo using the event sourcing pattern provided
by sourced. Most implementation details have been spec'd out in
the tests.

Persistence with sourced

The system uses sourced for
persistence, a library that persists and replays method calls with their passed params to restore an entity's
(in our case GeneralLedger) state. This can have some impact on startup time, though uses snapshotting to minimise the
effect.

Sourced has the advantages of leaving a comprehensive audit trail, and enabling us to recreate the state of the system
at a given timestamp - something we've built upon with the
/gl/:LEDGER_ID/snapshot/transactions endpoint.

The best way to see a ledger's state via the database is in the GeneralLedger.snapshots collection. To get the latest
snapshot, query by {id: LEDGER_ID}, sort by {version: -1} and limit to 1 result.

Balance generation

Generating balances based on thousands of transactions has some impact on performance, especially as we're using BigNumber to
prevent floating point arithmetic issues. To improve performance, we use a
Balance Cache for each
account at the monthly anniversary of the account's first transaction. Generating a balance for a date then involves only
adding the transactions between the date and the Balance Cache immediately prior to the date. To make things even snappier
we also cache the result of every balance request that's processed, so the second time you hit /gl/myco/balances?date=2015-01-13
will probably be faster than the first.

Whenever a transaction is added, updated, or deleted, all caches with dates after the transaction are invalidated. Regenerating the
caches can take seconds and, since node is unithreaded, get in the way of processing requests. To overcome this, the task is split
into microtasks (one per cache) which are placed on the
Low Priority Queue
(aka the LPQ). The LPQ processes a microtask then sleeps for a bit so requests can be processed. This means the balance caches
could take a few minutes to generate after CUDing some old transactions, resulting in slowed balance fetching, but this is unlikely
to have much real-world impact. You can monitor the status of the LPQ at
/lpq/stats.

Balances may be requested with a Filter that excludes Counterparties or Conta Accounts, or limit to a set of Counterparties.
Filtered transactions are unable to use the cached balances generated for unfiltered transactions, nor is a filter able to
use the cached balances for a different filter, as a different set of transactions may be used to calculate the transactions. Because
of this, each balance cache is also associated with a filter.

By default, only unfiltered transactions have balance caches generated automatically, though all requests will have the balance
cached against the filter provided in the request. You can get caches to generate automatically for a filter by using the
/gl/:LEDGER_ID/add-filter endpoint.

Multi-day transactions

Some Transactions, like depreciation, occur over a period instead of on a given date. These transactions have a dateEnd as well
as a date. When a balance is calculated on a date that falls part-way through the period, it will contain only the portion of
the transaction's amount for the period that has lapsed. For instance, for a transaction with
date='2015-01-01', dateEnd='2015-01-04', amount='4.00':

a balance on 2015-01-01 would include only $1 for that transaction.

a balance on 2015-01-02 would include $2

a balance on 2015-01-03 would include $3

balances on 2015-01-04 and beyond would include all $4

When requesting a list of transactions for a period that contains only a portion of the transaction, the transaction's amount will
reflect the amount during the overlap and the transaction's date or endDate will be adjusted so the transaction fits within
the specified period. E.g. a transaction with date='2015-01-01', dateEnd='2015-01-04', amount='4.00':

For reporting convenience, you can provide the chunkFrequency=end-of-month param to
/gl/:LEDGER_ID/transactions, which
will break a multi-day transaction into multiple transactions at each month's boundary.