1
2 """Medication handling code.
3
4 license: GPL
5 """
6
7 __version__ = "$Revision: 1.21 $"
8 __author__ = "K.Hilbert <Karsten.Hilbert@gmx.net>"
9
10 import sys, logging, csv, codecs, os, re as regex, subprocess, decimal
11 from xml.etree import ElementTree as etree
12
13
14 if __name__ == '__main__':
15 sys.path.insert(0, '../../')
16 from Gnumed.pycommon import gmBusinessDBObject, gmPG2, gmShellAPI, gmTools
17 from Gnumed.pycommon import gmDispatcher, gmDateTime, gmHooks
18 from Gnumed.business import gmATC, gmAllergy
19
20
21 _log = logging.getLogger('gm.meds')
22 _log.info(__version__)
23
24
28
29 gmDispatcher.connect(_on_substance_intake_modified, u'substance_intake_mod_db')
30
31
33
34 if search_term is None:
35 return u'http://www.dosing.de'
36
37 terms = []
38 names = []
39
40 if isinstance(search_term, cBrandedDrug):
41 if search_term['atc_code'] is not None:
42 terms.append(search_term['atc_code'])
43
44 elif isinstance(search_term, cSubstanceIntakeEntry):
45 names.append(search_term['substance'])
46 if search_term['atc_brand'] is not None:
47 terms.append(search_term['atc_brand'])
48 if search_term['atc_substance'] is not None:
49 terms.append(search_term['atc_substance'])
50
51 elif search_term is not None:
52 names.append(u'%s' % search_term)
53 terms.extend(gmATC.text2atc(text = u'%s' % search_term, fuzzy = True))
54
55 for name in names:
56 if name.endswith('e'):
57 terms.append(name[:-1])
58 else:
59 terms.append(name)
60
61
62
63
64 url_template = u'http://www.google.de/search?hl=de&source=hp&q=site%%3Adosing.de+%s&btnG=Google-Suche'
65 url = url_template % u'+OR+'.join(terms)
66
67 _log.debug(u'renal insufficiency URL: %s', url)
68
69 return url
70
71
72 -def create_data_source(long_name=None, short_name=None, version=None, source=None, language=None):
73
74 args = {
75 'lname': long_name,
76 'sname': short_name,
77 'ver': version,
78 'src': source,
79 'lang': language
80 }
81
82 cmd = u"""select pk from ref.data_source where name_long = %(lname)s and name_short = %(sname)s and version = %(ver)s"""
83 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}])
84 if len(rows) > 0:
85 return rows[0]['pk']
86
87 cmd = u"""
88 INSERT INTO ref.data_source (name_long, name_short, version, source, lang)
89 VALUES (
90 %(lname)s,
91 %(sname)s,
92 %(ver)s,
93 %(src)s,
94 %(lang)s
95 )
96 returning pk
97 """
98 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True)
99
100 return rows[0]['pk']
101
102
103
104
105
106
107
109 """Iterator over a Gelbe Liste/MMI v8.2 CSV file."""
110
111 version = u'Gelbe Liste/MMI v8.2 CSV file interface'
112 default_transfer_file_windows = r"c:\rezept.txt"
113
114 default_encoding = 'cp1250'
115 csv_fieldnames = [
116 u'name',
117 u'packungsgroesse',
118 u'darreichungsform',
119 u'packungstyp',
120 u'festbetrag',
121 u'avp',
122 u'hersteller',
123 u'rezepttext',
124 u'pzn',
125 u'status_vertrieb',
126 u'status_rezeptpflicht',
127 u'status_fachinfo',
128 u'btm',
129 u'atc',
130 u'anzahl_packungen',
131 u'zuzahlung_pro_packung',
132 u'einheit',
133 u'schedule_morgens',
134 u'schedule_mittags',
135 u'schedule_abends',
136 u'schedule_nachts',
137 u'status_dauermedikament',
138 u'status_hausliste',
139 u'status_negativliste',
140 u'ik_nummer',
141 u'status_rabattvertrag',
142 u'wirkstoffe',
143 u'wirkstoffmenge',
144 u'wirkstoffeinheit',
145 u'wirkstoffmenge_bezug',
146 u'wirkstoffmenge_bezugseinheit',
147 u'status_import',
148 u'status_lifestyle',
149 u'status_ausnahmeliste',
150 u'packungsmenge',
151 u'apothekenpflicht',
152 u'status_billigere_packung',
153 u'rezepttyp',
154 u'besonderes_arzneimittel',
155 u't_rezept_pflicht',
156 u'erstattbares_medizinprodukt',
157 u'hilfsmittel',
158 u'hzv_rabattkennung',
159 u'hzv_preis'
160 ]
161 boolean_fields = [
162 u'status_rezeptpflicht',
163 u'status_fachinfo',
164 u'btm',
165 u'status_dauermedikament',
166 u'status_hausliste',
167 u'status_negativliste',
168 u'status_rabattvertrag',
169 u'status_import',
170 u'status_lifestyle',
171 u'status_ausnahmeliste',
172 u'apothekenpflicht',
173 u'status_billigere_packung',
174 u'besonderes_arzneimittel',
175 u't_rezept_pflicht',
176 u'erstattbares_medizinprodukt',
177 u'hilfsmittel'
178 ]
179
199
202
204 line = self.csv_lines.next()
205
206 for field in cGelbeListeCSVFile.boolean_fields:
207 line[field] = (line[field].strip() == u'T')
208
209
210 if line['wirkstoffe'].strip() == u'':
211 line['wirkstoffe'] = []
212 else:
213 line['wirkstoffe'] = [ wirkstoff.strip() for wirkstoff in line['wirkstoffe'].split(u';') ]
214
215 return line
216
217 - def close(self, truncate=True):
218 try: self.csv_file.close()
219 except: pass
220
221 if truncate:
222 try: os.open(self.filename, 'wb').close
223 except: pass
224
227
228 has_unknown_fields = property(_get_has_unknown_fields, lambda x:x)
229
231
232
234 self.patient = None
235 self.custom_path_to_binary = None
236
238 raise NotImplementedError
239
241 raise NotImplementedError
242
244 raise NotImplementedError
245
247 raise NotImplementedError
248
250 raise NotImplementedError
251
253 raise NotImplementedError
254
256 raise NotImplementedError
257
259 raise NotImplementedError
260
262
263 version = u'FreeDiams v0.5.0 interface'
264 default_encoding = 'utf8'
265 default_dob_format = '%Y/%m/%d'
266
267 map_gender2mf = {
268 'm': u'M',
269 'f': u'F',
270 'tf': u'H',
271 'tm': u'H',
272 'h': u'H'
273 }
274
286
288
289
290 if not self.__detect_binary():
291 return False
292
293 freediams = subprocess.Popen (
294 args = u'--version',
295 executable = self.path_to_binary,
296 stdout = subprocess.PIPE,
297 stderr = subprocess.PIPE,
298
299 universal_newlines = True
300 )
301 data, errors = freediams.communicate()
302 version = regex.search('FreeDiams\s\d.\d.\d', data).group().split()[1]
303 _log.debug('FreeDiams %s', version)
304
305 return version
306
308 return create_data_source (
309 long_name = u'"FreeDiams" Drug Database Frontend',
310 short_name = u'FreeDiams',
311 version = self.get_data_source_version(),
312 source = u'http://ericmaeker.fr/FreeMedForms/di-manual/index.html',
313 language = u'fr'
314 )
315
317 """http://ericmaeker.fr/FreeMedForms/di-manual/en/html/ligne_commandes.html"""
318
319 if not self.__detect_binary():
320 return False
321
322 self.__create_gm2fd_file()
323 open(self.__fd2gm_filename, 'wb').close()
324
325 args = u'--exchange-in="%s"' % (self.__gm2fd_filename)
326 cmd = r'%s %s' % (self.path_to_binary, args)
327 if not gmShellAPI.run_command_in_shell(command = cmd, blocking = blocking):
328 _log.error('problem switching to the FreeDiams drug database')
329 return False
330
331 return True
332
335
337 """FreeDiams ONLY use CIS.
338
339 CIS stands for Unique Speciality Identifier (eg bisoprolol 5 mg, gel).
340 CIS is AFSSAPS specific, but pharmacist can retreive drug name with the CIS.
341 AFSSAPS is the French FDA.
342
343 CIP stands for Unique Presentation Identifier (eg 30 pills plaq)
344 CIP if you want to specify the packaging of the drug (30 pills
345 thermoformed tablet...) -- actually not really usefull for french
346 doctors.
347 # .external_code_type: u'FR-CIS'
348 # .external_cod: the CIS value
349 """
350 self.switch_to_frontend(blocking = True)
351 self.import_fd2gm_file()
352
354
355 if substances is None:
356 return
357 if len(substances) < 2:
358 return
359 drug_ids_list = [ (s.external_code_type, s.external_code) for s in substances ]
360 drug_ids_list = [ (code_value, code_type) for code_type, code_value in drug_ids_list if (code_value is not None)]
361
362 if drug_ids_list < 2:
363 return
364
365 self.__create_prescription_file(drug_ids_list = drug_ids_list)
366 self.switch_to_frontend(blocking = False)
367
372
380
381
382
384
385 if self.path_to_binary is not None:
386 return True
387
388 found, cmd = gmShellAPI.find_first_binary(binaries = [
389 r'/usr/bin/freediams',
390 r'freediams',
391 r'/Applications/FreeDiams.app/Contents/MacOs/FreeDiams',
392 r'c:\programs\freediams\freediams.exe',
393 r'freediams.exe'
394 ])
395
396 if found:
397 self.path_to_binary = cmd
398 return True
399
400 try:
401 self.custom_path_to_binary
402 except AttributeError:
403 _log.error('cannot find FreeDiams binary, no custom path set')
404 return False
405
406 found, cmd = gmShellAPI.detect_external_binary(binary = self.custom_path_to_binary)
407 if found:
408 self.path_to_binary = cmd
409 return True
410
411 _log.error('cannot find FreeDiams binary')
412 return False
413
415
416
417
418 xml = u"""<?xml version = "1.0" encoding = "UTF-8"?>
419
420 <FreeDiams>
421 <DrugsDatabaseName>%s</DrugsDatabaseName>
422 <FullPrescription version="0.4.0">
423
424 %s
425
426 </FullPrescription>
427 </FreeDiams>
428 """
429 drug_snippet = u"""<Prescription>
430 <OnlyForTest>True</OnlyForTest>
431 <Drug_UID>%s</Drug_UID>
432 <!-- <Drug_UID_type>%s</Drug_UID_type> -->
433 </Prescription>"""
434
435 xml_file = codecs.open(self.__fd2gm_filename, 'wb', 'utf8')
436
437 last_db_id = u'CA_HCDPD'
438 drug_snippets = []
439 for drug_id, db_id in drug_ids_list:
440 if db_id is not None:
441 last_db_id = db_id.replace(u'FreeDiams::', u'')
442 drug_snippets.append(drug_snippet % (drug_id, last_db_id))
443
444 xml_file.write(xml % (
445 last_db_id,
446 u'\n\t\t'.join(drug_snippets)
447 ))
448
449 xml_file.close()
450
452
453 xml_file = codecs.open(self.__gm2fd_filename, 'wb', 'utf8')
454
455 xml = u"""<?xml version="1.0" encoding="UTF-8"?>
456
457 <!-- Eric says the order of same-level nodes does not matter. -->
458
459 <FreeDiams_In version="0.5.0">
460 <EMR name="GNUmed" uid="unused"/>
461 <ConfigFile value="%s"/>
462 <ExchangeOut value="%s" format="xml"/> <!-- should perhaps better be html_xml ? -->
463 <!-- <DrugsDatabase uid="can be set to a specific DB"/> -->
464 <Ui editmode="select-only" blockPatientDatas="1"/>
465 %%s
466 </FreeDiams_In>
467
468 <!--
469 # FIXME: search by LOINC code and add (as soon as supported by FreeDiams ...)
470 <Creatinine value="12" unit="mg/l or mmol/l"/>
471 <Weight value="70" unit="kg or pd" />
472 <Height value="170" unit="cm or "/>
473 <ICD10 value="J11.0;A22;Z23"/>
474 -->
475 """ % (
476 self.__fd4gm_config_file,
477 self.__fd2gm_filename
478 )
479
480 if self.patient is None:
481 xml_file.write(xml % u'')
482 xml_file.close()
483 return
484
485 name = self.patient.get_active_name()
486 if self.patient['dob'] is None:
487 dob = u''
488 else:
489 dob = self.patient['dob'].strftime(cFreeDiamsInterface.default_dob_format)
490
491 emr = self.patient.get_emr()
492 allgs = emr.get_allergies()
493 atc_allgs = [
494 a['atc_code'] for a in allgs if ((a['atc_code'] is not None) and (a['type'] == u'allergy'))
495 ]
496 atc_sens = [
497 a['atc_code'] for a in allgs if ((a['atc_code'] is not None) and (a['type'] == u'sensitivity'))
498 ]
499 inn_allgs = [ a['allergene'] for a in allgs if a['type'] == u'allergy' ]
500 inn_sens = [ a['allergene'] for a in allgs if a['type'] == u'sensitivity' ]
501
502
503 uid_allgs = [
504 a['substance_code'] for a in allgs if ((a['substance_code'] is not None) and (a['type'] == u'allergy'))
505 ]
506 uid_sens = [
507 a['substance_code'] for a in allgs if ((a['substance_code'] is not None) and (a['type'] == u'sensitivity'))
508 ]
509
510 patient_xml = u"""<Patient>
511 <Identity
512 lastnames="%s"
513 firstnames="%s"
514 uid="%s"
515 dob="%s"
516 gender="%s"
517 />
518 <ATCAllergies value="%s"/>
519 <ATCIntolerances value="%s"/>
520
521 <InnAllergies value="%s"/>
522 <InnIntolerances value="%s"/>
523
524 <DrugsUidAllergies value="%s"/>
525 <DrugsUidIntolerances value="%s"/>
526 </Patient>
527 """ % (
528 name['lastnames'],
529 name['firstnames'],
530 self.patient.ID,
531 dob,
532 cFreeDiamsInterface.map_gender2mf[self.patient['gender']],
533 u';'.join(atc_allgs),
534 u';'.join(atc_sens),
535 u';'.join(inn_allgs),
536 u';'.join(inn_sens),
537 u';'.join(uid_allgs),
538 u';'.join(uid_sens)
539 )
540
541 xml_file.write(xml % patient_xml)
542 xml_file.close()
543
545 """
546 If returning textual prescriptions (say, drugs which FreeDiams
547 did not know) then "IsTextual" will be True and UID will be -1.
548 """
549 fd2gm_xml = etree.ElementTree()
550 fd2gm_xml.parse(self.__fd2gm_filename)
551
552 data_src_pk = self.create_data_source_entry()
553
554 db_id = fd2gm_xml.find('DrugsDatabaseName').text.strip()
555 drugs = fd2gm_xml.findall('FullPrescription/Prescription')
556 for drug in drugs:
557 drug_name = drug.find('DrugName').text.replace(', )', ')').strip()
558 drug_uid = drug.find('Drug_UID').text.strip()
559 drug_form = drug.find('DrugForm').text.strip()
560
561
562 new_drug = create_branded_drug(brand_name = drug_name, preparation = drug_form, return_existing = True)
563
564 new_drug['is_fake_brand'] = False
565
566 new_drug['external_code_type'] = u'FreeDiams::%s' % db_id
567 new_drug['external_code'] = drug_uid
568 new_drug['pk_data_source'] = data_src_pk
569 new_drug.save()
570
571 components = drug.getiterator('Composition')
572 for comp in components:
573
574 subst = comp.attrib['molecularName'].strip()
575
576 amount = regex.match(r'\d+[.,]{0,1}\d*', comp.attrib['strenght'].strip())
577 if amount is None:
578 amount = 99999
579 else:
580 amount = amount.group()
581
582 unit = regex.sub(r'\d+[.,]{0,1}\d*', u'', comp.attrib['strenght'].strip()).strip()
583 if unit == u'':
584 unit = u'*?*'
585
586 inn = comp.attrib['inn'].strip()
587 if inn != u'':
588 create_consumable_substance(substance = inn, atc = None, amount = amount, unit = unit)
589 if subst == u'':
590 subst = inn
591
592 new_drug.add_component(substance = subst, atc = None, amount = amount, unit = unit)
593
595 """Support v8.2 CSV file interface only."""
596
597 version = u'Gelbe Liste/MMI v8.2 interface'
598 default_encoding = 'cp1250'
599 bdt_line_template = u'%03d6210#%s\r\n'
600 bdt_line_base_length = 8
601
603
604 cDrugDataSourceInterface.__init__(self)
605
606 _log.info(u'%s (native Windows)', cGelbeListeWindowsInterface.version)
607
608 self.path_to_binary = r'C:\Programme\MMI PHARMINDEX\glwin.exe'
609 self.args = r'-KEEPBACKGROUND -PRESCRIPTIONFILE %s -CLOSETOTRAY'
610
611 paths = gmTools.gmPaths()
612
613 self.default_csv_filename = os.path.join(paths.home_dir, '.gnumed', 'tmp', 'rezept.txt')
614 self.default_csv_filename_arg = os.path.join(paths.home_dir, '.gnumed', 'tmp')
615 self.interactions_filename = os.path.join(paths.home_dir, '.gnumed', 'tmp', 'gm2mmi.bdt')
616 self.data_date_filename = r'C:\Programme\MMI PHARMINDEX\datadate.txt'
617
618 self.__data_date = None
619 self.__online_update_date = None
620
621
622
624
625 if self.__data_date is not None:
626 if not force_reload:
627 return {
628 'data': self.__data_date,
629 'online_update': self.__online_update_date
630 }
631
632 open(self.data_date_filename, 'wb').close()
633
634 cmd = u'%s -DATADATE' % self.path_to_binary
635 if not gmShellAPI.run_command_in_shell(command = cmd, blocking = True):
636 _log.error('problem querying the MMI drug database for version information')
637 self.__data_date = None
638 self.__online_update_date = None
639 return {
640 'data': u'?',
641 'online_update': u'?'
642 }
643
644 try:
645 version_file = open(self.data_date_filename, 'rU')
646 except StandardError:
647 _log.error('problem querying the MMI drug database for version information')
648 _log.exception('cannot open MMI drug database version file [%s]', self.data_date_filename)
649 self.__data_date = None
650 self.__online_update_date = None
651 return {
652 'data': u'?',
653 'online_update': u'?'
654 }
655
656 self.__data_date = version_file.readline()[:10]
657 self.__online_update_date = version_file.readline()[:10]
658 version_file.close()
659
660 return {
661 'data': self.__data_date,
662 'online_update': self.__online_update_date
663 }
664
666 versions = self.get_data_source_version()
667
668 return create_data_source (
669 long_name = u'Medikamentendatenbank "mmi PHARMINDEX" (Gelbe Liste)',
670 short_name = u'GL/MMI',
671 version = u'Daten: %s, Preise (Onlineupdate): %s' % (versions['data'], versions['online_update']),
672 source = u'Medizinische Medien Informations GmbH, Am Forsthaus Gravenbruch 7, 63263 Neu-Isenburg',
673 language = u'de'
674 )
675
677
678
679 open(self.default_csv_filename, 'wb').close()
680
681 if cmd is None:
682 cmd = (u'%s %s' % (self.path_to_binary, self.args)) % self.default_csv_filename_arg
683
684 if not gmShellAPI.run_command_in_shell(command = cmd, blocking = blocking):
685 _log.error('problem switching to the MMI drug database')
686
687
688
689
690 return True
691
701
703
704 selected_drugs = self.select_drugs()
705 if selected_drugs is None:
706 return None
707
708 new_substances = []
709
710 for drug in selected_drugs:
711 atc = None
712 if len(drug['wirkstoffe']) == 1:
713 atc = drug['atc']
714 for wirkstoff in drug['wirkstoffe']:
715 new_substances.append(create_consumable_substance(substance = wirkstoff, atc = atc, amount = amount, unit = unit))
716
717 selected_drugs.close()
718
719 return new_substances
720
722
723 selected_drugs = self.select_drugs()
724 if selected_drugs is None:
725 return None
726
727 data_src_pk = self.create_data_source_entry()
728
729 new_drugs = []
730 new_substances = []
731
732 for entry in selected_drugs:
733
734 _log.debug('importing drug: %s %s', entry['name'], entry['darreichungsform'])
735
736 if entry[u'hilfsmittel']:
737 _log.debug('skipping Hilfsmittel')
738 continue
739
740 if entry[u'erstattbares_medizinprodukt']:
741 _log.debug('skipping sonstiges Medizinprodukt')
742 continue
743
744
745 drug = create_branded_drug(brand_name = entry['name'], preparation = entry['darreichungsform'])
746 if drug is None:
747 drug = get_drug_by_brand(brand_name = entry['name'], preparation = entry['darreichungsform'])
748 new_drugs.append(drug)
749
750
751 drug['is_fake'] = False
752 drug['atc_code'] = entry['atc']
753 drug['external_code_type'] = u'DE-PZN'
754 drug['external_code'] = entry['pzn']
755 drug['fk_data_source'] = data_src_pk
756 drug.save()
757
758
759 atc = None
760 if len(entry['wirkstoffe']) == 1:
761 atc = entry['atc']
762 for wirkstoff in entry['wirkstoffe']:
763 drug.add_component(substance = wirkstoff, atc = atc)
764
765
766 atc = None
767 if len(entry['wirkstoffe']) == 1:
768 atc = entry['atc']
769 for wirkstoff in entry['wirkstoffe']:
770 new_substances.append(create_consumable_substance(substance = wirkstoff, atc = atc, amount = amount, unit = unit))
771
772 return new_drugs, new_substances
773
802
805
824
826
828 cGelbeListeWindowsInterface.__init__(self)
829
830 _log.info(u'%s (WINE extension)', cGelbeListeWindowsInterface.version)
831
832
833 self.path_to_binary = r'wine "C:\Programme\MMI PHARMINDEX\glwin.exe"'
834 self.args = r'"-PRESCRIPTIONFILE %s -KEEPBACKGROUND"'
835
836 paths = gmTools.gmPaths()
837
838 self.default_csv_filename = os.path.join(paths.home_dir, '.wine', 'drive_c', 'windows', 'temp', 'mmi2gm.csv')
839 self.default_csv_filename_arg = r'c:\windows\temp\mmi2gm.csv'
840 self.interactions_filename = os.path.join(paths.home_dir, '.wine', 'drive_c', 'windows', 'temp', 'gm2mmi.bdt')
841 self.data_date_filename = os.path.join(paths.home_dir, '.wine', 'drive_c', 'Programme', 'MMI PHARMINDEX', 'datadate.txt')
842
844 """empirical CSV interface"""
845
848
850
851 try:
852 csv_file = open(filename, 'rb')
853 except:
854 _log.exception('cannot access [%s]', filename)
855 csv_file = None
856
857 field_names = u'PZN Handelsname Form Abpackungsmenge Einheit Preis1 Hersteller Preis2 rezeptpflichtig Festbetrag Packungszahl Packungsgr\xf6\xdfe'.split()
858
859 if csv_file is None:
860 return False
861
862 csv_lines = csv.DictReader (
863 csv_file,
864 fieldnames = field_names,
865 delimiter = ';'
866 )
867
868 for line in csv_lines:
869 print "--------------------------------------------------------------------"[:31]
870 for key in field_names:
871 tmp = ('%s ' % key)[:30]
872 print '%s: %s' % (tmp, line[key])
873
874 csv_file.close()
875
876
877
878
879
880
881
882
883
884
885
886
887 drug_data_source_interfaces = {
888 'Deutschland: Gelbe Liste/MMI (Windows)': cGelbeListeWindowsInterface,
889 'Deutschland: Gelbe Liste/MMI (WINE)': cGelbeListeWineInterface,
890 'FreeDiams (France, US, Canada)': cFreeDiamsInterface
891 }
892
893
894
895
896 _SQL_get_consumable_substance = u"""
897 SELECT *, xmin
898 FROM ref.consumable_substance
899 WHERE %s
900 """
901
903
904 _cmd_fetch_payload = _SQL_get_consumable_substance % u"pk = %s"
905 _cmds_store_payload = [
906 u"""UPDATE ref.consumable_substance SET
907 description = %(description)s,
908 atc_code = gm.nullify_empty_string(%(atc_code)s),
909 amount = %(amount)s,
910 unit = gm.nullify_empty_string(%(unit)s)
911 WHERE
912 pk = %(pk)s
913 AND
914 xmin = %(xmin)s
915 AND
916 -- must not currently be used with a patient directly
917 NOT EXISTS (
918 SELECT 1
919 FROM clin.substance_intake
920 WHERE
921 fk_drug_component IS NULL
922 AND
923 fk_substance = %(pk)s
924 LIMIT 1
925 )
926 AND
927 -- must not currently be used with a patient indirectly, either
928 NOT EXISTS (
929 SELECT 1
930 FROM clin.substance_intake
931 WHERE
932 fk_drug_component IS NOT NULL
933 AND
934 fk_drug_component = (
935 SELECT r_ls2b.pk
936 FROM ref.lnk_substance2brand r_ls2b
937 WHERE fk_substance = %(pk)s
938 )
939 LIMIT 1
940 )
941 -- -- must not currently be used with a branded drug
942 -- -- (but this would make it rather hard fixing branded drugs which contain only this substance)
943 -- NOT EXISTS (
944 -- SELECT 1
945 -- FROM ref.lnk_substance2brand
946 -- WHERE fk_substance = %(pk)s
947 -- LIMIT 1
948 -- )
949 RETURNING
950 xmin
951 """
952 ]
953 _updatable_fields = [
954 u'description',
955 u'atc_code',
956 u'amount',
957 u'unit'
958 ]
959
961 success, data = super(self.__class__, self).save_payload(conn = conn)
962
963 if not success:
964 return (success, data)
965
966 if self._payload[self._idx['atc_code']] is not None:
967 atc = self._payload[self._idx['atc_code']].strip()
968 if atc != u'':
969 gmATC.propagate_atc (
970 substance = self._payload[self._idx['description']].strip(),
971 atc = atc
972 )
973
974 return (success, data)
975
976
977
979 cmd = u"""
980 SELECT
981 EXISTS (
982 SELECT 1
983 FROM clin.substance_intake
984 WHERE
985 fk_drug_component IS NULL
986 AND
987 fk_substance = %(pk)s
988 LIMIT 1
989 ) OR EXISTS (
990 SELECT 1
991 FROM clin.substance_intake
992 WHERE
993 fk_drug_component IS NOT NULL
994 AND
995 fk_drug_component = (
996 SELECT r_ls2b.pk
997 FROM ref.lnk_substance2brand r_ls2b
998 WHERE fk_substance = %(pk)s
999 )
1000 LIMIT 1
1001 )"""
1002 args = {'pk': self.pk_obj}
1003
1004 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
1005 return rows[0][0]
1006
1007 is_in_use_by_patients = property(_get_is_in_use_by_patients, lambda x:x)
1008
1010 cmd = u"""
1011 SELECT EXISTS (
1012 SELECT 1
1013 FROM ref.lnk_substance2brand
1014 WHERE fk_substance = %(pk)s
1015 LIMIT 1
1016 )"""
1017 args = {'pk': self.pk_obj}
1018
1019 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
1020 return rows[0][0]
1021
1022 is_drug_component = property(_get_is_drug_component, lambda x:x)
1023
1032
1034
1035 substance = substance
1036 if atc is not None:
1037 atc = atc.strip()
1038
1039 args = {
1040 'desc': substance.strip(),
1041 'amount': decimal.Decimal(amount),
1042 'unit': unit.strip(),
1043 'atc': atc
1044 }
1045 cmd = u"""
1046 SELECT pk FROM ref.consumable_substance
1047 WHERE
1048 lower(description) = lower(%(desc)s)
1049 AND
1050 amount = %(amount)s
1051 AND
1052 unit = %(unit)s
1053 """
1054 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}])
1055
1056 if len(rows) == 0:
1057 cmd = u"""
1058 INSERT INTO ref.consumable_substance (description, atc_code, amount, unit) VALUES (
1059 %(desc)s,
1060 gm.nullify_empty_string(%(atc)s),
1061 %(amount)s,
1062 gm.nullify_empty_string(%(unit)s)
1063 ) RETURNING pk"""
1064 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True, get_col_idx = False)
1065
1066 gmATC.propagate_atc(substance = substance, atc = atc)
1067
1068 return cConsumableSubstance(aPK_obj = rows[0]['pk'])
1069
1071 args = {'pk': substance}
1072 cmd = u"""
1073 DELETE FROM ref.consumable_substance
1074 WHERE
1075 pk = %(pk)s
1076 AND
1077
1078 -- must not currently be used with a patient
1079 NOT EXISTS (
1080 SELECT 1
1081 FROM clin.v_pat_substance_intake
1082 WHERE pk_substance = %(pk)s
1083 LIMIT 1
1084 )
1085 AND
1086
1087 -- must not currently be used with a branded drug
1088 NOT EXISTS (
1089 SELECT 1
1090 FROM ref.lnk_substance2brand
1091 WHERE fk_substance = %(pk)s
1092 LIMIT 1
1093 )"""
1094 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
1095 return True
1096
1097 -class cSubstanceIntakeEntry(gmBusinessDBObject.cBusinessDBObject):
1098 """Represents a substance currently taken by a patient."""
1099
1100 _cmd_fetch_payload = u"SELECT * FROM clin.v_pat_substance_intake WHERE pk_substance_intake = %s"
1101 _cmds_store_payload = [
1102 u"""UPDATE clin.substance_intake SET
1103 clin_when = %(started)s,
1104 discontinued = %(discontinued)s,
1105 discontinue_reason = gm.nullify_empty_string(%(discontinue_reason)s),
1106 preparation = %(preparation)s,
1107 schedule = gm.nullify_empty_string(%(schedule)s),
1108 aim = gm.nullify_empty_string(%(aim)s),
1109 narrative = gm.nullify_empty_string(%(notes)s),
1110 intake_is_approved_of = %(intake_is_approved_of)s,
1111
1112 -- is_long_term = %(is_long_term)s,
1113 is_long_term = (
1114 case
1115 when (
1116 (%(is_long_term)s is False)
1117 and
1118 (%(duration)s is NULL)
1119 ) is True then null
1120 else %(is_long_term)s
1121 end
1122 )::boolean,
1123 duration = (
1124 case
1125 when %(is_long_term)s is True then null
1126 else %(duration)s
1127 end
1128 )::interval,
1129
1130 fk_drug_component = %(pk_drug_component)s,
1131 fk_substance = %(pk_substance)s,
1132 fk_episode = %(pk_episode)s
1133 WHERE
1134 pk = %(pk_substance_intake)s
1135 AND
1136 xmin = %(xmin_substance_intake)s
1137 RETURNING
1138 xmin as xmin_substance_intake
1139 """
1140 ]
1141 _updatable_fields = [
1142 u'started',
1143 u'discontinued',
1144 u'discontinue_reason',
1145 u'preparation',
1146 u'intake_is_approved_of',
1147 u'schedule',
1148 u'duration',
1149 u'aim',
1150 u'is_long_term',
1151 u'notes',
1152 u'pk_drug_component',
1153 u'pk_substance',
1154 u'pk_episode'
1155 ]
1156
1157 - def format(self, left_margin=0, date_format='%Y-%m-%d'):
1158
1159 if self._payload[self._idx['duration']] is None:
1160 duration = gmTools.bool2subst (
1161 self._payload[self._idx['is_long_term']],
1162 _('long-term'),
1163 _('short-term'),
1164 _('?short-term')
1165 )
1166 else:
1167 duration = gmDateTime.format_interval (
1168 self._payload[self._idx['duration']],
1169 accuracy_wanted = gmDateTime.acc_days
1170 )
1171
1172 line = u'%s%s (%s %s): %s %s%s %s (%s)' % (
1173 u' ' * left_margin,
1174 self._payload[self._idx['started']].strftime(date_format),
1175 gmTools.u_right_arrow,
1176 duration,
1177 self._payload[self._idx['substance']],
1178 self._payload[self._idx['amount']],
1179 self._payload[self._idx['unit']],
1180 self._payload[self._idx['preparation']],
1181 gmTools.bool2subst(self._payload[self._idx['is_currently_active']], _('ongoing'), _('inactive'), _('?ongoing'))
1182 )
1183
1184 return line
1185
1186 - def turn_into_allergy(self, encounter_id=None, allergy_type='allergy'):
1187 allg = gmAllergy.create_allergy (
1188 allergene = self._payload[self._idx['substance']],
1189 allg_type = allergy_type,
1190 episode_id = self._payload[self._idx['pk_episode']],
1191 encounter_id = encounter_id
1192 )
1193 allg['substance'] = gmTools.coalesce (
1194 self._payload[self._idx['brand']],
1195 self._payload[self._idx['substance']]
1196 )
1197 allg['reaction'] = self._payload[self._idx['discontinue_reason']]
1198 allg['atc_code'] = gmTools.coalesce(self._payload[self._idx['atc_substance']], self._payload[self._idx['atc_brand']])
1199 if self._payload[self._idx['external_code_brand']] is not None:
1200 allg['substance_code'] = u'%s::::%s' % (self._payload[self._idx['external_code_type_brand']], self._payload[self._idx['external_code_brand']])
1201 allg['allergene'] = self._payload[self._idx['substance']]
1202 comps = [ c['substance'] for c in self.containing_drug.components ]
1203 if len(comps) == 0:
1204 allg['generics'] = self._payload[self._idx['substance']]
1205 else:
1206 allg['generics'] = u'; '.join(comps)
1207
1208 allg.save()
1209 return allg
1210
1211
1212
1213 - def _get_ddd(self):
1214
1215 try: self.__ddd
1216 except AttributeError: self.__ddd = None
1217
1218 if self.__ddd is not None:
1219 return self.__ddd
1220
1221 if self._payload[self._idx['atc_substance']] is not None:
1222 ddd = gmATC.atc2ddd(atc = self._payload[self._idx['atc_substance']])
1223 if len(ddd) != 0:
1224 self.__ddd = ddd[0]
1225 else:
1226 if self._payload[self._idx['atc_brand']] is not None:
1227 ddd = gmATC.atc2ddd(atc = self._payload[self._idx['atc_brand']])
1228 if len(ddd) != 0:
1229 self.__ddd = ddd[0]
1230
1231 return self.__ddd
1232
1233 ddd = property(_get_ddd, lambda x:x)
1234
1236 drug = self.containing_drug
1237
1238 if drug is None:
1239 return None
1240
1241 return drug.external_code
1242
1243 external_code = property(_get_external_code, lambda x:x)
1244
1246 drug = self.containing_drug
1247
1248 if drug is None:
1249 return None
1250
1251 return drug.external_code_type
1252
1253 external_code_type = property(_get_external_code_type, lambda x:x)
1254
1256 if self._payload[self._idx['pk_brand']] is None:
1257 return None
1258
1259 return cBrandedDrug(aPK_obj = self._payload[self._idx['pk_brand']])
1260
1261 containing_drug = property(_get_containing_drug, lambda x:x)
1262
1264 tests = [
1265
1266 ' 1-1-1-1 ',
1267
1268 '1-1-1-1',
1269 '22-1-1-1',
1270 '1/3-1-1-1',
1271 '/4-1-1-1'
1272 ]
1273 pattern = "^(\d\d|/\d|\d/\d|\d)[\s-]{1,5}\d{0,2}[\s-]{1,5}\d{0,2}[\s-]{1,5}\d{0,2}$"
1274 for test in tests:
1275 print test.strip(), ":", regex.match(pattern, test.strip())
1276
1277 -def create_substance_intake(pk_substance=None, pk_component=None, preparation=None, encounter=None, episode=None):
1278
1279 args = {
1280 'enc': encounter,
1281 'epi': episode,
1282 'comp': pk_component,
1283 'subst': pk_substance,
1284 'prep': preparation
1285 }
1286
1287 if pk_component is None:
1288 cmd = u"""
1289 INSERT INTO clin.substance_intake (
1290 fk_encounter,
1291 fk_episode,
1292 intake_is_approved_of,
1293 fk_substance,
1294 preparation
1295 ) VALUES (
1296 %(enc)s,
1297 %(epi)s,
1298 False,
1299 %(subst)s,
1300 %(prep)s
1301 )
1302 RETURNING pk"""
1303 else:
1304 cmd = u"""
1305 INSERT INTO clin.substance_intake (
1306 fk_encounter,
1307 fk_episode,
1308 intake_is_approved_of,
1309 fk_drug_component
1310 ) VALUES (
1311 %(enc)s,
1312 %(epi)s,
1313 False,
1314 %(comp)s
1315 )
1316 RETURNING pk"""
1317
1318 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True)
1319 return cSubstanceIntakeEntry(aPK_obj = rows[0][0])
1320
1321 -def create_substance_intake_old(substance=None, drug_component=None, atc=None, encounter=None, episode=None, preparation=None, amount=None, unit=None):
1322
1323 args = {
1324 'enc': encounter,
1325 'epi': episode,
1326 'prep': preparation,
1327 'comp': drug_component,
1328 'subst': create_consumable_substance(substance = substance, atc = atc, amount = amount, unit = unit)['pk']
1329 }
1330
1331 if drug_component is None:
1332 cmd = u"""
1333 INSERT INTO clin.substance_intake (
1334 fk_encounter,
1335 fk_episode,
1336 intake_is_approved_of,
1337 fk_substance,
1338 preparation
1339 ) VALUES (
1340 %(enc)s,
1341 %(epi)s,
1342 False,
1343 %(subst)s,
1344 gm.nullify_empty_string(%(prep)s)
1345 )
1346 RETURNING pk"""
1347 else:
1348 cmd = u"""
1349 INSERT INTO clin.substance_intake (
1350 fk_encounter,
1351 fk_episode,
1352 intake_is_approved_of.
1353 fk_drug_component
1354 ) VALUES (
1355 %(enc)s,
1356 %(epi)s,
1357 False,
1358 %(comp)s
1359 )
1360 RETURNING pk"""
1361
1362 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True)
1363 return cSubstanceIntakeEntry(aPK_obj = rows[0][0])
1364
1368
1403
1404
1481
1482 _SQL_get_drug_components = u'SELECT * FROM ref.v_drug_components WHERE %s'
1483
1527
1532
1534 """Represents a drug as marketed by a manufacturer."""
1535
1536 _cmd_fetch_payload = u"SELECT * FROM ref.v_branded_drugs WHERE pk_brand = %s"
1537 _cmds_store_payload = [
1538 u"""UPDATE ref.branded_drug SET
1539 description = %(brand)s,
1540 preparation = %(preparation)s,
1541 atc_code = gm.nullify_empty_string(%(atc)s),
1542 external_code = gm.nullify_empty_string(%(external_code)s),
1543 external_code_type = gm.nullify_empty_string(%(external_code_type)s),
1544 is_fake = %(is_fake_brand)s,
1545 fk_data_source = %(pk_data_source)s
1546 WHERE
1547 pk = %(pk_brand)s
1548 AND
1549 xmin = %(xmin_branded_drug)s
1550 RETURNING
1551 xmin AS xmin_branded_drug
1552 """
1553 ]
1554 _updatable_fields = [
1555 u'brand',
1556 u'preparation',
1557 u'atc',
1558 u'is_fake_brand',
1559 u'external_code',
1560 u'external_code_type',
1561 u'pk_data_source'
1562 ]
1563
1565 success, data = super(self.__class__, self).save_payload(conn = conn)
1566
1567 if not success:
1568 return (success, data)
1569
1570 if self._payload[self._idx['atc']] is not None:
1571 atc = self._payload[self._idx['atc']].strip()
1572 if atc != u'':
1573 gmATC.propagate_atc (
1574 substance = self._payload[self._idx['brand']].strip(),
1575 atc = atc
1576 )
1577
1578 return (success, data)
1579
1581
1582 if self._payload[self._idx['is_in_use']]:
1583 return False
1584
1585 args = {'brand': self._payload[self._idx['pk_brand']]}
1586
1587 queries = [{'cmd': u"DELETE FROM ref.lnk_substance2brand WHERE fk_brand = %(brand)s", 'args': args}]
1588 cmd = u'INSERT INTO ref.lnk_substance2brand (fk_brand, fk_substance) VALUES (%%(brand)s, %s)'
1589 for s in substances:
1590 queries.append({'cmd': cmd % s['pk'], 'args': args})
1591
1592 gmPG2.run_rw_queries(queries = queries)
1593 self.refetch_payload()
1594
1595 return True
1596
1597 - def add_component(self, substance=None, atc=None, amount=None, unit=None, pk_substance=None):
1598
1599 args = {
1600 'brand': self.pk_obj,
1601 'subst': consumable['description'],
1602 'atc': consumable['atc_code'],
1603 'pk_subst': pk_substance
1604 }
1605
1606 if pk_substance is None:
1607 consumable = create_consumable_substance(substance = substance, atc = atc, amount = amount, unit = unit)
1608 args['pk_subst'] = consumable['pk']
1609
1610
1611 cmd = u"""
1612 SELECT pk_component
1613 FROM ref.v_drug_components
1614 WHERE
1615 pk_brand = %(brand)s
1616 AND
1617 ((
1618 (lower(substance) = lower(%(subst)s))
1619 OR
1620 (lower(atc_substance) = lower(%(atc)s))
1621 OR
1622 (pk_consumable_substance = %(pk_subst)s)
1623 ) IS TRUE)
1624 """
1625 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
1626
1627 if len(rows) > 0:
1628 return
1629
1630
1631 cmd = u"""
1632 INSERT INTO ref.lnk_substance2brand (fk_brand, fk_substance)
1633 VALUES (%(brand)s, %(pk_subst)s)
1634 """
1635 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
1636
1638 if len(self._payload[self._idx['components']]) == 1:
1639 _log.error('cannot remove the only component of a drug')
1640 return False
1641
1642 args = {'brand': self.pk_obj, 'comp': substance}
1643 cmd = u"""
1644 DELETE FROM ref.lnk_substance2brand
1645 WHERE
1646 fk_brand = %(brand)s
1647 AND
1648 fk_substance = %(comp)s
1649 AND
1650 NOT EXISTS (
1651 SELECT 1
1652 FROM clin.substance_intake
1653 WHERE fk_drug_component = %(comp)s
1654 LIMIT 1
1655 )
1656 """
1657 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
1658 return True
1659
1660
1661
1663 if self._payload[self._idx['external_code']] is None:
1664 return None
1665
1666 return self._payload[self._idx['external_code']]
1667
1668 external_code = property(_get_external_code, lambda x:x)
1669
1671
1672
1673 if self._payload[self._idx['external_code_type']] is None:
1674 return None
1675
1676 return self._payload[self._idx['external_code_type']]
1677
1678 external_code_type = property(_get_external_code_type, lambda x:x)
1679
1681 cmd = _SQL_get_drug_components % u'pk_brand = %(brand)s'
1682 args = {'brand': self._payload[self._idx['pk_brand']]}
1683 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
1684 return [ cDrugComponent(row = {'data': r, 'idx': idx, 'pk_field': 'pk_component'}) for r in rows ]
1685
1686 components = property(_get_components, lambda x:x)
1687
1689 if self._payload[self._idx['pk_substances']] is None:
1690 return []
1691 cmd = _SQL_get_consumable_substance % u'pk IN %(pks)s'
1692 args = {'pks': tuple(self._payload[self._idx['pk_substances']])}
1693 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
1694 return [ cConsumableSubstance(row = {'data': r, 'idx': idx, 'pk_field': 'pk'}) for r in rows ]
1695
1696 components_as_substances = property(_get_components_as_substances, lambda x:x)
1697
1699 cmd = u'SELECT EXISTS (SELECT 1 FROM clin.vaccine WHERE fk_brand = %(fk_brand)s)'
1700 args = {'fk_brand': self._payload[self._idx['pk_brand']]}
1701 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
1702 return rows[0][0]
1703
1704 is_vaccine = property(_get_is_vaccine, lambda x:x)
1705
1707 cmd = u'SELECT pk FROM ref.branded_drug ORDER BY description'
1708 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = False)
1709 return [ cBrandedDrug(aPK_obj = r['pk']) for r in rows ]
1710
1712 args = {'brand': brand_name, 'prep': preparation}
1713
1714 cmd = u'SELECT pk FROM ref.branded_drug WHERE lower(description) = lower(%(brand)s) AND lower(preparation) = lower(%(prep)s)'
1715 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
1716
1717 if len(rows) == 0:
1718 return None
1719
1720 return cBrandedDrug(aPK_obj = rows[0]['pk'])
1721
1723
1724 if preparation is None:
1725 preparation = _('units')
1726
1727 if preparation.strip() == u'':
1728 preparation = _('units')
1729
1730 if return_existing:
1731 drug = get_drug_by_brand(brand_name = brand_name, preparation = preparation)
1732 if drug is not None:
1733 return drug
1734
1735 cmd = u'INSERT INTO ref.branded_drug (description, preparation) VALUES (%(brand)s, %(prep)s) RETURNING pk'
1736 args = {'brand': brand_name, 'prep': preparation}
1737 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True, get_col_idx = False)
1738
1739 return cBrandedDrug(aPK_obj = rows[0]['pk'])
1740
1742 queries = []
1743 args = {'pk': brand}
1744
1745
1746 cmd = u"""
1747 DELETE FROM ref.lnk_substance2brand
1748 WHERE
1749 fk_brand = %(pk)s
1750 AND
1751 NOT EXISTS (
1752 SELECT 1
1753 FROM clin.v_pat_substance_intake
1754 WHERE pk_brand = %(pk)s
1755 LIMIT 1
1756 )
1757 """
1758 queries.append({'cmd': cmd, 'args': args})
1759
1760
1761 cmd = u"""
1762 DELETE FROM ref.branded_drug
1763 WHERE
1764 pk = %(pk)s
1765 AND
1766 NOT EXISTS (
1767 SELECT 1
1768 FROM clin.v_pat_substance_intake
1769 WHERE pk_brand = %(pk)s
1770 LIMIT 1
1771 )
1772 """
1773 queries.append({'cmd': cmd, 'args': args})
1774
1775 gmPG2.run_rw_queries(queries = queries)
1776
1777
1778
1779 if __name__ == "__main__":
1780
1781 if len(sys.argv) < 2:
1782 sys.exit()
1783
1784 if sys.argv[1] != 'test':
1785 sys.exit()
1786
1787 from Gnumed.pycommon import gmLog2
1788 from Gnumed.pycommon import gmI18N
1789 from Gnumed.business import gmPerson
1790
1791 gmI18N.activate_locale()
1792
1793
1799
1801 mmi_file = cGelbeListeCSVFile(filename = sys.argv[2])
1802 for drug in mmi_file:
1803 print "-------------"
1804 print '"%s" (ATC: %s / PZN: %s)' % (drug['name'], drug['atc'], drug['pzn'])
1805 for stoff in drug['wirkstoffe']:
1806 print " Wirkstoff:", stoff
1807 raw_input()
1808 if mmi_file.has_unknown_fields is not None:
1809 print "has extra data under [%s]" % gmTools.default_csv_reader_rest_key
1810 for key in mmi_file.csv_fieldnames:
1811 print key, '->', drug[key]
1812 raw_input()
1813 mmi_file.close()
1814
1818
1820 mmi = cGelbeListeWineInterface()
1821 mmi_file = mmi.select_drugs()
1822 for drug in mmi_file:
1823 print "-------------"
1824 print '"%s" (ATC: %s / PZN: %s)' % (drug['name'], drug['atc'], drug['pzn'])
1825 for stoff in drug['wirkstoffe']:
1826 print " Wirkstoff:", stoff
1827 print drug
1828 mmi_file.close()
1829
1833
1835 mmi = cGelbeListeInterface()
1836 print mmi
1837 print "interface definition:", mmi.version
1838
1839 diclofenac = '7587712'
1840 phenprocoumon = '4421744'
1841 mmi.check_drug_interactions(drug_ids_list = [diclofenac, phenprocoumon])
1842
1843
1844
1851
1857
1858
1859
1867
1872
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887 test_fd_show_interactions()
1888
1889
1890
1891
1892
1893
1894
1895