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'message_inbox_generic_mod_db', receiver = self._on_message_inbox_generic_mod_db)
     526                  gmDispatcher.connect(signal = u'message_inbox_mod_db', receiver = self._on_message_inbox_mod_db)
     527                  # FIXME: listen for results insertion/deletion
     528                  gmDispatcher.connect(signal = u'reviewed_test_results_mod_db', receiver = self._on_results_mod_db)
     529                  gmDispatcher.connect(signal = u'identity_mod_db', receiver = self._on_identity_mod_db)
     530                  gmDispatcher.connect(signal = u'doc_mod_db', receiver = self._on_doc_mod_db)
     531                  gmDispatcher.connect(signal = u'doc_obj_review_mod_db', receiver = self._on_doc_obj_review_mod_db)
     532                  gmDispatcher.connect(signal = u'post_patient_selection', receiver = self._on_post_patient_selection)
     533          #--------------------------------------------------------
     534 -        def __init_ui(self):
     535                  self._LCTRL_provider_inbox.debug = 'provider inbox list'
     536
     537                  self._LCTRL_provider_inbox.set_columns([u'', _('Sent'), _('Status'), _('Category - Type'), _('Message')])
     538                  self._LCTRL_provider_inbox.searchable_columns = [2, 3, 4]
     539                  self._LCTRL_provider_inbox.item_tooltip_callback = self._get_msg_tooltip
     540
     541                  self.__update_greeting()
     542
     543                  if gmPerson.gmCurrentPatient().connected:
     544                          self._CHBOX_active_patient.Enable()
     545          #--------------------------------------------------------
     546 -        def __update_greeting(self, no_of_messages=None):
     547                  msg = _(' Inbox of %s %s%s') % (
     548                          gmTools.coalesce (
     549                                  self.provider['title'],
     550                                  gmPerson.map_gender2salutation(self.provider['gender'])
     551                          ),
     552                          self.provider['lastnames'],
     553                          gmTools.coalesce(no_of_messages, u'.', _(': %s message(s)'))
     554                  )
     555                  self._msg_welcome.SetLabel(msg)
     556          #--------------------------------------------------------
     557 -        def __populate_inbox(self):
     558                  _log.debug('populating provider inbox')
     559
     560                  # calculate constraints
     561                  pk_patient = None
     562                  if self._CHBOX_active_patient.IsChecked():
     563                          _log.debug('restricting to active patient')
     564                          curr_pat = gmPerson.gmCurrentPatient()
     565                          if curr_pat.connected:
     566                                  pk_patient = curr_pat.ID
     567
     568                  include_without_provider = True
     569                  if self._CHBOX_active_provider.IsChecked():
     570                          _log.debug('restricting to active provider directly')
     571                          include_without_provider = False
     572
     573                  # get which messages to show
     574                  if self._RBTN_all_messages.GetValue():
     575                          _log.debug('loading all but expired messages')
     576                          self.__msgs = self.provider.inbox.get_messages (
     577                                  pk_patient = pk_patient,
     578                                  include_without_provider = include_without_provider,
     579                                  exclude_expired = True,
     580                                  expired_only = False,
     581                                  overdue_only = False,
     582                                  unscheduled_only = False,
     583                                  exclude_unscheduled = False
     584                          )
     585                  elif self._RBTN_overdue_messages.GetValue():
     586                          _log.debug('loading overdue messages only')
     587                          self.__msgs = self.provider.inbox.get_messages (
     588                                  pk_patient = pk_patient,
     589                                  include_without_provider = include_without_provider,
     590                                  exclude_expired = True,
     591                                  expired_only = False,
     592                                  overdue_only = True,
     593                                  unscheduled_only = False,
     594                                  exclude_unscheduled = True,
     595                                  order_by = u'due_date, importance DESC, received_when DESC'
     596                          )
     597                  elif self._RBTN_scheduled_messages.GetValue():
     598                          _log.debug('loading overdue messages only')
     599                          self.__msgs = self.provider.inbox.get_messages (
     600                                  pk_patient = pk_patient,
     601                                  include_without_provider = include_without_provider,
     602                                  exclude_expired = True,
     603                                  expired_only = False,
     604                                  overdue_only = False,
     605                                  unscheduled_only = False,
     606                                  exclude_unscheduled = True,
     607                                  order_by = u'due_date, importance DESC, received_when DESC'
     608                          )
     609                  elif self._RBTN_unscheduled_messages.GetValue():
     610                          _log.debug('loading unscheduled messages only')
     611                          self.__msgs = self.provider.inbox.get_messages (
     612                                  pk_patient = pk_patient,
     613                                  include_without_provider = include_without_provider,
     614                                  exclude_expired = True,
     615                                  expired_only = False,
     616                                  overdue_only = False,
     617                                  unscheduled_only = True,
     618                                  exclude_unscheduled = False
     619                          )
     620                  elif self._RBTN_expired_messages.GetValue():
     621                          _log.debug('loading expired messages only')
     622                          self.__msgs = self.provider.inbox.get_messages (
     623                                  pk_patient = pk_patient,
     624                                  include_without_provider = include_without_provider,
     625                                  exclude_expired = False,
     626                                  expired_only = True,
     627                                  overdue_only = False,
     628                                  unscheduled_only = False,
     629                                  exclude_unscheduled = True,
     630                                  order_by = u'expiry_date DESC, importance DESC, received_when DESC'
     631                          )
     632
     633                  _log.debug('total # of inbox msgs: %s', len(self.__msgs))
     634
     635                  items = []
     636                  for m in self.__msgs:
     637                          item = [_indicator[m['importance']], gmDateTime.pydt_strftime(m['received_when'], '%Y-%m-%d')]
     638                          if m['due_date'] is None:
     639                                  item.append(u'')
     640                          else:
     641                                  if m['is_expired'] is True:
     642                                          item.append(_('expired'))
     643                                  else:
     644                                          if m['is_overdue'] is True:
     645                                                  item.append(_('%s overdue') % gmDateTime.format_interval_medically(m['interval_due']))
     646                                          else:
     647                                                  item.append(_('due in %s') % gmDateTime.format_interval_medically(m['interval_due']))
     648                          item.append(u'%s - %s' % (m['l10n_category'], m['l10n_type']))
     649                          item.append(m['comment'])
     650                          items.append(item)
     651
     652                  _log.debug('# of list items created from msgs: %s', len(items))
     653                  self._LCTRL_provider_inbox.set_string_items(items = items)
     654                  self._LCTRL_provider_inbox.set_data(data = self.__msgs)
     655                  self._LCTRL_provider_inbox.set_column_widths()
     656                  self._TXT_inbox_item_comment.SetValue(u'')
     657                  self.__update_greeting(len(items))
     658          #--------------------------------------------------------
     659          # event handlers
     660          #--------------------------------------------------------
     661 -        def _on_results_mod_db(self):
     662                  _log.debug('reviewed_test_results_mod_db')
     663                  wx.CallAfter(self.__on_message_inbox_mod_db)
     664          #--------------------------------------------------------
     665 -        def _on_identity_mod_db(self):
     666                  _log.debug('identity_mod_db')
     667                  wx.CallAfter(self.__on_message_inbox_mod_db)
     668          #--------------------------------------------------------
     669 -        def _on_doc_obj_review_mod_db(self):
     670                  _log.debug('doc_obj_review_mod_db')
     671                  wx.CallAfter(self.__on_message_inbox_mod_db)
     672          #--------------------------------------------------------
     673 -        def _on_doc_mod_db(self):
     674                  _log.debug('doc_mod_db')
     675                  wx.CallAfter(self.__on_message_inbox_mod_db)
     676          #--------------------------------------------------------
     677 -        def _on_message_inbox_generic_mod_db(self, *args, **kwargs):
     678                  _log.debug('message_inbox_generic_mod_db')
     679                  wx.CallAfter(self.__on_message_inbox_mod_db)
     680          #--------------------------------------------------------
     681 -        def _on_message_inbox_mod_db(self, *args, **kwargs):
     682                  _log.debug('message_inbox_mod_db')
     683                  wx.CallAfter(self.__on_message_inbox_mod_db)
     684
     685 -        def __on_message_inbox_mod_db(self):
     686                  self._schedule_data_reget()
     687                  gmDispatcher.send(signal = u'request_user_attention', msg = _('Please check your GNUmed Inbox !'))
     688          #--------------------------------------------------------
     689 -        def _on_post_patient_selection(self):
     690                  _log.debug('post_patient_selection')
     691                  wx.CallAfter(self.__on_post_patient_selection)
     692
     693 -        def __on_post_patient_selection(self):
     694                  self._CHBOX_active_patient.Enable()
     695                  self._schedule_data_reget()
     696          #--------------------------------------------------------
     697 -        def _lst_item_activated(self, evt):
     698
     699                  try:
     700                          msg = self._LCTRL_provider_inbox.get_selected_item_data(only_one = True)
     701                  except IndexError:
     702                          _log.exception('problem with provider inbox item data access')
     703                          gmGuiHelpers.gm_show_error (
     704                                  aTitle = _('handling provider inbox item'),
     705                                  aMessage = _('There was a problem accessing the message data.')
     706                          )
     707                          _log.debug('effecting inbox reload')
     708                          wx.CallAfter(self.__populate_inbox)
     709                          return False
     710
     711                  if msg is None:
     712                          return
     713
     714                  handler_key = '%s.%s' % (msg['category'], msg['type'])
     715                  try:
     716                          handle_item = cProviderInboxPnl._item_handlers[handler_key]
     717                  except KeyError:
     718                          if msg['pk_patient'] is None:
     719                                  gmGuiHelpers.gm_show_warning (
     720                                          _('No double-click action pre-programmed into\n'
     721                                          'GNUmed for message category and type:\n'
     722                                          '\n'
     723                                          ' [%s]\n'
     724                                          ) % handler_key,
     725                                          _('handling provider inbox item')
     726                                  )
     727                                  return False
     728                          handle_item = self._goto_patient
     729
     730                  if not handle_item(pk_context = msg['pk_context'], pk_patient = msg['pk_patient']):
     731                          _log.error('item handler returned <False>')
     732                          _log.error('handler key: [%s]', handler_key)
     733                          _log.error('message: %s', str(msg))
     734                          return False
     735
     736                  return True
     737          #--------------------------------------------------------
     738 -        def _lst_item_focused(self, evt):
     739                  pass
     740          #--------------------------------------------------------
     741 -        def _lst_item_selected(self, evt):
     742                  msg = self._LCTRL_provider_inbox.get_selected_item_data(only_one = True)
     743                  if msg is None:
     744                          return
     745
     746                  if msg['data'] is None:
     747                          tmp = _('Message: %s') % msg['comment']
     748                  else:
     749                          tmp = _('Message: %s\nData: %s') % (msg['comment'], msg['data'])
     750
     751                  self._TXT_inbox_item_comment.SetValue(tmp)
     752          #--------------------------------------------------------
     753 -        def _lst_item_right_clicked(self, evt):
     754                  tmp = self._LCTRL_provider_inbox.get_selected_item_data(only_one = True)
     755                  if tmp is None:
     756                          return
     757                  self.__focussed_msg = tmp
     758
     759                  # build menu
     760                  menu = wx.Menu(title = _('Inbox Message Actions:'))
     761
     762                  if self.__focussed_msg['pk_patient'] is not None:
     763                          ID = wx.NewId()
     764                          menu.AppendItem(wx.MenuItem(menu, ID, _('Activate patient')))
     765                          wx.EVT_MENU(menu, ID, self._on_goto_patient)
     766
     767                  if not self.__focussed_msg['is_virtual']:
     768                          # - delete message
     769                          ID = wx.NewId()
     770                          menu.AppendItem(wx.MenuItem(menu, ID, _('Delete')))
     771                          wx.EVT_MENU(menu, ID, self._on_delete_focussed_msg)
     772                          # - edit message
     773                          ID = wx.NewId()
     774                          menu.AppendItem(wx.MenuItem(menu, ID, _('Edit')))
     775                          wx.EVT_MENU(menu, ID, self._on_edit_focussed_msg)
     776
     777  #               if self.__focussed_msg['pk_staff'] is not None:
     778  #                       # - distribute to other providers
     779  #                       ID = wx.NewId()
     780  #                       menu.AppendItem(wx.MenuItem(menu, ID, _('Distribute')))
     781  #                       wx.EVT_MENU(menu, ID, self._on_distribute_focussed_msg)
     782
     783                  # show menu
     784                  self.PopupMenu(menu, wx.DefaultPosition)
     785                  menu.Destroy()
     786          #--------------------------------------------------------
     787 -        def _on_message_range_radiobutton_selected(self, event):
     788                  self._TXT_inbox_item_comment.SetValue(u'')
     789                  _log.debug('_on_message_range_radiobutton_selected')
     790                  self.__populate_inbox()
     791          #--------------------------------------------------------
     792 -        def _on_active_patient_checkbox_ticked(self, event):
     793                  self._TXT_inbox_item_comment.SetValue(u'')
     794                  _log.debug('_on_active_patient_checkbox_ticked')
     795                  self.__populate_inbox()
     796          #--------------------------------------------------------
     797 -        def _on_active_provider_checkbox_ticked(self, event):
     798                  self._TXT_inbox_item_comment.SetValue(u'')
     799                  _log.debug('_on_active_provider_checkbox_ticked')
     800                  self.__populate_inbox()
     801          #--------------------------------------------------------
     802 -        def _on_add_button_pressed(self, event):
     803                  edit_inbox_message(parent = self, message = None, single_entry = False)
     804          #--------------------------------------------------------
     805 -        def _get_msg_tooltip(self, msg):
     806                  return msg.format()
     807          #--------------------------------------------------------
     808          # item handlers
     809          #--------------------------------------------------------
     810 -        def _on_goto_patient(self, evt):
     811                  return self._goto_patient(pk_patient = self.__focussed_msg['pk_patient'])
     812          #--------------------------------------------------------
     813 -        def _on_delete_focussed_msg(self, evt):
     814                  if self.__focussed_msg['is_virtual']:
     815                          gmDispatcher.send(signal = 'statustext', msg = _('You must deal with the reason for this message to remove it from your inbox.'), beep = True)
     816                          return False
     817
     818                  pk_patient = self.__focussed_msg['pk_patient']
     819                  if pk_patient is not None:
     820                          emr = gmClinicalRecord.cClinicalRecord(aPKey = pk_patient, allow_user_interaction = False)
     821                          epi = emr.add_episode(episode_name = 'administration', is_open = False)
     822                          soap_cat = gmTools.bool2subst (
     823                                  (self.__focussed_msg['category'] == u'clinical'),
     824                                  u'U',
     825                                  None
     826                          )
     827                          narr = _('Deleted inbox message:\n%s') % self.__focussed_msg.format(with_patient = False)
     828                          emr.add_clin_narrative(note = narr, soap_cat = soap_cat, episode = epi)
     829                          gmDispatcher.send(signal = 'statustext', msg = _('Recorded deletion of inbox message in EMR.'), beep = False)
     830
     831                  if not self.provider.inbox.delete_message(self.__focussed_msg['pk_inbox_message']):
     832                          gmDispatcher.send(signal='statustext', msg=_('Problem removing message from Inbox.'))
     833                          return False
     834                  return True
     835          #--------------------------------------------------------
     836 -        def _on_edit_focussed_msg(self, evt):
     837                  if self.__focussed_msg['is_virtual']:
     838                          gmDispatcher.send(signal = 'statustext', msg = _('This message cannot be edited because it is virtual.'))
     839                          return False
     840                  edit_inbox_message(parent = self, message = self.__focussed_msg, single_entry = True)
     841                  return True
     842          #--------------------------------------------------------
     843 -        def _on_distribute_focussed_msg(self, evt):
     844                  if self.__focussed_msg['pk_staff'] is None:
     845                          gmDispatcher.send(signal = 'statustext', msg = _('This message is already visible to all providers.'))
     846                          return False
     847                  print "now distributing"
     848                  return True
     849          #--------------------------------------------------------
     850 -        def _goto_patient(self, pk_context=None, pk_patient=None):
     851
     852                  wx.BeginBusyCursor()
     853
     854                  msg = _('There is a message about patient [%s].\n\n'
     855                          'However, I cannot find that\n'
     856                          'patient in the GNUmed database.'
     857                  ) % pk_patient
     858
     859                  try:
     860                          pat = gmPerson.cIdentity(aPK_obj = pk_patient)
     861                  except gmExceptions.ConstructorError:
     862                          wx.EndBusyCursor()
     863                          _log.exception('patient [%s] not found', pk_patient)
     864                          gmGuiHelpers.gm_show_error(msg, _('handling provider inbox item'))
     865                          return False
     866                  except:
     867                          wx.EndBusyCursor()
     868                          raise
     869
     870                  success = set_active_patient(patient = pat)
     871
     872                  wx.EndBusyCursor()
     873
     874                  if not success:
     875                          gmGuiHelpers.gm_show_error(msg, _('handling provider inbox item'))
     876                          return False
     877
     878                  return True
     879          #--------------------------------------------------------
     880 -        def _goto_doc_review(self, pk_context=None, pk_patient=None):
     881
     882                  msg = _('Supposedly there are unreviewed documents\n'
     883                          'for patient [%s]. However, I cannot find\n'
     884                          'that patient in the GNUmed database.'
     885                  ) % pk_patient
     886
     887                  wx.BeginBusyCursor()
     888
     889                  try:
     890                          pat = gmPerson.cIdentity(aPK_obj = pk_patient)
     891                  except gmExceptions.ConstructorError:
     892                          wx.EndBusyCursor()
     893                          _log.exception('patient [%s] not found', pk_patient)
     894                          gmGuiHelpers.gm_show_error(msg, _('handling provider inbox item'))
     895                          return False
     896
     897                  success = set_active_patient(patient = pat)
     898
     899                  wx.EndBusyCursor()
     900
     901                  if not success:
     902                          gmGuiHelpers.gm_show_error(msg, _('handling provider inbox item'))
     903                          return False
     904
     905                  wx.CallAfter(gmDispatcher.send, signal = 'display_widget', name = 'gmShowMedDocs', sort_mode = 'review')
     906                  return True
     907          #--------------------------------------------------------
     908 -        def _goto_measurements_review(self, pk_context=None, pk_patient=None):
     909
     910                  msg = _('Supposedly there are unreviewed results\n'
     911                          'for patient [%s]. However, I cannot find\n'
     912                          'that patient in the GNUmed database.'
     913                  ) % pk_patient
     914
     915                  wx.BeginBusyCursor()
     916
     917                  try:
     918                          pat = gmPerson.cIdentity(aPK_obj = pk_patient)
     919                  except gmExceptions.ConstructorError:
     920                          wx.EndBusyCursor()
     921                          _log.exception('patient [%s] not found', pk_patient)
     922                          gmGuiHelpers.gm_show_error(msg, _('handling provider inbox item'))
     923                          return False
     924
     925                  success = set_active_patient(patient = pat)
     926
     927                  wx.EndBusyCursor()
     928
     929                  if not success:
     930                          gmGuiHelpers.gm_show_error(msg, _('handling provider inbox item'))
     931                          return False
     932
     933                  wx.CallAfter(gmDispatcher.send, signal = 'display_widget', name = 'gmMeasurementsGridPlugin')
     934                  return True
     935          #--------------------------------------------------------
     936 -        def _goto_vaccination_review(self, pk_context=None, pk_patient=None):
     937
     938                  msg = _('Supposedly there are conflicting vaccinations\n'
     939                          'for patient [%s]. However, I cannot find\n'
     940                          'that patient in the GNUmed database.'
     941                  ) % pk_patient
     942
     943                  wx.BeginBusyCursor()
     944
     945                  try:
     946                          pat = gmPerson.cIdentity(aPK_obj = pk_patient)
     947                  except gmExceptions.ConstructorError:
     948                          wx.EndBusyCursor()
     949                          _log.exception('patient [%s] not found', pk_patient)
     950                          gmGuiHelpers.gm_show_error(msg, _('handling provider inbox item'))
     951                          return False
     952
     953                  success = set_active_patient(patient = pat)
     954
     955                  wx.EndBusyCursor()
     956
     957                  if not success:
     958                          gmGuiHelpers.gm_show_error(msg, _('handling provider inbox item'))
     959                          return False
     960
     961                  wx.CallAfter(gmVaccWidgets.manage_vaccinations)
     962
     963                  return True
     964  #============================================================
     965 -def browse_dynamic_hints(parent=None):
     966
     967          if parent is None:
     968                  parent = wx.GetApp().GetTopWindow()
     969          #------------------------------------------------------------
     970          def get_tooltip(item):
     971                  if item is None:
     972                          return None
     973                  return item.format()
     974          #------------------------------------------------------------
     975          def switch_activation(item):
     976                  conn = gmAuthWidgets.get_dbowner_connection(procedure = _('Switching clinical hint activation'))
     977                  if conn is None:
     978                          return False
     979                  item['is_active'] = not item['is_active']
     980                  return item.save(conn = conn)
     981          #------------------------------------------------------------
     982          def manage_data_packs(item):
     983                  gmDataPackWidgets.manage_data_packs(parent = parent)
     984                  return True
     985          #------------------------------------------------------------
     986          def refresh(lctrl):
     987                  hints = gmProviderInbox.get_dynamic_hints(order_by = u'is_active DESC, source, hint')
     988                  items = [ [
     989                          gmTools.bool2subst(h['is_active'], gmTools.u_checkmark_thin, u''),
     990                          h['title'],
     991                          h['source'][:30],
     992                          h['hint'][:60],
     993                          gmTools.coalesce(h['url'], u'')[:60],
     994                          h['lang'],
     995                          h['pk']
     996                  ] for h in hints ]
     997                  lctrl.set_string_items(items)
     998                  lctrl.set_data(hints)
     999          #------------------------------------------------------------
    1000          gmListWidgets.get_choices_from_list (
    1001                  parent = parent,
    1002                  msg = _('\nDynamic hints registered with GNUmed.\n'),
    1003                  caption = _('Showing dynamic hints.'),
    1004                  columns = [ _('Active'), _('Title'), _('Source'), _('Hint'), u'URL', _('Language'), u'#' ],
    1005                  single_selection = True,
    1006                  refresh_callback = refresh,
    1007                  left_extra_button = (
    1008                          _('(De)-Activate'),
    1009                          _('Switch activation of the selected hint'),
    1010                          switch_activation
    1011                  ),
    1012                  right_extra_button = (
    1013                          _('Data packs'),
    1014                          _('Browse and install clinical hints data packs'),
    1015                          manage_data_packs
    1016                  ),
    1017                  list_tooltip_callback = get_tooltip
    1018          )
    1019
    1020  #============================================================
    1021  if __name__ == '__main__':
    1022
    1023          if len(sys.argv) < 2:
    1024                  sys.exit()
    1025
    1026          if sys.argv[1] != 'test':
    1027                  sys.exit()
    1028
    1029          gmI18N.activate_locale()
    1030          gmI18N.install_domain(domain = 'gnumed')
    1031
    1032 -        def test_message_inbox():
    1033                  app = wx.PyWidgetTester(size = (800, 600))
    1034                  app.SetWidget(cProviderInboxPnl, -1)
    1035                  app.MainLoop()
    1036
    1037 -        def test_msg_ea():
    1038                  app = wx.PyWidgetTester(size = (800, 600))
    1039                  app.SetWidget(cInboxMessageEAPnl, -1)
    1040                  app.MainLoop()
    1041
    1042
    1043          #test_message_inbox()
    1044          test_msg_ea()
    1045
    1046  #============================================================
    1047