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