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