Welcome | Get started | Dive | Contribute | Topics | Reference | Changes | More
Calendar functionality in Lino Voga¶
This document describes how Lino Voga extends the default calendar functions (documented separately in cal : Calendar functionality).
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.
>>> from lino import startup
>>> startup('lino_book.projects.voga2.settings')
>>> from lino.api.doctest import *
Workflow¶
The following workflow of calendar entries and guests (presences) are
defined in lino_voga.lib.cal.workflows
.
>>> 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
======= ============ ============ ============= ============= ======== ============= =========
>>> 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 ☒
======= =========== ============ =========== =============
Rooms¶
- class lino_voga.lib.cal.Room¶
Extends
lino_xl.lib.cal.Room
by adding one field:- fee¶
The default fee to pay when renting this room to an external organization.
>>> show_fields(cal.Room, 'name calendar fee company')
- Designation (name) : The designation of the room. This is not required to be unique.
- Calendar (calendar) : Calendar where events in this room are published.
- Fee (fee) : The default fee to pay when renting this room to an external organization.
- Responsible (company) : Pointer to Company.
The following rooms are defined in the
lino_book.projects.voga2.settings.fixtures.voga
demo fixture.
>>> ses = rt.login('robin')
>>> ses.show(cal.Rooms)
================= ================== ===================== ================= =================== ============================= ==============================
Designation Designation (de) Designation (fr) Calendar Fee Responsible Locality
----------------- ------------------ --------------------- ----------------- ------------------- ----------------------------- ------------------------------
Mirrored room Spiegelsaal Salle miroîtée Mirrored room Spiegelraum Eupen Lern- und Begegnungszentrum 4700 Eupen
Computer room Computersaal Salle informatique Computer room Rent per meeting Lern- und Begegnungszentrum 4700 Eupen
Conference room Konferenzsaal Salle de conférence Conference room Lern- und Begegnungszentrum 4750 Butgenbach / Bütgenbach
Computer room Computersaal Salle informatique Computer room Lern- und Begegnungszentrum 4750 Butgenbach / Bütgenbach
Computer room Computersaal Salle informatique Computer room Zur Klüüs 4720 Kelmis / La Calamine
Computer room Computersaal Salle informatique Computer room Sport- und Freizeitzentrum 4780 Sankt Vith / Saint-Vith
Outside Draußen Outside Outside
================= ================== ===================== ================= =================== ============================= ==============================
(The last room, because it has no company, caused a bug that was fixed on 2014-09-20)
Automatic calender events¶
For the following examples we select an activity that did not yet start, i.e.
that starts after today
.
>>> for obj in courses.Course.objects.filter(start_date__gte=dd.today()):
... print("Activity #{} starts {} and has {} events".format(obj.id, obj.start_date, obj.max_events))
...
Activity #12 starts 2015-07-11 and has 10 events
Activity #13 starts 2015-07-11 and has 10 events
Activity #14 starts 2015-07-11 and has 10 events
Activity #15 starts 2015-07-11 and has 10 events
Activity #16 starts 2015-07-11 and has 10 events
Activity #17 starts 2015-07-11 and has 10 events
Activity #26 starts 2015-06-19 and has 5 events
Let’s take the first of them:
>>> obj = courses.Course.objects.get(pk=12)
>>> obj
Course #12 ('012 Rücken (Swimming)')
Repair from previous incomplete test runs if necessary.
>>> response = obj.do_update_events() >>> response['success'] True
>>> ses.show(cal.EntriesByController, obj, column_names="when_text state", nosummary=True)
======================== ===========
When State
------------------------ -----------
Mon 06/06/2016 (11:00) Suggested
Mon 30/05/2016 (11:00) Suggested
Mon 23/05/2016 (11:00) Suggested
Mon 09/05/2016 (11:00) Suggested
Mon 02/05/2016 (11:00) Suggested
Mon 25/04/2016 (11:00) Suggested
Mon 18/04/2016 (11:00) Suggested
Mon 11/04/2016 (11:00) Suggested
Mon 04/04/2016 (11:00) Suggested
Mon 21/03/2016 (11:00) Suggested
======================== ===========
We run the UpdateEvents
action a first
time and verify that the events remain unchanged (if the following fails, make
sure you’ve run inv prep
before running inv test
).
>>> set_log_level(logging.DEBUG)
>>> res = obj.do_update_events()
...
Run Update calendar for 012 Rücken (Swimming)...
Generating events between 2015-07-13 and 2020-05-22 (max. 10).
012 Hour 1 wants 2015-07-13 but conflicts with <QuerySet [Event #465 ('Activity #10 010C Hour 38')]>, moving to 2015-07-20.
...
0 row(s) have been updated.
>>> res['success']
True
>>> ses.show(cal.EntriesByController, obj, column_names="when_text summary state", nosummary=True)
======================== =================== ===========
When Short description State
------------------------ ------------------- -----------
Mon 06/06/2016 (11:00) 012 Hour 10 Suggested
Mon 30/05/2016 (11:00) 012 Hour 9 Suggested
Mon 23/05/2016 (11:00) 012 Hour 8 Suggested
Mon 09/05/2016 (11:00) 012 Hour 7 Suggested
Mon 02/05/2016 (11:00) 012 Hour 6 Suggested
Mon 25/04/2016 (11:00) 012 Hour 5 Suggested
Mon 18/04/2016 (11:00) 012 Hour 4 Suggested
Mon 11/04/2016 (11:00) 012 Hour 3 Suggested
Mon 04/04/2016 (11:00) 012 Hour 2 Suggested
Mon 21/03/2016 (11:00) 012 Hour 1 Suggested
======================== =================== ===========
We select the event no 4 (2013-12-23, 2016-04-18):
>>> qs = obj.get_existing_auto_events()
>>> e = qs.get(start_date=i2d(20160418))
Yes, the state is “suggested”:
>>> print(e.state)
Suggested
Now we move that event to the next available date (the week after in our case):
>>> response = e.move_next()
...
Run Move down for Activity #12 012 Hour 4...
Generating events between 2015-07-13 and 2020-05-22 (max. 10).
...
1 row(s) have been updated.
>>> response['success']
True
The state is now “draft”:
>>> print(e.state)
Draft
Note that all subsequent events have also been moved to their next available date.
>>> ses.show(cal.EntriesByController, obj, column_names="when_text summary state", nosummary=True)
======================== =================== ===========
When Short description State
------------------------ ------------------- -----------
Mon 13/06/2016 (11:00) 012 Hour 10 Suggested
Mon 06/06/2016 (11:00) 012 Hour 9 Suggested
Mon 30/05/2016 (11:00) 012 Hour 8 Suggested
Mon 23/05/2016 (11:00) 012 Hour 7 Suggested
Mon 09/05/2016 (11:00) 012 Hour 6 Suggested
Mon 02/05/2016 (11:00) 012 Hour 5 Suggested
Mon 25/04/2016 (11:00) 012 Hour 4 Draft
Mon 11/04/2016 (11:00) 012 Hour 3 Suggested
Mon 04/04/2016 (11:00) 012 Hour 2 Suggested
Mon 21/03/2016 (11:00) 012 Hour 1 Suggested
======================== =================== ===========
The state “Draft” is normal: it indicates that the event has been manually modified.
Note that 2016-05-16 is a holiday:
>>> cal.Event.objects.filter(start_date=i2d(20160516))
<QuerySet [Event #86 ('Recurring event #12 Pentecost')]>
A sortable virtual field¶
The when_text
field of a
calendar entry is sortable despite the fact that it is virtual.
>>> de = rt.models.cal.Events.get_data_elem('when_text')
>>> de.__class__
<class 'lino.core.fields.VirtualField'>
>>> rmu(de.sortable_by)
['start_date', 'start_time']
>>> de.return_type.__class__
<class 'lino.core.fields.DisplayField'>
>>> rmu(de.return_type.sortable_by)
['start_date', 'start_time']
>>> th = rt.models.cal.Events.get_handle()
>>> col = th.get_columns()[0]
>>> col.__class__
<class 'lino.core.elems.DisplayElement'>
>>> col.name
'when_text'
>>> rmu(col.field.sortable_by)
['start_date', 'start_time']
>>> col.sortable
True