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

Source Code for Module Gnumed.wxpython.gmVaccWidgets

   1  """GNUmed immunisation/vaccination widgets. 
   2   
   3  Modelled after Richard Terry's design document. 
   4   
   5  copyright: authors 
   6  """ 
   7  #====================================================================== 
   8  __version__ = "$Revision: 1.36 $" 
   9  __author__ = "R.Terry, S.J.Tan, K.Hilbert" 
  10  __license__ = "GPL (details at http://www.gnu.org)" 
  11   
  12  import sys, time, logging 
  13   
  14   
  15  import wx 
  16   
  17   
  18  if __name__ == '__main__': 
  19          sys.path.insert(0, '../../') 
  20  from Gnumed.pycommon import gmDispatcher, gmMatchProvider, gmTools, gmI18N 
  21  from Gnumed.pycommon import gmCfg, gmDateTime 
  22  from Gnumed.business import gmPerson, gmVaccination, gmSurgery 
  23  from Gnumed.wxpython import gmPhraseWheel, gmTerryGuiParts, gmRegetMixin, gmGuiHelpers 
  24  from Gnumed.wxpython import gmEditArea, gmListWidgets 
  25   
  26   
  27  _log = logging.getLogger('gm.vaccination') 
  28  _log.info(__version__) 
  29   
  30  #====================================================================== 
  31  # vaccination indication related widgets 
  32  #---------------------------------------------------------------------- 
