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 amount 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 amount 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      Summa          Allahindlus   UPr      InvObj
-------------------- ------- -------- -------------- ------------- -------- --------
 Laud metallist               10       1 299,90                     129,99
 == Vahesumma ==              10       1 299,90
 Tool metallist               8        639,92                       79,99
 Majutus 1MB/s                4        15,96                        3,99
 == Vahesumma ==              12       655,88
 **Kokku (5 rida)**           **44**   **3 911,56**
==================== ======= ======== ============== ============= ======== ========

Parent layouts

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

>>> show_parent_layouts()
======================================== =========================
 actor                                    is used in
---------------------------------------- -------------------------
 accounting.MatchRulesByJournal           accounting.Journals
 accounting.MovementsByAccount            accounting.Accounts
 accounting.MovementsByPartner            contacts.Partners
 accounting.MovementsByProject            contacts.Partners
 accounting.MovementsByVoucher            finan.BankStatements
 assets.AssetsByPartner                   contacts.Partners
 checkdata.MessagesByChecker              checkdata.Checkers
 contacts.PartnersByCity                  countries.Places
 contacts.RolesByCompany                  contacts.Companies
 contacts.RolesByPerson                   contacts.Persons
 countries.PlacesByCountry                countries.Countries
 countries.PlacesByPlace                  countries.Places
 excerpts.ExcerptsByType                  excerpts.ExcerptTypes
 finan.ItemsByBankStatement               finan.BankStatements
 finan.ItemsByJournalEntry                finan.FinancialVouchers
 finan.ItemsByPaymentOrder                finan.PaymentOrders
 gfks.BrokenGFKsByModel                   gfks.ContentTypes
 invoicing.ItemsByPlan                    invoicing.Plans
 invoicing.RulesByTask                    invoicing.Tasks
 products.ProductsByCategory              products.Categories
 sepa.AccountsByPartner                   contacts.Partners
 sheets.MovementsByItemEntry              sheets.ItemEntries
 trading.InvoiceItemsByProduct            products.BaseProducts
 trading.InvoicesByPartner                contacts.Partners
 trading.ItemsByInvoice                   trading.Invoices
 trading.ItemsByInvoicePrint              trading.Invoices
 trading.ItemsByInvoicePrintNoQtyColumn   trading.Invoices
 trading.RulesByPartner                   contacts.Companies
 uploads.UploadsByController              finan.BankStatements
 uploads.UploadsByType                    uploads.UploadTypes
 uploads.UploadsByVolume                  uploads.Volumes
 users.AuthoritiesGiven                   users.Users
 users.AuthoritiesTaken                   users.Users
 vat.ItemsByInvoice                       vat.Invoices
 vat.MovementsByDeclaration               eevat.Declarations
 vat.MovementsByVoucher                   vat.Invoices
 vat.PurchasesByDeclaration               eevat.Declarations
 vat.SalesByDeclaration                   eevat.Declarations
 vat.VouchersByPartner                    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.