vat : Adding VAT (Value-added tax) functionality

The lino_xl.lib.vat plug-in adds functionality for handling sales and purchase invoices in a context where the site operator is subject to value-added tax (VAT). It also installs a framework for handling VAT declaratations.


The VAT plug-in defines the following concepts:

When using this plugin, you must also specify one of the national VAT implementations.

A tested document

This is a tested document. The following instructions are used for initialization:

>>> from lino import startup
>>> startup('lino_book.projects.pierre.settings.doctests')
>>> from lino.api.doctest import *

National VAT implementations

Applications using this plug-in must specify the national implementations for their VAT declarations by setting the declaration_plugin plugin attribute.

Currently we have three declaration plug-ins:

Accounting applications to be used by site operators who don't care about VAT might use lino_xl.lib.vatless instead (though this plug-in might become deprecated). The modules lino_xl.lib.vatless and lino_xl.lib.vat can theoretically both be installed though obviously this wouldn't make sense.

VAT regimes

A VAT regime must be assigned to each voucher and may optionally be assigned to each partner.

The VAT regime of a voucher influences how the VAT for this voucher is being handled, e.g. which VAT rates are available and whether and how VAT is to be declared and paid towards the national VAT office.

The VAT regime of a partner is used as the default value for all vouchers with this partner. When you define a default VAT regime per partner, any new voucher created for this partner will have this VAT regime. Existing vouchers are not changed when you change this field.

The available VAT regimes vary depending on which VAT declaration plugin is installed. See also Available VAT regimes. The list below is when no declaration module is installed, so we have only one default regime.

>>>, language="en")
======= ======== ======== ========== ============== ==========
 value   name     text     VAT area   Needs VAT id   item VAT
------- -------- -------- ---------- -------------- ----------
 10      normal   Normal              No             Yes
======= ======== ======== ========== ============== ==========

Note that the VAT regime does not depend on the trade type. For example, when a partner has the regime "Intra-community", this regime is used for both sales and purchase invoices with this partner. The difference between sales and purchases is defined by the VAT rules, not by the regime.

class lino_xl.lib.vat.VatRegime

Base class for the items of VatRegimes. Each VAT regime is an instance of this and has two properties:


In which VAT area this regime is available. See VatAreas.


Whether unit prices are VAT included or not.


Whether this VAT regime requires that partner to have a vat_id.

class lino_xl.lib.vat.VatRegimes

The global list of VAT regimes. Each item of this list is an instance of VatRegime.

Three VAT regimes are considered standard minimum:


Two additional regimes are defined in lino_xl.lib.bevat:


VAT classes

A VAT class is assigned to each product and to each item of an accounting invoice. The VAT class specifies how that product or invoice item behaves regarding to VAT, especially it influences the available rates. You can sell or purchase a same product to different partners using different VAT regimes.

>>>, language="en")
======= ========= ==================
 value   name      text
------- --------- ------------------
 0       exempt    Exempt from VAT
 1       reduced   Reduced VAT rate
 2       normal    Normal VAT rate
======= ========= ==================

A VAT class is a direct or indirect property of a trade object (e.g. a Product) and influences the VAT rate to be used. It does not contain the actual rate because this still varies depending on your country, the time and type of the operation, and possibly other factors.

class lino_xl.lib.vat.VatClasses

The global list of VAT classes.

Default classes are:


VAT rules

A VAT rule defines which VAT rate to apply and which account to use for a given combination of regime, class and trade type.

The available VAT rules vary depending on which VAT declaration plugin is installed. The list below is when no declaration module is installed, so we have only one default rule with no condition and zero rate.

>>>, language="en")
| value | Description      |
| 1     | VAT rule 1:      |
|       | apply 0 %        |
|       | and book to None |
class lino_xl.lib.vat.VatRule

A rule which defines how VAT is to be handled for a given invoice item.

Example data see lino_xl.lib.vat.fixtures.euvatrates.

