Exemplo n.º 1
0
	def _save_as_update(self):

		self.data['description'] = self._PRW_description.GetValue().strip()
		self.data['summary'] = self._TCTRL_status.GetValue().strip()
		self.data['episode_open'] = not self._CHBOX_closed.IsChecked()
		self.data['diagnostic_certainty_classification'] = self._PRW_certainty.GetData()

		issue_name = self._PRW_issue.GetValue().strip()
		if len(issue_name) == 0:
			self.data['pk_health_issue'] = None
		else:
			self.data['pk_health_issue'] = self._PRW_issue.GetData(can_create = True)
			issue = gmEMRStructItems.cHealthIssue(aPK_obj = self.data['pk_health_issue'])

			if not move_episode_to_issue(episode = self.data, target_issue = issue, save_to_backend = False):
				gmDispatcher.send (
					signal = 'statustext',
					msg = _('Cannot attach episode [%s] to health issue [%s] because it already has a running episode.') % (
						self.data['description'],
						issue['description']
					)
				)
				return False

		self.data.save()
		self.data.generic_codes = [ c['data'] for c in self._PRW_codes.GetData() ]

		return True
Exemplo n.º 2
0
	def _save_as_new(self):

		pat = gmPerson.gmCurrentPatient()
		emr = pat.emr

		epi = emr.add_episode(episode_name = self._PRW_description.GetValue().strip())
		epi['summary'] = self._TCTRL_status.GetValue().strip()
		epi['episode_open'] = not self._CHBOX_closed.IsChecked()
		epi['diagnostic_certainty_classification'] = self._PRW_certainty.GetData()

		issue_name = self._PRW_issue.GetValue().strip()
		if len(issue_name) != 0:
			epi['pk_health_issue'] = self._PRW_issue.GetData(can_create = True)
			issue = gmEMRStructItems.cHealthIssue(aPK_obj = epi['pk_health_issue'])

			if not move_episode_to_issue(episode = epi, target_issue = issue, save_to_backend = False):
				gmDispatcher.send (
					signal = 'statustext',
					msg = _('Cannot attach episode [%s] to health issue [%s] because it already has a running episode.') % (
						epi['description'],
						issue['description']
					)
				)
				gmEMRStructItems.delete_episode(episode = epi)
				return False

		epi.save()

		epi.generic_codes = [ c['data'] for c in self._PRW_codes.GetData() ]

		self.data = epi
		return True
Exemplo n.º 3
0
	def _on_add_patient_button_pressed(self, evt):
		self.__id_most_recently_activated_patient = None
		curr_pat = gmPerson.gmCurrentPatient()
		if not curr_pat.connected:
			gmDispatcher.send(signal = 'statustext', msg = _('Cannot add waiting list entry: No patient selected.'), beep = True)
			return
		edit_waiting_list_entry(parent = self, patient = curr_pat)
Exemplo n.º 4
0
def _check_birthday(patient=None):

	if patient['dob'] is None:
		return

	dbcfg = gmCfg.cCfgSQL()
	dob_distance = dbcfg.get2 (
		option = 'patient_search.dob_warn_interval',
		workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace,
		bias = 'user',
		default = '1 week'
	)

	if not patient.dob_in_range(dob_distance, dob_distance):
		return

	now = gmDateTime.pydt_now_here()
	enc = gmI18N.get_encoding()
	msg = _('%(pat)s turns %(age)s on %(month)s %(day)s ! (today is %(month_now)s %(day_now)s)') % {
		'pat': patient.get_description_gender(),
		'age': patient.get_medical_age().strip('y'),
		'month': patient.get_formatted_dob(format = '%B'),
		'day': patient.get_formatted_dob(format = '%d'),
		'month_now': gmDateTime.pydt_strftime(now, '%B', gmDateTime.acc_months),
		'day_now': gmDateTime.pydt_strftime(now, '%d', gmDateTime.acc_days)
	}
	gmDispatcher.send(signal = 'statustext', msg = msg)
Exemplo n.º 5
0
	def _on_identity_item_activated(self, event):
		data = self._LCTRL_identity.get_selected_item_data(only_one = True)
		if data is None:
			gmDispatcher.send(signal = 'display_widget', name = 'gmNotebookedPatientEditionPlugin')

		# <ctrl> down ?
		if not wx.GetKeyState(wx.WXK_CONTROL):
			gmDispatcher.send(signal = 'display_widget', name = 'gmNotebookedPatientEditionPlugin')

		# <ctrl> down !
		if isinstance(data, gmPerson.cPersonName):
			ea = gmDemographicsWidgets.cPersonNameEAPnl(self, -1, name = data)
			dlg = gmEditArea.cGenericEditAreaDlg2(self, -1, edit_area = ea, single_entry = True)
			dlg.SetTitle(_('Cloning name'))
			dlg.ShowModal()
			return

		if isinstance(data, dict):
			key = list(data.keys())[0]
			val = data[key]
			if key == 'id':
				ea = gmDemographicsWidgets.cExternalIDEditAreaPnl(self, -1, external_id = val)
				ea.id_holder = gmPerson.gmCurrentPatient()
				dlg = gmEditArea.cGenericEditAreaDlg2(self, -1, edit_area = ea, single_entry = True)
				dlg.SetTitle(_('Editing external ID'))
				dlg.ShowModal()
				return
			if key == 'job':
				gmDemographicsWidgets.edit_occupation()
				return
Exemplo n.º 6
0
def check_for_updates():

	dbcfg = gmCfg.cCfgSQL()

	url = dbcfg.get2 (
		option = u'horstspace.update.url',
		workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace,
		bias = 'workplace',
		default = u'http://www.gnumed.de/downloads/gnumed-versions.txt'
	)

	consider_latest_branch = bool(dbcfg.get2 (
		option = u'horstspace.update.consider_latest_branch',
		workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace,
		bias = 'workplace',
		default = True
	))

	_cfg = gmCfg2.gmCfgData()

	found, msg = gmNetworkTools.check_for_update (
		url = url,
		current_branch = _cfg.get(option = 'client_branch'),
		current_version = _cfg.get(option = 'client_version'),
		consider_latest_branch = consider_latest_branch
	)

	if found is False:
		gmDispatcher.send(signal = 'statustext', msg = _('Your client (%s) is up to date.') % _cfg.get(option = 'client_version'))
		return

	gmGuiHelpers.gm_show_info (
		msg,
		_('Checking for client updates')
	)
Exemplo n.º 7
0
	def run(self, patient=None, debug=False):
		self.pdf_result = None

		cfg_file = self.__write_config_file(patient = patient)

		# FIXME: add user-configured path
		if not self.__detect_binary():
			return False

		args = (
			self.path_to_binary,
			'--file=%s' % cfg_file,
			'--show-cli-pane=%s' % gmTools.bool2subst(debug, 'true', 'false')
		)

		try:
			subprocess.check_call(args = args, close_fds = True)
		except (OSError, ValueError, subprocess.CalledProcessError):
			_log.exception('there was a problem executing [%s]', self.path_to_binary)
			gmDispatcher.send(signal = u'statustext', msg = _('Cannot run [arriba] !'), beep = True)
			return False

		try:
			open(self.pdf_result).close()
		except:
			_log.exception('error accessing [%s]', self.pdf_result)
			gmDispatcher.send(signal = u'statustext', msg = _('No [arriba] result found in [%s].') % self.pdf_result, beep = False)
			return False

		return True
Exemplo n.º 8
0
	def delete(enc=None):
		if enc is None:
			return False
		question = _(
			'Really delete encounter [%s] ?\n'
			'\n'
			'Once deletion succeeds it cannot be undone.\n'
			'\n'
			'Note that it will only succeed if there\n'
			'is no data attached to the encounter.'
		) % enc['pk_encounter']
		delete_it = gmGuiHelpers.gm_show_question (
			question = question,
			title = _('Deleting encounter'),
			cancel_button = False
		)
		if not delete_it:
			return False
		if gmEMRStructItems.delete_encounter(pk_encounter = enc['pk_encounter']):
			return True
		gmDispatcher.send (
			signal = u'statustext',
			msg = _('Cannot delete encounter [%s]. It is probably in use.') % enc['pk_encounter'],
			beep = True
		)
		return False
Exemplo n.º 9
0
	def contribute_translations(item=None):

		do_it = gmGuiHelpers.gm_show_question (
			aTitle = _('Contributing translations'),
			aMessage = _('Do you want to contribute your translations to the GNUmed project ?')
		)
		if not do_it:
			return False

		fname = gmTools.get_unique_filename(prefix = 'gm-db-translations-', suffix = '.sql')
		gmPG2.export_translations_from_database(filename = fname)

		msg = (
			'These are database string translations contributed by a GNUmed user.\n'
			'\n'
			'\tThe GNUmed "%s" Client'
		) % gmI18N.system_locale

		if not gmNetworkTools.compose_and_send_email (
			auth = {'user': gmNetworkTools.default_mail_sender, 'password': '******'},
			sender = 'GNUmed Client <*****@*****.**>',
			receiver = ['*****@*****.**'],
			subject = '<contribution>: database translation',
			message = msg,
			attachments = [[fname, 'text/plain', 'quoted-printable']]
		):
			gmDispatcher.send(signal = 'statustext', msg = _('Unable to send mail. Cannot contribute translations to GNUmed community.') % report, beep = True)
			return False

		gmDispatcher.send(signal = 'statustext', msg = _('Thank you for your contribution to the GNUmed community!'), beep = True)
		return True
Exemplo n.º 10
0
	def register(self):
		"""Register ourselves with the main notebook widget."""

		_log.info("set: [%s] class: [%s] name: [%s]" % (self._set, self.__class__.__name__, self.name()))

		# create widget
		nb = self.gb['horstspace.notebook']
		widget = self.GetWidget(nb)

		# add ourselves to the main notebook
		nb.AddPage(widget, self.name())

		# so notebook can find this widget
		self.gb['horstspace.notebook.%s' % self._set][self.__class__.__name__] = self
		self.gb['horstspace.notebook.pages'].append(self)

		# and put ourselves into the menu structure
		menu_info = self.MenuInfo()
		if menu_info is None:
			# register with direct access menu only
			gmDispatcher.send(signal = 'plugin_loaded', plugin_name = self.name(), class_name = self.__class__.__name__)
		else:
			name_of_menu, menu_item_name = menu_info
			gmDispatcher.send (
				signal = 'plugin_loaded',
				plugin_name = menu_item_name,
				class_name = self.__class__.__name__,
				menu_name = name_of_menu,
				menu_item_name = menu_item_name,
				# FIXME: this shouldn't be self.name() but rather self.menu_help_string()
				menu_help_string = self.name()
			)

		return True
Exemplo n.º 11
0
def load_person_from_vcard_file():

	wildcards = '|'.join ([
		'%s (*.vcf)|*.vcf' % _('vcf files'),
		'%s (*.VCF)|*.VCF' % _('VCF files'),
		'%s (*)|*' % _('all files'),
		'%s (*.*)|*.*' % _('all files (Windows)')
	])

	dlg = wx.FileDialog (
		parent = wx.GetApp().GetTopWindow(),
		message = _('Choose a vCard file:'),
		defaultDir = os.path.join(gmTools.gmPaths().home_dir, 'gnumed'),
		wildcard = wildcards,
		style = wx.FD_OPEN | wx.FD_FILE_MUST_EXIST
	)
	result = dlg.ShowModal()
	fname = dlg.GetPath()
	dlg.DestroyLater()
	if result == wx.ID_CANCEL:
		return

	from Gnumed.business import gmVCard
	dto = gmVCard.parse_vcard2dto(filename = fname)
	if dto is None:
		gmDispatcher.send(signal='statustext', msg=_('[%s] does not seem to contain a vCard.') % fname)
		return

	idents = dto.get_candidate_identities(can_create = True)
	if len(idents) == 1:
		ident = idents[0]
		if not set_active_patient(patient = ident):
			gmGuiHelpers.gm_show_info (_(
				'Cannot activate patient:\n\n'
				'%s %s (%s)\n'
				'%s'
				) % (
					dto.firstnames, dto.lastnames, dto.gender, gmDateTime.pydt_strftime(dto.dob, '%Y %b %d')
				),
				_('Activating external patient')
			)
		return

	dlg = cSelectPersonFromListDlg(wx.GetApp().GetTopWindow(), -1)
	dlg.set_persons(persons = idents)
	result = dlg.ShowModal()
	ident = dlg.get_selected_person()
	dlg.DestroyLater()
	if result == wx.ID_CANCEL:
		return
	if not set_active_patient(patient = ident):
		gmGuiHelpers.gm_show_info (_(
			'Cannot activate patient:\n\n'
			'%s %s (%s)\n'
			'%s'
			) % (
				dto.firstnames, dto.lastnames, dto.gender, gmDateTime.pydt_strftime(dto.dob, '%Y %b %d')
			),
			_('Activating external patient')
		)
