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

Source Code for Module Gnumed.wxpython.gmEMRStructWidgets

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