| 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:\programs\freediams\freediams.exe',
411 r'freediams.exe'
412 ])
413
414 if found:
415 self.path_to_binary = cmd
416 return True
417
418 try:
419 self.custom_path_to_binary
420 except AttributeError:
421 _log.error('cannot find FreeDiams binary, no custom path set')
422 return False
423
424 if self.custom_path_to_binary is None:
425 _log.error('cannot find FreeDiams binary')
426 return False
427
428 found, cmd = gmShellAPI.detect_external_binary(binary = self.custom_path_to_binary)
429 if found:
430 self.path_to_binary = cmd
431 return True
432
433 _log.error('cannot find FreeDiams binary')
434 return False
435 #--------------------------------------------------------
437
438 if self.patient is None:
439 _log.debug('cannot export latest FreeDiams prescriptions w/o patient')
440 return False
441
442 docs = self.patient.get_document_folder()
443 prescription = docs.get_latest_freediams_prescription()
444 if prescription is None:
445 _log.debug('no FreeDiams prescription available')
446 return False
447
448 for part in prescription.parts:
449 if part['filename'] == u'freediams-prescription.xml':
450 if part.export_to_file(filename = self.__fd2gm_filename) is not None:
451 return True
452
453 _log.error('cannot export latest FreeDiams prescription to XML file')
454
455 return False
456 #--------------------------------------------------------
458 """FreeDiams calls this exchange-out or prescription file.
459
460 CIS stands for Unique Speciality Identifier (eg bisoprolol 5 mg, gel).
461 CIS is AFSSAPS specific, but pharmacist can retreive drug name with the CIS.
462 AFSSAPS is the French FDA.
463
464 CIP stands for Unique Presentation Identifier (eg 30 pills plaq)
465 CIP if you want to specify the packaging of the drug (30 pills
466 thermoformed tablet...) -- actually not really usefull for french
467 doctors.
468 # .external_code_type: u'FR-CIS'
469 # .external_cod: the CIS value
470
471 OnlyForTest:
472 OnlyForTest drugs will be processed by the IA Engine but
473 not printed (regardless of FreeDiams mode). They are shown
474 in gray in the prescription view.
475
476 Select-only is a mode where FreeDiams creates a list of drugs
477 not a full prescription. In this list, users can add ForTestOnly
478 drug if they want to
479 1. print the list without some drugs
480 2. but including these drugs in the IA engine calculation
481
482 Select-Only mode does not have any relation with the ForTestOnly drugs.
483
484 IsTextual:
485 What is the use and significance of the
486 <IsTextual>true/false</IsTextual>
487 flag when both <DrugName> and <TextualDrugName> exist ?
488
489 This tag must be setted even if it sounds like a duplicated
490 data. This tag is needed inside FreeDiams code.
491
492 INN:
493 GNUmed will pass the substance in <TextualDrugName
494 and will also pass <INN>True</INN>.
495
496 Eric: Nop, this is not usefull because pure textual drugs
497 are not processed but just shown.
498 """
499 # virginize file
500 open(self.__fd2gm_filename, 'wb').close()
501
502 # make sure we've got something to do
503 if substance_intakes is None:
504 if self.patient is None:
505 _log.warning('cannot create prescription file because there is neither a patient nor a substance intake list')
506 # do fail because __export_latest_prescription() should not have been called without patient
507 return False
508 emr = self.patient.get_emr()
509 substance_intakes = emr.get_current_substance_intake (
510 include_inactive = False,
511 include_unapproved = True
512 )
513
514 drug_snippets = []
515
516 # process FD drugs
517 fd_intakes = [ i for i in substance_intakes if (
518 (i['intake_is_approved_of'] is True)
519 and
520 (i['external_code_type_brand'] is not None)
521 and
522 (i['external_code_type_brand'].startswith(u'FreeDiams::'))
523 )]
524
525 intakes_pooled_by_brand = {}
526 for intake in fd_intakes:
527 # this will leave only one entry per brand
528 # but FreeDiams knows the components ...
529 intakes_pooled_by_brand[intake['brand']] = intake
530 del fd_intakes
531
532 drug_snippet = u"""<Prescription>
533 <IsTextual>False</IsTextual>
534 <DrugName>%s</DrugName>
535 <Drug_UID>%s</Drug_UID>
536 <Drug_UID_type>%s</Drug_UID_type> <!-- not yet supported by FreeDiams -->
537 </Prescription>"""
538
539 last_db_id = u'CA_HCDPD'
540 for intake in intakes_pooled_by_brand.values():
541 last_db_id = gmTools.xml_escape_string(text = intake['external_code_type_brand'].replace(u'FreeDiams::', u'').split(u'::')[0])
542 drug_snippets.append(drug_snippet % (
543 gmTools.xml_escape_string(text = intake['brand'].strip()),
544 gmTools.xml_escape_string(text = intake['external_code_brand'].strip()),
545 last_db_id
546 ))
547
548 # process non-FD drugs
549 non_fd_intakes = [ i for i in substance_intakes if (
550 (i['intake_is_approved_of'] is True)
551 and (
552 (i['external_code_type_brand'] is None)
553 or
554 (not i['external_code_type_brand'].startswith(u'FreeDiams::'))
555 )
556 )]
557
558 non_fd_brand_intakes = [ i for i in non_fd_intakes if i['brand'] is not None ]
559 non_fd_substance_intakes = [ i for i in non_fd_intakes if i['brand'] is None ]
560 del non_fd_intakes
561
562 drug_snippet = u"""<Prescription>
563 <IsTextual>True</IsTextual>
564 <TextualDrugName>%s</TextualDrugName>
565 </Prescription>"""
566
567 for intake in non_fd_substance_intakes:
568 drug_name = u'%s %s%s (%s)%s' % (
569 intake['substance'],
570 intake['amount'],
571 intake['unit'],
572 intake['preparation'],
573 gmTools.coalesce(intake['schedule'], u'', _('\n Take: %s'))
574 )
575 drug_snippets.append(drug_snippet % gmTools.xml_escape_string(text = drug_name.strip()))
576
577 intakes_pooled_by_brand = {}
578 for intake in non_fd_brand_intakes:
579 brand = u'%s %s' % (intake['brand'], intake['preparation'])
580 try:
581 intakes_pooled_by_brand[brand].append(intake)
582 except KeyError:
583 intakes_pooled_by_brand[brand] = [intake]
584
585 for brand, comps in intakes_pooled_by_brand.iteritems():
586 drug_name = u'%s\n' % brand
587 for comp in comps:
588 drug_name += u' %s %s%s\n' % (
589 comp['substance'],
590 comp['amount'],
591 comp['unit']
592 )
593 if comps[0]['schedule'] is not None:
594 drug_name += gmTools.coalesce(comps[0]['schedule'], u'', _('Take: %s'))
595 drug_snippets.append(drug_snippet % gmTools.xml_escape_string(text = drug_name.strip()))
596
597 # assemble XML file
598 xml = u"""<?xml version = "1.0" encoding = "UTF-8"?>
599
600 <FreeDiams>
601 <DrugsDatabaseName>%s</DrugsDatabaseName>
602 <FullPrescription version="0.5.0">
603
604 %s
605
606 </FullPrescription>
607 </FreeDiams>
608 """
609
610 xml_file = codecs.open(self.__fd2gm_filename, 'wb', 'utf8')
611 xml_file.write(xml % (
612 last_db_id,
613 u'\n\t\t'.join(drug_snippets)
614 ))
615 xml_file.close()
616
617 return True
618 #--------------------------------------------------------
620
621 if mode == 'interactions':
622 mode = u'select-only'
623 elif mode == 'prescription':
624 mode = u'prescriber'
625 else:
626 mode = u'select-only'
627
628 xml_file = codecs.open(self.__gm2fd_filename, 'wb', 'utf8')
629
630 xml = u"""<?xml version="1.0" encoding="UTF-8"?>
631
632 <FreeDiams_In version="0.5.0">
633 <EMR name="GNUmed" uid="unused"/>
634 <ConfigFile value="%s"/>
635 <ExchangeOut value="%s" format="xml"/>
636 <!-- <DrugsDatabase uid="can be set to a specific DB"/> -->
637 <Ui editmode="%s" blockPatientDatas="1"/>
638 %%s
639 </FreeDiams_In>
640
641 <!--
642 # FIXME: search by LOINC code and add (as soon as supported by FreeDiams ...)
643 <Creatinine value="12" unit="mg/l or mmol/l"/>
644 <Weight value="70" unit="kg or pd" />
645 <Height value="170" unit="cm or "/>
646 <ICD10 value="J11.0;A22;Z23"/>
647 -->
648 """ % (
649 self.__fd4gm_config_file,
650 self.__fd2gm_filename,
651 mode
652 )
653
654 if self.patient is None:
655 xml_file.write(xml % u'')
656 xml_file.close()
657 return
658
659 name = self.patient.get_active_name()
660 if self.patient['dob'] is None:
661 dob = u''
662 else:
663 dob = self.patient['dob'].strftime(cFreeDiamsInterface.default_dob_format)
664
665 emr = self.patient.get_emr()
666 allgs = emr.get_allergies()
667 atc_allgs = [
668 a['atc_code'] for a in allgs if ((a['atc_code'] is not None) and (a['type'] == u'allergy'))
669 ]
670 atc_sens = [
671 a['atc_code'] for a in allgs if ((a['atc_code'] is not None) and (a['type'] == u'sensitivity'))
672 ]
673 inn_allgs = [ a['allergene'] for a in allgs if a['type'] == u'allergy' ]
674 inn_sens = [ a['allergene'] for a in allgs if a['type'] == u'sensitivity' ]
675 # this is rather fragile: FreeDiams won't know what type of UID this is
676 # (but it will assume it is of the type of the drug database in use)
677 uid_allgs = [
678 a['substance_code'] for a in allgs if ((a['substance_code'] is not None) and (a['type'] == u'allergy'))
679 ]
680 uid_sens = [
681 a['substance_code'] for a in allgs if ((a['substance_code'] is not None) and (a['type'] == u'sensitivity'))
682 ]
683
684 patient_xml = u"""<Patient>
685 <Identity
686 lastnames="%s"
687 firstnames="%s"
688 uid="%s"
689 dob="%s"
690 gender="%s"
691 />
692 <ATCAllergies value="%s"/>
693 <ATCIntolerances value="%s"/>
694
695 <InnAllergies value="%s"/>
696 <InnIntolerances value="%s"/>
697
698 <DrugsUidAllergies value="%s"/>
699 <DrugsUidIntolerances value="%s"/>
700 </Patient>
701 """ % (
702 gmTools.xml_escape_string(text = name['lastnames']),
703 gmTools.xml_escape_string(text = name['firstnames']),
704 self.patient.ID,
705 dob,
706 cFreeDiamsInterface.map_gender2mf[self.patient['gender']],
707 gmTools.xml_escape_string(text = u';'.join(atc_allgs)),
708 gmTools.xml_escape_string(text = u';'.join(atc_sens)),
709 gmTools.xml_escape_string(text = u';'.join(inn_allgs)),
710 gmTools.xml_escape_string(text = u';'.join(inn_sens)),
711 gmTools.xml_escape_string(text = u';'.join(uid_allgs)),
712 gmTools.xml_escape_string(text = u';'.join(uid_sens))
713 )
714
715 xml_file.write(xml % patient_xml)
716 xml_file.close()
717 #--------------------------------------------------------
719
720 if filename is None:
721 filename = self.__fd2gm_filename
722
723 fd2gm_xml = etree.ElementTree()
724 fd2gm_xml.parse(filename)
725
726 pdfs = fd2gm_xml.findall('ExtraDatas/Printed')
727 if len(pdfs) == 0:
728 return
729
730 fd_filenames = []
731 for pdf in pdfs:
732 fd_filenames.append(pdf.attrib['file'])
733
734 docs = self.patient.get_document_folder()
735 emr = self.patient.get_emr()
736
737 prescription = docs.add_document (
738 document_type = create_document_type (
739 document_type = DOCUMENT_TYPE_PRESCRIPTION
740 )['pk_doc_type'],
741 encounter = emr.active_encounter['pk_encounter'],
742 episode = emr.add_episode (
743 episode_name = DEFAULT_MEDICATION_HISTORY_EPISODE,
744 is_open = False
745 )['pk_episode']
746 )
747 prescription['ext_ref'] = u'FreeDiams'
748 prescription.save()
749 fd_filenames.append(filename)
750 success, msg, parts = prescription.add_parts_from_files (
751 files = fd_filenames,
752 reviewer = self.reviewer['pk_staff']
753 )
754
755 if not success:
756 _log.error(msg)
757 return
758
759 xml_part = parts[-1]
760 xml_part['filename'] = u'freediams-prescription.xml'
761 xml_part.save()
762 #--------------------------------------------------------
764 """
765 If returning textual prescriptions (say, drugs which FreeDiams
766 did not know) then "IsTextual" will be True and UID will be -1.
767 """
768 if filename is None:
769 filename = self.__fd2gm_filename
770
771 # FIXME: do not import IsTextual drugs, or rather, make that configurable
772
773 fd2gm_xml = etree.ElementTree()
774 fd2gm_xml.parse(filename)
775
776 data_src_pk = self.create_data_source_entry()
777
778 db_def = fd2gm_xml.find('DrugsDatabaseName')
779 db_id = db_def.text.strip()
780 drug_id_name = db_def.attrib['drugUidName']
781 fd_xml_drug_entries = fd2gm_xml.findall('FullPrescription/Prescription')
782
783 self.__imported_drugs = []
784 for fd_xml_drug in fd_xml_drug_entries:
785 drug_uid = fd_xml_drug.find('Drug_UID').text.strip()
786 if drug_uid == u'-1':
787 _log.debug('skipping textual drug')
788 continue # it's a TextualDrug, skip it
789 drug_name = fd_xml_drug.find('DrugName').text.replace(', )', ')').strip()
790 drug_form = fd_xml_drug.find('DrugForm').text.strip()
791 drug_atc = fd_xml_drug.find('DrugATC')
792 if drug_atc is None:
793 drug_atc = u''
794 else:
795 drug_atc = drug_atc.text.strip()
796
797 # create new branded drug
798 new_drug = create_branded_drug(brand_name = drug_name, preparation = drug_form, return_existing = True)
799 self.__imported_drugs.append(new_drug)
800 new_drug['is_fake_brand'] = False
801 new_drug['atc'] = drug_atc
802 new_drug['external_code_type'] = u'FreeDiams::%s::%s' % (db_id, drug_id_name)
803 new_drug['external_code'] = drug_uid
804 new_drug['pk_data_source'] = data_src_pk
805 new_drug.save()
806
807 # parse XML for composition records
808 fd_xml_components = fd_xml_drug.getiterator('Composition')
809 comp_data = {}
810 for fd_xml_comp in fd_xml_components:
811
812 data = {}
813
814 amount = regex.match(r'\d+[.,]{0,1}\d*', fd_xml_comp.attrib['strenght'].strip()) # sic, typo
815 if amount is None:
816 amount = 99999
817 else:
818 amount = amount.group()
819 data['amount'] = amount
820
821 unit = regex.sub(r'\d+[.,]{0,1}\d*', u'', fd_xml_comp.attrib['strenght'].strip()).strip() # sic, typo
822 if unit == u'':
823 unit = u'*?*'
824 data['unit'] = unit
825
826 molecule_name = fd_xml_comp.attrib['molecularName'].strip()
827 if molecule_name != u'':
828 create_consumable_substance(substance = molecule_name, atc = None, amount = amount, unit = unit)
829 data['molecule_name'] = molecule_name
830
831 inn_name = fd_xml_comp.attrib['inn'].strip()
832 if inn_name != u'':
833 create_consumable_substance(substance = inn_name, atc = None, amount = amount, unit = unit)
834 data['inn_name'] = molecule_name
835
836 if molecule_name == u'':
837 data['substance'] = inn_name
838 _log.info('linking INN [%s] rather than molecularName as component', inn_name)
839 else:
840 data['substance'] = molecule_name
841
842 data['nature'] = fd_xml_comp.attrib['nature'].strip()
843 data['nature_ID'] = fd_xml_comp.attrib['natureLink'].strip()
844
845 # merge composition records of SA/FT nature
846 try:
847 old_data = comp_data[data['nature_ID']]
848 # normalize INN
849 if old_data['inn_name'] == u'':
850 old_data['inn_name'] = data['inn_name']
851 if data['inn_name'] == u'':
852 data['inn_name'] = old_data['inn_name']
853 # normalize molecule
854 if old_data['molecule_name'] == u'':
855 old_data['molecule_name'] = data['molecule_name']
856 if data['molecule_name'] == u'':
857 data['molecule_name'] = old_data['molecule_name']
858 # FT: transformed form
859 # SA: active substance
860 # it would be preferable to use the SA record because that's what's *actually*
861 # contained in the drug, however FreeDiams does not list the amount thereof
862 # (rather that of the INN)
863 if data['nature'] == u'FT':
864 comp_data[data['nature_ID']] = data
865 else:
866 comp_data[data['nature_ID']] = old_data
867
868 # or create new record
869 except KeyError:
870 comp_data[data['nature_ID']] = data
871
872 # actually create components from (possibly merged) composition records
873 for key, data in comp_data.items():
874 new_drug.add_component (
875 substance = data['substance'],
876 atc = None,
877 amount = data['amount'],
878 unit = data['unit']
879 )
880 #============================================================
882 """Support v8.2 CSV file interface only."""
883
884 version = u'Gelbe Liste/MMI v8.2 interface'
885 default_encoding = 'cp1250'
886 bdt_line_template = u'%03d6210#%s\r\n' # Medikament verordnet auf Kassenrezept
887 bdt_line_base_length = 8
888 #--------------------------------------------------------
890
891 cDrugDataSourceInterface.__init__(self)
892
893 _log.info(u'%s (native Windows)', cGelbeListeWindowsInterface.version)
894
895 self.path_to_binary = r'C:\Programme\MMI PHARMINDEX\glwin.exe'
896 self.args = r'-KEEPBACKGROUND -PRESCRIPTIONFILE %s -CLOSETOTRAY'
897
898 paths = gmTools.gmPaths()
899
900 self.default_csv_filename = os.path.join(paths.home_dir, '.gnumed', 'tmp', 'rezept.txt')
901 self.default_csv_filename_arg = os.path.join(paths.home_dir, '.gnumed', 'tmp')
902 self.interactions_filename = os.path.join(paths.home_dir, '.gnumed', 'tmp', 'gm2mmi.bdt')
903 self.data_date_filename = r'C:\Programme\MMI PHARMINDEX\datadate.txt'
904
905 self.__data_date = None
906 self.__online_update_date = None
907
908 # use adjusted config.dat
909 #--------------------------------------------------------
911
912 if self.__data_date is not None:
913 if not force_reload:
914 return {
915 'data': self.__data_date,
916 'online_update': self.__online_update_date
917 }
918
919 open(self.data_date_filename, 'wb').close()
920
921 cmd = u'%s -DATADATE' % self.path_to_binary
922 if not gmShellAPI.run_command_in_shell(command = cmd, blocking = True):
923 _log.error('problem querying the MMI drug database for version information')
924 self.__data_date = None
925 self.__online_update_date = None
926 return {
927 'data': u'?',
928 'online_update': u'?'
929 }
930
931 try:
932 version_file = open(self.data_date_filename, 'rU')
933 except StandardError:
934 _log.error('problem querying the MMI drug database for version information')
935 _log.exception('cannot open MMI drug database version file [%s]', self.data_date_filename)
936 self.__data_date = None
937 self.__online_update_date = None
938 return {
939 'data': u'?',
940 'online_update': u'?'
941 }
942
943 self.__data_date = version_file.readline()[:10]
944 self.__online_update_date = version_file.readline()[:10]
945 version_file.close()
946
947 return {
948 'data': self.__data_date,
949 'online_update': self.__online_update_date
950 }
951 #--------------------------------------------------------
953 versions = self.get_data_source_version()
954
955 return create_data_source (
956 long_name = u'Medikamentendatenbank "mmi PHARMINDEX" (Gelbe Liste)',
957 short_name = u'GL/MMI',
958 version = u'Daten: %s, Preise (Onlineupdate): %s' % (versions['data'], versions['online_update']),
959 source = u'Medizinische Medien Informations GmbH, Am Forsthaus Gravenbruch 7, 63263 Neu-Isenburg',
960 language = u'de'
961 )
962 #--------------------------------------------------------
964
965 # must make sure csv file exists
966 open(self.default_csv_filename, 'wb').close()
967
968 if cmd is None:
969 cmd = (u'%s %s' % (self.path_to_binary, self.args)) % self.default_csv_filename_arg
970
971 if not gmShellAPI.run_command_in_shell(command = cmd, blocking = blocking):
972 _log.error('problem switching to the MMI drug database')
973 # apparently on the first call MMI does not
974 # consistently return 0 on success
975 # return False
976
977 return True
978 #--------------------------------------------------------
980
981 # better to clean up interactions file
982 open(self.interactions_filename, 'wb').close()
983
984 if not self.switch_to_frontend(blocking = True):
985 return None
986
987 return cGelbeListeCSVFile(filename = self.default_csv_filename)
988 #--------------------------------------------------------
990
991 selected_drugs = self.__let_user_select_drugs()
992 if selected_drugs is None:
993 return None
994
995 new_substances = []
996
997 for drug in selected_drugs:
998 atc = None # hopefully MMI eventually supports atc-per-substance in a drug...
999 if len(drug['wirkstoffe']) == 1:
1000 atc = drug['atc']
1001 for wirkstoff in drug['wirkstoffe']:
1002 new_substances.append(create_consumable_substance(substance = wirkstoff, atc = atc, amount = amount, unit = unit))
1003
1004 selected_drugs.close()
1005
1006 return new_substances
1007 #--------------------------------------------------------
1009
1010 selected_drugs = self.__let_user_select_drugs()
1011 if selected_drugs is None:
1012 return None
1013
1014 data_src_pk = self.create_data_source_entry()
1015
1016 new_drugs = []
1017 new_substances = []
1018
1019 for entry in selected_drugs:
1020
1021 _log.debug('importing drug: %s %s', entry['name'], entry['darreichungsform'])
1022
1023 if entry[u'hilfsmittel']:
1024 _log.debug('skipping Hilfsmittel')
1025 continue
1026
1027 if entry[u'erstattbares_medizinprodukt']:
1028 _log.debug('skipping sonstiges Medizinprodukt')
1029 continue
1030
1031 # create branded drug (or get it if it already exists)
1032 drug = create_branded_drug(brand_name = entry['name'], preparation = entry['darreichungsform'])
1033 if drug is None:
1034 drug = get_drug_by_brand(brand_name = entry['name'], preparation = entry['darreichungsform'])
1035 new_drugs.append(drug)
1036
1037 # update fields
1038 drug['is_fake'] = False
1039 drug['atc_code'] = entry['atc']
1040 drug['external_code_type'] = u'DE-PZN'
1041 drug['external_code'] = entry['pzn']
1042 drug['fk_data_source'] = data_src_pk
1043 drug.save()
1044
1045 # add components to brand
1046 atc = None # hopefully MMI eventually supports atc-per-substance in a drug...
1047 if len(entry['wirkstoffe']) == 1:
1048 atc = entry['atc']
1049 for wirkstoff in entry['wirkstoffe']:
1050 drug.add_component(substance = wirkstoff, atc = atc)
1051
1052 # create as consumable substances, too
1053 atc = None # hopefully MMI eventually supports atc-per-substance in a drug...
1054 if len(entry['wirkstoffe']) == 1:
1055 atc = entry['atc']
1056 for wirkstoff in entry['wirkstoffe']:
1057 new_substances.append(create_consumable_substance(substance = wirkstoff, atc = atc, amount = amount, unit = unit))
1058
1059 return new_drugs, new_substances
1060 #--------------------------------------------------------
1062 """For this to work the BDT interaction check must be configured in the MMI."""
1063
1064 if drug_ids_list is None:
1065 if substances is None:
1066 return
1067 if len(substances) < 2:
1068 return
1069 drug_ids_list = [ (s.external_code_type, s.external_code) for s in substances ]
1070 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')]
1071
1072 else:
1073 if len(drug_ids_list) < 2:
1074 return
1075
1076 if drug_ids_list < 2:
1077 return
1078
1079 bdt_file = codecs.open(filename = self.interactions_filename, mode = 'wb', encoding = cGelbeListeWindowsInterface.default_encoding)
1080
1081 for pzn in drug_ids_list:
1082 pzn = pzn.strip()
1083 lng = cGelbeListeWindowsInterface.bdt_line_base_length + len(pzn)
1084 bdt_file.write(cGelbeListeWindowsInterface.bdt_line_template % (lng, pzn))
1085
1086 bdt_file.close()
1087
1088 self.switch_to_frontend(blocking = False)
1089 #--------------------------------------------------------
1091 self.switch_to_frontend(blocking = True)
1092 #--------------------------------------------------------
1094
1095 cmd = None
1096
1097 if substance.external_code_type == u'DE-PZN':
1098 cmd = u'%s -PZN %s' % (self.path_to_binary, substance.external_code)
1099
1100 if cmd is None:
1101 name = gmTools.coalesce (
1102 substance['brand'],
1103 substance['substance']
1104 )
1105 cmd = u'%s -NAME %s' % (self.path_to_binary, name)
1106
1107 # better to clean up interactions file
1108 open(self.interactions_filename, 'wb').close()
1109
1110 self.switch_to_frontend(cmd = cmd)
1111 #============================================================
1113
1115 cGelbeListeWindowsInterface.__init__(self)
1116
1117 _log.info(u'%s (WINE extension)', cGelbeListeWindowsInterface.version)
1118
1119 # FIXME: if -CLOSETOTRAY is used GNUmed cannot detect the end of MMI
1120 self.path_to_binary = r'wine "C:\Programme\MMI PHARMINDEX\glwin.exe"'
1121 self.args = r'"-PRESCRIPTIONFILE %s -KEEPBACKGROUND"'
1122
1123 paths = gmTools.gmPaths()
1124
1125 self.default_csv_filename = os.path.join(paths.home_dir, '.wine', 'drive_c', 'windows', 'temp', 'mmi2gm.csv')
1126 self.default_csv_filename_arg = r'c:\windows\temp\mmi2gm.csv'
1127 self.interactions_filename = os.path.join(paths.home_dir, '.wine', 'drive_c', 'windows', 'temp', 'gm2mmi.bdt')
1128 self.data_date_filename = os.path.join(paths.home_dir, '.wine', 'drive_c', 'Programme', 'MMI PHARMINDEX', 'datadate.txt')
1129 #============================================================
1131 """empirical CSV interface"""
1132
1135
1137
1138 try:
1139 csv_file = open(filename, 'rb') # FIXME: encoding ?
1140 except:
1141 _log.exception('cannot access [%s]', filename)
1142 csv_file = None
1143
1144 field_names = u'PZN Handelsname Form Abpackungsmenge Einheit Preis1 Hersteller Preis2 rezeptpflichtig Festbetrag Packungszahl Packungsgr\xf6\xdfe'.split()
1145
1146 if csv_file is None:
1147 return False
1148
1149 csv_lines = csv.DictReader (
1150 csv_file,
1151 fieldnames = field_names,
1152 delimiter = ';'
1153 )
1154
1155 for line in csv_lines:
1156 print "--------------------------------------------------------------------"[:31]
1157 for key in field_names:
1158 tmp = ('%s ' % key)[:30]
1159 print '%s: %s' % (tmp, line[key])
1160
1161 csv_file.close()
1162
1163 # narr = u'%sx %s %s %s (\u2258 %s %s) von %s (%s)' % (
1164 # line['Packungszahl'].strip(),
1165 # line['Handelsname'].strip(),
1166 # line['Form'].strip(),
1167 # line[u'Packungsgr\xf6\xdfe'].strip(),
1168 # line['Abpackungsmenge'].strip(),
1169 # line['Einheit'].strip(),
1170 # line['Hersteller'].strip(),
1171 # line['PZN'].strip()
1172 # )
1173 #============================================================
1174 drug_data_source_interfaces = {
1175 'Deutschland: Gelbe Liste/MMI (Windows)': cGelbeListeWindowsInterface,
1176 'Deutschland: Gelbe Liste/MMI (WINE)': cGelbeListeWineInterface,
1177 'FreeDiams (FR, US, CA, ZA)': cFreeDiamsInterface
1178 }
1179
1180 #============================================================
1181 #============================================================
1182 # substances in use across all patients
1183 #------------------------------------------------------------
1184 _SQL_get_consumable_substance = u"""
1185 SELECT *, xmin
1186 FROM ref.consumable_substance
1187 WHERE %s
1188 """
1189
1191
1192 _cmd_fetch_payload = _SQL_get_consumable_substance % u"pk = %s"
1193 _cmds_store_payload = [
1194 u"""UPDATE ref.consumable_substance SET
1195 description = %(description)s,
1196 atc_code = gm.nullify_empty_string(%(atc_code)s),
1197 amount = %(amount)s,
1198 unit = gm.nullify_empty_string(%(unit)s)
1199 WHERE
1200 pk = %(pk)s
1201 AND
1202 xmin = %(xmin)s
1203 AND
1204 -- must not currently be used with a patient directly
1205 NOT EXISTS (
1206 SELECT 1
1207 FROM clin.substance_intake
1208 WHERE
1209 fk_drug_component IS NULL
1210 AND
1211 fk_substance = %(pk)s
1212 LIMIT 1
1213 )
1214 AND
1215 -- must not currently be used with a patient indirectly, either
1216 NOT EXISTS (
1217 SELECT 1
1218 FROM clin.substance_intake
1219 WHERE
1220 fk_drug_component IS NOT NULL
1221 AND
1222 fk_drug_component = (
1223 SELECT r_ls2b.pk
1224 FROM ref.lnk_substance2brand r_ls2b
1225 WHERE fk_substance = %(pk)s
1226 )
1227 LIMIT 1
1228 )
1229 -- -- must not currently be used with a branded drug
1230 -- -- (but this would make it rather hard fixing branded drugs which contain only this substance)
1231 -- NOT EXISTS (
1232 -- SELECT 1
1233 -- FROM ref.lnk_substance2brand
1234 -- WHERE fk_substance = %(pk)s
1235 -- LIMIT 1
1236 -- )
1237 RETURNING
1238 xmin
1239 """
1240 ]
1241 _updatable_fields = [
1242 u'description',
1243 u'atc_code',
1244 u'amount',
1245 u'unit'
1246 ]
1247 #--------------------------------------------------------
1249 success, data = super(self.__class__, self).save_payload(conn = conn)
1250
1251 if not success:
1252 return (success, data)
1253
1254 if self._payload[self._idx['atc_code']] is not None:
1255 atc = self._payload[self._idx['atc_code']].strip()
1256 if atc != u'':
1257 gmATC.propagate_atc (
1258 substance = self._payload[self._idx['description']].strip(),
1259 atc = atc
1260 )
1261
1262 return (success, data)
1263 #--------------------------------------------------------
1264 # properties
1265 #--------------------------------------------------------
1267 cmd = u"""
1268 SELECT
1269 EXISTS (
1270 SELECT 1
1271 FROM clin.substance_intake
1272 WHERE
1273 fk_drug_component IS NULL
1274 AND
1275 fk_substance = %(pk)s
1276 LIMIT 1
1277 ) OR EXISTS (
1278 SELECT 1
1279 FROM clin.substance_intake
1280 WHERE
1281 fk_drug_component IS NOT NULL
1282 AND
1283 fk_drug_component = (
1284 SELECT r_ls2b.pk
1285 FROM ref.lnk_substance2brand r_ls2b
1286 WHERE fk_substance = %(pk)s
1287 )
1288 LIMIT 1
1289 )"""
1290 args = {'pk': self.pk_obj}
1291
1292 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
1293 return rows[0][0]
1294
1295 is_in_use_by_patients = property(_get_is_in_use_by_patients, lambda x:x)
1296 #--------------------------------------------------------
1298 cmd = u"""
1299 SELECT EXISTS (
1300 SELECT 1
1301 FROM ref.lnk_substance2brand
1302 WHERE fk_substance = %(pk)s
1303 LIMIT 1
1304 )"""
1305 args = {'pk': self.pk_obj}
1306
1307 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
1308 return rows[0][0]
1309
1310 is_drug_component = property(_get_is_drug_component, lambda x:x)
1311 #------------------------------------------------------------
1313 if order_by is None:
1314 order_by = u'true'
1315 else:
1316 order_by = u'true ORDER BY %s' % order_by
1317 cmd = _SQL_get_consumable_substance % order_by
1318 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = True)
1319 return [ cConsumableSubstance(row = {'data': r, 'idx': idx, 'pk_field': 'pk'}) for r in rows ]
1320 #------------------------------------------------------------
1322
1323 substance = substance
1324 if atc is not None:
1325 atc = atc.strip()
1326
1327 converted, amount = gmTools.input2decimal(amount)
1328 if not converted:
1329 raise ValueError('<amount> must be a number: %s (%s)', amount, type(amount))
1330
1331 args = {
1332 'desc': substance.strip(),
1333 'amount': amount,
1334 'unit': unit.strip(),
1335 'atc': atc
1336 }
1337 cmd = u"""
1338 SELECT pk FROM ref.consumable_substance
1339 WHERE
1340 lower(description) = lower(%(desc)s)
1341 AND
1342 amount = %(amount)s
1343 AND
1344 unit = %(unit)s
1345 """
1346 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}])
1347
1348 if len(rows) == 0:
1349 cmd = u"""
1350 INSERT INTO ref.consumable_substance (description, atc_code, amount, unit) VALUES (
1351 %(desc)s,
1352 gm.nullify_empty_string(%(atc)s),
1353 %(amount)s,
1354 gm.nullify_empty_string(%(unit)s)
1355 ) RETURNING pk"""
1356 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True, get_col_idx = False)
1357
1358 gmATC.propagate_atc(substance = substance, atc = atc)
1359
1360 return cConsumableSubstance(aPK_obj = rows[0]['pk'])
1361 #------------------------------------------------------------
1363 args = {'pk': substance}
1364 cmd = u"""
1365 DELETE FROM ref.consumable_substance
1366 WHERE
1367 pk = %(pk)s
1368 AND
1369
1370 -- must not currently be used with a patient
1371 NOT EXISTS (
1372 SELECT 1
1373 FROM clin.v_pat_substance_intake
1374 WHERE pk_substance = %(pk)s
1375 LIMIT 1
1376 )
1377 AND
1378
1379 -- must not currently be used with a branded drug
1380 NOT EXISTS (
1381 SELECT 1
1382 FROM ref.lnk_substance2brand
1383 WHERE fk_substance = %(pk)s
1384 LIMIT 1
1385 )"""
1386 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
1387 return True
1388 #------------------------------------------------------------
1390
1391 _pattern = regex.compile(r'^\D+\s*\d+$', regex.UNICODE | regex.LOCALE)
1392 _query1 = u"""
1393 SELECT
1394 pk::text,
1395 (description || ' ' || amount || unit) as subst
1396 FROM ref.consumable_substance
1397 WHERE description %(fragment_condition)s
1398 ORDER BY subst
1399 LIMIT 50"""
1400 _query2 = u"""
1401 SELECT
1402 pk::text,
1403 (description || ' ' || amount || unit) as subst
1404 FROM ref.consumable_substance
1405 WHERE
1406 %(fragment_condition)s
1407 ORDER BY subst
1408 LIMIT 50"""
1409
1410 #--------------------------------------------------------
1412 """Return matches for aFragment at start of phrases."""
1413
1414 if cSubstanceMatchProvider._pattern.match(aFragment):
1415 self._queries = [cSubstanceMatchProvider._query2]
1416 fragment_condition = """description ILIKE %(desc)s
1417 AND
1418 amount::text ILIKE %(amount)s"""
1419 self._args['desc'] = u'%s%%' % regex.sub(r'\s*\d+$', u'', aFragment)
1420 self._args['amount'] = u'%s%%' % regex.sub(r'^\D+\s*', u'', aFragment)
1421 else:
1422 self._queries = [cSubstanceMatchProvider._query1]
1423 fragment_condition = u"ILIKE %(fragment)s"
1424 self._args['fragment'] = u"%s%%" % aFragment
1425
1426 return self._find_matches(fragment_condition)
1427 #--------------------------------------------------------
1429 """Return matches for aFragment at start of words inside phrases."""
1430
1431 if cSubstanceMatchProvider._pattern.match(aFragment):
1432 self._queries = [cSubstanceMatchProvider._query2]
1433
1434 desc = regex.sub(r'\s*\d+$', u'', aFragment)
1435 desc = gmPG2.sanitize_pg_regex(expression = desc, escape_all = False)
1436
1437 fragment_condition = """description ~* %(desc)s
1438 AND
1439 amount::text ILIKE %(amount)s"""
1440
1441 self._args['desc'] = u"( %s)|(^%s)" % (desc, desc)
1442 self._args['amount'] = u'%s%%' % regex.sub(r'^\D+\s*', u'', aFragment)
1443 else:
1444 self._queries = [cSubstanceMatchProvider._query1]
1445 fragment_condition = u"~* %(fragment)s"
1446 aFragment = gmPG2.sanitize_pg_regex(expression = aFragment, escape_all = False)
1447 self._args['fragment'] = u"( %s)|(^%s)" % (aFragment, aFragment)
1448
1449 return self._find_matches(fragment_condition)
1450 #--------------------------------------------------------
1452 """Return matches for aFragment as a true substring."""
1453
1454 if cSubstanceMatchProvider._pattern.match(aFragment):
1455 self._queries = [cSubstanceMatchProvider._query2]
1456 fragment_condition = """description ILIKE %(desc)s
1457 AND
1458 amount::text ILIKE %(amount)s"""
1459 self._args['desc'] = u'%%%s%%' % regex.sub(r'\s*\d+$', u'', aFragment)
1460 self._args['amount'] = u'%s%%' % regex.sub(r'^\D+\s*', u'', aFragment)
1461 else:
1462 self._queries = [cSubstanceMatchProvider._query1]
1463 fragment_condition = u"ILIKE %(fragment)s"
1464 self._args['fragment'] = u"%%%s%%" % aFragment
1465
1466 return self._find_matches(fragment_condition)
1467 #============================================================
1469 """Represents a substance currently taken by a patient."""
1470
1471 _cmd_fetch_payload = u"SELECT * FROM clin.v_pat_substance_intake WHERE pk_substance_intake = %s"
1472 _cmds_store_payload = [
1473 u"""UPDATE clin.substance_intake SET
1474 clin_when = %(started)s,
1475 discontinued = %(discontinued)s,
1476 discontinue_reason = gm.nullify_empty_string(%(discontinue_reason)s),
1477 schedule = gm.nullify_empty_string(%(schedule)s),
1478 aim = gm.nullify_empty_string(%(aim)s),
1479 narrative = gm.nullify_empty_string(%(notes)s),
1480 intake_is_approved_of = %(intake_is_approved_of)s,
1481 fk_episode = %(pk_episode)s,
1482
1483 preparation = (
1484 case
1485 when %(pk_brand)s is NULL then %(preparation)s
1486 else NULL
1487 end
1488 )::text,
1489
1490 is_long_term = (
1491 case
1492 when (
1493 (%(is_long_term)s is False)
1494 and
1495 (%(duration)s is NULL)
1496 ) is True then null
1497 else %(is_long_term)s
1498 end
1499 )::boolean,
1500
1501 duration = (
1502 case
1503 when %(is_long_term)s is True then null
1504 else %(duration)s
1505 end
1506 )::interval
1507 WHERE
1508 pk = %(pk_substance_intake)s
1509 AND
1510 xmin = %(xmin_substance_intake)s
1511 RETURNING
1512 xmin as xmin_substance_intake
1513 """
1514 ]
1515 _updatable_fields = [
1516 u'started',
1517 u'discontinued',
1518 u'discontinue_reason',
1519 u'preparation',
1520 u'intake_is_approved_of',
1521 u'schedule',
1522 u'duration',
1523 u'aim',
1524 u'is_long_term',
1525 u'notes',
1526 u'pk_episode'
1527 ]
1528 #--------------------------------------------------------
1530
1531 if self._payload[self._idx['duration']] is None:
1532 duration = gmTools.bool2subst (
1533 self._payload[self._idx['is_long_term']],
1534 _('long-term'),
1535 _('short-term'),
1536 _('?short-term')
1537 )
1538 else:
1539 duration = gmDateTime.format_interval (
1540 self._payload[self._idx['duration']],
1541 accuracy_wanted = gmDateTime.acc_days
1542 )
1543
1544 line = u'%s%s (%s %s): %s %s%s %s (%s)' % (
1545 u' ' * left_margin,
1546 self._payload[self._idx['started']].strftime(date_format),
1547 gmTools.u_right_arrow,
1548 duration,
1549 self._payload[self._idx['substance']],
1550 self._payload[self._idx['amount']],
1551 self._payload[self._idx['unit']],
1552 self._payload[self._idx['preparation']],
1553 gmTools.bool2subst(self._payload[self._idx['is_currently_active']], _('ongoing'), _('inactive'), _('?ongoing'))
1554 )
1555
1556 return line
1557 #--------------------------------------------------------
1559 allg = gmAllergy.create_allergy (
1560 allergene = self._payload[self._idx['substance']],
1561 allg_type = allergy_type,
1562 episode_id = self._payload[self._idx['pk_episode']],
1563 encounter_id = encounter_id
1564 )
1565 allg['substance'] = gmTools.coalesce (
1566 self._payload[self._idx['brand']],
1567 self._payload[self._idx['substance']]
1568 )
1569 allg['reaction'] = self._payload[self._idx['discontinue_reason']]
1570 allg['atc_code'] = gmTools.coalesce(self._payload[self._idx['atc_substance']], self._payload[self._idx['atc_brand']])
1571 if self._payload[self._idx['external_code_brand']] is not None:
1572 allg['substance_code'] = u'%s::::%s' % (self._payload[self._idx['external_code_type_brand']], self._payload[self._idx['external_code_brand']])
1573 comps = [ c['substance'] for c in self.containing_drug.components ]
1574 if len(comps) == 0:
1575 allg['generics'] = self._payload[self._idx['substance']]
1576 else:
1577 allg['generics'] = u'; '.join(comps)
1578
1579 allg.save()
1580 return allg
1581 #--------------------------------------------------------
1582 # properties
1583 #--------------------------------------------------------
1585
1586 try: self.__ddd
1587 except AttributeError: self.__ddd = None
1588
1589 if self.__ddd is not None:
1590 return self.__ddd
1591
1592 if self._payload[self._idx['atc_substance']] is not None:
1593 ddd = gmATC.atc2ddd(atc = self._payload[self._idx['atc_substance']])
1594 if len(ddd) != 0:
1595 self.__ddd = ddd[0]
1596 else:
1597 if self._payload[self._idx['atc_brand']] is not None:
1598 ddd = gmATC.atc2ddd(atc = self._payload[self._idx['atc_brand']])
1599 if len(ddd) != 0:
1600 self.__ddd = ddd[0]
1601
1602 return self.__ddd
1603
1604 ddd = property(_get_ddd, lambda x:x)
1605 #--------------------------------------------------------
1607 drug = self.containing_drug
1608
1609 if drug is None:
1610 return None
1611
1612 return drug.external_code
1613
1614 external_code = property(_get_external_code, lambda x:x)
1615 #--------------------------------------------------------
1617 drug = self.containing_drug
1618
1619 if drug is None:
1620 return None
1621
1622 return drug.external_code_type
1623
1624 external_code_type = property(_get_external_code_type, lambda x:x)
1625 #--------------------------------------------------------
1627 if self._payload[self._idx['pk_brand']] is None:
1628 return None
1629
1630 return cBrandedDrug(aPK_obj = self._payload[self._idx['pk_brand']])
1631
1632 containing_drug = property(_get_containing_drug, lambda x:x)
1633 #--------------------------------------------------------
1635 tests = [
1636 # lead, trail
1637 ' 1-1-1-1 ',
1638 # leading dose
1639 '1-1-1-1',
1640 '22-1-1-1',
1641 '1/3-1-1-1',
1642 '/4-1-1-1'
1643 ]
1644 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}$"
1645 for test in tests:
1646 print test.strip(), ":", regex.match(pattern, test.strip())
1647 #------------------------------------------------------------
1648 -def create_substance_intake(pk_substance=None, pk_component=None, preparation=None, encounter=None, episode=None):
1649
1650 args = {
1651 'enc': encounter,
1652 'epi': episode,
1653 'comp': pk_component,
1654 'subst': pk_substance,
1655 'prep': preparation
1656 }
1657
1658 if pk_component is None:
1659 cmd = u"""
1660 INSERT INTO clin.substance_intake (
1661 fk_encounter,
1662 fk_episode,
1663 intake_is_approved_of,
1664 fk_substance,
1665 preparation
1666 ) VALUES (
1667 %(enc)s,
1668 %(epi)s,
1669 False,
1670 %(subst)s,
1671 %(prep)s
1672 )
1673 RETURNING pk"""
1674 else:
1675 cmd = u"""
1676 INSERT INTO clin.substance_intake (
1677 fk_encounter,
1678 fk_episode,
1679 intake_is_approved_of,
1680 fk_drug_component
1681 ) VALUES (
1682 %(enc)s,
1683 %(epi)s,
1684 False,
1685 %(comp)s
1686 )
1687 RETURNING pk"""
1688
1689 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True)
1690 return cSubstanceIntakeEntry(aPK_obj = rows[0][0])
1691 #------------------------------------------------------------
1693 cmd = u'delete from clin.substance_intake where pk = %(pk)s'
1694 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': {'pk': substance}}])
1695 #------------------------------------------------------------
1697
1698 tex = u'\n{\\small\n'
1699 tex += u'\\noindent %s\n' % _('Additional notes')
1700 tex += u'\n'
1701 tex += u'\\noindent \\begin{tabular}{|l|l|l|l|}\n'
1702 tex += u'\\hline\n'
1703 tex += u'%s & %s & %s & \\\\ \n' % (_('Substance'), _('Strength'), _('Brand'))
1704 tex += u'\\hline\n'
1705 tex += u'%s\n'
1706 tex += u'\n'
1707 tex += u'\\end{tabular}\n'
1708 tex += u'}\n'
1709
1710 current_meds = emr.get_current_substance_intake (
1711 include_inactive = False,
1712 include_unapproved = False,
1713 order_by = u'brand, substance'
1714 )
1715
1716 # create lines
1717 lines = []
1718 for med in current_meds:
1719
1720 lines.append(u'%s & %s%s & %s %s & {\\scriptsize %s} \\\\ \n \\hline \n' % (
1721 med['substance'],
1722 med['amount'],
1723 med['unit'],
1724 gmTools.coalesce(med['brand'], u''),
1725 med['preparation'],
1726 gmTools.coalesce(med['notes'], u'')
1727 ))
1728
1729 return tex % u' \n'.join(lines)
1730
1731 #------------------------------------------------------------
1733
1734 tex = u'\\noindent %s {\\tiny (%s)\\par}\n' % (_('Medication list'), _('ordered by brand'))
1735 tex += u'\n'
1736 tex += u'\\noindent \\begin{tabular}{|l|l|}\n'
1737 tex += u'\\hline\n'
1738 tex += u'%s & %s \\\\ \n' % (_('Drug'), _('Regimen'))
1739 tex += u'\\hline\n'
1740 tex += u'\n'
1741 tex += u'\\hline\n'
1742 tex += u'%s\n'
1743 tex += u'\n'
1744 tex += u'\\end{tabular}\n'
1745
1746 current_meds = emr.get_current_substance_intake (
1747 include_inactive = False,
1748 include_unapproved = False,
1749 order_by = u'brand, substance'
1750 )
1751
1752 # aggregate data
1753 line_data = {}
1754 for med in current_meds:
1755 identifier = gmTools.coalesce(med['brand'], med['substance'])
1756
1757 try:
1758 line_data[identifier]
1759 except KeyError:
1760 line_data[identifier] = {'brand': u'', 'preparation': u'', 'schedule': u'', 'aims': [], 'strengths': []}
1761
1762 line_data[identifier]['brand'] = identifier
1763 line_data[identifier]['strengths'].append(u'%s%s' % (med['amount'], med['unit'].strip()))
1764 line_data[identifier]['preparation'] = med['preparation']
1765 line_data[identifier]['schedule'] = gmTools.coalesce(med['schedule'], u'')
1766 if med['aim'] not in line_data[identifier]['aims']:
1767 line_data[identifier]['aims'].append(med['aim'])
1768
1769 # create lines
1770 already_seen = []
1771 lines = []
1772 line1_template = u'%s %s & %s \\\\'
1773 line2_template = u' & {\\scriptsize %s\\par} \\\\'
1774
1775 for med in current_meds:
1776 identifier = gmTools.coalesce(med['brand'], med['substance'])
1777
1778 if identifier in already_seen:
1779 continue
1780
1781 already_seen.append(identifier)
1782
1783 lines.append (line1_template % (
1784 line_data[identifier]['brand'],
1785 line_data[identifier]['preparation'],
1786 line_data[identifier]['schedule']
1787 ))
1788
1789 strengths = u'/'.join(line_data[identifier]['strengths'])
1790 if strengths == u'':
1791 template = u' & {\\scriptsize %s\\par} \\\\'
1792 for aim in line_data[identifier]['aims']:
1793 lines.append(template % aim)
1794 else:
1795 if len(line_data[identifier]['aims']) == 0:
1796 template = u'%s & \\\\'
1797 lines.append(template % strengths)
1798 else:
1799 template = u'%s & {\\scriptsize %s\\par} \\\\'
1800 lines.append(template % (strengths, line_data[identifier]['aims'][0]))
1801 template = u' & {\\scriptsize %s\\par} \\\\'
1802 for aim in line_data[identifier]['aims'][1:]:
1803 lines.append(template % aim)
1804
1805 lines.append(u'\\hline')
1806
1807 return tex % u' \n'.join(lines)
1808 #============================================================
1809 _SQL_get_drug_components = u'SELECT * FROM ref.v_drug_components WHERE %s'
1810
1812
1813 _cmd_fetch_payload = _SQL_get_drug_components % u'pk_component = %s'
1814 _cmds_store_payload = [
1815 u"""UPDATE ref.lnk_substance2brand SET
1816 fk_brand = %(pk_brand)s,
1817 fk_substance = %(pk_consumable_substance)s
1818 WHERE
1819 NOT EXISTS (
1820 SELECT 1
1821 FROM clin.substance_intake
1822 WHERE fk_drug_component = %(pk_component)s
1823 LIMIT 1
1824 )
1825 AND
1826 pk = %(pk_component)s
1827 AND
1828 xmin = %(xmin_lnk_substance2brand)s
1829 RETURNING
1830 xmin AS xmin_lnk_substance2brand
1831 """
1832 ]
1833 _updatable_fields = [
1834 u'pk_brand',
1835 u'pk_consumable_substance'
1836 ]
1837 #--------------------------------------------------------
1838 # properties
1839 #--------------------------------------------------------
1841 return cBrandedDrug(aPK_obj = self._payload[self._idx['pk_brand']])
1842
1843 containing_drug = property(_get_containing_drug, lambda x:x)
1844 #--------------------------------------------------------
1847
1848 is_in_use_by_patients = property(_get_is_in_use_by_patients, lambda x:x)
1849 #--------------------------------------------------------
1851 return cConsumableSubstance(aPK_obj = self._payload[self._idx['pk_consumable_substance']])
1852
1853 substance = property(_get_substance, lambda x:x)
1854 #------------------------------------------------------------
1856 cmd = _SQL_get_drug_components % u'true ORDER BY brand, substance'
1857 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = True)
1858 return [ cDrugComponent(row = {'data': r, 'idx': idx, 'pk_field': 'pk_component'}) for r in rows ]
1859 #------------------------------------------------------------
1861
1862 _pattern = regex.compile(r'^\D+\s*\d+$', regex.UNICODE | regex.LOCALE)
1863 _query_desc_only = u"""
1864 SELECT DISTINCT ON (component)
1865 pk_component,
1866 (substance || ' ' || amount || unit || ' ' || preparation || ' (' || brand || ')')
1867 AS component
1868 FROM ref.v_drug_components
1869 WHERE
1870 substance %(fragment_condition)s
1871 OR
1872 brand %(fragment_condition)s
1873 ORDER BY component
1874 LIMIT 50"""
1875 _query_desc_and_amount = u"""
1876
1877 SELECT DISTINCT ON (component)
1878 pk_component,
1879 (substance || ' ' || amount || unit || ' ' || preparation || ' (' || brand || ')')
1880 AS component
1881 FROM ref.v_drug_components
1882 WHERE
1883 %(fragment_condition)s
1884 ORDER BY component
1885 LIMIT 50"""
1886 #--------------------------------------------------------
1888 """Return matches for aFragment at start of phrases."""
1889
1890 if cDrugComponentMatchProvider._pattern.match(aFragment):
1891 self._queries = [cDrugComponentMatchProvider._query_desc_and_amount]
1892 fragment_condition = """(substance ILIKE %(desc)s OR brand ILIKE %(desc)s)
1893 AND
1894 amount::text ILIKE %(amount)s"""
1895 self._args['desc'] = u'%s%%' % regex.sub(r'\s*\d+$', u'', aFragment)
1896 self._args['amount'] = u'%s%%' % regex.sub(r'^\D+\s*', u'', aFragment)
1897 else:
1898 self._queries = [cDrugComponentMatchProvider._query_desc_only]
1899 fragment_condition = u"ILIKE %(fragment)s"
1900 self._args['fragment'] = u"%s%%" % aFragment
1901
1902 return self._find_matches(fragment_condition)
1903 #--------------------------------------------------------
1905 """Return matches for aFragment at start of words inside phrases."""
1906
1907 if cDrugComponentMatchProvider._pattern.match(aFragment):
1908 self._queries = [cDrugComponentMatchProvider._query_desc_and_amount]
1909
1910 desc = regex.sub(r'\s*\d+$', u'', aFragment)
1911 desc = gmPG2.sanitize_pg_regex(expression = desc, escape_all = False)
1912
1913 fragment_condition = """(substance ~* %(desc)s OR brand ~* %(desc)s)
1914 AND
1915 amount::text ILIKE %(amount)s"""
1916
1917 self._args['desc'] = u"( %s)|(^%s)" % (desc, desc)
1918 self._args['amount'] = u'%s%%' % regex.sub(r'^\D+\s*', u'', aFragment)
1919 else:
1920 self._queries = [cDrugComponentMatchProvider._query_desc_only]
1921 fragment_condition = u"~* %(fragment)s"
1922 aFragment = gmPG2.sanitize_pg_regex(expression = aFragment, escape_all = False)
1923 self._args['fragment'] = u"( %s)|(^%s)" % (aFragment, aFragment)
1924
1925 return self._find_matches(fragment_condition)
1926 #--------------------------------------------------------
1928 """Return matches for aFragment as a true substring."""
1929
1930 if cDrugComponentMatchProvider._pattern.match(aFragment):
1931 self._queries = [cDrugComponentMatchProvider._query_desc_and_amount]
1932 fragment_condition = """(substance ILIKE %(desc)s OR brand ILIKE %(desc)s)
1933 AND
1934 amount::text ILIKE %(amount)s"""
1935 self._args['desc'] = u'%%%s%%' % regex.sub(r'\s*\d+$', u'', aFragment)
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"ILIKE %(fragment)s"
1940 self._args['fragment'] = u"%%%s%%" % aFragment
1941
1942 return self._find_matches(fragment_condition)
1943
1944 #============================================================
1946 """Represents a drug as marketed by a manufacturer."""
1947
1948 _cmd_fetch_payload = u"SELECT * FROM ref.v_branded_drugs WHERE pk_brand = %s"
1949 _cmds_store_payload = [
1950 u"""UPDATE ref.branded_drug SET
1951 description = %(brand)s,
1952 preparation = %(preparation)s,
1953 atc_code = gm.nullify_empty_string(%(atc)s),
1954 external_code = gm.nullify_empty_string(%(external_code)s),
1955 external_code_type = gm.nullify_empty_string(%(external_code_type)s),
1956 is_fake = %(is_fake_brand)s,
1957 fk_data_source = %(pk_data_source)s
1958 WHERE
1959 pk = %(pk_brand)s
1960 AND
1961 xmin = %(xmin_branded_drug)s
1962 RETURNING
1963 xmin AS xmin_branded_drug
1964 """
1965 ]
1966 _updatable_fields = [
1967 u'brand',
1968 u'preparation',
1969 u'atc',
1970 u'is_fake_brand',
1971 u'external_code',
1972 u'external_code_type',
1973 u'pk_data_source'
1974 ]
1975 #--------------------------------------------------------
1977 success, data = super(self.__class__, self).save_payload(conn = conn)
1978
1979 if not success:
1980 return (success, data)
1981
1982 if self._payload[self._idx['atc']] is not None:
1983 atc = self._payload[self._idx['atc']].strip()
1984 if atc != u'':
1985 gmATC.propagate_atc (
1986 substance = self._payload[self._idx['brand']].strip(),
1987 atc = atc
1988 )
1989
1990 return (success, data)
1991 #--------------------------------------------------------
1993
1994 if self._payload[self._idx['is_in_use']]:
1995 return False
1996
1997 args = {'brand': self._payload[self._idx['pk_brand']]}
1998
1999 queries = [{'cmd': u"DELETE FROM ref.lnk_substance2brand WHERE fk_brand = %(brand)s", 'args': args}]
2000 cmd = u'INSERT INTO ref.lnk_substance2brand (fk_brand, fk_substance) VALUES (%%(brand)s, %s)'
2001 for s in substances:
2002 queries.append({'cmd': cmd % s['pk'], 'args': args})
2003
2004 gmPG2.run_rw_queries(queries = queries)
2005 self.refetch_payload()
2006
2007 return True
2008 #--------------------------------------------------------
2009 - def add_component(self, substance=None, atc=None, amount=None, unit=None, pk_substance=None):
2010
2011 args = {
2012 'brand': self.pk_obj,
2013 'subst': substance,
2014 'atc': atc,
2015 'pk_subst': pk_substance
2016 }
2017
2018 if pk_substance is None:
2019 consumable = create_consumable_substance(substance = substance, atc = atc, amount = amount, unit = unit)
2020 args['pk_subst'] = consumable['pk']
2021
2022 # already a component
2023 cmd = u"""
2024 SELECT pk_component
2025 FROM ref.v_drug_components
2026 WHERE
2027 pk_brand = %(brand)s
2028 AND
2029 ((
2030 (lower(substance) = lower(%(subst)s))
2031 OR
2032 (lower(atc_substance) = lower(%(atc)s))
2033 OR
2034 (pk_consumable_substance = %(pk_subst)s)
2035 ) IS TRUE)
2036 """
2037 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
2038
2039 if len(rows) > 0:
2040 return
2041
2042 # create it
2043 cmd = u"""
2044 INSERT INTO ref.lnk_substance2brand (fk_brand, fk_substance)
2045 VALUES (%(brand)s, %(pk_subst)s)
2046 """
2047 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
2048 self.refetch_payload()
2049 #------------------------------------------------------------
2051 if len(self._payload[self._idx['components']]) == 1:
2052 _log.error('cannot remove the only component of a drug')
2053 return False
2054
2055 args = {'brand': self.pk_obj, 'comp': substance}
2056 cmd = u"""
2057 DELETE FROM ref.lnk_substance2brand
2058 WHERE
2059 fk_brand = %(brand)s
2060 AND
2061 fk_substance = %(comp)s
2062 AND
2063 NOT EXISTS (
2064 SELECT 1
2065 FROM clin.substance_intake
2066 WHERE fk_drug_component = %(comp)s
2067 LIMIT 1
2068 )
2069 """
2070 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
2071 self.refetch_payload()
2072
2073 return True
2074 #--------------------------------------------------------
2075 # properties
2076 #--------------------------------------------------------
2078 if self._payload[self._idx['external_code']] is None:
2079 return None
2080
2081 return self._payload[self._idx['external_code']]
2082
2083 external_code = property(_get_external_code, lambda x:x)
2084 #--------------------------------------------------------
2086
2087 # FIXME: maybe evaluate fk_data_source ?
2088 if self._payload[self._idx['external_code_type']] is None:
2089 return None
2090
2091 return self._payload[self._idx['external_code_type']]
2092
2093 external_code_type = property(_get_external_code_type, lambda x:x)
2094 #--------------------------------------------------------
2096 cmd = _SQL_get_drug_components % u'pk_brand = %(brand)s'
2097 args = {'brand': self._payload[self._idx['pk_brand']]}
2098 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
2099 return [ cDrugComponent(row = {'data': r, 'idx': idx, 'pk_field': 'pk_component'}) for r in rows ]
2100
2101 components = property(_get_components, lambda x:x)
2102 #--------------------------------------------------------
2104 if self._payload[self._idx['pk_substances']] is None:
2105 return []
2106 cmd = _SQL_get_consumable_substance % u'pk IN %(pks)s'
2107 args = {'pks': tuple(self._payload[self._idx['pk_substances']])}
2108 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
2109 return [ cConsumableSubstance(row = {'data': r, 'idx': idx, 'pk_field': 'pk'}) for r in rows ]
2110
2111 components_as_substances = property(_get_components_as_substances, lambda x:x)
2112 #--------------------------------------------------------
2114 cmd = u'SELECT EXISTS (SELECT 1 FROM clin.vaccine WHERE fk_brand = %(fk_brand)s)'
2115 args = {'fk_brand': self._payload[self._idx['pk_brand']]}
2116 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
2117 return rows[0][0]
2118
2119 is_vaccine = property(_get_is_vaccine, lambda x:x)
2120 #------------------------------------------------------------
2122 cmd = u'SELECT pk FROM ref.branded_drug ORDER BY description'
2123 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = False)
2124 return [ cBrandedDrug(aPK_obj = r['pk']) for r in rows ]
2125 #------------------------------------------------------------
2127 args = {'brand': brand_name, 'prep': preparation}
2128
2129 cmd = u'SELECT pk FROM ref.branded_drug WHERE lower(description) = lower(%(brand)s) AND lower(preparation) = lower(%(prep)s)'
2130 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
2131
2132 if len(rows) == 0:
2133 return None
2134
2135 return cBrandedDrug(aPK_obj = rows[0]['pk'])
2136 #------------------------------------------------------------
2138
2139 if preparation is None:
2140 preparation = _('units')
2141
2142 if preparation.strip() == u'':
2143 preparation = _('units')
2144
2145 if return_existing:
2146 drug = get_drug_by_brand(brand_name = brand_name, preparation = preparation)
2147 if drug is not None:
2148 return drug
2149
2150 cmd = u'INSERT INTO ref.branded_drug (description, preparation) VALUES (%(brand)s, %(prep)s) RETURNING pk'
2151 args = {'brand': brand_name, 'prep': preparation}
2152 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True, get_col_idx = False)
2153
2154 return cBrandedDrug(aPK_obj = rows[0]['pk'])
2155 #------------------------------------------------------------
2157 queries = []
2158 args = {'pk': brand}
2159
2160 # delete components
2161 cmd = u"""
2162 DELETE FROM ref.lnk_substance2brand
2163 WHERE
2164 fk_brand = %(pk)s
2165 AND
2166 NOT EXISTS (
2167 SELECT 1
2168 FROM clin.v_pat_substance_intake
2169 WHERE pk_brand = %(pk)s
2170 LIMIT 1
2171 )
2172 """
2173 queries.append({'cmd': cmd, 'args': args})
2174
2175 # delete drug
2176 cmd = u"""
2177 DELETE FROM ref.branded_drug
2178 WHERE
2179 pk = %(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 gmPG2.run_rw_queries(queries = queries)
2191 #============================================================
2192 # main
2193 #------------------------------------------------------------
2194 if __name__ == "__main__":
2195
2196 if len(sys.argv) < 2:
2197 sys.exit()
2198
2199 if sys.argv[1] != 'test':
2200 sys.exit()
2201
2202 from Gnumed.pycommon import gmLog2
2203 from Gnumed.pycommon import gmI18N
2204 from Gnumed.business import gmPerson
2205
2206 gmI18N.activate_locale()
2207 # gmDateTime.init()
2208 #--------------------------------------------------------
2210 mmi = cGelbeListeWineInterface()
2211 print mmi
2212 print "interface definition:", mmi.version
2213 print "database versions: ", mmi.get_data_source_version()
2214 #--------------------------------------------------------
2216 mmi_file = cGelbeListeCSVFile(filename = sys.argv[2])
2217 for drug in mmi_file:
2218 print "-------------"
2219 print '"%s" (ATC: %s / PZN: %s)' % (drug['name'], drug['atc'], drug['pzn'])
2220 for stoff in drug['wirkstoffe']:
2221 print " Wirkstoff:", stoff
2222 raw_input()
2223 if mmi_file.has_unknown_fields is not None:
2224 print "has extra data under [%s]" % gmTools.default_csv_reader_rest_key
2225 for key in mmi_file.csv_fieldnames:
2226 print key, '->', drug[key]
2227 raw_input()
2228 mmi_file.close()
2229 #--------------------------------------------------------
2233 #--------------------------------------------------------
2235 mmi = cGelbeListeWineInterface()
2236 mmi_file = mmi.__let_user_select_drugs()
2237 for drug in mmi_file:
2238 print "-------------"
2239 print '"%s" (ATC: %s / PZN: %s)' % (drug['name'], drug['atc'], drug['pzn'])
2240 for stoff in drug['wirkstoffe']:
2241 print " Wirkstoff:", stoff
2242 print drug
2243 mmi_file.close()
2244 #--------------------------------------------------------
2248 #--------------------------------------------------------
2250 mmi = cGelbeListeInterface()
2251 print mmi
2252 print "interface definition:", mmi.version
2253 # Metoprolol + Hct vs Citalopram
2254 diclofenac = '7587712'
2255 phenprocoumon = '4421744'
2256 mmi.check_interactions(drug_ids_list = [diclofenac, phenprocoumon])
2257 #--------------------------------------------------------
2258 # FreeDiams
2259 #--------------------------------------------------------
2261 gmPerson.set_active_patient(patient = gmPerson.cIdentity(aPK_obj = 12))
2262 fd = cFreeDiamsInterface()
2263 fd.patient = gmPerson.gmCurrentPatient()
2264 # fd.switch_to_frontend(blocking = True)
2265 fd.import_fd2gm_file_as_drugs(filename = sys.argv[2])
2266 #--------------------------------------------------------
2268 gmPerson.set_active_patient(patient = gmPerson.cIdentity(aPK_obj = 12))
2269 fd = cFreeDiamsInterface()
2270 fd.patient = gmPerson.gmCurrentPatient()
2271 fd.check_interactions(substances = fd.patient.get_emr().get_current_substance_intake(include_unapproved = True))
2272 #--------------------------------------------------------
2273 # generic
2274 #--------------------------------------------------------
2276 drug = create_substance_intake (
2277 pk_component = 2,
2278 encounter = 1,
2279 episode = 1
2280 )
2281 print drug
2282 #--------------------------------------------------------
2287 #--------------------------------------------------------
2291 #--------------------------------------------------------
2292 #--------------------------------------------------------
2293 # MMI/Gelbe Liste
2294 #test_MMI_interface()
2295 #test_MMI_file()
2296 #test_mmi_switch_to()
2297 #test_mmi_let_user_select_drugs()
2298 #test_mmi_import_substances()
2299 #test_mmi_import_drugs()
2300
2301 # FreeDiams
2302 test_fd_switch_to()
2303 #test_fd_show_interactions()
2304
2305 # generic
2306 #test_interaction_check()
2307 #test_create_substance_intake()
2308 #test_show_components()
2309 #test_get_consumable_substances()
2310 #============================================================
2311
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Wed May 4 03:58:32 2011 | http://epydoc.sourceforge.net |