Welcome | Get started | Dive | Contribute | Topics | Reference | Changes | More

cosi3 : A Lino Così for Estonia

This demo project shows a Lino Così site for a small company in Estonia.

It uses lino_xl.lib.eevat, the VAT plugin for Estonia. It imports every place in Estonia from commondata.ee. It also shows invoices with a customized page_background_image

This project is also the first to demonstrate the lino_xl.lib.assets plugin.

This page also shows that the translations to Estonian need some work, they are less than 95% finished.

This page contains code snippets (lines starting with >>>), which are being tested during our development workflow. The following snippet initializes the demo project used throughout this page.

>>> from lino_book.projects.cosi3.startup import *
>>> ses = rt.login("rando")
>>> dd.translation.activate('et')
>>> dd.plugins.weasyprint.page_background_image
'...lino_book/projects/cosi3/config/weasyprint/page-background.png'
>>> dd.plugins.vat.declaration_plugin
'lino_xl.lib.eevat'
>>> settings.SITE.with_assets
True
>>> rt.models.trading.InvoiceItem.asset.field.verbose_name
'License plate'

Places in Estonia

The Estonian Wikipedia says:

Rapla maakonnas on 10 omavalitsusüksust (valda):

Juuru vald - Järvakandi vald - Kaiu vald - Kehtna vald - Kohila vald - Käru vald - Märjamaa vald - Raikküla vald - Rapla vald - Vigala vald

Lino and commondata.ee agree with this:

>>> raplamaa = countries.Place.objects.get(
...    name="Rapla", type=countries.PlaceTypes.county)
>>> ses.show("countries.PlacesByPlace", raplamaa)
==================== =========== ==========
 Asum                 Asumiliik   zip code
-------------------- ----------- ----------
 `Juuru <…>`__        Vald
 `Järvakandi <…>`__   Vald
 `Kaiu <…>`__         Vald
 `Kehtna <…>`__       Vald
 `Kohila <…>`__       Vald
 `Käru <…>`__         Vald
 `Märjamaa <…>`__     Vald
 `Raikküla <…>`__     Vald
 `Rapla <…>`__        Linn
 `Vigala <…>`__       Vald
==================== =========== ==========

Another test is the municipality of Juuru for which Wikipedia announces one small borough and 14 villages:

Juuru vallas on üks alevik (Juuru, elanikke 597) ja 14 küla: Atla (91), Helda, Hõreda (80), Härgla (84), Jaluse (40), Järlepa (235), Kalda, Lõiuse (103), Mahtra (99), Maidla (124), Orguse (43), Pirgu (102), Sadala ja Vankse (30).

Lino and commondata again agree with this:

>>> juuru = countries.Place.objects.get(name="Juuru",
...    type=countries.PlaceTypes.municipality)
>>> ses.show("countries.PlacesByPlace", juuru)
================= =========== ==========
 Asum              Asumiliik   zip code
----------------- ----------- ----------
 `Atla <…>`__      Küla        79403
 `Helda <…>`__     Küla        79417
 `Härgla <…>`__    Küla        79404
 `Hõreda <…>`__    Küla        79010
 `Jaluse <…>`__    Küla        79410
 `Juuru <…>`__     Alevik
 `Järlepa <…>`__   Küla
 `Kalda <…>`__     Küla        79418
 `Lõiuse <…>`__    Küla        79405
 `Mahtra <…>`__    Küla        79407
 `Orguse <…>`__    Küla
 `Pirgu <…>`__     Küla
 `Sadala <…>`__    Küla        79419
 `Vankse <…>`__    Küla        79406
================= =========== ==========

Formatting postal addresses

The country is being printed in the address, depends on the country_code setting.

>>> rmu(dd.plugins.countries.country_code)
'EE'
>>> dd.plugins.countries.get_my_country()
Country #EE ('Eesti')
>>> eesti = countries.Country.objects.get(isocode="EE")
>>> sindi = countries.Place.objects.get(name="Sindi")
>>> p = contacts.Person(first_name="Malle", last_name="Mets",
...     street="Männi tn", street_no="5", street_box="-6",
...     zip_code="86705", country=eesti, city=sindi)
>>> print(p.address)
Malle Mets
Männi tn 5-6
86705 Sindi

