Gnumed.wxpython.gmNarrativeWorkflows

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

# Source Code for Module Gnumed.wxpython.gmNarrativeWorkflows

      1  """GNUmed narrative workflows."""
      2  #================================================================
      3  __author__ = "Karsten Hilbert <Karsten.Hilbert@gmx.net>"
      4  __license__ = "GPL v2 or later (details at http://www.gnu.org)"
      5
      6  import sys
      7  import logging
      8  import os.path
      9  import time
     10
     11
     12  import wx
     13
     14
     15  if __name__ == '__main__':
     16          sys.path.insert(0, '../../')
     17
     18  from Gnumed.pycommon import gmI18N
     19
     20  if __name__ == '__main__':
     21          gmI18N.activate_locale()
     22          gmI18N.install_domain()
     23
     24  from Gnumed.pycommon import gmDispatcher
     25  from Gnumed.pycommon import gmTools
     26  from Gnumed.pycommon import gmDateTime
     27
     28  from Gnumed.business import gmPerson
     29  from Gnumed.business import gmStaff
     30  from Gnumed.business import gmEMRStructItems
     31  from Gnumed.business import gmClinNarrative
     32  from Gnumed.business import gmSoapDefs
     33  from Gnumed.business import gmProviderInbox
     34
     35  from Gnumed.wxpython import gmListWidgets
     36  from Gnumed.wxpython import gmEMRStructWidgets
     37  from Gnumed.wxpython import gmEncounterWidgets
     38  from Gnumed.wxpython import gmGuiHelpers
     39  from Gnumed.wxpython import gmNarrativeWidgets
     40  from Gnumed.wxpython.gmPatSearchWidgets import set_active_patient
     41
     42  from Gnumed.exporters import gmPatientExporter
     43
     44
     45  _log = logging.getLogger('gm.ui')
     46
     47  #============================================================
     48  # narrative related widgets/functions
     49  #------------------------------------------------------------
     50 -def edit_narrative(parent=None, narrative=None, single_entry=False):
     51          assert isinstance(narrative, gmClinNarrative.cNarrative), '<narrative> must be of type <cNarrative>'
     52
     53          title = _('Editing progress note')
     54          if narrative['modified_by_raw'] == gmStaff.gmCurrentProvider()['db_user']:
     55                  msg = _('Your original progress note:')
     56          else:
     57                  msg = _('Original progress note by %s [%s]\n(will be notified of changes):') % (
     58                          narrative['modified_by'],
     59                          narrative['modified_by_raw']
     60                  )
     61          if parent is None:
     62                  parent = wx.GetApp().GetTopWindow()
     63          dlg = gmGuiHelpers.cMultilineTextEntryDlg (
     64                  parent,
     65                  -1,
     66                  title = title,
     67                  msg = msg,
     68                  data = narrative.format(left_margin = ' ', fancy = True),
     69                  text = narrative['narrative'].strip()
     70          )
     71          decision = dlg.ShowModal()
     72          val = dlg.value.strip()
     73          dlg.DestroyLater()
     74          if decision != wx.ID_SAVE:
     75                  return False
     76
     77          if val == '':
     78                  return False
     79
     80          if val == narrative['narrative'].strip():
     81                  return False
     82
     83          if narrative['modified_by_raw'] == gmStaff.gmCurrentProvider()['db_user']:
     84                  narrative['narrative'] = val
     85                  narrative.save_payload()
     86                  return True
     87
     88          q = _(
     89                  'Original progress note written by someone else:\n'
     90                  '\n'
     91                  ' %s (%s)\n'
     92                  '\n'
     93                  'Upon saving changes that person will be notified.\n'
     94                  '\n'
     95                  'Consider saving as a new progress note instead.'
     96          ) % (
     97                  narrative['modified_by_raw'],
     98                  narrative['modified_by']
     99          )
    100          buttons = [
    101                  {'label': _('Save changes'), 'default': True},
    102                  {'label': _('Save new note')},
    103                  {'label': _('Discard')}
    104          ]
    105          dlg = gmGuiHelpers.c3ButtonQuestionDlg(parent = parent, caption = title, question = q, button_defs = buttons)
    106          decision = dlg.ShowModal()
    107          dlg.DestroyLater()
    108          if decision not in [wx.ID_YES, wx.ID_NO]:
    109                  return False
    110
    111          if decision == wx.ID_NO:
    112                  # create new progress note within the same context as the original one
    113                  gmClinNarrative.create_narrative_item (
    114                          narrative = val,
    115                          soap_cat = narrative['soap_cat'],
    116                          episode_id = narrative['pk_episode'],
    117                          encounter_id = narrative['pk_encounter']
    118                  )
    119                  return True
    120
    121          # notify original provider
    122          msg = gmProviderInbox.create_inbox_message (
    123                  staff = narrative.staff_id,
    124                  message_type = _('Change notification'),
    125                  message_category = 'administrative',
    126                  subject = _('A progress note of yours has been edited.'),
    127                  patient = narrative['pk_patient']
    128          )
    129          msg['data'] = _(
    130                  'Original (by [%s]):\n'
    131                  '%s\n'
    132                  '\n'
    133                  'Edited (by [%s]):\n'
    134                  '%s'
    135          ) % (
    136                  narrative['modified_by'],
    137                  narrative['narrative'].strip(),
    138                  gmStaff.gmCurrentProvider()['short_alias'],
    139                  val
    140          )
    141          msg.save()
    142          # notify /me about the staff member notification
    143          #gmProviderInbox.create_inbox_message (
    144          #       staff = curr_prov['pk_staff'],
    145          #       message_type = _('Privacy notice'),
    146          #       message_category = 'administrative',
    147          #       subject = _('%s: Staff member %s has been notified of your chart access.') % (prov, pat)
    148          #)
    149          # save narrative change
    150          narrative['narrative'] = val
    151          narrative.save()
    152          return True
    153
    154  #------------------------------------------------------------
    155 -def move_progress_notes_to_another_encounter(parent=None, encounters=None, episodes=None, patient=None, move_all=False):
    156
    157          # sanity checks
    158          if patient is None:
    159                  patient = gmPerson.gmCurrentPatient()
    160
    161          if not patient.connected:
    162                  gmDispatcher.send(signal = 'statustext', msg = _('Cannot move progress notes. No active patient.'))
    163                  return False
    164
    165          if parent is None:
    166                  parent = wx.GetApp().GetTopWindow()
    167
    168          emr = patient.emr
    169
    170          if encounters is None:
    171                  all_encs_in_epi = emr.get_encounters(episodes = episodes, skip_empty = True)
    172                  # nothing to do ?
    173                  if len(all_encs_in_epi) == 0:
    174                          return True
    175                  encounters = gmEncounterWidgets.select_encounters (
    176                          parent = parent,
    177                          patient = patient,
    178                          single_selection = False,
    179                          encounters = all_encs_in_epi
    180                  )
    181                  # cancelled
    182                  if encounters is None:
    183                          return True
    184                  # none selected
    185                  if len(encounters) == 0:
    186                          return True
    187
    188          notes = emr.get_clin_narrative (
    189                  encounters = encounters,
    190                  episodes = episodes
    191          )
    192
    193          # which narrative
    194          if move_all:
    195                  selected_narr = notes
    196          else:
    197                  selected_narr = gmListWidgets.get_choices_from_list (
    198                          parent = parent,
    199                          caption = _('Moving progress notes between encounters ...'),
    200                          single_selection = False,
    201                          can_return_empty = True,
    202                          data = notes,
    203                          msg = _('\n Select the progress notes to move from the list !\n\n'),
    204                          columns = [_('when'), _('who'), _('type'), _('entry')],
    205                          choices = [
    206                                  [       narr['date'].strftime('%x %H:%M'),
    207                                          narr['modified_by'],
    208                                          gmSoapDefs.soap_cat2l10n[narr['soap_cat']],
    209                                          narr['narrative'].replace('\n', '/').replace('\r', '/')
    210                                  ] for narr in notes
    211                          ]
    212                  )
    213
    214          if not selected_narr:
    215                  return True
    216
    217          # which encounter to move to
    218          enc2move2 = gmEncounterWidgets.select_encounters (
    219                  parent = parent,
    220                  patient = patient,
    221                  single_selection = True
    222          )
    223
    224          if not enc2move2:
    225                  return True
    226
    227          for narr in selected_narr:
    228                  narr['pk_encounter'] = enc2move2['pk_encounter']
    229                  narr.save()
    230
    231          return True
    232
    233  #------------------------------------------------------------
    234 -def manage_progress_notes(parent=None, encounters=None, episodes=None, patient=None):
    235
    236          # sanity checks
    237          if patient is None:
    238                  patient = gmPerson.gmCurrentPatient()
    239
    240          if not patient.connected:
    241                  gmDispatcher.send(signal = 'statustext', msg = _('Cannot edit progress notes. No active patient.'))
    242                  return False
    243
    244          if parent is None:
    245                  parent = wx.GetApp().GetTopWindow()
    246
    247          emr = patient.emr
    248          #--------------------------
    249          def delete(item):
    250                  if item is None:
    251                          return False
    252                  dlg = gmGuiHelpers.c2ButtonQuestionDlg (
    253                          parent,
    254                          -1,
    255                          caption = _('Deleting progress note'),
    256                          question = _(
    257                                  'Are you positively sure you want to delete this\n'
    258                                  'progress note from the medical record ?\n'
    259                                  '\n'
    260                                  'Note that even if you chose to delete the entry it will\n'
    261                                  'still be (invisibly) kept in the audit trail to protect\n'
    262                                  'you from litigation because physical deletion is known\n'
    263                                  'to be unlawful in some jurisdictions.\n'
    264                          ),
    265                          button_defs = (
    266                                  {'label': _('Delete'), 'tooltip': _('Yes, delete the progress note.'), 'default': False},
    267                                  {'label': _('Cancel'), 'tooltip': _('No, do NOT delete the progress note.'), 'default': True}
    268                          )
    269                  )
    270                  decision = dlg.ShowModal()
    271
    272                  if decision != wx.ID_YES:
    273                          return False
    274
    275                  gmClinNarrative.delete_clin_narrative(narrative = item['pk_narrative'])
    276                  return True
    277          #--------------------------
    278          def edit(item):
    279                  if item is None:
    280                          return False
    281
    282                  dlg = gmGuiHelpers.cMultilineTextEntryDlg (
    283                          parent,
    284                          -1,
    285                          title = _('Editing progress note'),
    286                          msg = _('This is the original progress note:'),
    287                          data = item.format(left_margin = ' ', fancy = True),
    288                          text = item['narrative']
    289                  )
    290                  decision = dlg.ShowModal()
    291
    292                  if decision != wx.ID_SAVE:
    293                          return False
    294
    295                  val = dlg.value
    296                  dlg.DestroyLater()
    297                  if val.strip() == '':
    298                          return False
    299
    300                  item['narrative'] = val
    301                  item.save_payload()
    302                  return True
    303
    304          #--------------------------
    305          def refresh(lctrl):
    306                  notes = emr.get_clin_narrative (
    307                          encounters = encounters,
    308                          episodes = episodes,
    309                          providers = [ gmStaff.gmCurrentProvider()['short_alias'] ]
    310                  )
    311                  lctrl.set_string_items(items = [
    312                          [       narr['date'].strftime('%x %H:%M'),
    313                                  gmSoapDefs.soap_cat2l10n[narr['soap_cat']],
    314                                  narr['narrative'].replace('\n', '/').replace('\r', '/')
    315                          ] for narr in notes
    316                  ])
    317                  lctrl.set_data(data = notes)
    318          #--------------------------
    319
    320          gmListWidgets.get_choices_from_list (
    321                  parent = parent,
    322                  caption = _('Managing progress notes'),
    323                  msg = _(
    324                          '\n'
    325                          ' This list shows the progress notes by %s.\n'
    326                          '\n'
    327                  ) % gmStaff.gmCurrentProvider()['short_alias'],
    328                  columns = [_('when'), _('type'), _('entry')],
    329                  single_selection = True,
    330                  can_return_empty = False,
    331                  edit_callback = edit,
    332                  delete_callback = delete,
    333                  refresh_callback = refresh
    334          )
    335
    336  #------------------------------------------------------------
    337 -def search_narrative_across_emrs(parent=None):
    338
    339          if parent is None:
    340                  parent = wx.GetApp().GetTopWindow()
    341
    342          search_term_dlg = wx.TextEntryDialog (
    343                  parent,
    344                  _('Enter (regex) term to search for across all EMRs:'),
    345                  caption = _('Text search across all EMRs'),
    346                  style = wx.OK | wx.CANCEL | wx.CENTRE
    347          )
    348          result = search_term_dlg.ShowModal()
    349
    350          if result != wx.ID_OK:
    351                  return
    352
    353          wx.BeginBusyCursor()
    354          search_term = search_term_dlg.GetValue()
    355          search_term_dlg.DestroyLater()
    356          results = gmClinNarrative.search_text_across_emrs(search_term = search_term)
    357          wx.EndBusyCursor()
    358
    359          if len(results) == 0:
    360                  gmGuiHelpers.gm_show_info (
    361                          _(
    362                          'Nothing found for search term:\n'
    363                          ' "%s"'
    364                          ) % search_term,
    365                          _('Search results')
    366                  )
    367                  return
    368
    369          items = [ [
    370                  gmPerson.cPerson(aPK_obj = r['pk_patient'])['description_gender'],
    371                  r['narrative'],
    372                  r['src_table']
    373          ] for r in results ]
    374
    375          selected_patient = gmListWidgets.get_choices_from_list (
    376                  parent = parent,
    377                  caption = _('Search results for [%s]') % search_term,
    378                  choices = items,
    379                  columns = [_('Patient'), _('Match'), _('Match location')],
    380                  data = [ r['pk_patient'] for r in results ],
    381                  single_selection = True,
    382                  can_return_empty = False
    383          )
    384
    385          if selected_patient is None:
    386                  return
    387
    388          wx.CallAfter(set_active_patient, patient = gmPerson.cPerson(aPK_obj = selected_patient))
    389
    390  #------------------------------------------------------------
    391 -def search_narrative_in_emr(parent=None, patient=None):
    392
    393          # sanity checks
    394          if patient is None:
    395                  patient = gmPerson.gmCurrentPatient()
    396
    397          if not patient.connected:
    398                  gmDispatcher.send(signal = 'statustext', msg = _('Cannot search EMR. No active patient.'))
    399                  return False
    400
    401          if parent is None:
    402                  parent = wx.GetApp().GetTopWindow()
    403
    404          search_term_dlg = wx.TextEntryDialog (
    405                  parent,
    406                  _('Enter search term:'),
    407                  caption = _('Text search of entire EMR of active patient'),
    408                  style = wx.OK | wx.CANCEL | wx.CENTRE
    409          )
    410          result = search_term_dlg.ShowModal()
    411
    412          if result != wx.ID_OK:
    413                  search_term_dlg.DestroyLater()
    414                  return False
    415
    416          wx.BeginBusyCursor()
    417          val = search_term_dlg.GetValue()
    418          search_term_dlg.DestroyLater()
    419          emr = patient.emr
    420          rows = emr.search_narrative_simple(val)
    421          wx.EndBusyCursor()
    422
    423          if len(rows) == 0:
    424                  gmGuiHelpers.gm_show_info (
    425                          _(
    426                          'Nothing found for search term:\n'
    427                          ' "%s"'
    428                          ) % val,
    429                          _('Search results')
    430                  )
    431                  return True
    432
    433          txt = ''
    434          for row in rows:
    435                  txt += '%s: %s\n' % (
    436                          row['soap_cat'],
    437                          row['narrative']
    438                  )
    439
    440                  txt += ' %s: %s - %s %s\n' % (
    441                          _('Encounter'),
    442                          row['encounter_started'].strftime('%x %H:%M'),
    443                          row['encounter_ended'].strftime('%H:%M'),
    444                          row['encounter_type']
    445                  )
    446                  txt += ' %s: %s\n' % (
    447                          _('Episode'),
    448                          row['episode']
    449                  )
    450                  txt += ' %s: %s\n\n' % (
    451                          _('Health issue'),
    452                          row['health_issue']
    453                  )
    454
    455          msg = _(
    456                  'Search term was: "%s"\n'
    457                  '\n'
    458                  'Search results:\n\n'
    459                  '%s\n'
    460          ) % (val, txt)
    461
    462          dlg = wx.MessageDialog (
    463                  parent = parent,
    464                  message = msg,
    465                  caption = _('Search results for [%s]') % val,
    466                  style = wx.OK | wx.STAY_ON_TOP
    467          )
    468          dlg.ShowModal()
    469          dlg.DestroyLater()
    470
    471          return True
    472
    473  #------------------------------------------------------------
    474 -def export_narrative_for_medistar_import(parent=None, soap_cats='soapu', encounter=None):
    475
    476          # sanity checks
    477          pat = gmPerson.gmCurrentPatient()
    478          if not pat.connected:
    479                  gmDispatcher.send(signal = 'statustext', msg = _('Cannot export EMR for Medistar. No active patient.'))
    480                  return False
    481
    482          if encounter is None:
    483                  encounter = pat.emr.active_encounter
    484
    485          if parent is None:
    486                  parent = wx.GetApp().GetTopWindow()
    487
    488          # get file name
    489          aWildcard = "%s (*.txt)|*.txt|%s (*)|*" % (_("text files"), _("all files"))
    490                  # FIXME: make configurable
    491          aDefDir = os.path.abspath(os.path.expanduser(os.path.join('~', 'gnumed')))
    492                  # FIXME: make configurable
    493          fname = '%s-%s-%s-%s-%s.txt' % (
    494                  'Medistar-MD',
    495                  time.strftime('%Y-%m-%d',time.localtime()),
    496                  pat['lastnames'].replace(' ', '-'),
    497                  pat['firstnames'].replace(' ', '_'),
    498                  pat.get_formatted_dob(format = '%Y-%m-%d')
    499          )
    500          dlg = wx.FileDialog (
    501                  parent = parent,
    502                  message = _("Save EMR extract for MEDISTAR import as..."),
    503                  defaultDir = aDefDir,
    504                  defaultFile = fname,
    505                  wildcard = aWildcard,
    506                  style = wx.FD_SAVE
    507          )
    508          choice = dlg.ShowModal()
    509          fname = dlg.GetPath()
    510          dlg.DestroyLater()
    511          if choice != wx.ID_OK:
    512                  return False
    513
    514          wx.BeginBusyCursor()
    515          _log.debug('exporting encounter for medistar import to [%s]', fname)
    516          exporter = gmPatientExporter.cMedistarSOAPExporter(patient = pat)
    517          successful, fname = exporter.save_to_file (
    518                  filename = fname,
    519                  encounter = encounter,
    520                  soap_cats = 'soapu',
    521                  export_to_import_file = True
    522          )
    523          if not successful:
    524                  gmGuiHelpers.gm_show_error (
    525                          _('Error exporting progress notes for MEDISTAR import.'),
    526                          _('MEDISTAR progress notes export')
    527                  )
    528                  wx.EndBusyCursor()
    529                  return False
    530
    531          gmDispatcher.send(signal = 'statustext', msg = _('Successfully exported progress notes into file [%s] for Medistar import.') % fname, beep=False)
    532
    533          wx.EndBusyCursor()
    534          return True
    535
    536  #------------------------------------------------------------
    537 -def select_narrative(parent=None, soap_cats=None, msg=None):
    538
    539          pat = gmPerson.gmCurrentPatient()
    540          emr = pat.emr
    541
    542          if parent is None:
    543                  parent = wx.GetApp().GetTopWindow()
    544
    545          if soap_cats is None:
    546                  soap_cats = 'soapu'
    547          soap_cats = list(soap_cats)
    548          i18n_soap_cats = [ gmSoapDefs.soap_cat2l10n[cat].upper() for cat in soap_cats ]
    549
    550          if msg is None:
    551                  msg = _('Pick the [%s] narrative you want to use.') % '/'.join(i18n_soap_cats)
    552
    553          #-----------------------------------------------
    554          def get_tooltip(soap):
    555                  return soap.format(fancy = True, width = 60)
    556          #-----------------------------------------------
    557          def refresh(lctrl):
    558                  lctrl.secondary_sort_column = 0
    559                  soap = emr.get_clin_narrative(soap_cats = soap_cats)
    560                  lctrl.set_string_items ([ [
    561                          gmDateTime.pydt_strftime(s['date'], '%Y %m %d'),
    562                          s['modified_by'],
    563                          gmSoapDefs.soap_cat2l10n[s['soap_cat']],
    564                          s['narrative'],
    565                          s['episode'],
    566                          s['health_issue']
    567                  ] for s in soap ])
    568                  lctrl.set_data(soap)
    569          #-----------------------------------------------
    570          return gmListWidgets.get_choices_from_list (
    571                  parent = parent,
    572                  msg = msg,
    573                  caption = _('Picking [%s] narrative') % ('/'.join(i18n_soap_cats)),
    574                  columns = [_('When'), _('Who'), _('Type'), _('Entry'), _('Episode'), _('Issue')],
    575                  single_selection = False,
    576                  can_return_empty = False,
    577                  refresh_callback = refresh,
    578                  list_tooltip_callback = get_tooltip
    579          )
    580
    581  #------------------------------------------------------------
    582 -def select_narrative_by_issue(parent=None, soap_cats=None):
    583
    584          pat = gmPerson.gmCurrentPatient()
    585          emr = pat.emr
    586
    587          # not useful if you think about it:
    588  #       issues = [ i for i in emr.health_issues ]
    589  #       if len(issues) == 0:
    590  #               gmDispatcher.send(signal = 'statustext', msg = _('No progress notes found.'))
    591  #               return []
    592
    593          if parent is None:
    594                  parent = wx.GetApp().GetTopWindow()
    595
    596          if soap_cats is None:
    597                  soap_cats = 'soapu'
    598          soap_cats = list(soap_cats)
    599          i18n_soap_cats = [ gmSoapDefs.soap_cat2l10n[cat].upper() for cat in soap_cats ]
    600
    601          selected_soap = {}
    602          #selected_narrative_pks = []
    603
    604          #-----------------------------------------------
    605          def get_soap_tooltip(soap):
    606                  return soap.format(fancy = True, width = 60)
    607          #-----------------------------------------------
    608          def pick_soap_from_issue(issue):
    609
    610                  if issue is None:
    611                          return False
    612
    613                  narr_for_issue = emr.get_clin_narrative(issues = [issue['pk_health_issue']], soap_cats = soap_cats)
    614
    615                  if len(narr_for_issue) == 0:
    616                          gmDispatcher.send(signal = 'statustext', msg = _('No narrative available for this health issue.'))
    617                          return True
    618
    619                  selected_narr = gmListWidgets.get_choices_from_list (
    620                          parent = parent,
    621                          msg = _('Pick the [%s] narrative you want to include in the report.') % '/'.join(i18n_soap_cats),
    622                          caption = _('Picking [%s] from %s%s%s') % (
    623                                  '/'.join(i18n_soap_cats),
    624                                  gmTools.u_left_double_angle_quote,
    625                                  issue['description'],
    626                                  gmTools.u_right_double_angle_quote
    627                          ),
    628                          columns = [_('When'), _('Who'), _('Type'), _('Entry')],
    629                          choices = [ [
    630                                  gmDateTime.pydt_strftime(narr['date'], '%Y %b %d  %H:%M', accuracy = gmDateTime.acc_minutes),
    631                                  narr['modified_by'],
    632                                  gmSoapDefs.soap_cat2l10n[narr['soap_cat']],
    633                                  narr['narrative'].replace('\n', '//').replace('\r', '//')
    634                          ] for narr in narr_for_issue ],
    635                          data = narr_for_issue,
    636                          #selections=None,
    637                          #edit_callback=None,
    638                          single_selection = False,
    639                          can_return_empty = False,
    640                          list_tooltip_callback = get_soap_tooltip
    641                  )
    642
    643                  if selected_narr is None:
    644                          return True
    645
    646                  for narr in selected_narr:
    647                          selected_soap[narr['pk_narrative']] = narr
    648
    649                  return True
    650          #-----------------------------------------------
    651          def edit_issue(issue):
    652                  return gmEMRStructWidgets.edit_health_issue(parent = parent, issue = issue)
    653          #-----------------------------------------------
    654          def refresh_issues(lctrl):
    655                  #issues = [ i for i in emr.health_issues ]
    656                  issues = emr.health_issues
    657                  lctrl.set_string_items ([ [
    658                                  gmTools.bool2subst(i['is_confidential'], _('!! CONFIDENTIAL !!'), ''),
    659                                  i['description'],
    660                                  gmTools.bool2subst(i['is_active'], _('active'), _('inactive'))
    661                          ] for i in issues
    662                  ])
    663                  lctrl.set_data(issues)
    664          #-----------------------------------------------
    665          def get_issue_tooltip(issue):
    666                  return issue.format (
    667                          patient = pat,
    668                          with_encounters = False,
    669                          with_medications = False,
    670                          with_hospital_stays = False,
    671                          with_procedures = False,
    672                          with_family_history = False,
    673                          with_documents = False,
    674                          with_tests = False,
    675                          with_vaccinations = False
    676                  )
    677          #-----------------------------------------------
    678          #selected_episode_pks = []
    679
    680          issues_picked_from = gmListWidgets.get_choices_from_list (
    681                  parent = parent,
    682                  msg = _('\n Select the issue you want to report on.'),
    683                  caption = _('Picking [%s] from health issues') % '/'.join(i18n_soap_cats),
    684                  columns = [_('Privacy'), _('Issue'), _('Status')],
    685                  edit_callback = edit_issue,
    686                  refresh_callback = refresh_issues,
    687                  single_selection = True,
    688                  can_return_empty = True,
    689                  ignore_OK_button = False,
    690                  left_extra_button = (
    691                          _('&Pick notes'),
    692                          _('Pick [%s] entries from selected health issue') % '/'.join(i18n_soap_cats),
    693                          pick_soap_from_issue
    694                  ),
    695                  list_tooltip_callback = get_issue_tooltip
    696          )
    697
    698          if issues_picked_from is None:
    699                  return []
    700
    701          return selected_soap.values()
    702
    703  #       selection_idxs = []
    704  #       for idx in range(len(all_epis)):
    705  #               if all_epis[idx]['pk_episode'] in selected_episode_pks:
    706  #                       selection_idxs.append(idx)
    707  #       if len(selection_idxs) != 0:
    708  #               dlg.set_selections(selections = selection_idxs)
    709
    710  #------------------------------------------------------------
    711 -def select_narrative_by_episode(parent=None, soap_cats=None):
    712
    713          pat = gmPerson.gmCurrentPatient()
    714          emr = pat.emr
    715
    716          all_epis = [ epi for epi in emr.get_episodes(order_by = 'description') if epi.has_narrative ]
    717          if len(all_epis) == 0:
    718                  gmDispatcher.send(signal = 'statustext', msg = _('No episodes with progress notes found.'))
    719                  return []
    720
    721          if parent is None:
    722                  parent = wx.GetApp().GetTopWindow()
    723
    724          if soap_cats is None:
    725                  soap_cats = 'soapu'
    726          soap_cats = list(soap_cats)
    727          i18n_soap_cats = [ gmSoapDefs.soap_cat2l10n[cat].upper() for cat in soap_cats ]
    728
    729          selected_soap = {}
    730          #selected_narrative_pks = []
    731
    732          #-----------------------------------------------
    733          def get_soap_tooltip(soap):
    734                  return soap.format(fancy = True, width = 60)
    735          #-----------------------------------------------
    736          def pick_soap_from_episode(episode):
    737
    738                  if episode is None:
    739                          return False
    740
    741                  narr_for_epi = emr.get_clin_narrative(episodes = [episode['pk_episode']], soap_cats = soap_cats)
    742
    743                  if len(narr_for_epi) == 0:
    744                          gmDispatcher.send(signal = 'statustext', msg = _('No narrative available for selected episode.'))
    745                          return True
    746
    747                  selected_narr = gmListWidgets.get_choices_from_list (
    748                          parent = parent,
    749                          msg = _('Pick the [%s] narrative you want to include in the report.') % '/'.join(i18n_soap_cats),
    750                          caption = _('Picking [%s] from %s%s%s') % (
    751                                  '/'.join(i18n_soap_cats),
    752                                  gmTools.u_left_double_angle_quote,
    753                                  episode['description'],
    754                                  gmTools.u_right_double_angle_quote
    755                          ),
    756                          columns = [_('When'), _('Who'), _('Type'), _('Entry')],
    757                          choices = [ [
    758                                  gmDateTime.pydt_strftime(narr['date'], '%Y %b %d  %H:%M', accuracy = gmDateTime.acc_minutes),
    759                                  narr['modified_by'],
    760                                  gmSoapDefs.soap_cat2l10n[narr['soap_cat']],
    761                                  narr['narrative'].replace('\n', '//').replace('\r', '//')
    762                          ] for narr in narr_for_epi ],
    763                          data = narr_for_epi,
    764                          #selections=None,
    765                          #edit_callback=None,
    766                          single_selection = False,
    767                          can_return_empty = False,
    768                          list_tooltip_callback = get_soap_tooltip
    769                  )
    770
    771                  if selected_narr is None:
    772                          return True
    773
    774                  for narr in selected_narr:
    775                          selected_soap[narr['pk_narrative']] = narr
    776
    777                  return True
    778
    779  #               selection_idxs = []
    780  #               for idx in range(len(narr_for_epi)):
    781  #                       if narr_for_epi[idx]['pk_narrative'] in selected_narrative_pks:
    782  #                               selection_idxs.append(idx)
    783  #               if len(selection_idxs) != 0:
    784  #                       dlg.set_selections(selections = selection_idxs)
    785
    786  #               selected_narrative_pks = [ i['pk_narrative'] for i in selected_narr ]
    787  #               for narr in selected_narr:
    788  #                       selected_soap[narr['pk_narrative']] = narr
    789  #
    790  #               print "before returning from picking soap"
    791  #
    792  #               return True
    793  #       #-----------------------------------------------
    794          def edit_episode(episode):
    795                  return gmEMRStructWidgets.edit_episode(parent = parent, episode = episode)
    796          #-----------------------------------------------
    797          def refresh_episodes(lctrl):
    798                  all_epis = [ epi for epi in emr.get_episodes(order_by = 'description') if epi.has_narrative ]
    799                  lctrl.set_string_items ([ [
    800                                  '%s%s' % (e['description'], gmTools.coalesce(e['health_issue'], '', ' (%s)')),
    801                                  gmTools.bool2subst(e['episode_open'], _('open'), _('closed'))
    802                          ] for e in all_epis
    803                  ])
    804                  lctrl.set_data(all_epis)
    805          #-----------------------------------------------
    806          def get_episode_tooltip(episode):
    807                  return episode.format (
    808                          patient = pat,
    809                          with_encounters = False,
    810                          with_documents = False,
    811                          with_hospital_stays = False,
    812                          with_procedures = False,
    813                          with_family_history = False,
    814                          with_tests = False,
    815                          with_vaccinations = False
    816                  )
    817          #-----------------------------------------------
    818          #selected_episode_pks = []
    819
    820          epis_picked_from = gmListWidgets.get_choices_from_list (
    821                  parent = parent,
    822                  msg = _('\n Select the episode you want to report on.'),
    823                  caption = _('Picking [%s] from episodes') % '/'.join(i18n_soap_cats),
    824                  columns = [_('Episode'), _('Status')],
    825                  edit_callback = edit_episode,
    826                  refresh_callback = refresh_episodes,
    827                  single_selection = True,
    828                  can_return_empty = True,
    829                  ignore_OK_button = False,
    830                  left_extra_button = (
    831                          _('&Pick notes'),
    832                          _('Pick [%s] entries from selected episode') % '/'.join(i18n_soap_cats),
    833                          pick_soap_from_episode
    834                  ),
    835                  list_tooltip_callback = get_episode_tooltip
    836          )
    837
    838          if epis_picked_from is None:
    839                  return []
    840
    841          return selected_soap.values()
    842
    843  #       selection_idxs = []
    844  #       for idx in range(len(all_epis)):
    845  #               if all_epis[idx]['pk_episode'] in selected_episode_pks:
    846  #                       selection_idxs.append(idx)
    847  #       if len(selection_idxs) != 0:
    848  #               dlg.set_selections(selections = selection_idxs)
    849
    850  #------------------------------------------------------------
    851 -def select_narrative_from_episodes(parent=None, soap_cats=None):
    852          """soap_cats needs to be a list"""
    853
    854          pat = gmPerson.gmCurrentPatient()
    855          emr = pat.emr
    856
    857          if parent is None:
    858                  parent = wx.GetApp().GetTopWindow()
    859
    860          selected_soap = {}
    861          selected_issue_pks = []
    862          selected_episode_pks = []
    863          selected_narrative_pks = []
    864
    865          while 1:
    866                  # 1) select health issues to select episodes from
    867                  all_issues = emr.get_health_issues()
    868                  all_issues.insert(0, gmEMRStructItems.get_dummy_health_issue())
    869                  dlg = gmEMRStructWidgets.cIssueListSelectorDlg (
    870                          parent = parent,
    871                          id = -1,
    872                          issues = all_issues,
    873                          msg = _('\n In the list below mark the health issues you want to report on.\n')
    874                  )
    875                  selection_idxs = []
    876                  for idx in range(len(all_issues)):
    877                          if all_issues[idx]['pk_health_issue'] in selected_issue_pks:
    878                                  selection_idxs.append(idx)
    879                  if len(selection_idxs) != 0:
    880                          dlg.set_selections(selections = selection_idxs)
    881                  btn_pressed = dlg.ShowModal()
    882                  selected_issues = dlg.get_selected_item_data()
    883                  dlg.DestroyLater()
    884
    885                  if btn_pressed == wx.ID_CANCEL:
    886                          return selected_soap.values()
    887
    888                  selected_issue_pks = [ i['pk_health_issue'] for i in selected_issues ]
    889
    890                  while 1:
    891                          # 2) select episodes to select items from
    892                          all_epis = emr.get_episodes(issues = selected_issue_pks)
    893
    894                          if len(all_epis) == 0:
    895                                  gmDispatcher.send(signal = 'statustext', msg = _('No episodes recorded for the health issues selected.'))
    896                                  break
    897
    898                          dlg = gmEMRStructWidgets.cEpisodeListSelectorDlg (
    899                                  parent = parent,
    900                                  id = -1,
    901                                  episodes = all_epis,
    902                                  msg = _(
    903                                          '\n These are the episodes known for the health issues just selected.\n\n'
    904                                          ' Now, mark the the episodes you want to report on.\n'
    905                                  )
    906                          )
    907                          selection_idxs = []
    908                          for idx in range(len(all_epis)):
    909                                  if all_epis[idx]['pk_episode'] in selected_episode_pks:
    910                                          selection_idxs.append(idx)
    911                          if len(selection_idxs) != 0:
    912                                  dlg.set_selections(selections = selection_idxs)
    913                          btn_pressed = dlg.ShowModal()
    914                          selected_epis = dlg.get_selected_item_data()
    915                          dlg.DestroyLater()
    916
    917                          if btn_pressed == wx.ID_CANCEL:
    918                                  break
    919
    920                          selected_episode_pks = [ i['pk_episode'] for i in selected_epis ]
    921
    922                          # 3) select narrative corresponding to the above constraints
    923                          all_narr = emr.get_clin_narrative(episodes = selected_episode_pks, soap_cats = soap_cats)
    924
    925                          if len(all_narr) == 0:
    926                                  gmDispatcher.send(signal = 'statustext', msg = _('No narrative available for selected episodes.'))
    927                                  continue
    928
    929                          dlg = cNarrativeListSelectorDlg (
    930                                  parent = parent,
    931                                  id = -1,
    932                                  narrative = all_narr,
    933                                  msg = _(
    934                                          '\n This is the narrative (type %s) for the chosen episodes.\n\n'
    935                                          ' Now, mark the entries you want to include in your report.\n'
    936                                  ) % '/'.join([ gmSoapDefs.soap_cat2l10n[cat] for cat in gmTools.coalesce(soap_cats, list('soapu')) ])
    937                          )
    938                          selection_idxs = []
    939                          for idx in range(len(all_narr)):
    940                                  if all_narr[idx]['pk_narrative'] in selected_narrative_pks:
    941                                          selection_idxs.append(idx)
    942                          if len(selection_idxs) != 0:
    943                                  dlg.set_selections(selections = selection_idxs)
    944                          btn_pressed = dlg.ShowModal()
    945                          selected_narr = dlg.get_selected_item_data()
    946                          dlg.DestroyLater()
    947
    948                          if btn_pressed == wx.ID_CANCEL:
    949                                  continue
    950
    951                          selected_narrative_pks = [ i['pk_narrative'] for i in selected_narr ]
    952                          for narr in selected_narr:
    953                                  selected_soap[narr['pk_narrative']] = narr
    954
    955  #============================================================
    956  # main
    957  #------------------------------------------------------------
    958  if __name__ == '__main__':
    959
    960          if len(sys.argv) < 2:
    961                  sys.exit()
    962
    963          if sys.argv[1] != 'test':
    964                  sys.exit()
    965
    966          from Gnumed.business import gmPersonSearch
    967
    968          gmI18N.activate_locale()
    969          gmI18N.install_domain(domain = 'gnumed')
    970
    971          #----------------------------------------
    972 -        def test_select_narrative_from_episodes():
    973                  pat = gmPersonSearch.ask_for_patient()
    974                  set_active_patient(patient = pat)
    975                  app = wx.PyWidgetTester(size = (200, 200))
    976                  sels = select_narrative_from_episodes_new()
    977                  print("selected:")
    978                  for sel in sels:
    979                          print(sel)
    980          #----------------------------------------
    981 -        def test_select_narrative():
    982                  pat = gmPersonSearch.ask_for_patient()
    983                  set_active_patient(patient = pat)
    984                  app = wx.PyWidgetTester(size = (200, 200))
    985                  sels = select_narrative(parent=None, soap_cats = None)
    986                  print("selected:")
    987                  for sel in sels:
    988                          print(sel)
    989          #----------------------------------------
    990          #test_select_narrative_from_episodes()
    991          test_select_narrative()
    992