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  # $Source: /cvsroot/gnumed/gnumed/gnumed/client/business/gmMedication.py,v $ 
  8  # $Id: gmMedication.py,v 1.21 2010/02/06 20:44:58 ncq Exp $ 
  9  __version__ = "$Revision: 1.21 $" 
 10  __author__ = "K.Hilbert <Karsten.Hilbert@gmx.net>" 
 11   
 12  import sys, logging, csv, codecs, os, re as regex 
 13   
 14   
 15  if __name__ == '__main__': 
 16          sys.path.insert(0, '../../') 
 17  from Gnumed.pycommon import gmBusinessDBObject, gmPG2, gmShellAPI, gmTools, gmDateTime 
 18  from Gnumed.business import gmATC 
 19   
 20   
 21  _log = logging.getLogger('gm.meds') 
 22  _log.info(__version__) 
 23   
 24  #============================================================ 
 25  # wishlist: 
 26  # - --conf-file= for glwin.exe 
 27  # - wirkstoff: Konzentration auch in Multiprodukten 
 28  # - wirkstoff: ATC auch in Multiprodukten 
 29  # - Suche nach ATC per CLI 
 30   
31 -class cGelbeListeCSVFile(object):
32 """Iterator over a Gelbe Liste/MMI v8.2 CSV file.""" 33 34 version = u'Gelbe Liste/MMI v8.2 CSV file interface' 35 default_transfer_file_windows = r"c:\rezept.txt" 36 #default_encoding = 'cp1252' 37 default_encoding = 'cp1250' 38 csv_fieldnames = [ 39 u'name', 40 u'packungsgroesse', # obsolete, use "packungsmenge" 41 u'darreichungsform', 42 u'packungstyp', 43 u'festbetrag', 44 u'avp', 45 u'hersteller', 46 u'rezepttext', 47 u'pzn', 48 u'status_vertrieb', 49 u'status_rezeptpflicht', 50 u'status_fachinfo', 51 u'btm', 52 u'atc', 53 u'anzahl_packungen', 54 u'zuzahlung_pro_packung', 55 u'einheit', 56 u'schedule_morgens', 57 u'schedule_mittags', 58 u'schedule_abends', 59 u'schedule_nachts', 60 u'status_dauermedikament', 61 u'status_hausliste', 62 u'status_negativliste', 63 u'ik_nummer', 64 u'status_rabattvertrag', 65 u'wirkstoffe', 66 u'wirkstoffmenge', 67 u'wirkstoffeinheit', 68 u'wirkstoffmenge_bezug', 69 u'wirkstoffmenge_bezugseinheit', 70 u'status_import', 71 u'status_lifestyle', 72 u'status_ausnahmeliste', 73 u'packungsmenge', 74 u'apothekenpflicht', 75 u'status_billigere_packung', 76 u'rezepttyp', 77 u'besonderes_arzneimittel', # Abstimmungsverfahren SGB-V 78 u't-rezept-pflicht', # Thalidomid-Rezept 79 u'erstattbares_medizinprodukt', 80 u'hilfsmittel', 81 u'hzv_rabattkennung', 82 u'hzv_preis' 83 ] 84 boolean_fields = [ 85 u'status_rezeptpflicht', 86 u'status_fachinfo', 87 u'btm', 88 u'status_dauermedikament', 89 u'status_hausliste', 90 u'status_negativliste', 91 u'status_rabattvertrag', 92 u'status_import', 93 u'status_lifestyle', 94 u'status_ausnahmeliste', 95 u'apothekenpflicht', 96 u'status_billigere_packung', 97 u'besonderes_arzneimittel', # Abstimmungsverfahren SGB-V 98 u't-rezept-pflicht', 99 u'erstattbares_medizinprodukt', 100 u'hilfsmittel' 101 ] 102 #--------------------------------------------------------
103 - def __init__(self, filename=None):
104 105 _log.info(cGelbeListeCSVFile.version) 106 107 self.filename = filename 108 if filename is None: 109 self.filename = cGelbeListeCSVFile.default_transfer_file_windows 110 111 _log.debug('reading Gelbe Liste/MMI drug data from [%s]', self.filename) 112 113 self.csv_file = codecs.open(filename = filename, mode = 'rUb', encoding = cGelbeListeCSVFile.default_encoding) 114 115 self.csv_lines = gmTools.unicode_csv_reader ( 116 self.csv_file, 117 fieldnames = cGelbeListeCSVFile.csv_fieldnames, 118 delimiter = ';', 119 quotechar = '"', 120 dict = True 121 )
122 #--------------------------------------------------------
123 - def __iter__(self):
124 return self
125 #--------------------------------------------------------
126 - def next(self):
127 line = self.csv_lines.next() 128 129 for field in cGelbeListeCSVFile.boolean_fields: 130 line[field] = (line[field].strip() == u'T') 131 132 # split field "Wirkstoff" by ";" 133 if line['wirkstoffe'].strip() == u'': 134 line['wirkstoffe'] = [] 135 else: 136 line['wirkstoffe'] = [ wirkstoff.strip() for wirkstoff in line['wirkstoffe'].split(u';') ] 137 138 return line
139 #--------------------------------------------------------
140 - def close(self, truncate=True):
141 try: self.csv_file.close() 142 except: pass 143 144 if truncate: 145 try: os.open(self.filename, 'wb').close 146 except: pass
147 #============================================================
148 -class cDrugDataSourceInterface(object):
149 150 #--------------------------------------------------------
151 - def get_data_source_version(self):
152 raise NotImplementedError
153 #--------------------------------------------------------
154 - def create_data_source_entry(self):
155 raise NotImplementedError
156 #--------------------------------------------------------
157 - def switch_to_frontend(self):
158 raise NotImplementedError
159 #--------------------------------------------------------
160 - def select_drugs(self):
161 raise NotImplementedError
162 #--------------------------------------------------------
163 - def import_drugs(self):
164 raise NotImplementedError
165 #--------------------------------------------------------
166 - def check_drug_interactions(self):
167 raise NotImplementedError
168 #--------------------------------------------------------
169 - def show_info_on_drug(self, drug=None):
170 raise NotImplementedError
171 #============================================================
172 -class cGelbeListeWindowsInterface(cDrugDataSourceInterface):
173 """Support v8.2 CSV file interface only.""" 174 175 version = u'Gelbe Liste/MMI v8.2 interface' 176 default_encoding = 'cp1250' 177 bdt_line_template = u'%03d6210#%s\r\n' # Medikament verordnet auf Kassenrezept 178 bdt_line_base_length = 8 179 #--------------------------------------------------------
180 - def __init__(self):
181 _log.info(u'%s (native Windows)', cGelbeListeWindowsInterface.version) 182 183 self.path_to_binary = r'C:\Programme\MMI PHARMINDEX\glwin.exe' 184 self.args = r'-KEEPBACKGROUND -PRESCRIPTIONFILE %s -CLOSETOTRAY' 185 186 paths = gmTools.gmPaths() 187 188 self.default_csv_filename = os.path.join(paths.home_dir, '.gnumed', 'tmp', 'rezept.txt') 189 self.default_csv_filename_arg = os.path.join(paths.home_dir, '.gnumed', 'tmp') 190 self.interactions_filename = os.path.join(paths.home_dir, '.gnumed', 'tmp', 'gm2mmi.bdt') 191 self.data_date_filename = r'C:\Programme\MMI PHARMINDEX\datadate.txt' 192 193 self.data_date = None 194 self.online_update_date = None
195 196 # use adjusted config.dat 197 #--------------------------------------------------------
198 - def get_data_source_version(self):
199 200 open(self.data_date_filename, 'wb').close() 201 202 cmd = u'%s -DATADATE' % self.path_to_binary 203 if not gmShellAPI.run_command_in_shell(command = cmd, blocking = True): 204 _log.error('problem querying the MMI drug database for version information') 205 return { 206 'data': u'?', 207 'online_update': u'?' 208 } 209 210 version_file = open(self.data_date_filename, 'rU') 211 versions = { 212 'data': version_file.readline()[:10], 213 'online_update': version_file.readline()[:10] 214 } 215 version_file.close() 216 217 return versions
218 #--------------------------------------------------------
219 - def create_data_source_entry(self):
220 versions = self.get_data_source_version() 221 222 args = { 223 'lname': u'Medikamentendatenbank "mmi PHARMINDEX" (Gelbe Liste)', 224 'sname': u'GL/MMI', 225 'ver': u'Daten: %s, Preise (Onlineupdate): %s' % (versions['data'], versions['online_update']), 226 'src': u'Medizinische Medien Informations GmbH, Am Forsthaus Gravenbruch 7, 63263 Neu-Isenburg', 227 'lang': u'de' 228 } 229 230 cmd = u"""select pk from ref.data_source where name_long = %(lname)s and name_short = %(sname)s and version = %(ver)s""" 231 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}]) 232 if len(rows) > 0: 233 return rows[0]['pk'] 234 235 cmd = u""" 236 INSERT INTO ref.data_source (name_long, name_short, version, source, lang) 237 VALUES ( 238 %(lname)s, 239 %(sname)s, 240 %(ver)s, 241 %(src)s, 242 %(lang)s 243 ) 244 returning pk 245 """ 246 247 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True) 248 249 return rows[0]['pk']
250 #--------------------------------------------------------
251 - def switch_to_frontend(self, blocking=False, cmd=None):
252 253 # must make sure csv file exists 254 open(self.default_csv_filename, 'wb').close() 255 256 if cmd is None: 257 cmd = (u'%s %s' % (self.path_to_binary, self.args)) % self.default_csv_filename_arg 258 259 if not gmShellAPI.run_command_in_shell(command = cmd, blocking = blocking): 260 _log.error('problem switching to the MMI drug database') 261 # apparently on the first call MMI does not 262 # consistently return 0 on success 263 # return False 264 265 return True
266 #--------------------------------------------------------
267 - def select_drugs(self, filename=None):
268 269 # better to clean up interactions file 270 open(self.interactions_filename, 'wb').close() 271 272 if not self.switch_to_frontend(blocking = True): 273 return None 274 275 return cGelbeListeCSVFile(filename = self.default_csv_filename)
276 #--------------------------------------------------------
278 279 selected_drugs = self.select_drugs() 280 if selected_drugs is None: 281 return None 282 283 new_substances = [] 284 285 for drug in selected_drugs: 286 atc = None # hopefully MMI eventually supports atc-per-substance in a drug... 287 if len(drug['wirkstoffe']) == 1: 288 atc = drug['atc'] 289 for wirkstoff in drug['wirkstoffe']: 290 new_substances.append(create_used_substance(substance = wirkstoff, atc = atc)) 291 292 selected_drugs.close() 293 294 return new_substances
295 #--------------------------------------------------------
296 - def import_drugs(self):
297 298 selected_drugs = self.select_drugs() 299 if selected_drugs is None: 300 return None 301 302 data_src_pk = self.create_data_source_entry() 303 304 new_drugs = [] 305 new_substances = [] 306 307 for entry in selected_drugs: 308 309 _log.debug('importing drug: %s %s', entry['name'], entry['darreichungsform']) 310 311 if entry[u'hilfsmittel']: 312 _log.debug('skipping Hilfsmittel') 313 continue 314 315 if entry[u'erstattbares_medizinprodukt']: 316 _log.debug('skipping sonstiges Medizinprodukt') 317 continue 318 319 # create branded drug (or get it if it already exists) 320 drug = create_branded_drug(brand_name = entry['name'], preparation = entry['darreichungsform']) 321 if drug is None: 322 drug = get_drug_by_brand(brand_name = entry['name'], preparation = entry['darreichungsform']) 323 new_drugs.append(drug) 324 325 # update fields 326 drug['is_fake'] = False 327 drug['atc_code'] = entry['atc'] 328 drug['external_code'] = u'%s::%s' % ('DE-PZN', entry['pzn']) 329 drug['fk_data_source'] = data_src_pk 330 drug.save() 331 332 # add components to brand 333 atc = None # hopefully MMI eventually supports atc-per-substance in a drug... 334 if len(entry['wirkstoffe']) == 1: 335 atc = entry['atc'] 336 for wirkstoff in entry['wirkstoffe']: 337 drug.add_component(substance = wirkstoff, atc = atc) 338 339 # create as consumable substances, too 340 atc = None # hopefully MMI eventually supports atc-per-substance in a drug... 341 if len(entry['wirkstoffe']) == 1: 342 atc = entry['atc'] 343 for wirkstoff in entry['wirkstoffe']: 344 new_substances.append(create_used_substance(substance = wirkstoff, atc = atc)) 345 346 return new_drugs, new_substances
347 #--------------------------------------------------------
348 - def check_drug_interactions(self, pzn_list=None, substances=None):
349 """For this to work the BDT interaction check must be configured in the MMI.""" 350 351 if pzn_list is None: 352 if substances is None: 353 return 354 if len(substances) < 2: 355 return 356 pzn_list = [ s.external_code for s in substances ] 357 pzn_list = [ pzn for pzn in pzn_list if pzn is not None ] 358 pzn_list = [ code_value for code_type, code_value in pzn_list if code_type == u'DE-PZN'] 359 360 else: 361 if len(pzn_list) < 2: 362 return 363 364 if pzn_list < 2: 365 return 366 367 bdt_file = codecs.open(filename = self.interactions_filename, mode = 'wb', encoding = cGelbeListeWindowsInterface.default_encoding) 368 369 for pzn in pzn_list: 370 pzn = pzn.strip() 371 lng = cGelbeListeWindowsInterface.bdt_line_base_length + len(pzn) 372 bdt_file.write(cGelbeListeWindowsInterface.bdt_line_template % (lng, pzn)) 373 374 bdt_file.close() 375 376 self.switch_to_frontend(blocking = False)
377 #--------------------------------------------------------
378 - def show_info_on_substance(self, substance=None):
379 380 cmd = None 381 382 if substance.external_code is not None: 383 code_type, pzn = substance.external_code 384 if code_type == u'DE-PZN': 385 cmd = u'%s -PZN %s' % (self.path_to_binary, pzn) 386 387 if cmd is None: 388 name = gmTools.coalesce ( 389 substance['brand'], 390 substance['substance'] 391 ) 392 cmd = u'%s -NAME %s' % (self.path_to_binary, name) 393 394 # better to clean up interactions file 395 open(self.interactions_filename, 'wb').close() 396 397 self.switch_to_frontend(cmd = cmd)
398 #============================================================
399 -class cGelbeListeWineInterface(cGelbeListeWindowsInterface):
400
401 - def __init__(self):
402 cGelbeListeWindowsInterface.__init__(self) 403 404 _log.info(u'%s (WINE extension)', cGelbeListeWindowsInterface.version) 405 406 # FIXME: if -CLOSETOTRAY is used GNUmed cannot detect the end of MMI 407 self.path_to_binary = r'wine "C:\Programme\MMI PHARMINDEX\glwin.exe"' 408 self.args = r'"-PRESCRIPTIONFILE %s -KEEPBACKGROUND"' 409 410 paths = gmTools.gmPaths() 411 412 self.default_csv_filename = os.path.join(paths.home_dir, '.wine', 'drive_c', 'windows', 'temp', 'mmi2gm.csv') 413 self.default_csv_filename_arg = r'c:\windows\temp\mmi2gm.csv' 414 self.interactions_filename = os.path.join(paths.home_dir, '.wine', 'drive_c', 'windows', 'temp', 'gm2mmi.bdt') 415 self.data_date_filename = os.path.join(paths.home_dir, '.wine', 'drive_c', 'Programme', 'MMI PHARMINDEX', 'datadate.txt')
416 #============================================================
417 -class cIfapInterface(cDrugDataSourceInterface):
418 """empirical CSV interface""" 419
420 - def __init__(self):
421 pass
422
423 - def print_transfer_file(self, filename=None):
424 425 try: 426 csv_file = open(filename, 'rb') # FIXME: encoding ? 427 except: 428 _log.exception('cannot access [%s]', filename) 429 csv_file = None 430 431 field_names = u'PZN Handelsname Form Abpackungsmenge Einheit Preis1 Hersteller Preis2 rezeptpflichtig Festbetrag Packungszahl Packungsgr\xf6\xdfe'.split() 432 433 if csv_file is None: 434 return False 435 436 csv_lines = csv.DictReader ( 437 csv_file, 438 fieldnames = field_names, 439 delimiter = ';' 440 ) 441 442 for line in csv_lines: 443 print "--------------------------------------------------------------------"[:31] 444 for key in field_names: 445 tmp = ('%s ' % key)[:30] 446 print '%s: %s' % (tmp, line[key]) 447 448 csv_file.close()
449 450 # narr = u'%sx %s %s %s (\u2258 %s %s) von %s (%s)' % ( 451 # line['Packungszahl'].strip(), 452 # line['Handelsname'].strip(), 453 # line['Form'].strip(), 454 # line[u'Packungsgr\xf6\xdfe'].strip(), 455 # line['Abpackungsmenge'].strip(), 456 # line['Einheit'].strip(), 457 # line['Hersteller'].strip(), 458 # line['PZN'].strip() 459 # ) 460 #============================================================ 461 drug_data_source_interfaces = { 462 'Gelbe Liste/MMI (Windows)': cGelbeListeWindowsInterface, 463 'Gelbe Liste/MMI (WINE)': cGelbeListeWineInterface 464 } 465 #============================================================ 466 # substances in use across all patients 467 #------------------------------------------------------------
468 -def get_substances_in_use():
469 cmd = u'select * from clin.consumed_substance order by description' 470 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}]) 471 return rows
472 #------------------------------------------------------------
473 -def get_substance_by_pk(pk=None):
474 cmd = u'select * from clin.consumed_substance WHERE pk = %(pk)s' 475 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': {'pk': pk}}]) 476 if len(rows) == 0: 477 return None 478 return rows[0]
479 #------------------------------------------------------------
480 -def create_used_substance(substance=None, atc=None):
481 482 substance = substance.strip() 483 484 if atc is not None: 485 atc = atc.strip() 486 487 args = {'desc': substance, 'atc': atc} 488 489 cmd = u'select pk, atc_code, description from clin.consumed_substance where description = %(desc)s' 490 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}]) 491 492 if len(rows) == 0: 493 cmd = u'insert into clin.consumed_substance (description, atc_code) values (%(desc)s, gm.nullify_empty_string(%(atc)s)) returning pk, atc_code, description' 494 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True) 495 496 gmATC.propagate_atc(substance = substance, atc = atc) 497 498 row = rows[0] 499 # unfortunately not a real dict so no setting stuff by keyword 500 #row['atc_code'] = args['atc'] 501 row[1] = args['atc'] 502 return row
503 #------------------------------------------------------------
504 -def delete_used_substance(substance=None):
505 args = {'pk': substance} 506 cmd = u""" 507 delete from clin.consumed_substance 508 where 509 pk = %(pk)s and not exists ( 510 select 1 from clin.substance_intake 511 where fk_substance = %(pk)s 512 )""" 513 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
514 #============================================================
515 -class cSubstanceIntakeEntry(gmBusinessDBObject.cBusinessDBObject):
516 """Represents a substance currently taken by a patient.""" 517 518 _cmd_fetch_payload = u"select * from clin.v_pat_substance_intake where pk_substance_intake = %s" 519 _cmds_store_payload = [ 520 u"""update clin.substance_intake set 521 clin_when = %(started)s, 522 strength = gm.nullify_empty_string(%(strength)s), 523 preparation = %(preparation)s, 524 schedule = gm.nullify_empty_string(%(schedule)s), 525 aim = gm.nullify_empty_string(%(aim)s), 526 narrative = gm.nullify_empty_string(%(notes)s), 527 intake_is_approved_of = %(intake_is_approved_of)s, 528 529 -- is_long_term = %(is_long_term)s, 530 is_long_term = ( 531 case 532 when ( 533 (%(is_long_term)s is False) 534 and 535 (gm.is_null_or_blank_string(%(duration)s) is True) 536 ) is True then null 537 else %(is_long_term)s 538 end 539 )::boolean, 540 duration = ( 541 case 542 when %(is_long_term)s is True then null 543 else gm.nullify_empty_string(%(duration)s) 544 end 545 )::interval, 546 547 fk_brand = %(pk_brand)s, 548 fk_substance = %(pk_substance)s, 549 fk_episode = %(pk_episode)s 550 where 551 pk = %(pk_substance_intake)s and 552 xmin = %(xmin_substance_intake)s 553 returning 554 xmin as xmin_substance_intake 555 """ 556 ] 557 _updatable_fields = [ 558 u'started', 559 u'preparation', 560 u'strength', 561 u'intake_is_approved_of', 562 u'schedule', 563 u'duration', 564 u'aim', 565 u'is_long_term', 566 u'notes', 567 u'pk_brand', 568 u'pk_substance', 569 u'pk_episode' 570 ] 571 #--------------------------------------------------------
572 - def format(self, left_margin=0, date_format='%Y-%m-%d'):
573 574 if self._payload[self._idx['duration']] is None: 575 duration = gmTools.bool2subst ( 576 self._payload[self._idx['is_long_term']], 577 _('long-term'), 578 _('short-term'), 579 _('?short-term') 580 ) 581 else: 582 duration = gmDateTime.format_interval ( 583 self._payload[self._idx['duration']], 584 accuracy_wanted = gmDateTime.acc_days 585 ) 586 587 line = u'%s%s (%s %s): %s %s %s (%s)' % ( 588 u' ' * left_margin, 589 self._payload[self._idx['started']].strftime(date_format), 590 gmTools.u_right_arrow, 591 duration, 592 self._payload[self._idx['substance']], 593 self._payload[self._idx['strength']], 594 self._payload[self._idx['preparation']], 595 gmTools.bool2subst(self._payload[self._idx['is_currently_active']], _('ongoing'), _('inactive'), _('?ongoing')) 596 ) 597 598 return line
599 #-------------------------------------------------------- 600 # properties 601 #--------------------------------------------------------
602 - def _get_ddd(self):
603 604 try: self.__ddd 605 except AttributeError: self.__ddd = None 606 607 if self.__ddd is not None: 608 return self.__ddd 609 610 if self._payload[self._idx['atc_substance']] is not None: 611 ddd = gmATC.atc2ddd(atc = self._payload[self._idx['atc_substance']]) 612 if len(ddd) != 0: 613 self.__ddd = ddd[0] 614 else: 615 if self._payload[self._idx['atc_brand']] is not None: 616 ddd = gmATC.atc2ddd(atc = self._payload[self._idx['atc_brand']]) 617 if len(ddd) != 0: 618 self.__ddd = ddd[0] 619 620 return self.__ddd
621 622 ddd = property(_get_ddd, lambda x:x) 623 #--------------------------------------------------------
624 - def _get_external_code(self):
625 drug = self.containing_drug 626 627 if drug is None: 628 return None 629 630 return drug.external_code
631 632 external_code = property(_get_external_code, lambda x:x) 633 #--------------------------------------------------------
634 - def _get_containing_drug(self):
635 if self._payload[self._idx['pk_brand']] is None: 636 return None 637 638 return cBrandedDrug(aPK_obj = self._payload[self._idx['pk_brand']])
639 640 containing_drug = property(_get_containing_drug, lambda x:x) 641 #--------------------------------------------------------
642 - def _get_parsed_schedule(self):
643 tests = [ 644 # lead, trail 645 ' 1-1-1-1 ', 646 # leading dose 647 '1-1-1-1', 648 '22-1-1-1', 649 '1/3-1-1-1', 650 '/4-1-1-1' 651 ] 652 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}$" 653 for test in tests: 654 print test.strip(), ":", regex.match(pattern, test.strip())
655 #------------------------------------------------------------
656 -def create_substance_intake(substance=None, atc=None, encounter=None, episode=None, preparation=None):
657 658 args = { 659 'enc': encounter, 660 'epi': episode, 661 'prep': preparation, 662 'subst': create_used_substance(substance = substance, atc = atc)['pk'] 663 } 664 665 cmd = u""" 666 insert into clin.substance_intake ( 667 fk_encounter, 668 fk_episode, 669 fk_substance, 670 preparation, 671 intake_is_approved_of 672 ) values ( 673 %(enc)s, 674 %(epi)s, 675 %(subst)s, 676 gm.nullify_empty_string(%(prep)s), 677 False 678 ) 679 returning pk 680 """ 681 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True) 682 return cSubstanceIntakeEntry(aPK_obj = rows[0][0])
683 #------------------------------------------------------------
684 -def delete_substance_intake(substance=None):
685 cmd = u'delete from clin.substance_intake where pk = %(pk)s' 686 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': {'pk': substance}}])
687 #============================================================
688 -class cBrandedDrug(gmBusinessDBObject.cBusinessDBObject):
689 """Represents a drug as marketed by a manufacturer.""" 690 691 _cmd_fetch_payload = u"select *, xmin from ref.branded_drug where pk = %s" 692 _cmds_store_payload = [ 693 u"""update ref.branded_drug set 694 description = %(description)s, 695 preparation = %(preparation)s, 696 atc_code = gm.nullify_empty_string(%(atc_code)s), 697 external_code = gm.nullify_empty_string(%(external_code)s), 698 is_fake = %(is_fake)s, 699 fk_data_source = %(fk_data_source)s 700 where 701 pk = %(pk)s and 702 xmin = %(xmin)s 703 returning 704 xmin 705 """ 706 ] 707 _updatable_fields = [ 708 u'description', 709 u'preparation', 710 u'atc_code', 711 u'is_fake', 712 u'external_code', 713 u'fk_data_source' 714 ] 715 #--------------------------------------------------------
716 - def _get_external_code(self):
717 if self._payload[self._idx['external_code']] is None: 718 return None 719 720 if regex.match(u'.+::.+', self._payload[self._idx['external_code']], regex.UNICODE) is None: 721 # FIXME: maybe evaluate fk_data_source 722 return None 723 724 return regex.split(u'::', self._payload[self._idx['external_code']], 1)
725 726 external_code = property(_get_external_code, lambda x:x) 727 #--------------------------------------------------------
728 - def _get_components(self):
729 cmd = u'select * from ref.substance_in_brand where fk_brand = %(brand)s' 730 args = {'brand': self._payload[self._idx['pk']]} 731 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False) 732 return rows
733 734 components = property(_get_components, lambda x:x) 735 #--------------------------------------------------------
736 - def add_component(self, substance=None, atc=None):
737 738 # normalize atc 739 atc = gmATC.propagate_atc(substance = substance, atc = atc) 740 741 args = { 742 'brand': self.pk_obj, 743 'desc': substance, 744 'atc': atc 745 } 746 747 # already exists ? 748 cmd = u""" 749 SELECT pk 750 FROM ref.substance_in_brand 751 WHERE 752 fk_brand = %(brand)s 753 AND 754 ((description = %(desc)s) OR ((atc_code = %(atc)s) IS TRUE)) 755 """ 756 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False) 757 if len(rows) > 0: 758 return 759 760 # create it 761 cmd = u""" 762 INSERT INTO ref.substance_in_brand (fk_brand, description, atc_code) 763 VALUES (%(brand)s, %(desc)s, %(atc)s) 764 """ 765 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
766 #------------------------------------------------------------
767 - def remove_component(substance=None):
768 delete_component_from_branded_drug(brand = self.pk_obj, component = substance)
769 #------------------------------------------------------------
770 -def get_substances_in_brands():
771 cmd = u'SELECT * FROM ref.v_substance_in_brand ORDER BY brand, substance' 772 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = False) 773 return rows
774 #------------------------------------------------------------
775 -def get_branded_drugs():
776 777 cmd = u'SELECT pk FROM ref.branded_drug ORDER BY description' 778 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = False) 779 780 return [ cBrandedDrug(aPK_obj = r['pk']) for r in rows ]
781 #------------------------------------------------------------
782 -def get_drug_by_brand(brand_name=None, preparation=None):
783 args = {'brand': brand_name, 'prep': preparation} 784 785 cmd = u'SELECT pk FROM ref.branded_drug WHERE description = %(brand)s AND preparation = %(prep)s' 786 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False) 787 788 if len(rows) == 0: 789 return None 790 791 return cBrandedDrug(aPK_obj = rows[0]['pk'])
792 #------------------------------------------------------------
793 -def create_branded_drug(brand_name=None, preparation=None, return_existing=False):
794 795 if preparation is None: 796 preparation = _('units') 797 798 if preparation.strip() == u'': 799 preparation = _('units') 800 801 drug = get_drug_by_brand(brand_name = brand_name, preparation = preparation) 802 803 if drug is not None: 804 if return_existing: 805 return drug 806 return None 807 808 cmd = u'insert into ref.branded_drug (description, preparation) values (%(brand)s, %(prep)s) returning pk' 809 args = {'brand': brand_name, 'prep': preparation} 810 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True, get_col_idx = False) 811 812 return cBrandedDrug(aPK_obj = rows[0]['pk'])
813 #------------------------------------------------------------
814 -def delete_branded_drug(brand=None):
815 cmd = u'delete from ref.branded_drug where pk = %(pk)s' 816 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': {'pk': brand}}])
817 #------------------------------------------------------------
818 -def delete_component_from_branded_drug(brand=None, component=None):
819 cmd = u'delete from ref.substance_in_brand where fk_brand = %(brand)s and pk = %(comp)s' 820 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': {'brand': brand, 'comp': component}}])
821 #============================================================ 822 # main 823 #------------------------------------------------------------ 824 if __name__ == "__main__": 825 826 from Gnumed.pycommon import gmLog2 827 from Gnumed.pycommon import gmI18N 828 829 gmI18N.activate_locale() 830 # gmDateTime.init() 831 #--------------------------------------------------------
832 - def test_MMI_interface():
833 mmi = cGelbeListeWineInterface() 834 print mmi 835 print "interface definition:", mmi.version 836 print "database versions: ", mmi.get_data_source_version()
837 #--------------------------------------------------------
838 - def test_MMI_file():
839 mmi_file = cGelbeListeCSVFile(filename = sys.argv[2]) 840 for drug in mmi_file: 841 print "-------------" 842 print '"%s" (ATC: %s / PZN: %s)' % (drug['name'], drug['atc'], drug['pzn']) 843 for stoff in drug['wirkstoffe']: 844 print " Wirkstoff:", stoff 845 print drug 846 mmi_file.close()
847 #--------------------------------------------------------
848 - def test_mmi_switch_to():
849 mmi = cGelbeListeWineInterface() 850 mmi.switch_to_frontend(blocking = False)
851 #--------------------------------------------------------
852 - def test_mmi_select_drugs():
853 mmi = cGelbeListeWineInterface() 854 mmi_file = mmi.select_drugs() 855 for drug in mmi_file: 856 print "-------------" 857 print '"%s" (ATC: %s / PZN: %s)' % (drug['name'], drug['atc'], drug['pzn']) 858 for stoff in drug['wirkstoffe']: 859 print " Wirkstoff:", stoff 860 print drug 861 mmi_file.close()
862 #--------------------------------------------------------
863 - def test_mmi_import_drugs():
864 mmi = cGelbeListeWineInterface() 865 mmi.import_drugs()
866 #--------------------------------------------------------
867 - def test_mmi_interaction_check():
868 mmi = cGelbeListeInterface() 869 print mmi 870 print "interface definition:", mmi.version 871 # Metoprolol + Hct vs Citalopram 872 diclofenac = '7587712' 873 phenprocoumon = '4421744' 874 mmi.check_drug_interactions(pzn_list = [diclofenac, phenprocoumon])
875 #--------------------------------------------------------
876 - def test_create_substance_intake():
877 drug = create_substance_intake ( 878 substance = u'Whiskey', 879 atc = u'no ATC available', 880 encounter = 1, 881 episode = 1, 882 preparation = 'a nice glass' 883 ) 884 print drug
885 #--------------------------------------------------------
886 - def test_show_components():
887 drug = cBrandedDrug(aPK_obj = sys.argv[2]) 888 print drug 889 print drug.components
890 #-------------------------------------------------------- 891 if (len(sys.argv)) > 1 and (sys.argv[1] == 'test'): 892 #test_MMI_interface() 893 #test_MMI_file() 894 #test_mmi_switch_to() 895 #test_mmi_select_drugs() 896 #test_mmi_import_substances() 897 #test_mmi_import_drugs() 898 #test_interaction_check() 899 #test_create_substance_intake() 900 test_show_components() 901 #============================================================ 902 # $Log: gmMedication.py,v $ 903 # Revision 1.21 2010/02/06 20:44:58 ncq 904 # - .ddd on substance intake 905 # 906 # Revision 1.20 2009/12/25 21:38:50 ncq 907 # - add 2 new fields to MMI CSV file 908 # - show-info-on-drug 909 # - enhance switch-to-frontend to allow custom startup cmd 910 # 911 # Revision 1.19 2009/12/02 16:48:58 ncq 912 # - add infrastructure for removing component from brand 913 # 914 # Revision 1.18 2009/12/01 21:48:09 ncq 915 # - get-substance-by-pk 916 # 917 # Revision 1.17 2009/11/30 21:56:36 ncq 918 # - components property on branded drug 919 # 920 # Revision 1.16 2009/11/30 15:06:27 ncq 921 # - handle a bunch of possibilities of dirty records retrieved from GLI/MMI 922 # - default preparation to i18n(units) 923 # 924 # Revision 1.15 2009/11/29 19:59:31 ncq 925 # - improve substance/component creation with propagate-atc 926 # 927 # Revision 1.14 2009/11/29 15:57:27 ncq 928 # - while SQL results are dicts as far as *retrieval* is concerned, 929 # they are NOT for inserting data into them, so use list access 930 # 931 # Revision 1.13 2009/11/28 18:27:30 ncq 932 # - much improved ATC detection on substance creation 933 # - create-patient-consumed-substance -> create-substance-intake 934 # - get-branded-drugs 935 # - get-substances-in-brands 936 # - delete-branded-drugs 937 # 938 # Revision 1.12 2009/11/24 19:57:22 ncq 939 # - implement getting/creating data souce entry for MMI 940 # - implement version retrieval for MMI 941 # - import-drugs() 942 # - check-drug-interactions() 943 # - cConsumedSubstance -> cSubstanceIntakeEntry + .external_code 944 # - cBrandedDrug 945 # - tests 946 # 947 # Revision 1.11 2009/11/06 15:05:07 ncq 948 # - get-substances-in-use 949 # - meds formatting 950 # - delete-patient-consumed-substance 951 # 952 # Revision 1.10 2009/10/29 17:16:59 ncq 953 # - return newly created substances from creator func and substance importer method 954 # - better naming 955 # - finish up cConsumedSubstance 956 # 957 # Revision 1.9 2009/10/28 16:40:12 ncq 958 # - add some docs about schedule parsing 959 # 960 # Revision 1.8 2009/10/26 22:29:05 ncq 961 # - better factorization of paths in MMI interface 962 # - update ATC on INN if now known 963 # - delete-consumed-substance 964 # 965 # Revision 1.7 2009/10/21 20:37:18 ncq 966 # - MMI uses cp1250, rather than cp1252, (at least under WINE) contrary to direct communication ... 967 # - use unicode csv reader 968 # - add a bunch of file cleanup 969 # - split MMI interface into WINE vs native Windows version 970 # 971 # Revision 1.6 2009/10/21 09:15:50 ncq 972 # - much improved MMI frontend 973 # 974 # Revision 1.5 2009/09/29 13:14:25 ncq 975 # - faulty ordering of definitions 976 # 977 # Revision 1.4 2009/09/01 22:16:35 ncq 978 # - improved interaction check test 979 # 980 # Revision 1.3 2009/08/24 18:36:20 ncq 981 # - add CSV file iterator 982 # - add BDT interaction check 983 # 984 # Revision 1.2 2009/08/21 09:56:37 ncq 985 # - start drug data source interfaces 986 # - add MMI/Gelbe Liste interface 987 # 988 # Revision 1.1 2009/05/12 12:02:01 ncq 989 # - start supporting current medications 990 # 991 # 992