1
2 """Code handling drug data sources (such as databases).
3
4 license: GPL v2 or later
5 """
6
7 __author__ = "K.Hilbert <Karsten.Hilbert@gmx.net>"
8
9 import sys
10 import csv
11 import os
12 import io
13 import logging
14 import subprocess
15 import re as regex
16 from xml.etree import ElementTree as etree
17
18
19 if __name__ == '__main__':
20 sys.path.insert(0, '../../')
21 from Gnumed.pycommon import gmI18N
22 gmI18N.activate_locale()
23 gmI18N.install_domain('gnumed')
24 from Gnumed.pycommon import gmTools
25 from Gnumed.pycommon import gmShellAPI
26 from Gnumed.business import gmMedication
27 from Gnumed.business import gmCoding
28
29
30 _log = logging.getLogger('gm.meds')
31
32
33
34
36
37
39 self.patient = None
40 self.reviewer = None
41 self.custom_path_to_binary = None
42
44 raise NotImplementedError
45
47 raise NotImplementedError
48
50 raise NotImplementedError
51
54
57
60
63
67
68
69
70
71
72
73
74
75
76
78 """Iterator over a Gelbe Liste/MMI v8.2 CSV file."""
79
80 version = 'Gelbe Liste/MMI v8.2 CSV file interface'
81 default_transfer_file_windows = r"c:\rezept.txt"
82
83 default_encoding = 'cp1250'
84 csv_fieldnames = [
85 'name',
86 'packungsgroesse',
87 'darreichungsform',
88 'packungstyp',
89 'festbetrag',
90 'avp',
91 'hersteller',
92 'rezepttext',
93 'pzn',
94 'status_vertrieb',
95 'status_rezeptpflicht',
96 'status_fachinfo',
97 'btm',
98 'atc',
99 'anzahl_packungen',
100 'zuzahlung_pro_packung',
101 'einheit',
102 'schedule_morgens',
103 'schedule_mittags',
104 'schedule_abends',
105 'schedule_nachts',
106 'status_dauermedikament',
107 'status_hausliste',
108 'status_negativliste',
109 'ik_nummer',
110 'status_rabattvertrag',
111 'wirkstoffe',
112 'wirkstoffmenge',
113 'wirkstoffeinheit',
114 'wirkstoffmenge_bezug',
115 'wirkstoffmenge_bezugseinheit',
116 'status_import',
117 'status_lifestyle',
118 'status_ausnahmeliste',
119 'packungsmenge',
120 'apothekenpflicht',
121 'status_billigere_packung',
122 'rezepttyp',
123 'besonderes_arzneimittel',
124 't_rezept_pflicht',
125 'erstattbares_medizinprodukt',
126 'hilfsmittel',
127 'hzv_rabattkennung',
128 'hzv_preis'
129 ]
130 boolean_fields = [
131 'status_rezeptpflicht',
132 'status_fachinfo',
133 'btm',
134 'status_dauermedikament',
135 'status_hausliste',
136 'status_negativliste',
137 'status_rabattvertrag',
138 'status_import',
139 'status_lifestyle',
140 'status_ausnahmeliste',
141 'apothekenpflicht',
142 'status_billigere_packung',
143 'besonderes_arzneimittel',
144 't_rezept_pflicht',
145 'erstattbares_medizinprodukt',
146 'hilfsmittel'
147 ]
148
168
171
173 line = self.csv_lines.next()
174
175 for field in cGelbeListeCSVFile.boolean_fields:
176 line[field] = (line[field].strip() == 'T')
177
178
179 if line['wirkstoffe'].strip() == '':
180 line['wirkstoffe'] = []
181 else:
182 line['wirkstoffe'] = [ wirkstoff.strip() for wirkstoff in line['wirkstoffe'].split(';') ]
183
184 return line
185
186 - def close(self, truncate=True):
187 try: self.csv_file.close()
188 except: pass
189
190 if truncate:
191 try: os.open(self.filename, 'wb').close
192 except: pass
193
196
197 has_unknown_fields = property(_get_has_unknown_fields, lambda x:x)
198
199
201 """Support v8.2 CSV file interface only."""
202
203 version = 'Gelbe Liste/MMI v8.2 interface'
204 default_encoding = 'cp1250'
205 bdt_line_template = '%03d6210#%s\r\n'
206 bdt_line_base_length = 8
207
209
210 cDrugDataSourceInterface.__init__(self)
211
212 _log.info('%s (native Windows)', cGelbeListeWindowsInterface.version)
213
214 self.path_to_binary = r'C:\Programme\MMI PHARMINDEX\glwin.exe'
215 self.args = r'-KEEPBACKGROUND -PRESCRIPTIONFILE %s -CLOSETOTRAY'
216
217 paths = gmTools.gmPaths()
218
219 self.default_csv_filename = os.path.join(paths.tmp_dir, 'rezept.txt')
220 self.default_csv_filename_arg = paths.tmp_dir
221 self.interactions_filename = os.path.join(paths.tmp_dir, 'gm2mmi.bdt')
222 self.data_date_filename = r'C:\Programme\MMI PHARMINDEX\datadate.txt'
223
224 self.__data_date = None
225 self.__online_update_date = None
226
227
228
230
231 if self.__data_date is not None:
232 if not force_reload:
233 return {
234 'data': self.__data_date,
235 'online_update': self.__online_update_date
236 }
237 try:
238 open(self.data_date_filename, 'wb').close()
239 except Exception:
240 _log.error('problem querying the MMI drug database for version information')
241 _log.exception('cannot create MMI drug database version file [%s]', self.data_date_filename)
242 self.__data_date = None
243 self.__online_update_date = None
244 return {
245 'data': '?',
246 'online_update': '?'
247 }
248
249 cmd = '%s -DATADATE' % self.path_to_binary
250 if not gmShellAPI.run_command_in_shell(command = cmd, blocking = True):
251 _log.error('problem querying the MMI drug database for version information')
252 self.__data_date = None
253 self.__online_update_date = None
254 return {
255 'data': '?',
256 'online_update': '?'
257 }
258
259 try:
260 version_file = io.open(self.data_date_filename, mode = 'rt', encoding = 'utf8')
261 except Exception:
262 _log.error('problem querying the MMI drug database for version information')
263 _log.exception('cannot open MMI drug database version file [%s]', self.data_date_filename)
264 self.__data_date = None
265 self.__online_update_date = None
266 return {
267 'data': '?',
268 'online_update': '?'
269 }
270
271 self.__data_date = version_file.readline()[:10]
272 self.__online_update_date = version_file.readline()[:10]
273 version_file.close()
274
275 return {
276 'data': self.__data_date,
277 'online_update': self.__online_update_date
278 }
279
281 versions = self.get_data_source_version()
282
283 return gmCoding.create_data_source (
284 long_name = 'Medikamentendatenbank "mmi PHARMINDEX" (Gelbe Liste)',
285 short_name = 'GL/MMI',
286 version = 'Daten: %s, Preise (Onlineupdate): %s' % (versions['data'], versions['online_update']),
287 source = 'Medizinische Medien Informations GmbH, Am Forsthaus Gravenbruch 7, 63263 Neu-Isenburg',
288 language = 'de'
289 )
290
292
293 try:
294
295 open(self.default_csv_filename, 'wb').close()
296 except IOError:
297 _log.exception('problem creating GL/MMI <-> GNUmed exchange file')
298 return False
299
300 if cmd is None:
301 cmd = ('%s %s' % (self.path_to_binary, self.args)) % self.default_csv_filename_arg
302
303 if os.name == 'nt':
304 blocking = True
305 if not gmShellAPI.run_command_in_shell(command = cmd, blocking = blocking):
306 _log.error('problem switching to the MMI drug database')
307
308
309
310
311 return True
312
322
324
325 selected_drugs = self.__let_user_select_drugs()
326 if selected_drugs is None:
327 return None
328
329 new_substances = []
330
331 for drug in selected_drugs:
332 atc = None
333 if len(drug['wirkstoffe']) == 1:
334 atc = drug['atc']
335 for wirkstoff in drug['wirkstoffe']:
336 new_substances.append(gmMedication.create_substance_dose(substance = wirkstoff, atc = atc, amount = amount, unit = unit))
337
338 selected_drugs.close()
339
340 return new_substances
341
343
344 selected_drugs = self.__let_user_select_drugs()
345 if selected_drugs is None:
346 return None
347
348 data_src_pk = self.create_data_source_entry()
349
350 new_drugs = []
351 new_substances = []
352
353 for entry in selected_drugs:
354
355 _log.debug('importing drug: %s %s', entry['name'], entry['darreichungsform'])
356
357 if entry['hilfsmittel']:
358 _log.debug('skipping Hilfsmittel')
359 continue
360
361 if entry['erstattbares_medizinprodukt']:
362 _log.debug('skipping sonstiges Medizinprodukt')
363 continue
364
365
366 drug = gmMedication.create_drug_product(product_name = entry['name'], preparation = entry['darreichungsform'])
367 if drug is None:
368 drug = gmMedication.get_drug_by_name(product_name = entry['name'], preparation = entry['darreichungsform'])
369 new_drugs.append(drug)
370
371
372 drug['is_fake_product'] = False
373 drug['atc'] = entry['atc']
374 drug['external_code_type'] = 'DE-PZN'
375 drug['external_code'] = entry['pzn']
376 drug['fk_data_source'] = data_src_pk
377 drug.save()
378
379
380 atc = None
381 if len(entry['wirkstoffe']) == 1:
382 atc = entry['atc']
383 for wirkstoff in entry['wirkstoffe']:
384 drug.add_component(substance = wirkstoff, atc = atc)
385
386
387 atc = None
388 if len(entry['wirkstoffe']) == 1:
389 atc = entry['atc']
390 for wirkstoff in entry['wirkstoffe']:
391 new_substances.append(gmMedication.create_substance_dose(substance = wirkstoff, atc = atc, amount = amount, unit = unit))
392
393 return new_drugs, new_substances
394
423
426
445
446
448
450 cGelbeListeWindowsInterface.__init__(self)
451
452 _log.info('%s (WINE extension)', cGelbeListeWindowsInterface.version)
453
454
455 self.path_to_binary = r'wine "C:\Programme\MMI PHARMINDEX\glwin.exe"'
456 self.args = r'"-PRESCRIPTIONFILE %s -KEEPBACKGROUND"'
457
458 paths = gmTools.gmPaths()
459
460 self.default_csv_filename = os.path.join(paths.home_dir, '.wine', 'drive_c', 'windows', 'temp', 'mmi2gm.csv')
461 self.default_csv_filename_arg = r'c:\windows\temp\mmi2gm.csv'
462 self.interactions_filename = os.path.join(paths.home_dir, '.wine', 'drive_c', 'windows', 'temp', 'gm2mmi.bdt')
463 self.data_date_filename = os.path.join(paths.home_dir, '.wine', 'drive_c', 'Programme', 'MMI PHARMINDEX', 'datadate.txt')
464
465
466
467
469
470 version = 'FreeDiams interface'
471 default_encoding = 'utf8'
472 default_dob_format = '%Y/%m/%d'
473
474 map_gender2mf = {
475 'm': 'M',
476 'f': 'F',
477 'tf': 'H',
478 'tm': 'H',
479 'h': 'H'
480 }
481
499
501
502
503 if not self.__detect_binary():
504 return False
505
506 freediams = subprocess.Popen (
507 args = '--version',
508 executable = self.path_to_binary,
509 stdout = subprocess.PIPE,
510 stderr = subprocess.PIPE,
511
512 universal_newlines = True
513 )
514 data, errors = freediams.communicate()
515 version = regex.search('FreeDiams\s\d.\d.\d', data).group().split()[1]
516 _log.debug('FreeDiams %s', version)
517
518 return version
519
521 return gmCoding.create_data_source (
522 long_name = '"FreeDiams" Drug Database Frontend',
523 short_name = 'FreeDiams',
524 version = self.get_data_source_version(),
525 source = 'http://ericmaeker.fr/FreeMedForms/di-manual/index.html',
526 language = 'fr'
527 )
528
530 """http://ericmaeker.fr/FreeMedForms/di-manual/en/html/ligne_commandes.html"""
531
532 _log.debug('calling FreeDiams in [%s] mode', mode)
533
534 self.__imported_drugs = []
535
536 if not self.__detect_binary():
537 return False
538
539 self.__create_gm2fd_file(mode = mode)
540
541 args = '--exchange-in="%s"' % (self.__gm2fd_filename)
542 cmd = r'%s %s' % (self.path_to_binary, args)
543 if os.name == 'nt':
544 blocking = True
545 if not gmShellAPI.run_command_in_shell(command = cmd, blocking = blocking):
546 _log.error('problem switching to the FreeDiams drug database')
547 return False
548
549 if blocking == True:
550 self.import_fd2gm_file_as_drugs()
551
552 return True
553
556
558 if substance_intakes is None:
559 return
560 if len(substance_intakes) < 2:
561 return
562
563 self.__create_prescription_file(substance_intakes = substance_intakes)
564 self.switch_to_frontend(mode = 'interactions', blocking = False)
565
567 if substance_intake is None:
568 return
569
570 self.__create_prescription_file(substance_intakes = [substance_intake])
571 self.switch_to_frontend(mode = 'interactions', blocking = False)
572
575
576 - def prescribe(self, substance_intakes=None):
577 if substance_intakes is None:
578 if not self.__export_latest_prescription():
579 self.__create_prescription_file()
580 else:
581 self.__create_prescription_file(substance_intakes = substance_intakes)
582
583 self.switch_to_frontend(mode = 'prescription', blocking = True)
584 self.import_fd2gm_file_as_prescription()
585
586 return self.__imported_drugs
587
588
589
591
592 if self.path_to_binary is not None:
593 return True
594
595 found, cmd = gmShellAPI.find_first_binary(binaries = [
596 r'/usr/bin/freediams',
597 r'freediams',
598 r'/Applications/FreeDiams.app/Contents/MacOs/FreeDiams',
599 r'C:\Program Files (x86)\FreeDiams\freediams.exe',
600 r'C:\Program Files\FreeDiams\freediams.exe',
601 r'c:\programs\freediams\freediams.exe',
602 r'freediams.exe'
603 ])
604
605 if found:
606 self.path_to_binary = cmd
607 return True
608
609 try:
610 self.custom_path_to_binary
611 except AttributeError:
612 _log.error('cannot find FreeDiams binary, no custom path set')
613 return False
614
615 if self.custom_path_to_binary is None:
616 _log.error('cannot find FreeDiams binary')
617 return False
618
619 found, cmd = gmShellAPI.detect_external_binary(binary = self.custom_path_to_binary)
620 if found:
621 self.path_to_binary = cmd
622 return True
623
624 _log.error('cannot find FreeDiams binary')
625 return False
626
628
629 if self.patient is None:
630 _log.debug('cannot export latest FreeDiams prescriptions w/o patient')
631 return False
632
633 docs = self.patient.get_document_folder()
634 prescription = docs.get_latest_freediams_prescription()
635 if prescription is None:
636 _log.debug('no FreeDiams prescription available')
637 return False
638
639 for part in prescription.parts:
640 if part['filename'] == 'freediams-prescription.xml':
641 if part.save_to_file(filename = self.__fd2gm_filename) is not None:
642 return True
643
644 _log.error('cannot export latest FreeDiams prescription to XML file')
645
646 return False
647
649 """FreeDiams calls this exchange-out or prescription file.
650
651 CIS stands for Unique Speciality Identifier (eg bisoprolol 5 mg, gel).
652 CIS is AFSSAPS specific, but pharmacist can retreive drug name with the CIS.
653 AFSSAPS is the French FDA.
654
655 CIP stands for Unique Presentation Identifier (eg 30 pills plaq)
656 CIP if you want to specify the packaging of the drug (30 pills
657 thermoformed tablet...) -- actually not really usefull for french
658 doctors.
659 # .external_code_type: u'FR-CIS'
660 # .external_cod: the CIS value
661
662 OnlyForTest:
663 OnlyForTest drugs will be processed by the IA Engine but
664 not printed (regardless of FreeDiams mode). They are shown
665 in gray in the prescription view.
666
667 Select-only is a mode where FreeDiams creates a list of drugs
668 not a full prescription. In this list, users can add ForTestOnly
669 drug if they want to
670 1. print the list without some drugs
671 2. but including these drugs in the IA engine calculation
672
673 Select-Only mode does not have any relation with the ForTestOnly drugs.
674
675 IsTextual:
676 What is the use and significance of the
677 <IsTextual>true/false</IsTextual>
678 flag when both <DrugName> and <TextualDrugName> exist ?
679
680 This tag must be setted even if it sounds like a duplicated
681 data. This tag is needed inside FreeDiams code.
682
683 INN:
684 GNUmed will pass the substance in <TextualDrugName
685 and will also pass <INN>True</INN>.
686
687 Eric: Nop, this is not usefull because pure textual drugs
688 are not processed but just shown.
689 """
690
691 open(self.__fd2gm_filename, 'wb').close()
692
693
694 if substance_intakes is None:
695 if self.patient is None:
696 _log.warning('cannot create prescription file because there is neither a patient nor a substance intake list')
697
698 return False
699 emr = self.patient.emr
700 substance_intakes = emr.get_current_medications (
701 include_inactive = False,
702 include_unapproved = True
703 )
704
705 drug_snippets = []
706
707
708 fd_intakes = [ i for i in substance_intakes if (
709 (i['intake_is_approved_of'] is True)
710 and
711 (i['external_code_type_product'] is not None)
712 and
713 (i['external_code_type_product'].startswith('FreeDiams::'))
714 )]
715
716 intakes_pooled_by_product = {}
717 for intake in fd_intakes:
718
719
720 intakes_pooled_by_product[intake['product']] = intake
721 del fd_intakes
722
723 drug_snippet = """<Prescription>
724 <Drug u1="%s" u2="" old="%s" u3="" db="%s"> <!-- "old" needs to be the same as "u1" if not known -->
725 <DrugName>%s</DrugName> <!-- just for identification when reading XML files -->
726 </Drug>
727 </Prescription>"""
728
729 last_db_id = 'CA_HCDPD'
730 for intake in intakes_pooled_by_product.values():
731 last_db_id = gmTools.xml_escape_string(text = intake['external_code_type_product'].replace('FreeDiams::', '').split('::')[0])
732 drug_snippets.append(drug_snippet % (
733 gmTools.xml_escape_string(text = intake['external_code_product'].strip()),
734 gmTools.xml_escape_string(text = intake['external_code_product'].strip()),
735 last_db_id,
736 gmTools.xml_escape_string(text = intake['product'].strip())
737 ))
738
739
740 non_fd_intakes = [ i for i in substance_intakes if (
741 (i['intake_is_approved_of'] is True)
742 and (
743 (i['external_code_type_product'] is None)
744 or
745 (not i['external_code_type_product'].startswith('FreeDiams::'))
746 )
747 )]
748
749 non_fd_product_intakes = [ i for i in non_fd_intakes if i['product'] is not None ]
750 non_fd_substance_intakes = [ i for i in non_fd_intakes if i['product'] is None ]
751 del non_fd_intakes
752
753 drug_snippet = """<Prescription>
754 <Drug u1="-1" u2="" old="" u3="" db="">
755 <DrugName>%s</DrugName>
756 </Drug>
757 <Dose Note="%s" IsTextual="true" IsAld="false"/>
758 </Prescription>"""
759
760
761
762
763
764 for intake in non_fd_substance_intakes:
765 drug_name = '%s %s%s (%s)' % (
766 intake['substance'],
767 intake['amount'],
768 intake['unit'],
769 intake['l10n_preparation']
770 )
771 drug_snippets.append(drug_snippet % (
772 gmTools.xml_escape_string(text = drug_name.strip()),
773 gmTools.xml_escape_string(text = gmTools.coalesce(intake['schedule'], ''))
774 ))
775
776 intakes_pooled_by_product = {}
777 for intake in non_fd_product_intakes:
778 prod = '%s %s' % (intake['product'], intake['l10n_preparation'])
779 try:
780 intakes_pooled_by_product[prod].append(intake)
781 except KeyError:
782 intakes_pooled_by_product[prod] = [intake]
783
784 for product, comps in intakes_pooled_by_product.items():
785 drug_name = '%s\n' % product
786 for comp in comps:
787 drug_name += ' %s %s%s\n' % (
788 comp['substance'],
789 comp['amount'],
790 comp['unit']
791 )
792 drug_snippets.append(drug_snippet % (
793 gmTools.xml_escape_string(text = drug_name.strip()),
794 gmTools.xml_escape_string(text = gmTools.coalesce(comps[0]['schedule'], ''))
795 ))
796
797
798 xml = """<?xml version = "1.0" encoding = "UTF-8"?>
799 <!DOCTYPE FreeMedForms>
800 <FreeDiams>
801 <FullPrescription version="0.7.2">
802 %s
803 </FullPrescription>
804 </FreeDiams>
805 """
806
807 xml_file = io.open(self.__fd2gm_filename, mode = 'wt', encoding = 'utf8')
808 xml_file.write(xml % '\n\t\t'.join(drug_snippets))
809 xml_file.close()
810
811 return True
812
814
815 if mode == 'interactions':
816 mode = 'select-only'
817 elif mode == 'prescription':
818 mode = 'prescriber'
819 else:
820 mode = 'select-only'
821
822 xml_file = io.open(self.__gm2fd_filename, mode = 'wt', encoding = 'utf8')
823
824 xml = """<?xml version="1.0" encoding="UTF-8"?>
825
826 <FreeDiams_In version="0.5.0">
827 <EMR name="GNUmed" uid="unused"/>
828 <ConfigFile value="%s"/>
829 <ExchangeOut value="%s" format="xml"/>
830 <!-- <DrugsDatabase uid="can be set to a specific DB"/> -->
831 <Ui editmode="%s" blockPatientDatas="1"/>
832 %%s
833 </FreeDiams_In>
834 """ % (
835 self.__fd4gm_config_file,
836 self.__fd2gm_filename,
837 mode
838 )
839
840 if self.patient is None:
841 xml_file.write(xml % '')
842 xml_file.close()
843 return
844
845 name = self.patient.get_active_name()
846 if self.patient['dob'] is None:
847 dob = ''
848 else:
849 dob = self.patient['dob'].strftime(cFreeDiamsInterface.default_dob_format)
850
851 emr = self.patient.emr
852 allgs = emr.get_allergies()
853 atc_allgs = [
854 a['atc_code'] for a in allgs if ((a['atc_code'] is not None) and (a['type'] == 'allergy'))
855 ]
856 atc_sens = [
857 a['atc_code'] for a in allgs if ((a['atc_code'] is not None) and (a['type'] == 'sensitivity'))
858 ]
859 inn_allgs = [
860 a['allergene'] for a in allgs if ((a['allergene'] is not None) and (a['type'] == 'allergy'))
861 ]
862 inn_sens = [
863 a['allergene'] for a in allgs if ((a['allergene'] is not None) and (a['type'] == 'sensitivity'))
864 ]
865
866
867
868 uid_allgs = [
869 a['substance_code'] for a in allgs if ((a['substance_code'] is not None) and (a['type'] == 'allergy'))
870 ]
871 uid_sens = [
872 a['substance_code'] for a in allgs if ((a['substance_code'] is not None) and (a['type'] == 'sensitivity'))
873 ]
874
875 patient_xml = """<Patient>
876 <Identity
877 lastnames="%s"
878 firstnames="%s"
879 uid="%s"
880 dob="%s"
881 gender="%s"
882 />
883 <!-- can be <7 characters class codes: -->
884 <ATCAllergies value="%s"/>
885 <ATCIntolerances value="%s"/>
886
887 <InnAllergies value="%s"/>
888 <InnIntolerances value="%s"/>
889
890 <DrugsUidAllergies value="%s"/>
891 <DrugsUidIntolerances value="%s"/>
892
893 <!--
894 # FIXME: search by LOINC code and add (as soon as supported by FreeDiams ...)
895 <Creatinine value="12" unit="mg/l or mmol/l"/>
896 <Weight value="70" unit="kg or pd" />
897 <WeightInGrams value="70"/>
898 <Height value="170" unit="cm or "/>
899 <HeightInCentimeters value="170"/>
900 <ICD10 value="J11.0;A22;Z23"/>
901 -->
902
903 </Patient>
904 """ % (
905 gmTools.xml_escape_string(text = name['lastnames']),
906 gmTools.xml_escape_string(text = name['firstnames']),
907 self.patient.ID,
908 dob,
909 cFreeDiamsInterface.map_gender2mf[self.patient['gender']],
910 gmTools.xml_escape_string(text = ';'.join(atc_allgs)),
911 gmTools.xml_escape_string(text = ';'.join(atc_sens)),
912 gmTools.xml_escape_string(text = ';'.join(inn_allgs)),
913 gmTools.xml_escape_string(text = ';'.join(inn_sens)),
914 gmTools.xml_escape_string(text = ';'.join(uid_allgs)),
915 gmTools.xml_escape_string(text = ';'.join(uid_sens))
916 )
917
918 xml_file.write(xml % patient_xml)
919 xml_file.close()
920
922
923 if filename is None:
924 filename = self.__fd2gm_filename
925
926 _log.debug('importing FreeDiams prescription information from [%s]', filename)
927
928 fd2gm_xml = etree.ElementTree()
929 fd2gm_xml.parse(filename)
930
931 pdfs = fd2gm_xml.findall('ExtraDatas/Printed')
932 if len(pdfs) == 0:
933 _log.debug('no PDF prescription files listed')
934 return
935
936 fd_filenames = []
937 for pdf in pdfs:
938 fd_filenames.append(pdf.attrib['file'])
939
940 _log.debug('listed PDF prescription files: %s', fd_filenames)
941
942 docs = self.patient.get_document_folder()
943 emr = self.patient.emr
944
945 prescription = docs.add_prescription (
946 encounter = emr.active_encounter['pk_encounter'],
947 episode = emr.add_episode (
948 episode_name = DEFAULT_MEDICATION_HISTORY_EPISODE,
949 is_open = False
950 )['pk_episode']
951 )
952 prescription['ext_ref'] = 'FreeDiams'
953 prescription.save()
954 fd_filenames.append(filename)
955 success, msg, parts = prescription.add_parts_from_files(files = fd_filenames)
956 if not success:
957 _log.error(msg)
958 return
959
960 for part in parts:
961 part['obj_comment'] = _('copy of printed prescription')
962 part.save()
963
964 xml_part = parts[-1]
965 xml_part['filename'] = 'freediams-prescription.xml'
966 xml_part['obj_comment'] = _('prescription data')
967 xml_part.save()
968
969
970 from Gnumed.business.gmStaff import gmCurrentProvider
971 me = gmCurrentProvider()
972
973 if xml_part['pk_intended_reviewer'] == me['pk_staff']:
974 prescription.set_reviewed(technically_abnormal = False, clinically_relevant = False)
975
977 """
978 If returning textual prescriptions (say, drugs which FreeDiams
979 did not know) then "IsTextual" will be True and UID will be -1.
980 """
981 if filename is None:
982 filename = self.__fd2gm_filename
983
984
985
986 fd2gm_xml = etree.ElementTree()
987 fd2gm_xml.parse(filename)
988
989 data_src_pk = self.create_data_source_entry()
990
991 xml_version = fd2gm_xml.find('FullPrescription').attrib['version']
992 _log.debug('fd2gm file version: %s', xml_version)
993
994 if xml_version in ['0.6.0', '0.7.2']:
995 return self.__import_fd2gm_file_as_drugs_0_6_0(fd2gm_xml = fd2gm_xml, pk_data_source = data_src_pk)
996
997 return self.__import_fd2gm_file_as_drugs_0_5(fd2gm_xml = fd2gm_xml, pk_data_source = data_src_pk)
998
1000
1001
1002 fd_xml_prescriptions = fd2gm_xml.findall('FullPrescription/Prescription')
1003
1004 self.__imported_drugs = []
1005 for fd_xml_prescription in fd_xml_prescriptions:
1006 drug_uid = fd_xml_prescription.find('Drug').attrib['u1'].strip()
1007 if drug_uid == '-1':
1008 _log.debug('skipping textual drug')
1009 continue
1010 drug_db = fd_xml_prescription.find('Drug').attrib['db'].strip()
1011 drug_uid_name = fd_xml_prescription.find('Drug/DrugUidName').text.strip()
1012
1013 drug_name = fd_xml_prescription.find('Drug/DrugName').text.replace(', )', ')').strip()
1014 drug_form = fd_xml_prescription.find('Drug/DrugForm').text.strip()
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025 new_drug = gmMedication.create_drug_product(product_name = drug_name, preparation = drug_form, return_existing = True)
1026 self.__imported_drugs.append(new_drug)
1027 new_drug['is_fake_product'] = False
1028
1029 new_drug['external_code_type'] = 'FreeDiams::%s::%s' % (drug_db, drug_uid_name)
1030 new_drug['external_code'] = drug_uid
1031 new_drug['pk_data_source'] = pk_data_source
1032 new_drug.save()
1033
1034
1035 fd_xml_components = fd_xml_prescription.getiterator('Composition')
1036 comp_data = {}
1037 for fd_xml_comp in fd_xml_components:
1038
1039 data = {}
1040
1041 xml_strength = fd_xml_comp.attrib['strength'].strip()
1042 amount = regex.match(r'^\d+[.,]{0,1}\d*', xml_strength)
1043 if amount is None:
1044 amount = 99999
1045 else:
1046 amount = amount.group()
1047 data['amount'] = amount
1048
1049
1050 unit = (xml_strength[len(amount):]).strip()
1051 if unit == '':
1052 unit = '*?*'
1053 data['unit'] = unit
1054
1055
1056 atc = regex.match(r'[A-Za-z]\d\d[A-Za-z]{2}\d\d', fd_xml_comp.attrib['atc'].strip())
1057 if atc is None:
1058 data['atc'] = None
1059 else:
1060 atc = atc.group()
1061 data['atc'] = atc
1062
1063 molecule_name = fd_xml_comp.attrib['molecularName'].strip()
1064 if molecule_name != '':
1065 gmMedication.create_substance_dose(substance = molecule_name, atc = atc, amount = amount, unit = unit)
1066 data['molecule_name'] = molecule_name
1067
1068 inn_name = fd_xml_comp.attrib['inn'].strip()
1069 if inn_name != '':
1070 gmMedication.create_substance_dose(substance = inn_name, atc = atc, amount = amount, unit = unit)
1071
1072 data['inn_name'] = inn_name
1073
1074 if molecule_name == '':
1075 data['substance'] = inn_name
1076 _log.info('linking INN [%s] rather than molecularName as component', inn_name)
1077 else:
1078 data['substance'] = molecule_name
1079
1080 data['nature'] = fd_xml_comp.attrib['nature'].strip()
1081 data['nature_ID'] = fd_xml_comp.attrib['natureLink'].strip()
1082
1083
1084 try:
1085 old_data = comp_data[data['nature_ID']]
1086
1087 if old_data['inn_name'] == '':
1088 old_data['inn_name'] = data['inn_name']
1089 if data['inn_name'] == '':
1090 data['inn_name'] = old_data['inn_name']
1091
1092 if old_data['molecule_name'] == '':
1093 old_data['molecule_name'] = data['molecule_name']
1094 if data['molecule_name'] == '':
1095 data['molecule_name'] = old_data['molecule_name']
1096
1097 if old_data['atc'] == '':
1098 old_data['atc'] = data['atc']
1099 if data['atc'] == '':
1100 data['atc'] = old_data['atc']
1101
1102
1103
1104
1105
1106
1107 if data['nature'] == 'FT':
1108 comp_data[data['nature_ID']] = data
1109 else:
1110 comp_data[data['nature_ID']] = old_data
1111
1112
1113 except KeyError:
1114 comp_data[data['nature_ID']] = data
1115
1116
1117 for key, data in comp_data.items():
1118 new_drug.add_component (
1119 substance = data['substance'],
1120 atc = data['atc'],
1121 amount = data['amount'],
1122 unit = data['unit']
1123 )
1124
1126
1127 db_def = fd2gm_xml.find('DrugsDatabaseName')
1128 db_id = db_def.text.strip()
1129 drug_id_name = db_def.attrib['drugUidName']
1130 fd_xml_drug_entries = fd2gm_xml.findall('FullPrescription/Prescription')
1131
1132 self.__imported_drugs = []
1133 for fd_xml_drug in fd_xml_drug_entries:
1134 drug_uid = fd_xml_drug.find('Drug_UID').text.strip()
1135 if drug_uid == '-1':
1136 _log.debug('skipping textual drug')
1137 continue
1138 drug_name = fd_xml_drug.find('DrugName').text.replace(', )', ')').strip()
1139 drug_form = fd_xml_drug.find('DrugForm').text.strip()
1140 drug_atc = fd_xml_drug.find('DrugATC')
1141 if drug_atc is None:
1142 drug_atc = ''
1143 else:
1144 if drug_atc.text is None:
1145 drug_atc = ''
1146 else:
1147 drug_atc = drug_atc.text.strip()
1148
1149
1150 new_drug = gmMedication.create_drug_product(product_name = drug_name, preparation = drug_form, return_existing = True)
1151 self.__imported_drugs.append(new_drug)
1152 new_drug['is_fake_product'] = False
1153 new_drug['atc'] = drug_atc
1154 new_drug['external_code_type'] = 'FreeDiams::%s::%s' % (db_id, drug_id_name)
1155 new_drug['external_code'] = drug_uid
1156 new_drug['pk_data_source'] = pk_data_source
1157 new_drug.save()
1158
1159
1160 fd_xml_components = fd_xml_drug.getiterator('Composition')
1161 comp_data = {}
1162 for fd_xml_comp in fd_xml_components:
1163
1164 data = {}
1165
1166 amount = regex.match(r'\d+[.,]{0,1}\d*', fd_xml_comp.attrib['strenght'].strip())
1167 if amount is None:
1168 amount = 99999
1169 else:
1170 amount = amount.group()
1171 data['amount'] = amount
1172
1173 unit = regex.sub(r'\d+[.,]{0,1}\d*', '', fd_xml_comp.attrib['strenght'].strip()).strip()
1174 if unit == '':
1175 unit = '*?*'
1176 data['unit'] = unit
1177
1178 molecule_name = fd_xml_comp.attrib['molecularName'].strip()
1179 if molecule_name != '':
1180 gmMedication.create_substance_dose(substance = molecule_name, atc = None, amount = amount, unit = unit)
1181 data['molecule_name'] = molecule_name
1182
1183 inn_name = fd_xml_comp.attrib['inn'].strip()
1184 if inn_name != '':
1185 gmMedication.create_substance_dose(substance = inn_name, atc = None, amount = amount, unit = unit)
1186 data['inn_name'] = molecule_name
1187
1188 if molecule_name == '':
1189 data['substance'] = inn_name
1190 _log.info('linking INN [%s] rather than molecularName as component', inn_name)
1191 else:
1192 data['substance'] = molecule_name
1193
1194 data['nature'] = fd_xml_comp.attrib['nature'].strip()
1195 data['nature_ID'] = fd_xml_comp.attrib['natureLink'].strip()
1196
1197
1198 try:
1199 old_data = comp_data[data['nature_ID']]
1200
1201 if old_data['inn_name'] == '':
1202 old_data['inn_name'] = data['inn_name']
1203 if data['inn_name'] == '':
1204 data['inn_name'] = old_data['inn_name']
1205
1206 if old_data['molecule_name'] == '':
1207 old_data['molecule_name'] = data['molecule_name']
1208 if data['molecule_name'] == '':
1209 data['molecule_name'] = old_data['molecule_name']
1210
1211
1212
1213
1214
1215 if data['nature'] == 'FT':
1216 comp_data[data['nature_ID']] = data
1217 else:
1218 comp_data[data['nature_ID']] = old_data
1219
1220
1221 except KeyError:
1222 comp_data[data['nature_ID']] = data
1223
1224
1225 for key, data in comp_data.items():
1226 new_drug.add_component (
1227 substance = data['substance'],
1228 amount = data['amount'],
1229 unit = data['unit']
1230 )
1231
1232
1233
1234
1236 """empirical CSV interface"""
1237
1240
1242
1243 try:
1244 csv_file = io.open(filename, mode = 'rt', encoding = 'latin1')
1245 except:
1246 _log.exception('cannot access [%s]', filename)
1247 csv_file = None
1248
1249 field_names = 'PZN Handelsname Form Abpackungsmenge Einheit Preis1 Hersteller Preis2 rezeptpflichtig Festbetrag Packungszahl Packungsgr\xf6\xdfe'.split()
1250
1251 if csv_file is None:
1252 return False
1253
1254 csv_lines = csv.DictReader (
1255 csv_file,
1256 fieldnames = field_names,
1257 delimiter = ';'
1258 )
1259
1260 for line in csv_lines:
1261 print("--------------------------------------------------------------------"[:31])
1262 for key in field_names:
1263 tmp = ('%s ' % key)[:30]
1264 print('%s: %s' % (tmp, line[key]))
1265
1266 csv_file.close()
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280 drug_data_source_interfaces = {
1281 'Deutschland: Gelbe Liste/MMI (Windows)': cGelbeListeWindowsInterface,
1282 'Deutschland: Gelbe Liste/MMI (WINE)': cGelbeListeWineInterface,
1283 'FreeDiams (FR, US, CA, ZA)': cFreeDiamsInterface
1284 }
1285
1286
1287
1288
1289 if __name__ == "__main__":
1290
1291 if len(sys.argv) < 2:
1292 sys.exit()
1293
1294 if sys.argv[1] != 'test':
1295 sys.exit()
1296
1297 from Gnumed.business import gmPerson
1298
1299
1305
1307 mmi_file = cGelbeListeCSVFile(filename = sys.argv[2])
1308 for drug in mmi_file:
1309 print("-------------")
1310 print('"%s" (ATC: %s / PZN: %s)' % (drug['name'], drug['atc'], drug['pzn']))
1311 for stoff in drug['wirkstoffe']:
1312 print(" Wirkstoff:", stoff)
1313 input()
1314 if mmi_file.has_unknown_fields is not None:
1315 print("has extra data under [%s]" % gmTools.default_csv_reader_rest_key)
1316 for key in mmi_file.csv_fieldnames:
1317 print(key, '->', drug[key])
1318 input()
1319 mmi_file.close()
1320
1324
1326 mmi = cGelbeListeWineInterface()
1327 mmi_file = mmi.__let_user_select_drugs()
1328 for drug in mmi_file:
1329 print("-------------")
1330 print('"%s" (ATC: %s / PZN: %s)' % (drug['name'], drug['atc'], drug['pzn']))
1331 for stoff in drug['wirkstoffe']:
1332 print(" Wirkstoff:", stoff)
1333 print(drug)
1334 mmi_file.close()
1335
1339
1341 mmi = cGelbeListeInterface()
1342 print(mmi)
1343 print("interface definition:", mmi.version)
1344
1345 diclofenac = '7587712'
1346 phenprocoumon = '4421744'
1347 mmi.check_interactions(drug_ids_list = [diclofenac, phenprocoumon])
1348
1349
1350
1357
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376