Package Gnumed :: Package wxpython :: Module gmProviderInboxWidgets |
[frames] | no frames]

# Source Code for Module Gnumed.wxpython.gmProviderInboxWidgets

       1  """GNUmed provider inbox handling widgets.
       2  """
       3  #================================================================
       4  __author__ = "Karsten Hilbert <Karsten.Hilbert@gmx.net>"
       5
       6  import sys
       7  import logging
       8
       9
      10  import wx
      11
      12
      13  if __name__ == '__main__':
      14          sys.path.insert(0, '../../')
      15  from Gnumed.pycommon import gmI18N
      16  from Gnumed.pycommon import gmExceptions
      17  from Gnumed.pycommon import gmPG2
      18  from Gnumed.pycommon import gmTools
      19  from Gnumed.pycommon import gmDispatcher
      20  from Gnumed.pycommon import gmMatchProvider
      21  from Gnumed.pycommon import gmDateTime
      22  from Gnumed.pycommon import gmNetworkTools
      23
      24  from Gnumed.business import gmPerson
      25  from Gnumed.business import gmStaff
      26  from Gnumed.business import gmProviderInbox
      27  from Gnumed.business import gmClinicalRecord
      28
      29  from Gnumed.wxpython import gmGuiHelpers
      30  from Gnumed.wxpython import gmListWidgets
      31  from Gnumed.wxpython import gmPlugin
      32  from Gnumed.wxpython import gmRegetMixin
      33  from Gnumed.wxpython import gmPhraseWheel
      34  from Gnumed.wxpython import gmEditArea
      35  from Gnumed.wxpython import gmAuthWidgets
      36  from Gnumed.wxpython import gmDataPackWidgets
      37  from Gnumed.wxpython.gmPatSearchWidgets import set_active_patient
      38  from Gnumed.wxpython.gmVaccWidgets import manage_vaccinations
      39
      40
      41  _log = logging.getLogger('gm.ui')
      42
      43  _indicator = {
      44          -1: '',
      45          0: '',
      46          1: '*!!*'
      47  }
      48
      49  #====================================================================
      50 -class cMessageTypePhraseWheel(gmPhraseWheel.cPhraseWheel):
      51
      52 -        def __init__(self, *args, **kwargs):
      53
      54                  gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
      55
      56                  query = u"""
      57                          SELECT DISTINCT ON (label)
      58                                  pk_type,
      59                                  (l10n_type || ' (' || l10n_category || ')')
      60                                          AS label
      61                          FROM
      62                                  dem.v_inbox_item_type
      63                          WHERE
      64                                  l10n_type %(fragment_condition)s
      65                                          OR
      66                                  type %(fragment_condition)s
      67                                          OR
      68                                  l10n_category %(fragment_condition)s
      69                                          OR
      70                                  category %(fragment_condition)s
      71                          ORDER BY label
      72                          LIMIT 50"""
      73
      74                  mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
      75                  mp.setThresholds(1, 2, 4)
      76                  self.matcher = mp
      77                  self.SetToolTipString(_('Select a message type.'))
      78          #----------------------------------------------------------------
      79 -        def _create_data(self):
      80                  if self.GetData() is not None:
      81                          return
      82
      83                  val = self.GetValue().strip()
      84                  if val == u'':
      85                          return
      86
      87                  self.SetText (
      88                          value = val,
      89                          data = gmProviderInbox.create_inbox_item_type(message_type = val)
      90                  )
      91  #====================================================================
      92 -def _display_clinical_reminders():
      93          wx.CallAfter(__display_clinical_reminders)
      94
      95  gmDispatcher.connect(signal = u'post_patient_selection', receiver = _display_clinical_reminders)
      96
      97 -def __display_clinical_reminders():
      98          pat = gmPerson.gmCurrentPatient()
      99          if not pat.connected:
     100                  return
     101          for msg in pat.overdue_messages:
     102                  if msg['expiry_date'] is None:
     103                          exp = u''
     104                  else:
     105                          exp = _(' - expires %s') % gmDateTime.pydt_strftime (
     106                                  msg['expiry_date'],
     107                                  '%Y %b %d',
     108                                  accuracy = gmDateTime.acc_days
     109                          )
     110                  txt = _(
     111                          'Due for %s (since %s%s):\n'
     112                          '%s'
     113                          '%s'
     114                          '\n'
     115                          'Patient: %s\n'
     116                          'Reminder by: %s'
     117                  ) % (
     118                          gmDateTime.format_interval_medically(msg['interval_due']),
     119                          gmDateTime.pydt_strftime(msg['due_date'], '%Y %b %d', accuracy = gmDateTime.acc_days),
     120                          exp,
     121                          gmTools.coalesce(msg['comment'], u'', u'\n%s\n'),
     122                          gmTools.coalesce(msg['data'], u'', u'\n%s\n'),
     123                          pat['description_gender'],
     124                          msg['modified_by']
     125                  )
     126                  gmGuiHelpers.gm_show_warning (
     127                          aTitle = _('Clinical reminder'),
     128                          aMessage = txt
     129                  )
     130          for hint in pat.dynamic_hints:
     131                  txt = u'%s\n\n%s\n\n          %s' % (
     132                          hint['title'],
     133                          gmTools.wrap(hint['hint'], width = 50, initial_indent = u' ', subsequent_indent = u' '),
     134                          hint['source']
     135                  )
     136                  dlg = gmGuiHelpers.c2ButtonQuestionDlg (
     137                          None,
     138                          -1,
     139                          caption = _('Clinical hint'),
     140                          question = txt,
     141                          button_defs = [
     142                                  {'label': _('OK'), 'tooltip': _('OK'), 'default': True},
     143                                  {'label': _('More info'), 'tooltip': _('Go to [%s]') % hint['url']}
     144                          ]
     145                  )
     146                  button = dlg.ShowModal()
     147                  dlg.Destroy()
     148                  if button == wx.ID_NO:
     149                          gmNetworkTools.open_url_in_browser(hint['url'], autoraise = False)
     150
     151          return
     152  #====================================================================
     153  from Gnumed.wxGladeWidgets import wxgInboxMessageEAPnl
     154
     155 -class cInboxMessageEAPnl(wxgInboxMessageEAPnl.wxgInboxMessageEAPnl, gmEditArea.cGenericEditAreaMixin):
     156
     157 -        def __init__(self, *args, **kwargs):
     158
     159                  try:
     160                          data = kwargs['message']
     161                          del kwargs['message']
     162                  except KeyError:
     163                          data = None
     164
     165                  wxgInboxMessageEAPnl.wxgInboxMessageEAPnl.__init__(self, *args, **kwargs)
     166                  gmEditArea.cGenericEditAreaMixin.__init__(self)
     167
     168                  # Code using this mixin should set mode and data
     169                  # after instantiating the class:
     170                  self.mode = 'new'
     171                  self.data = data
     172                  if data is not None:
     173                          self.mode = 'edit'
     174
     175                  self.__init_ui()
     176          #----------------------------------------------------------------
     177 -        def __init_ui(self):
     178                  if not gmPerson.gmCurrentPatient().connected:
     179                          self._CHBOX_active_patient.SetValue(False)
     180                          self._CHBOX_active_patient.Enable(False)
     181                          self._PRW_patient.Enable(True)
     182          #----------------------------------------------------------------
     183          # generic Edit Area mixin API
     184          #----------------------------------------------------------------
     185 -        def _valid_for_save(self):
     186                  validity = True
     187
     188                  if self._TCTRL_subject.GetValue().strip() == u'':
     189                          validity = False
     190                          self.display_ctrl_as_valid(ctrl = self._TCTRL_subject, valid = False)
     191                  else:
     192                          self.display_ctrl_as_valid(ctrl = self._TCTRL_subject, valid = True)
     193
     194                  if self._PRW_type.GetValue().strip() == u'':
     195                          validity = False
     196                          self._PRW_type.display_as_valid(False)
     197                  else:
     198                          self._PRW_type.display_as_valid(True)
     199
     200                  missing_receiver = (
     201                          (self._CHBOX_send_to_me.IsChecked() is False)
     202                                  and
     203                          (self._PRW_receiver.GetData() is None)
     204                  )
     205
     206                  missing_patient = (
     207                          (self._CHBOX_active_patient.IsChecked() is False)
     208                                  and
     209                          (self._PRW_patient.person is None)
     210                  )
     211
     212                  if missing_receiver and missing_patient:
     213                          validity = False
     214                          self.display_ctrl_as_valid(ctrl = self._CHBOX_send_to_me, valid = False)
     215                          self._PRW_receiver.display_as_valid(False)
     216                          self.display_ctrl_as_valid(ctrl = self._CHBOX_active_patient, valid = False)
     217                          self.display_ctrl_as_valid(ctrl = self._PRW_patient, valid = False)
     218                  else:
     219                          self.display_ctrl_as_valid(ctrl = self._CHBOX_send_to_me, valid = True)
     220                          self._PRW_receiver.display_as_valid(True)
     221                          self.display_ctrl_as_valid(ctrl = self._CHBOX_active_patient, valid = True)
     222                          self.display_ctrl_as_valid(ctrl = self._PRW_patient, valid = True)
     223
     224                  if self._PRW_due.is_valid_timestamp(allow_empty = True):
     225                          self._PRW_due.display_as_valid(True)
     226                  else:
     227                          # non-empty but also not valid
     228                          validity = False
     229                          self._PRW_due.display_as_valid(False)
     230
     231                  if self._PRW_expiry.is_valid_timestamp(allow_empty = True):
     232                          self._PRW_expiry.display_as_valid(True)
     233                  else:
     234                          # non-empty but also not valid
     235                          validity = False
     236                          self._PRW_expiry.display_as_valid(False)
     237
     238                  # if .due is not empty AND valid
     239                  if self._PRW_due.is_valid_timestamp(allow_empty = False):
     240                          # and if .expiry is ALSO not empty AND valid
     241                          if self._PRW_expiry.is_valid_timestamp(allow_empty = False):
     242                                  # only then compare .due and .expiry
     243                                  if not self._PRW_expiry.date > self._PRW_due.date:
     244                                          validity = False
     245                                          self._PRW_expiry.display_as_valid(False)
     246                                          gmDispatcher.send(signal = 'statustext', msg = _('Message cannot expire before being due.'))
     247
     248                  return validity
     249          #----------------------------------------------------------------
     250 -        def _save_as_new(self):
     251
     252                  pat_id = None
     253                  if self._CHBOX_active_patient.GetValue() is True:
     254                          pat_id = gmPerson.gmCurrentPatient().ID
     255                  else:
     256                          if self._PRW_patient.person is not None:
     257                                  pat_id = self._PRW_patient.person.ID
     258
     259                  receiver = None
     260                  if self._CHBOX_send_to_me.IsChecked():
     261                          receiver = gmStaff.gmCurrentProvider()['pk_staff']
     262                  else:
     263                          if self._PRW_receiver.GetData() is not None:
     264                                  receiver = self._PRW_receiver.GetData()
     265
     266                  msg = gmProviderInbox.create_inbox_message (
     267                          patient = pat_id,
     268                          staff = receiver,
     269                          message_type = self._PRW_type.GetData(can_create = True),
     270                          subject = self._TCTRL_subject.GetValue().strip()
     271                  )
     272
     273                  msg['data'] = self._TCTRL_message.GetValue().strip()
     274
     275                  if self._PRW_due.is_valid_timestamp():
     276                          msg['due_date'] = self._PRW_due.date
     277
     278                  if self._PRW_expiry.is_valid_timestamp():
     279                          msg['expiry_date'] = self._PRW_expiry.date
     280
     281                  if self._RBTN_normal.GetValue() is True:
     282                          msg['importance'] = 0
     283                  elif self._RBTN_high.GetValue() is True:
     284                          msg['importance'] = 1
     285                  else:
     286                          msg['importance'] = -1
     287
     288                  msg.save()
     289                  self.data = msg
     290                  return True
     291          #----------------------------------------------------------------
     292 -        def _save_as_update(self):
     293
     294                  self.data['comment'] = self._TCTRL_subject.GetValue().strip()
     295                  self.data['pk_type'] = self._PRW_type.GetData(can_create = True)
     296
     297                  if self._CHBOX_send_to_me.IsChecked():
     298                          self.data['pk_staff'] = gmStaff.gmCurrentProvider()['pk_staff']
     299                  else:
     300                          self.data['pk_staff'] = self._PRW_receiver.GetData()
     301
     302                  self.data['data'] = self._TCTRL_message.GetValue().strip()
     303
     304                  if self._CHBOX_active_patient.GetValue() is True:
     305                          self.data['pk_patient'] = gmPerson.gmCurrentPatient().ID
     306                  else:
     307                          if self._PRW_patient.person is None:
     308                                  self.data['pk_patient'] = None
     309                          else:
     310                                  self.data['pk_patient'] = self._PRW_patient.person.ID
     311
     312                  if self._PRW_due.is_valid_timestamp():
     313                          self.data['due_date'] = self._PRW_due.date
     314
     315                  if self._PRW_expiry.is_valid_timestamp():
     316                          self.data['expiry_date'] = self._PRW_expiry.date
     317
     318                  if self._RBTN_normal.GetValue() is True:
     319                          self.data['importance'] = 0
     320                  elif self._RBTN_high.GetValue() is True:
     321                          self.data['importance'] = 1
     322                  else:
     323                          self.data['importance'] = -1
     324
     325                  self.data.save()
     326                  return True
     327          #----------------------------------------------------------------
     328 -        def _refresh_as_new(self):
     329                  self._TCTRL_subject.SetValue(u'')
     330                  self._PRW_type.SetText(value = u'', data = None)
     331                  self._CHBOX_send_to_me.SetValue(True)
     332                  self._PRW_receiver.Enable(False)
     333                  self._PRW_receiver.SetData(data = gmStaff.gmCurrentProvider()['pk_staff'])
     334                  self._TCTRL_message.SetValue(u'')
     335                  self._PRW_due.SetText(data = None)
     336                  self._PRW_expiry.SetText(data = None)
     337                  self._RBTN_normal.SetValue(True)
     338                  self._RBTN_high.SetValue(False)
     339                  self._RBTN_low.SetValue(False)
     340
     341                  self._PRW_patient.person = None
     342
     343                  if gmPerson.gmCurrentPatient().connected:
     344                          self._CHBOX_active_patient.Enable(True)
     345                          self._CHBOX_active_patient.SetValue(True)
     346                          self._PRW_patient.Enable(False)
     347                  else:
     348                          self._CHBOX_active_patient.Enable(False)
     349                          self._CHBOX_active_patient.SetValue(False)
     350                          self._PRW_patient.Enable(True)
     351
     352                  self._TCTRL_subject.SetFocus()
     353          #----------------------------------------------------------------
     354 -        def _refresh_as_new_from_existing(self):
     355                  self._refresh_as_new()
     356          #----------------------------------------------------------------
     357 -        def _refresh_from_existing(self):
     358
     359                  self._TCTRL_subject.SetValue(gmTools.coalesce(self.data['comment'], u''))
     360                  self._PRW_type.SetData(data = self.data['pk_type'])
     361
     362                  curr_prov = gmStaff.gmCurrentProvider()
     363                  curr_pat = gmPerson.gmCurrentPatient()
     364
     365                  if curr_prov['pk_staff'] == self.data['pk_staff']:
     366                          self._CHBOX_send_to_me.SetValue(True)
     367                          self._PRW_receiver.Enable(False)
     368                          self._PRW_receiver.SetData(data = gmStaff.gmCurrentProvider()['pk_staff'])
     369                  else:
     370                          self._CHBOX_send_to_me.SetValue(False)
     371                          self._PRW_receiver.Enable(True)
     372                          self._PRW_receiver.SetData(data = self.data['pk_staff'])
     373
     374                  self._TCTRL_message.SetValue(gmTools.coalesce(self.data['data'], u''))
     375
     376                  if curr_pat.connected:
     377                          self._CHBOX_active_patient.Enable(True)
     378                          if curr_pat.ID == self.data['pk_patient']:
     379                                  self._CHBOX_active_patient.SetValue(True)
     380                                  self._PRW_patient.Enable(False)
     381                                  self._PRW_patient.person = None
     382                          else:
     383                                  self._CHBOX_active_patient.SetValue(False)
     384                                  self._PRW_patient.Enable(True)
     385                                  if self.data['pk_patient'] is None:
     386                                          self._PRW_patient.person = None
     387                                  else:
     388                                          self._PRW_patient.person = gmPerson.cIdentity(aPK_obj = self.data['pk_patient'])
     389                  else:
     390                          self._CHBOX_active_patient.Enable(False)
     391                          self._CHBOX_active_patient.SetValue(False)
     392                          self._PRW_patient.Enable(True)
     393                          if self.data['pk_patient'] is None:
     394                                  self._PRW_patient.person = None
     395                          else:
     396                                  self._PRW_patient.person = gmPerson.cIdentity(aPK_obj = self.data['pk_patient'])
     397
     398                  self._PRW_due.SetText(data = self.data['due_date'])
     399                  self._PRW_expiry.SetText(data = self.data['expiry_date'])
     400
     401                  self._RBTN_normal.SetValue(False)
     402                  self._RBTN_high.SetValue(False)
     403                  self._RBTN_low.SetValue(False)
     404                  {       -1: self._RBTN_low,
     405                          0: self._RBTN_normal,
     406                          1: self._RBTN_high
     407                  }[self.data['importance']].SetValue(True)
     408
     409                  self._TCTRL_subject.SetFocus()
     410          #----------------------------------------------------------------
     411          # event handlers
     412          #----------------------------------------------------------------
     413 -        def _on_active_patient_checked(self, event):
     414                  if self._CHBOX_active_patient.IsChecked():
     415                          self._PRW_patient.Enable(False)
     416                          self._PRW_patient.person = None
     417                  else:
     418                          self._PRW_patient.Enable(True)
     419          #----------------------------------------------------------------
     420 -        def _on_send_to_me_checked(self, event):
     421                  if self._CHBOX_send_to_me.IsChecked():
     422                          self._PRW_receiver.Enable(False)
     423                          self._PRW_receiver.SetData(data = gmStaff.gmCurrentProvider()['pk_staff'])
     424                  else:
     425                          self._PRW_receiver.Enable(True)
     426                          self._PRW_receiver.SetText(value = u'', data = None)
     427  #============================================================
     428 -def edit_inbox_message(parent=None, message=None, single_entry=True):
     429
     430          if parent is None:
     431                  parent = wx.GetApp().GetTopWindow()
     432
     433          ea = cInboxMessageEAPnl(parent = parent, id = -1)
     434          ea.data = message
     435          ea.mode = gmTools.coalesce(message, 'new', 'edit')
     436          dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = single_entry)
     437          dlg.SetTitle(gmTools.coalesce(message, _('Adding new inbox message'), _('Editing inbox message')))
     438          if dlg.ShowModal() == wx.ID_OK:
     439                  dlg.Destroy()
     440                  return True
     441          dlg.Destroy()
     442          return False
     443
     444  #============================================================
     445 -def manage_reminders(parent=None, patient=None):
     446
     447          if parent is None:
     448                  parent = wx.GetApp().GetTopWindow()
     449          #------------------------------------------------------------
     450          def refresh(lctrl):
     451                  reminders = gmProviderInbox.get_reminders(pk_patient = patient)
     452                  items = [ [
     453                          gmTools.bool2subst (
     454                                  r['is_overdue'],
     455                                  _('overdue for %s'),
     456                                  _('due in %s')
     457                          ) % gmDateTime.format_interval_medically(r['interval_due']),
     458                          r['comment'],
     459                          r['pk_inbox_message']
     460                  ] for r in reminders ]
     461                  lctrl.set_string_items(items)
     462                  lctrl.set_data(reminders)
     463          #------------------------------------------------------------
     464          return gmListWidgets.get_choices_from_list (
     465                  parent = parent,
     466                  msg = None,
     467                  caption = _('Reminders for the current patient'),
     468                  columns = [ _('Status'), _('Subject'), '#' ],
     469                  single_selection = False,
     470                  can_return_empty = True,
     471                  ignore_OK_button = False,
     472                  refresh_callback = refresh
     473  #               edit_callback=None,
     474  #               new_callback=None,
     475  #               delete_callback=None,
     476  #               left_extra_button=None,
     477  #               middle_extra_button=None,
     478  #               right_extra_button=None
     479          )
     480
     481  #============================================================
     482  from Gnumed.wxGladeWidgets import wxgProviderInboxPnl
     483
     484 -class cProviderInboxPnl(wxgProviderInboxPnl.wxgProviderInboxPnl, gmRegetMixin.cRegetOnPaintMixin):
     485
     486          _item_handlers = {}
     487
     488          #--------------------------------------------------------
     489 -        def __init__(self, *args, **kwds):
     490
     491                  wxgProviderInboxPnl.wxgProviderInboxPnl.__init__(self, *args, **kwds)
     492                  gmRegetMixin.cRegetOnPaintMixin.__init__(self)
     493
     494                  self.provider = gmStaff.gmCurrentProvider()
     495                  self.__init_ui()
     496
     497                  cProviderInboxPnl._item_handlers['clinical.review docs'] = self._goto_doc_review
     498                  cProviderInboxPnl._item_handlers['clinical.review results'] = self._goto_measurements_review
     499                  cProviderInboxPnl._item_handlers['clinical.review lab'] = self._goto_measurements_review
     500                  cProviderInboxPnl._item_handlers['clinical.review vaccs'] = self._goto_vaccination_review
     501
     502                  self.__register_interests()
     503          #--------------------------------------------------------
     504          # reget-on-paint API
     505          #--------------------------------------------------------
     506 -        def _schedule_data_reget(self):
     507                  _log.debug('called by reget-on-paint mixin API')
     508                  gmRegetMixin.cRegetOnPaintMixin._schedule_data_reget(self)
     509          #--------------------------------------------------------
     510 -        def _populate_with_data(self):
     511                  _log.debug('_populate_with_data() (after _schedule_data_reget ?)')
     512                  self.__populate_inbox()
     513                  return True
     514          #--------------------------------------------------------
     515          # notebook plugin API
     516          #--------------------------------------------------------
     517 -        def repopulate_ui(self):
     518                  _log.debug('called by notebook plugin API, skipping inbox loading')
     519                  #gmRegetMixin.cRegetOnPaintMixin.repopulate_ui(self)
     520                  return True
     521          #--------------------------------------------------------
     522          # internal helpers
     523          #--------------------------------------------------------
     524 -        def __register_interests(self):
     525                  gmDispatcher.connect(signal = u'dem.message_inbox_mod_db', receiver = self._on_message_inbox_mod_db)
     526                  # FIXME: listen for results insertion/deletion
     527                  gmDispatcher.connect(signal = u'clin.reviewed_test_results_mod_db', receiver = self._on_results_mod_db)
     528                  gmDispatcher.connect(signal = u'dem.identity_mod_db', receiver = self._on_identity_mod_db)
     529                  gmDispatcher.connect(signal = u'blobs.doc_med_mod_db', receiver = self._on_doc_mod_db)
     530                  gmDispatcher.connect(signal = u'blobs.reviewed_doc_objs_mod_db', receiver = self._on_doc_obj_review_mod_db)
     531                  gmDispatcher.connect(signal = u'post_patient_selection', receiver = self._on_post_patient_selection)
     532          #--------------------------------------------------------
     533 -        def __init_ui(self):
     534                  self._LCTRL_provider_inbox.debug = 'provider inbox list'
     535
     536                  self._LCTRL_provider_inbox.set_columns([u'', _('Sent'), _('Status'), _('Category - Type'), _('Message')])
     537                  self._LCTRL_provider_inbox.searchable_columns = [2, 3, 4]
     538                  self._LCTRL_provider_inbox.item_tooltip_callback = self._get_msg_tooltip
     539
     540                  self.__update_greeting()
     541
     542                  if gmPerson.gmCurrentPatient().connected:
     543                          self._CHBOX_active_patient.Enable()
     544          #--------------------------------------------------------
     545 -        def __update_greeting(self, no_of_messages=None):
     546                  msg = _(' Inbox of %s %s%s') % (
     547                          gmTools.coalesce (
     548                                  self.provider['title'],
     549                                  gmPerson.map_gender2salutation(self.provider['gender'])
     550                          ),
     551                          self.provider['lastnames'],
     552                          gmTools.coalesce(no_of_messages, u'.', _(': %s message(s)'))
     553                  )
     554                  self._msg_welcome.SetLabel(msg)
     555          #--------------------------------------------------------
     556 -        def __populate_inbox(self):
     557                  _log.debug('populating provider inbox')
     558
     559                  # calculate constraints
     560                  pk_patient = None
     561                  if self._CHBOX_active_patient.IsChecked():
     562                          _log.debug('restricting to active patient')
     563                          curr_pat = gmPerson.gmCurrentPatient()
     564                          if curr_pat.connected:
     565                                  pk_patient = curr_pat.ID
     566
     567                  include_without_provider = True
     568                  if self._CHBOX_active_provider.IsChecked():
     569                          _log.debug('restricting to active provider directly')
     570                          include_without_provider = False
     571
     572                  # get which messages to show
     573                  if self._RBTN_all_messages.GetValue():
     574                          _log.debug('loading all but expired messages')
     575                          self.__msgs = self.provider.inbox.get_messages (
     576                                  pk_patient = pk_patient,
     577                                  include_without_provider = include_without_provider,
     578                                  exclude_expired = True,
     579                                  expired_only = False,
     580                                  overdue_only = False,
     581                                  unscheduled_only = False,
     582                                  exclude_unscheduled = False
     583                          )
     584                  elif self._RBTN_overdue_messages.GetValue():
     585                          _log.debug('loading overdue messages only')
     586                          self.__msgs = self.provider.inbox.get_messages (
     587                                  pk_patient = pk_patient,
     588                                  include_without_provider = include_without_provider,
     589                                  exclude_expired = True,
     590                                  expired_only = False,
     591                                  overdue_only = True,
     592                                  unscheduled_only = False,
     593                                  exclude_unscheduled = True,
     594                                  order_by = u'due_date, importance DESC, received_when DESC'
     595                          )
     596                  elif self._RBTN_scheduled_messages.GetValue():
     597                          _log.debug('loading overdue messages only')
     598                          self.__msgs = self.provider.inbox.get_messages (
     599                                  pk_patient = pk_patient,
     600                                  include_without_provider = include_without_provider,
     601                                  exclude_expired = True,
     602                                  expired_only = False,
     603                                  overdue_only = False,
     604                                  unscheduled_only = False,
     605                                  exclude_unscheduled = True,
     606                                  order_by = u'due_date, importance DESC, received_when DESC'
     607                          )
     608                  elif self._RBTN_unscheduled_messages.GetValue():
     609                          _log.debug('loading unscheduled messages only')
     610                          self.__msgs = self.provider.inbox.get_messages (
     611                                  pk_patient = pk_patient,
     612                                  include_without_provider = include_without_provider,
     613                                  exclude_expired = True,
     614                                  expired_only = False,
     615                                  overdue_only = False,
     616                                  unscheduled_only = True,
     617                                  exclude_unscheduled = False
     618                          )
     619                  elif self._RBTN_expired_messages.GetValue():
     620                          _log.debug('loading expired messages only')
     621                          self.__msgs = self.provider.inbox.get_messages (
     622                                  pk_patient = pk_patient,
     623                                  include_without_provider = include_without_provider,
     624                                  exclude_expired = False,
     625                                  expired_only = True,
     626                                  overdue_only = False,
     627                                  unscheduled_only = False,
     628                                  exclude_unscheduled = True,
     629                                  order_by = u'expiry_date DESC, importance DESC, received_when DESC'
     630                          )
     631
     632                  _log.debug('total # of inbox msgs: %s', len(self.__msgs))
     633
     634                  items = []
     635                  for m in self.__msgs:
     636                          item = [_indicator[m['importance']], gmDateTime.pydt_strftime(m['received_when'], '%Y-%m-%d')]
     637                          if m['due_date'] is None:
     638                                  item.append(u'')
     639                          else:
     640                                  if m['is_expired'] is True:
     641                                          item.append(_('expired'))
     642                                  else:
     643                                          if m['is_overdue'] is True:
     644                                                  item.append(_('%s overdue') % gmDateTime.format_interval_medically(m['interval_due']))
     645                                          else:
     646                                                  item.append(_('due in %s') % gmDateTime.format_interval_medically(m['interval_due']))
     647                          item.append(u'%s - %s' % (m['l10n_category'], m['l10n_type']))
     648                          item.append(m['comment'])
     649                          items.append(item)
     650
     651                  _log.debug('# of list items created from msgs: %s', len(items))
     652                  self._LCTRL_provider_inbox.set_string_items(items = items)
     653                  self._LCTRL_provider_inbox.set_data(data = self.__msgs)
     654                  self._LCTRL_provider_inbox.set_column_widths()
     655                  self._TXT_inbox_item_comment.SetValue(u'')
     656                  self.__update_greeting(len(items))
     657          #--------------------------------------------------------
     658          # event handlers
     659          #--------------------------------------------------------
     660 -        def _on_results_mod_db(self):
     661                  _log.debug('reviewed_test_results_mod_db')
     662                  wx.CallAfter(self.__on_message_inbox_mod_db)
     663          #--------------------------------------------------------
     664 -        def _on_identity_mod_db(self):
     665                  _log.debug('identity_mod_db')
     666                  wx.CallAfter(self.__on_message_inbox_mod_db)
     667          #--------------------------------------------------------
     668 -        def _on_doc_obj_review_mod_db(self):
     669                  _log.debug('doc_obj_review_mod_db')
     670                  wx.CallAfter(self.__on_message_inbox_mod_db)
     671          #--------------------------------------------------------
     672 -        def _on_doc_mod_db(self):
     673                  _log.debug('doc_mod_db')
     674                  wx.CallAfter(self.__on_message_inbox_mod_db)
     675          #--------------------------------------------------------
     676 -        def _on_message_inbox_mod_db(self, *args, **kwargs):
     677                  _log.debug('message_inbox_mod_db')
     678                  wx.CallAfter(self.__on_message_inbox_mod_db)
     679
     680 -        def __on_message_inbox_mod_db(self):
     681                  self._schedule_data_reget()
     682                  gmDispatcher.send(signal = u'request_user_attention', msg = _('Please check your GNUmed Inbox !'))
     683          #--------------------------------------------------------
     684 -        def _on_post_patient_selection(self):
     685                  _log.debug('post_patient_selection')
     686                  wx.CallAfter(self.__on_post_patient_selection)
     687
     688 -        def __on_post_patient_selection(self):
     689                  self._CHBOX_active_patient.Enable()
     690                  self._schedule_data_reget()
     691          #--------------------------------------------------------
     692 -        def _lst_item_activated(self, evt):
     693
     694                  try:
     695                          msg = self._LCTRL_provider_inbox.get_selected_item_data(only_one = True)
     696                  except IndexError:
     697                          _log.exception('problem with provider inbox item data access')
     698                          gmGuiHelpers.gm_show_error (
     699                                  aTitle = _('handling provider inbox item'),
     700                                  aMessage = _('There was a problem accessing the message data.')
     701                          )
     702                          _log.debug('effecting inbox reload')
     703                          wx.CallAfter(self.__populate_inbox)
     704                          return False
     705
     706                  if msg is None:
     707                          return
     708
     709                  handler_key = '%s.%s' % (msg['category'], msg['type'])
     710                  try:
     711                          handle_item = cProviderInboxPnl._item_handlers[handler_key]
     712                  except KeyError:
     713                          if msg['pk_patient'] is None:
     714                                  gmGuiHelpers.gm_show_warning (
     715                                          _('No double-click action pre-programmed into\n'
     716                                          'GNUmed for message category and type:\n'
     717                                          '\n'
     718                                          ' [%s]\n'
     719                                          ) % handler_key,
     720                                          _('handling provider inbox item')
     721                                  )
     722                                  return False
     723                          handle_item = self._goto_patient
     724
     725                  if not handle_item(pk_context = msg['pk_context'], pk_patient = msg['pk_patient']):
     726                          _log.error('item handler returned <False>')
     727                          _log.error('handler key: [%s]', handler_key)
     728                          _log.error('message: %s', str(msg))
     729                          return False
     730
     731                  return True
     732          #--------------------------------------------------------
     733 -        def _lst_item_focused(self, evt):
     734                  pass
     735          #--------------------------------------------------------
     736 -        def _lst_item_selected(self, evt):
     737                  msg = self._LCTRL_provider_inbox.get_selected_item_data(only_one = True)
     738                  if msg is None:
     739                          return
     740
     741                  if msg['data'] is None:
     742                          tmp = _('Message: %s') % msg['comment']
     743                  else:
     744                          tmp = _('Message: %s\nData: %s') % (msg['comment'], msg['data'])
     745
     746                  self._TXT_inbox_item_comment.SetValue(tmp)
     747          #--------------------------------------------------------
     748 -        def _lst_item_right_clicked(self, evt):
     749                  tmp = self._LCTRL_provider_inbox.get_selected_item_data(only_one = True)
     750                  if tmp is None:
     751                          return
     752                  self.__focussed_msg = tmp
     753
     754                  # build menu
     755                  menu = wx.Menu(title = _('Inbox Message Actions:'))
     756
     757                  if self.__focussed_msg['pk_patient'] is not None:
     758                          ID = wx.NewId()
     759                          menu.AppendItem(wx.MenuItem(menu, ID, _('Activate patient')))
     760                          wx.EVT_MENU(menu, ID, self._on_goto_patient)
     761
     762                  if not self.__focussed_msg['is_virtual']:
     763                          # - delete message
     764                          ID = wx.NewId()
     765                          menu.AppendItem(wx.MenuItem(menu, ID, _('Delete')))
     766                          wx.EVT_MENU(menu, ID, self._on_delete_focussed_msg)
     767                          # - edit message
     768                          ID = wx.NewId()
     769                          menu.AppendItem(wx.MenuItem(menu, ID, _('Edit')))
     770                          wx.EVT_MENU(menu, ID, self._on_edit_focussed_msg)
     771
     772  #               if self.__focussed_msg['pk_staff'] is not None:
     773  #                       # - distribute to other providers
     774  #                       ID = wx.NewId()
     775  #                       menu.AppendItem(wx.MenuItem(menu, ID, _('Distribute')))
     776  #                       wx.EVT_MENU(menu, ID, self._on_distribute_focussed_msg)
     777
     778                  # show menu
     779                  self.PopupMenu(menu, wx.DefaultPosition)
     780                  menu.Destroy()
     781          #--------------------------------------------------------
     782 -        def _on_message_range_radiobutton_selected(self, event):
     783                  self._TXT_inbox_item_comment.SetValue(u'')
     784                  _log.debug('_on_message_range_radiobutton_selected')
     785                  self.__populate_inbox()
     786          #--------------------------------------------------------
     787 -        def _on_active_patient_checkbox_ticked(self, event):
     788                  self._TXT_inbox_item_comment.SetValue(u'')
     789                  _log.debug('_on_active_patient_checkbox_ticked')
     790                  self.__populate_inbox()
     791          #--------------------------------------------------------
     792 -        def _on_active_provider_checkbox_ticked(self, event):
     793                  self._TXT_inbox_item_comment.SetValue(u'')
     794                  _log.debug('_on_active_provider_checkbox_ticked')
     795                  self.__populate_inbox()
     796          #--------------------------------------------------------
     797 -        def _on_add_button_pressed(self, event):
     798                  edit_inbox_message(parent = self, message = None, single_entry = False)
     799          #--------------------------------------------------------
     800 -        def _get_msg_tooltip(self, msg):
     801                  return msg.format()
     802          #--------------------------------------------------------
     803          # item handlers
     804          #--------------------------------------------------------
     805 -        def _on_goto_patient(self, evt):
     806                  return self._goto_patient(pk_patient = self.__focussed_msg['pk_patient'])
     807          #--------------------------------------------------------
     808 -        def _on_delete_focussed_msg(self, evt):
     809                  if self.__focussed_msg['is_virtual']:
     810                          gmDispatcher.send(signal = 'statustext', msg = _('You must deal with the reason for this message to remove it from your inbox.'), beep = True)
     811                          return False
     812
     813                  pk_patient = self.__focussed_msg['pk_patient']
     814                  if pk_patient is not None:
     815                          emr = gmClinicalRecord.cClinicalRecord(aPKey = pk_patient, allow_user_interaction = False)
     816                          epi = emr.add_episode(episode_name = 'administrative', is_open = False)
     817                          soap_cat = gmTools.bool2subst (
     818                                  (self.__focussed_msg['category'] == u'clinical'),
     819                                  u'U',
     820                                  None
     821                          )
     822                          narr = _('Deleted inbox message:\n%s') % self.__focussed_msg.format(with_patient = False)
     823                          emr.add_clin_narrative(note = narr, soap_cat = soap_cat, episode = epi)
     824                          gmDispatcher.send(signal = 'statustext', msg = _('Recorded deletion of inbox message in EMR.'), beep = False)
     825
     826                  if not self.provider.inbox.delete_message(self.__focussed_msg['pk_inbox_message']):
     827                          gmDispatcher.send(signal='statustext', msg=_('Problem removing message from Inbox.'))
     828                          return False
     829                  return True
     830          #--------------------------------------------------------
     831 -        def _on_edit_focussed_msg(self, evt):
     832                  if self.__focussed_msg['is_virtual']:
     833                          gmDispatcher.send(signal = 'statustext', msg = _('This message cannot be edited because it is virtual.'))
     834                          return False
     835                  edit_inbox_message(parent = self, message = self.__focussed_msg, single_entry = True)
     836                  return True
     837          #--------------------------------------------------------
     838 -        def _on_distribute_focussed_msg(self, evt):
     839                  if self.__focussed_msg['pk_staff'] is None:
     840                          gmDispatcher.send(signal = 'statustext', msg = _('This message is already visible to all providers.'))
     841                          return False
     842                  print "now distributing"
     843                  return True
     844          #--------------------------------------------------------
     845 -        def _goto_patient(self, pk_context=None, pk_patient=None):
     846
     847                  wx.BeginBusyCursor()
     848
     849                  msg = _('There is a message about patient [%s].\n\n'
     850                          'However, I cannot find that\n'
     851                          'patient in the GNUmed database.'
     852                  ) % pk_patient
     853
     854                  try:
     855                          pat = gmPerson.cIdentity(aPK_obj = pk_patient)
     856                  except gmExceptions.ConstructorError:
     857                          wx.EndBusyCursor()
     858                          _log.exception('patient [%s] not found', pk_patient)
     859                          gmGuiHelpers.gm_show_error(msg, _('handling provider inbox item'))
     860                          return False
     861                  except:
     862                          wx.EndBusyCursor()
     863                          raise
     864
     865                  success = set_active_patient(patient = pat)
     866
     867                  wx.EndBusyCursor()
     868
     869                  if not success:
     870                          gmGuiHelpers.gm_show_error(msg, _('handling provider inbox item'))
     871                          return False
     872
     873                  return True
     874          #--------------------------------------------------------
     875 -        def _goto_doc_review(self, pk_context=None, pk_patient=None):
     876
     877                  msg = _('Supposedly there are unreviewed documents\n'
     878                          'for patient [%s]. However, I cannot find\n'
     879                          'that patient in the GNUmed database.'
     880                  ) % pk_patient
     881
     882                  wx.BeginBusyCursor()
     883
     884                  try:
     885                          pat = gmPerson.cIdentity(aPK_obj = pk_patient)
     886                  except gmExceptions.ConstructorError:
     887                          wx.EndBusyCursor()
     888                          _log.exception('patient [%s] not found', pk_patient)
     889                          gmGuiHelpers.gm_show_error(msg, _('handling provider inbox item'))
     890                          return False
     891
     892                  success = set_active_patient(patient = pat)
     893
     894                  wx.EndBusyCursor()
     895
     896                  if not success:
     897                          gmGuiHelpers.gm_show_error(msg, _('handling provider inbox item'))
     898                          return False
     899
     900                  wx.CallAfter(gmDispatcher.send, signal = 'display_widget', name = 'gmShowMedDocs', sort_mode = 'review')
     901                  return True
     902          #--------------------------------------------------------
     903 -        def _goto_measurements_review(self, pk_context=None, pk_patient=None):
     904
     905                  msg = _('Supposedly there are unreviewed results\n'
     906                          'for patient [%s]. However, I cannot find\n'
     907                          'that patient in the GNUmed database.'
     908                  ) % pk_patient
     909
     910                  wx.BeginBusyCursor()
     911
     912                  try:
     913                          pat = gmPerson.cIdentity(aPK_obj = pk_patient)
     914                  except gmExceptions.ConstructorError:
     915                          wx.EndBusyCursor()
     916                          _log.exception('patient [%s] not found', pk_patient)
     917                          gmGuiHelpers.gm_show_error(msg, _('handling provider inbox item'))
     918                          return False
     919
     920                  success = set_active_patient(patient = pat)
     921
     922                  wx.EndBusyCursor()
     923
     924                  if not success:
     925                          gmGuiHelpers.gm_show_error(msg, _('handling provider inbox item'))
     926                          return False
     927
     928                  wx.CallAfter(gmDispatcher.send, signal = 'display_widget', name = 'gmMeasurementsGridPlugin')
     929                  return True
     930          #--------------------------------------------------------
     931 -        def _goto_vaccination_review(self, pk_context=None, pk_patient=None):
     932
     933                  msg = _('Supposedly there are conflicting vaccinations\n'
     934                          'for patient [%s]. However, I cannot find\n'
     935                          'that patient in the GNUmed database.'
     936                  ) % pk_patient
     937
     938                  wx.BeginBusyCursor()
     939
     940                  try:
     941                          pat = gmPerson.cIdentity(aPK_obj = pk_patient)
     942                  except gmExceptions.ConstructorError:
     943                          wx.EndBusyCursor()
     944                          _log.exception('patient [%s] not found', pk_patient)
     945                          gmGuiHelpers.gm_show_error(msg, _('handling provider inbox item'))
     946                          return False
     947
     948                  success = set_active_patient(patient = pat)
     949
     950                  wx.EndBusyCursor()
     951
     952                  if not success:
     953                          gmGuiHelpers.gm_show_error(msg, _('handling provider inbox item'))
     954                          return False
     955
     956                  wx.CallAfter(gmVaccWidgets.manage_vaccinations)
     957
     958                  return True
     959  #============================================================
     960 -def browse_dynamic_hints(parent=None):
     961
     962          if parent is None:
     963                  parent = wx.GetApp().GetTopWindow()
     964          #------------------------------------------------------------
     965          def get_tooltip(item):
     966                  if item is None:
     967                          return None
     968                  return item.format()
     969          #------------------------------------------------------------
     970          def switch_activation(item):
     971                  conn = gmAuthWidgets.get_dbowner_connection(procedure = _('Switching clinical hint activation'))
     972                  if conn is None:
     973                          return False
     974                  item['is_active'] = not item['is_active']
     975                  return item.save(conn = conn)
     976          #------------------------------------------------------------
     977          def manage_data_packs(item):
     978                  gmDataPackWidgets.manage_data_packs(parent = parent)
     979                  return True
     980          #------------------------------------------------------------
     981          def refresh(lctrl):
     982                  hints = gmProviderInbox.get_dynamic_hints(order_by = u'is_active DESC, source, hint')
     983                  items = [ [
     984                          gmTools.bool2subst(h['is_active'], gmTools.u_checkmark_thin, u''),
     985                          h['title'],
     986                          h['source'][:30],
     987                          h['hint'][:60],
     988                          gmTools.coalesce(h['url'], u'')[:60],
     989                          h['lang'],
     990                          h['pk']
     991                  ] for h in hints ]
     992                  lctrl.set_string_items(items)
     993                  lctrl.set_data(hints)
     994          #------------------------------------------------------------
     995          gmListWidgets.get_choices_from_list (
     996                  parent = parent,
     997                  msg = _('\nDynamic hints registered with GNUmed.\n'),
     998                  caption = _('Showing dynamic hints.'),
     999                  columns = [ _('Active'), _('Title'), _('Source'), _('Hint'), u'URL', _('Language'), u'#' ],
    1000                  single_selection = True,
    1001                  refresh_callback = refresh,
    1002                  left_extra_button = (
    1003                          _('(De)-Activate'),
    1004                          _('Switch activation of the selected hint'),
    1005                          switch_activation
    1006                  ),
    1007                  right_extra_button = (
    1008                          _('Data packs'),
    1009                          _('Browse and install clinical hints data packs'),
    1010                          manage_data_packs
    1011                  ),
    1012                  list_tooltip_callback = get_tooltip
    1013          )
    1014
    1015  #============================================================
    1016  if __name__ == '__main__':
    1017
    1018          if len(sys.argv) < 2:
    1019                  sys.exit()
    1020
    1021          if sys.argv[1] != 'test':
    1022                  sys.exit()
    1023
    1024          gmI18N.activate_locale()
    1025          gmI18N.install_domain(domain = 'gnumed')
    1026
    1027 -        def test_message_inbox():
    1028                  app = wx.PyWidgetTester(size = (800, 600))
    1029                  app.SetWidget(cProviderInboxPnl, -1)
    1030                  app.MainLoop()
    1031
    1032 -        def test_msg_ea():
    1033                  app = wx.PyWidgetTester(size = (800, 600))
    1034                  app.SetWidget(cInboxMessageEAPnl, -1)
    1035                  app.MainLoop()
    1036
    1037
    1038          #test_message_inbox()
    1039          test_msg_ea()
    1040
    1041  #============================================================
    1042