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