Exemplo n.º 12
0
	def _on_allergies_dclicked(self, evt):
		if not self.curr_pat.connected:
			gmDispatcher.send('statustext', msg = _('Cannot activate Allergy Manager. No active patient.'))
			return
		dlg = gmAllergyWidgets.cAllergyManagerDlg(parent=self, id=-1)
		dlg.ShowModal()
		return
Exemplo n.º 13
0
	def _on_delete_problem_button_pressed(self, event):
		event.Skip()
		epi = self._LCTRL_problems.get_selected_item_data(only_one = True)
		if epi is None:
			return
		if not gmEMRStructItems.delete_episode(episode = epi):
			gmDispatcher.send(signal = 'statustext', msg = _('Cannot delete problem. There is still clinical data recorded for it.'))
Exemplo n.º 14
0
	def delete(item):
		delete_it = gmGuiHelpers.gm_show_question (
			aTitle = _('Deleting option'),
			aMessage = '%s\n\n%s %s (#%s) %s\n\n%s\n\n%s' % (
				tooltip(item),
				gmTools.u_box_horiz_single * 3,
				item['option'],
				item['pk_cfg_item'],
				gmTools.u_box_horiz_single * 3,
				_('Do you really want to delete this option ?'),
				_('(GNUmed will re-create options as needed.)')
			)
		)
		if not delete_it:
			return False

		from Gnumed.wxpython.gmAuthWidgets import get_dbowner_connection
		conn = get_dbowner_connection(procedure = _('Deleting option'))
		if conn is None:
			gmDispatcher.send(signal = 'statustext', msg = _('Cannot connect as database owner. Unable to delete option.'))
			return False

		cfg = gmCfg.cCfgSQL()
		cfg.delete(conn = conn, pk_option = item['pk_cfg_item'])
		return True
Exemplo n.º 15
0
	def _pre_exit_callback(self):
		"""The client is about to (be) shut down.

		Shutdown will not proceed before this returns.
		"""
		if self.__pat is None:
			return True

#		if self.__encounter_modified():
#			do_save_enc = gmGuiHelpers.gm_show_question (
#				aMessage = _(
#					'You have modified the details\n'
#					'of the current encounter.\n'
#					'\n'
#					'Do you want to save those changes ?'
#				),
#				aTitle = _('Starting new encounter')
#			)
#			if do_save_enc:
#				if not self.save_encounter():
#					gmDispatcher.send(signal = u'statustext', msg = _('Error saving current encounter.'), beep = True)

		saved = self._NB_soap_editors.save_all_editors (
			emr = self.__pat.emr,
			episode_name_candidates = [
				gmTools.none_if(self._TCTRL_aoe.GetValue().strip(), ''),
				gmTools.none_if(self._TCTRL_rfe.GetValue().strip(), '')
			]
		)
		if not saved:
			gmDispatcher.send(signal = 'statustext', msg = _('Cannot save all editors. Some were kept open.'), beep = True)
		return True
Exemplo n.º 16
0
	def _goto_measurements_review(self, pk_context=None, pk_patient=None):

		msg = _('Supposedly there are unreviewed results\n'
			'for patient [%s]. However, I cannot find\n'
			'that patient in the GNUmed database.'
		) % pk_patient

		wx.BeginBusyCursor()

		try:
			pat = gmPerson.cPerson(aPK_obj = pk_patient)
		except gmExceptions.ConstructorError:
			wx.EndBusyCursor()
			_log.exception('patient [%s] not found', pk_patient)
			gmGuiHelpers.gm_show_error(msg, _('handling provider inbox item'))
			return False

		success = set_active_patient(patient = pat)

		wx.EndBusyCursor()

		if not success:
			gmGuiHelpers.gm_show_error(msg, _('handling provider inbox item'))
			return False

		gmDispatcher.send(signal = 'display_widget', name = 'gmMeasurementsGridPlugin')
		return True
Exemplo n.º 17
0
	def _on_list_item_activated(self, evt):
		data = self.get_selected_item_data(only_one = True)
		pk_pat_col = self.__get_patient_pk_data_key(data = data)

		if pk_pat_col is None:
			gmDispatcher.send(signal = 'statustext', msg = _('List not known to be patient-related.'))
			return

		pat_data = data[pk_pat_col]
		try:
			pat_pk = int(pat_data)
			pat = gmPerson.cPerson(aPK_obj = pat_pk)
		except (ValueError, TypeError):
			searcher = gmPersonSearch.cPatientSearcher_SQL()
			idents = searcher.get_identities(pat_data)
			if len(idents) == 0:
				gmDispatcher.send(signal = 'statustext', msg = _('No matching patient found.'))
				return
			if len(idents) == 1:
				pat = idents[0]
			else:
				from Gnumed.wxpython import gmPatSearchWidgets
				dlg = gmPatSearchWidgets.cSelectPersonFromListDlg(parent=wx.GetTopLevelParent(self), id=-1)
				dlg.set_persons(persons=idents)
				result = dlg.ShowModal()
				if result == wx.ID_CANCEL:
					dlg.Destroy()
					return
				pat = dlg.get_selected_person()
				dlg.Destroy()

		from Gnumed.wxpython import gmPatSearchWidgets
		gmPatSearchWidgets.set_active_patient(patient = pat)
Exemplo n.º 18
0
def start_new_encounter(emr=None):
	emr.start_new_encounter()
	gmDispatcher.send(signal = 'statustext', msg = _('Started a new encounter for the active patient.'), beep = True)
	time.sleep(0.5)
	gmGuiHelpers.gm_show_info (
		_('\nA new encounter was started for the active patient.\n'),
		_('Start of new encounter')
	)
Exemplo n.º 19
0
def generate_form_from_template(parent=None, template_types=None, edit=None, template=None, excluded_template_types=None):
	"""If <edit> is None it will honor the template setting."""

	if parent is None:
		parent = wx.GetApp().GetTopWindow()

	# 1) get template to use
	if template is None:
		template = manage_form_templates (
			parent = parent,
			active_only = True,
			template_types = template_types,
			excluded_types = excluded_template_types
		)
		if template is None:
			gmDispatcher.send(signal = 'statustext', msg = _('No document template selected.'), beep = False)
			return None

	if template['engine'] == 'O':
		return print_doc_from_ooo_template(template = template)

	wx.BeginBusyCursor()

	# 2) process template
	try:
		form = template.instantiate()
	except KeyError:
		_log.exception('cannot instantiate document template [%s]', template)
		gmGuiHelpers.gm_show_error (
			aMessage = _('Invalid document template [%s - %s (%s)]') % (name, ver, template['engine']),
			aTitle = _('Generating document from template')
		)
		wx.EndBusyCursor()
		return None
	ph = gmMacro.gmPlaceholderHandler()
	#ph.debug = True
	form.substitute_placeholders(data_source = ph)
	if edit is None:
		if form.template['edit_after_substitution']:
			edit = True
		else:
			edit = False
	if edit:
		wx.EndBusyCursor()
		form.edit()
		wx.BeginBusyCursor()

	# 3) generate output
	pdf_name = form.generate_output()
	wx.EndBusyCursor()
	if pdf_name is not None:
		return form

	gmGuiHelpers.gm_show_error (
		aMessage = _('Error generating document printout.'),
		aTitle = _('Generating document printout')
	)
	return None
Exemplo n.º 20
0
	def _valid_for_save(self):

		has_errors = False

		if not self._DPRW_date.is_valid_timestamp():
			self._DPRW_date.display_as_valid(False)
			has_errors = True
		else:
			self._DPRW_date.display_as_valid(True)

		start = self._DPRW_date.GetData()
		end = self._DPRW_end.GetData()
		self._DPRW_end.display_as_valid(True)
		if end is not None:
			end = end.get_pydt()
			if start is not None:
				start = start.get_pydt()
				if end < start:
					has_errors = True
					self._DPRW_end.display_as_valid(False)
			if self._CHBOX_ongoing.IsChecked():
				now = gmDateTime.pydt_now_here()
				if end < now:
					has_errors = True
					self._DPRW_end.display_as_valid(False)

		if self._PRW_hospital_stay.GetData() is None:
			if self._PRW_episode.GetValue().strip() == '':
				self._PRW_episode.display_as_valid(False)
				has_errors = True
			else:
				self._PRW_episode.display_as_valid(True)
		else:
			self._PRW_episode.display_as_valid(True)

		if (self._PRW_procedure.GetValue() is None) or (self._PRW_procedure.GetValue().strip() == ''):
			self._PRW_procedure.display_as_valid(False)
			has_errors = True
		else:
			self._PRW_procedure.display_as_valid(True)

		invalid_location = (
			(self._PRW_hospital_stay.GetData() is None) and (self._PRW_location.GetData() is None)
				or
			(self._PRW_hospital_stay.GetData() is not None) and (self._PRW_location.GetData() is not None)
		)
		if invalid_location:
			self._PRW_hospital_stay.display_as_valid(False)
			self._PRW_location.display_as_valid(False)
			has_errors = True
		else:
			self._PRW_hospital_stay.display_as_valid(True)
			self._PRW_location.display_as_valid(True)

		gmDispatcher.send(signal = 'statustext', msg = _('Cannot save procedure.'), beep = True)

		return (has_errors is False)
Exemplo n.º 21
0
	def delete(enc_type=None):
		if gmEMRStructItems.delete_encounter_type(description = enc_type['description']):
			return True
		gmDispatcher.send (
			signal = u'statustext',
			msg = _('Cannot delete encounter type [%s]. It is in use.') % enc_type['l10n_description'],
			beep = True
		)
		return False
Exemplo n.º 22
0
	def delete(episode=None):
		if gmEMRStructItems.delete_episode(episode = episode):
			return True
		gmDispatcher.send (
			signal = 'statustext',
			msg = _('Cannot delete episode.'),
			beep = True
		)
		return False
Exemplo n.º 23
0
	def delete(stay=None):
		if gmEMRStructItems.delete_hospital_stay(stay = stay['pk_hospital_stay']):
			return True
		gmDispatcher.send (
			signal = 'statustext',
			msg = _('Cannot delete hospitalization.'),
			beep = True
		)
		return False
Exemplo n.º 24
0
	def _on_post_patient_selection(self, **kwargs):
		db_cfg = gmCfg.cCfgSQL()
		default_plugin = db_cfg.get2 (
			option = u'patient_search.plugin_to_raise_after_search',
			workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace,
			bias = u'user',
			default = u'gmPatientOverviewPlugin'
		)
		gmDispatcher.send(signal = 'display_widget', name = default_plugin)
Exemplo n.º 25
0
	def delete(issue=None):
		if gmEMRStructItems.delete_health_issue(health_issue = issue):
			return True
		gmDispatcher.send (
			signal = 'statustext',
			msg = _('Cannot delete health issue.'),
			beep = True
		)
		return False
