20130831 (Saturday, 31 August 2013)

Creating many invoices at once

Two days aga Roger asked “In faggio.sales.InvoicesToCreate, can’t you add me a button to create and print all invoices at once?” I answered “Yes that would be nice here, but don’t expect too much because Lino can’t yet do that”.

First I had to set cell_edit to False. That was easy, but I knew the real problem was that the AJAX call Lino.call_ajax_action in linoweb.js didn’t yet communicate to the server which rows were currently selected.

Well… now Lino can do it: The “Print” button of a CachedPrintable now transparently handles the case when multiple rows are selected. If multiple rows are selected (which continues to be possible only when cell_edit is True), then it will automatically build the printable cache for those objects who don’t yet have it built, then generate a single temporary pdf file which is simply a merge of these individual pdf documents.

A special challenge was the fact that the rows of a VirtualTable usually don’t have a primary key. Lino.call_ajax_action needs primary keys if we want it to communicate to the server which rows were currently selected.

And faggio.sales.InvoicesToCreate is a virtual table. But because this table groups invoiceables by partner and therefore will never display more than one row per partner, we can use the Partner id as a virtual primary key.

That’s why I added the new class methods lino.core.actors.Actor.get_pk_field() and lino.core.actors.Actor.get_row_by_pk()

Note also that faggio.sales.InvoicesToCreate overrides the original CachedPrintAction.

A new dependency

Note that the above changes created a new dependency: pyPdf. Updated /requirements.txt.

(According to his website, pyPdf’s original author Mathieu Fenniak has “stopped maintaining pyPdf, and a company named Phaseit has forked the project and continued development and maintenance with my blessing as pyPdf2”. But his latest version is still on PyPI and works well.)

Changed API of actions

I made a backwards incompatible change in Introduction to actions. Existing applications who define actions must change the signature of the miscellaneous run_from_ methods: the “selected row” is no longer passed as a first positional argument, but contained in a new selected_rows attribute of the ar argument.


def run_from_ui(self,obj,ar,**kw):


def run_from_ui(self,ar,**kw):
    obj = ar.selected_rows[0]

My apologies if this causes some work to others… though afaik not many people have written custom actions until now, and if you have, I guess that you agree that this signature was strange.


I continued a bit on the structure of the userdocs:

  • The actor directive works now best when called on a model (not a table).
  • New text role verbose_name.

Example application was the faggio.contacts page.