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 
  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 _log.debug(u'renal insufficiency URL: %s', url) 64 65 return url
66 #============================================================ 67 # this should be in gmCoding.py
68 -def create_data_source(long_name=None, short_name=None, version=None, source=None, language=None):
69 70 args = { 71 'lname': long_name, 72 'sname': short_name, 73 'ver': version, 74 'src': source, 75 'lang': language 76 } 77 78 cmd = u"""select pk from ref.data_source where name_long = %(lname)s and name_short = %(sname)s and version = %(ver)s""" 79 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}]) 80 if len(rows) > 0: 81 return rows[0]['pk'] 82 83 cmd = u""" 84 INSERT INTO ref.data_source (name_long, name_short, version, source, lang) 85 VALUES ( 86 %(lname)s, 87 %(sname)s, 88 %(ver)s, 89 %(src)s, 90 %(lang)s 91 ) 92 returning pk 93 """ 94 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True) 95 96 return rows[0]['pk']
97 #============================================================ 98 # wishlist: 99 # - --conf-file= for glwin.exe 100 # - wirkstoff: Konzentration auch in Multiprodukten 101 # - wirkstoff: ATC auch in Multiprodukten 102 # - Suche nach ATC per CLI 103
104 -class cGelbeListeCSVFile(object):
105 """Iterator over a Gelbe Liste/MMI v8.2 CSV file.""" 106 107 version = u'Gelbe Liste/MMI v8.2 CSV file interface' 108 default_transfer_file_windows = r"c:\rezept.txt" 109 #default_encoding = 'cp1252' 110 default_encoding = 'cp1250' 111 csv_fieldnames = [ 112 u'name', 113 u'packungsgroesse', # obsolete, use "packungsmenge" 114 u'darreichungsform', 115 u'packungstyp', 116 u'festbetrag', 117 u'avp', 118 u'hersteller', 119 u'rezepttext', 120 u'pzn', 121 u'status_vertrieb', 122 u'status_rezeptpflicht', 123 u'status_fachinfo', 124 u'btm', 125 u'atc', 126 u'anzahl_packungen', 127 u'zuzahlung_pro_packung', 128 u'einheit', 129 u'schedule_morgens', 130 u'schedule_mittags', 131 u'schedule_abends', 132 u'schedule_nachts', 133 u'status_dauermedikament', 134 u'status_hausliste', 135 u'status_negativliste', 136 u'ik_nummer', 137 u'status_rabattvertrag', 138 u'wirkstoffe', 139 u'wirkstoffmenge', 140 u'wirkstoffeinheit', 141 u'wirkstoffmenge_bezug', 142 u'wirkstoffmenge_bezugseinheit', 143 u'status_import', 144 u'status_lifestyle', 145 u'status_ausnahmeliste', 146 u'packungsmenge', 147 u'apothekenpflicht', 148 u'status_billigere_packung', 149 u'rezepttyp', 150 u'besonderes_arzneimittel', # Abstimmungsverfahren SGB-V 151 u't_rezept_pflicht', # Thalidomid-Rezept 152 u'erstattbares_medizinprodukt', 153 u'hilfsmittel', 154 u'hzv_rabattkennung', 155 u'hzv_preis' 156 ] 157 boolean_fields = [ 158 u'status_rezeptpflicht', 159 u'status_fachinfo', 160 u'btm', 161 u'status_dauermedikament', 162 u'status_hausliste', 163 u'status_negativliste', 164 u'status_rabattvertrag', 165 u'status_import', 166 u'status_lifestyle', 167 u'status_ausnahmeliste', 168 u'apothekenpflicht', 169 u'status_billigere_packung', 170 u'besonderes_arzneimittel', # Abstimmungsverfahren SGB-V 171 u't_rezept_pflicht', 172 u'erstattbares_medizinprodukt', 173 u'hilfsmittel' 174 ] 175 #--------------------------------------------------------
176 - def __init__(self, filename=None):
177 178 _log.info(cGelbeListeCSVFile.version) 179 180 self.filename = filename 181 if filename is None: 182 self.filename = cGelbeListeCSVFile.default_transfer_file_windows 183 184 _log.debug('reading Gelbe Liste/MMI drug data from [%s]', self.filename) 185 186 self.csv_file = codecs.open(filename = filename, mode = 'rUb', encoding = cGelbeListeCSVFile.default_encoding) 187 188 self.csv_lines = gmTools.unicode_csv_reader ( 189 self.csv_file, 190 fieldnames = cGelbeListeCSVFile.csv_fieldnames, 191 delimiter = ';', 192 quotechar = '"', 193 dict = True 194 )
195 #--------------------------------------------------------
196 - def __iter__(self):
197 return self
198 #--------------------------------------------------------
199 - def next(self):
200 line = self.csv_lines.next() 201 202 for field in cGelbeListeCSVFile.boolean_fields: 203 line[field] = (line[field].strip() == u'T') 204 205 # split field "Wirkstoff" by ";" 206 if line['wirkstoffe'].strip() == u'': 207 line['wirkstoffe'] = [] 208 else: 209 line['wirkstoffe'] = [ wirkstoff.strip() for wirkstoff in line['wirkstoffe'].split(u';') ] 210 211 return line
212 #--------------------------------------------------------
213 - def close(self, truncate=True):
214 try: self.csv_file.close() 215 except: pass 216 217 if truncate: 218 try: os.open(self.filename, 'wb').close 219 except: pass
220 #============================================================
221 -class cDrugDataSourceInterface(object):
222 223 #--------------------------------------------------------
224 - def __init__(self):
225 self.patient = None 226 self.custom_path_to_binary = None
227 #--------------------------------------------------------
228 - def get_data_source_version(self):
229 raise NotImplementedError
230 #--------------------------------------------------------
231 - def create_data_source_entry(self):
232 raise NotImplementedError
233 #--------------------------------------------------------
234 - def switch_to_frontend(self, blocking=False):
235 raise NotImplementedError
236 #--------------------------------------------------------
237 - def select_drugs(self):
238 raise NotImplementedError
239 #--------------------------------------------------------
240 - def import_drugs(self):
241 raise NotImplementedError
242 #--------------------------------------------------------
243 - def check_drug_interactions(self):
244 raise NotImplementedError
245 #--------------------------------------------------------
246 - def show_info_on_drug(self, drug=None):
247 raise NotImplementedError
248 #============================================================
249 -class cFreeDiamsInterface(cDrugDataSourceInterface):
250 251 """http://ericmaeker.fr/FreeMedForms/di-manual/ligne_commandes.html""" 252 253 version = u'FreeDiams v0.3.0 interface' 254 default_encoding = 'utf8' 255 default_dob_format = '%d/%m/%Y' 256 257 map_gender2mf = { 258 'm': u'M', 259 'f': u'F', 260 'tf': u'F', 261 'tm': u'M', 262 'h': u'H' 263 } 264 #--------------------------------------------------------
265 - def __init__(self):
266 cDrugDataSourceInterface.__init__(self) 267 _log.info(cFreeDiamsInterface.version) 268 269 paths = gmTools.gmPaths() 270 self.__exchange_filename = os.path.join(paths.home_dir, '.gnumed', 'tmp', 'gm2freediams.xml')
271 #--------------------------------------------------------
272 - def get_data_source_version(self):
273 #> Coded. Available next release 274 #> Use --version or -version or -v 275 return u'0.3.0'
276 # ~/.freediams/config.ini: [License] -> AcceptedVersion=.... 277 #--------------------------------------------------------
278 - def create_data_source_entry(self):
279 return create_data_source ( 280 long_name = u'"FreeDiams" Drug Database Frontend', 281 short_name = u'FreeDiams', 282 version = self.get_data_source_version(), 283 source = u'http://ericmaeker.fr/FreeMedForms/di-manual/index.html', 284 language = u'fr' # actually to be multi-locale 285 )
286 #--------------------------------------------------------
287 - def switch_to_frontend(self, blocking=False):
288 """ --medintux : définit une utilisation spécifique à MedinTux. 289 --exchange="xxx" : définit le fichier d'échange entre les deux applications. 290 --chrono : Chronomètres diverses fonctions du testeur d'interactions (proposé à des fins de déboggage) 291 --transmit-dosage = non documenté. 292 """ 293 found, cmd = gmShellAPI.find_first_binary(binaries = [ 294 self.custom_path_to_binary, 295 r'/usr/bin/freediams', 296 r'freediams', 297 r'/Applications/FreeDiams.app/Contents/MacOs/FreeDiams', 298 r'c:\programs\freediams\freediams.exe', 299 r'freediams.exe' 300 ]) 301 302 if not found: 303 _log.error('cannot find FreeDiams binary') 304 return False 305 306 # make sure csv file exists 307 open(self.__exchange_filename, 'wb').close() 308 args = u'--exchange="%s"' % self.__exchange_filename 309 310 if self.patient is not None: 311 312 args += u' --patientname="%(firstnames)s %(lastnames)s"' % self.patient.get_active_name() 313 314 args += u' --gender=%s' % cFreeDiamsInterface.map_gender2mf[self.patient['gender']] 315 316 if self.patient['dob'] is not None: 317 args += u' --dateofbirth="%s"' % self.patient['dob'].strftime(cFreeDiamsInterface.default_dob_format) 318 319 # FIXME: search by LOINC code and add 320 # --weight="dd" : définit le poids du patient (en kg) 321 # --size="ddd" : définit la taille du patient (en cm) 322 # --clcr="dd.d" : définit la clairance de la créatinine du patient (en ml/min) 323 # --creatinin="dd" : définit la créatininémie du patient (en mg/l) 324 325 cmd = r'%s %s' % (cmd, args) 326 327 if not gmShellAPI.run_command_in_shell(command = cmd): 328 _log.error('problem switching to the FreeDiams drug database') 329 return False 330 331 return True
332 #--------------------------------------------------------
333 - def select_drugs(self):
334 self.switch_to_frontend()
335 #--------------------------------------------------------
336 - def import_drugs(self):
337 """FreeDiams ONLY use CIS. 338 339 CIS stands for Unique Speciality Identifier (eg bisoprolol 5 mg, gel). 340 CIS is AFSSAPS specific, but pharmacist can retreive drug name with the CIS. 341 AFSSAPS is the French FDA. 342 343 CIP stands for Unique Presentation Identifier (eg 30 pills plaq) 344 CIP if you want to specify the packaging of the drug (30 pills 345 thermoformed tablet...) -- actually not really usefull for french 346 doctors. 347 """ 348 self.switch_to_frontend()
349 # .external_code_type: u'FR-CIS' 350 # .external_cod: the CIS value 351 #--------------------------------------------------------
352 - def check_drug_interactions(self):
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 -class cGelbeListeWindowsInterface(cDrugDataSourceInterface):
360 """Support v8.2 CSV file interface only.""" 361 362 version = u'Gelbe Liste/MMI v8.2 interface' 363 default_encoding = 'cp1250' 364 bdt_line_template = u'%03d6210#%s\r\n' # Medikament verordnet auf Kassenrezept 365 bdt_line_base_length = 8 366 #--------------------------------------------------------
367 - def __init__(self):
368 369 cDrugDataSourceInterface.__init__(self) 370 371 _log.info(u'%s (native Windows)', cGelbeListeWindowsInterface.version) 372 373 self.path_to_binary = r'C:\Programme\MMI PHARMINDEX\glwin.exe' 374 self.args = r'-KEEPBACKGROUND -PRESCRIPTIONFILE %s -CLOSETOTRAY' 375 376 paths = gmTools.gmPaths() 377 378 self.default_csv_filename = os.path.join(paths.home_dir, '.gnumed', 'tmp', 'rezept.txt') 379 self.default_csv_filename_arg = os.path.join(paths.home_dir, '.gnumed', 'tmp') 380 self.interactions_filename = os.path.join(paths.home_dir, '.gnumed', 'tmp', 'gm2mmi.bdt') 381 self.data_date_filename = r'C:\Programme\MMI PHARMINDEX\datadate.txt' 382 383 self.__data_date = None 384 self.__online_update_date = None
385 386 # use adjusted config.dat 387 #--------------------------------------------------------
388 - def get_data_source_version(self, force_reload=False):
389 390 if self.__data_date is not None: 391 if not force_reload: 392 return { 393 'data': self.__data_date, 394 'online_update': self.__online_update_date 395 } 396 397 open(self.data_date_filename, 'wb').close() 398 399 cmd = u'%s -DATADATE' % self.path_to_binary 400 if not gmShellAPI.run_command_in_shell(command = cmd, blocking = True): 401 _log.error('problem querying the MMI drug database for version information') 402 self.__data_date = None 403 self.__online_update_date = None 404 return { 405 'data': u'?', 406 'online_update': u'?' 407 } 408 409 version_file = open(self.data_date_filename, 'rU') 410 self.__data_date = version_file.readline()[:10] 411 self.__online_update_date = version_file.readline()[:10] 412 version_file.close() 413 414 return { 415 'data': self.__data_date, 416 'online_update': self.__online_update_date 417 }
418 #--------------------------------------------------------
419 - def create_data_source_entry(self):
420 versions = self.get_data_source_version() 421 422 return create_data_source ( 423 long_name = u'Medikamentendatenbank "mmi PHARMINDEX" (Gelbe Liste)', 424 short_name = u'GL/MMI', 425 version = u'Daten: %s, Preise (Onlineupdate): %s' % (versions['data'], versions['online_update']), 426 source = u'Medizinische Medien Informations GmbH, Am Forsthaus Gravenbruch 7, 63263 Neu-Isenburg', 427 language = u'de' 428 )
429 #--------------------------------------------------------
430 - def switch_to_frontend(self, blocking=False, cmd=None):
431 432 # must make sure csv file exists 433 open(self.default_csv_filename, 'wb').close() 434 435 if cmd is None: 436 cmd = (u'%s %s' % (self.path_to_binary, self.args)) % self.default_csv_filename_arg 437 438 if not gmShellAPI.run_command_in_shell(command = cmd, blocking = blocking): 439 _log.error('problem switching to the MMI drug database') 440 # apparently on the first call MMI does not 441 # consistently return 0 on success 442 # return False 443 444 return True
445 #--------------------------------------------------------
446 - def select_drugs(self, filename=None):
447 448 # better to clean up interactions file 449 open(self.interactions_filename, 'wb').close() 450 451 if not self.switch_to_frontend(blocking = True): 452 return None 453 454 return cGelbeListeCSVFile(filename = self.default_csv_filename)
455 #--------------------------------------------------------
456 - def import_drugs_as_substances(self):
457 458 selected_drugs = self.select_drugs() 459 if selected_drugs is None: 460 return None 461 462 new_substances = [] 463 464 for drug in selected_drugs: 465 atc = None # hopefully MMI eventually supports atc-per-substance in a drug... 466 if len(drug['wirkstoffe']) == 1: 467 atc = drug['atc'] 468 for wirkstoff in drug['wirkstoffe']: 469 new_substances.append(create_used_substance(substance = wirkstoff, atc = atc)) 470 471 selected_drugs.close() 472 473 return new_substances
474 #--------------------------------------------------------
475 - def import_drugs(self):
476 477 selected_drugs = self.select_drugs() 478 if selected_drugs is None: 479 return None 480 481 data_src_pk = self.create_data_source_entry() 482 483 new_drugs = [] 484 new_substances = [] 485 486 for entry in selected_drugs: 487 488 _log.debug('importing drug: %s %s', entry['name'], entry['darreichungsform']) 489 490 if entry[u'hilfsmittel']: 491 _log.debug('skipping Hilfsmittel') 492 continue 493 494 if entry[u'erstattbares_medizinprodukt']: 495 _log.debug('skipping sonstiges Medizinprodukt') 496 continue 497 498 # create branded drug (or get it if it already exists) 499 drug = create_branded_drug(brand_name = entry['name'], preparation = entry['darreichungsform']) 500 if drug is None: 501 drug = get_drug_by_brand(brand_name = entry['name'], preparation = entry['darreichungsform']) 502 new_drugs.append(drug) 503 504 # update fields 505 drug['is_fake'] = False 506 drug['atc_code'] = entry['atc'] 507 drug['external_code_type'] = u'DE-PZN' 508 drug['external_code'] = entry['pzn'] 509 drug['fk_data_source'] = data_src_pk 510 drug.save() 511 512 # add components to brand 513 atc = None # hopefully MMI eventually supports atc-per-substance in a drug... 514 if len(entry['wirkstoffe']) == 1: 515 atc = entry['atc'] 516 for wirkstoff in entry['wirkstoffe']: 517 drug.add_component(substance = wirkstoff, atc = atc) 518 519 # create as consumable substances, too 520 atc = None # hopefully MMI eventually supports atc-per-substance in a drug... 521 if len(entry['wirkstoffe']) == 1: 522 atc = entry['atc'] 523 for wirkstoff in entry['wirkstoffe']: 524 new_substances.append(create_used_substance(substance = wirkstoff, atc = atc)) 525 526 return new_drugs, new_substances
527 #--------------------------------------------------------
528 - def check_drug_interactions(self, pzn_list=None, substances=None):
529 """For this to work the BDT interaction check must be configured in the MMI.""" 530 531 if pzn_list is None: 532 if substances is None: 533 return 534 if len(substances) < 2: 535 return 536 pzn_list = [ (s.external_code_type, s.external_code) for s in substances ] 537 pzn_list = [ code_value for code_type, code_value in pzn_list if (code_value is not None) and (code_type == u'DE-PZN')] 538 539 else: 540 if len(pzn_list) < 2: 541 return 542 543 if pzn_list < 2: 544 return 545 546 bdt_file = codecs.open(filename = self.interactions_filename, mode = 'wb', encoding = cGelbeListeWindowsInterface.default_encoding) 547 548 for pzn in pzn_list: 549 pzn = pzn.strip() 550 lng = cGelbeListeWindowsInterface.bdt_line_base_length + len(pzn) 551 bdt_file.write(cGelbeListeWindowsInterface.bdt_line_template % (lng, pzn)) 552 553 bdt_file.close() 554 555 self.switch_to_frontend(blocking = False)
556 #--------------------------------------------------------
557 - def show_info_on_substance(self, substance=None):
558 559 cmd = None 560 561 if substance.external_code_type == u'DE-PZN': 562 cmd = u'%s -PZN %s' % (self.path_to_binary, substance.external_code) 563 564 if cmd is None: 565 name = gmTools.coalesce ( 566 substance['brand'], 567 substance['substance'] 568 ) 569 cmd = u'%s -NAME %s' % (self.path_to_binary, name) 570 571 # better to clean up interactions file 572 open(self.interactions_filename, 'wb').close() 573 574 self.switch_to_frontend(cmd = cmd)
575 #============================================================
576 -class cGelbeListeWineInterface(cGelbeListeWindowsInterface):
577
578 - def __init__(self):
579 cGelbeListeWindowsInterface.__init__(self) 580 581 _log.info(u'%s (WINE extension)', cGelbeListeWindowsInterface.version) 582 583 # FIXME: if -CLOSETOTRAY is used GNUmed cannot detect the end of MMI 584 self.path_to_binary = r'wine "C:\Programme\MMI PHARMINDEX\glwin.exe"' 585 self.args = r'"-PRESCRIPTIONFILE %s -KEEPBACKGROUND"' 586 587 paths = gmTools.gmPaths() 588 589 self.default_csv_filename = os.path.join(paths.home_dir, '.wine', 'drive_c', 'windows', 'temp', 'mmi2gm.csv') 590 self.default_csv_filename_arg = r'c:\windows\temp\mmi2gm.csv' 591 self.interactions_filename = os.path.join(paths.home_dir, '.wine', 'drive_c', 'windows', 'temp', 'gm2mmi.bdt') 592 self.data_date_filename = os.path.join(paths.home_dir, '.wine', 'drive_c', 'Programme', 'MMI PHARMINDEX', 'datadate.txt')
593 #============================================================
594 -class cIfapInterface(cDrugDataSourceInterface):
595 """empirical CSV interface""" 596
597 - def __init__(self):
598 pass
599
600 - def print_transfer_file(self, filename=None):
601 602 try: 603 csv_file = open(filename, 'rb') # FIXME: encoding ? 604 except: 605 _log.exception('cannot access [%s]', filename) 606 csv_file = None 607 608 field_names = u'PZN Handelsname Form Abpackungsmenge Einheit Preis1 Hersteller Preis2 rezeptpflichtig Festbetrag Packungszahl Packungsgr\xf6\xdfe'.split() 609 610 if csv_file is None: 611 return False 612 613 csv_lines = csv.DictReader ( 614 csv_file, 615 fieldnames = field_names, 616 delimiter = ';' 617 ) 618 619 for line in csv_lines: 620 print "--------------------------------------------------------------------"[:31] 621 for key in field_names: 622 tmp = ('%s ' % key)[:30] 623 print '%s: %s' % (tmp, line[key]) 624 625 csv_file.close()
626 627 # narr = u'%sx %s %s %s (\u2258 %s %s) von %s (%s)' % ( 628 # line['Packungszahl'].strip(), 629 # line['Handelsname'].strip(), 630 # line['Form'].strip(), 631 # line[u'Packungsgr\xf6\xdfe'].strip(), 632 # line['Abpackungsmenge'].strip(), 633 # line['Einheit'].strip(), 634 # line['Hersteller'].strip(), 635 # line['PZN'].strip() 636 # ) 637 #============================================================ 638 drug_data_source_interfaces = { 639 'Deutschland: Gelbe Liste/MMI (Windows)': cGelbeListeWindowsInterface, 640 'Deutschland: Gelbe Liste/MMI (WINE)': cGelbeListeWineInterface, 641 'France: FreeDiams': cFreeDiamsInterface 642 } 643 #============================================================ 644 # substances in use across all patients 645 #------------------------------------------------------------
646 -def get_substances_in_use():
647 cmd = u'select * from clin.consumed_substance order by description' 648 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}]) 649 return rows
650 #------------------------------------------------------------
651 -def get_substance_by_pk(pk=None):
652 cmd = u'select * from clin.consumed_substance WHERE pk = %(pk)s' 653 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': {'pk': pk}}]) 654 if len(rows) == 0: 655 return None 656 return rows[0]
657 #------------------------------------------------------------
658 -def create_used_substance(substance=None, atc=None):
659 660 substance = substance.strip() 661 662 if atc is not None: 663 atc = atc.strip() 664 665 args = {'desc': substance, 'atc': atc} 666 667 cmd = u'select pk, atc_code, description from clin.consumed_substance where description = %(desc)s' 668 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}]) 669 670 if len(rows) == 0: 671 cmd = u'insert into clin.consumed_substance (description, atc_code) values (%(desc)s, gm.nullify_empty_string(%(atc)s)) returning pk, atc_code, description' 672 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True) 673 674 gmATC.propagate_atc(substance = substance, atc = atc) 675 676 row = rows[0] 677 # unfortunately not a real dict so no setting stuff by keyword 678 #row['atc_code'] = args['atc'] 679 row[1] = args['atc'] 680 return row
681 #------------------------------------------------------------
682 -def delete_used_substance(substance=None):
683 args = {'pk': substance} 684 cmd = u""" 685 delete from clin.consumed_substance 686 where 687 pk = %(pk)s and not exists ( 688 select 1 from clin.substance_intake 689 where fk_substance = %(pk)s 690 )""" 691 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
692 #============================================================
693 -class cSubstanceIntakeEntry(gmBusinessDBObject.cBusinessDBObject):
694 """Represents a substance currently taken by a patient.""" 695 696 _cmd_fetch_payload = u"select * from clin.v_pat_substance_intake where pk_substance_intake = %s" 697 _cmds_store_payload = [ 698 u"""update clin.substance_intake set 699 clin_when = %(started)s, 700 discontinued = %(discontinued)s, 701 discontinue_reason = gm.nullify_empty_string(%(discontinue_reason)s), 702 strength = gm.nullify_empty_string(%(strength)s), 703 preparation = %(preparation)s, 704 schedule = gm.nullify_empty_string(%(schedule)s), 705 aim = gm.nullify_empty_string(%(aim)s), 706 narrative = gm.nullify_empty_string(%(notes)s), 707 intake_is_approved_of = %(intake_is_approved_of)s, 708 709 -- is_long_term = %(is_long_term)s, 710 is_long_term = ( 711 case 712 when ( 713 (%(is_long_term)s is False) 714 and 715 (gm.is_null_or_blank_string(%(duration)s) is True) 716 ) is True then null 717 else %(is_long_term)s 718 end 719 )::boolean, 720 duration = ( 721 case 722 when %(is_long_term)s is True then null 723 else gm.nullify_empty_string(%(duration)s) 724 end 725 )::interval, 726 727 fk_brand = %(pk_brand)s, 728 fk_substance = %(pk_substance)s, 729 fk_episode = %(pk_episode)s 730 where 731 pk = %(pk_substance_intake)s and 732 xmin = %(xmin_substance_intake)s 733 returning 734 xmin as xmin_substance_intake 735 """ 736 ] 737 _updatable_fields = [ 738 u'started', 739 u'discontinued', 740 u'discontinue_reason', 741 u'preparation', 742 u'strength', 743 u'intake_is_approved_of', 744 u'schedule', 745 u'duration', 746 u'aim', 747 u'is_long_term', 748 u'notes', 749 u'pk_brand', 750 u'pk_substance', 751 u'pk_episode' 752 ] 753 #--------------------------------------------------------
754 - def format(self, left_margin=0, date_format='%Y-%m-%d'):
755 756 if self._payload[self._idx['duration']] is None: 757 duration = gmTools.bool2subst ( 758 self._payload[self._idx['is_long_term']], 759 _('long-term'), 760 _('short-term'), 761 _('?short-term') 762 ) 763 else: 764 duration = gmDateTime.format_interval ( 765 self._payload[self._idx['duration']], 766 accuracy_wanted = gmDateTime.acc_days 767 ) 768 769 line = u'%s%s (%s %s): %s %s %s (%s)' % ( 770 u' ' * left_margin, 771 self._payload[self._idx['started']].strftime(date_format), 772 gmTools.u_right_arrow, 773 duration, 774 self._payload[self._idx['substance']], 775 self._payload[self._idx['strength']], 776 self._payload[self._idx['preparation']], 777 gmTools.bool2subst(self._payload[self._idx['is_currently_active']], _('ongoing'), _('inactive'), _('?ongoing')) 778 ) 779 780 return line
781 #--------------------------------------------------------
782 - def turn_into_allergy(self, encounter_id=None, allergy_type='allergy'):
783 allg = gmAllergy.create_allergy ( 784 substance = gmTools.coalesce ( 785 self._payload[self._idx['brand']], 786 self._payload[self._idx['substance']] 787 ), 788 allg_type = allergy_type, 789 episode_id = self._payload[self._idx['pk_episode']], 790 encounter_id = encounter_id 791 ) 792 allg['reaction'] = self._payload[self._idx['discontinue_reason']] 793 allg['atc_code'] = gmTools.coalesce(self._payload[self._idx['atc_substance']], self._payload[self._idx['atc_brand']]) 794 if self._payload[self._idx['external_code_brand']] is not None: 795 allg['substance_code'] = u'%s::::%s' % (self._payload[self._idx['external_code_type_brand']], self._payload[self._idx['external_code_brand']]) 796 allg['generics'] = self._payload[self._idx['substance']] 797 798 allg.save() 799 return allg
800 #-------------------------------------------------------- 801 # properties 802 #--------------------------------------------------------
803 - def _get_ddd(self):
804 805 try: self.__ddd 806 except AttributeError: self.__ddd = None 807 808 if self.__ddd is not None: 809 return self.__ddd 810 811 if self._payload[self._idx['atc_substance']] is not None: 812 ddd = gmATC.atc2ddd(atc = self._payload[self._idx['atc_substance']]) 813 if len(ddd) != 0: 814 self.__ddd = ddd[0] 815 else: 816 if self._payload[self._idx['atc_brand']] is not None: 817 ddd = gmATC.atc2ddd(atc = self._payload[self._idx['atc_brand']]) 818 if len(ddd) != 0: 819 self.__ddd = ddd[0] 820 821 return self.__ddd
822 823 ddd = property(_get_ddd, lambda x:x) 824 #--------------------------------------------------------
825 - def _get_external_code(self):
826 drug = self.containing_drug 827 828 if drug is None: 829 return None 830 831 return drug.external_code
832 833 external_code = property(_get_external_code, lambda x:x) 834 #--------------------------------------------------------
835 - def _get_external_code_type(self):
836 drug = self.containing_drug 837 838 if drug is None: 839 return None 840 841 return drug.external_code_type
842 843 external_code_type = property(_get_external_code_type, lambda x:x) 844 #--------------------------------------------------------
845 - def _get_containing_drug(self):
846 if self._payload[self._idx['pk_brand']] is None: 847 return None 848 849 return cBrandedDrug(aPK_obj = self._payload[self._idx['pk_brand']])
850 851 containing_drug = property(_get_containing_drug, lambda x:x) 852 #--------------------------------------------------------
853 - def _get_parsed_schedule(self):
854 tests = [ 855 # lead, trail 856 ' 1-1-1-1 ', 857 # leading dose 858 '1-1-1-1', 859 '22-1-1-1', 860 '1/3-1-1-1', 861 '/4-1-1-1' 862 ] 863 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}$" 864 for test in tests: 865 print test.strip(), ":", regex.match(pattern, test.strip())
866 #------------------------------------------------------------
867 -def create_substance_intake(substance=None, atc=None, encounter=None, episode=None, preparation=None):
868 869 args = { 870 'enc': encounter, 871 'epi': episode, 872 'prep': preparation, 873 'subst': create_used_substance(substance = substance, atc = atc)['pk'] 874 } 875 876 cmd = u""" 877 insert into clin.substance_intake ( 878 fk_encounter, 879 fk_episode, 880 fk_substance, 881 preparation, 882 intake_is_approved_of 883 ) values ( 884 %(enc)s, 885 %(epi)s, 886 %(subst)s, 887 gm.nullify_empty_string(%(prep)s), 888 False 889 ) 890 returning pk 891 """ 892 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True) 893 return cSubstanceIntakeEntry(aPK_obj = rows[0][0])
894 #------------------------------------------------------------
895 -def delete_substance_intake(substance=None):
896 cmd = u'delete from clin.substance_intake where pk = %(pk)s' 897 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': {'pk': substance}}])
898 #------------------------------------------------------------
899 -def format_substance_intake(emr=None, output_format=u'latex', table_type=u'by-brand'):
900 901 tex = u"""\\noindent %s {\\tiny (%s)}{\\tiny \\par} 902 903 \\noindent \\begin{tabular}{|l|l|l|} 904 \\hline 905 %s & %s & {\\scriptsize %s} \\\\ 906 \\hline 907 908 \\hline 909 %%s 910 911 \\end{tabular}""" % ( 912 _('Medication list'), 913 _('ordered by brand'), 914 _('Drug'), 915 _('Regimen'), 916 _('Substances') 917 ) 918 919 current_meds = emr.get_current_substance_intake ( 920 include_inactive = False, 921 include_unapproved = False, 922 order_by = u'brand, substance' 923 ) 924 925 # aggregate data 926 line_data = {} 927 for med in current_meds: 928 identifier = gmTools.coalesce(med['brand'], med['substance']) 929 930 try: 931 line_data[identifier] 932 except KeyError: 933 line_data[identifier] = {'brand': u'', 'substances': [], 'preparation': u'', 'schedule': u'', 'aims': [], 'notes': []} 934 935 line_data[identifier]['brand'] = identifier 936 line_data[identifier]['substances'].append(u'%s%s' % (med['substance'], gmTools.coalesce(med['strength'], u'', u' %s'))) 937 line_data[identifier]['preparation'] = med['preparation'] 938 line_data[identifier]['schedule'] = gmTools.coalesce(med['schedule'], u'') 939 if med['aim'] not in line_data[identifier]['aims']: 940 line_data[identifier]['aims'].append(med['aim']) 941 if med['notes'] not in line_data[identifier]['notes']: 942 line_data[identifier]['notes'].append(med['notes']) 943 944 # create lines 945 already_seen = [] 946 lines = [] 947 line1_template = u'%s %s & %s & {\\scriptsize %s} \\\\' 948 line2_template = u' & \\multicolumn{2}{l|}{{\\scriptsize %s}} \\\\' 949 950 for med in current_meds: 951 identifier = gmTools.coalesce(med['brand'], med['substance']) 952 953 if identifier in already_seen: 954 continue 955 956 already_seen.append(identifier) 957 958 lines.append (line1_template % ( 959 line_data[identifier]['brand'], 960 line_data[identifier]['preparation'], 961 line_data[identifier]['schedule'], 962 u', '.join(line_data[identifier]['substances']) 963 )) 964 965 for aim in line_data[identifier]['aims']: 966 lines.append(line2_template % aim) 967 968 for note in line_data[identifier]['notes']: 969 lines.append(line2_template % note) 970 971 lines.append(u'\\hline') 972 973 return tex % u' \n'.join(lines)
974 #============================================================
975 -class cBrandedDrug(gmBusinessDBObject.cBusinessDBObject):
976 """Represents a drug as marketed by a manufacturer.""" 977 978 _cmd_fetch_payload = u"select *, xmin from ref.branded_drug where pk = %s" 979 _cmds_store_payload = [ 980 u"""update ref.branded_drug set 981 description = %(description)s, 982 preparation = %(preparation)s, 983 atc_code = gm.nullify_empty_string(%(atc_code)s), 984 external_code = gm.nullify_empty_string(%(external_code)s), 985 external_code_type = gm.nullify_empty_string(%(external_code_type)s), 986 is_fake = %(is_fake)s, 987 fk_data_source = %(fk_data_source)s 988 where 989 pk = %(pk)s and 990 xmin = %(xmin)s 991 returning 992 xmin 993 """ 994 ] 995 _updatable_fields = [ 996 u'description', 997 u'preparation', 998 u'atc_code', 999 u'is_fake', 1000 u'external_code', 1001 u'external_code_type', 1002 u'fk_data_source' 1003 ] 1004 #--------------------------------------------------------
1005 - def _get_external_code(self):
1006 if self._payload[self._idx['external_code']] is None: 1007 return None 1008 1009 return self._payload[self._idx['external_code']]
1010 1011 external_code = property(_get_external_code, lambda x:x) 1012 #--------------------------------------------------------
1013 - def _get_external_code_type(self):
1014 1015 # FIXME: maybe evaluate fk_data_source ? 1016 if self._payload[self._idx['external_code_type']] is None: 1017 return None 1018 1019 return self._payload[self._idx['external_code_type']]
1020 1021 external_code_type = property(_get_external_code_type, lambda x:x) 1022 #--------------------------------------------------------
1023 - def _get_components(self):
1024 cmd = u'select * from ref.substance_in_brand where fk_brand = %(brand)s' 1025 args = {'brand': self._payload[self._idx['pk']]} 1026 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False) 1027 return rows
1028 1029 components = property(_get_components, lambda x:x) 1030 #--------------------------------------------------------
1031 - def add_component(self, substance=None, atc=None):
1032 1033 # normalize atc 1034 atc = gmATC.propagate_atc(substance = substance, atc = atc) 1035 1036 args = { 1037 'brand': self.pk_obj, 1038 'desc': substance, 1039 'atc': atc 1040 } 1041 1042 # already exists ? 1043 cmd = u""" 1044 SELECT pk 1045 FROM ref.substance_in_brand 1046 WHERE 1047 fk_brand = %(brand)s 1048 AND 1049 ((description = %(desc)s) OR ((atc_code = %(atc)s) IS TRUE)) 1050 """ 1051 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False) 1052 if len(rows) > 0: 1053 return 1054 1055 # create it 1056 cmd = u""" 1057 INSERT INTO ref.substance_in_brand (fk_brand, description, atc_code) 1058 VALUES (%(brand)s, %(desc)s, %(atc)s) 1059 """ 1060 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
1061 #------------------------------------------------------------
1062 - def remove_component(substance=None):
1063 delete_component_from_branded_drug(brand = self.pk_obj, component = substance)
1064 #------------------------------------------------------------
1065 -def get_substances_in_brands():
1066 cmd = u'SELECT * FROM ref.v_substance_in_brand ORDER BY brand, substance' 1067 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = False) 1068 return rows
1069 #------------------------------------------------------------
1070 -def get_branded_drugs():
1071 1072 cmd = u'SELECT pk FROM ref.branded_drug ORDER BY description' 1073 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = False) 1074 1075 return [ cBrandedDrug(aPK_obj = r['pk']) for r in rows ]
1076 #------------------------------------------------------------
1077 -def get_drug_by_brand(brand_name=None, preparation=None):
1078 args = {'brand': brand_name, 'prep': preparation} 1079 1080 cmd = u'SELECT pk FROM ref.branded_drug WHERE description = %(brand)s AND preparation = %(prep)s' 1081 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False) 1082 1083 if len(rows) == 0: 1084 return None 1085 1086 return cBrandedDrug(aPK_obj = rows[0]['pk'])
1087 #------------------------------------------------------------
1088 -def create_branded_drug(brand_name=None, preparation=None, return_existing=False):
1089 1090 if preparation is None: 1091 preparation = _('units') 1092 1093 if preparation.strip() == u'': 1094 preparation = _('units') 1095 1096 drug = get_drug_by_brand(brand_name = brand_name, preparation = preparation) 1097 1098 if drug is not None: 1099 if return_existing: 1100 return drug 1101 return None 1102 1103 cmd = u'insert into ref.branded_drug (description, preparation) values (%(brand)s, %(prep)s) returning pk' 1104 args = {'brand': brand_name, 'prep': preparation} 1105 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True, get_col_idx = False) 1106 1107 return cBrandedDrug(aPK_obj = rows[0]['pk'])
1108 #------------------------------------------------------------
1109 -def delete_branded_drug(brand=None):
1110 cmd = u'delete from ref.branded_drug where pk = %(pk)s' 1111 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': {'pk': brand}}])
1112 #------------------------------------------------------------
1113 -def delete_component_from_branded_drug(brand=None, component=None):
1114 cmd = u'delete from ref.substance_in_brand where fk_brand = %(brand)s and pk = %(comp)s' 1115 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': {'brand': brand, 'comp': component}}])
1116 #============================================================ 1117 # main 1118 #------------------------------------------------------------ 1119 if __name__ == "__main__": 1120 1121 if len(sys.argv) < 2: 1122 sys.exit() 1123 1124 if sys.argv[1] != 'test': 1125 sys.exit() 1126 1127 from Gnumed.pycommon import gmLog2 1128 from Gnumed.pycommon import gmI18N 1129 1130 gmI18N.activate_locale() 1131 # gmDateTime.init() 1132 #--------------------------------------------------------
1133 - def test_MMI_interface():
1134 mmi = cGelbeListeWineInterface() 1135 print mmi 1136 print "interface definition:", mmi.version 1137 print "database versions: ", mmi.get_data_source_version()
1138 #--------------------------------------------------------
1139 - def test_MMI_file():
1140 mmi_file = cGelbeListeCSVFile(filename = sys.argv[2]) 1141 for drug in mmi_file: 1142 print "-------------" 1143 print '"%s" (ATC: %s / PZN: %s)' % (drug['name'], drug['atc'], drug['pzn']) 1144 for stoff in drug['wirkstoffe']: 1145 print " Wirkstoff:", stoff 1146 print drug 1147 mmi_file.close()
1148 #--------------------------------------------------------
1149 - def test_mmi_switch_to():
1150 mmi = cGelbeListeWineInterface() 1151 mmi.switch_to_frontend(blocking = False)
1152 #--------------------------------------------------------
1153 - def test_mmi_select_drugs():
1154 mmi = cGelbeListeWineInterface() 1155 mmi_file = mmi.select_drugs() 1156 for drug in mmi_file: 1157 print "-------------" 1158 print '"%s" (ATC: %s / PZN: %s)' % (drug['name'], drug['atc'], drug['pzn']) 1159 for stoff in drug['wirkstoffe']: 1160 print " Wirkstoff:", stoff 1161 print drug 1162 mmi_file.close()
1163 #--------------------------------------------------------
1164 - def test_mmi_import_drugs():
1165 mmi = cGelbeListeWineInterface() 1166 mmi.import_drugs()
1167 #--------------------------------------------------------
1168 - def test_mmi_interaction_check():
1169 mmi = cGelbeListeInterface() 1170 print mmi 1171 print "interface definition:", mmi.version 1172 # Metoprolol + Hct vs Citalopram 1173 diclofenac = '7587712' 1174 phenprocoumon = '4421744' 1175 mmi.check_drug_interactions(pzn_list = [diclofenac, phenprocoumon])
1176 #--------------------------------------------------------
1177 - def test_create_substance_intake():
1178 drug = create_substance_intake ( 1179 substance = u'Whiskey', 1180 atc = u'no ATC available', 1181 encounter = 1, 1182 episode = 1, 1183 preparation = 'a nice glass' 1184 ) 1185 print drug
1186 #--------------------------------------------------------
1187 - def test_show_components():
1188 drug = cBrandedDrug(aPK_obj = sys.argv[2]) 1189 print drug 1190 print drug.components
1191 #-------------------------------------------------------- 1192 #test_MMI_interface() 1193 #test_MMI_file() 1194 #test_mmi_switch_to() 1195 #test_mmi_select_drugs() 1196 #test_mmi_import_substances() 1197 #test_mmi_import_drugs() 1198 #test_interaction_check() 1199 #test_create_substance_intake() 1200 test_show_components() 1201 #============================================================ 1202