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 = '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 '%s %s %s' % ( 78 gmTools.coalesce(r['row_version_before'], gmTools.u_diameter), 79 gmTools.u_arrow2right, 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 = '', 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['short_alias'], 106 '%s%s %s' % ( 107 gmTools.coalesce(s['title'], '', '%s '), 108 s['firstnames'], 109 s['lastnames'] 110 ), 111 s['l10n_role'], 112 gmTools.coalesce(s['comment'], '') 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.DestroyLater() 171 return False 172 173 include_cfg = dlg.checkbox_is_checked() 174 dlg.DestroyLater() 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, 190 _('Enter a descriptive name for the new workplace:'), 191 caption = _('Configuring GNUmed workplaces ...'), 192 value = '', 193 style = wx.OK | wx.CENTRE 194 ) 195 dlg.ShowModal() 196 workplace = dlg.GetValue().strip() 197 if workplace == '': 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 = '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.DestroyLater() 228 return False 229 230 new_plugins = picker.get_picks() 231 picker.DestroyLater() 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 = '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, 255 _('Enter a descriptive name for the new workplace:'), 256 caption = _('Configuring GNUmed workplaces ...'), 257 value = '', 258 style = wx.OK | wx.CENTRE 259 ) 260 dlg.ShowModal() 261 workplace = dlg.GetValue().strip() 262 if workplace == '': 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 = '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 = '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 = '%s-2' % workplace, 319 parent = parent 320 ).strip() 321 322 if new_name == '': 323 return False 324 325 dbcfg = gmCfg.cCfgSQL() 326 opt = '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 _log.debug('activated branch') 418 return True 419 420 if len(branches) == 0: 421 orgs = gmOrganization.get_orgs() 422 if len(orgs) == 0: 423 pk_cat = gmOrganization.create_org_category(category = 'Praxis') 424 org = gmOrganization.create_org(_('Your praxis'), pk_cat) 425 unit = org.add_unit(_('Your branch')) 426 branch = gmPraxis.create_praxis_branch(pk_org_unit = unit['pk_org_unit']) 427 _log.debug('auto-created praxis branch because no organizations existed: %s', branch) 428 gmPraxis.gmCurrentPraxisBranch(branch) 429 gmGuiHelpers.gm_show_info ( 430 title = _('Praxis configuration ...'), 431 info = _( 432 'GNUmed has auto-created the following\n' 433 'praxis branch for you (which you can\n' 434 'later configure as needed):\n' 435 '\n' 436 '%s' 437 ) % branch.format() 438 ) 439 return True 440 441 if len(orgs) == 1: 442 units = orgs[0].units 443 if len(units) == 1: 444 branch = gmPraxis.create_praxis_branch(pk_org_unit = units[0]['pk_org_unit']) 445 _log.debug('auto-selected praxis branch because only one organization with only one unit existed: %s', branch) 446 gmPraxis.gmCurrentPraxisBranch(branch) 447 gmGuiHelpers.gm_show_info ( 448 title = _('Praxis configuration ...'), 449 info = _( 450 'GNUmed has auto-selected the following\n' 451 'praxis branch for you (which you can\n' 452 'later configure as needed):\n' 453 '\n' 454 '%s' 455 ) % branch.format() 456 ) 457 return True 458 459 _log.debug('no praxis branches configured, selecting from organization units') 460 msg = _( 461 'No praxis branches configured currently.\n' 462 '\n' 463 'You MUST select one unit of an organization to be the initial\n' 464 'branch (site, office) which you are logging in from.' 465 ) 466 unit = gmOrganizationWidgets.select_org_unit(msg = msg, no_parent = True) 467 if unit is None: 468 _log.warning('no organization unit selected, aborting') 469 return False 470 _log.debug('org unit selected as praxis branch: %s', unit) 471 branch = gmPraxis.create_praxis_branch(pk_org_unit = unit['pk_org_unit']) 472 _log.debug('created praxis branch: %s', branch) 473 gmPraxis.gmCurrentPraxisBranch(branch) 474 return True 475 476 #-------------------- 477 def refresh(lctrl): 478 branches = gmPraxis.get_praxis_branches() 479 items = [ 480 [ b['branch'], 481 gmTools.coalesce(b['l10n_unit_category'], '') 482 ] for b in branches 483 ] 484 lctrl.set_string_items(items = items) 485 lctrl.set_data(data = branches)
486 #-------------------- 487 branch = gmListWidgets.get_choices_from_list ( 488 parent = parent, 489 msg = _("Select the branch of praxis [%s] which you are logging in from.\n") % branches[0]['praxis'], 490 caption = _('Praxis branch selection ...'), 491 columns = [_('Branch'), _('Branch type')], 492 can_return_empty = False, 493 single_selection = True, 494 refresh_callback = refresh 495 ) 496 if branch is None: 497 _log.warning('no praxis branch selected, aborting') 498 return False 499 gmPraxis.gmCurrentPraxisBranch(branch) 500 return True 501 502 #============================================================
503 -def manage_praxis_branches(parent=None):
504 505 if parent is None: 506 parent = wx.GetApp().GetTopWindow() 507 508 #--------------------------- 509 def get_unit_tooltip(unit): 510 if unit is None: 511 return None 512 return '\n'.join(unit.format(with_address = True, with_org = True, with_comms = True))
513 #--------------------------- 514 def manage_orgs(): 515 gmOrganizationWidgets.manage_orgs(parent = parent) 516 #--------------------------- 517 518 branches = gmPraxis.get_praxis_branches() 519 org = branches[0].organization 520 praxis = branches[0]['praxis'] 521 522 msg = _( 523 'Pick those units of "%s" which are branches of your praxis !\n' 524 '\n' 525 'Note that no other client should be connected at this time.\n' 526 '\n' 527 'If you want to select another organization entirely\n' 528 'first remove all existing branches.\n' 529 ) % praxis 530 531 picker = gmListWidgets.cItemPickerDlg(parent, -1, msg = msg) 532 picker.extra_button = ( 533 _('Manage units'), 534 _('Manage organizations and their units'), 535 manage_orgs 536 ) 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 = [ '%s%s' % (u['unit'], gmTools.coalesce(u['l10n_unit_category'], '', ' (%s)')) for u in units ] 547 picker.set_choices(choices = items, data = units) 548 items = [ '%s%s' % (u['unit'], gmTools.coalesce(u['l10n_unit_category'], '', ' (%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.DestroyLater() 559 return None 560 561 picks = picker.picks 562 picker.DestroyLater() 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 = """( 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 626 ) UNION ( 627 628 SELECT 629 pk_praxis_branch AS data, 630 branch || ' (' || praxis || ')' AS field_label, 631 branch || coalesce(' (' || l10n_unit_category || ')', '') || ' of ' || l10n_organization_category || ' "' || praxis || '"' AS list_label 632 FROM 633 dem.v_praxis_branches 634 WHERE 635 praxis %(fragment_condition)s 636 637 ) UNION ( 638 639 SELECT 640 pk_praxis_branch AS data, 641 branch || ' (' || praxis || ')' AS field_label, 642 branch || coalesce(' (' || l10n_unit_category || ')', '') || ' of ' || l10n_organization_category || ' "' || praxis || '"' AS list_label 643 FROM 644 dem.v_praxis_branches 645 WHERE 646 l10n_unit_category %(fragment_condition)s 647 648 ) 649 ORDER BY 650 list_label 651 LIMIT 50""" 652 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query) 653 mp.setThresholds(1, 2, 4) 654 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 655 self.SetToolTip(_("Select a praxis branch.")) 656 self.matcher = mp 657 self.selection_only = True 658 self.picklist_delay = 300
659 #--------------------------------------------------------
660 - def _get_data_tooltip(self):
661 if self.GetData() is None: 662 return None 663 branch = self._data2instance() 664 if branch is None: 665 return None 666 return branch.format()
667 #--------------------------------------------------------
668 - def _data2instance(self):
669 if self.GetData() is None: 670 return None 671 return gmPraxis.cPraxisBranch(aPK_obj = self.GetData())
672 673 #============================================================ 674 # main 675 #------------------------------------------------------------ 676 if __name__ == "__main__": 677 678 if len(sys.argv) < 2: 679 sys.exit() 680 681 if sys.argv[1] != 'test': 682 sys.exit() 683 684 # from Gnumed.pycommon import gmPG2 685 # from Gnumed.pycommon import gmI18N 686 # gmI18N.activate_locale() 687 # gmI18N.install_domain() 688
689 - def test_configure_wp_plugins():
690 app = wx.PyWidgetTester(size = (400, 300)) 691 configure_workplace_plugins()
692 693 #-------------------------------------------------------- 694 #test_org_unit_prw() 695 #test_configure_wp_plugins() 696