Database fields:


The sequence number.


The regime for which this rule applies.

Pointer to VatRegimes.


The VAT rate to be applied. Note that a VAT rate of 20 percent is stored as 0.20 (not 20).


The general account where VAT is to be booked.


Whether VAT is returnable. Returnable VAT does not increase the total amount of the voucher but causes an additional movement into the vat_returnable_account. See About returnable VAT.


Where to book returnable VAT. If this field is empty and vat_returnable is True, then VAT will be added to the base account. See About returnable VAT.

get_vat_rule(cls, trade_type, vat_regime,
vat_class=None, country=None, date=None)

Return the VAT rule to be applied for the given criteria.

Lino loops through all rules (ordered by their seqno) and returns the first object which matches.

class lino_xl.lib.vat.VatRules

The table of all VatRule objects.

This table is accessible via Explorer ‣ VAT ‣ VAT rules.

>>> show_menu_path(vat.VatRules, language='en')
Explorer --> VAT --> VAT rules

This table is filled by

VAT areas

A VAT area is a group of countries for which same VAT rules apply in the the country of the site owner.

>>>, language="en")
======= =============== ===============
 value   name            text
------- --------------- ---------------
 10      national        National
 20      eu              EU
 30      international   International
======= =============== ===============

The plugin property eu_country_codes defines which countries are considered part of the EU.

So the country field of a partner indirectly influences which VAT regimes are available this partner.

Available VAT regimes

The declaration plugin controls which VAT regimes are available for selection on a partner or on a voucher.

The list of available VAT regimes for a partner depends on the VAT area and on whether the partner has a VAT id or not.

get_vat_regime_choices(country=None, vat_id=None):

Used for the choosers of the vat_regime field of a partner and a voucher.

class lino_xl.lib.vat.VatAreas

The global list of VAT areas.

classmethod get_for_country(cls, country)

Return the VatArea instance for this country.

Why differentiate between VAT regimes and VAT classes?

You might ask why we use two sets of categories for specifying the VAT rate. Some other accounting programs do not have two different categories for the subtle difference between "exempt from VAT" and "VAT 0%", they have just a category "VAT rate" which you can set per invoice item (and a default value per provider).

The problem with this simplified vision is that at least for Belgian VAT declarations there is a big difference between having 0% of VAT because the provider is a private person and having 0% of VAT because you are buying post stamps or flight tickets (which are exempt from VAT).

Another thing to consider is that in Lino we want to be able to have partners who are both a provider and a customer. Their VAT regime remains the same for both trade types (sales and purchase) while the default VAT class to use in invoice items depends on the account or the product.

Accounting invoices

An accounting invoice is an invoice for which the user enters just the bare accounts and amounts. They are stored using the VatAccountInvoice model as voucher type. They are typically used to store incoming purchase invoices, and they do no not usually produce a printable document.

If you also need products, quantities and discounts, use a journal having VatProductInvoice as voucher type instead.

Accounting invoices are typically used to store incoming purchase invoices, but exceptions in both directions are possible: (1) purchase invoices can be stored using VatProductInvoice if stock management is important, or (2) outgoing sales invoice can be stored as VatAccountInvoice because they have been created using some external tool and are entered into Lino just for the general ledger.

There are two database models:

class lino_xl.lib.vat.VatAccountInvoice

Django model for storing accounting invoices.

class lino_xl.lib.vat.InvoiceItem

Django model for representing items of accounting invoices.

There are several views:

class lino_xl.lib.vat.Invoices

The table of all VatAccountInvoice objects.

class lino_xl.lib.vat.InvoicesByJournal

Shows all invoices of a given journal (whose voucher_type must be VatAccountInvoice)

class lino_xl.lib.vat.PrintableInvoicesByJournal

Purchase journal

class lino_xl.lib.vat.InvoiceDetail

The detail layout used by Invoices.

