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

Source Code for Module Gnumed.wxpython.gmEMRStructWidgets

   1  """GNUmed EMR structure editors 
   2   
   3          This module contains widgets to create and edit EMR structural 
   4          elements (issues, enconters, episodes). 
   5   
   6          This is based on initial work and ideas by Syan <kittylitter@swiftdsl.com.au> 
   7          and Karsten <Karsten.Hilbert@gmx.net>. 
   8  """ 
   9  #================================================================ 
  10  __author__ = "cfmoro1976@yahoo.es, karsten.hilbert@gmx.net" 
  11  __license__ = "GPL v2 or later" 
  12   
  13  # stdlib 
  14  import sys 
  15  import time 
  16  import logging 
  17  import datetime as pydt 
  18   
  19   
  20  # 3rd party 
  21  import wx 
  22   
  23   
  24  # GNUmed 
  25  if __name__ == '__main__': 
  26          sys.path.insert(0, '../../') 
  27   
  28  from Gnumed.pycommon import gmI18N 
  29  from Gnumed.pycommon import gmDateTime 
  30   
  31  if __name__ == '__main__': 
  32          gmI18N.activate_locale() 
  33          gmI18N.install_domain() 
  34          gmDateTime.init() 
  35   
  36  from Gnumed.pycommon import gmExceptions 
  37  from Gnumed.pycommon import gmCfg 
  38  from Gnumed.pycommon import gmTools 
  39  from Gnumed.pycommon import gmDispatcher 
  40  from Gnumed.pycommon import gmMatchProvider 
  41   
  42  from Gnumed.business import gmEMRStructItems 
  43  from Gnumed.business import gmPraxis 
  44  from Gnumed.business import gmPerson 
  45   
  46  from Gnumed.wxpython import gmPhraseWheel 
  47  from Gnumed.wxpython import gmGuiHelpers 
  48  from Gnumed.wxpython import gmListWidgets 
  49  from Gnumed.wxpython import gmEditArea 
  50   
  51   
  52  _log = logging.getLogger('gm.ui') 
  53   
  54  #================================================================ 
  55  # EMR access helper functions 
  56  #---------------------------------------------------------------- 
