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