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

Source Code for Module Gnumed.wxpython.gmEMRStructWidgets

   1  """GNUmed EMR structure editors 
   2   
   3          This module contains widgets to create and edit EMR structural 
   4          elements (issues, enconters, episodes). 
   5   
   6          This is based on initial work and ideas by Syan <kittylitter@swiftdsl.com.au> 
   7          and Karsten <Karsten.Hilbert@gmx.net>. 
   8  """ 
   9  #================================================================ 
  10  __author__ = "cfmoro1976@yahoo.es, karsten.hilbert@gmx.net" 
  11  __license__ = "GPL v2 or later" 
  12   
  13  # stdlib 
  14  import sys 
  15  import time 
  16  import logging 
  17  import datetime as pydt 
  18   
  19   
  20  # 3rd party 
  21  import wx 
  22   
  23   
  24  # GNUmed 
  25  if __name__ == '__main__': 
  26          sys.path.insert(0, '../../') 
  27  from Gnumed.pycommon import gmI18N 
  28  from Gnumed.pycommon import gmExceptions 
  29  from Gnumed.pycommon import gmCfg 
  30  from Gnumed.pycommon import gmDateTime 
  31  from Gnumed.pycommon import gmTools 
  32  from Gnumed.pycommon import gmDispatcher 
  33  from Gnumed.pycommon import gmMatchProvider 
  34   
  35  from Gnumed.business import gmEMRStructItems 
  36  from Gnumed.business import gmPraxis 
  37  from Gnumed.business import gmPerson 
  38   
  39  from Gnumed.wxpython import gmPhraseWheel 
  40  from Gnumed.wxpython import gmGuiHelpers 
  41  from Gnumed.wxpython import gmListWidgets 
  42  from Gnumed.wxpython import gmEditArea 
  43  from Gnumed.wxpython import gmOrganizationWidgets 
  44   
  45   
  46  _log = logging.getLogger('gm.ui') 
  47   
  48  #================================================================ 
  49  # EMR access helper functions 
  50  #---------------------------------------------------------------- 
