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  __author__ = "R.Terry, S.J.Tan, K.Hilbert" 
   9  __license__ = "GPL v2 or later (details at http://www.gnu.org)" 
  10   
  11  import sys 
  12  import logging 
  13   
  14   
  15  import wx 
  16   
  17   
  18  if __name__ == '__main__': 
  19          sys.path.insert(0, '../../') 
  20  from Gnumed.pycommon import gmDispatcher 
  21  from Gnumed.pycommon import gmMatchProvider 
  22  from Gnumed.pycommon import gmTools 
  23  from Gnumed.pycommon import gmI18N 
  24  from Gnumed.pycommon import gmCfg 
  25  from Gnumed.pycommon import gmCfg2 
  26  from Gnumed.pycommon import gmDateTime 
  27  from Gnumed.pycommon import gmNetworkTools 
  28  from Gnumed.pycommon import gmPrinting 
  29  from Gnumed.pycommon import gmPG2 
  30   
  31  from Gnumed.business import gmPerson 
  32  from Gnumed.business import gmVaccination 
  33  from Gnumed.business import gmPraxis 
  34  from Gnumed.business import gmProviderInbox 
  35   
  36  from Gnumed.wxpython import gmPhraseWheel 
  37  from Gnumed.wxpython import gmTerryGuiParts 
  38  from Gnumed.wxpython import gmRegetMixin 
  39  from Gnumed.wxpython import gmGuiHelpers 
  40  from Gnumed.wxpython import gmEditArea 
  41  from Gnumed.wxpython import gmListWidgets 
  42  from Gnumed.wxpython import gmFormWidgets 
  43  from Gnumed.wxpython import gmMacro 
  44  from Gnumed.wxpython import gmAuthWidgets 
  45  from Gnumed.wxpython import gmSubstanceMgmtWidgets 
  46   
  47   
  48  _log = logging.getLogger('gm.vacc') 
  49   
  50  #====================================================================== 
  51  # vaccine related widgets 
  52  #---------------------------------------------------------------------- 
