ledger: General accounting

The lino_xl.lib.ledger plugin adds basic notions for accounting: accounts, journals, vouchers and movements.

Table of contents:

Examples in this document use the lino_book.projects.apc demo project.

>>> from lino import startup
>>> startup('lino_book.projects.apc.settings.demo')
>>> from lino.api.doctest import *
>>> ses = rt.login("robin")
>>> translation.activate('en')

List of partners who are both supplier and customer and have open movements:

>>> from lino_xl.lib.ledger.choicelists import TradeTypes
>>> def has_mvt(obj, tt):
...     qs = ledger.Movement.objects.filter(partner=obj, cleared=False, voucher__journal__trade_type=tt)
...     return qs.count()
>>> for p in contacts.Partner.objects.all():
...     if has_mvt(p, TradeTypes.purchases) and has_mvt(p, TradeTypes.sales):
...         print(p.pk, p)


A ledger is a book in which the monetary transactions of a business are posted in the form of debits and credits (from 1).

In Lino, the ledger is implemented by three database models:

ledger voucher

Any document that serves as legal proof for a ledger transaction in the ledger. Examples of vouchers include invoices, bank statements, or payment orders, VAT declarations, ...

Vouchers are stored in the database using some subclass of the Voucher model. The voucher model is never being used directly despite the fact that it is a concrete model.


A series of sequentially numbered vouchers.

ledger movement

An atomic "transfer" of a given amount of money from (or to) a given ledger account at a given date. It is just a conceptual transfer, not a cash or bank transfer.

Moving money from (out of) an account is called "to debit", moving money to an account is called "to credit".

Movements are never created individually but by registering a ledger voucher.

ledger account

The most abstract representation for "something where you can place money and retrieve it later".

An account always has a given balance which can be negative or positive.

In applications which use the ledger plugin, accounts are used as the target of ledger movements.

payable transaction

A transaction that is expected to cause a payment by a partner.

For example sales invoices, purchase invoices, VAT declarations are payable transactions.

Some more concepts:

ledger transaction

The group of movements generated by a same ledger voucher. For each transaction there must be at least two movements for which the sum of debited money equals the sum of credited money.

A transaction always happens at a given date and in a given accounting period which itself is part of a given fiscal year.

common account

A well-known account for which the site manager must configure a corresponding account of your accounts chart. See CommonAccounts.

fiscal year

A sequence of consecutive accounting periods covered by an annual business activity report.

This usually corresponds to a calendar year. But not always. Exceptions may be companies having a shifted annual report or transitional periods.

When the annual report has been published (declared to the national tax office), the fiscal year should be closed to prevent accidental changes in the ledger of that year.

accounting period

The month or quarter into which a given transaction is booked. Usually the same as the calendar month of the voucher's entry date.


A ledger voucher sent to or received from a business partner, showing a list of goods or services, their price, and the amount due.

product invoice

An invoice that is also a trade document, i.e. the items of which point to a product.

Each product mentioned in the items maps to a ledger account according to configurable rules.

account invoice

An invoice where each row points directly to ledger accounts and doesn't mention any product. This is in contrast to an product invoice.

In a default Lino Così site, purchase invoices are implemented as account invoices while sales invoices are product invoices.


A ledger voucher sent to each employee every month, detailing the amount of the salary or wage and resulting tax and other legal transactions.

bank statement

A ledger voucher received from the bank, showing all transactions on a given account during a given date range.

cash book

A journal of all transactions in a given cash box.

The transactions are grouped into cash statements, which are similar to a bank statement, but issued internally and potentially to be signed by a responsible person.

preliminary transactions

Transactions that happened before the accounting period they are recorded for. They are part of the opening balance, but not to be considered as part of the actual accounting period's history.

They are used to enter any relevant account activity of a corporation that has been booked using another software and/or database.

Note that opening entries, i.e. transactions made at the start of an organization as part of the foundation process, are are not preliminary.

In Lino, you create them in a dedicated journal that has its preliminary field checked.

trade type

The type of a trade operation. For example "sales" and "purchases" are the most common trade types. But we can also have "salaries", "taxes", ... See Trade types

There are some secondary models and choice lists:

  • A match rule specifies that a movement into given account can be cleared using a given journal.

  • The payment term of an invoice (PaymentTerm) is a convention on how the invoice should be paid.

And then there are many views for looking at this data.


class lino_xl.lib.ledger.Account

Django model for representing a ledger account.


The multilingual designation of this account, as the users see it.


An optional unique name which can be used to reference a given account.


The account type of this account. This points to an item of CommonAccounts.


Whether bookings to this account need a partner specified.