Exemplo n.º 26
0
	def _valid_for_save(self):
		validity = True

		self.display_tctrl_as_valid(tctrl = self._PRW_patient, valid = (self._PRW_patient.person is not None))
		validity = (self._PRW_patient.person is not None)

		if validity is False:
			gmDispatcher.send(signal = 'statustext', msg = _('Cannot add to waiting list. Missing essential input.'))

		return validity
Exemplo n.º 27
0
	def delete(external_care_item=None):
		if gmExternalCare.delete_external_care_item(pk_external_care = external_care_item['pk_external_care']):
			return True

		gmDispatcher.send (
			signal = u'statustext',
			msg = _('Cannot delete external care item.'),
			beep = True
		)
		return False
Exemplo n.º 28
0
	def _on_result_activated(self, event):
#		data = self._LCTRL_inbox.get_selected_item_data(only_one = True)
#
#		if data is not None:
#			# <ctrl> down ?
#			if wx.GetKeyState(wx.WXK_CONTROL):
#				if isinstance(data, gmProviderInbox.cInboxMessage):
#					xxxxxxxxx
		gmDispatcher.send(signal = 'display_widget', name = 'gmMeasurementsGridPlugin')
		return
Exemplo n.º 29
0
	def _pre_exit_callback(self):
		"""The client is about to be shut down.

		Shutdown will not proceed before this returns.
		"""
		if not self.__curr_pat.connected:
			return
		if not self.__save_soap():
			gmDispatcher.send(signal = 'statustext', msg = _('Cannot save SimpleNotes SOAP note.'), beep = True)
		return
Exemplo n.º 30
0
	def delete(procedure=None):
		if gmEMRStructItems.delete_performed_procedure(procedure = procedure['pk_procedure']):
			return True

		gmDispatcher.send (
			signal = 'statustext',
			msg = _('Cannot delete performed procedure.'),
			beep = True
		)
		return False
Exemplo n.º 31
0
    def delete(item):
        delete_it = gmGuiHelpers.gm_show_question(
            aTitle=_('Deleting option'),
            aMessage='%s\n\n%s %s (#%s) %s\n\n%s\n\n%s' %
            (tooltip(item), gmTools.u_box_horiz_single * 3, item['option'],
             item['pk_cfg_item'], gmTools.u_box_horiz_single * 3,
             _('Do you really want to delete this option ?'),
             _('(GNUmed will re-create options as needed.)')))
        if not delete_it:
            return False

        from Gnumed.wxpython.gmAuthWidgets import get_dbowner_connection
        conn = get_dbowner_connection(procedure=_('Deleting option'))
        if conn is None:
            gmDispatcher.send(
                signal='statustext',
                msg=_(
                    'Cannot connect as database owner. Unable to delete option.'
                ))
            return False

        cfg = gmCfg.cCfgSQL()
        cfg.delete(conn=conn, pk_option=item['pk_cfg_item'])
        return True
Exemplo n.º 32
0
	def __export_as_zip(self, msg_title, encrypt=True, items=None):
		# get password
		zip_pwd = None
		if encrypt:
			zip_pwd = self.__get_password(msg_title)
			if zip_pwd is None:
				_log.debug('user aborted by not providing the same password twice')
				gmDispatcher.send(signal = 'statustext', msg = _('Password not provided twice. Aborting.'))
				return None
		# create archive
		wx.BeginBusyCursor()
		zip_file = None
		try:
			exp_area = gmPerson.gmCurrentPatient().export_area
			zip_file = exp_area.export_as_zip(passphrase = zip_pwd, items = items)
		except Exception:
			_log.exception('cannot create zip file')
		wx.EndBusyCursor()
		if zip_file is None:
			gmGuiHelpers.gm_show_error (
				aMessage = _('Error creating zip file.'),
				aTitle = msg_title
			)
		return zip_file
Exemplo n.º 33
0
 def delete(enc=None):
     if enc is None:
         return False
     question = _(
         'Really delete encounter [%s] ?\n'
         '\n'
         'Once deletion succeeds it cannot be undone.\n'
         '\n'
         'Note that it will only succeed if there\n'
         'is no data attached to the encounter.') % enc['pk_encounter']
     delete_it = gmGuiHelpers.gm_show_question(
         question=question,
         title=_('Deleting encounter'),
         cancel_button=False)
     if not delete_it:
         return False
     if gmEMRStructItems.delete_encounter(pk_encounter=enc['pk_encounter']):
         return True
     gmDispatcher.send(
         signal=u'statustext',
         msg=_('Cannot delete encounter [%s]. It is probably in use.') %
         enc['pk_encounter'],
         beep=True)
     return False
Exemplo n.º 34
0
    def __identity_valid_for_save(self):
        validity = True

        # name fields
        if self._PRW_lastname.GetValue().strip() == '':
            validity = False
            gmDispatcher.send(signal='statustext',
                              msg=_('Must enter lastname.'))
            self._PRW_lastname.display_as_valid(False)
        else:
            self._PRW_lastname.display_as_valid(True)

        if self._PRW_firstnames.GetValue().strip() == '':
            validity = False
            gmDispatcher.send(signal='statustext',
                              msg=_('Must enter first name.'))
            self._PRW_firstnames.display_as_valid(False)
        else:
            self._PRW_firstnames.display_as_valid(True)

        # gender
        if self._PRW_gender.GetData() is None:
            validity = False
            gmDispatcher.send(signal='statustext',
                              msg=_('Must select gender.'))
            self._PRW_gender.display_as_valid(False)
        else:
            self._PRW_gender.display_as_valid(True)

        # dob validation
        if not _validate_dob_field(self._PRW_dob):
            validity = False

        # TOB validation
        if _validate_tob_field(self._TCTRL_tob):
            self.display_ctrl_as_valid(ctrl=self._TCTRL_tob, valid=True)
        else:
            validity = False
            self.display_ctrl_as_valid(ctrl=self._TCTRL_tob, valid=False)

        # uniqueness
        if len(
                gmPerson.get_person_duplicates(
                    lastnames=self._PRW_lastname.GetValue(),
                    firstnames=self._PRW_firstnames.GetValue(),
                    dob=self._PRW_dob.GetData(),
                    gender=self._PRW_gender.GetData(),
                    comment=self._TCTRL_comment.Value)) > 0:
            validity = False
            self.StatusText = _(
                'Duplicate person. Modify name and/or DOB or use comment to make unique.'
            )

        return validity
Exemplo n.º 35
0
    def _on_confirm_button_pressed(self, evt):
        pat = gmPerson.gmCurrentPatient()
        emr = pat.emr
        allergies = emr.get_allergies()
        state = emr.allergy_state

        cmt = self._TCTRL_state_comment.GetValue().strip()

        if self._RBTN_unknown.GetValue():
            if len(allergies) > 0:
                gmDispatcher.send(
                    signal=u'statustext',
                    msg=
                    _('Cannot set allergy state to <unknown> because there are allergies stored for this patient.'
                      ),
                    beep=True)
                self._RBTN_some.SetValue(True)
                state['has_allergy'] = 1
                return False
            else:
                state['has_allergy'] = None

        elif self._RBTN_none.GetValue():
            if len(allergies) > 0:
                gmDispatcher.send(
                    signal=u'statustext',
                    msg=
                    _('Cannot set allergy state to <None> because there are allergies stored for this patient.'
                      ),
                    beep=True)
                self._RBTN_some.SetValue(True)
                state['has_allergy'] = 1
                return False
            else:
                state['has_allergy'] = 0

        elif self._RBTN_some.GetValue():
            if (len(allergies) == 0) and (cmt == u''):
                gmDispatcher.send(
                    signal=u'statustext',
                    msg=
                    _('Cannot set allergy state to <some> because there are neither allergies nor a comment available for this patient.'
                      ),
                    beep=True)
                return False
            else:
                state['has_allergy'] = 1

        state['comment'] = cmt
        state['last_confirmed'] = u'now'

        state.save_payload()
        self.__refresh_state_ui()
Exemplo n.º 36
0
    def _on_delete_focussed_msg(self, evt):
        if self.__focussed_msg['is_virtual']:
            gmDispatcher.send(
                signal='statustext',
                msg=
                _('You must deal with the reason for this message to remove it from your inbox.'
                  ),
                beep=True)
            return False

        # message to a certain provider ?
        if self.__focussed_msg['pk_staff'] is not None:
            # do not delete messages to *other* providers
            if self.__focussed_msg['pk_staff'] != gmStaff.gmCurrentProvider(
            )['pk_staff']:
                gmDispatcher.send(
                    signal='statustext',
                    msg=_('This message can only be deleted by [%s].') %
                    self.__focussed_msg['provider'],
                    beep=True)
                return False

        pk_patient = self.__focussed_msg['pk_patient']
        if pk_patient is not None:
            emr = gmClinicalRecord.cClinicalRecord(aPKey=pk_patient)
            epi = emr.add_episode(episode_name='administrative', is_open=False)
            soap_cat = gmTools.bool2subst(
                (self.__focussed_msg['category'] == 'clinical'), 'u', None)
            narr = _('Deleted inbox message:\n%s'
                     ) % self.__focussed_msg.format(with_patient=False)
            emr.add_clin_narrative(note=narr, soap_cat=soap_cat, episode=epi)
            gmDispatcher.send(
                signal='statustext',
                msg=_('Recorded deletion of inbox message in EMR.'),
                beep=False)

        if not self.provider.inbox.delete_message(
                self.__focussed_msg['pk_inbox_message']):
            gmDispatcher.send(signal='statustext',
                              msg=_('Problem removing message from Inbox.'))
            return False

        return True
Exemplo n.º 37
0
    def __identity_valid_for_save(self):
        error = False

        # name fields
        if self._PRW_lastname.GetValue().strip() == '':
            error = True
            gmDispatcher.send(signal='statustext',
                              msg=_('Must enter lastname.'))
            self._PRW_lastname.display_as_valid(False)
        else:
            self._PRW_lastname.display_as_valid(True)

        if self._PRW_firstnames.GetValue().strip() == '':
            error = True
            gmDispatcher.send(signal='statustext',
                              msg=_('Must enter first name.'))
            self._PRW_firstnames.display_as_valid(False)
        else:
            self._PRW_firstnames.display_as_valid(True)

        # gender
        if self._PRW_gender.GetData() is None:
            error = True
            gmDispatcher.send(signal='statustext',
                              msg=_('Must select gender.'))
            self._PRW_gender.display_as_valid(False)
        else:
            self._PRW_gender.display_as_valid(True)

        # dob validation
        if not _validate_dob_field(self._PRW_dob):
            error = True

        # TOB validation
        if _validate_tob_field(self._TCTRL_tob):
            self.display_ctrl_as_valid(ctrl=self._TCTRL_tob, valid=True)
        else:
            error = True
            self.display_ctrl_as_valid(ctrl=self._TCTRL_tob, valid=False)

        # uniqueness
        if gmPerson.this_person_exists(
                self._PRW_lastname.GetValue().strip(),
                self._PRW_firstnames.GetValue().strip(),
                self._PRW_dob.GetData(),
                gmTools.none_if(self._TCTRL_comment.GetValue().strip(), u'')):
            error = True
            self.StatusText = _(
                'Duplicate person. Modify name and/or DOB or use comment to make unique.'
            )

        return (not error)
