Gnumed.business.gmVaccination

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  __author__ = "K.Hilbert <Karsten.Hilbert@gmx.net>"
      5  __license__ = "GPL"
      6
      7  import sys
      8  import logging
      9  import io
     10
     11
     12  if __name__ == '__main__':
     13          sys.path.insert(0, '../../')
     14  from Gnumed.pycommon import gmBusinessDBObject
     15  from Gnumed.pycommon import gmPG2
     16  from Gnumed.pycommon import gmI18N
     17  from Gnumed.pycommon import gmTools
     18  from Gnumed.pycommon import gmDateTime
     19  if __name__ == '__main__':
     20          gmI18N.activate_locale()
     21          gmI18N.install_domain()
     22  from Gnumed.business import gmMedication
     23
     24
     25  _log = logging.getLogger('gm.vacc')
     26
     27  #============================================================
     28  URL_vaccination_plan = 'http://www.rki.de/DE/Content/Infekt/EpidBull/Archiv/2017/Ausgaben/34_17.pdf?__blob=publicationFile'
     29
     30  #============================================================
     31  _SQL_create_substance4vaccine = """-- in case <%(substance_tag)s> already exists: add ATC
     32  UPDATE ref.substance SET atc = '%(atc)s' WHERE lower(description) = lower('%(desc)s') AND atc IS NULL;
     33
     34  INSERT INTO ref.substance (description, atc)
     35          SELECT
     36                  '%(desc)s',
     37                  '%(atc)s'
     38          WHERE NOT EXISTS (
     39                  SELECT 1 FROM ref.substance WHERE
     40                          atc = '%(atc)s'
     41                                  AND
     42                          description = '%(desc)s'
     43          );
     44
     45  -- generic English
     46  SELECT i18n.upd_tx('en', '%(orig)s', '%(trans)s');
     47  -- user language, if any, fails if not set
     48  SELECT i18n.upd_tx('%(orig)s', '%(trans)s');"""
     49
     50  _SQL_map_indication2substance = """-- old-style "%(v21_ind)s" => "%(desc)s"
     51  INSERT INTO staging.lnk_vacc_ind2subst_dose (fk_indication, fk_dose, is_live)
     52          SELECT
     53                  (SELECT id FROM ref.vacc_indication WHERE description = '%(v21_ind)s'),
     54                  (SELECT pk_dose FROM ref.v_substance_doses WHERE
     55                          amount = 1
     56                                  AND
     57                          unit = 'dose'
     58                                  AND
     59                          dose_unit = 'shot'
     60                                  AND
     61                          substance = '%(desc)s'
     62                  ),
     63                  %(is_live)s
     64          WHERE EXISTS (
     65                  SELECT 1 FROM ref.vacc_indication WHERE description = '%(v21_ind)s'
     66          );"""
     67
     68  _SQL_create_vacc_product = """-- --------------------------------------------------------------
     69  -- in case <%(prod_name)s> exists: add ATC
     70  UPDATE ref.drug_product SET atc_code = '%(atc_prod)s' WHERE
     71          atc_code IS NULL
     72                  AND
     73          description = '%(prod_name)s'
     74                  AND
     75          preparation = '%(prep)s'
     76                  AND
     77          is_fake IS TRUE;
     78
     79  INSERT INTO ref.drug_product (description, preparation, is_fake, atc_code)
     80          SELECT
     81                  '%(prod_name)s',
     82                  '%(prep)s',
     83                  TRUE,
     84                  '%(atc_prod)s'
     85          WHERE NOT EXISTS (
     86                  SELECT 1 FROM ref.drug_product WHERE
     87                          description = '%(prod_name)s'
     88                                  AND
     89                          preparation = '%(prep)s'
     90                                  AND
     91                          is_fake = TRUE
     92                                  AND
     93                          atc_code = '%(atc_prod)s'
     94          );"""
     95
     96  _SQL_create_vaccine = """-- add vaccine if necessary
     97  INSERT INTO ref.vaccine (is_live, fk_drug_product)
     98          SELECT
     99                  %(is_live)s,
    100                  (SELECT pk FROM ref.drug_product WHERE
    101                          description = '%(prod_name)s'
    102                                  AND
    103                          preparation = '%(prep)s'
    104                                  AND
    105                          is_fake = TRUE
    106                                  AND
    107                          atc_code = '%(atc_prod)s'
    108                  )
    109          WHERE NOT EXISTS (
    110                  SELECT 1 FROM ref.vaccine WHERE
    111                          is_live IS %(is_live)s
    112                                  AND
    113                          fk_drug_product = (
    114                                  SELECT pk FROM ref.drug_product WHERE
    115                                          description = '%(prod_name)s'
    116                                                  AND
    117                                          preparation = '%(prep)s'
    118                                                  AND
    119                                          is_fake = TRUE
    120                                                  AND
    121                                          atc_code = '%(atc_prod)s'
    122                          )
    123          );"""
    124
    125  _SQL_create_vacc_subst_dose = """-- create dose, assumes substance exists
    126  INSERT INTO ref.dose (fk_substance, amount, unit, dose_unit)
    127          SELECT
    128                  (SELECT pk FROM ref.substance WHERE atc = '%(atc_subst)s' AND description = '%(name_subst)s' LIMIT 1),
    129                  1,
    130                  'dose',
    131                  'shot'
    132          WHERE NOT EXISTS (
    133                  SELECT 1 FROM ref.dose WHERE
    134                          fk_substance = (SELECT pk FROM ref.substance WHERE atc = '%(atc_subst)s' AND description = '%(name_subst)s' LIMIT 1)
    135                                  AND
    136                          amount = 1
    137                                  AND
    138                          unit = 'dose'
    139                                  AND
    140                          dose_unit IS NOT DISTINCT FROM 'shot'
    141          );"""
    142
    143  _SQL_link_dose2vacc_prod = """-- link dose to product
    144  INSERT INTO ref.lnk_dose2drug (fk_dose, fk_drug_product)
    145          SELECT
    146                  (SELECT pk from ref.dose WHERE
    147                          fk_substance = (SELECT pk FROM ref.substance WHERE atc = '%(atc_subst)s' AND description = '%(name_subst)s' LIMIT 1)
    148                                  AND
    149                          amount = 1
    150                                  AND
    151                          unit = 'dose'
    152                                  AND
    153                          dose_unit IS NOT DISTINCT FROM 'shot'
    154                  ),
    155                  (SELECT pk FROM ref.drug_product WHERE
    156                          description = '%(prod_name)s'
    157                                  AND
    158                          preparation = '%(prep)s'
    159                                  AND
    160                          is_fake = TRUE
    161                                  AND
    162                          atc_code = '%(atc_prod)s'
    163                  )
    164          WHERE NOT EXISTS (
    165                  SELECT 1 FROM ref.lnk_dose2drug WHERE
    166                          fk_dose = (
    167                                  SELECT PK from ref.dose WHERE
    168                                          fk_substance = (SELECT pk FROM ref.substance WHERE atc = '%(atc_subst)s' AND description = '%(name_subst)s' LIMIT 1)
    169                                                  AND
    170                                          amount = 1
    171                                                  AND
    172                                          unit = 'dose'
    173                                                  AND
    174                                          dose_unit IS NOT DISTINCT FROM 'shot'
    175                          )
    176                                  AND
    177                          fk_drug_product = (
    178                                  SELECT pk FROM ref.drug_product WHERE
    179                                          description = '%(prod_name)s'
    180                                                  AND
    181                                          preparation = '%(prep)s'
    182                                                  AND
    183                                          is_fake = TRUE
    184                                                  AND
    185                                          atc_code = '%(atc_prod)s'
    186                          )
    187          );"""
    188
    189  _SQL_create_indications_mapping_table = """-- set up helper table for conversion of vaccines from using
    190  -- linked indications to using linked substances,
    191  -- to be dropped after converting vaccines
    192  DROP TABLE IF EXISTS staging.lnk_vacc_ind2subst_dose CASCADE;
    193
    194  CREATE UNLOGGED TABLE staging.lnk_vacc_ind2subst_dose (
    195          fk_indication INTEGER
    196                  NOT NULL
    197                  REFERENCES ref.vacc_indication(id)
    198                          ON UPDATE CASCADE
    199                          ON DELETE RESTRICT,
    200          fk_dose INTEGER
    201                  NOT NULL
    202                  REFERENCES ref.dose(pk)
    203                          ON UPDATE CASCADE
    204                          ON DELETE RESTRICT,
    205          is_live
    206                  BOOLEAN
    207                  NOT NULL
    208                  DEFAULT false,
    209          UNIQUE(fk_indication, fk_dose),
    210          UNIQUE(fk_indication, is_live)
    211  );
    212
    213
    214  DROP VIEW IF EXISTS staging.v_lnk_vacc_ind2subst_dose CASCADE;
    215
    216  CREATE VIEW staging.v_lnk_vacc_ind2subst_dose AS
    217  SELECT
    218          s_lvi2sd.is_live
    219                  as mapping_is_for_live_vaccines,
    220          r_vi.id
    221                  as pk_indication,
    222          r_vi.description
    223                  as indication,
    224          r_vi.atcs_single_indication,
    225          r_vi.atcs_combi_indication,
    226          r_d.pk
    227                  as pk_dose,
    228          r_d.amount,
    229          r_d.unit,
    230          r_d.dose_unit,
    231          r_s.pk
    232                  as pk_substance,
    233          r_s.description
    234                  as substance,
    235          r_s.atc
    236                  as atc_substance
    237  FROM
    238          staging.lnk_vacc_ind2subst_dose s_lvi2sd
    239                  inner join ref.vacc_indication r_vi on (r_vi.id = s_lvi2sd.fk_indication)
    240                  inner join ref.dose r_d on (r_d.pk = s_lvi2sd.fk_dose)
    241                          inner join ref.substance r_s on (r_s.pk = r_d.fk_substance)
    242  ;"""
    243
    244  _SQL_create_generic_vaccines_script = """-- ==============================================================
    245  -- GNUmed database schema change script
    246  --
    247  -- License: GPL v2 or later
    248  -- Author: karsten.hilbert@gmx.net
    249  --
    250  -- THIS IS A GENERATED FILE. DO NOT EDIT.
    251  --
    252  -- ==============================================================
    253  \set ON_ERROR_STOP 1
    254  --set default_transaction_read_only to off;
    255
    256  -- --------------------------------------------------------------
    257  -- indications mapping helper table
    258  -- --------------------------------------------------------------
    259  %s
    260
    261  -- --------------------------------------------------------------
    262  -- generic vaccine "substances" (= indications)
    263  -- --------------------------------------------------------------
    264  %s
    265
    266  -- --------------------------------------------------------------
    267  -- generic vaccines
    268  -- --------------------------------------------------------------
    269  -- new-style vaccines are not linked to indications, so drop
    270  -- trigger asserting that condition,
    271  DROP FUNCTION IF EXISTS clin.trf_sanity_check_vaccine_has_indications() CASCADE;
    272
    273
    274  -- need to disable trigger before running
    275  ALTER TABLE ref.drug_product
    276          DISABLE TRIGGER tr_assert_product_has_components
    277  ;
    278
    279  %s
    280
    281  -- want to re-enable trigger as now all inserted
    282  -- vaccines satisfy the conditions
    283  ALTER TABLE ref.drug_product
    284          ENABLE TRIGGER tr_assert_product_has_components
    285  ;
    286
    287  -- --------------------------------------------------------------
    288  -- indications mapping data
    289  -- --------------------------------------------------------------
    290  -- map old style
    291  --              (clin|ref).vacc_indication.description
    292  -- to new style
    293  --              ref.v_substance_doses.substance
    294
    295  %s
    296
    297  -- --------------------------------------------------------------
    298  select gm.log_script_insertion('v%s-ref-create_generic_vaccines.sql', '%s');
    299  """
    300
    301  #============================================================
    302 -def write_generic_vaccine_sql(version, include_indications_mapping=False, filename=None):
    303          if filename is None:
    304                  filename = gmTools.get_unique_filename(suffix = '.sql')
    305          _log.debug('writing SQL for creating generic vaccines to: %s', filename)
    306          sql_file = io.open(filename, mode = 'wt', encoding = 'utf8')
    307          sql_file.write(create_generic_vaccine_sql (
    308                  version,
    309                  include_indications_mapping = include_indications_mapping
    310          ))
    311          sql_file.close()
    312          return filename
    313
    314  #------------------------------------------------------------
    315 -def create_generic_vaccine_sql(version, include_indications_mapping=False):
    316
    317          _log.debug('including indications mapping table with generic vaccines creation SQL: %s', include_indications_mapping)
    318
    319          from Gnumed.business import gmVaccDefs
    320
    321          sql_create_substances = []
    322          sql_populate_ind2subst_map = []
    323          sql_create_vaccines = []
    324
    325          for substance_tag in gmVaccDefs._VACCINE_SUBSTANCES:
    326                  subst = gmVaccDefs._VACCINE_SUBSTANCES[substance_tag]
    327                  args = {
    328                          'substance_tag': substance_tag,
    329                          'atc': subst['atc4target'],
    330                          'desc': subst['name'],
    331                          'orig': subst['target'].split('::')[0],
    332                          'trans': subst['target'].split('::')[-1]
    333                  }
    334                  sql_create_substances.append(_SQL_create_substance4vaccine % args)
    335                  try:
    336                          for v21_ind in subst['v21_indications']:
    337                                  args['v21_ind'] = v21_ind
    338                                  args['is_live'] = 'false'
    339                                  sql_populate_ind2subst_map.append(_SQL_map_indication2substance % args)
    340                  except KeyError:
    341                          pass
    342                  try:
    343                          for v21_ind in subst['v21_indications_live']:
    344                                  args['v21_ind'] = v21_ind
    345                                  args['is_live'] = 'true'
    346                                  sql_populate_ind2subst_map.append(_SQL_map_indication2substance % args)
    347                  except KeyError:
    348                          pass
    349                  args = {}
    350
    351          for key in gmVaccDefs._GENERIC_VACCINES:
    352                  vaccine_def = gmVaccDefs._GENERIC_VACCINES[key]
    353                  # create product
    354                  args = {
    355                          'atc_prod': vaccine_def['atc'],
    356                          'prod_name': vaccine_def['name'],
    357                          # generic vaccines always have the English preparation
    358                          'prep': 'vaccine',
    359                          'is_live': vaccine_def['live']
    360                  }
    361                  sql_create_vaccines.append(_SQL_create_vacc_product % args)
    362                  # create doses
    363                  for ingredient_tag in vaccine_def['ingredients']:
    364                          vacc_subst_def = gmVaccDefs._VACCINE_SUBSTANCES[ingredient_tag]
    365                          args['atc_subst'] = vacc_subst_def['atc4target']
    366                          args['name_subst'] = vacc_subst_def['name']
    367                          # substance already created, only need to create dose
    368                          sql_create_vaccines.append(_SQL_create_vacc_subst_dose % args)
    369                          # link dose to product
    370                          sql_create_vaccines.append(_SQL_link_dose2vacc_prod % args)
    371                          # the following does not work because there are mixed vaccines
    372                          # any live ingredients included ?
    373  #                       if vacc_subst_def.has_key('v21_indications_live'):
    374  #                               if vaccine_def['live'] is False:
    375  #                                       print vaccine_def
    376  #                                       raise Exception('vaccine def says "NOT live" but ingredients DO map to <v21_indications_LIVE>')
    377  #                       if vacc_subst_def.has_key('v21_indications'):
    378  #                               if vaccine_def['live'] is True:
    379  #                                       print vaccine_def
    380  #                                       raise Exception('vaccine def says "live" but ingredients do NOT map to v21_indications_LIVE')
    381
    382                  # create vaccine
    383                  sql_create_vaccines.append(_SQL_create_vaccine % args)
    384
    385          # join
    386          sql = _SQL_create_generic_vaccines_script % (
    387                  gmTools.bool2subst (
    388                          include_indications_mapping,
    389                          _SQL_create_indications_mapping_table,
    390                          '-- indications mapping table not included'
    391                  ),
    392                  '\n\n'.join(sql_create_substances),
    393                  '\n\n'.join(sql_create_vaccines),
    394                  gmTools.bool2subst (
    395                          include_indications_mapping,
    396                          '\n\n'.join(sql_populate_ind2subst_map),
    397                          '-- indications mapping table not populated'
    398                  ),
    399                  version,
    400                  version
    401          )
    402          return sql
    403
    404  #============================================================
    405  # vaccine related code
    406  #------------------------------------------------------------
    407  _SQL_get_vaccine_fields = """SELECT * FROM ref.v_vaccines WHERE %s"""
    408
    409 -class cVaccine(gmBusinessDBObject.cBusinessDBObject):
    410          """Represents one vaccine."""
    411
    412          _cmd_fetch_payload = _SQL_get_vaccine_fields % "pk_vaccine = %s"
    413
    414          _cmds_store_payload = [
    415                  """UPDATE ref.vaccine SET
    416                                  --id_route = %(pk_route)s,
    417                                  is_live = %(is_live)s,
    418                                  min_age = %(min_age)s,
    419                                  max_age = %(max_age)s,
    420                                  comment = gm.nullify_empty_string(%(comment)s),
    421                                  fk_drug_product = %(pk_drug_product)s
    422                          WHERE
    423                                  pk = %(pk_vaccine)s
    424                                          AND
    425                                  xmin = %(xmin_vaccine)s
    426                          RETURNING
    427                                  xmin as xmin_vaccine
    428                  """
    429          ]
    430
    431          _updatable_fields = [
    432                  #'pk_route',
    433                  'is_live',
    434                  'min_age',
    435                  'max_age',
    436                  'comment',
    437                  'pk_drug_product'
    438          ]
    439
    440          #--------------------------------------------------------
    441 -        def format(self, *args, **kwargs):
    442                  lines = []
    443                  lines.append(_('%s with %s %s     #%s') % (
    444                          gmTools.bool2subst(self._payload[self._idx['is_live']], _('Live vaccine'), _('Inactive vaccine'), '<liveness error in DB>'),
    445                          len(self._payload[self._idx['indications']]),
    446                          gmTools.bool2subst(len(self._payload[self._idx['indications']]) == 1, _('indication'), _('indications'), _('indication(s)')),
    447                          self._payload[self._idx['pk_vaccine']]
    448                  ))
    449                  lines.append(_(' Product: "%s"     #%s') % (
    450                          self._payload[self._idx['vaccine']],
    451                          self._payload[self._idx['pk_drug_product']]
    452                  ))
    453                  lines.append(_('  %s%s%s%s') % (
    454                          self._payload[self._idx['l10n_preparation']],
    455                          gmTools.coalesce(gmTools.bool2subst(self._payload[self._idx['is_fake_vaccine']], _('fake product'), None, None), '', ', %s'),
    456                          gmTools.coalesce(self._payload[self._idx['atc_code']], '', ' [ATC:%s]'),
    457                          gmTools.coalesce(self._payload[self._idx['external_code']], '', ' [%s:%%s]' % self._payload[self._idx['external_code_type']])
    458                  ))
    459                  #lines.append(_(u' %sage %s - %s') % (
    460                  #       gmTools.coalesce(self._payload[self._idx['route_description']], u'', u'%s, '),          #route_abbreviation
    461                  lines.append(_(' Age %s - %s') % (
    462                          gmTools.coalesce(self._payload[self._idx['min_age']], '?'),
    463                          gmTools.coalesce(self._payload[self._idx['max_age']], '?')
    464                  ))
    465                  if self._payload[self._idx['comment']] is not None:
    466                          lines.extend([ ' %s' % l for l in self._payload[self._idx['comment']].split('\n')] )
    467                  lines.append(_(' Indications'))
    468                  lines.extend( [ '  %s [ATC:%s]' % (i['l10n_indication'], i['atc_indication']) for i in self._payload[self._idx['indications']] ])
    469
    470                  return lines
    471
    472          #--------------------------------------------------------
    473          # properties
    474          #--------------------------------------------------------
    475 -        def _get_product(self):
    476                  return gmMedication.cDrugProduct(aPK_obj = self._payload[self._idx['pk_drug_product']])
    477
    478          product = property(_get_product, lambda x:x)
    479
    480          #--------------------------------------------------------
    481 -        def _get_is_in_use(self):
    482                  cmd = 'SELECT EXISTS(SELECT 1 FROM clin.vaccination WHERE fk_vaccine = %(pk)s)'
    483                  args = {'pk': self._payload[self._idx['pk_vaccine']]}
    484                  rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
    485                  return rows[0][0]
    486
    487          is_in_use = property(_get_is_in_use, lambda x:x)
    488
    489  #------------------------------------------------------------
    490 -def create_vaccine(pk_drug_product=None, product_name=None, indications=None, is_live=None):
    491
    492          assert (is_live is not None), '<is_live> must not be <None>'
    493
    494          conn = gmPG2.get_connection(readonly = False)
    495          if pk_drug_product is None:
    496                  #prep = _('vaccine')
    497                  prep = 'vaccine'
    498                  _log.debug('creating vaccine drug product [%s %s]', product_name, prep)
    499                  vacc_prod = gmMedication.create_drug_product (
    500                          product_name = product_name,
    501                          preparation = prep,
    502                          return_existing = True,
    503                          # indications are ref.dose rows
    504                          doses = indications,
    505                          link_obj = conn
    506                  )
    507                  #conn.commit()
    508                  vacc_prod['atc'] = 'J07'
    509                  vacc_prod.save(conn = conn)
    510                  pk_drug_product = vacc_prod['pk_drug_product']
    511          cmd = 'INSERT INTO ref.vaccine (fk_drug_product, is_live) values (%(pk_drug_product)s, %(live)s) RETURNING pk'
    512          queries = [{'cmd': cmd, 'args': {'pk_drug_product': pk_drug_product, 'live': is_live}}]
    513          rows, idx = gmPG2.run_rw_queries(link_obj = conn, queries = queries, get_col_idx = False, return_data = True, end_tx = True)
    514          conn.close()
    515          return cVaccine(aPK_obj = rows[0]['pk'])
    516
    517  #------------------------------------------------------------
    518 -def delete_vaccine(vaccine=None):
    519
    520          cmd = 'DELETE FROM ref.vaccine WHERE pk = %(pk)s'
    521          args = {'pk': vaccine}
    522
    523          try:
    524                  gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
    525          except gmPG2.dbapi.IntegrityError:
    526                  _log.exception('cannot delete vaccine [%s]', vaccine)
    527                  return False
    528
    529          return True
    530
    531  #------------------------------------------------------------
    532 -def get_vaccines(order_by=None):
    533
    534          if order_by is None:
    535                  cmd = _SQL_get_vaccine_fields % 'TRUE'
    536          else:
    537                  cmd = _SQL_get_vaccine_fields % ('TRUE\nORDER BY %s' % order_by)
    538
    539          rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = True)
    540
    541          return [ cVaccine(row = {'data': r, 'idx': idx, 'pk_field': 'pk_vaccine'}) for r in rows ]
    542
    543  #============================================================
    544  # vaccination related classes
    545  #============================================================
    546  _SQL_get_vaccination_fields = """SELECT * FROM clin.v_vaccinations WHERE %s"""
    547
    548 -class cVaccination(gmBusinessDBObject.cBusinessDBObject):
    549
    550          _cmd_fetch_payload = _SQL_get_vaccination_fields % "pk_vaccination = %s"
    551
    552          _cmds_store_payload = [
    553                  """UPDATE clin.vaccination SET
    554                                  soap_cat = %(soap_cat)s,
    555                                  clin_when = %(date_given)s,
    556                                  site = gm.nullify_empty_string(%(site)s),
    557                                  batch_no = gm.nullify_empty_string(%(batch_no)s),
    558                                  reaction = gm.nullify_empty_string(%(reaction)s),
    559                                  narrative = gm.nullify_empty_string(%(comment)s),
    560                                  fk_vaccine = %(pk_vaccine)s,
    561                                  fk_provider = %(pk_provider)s,
    562                                  fk_encounter = %(pk_encounter)s,
    563                                  fk_episode = %(pk_episode)s
    564                          WHERE
    565                                  pk = %(pk_vaccination)s
    566                                          AND
    567                                  xmin = %(xmin_vaccination)s
    568                          RETURNING
    569                                  xmin as xmin_vaccination
    570                  """
    571          ]
    572
    573          _updatable_fields = [
    574                  'soap_cat',
    575                  'date_given',
    576                  'site',
    577                  'batch_no',
    578                  'reaction',
    579                  'comment',
    580                  'pk_vaccine',
    581                  'pk_provider',
    582                  'pk_encounter',
    583                  'pk_episode'
    584          ]
    585
    586          #--------------------------------------------------------
    587 -        def format_maximum_information(self, patient=None):
    588                  return self.format (
    589                          with_indications = True,
    590                          with_comment = True,
    591                          with_reaction = True,
    592                          date_format = '%Y %b %d'
    593                  )
    594
    595          #--------------------------------------------------------
    596 -        def format(self, with_indications=False, with_comment=False, with_reaction=False, date_format='%Y-%m-%d'):
    597
    598                  lines = []
    599
    600                  lines.append (' %s: %s [%s]%s' % (
    601                          self._payload[self._idx['date_given']].strftime(date_format),
    602                          self._payload[self._idx['vaccine']],
    603                          self._payload[self._idx['batch_no']],
    604                          gmTools.coalesce(self._payload[self._idx['site']], '', ' (%s)')
    605                  ))
    606
    607                  if with_comment:
    608                          if self._payload[self._idx['comment']] is not None:
    609                                  lines.append('   %s' % self._payload[self._idx['comment']])
    610
    611                  if with_reaction:
    612                          if self._payload[self._idx['reaction']] is not None:
    613                                  lines.append('   %s' % self._payload[self._idx['reaction']])
    614
    615                  if with_indications:
    616                          lines.append('   %s' % ' / '.join([ i['l10n_indication'] for i in self._payload[self._idx['indications']] ]))
    617
    618                  return lines
    619
    620          #--------------------------------------------------------
    621 -        def _get_vaccine(self):
    622                  return cVaccine(aPK_obj = self._payload[self._idx['pk_vaccine']])
    623
    624          vaccine = property(_get_vaccine, lambda x:x)
    625
    626  #------------------------------------------------------------
    627 -def get_vaccinations():
    628          cmd = _SQL_get_vaccination_fields % 'True'
    629          args = {}
    630          rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = True)
    631          return [ cVaccination(row = {'data': r, 'idx': idx, 'pk_field': 'pk_vaccine'}) for r in rows ]
    632
    633  #------------------------------------------------------------
    634 -def create_vaccination(encounter=None, episode=None, vaccine=None, batch_no=None):
    635
    636          cmd = """
    637                  INSERT INTO clin.vaccination (
    638                          fk_encounter,
    639                          fk_episode,
    640                          fk_vaccine,
    641                          batch_no
    642                  ) VALUES (
    643                          %(enc)s,
    644                          %(epi)s,
    645                          %(vacc)s,
    646                          %(batch)s
    647                  ) RETURNING pk;
    648          """
    649          args = {
    650                  'enc': encounter,
    651                  'epi': episode,
    652                  'vacc': vaccine,
    653                  'batch': batch_no
    654          }
    655
    656          rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False, return_data = True)
    657
    658          return cVaccination(aPK_obj = rows[0][0])
    659
    660  #------------------------------------------------------------
    661 -def delete_vaccination(vaccination=None):
    662          cmd = """DELETE FROM clin.vaccination WHERE pk = %(pk)s"""
    663          args = {'pk': vaccination}
    664
    665          gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
    666
    667  #------------------------------------------------------------
    668
    669 -def format_latest_vaccinations(output_format='latex', emr=None):
    670
    671          _log.debug('formatting latest vaccinations into [%s]', output_format)
    672
    673          vaccs = emr.get_latest_vaccinations()
    674
    675          if output_format == 'latex':
    676                  return __format_latest_vaccinations_latex(vaccinations = vaccs)
    677
    678          msg = _('unknown vaccinations output format [%s]') % output_format
    679          _log.error(msg)
    680          return msg
    681
    682  #------------------------------------------------------------
    683
    684 -def __format_latest_vaccinations_latex(vaccinations=None):
    685
    686          if len(vaccinations) == 0:
    687                  return '\\noindent %s' % _('No vaccinations recorded.')
    688
    689          tex =  '\\noindent %s {\\tiny (%s)\\par}\n' % (_('Latest vaccinations'), _('per target condition'))
    690          tex += '\n'
    691          tex += '\\noindent \\begin{tabular}{|l|l|l|l|l|l|}\n'
    692          tex += '\\hline\n'
    693          tex += '%s & %s & {\\footnotesize %s} & {\\footnotesize %s} & {\\footnotesize %s\\footnotemark} & {\\footnotesize $\\Sigma$\\footnotemark}\\\\\n' % (
    694                  _('Target'),
    695                  _('Last given'),
    696                  _('Vaccine'),
    697                  _('Lot \#'),
    698                  _('SoaP')
    699          )
    700          tex += '\\hline\n'
    701          tex += '\n'
    702          tex += '\\hline\n'
    703          tex += '%s'                     # this is where the actual vaccination rows end up
    704          tex += '\n'
    705          tex += '\\end{tabular}\n'
    706          tex += '\n'
    707          tex += '\\addtocounter{footnote}{-1}\n'
    708          tex += '\\footnotetext{%s}\n' % _('SoaP -- "S"ubjective: vaccination was remembered by patient. "P"lan: vaccination was administered in the practice or copied from trustworthy records.')
    709          tex += '\\addtocounter{footnote}{1}\n'
    710          tex += '\\footnotetext{$\\Sigma$ -- %s}\n' % _('Total number of vaccinations recorded for the corresponding target condition.')
    711          tex += '\n'
    712
    713          row_template = '%s & %s & {\\scriptsize %s} & {\\scriptsize %s} & {\\scriptsize %s} & {\\scriptsize %s}\\\\\n'
    714          lines = ''
    715          targets = sorted(vaccinations.keys())
    716          for target in targets:
    717                  target_count, vacc = vaccinations[target]
    718                  lines += row_template % (
    719                          target,
    720                          gmDateTime.pydt_strftime(vacc['date_given'], '%Y %b %d'),
    721                          vacc['vaccine'],
    722                          gmTools.tex_escape_string(vacc['batch_no'].strip()),
    723                          vacc['soap_cat'].upper(),
    724                          target_count
    725                  )
    726                  if vacc['site'] is not None:
    727                          lines += ' & \\multicolumn{5}{l|}{\\scriptsize %s: %s\\par}\\\\\n' % (_('Injection site'), vacc['site'].strip())
    728                  if vacc['reaction'] is not None:
    729                          lines += ' & \\multicolumn{5}{l|}{\\scriptsize %s: %s\\par}\\\\\n' % (_('Reaction'), vacc['reaction'].strip())
    730                  if vacc['comment'] is not None:
    731                          lines += ' & \\multicolumn{5}{l|}{\\scriptsize %s: %s\\par}\\\\\n' % (_('Comment'), vacc['comment'].strip())
    732                  lines += '\\hline\n'
    733
    734          return tex % lines
    735
    736  #============================================================
    737  # main - unit testing
    738  #------------------------------------------------------------
    739  if __name__ == '__main__':
    740
    741          if len(sys.argv) < 2:
    742                  sys.exit()
    743
    744          if sys.argv[1] != 'test':
    745                  sys.exit()
    746
    747  #       from Gnumed.pycommon import gmPG
    748          #--------------------------------------------------------
    749 -        def test_vacc():
    750                  vacc = cVaccination(aPK_obj=1)
    751                  print(vacc)
    752                  fields = vacc.get_fields()
    753                  for field in fields:
    754                          print(field, ':', vacc[field])
    755                  print("updatable:", vacc.get_updatable_fields())
    756
    757          #--------------------------------------------------------
    758 -        def test_due_vacc():
    759                  # Test for a due vaccination
    760                  pk_args = {
    761                          'pat_id': 12,
    762                          'indication': 'meningococcus C',
    763                          'seq_no': 1
    764                  }
    765                  missing_vacc = cMissingVaccination(aPK_obj=pk_args)
    766                  fields = missing_vacc.get_fields()
    767                  print("\nDue vaccination:")
    768                  print(missing_vacc)
    769                  for field in fields:
    770                          print(field, ':', missing_vacc[field])
    771                  # Test for an overdue vaccination
    772                  pk_args = {
    773                          'pat_id': 12,
    774                          'indication': 'haemophilus influenzae b',
    775                          'seq_no': 2
    776                  }
    777                  missing_vacc = cMissingVaccination(aPK_obj=pk_args)
    778                  fields = missing_vacc.get_fields()
    779                  print("\nOverdue vaccination (?):")
    780                  print(missing_vacc)
    781                  for field in fields:
    782                          print(field, ':', missing_vacc[field])
    783
    784          #--------------------------------------------------------
    785 -        def test_due_booster():
    786                  pk_args = {
    787                          'pat_id': 12,
    788                          'indication': 'tetanus'
    789                  }
    790                  missing_booster = cMissingBooster(aPK_obj=pk_args)
    791                  fields = missing_booster.get_fields()
    792                  print("\nDue booster:")
    793                  print(missing_booster)
    794                  for field in fields:
    795                          print(field, ':', missing_booster[field])
    796
    797          #--------------------------------------------------------
    798 -        def test_scheduled_vacc():
    799                  scheduled_vacc = cScheduledVaccination(aPK_obj=20)
    800                  print("\nScheduled vaccination:")
    801                  print(scheduled_vacc)
    802                  fields = scheduled_vacc.get_fields()
    803                  for field in fields:
    804                          print(field, ':', scheduled_vacc[field])
    805                  print("updatable:", scheduled_vacc.get_updatable_fields())
    806
    807          #--------------------------------------------------------
    808 -        def test_vaccination_course():
    809                  vaccination_course = cVaccinationCourse(aPK_obj=7)
    810                  print("\nVaccination course:")
    811                  print(vaccination_course)
    812                  fields = vaccination_course.get_fields()
    813                  for field in fields:
    814                          print(field, ':', vaccination_course[field])
    815                  print("updatable:", vaccination_course.get_updatable_fields())
    816
    817          #--------------------------------------------------------
    818 -        def test_put_patient_on_schedule():
    819                  result, msg = put_patient_on_schedule(patient_id=12, course_id=1)
    820                  print('\nPutting patient id 12 on schedule id 1... %s (%s)' % (result, msg))
    821
    822          #--------------------------------------------------------
    823 -        def test_get_vaccines():
    824                  for vaccine in get_vaccines():
    825                          print('--------------------------------')
    826                          #print u'%s' % vaccine
    827                          print('\n'.join(vaccine.format()))
    828
    829          #--------------------------------------------------------
    830 -        def test_get_vaccinations():
    831                  for v in get_vaccinations():
    832                          print(v)
    833
    834          #--------------------------------------------------------
    835 -        def test_create_generic_vaccine_sql():
    836                  print(create_generic_vaccine_sql('22.0'))
    837
    838          #--------------------------------------------------------
    839 -        def test_write_generic_vaccine_sql(version, filename):
    840                  print(write_generic_vaccine_sql (
    841                          version,
    842                          include_indications_mapping = True,
    843                          filename = filename
    844                  ))
    845
    846          #--------------------------------------------------------
    847          #test_vaccination_course()
    848          #test_put_patient_on_schedule()
    849          #test_scheduled_vacc()
    850          #test_vacc()
    851          #test_due_vacc()
    852          #test_due_booster()
    853
    854          #test_get_vaccines()
    855          test_get_vaccinations()
    856          #test_create_generic_vaccine_sql()
    857          #test_write_generic_vaccine_sql(sys.argv[2], sys.argv[3])
    858