Miscellaneous

A tested document

This is a tested document. The following instructions are used for initialization:

>>> from lino import startup
>>> startup('lino_welfare.projects.mathieu.settings.doctests')
>>> from lino.api.doctest import *
>>> ses = rt.login('rolf')

Default template for excerpts

Check whether Lino returns the right default template for excerpts.

In lino_xl.lib.excerpts we define a template excerpts/Default.odt, but lino_welfare.modlib.welfare overrides this template.

The rule is that the *last* plugin wins when Lino searches for templates.

This means that if we want to see the welfare-specific version, our get_installed_apps in lino_welare.projects.std.settings must yield lino_welfare.modlib.welfare after lino_xl.lib.excerpts.

The following test verifies this rule:

>>> print(settings.SITE.find_config_file('Default.odt', 'excerpts'))
... 
/.../welfare/config/excerpts/Default.odt

Editing the print template of an excerpt

Here we want to see what the EditTemplate action says, especially when called on an excerpt where Lino has two possible locations.

Note that we need a local config directory for the following test to work. On travis we use LINO_CACHE_ROOT, so there is no local config dir. That’s why this doctest must create one.

>>> lcd = settings.SITE.cache_dir.child('config')
>>> rt.makedirs_if_missing(lcd)

After having created the directory, we must tell Lino to scan the file system again:

>>> settings.SITE.confdirs.scan_config_dirs()
>>> settings.SITE.confdirs.LOCAL_CONFIG_DIR.writeable
True

Excerpts are printables with two template groups. A printable with several template groups will use the first one that exists, and will fail only if non of them exists. The first template group is given by the owner (e.g. “immersion/Contract”) and the second is just “excerpts”. For example the owner of Excerpt #2 is an immersion training, while the owner of Excerpt #4 is an aids confirmation:

>>> excerpts.Excerpt.objects.get(pk=2).get_template_groups() 
['immersion/Contract', 'excerpts']
>>> excerpts.Excerpt.objects.get(pk=4).get_template_groups() 
['aids/Confirmation', 'excerpts']

When creating a local copy of the factory template, Lino copies the factory file to the directory given by the first group. Before doing so, it will ask for user confirmation. The following code snippet partly tests this situation.

>>> obj = excerpts.Excerpt.objects.get(pk=2)
>>> obj.owner
Contract #2 ("Stage d'immersion#2 (Edgar ENGELS)")
>>> ses.set_confirm_answer(False)
>>> rv = ses.run(obj.edit_template)
>>> print(rv['info_message'])
... 
Gonna copy ...welfare/config/excerpts/Default.odt to .../config/immersion/Contract/Default.odt
>>> print(rv['message'])
...     
Before you can edit this template we must create a local copy on the server. This will exclude the template from future updates.
D'accord?

Another thing is the location of the factory template.

>>> obj = excerpts.Excerpt.objects.get(pk=1)
>>> ses.set_confirm_answer(False)
>>> rv = ses.run(obj.edit_template)
>>> print(rv['info_message'])
... 
Gonna copy .../lino_welfare/modlib/welfare/config/excerpts/Default.odt to .../config/immersion/Contract/Default.odt

Yet another series of GET requests

>>> ContentType = rt.models.contenttypes.ContentType
>>> json_fields = 'count rows title success no_data_text param_values'
>>> kw = dict(fmt='json', limit=10, start=0)
>>> demo_get('rolf', 'api/contacts/Companies', json_fields, 40, **kw)
>>> demo_get('rolf', 'api/households/Households', json_fields, 15, **kw)
>>> demo_get('rolf', 'api/contacts/Partners', json_fields, 163, **kw)
>>> demo_get('rolf', 'api/jobs/JobProviders', json_fields, 4, **kw)
>>> json_fields = 'count rows title success no_data_text'
>>> demo_get('rolf', 'api/countries/Countries', json_fields, 271, **kw)
>>> demo_get('rolf', 'api/jobs/Jobs', json_fields, 9, **kw)
>>> json_fields = 'count rows title success no_data_text param_values'
>>> demo_get('rolf', 'api/contacts/Persons', json_fields, 103, **kw)
>>> demo_get('rolf', 'api/pcsw/CoachedClients', json_fields, 30, **kw)
>>> demo_get('rolf', 'api/debts/Clients', json_fields, 0, **kw)
>>> demo_get('rolf', 'api/cal/MyEntries', json_fields, 9, **kw)
>>> demo_get('rolf', 'api/newcomers/NewClients', json_fields, 23, **kw)
>>> demo_get(
...    'rolf', 'api/newcomers/AvailableCoachesByClient', json_fields,
...    2, mt=50, mk=120, **kw)
>>> demo_get('alicia', 'api/integ/Clients', json_fields, 7, **kw)
>>> demo_get('hubert', 'api/integ/Clients', json_fields, 17, **kw)
>>> alicia = settings.SITE.user_model.objects.get(username='alicia')

