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