contacts : Managing contacts

The lino_xl.lib.contacts plugin adds functionality for managing contacts. It adss the concept of partner with two specializations person and organization. Also adds roles of a person in an organization.

A tested document

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

>>> import lino
>>> lino.startup('lino_book.projects.min1.settings.doctests')
>>> from lino.api.doctest import *
>>> from django.db.models import Q


Natural person

A really existing person with a first and last name.

Represented by Person.

A corporation, company or organization.

Represented by Organization.

Database structure

This plugin defines the following database models.

  • The main models are Person and Company and their common base Partner. The Partner model is not abstract, i.e. you can see a table where persons organizations are together.

  • A Role is when a given person has a given function in a given company.

  • A RoleType ("Function") where you can configure the available functions.

  • A CompanyType model can be used to classify companies.


This plugin needs lino_xl.lib.countries and lino.modlib.system.

This plugin is being extended by Lino Welfare in lino_welfare.modlib.contacts or by Lino Voga in lino_voga.modlib.contacts.


==== ============= ================== =====================
 ID   Designation   Designation (de)   Designation (fr)
---- ------------- ------------------ ---------------------
 1    Manager       Geschäftsführer    Gérant
 2    Director      Direktor           Directeur
 3    Secretary     Sekretär           Secrétaire
 4    IT Manager    EDV-Manager        Gérant informatique
 5    President     Präsident          Président
==== ============= ================== =====================


A Partner is any physical or moral person for which you want to keep contact data (address, phone numbers, ...).

A partner can act as the recipient of a sales invoice, as the sender of an incoming purchases invoice, ...

A partner has at least a name and usually also an "official" address.

Predefined subclasses of Partners are Person for physical persons and Company for companies, organisations and any kind of non-formal Partners.

class lino_xl.lib.contacts.Partner

The Django model used to represent a partner.


The full name of this partner. Used for alphabetic sorting.

Subclasses may hide this field and fill it automatically, e.g. saving a Person will automatically set her name field to "last_name, first_name".


An optional name prefix. For organisations this is inserted before the name, for persons this is inserted between first name and last name.

See lino.mixins.human.Human.get_last_name_prefix().


The primary email address.


The primary phone number.

Note that Lino does not ignore formatting characters in phone numbers when searching. For example, if you enter "087/12.34.56" as a phone number, then a search for phone number containing "1234" will not find it.


The primary mobile phone number.


The language to use when communicating with this partner.


The general account to suggest as default value in purchase invoices from this partner.

This field exists only when lino_xl.lib.ledger is installed. It is defined as the invoice_account_field_name for TradeTypes.purchases.

Two fields exist only when lino_xl.lib.vat is installed:


The default VAT regime to use on invoices for this partner.


The national VAT identification number of this partner.


class lino_xl.lib.contacts.Persons

Shows all persons.

class lino_xl.lib.contacts.Person

A physical person and an individual human being. See also The Human mixin.



class lino_xl.lib.contacts.Company

An organisation. The verbose name is "Organization" while the internal name is "Company" because the latter easier to type and for historical reasons.


Pointer to the CompanyType.

The following fields are defined in the base model Partner, they are what companies and persons have in common:

class lino_xl.lib.contacts.Companies

Base table for all tables showing companies.

Quickly finding a partner using its primary key

A special type of quick search is when the search string starts with "#". In that case you get the partner with that primary key.

>>>, quick_search="#123", column_names="name phone id")
====================== ======= =====
 Name                   Phone   ID
---------------------- ------- -----
 Dobbelstein Dorothée           123
====================== ======= =====

This behaviour is the same for all subclasses of Partner, e.g. for persons and for organizations.

>>>, quick_search="berg")
=================== ============================= ================ ======= ===== ===== ==========
 Name                Address                       e-mail address   Phone   GSM   ID    Language
------------------- ----------------------------- ---------------- ------- ----- ----- ----------
 Mr Hans Altenberg   Aachener Straße, 4700 Eupen                                  114
=================== ============================= ================ ======= ===== ===== ==========
>>>, quick_search="berg")
==================== ============================= ================ ======= ===== ===== ==========
 Name                 Address                       e-mail address   Phone   GSM   ID    Language
-------------------- ----------------------------- ---------------- ------- ----- ----- ----------
 Garage Mergelsberg   Hauptstraße 13, 4730 Raeren                                  104
==================== ============================= ================ ======= ===== ===== ==========

Exporting contacts as vcard files

class lino_xl.lib.contacts.ExportVCardFile

Download all records as a .vcf file which you can import to another contacts application.

This action exists on every list of partners when your application has use_vcard_export set to True.


class lino_xl.lib.contacts.Plugin

The verbose_name of the region field.


Whether to define two additional fields Role.start_date and Role.end_date.


Whether Lino should provide a button for exporting contact data as a vcf file.

If you set this to True, then you must install vobject into your Python environment:

pip install vobject

User roles

class lino_xl.lib.contacts.SimpleContactsUser

A user who has access to basic contacts functionality.

class lino_xl.lib.contacts.ContactsUser

A user who has access to full contacts functionality.

class lino_xl.lib.contacts.ContactsStaff

A user who can configure contacts functionality.

Filtering partners

class lino_xl.lib.contacts.PartnerEvents

A choicelist of observable partner events.


See Filtering partners regarding ledger movements in ledger: General accounting. This choice exists only when lino_xl.lib.ledger is installed.

Other models