33 -def manage_vaccination_indications(parent=None):
34 35 if parent is None: 36 parent = wx.GetApp().GetTopWindow() 37 #------------------------------------------------------------ 38 def refresh(lctrl): 39 inds = gmVaccination.get_indications(order_by = 'description') 40 41 items = [ [ 42 i['description'], 43 gmTools.coalesce ( 44 i['atcs_single_indication'], 45 u'', 46 u'%s' 47 ), 48 gmTools.coalesce ( 49 i['atcs_combi_indication'], 50 u'', 51 u'%s' 52 ), 53 u'%s' % i['id'] 54 ] for i in inds ] 55 56 lctrl.set_string_items(items) 57 lctrl.set_data(inds)
58 #------------------------------------------------------------ 59 gmListWidgets.get_choices_from_list ( 60 parent = parent, 61 msg = _('\nConditions preventable by vaccination as currently known to GNUmed.\n'), 62 caption = _('Showing vaccination preventable conditions.'), 63 columns = [ _('Condition'), _('ATCs: single-condition vaccines'), _('ATCs: multi-condition vaccines'), u'#' ], 64 single_selection = True, 65 refresh_callback = refresh 66 ) 67 #====================================================================== 68 # vaccines related widgets 69 #----------------------------------------------------------------------
70 -def edit_vaccine(parent=None, vaccine=None, single_entry=True):
71 ea = cVaccineEAPnl(parent = parent, id = -1) 72 ea.data = vaccine 73 ea.mode = gmTools.coalesce(vaccine, 'new', 'edit') 74 dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = single_entry) 75 dlg.SetTitle(gmTools.coalesce(vaccine, _('Adding new vaccine'), _('Editing vaccine'))) 76 if dlg.ShowModal() == wx.ID_OK: 77 dlg.Destroy() 78 return True 79 dlg.Destroy() 80 return False
81 #----------------------------------------------------------------------
82 -def manage_vaccines(parent=None):
83 84 if parent is None: 85 parent = wx.GetApp().GetTopWindow() 86 #------------------------------------------------------------ 87 def delete(vaccine=None): 88 deleted = gmVaccination.delete_vaccine(vaccine = vaccine['pk_vaccine']) 89 if deleted: 90 return True 91 92 gmGuiHelpers.gm_show_info ( 93 _( 94 'Cannot delete vaccine\n' 95 '\n' 96 ' %s - %s (#%s)\n' 97 '\n' 98 'It is probably documented in a vaccination.' 99 ) % ( 100 vaccine['vaccine'], 101 vaccine['preparation'], 102 vaccine['pk_vaccine'] 103 ), 104 _('Deleting vaccine') 105 ) 106 107 return False
108 #------------------------------------------------------------ 109 def edit(vaccine=None): 110 return edit_vaccine(parent = parent, vaccine = vaccine, single_entry = True) 111 #------------------------------------------------------------ 112 def refresh(lctrl): 113 vaccines = gmVaccination.get_vaccines(order_by = 'vaccine') 114 115 items = [ [ 116 u'%s' % v['pk_brand'], 117 u'%s%s' % ( 118 v['vaccine'], 119 gmTools.bool2subst ( 120 v['is_fake_vaccine'], 121 u' (%s)' % _('fake'), 122 u'' 123 ) 124 ), 125 v['preparation'], 126 u'%s (%s)' % (v['route_abbreviation'], v['route_description']), 127 gmTools.bool2subst(v['is_live'], gmTools.u_checkmark_thin, u''), 128 gmTools.coalesce(v['atc_code'], u''), 129 u'%s%s' % ( 130 gmTools.coalesce(v['min_age'], u'?'), 131 gmTools.coalesce(v['max_age'], u'?', u' - %s'), 132 ), 133 gmTools.coalesce(v['comment'], u'') 134 ] for v in vaccines ] 135 lctrl.set_string_items(items) 136 lctrl.set_data(vaccines) 137 #------------------------------------------------------------ 138 gmListWidgets.get_choices_from_list ( 139 parent = parent, 140 msg = _('\nThe vaccines currently known to GNUmed.\n'), 141 caption = _('Showing vaccines.'), 142 columns = [ u'#', _('Brand'), _('Preparation'), _(u'Route'), _('Live'), _('ATC'), _('Age range'), _('Comment') ], 143 single_selection = True, 144 refresh_callback = refresh, 145 edit_callback = edit, 146 new_callback = edit, 147 delete_callback = delete 148 ) 149 #----------------------------------------------------------------------
150 -class cBatchNoPhraseWheel(gmPhraseWheel.cPhraseWheel):
151
152 - def __init__(self, *args, **kwargs):
153 154 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 155 156 context = { 157 u'ctxt_vaccine': { 158 u'where_part': u'AND pk_vaccine = %(pk_vaccine)s', 159 u'placeholder': u'pk_vaccine' 160 } 161 } 162 163 query = u""" 164 SELECT code, batch_no FROM ( 165 166 SELECT distinct on (batch_no) code, batch_no, rank FROM ( 167 168 ( 169 -- batch_no by vaccine 170 SELECT 171 batch_no AS code, 172 batch_no, 173 1 AS rank 174 FROM 175 clin.v_pat_vaccinations 176 WHERE 177 batch_no %(fragment_condition)s 178 %(ctxt_vaccine)s 179 ) UNION ALL ( 180 -- batch_no for any vaccine 181 SELECT 182 batch_no AS code, 183 batch_no, 184 2 AS rank 185 FROM 186 clin.v_pat_vaccinations 187 WHERE 188 batch_no %(fragment_condition)s 189 ) 190 191 ) AS matching_batch_nos 192 193 ) as unique_matches 194 195 ORDER BY rank, batch_no 196 LIMIT 25 197 """ 198 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query, context = context) 199 mp.setThresholds(1, 2, 3) 200 self.matcher = mp 201 202 self.unset_context(context = u'pk_vaccine') 203 self.SetToolTipString(_('Enter or select the batch/lot number of the vaccine used.')) 204 self.selection_only = False
205 #----------------------------------------------------------------------
206 -class cVaccinePhraseWheel(gmPhraseWheel.cPhraseWheel):
207
208 - def __init__(self, *args, **kwargs):
209 210 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 211 212 # consider ATCs in ref.branded_drug and vacc_indication 213 query = u""" 214 SELECT pk_vaccine, description FROM ( 215 216 SELECT DISTINCT ON (pk_vaccine) pk_vaccine, description FROM ( 217 218 ( 219 -- fragment -> vaccine 220 SELECT 221 pk_vaccine, 222 vaccine || ' (' || array_to_string(l10n_indications, ', ') || ')' 223 AS description 224 FROM 225 clin.v_vaccines 226 WHERE 227 vaccine %(fragment_condition)s 228 229 ) union all ( 230 231 -- fragment -> localized indication -> vaccines 232 SELECT 233 pk_vaccine, 234 vaccine || ' (' || array_to_string(l10n_indications, ', ') || ')' 235 AS description 236 FROM 237 clin.v_indications4vaccine 238 WHERE 239 l10n_indication %(fragment_condition)s 240 241 ) union all ( 242 243 -- fragment -> indication -> vaccines 244 SELECT 245 pk_vaccine, 246 vaccine || ' (' || array_to_string(indications, ', ') || ')' 247 AS description 248 FROM 249 clin.v_indications4vaccine 250 WHERE 251 indication %(fragment_condition)s 252 ) 253 ) AS distinct_total 254 255 ) AS total 256 257 ORDER by description 258 LIMIT 25 259 """ 260 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query) 261 mp.setThresholds(1, 2, 3) 262 self.matcher = mp 263 264 self.selection_only = True
265 #------------------------------------------------------------------
266 - def _data2instance(self):
267 return gmVaccination.cVaccine(aPK_obj = self.data)
268 #---------------------------------------------------------------------- 269 from Gnumed.wxGladeWidgets import wxgVaccineEAPnl 270
271 -class cVaccineEAPnl(wxgVaccineEAPnl.wxgVaccineEAPnl, gmEditArea.cGenericEditAreaMixin):
272
273 - def __init__(self, *args, **kwargs):
274 275 try: 276 data = kwargs['vaccine'] 277 del kwargs['vaccine'] 278 except KeyError: 279 data = None 280 281 wxgVaccineEAPnl.wxgVaccineEAPnl.__init__(self, *args, **kwargs) 282 gmEditArea.cGenericEditAreaMixin.__init__(self) 283 284 self.mode = 'new' 285 self.data = data 286 if data is not None: 287 self.mode = 'edit' 288 289 self.__init_ui()
290 #----------------------------------------------------------------
291 - def __init_ui(self):
292 # setup phrasewheels and stuff 293 self._PRW_route.selection_only = True 294 295 self.Layout() 296 self.Fit()
297 #---------------------------------------------------------------- 298 # generic Edit Area mixin API 299 #----------------------------------------------------------------
300 - def _valid_for_save(self):
301 302 has_errors = False 303 304 if self._PRW_brand.GetValue().strip() == u'': 305 has_errors = True 306 self._PRW_brand.display_as_valid(False) 307 else: 308 self._PRW_brand.display_as_valid(True) 309 310 if self._PRW_route.GetData() is None: 311 has_errors = True 312 self._PRW_route.display_as_valid(False) 313 else: 314 self._PRW_route.display_as_valid(True) 315 316 if not self._PNL_indications.has_selection: 317 has_errors = True 318 319 if self._PRW_atc.GetValue().strip() == u'': 320 self._PRW_atc.display_as_valid(True) 321 else: 322 if self._PRW_atc.GetData() is None: 323 self._PRW_atc.display_as_valid(True) 324 else: 325 has_errors = True 326 self._PRW_atc.display_as_valid(False) 327 328 val = self._PRW_age_min.GetValue().strip() 329 if val == u'': 330 self._PRW_age_min.display_as_valid(True) 331 else: 332 if gmDateTime.str2interval(val) is None: 333 has_errors = True 334 self._PRW_age_min.display_as_valid(False) 335 else: 336 self._PRW_age_min.display_as_valid(True) 337 338 val = self._PRW_age_max.GetValue().strip() 339 if val == u'': 340 self._PRW_age_max.display_as_valid(True) 341 else: 342 if gmDateTime.str2interval(val) is None: 343 has_errors = True 344 self._PRW_age_max.display_as_valid(False) 345 else: 346 self._PRW_age_max.display_as_valid(True) 347 348 return (has_errors is False)
349 #----------------------------------------------------------------
350 - def _save_as_new(self):
351 # save the data as a new instance 352 data = 1 353 354 data[''] = 1 355 data[''] = 1 356 357 #data.save() 358 359 # must be done very late or else the property access 360 # will refresh the display such that later field 361 # access will return empty values 362 #self.data = data 363 return False 364 return True
365 #----------------------------------------------------------------
366 - def _save_as_update(self):
367 # update self.data and save the changes 368 self.data[''] = 1 369 self.data[''] = 1 370 self.data[''] = 1 371 #self.data.save() 372 return True
373 #----------------------------------------------------------------
374 - def _refresh_as_new(self):
375 self._PRW_brand.SetText(value = u'', data = None, suppress_smarts = True) 376 self._PRW_route.SetText(value = u'intramuscular') 377 self._CHBOX_live.SetValue(False) 378 self._CHBOX_fake.SetValue(False) 379 self._PNL_indications.clear_all() 380 self._PRW_atc.SetText(value = u'', data = None, suppress_smarts = True) 381 self._PRW_age_min.SetText(value = u'', data = None, suppress_smarts = True) 382 self._PRW_age_max.SetText(value = u'', data = None, suppress_smarts = True) 383 self._TCTRL_comment.SetValue(u'')
384 #----------------------------------------------------------------
385 - def _refresh_from_existing(self):
386 self._PRW_brand.SetText(value = self.data['vaccine'], data = self.data['pk_brand']) 387 self._PRW_route.SetText(value = self.data['route_description'], data = self.data['pk_route']) 388 self._CHBOX_live.SetValue(self.data['is_live']) 389 self._CHBOX_fake.SetValue(self.data['is_fake_vaccine']) 390 self._PNL_indications.select(self.data['indications']) 391 self._PRW_atc.SetText(value = self.data['atc_code'], data = self.data['atc_code']) 392 if self.data['min_age'] is None: 393 self._PRW_age_min.SetText(value = u'', data = None, suppress_smarts = True) 394 else: 395 self._PRW_age_min.SetText ( 396 value = gmDateTime.format_interval(self.data['min_age'], gmDateTime.acc_years), 397 data = self.data['min_age'] 398 ) 399 if self.data['max_age'] is None: 400 self._PRW_age_max.SetText(value = u'', data = None, suppress_smarts = True) 401 else: 402 self._PRW_age_max.SetText ( 403 value = gmDateTime.format_interval(self.data['max_age'], gmDateTime.acc_years), 404 data = self.data['max_age'] 405 ) 406 self._TCTRL_comment.SetValue(gmTools.coalesce(self.data['comment'], u''))
407 #----------------------------------------------------------------
409 self._refresh_as_new()
410 #====================================================================== 411 # vaccination related widgets 412 #----------------------------------------------------------------------
413 -def edit_vaccination(parent=None, vaccination=None, single_entry=True):
414 ea = cVaccinationEAPnl(parent = parent, id = -1) 415 ea.data = vaccination 416 ea.mode = gmTools.coalesce(vaccination, 'new', 'edit') 417 dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = single_entry) 418 dlg.SetTitle(gmTools.coalesce(vaccination, _('Adding new vaccination'), _('Editing vaccination'))) 419 if dlg.ShowModal() == wx.ID_OK: 420 dlg.Destroy() 421 return True 422 dlg.Destroy() 423 return False
424 #----------------------------------------------------------------------
425 -def manage_vaccinations(parent=None):
426 427 pat = gmPerson.gmCurrentPatient() 428 emr = pat.get_emr() 429 430 if parent is None: 431 parent = wx.GetApp().GetTopWindow() 432 433 #------------------------------------------------------------ 434 def edit(vaccination=None): 435 return edit_vaccination(parent = parent, vaccination = vaccination, single_entry = True)
436 #------------------------------------------------------------ 437 def delete(vaccination=None): 438 gmVaccination.delete_vaccination(vaccination = vaccination['pk_vaccination']) 439 return True 440 #------------------------------------------------------------ 441 def refresh(lctrl): 442 443 vaccs = emr.get_vaccinations(order_by = 'date_given DESC, pk_vaccination') 444 445 items = [ [ 446 v['date_given'].strftime('%Y %B %d').decode(gmI18N.get_encoding()), 447 v['vaccine'], 448 u', '.join(v['l10n_indications']), 449 v['batch_no'], 450 gmTools.coalesce(v['site'], u''), 451 gmTools.coalesce(v['reaction'], u''), 452 gmTools.coalesce(v['comment'], u'') 453 ] for v in vaccs ] 454 455 lctrl.set_string_items(items) 456 lctrl.set_data(vaccs) 457 #------------------------------------------------------------ 458 gmListWidgets.get_choices_from_list ( 459 parent = parent, 460 msg = _('\nComplete vaccination history for this patient.\n'), 461 caption = _('Showing vaccinations.'), 462 columns = [ _('Date'), _('Vaccine'), _(u'Intended to protect from'), _('Batch'), _('Site'), _('Reaction'), _('Comment') ], 463 single_selection = True, 464 refresh_callback = refresh, 465 new_callback = edit, 466 edit_callback = edit, 467 delete_callback = delete 468 ) 469 #---------------------------------------------------------------------- 470 from Gnumed.wxGladeWidgets import wxgVaccinationIndicationsPnl 471
472 -class cVaccinationIndicationsPnl(wxgVaccinationIndicationsPnl.wxgVaccinationIndicationsPnl):
473
474 - def __init__(self, *args, **kwargs):
475 476 wxgVaccinationIndicationsPnl.wxgVaccinationIndicationsPnl.__init__(self, *args, **kwargs) 477 478 self.__indication2field = { 479 u'coxiella burnetii (Q fever)': self._CHBOX_coxq, 480 u'salmonella typhi (typhoid)': self._CHBOX_typhoid, 481 u'varicella (chickenpox, shingles)': self._CHBOX_varicella, 482 u'influenza (seasonal)': self._CHBOX_influenza, 483 u'bacillus anthracis (Anthrax)': self._CHBOX_anthrax, 484 u'human papillomavirus': self._CHBOX_hpv, 485 u'rotavirus': self._CHBOX_rota, 486 u'tuberculosis': self._CHBOX_tuberculosis, 487 u'variola virus (smallpox)': self._CHBOX_smallpox, 488 u'influenza (H1N1)': self._CHBOX_h1n1, 489 u'cholera': self._CHBOX_cholera, 490 u'diphtheria': self._CHBOX_diphtheria, 491 u'haemophilus influenzae b': self._CHBOX_hib, 492 u'hepatitis A': self._CHBOX_hepA, 493 u'hepatitis B': self._CHBOX_hepB, 494 u'japanese B encephalitis': self._CHBOX_japanese, 495 u'measles': self._CHBOX_measles, 496 u'meningococcus A': self._CHBOX_menA, 497 u'meningococcus C': self._CHBOX_menC, 498 u'meningococcus W': self._CHBOX_menW, 499 u'meningococcus Y': self._CHBOX_menY, 500 u'mumps': self._CHBOX_mumps, 501 u'pertussis': self._CHBOX_pertussis, 502 u'pneumococcus': self._CHBOX_pneumococcus, 503 u'poliomyelitis': self._CHBOX_polio, 504 u'rabies': self._CHBOX_rabies, 505 u'rubella': self._CHBOX_rubella, 506 u'tetanus': self._CHBOX_tetanus, 507 u'tick-borne meningoencephalitis': self._CHBOX_fsme, 508 u'yellow fever': self._CHBOX_yellow_fever, 509 u'yersinia pestis': self._CHBOX_yersinia_pestis 510 }
511 #------------------------------------------------------------------
512 - def enable_all(self):
513 for field in self.__dict__.keys(): 514 if field.startswith('_CHBOX_'): 515 self.__dict__[field].Enable() 516 self.Enable()
517 #------------------------------------------------------------------
518 - def disable_all(self):
519 for field in self.__dict__.keys(): 520 if field.startswith('_CHBOX_'): 521 self.__dict__[field].Disable() 522 self.Disable()
523 #------------------------------------------------------------------
524 - def clear_all(self):
525 for field in self.__dict__.keys(): 526 if field.startswith('_CHBOX_'): 527 self.__dict__[field].SetValue(False)
528 #------------------------------------------------------------------
529 - def select(self, indications=None):
530 for indication in indications: 531 self.__indication2field[indication].SetValue(True)
532 #------------------------------------------------------------------
533 - def _get_selected_indications(self):
534 indications = [] 535 for indication in self.__indication2field.keys(): 536 if self.__indication2field[indication].IsChecked(): 537 indications.append(indication) 538 return indications
539 540 selected_indications = property(_get_selected_indications, lambda x:x) 541 #------------------------------------------------------------------
542 - def _get_has_selection(self):
543 for indication in self.__indication2field.keys(): 544 if self.__indication2field[indication].IsChecked(): 545 return True 546 return False
547 548 has_selection = property(_get_has_selection, lambda x:x)
549 550 #---------------------------------------------------------------------- 551 from Gnumed.wxGladeWidgets import wxgVaccinationEAPnl 552
553 -class cVaccinationEAPnl(wxgVaccinationEAPnl.wxgVaccinationEAPnl, gmEditArea.cGenericEditAreaMixin):
554 """ 555 - warn on apparent duplicates 556 - ask if "missing" (= previous, non-recorded) vaccinations 557 should be estimated and saved (add note "auto-generated") 558 559 Batch No (http://www.fao.org/docrep/003/v9952E12.htm) 560 """
561 - def __init__(self, *args, **kwargs):
562 563 try: 564 data = kwargs['vaccination'] 565 del kwargs['vaccination'] 566 except KeyError: 567 data = None 568 569 wxgVaccinationEAPnl.wxgVaccinationEAPnl.__init__(self, *args, **kwargs) 570 gmEditArea.cGenericEditAreaMixin.__init__(self) 571 572 self.mode = 'new' 573 self.data = data 574 if data is not None: 575 self.mode = 'edit' 576 577 self.__init_ui()
578 #----------------------------------------------------------------
579 - def __init_ui(self):
580 # adjust phrasewheels etc 581 self._PRW_vaccine.add_callback_on_lose_focus(self._on_PRW_vaccine_lost_focus) 582 self._PRW_provider.selection_only = False 583 # self._PRW_batch.unset_context(context = 'pk_vaccine') # done in PRW init() 584 self._PRW_reaction.add_callback_on_lose_focus(self._on_PRW_reaction_lost_focus)
585 #----------------------------------------------------------------
586 - def _on_PRW_vaccine_lost_focus(self):
587 588 vaccine = self._PRW_vaccine.GetData(as_instance=True) 589 590 # if we are editing we do not allow using indications rather than a vaccine 591 if self.mode == u'edit': 592 self._PNL_indications.clear_all() 593 if vaccine is None: 594 self._PRW_batch.unset_context(context = 'pk_vaccine') 595 else: 596 self._PRW_batch.set_context(context = 'pk_vaccine', val = vaccine['pk_vaccine']) 597 self._PNL_indications.select(indications = vaccine['indications']) 598 self._PNL_indications.disable_all() 599 600 # we are entering a new vaccination 601 else: 602 if vaccine is None: 603 self._PRW_batch.unset_context(context = 'pk_vaccine') 604 self._PNL_indications.enable_all() 605 else: 606 self._PRW_batch.set_context(context = 'pk_vaccine', val = vaccine['pk_vaccine']) 607 self._PNL_indications.clear_all() 608 self._PNL_indications.select(indications = vaccine['indications']) 609 self._PNL_indications.disable_all()
610 #----------------------------------------------------------------
612 if self._PRW_reaction.GetValue().strip() == u'': 613 self._BTN_report.Enable(False) 614 else: 615 self._BTN_report.Enable(True)
616 #---------------------------------------------------------------- 617 # generic Edit Area mixin API 618 #----------------------------------------------------------------
619 - def _valid_for_save(self):
620 621 has_errors = False 622 623 if not self._DP_date_given.is_valid_timestamp(allow_none = False): 624 has_errors = True 625 626 vaccine = self._PRW_vaccine.GetData(as_instance = True) 627 628 # we are editing, require vaccine rather than indications 629 if self.mode == u'edit': 630 if vaccine is None: 631 has_errors = True 632 self._PRW_vaccine.display_as_valid(False) 633 else: 634 self._PRW_vaccine.display_as_valid(True) 635 self._PNL_indications.clear_all() 636 self._PNL_indications.select(indications = vaccine['indications']) 637 self._PNL_indications.disable_all() 638 # we are creating, allow either vaccine or indications 639 else: 640 if vaccine is None: 641 if self._PNL_indications.has_selection: 642 self._PRW_vaccine.display_as_valid(True) 643 else: 644 has_errors = True 645 self._PRW_vaccine.display_as_valid(False) 646 else: 647 self._PRW_vaccine.display_as_valid(True) 648 649 if self._PRW_batch.GetValue().strip() == u'': 650 has_errors = True 651 self._PRW_batch.display_as_valid(False) 652 else: 653 self._PRW_batch.display_as_valid(True) 654 655 if self._PRW_episode.GetValue().strip() == u'': 656 self._PRW_episode.SetText(value = _('prevention')) 657 658 return (has_errors is False)
659 #----------------------------------------------------------------
660 - def _save_as_new(self):
661 662 vaccine = self._PRW_vaccine.GetData() 663 if vaccine is None: 664 data = self.__save_new_from_indications() 665 else: 666 data = self.__save_new_from_vaccine(vaccine = vaccine) 667 668 # must be done very late or else the property access 669 # will refresh the display such that later field 670 # access will return empty values 671 self.data = data 672 673 return True
674 #----------------------------------------------------------------
676 677 inds = self._PNL_indications.selected_indications 678 vaccine = gmVaccination.map_indications2generic_vaccine(indications = inds) 679 680 if vaccine is None: 681 for ind in inds: 682 vaccine = gmVaccination.map_indications2generic_vaccine(indications = [ind]) 683 data = self.__save_new_from_vaccine(vaccine = vaccine['pk_vaccine']) 684 else: 685 data = self.__save_new_from_vaccine(vaccine = vaccine['pk_vaccine']) 686 687 return data
688 #----------------------------------------------------------------
689 - def __save_new_from_vaccine(self, vaccine=None):
690 691 emr = gmPerson.gmCurrentPatient().get_emr() 692 693 data = emr.add_vaccination ( 694 episode = self._PRW_episode.GetData(can_create = True, is_open = False), 695 vaccine = vaccine, 696 batch_no = self._PRW_batch.GetValue().strip() 697 ) 698 699 if self._CHBOX_anamnestic.GetValue() is True: 700 data['soap_cat'] = u's' 701 else: 702 data['soap_cat'] = u'p' 703 704 data['date_given'] = self._DP_date_given.get_pydt() 705 data['site'] = self._PRW_site.GetValue().strip() 706 data['pk_provider'] = self._PRW_provider.GetData() 707 data['reaction'] = self._PRW_reaction.GetValue().strip() 708 data['comment'] = self._TCTRL_comment.GetValue().strip() 709 710 data.save() 711 712 return data
713 #----------------------------------------------------------------
714 - def _save_as_update(self):
715 716 if self._CHBOX_anamnestic.GetValue() is True: 717 self.data['soap_cat'] = u's' 718 else: 719 self.data['soap_cat'] = u'p' 720 721 self.data['date_given'] = self._DP_date_given.get_pydt() 722 self.data['pk_vaccine'] = self._PRW_vaccine.GetData() 723 self.data['batch_no'] = self._PRW_batch.GetValue().strip() 724 self.data['pk_episode'] = self._PRW_episode.GetData(can_create = True, is_open = False) 725 self.data['site'] = self._PRW_site.GetValue().strip() 726 self.data['pk_provider'] = self._PRW_provider.GetData() 727 self.data['reaction'] = self._PRW_reaction.GetValue().strip() 728 self.data['comment'] = self._TCTRL_comment.GetValue().strip() 729 730 self.data.save() 731 732 return True
733 #----------------------------------------------------------------
734 - def _refresh_as_new(self):
735 self._DP_date_given.SetValue(gmDateTime.pydt_now_here()) 736 self._CHBOX_anamnestic.SetValue(True) 737 self._PRW_vaccine.SetText(value = u'', data = None, suppress_smarts = True) 738 739 self._PNL_indications.clear_all() 740 self._PRW_batch.unset_context(context = 'pk_vaccine') 741 self._PRW_batch.SetValue(u'') 742 743 self._PRW_episode.SetText(value = u'', data = None, suppress_smarts = True) 744 self._PRW_site.SetValue(u'') 745 self._PRW_provider.SetData(data = None) 746 self._PRW_reaction.SetText(value = u'', data = None, suppress_smarts = True) 747 self._BTN_report.Enable(False) 748 self._TCTRL_comment.SetValue(u'') 749 750 self._DP_date_given.SetFocus()
751 #----------------------------------------------------------------
752 - def _refresh_from_existing(self):
753 self._DP_date_given.SetValue(self.data['date_given']) 754 if self.data['soap_cat'] == u's': 755 self._CHBOX_anamnestic.SetValue(True) 756 else: 757 self._CHBOX_anamnestic.SetValue(False) 758 self._PRW_vaccine.SetText(value = self.data['vaccine'], data = self.data['pk_vaccine']) 759 760 self._PNL_indications.clear_all() 761 self._PNL_indications.select(indications = self.data['indications']) 762 self._PNL_indications.disable_all() 763 764 self._PRW_batch.SetValue(self.data['batch_no']) 765 self._PRW_episode.SetData(data = self.data['pk_episode']) 766 self._PRW_site.SetValue(gmTools.coalesce(self.data['site'], u'')) 767 self._PRW_provider.SetData(self.data['pk_provider']) 768 self._PRW_reaction.SetValue(gmTools.coalesce(self.data['reaction'], u'')) 769 if self.data['reaction'] is None: 770 self._BTN_report.Enable(False) 771 else: 772 self._BTN_report.Enable(True) 773 self._TCTRL_comment.SetValue(gmTools.coalesce(self.data['comment'], u'')) 774 775 self._DP_date_given.SetFocus()
776 #----------------------------------------------------------------
778 self._DP_date_given.SetValue(gmDateTime.pydt_now_here()) 779 self._CHBOX_anamnestic.SetValue(True) 780 self._PRW_vaccine.SetText(value = self.data['vaccine'], data = self.data['pk_vaccine']) 781 782 self._PNL_indications.clear_all() 783 self._PNL_indications.select(indications = self.data['indications']) 784 self._PNL_indications.disable_all() 785 786 self._PRW_batch.set_context(context = 'pk_vaccine', val = self.data['pk_vaccine']) 787 self._PRW_batch.SetValue(u'') 788 789 self._PRW_episode.SetData(data = self.data['pk_episode']) 790 self._PRW_site.SetValue(gmTools.coalesce(self.data['site'], u'')) 791 self._PRW_provider.SetData(self.data['pk_provider']) 792 self._PRW_reaction.SetValue(u'') 793 self._BTN_report.Enable(False) 794 self._TCTRL_comment.SetValue(u'') 795 796 self._DP_date_given.SetFocus()
797 #----------------------------------------------------------------
798 - def _on_report_button_pressed(self, event):
799 800 event.Skip() 801 802 dbcfg = gmCfg.cCfgSQL() 803 804 url = dbcfg.get2 ( 805 option = u'external.urls.report_vaccine_ADR', 806 workplace = gmSurgery.gmCurrentPractice().active_workplace, 807 bias = u'user', 808 default = u'http://www.pei.de/cln_042/SharedDocs/Downloads/fachkreise/uaw/meldeboegen/b-ifsg-meldebogen,templateId=raw,property=publicationFile.pdf/b-ifsg-meldebogen.pdf' 809 ) 810 811 if url.strip() == u'': 812 url = dbcfg.get2 ( 813 option = u'external.urls.report_ADR', 814 workplace = gmSurgery.gmCurrentPractice().active_workplace, 815 bias = u'user' 816 ) 817 818 webbrowser.open(url = url, new = False, autoraise = True)
819 #---------------------------------------------------------------- 820 821 #====================================================================== 822 #======================================================================
823 -class cImmunisationsPanel(wx.Panel, gmRegetMixin.cRegetOnPaintMixin):
824
825 - def __init__(self, parent, id):
826 wx.Panel.__init__(self, parent, id, wx.DefaultPosition, wx.DefaultSize, wx.RAISED_BORDER) 827 gmRegetMixin.cRegetOnPaintMixin.__init__(self) 828 self.__pat = gmPerson.gmCurrentPatient() 829 # do this here so "import cImmunisationsPanel from gmVaccWidgets" works 830 self.ID_VaccinatedIndicationsList = wx.NewId() 831 self.ID_VaccinationsPerRegimeList = wx.NewId() 832 self.ID_MissingShots = wx.NewId() 833 self.ID_ActiveSchedules = wx.NewId() 834 self.__do_layout() 835 self.__register_interests() 836 self.__reset_ui_content()
837 #----------------------------------------------------
838 - def __do_layout(self):
839 #----------------------------------------------- 840 # top part 841 #----------------------------------------------- 842 pnl_UpperCaption = gmTerryGuiParts.cHeadingCaption(self, -1, _(" IMMUNISATIONS ")) 843 self.editarea = cVaccinationEditArea(self, -1, wx.DefaultPosition, wx.DefaultSize, wx.NO_BORDER) 844 845 #----------------------------------------------- 846 # middle part 847 #----------------------------------------------- 848 # divider headings below editing area 849 indications_heading = gmTerryGuiParts.cDividerCaption(self, -1, _("Indications")) 850 vaccinations_heading = gmTerryGuiParts.cDividerCaption(self, -1, _("Vaccinations")) 851 schedules_heading = gmTerryGuiParts.cDividerCaption(self, -1, _("Active Schedules")) 852 szr_MiddleCap = wx.BoxSizer(wx.HORIZONTAL) 853 szr_MiddleCap.Add(indications_heading, 4, wx.EXPAND) 854 szr_MiddleCap.Add(vaccinations_heading, 6, wx.EXPAND) 855 szr_MiddleCap.Add(schedules_heading, 10, wx.EXPAND) 856 857 # left list: indications for which vaccinations have been given 858 self.LBOX_vaccinated_indications = wx.ListBox( 859 parent = self, 860 id = self.ID_VaccinatedIndicationsList, 861 choices = [], 862 style = wx.LB_HSCROLL | wx.LB_NEEDED_SB | wx.SUNKEN_BORDER 863 ) 864 self.LBOX_vaccinated_indications.SetFont(wx.Font(12,wx.SWISS, wx.NORMAL, wx.NORMAL, False, '')) 865 866 # right list: when an indication has been selected on the left 867 # display the corresponding vaccinations on the right 868 self.LBOX_given_shots = wx.ListBox( 869 parent = self, 870 id = self.ID_VaccinationsPerRegimeList, 871 choices = [], 872 style = wx.LB_HSCROLL | wx.LB_NEEDED_SB | wx.SUNKEN_BORDER 873 ) 874 self.LBOX_given_shots.SetFont(wx.Font(12,wx.SWISS, wx.NORMAL, wx.NORMAL, False, '')) 875 876 self.LBOX_active_schedules = wx.ListBox ( 877 parent = self, 878 id = self.ID_ActiveSchedules, 879 choices = [], 880 style = wx.LB_HSCROLL | wx.LB_NEEDED_SB | wx.SUNKEN_BORDER 881 ) 882 self.LBOX_active_schedules.SetFont(wx.Font(12, wx.SWISS, wx.NORMAL, wx.NORMAL, False, '')) 883 884 szr_MiddleLists = wx.BoxSizer(wx.HORIZONTAL) 885 szr_MiddleLists.Add(self.LBOX_vaccinated_indications, 4, wx.EXPAND) 886 szr_MiddleLists.Add(self.LBOX_given_shots, 6, wx.EXPAND) 887 szr_MiddleLists.Add(self.LBOX_active_schedules, 10, wx.EXPAND) 888 889 #--------------------------------------------- 890 # bottom part 891 #--------------------------------------------- 892 missing_heading = gmTerryGuiParts.cDividerCaption(self, -1, _("Missing Immunisations")) 893 szr_BottomCap = wx.BoxSizer(wx.HORIZONTAL) 894 szr_BottomCap.Add(missing_heading, 1, wx.EXPAND) 895 896 self.LBOX_missing_shots = wx.ListBox ( 897 parent = self, 898 id = self.ID_MissingShots, 899 choices = [], 900 style = wx.LB_HSCROLL | wx.LB_NEEDED_SB | wx.SUNKEN_BORDER 901 ) 902 self.LBOX_missing_shots.SetFont(wx.Font(12, wx.SWISS, wx.NORMAL, wx.NORMAL, False, '')) 903 904 szr_BottomLists = wx.BoxSizer(wx.HORIZONTAL) 905 szr_BottomLists.Add(self.LBOX_missing_shots, 1, wx.EXPAND) 906 907 # alert caption 908 pnl_AlertCaption = gmTerryGuiParts.cAlertCaption(self, -1, _(' Alerts ')) 909 910 #--------------------------------------------- 911 # add all elements to the main background sizer 912 #--------------------------------------------- 913 self.mainsizer = wx.BoxSizer(wx.VERTICAL) 914 self.mainsizer.Add(pnl_UpperCaption, 0, wx.EXPAND) 915 self.mainsizer.Add(self.editarea, 6, wx.EXPAND) 916 self.mainsizer.Add(szr_MiddleCap, 0, wx.EXPAND) 917 self.mainsizer.Add(szr_MiddleLists, 4, wx.EXPAND) 918 self.mainsizer.Add(szr_BottomCap, 0, wx.EXPAND) 919 self.mainsizer.Add(szr_BottomLists, 4, wx.EXPAND) 920 self.mainsizer.Add(pnl_AlertCaption, 0, wx.EXPAND) 921 922 self.SetAutoLayout(True) 923 self.SetSizer(self.mainsizer) 924 self.mainsizer.Fit(self)
925 #----------------------------------------------------
926 - def __register_interests(self):
927 # wxPython events 928 wx.EVT_SIZE(self, self.OnSize) 929 wx.EVT_LISTBOX(self, self.ID_VaccinatedIndicationsList, self._on_vaccinated_indication_selected) 930 wx.EVT_LISTBOX_DCLICK(self, self.ID_VaccinationsPerRegimeList, self._on_given_shot_selected) 931 wx.EVT_LISTBOX_DCLICK(self, self.ID_MissingShots, self._on_missing_shot_selected) 932 # wx.EVT_RIGHT_UP(self.lb1, self.EvtRightButton) 933 934 # client internal signals 935 gmDispatcher.connect(signal= u'post_patient_selection', receiver=self._schedule_data_reget) 936 gmDispatcher.connect(signal= u'vaccinations_updated', receiver=self._schedule_data_reget)
937 #---------------------------------------------------- 938 # event handlers 939 #----------------------------------------------------
940 - def OnSize (self, event):
941 w, h = event.GetSize() 942 self.mainsizer.SetDimension (0, 0, w, h)
943 #----------------------------------------------------
944 - def _on_given_shot_selected(self, event):
945 """Paste previously given shot into edit area. 946 """ 947 self.editarea.set_data(aVacc=event.GetClientData())
948 #----------------------------------------------------
949 - def _on_missing_shot_selected(self, event):
950 self.editarea.set_data(aVacc = event.GetClientData())
951 #----------------------------------------------------
952 - def _on_vaccinated_indication_selected(self, event):
953 """Update right hand middle list to show vaccinations given for selected indication.""" 954 ind_list = event.GetEventObject() 955 selected_item = ind_list.GetSelection() 956 ind = ind_list.GetClientData(selected_item) 957 # clear list 958 self.LBOX_given_shots.Set([]) 959 emr = self.__pat.get_emr() 960 shots = emr.get_vaccinations(indications = [ind]) 961 # FIXME: use Set() for entire array (but problem with client_data) 962 for shot in shots: 963 if shot['is_booster']: 964 marker = 'B' 965 else: 966 marker = '#%s' % shot['seq_no'] 967 label = '%s - %s: %s' % (marker, shot['date'].strftime('%m/%Y'), shot['vaccine']) 968 self.LBOX_given_shots.Append(label, shot)
969 #----------------------------------------------------
970 - def __reset_ui_content(self):
971 # clear edit area 972 self.editarea.set_data() 973 # clear lists 974 self.LBOX_vaccinated_indications.Clear() 975 self.LBOX_given_shots.Clear() 976 self.LBOX_active_schedules.Clear() 977 self.LBOX_missing_shots.Clear()
978 #----------------------------------------------------
979 - def _populate_with_data(self):
980 # clear lists 981 self.LBOX_vaccinated_indications.Clear() 982 self.LBOX_given_shots.Clear() 983 self.LBOX_active_schedules.Clear() 984 self.LBOX_missing_shots.Clear() 985 986 emr = self.__pat.get_emr() 987 988 t1 = time.time() 989 # populate vaccinated-indications list 990 # FIXME: consider adding virtual indication "most recent" to 991 # FIXME: display most recent of all indications as suggested by Syan 992 status, indications = emr.get_vaccinated_indications() 993 # FIXME: would be faster to use Set() but can't 994 # use Set(labels, client_data), and have to know 995 # line position in SetClientData :-( 996 for indication in indications: 997 self.LBOX_vaccinated_indications.Append(indication[1], indication[0]) 998 # self.LBOX_vaccinated_indications.Set(lines) 999 # self.LBOX_vaccinated_indications.SetClientData(data) 1000 print "vaccinated indications took", time.time()-t1, "seconds" 1001 1002 t1 = time.time() 1003 # populate active schedules list 1004 scheds = emr.get_scheduled_vaccination_regimes() 1005 if scheds is None: 1006 label = _('ERROR: cannot retrieve active vaccination schedules') 1007 self.LBOX_active_schedules.Append(label) 1008 elif len(scheds) == 0: 1009 label = _('no active vaccination schedules') 1010 self.LBOX_active_schedules.Append(label) 1011 else: 1012 for sched in scheds: 1013 label = _('%s for %s (%s shots): %s') % (sched['regime'], sched['l10n_indication'], sched['shots'], sched['comment']) 1014 self.LBOX_active_schedules.Append(label) 1015 print "active schedules took", time.time()-t1, "seconds" 1016 1017 t1 = time.time() 1018 # populate missing-shots list 1019 missing_shots = emr.get_missing_vaccinations() 1020 print "getting missing shots took", time.time()-t1, "seconds" 1021 if missing_shots is None: 1022 label = _('ERROR: cannot retrieve due/overdue vaccinations') 1023 self.LBOX_missing_shots.Append(label, None) 1024 return True 1025 # due 1026 due_template = _('%.0d weeks left: shot %s for %s in %s, due %s (%s)') 1027 overdue_template = _('overdue %.0dyrs %.0dwks: shot %s for %s in schedule "%s" (%s)') 1028 for shot in missing_shots['due']: 1029 if shot['overdue']: 1030 years, days_left = divmod(shot['amount_overdue'].days, 364.25) 1031 weeks = days_left / 7 1032 # amount_overdue, seq_no, indication, regime, vacc_comment 1033 label = overdue_template % ( 1034 years, 1035 weeks, 1036 shot['seq_no'], 1037 shot['l10n_indication'], 1038 shot['regime'], 1039 shot['vacc_comment'] 1040 ) 1041 self.LBOX_missing_shots.Append(label, shot) 1042 else: 1043 # time_left, seq_no, regime, latest_due, vacc_comment 1044 label = due_template % ( 1045 shot['time_left'].days / 7, 1046 shot['seq_no'], 1047 shot['indication'], 1048 shot['regime'], 1049 shot['latest_due'].strftime('%m/%Y'), 1050 shot['vacc_comment'] 1051 ) 1052 self.LBOX_missing_shots.Append(label, shot) 1053 # booster 1054 lbl_template = _('due now: booster for %s in schedule "%s" (%s)') 1055 for shot in missing_shots['boosters']: 1056 # indication, regime, vacc_comment 1057 label = lbl_template % ( 1058 shot['l10n_indication'], 1059 shot['regime'], 1060 shot['vacc_comment'] 1061 ) 1062 self.LBOX_missing_shots.Append(label, shot) 1063 print "displaying missing shots took", time.time()-t1, "seconds" 1064 1065 return True
1066 #----------------------------------------------------
1067 - def _on_post_patient_selection(self, **kwargs):
1068 return 1
1069 # FIXME: 1070 # if has_focus: 1071 # wxCallAfter(self.__reset_ui_content) 1072 # else: 1073 # return 1 1074 #----------------------------------------------------
1075 - def _on_vaccinations_updated(self, **kwargs):
1076 return 1
1077 # FIXME: 1078 # if has_focus: 1079 # wxCallAfter(self.__reset_ui_content) 1080 # else: 1081 # is_stale == True 1082 # return 1 1083 #====================================================================== 1084 # main 1085 #---------------------------------------------------------------------- 1086 if __name__ == "__main__": 1087 1088 if len(sys.argv) < 2: 1089 sys.exit() 1090 1091 if sys.argv[1] != u'test': 1092 sys.exit() 1093 1094 app = wxPyWidgetTester(size = (600, 600)) 1095 app.SetWidget(cImmunisationsPanel, -1) 1096 app.MainLoop() 1097 #====================================================================== 1098