53 -def regenerate_generic_vaccines():
54 55 dbo_conn = gmAuthWidgets.get_dbowner_connection(procedure = _('Regenerating generic vaccines')) 56 if dbo_conn is None: 57 return False 58 59 wx.BeginBusyCursor() 60 _cfg = gmCfg2.gmCfgData() 61 sql_script = gmVaccination.write_generic_vaccine_sql ( 62 'client-%s' % _cfg.get(option = 'client_version'), 63 include_indications_mapping = False 64 ) 65 _log.debug('regenerating generic vaccines, SQL script: %s', sql_script) 66 if not gmPG2.run_sql_script(sql_script, conn = dbo_conn): 67 wx.EndBusyCursor() 68 gmGuiHelpers.gm_show_warning ( 69 aMessage = _('Error regenerating generic vaccines.\n\nSee [%s]') % sql_script, 70 aTitle = _('Regenerating generic vaccines') 71 ) 72 return False 73 74 gmDispatcher.send(signal = 'statustext', msg = _('Successfully regenerated generic vaccines ...'), beep = False) 75 wx.EndBusyCursor() 76 return True
77 78 #----------------------------------------------------------------------
79 -def edit_vaccine(parent=None, vaccine=None, single_entry=True):
80 ea = cVaccineEAPnl(parent, -1) 81 ea.data = vaccine 82 ea.mode = gmTools.coalesce(vaccine, 'new', 'edit') 83 dlg = gmEditArea.cGenericEditAreaDlg2(parent, -1, edit_area = ea, single_entry = single_entry) 84 dlg.SetTitle(gmTools.coalesce(vaccine, _('Adding new vaccine'), _('Editing vaccine'))) 85 if dlg.ShowModal() == wx.ID_OK: 86 dlg.DestroyLater() 87 return True 88 dlg.DestroyLater() 89 return False
90 91 #----------------------------------------------------------------------
92 -def manage_vaccines(parent=None):
93 94 if parent is None: 95 parent = wx.GetApp().GetTopWindow() 96 97 # #------------------------------------------------------------ 98 # def delete(vaccine=None): 99 # product = vaccine.product 100 # deleted = gmVaccination.delete_vaccine(vaccine = vaccine['pk_vaccine']) 101 # if not deleted: 102 # gmGuiHelpers.gm_show_info ( 103 # _( 'Cannot delete vaccine\n' 104 # '\n' 105 # ' %s - %s (#%s)\n' 106 # '\n' 107 # 'It is probably documented in a vaccination.' 108 # ) % ( 109 # vaccine['vaccine'], 110 # vaccine['l10n_preparation'], 111 # vaccine['pk_vaccine'] 112 # ), 113 # _('Deleting vaccine') 114 # ) 115 # return False 116 # delete_product = gmGuiHelpers.gm_show_question ( 117 # title = _('Deleting vaccine'), 118 # question = _( 119 # u'Fully delete the vaccine (including the associated drug product) ?\n' 120 # u'\n' 121 # u' "%s" (%s)' 122 # ) % (product['product'], product['l10n_preparation']) 123 # ) 124 # if delete_product: 125 # pass 126 # return True 127 128 #------------------------------------------------------------ 129 def manage_drug_products(vaccine): 130 gmSubstanceMgmtWidgets.manage_drug_products(parent = parent) 131 return True
132 133 #------------------------------------------------------------ 134 def edit(vaccine=None): 135 return edit_vaccine(parent = parent, vaccine = vaccine, single_entry = True) 136 137 #------------------------------------------------------------ 138 def get_tooltip(vaccine): 139 if vaccine is None: 140 return None 141 return '\n'.join(vaccine.format()) 142 143 #------------------------------------------------------------ 144 def refresh(lctrl): 145 vaccines = gmVaccination.get_vaccines(order_by = 'vaccine') 146 147 items = [ [ 148 '%s' % v['pk_drug_product'], 149 '%s%s' % ( 150 v['vaccine'], 151 gmTools.bool2subst ( 152 v['is_fake_vaccine'], 153 ' (%s)' % _('fake'), 154 '' 155 ) 156 ), 157 v['l10n_preparation'], 158 gmTools.coalesce(v['atc_code'], ''), 159 '%s - %s' % ( 160 gmTools.coalesce(v['min_age'], '?'), 161 gmTools.coalesce(v['max_age'], '?'), 162 ), 163 gmTools.coalesce(v['comment'], '') 164 ] for v in vaccines ] 165 lctrl.set_string_items(items) 166 lctrl.set_data(vaccines) 167 168 #------------------------------------------------------------ 169 gmListWidgets.get_choices_from_list ( 170 parent = parent, 171 caption = _('Showing vaccine details'), 172 columns = [ '#', _('Vaccine'), _('Preparation'), _('ATC'), _('Age range'), _('Comment') ], 173 single_selection = True, 174 refresh_callback = refresh, 175 edit_callback = edit, 176 new_callback = edit, 177 #delete_callback = delete, 178 list_tooltip_callback = get_tooltip, 179 left_extra_button = (_('Products'), _('Manage drug products'), manage_drug_products) 180 ) 181 182 #----------------------------------------------------------------------
183 -class cBatchNoPhraseWheel(gmPhraseWheel.cPhraseWheel):
184
185 - def __init__(self, *args, **kwargs):
186 187 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 188 189 context = { 190 'ctxt_vaccine': { 191 'where_part': 'AND pk_vaccine = %(pk_vaccine)s', 192 'placeholder': 'pk_vaccine' 193 } 194 } 195 196 query = """ 197 SELECT data, field_label, list_label FROM ( 198 199 SELECT distinct on (field_label) 200 data, 201 field_label, 202 list_label, 203 rank 204 FROM (( 205 -- batch_no by vaccine 206 SELECT 207 batch_no AS data, 208 batch_no AS field_label, 209 batch_no || ' (' || vaccine || ')' AS list_label, 210 1 as rank 211 FROM 212 clin.v_vaccinations 213 WHERE 214 batch_no %(fragment_condition)s 215 %(ctxt_vaccine)s 216 ) UNION ALL ( 217 -- batch_no for any vaccine 218 SELECT 219 batch_no AS data, 220 batch_no AS field_label, 221 batch_no || ' (' || vaccine || ')' AS list_label, 222 2 AS rank 223 FROM 224 clin.v_vaccinations 225 WHERE 226 batch_no %(fragment_condition)s 227 ) 228 229 ) AS matching_batch_nos 230 231 ) as unique_matches 232 233 ORDER BY rank, list_label 234 LIMIT 25 235 """ 236 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query, context = context) 237 mp.setThresholds(1, 2, 3) 238 self.matcher = mp 239 240 self.unset_context(context = 'pk_vaccine') 241 self.SetToolTip(_('Enter or select the batch/lot number of the vaccine used.')) 242 self.selection_only = False
243 244 #----------------------------------------------------------------------
245 -class cVaccinePhraseWheel(gmPhraseWheel.cPhraseWheel):
246
247 - def __init__(self, *args, **kwargs):
248 249 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 250 251 # consider ATCs in ref.drug_product and ref.vacc_indication 252 query = """ 253 SELECT data, list_label, field_label FROM ( 254 255 SELECT DISTINCT ON (data) 256 data, 257 list_label, 258 field_label 259 FROM (( 260 -- fragment -> vaccine 261 SELECT 262 r_v_v.pk_vaccine 263 AS data, 264 r_v_v.vaccine || ' (' 265 || (SELECT string_agg(l10n_inds.ind_desc::text, ', ') FROM ( 266 SELECT unnest(r_v_v.indications)->>'l10n_indication' AS ind_desc 267 ) AS l10n_inds) 268 || ')' 269 AS list_label, 270 r_v_v.vaccine 271 AS field_label 272 FROM 273 ref.v_vaccines r_v_v 274 WHERE 275 r_v_v.vaccine %(fragment_condition)s 276 277 ) union all ( 278 279 -- fragment -> localized indication -> vaccines 280 SELECT 281 r_vi4v.pk_vaccine 282 AS data, 283 r_vi4v.vaccine || ' (' 284 || (SELECT string_agg(l10n_inds.ind_desc::text, ', ') FROM ( 285 SELECT unnest(r_vi4v.indications)->>'l10n_indication' AS ind_desc 286 ) AS l10n_inds) 287 || ')' 288 AS list_label, 289 r_vi4v.vaccine 290 AS field_label 291 FROM 292 ref.v_indications4vaccine r_vi4v 293 WHERE 294 r_vi4v.l10n_indication %(fragment_condition)s 295 296 ) union all ( 297 298 -- fragment -> indication -> vaccines 299 SELECT 300 r_vi4v.pk_vaccine 301 AS data, 302 r_vi4v.vaccine || ' (' 303 || (SELECT string_agg(l10n_inds.ind_desc::text, ', ') FROM ( 304 SELECT unnest(r_vi4v.indications)->>'l10n_indication' AS ind_desc 305 ) AS l10n_inds) 306 || ')' 307 AS list_label, 308 r_vi4v.vaccine 309 AS field_label 310 FROM 311 ref.v_indications4vaccine r_vi4v 312 WHERE 313 r_vi4v.indication %(fragment_condition)s 314 ) 315 ) AS distinct_total 316 317 ) AS total 318 319 ORDER by list_label 320 LIMIT 25 321 """ 322 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query) 323 mp.setThresholds(1, 2, 3) 324 self.matcher = mp 325 326 self.selection_only = True
327 #------------------------------------------------------------------
328 - def _data2instance(self):
329 return gmVaccination.cVaccine(aPK_obj = self.GetData())
330 331 #---------------------------------------------------------------------- 332 from Gnumed.wxGladeWidgets import wxgVaccineEAPnl 333
334 -class cVaccineEAPnl(wxgVaccineEAPnl.wxgVaccineEAPnl, gmEditArea.cGenericEditAreaMixin):
335
336 - def __init__(self, *args, **kwargs):
337 try: 338 data = kwargs['vaccine'] 339 del kwargs['vaccine'] 340 except KeyError: 341 data = None 342 343 wxgVaccineEAPnl.wxgVaccineEAPnl.__init__(self, *args, **kwargs) 344 gmEditArea.cGenericEditAreaMixin.__init__(self) 345 346 self.mode = 'new' 347 self.data = data 348 if data is not None: 349 self.mode = 'edit' 350 351 self.__indications = None
352 353 #----------------------------------------------------------------
354 - def __refresh_indications(self):
355 self._TCTRL_indications.SetValue('') 356 if self.data is None: 357 return 358 self._TCTRL_indications.SetValue('- ' + '\n- '.join([ i['l10n_indication'] for i in self.data['indications'] ]))
359 360 #---------------------------------------------------------------- 361 # generic Edit Area mixin API 362 #----------------------------------------------------------------
363 - def _valid_for_save(self):
364 365 has_errors = False 366 367 if self._PRW_drug_product.GetValue().strip() == '': 368 has_errors = True 369 self._PRW_drug_product.display_as_valid(False) 370 else: 371 self._PRW_drug_product.display_as_valid(True) 372 373 atc = self._PRW_atc.GetValue().strip() 374 if (atc == '') or (atc.startswith('J07')): 375 self._PRW_atc.display_as_valid(True) 376 else: 377 if self._PRW_atc.GetData() is None: 378 self._PRW_atc.display_as_valid(True) 379 else: 380 has_errors = True 381 self._PRW_atc.display_as_valid(False) 382 383 val = self._PRW_age_min.GetValue().strip() 384 if val == '': 385 self._PRW_age_min.display_as_valid(True) 386 else: 387 if gmDateTime.str2interval(val) is None: 388 has_errors = True 389 self._PRW_age_min.display_as_valid(False) 390 else: 391 self._PRW_age_min.display_as_valid(True) 392 393 val = self._PRW_age_max.GetValue().strip() 394 if val == '': 395 self._PRW_age_max.display_as_valid(True) 396 else: 397 if gmDateTime.str2interval(val) is None: 398 has_errors = True 399 self._PRW_age_max.display_as_valid(False) 400 else: 401 self._PRW_age_max.display_as_valid(True) 402 403 # complex conditions 404 # are we editing ? 405 if self.mode == 'edit': 406 change_of_product = self.data['pk_drug_product'] != self._PRW_drug_product.GetData() 407 if change_of_product and self.data.is_in_use: 408 do_it = gmGuiHelpers.gm_show_question ( 409 aTitle = _('Saving vaccine'), 410 aMessage = _( 411 'This vaccine is already in use:\n' 412 '\n' 413 ' "%s"\n' 414 '\n' 415 'Are you absolutely positively sure that\n' 416 'you really want to edit this vaccine ?\n' 417 '\n' 418 'This will change the vaccine name and/or target\n' 419 'conditions in each patient this vaccine was\n' 420 'used in to document a vaccination with.\n' 421 ) % self._PRW_drug_product.GetValue().strip() 422 ) 423 if not do_it: 424 has_errors = True 425 else: 426 if self._PRW_drug_product.GetData() is None: 427 # need to ask for indications ? 428 if self._PRW_drug_product.GetValue().strip() != '': 429 self.__indications = gmSubstanceMgmtWidgets.manage_substance_doses(vaccine_indications_only = True) 430 if self.__indications is None: 431 has_errors = True 432 else: 433 # existing drug product selected 434 pass 435 436 return (has_errors is False)
437 438 #----------------------------------------------------------------
439 - def _save_as_new(self):
440 441 # save the data as a new instance 442 vaccine = gmVaccination.create_vaccine ( 443 pk_drug_product = self._PRW_drug_product.GetData(), 444 product_name = self._PRW_drug_product.GetValue().strip(), 445 indications = self.__indications, 446 is_live = self._CHBOX_live.GetValue() 447 ) 448 val = self._PRW_age_min.GetValue().strip() 449 if val != '': 450 vaccine['min_age'] = gmDateTime.str2interval(val) 451 val = self._PRW_age_max.GetValue().strip() 452 if val != '': 453 vaccine['max_age'] = gmDateTime.str2interval(val) 454 val = self._TCTRL_comment.GetValue().strip() 455 if val != '': 456 vaccine['comment'] = val 457 vaccine.save() 458 459 drug = vaccine.product 460 drug['is_fake_product'] = self._CHBOX_fake.GetValue() 461 val = self._PRW_atc.GetData() 462 if val is not None: 463 if val != 'J07': 464 drug['atc'] = val.strip() 465 drug.save() 466 467 # must be done very late or else the property access 468 # will refresh the display such that later field 469 # access will return empty values 470 self.data = vaccine 471 472 return True
473 474 #----------------------------------------------------------------
475 - def _save_as_update(self):
476 477 drug = self.data.product 478 drug['product'] = self._PRW_drug_product.GetValue().strip() 479 drug['is_fake_product'] = self._CHBOX_fake.GetValue() 480 val = self._PRW_atc.GetData() 481 if val is not None: 482 if val != 'J07': 483 drug['atc'] = val.strip() 484 drug.save() 485 486 self.data['is_live'] = self._CHBOX_live.GetValue() 487 val = self._PRW_age_min.GetValue().strip() 488 if val != '': 489 self.data['min_age'] = gmDateTime.str2interval(val) 490 if val != '': 491 self.data['max_age'] = gmDateTime.str2interval(val) 492 val = self._TCTRL_comment.GetValue().strip() 493 if val != '': 494 self.data['comment'] = val 495 self.data.save() 496 497 return True
498 499 #----------------------------------------------------------------
500 - def _refresh_as_new(self):
501 self._PRW_drug_product.SetText(value = '', data = None, suppress_smarts = True) 502 self._CHBOX_live.SetValue(False) 503 self._CHBOX_fake.SetValue(False) 504 self._PRW_atc.SetText(value = '', data = None, suppress_smarts = True) 505 self._PRW_age_min.SetText(value = '', data = None, suppress_smarts = True) 506 self._PRW_age_max.SetText(value = '', data = None, suppress_smarts = True) 507 self._TCTRL_comment.SetValue('') 508 509 self.__refresh_indications() 510 511 self._PRW_drug_product.SetFocus()
512 513 #----------------------------------------------------------------
514 - def _refresh_from_existing(self):
515 self._PRW_drug_product.SetText(value = self.data['vaccine'], data = self.data['pk_drug_product']) 516 self._CHBOX_live.SetValue(self.data['is_live']) 517 self._CHBOX_fake.SetValue(self.data['is_fake_vaccine']) 518 self._PRW_atc.SetText(value = self.data['atc_code'], data = self.data['atc_code']) 519 if self.data['min_age'] is None: 520 self._PRW_age_min.SetText(value = '', data = None, suppress_smarts = True) 521 else: 522 self._PRW_age_min.SetText ( 523 value = gmDateTime.format_interval(self.data['min_age'], gmDateTime.acc_years), 524 data = self.data['min_age'] 525 ) 526 if self.data['max_age'] is None: 527 self._PRW_age_max.SetText(value = '', data = None, suppress_smarts = True) 528 else: 529 self._PRW_age_max.SetText ( 530 value = gmDateTime.format_interval(self.data['max_age'], gmDateTime.acc_years), 531 data = self.data['max_age'] 532 ) 533 self._TCTRL_comment.SetValue(gmTools.coalesce(self.data['comment'], '')) 534 535 self.__refresh_indications() 536 537 self._PRW_drug_product.SetFocus()
538 539 #----------------------------------------------------------------
541 self._refresh_as_new()
542 543 #====================================================================== 544 # vaccination related widgets 545 #----------------------------------------------------------------------
546 -def configure_adr_url():
547 548 def is_valid(value): 549 value = value.strip() 550 if value == '': 551 return True, gmVaccination.URL_vaccine_adr_german_default 552 try: 553 urllib.request.urlopen(value) 554 return True, value 555 except Exception: # FIXME: more specific 556 return True, value
557 558 gmCfgWidgets.configure_string_option ( 559 message = _( 560 'GNUmed will use this URL to access a website which lets\n' 561 'you report an adverse vaccination reaction (vADR).\n' 562 '\n' 563 'If you set it to a specific address that URL must be\n' 564 'accessible now. If you leave it empty it will fall back\n' 565 'to the URL for reporting other adverse drug reactions.' 566 ), 567 option = 'external.urls.report_vaccine_ADR', 568 bias = 'user', 569 default_value = gmVaccination.URL_vaccine_adr_german_default, 570 validator = is_valid 571 ) 572 573 #----------------------------------------------------------------------
574 -def configure_vaccination_plans_url():
575 576 def is_valid(value): 577 value = value.strip() 578 if value == '': 579 return True, gmVaccination.URL_vaccination_plan 580 try: 581 urllib.request.urlopen(value) 582 return True, value 583 except Exception: # FIXME: more specific 584 return True, value
585 586 gmCfgWidgets.configure_string_option ( 587 message = _( 588 'GNUmed will use this URL to access a page showing\n' 589 'vaccination schedules.\n' 590 '\n' 591 'You can leave this empty but to set it to a specific\n' 592 'address the URL must be accessible now.' 593 ), 594 option = 'external.urls.vaccination_plans', 595 bias = 'user', 596 default_value = gmVaccination.URL_vaccination_plan, 597 validator = is_valid 598 ) 599 600 #---------------------------------------------------------------------- 627 628 #----------------------------------------------------------------------
629 -def edit_vaccination(parent=None, vaccination=None, single_entry=True):
630 ea = cVaccinationEAPnl(parent, -1) 631 ea.data = vaccination 632 ea.mode = gmTools.coalesce(vaccination, 'new', 'edit') 633 dlg = gmEditArea.cGenericEditAreaDlg2(parent, -1, edit_area = ea, single_entry = single_entry) 634 dlg.SetTitle(gmTools.coalesce(vaccination, _('Adding new vaccinations'), _('Editing vaccination'))) 635 if dlg.ShowModal() == wx.ID_OK: 636 dlg.DestroyLater() 637 return True 638 dlg.DestroyLater() 639 if not single_entry: 640 return True 641 return False
642 643 #----------------------------------------------------------------------
644 -def manage_vaccinations(parent=None, latest_only=False, expand_indications=False):
645 646 pat = gmPerson.gmCurrentPatient() 647 emr = pat.emr 648 649 if parent is None: 650 parent = wx.GetApp().GetTopWindow() 651 652 #------------------------------------------------------------ 653 def browse2schedules(vaccination=None): 654 dbcfg = gmCfg.cCfgSQL() 655 url = dbcfg.get2 ( 656 option = 'external.urls.vaccination_plans', 657 workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace, 658 bias = 'user', 659 default = gmVaccination.URL_vaccination_plan 660 ) 661 662 gmNetworkTools.open_url_in_browser(url = url) 663 return False
664 665 #------------------------------------------------------------ 666 def print_vaccs(vaccination=None): 667 print_vaccinations(parent = parent) 668 return False 669 670 #------------------------------------------------------------ 671 def add_recall(vaccination=None): 672 if vaccination is None: 673 subject = _('vaccination recall') 674 else: 675 subject = _('vaccination recall (%s)') % vaccination['vaccine'] 676 677 recall = gmProviderInbox.create_inbox_message ( 678 message_type = _('Vaccination'), 679 subject = subject, 680 patient = pat.ID, 681 staff = None 682 ) 683 684 if vaccination is not None: 685 recall['data'] = _('Existing vaccination:\n\n%s') % '\n'.join(vaccination.format( 686 with_indications = True, 687 with_comment = True, 688 with_reaction = False, 689 date_format = '%Y %b %d' 690 )) 691 recall.save() 692 693 from Gnumed.wxpython import gmProviderInboxWidgets 694 gmProviderInboxWidgets.edit_inbox_message ( 695 parent = parent, 696 message = recall, 697 single_entry = False 698 ) 699 700 return False 701 702 #------------------------------------------------------------ 703 def get_tooltip(vaccination): 704 if vaccination is None: 705 return None 706 return '\n'.join(vaccination.format ( 707 with_indications = True, 708 with_comment = True, 709 with_reaction = True, 710 date_format = '%Y %b %d' 711 )) 712 713 #------------------------------------------------------------ 714 def edit(vaccination=None): 715 return edit_vaccination(parent = parent, vaccination = vaccination, single_entry = (vaccination is not None)) 716 717 #------------------------------------------------------------ 718 def delete(vaccination=None): 719 gmVaccination.delete_vaccination(vaccination = vaccination['pk_vaccination']) 720 return True 721 722 #------------------------------------------------------------ 723 def refresh(lctrl): 724 725 items = [] 726 data = [] 727 if latest_only: 728 latest_vaccs = emr.get_latest_vaccinations() 729 for indication in sorted(latest_vaccs): 730 no_of_shots4ind, latest_vacc4ind = latest_vaccs[indication] 731 items.append ([ 732 indication, 733 _('%s (latest of %s: %s ago)') % ( 734 gmDateTime.pydt_strftime(latest_vacc4ind['date_given'], format = '%Y %b'), 735 no_of_shots4ind, 736 gmDateTime.format_interval_medically(gmDateTime.pydt_now_here() - latest_vacc4ind['date_given']) 737 ), 738 latest_vacc4ind['vaccine'], 739 latest_vacc4ind['batch_no'], 740 gmTools.coalesce(latest_vacc4ind['site'], ''), 741 gmTools.coalesce(latest_vacc4ind['reaction'], ''), 742 gmTools.coalesce(latest_vacc4ind['comment'], '') 743 ]) 744 data.append(latest_vacc4ind) 745 else: 746 shots = emr.get_vaccinations(order_by = 'date_given DESC, pk_vaccination') 747 if expand_indications: 748 shots_by_ind = {} 749 for shot in shots: 750 for ind in shot['indications']: 751 try: 752 shots_by_ind[ind['l10n_indication']].append(shot) 753 except KeyError: 754 shots_by_ind[ind['l10n_indication']] = [shot] 755 for ind in sorted(shots_by_ind): 756 idx = len(shots_by_ind[ind]) 757 for shot in shots_by_ind[ind]: 758 items.append ([ 759 '%s (#%s)' % (ind, idx), 760 _('%s (%s ago)') % ( 761 gmDateTime.pydt_strftime(shot['date_given'], '%Y %b %d'), 762 gmDateTime.format_interval_medically(gmDateTime.pydt_now_here() - shot['date_given']) 763 ), 764 shot['vaccine'], 765 shot['batch_no'], 766 gmTools.coalesce(shot['site'], ''), 767 gmTools.coalesce(shot['reaction'], ''), 768 gmTools.coalesce(shot['comment'], '') 769 ]) 770 idx -= 1 771 data.append(shot) 772 else: 773 items = [ [ 774 gmDateTime.pydt_strftime(s['date_given'], '%Y %b %d'), 775 s['vaccine'], 776 ', '.join([ i['l10n_indication'] for i in s['indications'] ]), 777 s['batch_no'], 778 gmTools.coalesce(s['site'], ''), 779 gmTools.coalesce(s['reaction'], ''), 780 gmTools.coalesce(s['comment'], '') 781 ] for s in shots ] 782 data = shots 783 784 lctrl.set_string_items(items) 785 lctrl.set_data(data) 786 787 #------------------------------------------------------------ 788 if latest_only: 789 msg = _('Most recent vaccination for each indication.\n') 790 cols = [ _('Indication'), _('Date'), _('Vaccine'), _('Batch'), _('Site'), _('Reaction'), _('Comment') ] 791 else: 792 if expand_indications: 793 msg = _('Complete vaccination history (per indication).\n') 794 cols = [ _('Indication'), _('Date'), _('Vaccine'), _('Batch'), _('Site'), _('Reaction'), _('Comment') ] 795 else: 796 msg = _('Complete vaccination history (by shot).\n') 797 cols = [ _('Date'), _('Vaccine'), _('Intended to protect from'), _('Batch'), _('Site'), _('Reaction'), _('Comment') ] 798 799 gmListWidgets.get_choices_from_list ( 800 parent = parent, 801 msg = msg, 802 caption = _('Showing vaccinations.'), 803 columns = cols, 804 single_selection = True, 805 refresh_callback = refresh, 806 new_callback = edit, 807 edit_callback = edit, 808 delete_callback = delete, 809 list_tooltip_callback = get_tooltip, 810 left_extra_button = (_('Print'), _('Print vaccinations or recalls.'), print_vaccs), 811 middle_extra_button = (_('Recall'), _('Add a recall for a vaccination'), add_recall), 812 right_extra_button = (_('Vx schedules'), _('Open a browser showing vaccination schedules.'), browse2schedules) 813 ) 814 815 #---------------------------------------------------------------------- 816 from Gnumed.wxGladeWidgets import wxgVaccinationEAPnl 817
818 -class cVaccinationEAPnl(wxgVaccinationEAPnl.wxgVaccinationEAPnl, gmEditArea.cGenericEditAreaMixin):
819 """ 820 - warn on apparent duplicates 821 - ask if "missing" (= previous, non-recorded) vaccinations 822 should be estimated and saved (add note "auto-generated") 823 824 Batch No (http://www.fao.org/docrep/003/v9952E12.htm) 825 """
826 - def __init__(self, *args, **kwargs):
827 828 try: 829 data = kwargs['vaccination'] 830 del kwargs['vaccination'] 831 except KeyError: 832 data = None 833 834 wxgVaccinationEAPnl.wxgVaccinationEAPnl.__init__(self, *args, **kwargs) 835 gmEditArea.cGenericEditAreaMixin.__init__(self) 836 837 self.mode = 'new' 838 self.data = data 839 if data is not None: 840 self.mode = 'edit' 841 842 self.__init_ui()
843 844 #----------------------------------------------------------------
845 - def __init_ui(self):
846 # adjust phrasewheels etc 847 self._PRW_vaccine.add_callback_on_lose_focus(self._on_PRW_vaccine_lost_focus) 848 self._PRW_provider.selection_only = False 849 self._PRW_reaction.add_callback_on_lose_focus(self._on_PRW_reaction_lost_focus)
850 851 #----------------------------------------------------------------
852 - def _on_PRW_vaccine_lost_focus(self):
853 854 vaccine = self._PRW_vaccine.GetData(as_instance=True) 855 856 if self.mode == 'edit': 857 if vaccine is None: 858 self._PRW_batch.unset_context(context = 'pk_vaccine') 859 else: 860 self._PRW_batch.set_context(context = 'pk_vaccine', val = vaccine['pk_vaccine']) 861 # we are entering a new vaccination 862 else: 863 if vaccine is None: 864 self._PRW_batch.unset_context(context = 'pk_vaccine') 865 else: 866 self._PRW_batch.set_context(context = 'pk_vaccine', val = vaccine['pk_vaccine']) 867 868 self.__refresh_indications()
869 870 #----------------------------------------------------------------
872 if self._PRW_reaction.GetValue().strip() == '': 873 self._BTN_report.Enable(False) 874 else: 875 self._BTN_report.Enable(True)
876 877 #----------------------------------------------------------------
878 - def __refresh_indications(self):
879 self._TCTRL_indications.SetValue('') 880 vaccine = self._PRW_vaccine.GetData(as_instance = True) 881 if vaccine is None: 882 return 883 lines = [] 884 emr = gmPerson.gmCurrentPatient().emr 885 latest_vaccs = emr.get_latest_vaccinations ( 886 atc_indications = [ i['atc_indication'] for i in vaccine['indications'] ] 887 ) 888 for l10n_ind in [ i['l10n_indication'] for i in vaccine['indications'] ]: 889 try: 890 no_of_shots4ind, latest_vacc4ind = latest_vaccs[l10n_ind] 891 ago = gmDateTime.format_interval_medically(gmDateTime.pydt_now_here() - latest_vacc4ind['date_given']) 892 lines.append(_('%s (most recent shot of %s: %s ago)') % (l10n_ind, no_of_shots4ind, ago)) 893 except KeyError: 894 lines.append(_('%s (no previous vaccination recorded)') % l10n_ind) 895 896 self._TCTRL_indications.SetValue(_('Protects against:\n ') + '\n '.join(lines))
897 898 #---------------------------------------------------------------- 899 # generic Edit Area mixin API 900 #----------------------------------------------------------------
901 - def _valid_for_save(self):
902 903 has_errors = False 904 905 if not self._PRW_date_given.is_valid_timestamp(empty_is_valid = False): 906 has_errors = True 907 908 vaccine = self._PRW_vaccine.GetData(as_instance = True) 909 if vaccine is None: 910 has_errors = True 911 self._PRW_vaccine.display_as_valid(False) 912 else: 913 self._PRW_vaccine.display_as_valid(True) 914 915 if self._PRW_batch.GetValue().strip() == '': 916 has_errors = True 917 self._PRW_batch.display_as_valid(False) 918 else: 919 self._PRW_batch.display_as_valid(True) 920 921 if self._PRW_episode.GetValue().strip() == '': 922 self._PRW_episode.SetText(value = _('prevention')) 923 924 return (has_errors is False)
925 926 #----------------------------------------------------------------
927 - def _save_as_new(self):
928 929 vaccine = self._PRW_vaccine.GetData() 930 data = self.__save_new_from_vaccine(vaccine = vaccine) 931 932 # must be done very late or else the property access 933 # will refresh the display such that later field 934 # access will return empty values 935 self.data = data 936 937 return True
938 939 #----------------------------------------------------------------
940 - def __save_new_from_vaccine(self, vaccine=None):
941 942 emr = gmPerson.gmCurrentPatient().emr 943 944 data = emr.add_vaccination ( 945 episode = self._PRW_episode.GetData(can_create = True, is_open = False), 946 vaccine = vaccine, 947 batch_no = self._PRW_batch.GetValue().strip() 948 ) 949 950 if self._CHBOX_anamnestic.GetValue() is True: 951 data['soap_cat'] = 's' 952 else: 953 data['soap_cat'] = 'p' 954 955 data['date_given'] = self._PRW_date_given.GetData() 956 data['site'] = self._PRW_site.GetValue().strip() 957 data['pk_provider'] = self._PRW_provider.GetData() 958 data['reaction'] = self._PRW_reaction.GetValue().strip() 959 data['comment'] = self._TCTRL_comment.GetValue().strip() 960 961 data.save() 962 963 return data
964 965 #----------------------------------------------------------------
966 - def _save_as_update(self):
967 968 if self._CHBOX_anamnestic.GetValue() is True: 969 self.data['soap_cat'] = 's' 970 else: 971 self.data['soap_cat'] = 'p' 972 973 self.data['date_given'] = self._PRW_date_given.GetData() 974 self.data['pk_vaccine'] = self._PRW_vaccine.GetData() 975 self.data['batch_no'] = self._PRW_batch.GetValue().strip() 976 self.data['pk_episode'] = self._PRW_episode.GetData(can_create = True, is_open = False) 977 self.data['site'] = self._PRW_site.GetValue().strip() 978 self.data['pk_provider'] = self._PRW_provider.GetData() 979 self.data['reaction'] = self._PRW_reaction.GetValue().strip() 980 self.data['comment'] = self._TCTRL_comment.GetValue().strip() 981 982 self.data.save() 983 984 return True
985 986 #----------------------------------------------------------------
987 - def _refresh_as_new(self):
988 self._PRW_date_given.SetText(data = gmDateTime.pydt_now_here()) 989 self._CHBOX_anamnestic.SetValue(False) 990 self._PRW_vaccine.SetText(value = '', data = None, suppress_smarts = True) 991 self._PRW_batch.unset_context(context = 'pk_vaccine') 992 self._PRW_batch.SetValue('') 993 self._PRW_episode.SetText(value = '', data = None, suppress_smarts = True) 994 self._PRW_site.SetValue('') 995 self._PRW_provider.SetData(data = None) 996 self._PRW_reaction.SetText(value = '', data = None, suppress_smarts = True) 997 self._BTN_report.Enable(False) 998 self._TCTRL_comment.SetValue('') 999 1000 self.__refresh_indications() 1001 1002 self._PRW_date_given.SetFocus()
1003 1004 #----------------------------------------------------------------
1005 - def _refresh_from_existing(self):
1006 self._PRW_date_given.SetText(data = self.data['date_given']) 1007 if self.data['soap_cat'] == 's': 1008 self._CHBOX_anamnestic.SetValue(True) 1009 else: 1010 self._CHBOX_anamnestic.SetValue(False) 1011 self._PRW_vaccine.SetText(value = self.data['vaccine'], data = self.data['pk_vaccine']) 1012 1013 self._PRW_batch.SetValue(self.data['batch_no']) 1014 self._PRW_episode.SetData(data = self.data['pk_episode']) 1015 self._PRW_site.SetValue(gmTools.coalesce(self.data['site'], '')) 1016 self._PRW_provider.SetData(self.data['pk_provider']) 1017 self._PRW_reaction.SetValue(gmTools.coalesce(self.data['reaction'], '')) 1018 if self.data['reaction'] is None: 1019 self._BTN_report.Enable(False) 1020 else: 1021 self._BTN_report.Enable(True) 1022 self._TCTRL_comment.SetValue(gmTools.coalesce(self.data['comment'], '')) 1023 1024 self.__refresh_indications() 1025 1026 self._PRW_date_given.SetFocus()
1027 1028 #----------------------------------------------------------------
1030 self._PRW_date_given.SetText(data = self.data['date_given']) 1031 #self._CHBOX_anamnestic.SetValue(False) 1032 self._PRW_vaccine.SetText(value = self.data['vaccine'], data = self.data['pk_vaccine']) 1033 1034 self._PRW_batch.set_context(context = 'pk_vaccine', val = self.data['pk_vaccine']) 1035 self._PRW_batch.SetValue('') 1036 1037 self._PRW_episode.SetData(data = self.data['pk_episode']) 1038 self._PRW_site.SetValue(gmTools.coalesce(self.data['site'], '')) 1039 self._PRW_provider.SetData(self.data['pk_provider']) 1040 self._PRW_reaction.SetValue('') 1041 self._BTN_report.Enable(False) 1042 self._TCTRL_comment.SetValue('') 1043 1044 self.__refresh_indications() 1045 1046 self._PRW_date_given.SetFocus()
1047 1048 #---------------------------------------------------------------- 1049 # event handlers 1050 #----------------------------------------------------------------
1051 - def _on_report_button_pressed(self, event):
1052 event.Skip() 1053 dbcfg = gmCfg.cCfgSQL() 1054 url = dbcfg.get2 ( 1055 option = 'external.urls.report_vaccine_ADR', 1056 workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace, 1057 bias = 'user' 1058 ) 1059 if url.strip() == '': 1060 url = dbcfg.get2 ( 1061 option = 'external.urls.report_ADR', 1062 workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace, 1063 bias = 'user' 1064 ) 1065 gmNetworkTools.open_url_in_browser(url = url)
1066 1067 #----------------------------------------------------------------
1068 - def _on_add_vaccine_button_pressed(self, event):
1069 edit_vaccine(parent = self, vaccine = None, single_entry = False)
1070 # FIXME: could set newly generated vaccine here 1071 1072 #====================================================================== 1073 #====================================================================== 1074 #====================================================================== 1075 #======================================================================
1076 -class cImmunisationsPanel(wx.Panel, gmRegetMixin.cRegetOnPaintMixin):
1077
1078 - def __init__(self, parent, id):
1079 wx.Panel.__init__(self, parent, id, wx.DefaultPosition, wx.DefaultSize, wx.RAISED_BORDER) 1080 gmRegetMixin.cRegetOnPaintMixin.__init__(self) 1081 self.__pat = gmPerson.gmCurrentPatient() 1082 # do this here so "import cImmunisationsPanel from gmVaccWidgets" works 1083 self.ID_VaccinatedIndicationsList = wx.NewId() 1084 self.ID_VaccinationsPerRegimeList = wx.NewId() 1085 self.ID_MissingShots = wx.NewId() 1086 self.ID_ActiveSchedules = wx.NewId() 1087 self.__do_layout() 1088 self.__register_interests() 1089 self.__reset_ui_content()
1090 #----------------------------------------------------
1091 - def __do_layout(self):
1092 #----------------------------------------------- 1093 # top part 1094 #----------------------------------------------- 1095 pnl_UpperCaption = gmTerryGuiParts.cHeadingCaption(self, -1, _(" IMMUNISATIONS ")) 1096 self.editarea = cVaccinationEditArea(self, -1, wx.DefaultPosition, wx.DefaultSize, wx.NO_BORDER) 1097 1098 #----------------------------------------------- 1099 # middle part 1100 #----------------------------------------------- 1101 # divider headings below editing area 1102 indications_heading = gmTerryGuiParts.cDividerCaption(self, -1, _("Indications")) 1103 vaccinations_heading = gmTerryGuiParts.cDividerCaption(self, -1, _("Vaccinations")) 1104 schedules_heading = gmTerryGuiParts.cDividerCaption(self, -1, _("Active Schedules")) 1105 szr_MiddleCap = wx.BoxSizer(wx.HORIZONTAL) 1106 szr_MiddleCap.Add(indications_heading, 4, wx.EXPAND) 1107 szr_MiddleCap.Add(vaccinations_heading, 6, wx.EXPAND) 1108 szr_MiddleCap.Add(schedules_heading, 10, wx.EXPAND) 1109 1110 # left list: indications for which vaccinations have been given 1111 self.LBOX_vaccinated_indications = wx.ListBox( 1112 parent = self, 1113 id = self.ID_VaccinatedIndicationsList, 1114 choices = [], 1115 style = wx.LB_HSCROLL | wx.LB_NEEDED_SB | wx.SUNKEN_BORDER 1116 ) 1117 self.LBOX_vaccinated_indications.SetFont(wx.Font(12,wx.SWISS, wx.NORMAL, wx.NORMAL, False, '')) 1118 1119 # right list: when an indication has been selected on the left 1120 # display the corresponding vaccinations on the right 1121 self.LBOX_given_shots = wx.ListBox( 1122 parent = self, 1123 id = self.ID_VaccinationsPerRegimeList, 1124 choices = [], 1125 style = wx.LB_HSCROLL | wx.LB_NEEDED_SB | wx.SUNKEN_BORDER 1126 ) 1127 self.LBOX_given_shots.SetFont(wx.Font(12,wx.SWISS, wx.NORMAL, wx.NORMAL, False, '')) 1128 1129 self.LBOX_active_schedules = wx.ListBox ( 1130 parent = self, 1131 id = self.ID_ActiveSchedules, 1132 choices = [], 1133 style = wx.LB_HSCROLL | wx.LB_NEEDED_SB | wx.SUNKEN_BORDER 1134 ) 1135 self.LBOX_active_schedules.SetFont(wx.Font(12, wx.SWISS, wx.NORMAL, wx.NORMAL, False, '')) 1136 1137 szr_MiddleLists = wx.BoxSizer(wx.HORIZONTAL) 1138 szr_MiddleLists.Add(self.LBOX_vaccinated_indications, 4, wx.EXPAND) 1139 szr_MiddleLists.Add(self.LBOX_given_shots, 6, wx.EXPAND) 1140 szr_MiddleLists.Add(self.LBOX_active_schedules, 10, wx.EXPAND) 1141 1142 #--------------------------------------------- 1143 # bottom part 1144 #--------------------------------------------- 1145 missing_heading = gmTerryGuiParts.cDividerCaption(self, -1, _("Missing Immunisations")) 1146 szr_BottomCap = wx.BoxSizer(wx.HORIZONTAL) 1147 szr_BottomCap.Add(missing_heading, 1, wx.EXPAND) 1148 1149 self.LBOX_missing_shots = wx.ListBox ( 1150 parent = self, 1151 id = self.ID_MissingShots, 1152 choices = [], 1153 style = wx.LB_HSCROLL | wx.LB_NEEDED_SB | wx.SUNKEN_BORDER 1154 ) 1155 self.LBOX_missing_shots.SetFont(wx.Font(12, wx.SWISS, wx.NORMAL, wx.NORMAL, False, '')) 1156 1157 szr_BottomLists = wx.BoxSizer(wx.HORIZONTAL) 1158 szr_BottomLists.Add(self.LBOX_missing_shots, 1, wx.EXPAND) 1159 1160 # alert caption 1161 pnl_AlertCaption = gmTerryGuiParts.cAlertCaption(self, -1, _(' Alerts ')) 1162 1163 #--------------------------------------------- 1164 # add all elements to the main background sizer 1165 #--------------------------------------------- 1166 self.mainsizer = wx.BoxSizer(wx.VERTICAL) 1167 self.mainsizer.Add(pnl_UpperCaption, 0, wx.EXPAND) 1168 self.mainsizer.Add(self.editarea, 6, wx.EXPAND) 1169 self.mainsizer.Add(szr_MiddleCap, 0, wx.EXPAND) 1170 self.mainsizer.Add(szr_MiddleLists, 4, wx.EXPAND) 1171 self.mainsizer.Add(szr_BottomCap, 0, wx.EXPAND) 1172 self.mainsizer.Add(szr_BottomLists, 4, wx.EXPAND) 1173 self.mainsizer.Add(pnl_AlertCaption, 0, wx.EXPAND) 1174 1175 self.SetAutoLayout(True) 1176 self.SetSizer(self.mainsizer) 1177 self.mainsizer.Fit(self)
1178 #----------------------------------------------------
1179 - def __register_interests(self):
1180 # wxPython events 1181 wx.EVT_SIZE(self, self.OnSize) 1182 wx.EVT_LISTBOX(self, self.ID_VaccinatedIndicationsList, self._on_vaccinated_indication_selected) 1183 wx.EVT_LISTBOX_DCLICK(self, self.ID_VaccinationsPerRegimeList, self._on_given_shot_selected) 1184 wx.EVT_LISTBOX_DCLICK(self, self.ID_MissingShots, self._on_missing_shot_selected) 1185 # wx.EVT_RIGHT_UP(self.lb1, self.EvtRightButton) 1186 1187 # client internal signals 1188 gmDispatcher.connect(signal= 'post_patient_selection', receiver=self._schedule_data_reget) 1189 gmDispatcher.connect(signal= 'vaccinations_updated', receiver=self._schedule_data_reget)
1190 #---------------------------------------------------- 1191 # event handlers 1192 #----------------------------------------------------
1193 - def OnSize (self, event):
1194 w, h = event.GetSize() 1195 self.mainsizer.SetDimension (0, 0, w, h)
1196 #----------------------------------------------------
1197 - def _on_given_shot_selected(self, event):
1198 """Paste previously given shot into edit area. 1199 """ 1200 self.editarea.set_data(aVacc=event.GetClientData())
1201 #----------------------------------------------------
1202 - def _on_missing_shot_selected(self, event):
1203 self.editarea.set_data(aVacc = event.GetClientData())
1204 #----------------------------------------------------
1205 - def _on_vaccinated_indication_selected(self, event):
1206 """Update right hand middle list to show vaccinations given for selected indication.""" 1207 ind_list = event.GetEventObject() 1208 selected_item = ind_list.GetSelection() 1209 ind = ind_list.GetClientData(selected_item) 1210 # clear list 1211 self.LBOX_given_shots.Set([]) 1212 emr = self.__pat.emr 1213 shots = emr.get_vaccinations(indications = [ind]) 1214 # FIXME: use Set() for entire array (but problem with client_data) 1215 for shot in shots: 1216 if shot['is_booster']: 1217 marker = 'B' 1218 else: 1219 marker = '#%s' % shot['seq_no'] 1220 label = '%s - %s: %s' % (marker, shot['date'].strftime('%m/%Y'), shot['vaccine']) 1221 self.LBOX_given_shots.Append(label, shot)
1222 #----------------------------------------------------
1223 - def __reset_ui_content(self):
1224 # clear edit area 1225 self.editarea.set_data() 1226 # clear lists 1227 self.LBOX_vaccinated_indications.Clear() 1228 self.LBOX_given_shots.Clear() 1229 self.LBOX_active_schedules.Clear() 1230 self.LBOX_missing_shots.Clear()
1231 #----------------------------------------------------
1232 - def _populate_with_data(self):
1233 # clear lists 1234 self.LBOX_vaccinated_indications.Clear() 1235 self.LBOX_given_shots.Clear() 1236 self.LBOX_active_schedules.Clear() 1237 self.LBOX_missing_shots.Clear() 1238 1239 emr = self.__pat.emr 1240 1241 t1 = time.time() 1242 # populate vaccinated-indications list 1243 # FIXME: consider adding virtual indication "most recent" to 1244 # FIXME: display most recent of all indications as suggested by Syan 1245 status, indications = emr.get_vaccinated_indications() 1246 # FIXME: would be faster to use Set() but can't 1247 # use Set(labels, client_data), and have to know 1248 # line position in SetClientData :-( 1249 for indication in indications: 1250 self.LBOX_vaccinated_indications.Append(indication[1], indication[0]) 1251 # self.LBOX_vaccinated_indications.Set(lines) 1252 # self.LBOX_vaccinated_indications.SetClientData(data) 1253 print("vaccinated indications took", time.time()-t1, "seconds") 1254 1255 t1 = time.time() 1256 # populate active schedules list 1257 scheds = emr.get_scheduled_vaccination_regimes() 1258 if scheds is None: 1259 label = _('ERROR: cannot retrieve active vaccination schedules') 1260 self.LBOX_active_schedules.Append(label) 1261 elif len(scheds) == 0: 1262 label = _('no active vaccination schedules') 1263 self.LBOX_active_schedules.Append(label) 1264 else: 1265 for sched in scheds: 1266 label = _('%s for %s (%s shots): %s') % (sched['regime'], sched['l10n_indication'], sched['shots'], sched['comment']) 1267 self.LBOX_active_schedules.Append(label) 1268 print("active schedules took", time.time()-t1, "seconds") 1269 1270 t1 = time.time() 1271 # populate missing-shots list 1272 missing_shots = emr.get_missing_vaccinations() 1273 print("getting missing shots took", time.time()-t1, "seconds") 1274 if missing_shots is None: 1275 label = _('ERROR: cannot retrieve due/overdue vaccinations') 1276 self.LBOX_missing_shots.Append(label, None) 1277 return True 1278 # due 1279 due_template = _('%.0d weeks left: shot %s for %s in %s, due %s (%s)') 1280 overdue_template = _('overdue %.0dyrs %.0dwks: shot %s for %s in schedule "%s" (%s)') 1281 for shot in missing_shots['due']: 1282 if shot['overdue']: 1283 years, days_left = divmod(shot['amount_overdue'].days, 364.25) 1284 weeks = days_left / 7 1285 # amount_overdue, seq_no, indication, regime, vacc_comment 1286 label = overdue_template % ( 1287 years, 1288 weeks, 1289 shot['seq_no'], 1290 shot['l10n_indication'], 1291 shot['regime'], 1292 shot['vacc_comment'] 1293 ) 1294 self.LBOX_missing_shots.Append(label, shot) 1295 else: 1296 # time_left, seq_no, regime, latest_due, vacc_comment 1297 label = due_template % ( 1298 shot['time_left'].days / 7, 1299 shot['seq_no'], 1300 shot['indication'], 1301 shot['regime'], 1302 shot['latest_due'].strftime('%m/%Y'), 1303 shot['vacc_comment'] 1304 ) 1305 self.LBOX_missing_shots.Append(label, shot) 1306 # booster 1307 lbl_template = _('due now: booster for %s in schedule "%s" (%s)') 1308 for shot in missing_shots['boosters']: 1309 # indication, regime, vacc_comment 1310 label = lbl_template % ( 1311 shot['l10n_indication'], 1312 shot['regime'], 1313 shot['vacc_comment'] 1314 ) 1315 self.LBOX_missing_shots.Append(label, shot) 1316 print("displaying missing shots took", time.time()-t1, "seconds") 1317 1318 return True
1319 #----------------------------------------------------
1320 - def _on_post_patient_selection(self, **kwargs):
1321 return 1
1322 # FIXME: 1323 # if has_focus: 1324 # wxCallAfter(self.__reset_ui_content) 1325 # else: 1326 # return 1 1327 #----------------------------------------------------
1328 - def _on_vaccinations_updated(self, **kwargs):
1329 return 1
1330 # FIXME: 1331 # if has_focus: 1332 # wxCallAfter(self.__reset_ui_content) 1333 # else: 1334 # is_stale == True 1335 # return 1 1336 #====================================================================== 1337 # main 1338 #---------------------------------------------------------------------- 1339 if __name__ == "__main__": 1340 1341 if len(sys.argv) < 2: 1342 sys.exit() 1343 1344 if sys.argv[1] != 'test': 1345 sys.exit() 1346 1347 app = wx.PyWidgetTester(size = (600, 600)) 1348 app.SetWidget(cXxxPhraseWheel, -1) 1349 app.MainLoop() 1350