Example #1
0
	def __refresh_results(self, patient=None):
		list_items = []
		list_data = []

		emr = patient.get_emr()
		most_recent = emr.get_most_recent_results(no_of_results = 1)
		if most_recent is None:
			self._LCTRL_results.set_string_items(items = [])
			self._LCTRL_results.set_data(data = [])
			return

		now = gmDateTime.pydt_now_here()
		list_items.append(_('Latest: %s ago (%s %s%s%s%s)') % (
			gmDateTime.format_interval_medically(now - most_recent['clin_when']),
			most_recent['unified_abbrev'],
			most_recent['unified_val'],
			gmTools.coalesce(most_recent['val_unit'], u'', u' %s'),
			gmTools.coalesce(most_recent['abnormality_indicator'], u'', u' %s'),
			gmTools.bool2subst(most_recent['reviewed'], u'', (u' %s' % gmTools.u_writing_hand))
		))
		list_data.append(most_recent)
		most_recent_needs_red = False
		if most_recent.is_considered_abnormal is True:
			if most_recent['is_clinically_relevant']:
				most_recent_needs_red = True

		unsigned = emr.get_unsigned_results(order_by = u"(trim(coalesce(abnormality_indicator), '') <> '') DESC NULLS LAST, unified_abbrev")
		no_of_reds = 0
		for result in unsigned:
			if result['pk_test_result'] == most_recent['pk_test_result']:
				continue
			if result['abnormality_indicator'] is not None:
				if result['abnormality_indicator'].strip() != u'':
					no_of_reds += 1
			list_items.append(_('%s %s%s%s (%s ago, %s)') % (
				result['unified_abbrev'],
				result['unified_val'],
				gmTools.coalesce(result['val_unit'], u'', u' %s'),
				gmTools.coalesce(result['abnormality_indicator'], u'', u' %s'),
				gmDateTime.format_interval_medically(gmDateTime.pydt_now_here() - result['clin_when']),
				gmTools.u_writing_hand
			))
			list_data.append(result)

		self._LCTRL_results.set_string_items(items = list_items)
		self._LCTRL_results.set_data(data = list_data)

		if most_recent_needs_red:
			self._LCTRL_results.SetItemTextColour(0, wx.NamedColour('RED'))
		if no_of_reds > 0:
			for idx in range(1, no_of_reds + 1):
				self._LCTRL_results.SetItemTextColour(idx, wx.NamedColour('RED'))
Example #2
0
	def __refresh_results(self, patient=None):
		list_items = []
		list_data = []

		emr = patient.emr
		most_recent = emr.get_most_recent_results(no_of_results = 1)
		if most_recent is None:
			self._LCTRL_results.set_string_items(items = [])
			self._LCTRL_results.set_data(data = [])
			return

		now = gmDateTime.pydt_now_here()
		list_items.append(_('Latest: %s ago (%s %s%s%s%s)') % (
			gmDateTime.format_interval_medically(now - most_recent['clin_when']),
			most_recent['unified_abbrev'],
			most_recent['unified_val'],
			gmTools.coalesce(most_recent['val_unit'], '', ' %s'),
			gmTools.coalesce(most_recent['abnormality_indicator'], '', ' %s'),
			gmTools.bool2subst(most_recent['reviewed'], '', (' %s' % gmTools.u_writing_hand))
		))
		list_data.append(most_recent)
		most_recent_needs_red = False
		if most_recent.is_considered_abnormal is True:
			if most_recent['is_clinically_relevant']:
				most_recent_needs_red = True

		unsigned = emr.get_unsigned_results(order_by = "(trim(coalesce(abnormality_indicator), '') <> '') DESC NULLS LAST, unified_abbrev")
		no_of_reds = 0
		for result in unsigned:
			if result['pk_test_result'] == most_recent['pk_test_result']:
				continue
			if result['abnormality_indicator'] is not None:
				if result['abnormality_indicator'].strip() != '':
					no_of_reds += 1
			list_items.append(_('%s %s%s%s (%s ago, %s)') % (
				result['unified_abbrev'],
				result['unified_val'],
				gmTools.coalesce(result['val_unit'], '', ' %s'),
				gmTools.coalesce(result['abnormality_indicator'], '', ' %s'),
				gmDateTime.format_interval_medically(gmDateTime.pydt_now_here() - result['clin_when']),
				gmTools.u_writing_hand
			))
			list_data.append(result)

		self._LCTRL_results.set_string_items(items = list_items)
		self._LCTRL_results.set_data(data = list_data)

		if most_recent_needs_red:
			self._LCTRL_results.SetItemTextColour(0, wx.Colour('RED'))
		if no_of_reds > 0:
			for idx in range(1, no_of_reds + 1):
				self._LCTRL_results.SetItemTextColour(idx, wx.Colour('RED'))
Example #3
0
	def _get_data_tooltip(self):
		if len(self._data) == 0:
			return ''

		date = self.GetData()
		# if match provider only provided completions
		# but not a full date with it
		if date is None:
			return ''
		ts = date.timestamp
		now = gmDateTime.pydt_now_here()
		if ts > now:
			intv = ts - now
			template = _('%s\n %s\n in %s')
		else:
			intv = now - ts
			template = _('%s\n%s\n%s ago')
		txt = template % (
			date.format_accurately(self.display_accuracy),
			gmDateTime.pydt_strftime (
				ts,
				format = '%A, %B-%d %Y (%c)',
			),
			gmDateTime.format_interval (
				interval = intv,
				accuracy_wanted = gmDateTime.acc_days,
				verbose = True
			)
		)
		return txt
Example #4
0
    def _get_data_tooltip(self):
        if len(self._data) == 0:
            return ''

        date = self.GetData()
        # if match provider only provided completions
        # but not a full date with it
        if date is None:
            return ''
        ts = date.timestamp
        now = gmDateTime.pydt_now_here()
        if ts > now:
            intv = ts - now
            template = _('%s\n %s\n in %s')
        else:
            intv = now - ts
            template = _('%s\n%s\n%s ago')
        txt = template % (date.format_accurately(self.display_accuracy),
                          gmDateTime.pydt_strftime(
                              ts,
                              format='%A, %B-%d %Y (%c)',
                          ),
                          gmDateTime.format_interval(
                              interval=intv,
                              accuracy_wanted=gmDateTime.acc_days,
                              verbose=True))
        return txt
Example #5
0
    def get_EDC(self, lmp=None, nullipara=True):

        result = cClinicalResult(_('unknown EDC'))
        result.formula_name = u'EDC (Mittendorf 1990)'
        result.formula_source = u'Mittendorf, R. et al., "The length of uncomplicated human gestation," OB/GYN, Vol. 75, No., 6 June, 1990, pp. 907-932.'

        if lmp is None:
            result.message = _('EDC: unknown LMP')
            return result

        result.variables['LMP'] = lmp
        result.variables['nullipara'] = nullipara
        if nullipara:
            result.variables['parity_offset'] = 15  # days
        else:
            result.variables['parity_offset'] = 10  # days

        now = gmDateTime.pydt_now_here()
        if lmp > now:
            result.warnings.append(_(u'LMP in the future'))

        if self.__patient is None:
            result.warnings.append(_(u'cannot run sanity checks, no patient'))
        else:
            if self.__patient['dob'] is None:
                result.warnings.append(_(u'cannot run sanity checks, no DOB'))
            else:
                years, months, days, hours, minutes, seconds = gmDateTime.calculate_apparent_age(
                    start=self.__patient['dob'])
                # 5 years -- Myth ?
                # http://www.mirror.co.uk/news/uk-news/top-10-crazy-amazing-and-world-789842
                if years < 10:
                    result.warnings.append(
                        _(u'patient less than 10 years old'))
            if self.__patient['gender'] in [None, u'm']:
                result.warnings.append(
                    _(u'atypical gender for pregnancy: %s') %
                    self.__patient.gender_string)
            if self.__patient['deceased'] is not None:
                result.warnings.append(_(u'patient already passed away'))

        if lmp.month > 3:
            edc_month = lmp.month - 3
            edc_year = lmp.year + 1
        else:
            edc_month = lmp.month + 9
            edc_year = lmp.year

        result.numeric_value = gmDateTime.pydt_replace(
            dt=lmp, year=edc_year, month=edc_month,
            strict=False) + pydt.timedelta(
                days=result.variables['parity_offset'])

        result.message = _('EDC: %s') % gmDateTime.pydt_strftime(
            result.numeric_value, format='%Y %b %d')
        result.date_valid = now

        _log.debug(u'%s' % result)

        return result
Example #6
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)
Example #7
0
	def _refresh_as_new(self):
		self._PRW_hospital.SetText(value = '', data = None)
		self._PRW_episode.SetText(value = '')
		self._PRW_admission.SetText(data = gmDateTime.pydt_now_here())
		self._PRW_discharge.SetText()
		self._TCTRL_comment.SetValue('')
		self._PRW_hospital.SetFocus()
Example #8
0
    def _get_data_tooltip(self):
        if len(self._data) == 0:
            return ''

        date = self.GetData()
        # if match provider only provided completions
        # but not a full date with it
        if date is None:
            return ''

        now = gmDateTime.pydt_now_here()
        if date > now:
            intv = date - now
            template = _('%s\n (a %s in %s)')
        else:
            intv = now - date
            template = _('%s\n (a %s %s ago)')
        return template % (
            gmDateTime.pydt_strftime(
                date, format='%B %d %Y -- %c', accuracy=gmDateTime.acc_days),
            gmDateTime.pydt_strftime(
                date, format='%A', accuracy=gmDateTime.acc_days),
            gmDateTime.format_interval(interval=intv,
                                       accuracy_wanted=gmDateTime.acc_days,
                                       verbose=True))
Example #9
0
	def archive_forms(episode_name=None, comment=None):
		if episode_name is None:
			epi = None				# will ask for episode further down
		else:
			pat = gmPerson.gmCurrentPatient()
			emr = pat.emr
			epi = emr.add_episode(episode_name = episode_name, is_open = False)
		for form in forms:
			files2import = []
			files2import.extend(form.final_output_filenames)
			files2import.extend(form.re_editable_filenames)
			if len(files2import) == 0:
				continue
			save_files_as_new_document (
				parent = parent,
				filenames = files2import,
				document_type = form.template['instance_type'],
				unlock_patient = False,
				episode = epi,
				review_as_normal = review_copy_as_normal,
				reference = None,
				pk_org_unit = gmPraxis.gmCurrentPraxisBranch()['pk_org_unit'],
				comment = comment,
				date_generated = gmDateTime.pydt_now_here()
			)
		return True
Example #10
0
def parse_xml_linuxmednews(xml_text=None, filename=None):
	dob_format = '%Y-%m-%d'

	try:
		if xml_text is None:
			_log.debug('parsing XML in [%s]', filename)
			pat = etree.parse(filename)
		else:
			pat = etree.fromstring(xml_text)
	except etree.ParseError:
		_log.exception('Cannot parse, is this really XML ?')
		return None

	dto = gmPerson.cDTO_person()

	dto.firstnames = pat.find('firstname').text
	dto.lastnames = pat.find('lastname').text
	dto.title = pat.find('name_prefix').text
	dto.gender = pat.find('gender').text
	dob = pyDT.datetime.strptime(pat.find('DOB').text, dob_format)
	dto.dob = dob.replace(tzinfo = gmDateTime.pydt_now_here().tzinfo)
	dto.dob_is_estimated = False
	dto.source = 'LinuxMedNews XML'

	#dto.remember_comm_channel(channel=None, url=None):
	#dto.remember_address(number=None, street=None, urb=None, region_code=None, zip=None, country_code=None, adr_type=None, subunit=None)

	return dto
Example #11
0
 def _refresh_as_new(self):
     self._PRW_hospital.SetText(value=u'', data=None)
     self._PRW_episode.SetText(value=u'')
     self._PRW_admission.SetText(data=gmDateTime.pydt_now_here())
     self._PRW_discharge.SetText()
     self._TCTRL_comment.SetValue(u'')
     self._PRW_hospital.SetFocus()
Example #12
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()
	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(at_date = patient.birthday_this_year).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)
Example #13
0
def parse_xml_linuxmednews(xml_text=None, filename=None):
    dob_format = '%Y-%m-%d'

    try:
        if xml_text is None:
            _log.debug('parsing XML in [%s]', filename)
            pat = etree.parse(filename)
        else:
            pat = etree.fromstring(xml_text)
    except etree.ParseError:
        _log.exception('Cannot parse, is this really XML ?')
        return None

    dto = gmPerson.cDTO_person()

    dto.firstnames = pat.find('firstname').text
    dto.lastnames = pat.find('lastname').text
    dto.title = pat.find('name_prefix').text
    dto.gender = pat.find('gender').text
    dob = pyDT.datetime.strptime(pat.find('DOB').text, dob_format)
    dto.dob = dob.replace(tzinfo=gmDateTime.pydt_now_here().tzinfo)
    dto.dob_is_estimated = False
    dto.source = 'LinuxMedNews XML'

    #dto.remember_comm_channel(channel=None, url=None):
    #dto.remember_address(number=None, street=None, urb=None, region_code=None, zip=None, country_code=None, adr_type=None, subunit=None)

    return dto
Example #14
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() == u'':
                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() == u''):
            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)
Example #15
0
def get_invoice_id(pk_patient=None):
	return 'GM%s / %s' % (
		pk_patient,
		gmDateTime.pydt_strftime (
			gmDateTime.pydt_now_here(),
			'%Y-%m-%d / %H%M%S'
		)
	)
Example #16
0
def get_invoice_id(pk_patient=None):
	return 'GM%s / %s' % (
		pk_patient,
		gmDateTime.pydt_strftime (
			gmDateTime.pydt_now_here(),
			'%Y-%m-%d / %H%M%S'
		)
	)
Example #17
0
 def __init__(self):
     super().__init__()
     self.dob_formats = [
         AMTS_BMP_DOB_FORMAT, AMTS_BMP_DOB_FORMAT_NO_DAY,
         AMTS_BMP_DOB_FORMAT_YEAR_ONLY
     ]
     self.dob_tz = gmDateTime.pydt_now_here().tzinfo
     self.gender_map = AMTS2GMD_GENDER_MAP
Example #18
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)
Example #19
0
 def fit_last_year(self):
     end = gmDateTime.pydt_now_here()
     g_end = GregorianDateTime(end.year, end.month, end.day, end.hour,
                               end.minute, end.second).to_time()
     g_start = GregorianDateTime(end.year - 1, end.month, end.day, end.hour,
                                 end.minute, end.second).to_time()
     last_year = TimePeriod(g_start, g_end)
     self.Navigate(
         lambda tp: tp.update(last_year.start_time, last_year.end_time))
Example #20
0
	def get_EDC(self, lmp=None, nullipara=True):

		result = cClinicalResult(_('unknown EDC'))
		result.formula_name = 'EDC (Mittendorf 1990)'
		result.formula_source = 'Mittendorf, R. et al., "The length of uncomplicated human gestation," OB/GYN, Vol. 75, No., 6 June, 1990, pp. 907-932.'

		if lmp is None:
			result.message = _('EDC: unknown LMP')
			return result

		result.variables['LMP'] = lmp
		result.variables['nullipara'] = nullipara
		if nullipara:
			result.variables['parity_offset'] = 15		# days
		else:
			result.variables['parity_offset'] = 10		# days

		now = gmDateTime.pydt_now_here()
		if lmp > now:
			result.warnings.append(_('LMP in the future'))

		if self.__patient is None:
			result.warnings.append(_('cannot run sanity checks, no patient'))
		else:
			if self.__patient['dob'] is None:
				result.warnings.append(_('cannot run sanity checks, no DOB'))
			else:
				years, months, days, hours, minutes, seconds = gmDateTime.calculate_apparent_age(start = self.__patient['dob'])
				# 5 years -- Myth ?
				# http://www.mirror.co.uk/news/uk-news/top-10-crazy-amazing-and-world-789842
				if years < 10:
					result.warnings.append(_('patient less than 10 years old'))
			if self.__patient['gender'] in [None, 'm']:
				result.warnings.append(_('atypical gender for pregnancy: %s') % self.__patient.gender_string)
			if self.__patient['deceased'] is not None:
				result.warnings.append(_('patient already passed away'))

		if lmp.month > 3:
			edc_month = lmp.month - 3
			edc_year = lmp.year + 1
		else:
			edc_month = lmp.month + 9
			edc_year = lmp.year

		result.numeric_value = gmDateTime.pydt_replace(dt = lmp, year = edc_year, month = edc_month, strict = False) + pydt.timedelta(days = result.variables['parity_offset'])

		result.message = _('EDC: %s') % gmDateTime.pydt_strftime (
			result.numeric_value,
			format = '%Y %b %d'
		)
		result.date_valid = now

		_log.debug('%s' % result)

		return result
