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  from Gnumed.pycommon import gmI18N 
  28  from Gnumed.pycommon import gmExceptions 
  29  from Gnumed.pycommon import gmCfg 
  30  from Gnumed.pycommon import gmDateTime 
  31  from Gnumed.pycommon import gmTools 
  32  from Gnumed.pycommon import gmDispatcher 
  33  from Gnumed.pycommon import gmMatchProvider 
  34   
  35  from Gnumed.business import gmEMRStructItems 
  36  from Gnumed.business import gmSurgery 
  37  from Gnumed.business import gmPerson 
  38   
  39  from Gnumed.wxpython import gmPhraseWheel 
  40  from Gnumed.wxpython import gmGuiHelpers 
  41  from Gnumed.wxpython import gmListWidgets 
  42  from Gnumed.wxpython import gmEditArea 
  43  from Gnumed.wxpython import gmPatSearchWidgets 
  44   
  45   
  46  _log = logging.getLogger('gm.ui') 
  47  #================================================================ 
  48  # EMR access helper functions 
  49  #---------------------------------------------------------------- 
50 -def emr_access_spinner(time2spin=0):
51 """Spin time in seconds.""" 52 if time2spin == 0: 53 return 54 sleep_time = 0.1 55 total_rounds = int(time2spin / sleep_time) 56 if total_rounds < 1: 57 return 58 rounds = 0 59 while rounds < total_rounds: 60 wx.Yield() 61 time.sleep(sleep_time) 62 rounds += 1
63 #================================================================ 64 # performed procedure related widgets/functions 65 #----------------------------------------------------------------
66 -def manage_performed_procedures(parent=None):
67 68 pat = gmPerson.gmCurrentPatient() 69 emr = pat.get_emr() 70 71 if parent is None: 72 parent = wx.GetApp().GetTopWindow() 73 #----------------------------------------- 74 def edit(procedure=None): 75 return edit_procedure(parent = parent, procedure = procedure)
76 #----------------------------------------- 77 def delete(procedure=None): 78 if gmEMRStructItems.delete_performed_procedure(procedure = procedure['pk_procedure']): 79 return True 80 81 gmDispatcher.send ( 82 signal = u'statustext', 83 msg = _('Cannot delete performed procedure.'), 84 beep = True 85 ) 86 return False 87 #----------------------------------------- 88 def refresh(lctrl): 89 procs = emr.get_performed_procedures() 90 91 items = [ 92 [ 93 u'%s%s' % ( 94 p['clin_when'].strftime('%Y-%m-%d'), 95 gmTools.bool2subst ( 96 p['is_ongoing'], 97 _(' (ongoing)'), 98 gmTools.coalesce ( 99 initial = p['clin_end'], 100 instead = u'', 101 template_initial = u' - %s', 102 function_initial = ('strftime', u'%Y-%m-%d') 103 ) 104 ) 105 ), 106 p['clin_where'], 107 p['episode'], 108 p['performed_procedure'] 109 ] for p in procs 110 ] 111 lctrl.set_string_items(items = items) 112 lctrl.set_data(data = procs) 113 #----------------------------------------- 114 gmListWidgets.get_choices_from_list ( 115 parent = parent, 116 msg = _('\nSelect the procedure you want to edit !\n'), 117 caption = _('Editing performed procedures ...'), 118 columns = [_('When'), _('Where'), _('Episode'), _('Procedure')], 119 single_selection = True, 120 edit_callback = edit, 121 new_callback = edit, 122 delete_callback = delete, 123 refresh_callback = refresh 124 ) 125 #----------------------------------------------------------------
126 -def edit_procedure(parent=None, procedure=None):
127 ea = cProcedureEAPnl(parent = parent, id = -1) 128 ea.data = procedure 129 ea.mode = gmTools.coalesce(procedure, 'new', 'edit') 130 dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = True) 131 dlg.SetTitle(gmTools.coalesce(procedure, _('Adding a procedure'), _('Editing a procedure'))) 132 if dlg.ShowModal() == wx.ID_OK: 133 dlg.Destroy() 134 return True 135 dlg.Destroy() 136 return False
137 #---------------------------------------------------------------- 138 from Gnumed.wxGladeWidgets import wxgProcedureEAPnl 139
140 -class cProcedureEAPnl(wxgProcedureEAPnl.wxgProcedureEAPnl, gmEditArea.cGenericEditAreaMixin):
141
142 - def __init__(self, *args, **kwargs):
143 wxgProcedureEAPnl.wxgProcedureEAPnl.__init__(self, *args, **kwargs) 144 gmEditArea.cGenericEditAreaMixin.__init__(self) 145 146 self.mode = 'new' 147 self.data = None 148 149 self.__init_ui()
150 #----------------------------------------------------------------
151 - def __init_ui(self):
152 self._PRW_hospital_stay.add_callback_on_lose_focus(callback = self._on_hospital_stay_lost_focus) 153 self._PRW_hospital_stay.set_context(context = 'pat', val = gmPerson.gmCurrentPatient().ID) 154 self._PRW_location.add_callback_on_lose_focus(callback = self._on_location_lost_focus) 155 self._DPRW_date.add_callback_on_lose_focus(callback = self._on_start_lost_focus) 156 self._DPRW_end.add_callback_on_lose_focus(callback = self._on_end_lost_focus) 157 158 # location 159 mp = gmMatchProvider.cMatchProvider_SQL2 ( 160 queries = [ 161 u""" 162 SELECT DISTINCT ON (data) data, location 163 FROM ( 164 SELECT 165 clin_where as data, 166 clin_where as location 167 FROM 168 clin.procedure 169 WHERE 170 clin_where %(fragment_condition)s 171 172 UNION ALL 173 174 SELECT 175 narrative as data, 176 narrative as location 177 FROM 178 clin.hospital_stay 179 WHERE 180 narrative %(fragment_condition)s 181 ) as union_result 182 ORDER BY data 183 LIMIT 25""" 184 ] 185 ) 186 mp.setThresholds(2, 4, 6) 187 self._PRW_location.matcher = mp 188 189 # procedure 190 mp = gmMatchProvider.cMatchProvider_SQL2 ( 191 queries = [ 192 u""" 193 select distinct on (narrative) narrative, narrative 194 from clin.procedure 195 where narrative %(fragment_condition)s 196 order by narrative 197 limit 25 198 """ ] 199 ) 200 mp.setThresholds(2, 4, 6) 201 self._PRW_procedure.matcher = mp
202 #----------------------------------------------------------------
204 stay = self._PRW_hospital_stay.GetData() 205 if stay is None: 206 self._PRW_hospital_stay.SetText() 207 self._PRW_location.Enable(True) 208 self._PRW_episode.Enable(True) 209 self._LBL_hospital_details.SetLabel(u'') 210 else: 211 self._PRW_location.SetText() 212 self._PRW_location.Enable(False) 213 self._PRW_episode.SetText() 214 self._PRW_episode.Enable(False) 215 self._LBL_hospital_details.SetLabel(gmEMRStructItems.cHospitalStay(aPK_obj = stay).format())
216 #----------------------------------------------------------------
217 - def _on_location_lost_focus(self):
218 if self._PRW_location.GetValue().strip() == u'': 219 self._PRW_hospital_stay.Enable(True) 220 # self._PRW_episode.Enable(False) 221 else: 222 self._PRW_hospital_stay.SetText() 223 self._PRW_hospital_stay.Enable(False) 224 self._PRW_hospital_stay.display_as_valid(True)
225 # self._PRW_episode.Enable(True) 226 #----------------------------------------------------------------
227 - def _on_start_lost_focus(self):
228 if not self._DPRW_date.is_valid_timestamp(): 229 return 230 end = self._DPRW_end.GetData() 231 if end is None: 232 return 233 end = end.get_pydt() 234 start = self._DPRW_date.GetData().get_pydt() 235 if start < end: 236 return 237 self._DPRW_date.display_as_valid(False)
238 #----------------------------------------------------------------
239 - def _on_end_lost_focus(self):
240 end = self._DPRW_end.GetData() 241 if end is None: 242 self._CHBOX_ongoing.Enable(True) 243 self._DPRW_end.display_as_valid(True) 244 else: 245 self._CHBOX_ongoing.Enable(False) 246 end = end.get_pydt() 247 now = gmDateTime.pydt_now_here() 248 if end > now: 249 self._CHBOX_ongoing.SetValue(True) 250 else: 251 self._CHBOX_ongoing.SetValue(False) 252 start = self._DPRW_date.GetData() 253 if start is None: 254 self._DPRW_end.display_as_valid(True) 255 else: 256 start = start.get_pydt() 257 if end > start: 258 self._DPRW_end.display_as_valid(True) 259 else: 260 self._DPRW_end.display_as_valid(False)
261 #---------------------------------------------------------------- 262 # generic Edit Area mixin API 263 #----------------------------------------------------------------
264 - def _valid_for_save(self):
265 266 has_errors = False 267 268 if not self._DPRW_date.is_valid_timestamp(): 269 self._DPRW_date.display_as_valid(False) 270 has_errors = True 271 else: 272 self._DPRW_date.display_as_valid(True) 273 274 start = self._DPRW_date.GetData() 275 end = self._DPRW_end.GetData() 276 self._DPRW_end.display_as_valid(True) 277 if end is not None: 278 end = end.get_pydt() 279 if start is not None: 280 start = start.get_pydt() 281 if end < start: 282 has_errors = True 283 self._DPRW_end.display_as_valid(False) 284 if self._CHBOX_ongoing.IsChecked(): 285 now = gmDateTime.pydt_now_here() 286 if end < now: 287 has_errors = True 288 self._DPRW_end.display_as_valid(False) 289 290 if self._PRW_hospital_stay.GetData() is None: 291 if self._PRW_episode.GetData() is None: 292 self._PRW_episode.display_as_valid(False) 293 has_errors = True 294 else: 295 self._PRW_episode.display_as_valid(True) 296 else: 297 self._PRW_episode.display_as_valid(True) 298 299 if (self._PRW_procedure.GetValue() is None) or (self._PRW_procedure.GetValue().strip() == u''): 300 self._PRW_procedure.display_as_valid(False) 301 has_errors = True 302 else: 303 self._PRW_procedure.display_as_valid(True) 304 305 invalid_location = ( 306 (self._PRW_hospital_stay.GetData() is None) and (self._PRW_location.GetValue().strip() == u'') 307 or 308 (self._PRW_hospital_stay.GetData() is not None) and (self._PRW_location.GetValue().strip() != u'') 309 ) 310 if invalid_location: 311 self._PRW_hospital_stay.display_as_valid(False) 312 self._PRW_location.display_as_valid(False) 313 has_errors = True 314 else: 315 self._PRW_hospital_stay.display_as_valid(True) 316 self._PRW_location.display_as_valid(True) 317 318 gmDispatcher.send(signal = 'statustext', msg = _('Cannot save procedure.'), beep = True) 319 320 return (has_errors is False)
321 #----------------------------------------------------------------
322 - def _save_as_new(self):
323 324 pat = gmPerson.gmCurrentPatient() 325 emr = pat.get_emr() 326 327 if self._PRW_hospital_stay.GetData() is None: 328 stay = None 329 epi = self._PRW_episode.GetData() 330 loc = self._PRW_location.GetValue().strip() 331 else: 332 stay = self._PRW_hospital_stay.GetData() 333 epi = gmEMRStructItems.cHospitalStay(aPK_obj = stay)['pk_episode'] 334 loc = None 335 336 proc = emr.add_performed_procedure ( 337 episode = epi, 338 location = loc, 339 hospital_stay = stay, 340 procedure = self._PRW_procedure.GetValue().strip() 341 ) 342 343 proc['clin_when'] = self._DPRW_date.GetData().get_pydt() 344 if self._DPRW_end.GetData() is None: 345 proc['clin_end'] = None 346 else: 347 proc['clin_end'] = self._DPRW_end.GetData().get_pydt() 348 proc['is_ongoing'] = self._CHBOX_ongoing.IsChecked() 349 proc.save() 350 351 proc.generic_codes = [ c['data'] for c in self._PRW_codes.GetData() ] 352 353 self.data = proc 354 355 return True
356 #----------------------------------------------------------------
357 - def _save_as_update(self):
358 self.data['clin_when'] = self._DPRW_date.GetData().get_pydt() 359 360 if self._DPRW_end.GetData() is None: 361 self.data['clin_end'] = None 362 else: 363 self.data['clin_end'] = self._DPRW_end.GetData().get_pydt() 364 365 self.data['is_ongoing'] = self._CHBOX_ongoing.IsChecked() 366 367 if self._PRW_hospital_stay.GetData() is None: 368 self.data['pk_hospital_stay'] = None 369 self.data['clin_where'] = self._PRW_location.GetValue().strip() 370 self.data['pk_episode'] = self._PRW_episode.GetData() 371 else: 372 self.data['pk_hospital_stay'] = self._PRW_hospital_stay.GetData() 373 self.data['clin_where'] = None 374 stay = gmEMRStructItems.cHospitalStay(aPK_obj = self._PRW_hospital_stay.GetData()) 375 self.data['pk_episode'] = stay['pk_episode'] 376 377 self.data['performed_procedure'] = self._PRW_procedure.GetValue().strip() 378 379 self.data.save() 380 self.data.generic_codes = [ c['data'] for c in self._PRW_codes.GetData() ] 381 382 return True
383 #----------------------------------------------------------------
384 - def _refresh_as_new(self):
385 self._DPRW_date.SetText() 386 self._DPRW_end.SetText() 387 self._CHBOX_ongoing.SetValue(False) 388 self._CHBOX_ongoing.Enable(True) 389 self._PRW_hospital_stay.SetText() 390 self._PRW_location.SetText() 391 self._PRW_episode.SetText() 392 self._PRW_procedure.SetText() 393 self._PRW_codes.SetText() 394 395 self._PRW_procedure.SetFocus()
396 #----------------------------------------------------------------
397 - def _refresh_from_existing(self):
398 self._DPRW_date.SetData(data = self.data['clin_when']) 399 if self.data['clin_end'] is None: 400 self._DPRW_end.SetText() 401 self._CHBOX_ongoing.Enable(True) 402 self._CHBOX_ongoing.SetValue(self.data['is_ongoing']) 403 else: 404 self._DPRW_end.SetData(data = self.data['clin_end']) 405 self._CHBOX_ongoing.Enable(False) 406 now = gmDateTime.pydt_now_here() 407 if self.data['clin_end'] > now: 408 self._CHBOX_ongoing.SetValue(True) 409 else: 410 self._CHBOX_ongoing.SetValue(False) 411 self._PRW_episode.SetText(value = self.data['episode'], data = self.data['pk_episode']) 412 self._PRW_procedure.SetText(value = self.data['performed_procedure'], data = self.data['performed_procedure']) 413 414 if self.data['pk_hospital_stay'] is None: 415 self._PRW_hospital_stay.SetText() 416 self._LBL_hospital_details.SetLabel(u'') 417 self._PRW_location.SetText(value = self.data['clin_where'], data = self.data['clin_where']) 418 else: 419 self._PRW_hospital_stay.SetText(value = self.data['clin_where'], data = self.data['pk_hospital_stay']) 420 self._LBL_hospital_details.SetLabel(gmEMRStructItems.cHospitalStay(aPK_obj = self.data['pk_hospital_stay']).format()) 421 self._PRW_location.SetText() 422 423 val, data = self._PRW_codes.generic_linked_codes2item_dict(self.data.generic_codes) 424 self._PRW_codes.SetText(val, data) 425 426 self._PRW_procedure.SetFocus()
427 #----------------------------------------------------------------
429 self._refresh_as_new() 430 self._PRW_episode.SetText(value = self.data['episode'], data = self.data['pk_episode']) 431 if self.data['pk_hospital_stay'] is None: 432 self._PRW_hospital_stay.SetText() 433 self._PRW_location.SetText(value = self.data['clin_where'], data = self.data['clin_where']) 434 else: 435 self._PRW_hospital_stay.SetText(value = self.data['clin_where'], data = self.data['pk_hospital_stay']) 436 self._PRW_location.SetText() 437 438 self._PRW_procedure.SetFocus()
439 #---------------------------------------------------------------- 440 # event handlers 441 #----------------------------------------------------------------
443 # FIXME: this would benefit from setting the created stay 444 edit_hospital_stay(parent = self.GetParent()) 445 evt.Skip()
446 #----------------------------------------------------------------
447 - def _on_ongoing_checkbox_checked(self, event):
448 if self._CHBOX_ongoing.IsChecked(): 449 end = self._DPRW_end.GetData() 450 if end is None: 451 self._DPRW_end.display_as_valid(True) 452 else: 453 end = end.get_pydt() 454 now = gmDateTime.pydt_now_here() 455 if end > now: 456 self._DPRW_end.display_as_valid(True) 457 else: 458 self._DPRW_end.display_as_valid(False) 459 else: 460 self._DPRW_end.is_valid_timestamp() 461 event.Skip()
462 #================================================================ 463 # hospitalizations related widgets/functions 464 #----------------------------------------------------------------
465 -def manage_hospital_stays(parent=None):
466 467 pat = gmPerson.gmCurrentPatient() 468 emr = pat.get_emr() 469 470 if parent is None: 471 parent = wx.GetApp().GetTopWindow() 472 #----------------------------------------- 473 def edit(stay=None): 474 return edit_hospital_stay(parent = parent, hospital_stay = stay)
475 #----------------------------------------- 476 def delete(stay=None): 477 if gmEMRStructItems.delete_hospital_stay(stay = stay['pk_hospital_stay']): 478 return True 479 gmDispatcher.send ( 480 signal = u'statustext', 481 msg = _('Cannot delete hospitalization.'), 482 beep = True 483 ) 484 return False 485 #----------------------------------------- 486 def refresh(lctrl): 487 stays = emr.get_hospital_stays() 488 items = [ 489 [ 490 s['admission'].strftime('%Y-%m-%d'), 491 gmTools.coalesce(s['discharge'], u'', function_initial = ('strftime', '%Y-%m-%d')), 492 s['episode'], 493 gmTools.coalesce(s['hospital'], u'') 494 ] for s in stays 495 ] 496 lctrl.set_string_items(items = items) 497 lctrl.set_data(data = stays) 498 #----------------------------------------- 499 gmListWidgets.get_choices_from_list ( 500 parent = parent, 501 msg = _("The patient's hospitalizations:\n"), 502 caption = _('Editing hospitalizations ...'), 503 columns = [_('Admission'), _('Discharge'), _('Reason'), _('Hospital')], 504 single_selection = True, 505 edit_callback = edit, 506 new_callback = edit, 507 delete_callback = delete, 508 refresh_callback = refresh 509 ) 510 511 #----------------------------------------------------------------
512 -def edit_hospital_stay(parent=None, hospital_stay=None):
513 ea = cHospitalStayEditAreaPnl(parent = parent, id = -1) 514 ea.data = hospital_stay 515 ea.mode = gmTools.coalesce(hospital_stay, 'new', 'edit') 516 dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = True) 517 dlg.SetTitle(gmTools.coalesce(hospital_stay, _('Adding a hospitalization'), _('Editing a hospitalization'))) 518 if dlg.ShowModal() == wx.ID_OK: 519 dlg.Destroy() 520 return True 521 dlg.Destroy() 522 return False
523 #----------------------------------------------------------------
524 -class cHospitalStayPhraseWheel(gmPhraseWheel.cPhraseWheel):
525 """Phrasewheel to allow selection of a hospitalization."""
526 - def __init__(self, *args, **kwargs):
527 528 gmPhraseWheel.cPhraseWheel.__init__ (self, *args, **kwargs) 529 530 ctxt = {'ctxt_pat': {'where_part': u'pk_patient = %(pat)s and', 'placeholder': u'pat'}} 531 532 mp = gmMatchProvider.cMatchProvider_SQL2 ( 533 queries = [ 534 u""" 535 select 536 pk_hospital_stay, 537 descr 538 from ( 539 select distinct on (pk_hospital_stay) 540 pk_hospital_stay, 541 descr 542 from 543 (select 544 pk_hospital_stay, 545 ( 546 to_char(admission, 'YYYY-Mon-DD') 547 || coalesce((' (' || hospital || '):'), ': ') 548 || episode 549 || coalesce((' (' || health_issue || ')'), '') 550 ) as descr 551 from 552 clin.v_pat_hospital_stays 553 where 554 %(ctxt_pat)s 555 556 hospital %(fragment_condition)s 557 or 558 episode %(fragment_condition)s 559 or 560 health_issue %(fragment_condition)s 561 ) as the_stays 562 ) as distinct_stays 563 order by descr 564 limit 25 565 """ ], 566 context = ctxt 567 ) 568 mp.setThresholds(3, 4, 6) 569 mp.set_context('pat', gmPerson.gmCurrentPatient().ID) 570 571 self.matcher = mp 572 self.selection_only = True
573 #---------------------------------------------------------------- 574 from Gnumed.wxGladeWidgets import wxgHospitalStayEditAreaPnl 575
576 -class cHospitalStayEditAreaPnl(wxgHospitalStayEditAreaPnl.wxgHospitalStayEditAreaPnl, gmEditArea.cGenericEditAreaMixin):
577
578 - def __init__(self, *args, **kwargs):
581 #---------------------------------------------------------------- 582 # generic Edit Area mixin API 583 #----------------------------------------------------------------
584 - def _valid_for_save(self):
585 586 valid = True 587 588 if not self._PRW_admission.is_valid_timestamp(allow_empty = False): 589 valid = False 590 gmDispatcher.send(signal = 'statustext', msg = _('Missing admission data. Cannot save hospitalization.'), beep = True) 591 592 if self._PRW_discharge.is_valid_timestamp(allow_empty = True): 593 if self._PRW_discharge.date is not None: 594 if not self._PRW_discharge.date > self._PRW_admission.date: 595 valid = False 596 self._PRW_discharge.display_as_valid(False) 597 gmDispatcher.send(signal = 'statustext', msg = _('Discharge date must be empty or later than admission. Cannot save hospitalization.'), beep = True) 598 599 if self._PRW_episode.GetValue().strip() == u'': 600 valid = False 601 self._PRW_episode.display_as_valid(False) 602 gmDispatcher.send(signal = 'statustext', msg = _('Must select an episode or enter a name for a new one. Cannot save hospitalization.'), beep = True) 603 604 return (valid is True)
605 #----------------------------------------------------------------
606 - def _save_as_new(self):
607 608 pat = gmPerson.gmCurrentPatient() 609 emr = pat.get_emr() 610 stay = emr.add_hospital_stay(episode = self._PRW_episode.GetData(can_create = True)) 611 stay['hospital'] = gmTools.none_if(self._PRW_hospital.GetValue().strip(), u'') 612 stay['admission'] = self._PRW_admission.GetData() 613 stay['discharge'] = self._PRW_discharge.GetData() 614 stay.save_payload() 615 616 self.data = stay 617 return True
618 #----------------------------------------------------------------
619 - def _save_as_update(self):
620 621 self.data['pk_episode'] = self._PRW_episode.GetData(can_create = True) 622 self.data['hospital'] = gmTools.none_if(self._PRW_hospital.GetValue().strip(), u'') 623 self.data['admission'] = self._PRW_admission.GetData() 624 self.data['discharge'] = self._PRW_discharge.GetData() 625 self.data.save_payload() 626 627 return True
628 #----------------------------------------------------------------
629 - def _refresh_as_new(self):
630 self._PRW_hospital.SetText(value = u'') 631 self._PRW_episode.SetText(value = u'') 632 self._PRW_admission.SetText(data = gmDateTime.pydt_now_here()) 633 self._PRW_discharge.SetText()
634 #----------------------------------------------------------------
635 - def _refresh_from_existing(self):
636 if self.data['hospital'] is not None: 637 self._PRW_hospital.SetText(value = self.data['hospital']) 638 639 if self.data['pk_episode'] is not None: 640 self._PRW_episode.SetText(value = self.data['episode'], data = self.data['pk_episode']) 641 642 self._PRW_admission.SetText(data = self.data['admission']) 643 self._PRW_discharge.SetText(data = self.data['discharge'])
644 #----------------------------------------------------------------
646 print "this was not expected to be used in this edit area"
647 #================================================================ 648 # encounter related widgets/functions 649 #----------------------------------------------------------------
650 -def start_new_encounter(emr=None):
651 emr.start_new_encounter() 652 gmDispatcher.send(signal = 'statustext', msg = _('Started a new encounter for the active patient.'), beep = True) 653 time.sleep(0.5) 654 gmGuiHelpers.gm_show_info ( 655 _('\nA new encounter was started for the active patient.\n'), 656 _('Start of new encounter') 657 )
658 #---------------------------------------------------------------- 659 from Gnumed.wxGladeWidgets import wxgEncounterEditAreaDlg 660
661 -def edit_encounter(parent=None, encounter=None):
662 if parent is None: 663 parent = wx.GetApp().GetTopWindow() 664 665 # FIXME: use generic dialog 2 666 dlg = cEncounterEditAreaDlg(parent = parent, encounter = encounter) 667 if dlg.ShowModal() == wx.ID_OK: 668 dlg.Destroy() 669 return True 670 dlg.Destroy() 671 return False
672 #----------------------------------------------------------------
673 -def manage_encounters(**kwargs):
674 return select_encounters(**kwargs)
675
676 -def select_encounters(parent=None, patient=None, single_selection=True, encounters=None, ignore_OK_button=False):
677 678 if patient is None: 679 patient = gmPerson.gmCurrentPatient() 680 681 if not patient.connected: 682 gmDispatcher.send(signal = 'statustext', msg = _('Cannot list encounters. No active patient.')) 683 return False 684 685 if parent is None: 686 parent = wx.GetApp().GetTopWindow() 687 688 emr = patient.get_emr() 689 690 #-------------------- 691 def refresh(lctrl): 692 if encounters is None: 693 encs = emr.get_encounters() 694 else: 695 encs = encounters 696 697 items = [ 698 [ 699 e['started'].strftime('%x %H:%M'), 700 e['last_affirmed'].strftime('%H:%M'), 701 e['l10n_type'], 702 gmTools.coalesce(e['reason_for_encounter'], u''), 703 gmTools.coalesce(e['assessment_of_encounter'], u''), 704 gmTools.bool2subst(e.has_clinical_data(), u'', gmTools.u_checkmark_thin), 705 e['pk_encounter'] 706 ] for e in encs 707 ] 708 lctrl.set_string_items(items = items) 709 lctrl.set_data(data = encs) 710 active_pk = emr.active_encounter['pk_encounter'] 711 for idx in range(len(encs)): 712 e = encs[idx] 713 if e['pk_encounter'] == active_pk: 714 lctrl.SetItemTextColour(idx, col=wx.NamedColour('RED'))
715 #-------------------- 716 def new(): 717 cfg_db = gmCfg.cCfgSQL() 718 # FIXME: look for MRU/MCU encounter type config here 719 enc_type = cfg_db.get2 ( 720 option = u'encounter.default_type', 721 workplace = gmSurgery.gmCurrentPractice().active_workplace, 722 bias = u'user', 723 default = u'in surgery' 724 ) 725 enc = gmEMRStructItems.create_encounter(fk_patient = patient.ID, enc_type = enc_type) 726 return edit_encounter(parent = parent, encounter = enc) 727 #-------------------- 728 def edit(enc=None): 729 return edit_encounter(parent = parent, encounter = enc) 730 #-------------------- 731 def edit_active(enc=None): 732 return edit_encounter(parent = parent, encounter = emr.active_encounter) 733 #-------------------- 734 def start_new(enc=None): 735 start_new_encounter(emr = emr) 736 return True 737 #-------------------- 738 return gmListWidgets.get_choices_from_list ( 739 parent = parent, 740 msg = _("The patient's encounters.\n"), 741 caption = _('Encounters ...'), 742 columns = [_('Started'), _('Ended'), _('Type'), _('Reason for Encounter'), _('Assessment of Encounter'), _('Empty'), '#'], 743 can_return_empty = False, 744 single_selection = single_selection, 745 refresh_callback = refresh, 746 edit_callback = edit, 747 new_callback = new, 748 ignore_OK_button = ignore_OK_button, 749 left_extra_button = (_('Edit active'), _('Edit the active encounter'), edit_active), 750 middle_extra_button = (_('Start new'), _('Start new active encounter for the current patient.'), start_new) 751 ) 752 #----------------------------------------------------------------
753 -def ask_for_encounter_continuation(msg=None, caption=None, encounter=None, parent=None):
754 """This is used as the callback when the EMR detects that the 755 patient was here rather recently and wants to ask the 756 provider whether to continue the recent encounter. 757 """ 758 if parent is None: 759 parent = wx.GetApp().GetTopWindow() 760 761 dlg = gmGuiHelpers.c2ButtonQuestionDlg ( 762 parent = None, 763 id = -1, 764 caption = caption, 765 question = msg, 766 button_defs = [ 767 {'label': _('Continue'), 'tooltip': _('Continue the existing recent encounter.'), 'default': False}, 768 {'label': _('Start new'), 'tooltip': _('Start a new encounter. The existing one will be closed.'), 'default': True} 769 ], 770 show_checkbox = False 771 ) 772 773 result = dlg.ShowModal() 774 dlg.Destroy() 775 776 if result == wx.ID_YES: 777 return True 778 779 return False
780 #----------------------------------------------------------------
781 -def manage_encounter_types(parent=None):
782 783 if parent is None: 784 parent = wx.GetApp().GetTopWindow() 785 786 #-------------------- 787 def edit(enc_type=None): 788 return edit_encounter_type(parent = parent, encounter_type = enc_type)
789 #-------------------- 790 def delete(enc_type=None): 791 if gmEMRStructItems.delete_encounter_type(description = enc_type['description']): 792 return True 793 gmDispatcher.send ( 794 signal = u'statustext', 795 msg = _('Cannot delete encounter type [%s]. It is in use.') % enc_type['l10n_description'], 796 beep = True 797 ) 798 return False 799 #-------------------- 800 def refresh(lctrl): 801 enc_types = gmEMRStructItems.get_encounter_types() 802 lctrl.set_string_items(items = enc_types) 803 #-------------------- 804 gmListWidgets.get_choices_from_list ( 805 parent = parent, 806 msg = _('\nSelect the encounter type you want to edit !\n'), 807 caption = _('Managing encounter types ...'), 808 columns = [_('Local name'), _('Encounter type')], 809 single_selection = True, 810 edit_callback = edit, 811 new_callback = edit, 812 delete_callback = delete, 813 refresh_callback = refresh 814 ) 815 #----------------------------------------------------------------
816 -def edit_encounter_type(parent=None, encounter_type=None):
817 ea = cEncounterTypeEditAreaPnl(parent = parent, id = -1) 818 ea.data = encounter_type 819 ea.mode = gmTools.coalesce(encounter_type, 'new', 'edit') 820 dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea) 821 dlg.SetTitle(gmTools.coalesce(encounter_type, _('Adding new encounter type'), _('Editing local encounter type name'))) 822 if dlg.ShowModal() == wx.ID_OK: 823 return True 824 return False
825 #----------------------------------------------------------------
826 -class cEncounterPhraseWheel(gmPhraseWheel.cPhraseWheel):
827
828 - def __init__(self, *args, **kwargs):
829 gmPhraseWheel.cPhraseWheel.__init__ (self, *args, **kwargs) 830 831 cmd = u""" 832 SELECT -- DISTINCT ON (data) 833 pk_encounter 834 AS data, 835 to_char(started, 'YYYY Mon DD (HH24:MI)') || ': ' || l10n_type 836 AS list_label, 837 to_char(started, 'YYYY Mon DD') || ': ' || l10n_type 838 AS field_label 839 FROM 840 clin.v_pat_encounters 841 WHERE 842 to_char(started, 'YYYY-MM-DD') %(fragment_condition)s 843 OR 844 l10n_type %(fragment_condition)s 845 OR 846 type %(fragment_condition)s 847 %(ctxt_patient)s 848 ORDER BY 849 list_label 850 LIMIT 851 30 852 """ 853 context = {'ctxt_patient': { 854 'where_part': u'AND pk_patient = %(patient)s', 855 'placeholder': u'patient' 856 }} 857 858 self.matcher = gmMatchProvider.cMatchProvider_SQL2(queries = [cmd], context = context) 859 self.matcher._SQL_data2match = u""" 860 SELECT 861 pk_encounter 862 AS data, 863 to_char(started, 'YYYY Mon DD (HH24:MI)') || ': ' || l10n_type 864 AS list_label, 865 to_char(started, 'YYYY Mon DD') || ': ' || l10n_type 866 AS field_label 867 FROM 868 clin.v_pat_encounters 869 WHERE 870 pk_encounter = %(pk)s 871 """ 872 self.matcher.setThresholds(1, 3, 5) 873 self.selection_only = True 874 # outside code MUST bind this to a patient 875 self.set_context(context = 'patient', val = None)
876 #--------------------------------------------------------
877 - def set_from_instance(self, instance):
878 val = u'%s: %s' % ( 879 gmDateTime.pydt_strftime(instance['started'], '%Y %b %d'), 880 instance['l10n_type'] 881 ) 882 self.SetText(value = val, data = instance['pk_encounter'])
883 #------------------------------------------------------------
884 - def _get_data_tooltip(self):
885 if self.GetData() is None: 886 return None 887 enc = gmEMRStructItems.cEncounter(aPK_obj = self._data.values()[0]['data']) 888 return enc.format ( 889 with_docs = False, 890 with_tests = False, 891 with_vaccinations = False, 892 with_family_history = False 893 )
894 #----------------------------------------------------------------
895 -class cEncounterTypePhraseWheel(gmPhraseWheel.cPhraseWheel):
896 """Phrasewheel to allow selection of encounter type. 897 898 - user input interpreted as encounter type in English or local language 899 - data returned is pk of corresponding encounter type or None 900 """
901 - def __init__(self, *args, **kwargs):
902 903 gmPhraseWheel.cPhraseWheel.__init__ (self, *args, **kwargs) 904 905 mp = gmMatchProvider.cMatchProvider_SQL2 ( 906 queries = [ 907 u""" 908 SELECT 909 data, 910 field_label, 911 list_label 912 FROM ( 913 SELECT DISTINCT ON (data) * 914 FROM ( 915 SELECT 916 pk AS data, 917 _(description) AS field_label, 918 case 919 when _(description) = description then _(description) 920 else _(description) || ' (' || description || ')' 921 end AS list_label 922 FROM 923 clin.encounter_type 924 WHERE 925 _(description) %(fragment_condition)s 926 OR 927 description %(fragment_condition)s 928 ) AS q_distinct_pk 929 ) AS q_ordered 930 ORDER BY 931 list_label 932 """ ] 933 ) 934 mp.setThresholds(2, 4, 6) 935 936 self.matcher = mp 937 self.selection_only = True 938 self.picklist_delay = 50
939 #---------------------------------------------------------------- 940 from Gnumed.wxGladeWidgets import wxgEncounterTypeEditAreaPnl 941
942 -class cEncounterTypeEditAreaPnl(wxgEncounterTypeEditAreaPnl.wxgEncounterTypeEditAreaPnl, gmEditArea.cGenericEditAreaMixin):
943
944 - def __init__(self, *args, **kwargs):
948 949 # self.__register_interests() 950 #------------------------------------------------------- 951 # generic edit area API 952 #-------------------------------------------------------
953 - def _valid_for_save(self):
954 if self.mode == 'edit': 955 if self._TCTRL_l10n_name.GetValue().strip() == u'': 956 self.display_tctrl_as_valid(tctrl = self._TCTRL_l10n_name, valid = False) 957 return False 958 self.display_tctrl_as_valid(tctrl = self._TCTRL_l10n_name, valid = True) 959 return True 960 961 no_errors = True 962 963 if self._TCTRL_l10n_name.GetValue().strip() == u'': 964 if self._TCTRL_name.GetValue().strip() == u'': 965 self.display_tctrl_as_valid(tctrl = self._TCTRL_l10n_name, valid = False) 966 no_errors = False 967 else: 968 self.display_tctrl_as_valid(tctrl = self._TCTRL_l10n_name, valid = True) 969 else: 970 self.display_tctrl_as_valid(tctrl = self._TCTRL_l10n_name, valid = True) 971 972 if self._TCTRL_name.GetValue().strip() == u'': 973 if self._TCTRL_l10n_name.GetValue().strip() == u'': 974 self.display_tctrl_as_valid(tctrl = self._TCTRL_name, valid = False) 975 no_errors = False 976 else: 977 self.display_tctrl_as_valid(tctrl = self._TCTRL_name, valid = True) 978 else: 979 self.display_tctrl_as_valid(tctrl = self._TCTRL_name, valid = True) 980 981 return no_errors
982 #-------------------------------------------------------
983 - def _save_as_new(self):
984 enc_type = gmEMRStructItems.create_encounter_type ( 985 description = gmTools.none_if(self._TCTRL_name.GetValue().strip(), u''), 986 l10n_description = gmTools.coalesce ( 987 gmTools.none_if(self._TCTRL_l10n_name.GetValue().strip(), u''), 988 self._TCTRL_name.GetValue().strip() 989 ) 990 ) 991 if enc_type is None: 992 return False 993 self.data = enc_type 994 return True
995 #-------------------------------------------------------
996 - def _save_as_update(self):
997 enc_type = gmEMRStructItems.update_encounter_type ( 998 description = self._TCTRL_name.GetValue().strip(), 999 l10n_description = self._TCTRL_l10n_name.GetValue().strip() 1000 ) 1001 if enc_type is None: 1002 return False 1003 self.data = enc_type 1004 return True
1005 #-------------------------------------------------------
1006 - def _refresh_as_new(self):
1007 self._TCTRL_l10n_name.SetValue(u'') 1008 self._TCTRL_name.SetValue(u'') 1009 self._TCTRL_name.Enable(True)
1010 #-------------------------------------------------------
1011 - def _refresh_from_existing(self):
1012 self._TCTRL_l10n_name.SetValue(self.data['l10n_description']) 1013 self._TCTRL_name.SetValue(self.data['description']) 1014 # disallow changing type on all encounters by editing system name 1015 self._TCTRL_name.Enable(False)
1016 #-------------------------------------------------------
1018 self._TCTRL_l10n_name.SetValue(self.data['l10n_description']) 1019 self._TCTRL_name.SetValue(self.data['description']) 1020 self._TCTRL_name.Enable(True)
1021 #------------------------------------------------------- 1022 # internal API 1023 #------------------------------------------------------- 1024 # def __register_interests(self): 1025 # return 1026 #---------------------------------------------------------------- 1027 from Gnumed.wxGladeWidgets import wxgEncounterEditAreaPnl 1028
1029 -class cEncounterEditAreaPnl(wxgEncounterEditAreaPnl.wxgEncounterEditAreaPnl):
1030
1031 - def __init__(self, *args, **kwargs):
1032 try: 1033 self.__encounter = kwargs['encounter'] 1034 del kwargs['encounter'] 1035 except KeyError: 1036 self.__encounter = None 1037 1038 try: 1039 msg = kwargs['msg'] 1040 del kwargs['msg'] 1041 except KeyError: 1042 msg = None 1043 1044 wxgEncounterEditAreaPnl.wxgEncounterEditAreaPnl.__init__(self, *args, **kwargs) 1045 1046 self.refresh(msg = msg)
1047 #-------------------------------------------------------- 1048 # external API 1049 #--------------------------------------------------------
1050 - def refresh(self, encounter=None, msg=None):
1051 1052 if msg is not None: 1053 self._LBL_instructions.SetLabel(msg) 1054 1055 if encounter is not None: 1056 self.__encounter = encounter 1057 1058 if self.__encounter is None: 1059 return True 1060 1061 # getting the patient via the encounter allows us to act 1062 # on any encounter regardless of the currently active patient 1063 pat = gmPerson.cPatient(aPK_obj = self.__encounter['pk_patient']) 1064 self._LBL_patient.SetLabel(pat.get_description_gender()) 1065 1066 self._PRW_encounter_type.SetText(self.__encounter['l10n_type'], data=self.__encounter['pk_type']) 1067 1068 fts = gmDateTime.cFuzzyTimestamp ( 1069 timestamp = self.__encounter['started'], 1070 accuracy = gmDateTime.acc_minutes 1071 ) 1072 self._PRW_start.SetText(fts.format_accurately(), data=fts) 1073 1074 fts = gmDateTime.cFuzzyTimestamp ( 1075 timestamp = self.__encounter['last_affirmed'], 1076 accuracy = gmDateTime.acc_minutes 1077 ) 1078 self._PRW_end.SetText(fts.format_accurately(), data=fts) 1079 1080 # RFE 1081 self._TCTRL_rfe.SetValue(gmTools.coalesce(self.__encounter['reason_for_encounter'], '')) 1082 val, data = self._PRW_rfe_codes.generic_linked_codes2item_dict(self.__encounter.generic_codes_rfe) 1083 self._PRW_rfe_codes.SetText(val, data) 1084 1085 # AOE 1086 self._TCTRL_aoe.SetValue(gmTools.coalesce(self.__encounter['assessment_of_encounter'], '')) 1087 val, data = self._PRW_aoe_codes.generic_linked_codes2item_dict(self.__encounter.generic_codes_aoe) 1088 self._PRW_aoe_codes.SetText(val, data) 1089 1090 # last affirmed 1091 if self.__encounter['last_affirmed'] == self.__encounter['started']: 1092 self._PRW_end.SetFocus() 1093 else: 1094 self._TCTRL_aoe.SetFocus() 1095 1096 return True
1097 #--------------------------------------------------------
1098 - def __is_valid_for_save(self):
1099 1100 if self._PRW_encounter_type.GetData() is None: 1101 self._PRW_encounter_type.SetBackgroundColour('pink') 1102 self._PRW_encounter_type.Refresh() 1103 self._PRW_encounter_type.SetFocus() 1104 return False 1105 self._PRW_encounter_type.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)) 1106 self._PRW_encounter_type.Refresh() 1107 1108 # start 1109 if self._PRW_start.GetValue().strip() == u'': 1110 self._PRW_start.SetBackgroundColour('pink') 1111 self._PRW_start.Refresh() 1112 self._PRW_start.SetFocus() 1113 return False 1114 if not self._PRW_start.is_valid_timestamp(empty_is_valid = False): 1115 self._PRW_start.SetBackgroundColour('pink') 1116 self._PRW_start.Refresh() 1117 self._PRW_start.SetFocus() 1118 return False 1119 self._PRW_start.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)) 1120 self._PRW_start.Refresh() 1121 1122 # last_affirmed 1123 # if self._PRW_end.GetValue().strip() == u'': 1124 # self._PRW_end.SetBackgroundColour('pink') 1125 # self._PRW_end.Refresh() 1126 # self._PRW_end.SetFocus() 1127 # return False 1128 if not self._PRW_end.is_valid_timestamp(empty_is_valid = False): 1129 self._PRW_end.SetBackgroundColour('pink') 1130 self._PRW_end.Refresh() 1131 self._PRW_end.SetFocus() 1132 return False 1133 self._PRW_end.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)) 1134 self._PRW_end.Refresh() 1135 1136 return True
1137 #--------------------------------------------------------
1138 - def save(self):
1139 if not self.__is_valid_for_save(): 1140 return False 1141 1142 self.__encounter['pk_type'] = self._PRW_encounter_type.GetData() 1143 self.__encounter['started'] = self._PRW_start.GetData().get_pydt() 1144 self.__encounter['last_affirmed'] = self._PRW_end.GetData().get_pydt() 1145 self.__encounter['reason_for_encounter'] = gmTools.none_if(self._TCTRL_rfe.GetValue().strip(), u'') 1146 self.__encounter['assessment_of_encounter'] = gmTools.none_if(self._TCTRL_aoe.GetValue().strip(), u'') 1147 self.__encounter.save_payload() # FIXME: error checking 1148 1149 self.__encounter.generic_codes_rfe = [ c['data'] for c in self._PRW_rfe_codes.GetData() ] 1150 self.__encounter.generic_codes_aoe = [ c['data'] for c in self._PRW_aoe_codes.GetData() ] 1151 1152 return True
1153 #---------------------------------------------------------------- 1154 # FIXME: use generic dialog 2
1155 -class cEncounterEditAreaDlg(wxgEncounterEditAreaDlg.wxgEncounterEditAreaDlg):
1156
1157 - def __init__(self, *args, **kwargs):
1158 encounter = kwargs['encounter'] 1159 del kwargs['encounter'] 1160 1161 try: 1162 button_defs = kwargs['button_defs'] 1163 del kwargs['button_defs'] 1164 except KeyError: 1165 button_defs = None 1166 1167 try: 1168 msg = kwargs['msg'] 1169 del kwargs['msg'] 1170 except KeyError: 1171 msg = None 1172 1173 wxgEncounterEditAreaDlg.wxgEncounterEditAreaDlg.__init__(self, *args, **kwargs) 1174 self.SetSize((450, 280)) 1175 self.SetMinSize((450, 280)) 1176 1177 if button_defs is not None: 1178 self._BTN_save.SetLabel(button_defs[0][0]) 1179 self._BTN_save.SetToolTipString(button_defs[0][1]) 1180 self._BTN_close.SetLabel(button_defs[1][0]) 1181 self._BTN_close.SetToolTipString(button_defs[1][1]) 1182 self.Refresh() 1183 1184 self._PNL_edit_area.refresh(encounter = encounter, msg = msg) 1185 1186 self.Fit()
1187 #--------------------------------------------------------
1188 - def _on_save_button_pressed(self, evt):
1189 if self._PNL_edit_area.save(): 1190 if self.IsModal(): 1191 self.EndModal(wx.ID_OK) 1192 else: 1193 self.Close()
1194 #---------------------------------------------------------------- 1195 from Gnumed.wxGladeWidgets import wxgActiveEncounterPnl 1196
1197 -class cActiveEncounterPnl(wxgActiveEncounterPnl.wxgActiveEncounterPnl):
1198
1199 - def __init__(self, *args, **kwargs):
1200 wxgActiveEncounterPnl.wxgActiveEncounterPnl.__init__(self, *args, **kwargs) 1201 self.__register_events() 1202 self.refresh()
1203 #------------------------------------------------------------
1204 - def clear(self):
1205 self._TCTRL_encounter.SetValue(u'') 1206 self._TCTRL_encounter.SetToolTipString(u'') 1207 self._BTN_new.Enable(False) 1208 self._BTN_list.Enable(False)
1209 #------------------------------------------------------------
1210 - def refresh(self):
1211 pat = gmPerson.gmCurrentPatient() 1212 if not pat.connected: 1213 self.clear() 1214 return 1215 1216 enc = pat.get_emr().active_encounter 1217 self._TCTRL_encounter.SetValue(enc.format(with_docs = False, with_tests = False, fancy_header = False, with_vaccinations = False, with_family_history = False).strip('\n')) 1218 self._TCTRL_encounter.SetToolTipString ( 1219 _('The active encounter of the current patient:\n\n%s') % 1220 enc.format(with_docs = False, with_tests = False, fancy_header = True, with_vaccinations = False, with_rfe_aoe = True, with_family_history = False).strip('\n') 1221 ) 1222 self._BTN_new.Enable(True) 1223 self._BTN_list.Enable(True)
1224 #------------------------------------------------------------
1225 - def __register_events(self):
1226 self._TCTRL_encounter.Bind(wx.EVT_LEFT_DCLICK, self._on_ldclick) 1227 1228 gmDispatcher.connect(signal = u'pre_patient_selection', receiver = self._schedule_clear) 1229 # this would throw an exception due to concurrency issues: 1230 #gmDispatcher.connect(signal = u'post_patient_selection', receiver = self._schedule_refresh) 1231 gmDispatcher.connect(signal = u'episode_mod_db', receiver = self._schedule_refresh) 1232 gmDispatcher.connect(signal = u'current_encounter_modified', receiver = self._schedule_refresh) 1233 gmDispatcher.connect(signal = u'current_encounter_switched', receiver = self._schedule_refresh)
1234 #------------------------------------------------------------ 1235 # event handler 1236 #------------------------------------------------------------
1237 - def _schedule_clear(self):
1238 wx.CallAfter(self.clear)
1239 #------------------------------------------------------------
1240 - def _schedule_refresh(self, *args, **kwargs):
1241 wx.CallAfter(self.refresh) 1242 return True
1243 #------------------------------------------------------------
1244 - def _on_ldclick(self, event):
1245 pat = gmPerson.gmCurrentPatient() 1246 if not pat.connected: 1247 return 1248 edit_encounter(encounter = pat.get_emr().active_encounter)
1249 #------------------------------------------------------------
1250 - def _on_new_button_pressed(self, event):
1251 pat = gmPerson.gmCurrentPatient() 1252 if not pat.connected: 1253 return 1254 start_new_encounter(emr = pat.get_emr())
1255 #------------------------------------------------------------
1256 - def _on_list_button_pressed(self, event):
1257 if not gmPerson.gmCurrentPatient().connected: 1258 return 1259 select_encounters()
1260 #================================================================ 1261 # episode related widgets/functions 1262 #----------------------------------------------------------------
1263 -def edit_episode(parent=None, episode=None):
1264 ea = cEpisodeEditAreaPnl(parent = parent, id = -1) 1265 ea.data = episode 1266 ea.mode = gmTools.coalesce(episode, 'new', 'edit') 1267 dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = True) 1268 dlg.SetTitle(gmTools.coalesce(episode, _('Adding a new episode'), _('Editing an episode'))) 1269 if dlg.ShowModal() == wx.ID_OK: 1270 return True 1271 return False
1272 #----------------------------------------------------------------
1273 -def promote_episode_to_issue(parent=None, episode=None, emr=None):
1274 1275 created_new_issue = False 1276 1277 try: 1278 issue = gmEMRStructItems.cHealthIssue(name = episode['description'], patient = episode['pk_patient']) 1279 except gmExceptions.NoSuchBusinessObjectError: 1280 issue = None 1281 1282 if issue is None: 1283 issue = emr.add_health_issue(issue_name = episode['description']) 1284 created_new_issue = True 1285 else: 1286 # issue exists already, so ask user 1287 dlg = gmGuiHelpers.c3ButtonQuestionDlg ( 1288 parent, 1289 -1, 1290 caption = _('Promoting episode to health issue'), 1291 question = _( 1292 'There already is a health issue\n' 1293 '\n' 1294 ' %s\n' 1295 '\n' 1296 'What do you want to do ?' 1297 ) % issue['description'], 1298 button_defs = [ 1299 {'label': _('Use existing'), 'tooltip': _('Move episode into existing health issue'), 'default': False}, 1300 {'label': _('Create new'), 'tooltip': _('Create a new health issue with another name'), 'default': True} 1301 ] 1302 ) 1303 use_existing = dlg.ShowModal() 1304 dlg.Destroy() 1305 1306 if use_existing == wx.ID_CANCEL: 1307 return 1308 1309 # user wants to create new issue with alternate name 1310 if use_existing == wx.ID_NO: 1311 # loop until name modified but non-empty or cancelled 1312 issue_name = episode['description'] 1313 while issue_name == episode['description']: 1314 dlg = wx.TextEntryDialog ( 1315 parent = parent, 1316 message = _('Enter a short descriptive name for the new health issue:'), 1317 caption = _('Creating a new health issue ...'), 1318 defaultValue = issue_name, 1319 style = wx.OK | wx.CANCEL | wx.CENTRE 1320 ) 1321 decision = dlg.ShowModal() 1322 if decision != wx.ID_OK: 1323 dlg.Destroy() 1324 return 1325 issue_name = dlg.GetValue().strip() 1326 dlg.Destroy() 1327 if issue_name == u'': 1328 issue_name = episode['description'] 1329 1330 issue = emr.add_health_issue(issue_name = issue_name) 1331 created_new_issue = True 1332 1333 # eventually move the episode to the issue 1334 if not move_episode_to_issue(episode = episode, target_issue = issue, save_to_backend = True): 1335 # user cancelled the move so delete just-created issue 1336 if created_new_issue: 1337 # shouldn't fail as it is completely new 1338 gmEMRStructItems.delete_health_issue(health_issue = issue) 1339 return 1340 1341 return
1342 #----------------------------------------------------------------
1343 -def move_episode_to_issue(episode=None, target_issue=None, save_to_backend=False):
1344 """Prepare changing health issue for an episode. 1345 1346 Checks for two-open-episodes conflict. When this 1347 function succeeds, the pk_health_issue has been set 1348 on the episode instance and the episode should - for 1349 all practical purposes - be ready for save_payload(). 1350 """ 1351 # episode is closed: should always work 1352 if not episode['episode_open']: 1353 episode['pk_health_issue'] = target_issue['pk_health_issue'] 1354 if save_to_backend: 1355 episode.save_payload() 1356 return True 1357 1358 # un-associate: should always work, too 1359 if target_issue is None: 1360 episode['pk_health_issue'] = None 1361 if save_to_backend: 1362 episode.save_payload() 1363 return True 1364 1365 # try closing possibly expired episode on target issue if any 1366 db_cfg = gmCfg.cCfgSQL() 1367 epi_ttl = int(db_cfg.get2 ( 1368 option = u'episode.ttl', 1369 workplace = gmSurgery.gmCurrentPractice().active_workplace, 1370 bias = 'user', 1371 default = 60 # 2 months 1372 )) 1373 if target_issue.close_expired_episode(ttl=epi_ttl) is True: 1374 gmDispatcher.send(signal='statustext', msg=_('Closed episodes older than %s days on health issue [%s]') % (epi_ttl, target_issue['description'])) 1375 existing_epi = target_issue.get_open_episode() 1376 1377 # no more open episode on target issue: should work now 1378 if existing_epi is None: 1379 episode['pk_health_issue'] = target_issue['pk_health_issue'] 1380 if save_to_backend: 1381 episode.save_payload() 1382 return True 1383 1384 # don't conflict on SELF ;-) 1385 if existing_epi['pk_episode'] == episode['pk_episode']: 1386 episode['pk_health_issue'] = target_issue['pk_health_issue'] 1387 if save_to_backend: 1388 episode.save_payload() 1389 return True 1390 1391 # we got two open episodes at once, ask user 1392 move_range = episode.get_access_range() 1393 exist_range = existing_epi.get_access_range() 1394 question = _( 1395 'You want to associate the running episode:\n\n' 1396 ' "%(new_epi_name)s" (%(new_epi_start)s - %(new_epi_end)s)\n\n' 1397 'with the health issue:\n\n' 1398 ' "%(issue_name)s"\n\n' 1399 'There already is another episode running\n' 1400 'for this health issue:\n\n' 1401 ' "%(old_epi_name)s" (%(old_epi_start)s - %(old_epi_end)s)\n\n' 1402 'However, there can only be one running\n' 1403 'episode per health issue.\n\n' 1404 'Which episode do you want to close ?' 1405 ) % { 1406 'new_epi_name': episode['description'], 1407 'new_epi_start': move_range[0].strftime('%m/%y'), 1408 'new_epi_end': move_range[1].strftime('%m/%y'), 1409 'issue_name': target_issue['description'], 1410 'old_epi_name': existing_epi['description'], 1411 'old_epi_start': exist_range[0].strftime('%m/%y'), 1412 'old_epi_end': exist_range[1].strftime('%m/%y') 1413 } 1414 dlg = gmGuiHelpers.c3ButtonQuestionDlg ( 1415 parent = None, 1416 id = -1, 1417 caption = _('Resolving two-running-episodes conflict'), 1418 question = question, 1419 button_defs = [ 1420 {'label': _('old episode'), 'default': True, 'tooltip': _('close existing episode "%s"') % existing_epi['description']}, 1421 {'label': _('new episode'), 'default': False, 'tooltip': _('close moving (new) episode "%s"') % episode['description']} 1422 ] 1423 ) 1424 decision = dlg.ShowModal() 1425 1426 if decision == wx.ID_CANCEL: 1427 # button 3: move cancelled by user 1428 return False 1429 1430 elif decision == wx.ID_YES: 1431 # button 1: close old episode 1432 existing_epi['episode_open'] = False 1433 existing_epi.save_payload() 1434 1435 elif decision == wx.ID_NO: 1436 # button 2: close new episode 1437 episode['episode_open'] = False 1438 1439 else: 1440 raise ValueError('invalid result from c3ButtonQuestionDlg: [%s]' % decision) 1441 1442 episode['pk_health_issue'] = target_issue['pk_health_issue'] 1443 if save_to_backend: 1444 episode.save_payload() 1445 return True
1446 #----------------------------------------------------------------
1447 -class cEpisodeListSelectorDlg(gmListWidgets.cGenericListSelectorDlg):
1448 1449 # FIXME: support pre-selection 1450
1451 - def __init__(self, *args, **kwargs):
1452 1453 episodes = kwargs['episodes'] 1454 del kwargs['episodes'] 1455 1456 gmListWidgets.cGenericListSelectorDlg.__init__(self, *args, **kwargs) 1457 1458 self.SetTitle(_('Select the episodes you are interested in ...')) 1459 self._LCTRL_items.set_columns([_('Episode'), _('Status'), _('Health Issue')]) 1460 self._LCTRL_items.set_string_items ( 1461 items = [ 1462 [ epi['description'], 1463 gmTools.bool2str(epi['episode_open'], _('ongoing'), u''), 1464 gmTools.coalesce(epi['health_issue'], u'') 1465 ] 1466 for epi in episodes ] 1467 ) 1468 self._LCTRL_items.set_column_widths() 1469 self._LCTRL_items.set_data(data = episodes)
1470 #----------------------------------------------------------------
1471 -class cEpisodeDescriptionPhraseWheel(gmPhraseWheel.cPhraseWheel):
1472 """Let user select an episode *description*. 1473 1474 The user can select an episode description from the previously 1475 used descriptions across all episodes across all patients. 1476 1477 Selection is done with a phrasewheel so the user can 1478 type the episode name and matches will be shown. Typing 1479 "*" will show the entire list of episodes. 1480 1481 If the user types a description not existing yet a 1482 new episode description will be returned. 1483 """
1484 - def __init__(self, *args, **kwargs):
1485 1486 mp = gmMatchProvider.cMatchProvider_SQL2 ( 1487 queries = [ 1488 u""" 1489 SELECT DISTINCT ON (description) 1490 description 1491 AS data, 1492 description 1493 AS field_label, 1494 description || ' (' 1495 || CASE 1496 WHEN is_open IS TRUE THEN _('ongoing') 1497 ELSE _('closed') 1498 END 1499 || ')' 1500 AS list_label 1501 FROM 1502 clin.episode 1503 WHERE 1504 description %(fragment_condition)s 1505 ORDER BY description 1506 LIMIT 30 1507 """ 1508 ] 1509 ) 1510 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 1511 self.matcher = mp
1512 #----------------------------------------------------------------
1513 -class cEpisodeSelectionPhraseWheel(gmPhraseWheel.cPhraseWheel):
1514 """Let user select an episode. 1515 1516 The user can select an episode from the existing episodes of a 1517 patient. Selection is done with a phrasewheel so the user 1518 can type the episode name and matches will be shown. Typing 1519 "*" will show the entire list of episodes. Closed episodes 1520 will be marked as such. If the user types an episode name not 1521 in the list of existing episodes a new episode can be created 1522 from it if the programmer activated that feature. 1523 1524 If keyword <patient_id> is set to None or left out the control 1525 will listen to patient change signals and therefore act on 1526 gmPerson.gmCurrentPatient() changes. 1527 """
1528 - def __init__(self, *args, **kwargs):
1529 1530 ctxt = {'ctxt_pat': {'where_part': u'and pk_patient = %(pat)s', 'placeholder': u'pat'}} 1531 1532 mp = gmMatchProvider.cMatchProvider_SQL2 ( 1533 queries = [ 1534 u"""( 1535 1536 select 1537 pk_episode 1538 as data, 1539 description 1540 as field_label, 1541 coalesce ( 1542 description || ' - ' || health_issue, 1543 description 1544 ) as list_label, 1545 1 as rank 1546 from 1547 clin.v_pat_episodes 1548 where 1549 episode_open is true and 1550 description %(fragment_condition)s 1551 %(ctxt_pat)s 1552 1553 ) union all ( 1554 1555 select 1556 pk_episode 1557 as data, 1558 description 1559 as field_label, 1560 coalesce ( 1561 description || _(' (closed)') || ' - ' || health_issue, 1562 description || _(' (closed)') 1563 ) as list_label, 1564 2 as rank 1565 from 1566 clin.v_pat_episodes 1567 where 1568 description %(fragment_condition)s and 1569 episode_open is false 1570 %(ctxt_pat)s 1571 1572 ) 1573 1574 order by rank, list_label 1575 limit 30""" 1576 ], 1577 context = ctxt 1578 ) 1579 1580 try: 1581 kwargs['patient_id'] 1582 except KeyError: 1583 kwargs['patient_id'] = None 1584 1585 if kwargs['patient_id'] is None: 1586 self.use_current_patient = True 1587 self.__register_patient_change_signals() 1588 pat = gmPerson.gmCurrentPatient() 1589 if pat.connected: 1590 mp.set_context('pat', pat.ID) 1591 else: 1592 self.use_current_patient = False 1593 self.__patient_id = int(kwargs['patient_id']) 1594 mp.set_context('pat', self.__patient_id) 1595 1596 del kwargs['patient_id'] 1597 1598 gmPhraseWheel.cPhraseWheel.__init__ ( 1599 self, 1600 *args, 1601 **kwargs 1602 ) 1603 self.matcher = mp
1604 #-------------------------------------------------------- 1605 # external API 1606 #--------------------------------------------------------
1607 - def set_patient(self, patient_id=None):
1608 if self.use_current_patient: 1609 return False 1610 self.__patient_id = int(patient_id) 1611 self.set_context('pat', self.__patient_id) 1612 return True
1613 #--------------------------------------------------------
1614 - def GetData(self, can_create=False, as_instance=False, is_open=False):
1615 self.__is_open_for_create_data = is_open # used (only) in _create_data() 1616 return gmPhraseWheel.cPhraseWheel.GetData(self, can_create = can_create, as_instance = as_instance)
1617 #--------------------------------------------------------
1618 - def _create_data(self):
1619 1620 epi_name = self.GetValue().strip() 1621 if epi_name == u'': 1622 gmDispatcher.send(signal = u'statustext', msg = _('Cannot create episode without name.'), beep = True) 1623 _log.debug('cannot create episode without name') 1624 return 1625 1626 if self.use_current_patient: 1627 pat = gmPerson.gmCurrentPatient() 1628 else: 1629 pat = gmPerson.cPatient(aPK_obj = self.__patient_id) 1630 1631 emr = pat.get_emr() 1632 epi = emr.add_episode(episode_name = epi_name, is_open = self.__is_open_for_create_data) 1633 if epi is None: 1634 self.data = {} 1635 else: 1636 self.SetText ( 1637 value = epi_name, 1638 data = epi['pk_episode'] 1639 )
1640 #--------------------------------------------------------
1641 - def _data2instance(self):
1642 return gmEMRStructItems.cEpisode(aPK_obj = self.GetData())
1643 #-------------------------------------------------------- 1644 # internal API 1645 #--------------------------------------------------------
1647 gmDispatcher.connect(self._pre_patient_selection, u'pre_patient_selection') 1648 gmDispatcher.connect(self._post_patient_selection, u'post_patient_selection')
1649 #--------------------------------------------------------
1650 - def _pre_patient_selection(self):
1651 return True
1652 #--------------------------------------------------------
1653 - def _post_patient_selection(self):
1654 if self.use_current_patient: 1655 patient = gmPerson.gmCurrentPatient() 1656 self.set_context('pat', patient.ID) 1657 return True
1658 #---------------------------------------------------------------- 1659 from Gnumed.wxGladeWidgets import wxgEpisodeEditAreaPnl 1660
1661 -class cEpisodeEditAreaPnl(gmEditArea.cGenericEditAreaMixin, wxgEpisodeEditAreaPnl.wxgEpisodeEditAreaPnl):
1662
1663 - def __init__(self, *args, **kwargs):
1664 1665 try: 1666 episode = kwargs['episode'] 1667 del kwargs['episode'] 1668 except KeyError: 1669 episode = None 1670 1671 wxgEpisodeEditAreaPnl.wxgEpisodeEditAreaPnl.__init__(self, *args, **kwargs) 1672 gmEditArea.cGenericEditAreaMixin.__init__(self) 1673 1674 self.data = episode
1675 #---------------------------------------------------------------- 1676 # generic Edit Area mixin API 1677 #----------------------------------------------------------------
1678 - def _valid_for_save(self):
1679 1680 errors = False 1681 1682 if len(self._PRW_description.GetValue().strip()) == 0: 1683 errors = True 1684 self._PRW_description.display_as_valid(False) 1685 self._PRW_description.SetFocus() 1686 else: 1687 self._PRW_description.display_as_valid(True) 1688 self._PRW_description.Refresh() 1689 1690 return not errors
1691 #----------------------------------------------------------------
1692 - def _save_as_new(self):
1693 1694 pat = gmPerson.gmCurrentPatient() 1695 emr = pat.get_emr() 1696 1697 epi = emr.add_episode(episode_name = self._PRW_description.GetValue().strip()) 1698 epi['summary'] = self._TCTRL_status.GetValue().strip() 1699 epi['episode_open'] = not self._CHBOX_closed.IsChecked() 1700 epi['diagnostic_certainty_classification'] = self._PRW_certainty.GetData() 1701 1702 issue_name = self._PRW_issue.GetValue().strip() 1703 if len(issue_name) != 0: 1704 epi['pk_health_issue'] = self._PRW_issue.GetData(can_create = True) 1705 issue = gmEMRStructItems.cHealthIssue(aPK_obj = epi['pk_health_issue']) 1706 1707 if not move_episode_to_issue(episode = epi, target_issue = issue, save_to_backend = False): 1708 gmDispatcher.send ( 1709 signal = 'statustext', 1710 msg = _('Cannot attach episode [%s] to health issue [%s] because it already has a running episode.') % ( 1711 epi['description'], 1712 issue['description'] 1713 ) 1714 ) 1715 gmEMRStructItems.delete_episode(episode = epi) 1716 return False 1717 1718 epi.save() 1719 1720 epi.generic_codes = [ c['data'] for c in self._PRW_codes.GetData() ] 1721 1722 self.data = epi 1723 return True
1724 #----------------------------------------------------------------
1725 - def _save_as_update(self):
1726 1727 self.data['description'] = self._PRW_description.GetValue().strip() 1728 self.data['summary'] = self._TCTRL_status.GetValue().strip() 1729 self.data['episode_open'] = not self._CHBOX_closed.IsChecked() 1730 self.data['diagnostic_certainty_classification'] = self._PRW_certainty.GetData() 1731 1732 issue_name = self._PRW_issue.GetValue().strip() 1733 if len(issue_name) == 0: 1734 self.data['pk_health_issue'] = None 1735 else: 1736 self.data['pk_health_issue'] = self._PRW_issue.GetData(can_create = True) 1737 issue = gmEMRStructItems.cHealthIssue(aPK_obj = self.data['pk_health_issue']) 1738 1739 if not move_episode_to_issue(episode = self.data, target_issue = issue, save_to_backend = False): 1740 gmDispatcher.send ( 1741 signal = 'statustext', 1742 msg = _('Cannot attach episode [%s] to health issue [%s] because it already has a running episode.') % ( 1743 self.data['description'], 1744 issue['description'] 1745 ) 1746 ) 1747 return False 1748 1749 self.data.save() 1750 self.data.generic_codes = [ c['data'] for c in self._PRW_codes.GetData() ] 1751 1752 return True
1753 #----------------------------------------------------------------
1754 - def _refresh_as_new(self):
1755 if self.data is None: 1756 ident = gmPerson.gmCurrentPatient() 1757 else: 1758 ident = gmPerson.cIdentity(aPK_obj = self.data['pk_patient']) 1759 self._TCTRL_patient.SetValue(ident.get_description_gender()) 1760 self._PRW_issue.SetText() 1761 self._PRW_description.SetText() 1762 self._TCTRL_status.SetValue(u'') 1763 self._PRW_certainty.SetText() 1764 self._CHBOX_closed.SetValue(False) 1765 self._PRW_codes.SetText()
1766 #----------------------------------------------------------------
1767 - def _refresh_from_existing(self):
1768 ident = gmPerson.cIdentity(aPK_obj = self.data['pk_patient']) 1769 self._TCTRL_patient.SetValue(ident.get_description_gender()) 1770 1771 if self.data['pk_health_issue'] is not None: 1772 self._PRW_issue.SetText(self.data['health_issue'], data=self.data['pk_health_issue']) 1773 1774 self._PRW_description.SetText(self.data['description'], data=self.data['description']) 1775 1776 self._TCTRL_status.SetValue(gmTools.coalesce(self.data['summary'], u'')) 1777 1778 if self.data['diagnostic_certainty_classification'] is not None: 1779 self._PRW_certainty.SetData(data = self.data['diagnostic_certainty_classification']) 1780 1781 self._CHBOX_closed.SetValue(not self.data['episode_open']) 1782 1783 val, data = self._PRW_codes.generic_linked_codes2item_dict(self.data.generic_codes) 1784 self._PRW_codes.SetText(val, data)
1785 #----------------------------------------------------------------
1787 self._refresh_as_new()
1788 #================================================================ 1789 # health issue related widgets/functions 1790 #----------------------------------------------------------------
1791 -def edit_health_issue(parent=None, issue=None):
1792 ea = cHealthIssueEditAreaPnl(parent = parent, id = -1) 1793 ea.data = issue 1794 ea.mode = gmTools.coalesce(issue, 'new', 'edit') 1795 dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = (issue is not None)) 1796 dlg.SetTitle(gmTools.coalesce(issue, _('Adding a new health issue'), _('Editing a health issue'))) 1797 if dlg.ShowModal() == wx.ID_OK: 1798 return True 1799 return False
1800 #----------------------------------------------------------------
1801 -def select_health_issues(parent=None, emr=None):
1802 1803 if parent is None: 1804 parent = wx.GetApp().GetTopWindow() 1805 #----------------------------------------- 1806 def refresh(lctrl): 1807 issues = emr.get_health_issues() 1808 items = [ 1809 [ 1810 gmTools.bool2subst(i['is_confidential'], _('CONFIDENTIAL'), u'', u''), 1811 i['description'], 1812 gmTools.bool2subst(i['clinically_relevant'], _('relevant'), u'', u''), 1813 gmTools.bool2subst(i['is_active'], _('active'), u'', u''), 1814 gmTools.bool2subst(i['is_cause_of_death'], _('fatal'), u'', u'') 1815 ] for i in issues 1816 ] 1817 lctrl.set_string_items(items = items) 1818 lctrl.set_data(data = issues)
1819 #----------------------------------------- 1820 return gmListWidgets.get_choices_from_list ( 1821 parent = parent, 1822 msg = _('\nSelect the health issues !\n'), 1823 caption = _('Showing health issues ...'), 1824 columns = [u'', _('Health issue'), u'', u'', u''], 1825 single_selection = False, 1826 #edit_callback = edit, 1827 #new_callback = edit, 1828 #delete_callback = delete, 1829 refresh_callback = refresh 1830 ) 1831 #----------------------------------------------------------------
1832 -class cIssueListSelectorDlg(gmListWidgets.cGenericListSelectorDlg):
1833 1834 # FIXME: support pre-selection 1835
1836 - def __init__(self, *args, **kwargs):
1837 1838 issues = kwargs['issues'] 1839 del kwargs['issues'] 1840 1841 gmListWidgets.cGenericListSelectorDlg.__init__(self, *args, **kwargs) 1842 1843 self.SetTitle(_('Select the health issues you are interested in ...')) 1844 self._LCTRL_items.set_columns([u'', _('Health Issue'), u'', u'', u'']) 1845 1846 for issue in issues: 1847 if issue['is_confidential']: 1848 row_num = self._LCTRL_items.InsertStringItem(sys.maxint, label = _('confidential')) 1849 self._LCTRL_items.SetItemTextColour(row_num, col=wx.NamedColour('RED')) 1850 else: 1851 row_num = self._LCTRL_items.InsertStringItem(sys.maxint, label = u'') 1852 1853 self._LCTRL_items.SetStringItem(index = row_num, col = 1, label = issue['description']) 1854 if issue['clinically_relevant']: 1855 self._LCTRL_items.SetStringItem(index = row_num, col = 2, label = _('relevant')) 1856 if issue['is_active']: 1857 self._LCTRL_items.SetStringItem(index = row_num, col = 3, label = _('active')) 1858 if issue['is_cause_of_death']: 1859 self._LCTRL_items.SetStringItem(index = row_num, col = 4, label = _('fatal')) 1860 1861 self._LCTRL_items.set_column_widths() 1862 self._LCTRL_items.set_data(data = issues)
1863 #----------------------------------------------------------------
1864 -class cIssueSelectionPhraseWheel(gmPhraseWheel.cPhraseWheel):
1865 """Let the user select a health issue. 1866 1867 The user can select a health issue from the existing issues 1868 of a patient. Selection is done with a phrasewheel so the user 1869 can type the issue name and matches will be shown. Typing 1870 "*" will show the entire list of issues. Inactive issues 1871 will be marked as such. If the user types an issue name not 1872 in the list of existing issues a new issue can be created 1873 from it if the programmer activated that feature. 1874 1875 If keyword <patient_id> is set to None or left out the control 1876 will listen to patient change signals and therefore act on 1877 gmPerson.gmCurrentPatient() changes. 1878 """
1879 - def __init__(self, *args, **kwargs):
1880 1881 ctxt = {'ctxt_pat': {'where_part': u'pk_patient=%(pat)s', 'placeholder': u'pat'}} 1882 1883 mp = gmMatchProvider.cMatchProvider_SQL2 ( 1884 # FIXME: consider clin.health_issue.clinically_relevant 1885 queries = [ 1886 u""" 1887 SELECT 1888 data, 1889 field_label, 1890 list_label 1891 FROM (( 1892 SELECT 1893 pk_health_issue AS data, 1894 description AS field_label, 1895 description AS list_label 1896 FROM clin.v_health_issues 1897 WHERE 1898 is_active IS true 1899 AND 1900 description %(fragment_condition)s 1901 AND 1902 %(ctxt_pat)s 1903 1904 ) UNION ( 1905 1906 SELECT 1907 pk_health_issue AS data, 1908 description AS field_label, 1909 description || _(' (inactive)') AS list_label 1910 FROM clin.v_health_issues 1911 WHERE 1912 is_active IS false 1913 AND 1914 description %(fragment_condition)s 1915 AND 1916 %(ctxt_pat)s 1917 )) AS union_query 1918 ORDER BY 1919 list_label"""], 1920 context = ctxt 1921 ) 1922 1923 try: kwargs['patient_id'] 1924 except KeyError: kwargs['patient_id'] = None 1925 1926 if kwargs['patient_id'] is None: 1927 self.use_current_patient = True 1928 self.__register_patient_change_signals() 1929 pat = gmPerson.gmCurrentPatient() 1930 if pat.connected: 1931 mp.set_context('pat', pat.ID) 1932 else: 1933 self.use_current_patient = False 1934 self.__patient_id = int(kwargs['patient_id']) 1935 mp.set_context('pat', self.__patient_id) 1936 1937 del kwargs['patient_id'] 1938 1939 gmPhraseWheel.cPhraseWheel.__init__ ( 1940 self, 1941 *args, 1942 **kwargs 1943 ) 1944 self.matcher = mp
1945 #-------------------------------------------------------- 1946 # external API 1947 #--------------------------------------------------------
1948 - def set_patient(self, patient_id=None):
1949 if self.use_current_patient: 1950 return False 1951 self.__patient_id = int(patient_id) 1952 self.set_context('pat', self.__patient_id) 1953 return True
1954 #--------------------------------------------------------
1955 - def _create_data(self):
1956 issue_name = self.GetValue().strip() 1957 if issue_name == u'': 1958 gmDispatcher.send(signal = u'statustext', msg = _('Cannot create health issue without name.'), beep = True) 1959 _log.debug('cannot create health issue without name') 1960 return 1961 1962 if self.use_current_patient: 1963 pat = gmPerson.gmCurrentPatient() 1964 else: 1965 pat = gmPerson.cPatient(aPK_obj = self.__patient_id) 1966 1967 emr = pat.get_emr() 1968 issue = emr.add_health_issue(issue_name = issue_name) 1969 1970 if issue is None: 1971 self.data = {} 1972 else: 1973 self.SetText ( 1974 value = issue_name, 1975 data = issue['pk_health_issue'] 1976 )
1977 #--------------------------------------------------------
1978 - def _data2instance(self):
1979 return gmEMRStructItems.cHealthIssue(aPK_obj = self.GetData())
1980 #-------------------------------------------------------- 1981 # internal API 1982 #--------------------------------------------------------
1984 gmDispatcher.connect(self._pre_patient_selection, u'pre_patient_selection') 1985 gmDispatcher.connect(self._post_patient_selection, u'post_patient_selection')
1986 #--------------------------------------------------------
1987 - def _pre_patient_selection(self):
1988 return True
1989 #--------------------------------------------------------
1990 - def _post_patient_selection(self):
1991 if self.use_current_patient: 1992 patient = gmPerson.gmCurrentPatient() 1993 self.set_context('pat', patient.ID) 1994 return True
1995 #------------------------------------------------------------ 1996 from Gnumed.wxGladeWidgets import wxgIssueSelectionDlg 1997
1998 -class cIssueSelectionDlg(wxgIssueSelectionDlg.wxgIssueSelectionDlg):
1999
2000 - def __init__(self, *args, **kwargs):
2001 try: 2002 msg = kwargs['message'] 2003 except KeyError: 2004 msg = None 2005 del kwargs['message'] 2006 wxgIssueSelectionDlg.wxgIssueSelectionDlg.__init__(self, *args, **kwargs) 2007 if msg is not None: 2008 self._lbl_message.SetLabel(label=msg)
2009 #--------------------------------------------------------
2010 - def _on_OK_button_pressed(self, event):
2011 event.Skip() 2012 pk_issue = self._PhWheel_issue.GetData(can_create=True) 2013 if pk_issue is None: 2014 gmGuiHelpers.gm_show_error ( 2015 _('Cannot create new health issue:\n [%(issue)s]') % {'issue': self._PhWheel_issue.GetValue().strip()}, 2016 _('Selecting health issue') 2017 ) 2018 return False 2019 return True
2020 #------------------------------------------------------------ 2021 from Gnumed.wxGladeWidgets import wxgHealthIssueEditAreaPnl 2022
2023 -class cHealthIssueEditAreaPnl(gmEditArea.cGenericEditAreaMixin, wxgHealthIssueEditAreaPnl.wxgHealthIssueEditAreaPnl):
2024 """Panel encapsulating health issue edit area functionality.""" 2025
2026 - def __init__(self, *args, **kwargs):
2027 2028 try: 2029 issue = kwargs['issue'] 2030 except KeyError: 2031 issue = None 2032 2033 wxgHealthIssueEditAreaPnl.wxgHealthIssueEditAreaPnl.__init__(self, *args, **kwargs) 2034 2035 gmEditArea.cGenericEditAreaMixin.__init__(self) 2036 2037 # FIXME: include more sources: coding systems/other database columns 2038 mp = gmMatchProvider.cMatchProvider_SQL2 ( 2039 queries = [u"SELECT DISTINCT ON (description) description, description FROM clin.health_issue WHERE description %(fragment_condition)s LIMIT 50"] 2040 ) 2041 mp.setThresholds(1, 3, 5) 2042 self._PRW_condition.matcher = mp 2043 2044 mp = gmMatchProvider.cMatchProvider_SQL2 ( 2045 queries = [u""" 2046 select distinct on (grouping) grouping, grouping from ( 2047 2048 select rank, grouping from (( 2049 2050 select 2051 grouping, 2052 1 as rank 2053 from 2054 clin.health_issue 2055 where 2056 grouping %%(fragment_condition)s 2057 and 2058 (select True from clin.encounter where fk_patient = %s and pk = clin.health_issue.fk_encounter) 2059 2060 ) union ( 2061 2062 select 2063 grouping, 2064 2 as rank 2065 from 2066 clin.health_issue 2067 where 2068 grouping %%(fragment_condition)s 2069 2070 )) as union_result 2071 2072 order by rank 2073 2074 ) as order_result 2075 2076 limit 50""" % gmPerson.gmCurrentPatient().ID 2077 ] 2078 ) 2079 mp.setThresholds(1, 3, 5) 2080 self._PRW_grouping.matcher = mp 2081 2082 self._PRW_age_noted.add_callback_on_lose_focus(self._on_leave_age_noted) 2083 self._PRW_year_noted.add_callback_on_lose_focus(self._on_leave_year_noted) 2084 2085 self._PRW_age_noted.add_callback_on_modified(self._on_modified_age_noted) 2086 self._PRW_year_noted.add_callback_on_modified(self._on_modified_year_noted) 2087 2088 self._PRW_year_noted.Enable(True) 2089 2090 self._PRW_codes.add_callback_on_lose_focus(self._on_leave_codes) 2091 2092 self.data = issue
2093 #---------------------------------------------------------------- 2094 # generic Edit Area mixin API 2095 #----------------------------------------------------------------
2096 - def _valid_for_save(self):
2097 2098 if self._PRW_condition.GetValue().strip() == '': 2099 self._PRW_condition.display_as_valid(False) 2100 self._PRW_condition.SetFocus() 2101 return False 2102 self._PRW_condition.display_as_valid(True) 2103 self._PRW_condition.Refresh() 2104 2105 # FIXME: sanity check age/year diagnosed 2106 age_noted = self._PRW_age_noted.GetValue().strip() 2107 if age_noted != '': 2108 if gmDateTime.str2interval(str_interval = age_noted) is None: 2109 self._PRW_age_noted.display_as_valid(False) 2110 self._PRW_age_noted.SetFocus() 2111 return False 2112 self._PRW_age_noted.display_as_valid(True) 2113 2114 return True
2115 #----------------------------------------------------------------
2116 - def _save_as_new(self):
2117 pat = gmPerson.gmCurrentPatient() 2118 emr = pat.get_emr() 2119 2120 issue = emr.add_health_issue(issue_name = self._PRW_condition.GetValue().strip()) 2121 2122 side = u'' 2123 if self._ChBOX_left.GetValue(): 2124 side += u's' 2125 if self._ChBOX_right.GetValue(): 2126 side += u'd' 2127 issue['laterality'] = side 2128 2129 issue['summary'] = self._TCTRL_status.GetValue().strip() 2130 issue['diagnostic_certainty_classification'] = self._PRW_certainty.GetData() 2131 issue['grouping'] = self._PRW_grouping.GetValue().strip() 2132 issue['is_active'] = self._ChBOX_active.GetValue() 2133 issue['clinically_relevant'] = self._ChBOX_relevant.GetValue() 2134 issue['is_confidential'] = self._ChBOX_confidential.GetValue() 2135 issue['is_cause_of_death'] = self._ChBOX_caused_death.GetValue() 2136 2137 age_noted = self._PRW_age_noted.GetData() 2138 if age_noted is not None: 2139 issue['age_noted'] = age_noted 2140 2141 issue.save() 2142 2143 issue.generic_codes = [ c['data'] for c in self._PRW_codes.GetData() ] 2144 2145 self.data = issue 2146 return True
2147 #----------------------------------------------------------------
2148 - def _save_as_update(self):
2149 2150 self.data['description'] = self._PRW_condition.GetValue().strip() 2151 2152 side = u'' 2153 if self._ChBOX_left.GetValue(): 2154 side += u's' 2155 if self._ChBOX_right.GetValue(): 2156 side += u'd' 2157 self.data['laterality'] = side 2158 2159 self.data['summary'] = self._TCTRL_status.GetValue().strip() 2160 self.data['diagnostic_certainty_classification'] = self._PRW_certainty.GetData() 2161 self.data['grouping'] = self._PRW_grouping.GetValue().strip() 2162 self.data['is_active'] = bool(self._ChBOX_active.GetValue()) 2163 self.data['clinically_relevant'] = bool(self._ChBOX_relevant.GetValue()) 2164 self.data['is_confidential'] = bool(self._ChBOX_confidential.GetValue()) 2165 self.data['is_cause_of_death'] = bool(self._ChBOX_caused_death.GetValue()) 2166 2167 age_noted = self._PRW_age_noted.GetData() 2168 if age_noted is not None: 2169 self.data['age_noted'] = age_noted 2170 2171 self.data.save() 2172 self.data.generic_codes = [ c['data'] for c in self._PRW_codes.GetData() ] 2173 2174 return True
2175 #----------------------------------------------------------------
2176 - def _refresh_as_new(self):
2177 self._PRW_condition.SetText() 2178 self._ChBOX_left.SetValue(0) 2179 self._ChBOX_right.SetValue(0) 2180 self._PRW_codes.SetText() 2181 self._on_leave_codes() 2182 self._PRW_certainty.SetText() 2183 self._PRW_grouping.SetText() 2184 self._TCTRL_status.SetValue(u'') 2185 self._PRW_age_noted.SetText() 2186 self._PRW_year_noted.SetText() 2187 self._ChBOX_active.SetValue(0) 2188 self._ChBOX_relevant.SetValue(1) 2189 self._ChBOX_confidential.SetValue(0) 2190 self._ChBOX_caused_death.SetValue(0) 2191 2192 return True
2193 #----------------------------------------------------------------
2194 - def _refresh_from_existing(self):
2195 self._PRW_condition.SetText(self.data['description']) 2196 2197 lat = gmTools.coalesce(self.data['laterality'], '') 2198 if lat.find('s') == -1: 2199 self._ChBOX_left.SetValue(0) 2200 else: 2201 self._ChBOX_left.SetValue(1) 2202 if lat.find('d') == -1: 2203 self._ChBOX_right.SetValue(0) 2204 else: 2205 self._ChBOX_right.SetValue(1) 2206 2207 val, data = self._PRW_codes.generic_linked_codes2item_dict(self.data.generic_codes) 2208 self._PRW_codes.SetText(val, data) 2209 self._on_leave_codes() 2210 2211 if self.data['diagnostic_certainty_classification'] is not None: 2212 self._PRW_certainty.SetData(data = self.data['diagnostic_certainty_classification']) 2213 self._PRW_grouping.SetText(gmTools.coalesce(self.data['grouping'], u'')) 2214 self._TCTRL_status.SetValue(gmTools.coalesce(self.data['summary'], u'')) 2215 2216 if self.data['age_noted'] is None: 2217 self._PRW_age_noted.SetText() 2218 else: 2219 self._PRW_age_noted.SetText ( 2220 value = '%sd' % self.data['age_noted'].days, 2221 data = self.data['age_noted'] 2222 ) 2223 2224 self._ChBOX_active.SetValue(self.data['is_active']) 2225 self._ChBOX_relevant.SetValue(self.data['clinically_relevant']) 2226 self._ChBOX_confidential.SetValue(self.data['is_confidential']) 2227 self._ChBOX_caused_death.SetValue(self.data['is_cause_of_death']) 2228 2229 # this dance should assure self._PRW_year_noted gets set -- but it doesn't ... 2230 # self._PRW_age_noted.SetFocus() 2231 # self._PRW_condition.SetFocus() 2232 2233 return True
2234 #----------------------------------------------------------------
2236 return self._refresh_as_new()
2237 #-------------------------------------------------------- 2238 # internal helpers 2239 #--------------------------------------------------------
2240 - def _on_leave_codes(self, *args, **kwargs):
2241 if not self._PRW_codes.IsModified(): 2242 return True 2243 2244 self._TCTRL_code_details.SetValue(u'- ' + u'\n- '.join([ c['list_label'] for c in self._PRW_codes.GetData() ]))
2245 #--------------------------------------------------------
2246 - def _on_leave_age_noted(self, *args, **kwargs):
2247 2248 if not self._PRW_age_noted.IsModified(): 2249 return True 2250 2251 str_age = self._PRW_age_noted.GetValue().strip() 2252 2253 if str_age == u'': 2254 wx.CallAfter(self._PRW_year_noted.SetText, u'', None, True) 2255 return True 2256 2257 age = gmDateTime.str2interval(str_interval = str_age) 2258 2259 if age is None: 2260 gmDispatcher.send(signal='statustext', msg=_('Cannot parse [%s] into valid interval.') % str_age) 2261 self._PRW_age_noted.SetBackgroundColour('pink') 2262 self._PRW_age_noted.Refresh() 2263 wx.CallAfter(self._PRW_year_noted.SetText, u'', None, True) 2264 return True 2265 2266 pat = gmPerson.gmCurrentPatient() 2267 if pat['dob'] is not None: 2268 max_age = pydt.datetime.now(tz=pat['dob'].tzinfo) - pat['dob'] 2269 2270 if age >= max_age: 2271 gmDispatcher.send ( 2272 signal = 'statustext', 2273 msg = _( 2274 'Health issue cannot have been noted at age %s. Patient is only %s old.' 2275 ) % (age, pat.get_medical_age()) 2276 ) 2277 self._PRW_age_noted.SetBackgroundColour('pink') 2278 self._PRW_age_noted.Refresh() 2279 wx.CallAfter(self._PRW_year_noted.SetText, u'', None, True) 2280 return True 2281 2282 self._PRW_age_noted.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)) 2283 self._PRW_age_noted.Refresh() 2284 self._PRW_age_noted.SetData(data=age) 2285 2286 if pat['dob'] is not None: 2287 fts = gmDateTime.cFuzzyTimestamp ( 2288 timestamp = pat['dob'] + age, 2289 accuracy = gmDateTime.acc_months 2290 ) 2291 wx.CallAfter(self._PRW_year_noted.SetText, str(fts), fts) 2292 # if we do this we will *always* navigate there, regardless of TAB vs ALT-TAB 2293 #wx.CallAfter(self._ChBOX_active.SetFocus) 2294 # if we do the following instead it will take us to the save/update button ... 2295 #wx.CallAfter(self.Navigate) 2296 2297 return True
2298 #--------------------------------------------------------
2299 - def _on_leave_year_noted(self, *args, **kwargs):
2300 2301 if not self._PRW_year_noted.IsModified(): 2302 return True 2303 2304 year_noted = self._PRW_year_noted.GetData() 2305 2306 if year_noted is None: 2307 if self._PRW_year_noted.GetValue().strip() == u'': 2308 wx.CallAfter(self._PRW_age_noted.SetText, u'', None, True) 2309 return True 2310 self._PRW_year_noted.SetBackgroundColour('pink') 2311 self._PRW_year_noted.Refresh() 2312 wx.CallAfter(self._PRW_age_noted.SetText, u'', None, True) 2313 return True 2314 2315 year_noted = year_noted.get_pydt() 2316 2317 if year_noted >= pydt.datetime.now(tz=year_noted.tzinfo): 2318 gmDispatcher.send(signal='statustext', msg=_('Condition diagnosed in the future.')) 2319 self._PRW_year_noted.SetBackgroundColour('pink') 2320 self._PRW_year_noted.Refresh() 2321 wx.CallAfter(self._PRW_age_noted.SetText, u'', None, True) 2322 return True 2323 2324 self._PRW_year_noted.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)) 2325 self._PRW_year_noted.Refresh() 2326 2327 pat = gmPerson.gmCurrentPatient() 2328 if pat['dob'] is not None: 2329 issue_age = year_noted - pat['dob'] 2330 str_age = gmDateTime.format_interval_medically(interval = issue_age) 2331 wx.CallAfter(self._PRW_age_noted.SetText, str_age, issue_age) 2332 2333 return True
2334 #--------------------------------------------------------
2335 - def _on_modified_age_noted(self, *args, **kwargs):
2336 wx.CallAfter(self._PRW_year_noted.SetText, u'', None, True) 2337 return True
2338 #--------------------------------------------------------
2339 - def _on_modified_year_noted(self, *args, **kwargs):
2340 wx.CallAfter(self._PRW_age_noted.SetText, u'', None, True) 2341 return True
2342 #================================================================ 2343 # diagnostic certainty related widgets/functions 2344 #----------------------------------------------------------------
2345 -class cDiagnosticCertaintyClassificationPhraseWheel(gmPhraseWheel.cPhraseWheel):
2346
2347 - def __init__(self, *args, **kwargs):
2348 2349 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 2350 2351 self.selection_only = False # can be NULL, too 2352 2353 mp = gmMatchProvider.cMatchProvider_FixedList ( 2354 aSeq = [ 2355 {'data': u'A', 'list_label': gmEMRStructItems.diagnostic_certainty_classification2str(u'A'), 'field_label': gmEMRStructItems.diagnostic_certainty_classification2str(u'A'), 'weight': 1}, 2356 {'data': u'B', 'list_label': gmEMRStructItems.diagnostic_certainty_classification2str(u'B'), 'field_label': gmEMRStructItems.diagnostic_certainty_classification2str(u'B'), 'weight': 1}, 2357 {'data': u'C', 'list_label': gmEMRStructItems.diagnostic_certainty_classification2str(u'C'), 'field_label': gmEMRStructItems.diagnostic_certainty_classification2str(u'C'), 'weight': 1}, 2358 {'data': u'D', 'list_label': gmEMRStructItems.diagnostic_certainty_classification2str(u'D'), 'field_label': gmEMRStructItems.diagnostic_certainty_classification2str(u'D'), 'weight': 1} 2359 ] 2360 ) 2361 mp.setThresholds(1, 2, 4) 2362 self.matcher = mp 2363 2364 self.SetToolTipString(_( 2365 "The diagnostic classification or grading of this assessment.\n" 2366 "\n" 2367 "This documents how certain one is about this being a true diagnosis." 2368 ))
2369 #================================================================ 2370 # MAIN 2371 #---------------------------------------------------------------- 2372 if __name__ == '__main__': 2373 2374 from Gnumed.business import gmPersonSearch 2375 2376 #================================================================
2377 - class testapp (wx.App):
2378 """ 2379 Test application for testing EMR struct widgets 2380 """ 2381 #--------------------------------------------------------
2382 - def OnInit (self):
2383 """ 2384 Create test application UI 2385 """ 2386 frame = wx.Frame ( 2387 None, 2388 -4, 2389 'Testing EMR struct widgets', 2390 size=wx.Size(600, 400), 2391 style=wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE 2392 ) 2393 filemenu= wx.Menu() 2394 filemenu.AppendSeparator() 2395 filemenu.Append(ID_EXIT,"E&xit"," Terminate test application") 2396 2397 # Creating the menubar. 2398 menuBar = wx.MenuBar() 2399 menuBar.Append(filemenu,"&File") 2400 2401 frame.SetMenuBar(menuBar) 2402 2403 txt = wx.StaticText( frame, -1, _("Select desired test option from the 'File' menu"), 2404 wx.DefaultPosition, wx.DefaultSize, 0 ) 2405 2406 # event handlers 2407 wx.EVT_MENU(frame, ID_EXIT, self.OnCloseWindow) 2408 2409 # patient EMR 2410 self.__pat = gmPerson.gmCurrentPatient() 2411 2412 frame.Show(1) 2413 return 1
2414 #--------------------------------------------------------
2415 - def OnCloseWindow (self, e):
2416 """ 2417 Close test aplication 2418 """ 2419 self.ExitMainLoop ()
2420 #----------------------------------------------------------------
2421 - def test_encounter_edit_area_panel():
2422 app = wx.PyWidgetTester(size = (200, 300)) 2423 emr = pat.get_emr() 2424 enc = emr.active_encounter 2425 #enc = gmEMRStructItems.cEncounter(1) 2426 pnl = cEncounterEditAreaPnl(app.frame, -1, encounter=enc) 2427 app.frame.Show(True) 2428 app.MainLoop() 2429 return
2430 #----------------------------------------------------------------
2431 - def test_encounter_edit_area_dialog():
2432 app = wx.PyWidgetTester(size = (200, 300)) 2433 emr = pat.get_emr() 2434 enc = emr.active_encounter 2435 #enc = gmEMRStructItems.cEncounter(1) 2436 2437 dlg = cEncounterEditAreaDlg(parent=app.frame, id=-1, size = (400,400), encounter=enc) 2438 dlg.ShowModal()
2439 2440 # pnl = cEncounterEditAreaDlg(app.frame, -1, encounter=enc) 2441 # app.frame.Show(True) 2442 # app.MainLoop() 2443 #----------------------------------------------------------------
2444 - def test_epsiode_edit_area_pnl():
2445 app = wx.PyWidgetTester(size = (200, 300)) 2446 emr = pat.get_emr() 2447 epi = emr.get_episodes()[0] 2448 pnl = cEpisodeEditAreaPnl(app.frame, -1, episode=epi) 2449 app.frame.Show(True) 2450 app.MainLoop()
2451 #----------------------------------------------------------------
2452 - def test_episode_edit_area_dialog():
2453 app = wx.PyWidgetTester(size = (200, 300)) 2454 emr = pat.get_emr() 2455 epi = emr.get_episodes()[0] 2456 edit_episode(parent=app.frame, episode=epi)
2457 #----------------------------------------------------------------
2458 - def test_hospital_stay_prw():
2459 app = wx.PyWidgetTester(size = (400, 40)) 2460 app.SetWidget(cHospitalStayPhraseWheel, id=-1, size=(180,20), pos=(10,20)) 2461 app.MainLoop()
2462 #----------------------------------------------------------------
2463 - def test_episode_selection_prw():
2464 app = wx.PyWidgetTester(size = (400, 40)) 2465 app.SetWidget(cEpisodeSelectionPhraseWheel, id=-1, size=(180,20), pos=(10,20)) 2466 # app.SetWidget(cEpisodeSelectionPhraseWheel, id=-1, size=(350,20), pos=(10,20), patient_id=pat.ID) 2467 app.MainLoop()
2468 #----------------------------------------------------------------
2469 - def test_health_issue_edit_area_dlg():
2470 app = wx.PyWidgetTester(size = (200, 300)) 2471 edit_health_issue(parent=app.frame, issue=None)
2472 #----------------------------------------------------------------
2473 - def test_health_issue_edit_area_pnl():
2474 app = wx.PyWidgetTester(size = (200, 300)) 2475 app.SetWidget(cHealthIssueEditAreaPnl, id=-1, size = (400,400)) 2476 app.MainLoop()
2477 #----------------------------------------------------------------
2478 - def test_edit_procedure():
2479 app = wx.PyWidgetTester(size = (200, 300)) 2480 edit_procedure(parent=app.frame)
2481 #================================================================ 2482 2483 if (len(sys.argv) > 1) and (sys.argv[1] == 'test'): 2484 2485 gmI18N.activate_locale() 2486 gmI18N.install_domain() 2487 gmDateTime.init() 2488 2489 # obtain patient 2490 pat = gmPersonSearch.ask_for_patient() 2491 if pat is None: 2492 print "No patient. Exiting gracefully..." 2493 sys.exit(0) 2494 gmPatSearchWidgets.set_active_patient(patient=pat) 2495 2496 # try: 2497 # lauch emr dialogs test application 2498 # app = testapp(0) 2499 # app.MainLoop() 2500 # except StandardError: 2501 # _log.exception("unhandled exception caught !") 2502 # but re-raise them 2503 # raise 2504 2505 #test_encounter_edit_area_panel() 2506 #test_encounter_edit_area_dialog() 2507 #test_epsiode_edit_area_pnl() 2508 #test_episode_edit_area_dialog() 2509 #test_health_issue_edit_area_dlg() 2510 #test_episode_selection_prw() 2511 #test_hospital_stay_prw() 2512 test_edit_procedure() 2513 2514 #================================================================ 2515