Welcome | Get started | Dive | Contribute | Topics | Reference | Changes | More
Calendar functions in Lino Avanti¶
This document describes how standard calendar functionality is being extended by Lino Avanti.
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.avanti1.settings')
>>> from lino.api.doctest import *
Lino Avanti defines a plugin lino_avanti.lib.cal
that extends
lino_xl.lib.cal
.
- class lino_avanti.lib.cal.Guest¶
- absence_reason¶
Why the pupil was absent. Choices for this field are defined in
AbsenceReasons
.
Calendar workflow¶
It’s almost like lino_xl.lib.cal.workflows.voga
, except that the workflow
transition for presence state “excused” (GuestStates
) is customized.
It gives permission only when the course has “Excuses permitted” checked.
In existing data (until June 2018) the “excused” and “absent” states. In August
2018 we decided to no longer make this differentiation. In September 2024 we
partly re-introduced it for courses that have the new database field
can_excuse
checked.
>>> rt.show(cal.GuestStates)
======= =========== ============ =========== =============
value name Afterwards text Button text
------- ----------- ------------ ----------- -------------
10 invited No Invited ?
40 present Yes Present ☑
50 missing Yes Missing ☉
60 excused No Excused ⚕
90 cancelled No Cancelled ☒
======= =========== ============ =========== =============
>>> show_workflow(cal.GuestStates.workflow_actions)
============= ============== =========== ============== ===================================
Action name Verbose name Help text Target state Required states
------------- -------------- ----------- -------------- -----------------------------------
wf1 ☑ Present Present invited
wf2 ☉ Missing Missing invited
wf3 Excused Excused Excused invited
wf4 ? Invited Invited missing present excused cancelled
wf5 ☒ Cancelled Cancelled invited
============= ============== =========== ============== ===================================
>>> rt.show(cal.EntryStates)
======= ============ ============ ============= ============= ======== ============= =========
value name text Button text Fill guests Stable Transparent No auto
------- ------------ ------------ ------------- ------------- -------- ------------- ---------
10 suggested Suggested ? Yes No No No
20 draft Draft ☐ Yes No No No
50 took_place Took place ☑ No Yes No No
70 cancelled Cancelled ☒ No Yes Yes Yes
======= ============ ============ ============= ============= ======== ============= =========
>>> show_workflow(cal.EntryStates.workflow_actions)
============== ============== ============ ============== ================================
Action name Verbose name Help text Target state Required states
-------------- -------------- ------------ -------------- --------------------------------
reset_event Reset Suggested Suggested suggested took_place cancelled
wf2 ☐ Draft Draft suggested cancelled took_place
wf3 Took place Took place Took place suggested draft cancelled
cancel_entry Cancel Cancelled Cancelled suggested draft scheduled
============== ============== ============ ============== ================================
Choicelists¶
>>> base = '/choices/cal/Guests/partner'
>>> show_choices("rolf", base + '?query=')
ABAD Aábdeen (114/nathalie)
ABBASI Aáishá (118/romain)
ABDALLA Aádil (120/rolf)
ABDALLAH Aáish (127/robin)
ABDELLA Aákif (128/nathalie)
...
>>> show_choices("audrey", base + '?query=')
(114) from Eupen
(118) from Eupen
(120) from Eupen
(127) from Eupen
(128) from Eupen
(136) from Eupen
...
GuestsByPartner¶
GuestsByPartner
shows all presences except those in more than
one week and sorts them chronologically:
>>> obj = avanti.Client.objects.get(pk=115)
>>> rt.show(cal.GuestsByPartner, obj)
January 2017: *Mon 16.*☑ *Tue 17.*☑ *Thu 19.*☑ *Fri 20.*☑ *Mon 23.*☑ *Tue 24.*☑ *Thu 26.*☒ *Fri 27.*☑ *Mon 30.*☑ *Tue 31.*☑
February 2017: *Thu 02.*☑ *Fri 03.*☑ *Mon 06.*☑ *Tue 07.*☑ *Thu 09.*? *Fri 10.*? *Mon 13.*? *Tue 14.*? *Thu 16.*? *Fri 17.*? *Mon 20.*? *Tue 21.*?
Suggested : 8 , Draft : 0 , Took place : 13 , Cancelled : 1
Absence reasons¶
In Lino Avanti we record and analyze why pupils have been missing.
- class lino_avanti.lib.cal.AbsenceReasons¶
The table of possible absence reasons.
Accessible via
.>>> show_menu_path(cal.AbsenceReasons) Configure --> Calendar --> Absence reasons
>>> rt.show(cal.AbsenceReasons) ==== ==================== ========================== ==================== ID Designation Designation (de) Designation (fr) ---- -------------------- -------------------------- -------------------- 1 Sickness Krankheit Sickness 2 Other valid reason Sonstiger gültiger Grund Other valid reason 3 Unknown Unbekannt Inconnu 4 Unjustified Unberechtigt Unjustified ==== ==================== ========================== ====================
Courses with excuses¶
The following snippets show how the checkbox Allow excuses on a course influences the choices in the Workflow field when recording presences of participants. Participants in state “Invited” have either four workflow actions or only three because [⚕] is available only when Allow excuses is checked.
>>> ses = rt.login("robin")
>>> obj = cal.Event.objects.get(pk=193)
>>> obj
Event #193 ('Lesson 9 (30.01.2017 18:00)')
>>> obj.owner.can_excuse = True
>>> obj.owner.save()
>>> ses.show(cal.GuestsByEvent, master_instance=obj)
=================================== ======= ================================= ================ ========
Participant Role Workflow Absence reason Remark
----------------------------------- ------- --------------------------------- ---------------- --------
ABAD Aábdeen (114/nathalie) Pupil **? Invited** → [☑] [☉] [⚕] [☒]
ABDALLAH Aáish (127/robin) Pupil **☑ Present** → [?]
ABDELLA Aákif (128/nathalie) Pupil **☉ Missing** → [?]
ABDI Aátifá (136/rolf) Pupil **⚕ Excused** → [?]
ABDOU Abeer (143/nelly) Pupil **☒ Cancelled** → [?]
ABDULLA Abbáás (152/rolf) Pupil **? Invited** → [☑] [☉] [⚕] [☒]
ABDULLAH Afááf (155/robin) Pupil **☑ Present** → [?]
ABEZGAUZ Adrik (112/nelly) Pupil **☉ Missing** → [?]
ABOOD Abdul Fáttááh (163/rolf) Pupil **⚕ Excused** → [?]
ARSHAN Afimiá (132/nelly) Pupil **☒ Cancelled** → [?]
ARTEMIEVA Aloyshá (139/rolf) Pupil **? Invited** → [☑] [☉] [⚕] [☒]
BAH Aráli (119/nelly) Pupil **☑ Present** → [?]
BEK-MURZIN Agápiiá (160/romain) Pupil **☉ Missing** → [?]
DEMEULENAERE Dorothée (121/nelly) Pupil **⚕ Excused** → [?]
FOFANA Denzel (147/romain) Pupil **☒ Cancelled** → [?]
=================================== ======= ================================= ================ ========
>>> obj.owner.can_excuse = False
>>> obj.owner.save()
>>> ses.show(cal.GuestsByEvent, master_instance=obj)
=================================== ======= ============================= ================ ========
Participant Role Workflow Absence reason Remark
----------------------------------- ------- ----------------------------- ---------------- --------
ABAD Aábdeen (114/nathalie) Pupil **? Invited** → [☑] [☉] [☒]
ABDALLAH Aáish (127/robin) Pupil **☑ Present** → [?]
ABDELLA Aákif (128/nathalie) Pupil **☉ Missing** → [?]
ABDI Aátifá (136/rolf) Pupil **⚕ Excused** → [?]
ABDOU Abeer (143/nelly) Pupil **☒ Cancelled** → [?]
ABDULLA Abbáás (152/rolf) Pupil **? Invited** → [☑] [☉] [☒]
ABDULLAH Afááf (155/robin) Pupil **☑ Present** → [?]
ABEZGAUZ Adrik (112/nelly) Pupil **☉ Missing** → [?]
ABOOD Abdul Fáttááh (163/rolf) Pupil **⚕ Excused** → [?]
ARSHAN Afimiá (132/nelly) Pupil **☒ Cancelled** → [?]
ARTEMIEVA Aloyshá (139/rolf) Pupil **? Invited** → [☑] [☉] [☒]
BAH Aráli (119/nelly) Pupil **☑ Present** → [?]
BEK-MURZIN Agápiiá (160/romain) Pupil **☉ Missing** → [?]
DEMEULENAERE Dorothée (121/nelly) Pupil **⚕ Excused** → [?]
FOFANA Denzel (147/romain) Pupil **☒ Cancelled** → [?]
=================================== ======= ============================= ================ ========
Don’t read on¶
>>> print(cal.Event.objects.get(pk=123))
Ash Wednesday (01.03.2017)
>>> test_client.force_login(rt.login('robin').user)
>>> def mytest(k):
... url = 'http://127.0.0.1:8000/api/cal/MyEntries/{}'.format(k)
... # url = 'http://127.0.0.1:8000/#/api/cal/Entries/{}'.format(k)
... res = test_client.get(url, REMOTE_USER='robin')
... print(res)
... # assert res.status_code == 200
... # print(res.content)
>>> mytest("123")
Not Found: /api/cal/MyEntries/123
<HttpResponseNotFound status_code=404, "text/html; charset=utf-8">
Until 20241004 the result was a traceback:
Traceback (most recent call last):
...
AttributeError: 'Renderer' object has no attribute 'html_page'
>>> url = '/choices/cal/Events?query=¹'
>>> res = test_client.get(url, REMOTE_USER='robin')
>>> assert res.status_code == 200
>>> res.content
b'{ "count": 0, "rows": [ ] }'