Example #21
0
	def __refresh_results(self, patient=None):

		emr = patient.emr
		most_recent = emr.get_most_recent_results_for_patient()
		if len(most_recent) == 0:
			self._LCTRL_results.set_string_items(items = [])
			self._LCTRL_results.set_data(data = [])
			return
		most_recent = most_recent[0]

		list_items = []
		list_data = []
		now = gmDateTime.pydt_now_here()

		list_items.append(_('Most recent lab work: %s ago (%s)') % (
			gmDateTime.format_interval_medically(now - most_recent['clin_when']),
			gmDateTime.pydt_strftime(most_recent['clin_when'], format = '%Y %b %d')
		))
		list_data.append(most_recent)

		unsigned = emr.get_unsigned_results(order_by = "(trim(coalesce(abnormality_indicator), '') <> '') DESC NULLS LAST, unified_abbrev")
		no_of_reds = 0
		for result in unsigned:
			if result['abnormality_indicator'] is not None:
				if result['abnormality_indicator'].strip() != '':
					no_of_reds += 1
			list_items.append(_('%s %s%s%s (%s ago, %s)') % (
				result['unified_abbrev'],
				result['unified_val'],
				gmTools.coalesce(result['val_unit'], '', ' %s'),
				gmTools.coalesce(result['abnormality_indicator'], '', ' %s'),
				gmDateTime.format_interval_medically(gmDateTime.pydt_now_here() - result['clin_when']),
				gmTools.u_writing_hand
			))
			list_data.append(result)

		self._LCTRL_results.set_string_items(items = list_items)
		self._LCTRL_results.set_data(data = list_data)

		if no_of_reds > 0:
			for idx in range(1, no_of_reds + 1):
				self._LCTRL_results.SetItemTextColour(idx, wx.Colour('RED'))
Example #22
0
	def __refresh_results(self, patient=None):

		emr = patient.emr
		most_recent = emr.get_most_recent_results_for_patient()
		if len(most_recent) == 0:
			self._LCTRL_results.set_string_items(items = [])
			self._LCTRL_results.set_data(data = [])
			return
		most_recent = most_recent[0]

		list_items = []
		list_data = []
		now = gmDateTime.pydt_now_here()

		list_items.append(_('Most recent lab work: %s ago (%s)') % (
			gmDateTime.format_interval_medically(now - most_recent['clin_when']),
			gmDateTime.pydt_strftime(most_recent['clin_when'], format = '%Y %b %d')
		))
		list_data.append(most_recent)

		unsigned = emr.get_unsigned_results(order_by = "(trim(coalesce(abnormality_indicator), '') <> '') DESC NULLS LAST, unified_abbrev")
		no_of_reds = 0
		for result in unsigned:
			if result['abnormality_indicator'] is not None:
				if result['abnormality_indicator'].strip() != '':
					no_of_reds += 1
			list_items.append(_('%s %s%s%s (%s ago, %s)') % (
				result['unified_abbrev'],
				result['unified_val'],
				gmTools.coalesce(result['val_unit'], '', ' %s'),
				gmTools.coalesce(result['abnormality_indicator'], '', ' %s'),
				gmDateTime.format_interval_medically(gmDateTime.pydt_now_here() - result['clin_when']),
				gmTools.u_writing_hand
			))
			list_data.append(result)

		self._LCTRL_results.set_string_items(items = list_items)
		self._LCTRL_results.set_data(data = list_data)

		if no_of_reds > 0:
			for idx in range(1, no_of_reds + 1):
				self._LCTRL_results.SetItemTextColour(idx, wx.Colour('RED'))
Example #23
0
def get_scan2pay_data(branch, bill, provider=None, comment=None):
	"""Create scan2pay data for generating a QR code.

	https://www.scan2pay.info
	--------------------------------
	BCD														# (3) fixed, barcode tag
	002														# (3) fixed, version
	1														# (1) charset, 1 = utf8
	SCT														# (3) fixed
	$<praxis_id::BIC//Bank//%(value)s::11>$					# (11) <BIC>
	$2<range_of::$<current_provider_name::%(lastnames)s::>$,$<praxis::%(praxis)s::>$::70>2$			# (70) <Name of beneficiary> "Empfänger" - Praxis
	$<praxis_id::IBAN//Bank//%(value)s::34>$				# (34) <IBAN>
	EUR$<bill::%(total_amount_with_vat)s::12>$				# (12) <Amount in EURO> "EUR12.5"
															# (4) <purpose of transfer> - leer
															# (35) <remittance info - struct> - only this XOR the next field - GNUmed: leer
	$2<range_of::InvID=$<bill::%(invoice_id)s::>$/Date=$<today::%d.%B %Y::>$::140$>2$	# (140) <remittance info - text> "Client:Marie Louise La Lune" - "Rg Nr, date"
	<beneficiary-to-payor info>								# (70)	"pay soon :-)" - optional - GNUmed nur wenn bytes verfügbar
	--------------------------------
	total: 331 bytes (not chars ! - cave UTF8)
	EOL: LF or CRLF
	last *used* element not followed by anything, IOW can omit pending non-used elements
	"""
	assert (branch is not None), '<branch> must not be <None>'
	assert (bill is not None), '<bill> must not be <None>'

	data = {}
	IBANs = branch.get_external_ids(id_type = 'IBAN', issuer = 'Bank')
	if len(IBANs) == 0:
		_log.debug('no IBAN found, cannot create scan2pay data')
		return None
	data['IBAN'] = IBANs[0]['value'][:34]
	data['beneficiary'] = gmTools.coalesce (
		initial = provider,
		instead = branch['praxis'][:70],
		template_initial = '%%(lastnames)s, %s' % branch['praxis']
	)[:70]
	BICs = branch.get_external_ids(id_type = 'BIC', issuer = 'Bank')
	if len(BICs) == 0:
		data['BIC'] = ''
	else:
		data['BIC'] = BICs[0]['value'][:11]
	data['amount'] = bill['total_amount_with_vat'][:9]
	data['ref'] = (_('Inv: %s, %s') % (
		bill['invoice_id'],
		gmDateTime.pydt_strftime(gmDateTime.pydt_now_here(), '%d.%B %Y')
	))[:140]
	data['cmt'] = gmTools.coalesce(comment, '', '\n%s')[:70]

	data_str = 'BCD\n002\n1\nSCT\n%(BIC)s\n%(beneficiary)s\n%(IBAN)s\nEUR%(amount)s\n\n\n%(ref)s%(cmt)s' % data
	data_str_bytes = bytes(data_str, 'utf8')[:331]
	return str(data_str_bytes, 'utf8')
Example #24
0
def get_scan2pay_data(branch, bill, provider=None, comment=None):
	"""Create scan2pay data for generating a QR code.

	https://www.scan2pay.info
	--------------------------------
	BCD														# (3) fixed, barcode tag
	002														# (3) fixed, version
	1														# (1) charset, 1 = utf8
	SCT														# (3) fixed
	$<praxis_id::BIC//Bank//%(value)s::11>$					# (11) <BIC>
	$2<range_of::$<current_provider_name::%(lastnames)s::>$,$<praxis::%(praxis)s::>$::70>2$			# (70) <Name of beneficiary> "Empfänger" - Praxis
	$<praxis_id::IBAN//Bank//%(value)s::34>$				# (34) <IBAN>
	EUR$<bill::%(total_amount_with_vat)s::12>$				# (12) <Amount in EURO> "EUR12.5"
															# (4) <purpose of transfer> - leer
															# (35) <remittance info - struct> - only this XOR the next field - GNUmed: leer
	$2<range_of::InvID=$<bill::%(invoice_id)s::>$/Date=$<today::%d.%B %Y::>$::140$>2$	# (140) <remittance info - text> "Client:Marie Louise La Lune" - "Rg Nr, date"
	<beneficiary-to-payor info>								# (70)	"pay soon :-)" - optional - GNUmed nur wenn bytes verfügbar
	--------------------------------
	total: 331 bytes (not chars ! - cave UTF8)
	EOL: LF or CRLF
	last *used* element not followed by anything, IOW can omit pending non-used elements
	"""
	assert (branch is not None), '<branch> must not be <None>'
	assert (bill is not None), '<bill> must not be <None>'

	data = {}
	IBANs = branch.get_external_ids(id_type = 'IBAN', issuer = 'Bank')
	if len(IBANs) == 0:
		_log.debug('no IBAN found, cannot create scan2pay data')
		return None
	data['IBAN'] = IBANs[0]['value'][:34]
	data['beneficiary'] = gmTools.coalesce (
		value2test = provider,
		return_instead = branch['praxis'][:70],
		template4value = '%%(lastnames)s, %s' % branch['praxis']
	)[:70]
	BICs = branch.get_external_ids(id_type = 'BIC', issuer = 'Bank')
	if len(BICs) == 0:
		data['BIC'] = ''
	else:
		data['BIC'] = BICs[0]['value'][:11]
	data['amount'] = bill['total_amount_with_vat'][:9]
	data['ref'] = (_('Inv: %s, %s') % (
		bill['invoice_id'],
		gmDateTime.pydt_strftime(gmDateTime.pydt_now_here(), '%d.%B %Y')
	))[:140]
	data['cmt'] = gmTools.coalesce(comment, '', '\n%s')[:70]

	data_str = 'BCD\n002\n1\nSCT\n%(BIC)s\n%(beneficiary)s\n%(IBAN)s\nEUR%(amount)s\n\n\n%(ref)s%(cmt)s' % data
	data_str_bytes = bytes(data_str, 'utf8')[:331]
	return str(data_str_bytes, 'utf8')
Example #25
0
    def _refresh_from_existing(self):
        self._DPRW_date.SetData(data=self.data['clin_when'])
        if self.data['clin_end'] is None:
            self._DPRW_end.SetText()
            self._CHBOX_ongoing.Enable(True)
            self._CHBOX_ongoing.SetValue(self.data['is_ongoing'])
        else:
            self._DPRW_end.SetData(data=self.data['clin_end'])
            self._CHBOX_ongoing.Enable(False)
            now = gmDateTime.pydt_now_here()
            if self.data['clin_end'] > now:
                self._CHBOX_ongoing.SetValue(True)
            else:
                self._CHBOX_ongoing.SetValue(False)
        self._PRW_episode.SetText(value=self.data['episode'],
                                  data=self.data['pk_episode'])
        self._PRW_procedure.SetText(value=self.data['performed_procedure'],
                                    data=self.data['performed_procedure'])
        self._PRW_document.SetData(self.data['pk_doc'])
        self._TCTRL_comment.SetValue(
            gmTools.coalesce(self.data['comment'], u''))

        if self.data['pk_hospital_stay'] is None:
            self._PRW_hospital_stay.SetText()
            self._PRW_hospital_stay.Enable(False)
            self._LBL_hospital_details.SetLabel(u'')
            self._PRW_location.SetText(
                value=u'%s @ %s' %
                (self.data['unit'], self.data['organization']),
                data=self.data['pk_org_unit'])
            self._PRW_location.Enable(True)
            self._PRW_episode.Enable(True)
        else:
            self._PRW_hospital_stay.SetText(
                value=u'%s @ %s' %
                (self.data['unit'], self.data['organization']),
                data=self.data['pk_hospital_stay'])
            self._PRW_hospital_stay.Enable(True)
            self._LBL_hospital_details.SetLabel(
                gmEMRStructItems.cHospitalStay(
                    aPK_obj=self.data['pk_hospital_stay']).format())
            self._PRW_location.SetText()
            self._PRW_location.Enable(False)
            self._PRW_episode.Enable(False)

        val, data = self._PRW_codes.generic_linked_codes2item_dict(
            self.data.generic_codes)
        self._PRW_codes.SetText(val, data)

        self._PRW_procedure.SetFocus()
Example #26
0
	def _on_ongoing_checkbox_checked(self, event):
		if self._CHBOX_ongoing.IsChecked():
			end = self._DPRW_end.GetData()
			if end is None:
				self._DPRW_end.display_as_valid(True)
			else:
				end = end.get_pydt()
				now = gmDateTime.pydt_now_here()
				if end > now:
					self._DPRW_end.display_as_valid(True)
				else:
					self._DPRW_end.display_as_valid(False)
		else:
			self._DPRW_end.is_valid_timestamp()
		event.Skip()
Example #27
0
	def _on_ongoing_checkbox_checked(self, event):
		if self._CHBOX_ongoing.IsChecked():
			end = self._DPRW_end.GetData()
			if end is None:
				self._DPRW_end.display_as_valid(True)
			else:
				end = end.get_pydt()
				now = gmDateTime.pydt_now_here()
				if end > now:
					self._DPRW_end.display_as_valid(True)
				else:
					self._DPRW_end.display_as_valid(False)
		else:
			self._DPRW_end.is_valid_timestamp()
		event.Skip()
Example #28
0
	def _refresh_as_new(self):
		self._PRW_date_given.SetText(data = gmDateTime.pydt_now_here())
		self._CHBOX_anamnestic.SetValue(False)
		self._PRW_vaccine.SetText(value = '', data = None, suppress_smarts = True)
		self._PRW_batch.unset_context(context = 'pk_vaccine')
		self._PRW_batch.SetValue('')
		self._PRW_episode.SetText(value = '', data = None, suppress_smarts = True)
		self._PRW_site.SetValue('')
		self._PRW_provider.SetData(data = None)
		self._PRW_reaction.SetText(value = '', data = None, suppress_smarts = True)
		self._BTN_report.Enable(False)
		self._TCTRL_comment.SetValue('')

		self.__refresh_indications()

		self._PRW_date_given.SetFocus()
Example #29
0
	def _refresh_as_new(self):
		self._PRW_date_given.SetText(data = gmDateTime.pydt_now_here())
		self._CHBOX_anamnestic.SetValue(False)
		self._PRW_vaccine.SetText(value = '', data = None, suppress_smarts = True)
		self._PRW_batch.unset_context(context = 'pk_vaccine')
		self._PRW_batch.SetValue('')
		self._PRW_episode.SetText(value = '', data = None, suppress_smarts = True)
		self._PRW_site.SetValue('')
		self._PRW_provider.SetData(data = None)
		self._PRW_reaction.SetText(value = '', data = None, suppress_smarts = True)
		self._BTN_report.Enable(False)
		self._TCTRL_comment.SetValue('')

		self.__refresh_indications()

		self._PRW_date_given.SetFocus()
Example #30
0
	def __recalculate(self):
		lmp = self._PRW_lmp.date
		if lmp is None:
			self._PRW_edc.SetData(None)
			self._TCTRL_details.SetValue('')
			return

		edc = self.__calc.get_EDC(lmp = lmp, nullipara = self._CHBOX_first_pregnancy.GetValue())

		self._PRW_edc.SetData(edc.numeric_value)
		details = ''
		now = gmDateTime.pydt_now_here()
		# Beulah Hunter, 375 days (http://www.reference.com/motif/health/longest-human-pregnancy-on-record)
		if (lmp < now) and (edc.numeric_value > (now + pydt.timedelta(days = 380))):
			age = now - lmp
			weeks, days = divmod(age.days, 7)
			week = weeks
			if days > 0:
				week = weeks + 1
			month, tmp = divmod(age.days, 28)
			if days > 0:
				month += 1
			details += _(
				'Current age of pregnancy (%s):\n'
				' day %s = %s weeks %s days = week %s = month %s\n\n'
			) % (
				gmDateTime.pydt_strftime(now, '%Y %b %d'),
				age.days,
				int(weeks),
				int(days),
				week,
				month
			)

		details += edc.format (
			left_margin = 1,
			width = 50,
			with_formula = False,
			with_warnings = True,
			with_variables = True,
			with_sub_results = True,
			return_list = False
		)
		self._TCTRL_details.SetValue(details)