Rolf working as Alicia:

>>> kw = dict(fmt='json', limit=20, start=0, su=alicia.pk)
>>> demo_get('rolf', 'api/integ/Clients', json_fields, 7, **kw)

Some choices lists:

>>> kw = dict()
>>> fields = 'count rows'
>>> demo_get(
...    'rolf', 'choices/clients/ContactsByClient/company?type=1', fields, 4, **kw)
>>> demo_get(
...    'rolf', 'choices/aids/IncomeConfirmations/aid_type', fields, 11, **kw)
>>> demo_get(
...    'rolf', 'choices/aids/RefundConfirmations/aid_type', fields, 11, **kw)
>>> demo_get(
...    'rolf', 'apchoices/pcsw/Clients/create_visit/user', fields, 4, **kw)
>>> demo_get(
...    'robin', 'choices/countries/Countries/actual_country', fields, 266, **kw)

Visibility of eID reader action

Here is a list of the tables that have the lino.modlib.beid.mixins.FindByBeIdAction and the user profiles that can see it.

>>> from lino_xl.lib.beid.mixins import FindByBeIdAction
>>> print(analyzer.show_action_permissions(FindByBeIdAction))
... 
- debts.Clients.find_by_beid : visible for 120 300 420 admin 910
- integ.Clients.find_by_beid : visible for 100 110 120 420 admin 910
- newcomers.ClientsByFaculty.find_by_beid : visible for 100 110 120 200 210 220 300 400 410 420 800 admin 910
- newcomers.NewClients.find_by_beid : visible for 120 200 220 300 420 admin 910
- pcsw.AllClients.find_by_beid : visible for 110 120 410 420 admin 910
- pcsw.Clients.find_by_beid : visible for 100 110 120 200 210 220 300 400 410 420 800 admin 910
- pcsw.ClientsByNationality.find_by_beid : visible for 100 110 120 200 210 220 300 400 410 420 800 admin 910
- pcsw.CoachedClients.find_by_beid : visible for 100 110 120 200 300 400 410 420 admin 910
- reception.Clients.find_by_beid : visible for 100 110 120 200 210 220 300 400 410 420 800 admin 910

Visibility of duplicate action

Here is a list of the tables that have the lino.mixins.duplicable.Duplicate and the user types that can see it.

