Package Gnumed :: Package business :: Module gmVaccination |
[frames] | no frames]

# Source Code for Module Gnumed.business.gmVaccination

      1  """GNUmed vaccination related business objects.
      2  """
      3  #============================================================
      4  __version__ = "$Revision: 1.38 $"
      5  __author__ = "K.Hilbert <Karsten.Hilbert@gmx.net>"
      6  __license__ = "GPL"
      7
      8  import sys, copy, logging
      9
     10
     11  if __name__ == '__main__':
     12          sys.path.insert(0, '../../')
     13  from Gnumed.pycommon import gmBusinessDBObject, gmPG2, gmI18N, gmTools, gmDateTime
     14  from Gnumed.business import gmMedication
     15
     16
     17  _log = logging.getLogger('gm.vaccination')
     18  _log.info(__version__)
     19
     20  #============================================================
     21 -def get_indications(order_by=None, pk_indications=None):
     22          cmd = u'SELECT *, _(description) AS l10n_description FROM clin.vacc_indication'
     23          args = {}
     24
     25          if pk_indications is not None:
     26                  if len(pk_indications) != 0:
     27                          cmd += u' WHERE id IN %(pks)s'
     28                          args['pks'] = tuple(pk_indications)
     29
     30          if order_by is not None:
     31                  cmd += u' ORDER BY %s' % order_by
     32
     33          rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
     34
     35          return rows
     36  #============================================================
     37  _sql_fetch_vaccine = u"""SELECT *, xmin_vaccine FROM clin.v_vaccines WHERE %s"""
     38
     39 -class cVaccine(gmBusinessDBObject.cBusinessDBObject):
     40          """Represents one vaccine."""
     41
     42          _cmd_fetch_payload = _sql_fetch_vaccine % u"pk_vaccine = %s"
     43
     44          _cmds_store_payload = [
     45                  u"""UPDATE clin.vaccine SET
     46                                  --id_route = %(pk_route)s,
     47                                  --is_live = %(is_live)s,
     48                                  min_age = %(min_age)s,
     49                                  max_age = %(max_age)s,
     50                                  comment = gm.nullify_empty_string(%(comment)s),
     51                                  fk_brand = %(pk_brand)s
     52                          WHERE
     53                                  pk = %(pk_vaccine)s
     54                                          AND
     55                                  xmin = %(xmin_vaccine)s
     56                          RETURNING
     57                                  xmin as xmin_vaccine
     58                  """
     59          ]
     60
     61          _updatable_fields = [
     62                  #u'pk_route',
     63                  #u'is_live',
     64                  u'min_age',
     65                  u'max_age',
     66                  u'comment',
     67                  u'pk_brand'
     68          ]
     69          #--------------------------------------------------------
     70 -        def get_indications(self):
     71                  return get_indications(order_by = 'l10n_description', pk_indications = self._payload[self._idx['pk_indications']])
     72
     73 -        def set_indications(self, indications=None, pk_indications=None):
     74                  queries = [{
     75                          'cmd': u'DELETE FROM clin.lnk_vaccine2inds WHERE fk_vaccine = %(pk_vacc)s',
     76                          'args': {'pk_vacc': self._payload[self._idx['pk_vaccine']]}
     77                  }]
     78
     79                  if pk_indications is None:
     80                          if set(self._payload[self._idx['indications']]) == set(indications):
     81                                  return
     82
     83                          for ind in indications:
     84                                  queries.append ({
     85                                          'cmd': u"""
     86                                                  INSERT INTO clin.lnk_vaccine2inds (
     87                                                          fk_vaccine,
     88                                                          fk_indication
     89                                                  ) VALUES (
     90                                                          %(pk_vacc)s,
     91                                                          (SELECT id FROM clin.vacc_indication WHERE description = %(ind)s)
     92                                                  )""",
     93                                          'args': {'pk_vacc': self._payload[self._idx['pk_vaccine']], 'ind': ind}
     94                                  })
     95                  else:
     96                          if set(self._payload[self._idx['pk_indications']]) == set(pk_indications):
     97                                  return
     98
     99                          for pk_ind in pk_indications:
    100                                  queries.append ({
    101                                          'cmd': u"""
    102                                                  INSERT INTO clin.lnk_vaccine2inds (
    103                                                          fk_vaccine,
    104                                                          fk_indication
    105                                                  ) VALUES (
    106                                                          %(pk_vacc)s,
    107                                                          %(pk_ind)s
    108                                                  )""",
    109                                          'args': {'pk_vacc': self._payload[self._idx['pk_vaccine']], 'pk_ind': pk_ind}
    110                                  })
    111
    112                  gmPG2.run_rw_queries(queries = queries)
    113                  self.refetch_payload()
    114
    115          indications = property(get_indications, lambda x:x)
    116          #--------------------------------------------------------
    117          # properties
    118          #--------------------------------------------------------
    119 -        def _get_brand(self):
    120                  return gmMedication.cBrandedDrug(aPK_obj = self._payload[self._idx['pk_brand']])
    121
    122          brand = property(_get_brand, lambda x:x)
    123          #--------------------------------------------------------
    124 -        def _get_is_in_use(self):
    125                  cmd = u'SELECT EXISTS(SELECT 1 FROM clin.vaccination WHERE fk_vaccine = %(pk)s)'
    126                  args = {'pk': self._payload[self._idx['pk_vaccine']]}
    127                  rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
    128                  return rows[0][0]
    129
    130          is_in_use = property(_get_is_in_use, lambda x:x)
    131  #------------------------------------------------------------
    132 -def create_vaccine(pk_brand=None, brand_name=None, indications=None, pk_indications=None):
    133
    134          if pk_brand is None:
    135                  prep = _('vaccine')
    136                  _log.debug('creating branded drug [%s %s]', brand_name, prep)
    137                  drug = gmMedication.create_branded_drug (
    138                          brand_name = brand_name,
    139                          preparation = prep,
    140                          return_existing = True
    141                  )
    142                  drug['atc'] = u'J07'
    143                  drug.save()
    144                  pk_brand = drug['pk_brand']
    145
    146          cmd = u'INSERT INTO clin.vaccine (fk_brand) values (%(pk_brand)s) RETURNING pk'
    147          queries = [{'cmd': cmd, 'args': {'pk_brand': pk_brand}}]
    148
    149
    150          if pk_indications is None:
    151                  for indication in indications:
    152                          cmd = u"""
    153                                  INSERT INTO clin.lnk_vaccine2inds (
    154                                          fk_vaccine,
    155                                          fk_indication
    156                                  ) VALUES (
    157                                          currval(pg_get_serial_sequence('clin.vaccine', 'pk')),
    158                                          (SELECT id
    159                                           FROM clin.vacc_indication
    160                                           WHERE
    161                                                  lower(description) = lower(%(ind)s)
    162                                           LIMIT 1
    163                                          )
    164                                  )
    165                                  RETURNING fk_vaccine
    166                          """
    167                          queries.append({'cmd': cmd, 'args': {'ind': indication}})
    168          else:
    169                  for pk_indication in pk_indications:
    170                          cmd = u"""
    171                                  INSERT INTO clin.lnk_vaccine2inds (
    172                                          fk_vaccine,
    173                                          fk_indication
    174                                  ) VALUES (
    175                                          currval(pg_get_serial_sequence('clin.vaccine', 'pk')),
    176                                          %(pk_ind)s
    177                                  )
    178                                  RETURNING fk_vaccine
    179                          """
    180                          queries.append({'cmd': cmd, 'args': {'pk_ind': pk_indication}})
    181
    182          rows, idx = gmPG2.run_rw_queries(queries = queries, get_col_idx = False, return_data = True)
    183
    184          return cVaccine(aPK_obj = rows[0]['fk_vaccine'])
    185  #------------------------------------------------------------
    186 -def delete_vaccine(vaccine=None):
    187
    188          cmd = u'DELETE FROM clin.vaccine WHERE pk = %(pk)s'
    189          args = {'pk': vaccine}
    190
    191          try:
    192                  gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
    193          except gmPG2.dbapi.IntegrityError:
    194                  _log.exception('cannot delete vaccine [%s]', vaccine)
    195                  return False
    196
    197          return True
    198  #------------------------------------------------------------
    199 -def get_vaccines(order_by=None):
    200
    201          if order_by is None:
    202                  cmd = _sql_fetch_vaccine % u'TRUE'
    203          else:
    204                  cmd = _sql_fetch_vaccine % (u'TRUE\nORDER BY %s' % order_by)
    205
    206          rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = True)
    207
    208          return [ cVaccine(row = {'data': r, 'idx': idx, 'pk_field': 'pk_vaccine'}) for r in rows ]
    209  #------------------------------------------------------------
    210 -def map_indications2generic_vaccine(indications=None):
    211
    212          args = {'inds': indications}
    213          cmd = _sql_fetch_vaccine % (u'is_fake_vaccine is True AND indications @> %(inds)s AND %(inds)s @> indications')
    214
    215          rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
    216
    217          if len(rows) == 0:
    218                  _log.warning('no fake, generic vaccine found for [%s]', indications)
    219                  return None
    220
    221          return cVaccine(row = {'data': rows[0], 'idx': idx, 'pk_field': 'pk_vaccine'})
    222  #------------------------------------------------------------
    223 -def regenerate_generic_vaccines():
    224
    225          cmd = u'select gm.create_generic_monovalent_vaccines()'
    226          rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd}], return_data = True)
    227
    228          cmd = u'select gm.create_generic_combi_vaccines()'
    229          rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd}], return_data = True)
    230
    231          return rows[0][0]
    232  #============================================================
    233  # vaccination related classes
    234  #============================================================
    235  sql_fetch_vaccination = u"""SELECT * FROM clin.v_pat_vaccinations WHERE %s"""
    236
    237 -class cVaccination(gmBusinessDBObject.cBusinessDBObject):
    238
    239          _cmd_fetch_payload = sql_fetch_vaccination % u"pk_vaccination = %s"
    240
    241          _cmds_store_payload = [
    242                  u"""UPDATE clin.vaccination SET
    243                                  soap_cat = %(soap_cat)s,
    244                                  clin_when = %(date_given)s,
    245                                  site = gm.nullify_empty_string(%(site)s),
    246                                  batch_no = gm.nullify_empty_string(%(batch_no)s),
    247                                  reaction = gm.nullify_empty_string(%(reaction)s),
    248                                  narrative = gm.nullify_empty_string(%(comment)s),
    249                                  fk_vaccine = %(pk_vaccine)s,
    250                                  fk_provider = %(pk_provider)s,
    251                                  fk_encounter = %(pk_encounter)s,
    252                                  fk_episode = %(pk_episode)s
    253                          WHERE
    254                                  pk = %(pk_vaccination)s
    255                                          AND
    256                                  xmin = %(xmin_vaccination)s
    257                          RETURNING
    258                                  xmin as xmin_vaccination
    259                  """
    260          ]
    261
    262          _updatable_fields = [
    263                  u'soap_cat',
    264                  u'date_given',
    265                  u'site',
    266                  u'batch_no',
    267                  u'reaction',
    268                  u'comment',
    269                  u'pk_vaccine',
    270                  u'pk_provider',
    271                  u'pk_encounter',
    272                  u'pk_episode'
    273          ]
    274          #--------------------------------------------------------
    275 -        def format(self, with_indications=False, with_comment=False, with_reaction=False, date_format='%Y-%m-%d'):
    276
    277                  lines = []
    278
    279                  lines.append (u' %s: %s [%s]%s' % (
    280                          self._payload[self._idx['date_given']].strftime(date_format).decode(gmI18N.get_encoding()),
    281                          self._payload[self._idx['vaccine']],
    282                          self._payload[self._idx['batch_no']],
    283                          gmTools.coalesce(self._payload[self._idx['site']], u'', u' (%s)')
    284                  ))
    285
    286                  if with_comment:
    287                          if self._payload[self._idx['comment']] is not None:
    288                                  lines.append(u'   %s' % self._payload[self._idx['comment']])
    289
    290                  if with_reaction:
    291                          if self._payload[self._idx['reaction']] is not None:
    292                                  lines.append(u'   %s' % self._payload[self._idx['reaction']])
    293
    294                  if with_indications:
    295                          lines.append(u'   %s' % u' / '.join(self._payload[self._idx['indications']]))
    296
    297                  return lines
    298          #--------------------------------------------------------
    299 -        def _get_vaccine(self):
    300                  return cVaccine(aPK_obj = self._payload[self._idx['pk_vaccine']])
    301
    302          vaccine = property(_get_vaccine, lambda x:x)
    303  #------------------------------------------------------------
    304 -def create_vaccination(encounter=None, episode=None, vaccine=None, batch_no=None):
    305
    306          cmd = u"""
    307                  INSERT INTO clin.vaccination (
    308                          fk_encounter,
    309                          fk_episode,
    310                          fk_vaccine,
    311                          batch_no
    312                  ) VALUES (
    313                          %(enc)s,
    314                          %(epi)s,
    315                          %(vacc)s,
    316                          %(batch)s
    317                  ) RETURNING pk;
    318          """
    319          args = {
    320                  u'enc': encounter,
    321                  u'epi': episode,
    322                  u'vacc': vaccine,
    323                  u'batch': batch_no
    324          }
    325
    326          rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False, return_data = True)
    327
    328          return cVaccination(aPK_obj = rows[0][0])
    329
    330  #------------------------------------------------------------
    331
    332 -def delete_vaccination(vaccination=None):
    333          cmd = u"""DELETE FROM clin.vaccination WHERE pk = %(pk)s"""
    334          args = {'pk': vaccination}
    335
    336          gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
    337
    338  #------------------------------------------------------------
    339
    340 -def format_latest_vaccinations(output_format=u'latex', emr=None):
    341
    342          _log.debug(u'formatting latest vaccinations into [%s]', output_format)
    343
    344          vaccs = emr.get_latest_vaccinations()
    345
    346          if output_format == u'latex':
    347                  return __format_latest_vaccinations_latex(vaccinations = vaccs)
    348
    349          msg = _('unknown vaccinations output format [%s]') % output_format
    350          _log.error(msg)
    351          return msg
    352
    353  #------------------------------------------------------------
    354
    355 -def __format_latest_vaccinations_latex(vaccinations=None):
    356
    357          if len(vaccinations) == 0:
    358                  return u'\\noindent %s' % _('No vaccinations to format.')
    359
    360          tex =  u'\\noindent %s {\\tiny (%s)\\par}\n' % (_('Latest vaccinations'), _('per target condition'))
    361          tex += u'\n'
    362          tex += u'\\noindent \\begin{tabular}{|l|l|l|l|l|l|}\n'
    363          tex += u'\\hline\n'
    364          tex += u'%s & %s & {\\footnotesize %s} & {\\footnotesize %s} & {\\footnotesize %s\\footnotemark} & {\\footnotesize %s\\footnotemark} \\\\ \n' % (
    365                  _('Target'),
    366                  _('Last given'),
    367                  _('Vaccine'),
    368                  _('Lot \#'),
    369                  _('SoaP'),
    370                  gmTools.u_sum
    371          )
    372          tex += u'\\hline\n'
    373          tex += u'\n'
    374          tex += u'\\hline\n'
    375          tex += u'%s'
    376          tex += u'\n'
    377          tex += u'\\end{tabular}\n'
    378          tex += u'\n'
    379          tex += u'\\addtocounter{footnote}{-1} \n'
    380          tex += u'\\footnotetext{%s} \n' % _('SoaP -- "S"ubjective: vaccination was remembered by patient. "P"lan: vaccination was administered in the practice or copied from trustworthy records.')
    381          tex += u'\\addtocounter{footnote}{1} \n'
    382          tex += u'\\footnotetext{%s -- %s} \n' % (gmTools.u_sum, _('Total number of vaccinations recorded for the corresponding target condition.'))
    383          tex += u'\n'
    384
    385          row_template = u'%s & %s & {\\scriptsize %s} & {\\scriptsize %s} & {\\scriptsize %s} & {\\scriptsize %s} \\\\ \n'
    386          lines = u''
    387          targets = sorted(vaccinations.keys())
    388          for target in targets:
    389                  target_count, vacc = vaccinations[target]
    390                  lines += row_template % (
    391                          target,
    392                          gmDateTime.pydt_strftime(vacc['date_given'], '%Y %b %d'),
    393                          vacc['vaccine'],
    394                          gmTools.tex_escape_string(vacc['batch_no'].strip()),
    395                          vacc['soap_cat'].upper(),
    396                          target_count
    397                  )
    398                  if vacc['site'] is not None:
    399                          lines += u' & \\multicolumn{5}{l|}{\\scriptsize %s: %s\\par} \\\\ \n' % (_('Injection site'), vacc['site'].strip())
    400                  if vacc['reaction'] is not None:
    401                          lines += u' & \\multicolumn{5}{l|}{\\scriptsize %s: %s\\par} \\\\ \n' % (_('Reaction'), vacc['reaction'].strip())
    402                  if vacc['comment'] is not None:
    403                          lines += u' & \\multicolumn{5}{l|}{\\scriptsize %s: %s\\par} \\\\ \n' % (_('Comment'), vacc['comment'].strip())
    404                  lines += u'\\hline \n'
    405
    406          return tex % lines
    407
    408  #============================================================
    409  #============================================================
    410  #============================================================
    411  # old code
    412  #============================================================
    413 -class cMissingVaccination(gmBusinessDBObject.cBusinessDBObject):
    414          """Represents one missing vaccination.
    415
    416          - can be due or overdue
    417          """
    418          _cmd_fetch_payload = """
    419                          (select *, False as overdue
    420                          from clin.v_pat_missing_vaccs vpmv
    421                          where
    422                                  pk_patient=%(pat_id)s
    423                                          and
    424                                  (select dob from dem.identity where pk=%(pat_id)s) between (now() - age_due_min) and (now() - coalesce(age_due_max, '115 years'::interval))
    425                                          and
    426                                  indication=%(indication)s
    427                                          and
    428                                  seq_no=%(seq_no)s
    429                          order by time_left)
    430
    431                                  UNION
    432
    433                          (select *, True as overdue
    434                          from clin.v_pat_missing_vaccs vpmv
    435                          where
    436                                  pk_patient=%(pat_id)s
    437                                          and
    438                                  now() - ((select dob from dem.identity where pk=%(pat_id)s)) > coalesce(age_due_max, '115 years'::interval)
    439                                          and
    440                                  indication=%(indication)s
    441                                          and
    442                                  seq_no=%(seq_no)s
    443                          order by amount_overdue)"""
    444          _cmds_lock_rows_for_update = []
    445          _cmds_store_payload = ["""select 1"""]
    446          _updatable_fields = []
    447          #--------------------------------------------------------
    448 -        def is_overdue(self):
    449                  return self['overdue']
    450          #--------------------------------------------------------
    451 -        def create_vaccination(self):
    452                  # FIXME: create vaccination from myself,
    453                  # either pass in episode/encounter/vaccine id or use default for
    454                  # episode/encounter or use curr_pat.* if pk_patient=curr_pat,
    455                  # should we auto-destroy after create_vaccination() ?
    456                  return (False, 'not implemented')
    457  #============================================================
    458 -class cMissingBooster(gmBusinessDBObject.cBusinessDBObject):
    459          """Represents one due booster.
    460          """
    461          _cmd_fetch_payload = """
    462                  select *, now() - amount_overdue as latest_due
    463                  from clin.v_pat_missing_boosters vpmb
    464                  where
    465                          pk_patient=%(pat_id)s
    466                                  and
    467                          indication=%(indication)s
    468                  order by amount_overdue"""
    469          _cmds_lock_rows_for_update = []
    470          _cmds_store_payload = ["""select 1"""]
    471          _updatable_fields = []
    472  #============================================================
    473 -class cScheduledVaccination(gmBusinessDBObject.cBusinessDBObject):
    474          """Represents one vaccination scheduled following a course.
    475          """
    476          _cmd_fetch_payload = u"select * from clin.v_vaccs_scheduled4pat where pk_vacc_def=%s"
    477          _cmds_lock_rows_for_update = []
    478          _cmds_store_payload = ["""select 1"""]
    479          _updatable_fields = []
    480  #============================================================
    481 -class cVaccinationCourse(gmBusinessDBObject.cBusinessDBObject):
    482          """Represents one vaccination course.
    483          """
    484          _cmd_fetch_payload = """
    485                  select *, xmin_vaccination_course from clin.v_vaccination_courses
    486                  where pk_course=%s"""
    487          _cmds_lock_rows_for_update = [
    488                  """select 1 from clin.vaccination_course where id=%(pk_course)s and xmin=%(xmin_vaccination_course)s for update"""
    489          ]
    490          _cmds_store_payload = [
    491                  """update clin.vaccination_course set
    492                                  name=%(course)s,
    493                                  fk_recommended_by=%(pk_recommended_by)s,
    494                                  fk_indication=(select id from clin.vacc_indication where description=%(indication)s),
    495                                  comment=%(comment)s
    496                          where id=%(pk_course)s""",
    497                  """select xmin_vaccination_course from clin.v_vaccination_courses where pk_course=%(pk_course)s"""
    498          ]
    499          _updatable_fields = [
    500                  'course',
    501                  'pk_recommended_by',
    502                  'indication',
    503                  'comment'
    504          ]
    505  #============================================================
    506  #============================================================
    507  # convenience functions
    508  #------------------------------------------------------------
    509 -def create_vaccination_old(patient_id=None, episode_id=None, encounter_id=None, staff_id = None, vaccine=None):
    510          # sanity check
    511          # 1) any of the args being None should fail the SQL code
    512          # 2) do episode/encounter belong to the patient ?
    513          cmd = """
    514  select pk_patient
    515  from clin.v_pat_episodes
    516  where pk_episode=%s
    517          union
    518  select pk_patient
    519  from clin.v_pat_encounters
    520  where pk_encounter=%s"""
    521          rows = gmPG.run_ro_query('historica', cmd, None, episode_id, encounter_id)
    522          if (rows is None) or (len(rows) == 0):
    523                  _log.error('error checking episode [%s] <-> encounter [%s] consistency' % (episode_id, encounter_id))
    524                  return (False, _('internal error, check log'))
    525          if len(rows) > 1:
    526                  _log.error('episode [%s] and encounter [%s] belong to more than one patient !?!' % (episode_id, encounter_id))
    527                  return (False, _('consistency error, check log'))
    528          # insert new vaccination
    529          queries = []
    530          if type(vaccine) == types.IntType:
    531                  cmd = """insert into clin.vaccination (fk_encounter, fk_episode, fk_patient, fk_provider, fk_vaccine)
    532                                   values (%s, %s, %s, %s, %s)"""
    533          else:
    534                  cmd = """insert into clin.vaccination (fk_encounter, fk_episode, fk_patient, fk_provider, fk_vaccine)
    535                                   values (%s, %s, %s, %s, (select pk from clin.vaccine where trade_name=%s))"""
    536                  vaccine = str(vaccine)
    537          queries.append((cmd, [encounter_id, episode_id, patient_id, staff_id, vaccine]))
    538          # get PK of inserted row
    539          cmd = "select currval('clin.vaccination_id_seq')"
    540          queries.append((cmd, []))
    541          result, msg = gmPG.run_commit('historica', queries, True)
    542          if (result is None) or (len(result) == 0):
    543                  return (False, msg)
    544          try:
    545                  vacc = cVaccination(aPK_obj = result[0][0])
    546          except gmExceptions.ConstructorError:
    547                  _log.exception('cannot instantiate vaccination' % (result[0][0]), sys.exc_info, verbose=0)
    548                  return (False, _('internal error, check log'))
    549
    550          return (True, vacc)
    551  #--------------------------------------------------------
    552 -def get_vacc_courses():
    553          # FIXME: use cVaccinationCourse
    554          cmd = 'select name from clin.vaccination_course'
    555          rows = gmPG.run_ro_query('historica', cmd)
    556          if rows is None:
    557                  return None
    558          if len(rows) == 0:
    559                  return []
    560          data = []
    561          for row in rows:
    562                  data.extend(rows)
    563          return data
    564  #--------------------------------------------------------
    565 -def get_vacc_regimes_by_recommender_ordered(pk_patient=None, clear_cache=False):
    566          # check DbC, if it fails exception is due
    567          int(pk_patient)
    568
    569          cmd = """
    570  select fk_regime
    571  from clin.lnk_pat2vacc_reg l
    572  where l.fk_patient = %s""" % pk_patient
    573
    574          rows = gmPG.run_ro_query('historica', cmd)
    575          active = []
    576          if rows and len(rows):
    577                  active = [ r[0] for r in rows]
    578
    579          # FIXME: this is patient dependant so how would a cache
    580          # FIXME: work that's not taking into account pk_patient ?
    581  #       recommended_regimes = VaccByRecommender._recommended_regimes
    582  #       if not clear_cache and recommended_regimes:
    583  #               return recommended_regimes, active
    584
    585          r = ( {}, [] )
    586
    587          # FIXME: use views ?
    588          cmd = """
    589  select
    590          r.pk_regime ,
    591          r.pk_recommended_by ,
    592          r.indication,
    593          r.regime ,
    594          extract (epoch from d.min_age_due) /60/60/24,
    595          extract (epoch from d.max_age_due)  /60/60/24,
    596          extract (epoch from d.min_interval ) /60/60/24,
    597          d.seq_no
    598  from
    599          clin.v_vaccination_courses r, clin.vacc_def d
    600  where
    601          d.fk_regime = r.pk_regime
    602  order by
    603          r.pk_recommended_by, d.min_age_due"""
    604          #print cmd
    605          #import pdb
    606          #pdb.set_trace()
    607          #
    608          rows = gmPG.run_ro_query('historica', cmd)
    609          if rows is None:
    610                  VaccByRecommender._recommended_regimes = r
    611                  return r, active
    612
    613          row_fields = ['pk_regime', 'pk_recommender', 'indication' , 'regime', 'min_age_due', 'max_age_due', 'min_interval', 'seq_no' ]
    614
    615          for row in rows:
    616                  m = {}
    617                  for k, i in zip(row_fields, range(len(row))):
    618                          m[k] = row[i]
    619                  pk_recommender = m['pk_recommender']
    620
    621                  if not pk_recommender in r[0].keys():
    622                          r[0][pk_recommender] = []
    623                          r[1].append(pk_recommender)
    624                  r[0][pk_recommender].append(m)
    625
    626          for k, v in r[0].items():
    627                  print k
    628                  for x in v:
    629                          print '\t', x
    630
    631          VaccByRecommender._recommended_regimes = r
    632          return r, active
    633  #--------------------------------------------------------
    634 -def get_missing_vaccinations_ordered_min_due(pk_patient):
    635          # DbC
    636          int(pk_patient)
    637
    638          cmd = """
    639          select
    640                  indication, regime,
    641                  pk_regime,
    642                  pk_recommended_by,
    643                  seq_no ,
    644                  extract(epoch from age_due_min) /60/60/24 as age_due_min,
    645                  extract(epoch from age_due_max) /60/60/24 as age_due_max,
    646                  extract(epoch from min_interval)/60/60/24 as min_interval
    647          from
    648                  clin.v_pat_missing_vaccs
    649          where pk_patient = %s
    650          order by age_due_min, pk_recommended_by, indication
    651          """ % pk_patient
    652
    653          rows = gmPG.run_ro_query('historica', cmd)
    654
    655          return rows
    656  #--------------------------------------------------------
    657 -def get_indications_from_vaccinations(vaccinations=None):
    658          """Retrieves vaccination bundle indications list.
    659
    660                  * vaccinations = list of any type of vaccination
    661                          - indicated
    662                          - due vacc
    663                          - overdue vaccs
    664                          - due boosters
    665                          - arbitrary
    666          """
    667          # FIXME: can we not achieve this by:
    668          # [lambda [vacc['indication'], ['l10n_indication']] for vacc in vaccination_list]
    669          # I think we could, but we would be lacking error handling
    670          if vaccinations is None:
    671                  _log.error('list of vaccinations must be supplied')
    672                  return (False, [['ERROR: list of vaccinations not supplied', _('ERROR: list of vaccinations not supplied')]])
    673          if len(vaccinations) == 0:
    674                  return (True, [['empty list of vaccinations', _('empty list of vaccinations')]])
    675          inds = []
    676          for vacc in vaccinations:
    677                  try:
    678                          inds.append([vacc['indication'], vacc['l10n_indication']])
    679                  except KeyError:
    680                          try:
    681                                  inds.append([vacc['indication'], vacc['indication']])
    682                          except KeyError:
    683                                  inds.append(['vacc -> ind error: %s' % str(vacc), _('vacc -> ind error: %s') % str(vacc)])
    684          return (True, inds)
    685  #--------------------------------------------------------
    686 -def put_patient_on_schedule(patient_id=None, course=None):
    687          """
    688                  Schedules a vaccination course for a patient
    689
    690                  * patient_id = Patient's PK
    691                  * course = course object or Vaccination course's PK
    692          """
    693          # FIXME: add method schedule_vaccination_course() to gmPerson.cPatient
    694          if isinstance(course, cVaccinationCourse):
    695                  course_id = course['pk_course']
    696          else:
    697                  course_id = course
    698
    699          # insert new patient - vaccination course relation
    700          queries = []
    701          cmd = """insert into clin.lnk_pat2vacc_reg (fk_patient, fk_course)
    702                           values (%s, %s)"""
    703          queries.append((cmd, [patient_id, course_id]))
    704          result, msg = gmPG.run_commit('historica', queries, True)
    705          if result is None:
    706                  return (False, msg)
    707          return (True, msg)
    708  #--------------------------------------------------------
    709 -def remove_patient_from_schedule(patient_id=None, course=None):
    710          """unSchedules a vaccination course for a patient
    711
    712                  * patient_id = Patient's PK
    713                  * course = course object or Vaccination course's PK
    714          """
    715          # FIXME: add method schedule_vaccination_course() to gmPerson.cPatient
    716          if isinstance(course, cVaccinationCourse):
    717                  course_id = course['pk_course']
    718          else:
    719                  course_id = course
    720
    721          # delete  patient - vaccination course relation
    722          queries = []
    723          cmd = """delete from clin.lnk_pat2vacc_reg where fk_patient = %s and fk_course = %s"""
    724
    725          queries.append((cmd, [patient_id, course_id]))
    726          result, msg = gmPG.run_commit('historica', queries, True)
    727          if result is None:
    728                  return (False, msg)
    729          return (True, msg)
    730  #--------------------------------------------------------
    731 -def get_matching_vaccines_for_indications( all_ind):
    732
    733          quoted_inds = [ "'"+x + "%'" for x in all_ind]
    734
    735  #       cmd_inds_per_vaccine = """
    736  #               select count(v.trade_name) , v.trade_name
    737  #               from
    738  #                       clin.vaccine v, clin.lnk_vaccine2inds l, clin.vacc_indication i
    739  #               where
    740  #                       v.pk = l.fk_vaccine and l.fk_indication = i.id
    741  #               group
    742  #                       by trade_name
    743  #               """
    744
    745          cmd_inds_per_vaccine = """
    746  select
    747          count(trade_name),
    748          trade_name
    749  from clin.v_inds4vaccine
    750  group by trade_name"""
    751
    752          cmd_presence_in_vaccine = """
    753                          select count(v.trade_name) , v.trade_name
    754
    755                  from
    756                          clin.vaccine v, clin.lnk_vaccine2inds l, clin.vacc_indication i
    757                  where
    758                          v.pk = l.fk_vaccine and l.fk_indication = i.id
    759                  and
    760                          i.description like any ( array [ %s ] )
    761                  group
    762
    763                          by trade_name
    764
    765                  """             % ', '.join( quoted_inds )
    766
    767          inds_per_vaccine = gmPG.run_ro_query( 'historica', cmd_inds_per_vaccine)
    768
    769          presence_in_vaccine = gmPG.run_ro_query( 'historica', cmd_presence_in_vaccine)
    770
    771          map_vacc_count_inds = dict ( [ (x[1], x[0]) for x in inds_per_vaccine ] )
    772
    773          matched_vaccines = []
    774          for (presence, vaccine) in presence_in_vaccine:
    775                  if presence == len ( all_ind) :
    776                          # matched the number of indications selected with a vaccine
    777                          # is this also ALL the vaccine's indications ?
    778                          if map_vacc_count_inds[vaccine] == presence:
    779                                  matched_vaccines.append(vaccine)
    780          return matched_vaccines
    781  #============================================================
    782  # main - unit testing
    783  #------------------------------------------------------------
    784  if __name__ == '__main__':
    785
    786          if len(sys.argv) < 2:
    787                  sys.exit()
    788
    789          if sys.argv[1] != u'test':
    790                  sys.exit()
    791
    792  #       from Gnumed.pycommon import gmPG
    793          #--------------------------------------------------------
    794 -        def test_vacc():
    795                  vacc = cVaccination(aPK_obj=1)
    796                  print vacc
    797                  fields = vacc.get_fields()
    798                  for field in fields:
    799                          print field, ':', vacc[field]
    800                  print "updatable:", vacc.get_updatable_fields()
    801          #--------------------------------------------------------
    802 -        def test_due_vacc():
    803                  # Test for a due vaccination
    804                  pk_args = {
    805                          'pat_id': 12,
    806                          'indication': 'meningococcus C',
    807                          'seq_no': 1
    808                  }
    809                  missing_vacc = cMissingVaccination(aPK_obj=pk_args)
    810                  fields = missing_vacc.get_fields()
    811                  print "\nDue vaccination:"
    812                  print missing_vacc
    813                  for field in fields:
    814                          print field, ':', missing_vacc[field]
    815                  # Test for an overdue vaccination
    816                  pk_args = {
    817                          'pat_id': 12,
    818                          'indication': 'haemophilus influenzae b',
    819                          'seq_no': 2
    820                  }
    821                  missing_vacc = cMissingVaccination(aPK_obj=pk_args)
    822                  fields = missing_vacc.get_fields()
    823                  print "\nOverdue vaccination (?):"
    824                  print missing_vacc
    825                  for field in fields:
    826                          print field, ':', missing_vacc[field]
    827          #--------------------------------------------------------
    828 -        def test_due_booster():
    829                  pk_args = {
    830                          'pat_id': 12,
    831                          'indication': 'tetanus'
    832                  }
    833                  missing_booster = cMissingBooster(aPK_obj=pk_args)
    834                  fields = missing_booster.get_fields()
    835                  print "\nDue booster:"
    836                  print missing_booster
    837                  for field in fields:
    838                          print field, ':', missing_booster[field]
    839          #--------------------------------------------------------
    840 -        def test_scheduled_vacc():
    841                  scheduled_vacc = cScheduledVaccination(aPK_obj=20)
    842                  print "\nScheduled vaccination:"
    843                  print scheduled_vacc
    844                  fields = scheduled_vacc.get_fields()
    845                  for field in fields:
    846                          print field, ':', scheduled_vacc[field]
    847                  print "updatable:", scheduled_vacc.get_updatable_fields()
    848          #--------------------------------------------------------
    849 -        def test_vaccination_course():
    850                  vaccination_course = cVaccinationCourse(aPK_obj=7)
    851                  print "\nVaccination course:"
    852                  print vaccination_course
    853                  fields = vaccination_course.get_fields()
    854                  for field in fields:
    855                          print field, ':', vaccination_course[field]
    856                  print "updatable:", vaccination_course.get_updatable_fields()
    857          #--------------------------------------------------------
    858 -        def test_put_patient_on_schedule():
    859                  result, msg = put_patient_on_schedule(patient_id=12, course_id=1)
    860                  print '\nPutting patient id 12 on schedule id 1... %s (%s)' % (result, msg)
    861          #--------------------------------------------------------
    862 -        def test_get_vaccines():
    863
    864                  for vaccine in get_vaccines():
    865                          print vaccine
    866
    867          #--------------------------------------------------------
    868          #test_vaccination_course()
    869          #test_put_patient_on_schedule()
    870          #test_scheduled_vacc()
    871          #test_vacc()
    872          #test_due_vacc()
    873          #test_due_booster()
    874
    875          test_get_vaccines()
    876  #============================================================
    877