Example #31
0
	def __refresh_indications(self):
		self._TCTRL_indications.SetValue('')
		vaccine = self._PRW_vaccine.GetData(as_instance = True)
		if vaccine is None:
			return
		lines = []
		emr = gmPerson.gmCurrentPatient().emr
		latest_vaccs = emr.get_latest_vaccinations (
			atc_indications = [ i['atc_indication'] for i in vaccine['indications'] ]
		)
		for l10n_ind in [ i['l10n_indication'] for i in vaccine['indications'] ]:
			try:
				no_of_shots4ind, latest_vacc4ind = latest_vaccs[l10n_ind]
				ago = gmDateTime.format_interval_medically(gmDateTime.pydt_now_here() - latest_vacc4ind['date_given'])
				lines.append(_('%s  (most recent shot of %s: %s ago)') % (l10n_ind, no_of_shots4ind, ago))
			except KeyError:
				lines.append(_('%s  (no previous vaccination recorded)') % l10n_ind)

		self._TCTRL_indications.SetValue(_('Protects against:\n ') + '\n '.join(lines))
Example #32
0
	def __refresh_indications(self):
		self._TCTRL_indications.SetValue('')
		vaccine = self._PRW_vaccine.GetData(as_instance = True)
		if vaccine is None:
			return
		lines = []
		emr = gmPerson.gmCurrentPatient().emr
		latest_vaccs = emr.get_latest_vaccinations (
			atc_indications = [ i['atc_indication'] for i in vaccine['indications'] ]
		)
		for l10n_ind in [ i['l10n_indication'] for i in vaccine['indications'] ]:
			try:
				no_of_shots4ind, latest_vacc4ind = latest_vaccs[l10n_ind]
				ago = gmDateTime.format_interval_medically(gmDateTime.pydt_now_here() - latest_vacc4ind['date_given'])
				lines.append(_('%s  (most recent shot of %s: %s ago)') % (l10n_ind, no_of_shots4ind, ago))
			except KeyError:
				lines.append(_('%s  (no previous vaccination recorded)') % l10n_ind)

		self._TCTRL_indications.SetValue(_('Protects against:\n ') + '\n '.join(lines))
Example #33
0
    def __recalculate(self):
        lmp = self._PRW_lmp.date
        if lmp is None:
            self._PRW_edc.SetData(None)
            self._TCTRL_details.SetValue(u"")
            return

        edc = self.__calc.get_EDC(lmp=lmp, nullipara=self._CHBOX_first_pregnancy.GetValue())

        self._PRW_edc.SetData(edc.numeric_value)
        details = u""
        now = gmDateTime.pydt_now_here()
        # Beulah Hunter, 375 days (http://www.reference.com/motif/health/longest-human-pregnancy-on-record)
        if (lmp < now) and (edc.numeric_value > (now + pydt.timedelta(days=380))):
            age = now - lmp
            weeks, days = divmod(age.days, 7)
            week = weeks
            if days > 0:
                week = weeks + 1
            month, tmp = divmod(age.days, 28)
            if days > 0:
                month += 1
            details += _(u"Current age of pregnancy (%s):\n" u" day %s = %s weeks %s days = week %s = month %s\n\n") % (
                gmDateTime.pydt_strftime(now, "%Y %b %d"),
                age.days,
                int(weeks),
                int(days),
                week,
                month,
            )

        details += edc.format(
            left_margin=1,
            width=50,
            with_formula=False,
            with_warnings=True,
            with_variables=True,
            with_sub_results=True,
            return_list=False,
        )
        self._TCTRL_details.SetValue(details)
Example #34
0
	def _get_data_tooltip(self):
		if len(self._data) == 0:
			return ''

		date = self.GetData()
		# if match provider only provided completions
		# but not a full date with it
		if date is None:
			return ''

		now = gmDateTime.pydt_now_here()
		if date > now:
			intv = date - now
			template = _('%s\n (a %s in %s)')
		else:
			intv = now - date
			template = _('%s\n (a %s %s ago)')
		return template % (
			gmDateTime.pydt_strftime(date, format = '%B %d %Y -- %c', accuracy = gmDateTime.acc_days),
			gmDateTime.pydt_strftime(date, format = '%A', accuracy = gmDateTime.acc_days),
			gmDateTime.format_interval(interval = intv, accuracy_wanted = gmDateTime.acc_days, verbose = True)
		)
Example #35
0
	def _on_end_lost_focus(self):
		end = self._DPRW_end.GetData()
		if end is None:
			self._CHBOX_ongoing.Enable(True)
			self._DPRW_end.display_as_valid(True)
		else:
			self._CHBOX_ongoing.Enable(False)
			end = end.get_pydt()
			now = gmDateTime.pydt_now_here()
			if end > now:
				self._CHBOX_ongoing.SetValue(True)
			else:
				self._CHBOX_ongoing.SetValue(False)
			start = self._DPRW_date.GetData()
			if start is None:
				self._DPRW_end.display_as_valid(True)
			else:
				start = start.get_pydt()
				if end > start:
					self._DPRW_end.display_as_valid(True)
				else:
					self._DPRW_end.display_as_valid(False)
Example #36
0
	def _on_end_lost_focus(self):
		end = self._DPRW_end.GetData()
		if end is None:
			self._CHBOX_ongoing.Enable(True)
			self._DPRW_end.display_as_valid(True)
		else:
			self._CHBOX_ongoing.Enable(False)
			end = end.get_pydt()
			now = gmDateTime.pydt_now_here()
			if end > now:
				self._CHBOX_ongoing.SetValue(True)
			else:
				self._CHBOX_ongoing.SetValue(False)
			start = self._DPRW_date.GetData()
			if start is None:
				self._DPRW_end.display_as_valid(True)
			else:
				start = start.get_pydt()
				if end > start:
					self._DPRW_end.display_as_valid(True)
				else:
					self._DPRW_end.display_as_valid(False)
Example #37
0
	def _refresh_from_existing(self):
		self._DPRW_date.SetData(data = self.data['clin_when'])
		if self.data['clin_end'] is None:
			self._DPRW_end.SetText()
			self._CHBOX_ongoing.Enable(True)
			self._CHBOX_ongoing.SetValue(self.data['is_ongoing'])
		else:
			self._DPRW_end.SetData(data = self.data['clin_end'])
			self._CHBOX_ongoing.Enable(False)
			now = gmDateTime.pydt_now_here()
			if self.data['clin_end'] > now:
				self._CHBOX_ongoing.SetValue(True)
			else:
				self._CHBOX_ongoing.SetValue(False)
		self._PRW_episode.SetText(value = self.data['episode'], data = self.data['pk_episode'])
		self._PRW_procedure.SetText(value = self.data['performed_procedure'], data = self.data['performed_procedure'])
		self._PRW_document.SetData(self.data['pk_doc'])
		self._TCTRL_comment.SetValue(gmTools.coalesce(self.data['comment'], ''))

		if self.data['pk_hospital_stay'] is None:
			self._PRW_hospital_stay.SetText()
			self._PRW_hospital_stay.Enable(False)
			self._LBL_hospital_details.SetLabel('')
			self._PRW_location.SetText(value = '%s @ %s' % (self.data['unit'], self.data['organization']), data = self.data['pk_org_unit'])
			self._PRW_location.Enable(True)
			self._PRW_episode.Enable(True)
		else:
			self._PRW_hospital_stay.SetText(value = '%s @ %s' % (self.data['unit'], self.data['organization']), data = self.data['pk_hospital_stay'])
			self._PRW_hospital_stay.Enable(True)
			self._LBL_hospital_details.SetLabel(gmEMRStructItems.cHospitalStay(aPK_obj = self.data['pk_hospital_stay']).format())
			self._PRW_location.SetText()
			self._PRW_location.Enable(False)
			self._PRW_episode.Enable(False)

		val, data = self._PRW_codes.generic_linked_codes2item_dict(self.data.generic_codes)
		self._PRW_codes.SetText(val, data)

		self._PRW_procedure.SetFocus()
Example #38
0
	def __update_age_label(self):

		# no patient
		if not self.curr_pat.connected:
			self._LBL_age.SetLabel(_('<Age>'))
			self._LBL_age.SetToolTipString(_('no patient selected'))
			return

		# gender is always known
		tt = _(u'Gender: %s (%s) - %s\n') % (
			self.curr_pat.gender_symbol,
			gmTools.coalesce(self.curr_pat[u'gender'], u'?'),
			self.curr_pat.gender_string
		)

		# dob is not known
		if self.curr_pat['dob'] is None:
			age = u'%s  %s' % (
				self.curr_pat.gender_symbol,
				self.curr_pat.get_formatted_dob()
			)
			self._LBL_age.SetLabel(age)
			self._LBL_age.SetToolTipString(tt)
			return

		tt += _('Born: %s\n') % self.curr_pat.get_formatted_dob(format = '%d %b %Y', encoding = gmI18N.get_encoding())

		# patient is dead
		if self.curr_pat['deceased'] is not None:
			tt += _('Died: %s\n') % gmDateTime.pydt_strftime(self.curr_pat['deceased'], '%d %b %Y')
			tt += _('At age: %s\n') % self.curr_pat['medical_age']
			age = u'%s  %s - %s (%s)' % (
				self.curr_pat.gender_symbol,
				self.curr_pat.get_formatted_dob(format = '%d %b %Y', encoding = gmI18N.get_encoding()),
				gmDateTime.pydt_strftime(self.curr_pat['deceased'], '%d %b %Y'),
				self.curr_pat['medical_age']
			)
			if self.curr_pat['dob_is_estimated']:
				tt += _(' (date of birth and age are estimated)\n')
			self._LBL_age.SetLabel(age)
			self._LBL_age.SetToolTipString(tt)
			return

		# patient alive
		now = gmDateTime.pydt_now_here()

		# patient birthday ?
		if self.curr_pat.get_formatted_dob(format = '%m-%d') == now.strftime('%m-%d'):
			template = _('%(sex)s  %(dob)s (%(age)s today !)')
			tt += _("\nToday is the patient's birthday !\n\n")
		else:
			if self.curr_pat.current_birthday_passed():
				template = u'%(sex)s  %(dob)s%(l_arr)s (%(age)s)'
				tt += _(u'Birthday: %s ago\n') % gmDateTime.format_apparent_age_medically (
					age = gmDateTime.calculate_apparent_age(start = self.curr_pat.birthday_this_year, end = now)
				)
			else:
				template = u'%(sex)s  %(r_arr)s%(dob)s (%(age)s)'
				tt += _(u'Birthday: in %s\n') % gmDateTime.format_apparent_age_medically (
					age = gmDateTime.calculate_apparent_age(start = now, end = self.curr_pat.birthday_this_year)
				)

		tt += _('Age: %s\n') % self.curr_pat['medical_age']

		# FIXME: if the age is below, say, 2 hours we should fire
		# a timer here that updates the age in increments of 1 minute ... :-)
		age = template % {
			u'sex': self.curr_pat.gender_symbol,
			u'dob': self.curr_pat.get_formatted_dob(format = '%d %b %Y', encoding = gmI18N.get_encoding()),
			u'age': self.curr_pat['medical_age'],
			u'r_arr': gmTools.u_right_arrow,
			u'l_arr': gmTools.u_left_arrow
		}

		# Easter Egg ;-)
		if self.curr_pat['lastnames'] == u'Leibner':
			if self.curr_pat['firstnames'] == u'Steffi':
				if self.curr_pat['preferred'] == u'Wildfang':
					age = u'%s %s' % (gmTools.u_black_heart, age)

		if self.curr_pat['dob_is_estimated']:
			tt += _(' (date of birth and age are estimated)\n')

		self._LBL_age.SetLabel(age)
		self._LBL_age.SetToolTipString(tt)
Example #39
0
def create_fake_timeline_file(patient=None, filename=None):
	"""Used to create an 'empty' timeline file for display.

	- needed because .clear_timeline() doesn't really work
	"""
	emr = patient.emr
	global now
	now = gmDateTime.pydt_now_here()

	if filename is None:
		timeline_fname = gmTools.get_unique_filename(prefix = 'gm-', suffix = '.timeline')
	else:
		timeline_fname = filename

	_log.debug('creating dummy timeline in [%s]', timeline_fname)
	timeline = io.open(timeline_fname, mode = 'wt', encoding = 'utf8', errors = 'xmlcharrefreplace')

	timeline.write(__fake_timeline_start)

	# birth
	if patient['dob'] is None:
		start = now.replace(year = now.year - 100)
		timeline.write(__xml_encounter_template % (
			format_pydt(start),
			format_pydt(start),
			_('Birth') + ': ?',
			_('Life events'),
			_('Date of birth unknown'),
			'False'
		))
	else:
		start = patient['dob']
		timeline.write(__xml_encounter_template % (
			format_pydt(patient['dob']),
			format_pydt(patient['dob']),
			_('Birth') + gmTools.bool2subst(patient['dob_is_estimated'], ' (%s)' % gmTools.u_almost_equal_to, ''),
			_('Life events'),
			'',
			'False'
		))

	# death
	if patient['deceased'] is None:
		end = now
	else:
		end = patient['deceased']
		timeline.write(__xml_encounter_template % (
			format_pydt(end),
			format_pydt(end),
			#u'',
			_('Death'),
			_('Life events'),
			'',
			'False'
		))

	# fake issue
	timeline.write(__fake_timeline_body_template % (
		format_pydt(start),
		format_pydt(end),
		_('Cannot display timeline.'),
		_('Cannot display timeline.')
	))

	# display range
	if end.month == 2:
		if end.day == 29:
			# leap years aren't consecutive
			end = end.replace(day = 28)
	target_year = end.year + 1
	end = end.replace(year = target_year)
	timeline.write(xml_end % (
		format_pydt(start),
		format_pydt(end)
	))

	timeline.close()
	return timeline_fname
Example #40
0
def create_timeline_file(patient=None, filename=None, include_documents=False, include_vaccinations=False, include_encounters=False):

	emr = patient.emr
	global now
	now = gmDateTime.pydt_now_here()

	if filename is None:
		timeline_fname = gmTools.get_unique_filename(prefix = 'gm-', suffix = '.timeline')	# .timeline required ...
	else:
		timeline_fname = filename
	_log.debug('exporting EMR as timeline into [%s]', timeline_fname)
	timeline = io.open(timeline_fname, mode = 'wt', encoding = 'utf8', errors = 'xmlcharrefreplace')

	if patient['dob'] is None:
		lifespan_start = format_pydt(now.replace(year = now.year - 100))
	else:
		lifespan_start = format_pydt(patient['dob'])

	if patient['deceased'] is None:
		life_ends2day = 'True'
		lifespan_end = format_pydt(now)
	else:
		life_ends2day = 'False'
		lifespan_end = format_pydt(patient['deceased'])

	earliest_care_date = emr.earliest_care_date
	most_recent_care_date = emr.most_recent_care_date
	if most_recent_care_date is None:
		most_recent_care_date = lifespan_end
		care_ends2day = life_ends2day
	else:
		most_recent_care_date = format_pydt(most_recent_care_date)
		care_ends2day = 'False'

	timeline.write(xml_start % (
		# era: life span of patient
		_('Lifespan'),
		lifespan_start,
		lifespan_end,
		life_ends2day,
		ERA_NAME_CARE_PERIOD,
		format_pydt(earliest_care_date),
		most_recent_care_date,
		care_ends2day,
		# categories
		_('Health issues'),
		_('Episodes'),
		_('Encounters'),
		_('Hospital stays'),
		_('Procedures'),
		_('Documents'),
		_('Vaccinations'),
		_('Substances'),
		_('Life events')
	))
	# birth
	if patient['dob'] is None:
		start = now.replace(year = now.year - 100)
		timeline.write(__xml_encounter_template % (
			format_pydt(start),
			format_pydt(start),
			'?',
			_('Life events'),
			_('Date of birth unknown'),
			'True'
		))
	else:
		start = patient['dob']
		timeline.write(__xml_encounter_template % (
			format_pydt(patient['dob']),
			format_pydt(patient['dob']),
			'*',
			_('Life events'),
			'%s: %s (%s)' % (
				_('Birth'),
				patient.get_formatted_dob(format = '%Y %b %d %H:%M', honor_estimation = True),
				patient.get_medical_age()
			),
			'True'
		))

	# start of care
	timeline.write(__xml_encounter_template % (
		format_pydt(earliest_care_date),
		format_pydt(earliest_care_date),
		gmTools.u_heavy_greek_cross,
		_('Life events'),
		_('Start of Care: %s\n(the earliest recorded event of care in this praxis)') % format_pydt(earliest_care_date, format = '%Y %b %d'),
		'True'
	))

	# containers must be defined before their
	# subevents, so put health issues first
	timeline.write('\n		<!-- ========================================\n Health issues\n======================================== -->')
	for issue in emr.health_issues:
		timeline.write(__format_health_issue_as_timeline_xml(issue, patient, emr))

	timeline.write('\n		<!-- ========================================\n Episodes\n======================================== -->')
	for epi in emr.get_episodes(order_by = 'pk_health_issue'):
		timeline.write(__format_episode_as_timeline_xml(epi, patient))

	if include_encounters:
		timeline.write(u'\n<!--\n========================================\n Encounters\n======================================== -->')
		for enc in emr.get_encounters(skip_empty = True):
			timeline.write(__format_encounter_as_timeline_xml(enc, patient))

	timeline.write('\n<!--\n========================================\n Hospital stays\n======================================== -->')
	for stay in emr.hospital_stays:
		timeline.write(__format_hospital_stay_as_timeline_xml(stay))

	timeline.write('\n<!--\n========================================\n Procedures\n======================================== -->')
	for proc in emr.performed_procedures:
		timeline.write(__format_procedure_as_timeline_xml(proc))

	if include_vaccinations:
		timeline.write(u'\n<!--\n========================================\n Vaccinations\n======================================== -->')
		for vacc in emr.vaccinations:
			timeline.write(__format_vaccination_as_timeline_xml(vacc))

	timeline.write('\n<!--\n========================================\n Substance intakes\n======================================== -->')
	for intake in emr.get_current_medications(include_inactive = True, include_unapproved = False):
		timeline.write(__format_intake_as_timeline_xml(intake))

	if include_documents:
		timeline.write(u'\n<!--\n========================================\n Documents\n======================================== -->')
		for doc in patient.document_folder.documents:
			timeline.write(__format_document_as_timeline_xml(doc))

	# allergies ?
	# - unclear where and how to place
	# test results ?
	# - too many events, at most "day sample drawn"

	# death
	if patient['deceased'] is None:
		end = now
	else:
		end = patient['deceased']
		timeline.write(__xml_encounter_template % (
			format_pydt(end),
			format_pydt(end),
			gmTools.u_dagger,
			_('Life events'),
			_('Death: %s') % format_pydt(end, format = '%Y %b %d %H:%M')
		))

	# display range
	if end.month == 2:
		if end.day == 29:
			# leap years aren't consecutive
			end = end.replace(day = 28)
	target_year = end.year + 1
	end = end.replace(year = target_year)
	timeline.write(xml_end % (
		format_pydt(start),
		format_pydt(end)
	))

	timeline.close()
	return timeline_fname
