Gnumed.wxpython.gmVaccWidgets

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