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('%Y %b %d %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 #--------------------------------------------------------
1199 start = self._PRW_encounter_start.GetData() 1200 if start is None: 1201 return 1202 start = start.get_pydt() 1203 1204 end = self._PRW_encounter_end.GetData() 1205 if end is None: 1206 fts = gmDateTime.cFuzzyTimestamp ( 1207 timestamp = start, 1208 accuracy = gmDateTime.acc_minutes 1209 ) 1210 self._PRW_encounter_end.SetText(fts.format_accurately(), data = fts) 1211 return 1212 end = end.get_pydt() 1213 1214 if start > end: 1215 end = end.replace ( 1216 year = start.year, 1217 month = start.month, 1218 day = start.day 1219 ) 1220 fts = gmDateTime.cFuzzyTimestamp ( 1221 timestamp = end, 1222 accuracy = gmDateTime.acc_minutes 1223 ) 1224 self._PRW_encounter_end.SetText(fts.format_accurately(), data = fts) 1225 return 1226 1227 emr = self.__pat.get_emr() 1228 if start != emr.active_encounter['started']: 1229 end = end.replace ( 1230 year = start.year, 1231 month = start.month, 1232 day = start.day 1233 ) 1234 fts = gmDateTime.cFuzzyTimestamp ( 1235 timestamp = end, 1236 accuracy = gmDateTime.acc_minutes 1237 ) 1238 self._PRW_encounter_end.SetText(fts.format_accurately(), data = fts) 1239 return 1240 1241 return
1242 1243 #---------------------------------------------------------------- 1244 from Gnumed.wxGladeWidgets import wxgActiveEncounterPnl 1245
1246 -class cActiveEncounterPnl(wxgActiveEncounterPnl.wxgActiveEncounterPnl):
1247
1248 - def __init__(self, *args, **kwargs):
1249 wxgActiveEncounterPnl.wxgActiveEncounterPnl.__init__(self, *args, **kwargs) 1250 self.__register_events() 1251 self.refresh()
1252 #------------------------------------------------------------
1253 - def clear(self):
1254 self._TCTRL_encounter.SetValue(u'') 1255 self._TCTRL_encounter.SetToolTipString(u'') 1256 self._BTN_new.Enable(False) 1257 self._BTN_list.Enable(False)
1258 #------------------------------------------------------------
1259 - def refresh(self):
1260 pat = gmPerson.gmCurrentPatient() 1261 if not pat.connected: 1262 self.clear() 1263 return 1264 1265 enc = pat.get_emr().active_encounter 1266 self._TCTRL_encounter.SetValue(enc.format(with_docs = False, with_tests = False, fancy_header = False, with_vaccinations = False, with_family_history = False).strip('\n')) 1267 self._TCTRL_encounter.SetToolTipString ( 1268 _('The active encounter of the current patient:\n\n%s') % 1269 enc.format(with_docs = False, with_tests = False, fancy_header = True, with_vaccinations = False, with_rfe_aoe = True, with_family_history = False).strip('\n') 1270 ) 1271 self._BTN_new.Enable(True) 1272 self._BTN_list.Enable(True)
1273 #------------------------------------------------------------
1274 - def __register_events(self):
1275 self._TCTRL_encounter.Bind(wx.EVT_LEFT_DCLICK, self._on_ldclick) 1276 1277 gmDispatcher.connect(signal = u'pre_patient_selection', receiver = self._schedule_clear) 1278 # this would throw an exception due to concurrency issues: 1279 #gmDispatcher.connect(signal = u'post_patient_selection', receiver = self._schedule_refresh) 1280 gmDispatcher.connect(signal = u'episode_mod_db', receiver = self._schedule_refresh) 1281 gmDispatcher.connect(signal = u'current_encounter_modified', receiver = self._schedule_refresh) 1282 gmDispatcher.connect(signal = u'current_encounter_switched', receiver = self._schedule_refresh)
1283 #------------------------------------------------------------ 1284 # event handler 1285 #------------------------------------------------------------
1286 - def _schedule_clear(self):
1287 wx.CallAfter(self.clear)
1288 #------------------------------------------------------------
1289 - def _schedule_refresh(self, *args, **kwargs):
1290 wx.CallAfter(self.refresh) 1291 return True
1292 #------------------------------------------------------------
1293 - def _on_ldclick(self, event):
1294 pat = gmPerson.gmCurrentPatient() 1295 if not pat.connected: 1296 return 1297 edit_encounter(encounter = pat.get_emr().active_encounter)
1298 #------------------------------------------------------------
1299 - def _on_new_button_pressed(self, event):
1300 pat = gmPerson.gmCurrentPatient() 1301 if not pat.connected: 1302 return 1303 start_new_encounter(emr = pat.get_emr())
1304 #------------------------------------------------------------
1305 - def _on_list_button_pressed(self, event):
1306 if not gmPerson.gmCurrentPatient().connected: 1307 return 1308 select_encounters()
1309 #================================================================ 1310 # episode related widgets/functions 1311 #----------------------------------------------------------------
1312 -def edit_episode(parent=None, episode=None):
1313 ea = cEpisodeEditAreaPnl(parent = parent, id = -1) 1314 ea.data = episode 1315 ea.mode = gmTools.coalesce(episode, 'new', 'edit') 1316 dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = True) 1317 dlg.SetTitle(gmTools.coalesce(episode, _('Adding a new episode'), _('Editing an episode'))) 1318 if dlg.ShowModal() == wx.ID_OK: 1319 return True 1320 return False
1321 #----------------------------------------------------------------
1322 -def promote_episode_to_issue(parent=None, episode=None, emr=None):
1323 1324 created_new_issue = False 1325 1326 try: 1327 issue = gmEMRStructItems.cHealthIssue(name = episode['description'], patient = episode['pk_patient']) 1328 except gmExceptions.NoSuchBusinessObjectError: 1329 issue = None 1330 1331 if issue is None: 1332 issue = emr.add_health_issue(issue_name = episode['description']) 1333 created_new_issue = True 1334 else: 1335 # issue exists already, so ask user 1336 dlg = gmGuiHelpers.c3ButtonQuestionDlg ( 1337 parent, 1338 -1, 1339 caption = _('Promoting episode to health issue'), 1340 question = _( 1341 'There already is a health issue\n' 1342 '\n' 1343 ' %s\n' 1344 '\n' 1345 'What do you want to do ?' 1346 ) % issue['description'], 1347 button_defs = [ 1348 {'label': _('Use existing'), 'tooltip': _('Move episode into existing health issue'), 'default': False}, 1349 {'label': _('Create new'), 'tooltip': _('Create a new health issue with another name'), 'default': True} 1350 ] 1351 ) 1352 use_existing = dlg.ShowModal() 1353 dlg.Destroy() 1354 1355 if use_existing == wx.ID_CANCEL: 1356 return 1357 1358 # user wants to create new issue with alternate name 1359 if use_existing == wx.ID_NO: 1360 # loop until name modified but non-empty or cancelled 1361 issue_name = episode['description'] 1362 while issue_name == episode['description']: 1363 dlg = wx.TextEntryDialog ( 1364 parent = parent, 1365 message = _('Enter a short descriptive name for the new health issue:'), 1366 caption = _('Creating a new health issue ...'), 1367 defaultValue = issue_name, 1368 style = wx.OK | wx.CANCEL | wx.CENTRE 1369 ) 1370 decision = dlg.ShowModal() 1371 if decision != wx.ID_OK: 1372 dlg.Destroy() 1373 return 1374 issue_name = dlg.GetValue().strip() 1375 dlg.Destroy() 1376 if issue_name == u'': 1377 issue_name = episode['description'] 1378 1379 issue = emr.add_health_issue(issue_name = issue_name) 1380 created_new_issue = True 1381 1382 # eventually move the episode to the issue 1383 if not move_episode_to_issue(episode = episode, target_issue = issue, save_to_backend = True): 1384 # user cancelled the move so delete just-created issue 1385 if created_new_issue: 1386 # shouldn't fail as it is completely new 1387 gmEMRStructItems.delete_health_issue(health_issue = issue) 1388 return 1389 1390 return
1391 #----------------------------------------------------------------
1392 -def move_episode_to_issue(episode=None, target_issue=None, save_to_backend=False):
1393 """Prepare changing health issue for an episode. 1394 1395 Checks for two-open-episodes conflict. When this 1396 function succeeds, the pk_health_issue has been set 1397 on the episode instance and the episode should - for 1398 all practical purposes - be ready for save_payload(). 1399 """ 1400 # episode is closed: should always work 1401 if not episode['episode_open']: 1402 episode['pk_health_issue'] = target_issue['pk_health_issue'] 1403 if save_to_backend: 1404 episode.save_payload() 1405 return True 1406 1407 # un-associate: should always work, too 1408 if target_issue is None: 1409 episode['pk_health_issue'] = None 1410 if save_to_backend: 1411 episode.save_payload() 1412 return True 1413 1414 # try closing possibly expired episode on target issue if any 1415 db_cfg = gmCfg.cCfgSQL() 1416 epi_ttl = int(db_cfg.get2 ( 1417 option = u'episode.ttl', 1418 workplace = gmSurgery.gmCurrentPractice().active_workplace, 1419 bias = 'user', 1420 default = 60 # 2 months 1421 )) 1422 if target_issue.close_expired_episode(ttl=epi_ttl) is True: 1423 gmDispatcher.send(signal='statustext', msg=_('Closed episodes older than %s days on health issue [%s]') % (epi_ttl, target_issue['description'])) 1424 existing_epi = target_issue.get_open_episode() 1425 1426 # no more open episode on target issue: should work now 1427 if existing_epi is None: 1428 episode['pk_health_issue'] = target_issue['pk_health_issue'] 1429 if save_to_backend: 1430 episode.save_payload() 1431 return True 1432 1433 # don't conflict on SELF ;-) 1434 if existing_epi['pk_episode'] == episode['pk_episode']: 1435 episode['pk_health_issue'] = target_issue['pk_health_issue'] 1436 if save_to_backend: 1437 episode.save_payload() 1438 return True 1439 1440 # we got two open episodes at once, ask user 1441 move_range = episode.get_access_range() 1442 exist_range = existing_epi.get_access_range() 1443 question = _( 1444 'You want to associate the running episode:\n\n' 1445 ' "%(new_epi_name)s" (%(new_epi_start)s - %(new_epi_end)s)\n\n' 1446 'with the health issue:\n\n' 1447 ' "%(issue_name)s"\n\n' 1448 'There already is another episode running\n' 1449 'for this health issue:\n\n' 1450 ' "%(old_epi_name)s" (%(old_epi_start)s - %(old_epi_end)s)\n\n' 1451 'However, there can only be one running\n' 1452 'episode per health issue.\n\n' 1453 'Which episode do you want to close ?' 1454 ) % { 1455 'new_epi_name': episode['description'], 1456 'new_epi_start': move_range[0].strftime('%m/%y'), 1457 'new_epi_end': move_range[1].strftime('%m/%y'), 1458 'issue_name': target_issue['description'], 1459 'old_epi_name': existing_epi['description'], 1460 'old_epi_start': exist_range[0].strftime('%m/%y'), 1461 'old_epi_end': exist_range[1].strftime('%m/%y') 1462 } 1463 dlg = gmGuiHelpers.c3ButtonQuestionDlg ( 1464 parent = None, 1465 id = -1, 1466 caption = _('Resolving two-running-episodes conflict'), 1467 question = question, 1468 button_defs = [ 1469 {'label': _('old episode'), 'default': True, 'tooltip': _('close existing episode "%s"') % existing_epi['description']}, 1470 {'label': _('new episode'), 'default': False, 'tooltip': _('close moving (new) episode "%s"') % episode['description']} 1471 ] 1472 ) 1473 decision = dlg.ShowModal() 1474 1475 if decision == wx.ID_CANCEL: 1476 # button 3: move cancelled by user 1477 return False 1478 1479 elif decision == wx.ID_YES: 1480 # button 1: close old episode 1481 existing_epi['episode_open'] = False 1482 existing_epi.save_payload() 1483 1484 elif decision == wx.ID_NO: 1485 # button 2: close new episode 1486 episode['episode_open'] = False 1487 1488 else: 1489 raise ValueError('invalid result from c3ButtonQuestionDlg: [%s]' % decision) 1490 1491 episode['pk_health_issue'] = target_issue['pk_health_issue'] 1492 if save_to_backend: 1493 episode.save_payload() 1494 return True
1495 #----------------------------------------------------------------
1496 -class cEpisodeListSelectorDlg(gmListWidgets.cGenericListSelectorDlg):
1497 1498 # FIXME: support pre-selection 1499
1500 - def __init__(self, *args, **kwargs):
1501 1502 episodes = kwargs['episodes'] 1503 del kwargs['episodes'] 1504 1505 gmListWidgets.cGenericListSelectorDlg.__init__(self, *args, **kwargs) 1506 1507 self.SetTitle(_('Select the episodes you are interested in ...')) 1508 self._LCTRL_items.set_columns([_('Episode'), _('Status'), _('Health Issue')]) 1509 self._LCTRL_items.set_string_items ( 1510 items = [ 1511 [ epi['description'], 1512 gmTools.bool2str(epi['episode_open'], _('ongoing'), u''), 1513 gmTools.coalesce(epi['health_issue'], u'') 1514 ] 1515 for epi in episodes ] 1516 ) 1517 self._LCTRL_items.set_column_widths() 1518 self._LCTRL_items.set_data(data = episodes)
1519 #----------------------------------------------------------------
1520 -class cEpisodeDescriptionPhraseWheel(gmPhraseWheel.cPhraseWheel):
1521 """Let user select an episode *description*. 1522 1523 The user can select an episode description from the previously 1524 used descriptions across all episodes across all patients. 1525 1526 Selection is done with a phrasewheel so the user can 1527 type the episode name and matches will be shown. Typing 1528 "*" will show the entire list of episodes. 1529 1530 If the user types a description not existing yet a 1531 new episode description will be returned. 1532 """
1533 - def __init__(self, *args, **kwargs):
1534 1535 mp = gmMatchProvider.cMatchProvider_SQL2 ( 1536 queries = [ 1537 u""" 1538 SELECT DISTINCT ON (description) 1539 description 1540 AS data, 1541 description 1542 AS field_label, 1543 description || ' (' 1544 || CASE 1545 WHEN is_open IS TRUE THEN _('ongoing') 1546 ELSE _('closed') 1547 END 1548 || ')' 1549 AS list_label 1550 FROM 1551 clin.episode 1552 WHERE 1553 description %(fragment_condition)s 1554 ORDER BY description 1555 LIMIT 30 1556 """ 1557 ] 1558 ) 1559 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 1560 self.matcher = mp
1561 #----------------------------------------------------------------
1562 -class cEpisodeSelectionPhraseWheel(gmPhraseWheel.cPhraseWheel):
1563 """Let user select an episode. 1564 1565 The user can select an episode from the existing episodes of a 1566 patient. Selection is done with a phrasewheel so the user 1567 can type the episode name and matches will be shown. Typing 1568 "*" will show the entire list of episodes. Closed episodes 1569 will be marked as such. If the user types an episode name not 1570 in the list of existing episodes a new episode can be created 1571 from it if the programmer activated that feature. 1572 1573 If keyword <patient_id> is set to None or left out the control 1574 will listen to patient change signals and therefore act on 1575 gmPerson.gmCurrentPatient() changes. 1576 """
1577 - def __init__(self, *args, **kwargs):
1578 1579 ctxt = {'ctxt_pat': {'where_part': u'and pk_patient = %(pat)s', 'placeholder': u'pat'}} 1580 1581 mp = gmMatchProvider.cMatchProvider_SQL2 ( 1582 queries = [ 1583 u"""( 1584 1585 select 1586 pk_episode 1587 as data, 1588 description 1589 as field_label, 1590 coalesce ( 1591 description || ' - ' || health_issue, 1592 description 1593 ) as list_label, 1594 1 as rank 1595 from 1596 clin.v_pat_episodes 1597 where 1598 episode_open is true and 1599 description %(fragment_condition)s 1600 %(ctxt_pat)s 1601 1602 ) union all ( 1603 1604 select 1605 pk_episode 1606 as data, 1607 description 1608 as field_label, 1609 coalesce ( 1610 description || _(' (closed)') || ' - ' || health_issue, 1611 description || _(' (closed)') 1612 ) as list_label, 1613 2 as rank 1614 from 1615 clin.v_pat_episodes 1616 where 1617 description %(fragment_condition)s and 1618 episode_open is false 1619 %(ctxt_pat)s 1620 1621 ) 1622 1623 order by rank, list_label 1624 limit 30""" 1625 ], 1626 context = ctxt 1627 ) 1628 1629 try: 1630 kwargs['patient_id'] 1631 except KeyError: 1632 kwargs['patient_id'] = None 1633 1634 if kwargs['patient_id'] is None: 1635 self.use_current_patient = True 1636 self.__register_patient_change_signals() 1637 pat = gmPerson.gmCurrentPatient() 1638 if pat.connected: 1639 mp.set_context('pat', pat.ID) 1640 else: 1641 self.use_current_patient = False 1642 self.__patient_id = int(kwargs['patient_id']) 1643 mp.set_context('pat', self.__patient_id) 1644 1645 del kwargs['patient_id'] 1646 1647 gmPhraseWheel.cPhraseWheel.__init__ ( 1648 self, 1649 *args, 1650 **kwargs 1651 ) 1652 self.matcher = mp
1653 #-------------------------------------------------------- 1654 # external API 1655 #--------------------------------------------------------
1656 - def set_patient(self, patient_id=None):
1657 if self.use_current_patient: 1658 return False 1659 self.__patient_id = int(patient_id) 1660 self.set_context('pat', self.__patient_id) 1661 return True
1662 #--------------------------------------------------------
1663 - def GetData(self, can_create=False, as_instance=False, is_open=False):
1664 self.__is_open_for_create_data = is_open # used (only) in _create_data() 1665 return gmPhraseWheel.cPhraseWheel.GetData(self, can_create = can_create, as_instance = as_instance)
1666 #--------------------------------------------------------
1667 - def _create_data(self):
1668 1669 epi_name = self.GetValue().strip() 1670 if epi_name == u'': 1671 gmDispatcher.send(signal = u'statustext', msg = _('Cannot create episode without name.'), beep = True) 1672 _log.debug('cannot create episode without name') 1673 return 1674 1675 if self.use_current_patient: 1676 pat = gmPerson.gmCurrentPatient() 1677 else: 1678 pat = gmPerson.cPatient(aPK_obj = self.__patient_id) 1679 1680 emr = pat.get_emr() 1681 epi = emr.add_episode(episode_name = epi_name, is_open = self.__is_open_for_create_data) 1682 if epi is None: 1683 self.data = {} 1684 else: 1685 self.SetText ( 1686 value = epi_name, 1687 data = epi['pk_episode'] 1688 )
1689 #--------------------------------------------------------
1690 - def _data2instance(self):
1691 return gmEMRStructItems.cEpisode(aPK_obj = self.GetData())
1692 #-------------------------------------------------------- 1693 # internal API 1694 #--------------------------------------------------------
1696 gmDispatcher.connect(self._pre_patient_selection, u'pre_patient_selection') 1697 gmDispatcher.connect(self._post_patient_selection, u'post_patient_selection')
1698 #--------------------------------------------------------
1699 - def _pre_patient_selection(self):
1700 return True
1701 #--------------------------------------------------------
1702 - def _post_patient_selection(self):
1703 if self.use_current_patient: 1704 patient = gmPerson.gmCurrentPatient() 1705 self.set_context('pat', patient.ID) 1706 return True
1707 #---------------------------------------------------------------- 1708 from Gnumed.wxGladeWidgets import wxgEpisodeEditAreaPnl 1709
1710 -class cEpisodeEditAreaPnl(gmEditArea.cGenericEditAreaMixin, wxgEpisodeEditAreaPnl.wxgEpisodeEditAreaPnl):
1711
1712 - def __init__(self, *args, **kwargs):
1713 1714 try: 1715 episode = kwargs['episode'] 1716 del kwargs['episode'] 1717 except KeyError: 1718 episode = None 1719 1720 wxgEpisodeEditAreaPnl.wxgEpisodeEditAreaPnl.__init__(self, *args, **kwargs) 1721 gmEditArea.cGenericEditAreaMixin.__init__(self) 1722 1723 self.data = episode
1724 #---------------------------------------------------------------- 1725 # generic Edit Area mixin API 1726 #----------------------------------------------------------------
1727 - def _valid_for_save(self):
1728 1729 errors = False 1730 1731 if len(self._PRW_description.GetValue().strip()) == 0: 1732 errors = True 1733 self._PRW_description.display_as_valid(False) 1734 self._PRW_description.SetFocus() 1735 else: 1736 self._PRW_description.display_as_valid(True) 1737 self._PRW_description.Refresh() 1738 1739 return not errors
1740 #----------------------------------------------------------------
1741 - def _save_as_new(self):
1742 1743 pat = gmPerson.gmCurrentPatient() 1744 emr = pat.get_emr() 1745 1746 epi = emr.add_episode(episode_name = self._PRW_description.GetValue().strip()) 1747 epi['summary'] = self._TCTRL_status.GetValue().strip() 1748 epi['episode_open'] = not self._CHBOX_closed.IsChecked() 1749 epi['diagnostic_certainty_classification'] = self._PRW_certainty.GetData() 1750 1751 issue_name = self._PRW_issue.GetValue().strip() 1752 if len(issue_name) != 0: 1753 epi['pk_health_issue'] = self._PRW_issue.GetData(can_create = True) 1754 issue = gmEMRStructItems.cHealthIssue(aPK_obj = epi['pk_health_issue']) 1755 1756 if not move_episode_to_issue(episode = epi, target_issue = issue, save_to_backend = False): 1757 gmDispatcher.send ( 1758 signal = 'statustext', 1759 msg = _('Cannot attach episode [%s] to health issue [%s] because it already has a running episode.') % ( 1760 epi['description'], 1761 issue['description'] 1762 ) 1763 ) 1764 gmEMRStructItems.delete_episode(episode = epi) 1765 return False 1766 1767 epi.save() 1768 1769 epi.generic_codes = [ c['data'] for c in self._PRW_codes.GetData() ] 1770 1771 self.data = epi 1772 return True
1773 #----------------------------------------------------------------
1774 - def _save_as_update(self):
1775 1776 self.data['description'] = self._PRW_description.GetValue().strip() 1777 self.data['summary'] = self._TCTRL_status.GetValue().strip() 1778 self.data['episode_open'] = not self._CHBOX_closed.IsChecked() 1779 self.data['diagnostic_certainty_classification'] = self._PRW_certainty.GetData() 1780 1781 issue_name = self._PRW_issue.GetValue().strip() 1782 if len(issue_name) == 0: 1783 self.data['pk_health_issue'] = None 1784 else: 1785 self.data['pk_health_issue'] = self._PRW_issue.GetData(can_create = True) 1786 issue = gmEMRStructItems.cHealthIssue(aPK_obj = self.data['pk_health_issue']) 1787 1788 if not move_episode_to_issue(episode = self.data, target_issue = issue, save_to_backend = False): 1789 gmDispatcher.send ( 1790 signal = 'statustext', 1791 msg = _('Cannot attach episode [%s] to health issue [%s] because it already has a running episode.') % ( 1792 self.data['description'], 1793 issue['description'] 1794 ) 1795 ) 1796 return False 1797 1798 self.data.save() 1799 self.data.generic_codes = [ c['data'] for c in self._PRW_codes.GetData() ] 1800 1801 return True
1802 #----------------------------------------------------------------
1803 - def _refresh_as_new(self):
1804 if self.data is None: 1805 ident = gmPerson.gmCurrentPatient() 1806 else: 1807 ident = gmPerson.cIdentity(aPK_obj = self.data['pk_patient']) 1808 self._TCTRL_patient.SetValue(ident.get_description_gender()) 1809 self._PRW_issue.SetText() 1810 self._PRW_description.SetText() 1811 self._TCTRL_status.SetValue(u'') 1812 self._PRW_certainty.SetText() 1813 self._CHBOX_closed.SetValue(False) 1814 self._PRW_codes.SetText()
1815 #----------------------------------------------------------------
1816 - def _refresh_from_existing(self):
1817 ident = gmPerson.cIdentity(aPK_obj = self.data['pk_patient']) 1818 self._TCTRL_patient.SetValue(ident.get_description_gender()) 1819 1820 if self.data['pk_health_issue'] is not None: 1821 self._PRW_issue.SetText(self.data['health_issue'], data=self.data['pk_health_issue']) 1822 1823 self._PRW_description.SetText(self.data['description'], data=self.data['description']) 1824 1825 self._TCTRL_status.SetValue(gmTools.coalesce(self.data['summary'], u'')) 1826 1827 if self.data['diagnostic_certainty_classification'] is not None: 1828 self._PRW_certainty.SetData(data = self.data['diagnostic_certainty_classification']) 1829 1830 self._CHBOX_closed.SetValue(not self.data['episode_open']) 1831 1832 val, data = self._PRW_codes.generic_linked_codes2item_dict(self.data.generic_codes) 1833 self._PRW_codes.SetText(val, data)
1834 #----------------------------------------------------------------
1836 self._refresh_as_new()
1837 #================================================================ 1838 # health issue related widgets/functions 1839 #----------------------------------------------------------------
1840 -def edit_health_issue(parent=None, issue=None):
1841 ea = cHealthIssueEditAreaPnl(parent = parent, id = -1) 1842 ea.data = issue 1843 ea.mode = gmTools.coalesce(issue, 'new', 'edit') 1844 dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = (issue is not None)) 1845 dlg.SetTitle(gmTools.coalesce(issue, _('Adding a new health issue'), _('Editing a health issue'))) 1846 if dlg.ShowModal() == wx.ID_OK: 1847 return True 1848 return False
1849 #----------------------------------------------------------------
1850 -def select_health_issues(parent=None, emr=None):
1851 1852 if parent is None: 1853 parent = wx.GetApp().GetTopWindow() 1854 #----------------------------------------- 1855 def refresh(lctrl): 1856 issues = emr.get_health_issues() 1857 items = [ 1858 [ 1859 gmTools.bool2subst(i['is_confidential'], _('CONFIDENTIAL'), u'', u''), 1860 i['description'], 1861 gmTools.bool2subst(i['clinically_relevant'], _('relevant'), u'', u''), 1862 gmTools.bool2subst(i['is_active'], _('active'), u'', u''), 1863 gmTools.bool2subst(i['is_cause_of_death'], _('fatal'), u'', u'') 1864 ] for i in issues 1865 ] 1866 lctrl.set_string_items(items = items) 1867 lctrl.set_data(data = issues)
1868 #----------------------------------------- 1869 return gmListWidgets.get_choices_from_list ( 1870 parent = parent, 1871 msg = _('\nSelect the health issues !\n'), 1872 caption = _('Showing health issues ...'), 1873 columns = [u'', _('Health issue'), u'', u'', u''], 1874 single_selection = False, 1875 #edit_callback = edit, 1876 #new_callback = edit, 1877 #delete_callback = delete, 1878 refresh_callback = refresh 1879 ) 1880 #----------------------------------------------------------------
1881 -class cIssueListSelectorDlg(gmListWidgets.cGenericListSelectorDlg):
1882 1883 # FIXME: support pre-selection 1884
1885 - def __init__(self, *args, **kwargs):
1886 1887 issues = kwargs['issues'] 1888 del kwargs['issues'] 1889 1890 gmListWidgets.cGenericListSelectorDlg.__init__(self, *args, **kwargs) 1891 1892 self.SetTitle(_('Select the health issues you are interested in ...')) 1893 self._LCTRL_items.set_columns([u'', _('Health Issue'), u'', u'', u'']) 1894 1895 for issue in issues: 1896 if issue['is_confidential']: 1897 row_num = self._LCTRL_items.InsertStringItem(sys.maxint, label = _('confidential')) 1898 self._LCTRL_items.SetItemTextColour(row_num, col=wx.NamedColour('RED')) 1899 else: 1900 row_num = self._LCTRL_items.InsertStringItem(sys.maxint, label = u'') 1901 1902 self._LCTRL_items.SetStringItem(index = row_num, col = 1, label = issue['description']) 1903 if issue['clinically_relevant']: 1904 self._LCTRL_items.SetStringItem(index = row_num, col = 2, label = _('relevant')) 1905 if issue['is_active']: 1906 self._LCTRL_items.SetStringItem(index = row_num, col = 3, label = _('active')) 1907 if issue['is_cause_of_death']: 1908 self._LCTRL_items.SetStringItem(index = row_num, col = 4, label = _('fatal')) 1909 1910 self._LCTRL_items.set_column_widths() 1911 self._LCTRL_items.set_data(data = issues)
1912 #----------------------------------------------------------------
1913 -class cIssueSelectionPhraseWheel(gmPhraseWheel.cPhraseWheel):
1914 """Let the user select a health issue. 1915 1916 The user can select a health issue from the existing issues 1917 of a patient. Selection is done with a phrasewheel so the user 1918 can type the issue name and matches will be shown. Typing 1919 "*" will show the entire list of issues. Inactive issues 1920 will be marked as such. If the user types an issue name not 1921 in the list of existing issues a new issue can be created 1922 from it if the programmer activated that feature. 1923 1924 If keyword <patient_id> is set to None or left out the control 1925 will listen to patient change signals and therefore act on 1926 gmPerson.gmCurrentPatient() changes. 1927 """
1928 - def __init__(self, *args, **kwargs):
1929 1930 ctxt = {'ctxt_pat': {'where_part': u'pk_patient=%(pat)s', 'placeholder': u'pat'}} 1931 1932 mp = gmMatchProvider.cMatchProvider_SQL2 ( 1933 # FIXME: consider clin.health_issue.clinically_relevant 1934 queries = [ 1935 u""" 1936 SELECT 1937 data, 1938 field_label, 1939 list_label 1940 FROM (( 1941 SELECT 1942 pk_health_issue AS data, 1943 description AS field_label, 1944 description AS list_label 1945 FROM clin.v_health_issues 1946 WHERE 1947 is_active IS true 1948 AND 1949 description %(fragment_condition)s 1950 AND 1951 %(ctxt_pat)s 1952 1953 ) UNION ( 1954 1955 SELECT 1956 pk_health_issue AS data, 1957 description AS field_label, 1958 description || _(' (inactive)') AS list_label 1959 FROM clin.v_health_issues 1960 WHERE 1961 is_active IS false 1962 AND 1963 description %(fragment_condition)s 1964 AND 1965 %(ctxt_pat)s 1966 )) AS union_query 1967 ORDER BY 1968 list_label"""], 1969 context = ctxt 1970 ) 1971 1972 try: kwargs['patient_id'] 1973 except KeyError: kwargs['patient_id'] = None 1974 1975 if kwargs['patient_id'] is None: 1976 self.use_current_patient = True 1977 self.__register_patient_change_signals() 1978 pat = gmPerson.gmCurrentPatient() 1979 if pat.connected: 1980 mp.set_context('pat', pat.ID) 1981 else: 1982 self.use_current_patient = False 1983 self.__patient_id = int(kwargs['patient_id']) 1984 mp.set_context('pat', self.__patient_id) 1985 1986 del kwargs['patient_id'] 1987 1988 gmPhraseWheel.cPhraseWheel.__init__ ( 1989 self, 1990 *args, 1991 **kwargs 1992 ) 1993 self.matcher = mp
1994 #-------------------------------------------------------- 1995 # external API 1996 #--------------------------------------------------------
1997 - def set_patient(self, patient_id=None):
1998 if self.use_current_patient: 1999 return False 2000 self.__patient_id = int(patient_id) 2001 self.set_context('pat', self.__patient_id) 2002 return True
2003 #--------------------------------------------------------
2004 - def _create_data(self):
2005 issue_name = self.GetValue().strip() 2006 if issue_name == u'': 2007 gmDispatcher.send(signal = u'statustext', msg = _('Cannot create health issue without name.'), beep = True) 2008 _log.debug('cannot create health issue without name') 2009 return 2010 2011 if self.use_current_patient: 2012 pat = gmPerson.gmCurrentPatient() 2013 else: 2014 pat = gmPerson.cPatient(aPK_obj = self.__patient_id) 2015 2016 emr = pat.get_emr() 2017 issue = emr.add_health_issue(issue_name = issue_name) 2018 2019 if issue is None: 2020 self.data = {} 2021 else: 2022 self.SetText ( 2023 value = issue_name, 2024 data = issue['pk_health_issue'] 2025 )
2026 #--------------------------------------------------------
2027 - def _data2instance(self):
2028 return gmEMRStructItems.cHealthIssue(aPK_obj = self.GetData())
2029 #-------------------------------------------------------- 2030 # internal API 2031 #--------------------------------------------------------
2033 gmDispatcher.connect(self._pre_patient_selection, u'pre_patient_selection') 2034 gmDispatcher.connect(self._post_patient_selection, u'post_patient_selection')
2035 #--------------------------------------------------------
2036 - def _pre_patient_selection(self):
2037 return True
2038 #--------------------------------------------------------
2039 - def _post_patient_selection(self):
2040 if self.use_current_patient: 2041 patient = gmPerson.gmCurrentPatient() 2042 self.set_context('pat', patient.ID) 2043 return True
2044 #------------------------------------------------------------ 2045 from Gnumed.wxGladeWidgets import wxgIssueSelectionDlg 2046
2047 -class cIssueSelectionDlg(wxgIssueSelectionDlg.wxgIssueSelectionDlg):
2048
2049 - def __init__(self, *args, **kwargs):
2050 try: 2051 msg = kwargs['message'] 2052 except KeyError: 2053 msg = None 2054 del kwargs['message'] 2055 wxgIssueSelectionDlg.wxgIssueSelectionDlg.__init__(self, *args, **kwargs) 2056 if msg is not None: 2057 self._lbl_message.SetLabel(label=msg)
2058 #--------------------------------------------------------
2059 - def _on_OK_button_pressed(self, event):
2060 event.Skip() 2061 pk_issue = self._PhWheel_issue.GetData(can_create=True) 2062 if pk_issue is None: 2063 gmGuiHelpers.gm_show_error ( 2064 _('Cannot create new health issue:\n [%(issue)s]') % {'issue': self._PhWheel_issue.GetValue().strip()}, 2065 _('Selecting health issue') 2066 ) 2067 return False 2068 return True
2069 #------------------------------------------------------------ 2070 from Gnumed.wxGladeWidgets import wxgHealthIssueEditAreaPnl 2071
2072 -class cHealthIssueEditAreaPnl(gmEditArea.cGenericEditAreaMixin, wxgHealthIssueEditAreaPnl.wxgHealthIssueEditAreaPnl):
2073 """Panel encapsulating health issue edit area functionality.""" 2074
2075 - def __init__(self, *args, **kwargs):
2076 2077 try: 2078 issue = kwargs['issue'] 2079 except KeyError: 2080 issue = None 2081 2082 wxgHealthIssueEditAreaPnl.wxgHealthIssueEditAreaPnl.__init__(self, *args, **kwargs) 2083 2084 gmEditArea.cGenericEditAreaMixin.__init__(self) 2085 2086 # FIXME: include more sources: coding systems/other database columns 2087 mp = gmMatchProvider.cMatchProvider_SQL2 ( 2088 queries = [u"SELECT DISTINCT ON (description) description, description FROM clin.health_issue WHERE description %(fragment_condition)s LIMIT 50"] 2089 ) 2090 mp.setThresholds(1, 3, 5) 2091 self._PRW_condition.matcher = mp 2092 2093 mp = gmMatchProvider.cMatchProvider_SQL2 ( 2094 queries = [u""" 2095 select distinct on (grouping) grouping, grouping from ( 2096 2097 select rank, grouping from (( 2098 2099 select 2100 grouping, 2101 1 as rank 2102 from 2103 clin.health_issue 2104 where 2105 grouping %%(fragment_condition)s 2106 and 2107 (select True from clin.encounter where fk_patient = %s and pk = clin.health_issue.fk_encounter) 2108 2109 ) union ( 2110 2111 select 2112 grouping, 2113 2 as rank 2114 from 2115 clin.health_issue 2116 where 2117 grouping %%(fragment_condition)s 2118 2119 )) as union_result 2120 2121 order by rank 2122 2123 ) as order_result 2124 2125 limit 50""" % gmPerson.gmCurrentPatient().ID 2126 ] 2127 ) 2128 mp.setThresholds(1, 3, 5) 2129 self._PRW_grouping.matcher = mp 2130 2131 self._PRW_age_noted.add_callback_on_lose_focus(self._on_leave_age_noted) 2132 self._PRW_year_noted.add_callback_on_lose_focus(self._on_leave_year_noted) 2133 2134 self._PRW_age_noted.add_callback_on_modified(self._on_modified_age_noted) 2135 self._PRW_year_noted.add_callback_on_modified(self._on_modified_year_noted) 2136 2137 self._PRW_year_noted.Enable(True) 2138 2139 self._PRW_codes.add_callback_on_lose_focus(self._on_leave_codes) 2140 2141 self.data = issue
2142 #---------------------------------------------------------------- 2143 # generic Edit Area mixin API 2144 #----------------------------------------------------------------
2145 - def _valid_for_save(self):
2146 2147 if self._PRW_condition.GetValue().strip() == '': 2148 self._PRW_condition.display_as_valid(False) 2149 self._PRW_condition.SetFocus() 2150 return False 2151 self._PRW_condition.display_as_valid(True) 2152 self._PRW_condition.Refresh() 2153 2154 # FIXME: sanity check age/year diagnosed 2155 age_noted = self._PRW_age_noted.GetValue().strip() 2156 if age_noted != '': 2157 if gmDateTime.str2interval(str_interval = age_noted) is None: 2158 self._PRW_age_noted.display_as_valid(False) 2159 self._PRW_age_noted.SetFocus() 2160 return False 2161 self._PRW_age_noted.display_as_valid(True) 2162 2163 return True
2164 #----------------------------------------------------------------
2165 - def _save_as_new(self):
2166 pat = gmPerson.gmCurrentPatient() 2167 emr = pat.get_emr() 2168 2169 issue = emr.add_health_issue(issue_name = self._PRW_condition.GetValue().strip()) 2170 2171 side = u'' 2172 if self._ChBOX_left.GetValue(): 2173 side += u's' 2174 if self._ChBOX_right.GetValue(): 2175 side += u'd' 2176 issue['laterality'] = side 2177 2178 issue['summary'] = self._TCTRL_status.GetValue().strip() 2179 issue['diagnostic_certainty_classification'] = self._PRW_certainty.GetData() 2180 issue['grouping'] = self._PRW_grouping.GetValue().strip() 2181 issue['is_active'] = self._ChBOX_active.GetValue() 2182 issue['clinically_relevant'] = self._ChBOX_relevant.GetValue() 2183 issue['is_confidential'] = self._ChBOX_confidential.GetValue() 2184 issue['is_cause_of_death'] = self._ChBOX_caused_death.GetValue() 2185 2186 age_noted = self._PRW_age_noted.GetData() 2187 if age_noted is not None: 2188 issue['age_noted'] = age_noted 2189 2190 issue.save() 2191 2192 issue.generic_codes = [ c['data'] for c in self._PRW_codes.GetData() ] 2193 2194 self.data = issue 2195 return True
2196 #----------------------------------------------------------------
2197 - def _save_as_update(self):
2198 2199 self.data['description'] = self._PRW_condition.GetValue().strip() 2200 2201 side = u'' 2202 if self._ChBOX_left.GetValue(): 2203 side += u's' 2204 if self._ChBOX_right.GetValue(): 2205 side += u'd' 2206 self.data['laterality'] = side 2207 2208 self.data['summary'] = self._TCTRL_status.GetValue().strip() 2209 self.data['diagnostic_certainty_classification'] = self._PRW_certainty.GetData() 2210 self.data['grouping'] = self._PRW_grouping.GetValue().strip() 2211 self.data['is_active'] = bool(self._ChBOX_active.GetValue()) 2212 self.data['clinically_relevant'] = bool(self._ChBOX_relevant.GetValue()) 2213 self.data['is_confidential'] = bool(self._ChBOX_confidential.GetValue()) 2214 self.data['is_cause_of_death'] = bool(self._ChBOX_caused_death.GetValue()) 2215 2216 age_noted = self._PRW_age_noted.GetData() 2217 if age_noted is not None: 2218 self.data['age_noted'] = age_noted 2219 2220 self.data.save() 2221 self.data.generic_codes = [ c['data'] for c in self._PRW_codes.GetData() ] 2222 2223 return True
2224 #----------------------------------------------------------------
2225 - def _refresh_as_new(self):
2226 self._PRW_condition.SetText() 2227 self._ChBOX_left.SetValue(0) 2228 self._ChBOX_right.SetValue(0) 2229 self._PRW_codes.SetText() 2230 self._on_leave_codes() 2231 self._PRW_certainty.SetText() 2232 self._PRW_grouping.SetText() 2233 self._TCTRL_status.SetValue(u'') 2234 self._PRW_age_noted.SetText() 2235 self._PRW_year_noted.SetText() 2236 self._ChBOX_active.SetValue(1) 2237 self._ChBOX_relevant.SetValue(1) 2238 self._ChBOX_confidential.SetValue(0) 2239 self._ChBOX_caused_death.SetValue(0) 2240 2241 return True
2242 #----------------------------------------------------------------
2243 - def _refresh_from_existing(self):
2244 self._PRW_condition.SetText(self.data['description']) 2245 2246 lat = gmTools.coalesce(self.data['laterality'], '') 2247 if lat.find('s') == -1: 2248 self._ChBOX_left.SetValue(0) 2249 else: 2250 self._ChBOX_left.SetValue(1) 2251 if lat.find('d') == -1: 2252 self._ChBOX_right.SetValue(0) 2253 else: 2254 self._ChBOX_right.SetValue(1) 2255 2256 val, data = self._PRW_codes.generic_linked_codes2item_dict(self.data.generic_codes) 2257 self._PRW_codes.SetText(val, data) 2258 self._on_leave_codes() 2259 2260 if self.data['diagnostic_certainty_classification'] is not None: 2261 self._PRW_certainty.SetData(data = self.data['diagnostic_certainty_classification']) 2262 self._PRW_grouping.SetText(gmTools.coalesce(self.data['grouping'], u'')) 2263 self._TCTRL_status.SetValue(gmTools.coalesce(self.data['summary'], u'')) 2264 2265 if self.data['age_noted'] is None: 2266 self._PRW_age_noted.SetText() 2267 else: 2268 self._PRW_age_noted.SetText ( 2269 value = '%sd' % self.data['age_noted'].days, 2270 data = self.data['age_noted'] 2271 ) 2272 2273 self._ChBOX_active.SetValue(self.data['is_active']) 2274 self._ChBOX_relevant.SetValue(self.data['clinically_relevant']) 2275 self._ChBOX_confidential.SetValue(self.data['is_confidential']) 2276 self._ChBOX_caused_death.SetValue(self.data['is_cause_of_death']) 2277 2278 # this dance should assure self._PRW_year_noted gets set -- but it doesn't ... 2279 # self._PRW_age_noted.SetFocus() 2280 # self._PRW_condition.SetFocus() 2281 2282 return True
2283 #----------------------------------------------------------------
2285 return self._refresh_as_new()
2286 #-------------------------------------------------------- 2287 # internal helpers 2288 #--------------------------------------------------------
2289 - def _on_leave_codes(self, *args, **kwargs):
2290 if not self._PRW_codes.IsModified(): 2291 return True 2292 2293 self._TCTRL_code_details.SetValue(u'- ' + u'\n- '.join([ c['list_label'] for c in self._PRW_codes.GetData() ]))
2294 #--------------------------------------------------------
2295 - def _on_leave_age_noted(self, *args, **kwargs):
2296 2297 if not self._PRW_age_noted.IsModified(): 2298 return True 2299 2300 str_age = self._PRW_age_noted.GetValue().strip() 2301 2302 if str_age == u'': 2303 wx.CallAfter(self._PRW_year_noted.SetText, u'', None, True) 2304 return True 2305 2306 age = gmDateTime.str2interval(str_interval = str_age) 2307 2308 if age is None: 2309 gmDispatcher.send(signal='statustext', msg=_('Cannot parse [%s] into valid interval.') % str_age) 2310 self._PRW_age_noted.SetBackgroundColour('pink') 2311 self._PRW_age_noted.Refresh() 2312 wx.CallAfter(self._PRW_year_noted.SetText, u'', None, True) 2313 return True 2314 2315 pat = gmPerson.gmCurrentPatient() 2316 if pat['dob'] is not None: 2317 max_age = pydt.datetime.now(tz=pat['dob'].tzinfo) - pat['dob'] 2318 2319 if age >= max_age: 2320 gmDispatcher.send ( 2321 signal = 'statustext', 2322 msg = _( 2323 'Health issue cannot have been noted at age %s. Patient is only %s old.' 2324 ) % (age, pat.get_medical_age()) 2325 ) 2326 self._PRW_age_noted.SetBackgroundColour('pink') 2327 self._PRW_age_noted.Refresh() 2328 wx.CallAfter(self._PRW_year_noted.SetText, u'', None, True) 2329 return True 2330 2331 self._PRW_age_noted.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)) 2332 self._PRW_age_noted.Refresh() 2333 self._PRW_age_noted.SetData(data=age) 2334 2335 if pat['dob'] is not None: 2336 fts = gmDateTime.cFuzzyTimestamp ( 2337 timestamp = pat['dob'] + age, 2338 accuracy = gmDateTime.acc_months 2339 ) 2340 wx.CallAfter(self._PRW_year_noted.SetText, str(fts), fts) 2341 # if we do this we will *always* navigate there, regardless of TAB vs ALT-TAB 2342 #wx.CallAfter(self._ChBOX_active.SetFocus) 2343 # if we do the following instead it will take us to the save/update button ... 2344 #wx.CallAfter(self.Navigate) 2345 2346 return True
2347 #--------------------------------------------------------
2348 - def _on_leave_year_noted(self, *args, **kwargs):
2349 2350 if not self._PRW_year_noted.IsModified(): 2351 return True 2352 2353 year_noted = self._PRW_year_noted.GetData() 2354 2355 if year_noted is None: 2356 if self._PRW_year_noted.GetValue().strip() == u'': 2357 wx.CallAfter(self._PRW_age_noted.SetText, u'', None, True) 2358 return True 2359 self._PRW_year_noted.SetBackgroundColour('pink') 2360 self._PRW_year_noted.Refresh() 2361 wx.CallAfter(self._PRW_age_noted.SetText, u'', None, True) 2362 return True 2363 2364 year_noted = year_noted.get_pydt() 2365 2366 if year_noted >= pydt.datetime.now(tz=year_noted.tzinfo): 2367 gmDispatcher.send(signal='statustext', msg=_('Condition diagnosed in the future.')) 2368 self._PRW_year_noted.SetBackgroundColour('pink') 2369 self._PRW_year_noted.Refresh() 2370 wx.CallAfter(self._PRW_age_noted.SetText, u'', None, True) 2371 return True 2372 2373 self._PRW_year_noted.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)) 2374 self._PRW_year_noted.Refresh() 2375 2376 pat = gmPerson.gmCurrentPatient() 2377 if pat['dob'] is not None: 2378 issue_age = year_noted - pat['dob'] 2379 str_age = gmDateTime.format_interval_medically(interval = issue_age) 2380 wx.CallAfter(self._PRW_age_noted.SetText, str_age, issue_age) 2381 2382 return True
2383 #--------------------------------------------------------
2384 - def _on_modified_age_noted(self, *args, **kwargs):
2385 wx.CallAfter(self._PRW_year_noted.SetText, u'', None, True) 2386 return True
2387 #--------------------------------------------------------
2388 - def _on_modified_year_noted(self, *args, **kwargs):
2389 wx.CallAfter(self._PRW_age_noted.SetText, u'', None, True) 2390 return True
2391 #================================================================ 2392 # diagnostic certainty related widgets/functions 2393 #----------------------------------------------------------------
2394 -class cDiagnosticCertaintyClassificationPhraseWheel(gmPhraseWheel.cPhraseWheel):
2395
2396 - def __init__(self, *args, **kwargs):
2397 2398 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 2399 2400 self.selection_only = False # can be NULL, too 2401 2402 mp = gmMatchProvider.cMatchProvider_FixedList ( 2403 aSeq = [ 2404 {'data': u'A', 'list_label': gmEMRStructItems.diagnostic_certainty_classification2str(u'A'), 'field_label': gmEMRStructItems.diagnostic_certainty_classification2str(u'A'), 'weight': 1}, 2405 {'data': u'B', 'list_label': gmEMRStructItems.diagnostic_certainty_classification2str(u'B'), 'field_label': gmEMRStructItems.diagnostic_certainty_classification2str(u'B'), 'weight': 1}, 2406 {'data': u'C', 'list_label': gmEMRStructItems.diagnostic_certainty_classification2str(u'C'), 'field_label': gmEMRStructItems.diagnostic_certainty_classification2str(u'C'), 'weight': 1}, 2407 {'data': u'D', 'list_label': gmEMRStructItems.diagnostic_certainty_classification2str(u'D'), 'field_label': gmEMRStructItems.diagnostic_certainty_classification2str(u'D'), 'weight': 1} 2408 ] 2409 ) 2410 mp.setThresholds(1, 2, 4) 2411 self.matcher = mp 2412 2413 self.SetToolTipString(_( 2414 "The diagnostic classification or grading of this assessment.\n" 2415 "\n" 2416 "This documents how certain one is about this being a true diagnosis." 2417 ))
2418 #================================================================ 2419 # MAIN 2420 #---------------------------------------------------------------- 2421 if __name__ == '__main__': 2422 2423 from Gnumed.business import gmPersonSearch 2424 2425 #================================================================
2426 - class testapp (wx.App):
2427 """ 2428 Test application for testing EMR struct widgets 2429 """ 2430 #--------------------------------------------------------
2431 - def OnInit (self):
2432 """ 2433 Create test application UI 2434 """ 2435 frame = wx.Frame ( 2436 None, 2437 -4, 2438 'Testing EMR struct widgets', 2439 size=wx.Size(600, 400), 2440 style=wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE 2441 ) 2442 filemenu= wx.Menu() 2443 filemenu.AppendSeparator() 2444 filemenu.Append(ID_EXIT,"E&xit"," Terminate test application") 2445 2446 # Creating the menubar. 2447 menuBar = wx.MenuBar() 2448 menuBar.Append(filemenu,"&File") 2449 2450 frame.SetMenuBar(menuBar) 2451 2452 txt = wx.StaticText( frame, -1, _("Select desired test option from the 'File' menu"), 2453 wx.DefaultPosition, wx.DefaultSize, 0 ) 2454 2455 # event handlers 2456 wx.EVT_MENU(frame, ID_EXIT, self.OnCloseWindow) 2457 2458 # patient EMR 2459 self.__pat = gmPerson.gmCurrentPatient() 2460 2461 frame.Show(1) 2462 return 1
2463 #--------------------------------------------------------
2464 - def OnCloseWindow (self, e):
2465 """ 2466 Close test aplication 2467 """ 2468 self.ExitMainLoop ()
2469 #----------------------------------------------------------------
2470 - def test_encounter_edit_area_panel():
2471 app = wx.PyWidgetTester(size = (200, 300)) 2472 emr = pat.get_emr() 2473 enc = emr.active_encounter 2474 #enc = gmEMRStructItems.cEncounter(1) 2475 pnl = cEncounterEditAreaPnl(app.frame, -1, encounter=enc) 2476 app.frame.Show(True) 2477 app.MainLoop() 2478 return
2479 #----------------------------------------------------------------
2480 - def test_encounter_edit_area_dialog():
2481 app = wx.PyWidgetTester(size = (200, 300)) 2482 emr = pat.get_emr() 2483 enc = emr.active_encounter 2484 #enc = gmEMRStructItems.cEncounter(1) 2485 2486 dlg = cEncounterEditAreaDlg(parent=app.frame, id=-1, size = (400,400), encounter=enc) 2487 dlg.ShowModal()
2488 2489 # pnl = cEncounterEditAreaDlg(app.frame, -1, encounter=enc) 2490 # app.frame.Show(True) 2491 # app.MainLoop() 2492 #----------------------------------------------------------------
2493 - def test_epsiode_edit_area_pnl():
2494 app = wx.PyWidgetTester(size = (200, 300)) 2495 emr = pat.get_emr() 2496 epi = emr.get_episodes()[0] 2497 pnl = cEpisodeEditAreaPnl(app.frame, -1, episode=epi) 2498 app.frame.Show(True) 2499 app.MainLoop()
2500 #----------------------------------------------------------------
2501 - def test_episode_edit_area_dialog():
2502 app = wx.PyWidgetTester(size = (200, 300)) 2503 emr = pat.get_emr() 2504 epi = emr.get_episodes()[0] 2505 edit_episode(parent=app.frame, episode=epi)
2506 #----------------------------------------------------------------
2507 - def test_hospital_stay_prw():
2508 app = wx.PyWidgetTester(size = (400, 40)) 2509 app.SetWidget(cHospitalStayPhraseWheel, id=-1, size=(180,20), pos=(10,20)) 2510 app.MainLoop()
2511 #----------------------------------------------------------------
2512 - def test_episode_selection_prw():
2513 app = wx.PyWidgetTester(size = (400, 40)) 2514 app.SetWidget(cEpisodeSelectionPhraseWheel, id=-1, size=(180,20), pos=(10,20)) 2515 # app.SetWidget(cEpisodeSelectionPhraseWheel, id=-1, size=(350,20), pos=(10,20), patient_id=pat.ID) 2516 app.MainLoop()
2517 #----------------------------------------------------------------
2518 - def test_health_issue_edit_area_dlg():
2519 app = wx.PyWidgetTester(size = (200, 300)) 2520 edit_health_issue(parent=app.frame, issue=None)
2521 #----------------------------------------------------------------
2522 - def test_health_issue_edit_area_pnl():
2523 app = wx.PyWidgetTester(size = (200, 300)) 2524 app.SetWidget(cHealthIssueEditAreaPnl, id=-1, size = (400,400)) 2525 app.MainLoop()
2526 #----------------------------------------------------------------
2527 - def test_edit_procedure():
2528 app = wx.PyWidgetTester(size = (200, 300)) 2529 edit_procedure(parent=app.frame)
2530 #================================================================ 2531 2532 if (len(sys.argv) > 1) and (sys.argv[1] == 'test'): 2533 2534 gmI18N.activate_locale() 2535 gmI18N.install_domain() 2536 gmDateTime.init() 2537 2538 # obtain patient 2539 pat = gmPersonSearch.ask_for_patient() 2540 if pat is None: 2541 print "No patient. Exiting gracefully..." 2542 sys.exit(0) 2543 gmPatSearchWidgets.set_active_patient(patient=pat) 2544 2545 # try: 2546 # lauch emr dialogs test application 2547 # app = testapp(0) 2548 # app.MainLoop() 2549 # except StandardError: 2550 # _log.exception("unhandled exception caught !") 2551 # but re-raise them 2552 # raise 2553 2554 #test_encounter_edit_area_panel() 2555 #test_encounter_edit_area_dialog() 2556 #test_epsiode_edit_area_pnl() 2557 #test_episode_edit_area_dialog() 2558 #test_health_issue_edit_area_dlg() 2559 #test_episode_selection_prw() 2560 #test_hospital_stay_prw() 2561 test_edit_procedure() 2562 2563 #================================================================ 2564