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