| 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.home_dir, '.gnumed', 'tmp', 'rezept.txt')
1076 self.default_csv_filename_arg = os.path.join(paths.home_dir, '.gnumed', 'tmp')
1077 self.interactions_filename = os.path.join(paths.home_dir, '.gnumed', 'tmp', '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 _query_desc_only = u"""
2208 SELECT DISTINCT ON (component)
2209 pk_component,
2210 (substance || ' ' || amount || unit || ' ' || preparation || ' (' || brand || ')')
2211 AS component
2212 FROM ref.v_drug_components
2213 WHERE
2214 substance %(fragment_condition)s
2215 OR
2216 brand %(fragment_condition)s
2217 ORDER BY component
2218 LIMIT 50"""
2219 _query_desc_and_amount = u"""
2220
2221 SELECT DISTINCT ON (component)
2222 pk_component,
2223 (substance || ' ' || amount || unit || ' ' || preparation || ' (' || brand || ')')
2224 AS component
2225 FROM ref.v_drug_components
2226 WHERE
2227 %(fragment_condition)s
2228 ORDER BY component
2229 LIMIT 50"""
2230 #--------------------------------------------------------
2232 """Return matches for aFragment at start of phrases."""
2233
2234 if cDrugComponentMatchProvider._pattern.match(aFragment):
2235 self._queries = [cDrugComponentMatchProvider._query_desc_and_amount]
2236 fragment_condition = """(substance ILIKE %(desc)s OR brand ILIKE %(desc)s)
2237 AND
2238 amount::text ILIKE %(amount)s"""
2239 self._args['desc'] = u'%s%%' % regex.sub(r'\s*\d+$', u'', aFragment)
2240 self._args['amount'] = u'%s%%' % regex.sub(r'^\D+\s*', u'', aFragment)
2241 else:
2242 self._queries = [cDrugComponentMatchProvider._query_desc_only]
2243 fragment_condition = u"ILIKE %(fragment)s"
2244 self._args['fragment'] = u"%s%%" % aFragment
2245
2246 return self._find_matches(fragment_condition)
2247 #--------------------------------------------------------
2249 """Return matches for aFragment at start of words inside phrases."""
2250
2251 if cDrugComponentMatchProvider._pattern.match(aFragment):
2252 self._queries = [cDrugComponentMatchProvider._query_desc_and_amount]
2253
2254 desc = regex.sub(r'\s*\d+$', u'', aFragment)
2255 desc = gmPG2.sanitize_pg_regex(expression = desc, escape_all = False)
2256
2257 fragment_condition = """(substance ~* %(desc)s OR brand ~* %(desc)s)
2258 AND
2259 amount::text ILIKE %(amount)s"""
2260
2261 self._args['desc'] = u"( %s)|(^%s)" % (desc, desc)
2262 self._args['amount'] = u'%s%%' % regex.sub(r'^\D+\s*', u'', aFragment)
2263 else:
2264 self._queries = [cDrugComponentMatchProvider._query_desc_only]
2265 fragment_condition = u"~* %(fragment)s"
2266 aFragment = gmPG2.sanitize_pg_regex(expression = aFragment, escape_all = False)
2267 self._args['fragment'] = u"( %s)|(^%s)" % (aFragment, aFragment)
2268
2269 return self._find_matches(fragment_condition)
2270 #--------------------------------------------------------
2272 """Return matches for aFragment as a true substring."""
2273
2274 if cDrugComponentMatchProvider._pattern.match(aFragment):
2275 self._queries = [cDrugComponentMatchProvider._query_desc_and_amount]
2276 fragment_condition = """(substance ILIKE %(desc)s OR brand ILIKE %(desc)s)
2277 AND
2278 amount::text ILIKE %(amount)s"""
2279 self._args['desc'] = u'%%%s%%' % regex.sub(r'\s*\d+$', u'', aFragment)
2280 self._args['amount'] = u'%s%%' % regex.sub(r'^\D+\s*', u'', aFragment)
2281 else:
2282 self._queries = [cDrugComponentMatchProvider._query_desc_only]
2283 fragment_condition = u"ILIKE %(fragment)s"
2284 self._args['fragment'] = u"%%%s%%" % aFragment
2285
2286 return self._find_matches(fragment_condition)
2287
2288 #============================================================
2290 """Represents a drug as marketed by a manufacturer."""
2291
2292 _cmd_fetch_payload = u"SELECT * FROM ref.v_branded_drugs WHERE pk_brand = %s"
2293 _cmds_store_payload = [
2294 u"""UPDATE ref.branded_drug SET
2295 description = %(brand)s,
2296 preparation = %(preparation)s,
2297 atc_code = gm.nullify_empty_string(%(atc)s),
2298 external_code = gm.nullify_empty_string(%(external_code)s),
2299 external_code_type = gm.nullify_empty_string(%(external_code_type)s),
2300 is_fake = %(is_fake_brand)s,
2301 fk_data_source = %(pk_data_source)s
2302 WHERE
2303 pk = %(pk_brand)s
2304 AND
2305 xmin = %(xmin_branded_drug)s
2306 RETURNING
2307 xmin AS xmin_branded_drug
2308 """
2309 ]
2310 _updatable_fields = [
2311 u'brand',
2312 u'preparation',
2313 u'atc',
2314 u'is_fake_brand',
2315 u'external_code',
2316 u'external_code_type',
2317 u'pk_data_source'
2318 ]
2319 #--------------------------------------------------------
2321 success, data = super(self.__class__, self).save_payload(conn = conn)
2322
2323 if not success:
2324 return (success, data)
2325
2326 if self._payload[self._idx['atc']] is not None:
2327 atc = self._payload[self._idx['atc']].strip()
2328 if atc != u'':
2329 gmATC.propagate_atc (
2330 substance = self._payload[self._idx['brand']].strip(),
2331 atc = atc
2332 )
2333
2334 return (success, data)
2335 #--------------------------------------------------------
2337
2338 if self.is_in_use_by_patients:
2339 return False
2340
2341 pk_substances2keep = [ s['pk'] for s in substances ]
2342 args = {'brand': self._payload[self._idx['pk_brand']]}
2343 queries = []
2344
2345 # INSERT those which are not there yet
2346 cmd = u"""
2347 INSERT INTO ref.lnk_substance2brand (
2348 fk_brand,
2349 fk_substance
2350 )
2351 SELECT
2352 %(brand)s,
2353 %(subst)s
2354 WHERE NOT EXISTS (
2355 SELECT 1
2356 FROM ref.lnk_substance2brand
2357 WHERE
2358 fk_brand = %(brand)s
2359 AND
2360 fk_substance = %(subst)s
2361 )"""
2362 for pk in pk_substances2keep:
2363 args['subst'] = pk
2364 queries.append({'cmd': cmd, 'args': args})
2365
2366 # DELETE those that don't belong anymore
2367 args['substances2keep'] = tuple(pk_substances2keep)
2368 cmd = u"""
2369 DELETE FROM ref.lnk_substance2brand
2370 WHERE
2371 fk_brand = %(brand)s
2372 AND
2373 fk_substance NOT IN %(substances2keep)s"""
2374 queries.append({'cmd': cmd, 'args': args})
2375
2376 gmPG2.run_rw_queries(queries = queries)
2377 self.refetch_payload()
2378
2379 return True
2380 #--------------------------------------------------------
2381 - def add_component(self, substance=None, atc=None, amount=None, unit=None, pk_substance=None):
2382
2383 args = {
2384 'brand': self.pk_obj,
2385 'subst': substance,
2386 'atc': atc,
2387 'pk_subst': pk_substance
2388 }
2389
2390 if pk_substance is None:
2391 consumable = create_consumable_substance(substance = substance, atc = atc, amount = amount, unit = unit)
2392 args['pk_subst'] = consumable['pk']
2393
2394 # already a component
2395 cmd = u"""
2396 SELECT pk_component
2397 FROM ref.v_drug_components
2398 WHERE
2399 pk_brand = %(brand)s
2400 AND
2401 ((
2402 (lower(substance) = lower(%(subst)s))
2403 OR
2404 (lower(atc_substance) = lower(%(atc)s))
2405 OR
2406 (pk_consumable_substance = %(pk_subst)s)
2407 ) IS TRUE)
2408 """
2409 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
2410
2411 if len(rows) > 0:
2412 return
2413
2414 # create it
2415 cmd = u"""
2416 INSERT INTO ref.lnk_substance2brand (fk_brand, fk_substance)
2417 VALUES (%(brand)s, %(pk_subst)s)
2418 """
2419 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
2420 self.refetch_payload()
2421 #------------------------------------------------------------
2423 if len(self._payload[self._idx['components']]) == 1:
2424 _log.error('cannot remove the only component of a drug')
2425 return False
2426
2427 args = {'brand': self.pk_obj, 'comp': substance}
2428 cmd = u"""
2429 DELETE FROM ref.lnk_substance2brand
2430 WHERE
2431 fk_brand = %(brand)s
2432 AND
2433 fk_substance = %(comp)s
2434 AND
2435 NOT EXISTS (
2436 SELECT 1
2437 FROM clin.substance_intake
2438 WHERE fk_drug_component = %(comp)s
2439 LIMIT 1
2440 )
2441 """
2442 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
2443 self.refetch_payload()
2444
2445 return True
2446 #--------------------------------------------------------
2447 # properties
2448 #--------------------------------------------------------
2450 if self._payload[self._idx['external_code']] is None:
2451 return None
2452
2453 return self._payload[self._idx['external_code']]
2454
2455 external_code = property(_get_external_code, lambda x:x)
2456 #--------------------------------------------------------
2458
2459 # FIXME: maybe evaluate fk_data_source ?
2460 if self._payload[self._idx['external_code_type']] is None:
2461 return None
2462
2463 return self._payload[self._idx['external_code_type']]
2464
2465 external_code_type = property(_get_external_code_type, lambda x:x)
2466 #--------------------------------------------------------
2468 cmd = _SQL_get_drug_components % u'pk_brand = %(brand)s'
2469 args = {'brand': self._payload[self._idx['pk_brand']]}
2470 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
2471 return [ cDrugComponent(row = {'data': r, 'idx': idx, 'pk_field': 'pk_component'}) for r in rows ]
2472
2473 components = property(_get_components, lambda x:x)
2474 #--------------------------------------------------------
2476 if self._payload[self._idx['pk_substances']] is None:
2477 return []
2478 cmd = _SQL_get_consumable_substance % u'pk IN %(pks)s'
2479 args = {'pks': tuple(self._payload[self._idx['pk_substances']])}
2480 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
2481 return [ cConsumableSubstance(row = {'data': r, 'idx': idx, 'pk_field': 'pk'}) for r in rows ]
2482
2483 components_as_substances = property(_get_components_as_substances, lambda x:x)
2484 #--------------------------------------------------------
2486 cmd = u'SELECT EXISTS (SELECT 1 FROM clin.vaccine WHERE fk_brand = %(fk_brand)s)'
2487 args = {'fk_brand': self._payload[self._idx['pk_brand']]}
2488 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
2489 return rows[0][0]
2490
2491 is_vaccine = property(_get_is_vaccine, lambda x:x)
2492 #--------------------------------------------------------
2494 cmd = u"""
2495 SELECT EXISTS (
2496 SELECT 1
2497 FROM clin.substance_intake
2498 WHERE
2499 fk_drug_component IS NOT NULL
2500 AND
2501 fk_drug_component IN (
2502 SELECT r_ls2b.pk
2503 FROM ref.lnk_substance2brand r_ls2b
2504 WHERE fk_brand = %(pk)s
2505 )
2506 LIMIT 1
2507 )"""
2508 args = {'pk': self.pk_obj}
2509
2510 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
2511 return rows[0][0]
2512
2513 is_in_use_by_patients = property(_get_is_in_use_by_patients, lambda x:x)
2514 #------------------------------------------------------------
2516 cmd = u'SELECT pk FROM ref.branded_drug ORDER BY description'
2517 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = False)
2518 return [ cBrandedDrug(aPK_obj = r['pk']) for r in rows ]
2519 #------------------------------------------------------------
2521 args = {'brand': brand_name, 'prep': preparation}
2522
2523 cmd = u'SELECT pk FROM ref.branded_drug WHERE lower(description) = lower(%(brand)s) AND lower(preparation) = lower(%(prep)s)'
2524 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
2525
2526 if len(rows) == 0:
2527 return None
2528
2529 return cBrandedDrug(aPK_obj = rows[0]['pk'])
2530 #------------------------------------------------------------
2532
2533 if preparation is None:
2534 preparation = _('units')
2535
2536 if preparation.strip() == u'':
2537 preparation = _('units')
2538
2539 if return_existing:
2540 drug = get_drug_by_brand(brand_name = brand_name, preparation = preparation)
2541 if drug is not None:
2542 return drug
2543
2544 cmd = u'INSERT INTO ref.branded_drug (description, preparation) VALUES (%(brand)s, %(prep)s) RETURNING pk'
2545 args = {'brand': brand_name, 'prep': preparation}
2546 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True, get_col_idx = False)
2547
2548 return cBrandedDrug(aPK_obj = rows[0]['pk'])
2549 #------------------------------------------------------------
2551 queries = []
2552 args = {'pk': brand}
2553
2554 # delete components
2555 cmd = u"""
2556 DELETE FROM ref.lnk_substance2brand
2557 WHERE
2558 fk_brand = %(pk)s
2559 AND
2560 NOT EXISTS (
2561 SELECT 1
2562 FROM clin.v_pat_substance_intake
2563 WHERE pk_brand = %(pk)s
2564 LIMIT 1
2565 )
2566 """
2567 queries.append({'cmd': cmd, 'args': args})
2568
2569 # delete drug
2570 cmd = u"""
2571 DELETE FROM ref.branded_drug
2572 WHERE
2573 pk = %(pk)s
2574 AND
2575 NOT EXISTS (
2576 SELECT 1
2577 FROM clin.v_pat_substance_intake
2578 WHERE pk_brand = %(pk)s
2579 LIMIT 1
2580 )
2581 """
2582 queries.append({'cmd': cmd, 'args': args})
2583
2584 gmPG2.run_rw_queries(queries = queries)
2585 #============================================================
2586 # main
2587 #------------------------------------------------------------
2588 if __name__ == "__main__":
2589
2590 if len(sys.argv) < 2:
2591 sys.exit()
2592
2593 if sys.argv[1] != 'test':
2594 sys.exit()
2595
2596 from Gnumed.pycommon import gmLog2
2597 from Gnumed.pycommon import gmI18N
2598 from Gnumed.business import gmPerson
2599
2600 gmI18N.activate_locale()
2601 # gmDateTime.init()
2602 #--------------------------------------------------------
2604 mmi = cGelbeListeWineInterface()
2605 print mmi
2606 print "interface definition:", mmi.version
2607 print "database versions: ", mmi.get_data_source_version()
2608 #--------------------------------------------------------
2610 mmi_file = cGelbeListeCSVFile(filename = sys.argv[2])
2611 for drug in mmi_file:
2612 print "-------------"
2613 print '"%s" (ATC: %s / PZN: %s)' % (drug['name'], drug['atc'], drug['pzn'])
2614 for stoff in drug['wirkstoffe']:
2615 print " Wirkstoff:", stoff
2616 raw_input()
2617 if mmi_file.has_unknown_fields is not None:
2618 print "has extra data under [%s]" % gmTools.default_csv_reader_rest_key
2619 for key in mmi_file.csv_fieldnames:
2620 print key, '->', drug[key]
2621 raw_input()
2622 mmi_file.close()
2623 #--------------------------------------------------------
2627 #--------------------------------------------------------
2629 mmi = cGelbeListeWineInterface()
2630 mmi_file = mmi.__let_user_select_drugs()
2631 for drug in mmi_file:
2632 print "-------------"
2633 print '"%s" (ATC: %s / PZN: %s)' % (drug['name'], drug['atc'], drug['pzn'])
2634 for stoff in drug['wirkstoffe']:
2635 print " Wirkstoff:", stoff
2636 print drug
2637 mmi_file.close()
2638 #--------------------------------------------------------
2642 #--------------------------------------------------------
2644 mmi = cGelbeListeInterface()
2645 print mmi
2646 print "interface definition:", mmi.version
2647 # Metoprolol + Hct vs Citalopram
2648 diclofenac = '7587712'
2649 phenprocoumon = '4421744'
2650 mmi.check_interactions(drug_ids_list = [diclofenac, phenprocoumon])
2651 #--------------------------------------------------------
2652 # FreeDiams
2653 #--------------------------------------------------------
2655 gmPerson.set_active_patient(patient = gmPerson.cIdentity(aPK_obj = 12))
2656 fd = cFreeDiamsInterface()
2657 fd.patient = gmPerson.gmCurrentPatient()
2658 # fd.switch_to_frontend(blocking = True)
2659 fd.import_fd2gm_file_as_drugs(filename = sys.argv[2])
2660 #--------------------------------------------------------
2662 gmPerson.set_active_patient(patient = gmPerson.cIdentity(aPK_obj = 12))
2663 fd = cFreeDiamsInterface()
2664 fd.patient = gmPerson.gmCurrentPatient()
2665 fd.check_interactions(substances = fd.patient.get_emr().get_current_substance_intake(include_unapproved = True))
2666 #--------------------------------------------------------
2667 # generic
2668 #--------------------------------------------------------
2670 drug = create_substance_intake (
2671 pk_component = 2,
2672 encounter = 1,
2673 episode = 1
2674 )
2675 print drug
2676 #--------------------------------------------------------
2681 #--------------------------------------------------------
2685 #--------------------------------------------------------
2687 drug2renal_insufficiency_url(search_term = 'Metoprolol')
2688 #--------------------------------------------------------
2689 # MMI/Gelbe Liste
2690 #test_MMI_interface()
2691 #test_MMI_file()
2692 #test_mmi_switch_to()
2693 #test_mmi_let_user_select_drugs()
2694 #test_mmi_import_substances()
2695 #test_mmi_import_drugs()
2696
2697 # FreeDiams
2698 test_fd_switch_to()
2699 #test_fd_show_interactions()
2700
2701 # generic
2702 #test_interaction_check()
2703 #test_create_substance_intake()
2704 #test_show_components()
2705 #test_get_consumable_substances()
2706
2707 #test_drug2renal_insufficiency_url()
2708 #============================================================
2709
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Mon Jun 25 03:58:52 2012 | http://epydoc.sourceforge.net |