Townships in Estonia get special handling: their name is replaced by the town’s name when a zip code is known:

>>> city = countries.Place.objects.get(name="Kesklinn")
>>> print(city)
Kesklinn
>>> city.type
<countries.PlaceTypes.township:55>
>>> p = contacts.Person(first_name="Kati", last_name="Kask",
...     street="Tartu mnt", street_no="71", street_box="-5",
...     zip_code="10115", country=eesti, city=city)
>>> print(p.address)
Kati Kask
Tartu mnt 71-5
10115 Tallinn

And yet another rule for countryside addresses:

>>> city = countries.Place.objects.get(name="Vana-Vigala")
>>> city.type
<countries.PlaceTypes.village:70>
>>> p = contacts.Person(first_name="Kati", last_name="Kask",
...     street="Hirvepargi", street_no="123",
...     zip_code="78003", country=eesti, city=city)
>>> print(p.address)
Kati Kask
Hirvepargi 123
Vana-Vigala küla
Vigala vald
78003 Rapla maakond

Some examples for customizing the trading plugin

The cosi3 demo project has a customized items_column_names for its ItemsByInvoice table, which uses absolute instead of relative discounts. It also shows how to use lino.core.model.Model.update_field() change the number of decimal positions of a price field.

The settings.py file says:

def get_plugin_configs(self):
    ...
    yield ("trading", "items_column_names",
           "product unit_price qty discount_amount {TOTAL} invoiceable *")

def do_site_startup(self):
    # change the number of decimal places from 4 to 2:
    update_field = self.models.trading.InvoiceItem.update_field
    update_field('unit_price', decimal_places=2)
    update_field('total_base', decimal_places=2)
    ...

Result:

>>> dd.plugins.trading.items_column_names
'product asset qty {TOTAL} discount_amount unit_price invoiceable *'
>>> # obj = trading.VatProductInvoice.objects.filter(partner=1).last()
>>> obj = trading.VatProductInvoice.objects.last()
>>> obj
VatProductInvoice #208 ('SLS 25/2024')
>>> obj.partner
Partner #76 ('Heinsalu Ivo')
>>> rt.show('trading.ItemsByInvoice', obj)
==================== ======= ======== ================ ============= ======== ========
 Toode                Plate   Qty      TotIncl          Allahindlus   UPr      InvObj
-------------------- ------- -------- ---------------- ------------- -------- --------
 Laud metallist               10       1 299,9000                     129,99
 == Vahesumma ==              10       1 299,9000
 Tool metallist               8        639,9200                       79,99
 Majutus 1MB/s                4        15,9600                        3,99
 == Vahesumma ==              12       655,8800
 **Kokku (5 rida)**           **44**   **3 911,5600**
==================== ======= ======== ================ ============= ======== ========

Parent layouts

Lino has a utility function lino.api.doctest.show_parent_layouts():

>>> show_parent_layouts()
======================================== ===================
 name                                     parent layout
---------------------------------------- -------------------
 countries.PlacesByPlace                  countries.Places
 contacts.PartnersByCity                  countries.Places
 accounting.MovementsByPartner            contacts.Partners
 accounting.MovementsByProject            contacts.Partners
 sepa.AccountsByPartner                   contacts.Partners
 vat.VouchersByPartner                    contacts.Partners
 vat.MovementsByVoucher                   trading.Invoices
 trading.ItemsByInvoice                   trading.Invoices
 trading.ItemsByInvoicePrint              trading.Invoices
 trading.ItemsByInvoicePrintNoQtyColumn   trading.Invoices
 trading.InvoicesByPartner                contacts.Partners
 assets.AssetsByPartner                   contacts.Partners
======================================== ===================

The idea was introduced to implement customizable column_names for the items of an invoice. We then didn’t use it but thought that the idea itself deserves further exploration.