Example #41
0
def process_staged_single_PID_hl7_file(staged_item):

	log_name = gmTools.get_unique_filename (
		prefix = 'gm-staged_hl7_import-',
		suffix = '.log'
	)
	import_logger = logging.FileHandler(log_name)
	import_logger.setLevel(logging.DEBUG)
	root_logger = logging.getLogger('')
	root_logger.addHandler(import_logger)
	_log.debug('log file: %s', log_name)

	if not staged_item.lock():
		_log.error('cannot lock staged data for HL7 import')
		root_logger.removeHandler(import_logger)
		return False, log_name

	_log.debug('reference ID of staged HL7 data: %s', staged_item['external_data_id'])

	filename = staged_item.save_to_file()
	_log.debug('unstaged HL7 data into: %s', filename)

	if staged_item['pk_identity_disambiguated'] is None:
		emr = None
	else:
		emr = gmPerson.cPatient(staged_item['pk_identity_disambiguated']).emr

	success = False
	try:
		success = __import_single_PID_hl7_file(filename, emr = emr)
		if success:
			gmIncomingData.delete_incoming_data(pk_incoming_data = staged_item['pk_incoming_data_unmatched'])
			staged_item.unlock()
			root_logger.removeHandler(import_logger)
			return True, log_name
		_log.error('error when importing single-PID/single-MSH file')
	except Exception:
		_log.exception('error when importing single-PID/single-MSH file')

	if not success:
		staged_item['comment'] = _('failed import: %s\n') % gmDateTime.pydt_strftime(gmDateTime.pydt_now_here())
		staged_item['comment'] += '\n'
		staged_item['comment'] += ('-' * 80)
		staged_item['comment'] += '\n\n'
		log = io.open(log_name, mode = 'rt', encoding = 'utf8')
		staged_item['comment'] += log.read()
		log.close()
		staged_item['comment'] += '\n'
		staged_item['comment'] += ('-' * 80)
		staged_item['comment'] += '\n\n'
		staged_item['comment'] += format_hl7_file (
			filename,
			skip_empty_fields = True,
			eol = '\n ',
			return_filename = False
		)
		staged_item.save()

	staged_item.unlock()
	root_logger.removeHandler(import_logger)
	return success, log_name
Example #42
0
def create_gnumed_import_sql(filename):
	# CREATE TABLE patients (gender TEXT, doctor INTEGER, surname TEXT, ID INTEGER PRIMARY KEY, identification_code TEXT, phone TEXT, given_name TEXT, birth_date TEXT, residence_address TEXT);

	print u''
	print u'set default_transaction_read_only to off;'
	print u''
	print u"begin;"
	print u''

	now = gmDateTime.pydt_now_here().isoformat()

	clinica_db = sqlite.connect(database = filename)
	curs = clinica_db.cursor()
	cmd = u'select * from patients'
	curs.execute(cmd)
	keys = [ r[0] for r in curs.description ]
	row = curs.fetchone()

	if row is None:
		print "-- no patients in database"
		return

	row = sanitize_patient_row(dict(zip(keys, row)))
	print u'-- import-related encounter type'
	print u"INSERT INTO clin.encounter_type (description) SELECT '%s' WHERE NOT EXISTS (SELECT 1 FROM clin.encounter_type WHERE description = '%s' LIMIT 1);" % (
		Clinica_encounter_type,
		Clinica_encounter_type
	)

	while row is not None:
		print u''
		print u'-- next patient'
		print u"INSERT INTO dem.identity (gender, dob, comment) VALUES ('%s', NULL, 'Clinica import @ %s');" % (
			row['gender'],
			now
		)
		if row['birth_date'] is not None:
			if row['birth_date'].strip() != u'':
				print u"""UPDATE dem.identity SET dob = '%s'::timestamp with time zone WHERE pk = currval('dem.identity_pk_seq');""" % row['birth_date']
		print u"""SELECT dem.add_name(currval('dem.identity_pk_seq')::integer, '%s'::text, '%s'::text, True);""" % (
			row['given_name'],
			row['surname']
		)
		print u"""INSERT INTO dem.lnk_identity2ext_id (id_identity, external_id, fk_origin) VALUES (currval('dem.identity_pk_seq'), '%s', dem.add_external_id_type('Clinica primary key', 'Clinica EMR'));""" % row['ID']
		if row['identification_code'] is not None:
			print u"""INSERT INTO dem.lnk_identity2ext_id (id_identity, external_id, fk_origin) VALUES (currval('dem.identity_pk_seq'), '%s', dem.add_external_id_type('Clinica-external ID', 'Clinica EMR'));""" % row['identification_code']
		if row['phone'] is not None:
			print u"""INSERT INTO dem.lnk_identity2comm (fk_identity, url, fk_type) VALUES (currval('dem.identity_pk_seq'), '%s', dem.create_comm_type('homephone'));""" % row['phone']
		if row['residence_address'] is not None:
			print u"""INSERT INTO dem.lnk_identity2comm (fk_identity, url, fk_type) VALUES (currval('dem.identity_pk_seq'), '%s', dem.create_comm_type('Clinica address'));""" % row['residence_address']

		create_visit_sql(row['ID'], clinica_db)

		row = curs.fetchone()
		if row is not None:
			row = sanitize_patient_row(dict(zip(keys, row)))

	print u''
	print u'-- comment this out when you are ready to *really* run the data import:'
	print u'rollback;'
	print u''
	print u'commit;'
Example #43
0
def __import_single_PID_hl7_file(filename, emr=None):
	"""Assumes single-PID/single-MSH HL7 file."""

	_log.debug('importing single-PID single-MSH HL7 data from [%s]', filename)

	# read the file
	MSH_file = io.open(filename, mode = 'rt', encoding = 'utf8', newline = '')
	HL7 = pyhl7.parse(MSH_file.read(1024 * 1024 * 5))	# 5 MB max
	MSH_file.close()

	# sanity checks
	if len(HL7.segments('MSH')) != 1:
		_log.error('more than one MSH segment')
		return False
	if len(HL7.segments('PID')) != 1:
		_log.error('more than one PID segment')
		return False

	# ensure lab is in database
	hl7_lab = HL7.extract_field('MSH', field_num = MSH_field__sending_lab)
	gm_lab = __find_or_create_lab(hl7_lab)

	# ensure test types exist
	conn = gmPG2.get_connection(readonly = False)
	__ensure_hl7_test_types_exist_in_gnumed(link_obj = conn, hl7_data = HL7, pk_test_org = gm_lab['pk_test_org'])

	# find patient
	if emr is None:
		#PID = HL7.segment('PID')
		pats = __PID2dto(HL7 = HL7)
		if len(pats) == 0:
			conn.rollback()
			return False
		if len(pats) > 1:
			conn.rollback()
			return False
		emr = pats[0].emr

	# import values: loop over segments
	when_list = {}
	current_result = None
	previous_segment = None
	had_errors = False
	msh_seen = False
	pid_seen = False
	last_obr = None
	obr = {}
	for seg_idx in range(len(HL7)):
		seg = HL7[seg_idx]
		seg_type = seg[0][0]

		_log.debug('processing line #%s = segment of type <%s>', seg_idx, seg_type)

		if seg_type == 'MSH':
			msh_seen = True

		if seg_type == 'PID':
			if not msh_seen:
				conn.rollback()
				_log.error('PID segment before MSH segment')
				return False
			pid_seen = True

		if seg_type in ['MSH', 'PID']:
			_log.info('segment already handled')
			previous_segment = seg_type
			obr = {}
			current_result = None
			continue

		if seg_type in ['ORC']:
			_log.info('currently ignoring %s segments', seg_type)
			previous_segment = seg_type
			obr = {}
			current_result = None
			continue

		if seg_type == 'OBR':
			previous_segment = seg_type
			last_obr = seg
			current_result = None
			obr['abbrev'] = ('%s' % seg[OBR_field__service_name][0]).strip()
			try:
				obr['name'] = ('%s' % seg[OBR_field__service_name][1]).strip()
			except IndexError:
				obr['name'] = obr['abbrev']
			for field_name in [OBR_field__ts_ended, OBR_field__ts_started, OBR_field__ts_specimen_received, OBR_field__ts_requested]:
				obr['clin_when'] = seg[field_name][0].strip()
				if obr['clin_when'] != '':
					break
			continue

		if seg_type == 'OBX':
			current_result = None
			# determine value
			val_alpha = seg[OBX_field__value][0].strip()
			is_num, val_num = gmTools.input2decimal(initial = val_alpha)
			if is_num:
				val_alpha = None
			else:
				val_num = None
				val_alpha = val_alpha.replace('\.br\\', '\n')
			# determine test type
			unit = seg[OBX_field__unit][0].strip()
			if unit == '':
				if is_num:
					unit = '1/1'
				else:
					unit = None
			test_type = __find_or_create_test_type (
				loinc = '%s' % seg[OBX_field__type][0][OBX_component__loinc-1],
				name = '%s' % seg[OBX_field__type][0][OBX_component__name-1],
				pk_lab = gm_lab['pk_test_org'],
				unit = unit,
				link_obj = conn
			)
			# eventually, episode should be read from lab_request
			epi = emr.add_episode (
				link_obj = conn,
				episode_name = 'administrative',
				is_open = False,
				allow_dupes = False
			)
			current_result = emr.add_test_result (
				link_obj = conn,
				episode = epi['pk_episode'],
				type = test_type['pk_test_type'],
				intended_reviewer = gmStaff.gmCurrentProvider()['pk_staff'],
				val_num = val_num,
				val_alpha = val_alpha,
				unit = unit
			)
			# handle range information et al
			ref_range = seg[OBX_field__range][0].strip()
			if ref_range != '':
				current_result.reference_range = ref_range
			flag = seg[OBX_field__abnormal_flag][0].strip()
			if flag != '':
				current_result['abnormality_indicator'] = flag
			current_result['status'] = seg[OBX_field__status][0].strip()
			current_result['val_grouping'] = seg[OBX_field__subid][0].strip()
			current_result['source_data'] = ''
			if last_obr is not None:
				current_result['source_data'] += str(last_obr)
				current_result['source_data'] += '\n'
			current_result['source_data'] += str(seg)
			clin_when = seg[OBX_field__timestamp][0].strip()
			if clin_when == '':
				_log.warning('no <Observation timestamp> in OBX, trying OBR timestamp')
				clin_when = obr['clin_when']
			try:
				clin_when = __hl7dt2pydt(clin_when)
			except ValueError:
				_log.exception('clin_when from OBX or OBR not useable, assuming <today>')
			if clin_when is not None:
				current_result['clin_when'] = clin_when
			current_result.save(conn = conn)
			when_list[gmDateTime.pydt_strftime(current_result['clin_when'], '%Y %b %d')] = 1
			previous_segment = seg_type
			continue

		if seg_type == 'NTE':
			note = seg[NET_field__note][0].strip().replace('\.br\\', '\n')
			if note == '':
				_log.debug('empty NTE segment')
				previous_segment = seg_type			# maybe not ? (HL7 providers happen to use empty NTE segments to "structure" raw HL7 |-)
				continue

			# if this is an NTE following an OBR (IOW an order-related
			# comment): make this a test result all of its own :-)
			if previous_segment == 'OBR':
				_log.debug('NTE following OBR: general note, using OBR timestamp [%s]', obr['clin_when'])
				current_result = None
				name = obr['name']
				if name == '':
					name = _('Comment')
				# FIXME: please suggest a LOINC for "order comment"
				test_type = __find_or_create_test_type(name = name, pk_lab = gm_lab['pk_test_org'], abbrev = obr['abbrev'], link_obj = conn)
				# eventually, episode should be read from lab_request
				epi = emr.add_episode (
					link_obj = conn,
					episode_name = 'administrative',
					is_open = False,
					allow_dupes = False
				)
				nte_result = emr.add_test_result (
					link_obj = conn,
					episode = epi['pk_episode'],
					type = test_type['pk_test_type'],
					intended_reviewer = gmStaff.gmCurrentProvider()['pk_staff'],
					val_alpha = note
				)
				#nte_result['val_grouping'] = seg[OBX_field__subid][0].strip()
				nte_result['source_data'] = str(seg)
				try:
					nte_result['clin_when'] = __hl7dt2pydt(obr['clin_when'])
				except ValueError:
					_log.exception('no .clin_when from OBR for NTE pseudo-OBX available')
				nte_result.save(conn = conn)
				continue

			if (previous_segment == 'OBX') and (current_result is not None):
				current_result['source_data'] += '\n'
				current_result['source_data'] += str(seg)
				current_result['note_test_org'] = gmTools.coalesce (
					current_result['note_test_org'],
					note,
					'%%s\n%s' % note
				)
				current_result.save(conn = conn)
				previous_segment = seg_type
				continue

			_log.error('unexpected NTE segment')
			had_errors = True
			break

		_log.error('unknown segment, aborting')
		_log.debug('line: %s', seg)
		had_errors = True
		break

	if had_errors:
		conn.rollback()
		return False

	conn.commit()

	# record import in chart
	try:
		no_results = len(HL7.segments('OBX'))
	except KeyError:
		no_results = '?'
	soap = _(
		'Imported HL7 file [%s]:\n'
		' lab "%s" (%s@%s), %s results (%s)'
	) % (
		filename,
		hl7_lab,
		gm_lab['unit'],
		gm_lab['organization'],
		no_results,
		' / '.join(list(when_list))
	)
	epi = emr.add_episode (
		episode_name = 'administrative',
		is_open = False,
		allow_dupes = False
	)
	emr.add_clin_narrative (
		note = soap,
		soap_cat = None,
		episode = epi
	)

	# keep copy of HL7 data in document archive
	folder = gmPerson.cPatient(emr.pk_patient).document_folder
	hl7_docs = folder.get_documents (
		doc_type = 'HL7 data',
		pk_episodes = [epi['pk_episode']],
		order_by = 'ORDER BY clin_when DESC'
	)
	if len(hl7_docs) > 0:
		# there should only ever be one unless the user manually creates more,
		# also, it should always be the latest since "ORDER BY clin_when DESC"
		hl7_doc = hl7_docs[0]
	else:
		hl7_doc = folder.add_document (
			document_type = 'HL7 data',
			encounter = emr.active_encounter['pk_encounter'],
			episode = epi['pk_episode']
		)
		hl7_doc['comment'] = _('list of imported HL7 data files')
		hl7_doc['pk_org_unit'] = gmPraxis.gmCurrentPraxisBranch()['pk_org_unit']
	hl7_doc['clin_when'] = gmDateTime.pydt_now_here()
	hl7_doc.save()
	part = hl7_doc.add_part(file = filename)
	part['obj_comment'] = _('Result dates: %s') % ' / '.join(list(when_list))
	part.save()
	hl7_doc.set_reviewed(technically_abnormal = False, clinically_relevant = False)

	return True