Exemplo n.º 38
0
	def _on_export_items_button_pressed(self, event):
		event.Skip()

		items = self.__get_items_to_work_on(_('Exporting entries'))
		if items is None:
			return

		# export dialog
		pat = gmPerson.gmCurrentPatient()
		dlg = cExportAreaExportToMediaDlg(self, -1, patient = pat, item_count = len(items))
		choice = dlg.ShowModal()
		media = dlg._LCTRL_removable_media.get_selected_item_data(only_one = True)
		use_subdir = dlg._CHBOX_use_subdirectory.IsChecked()
		encrypt = dlg._CHBOX_encrypt.IsChecked()
		dlg.DestroyLater()
		if choice == wx.ID_CANCEL:
			return

		# export the files
		if media['type'] == 'cd':
			base_dir = gmTools.mk_sandbox_dir(prefix = 'iso-')
		else:
			base_dir = media['mountpoint']
		if use_subdir:
			dir2save2 = os.path.join(base_dir, pat.subdir_name)
		else:
			dir2save2 = base_dir
		export_dir = self.__export_as_files (
			gmTools.coalesce(encrypt, _('Exporting encrypted entries'), _('Exporting entries')),
			base_dir = dir2save2,
			items = items,
			encrypt = encrypt,
			with_metadata = True
		)
		if export_dir is None:
			gmDispatcher.send(signal = 'statustext', msg = _('Cannot export: aborted or error.'))
			return

		if media['type'] == 'cd':
			if not self.__burn_dir_to_disk(base_dir = base_dir):
				return
			gmDispatcher.send(signal = 'statustext', msg = _('Entries successfully burned to disk.'))
			self.__save_soap_note(soap = _('Burned onto CD/DVD:\n - %s') % '\n - '.join([ i['description'] for i in items ]))
		else:
			gmDispatcher.send(signal = 'statustext', msg = _('Exported entries into [%s]') % export_dir)
			self.__save_soap_note(soap = _('Exported onto removable media:\n - %s') % '\n - '.join([ i['description'] for i in items ]))

		self.__browse_patient_data(dir2save2, encrypted = encrypt, archive = False, has_metadata = True)

		# remove_entries ?

		return True
Exemplo n.º 39
0
def update_loinc_reference_data():

    wx.BeginBusyCursor()

    gmDispatcher.send(signal='statustext',
                      msg=_('Updating LOINC data can take quite a while...'),
                      beep=True)

    # download
    loinc_zip = gmNetworkTools.download_file(
        url='http://www.gnumed.de/downloads/data/loinc/loinctab.zip',
        suffix='.zip')
    if loinc_zip is None:
        wx.EndBusyCursor()
        gmGuiHelpers.gm_show_warning(
            aTitle=_('Downloading LOINC'),
            aMessage=_('Error downloading the latest LOINC data.\n'))
        return False

    _log.debug('downloaded zipped LOINC data into [%s]', loinc_zip)

    loinc_dir = gmNetworkTools.unzip_data_pack(filename=loinc_zip)

    # split master data file
    data_fname, license_fname = gmLOINC.split_LOINCDBTXT(
        input_fname=os.path.join(loinc_dir, 'LOINCDB.TXT'))

    wx.EndBusyCursor()

    conn = gmAuthWidgets.get_dbowner_connection(
        procedure=_('importing LOINC reference data'))
    if conn is None:
        return False

    wx.BeginBusyCursor()

    # import data
    if gmLOINC.loinc_import(data_fname=data_fname,
                            license_fname=license_fname,
                            conn=conn):
        gmDispatcher.send(signal='statustext',
                          msg=_('Successfully imported LOINC reference data.'))
    else:
        gmDispatcher.send(signal='statustext',
                          msg=_('Importing LOINC reference data failed.'),
                          beep=True)

    wx.EndBusyCursor()
    return True
Exemplo n.º 40
0
    def __identity_valid_for_save(self):
        error = False

        # name fields
        if self._PRW_lastname.GetValue().strip() == '':
            error = True
            gmDispatcher.send(signal='statustext',
                              msg=_('Must enter lastname.'))
            self._PRW_lastname.display_as_valid(False)
        else:
            self._PRW_lastname.display_as_valid(True)

        if self._PRW_firstnames.GetValue().strip() == '':
            error = True
            gmDispatcher.send(signal='statustext',
                              msg=_('Must enter first name.'))
            self._PRW_firstnames.display_as_valid(False)
        else:
            self._PRW_firstnames.display_as_valid(True)

        # gender
        if self._PRW_gender.GetData() is None:
            error = True
            gmDispatcher.send(signal='statustext',
                              msg=_('Must select gender.'))
            self._PRW_gender.display_as_valid(False)
        else:
            self._PRW_gender.display_as_valid(True)

        # dob validation
        if not _validate_dob_field(self._PRW_dob):
            error = True

        # TOB validation
        if _validate_tob_field(self._TCTRL_tob):
            self.display_ctrl_as_valid(ctrl=self._TCTRL_tob, valid=True)
        else:
            error = True
            self.display_ctrl_as_valid(ctrl=self._TCTRL_tob, valid=False)

        return (not error)
Exemplo n.º 41
0
    def _on_list_item_activated(self, evt):
        data = self.get_selected_item_data(only_one=True)
        pk_pat_col = self.__get_patient_pk_data_key(data=data)

        if pk_pat_col is None:
            gmDispatcher.send(signal='statustext',
                              msg=_('List not known to be patient-related.'))
            return

        pat_data = data[pk_pat_col]
        try:
            pat_pk = int(pat_data)
            pat = gmPerson.cPerson(aPK_obj=pat_pk)
        except (ValueError, TypeError):
            searcher = gmPersonSearch.cPatientSearcher_SQL()
            idents = searcher.get_identities(pat_data)
            if len(idents) == 0:
                gmDispatcher.send(signal='statustext',
                                  msg=_('No matching patient found.'))
                return
            if len(idents) == 1:
                pat = idents[0]
            else:
                from Gnumed.wxpython import gmPatSearchWidgets
                dlg = gmPatSearchWidgets.cSelectPersonFromListDlg(
                    parent=wx.GetTopLevelParent(self), id=-1)
                dlg.set_persons(persons=idents)
                result = dlg.ShowModal()
                if result == wx.ID_CANCEL:
                    dlg.Destroy()
                    return
                pat = dlg.get_selected_person()
                dlg.Destroy()
        except ConstructorError:
            gmDispatcher.send(signal='statustext',
                              msg=_('No matching patient found.'))
            return

        from Gnumed.wxpython import gmPatSearchWidgets
        gmPatSearchWidgets.set_active_patient(patient=pat)
Exemplo n.º 42
0
    def is_valid(value):

        if value is None:
            gmDispatcher.send(signal='statustext',
                              msg=_('You need to actually set an editor.'),
                              beep=True)
            return False, value

        if value.strip() == u'':
            gmDispatcher.send(signal='statustext',
                              msg=_('You need to actually set an editor.'),
                              beep=True)
            return False, value

        found, binary = gmShellAPI.detect_external_binary(value)
        if not found:
            gmDispatcher.send(signal='statustext',
                              msg=_('The command [%s] is not found.') % value,
                              beep=True)
            return True, value

        return True, binary
Exemplo n.º 43
0
	def _on_inbox_item_activated(self, event):

		data = self._LCTRL_inbox.get_selected_item_data(only_one = True)

		# if it is a dynamic hint open the URL for that
		if isinstance(data, gmAutoHints.cDynamicHint):
			if data['url'] is not None:
				gmNetworkTools.open_url_in_browser(data['url'])
			return

		# holding down <CTRL> when double-clicking an inbox
		# item indicates the desire to delete it
		# <ctrl> down ?
		if wx.GetKeyState(wx.WXK_CONTROL):
			# better safe than sorry: can only delete real inbox items
			if data is None:
				return
			if not isinstance(data, gmProviderInbox.cInboxMessage):
				return
			delete_it = gmGuiHelpers.gm_show_question (
				question = _('Do you really want to\ndelete this inbox message ?'),
				title = _('Deleting inbox message')
			)
			if not delete_it:
				return
			gmProviderInbox.delete_inbox_message(inbox_message = data['pk_inbox_message'])
			return

		if data is None:
			gmDispatcher.send(signal = 'display_widget', name = 'gmProviderInboxPlugin')
			return

		if not isinstance(data, gmProviderInbox.cInboxMessage):
			gmDispatcher.send(signal = 'display_widget', name = 'gmProviderInboxPlugin')
			return

		gmDispatcher.send(signal = 'display_widget', name = 'gmProviderInboxPlugin', filter_by_active_patient = True)
		return
Exemplo n.º 44
0
def manage_progress_notes(parent=None,
                          encounters=None,
                          episodes=None,
                          patient=None):

    # sanity checks
    if patient is None:
        patient = gmPerson.gmCurrentPatient()

    if not patient.connected:
        gmDispatcher.send(
            signal='statustext',
            msg=_('Cannot edit progress notes. No active patient.'))
        return False

    if parent is None:
        parent = wx.GetApp().GetTopWindow()

    emr = patient.emr

    #--------------------------
    def delete(item):
        if item is None:
            return False
        dlg = gmGuiHelpers.c2ButtonQuestionDlg(
            parent,
            -1,
            caption=_('Deleting progress note'),
            question=_(
                'Are you positively sure you want to delete this\n'
                'progress note from the medical record ?\n'
                '\n'
                'Note that even if you chose to delete the entry it will\n'
                'still be (invisibly) kept in the audit trail to protect\n'
                'you from litigation because physical deletion is known\n'
                'to be unlawful in some jurisdictions.\n'),
            button_defs=({
                'label': _('Delete'),
                'tooltip': _('Yes, delete the progress note.'),
                'default': False
            }, {
                'label': _('Cancel'),
                'tooltip': _('No, do NOT delete the progress note.'),
                'default': True
            }))
        decision = dlg.ShowModal()

        if decision != wx.ID_YES:
            return False

        gmClinNarrative.delete_clin_narrative(narrative=item['pk_narrative'])
        return True

    #--------------------------
    def edit(item):
        if item is None:
            return False

        dlg = gmGuiHelpers.cMultilineTextEntryDlg(
            parent,
            -1,
            title=_('Editing progress note'),
            msg=_('This is the original progress note:'),
            data=item.format(left_margin=' ', fancy=True),
            text=item['narrative'])
        decision = dlg.ShowModal()

        if decision != wx.ID_SAVE:
            return False

        val = dlg.value
        dlg.Destroy()
        if val.strip() == '':
            return False

        item['narrative'] = val
        item.save_payload()

        return True

    #--------------------------
    def refresh(lctrl):
        notes = emr.get_clin_narrative(
            encounters=encounters,
            episodes=episodes,
            providers=[gmStaff.gmCurrentProvider()['short_alias']])
        lctrl.set_string_items(items=[[
            narr['date'].strftime('%x %H:%M'), gmSoapDefs.soap_cat2l10n[
                narr['soap_cat']], narr['narrative'].replace(
                    '\n', '/').replace('\r', '/')
        ] for narr in notes])
        lctrl.set_data(data=notes)

    #--------------------------

    gmListWidgets.get_choices_from_list(
        parent=parent,
        caption=_('Managing progress notes'),
        msg=_('\n'
              ' This list shows the progress notes by %s.\n'
              '\n') % gmStaff.gmCurrentProvider()['short_alias'],
        columns=[_('when'), _('type'), _('entry')],
        single_selection=True,
        can_return_empty=False,
        edit_callback=edit,
        delete_callback=delete,
        refresh_callback=refresh)
