| Home | Trees | Indices | Help |
|
|---|
|
|
1 # -*- coding: utf8 -*-
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
11
12
13 if __name__ == '__main__':
14 sys.path.insert(0, '../../')
15 from Gnumed.pycommon import gmBusinessDBObject, gmPG2, gmShellAPI, gmTools
16 from Gnumed.pycommon import gmDispatcher, gmDateTime, gmHooks
17 from Gnumed.business import gmATC, gmAllergy
18
19
20 _log = logging.getLogger('gm.meds')
21 _log.info(__version__)
22
23 #============================================================
25 """Always relates to the active patient."""
26 gmHooks.run_hook_script(hook = u'after_substance_intake_modified')
27
28 gmDispatcher.connect(_on_substance_intake_modified, u'substance_intake_mod_db')
29
30 #============================================================
32
33 if search_term is None:
34 return u'http://www.dosing.de'
35
36 terms = []
37 names = []
38
39 if isinstance(search_term, cBrandedDrug):
40 if search_term['atc_code'] is not None:
41 terms.append(search_term['atc_code'])
42
43 elif isinstance(search_term, cSubstanceIntakeEntry):
44 names.append(search_term['substance'])
45 if search_term['atc_brand'] is not None:
46 terms.append(search_term['atc_brand'])
47 if search_term['atc_substance'] is not None:
48 terms.append(search_term['atc_substance'])
49
50 elif search_term is not None:
51 names.append(u'%s' % search_term)
52 terms.extend(gmATC.text2atc(text = u'%s' % search_term, fuzzy = True))
53
54 for name in names:
55 if name.endswith('e'):
56 terms.append(name[:-1])
57 else:
58 terms.append(name)
59
60 #url_template = u'http://www.google.de/#q=site%%3Adosing.de+%s'
61 #url = url_template % u'+OR+'.join(terms)
62
63 url_template = u'http://www.google.de/search?hl=de&source=hp&q=site%%3Adosing.de+%s&btnG=Google-Suche'
64 url = url_template % u'+OR+'.join(terms)
65
66 _log.debug(u'renal insufficiency URL: %s', url)
67
68 return url
69 #============================================================
70 # this should be in gmCoding.py
71 -def create_data_source(long_name=None, short_name=None, version=None, source=None, language=None):
72
73 args = {
74 'lname': long_name,
75 'sname': short_name,
76 'ver': version,
77 'src': source,
78 'lang': language
79 }
80
81 cmd = u"""select pk from ref.data_source where name_long = %(lname)s and name_short = %(sname)s and version = %(ver)s"""
82 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}])
83 if len(rows) > 0:
84 return rows[0]['pk']
85
86 cmd = u"""
87 INSERT INTO ref.data_source (name_long, name_short, version, source, lang)
88 VALUES (
89 %(lname)s,
90 %(sname)s,
91 %(ver)s,
92 %(src)s,
93 %(lang)s
94 )
95 returning pk
96 """
97 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True)
98
99 return rows[0]['pk']
100 #============================================================
101 # wishlist:
102 # - --conf-file= for glwin.exe
103 # - wirkstoff: Konzentration auch in Multiprodukten
104 # - wirkstoff: ATC auch in Multiprodukten
105 # - Suche nach ATC per CLI
106
108 """Iterator over a Gelbe Liste/MMI v8.2 CSV file."""
109
110 version = u'Gelbe Liste/MMI v8.2 CSV file interface'
111 default_transfer_file_windows = r"c:\rezept.txt"
112 #default_encoding = 'cp1252'
113 default_encoding = 'cp1250'
114 csv_fieldnames = [
115 u'name',
116 u'packungsgroesse', # obsolete, use "packungsmenge"
117 u'darreichungsform',
118 u'packungstyp',
119 u'festbetrag',
120 u'avp',
121 u'hersteller',
122 u'rezepttext',
123 u'pzn',
124 u'status_vertrieb',
125 u'status_rezeptpflicht',
126 u'status_fachinfo',
127 u'btm',
128 u'atc',
129 u'anzahl_packungen',
130 u'zuzahlung_pro_packung',
131 u'einheit',
132 u'schedule_morgens',
133 u'schedule_mittags',
134 u'schedule_abends',
135 u'schedule_nachts',
136 u'status_dauermedikament',
137 u'status_hausliste',
138 u'status_negativliste',
139 u'ik_nummer',
140 u'status_rabattvertrag',
141 u'wirkstoffe',
142 u'wirkstoffmenge',
143 u'wirkstoffeinheit',
144 u'wirkstoffmenge_bezug',
145 u'wirkstoffmenge_bezugseinheit',
146 u'status_import',
147 u'status_lifestyle',
148 u'status_ausnahmeliste',
149 u'packungsmenge',
150 u'apothekenpflicht',
151 u'status_billigere_packung',
152 u'rezepttyp',
153 u'besonderes_arzneimittel', # Abstimmungsverfahren SGB-V
154 u't_rezept_pflicht', # Thalidomid-Rezept
155 u'erstattbares_medizinprodukt',
156 u'hilfsmittel',
157 u'hzv_rabattkennung',
158 u'hzv_preis'
159 ]
160 boolean_fields = [
161 u'status_rezeptpflicht',
162 u'status_fachinfo',
163 u'btm',
164 u'status_dauermedikament',
165 u'status_hausliste',
166 u'status_negativliste',
167 u'status_rabattvertrag',
168 u'status_import',
169 u'status_lifestyle',
170 u'status_ausnahmeliste',
171 u'apothekenpflicht',
172 u'status_billigere_packung',
173 u'besonderes_arzneimittel', # Abstimmungsverfahren SGB-V
174 u't_rezept_pflicht',
175 u'erstattbares_medizinprodukt',
176 u'hilfsmittel'
177 ]
178 #--------------------------------------------------------
180
181 _log.info(cGelbeListeCSVFile.version)
182
183 self.filename = filename
184 if filename is None:
185 self.filename = cGelbeListeCSVFile.default_transfer_file_windows
186
187 _log.debug('reading Gelbe Liste/MMI drug data from [%s]', self.filename)
188
189 self.csv_file = codecs.open(filename = filename, mode = 'rUb', encoding = cGelbeListeCSVFile.default_encoding)
190
191 self.csv_lines = gmTools.unicode_csv_reader (
192 self.csv_file,
193 fieldnames = cGelbeListeCSVFile.csv_fieldnames,
194 delimiter = ';',
195 quotechar = '"',
196 dict = True
197 )
198 #--------------------------------------------------------
201 #--------------------------------------------------------
203 line = self.csv_lines.next()
204
205 for field in cGelbeListeCSVFile.boolean_fields:
206 line[field] = (line[field].strip() == u'T')
207
208 # split field "Wirkstoff" by ";"
209 if line['wirkstoffe'].strip() == u'':
210 line['wirkstoffe'] = []
211 else:
212 line['wirkstoffe'] = [ wirkstoff.strip() for wirkstoff in line['wirkstoffe'].split(u';') ]
213
214 return line
215 #--------------------------------------------------------
217 try: self.csv_file.close()
218 except: pass
219
220 if truncate:
221 try: os.open(self.filename, 'wb').close
222 except: pass
223 #--------------------------------------------------------
226
227 has_unknown_fields = property(_get_has_unknown_fields, lambda x:x)
228 #============================================================
230
231 #--------------------------------------------------------
235 #--------------------------------------------------------
238 #--------------------------------------------------------
241 #--------------------------------------------------------
244 #--------------------------------------------------------
247 #--------------------------------------------------------
250 #--------------------------------------------------------
253 #--------------------------------------------------------
256 #============================================================
258
259 version = u'FreeDiams v0.4.2 interface'
260 default_encoding = 'utf8'
261 default_dob_format = '%Y/%m/%d'
262
263 map_gender2mf = {
264 'm': u'M',
265 'f': u'F',
266 'tf': u'H',
267 'tm': u'H',
268 'h': u'H'
269 }
270 #--------------------------------------------------------
272 cDrugDataSourceInterface.__init__(self)
273 _log.info(cFreeDiamsInterface.version)
274
275 paths = gmTools.gmPaths()
276 self.__gm2fd_filename = os.path.join(paths.home_dir, '.gnumed', 'tmp', 'gm2freediams.xml')
277 self.__fd2gm_filename = os.path.join(paths.home_dir, '.gnumed', 'tmp', 'freediams2gm.xml')
278 self.__fd4gm_config_file = os.path.join(paths.home_dir, '.gnumed', 'freediams4gm.conf')
279
280 self.path_to_binary = None
281 self.__detect_binary()
282 #--------------------------------------------------------
284 # ~/.freediams/config.ini: [License] -> AcceptedVersion=....
285
286 if not self.__detect_binary():
287 return False
288
289 freediams = subprocess.Popen (
290 args = u'--version', # --version or -version or -v
291 executable = self.path_to_binary,
292 stdout = subprocess.PIPE,
293 stderr = subprocess.PIPE,
294 # close_fds = True, # Windows can't do that in conjunction with stdout/stderr = ... :-(
295 universal_newlines = True
296 )
297 data, errors = freediams.communicate()
298 ver = regex.search('FreeDiams\s\d.\d.\d', data).group().split()[1]
299 _log.debug('FreeDiams %s', ver)
300
301 return version
302 #--------------------------------------------------------
304 return create_data_source (
305 long_name = u'"FreeDiams" Drug Database Frontend',
306 short_name = u'FreeDiams',
307 version = self.get_data_source_version(),
308 source = u'http://ericmaeker.fr/FreeMedForms/di-manual/index.html',
309 language = u'fr' # actually to be multi-locale
310 )
311 #--------------------------------------------------------
313 """http://ericmaeker.fr/FreeMedForms/di-manual/en/html/ligne_commandes.html"""
314
315 if not self.__detect_binary():
316 return False
317
318 self.__create_gm2fd_file()
319 open(self.__fd2gm_filename, 'wb').close()
320
321 args = u'--exchange-in="%s"' % (self.__gm2fd_filename)
322
323 cmd = r'%s %s' % (self.path_to_binary, args)
324
325 # if self.patient is not None:
326 # names = self.patient.get_active_name()
327 # args += u' --patientname="%(lastnames)s, %(firstnames)s"' % names
328 # args += u' --patientsurname="%(lastnames)s"' % names
329 # args += u' --gender=%s' % cFreeDiamsInterface.map_gender2mf[self.patient['gender']]
330 # if self.patient['dob'] is not None:
331 # args += u' --dateofbirth=%s' % self.patient['dob'].strftime(cFreeDiamsInterface.default_dob_format)
332
333 if not gmShellAPI.run_command_in_shell(command = cmd, blocking = blocking):
334 _log.error('problem switching to the FreeDiams drug database')
335 return False
336
337 return True
338 #--------------------------------------------------------
340 self.switch_to_frontend()
341 #--------------------------------------------------------
343 """FreeDiams ONLY use CIS.
344
345 CIS stands for Unique Speciality Identifier (eg bisoprolol 5 mg, gel).
346 CIS is AFSSAPS specific, but pharmacist can retreive drug name with the CIS.
347 AFSSAPS is the French FDA.
348
349 CIP stands for Unique Presentation Identifier (eg 30 pills plaq)
350 CIP if you want to specify the packaging of the drug (30 pills
351 thermoformed tablet...) -- actually not really usefull for french
352 doctors.
353 """
354 self.switch_to_frontend()
355 # .external_code_type: u'FR-CIS'
356 # .external_cod: the CIS value
357 #--------------------------------------------------------
359 self.switch_to_frontend()
360 #--------------------------------------------------------
364 #--------------------------------------------------------
365 # internal helpers
366 #--------------------------------------------------------
368
369 if self.path_to_binary is not None:
370 return True
371
372 found, cmd = gmShellAPI.find_first_binary(binaries = [
373 r'/usr/bin/freediams',
374 r'freediams',
375 r'/Applications/FreeDiams.app/Contents/MacOs/FreeDiams',
376 r'c:\programs\freediams\freediams.exe',
377 r'freediams.exe'
378 ])
379
380 if found:
381 self.path_to_binary = cmd
382 return True
383
384 try:
385 self.custom_path_to_binary
386 except AttributeError:
387 _log.error('cannot find FreeDiams binary, no custom path set')
388 return False
389
390 found, cmd = gmShellAPI.detect_external_binary(binary = self.custom_path_to_binary)
391 if found:
392 self.path_to_binary = cmd
393 return True
394
395 _log.error('cannot find FreeDiams binary')
396 return False
397 #--------------------------------------------------------
399
400 xml_file = codecs.open(self.__gm2fd_filename, 'wb', 'utf8')
401 if self.patient is None:
402 xml_file.close()
403 return
404
405 name = self.patient.get_active_name()
406 if self.patient['dob'] is None:
407 dob = u''
408 else:
409 dob = self.patient['dob'].strftime(cFreeDiamsInterface.default_dob_format)
410
411 emr = self.patient.get_emr()
412 allgs = emr.get_allergies() # leave out sensitivities ?
413 atcs = [ a['atc_code'] for a in allgs if a['atc_code'] is not None ]
414 inns = [ a['allergene'] for a in allgs ]
415 # this is rather fragile: FreeDiams won't know what type of UID this is
416 # (but it will assume it is of the type of the drug database in use)
417 uids = [ a['substance_code'] for a in allgs if a['substance_code'] is not None ]
418
419 # Eric says the order of same-level nodes does not matter.
420 xml = u"""<?xml version="1.0" encoding="UTF-8"?>
421
422 <FreeDiams_In version="0.4.2">
423 <EMR name="GNUmed" uid="unused"/>
424 <ConfigFile value="%s"/>
425 <OutFile value="%s" format="html_xml"/>
426 <Ui editmode="select-only" blockPatientDatas="1"/>
427 <Patient>
428 <Identity name="%s" surname="%s" uid="%s" dob="%s" gender="%s"/>
429 <ATCAllergies value="%s"/>
430 <InnAllergies value="%s"/>
431 <DrugsUidAllergies value="%s"/>
432 </Patient>
433 </FreeDiams_In>
434
435 <!--
436 <InnIntolerances value=""/>
437 <ATCIntolerances value="B05B"/>
438 <DrugsUidIntolerances value="68586203;62869109"/>
439 # FIXME: search by LOINC code and add (as soon as supported by FreeDiams ...)
440 <Creatinine value="12" unit="mg/l or mmol/l"/>
441 <Weight value="70" unit="kg or pd" />
442 <Height value="170" unit="cm or "/>
443 <ICD10 value="J11.0;A22;Z23"/>
444 -->
445 """ % (
446 self.__fd4gm_config_file,
447 self.__fd2gm_filename,
448 name['firstnames'], name['lastnames'], self.patient.ID, dob, cFreeDiamsInterface.map_gender2mf[self.patient['gender']],
449 u';'.join(atcs),
450 u';'.join(inns),
451 u';'.join(uids)
452 )
453
454 xml_file = codecs.open(self.__gm2fd_filename, 'wb', 'utf8')
455 xml_file.write(xml)
456 xml_file.close()
457 #--------------------------------------------------------
459
460 # fixed_xml = codecs.open(gmTools.get_unique_filename(suffix = '.xml', 'w', 'utf-8')
461 # for line in self.__fd2gm_filename:
462
463 # fd2gm = codecs.open(self.__fd2gm_filename, 'rU', 'utf-8')
464
465 from xml.etree import ElementTree as etree
466
467 fd2gm_xml = etree.ElementTree()
468 fd2gm_xml.parse(self.__fd2gm_filename)
469
470 print fd2gm_xml
471
472 #============================================================
474 """Support v8.2 CSV file interface only."""
475
476 version = u'Gelbe Liste/MMI v8.2 interface'
477 default_encoding = 'cp1250'
478 bdt_line_template = u'%03d6210#%s\r\n' # Medikament verordnet auf Kassenrezept
479 bdt_line_base_length = 8
480 #--------------------------------------------------------
482
483 cDrugDataSourceInterface.__init__(self)
484
485 _log.info(u'%s (native Windows)', cGelbeListeWindowsInterface.version)
486
487 self.path_to_binary = r'C:\Programme\MMI PHARMINDEX\glwin.exe'
488 self.args = r'-KEEPBACKGROUND -PRESCRIPTIONFILE %s -CLOSETOTRAY'
489
490 paths = gmTools.gmPaths()
491
492 self.default_csv_filename = os.path.join(paths.home_dir, '.gnumed', 'tmp', 'rezept.txt')
493 self.default_csv_filename_arg = os.path.join(paths.home_dir, '.gnumed', 'tmp')
494 self.interactions_filename = os.path.join(paths.home_dir, '.gnumed', 'tmp', 'gm2mmi.bdt')
495 self.data_date_filename = r'C:\Programme\MMI PHARMINDEX\datadate.txt'
496
497 self.__data_date = None
498 self.__online_update_date = None
499
500 # use adjusted config.dat
501 #--------------------------------------------------------
503
504 if self.__data_date is not None:
505 if not force_reload:
506 return {
507 'data': self.__data_date,
508 'online_update': self.__online_update_date
509 }
510
511 open(self.data_date_filename, 'wb').close()
512
513 cmd = u'%s -DATADATE' % self.path_to_binary
514 if not gmShellAPI.run_command_in_shell(command = cmd, blocking = True):
515 _log.error('problem querying the MMI drug database for version information')
516 self.__data_date = None
517 self.__online_update_date = None
518 return {
519 'data': u'?',
520 'online_update': u'?'
521 }
522
523 try:
524 version_file = open(self.data_date_filename, 'rU')
525 except StandardError:
526 _log.error('problem querying the MMI drug database for version information')
527 _log.exception('cannot open MMI drug database version file [%s]', self.data_date_filename)
528 self.__data_date = None
529 self.__online_update_date = None
530 return {
531 'data': u'?',
532 'online_update': u'?'
533 }
534
535 self.__data_date = version_file.readline()[:10]
536 self.__online_update_date = version_file.readline()[:10]
537 version_file.close()
538
539 return {
540 'data': self.__data_date,
541 'online_update': self.__online_update_date
542 }
543 #--------------------------------------------------------
545 versions = self.get_data_source_version()
546
547 return create_data_source (
548 long_name = u'Medikamentendatenbank "mmi PHARMINDEX" (Gelbe Liste)',
549 short_name = u'GL/MMI',
550 version = u'Daten: %s, Preise (Onlineupdate): %s' % (versions['data'], versions['online_update']),
551 source = u'Medizinische Medien Informations GmbH, Am Forsthaus Gravenbruch 7, 63263 Neu-Isenburg',
552 language = u'de'
553 )
554 #--------------------------------------------------------
556
557 # must make sure csv file exists
558 open(self.default_csv_filename, 'wb').close()
559
560 if cmd is None:
561 cmd = (u'%s %s' % (self.path_to_binary, self.args)) % self.default_csv_filename_arg
562
563 if not gmShellAPI.run_command_in_shell(command = cmd, blocking = blocking):
564 _log.error('problem switching to the MMI drug database')
565 # apparently on the first call MMI does not
566 # consistently return 0 on success
567 # return False
568
569 return True
570 #--------------------------------------------------------
572
573 # better to clean up interactions file
574 open(self.interactions_filename, 'wb').close()
575
576 if not self.switch_to_frontend(blocking = True):
577 return None
578
579 return cGelbeListeCSVFile(filename = self.default_csv_filename)
580 #--------------------------------------------------------
582
583 selected_drugs = self.select_drugs()
584 if selected_drugs is None:
585 return None
586
587 new_substances = []
588
589 for drug in selected_drugs:
590 atc = None # hopefully MMI eventually supports atc-per-substance in a drug...
591 if len(drug['wirkstoffe']) == 1:
592 atc = drug['atc']
593 for wirkstoff in drug['wirkstoffe']:
594 new_substances.append(create_used_substance(substance = wirkstoff, atc = atc))
595
596 selected_drugs.close()
597
598 return new_substances
599 #--------------------------------------------------------
601
602 selected_drugs = self.select_drugs()
603 if selected_drugs is None:
604 return None
605
606 data_src_pk = self.create_data_source_entry()
607
608 new_drugs = []
609 new_substances = []
610
611 for entry in selected_drugs:
612
613 _log.debug('importing drug: %s %s', entry['name'], entry['darreichungsform'])
614
615 if entry[u'hilfsmittel']:
616 _log.debug('skipping Hilfsmittel')
617 continue
618
619 if entry[u'erstattbares_medizinprodukt']:
620 _log.debug('skipping sonstiges Medizinprodukt')
621 continue
622
623 # create branded drug (or get it if it already exists)
624 drug = create_branded_drug(brand_name = entry['name'], preparation = entry['darreichungsform'])
625 if drug is None:
626 drug = get_drug_by_brand(brand_name = entry['name'], preparation = entry['darreichungsform'])
627 new_drugs.append(drug)
628
629 # update fields
630 drug['is_fake'] = False
631 drug['atc_code'] = entry['atc']
632 drug['external_code_type'] = u'DE-PZN'
633 drug['external_code'] = entry['pzn']
634 drug['fk_data_source'] = data_src_pk
635 drug.save()
636
637 # add components to brand
638 atc = None # hopefully MMI eventually supports atc-per-substance in a drug...
639 if len(entry['wirkstoffe']) == 1:
640 atc = entry['atc']
641 for wirkstoff in entry['wirkstoffe']:
642 drug.add_component(substance = wirkstoff, atc = atc)
643
644 # create as consumable substances, too
645 atc = None # hopefully MMI eventually supports atc-per-substance in a drug...
646 if len(entry['wirkstoffe']) == 1:
647 atc = entry['atc']
648 for wirkstoff in entry['wirkstoffe']:
649 new_substances.append(create_used_substance(substance = wirkstoff, atc = atc))
650
651 return new_drugs, new_substances
652 #--------------------------------------------------------
654 """For this to work the BDT interaction check must be configured in the MMI."""
655
656 if drug_ids_list is None:
657 if substances is None:
658 return
659 if len(substances) < 2:
660 return
661 drug_ids_list = [ (s.external_code_type, s.external_code) for s in substances ]
662 drug_ids_list = [ code_value for code_type, code_value in drug_ids_list if (code_value is not None) and (code_type == u'DE-PZN')]
663
664 else:
665 if len(drug_ids_list) < 2:
666 return
667
668 if drug_ids_list < 2:
669 return
670
671 bdt_file = codecs.open(filename = self.interactions_filename, mode = 'wb', encoding = cGelbeListeWindowsInterface.default_encoding)
672
673 for pzn in drug_ids_list:
674 pzn = pzn.strip()
675 lng = cGelbeListeWindowsInterface.bdt_line_base_length + len(pzn)
676 bdt_file.write(cGelbeListeWindowsInterface.bdt_line_template % (lng, pzn))
677
678 bdt_file.close()
679
680 self.switch_to_frontend(blocking = False)
681 #--------------------------------------------------------
683
684 cmd = None
685
686 if substance.external_code_type == u'DE-PZN':
687 cmd = u'%s -PZN %s' % (self.path_to_binary, substance.external_code)
688
689 if cmd is None:
690 name = gmTools.coalesce (
691 substance['brand'],
692 substance['substance']
693 )
694 cmd = u'%s -NAME %s' % (self.path_to_binary, name)
695
696 # better to clean up interactions file
697 open(self.interactions_filename, 'wb').close()
698
699 self.switch_to_frontend(cmd = cmd)
700 #============================================================
702
704 cGelbeListeWindowsInterface.__init__(self)
705
706 _log.info(u'%s (WINE extension)', cGelbeListeWindowsInterface.version)
707
708 # FIXME: if -CLOSETOTRAY is used GNUmed cannot detect the end of MMI
709 self.path_to_binary = r'wine "C:\Programme\MMI PHARMINDEX\glwin.exe"'
710 self.args = r'"-PRESCRIPTIONFILE %s -KEEPBACKGROUND"'
711
712 paths = gmTools.gmPaths()
713
714 self.default_csv_filename = os.path.join(paths.home_dir, '.wine', 'drive_c', 'windows', 'temp', 'mmi2gm.csv')
715 self.default_csv_filename_arg = r'c:\windows\temp\mmi2gm.csv'
716 self.interactions_filename = os.path.join(paths.home_dir, '.wine', 'drive_c', 'windows', 'temp', 'gm2mmi.bdt')
717 self.data_date_filename = os.path.join(paths.home_dir, '.wine', 'drive_c', 'Programme', 'MMI PHARMINDEX', 'datadate.txt')
718 #============================================================
720 """empirical CSV interface"""
721
724
726
727 try:
728 csv_file = open(filename, 'rb') # FIXME: encoding ?
729 except:
730 _log.exception('cannot access [%s]', filename)
731 csv_file = None
732
733 field_names = u'PZN Handelsname Form Abpackungsmenge Einheit Preis1 Hersteller Preis2 rezeptpflichtig Festbetrag Packungszahl Packungsgr\xf6\xdfe'.split()
734
735 if csv_file is None:
736 return False
737
738 csv_lines = csv.DictReader (
739 csv_file,
740 fieldnames = field_names,
741 delimiter = ';'
742 )
743
744 for line in csv_lines:
745 print "--------------------------------------------------------------------"[:31]
746 for key in field_names:
747 tmp = ('%s ' % key)[:30]
748 print '%s: %s' % (tmp, line[key])
749
750 csv_file.close()
751
752 # narr = u'%sx %s %s %s (\u2258 %s %s) von %s (%s)' % (
753 # line['Packungszahl'].strip(),
754 # line['Handelsname'].strip(),
755 # line['Form'].strip(),
756 # line[u'Packungsgr\xf6\xdfe'].strip(),
757 # line['Abpackungsmenge'].strip(),
758 # line['Einheit'].strip(),
759 # line['Hersteller'].strip(),
760 # line['PZN'].strip()
761 # )
762 #============================================================
763 drug_data_source_interfaces = {
764 'Deutschland: Gelbe Liste/MMI (Windows)': cGelbeListeWindowsInterface,
765 'Deutschland: Gelbe Liste/MMI (WINE)': cGelbeListeWineInterface,
766 'FreeDiams (France, US, Canada)': cFreeDiamsInterface
767 }
768 #============================================================
769 # substances in use across all patients
770 #------------------------------------------------------------
772 cmd = u'select * from clin.consumed_substance order by description'
773 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}])
774 return rows
775 #------------------------------------------------------------
777 cmd = u'SELECT * FROM clin.consumed_substance WHERE pk = %(pk)s'
778 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': {'pk': pk}}])
779 if len(rows) == 0:
780 return None
781 return rows[0]
782 #------------------------------------------------------------
784
785 substance = substance.strip()
786
787 if atc is not None:
788 atc = atc.strip()
789
790 args = {'desc': substance, 'atc': atc}
791
792 cmd = u'select pk, atc_code, description from clin.consumed_substance where description = %(desc)s'
793 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}])
794
795 if len(rows) == 0:
796 cmd = u'insert into clin.consumed_substance (description, atc_code) values (%(desc)s, gm.nullify_empty_string(%(atc)s)) returning pk, atc_code, description'
797 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True)
798
799 gmATC.propagate_atc(substance = substance, atc = atc)
800
801 row = rows[0]
802 # unfortunately not a real dict so no setting stuff by keyword
803 #row['atc_code'] = args['atc']
804 row[1] = args['atc']
805 return row
806 #------------------------------------------------------------
808 args = {'pk': substance}
809 cmd = u"""
810 delete from clin.consumed_substance
811 where
812 pk = %(pk)s and not exists (
813 select 1 from clin.substance_intake
814 where fk_substance = %(pk)s
815 )"""
816 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
817 #============================================================
819 """Represents a substance currently taken by a patient."""
820
821 _cmd_fetch_payload = u"select * from clin.v_pat_substance_intake where pk_substance_intake = %s"
822 _cmds_store_payload = [
823 u"""update clin.substance_intake set
824 clin_when = %(started)s,
825 discontinued = %(discontinued)s,
826 discontinue_reason = gm.nullify_empty_string(%(discontinue_reason)s),
827 strength = gm.nullify_empty_string(%(strength)s),
828 preparation = %(preparation)s,
829 schedule = gm.nullify_empty_string(%(schedule)s),
830 aim = gm.nullify_empty_string(%(aim)s),
831 narrative = gm.nullify_empty_string(%(notes)s),
832 intake_is_approved_of = %(intake_is_approved_of)s,
833
834 -- is_long_term = %(is_long_term)s,
835 is_long_term = (
836 case
837 when (
838 (%(is_long_term)s is False)
839 and
840 (%(duration)s is NULL)
841 ) is True then null
842 else %(is_long_term)s
843 end
844 )::boolean,
845 duration = (
846 case
847 when %(is_long_term)s is True then null
848 else %(duration)s
849 end
850 )::interval,
851
852 fk_brand = %(pk_brand)s,
853 fk_substance = %(pk_substance)s,
854 fk_episode = %(pk_episode)s
855 where
856 pk = %(pk_substance_intake)s and
857 xmin = %(xmin_substance_intake)s
858 returning
859 xmin as xmin_substance_intake
860 """
861 ]
862 _updatable_fields = [
863 u'started',
864 u'discontinued',
865 u'discontinue_reason',
866 u'preparation',
867 u'strength',
868 u'intake_is_approved_of',
869 u'schedule',
870 u'duration',
871 u'aim',
872 u'is_long_term',
873 u'notes',
874 u'pk_brand',
875 u'pk_substance',
876 u'pk_episode'
877 ]
878 #--------------------------------------------------------
880
881 if self._payload[self._idx['duration']] is None:
882 duration = gmTools.bool2subst (
883 self._payload[self._idx['is_long_term']],
884 _('long-term'),
885 _('short-term'),
886 _('?short-term')
887 )
888 else:
889 duration = gmDateTime.format_interval (
890 self._payload[self._idx['duration']],
891 accuracy_wanted = gmDateTime.acc_days
892 )
893
894 line = u'%s%s (%s %s): %s %s %s (%s)' % (
895 u' ' * left_margin,
896 self._payload[self._idx['started']].strftime(date_format),
897 gmTools.u_right_arrow,
898 duration,
899 self._payload[self._idx['substance']],
900 gmTools.coalesce(self._payload[self._idx['strength']], u''),
901 self._payload[self._idx['preparation']],
902 gmTools.bool2subst(self._payload[self._idx['is_currently_active']], _('ongoing'), _('inactive'), _('?ongoing'))
903 )
904
905 return line
906 #--------------------------------------------------------
908 allg = gmAllergy.create_allergy (
909 allergene = self._payload[self._idx['substance']],
910 allg_type = allergy_type,
911 episode_id = self._payload[self._idx['pk_episode']],
912 encounter_id = encounter_id
913 )
914 allg['substance'] = gmTools.coalesce (
915 self._payload[self._idx['brand']],
916 self._payload[self._idx['substance']]
917 )
918 allg['reaction'] = self._payload[self._idx['discontinue_reason']]
919 allg['atc_code'] = gmTools.coalesce(self._payload[self._idx['atc_substance']], self._payload[self._idx['atc_brand']])
920 if self._payload[self._idx['external_code_brand']] is not None:
921 allg['substance_code'] = u'%s::::%s' % (self._payload[self._idx['external_code_type_brand']], self._payload[self._idx['external_code_brand']])
922 allg['allergene'] = self._payload[self._idx['substance']]
923 comps = [ c['description'] for c in self.containing_drug.components ]
924 if len(comps) == 0:
925 allg['generics'] = self._payload[self._idx['substance']]
926 else:
927 allg['generics'] = u'; '.join(comps)
928
929 allg.save()
930 return allg
931 #--------------------------------------------------------
932 # properties
933 #--------------------------------------------------------
935
936 try: self.__ddd
937 except AttributeError: self.__ddd = None
938
939 if self.__ddd is not None:
940 return self.__ddd
941
942 if self._payload[self._idx['atc_substance']] is not None:
943 ddd = gmATC.atc2ddd(atc = self._payload[self._idx['atc_substance']])
944 if len(ddd) != 0:
945 self.__ddd = ddd[0]
946 else:
947 if self._payload[self._idx['atc_brand']] is not None:
948 ddd = gmATC.atc2ddd(atc = self._payload[self._idx['atc_brand']])
949 if len(ddd) != 0:
950 self.__ddd = ddd[0]
951
952 return self.__ddd
953
954 ddd = property(_get_ddd, lambda x:x)
955 #--------------------------------------------------------
957 drug = self.containing_drug
958
959 if drug is None:
960 return None
961
962 return drug.external_code
963
964 external_code = property(_get_external_code, lambda x:x)
965 #--------------------------------------------------------
967 drug = self.containing_drug
968
969 if drug is None:
970 return None
971
972 return drug.external_code_type
973
974 external_code_type = property(_get_external_code_type, lambda x:x)
975 #--------------------------------------------------------
977 if self._payload[self._idx['pk_brand']] is None:
978 return None
979
980 return cBrandedDrug(aPK_obj = self._payload[self._idx['pk_brand']])
981
982 containing_drug = property(_get_containing_drug, lambda x:x)
983 #--------------------------------------------------------
985 tests = [
986 # lead, trail
987 ' 1-1-1-1 ',
988 # leading dose
989 '1-1-1-1',
990 '22-1-1-1',
991 '1/3-1-1-1',
992 '/4-1-1-1'
993 ]
994 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}$"
995 for test in tests:
996 print test.strip(), ":", regex.match(pattern, test.strip())
997 #------------------------------------------------------------
998 -def create_substance_intake(substance=None, atc=None, encounter=None, episode=None, preparation=None):
999
1000 args = {
1001 'enc': encounter,
1002 'epi': episode,
1003 'prep': preparation,
1004 'subst': create_used_substance(substance = substance, atc = atc)['pk']
1005 }
1006
1007 cmd = u"""
1008 insert into clin.substance_intake (
1009 fk_encounter,
1010 fk_episode,
1011 fk_substance,
1012 preparation,
1013 intake_is_approved_of
1014 ) values (
1015 %(enc)s,
1016 %(epi)s,
1017 %(subst)s,
1018 gm.nullify_empty_string(%(prep)s),
1019 False
1020 )
1021 returning pk
1022 """
1023 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True)
1024 return cSubstanceIntakeEntry(aPK_obj = rows[0][0])
1025 #------------------------------------------------------------
1027 cmd = u'delete from clin.substance_intake where pk = %(pk)s'
1028 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': {'pk': substance}}])
1029 #------------------------------------------------------------
1031
1032 tex = u'\n{\\small\n'
1033 tex += u'\\noindent %s\n' % _('Additional notes')
1034 tex += u'\n'
1035 tex += u'\\noindent \\begin{tabular}{|l|l|l|l|}\n'
1036 tex += u'\\hline\n'
1037 tex += u'%s & %s & %s & \\\\ \n' % (_('Substance'), _('Strength'), _('Brand'))
1038 tex += u'\\hline\n'
1039 tex += u'%s\n'
1040 tex += u'\n'
1041 tex += u'\\end{tabular}\n'
1042 tex += u'}\n'
1043
1044 current_meds = emr.get_current_substance_intake (
1045 include_inactive = False,
1046 include_unapproved = False,
1047 order_by = u'brand, substance'
1048 )
1049
1050 # create lines
1051 lines = []
1052 for med in current_meds:
1053
1054 lines.append(u'%s & %s & %s %s & {\\scriptsize %s} \\\\ \n \\hline \n' % (
1055 med['substance'],
1056 gmTools.coalesce(med['strength'], u''),
1057 gmTools.coalesce(med['brand'], u''),
1058 med['preparation'],
1059 gmTools.coalesce(med['notes'], u'')
1060 ))
1061
1062 return tex % u' \n'.join(lines)
1063
1064 #------------------------------------------------------------
1066
1067 tex = u'\\noindent %s {\\tiny (%s)\\par}\n' % (_('Medication list'), _('ordered by brand'))
1068 tex += u'\n'
1069 tex += u'\\noindent \\begin{tabular}{|l|l|}\n'
1070 tex += u'\\hline\n'
1071 tex += u'%s & %s \\\\ \n' % (_('Drug'), _('Regimen'))
1072 tex += u'\\hline\n'
1073 tex += u'\n'
1074 tex += u'\\hline\n'
1075 tex += u'%s\n'
1076 tex += u'\n'
1077 tex += u'\\end{tabular}\n'
1078
1079 current_meds = emr.get_current_substance_intake (
1080 include_inactive = False,
1081 include_unapproved = False,
1082 order_by = u'brand, substance'
1083 )
1084
1085 # aggregate data
1086 line_data = {}
1087 for med in current_meds:
1088 identifier = gmTools.coalesce(med['brand'], med['substance'])
1089
1090 try:
1091 line_data[identifier]
1092 except KeyError:
1093 line_data[identifier] = {'brand': u'', 'preparation': u'', 'schedule': u'', 'aims': [], 'strengths': []}
1094
1095 line_data[identifier]['brand'] = identifier
1096 if med['strength'] is not None:
1097 line_data[identifier]['strengths'].append(med['strength'].strip())
1098 line_data[identifier]['preparation'] = med['preparation']
1099 line_data[identifier]['schedule'] = gmTools.coalesce(med['schedule'], u'')
1100 if med['aim'] not in line_data[identifier]['aims']:
1101 line_data[identifier]['aims'].append(med['aim'])
1102
1103 # create lines
1104 already_seen = []
1105 lines = []
1106 line1_template = u'%s %s & %s \\\\'
1107 line2_template = u' & {\\scriptsize %s\\par} \\\\'
1108
1109 for med in current_meds:
1110 identifier = gmTools.coalesce(med['brand'], med['substance'])
1111
1112 if identifier in already_seen:
1113 continue
1114
1115 already_seen.append(identifier)
1116
1117 lines.append (line1_template % (
1118 line_data[identifier]['brand'],
1119 line_data[identifier]['preparation'],
1120 line_data[identifier]['schedule']
1121 ))
1122
1123 strengths = u'/'.join(line_data[identifier]['strengths'])
1124 if strengths == u'':
1125 template = u' & {\\scriptsize %s\\par} \\\\'
1126 for aim in line_data[identifier]['aims']:
1127 lines.append(template % aim)
1128 else:
1129 if len(line_data[identifier]['aims']) == 0:
1130 template = u'%s & \\\\'
1131 lines.append(template % strengths)
1132 else:
1133 template = u'%s & {\\scriptsize %s\\par} \\\\'
1134 lines.append(template % (strengths, line_data[identifier]['aims'][0]))
1135 template = u' & {\\scriptsize %s\\par} \\\\'
1136 for aim in line_data[identifier]['aims'][1:]:
1137 lines.append(template % aim)
1138
1139 lines.append(u'\\hline')
1140
1141 return tex % u' \n'.join(lines)
1142 #============================================================
1144 """Represents a drug as marketed by a manufacturer."""
1145
1146 _cmd_fetch_payload = u"select *, xmin from ref.branded_drug where pk = %s"
1147 _cmds_store_payload = [
1148 u"""update ref.branded_drug set
1149 description = %(description)s,
1150 preparation = %(preparation)s,
1151 atc_code = gm.nullify_empty_string(%(atc_code)s),
1152 external_code = gm.nullify_empty_string(%(external_code)s),
1153 external_code_type = gm.nullify_empty_string(%(external_code_type)s),
1154 is_fake = %(is_fake)s,
1155 fk_data_source = %(fk_data_source)s
1156 where
1157 pk = %(pk)s and
1158 xmin = %(xmin)s
1159 returning
1160 xmin
1161 """
1162 ]
1163 _updatable_fields = [
1164 u'description',
1165 u'preparation',
1166 u'atc_code',
1167 u'is_fake',
1168 u'external_code',
1169 u'external_code_type',
1170 u'fk_data_source'
1171 ]
1172 #--------------------------------------------------------
1174 if self._payload[self._idx['external_code']] is None:
1175 return None
1176
1177 return self._payload[self._idx['external_code']]
1178
1179 external_code = property(_get_external_code, lambda x:x)
1180 #--------------------------------------------------------
1182
1183 # FIXME: maybe evaluate fk_data_source ?
1184 if self._payload[self._idx['external_code_type']] is None:
1185 return None
1186
1187 return self._payload[self._idx['external_code_type']]
1188
1189 external_code_type = property(_get_external_code_type, lambda x:x)
1190 #--------------------------------------------------------
1192 cmd = u'select * from ref.substance_in_brand where fk_brand = %(brand)s'
1193 args = {'brand': self._payload[self._idx['pk']]}
1194 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
1195 return rows
1196
1197 components = property(_get_components, lambda x:x)
1198 #--------------------------------------------------------
1200 cmd = u'SELECT EXISTS (SELECT 1 FROM clin.vaccine WHERE fk_brand = %(fk_brand)s)'
1201 args = {'fk_brand': self._payload[self._idx['pk']]}
1202 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
1203 return rows[0][0]
1204
1205 is_vaccine = property(_get_is_vaccine, lambda x:x)
1206 #--------------------------------------------------------
1208
1209 # normalize atc
1210 atc = gmATC.propagate_atc(substance = substance, atc = atc)
1211
1212 args = {
1213 'brand': self.pk_obj,
1214 'desc': substance,
1215 'atc': atc
1216 }
1217
1218 # already exists ?
1219 cmd = u"""
1220 SELECT pk
1221 FROM ref.substance_in_brand
1222 WHERE
1223 fk_brand = %(brand)s
1224 AND
1225 ((description = %(desc)s) OR ((atc_code = %(atc)s) IS TRUE))
1226 """
1227 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
1228 if len(rows) > 0:
1229 return
1230
1231 # create it
1232 cmd = u"""
1233 INSERT INTO ref.substance_in_brand (fk_brand, description, atc_code)
1234 VALUES (%(brand)s, %(desc)s, %(atc)s)
1235 """
1236 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
1237 #------------------------------------------------------------
1240 #------------------------------------------------------------
1242 cmd = u'SELECT * FROM ref.v_substance_in_brand ORDER BY brand, substance'
1243 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = False)
1244 return rows
1245 #------------------------------------------------------------
1247
1248 cmd = u'SELECT pk FROM ref.branded_drug ORDER BY description'
1249 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = False)
1250
1251 return [ cBrandedDrug(aPK_obj = r['pk']) for r in rows ]
1252 #------------------------------------------------------------
1254 args = {'brand': brand_name, 'prep': preparation}
1255
1256 cmd = u'SELECT pk FROM ref.branded_drug WHERE description = %(brand)s AND preparation = %(prep)s'
1257 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
1258
1259 if len(rows) == 0:
1260 return None
1261
1262 return cBrandedDrug(aPK_obj = rows[0]['pk'])
1263 #------------------------------------------------------------
1265
1266 if preparation is None:
1267 preparation = _('units')
1268
1269 if preparation.strip() == u'':
1270 preparation = _('units')
1271
1272 drug = get_drug_by_brand(brand_name = brand_name, preparation = preparation)
1273
1274 if drug is not None:
1275 if return_existing:
1276 return drug
1277 return None
1278
1279 cmd = u'insert into ref.branded_drug (description, preparation) values (%(brand)s, %(prep)s) returning pk'
1280 args = {'brand': brand_name, 'prep': preparation}
1281 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True, get_col_idx = False)
1282
1283 return cBrandedDrug(aPK_obj = rows[0]['pk'])
1284 #------------------------------------------------------------
1286 cmd = u'delete from ref.branded_drug where pk = %(pk)s'
1287 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': {'pk': brand}}])
1288 #------------------------------------------------------------
1290 cmd = u'delete from ref.substance_in_brand where fk_brand = %(brand)s and pk = %(comp)s'
1291 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': {'brand': brand, 'comp': component}}])
1292 #============================================================
1293 # main
1294 #------------------------------------------------------------
1295 if __name__ == "__main__":
1296
1297 if len(sys.argv) < 2:
1298 sys.exit()
1299
1300 if sys.argv[1] != 'test':
1301 sys.exit()
1302
1303 from Gnumed.pycommon import gmLog2
1304 from Gnumed.pycommon import gmI18N
1305 from Gnumed.business import gmPerson
1306
1307 gmI18N.activate_locale()
1308 # gmDateTime.init()
1309 #--------------------------------------------------------
1311 mmi = cGelbeListeWineInterface()
1312 print mmi
1313 print "interface definition:", mmi.version
1314 print "database versions: ", mmi.get_data_source_version()
1315 #--------------------------------------------------------
1317 mmi_file = cGelbeListeCSVFile(filename = sys.argv[2])
1318 for drug in mmi_file:
1319 print "-------------"
1320 print '"%s" (ATC: %s / PZN: %s)' % (drug['name'], drug['atc'], drug['pzn'])
1321 for stoff in drug['wirkstoffe']:
1322 print " Wirkstoff:", stoff
1323 raw_input()
1324 if mmi_file.has_unknown_fields is not None:
1325 print "has extra data under [%s]" % gmTools.default_csv_reader_rest_key
1326 for key in mmi_file.csv_fieldnames:
1327 print key, '->', drug[key]
1328 raw_input()
1329 mmi_file.close()
1330 #--------------------------------------------------------
1334 #--------------------------------------------------------
1336 mmi = cGelbeListeWineInterface()
1337 mmi_file = mmi.select_drugs()
1338 for drug in mmi_file:
1339 print "-------------"
1340 print '"%s" (ATC: %s / PZN: %s)' % (drug['name'], drug['atc'], drug['pzn'])
1341 for stoff in drug['wirkstoffe']:
1342 print " Wirkstoff:", stoff
1343 print drug
1344 mmi_file.close()
1345 #--------------------------------------------------------
1349 #--------------------------------------------------------
1351 mmi = cGelbeListeInterface()
1352 print mmi
1353 print "interface definition:", mmi.version
1354 # Metoprolol + Hct vs Citalopram
1355 diclofenac = '7587712'
1356 phenprocoumon = '4421744'
1357 mmi.check_drug_interactions(drug_ids_list = [diclofenac, phenprocoumon])
1358 #--------------------------------------------------------
1359 # FreeDiams
1360 #--------------------------------------------------------
1362 gmPerson.set_active_patient(patient = gmPerson.cIdentity(aPK_obj = 12))
1363 fd = cFreeDiamsInterface()
1364 fd.patient = gmPerson.gmCurrentPatient()
1365 fd.switch_to_frontend(blocking = True)
1366 fd.import_fd2gm_file()
1367 #--------------------------------------------------------
1368 # generic
1369 #--------------------------------------------------------
1371 drug = create_substance_intake (
1372 substance = u'Whiskey',
1373 atc = u'no ATC available',
1374 encounter = 1,
1375 episode = 1,
1376 preparation = 'a nice glass'
1377 )
1378 print drug
1379 #--------------------------------------------------------
1384 #--------------------------------------------------------
1385 #test_MMI_interface()
1386 test_MMI_file()
1387 #test_mmi_switch_to()
1388 #test_mmi_select_drugs()
1389 #test_mmi_import_substances()
1390 #test_mmi_import_drugs()
1391 #test_fd_switch_to()
1392 #test_interaction_check()
1393 #test_create_substance_intake()
1394 #test_show_components()
1395 #============================================================
1396
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Mon Nov 29 04:06:36 2010 | http://epydoc.sourceforge.net |