class lino_xl.lib.vat.ItemsByInvoice
class lino_xl.lib.vat.VouchersByPartner


The lino_xl.lib.vat.utils module contains some utility functions.

>>> from lino_xl.lib.vat.utils import add_vat, remove_vat
>>> add_vat(100, 21)
>>> remove_vat(121, 21)
>>> add_vat(10, 21)
>>> add_vat(1, 21)

Intracom sales and purchases

The plugin defines two reports accessible via the Reports ‣ Accounting menu and integrated in the printout of a VAT declaration:

class lino_xl.lib.vat.IntracomSales

Show a list of all sales invoices whose VAT regime is Intra-Community.

class lino_xl.lib.vat.IntracomPurchases

Show a list of all purchase invoices whose VAT regime is Intra-Community.

class lino_xl.lib.vat.IntracomInvoices

Common base class for IntracomSales and IntracomPurchases

These reports areempty when you have no national declaration plugin installed:

>>>, language='en')
No data to display
>>>, language='en')
No data to display

Model mixins

class lino_xl.lib.vat.VatTotal

Model mixin which defines the database fields total_incl, total_base and total_vat and some related behaviour.

Used for both the voucher (VatDocument) and for each item (VatItemBase).


The amount VAT included.


The amount VAT excluded.


The amount of VAT.

All three total fields are lino.core.fields.PriceField instances.

The fields are editable by default, but implementing models can call lino.core.fields.update_field() to change this behaviour. A model that sets all fields to non-editable should also set edit_totals to False.


Subclasses of VatTotal must implement this method.


Return the VAT rule for this voucher or voucher item. Called when user edits a total field in the document header when edit_totals is True.


Called when user has edited the total_base field. If total_base has been set to blank, then Lino fills it using reset_totals(). If user has entered a value, compute total_vat and total_incl from this value using the vat rate. If there is no VatRule, total_incl and total_vat are set to None.

If there are rounding differences, total_vat will get them.


Called when user has edited the total_vat field. If it has been set to blank, then Lino fills it using reset_totals(). If user has entered a value, compute total_incl. If there is no VatRule, total_incl is set to None.


Called when user has edited the total_incl field. If total_incl has been set to blank, then Lino fills it using reset_totals(). If user enters a value, compute total_base and total_vat from this value using the vat rate. If there is no VatRule, total_incl should be disabled, so this method will never be called.

If there are rounding differences, total_vat will get them.

class lino_xl.lib.vat.VatDocument

Abstract base class for invoices, offers and other vouchers.

Inherited by VatAccountInvoice as well as in other plugins (e.g. lino_xl.lib.sales.VatProductInvoice and lino_xl.lib.ana.AnaAccountInvoice).

Models that inherit this mixin can set the following class attribute:


Whether the user usually wants to edit the total amount or not.

The total fields of an invoice are not automatically updated each time an item is modified. Users must click the Σ ("Compute sums") button (or Save or the Register button) to see the invoice's totals.

Inherits the following database fields from VatTotal:


Adds the following database fields:


Pointer to a lino_xl.lib.ledger.Plugin.project_model.


Mandatory field to be defined in the implementing class.


An automatically managed boolean field which says whether the user has manually edited the items of this document. If this is False and edit_totals is True, Lino will automatically update the only invoice item according to partner and vat_regime and total_incl.


The VAT regime to be used in this document.

A pointer to VatRegimes.

Adds an action:


Calls ComputeSums for this document.

class lino_xl.lib.vat.ComputeSums

Compute the sum fields of a VatDocument based on its items.

Represented by a "Σ" button.

class lino_xl.lib.vat.VatItemBase

Model mixin for items of a VatDocument.

Abstract Base class for lino_xl.lib.ledger.InvoiceItem, i.e. the lines of invoices without unit prices and quantities.

Subclasses must define a field called "voucher" which must be a ForeignKey with related_name="items" to the "owning document", which in turn must be a subclass of VatDocument).