Exemplo n.º 45
0
def print_generic_document(parent=None, jobtype:str=None, episode=None):
	"""Call LibreOffice Writer with a generated (fake) ODT file.

	Once Writer is closed, the ODT is imported if different from its initial content.

	Note:
		The file passed to LO _must_ reside in a directory the parents of
		which are all R-X by the user or else LO will throw up its arms
		in despair and fall back to the user's home dir upon saving.

		So,

			/tmp/user/$UID/some-file.odt

		will *not* work (because .../user/... is "drwx--x--x root.root") while

			/home/$USER/some/dir/some-file.odt

		does.
	"""
	sandbox = os.path.join(gmTools.gmPaths().user_tmp_dir, 'libreoffice')
	gmTools.mkdir(sandbox)
	fpath = gmTools.get_unique_filename(suffix = '.txt', tmp_dir = sandbox)
	doc_file = open(fpath, mode = 'wt')
	doc_file.write(__ODT_FILE_PREAMBLE)
	doc_file.write(_('Today: %s') % gmDateTime.pydt_now_here().strftime('%c'))
	doc_file.write('\n\n')
	prax = gmPraxis.gmCurrentPraxisBranch()
	doc_file.write('Praxis:\n')
	doc_file.write(prax.format())
	doc_file.write('\n')
	doc_file.write('Praxis branch:\n')
	doc_file.write('\n'.join(prax.org_unit.format (
		with_address = True,
		with_org = True,
		with_comms = True
	)))
	doc_file.write('\n\n')
	pat = gmPerson.gmCurrentPatient(gmPerson.cPatient(12))
	if pat.connected:
		doc_file.write('Patient:\n')
		doc_file.write(pat.get_description_gender())
		doc_file.write('\n\n')
		for adr in pat.get_addresses():
			doc_file.write(adr.format(single_line = False, verbose = True, show_type = True))
		doc_file.write('\n\n')
		for chan in pat.get_comm_channels():
			doc_file.werite(chan.format())
		doc_file.write('\n\n')
	doc_file.write('Provider:\n')
	doc_file.write('\n'.join(gmStaff.gmCurrentProvider().get_staff().format()))
	doc_file.write('\n\n-----------------------------------------------------------------------------\n\n')
	doc_file.close()

	# convert txt -> odt
	success, ret_code, stdout = gmShellAPI.run_process (
		cmd_line = [
			'lowriter',
			'--convert-to', 'odt',
			'--outdir', os.path.split(fpath)[0],
			fpath
		],
		verbose = True
	)
	if success:
		fpath = gmTools.fname_stem_with_path(fpath) + '.odt'
	else:
		_log.warning('cannot convert .txt to .odt')
	md5_before = gmTools.file2md5(fpath)
	gmShellAPI.run_process(cmd_line = ['lowriter', fpath], verbose = True)
	md5_after = gmTools.file2md5(fpath)
	if md5_before == md5_after:
		gmDispatcher.send(signal = 'statustext', msg = _('Document not modified. Discarding.'), beep = False)
		return

	if not pat.connected:
		shutil.move(fpath, gmTools.gmPaths().user_work_dir)
		gmDispatcher.send(signal = 'statustext', msg = _('No patient. Moved file into %s') % gmTools.gmPaths().user_work_dir, beep = False)
		return

	pat.export_area.add_file (
		filename = fpath,
		hint = _('Generic letter, written at %s') % gmDateTime.pydt_now_here().strftime('%Y %b %d  %H:%M')
	)
	gmDispatcher.send(signal = 'display_widget', name = 'gmExportAreaPlugin')
