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

cosi2 : A Lino Così for Belgium (FR)

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.cosi2.startup import *
>>> ses = rt.login('robin')

Used in miscellaneous tested documents, e.g.

Miscellaneous

Because with_assets is False for cosi2, lino_xl.lib.trading.InvoiceItem.asset is a dummy field, which we can see by testing whether field is None.

>>> settings.SITE.with_assets
False
>>> print(rt.models.trading.InvoiceItem.asset.field)
None

Person #16 is not a Partner

Person #16 (‘Altenberg Hans’) is not a Partner (master_key is <django.db.models.fields.related.ForeignKey: partner>)

>>> url = '/bs3/contacts/Person/16'
>>> test_client.force_login(rt.login('robin').user)
>>> res = test_client.get(url, REMOTE_USER='robin')
>>> print(res.status_code)
200

Slave tables with more than 15 rows

When you look at the detail window of Belgium in Lino Così then you see a list of all places in Belgium. This demo database contains exactly 48 entries:

>>> be = countries.Country.objects.get(isocode="BE")
>>> be.place_set.count()
48
>>> countries.PlacesByCountry.create_request(be).get_total_count()
48
>>> url = '/api/countries/PlacesByCountry?fmt=json&start=0&mt=5&mk=BE'
>>> res = test_client.get(url,REMOTE_USER='robin')
>>> print(res.status_code)
200
>>> result = json.loads(res.content.decode('utf-8'))
>>> print(len(result['rows']))
15

The 15 is because Lino has a hard-coded default value of returning only 15 rows when no limit has been specified.

In versions after 2013-09-03 you can change that limit for a given table by overriding the preview_limit parameter of your table definition. Or you can change it globally for all your tables by setting the preview_limit Site attribute to either None or some bigger value.

This parameter existed before but wasn’t tested. In your code this would simply look like this:

class PlacesByCountry(Places):
    preview_limit = 30

Here we override it on the living object:

>>> countries.PlacesByCountry.preview_limit = 25

Same request returns now 25 data rows:

>>> res = test_client.get(url, REMOTE_USER='robin')
>>> result = json.loads(res.content.decode('utf-8'))
>>> print(len(result['rows']))
25

To remove the limit altogether, you can say:

>>> countries.PlacesByCountry.preview_limit = None

and the same request now returns all 49 data rows:

>>> res = test_client.get(url,REMOTE_USER='robin')
>>> result = json.loads(res.content.decode('utf-8'))
>>> print(len(result['rows']))
49

Invoices to emit

The cosi2 demo project showcases an approach used e.g. in petrol stations where customers pay upon delivery when they fill their tank, they want to have a single invoice at the end of the month where every delivery is mentioned, and the station is legally required to book their purchases and sales of petrol every day. Some customers have the privilege of needing to pay only at the end of the month when they receive the invoice.

Lino helps to manage this kind of situations by using an accounting concept called factures à établir. The site owner writes a single daily invoice to a fictive customer “Invoices to emit”. This daily invoice causes VAT to get booked and the daily turnover to sync with sales and purchases. At the end of the month we then send the actual invoices to the customers. These invoices don’t report about our business activity, they are only informative, we call them “informal”, they list the deliveries of the last month and just book the total turnover from “Invoices to emit” to the real customer.

Payment term A means: this is just an informative invoice and the customer has already paid upon delivery.

>>> obj = rt.models.trading.VatProductInvoice.objects.filter(payment_term__ref="A").first()
>>> obj
VatProductInvoice #9 ('SLS 9/2016')
>>> rt.show(accounting.MovementsByVoucher, obj)
================== =========================== ============ ============ ================ =========
 Account            Partner                     Debit        Credit       Match            Cleared
------------------ --------------------------- ------------ ------------ ---------------- ---------
 (4000) Customers   Bernd Brechts Bücherladen   815,96                    **SLS 9/2016**   Yes
 (4000) Customers   Bernd Brechts Bücherladen                815,96       **SLS 9/2016**   Yes
                                                **815,96**   **815,96**
================== =========================== ============ ============ ================ =========

Payment terms B means: this is just an informative invoice regarding VAT, but the customer still has to pay.

>>> obj = rt.models.trading.VatProductInvoice.objects.filter(payment_term__ref="B").first()
>>> obj
VatProductInvoice #10 ('SLS 10/2016')
>>> obj.payment_term.informal
True
>>> obj.payment_term.payer
Company #82 ('Invoices to emit')
>>> rt.show(accounting.MovementsByVoucher, obj)
=========================== ====================== ============ ============ ================= =========
 Account                     Partner                Debit        Credit       Match             Cleared
--------------------------- ---------------------- ------------ ------------ ----------------- ---------
 (4000) Customers            Reinhards Baumschule   320,00                    **SLS 10/2016**   No
 (4800) Internal clearings   Invoices to emit                    320,00       **SLS 10/2016**   No
                                                    **320,00**   **320,00**
=========================== ====================== ============ ============ ================= =========

The customer “Invoices to emit” is used to record internal clearing of invoices that have been paid at delivery. TODO: add monthly transaction to balance the invoices to emit.

>>> obj = contacts.Company.objects.get(name="Invoices to emit")
>>> obj
Company #82 ('Invoices to emit')
>>> rt.show(accounting.MovementsByPartner, obj, display_mode="grid")
============ ===================== ============================================================================================= ======= ============== ============= =========
 Value date   Voucher               Description                                                                                   Debit   Credit         Match         Cleared
------------ --------------------- --------------------------------------------------------------------------------------------- ------- -------------- ------------- ---------
 13/02/2017   `SLS 8/2017 <…>`__    `(4800) Internal clearings <…>`__ | `Blondeeuw Tristan <…>`__ | `Invoices to emit <…>`__              740,00         SLS 8/2017    No
 07/12/2016   `SLS 54/2016 <…>`__   `(4800) Internal clearings <…>`__ | `Beauve Marius <…>`__ | `Invoices to emit <…>`__                  770,00         SLS 54/2016   No
 07/10/2016   `SLS 43/2016 <…>`__   `(4800) Internal clearings <…>`__ | `Arquin Geoffroy <…>`__ | `Invoices to emit <…>`__                600,00         SLS 43/2016   No
 09/07/2016   `SLS 32/2016 <…>`__   `(4800) Internal clearings <…>`__ | `Alsteen Cyprien <…>`__ | `Invoices to emit <…>`__                670,00         SLS 32/2016   No
 09/05/2016   `SLS 21/2016 <…>`__   `(4800) Internal clearings <…>`__ | `Adriensence Anastase <…>`__ | `Invoices to emit <…>`__           990,00         SLS 21/2016   No
 07/03/2016   `SLS 10/2016 <…>`__   `(4800) Internal clearings <…>`__ | `Reinhards Baumschule <…>`__ | `Invoices to emit <…>`__           320,00         SLS 10/2016   No
                                    **Balance -4090.00 (6 movements)**                                                                    **4 090,00**
============ ===================== ============================================================================================= ======= ============== ============= =========