def __format_episode_as_timeline_xml(episode, patient): end = gmTools.bool2subst( episode['episode_open'], format_pydt(now), format_pydt(episode.latest_access_date), ) return __xml_episode_template % ( format_pydt(episode.best_guess_start_date), # start end, # end gmTools.xml_escape_string(episode['description']), # text gmTools.bool2subst(episode['episode_open'], u'True', u'False'), # ends_today _('Episodes'), # category gmTools.xml_escape_string( episode.format( # description patient=patient, with_summary=True, with_codes=True, with_encounters=True, with_documents=False, with_hospital_stays=False, with_procedures=False, with_family_history=False, with_tests=False, with_vaccinations=False, with_health_issue=True)))
def __format_episode_as_timeline_xml(episode, patient): end = gmTools.bool2subst ( episode['episode_open'], format_pydt(now), format_pydt(episode.latest_access_date), ) return __xml_episode_template % ( format_pydt(episode.best_guess_start_date), # start end, # end gmTools.xml_escape_string(episode['description']), # text gmTools.bool2subst(episode['episode_open'], u'True', u'False'), # ends_today _('Episodes'), # category gmTools.xml_escape_string(episode.format ( # description patient = patient, with_summary = True, with_codes = True, with_encounters = True, with_documents = False, with_hospital_stays = False, with_procedures = False, with_family_history = False, with_tests = False, with_vaccinations = False, with_health_issue = True )) )
def __format_episode_as_timeline_xml(episode, patient): data = { 'category': _('Episodes'), 'start': format_pydt(episode.best_guess_clinical_start_date), 'container_id': gmTools.coalesce(episode['pk_health_issue'], '', '(%s)'), 'label': gmTools.xml_escape_string ( gmTools.shorten_words_in_line(text = episode['description'], max_length = 20, min_word_length = 5) ), 'ends2day': gmTools.bool2subst(episode['episode_open'], 'True', 'False'), 'progress': gmTools.bool2subst(episode['episode_open'], '0', '100'), 'desc': gmTools.xml_escape_string(episode.format ( patient = patient, with_summary = True, with_codes = True, with_encounters = True, with_documents = False, with_hospital_stays = False, with_procedures = False, with_family_history = False, with_tests = False, with_vaccinations = False, with_health_issue = True ).strip().strip('\n').strip()) } end = episode.best_guess_clinical_end_date if end is None: data['end'] = format_pydt(now) else: data['end'] = format_pydt(end) return __xml_episode_template % data
def __format_episode_as_timeline_xml(episode, patient): data = { 'category': _('Episodes'), 'start': format_pydt(episode.best_guess_clinical_start_date), 'container_id': gmTools.coalesce ( value2test = episode['pk_health_issue'], return_instead = '', template4value = '(%s)' ), 'label': gmTools.xml_escape_string ( gmTools.shorten_words_in_line(text = episode['description'], max_length = 20, min_word_length = 5) ), 'ends2day': gmTools.bool2subst(episode['episode_open'], 'True', 'False'), 'progress': gmTools.bool2subst(episode['episode_open'], '0', '100'), 'desc': gmTools.xml_escape_string(episode.format ( patient = patient, with_summary = True, with_codes = True, with_encounters = True, with_documents = False, with_hospital_stays = False, with_procedures = False, with_family_history = False, with_tests = False, with_vaccinations = False, with_health_issue = True ).strip().strip('\n').strip()) } end = episode.best_guess_clinical_end_date if end is None: data['end'] = format_pydt(now) else: data['end'] = format_pydt(end) return __xml_episode_template % data
def __format_document_as_timeline_xml(doc): desc = gmTools.shorten_words_in_line(text=doc['l10n_type'], max_length=20, min_word_length=5) return __xml_document_template % ( format_pydt(doc['clin_when']), format_pydt( doc['clin_when']), gmTools.xml_escape_string(desc), _('Documents'), gmTools.xml_escape_string(doc.format().strip().strip('\n').strip()))
def __format_document_as_timeline_xml(doc): return __xml_document_template % ( format_pydt(doc['clin_when']), format_pydt(doc['clin_when']), gmTools.xml_escape_string(doc['l10n_type']), _('Documents'), gmTools.xml_escape_string(doc.format()) )
def __format_vaccination_as_timeline_xml(vacc): return __xml_vaccination_template % ( format_pydt(vacc['date_given']), format_pydt(vacc['date_given']), gmTools.xml_escape_string(vacc['vaccine']), _('Vaccinations'), gmTools.xml_escape_string('\n'.join( vacc.format(with_indications=True, with_comment=True, with_reaction=True, date_format='%Y %b %d')).strip().strip('\n').strip()))
def __format_document_as_timeline_xml(doc): desc = gmTools.shorten_words_in_line(text = doc['l10n_type'], max_length = 20, min_word_length = 5) return __xml_document_template % ( format_pydt(doc['clin_when']), format_pydt(doc['clin_when']), gmTools.xml_escape_string(desc), _('Documents'), gmTools.xml_escape_string(doc.format().strip().strip('\n').strip()) )
def __format_hospital_stay_as_timeline_xml(stay): end = stay['discharge'] if end is None: end = now return __xml_hospital_stay_template % ( format_pydt(stay['admission']), format_pydt(end), gmTools.xml_escape_string(stay['hospital']), _('Hospital stays'), # category gmTools.xml_escape_string(stay.format().strip().strip('\n').strip()))
def __format_hospital_stay_as_timeline_xml(stay): end = stay['discharge'] if end is None: end = now return __xml_hospital_stay_template % ( format_pydt(stay['admission']), format_pydt(end), gmTools.xml_escape_string(stay['hospital']), _('Hospital stays'), # category gmTools.xml_escape_string(stay.format()) )
def __format_health_issue_as_timeline_xml(issue, patient, emr): # container IDs are supposed to be numeric # [email protected] data = {'category': _('Health issues')} possible_start = issue.possible_start_date safe_start = issue.safe_start_date end = issue.clinical_end_date ends_today = 'False' if end is None: # open episode or active ends_today = 'True' end = now # somewhat hacky and not really correct: start2use = safe_start if safe_start > end: if possible_start < end: start2use = possible_start else: start2use = end data['desc'] = gmTools.xml_escape_string( issue.format(patient=patient, with_summary=True, with_codes=True, with_episodes=True, with_encounters=False, with_medications=False, with_hospital_stays=False, with_procedures=False, with_family_history=False, with_documents=False, with_tests=False, with_vaccinations=False).strip().strip('\n').strip()) label = gmTools.shorten_words_in_line(text=issue['description'], max_length=25, min_word_length=5) xml = '' # if possible_start < safe_start: # data['start'] = format_pydt(possible_start) # data['end'] = format_pydt(safe_start) # data['ends2day'] = 'False' # data['fuzzy'] = 'True' # data['container_id'] = '' # data['label'] = '?%s?' % gmTools.xml_escape_string(label) # xml += __xml_issue_template % data data['start'] = format_pydt(start2use) data['end'] = format_pydt(end) data['ends2day'] = ends_today data['fuzzy'] = 'False' data['container_id'] = '[%s]' % issue['pk_health_issue'] data['label'] = gmTools.xml_escape_string(label) xml += __xml_issue_template % data return xml
def __format_vaccination_as_timeline_xml(vacc): return __xml_vaccination_template % ( format_pydt(vacc['date_given']), format_pydt(vacc['date_given']), gmTools.xml_escape_string(vacc['vaccine']), _('Vaccinations'), gmTools.xml_escape_string(u'\n'.join(vacc.format ( with_indications = True, with_comment = True, with_reaction = True, date_format = '%Y %b %d' ))) )
def __format_procedure_as_timeline_xml(proc): if proc['is_ongoing']: end = now else: if proc['clin_end'] is None: end = proc['clin_when'] else: end = proc['clin_end'] return __xml_procedure_template % ( format_pydt(proc['clin_when']), format_pydt(end), gmTools.xml_escape_string( proc['performed_procedure']), _('Procedures'), gmTools.xml_escape_string( proc.format(include_episode=True, include_codes=True)))
def __format_procedure_as_timeline_xml(proc): if proc['is_ongoing']: end = now else: if proc['clin_end'] is None: end = proc['clin_when'] else: end = proc['clin_end'] desc = gmTools.shorten_words_in_line(text=proc['performed_procedure'], max_length=20, min_word_length=5) return __xml_procedure_template % ( format_pydt(proc['clin_when']), format_pydt(end), gmTools.xml_escape_string(desc), _('Procedures'), gmTools.xml_escape_string( proc.format(include_episode=True, include_codes=True).strip().strip('\n').strip()))
def __format_encounter_as_timeline_xml(encounter, patient): return __xml_encounter_template % ( format_pydt(encounter['started']), format_pydt(encounter['last_affirmed']), #u'(%s)' % encounter['pk_episode'], gmTools.xml_escape_string( format_pydt(encounter['started'], format='%b %d')), _('Encounters'), # category gmTools.xml_escape_string( encounter.format(patient=patient, with_soap=True, with_docs=False, with_tests=False, fancy_header=False, with_vaccinations=False, with_co_encountlet_hints=False, with_rfe_aoe=True, with_family_history=False)))
def __format_procedure_as_timeline_xml(proc): if proc['is_ongoing']: end = now else: if proc['clin_end'] is None: end = proc['clin_when'] else: end = proc['clin_end'] return __xml_procedure_template % ( format_pydt(proc['clin_when']), format_pydt(end), gmTools.xml_escape_string(proc['performed_procedure']), _('Procedures'), gmTools.xml_escape_string(proc.format ( include_episode = True, include_codes = True )) )
def __format_intake_as_timeline_xml(intake): if intake['discontinued'] is None: if intake['duration'] is None: if intake['seems_inactive']: end = intake['started'] else: end = now else: end = intake['started'] + intake['duration'] else: end = intake['discontinued'] return __xml_intake_template % ( format_pydt(intake['started']), format_pydt(end), gmTools.xml_escape_string(intake['substance']), _('Substances'), gmTools.xml_escape_string( intake.format(single_line=False, show_all_product_components=False ).strip().strip('\n').strip()))
def __format_health_issue_as_timeline_xml(issue, patient, emr): # container IDs are supposed to be numeric # [email protected] data = {'category': _('Health issues')} possible_start = issue.possible_start_date safe_start = issue.safe_start_date end = issue.clinical_end_date ends_today = 'False' if end is None: # open episode or active ends_today = 'True' end = now data['desc'] = gmTools.xml_escape_string(issue.format ( patient = patient, with_summary = True, with_codes = True, with_episodes = True, with_encounters = False, with_medications = False, with_hospital_stays = False, with_procedures = False, with_family_history = False, with_documents = False, with_tests = False, with_vaccinations = False ).strip().strip('\n').strip()) label = gmTools.shorten_words_in_line(text = issue['description'], max_length = 25, min_word_length = 5) xml = '' # if possible_start < safe_start: # data['start'] = format_pydt(possible_start) # data['end'] = format_pydt(safe_start) # data['ends2day'] = 'False' # data['fuzzy'] = 'True' # data['container_id'] = '' # data['label'] = '?%s?' % gmTools.xml_escape_string(label) # xml += __xml_issue_template % data data['start'] = format_pydt(safe_start) data['end'] = format_pydt(end) data['ends2day'] = ends_today data['fuzzy'] = 'False' data['container_id'] = '[%s]' % issue['pk_health_issue'] data['label'] = gmTools.xml_escape_string(label) xml += __xml_issue_template % data return xml
def __format_encounter_as_timeline_xml(encounter, patient): return __xml_encounter_template % ( format_pydt(encounter['started']), format_pydt(encounter['last_affirmed']), #u'(%s)' % encounter['pk_episode'], gmTools.xml_escape_string(format_pydt(encounter['started'], format = '%b %d')), _('Encounters'), # category gmTools.xml_escape_string(encounter.format ( patient = patient, with_soap = True, with_docs = False, with_tests = False, fancy_header = False, with_vaccinations = False, with_co_encountlet_hints = False, with_rfe_aoe = True, with_family_history = False )) )
def __format_procedure_as_timeline_xml(proc): if proc['is_ongoing']: end = now else: if proc['clin_end'] is None: end = proc['clin_when'] else: end = proc['clin_end'] desc = gmTools.shorten_words_in_line(text = proc['performed_procedure'], max_length = 20, min_word_length = 5) return __xml_procedure_template % ( format_pydt(proc['clin_when']), format_pydt(end), gmTools.xml_escape_string(desc), _('Procedures'), gmTools.xml_escape_string(proc.format ( include_episode = True, include_codes = True ).strip().strip('\n').strip()) )
def __format_intake_as_timeline_xml(intake): if intake['discontinued'] is None: if intake['duration'] is None: if intake['seems_inactive']: end = intake['started'] else: end = now else: end = intake['started'] + intake['duration'] else: end = intake['discontinued'] return __xml_intake_template % ( format_pydt(intake['started']), format_pydt(end), gmTools.xml_escape_string(intake['substance']), _('Substances'), gmTools.xml_escape_string(intake.format ( one_line = False, show_all_brand_components = False )) )
def __format_health_issue_as_timeline_xml(issue, patient, emr): tooltip = issue.format ( patient = patient, with_summary = True, with_codes = True, with_episodes = True, with_encounters = False, with_medications = False, with_hospital_stays = False, with_procedures = False, with_family_history = False, with_documents = False, with_tests = False, with_vaccinations = False ) safe_start = issue.safe_start_date possible_start = issue.possible_start_date txt = u'' if possible_start < safe_start: txt += __xml_issue_template % ( format_pydt(possible_start), # start format_pydt(safe_start), # end gmTools.xml_escape_string(u'?[%s]?' % issue['description']), # text u'False', # ends_today _('Health issues'), # category gmTools.xml_escape_string(tooltip) # description ) txt += __xml_issue_template % ( format_pydt(safe_start), # start format_pydt(issue.end_date), # end gmTools.xml_escape_string(issue['description']), # text gmTools.bool2subst(issue['is_active'], u'True', u'False'), # ends_today _('Health issues'), # category gmTools.xml_escape_string(tooltip) # description ) return txt
def __format_health_issue_as_timeline_xml(issue, patient, emr): tooltip = issue.format(patient=patient, with_summary=True, with_codes=True, with_episodes=True, with_encounters=False, with_medications=False, with_hospital_stays=False, with_procedures=False, with_family_history=False, with_documents=False, with_tests=False, with_vaccinations=False) safe_start = issue.safe_start_date possible_start = issue.possible_start_date txt = u'' if possible_start < safe_start: txt += __xml_issue_template % ( format_pydt(possible_start), # start format_pydt(safe_start), # end gmTools.xml_escape_string( u'?[%s]?' % issue['description']), # text u'False', # ends_today _('Health issues'), # category gmTools.xml_escape_string(tooltip) # description ) txt += __xml_issue_template % ( format_pydt(safe_start), # start format_pydt(issue.end_date), # end gmTools.xml_escape_string(issue['description']), # text gmTools.bool2subst(issue['is_active'], u'True', u'False'), # ends_today _('Health issues'), # category gmTools.xml_escape_string(tooltip) # description ) return txt
def __format_document_as_timeline_xml(doc): return __xml_document_template % ( format_pydt(doc['clin_when']), format_pydt( doc['clin_when']), gmTools.xml_escape_string(doc['l10n_type']), _('Documents'), gmTools.xml_escape_string(doc.format()))
def __create_prescription_file(self, substance_intakes=None): """FreeDiams calls this exchange-out or prescription file. CIS stands for Unique Speciality Identifier (eg bisoprolol 5 mg, gel). CIS is AFSSAPS specific, but pharmacist can retreive drug name with the CIS. AFSSAPS is the French FDA. CIP stands for Unique Presentation Identifier (eg 30 pills plaq) CIP if you want to specify the packaging of the drug (30 pills thermoformed tablet...) -- actually not really usefull for french doctors. # .external_code_type: u'FR-CIS' # .external_cod: the CIS value OnlyForTest: OnlyForTest drugs will be processed by the IA Engine but not printed (regardless of FreeDiams mode). They are shown in gray in the prescription view. Select-only is a mode where FreeDiams creates a list of drugs not a full prescription. In this list, users can add ForTestOnly drug if they want to 1. print the list without some drugs 2. but including these drugs in the IA engine calculation Select-Only mode does not have any relation with the ForTestOnly drugs. IsTextual: What is the use and significance of the <IsTextual>true/false</IsTextual> flag when both <DrugName> and <TextualDrugName> exist ? This tag must be setted even if it sounds like a duplicated data. This tag is needed inside FreeDiams code. INN: GNUmed will pass the substance in <TextualDrugName and will also pass <INN>True</INN>. Eric: Nop, this is not usefull because pure textual drugs are not processed but just shown. """ # virginize file open(self.__fd2gm_filename, 'wb').close() # make sure we've got something to do if substance_intakes is None: if self.patient is None: _log.warning('cannot create prescription file because there is neither a patient nor a substance intake list') # do fail because __export_latest_prescription() should not have been called without patient return False emr = self.patient.emr substance_intakes = emr.get_current_medications ( include_inactive = False, include_unapproved = True ) drug_snippets = [] # process FD drugs fd_intakes = [ i for i in substance_intakes if ( (i['intake_is_approved_of'] is True) and (i['external_code_type_product'] is not None) and (i['external_code_type_product'].startswith('FreeDiams::')) )] intakes_pooled_by_product = {} for intake in fd_intakes: # this will leave only one entry per drug # but FreeDiams knows the components ... intakes_pooled_by_product[intake['product']] = intake del fd_intakes drug_snippet = """<Prescription> <Drug u1="%s" u2="" old="%s" u3="" db="%s"> <!-- "old" needs to be the same as "u1" if not known --> <DrugName>%s</DrugName> <!-- just for identification when reading XML files --> </Drug> </Prescription>""" last_db_id = 'CA_HCDPD' for intake in intakes_pooled_by_product.values(): last_db_id = gmTools.xml_escape_string(text = intake['external_code_type_product'].replace('FreeDiams::', '').split('::')[0]) drug_snippets.append(drug_snippet % ( gmTools.xml_escape_string(text = intake['external_code_product'].strip()), gmTools.xml_escape_string(text = intake['external_code_product'].strip()), last_db_id, gmTools.xml_escape_string(text = intake['product'].strip()) )) # process non-FD drugs non_fd_intakes = [ i for i in substance_intakes if ( (i['intake_is_approved_of'] is True) and ( (i['external_code_type_product'] is None) or (not i['external_code_type_product'].startswith('FreeDiams::')) ) )] non_fd_product_intakes = [ i for i in non_fd_intakes if i['product'] is not None ] non_fd_substance_intakes = [ i for i in non_fd_intakes if i['product'] is None ] del non_fd_intakes drug_snippet = """<Prescription> <Drug u1="-1" u2="" old="" u3="" db=""> <DrugName>%s</DrugName> </Drug> <Dose Note="%s" IsTextual="true" IsAld="false"/> </Prescription>""" # <DrugUidName></DrugUidName> # <DrugForm></DrugForm> # <DrugRoute></DrugRoute> # <DrugStrength/> for intake in non_fd_substance_intakes: drug_name = '%s %s%s (%s)' % ( intake['substance'], intake['amount'], intake['unit'], intake['l10n_preparation'] ) drug_snippets.append(drug_snippet % ( gmTools.xml_escape_string(text = drug_name.strip()), gmTools.xml_escape_string(text = gmTools.coalesce(intake['schedule'], '')) )) intakes_pooled_by_product = {} for intake in non_fd_product_intakes: prod = '%s %s' % (intake['product'], intake['l10n_preparation']) try: intakes_pooled_by_product[prod].append(intake) except KeyError: intakes_pooled_by_product[prod] = [intake] for product, comps in intakes_pooled_by_product.items(): drug_name = '%s\n' % product for comp in comps: drug_name += ' %s %s%s\n' % ( comp['substance'], comp['amount'], comp['unit'] ) drug_snippets.append(drug_snippet % ( gmTools.xml_escape_string(text = drug_name.strip()), gmTools.xml_escape_string(text = gmTools.coalesce(comps[0]['schedule'], '')) )) # assemble XML file xml = """<?xml version = "1.0" encoding = "UTF-8"?> <!DOCTYPE FreeMedForms> <FreeDiams> <FullPrescription version="0.7.2"> %s </FullPrescription> </FreeDiams> """ xml_file = io.open(self.__fd2gm_filename, mode = 'wt', encoding = 'utf8') xml_file.write(xml % '\n\t\t'.join(drug_snippets)) xml_file.close() return True
def __create_gm2fd_file(self, mode='interactions'): if mode == 'interactions': mode = 'select-only' elif mode == 'prescription': mode = 'prescriber' else: mode = 'select-only' xml_file = io.open(self.__gm2fd_filename, mode = 'wt', encoding = 'utf8') xml = """<?xml version="1.0" encoding="UTF-8"?> <FreeDiams_In version="0.5.0"> <EMR name="GNUmed" uid="unused"/> <ConfigFile value="%s"/> <ExchangeOut value="%s" format="xml"/> <!-- <DrugsDatabase uid="can be set to a specific DB"/> --> <Ui editmode="%s" blockPatientDatas="1"/> %%s </FreeDiams_In> """ % ( self.__fd4gm_config_file, self.__fd2gm_filename, mode ) if self.patient is None: xml_file.write(xml % '') xml_file.close() return name = self.patient.get_active_name() if self.patient['dob'] is None: dob = '' else: dob = self.patient['dob'].strftime(cFreeDiamsInterface.default_dob_format) emr = self.patient.emr allgs = emr.get_allergies() atc_allgs = [ a['atc_code'] for a in allgs if ((a['atc_code'] is not None) and (a['type'] == 'allergy')) ] atc_sens = [ a['atc_code'] for a in allgs if ((a['atc_code'] is not None) and (a['type'] == 'sensitivity')) ] inn_allgs = [ a['allergene'] for a in allgs if ((a['allergene'] is not None) and (a['type'] == 'allergy')) ] inn_sens = [ a['allergene'] for a in allgs if ((a['allergene'] is not None) and (a['type'] == 'sensitivity')) ] # this is rather fragile: FreeDiams won't know what type of UID this is # (but it will assume it is of the type of the drug database in use) # but eventually FreeDiams puts all drugs into one database :-) uid_allgs = [ a['substance_code'] for a in allgs if ((a['substance_code'] is not None) and (a['type'] == 'allergy')) ] uid_sens = [ a['substance_code'] for a in allgs if ((a['substance_code'] is not None) and (a['type'] == 'sensitivity')) ] patient_xml = """<Patient> <Identity lastnames="%s" firstnames="%s" uid="%s" dob="%s" gender="%s" /> <!-- can be <7 characters class codes: --> <ATCAllergies value="%s"/> <ATCIntolerances value="%s"/> <InnAllergies value="%s"/> <InnIntolerances value="%s"/> <DrugsUidAllergies value="%s"/> <DrugsUidIntolerances value="%s"/> <!-- # FIXME: search by LOINC code and add (as soon as supported by FreeDiams ...) <Creatinine value="12" unit="mg/l or mmol/l"/> <Weight value="70" unit="kg or pd" /> <WeightInGrams value="70"/> <Height value="170" unit="cm or "/> <HeightInCentimeters value="170"/> <ICD10 value="J11.0;A22;Z23"/> --> </Patient> """ % ( gmTools.xml_escape_string(text = name['lastnames']), gmTools.xml_escape_string(text = name['firstnames']), self.patient.ID, dob, cFreeDiamsInterface.map_gender2mf[self.patient['gender']], gmTools.xml_escape_string(text = ';'.join(atc_allgs)), gmTools.xml_escape_string(text = ';'.join(atc_sens)), gmTools.xml_escape_string(text = ';'.join(inn_allgs)), gmTools.xml_escape_string(text = ';'.join(inn_sens)), gmTools.xml_escape_string(text = ';'.join(uid_allgs)), gmTools.xml_escape_string(text = ';'.join(uid_sens)) ) xml_file.write(xml % patient_xml) xml_file.close()
def __create_prescription_file(self, substance_intakes=None): """FreeDiams calls this exchange-out or prescription file. CIS stands for Unique Speciality Identifier (eg bisoprolol 5 mg, gel). CIS is AFSSAPS specific, but pharmacist can retrieve drug name with the CIS. AFSSAPS is the French FDA. CIP stands for Unique Presentation Identifier (eg 30 pills plaq) CIP if you want to specify the packaging of the drug (30 pills thermoformed tablet...) -- actually not really usefull for french doctors. # .external_code_type: u'FR-CIS' # .external_cod: the CIS value OnlyForTest: OnlyForTest drugs will be processed by the IA Engine but not printed (regardless of FreeDiams mode). They are shown in gray in the prescription view. Select-only is a mode where FreeDiams creates a list of drugs not a full prescription. In this list, users can add ForTestOnly drug if they want to 1. print the list without some drugs 2. but including these drugs in the IA engine calculation Select-Only mode does not have any relation with the ForTestOnly drugs. IsTextual: What is the use and significance of the <IsTextual>true/false</IsTextual> flag when both <DrugName> and <TextualDrugName> exist ? This tag must be setted even if it sounds like a duplicated data. This tag is needed inside FreeDiams code. INN: GNUmed will pass the substance in <TextualDrugName and will also pass <INN>True</INN>. Eric: Nop, this is not useful because pure textual drugs are not processed but just shown. """ # virginize file open(self.__fd2gm_filename, 'wb').close() # make sure we've got something to do if substance_intakes is None: if self.patient is None: _log.warning('cannot create prescription file because there is neither a patient nor a substance intake list') # do fail because __export_latest_prescription() should not have been called without patient return False emr = self.patient.emr substance_intakes = emr.get_current_medications ( include_inactive = False ) drug_snippets = [] # process FD drugs fd_intakes = [ i for i in substance_intakes if ( (i['external_code_type_product'] is not None) and (i['external_code_type_product'].startswith('FreeDiams::')) )] intakes_pooled_by_product = {} for intake in fd_intakes: # this will leave only one entry per drug # but FreeDiams knows the components ... intakes_pooled_by_product[intake['drug_product']] = intake del fd_intakes drug_snippet = """<Prescription> <Drug u1="%s" u2="" old="%s" u3="" db="%s"> <!-- "old" needs to be the same as "u1" if not known --> <DrugName>%s</DrugName> <!-- just for identification when reading XML files --> </Drug> </Prescription>""" last_db_id = 'CA_HCDPD' for intake in intakes_pooled_by_product.values(): last_db_id = gmTools.xml_escape_string(text = intake['external_code_type_product'].replace('FreeDiams::', '').split('::')[0]) drug_snippets.append(drug_snippet % ( gmTools.xml_escape_string(text = intake['external_code_product'].strip()), gmTools.xml_escape_string(text = intake['external_code_product'].strip()), last_db_id, gmTools.xml_escape_string(text = intake['drug_product'].strip()) )) # process non-FD drugs non_fd_intakes = [ i for i in substance_intakes if ( ( (i['external_code_type_product'] is None) or (not i['external_code_type_product'].startswith('FreeDiams::')) ) )] non_fd_product_intakes = [ i for i in non_fd_intakes if i['drug_product'] is not None ] non_fd_substance_intakes = [ i for i in non_fd_intakes if i['drug_product'] is None ] del non_fd_intakes drug_snippet = """<Prescription> <Drug u1="-1" u2="" old="" u3="" db=""> <DrugName>%s</DrugName> </Drug> <Dose Note="%s" IsTextual="true" IsAld="false"/> </Prescription>""" # <DrugUidName></DrugUidName> # <DrugForm></DrugForm> # <DrugRoute></DrugRoute> # <DrugStrength/> for intake in non_fd_substance_intakes: drug_name = '%s %s%s (%s)' % ( intake['substance'], intake['amount'], intake['unit'], intake['l10n_preparation'] ) drug_snippets.append(drug_snippet % ( gmTools.xml_escape_string(text = drug_name.strip()), gmTools.xml_escape_string(text = gmTools.coalesce(intake['schedule'], '')) )) intakes_pooled_by_product = {} for intake in non_fd_product_intakes: prod = '%s %s' % (intake['drug_product'], intake['l10n_preparation']) try: intakes_pooled_by_product[prod].append(intake) except KeyError: intakes_pooled_by_product[prod] = [intake] for product, comps in intakes_pooled_by_product.items(): drug_name = '%s\n' % product for comp in comps: drug_name += ' %s %s%s\n' % ( comp['substance'], comp['amount'], comp['unit'] ) drug_snippets.append(drug_snippet % ( gmTools.xml_escape_string(text = drug_name.strip()), gmTools.xml_escape_string(text = gmTools.coalesce(comps[0]['schedule'], '')) )) # assemble XML file xml = """<?xml version = "1.0" encoding = "UTF-8"?> <!DOCTYPE FreeMedForms> <FreeDiams> <FullPrescription version="0.7.2"> %s </FullPrescription> </FreeDiams> """ xml_file = io.open(self.__fd2gm_filename, mode = 'wt', encoding = 'utf8') xml_file.write(xml % '\n\t\t'.join(drug_snippets)) xml_file.close() return True