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