Exemplo n.º 46
0
def save_screenshot_to_file(filename=None, widget=None, settle_time=None):
    """Take screenshot of widget.

	<settle_time> in milliseconds
	"""
    assert (isinstance(widget,
                       wx.Window)), '<widget> must be (sub)class of wx.Window'

    if filename is None:
        filename = gmTools.get_unique_filename(
            prefix='gm-screenshot-%s-' %
            pyDT.datetime.now().strftime('%Y-%m-%d_%H-%M-%S'),
            suffix='.png'
            # for testing:
            #,tmp_dir = os.path.join(gmTools.gmPaths().home_dir, 'gnumed')
        )
    else:
        filename = gmTools.fname_sanitize(filename)

    _log.debug('filename: %s', filename)
    _log.debug('widget: %s', widget)
    _log.debug('display size: %s', wx.DisplaySize())

    # let it settle a bit for, say, tooltips
    if settle_time is not None:
        for wait_slice in range(int(settle_time // 100)):
            wx.SafeYield()
            time.sleep(0.1)

    widget_rect_on_screen = widget.GetScreenRect()
    client_area_origin_on_screen = widget.ClientToScreen((0, 0))
    widget_rect_local = widget.GetRect()
    widget_rect_client_area = widget.GetClientRect()
    client_area_origin_local = widget.GetClientAreaOrigin()

    _log.debug('widget.GetScreenRect(): %s', widget_rect_on_screen)
    _log.debug('widget.ClientToScreen(0, 0): %s', client_area_origin_on_screen)
    _log.debug('widget.GetRect(): %s', widget_rect_local)
    _log.debug('widget.GetClientRect(): %s', widget_rect_client_area)
    _log.debug('widget.GetClientAreaOrigin(): %s', client_area_origin_local)

    width2snap = widget_rect_local.width
    height2snap = widget_rect_local.height
    border_x = client_area_origin_on_screen.x - widget_rect_local.x
    x2snap_from = 0 - border_x
    title_and_menu_height = client_area_origin_on_screen.y - widget_rect_on_screen.y
    y2snap_from = 0 - title_and_menu_height

    # those are the correct dimensions but we don't get to
    # *see* the window decorations on a WindowDC or ClientDC :-(
    # (and a screendc doesn't work either)
    _log.debug('left (x) border: %s', border_x)
    _log.debug('top (y) border: %s', title_and_menu_height)
    _log.debug('x2snap_from: %s', x2snap_from)
    _log.debug('y2snap_from: %s', y2snap_from)
    _log.debug('width2snap: %s', width2snap)
    _log.debug('height2snap: %s', height2snap)

    # WindowDC includes decorations, supposedly, but Windows only
    window_dc = wx.WindowDC(widget)
    wxbmp = __snapshot_to_bitmap(source_dc=window_dc,
                                 x2snap_from=x2snap_from,
                                 y2snap_from=y2snap_from,
                                 width2snap=width2snap,
                                 height2snap=height2snap)
    window_dc.Destroy()
    del window_dc
    wxbmp.SaveFile(filename, wx.BITMAP_TYPE_PNG)
    del wxbmp

    x2snap_on_screen = widget_rect_on_screen.x
    y2snap_on_screen = widget_rect_on_screen.y  # adjust for menu/title ?
    sane_x2snap_on_screen = max(0, x2snap_on_screen)
    sane_y2snap_on_screen = max(0, y2snap_on_screen)

    _log.debug('x2snap_on_screen: %s', x2snap_on_screen)
    _log.debug('y2snap_on_screen: %s', y2snap_on_screen)
    _log.debug('sane x2snap_on_screen: %s', sane_x2snap_on_screen)
    _log.debug('sane x2snap_on_screen: %s', sane_y2snap_on_screen)

    screen_dc = wx.ScreenDC()
    # not implemented:
    #wxbmp = screen_dc.GetAsBitmap()		# can use subrect=...
    wxbmp = __snapshot_to_bitmap(source_dc=screen_dc,
                                 x2snap_from=sane_x2snap_on_screen,
                                 y2snap_from=sane_y2snap_on_screen,
                                 width2snap=width2snap,
                                 height2snap=height2snap)
    screen_dc.Destroy()
    del screen_dc
    wxbmp.SaveFile(filename + '.screendc.png', wx.BITMAP_TYPE_PNG)
    del wxbmp

    # ClientDC does not include decorations, only client area
    #client_dc = wx.ClientDC(widget)
    #wxbmp = __snapshot_to_bitmap (
    #	source_dc = client_dc,
    #	x2snap_from = x2snap_from,
    #	y2snap_from = y2snap_from,
    #	width2snap = width2snap,
    #	height2snap = height2snap
    #)
    #client_dc.Destroy()
    #del client_dc
    #wxbmp.SaveFile(filename + '.clientdc.png', wx.BITMAP_TYPE_PNG)
    #del wxbmp

    # adjust for window decoration on Linux
    #if sys.platform == 'linux':
    # If the widget has a menu bar, remove that from the title bar height.
    #if hasattr(widget, 'GetMenuBar'):
    #	if widget.GetMenuBar():
    #		title_bar_height /= 2
    #		print('title bar height:', title_bar_height)
    #width2snap += (border_width * 2)
    #height2snap += title_bar_height + border_width

    gmDispatcher.send(signal='statustext',
                      msg=_('Saved screenshot to file [%s].') % filename)
    return filename
Exemplo n.º 47
0
def select_narrative_from_episodes(parent=None, soap_cats=None):
    """soap_cats needs to be a list"""

    pat = gmPerson.gmCurrentPatient()
    emr = pat.emr

    if parent is None:
        parent = wx.GetApp().GetTopWindow()

    selected_soap = {}
    selected_issue_pks = []
    selected_episode_pks = []
    selected_narrative_pks = []

    while 1:
        # 1) select health issues to select episodes from
        all_issues = emr.get_health_issues()
        all_issues.insert(0, gmEMRStructItems.get_dummy_health_issue())
        dlg = gmEMRStructWidgets.cIssueListSelectorDlg(
            parent=parent,
            id=-1,
            issues=all_issues,
            msg=
            _('\n In the list below mark the health issues you want to report on.\n'
              ))
        selection_idxs = []
        for idx in range(len(all_issues)):
            if all_issues[idx]['pk_health_issue'] in selected_issue_pks:
                selection_idxs.append(idx)
        if len(selection_idxs) != 0:
            dlg.set_selections(selections=selection_idxs)
        btn_pressed = dlg.ShowModal()
        selected_issues = dlg.get_selected_item_data()
        dlg.Destroy()

        if btn_pressed == wx.ID_CANCEL:
            return selected_soap.values()

        selected_issue_pks = [i['pk_health_issue'] for i in selected_issues]

        while 1:
            # 2) select episodes to select items from
            all_epis = emr.get_episodes(issues=selected_issue_pks)

            if len(all_epis) == 0:
                gmDispatcher.send(
                    signal='statustext',
                    msg=_(
                        'No episodes recorded for the health issues selected.')
                )
                break

            dlg = gmEMRStructWidgets.cEpisodeListSelectorDlg(
                parent=parent,
                id=-1,
                episodes=all_epis,
                msg=_(
                    '\n These are the episodes known for the health issues just selected.\n\n'
                    ' Now, mark the the episodes you want to report on.\n'))
            selection_idxs = []
            for idx in range(len(all_epis)):
                if all_epis[idx]['pk_episode'] in selected_episode_pks:
                    selection_idxs.append(idx)
            if len(selection_idxs) != 0:
                dlg.set_selections(selections=selection_idxs)
            btn_pressed = dlg.ShowModal()
            selected_epis = dlg.get_selected_item_data()
            dlg.Destroy()

            if btn_pressed == wx.ID_CANCEL:
                break

            selected_episode_pks = [i['pk_episode'] for i in selected_epis]

            # 3) select narrative corresponding to the above constraints
            all_narr = emr.get_clin_narrative(episodes=selected_episode_pks,
                                              soap_cats=soap_cats)

            if len(all_narr) == 0:
                gmDispatcher.send(
                    signal='statustext',
                    msg=_('No narrative available for selected episodes.'))
                continue

            dlg = cNarrativeListSelectorDlg(
                parent=parent,
                id=-1,
                narrative=all_narr,
                msg=
                _('\n This is the narrative (type %s) for the chosen episodes.\n\n'
                  ' Now, mark the entries you want to include in your report.\n'
                  ) % '/'.join([
                      gmSoapDefs.soap_cat2l10n[cat]
                      for cat in gmTools.coalesce(soap_cats, list('soapu'))
                  ]))
            selection_idxs = []
            for idx in range(len(all_narr)):
                if all_narr[idx]['pk_narrative'] in selected_narrative_pks:
                    selection_idxs.append(idx)
            if len(selection_idxs) != 0:
                dlg.set_selections(selections=selection_idxs)
            btn_pressed = dlg.ShowModal()
            selected_narr = dlg.get_selected_item_data()
            dlg.Destroy()

            if btn_pressed == wx.ID_CANCEL:
                continue

            selected_narrative_pks = [i['pk_narrative'] for i in selected_narr]
            for narr in selected_narr:
                selected_soap[narr['pk_narrative']] = narr
Exemplo n.º 48
0
def import_hook_module(reimport=False):

    global hook_module
    if not reimport:
        if hook_module is not None:
            return True

    # hardcoding path and script name allows us to
    # not need configuration for it, the environment
    # can always be detected at runtime (workplace etc)
    script_name = 'hook_script.py'
    script_path = os.path.expanduser(os.path.join('~', '.gnumed', 'scripts'))
    full_script = os.path.join(script_path, script_name)

    if not os.access(full_script, os.F_OK):
        _log.warning('creating default hook script')
        f = io.open(full_script, mode='wt', encoding='utf8')
        f.write("""
# known hooks:
#  %s

def run_script(hook=None):
	pass
""" % '#  '.join(known_hooks))
        f.close()
        os.chmod(full_script, 384)

    if os.path.islink(full_script):
        gmDispatcher.send(signal='statustext',
                          msg=_('Script must not be a link: [%s].') %
                          full_script)
        return False

    if not os.access(full_script, os.R_OK):
        gmDispatcher.send(
            signal='statustext',
            msg=_('Script must be readable by the calling user: [%s].') %
            full_script)
        return False

    script_stat_val = os.stat(full_script)
    _log.debug('hook script stat(): %s', script_stat_val)
    script_perms = stat.S_IMODE(script_stat_val.st_mode)
    _log.debug('hook script mode: %s (oktal: %s)', script_perms,
               oct(script_perms))
    if script_perms != 384:  # octal 0600
        if os.name in ['nt']:
            _log.warning(
                'this platform does not support os.stat() file permission checking'
            )
        else:
            gmDispatcher.send(
                signal='statustext',
                msg=
                _('Script must be readable by the calling user only (permissions "0600"): [%s].'
                  ) % full_script)
            return False

    try:
        tmp = gmTools.import_module_from_directory(script_path, script_name)
    except Exception:
        _log.exception('cannot import hook script')
        return False

    hook_module = tmp
    #	if reimport:
    #		imp.reload(tmp)			# this has well-known shortcomings !

    _log.info('hook script: %s', full_script)
    return True
Exemplo n.º 49
0
	def _on_merge_button_pressed(self, event):

		if self._TCTRL_patient1.person is None:
			gmDispatcher.send(signal = 'statustext', msg = _('No patient selected on the left.'), beep = True)
			return

		if self._TCTRL_patient2.person is None:
			gmDispatcher.send(signal = 'statustext', msg = _('No patient selected on the right.'), beep = True)
			return

		if self._RBTN_patient1.GetValue():
			patient2keep = self._TCTRL_patient1.person
			patient2merge = self._TCTRL_patient2.person
		else:
			patient2keep = self._TCTRL_patient2.person
			patient2merge = self._TCTRL_patient1.person

		if patient2merge['lastnames'] == 'Kirk':
			if _cfg.get(option = 'debug'):
				gmNetworkTools.open_url_in_browser(url = 'http://en.wikipedia.org/wiki/File:Picard_as_Locutus.jpg')
				gmGuiHelpers.gm_show_info(_('\n\nYou will be assimilated.\n\n'), _('The Borg'))
				return
			else:
				gmDispatcher.send(signal = 'statustext', msg = _('Cannot merge Kirk into another patient.'), beep = True)
				return

		doit = gmGuiHelpers.gm_show_question (
			aMessage = _(
				'Are you positively sure you want to merge patient\n\n'
				' #%s: %s (%s, %s)\n\n'
				'into patient\n\n'
				' #%s: %s (%s, %s) ?\n\n'
				'Note that this action can ONLY be reversed by a laborious\n'
				'manual process requiring in-depth knowledge about databases\n'
				'and the patients in question !\n'
			) % (
				patient2merge.ID,
				patient2merge['description_gender'],
				patient2merge['gender'],
				patient2merge.get_formatted_dob(format = '%Y %b %d'),
				patient2keep.ID,
				patient2keep['description_gender'],
				patient2keep['gender'],
				patient2keep.get_formatted_dob(format = '%Y %b %d')
			),
			aTitle = _('Merging patients: confirmation'),
			cancel_button = False
		)
		if not doit:
			return

		conn = gmAuthWidgets.get_dbowner_connection(procedure = _('Merging patients'))
		if conn is None:
			gmDispatcher.send(signal = 'statustext', msg = _('Cannot merge patients without admin access.'), beep = True)
			return

		success, msg = patient2keep.assimilate_identity(other_identity = patient2merge, link_obj = conn)
		conn.close()
		if not success:
			gmDispatcher.send(signal = 'statustext', msg = msg, beep = True)
			return

		msg = _(
			'The patient\n'
			'\n'
			' #%s: %s (%s, %s)\n'
			'\n'
			'has successfully been merged into\n'
			'\n'
			' #%s: %s (%s, %s)'
		) % (
			patient2merge.ID,
			patient2merge['description_gender'],
			patient2merge['gender'],
			patient2merge.get_formatted_dob(format = '%Y %b %d'),
			patient2keep.ID,
			patient2keep['description_gender'],
			patient2keep['gender'],
			patient2keep.get_formatted_dob(format = '%Y %b %d')
		)
		title = _('Merging patients: success')

		curr_pat = gmPerson.gmCurrentPatient()
		# announce success
		if (curr_pat.connected) and (patient2keep.ID == curr_pat.ID):
			gmGuiHelpers.gm_show_info(aMessage = msg, aTitle = title)
		# and offer to activate kept patient if not active
		else:
			msg = msg + (
			'\n\n\n'
			'Do you want to activate that patient\n'
			'now for further modifications ?\n'
			)
			doit = gmGuiHelpers.gm_show_question (
				aMessage = msg,
				aTitle = title,
				cancel_button = False
			)
			if doit:
				wx.CallAfter(set_active_patient, patient = patient2keep)

		if self.IsModal():
			self.EndModal(wx.ID_OK)
		else:
			self.Close()
Exemplo n.º 50
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)
Exemplo n.º 51
0
def edit_visual_progress_note(filename=None,
                              episode=None,
                              discard_unmodified=False,
                              doc_part=None,
                              health_issue=None):
    """This assumes <filename> contains an image which can be handled by the configured image editor."""

    if doc_part is not None:
        filename = doc_part.export_to_file()
        if filename is None:
            gmDispatcher.send(
                signal=u'statustext',
                msg=_('Cannot export visual progress note to file.'))
            return None

    dbcfg = gmCfg.cCfgSQL()
    cmd = dbcfg.get2(
        option=u'external.tools.visual_soap_editor_cmd',
        workplace=gmPraxis.gmCurrentPraxisBranch().active_workplace,
        bias='user')

    if cmd is None:
        gmDispatcher.send(
            signal=u'statustext',
            msg=_('Editor for visual progress note not configured.'),
            beep=False)
        cmd = configure_visual_progress_note_editor()
        if cmd is None:
            gmDispatcher.send(
                signal=u'statustext',
                msg=_('Editor for visual progress note not configured.'),
                beep=True)
            return None

    if u'%(img)s' in cmd:
        cmd = cmd % {u'img': filename}
    else:
        cmd = u'%s %s' % (cmd, filename)

    if discard_unmodified:
        original_stat = os.stat(filename)
        original_md5 = gmTools.file2md5(filename)

    success = gmShellAPI.run_command_in_shell(cmd, blocking=True)
    if not success:
        gmGuiHelpers.gm_show_error(
            _('There was a problem with running the editor\n'
              'for visual progress notes.\n'
              '\n'
              ' [%s]\n'
              '\n') % cmd, _('Editing visual progress note'))
        return None

    try:
        open(filename, 'r').close()
    except Exception:
        _log.exception('problem accessing visual progress note file [%s]',
                       filename)
        gmGuiHelpers.gm_show_error(
            _('There was a problem reading the visual\n'
              'progress note from the file:\n'
              '\n'
              ' [%s]\n'
              '\n') % filename, _('Saving visual progress note'))
        return None

    if discard_unmodified:
        modified_stat = os.stat(filename)
        # same size ?
        if original_stat.st_size == modified_stat.st_size:
            modified_md5 = gmTools.file2md5(filename)
            # same hash ?
            if original_md5 == modified_md5:
                _log.debug('visual progress note (template) not modified')
                # ask user to decide
                msg = _(
                    u'You either created a visual progress note from a template\n'
                    u'in the database (rather than from a file on disk) or you\n'
                    u'edited an existing visual progress note.\n'
                    u'\n'
                    u'The template/original was not modified at all, however.\n'
                    u'\n'
                    u'Do you still want to save the unmodified image as a\n'
                    u'visual progress note into the EMR of the patient ?\n')
                save_unmodified = gmGuiHelpers.gm_show_question(
                    msg, _('Saving visual progress note'))
                if not save_unmodified:
                    _log.debug('user discarded unmodified note')
                    return

    if doc_part is not None:
        _log.debug('updating visual progress note')
        doc_part.update_data_from_file(fname=filename)
        doc_part.set_reviewed(technically_abnormal=False,
                              clinically_relevant=True)
        return None

    if not isinstance(episode, gmEMRStructItems.cEpisode):
        if episode is None:
            episode = _('visual progress notes')
        pat = gmPerson.gmCurrentPatient()
        emr = pat.emr
        episode = emr.add_episode(episode_name=episode.strip(),
                                  pk_health_issue=health_issue,
                                  is_open=False)

    doc = gmDocumentWidgets.save_file_as_new_document(
        filename=filename,
        document_type=gmDocuments.DOCUMENT_TYPE_VISUAL_PROGRESS_NOTE,
        episode=episode,
        unlock_patient=False,
        pk_org_unit=gmPraxis.gmCurrentPraxisBranch()['pk_org_unit'])
    doc.set_reviewed(technically_abnormal=False, clinically_relevant=True)

    return doc
Exemplo n.º 52
0
def select_encounters(parent=None,
                      patient=None,
                      single_selection=True,
                      encounters=None,
                      ignore_OK_button=False):

    if patient is None:
        patient = gmPerson.gmCurrentPatient()

    if not patient.connected:
        gmDispatcher.send(signal='statustext',
                          msg=_('Cannot list encounters. No active patient.'))
        return False

    if parent is None:
        parent = wx.GetApp().GetTopWindow()

    emr = patient.emr

    #--------------------
    def new():
        enc_type = gmCfgDB.get4user(
            option='encounter.default_type',
            workplace=gmPraxis.gmCurrentPraxisBranch().active_workplace)
        if enc_type is None:
            enc_type = gmEMRStructItems.get_most_commonly_used_encounter_type()
        if enc_type is None:
            enc_type = 'in surgery'
        enc = gmEMRStructItems.create_encounter(fk_patient=patient.ID,
                                                enc_type=enc_type)
        saved = edit_encounter(parent=parent, encounter=enc)
        if saved:
            return True
        gmEMRStructItems.delete_encounter(pk_encounter=enc['pk_encounter'])
        return False

    #--------------------
    def edit(enc=None):
        if enc is None:
            return False
        return edit_encounter(parent=parent, encounter=enc)

    #--------------------
    def edit_active(enc=None):
        return edit_encounter(parent=parent, encounter=emr.active_encounter)

    #--------------------
    def start_new(enc=None):
        start_new_encounter(emr=emr)
        return True

    #--------------------
    def delete(enc=None):
        if enc is None:
            return False
        question = _(
            'Really delete encounter [%s] ?\n'
            '\n'
            'Once deletion succeeds it cannot be undone.\n'
            '\n'
            'Note that it will only succeed if there\n'
            'is no data attached to the encounter.') % enc['pk_encounter']
        delete_it = gmGuiHelpers.gm_show_question(
            question=question,
            title=_('Deleting encounter'),
            cancel_button=False)
        if not delete_it:
            return False
        if gmEMRStructItems.delete_encounter(pk_encounter=enc['pk_encounter']):
            return True
        gmDispatcher.send(
            signal='statustext',
            msg=_('Cannot delete encounter [%s]. It is probably in use.') %
            enc['pk_encounter'],
            beep=True)
        return False

    #--------------------
    def get_tooltip(data):
        if data is None:
            return None
        return data.format(
            patient=patient,
            with_soap=False,
            with_docs=False,
            with_tests=False,
            with_vaccinations=False,
            with_rfe_aoe=True,
            with_family_history=False,
            by_episode=False,
            fancy_header=True,
        )

    #--------------------
    def refresh(lctrl):
        if encounters is None:
            encs = emr.get_encounters()
        else:
            encs = encounters

        items = [[
            '%s - %s' %
            (gmDateTime.pydt_strftime(e['started'], '%Y %b %d  %H:%M'),
             e['last_affirmed'].strftime('%H:%M')), e['l10n_type'],
            gmTools.coalesce(e['praxis_branch'], ''),
            gmTools.coalesce(e['reason_for_encounter'], ''),
            gmTools.coalesce(e['assessment_of_encounter'], ''),
            gmTools.bool2subst(e.has_clinical_data(), '',
                               gmTools.u_checkmark_thin), e['pk_encounter']
        ] for e in encs]
        lctrl.set_string_items(items=items)
        lctrl.set_data(data=encs)
        active_pk = emr.active_encounter['pk_encounter']
        for idx in range(len(encs)):
            e = encs[idx]
            if e['pk_encounter'] == active_pk:
                lctrl.SetItemTextColour(idx, wx.Colour('RED'))

    #--------------------
    return gmListWidgets.get_choices_from_list(
        parent=parent,
        msg=_("The patient's encounters.\n"),
        caption=_('Encounters ...'),
        columns=[
            _('When'),
            _('Type'),
            _('Where'),
            _('Reason for Encounter'),
            _('Assessment of Encounter'),
            _('Empty'), '#'
        ],
        can_return_empty=False,
        single_selection=single_selection,
        refresh_callback=refresh,
        edit_callback=edit,
        new_callback=new,
        delete_callback=delete,
        list_tooltip_callback=get_tooltip,
        ignore_OK_button=ignore_OK_button,
        left_extra_button=(_('Edit active'), _('Edit the active encounter'),
                           edit_active),
        middle_extra_button=(
            _('Start new'),
            _('Start new active encounter for the current patient.'),
            start_new))
Exemplo n.º 53
0
def search_narrative_in_emr(parent=None, patient=None):

    # sanity checks
    if patient is None:
        patient = gmPerson.gmCurrentPatient()

    if not patient.connected:
        gmDispatcher.send(signal='statustext',
                          msg=_('Cannot search EMR. No active patient.'))
        return False

    if parent is None:
        parent = wx.GetApp().GetTopWindow()

    search_term_dlg = wx.TextEntryDialog(
        parent=parent,
        message=_('Enter search term:'),
        caption=_('Text search of entire EMR of active patient'),
        style=wx.OK | wx.CANCEL | wx.CENTRE)
    result = search_term_dlg.ShowModal()

    if result != wx.ID_OK:
        search_term_dlg.Destroy()
        return False

    wx.BeginBusyCursor()
    val = search_term_dlg.GetValue()
    search_term_dlg.Destroy()
    emr = patient.emr
    rows = emr.search_narrative_simple(val)
    wx.EndBusyCursor()

    if len(rows) == 0:
        gmGuiHelpers.gm_show_info(
            _('Nothing found for search term:\n'
              ' "%s"') % val, _('Search results'))
        return True

    txt = ''
    for row in rows:
        txt += '%s: %s\n' % (row['soap_cat'], row['narrative'])

        txt += ' %s: %s - %s %s\n' % (
            _('Encounter'), row['encounter_started'].strftime('%x %H:%M'),
            row['encounter_ended'].strftime('%H:%M'), row['encounter_type'])
        txt += ' %s: %s\n' % (_('Episode'), row['episode'])
        txt += ' %s: %s\n\n' % (_('Health issue'), row['health_issue'])

    msg = _('Search term was: "%s"\n'
            '\n'
            'Search results:\n\n'
            '%s\n') % (val, txt)

    dlg = wx.MessageDialog(parent=parent,
                           message=msg,
                           caption=_('Search results for [%s]') % val,
                           style=wx.OK | wx.STAY_ON_TOP)
    dlg.ShowModal()
    dlg.Destroy()

    return True
Exemplo n.º 54
0
def move_progress_notes_to_another_encounter(parent=None,
                                             encounters=None,
                                             episodes=None,
                                             patient=None,
                                             move_all=False):

    # sanity checks
    if patient is None:
        patient = gmPerson.gmCurrentPatient()

    if not patient.connected:
        gmDispatcher.send(
            signal='statustext',
            msg=_('Cannot move progress notes. No active patient.'))
        return False

    if parent is None:
        parent = wx.GetApp().GetTopWindow()

    emr = patient.emr

    if encounters is None:
        all_encs_in_epi = emr.get_encounters(episodes=episodes,
                                             skip_empty=True)
        # nothing to do ?
        if len(all_encs_in_epi) == 0:
            return True
        encounters = gmEncounterWidgets.select_encounters(
            parent=parent,
            patient=patient,
            single_selection=False,
            encounters=all_encs_in_epi)
        # cancelled
        if encounters is None:
            return True
        # none selected
        if len(encounters) == 0:
            return True

    notes = emr.get_clin_narrative(encounters=encounters, episodes=episodes)

    # which narrative
    if move_all:
        selected_narr = notes
    else:
        selected_narr = gmListWidgets.get_choices_from_list(
            parent=parent,
            caption=_('Moving progress notes between encounters ...'),
            single_selection=False,
            can_return_empty=True,
            data=notes,
            msg=_('\n Select the progress notes to move from the list !\n\n'),
            columns=[_('when'), _('who'),
                     _('type'), _('entry')],
            choices=[[
                narr['date'].strftime('%x %H:%M'), narr['modified_by'],
                gmSoapDefs.soap_cat2l10n[narr['soap_cat']],
                narr['narrative'].replace('\n', '/').replace('\r', '/')
            ] for narr in notes])

    if not selected_narr:
        return True

    # which encounter to move to
    enc2move2 = gmEncounterWidgets.select_encounters(parent=parent,
                                                     patient=patient,
                                                     single_selection=True)

    if not enc2move2:
        return True

    for narr in selected_narr:
        narr['pk_encounter'] = enc2move2['pk_encounter']
        narr.save()

    return True
Exemplo n.º 55
0
def export_narrative_for_medistar_import(parent=None,
                                         soap_cats='soapu',
                                         encounter=None):

    # sanity checks
    pat = gmPerson.gmCurrentPatient()
    if not pat.connected:
        gmDispatcher.send(
            signal='statustext',
            msg=_('Cannot export EMR for Medistar. No active patient.'))
        return False

    if encounter is None:
        encounter = pat.emr.active_encounter

    if parent is None:
        parent = wx.GetApp().GetTopWindow()

    # get file name
    aWildcard = "%s (*.txt)|*.txt|%s (*)|*" % (_("text files"), _("all files"))
    # FIXME: make configurable
    aDefDir = os.path.abspath(os.path.expanduser(os.path.join('~', 'gnumed')))
    # FIXME: make configurable
    fname = '%s-%s-%s-%s-%s.txt' % (
        'Medistar-MD', time.strftime('%Y-%m-%d', time.localtime()),
        pat['lastnames'].replace(' ', '-'), pat['firstnames'].replace(
            ' ', '_'), pat.get_formatted_dob(format='%Y-%m-%d'))
    dlg = wx.FileDialog(
        parent=parent,
        message=_("Save EMR extract for MEDISTAR import as..."),
        defaultDir=aDefDir,
        defaultFile=fname,
        wildcard=aWildcard,
        style=wx.FD_SAVE)
    choice = dlg.ShowModal()
    fname = dlg.GetPath()
    dlg.Destroy()
    if choice != wx.ID_OK:
        return False

    wx.BeginBusyCursor()
    _log.debug('exporting encounter for medistar import to [%s]', fname)
    exporter = gmPatientExporter.cMedistarSOAPExporter(patient=pat)
    successful, fname = exporter.save_to_file(filename=fname,
                                              encounter=encounter,
                                              soap_cats='soapu',
                                              export_to_import_file=True)
    if not successful:
        gmGuiHelpers.gm_show_error(
            _('Error exporting progress notes for MEDISTAR import.'),
            _('MEDISTAR progress notes export'))
        wx.EndBusyCursor()
        return False

    gmDispatcher.send(
        signal='statustext',
        msg=
        _('Successfully exported progress notes into file [%s] for Medistar import.'
          ) % fname,
        beep=False)

    wx.EndBusyCursor()
    return True
Exemplo n.º 56
0
def generate_form_from_template(parent=None,
                                template_types=None,
                                edit=None,
                                template=None,
                                excluded_template_types=None):
    """If <edit> is None it will honor the template setting."""

    if parent is None:
        parent = wx.GetApp().GetTopWindow()

    # 1) get template to use
    if template is None:
        template = manage_form_templates(
            parent=parent,
            active_only=True,
            template_types=template_types,
            excluded_types=excluded_template_types)
        if template is None:
            gmDispatcher.send(signal='statustext',
                              msg=_('No document template selected.'),
                              beep=False)
            return None

    if template['engine'] == 'O':
        return print_doc_from_ooo_template(template=template)

    wx.BeginBusyCursor()

    # 2) process template
    try:
        form = template.instantiate()
    except KeyError:
        _log.exception('cannot instantiate document template [%s]', template)
        gmGuiHelpers.gm_show_error(
            aMessage=_('Invalid document template [%s - %s (%s)]') %
            (name, ver, template['engine']),
            aTitle=_('Generating document from template'))
        wx.EndBusyCursor()
        return None
    ph = gmMacro.gmPlaceholderHandler()
    #ph.debug = True
    form.substitute_placeholders(data_source=ph)
    if edit is None:
        if form.template['edit_after_substitution']:
            edit = True
        else:
            edit = False
    if edit:
        wx.EndBusyCursor()
        form.edit()
        wx.BeginBusyCursor()

    # 3) generate output
    pdf_name = form.generate_output()
    wx.EndBusyCursor()
    if pdf_name is not None:
        return form

    gmGuiHelpers.gm_show_error(
        aMessage=_('Error generating document printout.'),
        aTitle=_('Generating document printout'))
    return None
Exemplo n.º 57
0
def select_narrative_by_episode(parent=None, soap_cats=None):

    pat = gmPerson.gmCurrentPatient()
    emr = pat.emr

    all_epis = [
        epi for epi in emr.get_episodes(order_by='description')
        if epi.has_narrative
    ]
    if len(all_epis) == 0:
        gmDispatcher.send(signal='statustext',
                          msg=_('No episodes with progress notes found.'))
        return []

    if parent is None:
        parent = wx.GetApp().GetTopWindow()

    if soap_cats is None:
        soap_cats = 'soapu'
    soap_cats = list(soap_cats)
    i18n_soap_cats = [
        gmSoapDefs.soap_cat2l10n[cat].upper() for cat in soap_cats
    ]

    selected_soap = {}

    #selected_narrative_pks = []

    #-----------------------------------------------
    def get_soap_tooltip(soap):
        return soap.format(fancy=True, width=60)

    #-----------------------------------------------
    def pick_soap_from_episode(episode):

        if episode is None:
            return False

        narr_for_epi = emr.get_clin_narrative(episodes=[episode['pk_episode']],
                                              soap_cats=soap_cats)

        if len(narr_for_epi) == 0:
            gmDispatcher.send(
                signal='statustext',
                msg=_('No narrative available for selected episode.'))
            return True

        selected_narr = gmListWidgets.get_choices_from_list(
            parent=parent,
            msg=_('Pick the [%s] narrative you want to include in the report.')
            % '/'.join(i18n_soap_cats),
            caption=_('Picking [%s] from %s%s%s') %
            ('/'.join(i18n_soap_cats), gmTools.u_left_double_angle_quote,
             episode['description'], gmTools.u_right_double_angle_quote),
            columns=[_('When'), _('Who'),
                     _('Type'), _('Entry')],
            choices=[[
                gmDateTime.pydt_strftime(narr['date'],
                                         '%Y %b %d  %H:%M',
                                         accuracy=gmDateTime.acc_minutes),
                narr['modified_by'],
                gmSoapDefs.soap_cat2l10n[narr['soap_cat']],
                narr['narrative'].replace('\n', '//').replace('\r', '//')
            ] for narr in narr_for_epi],
            data=narr_for_epi,
            #selections=None,
            #edit_callback=None,
            single_selection=False,
            can_return_empty=False,
            list_tooltip_callback=get_soap_tooltip)

        if selected_narr is None:
            return True

        for narr in selected_narr:
            selected_soap[narr['pk_narrative']] = narr

        return True

#		selection_idxs = []
#		for idx in range(len(narr_for_epi)):
#			if narr_for_epi[idx]['pk_narrative'] in selected_narrative_pks:
#				selection_idxs.append(idx)
#		if len(selection_idxs) != 0:
#			dlg.set_selections(selections = selection_idxs)

#		selected_narrative_pks = [ i['pk_narrative'] for i in selected_narr ]
#		for narr in selected_narr:
#			selected_soap[narr['pk_narrative']] = narr
#
#		print "before returning from picking soap"
#
#		return True
#	#-----------------------------------------------

    def edit_episode(episode):
        return gmEMRStructWidgets.edit_episode(parent=parent, episode=episode)

    #-----------------------------------------------
    def refresh_episodes(lctrl):
        all_epis = [
            epi for epi in emr.get_episodes(order_by='description')
            if epi.has_narrative
        ]
        lctrl.set_string_items([[
            '%s%s' % (e['description'],
                      gmTools.coalesce(e['health_issue'], '', ' (%s)')),
            gmTools.bool2subst(e['episode_open'], _('open'), _('closed'))
        ] for e in all_epis])
        lctrl.set_data(all_epis)

    #-----------------------------------------------
    def get_episode_tooltip(episode):
        return episode.format(patient=pat,
                              with_encounters=False,
                              with_documents=False,
                              with_hospital_stays=False,
                              with_procedures=False,
                              with_family_history=False,
                              with_tests=False,
                              with_vaccinations=False)

    #-----------------------------------------------
    #selected_episode_pks = []

    epis_picked_from = gmListWidgets.get_choices_from_list(
        parent=parent,
        msg=_('\n Select the episode you want to report on.'),
        caption=_('Picking [%s] from episodes') % '/'.join(i18n_soap_cats),
        columns=[_('Episode'), _('Status')],
        edit_callback=edit_episode,
        refresh_callback=refresh_episodes,
        single_selection=True,
        can_return_empty=True,
        ignore_OK_button=False,
        left_extra_button=(_('&Pick notes'),
                           _('Pick [%s] entries from selected episode') %
                           '/'.join(i18n_soap_cats), pick_soap_from_episode),
        list_tooltip_callback=get_episode_tooltip)

    if epis_picked_from is None:
        return []

    return selected_soap.values()
Exemplo n.º 58
0
    def _on_notebook_page_changing(self, event):
        """Called before notebook page change is processed."""

        _log.debug('just before switching notebook tabs')

        _log.debug('id: %s', event.Id)
        _log.debug('event object (= source notebook): %s = %s',
                   event.EventObject.Id, event.EventObject)
        _log.debug('this notebook (= event receiver): %s = %s', self.Id, self)
        if event.EventObject.Id != self.Id:
            _log.error('this event came from another notebook')

        self.__target_page_already_checked = False

        self.__id_nb_page_before_switch = self.GetSelection()
        self.__id_evt_page_before_switch = event.GetOldSelection()
        __id_evt_page_after_switch = event.GetSelection()

        _log.debug('source/target page state in EVT_NOTEBOOK_PAGE_CHANGING:')
        _log.debug(
            ' #1 - notebook current page: %s (= notebook.GetSelection())',
            self.__id_nb_page_before_switch)
        _log.debug(
            ' #2 - event source page: %s (= page event says it is coming from, event.GetOldSelection())',
            self.__id_evt_page_before_switch)
        _log.debug(
            ' #3 - event target page: %s (= page event wants to go to, event.GetSelection())',
            __id_evt_page_after_switch)
        if self.__id_evt_page_before_switch != self.__id_nb_page_before_switch:
            _log.warning(' problem: #1 and #2 really should match but do not')

        # can we check the target page ?
        if __id_evt_page_after_switch == self.__id_evt_page_before_switch:
            # no, so complain
            # (the docs say that on Windows GetSelection() returns the
            #  old page ID, eg. the same value GetOldSelection() returns)
            _log.debug('this system is: sys: [%s] wx: [%s]', sys.platform,
                       wx.Platform)
            _log.debug(
                'it seems to be one of those platforms that have no clue which notebook page they are switching to'
            )
            _log.debug(
                '(Windows is documented to return the old page from both evt.GetOldSelection() and evt.GetSelection())'
            )
            _log.debug('current notebook page : %s',
                       self.__id_nb_page_before_switch)
            _log.debug('source page from event: %s',
                       self.__id_evt_page_before_switch)
            _log.debug('target page from event: %s',
                       __id_evt_page_after_switch)
            _log.warning(
                'cannot check whether notebook page change needs to be vetoed')
            # but let's do a basic check anyways
            pat = gmPerson.gmCurrentPatient()
            if not pat.connected:
                gmDispatcher.send(
                    signal='statustext',
                    msg=_('Cannot change notebook tabs. No active patient.'))
                event.Veto()
                return
            # that test passed, so let's hope things are fine
            event.Allow()  # redundant ?
            event.Skip()
            return

        # check target page
        target_page = self.__gb['horstspace.notebook.pages'][
            __id_evt_page_after_switch]
        _log.debug('checking event target page for focussability: %s',
                   target_page)
        if not target_page.can_receive_focus():
            _log.warning('veto()ing page change')
            event.Veto()
            return

        # everything seems fine so switch
        _log.debug('event target page seems focussable')
        self.__target_page_already_checked = True
        event.Allow()  # redundant ?
        event.Skip()
        return
Exemplo n.º 59
0
	def add_editor(self, problem=None, allow_same_problem=False):
		"""Add a progress note editor page.

		The way <allow_same_problem> is currently used in callers
		it only applies to unassociated episodes.
		"""
		problem_to_add = problem

		# determine label
		if problem_to_add is None:
			label = _('new problem')
		else:
			# normalize problem type
			if isinstance(problem_to_add, gmEMRStructItems.cEpisode):
				problem_to_add = gmEMRStructItems.episode2problem(episode = problem_to_add, allow_closed = True)

			elif isinstance(problem_to_add, gmEMRStructItems.cHealthIssue):
				problem_to_add = gmEMRStructItems.health_issue2problem(health_issue = problem_to_add, allow_irrelevant = True)

			if not isinstance(problem_to_add, gmEMRStructItems.cProblem):
				raise TypeError('cannot open progress note editor for [%s]' % problem_to_add)

			label = problem_to_add['problem']
			# FIXME: configure maximum length
			if len(label) > 23:
				label = label[:21] + gmTools.u_ellipsis

		# new unassociated problem or dupes allowed
		if allow_same_problem:
			new_page = gmProgressNotesEAWidgets.cProgressNotesEAPnl(self, -1, problem = problem_to_add)
			result = self.AddPage (
				page = new_page,
				text = label,
				select = True
			)
			return result

		# real problem, no dupes allowed
		# - raise existing editor
		for page_idx in range(self.GetPageCount()):
			page = self.GetPage(page_idx)

			if problem_to_add is None:
				if page.problem is None:
					self.SetSelection(page_idx)
					gmDispatcher.send(signal = 'statustext', msg = 'Raising existing editor.', beep = True)
					return True
				continue

			# editor is for unassociated new problem
			if page.problem is None:
				continue

			# editor is for episode
			if page.problem['type'] == 'episode':
				if page.problem['pk_episode'] == problem_to_add['pk_episode']:
					self.SetSelection(page_idx)
					gmDispatcher.send(signal = 'statustext', msg = 'Raising existing editor.', beep = True)
					return True
				continue

			# editor is for health issue
			if page.problem['type'] == 'issue':
				if page.problem['pk_health_issue'] == problem_to_add['pk_health_issue']:
					self.SetSelection(page_idx)
					gmDispatcher.send(signal = 'statustext', msg = 'Raising existing editor.', beep = True)
					return True
				continue

		# - or add new editor
		new_page = gmProgressNotesEAWidgets.cProgressNotesEAPnl(parent = self, problem = problem_to_add)
		result = self.AddPage (
			page = new_page,
			text = label,
			select = True
		)

		return result
Exemplo n.º 60
0
def get_person_from_external_sources(parent=None, search_immediately=False, activate_immediately=False):
	"""Load patient from external source.

	- scan external sources for candidates
	- let user select source
	  - if > 1 available: always
	  - if only 1 available: depending on search_immediately
	- search for patients matching info from external source
	- if more than one match:
	  - let user select patient
	- if no match:
	  - create patient
	- activate patient
	"""
	# get DTOs from interfaces
	dtos = []
	dtos.extend(load_persons_from_xdt())
	dtos.extend(load_persons_from_pracsoft_au())
	dtos.extend(load_persons_from_kvks())
	dtos.extend(load_persons_from_ca_msva())

	# no external persons
	if len(dtos) == 0:
		gmDispatcher.send(signal='statustext', msg=_('No patients found in external sources.'))
		return None

	# one external patient with DOB - already active ?
	if (len(dtos) == 1) and (dtos[0]['dto'].dob is not None):
		dto = dtos[0]['dto']
		# is it already the current patient ?
		curr_pat = gmPerson.gmCurrentPatient()
		if curr_pat.connected:
			key_dto = dto.firstnames + dto.lastnames + dto.dob.strftime('%Y-%m-%d') + dto.gender
			names = curr_pat.get_active_name()
			key_pat = names['firstnames'] + names['lastnames'] + curr_pat.get_formatted_dob(format = '%Y-%m-%d') + curr_pat['gender']
			_log.debug('current patient: %s' % key_pat)
			_log.debug('dto patient    : %s' % key_dto)
			if key_dto == key_pat:
				gmDispatcher.send(signal='statustext', msg=_('The only external patient is already active in GNUmed.'), beep=False)
				return None

	# one external person - look for internal match immediately ?
	if (len(dtos) == 1) and search_immediately:
		dto = dtos[0]['dto']

	# several external persons
	else:
		if parent is None:
			parent = wx.GetApp().GetTopWindow()
		dlg = cSelectPersonDTOFromListDlg(parent=parent, id=-1)
		dlg.set_dtos(dtos=dtos)
		result = dlg.ShowModal()
		if result == wx.ID_CANCEL:
			return None
		dto = dlg.get_selected_dto()['dto']
		dlg.DestroyLater()

	# search
	idents = dto.get_candidate_identities(can_create=True)
	if idents is None:
		gmGuiHelpers.gm_show_info (_(
			'Cannot create new patient:\n\n'
			' [%s %s (%s), %s]'
			) % (
				dto.firstnames, dto.lastnames, dto.gender, gmDateTime.pydt_strftime(dto.dob, '%Y %b %d')
			),
			_('Activating external patient')
		)
		return None

	if len(idents) == 1:
		ident = idents[0]

	if len(idents) > 1:
		if parent is None:
			parent = wx.GetApp().GetTopWindow()
		dlg = cSelectPersonFromListDlg(parent=parent, id=-1)
		dlg.set_persons(persons=idents)
		result = dlg.ShowModal()
		ident = dlg.get_selected_person()
		dlg.DestroyLater()
		if result == wx.ID_CANCEL:
			return None

	if activate_immediately:
		if not set_active_patient(patient = ident):
			gmGuiHelpers.gm_show_info (_(
				'Cannot activate patient:\n\n'
				'%s %s (%s)\n'
				'%s'
				) % (
					dto.firstnames, dto.lastnames, dto.gender, gmDateTime.pydt_strftime(dto.dob, '%Y %b %d')
				),
				_('Activating external patient')
			)
			return None

	dto.import_extra_data(identity = ident)
	dto.delete_from_source()

	return ident