51 -def emr_access_spinner(time2spin=0):
52 """Spin time in seconds.""" 53 if time2spin == 0: 54 return 55 sleep_time = 0.1 56 total_rounds = int(time2spin / sleep_time) 57 if total_rounds < 1: 58 return 59 rounds = 0 60 while rounds < total_rounds: 61 wx.Yield() 62 time.sleep(sleep_time) 63 rounds += 1
64 #================================================================ 65 # performed procedure related widgets/functions 66 #----------------------------------------------------------------
67 -def manage_performed_procedures(parent=None):
68 69 pat = gmPerson.gmCurrentPatient() 70 emr = pat.get_emr() 71 72 if parent is None: 73 parent = wx.GetApp().GetTopWindow() 74 #----------------------------------------- 75 def edit(procedure=None): 76 return edit_procedure(parent = parent, procedure = procedure)
77 #----------------------------------------- 78 def delete(procedure=None): 79 if gmEMRStructItems.delete_performed_procedure(procedure = procedure['pk_procedure']): 80 return True 81 82 gmDispatcher.send ( 83 signal = u'statustext', 84 msg = _('Cannot delete performed procedure.'), 85 beep = True 86 ) 87 return False 88 #----------------------------------------- 89 def refresh(lctrl): 90 procs = emr.get_performed_procedures() 91 92 items = [ 93 [ 94 u'%s%s' % ( 95 p['clin_when'].strftime('%Y-%m-%d'), 96 gmTools.bool2subst ( 97 p['is_ongoing'], 98 _(' (ongoing)'), 99 gmTools.coalesce ( 100 initial = p['clin_end'], 101 instead = u'', 102 template_initial = u' - %s', 103 function_initial = ('strftime', u'%Y-%m-%d') 104 ) 105 ) 106 ), 107 u'%s @ %s' % (p['unit'], p['organization']), 108 p['episode'], 109 p['performed_procedure'] 110 ] for p in procs 111 ] 112 lctrl.set_string_items(items = items) 113 lctrl.set_data(data = procs) 114 #----------------------------------------- 115 gmListWidgets.get_choices_from_list ( 116 parent = parent, 117 msg = _('\nSelect the procedure you want to edit !\n'), 118 caption = _('Editing performed procedures ...'), 119 columns = [_('When'), _('Where'), _('Episode'), _('Procedure')], 120 single_selection = True, 121 edit_callback = edit, 122 new_callback = edit, 123 delete_callback = delete, 124 refresh_callback = refresh 125 ) 126 #----------------------------------------------------------------
127 -def edit_procedure(parent=None, procedure=None):
128 ea = cProcedureEAPnl(parent = parent, id = -1) 129 ea.data = procedure 130 ea.mode = gmTools.coalesce(procedure, 'new', 'edit') 131 dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = True) 132 dlg.SetTitle(gmTools.coalesce(procedure, _('Adding a procedure'), _('Editing a procedure'))) 133 if dlg.ShowModal() == wx.ID_OK: 134 dlg.Destroy() 135 return True 136 dlg.Destroy() 137 return False
138 #---------------------------------------------------------------- 139 from Gnumed.wxGladeWidgets import wxgProcedureEAPnl 140
141 -class cProcedureEAPnl(wxgProcedureEAPnl.wxgProcedureEAPnl, gmEditArea.cGenericEditAreaMixin):
142
143 - def __init__(self, *args, **kwargs):
144 wxgProcedureEAPnl.wxgProcedureEAPnl.__init__(self, *args, **kwargs) 145 gmEditArea.cGenericEditAreaMixin.__init__(self) 146 147 self.mode = 'new' 148 self.data = None 149 150 self.__init_ui()
151 #----------------------------------------------------------------
152 - def __init_ui(self):
153 self._PRW_hospital_stay.add_callback_on_lose_focus(callback = self._on_hospital_stay_lost_focus) 154 self._PRW_hospital_stay.set_context(context = 'pat', val = gmPerson.gmCurrentPatient().ID) 155 self._PRW_location.add_callback_on_lose_focus(callback = self._on_location_lost_focus) 156 self._DPRW_date.add_callback_on_lose_focus(callback = self._on_start_lost_focus) 157 self._DPRW_end.add_callback_on_lose_focus(callback = self._on_end_lost_focus) 158 159 # procedure 160 mp = gmMatchProvider.cMatchProvider_SQL2 ( 161 queries = [ 162 u""" 163 select distinct on (narrative) narrative, narrative 164 from clin.procedure 165 where narrative %(fragment_condition)s 166 order by narrative 167 limit 25 168 """ ] 169 ) 170 mp.setThresholds(2, 4, 6) 171 self._PRW_procedure.matcher = mp
172 #----------------------------------------------------------------
174 stay = self._PRW_hospital_stay.GetData() 175 if stay is None: 176 self._PRW_hospital_stay.SetText() 177 self._PRW_location.Enable(True) 178 self._PRW_location.display_as_disabled(False) 179 self._PRW_episode.Enable(True) 180 self._PRW_episode.display_as_disabled(False) 181 self._LBL_hospital_details.SetLabel(u'') 182 else: 183 self._PRW_location.SetText() 184 self._PRW_location.Enable(False) 185 self._PRW_location.display_as_disabled(True) 186 self._PRW_episode.SetText() 187 self._PRW_episode.Enable(False) 188 self._PRW_episode.display_as_disabled(True) 189 self._LBL_hospital_details.SetLabel(gmEMRStructItems.cHospitalStay(aPK_obj = stay).format())
190 #----------------------------------------------------------------
191 - def _on_location_lost_focus(self):
192 loc = self._PRW_location.GetData() 193 if loc is None: 194 self._PRW_hospital_stay.Enable(True) 195 self._PRW_hospital_stay.display_as_disabled(False) 196 self._PRW_episode.Enable(False) 197 self._PRW_episode.display_as_disabled(True) 198 else: 199 self._PRW_hospital_stay.SetText() 200 self._PRW_hospital_stay.Enable(False) 201 self._PRW_hospital_stay.display_as_disabled(True) 202 self._PRW_episode.Enable(True) 203 self._PRW_episode.display_as_disabled(False)
204 #----------------------------------------------------------------
205 - def _on_start_lost_focus(self):
206 if not self._DPRW_date.is_valid_timestamp(): 207 return 208 end = self._DPRW_end.GetData() 209 if end is None: 210 return 211 end = end.get_pydt() 212 start = self._DPRW_date.GetData().get_pydt() 213 if start < end: 214 return 215 self._DPRW_date.display_as_valid(False)
216 #----------------------------------------------------------------
217 - def _on_end_lost_focus(self):
218 end = self._DPRW_end.GetData() 219 if end is None: 220 self._CHBOX_ongoing.Enable(True) 221 self._DPRW_end.display_as_valid(True) 222 else: 223 self._CHBOX_ongoing.Enable(False) 224 end = end.get_pydt() 225 now = gmDateTime.pydt_now_here() 226 if end > now: 227 self._CHBOX_ongoing.SetValue(True) 228 else: 229 self._CHBOX_ongoing.SetValue(False) 230 start = self._DPRW_date.GetData() 231 if start is None: 232 self._DPRW_end.display_as_valid(True) 233 else: 234 start = start.get_pydt() 235 if end > start: 236 self._DPRW_end.display_as_valid(True) 237 else: 238 self._DPRW_end.display_as_valid(False)
239 #---------------------------------------------------------------- 240 # generic Edit Area mixin API 241 #----------------------------------------------------------------
242 - def _valid_for_save(self):
243 244 has_errors = False 245 246 if not self._DPRW_date.is_valid_timestamp(): 247 self._DPRW_date.display_as_valid(False) 248 has_errors = True 249 else: 250 self._DPRW_date.display_as_valid(True) 251 252 start = self._DPRW_date.GetData() 253 end = self._DPRW_end.GetData() 254 self._DPRW_end.display_as_valid(True) 255 if end is not None: 256 end = end.get_pydt() 257 if start is not None: 258 start = start.get_pydt() 259 if end < start: 260 has_errors = True 261 self._DPRW_end.display_as_valid(False) 262 if self._CHBOX_ongoing.IsChecked(): 263 now = gmDateTime.pydt_now_here() 264 if end < now: 265 has_errors = True 266 self._DPRW_end.display_as_valid(False) 267 268 if self._PRW_hospital_stay.GetData() is None: 269 if self._PRW_episode.GetValue().strip() == u'': 270 self._PRW_episode.display_as_valid(False) 271 has_errors = True 272 else: 273 self._PRW_episode.display_as_valid(True) 274 else: 275 self._PRW_episode.display_as_valid(True) 276 277 if (self._PRW_procedure.GetValue() is None) or (self._PRW_procedure.GetValue().strip() == u''): 278 self._PRW_procedure.display_as_valid(False) 279 has_errors = True 280 else: 281 self._PRW_procedure.display_as_valid(True) 282 283 invalid_location = ( 284 (self._PRW_hospital_stay.GetData() is None) and (self._PRW_location.GetData() is None) 285 or 286 (self._PRW_hospital_stay.GetData() is not None) and (self._PRW_location.GetData() is not None) 287 ) 288 if invalid_location: 289 self._PRW_hospital_stay.display_as_valid(False) 290 self._PRW_location.display_as_valid(False) 291 has_errors = True 292 else: 293 self._PRW_hospital_stay.display_as_valid(True) 294 self._PRW_location.display_as_valid(True) 295 296 gmDispatcher.send(signal = 'statustext', msg = _('Cannot save procedure.'), beep = True) 297 298 return (has_errors is False)
299 #----------------------------------------------------------------
300 - def _save_as_new(self):
301 302 pat = gmPerson.gmCurrentPatient() 303 emr = pat.get_emr() 304 305 stay = self._PRW_hospital_stay.GetData() 306 if stay is None: 307 epi = self._PRW_episode.GetData(can_create = True) 308 else: 309 epi = gmEMRStructItems.cHospitalStay(aPK_obj = stay)['pk_episode'] 310 311 proc = emr.add_performed_procedure ( 312 episode = epi, 313 location = self._PRW_location.GetData(), 314 hospital_stay = stay, 315 procedure = self._PRW_procedure.GetValue().strip() 316 ) 317 318 proc['clin_when'] = self._DPRW_date.GetData().get_pydt() 319 if self._DPRW_end.GetData() is None: 320 proc['clin_end'] = None 321 else: 322 proc['clin_end'] = self._DPRW_end.GetData().get_pydt() 323 proc['is_ongoing'] = self._CHBOX_ongoing.IsChecked() 324 proc.save() 325 326 proc.generic_codes = [ c['data'] for c in self._PRW_codes.GetData() ] 327 328 self.data = proc 329 330 return True
331 #----------------------------------------------------------------
332 - def _save_as_update(self):
333 self.data['clin_when'] = self._DPRW_date.GetData().get_pydt() 334 self.data['is_ongoing'] = self._CHBOX_ongoing.IsChecked() 335 self.data['pk_org_unit'] = self._PRW_location.GetData() 336 self.data['pk_hospital_stay'] = self._PRW_hospital_stay.GetData() 337 self.data['performed_procedure'] = self._PRW_procedure.GetValue().strip() 338 if self._DPRW_end.GetData() is None: 339 self.data['clin_end'] = None 340 else: 341 self.data['clin_end'] = self._DPRW_end.GetData().get_pydt() 342 if self.data['pk_hospital_stay'] is None: 343 self.data['pk_episode'] = self._PRW_episode.GetData() 344 else: 345 self.data['pk_episode'] = gmEMRStructItems.cHospitalStay(aPK_obj = self._PRW_hospital_stay.GetData())['pk_episode'] 346 self.data.save() 347 348 self.data.generic_codes = [ c['data'] for c in self._PRW_codes.GetData() ] 349 350 return True
351 #----------------------------------------------------------------
352 - def _refresh_as_new(self):
353 self._DPRW_date.SetText() 354 self._DPRW_end.SetText() 355 self._CHBOX_ongoing.SetValue(False) 356 self._CHBOX_ongoing.Enable(True) 357 self._PRW_hospital_stay.SetText() 358 self._LBL_hospital_details.SetLabel(u'') 359 self._PRW_location.SetText() 360 self._PRW_episode.SetText() 361 self._PRW_procedure.SetText() 362 self._PRW_codes.SetText() 363 364 self._PRW_procedure.SetFocus()
365 #----------------------------------------------------------------
366 - def _refresh_from_existing(self):
367 self._DPRW_date.SetData(data = self.data['clin_when']) 368 if self.data['clin_end'] is None: 369 self._DPRW_end.SetText() 370 self._CHBOX_ongoing.Enable(True) 371 self._CHBOX_ongoing.SetValue(self.data['is_ongoing']) 372 else: 373 self._DPRW_end.SetData(data = self.data['clin_end']) 374 self._CHBOX_ongoing.Enable(False) 375 now = gmDateTime.pydt_now_here() 376 if self.data['clin_end'] > now: 377 self._CHBOX_ongoing.SetValue(True) 378 else: 379 self._CHBOX_ongoing.SetValue(False) 380 self._PRW_episode.SetText(value = self.data['episode'], data = self.data['pk_episode']) 381 self._PRW_procedure.SetText(value = self.data['performed_procedure'], data = self.data['performed_procedure']) 382 383 if self.data['pk_hospital_stay'] is None: 384 self._PRW_hospital_stay.SetText() 385 self._PRW_hospital_stay.Enable(False) 386 self._PRW_hospital_stay.display_as_disabled(True) 387 self._LBL_hospital_details.SetLabel(u'') 388 self._PRW_location.SetText(value = u'%s @ %s' % (self.data['unit'], self.data['organization']), data = self.data['pk_org_unit']) 389 self._PRW_location.Enable(True) 390 self._PRW_location.display_as_disabled(False) 391 self._PRW_episode.Enable(True) 392 self._PRW_episode.display_as_disabled(False) 393 else: 394 self._PRW_hospital_stay.SetText(value = u'%s @ %s' % (self.data['unit'], self.data['organization']), data = self.data['pk_hospital_stay']) 395 self._PRW_hospital_stay.Enable(True) 396 self._PRW_hospital_stay.display_as_disabled(False) 397 self._LBL_hospital_details.SetLabel(gmEMRStructItems.cHospitalStay(aPK_obj = self.data['pk_hospital_stay']).format()) 398 self._PRW_location.SetText() 399 self._PRW_location.Enable(False) 400 self._PRW_location.display_as_disabled(True) 401 self._PRW_episode.Enable(False) 402 self._PRW_episode.display_as_disabled(True) 403 404 val, data = self._PRW_codes.generic_linked_codes2item_dict(self.data.generic_codes) 405 self._PRW_codes.SetText(val, data) 406 407 self._PRW_procedure.SetFocus()
408 #----------------------------------------------------------------
410 self._refresh_as_new() 411 412 self._PRW_episode.SetText(value = self.data['episode'], data = self.data['pk_episode']) 413 414 if self.data['pk_hospital_stay'] is None: 415 self._PRW_hospital_stay.SetText() 416 self._PRW_hospital_stay.Enable(False) 417 self._PRW_hospital_stay.display_as_disabled(True) 418 self._LBL_hospital_details.SetLabel(u'') 419 self._PRW_location.SetText(value = u'%s @ %s' % (self.data['unit'], self.data['organization']), data = self.data['pk_org_unit']) 420 self._PRW_location.Enable(True) 421 self._PRW_location.display_as_disabled(False) 422 self._PRW_episode.Enable(True) 423 self._PRW_episode.display_as_disabled(False) 424 else: 425 self._PRW_hospital_stay.SetText(value = u'%s @ %s' % (self.data['unit'], self.data['organization']), data = self.data['pk_hospital_stay']) 426 self._PRW_hospital_stay.Enable(True) 427 self._PRW_hospital_stay.display_as_disabled(False) 428 self._LBL_hospital_details.SetLabel(gmEMRStructItems.cHospitalStay(aPK_obj = self.data['pk_hospital_stay']).format()) 429 self._PRW_location.SetText() 430 self._PRW_location.Enable(False) 431 self._PRW_location.display_as_disabled(True) 432 self._PRW_episode.Enable(False) 433 self._PRW_episode.display_as_disabled(True) 434 435 self._PRW_procedure.SetFocus()
436 #---------------------------------------------------------------- 437 # event handlers 438 #----------------------------------------------------------------
440 # FIXME: this would benefit from setting the created stay 441 edit_hospital_stay(parent = self.GetParent()) 442 evt.Skip()
443 #----------------------------------------------------------------
444 - def _on_add_location_button_pressed(self, event):
445 gmOrganizationWidgets.manage_orgs(parent = self) #self.GetParent()) 446 event.Skip()
447 #----------------------------------------------------------------
448 - def _on_ongoing_checkbox_checked(self, event):
449 if self._CHBOX_ongoing.IsChecked(): 450 end = self._DPRW_end.GetData() 451 if end is None: 452 self._DPRW_end.display_as_valid(True) 453 else: 454 end = end.get_pydt() 455 now = gmDateTime.pydt_now_here() 456 if end > now: 457 self._DPRW_end.display_as_valid(True) 458 else: 459 self._DPRW_end.display_as_valid(False) 460 else: 461 self._DPRW_end.is_valid_timestamp() 462 event.Skip()
463 464 #================================================================ 465 # hospitalizations related widgets/functions 466 #----------------------------------------------------------------
467 -def manage_hospital_stays(parent=None):
468 469 pat = gmPerson.gmCurrentPatient() 470 emr = pat.get_emr() 471 472 if parent is None: 473 parent = wx.GetApp().GetTopWindow() 474 #----------------------------------------- 475 def get_tooltip(stay=None): 476 if stay is None: 477 return None 478 return stay.format ( 479 include_procedures = True, 480 include_docs = True 481 )
482 #----------------------------------------- 483 def edit(stay=None): 484 return edit_hospital_stay(parent = parent, hospital_stay = stay) 485 #----------------------------------------- 486 def delete(stay=None): 487 if gmEMRStructItems.delete_hospital_stay(stay = stay['pk_hospital_stay']): 488 return True 489 gmDispatcher.send ( 490 signal = u'statustext', 491 msg = _('Cannot delete hospitalization.'), 492 beep = True 493 ) 494 return False 495 #----------------------------------------- 496 def refresh(lctrl): 497 stays = emr.get_hospital_stays() 498 items = [ 499 [ 500 s['admission'].strftime('%Y-%m-%d'), 501 gmTools.coalesce(s['discharge'], u'', function_initial = ('strftime', '%Y-%m-%d')), 502 s['episode'], 503 u'%s @ %s' % (s['ward'], s['hospital']) 504 ] for s in stays 505 ] 506 lctrl.set_string_items(items = items) 507 lctrl.set_data(data = stays) 508 #----------------------------------------- 509 gmListWidgets.get_choices_from_list ( 510 parent = parent, 511 msg = _("The patient's hospitalizations:\n"), 512 caption = _('Editing hospitalizations ...'), 513 columns = [_('Admission'), _('Discharge'), _('Reason'), _('Hospital')], 514 single_selection = True, 515 edit_callback = edit, 516 new_callback = edit, 517 delete_callback = delete, 518 refresh_callback = refresh, 519 list_tooltip_callback = get_tooltip 520 ) 521 522 #----------------------------------------------------------------
523 -def edit_hospital_stay(parent=None, hospital_stay=None):
524 ea = cHospitalStayEditAreaPnl(parent = parent, id = -1) 525 ea.data = hospital_stay 526 ea.mode = gmTools.coalesce(hospital_stay, 'new', 'edit') 527 dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = True) 528 dlg.SetTitle(gmTools.coalesce(hospital_stay, _('Adding a hospitalization'), _('Editing a hospitalization'))) 529 if dlg.ShowModal() == wx.ID_OK: 530 dlg.Destroy() 531 return True 532 dlg.Destroy() 533 return False
534 535 #----------------------------------------------------------------
536 -class cHospitalWardPhraseWheel(gmPhraseWheel.cPhraseWheel):
537 """Phrasewheel to allow selection of a hospitalization."""
538 - def __init__(self, *args, **kwargs):
539 540 gmPhraseWheel.cPhraseWheel.__init__ (self, *args, **kwargs) 541 542 query = u""" 543 SELECT data, list_label, field_label FROM ( 544 SELECT DISTINCT ON (data) * FROM (( 545 546 -- already-used org_units 547 SELECT 548 pk_org_unit 549 AS data, 550 ward || ' @ ' || hospital 551 AS list_label, 552 ward || ' @ ' || hospital 553 AS field_label, 554 1 555 AS rank 556 FROM 557 clin.v_hospital_stays 558 WHERE 559 ward %(fragment_condition)s 560 OR 561 hospital %(fragment_condition)s 562 563 ) UNION ALL ( 564 -- wards 565 SELECT 566 pk_org_unit 567 AS data, 568 unit || ' (' || l10n_unit_category || ') @ ' || organization 569 AS list_label, 570 unit || ' @ ' || organization 571 AS field_label, 572 2 573 AS rank 574 FROM 575 dem.v_org_units 576 WHERE 577 unit_category = 'Ward' 578 AND 579 unit %(fragment_condition)s 580 AND 581 NOT EXISTS ( 582 SELECT 1 FROM clin.v_hospital_stays WHERE clin.v_hospital_stays.pk_org_unit = dem.v_org_units.pk_org_unit 583 ) 584 585 ) UNION ALL ( 586 -- hospital units 587 SELECT 588 pk_org_unit 589 AS data, 590 unit || coalesce(' (' || l10n_unit_category || ')', '') || ' @ ' || organization || ' (' || l10n_organization_category || ')' 591 AS list_label, 592 unit || ' @ ' || organization 593 AS field_label, 594 3 595 AS rank 596 FROM 597 dem.v_org_units 598 WHERE 599 unit_category <> 'Ward' 600 AND 601 organization_category = 'Hospital' 602 AND 603 unit %(fragment_condition)s 604 AND 605 NOT EXISTS ( 606 SELECT 1 FROM clin.v_hospital_stays WHERE clin.v_hospital_stays.pk_org_unit = dem.v_org_units.pk_org_unit 607 ) 608 609 ) UNION ALL ( 610 -- any other units 611 SELECT 612 pk_org_unit 613 AS data, 614 unit || coalesce(' (' || l10n_unit_category || ')', '') || ' @ ' || organization || ' (' || l10n_organization_category || ')' 615 AS list_label, 616 unit || ' @ ' || organization 617 AS field_label, 618 3 619 AS rank 620 FROM 621 dem.v_org_units 622 WHERE 623 unit_category <> 'Ward' 624 AND 625 organization_category <> 'Hospital' 626 AND 627 unit %(fragment_condition)s 628 AND 629 NOT EXISTS ( 630 SELECT 1 FROM clin.v_hospital_stays WHERE clin.v_hospital_stays.pk_org_unit = dem.v_org_units.pk_org_unit 631 ) 632 )) AS all_matches 633 ORDER BY data, rank 634 ) AS distinct_matches 635 ORDER BY rank, list_label 636 LIMIT 50 637 """ 638 639 mp = gmMatchProvider.cMatchProvider_SQL2(queries = [query]) 640 mp.setThresholds(2, 4, 6) 641 self.matcher = mp 642 self.selection_only = True
643 644 #----------------------------------------------------------------
645 -class cHospitalStayPhraseWheel(gmPhraseWheel.cPhraseWheel):
646 """Phrasewheel to allow selection of a hospital-type org_unit."""
647 - def __init__(self, *args, **kwargs):
648 649 gmPhraseWheel.cPhraseWheel.__init__ (self, *args, **kwargs) 650 651 ctxt = {'ctxt_pat': {'where_part': u'pk_patient = %(pat)s and', 'placeholder': u'pat'}} 652 653 mp = gmMatchProvider.cMatchProvider_SQL2 ( 654 queries = [ 655 u""" 656 SELECT 657 pk_hospital_stay, 658 descr 659 FROM ( 660 SELECT DISTINCT ON (pk_hospital_stay) 661 pk_hospital_stay, 662 descr 663 FROM 664 (SELECT 665 pk_hospital_stay, 666 ( 667 to_char(admission, 'YYYY-Mon-DD') 668 || ' (' || ward || ' @ ' || hospital || '):' 669 || episode 670 || coalesce((' (' || health_issue || ')'), '') 671 ) AS descr 672 FROM 673 clin.v_hospital_stays 674 WHERE 675 %(ctxt_pat)s 676 677 hospital %(fragment_condition)s 678 OR 679 ward %(fragment_condition)s 680 OR 681 episode %(fragment_condition)s 682 OR 683 health_issue %(fragment_condition)s 684 ) AS the_stays 685 ) AS distinct_stays 686 ORDER BY descr 687 LIMIT 25 688 """ ], 689 context = ctxt 690 ) 691 mp.setThresholds(3, 4, 6) 692 mp.set_context('pat', gmPerson.gmCurrentPatient().ID) 693 694 self.matcher = mp 695 self.selection_only = True
696 697 #---------------------------------------------------------------- 698 from Gnumed.wxGladeWidgets import wxgHospitalStayEditAreaPnl 699
700 -class cHospitalStayEditAreaPnl(wxgHospitalStayEditAreaPnl.wxgHospitalStayEditAreaPnl, gmEditArea.cGenericEditAreaMixin):
701
702 - def __init__(self, *args, **kwargs):
705 #---------------------------------------------------------------- 706 # generic Edit Area mixin API 707 #----------------------------------------------------------------
708 - def _valid_for_save(self):
709 710 valid = True 711 712 if self._PRW_episode.GetValue().strip() == u'': 713 valid = False 714 self._PRW_episode.display_as_valid(False) 715 gmDispatcher.send(signal = 'statustext', msg = _('Must select an episode or enter a name for a new one. Cannot save hospitalization.'), beep = True) 716 self._PRW_episode.SetFocus() 717 718 if not self._PRW_admission.is_valid_timestamp(allow_empty = False): 719 valid = False 720 gmDispatcher.send(signal = 'statustext', msg = _('Missing admission data. Cannot save hospitalization.'), beep = True) 721 self._PRW_admission.SetFocus() 722 723 if self._PRW_discharge.is_valid_timestamp(allow_empty = True): 724 if self._PRW_discharge.date is not None: 725 adm = self._PRW_admission.date 726 discharge = self._PRW_discharge.date 727 # normalize for comparison 728 discharge = discharge.replace ( 729 hour = adm.hour, 730 minute = adm.minute, 731 second = adm.second, 732 microsecond = adm.microsecond 733 ) 734 if adm is not None: 735 if discharge == adm: 736 self._PRW_discharge.SetData(discharge + pydt.timedelta(seconds = 1)) 737 elif not self._PRW_discharge.date > self._PRW_admission.date: 738 valid = False 739 self._PRW_discharge.display_as_valid(False) 740 gmDispatcher.send(signal = 'statustext', msg = _('Discharge date must be empty or later than admission. Cannot save hospitalization.'), beep = True) 741 self._PRW_discharge.SetFocus() 742 743 if self._PRW_hospital.GetData() is None: 744 self._PRW_hospital.display_as_valid(False) 745 self.status_message = _('Must select a hospital. Cannot save hospitalization.') 746 self._PRW_hospital.SetFocus() 747 else: 748 self._PRW_hospital.display_as_valid(True) 749 750 return (valid is True)
751 #----------------------------------------------------------------
752 - def _save_as_new(self):
753 754 pat = gmPerson.gmCurrentPatient() 755 emr = pat.get_emr() 756 stay = emr.add_hospital_stay(episode = self._PRW_episode.GetData(can_create = True), fk_org_unit = self._PRW_hospital.GetData()) 757 stay['comment'] = self._TCTRL_comment.GetValue().strip() 758 stay['admission'] = self._PRW_admission.GetData() 759 stay['discharge'] = self._PRW_discharge.GetData() 760 stay['comment'] = self._TCTRL_comment.GetValue() 761 stay.save_payload() 762 763 self.data = stay 764 return True
765 #----------------------------------------------------------------
766 - def _save_as_update(self):
767 768 self.data['pk_episode'] = self._PRW_episode.GetData(can_create = True) 769 self.data['pk_org_unit'] = self._PRW_hospital.GetData() 770 self.data['admission'] = self._PRW_admission.GetData() 771 self.data['discharge'] = self._PRW_discharge.GetData() 772 self.data['comment'] = self._TCTRL_comment.GetValue() 773 self.data.save_payload() 774 775 return True
776 #----------------------------------------------------------------
777 - def _refresh_as_new(self):
778 self._PRW_hospital.SetText(value = u'', data = None) 779 self._PRW_episode.SetText(value = u'') 780 self._PRW_admission.SetText(data = gmDateTime.pydt_now_here()) 781 self._PRW_discharge.SetText() 782 self._TCTRL_comment.SetValue(u'') 783 self._PRW_hospital.SetFocus()
784 #----------------------------------------------------------------
785 - def _refresh_from_existing(self):
786 self._PRW_hospital.SetText(value = u'%s @ %s' % (self.data['ward'], self.data['hospital']), data = self.data['pk_org_unit']) 787 788 if self.data['pk_episode'] is not None: 789 self._PRW_episode.SetText(value = self.data['episode'], data = self.data['pk_episode']) 790 791 self._PRW_admission.SetText(data = self.data['admission']) 792 self._PRW_discharge.SetText(data = self.data['discharge']) 793 self._TCTRL_comment.SetValue(self.data['comment']) 794 795 self._PRW_hospital.SetFocus()
796 #----------------------------------------------------------------
798 print "this was not expected to be used in this edit area"
799 800 #================================================================ 801 # episode related widgets/functions 802 #----------------------------------------------------------------
803 -def edit_episode(parent=None, episode=None):
804 ea = cEpisodeEditAreaPnl(parent = parent, id = -1) 805 ea.data = episode 806 ea.mode = gmTools.coalesce(episode, 'new', 'edit') 807 dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = True) 808 dlg.SetTitle(gmTools.coalesce(episode, _('Adding a new episode'), _('Editing an episode'))) 809 if dlg.ShowModal() == wx.ID_OK: 810 return True 811 return False
812 #----------------------------------------------------------------
813 -def promote_episode_to_issue(parent=None, episode=None, emr=None):
814 815 created_new_issue = False 816 817 try: 818 issue = gmEMRStructItems.cHealthIssue(name = episode['description'], patient = episode['pk_patient']) 819 except gmExceptions.NoSuchBusinessObjectError: 820 issue = None 821 822 if issue is None: 823 issue = emr.add_health_issue(issue_name = episode['description']) 824 created_new_issue = True 825 else: 826 # issue exists already, so ask user 827 dlg = gmGuiHelpers.c3ButtonQuestionDlg ( 828 parent, 829 -1, 830 caption = _('Promoting episode to health issue'), 831 question = _( 832 'There already is a health issue\n' 833 '\n' 834 ' %s\n' 835 '\n' 836 'What do you want to do ?' 837 ) % issue['description'], 838 button_defs = [ 839 {'label': _('Use existing'), 'tooltip': _('Move episode into existing health issue'), 'default': False}, 840 {'label': _('Create new'), 'tooltip': _('Create a new health issue with another name'), 'default': True} 841 ] 842 ) 843 use_existing = dlg.ShowModal() 844 dlg.Destroy() 845 846 if use_existing == wx.ID_CANCEL: 847 return 848 849 # user wants to create new issue with alternate name 850 if use_existing == wx.ID_NO: 851 # loop until name modified but non-empty or cancelled 852 issue_name = episode['description'] 853 while issue_name == episode['description']: 854 dlg = wx.TextEntryDialog ( 855 parent = parent, 856 message = _('Enter a short descriptive name for the new health issue:'), 857 caption = _('Creating a new health issue ...'), 858 defaultValue = issue_name, 859 style = wx.OK | wx.CANCEL | wx.CENTRE 860 ) 861 decision = dlg.ShowModal() 862 if decision != wx.ID_OK: 863 dlg.Destroy() 864 return 865 issue_name = dlg.GetValue().strip() 866 dlg.Destroy() 867 if issue_name == u'': 868 issue_name = episode['description'] 869 870 issue = emr.add_health_issue(issue_name = issue_name) 871 created_new_issue = True 872 873 # eventually move the episode to the issue 874 if not move_episode_to_issue(episode = episode, target_issue = issue, save_to_backend = True): 875 # user cancelled the move so delete just-created issue 876 if created_new_issue: 877 # shouldn't fail as it is completely new 878 gmEMRStructItems.delete_health_issue(health_issue = issue) 879 return 880 881 return
882 #----------------------------------------------------------------
883 -def move_episode_to_issue(episode=None, target_issue=None, save_to_backend=False):
884 """Prepare changing health issue for an episode. 885 886 Checks for two-open-episodes conflict. When this 887 function succeeds, the pk_health_issue has been set 888 on the episode instance and the episode should - for 889 all practical purposes - be ready for save_payload(). 890 """ 891 # episode is closed: should always work 892 if not episode['episode_open']: 893 episode['pk_health_issue'] = target_issue['pk_health_issue'] 894 if save_to_backend: 895 episode.save_payload() 896 return True 897 898 # un-associate: should always work, too 899 if target_issue is None: 900 episode['pk_health_issue'] = None 901 if save_to_backend: 902 episode.save_payload() 903 return True 904 905 # try closing possibly expired episode on target issue if any 906 db_cfg = gmCfg.cCfgSQL() 907 epi_ttl = int(db_cfg.get2 ( 908 option = u'episode.ttl', 909 workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace, 910 bias = 'user', 911 default = 60 # 2 months 912 )) 913 if target_issue.close_expired_episode(ttl=epi_ttl) is True: 914 gmDispatcher.send(signal='statustext', msg=_('Closed episodes older than %s days on health issue [%s]') % (epi_ttl, target_issue['description'])) 915 existing_epi = target_issue.get_open_episode() 916 917 # no more open episode on target issue: should work now 918 if existing_epi is None: 919 episode['pk_health_issue'] = target_issue['pk_health_issue'] 920 if save_to_backend: 921 episode.save_payload() 922 return True 923 924 # don't conflict on SELF ;-) 925 if existing_epi['pk_episode'] == episode['pk_episode']: 926 episode['pk_health_issue'] = target_issue['pk_health_issue'] 927 if save_to_backend: 928 episode.save_payload() 929 return True 930 931 # we got two open episodes at once, ask user 932 move_range = episode.get_access_range() 933 exist_range = existing_epi.get_access_range() 934 question = _( 935 'You want to associate the running episode:\n\n' 936 ' "%(new_epi_name)s" (%(new_epi_start)s - %(new_epi_end)s)\n\n' 937 'with the health issue:\n\n' 938 ' "%(issue_name)s"\n\n' 939 'There already is another episode running\n' 940 'for this health issue:\n\n' 941 ' "%(old_epi_name)s" (%(old_epi_start)s - %(old_epi_end)s)\n\n' 942 'However, there can only be one running\n' 943 'episode per health issue.\n\n' 944 'Which episode do you want to close ?' 945 ) % { 946 'new_epi_name': episode['description'], 947 'new_epi_start': move_range[0].strftime('%m/%y'), 948 'new_epi_end': move_range[1].strftime('%m/%y'), 949 'issue_name': target_issue['description'], 950 'old_epi_name': existing_epi['description'], 951 'old_epi_start': exist_range[0].strftime('%m/%y'), 952 'old_epi_end': exist_range[1].strftime('%m/%y') 953 } 954 dlg = gmGuiHelpers.c3ButtonQuestionDlg ( 955 parent = None, 956 id = -1, 957 caption = _('Resolving two-running-episodes conflict'), 958 question = question, 959 button_defs = [ 960 {'label': _('old episode'), 'default': True, 'tooltip': _('close existing episode "%s"') % existing_epi['description']}, 961 {'label': _('new episode'), 'default': False, 'tooltip': _('close moving (new) episode "%s"') % episode['description']} 962 ] 963 ) 964 decision = dlg.ShowModal() 965 966 if decision == wx.ID_CANCEL: 967 # button 3: move cancelled by user 968 return False 969 970 elif decision == wx.ID_YES: 971 # button 1: close old episode 972 existing_epi['episode_open'] = False 973 existing_epi.save_payload() 974 975 elif decision == wx.ID_NO: 976 # button 2: close new episode 977 episode['episode_open'] = False 978 979 else: 980 raise ValueError('invalid result from c3ButtonQuestionDlg: [%s]' % decision) 981 982 episode['pk_health_issue'] = target_issue['pk_health_issue'] 983 if save_to_backend: 984 episode.save_payload() 985 return True
986 #----------------------------------------------------------------
987 -class cEpisodeListSelectorDlg(gmListWidgets.cGenericListSelectorDlg):
988 989 # FIXME: support pre-selection 990
991 - def __init__(self, *args, **kwargs):
992 993 episodes = kwargs['episodes'] 994 del kwargs['episodes'] 995 996 gmListWidgets.cGenericListSelectorDlg.__init__(self, *args, **kwargs) 997 998 self.SetTitle(_('Select the episodes you are interested in ...')) 999 self._LCTRL_items.set_columns([_('Episode'), _('Status'), _('Health Issue')]) 1000 self._LCTRL_items.set_string_items ( 1001 items = [ 1002 [ epi['description'], 1003 gmTools.bool2str(epi['episode_open'], _('ongoing'), u''), 1004 gmTools.coalesce(epi['health_issue'], u'') 1005 ] 1006 for epi in episodes ] 1007 ) 1008 self._LCTRL_items.set_column_widths() 1009 self._LCTRL_items.set_data(data = episodes)
1010 #----------------------------------------------------------------
1011 -class cEpisodeDescriptionPhraseWheel(gmPhraseWheel.cPhraseWheel):
1012 """Let user select an episode *description*. 1013 1014 The user can select an episode description from the previously 1015 used descriptions across all episodes across all patients. 1016 1017 Selection is done with a phrasewheel so the user can 1018 type the episode name and matches will be shown. Typing 1019 "*" will show the entire list of episodes. 1020 1021 If the user types a description not existing yet a 1022 new episode description will be returned. 1023 """
1024 - def __init__(self, *args, **kwargs):
1025 1026 mp = gmMatchProvider.cMatchProvider_SQL2 ( 1027 queries = [ 1028 u""" 1029 SELECT DISTINCT ON (description) 1030 description 1031 AS data, 1032 description 1033 AS field_label, 1034 description || ' (' 1035 || CASE 1036 WHEN is_open IS TRUE THEN _('ongoing') 1037 ELSE _('closed') 1038 END 1039 || ')' 1040 AS list_label 1041 FROM 1042 clin.episode 1043 WHERE 1044 description %(fragment_condition)s 1045 ORDER BY description 1046 LIMIT 30 1047 """ 1048 ] 1049 ) 1050 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 1051 self.matcher = mp
1052 #----------------------------------------------------------------
1053 -class cEpisodeSelectionPhraseWheel(gmPhraseWheel.cPhraseWheel):
1054 """Let user select an episode. 1055 1056 The user can select an episode from the existing episodes of a 1057 patient. Selection is done with a phrasewheel so the user 1058 can type the episode name and matches will be shown. Typing 1059 "*" will show the entire list of episodes. Closed episodes 1060 will be marked as such. If the user types an episode name not 1061 in the list of existing episodes a new episode can be created 1062 from it if the programmer activated that feature. 1063 1064 If keyword <patient_id> is set to None or left out the control 1065 will listen to patient change signals and therefore act on 1066 gmPerson.gmCurrentPatient() changes. 1067 """
1068 - def __init__(self, *args, **kwargs):
1069 1070 ctxt = {'ctxt_pat': {'where_part': u'and pk_patient = %(pat)s', 'placeholder': u'pat'}} 1071 1072 mp = gmMatchProvider.cMatchProvider_SQL2 ( 1073 queries = [ 1074 u"""( 1075 1076 SELECT 1077 pk_episode 1078 as data, 1079 description 1080 as field_label, 1081 coalesce ( 1082 description || ' - ' || health_issue, 1083 description 1084 ) as list_label, 1085 1 as rank 1086 from 1087 clin.v_pat_episodes 1088 where 1089 episode_open is true and 1090 description %(fragment_condition)s 1091 %(ctxt_pat)s 1092 1093 ) union all ( 1094 1095 SELECT 1096 pk_episode 1097 as data, 1098 description 1099 as field_label, 1100 coalesce ( 1101 description || _(' (closed)') || ' - ' || health_issue, 1102 description || _(' (closed)') 1103 ) as list_label, 1104 2 as rank 1105 from 1106 clin.v_pat_episodes 1107 where 1108 description %(fragment_condition)s and 1109 episode_open is false 1110 %(ctxt_pat)s 1111 1112 ) 1113 1114 order by rank, list_label 1115 limit 30""" 1116 ], 1117 context = ctxt 1118 ) 1119 1120 try: 1121 kwargs['patient_id'] 1122 except KeyError: 1123 kwargs['patient_id'] = None 1124 1125 if kwargs['patient_id'] is None: 1126 self.use_current_patient = True 1127 self.__register_patient_change_signals() 1128 pat = gmPerson.gmCurrentPatient() 1129 if pat.connected: 1130 mp.set_context('pat', pat.ID) 1131 else: 1132 self.use_current_patient = False 1133 self.__patient_id = int(kwargs['patient_id']) 1134 mp.set_context('pat', self.__patient_id) 1135 1136 del kwargs['patient_id'] 1137 1138 gmPhraseWheel.cPhraseWheel.__init__ ( 1139 self, 1140 *args, 1141 **kwargs 1142 ) 1143 self.matcher = mp
1144 #-------------------------------------------------------- 1145 # external API 1146 #--------------------------------------------------------
1147 - def set_patient(self, patient_id=None):
1148 if self.use_current_patient: 1149 return False 1150 self.__patient_id = int(patient_id) 1151 self.set_context('pat', self.__patient_id) 1152 return True
1153 #--------------------------------------------------------
1154 - def GetData(self, can_create=False, as_instance=False, is_open=False):
1155 self.__is_open_for_create_data = is_open # used (only) in _create_data() 1156 return gmPhraseWheel.cPhraseWheel.GetData(self, can_create = can_create, as_instance = as_instance)
1157 #--------------------------------------------------------
1158 - def _create_data(self):
1159 1160 epi_name = self.GetValue().strip() 1161 if epi_name == u'': 1162 gmDispatcher.send(signal = u'statustext', msg = _('Cannot create episode without name.'), beep = True) 1163 _log.debug('cannot create episode without name') 1164 return 1165 1166 if self.use_current_patient: 1167 pat = gmPerson.gmCurrentPatient() 1168 else: 1169 pat = gmPerson.cPatient(aPK_obj = self.__patient_id) 1170 1171 emr = pat.get_emr() 1172 epi = emr.add_episode(episode_name = epi_name, is_open = self.__is_open_for_create_data) 1173 if epi is None: 1174 self.data = {} 1175 else: 1176 self.SetText ( 1177 value = epi_name, 1178 data = epi['pk_episode'] 1179 )
1180 #--------------------------------------------------------
1181 - def _data2instance(self):
1182 return gmEMRStructItems.cEpisode(aPK_obj = self.GetData())
1183 #-------------------------------------------------------- 1184 # internal API 1185 #--------------------------------------------------------
1187 gmDispatcher.connect(self._pre_patient_selection, u'pre_patient_selection') 1188 gmDispatcher.connect(self._post_patient_selection, u'post_patient_selection')
1189 #--------------------------------------------------------
1190 - def _pre_patient_selection(self):
1191 return True
1192 #--------------------------------------------------------
1193 - def _post_patient_selection(self):
1194 if self.use_current_patient: 1195 patient = gmPerson.gmCurrentPatient() 1196 self.set_context('pat', patient.ID) 1197 return True
1198 #---------------------------------------------------------------- 1199 from Gnumed.wxGladeWidgets import wxgEpisodeEditAreaPnl 1200
1201 -class cEpisodeEditAreaPnl(gmEditArea.cGenericEditAreaMixin, wxgEpisodeEditAreaPnl.wxgEpisodeEditAreaPnl):
1202
1203 - def __init__(self, *args, **kwargs):
1204 1205 try: 1206 episode = kwargs['episode'] 1207 del kwargs['episode'] 1208 except KeyError: 1209 episode = None 1210 1211 wxgEpisodeEditAreaPnl.wxgEpisodeEditAreaPnl.__init__(self, *args, **kwargs) 1212 gmEditArea.cGenericEditAreaMixin.__init__(self) 1213 1214 self.data = episode
1215 #---------------------------------------------------------------- 1216 # generic Edit Area mixin API 1217 #----------------------------------------------------------------
1218 - def _valid_for_save(self):
1219 1220 errors = False 1221 1222 if len(self._PRW_description.GetValue().strip()) == 0: 1223 errors = True 1224 self._PRW_description.display_as_valid(False) 1225 self._PRW_description.SetFocus() 1226 else: 1227 self._PRW_description.display_as_valid(True) 1228 self._PRW_description.Refresh() 1229 1230 return not errors
1231 #----------------------------------------------------------------
1232 - def _save_as_new(self):
1233 1234 pat = gmPerson.gmCurrentPatient() 1235 emr = pat.get_emr() 1236 1237 epi = emr.add_episode(episode_name = self._PRW_description.GetValue().strip()) 1238 epi['summary'] = self._TCTRL_status.GetValue().strip() 1239 epi['episode_open'] = not self._CHBOX_closed.IsChecked() 1240 epi['diagnostic_certainty_classification'] = self._PRW_certainty.GetData() 1241 1242 issue_name = self._PRW_issue.GetValue().strip() 1243 if len(issue_name) != 0: 1244 epi['pk_health_issue'] = self._PRW_issue.GetData(can_create = True) 1245 issue = gmEMRStructItems.cHealthIssue(aPK_obj = epi['pk_health_issue']) 1246 1247 if not move_episode_to_issue(episode = epi, target_issue = issue, save_to_backend = False): 1248 gmDispatcher.send ( 1249 signal = 'statustext', 1250 msg = _('Cannot attach episode [%s] to health issue [%s] because it already has a running episode.') % ( 1251 epi['description'], 1252 issue['description'] 1253 ) 1254 ) 1255 gmEMRStructItems.delete_episode(episode = epi) 1256 return False 1257 1258 epi.save() 1259 1260 epi.generic_codes = [ c['data'] for c in self._PRW_codes.GetData() ] 1261 1262 self.data = epi 1263 return True
1264 #----------------------------------------------------------------
1265 - def _save_as_update(self):
1266 1267 self.data['description'] = self._PRW_description.GetValue().strip() 1268 self.data['summary'] = self._TCTRL_status.GetValue().strip() 1269 self.data['episode_open'] = not self._CHBOX_closed.IsChecked() 1270 self.data['diagnostic_certainty_classification'] = self._PRW_certainty.GetData() 1271 1272 issue_name = self._PRW_issue.GetValue().strip() 1273 if len(issue_name) == 0: 1274 self.data['pk_health_issue'] = None 1275 else: 1276 self.data['pk_health_issue'] = self._PRW_issue.GetData(can_create = True) 1277 issue = gmEMRStructItems.cHealthIssue(aPK_obj = self.data['pk_health_issue']) 1278 1279 if not move_episode_to_issue(episode = self.data, target_issue = issue, save_to_backend = False): 1280 gmDispatcher.send ( 1281 signal = 'statustext', 1282 msg = _('Cannot attach episode [%s] to health issue [%s] because it already has a running episode.') % ( 1283 self.data['description'], 1284 issue['description'] 1285 ) 1286 ) 1287 return False 1288 1289 self.data.save() 1290 self.data.generic_codes = [ c['data'] for c in self._PRW_codes.GetData() ] 1291 1292 return True
1293 #----------------------------------------------------------------
1294 - def _refresh_as_new(self):
1295 if self.data is None: 1296 ident = gmPerson.gmCurrentPatient() 1297 else: 1298 ident = gmPerson.cIdentity(aPK_obj = self.data['pk_patient']) 1299 self._TCTRL_patient.SetValue(ident.get_description_gender()) 1300 self._PRW_issue.SetText() 1301 self._PRW_description.SetText() 1302 self._TCTRL_status.SetValue(u'') 1303 self._PRW_certainty.SetText() 1304 self._CHBOX_closed.SetValue(False) 1305 self._PRW_codes.SetText()
1306 #----------------------------------------------------------------
1307 - def _refresh_from_existing(self):
1308 ident = gmPerson.cIdentity(aPK_obj = self.data['pk_patient']) 1309 self._TCTRL_patient.SetValue(ident.get_description_gender()) 1310 1311 if self.data['pk_health_issue'] is not None: 1312 self._PRW_issue.SetText(self.data['health_issue'], data=self.data['pk_health_issue']) 1313 1314 self._PRW_description.SetText(self.data['description'], data=self.data['description']) 1315 1316 self._TCTRL_status.SetValue(gmTools.coalesce(self.data['summary'], u'')) 1317 1318 if self.data['diagnostic_certainty_classification'] is not None: 1319 self._PRW_certainty.SetData(data = self.data['diagnostic_certainty_classification']) 1320 1321 self._CHBOX_closed.SetValue(not self.data['episode_open']) 1322 1323 val, data = self._PRW_codes.generic_linked_codes2item_dict(self.data.generic_codes) 1324 self._PRW_codes.SetText(val, data)
1325 #----------------------------------------------------------------
1327 self._refresh_as_new()
1328 #================================================================ 1329 # health issue related widgets/functions 1330 #----------------------------------------------------------------
1331 -def edit_health_issue(parent=None, issue=None):
1332 ea = cHealthIssueEditAreaPnl(parent = parent, id = -1) 1333 ea.data = issue 1334 ea.mode = gmTools.coalesce(issue, 'new', 'edit') 1335 dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = (issue is not None)) 1336 dlg.SetTitle(gmTools.coalesce(issue, _('Adding a new health issue'), _('Editing a health issue'))) 1337 if dlg.ShowModal() == wx.ID_OK: 1338 dlg.Destroy() 1339 return True 1340 dlg.Destroy() 1341 return False
1342 #----------------------------------------------------------------
1343 -def select_health_issues(parent=None, emr=None):
1344 1345 if parent is None: 1346 parent = wx.GetApp().GetTopWindow() 1347 #----------------------------------------- 1348 def refresh(lctrl): 1349 issues = emr.get_health_issues() 1350 items = [ 1351 [ 1352 gmTools.bool2subst(i['is_confidential'], _('CONFIDENTIAL'), u'', u''), 1353 i['description'], 1354 gmTools.bool2subst(i['clinically_relevant'], _('relevant'), u'', u''), 1355 gmTools.bool2subst(i['is_active'], _('active'), u'', u''), 1356 gmTools.bool2subst(i['is_cause_of_death'], _('fatal'), u'', u'') 1357 ] for i in issues 1358 ] 1359 lctrl.set_string_items(items = items) 1360 lctrl.set_data(data = issues)
1361 #----------------------------------------- 1362 return gmListWidgets.get_choices_from_list ( 1363 parent = parent, 1364 msg = _('\nSelect the health issues !\n'), 1365 caption = _('Showing health issues ...'), 1366 columns = [u'', _('Health issue'), u'', u'', u''], 1367 single_selection = False, 1368 #edit_callback = edit, 1369 #new_callback = edit, 1370 #delete_callback = delete, 1371 refresh_callback = refresh 1372 ) 1373 #----------------------------------------------------------------
1374 -class cIssueListSelectorDlg(gmListWidgets.cGenericListSelectorDlg):
1375 1376 # FIXME: support pre-selection 1377
1378 - def __init__(self, *args, **kwargs):
1379 1380 issues = kwargs['issues'] 1381 del kwargs['issues'] 1382 1383 gmListWidgets.cGenericListSelectorDlg.__init__(self, *args, **kwargs) 1384 1385 self.SetTitle(_('Select the health issues you are interested in ...')) 1386 self._LCTRL_items.set_columns([u'', _('Health Issue'), u'', u'', u'']) 1387 1388 for issue in issues: 1389 if issue['is_confidential']: 1390 row_num = self._LCTRL_items.InsertStringItem(sys.maxint, label = _('confidential')) 1391 self._LCTRL_items.SetItemTextColour(row_num, col=wx.NamedColour('RED')) 1392 else: 1393 row_num = self._LCTRL_items.InsertStringItem(sys.maxint, label = u'') 1394 1395 self._LCTRL_items.SetStringItem(index = row_num, col = 1, label = issue['description']) 1396 if issue['clinically_relevant']: 1397 self._LCTRL_items.SetStringItem(index = row_num, col = 2, label = _('relevant')) 1398 if issue['is_active']: 1399 self._LCTRL_items.SetStringItem(index = row_num, col = 3, label = _('active')) 1400 if issue['is_cause_of_death']: 1401 self._LCTRL_items.SetStringItem(index = row_num, col = 4, label = _('fatal')) 1402 1403 self._LCTRL_items.set_column_widths() 1404 self._LCTRL_items.set_data(data = issues)
1405 #----------------------------------------------------------------
1406 -class cIssueSelectionPhraseWheel(gmPhraseWheel.cPhraseWheel):
1407 """Let the user select a health issue. 1408 1409 The user can select a health issue from the existing issues 1410 of a patient. Selection is done with a phrasewheel so the user 1411 can type the issue name and matches will be shown. Typing 1412 "*" will show the entire list of issues. Inactive issues 1413 will be marked as such. If the user types an issue name not 1414 in the list of existing issues a new issue can be created 1415 from it if the programmer activated that feature. 1416 1417 If keyword <patient_id> is set to None or left out the control 1418 will listen to patient change signals and therefore act on 1419 gmPerson.gmCurrentPatient() changes. 1420 """
1421 - def __init__(self, *args, **kwargs):
1422 1423 ctxt = {'ctxt_pat': {'where_part': u'pk_patient=%(pat)s', 'placeholder': u'pat'}} 1424 1425 mp = gmMatchProvider.cMatchProvider_SQL2 ( 1426 # FIXME: consider clin.health_issue.clinically_relevant 1427 queries = [ 1428 u""" 1429 SELECT 1430 data, 1431 field_label, 1432 list_label 1433 FROM (( 1434 SELECT 1435 pk_health_issue AS data, 1436 description AS field_label, 1437 description AS list_label 1438 FROM clin.v_health_issues 1439 WHERE 1440 is_active IS true 1441 AND 1442 description %(fragment_condition)s 1443 AND 1444 %(ctxt_pat)s 1445 1446 ) UNION ( 1447 1448 SELECT 1449 pk_health_issue AS data, 1450 description AS field_label, 1451 description || _(' (inactive)') AS list_label 1452 FROM clin.v_health_issues 1453 WHERE 1454 is_active IS false 1455 AND 1456 description %(fragment_condition)s 1457 AND 1458 %(ctxt_pat)s 1459 )) AS union_query 1460 ORDER BY 1461 list_label"""], 1462 context = ctxt 1463 ) 1464 1465 try: kwargs['patient_id'] 1466 except KeyError: kwargs['patient_id'] = None 1467 1468 if kwargs['patient_id'] is None: 1469 self.use_current_patient = True 1470 self.__register_patient_change_signals() 1471 pat = gmPerson.gmCurrentPatient() 1472 if pat.connected: 1473 mp.set_context('pat', pat.ID) 1474 else: 1475 self.use_current_patient = False 1476 self.__patient_id = int(kwargs['patient_id']) 1477 mp.set_context('pat', self.__patient_id) 1478 1479 del kwargs['patient_id'] 1480 1481 gmPhraseWheel.cPhraseWheel.__init__ ( 1482 self, 1483 *args, 1484 **kwargs 1485 ) 1486 self.matcher = mp
1487 #-------------------------------------------------------- 1488 # external API 1489 #--------------------------------------------------------
1490 - def set_patient(self, patient_id=None):
1491 if self.use_current_patient: 1492 return False 1493 self.__patient_id = int(patient_id) 1494 self.set_context('pat', self.__patient_id) 1495 return True
1496 #--------------------------------------------------------
1497 - def _create_data(self):
1498 issue_name = self.GetValue().strip() 1499 if issue_name == u'': 1500 gmDispatcher.send(signal = u'statustext', msg = _('Cannot create health issue without name.'), beep = True) 1501 _log.debug('cannot create health issue without name') 1502 return 1503 1504 if self.use_current_patient: 1505 pat = gmPerson.gmCurrentPatient() 1506 else: 1507 pat = gmPerson.cPatient(aPK_obj = self.__patient_id) 1508 1509 emr = pat.get_emr() 1510 issue = emr.add_health_issue(issue_name = issue_name) 1511 1512 if issue is None: 1513 self.data = {} 1514 else: 1515 self.SetText ( 1516 value = issue_name, 1517 data = issue['pk_health_issue'] 1518 )
1519 #--------------------------------------------------------
1520 - def _data2instance(self):
1521 return gmEMRStructItems.cHealthIssue(aPK_obj = self.GetData())
1522 #-------------------------------------------------------- 1523 # internal API 1524 #--------------------------------------------------------
1526 gmDispatcher.connect(self._pre_patient_selection, u'pre_patient_selection') 1527 gmDispatcher.connect(self._post_patient_selection, u'post_patient_selection')
1528 #--------------------------------------------------------
1529 - def _pre_patient_selection(self):
1530 return True
1531 #--------------------------------------------------------
1532 - def _post_patient_selection(self):
1533 if self.use_current_patient: 1534 patient = gmPerson.gmCurrentPatient() 1535 self.set_context('pat', patient.ID) 1536 return True
1537 #------------------------------------------------------------ 1538 from Gnumed.wxGladeWidgets import wxgIssueSelectionDlg 1539
1540 -class cIssueSelectionDlg(wxgIssueSelectionDlg.wxgIssueSelectionDlg):
1541
1542 - def __init__(self, *args, **kwargs):
1543 try: 1544 msg = kwargs['message'] 1545 except KeyError: 1546 msg = None 1547 del kwargs['message'] 1548 wxgIssueSelectionDlg.wxgIssueSelectionDlg.__init__(self, *args, **kwargs) 1549 if msg is not None: 1550 self._lbl_message.SetLabel(label=msg)
1551 #--------------------------------------------------------
1552 - def _on_OK_button_pressed(self, event):
1553 event.Skip() 1554 pk_issue = self._PhWheel_issue.GetData(can_create=True) 1555 if pk_issue is None: 1556 gmGuiHelpers.gm_show_error ( 1557 _('Cannot create new health issue:\n [%(issue)s]') % {'issue': self._PhWheel_issue.GetValue().strip()}, 1558 _('Selecting health issue') 1559 ) 1560 return False 1561 return True
1562 #------------------------------------------------------------ 1563 from Gnumed.wxGladeWidgets import wxgHealthIssueEditAreaPnl 1564
1565 -class cHealthIssueEditAreaPnl(gmEditArea.cGenericEditAreaMixin, wxgHealthIssueEditAreaPnl.wxgHealthIssueEditAreaPnl):
1566 """Panel encapsulating health issue edit area functionality.""" 1567
1568 - def __init__(self, *args, **kwargs):
1569 1570 try: 1571 data = kwargs['issue'] 1572 del kwargs['issue'] 1573 except KeyError: 1574 data = None 1575 1576 wxgHealthIssueEditAreaPnl.wxgHealthIssueEditAreaPnl.__init__(self, *args, **kwargs) 1577 gmEditArea.cGenericEditAreaMixin.__init__(self) 1578 1579 self.mode = 'new' 1580 self.data = data 1581 if data is not None: 1582 self.mode = 'edit' 1583 1584 self.__init_ui()
1585 #----------------------------------------------------------------
1586 - def __init_ui(self):
1587 1588 # FIXME: include more sources: coding systems/other database columns 1589 mp = gmMatchProvider.cMatchProvider_SQL2 ( 1590 queries = [u"SELECT DISTINCT ON (description) description, description FROM clin.health_issue WHERE description %(fragment_condition)s LIMIT 50"] 1591 ) 1592 mp.setThresholds(1, 3, 5) 1593 self._PRW_condition.matcher = mp 1594 1595 mp = gmMatchProvider.cMatchProvider_SQL2 ( 1596 queries = [u""" 1597 SELECT DISTINCT ON (grouping) grouping, grouping from ( 1598 1599 SELECT rank, grouping from (( 1600 1601 SELECT 1602 grouping, 1603 1 as rank 1604 from 1605 clin.health_issue 1606 where 1607 grouping %%(fragment_condition)s 1608 and 1609 (SELECT True from clin.encounter where fk_patient = %s and pk = clin.health_issue.fk_encounter) 1610 1611 ) union ( 1612 1613 SELECT 1614 grouping, 1615 2 as rank 1616 from 1617 clin.health_issue 1618 where 1619 grouping %%(fragment_condition)s 1620 1621 )) as union_result 1622 1623 order by rank 1624 1625 ) as order_result 1626 1627 limit 50""" % gmPerson.gmCurrentPatient().ID 1628 ] 1629 ) 1630 mp.setThresholds(1, 3, 5) 1631 self._PRW_grouping.matcher = mp 1632 1633 self._PRW_age_noted.add_callback_on_lose_focus(self._on_leave_age_noted) 1634 self._PRW_year_noted.add_callback_on_lose_focus(self._on_leave_year_noted) 1635 1636 # self._PRW_age_noted.add_callback_on_modified(self._on_modified_age_noted) 1637 # self._PRW_year_noted.add_callback_on_modified(self._on_modified_year_noted) 1638 1639 self._PRW_year_noted.Enable(True) 1640 1641 self._PRW_codes.add_callback_on_lose_focus(self._on_leave_codes)
1642 1643 #---------------------------------------------------------------- 1644 # generic Edit Area mixin API 1645 #----------------------------------------------------------------
1646 - def _valid_for_save(self):
1647 1648 if self._PRW_condition.GetValue().strip() == '': 1649 self._PRW_condition.display_as_valid(False) 1650 self._PRW_condition.SetFocus() 1651 return False 1652 self._PRW_condition.display_as_valid(True) 1653 self._PRW_condition.Refresh() 1654 1655 # FIXME: sanity check age/year diagnosed 1656 age_noted = self._PRW_age_noted.GetValue().strip() 1657 if age_noted != u'': 1658 if gmDateTime.str2interval(str_interval = age_noted) is None: 1659 self._PRW_age_noted.display_as_valid(False) 1660 self._PRW_age_noted.SetFocus() 1661 return False 1662 self._PRW_age_noted.display_as_valid(True) 1663 return True
1664 #----------------------------------------------------------------
1665 - def _save_as_new(self):
1666 pat = gmPerson.gmCurrentPatient() 1667 emr = pat.get_emr() 1668 1669 issue = emr.add_health_issue(issue_name = self._PRW_condition.GetValue().strip()) 1670 1671 side = u'' 1672 if self._ChBOX_left.GetValue(): 1673 side += u's' 1674 if self._ChBOX_right.GetValue(): 1675 side += u'd' 1676 issue['laterality'] = side 1677 1678 issue['summary'] = self._TCTRL_status.GetValue().strip() 1679 issue['diagnostic_certainty_classification'] = self._PRW_certainty.GetData() 1680 issue['grouping'] = self._PRW_grouping.GetValue().strip() 1681 issue['is_active'] = self._ChBOX_active.GetValue() 1682 issue['clinically_relevant'] = self._ChBOX_relevant.GetValue() 1683 issue['is_confidential'] = self._ChBOX_confidential.GetValue() 1684 issue['is_cause_of_death'] = self._ChBOX_caused_death.GetValue() 1685 1686 age_noted = self._PRW_age_noted.GetData() 1687 if age_noted is not None: 1688 issue['age_noted'] = age_noted 1689 1690 issue.save() 1691 1692 issue.generic_codes = [ c['data'] for c in self._PRW_codes.GetData() ] 1693 1694 self.data = issue 1695 return True
1696 #----------------------------------------------------------------
1697 - def _save_as_update(self):
1698 1699 self.data['description'] = self._PRW_condition.GetValue().strip() 1700 1701 side = u'' 1702 if self._ChBOX_left.GetValue(): 1703 side += u's' 1704 if self._ChBOX_right.GetValue(): 1705 side += u'd' 1706 self.data['laterality'] = side 1707 1708 self.data['summary'] = self._TCTRL_status.GetValue().strip() 1709 self.data['diagnostic_certainty_classification'] = self._PRW_certainty.GetData() 1710 self.data['grouping'] = self._PRW_grouping.GetValue().strip() 1711 self.data['is_active'] = bool(self._ChBOX_active.GetValue()) 1712 self.data['clinically_relevant'] = bool(self._ChBOX_relevant.GetValue()) 1713 self.data['is_confidential'] = bool(self._ChBOX_confidential.GetValue()) 1714 self.data['is_cause_of_death'] = bool(self._ChBOX_caused_death.GetValue()) 1715 1716 age_noted = self._PRW_age_noted.GetData() 1717 if age_noted is not None: 1718 self.data['age_noted'] = age_noted 1719 1720 self.data.save() 1721 self.data.generic_codes = [ c['data'] for c in self._PRW_codes.GetData() ] 1722 1723 return True
1724 #----------------------------------------------------------------
1725 - def _refresh_as_new(self):
1726 self._PRW_condition.SetText() 1727 self._ChBOX_left.SetValue(0) 1728 self._ChBOX_right.SetValue(0) 1729 self._PRW_codes.SetText() 1730 self._on_leave_codes() 1731 self._PRW_certainty.SetText() 1732 self._PRW_grouping.SetText() 1733 self._TCTRL_status.SetValue(u'') 1734 self._PRW_age_noted.SetText() 1735 self._PRW_year_noted.SetText() 1736 self._ChBOX_active.SetValue(1) 1737 self._ChBOX_relevant.SetValue(1) 1738 self._ChBOX_confidential.SetValue(0) 1739 self._ChBOX_caused_death.SetValue(0) 1740 1741 self._PRW_condition.SetFocus() 1742 return True
1743 #----------------------------------------------------------------
1744 - def _refresh_from_existing(self):
1745 self._PRW_condition.SetText(self.data['description']) 1746 1747 lat = gmTools.coalesce(self.data['laterality'], '') 1748 if lat.find('s') == -1: 1749 self._ChBOX_left.SetValue(0) 1750 else: 1751 self._ChBOX_left.SetValue(1) 1752 if lat.find('d') == -1: 1753 self._ChBOX_right.SetValue(0) 1754 else: 1755 self._ChBOX_right.SetValue(1) 1756 1757 val, data = self._PRW_codes.generic_linked_codes2item_dict(self.data.generic_codes) 1758 self._PRW_codes.SetText(val, data) 1759 self._on_leave_codes() 1760 1761 if self.data['diagnostic_certainty_classification'] is not None: 1762 self._PRW_certainty.SetData(data = self.data['diagnostic_certainty_classification']) 1763 self._PRW_grouping.SetText(gmTools.coalesce(self.data['grouping'], u'')) 1764 self._TCTRL_status.SetValue(gmTools.coalesce(self.data['summary'], u'')) 1765 1766 if self.data['age_noted'] is None: 1767 self._PRW_age_noted.SetText() 1768 else: 1769 self._PRW_age_noted.SetText ( 1770 value = '%sd' % self.data['age_noted'].days, 1771 data = self.data['age_noted'] 1772 ) 1773 1774 self._ChBOX_active.SetValue(self.data['is_active']) 1775 self._ChBOX_relevant.SetValue(self.data['clinically_relevant']) 1776 self._ChBOX_confidential.SetValue(self.data['is_confidential']) 1777 self._ChBOX_caused_death.SetValue(self.data['is_cause_of_death']) 1778 1779 self._TCTRL_status.SetFocus() 1780 1781 return True
1782 #----------------------------------------------------------------
1784 return self._refresh_as_new()
1785 #-------------------------------------------------------- 1786 # internal helpers 1787 #--------------------------------------------------------
1788 - def _on_leave_codes(self, *args, **kwargs):
1789 if not self._PRW_codes.IsModified(): 1790 return True 1791 1792 self._TCTRL_code_details.SetValue(u'- ' + u'\n- '.join([ c['list_label'] for c in self._PRW_codes.GetData() ]))
1793 #--------------------------------------------------------
1794 - def _on_leave_age_noted(self, *args, **kwargs):
1795 1796 if not self._PRW_age_noted.IsModified(): 1797 return True 1798 1799 age_str = self._PRW_age_noted.GetValue().strip() 1800 1801 if age_str == u'': 1802 return True 1803 1804 issue_age = gmDateTime.str2interval(str_interval = age_str) 1805 1806 if issue_age is None: 1807 self.status_message = _('Cannot parse [%s] into valid interval.') % age_str 1808 self._PRW_age_noted.display_as_valid(False) 1809 return True 1810 1811 pat = gmPerson.gmCurrentPatient() 1812 if pat['dob'] is not None: 1813 max_issue_age = pydt.datetime.now(tz=pat['dob'].tzinfo) - pat['dob'] 1814 if issue_age >= max_issue_age: 1815 self.status_message = _('Health issue cannot have been noted at age %s. Patient is only %s old.') % (issue_age, pat.get_medical_age()) 1816 self._PRW_age_noted.display_as_valid(False) 1817 return True 1818 1819 self._PRW_age_noted.display_as_valid(True) 1820 self._PRW_age_noted.SetText(value = age_str, data = issue_age) 1821 1822 if pat['dob'] is not None: 1823 fts = gmDateTime.cFuzzyTimestamp ( 1824 timestamp = pat['dob'] + issue_age, 1825 accuracy = gmDateTime.acc_months 1826 ) 1827 self._PRW_year_noted.SetText(value = str(fts), data = fts) 1828 1829 return True
1830 #--------------------------------------------------------
1831 - def _on_leave_year_noted(self, *args, **kwargs):
1832 1833 if not self._PRW_year_noted.IsModified(): 1834 return True 1835 1836 year_noted = self._PRW_year_noted.GetData() 1837 1838 if year_noted is None: 1839 if self._PRW_year_noted.GetValue().strip() == u'': 1840 self._PRW_year_noted.display_as_valid(True) 1841 return True 1842 self._PRW_year_noted.display_as_valid(False) 1843 return True 1844 1845 year_noted = year_noted.get_pydt() 1846 1847 if year_noted >= pydt.datetime.now(tz = year_noted.tzinfo): 1848 self.status_message = _('Condition diagnosed in the future.') 1849 self._PRW_year_noted.display_as_valid(False) 1850 return True 1851 1852 self._PRW_year_noted.display_as_valid(True) 1853 1854 pat = gmPerson.gmCurrentPatient() 1855 if pat['dob'] is not None: 1856 issue_age = year_noted - pat['dob'] 1857 age_str = gmDateTime.format_interval_medically(interval = issue_age) 1858 self._PRW_age_noted.SetText(age_str, issue_age, True) 1859 1860 return True
1861 #--------------------------------------------------------
1862 - def _on_modified_age_noted(self, *args, **kwargs):
1863 wx.CallAfter(self._PRW_year_noted.SetText, u'', None, True) 1864 return True
1865 #--------------------------------------------------------
1866 - def _on_modified_year_noted(self, *args, **kwargs):
1867 wx.CallAfter(self._PRW_age_noted.SetText, u'', None, True) 1868 return True
1869 #================================================================ 1870 # diagnostic certainty related widgets/functions 1871 #----------------------------------------------------------------
1872 -class cDiagnosticCertaintyClassificationPhraseWheel(gmPhraseWheel.cPhraseWheel):
1873
1874 - def __init__(self, *args, **kwargs):
1875 1876 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 1877 1878 self.selection_only = False # can be NULL, too 1879 1880 mp = gmMatchProvider.cMatchProvider_FixedList ( 1881 aSeq = [ 1882 {'data': u'A', 'list_label': gmEMRStructItems.diagnostic_certainty_classification2str(u'A'), 'field_label': gmEMRStructItems.diagnostic_certainty_classification2str(u'A'), 'weight': 1}, 1883 {'data': u'B', 'list_label': gmEMRStructItems.diagnostic_certainty_classification2str(u'B'), 'field_label': gmEMRStructItems.diagnostic_certainty_classification2str(u'B'), 'weight': 1}, 1884 {'data': u'C', 'list_label': gmEMRStructItems.diagnostic_certainty_classification2str(u'C'), 'field_label': gmEMRStructItems.diagnostic_certainty_classification2str(u'C'), 'weight': 1}, 1885 {'data': u'D', 'list_label': gmEMRStructItems.diagnostic_certainty_classification2str(u'D'), 'field_label': gmEMRStructItems.diagnostic_certainty_classification2str(u'D'), 'weight': 1} 1886 ] 1887 ) 1888 mp.setThresholds(1, 2, 4) 1889 self.matcher = mp 1890 1891 self.SetToolTipString(_( 1892 "The diagnostic classification or grading of this assessment.\n" 1893 "\n" 1894 "This documents how certain one is about this being a true diagnosis." 1895 ))
1896 1897 #================================================================ 1898 # MAIN 1899 #---------------------------------------------------------------- 1900 if __name__ == '__main__': 1901 1902 from Gnumed.business import gmPersonSearch 1903 from Gnumed.wxpython import gmPatSearchWidgets 1904 1905 #================================================================
1906 - class testapp (wx.App):
1907 """ 1908 Test application for testing EMR struct widgets 1909 """ 1910 #--------------------------------------------------------
1911 - def OnInit (self):
1912 """ 1913 Create test application UI 1914 """ 1915 frame = wx.Frame ( 1916 None, 1917 -4, 1918 'Testing EMR struct widgets', 1919 size=wx.Size(600, 400), 1920 style=wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE 1921 ) 1922 filemenu= wx.Menu() 1923 filemenu.AppendSeparator() 1924 filemenu.Append(ID_EXIT,"E&xit"," Terminate test application") 1925 1926 # Creating the menubar. 1927 menuBar = wx.MenuBar() 1928 menuBar.Append(filemenu,"&File") 1929 1930 frame.SetMenuBar(menuBar) 1931 1932 txt = wx.StaticText( frame, -1, _("Select desired test option from the 'File' menu"), 1933 wx.DefaultPosition, wx.DefaultSize, 0 ) 1934 1935 # event handlers 1936 wx.EVT_MENU(frame, ID_EXIT, self.OnCloseWindow) 1937 1938 # patient EMR 1939 self.__pat = gmPerson.gmCurrentPatient() 1940 1941 frame.Show(1) 1942 return 1
1943 #--------------------------------------------------------
1944 - def OnCloseWindow (self, e):
1945 """ 1946 Close test aplication 1947 """ 1948 self.ExitMainLoop ()
1949 1950 #----------------------------------------------------------------
1951 - def test_epsiode_edit_area_pnl():
1952 app = wx.PyWidgetTester(size = (200, 300)) 1953 emr = pat.get_emr() 1954 epi = emr.get_episodes()[0] 1955 pnl = cEpisodeEditAreaPnl(app.frame, -1, episode=epi) 1956 app.frame.Show(True) 1957 app.MainLoop()
1958 #----------------------------------------------------------------
1959 - def test_episode_edit_area_dialog():
1960 app = wx.PyWidgetTester(size = (200, 300)) 1961 emr = pat.get_emr() 1962 epi = emr.get_episodes()[0] 1963 edit_episode(parent=app.frame, episode=epi)
1964 #----------------------------------------------------------------
1965 - def test_hospital_stay_prw():
1966 app = wx.PyWidgetTester(size = (400, 40)) 1967 app.SetWidget(cHospitalStayPhraseWheel, id=-1, size=(180,20), pos=(10,20)) 1968 app.MainLoop()
1969 #----------------------------------------------------------------
1970 - def test_episode_selection_prw():
1971 app = wx.PyWidgetTester(size = (400, 40)) 1972 app.SetWidget(cEpisodeSelectionPhraseWheel, id=-1, size=(180,20), pos=(10,20)) 1973 # app.SetWidget(cEpisodeSelectionPhraseWheel, id=-1, size=(350,20), pos=(10,20), patient_id=pat.ID) 1974 app.MainLoop()
1975 #----------------------------------------------------------------
1976 - def test_health_issue_edit_area_dlg():
1977 app = wx.PyWidgetTester(size = (200, 300)) 1978 edit_health_issue(parent=app.frame, issue=None)
1979 #----------------------------------------------------------------
1980 - def test_health_issue_edit_area_pnl():
1981 app = wx.PyWidgetTester(size = (200, 300)) 1982 app.SetWidget(cHealthIssueEditAreaPnl, id=-1, size = (400,400)) 1983 app.MainLoop()
1984 #----------------------------------------------------------------
1985 - def test_edit_procedure():
1986 app = wx.PyWidgetTester(size = (200, 300)) 1987 edit_procedure(parent=app.frame)
1988 #================================================================ 1989 1990 if (len(sys.argv) > 1) and (sys.argv[1] == 'test'): 1991 1992 gmI18N.activate_locale() 1993 gmI18N.install_domain() 1994 gmDateTime.init() 1995 1996 # obtain patient 1997 pat = gmPersonSearch.ask_for_patient() 1998 if pat is None: 1999 print "No patient. Exiting gracefully..." 2000 sys.exit(0) 2001 gmPatSearchWidgets.set_active_patient(patient=pat) 2002 2003 # try: 2004 # lauch emr dialogs test application 2005 # app = testapp(0) 2006 # app.MainLoop() 2007 # except StandardError: 2008 # _log.exception("unhandled exception caught !") 2009 # but re-raise them 2010 # raise 2011 2012 #test_epsiode_edit_area_pnl() 2013 #test_episode_edit_area_dialog() 2014 #test_health_issue_edit_area_dlg() 2015 #test_episode_selection_prw() 2016 #test_hospital_stay_prw() 2017 test_edit_procedure() 2018 2019 #================================================================ 2020