| Home | Trees | Indices | Help |
|
|---|
|
|
1 # -*- coding: utf8 -*-
2 """Medication handling code.
3
4 license: GPL v2 or later
5 """
6 #============================================================
7 __version__ = "$Revision: 1.21 $"
8 __author__ = "K.Hilbert <Karsten.Hilbert@gmx.net>"
9
10 import sys
11 import logging
12 import csv
13 import codecs
14 import os
15 import re as regex
16 import subprocess
17 import decimal
18 from xml.etree import ElementTree as etree
19
20
21 if __name__ == '__main__':
22 sys.path.insert(0, '../../')
23 _ = lambda x:x
24 from Gnumed.pycommon import gmBusinessDBObject
25 from Gnumed.pycommon import gmTools
26 from Gnumed.pycommon import gmShellAPI
27 from Gnumed.pycommon import gmPG2
28 from Gnumed.pycommon import gmDispatcher
29 from Gnumed.pycommon import gmMatchProvider
30 from Gnumed.pycommon import gmHooks
31 from Gnumed.pycommon import gmDateTime
32
33 from Gnumed.business import gmATC
34 from Gnumed.business import gmAllergy
35 from Gnumed.business.gmDocuments import DOCUMENT_TYPE_PRESCRIPTION
36 from Gnumed.business.gmDocuments import create_document_type
37
38
39 _log = logging.getLogger('gm.meds')
40 _log.info(__version__)
41
42
43 DEFAULT_MEDICATION_HISTORY_EPISODE = _('Medication history')
44 #============================================================
46 """Always relates to the active patient."""
47 gmHooks.run_hook_script(hook = u'after_substance_intake_modified')
48
49 gmDispatcher.connect(_on_substance_intake_modified, u'substance_intake_mod_db')
50
51 #============================================================
53
54 if search_term is None:
55 return u'http://www.dosing.de'
56
57 terms = []
58 names = []
59
60 if isinstance(search_term, cBrandedDrug):
61 if search_term['atc'] is not None:
62 terms.append(search_term['atc'])
63
64 elif isinstance(search_term, cSubstanceIntakeEntry):
65 names.append(search_term['substance'])
66 if search_term['atc_brand'] is not None:
67 terms.append(search_term['atc_brand'])
68 if search_term['atc_substance'] is not None:
69 terms.append(search_term['atc_substance'])
70
71 elif search_term is not None:
72 names.append(u'%s' % search_term)
73 terms.extend(gmATC.text2atc(text = u'%s' % search_term, fuzzy = True))
74
75 for name in names:
76 if name.endswith('e'):
77 terms.append(name[:-1])
78 else:
79 terms.append(name)
80
81 #url_template = u'http://www.google.de/#q=site%%3Adosing.de+%s'
82 #url = url_template % u'+OR+'.join(terms)
83
84 url_template = u'http://www.google.com/search?hl=de&source=hp&q=site%%3Adosing.de+%s&btnG=Google-Suche'
85 url = url_template % u'+OR+'.join(terms)
86
87 _log.debug(u'renal insufficiency URL: %s', url)
88
89 return url
90 #============================================================
91 # this should be in gmCoding.py
92 -def create_data_source(long_name=None, short_name=None, version=None, source=None, language=None):
93
94 args = {
95 'lname': long_name,
96 'sname': short_name,
97 'ver': version,
98 'src': source,
99 'lang': language
100 }
101
102 cmd = u"""select pk from ref.data_source where name_long = %(lname)s and name_short = %(sname)s and version = %(ver)s"""
103 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}])
104 if len(rows) > 0:
105 return rows[0]['pk']
106
107 cmd = u"""
108 INSERT INTO ref.data_source (name_long, name_short, version, source, lang)
109 VALUES (
110 %(lname)s,
111 %(sname)s,
112 %(ver)s,
113 %(src)s,
114 %(lang)s
115 )
116 returning pk
117 """
118 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True)
119
120 return rows[0]['pk']
121 #============================================================
122 # wishlist:
123 # - --conf-file= for glwin.exe
124 # - wirkstoff: Konzentration auch in Multiprodukten
125 # - wirkstoff: ATC auch in Multiprodukten
126 # - Suche nach ATC per CLI
127
129 """Iterator over a Gelbe Liste/MMI v8.2 CSV file."""
130
131 version = u'Gelbe Liste/MMI v8.2 CSV file interface'
132 default_transfer_file_windows = r"c:\rezept.txt"
133 #default_encoding = 'cp1252'
134 default_encoding = 'cp1250'
135 csv_fieldnames = [
136 u'name',
137 u'packungsgroesse', # obsolete, use "packungsmenge"
138 u'darreichungsform',
139 u'packungstyp',
140 u'festbetrag',
141 u'avp',
142 u'hersteller',
143 u'rezepttext',
144 u'pzn',
145 u'status_vertrieb',
146 u'status_rezeptpflicht',
147 u'status_fachinfo',
148 u'btm',
149 u'atc',
150 u'anzahl_packungen',
151 u'zuzahlung_pro_packung',
152 u'einheit',
153 u'schedule_morgens',
154 u'schedule_mittags',
155 u'schedule_abends',
156 u'schedule_nachts',
157 u'status_dauermedikament',
158 u'status_hausliste',
159 u'status_negativliste',
160 u'ik_nummer',
161 u'status_rabattvertrag',
162 u'wirkstoffe',
163 u'wirkstoffmenge',
164 u'wirkstoffeinheit',
165 u'wirkstoffmenge_bezug',
166 u'wirkstoffmenge_bezugseinheit',
167 u'status_import',
168 u'status_lifestyle',
169 u'status_ausnahmeliste',
170 u'packungsmenge',
171 u'apothekenpflicht',
172 u'status_billigere_packung',
173 u'rezepttyp',
174 u'besonderes_arzneimittel', # Abstimmungsverfahren SGB-V
175 u't_rezept_pflicht', # Thalidomid-Rezept
176 u'erstattbares_medizinprodukt',
177 u'hilfsmittel',
178 u'hzv_rabattkennung',
179 u'hzv_preis'
180 ]
181 boolean_fields = [
182 u'status_rezeptpflicht',
183 u'status_fachinfo',
184 u'btm',
185 u'status_dauermedikament',
186 u'status_hausliste',
187 u'status_negativliste',
188 u'status_rabattvertrag',
189 u'status_import',
190 u'status_lifestyle',
191 u'status_ausnahmeliste',
192 u'apothekenpflicht',
193 u'status_billigere_packung',
194 u'besonderes_arzneimittel', # Abstimmungsverfahren SGB-V
195 u't_rezept_pflicht',
196 u'erstattbares_medizinprodukt',
197 u'hilfsmittel'
198 ]
199 #--------------------------------------------------------
201
202 _log.info(cGelbeListeCSVFile.version)
203
204 self.filename = filename
205 if filename is None:
206 self.filename = cGelbeListeCSVFile.default_transfer_file_windows
207
208 _log.debug('reading Gelbe Liste/MMI drug data from [%s]', self.filename)
209
210 self.csv_file = codecs.open(filename = filename, mode = 'rUb', encoding = cGelbeListeCSVFile.default_encoding)
211
212 self.csv_lines = gmTools.unicode_csv_reader (
213 self.csv_file,
214 fieldnames = cGelbeListeCSVFile.csv_fieldnames,
215 delimiter = ';',
216 quotechar = '"',
217 dict = True
218 )
219 #--------------------------------------------------------
222 #--------------------------------------------------------
224 line = self.csv_lines.next()
225
226 for field in cGelbeListeCSVFile.boolean_fields:
227 line[field] = (line[field].strip() == u'T')
228
229 # split field "Wirkstoff" by ";"
230 if line['wirkstoffe'].strip() == u'':
231 line['wirkstoffe'] = []
232 else:
233 line['wirkstoffe'] = [ wirkstoff.strip() for wirkstoff in line['wirkstoffe'].split(u';') ]
234
235 return line
236 #--------------------------------------------------------
238 try: self.csv_file.close()
239 except: pass
240
241 if truncate:
242 try: os.open(self.filename, 'wb').close
243 except: pass
244 #--------------------------------------------------------
247
248 has_unknown_fields = property(_get_has_unknown_fields, lambda x:x)
249 #============================================================
251
252 #--------------------------------------------------------
257 #--------------------------------------------------------
260 #--------------------------------------------------------
263 #--------------------------------------------------------
266 #--------------------------------------------------------
268 self.switch_to_frontend()
269 #--------------------------------------------------------
271 self.switch_to_frontend()
272 #--------------------------------------------------------
274 self.switch_to_frontend()
275 #--------------------------------------------------------
277 self.switch_to_frontend()
278 #--------------------------------------------------------
282 #============================================================
284
285 version = u'FreeDiams v0.5.4 interface'
286 default_encoding = 'utf8'
287 default_dob_format = '%Y/%m/%d'
288
289 map_gender2mf = {
290 'm': u'M',
291 'f': u'F',
292 'tf': u'H',
293 'tm': u'H',
294 'h': u'H'
295 }
296 #--------------------------------------------------------
298 cDrugDataSourceInterface.__init__(self)
299 _log.info(cFreeDiamsInterface.version)
300
301 self.__imported_drugs = []
302
303 self.__gm2fd_filename = gmTools.get_unique_filename(prefix = r'gm2freediams-', suffix = r'.xml')
304 _log.debug('GNUmed -> FreeDiams "exchange-in" file: %s', self.__gm2fd_filename)
305 self.__fd2gm_filename = gmTools.get_unique_filename(prefix = r'freediams2gm-', suffix = r'.xml')
306 _log.debug('GNUmed <-> FreeDiams "exchange-out"/"prescription" file: %s', self.__fd2gm_filename)
307 paths = gmTools.gmPaths()
308 self.__fd4gm_config_file = os.path.join(paths.home_dir, '.gnumed', 'freediams4gm.conf')
309
310 self.path_to_binary = None
311 self.__detect_binary()
312 #--------------------------------------------------------
314 # ~/.freediams/config.ini: [License] -> AcceptedVersion=....
315
316 if not self.__detect_binary():
317 return False
318
319 freediams = subprocess.Popen (
320 args = u'--version', # --version or -version or -v
321 executable = self.path_to_binary,
322 stdout = subprocess.PIPE,
323 stderr = subprocess.PIPE,
324 # close_fds = True, # Windows can't do that in conjunction with stdout/stderr = ... :-(
325 universal_newlines = True
326 )
327 data, errors = freediams.communicate()
328 version = regex.search('FreeDiams\s\d.\d.\d', data).group().split()[1]
329 _log.debug('FreeDiams %s', version)
330
331 return version
332 #--------------------------------------------------------
334 return create_data_source (
335 long_name = u'"FreeDiams" Drug Database Frontend',
336 short_name = u'FreeDiams',
337 version = self.get_data_source_version(),
338 source = u'http://ericmaeker.fr/FreeMedForms/di-manual/index.html',
339 language = u'fr' # actually to be multi-locale
340 )
341 #--------------------------------------------------------
343 """http://ericmaeker.fr/FreeMedForms/di-manual/en/html/ligne_commandes.html"""
344
345 _log.debug('calling FreeDiams in [%s] mode', mode)
346
347 self.__imported_drugs = []
348
349 if not self.__detect_binary():
350 return False
351
352 self.__create_gm2fd_file(mode = mode)
353
354 args = u'--exchange-in="%s"' % (self.__gm2fd_filename)
355 cmd = r'%s %s' % (self.path_to_binary, args)
356 if not gmShellAPI.run_command_in_shell(command = cmd, blocking = blocking):
357 _log.error('problem switching to the FreeDiams drug database')
358 return False
359
360 if blocking == True:
361 self.import_fd2gm_file_as_drugs()
362
363 return True
364 #--------------------------------------------------------
366 self.switch_to_frontend(blocking = True)
367 #--------------------------------------------------------
369 if substance_intakes is None:
370 return
371 if len(substance_intakes) < 2:
372 return
373
374 self.__create_prescription_file(substance_intakes = substance_intakes)
375 self.switch_to_frontend(mode = 'interactions', blocking = False)
376 #--------------------------------------------------------
378 if substance_intake is None:
379 return
380
381 self.__create_prescription_file(substance_intakes = [substance_intake])
382 self.switch_to_frontend(mode = 'interactions', blocking = False)
383 #--------------------------------------------------------
385 self.show_info_on_drug(substance_intake = substance_intake)
386 #--------------------------------------------------------
388 if substance_intakes is None:
389 if not self.__export_latest_prescription():
390 self.__create_prescription_file()
391 else:
392 self.__create_prescription_file(substance_intakes = substance_intakes)
393
394 self.switch_to_frontend(mode = 'prescription', blocking = True)
395 self.import_fd2gm_file_as_prescription()
396
397 return self.__imported_drugs
398 #--------------------------------------------------------
399 # internal helpers
400 #--------------------------------------------------------
402
403 if self.path_to_binary is not None:
404 return True
405
406 found, cmd = gmShellAPI.find_first_binary(binaries = [
407 r'/usr/bin/freediams',
408 r'freediams',
409 r'/Applications/FreeDiams.app/Contents/MacOs/FreeDiams',
410 r'C:\Program Files\FreeDiams\freediams.exe',
411 r'c:\programs\freediams\freediams.exe',
412 r'freediams.exe'
413 ])
414
415 if found:
416 self.path_to_binary = cmd
417 return True
418
419 try:
420 self.custom_path_to_binary
421 except AttributeError:
422 _log.error('cannot find FreeDiams binary, no custom path set')
423 return False
424
425 if self.custom_path_to_binary is None:
426 _log.error('cannot find FreeDiams binary')
427 return False
428
429 found, cmd = gmShellAPI.detect_external_binary(binary = self.custom_path_to_binary)
430 if found:
431 self.path_to_binary = cmd
432 return True
433
434 _log.error('cannot find FreeDiams binary')
435 return False
436 #--------------------------------------------------------
438
439 if self.patient is None:
440 _log.debug('cannot export latest FreeDiams prescriptions w/o patient')
441 return False
442
443 docs = self.patient.get_document_folder()
444 prescription = docs.get_latest_freediams_prescription()
445 if prescription is None:
446 _log.debug('no FreeDiams prescription available')
447 return False
448
449 for part in prescription.parts:
450 if part['filename'] == u'freediams-prescription.xml':
451 if part.export_to_file(filename = self.__fd2gm_filename) is not None:
452 return True
453
454 _log.error('cannot export latest FreeDiams prescription to XML file')
455
456 return False
457 #--------------------------------------------------------
459 """FreeDiams calls this exchange-out or prescription file.
460
461 CIS stands for Unique Speciality Identifier (eg bisoprolol 5 mg, gel).
462 CIS is AFSSAPS specific, but pharmacist can retreive drug name with the CIS.
463 AFSSAPS is the French FDA.
464
465 CIP stands for Unique Presentation Identifier (eg 30 pills plaq)
466 CIP if you want to specify the packaging of the drug (30 pills
467 thermoformed tablet...) -- actually not really usefull for french
468 doctors.
469 # .external_code_type: u'FR-CIS'
470 # .external_cod: the CIS value
471
472 OnlyForTest:
473 OnlyForTest drugs will be processed by the IA Engine but
474 not printed (regardless of FreeDiams mode). They are shown
475 in gray in the prescription view.
476
477 Select-only is a mode where FreeDiams creates a list of drugs
478 not a full prescription. In this list, users can add ForTestOnly
479 drug if they want to
480 1. print the list without some drugs
481 2. but including these drugs in the IA engine calculation
482
483 Select-Only mode does not have any relation with the ForTestOnly drugs.
484
485 IsTextual:
486 What is the use and significance of the
487 <IsTextual>true/false</IsTextual>
488 flag when both <DrugName> and <TextualDrugName> exist ?
489
490 This tag must be setted even if it sounds like a duplicated
491 data. This tag is needed inside FreeDiams code.
492
493 INN:
494 GNUmed will pass the substance in <TextualDrugName
495 and will also pass <INN>True</INN>.
496
497 Eric: Nop, this is not usefull because pure textual drugs
498 are not processed but just shown.
499 """
500 # virginize file
501 open(self.__fd2gm_filename, 'wb').close()
502
503 # make sure we've got something to do
504 if substance_intakes is None:
505 if self.patient is None:
506 _log.warning('cannot create prescription file because there is neither a patient nor a substance intake list')
507 # do fail because __export_latest_prescription() should not have been called without patient
508 return False
509 emr = self.patient.get_emr()
510 substance_intakes = emr.get_current_substance_intake (
511 include_inactive = False,
512 include_unapproved = True
513 )
514
515 drug_snippets = []
516
517 # process FD drugs
518 fd_intakes = [ i for i in substance_intakes if (
519 (i['intake_is_approved_of'] is True)
520 and
521 (i['external_code_type_brand'] is not None)
522 and
523 (i['external_code_type_brand'].startswith(u'FreeDiams::'))
524 )]
525
526 intakes_pooled_by_brand = {}
527 for intake in fd_intakes:
528 # this will leave only one entry per brand
529 # but FreeDiams knows the components ...
530 intakes_pooled_by_brand[intake['brand']] = intake
531 del fd_intakes
532
533 drug_snippet = u"""<Prescription>
534 <IsTextual>False</IsTextual>
535 <DrugName>%s</DrugName>
536 <Drug_UID>%s</Drug_UID>
537 <Drug_UID_type>%s</Drug_UID_type> <!-- not yet supported by FreeDiams -->
538 </Prescription>"""
539
540 last_db_id = u'CA_HCDPD'
541 for intake in intakes_pooled_by_brand.values():
542 last_db_id = gmTools.xml_escape_string(text = intake['external_code_type_brand'].replace(u'FreeDiams::', u'').split(u'::')[0])
543 drug_snippets.append(drug_snippet % (
544 gmTools.xml_escape_string(text = intake['brand'].strip()),
545 gmTools.xml_escape_string(text = intake['external_code_brand'].strip()),
546 last_db_id
547 ))
548
549 # process non-FD drugs
550 non_fd_intakes = [ i for i in substance_intakes if (
551 (i['intake_is_approved_of'] is True)
552 and (
553 (i['external_code_type_brand'] is None)
554 or
555 (not i['external_code_type_brand'].startswith(u'FreeDiams::'))
556 )
557 )]
558
559 non_fd_brand_intakes = [ i for i in non_fd_intakes if i['brand'] is not None ]
560 non_fd_substance_intakes = [ i for i in non_fd_intakes if i['brand'] is None ]
561 del non_fd_intakes
562
563 drug_snippet = u"""<Prescription>
564 <IsTextual>True</IsTextual>
565 <TextualDrugName>%s</TextualDrugName>
566 </Prescription>"""
567
568 for intake in non_fd_substance_intakes:
569 drug_name = u'%s %s%s (%s)%s' % (
570 intake['substance'],
571 intake['amount'],
572 intake['unit'],
573 intake['preparation'],
574 gmTools.coalesce(intake['schedule'], u'', _('\n Take: %s'))
575 )
576 drug_snippets.append(drug_snippet % gmTools.xml_escape_string(text = drug_name.strip()))
577
578 intakes_pooled_by_brand = {}
579 for intake in non_fd_brand_intakes:
580 brand = u'%s %s' % (intake['brand'], intake['preparation'])
581 try:
582 intakes_pooled_by_brand[brand].append(intake)
583 except KeyError:
584 intakes_pooled_by_brand[brand] = [intake]
585
586 for brand, comps in intakes_pooled_by_brand.iteritems():
587 drug_name = u'%s\n' % brand
588 for comp in comps:
589 drug_name += u' %s %s%s\n' % (
590 comp['substance'],
591 comp['amount'],
592 comp['unit']
593 )
594 if comps[0]['schedule'] is not None:
595 drug_name += gmTools.coalesce(comps[0]['schedule'], u'', _('Take: %s'))
596 drug_snippets.append(drug_snippet % gmTools.xml_escape_string(text = drug_name.strip()))
597
598 # assemble XML file
599 xml = u"""<?xml version = "1.0" encoding = "UTF-8"?>
600
601 <FreeDiams>
602 <DrugsDatabaseName>%s</DrugsDatabaseName>
603 <FullPrescription version="0.5.0">
604
605 %s
606
607 </FullPrescription>
608 </FreeDiams>
609 """
610
611 xml_file = codecs.open(self.__fd2gm_filename, 'wb', 'utf8')
612 xml_file.write(xml % (
613 last_db_id,
614 u'\n\t\t'.join(drug_snippets)
615 ))
616 xml_file.close()
617
618 return True
619 #--------------------------------------------------------
621
622 if mode == 'interactions':
623 mode = u'select-only'
624 elif mode == 'prescription':
625 mode = u'prescriber'
626 else:
627 mode = u'select-only'
628
629 xml_file = codecs.open(self.__gm2fd_filename, 'wb', 'utf8')
630
631 xml = u"""<?xml version="1.0" encoding="UTF-8"?>
632
633 <FreeDiams_In version="0.5.0">
634 <EMR name="GNUmed" uid="unused"/>
635 <ConfigFile value="%s"/>
636 <ExchangeOut value="%s" format="xml"/>
637 <!-- <DrugsDatabase uid="can be set to a specific DB"/> -->
638 <Ui editmode="%s" blockPatientDatas="1"/>
639 %%s
640 </FreeDiams_In>
641
642 <!--
643 # FIXME: search by LOINC code and add (as soon as supported by FreeDiams ...)
644 <Creatinine value="12" unit="mg/l or mmol/l"/>
645 <Weight value="70" unit="kg or pd" />
646 <Height value="170" unit="cm or "/>
647 <ICD10 value="J11.0;A22;Z23"/>
648 -->
649 """ % (
650 self.__fd4gm_config_file,
651 self.__fd2gm_filename,
652 mode
653 )
654
655 if self.patient is None:
656 xml_file.write(xml % u'')
657 xml_file.close()
658 return
659
660 name = self.patient.get_active_name()
661 if self.patient['dob'] is None:
662 dob = u''
663 else:
664 dob = self.patient['dob'].strftime(cFreeDiamsInterface.default_dob_format)
665
666 emr = self.patient.get_emr()
667 allgs = emr.get_allergies()
668 atc_allgs = [
669 a['atc_code'] for a in allgs if ((a['atc_code'] is not None) and (a['type'] == u'allergy'))
670 ]
671 atc_sens = [
672 a['atc_code'] for a in allgs if ((a['atc_code'] is not None) and (a['type'] == u'sensitivity'))
673 ]
674 inn_allgs = [
675 a['allergene'] for a in allgs if ((a['allergene'] is not None) and (a['type'] == u'allergy'))
676 ]
677 inn_sens = [
678 a['allergene'] for a in allgs if ((a['allergene'] is not None) and (a['type'] == u'sensitivity'))
679 ]
680 # this is rather fragile: FreeDiams won't know what type of UID this is
681 # (but it will assume it is of the type of the drug database in use)
682 # but eventually FreeDiams puts all drugs into one database :-)
683 uid_allgs = [
684 a['substance_code'] for a in allgs if ((a['substance_code'] is not None) and (a['type'] == u'allergy'))
685 ]
686 uid_sens = [
687 a['substance_code'] for a in allgs if ((a['substance_code'] is not None) and (a['type'] == u'sensitivity'))
688 ]
689
690 patient_xml = u"""<Patient>
691 <Identity
692 lastnames="%s"
693 firstnames="%s"
694 uid="%s"
695 dob="%s"
696 gender="%s"
697 />
698 <ATCAllergies value="%s"/>
699 <ATCIntolerances value="%s"/>
700
701 <InnAllergies value="%s"/>
702 <InnIntolerances value="%s"/>
703
704 <DrugsUidAllergies value="%s"/>
705 <DrugsUidIntolerances value="%s"/>
706 </Patient>
707 """ % (
708 gmTools.xml_escape_string(text = name['lastnames']),
709 gmTools.xml_escape_string(text = name['firstnames']),
710 self.patient.ID,
711 dob,
712 cFreeDiamsInterface.map_gender2mf[self.patient['gender']],
713 gmTools.xml_escape_string(text = u';'.join(atc_allgs)),
714 gmTools.xml_escape_string(text = u';'.join(atc_sens)),
715 gmTools.xml_escape_string(text = u';'.join(inn_allgs)),
716 gmTools.xml_escape_string(text = u';'.join(inn_sens)),
717 gmTools.xml_escape_string(text = u';'.join(uid_allgs)),
718 gmTools.xml_escape_string(text = u';'.join(uid_sens))
719 )
720
721 xml_file.write(xml % patient_xml)
722 xml_file.close()
723 #--------------------------------------------------------
725
726 if filename is None:
727 filename = self.__fd2gm_filename
728
729 fd2gm_xml = etree.ElementTree()
730 fd2gm_xml.parse(filename)
731
732 pdfs = fd2gm_xml.findall('ExtraDatas/Printed')
733 if len(pdfs) == 0:
734 return
735
736 fd_filenames = []
737 for pdf in pdfs:
738 fd_filenames.append(pdf.attrib['file'])
739
740 docs = self.patient.get_document_folder()
741 emr = self.patient.get_emr()
742
743 prescription = docs.add_document (
744 document_type = create_document_type (
745 document_type = DOCUMENT_TYPE_PRESCRIPTION
746 )['pk_doc_type'],
747 encounter = emr.active_encounter['pk_encounter'],
748 episode = emr.add_episode (
749 episode_name = DEFAULT_MEDICATION_HISTORY_EPISODE,
750 is_open = False
751 )['pk_episode']
752 )
753 prescription['ext_ref'] = u'FreeDiams'
754 prescription.save()
755 fd_filenames.append(filename)
756 success, msg, parts = prescription.add_parts_from_files(files = fd_filenames)
757 if not success:
758 _log.error(msg)
759 return
760
761 for part in parts:
762 part['obj_comment'] = _('copy')
763 part.save()
764
765 xml_part = parts[-1]
766 xml_part['filename'] = u'freediams-prescription.xml'
767 xml_part['obj_comment'] = _('data')
768 xml_part.save()
769
770 # are we the intended reviewer ?
771 from Gnumed.business.gmPerson import gmCurrentProvider
772 me = gmCurrentProvider()
773 # if so: auto-sign the prescription
774 if xml_part['pk_intended_reviewer'] == me['pk_staff']:
775 prescription.set_reviewed(technically_abnormal = False, clinically_relevant = False)
776 #--------------------------------------------------------
778 """
779 If returning textual prescriptions (say, drugs which FreeDiams
780 did not know) then "IsTextual" will be True and UID will be -1.
781 """
782 if filename is None:
783 filename = self.__fd2gm_filename
784
785 # FIXME: do not import IsTextual drugs, or rather, make that configurable
786
787 fd2gm_xml = etree.ElementTree()
788 fd2gm_xml.parse(filename)
789
790 data_src_pk = self.create_data_source_entry()
791
792 db_def = fd2gm_xml.find('DrugsDatabaseName')
793 db_id = db_def.text.strip()
794 drug_id_name = db_def.attrib['drugUidName']
795 fd_xml_drug_entries = fd2gm_xml.findall('FullPrescription/Prescription')
796
797 self.__imported_drugs = []
798 for fd_xml_drug in fd_xml_drug_entries:
799 drug_uid = fd_xml_drug.find('Drug_UID').text.strip()
800 if drug_uid == u'-1':
801 _log.debug('skipping textual drug')
802 continue # it's a TextualDrug, skip it
803 drug_name = fd_xml_drug.find('DrugName').text.replace(', )', ')').strip()
804 drug_form = fd_xml_drug.find('DrugForm').text.strip()
805 drug_atc = fd_xml_drug.find('DrugATC')
806 if drug_atc is None:
807 drug_atc = u''
808 else:
809 if drug_atc.text is None:
810 drug_atc = u''
811 else:
812 drug_atc = drug_atc.text.strip()
813
814 # create new branded drug
815 new_drug = create_branded_drug(brand_name = drug_name, preparation = drug_form, return_existing = True)
816 self.__imported_drugs.append(new_drug)
817 new_drug['is_fake_brand'] = False
818 new_drug['atc'] = drug_atc
819 new_drug['external_code_type'] = u'FreeDiams::%s::%s' % (db_id, drug_id_name)
820 new_drug['external_code'] = drug_uid
821 new_drug['pk_data_source'] = data_src_pk
822 new_drug.save()
823
824 # parse XML for composition records
825 fd_xml_components = fd_xml_drug.getiterator('Composition')
826 comp_data = {}
827 for fd_xml_comp in fd_xml_components:
828
829 data = {}
830
831 amount = regex.match(r'\d+[.,]{0,1}\d*', fd_xml_comp.attrib['strenght'].strip()) # sic, typo
832 if amount is None:
833 amount = 99999
834 else:
835 amount = amount.group()
836 data['amount'] = amount
837
838 unit = regex.sub(r'\d+[.,]{0,1}\d*', u'', fd_xml_comp.attrib['strenght'].strip()).strip() # sic, typo
839 if unit == u'':
840 unit = u'*?*'
841 data['unit'] = unit
842
843 molecule_name = fd_xml_comp.attrib['molecularName'].strip()
844 if molecule_name != u'':
845 create_consumable_substance(substance = molecule_name, atc = None, amount = amount, unit = unit)
846 data['molecule_name'] = molecule_name
847
848 inn_name = fd_xml_comp.attrib['inn'].strip()
849 if inn_name != u'':
850 create_consumable_substance(substance = inn_name, atc = None, amount = amount, unit = unit)
851 data['inn_name'] = molecule_name
852
853 if molecule_name == u'':
854 data['substance'] = inn_name
855 _log.info('linking INN [%s] rather than molecularName as component', inn_name)
856 else:
857 data['substance'] = molecule_name
858
859 data['nature'] = fd_xml_comp.attrib['nature'].strip()
860 data['nature_ID'] = fd_xml_comp.attrib['natureLink'].strip()
861
862 # merge composition records of SA/FT nature
863 try:
864 old_data = comp_data[data['nature_ID']]
865 # normalize INN
866 if old_data['inn_name'] == u'':
867 old_data['inn_name'] = data['inn_name']
868 if data['inn_name'] == u'':
869 data['inn_name'] = old_data['inn_name']
870 # normalize molecule
871 if old_data['molecule_name'] == u'':
872 old_data['molecule_name'] = data['molecule_name']
873 if data['molecule_name'] == u'':
874 data['molecule_name'] = old_data['molecule_name']
875 # FT: transformed form
876 # SA: active substance
877 # it would be preferable to use the SA record because that's what's *actually*
878 # contained in the drug, however FreeDiams does not list the amount thereof
879 # (rather that of the INN)
880 if data['nature'] == u'FT':
881 comp_data[data['nature_ID']] = data
882 else:
883 comp_data[data['nature_ID']] = old_data
884
885 # or create new record
886 except KeyError:
887 comp_data[data['nature_ID']] = data
888
889 # actually create components from (possibly merged) composition records
890 for key, data in comp_data.items():
891 new_drug.add_component (
892 substance = data['substance'],
893 atc = None,
894 amount = data['amount'],
895 unit = data['unit']
896 )
897 #============================================================
899 """Support v8.2 CSV file interface only."""
900
901 version = u'Gelbe Liste/MMI v8.2 interface'
902 default_encoding = 'cp1250'
903 bdt_line_template = u'%03d6210#%s\r\n' # Medikament verordnet auf Kassenrezept
904 bdt_line_base_length = 8
905 #--------------------------------------------------------
907
908 cDrugDataSourceInterface.__init__(self)
909
910 _log.info(u'%s (native Windows)', cGelbeListeWindowsInterface.version)
911
912 self.path_to_binary = r'C:\Programme\MMI PHARMINDEX\glwin.exe'
913 self.args = r'-KEEPBACKGROUND -PRESCRIPTIONFILE %s -CLOSETOTRAY'
914
915 paths = gmTools.gmPaths()
916
917 self.default_csv_filename = os.path.join(paths.home_dir, '.gnumed', 'tmp', 'rezept.txt')
918 self.default_csv_filename_arg = os.path.join(paths.home_dir, '.gnumed', 'tmp')
919 self.interactions_filename = os.path.join(paths.home_dir, '.gnumed', 'tmp', 'gm2mmi.bdt')
920 self.data_date_filename = r'C:\Programme\MMI PHARMINDEX\datadate.txt'
921
922 self.__data_date = None
923 self.__online_update_date = None
924
925 # use adjusted config.dat
926 #--------------------------------------------------------
928
929 if self.__data_date is not None:
930 if not force_reload:
931 return {
932 'data': self.__data_date,
933 'online_update': self.__online_update_date
934 }
935 try:
936 open(self.data_date_filename, 'wb').close()
937 except StandardError:
938 _log.error('problem querying the MMI drug database for version information')
939 _log.exception('cannot create MMI drug database version file [%s]', self.data_date_filename)
940 self.__data_date = None
941 self.__online_update_date = None
942 return {
943 'data': u'?',
944 'online_update': u'?'
945 }
946
947 cmd = u'%s -DATADATE' % self.path_to_binary
948 if not gmShellAPI.run_command_in_shell(command = cmd, blocking = True):
949 _log.error('problem querying the MMI drug database for version information')
950 self.__data_date = None
951 self.__online_update_date = None
952 return {
953 'data': u'?',
954 'online_update': u'?'
955 }
956
957 try:
958 version_file = open(self.data_date_filename, 'rU')
959 except StandardError:
960 _log.error('problem querying the MMI drug database for version information')
961 _log.exception('cannot open MMI drug database version file [%s]', self.data_date_filename)
962 self.__data_date = None
963 self.__online_update_date = None
964 return {
965 'data': u'?',
966 'online_update': u'?'
967 }
968
969 self.__data_date = version_file.readline()[:10]
970 self.__online_update_date = version_file.readline()[:10]
971 version_file.close()
972
973 return {
974 'data': self.__data_date,
975 'online_update': self.__online_update_date
976 }
977 #--------------------------------------------------------
979 versions = self.get_data_source_version()
980
981 return create_data_source (
982 long_name = u'Medikamentendatenbank "mmi PHARMINDEX" (Gelbe Liste)',
983 short_name = u'GL/MMI',
984 version = u'Daten: %s, Preise (Onlineupdate): %s' % (versions['data'], versions['online_update']),
985 source = u'Medizinische Medien Informations GmbH, Am Forsthaus Gravenbruch 7, 63263 Neu-Isenburg',
986 language = u'de'
987 )
988 #--------------------------------------------------------
990
991 try:
992 # must make sure csv file exists
993 open(self.default_csv_filename, 'wb').close()
994 except IOError:
995 _log.exception('problem creating GL/MMI <-> GNUmed exchange file')
996 return False
997
998 if cmd is None:
999 cmd = (u'%s %s' % (self.path_to_binary, self.args)) % self.default_csv_filename_arg
1000
1001 if not gmShellAPI.run_command_in_shell(command = cmd, blocking = blocking):
1002 _log.error('problem switching to the MMI drug database')
1003 # apparently on the first call MMI does not
1004 # consistently return 0 on success
1005 # return False
1006
1007 return True
1008 #--------------------------------------------------------
1010
1011 # better to clean up interactions file
1012 open(self.interactions_filename, 'wb').close()
1013
1014 if not self.switch_to_frontend(blocking = True):
1015 return None
1016
1017 return cGelbeListeCSVFile(filename = self.default_csv_filename)
1018 #--------------------------------------------------------
1020
1021 selected_drugs = self.__let_user_select_drugs()
1022 if selected_drugs is None:
1023 return None
1024
1025 new_substances = []
1026
1027 for drug in selected_drugs:
1028 atc = None # hopefully MMI eventually supports atc-per-substance in a drug...
1029 if len(drug['wirkstoffe']) == 1:
1030 atc = drug['atc']
1031 for wirkstoff in drug['wirkstoffe']:
1032 new_substances.append(create_consumable_substance(substance = wirkstoff, atc = atc, amount = amount, unit = unit))
1033
1034 selected_drugs.close()
1035
1036 return new_substances
1037 #--------------------------------------------------------
1039
1040 selected_drugs = self.__let_user_select_drugs()
1041 if selected_drugs is None:
1042 return None
1043
1044 data_src_pk = self.create_data_source_entry()
1045
1046 new_drugs = []
1047 new_substances = []
1048
1049 for entry in selected_drugs:
1050
1051 _log.debug('importing drug: %s %s', entry['name'], entry['darreichungsform'])
1052
1053 if entry[u'hilfsmittel']:
1054 _log.debug('skipping Hilfsmittel')
1055 continue
1056
1057 if entry[u'erstattbares_medizinprodukt']:
1058 _log.debug('skipping sonstiges Medizinprodukt')
1059 continue
1060
1061 # create branded drug (or get it if it already exists)
1062 drug = create_branded_drug(brand_name = entry['name'], preparation = entry['darreichungsform'])
1063 if drug is None:
1064 drug = get_drug_by_brand(brand_name = entry['name'], preparation = entry['darreichungsform'])
1065 new_drugs.append(drug)
1066
1067 # update fields
1068 drug['is_fake_brand'] = False
1069 drug['atc'] = entry['atc']
1070 drug['external_code_type'] = u'DE-PZN'
1071 drug['external_code'] = entry['pzn']
1072 drug['fk_data_source'] = data_src_pk
1073 drug.save()
1074
1075 # add components to brand
1076 atc = None # hopefully MMI eventually supports atc-per-substance in a drug...
1077 if len(entry['wirkstoffe']) == 1:
1078 atc = entry['atc']
1079 for wirkstoff in entry['wirkstoffe']:
1080 drug.add_component(substance = wirkstoff, atc = atc)
1081
1082 # create as consumable substances, too
1083 atc = None # hopefully MMI eventually supports atc-per-substance in a drug...
1084 if len(entry['wirkstoffe']) == 1:
1085 atc = entry['atc']
1086 for wirkstoff in entry['wirkstoffe']:
1087 new_substances.append(create_consumable_substance(substance = wirkstoff, atc = atc, amount = amount, unit = unit))
1088
1089 return new_drugs, new_substances
1090 #--------------------------------------------------------
1092 """For this to work the BDT interaction check must be configured in the MMI."""
1093
1094 if drug_ids_list is None:
1095 if substances is None:
1096 return
1097 if len(substances) < 2:
1098 return
1099 drug_ids_list = [ (s.external_code_type, s.external_code) for s in substances ]
1100 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')]
1101
1102 else:
1103 if len(drug_ids_list) < 2:
1104 return
1105
1106 if drug_ids_list < 2:
1107 return
1108
1109 bdt_file = codecs.open(filename = self.interactions_filename, mode = 'wb', encoding = cGelbeListeWindowsInterface.default_encoding)
1110
1111 for pzn in drug_ids_list:
1112 pzn = pzn.strip()
1113 lng = cGelbeListeWindowsInterface.bdt_line_base_length + len(pzn)
1114 bdt_file.write(cGelbeListeWindowsInterface.bdt_line_template % (lng, pzn))
1115
1116 bdt_file.close()
1117
1118 self.switch_to_frontend(blocking = False)
1119 #--------------------------------------------------------
1121 self.switch_to_frontend(blocking = True)
1122 #--------------------------------------------------------
1124
1125 cmd = None
1126
1127 if substance.external_code_type == u'DE-PZN':
1128 cmd = u'%s -PZN %s' % (self.path_to_binary, substance.external_code)
1129
1130 if cmd is None:
1131 name = gmTools.coalesce (
1132 substance['brand'],
1133 substance['substance']
1134 )
1135 cmd = u'%s -NAME %s' % (self.path_to_binary, name)
1136
1137 # better to clean up interactions file
1138 open(self.interactions_filename, 'wb').close()
1139
1140 self.switch_to_frontend(cmd = cmd)
1141 #============================================================
1143
1145 cGelbeListeWindowsInterface.__init__(self)
1146
1147 _log.info(u'%s (WINE extension)', cGelbeListeWindowsInterface.version)
1148
1149 # FIXME: if -CLOSETOTRAY is used GNUmed cannot detect the end of MMI
1150 self.path_to_binary = r'wine "C:\Programme\MMI PHARMINDEX\glwin.exe"'
1151 self.args = r'"-PRESCRIPTIONFILE %s -KEEPBACKGROUND"'
1152
1153 paths = gmTools.gmPaths()
1154
1155 self.default_csv_filename = os.path.join(paths.home_dir, '.wine', 'drive_c', 'windows', 'temp', 'mmi2gm.csv')
1156 self.default_csv_filename_arg = r'c:\windows\temp\mmi2gm.csv'
1157 self.interactions_filename = os.path.join(paths.home_dir, '.wine', 'drive_c', 'windows', 'temp', 'gm2mmi.bdt')
1158 self.data_date_filename = os.path.join(paths.home_dir, '.wine', 'drive_c', 'Programme', 'MMI PHARMINDEX', 'datadate.txt')
1159 #============================================================
1161 """empirical CSV interface"""
1162
1165
1167
1168 try:
1169 csv_file = open(filename, 'rb') # FIXME: encoding ?
1170 except:
1171 _log.exception('cannot access [%s]', filename)
1172 csv_file = None
1173
1174 field_names = u'PZN Handelsname Form Abpackungsmenge Einheit Preis1 Hersteller Preis2 rezeptpflichtig Festbetrag Packungszahl Packungsgr\xf6\xdfe'.split()
1175
1176 if csv_file is None:
1177 return False
1178
1179 csv_lines = csv.DictReader (
1180 csv_file,
1181 fieldnames = field_names,
1182 delimiter = ';'
1183 )
1184
1185 for line in csv_lines:
1186 print "--------------------------------------------------------------------"[:31]
1187 for key in field_names:
1188 tmp = ('%s ' % key)[:30]
1189 print '%s: %s' % (tmp, line[key])
1190
1191 csv_file.close()
1192
1193 # narr = u'%sx %s %s %s (\u2258 %s %s) von %s (%s)' % (
1194 # line['Packungszahl'].strip(),
1195 # line['Handelsname'].strip(),
1196 # line['Form'].strip(),
1197 # line[u'Packungsgr\xf6\xdfe'].strip(),
1198 # line['Abpackungsmenge'].strip(),
1199 # line['Einheit'].strip(),
1200 # line['Hersteller'].strip(),
1201 # line['PZN'].strip()
1202 # )
1203 #============================================================
1204 drug_data_source_interfaces = {
1205 'Deutschland: Gelbe Liste/MMI (Windows)': cGelbeListeWindowsInterface,
1206 'Deutschland: Gelbe Liste/MMI (WINE)': cGelbeListeWineInterface,
1207 'FreeDiams (FR, US, CA, ZA)': cFreeDiamsInterface
1208 }
1209
1210 #============================================================
1211 #============================================================
1212 # substances in use across all patients
1213 #------------------------------------------------------------
1214 _SQL_get_consumable_substance = u"""
1215 SELECT *, xmin
1216 FROM ref.consumable_substance
1217 WHERE %s
1218 """
1219
1221
1222 _cmd_fetch_payload = _SQL_get_consumable_substance % u"pk = %s"
1223 _cmds_store_payload = [
1224 u"""UPDATE ref.consumable_substance SET
1225 description = %(description)s,
1226 atc_code = gm.nullify_empty_string(%(atc_code)s),
1227 amount = %(amount)s,
1228 unit = gm.nullify_empty_string(%(unit)s)
1229 WHERE
1230 pk = %(pk)s
1231 AND
1232 xmin = %(xmin)s
1233 AND
1234 -- must not currently be used with a patient directly
1235 NOT EXISTS (
1236 SELECT 1
1237 FROM clin.substance_intake
1238 WHERE
1239 fk_drug_component IS NULL
1240 AND
1241 fk_substance = %(pk)s
1242 LIMIT 1
1243 )
1244 AND
1245 -- must not currently be used with a patient indirectly, either
1246 NOT EXISTS (
1247 SELECT 1
1248 FROM clin.substance_intake
1249 WHERE
1250 fk_drug_component IS NOT NULL
1251 AND
1252 fk_drug_component = (
1253 SELECT r_ls2b.pk
1254 FROM ref.lnk_substance2brand r_ls2b
1255 WHERE fk_substance = %(pk)s
1256 )
1257 LIMIT 1
1258 )
1259 -- -- must not currently be used with a branded drug
1260 -- -- (but this would make it rather hard fixing branded drugs which contain only this substance)
1261 -- NOT EXISTS (
1262 -- SELECT 1
1263 -- FROM ref.lnk_substance2brand
1264 -- WHERE fk_substance = %(pk)s
1265 -- LIMIT 1
1266 -- )
1267 RETURNING
1268 xmin
1269 """
1270 ]
1271 _updatable_fields = [
1272 u'description',
1273 u'atc_code',
1274 u'amount',
1275 u'unit'
1276 ]
1277 #--------------------------------------------------------
1279 success, data = super(self.__class__, self).save_payload(conn = conn)
1280
1281 if not success:
1282 return (success, data)
1283
1284 if self._payload[self._idx['atc_code']] is not None:
1285 atc = self._payload[self._idx['atc_code']].strip()
1286 if atc != u'':
1287 gmATC.propagate_atc (
1288 substance = self._payload[self._idx['description']].strip(),
1289 atc = atc
1290 )
1291
1292 return (success, data)
1293 #--------------------------------------------------------
1294 # properties
1295 #--------------------------------------------------------
1297 cmd = u"""
1298 SELECT
1299 EXISTS (
1300 SELECT 1
1301 FROM clin.substance_intake
1302 WHERE
1303 fk_drug_component IS NULL
1304 AND
1305 fk_substance = %(pk)s
1306 LIMIT 1
1307 ) OR EXISTS (
1308 SELECT 1
1309 FROM clin.substance_intake
1310 WHERE
1311 fk_drug_component IS NOT NULL
1312 AND
1313 fk_drug_component IN (
1314 SELECT r_ls2b.pk
1315 FROM ref.lnk_substance2brand r_ls2b
1316 WHERE fk_substance = %(pk)s
1317 )
1318 LIMIT 1
1319 )"""
1320 args = {'pk': self.pk_obj}
1321
1322 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
1323 return rows[0][0]
1324
1325 is_in_use_by_patients = property(_get_is_in_use_by_patients, lambda x:x)
1326 #--------------------------------------------------------
1328 cmd = u"""
1329 SELECT EXISTS (
1330 SELECT 1
1331 FROM ref.lnk_substance2brand
1332 WHERE fk_substance = %(pk)s
1333 LIMIT 1
1334 )"""
1335 args = {'pk': self.pk_obj}
1336
1337 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
1338 return rows[0][0]
1339
1340 is_drug_component = property(_get_is_drug_component, lambda x:x)
1341 #------------------------------------------------------------
1343 if order_by is None:
1344 order_by = u'true'
1345 else:
1346 order_by = u'true ORDER BY %s' % order_by
1347 cmd = _SQL_get_consumable_substance % order_by
1348 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = True)
1349 return [ cConsumableSubstance(row = {'data': r, 'idx': idx, 'pk_field': 'pk'}) for r in rows ]
1350 #------------------------------------------------------------
1352
1353 substance = substance
1354 if atc is not None:
1355 atc = atc.strip()
1356
1357 converted, amount = gmTools.input2decimal(amount)
1358 if not converted:
1359 raise ValueError('<amount> must be a number: %s (%s)', amount, type(amount))
1360
1361 args = {
1362 'desc': substance.strip(),
1363 'amount': amount,
1364 'unit': unit.strip(),
1365 'atc': atc
1366 }
1367 cmd = u"""
1368 SELECT pk FROM ref.consumable_substance
1369 WHERE
1370 lower(description) = lower(%(desc)s)
1371 AND
1372 amount = %(amount)s
1373 AND
1374 unit = %(unit)s
1375 """
1376 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}])
1377
1378 if len(rows) == 0:
1379 cmd = u"""
1380 INSERT INTO ref.consumable_substance (description, atc_code, amount, unit) VALUES (
1381 %(desc)s,
1382 gm.nullify_empty_string(%(atc)s),
1383 %(amount)s,
1384 gm.nullify_empty_string(%(unit)s)
1385 ) RETURNING pk"""
1386 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True, get_col_idx = False)
1387
1388 gmATC.propagate_atc(substance = substance, atc = atc)
1389
1390 return cConsumableSubstance(aPK_obj = rows[0]['pk'])
1391 #------------------------------------------------------------
1393 args = {'pk': substance}
1394 cmd = u"""
1395 DELETE FROM ref.consumable_substance
1396 WHERE
1397 pk = %(pk)s
1398 AND
1399
1400 -- must not currently be used with a patient
1401 NOT EXISTS (
1402 SELECT 1
1403 FROM clin.v_pat_substance_intake
1404 WHERE pk_substance = %(pk)s
1405 LIMIT 1
1406 )
1407 AND
1408
1409 -- must not currently be used with a branded drug
1410 NOT EXISTS (
1411 SELECT 1
1412 FROM ref.lnk_substance2brand
1413 WHERE fk_substance = %(pk)s
1414 LIMIT 1
1415 )"""
1416 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
1417 return True
1418 #------------------------------------------------------------
1420
1421 _pattern = regex.compile(r'^\D+\s*\d+$', regex.UNICODE | regex.LOCALE)
1422 _query1 = u"""
1423 SELECT
1424 pk::text,
1425 (description || ' ' || amount || ' ' || unit) as subst
1426 FROM ref.consumable_substance
1427 WHERE description %(fragment_condition)s
1428 ORDER BY subst
1429 LIMIT 50"""
1430 _query2 = u"""
1431 SELECT
1432 pk::text,
1433 (description || ' ' || amount || ' ' || unit) as subst
1434 FROM ref.consumable_substance
1435 WHERE
1436 %(fragment_condition)s
1437 ORDER BY subst
1438 LIMIT 50"""
1439
1440 #--------------------------------------------------------
1442 """Return matches for aFragment at start of phrases."""
1443
1444 if cSubstanceMatchProvider._pattern.match(aFragment):
1445 self._queries = [cSubstanceMatchProvider._query2]
1446 fragment_condition = """description ILIKE %(desc)s
1447 AND
1448 amount::text ILIKE %(amount)s"""
1449 self._args['desc'] = u'%s%%' % regex.sub(r'\s*\d+$', u'', aFragment)
1450 self._args['amount'] = u'%s%%' % regex.sub(r'^\D+\s*', u'', aFragment)
1451 else:
1452 self._queries = [cSubstanceMatchProvider._query1]
1453 fragment_condition = u"ILIKE %(fragment)s"
1454 self._args['fragment'] = u"%s%%" % aFragment
1455
1456 return self._find_matches(fragment_condition)
1457 #--------------------------------------------------------
1459 """Return matches for aFragment at start of words inside phrases."""
1460
1461 if cSubstanceMatchProvider._pattern.match(aFragment):
1462 self._queries = [cSubstanceMatchProvider._query2]
1463
1464 desc = regex.sub(r'\s*\d+$', u'', aFragment)
1465 desc = gmPG2.sanitize_pg_regex(expression = desc, escape_all = False)
1466
1467 fragment_condition = """description ~* %(desc)s
1468 AND
1469 amount::text ILIKE %(amount)s"""
1470
1471 self._args['desc'] = u"( %s)|(^%s)" % (desc, desc)
1472 self._args['amount'] = u'%s%%' % regex.sub(r'^\D+\s*', u'', aFragment)
1473 else:
1474 self._queries = [cSubstanceMatchProvider._query1]
1475 fragment_condition = u"~* %(fragment)s"
1476 aFragment = gmPG2.sanitize_pg_regex(expression = aFragment, escape_all = False)
1477 self._args['fragment'] = u"( %s)|(^%s)" % (aFragment, aFragment)
1478
1479 return self._find_matches(fragment_condition)
1480 #--------------------------------------------------------
1482 """Return matches for aFragment as a true substring."""
1483
1484 if cSubstanceMatchProvider._pattern.match(aFragment):
1485 self._queries = [cSubstanceMatchProvider._query2]
1486 fragment_condition = """description ILIKE %(desc)s
1487 AND
1488 amount::text ILIKE %(amount)s"""
1489 self._args['desc'] = u'%%%s%%' % regex.sub(r'\s*\d+$', u'', aFragment)
1490 self._args['amount'] = u'%s%%' % regex.sub(r'^\D+\s*', u'', aFragment)
1491 else:
1492 self._queries = [cSubstanceMatchProvider._query1]
1493 fragment_condition = u"ILIKE %(fragment)s"
1494 self._args['fragment'] = u"%%%s%%" % aFragment
1495
1496 return self._find_matches(fragment_condition)
1497 #============================================================
1499 """Represents a substance currently taken by a patient."""
1500
1501 _cmd_fetch_payload = u"SELECT * FROM clin.v_pat_substance_intake WHERE pk_substance_intake = %s"
1502 _cmds_store_payload = [
1503 u"""UPDATE clin.substance_intake SET
1504 clin_when = %(started)s,
1505 discontinued = %(discontinued)s,
1506 discontinue_reason = gm.nullify_empty_string(%(discontinue_reason)s),
1507 schedule = gm.nullify_empty_string(%(schedule)s),
1508 aim = gm.nullify_empty_string(%(aim)s),
1509 narrative = gm.nullify_empty_string(%(notes)s),
1510 intake_is_approved_of = %(intake_is_approved_of)s,
1511 fk_episode = %(pk_episode)s,
1512
1513 preparation = (
1514 case
1515 when %(pk_brand)s is NULL then %(preparation)s
1516 else NULL
1517 end
1518 )::text,
1519
1520 is_long_term = (
1521 case
1522 when (
1523 (%(is_long_term)s is False)
1524 and
1525 (%(duration)s is NULL)
1526 ) is True then null
1527 else %(is_long_term)s
1528 end
1529 )::boolean,
1530
1531 duration = (
1532 case
1533 when %(is_long_term)s is True then null
1534 else %(duration)s
1535 end
1536 )::interval
1537 WHERE
1538 pk = %(pk_substance_intake)s
1539 AND
1540 xmin = %(xmin_substance_intake)s
1541 RETURNING
1542 xmin as xmin_substance_intake
1543 """
1544 ]
1545 _updatable_fields = [
1546 u'started',
1547 u'discontinued',
1548 u'discontinue_reason',
1549 u'preparation',
1550 u'intake_is_approved_of',
1551 u'schedule',
1552 u'duration',
1553 u'aim',
1554 u'is_long_term',
1555 u'notes',
1556 u'pk_episode'
1557 ]
1558 #--------------------------------------------------------
1560
1561 if self._payload[self._idx['duration']] is None:
1562 duration = gmTools.bool2subst (
1563 self._payload[self._idx['is_long_term']],
1564 _('long-term'),
1565 _('short-term'),
1566 _('?short-term')
1567 )
1568 else:
1569 duration = gmDateTime.format_interval (
1570 self._payload[self._idx['duration']],
1571 accuracy_wanted = gmDateTime.acc_days
1572 )
1573
1574 line = u'%s%s (%s %s): %s %s%s %s (%s)' % (
1575 u' ' * left_margin,
1576 self._payload[self._idx['started']].strftime(date_format),
1577 gmTools.u_right_arrow,
1578 duration,
1579 self._payload[self._idx['substance']],
1580 self._payload[self._idx['amount']],
1581 self._payload[self._idx['unit']],
1582 self._payload[self._idx['preparation']],
1583 gmTools.bool2subst(self._payload[self._idx['is_currently_active']], _('ongoing'), _('inactive'), _('?ongoing'))
1584 )
1585
1586 return line
1587 #--------------------------------------------------------
1589 allg = gmAllergy.create_allergy (
1590 allergene = self._payload[self._idx['substance']],
1591 allg_type = allergy_type,
1592 episode_id = self._payload[self._idx['pk_episode']],
1593 encounter_id = encounter_id
1594 )
1595 allg['substance'] = gmTools.coalesce (
1596 self._payload[self._idx['brand']],
1597 self._payload[self._idx['substance']]
1598 )
1599 allg['reaction'] = self._payload[self._idx['discontinue_reason']]
1600 allg['atc_code'] = gmTools.coalesce(self._payload[self._idx['atc_substance']], self._payload[self._idx['atc_brand']])
1601 if self._payload[self._idx['external_code_brand']] is not None:
1602 allg['substance_code'] = u'%s::::%s' % (self._payload[self._idx['external_code_type_brand']], self._payload[self._idx['external_code_brand']])
1603
1604 if self._payload[self._idx['pk_brand']] is None:
1605 allg['generics'] = self._payload[self._idx['substance']]
1606 else:
1607 comps = [ c['substance'] for c in self.containing_drug.components ]
1608 if len(comps) == 0:
1609 allg['generics'] = self._payload[self._idx['substance']]
1610 else:
1611 allg['generics'] = u'; '.join(comps)
1612
1613 allg.save()
1614 return allg
1615 #--------------------------------------------------------
1616 # properties
1617 #--------------------------------------------------------
1619
1620 try: self.__ddd
1621 except AttributeError: self.__ddd = None
1622
1623 if self.__ddd is not None:
1624 return self.__ddd
1625
1626 if self._payload[self._idx['atc_substance']] is not None:
1627 ddd = gmATC.atc2ddd(atc = self._payload[self._idx['atc_substance']])
1628 if len(ddd) != 0:
1629 self.__ddd = ddd[0]
1630 else:
1631 if self._payload[self._idx['atc_brand']] is not None:
1632 ddd = gmATC.atc2ddd(atc = self._payload[self._idx['atc_brand']])
1633 if len(ddd) != 0:
1634 self.__ddd = ddd[0]
1635
1636 return self.__ddd
1637
1638 ddd = property(_get_ddd, lambda x:x)
1639 #--------------------------------------------------------
1641 drug = self.containing_drug
1642
1643 if drug is None:
1644 return None
1645
1646 return drug.external_code
1647
1648 external_code = property(_get_external_code, lambda x:x)
1649 #--------------------------------------------------------
1651 drug = self.containing_drug
1652
1653 if drug is None:
1654 return None
1655
1656 return drug.external_code_type
1657
1658 external_code_type = property(_get_external_code_type, lambda x:x)
1659 #--------------------------------------------------------
1661 if self._payload[self._idx['pk_brand']] is None:
1662 return None
1663
1664 return cBrandedDrug(aPK_obj = self._payload[self._idx['pk_brand']])
1665
1666 containing_drug = property(_get_containing_drug, lambda x:x)
1667 #--------------------------------------------------------
1669 tests = [
1670 # lead, trail
1671 ' 1-1-1-1 ',
1672 # leading dose
1673 '1-1-1-1',
1674 '22-1-1-1',
1675 '1/3-1-1-1',
1676 '/4-1-1-1'
1677 ]
1678 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}$"
1679 for test in tests:
1680 print test.strip(), ":", regex.match(pattern, test.strip())
1681 #------------------------------------------------------------
1683 args = {'comp': pk_component, 'pat': pk_identity}
1684 cmd = u"""
1685 SELECT exists (
1686 SELECT 1 FROM clin.substance_intake
1687 WHERE
1688 fk_drug_component = %(comp)s
1689 AND
1690 fk_encounter IN (
1691 SELECT pk FROM clin.encounter WHERE fk_patient = %(pat)s
1692 )
1693 LIMIT 1
1694 )"""
1695 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}])
1696 return rows[0][0]
1697 #------------------------------------------------------------
1698 -def create_substance_intake(pk_substance=None, pk_component=None, preparation=None, encounter=None, episode=None):
1699
1700 args = {
1701 'enc': encounter,
1702 'epi': episode,
1703 'comp': pk_component,
1704 'subst': pk_substance,
1705 'prep': preparation
1706 }
1707
1708 if pk_component is None:
1709 cmd = u"""
1710 INSERT INTO clin.substance_intake (
1711 fk_encounter,
1712 fk_episode,
1713 intake_is_approved_of,
1714 fk_substance,
1715 preparation
1716 ) VALUES (
1717 %(enc)s,
1718 %(epi)s,
1719 False,
1720 %(subst)s,
1721 %(prep)s
1722 )
1723 RETURNING pk"""
1724 else:
1725 cmd = u"""
1726 INSERT INTO clin.substance_intake (
1727 fk_encounter,
1728 fk_episode,
1729 intake_is_approved_of,
1730 fk_drug_component
1731 ) VALUES (
1732 %(enc)s,
1733 %(epi)s,
1734 False,
1735 %(comp)s
1736 )
1737 RETURNING pk"""
1738
1739 try:
1740 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True)
1741 except gmPG2.dbapi.InternalError, e:
1742 if e.pgerror is None:
1743 raise
1744 if 'prevent_duplicate_component' in e.pgerror:
1745 _log.exception('will not create duplicate substance intake entry')
1746 _log.error(e.pgerror)
1747 return None
1748 raise
1749
1750 return cSubstanceIntakeEntry(aPK_obj = rows[0][0])
1751 #------------------------------------------------------------
1753 cmd = u'delete from clin.substance_intake where pk = %(pk)s'
1754 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': {'pk': substance}}])
1755 #------------------------------------------------------------
1757
1758 tex = u'\n{\\small\n'
1759 tex += u'\\noindent %s\n' % _('Additional notes')
1760 tex += u'\n'
1761 tex += u'\\noindent \\begin{tabularx}{\\textwidth}{|X|l|X|p{7.5cm}|}\n'
1762 tex += u'\\hline\n'
1763 tex += u'%s {\\scriptsize (%s)} & %s & %s \\\\ \n' % (_('Substance'), _('Brand'), _('Strength'), _('Advice'))
1764 tex += u'\\hline\n'
1765 tex += u'%s\n'
1766 tex += u'\n'
1767 tex += u'\\end{tabularx}\n'
1768 tex += u'}\n'
1769
1770 current_meds = emr.get_current_substance_intake (
1771 include_inactive = False,
1772 include_unapproved = False,
1773 order_by = u'brand, substance'
1774 )
1775
1776 # create lines
1777 lines = []
1778 for med in current_meds:
1779 lines.append(u'%s%s %s & %s%s & %s \\\\ \n \\hline \n' % (
1780 med['substance'],
1781 gmTools.coalesce(med['brand'], u'', u' {\\scriptsize (%s)}'),
1782 med['preparation'],
1783 med['amount'],
1784 med['unit'],
1785 gmTools.coalesce(med['notes'], u'', u'{\\scriptsize %s}')
1786 ))
1787
1788 return tex % u' \n'.join(lines)
1789
1790 #------------------------------------------------------------
1792
1793 tex = u'\\noindent %s {\\tiny (%s)\\par}\n' % (_('Medication list'), _('ordered by brand'))
1794 tex += u'\n'
1795 tex += u'\\noindent \\begin{tabular}{|l|l|}\n'
1796 tex += u'\\hline\n'
1797 tex += u'%s & %s \\\\ \n' % (_('Drug'), _('Regimen'))
1798 tex += u'\\hline\n'
1799 tex += u'\n'
1800 tex += u'\\hline\n'
1801 tex += u'%s\n'
1802 tex += u'\n'
1803 tex += u'\\end{tabular}\n'
1804
1805 current_meds = emr.get_current_substance_intake (
1806 include_inactive = False,
1807 include_unapproved = False,
1808 order_by = u'brand, substance'
1809 )
1810
1811 # aggregate data
1812 line_data = {}
1813 for med in current_meds:
1814 identifier = gmTools.coalesce(med['brand'], med['substance'])
1815
1816 try:
1817 line_data[identifier]
1818 except KeyError:
1819 line_data[identifier] = {'brand': u'', 'preparation': u'', 'schedule': u'', 'aims': [], 'strengths': []}
1820
1821 line_data[identifier]['brand'] = identifier
1822 line_data[identifier]['strengths'].append(u'%s%s' % (med['amount'], med['unit'].strip()))
1823 line_data[identifier]['preparation'] = med['preparation']
1824 line_data[identifier]['schedule'] = gmTools.coalesce(med['schedule'], u'')
1825 if med['aim'] not in line_data[identifier]['aims']:
1826 line_data[identifier]['aims'].append(med['aim'])
1827
1828 # create lines
1829 already_seen = []
1830 lines = []
1831 line1_template = u'%s %s & %s \\\\'
1832 line2_template = u' & {\\scriptsize %s\\par} \\\\'
1833
1834 for med in current_meds:
1835 identifier = gmTools.coalesce(med['brand'], med['substance'])
1836
1837 if identifier in already_seen:
1838 continue
1839
1840 already_seen.append(identifier)
1841
1842 lines.append (line1_template % (
1843 line_data[identifier]['brand'],
1844 line_data[identifier]['preparation'],
1845 line_data[identifier]['schedule']
1846 ))
1847
1848 strengths = u'/'.join(line_data[identifier]['strengths'])
1849 if strengths == u'':
1850 template = u' & {\\scriptsize %s\\par} \\\\'
1851 for aim in line_data[identifier]['aims']:
1852 lines.append(template % aim)
1853 else:
1854 if len(line_data[identifier]['aims']) == 0:
1855 template = u'%s & \\\\'
1856 lines.append(template % strengths)
1857 else:
1858 template = u'%s & {\\scriptsize %s\\par} \\\\'
1859 lines.append(template % (strengths, line_data[identifier]['aims'][0]))
1860 template = u' & {\\scriptsize %s\\par} \\\\'
1861 for aim in line_data[identifier]['aims'][1:]:
1862 lines.append(template % aim)
1863
1864 lines.append(u'\\hline')
1865
1866 return tex % u' \n'.join(lines)
1867 #============================================================
1868 _SQL_get_drug_components = u'SELECT * FROM ref.v_drug_components WHERE %s'
1869
1871
1872 _cmd_fetch_payload = _SQL_get_drug_components % u'pk_component = %s'
1873 _cmds_store_payload = [
1874 u"""UPDATE ref.lnk_substance2brand SET
1875 fk_brand = %(pk_brand)s,
1876 fk_substance = %(pk_consumable_substance)s
1877 WHERE
1878 NOT EXISTS (
1879 SELECT 1
1880 FROM clin.substance_intake
1881 WHERE fk_drug_component = %(pk_component)s
1882 LIMIT 1
1883 )
1884 AND
1885 pk = %(pk_component)s
1886 AND
1887 xmin = %(xmin_lnk_substance2brand)s
1888 RETURNING
1889 xmin AS xmin_lnk_substance2brand
1890 """
1891 ]
1892 _updatable_fields = [
1893 u'pk_brand',
1894 u'pk_consumable_substance'
1895 ]
1896 #--------------------------------------------------------
1897 # properties
1898 #--------------------------------------------------------
1900 return cBrandedDrug(aPK_obj = self._payload[self._idx['pk_brand']])
1901
1902 containing_drug = property(_get_containing_drug, lambda x:x)
1903 #--------------------------------------------------------
1906
1907 is_in_use_by_patients = property(_get_is_in_use_by_patients, lambda x:x)
1908 #--------------------------------------------------------
1910 return cConsumableSubstance(aPK_obj = self._payload[self._idx['pk_consumable_substance']])
1911
1912 substance = property(_get_substance, lambda x:x)
1913 #------------------------------------------------------------
1915 cmd = _SQL_get_drug_components % u'true ORDER BY brand, substance'
1916 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = True)
1917 return [ cDrugComponent(row = {'data': r, 'idx': idx, 'pk_field': 'pk_component'}) for r in rows ]
1918 #------------------------------------------------------------
1920
1921 _pattern = regex.compile(r'^\D+\s*\d+$', regex.UNICODE | regex.LOCALE)
1922 _query_desc_only = u"""
1923 SELECT DISTINCT ON (component)
1924 pk_component,
1925 (substance || ' ' || amount || unit || ' ' || preparation || ' (' || brand || ')')
1926 AS component
1927 FROM ref.v_drug_components
1928 WHERE
1929 substance %(fragment_condition)s
1930 OR
1931 brand %(fragment_condition)s
1932 ORDER BY component
1933 LIMIT 50"""
1934 _query_desc_and_amount = u"""
1935
1936 SELECT DISTINCT ON (component)
1937 pk_component,
1938 (substance || ' ' || amount || unit || ' ' || preparation || ' (' || brand || ')')
1939 AS component
1940 FROM ref.v_drug_components
1941 WHERE
1942 %(fragment_condition)s
1943 ORDER BY component
1944 LIMIT 50"""
1945 #--------------------------------------------------------
1947 """Return matches for aFragment at start of phrases."""
1948
1949 if cDrugComponentMatchProvider._pattern.match(aFragment):
1950 self._queries = [cDrugComponentMatchProvider._query_desc_and_amount]
1951 fragment_condition = """(substance ILIKE %(desc)s OR brand ILIKE %(desc)s)
1952 AND
1953 amount::text ILIKE %(amount)s"""
1954 self._args['desc'] = u'%s%%' % regex.sub(r'\s*\d+$', u'', aFragment)
1955 self._args['amount'] = u'%s%%' % regex.sub(r'^\D+\s*', u'', aFragment)
1956 else:
1957 self._queries = [cDrugComponentMatchProvider._query_desc_only]
1958 fragment_condition = u"ILIKE %(fragment)s"
1959 self._args['fragment'] = u"%s%%" % aFragment
1960
1961 return self._find_matches(fragment_condition)
1962 #--------------------------------------------------------
1964 """Return matches for aFragment at start of words inside phrases."""
1965
1966 if cDrugComponentMatchProvider._pattern.match(aFragment):
1967 self._queries = [cDrugComponentMatchProvider._query_desc_and_amount]
1968
1969 desc = regex.sub(r'\s*\d+$', u'', aFragment)
1970 desc = gmPG2.sanitize_pg_regex(expression = desc, escape_all = False)
1971
1972 fragment_condition = """(substance ~* %(desc)s OR brand ~* %(desc)s)
1973 AND
1974 amount::text ILIKE %(amount)s"""
1975
1976 self._args['desc'] = u"( %s)|(^%s)" % (desc, desc)
1977 self._args['amount'] = u'%s%%' % regex.sub(r'^\D+\s*', u'', aFragment)
1978 else:
1979 self._queries = [cDrugComponentMatchProvider._query_desc_only]
1980 fragment_condition = u"~* %(fragment)s"
1981 aFragment = gmPG2.sanitize_pg_regex(expression = aFragment, escape_all = False)
1982 self._args['fragment'] = u"( %s)|(^%s)" % (aFragment, aFragment)
1983
1984 return self._find_matches(fragment_condition)
1985 #--------------------------------------------------------
1987 """Return matches for aFragment as a true substring."""
1988
1989 if cDrugComponentMatchProvider._pattern.match(aFragment):
1990 self._queries = [cDrugComponentMatchProvider._query_desc_and_amount]
1991 fragment_condition = """(substance ILIKE %(desc)s OR brand ILIKE %(desc)s)
1992 AND
1993 amount::text ILIKE %(amount)s"""
1994 self._args['desc'] = u'%%%s%%' % regex.sub(r'\s*\d+$', u'', aFragment)
1995 self._args['amount'] = u'%s%%' % regex.sub(r'^\D+\s*', u'', aFragment)
1996 else:
1997 self._queries = [cDrugComponentMatchProvider._query_desc_only]
1998 fragment_condition = u"ILIKE %(fragment)s"
1999 self._args['fragment'] = u"%%%s%%" % aFragment
2000
2001 return self._find_matches(fragment_condition)
2002
2003 #============================================================
2005 """Represents a drug as marketed by a manufacturer."""
2006
2007 _cmd_fetch_payload = u"SELECT * FROM ref.v_branded_drugs WHERE pk_brand = %s"
2008 _cmds_store_payload = [
2009 u"""UPDATE ref.branded_drug SET
2010 description = %(brand)s,
2011 preparation = %(preparation)s,
2012 atc_code = gm.nullify_empty_string(%(atc)s),
2013 external_code = gm.nullify_empty_string(%(external_code)s),
2014 external_code_type = gm.nullify_empty_string(%(external_code_type)s),
2015 is_fake = %(is_fake_brand)s,
2016 fk_data_source = %(pk_data_source)s
2017 WHERE
2018 pk = %(pk_brand)s
2019 AND
2020 xmin = %(xmin_branded_drug)s
2021 RETURNING
2022 xmin AS xmin_branded_drug
2023 """
2024 ]
2025 _updatable_fields = [
2026 u'brand',
2027 u'preparation',
2028 u'atc',
2029 u'is_fake_brand',
2030 u'external_code',
2031 u'external_code_type',
2032 u'pk_data_source'
2033 ]
2034 #--------------------------------------------------------
2036 success, data = super(self.__class__, self).save_payload(conn = conn)
2037
2038 if not success:
2039 return (success, data)
2040
2041 if self._payload[self._idx['atc']] is not None:
2042 atc = self._payload[self._idx['atc']].strip()
2043 if atc != u'':
2044 gmATC.propagate_atc (
2045 substance = self._payload[self._idx['brand']].strip(),
2046 atc = atc
2047 )
2048
2049 return (success, data)
2050 #--------------------------------------------------------
2052
2053 if self.is_in_use_by_patients:
2054 return False
2055
2056 args = {'brand': self._payload[self._idx['pk_brand']]}
2057
2058 queries = [{'cmd': u"DELETE FROM ref.lnk_substance2brand WHERE fk_brand = %(brand)s", 'args': args}]
2059 cmd = u'INSERT INTO ref.lnk_substance2brand (fk_brand, fk_substance) VALUES (%%(brand)s, %s)'
2060 for s in substances:
2061 queries.append({'cmd': cmd % s['pk'], 'args': args})
2062
2063 gmPG2.run_rw_queries(queries = queries)
2064 self.refetch_payload()
2065
2066 return True
2067 #--------------------------------------------------------
2068 - def add_component(self, substance=None, atc=None, amount=None, unit=None, pk_substance=None):
2069
2070 args = {
2071 'brand': self.pk_obj,
2072 'subst': substance,
2073 'atc': atc,
2074 'pk_subst': pk_substance
2075 }
2076
2077 if pk_substance is None:
2078 consumable = create_consumable_substance(substance = substance, atc = atc, amount = amount, unit = unit)
2079 args['pk_subst'] = consumable['pk']
2080
2081 # already a component
2082 cmd = u"""
2083 SELECT pk_component
2084 FROM ref.v_drug_components
2085 WHERE
2086 pk_brand = %(brand)s
2087 AND
2088 ((
2089 (lower(substance) = lower(%(subst)s))
2090 OR
2091 (lower(atc_substance) = lower(%(atc)s))
2092 OR
2093 (pk_consumable_substance = %(pk_subst)s)
2094 ) IS TRUE)
2095 """
2096 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
2097
2098 if len(rows) > 0:
2099 return
2100
2101 # create it
2102 cmd = u"""
2103 INSERT INTO ref.lnk_substance2brand (fk_brand, fk_substance)
2104 VALUES (%(brand)s, %(pk_subst)s)
2105 """
2106 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
2107 self.refetch_payload()
2108 #------------------------------------------------------------
2110 if len(self._payload[self._idx['components']]) == 1:
2111 _log.error('cannot remove the only component of a drug')
2112 return False
2113
2114 args = {'brand': self.pk_obj, 'comp': substance}
2115 cmd = u"""
2116 DELETE FROM ref.lnk_substance2brand
2117 WHERE
2118 fk_brand = %(brand)s
2119 AND
2120 fk_substance = %(comp)s
2121 AND
2122 NOT EXISTS (
2123 SELECT 1
2124 FROM clin.substance_intake
2125 WHERE fk_drug_component = %(comp)s
2126 LIMIT 1
2127 )
2128 """
2129 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
2130 self.refetch_payload()
2131
2132 return True
2133 #--------------------------------------------------------
2134 # properties
2135 #--------------------------------------------------------
2137 if self._payload[self._idx['external_code']] is None:
2138 return None
2139
2140 return self._payload[self._idx['external_code']]
2141
2142 external_code = property(_get_external_code, lambda x:x)
2143 #--------------------------------------------------------
2145
2146 # FIXME: maybe evaluate fk_data_source ?
2147 if self._payload[self._idx['external_code_type']] is None:
2148 return None
2149
2150 return self._payload[self._idx['external_code_type']]
2151
2152 external_code_type = property(_get_external_code_type, lambda x:x)
2153 #--------------------------------------------------------
2155 cmd = _SQL_get_drug_components % u'pk_brand = %(brand)s'
2156 args = {'brand': self._payload[self._idx['pk_brand']]}
2157 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
2158 return [ cDrugComponent(row = {'data': r, 'idx': idx, 'pk_field': 'pk_component'}) for r in rows ]
2159
2160 components = property(_get_components, lambda x:x)
2161 #--------------------------------------------------------
2163 if self._payload[self._idx['pk_substances']] is None:
2164 return []
2165 cmd = _SQL_get_consumable_substance % u'pk IN %(pks)s'
2166 args = {'pks': tuple(self._payload[self._idx['pk_substances']])}
2167 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
2168 return [ cConsumableSubstance(row = {'data': r, 'idx': idx, 'pk_field': 'pk'}) for r in rows ]
2169
2170 components_as_substances = property(_get_components_as_substances, lambda x:x)
2171 #--------------------------------------------------------
2173 cmd = u'SELECT EXISTS (SELECT 1 FROM clin.vaccine WHERE fk_brand = %(fk_brand)s)'
2174 args = {'fk_brand': self._payload[self._idx['pk_brand']]}
2175 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
2176 return rows[0][0]
2177
2178 is_vaccine = property(_get_is_vaccine, lambda x:x)
2179 #--------------------------------------------------------
2181 cmd = u"""
2182 SELECT EXISTS (
2183 SELECT 1
2184 FROM clin.substance_intake
2185 WHERE
2186 fk_drug_component IS NOT NULL
2187 AND
2188 fk_drug_component IN (
2189 SELECT r_ls2b.pk
2190 FROM ref.lnk_substance2brand r_ls2b
2191 WHERE fk_brand = %(pk)s
2192 )
2193 LIMIT 1
2194 )"""
2195 args = {'pk': self.pk_obj}
2196
2197 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
2198 return rows[0][0]
2199
2200 is_in_use_by_patients = property(_get_is_in_use_by_patients, lambda x:x)
2201 #------------------------------------------------------------
2203 cmd = u'SELECT pk FROM ref.branded_drug ORDER BY description'
2204 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = False)
2205 return [ cBrandedDrug(aPK_obj = r['pk']) for r in rows ]
2206 #------------------------------------------------------------
2208 args = {'brand': brand_name, 'prep': preparation}
2209
2210 cmd = u'SELECT pk FROM ref.branded_drug WHERE lower(description) = lower(%(brand)s) AND lower(preparation) = lower(%(prep)s)'
2211 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
2212
2213 if len(rows) == 0:
2214 return None
2215
2216 return cBrandedDrug(aPK_obj = rows[0]['pk'])
2217 #------------------------------------------------------------
2219
2220 if preparation is None:
2221 preparation = _('units')
2222
2223 if preparation.strip() == u'':
2224 preparation = _('units')
2225
2226 if return_existing:
2227 drug = get_drug_by_brand(brand_name = brand_name, preparation = preparation)
2228 if drug is not None:
2229 return drug
2230
2231 cmd = u'INSERT INTO ref.branded_drug (description, preparation) VALUES (%(brand)s, %(prep)s) RETURNING pk'
2232 args = {'brand': brand_name, 'prep': preparation}
2233 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True, get_col_idx = False)
2234
2235 return cBrandedDrug(aPK_obj = rows[0]['pk'])
2236 #------------------------------------------------------------
2238 queries = []
2239 args = {'pk': brand}
2240
2241 # delete components
2242 cmd = u"""
2243 DELETE FROM ref.lnk_substance2brand
2244 WHERE
2245 fk_brand = %(pk)s
2246 AND
2247 NOT EXISTS (
2248 SELECT 1
2249 FROM clin.v_pat_substance_intake
2250 WHERE pk_brand = %(pk)s
2251 LIMIT 1
2252 )
2253 """
2254 queries.append({'cmd': cmd, 'args': args})
2255
2256 # delete drug
2257 cmd = u"""
2258 DELETE FROM ref.branded_drug
2259 WHERE
2260 pk = %(pk)s
2261 AND
2262 NOT EXISTS (
2263 SELECT 1
2264 FROM clin.v_pat_substance_intake
2265 WHERE pk_brand = %(pk)s
2266 LIMIT 1
2267 )
2268 """
2269 queries.append({'cmd': cmd, 'args': args})
2270
2271 gmPG2.run_rw_queries(queries = queries)
2272 #============================================================
2273 # main
2274 #------------------------------------------------------------
2275 if __name__ == "__main__":
2276
2277 if len(sys.argv) < 2:
2278 sys.exit()
2279
2280 if sys.argv[1] != 'test':
2281 sys.exit()
2282
2283 from Gnumed.pycommon import gmLog2
2284 from Gnumed.pycommon import gmI18N
2285 from Gnumed.business import gmPerson
2286
2287 gmI18N.activate_locale()
2288 # gmDateTime.init()
2289 #--------------------------------------------------------
2291 mmi = cGelbeListeWineInterface()
2292 print mmi
2293 print "interface definition:", mmi.version
2294 print "database versions: ", mmi.get_data_source_version()
2295 #--------------------------------------------------------
2297 mmi_file = cGelbeListeCSVFile(filename = sys.argv[2])
2298 for drug in mmi_file:
2299 print "-------------"
2300 print '"%s" (ATC: %s / PZN: %s)' % (drug['name'], drug['atc'], drug['pzn'])
2301 for stoff in drug['wirkstoffe']:
2302 print " Wirkstoff:", stoff
2303 raw_input()
2304 if mmi_file.has_unknown_fields is not None:
2305 print "has extra data under [%s]" % gmTools.default_csv_reader_rest_key
2306 for key in mmi_file.csv_fieldnames:
2307 print key, '->', drug[key]
2308 raw_input()
2309 mmi_file.close()
2310 #--------------------------------------------------------
2314 #--------------------------------------------------------
2316 mmi = cGelbeListeWineInterface()
2317 mmi_file = mmi.__let_user_select_drugs()
2318 for drug in mmi_file:
2319 print "-------------"
2320 print '"%s" (ATC: %s / PZN: %s)' % (drug['name'], drug['atc'], drug['pzn'])
2321 for stoff in drug['wirkstoffe']:
2322 print " Wirkstoff:", stoff
2323 print drug
2324 mmi_file.close()
2325 #--------------------------------------------------------
2329 #--------------------------------------------------------
2331 mmi = cGelbeListeInterface()
2332 print mmi
2333 print "interface definition:", mmi.version
2334 # Metoprolol + Hct vs Citalopram
2335 diclofenac = '7587712'
2336 phenprocoumon = '4421744'
2337 mmi.check_interactions(drug_ids_list = [diclofenac, phenprocoumon])
2338 #--------------------------------------------------------
2339 # FreeDiams
2340 #--------------------------------------------------------
2342 gmPerson.set_active_patient(patient = gmPerson.cIdentity(aPK_obj = 12))
2343 fd = cFreeDiamsInterface()
2344 fd.patient = gmPerson.gmCurrentPatient()
2345 # fd.switch_to_frontend(blocking = True)
2346 fd.import_fd2gm_file_as_drugs(filename = sys.argv[2])
2347 #--------------------------------------------------------
2349 gmPerson.set_active_patient(patient = gmPerson.cIdentity(aPK_obj = 12))
2350 fd = cFreeDiamsInterface()
2351 fd.patient = gmPerson.gmCurrentPatient()
2352 fd.check_interactions(substances = fd.patient.get_emr().get_current_substance_intake(include_unapproved = True))
2353 #--------------------------------------------------------
2354 # generic
2355 #--------------------------------------------------------
2357 drug = create_substance_intake (
2358 pk_component = 2,
2359 encounter = 1,
2360 episode = 1
2361 )
2362 print drug
2363 #--------------------------------------------------------
2368 #--------------------------------------------------------
2372 #--------------------------------------------------------
2374 drug2renal_insufficiency_url(search_term = 'Metoprolol')
2375 #--------------------------------------------------------
2376 # MMI/Gelbe Liste
2377 #test_MMI_interface()
2378 #test_MMI_file()
2379 #test_mmi_switch_to()
2380 #test_mmi_let_user_select_drugs()
2381 #test_mmi_import_substances()
2382 #test_mmi_import_drugs()
2383
2384 # FreeDiams
2385 #test_fd_switch_to()
2386 #test_fd_show_interactions()
2387
2388 # generic
2389 #test_interaction_check()
2390 #test_create_substance_intake()
2391 #test_show_components()
2392 #test_get_consumable_substances()
2393
2394 test_drug2renal_insufficiency_url()
2395 #============================================================
2396
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Mon Dec 5 04:00:09 2011 | http://epydoc.sourceforge.net |