Welcome | Get started | Dive | Contribute | Topics | Reference | Changes | More
invoicing
(Invoicing in Noi)¶
Side note: Code snippets (lines starting with >>>
) in this document get
tested as part of our development workflow. The following
initialization snippet tells you which demo project is being used in
this document.
>>> import lino
>>> lino.startup('lino_book.projects.noi1r.settings')
>>> from lino.api.doctest import *
Overview¶
A subscription generates one invoice per year or month. Each invoice for a
same customer has the same amount. Working 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(accounting.JournalsOverview)
**39 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)) Working 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 #104 ('SLS 8/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 Hourly rate `Filler Rumma & Ko OÜ Purchased Hourly rate <…>`__
Hourly rate Hourly rate 60,00 15:34 934,00
**Total (2 rows)** **15:34** **934,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": 104 } })" style="text-decoration:none">SLS 8/2015</a>
>>> print(rnd.obj2url(ar, obj))
javascript:window.App.runAction({ "actorId": "trading.Invoices", "an": "detail", "rp": null, "status": { "record_id": 104 } })
>>> 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'> Hourly rate
<class 'lino_xl.lib.accounting.models.Movement'> None
<class 'lino_xl.lib.accounting.models.Movement'> None