Example #44
0
	def center_at_today(self):
		now = gmDateTime.pydt_now_here()
		g_now = GregorianDateTime(now.year, now.month, now.day, now.hour, now.minute, now.second).to_time()
		self.Navigate(lambda tp: tp.center(g_now))
Example #45
0
File: gmHL7.py Project: sk/gnumed
def __import_single_PID_hl7_file(filename, emr=None):
	"""Assumes single-PID/single-MSH HL7 file."""

	_log.debug('importing single-PID single-MSH HL7 data from [%s]', filename)

	# read the file
	MSH_file = io.open(filename, mode = 'rt', encoding = 'utf8')
	HL7 = pyhl7.parse(MSH_file.read(1024 * 1024 * 5))	# 5 MB max
	MSH_file.close()

	# sanity checks
	if len(HL7.segments('MSH')) != 1:
		_log.error('more than one MSH segment')
		return False
	if len(HL7.segments('PID')) != 1:
		_log.error('more than one PID segment')
		return False

	# ensure lab is in database
	hl7_lab = HL7.extract_field('MSH', field_num = MSH_field__sending_lab)
	gm_lab = __find_or_create_lab(hl7_lab)

	# ensure test types exist
	conn = gmPG2.get_connection(readonly = False)
	__ensure_hl7_test_types_exist_in_gnumed(link_obj = conn, hl7_data = HL7, pk_test_org = gm_lab['pk_test_org'])

	# find patient
	if emr is None:
		#PID = HL7.segment('PID')
		pats = __PID2dto(HL7 = HL7)
		if len(pats) == 0:
			conn.rollback()
			return False
		if len(pats) > 1:
			conn.rollback()
			return False
		emr = pats[0].emr

	# import values: loop over segments
	when_list = {}
	current_result = None
	previous_segment = None
	had_errors = False
	msh_seen = False
	pid_seen = False
	last_obr = None
	obr = {}
	for seg_idx in range(len(HL7)):
		seg = HL7[seg_idx]
		seg_type = seg[0][0]

		_log.debug('processing line #%s = segment of type <%s>', seg_idx, seg_type)

		if seg_type == u'MSH':
			msh_seen = True

		if seg_type == u'PID':
			if not msh_seen:
				conn.rollback()
				_log.error('PID segment before MSH segment')
				return False
			pid_seen = True

		if seg_type in [u'MSH', u'PID']:
			_log.info('segment already handled')
			previous_segment = seg_type
			obr = {}
			current_result = None
			continue

		if seg_type in [u'ORC']:
			_log.info('currently ignoring %s segments', seg_type)
			previous_segment = seg_type
			obr = {}
			current_result = None
			continue

		if seg_type == u'OBR':
			previous_segment = seg_type
			last_obr = seg
			current_result = None
			obr['abbrev'] = (u'%s' % seg[OBR_field__service_name][0]).strip()
			try:
				obr['name'] = (u'%s' % seg[OBR_field__service_name][1]).strip()
			except IndexError:
				obr['name'] = obr['abbrev']
			for field_name in [OBR_field__ts_ended, OBR_field__ts_started, OBR_field__ts_specimen_received, OBR_field__ts_requested]:
				obr['clin_when'] = seg[field_name][0].strip()
				if obr['clin_when'] != u'':
					break
			continue

		if seg_type == u'OBX':
			current_result = None
			# determine value
			val_alpha = seg[OBX_field__value][0].strip()
			is_num, val_num = gmTools.input2decimal(initial = val_alpha)
			if is_num:
				val_alpha = None
			else:
				val_num = None
				val_alpha = val_alpha.replace('\.br\\', u'\n')
			# determine test type
			unit = seg[OBX_field__unit][0].strip()
			if unit == u'':
				if is_num:
					unit = u'1/1'
				else:
					unit = None
			test_type = __find_or_create_test_type (
				loinc = u'%s' % seg[OBX_field__type][0][OBX_component__loinc-1],
				name = u'%s' % seg[OBX_field__type][0][OBX_component__name-1],
				pk_lab = gm_lab['pk_test_org'],
				unit = unit
			)
			# eventually, episode should be read from lab_request
			epi = emr.add_episode (
				link_obj = conn,
				episode_name = u'administrative',
				is_open = False,
				allow_dupes = False
			)
			current_result = emr.add_test_result (
				link_obj = conn,
				episode = epi['pk_episode'],
				type = test_type['pk_test_type'],
				intended_reviewer = gmStaff.gmCurrentProvider()['pk_staff'],
				val_num = val_num,
				val_alpha = val_alpha,
				unit = unit
			)
			# handle range information et al
			ref_range = seg[OBX_field__range][0].strip()
			if ref_range != u'':
				current_result.reference_range = ref_range
			flag = seg[OBX_field__abnormal_flag][0].strip()
			if flag != u'':
				current_result['abnormality_indicator'] = flag
			current_result['status'] = seg[OBX_field__status][0].strip()
			current_result['val_grouping'] = seg[OBX_field__subid][0].strip()
			current_result['source_data'] = u''
			if last_obr is not None:
				current_result['source_data'] += unicode(last_obr)
				current_result['source_data'] += u'\n'
			current_result['source_data'] += unicode(seg)
			clin_when = seg[OBX_field__timestamp][0].strip()
			if clin_when == u'':
				_log.warning('no <Observation timestamp> in OBX, trying OBR timestamp')
				clin_when = obr['clin_when']
			try:
				clin_when = __hl7dt2pydt(clin_when)
			except ValueError:
				_log.exception('clin_when from OBX or OBR not useable, assuming <today>')
			if clin_when is not None:
				current_result['clin_when'] = clin_when
			current_result.save(conn = conn)
			when_list[gmDateTime.pydt_strftime(current_result['clin_when'], '%Y %b %d')] = 1
			previous_segment = seg_type
			continue

		if seg_type == u'NTE':
			note = seg[NET_field__note][0].strip().replace('\.br\\', u'\n')
			if note == u'':
				_log.debug('empty NTE segment')
				previous_segment = seg_type			# maybe not ? (HL7 providers happen to use empty NTE segments to "structure" raw HL7 |-)
				continue

			# if this is an NTE following an OBR (IOW an order-related
			# comment): make this a test result all of its own :-)
			if previous_segment == u'OBR':
				_log.debug('NTE following OBR: general note, using OBR timestamp [%s]', obr['clin_when'])
				current_result = None
				name = obr['name']
				if name == u'':
					name = _('Comment')
				# FIXME: please suggest a LOINC for "order comment"
				test_type = __find_or_create_test_type(name = name, pk_lab = gm_lab['pk_test_org'], abbrev = obr['abbrev'])
				# eventually, episode should be read from lab_request
				epi = emr.add_episode (
					link_obj = conn,
					episode_name = u'administrative',
					is_open = False,
					allow_dupes = False
				)
				nte_result = emr.add_test_result (
					link_obj = conn,
					episode = epi['pk_episode'],
					type = test_type['pk_test_type'],
					intended_reviewer = gmStaff.gmCurrentProvider()['pk_staff'],
					val_alpha = note
				)
				#nte_result['val_grouping'] = seg[OBX_field__subid][0].strip()
				nte_result['source_data'] = unicode(seg)
				try:
					nte_result['clin_when'] = __hl7dt2pydt(obr['clin_when'])
				except ValueError:
					_log.exception('no .clin_when from OBR for NTE pseudo-OBX available')
				nte_result.save(conn = conn)
				continue

			if (previous_segment == u'OBX') and (current_result is not None):
				current_result['source_data'] += u'\n'
				current_result['source_data'] += unicode(seg)
				current_result['note_test_org'] = gmTools.coalesce (
					current_result['note_test_org'],
					note,
					u'%%s\n%s' % note
				)
				current_result.save(conn = conn)
				previous_segment = seg_type
				continue

			_log.error(u'unexpected NTE segment')
			had_errors = True
			break

		_log.error('unknown segment, aborting')
		_log.debug('line: %s', seg)
		had_errors = True
		break

	if had_errors:
		conn.rollback()
		return False

	conn.commit()

	# record import in chart
	try:
		no_results = len(HL7.segments('OBX'))
	except KeyError:
		no_results = u'?'
	soap = _(
		'Imported HL7 file [%s]:\n'
		' lab "%s" (%s@%s), %s results (%s)'
	) % (
		filename,
		hl7_lab,
		gm_lab['unit'],
		gm_lab['organization'],
		no_results,
		u' / '.join(when_list.keys())
	)
	epi = emr.add_episode (
		episode_name = u'administrative',
		is_open = False,
		allow_dupes = False
	)
	emr.add_clin_narrative (
		note = soap,
		soap_cat = None,
		episode = epi
	)

	# keep copy of HL7 data in document archive
	folder = gmPerson.cPatient(emr.pk_patient).document_folder
	hl7_docs = folder.get_documents (
		doc_type = u'HL7 data',
		episodes = [epi['pk_episode']],
		order_by = u'ORDER BY clin_when DESC'
	)
	if len(hl7_docs) > 0:
		# there should only ever be one unless the user manually creates more,
		# also, it should always be the latest since "ORDER BY clin_when DESC"
		hl7_doc = hl7_docs[0]
	else:
		hl7_doc = folder.add_document (
			document_type = u'HL7 data',
			encounter = emr.active_encounter['pk_encounter'],
			episode = epi['pk_episode']
		)
		hl7_doc['comment'] = _('list of imported HL7 data files')
	hl7_doc['clin_when'] = gmDateTime.pydt_now_here()
	hl7_doc.save()
	part = hl7_doc.add_part(file = filename)
	part['obj_comment'] = _('Result dates: %s') % u' / '.join(when_list.keys())
	part.save()
	hl7_doc.set_reviewed(technically_abnormal = False, clinically_relevant = False)

	return True