The VAT class to be applied for this item. A pointer to VatClasses.

get_vat_rule(self, tt)

Return the VatRule which applies for this item.

tt is the trade type (which is the same for each item of a voucher, that's why we expect the caller to provide it).

This basically calls the class method VatRule.get_vat_rule() with appropriate arguments.

When selling certain products ("automated digital services") in the EU, you have to pay VAT in the buyer's country at that country's VAT rate. See e.g. How can I comply with VAT obligations?.

TODO: Add a new attribute VatClass.buyers_country or a checkbox Product.buyers_country or some other way to specify this.

class lino_xl.lib.vat.QtyVatItemBase

Model mixin for items of a VatTotal. Extends VatItemBase by adding unit_price and qty.

Abstract Base class for lino_xl.lib.sales.InvoiceItem and lino_xl.lib.sales.OrderItem, i.e. invoice items with unit prices and quantities.


The unit price for this item.


Changing the unit_price ot the qty will automatically reset the total amount of this item: the value unit_price * qty will be stored in total_incl if VatRegime.item_vat is True, otherwise in total_base.

VAT columns

class lino_xl.lib.vat.VatColumns

The global list of VAT columns.

The VAT column of a ledger account indicates where the movements on this account are to be collected in VAT declarations.

VAT declarations

A VAT declaration is when a company declares to its government how much sales and purchases they've done during a given period.

A VAT declaration is a computed summary of ledger movements in an observed period, but it is also itself a ledger voucher which generates new movements in its own period.

class lino_xl.lib.vat.VatDeclaration

Abstract base class for VAT declarations.

lino_xl.lib.sepa.Payable lino_xl.lib.ledger.Voucher lino_xl.lib.excerpts.Certifiable lino_xl.lib.ledger.PeriodRange


Implements lino_xl.lib.sepa.Payable.get_payable_sums_dict().

As a side effect this updates values in the computed fields of this declaration.

class lino_xl.lib.vat.DeclarationField

Base class for all fields of VAT declarations.


An optional space-separated list of names of other declaration fields to be observed by this field.

class lino_xl.lib.vat.DeclarationFieldsBase


See also lino_xl.lib.vat.Plugin for configuration options.

Fill invoice items based on voucher's total

In a VatAccountInvoice users may edit the total amount of the invoice in order to have Lino assist them for filling invoice items based on this amount.

Manually editing the VAT amount of invoice items

Users can manually edit any amount of an invoice item.

When you enter a total_incl, Lino automatically computes the total_base and total_vat. But when entering data from a legacy system, you may want to manually specify a different VAT amount.


An electricity invoice of 94,88 €. Only 35% of the total amount is deductible.

  • Manually enter 94.88 in VatProductInvoice.total_incl. Lino fills one invoice item. The general account of this item is either the provider's purchase_account or (if that field is empty) lino_xl.lib.ledger.CommonAccounts.waiting.

  • Change the amount of the invoice item (total_incl) from 94.88 to 33.22 (94.88 * 0.35). Lino automatically sets total_base to 27.68 € (33.22 / 1.20) and total_vat to 5.54 (33.22 - 27.68).

  • Add a second line and manually set InvoiceItem.account to 600020 (Non deducible costs). Lino automatically fills the remaining amount (94.88 - 33.22 = 61.66) into the InvoiceItem.total_incl field and computes the other amounts of that line. Since account 600020 has vat_class set to exempt, the other amounts are set to blank.

About returnable VAT

VAT declaration

A voucher that expresses the fact that we submitted a VAT declaration to the national tax office.

Returnable VAT

A VAT amount in an invoice that is not to be paid to (or by) the partner but must be declared in the VAT declaration.

Returnable VAT, unlike normal VAT, does not increase the total amount of the voucher but causes an additional movement into the account configured as "VAT returnable" (a common account).

See also vat_returnable_account.