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 v2 or later 
   5  """ 
   6  #============================================================ 
   7  __version__ = "$Revision: 1.21 $" 
   8  __author__ = "K.Hilbert <Karsten.Hilbert@gmx.net>" 
   9   
  10  import sys 
  11  import logging 
  12  import csv 
  13  import codecs 
  14  import os 
  15  import re as regex 
  16  import subprocess 
  17  import decimal 
  18  from xml.etree import ElementTree as etree 
  19   
  20   
  21  if __name__ == '__main__': 
  22          sys.path.insert(0, '../../') 
  23          _ = lambda x:x 
  24  from Gnumed.pycommon import gmBusinessDBObject 
  25  from Gnumed.pycommon import gmTools 
  26  from Gnumed.pycommon import gmShellAPI 
  27  from Gnumed.pycommon import gmPG2 
  28  from Gnumed.pycommon import gmDispatcher 
  29  from Gnumed.pycommon import gmMatchProvider 
  30  from Gnumed.pycommon import gmHooks 
  31  from Gnumed.pycommon import gmDateTime 
  32   
  33  from Gnumed.business import gmATC 
  34  from Gnumed.business import gmAllergy 
  35  from Gnumed.business.gmDocuments import DOCUMENT_TYPE_PRESCRIPTION 
  36  from Gnumed.business.gmDocuments import create_document_type 
  37   
  38   
  39  _log = logging.getLogger('gm.meds') 
  40  _log.info(__version__) 
  41   
  42  #_ = lambda x:x 
  43  DEFAULT_MEDICATION_HISTORY_EPISODE = _('Medication history') 
  44  #============================================================ 
45 -def _on_substance_intake_modified():
46 """Always relates to the active patient.""" 47 gmHooks.run_hook_script(hook = u'after_substance_intake_modified')
48 49 gmDispatcher.connect(_on_substance_intake_modified, u'substance_intake_mod_db') 50 51 #============================================================
52 -def drug2renal_insufficiency_url(search_term=None):
53 54 if search_term is None: 55 return u'http://www.dosing.de' 56 57 if isinstance(search_term, basestring): 58 if search_term.strip() == u'': 59 return u'http://www.dosing.de' 60 61 terms = [] 62 names = [] 63 64 if isinstance(search_term, cBrandedDrug): 65 if search_term['atc'] is not None: 66 terms.append(search_term['atc']) 67 68 elif isinstance(search_term, cSubstanceIntakeEntry): 69 names.append(search_term['substance']) 70 if search_term['atc_brand'] is not None: 71 terms.append(search_term['atc_brand']) 72 if search_term['atc_substance'] is not None: 73 terms.append(search_term['atc_substance']) 74 75 elif isinstance(search_term, cDrugComponent): 76 names.append(search_term['substance']) 77 if search_term['atc_brand'] is not None: 78 terms.append(search_term['atc_brand']) 79 if search_term['atc_substance'] is not None: 80 terms.append(search_term['atc_substance']) 81 82 elif isinstance(search_term, cConsumableSubstance): 83 names.append(search_term['description']) 84 if search_term['atc_code'] is not None: 85 terms.append(search_term['atc_code']) 86 87 elif search_term is not None: 88 names.append(u'%s' % search_term) 89 terms.extend(gmATC.text2atc(text = u'%s' % search_term, fuzzy = True)) 90 91 for name in names: 92 if name.endswith('e'): 93 terms.append(name[:-1]) 94 else: 95 terms.append(name) 96 97 #url_template = u'http://www.google.de/#q=site%%3Adosing.de+%s' 98 #url = url_template % u'+OR+'.join(terms) 99 100 url_template = u'http://www.google.com/search?hl=de&source=hp&q=site%%3Adosing.de+%s&btnG=Google-Suche' 101 url = url_template % u'+OR+'.join(terms) 102 103 _log.debug(u'renal insufficiency URL: %s', url) 104 105 return url
106 #============================================================ 107 # this should be in gmCoding.py
108 -def create_data_source(long_name=None, short_name=None, version=None, source=None, language=None):
109 110 args = { 111 'lname': long_name, 112 'sname': short_name, 113 'ver': version, 114 'src': source, 115 'lang': language 116 } 117 118 cmd = u"""select pk from ref.data_source where name_long = %(lname)s and name_short = %(sname)s and version = %(ver)s""" 119 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}]) 120 if len(rows) > 0: 121 return rows[0]['pk'] 122 123 cmd = u""" 124 INSERT INTO ref.data_source (name_long, name_short, version, source, lang) 125 VALUES ( 126 %(lname)s, 127 %(sname)s, 128 %(ver)s, 129 %(src)s, 130 %(lang)s 131 ) 132 returning pk 133 """ 134 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True) 135 136 return rows[0]['pk']
137 #============================================================ 138 # wishlist: 139 # - --conf-file= for glwin.exe 140 # - wirkstoff: Konzentration auch in Multiprodukten 141 # - wirkstoff: ATC auch in Multiprodukten 142 # - Suche nach ATC per CLI 143
144 -class cGelbeListeCSVFile(object):
145 """Iterator over a Gelbe Liste/MMI v8.2 CSV file.""" 146 147 version = u'Gelbe Liste/MMI v8.2 CSV file interface' 148 default_transfer_file_windows = r"c:\rezept.txt" 149 #default_encoding = 'cp1252' 150 default_encoding = 'cp1250' 151 csv_fieldnames = [ 152 u'name', 153 u'packungsgroesse', # obsolete, use "packungsmenge" 154 u'darreichungsform', 155 u'packungstyp', 156 u'festbetrag', 157 u'avp', 158 u'hersteller', 159 u'rezepttext', 160 u'pzn', 161 u'status_vertrieb', 162 u'status_rezeptpflicht', 163 u'status_fachinfo', 164 u'btm', 165 u'atc', 166 u'anzahl_packungen', 167 u'zuzahlung_pro_packung', 168 u'einheit', 169 u'schedule_morgens', 170 u'schedule_mittags', 171 u'schedule_abends', 172 u'schedule_nachts', 173 u'status_dauermedikament', 174 u'status_hausliste', 175 u'status_negativliste', 176 u'ik_nummer', 177 u'status_rabattvertrag', 178 u'wirkstoffe', 179 u'wirkstoffmenge', 180 u'wirkstoffeinheit', 181 u'wirkstoffmenge_bezug', 182 u'wirkstoffmenge_bezugseinheit', 183 u'status_import', 184 u'status_lifestyle', 185 u'status_ausnahmeliste', 186 u'packungsmenge', 187 u'apothekenpflicht', 188 u'status_billigere_packung', 189 u'rezepttyp', 190 u'besonderes_arzneimittel', # Abstimmungsverfahren SGB-V 191 u't_rezept_pflicht', # Thalidomid-Rezept 192 u'erstattbares_medizinprodukt', 193 u'hilfsmittel', 194 u'hzv_rabattkennung', 195 u'hzv_preis' 196 ] 197 boolean_fields = [ 198 u'status_rezeptpflicht', 199 u'status_fachinfo', 200 u'btm', 201 u'status_dauermedikament', 202 u'status_hausliste', 203 u'status_negativliste', 204 u'status_rabattvertrag', 205 u'status_import', 206 u'status_lifestyle', 207 u'status_ausnahmeliste', 208 u'apothekenpflicht', 209 u'status_billigere_packung', 210 u'besonderes_arzneimittel', # Abstimmungsverfahren SGB-V 211 u't_rezept_pflicht', 212 u'erstattbares_medizinprodukt', 213 u'hilfsmittel' 214 ] 215 #--------------------------------------------------------
216 - def __init__(self, filename=None):
217 218 _log.info(cGelbeListeCSVFile.version) 219 220 self.filename = filename 221 if filename is None: 222 self.filename = cGelbeListeCSVFile.default_transfer_file_windows 223 224 _log.debug('reading Gelbe Liste/MMI drug data from [%s]', self.filename) 225 226 self.csv_file = codecs.open(filename = filename, mode = 'rUb', encoding = cGelbeListeCSVFile.default_encoding) 227 228 self.csv_lines = gmTools.unicode_csv_reader ( 229 self.csv_file, 230 fieldnames = cGelbeListeCSVFile.csv_fieldnames, 231 delimiter = ';', 232 quotechar = '"', 233 dict = True 234 )
235 #--------------------------------------------------------
236 - def __iter__(self):
237 return self
238 #--------------------------------------------------------
239 - def next(self):
240 line = self.csv_lines.next() 241 242 for field in cGelbeListeCSVFile.boolean_fields: 243 line[field] = (line[field].strip() == u'T') 244 245 # split field "Wirkstoff" by ";" 246 if line['wirkstoffe'].strip() == u'': 247 line['wirkstoffe'] = [] 248 else: 249 line['wirkstoffe'] = [ wirkstoff.strip() for wirkstoff in line['wirkstoffe'].split(u';') ] 250 251 return line
252 #--------------------------------------------------------
253 - def close(self, truncate=True):
254 try: self.csv_file.close() 255 except: pass 256 257 if truncate: 258 try: os.open(self.filename, 'wb').close 259 except: pass
260 #--------------------------------------------------------
261 - def _get_has_unknown_fields(self):
263 264 has_unknown_fields = property(_get_has_unknown_fields, lambda x:x)
265 #============================================================
266 -class cDrugDataSourceInterface(object):
267 268 #--------------------------------------------------------
269 - def __init__(self):
270 self.patient = None 271 self.reviewer = None 272 self.custom_path_to_binary = None
273 #--------------------------------------------------------
274 - def get_data_source_version(self):
275 raise NotImplementedError
276 #--------------------------------------------------------
277 - def create_data_source_entry(self):
278 raise NotImplementedError
279 #--------------------------------------------------------
280 - def switch_to_frontend(self, blocking=False):
281 raise NotImplementedError
282 #--------------------------------------------------------
283 - def import_drugs(self):
284 self.switch_to_frontend()
285 #--------------------------------------------------------
286 - def check_interactions(self, substance_intakes=None):
287 self.switch_to_frontend()
288 #--------------------------------------------------------
289 - def show_info_on_drug(self, substance_intake=None):
290 self.switch_to_frontend()
291 #--------------------------------------------------------
292 - def show_info_on_substance(self, substance_intake=None):
293 self.switch_to_frontend()
294 #--------------------------------------------------------
295 - def prescribe(self, substance_intakes=None):
296 self.switch_to_frontend() 297 return []
298 #============================================================
299 -class cFreeDiamsInterface(cDrugDataSourceInterface):
300 301 version = u'FreeDiams interface' 302 default_encoding = 'utf8' 303 default_dob_format = '%Y/%m/%d' 304 305 map_gender2mf = { 306 'm': u'M', 307 'f': u'F', 308 'tf': u'H', 309 'tm': u'H', 310 'h': u'H' 311 } 312 #--------------------------------------------------------
313 - def __init__(self):
314 cDrugDataSourceInterface.__init__(self) 315 _log.info(cFreeDiamsInterface.version) 316 317 self.__imported_drugs = [] 318 319 self.__gm2fd_filename = gmTools.get_unique_filename(prefix = r'gm2freediams-', suffix = r'.xml') 320 _log.debug('GNUmed -> FreeDiams "exchange-in" file: %s', self.__gm2fd_filename) 321 self.__fd2gm_filename = gmTools.get_unique_filename(prefix = r'freediams2gm-', suffix = r'.xml') 322 _log.debug('GNUmed <-> FreeDiams "exchange-out"/"prescription" file: %s', self.__fd2gm_filename) 323 paths = gmTools.gmPaths() 324 self.__fd4gm_config_file = os.path.join(paths.home_dir, '.gnumed', 'freediams4gm.conf') 325 326 self.path_to_binary = None 327 self.__detect_binary()
328 #--------------------------------------------------------
329 - def get_data_source_version(self):
330 # ~/.freediams/config.ini: [License] -> AcceptedVersion=.... 331 332 if not self.__detect_binary(): 333 return False 334 335 freediams = subprocess.Popen ( 336 args = u'--version', # --version or -version or -v 337 executable = self.path_to_binary, 338 stdout = subprocess.PIPE, 339 stderr = subprocess.PIPE, 340 # close_fds = True, # Windows can't do that in conjunction with stdout/stderr = ... :-( 341 universal_newlines = True 342 ) 343 data, errors = freediams.communicate() 344 version = regex.search('FreeDiams\s\d.\d.\d', data).group().split()[1] 345 _log.debug('FreeDiams %s', version) 346 347 return version
348 #--------------------------------------------------------
349 - def create_data_source_entry(self):
350 return create_data_source ( 351 long_name = u'"FreeDiams" Drug Database Frontend', 352 short_name = u'FreeDiams', 353 version = self.get_data_source_version(), 354 source = u'http://ericmaeker.fr/FreeMedForms/di-manual/index.html', 355 language = u'fr' # actually to be multi-locale 356 )
357 #--------------------------------------------------------
358 - def switch_to_frontend(self, blocking=False, mode='interactions'):
359 """http://ericmaeker.fr/FreeMedForms/di-manual/en/html/ligne_commandes.html""" 360 361 _log.debug('calling FreeDiams in [%s] mode', mode) 362 363 self.__imported_drugs = [] 364 365 if not self.__detect_binary(): 366 return False 367 368 self.__create_gm2fd_file(mode = mode) 369 370 args = u'--exchange-in="%s"' % (self.__gm2fd_filename) 371 cmd = r'%s %s' % (self.path_to_binary, args) 372 if os.name == 'nt': 373 blocking = True 374 if not gmShellAPI.run_command_in_shell(command = cmd, blocking = blocking): 375 _log.error('problem switching to the FreeDiams drug database') 376 return False 377 378 if blocking == True: 379 self.import_fd2gm_file_as_drugs() 380 381 return True
382 #--------------------------------------------------------
383 - def import_drugs(self):
384 self.switch_to_frontend(blocking = True)
385 #--------------------------------------------------------
386 - def check_interactions(self, substance_intakes=None):
387 if substance_intakes is None: 388 return 389 if len(substance_intakes) < 2: 390 return 391 392 self.__create_prescription_file(substance_intakes = substance_intakes) 393 self.switch_to_frontend(mode = 'interactions', blocking = False)
394 #--------------------------------------------------------
395 - def show_info_on_drug(self, substance_intake=None):
396 if substance_intake is None: 397 return 398 399 self.__create_prescription_file(substance_intakes = [substance_intake]) 400 self.switch_to_frontend(mode = 'interactions', blocking = False)
401 #--------------------------------------------------------
402 - def show_info_on_substance(self, substance_intake=None):
403 self.show_info_on_drug(substance_intake = substance_intake)
404 #--------------------------------------------------------
405 - def prescribe(self, substance_intakes=None):
406 if substance_intakes is None: 407 if not self.__export_latest_prescription(): 408 self.__create_prescription_file() 409 else: 410 self.__create_prescription_file(substance_intakes = substance_intakes) 411 412 self.switch_to_frontend(mode = 'prescription', blocking = True) 413 self.import_fd2gm_file_as_prescription() 414 415 return self.__imported_drugs
416 #-------------------------------------------------------- 417 # internal helpers 418 #--------------------------------------------------------
419 - def __detect_binary(self):
420 421 if self.path_to_binary is not None: 422 return True 423 424 found, cmd = gmShellAPI.find_first_binary(binaries = [ 425 r'/usr/bin/freediams', 426 r'freediams', 427 r'/Applications/FreeDiams.app/Contents/MacOs/FreeDiams', 428 r'C:\Program Files (x86)\FreeDiams\freediams.exe', 429 r'C:\Program Files\FreeDiams\freediams.exe', 430 r'c:\programs\freediams\freediams.exe', 431 r'freediams.exe' 432 ]) 433 434 if found: 435 self.path_to_binary = cmd 436 return True 437 438 try: 439 self.custom_path_to_binary 440 except AttributeError: 441 _log.error('cannot find FreeDiams binary, no custom path set') 442 return False 443 444 if self.custom_path_to_binary is None: 445 _log.error('cannot find FreeDiams binary') 446 return False 447 448 found, cmd = gmShellAPI.detect_external_binary(binary = self.custom_path_to_binary) 449 if found: 450 self.path_to_binary = cmd 451 return True 452 453 _log.error('cannot find FreeDiams binary') 454 return False
455 #--------------------------------------------------------
457 458 if self.patient is None: 459 _log.debug('cannot export latest FreeDiams prescriptions w/o patient') 460 return False 461 462 docs = self.patient.get_document_folder() 463 prescription = docs.get_latest_freediams_prescription() 464 if prescription is None: 465 _log.debug('no FreeDiams prescription available') 466 return False 467 468 for part in prescription.parts: 469 if part['filename'] == u'freediams-prescription.xml': 470 if part.export_to_file(filename = self.__fd2gm_filename) is not None: 471 return True 472 473 _log.error('cannot export latest FreeDiams prescription to XML file') 474 475 return False
476 #--------------------------------------------------------
477 - def __create_prescription_file(self, substance_intakes=None):
478 """FreeDiams calls this exchange-out or prescription file. 479 480 CIS stands for Unique Speciality Identifier (eg bisoprolol 5 mg, gel). 481 CIS is AFSSAPS specific, but pharmacist can retreive drug name with the CIS. 482 AFSSAPS is the French FDA. 483 484 CIP stands for Unique Presentation Identifier (eg 30 pills plaq) 485 CIP if you want to specify the packaging of the drug (30 pills 486 thermoformed tablet...) -- actually not really usefull for french 487 doctors. 488 # .external_code_type: u'FR-CIS' 489 # .external_cod: the CIS value 490 491 OnlyForTest: 492 OnlyForTest drugs will be processed by the IA Engine but 493 not printed (regardless of FreeDiams mode). They are shown 494 in gray in the prescription view. 495 496 Select-only is a mode where FreeDiams creates a list of drugs 497 not a full prescription. In this list, users can add ForTestOnly 498 drug if they want to 499 1. print the list without some drugs 500 2. but including these drugs in the IA engine calculation 501 502 Select-Only mode does not have any relation with the ForTestOnly drugs. 503 504 IsTextual: 505 What is the use and significance of the 506 <IsTextual>true/false</IsTextual> 507 flag when both <DrugName> and <TextualDrugName> exist ? 508 509 This tag must be setted even if it sounds like a duplicated 510 data. This tag is needed inside FreeDiams code. 511 512 INN: 513 GNUmed will pass the substance in <TextualDrugName 514 and will also pass <INN>True</INN>. 515 516 Eric: Nop, this is not usefull because pure textual drugs 517 are not processed but just shown. 518 """ 519 # virginize file 520 open(self.__fd2gm_filename, 'wb').close() 521 522 # make sure we've got something to do 523 if substance_intakes is None: 524 if self.patient is None: 525 _log.warning('cannot create prescription file because there is neither a patient nor a substance intake list') 526 # do fail because __export_latest_prescription() should not have been called without patient 527 return False 528 emr = self.patient.get_emr() 529 substance_intakes = emr.get_current_substance_intake ( 530 include_inactive = False, 531 include_unapproved = True 532 ) 533 534 drug_snippets = [] 535 536 # process FD drugs 537 fd_intakes = [ i for i in substance_intakes if ( 538 (i['intake_is_approved_of'] is True) 539 and 540 (i['external_code_type_brand'] is not None) 541 and 542 (i['external_code_type_brand'].startswith(u'FreeDiams::')) 543 )] 544 545 intakes_pooled_by_brand = {} 546 for intake in fd_intakes: 547 # this will leave only one entry per brand 548 # but FreeDiams knows the components ... 549 intakes_pooled_by_brand[intake['brand']] = intake 550 del fd_intakes 551 552 drug_snippet = u"""<Prescription> 553 <Drug u1="%s" u2="" old="%s" u3="" db="%s"> <!-- "old" needs to be the same as "u1" if not known --> 554 <DrugName>%s</DrugName> <!-- just for identification when reading XML files --> 555 </Drug> 556 </Prescription>""" 557 558 last_db_id = u'CA_HCDPD' 559 for intake in intakes_pooled_by_brand.values(): 560 last_db_id = gmTools.xml_escape_string(text = intake['external_code_type_brand'].replace(u'FreeDiams::', u'').split(u'::')[0]) 561 drug_snippets.append(drug_snippet % ( 562 gmTools.xml_escape_string(text = intake['external_code_brand'].strip()), 563 gmTools.xml_escape_string(text = intake['external_code_brand'].strip()), 564 last_db_id, 565 gmTools.xml_escape_string(text = intake['brand'].strip()) 566 )) 567 568 # process non-FD drugs 569 non_fd_intakes = [ i for i in substance_intakes if ( 570 (i['intake_is_approved_of'] is True) 571 and ( 572 (i['external_code_type_brand'] is None) 573 or 574 (not i['external_code_type_brand'].startswith(u'FreeDiams::')) 575 ) 576 )] 577 578 non_fd_brand_intakes = [ i for i in non_fd_intakes if i['brand'] is not None ] 579 non_fd_substance_intakes = [ i for i in non_fd_intakes if i['brand'] is None ] 580 del non_fd_intakes 581 582 drug_snippet = u"""<Prescription> 583 <Drug u1="-1" u2="" old="" u3="" db=""> 584 <DrugName>%s</DrugName> 585 </Drug> 586 <Dose Note="%s" IsTextual="true" IsAld="false"/> 587 </Prescription>""" 588 # <DrugUidName></DrugUidName> 589 # <DrugForm></DrugForm> 590 # <DrugRoute></DrugRoute> 591 # <DrugStrength/> 592 593 for intake in non_fd_substance_intakes: 594 drug_name = u'%s %s%s (%s)' % ( 595 intake['substance'], 596 intake['amount'], 597 intake['unit'], 598 intake['preparation'] 599 ) 600 drug_snippets.append(drug_snippet % ( 601 gmTools.xml_escape_string(text = drug_name.strip()), 602 gmTools.xml_escape_string(text = gmTools.coalesce(intake['schedule'], u'')) 603 )) 604 605 intakes_pooled_by_brand = {} 606 for intake in non_fd_brand_intakes: 607 brand = u'%s %s' % (intake['brand'], intake['preparation']) 608 try: 609 intakes_pooled_by_brand[brand].append(intake) 610 except KeyError: 611 intakes_pooled_by_brand[brand] = [intake] 612 613 for brand, comps in intakes_pooled_by_brand.iteritems(): 614 drug_name = u'%s\n' % brand 615 for comp in comps: 616 drug_name += u' %s %s%s\n' % ( 617 comp['substance'], 618 comp['amount'], 619 comp['unit'] 620 ) 621 drug_snippets.append(drug_snippet % ( 622 gmTools.xml_escape_string(text = drug_name.strip()), 623 gmTools.xml_escape_string(text = gmTools.coalesce(comps[0]['schedule'], u'')) 624 )) 625 626 # assemble XML file 627 xml = u"""<?xml version = "1.0" encoding = "UTF-8"?> 628 <!DOCTYPE FreeMedForms> 629 <FreeDiams> 630 <FullPrescription version="0.7.2"> 631 %s 632 </FullPrescription> 633 </FreeDiams> 634 """ 635 636 xml_file = codecs.open(self.__fd2gm_filename, 'wb', 'utf8') 637 xml_file.write(xml % u'\n\t\t'.join(drug_snippets)) 638 xml_file.close() 639 640 return True
641 #--------------------------------------------------------
642 - def __create_gm2fd_file(self, mode='interactions'):
643 644 if mode == 'interactions': 645 mode = u'select-only' 646 elif mode == 'prescription': 647 mode = u'prescriber' 648 else: 649 mode = u'select-only' 650 651 xml_file = codecs.open(self.__gm2fd_filename, 'wb', 'utf8') 652 653 xml = u"""<?xml version="1.0" encoding="UTF-8"?> 654 655 <FreeDiams_In version="0.5.0"> 656 <EMR name="GNUmed" uid="unused"/> 657 <ConfigFile value="%s"/> 658 <ExchangeOut value="%s" format="xml"/> 659 <!-- <DrugsDatabase uid="can be set to a specific DB"/> --> 660 <Ui editmode="%s" blockPatientDatas="1"/> 661 %%s 662 </FreeDiams_In> 663 664 <!-- 665 # FIXME: search by LOINC code and add (as soon as supported by FreeDiams ...) 666 <Creatinine value="12" unit="mg/l or mmol/l"/> 667 <Weight value="70" unit="kg or pd" /> 668 <Height value="170" unit="cm or "/> 669 <ICD10 value="J11.0;A22;Z23"/> 670 --> 671 """ % ( 672 self.__fd4gm_config_file, 673 self.__fd2gm_filename, 674 mode 675 ) 676 677 if self.patient is None: 678 xml_file.write(xml % u'') 679 xml_file.close() 680 return 681 682 name = self.patient.get_active_name() 683 if self.patient['dob'] is None: 684 dob = u'' 685 else: 686 dob = self.patient['dob'].strftime(cFreeDiamsInterface.default_dob_format) 687 688 emr = self.patient.get_emr() 689 allgs = emr.get_allergies() 690 atc_allgs = [ 691 a['atc_code'] for a in allgs if ((a['atc_code'] is not None) and (a['type'] == u'allergy')) 692 ] 693 atc_sens = [ 694 a['atc_code'] for a in allgs if ((a['atc_code'] is not None) and (a['type'] == u'sensitivity')) 695 ] 696 inn_allgs = [ 697 a['allergene'] for a in allgs if ((a['allergene'] is not None) and (a['type'] == u'allergy')) 698 ] 699 inn_sens = [ 700 a['allergene'] for a in allgs if ((a['allergene'] is not None) and (a['type'] == u'sensitivity')) 701 ] 702 # this is rather fragile: FreeDiams won't know what type of UID this is 703 # (but it will assume it is of the type of the drug database in use) 704 # but eventually FreeDiams puts all drugs into one database :-) 705 uid_allgs = [ 706 a['substance_code'] for a in allgs if ((a['substance_code'] is not None) and (a['type'] == u'allergy')) 707 ] 708 uid_sens = [ 709 a['substance_code'] for a in allgs if ((a['substance_code'] is not None) and (a['type'] == u'sensitivity')) 710 ] 711 712 patient_xml = u"""<Patient> 713 <Identity 714 lastnames="%s" 715 firstnames="%s" 716 uid="%s" 717 dob="%s" 718 gender="%s" 719 /> 720 <ATCAllergies value="%s"/> 721 <ATCIntolerances value="%s"/> 722 723 <InnAllergies value="%s"/> 724 <InnIntolerances value="%s"/> 725 726 <DrugsUidAllergies value="%s"/> 727 <DrugsUidIntolerances value="%s"/> 728 </Patient> 729 """ % ( 730 gmTools.xml_escape_string(text = name['lastnames']), 731 gmTools.xml_escape_string(text = name['firstnames']), 732 self.patient.ID, 733 dob, 734 cFreeDiamsInterface.map_gender2mf[self.patient['gender']], 735 gmTools.xml_escape_string(text = u';'.join(atc_allgs)), 736 gmTools.xml_escape_string(text = u';'.join(atc_sens)), 737 gmTools.xml_escape_string(text = u';'.join(inn_allgs)), 738 gmTools.xml_escape_string(text = u';'.join(inn_sens)), 739 gmTools.xml_escape_string(text = u';'.join(uid_allgs)), 740 gmTools.xml_escape_string(text = u';'.join(uid_sens)) 741 ) 742 743 xml_file.write(xml % patient_xml) 744 xml_file.close()
745 #--------------------------------------------------------
746 - def import_fd2gm_file_as_prescription(self, filename=None):
747 748 if filename is None: 749 filename = self.__fd2gm_filename 750 751 fd2gm_xml = etree.ElementTree() 752 fd2gm_xml.parse(filename) 753 754 pdfs = fd2gm_xml.findall('ExtraDatas/Printed') 755 if len(pdfs) == 0: 756 return 757 758 fd_filenames = [] 759 for pdf in pdfs: 760 fd_filenames.append(pdf.attrib['file']) 761 762 docs = self.patient.get_document_folder() 763 emr = self.patient.get_emr() 764 765 prescription = docs.add_document ( 766 document_type = create_document_type ( 767 document_type = DOCUMENT_TYPE_PRESCRIPTION 768 )['pk_doc_type'], 769 encounter = emr.active_encounter['pk_encounter'], 770 episode = emr.add_episode ( 771 episode_name = DEFAULT_MEDICATION_HISTORY_EPISODE, 772 is_open = False 773 )['pk_episode'] 774 ) 775 prescription['ext_ref'] = u'FreeDiams' 776 prescription.save() 777 fd_filenames.append(filename) 778 success, msg, parts = prescription.add_parts_from_files(files = fd_filenames) 779 if not success: 780 _log.error(msg) 781 return 782 783 for part in parts: 784 part['obj_comment'] = _('copy') 785 part.save() 786 787 xml_part = parts[-1] 788 xml_part['filename'] = u'freediams-prescription.xml' 789 xml_part['obj_comment'] = _('data') 790 xml_part.save() 791 792 # are we the intended reviewer ? 793 from Gnumed.business.gmPerson import gmCurrentProvider 794 me = gmCurrentProvider() 795 # if so: auto-sign the prescription 796 if xml_part['pk_intended_reviewer'] == me['pk_staff']: 797 prescription.set_reviewed(technically_abnormal = False, clinically_relevant = False)
798 #--------------------------------------------------------
799 - def import_fd2gm_file_as_drugs(self, filename=None):
800 """ 801 If returning textual prescriptions (say, drugs which FreeDiams 802 did not know) then "IsTextual" will be True and UID will be -1. 803 """ 804 if filename is None: 805 filename = self.__fd2gm_filename 806 807 # FIXME: do not import IsTextual drugs, or rather, make that configurable 808 809 fd2gm_xml = etree.ElementTree() 810 fd2gm_xml.parse(filename) 811 812 data_src_pk = self.create_data_source_entry() 813 814 xml_version = fd2gm_xml.find('FullPrescription').attrib['version'] 815 _log.debug('fd2gm file version: %s', xml_version) 816 817 if xml_version in ['0.6.0', '0.7.2']: 818 return self.__import_fd2gm_file_as_drugs_0_6_0(fd2gm_xml = fd2gm_xml, pk_data_source = data_src_pk) 819 820 return self.__import_fd2gm_file_as_drugs_0_5(fd2gm_xml = fd2gm_xml, pk_data_source = data_src_pk)
821 #--------------------------------------------------------
822 - def __import_fd2gm_file_as_drugs_0_6_0(self, fd2gm_xml=None, pk_data_source=None):
823 824 # drug_id_name = db_def.attrib['drugUidName'] 825 fd_xml_prescriptions = fd2gm_xml.findall('FullPrescription/Prescription') 826 827 self.__imported_drugs = [] 828 for fd_xml_prescription in fd_xml_prescriptions: 829 drug_uid = fd_xml_prescription.find('Drug').attrib['u1'].strip() 830 if drug_uid == u'-1': 831 _log.debug('skipping textual drug') 832 continue 833 drug_db = fd_xml_prescription.find('Drug').attrib['db'].strip() 834 drug_uid_name = fd_xml_prescription.find('Drug/DrugUidName').text.strip() 835 #drug_uid_name = u'<%s>' % drug_db 836 drug_name = fd_xml_prescription.find('Drug/DrugName').text.replace(', )', ')').strip() 837 drug_form = fd_xml_prescription.find('Drug/DrugForm').text.strip() 838 # drug_atc = fd_xml_prescription.find('DrugATC') 839 # if drug_atc is None: 840 # drug_atc = u'' 841 # else: 842 # if drug_atc.text is None: 843 # drug_atc = u'' 844 # else: 845 # drug_atc = drug_atc.text.strip() 846 847 # create new branded drug 848 new_drug = create_branded_drug(brand_name = drug_name, preparation = drug_form, return_existing = True) 849 self.__imported_drugs.append(new_drug) 850 new_drug['is_fake_brand'] = False 851 # new_drug['atc'] = drug_atc 852 new_drug['external_code_type'] = u'FreeDiams::%s::%s' % (drug_db, drug_uid_name) 853 new_drug['external_code'] = drug_uid 854 new_drug['pk_data_source'] = pk_data_source 855 new_drug.save() 856 857 # parse XML for composition records 858 fd_xml_components = fd_xml_prescription.getiterator('Composition') 859 comp_data = {} 860 for fd_xml_comp in fd_xml_components: 861 862 data = {} 863 864 xml_strength = fd_xml_comp.attrib['strength'].strip() 865 amount = regex.match(r'^\d+[.,]{0,1}\d*', xml_strength) 866 if amount is None: 867 amount = 99999 868 else: 869 amount = amount.group() 870 data['amount'] = amount 871 872 #unit = regex.sub(r'\d+[.,]{0,1}\d*', u'', xml_strength).strip() 873 unit = (xml_strength[len(amount):]).strip() 874 if unit == u'': 875 unit = u'*?*' 876 data['unit'] = unit 877 878 # hopefully, FreeDiams gets their act together, eventually: 879 atc = regex.match(r'[A-Za-z]\d\d[A-Za-z]{2}\d\d', fd_xml_comp.attrib['atc'].strip()) 880 if atc is None: 881 data['atc'] = None 882 else: 883 atc = atc.group() 884 data['atc'] = atc 885 886 molecule_name = fd_xml_comp.attrib['molecularName'].strip() 887 if molecule_name != u'': 888 create_consumable_substance(substance = molecule_name, atc = atc, amount = amount, unit = unit) 889 data['molecule_name'] = molecule_name 890 891 inn_name = fd_xml_comp.attrib['inn'].strip() 892 if inn_name != u'': 893 create_consumable_substance(substance = inn_name, atc = atc, amount = amount, unit = unit) 894 #data['inn_name'] = molecule_name 895 data['inn_name'] = inn_name 896 897 if molecule_name == u'': 898 data['substance'] = inn_name 899 _log.info('linking INN [%s] rather than molecularName as component', inn_name) 900 else: 901 data['substance'] = molecule_name 902 903 data['nature'] = fd_xml_comp.attrib['nature'].strip() 904 data['nature_ID'] = fd_xml_comp.attrib['natureLink'].strip() 905 906 # merge composition records of SA/FT nature 907 try: 908 old_data = comp_data[data['nature_ID']] 909 # normalize INN 910 if old_data['inn_name'] == u'': 911 old_data['inn_name'] = data['inn_name'] 912 if data['inn_name'] == u'': 913 data['inn_name'] = old_data['inn_name'] 914 # normalize molecule 915 if old_data['molecule_name'] == u'': 916 old_data['molecule_name'] = data['molecule_name'] 917 if data['molecule_name'] == u'': 918 data['molecule_name'] = old_data['molecule_name'] 919 # normalize ATC 920 if old_data['atc'] == u'': 921 old_data['atc'] = data['atc'] 922 if data['atc'] == u'': 923 data['atc'] = old_data['atc'] 924 # FT: transformed form 925 # SA: active substance 926 # it would be preferable to use the SA record because that's what's *actually* 927 # contained in the drug, however FreeDiams does not list the amount thereof 928 # (rather that of the INN) 929 # FT and SA records of the same component carry the same nature_ID 930 if data['nature'] == u'FT': 931 comp_data[data['nature_ID']] = data 932 else: 933 comp_data[data['nature_ID']] = old_data 934 935 # or create new record 936 except KeyError: 937 comp_data[data['nature_ID']] = data 938 939 # actually create components from (possibly merged) composition records 940 for key, data in comp_data.items(): 941 new_drug.add_component ( 942 substance = data['substance'], 943 atc = data['atc'], 944 amount = data['amount'], 945 unit = data['unit'] 946 )
947 #--------------------------------------------------------
948 - def __import_fd2gm_file_as_drugs_0_5(self, fd2gm_xml=None, pk_data_source=None):
949 950 db_def = fd2gm_xml.find('DrugsDatabaseName') 951 db_id = db_def.text.strip() 952 drug_id_name = db_def.attrib['drugUidName'] 953 fd_xml_drug_entries = fd2gm_xml.findall('FullPrescription/Prescription') 954 955 self.__imported_drugs = [] 956 for fd_xml_drug in fd_xml_drug_entries: 957 drug_uid = fd_xml_drug.find('Drug_UID').text.strip() 958 if drug_uid == u'-1': 959 _log.debug('skipping textual drug') 960 continue # it's a TextualDrug, skip it 961 drug_name = fd_xml_drug.find('DrugName').text.replace(', )', ')').strip() 962 drug_form = fd_xml_drug.find('DrugForm').text.strip() 963 drug_atc = fd_xml_drug.find('DrugATC') 964 if drug_atc is None: 965 drug_atc = u'' 966 else: 967 if drug_atc.text is None: 968 drug_atc = u'' 969 else: 970 drug_atc = drug_atc.text.strip() 971 972 # create new branded drug 973 new_drug = create_branded_drug(brand_name = drug_name, preparation = drug_form, return_existing = True) 974 self.__imported_drugs.append(new_drug) 975 new_drug['is_fake_brand'] = False 976 new_drug['atc'] = drug_atc 977 new_drug['external_code_type'] = u'FreeDiams::%s::%s' % (db_id, drug_id_name) 978 new_drug['external_code'] = drug_uid 979 new_drug['pk_data_source'] = pk_data_source 980 new_drug.save() 981 982 # parse XML for composition records 983 fd_xml_components = fd_xml_drug.getiterator('Composition') 984 comp_data = {} 985 for fd_xml_comp in fd_xml_components: 986 987 data = {} 988 989 amount = regex.match(r'\d+[.,]{0,1}\d*', fd_xml_comp.attrib['strenght'].strip()) # sic, typo 990 if amount is None: 991 amount = 99999 992 else: 993 amount = amount.group() 994 data['amount'] = amount 995 996 unit = regex.sub(r'\d+[.,]{0,1}\d*', u'', fd_xml_comp.attrib['strenght'].strip()).strip() # sic, typo 997 if unit == u'': 998 unit = u'*?*' 999 data['unit'] = unit 1000 1001 molecule_name = fd_xml_comp.attrib['molecularName'].strip() 1002 if molecule_name != u'': 1003 create_consumable_substance(substance = molecule_name, atc = None, amount = amount, unit = unit) 1004 data['molecule_name'] = molecule_name 1005 1006 inn_name = fd_xml_comp.attrib['inn'].strip() 1007 if inn_name != u'': 1008 create_consumable_substance(substance = inn_name, atc = None, amount = amount, unit = unit) 1009 data['inn_name'] = molecule_name 1010 1011 if molecule_name == u'': 1012 data['substance'] = inn_name 1013 _log.info('linking INN [%s] rather than molecularName as component', inn_name) 1014 else: 1015 data['substance'] = molecule_name 1016 1017 data['nature'] = fd_xml_comp.attrib['nature'].strip() 1018 data['nature_ID'] = fd_xml_comp.attrib['natureLink'].strip() 1019 1020 # merge composition records of SA/FT nature 1021 try: 1022 old_data = comp_data[data['nature_ID']] 1023 # normalize INN 1024 if old_data['inn_name'] == u'': 1025 old_data['inn_name'] = data['inn_name'] 1026 if data['inn_name'] == u'': 1027 data['inn_name'] = old_data['inn_name'] 1028 # normalize molecule 1029 if old_data['molecule_name'] == u'': 1030 old_data['molecule_name'] = data['molecule_name'] 1031 if data['molecule_name'] == u'': 1032 data['molecule_name'] = old_data['molecule_name'] 1033 # FT: transformed form 1034 # SA: active substance 1035 # it would be preferable to use the SA record because that's what's *actually* 1036 # contained in the drug, however FreeDiams does not list the amount thereof 1037 # (rather that of the INN) 1038 if data['nature'] == u'FT': 1039 comp_data[data['nature_ID']] = data 1040 else: 1041 comp_data[data['nature_ID']] = old_data 1042 1043 # or create new record 1044 except KeyError: 1045 comp_data[data['nature_ID']] = data 1046 1047 # actually create components from (possibly merged) composition records 1048 for key, data in comp_data.items(): 1049 new_drug.add_component ( 1050 substance = data['substance'], 1051 atc = None, 1052 amount = data['amount'], 1053 unit = data['unit'] 1054 )
1055 #============================================================
1056 -class cGelbeListeWindowsInterface(cDrugDataSourceInterface):
1057 """Support v8.2 CSV file interface only.""" 1058 1059 version = u'Gelbe Liste/MMI v8.2 interface' 1060 default_encoding = 'cp1250' 1061 bdt_line_template = u'%03d6210#%s\r\n' # Medikament verordnet auf Kassenrezept 1062 bdt_line_base_length = 8 1063 #--------------------------------------------------------
1064 - def __init__(self):
1065 1066 cDrugDataSourceInterface.__init__(self) 1067 1068 _log.info(u'%s (native Windows)', cGelbeListeWindowsInterface.version) 1069 1070 self.path_to_binary = r'C:\Programme\MMI PHARMINDEX\glwin.exe' 1071 self.args = r'-KEEPBACKGROUND -PRESCRIPTIONFILE %s -CLOSETOTRAY' 1072 1073 paths = gmTools.gmPaths() 1074 1075 self.default_csv_filename = os.path.join(paths.home_dir, '.gnumed', 'tmp', 'rezept.txt') 1076 self.default_csv_filename_arg = os.path.join(paths.home_dir, '.gnumed', 'tmp') 1077 self.interactions_filename = os.path.join(paths.home_dir, '.gnumed', 'tmp', 'gm2mmi.bdt') 1078 self.data_date_filename = r'C:\Programme\MMI PHARMINDEX\datadate.txt' 1079 1080 self.__data_date = None 1081 self.__online_update_date = None
1082 1083 # use adjusted config.dat 1084 #--------------------------------------------------------
1085 - def get_data_source_version(self, force_reload=False):
1086 1087 if self.__data_date is not None: 1088 if not force_reload: 1089 return { 1090 'data': self.__data_date, 1091 'online_update': self.__online_update_date 1092 } 1093 try: 1094 open(self.data_date_filename, 'wb').close() 1095 except StandardError: 1096 _log.error('problem querying the MMI drug database for version information') 1097 _log.exception('cannot create MMI drug database version file [%s]', self.data_date_filename) 1098 self.__data_date = None 1099 self.__online_update_date = None 1100 return { 1101 'data': u'?', 1102 'online_update': u'?' 1103 } 1104 1105 cmd = u'%s -DATADATE' % self.path_to_binary 1106 if not gmShellAPI.run_command_in_shell(command = cmd, blocking = True): 1107 _log.error('problem querying the MMI drug database for version information') 1108 self.__data_date = None 1109 self.__online_update_date = None 1110 return { 1111 'data': u'?', 1112 'online_update': u'?' 1113 } 1114 1115 try: 1116 version_file = open(self.data_date_filename, 'rU') 1117 except StandardError: 1118 _log.error('problem querying the MMI drug database for version information') 1119 _log.exception('cannot open MMI drug database version file [%s]', self.data_date_filename) 1120 self.__data_date = None 1121 self.__online_update_date = None 1122 return { 1123 'data': u'?', 1124 'online_update': u'?' 1125 } 1126 1127 self.__data_date = version_file.readline()[:10] 1128 self.__online_update_date = version_file.readline()[:10] 1129 version_file.close() 1130 1131 return { 1132 'data': self.__data_date, 1133 'online_update': self.__online_update_date 1134 }
1135 #--------------------------------------------------------
1136 - def create_data_source_entry(self):
1137 versions = self.get_data_source_version() 1138 1139 return create_data_source ( 1140 long_name = u'Medikamentendatenbank "mmi PHARMINDEX" (Gelbe Liste)', 1141 short_name = u'GL/MMI', 1142 version = u'Daten: %s, Preise (Onlineupdate): %s' % (versions['data'], versions['online_update']), 1143 source = u'Medizinische Medien Informations GmbH, Am Forsthaus Gravenbruch 7, 63263 Neu-Isenburg', 1144 language = u'de' 1145 )
1146 #--------------------------------------------------------
1147 - def switch_to_frontend(self, blocking=False, cmd=None):
1148 1149 try: 1150 # must make sure csv file exists 1151 open(self.default_csv_filename, 'wb').close() 1152 except IOError: 1153 _log.exception('problem creating GL/MMI <-> GNUmed exchange file') 1154 return False 1155 1156 if cmd is None: 1157 cmd = (u'%s %s' % (self.path_to_binary, self.args)) % self.default_csv_filename_arg 1158 1159 if os.name == 'nt': 1160 blocking = True 1161 if not gmShellAPI.run_command_in_shell(command = cmd, blocking = blocking): 1162 _log.error('problem switching to the MMI drug database') 1163 # apparently on the first call MMI does not 1164 # consistently return 0 on success 1165 # return False 1166 1167 return True
1168 #--------------------------------------------------------
1169 - def __let_user_select_drugs(self):
1170 1171 # better to clean up interactions file 1172 open(self.interactions_filename, 'wb').close() 1173 1174 if not self.switch_to_frontend(blocking = True): 1175 return None 1176 1177 return cGelbeListeCSVFile(filename = self.default_csv_filename)
1178 #--------------------------------------------------------
1179 - def import_drugs_as_substances(self):
1180 1181 selected_drugs = self.__let_user_select_drugs() 1182 if selected_drugs is None: 1183 return None 1184 1185 new_substances = [] 1186 1187 for drug in selected_drugs: 1188 atc = None # hopefully MMI eventually supports atc-per-substance in a drug... 1189 if len(drug['wirkstoffe']) == 1: 1190 atc = drug['atc'] 1191 for wirkstoff in drug['wirkstoffe']: 1192 new_substances.append(create_consumable_substance(substance = wirkstoff, atc = atc, amount = amount, unit = unit)) 1193 1194 selected_drugs.close() 1195 1196 return new_substances
1197 #--------------------------------------------------------
1198 - def import_drugs(self):
1199 1200 selected_drugs = self.__let_user_select_drugs() 1201 if selected_drugs is None: 1202 return None 1203 1204 data_src_pk = self.create_data_source_entry() 1205 1206 new_drugs = [] 1207 new_substances = [] 1208 1209 for entry in selected_drugs: 1210 1211 _log.debug('importing drug: %s %s', entry['name'], entry['darreichungsform']) 1212 1213 if entry[u'hilfsmittel']: 1214 _log.debug('skipping Hilfsmittel') 1215 continue 1216 1217 if entry[u'erstattbares_medizinprodukt']: 1218 _log.debug('skipping sonstiges Medizinprodukt') 1219 continue 1220 1221 # create branded drug (or get it if it already exists) 1222 drug = create_branded_drug(brand_name = entry['name'], preparation = entry['darreichungsform']) 1223 if drug is None: 1224 drug = get_drug_by_brand(brand_name = entry['name'], preparation = entry['darreichungsform']) 1225 new_drugs.append(drug) 1226 1227 # update fields 1228 drug['is_fake_brand'] = False 1229 drug['atc'] = entry['atc'] 1230 drug['external_code_type'] = u'DE-PZN' 1231 drug['external_code'] = entry['pzn'] 1232 drug['fk_data_source'] = data_src_pk 1233 drug.save() 1234 1235 # add components to brand 1236 atc = None # hopefully MMI eventually supports atc-per-substance in a drug... 1237 if len(entry['wirkstoffe']) == 1: 1238 atc = entry['atc'] 1239 for wirkstoff in entry['wirkstoffe']: 1240 drug.add_component(substance = wirkstoff, atc = atc) 1241 1242 # create as consumable substances, too 1243 atc = None # hopefully MMI eventually supports atc-per-substance in a drug... 1244 if len(entry['wirkstoffe']) == 1: 1245 atc = entry['atc'] 1246 for wirkstoff in entry['wirkstoffe']: 1247 new_substances.append(create_consumable_substance(substance = wirkstoff, atc = atc, amount = amount, unit = unit)) 1248 1249 return new_drugs, new_substances
1250 #--------------------------------------------------------
1251 - def check_interactions(self, drug_ids_list=None, substances=None):
1252 """For this to work the BDT interaction check must be configured in the MMI.""" 1253 1254 if drug_ids_list is None: 1255 if substances is None: 1256 return 1257 if len(substances) < 2: 1258 return 1259 drug_ids_list = [ (s.external_code_type, s.external_code) for s in substances ] 1260 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')] 1261 1262 else: 1263 if len(drug_ids_list) < 2: 1264 return 1265 1266 if drug_ids_list < 2: 1267 return 1268 1269 bdt_file = codecs.open(filename = self.interactions_filename, mode = 'wb', encoding = cGelbeListeWindowsInterface.default_encoding) 1270 1271 for pzn in drug_ids_list: 1272 pzn = pzn.strip() 1273 lng = cGelbeListeWindowsInterface.bdt_line_base_length + len(pzn) 1274 bdt_file.write(cGelbeListeWindowsInterface.bdt_line_template % (lng, pzn)) 1275 1276 bdt_file.close() 1277 1278 self.switch_to_frontend(blocking = True)
1279 #--------------------------------------------------------
1280 - def show_info_on_drug(self, drug=None):
1281 self.switch_to_frontend(blocking = True)
1282 #--------------------------------------------------------
1283 - def show_info_on_substance(self, substance=None):
1284 1285 cmd = None 1286 1287 if substance.external_code_type == u'DE-PZN': 1288 cmd = u'%s -PZN %s' % (self.path_to_binary, substance.external_code) 1289 1290 if cmd is None: 1291 name = gmTools.coalesce ( 1292 substance['brand'], 1293 substance['substance'] 1294 ) 1295 cmd = u'%s -NAME %s' % (self.path_to_binary, name) 1296 1297 # better to clean up interactions file 1298 open(self.interactions_filename, 'wb').close() 1299 1300 self.switch_to_frontend(cmd = cmd)
1301 #============================================================
1302 -class cGelbeListeWineInterface(cGelbeListeWindowsInterface):
1303
1304 - def __init__(self):
1305 cGelbeListeWindowsInterface.__init__(self) 1306 1307 _log.info(u'%s (WINE extension)', cGelbeListeWindowsInterface.version) 1308 1309 # FIXME: if -CLOSETOTRAY is used GNUmed cannot detect the end of MMI 1310 self.path_to_binary = r'wine "C:\Programme\MMI PHARMINDEX\glwin.exe"' 1311 self.args = r'"-PRESCRIPTIONFILE %s -KEEPBACKGROUND"' 1312 1313 paths = gmTools.gmPaths() 1314 1315 self.default_csv_filename = os.path.join(paths.home_dir, '.wine', 'drive_c', 'windows', 'temp', 'mmi2gm.csv') 1316 self.default_csv_filename_arg = r'c:\windows\temp\mmi2gm.csv' 1317 self.interactions_filename = os.path.join(paths.home_dir, '.wine', 'drive_c', 'windows', 'temp', 'gm2mmi.bdt') 1318 self.data_date_filename = os.path.join(paths.home_dir, '.wine', 'drive_c', 'Programme', 'MMI PHARMINDEX', 'datadate.txt')
1319 #============================================================
1320 -class cIfapInterface(cDrugDataSourceInterface):
1321 """empirical CSV interface""" 1322
1323 - def __init__(self):
1324 pass
1325
1326 - def print_transfer_file(self, filename=None):
1327 1328 try: 1329 csv_file = open(filename, 'rb') # FIXME: encoding ? 1330 except: 1331 _log.exception('cannot access [%s]', filename) 1332 csv_file = None 1333 1334 field_names = u'PZN Handelsname Form Abpackungsmenge Einheit Preis1 Hersteller Preis2 rezeptpflichtig Festbetrag Packungszahl Packungsgr\xf6\xdfe'.split() 1335 1336 if csv_file is None: 1337 return False 1338 1339 csv_lines = csv.DictReader ( 1340 csv_file, 1341 fieldnames = field_names, 1342 delimiter = ';' 1343 ) 1344 1345 for line in csv_lines: 1346 print "--------------------------------------------------------------------"[:31] 1347 for key in field_names: 1348 tmp = ('%s ' % key)[:30] 1349 print '%s: %s' % (tmp, line[key]) 1350 1351 csv_file.close()
1352 1353 # narr = u'%sx %s %s %s (\u2258 %s %s) von %s (%s)' % ( 1354 # line['Packungszahl'].strip(), 1355 # line['Handelsname'].strip(), 1356 # line['Form'].strip(), 1357 # line[u'Packungsgr\xf6\xdfe'].strip(), 1358 # line['Abpackungsmenge'].strip(), 1359 # line['Einheit'].strip(), 1360 # line['Hersteller'].strip(), 1361 # line['PZN'].strip() 1362 # ) 1363 #============================================================ 1364 drug_data_source_interfaces = { 1365 'Deutschland: Gelbe Liste/MMI (Windows)': cGelbeListeWindowsInterface, 1366 'Deutschland: Gelbe Liste/MMI (WINE)': cGelbeListeWineInterface, 1367 'FreeDiams (FR, US, CA, ZA)': cFreeDiamsInterface 1368 } 1369 1370 #============================================================ 1371 #============================================================ 1372 # substances in use across all patients 1373 #------------------------------------------------------------ 1374 _SQL_get_consumable_substance = u""" 1375 SELECT *, xmin 1376 FROM ref.consumable_substance 1377 WHERE %s 1378 """ 1379
1380 -class cConsumableSubstance(gmBusinessDBObject.cBusinessDBObject):
1381 1382 _cmd_fetch_payload = _SQL_get_consumable_substance % u"pk = %s" 1383 _cmds_store_payload = [ 1384 u"""UPDATE ref.consumable_substance SET 1385 description = %(description)s, 1386 atc_code = gm.nullify_empty_string(%(atc_code)s), 1387 amount = %(amount)s, 1388 unit = gm.nullify_empty_string(%(unit)s) 1389 WHERE 1390 pk = %(pk)s 1391 AND 1392 xmin = %(xmin)s 1393 AND 1394 -- must not currently be used with a patient directly 1395 NOT EXISTS ( 1396 SELECT 1 1397 FROM clin.substance_intake 1398 WHERE 1399 fk_drug_component IS NULL 1400 AND 1401 fk_substance = %(pk)s 1402 LIMIT 1 1403 ) 1404 AND 1405 -- must not currently be used with a patient indirectly, either 1406 NOT EXISTS ( 1407 SELECT 1 1408 FROM clin.substance_intake 1409 WHERE 1410 fk_drug_component IS NOT NULL 1411 AND 1412 fk_drug_component = ( 1413 SELECT r_ls2b.pk 1414 FROM ref.lnk_substance2brand r_ls2b 1415 WHERE fk_substance = %(pk)s 1416 ) 1417 LIMIT 1 1418 ) 1419 -- -- must not currently be used with a branded drug 1420 -- -- (but this would make it rather hard fixing branded drugs which contain only this substance) 1421 -- NOT EXISTS ( 1422 -- SELECT 1 1423 -- FROM ref.lnk_substance2brand 1424 -- WHERE fk_substance = %(pk)s 1425 -- LIMIT 1 1426 -- ) 1427 RETURNING 1428 xmin 1429 """ 1430 ] 1431 _updatable_fields = [ 1432 u'description', 1433 u'atc_code', 1434 u'amount', 1435 u'unit' 1436 ] 1437 #--------------------------------------------------------
1438 - def save_payload(self, conn=None):
1439 success, data = super(self.__class__, self).save_payload(conn = conn) 1440 1441 if not success: 1442 return (success, data) 1443 1444 if self._payload[self._idx['atc_code']] is not None: 1445 atc = self._payload[self._idx['atc_code']].strip() 1446 if atc != u'': 1447 gmATC.propagate_atc ( 1448 substance = self._payload[self._idx['description']].strip(), 1449 atc = atc 1450 ) 1451 1452 return (success, data)
1453 #-------------------------------------------------------- 1454 # properties 1455 #--------------------------------------------------------
1456 - def _get_is_in_use_by_patients(self):
1457 cmd = u""" 1458 SELECT 1459 EXISTS ( 1460 SELECT 1 1461 FROM clin.substance_intake 1462 WHERE 1463 fk_drug_component IS NULL 1464 AND 1465 fk_substance = %(pk)s 1466 LIMIT 1 1467 ) OR EXISTS ( 1468 SELECT 1 1469 FROM clin.substance_intake 1470 WHERE 1471 fk_drug_component IS NOT NULL 1472 AND 1473 fk_drug_component IN ( 1474 SELECT r_ls2b.pk 1475 FROM ref.lnk_substance2brand r_ls2b 1476 WHERE fk_substance = %(pk)s 1477 ) 1478 LIMIT 1 1479 )""" 1480 args = {'pk': self.pk_obj} 1481 1482 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False) 1483 return rows[0][0]
1484 1485 is_in_use_by_patients = property(_get_is_in_use_by_patients, lambda x:x) 1486 #--------------------------------------------------------
1487 - def _get_is_drug_component(self):
1488 cmd = u""" 1489 SELECT EXISTS ( 1490 SELECT 1 1491 FROM ref.lnk_substance2brand 1492 WHERE fk_substance = %(pk)s 1493 LIMIT 1 1494 )""" 1495 args = {'pk': self.pk_obj} 1496 1497 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False) 1498 return rows[0][0]
1499 1500 is_drug_component = property(_get_is_drug_component, lambda x:x)
1501 #------------------------------------------------------------
1502 -def get_consumable_substances(order_by=None):
1503 if order_by is None: 1504 order_by = u'true' 1505 else: 1506 order_by = u'true ORDER BY %s' % order_by 1507 cmd = _SQL_get_consumable_substance % order_by 1508 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = True) 1509 return [ cConsumableSubstance(row = {'data': r, 'idx': idx, 'pk_field': 'pk'}) for r in rows ]
1510 #------------------------------------------------------------
1511 -def create_consumable_substance(substance=None, atc=None, amount=None, unit=None):
1512 1513 substance = substance 1514 if atc is not None: 1515 atc = atc.strip() 1516 1517 converted, amount = gmTools.input2decimal(amount) 1518 if not converted: 1519 raise ValueError('<amount> must be a number: %s (%s)', amount, type(amount)) 1520 1521 args = { 1522 'desc': substance.strip(), 1523 'amount': amount, 1524 'unit': unit.strip(), 1525 'atc': atc 1526 } 1527 cmd = u""" 1528 SELECT pk FROM ref.consumable_substance 1529 WHERE 1530 lower(description) = lower(%(desc)s) 1531 AND 1532 amount = %(amount)s 1533 AND 1534 unit = %(unit)s 1535 """ 1536 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}]) 1537 1538 if len(rows) == 0: 1539 cmd = u""" 1540 INSERT INTO ref.consumable_substance (description, atc_code, amount, unit) VALUES ( 1541 %(desc)s, 1542 gm.nullify_empty_string(%(atc)s), 1543 %(amount)s, 1544 gm.nullify_empty_string(%(unit)s) 1545 ) RETURNING pk""" 1546 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True, get_col_idx = False) 1547 1548 gmATC.propagate_atc(substance = substance, atc = atc) 1549 1550 return cConsumableSubstance(aPK_obj = rows[0]['pk'])
1551 #------------------------------------------------------------
1552 -def delete_consumable_substance(substance=None):
1553 args = {'pk': substance} 1554 cmd = u""" 1555 DELETE FROM ref.consumable_substance 1556 WHERE 1557 pk = %(pk)s 1558 AND 1559 1560 -- must not currently be used with a patient 1561 NOT EXISTS ( 1562 SELECT 1 1563 FROM clin.v_pat_substance_intake 1564 WHERE pk_substance = %(pk)s 1565 LIMIT 1 1566 ) 1567 AND 1568 1569 -- must not currently be used with a branded drug 1570 NOT EXISTS ( 1571 SELECT 1 1572 FROM ref.lnk_substance2brand 1573 WHERE fk_substance = %(pk)s 1574 LIMIT 1 1575 )""" 1576 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}]) 1577 return True
1578 #------------------------------------------------------------
1579 -class cSubstanceMatchProvider(gmMatchProvider.cMatchProvider_SQL2):
1580 1581 _pattern = regex.compile(r'^\D+\s*\d+$', regex.UNICODE | regex.LOCALE) 1582 _query1 = u""" 1583 SELECT 1584 pk::text, 1585 (description || ' ' || amount || ' ' || unit) as subst 1586 FROM ref.consumable_substance 1587 WHERE description %(fragment_condition)s 1588 ORDER BY subst 1589 LIMIT 50""" 1590 _query2 = u""" 1591 SELECT 1592 pk::text, 1593 (description || ' ' || amount || ' ' || unit) as subst 1594 FROM ref.consumable_substance 1595 WHERE 1596 %(fragment_condition)s 1597 ORDER BY subst 1598 LIMIT 50""" 1599 1600 #--------------------------------------------------------
1601 - def getMatchesByPhrase(self, aFragment):
1602 """Return matches for aFragment at start of phrases.""" 1603 1604 if cSubstanceMatchProvider._pattern.match(aFragment): 1605 self._queries = [cSubstanceMatchProvider._query2] 1606 fragment_condition = """description ILIKE %(desc)s 1607 AND 1608 amount::text ILIKE %(amount)s""" 1609 self._args['desc'] = u'%s%%' % regex.sub(r'\s*\d+$', u'', aFragment) 1610 self._args['amount'] = u'%s%%' % regex.sub(r'^\D+\s*', u'', aFragment) 1611 else: 1612 self._queries = [cSubstanceMatchProvider._query1] 1613 fragment_condition = u"ILIKE %(fragment)s" 1614 self._args['fragment'] = u"%s%%" % aFragment 1615 1616 return self._find_matches(fragment_condition)
1617 #--------------------------------------------------------
1618 - def getMatchesByWord(self, aFragment):
1619 """Return matches for aFragment at start of words inside phrases.""" 1620 1621 if cSubstanceMatchProvider._pattern.match(aFragment): 1622 self._queries = [cSubstanceMatchProvider._query2] 1623 1624 desc = regex.sub(r'\s*\d+$', u'', aFragment) 1625 desc = gmPG2.sanitize_pg_regex(expression = desc, escape_all = False) 1626 1627 fragment_condition = """description ~* %(desc)s 1628 AND 1629 amount::text ILIKE %(amount)s""" 1630 1631 self._args['desc'] = u"( %s)|(^%s)" % (desc, desc) 1632 self._args['amount'] = u'%s%%' % regex.sub(r'^\D+\s*', u'', aFragment) 1633 else: 1634 self._queries = [cSubstanceMatchProvider._query1] 1635 fragment_condition = u"~* %(fragment)s" 1636 aFragment = gmPG2.sanitize_pg_regex(expression = aFragment, escape_all = False) 1637 self._args['fragment'] = u"( %s)|(^%s)" % (aFragment, aFragment) 1638 1639 return self._find_matches(fragment_condition)
1640 #--------------------------------------------------------
1641 - def getMatchesBySubstr(self, aFragment):
1642 """Return matches for aFragment as a true substring.""" 1643 1644 if cSubstanceMatchProvider._pattern.match(aFragment): 1645 self._queries = [cSubstanceMatchProvider._query2] 1646 fragment_condition = """description ILIKE %(desc)s 1647 AND 1648 amount::text ILIKE %(amount)s""" 1649 self._args['desc'] = u'%%%s%%' % regex.sub(r'\s*\d+$', u'', aFragment) 1650 self._args['amount'] = u'%s%%' % regex.sub(r'^\D+\s*', u'', aFragment) 1651 else: 1652 self._queries = [cSubstanceMatchProvider._query1] 1653 fragment_condition = u"ILIKE %(fragment)s" 1654 self._args['fragment'] = u"%%%s%%" % aFragment 1655 1656 return self._find_matches(fragment_condition)
1657 #============================================================
1658 -class cSubstanceIntakeEntry(gmBusinessDBObject.cBusinessDBObject):
1659 """Represents a substance currently taken by a patient.""" 1660 1661 _cmd_fetch_payload = u"SELECT * FROM clin.v_pat_substance_intake WHERE pk_substance_intake = %s" 1662 _cmds_store_payload = [ 1663 u"""UPDATE clin.substance_intake SET 1664 clin_when = %(started)s, 1665 discontinued = %(discontinued)s, 1666 discontinue_reason = gm.nullify_empty_string(%(discontinue_reason)s), 1667 schedule = gm.nullify_empty_string(%(schedule)s), 1668 aim = gm.nullify_empty_string(%(aim)s), 1669 narrative = gm.nullify_empty_string(%(notes)s), 1670 intake_is_approved_of = %(intake_is_approved_of)s, 1671 fk_episode = %(pk_episode)s, 1672 1673 preparation = ( 1674 case 1675 when %(pk_brand)s is NULL then %(preparation)s 1676 else NULL 1677 end 1678 )::text, 1679 1680 is_long_term = ( 1681 case 1682 when ( 1683 (%(is_long_term)s is False) 1684 and 1685 (%(duration)s is NULL) 1686 ) is True then null 1687 else %(is_long_term)s 1688 end 1689 )::boolean, 1690 1691 duration = ( 1692 case 1693 when %(is_long_term)s is True then null 1694 else %(duration)s 1695 end 1696 )::interval 1697 WHERE 1698 pk = %(pk_substance_intake)s 1699 AND 1700 xmin = %(xmin_substance_intake)s 1701 RETURNING 1702 xmin as xmin_substance_intake 1703 """ 1704 ] 1705 _updatable_fields = [ 1706 u'started', 1707 u'discontinued', 1708 u'discontinue_reason', 1709 u'preparation', 1710 u'intake_is_approved_of', 1711 u'schedule', 1712 u'duration', 1713 u'aim', 1714 u'is_long_term', 1715 u'notes', 1716 u'pk_episode' 1717 ] 1718 #--------------------------------------------------------
1719 - def format(self, left_margin=0, date_format='%Y %B %d', one_line=True, allergy=None, show_all_brand_components=False):
1720 if one_line: 1721 return self.format_as_one_line(left_margin = left_margin, date_format = date_format) 1722 1723 return self.format_as_multiple_lines ( 1724 left_margin = left_margin, 1725 date_format = date_format, 1726 allergy = allergy, 1727 show_all_brand_components = show_all_brand_components 1728 )
1729 #--------------------------------------------------------
1730 - def format_as_one_line(self, left_margin=0, date_format='%Y %B %d'):
1731 1732 if self._payload[self._idx['duration']] is None: 1733 duration = gmTools.bool2subst ( 1734 self._payload[self._idx['is_long_term']], 1735 _('long-term'), 1736 _('short-term'), 1737 _('?short-term') 1738 ) 1739 else: 1740 duration = gmDateTime.format_interval ( 1741 self._payload[self._idx['duration']], 1742 accuracy_wanted = gmDateTime.acc_days 1743 ) 1744 1745 line = u'%s%s (%s %s): %s %s%s %s (%s)' % ( 1746 u' ' * left_margin, 1747 self._payload[self._idx['started']].strftime(date_format), 1748 gmTools.u_right_arrow, 1749 duration, 1750 self._payload[self._idx['substance']], 1751 self._payload[self._idx['amount']], 1752 self._payload[self._idx['unit']], 1753 self._payload[self._idx['preparation']], 1754 gmTools.bool2subst(self._payload[self._idx['is_currently_active']], _('ongoing'), _('inactive'), _('?ongoing')) 1755 ) 1756 1757 return line
1758 #--------------------------------------------------------
1759 - def format_as_multiple_lines(self, left_margin=0, date_format='%Y %B %d', allergy=None, show_all_brand_components=False):
1760 1761 txt = _('Substance intake entry (%s, %s) [#%s] \n') % ( 1762 gmTools.bool2subst ( 1763 boolean = self._payload[self._idx['is_currently_active']], 1764 true_return = gmTools.bool2subst ( 1765 boolean = self._payload[self._idx['seems_inactive']], 1766 true_return = _('active, needs check'), 1767 false_return = _('active'), 1768 none_return = _('assumed active') 1769 ), 1770 false_return = _('inactive') 1771 ), 1772 gmTools.bool2subst ( 1773 boolean = self._payload[self._idx['intake_is_approved_of']], 1774 true_return = _('approved'), 1775 false_return = _('unapproved') 1776 ), 1777 self._payload[self._idx['pk_substance_intake']] 1778 ) 1779 1780 if allergy is not None: 1781 certainty = gmTools.bool2subst(allergy['definite'], _('definite'), _('suspected')) 1782 txt += u'\n' 1783 txt += u' !! ---- Cave ---- !!\n' 1784 txt += u' %s (%s): %s (%s)\n' % ( 1785 allergy['l10n_type'], 1786 certainty, 1787 allergy['descriptor'], 1788 gmTools.coalesce(allergy['reaction'], u'')[:40] 1789 ) 1790 txt += u'\n' 1791 1792 txt += u' ' + _('Substance: %s [#%s]\n') % (self._payload[self._idx['substance']], self._payload[self._idx['pk_substance']]) 1793 txt += u' ' + _('Preparation: %s\n') % self._payload[self._idx['preparation']] 1794 txt += u' ' + _('Amount per dose: %s %s') % (self._payload[self._idx['amount']], self._payload[self._idx['unit']]) 1795 if self.ddd is not None: 1796 txt += u' (DDD: %s %s)' % (self.ddd['ddd'], self.ddd['unit']) 1797 txt += u'\n' 1798 txt += gmTools.coalesce(self._payload[self._idx['atc_substance']], u'', _(' ATC (substance): %s\n')) 1799 1800 txt += u'\n' 1801 1802 txt += gmTools.coalesce ( 1803 self._payload[self._idx['brand']], 1804 u'', 1805 _(' Brand name: %%s [#%s]\n') % self._payload[self._idx['pk_brand']] 1806 ) 1807 txt += gmTools.coalesce(self._payload[self._idx['atc_brand']], u'', _(' ATC (brand): %s\n')) 1808 if show_all_brand_components and (self._payload[self._idx['pk_brand']] is not None): 1809 brand = self.containing_drug 1810 if len(brand['pk_substances']) > 1: 1811 for comp in brand['components']: 1812 if comp.startswith(self._payload[self._idx['substance']] + u'::'): 1813 continue 1814 txt += _(' Other component: %s\n') % comp 1815 1816 txt += u'\n' 1817 1818 txt += gmTools.coalesce(self._payload[self._idx['schedule']], u'', _(' Regimen: %s\n')) 1819 1820 if self._payload[self._idx['is_long_term']]: 1821 duration = u' %s %s' % (gmTools.u_right_arrow, gmTools.u_infinity) 1822 else: 1823 if self._payload[self._idx['duration']] is None: 1824 duration = u'' 1825 else: 1826 duration = u' %s %s' % (gmTools.u_right_arrow, gmDateTime.format_interval(self._payload[self._idx['duration']], gmDateTime.acc_days)) 1827 1828 txt += _(' Started %s%s%s\n') % ( 1829 gmDateTime.pydt_strftime ( 1830 self._payload[self._idx['started']], 1831 format = date_format, 1832 accuracy = gmDateTime.acc_days 1833 ), 1834 duration, 1835 gmTools.bool2subst(self._payload[self._idx['is_long_term']], _(' (long-term)'), _(' (short-term)'), u'') 1836 ) 1837 1838 if self._payload[self._idx['discontinued']] is not None: 1839 txt += _(' Discontinued %s\n') % ( 1840 gmDateTime.pydt_strftime ( 1841 self._payload[self._idx['discontinued']], 1842 format = date_format, 1843 accuracy = gmDateTime.acc_days 1844 ) 1845 ) 1846 txt += _(' Reason: %s\n') % self._payload[self._idx['discontinue_reason']] 1847 1848 txt += u'\n' 1849 1850 txt += gmTools.coalesce(self._payload[self._idx['aim']], u'', _(' Aim: %s\n')) 1851 txt += gmTools.coalesce(self._payload[self._idx['episode']], u'', _(' Episode: %s\n')) 1852 txt += gmTools.coalesce(self._payload[self._idx['health_issue']], u'', _(' Health issue: %s\n')) 1853 txt += gmTools.coalesce(self._payload[self._idx['notes']], u'', _(' Advice: %s\n')) 1854 1855 txt += u'\n' 1856 1857 txt += _(u'Revision: #%(row_ver)s, %(mod_when)s by %(mod_by)s.') % { 1858 'row_ver': self._payload[self._idx['row_version']], 1859 'mod_when': gmDateTime.pydt_strftime(self._payload[self._idx['modified_when']]), 1860 'mod_by': self._payload[self._idx['modified_by']] 1861 } 1862 1863 return txt
1864 #--------------------------------------------------------
1865 - def turn_into_allergy(self, encounter_id=None, allergy_type='allergy'):
1866 allg = gmAllergy.create_allergy ( 1867 allergene = self._payload[self._idx['substance']], 1868 allg_type = allergy_type, 1869 episode_id = self._payload[self._idx['pk_episode']], 1870 encounter_id = encounter_id 1871 ) 1872 allg['substance'] = gmTools.coalesce ( 1873 self._payload[self._idx['brand']], 1874 self._payload[self._idx['substance']] 1875 ) 1876 allg['reaction'] = self._payload[self._idx['discontinue_reason']] 1877 allg['atc_code'] = gmTools.coalesce(self._payload[self._idx['atc_substance']], self._payload[self._idx['atc_brand']]) 1878 if self._payload[self._idx['external_code_brand']] is not None: 1879 allg['substance_code'] = u'%s::::%s' % (self._payload[self._idx['external_code_type_brand']], self._payload[self._idx['external_code_brand']]) 1880 1881 if self._payload[self._idx['pk_brand']] is None: 1882 allg['generics'] = self._payload[self._idx['substance']] 1883 else: 1884 comps = [ c['substance'] for c in self.containing_drug.components ] 1885 if len(comps) == 0: 1886 allg['generics'] = self._payload[self._idx['substance']] 1887 else: 1888 allg['generics'] = u'; '.join(comps) 1889 1890 allg.save() 1891 return allg
1892 #-------------------------------------------------------- 1893 # properties 1894 #--------------------------------------------------------
1895 - def _get_ddd(self):
1896 1897 try: self.__ddd 1898 except AttributeError: self.__ddd = None 1899 1900 if self.__ddd is not None: 1901 return self.__ddd 1902 1903 if self._payload[self._idx['atc_substance']] is not None: 1904 ddd = gmATC.atc2ddd(atc = self._payload[self._idx['atc_substance']]) 1905 if len(ddd) != 0: 1906 self.__ddd = ddd[0] 1907 else: 1908 if self._payload[self._idx['atc_brand']] is not None: 1909 ddd = gmATC.atc2ddd(atc = self._payload[self._idx['atc_brand']]) 1910 if len(ddd) != 0: 1911 self.__ddd = ddd[0] 1912 1913 return self.__ddd
1914 1915 ddd = property(_get_ddd, lambda x:x) 1916 #--------------------------------------------------------
1917 - def _get_external_code(self):
1918 drug = self.containing_drug 1919 1920 if drug is None: 1921 return None 1922 1923 return drug.external_code
1924 1925 external_code = property(_get_external_code, lambda x:x) 1926 #--------------------------------------------------------
1927 - def _get_external_code_type(self):
1928 drug = self.containing_drug 1929 1930 if drug is None: 1931 return None 1932 1933 return drug.external_code_type
1934 1935 external_code_type = property(_get_external_code_type, lambda x:x) 1936 #--------------------------------------------------------
1937 - def _get_containing_drug(self):
1938 if self._payload[self._idx['pk_brand']] is None: 1939 return None 1940 1941 return cBrandedDrug(aPK_obj = self._payload[self._idx['pk_brand']])
1942 1943 containing_drug = property(_get_containing_drug, lambda x:x) 1944 #--------------------------------------------------------
1945 - def _get_parsed_schedule(self):
1946 tests = [ 1947 # lead, trail 1948 ' 1-1-1-1 ', 1949 # leading dose 1950 '1-1-1-1', 1951 '22-1-1-1', 1952 '1/3-1-1-1', 1953 '/4-1-1-1' 1954 ] 1955 pattern = "^(\d\d|/\d|\d/\d|\d)[\s-]{1,5}\d{0,2}[\s-]{1,5}\d{0,2}[\s-]{1,5}\d{0,2}$" 1956 for test in tests: 1957 print test.strip(), ":", regex.match(pattern, test.strip())
1958 #------------------------------------------------------------
1959 -def substance_intake_exists(pk_component=None, pk_substance=None, pk_identity=None):
1960 args = {'comp': pk_component, 'subst': pk_substance, 'pat': pk_identity} 1961 1962 where_clause = u""" 1963 fk_encounter IN ( 1964 SELECT pk FROM clin.encounter WHERE fk_patient = %(pat)s 1965 ) 1966 AND 1967 """ 1968 1969 if pk_substance is not None: 1970 where_clause += u'fk_substance = %(subst)s' 1971 if pk_component is not None: 1972 where_clause += u'fk_drug_component = %(comp)s' 1973 1974 cmd = u"""SELECT exists ( 1975 SELECT 1 FROM clin.substance_intake 1976 WHERE 1977 %s 1978 LIMIT 1 1979 )""" % where_clause 1980 1981 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}]) 1982 return rows[0][0]
1983 #------------------------------------------------------------
1984 -def create_substance_intake(pk_substance=None, pk_component=None, preparation=None, encounter=None, episode=None):
1985 1986 args = { 1987 'enc': encounter, 1988 'epi': episode, 1989 'comp': pk_component, 1990 'subst': pk_substance, 1991 'prep': preparation 1992 } 1993 1994 if pk_component is None: 1995 cmd = u""" 1996 INSERT INTO clin.substance_intake ( 1997 fk_encounter, 1998 fk_episode, 1999 intake_is_approved_of, 2000 fk_substance, 2001 preparation 2002 ) VALUES ( 2003 %(enc)s, 2004 %(epi)s, 2005 False, 2006 %(subst)s, 2007 %(prep)s 2008 ) 2009 RETURNING pk""" 2010 else: 2011 cmd = u""" 2012 INSERT INTO clin.substance_intake ( 2013 fk_encounter, 2014 fk_episode, 2015 intake_is_approved_of, 2016 fk_drug_component 2017 ) VALUES ( 2018 %(enc)s, 2019 %(epi)s, 2020 False, 2021 %(comp)s 2022 ) 2023 RETURNING pk""" 2024 2025 try: 2026 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True) 2027 except gmPG2.dbapi.InternalError, e: 2028 if e.pgerror is None: 2029 raise 2030 if 'prevent_duplicate_component' in e.pgerror: 2031 _log.exception('will not create duplicate substance intake entry') 2032 _log.error(e.pgerror) 2033 return None 2034 raise 2035 2036 return cSubstanceIntakeEntry(aPK_obj = rows[0][0])
2037 #------------------------------------------------------------
2038 -def delete_substance_intake(substance=None):
2039 cmd = u'delete from clin.substance_intake where pk = %(pk)s' 2040 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': {'pk': substance}}])
2041 #------------------------------------------------------------
2042 -def format_substance_intake_notes(emr=None, output_format=u'latex', table_type=u'by-brand'):
2043 2044 tex = u'\n\\noindent %s\n' % _('Additional notes') 2045 tex += u'\n' 2046 tex += u'\\noindent \\begin{tabularx}{\\textwidth}{|>{\\RaggedRight}X|l|>{\\RaggedRight}X|p{7.5cm}|}\n' 2047 tex += u'\\hline\n' 2048 tex += u'%s {\\scriptsize (%s)} & %s & %s \\tabularnewline \n' % (_('Substance'), _('Brand'), _('Strength'), _('Aim')) 2049 tex += u'\\hline\n' 2050 tex += u'%s\n' 2051 tex += u'\\end{tabularx}\n\n' 2052 2053 current_meds = emr.get_current_substance_intake ( 2054 include_inactive = False, 2055 include_unapproved = False, 2056 order_by = u'brand, substance' 2057 ) 2058 2059 # create lines 2060 lines = [] 2061 for med in current_meds: 2062 if med['brand'] is None: 2063 brand = u'' 2064 else: 2065 brand = u': {\\tiny %s}' % gmTools.tex_escape_string(med['brand']) 2066 if med['aim'] is None: 2067 aim = u'' 2068 else: 2069 aim = u'{\\scriptsize %s}' % gmTools.tex_escape_string(med['aim']) 2070 lines.append(u'%s ({\\small %s}%s) & %s%s & %s \\tabularnewline\n \\hline' % ( 2071 gmTools.tex_escape_string(med['substance']), 2072 gmTools.tex_escape_string(med['preparation']), 2073 brand, 2074 med['amount'], 2075 gmTools.tex_escape_string(med['unit']), 2076 aim 2077 )) 2078 2079 return tex % u'\n'.join(lines)
2080 2081 #------------------------------------------------------------
2082 -def format_substance_intake(emr=None, output_format=u'latex', table_type=u'by-brand'):
2083 2084 tex = u'\\noindent %s {\\tiny (%s)\\par}\n' % (_('Medication list'), _('ordered by brand')) 2085 tex += u'\n' 2086 tex += u'\\noindent \\begin{tabularx}{\\textwidth}{|>{\\RaggedRight}X|>{\\RaggedRight}X|}\n' 2087 tex += u'\\hline\n' 2088 tex += u'%s & %s \\tabularnewline \n' % (_('Drug'), _('Regimen / Advice')) 2089 tex += u'\\hline\n' 2090 tex += u'\\hline\n' 2091 tex += u'%s\n' 2092 tex += u'\\end{tabularx}\n' 2093 2094 current_meds = emr.get_current_substance_intake ( 2095 include_inactive = False, 2096 include_unapproved = False, 2097 order_by = u'brand, substance' 2098 ) 2099 2100 # aggregate data 2101 line_data = {} 2102 for med in current_meds: 2103 identifier = gmTools.coalesce(med['brand'], med['substance']) 2104 2105 try: 2106 line_data[identifier] 2107 except KeyError: 2108 line_data[identifier] = {'brand': u'', 'preparation': u'', 'schedule': u'', 'notes': [], 'strengths': []} 2109 2110 line_data[identifier]['brand'] = identifier 2111 line_data[identifier]['strengths'].append(u'%s %s%s' % (med['substance'][:20], med['amount'], med['unit'].strip())) 2112 line_data[identifier]['preparation'] = med['preparation'] 2113 line_data[identifier]['schedule'] = gmTools.coalesce(med['schedule'], u'') 2114 if med['notes'] is not None: 2115 if med['notes'] not in line_data[identifier]['notes']: 2116 line_data[identifier]['notes'].append(med['notes']) 2117 2118 # create lines 2119 already_seen = [] 2120 lines = [] 2121 line1_template = u'%s %s & %s \\tabularnewline' 2122 line2_template = u' {\\tiny %s\\par} & {\\scriptsize %s\\par} \\tabularnewline' 2123 line3_template = u' & {\\scriptsize %s\\par} \\tabularnewline' 2124 2125 for med in current_meds: 2126 identifier = gmTools.coalesce(med['brand'], med['substance']) 2127 2128 if identifier in already_seen: 2129 continue 2130 2131 already_seen.append(identifier) 2132 2133 lines.append (line1_template % ( 2134 gmTools.tex_escape_string(line_data[identifier]['brand']), 2135 gmTools.tex_escape_string(line_data[identifier]['preparation']), 2136 gmTools.tex_escape_string(line_data[identifier]['schedule']) 2137 )) 2138 2139 strengths = gmTools.tex_escape_string(u' / '.join(line_data[identifier]['strengths'])) 2140 if len(line_data[identifier]['notes']) == 0: 2141 first_note = u'' 2142 else: 2143 first_note = gmTools.tex_escape_string(line_data[identifier]['notes'][0]) 2144 lines.append(line2_template % (strengths, first_note)) 2145 if len(line_data[identifier]['notes']) > 1: 2146 for note in line_data[identifier]['notes'][1:]: 2147 lines.append(line3_template % gmTools.tex_escape_string(note)) 2148 2149 lines.append(u'\\hline') 2150 2151 return tex % u'\n'.join(lines)
2152 #============================================================ 2153 _SQL_get_drug_components = u'SELECT * FROM ref.v_drug_components WHERE %s' 2154
2155 -class cDrugComponent(gmBusinessDBObject.cBusinessDBObject):
2156 2157 _cmd_fetch_payload = _SQL_get_drug_components % u'pk_component = %s' 2158 _cmds_store_payload = [ 2159 u"""UPDATE ref.lnk_substance2brand SET 2160 fk_brand = %(pk_brand)s, 2161 fk_substance = %(pk_consumable_substance)s 2162 WHERE 2163 NOT EXISTS ( 2164 SELECT 1 2165 FROM clin.substance_intake 2166 WHERE fk_drug_component = %(pk_component)s 2167 LIMIT 1 2168 ) 2169 AND 2170 pk = %(pk_component)s 2171 AND 2172 xmin = %(xmin_lnk_substance2brand)s 2173 RETURNING 2174 xmin AS xmin_lnk_substance2brand 2175 """ 2176 ] 2177 _updatable_fields = [ 2178 u'pk_brand', 2179 u'pk_consumable_substance' 2180 ] 2181 #-------------------------------------------------------- 2182 # properties 2183 #--------------------------------------------------------
2184 - def _get_containing_drug(self):
2185 return cBrandedDrug(aPK_obj = self._payload[self._idx['pk_brand']])
2186 2187 containing_drug = property(_get_containing_drug, lambda x:x) 2188 #--------------------------------------------------------
2189 - def _get_is_in_use_by_patients(self):
2190 return self._payload[self._idx['is_in_use']]
2191 2192 is_in_use_by_patients = property(_get_is_in_use_by_patients, lambda x:x) 2193 #--------------------------------------------------------
2194 - def _get_substance(self):
2195 return cConsumableSubstance(aPK_obj = self._payload[self._idx['pk_consumable_substance']])
2196 2197 substance = property(_get_substance, lambda x:x)
2198 #------------------------------------------------------------
2199 -def get_drug_components():
2200 cmd = _SQL_get_drug_components % u'true ORDER BY brand, substance' 2201 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = True) 2202 return [ cDrugComponent(row = {'data': r, 'idx': idx, 'pk_field': 'pk_component'}) for r in rows ]
2203 #------------------------------------------------------------
2204 -class cDrugComponentMatchProvider(gmMatchProvider.cMatchProvider_SQL2):
2205 2206 _pattern = regex.compile(r'^\D+\s*\d+$', regex.UNICODE | regex.LOCALE) 2207 _query_desc_only = u""" 2208 SELECT DISTINCT ON (component) 2209 pk_component, 2210 (substance || ' ' || amount || unit || ' ' || preparation || ' (' || brand || ')') 2211 AS component 2212 FROM ref.v_drug_components 2213 WHERE 2214 substance %(fragment_condition)s 2215 OR 2216 brand %(fragment_condition)s 2217 ORDER BY component 2218 LIMIT 50""" 2219 _query_desc_and_amount = u""" 2220 2221 SELECT DISTINCT ON (component) 2222 pk_component, 2223 (substance || ' ' || amount || unit || ' ' || preparation || ' (' || brand || ')') 2224 AS component 2225 FROM ref.v_drug_components 2226 WHERE 2227 %(fragment_condition)s 2228 ORDER BY component 2229 LIMIT 50""" 2230 #--------------------------------------------------------
2231 - def getMatchesByPhrase(self, aFragment):
2232 """Return matches for aFragment at start of phrases.""" 2233 2234 if cDrugComponentMatchProvider._pattern.match(aFragment): 2235 self._queries = [cDrugComponentMatchProvider._query_desc_and_amount] 2236 fragment_condition = """(substance ILIKE %(desc)s OR brand ILIKE %(desc)s) 2237 AND 2238 amount::text ILIKE %(amount)s""" 2239 self._args['desc'] = u'%s%%' % regex.sub(r'\s*\d+$', u'', aFragment) 2240 self._args['amount'] = u'%s%%' % regex.sub(r'^\D+\s*', u'', aFragment) 2241 else: 2242 self._queries = [cDrugComponentMatchProvider._query_desc_only] 2243 fragment_condition = u"ILIKE %(fragment)s" 2244 self._args['fragment'] = u"%s%%" % aFragment 2245 2246 return self._find_matches(fragment_condition)
2247 #--------------------------------------------------------
2248 - def getMatchesByWord(self, aFragment):
2249 """Return matches for aFragment at start of words inside phrases.""" 2250 2251 if cDrugComponentMatchProvider._pattern.match(aFragment): 2252 self._queries = [cDrugComponentMatchProvider._query_desc_and_amount] 2253 2254 desc = regex.sub(r'\s*\d+$', u'', aFragment) 2255 desc = gmPG2.sanitize_pg_regex(expression = desc, escape_all = False) 2256 2257 fragment_condition = """(substance ~* %(desc)s OR brand ~* %(desc)s) 2258 AND 2259 amount::text ILIKE %(amount)s""" 2260 2261 self._args['desc'] = u"( %s)|(^%s)" % (desc, desc) 2262 self._args['amount'] = u'%s%%' % regex.sub(r'^\D+\s*', u'', aFragment) 2263 else: 2264 self._queries = [cDrugComponentMatchProvider._query_desc_only] 2265 fragment_condition = u"~* %(fragment)s" 2266 aFragment = gmPG2.sanitize_pg_regex(expression = aFragment, escape_all = False) 2267 self._args['fragment'] = u"( %s)|(^%s)" % (aFragment, aFragment) 2268 2269 return self._find_matches(fragment_condition)
2270 #--------------------------------------------------------
2271 - def getMatchesBySubstr(self, aFragment):
2272 """Return matches for aFragment as a true substring.""" 2273 2274 if cDrugComponentMatchProvider._pattern.match(aFragment): 2275 self._queries = [cDrugComponentMatchProvider._query_desc_and_amount] 2276 fragment_condition = """(substance ILIKE %(desc)s OR brand ILIKE %(desc)s) 2277 AND 2278 amount::text ILIKE %(amount)s""" 2279 self._args['desc'] = u'%%%s%%' % regex.sub(r'\s*\d+$', u'', aFragment) 2280 self._args['amount'] = u'%s%%' % regex.sub(r'^\D+\s*', u'', aFragment) 2281 else: 2282 self._queries = [cDrugComponentMatchProvider._query_desc_only] 2283 fragment_condition = u"ILIKE %(fragment)s" 2284 self._args['fragment'] = u"%%%s%%" % aFragment 2285 2286 return self._find_matches(fragment_condition)
2287 2288 #============================================================
2289 -class cBrandedDrug(gmBusinessDBObject.cBusinessDBObject):
2290 """Represents a drug as marketed by a manufacturer.""" 2291 2292 _cmd_fetch_payload = u"SELECT * FROM ref.v_branded_drugs WHERE pk_brand = %s" 2293 _cmds_store_payload = [ 2294 u"""UPDATE ref.branded_drug SET 2295 description = %(brand)s, 2296 preparation = %(preparation)s, 2297 atc_code = gm.nullify_empty_string(%(atc)s), 2298 external_code = gm.nullify_empty_string(%(external_code)s), 2299 external_code_type = gm.nullify_empty_string(%(external_code_type)s), 2300 is_fake = %(is_fake_brand)s, 2301 fk_data_source = %(pk_data_source)s 2302 WHERE 2303 pk = %(pk_brand)s 2304 AND 2305 xmin = %(xmin_branded_drug)s 2306 RETURNING 2307 xmin AS xmin_branded_drug 2308 """ 2309 ] 2310 _updatable_fields = [ 2311 u'brand', 2312 u'preparation', 2313 u'atc', 2314 u'is_fake_brand', 2315 u'external_code', 2316 u'external_code_type', 2317 u'pk_data_source' 2318 ] 2319 #--------------------------------------------------------
2320 - def save_payload(self, conn=None):
2321 success, data = super(self.__class__, self).save_payload(conn = conn) 2322 2323 if not success: 2324 return (success, data) 2325 2326 if self._payload[self._idx['atc']] is not None: 2327 atc = self._payload[self._idx['atc']].strip() 2328 if atc != u'': 2329 gmATC.propagate_atc ( 2330 substance = self._payload[self._idx['brand']].strip(), 2331 atc = atc 2332 ) 2333 2334 return (success, data)
2335 #--------------------------------------------------------
2336 - def set_substances_as_components(self, substances=None):
2337 2338 if self.is_in_use_by_patients: 2339 return False 2340 2341 pk_substances2keep = [ s['pk'] for s in substances ] 2342 args = {'brand': self._payload[self._idx['pk_brand']]} 2343 queries = [] 2344 2345 # INSERT those which are not there yet 2346 cmd = u""" 2347 INSERT INTO ref.lnk_substance2brand ( 2348 fk_brand, 2349 fk_substance 2350 ) 2351 SELECT 2352 %(brand)s, 2353 %(subst)s 2354 WHERE NOT EXISTS ( 2355 SELECT 1 2356 FROM ref.lnk_substance2brand 2357 WHERE 2358 fk_brand = %(brand)s 2359 AND 2360 fk_substance = %(subst)s 2361 )""" 2362 for pk in pk_substances2keep: 2363 args['subst'] = pk 2364 queries.append({'cmd': cmd, 'args': args}) 2365 2366 # DELETE those that don't belong anymore 2367 args['substances2keep'] = tuple(pk_substances2keep) 2368 cmd = u""" 2369 DELETE FROM ref.lnk_substance2brand 2370 WHERE 2371 fk_brand = %(brand)s 2372 AND 2373 fk_substance NOT IN %(substances2keep)s""" 2374 queries.append({'cmd': cmd, 'args': args}) 2375 2376 gmPG2.run_rw_queries(queries = queries) 2377 self.refetch_payload() 2378 2379 return True
2380 #--------------------------------------------------------
2381 - def add_component(self, substance=None, atc=None, amount=None, unit=None, pk_substance=None):
2382 2383 args = { 2384 'brand': self.pk_obj, 2385 'subst': substance, 2386 'atc': atc, 2387 'pk_subst': pk_substance 2388 } 2389 2390 if pk_substance is None: 2391 consumable = create_consumable_substance(substance = substance, atc = atc, amount = amount, unit = unit) 2392 args['pk_subst'] = consumable['pk'] 2393 2394 # already a component 2395 cmd = u""" 2396 SELECT pk_component 2397 FROM ref.v_drug_components 2398 WHERE 2399 pk_brand = %(brand)s 2400 AND 2401 (( 2402 (lower(substance) = lower(%(subst)s)) 2403 OR 2404 (lower(atc_substance) = lower(%(atc)s)) 2405 OR 2406 (pk_consumable_substance = %(pk_subst)s) 2407 ) IS TRUE) 2408 """ 2409 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False) 2410 2411 if len(rows) > 0: 2412 return 2413 2414 # create it 2415 cmd = u""" 2416 INSERT INTO ref.lnk_substance2brand (fk_brand, fk_substance) 2417 VALUES (%(brand)s, %(pk_subst)s) 2418 """ 2419 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}]) 2420 self.refetch_payload()
2421 #------------------------------------------------------------
2422 - def remove_component(self, substance=None):
2423 if len(self._payload[self._idx['components']]) == 1: 2424 _log.error('cannot remove the only component of a drug') 2425 return False 2426 2427 args = {'brand': self.pk_obj, 'comp': substance} 2428 cmd = u""" 2429 DELETE FROM ref.lnk_substance2brand 2430 WHERE 2431 fk_brand = %(brand)s 2432 AND 2433 fk_substance = %(comp)s 2434 AND 2435 NOT EXISTS ( 2436 SELECT 1 2437 FROM clin.substance_intake 2438 WHERE fk_drug_component = %(comp)s 2439 LIMIT 1 2440 ) 2441 """ 2442 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}]) 2443 self.refetch_payload() 2444 2445 return True
2446 #-------------------------------------------------------- 2447 # properties 2448 #--------------------------------------------------------
2449 - def _get_external_code(self):
2450 if self._payload[self._idx['external_code']] is None: 2451 return None 2452 2453 return self._payload[self._idx['external_code']]
2454 2455 external_code = property(_get_external_code, lambda x:x) 2456 #--------------------------------------------------------
2457 - def _get_external_code_type(self):
2458 2459 # FIXME: maybe evaluate fk_data_source ? 2460 if self._payload[self._idx['external_code_type']] is None: 2461 return None 2462 2463 return self._payload[self._idx['external_code_type']]
2464 2465 external_code_type = property(_get_external_code_type, lambda x:x) 2466 #--------------------------------------------------------
2467 - def _get_components(self):
2468 cmd = _SQL_get_drug_components % u'pk_brand = %(brand)s' 2469 args = {'brand': self._payload[self._idx['pk_brand']]} 2470 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True) 2471 return [ cDrugComponent(row = {'data': r, 'idx': idx, 'pk_field': 'pk_component'}) for r in rows ]
2472 2473 components = property(_get_components, lambda x:x) 2474 #--------------------------------------------------------
2476 if self._payload[self._idx['pk_substances']] is None: 2477 return [] 2478 cmd = _SQL_get_consumable_substance % u'pk IN %(pks)s' 2479 args = {'pks': tuple(self._payload[self._idx['pk_substances']])} 2480 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True) 2481 return [ cConsumableSubstance(row = {'data': r, 'idx': idx, 'pk_field': 'pk'}) for r in rows ]
2482 2483 components_as_substances = property(_get_components_as_substances, lambda x:x) 2484 #--------------------------------------------------------
2485 - def _get_is_vaccine(self):
2486 cmd = u'SELECT EXISTS (SELECT 1 FROM clin.vaccine WHERE fk_brand = %(fk_brand)s)' 2487 args = {'fk_brand': self._payload[self._idx['pk_brand']]} 2488 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False) 2489 return rows[0][0]
2490 2491 is_vaccine = property(_get_is_vaccine, lambda x:x) 2492 #--------------------------------------------------------
2493 - def _get_is_in_use_by_patients(self):
2494 cmd = u""" 2495 SELECT EXISTS ( 2496 SELECT 1 2497 FROM clin.substance_intake 2498 WHERE 2499 fk_drug_component IS NOT NULL 2500 AND 2501 fk_drug_component IN ( 2502 SELECT r_ls2b.pk 2503 FROM ref.lnk_substance2brand r_ls2b 2504 WHERE fk_brand = %(pk)s 2505 ) 2506 LIMIT 1 2507 )""" 2508 args = {'pk': self.pk_obj} 2509 2510 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False) 2511 return rows[0][0]
2512 2513 is_in_use_by_patients = property(_get_is_in_use_by_patients, lambda x:x)
2514 #------------------------------------------------------------
2515 -def get_branded_drugs():
2516 cmd = u'SELECT pk FROM ref.branded_drug ORDER BY description' 2517 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = False) 2518 return [ cBrandedDrug(aPK_obj = r['pk']) for r in rows ]
2519 #------------------------------------------------------------
2520 -def get_drug_by_brand(brand_name=None, preparation=None):
2521 args = {'brand': brand_name, 'prep': preparation} 2522 2523 cmd = u'SELECT pk FROM ref.branded_drug WHERE lower(description) = lower(%(brand)s) AND lower(preparation) = lower(%(prep)s)' 2524 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False) 2525 2526 if len(rows) == 0: 2527 return None 2528 2529 return cBrandedDrug(aPK_obj = rows[0]['pk'])
2530 #------------------------------------------------------------
2531 -def create_branded_drug(brand_name=None, preparation=None, return_existing=False):
2532 2533 if preparation is None: 2534 preparation = _('units') 2535 2536 if preparation.strip() == u'': 2537 preparation = _('units') 2538 2539 if return_existing: 2540 drug = get_drug_by_brand(brand_name = brand_name, preparation = preparation) 2541 if drug is not None: 2542 return drug 2543 2544 cmd = u'INSERT INTO ref.branded_drug (description, preparation) VALUES (%(brand)s, %(prep)s) RETURNING pk' 2545 args = {'brand': brand_name, 'prep': preparation} 2546 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True, get_col_idx = False) 2547 2548 return cBrandedDrug(aPK_obj = rows[0]['pk'])
2549 #------------------------------------------------------------
2550 -def delete_branded_drug(brand=None):
2551 queries = [] 2552 args = {'pk': brand} 2553 2554 # delete components 2555 cmd = u""" 2556 DELETE FROM ref.lnk_substance2brand 2557 WHERE 2558 fk_brand = %(pk)s 2559 AND 2560 NOT EXISTS ( 2561 SELECT 1 2562 FROM clin.v_pat_substance_intake 2563 WHERE pk_brand = %(pk)s 2564 LIMIT 1 2565 ) 2566 """ 2567 queries.append({'cmd': cmd, 'args': args}) 2568 2569 # delete drug 2570 cmd = u""" 2571 DELETE FROM ref.branded_drug 2572 WHERE 2573 pk = %(pk)s 2574 AND 2575 NOT EXISTS ( 2576 SELECT 1 2577 FROM clin.v_pat_substance_intake 2578 WHERE pk_brand = %(pk)s 2579 LIMIT 1 2580 ) 2581 """ 2582 queries.append({'cmd': cmd, 'args': args}) 2583 2584 gmPG2.run_rw_queries(queries = queries)
2585 #============================================================ 2586 # main 2587 #------------------------------------------------------------ 2588 if __name__ == "__main__": 2589 2590 if len(sys.argv) < 2: 2591 sys.exit() 2592 2593 if sys.argv[1] != 'test': 2594 sys.exit() 2595 2596 from Gnumed.pycommon import gmLog2 2597 from Gnumed.pycommon import gmI18N 2598 from Gnumed.business import gmPerson 2599 2600 gmI18N.activate_locale() 2601 # gmDateTime.init() 2602 #--------------------------------------------------------
2603 - def test_MMI_interface():
2604 mmi = cGelbeListeWineInterface() 2605 print mmi 2606 print "interface definition:", mmi.version 2607 print "database versions: ", mmi.get_data_source_version()
2608 #--------------------------------------------------------
2609 - def test_MMI_file():
2610 mmi_file = cGelbeListeCSVFile(filename = sys.argv[2]) 2611 for drug in mmi_file: 2612 print "-------------" 2613 print '"%s" (ATC: %s / PZN: %s)' % (drug['name'], drug['atc'], drug['pzn']) 2614 for stoff in drug['wirkstoffe']: 2615 print " Wirkstoff:", stoff 2616 raw_input() 2617 if mmi_file.has_unknown_fields is not None: 2618 print "has extra data under [%s]" % gmTools.default_csv_reader_rest_key 2619 for key in mmi_file.csv_fieldnames: 2620 print key, '->', drug[key] 2621 raw_input() 2622 mmi_file.close()
2623 #--------------------------------------------------------
2624 - def test_mmi_switch_to():
2625 mmi = cGelbeListeWineInterface() 2626 mmi.switch_to_frontend(blocking = True)
2627 #--------------------------------------------------------
2628 - def test_mmi_let_user_select_drugs():
2629 mmi = cGelbeListeWineInterface() 2630 mmi_file = mmi.__let_user_select_drugs() 2631 for drug in mmi_file: 2632 print "-------------" 2633 print '"%s" (ATC: %s / PZN: %s)' % (drug['name'], drug['atc'], drug['pzn']) 2634 for stoff in drug['wirkstoffe']: 2635 print " Wirkstoff:", stoff 2636 print drug 2637 mmi_file.close()
2638 #--------------------------------------------------------
2639 - def test_mmi_import_drugs():
2640 mmi = cGelbeListeWineInterface() 2641 mmi.import_drugs()
2642 #--------------------------------------------------------
2643 - def test_mmi_interaction_check():
2644 mmi = cGelbeListeInterface() 2645 print mmi 2646 print "interface definition:", mmi.version 2647 # Metoprolol + Hct vs Citalopram 2648 diclofenac = '7587712' 2649 phenprocoumon = '4421744' 2650 mmi.check_interactions(drug_ids_list = [diclofenac, phenprocoumon])
2651 #-------------------------------------------------------- 2652 # FreeDiams 2653 #--------------------------------------------------------
2654 - def test_fd_switch_to():
2655 gmPerson.set_active_patient(patient = gmPerson.cIdentity(aPK_obj = 12)) 2656 fd = cFreeDiamsInterface() 2657 fd.patient = gmPerson.gmCurrentPatient() 2658 # fd.switch_to_frontend(blocking = True) 2659 fd.import_fd2gm_file_as_drugs(filename = sys.argv[2])
2660 #--------------------------------------------------------
2661 - def test_fd_show_interactions():
2662 gmPerson.set_active_patient(patient = gmPerson.cIdentity(aPK_obj = 12)) 2663 fd = cFreeDiamsInterface() 2664 fd.patient = gmPerson.gmCurrentPatient() 2665 fd.check_interactions(substances = fd.patient.get_emr().get_current_substance_intake(include_unapproved = True))
2666 #-------------------------------------------------------- 2667 # generic 2668 #--------------------------------------------------------
2669 - def test_create_substance_intake():
2670 drug = create_substance_intake ( 2671 pk_component = 2, 2672 encounter = 1, 2673 episode = 1 2674 ) 2675 print drug
2676 #--------------------------------------------------------
2677 - def test_show_components():
2678 drug = cBrandedDrug(aPK_obj = sys.argv[2]) 2679 print drug 2680 print drug.components
2681 #--------------------------------------------------------
2682 - def test_get_consumable_substances():
2683 for s in get_consumable_substances(): 2684 print s
2685 #--------------------------------------------------------
2686 - def test_drug2renal_insufficiency_url():
2687 drug2renal_insufficiency_url(search_term = 'Metoprolol')
2688 #-------------------------------------------------------- 2689 # MMI/Gelbe Liste 2690 #test_MMI_interface() 2691 #test_MMI_file() 2692 #test_mmi_switch_to() 2693 #test_mmi_let_user_select_drugs() 2694 #test_mmi_import_substances() 2695 #test_mmi_import_drugs() 2696 2697 # FreeDiams 2698 test_fd_switch_to() 2699 #test_fd_show_interactions() 2700 2701 # generic 2702 #test_interaction_check() 2703 #test_create_substance_intake() 2704 #test_show_components() 2705 #test_get_consumable_substances() 2706 2707 #test_drug2renal_insufficiency_url() 2708 #============================================================ 2709