| 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
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_code'] is not None:
62 terms.append(search_term['atc_code'])
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.de/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 = [ a['allergene'] for a in allgs if a['type'] == u'allergy' ]
675 inn_sens = [ a['allergene'] for a in allgs if a['type'] == u'sensitivity' ]
676 # this is rather fragile: FreeDiams won't know what type of UID this is
677 # (but it will assume it is of the type of the drug database in use)
678 uid_allgs = [
679 a['substance_code'] for a in allgs if ((a['substance_code'] is not None) and (a['type'] == u'allergy'))
680 ]
681 uid_sens = [
682 a['substance_code'] for a in allgs if ((a['substance_code'] is not None) and (a['type'] == u'sensitivity'))
683 ]
684
685 patient_xml = u"""<Patient>
686 <Identity
687 lastnames="%s"
688 firstnames="%s"
689 uid="%s"
690 dob="%s"
691 gender="%s"
692 />
693 <ATCAllergies value="%s"/>
694 <ATCIntolerances value="%s"/>
695
696 <InnAllergies value="%s"/>
697 <InnIntolerances value="%s"/>
698
699 <DrugsUidAllergies value="%s"/>
700 <DrugsUidIntolerances value="%s"/>
701 </Patient>
702 """ % (
703 gmTools.xml_escape_string(text = name['lastnames']),
704 gmTools.xml_escape_string(text = name['firstnames']),
705 self.patient.ID,
706 dob,
707 cFreeDiamsInterface.map_gender2mf[self.patient['gender']],
708 gmTools.xml_escape_string(text = u';'.join(atc_allgs)),
709 gmTools.xml_escape_string(text = u';'.join(atc_sens)),
710 gmTools.xml_escape_string(text = u';'.join(inn_allgs)),
711 gmTools.xml_escape_string(text = u';'.join(inn_sens)),
712 gmTools.xml_escape_string(text = u';'.join(uid_allgs)),
713 gmTools.xml_escape_string(text = u';'.join(uid_sens))
714 )
715
716 xml_file.write(xml % patient_xml)
717 xml_file.close()
718 #--------------------------------------------------------
720
721 if filename is None:
722 filename = self.__fd2gm_filename
723
724 fd2gm_xml = etree.ElementTree()
725 fd2gm_xml.parse(filename)
726
727 pdfs = fd2gm_xml.findall('ExtraDatas/Printed')
728 if len(pdfs) == 0:
729 return
730
731 fd_filenames = []
732 for pdf in pdfs:
733 fd_filenames.append(pdf.attrib['file'])
734
735 docs = self.patient.get_document_folder()
736 emr = self.patient.get_emr()
737
738 prescription = docs.add_document (
739 document_type = create_document_type (
740 document_type = DOCUMENT_TYPE_PRESCRIPTION
741 )['pk_doc_type'],
742 encounter = emr.active_encounter['pk_encounter'],
743 episode = emr.add_episode (
744 episode_name = DEFAULT_MEDICATION_HISTORY_EPISODE,
745 is_open = False
746 )['pk_episode']
747 )
748 prescription['ext_ref'] = u'FreeDiams'
749 prescription.save()
750 fd_filenames.append(filename)
751 success, msg, parts = prescription.add_parts_from_files (
752 files = fd_filenames,
753 reviewer = self.reviewer['pk_staff']
754 )
755
756 if not success:
757 _log.error(msg)
758 return
759
760 xml_part = parts[-1]
761 xml_part['filename'] = u'freediams-prescription.xml'
762 xml_part.save()
763 #--------------------------------------------------------
765 """
766 If returning textual prescriptions (say, drugs which FreeDiams
767 did not know) then "IsTextual" will be True and UID will be -1.
768 """
769 if filename is None:
770 filename = self.__fd2gm_filename
771
772 # FIXME: do not import IsTextual drugs, or rather, make that configurable
773
774 fd2gm_xml = etree.ElementTree()
775 fd2gm_xml.parse(filename)
776
777 data_src_pk = self.create_data_source_entry()
778
779 db_def = fd2gm_xml.find('DrugsDatabaseName')
780 db_id = db_def.text.strip()
781 drug_id_name = db_def.attrib['drugUidName']
782 fd_xml_drug_entries = fd2gm_xml.findall('FullPrescription/Prescription')
783
784 self.__imported_drugs = []
785 for fd_xml_drug in fd_xml_drug_entries:
786 drug_uid = fd_xml_drug.find('Drug_UID').text.strip()
787 if drug_uid == u'-1':
788 _log.debug('skipping textual drug')
789 continue # it's a TextualDrug, skip it
790 drug_name = fd_xml_drug.find('DrugName').text.replace(', )', ')').strip()
791 drug_form = fd_xml_drug.find('DrugForm').text.strip()
792 drug_atc = fd_xml_drug.find('DrugATC')
793 if drug_atc is None:
794 drug_atc = u''
795 else:
796 drug_atc = drug_atc.text.strip()
797
798 # create new branded drug
799 new_drug = create_branded_drug(brand_name = drug_name, preparation = drug_form, return_existing = True)
800 self.__imported_drugs.append(new_drug)
801 new_drug['is_fake_brand'] = False
802 new_drug['atc'] = drug_atc
803 new_drug['external_code_type'] = u'FreeDiams::%s::%s' % (db_id, drug_id_name)
804 new_drug['external_code'] = drug_uid
805 new_drug['pk_data_source'] = data_src_pk
806 new_drug.save()
807
808 # parse XML for composition records
809 fd_xml_components = fd_xml_drug.getiterator('Composition')
810 comp_data = {}
811 for fd_xml_comp in fd_xml_components:
812
813 data = {}
814
815 amount = regex.match(r'\d+[.,]{0,1}\d*', fd_xml_comp.attrib['strenght'].strip()) # sic, typo
816 if amount is None:
817 amount = 99999
818 else:
819 amount = amount.group()
820 data['amount'] = amount
821
822 unit = regex.sub(r'\d+[.,]{0,1}\d*', u'', fd_xml_comp.attrib['strenght'].strip()).strip() # sic, typo
823 if unit == u'':
824 unit = u'*?*'
825 data['unit'] = unit
826
827 molecule_name = fd_xml_comp.attrib['molecularName'].strip()
828 if molecule_name != u'':
829 create_consumable_substance(substance = molecule_name, atc = None, amount = amount, unit = unit)
830 data['molecule_name'] = molecule_name
831
832 inn_name = fd_xml_comp.attrib['inn'].strip()
833 if inn_name != u'':
834 create_consumable_substance(substance = inn_name, atc = None, amount = amount, unit = unit)
835 data['inn_name'] = molecule_name
836
837 if molecule_name == u'':
838 data['substance'] = inn_name
839 _log.info('linking INN [%s] rather than molecularName as component', inn_name)
840 else:
841 data['substance'] = molecule_name
842
843 data['nature'] = fd_xml_comp.attrib['nature'].strip()
844 data['nature_ID'] = fd_xml_comp.attrib['natureLink'].strip()
845
846 # merge composition records of SA/FT nature
847 try:
848 old_data = comp_data[data['nature_ID']]
849 # normalize INN
850 if old_data['inn_name'] == u'':
851 old_data['inn_name'] = data['inn_name']
852 if data['inn_name'] == u'':
853 data['inn_name'] = old_data['inn_name']
854 # normalize molecule
855 if old_data['molecule_name'] == u'':
856 old_data['molecule_name'] = data['molecule_name']
857 if data['molecule_name'] == u'':
858 data['molecule_name'] = old_data['molecule_name']
859 # FT: transformed form
860 # SA: active substance
861 # it would be preferable to use the SA record because that's what's *actually*
862 # contained in the drug, however FreeDiams does not list the amount thereof
863 # (rather that of the INN)
864 if data['nature'] == u'FT':
865 comp_data[data['nature_ID']] = data
866 else:
867 comp_data[data['nature_ID']] = old_data
868
869 # or create new record
870 except KeyError:
871 comp_data[data['nature_ID']] = data
872
873 # actually create components from (possibly merged) composition records
874 for key, data in comp_data.items():
875 new_drug.add_component (
876 substance = data['substance'],
877 atc = None,
878 amount = data['amount'],
879 unit = data['unit']
880 )
881 #============================================================
883 """Support v8.2 CSV file interface only."""
884
885 version = u'Gelbe Liste/MMI v8.2 interface'
886 default_encoding = 'cp1250'
887 bdt_line_template = u'%03d6210#%s\r\n' # Medikament verordnet auf Kassenrezept
888 bdt_line_base_length = 8
889 #--------------------------------------------------------
891
892 cDrugDataSourceInterface.__init__(self)
893
894 _log.info(u'%s (native Windows)', cGelbeListeWindowsInterface.version)
895
896 self.path_to_binary = r'C:\Programme\MMI PHARMINDEX\glwin.exe'
897 self.args = r'-KEEPBACKGROUND -PRESCRIPTIONFILE %s -CLOSETOTRAY'
898
899 paths = gmTools.gmPaths()
900
901 self.default_csv_filename = os.path.join(paths.home_dir, '.gnumed', 'tmp', 'rezept.txt')
902 self.default_csv_filename_arg = os.path.join(paths.home_dir, '.gnumed', 'tmp')
903 self.interactions_filename = os.path.join(paths.home_dir, '.gnumed', 'tmp', 'gm2mmi.bdt')
904 self.data_date_filename = r'C:\Programme\MMI PHARMINDEX\datadate.txt'
905
906 self.__data_date = None
907 self.__online_update_date = None
908
909 # use adjusted config.dat
910 #--------------------------------------------------------
912
913 if self.__data_date is not None:
914 if not force_reload:
915 return {
916 'data': self.__data_date,
917 'online_update': self.__online_update_date
918 }
919
920 open(self.data_date_filename, 'wb').close()
921
922 cmd = u'%s -DATADATE' % self.path_to_binary
923 if not gmShellAPI.run_command_in_shell(command = cmd, blocking = True):
924 _log.error('problem querying the MMI drug database for version information')
925 self.__data_date = None
926 self.__online_update_date = None
927 return {
928 'data': u'?',
929 'online_update': u'?'
930 }
931
932 try:
933 version_file = open(self.data_date_filename, 'rU')
934 except StandardError:
935 _log.error('problem querying the MMI drug database for version information')
936 _log.exception('cannot open MMI drug database version file [%s]', self.data_date_filename)
937 self.__data_date = None
938 self.__online_update_date = None
939 return {
940 'data': u'?',
941 'online_update': u'?'
942 }
943
944 self.__data_date = version_file.readline()[:10]
945 self.__online_update_date = version_file.readline()[:10]
946 version_file.close()
947
948 return {
949 'data': self.__data_date,
950 'online_update': self.__online_update_date
951 }
952 #--------------------------------------------------------
954 versions = self.get_data_source_version()
955
956 return create_data_source (
957 long_name = u'Medikamentendatenbank "mmi PHARMINDEX" (Gelbe Liste)',
958 short_name = u'GL/MMI',
959 version = u'Daten: %s, Preise (Onlineupdate): %s' % (versions['data'], versions['online_update']),
960 source = u'Medizinische Medien Informations GmbH, Am Forsthaus Gravenbruch 7, 63263 Neu-Isenburg',
961 language = u'de'
962 )
963 #--------------------------------------------------------
965
966 try:
967 # must make sure csv file exists
968 open(self.default_csv_filename, 'wb').close()
969 except IOError:
970 _log.exception('problem creating GL/MMI <-> GNUmed exchange file')
971 return False
972
973 if cmd is None:
974 cmd = (u'%s %s' % (self.path_to_binary, self.args)) % self.default_csv_filename_arg
975
976 if not gmShellAPI.run_command_in_shell(command = cmd, blocking = blocking):
977 _log.error('problem switching to the MMI drug database')
978 # apparently on the first call MMI does not
979 # consistently return 0 on success
980 # return False
981
982 return True
983 #--------------------------------------------------------
985
986 # better to clean up interactions file
987 open(self.interactions_filename, 'wb').close()
988
989 if not self.switch_to_frontend(blocking = True):
990 return None
991
992 return cGelbeListeCSVFile(filename = self.default_csv_filename)
993 #--------------------------------------------------------
995
996 selected_drugs = self.__let_user_select_drugs()
997 if selected_drugs is None:
998 return None
999
1000 new_substances = []
1001
1002 for drug in selected_drugs:
1003 atc = None # hopefully MMI eventually supports atc-per-substance in a drug...
1004 if len(drug['wirkstoffe']) == 1:
1005 atc = drug['atc']
1006 for wirkstoff in drug['wirkstoffe']:
1007 new_substances.append(create_consumable_substance(substance = wirkstoff, atc = atc, amount = amount, unit = unit))
1008
1009 selected_drugs.close()
1010
1011 return new_substances
1012 #--------------------------------------------------------
1014
1015 selected_drugs = self.__let_user_select_drugs()
1016 if selected_drugs is None:
1017 return None
1018
1019 data_src_pk = self.create_data_source_entry()
1020
1021 new_drugs = []
1022 new_substances = []
1023
1024 for entry in selected_drugs:
1025
1026 _log.debug('importing drug: %s %s', entry['name'], entry['darreichungsform'])
1027
1028 if entry[u'hilfsmittel']:
1029 _log.debug('skipping Hilfsmittel')
1030 continue
1031
1032 if entry[u'erstattbares_medizinprodukt']:
1033 _log.debug('skipping sonstiges Medizinprodukt')
1034 continue
1035
1036 # create branded drug (or get it if it already exists)
1037 drug = create_branded_drug(brand_name = entry['name'], preparation = entry['darreichungsform'])
1038 if drug is None:
1039 drug = get_drug_by_brand(brand_name = entry['name'], preparation = entry['darreichungsform'])
1040 new_drugs.append(drug)
1041
1042 # update fields
1043 drug['is_fake'] = False
1044 drug['atc_code'] = entry['atc']
1045 drug['external_code_type'] = u'DE-PZN'
1046 drug['external_code'] = entry['pzn']
1047 drug['fk_data_source'] = data_src_pk
1048 drug.save()
1049
1050 # add components to brand
1051 atc = None # hopefully MMI eventually supports atc-per-substance in a drug...
1052 if len(entry['wirkstoffe']) == 1:
1053 atc = entry['atc']
1054 for wirkstoff in entry['wirkstoffe']:
1055 drug.add_component(substance = wirkstoff, atc = atc)
1056
1057 # create as consumable substances, too
1058 atc = None # hopefully MMI eventually supports atc-per-substance in a drug...
1059 if len(entry['wirkstoffe']) == 1:
1060 atc = entry['atc']
1061 for wirkstoff in entry['wirkstoffe']:
1062 new_substances.append(create_consumable_substance(substance = wirkstoff, atc = atc, amount = amount, unit = unit))
1063
1064 return new_drugs, new_substances
1065 #--------------------------------------------------------
1067 """For this to work the BDT interaction check must be configured in the MMI."""
1068
1069 if drug_ids_list is None:
1070 if substances is None:
1071 return
1072 if len(substances) < 2:
1073 return
1074 drug_ids_list = [ (s.external_code_type, s.external_code) for s in substances ]
1075 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')]
1076
1077 else:
1078 if len(drug_ids_list) < 2:
1079 return
1080
1081 if drug_ids_list < 2:
1082 return
1083
1084 bdt_file = codecs.open(filename = self.interactions_filename, mode = 'wb', encoding = cGelbeListeWindowsInterface.default_encoding)
1085
1086 for pzn in drug_ids_list:
1087 pzn = pzn.strip()
1088 lng = cGelbeListeWindowsInterface.bdt_line_base_length + len(pzn)
1089 bdt_file.write(cGelbeListeWindowsInterface.bdt_line_template % (lng, pzn))
1090
1091 bdt_file.close()
1092
1093 self.switch_to_frontend(blocking = False)
1094 #--------------------------------------------------------
1096 self.switch_to_frontend(blocking = True)
1097 #--------------------------------------------------------
1099
1100 cmd = None
1101
1102 if substance.external_code_type == u'DE-PZN':
1103 cmd = u'%s -PZN %s' % (self.path_to_binary, substance.external_code)
1104
1105 if cmd is None:
1106 name = gmTools.coalesce (
1107 substance['brand'],
1108 substance['substance']
1109 )
1110 cmd = u'%s -NAME %s' % (self.path_to_binary, name)
1111
1112 # better to clean up interactions file
1113 open(self.interactions_filename, 'wb').close()
1114
1115 self.switch_to_frontend(cmd = cmd)
1116 #============================================================
1118
1120 cGelbeListeWindowsInterface.__init__(self)
1121
1122 _log.info(u'%s (WINE extension)', cGelbeListeWindowsInterface.version)
1123
1124 # FIXME: if -CLOSETOTRAY is used GNUmed cannot detect the end of MMI
1125 self.path_to_binary = r'wine "C:\Programme\MMI PHARMINDEX\glwin.exe"'
1126 self.args = r'"-PRESCRIPTIONFILE %s -KEEPBACKGROUND"'
1127
1128 paths = gmTools.gmPaths()
1129
1130 self.default_csv_filename = os.path.join(paths.home_dir, '.wine', 'drive_c', 'windows', 'temp', 'mmi2gm.csv')
1131 self.default_csv_filename_arg = r'c:\windows\temp\mmi2gm.csv'
1132 self.interactions_filename = os.path.join(paths.home_dir, '.wine', 'drive_c', 'windows', 'temp', 'gm2mmi.bdt')
1133 self.data_date_filename = os.path.join(paths.home_dir, '.wine', 'drive_c', 'Programme', 'MMI PHARMINDEX', 'datadate.txt')
1134 #============================================================
1136 """empirical CSV interface"""
1137
1140
1142
1143 try:
1144 csv_file = open(filename, 'rb') # FIXME: encoding ?
1145 except:
1146 _log.exception('cannot access [%s]', filename)
1147 csv_file = None
1148
1149 field_names = u'PZN Handelsname Form Abpackungsmenge Einheit Preis1 Hersteller Preis2 rezeptpflichtig Festbetrag Packungszahl Packungsgr\xf6\xdfe'.split()
1150
1151 if csv_file is None:
1152 return False
1153
1154 csv_lines = csv.DictReader (
1155 csv_file,
1156 fieldnames = field_names,
1157 delimiter = ';'
1158 )
1159
1160 for line in csv_lines:
1161 print "--------------------------------------------------------------------"[:31]
1162 for key in field_names:
1163 tmp = ('%s ' % key)[:30]
1164 print '%s: %s' % (tmp, line[key])
1165
1166 csv_file.close()
1167
1168 # narr = u'%sx %s %s %s (\u2258 %s %s) von %s (%s)' % (
1169 # line['Packungszahl'].strip(),
1170 # line['Handelsname'].strip(),
1171 # line['Form'].strip(),
1172 # line[u'Packungsgr\xf6\xdfe'].strip(),
1173 # line['Abpackungsmenge'].strip(),
1174 # line['Einheit'].strip(),
1175 # line['Hersteller'].strip(),
1176 # line['PZN'].strip()
1177 # )
1178 #============================================================
1179 drug_data_source_interfaces = {
1180 'Deutschland: Gelbe Liste/MMI (Windows)': cGelbeListeWindowsInterface,
1181 'Deutschland: Gelbe Liste/MMI (WINE)': cGelbeListeWineInterface,
1182 'FreeDiams (FR, US, CA, ZA)': cFreeDiamsInterface
1183 }
1184
1185 #============================================================
1186 #============================================================
1187 # substances in use across all patients
1188 #------------------------------------------------------------
1189 _SQL_get_consumable_substance = u"""
1190 SELECT *, xmin
1191 FROM ref.consumable_substance
1192 WHERE %s
1193 """
1194
1196
1197 _cmd_fetch_payload = _SQL_get_consumable_substance % u"pk = %s"
1198 _cmds_store_payload = [
1199 u"""UPDATE ref.consumable_substance SET
1200 description = %(description)s,
1201 atc_code = gm.nullify_empty_string(%(atc_code)s),
1202 amount = %(amount)s,
1203 unit = gm.nullify_empty_string(%(unit)s)
1204 WHERE
1205 pk = %(pk)s
1206 AND
1207 xmin = %(xmin)s
1208 AND
1209 -- must not currently be used with a patient directly
1210 NOT EXISTS (
1211 SELECT 1
1212 FROM clin.substance_intake
1213 WHERE
1214 fk_drug_component IS NULL
1215 AND
1216 fk_substance = %(pk)s
1217 LIMIT 1
1218 )
1219 AND
1220 -- must not currently be used with a patient indirectly, either
1221 NOT EXISTS (
1222 SELECT 1
1223 FROM clin.substance_intake
1224 WHERE
1225 fk_drug_component IS NOT NULL
1226 AND
1227 fk_drug_component = (
1228 SELECT r_ls2b.pk
1229 FROM ref.lnk_substance2brand r_ls2b
1230 WHERE fk_substance = %(pk)s
1231 )
1232 LIMIT 1
1233 )
1234 -- -- must not currently be used with a branded drug
1235 -- -- (but this would make it rather hard fixing branded drugs which contain only this substance)
1236 -- NOT EXISTS (
1237 -- SELECT 1
1238 -- FROM ref.lnk_substance2brand
1239 -- WHERE fk_substance = %(pk)s
1240 -- LIMIT 1
1241 -- )
1242 RETURNING
1243 xmin
1244 """
1245 ]
1246 _updatable_fields = [
1247 u'description',
1248 u'atc_code',
1249 u'amount',
1250 u'unit'
1251 ]
1252 #--------------------------------------------------------
1254 success, data = super(self.__class__, self).save_payload(conn = conn)
1255
1256 if not success:
1257 return (success, data)
1258
1259 if self._payload[self._idx['atc_code']] is not None:
1260 atc = self._payload[self._idx['atc_code']].strip()
1261 if atc != u'':
1262 gmATC.propagate_atc (
1263 substance = self._payload[self._idx['description']].strip(),
1264 atc = atc
1265 )
1266
1267 return (success, data)
1268 #--------------------------------------------------------
1269 # properties
1270 #--------------------------------------------------------
1272 cmd = u"""
1273 SELECT
1274 EXISTS (
1275 SELECT 1
1276 FROM clin.substance_intake
1277 WHERE
1278 fk_drug_component IS NULL
1279 AND
1280 fk_substance = %(pk)s
1281 LIMIT 1
1282 ) OR EXISTS (
1283 SELECT 1
1284 FROM clin.substance_intake
1285 WHERE
1286 fk_drug_component IS NOT NULL
1287 AND
1288 fk_drug_component = (
1289 SELECT r_ls2b.pk
1290 FROM ref.lnk_substance2brand r_ls2b
1291 WHERE fk_substance = %(pk)s
1292 )
1293 LIMIT 1
1294 )"""
1295 args = {'pk': self.pk_obj}
1296
1297 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
1298 return rows[0][0]
1299
1300 is_in_use_by_patients = property(_get_is_in_use_by_patients, lambda x:x)
1301 #--------------------------------------------------------
1303 cmd = u"""
1304 SELECT EXISTS (
1305 SELECT 1
1306 FROM ref.lnk_substance2brand
1307 WHERE fk_substance = %(pk)s
1308 LIMIT 1
1309 )"""
1310 args = {'pk': self.pk_obj}
1311
1312 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
1313 return rows[0][0]
1314
1315 is_drug_component = property(_get_is_drug_component, lambda x:x)
1316 #------------------------------------------------------------
1318 if order_by is None:
1319 order_by = u'true'
1320 else:
1321 order_by = u'true ORDER BY %s' % order_by
1322 cmd = _SQL_get_consumable_substance % order_by
1323 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = True)
1324 return [ cConsumableSubstance(row = {'data': r, 'idx': idx, 'pk_field': 'pk'}) for r in rows ]
1325 #------------------------------------------------------------
1327
1328 substance = substance
1329 if atc is not None:
1330 atc = atc.strip()
1331
1332 converted, amount = gmTools.input2decimal(amount)
1333 if not converted:
1334 raise ValueError('<amount> must be a number: %s (%s)', amount, type(amount))
1335
1336 args = {
1337 'desc': substance.strip(),
1338 'amount': amount,
1339 'unit': unit.strip(),
1340 'atc': atc
1341 }
1342 cmd = u"""
1343 SELECT pk FROM ref.consumable_substance
1344 WHERE
1345 lower(description) = lower(%(desc)s)
1346 AND
1347 amount = %(amount)s
1348 AND
1349 unit = %(unit)s
1350 """
1351 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}])
1352
1353 if len(rows) == 0:
1354 cmd = u"""
1355 INSERT INTO ref.consumable_substance (description, atc_code, amount, unit) VALUES (
1356 %(desc)s,
1357 gm.nullify_empty_string(%(atc)s),
1358 %(amount)s,
1359 gm.nullify_empty_string(%(unit)s)
1360 ) RETURNING pk"""
1361 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True, get_col_idx = False)
1362
1363 gmATC.propagate_atc(substance = substance, atc = atc)
1364
1365 return cConsumableSubstance(aPK_obj = rows[0]['pk'])
1366 #------------------------------------------------------------
1368 args = {'pk': substance}
1369 cmd = u"""
1370 DELETE FROM ref.consumable_substance
1371 WHERE
1372 pk = %(pk)s
1373 AND
1374
1375 -- must not currently be used with a patient
1376 NOT EXISTS (
1377 SELECT 1
1378 FROM clin.v_pat_substance_intake
1379 WHERE pk_substance = %(pk)s
1380 LIMIT 1
1381 )
1382 AND
1383
1384 -- must not currently be used with a branded drug
1385 NOT EXISTS (
1386 SELECT 1
1387 FROM ref.lnk_substance2brand
1388 WHERE fk_substance = %(pk)s
1389 LIMIT 1
1390 )"""
1391 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
1392 return True
1393 #------------------------------------------------------------
1395
1396 _pattern = regex.compile(r'^\D+\s*\d+$', regex.UNICODE | regex.LOCALE)
1397 _query1 = u"""
1398 SELECT
1399 pk::text,
1400 (description || ' ' || amount || unit) as subst
1401 FROM ref.consumable_substance
1402 WHERE description %(fragment_condition)s
1403 ORDER BY subst
1404 LIMIT 50"""
1405 _query2 = u"""
1406 SELECT
1407 pk::text,
1408 (description || ' ' || amount || unit) as subst
1409 FROM ref.consumable_substance
1410 WHERE
1411 %(fragment_condition)s
1412 ORDER BY subst
1413 LIMIT 50"""
1414
1415 #--------------------------------------------------------
1417 """Return matches for aFragment at start of phrases."""
1418
1419 if cSubstanceMatchProvider._pattern.match(aFragment):
1420 self._queries = [cSubstanceMatchProvider._query2]
1421 fragment_condition = """description ILIKE %(desc)s
1422 AND
1423 amount::text ILIKE %(amount)s"""
1424 self._args['desc'] = u'%s%%' % regex.sub(r'\s*\d+$', u'', aFragment)
1425 self._args['amount'] = u'%s%%' % regex.sub(r'^\D+\s*', u'', aFragment)
1426 else:
1427 self._queries = [cSubstanceMatchProvider._query1]
1428 fragment_condition = u"ILIKE %(fragment)s"
1429 self._args['fragment'] = u"%s%%" % aFragment
1430
1431 return self._find_matches(fragment_condition)
1432 #--------------------------------------------------------
1434 """Return matches for aFragment at start of words inside phrases."""
1435
1436 if cSubstanceMatchProvider._pattern.match(aFragment):
1437 self._queries = [cSubstanceMatchProvider._query2]
1438
1439 desc = regex.sub(r'\s*\d+$', u'', aFragment)
1440 desc = gmPG2.sanitize_pg_regex(expression = desc, escape_all = False)
1441
1442 fragment_condition = """description ~* %(desc)s
1443 AND
1444 amount::text ILIKE %(amount)s"""
1445
1446 self._args['desc'] = u"( %s)|(^%s)" % (desc, desc)
1447 self._args['amount'] = u'%s%%' % regex.sub(r'^\D+\s*', u'', aFragment)
1448 else:
1449 self._queries = [cSubstanceMatchProvider._query1]
1450 fragment_condition = u"~* %(fragment)s"
1451 aFragment = gmPG2.sanitize_pg_regex(expression = aFragment, escape_all = False)
1452 self._args['fragment'] = u"( %s)|(^%s)" % (aFragment, aFragment)
1453
1454 return self._find_matches(fragment_condition)
1455 #--------------------------------------------------------
1457 """Return matches for aFragment as a true substring."""
1458
1459 if cSubstanceMatchProvider._pattern.match(aFragment):
1460 self._queries = [cSubstanceMatchProvider._query2]
1461 fragment_condition = """description ILIKE %(desc)s
1462 AND
1463 amount::text ILIKE %(amount)s"""
1464 self._args['desc'] = u'%%%s%%' % regex.sub(r'\s*\d+$', u'', aFragment)
1465 self._args['amount'] = u'%s%%' % regex.sub(r'^\D+\s*', u'', aFragment)
1466 else:
1467 self._queries = [cSubstanceMatchProvider._query1]
1468 fragment_condition = u"ILIKE %(fragment)s"
1469 self._args['fragment'] = u"%%%s%%" % aFragment
1470
1471 return self._find_matches(fragment_condition)
1472 #============================================================
1474 """Represents a substance currently taken by a patient."""
1475
1476 _cmd_fetch_payload = u"SELECT * FROM clin.v_pat_substance_intake WHERE pk_substance_intake = %s"
1477 _cmds_store_payload = [
1478 u"""UPDATE clin.substance_intake SET
1479 clin_when = %(started)s,
1480 discontinued = %(discontinued)s,
1481 discontinue_reason = gm.nullify_empty_string(%(discontinue_reason)s),
1482 schedule = gm.nullify_empty_string(%(schedule)s),
1483 aim = gm.nullify_empty_string(%(aim)s),
1484 narrative = gm.nullify_empty_string(%(notes)s),
1485 intake_is_approved_of = %(intake_is_approved_of)s,
1486 fk_episode = %(pk_episode)s,
1487
1488 preparation = (
1489 case
1490 when %(pk_brand)s is NULL then %(preparation)s
1491 else NULL
1492 end
1493 )::text,
1494
1495 is_long_term = (
1496 case
1497 when (
1498 (%(is_long_term)s is False)
1499 and
1500 (%(duration)s is NULL)
1501 ) is True then null
1502 else %(is_long_term)s
1503 end
1504 )::boolean,
1505
1506 duration = (
1507 case
1508 when %(is_long_term)s is True then null
1509 else %(duration)s
1510 end
1511 )::interval
1512 WHERE
1513 pk = %(pk_substance_intake)s
1514 AND
1515 xmin = %(xmin_substance_intake)s
1516 RETURNING
1517 xmin as xmin_substance_intake
1518 """
1519 ]
1520 _updatable_fields = [
1521 u'started',
1522 u'discontinued',
1523 u'discontinue_reason',
1524 u'preparation',
1525 u'intake_is_approved_of',
1526 u'schedule',
1527 u'duration',
1528 u'aim',
1529 u'is_long_term',
1530 u'notes',
1531 u'pk_episode'
1532 ]
1533 #--------------------------------------------------------
1535
1536 if self._payload[self._idx['duration']] is None:
1537 duration = gmTools.bool2subst (
1538 self._payload[self._idx['is_long_term']],
1539 _('long-term'),
1540 _('short-term'),
1541 _('?short-term')
1542 )
1543 else:
1544 duration = gmDateTime.format_interval (
1545 self._payload[self._idx['duration']],
1546 accuracy_wanted = gmDateTime.acc_days
1547 )
1548
1549 line = u'%s%s (%s %s): %s %s%s %s (%s)' % (
1550 u' ' * left_margin,
1551 self._payload[self._idx['started']].strftime(date_format),
1552 gmTools.u_right_arrow,
1553 duration,
1554 self._payload[self._idx['substance']],
1555 self._payload[self._idx['amount']],
1556 self._payload[self._idx['unit']],
1557 self._payload[self._idx['preparation']],
1558 gmTools.bool2subst(self._payload[self._idx['is_currently_active']], _('ongoing'), _('inactive'), _('?ongoing'))
1559 )
1560
1561 return line
1562 #--------------------------------------------------------
1564 allg = gmAllergy.create_allergy (
1565 allergene = self._payload[self._idx['substance']],
1566 allg_type = allergy_type,
1567 episode_id = self._payload[self._idx['pk_episode']],
1568 encounter_id = encounter_id
1569 )
1570 allg['substance'] = gmTools.coalesce (
1571 self._payload[self._idx['brand']],
1572 self._payload[self._idx['substance']]
1573 )
1574 allg['reaction'] = self._payload[self._idx['discontinue_reason']]
1575 allg['atc_code'] = gmTools.coalesce(self._payload[self._idx['atc_substance']], self._payload[self._idx['atc_brand']])
1576 if self._payload[self._idx['external_code_brand']] is not None:
1577 allg['substance_code'] = u'%s::::%s' % (self._payload[self._idx['external_code_type_brand']], self._payload[self._idx['external_code_brand']])
1578 comps = [ c['substance'] for c in self.containing_drug.components ]
1579 if len(comps) == 0:
1580 allg['generics'] = self._payload[self._idx['substance']]
1581 else:
1582 allg['generics'] = u'; '.join(comps)
1583
1584 allg.save()
1585 return allg
1586 #--------------------------------------------------------
1587 # properties
1588 #--------------------------------------------------------
1590
1591 try: self.__ddd
1592 except AttributeError: self.__ddd = None
1593
1594 if self.__ddd is not None:
1595 return self.__ddd
1596
1597 if self._payload[self._idx['atc_substance']] is not None:
1598 ddd = gmATC.atc2ddd(atc = self._payload[self._idx['atc_substance']])
1599 if len(ddd) != 0:
1600 self.__ddd = ddd[0]
1601 else:
1602 if self._payload[self._idx['atc_brand']] is not None:
1603 ddd = gmATC.atc2ddd(atc = self._payload[self._idx['atc_brand']])
1604 if len(ddd) != 0:
1605 self.__ddd = ddd[0]
1606
1607 return self.__ddd
1608
1609 ddd = property(_get_ddd, lambda x:x)
1610 #--------------------------------------------------------
1612 drug = self.containing_drug
1613
1614 if drug is None:
1615 return None
1616
1617 return drug.external_code
1618
1619 external_code = property(_get_external_code, lambda x:x)
1620 #--------------------------------------------------------
1622 drug = self.containing_drug
1623
1624 if drug is None:
1625 return None
1626
1627 return drug.external_code_type
1628
1629 external_code_type = property(_get_external_code_type, lambda x:x)
1630 #--------------------------------------------------------
1632 if self._payload[self._idx['pk_brand']] is None:
1633 return None
1634
1635 return cBrandedDrug(aPK_obj = self._payload[self._idx['pk_brand']])
1636
1637 containing_drug = property(_get_containing_drug, lambda x:x)
1638 #--------------------------------------------------------
1640 tests = [
1641 # lead, trail
1642 ' 1-1-1-1 ',
1643 # leading dose
1644 '1-1-1-1',
1645 '22-1-1-1',
1646 '1/3-1-1-1',
1647 '/4-1-1-1'
1648 ]
1649 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}$"
1650 for test in tests:
1651 print test.strip(), ":", regex.match(pattern, test.strip())
1652 #------------------------------------------------------------
1653 -def create_substance_intake(pk_substance=None, pk_component=None, preparation=None, encounter=None, episode=None):
1654
1655 args = {
1656 'enc': encounter,
1657 'epi': episode,
1658 'comp': pk_component,
1659 'subst': pk_substance,
1660 'prep': preparation
1661 }
1662
1663 if pk_component is None:
1664 cmd = u"""
1665 INSERT INTO clin.substance_intake (
1666 fk_encounter,
1667 fk_episode,
1668 intake_is_approved_of,
1669 fk_substance,
1670 preparation
1671 ) VALUES (
1672 %(enc)s,
1673 %(epi)s,
1674 False,
1675 %(subst)s,
1676 %(prep)s
1677 )
1678 RETURNING pk"""
1679 else:
1680 cmd = u"""
1681 INSERT INTO clin.substance_intake (
1682 fk_encounter,
1683 fk_episode,
1684 intake_is_approved_of,
1685 fk_drug_component
1686 ) VALUES (
1687 %(enc)s,
1688 %(epi)s,
1689 False,
1690 %(comp)s
1691 )
1692 RETURNING pk"""
1693
1694 try:
1695 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True)
1696 except gmPG2.dbapi.InternalError, e:
1697 if e.pgerror is None:
1698 raise
1699 if 'prevent_duplicate_component' in e.pgerror:
1700 _log.exception('will not create duplicate substance intake entry')
1701 _log.error(e.pgerror)
1702 return None
1703 raise
1704
1705 return cSubstanceIntakeEntry(aPK_obj = rows[0][0])
1706 #------------------------------------------------------------
1708 cmd = u'delete from clin.substance_intake where pk = %(pk)s'
1709 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': {'pk': substance}}])
1710 #------------------------------------------------------------
1712
1713 tex = u'\n{\\small\n'
1714 tex += u'\\noindent %s\n' % _('Additional notes')
1715 tex += u'\n'
1716 tex += u'\\noindent \\begin{tabular}{|l|l|l|l|}\n'
1717 tex += u'\\hline\n'
1718 tex += u'%s & %s & %s & \\\\ \n' % (_('Substance'), _('Strength'), _('Brand'))
1719 tex += u'\\hline\n'
1720 tex += u'%s\n'
1721 tex += u'\n'
1722 tex += u'\\end{tabular}\n'
1723 tex += u'}\n'
1724
1725 current_meds = emr.get_current_substance_intake (
1726 include_inactive = False,
1727 include_unapproved = False,
1728 order_by = u'brand, substance'
1729 )
1730
1731 # create lines
1732 lines = []
1733 for med in current_meds:
1734
1735 lines.append(u'%s & %s%s & %s %s & {\\scriptsize %s} \\\\ \n \\hline \n' % (
1736 med['substance'],
1737 med['amount'],
1738 med['unit'],
1739 gmTools.coalesce(med['brand'], u''),
1740 med['preparation'],
1741 gmTools.coalesce(med['notes'], u'')
1742 ))
1743
1744 return tex % u' \n'.join(lines)
1745
1746 #------------------------------------------------------------
1748
1749 tex = u'\\noindent %s {\\tiny (%s)\\par}\n' % (_('Medication list'), _('ordered by brand'))
1750 tex += u'\n'
1751 tex += u'\\noindent \\begin{tabular}{|l|l|}\n'
1752 tex += u'\\hline\n'
1753 tex += u'%s & %s \\\\ \n' % (_('Drug'), _('Regimen'))
1754 tex += u'\\hline\n'
1755 tex += u'\n'
1756 tex += u'\\hline\n'
1757 tex += u'%s\n'
1758 tex += u'\n'
1759 tex += u'\\end{tabular}\n'
1760
1761 current_meds = emr.get_current_substance_intake (
1762 include_inactive = False,
1763 include_unapproved = False,
1764 order_by = u'brand, substance'
1765 )
1766
1767 # aggregate data
1768 line_data = {}
1769 for med in current_meds:
1770 identifier = gmTools.coalesce(med['brand'], med['substance'])
1771
1772 try:
1773 line_data[identifier]
1774 except KeyError:
1775 line_data[identifier] = {'brand': u'', 'preparation': u'', 'schedule': u'', 'aims': [], 'strengths': []}
1776
1777 line_data[identifier]['brand'] = identifier
1778 line_data[identifier]['strengths'].append(u'%s%s' % (med['amount'], med['unit'].strip()))
1779 line_data[identifier]['preparation'] = med['preparation']
1780 line_data[identifier]['schedule'] = gmTools.coalesce(med['schedule'], u'')
1781 if med['aim'] not in line_data[identifier]['aims']:
1782 line_data[identifier]['aims'].append(med['aim'])
1783
1784 # create lines
1785 already_seen = []
1786 lines = []
1787 line1_template = u'%s %s & %s \\\\'
1788 line2_template = u' & {\\scriptsize %s\\par} \\\\'
1789
1790 for med in current_meds:
1791 identifier = gmTools.coalesce(med['brand'], med['substance'])
1792
1793 if identifier in already_seen:
1794 continue
1795
1796 already_seen.append(identifier)
1797
1798 lines.append (line1_template % (
1799 line_data[identifier]['brand'],
1800 line_data[identifier]['preparation'],
1801 line_data[identifier]['schedule']
1802 ))
1803
1804 strengths = u'/'.join(line_data[identifier]['strengths'])
1805 if strengths == u'':
1806 template = u' & {\\scriptsize %s\\par} \\\\'
1807 for aim in line_data[identifier]['aims']:
1808 lines.append(template % aim)
1809 else:
1810 if len(line_data[identifier]['aims']) == 0:
1811 template = u'%s & \\\\'
1812 lines.append(template % strengths)
1813 else:
1814 template = u'%s & {\\scriptsize %s\\par} \\\\'
1815 lines.append(template % (strengths, line_data[identifier]['aims'][0]))
1816 template = u' & {\\scriptsize %s\\par} \\\\'
1817 for aim in line_data[identifier]['aims'][1:]:
1818 lines.append(template % aim)
1819
1820 lines.append(u'\\hline')
1821
1822 return tex % u' \n'.join(lines)
1823 #============================================================
1824 _SQL_get_drug_components = u'SELECT * FROM ref.v_drug_components WHERE %s'
1825
1827
1828 _cmd_fetch_payload = _SQL_get_drug_components % u'pk_component = %s'
1829 _cmds_store_payload = [
1830 u"""UPDATE ref.lnk_substance2brand SET
1831 fk_brand = %(pk_brand)s,
1832 fk_substance = %(pk_consumable_substance)s
1833 WHERE
1834 NOT EXISTS (
1835 SELECT 1
1836 FROM clin.substance_intake
1837 WHERE fk_drug_component = %(pk_component)s
1838 LIMIT 1
1839 )
1840 AND
1841 pk = %(pk_component)s
1842 AND
1843 xmin = %(xmin_lnk_substance2brand)s
1844 RETURNING
1845 xmin AS xmin_lnk_substance2brand
1846 """
1847 ]
1848 _updatable_fields = [
1849 u'pk_brand',
1850 u'pk_consumable_substance'
1851 ]
1852 #--------------------------------------------------------
1853 # properties
1854 #--------------------------------------------------------
1856 return cBrandedDrug(aPK_obj = self._payload[self._idx['pk_brand']])
1857
1858 containing_drug = property(_get_containing_drug, lambda x:x)
1859 #--------------------------------------------------------
1862
1863 is_in_use_by_patients = property(_get_is_in_use_by_patients, lambda x:x)
1864 #--------------------------------------------------------
1866 return cConsumableSubstance(aPK_obj = self._payload[self._idx['pk_consumable_substance']])
1867
1868 substance = property(_get_substance, lambda x:x)
1869 #------------------------------------------------------------
1871 cmd = _SQL_get_drug_components % u'true ORDER BY brand, substance'
1872 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = True)
1873 return [ cDrugComponent(row = {'data': r, 'idx': idx, 'pk_field': 'pk_component'}) for r in rows ]
1874 #------------------------------------------------------------
1876
1877 _pattern = regex.compile(r'^\D+\s*\d+$', regex.UNICODE | regex.LOCALE)
1878 _query_desc_only = u"""
1879 SELECT DISTINCT ON (component)
1880 pk_component,
1881 (substance || ' ' || amount || unit || ' ' || preparation || ' (' || brand || ')')
1882 AS component
1883 FROM ref.v_drug_components
1884 WHERE
1885 substance %(fragment_condition)s
1886 OR
1887 brand %(fragment_condition)s
1888 ORDER BY component
1889 LIMIT 50"""
1890 _query_desc_and_amount = u"""
1891
1892 SELECT DISTINCT ON (component)
1893 pk_component,
1894 (substance || ' ' || amount || unit || ' ' || preparation || ' (' || brand || ')')
1895 AS component
1896 FROM ref.v_drug_components
1897 WHERE
1898 %(fragment_condition)s
1899 ORDER BY component
1900 LIMIT 50"""
1901 #--------------------------------------------------------
1903 """Return matches for aFragment at start of phrases."""
1904
1905 if cDrugComponentMatchProvider._pattern.match(aFragment):
1906 self._queries = [cDrugComponentMatchProvider._query_desc_and_amount]
1907 fragment_condition = """(substance ILIKE %(desc)s OR brand ILIKE %(desc)s)
1908 AND
1909 amount::text ILIKE %(amount)s"""
1910 self._args['desc'] = u'%s%%' % regex.sub(r'\s*\d+$', u'', aFragment)
1911 self._args['amount'] = u'%s%%' % regex.sub(r'^\D+\s*', u'', aFragment)
1912 else:
1913 self._queries = [cDrugComponentMatchProvider._query_desc_only]
1914 fragment_condition = u"ILIKE %(fragment)s"
1915 self._args['fragment'] = u"%s%%" % aFragment
1916
1917 return self._find_matches(fragment_condition)
1918 #--------------------------------------------------------
1920 """Return matches for aFragment at start of words inside phrases."""
1921
1922 if cDrugComponentMatchProvider._pattern.match(aFragment):
1923 self._queries = [cDrugComponentMatchProvider._query_desc_and_amount]
1924
1925 desc = regex.sub(r'\s*\d+$', u'', aFragment)
1926 desc = gmPG2.sanitize_pg_regex(expression = desc, escape_all = False)
1927
1928 fragment_condition = """(substance ~* %(desc)s OR brand ~* %(desc)s)
1929 AND
1930 amount::text ILIKE %(amount)s"""
1931
1932 self._args['desc'] = u"( %s)|(^%s)" % (desc, desc)
1933 self._args['amount'] = u'%s%%' % regex.sub(r'^\D+\s*', u'', aFragment)
1934 else:
1935 self._queries = [cDrugComponentMatchProvider._query_desc_only]
1936 fragment_condition = u"~* %(fragment)s"
1937 aFragment = gmPG2.sanitize_pg_regex(expression = aFragment, escape_all = False)
1938 self._args['fragment'] = u"( %s)|(^%s)" % (aFragment, aFragment)
1939
1940 return self._find_matches(fragment_condition)
1941 #--------------------------------------------------------
1943 """Return matches for aFragment as a true substring."""
1944
1945 if cDrugComponentMatchProvider._pattern.match(aFragment):
1946 self._queries = [cDrugComponentMatchProvider._query_desc_and_amount]
1947 fragment_condition = """(substance ILIKE %(desc)s OR brand ILIKE %(desc)s)
1948 AND
1949 amount::text ILIKE %(amount)s"""
1950 self._args['desc'] = u'%%%s%%' % regex.sub(r'\s*\d+$', u'', aFragment)
1951 self._args['amount'] = u'%s%%' % regex.sub(r'^\D+\s*', u'', aFragment)
1952 else:
1953 self._queries = [cDrugComponentMatchProvider._query_desc_only]
1954 fragment_condition = u"ILIKE %(fragment)s"
1955 self._args['fragment'] = u"%%%s%%" % aFragment
1956
1957 return self._find_matches(fragment_condition)
1958
1959 #============================================================
1961 """Represents a drug as marketed by a manufacturer."""
1962
1963 _cmd_fetch_payload = u"SELECT * FROM ref.v_branded_drugs WHERE pk_brand = %s"
1964 _cmds_store_payload = [
1965 u"""UPDATE ref.branded_drug SET
1966 description = %(brand)s,
1967 preparation = %(preparation)s,
1968 atc_code = gm.nullify_empty_string(%(atc)s),
1969 external_code = gm.nullify_empty_string(%(external_code)s),
1970 external_code_type = gm.nullify_empty_string(%(external_code_type)s),
1971 is_fake = %(is_fake_brand)s,
1972 fk_data_source = %(pk_data_source)s
1973 WHERE
1974 pk = %(pk_brand)s
1975 AND
1976 xmin = %(xmin_branded_drug)s
1977 RETURNING
1978 xmin AS xmin_branded_drug
1979 """
1980 ]
1981 _updatable_fields = [
1982 u'brand',
1983 u'preparation',
1984 u'atc',
1985 u'is_fake_brand',
1986 u'external_code',
1987 u'external_code_type',
1988 u'pk_data_source'
1989 ]
1990 #--------------------------------------------------------
1992 success, data = super(self.__class__, self).save_payload(conn = conn)
1993
1994 if not success:
1995 return (success, data)
1996
1997 if self._payload[self._idx['atc']] is not None:
1998 atc = self._payload[self._idx['atc']].strip()
1999 if atc != u'':
2000 gmATC.propagate_atc (
2001 substance = self._payload[self._idx['brand']].strip(),
2002 atc = atc
2003 )
2004
2005 return (success, data)
2006 #--------------------------------------------------------
2008
2009 if self._payload[self._idx['is_in_use']]:
2010 return False
2011
2012 args = {'brand': self._payload[self._idx['pk_brand']]}
2013
2014 queries = [{'cmd': u"DELETE FROM ref.lnk_substance2brand WHERE fk_brand = %(brand)s", 'args': args}]
2015 cmd = u'INSERT INTO ref.lnk_substance2brand (fk_brand, fk_substance) VALUES (%%(brand)s, %s)'
2016 for s in substances:
2017 queries.append({'cmd': cmd % s['pk'], 'args': args})
2018
2019 gmPG2.run_rw_queries(queries = queries)
2020 self.refetch_payload()
2021
2022 return True
2023 #--------------------------------------------------------
2024 - def add_component(self, substance=None, atc=None, amount=None, unit=None, pk_substance=None):
2025
2026 args = {
2027 'brand': self.pk_obj,
2028 'subst': substance,
2029 'atc': atc,
2030 'pk_subst': pk_substance
2031 }
2032
2033 if pk_substance is None:
2034 consumable = create_consumable_substance(substance = substance, atc = atc, amount = amount, unit = unit)
2035 args['pk_subst'] = consumable['pk']
2036
2037 # already a component
2038 cmd = u"""
2039 SELECT pk_component
2040 FROM ref.v_drug_components
2041 WHERE
2042 pk_brand = %(brand)s
2043 AND
2044 ((
2045 (lower(substance) = lower(%(subst)s))
2046 OR
2047 (lower(atc_substance) = lower(%(atc)s))
2048 OR
2049 (pk_consumable_substance = %(pk_subst)s)
2050 ) IS TRUE)
2051 """
2052 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
2053
2054 if len(rows) > 0:
2055 return
2056
2057 # create it
2058 cmd = u"""
2059 INSERT INTO ref.lnk_substance2brand (fk_brand, fk_substance)
2060 VALUES (%(brand)s, %(pk_subst)s)
2061 """
2062 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
2063 self.refetch_payload()
2064 #------------------------------------------------------------
2066 if len(self._payload[self._idx['components']]) == 1:
2067 _log.error('cannot remove the only component of a drug')
2068 return False
2069
2070 args = {'brand': self.pk_obj, 'comp': substance}
2071 cmd = u"""
2072 DELETE FROM ref.lnk_substance2brand
2073 WHERE
2074 fk_brand = %(brand)s
2075 AND
2076 fk_substance = %(comp)s
2077 AND
2078 NOT EXISTS (
2079 SELECT 1
2080 FROM clin.substance_intake
2081 WHERE fk_drug_component = %(comp)s
2082 LIMIT 1
2083 )
2084 """
2085 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
2086 self.refetch_payload()
2087
2088 return True
2089 #--------------------------------------------------------
2090 # properties
2091 #--------------------------------------------------------
2093 if self._payload[self._idx['external_code']] is None:
2094 return None
2095
2096 return self._payload[self._idx['external_code']]
2097
2098 external_code = property(_get_external_code, lambda x:x)
2099 #--------------------------------------------------------
2101
2102 # FIXME: maybe evaluate fk_data_source ?
2103 if self._payload[self._idx['external_code_type']] is None:
2104 return None
2105
2106 return self._payload[self._idx['external_code_type']]
2107
2108 external_code_type = property(_get_external_code_type, lambda x:x)
2109 #--------------------------------------------------------
2111 cmd = _SQL_get_drug_components % u'pk_brand = %(brand)s'
2112 args = {'brand': self._payload[self._idx['pk_brand']]}
2113 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
2114 return [ cDrugComponent(row = {'data': r, 'idx': idx, 'pk_field': 'pk_component'}) for r in rows ]
2115
2116 components = property(_get_components, lambda x:x)
2117 #--------------------------------------------------------
2119 if self._payload[self._idx['pk_substances']] is None:
2120 return []
2121 cmd = _SQL_get_consumable_substance % u'pk IN %(pks)s'
2122 args = {'pks': tuple(self._payload[self._idx['pk_substances']])}
2123 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
2124 return [ cConsumableSubstance(row = {'data': r, 'idx': idx, 'pk_field': 'pk'}) for r in rows ]
2125
2126 components_as_substances = property(_get_components_as_substances, lambda x:x)
2127 #--------------------------------------------------------
2129 cmd = u'SELECT EXISTS (SELECT 1 FROM clin.vaccine WHERE fk_brand = %(fk_brand)s)'
2130 args = {'fk_brand': self._payload[self._idx['pk_brand']]}
2131 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
2132 return rows[0][0]
2133
2134 is_vaccine = property(_get_is_vaccine, lambda x:x)
2135 #------------------------------------------------------------
2137 cmd = u'SELECT pk FROM ref.branded_drug ORDER BY description'
2138 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = False)
2139 return [ cBrandedDrug(aPK_obj = r['pk']) for r in rows ]
2140 #------------------------------------------------------------
2142 args = {'brand': brand_name, 'prep': preparation}
2143
2144 cmd = u'SELECT pk FROM ref.branded_drug WHERE lower(description) = lower(%(brand)s) AND lower(preparation) = lower(%(prep)s)'
2145 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
2146
2147 if len(rows) == 0:
2148 return None
2149
2150 return cBrandedDrug(aPK_obj = rows[0]['pk'])
2151 #------------------------------------------------------------
2153
2154 if preparation is None:
2155 preparation = _('units')
2156
2157 if preparation.strip() == u'':
2158 preparation = _('units')
2159
2160 if return_existing:
2161 drug = get_drug_by_brand(brand_name = brand_name, preparation = preparation)
2162 if drug is not None:
2163 return drug
2164
2165 cmd = u'INSERT INTO ref.branded_drug (description, preparation) VALUES (%(brand)s, %(prep)s) RETURNING pk'
2166 args = {'brand': brand_name, 'prep': preparation}
2167 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True, get_col_idx = False)
2168
2169 return cBrandedDrug(aPK_obj = rows[0]['pk'])
2170 #------------------------------------------------------------
2172 queries = []
2173 args = {'pk': brand}
2174
2175 # delete components
2176 cmd = u"""
2177 DELETE FROM ref.lnk_substance2brand
2178 WHERE
2179 fk_brand = %(pk)s
2180 AND
2181 NOT EXISTS (
2182 SELECT 1
2183 FROM clin.v_pat_substance_intake
2184 WHERE pk_brand = %(pk)s
2185 LIMIT 1
2186 )
2187 """
2188 queries.append({'cmd': cmd, 'args': args})
2189
2190 # delete drug
2191 cmd = u"""
2192 DELETE FROM ref.branded_drug
2193 WHERE
2194 pk = %(pk)s
2195 AND
2196 NOT EXISTS (
2197 SELECT 1
2198 FROM clin.v_pat_substance_intake
2199 WHERE pk_brand = %(pk)s
2200 LIMIT 1
2201 )
2202 """
2203 queries.append({'cmd': cmd, 'args': args})
2204
2205 gmPG2.run_rw_queries(queries = queries)
2206 #============================================================
2207 # main
2208 #------------------------------------------------------------
2209 if __name__ == "__main__":
2210
2211 if len(sys.argv) < 2:
2212 sys.exit()
2213
2214 if sys.argv[1] != 'test':
2215 sys.exit()
2216
2217 from Gnumed.pycommon import gmLog2
2218 from Gnumed.pycommon import gmI18N
2219 from Gnumed.business import gmPerson
2220
2221 gmI18N.activate_locale()
2222 # gmDateTime.init()
2223 #--------------------------------------------------------
2225 mmi = cGelbeListeWineInterface()
2226 print mmi
2227 print "interface definition:", mmi.version
2228 print "database versions: ", mmi.get_data_source_version()
2229 #--------------------------------------------------------
2231 mmi_file = cGelbeListeCSVFile(filename = sys.argv[2])
2232 for drug in mmi_file:
2233 print "-------------"
2234 print '"%s" (ATC: %s / PZN: %s)' % (drug['name'], drug['atc'], drug['pzn'])
2235 for stoff in drug['wirkstoffe']:
2236 print " Wirkstoff:", stoff
2237 raw_input()
2238 if mmi_file.has_unknown_fields is not None:
2239 print "has extra data under [%s]" % gmTools.default_csv_reader_rest_key
2240 for key in mmi_file.csv_fieldnames:
2241 print key, '->', drug[key]
2242 raw_input()
2243 mmi_file.close()
2244 #--------------------------------------------------------
2248 #--------------------------------------------------------
2250 mmi = cGelbeListeWineInterface()
2251 mmi_file = mmi.__let_user_select_drugs()
2252 for drug in mmi_file:
2253 print "-------------"
2254 print '"%s" (ATC: %s / PZN: %s)' % (drug['name'], drug['atc'], drug['pzn'])
2255 for stoff in drug['wirkstoffe']:
2256 print " Wirkstoff:", stoff
2257 print drug
2258 mmi_file.close()
2259 #--------------------------------------------------------
2263 #--------------------------------------------------------
2265 mmi = cGelbeListeInterface()
2266 print mmi
2267 print "interface definition:", mmi.version
2268 # Metoprolol + Hct vs Citalopram
2269 diclofenac = '7587712'
2270 phenprocoumon = '4421744'
2271 mmi.check_interactions(drug_ids_list = [diclofenac, phenprocoumon])
2272 #--------------------------------------------------------
2273 # FreeDiams
2274 #--------------------------------------------------------
2276 gmPerson.set_active_patient(patient = gmPerson.cIdentity(aPK_obj = 12))
2277 fd = cFreeDiamsInterface()
2278 fd.patient = gmPerson.gmCurrentPatient()
2279 # fd.switch_to_frontend(blocking = True)
2280 fd.import_fd2gm_file_as_drugs(filename = sys.argv[2])
2281 #--------------------------------------------------------
2283 gmPerson.set_active_patient(patient = gmPerson.cIdentity(aPK_obj = 12))
2284 fd = cFreeDiamsInterface()
2285 fd.patient = gmPerson.gmCurrentPatient()
2286 fd.check_interactions(substances = fd.patient.get_emr().get_current_substance_intake(include_unapproved = True))
2287 #--------------------------------------------------------
2288 # generic
2289 #--------------------------------------------------------
2291 drug = create_substance_intake (
2292 pk_component = 2,
2293 encounter = 1,
2294 episode = 1
2295 )
2296 print drug
2297 #--------------------------------------------------------
2302 #--------------------------------------------------------
2306 #--------------------------------------------------------
2307 #--------------------------------------------------------
2308 # MMI/Gelbe Liste
2309 #test_MMI_interface()
2310 #test_MMI_file()
2311 #test_mmi_switch_to()
2312 #test_mmi_let_user_select_drugs()
2313 #test_mmi_import_substances()
2314 #test_mmi_import_drugs()
2315
2316 # FreeDiams
2317 test_fd_switch_to()
2318 #test_fd_show_interactions()
2319
2320 # generic
2321 #test_interaction_check()
2322 #test_create_substance_intake()
2323 #test_show_components()
2324 #test_get_consumable_substances()
2325 #============================================================
2326
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Thu May 19 03:59:08 2011 | http://epydoc.sourceforge.net |