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

# Source Code for Module Gnumed.business.gmProviderInbox

      1  # -*- coding: latin-1 -*-
      2  """GNUmed provider inbox 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.inbox')
     25
     26  #============================================================
     27  # provider message inbox
     28  #------------------------------------------------------------
     29  _SQL_get_inbox_messages = """SELECT * FROM dem.v_message_inbox d_vi WHERE %s"""
     30
     31 -class cInboxMessage(gmBusinessDBObject.cBusinessDBObject):
     32
     33          _cmd_fetch_payload = _SQL_get_inbox_messages % "pk_inbox_message = %s"
     34          _cmds_store_payload = [
     35                  """
     36                          UPDATE dem.message_inbox SET
     37                                  fk_staff = %(pk_staff)s,
     38                                  fk_inbox_item_type = %(pk_type)s,
     39                                  comment = gm.nullify_empty_string(%(comment)s),
     40                                  data = gm.nullify_empty_string(%(data)s),
     41                                  importance = %(importance)s,
     42                                  fk_patient = %(pk_patient)s,
     43                                  ufk_context = NULLIF(%(pk_context)s::integer[], ARRAY[NULL::integer]),
     44                                  due_date = %(due_date)s,
     45                                  expiry_date = %(expiry_date)s
     46                          WHERE
     47                                  pk = %(pk_inbox_message)s
     48                                          AND
     49                                  xmin = %(xmin_message_inbox)s
     50                          RETURNING
     51                                  pk as pk_inbox_message,
     52                                  xmin as xmin_message_inbox
     53                  """
     54          ]
     55          _updatable_fields = [
     56                  'pk_staff',
     57                  'pk_type',
     58                  'comment',
     59                  'data',
     60                  'importance',
     61                  'pk_patient',
     62                  'pk_context',
     63                  'due_date',
     64                  'expiry_date'
     65          ]
     66          #------------------------------------------------------------
     67 -        def format(self, with_patient=True):
     68                  tt = '%s: %s%s\n' % (
     69                          gmDateTime.pydt_strftime (
     70                                  self._payload[self._idx['received_when']],
     71                                  format = '%A, %Y %b %d, %H:%M',
     72                                  accuracy = gmDateTime.acc_minutes
     73                          ),
     74                          gmTools.bool2subst(self._payload[self._idx['is_virtual']], _('virtual message'), _('message')),
     75                          gmTools.coalesce(self._payload[self._idx['pk_inbox_message']], '', ' #%s ')
     76                  )
     77
     78                  tt += '%s: %s\n' % (
     79                          self._payload[self._idx['l10n_category']],
     80                          self._payload[self._idx['l10n_type']]
     81                  )
     82
     83                  tt += '%s %s %s\n' % (
     84                          self._payload[self._idx['modified_by']],
     85                          gmTools.u_arrow2right,
     86                          gmTools.coalesce(self._payload[self._idx['provider']], _('everyone'))
     87                  )
     88
     89                  tt += '\n%s%s%s\n\n' % (
     90                          gmTools.u_left_double_angle_quote,
     91                          self._payload[self._idx['comment']],
     92                          gmTools.u_right_double_angle_quote
     93                  )
     94
     95                  if with_patient and (self._payload[self._idx['pk_patient']] is not None):
     96                          tt += _('Patient: %s, %s%s %s   #%s\n' % (
     97                                  self._payload[self._idx['lastnames']],
     98                                  self._payload[self._idx['firstnames']],
     99                                  gmTools.coalesce(self._payload[self._idx['l10n_gender']], '', ' (%s)'),
    100                                  gmDateTime.pydt_strftime(self._payload[self._idx['dob']], '%Y %b %d', none_str = ''),
    101                                  self._payload[self._idx['pk_patient']]
    102                          ))
    103
    104                  if self._payload[self._idx['due_date']] is not None:
    105                          if self._payload[self._idx['is_overdue']]:
    106                                  template = _('Due: %s (%s ago)\n')
    107                          else:
    108                                  template = _('Due: %s (in %s)\n')
    109                          tt += template % (
    110                                  gmDateTime.pydt_strftime(self._payload[self._idx['due_date']], '%Y %b %d'),
    111                                  gmDateTime.format_interval_medically(self._payload[self._idx['interval_due']])
    112                          )
    113
    114                  if self._payload[self._idx['expiry_date']] is not None:
    115                          if self._payload[self._idx['is_expired']]:
    116                                  template = _('Expired: %s\n')
    117                          else:
    118                                  template = _('Expires: %s\n')
    119                          tt += template % gmDateTime.pydt_strftime(self._payload[self._idx['expiry_date']], '%Y %b %d')
    120
    121                  if self._payload[self._idx['data']] is not None:
    122                          tt += self._payload[self._idx['data']][:150]
    123                          if len(self._payload[self._idx['data']]) > 150:
    124                                  tt += gmTools.u_ellipsis
    125
    126                  return tt
    127  #------------------------------------------------------------
    128 -def get_reminders(pk_patient=None, order_by=None, return_pks=False):
    129
    130          if order_by is None:
    131                  order_by = '%s ORDER BY due_date, importance DESC, received_when DESC'
    132          else:
    133                  order_by = '%%s ORDER BY %s' % order_by
    134
    135          args = {'pat': pk_patient}
    136          where_parts = [
    137                  'pk_patient = %(pat)s',
    138                  'due_date IS NOT NULL'
    139          ]
    140
    141          cmd = "SELECT * FROM dem.v_message_inbox WHERE %s" % (
    142                  order_by % ' AND '.join(where_parts)
    143          )
    144          _log.debug('SQL: %s', cmd)
    145          _log.debug('args: %s', args)
    146          rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
    147          if return_pks:
    148                  return [ r['pk_inbox_message'] for r in rows ]
    149          return [ cInboxMessage(row = {'data': r, 'idx': idx, 'pk_field': 'pk_inbox_message'}) for r in rows ]
    150
    151  #------------------------------------------------------------
    152 -def get_overdue_messages(pk_patient=None, order_by=None, return_pks=False):
    153
    154          if order_by is None:
    155                  order_by = '%s ORDER BY due_date, importance DESC, received_when DESC'
    156          else:
    157                  order_by = '%%s ORDER BY %s' % order_by
    158
    159          args = {'pat': pk_patient}
    160          where_parts = [
    161                  'pk_patient = %(pat)s',
    162                  'is_overdue IS TRUE'
    163          ]
    164
    165          cmd = "SELECT * FROM dem.v_message_inbox WHERE %s" % (
    166                  order_by % ' AND '.join(where_parts)
    167          )
    168          _log.debug('SQL: %s', cmd)
    169          _log.debug('args: %s', args)
    170          rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
    171          if return_pks:
    172                  return [ r['pk_inbox_message'] for r in rows ]
    173          return [ cInboxMessage(row = {'data': r, 'idx': idx, 'pk_field': 'pk_inbox_message'}) for r in rows ]
    174
    175  #------------------------------------------------------------
    176 -def get_relevant_messages(pk_staff=None, pk_patient=None, include_without_provider=False, order_by=None, return_pks=False):
    177
    178          if order_by is None:
    179                  order_by = '%s ORDER BY importance desc, received_when desc'
    180          else:
    181                  order_by = '%%s ORDER BY %s' % order_by
    182
    183          args = {}
    184          where_parts = []
    185
    186          if pk_staff is not None:
    187                  if include_without_provider:
    188                          where_parts.append('((pk_staff IN (%(staff)s, NULL)) OR (modified_by = (SELECT short_alias FROM dem.staff WHERE pk = %(staff)s)))')
    189                  else:
    190                          where_parts.append('((pk_staff = %(staff)s) OR (modified_by = (SELECT short_alias FROM dem.staff WHERE pk = %(staff)s)))')
    191                  args['staff'] = pk_staff
    192
    193          if pk_patient is not None:
    194                  where_parts.append('pk_patient = %(pat)s')
    195                  args['pat'] = pk_patient
    196
    197          where_parts.append("""
    198                  -- messages which have no due date and are not expired
    199                  ((due_date IS NULL) AND ((expiry_date IS NULL) OR (expiry_date > now())))
    200                          OR
    201                  -- messages which are due and not expired
    202                  ((due_date IS NOT NULL) AND (due_date < now()) AND ((expiry_date IS NULL) OR (expiry_date > now())))
    203          """)
    204
    205          cmd = _SQL_get_inbox_messages % (
    206                  order_by % ' AND '.join(where_parts)
    207          )
    208          _log.debug('SQL: %s', cmd)
    209          _log.debug('args: %s', args)
    210          rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
    211          if return_pks:
    212                  return [ r['pk_inbox_message'] for r in rows ]
    213          return [ cInboxMessage(row = {'data': r, 'idx': idx, 'pk_field': 'pk_inbox_message'}) for r in rows ]
    214
    215  #------------------------------------------------------------
    216 -def get_inbox_messages(pk_staff=None, pk_patient=None, include_without_provider=False, exclude_expired=False, expired_only=False, overdue_only=False, unscheduled_only=False, exclude_unscheduled=False, order_by=None, return_pks=False):
    217
    218          if order_by is None:
    219                  order_by = '%s ORDER BY importance desc, received_when desc'
    220          else:
    221                  order_by = '%%s ORDER BY %s' % order_by
    222
    223          args = {}
    224          where_parts = []
    225
    226          if pk_staff is not None:
    227                  if include_without_provider:
    228                          where_parts.append('((pk_staff IN (%(staff)s, NULL)) OR (modified_by = (SELECT short_alias FROM dem.staff WHERE pk = %(staff)s)))')
    229                  else:
    230                          where_parts.append('((pk_staff = %(staff)s) OR (modified_by = (SELECT short_alias FROM dem.staff WHERE pk = %(staff)s)))')
    231                  args['staff'] = pk_staff
    232
    233          if pk_patient is not None:
    234                  where_parts.append('pk_patient = %(pat)s')
    235                  args['pat'] = pk_patient
    236
    237          if exclude_expired:
    238                  where_parts.append('is_expired IS FALSE')
    239
    240          if expired_only:
    241                  where_parts.append('is_expired IS TRUE')
    242
    243          if overdue_only:
    244                  where_parts.append('is_overdue IS TRUE')
    245
    246          if unscheduled_only:
    247                  where_parts.append('due_date IS NULL')
    248
    249          if exclude_unscheduled:
    250                  where_parts.append('due_date IS NOT NULL')
    251
    252          cmd = _SQL_get_inbox_messages % (
    253                  order_by % ' AND '.join(where_parts)
    254          )
    255          _log.debug('SQL: %s', cmd)
    256          _log.debug('args: %s', args)
    257          rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
    258          if return_pks:
    259                  return [ r['pk_inbox_message'] for r in rows ]
    260          return [ cInboxMessage(row = {'data': r, 'idx': idx, 'pk_field': 'pk_inbox_message'}) for r in rows ]
    261
    262  #------------------------------------------------------------
    263 -def create_inbox_message(message_type=None, subject=None, patient=None, staff=None, message_category='clinical'):
    264
    265          success, pk_type = gmTools.input2int(initial = message_type)
    266          if not success:
    267                  pk_type = create_inbox_item_type(message_type = message_type, category = message_category)
    268
    269          cmd = """
    270                  INSERT INTO dem.message_inbox (
    271                          fk_staff,
    272                          fk_patient,
    273                          fk_inbox_item_type,
    274                          comment
    275                  ) VALUES (
    276                          %(staff)s,
    277                          %(pat)s,
    278                          %(type)s,
    279                          gm.nullify_empty_string(%(subject)s)
    280                  )
    281                  RETURNING pk
    282          """
    283          args = {
    284                  'staff': staff,
    285                  'pat': patient,
    286                  'type': pk_type,
    287                  'subject': subject
    288          }
    289          rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True, get_col_idx = False)
    290
    291          return cInboxMessage(aPK_obj = rows[0]['pk'])
    292
    293  #------------------------------------------------------------
    294 -def delete_inbox_message(inbox_message=None):
    295          args = {'pk': inbox_message}
    296          cmd = "DELETE FROM dem.message_inbox WHERE pk = %(pk)s"
    297          gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
    298          return True
    299
    300  #------------------------------------------------------------
    301 -def create_inbox_item_type(message_type=None, category='clinical'):
    302
    303          # determine category PK
    304          success, pk_cat = gmTools.input2int(initial = category)
    305          if not success:
    306                  args = {'cat': category}
    307                  cmd = """SELECT COALESCE (
    308                          (SELECT pk FROM dem.inbox_item_category WHERE _(description) = %(cat)s),
    309                          (SELECT pk FROM dem.inbox_item_category WHERE description = %(cat)s)
    310                  ) AS pk"""
    311                  rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}])
    312                  if rows[0]['pk'] is None:
    313                          cmd = "INSERT INTO dem.inbox_item_category (description) VALUES (%(cat)s) RETURNING pk"
    314                          rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True)
    315                          pk_cat = rows[0]['pk']
    316                  else:
    317                          pk_cat = rows[0]['pk']
    318
    319          # find type PK or create type
    320          args = {'pk_cat': pk_cat, 'type': message_type}
    321          cmd = """SELECT COALESCE (
    322                  (SELECT pk FROM dem.inbox_item_type where fk_inbox_item_category = %(pk_cat)s AND _(description) = %(type)s),
    323                  (SELECT pk FROM dem.inbox_item_type where fk_inbox_item_category = %(pk_cat)s AND description = %(type)s)
    324          ) AS pk"""
    325          rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}])
    326          if rows[0]['pk'] is None:
    327                  cmd = """
    328                          INSERT INTO dem.inbox_item_type (
    329                                  fk_inbox_item_category,
    330                                  description,
    331                                  is_user
    332                          ) VALUES (
    333                                  %(pk_cat)s,
    334                                  %(type)s,
    335                                  TRUE
    336                          ) RETURNING pk"""
    337                  rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True)
    338
    339          return rows[0]['pk']
    340
    341  #============================================================
    342 -class cProviderInbox:
    343 -        def __init__(self, provider_id=None):
    344                  if provider_id is None:
    345                          self.__provider_id = gmStaff.gmCurrentProvider()['pk_staff']
    346                  else:
    347                          self.__provider_id = provider_id
    348          #--------------------------------------------------------
    349 -        def delete_message(self, pk=None):
    350                  return delete_inbox_message(inbox_message = pk)
    351          #--------------------------------------------------------
    352 -        def add_message(message_type=None, subject=None, patient=None):
    353                  return create_inbox_message (
    354                          message_type = message_type,
    355                          subject = subject,
    356                          patient = patient,
    357                          staff = self.__provider_id
    358                  )
    359          #--------------------------------------------------------
    360          # properties
    361          #--------------------------------------------------------
    362 -        def get_messages(self, pk_patient=None, include_without_provider=False, exclude_expired=False, expired_only=False, overdue_only=False, unscheduled_only=False, exclude_unscheduled=False, order_by=None):
    363                  return get_inbox_messages (
    364                          pk_staff = self.__provider_id,
    365                          pk_patient = pk_patient,
    366                          include_without_provider = include_without_provider,
    367                          exclude_expired = exclude_expired,
    368                          expired_only = expired_only,
    369                          overdue_only = overdue_only,
    370                          unscheduled_only = unscheduled_only,
    371                          exclude_unscheduled = exclude_unscheduled,
    372                          order_by = order_by
    373                  )
    374
    375          messages = property(get_messages, lambda x:x)
    376
    377          #--------------------------------------------------------
    378 -        def get_relevant_messages(self, pk_patient=None, include_without_provider=True):
    379                  return get_relevant_messages (
    380                          pk_staff = self.__provider_id,
    381                          pk_patient = pk_patient,
    382                          include_without_provider = include_without_provider
    383                  )
    384
    385  #============================================================
    386  if __name__ == '__main__':
    387
    388          if len(sys.argv) < 2:
    389                  sys.exit()
    390
    391          if sys.argv[1] != 'test':
    392                  sys.exit()
    393
    394          from Gnumed.pycommon import gmI18N
    395
    396          gmI18N.activate_locale()
    397          gmI18N.install_domain()
    398
    399          #---------------------------------------
    400 -        def test_inbox():
    401                  gmStaff.gmCurrentProvider(provider = gmStaff.cStaff())
    402                  inbox = cProviderInbox()
    403                  for msg in inbox.messages:
    404                          print(msg)
    405          #---------------------------------------
    406 -        def test_msg():
    407                  msg = cInboxMessage(aPK_obj = 1)
    408                  print(msg)
    409          #---------------------------------------
    410 -        def test_create_type():
    411                  print(create_inbox_item_type(message_type = 'test'))
    412          #---------------------------------------
    413 -        def test_due():
    414                  for msg in get_overdue_messages(pk_patient = 12):
    415                          print(msg.format())
    416          #---------------------------------------
    417          #test_inbox()
    418          #test_msg()
    419          #test_create_type()
    420          #test_due()
    421
    422  #============================================================
    423