1
2 """Medication handling code.
3
4 license: GPL
5 """
6
7 __version__ = "$Revision: 1.21 $"
8 __author__ = "K.Hilbert <Karsten.Hilbert@gmx.net>"
9
10 import sys
11 import logging
12 import csv
13 import codecs
14 import os
15 import re as regex
16 import subprocess
17 import decimal
18 from xml.etree import ElementTree as etree
19
20
21 if __name__ == '__main__':
22 sys.path.insert(0, '../../')
23 _ = lambda x:x
24 from Gnumed.pycommon import gmBusinessDBObject, gmPG2, gmShellAPI, gmTools
25 from Gnumed.pycommon import gmDispatcher, gmDateTime, gmHooks
26 from Gnumed.pycommon import gmMatchProvider
27
28 from Gnumed.business import gmATC
29 from Gnumed.business import gmAllergy
30 from Gnumed.business.gmDocuments import DOCUMENT_TYPE_PRESCRIPTION
31 from Gnumed.business.gmDocuments import create_document_type
32
33
34 _log = logging.getLogger('gm.meds')
35 _log.info(__version__)
36
37
38 DEFAULT_MEDICATION_HISTORY_EPISODE = _('Medication history')
39
43
44 gmDispatcher.connect(_on_substance_intake_modified, u'substance_intake_mod_db')
45
46
48
49 if search_term is None:
50 return u'http://www.dosing.de'
51
52 terms = []
53 names = []
54
55 if isinstance(search_term, cBrandedDrug):
56 if search_term['atc_code'] is not None:
57 terms.append(search_term['atc_code'])
58
59 elif isinstance(search_term, cSubstanceIntakeEntry):
60 names.append(search_term['substance'])
61 if search_term['atc_brand'] is not None:
62 terms.append(search_term['atc_brand'])
63 if search_term['atc_substance'] is not None:
64 terms.append(search_term['atc_substance'])
65
66 elif search_term is not None:
67 names.append(u'%s' % search_term)
68 terms.extend(gmATC.text2atc(text = u'%s' % search_term, fuzzy = True))
69
70 for name in names:
71 if name.endswith('e'):
72 terms.append(name[:-1])
73 else:
74 terms.append(name)
75
76
77
78
79 url_template = u'http://www.google.de/search?hl=de&source=hp&q=site%%3Adosing.de+%s&btnG=Google-Suche'
80 url = url_template % u'+OR+'.join(terms)
81
82 _log.debug(u'renal insufficiency URL: %s', url)
83
84 return url
85
86
87 -def create_data_source(long_name=None, short_name=None, version=None, source=None, language=None):
88
89 args = {
90 'lname': long_name,
91 'sname': short_name,
92 'ver': version,
93 'src': source,
94 'lang': language
95 }
96
97 cmd = u"""select pk from ref.data_source where name_long = %(lname)s and name_short = %(sname)s and version = %(ver)s"""
98 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}])
99 if len(rows) > 0:
100 return rows[0]['pk']
101
102 cmd = u"""
103 INSERT INTO ref.data_source (name_long, name_short, version, source, lang)
104 VALUES (
105 %(lname)s,
106 %(sname)s,
107 %(ver)s,
108 %(src)s,
109 %(lang)s
110 )
111 returning pk
112 """
113 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True)
114
115 return rows[0]['pk']
116
117
118
119
120
121
122
124 """Iterator over a Gelbe Liste/MMI v8.2 CSV file."""
125
126 version = u'Gelbe Liste/MMI v8.2 CSV file interface'
127 default_transfer_file_windows = r"c:\rezept.txt"
128
129 default_encoding = 'cp1250'
130 csv_fieldnames = [
131 u'name',
132 u'packungsgroesse',
133 u'darreichungsform',
134 u'packungstyp',
135 u'festbetrag',
136 u'avp',
137 u'hersteller',
138 u'rezepttext',
139 u'pzn',
140 u'status_vertrieb',
141 u'status_rezeptpflicht',
142 u'status_fachinfo',
143 u'btm',
144 u'atc',
145 u'anzahl_packungen',
146 u'zuzahlung_pro_packung',
147 u'einheit',
148 u'schedule_morgens',
149 u'schedule_mittags',
150 u'schedule_abends',
151 u'schedule_nachts',
152 u'status_dauermedikament',
153 u'status_hausliste',
154 u'status_negativliste',
155 u'ik_nummer',
156 u'status_rabattvertrag',
157 u'wirkstoffe',
158 u'wirkstoffmenge',
159 u'wirkstoffeinheit',
160 u'wirkstoffmenge_bezug',
161 u'wirkstoffmenge_bezugseinheit',
162 u'status_import',
163 u'status_lifestyle',
164 u'status_ausnahmeliste',
165 u'packungsmenge',
166 u'apothekenpflicht',
167 u'status_billigere_packung',
168 u'rezepttyp',
169 u'besonderes_arzneimittel',
170 u't_rezept_pflicht',
171 u'erstattbares_medizinprodukt',
172 u'hilfsmittel',
173 u'hzv_rabattkennung',
174 u'hzv_preis'
175 ]
176 boolean_fields = [
177 u'status_rezeptpflicht',
178 u'status_fachinfo',
179 u'btm',
180 u'status_dauermedikament',
181 u'status_hausliste',
182 u'status_negativliste',
183 u'status_rabattvertrag',
184 u'status_import',
185 u'status_lifestyle',
186 u'status_ausnahmeliste',
187 u'apothekenpflicht',
188 u'status_billigere_packung',
189 u'besonderes_arzneimittel',
190 u't_rezept_pflicht',
191 u'erstattbares_medizinprodukt',
192 u'hilfsmittel'
193 ]
194
214
217
219 line = self.csv_lines.next()
220
221 for field in cGelbeListeCSVFile.boolean_fields:
222 line[field] = (line[field].strip() == u'T')
223
224
225 if line['wirkstoffe'].strip() == u'':
226 line['wirkstoffe'] = []
227 else:
228 line['wirkstoffe'] = [ wirkstoff.strip() for wirkstoff in line['wirkstoffe'].split(u';') ]
229
230 return line
231
232 - def close(self, truncate=True):
233 try: self.csv_file.close()
234 except: pass
235
236 if truncate:
237 try: os.open(self.filename, 'wb').close
238 except: pass
239
242
243 has_unknown_fields = property(_get_has_unknown_fields, lambda x:x)
244
246
247
249 self.patient = None
250 self.reviewer = None
251 self.custom_path_to_binary = None
252
254 raise NotImplementedError
255
257 raise NotImplementedError
258
260 raise NotImplementedError
261
264
267
270
273
274 - def prescribe(self, substance_intakes=None):
276
278
279 version = u'FreeDiams v0.5.4 interface'
280 default_encoding = 'utf8'
281 default_dob_format = '%Y/%m/%d'
282
283 map_gender2mf = {
284 'm': u'M',
285 'f': u'F',
286 'tf': u'H',
287 'tm': u'H',
288 'h': u'H'
289 }
290
304
306
307
308 if not self.__detect_binary():
309 return False
310
311 freediams = subprocess.Popen (
312 args = u'--version',
313 executable = self.path_to_binary,
314 stdout = subprocess.PIPE,
315 stderr = subprocess.PIPE,
316
317 universal_newlines = True
318 )
319 data, errors = freediams.communicate()
320 version = regex.search('FreeDiams\s\d.\d.\d', data).group().split()[1]
321 _log.debug('FreeDiams %s', version)
322
323 return version
324
326 return create_data_source (
327 long_name = u'"FreeDiams" Drug Database Frontend',
328 short_name = u'FreeDiams',
329 version = self.get_data_source_version(),
330 source = u'http://ericmaeker.fr/FreeMedForms/di-manual/index.html',
331 language = u'fr'
332 )
333
335 """http://ericmaeker.fr/FreeMedForms/di-manual/en/html/ligne_commandes.html"""
336
337 _log.debug('calling FreeDiams in [%s] mode', mode)
338
339 if not self.__detect_binary():
340 return False
341
342 self.__create_gm2fd_file(mode = mode)
343
344 args = u'--exchange-in="%s"' % (self.__gm2fd_filename)
345 cmd = r'%s %s' % (self.path_to_binary, args)
346 if not gmShellAPI.run_command_in_shell(command = cmd, blocking = blocking):
347 _log.error('problem switching to the FreeDiams drug database')
348 return False
349
350 if blocking == True:
351 self.import_fd2gm_file_as_drugs()
352
353 return True
354
357
359 if substance_intakes is None:
360 return
361 if len(substance_intakes) < 2:
362 return
363
364 self.__create_prescription_file(substance_intakes = substance_intakes)
365 self.switch_to_frontend(mode = 'interactions', blocking = False)
366
368 if substance_intake is None:
369 return
370
371 self.__create_prescription_file(substance_intakes = [substance_intake])
372 self.switch_to_frontend(mode = 'interactions', blocking = False)
373
376
377 - def prescribe(self, substance_intakes=None):
378 if substance_intakes is None:
379 if not self.__export_latest_prescription():
380 self.__create_prescription_file()
381 else:
382 self.__create_prescription_file(substance_intakes = substance_intakes)
383
384 self.switch_to_frontend(mode = 'prescription', blocking = True)
385 self.import_fd2gm_file_as_prescription()
386
387
388
390
391 if self.path_to_binary is not None:
392 return True
393
394 found, cmd = gmShellAPI.find_first_binary(binaries = [
395 r'/usr/bin/freediams',
396 r'freediams',
397 r'/Applications/FreeDiams.app/Contents/MacOs/FreeDiams',
398 r'c:\programs\freediams\freediams.exe',
399 r'freediams.exe'
400 ])
401
402 if found:
403 self.path_to_binary = cmd
404 return True
405
406 try:
407 self.custom_path_to_binary
408 except AttributeError:
409 _log.error('cannot find FreeDiams binary, no custom path set')
410 return False
411
412 found, cmd = gmShellAPI.detect_external_binary(binary = self.custom_path_to_binary)
413 if found:
414 self.path_to_binary = cmd
415 return True
416
417 _log.error('cannot find FreeDiams binary')
418 return False
419
421
422 if self.patient is None:
423 _log.debug('cannot export latest FreeDiams prescriptions w/o patient')
424 return False
425
426 docs = self.patient.get_document_folder()
427 prescription = docs.get_latest_freediams_prescription()
428 if prescription is None:
429 _log.debug('no FreeDiams prescription available')
430 return False
431
432 for part in prescription.parts:
433 if part['filename'] == u'freediams-prescription.xml':
434 if part.export_to_file(filename = self.__fd2gm_filename) is not None:
435 return True
436
437 _log.error('cannot export latest FreeDiams prescription to XML file')
438
439 return False
440
442 """FreeDiams calls this exchange-out or prescription file.
443
444 CIS stands for Unique Speciality Identifier (eg bisoprolol 5 mg, gel).
445 CIS is AFSSAPS specific, but pharmacist can retreive drug name with the CIS.
446 AFSSAPS is the French FDA.
447
448 CIP stands for Unique Presentation Identifier (eg 30 pills plaq)
449 CIP if you want to specify the packaging of the drug (30 pills
450 thermoformed tablet...) -- actually not really usefull for french
451 doctors.
452 # .external_code_type: u'FR-CIS'
453 # .external_cod: the CIS value
454
455 OnlyForTest:
456 OnlyForTest drugs will be processed by the IA Engine but
457 not printed (regardless of FreeDiams mode). They are shown
458 in gray in the prescription view.
459
460 Select-only is a mode where FreeDiams creates a list of drugs
461 not a full prescription. In this list, users can add ForTestOnly
462 drug if they want to
463 1. print the list without some drugs
464 2. but including these drugs in the IA engine calculation
465
466 Select-Only mode does not have any relation with the ForTestOnly drugs.
467
468 IsTextual:
469 What is the use and significance of the
470 <IsTextual>true/false</IsTextual>
471 flag when both <DrugName> and <TextualDrugName> exist ?
472
473 This tag must be setted even if it sounds like a duplicated
474 data. This tag is needed inside FreeDiams code.
475
476 INN:
477 GNUmed will pass the substance in <TextualDrugName
478 and will also pass <INN>True</INN>.
479
480 Eric: Nop, this is not usefull because pure textual drugs
481 are not processed but just shown.
482 """
483
484 open(self.__fd2gm_filename, 'wb').close()
485
486
487 if substance_intakes is None:
488 if self.patient is None:
489 _log.warning('cannot create prescription file because there is neither a patient nor a substance intake list')
490
491 return False
492 emr = self.patient.get_emr()
493 substance_intakes = emr.get_current_substance_intake (
494 include_inactive = False,
495 include_unapproved = True
496 )
497
498 drug_snippets = []
499
500
501 fd_intakes = [ i for i in substance_intakes if (
502 (i['intake_is_approved_of'] is True)
503 and
504 (i['external_code_type_brand'] is not None)
505 and
506 (i['external_code_type_brand'].startswith(u'FreeDiams::'))
507 )]
508
509 intakes_pooled_by_brand = {}
510 for intake in fd_intakes:
511
512
513 intakes_pooled_by_brand[intake['brand']] = intake
514 del fd_intakes
515
516 drug_snippet = u"""<Prescription>
517 <IsTextual>False</IsTextual>
518 <DrugName>%s</DrugName>
519 <Drug_UID>%s</Drug_UID>
520 <Drug_UID_type>%s</Drug_UID_type> <!-- not yet supported by FreeDiams -->
521 </Prescription>"""
522
523 last_db_id = u'CA_HCDPD'
524 for intake in intakes_pooled_by_brand.values():
525 last_db_id = gmTools.xml_escape_string(text = intake['external_code_type_brand'].replace(u'FreeDiams::', u'').split(u'::')[0])
526 drug_snippets.append(drug_snippet % (
527 gmTools.xml_escape_string(text = intake['brand'].strip()),
528 gmTools.xml_escape_string(text = intake['external_code_brand'].strip()),
529 last_db_id
530 ))
531
532
533 non_fd_intakes = [ i for i in substance_intakes if (
534 (i['intake_is_approved_of'] is True)
535 and (
536 (i['external_code_type_brand'] is None)
537 or
538 (not i['external_code_type_brand'].startswith(u'FreeDiams::'))
539 )
540 )]
541
542 non_fd_brand_intakes = [ i for i in non_fd_intakes if i['brand'] is not None ]
543 non_fd_substance_intakes = [ i for i in non_fd_intakes if i['brand'] is None ]
544 del non_fd_intakes
545
546 drug_snippet = u"""<Prescription>
547 <IsTextual>True</IsTextual>
548 <TextualDrugName>%s</TextualDrugName>
549 </Prescription>"""
550
551 for intake in non_fd_substance_intakes:
552 drug_name = u'%s %s%s (%s)%s' % (
553 intake['substance'],
554 intake['amount'],
555 intake['unit'],
556 intake['preparation'],
557 gmTools.coalesce(intake['schedule'], u'', _('\n Take: %s'))
558 )
559 drug_snippets.append(drug_snippet % gmTools.xml_escape_string(text = drug_name.strip()))
560
561 intakes_pooled_by_brand = {}
562 for intake in non_fd_brand_intakes:
563 brand = u'%s %s' % (intake['brand'], intake['preparation'])
564 try:
565 intakes_pooled_by_brand[brand].append(intake)
566 except KeyError:
567 intakes_pooled_by_brand[brand] = [intake]
568
569 for brand, comps in intakes_pooled_by_brand.iteritems():
570 drug_name = u'%s\n' % brand
571 for comp in comps:
572 drug_name += u' %s %s%s\n' % (
573 comp['substance'],
574 comp['amount'],
575 comp['unit']
576 )
577 if comps[0]['schedule'] is not None:
578 drug_name += gmTools.coalesce(comps[0]['schedule'], u'', _('Take: %s'))
579 drug_snippets.append(drug_snippet % gmTools.xml_escape_string(text = drug_name.strip()))
580
581
582 xml = u"""<?xml version = "1.0" encoding = "UTF-8"?>
583
584 <FreeDiams>
585 <DrugsDatabaseName>%s</DrugsDatabaseName>
586 <FullPrescription version="0.5.0">
587
588 %s
589
590 </FullPrescription>
591 </FreeDiams>
592 """
593
594 xml_file = codecs.open(self.__fd2gm_filename, 'wb', 'utf8')
595 xml_file.write(xml % (
596 last_db_id,
597 u'\n\t\t'.join(drug_snippets)
598 ))
599 xml_file.close()
600
601 return True
602
604
605 if mode == 'interactions':
606 mode = u'select-only'
607 elif mode == 'prescription':
608 mode = u'prescriber'
609 else:
610 mode = u'select-only'
611
612 xml_file = codecs.open(self.__gm2fd_filename, 'wb', 'utf8')
613
614 xml = u"""<?xml version="1.0" encoding="UTF-8"?>
615
616 <FreeDiams_In version="0.5.0">
617 <EMR name="GNUmed" uid="unused"/>
618 <ConfigFile value="%s"/>
619 <ExchangeOut value="%s" format="xml"/>
620 <!-- <DrugsDatabase uid="can be set to a specific DB"/> -->
621 <Ui editmode="%s" blockPatientDatas="1"/>
622 %%s
623 </FreeDiams_In>
624
625 <!--
626 # FIXME: search by LOINC code and add (as soon as supported by FreeDiams ...)
627 <Creatinine value="12" unit="mg/l or mmol/l"/>
628 <Weight value="70" unit="kg or pd" />
629 <Height value="170" unit="cm or "/>
630 <ICD10 value="J11.0;A22;Z23"/>
631 -->
632 """ % (
633 self.__fd4gm_config_file,
634 self.__fd2gm_filename,
635 mode
636 )
637
638 if self.patient is None:
639 xml_file.write(xml % u'')
640 xml_file.close()
641 return
642
643 name = self.patient.get_active_name()
644 if self.patient['dob'] is None:
645 dob = u''
646 else:
647 dob = self.patient['dob'].strftime(cFreeDiamsInterface.default_dob_format)
648
649 emr = self.patient.get_emr()
650 allgs = emr.get_allergies()
651 atc_allgs = [
652 a['atc_code'] for a in allgs if ((a['atc_code'] is not None) and (a['type'] == u'allergy'))
653 ]
654 atc_sens = [
655 a['atc_code'] for a in allgs if ((a['atc_code'] is not None) and (a['type'] == u'sensitivity'))
656 ]
657 inn_allgs = [ a['allergene'] for a in allgs if a['type'] == u'allergy' ]
658 inn_sens = [ a['allergene'] for a in allgs if a['type'] == u'sensitivity' ]
659
660
661 uid_allgs = [
662 a['substance_code'] for a in allgs if ((a['substance_code'] is not None) and (a['type'] == u'allergy'))
663 ]
664 uid_sens = [
665 a['substance_code'] for a in allgs if ((a['substance_code'] is not None) and (a['type'] == u'sensitivity'))
666 ]
667
668 patient_xml = u"""<Patient>
669 <Identity
670 lastnames="%s"
671 firstnames="%s"
672 uid="%s"
673 dob="%s"
674 gender="%s"
675 />
676 <ATCAllergies value="%s"/>
677 <ATCIntolerances value="%s"/>
678
679 <InnAllergies value="%s"/>
680 <InnIntolerances value="%s"/>
681
682 <DrugsUidAllergies value="%s"/>
683 <DrugsUidIntolerances value="%s"/>
684 </Patient>
685 """ % (
686 gmTools.xml_escape_string(text = name['lastnames']),
687 gmTools.xml_escape_string(text = name['firstnames']),
688 self.patient.ID,
689 dob,
690 cFreeDiamsInterface.map_gender2mf[self.patient['gender']],
691 gmTools.xml_escape_string(text = u';'.join(atc_allgs)),
692 gmTools.xml_escape_string(text = u';'.join(atc_sens)),
693 gmTools.xml_escape_string(text = u';'.join(inn_allgs)),
694 gmTools.xml_escape_string(text = u';'.join(inn_sens)),
695 gmTools.xml_escape_string(text = u';'.join(uid_allgs)),
696 gmTools.xml_escape_string(text = u';'.join(uid_sens))
697 )
698
699 xml_file.write(xml % patient_xml)
700 xml_file.close()
701
746
748 """
749 If returning textual prescriptions (say, drugs which FreeDiams
750 did not know) then "IsTextual" will be True and UID will be -1.
751 """
752 if filename is None:
753 filename = self.__fd2gm_filename
754
755
756
757 fd2gm_xml = etree.ElementTree()
758 fd2gm_xml.parse(filename)
759
760 data_src_pk = self.create_data_source_entry()
761
762 db_def = fd2gm_xml.find('DrugsDatabaseName')
763 db_id = db_def.text.strip()
764 drug_id_name = db_def.attrib['drugUidName']
765 drugs = fd2gm_xml.findall('FullPrescription/Prescription')
766 for drug in drugs:
767 drug_uid = drug.find('Drug_UID').text.strip()
768 if drug_uid == u'-1':
769 _log.debug('skipping textual drug')
770 continue
771 drug_name = drug.find('DrugName').text.replace(', )', ')').strip()
772 drug_form = drug.find('DrugForm').text.strip()
773 drug_atc = drug.find('DrugATC')
774 if drug_atc is None:
775 drug_atc = u''
776 else:
777 drug_atc = drug_atc.text.strip()
778
779 new_drug = create_branded_drug(brand_name = drug_name, preparation = drug_form, return_existing = True)
780
781 new_drug['is_fake_brand'] = False
782 new_drug['atc'] = drug_atc
783 new_drug['external_code_type'] = u'FreeDiams::%s::%s' % (db_id, drug_id_name)
784 new_drug['external_code'] = drug_uid
785 new_drug['pk_data_source'] = data_src_pk
786 new_drug.save()
787
788 components = drug.getiterator('Composition')
789 for comp in components:
790
791 amount = regex.match(r'\d+[.,]{0,1}\d*', comp.attrib['strenght'].strip())
792 if amount is None:
793 amount = 99999
794 else:
795 amount = amount.group()
796
797 unit = regex.sub(r'\d+[.,]{0,1}\d*', u'', comp.attrib['strenght'].strip()).strip()
798 if unit == u'':
799 unit = u'*?*'
800
801 substance_name = comp.attrib['molecularName'].strip()
802 if substance_name != u'':
803 create_consumable_substance(substance = substance_name, atc = None, amount = amount, unit = unit)
804
805 inn_name = comp.attrib['inn'].strip()
806 if inn_name != u'':
807 create_consumable_substance(substance = inn_name, atc = None, amount = amount, unit = unit)
808 if substance_name == u'':
809 _log.info('linking INN [%s] rather than molecularName as component', inn_name)
810 substance_name = inn_name
811
812 new_drug.add_component(substance = substance_name, atc = None, amount = amount, unit = unit)
813
815 """Support v8.2 CSV file interface only."""
816
817 version = u'Gelbe Liste/MMI v8.2 interface'
818 default_encoding = 'cp1250'
819 bdt_line_template = u'%03d6210#%s\r\n'
820 bdt_line_base_length = 8
821
823
824 cDrugDataSourceInterface.__init__(self)
825
826 _log.info(u'%s (native Windows)', cGelbeListeWindowsInterface.version)
827
828 self.path_to_binary = r'C:\Programme\MMI PHARMINDEX\glwin.exe'
829 self.args = r'-KEEPBACKGROUND -PRESCRIPTIONFILE %s -CLOSETOTRAY'
830
831 paths = gmTools.gmPaths()
832
833 self.default_csv_filename = os.path.join(paths.home_dir, '.gnumed', 'tmp', 'rezept.txt')
834 self.default_csv_filename_arg = os.path.join(paths.home_dir, '.gnumed', 'tmp')
835 self.interactions_filename = os.path.join(paths.home_dir, '.gnumed', 'tmp', 'gm2mmi.bdt')
836 self.data_date_filename = r'C:\Programme\MMI PHARMINDEX\datadate.txt'
837
838 self.__data_date = None
839 self.__online_update_date = None
840
841
842
844
845 if self.__data_date is not None:
846 if not force_reload:
847 return {
848 'data': self.__data_date,
849 'online_update': self.__online_update_date
850 }
851
852 open(self.data_date_filename, 'wb').close()
853
854 cmd = u'%s -DATADATE' % self.path_to_binary
855 if not gmShellAPI.run_command_in_shell(command = cmd, blocking = True):
856 _log.error('problem querying the MMI drug database for version information')
857 self.__data_date = None
858 self.__online_update_date = None
859 return {
860 'data': u'?',
861 'online_update': u'?'
862 }
863
864 try:
865 version_file = open(self.data_date_filename, 'rU')
866 except StandardError:
867 _log.error('problem querying the MMI drug database for version information')
868 _log.exception('cannot open MMI drug database version file [%s]', self.data_date_filename)
869 self.__data_date = None
870 self.__online_update_date = None
871 return {
872 'data': u'?',
873 'online_update': u'?'
874 }
875
876 self.__data_date = version_file.readline()[:10]
877 self.__online_update_date = version_file.readline()[:10]
878 version_file.close()
879
880 return {
881 'data': self.__data_date,
882 'online_update': self.__online_update_date
883 }
884
886 versions = self.get_data_source_version()
887
888 return create_data_source (
889 long_name = u'Medikamentendatenbank "mmi PHARMINDEX" (Gelbe Liste)',
890 short_name = u'GL/MMI',
891 version = u'Daten: %s, Preise (Onlineupdate): %s' % (versions['data'], versions['online_update']),
892 source = u'Medizinische Medien Informations GmbH, Am Forsthaus Gravenbruch 7, 63263 Neu-Isenburg',
893 language = u'de'
894 )
895
897
898
899 open(self.default_csv_filename, 'wb').close()
900
901 if cmd is None:
902 cmd = (u'%s %s' % (self.path_to_binary, self.args)) % self.default_csv_filename_arg
903
904 if not gmShellAPI.run_command_in_shell(command = cmd, blocking = blocking):
905 _log.error('problem switching to the MMI drug database')
906
907
908
909
910 return True
911
921
923
924 selected_drugs = self.__let_user_select_drugs()
925 if selected_drugs is None:
926 return None
927
928 new_substances = []
929
930 for drug in selected_drugs:
931 atc = None
932 if len(drug['wirkstoffe']) == 1:
933 atc = drug['atc']
934 for wirkstoff in drug['wirkstoffe']:
935 new_substances.append(create_consumable_substance(substance = wirkstoff, atc = atc, amount = amount, unit = unit))
936
937 selected_drugs.close()
938
939 return new_substances
940
942
943 selected_drugs = self.__let_user_select_drugs()
944 if selected_drugs is None:
945 return None
946
947 data_src_pk = self.create_data_source_entry()
948
949 new_drugs = []
950 new_substances = []
951
952 for entry in selected_drugs:
953
954 _log.debug('importing drug: %s %s', entry['name'], entry['darreichungsform'])
955
956 if entry[u'hilfsmittel']:
957 _log.debug('skipping Hilfsmittel')
958 continue
959
960 if entry[u'erstattbares_medizinprodukt']:
961 _log.debug('skipping sonstiges Medizinprodukt')
962 continue
963
964
965 drug = create_branded_drug(brand_name = entry['name'], preparation = entry['darreichungsform'])
966 if drug is None:
967 drug = get_drug_by_brand(brand_name = entry['name'], preparation = entry['darreichungsform'])
968 new_drugs.append(drug)
969
970
971 drug['is_fake'] = False
972 drug['atc_code'] = entry['atc']
973 drug['external_code_type'] = u'DE-PZN'
974 drug['external_code'] = entry['pzn']
975 drug['fk_data_source'] = data_src_pk
976 drug.save()
977
978
979 atc = None
980 if len(entry['wirkstoffe']) == 1:
981 atc = entry['atc']
982 for wirkstoff in entry['wirkstoffe']:
983 drug.add_component(substance = wirkstoff, atc = atc)
984
985
986 atc = None
987 if len(entry['wirkstoffe']) == 1:
988 atc = entry['atc']
989 for wirkstoff in entry['wirkstoffe']:
990 new_substances.append(create_consumable_substance(substance = wirkstoff, atc = atc, amount = amount, unit = unit))
991
992 return new_drugs, new_substances
993
1022
1025
1044
1046
1048 cGelbeListeWindowsInterface.__init__(self)
1049
1050 _log.info(u'%s (WINE extension)', cGelbeListeWindowsInterface.version)
1051
1052
1053 self.path_to_binary = r'wine "C:\Programme\MMI PHARMINDEX\glwin.exe"'
1054 self.args = r'"-PRESCRIPTIONFILE %s -KEEPBACKGROUND"'
1055
1056 paths = gmTools.gmPaths()
1057
1058 self.default_csv_filename = os.path.join(paths.home_dir, '.wine', 'drive_c', 'windows', 'temp', 'mmi2gm.csv')
1059 self.default_csv_filename_arg = r'c:\windows\temp\mmi2gm.csv'
1060 self.interactions_filename = os.path.join(paths.home_dir, '.wine', 'drive_c', 'windows', 'temp', 'gm2mmi.bdt')
1061 self.data_date_filename = os.path.join(paths.home_dir, '.wine', 'drive_c', 'Programme', 'MMI PHARMINDEX', 'datadate.txt')
1062
1064 """empirical CSV interface"""
1065
1068
1070
1071 try:
1072 csv_file = open(filename, 'rb')
1073 except:
1074 _log.exception('cannot access [%s]', filename)
1075 csv_file = None
1076
1077 field_names = u'PZN Handelsname Form Abpackungsmenge Einheit Preis1 Hersteller Preis2 rezeptpflichtig Festbetrag Packungszahl Packungsgr\xf6\xdfe'.split()
1078
1079 if csv_file is None:
1080 return False
1081
1082 csv_lines = csv.DictReader (
1083 csv_file,
1084 fieldnames = field_names,
1085 delimiter = ';'
1086 )
1087
1088 for line in csv_lines:
1089 print "--------------------------------------------------------------------"[:31]
1090 for key in field_names:
1091 tmp = ('%s ' % key)[:30]
1092 print '%s: %s' % (tmp, line[key])
1093
1094 csv_file.close()
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107 drug_data_source_interfaces = {
1108 'Deutschland: Gelbe Liste/MMI (Windows)': cGelbeListeWindowsInterface,
1109 'Deutschland: Gelbe Liste/MMI (WINE)': cGelbeListeWineInterface,
1110 'FreeDiams (FR, US, CA, ZA)': cFreeDiamsInterface
1111 }
1112
1113
1114
1115
1116
1117 _SQL_get_consumable_substance = u"""
1118 SELECT *, xmin
1119 FROM ref.consumable_substance
1120 WHERE %s
1121 """
1122
1124
1125 _cmd_fetch_payload = _SQL_get_consumable_substance % u"pk = %s"
1126 _cmds_store_payload = [
1127 u"""UPDATE ref.consumable_substance SET
1128 description = %(description)s,
1129 atc_code = gm.nullify_empty_string(%(atc_code)s),
1130 amount = %(amount)s,
1131 unit = gm.nullify_empty_string(%(unit)s)
1132 WHERE
1133 pk = %(pk)s
1134 AND
1135 xmin = %(xmin)s
1136 AND
1137 -- must not currently be used with a patient directly
1138 NOT EXISTS (
1139 SELECT 1
1140 FROM clin.substance_intake
1141 WHERE
1142 fk_drug_component IS NULL
1143 AND
1144 fk_substance = %(pk)s
1145 LIMIT 1
1146 )
1147 AND
1148 -- must not currently be used with a patient indirectly, either
1149 NOT EXISTS (
1150 SELECT 1
1151 FROM clin.substance_intake
1152 WHERE
1153 fk_drug_component IS NOT NULL
1154 AND
1155 fk_drug_component = (
1156 SELECT r_ls2b.pk
1157 FROM ref.lnk_substance2brand r_ls2b
1158 WHERE fk_substance = %(pk)s
1159 )
1160 LIMIT 1
1161 )
1162 -- -- must not currently be used with a branded drug
1163 -- -- (but this would make it rather hard fixing branded drugs which contain only this substance)
1164 -- NOT EXISTS (
1165 -- SELECT 1
1166 -- FROM ref.lnk_substance2brand
1167 -- WHERE fk_substance = %(pk)s
1168 -- LIMIT 1
1169 -- )
1170 RETURNING
1171 xmin
1172 """
1173 ]
1174 _updatable_fields = [
1175 u'description',
1176 u'atc_code',
1177 u'amount',
1178 u'unit'
1179 ]
1180
1182 success, data = super(self.__class__, self).save_payload(conn = conn)
1183
1184 if not success:
1185 return (success, data)
1186
1187 if self._payload[self._idx['atc_code']] is not None:
1188 atc = self._payload[self._idx['atc_code']].strip()
1189 if atc != u'':
1190 gmATC.propagate_atc (
1191 substance = self._payload[self._idx['description']].strip(),
1192 atc = atc
1193 )
1194
1195 return (success, data)
1196
1197
1198
1200 cmd = u"""
1201 SELECT
1202 EXISTS (
1203 SELECT 1
1204 FROM clin.substance_intake
1205 WHERE
1206 fk_drug_component IS NULL
1207 AND
1208 fk_substance = %(pk)s
1209 LIMIT 1
1210 ) OR EXISTS (
1211 SELECT 1
1212 FROM clin.substance_intake
1213 WHERE
1214 fk_drug_component IS NOT NULL
1215 AND
1216 fk_drug_component = (
1217 SELECT r_ls2b.pk
1218 FROM ref.lnk_substance2brand r_ls2b
1219 WHERE fk_substance = %(pk)s
1220 )
1221 LIMIT 1
1222 )"""
1223 args = {'pk': self.pk_obj}
1224
1225 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
1226 return rows[0][0]
1227
1228 is_in_use_by_patients = property(_get_is_in_use_by_patients, lambda x:x)
1229
1231 cmd = u"""
1232 SELECT EXISTS (
1233 SELECT 1
1234 FROM ref.lnk_substance2brand
1235 WHERE fk_substance = %(pk)s
1236 LIMIT 1
1237 )"""
1238 args = {'pk': self.pk_obj}
1239
1240 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
1241 return rows[0][0]
1242
1243 is_drug_component = property(_get_is_drug_component, lambda x:x)
1244
1253
1255
1256 substance = substance
1257 if atc is not None:
1258 atc = atc.strip()
1259
1260 args = {
1261 'desc': substance.strip(),
1262 'amount': decimal.Decimal(amount),
1263 'unit': unit.strip(),
1264 'atc': atc
1265 }
1266 cmd = u"""
1267 SELECT pk FROM ref.consumable_substance
1268 WHERE
1269 lower(description) = lower(%(desc)s)
1270 AND
1271 amount = %(amount)s
1272 AND
1273 unit = %(unit)s
1274 """
1275 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}])
1276
1277 if len(rows) == 0:
1278 cmd = u"""
1279 INSERT INTO ref.consumable_substance (description, atc_code, amount, unit) VALUES (
1280 %(desc)s,
1281 gm.nullify_empty_string(%(atc)s),
1282 %(amount)s,
1283 gm.nullify_empty_string(%(unit)s)
1284 ) RETURNING pk"""
1285 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True, get_col_idx = False)
1286
1287 gmATC.propagate_atc(substance = substance, atc = atc)
1288
1289 return cConsumableSubstance(aPK_obj = rows[0]['pk'])
1290
1292 args = {'pk': substance}
1293 cmd = u"""
1294 DELETE FROM ref.consumable_substance
1295 WHERE
1296 pk = %(pk)s
1297 AND
1298
1299 -- must not currently be used with a patient
1300 NOT EXISTS (
1301 SELECT 1
1302 FROM clin.v_pat_substance_intake
1303 WHERE pk_substance = %(pk)s
1304 LIMIT 1
1305 )
1306 AND
1307
1308 -- must not currently be used with a branded drug
1309 NOT EXISTS (
1310 SELECT 1
1311 FROM ref.lnk_substance2brand
1312 WHERE fk_substance = %(pk)s
1313 LIMIT 1
1314 )"""
1315 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
1316 return True
1317
1319
1320 _pattern = regex.compile(r'^\D+\s*\d+$', regex.UNICODE | regex.LOCALE)
1321 _query1 = u"""
1322 SELECT
1323 pk::text,
1324 (description || ' ' || amount || unit) as subst
1325 FROM ref.consumable_substance
1326 WHERE description %(fragment_condition)s
1327 ORDER BY subst
1328 LIMIT 50"""
1329 _query2 = u"""
1330 SELECT
1331 pk::text,
1332 (description || ' ' || amount || unit) as subst
1333 FROM ref.consumable_substance
1334 WHERE
1335 %(fragment_condition)s
1336 ORDER BY subst
1337 LIMIT 50"""
1338
1339
1341 """Return matches for aFragment at start of phrases."""
1342
1343 if cSubstanceMatchProvider._pattern.match(aFragment):
1344 self._queries = [cSubstanceMatchProvider._query2]
1345 fragment_condition = """description ILIKE %(desc)s
1346 AND
1347 amount::text ILIKE %(amount)s"""
1348 self._args['desc'] = u'%s%%' % regex.sub(r'\s*\d+$', u'', aFragment)
1349 self._args['amount'] = u'%s%%' % regex.sub(r'^\D+\s*', u'', aFragment)
1350 else:
1351 self._queries = [cSubstanceMatchProvider._query1]
1352 fragment_condition = u"ILIKE %(fragment)s"
1353 self._args['fragment'] = u"%s%%" % aFragment
1354
1355 return self._find_matches(fragment_condition)
1356
1358 """Return matches for aFragment at start of words inside phrases."""
1359
1360 if cSubstanceMatchProvider._pattern.match(aFragment):
1361 self._queries = [cSubstanceMatchProvider._query2]
1362
1363 desc = regex.sub(r'\s*\d+$', u'', aFragment)
1364 desc = gmPG2.sanitize_pg_regex(expression = desc, escape_all = False)
1365
1366 fragment_condition = """description ~* %(desc)s
1367 AND
1368 amount::text ILIKE %(amount)s"""
1369
1370 self._args['desc'] = u"( %s)|(^%s)" % (desc, desc)
1371 self._args['amount'] = u'%s%%' % regex.sub(r'^\D+\s*', u'', aFragment)
1372 else:
1373 self._queries = [cSubstanceMatchProvider._query1]
1374 fragment_condition = u"~* %(fragment)s"
1375 aFragment = gmPG2.sanitize_pg_regex(expression = aFragment, escape_all = False)
1376 self._args['fragment'] = u"( %s)|(^%s)" % (aFragment, aFragment)
1377
1378 return self._find_matches(fragment_condition)
1379
1381 """Return matches for aFragment as a true substring."""
1382
1383 if cSubstanceMatchProvider._pattern.match(aFragment):
1384 self._queries = [cSubstanceMatchProvider._query2]
1385 fragment_condition = """description ILIKE %(desc)s
1386 AND
1387 amount::text ILIKE %(amount)s"""
1388 self._args['desc'] = u'%%%s%%' % regex.sub(r'\s*\d+$', u'', aFragment)
1389 self._args['amount'] = u'%s%%' % regex.sub(r'^\D+\s*', u'', aFragment)
1390 else:
1391 self._queries = [cSubstanceMatchProvider._query1]
1392 fragment_condition = u"ILIKE %(fragment)s"
1393 self._args['fragment'] = u"%%%s%%" % aFragment
1394
1395 return self._find_matches(fragment_condition)
1396
1397 -class cSubstanceIntakeEntry(gmBusinessDBObject.cBusinessDBObject):
1398 """Represents a substance currently taken by a patient."""
1399
1400 _cmd_fetch_payload = u"SELECT * FROM clin.v_pat_substance_intake WHERE pk_substance_intake = %s"
1401 _cmds_store_payload = [
1402 u"""UPDATE clin.substance_intake SET
1403 clin_when = %(started)s,
1404 discontinued = %(discontinued)s,
1405 discontinue_reason = gm.nullify_empty_string(%(discontinue_reason)s),
1406 schedule = gm.nullify_empty_string(%(schedule)s),
1407 aim = gm.nullify_empty_string(%(aim)s),
1408 narrative = gm.nullify_empty_string(%(notes)s),
1409 intake_is_approved_of = %(intake_is_approved_of)s,
1410 fk_episode = %(pk_episode)s,
1411
1412 preparation = (
1413 case
1414 when %(pk_brand)s is NULL then %(preparation)s
1415 else NULL
1416 end
1417 )::text,
1418
1419 is_long_term = (
1420 case
1421 when (
1422 (%(is_long_term)s is False)
1423 and
1424 (%(duration)s is NULL)
1425 ) is True then null
1426 else %(is_long_term)s
1427 end
1428 )::boolean,
1429
1430 duration = (
1431 case
1432 when %(is_long_term)s is True then null
1433 else %(duration)s
1434 end
1435 )::interval
1436 WHERE
1437 pk = %(pk_substance_intake)s
1438 AND
1439 xmin = %(xmin_substance_intake)s
1440 RETURNING
1441 xmin as xmin_substance_intake
1442 """
1443 ]
1444 _updatable_fields = [
1445 u'started',
1446 u'discontinued',
1447 u'discontinue_reason',
1448 u'preparation',
1449 u'intake_is_approved_of',
1450 u'schedule',
1451 u'duration',
1452 u'aim',
1453 u'is_long_term',
1454 u'notes',
1455 u'pk_episode'
1456 ]
1457
1458 - def format(self, left_margin=0, date_format='%Y-%m-%d'):
1459
1460 if self._payload[self._idx['duration']] is None:
1461 duration = gmTools.bool2subst (
1462 self._payload[self._idx['is_long_term']],
1463 _('long-term'),
1464 _('short-term'),
1465 _('?short-term')
1466 )
1467 else:
1468 duration = gmDateTime.format_interval (
1469 self._payload[self._idx['duration']],
1470 accuracy_wanted = gmDateTime.acc_days
1471 )
1472
1473 line = u'%s%s (%s %s): %s %s%s %s (%s)' % (
1474 u' ' * left_margin,
1475 self._payload[self._idx['started']].strftime(date_format),
1476 gmTools.u_right_arrow,
1477 duration,
1478 self._payload[self._idx['substance']],
1479 self._payload[self._idx['amount']],
1480 self._payload[self._idx['unit']],
1481 self._payload[self._idx['preparation']],
1482 gmTools.bool2subst(self._payload[self._idx['is_currently_active']], _('ongoing'), _('inactive'), _('?ongoing'))
1483 )
1484
1485 return line
1486
1487 - def turn_into_allergy(self, encounter_id=None, allergy_type='allergy'):
1488 allg = gmAllergy.create_allergy (
1489 allergene = self._payload[self._idx['substance']],
1490 allg_type = allergy_type,
1491 episode_id = self._payload[self._idx['pk_episode']],
1492 encounter_id = encounter_id
1493 )
1494 allg['substance'] = gmTools.coalesce (
1495 self._payload[self._idx['brand']],
1496 self._payload[self._idx['substance']]
1497 )
1498 allg['reaction'] = self._payload[self._idx['discontinue_reason']]
1499 allg['atc_code'] = gmTools.coalesce(self._payload[self._idx['atc_substance']], self._payload[self._idx['atc_brand']])
1500 if self._payload[self._idx['external_code_brand']] is not None:
1501 allg['substance_code'] = u'%s::::%s' % (self._payload[self._idx['external_code_type_brand']], self._payload[self._idx['external_code_brand']])
1502 comps = [ c['substance'] for c in self.containing_drug.components ]
1503 if len(comps) == 0:
1504 allg['generics'] = self._payload[self._idx['substance']]
1505 else:
1506 allg['generics'] = u'; '.join(comps)
1507
1508 allg.save()
1509 return allg
1510
1511
1512
1513 - def _get_ddd(self):
1514
1515 try: self.__ddd
1516 except AttributeError: self.__ddd = None
1517
1518 if self.__ddd is not None:
1519 return self.__ddd
1520
1521 if self._payload[self._idx['atc_substance']] is not None:
1522 ddd = gmATC.atc2ddd(atc = self._payload[self._idx['atc_substance']])
1523 if len(ddd) != 0:
1524 self.__ddd = ddd[0]
1525 else:
1526 if self._payload[self._idx['atc_brand']] is not None:
1527 ddd = gmATC.atc2ddd(atc = self._payload[self._idx['atc_brand']])
1528 if len(ddd) != 0:
1529 self.__ddd = ddd[0]
1530
1531 return self.__ddd
1532
1533 ddd = property(_get_ddd, lambda x:x)
1534
1536 drug = self.containing_drug
1537
1538 if drug is None:
1539 return None
1540
1541 return drug.external_code
1542
1543 external_code = property(_get_external_code, lambda x:x)
1544
1546 drug = self.containing_drug
1547
1548 if drug is None:
1549 return None
1550
1551 return drug.external_code_type
1552
1553 external_code_type = property(_get_external_code_type, lambda x:x)
1554
1556 if self._payload[self._idx['pk_brand']] is None:
1557 return None
1558
1559 return cBrandedDrug(aPK_obj = self._payload[self._idx['pk_brand']])
1560
1561 containing_drug = property(_get_containing_drug, lambda x:x)
1562
1564 tests = [
1565
1566 ' 1-1-1-1 ',
1567
1568 '1-1-1-1',
1569 '22-1-1-1',
1570 '1/3-1-1-1',
1571 '/4-1-1-1'
1572 ]
1573 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}$"
1574 for test in tests:
1575 print test.strip(), ":", regex.match(pattern, test.strip())
1576
1577 -def create_substance_intake(pk_substance=None, pk_component=None, preparation=None, encounter=None, episode=None):
1578
1579 args = {
1580 'enc': encounter,
1581 'epi': episode,
1582 'comp': pk_component,
1583 'subst': pk_substance,
1584 'prep': preparation
1585 }
1586
1587 if pk_component is None:
1588 cmd = u"""
1589 INSERT INTO clin.substance_intake (
1590 fk_encounter,
1591 fk_episode,
1592 intake_is_approved_of,
1593 fk_substance,
1594 preparation
1595 ) VALUES (
1596 %(enc)s,
1597 %(epi)s,
1598 False,
1599 %(subst)s,
1600 %(prep)s
1601 )
1602 RETURNING pk"""
1603 else:
1604 cmd = u"""
1605 INSERT INTO clin.substance_intake (
1606 fk_encounter,
1607 fk_episode,
1608 intake_is_approved_of,
1609 fk_drug_component
1610 ) VALUES (
1611 %(enc)s,
1612 %(epi)s,
1613 False,
1614 %(comp)s
1615 )
1616 RETURNING pk"""
1617
1618 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True)
1619 return cSubstanceIntakeEntry(aPK_obj = rows[0][0])
1620
1624
1659
1660
1737
1738 _SQL_get_drug_components = u'SELECT * FROM ref.v_drug_components WHERE %s'
1739
1741
1742 _cmd_fetch_payload = _SQL_get_drug_components % u'pk_component = %s'
1743 _cmds_store_payload = [
1744 u"""UPDATE ref.lnk_substance2brand SET
1745 fk_brand = %(pk_brand)s,
1746 fk_substance = %(pk_consumable_substance)s
1747 WHERE
1748 NOT EXISTS (
1749 SELECT 1
1750 FROM clin.substance_intake
1751 WHERE fk_drug_component = %(pk_component)s
1752 LIMIT 1
1753 )
1754 AND
1755 pk = %(pk_component)s
1756 AND
1757 xmin = %(xmin_lnk_substance2brand)s
1758 RETURNING
1759 xmin AS xmin_lnk_substance2brand
1760 """
1761 ]
1762 _updatable_fields = [
1763 u'pk_brand',
1764 u'pk_consumable_substance'
1765 ]
1766
1767
1768
1770 return cBrandedDrug(aPK_obj = self._payload[self._idx['pk_brand']])
1771
1772 containing_drug = property(_get_containing_drug, lambda x:x)
1773
1775 return self._payload[self._idx['is_in_use']]
1776
1777 is_in_use_by_patients = property(_get_is_in_use_by_patients, lambda x:x)
1778
1781
1782 substance = property(_get_substance, lambda x:x)
1783
1788
1790
1791 _pattern = regex.compile(r'^\D+\s*\d+$', regex.UNICODE | regex.LOCALE)
1792 _query_desc_only = u"""
1793 SELECT DISTINCT ON (component)
1794 pk_component,
1795 (substance || ' ' || amount || unit || ' ' || preparation || ' (' || brand || ')')
1796 AS component
1797 FROM ref.v_drug_components
1798 WHERE
1799 substance %(fragment_condition)s
1800 OR
1801 brand %(fragment_condition)s
1802 ORDER BY component
1803 LIMIT 50"""
1804 _query_desc_and_amount = u"""
1805
1806 SELECT DISTINCT ON (component)
1807 pk_component,
1808 (substance || ' ' || amount || unit || ' ' || preparation || ' (' || brand || ')')
1809 AS component
1810 FROM ref.v_drug_components
1811 WHERE
1812 %(fragment_condition)s
1813 ORDER BY component
1814 LIMIT 50"""
1815
1817 """Return matches for aFragment at start of phrases."""
1818
1819 if cDrugComponentMatchProvider._pattern.match(aFragment):
1820 self._queries = [cDrugComponentMatchProvider._query_desc_and_amount]
1821 fragment_condition = """(substance ILIKE %(desc)s OR brand ILIKE %(desc)s)
1822 AND
1823 amount::text ILIKE %(amount)s"""
1824 self._args['desc'] = u'%s%%' % regex.sub(r'\s*\d+$', u'', aFragment)
1825 self._args['amount'] = u'%s%%' % regex.sub(r'^\D+\s*', u'', aFragment)
1826 else:
1827 self._queries = [cDrugComponentMatchProvider._query_desc_only]
1828 fragment_condition = u"ILIKE %(fragment)s"
1829 self._args['fragment'] = u"%s%%" % aFragment
1830
1831 return self._find_matches(fragment_condition)
1832
1834 """Return matches for aFragment at start of words inside phrases."""
1835
1836 if cDrugComponentMatchProvider._pattern.match(aFragment):
1837 self._queries = [cDrugComponentMatchProvider._query_desc_and_amount]
1838
1839 desc = regex.sub(r'\s*\d+$', u'', aFragment)
1840 desc = gmPG2.sanitize_pg_regex(expression = desc, escape_all = False)
1841
1842 fragment_condition = """(substance ~* %(desc)s OR brand ~* %(desc)s)
1843 AND
1844 amount::text ILIKE %(amount)s"""
1845
1846 self._args['desc'] = u"( %s)|(^%s)" % (desc, desc)
1847 self._args['amount'] = u'%s%%' % regex.sub(r'^\D+\s*', u'', aFragment)
1848 else:
1849 self._queries = [cDrugComponentMatchProvider._query_desc_only]
1850 fragment_condition = u"~* %(fragment)s"
1851 aFragment = gmPG2.sanitize_pg_regex(expression = aFragment, escape_all = False)
1852 self._args['fragment'] = u"( %s)|(^%s)" % (aFragment, aFragment)
1853
1854 return self._find_matches(fragment_condition)
1855
1857 """Return matches for aFragment as a true substring."""
1858
1859 if cDrugComponentMatchProvider._pattern.match(aFragment):
1860 self._queries = [cDrugComponentMatchProvider._query_desc_and_amount]
1861 fragment_condition = """(substance ILIKE %(desc)s OR brand ILIKE %(desc)s)
1862 AND
1863 amount::text ILIKE %(amount)s"""
1864 self._args['desc'] = u'%%%s%%' % regex.sub(r'\s*\d+$', u'', aFragment)
1865 self._args['amount'] = u'%s%%' % regex.sub(r'^\D+\s*', u'', aFragment)
1866 else:
1867 self._queries = [cDrugComponentMatchProvider._query_desc_only]
1868 fragment_condition = u"ILIKE %(fragment)s"
1869 self._args['fragment'] = u"%%%s%%" % aFragment
1870
1871 return self._find_matches(fragment_condition)
1872
1873
1875 """Represents a drug as marketed by a manufacturer."""
1876
1877 _cmd_fetch_payload = u"SELECT * FROM ref.v_branded_drugs WHERE pk_brand = %s"
1878 _cmds_store_payload = [
1879 u"""UPDATE ref.branded_drug SET
1880 description = %(brand)s,
1881 preparation = %(preparation)s,
1882 atc_code = gm.nullify_empty_string(%(atc)s),
1883 external_code = gm.nullify_empty_string(%(external_code)s),
1884 external_code_type = gm.nullify_empty_string(%(external_code_type)s),
1885 is_fake = %(is_fake_brand)s,
1886 fk_data_source = %(pk_data_source)s
1887 WHERE
1888 pk = %(pk_brand)s
1889 AND
1890 xmin = %(xmin_branded_drug)s
1891 RETURNING
1892 xmin AS xmin_branded_drug
1893 """
1894 ]
1895 _updatable_fields = [
1896 u'brand',
1897 u'preparation',
1898 u'atc',
1899 u'is_fake_brand',
1900 u'external_code',
1901 u'external_code_type',
1902 u'pk_data_source'
1903 ]
1904
1906 success, data = super(self.__class__, self).save_payload(conn = conn)
1907
1908 if not success:
1909 return (success, data)
1910
1911 if self._payload[self._idx['atc']] is not None:
1912 atc = self._payload[self._idx['atc']].strip()
1913 if atc != u'':
1914 gmATC.propagate_atc (
1915 substance = self._payload[self._idx['brand']].strip(),
1916 atc = atc
1917 )
1918
1919 return (success, data)
1920
1922
1923 if self._payload[self._idx['is_in_use']]:
1924 return False
1925
1926 args = {'brand': self._payload[self._idx['pk_brand']]}
1927
1928 queries = [{'cmd': u"DELETE FROM ref.lnk_substance2brand WHERE fk_brand = %(brand)s", 'args': args}]
1929 cmd = u'INSERT INTO ref.lnk_substance2brand (fk_brand, fk_substance) VALUES (%%(brand)s, %s)'
1930 for s in substances:
1931 queries.append({'cmd': cmd % s['pk'], 'args': args})
1932
1933 gmPG2.run_rw_queries(queries = queries)
1934 self.refetch_payload()
1935
1936 return True
1937
1938 - def add_component(self, substance=None, atc=None, amount=None, unit=None, pk_substance=None):
1939
1940 args = {
1941 'brand': self.pk_obj,
1942 'subst': substance,
1943 'atc': atc,
1944 'pk_subst': pk_substance
1945 }
1946
1947 if pk_substance is None:
1948 consumable = create_consumable_substance(substance = substance, atc = atc, amount = amount, unit = unit)
1949 args['pk_subst'] = consumable['pk']
1950
1951
1952 cmd = u"""
1953 SELECT pk_component
1954 FROM ref.v_drug_components
1955 WHERE
1956 pk_brand = %(brand)s
1957 AND
1958 ((
1959 (lower(substance) = lower(%(subst)s))
1960 OR
1961 (lower(atc_substance) = lower(%(atc)s))
1962 OR
1963 (pk_consumable_substance = %(pk_subst)s)
1964 ) IS TRUE)
1965 """
1966 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
1967
1968 if len(rows) > 0:
1969 return
1970
1971
1972 cmd = u"""
1973 INSERT INTO ref.lnk_substance2brand (fk_brand, fk_substance)
1974 VALUES (%(brand)s, %(pk_subst)s)
1975 """
1976 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
1977
1979 if len(self._payload[self._idx['components']]) == 1:
1980 _log.error('cannot remove the only component of a drug')
1981 return False
1982
1983 args = {'brand': self.pk_obj, 'comp': substance}
1984 cmd = u"""
1985 DELETE FROM ref.lnk_substance2brand
1986 WHERE
1987 fk_brand = %(brand)s
1988 AND
1989 fk_substance = %(comp)s
1990 AND
1991 NOT EXISTS (
1992 SELECT 1
1993 FROM clin.substance_intake
1994 WHERE fk_drug_component = %(comp)s
1995 LIMIT 1
1996 )
1997 """
1998 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
1999 return True
2000
2001
2002
2004 if self._payload[self._idx['external_code']] is None:
2005 return None
2006
2007 return self._payload[self._idx['external_code']]
2008
2009 external_code = property(_get_external_code, lambda x:x)
2010
2012
2013
2014 if self._payload[self._idx['external_code_type']] is None:
2015 return None
2016
2017 return self._payload[self._idx['external_code_type']]
2018
2019 external_code_type = property(_get_external_code_type, lambda x:x)
2020
2022 cmd = _SQL_get_drug_components % u'pk_brand = %(brand)s'
2023 args = {'brand': self._payload[self._idx['pk_brand']]}
2024 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
2025 return [ cDrugComponent(row = {'data': r, 'idx': idx, 'pk_field': 'pk_component'}) for r in rows ]
2026
2027 components = property(_get_components, lambda x:x)
2028
2030 if self._payload[self._idx['pk_substances']] is None:
2031 return []
2032 cmd = _SQL_get_consumable_substance % u'pk IN %(pks)s'
2033 args = {'pks': tuple(self._payload[self._idx['pk_substances']])}
2034 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
2035 return [ cConsumableSubstance(row = {'data': r, 'idx': idx, 'pk_field': 'pk'}) for r in rows ]
2036
2037 components_as_substances = property(_get_components_as_substances, lambda x:x)
2038
2040 cmd = u'SELECT EXISTS (SELECT 1 FROM clin.vaccine WHERE fk_brand = %(fk_brand)s)'
2041 args = {'fk_brand': self._payload[self._idx['pk_brand']]}
2042 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
2043 return rows[0][0]
2044
2045 is_vaccine = property(_get_is_vaccine, lambda x:x)
2046
2048 cmd = u'SELECT pk FROM ref.branded_drug ORDER BY description'
2049 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = False)
2050 return [ cBrandedDrug(aPK_obj = r['pk']) for r in rows ]
2051
2053 args = {'brand': brand_name, 'prep': preparation}
2054
2055 cmd = u'SELECT pk FROM ref.branded_drug WHERE lower(description) = lower(%(brand)s) AND lower(preparation) = lower(%(prep)s)'
2056 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
2057
2058 if len(rows) == 0:
2059 return None
2060
2061 return cBrandedDrug(aPK_obj = rows[0]['pk'])
2062
2064
2065 if preparation is None:
2066 preparation = _('units')
2067
2068 if preparation.strip() == u'':
2069 preparation = _('units')
2070
2071 if return_existing:
2072 drug = get_drug_by_brand(brand_name = brand_name, preparation = preparation)
2073 if drug is not None:
2074 return drug
2075
2076 cmd = u'INSERT INTO ref.branded_drug (description, preparation) VALUES (%(brand)s, %(prep)s) RETURNING pk'
2077 args = {'brand': brand_name, 'prep': preparation}
2078 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True, get_col_idx = False)
2079
2080 return cBrandedDrug(aPK_obj = rows[0]['pk'])
2081
2083 queries = []
2084 args = {'pk': brand}
2085
2086
2087 cmd = u"""
2088 DELETE FROM ref.lnk_substance2brand
2089 WHERE
2090 fk_brand = %(pk)s
2091 AND
2092 NOT EXISTS (
2093 SELECT 1
2094 FROM clin.v_pat_substance_intake
2095 WHERE pk_brand = %(pk)s
2096 LIMIT 1
2097 )
2098 """
2099 queries.append({'cmd': cmd, 'args': args})
2100
2101
2102 cmd = u"""
2103 DELETE FROM ref.branded_drug
2104 WHERE
2105 pk = %(pk)s
2106 AND
2107 NOT EXISTS (
2108 SELECT 1
2109 FROM clin.v_pat_substance_intake
2110 WHERE pk_brand = %(pk)s
2111 LIMIT 1
2112 )
2113 """
2114 queries.append({'cmd': cmd, 'args': args})
2115
2116 gmPG2.run_rw_queries(queries = queries)
2117
2118
2119
2120 if __name__ == "__main__":
2121
2122 if len(sys.argv) < 2:
2123 sys.exit()
2124
2125 if sys.argv[1] != 'test':
2126 sys.exit()
2127
2128 from Gnumed.pycommon import gmLog2
2129 from Gnumed.pycommon import gmI18N
2130 from Gnumed.business import gmPerson
2131
2132 gmI18N.activate_locale()
2133
2134
2140
2142 mmi_file = cGelbeListeCSVFile(filename = sys.argv[2])
2143 for drug in mmi_file:
2144 print "-------------"
2145 print '"%s" (ATC: %s / PZN: %s)' % (drug['name'], drug['atc'], drug['pzn'])
2146 for stoff in drug['wirkstoffe']:
2147 print " Wirkstoff:", stoff
2148 raw_input()
2149 if mmi_file.has_unknown_fields is not None:
2150 print "has extra data under [%s]" % gmTools.default_csv_reader_rest_key
2151 for key in mmi_file.csv_fieldnames:
2152 print key, '->', drug[key]
2153 raw_input()
2154 mmi_file.close()
2155
2159
2161 mmi = cGelbeListeWineInterface()
2162 mmi_file = mmi.__let_user_select_drugs()
2163 for drug in mmi_file:
2164 print "-------------"
2165 print '"%s" (ATC: %s / PZN: %s)' % (drug['name'], drug['atc'], drug['pzn'])
2166 for stoff in drug['wirkstoffe']:
2167 print " Wirkstoff:", stoff
2168 print drug
2169 mmi_file.close()
2170
2174
2176 mmi = cGelbeListeInterface()
2177 print mmi
2178 print "interface definition:", mmi.version
2179
2180 diclofenac = '7587712'
2181 phenprocoumon = '4421744'
2182 mmi.check_interactions(drug_ids_list = [diclofenac, phenprocoumon])
2183
2184
2185
2192
2198
2199
2200
2202 drug = create_substance_intake (
2203 pk_component = 2,
2204 encounter = 1,
2205 episode = 1
2206 )
2207 print drug
2208
2213
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228 test_fd_switch_to()
2229
2230
2231
2232
2233
2234
2235
2236
2237