Beispiel #1
0
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
Beispiel #2
0
    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()
Beispiel #3
0
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
Beispiel #4
0
	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()
Beispiel #5
0
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
Beispiel #6
0
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)
Beispiel #7
0
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
Beispiel #8
0
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
Beispiel #9
0
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
Beispiel #10
0
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
Beispiel #11
0
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