Example #46
0
class cExportArea(object):
    def __init__(self, pk_identity):
        self.__pk_identity = pk_identity

    #--------------------------------------------------------
    def add_form(self, form=None, designation=None):

        if len(form.final_output_filenames) == 0:
            return True

        items = []
        for fname in form.final_output_filenames:
            item = self.add_file(filename=fname)
            if item is None:
                for prev_item in items:
                    delete_export_item(
                        pk_export_item=prev_item['pk_export_item'])
                return False
            items.append(item)
            item['description'] = _(u'form: %s %s (%s)') % (
                form.template['name_long'], form.template['external_version'],
                fname)
            item['designation'] = designation
            item.save()

        return True

    #--------------------------------------------------------
    def add_forms(self, forms=None, designation=None):
        all_ok = True
        for form in forms:
            all_ok = all_ok and self.add_form(form=form,
                                              designation=designation)

        return all_ok

    #--------------------------------------------------------
    def add_file(self, filename=None, hint=None):
        try:
            open(filename).close()
        except Exception:
            _log.exception('cannot open file <%s>', filename)
            return None

        file_md5 = gmTools.file2md5(filename=filename, return_hex=True)
        existing_item = self.md5_exists(md5=file_md5,
                                        include_document_parts=False)
        if existing_item is not None:
            _log.debug('md5 match (%s): %s already in export area', file_md5,
                       filename)
            return existing_item

        path, basename = os.path.split(filename)
        item = create_export_item(
            description=u'%s: %s (%s/)' %
            (gmTools.coalesce(hint, _(u'file'), u'%s'), basename, path),
            pk_identity=self.__pk_identity,
            filename=filename)

        if item.update_data_from_file(filename=filename):
            return item

        delete_export_item(pk_export_item=item['pk_export_item'])
        return None

    #--------------------------------------------------------
    def add_files(self, filenames=None, hint=None):
        all_ok = True
        for fname in filenames:
            all_ok = all_ok and (self.add_file(filename=fname, hint=hint)
                                 is not None)

        return all_ok

    #--------------------------------------------------------
    def add_documents(self, documents=None):
        for doc in documents:
            doc_tag = _(u'%s (%s)%s') % (
                doc['l10n_type'],
                gmDateTime.pydt_strftime(doc['clin_when'], '%Y %b %d'),
                gmTools.coalesce(doc['comment'], u'', u' "%s"'))
            for obj in doc.parts:
                if self.document_part_item_exists(pk_part=obj['pk_obj']):
                    continue
                f_ext = u''
                if obj['filename'] is not None:
                    f_ext = os.path.splitext(
                        obj['filename'])[1].strip('.').strip()
                if f_ext != u'':
                    f_ext = u' .' + f_ext.upper()
                obj_tag = _(u'part %s (%s%s)%s') % (
                    obj['seq_idx'], gmTools.size2str(obj['size']), f_ext,
                    gmTools.coalesce(obj['obj_comment'], u'', u' "%s"'))
                create_export_item(description=u'%s - %s' % (doc_tag, obj_tag),
                                   pk_doc_obj=obj['pk_obj'])

    #--------------------------------------------------------
    def document_part_item_exists(self, pk_part=None):
        cmd = u"SELECT EXISTS (SELECT 1 FROM clin.export_item WHERE fk_doc_obj = %(pk_obj)s)"
        args = {'pk_obj': pk_part}
        rows, idx = gmPG2.run_ro_queries(queries=[{
            'cmd': cmd,
            'args': args
        }],
                                         get_col_idx=False)
        return rows[0][0]

    #--------------------------------------------------------
    def md5_exists(self, md5=None, include_document_parts=False):
        where_parts = [u'pk_identity = %(pat)s', u'md5_sum = %(md5)s']
        args = {'pat': self.__pk_identity, 'md5': md5}

        if not include_document_parts:
            where_parts.append(u'pk_doc_obj IS NULL')

        cmd = _SQL_get_export_items % u' AND '.join(where_parts)
        rows, idx = gmPG2.run_ro_queries(queries=[{
            'cmd': cmd,
            'args': args
        }],
                                         get_col_idx=True)

        if len(rows) == 0:
            return None

        r = rows[0]
        return cExportItem(row={
            'data': r,
            'idx': idx,
            'pk_field': 'pk_export_item'
        })

    #--------------------------------------------------------
    def dump_items_to_disk(self, base_dir=None, items=None):
        if items is None:
            items = self.items

        if len(items) == 0:
            return None

        if base_dir is None:
            from Gnumed.business.gmPerson import cPatient
            pat = cPatient(aPK_obj=self.__pk_identity)
            base_dir = gmTools.mk_sandbox_dir(prefix=u'exp-%s-' % pat.dirname)
        _log.debug('dumping export items to: %s', base_dir)

        gmTools.mkdir(base_dir)
        for item in items:
            item.save_to_file(directory=base_dir)
        return base_dir

    #--------------------------------------------------------
    def export(self, base_dir=None, items=None, expand_compressed=False):

        if items is None:
            items = self.items

        if len(items) == 0:
            return None

        media_base_dir = base_dir

        from Gnumed.business.gmPerson import cPatient
        pat = cPatient(aPK_obj=self.__pk_identity)
        if media_base_dir is None:
            media_base_dir = gmTools.mk_sandbox_dir(prefix=u'exp-%s-' %
                                                    pat.dirname)
        _log.debug('patient media base dir: %s', media_base_dir)

        doc_dir = os.path.join(media_base_dir, r'documents')
        if os.path.isdir(doc_dir):
            index_existing_docs = True
        else:
            index_existing_docs = False
            gmTools.mkdir(doc_dir)

        _html_start_data = {
            u'html_title_header':
            _('Patient data for'),
            u'html_title_patient':
            gmTools.html_escape_string(
                pat.get_description_gender(with_nickname=False) + u', ' +
                _(u'born') + u' ' + pat.get_formatted_dob('%Y %B %d')),
            u'title':
            _('Patient data export'),
            u'pat_name':
            gmTools.html_escape_string(
                pat.get_description_gender(with_nickname=False)),
            u'pat_dob':
            gmTools.html_escape_string(
                _(u'born') + u' ' + pat.get_formatted_dob('%Y %B %d')),
            u'mugshot_url':
            u'documents/no-such-file.png',
            u'mugshot_alt':
            _('no patient photograph available'),
            u'mugshot_title':
            u'',
            u'docs_title':
            _(u'Documents'),
            u'browse_root':
            _(u'browse storage medium'),
            u'browse_docs':
            _(u'browse documents area'),
            u'browse_dicomdir':
            u'',
            u'run_dicom_viewer':
            u''
        }

        mugshot = pat.document_folder.latest_mugshot
        if mugshot is not None:
            _html_start_data['mugshot_url'] = mugshot.save_to_file(
                directory=doc_dir, adjust_extension=True)
            _html_start_data['mugshot_alt'] = _(
                'patient photograph from %s') % gmDateTime.pydt_strftime(
                    mugshot['date_generated'], '%B %Y')
            _html_start_data['mugshot_title'] = gmDateTime.pydt_strftime(
                mugshot['date_generated'], '%B %Y')

        if u'DICOMDIR' in os.listdir(media_base_dir):
            _html_start_data[
                u'browse_dicomdir'] = u'<li><a href="./DICOMDIR">%s</a></li>' % _(
                    u'show DICOMDIR file')
            # copy DWV into target dir
            dwv_target_dir = os.path.join(media_base_dir, u'dwv')
            gmTools.rmdir(dwv_target_dir)
            dwv_src_dir = os.path.join(gmTools.gmPaths().local_base_dir,
                                       u'dwv4export')
            if not os.path.isdir(dwv_src_dir):
                dwv_src_dir = os.path.join(
                    gmTools.gmPaths().system_app_data_dir, u'dwv4export')
            try:
                shutil.copytree(dwv_src_dir, dwv_target_dir)
                _html_start_data[
                    u'run_dicom_viewer'] = u'<li><a href="./dwv/viewers/mobile-local/index.html">%s</a></li>' % _(
                        u'run Radiology Images (DICOM) Viewer')
            except shutil.Error, OSError:
                _log.exception('cannot include DWV, skipping')

        # index.html
        # - header
        idx_fname = os.path.join(media_base_dir, u'index.html')
        idx_file = io.open(idx_fname, mode=u'wt', encoding=u'utf8')
        idx_file.write(_html_start % _html_start_data)
        # - middle (side effect ! -> exports items into files ...)
        existing_docs = os.listdir(
            doc_dir
        )  # get them now, or else we will include the to-be-exported items
        # - export items
        for item in items:
            item_path = item.save_to_file(directory=doc_dir)
            item_fname = os.path.split(item_path)[1]
            idx_file.write(
                _html_list_item %
                (item_fname, gmTools.html_escape_string(item['description'])))
        # - preexisting documents
        for doc_fname in existing_docs:
            idx_file.write(
                _html_list_item %
                (doc_fname,
                 gmTools.html_escape_string(_(u'other: %s') % doc_fname)))
        # - footer
        _cfg = gmCfg2.gmCfgData()
        from Gnumed.business.gmPraxis import gmCurrentPraxisBranch
        prax = gmCurrentPraxisBranch()
        lines = []
        adr = prax.branch.org_unit.address
        if adr is not None:
            lines.extend(adr.format())
        for comm in prax.branch.org_unit.comm_channels:
            if comm['is_confidential'] is True:
                continue
            lines.append(u'%s: %s' % (comm['l10n_comm_type'], comm['url']))
        adr = u''
        if len(lines) > 0:
            adr = gmTools.html_escape_string(u'\n'.join(lines),
                                             replace_eol=True,
                                             keep_visual_eol=True)
        _html_end_data = {
            'branch':
            gmTools.html_escape_string(prax['branch']),
            'praxis':
            gmTools.html_escape_string(prax['praxis']),
            'date':
            gmTools.html_escape_string(
                gmDateTime.pydt_strftime(gmDateTime.pydt_now_here(),
                                         format='%Y %B %d',
                                         encoding=u'utf8')),
            'gm_ver':
            gmTools.html_escape_string(_cfg.get(option=u'client_version')),
            #'gm_ver': 'git HEAD',				# for testing
            'adr':
            adr
        }
        idx_file.write(_html_end % _html_end_data)
        idx_file.close()

        # start.html (just a copy of index.html, really ;-)
        start_fname = os.path.join(media_base_dir, u'start.html')
        try:
            shutil.copy2(idx_fname, start_fname)
        except Exception:
            _log.exception('cannot copy %s to %s', idx_fname, start_fname)

        # autorun.inf
        # - compute label
        autorun_dict = {}
        name = pat.active_name
        last = name['lastnames'][:14]
        first = name['firstnames'][:min(14, 18 - len(last))]
        autorun_dict['label'] = (
            (u'%s%s%s' %
             (u'%s,%s' %
              (last, first), gmTools.coalesce(pat['gender'], u'', u' (%s)'),
              pat.get_formatted_dob(format=' %Y%m%d',
                                    none_string=u'',
                                    honor_estimation=False))).strip()
        )[:
          32]  # max 32 chars, supposedly ASCII, but CP1252 likely works pretty well
        # - compute icon
        media_icon_kwd = u'$$gnumed_patient_media_export_icon'
        media_icon_kwd_exp = gmKeywordExpansion.get_expansion(
            keyword=media_icon_kwd, textual_only=False, binary_only=True)
        icon_tmp_file = media_icon_kwd_exp.save_to_file(
            target_mime=u'image/x-icon',
            target_extension=u'.ico',
            ignore_conversion_problems=True)
        autorun_dict['icon'] = u''
        if icon_tmp_file is None:
            _log.debug(u'cannot retrieve <%s>', media_icon_kwd)
        else:
            media_icon_fname = os.path.join(media_base_dir, u'gnumed.ico')
            try:
                shutil.move(icon_tmp_file, media_icon_fname)
                autorun_dict['icon'] = u'icon=gnumed.ico'
            except Exception:
                _log.exception('cannot move %s to %s', icon_tmp_file,
                               media_icon_fname)
        # - compute action
        autorun_dict['action'] = _('Browse patient data')
        # - create file
        autorun_fname = os.path.join(media_base_dir, u'autorun.inf')
        autorun_file = io.open(autorun_fname,
                               mode='wt',
                               encoding='cp1252',
                               errors='replace')
        autorun_file.write(_autorun_inf % autorun_dict)
        autorun_file.close()

        # cd.inf
        cd_inf_fname = os.path.join(media_base_dir, u'cd.inf')
        cd_inf_file = io.open(cd_inf_fname, mode=u'wt', encoding=u'utf8')
        cd_inf_file.write(
            _cd_inf %
            (pat['lastnames'], pat['firstnames'],
             gmTools.coalesce(pat['gender'],
                              u'?'), pat.get_formatted_dob('%Y-%m-%d'),
             gmDateTime.pydt_strftime(gmDateTime.pydt_now_here(),
                                      format='%Y-%m-%d',
                                      encoding=u'utf8'), pat.ID,
             _cfg.get(option=u'client_version'), u' / '.join([
                 u'%s = %s (%s)' % (g['tag'], g['label'], g['l10n_label'])
                 for g in pat.gender_list
             ])))
        cd_inf_file.close()

        # README
        readme_fname = os.path.join(media_base_dir, u'README')
        readme_file = io.open(readme_fname, mode=u'wt', encoding=u'utf8')
        readme_file.write(
            _README %
            (pat.get_description_gender(with_nickname=False) + u', ' +
             _(u'born') + u' ' + pat.get_formatted_dob('%Y %B %d')))
        readme_file.close()

        # patient demographics as GDT/XML/VCF
        pat.export_as_gdt(
            filename=os.path.join(media_base_dir, u'patient.gdt'))
        pat.export_as_xml_linuxmednews(
            filename=os.path.join(media_base_dir, u'patient.xml'))
        pat.export_as_vcard(
            filename=os.path.join(media_base_dir, u'patient.vcf'))

        # praxis VCF
        shutil.move(prax.vcf, os.path.join(media_base_dir, u'praxis.vcf'))

        return media_base_dir
Example #47
0
	def fit_last_year(self):
		end = gmDateTime.pydt_now_here()
		g_end = GregorianDateTime(end.year, end.month, end.day, end.hour, end.minute, end.second).to_time()
		g_start = GregorianDateTime(end.year - 1, end.month, end.day, end.hour, end.minute, end.second).to_time()
		last_year = TimePeriod(g_start, g_end)
		self.Navigate(lambda tp: tp.update(last_year.start_time, last_year.end_time))
Example #48
0
	def _get_body_mass_index(self):

		try:
			return self.__cache['body_mass_index']
		except KeyError:
			pass

		result = cClinicalResult(_('unknown BMI'))
		result.formula_name = 'BMI/Quetelet Index'
		result.formula_source = '08/2014: https://en.wikipedia.org/wiki/Body_mass_index'

		if self.__patient is None:
			result.message = _('BMI: no patient')
			return result

		result.variables['height'] = self.__patient.emr.get_most_recent_results_in_loinc_group(loincs = gmLOINC.LOINC_height, no_of_results = 1)
		if result.variables['height'] is None:
			result.message = _('BMI: height not found')
			return result
		if result.variables['height']['val_num'] is None:
			result.message = _('BMI: height not numeric')
			return result
		if result.variables['height']['val_unit'] == 'cm':
			result.variables['height_m'] = self.d(result.variables['height']['val_num'] / self.d(100))
		elif result.variables['height']['val_unit'] == 'mm':
			result.variables['height_m'] = self.d(result.variables['height']['val_num'] / self.d(1000))
		elif result.variables['height']['val_unit'] == 'm':
			result.variables['height_m'] = self.d(result.variables['height']['val_num'])
		else:
			result.message = _('BMI: height not in m, cm, or mm')
			return result

		result.variables['weight'] = self.__patient.emr.get_result_at_timestamp (
			timestamp = result.variables['height']['clin_when'],
			loinc = gmLOINC.LOINC_weight,
			tolerance_interval = '10 days'
		)
		if result.variables['weight'] is None:
			result.message = _('BMI: weight not found')
			return result
		if result.variables['weight']['val_num'] is None:
			result.message = _('BMI: weight not numeric')
			return result
		if result.variables['weight']['val_unit'] == 'kg':
			result.variables['weight_kg'] = self.d(result.variables['weight']['val_num'])
		elif result.variables['weight']['val_unit'] == 'g':
			result.variables['weight_kg'] = self.d(result.variables['weight']['val_num'] / self.d(1000))
		else:
			result.message = _('BMI: weight not in kg or g')
			return result

		result.variables['dob'] = self.__patient['dob']
		start = result.variables['dob']
		end = result.variables['height']['clin_when']
		multiplier = 1
		if end < start:
			start = result.variables['height']['clin_when']
			end = result.variables['dob']
			multiplier = -1
		result.variables['age@height'] = multiplier * self.d(gmDateTime.calculate_apparent_age(start, end)[0])
		if (result.variables['age@height'] < 18):
			result.message = _('BMI (Quetelet): formula does not apply at age [%s] (0 < age < 18)') % result.variables['age@height']
			return result

		# bmi = mass kg / height m2
		result.numeric_value = result.variables['weight_kg'] / (result.variables['height_m'] * result.variables['height_m'])
		result.unit = 'kg/m²'

		result.message = _('BMI (Quetelet): %.2f %s') % (
			result.numeric_value,
			result.unit
		)
		result.date_valid = gmDateTime.pydt_now_here()

		self.__cache['body_mass_index'] = result
		_log.debug('%s' % result)

		return result
Example #49
0
	def __refresh_history(self, patient=None):
		emr = patient.emr

		sort_key_list = []
		date_format4sorting = '%Y %m %d %H %M %S'
		now = gmDateTime.pydt_now_here()
		data = {}

		# undated entries
		# pregnancy
		edc = emr.EDC
		if edc is not None:
			sort_key = '99999 edc'
			if emr.EDC_is_fishy:
				label = _('EDC (!?!): %s') % gmDateTime.pydt_strftime(edc, format = '%Y %b %d')
				tt = _(
					'The Expected Date of Confinement is rather questionable.\n'
					'\n'
					'Please check patient age, patient gender, time until/since EDC.'
				)
			else:
				label = _('EDC: %s') % gmDateTime.pydt_strftime(edc, format = '%Y %b %d')
				tt = ''
			sort_key_list.append(sort_key)
			data[sort_key] = [label, tt]

		# family history
		fhxs = emr.get_family_history()
		for fhx in fhxs:
			sort_key = '99998 %s::%s' % (fhx['l10n_relation'], fhx['pk_family_history'])
			sort_key_list.append(sort_key)
			#gmDateTime.pydt_strftime(fhx['when_known_to_patient'], format = '%Y %m %d %H %M %S')
			label = '%s%s: %s' % (fhx['l10n_relation'], gmTools.coalesce(fhx['age_noted'], '', ' (@ %s)'), fhx['condition'])
			data[sort_key] = [label, fhx]
		del fhxs

		# dated entries
		issues = [
			i for i in emr.get_health_issues()
			if ((i['clinically_relevant'] is False) or (i['is_active'] is False))
		]
		for issue in issues:
			last_encounter = emr.get_last_encounter(issue_id = issue['pk_health_issue'])
			linked_encounter = gmEMRStructItems.cEncounter(issue['pk_encounter'])
			when_candidates = [issue['modified_when'], linked_encounter['last_affirmed']]
			if last_encounter is not None:
				when_candidates.append(last_encounter['last_affirmed'])
			if (patient['dob'] is not None) and (issue['age_noted'] is not None):
				when_candidates.append(patient['dob'] + issue['age_noted'])
			if issue['is_active']:
				# sort active issues by time of most recent clinical access, which
				# means the most recent of:
				# issue.modified_when
				# last_encounter.last_affirmed
				# linked_encounter.last_affirmed
				# dob + age
				relevant_date = max(when_candidates)
			else:
				# sort IN-active issues by best guess of real clinical start
				# means either:
				# - dob + age
				# or the earliest of:
				# - issue.modified_when
				# - last_encounter.last_affirmed
				# - linked_encounter.last_affirmed
				if (patient['dob'] is not None) and (issue['age_noted'] is not None):
					relevant_date = patient['dob'] + issue['age_noted']
				else:
					relevant_date = min(when_candidates)
			sort_key = '%s::%s' % (gmDateTime.pydt_strftime(relevant_date, format = date_format4sorting), issue['pk_health_issue'])
			relevant_date_str = gmDateTime.pydt_strftime(relevant_date, format = '%Y %b')
			if issue['age_noted'] is None:
				encounter = gmEMRStructItems.cEncounter(issue['pk_encounter'])
				age = _(' (entered %s ago)') % gmDateTime.format_interval_medically(now - encounter['started'])
			else:
				age = ' (@ %s)' % gmDateTime.format_interval_medically(issue['age_noted'])
			sort_key_list.append(sort_key)
			data[sort_key] = ['%s %s%s' % (relevant_date_str, issue['description'], age), issue]
		del issues

		stays = emr.get_hospital_stays()
		for stay in stays:
			sort_key = '%s::%s' % (gmDateTime.pydt_strftime(stay['admission'], format = date_format4sorting), stay['pk_hospital_stay'])
			label = '%s %s: %s (%s)' % (
				gmDateTime.pydt_strftime(stay['admission'], format = '%Y %b'),
				stay['hospital'],
				stay['episode'],
				_('%s ago') % gmDateTime.format_interval_medically(now - stay['admission'])
			)
			sort_key_list.append(sort_key)
			data[sort_key] = [label, stay]
		del stays

		procs = emr.get_performed_procedures()
		for proc in procs:
			sort_key = '%s::%s' % (gmDateTime.pydt_strftime(proc['clin_when'], format = date_format4sorting), proc['pk_procedure'])
			label = '%s%s %s (%s @ %s)' % (
				gmDateTime.pydt_strftime(proc['clin_when'], format = '%Y %b'),
				gmTools.bool2subst(proc['is_ongoing'], gmTools.u_ellipsis, '', ''),
				proc['performed_procedure'],
				_('%s ago') % gmDateTime.format_interval_medically(now - proc['clin_when']),
				gmDateTime.format_interval_medically(proc['clin_when'] - patient['dob'])
			)
			sort_key_list.append(sort_key)
			data[sort_key] = [label, proc]
		del procs

		vaccs = emr.get_latest_vaccinations()
		for ind, tmp in vaccs.items():
			no_of_shots, vacc = tmp
			sort_key = '%s::%s::%s' % (gmDateTime.pydt_strftime(vacc['date_given'], format = date_format4sorting), vacc['pk_vaccination'], ind)
			label = _('%s Vacc: %s (latest of %s: %s ago)') % (
				gmDateTime.pydt_strftime(vacc['date_given'], format = '%Y %b'),
				ind,
				no_of_shots,
				gmDateTime.format_interval_medically(now - vacc['date_given'])
			)
			sort_key_list.append(sort_key)
			data[sort_key] = [label, vacc]
		del vaccs

		for abuse in [ a for a in emr.abused_substances if a['harmful_use_type'] == 3 ]:
			sort_key = '%s::%s' % (gmDateTime.pydt_strftime(abuse['last_checked_when'], format = date_format4sorting), abuse['substance'])
			label = _('Hx of addiction: %s') % abuse['substance']
			sort_key_list.append(sort_key)
			data[sort_key] = [label, abuse]

		sort_key_list.sort()
		sort_key_list.reverse()
		list_items = []
		list_data = []
		for key in sort_key_list:
			label, item = data[key]
			list_items.append(label)
			list_data.append(item)

		self._LCTRL_history.set_string_items(items = list_items)
		self._LCTRL_history.set_data(data = list_data)