For payment orders this causes the contra entry of financial documents to be detailed or not (i.e. one contra entry for every item or a single contra entry per voucher.


The default VAT class to use for transactions on this account.


The default amount to book in bank statements or journal entries when this account has been selected manually. The default booking direction is that of the type.


These checkboxes indicate whether this account can be used on an item of a purchases (or sales or wages or FOO) invoice. There is one such checkbox for every trade type (TradeTypes). They exist only when the ledger plugin is installed as well. See also the get_allowed_accounts method.


Whether transactions on this account require the user to also specify an analytic account.

This file exists only when lino_xl.lib.ana is installed as well.


Which analytic account to suggest for transactions on this account.

This file exists only when lino_xl.lib.ana is installed as well.


Pointer to the item of the balance sheet or income statement that will report the movements of this account.

This file is a dummy field when lino_xl.lib.sheets is not installed.

Common accounts

The accounts plugin defines a choicelist of common accounts which are used to reference the database object for certain accounts which have a special meaning.

class lino_xl.lib.ledger.CommonAccounts

The global list of common accounts.

This is a lino.core.choicelists.ChoiceList. Every item is an instance of CommonAccount.

This list is automatically sorted at startup because it is populated by several plugins, and because the natural sorting order would be useless and irritating.

class lino_xl.lib.ledger.CommonAccount

The base class for items of :CommonAccounts.

It defines two additional attributes:


Default value for Account.clearable.


Default value for Account.needs_partner.


Return the database object representing this common account.

set_object(self, obj)

Set the cached database object representing this common account.

Called internally when Account.common_account is updated via web interface.

Here is the standard list of common accounts in a Lino Così application:

>>> rt.show(ledger.CommonAccounts, language="en")
======= ========================= ========================= =========== ================================
 value   name                      text                      Clearable   Account
------- ------------------------- ------------------------- ----------- --------------------------------
 1000    net_income_loss           Net income (loss)         Yes         (1000) Net income (loss)
 4000    customers                 Customers                 Yes         (4000) Customers
 4100    suppliers                 Suppliers                 Yes         (4100) Suppliers
 4200    employees                 Employees                 Yes         (4200) Employees
 4300    pending_po                Pending Payment Orders    Yes         (4300) Pending Payment Orders
 4500    tax_offices               Tax Offices               Yes         (4500) Tax Offices
 4510    vat_due                   VAT due                   No          (4510) VAT due
 4513    due_taxes                 VAT declared              No          (4513) VAT declared
 4520    vat_deductible            VAT deductible            No          (4520) VAT deductible
 4530    vat_returnable            VAT returnable            No          (4530) VAT returnable
 4800    clearings                 Internal clearings        Yes         (4800) Internal clearings
 4900    waiting                   Waiting account           Yes         (4900) Waiting account
 5500    best_bank                 BestBank                  No          (5500) BestBank
 5700    cash                      Cash                      No          (5700) Cash
 6010    purchase_of_services      Purchase of services      No          (6010) Purchase of services
 6020    purchase_of_investments   Purchase of investments   No          (6020) Purchase of investments
 6040    purchase_of_goods         Purchase of goods         No          (6040) Purchase of goods
 6300    wages                     Wages                     No          (6300) Wages
 6900    net_income                Net income                No          (6900) Net income
 7000    sales                     Sales                     No          (7000) Sales
 7900    net_loss                  Net loss                  No
======= ========================= ========================= =========== ================================

Lino applications can add specific items to that list or potentially redefine it completely.

Keep in mind that common accounts are no database objects. See them rather as a list of configuration values. They are just a list of named pointers to actual database objects.

For example you might want to know how many sales operations are in your database:

>>> obj = ledger.CommonAccounts.sales.get_object()
>>> obj
Account #20 ('(7000) Sales')
>>> ledger.Movement.objects.filter(account=obj).count()

A common account neither requires nor makes sure that its database object exists. For example the common account "Net loss" has no database object in the accounts chart pointing to it. The above trick won't work for counting the number of net loss operations:

>>> obj = ledger.CommonAccounts.net_loss.get_object()
>>> obj
>>> ledger.Movement.objects.filter(account=obj).count()
Traceback (most recent call last):
TypeError: Field 'id' expected a number but got MissingAccount(<ledger.CommonAccounts.net_loss:7900>).

Debit and credit


Every movement of a financial transaction "moves" some amount either out of or into a given account. For some reasons beyond the scope of this book, accountants didn't want to express this "direction" of a movement simply by using either a positive or a negative number, they wanted an explicit word for it and called it debiting and crediting.

We represent the direction of a movement internally as the boolean values True and False, but define two names DEBIT and CREDIT for them:

>>> from lino_xl.lib.ledger.utils import DEBIT, CREDIT

Since it is a boolean field, some frontends might represent it as a checkbox. In that case remember that checked means credit and not checked means debit.

The balance of an account

The balance of an account is the amount of money in that account. An account balance is either Debit or Credit.

class lino_xl.lib.ledger.Balance

Light-weight object to represent a balance, i.e. an amount together with its booking direction (debit or credit).



The amount of this balance when it is debiting, otherwise zero.


The amount of this balance when it is crediting, otherwise zero.

A negative value on one side of the balance is automatically moved to the other side.

>>> from lino_xl.lib.ledger.utils import Balance
>>> Balance(10, -2)

Database fields

class lino_xl.lib.ledger.DebitOrCreditField

A field that stores the "direction" of a movement, i.e. either DEBIT or CREDIT.

class lino_xl.lib.ledger.DebitOrCreditStoreField

Uused as lino_atomizer_class for DebitOrCreditField.


class lino_xl.lib.ledger.Movement

Django model used to represent a ledger movement


The date at which this movement is to be entered into the ledger. This is usually the voucher's entry_date, except e.g. for bank statements where each item can have its own value date.


Pointer to the ledger voucher that caused this movement.


Pointer to the partner involved in this movement.

If account has Account.needs_partner set, this may not be blank, otherwise it must be blank.


Sequential number within a voucher.


Pointer to the Account that is being moved by this movement.


Virtual field showing amount if dc is DEBIT.


Virtual field showing amount if dc is CREDIT.


Pointer to the Movement that is being cleared by this movement.




A virtual field which returns the partner of the voucher. For incoming invoices this is the supplier, for outgoing invoices this is the customer, for financial vouchers this is empty.

A virtual field which shows a link to the voucher.

A virtual field which shows a clickable variant of the match string. Clicking it will open a table with all movements having that match.


The analytic account to move together with this transactions.

This file exists only when lino_xl.lib.ana is installed as well.

class lino_xl.lib.ledger.Movements

The base table for all tables having ledger movements as rows.

Defines filtering parameters and general behaviour.

class lino_xl.lib.ledger.MovementsByPartner

Shows the ledger movements linked to a given partner.

class lino_xl.lib.ledger.MovementsByAccount

Shows the ledger movements done on a given general account.


A virtual field showing a comma-separated list of the following items:

  • voucher narration

  • voucher partner

  • transaction's partner

  • transaction's project

class lino_xl.lib.ledger.MovementsByMatch

Show all movements having a given Movement.match.

This is another example of a slave table whose master is not a database object, and the first example of a slave table whose master is a simple string.

class lino_xl.lib.ledger.MovementsByProject

Show the ledger movements of a project.

class lino_xl.lib.ledger.AllMovements

Show all the ledger movements in the database.

Displayed by Explorer ‣ Accounting ‣ Movements.

class lino_xl.lib.ledger.MovementsByVoucher

Show the ledger movements generated by a given voucher.

The summary of MovementsByPartner shows a balance. A negative number means that we owe money to this partner, a positive number means that this partner owes us money.

For example David da Vinci has 4 open invoices:

>>> obj = rt.models.contacts.Person.objects.get(pk=165)
>>> obj
Person #165 ('Mr David da Vinci')
>>> rt.show(rt.models.ledger.MovementsByPartner, obj)
**2 open movements (1946.43 €)**
>>> rt.show(rt.models.ledger.MovementsByPartner, obj, nosummary=True)
============ =============== ======================================= ============== ======== ================= =========
 Value date   Voucher         Description                             Debit          Credit   Match             Cleared
------------ --------------- --------------------------------------- -------------- -------- ----------------- ---------
 12/03/2015   *SLS 15/2015*   *(4000) Customers* | *da Vinci David*   1 299,08                **SLS 15/2015**   No
 11/03/2015   *SLS 14/2015*   *(4000) Customers* | *da Vinci David*   647,35                  **SLS 14/2015**   No
                              **Balance 1946.43 (2 movements)**       **1 946,43**
============ =============== ======================================= ============== ======== ================= =========


class lino_xl.lib.ledger.Voucher

Django model used to represent a ledger voucher.

This model is not abstract so that Movement can have a ForeignKey to a Voucher.

A voucher is never instantiated using this base model but using one of its subclasses. Here are the voucher subclasses available in Lino Così:

>>> pprint(rt.models_by_base(ledger.Voucher))
[<class 'lino_xl.lib.bevat.models.Declaration'>,
 <class 'lino_xl.lib.finan.models.BankStatement'>,
 <class 'lino_xl.lib.finan.models.JournalEntry'>,
 <class 'lino_xl.lib.finan.models.PaymentOrder'>,
 <class 'lino_xl.lib.ledger.models.Voucher'>,
 <class 'lino_xl.lib.sales.models.VatProductInvoice'>,
 <class 'lino_xl.lib.vat.models.VatAccountInvoice'>]

When the partner of an empty voucher has a purchase account, Lino automatically creates a voucher item using this account with empty amount.


The workflow state of this voucher.

This field is defined by the implementing voucher class, which depends on the journal's voucher type.

Choices are defined in VoucherStates


The journal into which this voucher has been booked. This is a mandatory pointer to a Journal instance.


The sequence number of this voucher in the journal.

The voucher number is automatically assigned when the voucher is saved for the first time. The voucher number depends on whether yearly_numbering is enabled or not.

There might be surprising numbering if two users create vouchers in a same journal at the same time.


The date of the journal entry, i.e. when this voucher is to journalized or booked.


The date on the voucher (i.e. when it has been issued by its emitter).

This is usually the same as entry_date. Exceptions may be invoices arriving after their fiscal year has been closed. Note that if you change entry_date of a voucher, then Lino will set the voucher_date to that date.


The accounting period to use when booking this voucher. The default value is determined from entry_date.

If user changes this field, the number gets re-computed because it might change depending on the fiscal year of the accounting period.


A short explanation which ascertains the subject matter of this journal entry.


A text like "2019-12".

do_and_clear(func, do_clear)

Delete all movements of this voucher, then run the given callable func, passing it a set with all partners who had at least one movement in this voucher. The function is expected to add more partners to this set. Then call check_clearings() for all these partners.

create_movement(item, acc_tuple, project, dc, amount, **kw):

Create a movement for this voucher.

The specified item may be None if this the movement is caused by more than one item. It is used by DatedFinancialVoucher.


Return the partner related to this voucher. Overridden by PartnerRelated vouchers.

get_movement_description(self, ar)

Generate a series of HTML chunks to be displayed in the Movment.description field.


Subclasses must implement this. Supposed to return or yield a list of unsaved Movement instances.


Return the specialized form of this voucher.

From any Voucher instance we can get the actual document (Invoice, PaymentOrder, BankStatement, ...) by calling this method.

Class inheritance diagram

Inheritance diagram of lino_xl.lib.ledger.models.Voucher

Registering a voucher

A ledger voucher is always in one of the three states "Draft", "Registered" or "Cancelled". "Registering a voucher" means to change it status from "Draft" to "Registered".

When a voucher is registered, it receives a sequence number in its journal and Lino generates the movements according to the data in the voucher.

A registered voucher cannot be edited or deleted.

You can deregister a voucher at any moment (except when you lack permission for this actions, or when the voucher is in a fiscal year that has been closed).

When you deregister a voucher, all movements are deleted.

class lino_xl.lib.ledger.RegistrableVoucher

Toggle between "registered" and "draft" state.

A one-click action to quickly toggle between the two the most-used states of a voucher.

>>> finan.BankStatement.toggle_state.help_text
'Toggle between "registered" and "draft" state.'

We usually don't want to see the number of a voucher in an editable state because that number may change. We prefer to see the primary key prefixed with a hash to indicate that the voucher is not registered. But e.g. in lino_xl.lib.orders we want to disable this feature.

NB we might simply override __str__(), but maybe this feature will be used in other contexts as well.

The state of a voucher is stored in a field voucher_state. The available states and the rules for changing the state are called the workflow.

class lino_xl.lib.ledger.ToggleState

The action behind RegistrableVoucher.toggle_state.


Here is the list of all journals.

>>> ses.show(ledger.Journals,
...     column_names="ref name trade_type account dc")
=========== ============================ ============================ ============================ ===================== =============================== ===========================
 Reference   Designation                  Designation (fr)             Designation (en)             Trade type            Account                         Primary booking direction
----------- ---------------------------- ---------------------------- ---------------------------- --------------------- ------------------------------- ---------------------------
 SLS         Verkaufsrechnungen           Factures vente               Sales invoices               Sales                                                 Credit
 SLC         Gutschriften Verkauf         Notes de crédit vente        Sales credit notes           Sales                                                 Debit
 PRC         Einkaufsrechnungen           Factures achat               Purchase invoices            Purchases                                             Debit
 PMO         Zahlungsaufträge             Ordre de paiement Bestbank   Bestbank Payment Orders      Bank payment orders   (4300) Pending Payment Orders   Debit
 CSH         Kassenbuch                   Livre de caisse              Cash book                                          (5700) Cash                     Credit
 BNK         Bestbank                     Bestbank                     Bestbank                                           (5500) BestBank                 Credit
 MSC         Miscellaneous transactions   Opérations diverses          Miscellaneous transactions                         (5700) Cash                     Credit
 PRE         Preliminary transactions     Preliminary transactions     Preliminary transactions                           (5700) Cash                     Credit
 SAL         Lohnscheine                  Fiches de paie               Paychecks                                          (5700) Cash                     Credit
 VAT         MwSt.-Erklärungen            Déclarations TVA             VAT declarations             Taxes                 (4513) VAT declared             Debit
=========== ============================ ============================ ============================ ===================== =============================== ===========================
class lino_xl.lib.ledger.Journal

Django model used to represent a journal.



Pointer to TradeTypes.


Pointer to an item of VoucherTypes.


Pointer to an item of JournalGroups.


Whether the number of vouchers should restart at 1 every year.


Whether transactions in this journal are considered preliminary.


The account to use for the counter-movements generated by vouchers in this journal.


The partner to use as default partner for all vouchers in this journal.


The primary booking direction (checked means Credit, unchecked Debit).

In a journal of sales invoices this should be Debit (checked), because a positive invoice total should be debited from the customer's account.

In a journal of purchase invoices this should be Credit (not checked), because a positive invoice total should be credited to the supplier's account.

In a journal of bank statements this should be Debit (checked), because a positive balance change should be debited from the bank's general account.

In a journal of payment orders this should be Credit (not checked), because a positive total means an "expense" and should be credited from the journal's general account.

In all financial vouchers, the amount of every item increases the total if its direction is opposite of the primary direction.


Whether to automatically check and update the 'cleared' status of involved transactions when (de)registering a voucher of this journal.

This can be temporarily disabled e.g. by batch actions in order to save time.


Whether to automatically fill voucher item from due payments of the partner when entering a financial voucher.


See PrintableType.template.


Your bank account to specify in payment order.

Added by sepa : Communicating with the bank using SEPA.

class lino_xl.lib.ledger.Journals

List of all Journals. Accessible via Configure ‣ Accounting ‣ Journals.

class lino_xl.lib.ledger.JournalsOverview

The list of all Journals shown in the dashboard.

This is used as the primary dashboard item in Lino Così. It gives an idea of how much data is in the database, and it adds links for quickly opening a journal (which is after all one of the frequent actions in an accounting application).

>>> rt.login("robin").show(ledger.JournalsOverview)
**72 Sales invoices (SLS)** **⊕**
**0 Sales credit notes (SLC)** **⊕**
**105 Purchase invoices (PRC)** **⊕**
**14 Bestbank Payment Orders (PMO)** **⊕**
**0 Cash book (CSH)** **⊕**
**14 Bestbank (BNK)** **⊕**
**0 Miscellaneous transactions (MSC)** **⊕**
**1 Preliminary transactions (PRE)** **⊕**
**0 Paychecks (SAL)** **⊕**
**14 VAT declarations (VAT)** **⊕**
>>> rt.login("robin").show(ledger.JournalsOverview, nosummary=True)
======================================================== ========= =========== ============ ============ ==========
 Description                                              Total     This year   This month   Unfinished   Warnings
-------------------------------------------------------- --------- ----------- ------------ ------------ ----------
 Sales invoices (SLS) / **New Invoice**                   **72**    **15**      **6**
 Sales credit notes (SLC) / **New Credit note**
 Purchase invoices (PRC) / **New Invoice**                **105**   **21**      **7**
 Bestbank Payment Orders (PMO) / **New Payment order**    **14**    **2**
 Cash book (CSH) / **New Cash statement**
 Bestbank (BNK) / **New Bank statement**                  **14**    **2**
 Miscellaneous transactions (MSC) / **New Transaction**
 Preliminary transactions (PRE) / **New Transaction**     **1**
 Paychecks (SAL) / **New Paycheck**
 VAT declarations (VAT) / **New VAT declaration**         **14**    **2**
 **Total (10 rows)**                                      **220**   **42**      **13**       **0**
======================================================== ========= =========== ============ ============ ==========

Class inheritance diagram

Inheritance diagram of lino_xl.lib.ledger.models.Journal

Debit or credit

The "PCSD" rule: A purchase invoice credits the supplier's account, a sales invoice debits the customer's account.

>>> obj = vat.VatAccountInvoice.objects.order_by('id')[0]
>>> rt.show(vat.MovementsByVoucher, obj)
============================= ========== =========== =========== ========================== ================ =========
 Account                       Partner    Debit       Credit      VAT class                  Match            Cleared
----------------------------- ---------- ----------- ----------- -------------------------- ---------------- ---------
 (4100) Suppliers              Bestbank               40,00                                  **PRC 1/2014**   Yes
 (4520) VAT deductible                    6,94                    Goods at normal VAT rate                    Yes
 (6010) Purchase of services              33,06                   Goods at normal VAT rate                    Yes
                                          **40,00**   **40,00**
============================= ========== =========== =========== ========================== ================ =========
>>> obj = sales.VatProductInvoice.objects.order_by('id')[0]
>>> rt.show(vat.MovementsByVoucher, obj)
================== ========== ============== ============== =========== ================ =========
 Account            Partner    Debit          Credit         VAT class   Match            Cleared
------------------ ---------- -------------- -------------- ----------- ---------------- ---------
 (4000) Customers   Bestbank   3 629,82                                  **SLS 1/2014**   Yes
 (4510) VAT due                               629,97         Services                     Yes
 (7000) Sales                                 2 999,85       Services                     Yes
                               **3 629,82**   **3 629,82**
================== ========== ============== ============== =========== ================ =========

So the balance of a supplier's account (when open) is usually on the credit side (they gave us money) while a customer's balance is usually on the debit side (they owe us money).

>>> from lino_xl.lib.ledger.utils import DCLABELS
>>> print(DCLABELS[ledger.TradeTypes.purchases.dc])
>>> print(DCLABELS[ledger.TradeTypes.sales.dc])

Ledger info

class lino_xl.lib.ledger.LedgerInfo

Django model used to store ledger specific information per user.


OneToOneField pointing to the user.


The last value this user typed as entry_date of a voucher. It is the default value for every new voucher.

classmethod get_by_user(self, user)

Returns the ledger info entry for a given user.

Match rules

class lino_xl.lib.ledger.MatchRule

Django model used to store match rules.

Payment terms

class lino_xl.lib.ledger.PaymentTerm

Django model used to store payment terms.

The following fields define the default value for due_date:


Number of days to add to voucher_date.


Number of months to add to voucher_date.


Whether to move voucher_date to the end of month.


The worker who pays or collects the invoice using Internal clearings.


Used in sales/VatProductInvoice/trailer.html as follows:

{% if obj.payment_term.printed_text %}
{% else %}
{{_("Payment terms")}} : {{obj.payment_term}}
{% endif %}

The printed_text field is important when using prepayments or other more complex payment terms. Lino uses a rather simple approach to handle prepayment invoices: only the global amount and the final due date is stored in the database, all intermediate amounts and due dates are just generated in the printable document. You just define one PaymentTerm row for each prepayment formula and configure your printed_text field. For example:

Prepayment <b>30%</b>
({{(obj.total_incl*30)/100}} {{obj.currency}})
due on <b>{{fds(obj.due_date)}}</b>, remaining
{{obj.total_incl - (obj.total_incl*30)/100}} {{obj.currency}}
due 10 days before delivery.

Accounting periods

class lino_xl.lib.ledger.AccountingPeriod

An accounting period is the smallest time slice to be observed (declare) in accounting reports. Usually it corresponds to one month. Except for some small companies which declare per quarter.

For each period it is possible to specify the exact dates during which it is allowed to register vouchers into this period, and also its "state": whether it is "closed" or not.



class lino_xl.lib.ledger.ByJournal

Mixin for journal-based tables of vouchers.

Note that this is not explicitly marked as abstract by the application developer, but Lino knows that it is abstract because it has no model.

>>> ledger.ByJournal.abstract
>>> ledger.ByJournal.is_abstract()
class lino_xl.lib.ledger.Vouchers

The base table for all tables working on Voucher.

class lino_xl.lib.ledger.ExpectedMovements

A virtual table of DueMovement rows, showing all "expected" "movements (payments)".

Subclasses are DebtsByAccount and DebtsByPartner.

Also subclassed by lino_xl.lib.finan.SuggestionsByVoucher.


Show only movements whose booking date is before or on the given date.


Show only movements in the given trade type.


Show only movements generated by a voucher in the given journal.


Show only movements that may be matched by the given journal (i.e. for which a match rule exists).


Show only movements on the given account.


Show only movements with the given partner.


Show only movements about the given project.


Show only movements whose partner has a SEPA account.


Show only movements having the same booking direction as the target voucher.

class lino_xl.lib.ledger.DebtsByAccount

The ExpectedMovements accessible by clicking the "Debts" action button on an account.

class lino_xl.lib.ledger.DebtsByPartner

This is the table being printed in a Payment Reminder. Usually this table has one row per sales invoice which is not fully paid. But several invoices ("debts") may be grouped by match. If the partner has purchase invoices, these are deduced from the balance.

This table is accessible by clicking the "Debts" action button on a Partner.

class lino_xl.lib.ledger.PartnerVouchers

Base class for tables of partner vouchers.

  • Yes : show only completely cleared vouchers.

  • No : show only vouchers with at least one open partner movement.

  • empty: don't care about movements.

class lino_xl.lib.ledger.AccountsBalance

A virtual table, the base class for different reports that show a list of accounts with the following columns:

ref description old_d old_c during_d during_c new_d new_c

Subclasses are :class:'GeneralAccountsBalance`, :class:'CustomerAccountsBalance` and :class:'SupplierAccountsBalance`.

class lino_xl.lib.ledger.GeneralAccountsBalance

An AccountsBalance for general accounts.

class lino_xl.lib.ledger.PartnerAccountsBalance

An AccountsBalance for partner accounts.

class lino_xl.lib.ledger.CustomerAccountsBalance

A PartnerAccountsBalance for the TradeType "sales".

class lino_xl.lib.ledger.SuppliersAccountsBalance

A PartnerAccountsBalance for the TradeType "purchases".

class lino_xl.lib.ledger.DebtorsCreditors

Abstract base class for different tables showing a list of partners with the following columns:

partner due_date balance actions

class lino_xl.lib.ledger.Debtors

Shows partners who have some debt against us. Inherits from DebtorsCreditors.

class lino_xl.lib.ledger.Creditors

Shows partners who give us some form of credit. Inherits from DebtorsCreditors.

Trade types

The trade type is one of the basic properties of every ledger operation that involves an external partner. Every movement involving a partner is of one and only one trade type.

The default list of trade types is:

>>> rt.show(ledger.TradeTypes)
======= =========== ===================== ======================================================== ============================================== =============================== =====================================
 value   name        text                  Main account                                             Base account                                   Product account field           Invoice account field
------- ----------- --------------------- -------------------------------------------------------- ---------------------------------------------- ------------------------------- -------------------------------------
 S       sales       Sales                 (4000) Customers (Customers)                             (7000) Sales (Sales)                           Sales account (sales_account)
 P       purchases   Purchases             (4100) Suppliers (Suppliers)                             (6040) Purchase of goods (Purchase of goods)                                   Purchase account (purchase_account)
 W       wages       Wages                 (4200) Employees (Employees)                             (6300) Wages (Wages)
 T       taxes       Taxes                 (4500) Tax Offices (Tax Offices)                         (4513) VAT declared (VAT declared)
 C       clearings   Clearings             (4800) Internal clearings (Internal clearings)
 B       bank_po     Bank payment orders   (4300) Pending Payment Orders (Pending Payment Orders)
======= =========== ===================== ======================================================== ============================================== =============================== =====================================

Your application might have a different list. You can see the actually configured list for your site via Explorer ‣ Accounting ‣ Trade types.

class lino_xl.lib.ledger.TradeTypes

The choicelist with the trade types defined for this application.

The default configuration defines the following trade types:


When you write an invoice to a customer and when the customer pays it.


When you get an invoice from a provider and when you pay it.


When you write a payroll (declare the fact that you owe some wage to an employee) and later pay it (e.g. via a payment order).


When an employee declares that he paid some invoice for you, and later you pay that money back to his account. Or the employee collects money for a sales invoice and later returns that money to you. See Internal clearings.


When you ask your bank to execute a payment, and later the bank debits your account.

Every trade type has the following properties.

class lino_xl.lib.ledger.TradeType

Base class for the choices of TradeTypes.


The default booking direction.


The common account into which the total amount of partner vouchers (base + taxes) and their payments should be booked.


The default common account into which the base amount of any operation should be booked.


The name of a field to be injected on the Partner model which points to an account to be used instead of the default base_account.


The name of a field to be injected on the Product database model which points to an account to be used instead of the default base_account.


The name and label of the price field to be defined on the Product database model.


Return the account into which the base amount of any operation of this rete type should be booked.

This is either the base account defined in the base_account_field_name for the given product, or the site-wide base_account.


Return the catalog price of the given product for operations with this trade type.


Return the account to use as default value for account invoice items. This is the invoice_account_field of the given partner and can be None.

Match rules

A match rule specifies that a movement into given account can be cleared using a given journal.

You can configure match rules either in the detail view of a journal or globally via Explorer ‣ Accounting ‣ Match rules.

The demo database has the following match rules:

>>> ses.show(ledger.MatchRules)
==== =============================== ==================================
 ID   Account                         Journal
---- ------------------------------- ----------------------------------
 1    (4000) Customers                Sales invoices (SLS)
 2    (4000) Customers                Sales credit notes (SLC)
 3    (4100) Suppliers                Purchase invoices (PRC)
 4    (4000) Customers                Bestbank Payment Orders (PMO)
 5    (4100) Suppliers                Bestbank Payment Orders (PMO)
 6    (4500) Tax Offices              Bestbank Payment Orders (PMO)
 7    (6300) Wages                    Bestbank Payment Orders (PMO)
 8    (4000) Customers                Cash book (CSH)
 9    (4100) Suppliers                Cash book (CSH)
 10   (4500) Tax Offices              Cash book (CSH)
 11   (6300) Wages                    Cash book (CSH)
 12   (4300) Pending Payment Orders   Cash book (CSH)
 13   (4000) Customers                Bestbank (BNK)
 14   (4100) Suppliers                Bestbank (BNK)
 15   (4500) Tax Offices              Bestbank (BNK)
 16   (6300) Wages                    Bestbank (BNK)
 17   (4300) Pending Payment Orders   Bestbank (BNK)
 18   (4000) Customers                Miscellaneous transactions (MSC)
 19   (4100) Suppliers                Miscellaneous transactions (MSC)
 20   (4500) Tax Offices              Miscellaneous transactions (MSC)
 21   (6300) Wages                    Miscellaneous transactions (MSC)
 22   (4300) Pending Payment Orders   Miscellaneous transactions (MSC)
 23   (4000) Customers                Preliminary transactions (PRE)
 24   (4100) Suppliers                Preliminary transactions (PRE)
 25   (4500) Tax Offices              Preliminary transactions (PRE)
 26   (6300) Wages                    Preliminary transactions (PRE)
 27   (4300) Pending Payment Orders   Preliminary transactions (PRE)
 28   (4000) Customers                Paychecks (SAL)
 29   (4100) Suppliers                Paychecks (SAL)
 30   (4500) Tax Offices              Paychecks (SAL)
 31   (6300) Wages                    Paychecks (SAL)
 32   (4300) Pending Payment Orders   Paychecks (SAL)
 33   (4500) Tax Offices              VAT declarations (VAT)
==== =============================== ==================================

For example a payment order can be used to pay wages and suppliers invoices or (less frequently) to send back money that a customer had paid too much:

>>> jnl = ledger.Journal.objects.get(ref="PMO")
>>> rt.show(ledger.MatchRulesByJournal, jnl)
 (4000) Customers
 (4100) Suppliers
 (4500) Tax Offices
 (6300) Wages

Or a sales invoice can be used to clear another sales invoice:

>>> jnl = ledger.Journal.objects.get(ref="SLS")
>>> rt.show(ledger.MatchRulesByJournal, jnl)
 (4000) Customers


Debtors are partners who received credit from us and therefore are in debt towards us.

The most common debtors are customers, i.e. partners who received a sales invoice from us and did not yet pay that invoice.

There can be debtors who are not customers. For example a bank or a tax office. A bank is a debtor when pending payment orders are booked to this account. A tax office is a debtor when we had more VAT deductible (sales) than VAT due (purchases).

>>> ses.show(ledger.Debtors, column_names="due_date partner partner_id balance")
==================== ======================= ========== ===============
 Due date             Partner                 ID         Balance
-------------------- ----------------------- ---------- ---------------
 10/02/2014           Dubois Robin            179        8 908,45
 08/02/2015           Radermacher Christian   155        853,97
 11/02/2015           Radermacher Fritz       158        632,96
 07/03/2015           Radermacher Hedi        161        3 629,82
 09/03/2015           Radermacher Jean        163        822,57
 10/03/2015           di Rupo Didier          164        338,80
 11/03/2015           da Vinci David          165        1 946,43
 **Total (7 rows)**                           **1145**   **17 133,00**
==================== ======================= ========== ===============

The DebtsByPartner shows one row per uncleared invoice, and a list of --usually partial-- payments per invoice. For example here is the detail of the debts for partner 165 from above list:

>>> obj = contacts.Partner.objects.get(pk=165)
>>> obj
Partner #165 ('da Vinci David')
>>> ses.show(ledger.DebtsByPartner, obj)
==================== ============== ========================== ==========
 Due date             Balance        Debts                      Payments
-------------------- -------------- -------------------------- ----------
 11/03/2015           647,35         `SLS 14/2015 <Detail>`__
 12/03/2015           1 299,08       `SLS 15/2015 <Detail>`__
 **Total (2 rows)**   **1 946,43**
==================== ============== ========================== ==========

Creditors are partners who gave us credit, IOW to whom we owe money. The most common creditors are providers, i.e. partners who send us a purchase invoice (which we did not yet pay).

>>> ses.show(ledger.Creditors, column_names="partner partner_id balance")
===================== ========= ==============
 Partner               ID        Balance
--------------------- --------- --------------
 Bestbank              100       42,90
 Rumma & Ko OÜ         101       141,60
 Bäckerei Ausdemwald   102       608,20
 Bäckerei Mießen       103       1 214,40
 Bäckerei Schmitz      104       3 272,98
 Garage Mergelsberg    105       143,40
 Donderweer BV         106       204,40
 **Total (7 rows)**    **721**   **5 627,88**
===================== ========= ==============

(Currently not tested because the only example is a sales invoice for 101 in 2014-01 which is already paid. need to adapt some fixture to getmore cases) Partner 101 from above list is both a supplier and a customer: Note that most numbers in above table are negative. A purchase invoice is a credit received from the provider, and we asked a list of debts by partner.

>>> obj = contacts.Partner.objects.get(pk=101)
>>> ses.show(ledger.DebtsByPartner, obj)
===================== ============ ========================= ==========================
 Due date              Balance      Debts                     Payments
--------------------- ------------ ------------------------- --------------------------
 04/01/2016            -141,30                                `PRC 2/2016 <Detail>`__
 08/01/2016            2 039,82     `SLS 2/2016 <Detail>`__
 04/02/2016            -142,00                                `PRC 9/2016 <Detail>`__
 04/03/2016            -143,40                                `PRC 16/2016 <Detail>`__
 04/04/2016            -142,10                                `PRC 23/2016 <Detail>`__
 04/05/2016            -140,20                                `PRC 30/2016 <Detail>`__
 04/06/2016            -141,30                                `PRC 37/2016 <Detail>`__
 04/07/2016            -142,00                                `PRC 44/2016 <Detail>`__
 04/08/2016            -143,40                                `PRC 51/2016 <Detail>`__
 04/09/2016            -142,10                                `PRC 58/2016 <Detail>`__
 04/10/2016            -140,20                                `PRC 65/2016 <Detail>`__
 04/11/2016            -141,30                                `PRC 72/2016 <Detail>`__
 04/12/2016            -142,00                                `PRC 79/2016 <Detail>`__
 04/01/2017            -144,80                                `PRC 2/2017 <Detail>`__
 04/02/2017            -143,50                                `PRC 9/2017 <Detail>`__
 04/03/2017            -141,60                                `PRC 16/2017 <Detail>`__
 **Total (16 rows)**   **-91,38**
===================== ============ ========================= ==========================

Fiscal years

Lino has a table of fiscal years. A fiscal year often corresponds to the calendar year, but not necessarily.

If lino_xl.lib.sheets is installed, the detail window of a FiscalYear object shows the financial reports (balance sheet and income statement) for this year.

class lino_xl.lib.ledger.FiscalYear
class lino_xl.lib.ledger.FiscalYears

The fiscal years available in this database.

The lino_xl.lib.ledger.fixtures.std fixture fills this table with 5 years starting from start_year.

>>> dd.plugins.ledger.start_year
>>> dd.today()
datetime.date(2015, 3, 12)
>>> dd.today().year + 5
>>> rt.show(ledger.FiscalYears)
=========== ============ ============ =======
 Reference   Start date   End date     State
----------- ------------ ------------ -------
 2014        01/01/2014   31/12/2014   Open
 2015        01/01/2015   31/12/2015   Open
 2016        01/01/2016   31/12/2016   Open
 2017        01/01/2017   31/12/2017   Open
 2018        01/01/2018   31/12/2018   Open
 2019        01/01/2019   31/12/2019   Open
 2020        01/01/2020   31/12/2020   Open
=========== ============ ============ =======

Accounting periods

Each ledger movement happens in a given accounting period. An accounting period usually corresponds to a month of the calendar. Accounting periods are automatically created the first time they are needed by some operation.

>>> rt.show(ledger.AccountingPeriods)
=========== ============ ============ ============= ======= ========
 Reference   Start date   End date     Fiscal year   State   Remark
----------- ------------ ------------ ------------- ------- --------
 2014-01     01/01/2014   31/01/2014   2014          Open
 2014-02     01/02/2014   28/02/2014   2014          Open
 2014-03     01/03/2014   31/03/2014   2014          Open
 2014-04     01/04/2014   30/04/2014   2014          Open
 2014-05     01/05/2014   31/05/2014   2014          Open
 2014-06     01/06/2014   30/06/2014   2014          Open
 2014-07     01/07/2014   31/07/2014   2014          Open
 2014-08     01/08/2014   31/08/2014   2014          Open
 2014-09     01/09/2014   30/09/2014   2014          Open
 2014-10     01/10/2014   31/10/2014   2014          Open
 2014-11     01/11/2014   30/11/2014   2014          Open
 2014-12     01/12/2014   31/12/2014   2014          Open
 2015-01     01/01/2015   31/01/2015   2015          Open
 2015-02     01/02/2015   28/02/2015   2015          Open
 2015-03     01/03/2015   31/03/2015   2015          Open
 2015-12     01/12/2015   31/12/2015   2015          Open
=========== ============ ============ ============= ======= ========

The reference of a new accounting period is computed by applying the voucher's entry date to the template defined in the date_to_period_tpl attribute of the ledger plugin. The default implementation leads to the following references:

>>> print(ledger.AccountingPeriod.get_ref_for_date(i2d(19940202)))
>>> print(ledger.AccountingPeriod.get_ref_for_date(i2d(20150228)))
>>> print(ledger.AccountingPeriod.get_ref_for_date(i2d(20150401)))

You may manually create additional accounting periods. For example

  • 2015-00 might stand for a fictive "opening" period before January 2015 and after December 2014.

  • 2015-13 might stand for January 2016 in a company which is changing their fiscal year from "January-December" to "July-June".

Payment terms

>>> rt.show('ledger.PaymentTerms')
==================== ==================================== ==================================== ======================================= ======== ========= ============== =================
 Reference            Designation                          Designation (fr)                     Designation (en)                        Months   Days      End of month   Worker
-------------------- ------------------------------------ ------------------------------------ --------------------------------------- -------- --------- -------------- -----------------
 07                   Zahlung sieben Tage Rechnungsdatum   Zahlung sieben Tage Rechnungsdatum   Payment seven days after invoice date   0        7         No
 10                   Zahlung zehn Tage Rechnungsdatum     Zahlung zehn Tage Rechnungsdatum     Payment ten days after invoice date     0        10        No
 30                   Zahlung 30 Tage Rechnungsdatum       Zahlung 30 Tage Rechnungsdatum       Payment 30 days after invoice date      0        30        No
 60                   Zahlung 60 Tage Rechnungsdatum       Zahlung 60 Tage Rechnungsdatum       Payment 60 days after invoice date      0        60        No
 90                   Zahlung 90 Tage Rechnungsdatum       Zahlung 90 Tage Rechnungsdatum       Payment 90 days after invoice date      0        90        No
 EOM                  Zahlung Monatsende                   Zahlung Monatsende                   Payment end of month                    0        0         Yes
 P30                  Anzahlung 30%                        Anzahlung 30%                        Prepayment 30%                          0        30        No
 PIA                  Vorauszahlung                        Vorauszahlung                        Payment in advance                      0        0         No
 robin                Cash Robin                           Cash Robin                           Cash Robin                              0        0         No             Mr Robin Dubois
 **Total (9 rows)**                                                                                                                     **0**    **227**
==================== ==================================== ==================================== ======================================= ======== ========= ============== =================

Journal groups

class lino_xl.lib.ledger.JournalGroup

The name of another plugin

For each journal group there will be a menu item in the main menu.

If the journal group has a menu_group, then journals are added to the menu of the named plugin, otherwise to the menu of the ledger plugin.

class lino_xl.lib.ledger.JournalGroups

The list of possible journal groups.

This list is used to build the main menu. Journals whose journal_group is empty will not be available through the main user menu. See also JournalGroup.menu_group.

The default configuration defines the following journal groups:

>>> rt.show(ledger.JournalGroups)
======= =========== ============================
 value   name        text
------- ----------- ----------------------------
 10      sales       Sales
 20      purchases   Purchases
 30      wages       Wages
 40      financial   Financial
 50      vat         VAT
 60      misc        Miscellaneous transactions
======= =========== ============================

For sales journals.


For purchases journals.


For wages journals.


For financial journals (bank statements and cash reports)

class lino_xl.lib.ledger.PeriodStates

The list of possible states of an accounting period.


Voucher types

The ledger plugin defines a list of voucher types, a choicelist that is populated by other plugins like lino_xl.lib.vat, lino_xl.lib.sales or lino_xl.lib.orders who define some subclass of Voucher and then must "register" that model to be used by one or several voucher types.

Every journal must have its voucher type, configured in the journal's voucher_type field. Several journals may share a same voucher type. The voucher type of a journal must not change as long as the journal has at least one voucher.

class lino_xl.lib.ledger.VoucherTypes

The list of voucher types available in this application.

Each item is an instances of VoucherType.

class lino_xl.lib.ledger.VoucherType

Base class for all items of VoucherTypes.

The voucher type defines the database model used to store vouchers of this type (model).

In more complex cases the application developer can define more than one voucher type per model by providing alternative tables (views) for it.


The database model used to store vouchers of this type. A subclass of lino_xl.lib.ledger.models.Voucher`.


Must be a table on model having master_key set to the journal.

class lino_xl.lib.ledger.VoucherState

Base class for items of VoucherStates.


Whether a voucher in this state is editable.

class lino_xl.lib.ledger.VoucherStates

The list of possible states of a voucher.

In a default configuration, vouchers can be draft, registered, cancelled or signed.

>>> rt.show(ledger.VoucherStates)
======= ============ ============ ==========
 value   name         text         Editable
------- ------------ ------------ ----------
 10      draft        Draft        Yes
 20      registered   Registered   No
 30      signed       Signed       No
 40      cancelled    Cancelled    No
======= ============ ============ ==========

Draft vouchers can be modified but are not yet visible as movements in the ledger.


Registered vouchers cannot be modified, but are visible as movements in the ledger.


Cancelled is similar to Draft, except that you cannot edit the fields. This is used for invoices which have been sent, but the customer signaled that they doen't agree. Instead of writing a credit nota, you can decide to just cancel the invoice.


The Signed state is similar to registered, but cannot usually be deregistered anymore. This state is not visible in the default configuration. In order to make it usable, you must define a custom workflow for VoucherStates.

Model mixins

class lino_xl.lib.ledger.SequencedVoucherItem

A VoucherItem which also inherits from lino.mixins.sequenced.Sequenced.

class lino_xl.lib.ledger.AccountVoucherItem

Abstract base class for voucher items which point to an account.

This is also a SequencedVoucherItem.

This is subclassed by lino_xl.lib.vat.models.InvoiceItem and lino_xl.lib.vatless.models.InvoiceItem.

It defines the account field and some related methods.


ForeignKey pointing to the account (ledger.Account) that is to be moved.

class lino_xl.lib.ledger.VoucherItem

Base class for items of a voucher.

Subclasses must define the following fields:


Pointer to the voucher which contains this item. Non nullable. The voucher must be a subclass of ledger.Voucher. The related_name must be 'items'.


The title of this voucher.

Currently (because of Django ticket #19465), this field is not implemented here but in the subclasses:

lino_xl.lib.vat.models.AccountInvoice lino_xl.lib.vat.models.InvoiceItem

class lino_xl.lib.ledger.Matching

Model mixin for database objects that are considered matching transactions. A matching transaction is a transaction that points to some other movement which it "clears" at least partially.

A movement is cleared when its amount equals the sum of all matching movements.

Adds a field match and a chooser for it. Requires a field partner. The default implementation of the chooser for match requires a journal.

Base class for lino_xl.lib.vat.AccountInvoice (and e.g. lino_xl.lib.sales.Invoice, lino_xl.lib.finan.DocItem)


Pointer to the movement which is being cleared by this movement.

class lino_xl.lib.ledger.PartnerRelated

Base class for things that are related to one and only one trade partner. This is base class for both (1) trade document vouchers (e.g. invoices or offers) and (2) for the individual entries of financial vouchers and ledger movements.


The recipient of this document. A pointer to lino_xl.lib.contacts.models.Partner.


The payment terms to be used in this document. A pointer to PaymentTerm.


Alias for the partner

class lino_xl.lib.ledger.ProjectRelated

Model mixin for objects that are related to a project.


Pointer to the "project". This field exists only if the project_model setting is nonempty.

class lino_xl.lib.ledger.Payable

Model mixin for objects that represent a payable transaction.

Inherits from PartnerRelated.


See lino_xl.lib.ledger.mixins.PartnerRelated.payment_term


A char field with a description for this transaction.


To be implemented by subclasses. Expected to return a dict which maps 4-tuples (acc_tuple, project, vat_class, vat_regime) to the payable amount. acc_tuple is itself a tuple (general_account, analytic_account), vat_class is a lino_xl.lib.vat.VatClasses choice and vat_regime a lino_xl.lib.vat.VatRegimes choice.


Implements lino_xl.lib.ledger.Voucher.get_wanted_movements().

class lino_xl.lib.ledger.PeriodRange

Model mixin for objects that cover a range of accounting periods.


The first period of the range to cover.


The last period of the range to cover.

Leave empty if you want only one period (specified in start_period). If this is non-empty, all periods between and including these two are covered.

get_period_filter(self, voucher_prefix, **kwargs)
class lino_xl.lib.ledger.PeriodRangeObservable

Model mixin for objects that can be filtered by a range of accounting periods. This adds two parameter fields start_period and end_period to every table on this model.

Class attribute:

observable_period_field = 'accounting_period'

The name of the database field on the observed model to use for filtering.

class lino_xl.lib.ledger.ItemsByVoucher

Shows the items of this voucher.

This is used as base class for slave tables in lino_xl.lib.finan, lino_xl.lib.vat, lino_xl.lib.vatless, lino_xl.lib.ana, ...

Filtering partners regarding ledger movements

The ledger plugin adds a choice has_open_movements to the observed_events parameter field of the lino_xl.lib.contacts.Partners table.

Show only companies that have at least one open ledger movement:

>>> pv = dict(observed_event=rt.models.contacts.PartnerEvents.has_open_movements)
>>> rt.login("robin").show(contacts.Companies, param_values=pv)
===================== ===================================================== ================ ======= ===== ===== ==========
 Name                  Address                                               e-mail address   Phone   GSM   ID    Language
--------------------- ----------------------------------------------------- ---------------- ------- ----- ----- ----------
 Bestbank                                                                                                   100
 Bäckerei Ausdemwald   Vervierser Straße 45, 4700 Eupen                                                     102
 Bäckerei Mießen       Gospert 103, 4700 Eupen                                                              103
 Bäckerei Schmitz      Aachener Straße 53, 4700 Eupen                                                       104
 Donderweer BV         Edisonstraat 12, 4816 AR Breda, Netherlands                                          106
 Garage Mergelsberg    Hauptstraße 13, 4730 Raeren                                                          105
 Rumma & Ko OÜ         Uus tn 1, Vigala vald, 78003 Rapla maakond, Estonia                                  101
===================== ===================================================== ================ ======= ===== ===== ==========
>>> settings.SITE.the_demo_date
datetime.date(2015, 3, 12)
>>> pv['start_date'] = i2d(20141231)
>>> rt.login("robin").show(contacts.Companies, param_values=pv)
===================== ===================================================== ================ ======= ===== ===== ==========
 Name                  Address                                               e-mail address   Phone   GSM   ID    Language
--------------------- ----------------------------------------------------- ---------------- ------- ----- ----- ----------
 Bestbank                                                                                                   100
 Bäckerei Ausdemwald   Vervierser Straße 45, 4700 Eupen                                                     102
 Bäckerei Mießen       Gospert 103, 4700 Eupen                                                              103
 Bäckerei Schmitz      Aachener Straße 53, 4700 Eupen                                                       104
 Donderweer BV         Edisonstraat 12, 4816 AR Breda, Netherlands                                          106
 Garage Mergelsberg    Hauptstraße 13, 4730 Raeren                                                          105
 Rumma & Ko OÜ         Uus tn 1, Vigala vald, 78003 Rapla maakond, Estonia                                  101
===================== ===================================================== ================ ======= ===== ===== ==========
>>> pv['start_date'] = i2d(20151231)
>>> rt.login("robin").show(contacts.Companies, param_values=pv)
No data to display


class lino_xl.lib.ledger.DueMovement

A volatile object representing a group of matching movements.

A due movement is a movement which a partner should do in order to clear their debt. Or which we should do in order to clear our debt towards a partner.

The "matching" movements of a given movement are those whose match, partner and account fields have the same values.

These movements are themselves grouped into "debts" and "payments". A "debt" increases the debt and a "payment" decreases it.


The common match string of these movments


Whether I mean my debts and payments (towards that partner) or those of the partner (towards me).

lino_xl.lib.ledger.get_due_movements(dc, flt)

Generates a series of DueMovement objects which --if they were booked-- would clear the movements given by the filter condition flt.

There will be at most one DueMovement per (account, partner, project, match), each of them grouping the movements with same partner, account, project and match.

This is the data source for ExpectedMovements and subclasses.

The balances of the DueMovement objects will be positive or negative depending on the specified dc.



(boolean): The target booking direction, i.e. which direction should be considered positive. Open movements in the opposite direction will be negative.


Optional filter arguments to give to Django's filter() method in order to specifiy which Movement objects to consider.

lino_xl.lib.ledger.check_clearings(qs, matches=[])

Check whether involved movements are cleared or not, and update their cleared field accordingly.

lino_xl.lib.ledger.check_clearings_by_account(account, matches=[])

Call check_clearings() for the given ledger account.

lino_xl.lib.ledger.check_clearings_by_partner(partner, matches=[])

Call check_clearings() for the given partner.

Plugin attributes

See lino_xl.lib.ledger.Plugin.


class lino_xl.lib.ledger.AccountBalances

A table which shows a list of general ledger accounts during the observed period, showing their old and new balances and the sum of debit and credit movements.

class lino_xl.lib.ledger.AccountingPeriodRange

A parameter panel with two fields:


Start of observed period range.


Optional end of observed period range. Leave empty to consider only the Start period.

The Y2K problem

Lino supports accounting across milleniums.

>>> FiscalYear = rt.models.ledger.FiscalYear
>>> print(FiscalYear.year2ref(1985))
>>> print(FiscalYear.year2ref(9985))

But there are legacy systems where the year was internally represented using a two-letter code.

The fix_y2k is either True or False.

>>> dd.plugins.ledger.fix_y2k
>>> dd.plugins.ledger.fix_y2k = True
>>> print(FiscalYear.year2ref(1985))
>>> print(FiscalYear.year2ref(1999))
>>> print(FiscalYear.year2ref(2000))
>>> print(FiscalYear.year2ref(2015))
>>> print(FiscalYear.year2ref(2135))
>>> print(FiscalYear.year2ref(2259))
>>> print(FiscalYear.year2ref(2260))

The on_ledger_movement signal


Custom signal sent when a partner has had at least one change in a ledger movement.

  • sender the database model

  • instance the partner

Don't read me

Until 20181016 it was not possible to manually reverse the sort order of a virtual field having a sortable_by which contained itself a reversed field. The Movement.credit field is an example:

>>> rmu(ledger.Movement.get_data_elem('credit').sortable_by)
['-amount', 'value_date']
>>> par = contacts.Partner.objects.get(pk=109)
>>> rt.show(ledger.MovementsByPartner, par, nosummary=True)
============ =============== ================================================== ============ ============ ================= =========
 Value date   Voucher         Description                                        Debit        Credit       Match             Cleared
------------ --------------- -------------------------------------------------- ------------ ------------ ----------------- ---------
 21/04/2014   *BNK 4/2014*    *(4000) Customers* | *Bernd Brechts Bücherladen*                19,36        **SLS 10/2014**   Yes
 21/03/2014   *BNK 3/2014*    *(4000) Customers* | *Bernd Brechts Bücherladen*                367,84       **SLS 10/2014**   Yes
 07/03/2014   *SLS 10/2014*   *(4000) Customers*                                 387,20                    **SLS 10/2014**   Yes
                              **Balance 0.00 (3 movements)**                     **387,20**   **387,20**
============ =============== ================================================== ============ ============ ================= =========
>>> mt = contenttypes.ContentType.objects.get_for_model(par.__class__).pk
>>> url = "api/ledger/MovementsByPartner?fmt=json&mk={}&mt={}".format(par.pk, mt)
>>> args = ('count rows no_data_text success title param_values', 3)
>>> demo_get('robin', url + "&sort=credit&dir=ASC", *args)

The following failed before 20181016:

>>> demo_get('robin', url + "&sort=credit&dir=DESC", *args)



Defines the body text of a payment reminder.


Defines the body text of a payment reminder.

Generating counter-entries

A payment order generates counter entries

If you want Lino to suggest the cleaning of payment orders when entering bank statements, then create a an organization (contacts.Company) representing your bank and have the Journal.partner field point to that partner.

Note that the journal must also have an account with Account.needs_partner enabled in order to prevent Lino from generating detailed counter-entries (one per item). Clearing a payment order makes sense only when the counter-entry is the sum of all movements.