Welcome | Get started | Dive into Lino | Contribute | Topics | Reference | More
invoicing
(Invoicing in Noi)¶
This page is a tested document and the following instructions are used for initialization:
>>> import lino
>>> lino.startup('lino_book.projects.noi1r.settings')
>>> from lino.api.doctest import *
Overview¶
Subscriptions generate one invoice per year or month. Each invoice
for a same customer has the same amount. Sessions generate service reports,
which are just internal delivery notes, not invoices. Fillers monitor the
time credit of customers and generate an invoice to buy new credit when needed.
And the first invoice generator, lino_xl.lib.trading.InvoiceItem
, is not
used.
>>> rt.show(ledger.JournalsOverview)
**60 Sales invoices (SLS)**
**8 Subscription invoices (SUB)**
**55 Service reports (SRV)**
**5 Service Level Agreements (SLA)**
>>> rt.show('invoicing.Tasks')
...
===== ============ ============================= ===================================== =============== ========== =========== =======================
No. Author Target journal Invoice generators Logging level Disabled When Status
----- ------------ ----------------------------- ------------------------------------- --------------- ---------- ----------- -----------------------
1 Robin Rood Service reports (SRV) working.Session INFO No Every day Scheduled to run asap
2 Robin Rood Sales invoices (SLS) storage.Filler, trading.InvoiceItem INFO No Every day Scheduled to run asap
3 Robin Rood Subscription invoices (SUB) subscriptions.SubscriptionPeriod INFO No Every day Scheduled to run asap
===== ============ ============================= ===================================== =============== ========== =========== =======================
These are the invoice generators in Noi:
>>> pprint(rt.models_by_base(invoicing.InvoiceGenerator))
[<class 'lino_xl.lib.storage.models.Filler'>,
<class 'lino_xl.lib.subscriptions.models.SubscriptionPeriod'>,
<class 'lino_xl.lib.trading.models.InvoiceItem'>,
<class 'lino_xl.lib.working.models.Session'>]
Note that the reporting
area should run one day before the default
area.
Subscription invoices get created based on the subscription periods (which in turn get created as summary data of the actual subscriptions one per year or month).
Sales invoices get created based on service reports and storage fillers.
Service reports get created based on working sessions.
>>> rt.show('invoicing.FollowUpRules')
===== ====================================================== ===================== ================
No. Invoicing task Invoice generator Source journal
----- ------------------------------------------------------ --------------------- ----------------
1 Invoicing task #1 (Make Service reports (SRV)) Session
2 Invoicing task #3 (Make Subscription invoices (SUB)) Subscription period
3 Invoicing task #2 (Make Sales invoices (SLS)) Storage filler
4 Invoicing task #2 (Make Sales invoices (SLS)) Sales invoice item
===== ====================================================== ===================== ================
#5386 (detail link on a ledger movement causes traceback)¶
>>> obj = rt.models.trading.VatProductInvoice.objects.filter(partner=100).last()
>>> obj
VatProductInvoice #123 ('SLS 11/2015')
>>> obj.partner
Partner #100 ('Rumma & Ko OÜ')
>>> rt.show('trading.ItemsByInvoice', obj)
==================== ======================================== ========== ============ =========== ================= ==========================================
Product Heading Discount Unit price Quantity Total excl. VAT Invoiced object
-------------------- ---------------------------------------- ---------- ------------ ----------- ----------------- ------------------------------------------
Filler Rumma & Ko OÜ Purchased Regular *Filler Rumma & Ko OÜ Purchased Regular*
Regular Regular 60,00 35:26 2 126,00
**Total (2 rows)** **35:26** **2 126,00**
==================== ======================================== ========== ============ =========== ================= ==========================================
>>> ar = rt.login("robin")
>>> rnd = settings.SITE.kernel.default_renderer
The default table for a trading.VatProductInvoice
is
trading.Invoices
:
>>> obj.__class__.get_default_table()
lino_xl.lib.trading.ui.Invoices
Until 20240116, the detail_link of an invoice pointed to
trading.InvoicesByJournal
because the detail_layout to use depends on
the journal's voucher type. The following cases are skipped:
>>> print(tostring(rnd.obj2html(ar, obj)))
...
<a href="javascript:window.App.runAction({ "actorId":
"trading.InvoicesByJournal", "an": "detail",
"rp": null, "status": { "record_id": 113 } })">SLS
11/2015</a>
>>> print(rnd.obj2url(ar, obj))
javascript:window.App.runAction({ "actorId": "trading.InvoicesByJournal", "an": "detail", "rp": null, "status": { "record_id": 113 } })
>>> obj.get_detail_action(ar)
<BoundAction(trading.InvoicesByJournal, <lino.core.actions.ShowDetail detail ('Detail')>)>
Workaround was to deactivate Voucher.get_detail_action()
:
>>> print(tostring(rnd.obj2html(ar, obj)))
...
<a href="javascript:window.App.runAction({ "actorId": "trading.Invoices", "an": "detail", "rp": null, "status": { "record_id": 123 } })" style="text-decoration:none">SLS 11/2015</a>
>>> print(rnd.obj2url(ar, obj))
javascript:window.App.runAction({ "actorId": "trading.Invoices", "an": "detail", "rp": null, "status": { "record_id": 123 } })
>>> obj.get_detail_action(ar)
<BoundAction(trading.Invoices, <lino.core.actions.ShowDetail detail ('Detail')>)>
>>> for wm in obj.get_wanted_movements():
... print(wm.__class__, wm.product)
<class 'lino_xl.lib.storage.models.Movement'> Regular
<class 'lino_xl.lib.ledger.models.Movement'> None
<class 'lino_xl.lib.ledger.models.Movement'> None