Example #50
0
def process_staged_single_PID_hl7_file(staged_item):

	log_name = gmTools.get_unique_filename (
		prefix = 'gm-staged_hl7_import-',
		suffix = '.log'
	)
	import_logger = logging.FileHandler(log_name)
	import_logger.setLevel(logging.DEBUG)
	root_logger = logging.getLogger('')
	root_logger.addHandler(import_logger)
	_log.debug('log file: %s', log_name)

	if not staged_item.lock():
		_log.error('cannot lock staged data for HL7 import')
		root_logger.removeHandler(import_logger)
		return False, log_name

	_log.debug('reference ID of staged HL7 data: %s', staged_item['external_data_id'])

	filename = staged_item.save_to_file()
	_log.debug('unstaged HL7 data into: %s', filename)

	if staged_item['pk_identity_disambiguated'] is None:
		emr = None
	else:
		emr = gmPerson.cPatient(staged_item['pk_identity_disambiguated']).emr

	success = False
	try:
		success = __import_single_PID_hl7_file(filename, emr = emr)
		if success:
			gmIncomingData.delete_incoming_data(pk_incoming_data = staged_item['pk_incoming_data_unmatched'])
			staged_item.unlock()
			root_logger.removeHandler(import_logger)
			return True, log_name
		_log.error('error when importing single-PID/single-MSH file')
	except Exception:
		_log.exception('error when importing single-PID/single-MSH file')

	if not success:
		staged_item['comment'] = _('failed import: %s\n') % gmDateTime.pydt_strftime(gmDateTime.pydt_now_here())
		staged_item['comment'] += '\n'
		staged_item['comment'] += ('-' * 80)
		staged_item['comment'] += '\n\n'
		log = io.open(log_name, mode = 'rt', encoding = 'utf8')
		staged_item['comment'] += log.read()
		log.close()
		staged_item['comment'] += '\n'
		staged_item['comment'] += ('-' * 80)
		staged_item['comment'] += '\n\n'
		staged_item['comment'] += format_hl7_file (
			filename,
			skip_empty_fields = True,
			eol = '\n ',
			return_filename = False
		)
		staged_item.save()

	staged_item.unlock()
	root_logger.removeHandler(import_logger)
	return success, log_name
Example #51
0
def parse_vcard2dto(vc_text=None, filename=None):

    import vobject

    if vc_text is None:
        _log.info('trying to parse vCard from [%s]', filename)
        for encoding in ['utf8', 'Windows-1252']:
            try:
                vcf = io.open(filename, mode='rt', encoding=encoding)
                vc_text = vcf.read()
                vcf.close()
                break
            except UnicodeDecodeError:
                _log.exception('vCard not encoded as [%s]', encoding)
        if vc_text is None:
            return None
        vcf_lines = []
        found_first = False
        for line in vc_text.split('\n'):
            if not found_first:
                if line.strip() == 'BEGIN:VCARD':
                    found_first = True
                    vcf_lines.append(line)
                continue
            vcf_lines.append(line)
            if line.strip() == 'END:VCARD':
                break
        vc_text = '\n'.join(vcf_lines)

    dob_format = '%Y%m%d'

    try:
        vc = vobject.readOne(vc_text)
    except vobject.base.ParseError:
        _log.exception('cannot parse, really a vcf ?')
        return None

    try:
        if vc.kind.value.strip() != 'individual':
            _log.warning('not a vCard for a single person (vCard.KIND=%s)',
                         vc.kind.value)
            return None
    except AttributeError:
        _log.debug('vCard.KIND attribute not available')

    dto = gmPerson.cDTO_person()
    dto.firstnames = vc.n.value.given.strip()
    dto.lastnames = vc.n.value.family.strip()
    try:
        dto.title = vc.title.value.strip()
    except AttributeError:
        _log.debug('vCard.TITLE attribute not available')
    try:
        gender = vc.gender.value.strip().lower()
        if gender != '':
            dto.gender = gender
    except AttributeError:
        _log.debug('vCard.GENDER attribute not available')
    try:
        dob = pyDT.datetime.strptime(vc.bday.value.strip(), dob_format)
        dto.dob = dob.replace(tzinfo=gmDateTime.pydt_now_here().tzinfo)
        dto.dob_is_estimated = False
    except AttributeError:
        _log.debug('vCard.BDAY attribute not available')
    dto.source = 'vCard %s' % vc.version.value.strip()

    adr = None
    try:
        adr = vc.adr.value
    except AttributeError:
        _log.debug('vCard.ADR attribute not available')
    if adr is not None:
        region_code = None
        region = adr.region.strip()
        if region == '':
            region = None
        # deduce country
        country_code = None
        country = adr.country.strip()
        if country == '':
            country = None
        if country is None:
            country_row = gmDemographicRecord.map_urb_zip_region2country(
                urb=adr.city, zip=adr.code, region=region)
            if country_row is not None:
                country = country_row['country']
                country_code = country_row['code_country']
        else:
            country_code = gmDemographicRecord.map_country2code(
                country=country)
        if None in [country, country_code]:
            _log.error('unknown vCard.ADR.country (%s), skipping address',
                       adr.country)
        else:
            # deduce region
            if region is None:
                region_row = gmDemographicRecord.map_urb_zip_country2region(
                    urb=adr.city, zip=adr.code, country_code=country_code)
                if region_row is not None:
                    region = region_row['region']
                    region_code = region_row['code_region']
            else:
                region_code = gmDemographicRecord.map_region2code(
                    region=region, country_code=country_code)
            if region_code is None:
                _log.warning(
                    'unknown vCard.ADR.region (%s), using default region',
                    adr.region)
            dto.remember_address(number='?',
                                 street=adr.street,
                                 urb=adr.city,
                                 region_code=region_code,
                                 zip=adr.code,
                                 country_code=country_code,
                                 adr_type='home',
                                 subunit=None)

    tel = None
    try:
        tel = vc.tel.value
    except AttributeError:
        _log.debug('vCard.TEL attribute not available')
    if tel is not None:
        if 'TYPE' in vc.tel.params:
            channel = (vc.tel.params['TYPE'][0]).lower()
            if not channel.endswith('phone'):
                channel += 'phone'
        else:
            channel = 'homephone'
        dto.remember_comm_channel(channel=channel, url=tel)

    email = None
    try:
        email = vc.email.value
    except AttributeError:
        _log.debug('vCard.EMAIL attribute not available')
    if email is not None:
        dto.remember_comm_channel(channel='email', url=email)

    url = None
    try:
        url = vc.url.value
    except AttributeError:
        _log.debug('vCard.URL attribute not available')
    if url is not None:
        dto.remember_comm_channel(channel='web', url=url)

    return dto
Example #52
0
	def _get_body_surface_area(self):

		try:
			return self.__cache['body_surface_area']
		except KeyError:
			pass

		result = cClinicalResult(_('unknown body surface area'))
		result.formula_name = 'Du Bois Body Surface Area'
		result.formula_source = '12/2012: http://en.wikipedia.org/wiki/Body_surface_area'

		if self.__patient is None:
			result.message = _('Body Surface Area: no patient')
			return result

		result.variables['height'] = self.__patient.emr.get_most_recent_results_in_loinc_group(loincs = gmLOINC.LOINC_height, no_of_results = 1)
		if result.variables['height'] is None:
			result.message = _('Body Surface Area: height not found')
			return result
		if result.variables['height']['val_num'] is None:
			result.message = _('Body Surface Area: height not numeric')
			return result
		if result.variables['height']['val_unit'] == 'cm':
			result.variables['height_cm'] = self.d(result.variables['height']['val_num'])
		elif result.variables['height']['val_unit'] == 'mm':
			result.variables['height_cm'] = self.d(result.variables['height']['val_num'] / self.d(10))
		elif result.variables['height']['val_unit'] == 'm':
			result.variables['height_cm'] = self.d(result.variables['height']['val_num'] * 100)
		else:
			result.message = _('Body Surface Area: height not in m, cm, or mm')
			return result

		result.variables['weight'] = self.__patient.emr.get_result_at_timestamp (
			timestamp = result.variables['height']['clin_when'],
			loinc = gmLOINC.LOINC_weight,
			tolerance_interval = '10 days'
		)
		if result.variables['weight'] is None:
			result.message = _('Body Surface Area: weight not found')
			return result
		if result.variables['weight']['val_num'] is None:
			result.message = _('Body Surface Area: weight not numeric')
			return result
		if result.variables['weight']['val_unit'] == 'kg':
			result.variables['weight_kg'] = self.d(result.variables['weight']['val_num'])
		elif result.variables['weight']['val_unit'] == 'g':
			result.variables['weight_kg'] = self.d(result.variables['weight']['val_num'] / self.d(1000))
		else:
			result.message = _('Body Surface Area: weight not in kg or g')
			return result

		result.numeric_value = self.d('0.007184') * \
			pow(result.variables['weight_kg'], self.d('0.425')) * \
			pow(result.variables['height_cm'], self.d('0.725'))
		result.unit = 'm²'

		result.message = _('BSA (DuBois): %.2f %s') % (
			result.numeric_value,
			result.unit
		)
		result.date_valid = gmDateTime.pydt_now_here()

		self.__cache['body_surface_area'] = result
		_log.debug('%s' % result)

		return result
Example #53
0
File: gmVCard.py Project: sk/gnumed
def parse_vcard2dto(vc_text=None, filename=None):

	import vobject

	if vc_text is None:
		_log.info('trying to parse vCard from [%s]', filename)
		for encoding in ['utf8', 'Windows-1252']:
			try:
				vcf = io.open(filename, mode = u'rt', encoding = encoding)
				vc_text = vcf.read()
				vcf.close()
				break
			except UnicodeDecodeError:
				_log.exception('vCard not encoded as [%s]', encoding)
		if vc_text is None:
			return None

	dob_format = '%Y%m%d'

	try:
		vc = vobject.readOne(vc_text)
	except vobject.base.ParseError:
		_log.exception('cannot parse, really a vcf ?')
		return None

	try:
		if vc.kind.value.strip() != u'individual':
			_log.warning('not a vCard for a single person (vCard.KIND=%s)', vc.kind.value)
			return None
	except AttributeError:
		_log.debug('vCard.KIND attribute not available')

	dto = gmPerson.cDTO_person()
	dto.firstnames = vc.n.value.given.strip()
	dto.lastnames = vc.n.value.family.strip()
	if vc.title:
		dto.title = vc.title.value.strip()
	try:
		gender = vc.gender.value.strip().lower()
		if gender != u'':
			dto.gender = gender
	except AttributeError:
		_log.debug('vCard.GENDER attribute not available')
	try:
		dob = pyDT.datetime.strptime(vc.bday.value.strip(), dob_format)
		dto.dob = dob.replace(tzinfo = gmDateTime.pydt_now_here().tzinfo)
		dto.dob_is_estimated = False
	except AttributeError:
		_log.debug('vCard.BDAY attribute not available')
	dto.source = u'vCard %s' % vc.version.value.strip()

	adr = None
	try:
		adr = vc.adr.value
	except AttributeError:
		_log.debug('vCard.ADR attribute not available')
	if adr is not None:
		region_code = None
		region = adr.region.strip()
		if region == u'':
			region = None
		# deduce country
		country_code = None
		country = adr.country.strip()
		if country == u'':
			country = None
		if country is None:
			country_row = gmDemographicRecord.map_urb_zip_region2country(urb = adr.city, zip = adr.code, region = region)
			if country_row is not None:
				country = country_row['country']
				country_code = country_row['code_country']
		else:
			country_code = gmDemographicRecord.map_country2code(country = country)
		if None in [country, country_code]:
			_log.error('unknown vCard.ADR.country (%s), skipping address', adr.country)
		else:
			# deduce region
			if region is None:
				region_row = gmDemographicRecord.map_urb_zip_country2region(urb = adr.city, zip = adr.code, country_code = country_code)
				if region_row is not None:
					region = region_row['state']
					region_code = region_row['code_state']
			else:
				region_code = gmDemographicRecord.map_region2code(region = region, country_code = country_code)
			if region_code is None:
				_log.warning('unknown vCard.ADR.region (%s), using default region', adr.region)
			dto.remember_address (
				number = u'?',
				street = adr.street,
				urb = adr.city,
				region_code = region_code,
				zip = adr.code,
				country_code = country_code,
				adr_type = 'home',
				subunit = None
			)

	tel = None
	try:
		tel = vc.tel.value
	except AttributeError:
		_log.debug('vCard.TEL attribute not available')
	if tel is not None:
		if u'TYPE' in vc.tel.params:
			channel = (vc.tel.params[u'TYPE'][0]).lower()
			if not channel.endswith('phone'):
				channel += 'phone'
		else:
			channel = u'homephone'
		dto.remember_comm_channel(channel = channel, url = tel)

	email = None
	try:
		email = vc.email.value
	except AttributeError:
		_log.debug('vCard.EMAIL attribute not available')
	if email is not None:
		dto.remember_comm_channel(channel = 'email', url = email)

	url = None
	try:
		url = vc.url.value
	except AttributeError:
		_log.debug('vCard.URL attribute not available')
	if url is not None:
		dto.remember_comm_channel(channel = 'web', url = url)

	return dto