class lino_xl.lib.contacts.CompanyTypes
class lino_xl.lib.contacts.CompanyType

A type of organization. Used by Company.type field.

class lino_xl.lib.contacts.RoleType

A function (RoleType) is what a given Person can be in a given Company.

TODO: rename "RoleType" to "Function" or "ContactType".


A translatable designation. Used e.g. in document templates for contracts.

class lino_xl.lib.contacts.Role

A role is when a given person exercises a given function (ContactType) in a given organization.


The organization where this person has this role.


The function of this person in this organization.


The person having this role in this organization.

This is a learning foreign key. See Automatically creating contact persons


When this person started to exercise this function in this organization.

This is a dummy field when Plugin.with_roles_history is False.


When this person stopped to exercise this function in this organization.

This is a dummy field when Plugin.with_roles_history is False.

class lino_xl.lib.contacts.ContactRelated

Model mixin for things that relate to either a private person or a company, the latter potentially represented by a contact person having a given role in that company. Typical usages are invoices or contracts.

Adds 3 database fields and two virtual fields.


Pointer to Company.


Pointer to Person.


The optional Role of the contact_person within company.


(Virtual field) The "legal partner", i.e. usually the company, except when that field is empty, in which case partner contains the contact_person. If both fields are empty, then partner contains None.


(Virtual field) The Addressable object to use when printing a postal address for this. This is typically either the company or contact_person (if one of these fields is non-empty). It may also be a lino_xl.lib.contacts.models.Role object.

Difference between partner and recipient: an invoice can be issued and addressed to a given person in a company (i.e. a Role object), but accountants want to know the juristic person, which is either the company or a private person (if no company specified), but not a combination of both.

class lino_xl.lib.contacts.PartnerDocument

Deprecated. Adds two fields 'partner' and 'person' to this model, making it something that refers to a "partner". person means a "contact person" for the partner.

Civil state

>>> from lino_xl.lib.contacts.choicelists import CivilStates
>>> show_choicelist(CivilStates)
======= ==================== ==================== ============================= =============================
 value   name                 en                   de                            fr
------- -------------------- -------------------- ----------------------------- -----------------------------
 10      single               Single               Ledig                         célibataire
 20      married              Married              Verheiratet                   marié
 30      widowed              Widowed              Verwitwet                     veuf/veuve
 40      divorced             Divorced             Geschieden                    divorcé
 50      separated            Separated            Getrennt von Tisch und Bett   Séparé de corps et de biens
 51      separated_de_facto   De facto separated   Faktisch getrennt             Séparé de fait
 60      cohabitating         Cohabitating         Zusammenwohnend               Cohabitant
======= ==================== ==================== ============================= =============================
class lino_xl.lib.contacts.CivilStates

The global list of civil states that a person can have. The field pointing to this list is usually named civil_state.

Usage examples are lino_welfare.modlib.pcsw.models.Client> and lino_tera.lib.tera.Client> and lino_avanti.lib.avanti.Client> .

The four official civil states according to Belgian law are:


célibataire : vous n’avez pas de partenaire auquel vous êtes officiellement lié


marié(e) : vous êtes légalement marié


veuf (veuve) / Verwitwet : vous êtes légalement marié mais votre partenaire est décédé


divorcé(e) (Geschieden) : votre mariage a été juridiquement dissolu

Some institutions define additional civil states for people who are officially still married but at different degrees of separation:


De facto separated (Séparé de fait, faktisch getrennt)

Des conjoints sont séparés de fait lorsqu'ils ne respectent plus le devoir de cohabitation. Leur mariage n'est cependant pas dissous.

La notion de séparation de fait n'est pas définie par la loi. Toutefois, le droit en tient compte dans différents domaines, par exemple en matière fiscale ou en matière de sécurité sociale (assurance maladie invalidité, allocations familiales, chômage, pension, accidents du travail, maladies professionnelles).


Legally separated, aka "Separated as to property" (Séparé de corps et de biens, Getrennt von Tisch und Bett)

La séparation de corps et de biens est une procédure judiciaire qui, sans dissoudre le mariage, réduit les droits et devoirs réciproques des conjoints. Le devoir de cohabitation est supprimé. Les biens sont séparés. Les impôts sont perçus de la même manière que dans le cas d'un divorce. Cette procédure est devenue très rare.

Another unofficial civil state (but relevant in certain situations) is:


Cohabitating (cohabitant, zusammenlebend)

Vous habitez avec votre partenaire et c’est reconnu légalement.

Sources for above:,,

Automatically creating contact persons

The Role.person field in the RolesByCompany table is a Learning foreign key field: if you type the name of a person that does not yet exist in the database, Lino creates it silently.

Some examples of how the name is parsed when creating a person:

>>> pprint(rt.models.contacts.Person.parse_to_dict("joe smith"))
{'first_name': 'Joe', 'last_name': 'Smith'}
>>> pprint(rt.models.contacts.Person.parse_to_dict("Joe W. Smith"))
{'first_name': 'Joe W.', 'last_name': 'Smith'}
>>> pprint(rt.models.contacts.Person.parse_to_dict("Joe"))
Traceback (most recent call last):
django.core.exceptions.ValidationError: ['Cannot find first and last name in "Joe"']
>>> pprint(rt.models.contacts.Person.parse_to_dict("Guido van Rossum"))
{'first_name': 'Guido', 'last_name': 'van Rossum'}

The algorithm has already some basic intelligence but plenty of growing potential...