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          # 1) get template
     577          template = gmFormWidgets.manage_form_templates (
     578                  parent = parent,
     579                  active_only = True,
     580                  template_types = [u'Medical statement', u'vaccination report', u'vaccination record']
     581          )
     582
     583          if template is None:
     584                  gmDispatcher.send(signal = 'statustext', msg = _('No vaccination document template selected.'), beep = False)
     585                  return None
     586
     587          # 2) process template
     588          try:
     589                  vaccs_printout = template.instantiate()
     590          except KeyError:
     591                  _log.exception('cannot instantiate vaccinations printout template [%s]', template)
     592                  gmGuiHelpers.gm_show_error (
     593                          aMessage = _('Invalid vaccinations printout template [%s - %s (%s)]') % (name, ver, template['engine']),
     594                          aTitle = _('Printing vaccinations')
     595                  )
     596                  return False
     597
     598          ph = gmMacro.gmPlaceholderHandler()
     599          #ph.debug = True
     600          vaccs_printout.substitute_placeholders(data_source = ph)
     601          pdf_name = vaccs_printout.generate_output()
     602          if pdf_name is None:
     603                  gmGuiHelpers.gm_show_error (
     604                          aMessage = _('Error generating the vaccinations printout.'),
     605                          aTitle = _('Printing vaccinations')
     606                  )
     607                  return False
     608
     609          # 3) print template
     610          printed = gmPrinting.print_files(filenames = [pdf_name], jobtype = 'vaccinations')
     611          if not printed:
     612                  gmGuiHelpers.gm_show_error (
     613                          aMessage = _('Error printing vaccinations.'),
     614                          aTitle = _('Printing vaccinations')
     615                  )
     616                  return False
     617
     618          pat = gmPerson.gmCurrentPatient()
     619          emr = pat.get_emr()
     620          epi = emr.add_episode(episode_name = 'administration', is_open = False)
     621          emr.add_clin_narrative (
     622                  soap_cat = None,
     623                  note = _('vaccinations printed from template [%s - %s]') % (template['name_long'], template['external_version']),
     624                  episode = epi
     625          )
     626
     627          return True
     628
     629  #----------------------------------------------------------------------
     630 -def edit_vaccination(parent=None, vaccination=None, single_entry=True):
     631          ea = cVaccinationEAPnl(parent = parent, id = -1)
     632          ea.data = vaccination
     633          ea.mode = gmTools.coalesce(vaccination, 'new', 'edit')
     634          dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = single_entry)
     635          dlg.SetTitle(gmTools.coalesce(vaccination, _('Adding new vaccinations'), _('Editing vaccination')))
     636          if dlg.ShowModal() == wx.ID_OK:
     637                  dlg.Destroy()
     638                  return True
     639          dlg.Destroy()
     640          if not single_entry:
     641                  return True
     642          return False
     643
     644  #----------------------------------------------------------------------
     645 -def manage_vaccinations(parent=None):
     646
     647          pat = gmPerson.gmCurrentPatient()
     648          emr = pat.get_emr()
     649
     650          if parent is None:
     651                  parent = wx.GetApp().GetTopWindow()
     652          #------------------------------------------------------------
     653          def browse2schedules(vaccination=None):
     654                  dbcfg = gmCfg.cCfgSQL()
     655                  url = dbcfg.get2 (
     656                          option = 'external.urls.vaccination_plans',
     657                          workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace,
     658                          bias = 'user',
     659                          default = u'http://www.bundesaerztekammer.de/downloads/STIKOEmpf2011.pdf'
     660                  )
     661
     662                  gmNetworkTools.open_url_in_browser(url = url)
     663                  return False
     664          #------------------------------------------------------------
     665          def print_vaccs(vaccination=None):
     666                  print_vaccinations(parent = parent)
     667                  return False
     668          #------------------------------------------------------------
     669          def add_recall(vaccination=None):
     670                  if vaccination is None:
     671                          subject = _('vaccination recall')
     672                  else:
     673                          subject = _('vaccination recall (%s)') % vaccination['vaccine']
     674
     675                  recall = gmProviderInbox.create_inbox_message (
     676                          message_type = _('Vaccination'),
     677                          subject = subject,
     678                          patient = pat.ID,
     679                          staff = None
     680                  )
     681
     682                  if vaccination is not None:
     683                          recall['data'] = _('Existing vaccination:\n\n%s') % u'\n'.join(vaccination.format(
     684                                  with_indications = True,
     685                                  with_comment = True,
     686                                  with_reaction = False,
     687                                  date_format = '%Y %b %d'
     688                          ))
     689                          recall.save()
     690
     691                  from Gnumed.wxpython import gmProviderInboxWidgets
     692                  gmProviderInboxWidgets.edit_inbox_message (
     693                          parent = parent,
     694                          message = recall,
     695                          single_entry = False
     696                  )
     697
     698                  return False
     699          #------------------------------------------------------------
     700          def get_tooltip(vaccination):
     701                  if vaccination is None:
     702                          return None
     703                  return u'\n'.join(vaccination.format (
     704                          with_indications = True,
     705                          with_comment = True,
     706                          with_reaction = True,
     707                          date_format = '%Y %b %d'
     708                  ))
     709          #------------------------------------------------------------
     710          def edit(vaccination=None):
     711                  return edit_vaccination(parent = parent, vaccination = vaccination, single_entry = (vaccination is not None))
     712          #------------------------------------------------------------
     713          def delete(vaccination=None):
     714                  gmVaccination.delete_vaccination(vaccination = vaccination['pk_vaccination'])
     715                  return True
     716          #------------------------------------------------------------
     717          def refresh(lctrl):
     718
     719                  vaccs = emr.get_vaccinations(order_by = 'date_given DESC, pk_vaccination')
     720
     721                  items = [ [
     722                          gmDateTime.pydt_strftime(v['date_given'], '%Y %b %d'),
     723                          v['vaccine'],
     724                          u', '.join(v['l10n_indications']),
     725                          v['batch_no'],
     726                          gmTools.coalesce(v['site'], u''),
     727                          gmTools.coalesce(v['reaction'], u''),
     728                          gmTools.coalesce(v['comment'], u'')
     729                  ] for v in vaccs ]
     730
     731                  lctrl.set_string_items(items)
     732                  lctrl.set_data(vaccs)
     733          #------------------------------------------------------------
     734          gmListWidgets.get_choices_from_list (
     735                  parent = parent,
     736                  msg = _('\nComplete vaccination history for this patient.\n'),
     737                  caption = _('Showing vaccinations.'),
     738                  columns = [ _('Date'), _('Vaccine'), _(u'Intended to protect from'), _('Batch'), _('Site'), _('Reaction'), _('Comment') ],
     739                  single_selection = True,
     740                  refresh_callback = refresh,
     741                  new_callback = edit,
     742                  edit_callback = edit,
     743                  delete_callback = delete,
     744                  list_tooltip_callback = get_tooltip,
     745                  left_extra_button = (_('Print'), _('Print vaccinations using a template.'), print_vaccs),
     746                  middle_extra_button = (_('Recall'), _('Add a recall for a vaccination'), add_recall),
     747                  right_extra_button = (_('Vaccination Plans'), _('Open a browser showing vaccination schedules.'), browse2schedules)
     748          )
     749  #----------------------------------------------------------------------
     750  from Gnumed.wxGladeWidgets import wxgVaccinationEAPnl
     751
     752 -class cVaccinationEAPnl(wxgVaccinationEAPnl.wxgVaccinationEAPnl, gmEditArea.cGenericEditAreaMixin):
     753          """
     754          - warn on apparent duplicates
     755          - ask if "missing" (= previous, non-recorded) vaccinations
     756            should be estimated and saved (add note "auto-generated")
     757
     758          Batch No (http://www.fao.org/docrep/003/v9952E12.htm)
     759          """
     760 -        def __init__(self, *args, **kwargs):
     761
     762                  try:
     763                          data = kwargs['vaccination']
     764                          del kwargs['vaccination']
     765                  except KeyError:
     766                          data = None
     767
     768                  wxgVaccinationEAPnl.wxgVaccinationEAPnl.__init__(self, *args, **kwargs)
     769                  gmEditArea.cGenericEditAreaMixin.__init__(self)
     770
     771                  self.mode = 'new'
     772                  self.data = data
     773                  if data is not None:
     774                          self.mode = 'edit'
     775
     776                  self.__init_ui()
     777          #----------------------------------------------------------------
     778 -        def __init_ui(self):
     779                  # adjust phrasewheels etc
     780                  self._PRW_vaccine.add_callback_on_lose_focus(self._on_PRW_vaccine_lost_focus)
     781                  self._PRW_provider.selection_only = False
     782                  self._PRW_reaction.add_callback_on_lose_focus(self._on_PRW_reaction_lost_focus)
     783                  if self.mode == 'edit':
     784                          self._BTN_select_indications.Disable()
     785          #----------------------------------------------------------------
     786 -        def _on_PRW_vaccine_lost_focus(self):
     787
     788                  vaccine = self._PRW_vaccine.GetData(as_instance=True)
     789
     790                  # if we are editing we do not allow using indications rather than a vaccine
     791                  if self.mode == u'edit':
     792                          if vaccine is None:
     793                                  self._PRW_batch.unset_context(context = 'pk_vaccine')
     794                                  self.__indications = []
     795                          else:
     796                                  self._PRW_batch.set_context(context = 'pk_vaccine', val = vaccine['pk_vaccine'])
     797                                  self.__indications = vaccine.indications
     798                  # we are entering a new vaccination
     799                  else:
     800                          if vaccine is None:
     801                                  self._PRW_batch.unset_context(context = 'pk_vaccine')
     802                                  self.__indications = []
     803                                  self._BTN_select_indications.Enable()
     804                          else:
     805                                  self._PRW_batch.set_context(context = 'pk_vaccine', val = vaccine['pk_vaccine'])
     806                                  self.__indications = vaccine.indications
     807                                  self._BTN_select_indications.Disable()
     808
     809                  self.__refresh_indications()
     810          #----------------------------------------------------------------
     811 -        def _on_PRW_reaction_lost_focus(self):
     812                  if self._PRW_reaction.GetValue().strip() == u'':
     813                          self._BTN_report.Enable(False)
     814                  else:
     815                          self._BTN_report.Enable(True)
     816          #----------------------------------------------------------------
     817 -        def __refresh_indications(self):
     818                  self._TCTRL_indications.SetValue(u'')
     819                  if len(self.__indications) == 0:
     820                          return
     821                  self._TCTRL_indications.SetValue(u'- ' + u'\n- '.join([ i['l10n_description'] for i in self.__indications ]))
     822          #----------------------------------------------------------------
     823          # generic Edit Area mixin API
     824          #----------------------------------------------------------------
     825 -        def _valid_for_save(self):
     826
     827                  has_errors = False
     828
     829                  if not self._PRW_date_given.is_valid_timestamp(allow_empty = False):
     830                          has_errors = True
     831
     832                  vaccine = self._PRW_vaccine.GetData(as_instance = True)
     833
     834                  # we are editing, require vaccine rather than indications
     835                  if self.mode == u'edit':
     836                          if vaccine is None:
     837                                  has_errors = True
     838                                  self._PRW_vaccine.display_as_valid(False)
     839                          else:
     840                                  self._PRW_vaccine.display_as_valid(True)
     841                  # we are creating, allow either vaccine or indications
     842                  else:
     843                          if vaccine is None:
     844                                  if len(self.__indications) == 0:
     845                                          self._PRW_vaccine.display_as_valid(False)
     846                                          has_errors = True
     847                                  else:
     848                                          self._PRW_vaccine.display_as_valid(True)
     849                          else:
     850                                  self._PRW_vaccine.display_as_valid(True)
     851
     852                  if self._PRW_batch.GetValue().strip() == u'':
     853                          has_errors = True
     854                          self._PRW_batch.display_as_valid(False)
     855                  else:
     856                          self._PRW_batch.display_as_valid(True)
     857
     858                  if self._PRW_episode.GetValue().strip() == u'':
     859                          self._PRW_episode.SetText(value = _('prevention'))
     860
     861                  return (has_errors is False)
     862          #----------------------------------------------------------------
     863 -        def _save_as_new(self):
     864
     865                  vaccine = self._PRW_vaccine.GetData()
     866                  if vaccine is None:
     867                          data = self.__save_new_from_indications()
     868                  else:
     869                          data = self.__save_new_from_vaccine(vaccine = vaccine)
     870
     871                  # must be done very late or else the property access
     872                  # will refresh the display such that later field
     873                  # access will return empty values
     874                  self.data = data
     875
     876                  return True
     877          #----------------------------------------------------------------
     878 -        def __save_new_from_indications(self):
     879
     880                  if len(self.__indications) == 0:
     881                          gmGuiHelpers.gm_show_info (
     882                                  aTitle = _('Saving vaccination'),
     883                                  aMessage = _('You must select at least one indication.')
     884                          )
     885                          return False
     886
     887                  vaccine = gmVaccination.map_indications2generic_vaccine(indications = [ i['description'] for i in self.__indications ])
     888
     889                  if vaccine is None:
     890                          for ind in self.__indications:
     891                                  vaccine = gmVaccination.map_indications2generic_vaccine(indications = [ind['description']])
     892                                  data = self.__save_new_from_vaccine(vaccine = vaccine['pk_vaccine'])
     893                  else:
     894                          data = self.__save_new_from_vaccine(vaccine = vaccine['pk_vaccine'])
     895
     896                  return data
     897          #----------------------------------------------------------------
     898 -        def __save_new_from_vaccine(self, vaccine=None):
     899
     900                  emr = gmPerson.gmCurrentPatient().get_emr()
     901
     902                  data = emr.add_vaccination (
     903                          episode = self._PRW_episode.GetData(can_create = True, is_open = False),
     904                          vaccine = vaccine,
     905                          batch_no = self._PRW_batch.GetValue().strip()
     906                  )
     907
     908                  if self._CHBOX_anamnestic.GetValue() is True:
     909                          data['soap_cat'] = u's'
     910                  else:
     911                          data['soap_cat'] = u'p'
     912
     913                  data['date_given'] = self._PRW_date_given.GetData()
     914                  data['site'] = self._PRW_site.GetValue().strip()
     915                  data['pk_provider'] = self._PRW_provider.GetData()
     916                  data['reaction'] = self._PRW_reaction.GetValue().strip()
     917                  data['comment'] = self._TCTRL_comment.GetValue().strip()
     918
     919                  data.save()
     920
     921                  return data
     922          #----------------------------------------------------------------
     923 -        def _save_as_update(self):
     924
     925                  if self._CHBOX_anamnestic.GetValue() is True:
     926                          self.data['soap_cat'] = u's'
     927                  else:
     928                          self.data['soap_cat'] = u'p'
     929
     930                  self.data['date_given'] = self._PRW_date_given.GetData()
     931                  self.data['pk_vaccine'] = self._PRW_vaccine.GetData()
     932                  self.data['batch_no'] = self._PRW_batch.GetValue().strip()
     933                  self.data['pk_episode'] = self._PRW_episode.GetData(can_create = True, is_open = False)
     934                  self.data['site'] = self._PRW_site.GetValue().strip()
     935                  self.data['pk_provider'] = self._PRW_provider.GetData()
     936                  self.data['reaction'] = self._PRW_reaction.GetValue().strip()
     937                  self.data['comment'] = self._TCTRL_comment.GetValue().strip()
     938
     939                  self.data.save()
     940
     941                  return True
     942          #----------------------------------------------------------------
     943 -        def _refresh_as_new(self):
     944                  self._PRW_date_given.SetText(data = gmDateTime.pydt_now_here())
     945                  self._CHBOX_anamnestic.SetValue(False)
     946                  self._PRW_vaccine.SetText(value = u'', data = None, suppress_smarts = True)
     947                  self._PRW_batch.unset_context(context = 'pk_vaccine')
     948                  self._PRW_batch.SetValue(u'')
     949                  self._PRW_episode.SetText(value = u'', data = None, suppress_smarts = True)
     950                  self._PRW_site.SetValue(u'')
     951                  self._PRW_provider.SetData(data = None)
     952                  self._PRW_reaction.SetText(value = u'', data = None, suppress_smarts = True)
     953                  self._BTN_report.Enable(False)
     954                  self._TCTRL_comment.SetValue(u'')
     955
     956                  self.__indications = []
     957                  self.__refresh_indications()
     958                  self._BTN_select_indications.Enable()
     959
     960                  self._PRW_date_given.SetFocus()
     961          #----------------------------------------------------------------
     962 -        def _refresh_from_existing(self):
     963                  self._PRW_date_given.SetText(data = self.data['date_given'])
     964                  if self.data['soap_cat'] == u's':
     965                          self._CHBOX_anamnestic.SetValue(True)
     966                  else:
     967                          self._CHBOX_anamnestic.SetValue(False)
     968                  self._PRW_vaccine.SetText(value = self.data['vaccine'], data = self.data['pk_vaccine'])
     969
     970                  self._PRW_batch.SetValue(self.data['batch_no'])
     971                  self._PRW_episode.SetData(data = self.data['pk_episode'])
     972                  self._PRW_site.SetValue(gmTools.coalesce(self.data['site'], u''))
     973                  self._PRW_provider.SetData(self.data['pk_provider'])
     974                  self._PRW_reaction.SetValue(gmTools.coalesce(self.data['reaction'], u''))
     975                  if self.data['reaction'] is None:
     976                          self._BTN_report.Enable(False)
     977                  else:
     978                          self._BTN_report.Enable(True)
     979                  self._TCTRL_comment.SetValue(gmTools.coalesce(self.data['comment'], u''))
     980
     981                  self.__indications = self.data.vaccine.indications
     982                  self.__refresh_indications()
     983                  self._BTN_select_indications.Disable()
     984
     985                  self._PRW_date_given.SetFocus()
     986          #----------------------------------------------------------------
     987 -        def _refresh_as_new_from_existing(self):
     988                  self._PRW_date_given.SetText(data = self.data['date_given'])
     989                  #self._CHBOX_anamnestic.SetValue(False)
     990                  self._PRW_vaccine.SetText(value = self.data['vaccine'], data = self.data['pk_vaccine'])
     991
     992                  self._PRW_batch.set_context(context = 'pk_vaccine', val = self.data['pk_vaccine'])
     993                  self._PRW_batch.SetValue(u'')
     994
     995                  self._PRW_episode.SetData(data = self.data['pk_episode'])
     996                  self._PRW_site.SetValue(gmTools.coalesce(self.data['site'], u''))
     997                  self._PRW_provider.SetData(self.data['pk_provider'])
     998                  self._PRW_reaction.SetValue(u'')
     999                  self._BTN_report.Enable(False)
    1000                  self._TCTRL_comment.SetValue(u'')
    1001
    1002                  self.__indications = self.data.vaccine.indications
    1003                  self.__refresh_indications()
    1004                  self._BTN_select_indications.Enable()
    1005
    1006                  self._PRW_date_given.SetFocus()
    1007          #----------------------------------------------------------------
    1008          # event handlers
    1009          #----------------------------------------------------------------
    1010 -        def _on_report_button_pressed(self, event):
    1011                  event.Skip()
    1012                  dbcfg = gmCfg.cCfgSQL()
    1013                  url = dbcfg.get2 (
    1014                          option = u'external.urls.report_vaccine_ADR',
    1015                          workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace,
    1016                          bias = u'user',
    1017                          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'
    1018                  )
    1019
    1020                  if url.strip() == u'':
    1021                          url = dbcfg.get2 (
    1022                                  option = u'external.urls.report_ADR',
    1023                                  workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace,
    1024                                  bias = u'user'
    1025                          )
    1026                  gmNetworkTools.open_url_in_browser(url = url)
    1027          #----------------------------------------------------------------
    1028 -        def _on_add_vaccine_button_pressed(self, event):
    1029                  edit_vaccine(parent = self, vaccine = None, single_entry = False)
    1030                  # FIXME: could set newly generated vaccine here
    1031          #----------------------------------------------------------------
    1032 -        def _on_select_indications_button_pressed(self, event):
    1033                  event.Skip()
    1034
    1035                  picks = pick_indications (
    1036                          parent = self,
    1037                          msg = _('Pick the diseases this vaccination was given against.'),
    1038                          right_column = _('This vaccine'),
    1039                          picks = self.__indications
    1040                  )
    1041                  if picks is None:
    1042                          return
    1043
    1044                  self.__indications = picks
    1045                  self.__refresh_indications()
    1046
    1047  #======================================================================
    1048  #======================================================================
    1049  #======================================================================
    1050  #======================================================================
    1051 -class cImmunisationsPanel(wx.Panel, gmRegetMixin.cRegetOnPaintMixin):
    1052
    1053 -        def __init__(self, parent, id):
    1054                  wx.Panel.__init__(self, parent, id, wx.DefaultPosition, wx.DefaultSize, wx.RAISED_BORDER)
    1055                  gmRegetMixin.cRegetOnPaintMixin.__init__(self)
    1056                  self.__pat = gmPerson.gmCurrentPatient()
    1057                  # do this here so "import cImmunisationsPanel from gmVaccWidgets" works
    1058                  self.ID_VaccinatedIndicationsList = wx.NewId()
    1059                  self.ID_VaccinationsPerRegimeList = wx.NewId()
    1060                  self.ID_MissingShots = wx.NewId()
    1061                  self.ID_ActiveSchedules = wx.NewId()
    1062                  self.__do_layout()
    1063                  self.__register_interests()
    1064                  self.__reset_ui_content()
    1065          #----------------------------------------------------
    1066 -        def __do_layout(self):
    1067                  #-----------------------------------------------
    1068                  # top part
    1069                  #-----------------------------------------------
    1070                  pnl_UpperCaption = gmTerryGuiParts.cHeadingCaption(self, -1, _("  IMMUNISATIONS  "))
    1071                  self.editarea = cVaccinationEditArea(self, -1, wx.DefaultPosition, wx.DefaultSize, wx.NO_BORDER)
    1072
    1073                  #-----------------------------------------------
    1074                  # middle part
    1075                  #-----------------------------------------------
    1076                  # divider headings below editing area
    1077                  indications_heading = gmTerryGuiParts.cDividerCaption(self, -1, _("Indications"))
    1078                  vaccinations_heading = gmTerryGuiParts.cDividerCaption(self, -1, _("Vaccinations"))
    1079                  schedules_heading = gmTerryGuiParts.cDividerCaption(self, -1, _("Active Schedules"))
    1080                  szr_MiddleCap = wx.BoxSizer(wx.HORIZONTAL)
    1081                  szr_MiddleCap.Add(indications_heading, 4, wx.EXPAND)
    1082                  szr_MiddleCap.Add(vaccinations_heading, 6, wx.EXPAND)
    1083                  szr_MiddleCap.Add(schedules_heading, 10, wx.EXPAND)
    1084
    1085                  # left list: indications for which vaccinations have been given
    1086                  self.LBOX_vaccinated_indications = wx.ListBox(
    1087                          parent = self,
    1088                          id = self.ID_VaccinatedIndicationsList,
    1089                          choices = [],
    1090                          style = wx.LB_HSCROLL | wx.LB_NEEDED_SB | wx.SUNKEN_BORDER
    1091                  )
    1092                  self.LBOX_vaccinated_indications.SetFont(wx.Font(12,wx.SWISS, wx.NORMAL, wx.NORMAL, False, ''))
    1093
    1094                  # right list: when an indication has been selected on the left
    1095                  # display the corresponding vaccinations on the right
    1096                  self.LBOX_given_shots = wx.ListBox(
    1097                          parent = self,
    1098                          id = self.ID_VaccinationsPerRegimeList,
    1099                          choices = [],
    1100                          style = wx.LB_HSCROLL | wx.LB_NEEDED_SB | wx.SUNKEN_BORDER
    1101                  )
    1102                  self.LBOX_given_shots.SetFont(wx.Font(12,wx.SWISS, wx.NORMAL, wx.NORMAL, False, ''))
    1103
    1104                  self.LBOX_active_schedules = wx.ListBox (
    1105                          parent = self,
    1106                          id = self.ID_ActiveSchedules,
    1107                          choices = [],
    1108                          style = wx.LB_HSCROLL | wx.LB_NEEDED_SB | wx.SUNKEN_BORDER
    1109                  )
    1110                  self.LBOX_active_schedules.SetFont(wx.Font(12, wx.SWISS, wx.NORMAL, wx.NORMAL, False, ''))
    1111
    1112                  szr_MiddleLists = wx.BoxSizer(wx.HORIZONTAL)
    1113                  szr_MiddleLists.Add(self.LBOX_vaccinated_indications, 4, wx.EXPAND)
    1114                  szr_MiddleLists.Add(self.LBOX_given_shots, 6, wx.EXPAND)
    1115                  szr_MiddleLists.Add(self.LBOX_active_schedules, 10, wx.EXPAND)
    1116
    1117                  #---------------------------------------------
    1118                  # bottom part
    1119                  #---------------------------------------------
    1120                  missing_heading = gmTerryGuiParts.cDividerCaption(self, -1, _("Missing Immunisations"))
    1121                  szr_BottomCap = wx.BoxSizer(wx.HORIZONTAL)
    1122                  szr_BottomCap.Add(missing_heading, 1, wx.EXPAND)
    1123
    1124                  self.LBOX_missing_shots = wx.ListBox (
    1125                          parent = self,
    1126                          id = self.ID_MissingShots,
    1127                          choices = [],
    1128                          style = wx.LB_HSCROLL | wx.LB_NEEDED_SB | wx.SUNKEN_BORDER
    1129                  )
    1130                  self.LBOX_missing_shots.SetFont(wx.Font(12, wx.SWISS, wx.NORMAL, wx.NORMAL, False, ''))
    1131
    1132                  szr_BottomLists = wx.BoxSizer(wx.HORIZONTAL)
    1133                  szr_BottomLists.Add(self.LBOX_missing_shots, 1, wx.EXPAND)
    1134
    1135                  # alert caption
    1136                  pnl_AlertCaption = gmTerryGuiParts.cAlertCaption(self, -1, _('  Alerts  '))
    1137
    1138                  #---------------------------------------------
    1139                  # add all elements to the main background sizer
    1140                  #---------------------------------------------
    1141                  self.mainsizer = wx.BoxSizer(wx.VERTICAL)
    1142                  self.mainsizer.Add(pnl_UpperCaption, 0, wx.EXPAND)
    1143                  self.mainsizer.Add(self.editarea, 6, wx.EXPAND)
    1144                  self.mainsizer.Add(szr_MiddleCap, 0, wx.EXPAND)
    1145                  self.mainsizer.Add(szr_MiddleLists, 4, wx.EXPAND)
    1146                  self.mainsizer.Add(szr_BottomCap, 0, wx.EXPAND)
    1147                  self.mainsizer.Add(szr_BottomLists, 4, wx.EXPAND)
    1148                  self.mainsizer.Add(pnl_AlertCaption, 0, wx.EXPAND)
    1149
    1150                  self.SetAutoLayout(True)
    1151                  self.SetSizer(self.mainsizer)
    1152                  self.mainsizer.Fit(self)
    1153          #----------------------------------------------------
    1154 -        def __register_interests(self):
    1155                  # wxPython events
    1156                  wx.EVT_SIZE(self, self.OnSize)
    1157                  wx.EVT_LISTBOX(self, self.ID_VaccinatedIndicationsList, self._on_vaccinated_indication_selected)
    1158                  wx.EVT_LISTBOX_DCLICK(self, self.ID_VaccinationsPerRegimeList, self._on_given_shot_selected)
    1159                  wx.EVT_LISTBOX_DCLICK(self, self.ID_MissingShots, self._on_missing_shot_selected)
    1160  #               wx.EVT_RIGHT_UP(self.lb1, self.EvtRightButton)
    1161
    1162                  # client internal signals
    1163                  gmDispatcher.connect(signal= u'post_patient_selection', receiver=self._schedule_data_reget)
    1164                  gmDispatcher.connect(signal= u'vaccinations_updated', receiver=self._schedule_data_reget)
    1165          #----------------------------------------------------
    1166          # event handlers
    1167          #----------------------------------------------------
    1168 -        def OnSize (self, event):
    1169                  w, h = event.GetSize()
    1170                  self.mainsizer.SetDimension (0, 0, w, h)
    1171          #----------------------------------------------------
    1172 -        def _on_given_shot_selected(self, event):
    1173                  """Paste previously given shot into edit area.
    1174                  """
    1175                  self.editarea.set_data(aVacc=event.GetClientData())
    1176          #----------------------------------------------------
    1177 -        def _on_missing_shot_selected(self, event):
    1178                  self.editarea.set_data(aVacc = event.GetClientData())
    1179          #----------------------------------------------------
    1180 -        def _on_vaccinated_indication_selected(self, event):
    1181                  """Update right hand middle list to show vaccinations given for selected indication."""
    1182                  ind_list = event.GetEventObject()
    1183                  selected_item = ind_list.GetSelection()
    1184                  ind = ind_list.GetClientData(selected_item)
    1185                  # clear list
    1186                  self.LBOX_given_shots.Set([])
    1187                  emr = self.__pat.get_emr()
    1188                  shots = emr.get_vaccinations(indications = [ind])
    1189                  # FIXME: use Set() for entire array (but problem with client_data)
    1190                  for shot in shots:
    1191                          if shot['is_booster']:
    1192                                  marker = 'B'
    1193                          else:
    1194                                  marker = '#%s' % shot['seq_no']
    1195                          label = '%s - %s: %s' % (marker, shot['date'].strftime('%m/%Y'), shot['vaccine'])
    1196                          self.LBOX_given_shots.Append(label, shot)
    1197          #----------------------------------------------------
    1198 -        def __reset_ui_content(self):
    1199                  # clear edit area
    1200                  self.editarea.set_data()
    1201                  # clear lists
    1202                  self.LBOX_vaccinated_indications.Clear()
    1203                  self.LBOX_given_shots.Clear()
    1204                  self.LBOX_active_schedules.Clear()
    1205                  self.LBOX_missing_shots.Clear()
    1206          #----------------------------------------------------
    1207 -        def _populate_with_data(self):
    1208                  # clear lists
    1209                  self.LBOX_vaccinated_indications.Clear()
    1210                  self.LBOX_given_shots.Clear()
    1211                  self.LBOX_active_schedules.Clear()
    1212                  self.LBOX_missing_shots.Clear()
    1213
    1214                  emr = self.__pat.get_emr()
    1215
    1216                  t1 = time.time()
    1217                  # populate vaccinated-indications list
    1218                  # FIXME: consider adding virtual indication "most recent" to
    1219                  # FIXME: display most recent of all indications as suggested by Syan
    1220                  status, indications = emr.get_vaccinated_indications()
    1221                  # FIXME: would be faster to use Set() but can't
    1222                  # use Set(labels, client_data), and have to know
    1223                  # line position in SetClientData :-(
    1224                  for indication in indications:
    1225                          self.LBOX_vaccinated_indications.Append(indication[1], indication[0])
    1226  #               self.LBOX_vaccinated_indications.Set(lines)
    1227  #               self.LBOX_vaccinated_indications.SetClientData(data)
    1228                  print "vaccinated indications took", time.time()-t1, "seconds"
    1229
    1230                  t1 = time.time()
    1231                  # populate active schedules list
    1232                  scheds = emr.get_scheduled_vaccination_regimes()
    1233                  if scheds is None:
    1234                          label = _('ERROR: cannot retrieve active vaccination schedules')
    1235                          self.LBOX_active_schedules.Append(label)
    1236                  elif len(scheds) == 0:
    1237                          label = _('no active vaccination schedules')
    1238                          self.LBOX_active_schedules.Append(label)
    1239                  else:
    1240                          for sched in scheds:
    1241                                  label = _('%s for %s (%s shots): %s') % (sched['regime'], sched['l10n_indication'], sched['shots'], sched['comment'])
    1242                                  self.LBOX_active_schedules.Append(label)
    1243                  print "active schedules took", time.time()-t1, "seconds"
    1244
    1245                  t1 = time.time()
    1246                  # populate missing-shots list
    1247                  missing_shots = emr.get_missing_vaccinations()
    1248                  print "getting missing shots took", time.time()-t1, "seconds"
    1249                  if missing_shots is None:
    1250                          label = _('ERROR: cannot retrieve due/overdue vaccinations')
    1251                          self.LBOX_missing_shots.Append(label, None)
    1252                          return True
    1253                  # due
    1254                  due_template = _('%.0d weeks left: shot %s for %s in %s, due %s (%s)')
    1255                  overdue_template = _('overdue %.0dyrs %.0dwks: shot %s for %s in schedule "%s" (%s)')
    1256                  for shot in missing_shots['due']:
    1257                          if shot['overdue']:
    1258                                  years, days_left = divmod(shot['amount_overdue'].days, 364.25)
    1259                                  weeks = days_left / 7
    1260                                  # amount_overdue, seq_no, indication, regime, vacc_comment
    1261                                  label = overdue_template % (
    1262                                          years,
    1263                                          weeks,
    1264                                          shot['seq_no'],
    1265                                          shot['l10n_indication'],
    1266                                          shot['regime'],
    1267                                          shot['vacc_comment']
    1268                                  )
    1269                                  self.LBOX_missing_shots.Append(label, shot)
    1270                          else:
    1271                                  # time_left, seq_no, regime, latest_due, vacc_comment
    1272                                  label = due_template % (
    1273                                          shot['time_left'].days / 7,
    1274                                          shot['seq_no'],
    1275                                          shot['indication'],
    1276                                          shot['regime'],
    1277                                          shot['latest_due'].strftime('%m/%Y'),
    1278                                          shot['vacc_comment']
    1279                                  )
    1280                                  self.LBOX_missing_shots.Append(label, shot)
    1281                  # booster
    1282                  lbl_template = _('due now: booster for %s in schedule "%s" (%s)')
    1283                  for shot in missing_shots['boosters']:
    1284                          # indication, regime, vacc_comment
    1285                          label = lbl_template % (
    1286                                  shot['l10n_indication'],
    1287                                  shot['regime'],
    1288                                  shot['vacc_comment']
    1289                          )
    1290                          self.LBOX_missing_shots.Append(label, shot)
    1291                  print "displaying missing shots took", time.time()-t1, "seconds"
    1292
    1293                  return True
    1294          #----------------------------------------------------
    1295 -        def _on_post_patient_selection(self, **kwargs):
    1296                  return 1
    1297                  # FIXME:
    1298  #               if has_focus:
    1299  #                       wxCallAfter(self.__reset_ui_content)
    1300  #               else:
    1301  #                       return 1
    1302          #----------------------------------------------------
    1303 -        def _on_vaccinations_updated(self, **kwargs):
    1304                  return 1
    1305                  # FIXME:
    1306  #               if has_focus:
    1307  #                       wxCallAfter(self.__reset_ui_content)
    1308  #               else:
    1309  #                       is_stale == True
    1310  #                       return 1
    1311  #======================================================================
    1312  # main
    1313  #----------------------------------------------------------------------
    1314  if __name__ == "__main__":
    1315
    1316          if len(sys.argv) < 2:
    1317                  sys.exit()
    1318
    1319          if sys.argv[1] != u'test':
    1320                  sys.exit()
    1321
    1322          app = wx.PyWidgetTester(size = (600, 600))
    1323          app.SetWidget(cATCPhraseWheel, -1)
    1324          app.MainLoop()
    1325