1 """GNUmed praxis related widgets.
2
3 Praxis:
4
5 Each database belongs to ONE praxis only. A praxis can
6 have several branches. A praxis is at the same level
7 as an organization, except that it is not explicitely
8 defined. Rather, that ONE organization of which at least
9 one unit is defined as a praxis branch IS the praxis.
10
11 Praxis branch
12
13 Branches are the sites/locations of a praxis. There
14 can be several branches. Each branch must link to
15 units of ONE AND THE SAME organization (because
16 it is not considered good data protection practice
17 to mix charts of *different* organizations within
18 one database). However, that organization which
19 has units that are praxis branches can also have
20 other units which are not branches :-)
21
22 copyright: authors
23 """
24
25 __author__ = "K.Hilbert"
26 __license__ = "GPL v2 or later (details at http://www.gnu.org)"
27
28 import logging
29 import sys
30
31
32
33 import wx
34
35
36 if __name__ == '__main__':
37 sys.path.insert(0, '../../')
38 from Gnumed.pycommon import gmCfg
39 from Gnumed.pycommon import gmDispatcher
40 from Gnumed.pycommon import gmTools
41 from Gnumed.pycommon import gmPG2
42 from Gnumed.pycommon import gmMatchProvider
43
44 from Gnumed.business import gmPraxis
45 from Gnumed.business import gmStaff
46 from Gnumed.business import gmOrganization
47
48 from Gnumed.wxpython import gmOrganizationWidgets
49 from Gnumed.wxpython import gmGuiHelpers
50 from Gnumed.wxpython import gmAuthWidgets
51 from Gnumed.wxpython import gmListWidgets
52 from Gnumed.wxpython import gmPlugin
53 from Gnumed.wxpython import gmCfgWidgets
54 from Gnumed.wxpython import gmPhraseWheel
55
56
57 _log = logging.getLogger('gm.praxis')
58
59
61
62 if parent is None:
63 parent = wx.GetApp().GetTopWindow()
64
65 conn = gmAuthWidgets.get_dbowner_connection(procedure = _('showing audit trail'))
66 if conn is None:
67 return False
68
69
70 def refresh(lctrl):
71 cmd = u'SELECT * FROM audit.v_audit_trail ORDER BY audit_when_ts'
72 rows, idx = gmPG2.run_ro_queries(link_obj = conn, queries = [{'cmd': cmd}], get_col_idx = False)
73 lctrl.set_string_items (
74 [ [
75 r['event_when'],
76 r['event_by'],
77 u'%s %s %s' % (
78 gmTools.coalesce(r['row_version_before'], gmTools.u_diameter),
79 gmTools.u_right_arrow,
80 gmTools.coalesce(r['row_version_after'], gmTools.u_diameter)
81 ),
82 r['event_table'],
83 r['event'],
84 r['pk_audit']
85 ] for r in rows ]
86 )
87
88 gmListWidgets.get_choices_from_list (
89 parent = parent,
90 msg = u'',
91 caption = _('GNUmed database audit log ...'),
92 columns = [ _('When'), _('Who'), _('Revisions'), _('Table'), _('Event'), '#' ],
93 single_selection = True,
94 refresh_callback = refresh
95 )
96
97
134
135
136
137
182
183 def edit(workplace=None):
184
185 dbcfg = gmCfg.cCfgSQL()
186
187 if workplace is None:
188 dlg = wx.TextEntryDialog (
189 parent = parent,
190 message = _('Enter a descriptive name for the new workplace:'),
191 caption = _('Configuring GNUmed workplaces ...'),
192 defaultValue = u'',
193 style = wx.OK | wx.CENTRE
194 )
195 dlg.ShowModal()
196 workplace = dlg.GetValue().strip()
197 if workplace == u'':
198 gmGuiHelpers.gm_show_error(_('Cannot save a new workplace without a name.'), _('Configuring GNUmed workplaces ...'))
199 return False
200 curr_plugins = []
201 else:
202 curr_plugins = gmTools.coalesce(dbcfg.get2 (
203 option = u'horstspace.notebook.plugin_load_order',
204 workplace = workplace,
205 bias = 'workplace'
206 ), []
207 )
208
209 msg = _(
210 'Pick the plugin(s) to be loaded the next time the client is restarted under the workplace:\n'
211 '\n'
212 ' [%s]\n'
213 ) % workplace
214
215 picker = gmListWidgets.cItemPickerDlg (
216 parent,
217 -1,
218 title = _('Configuring workplace plugins ...'),
219 msg = msg
220 )
221 picker.set_columns(['Available plugins'], ['Active plugins'])
222 available_plugins = gmPlugin.get_installed_plugins(plugin_dir = 'gui')
223 picker.set_choices(available_plugins)
224 picker.set_picks(picks = curr_plugins[:])
225 btn_pressed = picker.ShowModal()
226 if btn_pressed != wx.ID_OK:
227 picker.Destroy()
228 return False
229
230 new_plugins = picker.get_picks()
231 picker.Destroy()
232 if new_plugins == curr_plugins:
233 return True
234
235 if new_plugins is None:
236 return True
237
238 dbcfg.set (
239 option = u'horstspace.notebook.plugin_load_order',
240 value = new_plugins,
241 workplace = workplace
242 )
243
244 return True
245
246 def edit_old(workplace=None):
247
248 available_plugins = gmPlugin.get_installed_plugins(plugin_dir='gui')
249
250 dbcfg = gmCfg.cCfgSQL()
251
252 if workplace is None:
253 dlg = wx.TextEntryDialog (
254 parent = parent,
255 message = _('Enter a descriptive name for the new workplace:'),
256 caption = _('Configuring GNUmed workplaces ...'),
257 defaultValue = u'',
258 style = wx.OK | wx.CENTRE
259 )
260 dlg.ShowModal()
261 workplace = dlg.GetValue().strip()
262 if workplace == u'':
263 gmGuiHelpers.gm_show_error(_('Cannot save a new workplace without a name.'), _('Configuring GNUmed workplaces ...'))
264 return False
265 curr_plugins = []
266 choices = available_plugins
267 else:
268 curr_plugins = gmTools.coalesce(dbcfg.get2 (
269 option = u'horstspace.notebook.plugin_load_order',
270 workplace = workplace,
271 bias = 'workplace'
272 ), []
273 )
274 choices = curr_plugins[:]
275 for p in available_plugins:
276 if p not in choices:
277 choices.append(p)
278
279 sels = range(len(curr_plugins))
280 new_plugins = gmListWidgets.get_choices_from_list (
281 parent = parent,
282 msg = _(
283 '\n'
284 'Select the plugin(s) to be loaded the next time\n'
285 'the client is restarted under the workplace:\n'
286 '\n'
287 ' [%s]'
288 '\n'
289 ) % workplace,
290 caption = _('Configuring GNUmed workplaces ...'),
291 choices = choices,
292 selections = sels,
293 columns = [_('Plugins')],
294 single_selection = False
295 )
296
297 if new_plugins == curr_plugins:
298 return True
299
300 if new_plugins is None:
301 return True
302
303 dbcfg.set (
304 option = u'horstspace.notebook.plugin_load_order',
305 value = new_plugins,
306 workplace = workplace
307 )
308
309 return True
310
311 def clone(workplace=None):
312 if workplace is None:
313 return False
314
315 new_name = wx.GetTextFromUser (
316 message = _('Enter a name for the new workplace !'),
317 caption = _('Cloning workplace'),
318 default_value = u'%s-2' % workplace,
319 parent = parent
320 ).strip()
321
322 if new_name == u'':
323 return False
324
325 dbcfg = gmCfg.cCfgSQL()
326 opt = u'horstspace.notebook.plugin_load_order'
327
328 plugins = dbcfg.get2 (
329 option = opt,
330 workplace = workplace,
331 bias = 'workplace'
332 )
333
334 dbcfg.set (
335 option = opt,
336 value = plugins,
337 workplace = new_name
338 )
339
340
341
342 return True
343
344 def refresh(lctrl):
345 workplaces = gmPraxis.gmCurrentPraxisBranch().workplaces
346 curr_workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace
347 try:
348 sels = [workplaces.index(curr_workplace)]
349 except ValueError:
350 sels = []
351
352 lctrl.set_string_items(workplaces)
353 lctrl.set_selections(selections = sels)
354
355 gmListWidgets.get_choices_from_list (
356 parent = parent,
357 msg = _(
358 '\nSelect the workplace to configure below.\n'
359 '\n'
360 'The currently active workplace is preselected.\n'
361 ),
362 caption = _('Configuring GNUmed workplaces ...'),
363 columns = [_('Workplace')],
364 single_selection = True,
365 refresh_callback = refresh,
366 edit_callback = edit,
367 new_callback = edit,
368 delete_callback = delete,
369 left_extra_button = (_('Clone'), _('Clone the selected workplace'), clone)
370 )
371
372
373 from Gnumed.wxGladeWidgets import wxgGreetingEditorDlg
374
391
392
400
401
402
403
405
406 if no_parent:
407 parent = None
408 else:
409 if parent is None:
410 parent = wx.GetApp().GetTopWindow()
411
412 branches = gmPraxis.get_praxis_branches()
413
414 if len(branches) == 1:
415 _log.debug('only one praxis branch configured')
416 gmPraxis.gmCurrentPraxisBranch(branches[0])
417 return True
418
419 if len(branches) == 0:
420 orgs = gmOrganization.get_orgs()
421 if len(orgs) == 0:
422 pk_cat = gmOrganization.create_org_category(category = u'Praxis')
423 org = gmOrganization.create_org(_('Your praxis'), pk_cat)
424 unit = org.add_unit(_('Your branch'))
425 branch = gmPraxis.create_praxis_branch(pk_org_unit = unit['pk_org_unit'])
426 _log.debug('auto-created praxis branch because no organizations existed: %s', branch)
427 gmPraxis.gmCurrentPraxisBranch(branch)
428 gmGuiHelpers.gm_show_info (
429 title = _('Praxis configuration ...'),
430 info = _(
431 'GNUmed has auto-created the following\n'
432 'praxis branch for you (which you can\n'
433 'later configure as needed):\n'
434 '\n'
435 '%s'
436 ) % branch.format()
437 )
438 return True
439
440 if len(orgs) == 1:
441 units = orgs[0].units
442 if len(units) == 1:
443 branch = gmPraxis.create_praxis_branch(pk_org_unit = units[0]['pk_org_unit'])
444 _log.debug('auto-selected praxis branch because only one organization with only one unit existed: %s', branch)
445 gmPraxis.gmCurrentPraxisBranch(branch)
446 gmGuiHelpers.gm_show_info (
447 title = _('Praxis configuration ...'),
448 info = _(
449 'GNUmed has auto-selected the following\n'
450 'praxis branch for you (which you can\n'
451 'later configure as needed):\n'
452 '\n'
453 '%s'
454 ) % branch.format()
455 )
456 return True
457
458 _log.debug('no praxis branches configured, selecting from organization units')
459 msg = _(
460 'No praxis branches configured currently.\n'
461 '\n'
462 'You MUST select one unit of an organization to be the initial\n'
463 'branch (site, office) which you are logging in from.'
464 )
465 unit = gmOrganizationWidgets.select_org_unit(msg = msg, no_parent = True)
466 if unit is None:
467 _log.warning('no organization unit selected, aborting')
468 return False
469 _log.debug('org unit selected as praxis branch: %s', unit)
470 branch = gmPraxis.create_praxis_branch(pk_org_unit = unit['pk_org_unit'])
471 _log.debug('created praxis branch: %s', branch)
472 gmPraxis.gmCurrentPraxisBranch(branch)
473 return True
474
475
476 def refresh(lctrl):
477 branches = gmPraxis.get_praxis_branches()
478 items = [
479 [ b['branch'],
480 gmTools.coalesce(b['l10n_unit_category'], u'')
481 ] for b in branches
482 ]
483 lctrl.set_string_items(items = items)
484 lctrl.set_data(data = branches)
485
486 branch = gmListWidgets.get_choices_from_list (
487 parent = parent,
488 msg = _("Select branch (of praxis [%s]) which you are logging in from.\n") % branches[0]['praxis'],
489 caption = _('Praxis branch selection ...'),
490 columns = [_('Branch'), _('Branch type')],
491 can_return_empty = False,
492 single_selection = True,
493 refresh_callback = refresh
494 )
495 if branch is None:
496 _log.warning('no praxis branch selected, aborting')
497 return False
498 gmPraxis.gmCurrentPraxisBranch(branch)
499 return True
500
501
503
504 if parent is None:
505 parent = wx.GetApp().GetTopWindow()
506
507
508 def get_unit_tooltip(unit):
509 if unit is None:
510 return None
511 return u'\n'.join(unit.format(with_address = True, with_org = True, with_comms = True))
512
513 def manage_orgs():
514 gmOrganizationWidgets.manage_orgs(parent = parent)
515
516
517 branches = gmPraxis.get_praxis_branches()
518 org = branches[0].organization
519 praxis = branches[0]['praxis']
520
521 msg = _(
522 'Pick those units of "%s" which are branches of your praxis !\n'
523 '\n'
524 'Note that no other client should be connected at this time.\n'
525 '\n'
526 'If you want to select another organization entirely\n'
527 'first remove all existing branches.\n'
528 ) % praxis
529
530 picker = gmListWidgets.cItemPickerDlg(parent, -1, msg = msg)
531 picker.extra_button = (
532 _('Manage units'),
533 _('Manage organizations and their units'),
534 manage_orgs
535 )
536 picker.allow_duplicate_picks = False
537 picker.left_item_tooltip_callback = get_unit_tooltip
538 picker.right_item_tooltip_callback = get_unit_tooltip
539 picker.set_columns(columns = [_('Units of "%s"') % praxis], columns_right = [_('Branches of your praxis')])
540 units = org.units
541 branch_unit_pks = [b['pk_org_unit'] for b in branches]
542 branch_units = []
543 for unit in units:
544 if unit['pk_org_unit'] in branch_unit_pks:
545 branch_units.append(unit)
546 items = [ u'%s%s' % (u['unit'], gmTools.coalesce(u['l10n_unit_category'], u'', u' (%s)')) for u in units ]
547 picker.set_choices(choices = items, data = units)
548 items = [ u'%s%s' % (u['unit'], gmTools.coalesce(u['l10n_unit_category'], u'', u' (%s)')) for u in branch_units ]
549 picker.set_picks(picks = items, data = branch_units)
550 del units
551 del branch_unit_pks
552 del branch_units
553 del items
554
555 result = picker.ShowModal()
556
557 if result == wx.ID_CANCEL:
558 picker.Destroy()
559 return None
560
561 picks = picker.picks
562 picker.Destroy()
563
564 failed_delete_msg = _(
565 'Cannot delete praxis branch(es).\n'
566 '\n'
567 'There are probably clients logged in\n'
568 'from other locations. You need to log out\n'
569 'all but this client before the praxis can\n'
570 'be reconfigured.'
571 )
572
573 if len(picks) == 0:
574 if not gmPraxis.delete_praxis_branches():
575 gmGuiHelpers.gm_show_error (
576 error = failed_delete_msg,
577 title = _('Configuring praxis ...')
578 )
579 return False
580 while not set_active_praxis_branch(parent = parent):
581 pass
582 return
583
584 pk_picked_units = [p['pk_org_unit'] for p in picks]
585 pk_branches_to_keep = [
586 b['pk_praxis_branch'] for b in gmPraxis.get_praxis_branches()
587 if b['pk_org_unit'] in pk_picked_units
588 ]
589 if len(pk_branches_to_keep) == 0:
590 if not gmPraxis.delete_praxis_branches():
591 gmGuiHelpers.gm_show_error (
592 error = failed_delete_msg,
593 title = _('Configuring praxis ...')
594 )
595 return False
596 else:
597 if not gmPraxis.delete_praxis_branches(except_pk_praxis_branches = pk_branches_to_keep):
598 gmGuiHelpers.gm_show_error (
599 error = failed_delete_msg,
600 title = _('Configuring praxis ...')
601 )
602 return False
603 gmPraxis.create_praxis_branches(pk_org_units = pk_picked_units)
604
605
606 if gmPraxis.gmCurrentPraxisBranch()['pk_praxis_branch'] in pk_branches_to_keep:
607 return
608
609 while not set_active_praxis_branch(parent = parent):
610 pass
611
612
614
616 query = u"""
617 SELECT
618 pk_praxis_branch AS data,
619 branch || ' (' || praxis || ')' AS field_label,
620 branch || coalesce(' (' || l10n_unit_category || ')', '') || ' of ' || l10n_organization_category || ' "' || praxis || '"' AS list_label
621 FROM
622 dem.v_praxis_branches
623 WHERE
624 branch %(fragment_condition)s
625 OR
626 praxis %(fragment_condition)s
627 OR
628 l10n_unit_category %(fragment_condition)s
629 ORDER BY
630 list_label
631 LIMIT 50
632 """
633 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
634 mp.setThresholds(1, 2, 4)
635 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
636 self.SetToolTipString(_("Select a praxis branch."))
637 self.matcher = mp
638 self.selection_only = True
639
647
652
653
654
655
656 if __name__ == "__main__":
657
658 if len(sys.argv) < 2:
659 sys.exit()
660
661 if sys.argv[1] != u'test':
662 sys.exit()
663
664
665
666
667
668
672
673
674
675
676