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

# Source Code for Module Gnumed.business.gmAutoHints

      1  # -*- coding: utf-8 -*-
      2  """GNUmed auto hints middleware.
      3
      4  This should eventually end up in a class cPractice.
      5  """
      6  #============================================================
      7  __license__ = "GPL"
      8  __author__ = "K.Hilbert <Karsten.Hilbert@gmx.net>"
      9
     10
     11  import sys
     12  import logging
     13
     14
     15  if __name__ == '__main__':
     16          sys.path.insert(0, '../../')
     17  from Gnumed.pycommon import gmPG2
     18  from Gnumed.pycommon import gmBusinessDBObject
     19  from Gnumed.pycommon import gmTools
     20  from Gnumed.pycommon import gmDateTime
     21
     22  from Gnumed.business import gmStaff
     23
     24  _log = logging.getLogger('gm.hints')
     25
     26  #============================================================
     27  # dynamic hints API
     28  #------------------------------------------------------------
     29  _SQL_get_dynamic_hints = "SELECT * FROM ref.v_auto_hints WHERE %s"
     30
     31 -class cDynamicHint(gmBusinessDBObject.cBusinessDBObject):
     32          """Represents dynamic hints to be run against the database."""
     33
     34          _cmd_fetch_payload = _SQL_get_dynamic_hints % "pk_auto_hint = %s"
     35          _cmds_store_payload = [
     36                  """UPDATE ref.auto_hint SET
     37                                  query = gm.nullify_empty_string(%(query)s),
     38                                  recommendation_query = gm.nullify_empty_string(%(recommendation_query)s),
     39                                  title = gm.nullify_empty_string(%(title)s),
     40                                  hint = gm.nullify_empty_string(%(hint)s),
     41                                  url = gm.nullify_empty_string(%(url)s),
     42                                  source = gm.nullify_empty_string(%(source)s),
     43                                  is_active = %(is_active)s,
     44                                  popup_type = %(popup_type)s,
     45                                  highlight_as_priority = %(highlight_as_priority)s
     46                          WHERE
     47                                  pk = %(pk_auto_hint)s
     48                                          AND
     49                                  xmin = %(xmin_auto_hint)s
     50                          RETURNING
     51                                  xmin AS xmin_auto_hint
     52                  """
     53          ]
     54          _updatable_fields = [
     55                  'query',
     56                  'recommendation_query',
     57                  'title',
     58                  'hint',
     59                  'url',
     60                  'source',
     61                  'is_active',
     62                  'popup_type',
     63                  'highlight_as_priority'
     64          ]
     65          #--------------------------------------------------------
     66 -        def format_maximum_information(self, patient):
     67                  return self.format(include_sql = True).split('\n')
     68
     69          #--------------------------------------------------------
     70 -        def format(self, include_sql=False):
     71                  txt = '%s               [#%s]\n' % (
     72                          gmTools.bool2subst(self._payload[self._idx['is_active']], _('Active clinical hint'), _('Inactive clinical hint')),
     73                          self._payload[self._idx['pk_auto_hint']]
     74                  )
     75                  txt += '\n'
     76                  txt += self._payload[self._idx['title']]
     77                  txt += '\n'
     78                  txt += '\n'
     79                  txt += _('Source: %s\n') % self._payload[self._idx['source']]
     80                  txt += _('Language: %s\n') % self._payload[self._idx['lang']]
     81                  txt += '\n'
     82                  txt += gmTools.wrap(self._payload[self._idx['hint']], width = 50, initial_indent = ' ', subsequent_indent = ' ')
     83                  txt += '\n'
     84                  txt += '\n'
     85                  if self._payload[self._idx['recommendation']] is not None:
     86                          txt += gmTools.wrap(self._payload[self._idx['recommendation']], width = 50, initial_indent = ' ', subsequent_indent = ' ')
     87                          txt += '\n'
     88                          txt += '\n'
     89                  txt += gmTools.wrap (
     90                          gmTools.coalesce(self._payload[self._idx['url']], ''),
     91                          width = 50,
     92                          initial_indent = ' ',
     93                          subsequent_indent = ' '
     94                  )
     95                  txt += '\n'
     96                  if include_sql:
     97                          txt += '\n'
     98                          txt += gmTools.wrap(self._payload[self._idx['query']], width = 50, initial_indent = ' ', subsequent_indent = ' ')
     99                          txt += '\n'
    100                          if self._payload[self._idx['recommendation_query']] is not None:
    101                                  txt += '\n'
    102                                  txt += gmTools.wrap(self._payload[self._idx['recommendation_query']], width = 50, initial_indent = ' ', subsequent_indent = ' ')
    103                                  txt += '\n'
    104                  if self._payload[self._idx['rationale4suppression']] is not None:
    105                          txt += '\n'
    106                          txt += _('Rationale for suppression:')
    107                          txt += '\n'
    108                          txt += gmTools.wrap(self._payload[self._idx['rationale4suppression']], width = 50, initial_indent = ' ', subsequent_indent = ' ')
    109                          txt += '\n'
    110                  return txt
    111
    112          #--------------------------------------------------------
    113 -        def suppress(self, rationale=None, pk_encounter=None):
    114                  return suppress_dynamic_hint (
    115                          pk_hint = self._payload[self._idx['pk_auto_hint']],
    116                          pk_encounter = pk_encounter,
    117                          rationale = rationale
    118                  )
    119          #--------------------------------------------------------
    120 -        def invalidate_suppression(self, pk_encounter=None):
    121                  return invalidate_hint_suppression (
    122                          pk_hint = self._payload[self._idx['pk_auto_hint']],
    123                          pk_encounter = pk_encounter
    124                  )
    125
    126  #------------------------------------------------------------
    127 -def get_dynamic_hints(order_by=None, link_obj=None, return_pks=False):
    128          if order_by is None:
    129                  order_by = 'TRUE'
    130          else:
    131                  order_by = 'TRUE ORDER BY %s' % order_by
    132          cmd = _SQL_get_dynamic_hints % order_by
    133          rows, idx = gmPG2.run_ro_queries(link_obj = link_obj, queries = [{'cmd': cmd}], get_col_idx = True)
    134          if return_pks:
    135                  return [ r['pk_auto_hint'] for r in rows ]
    136          return [ cDynamicHint(row = {'data': r, 'idx': idx, 'pk_field': 'pk_auto_hint'}) for r in rows ]
    137
    138  #------------------------------------------------------------
    139 -def create_dynamic_hint(link_obj=None, query=None, title=None, hint=None, source=None):
    140          args = {
    141                  'query': query,
    142                  'title': title,
    143                  'hint': hint,
    144                  'source': source,
    145                  'usr': gmStaff.gmCurrentProvider()['db_user']
    146          }
    147          cmd = """
    148                  INSERT INTO ref.auto_hint (
    149                          query,
    150                          title,
    151                          hint,
    152                          source,
    153                          lang
    154                  ) VALUES (
    155                          gm.nullify_empty_string(%(query)s),
    156                          gm.nullify_empty_string(%(title)s),
    157                          gm.nullify_empty_string(%(hint)s),
    158                          gm.nullify_empty_string(%(source)s),
    159                          i18n.get_curr_lang(%(usr)s)
    160                  )
    161                  RETURNING pk
    162          """
    163          rows, idx = gmPG2.run_rw_queries(link_obj = link_obj, queries = [{'cmd': cmd, 'args': args}], return_data = True, get_col_idx = True)
    164          return cDynamicHint(aPK_obj = rows[0]['pk'], link_obj = link_obj)
    165
    166  #------------------------------------------------------------
    167 -def delete_dynamic_hint(link_obj=None, pk_hint=None):
    168          args = {'pk': pk_hint}
    169          cmd = "DELETE FROM ref.auto_hint WHERE pk = %(pk)s"
    170          gmPG2.run_rw_queries(link_obj = link_obj, queries = [{'cmd': cmd, 'args': args}])
    171          return True
    172
    173  #------------------------------------------------------------
    174 -def get_hints_for_patient(pk_identity=None, pk_encounter=None):
    175          conn = gmPG2.get_connection()
    176          curs = conn.cursor()
    177          curs.callproc('clin.get_hints_for_patient', [pk_identity])
    178          rows = curs.fetchall()
    179          idx = gmPG2.get_col_indices(curs)
    180          curs.close()
    181          conn.rollback()
    182
    183          applying_rows = []
    184          for row in rows:
    185                  if row['rationale4suppression'] is None:
    186                          applying_rows.append(row)
    187                          continue
    188                  if row['rationale4suppression'].startswith('magic_tag::'):
    189                          _log.debug('hint with magic tag: %s', row['rationale4suppression'])
    190                          if 'suppression_needs_invalidation' in row['rationale4suppression']:
    191                                  _log.debug('database asks for invalidation of suppression of hint [%s]', row)
    192                                  if pk_encounter is not None:
    193                                          invalidate_hint_suppression(pk_hint = row['pk_auto_hint'], pk_encounter = pk_encounter)
    194                          if 'does_not_apply' in row['rationale4suppression']:
    195                                  continue
    196                          # we would need to reload the relevant hint at this time,
    197                          # however currently, only hints which do not apply ask
    198                          # for invalidation of suppression
    199                  applying_rows.append(row)
    200
    201          return [ cDynamicHint(row = {'data': r, 'idx': idx, 'pk_field': 'pk_auto_hint'}) for r in applying_rows ]
    202
    203  #------------------------------------------------------------
    204 -def suppress_dynamic_hint(pk_hint=None, rationale=None, pk_encounter=None):
    205          args = {
    206                  'hint': pk_hint,
    207                  'rationale': rationale,
    208                  'enc': pk_encounter
    209          }
    210          cmd = """
    211                  DELETE FROM clin.suppressed_hint
    212                  WHERE
    213                          fk_hint = %(hint)s
    214                                  AND
    215                          fk_encounter IN (
    216                                  SELECT pk FROM clin.encounter WHERE fk_patient = (
    217                                          SELECT fk_patient FROM clin.encounter WHERE pk = %(enc)s
    218                                  )
    219                          )
    220          """
    221          queries = [{'cmd': cmd, 'args': args}]
    222          cmd = """
    223                  INSERT INTO clin.suppressed_hint (
    224                          fk_encounter,
    225                          fk_hint,
    226                          rationale,
    227                          md5_sum
    228                  ) VALUES (
    229                          %(enc)s,
    230                          %(hint)s,
    231                          %(rationale)s,
    232                          (SELECT r_vah.md5_sum FROM ref.v_auto_hints r_vah WHERE r_vah.pk_auto_hint = %(hint)s)
    233                  )
    234          """
    235          queries.append({'cmd': cmd, 'args': args})
    236          gmPG2.run_rw_queries(queries = queries)
    237          return True
    238
    239  #------------------------------------------------------------
    240  # suppressed dynamic hints
    241  #------------------------------------------------------------
    242  _SQL_get_suppressed_hints = "SELECT * FROM clin.v_suppressed_hints WHERE %s"
    243
    244 -class cSuppressedHint(gmBusinessDBObject.cBusinessDBObject):
    245          """Represents suppressed dynamic hints per patient."""
    246
    247          _cmd_fetch_payload = _SQL_get_suppressed_hints % "pk_suppressed_hint = %s"
    248          _cmds_store_payload = []
    249          _updatable_fields = []
    250          #--------------------------------------------------------
    251 -        def format(self):
    252                  txt = '%s               [#%s]\n' % (
    253                          gmTools.bool2subst(self._payload[self._idx['is_active']], _('Suppressed active dynamic hint'), _('Suppressed inactive dynamic hint')),
    254                          self._payload[self._idx['pk_suppressed_hint']]
    255                  )
    256                  txt += '\n'
    257                  txt += '%s\n\n' % self._payload[self._idx['title']]
    258                  txt += _('Suppressed by: %s\n') % self._payload[self._idx['suppressed_by']]
    259                  txt += _('Suppressed at: %s\n') % gmDateTime.pydt_strftime(self._payload[self._idx['suppressed_when']], '%Y %b %d')
    260                  txt += _('Hint #: %s\n') % self._payload[self._idx['pk_hint']]
    261                  txt += _('Patient #: %s\n') % self._payload[self._idx['pk_identity']]
    262                  txt += _('MD5 (currently): %s\n') % self._payload[self._idx['md5_hint']]
    263                  txt += _('MD5 (at suppression): %s\n') % self._payload[self._idx['md5_suppressed']]
    264                  txt += _('Source: %s\n') % self._payload[self._idx['source']]
    265                  txt += _('Language: %s\n') % self._payload[self._idx['lang']]
    266                  txt += '\n'
    267                  txt += '%s\n' % gmTools.wrap(self._payload[self._idx['hint']], width = 50, initial_indent = ' ', subsequent_indent = ' ')
    268                  txt += '\n'
    269                  if self._payload[self._idx['recommendation']] is not None:
    270                          txt += '\n'
    271                          txt += '%s\n' % gmTools.wrap(self._payload[self._idx['recommendation']], width = 50, initial_indent = ' ', subsequent_indent = ' ')
    272                          txt += '\n'
    273                  txt += '%s\n' % gmTools.wrap (
    274                          gmTools.coalesce(self._payload[self._idx['url']], ''),
    275                          width = 50,
    276                          initial_indent = ' ',
    277                          subsequent_indent = ' '
    278                  )
    279                  txt += '\n'
    280                  txt += '%s\n' % gmTools.wrap(self._payload[self._idx['query']], width = 50, initial_indent = ' ', subsequent_indent = ' ')
    281                  return txt
    282
    283  #------------------------------------------------------------
    284 -def get_suppressed_hints(pk_identity=None, order_by=None, return_pks=False):
    285          args = {'pat': pk_identity}
    286          if pk_identity is None:
    287                  where = 'true'
    288          else:
    289                  where = "pk_identity = %(pat)s"
    290          if order_by is None:
    291                  order_by = ''
    292          else:
    293                  order_by = ' ORDER BY %s' % order_by
    294          cmd = (_SQL_get_suppressed_hints % where) + order_by
    295          rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
    296          if return_pks:
    297                  return [ r['pk_suppressed_hint'] for r in rows ]
    298          return [ cSuppressedHint(row = {'data': r, 'idx': idx, 'pk_field': 'pk_suppressed_hint'}) for r in rows ]
    299
    300  #------------------------------------------------------------
    301 -def delete_suppressed_hint(pk_suppressed_hint=None):
    302          args = {'pk': pk_suppressed_hint}
    303          cmd = "DELETE FROM clin.suppressed_hint WHERE pk = %(pk)s"
    304          gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
    305          return True
    306
    307  #------------------------------------------------------------
    308 -def invalidate_hint_suppression(pk_hint=None, pk_encounter=None):
    309          _log.debug('invalidating suppression of hint #%s', pk_hint)
    310          args = {
    311                  'pk_hint': pk_hint,
    312                  'enc': pk_encounter,
    313                  'fake_md5': '***INVALIDATED***'                 # only needs to NOT match ANY md5 sum
    314          }
    315          cmd = """
    316                  UPDATE clin.suppressed_hint SET
    317                          fk_encounter = %(enc)s,
    318                          md5_sum = %(fake_md5)s
    319                  WHERE
    320                          pk = (
    321                                  SELECT pk_suppressed_hint
    322                                  FROM clin.v_suppressed_hints
    323                                  WHERE
    324                                          pk_hint = %(pk_hint)s
    325                                                  AND
    326                                          pk_identity = (
    327                                                  SELECT fk_patient FROM clin.encounter WHERE pk = %(enc)s
    328                                          )
    329                          )
    330          """
    331          gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
    332          return True
    333
    334  #============================================================
    335  if __name__ == '__main__':
    336
    337          if len(sys.argv) < 2:
    338                  sys.exit()
    339
    340          if sys.argv[1] != 'test':
    341                  sys.exit()
    342
    343          from Gnumed.pycommon import gmI18N
    344
    345          gmI18N.activate_locale()
    346          gmI18N.install_domain()
    347
    348          #---------------------------------------
    349 -        def test_auto_hints():
    350  #               for row in get_dynamic_hints():
    351  #                       print row
    352                  for row in get_hints_for_patient(pk_identity = 12):
    353                          print(row)
    354          #---------------------------------------
    355          test_auto_hints()
    356