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