Package Gnumed :: Package business :: Module gmMedication
[frames] | no frames]

Source Code for Module Gnumed.business.gmMedication

   1  # -*- coding: utf8 -*- 
   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, logging, csv, codecs, os, re as regex, subprocess 
  11   
  12   
  13  if __name__ == '__main__': 
  14          sys.path.insert(0, '../../') 
  15  from Gnumed.pycommon import gmBusinessDBObject, gmPG2, gmShellAPI, gmTools 
  16  from Gnumed.pycommon import gmDispatcher, gmDateTime, gmHooks 
  17  from Gnumed.business import gmATC, gmAllergy 
  18   
  19   
  20  _log = logging.getLogger('gm.meds') 
  21  _log.info(__version__) 
  22   
  23  #============================================================ 
24 -def _on_substance_intake_modified():
25 """Always relates to the active patient.""" 26 gmHooks.run_hook_script(hook = u'after_substance_intake_modified')
27 28 gmDispatcher.connect(_on_substance_intake_modified, u'substance_intake_mod_db') 29 30 #============================================================
31 -def drug2renal_insufficiency_url(search_term=None):
32 33 if search_term is None: 34 return u'http://www.dosing.de' 35 36 terms = [] 37 names = [] 38 39 if isinstance(search_term, cBrandedDrug): 40 if search_term['atc_code'] is not None: 41 terms.append(search_term['atc_code']) 42 43 elif isinstance(search_term, cSubstanceIntakeEntry): 44 names.append(search_term['substance']) 45 if search_term['atc_brand'] is not None: 46 terms.append(search_term['atc_brand']) 47 if search_term['atc_substance'] is not None: 48 terms.append(search_term['atc_substance']) 49 50 elif search_term is not None: 51 names.append(u'%s' % search_term) 52 terms.extend(gmATC.text2atc(text = u'%s' % search_term, fuzzy = True)) 53 54 for name in names: 55 if name.endswith('e'): 56 terms.append(name[:-1]) 57 else: 58 terms.append(name) 59 60 #url_template = u'http://www.google.de/#q=site%%3Adosing.de+%s' 61 #url = url_template % u'+OR+'.join(terms) 62 63 url_template = u'http://www.google.de/search?hl=de&source=hp&q=site%%3Adosing.de+%s&btnG=Google-Suche' 64 url = url_template % u'+OR+'.join(terms) 65 66 _log.debug(u'renal insufficiency URL: %s', url) 67 68 return url
69 #============================================================ 70 # this should be in gmCoding.py
71 -def create_data_source(long_name=None, short_name=None, version=None, source=None, language=None):
72 73 args = { 74 'lname': long_name, 75 'sname': short_name, 76 'ver': version, 77 'src': source, 78 'lang': language 79 } 80 81 cmd = u"""select pk from ref.data_source where name_long = %(lname)s and name_short = %(sname)s and version = %(ver)s""" 82 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}]) 83 if len(rows) > 0: 84 return rows[0]['pk'] 85 86 cmd = u""" 87 INSERT INTO ref.data_source (name_long, name_short, version, source, lang) 88 VALUES ( 89 %(lname)s, 90 %(sname)s, 91 %(ver)s, 92 %(src)s, 93 %(lang)s 94 ) 95 returning pk 96 """ 97 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True) 98 99 return rows[0]['pk']
100 #============================================================ 101 # wishlist: 102 # - --conf-file= for glwin.exe 103 # - wirkstoff: Konzentration auch in Multiprodukten 104 # - wirkstoff: ATC auch in Multiprodukten 105 # - Suche nach ATC per CLI 106
107 -class cGelbeListeCSVFile(object):
108 """Iterator over a Gelbe Liste/MMI v8.2 CSV file.""" 109 110 version = u'Gelbe Liste/MMI v8.2 CSV file interface' 111 default_transfer_file_windows = r"c:\rezept.txt" 112 #default_encoding = 'cp1252' 113 default_encoding = 'cp1250' 114 csv_fieldnames = [ 115 u'name', 116 u'packungsgroesse', # obsolete, use "packungsmenge" 117 u'darreichungsform', 118 u'packungstyp', 119 u'festbetrag', 120 u'avp', 121 u'hersteller', 122 u'rezepttext', 123 u'pzn', 124 u'status_vertrieb', 125 u'status_rezeptpflicht', 126 u'status_fachinfo', 127 u'btm', 128 u'atc', 129 u'anzahl_packungen', 130 u'zuzahlung_pro_packung', 131 u'einheit', 132 u'schedule_morgens', 133 u'schedule_mittags', 134 u'schedule_abends', 135 u'schedule_nachts', 136 u'status_dauermedikament', 137 u'status_hausliste', 138 u'status_negativliste', 139 u'ik_nummer', 140 u'status_rabattvertrag', 141 u'wirkstoffe', 142 u'wirkstoffmenge', 143 u'wirkstoffeinheit', 144 u'wirkstoffmenge_bezug', 145 u'wirkstoffmenge_bezugseinheit', 146 u'status_import', 147 u'status_lifestyle', 148 u'status_ausnahmeliste', 149 u'packungsmenge', 150 u'apothekenpflicht', 151 u'status_billigere_packung', 152 u'rezepttyp', 153 u'besonderes_arzneimittel', # Abstimmungsverfahren SGB-V 154 u't_rezept_pflicht', # Thalidomid-Rezept 155 u'erstattbares_medizinprodukt', 156 u'hilfsmittel', 157 u'hzv_rabattkennung', 158 u'hzv_preis' 159 ] 160 boolean_fields = [ 161 u'status_rezeptpflicht', 162 u'status_fachinfo', 163 u'btm', 164 u'status_dauermedikament', 165 u'status_hausliste', 166 u'status_negativliste', 167 u'status_rabattvertrag', 168 u'status_import', 169 u'status_lifestyle', 170 u'status_ausnahmeliste', 171 u'apothekenpflicht', 172 u'status_billigere_packung', 173 u'besonderes_arzneimittel', # Abstimmungsverfahren SGB-V 174 u't_rezept_pflicht', 175 u'erstattbares_medizinprodukt', 176 u'hilfsmittel' 177 ] 178 #--------------------------------------------------------
179 - def __init__(self, filename=None):
180 181 _log.info(cGelbeListeCSVFile.version) 182 183 self.filename = filename 184 if filename is None: 185 self.filename = cGelbeListeCSVFile.default_transfer_file_windows 186 187 _log.debug('reading Gelbe Liste/MMI drug data from [%s]', self.filename) 188 189 self.csv_file = codecs.open(filename = filename, mode = 'rUb', encoding = cGelbeListeCSVFile.default_encoding) 190 191 self.csv_lines = gmTools.unicode_csv_reader ( 192 self.csv_file, 193 fieldnames = cGelbeListeCSVFile.csv_fieldnames, 194 delimiter = ';', 195 quotechar = '"', 196 dict = True 197 )
198 #--------------------------------------------------------
199 - def __iter__(self):
200 return self
201 #--------------------------------------------------------
202 - def next(self):
203 line = self.csv_lines.next() 204 205 for field in cGelbeListeCSVFile.boolean_fields: 206 line[field] = (line[field].strip() == u'T') 207 208 # split field "Wirkstoff" by ";" 209 if line['wirkstoffe'].strip() == u'': 210 line['wirkstoffe'] = [] 211 else: 212 line['wirkstoffe'] = [ wirkstoff.strip() for wirkstoff in line['wirkstoffe'].split(u';') ] 213 214 return line
215 #--------------------------------------------------------
216 - def close(self, truncate=True):
217 try: self.csv_file.close() 218 except: pass 219 220 if truncate: 221 try: os.open(self.filename, 'wb').close 222 except: pass
223 #--------------------------------------------------------
224 - def _get_has_unknown_fields(self):
226 227 has_unknown_fields = property(_get_has_unknown_fields, lambda x:x)
228 #============================================================
229 -class cDrugDataSourceInterface(object):
230 231 #--------------------------------------------------------
232 - def __init__(self):
233 self.patient = None 234 self.custom_path_to_binary = None
235 #--------------------------------------------------------
236 - def get_data_source_version(self):
237 raise NotImplementedError
238 #--------------------------------------------------------
239 - def create_data_source_entry(self):
240 raise NotImplementedError
241 #--------------------------------------------------------
242 - def switch_to_frontend(self, blocking=False):
243 raise NotImplementedError
244 #--------------------------------------------------------
245 - def select_drugs(self):
246 raise NotImplementedError
247 #--------------------------------------------------------
248 - def import_drugs(self):
249 raise NotImplementedError
250 #--------------------------------------------------------
251 - def check_drug_interactions(self, drug_ids_list=None, substances=None):
252 raise NotImplementedError
253 #--------------------------------------------------------
254 - def show_info_on_drug(self, drug=None):
255 raise NotImplementedError
256 #--------------------------------------------------------
257 - def show_info_on_substance(self, substance=None):
258 raise NotImplementedError
259 #============================================================
260 -class cFreeDiamsInterface(cDrugDataSourceInterface):
261 262 version = u'FreeDiams v0.5.0 interface' 263 default_encoding = 'utf8' 264 default_dob_format = '%Y/%m/%d' 265 266 map_gender2mf = { 267 'm': u'M', 268 'f': u'F', 269 'tf': u'H', 270 'tm': u'H', 271 'h': u'H' 272 } 273 #--------------------------------------------------------
274 - def __init__(self):
275 cDrugDataSourceInterface.__init__(self) 276 _log.info(cFreeDiamsInterface.version) 277 278 paths = gmTools.gmPaths() 279 self.__gm2fd_filename = os.path.join(paths.home_dir, '.gnumed', 'tmp', 'gm2freediams.xml') 280 self.__fd2gm_filename = os.path.join(paths.home_dir, '.gnumed', 'tmp', 'freediams2gm.xml') 281 self.__fd4gm_config_file = os.path.join(paths.home_dir, '.gnumed', 'freediams4gm.conf') 282 283 self.path_to_binary = None 284 self.__detect_binary()
285 #--------------------------------------------------------
286 - def get_data_source_version(self):
287 # ~/.freediams/config.ini: [License] -> AcceptedVersion=.... 288 289 if not self.__detect_binary(): 290 return False 291 292 freediams = subprocess.Popen ( 293 args = u'--version', # --version or -version or -v 294 executable = self.path_to_binary, 295 stdout = subprocess.PIPE, 296 stderr = subprocess.PIPE, 297 # close_fds = True, # Windows can't do that in conjunction with stdout/stderr = ... :-( 298 universal_newlines = True 299 ) 300 data, errors = freediams.communicate() 301 version = regex.search('FreeDiams\s\d.\d.\d', data).group().split()[1] 302 _log.debug('FreeDiams %s', version) 303 304 return version
305 #--------------------------------------------------------
306 - def create_data_source_entry(self):
307 return create_data_source ( 308 long_name = u'"FreeDiams" Drug Database Frontend', 309 short_name = u'FreeDiams', 310 version = self.get_data_source_version(), 311 source = u'http://ericmaeker.fr/FreeMedForms/di-manual/index.html', 312 language = u'fr' # actually to be multi-locale 313 )
314 #--------------------------------------------------------
315 - def switch_to_frontend(self, blocking=False):
316 """http://ericmaeker.fr/FreeMedForms/di-manual/en/html/ligne_commandes.html""" 317 318 if not self.__detect_binary(): 319 return False 320 321 self.__create_gm2fd_file() 322 open(self.__fd2gm_filename, 'wb').close() 323 324 args = u'--exchange-in="%s"' % (self.__gm2fd_filename) 325 cmd = r'%s %s' % (self.path_to_binary, args) 326 if not gmShellAPI.run_command_in_shell(command = cmd, blocking = blocking): 327 _log.error('problem switching to the FreeDiams drug database') 328 return False 329 330 return True
331 #--------------------------------------------------------
332 - def select_drugs(self):
333 self.switch_to_frontend()
334 #--------------------------------------------------------
335 - def import_drugs(self):
336 """FreeDiams ONLY use CIS. 337 338 CIS stands for Unique Speciality Identifier (eg bisoprolol 5 mg, gel). 339 CIS is AFSSAPS specific, but pharmacist can retreive drug name with the CIS. 340 AFSSAPS is the French FDA. 341 342 CIP stands for Unique Presentation Identifier (eg 30 pills plaq) 343 CIP if you want to specify the packaging of the drug (30 pills 344 thermoformed tablet...) -- actually not really usefull for french 345 doctors. 346 # .external_code_type: u'FR-CIS' 347 # .external_cod: the CIS value 348 """ 349 self.switch_to_frontend(blocking = True) 350 self.import_fd2gm_file()
351 #--------------------------------------------------------
352 - def check_drug_interactions(self, drug_ids_list=None, substances=None):
353 self.switch_to_frontend()
354 #--------------------------------------------------------
355 - def show_info_on_drug(self, drug=None):
356 # pass in CIS 357 self.switch_to_frontend()
358 #--------------------------------------------------------
359 - def show_info_on_substance(self, substance=None):
360 # pass in CIS 361 self.switch_to_frontend()
362 #-------------------------------------------------------- 363 # internal helpers 364 #--------------------------------------------------------
365 - def __detect_binary(self):
366 367 if self.path_to_binary is not None: 368 return True 369 370 found, cmd = gmShellAPI.find_first_binary(binaries = [ 371 r'/usr/bin/freediams', 372 r'freediams', 373 r'/Applications/FreeDiams.app/Contents/MacOs/FreeDiams', 374 r'c:\programs\freediams\freediams.exe', 375 r'freediams.exe' 376 ]) 377 378 if found: 379 self.path_to_binary = cmd 380 return True 381 382 try: 383 self.custom_path_to_binary 384 except AttributeError: 385 _log.error('cannot find FreeDiams binary, no custom path set') 386 return False 387 388 found, cmd = gmShellAPI.detect_external_binary(binary = self.custom_path_to_binary) 389 if found: 390 self.path_to_binary = cmd 391 return True 392 393 _log.error('cannot find FreeDiams binary') 394 return False
395 #--------------------------------------------------------
396 - def __create_prescription_file(self):
397 398 u"""<?xml version = "1.0" encoding = "UTF-8"?> 399 400 <FreeDiams> 401 <!-- <DrugsDatabaseName>FR_AFSSAPS</DrugsDatabaseName> --> 402 <FullPrescription version="0.4.0"> 403 </FullPrescription> 404 </FreeDiams> 405 """ 406 407 drug_snippet = u""" 408 <Prescription> 409 <OnlyForTest>True</OnlyForTest> 410 <Drug_UID>%s</Drug_UID> 411 </Prescription> 412 """ 413 414 xml_file = codecs.open(self.__gm2fd_filename, 'wb', 'utf8') 415 if self.patient is None: 416 xml_file.close() 417 return
418 419 #--------------------------------------------------------
420 - def __create_gm2fd_file(self):
421 422 xml_file = codecs.open(self.__gm2fd_filename, 'wb', 'utf8') 423 424 xml = u"""<?xml version="1.0" encoding="UTF-8"?> 425 426 <!-- Eric says the order of same-level nodes does not matter. --> 427 428 <FreeDiams_In version="0.5.0"> 429 <EMR name="GNUmed" uid="unused"/> 430 <ConfigFile value="%s"/> 431 <ExchangeOut value="%s" format="xml"/> <!-- should perhaps better be html_xml ? --> 432 <!-- <DrugsDatabase uid="can be set to a specific DB"/> --> 433 <Ui editmode="select-only" blockPatientDatas="1"/> 434 %%s 435 </FreeDiams_In> 436 437 <!-- 438 # FIXME: search by LOINC code and add (as soon as supported by FreeDiams ...) 439 <Creatinine value="12" unit="mg/l or mmol/l"/> 440 <Weight value="70" unit="kg or pd" /> 441 <Height value="170" unit="cm or "/> 442 <ICD10 value="J11.0;A22;Z23"/> 443 --> 444 """ % ( 445 self.__fd4gm_config_file, 446 self.__fd2gm_filename 447 ) 448 449 if self.patient is None: 450 xml_file.write(xml % u'') 451 xml_file.close() 452 return 453 454 name = self.patient.get_active_name() 455 if self.patient['dob'] is None: 456 dob = u'' 457 else: 458 dob = self.patient['dob'].strftime(cFreeDiamsInterface.default_dob_format) 459 460 emr = self.patient.get_emr() 461 allgs = emr.get_allergies() 462 atc_allgs = [ 463 a['atc_code'] for a in allgs if ((a['atc_code'] is not None) and (a['type'] == u'allergy')) 464 ] 465 atc_sens = [ 466 a['atc_code'] for a in allgs if ((a['atc_code'] is not None) and (a['type'] == u'sensitivity')) 467 ] 468 inn_allgs = [ a['allergene'] for a in allgs if a['type'] == u'allergy' ] 469 inn_sens = [ a['allergene'] for a in allgs if a['type'] == u'sensitivity' ] 470 # this is rather fragile: FreeDiams won't know what type of UID this is 471 # (but it will assume it is of the type of the drug database in use) 472 uid_allgs = [ 473 a['substance_code'] for a in allgs if ((a['substance_code'] is not None) and (a['type'] == u'allergy')) 474 ] 475 uid_sens = [ 476 a['substance_code'] for a in allgs if ((a['substance_code'] is not None) and (a['type'] == u'sensitivity')) 477 ] 478 479 patient_xml = u"""<Patient> 480 <Identity 481 lastnames="%s" 482 firstnames="%s" 483 uid="%s" 484 dob="%s" 485 gender="%s" 486 /> 487 <ATCAllergies value="%s"/> 488 <ATCIntolerances value="%s"/> 489 490 <InnAllergies value="%s"/> 491 <InnIntolerances value="%s"/> 492 493 <DrugsUidAllergies value="%s"/> 494 <DrugsUidIntolerances value="%s"/> 495 </Patient> 496 """ % ( 497 name['lastnames'], 498 name['firstnames'], 499 self.patient.ID, 500 dob, 501 cFreeDiamsInterface.map_gender2mf[self.patient['gender']], 502 u';'.join(atc_allgs), 503 u';'.join(atc_sens), 504 u';'.join(inn_allgs), 505 u';'.join(inn_sens), 506 u';'.join(uid_allgs), 507 u';'.join(uid_sens) 508 ) 509 510 xml_file.write(xml % patient_xml) 511 xml_file.close()
512 #--------------------------------------------------------
513 - def import_fd2gm_file(self):
514 515 from xml.etree import ElementTree as etree 516 fd2gm_xml = etree.ElementTree() 517 fd2gm_xml.parse(self.__fd2gm_filename) 518 519 data_src_pk = self.create_data_source_entry() 520 521 db_id = fd2gm_xml.find('DrugsDatabaseName').text.strip() 522 drugs = fd2gm_xml.findall('FullPrescription/Prescription') 523 for drug in drugs: 524 drug_name = drug.find('DrugName').text.replace(', )', ')').strip() 525 drug_uid = drug.find('Drug_UID').text.strip() 526 drug_form = drug.find('DrugForm').text.strip() 527 #drug_atc = drug.find('DrugATC').text.strip() # asked Eric to include 528 529 new_drug = create_branded_drug(brand_name = drug_name, preparation = drug_form, return_existing = True) 530 # update fields 531 new_drug['is_fake_brand'] = False 532 #new_drug['atc'] = drug_atc 533 new_drug['external_code_type'] = u'FreeDiams::%s' % db_id 534 new_drug['external_code'] = drug_uid 535 new_drug['pk_data_source'] = data_src_pk 536 new_drug.save() 537 538 components = drug.getiterator('Composition') 539 for comp in components: 540 541 subst = comp.attrib['molecularName'].strip() 542 inn = comp.attrib['inn'].strip() 543 if inn != u'': 544 create_consumable_substance(substance = inn, atc = None) 545 if subst == u'': 546 subst = inn 547 548 amount = regex.match(r'\d+[.,]{0,1}\d*', comp.attrib['strenght'].strip()) # sic, typo 549 if amount is None: 550 amount = 99999 551 else: 552 amount = amount.group() 553 554 unit = regex.sub(r'\d+[.,]{0,1}\d*', u'', comp.attrib['strenght'].strip()).strip() # sic, typo 555 if unit == u'': 556 unit = u'*?*' 557 558 new_drug.add_component(substance = subst, atc = None, amount = amount, unit = unit)
559 #============================================================
560 -class cGelbeListeWindowsInterface(cDrugDataSourceInterface):
561 """Support v8.2 CSV file interface only.""" 562 563 version = u'Gelbe Liste/MMI v8.2 interface' 564 default_encoding = 'cp1250' 565 bdt_line_template = u'%03d6210#%s\r\n' # Medikament verordnet auf Kassenrezept 566 bdt_line_base_length = 8 567 #--------------------------------------------------------
568 - def __init__(self):
569 570 cDrugDataSourceInterface.__init__(self) 571 572 _log.info(u'%s (native Windows)', cGelbeListeWindowsInterface.version) 573 574 self.path_to_binary = r'C:\Programme\MMI PHARMINDEX\glwin.exe' 575 self.args = r'-KEEPBACKGROUND -PRESCRIPTIONFILE %s -CLOSETOTRAY' 576 577 paths = gmTools.gmPaths() 578 579 self.default_csv_filename = os.path.join(paths.home_dir, '.gnumed', 'tmp', 'rezept.txt') 580 self.default_csv_filename_arg = os.path.join(paths.home_dir, '.gnumed', 'tmp') 581 self.interactions_filename = os.path.join(paths.home_dir, '.gnumed', 'tmp', 'gm2mmi.bdt') 582 self.data_date_filename = r'C:\Programme\MMI PHARMINDEX\datadate.txt' 583 584 self.__data_date = None 585 self.__online_update_date = None
586 587 # use adjusted config.dat 588 #--------------------------------------------------------
589 - def get_data_source_version(self, force_reload=False):
590 591 if self.__data_date is not None: 592 if not force_reload: 593 return { 594 'data': self.__data_date, 595 'online_update': self.__online_update_date 596 } 597 598 open(self.data_date_filename, 'wb').close() 599 600 cmd = u'%s -DATADATE' % self.path_to_binary 601 if not gmShellAPI.run_command_in_shell(command = cmd, blocking = True): 602 _log.error('problem querying the MMI drug database for version information') 603 self.__data_date = None 604 self.__online_update_date = None 605 return { 606 'data': u'?', 607 'online_update': u'?' 608 } 609 610 try: 611 version_file = open(self.data_date_filename, 'rU') 612 except StandardError: 613 _log.error('problem querying the MMI drug database for version information') 614 _log.exception('cannot open MMI drug database version file [%s]', self.data_date_filename) 615 self.__data_date = None 616 self.__online_update_date = None 617 return { 618 'data': u'?', 619 'online_update': u'?' 620 } 621 622 self.__data_date = version_file.readline()[:10] 623 self.__online_update_date = version_file.readline()[:10] 624 version_file.close() 625 626 return { 627 'data': self.__data_date, 628 'online_update': self.__online_update_date 629 }
630 #--------------------------------------------------------
631 - def create_data_source_entry(self):
632 versions = self.get_data_source_version() 633 634 return create_data_source ( 635 long_name = u'Medikamentendatenbank "mmi PHARMINDEX" (Gelbe Liste)', 636 short_name = u'GL/MMI', 637 version = u'Daten: %s, Preise (Onlineupdate): %s' % (versions['data'], versions['online_update']), 638 source = u'Medizinische Medien Informations GmbH, Am Forsthaus Gravenbruch 7, 63263 Neu-Isenburg', 639 language = u'de' 640 )
641 #--------------------------------------------------------
642 - def switch_to_frontend(self, blocking=False, cmd=None):
643 644 # must make sure csv file exists 645 open(self.default_csv_filename, 'wb').close() 646 647 if cmd is None: 648 cmd = (u'%s %s' % (self.path_to_binary, self.args)) % self.default_csv_filename_arg 649 650 if not gmShellAPI.run_command_in_shell(command = cmd, blocking = blocking): 651 _log.error('problem switching to the MMI drug database') 652 # apparently on the first call MMI does not 653 # consistently return 0 on success 654 # return False 655 656 return True
657 #--------------------------------------------------------
658 - def select_drugs(self, filename=None):
659 660 # better to clean up interactions file 661 open(self.interactions_filename, 'wb').close() 662 663 if not self.switch_to_frontend(blocking = True): 664 return None 665 666 return cGelbeListeCSVFile(filename = self.default_csv_filename)
667 #--------------------------------------------------------
668 - def import_drugs_as_substances(self):
669 670 selected_drugs = self.select_drugs() 671 if selected_drugs is None: 672 return None 673 674 new_substances = [] 675 676 for drug in selected_drugs: 677 atc = None # hopefully MMI eventually supports atc-per-substance in a drug... 678 if len(drug['wirkstoffe']) == 1: 679 atc = drug['atc'] 680 for wirkstoff in drug['wirkstoffe']: 681 new_substances.append(create_consumable_substance(substance = wirkstoff, atc = atc)) 682 683 selected_drugs.close() 684 685 return new_substances
686 #--------------------------------------------------------
687 - def import_drugs(self):
688 689 selected_drugs = self.select_drugs() 690 if selected_drugs is None: 691 return None 692 693 data_src_pk = self.create_data_source_entry() 694 695 new_drugs = [] 696 new_substances = [] 697 698 for entry in selected_drugs: 699 700 _log.debug('importing drug: %s %s', entry['name'], entry['darreichungsform']) 701 702 if entry[u'hilfsmittel']: 703 _log.debug('skipping Hilfsmittel') 704 continue 705 706 if entry[u'erstattbares_medizinprodukt']: 707 _log.debug('skipping sonstiges Medizinprodukt') 708 continue 709 710 # create branded drug (or get it if it already exists) 711 drug = create_branded_drug(brand_name = entry['name'], preparation = entry['darreichungsform']) 712 if drug is None: 713 drug = get_drug_by_brand(brand_name = entry['name'], preparation = entry['darreichungsform']) 714 new_drugs.append(drug) 715 716 # update fields 717 drug['is_fake'] = False 718 drug['atc_code'] = entry['atc'] 719 drug['external_code_type'] = u'DE-PZN' 720 drug['external_code'] = entry['pzn'] 721 drug['fk_data_source'] = data_src_pk 722 drug.save() 723 724 # add components to brand 725 atc = None # hopefully MMI eventually supports atc-per-substance in a drug... 726 if len(entry['wirkstoffe']) == 1: 727 atc = entry['atc'] 728 for wirkstoff in entry['wirkstoffe']: 729 drug.add_component(substance = wirkstoff, atc = atc) 730 731 # create as consumable substances, too 732 atc = None # hopefully MMI eventually supports atc-per-substance in a drug... 733 if len(entry['wirkstoffe']) == 1: 734 atc = entry['atc'] 735 for wirkstoff in entry['wirkstoffe']: 736 new_substances.append(create_consumable_substance(substance = wirkstoff, atc = atc)) 737 738 return new_drugs, new_substances
739 #--------------------------------------------------------
740 - def check_drug_interactions(self, drug_ids_list=None, substances=None):
741 """For this to work the BDT interaction check must be configured in the MMI.""" 742 743 if drug_ids_list is None: 744 if substances is None: 745 return 746 if len(substances) < 2: 747 return 748 drug_ids_list = [ (s.external_code_type, s.external_code) for s in substances ] 749 drug_ids_list = [ code_value for code_type, code_value in drug_ids_list if (code_value is not None) and (code_type == u'DE-PZN')] 750 751 else: 752 if len(drug_ids_list) < 2: 753 return 754 755 if drug_ids_list < 2: 756 return 757 758 bdt_file = codecs.open(filename = self.interactions_filename, mode = 'wb', encoding = cGelbeListeWindowsInterface.default_encoding) 759 760 for pzn in drug_ids_list: 761 pzn = pzn.strip() 762 lng = cGelbeListeWindowsInterface.bdt_line_base_length + len(pzn) 763 bdt_file.write(cGelbeListeWindowsInterface.bdt_line_template % (lng, pzn)) 764 765 bdt_file.close() 766 767 self.switch_to_frontend(blocking = False)
768 #--------------------------------------------------------
769 - def show_info_on_drug(self, drug=None):
770 self.switch_to_frontend(blocking = True)
771 #--------------------------------------------------------
772 - def show_info_on_substance(self, substance=None):
773 774 cmd = None 775 776 if substance.external_code_type == u'DE-PZN': 777 cmd = u'%s -PZN %s' % (self.path_to_binary, substance.external_code) 778 779 if cmd is None: 780 name = gmTools.coalesce ( 781 substance['brand'], 782 substance['substance'] 783 ) 784 cmd = u'%s -NAME %s' % (self.path_to_binary, name) 785 786 # better to clean up interactions file 787 open(self.interactions_filename, 'wb').close() 788 789 self.switch_to_frontend(cmd = cmd)
790 #============================================================
791 -class cGelbeListeWineInterface(cGelbeListeWindowsInterface):
792
793 - def __init__(self):
794 cGelbeListeWindowsInterface.__init__(self) 795 796 _log.info(u'%s (WINE extension)', cGelbeListeWindowsInterface.version) 797 798 # FIXME: if -CLOSETOTRAY is used GNUmed cannot detect the end of MMI 799 self.path_to_binary = r'wine "C:\Programme\MMI PHARMINDEX\glwin.exe"' 800 self.args = r'"-PRESCRIPTIONFILE %s -KEEPBACKGROUND"' 801 802 paths = gmTools.gmPaths() 803 804 self.default_csv_filename = os.path.join(paths.home_dir, '.wine', 'drive_c', 'windows', 'temp', 'mmi2gm.csv') 805 self.default_csv_filename_arg = r'c:\windows\temp\mmi2gm.csv' 806 self.interactions_filename = os.path.join(paths.home_dir, '.wine', 'drive_c', 'windows', 'temp', 'gm2mmi.bdt') 807 self.data_date_filename = os.path.join(paths.home_dir, '.wine', 'drive_c', 'Programme', 'MMI PHARMINDEX', 'datadate.txt')
808 #============================================================
809 -class cIfapInterface(cDrugDataSourceInterface):
810 """empirical CSV interface""" 811
812 - def __init__(self):
813 pass
814
815 - def print_transfer_file(self, filename=None):
816 817 try: 818 csv_file = open(filename, 'rb') # FIXME: encoding ? 819 except: 820 _log.exception('cannot access [%s]', filename) 821 csv_file = None 822 823 field_names = u'PZN Handelsname Form Abpackungsmenge Einheit Preis1 Hersteller Preis2 rezeptpflichtig Festbetrag Packungszahl Packungsgr\xf6\xdfe'.split() 824 825 if csv_file is None: 826 return False 827 828 csv_lines = csv.DictReader ( 829 csv_file, 830 fieldnames = field_names, 831 delimiter = ';' 832 ) 833 834 for line in csv_lines: 835 print "--------------------------------------------------------------------"[:31] 836 for key in field_names: 837 tmp = ('%s ' % key)[:30] 838 print '%s: %s' % (tmp, line[key]) 839 840 csv_file.close()
841 842 # narr = u'%sx %s %s %s (\u2258 %s %s) von %s (%s)' % ( 843 # line['Packungszahl'].strip(), 844 # line['Handelsname'].strip(), 845 # line['Form'].strip(), 846 # line[u'Packungsgr\xf6\xdfe'].strip(), 847 # line['Abpackungsmenge'].strip(), 848 # line['Einheit'].strip(), 849 # line['Hersteller'].strip(), 850 # line['PZN'].strip() 851 # ) 852 #============================================================ 853 drug_data_source_interfaces = { 854 'Deutschland: Gelbe Liste/MMI (Windows)': cGelbeListeWindowsInterface, 855 'Deutschland: Gelbe Liste/MMI (WINE)': cGelbeListeWineInterface, 856 'FreeDiams (France, US, Canada)': cFreeDiamsInterface 857 } 858 #============================================================ 859 # substances in use across all patients 860 #------------------------------------------------------------ 861 _SQL_get_consumable_substance = u""" 862 SELECT *, xmin 863 FROM ref.consumable_substance 864 WHERE %s 865 """ 866
867 -class cConsumableSubstance(gmBusinessDBObject.cBusinessDBObject):
868 869 _cmd_fetch_payload = _SQL_get_consumable_substance % u"pk = %s" 870 _cmds_store_payload = [ 871 u"""UPDATE ref.consumable_substance SET 872 description = %(description)s, 873 atc_code = gm.nullify_empty_string(%(atc_code)s) 874 WHERE 875 pk = %(pk)s 876 AND 877 xmin = %(xmin)s 878 AND 879 -- must not currently be used with a patient directly 880 NOT EXISTS ( 881 SELECT 1 882 FROM clin.substance_intake 883 WHERE 884 fk_drug_component IS NULL 885 AND 886 fk_substance = %(pk)s 887 LIMIT 1 888 ) 889 AND 890 -- must not currently be used with a patient indirectly, either 891 NOT EXISTS ( 892 SELECT 1 893 FROM clin.substance_intake 894 WHERE 895 fk_drug_component IS NOT NULL 896 AND 897 fk_drug_component = ( 898 SELECT r_ls2b.pk 899 FROM ref.lnk_substance2brand r_ls2b 900 WHERE fk_substance = %(pk)s 901 ) 902 LIMIT 1 903 ) 904 -- -- must not currently be used with a branded drug 905 -- -- (but this would make it rather hard fixing branded drugs which contain only this substance) 906 -- NOT EXISTS ( 907 -- SELECT 1 908 -- FROM ref.lnk_substance2brand 909 -- WHERE fk_substance = %(pk)s 910 -- LIMIT 1 911 -- ) 912 RETURNING 913 xmin 914 """ 915 ] 916 _updatable_fields = [ 917 u'description', 918 u'atc_code' 919 ]
920 #------------------------------------------------------------
921 -def get_consumable_substances(order_by=None):
922 if order_by is None: 923 order_by = u'true' 924 else: 925 order_by = u'true ORDER BY %s' % order_by 926 cmd = _SQL_get_consumable_substance % order_by 927 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = True) 928 return [ cConsumableSubstance(row = {'data': r, 'idx': idx, 'pk_field': 'pk'}) for r in rows ]
929 #------------------------------------------------------------
930 -def create_consumable_substance(substance=None, atc=None):
931 932 substance = substance.strip() 933 if atc is not None: 934 atc = atc.strip() 935 args = {'desc': substance, 'atc': atc} 936 937 cmd = u'SELECT pk FROM ref.consumable_substance WHERE lower(description) = lower(%(desc)s)' 938 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}]) 939 940 if len(rows) == 0: 941 cmd = u""" 942 INSERT INTO ref.consumable_substance (description, atc_code) VALUES ( 943 %(desc)s, 944 gm.nullify_empty_string(%(atc)s) 945 ) RETURNING pk""" 946 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True, get_col_idx = True) 947 948 gmATC.propagate_atc(substance = substance, atc = atc) 949 950 return cConsumableSubstance(aPK_obj = rows[0]['pk'])
951 #------------------------------------------------------------
952 -def delete_consumable_substance(substance=None):
953 args = {'pk': substance} 954 cmd = u""" 955 DELETE FROM ref.consumable_substance 956 WHERE 957 pk = %(pk)s 958 AND 959 960 -- must not currently be used with a patient 961 NOT EXISTS ( 962 SELECT 1 963 FROM clin.v_pat_substance_intake 964 WHERE pk_substance = %(pk)s 965 LIMIT 1 966 ) 967 AND 968 969 -- must not currently be used with a branded drug 970 NOT EXISTS ( 971 SELECT 1 972 FROM ref.lnk_substance2brand 973 WHERE fk_substance = %(pk)s 974 LIMIT 1 975 )""" 976 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}]) 977 return True
978 #============================================================
979 -class cSubstanceIntakeEntry(gmBusinessDBObject.cBusinessDBObject):
980 """Represents a substance currently taken by a patient.""" 981 982 _cmd_fetch_payload = u"SELECT * FROM clin.v_pat_substance_intake WHERE pk_substance_intake = %s" 983 _cmds_store_payload = [ 984 u"""UPDATE clin.substance_intake SET 985 clin_when = %(started)s, 986 discontinued = %(discontinued)s, 987 discontinue_reason = gm.nullify_empty_string(%(discontinue_reason)s), 988 amount = %(amount)s, 989 unit = %(unit)s, 990 preparation = %(preparation)s, 991 schedule = gm.nullify_empty_string(%(schedule)s), 992 aim = gm.nullify_empty_string(%(aim)s), 993 narrative = gm.nullify_empty_string(%(notes)s), 994 intake_is_approved_of = %(intake_is_approved_of)s, 995 996 -- is_long_term = %(is_long_term)s, 997 is_long_term = ( 998 case 999 when ( 1000 (%(is_long_term)s is False) 1001 and 1002 (%(duration)s is NULL) 1003 ) is True then null 1004 else %(is_long_term)s 1005 end 1006 )::boolean, 1007 duration = ( 1008 case 1009 when %(is_long_term)s is True then null 1010 else %(duration)s 1011 end 1012 )::interval, 1013 1014 fk_drug_component = %(pk_drug_component)s, 1015 fk_substance = %(pk_substance)s, 1016 fk_episode = %(pk_episode)s 1017 WHERE 1018 pk = %(pk_substance_intake)s 1019 AND 1020 xmin = %(xmin_substance_intake)s 1021 RETURNING 1022 xmin as xmin_substance_intake 1023 """ 1024 ] 1025 _updatable_fields = [ 1026 u'started', 1027 u'discontinued', 1028 u'discontinue_reason', 1029 u'preparation', 1030 u'amount', 1031 u'unit', 1032 u'intake_is_approved_of', 1033 u'schedule', 1034 u'duration', 1035 u'aim', 1036 u'is_long_term', 1037 u'notes', 1038 u'pk_drug_component', 1039 u'pk_substance', 1040 u'pk_episode' 1041 ] 1042 #--------------------------------------------------------
1043 - def format(self, left_margin=0, date_format='%Y-%m-%d'):
1044 1045 if self._payload[self._idx['duration']] is None: 1046 duration = gmTools.bool2subst ( 1047 self._payload[self._idx['is_long_term']], 1048 _('long-term'), 1049 _('short-term'), 1050 _('?short-term') 1051 ) 1052 else: 1053 duration = gmDateTime.format_interval ( 1054 self._payload[self._idx['duration']], 1055 accuracy_wanted = gmDateTime.acc_days 1056 ) 1057 1058 line = u'%s%s (%s %s): %s %s%s %s (%s)' % ( 1059 u' ' * left_margin, 1060 self._payload[self._idx['started']].strftime(date_format), 1061 gmTools.u_right_arrow, 1062 duration, 1063 self._payload[self._idx['substance']], 1064 self._payload[self._idx['amount']], 1065 self._payload[self._idx['unit']], 1066 self._payload[self._idx['preparation']], 1067 gmTools.bool2subst(self._payload[self._idx['is_currently_active']], _('ongoing'), _('inactive'), _('?ongoing')) 1068 ) 1069 1070 return line
1071 #--------------------------------------------------------
1072 - def turn_into_allergy(self, encounter_id=None, allergy_type='allergy'):
1073 allg = gmAllergy.create_allergy ( 1074 allergene = self._payload[self._idx['substance']], 1075 allg_type = allergy_type, 1076 episode_id = self._payload[self._idx['pk_episode']], 1077 encounter_id = encounter_id 1078 ) 1079 allg['substance'] = gmTools.coalesce ( 1080 self._payload[self._idx['brand']], 1081 self._payload[self._idx['substance']] 1082 ) 1083 allg['reaction'] = self._payload[self._idx['discontinue_reason']] 1084 allg['atc_code'] = gmTools.coalesce(self._payload[self._idx['atc_substance']], self._payload[self._idx['atc_brand']]) 1085 if self._payload[self._idx['external_code_brand']] is not None: 1086 allg['substance_code'] = u'%s::::%s' % (self._payload[self._idx['external_code_type_brand']], self._payload[self._idx['external_code_brand']]) 1087 allg['allergene'] = self._payload[self._idx['substance']] 1088 comps = [ c['description'] for c in self.containing_drug.components ] 1089 if len(comps) == 0: 1090 allg['generics'] = self._payload[self._idx['substance']] 1091 else: 1092 allg['generics'] = u'; '.join(comps) 1093 1094 allg.save() 1095 return allg
1096 #-------------------------------------------------------- 1097 # properties 1098 #--------------------------------------------------------
1099 - def _get_ddd(self):
1100 1101 try: self.__ddd 1102 except AttributeError: self.__ddd = None 1103 1104 if self.__ddd is not None: 1105 return self.__ddd 1106 1107 if self._payload[self._idx['atc_substance']] is not None: 1108 ddd = gmATC.atc2ddd(atc = self._payload[self._idx['atc_substance']]) 1109 if len(ddd) != 0: 1110 self.__ddd = ddd[0] 1111 else: 1112 if self._payload[self._idx['atc_brand']] is not None: 1113 ddd = gmATC.atc2ddd(atc = self._payload[self._idx['atc_brand']]) 1114 if len(ddd) != 0: 1115 self.__ddd = ddd[0] 1116 1117 return self.__ddd
1118 1119 ddd = property(_get_ddd, lambda x:x) 1120 #--------------------------------------------------------
1121 - def _get_external_code(self):
1122 drug = self.containing_drug 1123 1124 if drug is None: 1125 return None 1126 1127 return drug.external_code
1128 1129 external_code = property(_get_external_code, lambda x:x) 1130 #--------------------------------------------------------
1131 - def _get_external_code_type(self):
1132 drug = self.containing_drug 1133 1134 if drug is None: 1135 return None 1136 1137 return drug.external_code_type
1138 1139 external_code_type = property(_get_external_code_type, lambda x:x) 1140 #--------------------------------------------------------
1141 - def _get_containing_drug(self):
1142 if self._payload[self._idx['pk_brand']] is None: 1143 return None 1144 1145 return cBrandedDrug(aPK_obj = self._payload[self._idx['pk_brand']])
1146 1147 containing_drug = property(_get_containing_drug, lambda x:x) 1148 #--------------------------------------------------------
1149 - def _get_parsed_schedule(self):
1150 tests = [ 1151 # lead, trail 1152 ' 1-1-1-1 ', 1153 # leading dose 1154 '1-1-1-1', 1155 '22-1-1-1', 1156 '1/3-1-1-1', 1157 '/4-1-1-1' 1158 ] 1159 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}$" 1160 for test in tests: 1161 print test.strip(), ":", regex.match(pattern, test.strip())
1162 #------------------------------------------------------------
1163 -def create_substance_intake(substance=None, drug_component=None, atc=None, encounter=None, episode=None, preparation=None):
1164 1165 args = { 1166 'enc': encounter, 1167 'epi': episode, 1168 'prep': preparation, 1169 'comp': drug_component, 1170 'subst': create_consumable_substance(substance = substance, atc = atc)['pk'] 1171 } 1172 1173 if drug_component is None: 1174 cmd = u""" 1175 INSERT INTO clin.substance_intake ( 1176 fk_encounter, 1177 fk_episode, 1178 fk_substance, 1179 preparation, 1180 intake_is_approved_of 1181 ) VALUES ( 1182 %(enc)s, 1183 %(epi)s, 1184 %(subst)s, 1185 gm.nullify_empty_string(%(prep)s), 1186 False 1187 ) 1188 RETURNING pk""" 1189 else: 1190 cmd = u""" 1191 INSERT INTO clin.substance_intake ( 1192 fk_encounter, 1193 fk_episode, 1194 fk_drug_component, 1195 intake_is_approved_of 1196 ) VALUES ( 1197 %(enc)s, 1198 %(epi)s, 1199 %(comp)s, 1200 False 1201 ) 1202 RETURNING pk""" 1203 1204 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True) 1205 return cSubstanceIntakeEntry(aPK_obj = rows[0][0])
1206 #------------------------------------------------------------
1207 -def delete_substance_intake(substance=None):
1208 cmd = u'delete from clin.substance_intake where pk = %(pk)s' 1209 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': {'pk': substance}}])
1210 #------------------------------------------------------------
1211 -def format_substance_intake_notes(emr=None, output_format=u'latex', table_type=u'by-brand'):
1212 1213 tex = u'\n{\\small\n' 1214 tex += u'\\noindent %s\n' % _('Additional notes') 1215 tex += u'\n' 1216 tex += u'\\noindent \\begin{tabular}{|l|l|l|l|}\n' 1217 tex += u'\\hline\n' 1218 tex += u'%s & %s & %s & \\\\ \n' % (_('Substance'), _('Strength'), _('Brand')) 1219 tex += u'\\hline\n' 1220 tex += u'%s\n' 1221 tex += u'\n' 1222 tex += u'\\end{tabular}\n' 1223 tex += u'}\n' 1224 1225 current_meds = emr.get_current_substance_intake ( 1226 include_inactive = False, 1227 include_unapproved = False, 1228 order_by = u'brand, substance' 1229 ) 1230 1231 # create lines 1232 lines = [] 1233 for med in current_meds: 1234 1235 lines.append(u'%s & %s%s & %s %s & {\\scriptsize %s} \\\\ \n \\hline \n' % ( 1236 med['substance'], 1237 med['amount'], 1238 med['unit'], 1239 gmTools.coalesce(med['brand'], u''), 1240 med['preparation'], 1241 gmTools.coalesce(med['notes'], u'') 1242 )) 1243 1244 return tex % u' \n'.join(lines)
1245 1246 #------------------------------------------------------------
1247 -def format_substance_intake(emr=None, output_format=u'latex', table_type=u'by-brand'):
1248 1249 tex = u'\\noindent %s {\\tiny (%s)\\par}\n' % (_('Medication list'), _('ordered by brand')) 1250 tex += u'\n' 1251 tex += u'\\noindent \\begin{tabular}{|l|l|}\n' 1252 tex += u'\\hline\n' 1253 tex += u'%s & %s \\\\ \n' % (_('Drug'), _('Regimen')) 1254 tex += u'\\hline\n' 1255 tex += u'\n' 1256 tex += u'\\hline\n' 1257 tex += u'%s\n' 1258 tex += u'\n' 1259 tex += u'\\end{tabular}\n' 1260 1261 current_meds = emr.get_current_substance_intake ( 1262 include_inactive = False, 1263 include_unapproved = False, 1264 order_by = u'brand, substance' 1265 ) 1266 1267 # aggregate data 1268 line_data = {} 1269 for med in current_meds: 1270 identifier = gmTools.coalesce(med['brand'], med['substance']) 1271 1272 try: 1273 line_data[identifier] 1274 except KeyError: 1275 line_data[identifier] = {'brand': u'', 'preparation': u'', 'schedule': u'', 'aims': [], 'strengths': []} 1276 1277 line_data[identifier]['brand'] = identifier 1278 line_data[identifier]['strengths'].append(u'%s%s' % (med['amount'].strip(), med['unit'].strip())) 1279 line_data[identifier]['preparation'] = med['preparation'] 1280 line_data[identifier]['schedule'] = gmTools.coalesce(med['schedule'], u'') 1281 if med['aim'] not in line_data[identifier]['aims']: 1282 line_data[identifier]['aims'].append(med['aim']) 1283 1284 # create lines 1285 already_seen = [] 1286 lines = [] 1287 line1_template = u'%s %s & %s \\\\' 1288 line2_template = u' & {\\scriptsize %s\\par} \\\\' 1289 1290 for med in current_meds: 1291 identifier = gmTools.coalesce(med['brand'], med['substance']) 1292 1293 if identifier in already_seen: 1294 continue 1295 1296 already_seen.append(identifier) 1297 1298 lines.append (line1_template % ( 1299 line_data[identifier]['brand'], 1300 line_data[identifier]['preparation'], 1301 line_data[identifier]['schedule'] 1302 )) 1303 1304 strengths = u'/'.join(line_data[identifier]['strengths']) 1305 if strengths == u'': 1306 template = u' & {\\scriptsize %s\\par} \\\\' 1307 for aim in line_data[identifier]['aims']: 1308 lines.append(template % aim) 1309 else: 1310 if len(line_data[identifier]['aims']) == 0: 1311 template = u'%s & \\\\' 1312 lines.append(template % strengths) 1313 else: 1314 template = u'%s & {\\scriptsize %s\\par} \\\\' 1315 lines.append(template % (strengths, line_data[identifier]['aims'][0])) 1316 template = u' & {\\scriptsize %s\\par} \\\\' 1317 for aim in line_data[identifier]['aims'][1:]: 1318 lines.append(template % aim) 1319 1320 lines.append(u'\\hline') 1321 1322 return tex % u' \n'.join(lines)
1323 #============================================================ 1324 _SQL_get_drug_components = u'SELECT * FROM ref.v_drug_components WHERE %s' 1325
1326 -class cDrugComponent(gmBusinessDBObject.cBusinessDBObject):
1327 1328 _cmd_fetch_payload = _SQL_get_drug_components % u'pk_component = %s' 1329 _cmds_store_payload = [ 1330 u"""UPDATE ref.lnk_substance2brand SET 1331 fk_brand = %(pk_brand)s, 1332 fk_substance = %(pk_consumable_substance)s, 1333 amount = %(amount)s, 1334 unit = gm.nullify_empty_string(%(unit)s) 1335 WHERE 1336 NOT EXISTS ( 1337 SELECT 1 1338 FROM clin.substance_intake 1339 WHERE fk_drug_component = %(pk_component)s 1340 LIMIT 1 1341 ) 1342 AND 1343 pk = %(pk_component)s 1344 AND 1345 xmin = %(xmin_lnk_substance2brand)s 1346 RETURNING 1347 xmin AS xmin_lnk_substance2brand 1348 """ 1349 ] 1350 _updatable_fields = [ 1351 u'pk_brand', 1352 u'pk_consumable_substance', 1353 u'amount', 1354 u'unit' 1355 ] 1356 #-------------------------------------------------------- 1357 # properties 1358 #--------------------------------------------------------
1359 - def _get_containing_drug(self):
1360 return cBrandedDrug(aPK_obj = self._payload[self._idx['pk_brand']])
1361 1362 containing_drug = property(_get_containing_drug, lambda x:x)
1363 #------------------------------------------------------------
1364 -def get_drug_components():
1365 cmd = _SQL_get_drug_components % u'true ORDER BY brand, substance' 1366 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = True) 1367 return [ cDrugComponent(row = {'data': r, 'idx': idx, 'pk_field': 'pk_component'}) for r in rows ]
1368 #============================================================
1369 -class cBrandedDrug(gmBusinessDBObject.cBusinessDBObject):
1370 """Represents a drug as marketed by a manufacturer.""" 1371 1372 _cmd_fetch_payload = u"SELECT * FROM ref.v_branded_drugs WHERE pk_brand = %s" 1373 _cmds_store_payload = [ 1374 u"""UPDATE ref.branded_drug SET 1375 description = %(brand)s, 1376 preparation = %(preparation)s, 1377 atc_code = gm.nullify_empty_string(%(atc)s), 1378 external_code = gm.nullify_empty_string(%(external_code)s), 1379 external_code_type = gm.nullify_empty_string(%(external_code_type)s), 1380 is_fake = %(is_fake_brand)s, 1381 fk_data_source = %(pk_data_source)s 1382 WHERE 1383 pk = %(pk_brand)s 1384 AND 1385 xmin = %(xmin_branded_drug)s 1386 RETURNING 1387 xmin AS xmin_branded_drug 1388 """ 1389 ] 1390 _updatable_fields = [ 1391 u'brand', 1392 u'preparation', 1393 u'atc', 1394 u'is_fake_brand', 1395 u'external_code', 1396 u'external_code_type', 1397 u'pk_data_source' 1398 ] 1399 #--------------------------------------------------------
1400 - def add_component(self, substance=None, atc=None, amount=None, unit=None):
1401 1402 consumable = create_consumable_substance(substance = substance, atc = atc) 1403 1404 args = { 1405 'brand': self.pk_obj, 1406 'subst': consumable['description'], 1407 'atc': consumable['atc_code'], 1408 'pk_subst': consumable['pk'], 1409 'amount': amount, 1410 'unit': unit 1411 } 1412 1413 # already exists ? 1414 cmd = u""" 1415 SELECT pk_component 1416 FROM ref.v_drug_components 1417 WHERE 1418 pk_brand = %(brand)s 1419 AND 1420 (( 1421 (lower(substance) = lower(%(subst)s)) 1422 OR 1423 (atc_substance = %(atc)s) 1424 OR 1425 (pk_consumable_substance = %(pk_subst)s) 1426 ) IS TRUE) 1427 """ 1428 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False) 1429 1430 if len(rows) > 0: 1431 return 1432 1433 # create it 1434 cmd = u""" 1435 INSERT INTO ref.lnk_substance2brand (fk_brand, fk_substance, amount, unit) 1436 VALUES (%(brand)s, %(pk_subst)s, %(amount)s, %(unit)s) 1437 """ 1438 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
1439 #------------------------------------------------------------
1440 - def remove_component(self, substance=None):
1441 if len(self._payload[self._idx['components']]) == 1: 1442 _log.error('cannot remove the only component of a drug') 1443 return False 1444 1445 args = {'brand': self.pk_obj, 'comp': substance} 1446 cmd = u""" 1447 DELETE FROM ref.lnk_substance2brand 1448 WHERE 1449 fk_brand = %(brand)s 1450 AND 1451 fk_substance = %(comp)s 1452 AND 1453 NOT EXISTS ( 1454 SELECT 1 1455 FROM clin.substance_intake 1456 WHERE fk_drug_component = %(comp)s 1457 LIMIT 1 1458 ) 1459 """ 1460 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}]) 1461 return True
1462 #-------------------------------------------------------- 1463 # properties 1464 #--------------------------------------------------------
1465 - def _get_external_code(self):
1466 if self._payload[self._idx['external_code']] is None: 1467 return None 1468 1469 return self._payload[self._idx['external_code']]
1470 1471 external_code = property(_get_external_code, lambda x:x) 1472 #--------------------------------------------------------
1473 - def _get_external_code_type(self):
1474 1475 # FIXME: maybe evaluate fk_data_source ? 1476 if self._payload[self._idx['external_code_type']] is None: 1477 return None 1478 1479 return self._payload[self._idx['external_code_type']]
1480 1481 external_code_type = property(_get_external_code_type, lambda x:x) 1482 #--------------------------------------------------------
1483 - def _get_components(self):
1484 cmd = u'SELECT * FROM ref.v_drug_components WHERE pk_brand = %(brand)s' 1485 args = {'brand': self._payload[self._idx['pk_brand']]} 1486 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False) 1487 return rows
1488 1489 components = property(_get_components, lambda x:x) 1490 #--------------------------------------------------------
1491 - def _get_is_vaccine(self):
1492 cmd = u'SELECT EXISTS (SELECT 1 FROM clin.vaccine WHERE fk_brand = %(fk_brand)s)' 1493 args = {'fk_brand': self._payload[self._idx['pk_brand']]} 1494 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False) 1495 return rows[0][0]
1496 1497 is_vaccine = property(_get_is_vaccine, lambda x:x)
1498 #------------------------------------------------------------
1499 -def get_branded_drugs():
1500 cmd = u'SELECT pk FROM ref.branded_drug ORDER BY description' 1501 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = False) 1502 return [ cBrandedDrug(aPK_obj = r['pk']) for r in rows ]
1503 #------------------------------------------------------------
1504 -def get_drug_by_brand(brand_name=None, preparation=None):
1505 args = {'brand': brand_name, 'prep': preparation} 1506 1507 cmd = u'SELECT pk FROM ref.branded_drug WHERE lower(description) = lower(%(brand)s) AND lower(preparation) = lower(%(prep)s)' 1508 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False) 1509 1510 if len(rows) == 0: 1511 return None 1512 1513 return cBrandedDrug(aPK_obj = rows[0]['pk'])
1514 #------------------------------------------------------------
1515 -def create_branded_drug(brand_name=None, preparation=None, return_existing=False):
1516 1517 if preparation is None: 1518 preparation = _('units') 1519 1520 if preparation.strip() == u'': 1521 preparation = _('units') 1522 1523 if return_existing: 1524 drug = get_drug_by_brand(brand_name = brand_name, preparation = preparation) 1525 if drug is not None: 1526 return drug 1527 1528 cmd = u'INSERT INTO ref.branded_drug (description, preparation) VALUES (%(brand)s, %(prep)s) RETURNING pk' 1529 args = {'brand': brand_name, 'prep': preparation} 1530 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True, get_col_idx = False) 1531 1532 return cBrandedDrug(aPK_obj = rows[0]['pk'])
1533 #------------------------------------------------------------
1534 -def delete_branded_drug(brand=None):
1535 cmd = u""" 1536 DELETE FROM ref.branded_drug 1537 WHERE 1538 pk = %(pk)s 1539 AND 1540 NOT EXISTS ( 1541 SELECT 1 1542 FROM clin.v_pat_substance_intake 1543 WHERE pk_brand = %(pk)s 1544 LIMIT 1 1545 ) 1546 """ 1547 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': {'pk': brand}}])
1548 #============================================================ 1549 # main 1550 #------------------------------------------------------------ 1551 if __name__ == "__main__": 1552 1553 if len(sys.argv) < 2: 1554 sys.exit() 1555 1556 if sys.argv[1] != 'test': 1557 sys.exit() 1558 1559 from Gnumed.pycommon import gmLog2 1560 from Gnumed.pycommon import gmI18N 1561 from Gnumed.business import gmPerson 1562 1563 gmI18N.activate_locale() 1564 # gmDateTime.init() 1565 #--------------------------------------------------------
1566 - def test_MMI_interface():
1567 mmi = cGelbeListeWineInterface() 1568 print mmi 1569 print "interface definition:", mmi.version 1570 print "database versions: ", mmi.get_data_source_version()
1571 #--------------------------------------------------------
1572 - def test_MMI_file():
1573 mmi_file = cGelbeListeCSVFile(filename = sys.argv[2]) 1574 for drug in mmi_file: 1575 print "-------------" 1576 print '"%s" (ATC: %s / PZN: %s)' % (drug['name'], drug['atc'], drug['pzn']) 1577 for stoff in drug['wirkstoffe']: 1578 print " Wirkstoff:", stoff 1579 raw_input() 1580 if mmi_file.has_unknown_fields is not None: 1581 print "has extra data under [%s]" % gmTools.default_csv_reader_rest_key 1582 for key in mmi_file.csv_fieldnames: 1583 print key, '->', drug[key] 1584 raw_input() 1585 mmi_file.close()
1586 #--------------------------------------------------------
1587 - def test_mmi_switch_to():
1588 mmi = cGelbeListeWineInterface() 1589 mmi.switch_to_frontend(blocking = False)
1590 #--------------------------------------------------------
1591 - def test_mmi_select_drugs():
1592 mmi = cGelbeListeWineInterface() 1593 mmi_file = mmi.select_drugs() 1594 for drug in mmi_file: 1595 print "-------------" 1596 print '"%s" (ATC: %s / PZN: %s)' % (drug['name'], drug['atc'], drug['pzn']) 1597 for stoff in drug['wirkstoffe']: 1598 print " Wirkstoff:", stoff 1599 print drug 1600 mmi_file.close()
1601 #--------------------------------------------------------
1602 - def test_mmi_import_drugs():
1603 mmi = cGelbeListeWineInterface() 1604 mmi.import_drugs()
1605 #--------------------------------------------------------
1606 - def test_mmi_interaction_check():
1607 mmi = cGelbeListeInterface() 1608 print mmi 1609 print "interface definition:", mmi.version 1610 # Metoprolol + Hct vs Citalopram 1611 diclofenac = '7587712' 1612 phenprocoumon = '4421744' 1613 mmi.check_drug_interactions(drug_ids_list = [diclofenac, phenprocoumon])
1614 #-------------------------------------------------------- 1615 # FreeDiams 1616 #--------------------------------------------------------
1617 - def test_fd_switch_to():
1618 gmPerson.set_active_patient(patient = gmPerson.cIdentity(aPK_obj = 12)) 1619 fd = cFreeDiamsInterface() 1620 fd.patient = gmPerson.gmCurrentPatient() 1621 fd.switch_to_frontend(blocking = True) 1622 fd.import_fd2gm_file()
1623 #-------------------------------------------------------- 1624 # generic 1625 #--------------------------------------------------------
1626 - def test_create_substance_intake():
1627 drug = create_substance_intake ( 1628 substance = u'Whiskey', 1629 atc = u'no ATC available', 1630 encounter = 1, 1631 episode = 1, 1632 preparation = 'a nice glass' 1633 ) 1634 print drug
1635 #--------------------------------------------------------
1636 - def test_show_components():
1637 drug = cBrandedDrug(aPK_obj = sys.argv[2]) 1638 print drug 1639 print drug.components
1640 #--------------------------------------------------------
1641 - def test_get_consumable_substances():
1642 for s in get_consumable_substances(): 1643 print s
1644 #-------------------------------------------------------- 1645 # MMI/Gelbe Liste 1646 #test_MMI_interface() 1647 #test_MMI_file() 1648 #test_mmi_switch_to() 1649 #test_mmi_select_drugs() 1650 #test_mmi_import_substances() 1651 #test_mmi_import_drugs() 1652 1653 # FreeDiams 1654 test_fd_switch_to() 1655 1656 # generic 1657 #test_interaction_check() 1658 #test_create_substance_intake() 1659 #test_show_components() 1660 #test_get_consumable_substances() 1661 #============================================================ 1662