>>> from lino.mixins.duplicable import Duplicate
>>> print(analyzer.show_action_permissions(Duplicate))
... 
- cal.AllEntries.duplicate : visible for admin 910
- cal.ConflictingEvents.duplicate : visible for 110 120 410 420 admin 910
- cal.EntriesByClient.duplicate : visible for 100 110 120 200 210 220 300 400 410 420 500 510 800 admin 910
- cal.EntriesByController.duplicate : visible for 100 110 120 200 210 220 300 400 410 420 500 510 800 admin 910
- cal.EntriesByDay.duplicate : visible for 100 110 120 200 210 220 300 400 410 420 500 510 800 admin 910
- cal.EntriesByGuest.duplicate : visible for 100 110 120 200 210 220 300 400 410 420 500 510 800 admin 910
- cal.EntriesByProject.duplicate : visible for 100 110 120 200 210 220 300 400 410 420 500 510 800 admin 910
- cal.EntriesByRoom.duplicate : visible for 110 120 410 420 admin 910
- cal.EntriesByType.duplicate : visible for 110 120 410 420 admin 910
- cal.EventTypes.duplicate : visible for 110 120 410 420 admin 910
- cal.Events.duplicate : visible for 110 120 410 420 admin 910
- cal.MyAssignedEvents.duplicate : visible for 100 110 120 200 300 400 410 420 500 510 admin 910
- cal.MyEntries.duplicate : visible for 100 110 120 200 300 400 410 420 500 510 admin 910
- cal.MyEntriesToday.duplicate : visible for 100 110 120 200 300 400 410 420 500 510 admin 910
- cal.MyOverdueAppointments.duplicate : visible for 100 110 120 200 300 400 410 420 500 510 admin 910
- cal.MyUnconfirmedAppointments.duplicate : visible for 100 110 120 200 300 400 410 420 500 510 admin 910
- cal.OneEvent.duplicate : visible for 100 110 120 200 210 220 300 400 410 420 500 510 800 admin 910
- cal.OverdueAppointments.duplicate : visible for 110 120 410 420 admin 910
- cal.PublicEntries.duplicate : visible for nobody
- cal.RemoteCalendars.duplicate : visible for 110 120 410 420 admin 910
- calview.DailyPlanner.duplicate : visible for 100 110 120 200 210 220 300 400 410 420 500 510 800 admin 910
- calview.DailyPlannerRows.duplicate : visible for 110 120 410 420 admin 910
- calview.DailySlave.duplicate : visible for 100 110 120 200 210 220 300 400 410 420 500 510 800 admin 910
- calview.WeeklySlave.duplicate : visible for 110 120 410 420 admin 910
- cbss.AllIdentifyPersonRequests.duplicate : visible for admin 910
- cbss.AllManageAccessRequests.duplicate : visible for admin 910
- cbss.AllRetrieveTIGroupsRequests.duplicate : visible for admin 910
- cbss.IdentifyPersonRequests.duplicate : visible for 100 110 120 200 210 300 400 410 420 admin 910
- cbss.IdentifyRequestsByPerson.duplicate : visible for 100 110 120 200 210 300 400 410 420 admin 910
- cbss.ManageAccessRequests.duplicate : visible for 100 110 120 200 210 300 400 410 420 admin 910
- cbss.ManageAccessRequestsByPerson.duplicate : visible for 100 110 120 200 210 300 400 410 420 admin 910
- cbss.MyIdentifyPersonRequests.duplicate : visible for 100 110 120 200 210 300 400 410 420 admin 910
- cbss.MyManageAccessRequests.duplicate : visible for 100 110 120 200 210 300 400 410 420 admin 910
- cbss.MyRetrieveTIGroupsRequests.duplicate : visible for 100 110 120 200 210 300 400 410 420 admin 910
- cbss.RetrieveTIGroupsRequests.duplicate : visible for 100 110 120 200 210 300 400 410 420 admin 910
- cbss.RetrieveTIGroupsRequestsByPerson.duplicate : visible for 100 110 120 200 210 300 400 410 420 admin 910
- clients.PartnersByClientContactType.duplicate : visible for 100 110 120 200 210 220 300 400 410 420 500 510 800 admin 910
- coachings.CoachingEndings.duplicate : visible for 110 120 210 410 420 admin 910
- contacts.Companies.duplicate : visible for 100 110 120 200 210 220 300 400 410 420 500 510 800 admin 910
- contacts.Partners.duplicate : visible for 100 110 120 200 210 220 300 400 410 420 500 510 800 admin 910
- contacts.PartnersByCity.duplicate : visible for 100 110 120 200 210 220 300 400 410 420 500 510 800 admin 910
- contacts.PartnersByCountry.duplicate : visible for 100 110 120 200 210 220 300 400 410 420 500 510 800 admin 910
- contacts.Persons.duplicate : visible for 100 110 120 200 210 220 300 400 410 420 500 510 800 admin 910
- countries.Places.duplicate : visible for 110 120 210 410 420 800 admin 910
- countries.PlacesByCountry.duplicate : visible for 100 110 120 200 210 220 300 400 410 420 500 510 800 admin 910
- countries.PlacesByPlace.duplicate : visible for 110 120 210 410 420 800 admin 910
- courses.ActiveActivities.duplicate : visible for 100 110 120 200 210 300 400 410 420 800 admin 910
- courses.Activities.duplicate : visible for 100 110 120 200 210 300 400 410 420 800 admin 910
- courses.ActivitiesByLayout.duplicate : visible for 100 110 120 200 210 300 400 410 420 800 admin 910
- courses.ActivitiesByLine.duplicate : visible for 100 110 120 200 210 300 400 410 420 800 admin 910
- courses.ActivitiesBySlot.duplicate : visible for 100 110 120 200 210 300 400 410 420 800 admin 910
- courses.ActivitiesByTeacher.duplicate : visible for 100 110 120 200 210 300 400 410 420 800 admin 910
- courses.ActivitiesByTopic.duplicate : visible for 100 110 120 200 210 300 400 410 420 800 admin 910
- courses.AllActivities.duplicate : visible for admin 910
- courses.ClosedActivities.duplicate : visible for 100 110 120 200 210 300 400 410 420 800 admin 910
- courses.DraftActivities.duplicate : visible for 100 110 120 200 210 300 400 410 420 800 admin 910
- courses.EntriesByTeacher.duplicate : visible for 110 120 410 420 admin 910
- courses.InactiveActivities.duplicate : visible for 100 110 120 200 210 300 400 410 420 800 admin 910
- courses.JobCourses.duplicate : visible for 100 110 120 200 210 300 400 410 420 800 admin 910
- courses.Lines.duplicate : visible for 100 110 120 200 210 300 400 410 420 800 admin 910
- courses.LinesByTopic.duplicate : visible for 100 110 120 200 210 300 400 410 420 800 admin 910
- courses.MyActivities.duplicate : visible for 100 110 120 200 210 300 400 410 420 800 admin 910
- courses.MyCoursesGiven.duplicate : visible for nobody
- courses.Slots.duplicate : visible for admin 910
- courses.Topics.duplicate : visible for admin 910
- cv.EducationLevels.duplicate : visible for 110 120 420 admin 910
- dashboard.AllWidgets.duplicate : visible for admin 910
- dashboard.Widgets.duplicate : visible for 100 110 120 200 210 220 300 400 410 420 500 510 800 admin 910
- dashboard.WidgetsByUser.duplicate : visible for 100 110 120 200 210 220 300 400 410 420 500 510 800 admin 910
- debts.Accounts.duplicate : visible for admin 910
- debts.AccountsByGroup.duplicate : visible for 100 110 120 200 210 220 300 400 410 420 500 510 800 admin 910
- debts.Actors.duplicate : visible for admin 910
- debts.ActorsByBudget.duplicate : visible for 120 300 420 admin 910
- debts.ActorsByPartner.duplicate : visible for 120 300 420 admin 910
- debts.AssetsByBudget.duplicate : visible for 120 300 420 admin 910
- debts.Budgets.duplicate : visible for admin 910
- debts.BudgetsByPartner.duplicate : visible for 120 300 420 admin 910
- debts.Clients.duplicate : visible for 120 300 420 admin 910
- debts.DistByBudget.duplicate : visible for 120 300 420 admin 910
- debts.Entries.duplicate : visible for admin 910
- debts.EntriesByAccount.duplicate : visible for admin 910
- debts.EntriesByBudget.duplicate : visible for 120 300 420 admin 910
- debts.EntriesByType.duplicate : visible for 120 300 420 admin 910
- debts.ExpensesByBudget.duplicate : visible for 120 300 420 admin 910
- debts.IncomesByBudget.duplicate : visible for 120 300 420 admin 910
- debts.LiabilitiesByBudget.duplicate : visible for 120 300 420 admin 910
- debts.MyBudgets.duplicate : visible for 120 300 420 admin 910
- excerpts.AllExcerpts.duplicate : visible for admin 910
- excerpts.Excerpts.duplicate : visible for 100 110 120 200 210 220 300 400 410 420 500 510 800 admin 910
- excerpts.ExcerptsByOwner.duplicate : visible for 100 110 120 200 210 220 300 400 410 420 500 510 800 admin 910
- excerpts.ExcerptsByProject.duplicate : visible for 100 110 120 200 210 300 400 410 420 500 510 800 admin 910
- excerpts.ExcerptsByType.duplicate : visible for 100 110 120 200 210 220 300 400 410 420 500 510 800 admin 910
- excerpts.MyExcerpts.duplicate : visible for 100 110 120 200 210 220 300 400 410 420 500 510 800 admin 910
- extensible.PanelEvents.duplicate : visible for 100 110 120 200 300 400 410 420 500 510 admin 910
- households.Households.duplicate : visible for 100 110 120 200 210 300 400 410 420 500 510 800 admin 910
- households.HouseholdsByType.duplicate : visible for 100 110 120 200 210 300 400 410 420 500 510 800 admin 910
- integ.Clients.duplicate : visible for 100 110 120 420 admin 910
- integ.CoachingEndingsByType.duplicate : visible for 110 120 210 410 420 admin 910
- integ.CoachingEndingsByUser.duplicate : visible for 110 120 210 410 420 admin 910
- integ.CompaniesAndContracts.duplicate : visible for 100 110 120 200 210 220 300 400 410 420 500 510 800 admin 910
- integ.JobProvidersAndContracts.duplicate : visible for 100 110 120 200 210 220 300 400 410 420 500 510 800 admin 910
- isip.EntriesByContract.duplicate : visible for 100 110 120 200 210 220 300 400 410 420 500 510 800 admin 910
- jobs.JobProviders.duplicate : visible for 100 110 120 420 admin 910
- jobs.JobTypes.duplicate : visible for 110 120 410 420 admin 910
- newcomers.ClientsByFaculty.duplicate : visible for 100 110 120 200 210 220 300 400 410 420 500 510 800 admin 910
- newcomers.Competences.duplicate : visible for 110 120 410 420 admin 910
- newcomers.CompetencesByFaculty.duplicate : visible for 110 120 410 420 admin 910
- newcomers.CompetencesByUser.duplicate : visible for 100 110 120 200 210 220 300 400 410 420 500 510 800 admin 910
- newcomers.MyCompetences.duplicate : visible for 100 110 120 200 210 220 300 400 410 420 500 510 800 admin 910
- newcomers.NewClients.duplicate : visible for 120 200 220 300 420 admin 910
- notes.AllNotes.duplicate : visible for 110 120 420 admin 910
- notes.MyNotes.duplicate : visible for 100 110 120 200 210 220 300 400 410 420 500 510 800 admin 910
- notes.Notes.duplicate : visible for 100 110 120 200 210 220 300 400 410 420 500 510 800 admin 910
- notes.NotesByCompany.duplicate : visible for 100 110 120 200 210 300 400 410 420 500 510 800 admin 910
- notes.NotesByEventType.duplicate : visible for 100 110 120 200 210 220 300 400 410 420 500 510 800 admin 910
- notes.NotesByOwner.duplicate : visible for 100 110 120 200 210 220 300 400 410 420 500 510 800 admin 910
- notes.NotesByPerson.duplicate : visible for 100 110 120 200 210 220 300 400 410 420 500 510 800 admin 910
- notes.NotesByProject.duplicate : visible for 100 110 120 200 210 300 400 410 420 500 510 800 admin 910
- notes.NotesByType.duplicate : visible for 100 110 120 200 210 220 300 400 410 420 500 510 800 admin 910
- pcsw.AllClients.duplicate : visible for 110 120 410 420 admin 910
- pcsw.Clients.duplicate : visible for 100 110 120 200 210 220 300 400 410 420 500 510 800 admin 910
- pcsw.ClientsByNationality.duplicate : visible for 100 110 120 200 210 220 300 400 410 420 500 510 800 admin 910
- pcsw.CoachedClients.duplicate : visible for 100 110 120 200 300 400 410 420 admin 910
- pcsw.DispenseReasons.duplicate : visible for 110 120 410 420 admin 910
- polls.Choices.duplicate : visible for 110 120 410 420 admin 910
- polls.ChoicesBySet.duplicate : visible for 110 120 410 420 admin 910
- polls.PollResult.duplicate : visible for 110 120 410 420 admin 910
- polls.Questions.duplicate : visible for 110 120 410 420 admin 910
- polls.QuestionsByPoll.duplicate : visible for 100 110 120 200 300 400 410 420 admin 910
- reception.Clients.duplicate : visible for 100 110 120 200 210 220 300 400 410 420 500 510 800 admin 910

Permissions

Test whether everybody can display the detail of a client:

>>> o = pcsw.Client.objects.get(id=177)
>>> for u in ('robin', 'alicia', 'theresia', 'caroline', 'kerstin', None):
...     print(tostring(rt.login(u).obj2html(o)))
... 
<a href="Detail">BRECHT Bernd (177)</a>
<a href="Detail">BRECHT Bernd (177)</a>
<a href="Detail">BRECHT Bernd (177)</a>
<a href="Detail">BRECHT Bernd (177)</a>
<a href="Detail">BRECHT Bernd (177)</a>
<em>BRECHT Bernd (177)</em>

Miscellaneous tests

See 2013-05-08:

>>> for model in (debts.Entry,):
...     for o in model.objects.all():
...         o.full_clean()