def configure_boolean_option(parent=None, question=None, option=None, button_tooltips=None): if parent is None: parent = wx.GetApp().GetTopWindow() tooltips = [ _('Set "%s" to <True>.') % option, _('Set "%s" to <False>.') % option, _('Abort the dialog and do not change the current setting.') ] if button_tooltips is not None: for idx in range(len(button_tooltips)): tooltips[idx] = button_tooltips[idx] dlg = gmGuiHelpers.c3ButtonQuestionDlg(parent, -1, caption=_('Configuration'), question=question, button_defs=[{ 'label': _('Yes'), 'tooltip': tooltips[0] }, { 'label': _('No'), 'tooltip': tooltips[1] }, { 'label': _('Cancel'), 'tooltip': tooltips[2], 'default': True }]) decision = dlg.ShowModal() if decision == wx.ID_YES: gmCfgDB.set( workplace=gmPraxis.gmCurrentPraxisBranch().active_workplace, option=option, value=True) elif decision == wx.ID_NO: gmCfgDB.set( workplace=gmPraxis.gmCurrentPraxisBranch().active_workplace, option=option, value=False) return
def save_unsaved_soap(self): save_all = False dlg = None for page_idx in range(self.GetPageCount()): page = self.GetPage(page_idx) if page.editor_empty(): continue if dlg is None: dlg = gmGuiHelpers.c3ButtonQuestionDlg( self, -1, caption=_('Unsaved progress note'), question=_('This progress note has not been saved yet.\n' '\n' 'Do you want to save it or discard it ?\n\n'), button_defs=[{ 'label': _('&Save'), 'tooltip': _('Save this progress note'), 'default': True }, { 'label': _('&Discard'), 'tooltip': _('Discard this progress note'), 'default': False }, { 'label': _('Save &all'), 'tooltip': _('Save all remaining unsaved progress notes'), 'default': False }]) if not save_all: self.ChangeSelection(page_idx) decision = dlg.ShowModal() if decision == wx.ID_NO: _log.info( 'user requested discarding of unsaved progress note') continue if decision == wx.ID_CANCEL: save_all = True page.save() if dlg is not None: dlg.Destroy()
def configure_boolean_option(parent=None, question=None, option=None, button_tooltips=None): if parent is None: parent = wx.GetApp().GetTopWindow() tooltips = [ _('Set "%s" to <True>.') % option, _('Set "%s" to <False>.') % option, _('Abort the dialog and do not change the current setting.') ] if button_tooltips is not None: for idx in range(len(button_tooltips)): tooltips[idx] = button_tooltips[idx] dlg = gmGuiHelpers.c3ButtonQuestionDlg ( parent, -1, caption = _('Configuration'), question = question, button_defs = [ {'label': _('Yes'), 'tooltip': tooltips[0]}, {'label': _('No'), 'tooltip': tooltips[1]}, {'label': _('Cancel'), 'tooltip': tooltips[2], 'default': True} ] ) decision = dlg.ShowModal() dbcfg = gmCfg.cCfgSQL() if decision == wx.ID_YES: dbcfg.set ( workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace, option = option, value = True ) elif decision == wx.ID_NO: dbcfg.set ( workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace, option = option, value = False ) return
def save_unsaved_soap(self): save_all = False dlg = None for page_idx in range(self.GetPageCount()): page = self.GetPage(page_idx) if page.editor_empty(): continue if dlg is None: dlg = gmGuiHelpers.c3ButtonQuestionDlg ( self, -1, caption = _('Unsaved progress note'), question = _( 'This progress note has not been saved yet.\n' '\n' 'Do you want to save it or discard it ?\n\n' ), button_defs = [ {'label': _('&Save'), 'tooltip': _('Save this progress note'), 'default': True}, {'label': _('&Discard'), 'tooltip': _('Discard this progress note'), 'default': False}, {'label': _('Save &all'), 'tooltip': _('Save all remaining unsaved progress notes'), 'default': False} ] ) if not save_all: self.ChangeSelection(page_idx) decision = dlg.ShowModal() if decision == wx.ID_NO: _log.info('user requested discarding of unsaved progress note') continue if decision == wx.ID_CANCEL: save_all = True page.save() if dlg is not None: dlg.DestroyLater()
def import_amts_bmp(parent=None, bmp_filename: str = None) -> typing.Union[bool, None]: if bmp_filename is None: dlg = wx.FileDialog(parent=parent, message=_('Choose an AMTS BMP medication plan.'), defaultDir=os.path.expanduser( os.path.join('~', 'gnumed')), defaultFile='', wildcard="%s (*.xml)|*.xml|%s (*)|*" % (_('BMP files'), _('all files')), style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) result = dlg.ShowModal() if result == wx.ID_CANCEL: return None bmp_filename = dlg.GetPath() dlg.DestroyLater() dlg_title = _('Importing AMTS BMP Medikationsplan') bmp = gmAMTS_BMP.cAmtsBmpFile(bmp_filename) if not bmp.valid(): gmGuiHelpers.gm_show_error( title=dlg_title, error=_('The file\n' '\n' ' [%s]\n' '\n' 'does not seem to be a Medikationsplan.') % bmp_filename) return False dto = bmp.patient_as_dto person = dto.unambiguous_identity if person is None: candidates = dto.candidate_identities if len(candidates) == 0: # no match found -> ask for creation or ask whether to import for the current patient curr_pat = gmPerson.gmCurrentPatient() if curr_pat.is_connected: gmGuiHelpers.c3ButtonQuestionDlg( parent=parent, caption=dlg_title, question=_('No matching patient found in GNUmed.\n' '\n' 'The patient in the Medikationsplan is:\n' '\n' ' %s\n' '\n' 'Do you want to create that patient ?') % dto.format(), button_defs=[]) else: gmGuiHelpers.gm_show_question( title=dlg_title, question=_('No matching patient found in GNUmed.\n' '\n' 'The patient in the Medikationsplan is:\n' '\n' ' %s\n' '\n' 'Do you want to create that patient ?') % dto.format()) elif len(candidates) == 1: # one match found -> ask whether to import pass else: # several found -> ask which to use pass # msg = _('None or several matching patients found.') # gmGuiHelpers.gm_show_info ( # title = _('Importing AMTS BMP Medikationsplan'), # info = msg + '\n\n' + bmp.format(eol = '\n') # ) else: gmGuiHelpers.gm_show_info( title=_('Importing AMTS BMP Medikationsplan'), info=bmp.format(eol='\n')) return True
def select_visual_progress_note_template(parent=None): if parent is None: parent = wx.GetApp().GetTopWindow() dlg = gmGuiHelpers.c3ButtonQuestionDlg( parent, -1, caption=_('Visual progress note source'), question=_( 'From which source do you want to pick the image template ?'), button_defs=[{ 'label': _('Database'), 'tooltip': _('List of templates in the database.'), 'default': True }, { 'label': _('File'), 'tooltip': _('Files in the filesystem.'), 'default': False }, { 'label': _('Device'), 'tooltip': _('Image capture devices (scanners, cameras, etc)'), 'default': False }]) result = dlg.ShowModal() dlg.Destroy() # 1) select from template if result == wx.ID_YES: _log.debug('visual progress note template from: database template') from Gnumed.wxpython import gmFormWidgets template = gmFormWidgets.manage_form_templates( parent=parent, template_types=[gmDocuments.DOCUMENT_TYPE_VISUAL_PROGRESS_NOTE], active_only=True) if template is None: return (None, None) filename = template.export_to_file() if filename is None: gmDispatcher.send( signal=u'statustext', msg=_('Cannot export visual progress note template for [%s].') % template['name_long']) return (None, None) return (filename, True) # 2) select from disk file if result == wx.ID_NO: _log.debug('visual progress note template from: disk file') fname = select_file_as_visual_progress_note_template(parent=parent) if fname is None: return (None, None) # create a copy of the picked file -- don't modify the original ext = os.path.splitext(fname)[1] tmp_name = gmTools.get_unique_filename(suffix=ext) _log.debug('visual progress note from file: [%s] -> [%s]', fname, tmp_name) shutil.copy2(fname, tmp_name) return (tmp_name, False) # 3) acquire from capture device if result == wx.ID_CANCEL: _log.debug('visual progress note template from: image capture device') fnames = gmDocumentWidgets.acquire_images_from_capture_device( device=None, calling_window=parent) if fnames is None: return (None, None) if len(fnames) == 0: return (None, None) return (fnames[0], False) _log.debug('no visual progress note template source selected') return (None, None)
def edit_narrative(parent=None, narrative=None, single_entry=False): assert isinstance(narrative, gmClinNarrative.cNarrative), '<narrative> must be of type <cNarrative>' title = _('Editing progress note') if narrative['modified_by_raw'] == gmStaff.gmCurrentProvider()['db_user']: msg = _('Your original progress note:') else: msg = _('Original progress note by %s [%s]\n(will be notified of changes):') % ( narrative['modified_by'], narrative['modified_by_raw'] ) if parent is None: parent = wx.GetApp().GetTopWindow() dlg = gmGuiHelpers.cMultilineTextEntryDlg ( parent, -1, title = title, msg = msg, data = narrative.format(left_margin = ' ', fancy = True), text = narrative['narrative'].strip() ) decision = dlg.ShowModal() val = dlg.value.strip() dlg.DestroyLater() if decision != wx.ID_SAVE: return False if val == '': return False if val == narrative['narrative'].strip(): return False if narrative['modified_by_raw'] == gmStaff.gmCurrentProvider()['db_user']: narrative['narrative'] = val narrative.save_payload() return True q = _( 'Original progress note written by someone else:\n' '\n' ' %s (%s)\n' '\n' 'Upon saving changes that person will be notified.\n' '\n' 'Consider saving as a new progress note instead.' ) % ( narrative['modified_by_raw'], narrative['modified_by'] ) buttons = [ {'label': _('Save changes'), 'default': True}, {'label': _('Save new note')}, {'label': _('Discard')} ] dlg = gmGuiHelpers.c3ButtonQuestionDlg(parent = parent, caption = title, question = q, button_defs = buttons) decision = dlg.ShowModal() dlg.DestroyLater() if decision not in [wx.ID_YES, wx.ID_NO]: return False if decision == wx.ID_NO: # create new progress note within the same context as the original one gmClinNarrative.create_narrative_item ( narrative = val, soap_cat = narrative['soap_cat'], episode_id = narrative['pk_episode'], encounter_id = narrative['pk_encounter'] ) return True # notify original provider msg = gmProviderInbox.create_inbox_message ( staff = narrative.staff_id, message_type = _('Change notification'), message_category = 'administrative', subject = _('A progress note of yours has been edited.'), patient = narrative['pk_patient'] ) msg['data'] = _( 'Original (by [%s]):\n' '%s\n' '\n' 'Edited (by [%s]):\n' '%s' ) % ( narrative['modified_by'], narrative['narrative'].strip(), gmStaff.gmCurrentProvider()['short_alias'], val ) msg.save() # notify /me about the staff member notification #gmProviderInbox.create_inbox_message ( # staff = curr_prov['pk_staff'], # message_type = _('Privacy notice'), # message_category = 'administrative', # subject = _('%s: Staff member %s has been notified of your chart access.') % (prov, pat) #) # save narrative change narrative['narrative'] = val narrative.save() return True
def move_episode_to_issue(episode=None, target_issue=None, save_to_backend=False): """Prepare changing health issue for an episode. Checks for two-open-episodes conflict. When this function succeeds, the pk_health_issue has been set on the episode instance and the episode should - for all practical purposes - be ready for save_payload(). """ # episode is closed: should always work if not episode['episode_open']: episode['pk_health_issue'] = target_issue['pk_health_issue'] if save_to_backend: episode.save_payload() return True # un-associate: should always work, too if target_issue is None: episode['pk_health_issue'] = None if save_to_backend: episode.save_payload() return True # try closing possibly expired episode on target issue if any db_cfg = gmCfg.cCfgSQL() epi_ttl = int(db_cfg.get2 ( option = 'episode.ttl', workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace, bias = 'user', default = 60 # 2 months )) if target_issue.close_expired_episode(ttl=epi_ttl) is True: gmDispatcher.send(signal='statustext', msg=_('Closed episodes older than %s days on health issue [%s]') % (epi_ttl, target_issue['description'])) existing_epi = target_issue.get_open_episode() # no more open episode on target issue: should work now if existing_epi is None: episode['pk_health_issue'] = target_issue['pk_health_issue'] if save_to_backend: episode.save_payload() return True # don't conflict on SELF ;-) if existing_epi['pk_episode'] == episode['pk_episode']: episode['pk_health_issue'] = target_issue['pk_health_issue'] if save_to_backend: episode.save_payload() return True # we got two open episodes at once, ask user move_range = (episode.best_guess_clinical_start_date, episode.best_guess_clinical_end_date) if move_range[1] is None: move_range_end = '?' else: move_range_end = move_range[1].strftime('%m/%y') exist_range = (existing_epi.best_guess_clinical_start_date, existing_epi.best_guess_clinical_end_date) if exist_range[1] is None: exist_range_end = '?' else: exist_range_end = exist_range[1].strftime('%m/%y') question = _( 'You want to associate the running episode:\n\n' ' "%(new_epi_name)s" (%(new_epi_start)s - %(new_epi_end)s)\n\n' 'with the health issue:\n\n' ' "%(issue_name)s"\n\n' 'There already is another episode running\n' 'for this health issue:\n\n' ' "%(old_epi_name)s" (%(old_epi_start)s - %(old_epi_end)s)\n\n' 'However, there can only be one running\n' 'episode per health issue.\n\n' 'Which episode do you want to close ?' ) % { 'new_epi_name': episode['description'], 'new_epi_start': move_range[0].strftime('%m/%y'), 'new_epi_end': move_range_end, 'issue_name': target_issue['description'], 'old_epi_name': existing_epi['description'], 'old_epi_start': exist_range[0].strftime('%m/%y'), 'old_epi_end': exist_range_end } dlg = gmGuiHelpers.c3ButtonQuestionDlg ( parent = None, id = -1, caption = _('Resolving two-running-episodes conflict'), question = question, button_defs = [ {'label': _('old episode'), 'default': True, 'tooltip': _('close existing episode "%s"') % existing_epi['description']}, {'label': _('new episode'), 'default': False, 'tooltip': _('close moving (new) episode "%s"') % episode['description']} ] ) decision = dlg.ShowModal() if decision == wx.ID_CANCEL: # button 3: move cancelled by user return False elif decision == wx.ID_YES: # button 1: close old episode existing_epi['episode_open'] = False existing_epi.save_payload() elif decision == wx.ID_NO: # button 2: close new episode episode['episode_open'] = False else: raise ValueError('invalid result from c3ButtonQuestionDlg: [%s]' % decision) episode['pk_health_issue'] = target_issue['pk_health_issue'] if save_to_backend: episode.save_payload() return True
def promote_episode_to_issue(parent=None, episode=None, emr=None): created_new_issue = False try: issue = gmEMRStructItems.cHealthIssue(name = episode['description'], patient = episode['pk_patient']) except gmExceptions.NoSuchBusinessObjectError: issue = None if issue is None: issue = emr.add_health_issue(issue_name = episode['description']) created_new_issue = True else: # issue exists already, so ask user dlg = gmGuiHelpers.c3ButtonQuestionDlg ( parent, -1, caption = _('Promoting episode to health issue'), question = _( 'There already is a health issue\n' '\n' ' %s\n' '\n' 'What do you want to do ?' ) % issue['description'], button_defs = [ {'label': _('Use existing'), 'tooltip': _('Move episode into existing health issue'), 'default': False}, {'label': _('Create new'), 'tooltip': _('Create a new health issue with another name'), 'default': True} ] ) use_existing = dlg.ShowModal() dlg.DestroyLater() if use_existing == wx.ID_CANCEL: return # user wants to create new issue with alternate name if use_existing == wx.ID_NO: # loop until name modified but non-empty or cancelled issue_name = episode['description'] while issue_name == episode['description']: dlg = wx.TextEntryDialog ( parent, _('Enter a short descriptive name for the new health issue:'), caption = _('Creating a new health issue ...'), value = issue_name, style = wx.OK | wx.CANCEL | wx.CENTRE ) decision = dlg.ShowModal() if decision != wx.ID_OK: dlg.DestroyLater() return issue_name = dlg.GetValue().strip() dlg.DestroyLater() if issue_name == '': issue_name = episode['description'] issue = emr.add_health_issue(issue_name = issue_name) created_new_issue = True # eventually move the episode to the issue if not move_episode_to_issue(episode = episode, target_issue = issue, save_to_backend = True): # user cancelled the move so delete just-created issue if created_new_issue: # shouldn't fail as it is completely new gmEMRStructItems.delete_health_issue(health_issue = issue) return return