Example #54
0
    def _get_body_mass_index(self):

        try:
            return self.__cache['body_mass_index']
        except KeyError:
            pass

        result = cClinicalResult(_('unknown BMI'))
        result.formula_name = u'BMI/Quetelet Index'
        result.formula_source = u'08/2014: https://en.wikipedia.org/wiki/Body_mass_index'

        if self.__patient is None:
            result.message = _('BMI: no patient')
            return result

        result.variables[
            'height'] = self.__patient.emr.get_most_recent_results(
                loinc=gmLOINC.LOINC_height, no_of_results=1)
        if result.variables['height'] is None:
            result.message = _('BMI: height not found')
            return result
        if result.variables['height']['val_num'] is None:
            result.message = _('BMI: height not numeric')
            return result
        if result.variables['height']['val_unit'] == u'cm':
            result.variables['height_m'] = self.d(
                result.variables['height']['val_num'] / self.d(100))
        elif result.variables['height']['val_unit'] == u'mm':
            result.variables['height_m'] = self.d(
                result.variables['height']['val_num'] / self.d(1000))
        elif result.variables['height']['val_unit'] == u'm':
            result.variables['height_m'] = self.d(
                result.variables['height']['val_num'])
        else:
            result.message = _('BMI: height not in m, cm, or mm')
            return result

        result.variables[
            'weight'] = self.__patient.emr.get_result_at_timestamp(
                timestamp=result.variables['height']['clin_when'],
                loinc=gmLOINC.LOINC_weight,
                tolerance_interval='10 days')
        if result.variables['weight'] is None:
            result.message = _('BMI: weight not found')
            return result
        if result.variables['weight']['val_num'] is None:
            result.message = _('BMI: weight not numeric')
            return result
        if result.variables['weight']['val_unit'] == u'kg':
            result.variables['weight_kg'] = self.d(
                result.variables['weight']['val_num'])
        elif result.variables['weight']['val_unit'] == u'g':
            result.variables['weight_kg'] = self.d(
                result.variables['weight']['val_num'] / self.d(1000))
        else:
            result.message = _('BMI: weight not in kg or g')
            return result

        result.variables['dob'] = self.__patient['dob']
        start = result.variables['dob']
        end = result.variables['height']['clin_when']
        multiplier = 1
        if end < start:
            start = result.variables['height']['clin_when']
            end = result.variables['dob']
            multiplier = -1
        result.variables['age@height'] = multiplier * self.d(
            gmDateTime.calculate_apparent_age(start, end)[0])
        if (result.variables['age@height'] < 18):
            result.message = _(
                'BMI (Quetelet): formula does not apply at age [%s] (0 < age < 18)'
            ) % result.variables['age@height']
            return result

        # bmi = mass kg / height m2
        result.numeric_value = result.variables['weight_kg'] / (
            result.variables['height_m'] * result.variables['height_m'])
        result.unit = u'kg/m²'

        result.message = _('BMI (Quetelet): %.2f %s') % (result.numeric_value,
                                                         result.unit)
        result.date_valid = gmDateTime.pydt_now_here()

        self.__cache['body_mass_index'] = result
        _log.debug(u'%s' % result)

        return result
Example #55
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')
Example #56
0
	def refresh(lctrl):

		items = []
		data = []
		if latest_only:
			latest_vaccs = emr.get_latest_vaccinations()
			for indication in sorted(latest_vaccs.keys()):
				no_of_shots4ind, latest_vacc4ind = latest_vaccs[indication]
				items.append ([
					indication,
					_('%s (latest of %s: %s ago)') % (
						gmDateTime.pydt_strftime(latest_vacc4ind['date_given'], format = '%Y %b'),
						no_of_shots4ind,
						gmDateTime.format_interval_medically(gmDateTime.pydt_now_here() - latest_vacc4ind['date_given'])
					),
					latest_vacc4ind['vaccine'],
					latest_vacc4ind['batch_no'],
					gmTools.coalesce(latest_vacc4ind['site'], ''),
					gmTools.coalesce(latest_vacc4ind['reaction'], ''),
					gmTools.coalesce(latest_vacc4ind['comment'], '')
				])
				data.append(latest_vacc4ind)
		else:
			shots = emr.get_vaccinations(order_by = 'date_given DESC, pk_vaccination')
			if expand_indications:
				shots_by_ind = {}
				for shot in shots:
					for ind in shot['indications']:
						try:
							shots_by_ind[ind['l10n_indication']].append(shot)
						except KeyError:
							shots_by_ind[ind['l10n_indication']] = [shot]
				for ind in sorted(shots_by_ind.keys()):
					idx = len(shots_by_ind[ind])
					for shot in shots_by_ind[ind]:
						items.append ([
							'%s (#%s)' % (ind, idx),
							_('%s (%s ago)') % (
								gmDateTime.pydt_strftime(shot['date_given'], '%Y %b %d'),
								gmDateTime.format_interval_medically(gmDateTime.pydt_now_here() - shot['date_given'])
							),
							shot['vaccine'],
							shot['batch_no'],
							gmTools.coalesce(shot['site'], ''),
							gmTools.coalesce(shot['reaction'], ''),
							gmTools.coalesce(shot['comment'], '')
						])
						idx -= 1
						data.append(shot)
			else:
				items = [ [
					gmDateTime.pydt_strftime(s['date_given'], '%Y %b %d'),
					s['vaccine'],
					', '.join([ i['l10n_indication'] for i in s['indications'] ]),
					s['batch_no'],
					gmTools.coalesce(s['site'], ''),
					gmTools.coalesce(s['reaction'], ''),
					gmTools.coalesce(s['comment'], '')
				] for s in shots ]
				data = shots

		lctrl.set_string_items(items)
		lctrl.set_data(data)
Example #57
0
    def _get_body_surface_area(self):

        try:
            return self.__cache['body_surface_area']
        except KeyError:
            pass

        result = cClinicalResult(_('unknown body surface area'))
        result.formula_name = u'Du Bois Body Surface Area'
        result.formula_source = u'12/2012: http://en.wikipedia.org/wiki/Body_surface_area'

        if self.__patient is None:
            result.message = _('Body Surface Area: no patient')
            return result

        result.variables[
            'height'] = self.__patient.emr.get_most_recent_results(
                loinc=gmLOINC.LOINC_height, no_of_results=1)
        if result.variables['height'] is None:
            result.message = _('Body Surface Area: height not found')
            return result
        if result.variables['height']['val_num'] is None:
            result.message = _('Body Surface Area: height not numeric')
            return result
        if result.variables['height']['val_unit'] == u'cm':
            result.variables['height_cm'] = self.d(
                result.variables['height']['val_num'])
        elif result.variables['height']['val_unit'] == u'mm':
            result.variables['height_cm'] = self.d(
                result.variables['height']['val_num'] / self.d(10))
        elif result.variables['height']['val_unit'] == u'm':
            result.variables['height_cm'] = self.d(
                result.variables['height']['val_num'] * 100)
        else:
            result.message = _('Body Surface Area: height not in m, cm, or mm')
            return result

        result.variables[
            'weight'] = self.__patient.emr.get_result_at_timestamp(
                timestamp=result.variables['height']['clin_when'],
                loinc=gmLOINC.LOINC_weight,
                tolerance_interval='10 days')
        if result.variables['weight'] is None:
            result.message = _('Body Surface Area: weight not found')
            return result
        if result.variables['weight']['val_num'] is None:
            result.message = _('Body Surface Area: weight not numeric')
            return result
        if result.variables['weight']['val_unit'] == u'kg':
            result.variables['weight_kg'] = self.d(
                result.variables['weight']['val_num'])
        elif result.variables['weight']['val_unit'] == u'g':
            result.variables['weight_kg'] = self.d(
                result.variables['weight']['val_num'] / self.d(1000))
        else:
            result.message = _('Body Surface Area: weight not in kg or g')
            return result

        result.numeric_value = self.d('0.007184') * \
         pow(result.variables['weight_kg'], self.d('0.425')) * \
         pow(result.variables['height_cm'], self.d('0.725'))
        result.unit = u'm²'

        result.message = _('BSA (DuBois): %.2f %s') % (result.numeric_value,
                                                       result.unit)
        result.date_valid = gmDateTime.pydt_now_here()

        self.__cache['body_surface_area'] = result
        _log.debug(u'%s' % result)

        return result
Example #58
0
def create_timeline_file(patient=None, filename=None):

	emr = patient.emr
	global now
	now = gmDateTime.pydt_now_here()

	if filename is None:
		timeline_fname = gmTools.get_unique_filename(prefix = u'gm-', suffix = u'.timeline')
	else:
		timeline_fname = filename
	_log.debug('exporting EMR as timeline into [%s]', timeline_fname)
	timeline = io.open(timeline_fname, mode = 'wt', encoding = 'utf8', errors = 'xmlcharrefreplace')
	timeline.write(xml_start % (
		_('Health issues'),
		_('Episodes'),
		_('Encounters'),
		_('Hospital stays'),
		_('Procedures'),
		_('Documents'),
		_('Vaccinations'),
		_('Substances'),
		_('Life events')
	))
	# birth
	if patient['dob'] is None:
		start = now.replace(year = now.year - 100)
		timeline.write(__xml_encounter_template % (
			format_pydt(start),
			format_pydt(start),
			_('Birth') + u': ?',
			_('Life events'),
			_('Date of birth unknown')
		))
	else:
		start = patient['dob']
		timeline.write(__xml_encounter_template % (
			format_pydt(patient['dob']),
			format_pydt(patient['dob']),
			_('Birth') + gmTools.bool2subst(patient['dob_is_estimated'], u' (%s)' % gmTools.u_almost_equal_to, u''),
			_('Life events'),
			u''
		))

	# start of care
	timeline.write(__xml_encounter_template % (
		format_pydt(emr.earliest_care_date),
		format_pydt(emr.earliest_care_date),
		_('Start of Care'),
		_('Life events'),
		_('The earliest recorded event of care in this praxis.')
	))

	timeline.write(u'\n<!--\n========================================\n Health issues\n======================================== -->')
	for issue in emr.health_issues:
		timeline.write(__format_health_issue_as_timeline_xml(issue, patient, emr))

	timeline.write(u'\n<!--\n========================================\n Episodes\n======================================== -->')
	for epi in emr.get_episodes(order_by = u'pk_health_issue'):
		timeline.write(__format_episode_as_timeline_xml(epi, patient))

	timeline.write(u'\n<!--\n========================================\n Encounters\n======================================== -->')
	for enc in emr.get_encounters(skip_empty = True):
		timeline.write(__format_encounter_as_timeline_xml(enc, patient))

	timeline.write(u'\n<!--\n========================================\n Hospital stays\n======================================== -->')
	for stay in emr.hospital_stays:
		timeline.write(__format_hospital_stay_as_timeline_xml(stay))

	timeline.write(u'\n<!--\n========================================\n Procedures\n======================================== -->')
	for proc in emr.performed_procedures:
		timeline.write(__format_procedure_as_timeline_xml(proc))

	timeline.write(u'\n<!--\n========================================\n Vaccinations\n======================================== -->')
	for vacc in emr.vaccinations:
		timeline.write(__format_vaccination_as_timeline_xml(vacc))

	timeline.write(u'\n<!--\n========================================\n Substance intakes\n======================================== -->')
	for intake in emr.get_current_substance_intakes(include_inactive = True, include_unapproved = False):
		timeline.write(__format_intake_as_timeline_xml(intake))

	timeline.write(u'\n<!--\n========================================\n Documents\n======================================== -->')
	for doc in patient.document_folder.documents:
		timeline.write(__format_document_as_timeline_xml(doc))

	# allergies ?
	# test results ?

	# death
	if patient['deceased'] is None:
		end = now
	else:
		end = patient['deceased']
		timeline.write(__xml_encounter_template % (
			format_pydt(end),
			format_pydt(end),
			#u'',
			_('Death'),
			_('Life events'),
			u''
		))

	# display range
	if end.month == 2:
		if end.day == 29:
			# leap years aren't consecutive
			end = end.replace(day = 28)
	target_year = end.year + 1
	end = end.replace(year = target_year)
	timeline.write(xml_end % (
		format_pydt(start),
		format_pydt(end)
	))
	timeline.close()
	return timeline_fname
Example #59
0
def generate_invoice_id(template=None,
                        pk_patient=None,
                        person=None,
                        date_format='%Y-%m-%d',
                        time_format='%H%M%S'):
    """Generate invoice ID string, based on template.

	No template given -> generate old style fixed format invoice ID.

	Placeholders:
		%(pk_pat)s
		%(date)s
		%(time)s
			if included, $counter$ is not *needed* (but still possible)
		%(firstname)s
		%(lastname)s
		%(dob)s

		#counter#
			will be replaced by a counter, counting up from 1 until the invoice id is unique, max 999999
	"""
    assert (None in [
        pk_patient, person
    ]), u'either of <pk_patient> or <person> can be defined, but not both'

    if (template is None) or (template.strip() == u''):
        template = DEFAULT_INVOICE_ID_TEMPLATE
        date_format = '%Y-%m-%d'
        time_format = '%H%M%S'
    template = template.strip()
    _log.debug('invoice ID template: %s', template)
    if pk_patient is None:
        if person is not None:
            pk_patient = person.ID
    now = gmDateTime.pydt_now_here()
    data = {}
    data['pk_pat'] = gmTools.coalesce(pk_patient, '?')
    data['date'] = gmDateTime.pydt_strftime(now, date_format).strip()
    data['time'] = gmDateTime.pydt_strftime(now, time_format).strip()
    if person is None:
        data['firstname'] = u'?'
        data['lastname'] = u'?'
        data['dob'] = u'?'
    else:
        data['firstname'] = person['firstnames'].replace(
            ' ', gmTools.u_space_as_open_box).strip()
        data['lastname'] = person['lastnames'].replace(
            ' ', gmTools.u_space_as_open_box).strip()
        data['dob'] = person.get_formatted_dob(format=date_format,
                                               none_string=u'?',
                                               honor_estimation=False).strip()
    candidate_invoice_id = template % data
    if u'#counter#' not in candidate_invoice_id:
        if u'%(time)s' in template:
            return candidate_invoice_id

        candidate_invoice_id = candidate_invoice_id + u' [##counter#]'

    _log.debug('invoice id candidate: %s', candidate_invoice_id)
    # get existing invoice IDs consistent with candidate
    search_term = u'^\s*%s\s*$' % gmPG2.sanitize_pg_regex(
        expression=candidate_invoice_id).replace(u'#counter#', '\d+')
    cmd = u'SELECT invoice_id FROM bill.bill WHERE invoice_id ~* %(search_term)s UNION ALL SELECT invoice_id FROM audit.log_bill WHERE invoice_id ~* %(search_term)s'
    args = {'search_term': search_term}
    rows, idx = gmPG2.run_ro_queries(queries=[{'cmd': cmd, 'args': args}])
    if len(rows) == 0:
        return candidate_invoice_id.replace(u'#counter#', u'1')

    existing_invoice_ids = [r['invoice_id'].strip() for r in rows]
    counter = None
    counter_max = 999999
    for idx in range(1, counter_max):
        candidate = candidate_invoice_id.replace(u'#counter#', '%s' % idx)
        if candidate not in existing_invoice_ids:
            counter = idx
            break
    if counter is None:
        # exhausted the range, unlikely (1 million bills are possible
        # even w/o any other invoice ID data) but technically possible
        _log.debug(
            'exhausted uniqueness space of [%s] invoice IDs per template',
            counter_max)
        counter = '>%s[%s]' % (counter_max, data['time'])

    return candidate_invoice_id.replace(u'#counter#', '%s' % counter)
Example #60
0
def create_fake_timeline_file(patient=None, filename=None):
	"""Used to create an 'empty' timeline file for display.

	- needed because .clear_timeline() doesn't really work
	"""
	emr = patient.emr
	global now
	now = gmDateTime.pydt_now_here()

	if filename is None:
		timeline_fname = gmTools.get_unique_filename(prefix = u'gm-', suffix = u'.timeline')
	else:
		timeline_fname = filename

	_log.debug('creating dummy timeline in [%s]', timeline_fname)
	timeline = io.open(timeline_fname, mode = 'wt', encoding = 'utf8', errors = 'xmlcharrefreplace')

	timeline.write(__fake_timeline_start)

	# birth
	if patient['dob'] is None:
		start = now.replace(year = now.year - 100)
		timeline.write(__xml_encounter_template % (
			format_pydt(start),
			format_pydt(start),
			_('Birth') + u': ?',
			_('Life events'),
			_('Date of birth unknown')
		))
	else:
		start = patient['dob']
		timeline.write(__xml_encounter_template % (
			format_pydt(patient['dob']),
			format_pydt(patient['dob']),
			_('Birth') + gmTools.bool2subst(patient['dob_is_estimated'], u' (%s)' % gmTools.u_almost_equal_to, u''),
			_('Life events'),
			u''
		))

	# death
	if patient['deceased'] is None:
		end = now
	else:
		end = patient['deceased']
		timeline.write(__xml_encounter_template % (
			format_pydt(end),
			format_pydt(end),
			#u'',
			_('Death'),
			_('Life events'),
			u''
		))

	# fake issue
	timeline.write(__fake_timeline_body_template % (
		format_pydt(start),
		format_pydt(end),
		_('Cannot display timeline.'),
		_('Cannot display timeline.')
	))

	# display range
	if end.month == 2:
		if end.day == 29:
			# leap years aren't consecutive
			end = end.replace(day = 28)
	target_year = end.year + 1
	end = end.replace(year = target_year)
	timeline.write(xml_end % (
		format_pydt(start),
		format_pydt(end)
	))

	timeline.close()
	return timeline_fname