57 -def emr_access_spinner(time2spin=0):
58 """Spin time in seconds but let wx go on.""" 59 if time2spin == 0: 60 return 61 sleep_time = 0.1 # 100ms 62 total_rounds = int(time2spin / sleep_time) 63 if total_rounds < 1: 64 wx.Yield() 65 time.sleep(sleep_time) 66 return 67 rounds = 0 68 while rounds < total_rounds: 69 wx.Yield() 70 time.sleep(sleep_time) 71 rounds += 1
72 73 #================================================================ 74 # episode related widgets/functions 75 #----------------------------------------------------------------
76 -def edit_episode(parent=None, episode=None, single_entry=True):
77 ea = cEpisodeEditAreaPnl(parent, -1) 78 ea.data = episode 79 ea.mode = gmTools.coalesce(episode, 'new', 'edit') 80 dlg = gmEditArea.cGenericEditAreaDlg2(parent, -1, edit_area = ea, single_entry = single_entry) 81 dlg.SetTitle(gmTools.coalesce(episode, _('Adding a new episode'), _('Editing an episode'))) 82 if dlg.ShowModal() == wx.ID_OK: 83 return True 84 return False
85 86 #----------------------------------------------------------------
87 -def manage_episodes(parent=None):
88 89 pat = gmPerson.gmCurrentPatient() 90 emr = pat.emr 91 92 if parent is None: 93 parent = wx.GetApp().GetTopWindow() 94 #----------------------------------------- 95 def edit(episode=None): 96 return edit_episode(parent = parent, episode = episode)
97 #----------------------------------------- 98 def delete(episode=None): 99 if gmEMRStructItems.delete_episode(episode = episode): 100 return True 101 gmDispatcher.send ( 102 signal = 'statustext', 103 msg = _('Cannot delete episode.'), 104 beep = True 105 ) 106 return False 107 #----------------------------------------- 108 def manage_issues(episode=None): 109 return select_health_issues(parent = None, emr = emr) 110 #----------------------------------------- 111 def get_tooltip(data): 112 if data is None: 113 return None 114 return data.format ( 115 patient = pat, 116 with_summary = True, 117 with_codes = True, 118 with_encounters = False, 119 with_documents = False, 120 with_hospital_stays = False, 121 with_procedures = False, 122 with_family_history = False, 123 with_tests = False, 124 with_vaccinations = False, 125 with_health_issue = True 126 ) 127 #----------------------------------------- 128 def refresh(lctrl): 129 epis = emr.get_episodes(order_by = 'description') 130 items = [ 131 [ e['description'], 132 gmTools.bool2subst(e['episode_open'], _('ongoing'), _('closed'), '<unknown>'), 133 gmDateTime.pydt_strftime(e.best_guess_clinical_start_date, '%Y %b %d'), 134 gmTools.coalesce(e['health_issue'], '') 135 ] for e in epis 136 ] 137 lctrl.set_string_items(items = items) 138 lctrl.set_data(data = epis) 139 #----------------------------------------- 140 gmListWidgets.get_choices_from_list ( 141 parent = parent, 142 msg = _('\nSelect the episode you want to edit !\n'), 143 caption = _('Editing episodes ...'), 144 columns = [_('Episode'), _('Status'), _('Started'), _('Health issue')], 145 single_selection = True, 146 edit_callback = edit, 147 new_callback = edit, 148 delete_callback = delete, 149 refresh_callback = refresh, 150 list_tooltip_callback = get_tooltip, 151 left_extra_button = (_('Manage issues'), _('Manage health issues'), manage_issues) 152 ) 153 154 #----------------------------------------------------------------
155 -def promote_episode_to_issue(parent=None, episode=None, emr=None):
156 157 created_new_issue = False 158 159 try: 160 issue = gmEMRStructItems.cHealthIssue(name = episode['description'], patient = episode['pk_patient']) 161 except gmExceptions.NoSuchBusinessObjectError: 162 issue = None 163 164 if issue is None: 165 issue = emr.add_health_issue(issue_name = episode['description']) 166 created_new_issue = True 167 else: 168 # issue exists already, so ask user 169 dlg = gmGuiHelpers.c3ButtonQuestionDlg ( 170 parent, 171 -1, 172 caption = _('Promoting episode to health issue'), 173 question = _( 174 'There already is a health issue\n' 175 '\n' 176 ' %s\n' 177 '\n' 178 'What do you want to do ?' 179 ) % issue['description'], 180 button_defs = [ 181 {'label': _('Use existing'), 'tooltip': _('Move episode into existing health issue'), 'default': False}, 182 {'label': _('Create new'), 'tooltip': _('Create a new health issue with another name'), 'default': True} 183 ] 184 ) 185 use_existing = dlg.ShowModal() 186 dlg.DestroyLater() 187 188 if use_existing == wx.ID_CANCEL: 189 return 190 191 # user wants to create new issue with alternate name 192 if use_existing == wx.ID_NO: 193 # loop until name modified but non-empty or cancelled 194 issue_name = episode['description'] 195 while issue_name == episode['description']: 196 dlg = wx.TextEntryDialog ( 197 parent, 198 _('Enter a short descriptive name for the new health issue:'), 199 caption = _('Creating a new health issue ...'), 200 value = issue_name, 201 style = wx.OK | wx.CANCEL | wx.CENTRE 202 ) 203 decision = dlg.ShowModal() 204 if decision != wx.ID_OK: 205 dlg.DestroyLater() 206 return 207 issue_name = dlg.GetValue().strip() 208 dlg.DestroyLater() 209 if issue_name == '': 210 issue_name = episode['description'] 211 212 issue = emr.add_health_issue(issue_name = issue_name) 213 created_new_issue = True 214 215 # eventually move the episode to the issue 216 if not move_episode_to_issue(episode = episode, target_issue = issue, save_to_backend = True): 217 # user cancelled the move so delete just-created issue 218 if created_new_issue: 219 # shouldn't fail as it is completely new 220 gmEMRStructItems.delete_health_issue(health_issue = issue) 221 return 222 223 return
224 225 #----------------------------------------------------------------
226 -def move_episode_to_issue(episode=None, target_issue=None, save_to_backend=False):
227 """Prepare changing health issue for an episode. 228 229 Checks for two-open-episodes conflict. When this 230 function succeeds, the pk_health_issue has been set 231 on the episode instance and the episode should - for 232 all practical purposes - be ready for save_payload(). 233 """ 234 # episode is closed: should always work 235 if not episode['episode_open']: 236 episode['pk_health_issue'] = target_issue['pk_health_issue'] 237 if save_to_backend: 238 episode.save_payload() 239 return True 240 241 # un-associate: should always work, too 242 if target_issue is None: 243 episode['pk_health_issue'] = None 244 if save_to_backend: 245 episode.save_payload() 246 return True 247 248 # try closing possibly expired episode on target issue if any 249 db_cfg = gmCfg.cCfgSQL() 250 epi_ttl = int(db_cfg.get2 ( 251 option = 'episode.ttl', 252 workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace, 253 bias = 'user', 254 default = 60 # 2 months 255 )) 256 if target_issue.close_expired_episode(ttl=epi_ttl) is True: 257 gmDispatcher.send(signal='statustext', msg=_('Closed episodes older than %s days on health issue [%s]') % (epi_ttl, target_issue['description'])) 258 existing_epi = target_issue.get_open_episode() 259 260 # no more open episode on target issue: should work now 261 if existing_epi is None: 262 episode['pk_health_issue'] = target_issue['pk_health_issue'] 263 if save_to_backend: 264 episode.save_payload() 265 return True 266 267 # don't conflict on SELF ;-) 268 if existing_epi['pk_episode'] == episode['pk_episode']: 269 episode['pk_health_issue'] = target_issue['pk_health_issue'] 270 if save_to_backend: 271 episode.save_payload() 272 return True 273 274 # we got two open episodes at once, ask user 275 move_range = (episode.best_guess_clinical_start_date, episode.best_guess_clinical_end_date) 276 if move_range[1] is None: 277 move_range_end = '?' 278 else: 279 move_range_end = move_range[1].strftime('%m/%y') 280 exist_range = (existing_epi.best_guess_clinical_start_date, existing_epi.best_guess_clinical_end_date) 281 if exist_range[1] is None: 282 exist_range_end = '?' 283 else: 284 exist_range_end = exist_range[1].strftime('%m/%y') 285 question = _( 286 'You want to associate the running episode:\n\n' 287 ' "%(new_epi_name)s" (%(new_epi_start)s - %(new_epi_end)s)\n\n' 288 'with the health issue:\n\n' 289 ' "%(issue_name)s"\n\n' 290 'There already is another episode running\n' 291 'for this health issue:\n\n' 292 ' "%(old_epi_name)s" (%(old_epi_start)s - %(old_epi_end)s)\n\n' 293 'However, there can only be one running\n' 294 'episode per health issue.\n\n' 295 'Which episode do you want to close ?' 296 ) % { 297 'new_epi_name': episode['description'], 298 'new_epi_start': move_range[0].strftime('%m/%y'), 299 'new_epi_end': move_range_end, 300 'issue_name': target_issue['description'], 301 'old_epi_name': existing_epi['description'], 302 'old_epi_start': exist_range[0].strftime('%m/%y'), 303 'old_epi_end': exist_range_end 304 } 305 dlg = gmGuiHelpers.c3ButtonQuestionDlg ( 306 parent = None, 307 id = -1, 308 caption = _('Resolving two-running-episodes conflict'), 309 question = question, 310 button_defs = [ 311 {'label': _('old episode'), 'default': True, 'tooltip': _('close existing episode "%s"') % existing_epi['description']}, 312 {'label': _('new episode'), 'default': False, 'tooltip': _('close moving (new) episode "%s"') % episode['description']} 313 ] 314 ) 315 decision = dlg.ShowModal() 316 317 if decision == wx.ID_CANCEL: 318 # button 3: move cancelled by user 319 return False 320 321 elif decision == wx.ID_YES: 322 # button 1: close old episode 323 existing_epi['episode_open'] = False 324 existing_epi.save_payload() 325 326 elif decision == wx.ID_NO: 327 # button 2: close new episode 328 episode['episode_open'] = False 329 330 else: 331 raise ValueError('invalid result from c3ButtonQuestionDlg: [%s]' % decision) 332 333 episode['pk_health_issue'] = target_issue['pk_health_issue'] 334 if save_to_backend: 335 episode.save_payload() 336 return True
337 338 #----------------------------------------------------------------
339 -class cEpisodeListSelectorDlg(gmListWidgets.cGenericListSelectorDlg):
340 341 # FIXME: support pre-selection 342
343 - def __init__(self, *args, **kwargs):
344 345 episodes = kwargs['episodes'] 346 del kwargs['episodes'] 347 348 gmListWidgets.cGenericListSelectorDlg.__init__(self, *args, **kwargs) 349 350 self.SetTitle(_('Select the episodes you are interested in ...')) 351 self._LCTRL_items.set_columns([_('Episode'), _('Status'), _('Health Issue')]) 352 self._LCTRL_items.set_string_items ( 353 items = [ 354 [ epi['description'], 355 gmTools.bool2str(epi['episode_open'], _('ongoing'), ''), 356 gmTools.coalesce(epi['health_issue'], '') 357 ] 358 for epi in episodes ] 359 ) 360 self._LCTRL_items.set_column_widths() 361 self._LCTRL_items.set_data(data = episodes)
362 363 #----------------------------------------------------------------
364 -class cEpisodeDescriptionPhraseWheel(gmPhraseWheel.cPhraseWheel):
365 """Let user select an episode *description*. 366 367 The user can select an episode description from the previously 368 used descriptions across all episodes across all patients. 369 370 Selection is done with a phrasewheel so the user can 371 type the episode name and matches will be shown. Typing 372 "*" will show the entire list of episodes. 373 374 If the user types a description not existing yet a 375 new episode description will be returned. 376 """
377 - def __init__(self, *args, **kwargs):
378 379 mp = gmMatchProvider.cMatchProvider_SQL2 ( 380 queries = [ 381 """ 382 SELECT DISTINCT ON (description) 383 description 384 AS data, 385 description 386 AS field_label, 387 description || ' (' 388 || CASE 389 WHEN is_open IS TRUE THEN _('ongoing') 390 ELSE _('closed') 391 END 392 || ')' 393 AS list_label 394 FROM 395 clin.episode 396 WHERE 397 description %(fragment_condition)s 398 ORDER BY description 399 LIMIT 30 400 """ 401 ] 402 ) 403 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 404 self.matcher = mp
405 406 #----------------------------------------------------------------
407 -class cEpisodeSelectionPhraseWheel(gmPhraseWheel.cPhraseWheel):
408 """Let user select an episode. 409 410 The user can select an episode from the existing episodes of a 411 patient. Selection is done with a phrasewheel so the user 412 can type the episode name and matches will be shown. Typing 413 "*" will show the entire list of episodes. Closed episodes 414 will be marked as such. If the user types an episode name not 415 in the list of existing episodes a new episode can be created 416 from it if the programmer activated that feature. 417 418 If keyword <patient_id> is set to None or left out the control 419 will listen to patient change signals and therefore act on 420 gmPerson.gmCurrentPatient() changes. 421 """
422 - def __init__(self, *args, **kwargs):
423 try: 424 self.__patient_id = int(kwargs['patient_id']) 425 self.use_current_patient = False 426 del kwargs['patient_id'] 427 except KeyError: 428 self.__patient_id = None 429 self.use_current_patient = True 430 431 mp = gmEMRStructItems.cEpisodeMatchProvider() 432 if self.use_current_patient: 433 self.__register_patient_change_signals() 434 pat = gmPerson.gmCurrentPatient() 435 if pat.connected: 436 mp.set_context('pat', pat.ID) 437 else: 438 mp.set_context('pat', self.__patient_id) 439 440 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 441 442 self.matcher = mp
443 444 #-------------------------------------------------------- 445 # external API 446 #--------------------------------------------------------
447 - def set_patient(self, patient_id=None):
448 if self.use_current_patient: 449 return False 450 self.__patient_id = int(patient_id) 451 self.set_context('pat', self.__patient_id) 452 return True
453 454 #--------------------------------------------------------
455 - def GetData(self, can_create=False, as_instance=False, is_open=False):
456 self.__is_open_for_create_data = is_open # used (only) in _create_data() 457 return gmPhraseWheel.cPhraseWheel.GetData(self, can_create = can_create, as_instance = as_instance)
458 459 #--------------------------------------------------------
460 - def _create_data(self):
461 462 epi_name = self.GetValue().strip() 463 if epi_name == '': 464 gmDispatcher.send(signal = 'statustext', msg = _('Cannot create episode without name.'), beep = True) 465 _log.debug('cannot create episode without name') 466 return 467 468 if self.use_current_patient: 469 pat = gmPerson.gmCurrentPatient() 470 else: 471 pat = gmPerson.cPatient(aPK_obj = self.__patient_id) 472 473 emr = pat.emr 474 epi = emr.add_episode(episode_name = epi_name, is_open = self.__is_open_for_create_data) 475 if epi is None: 476 self.data = {} 477 else: 478 self.SetText ( 479 value = epi_name, 480 data = epi['pk_episode'] 481 )
482 483 #--------------------------------------------------------
484 - def _data2instance(self):
485 return gmEMRStructItems.cEpisode(aPK_obj = self.GetData())
486 487 #-------------------------------------------------------- 488 # internal API 489 #--------------------------------------------------------
491 gmDispatcher.connect(self._pre_patient_unselection, 'pre_patient_unselection') 492 gmDispatcher.connect(self._post_patient_selection, 'post_patient_selection')
493 494 #--------------------------------------------------------
495 - def _pre_patient_unselection(self):
496 self.__patient_id = None 497 self.unset_context('pat') 498 self.SetData() 499 return True
500 501 #--------------------------------------------------------
502 - def _post_patient_selection(self):
503 if self.use_current_patient: 504 patient = gmPerson.gmCurrentPatient() 505 self.set_context('pat', patient.ID) 506 return True
507 508 #---------------------------------------------------------------- 509 from Gnumed.wxGladeWidgets import wxgEpisodeEditAreaPnl 510
511 -class cEpisodeEditAreaPnl(gmEditArea.cGenericEditAreaMixin, wxgEpisodeEditAreaPnl.wxgEpisodeEditAreaPnl):
512
513 - def __init__(self, *args, **kwargs):
514 515 try: 516 episode = kwargs['episode'] 517 del kwargs['episode'] 518 except KeyError: 519 episode = None 520 521 wxgEpisodeEditAreaPnl.wxgEpisodeEditAreaPnl.__init__(self, *args, **kwargs) 522 gmEditArea.cGenericEditAreaMixin.__init__(self) 523 524 self.data = episode
525 526 #---------------------------------------------------------------- 527 # generic Edit Area mixin API 528 #----------------------------------------------------------------
529 - def _valid_for_save(self):
530 531 errors = False 532 533 if len(self._PRW_description.GetValue().strip()) == 0: 534 errors = True 535 self._PRW_description.display_as_valid(False) 536 self._PRW_description.SetFocus() 537 else: 538 self._PRW_description.display_as_valid(True) 539 self._PRW_description.Refresh() 540 541 return not errors
542 543 #----------------------------------------------------------------
544 - def _save_as_new(self):
545 546 pat = gmPerson.gmCurrentPatient() 547 emr = pat.emr 548 549 epi = emr.add_episode(episode_name = self._PRW_description.GetValue().strip()) 550 epi['summary'] = self._TCTRL_status.GetValue().strip() 551 epi['episode_open'] = not self._CHBOX_closed.IsChecked() 552 epi['diagnostic_certainty_classification'] = self._PRW_certainty.GetData() 553 554 issue_name = self._PRW_issue.GetValue().strip() 555 if len(issue_name) != 0: 556 epi['pk_health_issue'] = self._PRW_issue.GetData(can_create = True) 557 issue = gmEMRStructItems.cHealthIssue(aPK_obj = epi['pk_health_issue']) 558 559 if not move_episode_to_issue(episode = epi, target_issue = issue, save_to_backend = False): 560 gmDispatcher.send ( 561 signal = 'statustext', 562 msg = _('Cannot attach episode [%s] to health issue [%s] because it already has a running episode.') % ( 563 epi['description'], 564 issue['description'] 565 ) 566 ) 567 gmEMRStructItems.delete_episode(episode = epi) 568 return False 569 570 epi.save() 571 572 epi.generic_codes = [ c['data'] for c in self._PRW_codes.GetData() ] 573 574 self.data = epi 575 return True
576 577 #----------------------------------------------------------------
578 - def _save_as_update(self):
579 580 self.data['description'] = self._PRW_description.GetValue().strip() 581 self.data['summary'] = self._TCTRL_status.GetValue().strip() 582 self.data['episode_open'] = not self._CHBOX_closed.IsChecked() 583 self.data['diagnostic_certainty_classification'] = self._PRW_certainty.GetData() 584 585 issue_name = self._PRW_issue.GetValue().strip() 586 if len(issue_name) == 0: 587 self.data['pk_health_issue'] = None 588 else: 589 self.data['pk_health_issue'] = self._PRW_issue.GetData(can_create = True) 590 issue = gmEMRStructItems.cHealthIssue(aPK_obj = self.data['pk_health_issue']) 591 592 if not move_episode_to_issue(episode = self.data, target_issue = issue, save_to_backend = False): 593 gmDispatcher.send ( 594 signal = 'statustext', 595 msg = _('Cannot attach episode [%s] to health issue [%s] because it already has a running episode.') % ( 596 self.data['description'], 597 issue['description'] 598 ) 599 ) 600 return False 601 602 self.data.save() 603 self.data.generic_codes = [ c['data'] for c in self._PRW_codes.GetData() ] 604 605 return True
606 607 #----------------------------------------------------------------
608 - def _refresh_as_new(self):
609 if self.data is None: 610 ident = gmPerson.gmCurrentPatient() 611 else: 612 ident = gmPerson.cPerson(aPK_obj = self.data['pk_patient']) 613 self._TCTRL_patient.SetValue(ident.get_description_gender()) 614 self._PRW_issue.SetText() 615 self._PRW_description.SetText() 616 self._TCTRL_status.SetValue('') 617 self._PRW_certainty.SetText() 618 self._CHBOX_closed.SetValue(False) 619 self._PRW_codes.SetText() 620 621 self._PRW_issue.SetFocus()
622 623 #----------------------------------------------------------------
624 - def _refresh_from_existing(self):
625 ident = gmPerson.cPerson(aPK_obj = self.data['pk_patient']) 626 self._TCTRL_patient.SetValue(ident.get_description_gender()) 627 628 if self.data['pk_health_issue'] is not None: 629 self._PRW_issue.SetText ( 630 self.data['health_issue'], 631 data = self.data['pk_health_issue'] 632 ) 633 634 self._PRW_description.SetText ( 635 self.data['description'], 636 data = self.data['description'] 637 ) 638 639 self._TCTRL_status.SetValue(gmTools.coalesce(self.data['summary'], '')) 640 641 if self.data['diagnostic_certainty_classification'] is not None: 642 self._PRW_certainty.SetData(data = self.data['diagnostic_certainty_classification']) 643 644 self._CHBOX_closed.SetValue(not self.data['episode_open']) 645 646 val, data = self._PRW_codes.generic_linked_codes2item_dict(self.data.generic_codes) 647 self._PRW_codes.SetText(val, data) 648 649 if self.data['pk_health_issue'] is None: 650 self._PRW_issue.SetFocus() 651 else: 652 self._PRW_description.SetFocus()
653 654 #----------------------------------------------------------------
656 self._refresh_as_new()
657 658 #================================================================ 659 # health issue related widgets/functions 660 #----------------------------------------------------------------
661 -def edit_health_issue(parent=None, issue=None, single_entry=False):
662 ea = cHealthIssueEditAreaPnl(parent, -1) 663 ea.data = issue 664 ea.mode = gmTools.coalesce(issue, 'new', 'edit') 665 dlg = gmEditArea.cGenericEditAreaDlg2(parent, -1, edit_area = ea, single_entry = single_entry) 666 dlg.SetTitle(gmTools.coalesce(issue, _('Adding a new health issue'), _('Editing a health issue'))) 667 if dlg.ShowModal() == wx.ID_OK: 668 dlg.DestroyLater() 669 return True 670 dlg.DestroyLater() 671 return False
672 673 #----------------------------------------------------------------
674 -def select_health_issues(parent=None, emr=None):
675 676 if parent is None: 677 parent = wx.GetApp().GetTopWindow() 678 #----------------------------------------- 679 def edit(issue=None): 680 return edit_health_issue(parent = parent, issue = issue)
681 #----------------------------------------- 682 def delete(issue=None): 683 if gmEMRStructItems.delete_health_issue(health_issue = issue): 684 return True 685 gmDispatcher.send ( 686 signal = 'statustext', 687 msg = _('Cannot delete health issue.'), 688 beep = True 689 ) 690 return False 691 #----------------------------------------- 692 def get_tooltip(data): 693 if data is None: 694 return None 695 patient = gmPerson.cPatient(data['pk_patient']) 696 return data.format ( 697 patient = patient, 698 with_summary = True, 699 with_codes = True, 700 with_episodes = True, 701 with_encounters = True, 702 with_medications = False, 703 with_hospital_stays = False, 704 with_procedures = False, 705 with_family_history = False, 706 with_documents = False, 707 with_tests = False, 708 with_vaccinations = False 709 ) 710 #----------------------------------------- 711 def refresh(lctrl): 712 issues = emr.get_health_issues() 713 items = [ 714 [ 715 gmTools.bool2subst(i['is_confidential'], _('CONFIDENTIAL'), '', ''), 716 i['description'], 717 gmTools.bool2subst(i['clinically_relevant'], _('relevant'), '', ''), 718 gmTools.bool2subst(i['is_active'], _('active'), '', ''), 719 gmTools.bool2subst(i['is_cause_of_death'], _('fatal'), '', '') 720 ] for i in issues 721 ] 722 lctrl.set_string_items(items = items) 723 lctrl.set_data(data = issues) 724 #----------------------------------------- 725 return gmListWidgets.get_choices_from_list ( 726 parent = parent, 727 msg = _('\nSelect the health issues !\n'), 728 caption = _('Showing health issues ...'), 729 columns = ['', _('Health issue'), '', '', ''], 730 single_selection = False, 731 edit_callback = edit, 732 new_callback = edit, 733 delete_callback = delete, 734 refresh_callback = refresh 735 ) 736 #----------------------------------------------------------------
737 -class cIssueListSelectorDlg(gmListWidgets.cGenericListSelectorDlg):
738 739 # FIXME: support pre-selection 740
741 - def __init__(self, *args, **kwargs):
742 743 issues = kwargs['issues'] 744 del kwargs['issues'] 745 746 gmListWidgets.cGenericListSelectorDlg.__init__(self, *args, **kwargs) 747 748 self.SetTitle(_('Select the health issues you are interested in ...')) 749 self._LCTRL_items.set_columns(['', _('Health Issue'), '', '', '']) 750 751 for issue in issues: 752 if issue['is_confidential']: 753 row_num = self._LCTRL_items.InsertItem(sys.maxsize, label = _('confidential')) 754 self._LCTRL_items.SetItemTextColour(row_num, wx.Colour('RED')) 755 else: 756 row_num = self._LCTRL_items.InsertItem(sys.maxsize, label = '') 757 758 self._LCTRL_items.SetItem(index = row_num, column = 1, label = issue['description']) 759 if issue['clinically_relevant']: 760 self._LCTRL_items.SetItem(index = row_num, column = 2, label = _('relevant')) 761 if issue['is_active']: 762 self._LCTRL_items.SetItem(index = row_num, column = 3, label = _('active')) 763 if issue['is_cause_of_death']: 764 self._LCTRL_items.SetItem(index = row_num, column = 4, label = _('fatal')) 765 766 self._LCTRL_items.set_column_widths() 767 self._LCTRL_items.set_data(data = issues)
768 769 #----------------------------------------------------------------
770 -class cIssueSelectionPhraseWheel(gmPhraseWheel.cPhraseWheel):
771 """Let the user select a health issue. 772 773 The user can select a health issue from the existing issues 774 of a patient. Selection is done with a phrasewheel so the user 775 can type the issue name and matches will be shown. Typing 776 "*" will show the entire list of issues. Inactive issues 777 will be marked as such. If the user types an issue name not 778 in the list of existing issues a new issue can be created 779 from it if the programmer activated that feature. 780 781 If keyword <patient_id> is set to None or left out the control 782 will listen to patient change signals and therefore act on 783 gmPerson.gmCurrentPatient() changes. 784 """
785 - def __init__(self, *args, **kwargs):
786 787 ctxt = {'ctxt_pat': {'where_part': 'pk_patient=%(pat)s', 'placeholder': 'pat'}} 788 789 mp = gmMatchProvider.cMatchProvider_SQL2 ( 790 # FIXME: consider clin.health_issue.clinically_relevant 791 queries = [""" 792 SELECT 793 data, 794 field_label, 795 list_label 796 FROM (( 797 SELECT 798 pk_health_issue AS data, 799 description AS field_label, 800 description AS list_label 801 FROM clin.v_health_issues 802 WHERE 803 is_active IS true 804 AND 805 description %(fragment_condition)s 806 AND 807 %(ctxt_pat)s 808 809 ) UNION ( 810 811 SELECT 812 pk_health_issue AS data, 813 description AS field_label, 814 description || _(' (inactive)') AS list_label 815 FROM clin.v_health_issues 816 WHERE 817 is_active IS false 818 AND 819 description %(fragment_condition)s 820 AND 821 %(ctxt_pat)s 822 )) AS union_query 823 ORDER BY 824 list_label""" 825 ], 826 context = ctxt 827 ) 828 try: kwargs['patient_id'] 829 except KeyError: kwargs['patient_id'] = None 830 831 if kwargs['patient_id'] is None: 832 self.use_current_patient = True 833 self.__register_patient_change_signals() 834 pat = gmPerson.gmCurrentPatient() 835 if pat.connected: 836 mp.set_context('pat', pat.ID) 837 else: 838 self.use_current_patient = False 839 self.__patient_id = int(kwargs['patient_id']) 840 mp.set_context('pat', self.__patient_id) 841 842 del kwargs['patient_id'] 843 844 gmPhraseWheel.cPhraseWheel.__init__ ( 845 self, 846 *args, 847 **kwargs 848 ) 849 self.matcher = mp
850 #-------------------------------------------------------- 851 # external API 852 #--------------------------------------------------------
853 - def set_patient(self, patient_id=None):
854 if self.use_current_patient: 855 return False 856 self.__patient_id = int(patient_id) 857 self.set_context('pat', self.__patient_id) 858 return True
859 #--------------------------------------------------------
860 - def _create_data(self):
861 issue_name = self.GetValue().strip() 862 if issue_name == '': 863 gmDispatcher.send(signal = 'statustext', msg = _('Cannot create health issue without name.'), beep = True) 864 _log.debug('cannot create health issue without name') 865 return 866 867 if self.use_current_patient: 868 pat = gmPerson.gmCurrentPatient() 869 else: 870 pat = gmPerson.cPatient(aPK_obj = self.__patient_id) 871 872 emr = pat.emr 873 issue = emr.add_health_issue(issue_name = issue_name) 874 875 if issue is None: 876 self.data = {} 877 else: 878 self.SetText ( 879 value = issue_name, 880 data = issue['pk_health_issue'] 881 )
882 #--------------------------------------------------------
883 - def _data2instance(self):
884 return gmEMRStructItems.cHealthIssue(aPK_obj = self.GetData())
885 #--------------------------------------------------------
886 - def _get_data_tooltip(self):
887 if self.GetData() is None: 888 return None 889 issue = self._data2instance() 890 if issue is None: 891 return None 892 return issue.format ( 893 patient = None, 894 with_summary = True, 895 with_codes = False, 896 with_episodes = True, 897 with_encounters = True, 898 with_medications = False, 899 with_hospital_stays = False, 900 with_procedures = False, 901 with_family_history = False, 902 with_documents = False, 903 with_tests = False, 904 with_vaccinations = False, 905 with_external_care = True 906 )
907 #-------------------------------------------------------- 908 # internal API 909 #--------------------------------------------------------
911 gmDispatcher.connect(self._pre_patient_unselection, 'pre_patient_unselection') 912 gmDispatcher.connect(self._post_patient_selection, 'post_patient_selection')
913 #--------------------------------------------------------
914 - def _pre_patient_unselection(self):
915 return True
916 #--------------------------------------------------------
917 - def _post_patient_selection(self):
918 if self.use_current_patient: 919 patient = gmPerson.gmCurrentPatient() 920 self.set_context('pat', patient.ID) 921 return True
922 #------------------------------------------------------------ 923 from Gnumed.wxGladeWidgets import wxgIssueSelectionDlg 924
925 -class cIssueSelectionDlg(wxgIssueSelectionDlg.wxgIssueSelectionDlg):
926
927 - def __init__(self, *args, **kwargs):
928 try: 929 msg = kwargs['message'] 930 except KeyError: 931 msg = None 932 del kwargs['message'] 933 wxgIssueSelectionDlg.wxgIssueSelectionDlg.__init__(self, *args, **kwargs) 934 if msg is not None: 935 self._lbl_message.SetLabel(label=msg)
936 #--------------------------------------------------------
937 - def _on_OK_button_pressed(self, event):
938 event.Skip() 939 pk_issue = self._PhWheel_issue.GetData(can_create=True) 940 if pk_issue is None: 941 gmGuiHelpers.gm_show_error ( 942 _('Cannot create new health issue:\n [%(issue)s]') % {'issue': self._PhWheel_issue.GetValue().strip()}, 943 _('Selecting health issue') 944 ) 945 return False 946 return True
947 #------------------------------------------------------------ 948 from Gnumed.wxGladeWidgets import wxgHealthIssueEditAreaPnl 949
950 -class cHealthIssueEditAreaPnl(gmEditArea.cGenericEditAreaMixin, wxgHealthIssueEditAreaPnl.wxgHealthIssueEditAreaPnl):
951 """Panel encapsulating health issue edit area functionality.""" 952
953 - def __init__(self, *args, **kwargs):
954 955 try: 956 data = kwargs['issue'] 957 del kwargs['issue'] 958 except KeyError: 959 data = None 960 961 wxgHealthIssueEditAreaPnl.wxgHealthIssueEditAreaPnl.__init__(self, *args, **kwargs) 962 gmEditArea.cGenericEditAreaMixin.__init__(self) 963 964 self.mode = 'new' 965 self.data = data 966 if data is not None: 967 self.mode = 'edit' 968 969 self.__init_ui()
970 #----------------------------------------------------------------
971 - def __init_ui(self):
972 973 # FIXME: include more sources: coding systems/other database columns 974 mp = gmMatchProvider.cMatchProvider_SQL2 ( 975 queries = ["SELECT DISTINCT ON (description) description, description FROM clin.health_issue WHERE description %(fragment_condition)s LIMIT 50"] 976 ) 977 mp.setThresholds(1, 3, 5) 978 self._PRW_condition.matcher = mp 979 980 mp = gmMatchProvider.cMatchProvider_SQL2 ( 981 queries = [""" 982 SELECT DISTINCT ON (grouping) grouping, grouping from ( 983 984 SELECT rank, grouping from (( 985 986 SELECT 987 grouping, 988 1 as rank 989 from 990 clin.health_issue 991 where 992 grouping %%(fragment_condition)s 993 and 994 (SELECT True from clin.encounter where fk_patient = %s and pk = clin.health_issue.fk_encounter) 995 996 ) union ( 997 998 SELECT 999 grouping, 1000 2 as rank 1001 from 1002 clin.health_issue 1003 where 1004 grouping %%(fragment_condition)s 1005 1006 )) as union_result 1007 1008 order by rank 1009 1010 ) as order_result 1011 1012 limit 50""" % gmPerson.gmCurrentPatient().ID 1013 ] 1014 ) 1015 mp.setThresholds(1, 3, 5) 1016 self._PRW_grouping.matcher = mp 1017 1018 self._PRW_age_noted.add_callback_on_lose_focus(self._on_leave_age_noted) 1019 self._PRW_year_noted.add_callback_on_lose_focus(self._on_leave_year_noted) 1020 1021 # self._PRW_age_noted.add_callback_on_modified(self._on_modified_age_noted) 1022 # self._PRW_year_noted.add_callback_on_modified(self._on_modified_year_noted) 1023 1024 self._PRW_year_noted.Enable(True) 1025 1026 self._PRW_codes.add_callback_on_lose_focus(self._on_leave_codes)
1027 1028 #---------------------------------------------------------------- 1029 # generic Edit Area mixin API 1030 #----------------------------------------------------------------
1031 - def _valid_for_save(self):
1032 1033 if self._PRW_condition.GetValue().strip() == '': 1034 self._PRW_condition.display_as_valid(False) 1035 self._PRW_condition.SetFocus() 1036 return False 1037 self._PRW_condition.display_as_valid(True) 1038 self._PRW_condition.Refresh() 1039 1040 # FIXME: sanity check age/year diagnosed 1041 age_noted = self._PRW_age_noted.GetValue().strip() 1042 if age_noted != '': 1043 if gmDateTime.str2interval(str_interval = age_noted) is None: 1044 self._PRW_age_noted.display_as_valid(False) 1045 self._PRW_age_noted.SetFocus() 1046 return False 1047 self._PRW_age_noted.display_as_valid(True) 1048 return True
1049 1050 #----------------------------------------------------------------
1051 - def _save_as_new(self):
1052 pat = gmPerson.gmCurrentPatient() 1053 emr = pat.emr 1054 1055 issue = emr.add_health_issue(issue_name = self._PRW_condition.GetValue().strip()) 1056 1057 side = '' 1058 if self._ChBOX_left.GetValue(): 1059 side += 's' 1060 if self._ChBOX_right.GetValue(): 1061 side += 'd' 1062 issue['laterality'] = side 1063 1064 issue['summary'] = self._TCTRL_status.GetValue().strip() 1065 issue['diagnostic_certainty_classification'] = self._PRW_certainty.GetData() 1066 issue['grouping'] = self._PRW_grouping.GetValue().strip() 1067 issue['is_active'] = self._ChBOX_active.GetValue() 1068 issue['clinically_relevant'] = self._ChBOX_relevant.GetValue() 1069 issue['is_confidential'] = self._ChBOX_confidential.GetValue() 1070 issue['is_cause_of_death'] = self._ChBOX_caused_death.GetValue() 1071 1072 age_noted = self._PRW_age_noted.GetData() 1073 if age_noted is not None: 1074 issue['age_noted'] = age_noted 1075 1076 issue.save() 1077 1078 issue.generic_codes = [ c['data'] for c in self._PRW_codes.GetData() ] 1079 1080 self.data = issue 1081 return True
1082 #----------------------------------------------------------------
1083 - def _save_as_update(self):
1084 1085 self.data['description'] = self._PRW_condition.GetValue().strip() 1086 1087 side = '' 1088 if self._ChBOX_left.GetValue(): 1089 side += 's' 1090 if self._ChBOX_right.GetValue(): 1091 side += 'd' 1092 self.data['laterality'] = side 1093 1094 self.data['summary'] = self._TCTRL_status.GetValue().strip() 1095 self.data['diagnostic_certainty_classification'] = self._PRW_certainty.GetData() 1096 self.data['grouping'] = self._PRW_grouping.GetValue().strip() 1097 self.data['is_active'] = bool(self._ChBOX_active.GetValue()) 1098 self.data['clinically_relevant'] = bool(self._ChBOX_relevant.GetValue()) 1099 self.data['is_confidential'] = bool(self._ChBOX_confidential.GetValue()) 1100 self.data['is_cause_of_death'] = bool(self._ChBOX_caused_death.GetValue()) 1101 1102 age_noted = self._PRW_age_noted.GetData() 1103 if age_noted is not None: 1104 self.data['age_noted'] = age_noted 1105 1106 self.data.save() 1107 self.data.generic_codes = [ c['data'] for c in self._PRW_codes.GetData() ] 1108 1109 return True
1110 #----------------------------------------------------------------
1111 - def _refresh_as_new(self):
1112 self._PRW_condition.SetText() 1113 self._ChBOX_left.SetValue(0) 1114 self._ChBOX_right.SetValue(0) 1115 self._PRW_codes.SetText() 1116 self._on_leave_codes() 1117 self._PRW_certainty.SetText() 1118 self._PRW_grouping.SetText() 1119 self._TCTRL_status.SetValue('') 1120 self._PRW_age_noted.SetText() 1121 self._PRW_year_noted.SetText() 1122 self._ChBOX_active.SetValue(1) 1123 self._ChBOX_relevant.SetValue(1) 1124 self._ChBOX_confidential.SetValue(0) 1125 self._ChBOX_caused_death.SetValue(0) 1126 1127 self._PRW_condition.SetFocus() 1128 return True
1129 #----------------------------------------------------------------
1130 - def _refresh_from_existing(self):
1131 self._PRW_condition.SetText(self.data['description']) 1132 1133 lat = gmTools.coalesce(self.data['laterality'], '') 1134 if lat.find('s') == -1: 1135 self._ChBOX_left.SetValue(0) 1136 else: 1137 self._ChBOX_left.SetValue(1) 1138 if lat.find('d') == -1: 1139 self._ChBOX_right.SetValue(0) 1140 else: 1141 self._ChBOX_right.SetValue(1) 1142 1143 val, data = self._PRW_codes.generic_linked_codes2item_dict(self.data.generic_codes) 1144 self._PRW_codes.SetText(val, data) 1145 self._on_leave_codes() 1146 1147 if self.data['diagnostic_certainty_classification'] is not None: 1148 self._PRW_certainty.SetData(data = self.data['diagnostic_certainty_classification']) 1149 self._PRW_grouping.SetText(gmTools.coalesce(self.data['grouping'], '')) 1150 self._TCTRL_status.SetValue(gmTools.coalesce(self.data['summary'], '')) 1151 1152 if self.data['age_noted'] is None: 1153 self._PRW_age_noted.SetText() 1154 else: 1155 self._PRW_age_noted.SetText ( 1156 value = '%sd' % self.data['age_noted'].days, 1157 data = self.data['age_noted'] 1158 ) 1159 1160 self._ChBOX_active.SetValue(self.data['is_active']) 1161 self._ChBOX_relevant.SetValue(self.data['clinically_relevant']) 1162 self._ChBOX_confidential.SetValue(self.data['is_confidential']) 1163 self._ChBOX_caused_death.SetValue(self.data['is_cause_of_death']) 1164 1165 self._TCTRL_status.SetFocus() 1166 1167 return True
1168 #----------------------------------------------------------------
1170 return self._refresh_as_new()
1171 #-------------------------------------------------------- 1172 # internal helpers 1173 #--------------------------------------------------------
1174 - def _on_leave_codes(self, *args, **kwargs):
1175 if not self._PRW_codes.IsModified(): 1176 return True 1177 1178 self._TCTRL_code_details.SetValue('- ' + '\n- '.join([ c['list_label'] for c in self._PRW_codes.GetData() ]))
1179 #--------------------------------------------------------
1180 - def _on_leave_age_noted(self, *args, **kwargs):
1181 1182 if not self._PRW_age_noted.IsModified(): 1183 return True 1184 1185 age_str = self._PRW_age_noted.GetValue().strip() 1186 1187 if age_str == '': 1188 return True 1189 1190 issue_age = gmDateTime.str2interval(str_interval = age_str) 1191 1192 if issue_age is None: 1193 self.StatusText = _('Cannot parse [%s] into valid interval.') % age_str 1194 self._PRW_age_noted.display_as_valid(False) 1195 return True 1196 1197 pat = gmPerson.gmCurrentPatient() 1198 if pat['dob'] is not None: 1199 max_issue_age = pydt.datetime.now(tz=pat['dob'].tzinfo) - pat['dob'] 1200 if issue_age >= max_issue_age: 1201 self.StatusText = _('Health issue cannot have been noted at age %s. Patient is only %s old.') % (issue_age, pat.get_medical_age()) 1202 self._PRW_age_noted.display_as_valid(False) 1203 return True 1204 1205 self._PRW_age_noted.display_as_valid(True) 1206 self._PRW_age_noted.SetText(value = age_str, data = issue_age) 1207 1208 if pat['dob'] is not None: 1209 fts = gmDateTime.cFuzzyTimestamp ( 1210 timestamp = pat['dob'] + issue_age, 1211 accuracy = gmDateTime.acc_months 1212 ) 1213 self._PRW_year_noted.SetText(value = str(fts), data = fts) 1214 1215 return True
1216 #--------------------------------------------------------
1217 - def _on_leave_year_noted(self, *args, **kwargs):
1218 1219 if not self._PRW_year_noted.IsModified(): 1220 return True 1221 1222 year_noted = self._PRW_year_noted.GetData() 1223 1224 if year_noted is None: 1225 if self._PRW_year_noted.GetValue().strip() == '': 1226 self._PRW_year_noted.display_as_valid(True) 1227 return True 1228 self._PRW_year_noted.display_as_valid(False) 1229 return True 1230 1231 year_noted = year_noted.get_pydt() 1232 1233 if year_noted >= pydt.datetime.now(tz = year_noted.tzinfo): 1234 self.StatusText = _('Condition diagnosed in the future.') 1235 self._PRW_year_noted.display_as_valid(False) 1236 return True 1237 1238 self._PRW_year_noted.display_as_valid(True) 1239 1240 pat = gmPerson.gmCurrentPatient() 1241 if pat['dob'] is not None: 1242 issue_age = year_noted - pat['dob'] 1243 age_str = gmDateTime.format_interval_medically(interval = issue_age) 1244 self._PRW_age_noted.SetText(age_str, issue_age, True) 1245 1246 return True
1247 #--------------------------------------------------------
1248 - def _on_modified_age_noted(self, *args, **kwargs):
1249 wx.CallAfter(self._PRW_year_noted.SetText, '', None, True) 1250 return True
1251 #--------------------------------------------------------
1252 - def _on_modified_year_noted(self, *args, **kwargs):
1253 wx.CallAfter(self._PRW_age_noted.SetText, '', None, True) 1254 return True
1255 1256 #================================================================ 1257 # diagnostic certainty related widgets/functions 1258 #----------------------------------------------------------------
1259 -class cDiagnosticCertaintyClassificationPhraseWheel(gmPhraseWheel.cPhraseWheel):
1260
1261 - def __init__(self, *args, **kwargs):
1262 1263 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 1264 1265 self.selection_only = False # can be NULL, too 1266 1267 mp = gmMatchProvider.cMatchProvider_FixedList ( 1268 aSeq = [ 1269 {'data': 'A', 'list_label': gmEMRStructItems.diagnostic_certainty_classification2str('A'), 'field_label': gmEMRStructItems.diagnostic_certainty_classification2str('A'), 'weight': 1}, 1270 {'data': 'B', 'list_label': gmEMRStructItems.diagnostic_certainty_classification2str('B'), 'field_label': gmEMRStructItems.diagnostic_certainty_classification2str('B'), 'weight': 1}, 1271 {'data': 'C', 'list_label': gmEMRStructItems.diagnostic_certainty_classification2str('C'), 'field_label': gmEMRStructItems.diagnostic_certainty_classification2str('C'), 'weight': 1}, 1272 {'data': 'D', 'list_label': gmEMRStructItems.diagnostic_certainty_classification2str('D'), 'field_label': gmEMRStructItems.diagnostic_certainty_classification2str('D'), 'weight': 1} 1273 ] 1274 ) 1275 mp.setThresholds(1, 2, 4) 1276 self.matcher = mp 1277 1278 self.SetToolTip(_( 1279 "The diagnostic classification or grading of this assessment.\n" 1280 "\n" 1281 "This documents how certain one is about this being a true diagnosis." 1282 ))
1283 1284 #================================================================ 1285 # MAIN 1286 #---------------------------------------------------------------- 1287 if __name__ == '__main__': 1288 1289 if len(sys.argv) < 2: 1290 sys.exit() 1291 1292 if sys.argv[1] != 'test': 1293 sys.exit() 1294 1295 from Gnumed.business import gmPersonSearch 1296 from Gnumed.wxpython import gmPatSearchWidgets 1297 1298 #================================================================
1299 - class testapp (wx.App):
1300 """ 1301 Test application for testing EMR struct widgets 1302 """ 1303 #--------------------------------------------------------
1304 - def OnInit (self):
1305 """ 1306 Create test application UI 1307 """ 1308 frame = wx.Frame ( 1309 None, 1310 -4, 1311 'Testing EMR struct widgets', 1312 size=wx.Size(600, 400), 1313 style=wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE 1314 ) 1315 filemenu = wx.Menu() 1316 filemenu.AppendSeparator() 1317 item = filemenu.Append(ID_EXIT, "E&xit"," Terminate test application") 1318 self.Bind(wx.EVT_MENU, self.OnCloseWindow, item) 1319 1320 # Creating the menubar. 1321 menuBar = wx.MenuBar() 1322 menuBar.Append(filemenu,"&File") 1323 1324 frame.SetMenuBar(menuBar) 1325 1326 txt = wx.StaticText( frame, -1, _("Select desired test option from the 'File' menu"), 1327 wx.DefaultPosition, wx.DefaultSize, 0 ) 1328 1329 # patient EMR 1330 self.__pat = gmPerson.gmCurrentPatient() 1331 1332 frame.Show(1) 1333 return 1
1334 #--------------------------------------------------------
1335 - def OnCloseWindow (self, e):
1336 """ 1337 Close test aplication 1338 """ 1339 self.ExitMainLoop ()
1340 1341 #----------------------------------------------------------------
1342 - def test_epsiode_edit_area_pnl():
1343 app = wx.PyWidgetTester(size = (200, 300)) 1344 emr = pat.emr 1345 epi = emr.get_episodes()[0] 1346 pnl = cEpisodeEditAreaPnl(app.frame, -1, episode=epi) 1347 app.frame.Show(True) 1348 app.MainLoop()
1349 #----------------------------------------------------------------
1350 - def test_episode_edit_area_dialog():
1351 app = wx.PyWidgetTester(size = (200, 300)) 1352 emr = pat.emr 1353 epi = emr.get_episodes()[0] 1354 edit_episode(parent=app.frame, episode=epi)
1355 1356 #----------------------------------------------------------------
1357 - def test_episode_selection_prw():
1358 frame = wx.Frame() 1359 wx.GetApp().SetTopWindow(frame) 1360 prw = cEpisodeSelectionPhraseWheel(frame) 1361 #app.SetWidget() 1362 # app.SetWidget(cEpisodeSelectionPhraseWheel, id=-1, size=(350,20), pos=(10,20), patient_id=pat.ID) 1363 frame.Show(True) 1364 wx.GetApp().MainLoop()
1365 1366 #----------------------------------------------------------------
1367 - def test_health_issue_edit_area_dlg():
1368 app = wx.PyWidgetTester(size = (200, 300)) 1369 edit_health_issue(parent=app.frame, issue=None)
1370 1371 #----------------------------------------------------------------
1372 - def test_health_issue_edit_area_pnl():
1373 app = wx.PyWidgetTester(size = (200, 300)) 1374 app.SetWidget(cHealthIssueEditAreaPnl, id=-1, size = (400,400)) 1375 app.MainLoop()
1376 1377 #================================================================ 1378 1379 branch = gmPraxis.get_praxis_branches()[0] 1380 prax = gmPraxis.gmCurrentPraxisBranch(branch) 1381 print(prax) 1382 1383 #app = wx.PyWidgetTester(size = (400, 40)) 1384 app = wx.App()#size = (400, 40)) 1385 1386 # obtain patient 1387 pat = gmPersonSearch.ask_for_patient() 1388 if pat is None: 1389 print("No patient. Exiting gracefully...") 1390 sys.exit(0) 1391 gmPatSearchWidgets.set_active_patient(patient=pat) 1392 1393 # try: 1394 # lauch emr dialogs test application 1395 # app = testapp(0) 1396 # app.MainLoop() 1397 # except Exception: 1398 # _log.exception("unhandled exception caught !") 1399 # but re-raise them 1400 # raise 1401 1402 #test_epsiode_edit_area_pnl() 1403 #test_episode_edit_area_dialog() 1404 #test_health_issue_edit_area_dlg() 1405 test_episode_selection_prw() 1406