Package Gnumed :: Package wxpython :: Module gmPraxisWidgets
[frames] | no frames]

Source Code for Module Gnumed.wxpython.gmPraxisWidgets

  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  #import datetime as pydt 
 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  #========================================================================= 
60 -def show_audit_trail(parent=None):
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 #============================================================
98 -def configure_fallback_primary_provider(parent=None):
99 100 if parent is None: 101 parent = wx.GetApp().GetTopWindow() 102 103 staff = gmStaff.get_staff_list() 104 choices = [ [ 105 s[u'short_alias'], 106 u'%s%s %s' % ( 107 gmTools.coalesce(s['title'], u'', u'%s '), 108 s['firstnames'], 109 s['lastnames'] 110 ), 111 s['l10n_role'], 112 gmTools.coalesce(s['comment'], u'') 113 ] 114 for s in staff 115 if s['is_active'] is True 116 ] 117 data = [ s['pk_staff'] for s in staff if s['is_active'] is True ] 118 119 gmCfgWidgets.configure_string_from_list_option ( 120 parent = parent, 121 message = _( 122 '\n' 123 'Please select the provider to fall back to in case\n' 124 'no primary provider is configured for a patient.\n' 125 ), 126 option = 'patient.fallback_primary_provider', 127 bias = 'user', 128 default_value = None, 129 choices = choices, 130 columns = [_('Alias'), _('Provider'), _('Role'), _('Comment')], 131 data = data, 132 caption = _('Configuring fallback primary provider') 133 )
134 135 #============================================================ 136 # workplace plugin configuration widgets 137 #------------------------------------------------------------
138 -def configure_workplace_plugins(parent=None):
139 140 if parent is None: 141 parent = wx.GetApp().GetTopWindow() 142 143 #----------------------------------- 144 def delete(workplace): 145 146 curr_workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace 147 if workplace == curr_workplace: 148 gmDispatcher.send(signal = 'statustext', msg = _('Cannot delete the active workplace.'), beep = True) 149 return False 150 151 dlg = gmGuiHelpers.c2ButtonQuestionDlg ( 152 parent, 153 -1, 154 caption = _('Deleting workplace ...'), 155 question = _('Are you sure you want to delete this workplace ?\n\n "%s"\n') % workplace, 156 show_checkbox = True, 157 checkbox_msg = _('delete configuration, too'), 158 checkbox_tooltip = _( 159 'Check this if you want to delete all configuration items\n' 160 'for this workplace along with the workplace itself.' 161 ), 162 button_defs = [ 163 {'label': _('Delete'), 'tooltip': _('Yes, delete this workplace.'), 'default': True}, 164 {'label': _('Do NOT delete'), 'tooltip': _('No, do NOT delete this workplace'), 'default': False} 165 ] 166 ) 167 168 decision = dlg.ShowModal() 169 if decision != wx.ID_YES: 170 dlg.Destroy() 171 return False 172 173 include_cfg = dlg.checkbox_is_checked() 174 dlg.Destroy() 175 176 dbo_conn = gmAuthWidgets.get_dbowner_connection(procedure = _('delete workplace')) 177 if not dbo_conn: 178 return False 179 180 gmPraxis.delete_workplace(workplace = workplace, conn = dbo_conn, delete_config = include_cfg) 181 return True
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 # FIXME: clone cfg, too 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
375 -class cGreetingEditorDlg(wxgGreetingEditorDlg.wxgGreetingEditorDlg):
376
377 - def __init__(self, *args, **kwargs):
378 wxgGreetingEditorDlg.wxgGreetingEditorDlg.__init__(self, *args, **kwargs) 379 380 self.praxis = gmPraxis.gmCurrentPraxisBranch() 381 self._TCTRL_message.SetValue(self.praxis.db_logon_banner)
382 #-------------------------------------------------------- 383 # event handlers 384 #--------------------------------------------------------
385 - def _on_save_button_pressed(self, evt):
386 self.praxis.db_logon_banner = self._TCTRL_message.GetValue().strip() 387 if self.IsModal(): 388 self.EndModal(wx.ID_SAVE) 389 else: 390 self.Close()
391 392 #============================================================
393 -def select_praxis_branch(parent=None):
394 395 branches = gmPraxis.get_praxis_branches() 396 397 if len(branches) == 0: 398 if not set_active_praxis_branch(parent = parent, no_parent = False): 399 return None
400 401 # FIXME: needs implementation 402 403 #============================================================
404 -def set_active_praxis_branch(parent=None, no_parent=False):
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 #============================================================
502 -def manage_praxis_branches(parent=None):
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 # detect whether active branch in kept branches 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 #============================================================
613 -class cPraxisBranchPhraseWheel(gmPhraseWheel.cPhraseWheel):
614
615 - def __init__(self, *args, **kwargs):
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 #--------------------------------------------------------
640 - def _get_data_tooltip(self):
641 if self.GetData() is None: 642 return None 643 branch = self._data2instance() 644 if branch is None: 645 return None 646 return branch.format()
647 #--------------------------------------------------------
648 - def _data2instance(self):
649 if self.GetData() is None: 650 return None 651 return gmPraxis.cPraxisBranch(aPK_obj = self.GetData())
652 653 #============================================================ 654 # main 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 # from Gnumed.pycommon import gmPG2 665 # from Gnumed.pycommon import gmI18N 666 # gmI18N.activate_locale() 667 # gmI18N.install_domain() 668
669 - def test_configure_wp_plugins():
670 app = wx.PyWidgetTester(size = (400, 300)) 671 configure_workplace_plugins()
672 673 #-------------------------------------------------------- 674 #test_org_unit_prw() 675 #test_configure_wp_plugins() 676