1
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
43 DEFAULT_MEDICATION_HISTORY_EPISODE = _('Medication history')
44
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
98
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
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
139
140
141
142
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
150 default_encoding = 'cp1250'
151 csv_fieldnames = [
152 u'name',
153 u'packungsgroesse',
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',
191 u't_rezept_pflicht',
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',
211 u't_rezept_pflicht',
212 u'erstattbares_medizinprodukt',
213 u'hilfsmittel'
214 ]
215
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
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
253 - def close(self, truncate=True):
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
270 self.patient = None
271 self.reviewer = None
272 self.custom_path_to_binary = None
273
275 raise NotImplementedError
276
278 raise NotImplementedError
279
281 raise NotImplementedError
282
285
288
291
294
295 - def prescribe(self, substance_intakes=None):
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
328
330
331
332 if not self.__detect_binary():
333 return False
334
335 freediams = subprocess.Popen (
336 args = u'--version',
337 executable = self.path_to_binary,
338 stdout = subprocess.PIPE,
339 stderr = subprocess.PIPE,
340
341 universal_newlines = True
342 )
343 data, errors = freediams.communicate()
344 version = regex.search('FreeDiams\s\d.\d.\d', data).group().split()[1]
345 _log.debug('FreeDiams %s', version)
346
347 return version
348
350 return create_data_source (
351 long_name = u'"FreeDiams" Drug Database Frontend',
352 short_name = u'FreeDiams',
353 version = self.get_data_source_version(),
354 source = u'http://ericmaeker.fr/FreeMedForms/di-manual/index.html',
355 language = u'fr'
356 )
357
359 """http://ericmaeker.fr/FreeMedForms/di-manual/en/html/ligne_commandes.html"""
360
361 _log.debug('calling FreeDiams in [%s] mode', mode)
362
363 self.__imported_drugs = []
364
365 if not self.__detect_binary():
366 return False
367
368 self.__create_gm2fd_file(mode = mode)
369
370 args = u'--exchange-in="%s"' % (self.__gm2fd_filename)
371 cmd = r'%s %s' % (self.path_to_binary, args)
372 if os.name == 'nt':
373 blocking = True
374 if not gmShellAPI.run_command_in_shell(command = cmd, blocking = blocking):
375 _log.error('problem switching to the FreeDiams drug database')
376 return False
377
378 if blocking == True:
379 self.import_fd2gm_file_as_drugs()
380
381 return True
382
385
387 if substance_intakes is None:
388 return
389 if len(substance_intakes) < 2:
390 return
391
392 self.__create_prescription_file(substance_intakes = substance_intakes)
393 self.switch_to_frontend(mode = 'interactions', blocking = False)
394
396 if substance_intake is None:
397 return
398
399 self.__create_prescription_file(substance_intakes = [substance_intake])
400 self.switch_to_frontend(mode = 'interactions', blocking = False)
401
404
405 - def prescribe(self, substance_intakes=None):
406 if substance_intakes is None:
407 if not self.__export_latest_prescription():
408 self.__create_prescription_file()
409 else:
410 self.__create_prescription_file(substance_intakes = substance_intakes)
411
412 self.switch_to_frontend(mode = 'prescription', blocking = True)
413 self.import_fd2gm_file_as_prescription()
414
415 return self.__imported_drugs
416
417
418
420
421 if self.path_to_binary is not None:
422 return True
423
424 found, cmd = gmShellAPI.find_first_binary(binaries = [
425 r'/usr/bin/freediams',
426 r'freediams',
427 r'/Applications/FreeDiams.app/Contents/MacOs/FreeDiams',
428 r'C:\Program Files (x86)\FreeDiams\freediams.exe',
429 r'C:\Program Files\FreeDiams\freediams.exe',
430 r'c:\programs\freediams\freediams.exe',
431 r'freediams.exe'
432 ])
433
434 if found:
435 self.path_to_binary = cmd
436 return True
437
438 try:
439 self.custom_path_to_binary
440 except AttributeError:
441 _log.error('cannot find FreeDiams binary, no custom path set')
442 return False
443
444 if self.custom_path_to_binary is None:
445 _log.error('cannot find FreeDiams binary')
446 return False
447
448 found, cmd = gmShellAPI.detect_external_binary(binary = self.custom_path_to_binary)
449 if found:
450 self.path_to_binary = cmd
451 return True
452
453 _log.error('cannot find FreeDiams binary')
454 return False
455
457
458 if self.patient is None:
459 _log.debug('cannot export latest FreeDiams prescriptions w/o patient')
460 return False
461
462 docs = self.patient.get_document_folder()
463 prescription = docs.get_latest_freediams_prescription()
464 if prescription is None:
465 _log.debug('no FreeDiams prescription available')
466 return False
467
468 for part in prescription.parts:
469 if part['filename'] == u'freediams-prescription.xml':
470 if part.export_to_file(filename = self.__fd2gm_filename) is not None:
471 return True
472
473 _log.error('cannot export latest FreeDiams prescription to XML file')
474
475 return False
476
478 """FreeDiams calls this exchange-out or prescription file.
479
480 CIS stands for Unique Speciality Identifier (eg bisoprolol 5 mg, gel).
481 CIS is AFSSAPS specific, but pharmacist can retreive drug name with the CIS.
482 AFSSAPS is the French FDA.
483
484 CIP stands for Unique Presentation Identifier (eg 30 pills plaq)
485 CIP if you want to specify the packaging of the drug (30 pills
486 thermoformed tablet...) -- actually not really usefull for french
487 doctors.
488 # .external_code_type: u'FR-CIS'
489 # .external_cod: the CIS value
490
491 OnlyForTest:
492 OnlyForTest drugs will be processed by the IA Engine but
493 not printed (regardless of FreeDiams mode). They are shown
494 in gray in the prescription view.
495
496 Select-only is a mode where FreeDiams creates a list of drugs
497 not a full prescription. In this list, users can add ForTestOnly
498 drug if they want to
499 1. print the list without some drugs
500 2. but including these drugs in the IA engine calculation
501
502 Select-Only mode does not have any relation with the ForTestOnly drugs.
503
504 IsTextual:
505 What is the use and significance of the
506 <IsTextual>true/false</IsTextual>
507 flag when both <DrugName> and <TextualDrugName> exist ?
508
509 This tag must be setted even if it sounds like a duplicated
510 data. This tag is needed inside FreeDiams code.
511
512 INN:
513 GNUmed will pass the substance in <TextualDrugName
514 and will also pass <INN>True</INN>.
515
516 Eric: Nop, this is not usefull because pure textual drugs
517 are not processed but just shown.
518 """
519
520 open(self.__fd2gm_filename, 'wb').close()
521
522
523 if substance_intakes is None:
524 if self.patient is None:
525 _log.warning('cannot create prescription file because there is neither a patient nor a substance intake list')
526
527 return False
528 emr = self.patient.get_emr()
529 substance_intakes = emr.get_current_substance_intake (
530 include_inactive = False,
531 include_unapproved = True
532 )
533
534 drug_snippets = []
535
536
537 fd_intakes = [ i for i in substance_intakes if (
538 (i['intake_is_approved_of'] is True)
539 and
540 (i['external_code_type_brand'] is not None)
541 and
542 (i['external_code_type_brand'].startswith(u'FreeDiams::'))
543 )]
544
545 intakes_pooled_by_brand = {}
546 for intake in fd_intakes:
547
548
549 intakes_pooled_by_brand[intake['brand']] = intake
550 del fd_intakes
551
552 drug_snippet = u"""<Prescription>
553 <Drug u1="%s" u2="" old="%s" u3="" db="%s"> <!-- "old" needs to be the same as "u1" if not known -->
554 <DrugName>%s</DrugName> <!-- just for identification when reading XML files -->
555 </Drug>
556 </Prescription>"""
557
558 last_db_id = u'CA_HCDPD'
559 for intake in intakes_pooled_by_brand.values():
560 last_db_id = gmTools.xml_escape_string(text = intake['external_code_type_brand'].replace(u'FreeDiams::', u'').split(u'::')[0])
561 drug_snippets.append(drug_snippet % (
562 gmTools.xml_escape_string(text = intake['external_code_brand'].strip()),
563 gmTools.xml_escape_string(text = intake['external_code_brand'].strip()),
564 last_db_id,
565 gmTools.xml_escape_string(text = intake['brand'].strip())
566 ))
567
568
569 non_fd_intakes = [ i for i in substance_intakes if (
570 (i['intake_is_approved_of'] is True)
571 and (
572 (i['external_code_type_brand'] is None)
573 or
574 (not i['external_code_type_brand'].startswith(u'FreeDiams::'))
575 )
576 )]
577
578 non_fd_brand_intakes = [ i for i in non_fd_intakes if i['brand'] is not None ]
579 non_fd_substance_intakes = [ i for i in non_fd_intakes if i['brand'] is None ]
580 del non_fd_intakes
581
582 drug_snippet = u"""<Prescription>
583 <Drug u1="-1" u2="" old="" u3="" db="">
584 <DrugName>%s</DrugName>
585 </Drug>
586 <Dose Note="%s" IsTextual="true" IsAld="false"/>
587 </Prescription>"""
588
589
590
591
592
593 for intake in non_fd_substance_intakes:
594 drug_name = u'%s %s%s (%s)' % (
595 intake['substance'],
596 intake['amount'],
597 intake['unit'],
598 intake['preparation']
599 )
600 drug_snippets.append(drug_snippet % (
601 gmTools.xml_escape_string(text = drug_name.strip()),
602 gmTools.xml_escape_string(text = gmTools.coalesce(intake['schedule'], u''))
603 ))
604
605 intakes_pooled_by_brand = {}
606 for intake in non_fd_brand_intakes:
607 brand = u'%s %s' % (intake['brand'], intake['preparation'])
608 try:
609 intakes_pooled_by_brand[brand].append(intake)
610 except KeyError:
611 intakes_pooled_by_brand[brand] = [intake]
612
613 for brand, comps in intakes_pooled_by_brand.iteritems():
614 drug_name = u'%s\n' % brand
615 for comp in comps:
616 drug_name += u' %s %s%s\n' % (
617 comp['substance'],
618 comp['amount'],
619 comp['unit']
620 )
621 drug_snippets.append(drug_snippet % (
622 gmTools.xml_escape_string(text = drug_name.strip()),
623 gmTools.xml_escape_string(text = gmTools.coalesce(comps[0]['schedule'], u''))
624 ))
625
626
627 xml = u"""<?xml version = "1.0" encoding = "UTF-8"?>
628 <!DOCTYPE FreeMedForms>
629 <FreeDiams>
630 <FullPrescription version="0.7.2">
631 %s
632 </FullPrescription>
633 </FreeDiams>
634 """
635
636 xml_file = codecs.open(self.__fd2gm_filename, 'wb', 'utf8')
637 xml_file.write(xml % u'\n\t\t'.join(drug_snippets))
638 xml_file.close()
639
640 return True
641
643
644 if mode == 'interactions':
645 mode = u'select-only'
646 elif mode == 'prescription':
647 mode = u'prescriber'
648 else:
649 mode = u'select-only'
650
651 xml_file = codecs.open(self.__gm2fd_filename, 'wb', 'utf8')
652
653 xml = u"""<?xml version="1.0" encoding="UTF-8"?>
654
655 <FreeDiams_In version="0.5.0">
656 <EMR name="GNUmed" uid="unused"/>
657 <ConfigFile value="%s"/>
658 <ExchangeOut value="%s" format="xml"/>
659 <!-- <DrugsDatabase uid="can be set to a specific DB"/> -->
660 <Ui editmode="%s" blockPatientDatas="1"/>
661 %%s
662 </FreeDiams_In>
663
664 <!--
665 # FIXME: search by LOINC code and add (as soon as supported by FreeDiams ...)
666 <Creatinine value="12" unit="mg/l or mmol/l"/>
667 <Weight value="70" unit="kg or pd" />
668 <Height value="170" unit="cm or "/>
669 <ICD10 value="J11.0;A22;Z23"/>
670 -->
671 """ % (
672 self.__fd4gm_config_file,
673 self.__fd2gm_filename,
674 mode
675 )
676
677 if self.patient is None:
678 xml_file.write(xml % u'')
679 xml_file.close()
680 return
681
682 name = self.patient.get_active_name()
683 if self.patient['dob'] is None:
684 dob = u''
685 else:
686 dob = self.patient['dob'].strftime(cFreeDiamsInterface.default_dob_format)
687
688 emr = self.patient.get_emr()
689 allgs = emr.get_allergies()
690 atc_allgs = [
691 a['atc_code'] for a in allgs if ((a['atc_code'] is not None) and (a['type'] == u'allergy'))
692 ]
693 atc_sens = [
694 a['atc_code'] for a in allgs if ((a['atc_code'] is not None) and (a['type'] == u'sensitivity'))
695 ]
696 inn_allgs = [
697 a['allergene'] for a in allgs if ((a['allergene'] is not None) and (a['type'] == u'allergy'))
698 ]
699 inn_sens = [
700 a['allergene'] for a in allgs if ((a['allergene'] is not None) and (a['type'] == u'sensitivity'))
701 ]
702
703
704
705 uid_allgs = [
706 a['substance_code'] for a in allgs if ((a['substance_code'] is not None) and (a['type'] == u'allergy'))
707 ]
708 uid_sens = [
709 a['substance_code'] for a in allgs if ((a['substance_code'] is not None) and (a['type'] == u'sensitivity'))
710 ]
711
712 patient_xml = u"""<Patient>
713 <Identity
714 lastnames="%s"
715 firstnames="%s"
716 uid="%s"
717 dob="%s"
718 gender="%s"
719 />
720 <ATCAllergies value="%s"/>
721 <ATCIntolerances value="%s"/>
722
723 <InnAllergies value="%s"/>
724 <InnIntolerances value="%s"/>
725
726 <DrugsUidAllergies value="%s"/>
727 <DrugsUidIntolerances value="%s"/>
728 </Patient>
729 """ % (
730 gmTools.xml_escape_string(text = name['lastnames']),
731 gmTools.xml_escape_string(text = name['firstnames']),
732 self.patient.ID,
733 dob,
734 cFreeDiamsInterface.map_gender2mf[self.patient['gender']],
735 gmTools.xml_escape_string(text = u';'.join(atc_allgs)),
736 gmTools.xml_escape_string(text = u';'.join(atc_sens)),
737 gmTools.xml_escape_string(text = u';'.join(inn_allgs)),
738 gmTools.xml_escape_string(text = u';'.join(inn_sens)),
739 gmTools.xml_escape_string(text = u';'.join(uid_allgs)),
740 gmTools.xml_escape_string(text = u';'.join(uid_sens))
741 )
742
743 xml_file.write(xml % patient_xml)
744 xml_file.close()
745
798
800 """
801 If returning textual prescriptions (say, drugs which FreeDiams
802 did not know) then "IsTextual" will be True and UID will be -1.
803 """
804 if filename is None:
805 filename = self.__fd2gm_filename
806
807
808
809 fd2gm_xml = etree.ElementTree()
810 fd2gm_xml.parse(filename)
811
812 data_src_pk = self.create_data_source_entry()
813
814 xml_version = fd2gm_xml.find('FullPrescription').attrib['version']
815 _log.debug('fd2gm file version: %s', xml_version)
816
817 if xml_version in ['0.6.0', '0.7.2']:
818 return self.__import_fd2gm_file_as_drugs_0_6_0(fd2gm_xml = fd2gm_xml, pk_data_source = data_src_pk)
819
820 return self.__import_fd2gm_file_as_drugs_0_5(fd2gm_xml = fd2gm_xml, pk_data_source = data_src_pk)
821
823
824
825 fd_xml_prescriptions = fd2gm_xml.findall('FullPrescription/Prescription')
826
827 self.__imported_drugs = []
828 for fd_xml_prescription in fd_xml_prescriptions:
829 drug_uid = fd_xml_prescription.find('Drug').attrib['u1'].strip()
830 if drug_uid == u'-1':
831 _log.debug('skipping textual drug')
832 continue
833 drug_db = fd_xml_prescription.find('Drug').attrib['db'].strip()
834 drug_uid_name = fd_xml_prescription.find('Drug/DrugUidName').text.strip()
835
836 drug_name = fd_xml_prescription.find('Drug/DrugName').text.replace(', )', ')').strip()
837 drug_form = fd_xml_prescription.find('Drug/DrugForm').text.strip()
838
839
840
841
842
843
844
845
846
847
848 new_drug = create_branded_drug(brand_name = drug_name, preparation = drug_form, return_existing = True)
849 self.__imported_drugs.append(new_drug)
850 new_drug['is_fake_brand'] = False
851
852 new_drug['external_code_type'] = u'FreeDiams::%s::%s' % (drug_db, drug_uid_name)
853 new_drug['external_code'] = drug_uid
854 new_drug['pk_data_source'] = pk_data_source
855 new_drug.save()
856
857
858 fd_xml_components = fd_xml_prescription.getiterator('Composition')
859 comp_data = {}
860 for fd_xml_comp in fd_xml_components:
861
862 data = {}
863
864 xml_strength = fd_xml_comp.attrib['strength'].strip()
865 amount = regex.match(r'^\d+[.,]{0,1}\d*', xml_strength)
866 if amount is None:
867 amount = 99999
868 else:
869 amount = amount.group()
870 data['amount'] = amount
871
872
873 unit = (xml_strength[len(amount):]).strip()
874 if unit == u'':
875 unit = u'*?*'
876 data['unit'] = unit
877
878
879 atc = regex.match(r'[A-Za-z]\d\d[A-Za-z]{2}\d\d', fd_xml_comp.attrib['atc'].strip())
880 if atc is None:
881 data['atc'] = None
882 else:
883 atc = atc.group()
884 data['atc'] = atc
885
886 molecule_name = fd_xml_comp.attrib['molecularName'].strip()
887 if molecule_name != u'':
888 create_consumable_substance(substance = molecule_name, atc = atc, amount = amount, unit = unit)
889 data['molecule_name'] = molecule_name
890
891 inn_name = fd_xml_comp.attrib['inn'].strip()
892 if inn_name != u'':
893 create_consumable_substance(substance = inn_name, atc = atc, amount = amount, unit = unit)
894
895 data['inn_name'] = inn_name
896
897 if molecule_name == u'':
898 data['substance'] = inn_name
899 _log.info('linking INN [%s] rather than molecularName as component', inn_name)
900 else:
901 data['substance'] = molecule_name
902
903 data['nature'] = fd_xml_comp.attrib['nature'].strip()
904 data['nature_ID'] = fd_xml_comp.attrib['natureLink'].strip()
905
906
907 try:
908 old_data = comp_data[data['nature_ID']]
909
910 if old_data['inn_name'] == u'':
911 old_data['inn_name'] = data['inn_name']
912 if data['inn_name'] == u'':
913 data['inn_name'] = old_data['inn_name']
914
915 if old_data['molecule_name'] == u'':
916 old_data['molecule_name'] = data['molecule_name']
917 if data['molecule_name'] == u'':
918 data['molecule_name'] = old_data['molecule_name']
919
920 if old_data['atc'] == u'':
921 old_data['atc'] = data['atc']
922 if data['atc'] == u'':
923 data['atc'] = old_data['atc']
924
925
926
927
928
929
930 if data['nature'] == u'FT':
931 comp_data[data['nature_ID']] = data
932 else:
933 comp_data[data['nature_ID']] = old_data
934
935
936 except KeyError:
937 comp_data[data['nature_ID']] = data
938
939
940 for key, data in comp_data.items():
941 new_drug.add_component (
942 substance = data['substance'],
943 atc = data['atc'],
944 amount = data['amount'],
945 unit = data['unit']
946 )
947
949
950 db_def = fd2gm_xml.find('DrugsDatabaseName')
951 db_id = db_def.text.strip()
952 drug_id_name = db_def.attrib['drugUidName']
953 fd_xml_drug_entries = fd2gm_xml.findall('FullPrescription/Prescription')
954
955 self.__imported_drugs = []
956 for fd_xml_drug in fd_xml_drug_entries:
957 drug_uid = fd_xml_drug.find('Drug_UID').text.strip()
958 if drug_uid == u'-1':
959 _log.debug('skipping textual drug')
960 continue
961 drug_name = fd_xml_drug.find('DrugName').text.replace(', )', ')').strip()
962 drug_form = fd_xml_drug.find('DrugForm').text.strip()
963 drug_atc = fd_xml_drug.find('DrugATC')
964 if drug_atc is None:
965 drug_atc = u''
966 else:
967 if drug_atc.text is None:
968 drug_atc = u''
969 else:
970 drug_atc = drug_atc.text.strip()
971
972
973 new_drug = create_branded_drug(brand_name = drug_name, preparation = drug_form, return_existing = True)
974 self.__imported_drugs.append(new_drug)
975 new_drug['is_fake_brand'] = False
976 new_drug['atc'] = drug_atc
977 new_drug['external_code_type'] = u'FreeDiams::%s::%s' % (db_id, drug_id_name)
978 new_drug['external_code'] = drug_uid
979 new_drug['pk_data_source'] = pk_data_source
980 new_drug.save()
981
982
983 fd_xml_components = fd_xml_drug.getiterator('Composition')
984 comp_data = {}
985 for fd_xml_comp in fd_xml_components:
986
987 data = {}
988
989 amount = regex.match(r'\d+[.,]{0,1}\d*', fd_xml_comp.attrib['strenght'].strip())
990 if amount is None:
991 amount = 99999
992 else:
993 amount = amount.group()
994 data['amount'] = amount
995
996 unit = regex.sub(r'\d+[.,]{0,1}\d*', u'', fd_xml_comp.attrib['strenght'].strip()).strip()
997 if unit == u'':
998 unit = u'*?*'
999 data['unit'] = unit
1000
1001 molecule_name = fd_xml_comp.attrib['molecularName'].strip()
1002 if molecule_name != u'':
1003 create_consumable_substance(substance = molecule_name, atc = None, amount = amount, unit = unit)
1004 data['molecule_name'] = molecule_name
1005
1006 inn_name = fd_xml_comp.attrib['inn'].strip()
1007 if inn_name != u'':
1008 create_consumable_substance(substance = inn_name, atc = None, amount = amount, unit = unit)
1009 data['inn_name'] = molecule_name
1010
1011 if molecule_name == u'':
1012 data['substance'] = inn_name
1013 _log.info('linking INN [%s] rather than molecularName as component', inn_name)
1014 else:
1015 data['substance'] = molecule_name
1016
1017 data['nature'] = fd_xml_comp.attrib['nature'].strip()
1018 data['nature_ID'] = fd_xml_comp.attrib['natureLink'].strip()
1019
1020
1021 try:
1022 old_data = comp_data[data['nature_ID']]
1023
1024 if old_data['inn_name'] == u'':
1025 old_data['inn_name'] = data['inn_name']
1026 if data['inn_name'] == u'':
1027 data['inn_name'] = old_data['inn_name']
1028
1029 if old_data['molecule_name'] == u'':
1030 old_data['molecule_name'] = data['molecule_name']
1031 if data['molecule_name'] == u'':
1032 data['molecule_name'] = old_data['molecule_name']
1033
1034
1035
1036
1037
1038 if data['nature'] == u'FT':
1039 comp_data[data['nature_ID']] = data
1040 else:
1041 comp_data[data['nature_ID']] = old_data
1042
1043
1044 except KeyError:
1045 comp_data[data['nature_ID']] = data
1046
1047
1048 for key, data in comp_data.items():
1049 new_drug.add_component (
1050 substance = data['substance'],
1051 atc = None,
1052 amount = data['amount'],
1053 unit = data['unit']
1054 )
1055
1057 """Support v8.2 CSV file interface only."""
1058
1059 version = u'Gelbe Liste/MMI v8.2 interface'
1060 default_encoding = 'cp1250'
1061 bdt_line_template = u'%03d6210#%s\r\n'
1062 bdt_line_base_length = 8
1063
1065
1066 cDrugDataSourceInterface.__init__(self)
1067
1068 _log.info(u'%s (native Windows)', cGelbeListeWindowsInterface.version)
1069
1070 self.path_to_binary = r'C:\Programme\MMI PHARMINDEX\glwin.exe'
1071 self.args = r'-KEEPBACKGROUND -PRESCRIPTIONFILE %s -CLOSETOTRAY'
1072
1073 paths = gmTools.gmPaths()
1074
1075 self.default_csv_filename = os.path.join(paths.home_dir, '.gnumed', 'tmp', 'rezept.txt')
1076 self.default_csv_filename_arg = os.path.join(paths.home_dir, '.gnumed', 'tmp')
1077 self.interactions_filename = os.path.join(paths.home_dir, '.gnumed', 'tmp', 'gm2mmi.bdt')
1078 self.data_date_filename = r'C:\Programme\MMI PHARMINDEX\datadate.txt'
1079
1080 self.__data_date = None
1081 self.__online_update_date = None
1082
1083
1084
1086
1087 if self.__data_date is not None:
1088 if not force_reload:
1089 return {
1090 'data': self.__data_date,
1091 'online_update': self.__online_update_date
1092 }
1093 try:
1094 open(self.data_date_filename, 'wb').close()
1095 except StandardError:
1096 _log.error('problem querying the MMI drug database for version information')
1097 _log.exception('cannot create MMI drug database version file [%s]', self.data_date_filename)
1098 self.__data_date = None
1099 self.__online_update_date = None
1100 return {
1101 'data': u'?',
1102 'online_update': u'?'
1103 }
1104
1105 cmd = u'%s -DATADATE' % self.path_to_binary
1106 if not gmShellAPI.run_command_in_shell(command = cmd, blocking = True):
1107 _log.error('problem querying the MMI drug database for version information')
1108 self.__data_date = None
1109 self.__online_update_date = None
1110 return {
1111 'data': u'?',
1112 'online_update': u'?'
1113 }
1114
1115 try:
1116 version_file = open(self.data_date_filename, 'rU')
1117 except StandardError:
1118 _log.error('problem querying the MMI drug database for version information')
1119 _log.exception('cannot open MMI drug database version file [%s]', self.data_date_filename)
1120 self.__data_date = None
1121 self.__online_update_date = None
1122 return {
1123 'data': u'?',
1124 'online_update': u'?'
1125 }
1126
1127 self.__data_date = version_file.readline()[:10]
1128 self.__online_update_date = version_file.readline()[:10]
1129 version_file.close()
1130
1131 return {
1132 'data': self.__data_date,
1133 'online_update': self.__online_update_date
1134 }
1135
1137 versions = self.get_data_source_version()
1138
1139 return create_data_source (
1140 long_name = u'Medikamentendatenbank "mmi PHARMINDEX" (Gelbe Liste)',
1141 short_name = u'GL/MMI',
1142 version = u'Daten: %s, Preise (Onlineupdate): %s' % (versions['data'], versions['online_update']),
1143 source = u'Medizinische Medien Informations GmbH, Am Forsthaus Gravenbruch 7, 63263 Neu-Isenburg',
1144 language = u'de'
1145 )
1146
1148
1149 try:
1150
1151 open(self.default_csv_filename, 'wb').close()
1152 except IOError:
1153 _log.exception('problem creating GL/MMI <-> GNUmed exchange file')
1154 return False
1155
1156 if cmd is None:
1157 cmd = (u'%s %s' % (self.path_to_binary, self.args)) % self.default_csv_filename_arg
1158
1159 if os.name == 'nt':
1160 blocking = True
1161 if not gmShellAPI.run_command_in_shell(command = cmd, blocking = blocking):
1162 _log.error('problem switching to the MMI drug database')
1163
1164
1165
1166
1167 return True
1168
1178
1180
1181 selected_drugs = self.__let_user_select_drugs()
1182 if selected_drugs is None:
1183 return None
1184
1185 new_substances = []
1186
1187 for drug in selected_drugs:
1188 atc = None
1189 if len(drug['wirkstoffe']) == 1:
1190 atc = drug['atc']
1191 for wirkstoff in drug['wirkstoffe']:
1192 new_substances.append(create_consumable_substance(substance = wirkstoff, atc = atc, amount = amount, unit = unit))
1193
1194 selected_drugs.close()
1195
1196 return new_substances
1197
1199
1200 selected_drugs = self.__let_user_select_drugs()
1201 if selected_drugs is None:
1202 return None
1203
1204 data_src_pk = self.create_data_source_entry()
1205
1206 new_drugs = []
1207 new_substances = []
1208
1209 for entry in selected_drugs:
1210
1211 _log.debug('importing drug: %s %s', entry['name'], entry['darreichungsform'])
1212
1213 if entry[u'hilfsmittel']:
1214 _log.debug('skipping Hilfsmittel')
1215 continue
1216
1217 if entry[u'erstattbares_medizinprodukt']:
1218 _log.debug('skipping sonstiges Medizinprodukt')
1219 continue
1220
1221
1222 drug = create_branded_drug(brand_name = entry['name'], preparation = entry['darreichungsform'])
1223 if drug is None:
1224 drug = get_drug_by_brand(brand_name = entry['name'], preparation = entry['darreichungsform'])
1225 new_drugs.append(drug)
1226
1227
1228 drug['is_fake_brand'] = False
1229 drug['atc'] = entry['atc']
1230 drug['external_code_type'] = u'DE-PZN'
1231 drug['external_code'] = entry['pzn']
1232 drug['fk_data_source'] = data_src_pk
1233 drug.save()
1234
1235
1236 atc = None
1237 if len(entry['wirkstoffe']) == 1:
1238 atc = entry['atc']
1239 for wirkstoff in entry['wirkstoffe']:
1240 drug.add_component(substance = wirkstoff, atc = atc)
1241
1242
1243 atc = None
1244 if len(entry['wirkstoffe']) == 1:
1245 atc = entry['atc']
1246 for wirkstoff in entry['wirkstoffe']:
1247 new_substances.append(create_consumable_substance(substance = wirkstoff, atc = atc, amount = amount, unit = unit))
1248
1249 return new_drugs, new_substances
1250
1279
1282
1301
1303
1305 cGelbeListeWindowsInterface.__init__(self)
1306
1307 _log.info(u'%s (WINE extension)', cGelbeListeWindowsInterface.version)
1308
1309
1310 self.path_to_binary = r'wine "C:\Programme\MMI PHARMINDEX\glwin.exe"'
1311 self.args = r'"-PRESCRIPTIONFILE %s -KEEPBACKGROUND"'
1312
1313 paths = gmTools.gmPaths()
1314
1315 self.default_csv_filename = os.path.join(paths.home_dir, '.wine', 'drive_c', 'windows', 'temp', 'mmi2gm.csv')
1316 self.default_csv_filename_arg = r'c:\windows\temp\mmi2gm.csv'
1317 self.interactions_filename = os.path.join(paths.home_dir, '.wine', 'drive_c', 'windows', 'temp', 'gm2mmi.bdt')
1318 self.data_date_filename = os.path.join(paths.home_dir, '.wine', 'drive_c', 'Programme', 'MMI PHARMINDEX', 'datadate.txt')
1319
1321 """empirical CSV interface"""
1322
1325
1327
1328 try:
1329 csv_file = open(filename, 'rb')
1330 except:
1331 _log.exception('cannot access [%s]', filename)
1332 csv_file = None
1333
1334 field_names = u'PZN Handelsname Form Abpackungsmenge Einheit Preis1 Hersteller Preis2 rezeptpflichtig Festbetrag Packungszahl Packungsgr\xf6\xdfe'.split()
1335
1336 if csv_file is None:
1337 return False
1338
1339 csv_lines = csv.DictReader (
1340 csv_file,
1341 fieldnames = field_names,
1342 delimiter = ';'
1343 )
1344
1345 for line in csv_lines:
1346 print "--------------------------------------------------------------------"[:31]
1347 for key in field_names:
1348 tmp = ('%s ' % key)[:30]
1349 print '%s: %s' % (tmp, line[key])
1350
1351 csv_file.close()
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364 drug_data_source_interfaces = {
1365 'Deutschland: Gelbe Liste/MMI (Windows)': cGelbeListeWindowsInterface,
1366 'Deutschland: Gelbe Liste/MMI (WINE)': cGelbeListeWineInterface,
1367 'FreeDiams (FR, US, CA, ZA)': cFreeDiamsInterface
1368 }
1369
1370
1371
1372
1373
1374 _SQL_get_consumable_substance = u"""
1375 SELECT *, xmin
1376 FROM ref.consumable_substance
1377 WHERE %s
1378 """
1379
1381
1382 _cmd_fetch_payload = _SQL_get_consumable_substance % u"pk = %s"
1383 _cmds_store_payload = [
1384 u"""UPDATE ref.consumable_substance SET
1385 description = %(description)s,
1386 atc_code = gm.nullify_empty_string(%(atc_code)s),
1387 amount = %(amount)s,
1388 unit = gm.nullify_empty_string(%(unit)s)
1389 WHERE
1390 pk = %(pk)s
1391 AND
1392 xmin = %(xmin)s
1393 AND
1394 -- must not currently be used with a patient directly
1395 NOT EXISTS (
1396 SELECT 1
1397 FROM clin.substance_intake
1398 WHERE
1399 fk_drug_component IS NULL
1400 AND
1401 fk_substance = %(pk)s
1402 LIMIT 1
1403 )
1404 AND
1405 -- must not currently be used with a patient indirectly, either
1406 NOT EXISTS (
1407 SELECT 1
1408 FROM clin.substance_intake
1409 WHERE
1410 fk_drug_component IS NOT NULL
1411 AND
1412 fk_drug_component = (
1413 SELECT r_ls2b.pk
1414 FROM ref.lnk_substance2brand r_ls2b
1415 WHERE fk_substance = %(pk)s
1416 )
1417 LIMIT 1
1418 )
1419 -- -- must not currently be used with a branded drug
1420 -- -- (but this would make it rather hard fixing branded drugs which contain only this substance)
1421 -- NOT EXISTS (
1422 -- SELECT 1
1423 -- FROM ref.lnk_substance2brand
1424 -- WHERE fk_substance = %(pk)s
1425 -- LIMIT 1
1426 -- )
1427 RETURNING
1428 xmin
1429 """
1430 ]
1431 _updatable_fields = [
1432 u'description',
1433 u'atc_code',
1434 u'amount',
1435 u'unit'
1436 ]
1437
1439 success, data = super(self.__class__, self).save_payload(conn = conn)
1440
1441 if not success:
1442 return (success, data)
1443
1444 if self._payload[self._idx['atc_code']] is not None:
1445 atc = self._payload[self._idx['atc_code']].strip()
1446 if atc != u'':
1447 gmATC.propagate_atc (
1448 substance = self._payload[self._idx['description']].strip(),
1449 atc = atc
1450 )
1451
1452 return (success, data)
1453
1454
1455
1457 cmd = u"""
1458 SELECT
1459 EXISTS (
1460 SELECT 1
1461 FROM clin.substance_intake
1462 WHERE
1463 fk_drug_component IS NULL
1464 AND
1465 fk_substance = %(pk)s
1466 LIMIT 1
1467 ) OR EXISTS (
1468 SELECT 1
1469 FROM clin.substance_intake
1470 WHERE
1471 fk_drug_component IS NOT NULL
1472 AND
1473 fk_drug_component IN (
1474 SELECT r_ls2b.pk
1475 FROM ref.lnk_substance2brand r_ls2b
1476 WHERE fk_substance = %(pk)s
1477 )
1478 LIMIT 1
1479 )"""
1480 args = {'pk': self.pk_obj}
1481
1482 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
1483 return rows[0][0]
1484
1485 is_in_use_by_patients = property(_get_is_in_use_by_patients, lambda x:x)
1486
1488 cmd = u"""
1489 SELECT EXISTS (
1490 SELECT 1
1491 FROM ref.lnk_substance2brand
1492 WHERE fk_substance = %(pk)s
1493 LIMIT 1
1494 )"""
1495 args = {'pk': self.pk_obj}
1496
1497 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
1498 return rows[0][0]
1499
1500 is_drug_component = property(_get_is_drug_component, lambda x:x)
1501
1510
1512
1513 substance = substance
1514 if atc is not None:
1515 atc = atc.strip()
1516
1517 converted, amount = gmTools.input2decimal(amount)
1518 if not converted:
1519 raise ValueError('<amount> must be a number: %s (%s)', amount, type(amount))
1520
1521 args = {
1522 'desc': substance.strip(),
1523 'amount': amount,
1524 'unit': unit.strip(),
1525 'atc': atc
1526 }
1527 cmd = u"""
1528 SELECT pk FROM ref.consumable_substance
1529 WHERE
1530 lower(description) = lower(%(desc)s)
1531 AND
1532 amount = %(amount)s
1533 AND
1534 unit = %(unit)s
1535 """
1536 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}])
1537
1538 if len(rows) == 0:
1539 cmd = u"""
1540 INSERT INTO ref.consumable_substance (description, atc_code, amount, unit) VALUES (
1541 %(desc)s,
1542 gm.nullify_empty_string(%(atc)s),
1543 %(amount)s,
1544 gm.nullify_empty_string(%(unit)s)
1545 ) RETURNING pk"""
1546 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True, get_col_idx = False)
1547
1548 gmATC.propagate_atc(substance = substance, atc = atc)
1549
1550 return cConsumableSubstance(aPK_obj = rows[0]['pk'])
1551
1553 args = {'pk': substance}
1554 cmd = u"""
1555 DELETE FROM ref.consumable_substance
1556 WHERE
1557 pk = %(pk)s
1558 AND
1559
1560 -- must not currently be used with a patient
1561 NOT EXISTS (
1562 SELECT 1
1563 FROM clin.v_pat_substance_intake
1564 WHERE pk_substance = %(pk)s
1565 LIMIT 1
1566 )
1567 AND
1568
1569 -- must not currently be used with a branded drug
1570 NOT EXISTS (
1571 SELECT 1
1572 FROM ref.lnk_substance2brand
1573 WHERE fk_substance = %(pk)s
1574 LIMIT 1
1575 )"""
1576 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
1577 return True
1578
1580
1581 _pattern = regex.compile(r'^\D+\s*\d+$', regex.UNICODE | regex.LOCALE)
1582 _query1 = u"""
1583 SELECT
1584 pk::text,
1585 (description || ' ' || amount || ' ' || unit) as subst
1586 FROM ref.consumable_substance
1587 WHERE description %(fragment_condition)s
1588 ORDER BY subst
1589 LIMIT 50"""
1590 _query2 = u"""
1591 SELECT
1592 pk::text,
1593 (description || ' ' || amount || ' ' || unit) as subst
1594 FROM ref.consumable_substance
1595 WHERE
1596 %(fragment_condition)s
1597 ORDER BY subst
1598 LIMIT 50"""
1599
1600
1602 """Return matches for aFragment at start of phrases."""
1603
1604 if cSubstanceMatchProvider._pattern.match(aFragment):
1605 self._queries = [cSubstanceMatchProvider._query2]
1606 fragment_condition = """description ILIKE %(desc)s
1607 AND
1608 amount::text ILIKE %(amount)s"""
1609 self._args['desc'] = u'%s%%' % regex.sub(r'\s*\d+$', u'', aFragment)
1610 self._args['amount'] = u'%s%%' % regex.sub(r'^\D+\s*', u'', aFragment)
1611 else:
1612 self._queries = [cSubstanceMatchProvider._query1]
1613 fragment_condition = u"ILIKE %(fragment)s"
1614 self._args['fragment'] = u"%s%%" % aFragment
1615
1616 return self._find_matches(fragment_condition)
1617
1619 """Return matches for aFragment at start of words inside phrases."""
1620
1621 if cSubstanceMatchProvider._pattern.match(aFragment):
1622 self._queries = [cSubstanceMatchProvider._query2]
1623
1624 desc = regex.sub(r'\s*\d+$', u'', aFragment)
1625 desc = gmPG2.sanitize_pg_regex(expression = desc, escape_all = False)
1626
1627 fragment_condition = """description ~* %(desc)s
1628 AND
1629 amount::text ILIKE %(amount)s"""
1630
1631 self._args['desc'] = u"( %s)|(^%s)" % (desc, desc)
1632 self._args['amount'] = u'%s%%' % regex.sub(r'^\D+\s*', u'', aFragment)
1633 else:
1634 self._queries = [cSubstanceMatchProvider._query1]
1635 fragment_condition = u"~* %(fragment)s"
1636 aFragment = gmPG2.sanitize_pg_regex(expression = aFragment, escape_all = False)
1637 self._args['fragment'] = u"( %s)|(^%s)" % (aFragment, aFragment)
1638
1639 return self._find_matches(fragment_condition)
1640
1642 """Return matches for aFragment as a true substring."""
1643
1644 if cSubstanceMatchProvider._pattern.match(aFragment):
1645 self._queries = [cSubstanceMatchProvider._query2]
1646 fragment_condition = """description ILIKE %(desc)s
1647 AND
1648 amount::text ILIKE %(amount)s"""
1649 self._args['desc'] = u'%%%s%%' % regex.sub(r'\s*\d+$', u'', aFragment)
1650 self._args['amount'] = u'%s%%' % regex.sub(r'^\D+\s*', u'', aFragment)
1651 else:
1652 self._queries = [cSubstanceMatchProvider._query1]
1653 fragment_condition = u"ILIKE %(fragment)s"
1654 self._args['fragment'] = u"%%%s%%" % aFragment
1655
1656 return self._find_matches(fragment_condition)
1657
1658 -class cSubstanceIntakeEntry(gmBusinessDBObject.cBusinessDBObject):
1659 """Represents a substance currently taken by a patient."""
1660
1661 _cmd_fetch_payload = u"SELECT * FROM clin.v_pat_substance_intake WHERE pk_substance_intake = %s"
1662 _cmds_store_payload = [
1663 u"""UPDATE clin.substance_intake SET
1664 clin_when = %(started)s,
1665 discontinued = %(discontinued)s,
1666 discontinue_reason = gm.nullify_empty_string(%(discontinue_reason)s),
1667 schedule = gm.nullify_empty_string(%(schedule)s),
1668 aim = gm.nullify_empty_string(%(aim)s),
1669 narrative = gm.nullify_empty_string(%(notes)s),
1670 intake_is_approved_of = %(intake_is_approved_of)s,
1671 fk_episode = %(pk_episode)s,
1672
1673 preparation = (
1674 case
1675 when %(pk_brand)s is NULL then %(preparation)s
1676 else NULL
1677 end
1678 )::text,
1679
1680 is_long_term = (
1681 case
1682 when (
1683 (%(is_long_term)s is False)
1684 and
1685 (%(duration)s is NULL)
1686 ) is True then null
1687 else %(is_long_term)s
1688 end
1689 )::boolean,
1690
1691 duration = (
1692 case
1693 when %(is_long_term)s is True then null
1694 else %(duration)s
1695 end
1696 )::interval
1697 WHERE
1698 pk = %(pk_substance_intake)s
1699 AND
1700 xmin = %(xmin_substance_intake)s
1701 RETURNING
1702 xmin as xmin_substance_intake
1703 """
1704 ]
1705 _updatable_fields = [
1706 u'started',
1707 u'discontinued',
1708 u'discontinue_reason',
1709 u'preparation',
1710 u'intake_is_approved_of',
1711 u'schedule',
1712 u'duration',
1713 u'aim',
1714 u'is_long_term',
1715 u'notes',
1716 u'pk_episode'
1717 ]
1718
1719 - def format(self, left_margin=0, date_format='%Y %B %d', one_line=True, allergy=None, show_all_brand_components=False):
1720 if one_line:
1721 return self.format_as_one_line(left_margin = left_margin, date_format = date_format)
1722
1723 return self.format_as_multiple_lines (
1724 left_margin = left_margin,
1725 date_format = date_format,
1726 allergy = allergy,
1727 show_all_brand_components = show_all_brand_components
1728 )
1729
1731
1732 if self._payload[self._idx['duration']] is None:
1733 duration = gmTools.bool2subst (
1734 self._payload[self._idx['is_long_term']],
1735 _('long-term'),
1736 _('short-term'),
1737 _('?short-term')
1738 )
1739 else:
1740 duration = gmDateTime.format_interval (
1741 self._payload[self._idx['duration']],
1742 accuracy_wanted = gmDateTime.acc_days
1743 )
1744
1745 line = u'%s%s (%s %s): %s %s%s %s (%s)' % (
1746 u' ' * left_margin,
1747 self._payload[self._idx['started']].strftime(date_format),
1748 gmTools.u_right_arrow,
1749 duration,
1750 self._payload[self._idx['substance']],
1751 self._payload[self._idx['amount']],
1752 self._payload[self._idx['unit']],
1753 self._payload[self._idx['preparation']],
1754 gmTools.bool2subst(self._payload[self._idx['is_currently_active']], _('ongoing'), _('inactive'), _('?ongoing'))
1755 )
1756
1757 return line
1758
1759 - def format_as_multiple_lines(self, left_margin=0, date_format='%Y %B %d', allergy=None, show_all_brand_components=False):
1760
1761 txt = _('Substance intake entry (%s, %s) [#%s] \n') % (
1762 gmTools.bool2subst (
1763 boolean = self._payload[self._idx['is_currently_active']],
1764 true_return = gmTools.bool2subst (
1765 boolean = self._payload[self._idx['seems_inactive']],
1766 true_return = _('active, needs check'),
1767 false_return = _('active'),
1768 none_return = _('assumed active')
1769 ),
1770 false_return = _('inactive')
1771 ),
1772 gmTools.bool2subst (
1773 boolean = self._payload[self._idx['intake_is_approved_of']],
1774 true_return = _('approved'),
1775 false_return = _('unapproved')
1776 ),
1777 self._payload[self._idx['pk_substance_intake']]
1778 )
1779
1780 if allergy is not None:
1781 certainty = gmTools.bool2subst(allergy['definite'], _('definite'), _('suspected'))
1782 txt += u'\n'
1783 txt += u' !! ---- Cave ---- !!\n'
1784 txt += u' %s (%s): %s (%s)\n' % (
1785 allergy['l10n_type'],
1786 certainty,
1787 allergy['descriptor'],
1788 gmTools.coalesce(allergy['reaction'], u'')[:40]
1789 )
1790 txt += u'\n'
1791
1792 txt += u' ' + _('Substance: %s [#%s]\n') % (self._payload[self._idx['substance']], self._payload[self._idx['pk_substance']])
1793 txt += u' ' + _('Preparation: %s\n') % self._payload[self._idx['preparation']]
1794 txt += u' ' + _('Amount per dose: %s %s') % (self._payload[self._idx['amount']], self._payload[self._idx['unit']])
1795 if self.ddd is not None:
1796 txt += u' (DDD: %s %s)' % (self.ddd['ddd'], self.ddd['unit'])
1797 txt += u'\n'
1798 txt += gmTools.coalesce(self._payload[self._idx['atc_substance']], u'', _(' ATC (substance): %s\n'))
1799
1800 txt += u'\n'
1801
1802 txt += gmTools.coalesce (
1803 self._payload[self._idx['brand']],
1804 u'',
1805 _(' Brand name: %%s [#%s]\n') % self._payload[self._idx['pk_brand']]
1806 )
1807 txt += gmTools.coalesce(self._payload[self._idx['atc_brand']], u'', _(' ATC (brand): %s\n'))
1808 if show_all_brand_components and (self._payload[self._idx['pk_brand']] is not None):
1809 brand = self.containing_drug
1810 if len(brand['pk_substances']) > 1:
1811 for comp in brand['components']:
1812 if comp.startswith(self._payload[self._idx['substance']] + u'::'):
1813 continue
1814 txt += _(' Other component: %s\n') % comp
1815
1816 txt += u'\n'
1817
1818 txt += gmTools.coalesce(self._payload[self._idx['schedule']], u'', _(' Regimen: %s\n'))
1819
1820 if self._payload[self._idx['is_long_term']]:
1821 duration = u' %s %s' % (gmTools.u_right_arrow, gmTools.u_infinity)
1822 else:
1823 if self._payload[self._idx['duration']] is None:
1824 duration = u''
1825 else:
1826 duration = u' %s %s' % (gmTools.u_right_arrow, gmDateTime.format_interval(self._payload[self._idx['duration']], gmDateTime.acc_days))
1827
1828 txt += _(' Started %s%s%s\n') % (
1829 gmDateTime.pydt_strftime (
1830 self._payload[self._idx['started']],
1831 format = date_format,
1832 accuracy = gmDateTime.acc_days
1833 ),
1834 duration,
1835 gmTools.bool2subst(self._payload[self._idx['is_long_term']], _(' (long-term)'), _(' (short-term)'), u'')
1836 )
1837
1838 if self._payload[self._idx['discontinued']] is not None:
1839 txt += _(' Discontinued %s\n') % (
1840 gmDateTime.pydt_strftime (
1841 self._payload[self._idx['discontinued']],
1842 format = date_format,
1843 accuracy = gmDateTime.acc_days
1844 )
1845 )
1846 txt += _(' Reason: %s\n') % self._payload[self._idx['discontinue_reason']]
1847
1848 txt += u'\n'
1849
1850 txt += gmTools.coalesce(self._payload[self._idx['aim']], u'', _(' Aim: %s\n'))
1851 txt += gmTools.coalesce(self._payload[self._idx['episode']], u'', _(' Episode: %s\n'))
1852 txt += gmTools.coalesce(self._payload[self._idx['health_issue']], u'', _(' Health issue: %s\n'))
1853 txt += gmTools.coalesce(self._payload[self._idx['notes']], u'', _(' Advice: %s\n'))
1854
1855 txt += u'\n'
1856
1857 txt += _(u'Revision: #%(row_ver)s, %(mod_when)s by %(mod_by)s.') % {
1858 'row_ver': self._payload[self._idx['row_version']],
1859 'mod_when': gmDateTime.pydt_strftime(self._payload[self._idx['modified_when']]),
1860 'mod_by': self._payload[self._idx['modified_by']]
1861 }
1862
1863 return txt
1864
1865 - def turn_into_allergy(self, encounter_id=None, allergy_type='allergy'):
1866 allg = gmAllergy.create_allergy (
1867 allergene = self._payload[self._idx['substance']],
1868 allg_type = allergy_type,
1869 episode_id = self._payload[self._idx['pk_episode']],
1870 encounter_id = encounter_id
1871 )
1872 allg['substance'] = gmTools.coalesce (
1873 self._payload[self._idx['brand']],
1874 self._payload[self._idx['substance']]
1875 )
1876 allg['reaction'] = self._payload[self._idx['discontinue_reason']]
1877 allg['atc_code'] = gmTools.coalesce(self._payload[self._idx['atc_substance']], self._payload[self._idx['atc_brand']])
1878 if self._payload[self._idx['external_code_brand']] is not None:
1879 allg['substance_code'] = u'%s::::%s' % (self._payload[self._idx['external_code_type_brand']], self._payload[self._idx['external_code_brand']])
1880
1881 if self._payload[self._idx['pk_brand']] is None:
1882 allg['generics'] = self._payload[self._idx['substance']]
1883 else:
1884 comps = [ c['substance'] for c in self.containing_drug.components ]
1885 if len(comps) == 0:
1886 allg['generics'] = self._payload[self._idx['substance']]
1887 else:
1888 allg['generics'] = u'; '.join(comps)
1889
1890 allg.save()
1891 return allg
1892
1893
1894
1895 - def _get_ddd(self):
1896
1897 try: self.__ddd
1898 except AttributeError: self.__ddd = None
1899
1900 if self.__ddd is not None:
1901 return self.__ddd
1902
1903 if self._payload[self._idx['atc_substance']] is not None:
1904 ddd = gmATC.atc2ddd(atc = self._payload[self._idx['atc_substance']])
1905 if len(ddd) != 0:
1906 self.__ddd = ddd[0]
1907 else:
1908 if self._payload[self._idx['atc_brand']] is not None:
1909 ddd = gmATC.atc2ddd(atc = self._payload[self._idx['atc_brand']])
1910 if len(ddd) != 0:
1911 self.__ddd = ddd[0]
1912
1913 return self.__ddd
1914
1915 ddd = property(_get_ddd, lambda x:x)
1916
1918 drug = self.containing_drug
1919
1920 if drug is None:
1921 return None
1922
1923 return drug.external_code
1924
1925 external_code = property(_get_external_code, lambda x:x)
1926
1928 drug = self.containing_drug
1929
1930 if drug is None:
1931 return None
1932
1933 return drug.external_code_type
1934
1935 external_code_type = property(_get_external_code_type, lambda x:x)
1936
1938 if self._payload[self._idx['pk_brand']] is None:
1939 return None
1940
1941 return cBrandedDrug(aPK_obj = self._payload[self._idx['pk_brand']])
1942
1943 containing_drug = property(_get_containing_drug, lambda x:x)
1944
1946 tests = [
1947
1948 ' 1-1-1-1 ',
1949
1950 '1-1-1-1',
1951 '22-1-1-1',
1952 '1/3-1-1-1',
1953 '/4-1-1-1'
1954 ]
1955 pattern = "^(\d\d|/\d|\d/\d|\d)[\s-]{1,5}\d{0,2}[\s-]{1,5}\d{0,2}[\s-]{1,5}\d{0,2}$"
1956 for test in tests:
1957 print test.strip(), ":", regex.match(pattern, test.strip())
1958
1960 args = {'comp': pk_component, 'subst': pk_substance, 'pat': pk_identity}
1961
1962 where_clause = u"""
1963 fk_encounter IN (
1964 SELECT pk FROM clin.encounter WHERE fk_patient = %(pat)s
1965 )
1966 AND
1967 """
1968
1969 if pk_substance is not None:
1970 where_clause += u'fk_substance = %(subst)s'
1971 if pk_component is not None:
1972 where_clause += u'fk_drug_component = %(comp)s'
1973
1974 cmd = u"""SELECT exists (
1975 SELECT 1 FROM clin.substance_intake
1976 WHERE
1977 %s
1978 LIMIT 1
1979 )""" % where_clause
1980
1981 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}])
1982 return rows[0][0]
1983
1984 -def create_substance_intake(pk_substance=None, pk_component=None, preparation=None, encounter=None, episode=None):
1985
1986 args = {
1987 'enc': encounter,
1988 'epi': episode,
1989 'comp': pk_component,
1990 'subst': pk_substance,
1991 'prep': preparation
1992 }
1993
1994 if pk_component is None:
1995 cmd = u"""
1996 INSERT INTO clin.substance_intake (
1997 fk_encounter,
1998 fk_episode,
1999 intake_is_approved_of,
2000 fk_substance,
2001 preparation
2002 ) VALUES (
2003 %(enc)s,
2004 %(epi)s,
2005 False,
2006 %(subst)s,
2007 %(prep)s
2008 )
2009 RETURNING pk"""
2010 else:
2011 cmd = u"""
2012 INSERT INTO clin.substance_intake (
2013 fk_encounter,
2014 fk_episode,
2015 intake_is_approved_of,
2016 fk_drug_component
2017 ) VALUES (
2018 %(enc)s,
2019 %(epi)s,
2020 False,
2021 %(comp)s
2022 )
2023 RETURNING pk"""
2024
2025 try:
2026 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True)
2027 except gmPG2.dbapi.InternalError, e:
2028 if e.pgerror is None:
2029 raise
2030 if 'prevent_duplicate_component' in e.pgerror:
2031 _log.exception('will not create duplicate substance intake entry')
2032 _log.error(e.pgerror)
2033 return None
2034 raise
2035
2036 return cSubstanceIntakeEntry(aPK_obj = rows[0][0])
2037
2041
2080
2081
2152
2153 _SQL_get_drug_components = u'SELECT * FROM ref.v_drug_components WHERE %s'
2154
2156
2157 _cmd_fetch_payload = _SQL_get_drug_components % u'pk_component = %s'
2158 _cmds_store_payload = [
2159 u"""UPDATE ref.lnk_substance2brand SET
2160 fk_brand = %(pk_brand)s,
2161 fk_substance = %(pk_consumable_substance)s
2162 WHERE
2163 NOT EXISTS (
2164 SELECT 1
2165 FROM clin.substance_intake
2166 WHERE fk_drug_component = %(pk_component)s
2167 LIMIT 1
2168 )
2169 AND
2170 pk = %(pk_component)s
2171 AND
2172 xmin = %(xmin_lnk_substance2brand)s
2173 RETURNING
2174 xmin AS xmin_lnk_substance2brand
2175 """
2176 ]
2177 _updatable_fields = [
2178 u'pk_brand',
2179 u'pk_consumable_substance'
2180 ]
2181
2182
2183
2185 return cBrandedDrug(aPK_obj = self._payload[self._idx['pk_brand']])
2186
2187 containing_drug = property(_get_containing_drug, lambda x:x)
2188
2190 return self._payload[self._idx['is_in_use']]
2191
2192 is_in_use_by_patients = property(_get_is_in_use_by_patients, lambda x:x)
2193
2196
2197 substance = property(_get_substance, lambda x:x)
2198
2203
2205
2206 _pattern = regex.compile(r'^\D+\s*\d+$', regex.UNICODE | regex.LOCALE)
2207 _query_desc_only = u"""
2208 SELECT DISTINCT ON (component)
2209 pk_component,
2210 (substance || ' ' || amount || unit || ' ' || preparation || ' (' || brand || ')')
2211 AS component
2212 FROM ref.v_drug_components
2213 WHERE
2214 substance %(fragment_condition)s
2215 OR
2216 brand %(fragment_condition)s
2217 ORDER BY component
2218 LIMIT 50"""
2219 _query_desc_and_amount = u"""
2220
2221 SELECT DISTINCT ON (component)
2222 pk_component,
2223 (substance || ' ' || amount || unit || ' ' || preparation || ' (' || brand || ')')
2224 AS component
2225 FROM ref.v_drug_components
2226 WHERE
2227 %(fragment_condition)s
2228 ORDER BY component
2229 LIMIT 50"""
2230
2232 """Return matches for aFragment at start of phrases."""
2233
2234 if cDrugComponentMatchProvider._pattern.match(aFragment):
2235 self._queries = [cDrugComponentMatchProvider._query_desc_and_amount]
2236 fragment_condition = """(substance ILIKE %(desc)s OR brand ILIKE %(desc)s)
2237 AND
2238 amount::text ILIKE %(amount)s"""
2239 self._args['desc'] = u'%s%%' % regex.sub(r'\s*\d+$', u'', aFragment)
2240 self._args['amount'] = u'%s%%' % regex.sub(r'^\D+\s*', u'', aFragment)
2241 else:
2242 self._queries = [cDrugComponentMatchProvider._query_desc_only]
2243 fragment_condition = u"ILIKE %(fragment)s"
2244 self._args['fragment'] = u"%s%%" % aFragment
2245
2246 return self._find_matches(fragment_condition)
2247
2249 """Return matches for aFragment at start of words inside phrases."""
2250
2251 if cDrugComponentMatchProvider._pattern.match(aFragment):
2252 self._queries = [cDrugComponentMatchProvider._query_desc_and_amount]
2253
2254 desc = regex.sub(r'\s*\d+$', u'', aFragment)
2255 desc = gmPG2.sanitize_pg_regex(expression = desc, escape_all = False)
2256
2257 fragment_condition = """(substance ~* %(desc)s OR brand ~* %(desc)s)
2258 AND
2259 amount::text ILIKE %(amount)s"""
2260
2261 self._args['desc'] = u"( %s)|(^%s)" % (desc, desc)
2262 self._args['amount'] = u'%s%%' % regex.sub(r'^\D+\s*', u'', aFragment)
2263 else:
2264 self._queries = [cDrugComponentMatchProvider._query_desc_only]
2265 fragment_condition = u"~* %(fragment)s"
2266 aFragment = gmPG2.sanitize_pg_regex(expression = aFragment, escape_all = False)
2267 self._args['fragment'] = u"( %s)|(^%s)" % (aFragment, aFragment)
2268
2269 return self._find_matches(fragment_condition)
2270
2272 """Return matches for aFragment as a true substring."""
2273
2274 if cDrugComponentMatchProvider._pattern.match(aFragment):
2275 self._queries = [cDrugComponentMatchProvider._query_desc_and_amount]
2276 fragment_condition = """(substance ILIKE %(desc)s OR brand ILIKE %(desc)s)
2277 AND
2278 amount::text ILIKE %(amount)s"""
2279 self._args['desc'] = u'%%%s%%' % regex.sub(r'\s*\d+$', u'', aFragment)
2280 self._args['amount'] = u'%s%%' % regex.sub(r'^\D+\s*', u'', aFragment)
2281 else:
2282 self._queries = [cDrugComponentMatchProvider._query_desc_only]
2283 fragment_condition = u"ILIKE %(fragment)s"
2284 self._args['fragment'] = u"%%%s%%" % aFragment
2285
2286 return self._find_matches(fragment_condition)
2287
2288
2290 """Represents a drug as marketed by a manufacturer."""
2291
2292 _cmd_fetch_payload = u"SELECT * FROM ref.v_branded_drugs WHERE pk_brand = %s"
2293 _cmds_store_payload = [
2294 u"""UPDATE ref.branded_drug SET
2295 description = %(brand)s,
2296 preparation = %(preparation)s,
2297 atc_code = gm.nullify_empty_string(%(atc)s),
2298 external_code = gm.nullify_empty_string(%(external_code)s),
2299 external_code_type = gm.nullify_empty_string(%(external_code_type)s),
2300 is_fake = %(is_fake_brand)s,
2301 fk_data_source = %(pk_data_source)s
2302 WHERE
2303 pk = %(pk_brand)s
2304 AND
2305 xmin = %(xmin_branded_drug)s
2306 RETURNING
2307 xmin AS xmin_branded_drug
2308 """
2309 ]
2310 _updatable_fields = [
2311 u'brand',
2312 u'preparation',
2313 u'atc',
2314 u'is_fake_brand',
2315 u'external_code',
2316 u'external_code_type',
2317 u'pk_data_source'
2318 ]
2319
2321 success, data = super(self.__class__, self).save_payload(conn = conn)
2322
2323 if not success:
2324 return (success, data)
2325
2326 if self._payload[self._idx['atc']] is not None:
2327 atc = self._payload[self._idx['atc']].strip()
2328 if atc != u'':
2329 gmATC.propagate_atc (
2330 substance = self._payload[self._idx['brand']].strip(),
2331 atc = atc
2332 )
2333
2334 return (success, data)
2335
2337
2338 if self.is_in_use_by_patients:
2339 return False
2340
2341 pk_substances2keep = [ s['pk'] for s in substances ]
2342 args = {'brand': self._payload[self._idx['pk_brand']]}
2343 queries = []
2344
2345
2346 cmd = u"""
2347 INSERT INTO ref.lnk_substance2brand (
2348 fk_brand,
2349 fk_substance
2350 )
2351 SELECT
2352 %(brand)s,
2353 %(subst)s
2354 WHERE NOT EXISTS (
2355 SELECT 1
2356 FROM ref.lnk_substance2brand
2357 WHERE
2358 fk_brand = %(brand)s
2359 AND
2360 fk_substance = %(subst)s
2361 )"""
2362 for pk in pk_substances2keep:
2363 args['subst'] = pk
2364 queries.append({'cmd': cmd, 'args': args})
2365
2366
2367 args['substances2keep'] = tuple(pk_substances2keep)
2368 cmd = u"""
2369 DELETE FROM ref.lnk_substance2brand
2370 WHERE
2371 fk_brand = %(brand)s
2372 AND
2373 fk_substance NOT IN %(substances2keep)s"""
2374 queries.append({'cmd': cmd, 'args': args})
2375
2376 gmPG2.run_rw_queries(queries = queries)
2377 self.refetch_payload()
2378
2379 return True
2380
2381 - def add_component(self, substance=None, atc=None, amount=None, unit=None, pk_substance=None):
2382
2383 args = {
2384 'brand': self.pk_obj,
2385 'subst': substance,
2386 'atc': atc,
2387 'pk_subst': pk_substance
2388 }
2389
2390 if pk_substance is None:
2391 consumable = create_consumable_substance(substance = substance, atc = atc, amount = amount, unit = unit)
2392 args['pk_subst'] = consumable['pk']
2393
2394
2395 cmd = u"""
2396 SELECT pk_component
2397 FROM ref.v_drug_components
2398 WHERE
2399 pk_brand = %(brand)s
2400 AND
2401 ((
2402 (lower(substance) = lower(%(subst)s))
2403 OR
2404 (lower(atc_substance) = lower(%(atc)s))
2405 OR
2406 (pk_consumable_substance = %(pk_subst)s)
2407 ) IS TRUE)
2408 """
2409 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
2410
2411 if len(rows) > 0:
2412 return
2413
2414
2415 cmd = u"""
2416 INSERT INTO ref.lnk_substance2brand (fk_brand, fk_substance)
2417 VALUES (%(brand)s, %(pk_subst)s)
2418 """
2419 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
2420 self.refetch_payload()
2421
2423 if len(self._payload[self._idx['components']]) == 1:
2424 _log.error('cannot remove the only component of a drug')
2425 return False
2426
2427 args = {'brand': self.pk_obj, 'comp': substance}
2428 cmd = u"""
2429 DELETE FROM ref.lnk_substance2brand
2430 WHERE
2431 fk_brand = %(brand)s
2432 AND
2433 fk_substance = %(comp)s
2434 AND
2435 NOT EXISTS (
2436 SELECT 1
2437 FROM clin.substance_intake
2438 WHERE fk_drug_component = %(comp)s
2439 LIMIT 1
2440 )
2441 """
2442 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
2443 self.refetch_payload()
2444
2445 return True
2446
2447
2448
2450 if self._payload[self._idx['external_code']] is None:
2451 return None
2452
2453 return self._payload[self._idx['external_code']]
2454
2455 external_code = property(_get_external_code, lambda x:x)
2456
2458
2459
2460 if self._payload[self._idx['external_code_type']] is None:
2461 return None
2462
2463 return self._payload[self._idx['external_code_type']]
2464
2465 external_code_type = property(_get_external_code_type, lambda x:x)
2466
2468 cmd = _SQL_get_drug_components % u'pk_brand = %(brand)s'
2469 args = {'brand': self._payload[self._idx['pk_brand']]}
2470 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
2471 return [ cDrugComponent(row = {'data': r, 'idx': idx, 'pk_field': 'pk_component'}) for r in rows ]
2472
2473 components = property(_get_components, lambda x:x)
2474
2476 if self._payload[self._idx['pk_substances']] is None:
2477 return []
2478 cmd = _SQL_get_consumable_substance % u'pk IN %(pks)s'
2479 args = {'pks': tuple(self._payload[self._idx['pk_substances']])}
2480 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
2481 return [ cConsumableSubstance(row = {'data': r, 'idx': idx, 'pk_field': 'pk'}) for r in rows ]
2482
2483 components_as_substances = property(_get_components_as_substances, lambda x:x)
2484
2486 cmd = u'SELECT EXISTS (SELECT 1 FROM clin.vaccine WHERE fk_brand = %(fk_brand)s)'
2487 args = {'fk_brand': self._payload[self._idx['pk_brand']]}
2488 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
2489 return rows[0][0]
2490
2491 is_vaccine = property(_get_is_vaccine, lambda x:x)
2492
2494 cmd = u"""
2495 SELECT EXISTS (
2496 SELECT 1
2497 FROM clin.substance_intake
2498 WHERE
2499 fk_drug_component IS NOT NULL
2500 AND
2501 fk_drug_component IN (
2502 SELECT r_ls2b.pk
2503 FROM ref.lnk_substance2brand r_ls2b
2504 WHERE fk_brand = %(pk)s
2505 )
2506 LIMIT 1
2507 )"""
2508 args = {'pk': self.pk_obj}
2509
2510 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
2511 return rows[0][0]
2512
2513 is_in_use_by_patients = property(_get_is_in_use_by_patients, lambda x:x)
2514
2516 cmd = u'SELECT pk FROM ref.branded_drug ORDER BY description'
2517 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = False)
2518 return [ cBrandedDrug(aPK_obj = r['pk']) for r in rows ]
2519
2521 args = {'brand': brand_name, 'prep': preparation}
2522
2523 cmd = u'SELECT pk FROM ref.branded_drug WHERE lower(description) = lower(%(brand)s) AND lower(preparation) = lower(%(prep)s)'
2524 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
2525
2526 if len(rows) == 0:
2527 return None
2528
2529 return cBrandedDrug(aPK_obj = rows[0]['pk'])
2530
2532
2533 if preparation is None:
2534 preparation = _('units')
2535
2536 if preparation.strip() == u'':
2537 preparation = _('units')
2538
2539 if return_existing:
2540 drug = get_drug_by_brand(brand_name = brand_name, preparation = preparation)
2541 if drug is not None:
2542 return drug
2543
2544 cmd = u'INSERT INTO ref.branded_drug (description, preparation) VALUES (%(brand)s, %(prep)s) RETURNING pk'
2545 args = {'brand': brand_name, 'prep': preparation}
2546 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True, get_col_idx = False)
2547
2548 return cBrandedDrug(aPK_obj = rows[0]['pk'])
2549
2551 queries = []
2552 args = {'pk': brand}
2553
2554
2555 cmd = u"""
2556 DELETE FROM ref.lnk_substance2brand
2557 WHERE
2558 fk_brand = %(pk)s
2559 AND
2560 NOT EXISTS (
2561 SELECT 1
2562 FROM clin.v_pat_substance_intake
2563 WHERE pk_brand = %(pk)s
2564 LIMIT 1
2565 )
2566 """
2567 queries.append({'cmd': cmd, 'args': args})
2568
2569
2570 cmd = u"""
2571 DELETE FROM ref.branded_drug
2572 WHERE
2573 pk = %(pk)s
2574 AND
2575 NOT EXISTS (
2576 SELECT 1
2577 FROM clin.v_pat_substance_intake
2578 WHERE pk_brand = %(pk)s
2579 LIMIT 1
2580 )
2581 """
2582 queries.append({'cmd': cmd, 'args': args})
2583
2584 gmPG2.run_rw_queries(queries = queries)
2585
2586
2587
2588 if __name__ == "__main__":
2589
2590 if len(sys.argv) < 2:
2591 sys.exit()
2592
2593 if sys.argv[1] != 'test':
2594 sys.exit()
2595
2596 from Gnumed.pycommon import gmLog2
2597 from Gnumed.pycommon import gmI18N
2598 from Gnumed.business import gmPerson
2599
2600 gmI18N.activate_locale()
2601
2602
2608
2610 mmi_file = cGelbeListeCSVFile(filename = sys.argv[2])
2611 for drug in mmi_file:
2612 print "-------------"
2613 print '"%s" (ATC: %s / PZN: %s)' % (drug['name'], drug['atc'], drug['pzn'])
2614 for stoff in drug['wirkstoffe']:
2615 print " Wirkstoff:", stoff
2616 raw_input()
2617 if mmi_file.has_unknown_fields is not None:
2618 print "has extra data under [%s]" % gmTools.default_csv_reader_rest_key
2619 for key in mmi_file.csv_fieldnames:
2620 print key, '->', drug[key]
2621 raw_input()
2622 mmi_file.close()
2623
2627
2629 mmi = cGelbeListeWineInterface()
2630 mmi_file = mmi.__let_user_select_drugs()
2631 for drug in mmi_file:
2632 print "-------------"
2633 print '"%s" (ATC: %s / PZN: %s)' % (drug['name'], drug['atc'], drug['pzn'])
2634 for stoff in drug['wirkstoffe']:
2635 print " Wirkstoff:", stoff
2636 print drug
2637 mmi_file.close()
2638
2642
2644 mmi = cGelbeListeInterface()
2645 print mmi
2646 print "interface definition:", mmi.version
2647
2648 diclofenac = '7587712'
2649 phenprocoumon = '4421744'
2650 mmi.check_interactions(drug_ids_list = [diclofenac, phenprocoumon])
2651
2652
2653
2660
2666
2667
2668
2670 drug = create_substance_intake (
2671 pk_component = 2,
2672 encounter = 1,
2673 episode = 1
2674 )
2675 print drug
2676
2681
2685
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698 test_fd_switch_to()
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709