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 <IsTextual>False</IsTextual> 554 <DrugName>%s</DrugName> 555 <Drug_UID>%s</Drug_UID> 556 <Drug_UID_type>%s</Drug_UID_type> <!-- not yet supported by FreeDiams --> 557 </Prescription>""" 558 559 last_db_id = u'CA_HCDPD' 560 for intake in intakes_pooled_by_brand.values(): 561 last_db_id = gmTools.xml_escape_string(text = intake['external_code_type_brand'].replace(u'FreeDiams::', u'').split(u'::')[0]) 562 drug_snippets.append(drug_snippet % ( 563 gmTools.xml_escape_string(text = intake['brand'].strip()), 564 gmTools.xml_escape_string(text = intake['external_code_brand'].strip()), 565 last_db_id 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 <IsTextual>True</IsTextual> 584 <TextualDrugName>%s</TextualDrugName> 585 </Prescription>""" 586 587 for intake in non_fd_substance_intakes: 588 drug_name = u'%s %s%s (%s)%s' % ( 589 intake['substance'], 590 intake['amount'], 591 intake['unit'], 592 intake['preparation'], 593 gmTools.coalesce(intake['schedule'], u'', _('\n Take: %s')) 594 ) 595 drug_snippets.append(drug_snippet % gmTools.xml_escape_string(text = drug_name.strip())) 596 597 intakes_pooled_by_brand = {} 598 for intake in non_fd_brand_intakes: 599 brand = u'%s %s' % (intake['brand'], intake['preparation']) 600 try: 601 intakes_pooled_by_brand[brand].append(intake) 602 except KeyError: 603 intakes_pooled_by_brand[brand] = [intake] 604 605 for brand, comps in intakes_pooled_by_brand.iteritems(): 606 drug_name = u'%s\n' % brand 607 for comp in comps: 608 drug_name += u' %s %s%s\n' % ( 609 comp['substance'], 610 comp['amount'], 611 comp['unit'] 612 ) 613 if comps[0]['schedule'] is not None: 614 drug_name += gmTools.coalesce(comps[0]['schedule'], u'', _('Take: %s')) 615 drug_snippets.append(drug_snippet % gmTools.xml_escape_string(text = drug_name.strip())) 616 617 # assemble XML file 618 xml = u"""<?xml version = "1.0" encoding = "UTF-8"?> 619 620 <FreeDiams> 621 <DrugsDatabaseName>%s</DrugsDatabaseName> 622 <FullPrescription version="0.5.0"> 623 624 %s 625 626 </FullPrescription> 627 </FreeDiams> 628 """ 629 630 xml_file = codecs.open(self.__fd2gm_filename, 'wb', 'utf8') 631 xml_file.write(xml % ( 632 last_db_id, 633 u'\n\t\t'.join(drug_snippets) 634 )) 635 xml_file.close() 636 637 return True
638 #--------------------------------------------------------
639 - def __create_gm2fd_file(self, mode='interactions'):
640 641 if mode == 'interactions': 642 mode = u'select-only' 643 elif mode == 'prescription': 644 mode = u'prescriber' 645 else: 646 mode = u'select-only' 647 648 xml_file = codecs.open(self.__gm2fd_filename, 'wb', 'utf8') 649 650 xml = u"""<?xml version="1.0" encoding="UTF-8"?> 651 652 <FreeDiams_In version="0.5.0"> 653 <EMR name="GNUmed" uid="unused"/> 654 <ConfigFile value="%s"/> 655 <ExchangeOut value="%s" format="xml"/> 656 <!-- <DrugsDatabase uid="can be set to a specific DB"/> --> 657 <Ui editmode="%s" blockPatientDatas="1"/> 658 %%s 659 </FreeDiams_In> 660 661 <!-- 662 # FIXME: search by LOINC code and add (as soon as supported by FreeDiams ...) 663 <Creatinine value="12" unit="mg/l or mmol/l"/> 664 <Weight value="70" unit="kg or pd" /> 665 <Height value="170" unit="cm or "/> 666 <ICD10 value="J11.0;A22;Z23"/> 667 --> 668 """ % ( 669 self.__fd4gm_config_file, 670 self.__fd2gm_filename, 671 mode 672 ) 673 674 if self.patient is None: 675 xml_file.write(xml % u'') 676 xml_file.close() 677 return 678 679 name = self.patient.get_active_name() 680 if self.patient['dob'] is None: 681 dob = u'' 682 else: 683 dob = self.patient['dob'].strftime(cFreeDiamsInterface.default_dob_format) 684 685 emr = self.patient.get_emr() 686 allgs = emr.get_allergies() 687 atc_allgs = [ 688 a['atc_code'] for a in allgs if ((a['atc_code'] is not None) and (a['type'] == u'allergy')) 689 ] 690 atc_sens = [ 691 a['atc_code'] for a in allgs if ((a['atc_code'] is not None) and (a['type'] == u'sensitivity')) 692 ] 693 inn_allgs = [ 694 a['allergene'] for a in allgs if ((a['allergene'] is not None) and (a['type'] == u'allergy')) 695 ] 696 inn_sens = [ 697 a['allergene'] for a in allgs if ((a['allergene'] is not None) and (a['type'] == u'sensitivity')) 698 ] 699 # this is rather fragile: FreeDiams won't know what type of UID this is 700 # (but it will assume it is of the type of the drug database in use) 701 # but eventually FreeDiams puts all drugs into one database :-) 702 uid_allgs = [ 703 a['substance_code'] for a in allgs if ((a['substance_code'] is not None) and (a['type'] == u'allergy')) 704 ] 705 uid_sens = [ 706 a['substance_code'] for a in allgs if ((a['substance_code'] is not None) and (a['type'] == u'sensitivity')) 707 ] 708 709 patient_xml = u"""<Patient> 710 <Identity 711 lastnames="%s" 712 firstnames="%s" 713 uid="%s" 714 dob="%s" 715 gender="%s" 716 /> 717 <ATCAllergies value="%s"/> 718 <ATCIntolerances value="%s"/> 719 720 <InnAllergies value="%s"/> 721 <InnIntolerances value="%s"/> 722 723 <DrugsUidAllergies value="%s"/> 724 <DrugsUidIntolerances value="%s"/> 725 </Patient> 726 """ % ( 727 gmTools.xml_escape_string(text = name['lastnames']), 728 gmTools.xml_escape_string(text = name['firstnames']), 729 self.patient.ID, 730 dob, 731 cFreeDiamsInterface.map_gender2mf[self.patient['gender']], 732 gmTools.xml_escape_string(text = u';'.join(atc_allgs)), 733 gmTools.xml_escape_string(text = u';'.join(atc_sens)), 734 gmTools.xml_escape_string(text = u';'.join(inn_allgs)), 735 gmTools.xml_escape_string(text = u';'.join(inn_sens)), 736 gmTools.xml_escape_string(text = u';'.join(uid_allgs)), 737 gmTools.xml_escape_string(text = u';'.join(uid_sens)) 738 ) 739 740 xml_file.write(xml % patient_xml) 741 xml_file.close()
742 #--------------------------------------------------------
743 - def import_fd2gm_file_as_prescription(self, filename=None):
744 745 if filename is None: 746 filename = self.__fd2gm_filename 747 748 fd2gm_xml = etree.ElementTree() 749 fd2gm_xml.parse(filename) 750 751 pdfs = fd2gm_xml.findall('ExtraDatas/Printed') 752 if len(pdfs) == 0: 753 return 754 755 fd_filenames = [] 756 for pdf in pdfs: 757 fd_filenames.append(pdf.attrib['file']) 758 759 docs = self.patient.get_document_folder() 760 emr = self.patient.get_emr() 761 762 prescription = docs.add_document ( 763 document_type = create_document_type ( 764 document_type = DOCUMENT_TYPE_PRESCRIPTION 765 )['pk_doc_type'], 766 encounter = emr.active_encounter['pk_encounter'], 767 episode = emr.add_episode ( 768 episode_name = DEFAULT_MEDICATION_HISTORY_EPISODE, 769 is_open = False 770 )['pk_episode'] 771 ) 772 prescription['ext_ref'] = u'FreeDiams' 773 prescription.save() 774 fd_filenames.append(filename) 775 success, msg, parts = prescription.add_parts_from_files(files = fd_filenames) 776 if not success: 777 _log.error(msg) 778 return 779 780 for part in parts: 781 part['obj_comment'] = _('copy') 782 part.save() 783 784 xml_part = parts[-1] 785 xml_part['filename'] = u'freediams-prescription.xml' 786 xml_part['obj_comment'] = _('data') 787 xml_part.save() 788 789 # are we the intended reviewer ? 790 from Gnumed.business.gmPerson import gmCurrentProvider 791 me = gmCurrentProvider() 792 # if so: auto-sign the prescription 793 if xml_part['pk_intended_reviewer'] == me['pk_staff']: 794 prescription.set_reviewed(technically_abnormal = False, clinically_relevant = False)
795 #--------------------------------------------------------
796 - def import_fd2gm_file_as_drugs(self, filename=None):
797 """ 798 If returning textual prescriptions (say, drugs which FreeDiams 799 did not know) then "IsTextual" will be True and UID will be -1. 800 """ 801 if filename is None: 802 filename = self.__fd2gm_filename 803 804 # FIXME: do not import IsTextual drugs, or rather, make that configurable 805 806 fd2gm_xml = etree.ElementTree() 807 fd2gm_xml.parse(filename) 808 809 data_src_pk = self.create_data_source_entry() 810 811 xml_version = fd2gm_xml.find('FullPrescription').attrib['version'] 812 _log.debug('fd2gm file version: %s', xml_version) 813 814 if xml_version == '0.6.0': 815 return self.__import_fd2gm_file_as_drugs_0_6_0(fd2gm_xml = fd2gm_xml, pk_data_source = data_src_pk) 816 817 return self.__import_fd2gm_file_as_drugs_0_5(fd2gm_xml = fd2gm_xml, pk_data_source = data_src_pk)
818 #--------------------------------------------------------
819 - def __import_fd2gm_file_as_drugs_0_6_0(self, fd2gm_xml=None, pk_data_source=None):
820 821 # drug_id_name = db_def.attrib['drugUidName'] 822 fd_xml_prescriptions = fd2gm_xml.findall('FullPrescription/Prescription') 823 824 self.__imported_drugs = [] 825 for fd_xml_prescription in fd_xml_prescriptions: 826 drug_db = fd_xml_prescription.find('Drug').attrib['db'].strip() 827 drug_uid = fd_xml_prescription.find('Drug').attrib['u1'].strip() 828 #drug_uid_name = fd_xml_prescription.find('Drug_UID_Name').text.strip() 829 drug_uid_name = u'<%s>' % drug_db 830 if drug_uid == u'-1': 831 _log.debug('skipping textual drug') 832 continue # it's a TextualDrug, skip it 833 drug_name = fd_xml_prescription.find('Drug/DrugName').text.replace(', )', ')').strip() 834 drug_form = fd_xml_prescription.find('Drug/DrugForm').text.strip() 835 # drug_atc = fd_xml_prescription.find('DrugATC') 836 # if drug_atc is None: 837 # drug_atc = u'' 838 # else: 839 # if drug_atc.text is None: 840 # drug_atc = u'' 841 # else: 842 # drug_atc = drug_atc.text.strip() 843 844 # create new branded drug 845 new_drug = create_branded_drug(brand_name = drug_name, preparation = drug_form, return_existing = True) 846 self.__imported_drugs.append(new_drug) 847 new_drug['is_fake_brand'] = False 848 # new_drug['atc'] = drug_atc 849 new_drug['external_code_type'] = u'FreeDiams::%s::%s' % (drug_db, drug_uid_name) 850 new_drug['external_code'] = drug_uid 851 new_drug['pk_data_source'] = pk_data_source 852 new_drug.save() 853 854 # parse XML for composition records 855 fd_xml_components = fd_xml_prescription.getiterator('Composition') 856 comp_data = {} 857 for fd_xml_comp in fd_xml_components: 858 859 data = {} 860 861 xml_strength = fd_xml_comp.attrib['strength'].strip() 862 amount = regex.match(r'^\d+[.,]{0,1}\d*', xml_strength) 863 if amount is None: 864 amount = 99999 865 else: 866 amount = amount.group() 867 data['amount'] = amount 868 869 #unit = regex.sub(r'\d+[.,]{0,1}\d*', u'', xml_strength).strip() 870 unit = (xml_strength[len(amount):]).strip() 871 if unit == u'': 872 unit = u'*?*' 873 data['unit'] = unit 874 875 # hopefully, FreeDiams gets their act together, eventually: 876 atc = regex.match(r'[A-Za-z]\d\d[A-Za-z]{2}\d\d', fd_xml_comp.attrib['atc'].strip()) 877 if atc is None: 878 data['atc'] = None 879 else: 880 atc = atc.group() 881 data['atc'] = atc 882 883 molecule_name = fd_xml_comp.attrib['molecularName'].strip() 884 if molecule_name != u'': 885 create_consumable_substance(substance = molecule_name, atc = atc, amount = amount, unit = unit) 886 data['molecule_name'] = molecule_name 887 888 inn_name = fd_xml_comp.attrib['inn'].strip() 889 if inn_name != u'': 890 create_consumable_substance(substance = inn_name, atc = atc, amount = amount, unit = unit) 891 #data['inn_name'] = molecule_name 892 data['inn_name'] = inn_name 893 894 if molecule_name == u'': 895 data['substance'] = inn_name 896 _log.info('linking INN [%s] rather than molecularName as component', inn_name) 897 else: 898 data['substance'] = molecule_name 899 900 data['nature'] = fd_xml_comp.attrib['nature'].strip() 901 data['nature_ID'] = fd_xml_comp.attrib['natureLink'].strip() 902 903 # merge composition records of SA/FT nature 904 try: 905 old_data = comp_data[data['nature_ID']] 906 # normalize INN 907 if old_data['inn_name'] == u'': 908 old_data['inn_name'] = data['inn_name'] 909 if data['inn_name'] == u'': 910 data['inn_name'] = old_data['inn_name'] 911 # normalize molecule 912 if old_data['molecule_name'] == u'': 913 old_data['molecule_name'] = data['molecule_name'] 914 if data['molecule_name'] == u'': 915 data['molecule_name'] = old_data['molecule_name'] 916 # normalize ATC 917 if old_data['atc'] == u'': 918 old_data['atc'] = data['atc'] 919 if data['atc'] == u'': 920 data['atc'] = old_data['atc'] 921 # FT: transformed form 922 # SA: active substance 923 # it would be preferable to use the SA record because that's what's *actually* 924 # contained in the drug, however FreeDiams does not list the amount thereof 925 # (rather that of the INN) 926 # FT and SA records of the same component carry the same nature_ID 927 if data['nature'] == u'FT': 928 comp_data[data['nature_ID']] = data 929 else: 930 comp_data[data['nature_ID']] = old_data 931 932 # or create new record 933 except KeyError: 934 comp_data[data['nature_ID']] = data 935 936 # actually create components from (possibly merged) composition records 937 for key, data in comp_data.items(): 938 new_drug.add_component ( 939 substance = data['substance'], 940 atc = data['atc'], 941 amount = data['amount'], 942 unit = data['unit'] 943 )
944 #--------------------------------------------------------
945 - def __import_fd2gm_file_as_drugs_0_5(self, fd2gm_xml=None, pk_data_source=None):
946 947 db_def = fd2gm_xml.find('DrugsDatabaseName') 948 db_id = db_def.text.strip() 949 drug_id_name = db_def.attrib['drugUidName'] 950 fd_xml_drug_entries = fd2gm_xml.findall('FullPrescription/Prescription') 951 952 self.__imported_drugs = [] 953 for fd_xml_drug in fd_xml_drug_entries: 954 drug_uid = fd_xml_drug.find('Drug_UID').text.strip() 955 if drug_uid == u'-1': 956 _log.debug('skipping textual drug') 957 continue # it's a TextualDrug, skip it 958 drug_name = fd_xml_drug.find('DrugName').text.replace(', )', ')').strip() 959 drug_form = fd_xml_drug.find('DrugForm').text.strip() 960 drug_atc = fd_xml_drug.find('DrugATC') 961 if drug_atc is None: 962 drug_atc = u'' 963 else: 964 if drug_atc.text is None: 965 drug_atc = u'' 966 else: 967 drug_atc = drug_atc.text.strip() 968 969 # create new branded drug 970 new_drug = create_branded_drug(brand_name = drug_name, preparation = drug_form, return_existing = True) 971 self.__imported_drugs.append(new_drug) 972 new_drug['is_fake_brand'] = False 973 new_drug['atc'] = drug_atc 974 new_drug['external_code_type'] = u'FreeDiams::%s::%s' % (db_id, drug_id_name) 975 new_drug['external_code'] = drug_uid 976 new_drug['pk_data_source'] = pk_data_source 977 new_drug.save() 978 979 # parse XML for composition records 980 fd_xml_components = fd_xml_drug.getiterator('Composition') 981 comp_data = {} 982 for fd_xml_comp in fd_xml_components: 983 984 data = {} 985 986 amount = regex.match(r'\d+[.,]{0,1}\d*', fd_xml_comp.attrib['strenght'].strip()) # sic, typo 987 if amount is None: 988 amount = 99999 989 else: 990 amount = amount.group() 991 data['amount'] = amount 992 993 unit = regex.sub(r'\d+[.,]{0,1}\d*', u'', fd_xml_comp.attrib['strenght'].strip()).strip() # sic, typo 994 if unit == u'': 995 unit = u'*?*' 996 data['unit'] = unit 997 998 molecule_name = fd_xml_comp.attrib['molecularName'].strip() 999 if molecule_name != u'': 1000 create_consumable_substance(substance = molecule_name, atc = None, amount = amount, unit = unit) 1001 data['molecule_name'] = molecule_name 1002 1003 inn_name = fd_xml_comp.attrib['inn'].strip() 1004 if inn_name != u'': 1005 create_consumable_substance(substance = inn_name, atc = None, amount = amount, unit = unit) 1006 data['inn_name'] = molecule_name 1007 1008 if molecule_name == u'': 1009 data['substance'] = inn_name 1010 _log.info('linking INN [%s] rather than molecularName as component', inn_name) 1011 else: 1012 data['substance'] = molecule_name 1013 1014 data['nature'] = fd_xml_comp.attrib['nature'].strip() 1015 data['nature_ID'] = fd_xml_comp.attrib['natureLink'].strip() 1016 1017 # merge composition records of SA/FT nature 1018 try: 1019 old_data = comp_data[data['nature_ID']] 1020 # normalize INN 1021 if old_data['inn_name'] == u'': 1022 old_data['inn_name'] = data['inn_name'] 1023 if data['inn_name'] == u'': 1024 data['inn_name'] = old_data['inn_name'] 1025 # normalize molecule 1026 if old_data['molecule_name'] == u'': 1027 old_data['molecule_name'] = data['molecule_name'] 1028 if data['molecule_name'] == u'': 1029 data['molecule_name'] = old_data['molecule_name'] 1030 # FT: transformed form 1031 # SA: active substance 1032 # it would be preferable to use the SA record because that's what's *actually* 1033 # contained in the drug, however FreeDiams does not list the amount thereof 1034 # (rather that of the INN) 1035 if data['nature'] == u'FT': 1036 comp_data[data['nature_ID']] = data 1037 else: 1038 comp_data[data['nature_ID']] = old_data 1039 1040 # or create new record 1041 except KeyError: 1042 comp_data[data['nature_ID']] = data 1043 1044 # actually create components from (possibly merged) composition records 1045 for key, data in comp_data.items(): 1046 new_drug.add_component ( 1047 substance = data['substance'], 1048 atc = None, 1049 amount = data['amount'], 1050 unit = data['unit'] 1051 )
1052 #============================================================
1053 -class cGelbeListeWindowsInterface(cDrugDataSourceInterface):
1054 """Support v8.2 CSV file interface only.""" 1055 1056 version = u'Gelbe Liste/MMI v8.2 interface' 1057 default_encoding = 'cp1250' 1058 bdt_line_template = u'%03d6210#%s\r\n' # Medikament verordnet auf Kassenrezept 1059 bdt_line_base_length = 8 1060 #--------------------------------------------------------
1061 - def __init__(self):
1062 1063 cDrugDataSourceInterface.__init__(self) 1064 1065 _log.info(u'%s (native Windows)', cGelbeListeWindowsInterface.version) 1066 1067 self.path_to_binary = r'C:\Programme\MMI PHARMINDEX\glwin.exe' 1068 self.args = r'-KEEPBACKGROUND -PRESCRIPTIONFILE %s -CLOSETOTRAY' 1069 1070 paths = gmTools.gmPaths() 1071 1072 self.default_csv_filename = os.path.join(paths.home_dir, '.gnumed', 'tmp', 'rezept.txt') 1073 self.default_csv_filename_arg = os.path.join(paths.home_dir, '.gnumed', 'tmp') 1074 self.interactions_filename = os.path.join(paths.home_dir, '.gnumed', 'tmp', 'gm2mmi.bdt') 1075 self.data_date_filename = r'C:\Programme\MMI PHARMINDEX\datadate.txt' 1076 1077 self.__data_date = None 1078 self.__online_update_date = None
1079 1080 # use adjusted config.dat 1081 #--------------------------------------------------------
1082 - def get_data_source_version(self, force_reload=False):
1083 1084 if self.__data_date is not None: 1085 if not force_reload: 1086 return { 1087 'data': self.__data_date, 1088 'online_update': self.__online_update_date 1089 } 1090 try: 1091 open(self.data_date_filename, 'wb').close() 1092 except StandardError: 1093 _log.error('problem querying the MMI drug database for version information') 1094 _log.exception('cannot create MMI drug database version file [%s]', self.data_date_filename) 1095 self.__data_date = None 1096 self.__online_update_date = None 1097 return { 1098 'data': u'?', 1099 'online_update': u'?' 1100 } 1101 1102 cmd = u'%s -DATADATE' % self.path_to_binary 1103 if not gmShellAPI.run_command_in_shell(command = cmd, blocking = True): 1104 _log.error('problem querying the MMI drug database for version information') 1105 self.__data_date = None 1106 self.__online_update_date = None 1107 return { 1108 'data': u'?', 1109 'online_update': u'?' 1110 } 1111 1112 try: 1113 version_file = open(self.data_date_filename, 'rU') 1114 except StandardError: 1115 _log.error('problem querying the MMI drug database for version information') 1116 _log.exception('cannot open MMI drug database version file [%s]', self.data_date_filename) 1117 self.__data_date = None 1118 self.__online_update_date = None 1119 return { 1120 'data': u'?', 1121 'online_update': u'?' 1122 } 1123 1124 self.__data_date = version_file.readline()[:10] 1125 self.__online_update_date = version_file.readline()[:10] 1126 version_file.close() 1127 1128 return { 1129 'data': self.__data_date, 1130 'online_update': self.__online_update_date 1131 }
1132 #--------------------------------------------------------
1133 - def create_data_source_entry(self):
1134 versions = self.get_data_source_version() 1135 1136 return create_data_source ( 1137 long_name = u'Medikamentendatenbank "mmi PHARMINDEX" (Gelbe Liste)', 1138 short_name = u'GL/MMI', 1139 version = u'Daten: %s, Preise (Onlineupdate): %s' % (versions['data'], versions['online_update']), 1140 source = u'Medizinische Medien Informations GmbH, Am Forsthaus Gravenbruch 7, 63263 Neu-Isenburg', 1141 language = u'de' 1142 )
1143 #--------------------------------------------------------
1144 - def switch_to_frontend(self, blocking=False, cmd=None):
1145 1146 try: 1147 # must make sure csv file exists 1148 open(self.default_csv_filename, 'wb').close() 1149 except IOError: 1150 _log.exception('problem creating GL/MMI <-> GNUmed exchange file') 1151 return False 1152 1153 if cmd is None: 1154 cmd = (u'%s %s' % (self.path_to_binary, self.args)) % self.default_csv_filename_arg 1155 1156 if os.name == 'nt': 1157 blocking = True 1158 if not gmShellAPI.run_command_in_shell(command = cmd, blocking = blocking): 1159 _log.error('problem switching to the MMI drug database') 1160 # apparently on the first call MMI does not 1161 # consistently return 0 on success 1162 # return False 1163 1164 return True
1165 #--------------------------------------------------------
1166 - def __let_user_select_drugs(self):
1167 1168 # better to clean up interactions file 1169 open(self.interactions_filename, 'wb').close() 1170 1171 if not self.switch_to_frontend(blocking = True): 1172 return None 1173 1174 return cGelbeListeCSVFile(filename = self.default_csv_filename)
1175 #--------------------------------------------------------
1176 - def import_drugs_as_substances(self):
1177 1178 selected_drugs = self.__let_user_select_drugs() 1179 if selected_drugs is None: 1180 return None 1181 1182 new_substances = [] 1183 1184 for drug in selected_drugs: 1185 atc = None # hopefully MMI eventually supports atc-per-substance in a drug... 1186 if len(drug['wirkstoffe']) == 1: 1187 atc = drug['atc'] 1188 for wirkstoff in drug['wirkstoffe']: 1189 new_substances.append(create_consumable_substance(substance = wirkstoff, atc = atc, amount = amount, unit = unit)) 1190 1191 selected_drugs.close() 1192 1193 return new_substances
1194 #--------------------------------------------------------
1195 - def import_drugs(self):
1196 1197 selected_drugs = self.__let_user_select_drugs() 1198 if selected_drugs is None: 1199 return None 1200 1201 data_src_pk = self.create_data_source_entry() 1202 1203 new_drugs = [] 1204 new_substances = [] 1205 1206 for entry in selected_drugs: 1207 1208 _log.debug('importing drug: %s %s', entry['name'], entry['darreichungsform']) 1209 1210 if entry[u'hilfsmittel']: 1211 _log.debug('skipping Hilfsmittel') 1212 continue 1213 1214 if entry[u'erstattbares_medizinprodukt']: 1215 _log.debug('skipping sonstiges Medizinprodukt') 1216 continue 1217 1218 # create branded drug (or get it if it already exists) 1219 drug = create_branded_drug(brand_name = entry['name'], preparation = entry['darreichungsform']) 1220 if drug is None: 1221 drug = get_drug_by_brand(brand_name = entry['name'], preparation = entry['darreichungsform']) 1222 new_drugs.append(drug) 1223 1224 # update fields 1225 drug['is_fake_brand'] = False 1226 drug['atc'] = entry['atc'] 1227 drug['external_code_type'] = u'DE-PZN' 1228 drug['external_code'] = entry['pzn'] 1229 drug['fk_data_source'] = data_src_pk 1230 drug.save() 1231 1232 # add components to brand 1233 atc = None # hopefully MMI eventually supports atc-per-substance in a drug... 1234 if len(entry['wirkstoffe']) == 1: 1235 atc = entry['atc'] 1236 for wirkstoff in entry['wirkstoffe']: 1237 drug.add_component(substance = wirkstoff, atc = atc) 1238 1239 # create as consumable substances, too 1240 atc = None # hopefully MMI eventually supports atc-per-substance in a drug... 1241 if len(entry['wirkstoffe']) == 1: 1242 atc = entry['atc'] 1243 for wirkstoff in entry['wirkstoffe']: 1244 new_substances.append(create_consumable_substance(substance = wirkstoff, atc = atc, amount = amount, unit = unit)) 1245 1246 return new_drugs, new_substances
1247 #--------------------------------------------------------
1248 - def check_interactions(self, drug_ids_list=None, substances=None):
1249 """For this to work the BDT interaction check must be configured in the MMI.""" 1250 1251 if drug_ids_list is None: 1252 if substances is None: 1253 return 1254 if len(substances) < 2: 1255 return 1256 drug_ids_list = [ (s.external_code_type, s.external_code) for s in substances ] 1257 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')] 1258 1259 else: 1260 if len(drug_ids_list) < 2: 1261 return 1262 1263 if drug_ids_list < 2: 1264 return 1265 1266 bdt_file = codecs.open(filename = self.interactions_filename, mode = 'wb', encoding = cGelbeListeWindowsInterface.default_encoding) 1267 1268 for pzn in drug_ids_list: 1269 pzn = pzn.strip() 1270 lng = cGelbeListeWindowsInterface.bdt_line_base_length + len(pzn) 1271 bdt_file.write(cGelbeListeWindowsInterface.bdt_line_template % (lng, pzn)) 1272 1273 bdt_file.close() 1274 1275 self.switch_to_frontend(blocking = True)
1276 #--------------------------------------------------------
1277 - def show_info_on_drug(self, drug=None):
1278 self.switch_to_frontend(blocking = True)
1279 #--------------------------------------------------------
1280 - def show_info_on_substance(self, substance=None):
1281 1282 cmd = None 1283 1284 if substance.external_code_type == u'DE-PZN': 1285 cmd = u'%s -PZN %s' % (self.path_to_binary, substance.external_code) 1286 1287 if cmd is None: 1288 name = gmTools.coalesce ( 1289 substance['brand'], 1290 substance['substance'] 1291 ) 1292 cmd = u'%s -NAME %s' % (self.path_to_binary, name) 1293 1294 # better to clean up interactions file 1295 open(self.interactions_filename, 'wb').close() 1296 1297 self.switch_to_frontend(cmd = cmd)
1298 #============================================================
1299 -class cGelbeListeWineInterface(cGelbeListeWindowsInterface):
1300
1301 - def __init__(self):
1302 cGelbeListeWindowsInterface.__init__(self) 1303 1304 _log.info(u'%s (WINE extension)', cGelbeListeWindowsInterface.version) 1305 1306 # FIXME: if -CLOSETOTRAY is used GNUmed cannot detect the end of MMI 1307 self.path_to_binary = r'wine "C:\Programme\MMI PHARMINDEX\glwin.exe"' 1308 self.args = r'"-PRESCRIPTIONFILE %s -KEEPBACKGROUND"' 1309 1310 paths = gmTools.gmPaths() 1311 1312 self.default_csv_filename = os.path.join(paths.home_dir, '.wine', 'drive_c', 'windows', 'temp', 'mmi2gm.csv') 1313 self.default_csv_filename_arg = r'c:\windows\temp\mmi2gm.csv' 1314 self.interactions_filename = os.path.join(paths.home_dir, '.wine', 'drive_c', 'windows', 'temp', 'gm2mmi.bdt') 1315 self.data_date_filename = os.path.join(paths.home_dir, '.wine', 'drive_c', 'Programme', 'MMI PHARMINDEX', 'datadate.txt')
1316 #============================================================
1317 -class cIfapInterface(cDrugDataSourceInterface):
1318 """empirical CSV interface""" 1319
1320 - def __init__(self):
1321 pass
1322
1323 - def print_transfer_file(self, filename=None):
1324 1325 try: 1326 csv_file = open(filename, 'rb') # FIXME: encoding ? 1327 except: 1328 _log.exception('cannot access [%s]', filename) 1329 csv_file = None 1330 1331 field_names = u'PZN Handelsname Form Abpackungsmenge Einheit Preis1 Hersteller Preis2 rezeptpflichtig Festbetrag Packungszahl Packungsgr\xf6\xdfe'.split() 1332 1333 if csv_file is None: 1334 return False 1335 1336 csv_lines = csv.DictReader ( 1337 csv_file, 1338 fieldnames = field_names, 1339 delimiter = ';' 1340 ) 1341 1342 for line in csv_lines: 1343 print "--------------------------------------------------------------------"[:31] 1344 for key in field_names: 1345 tmp = ('%s ' % key)[:30] 1346 print '%s: %s' % (tmp, line[key]) 1347 1348 csv_file.close()
1349 1350 # narr = u'%sx %s %s %s (\u2258 %s %s) von %s (%s)' % ( 1351 # line['Packungszahl'].strip(), 1352 # line['Handelsname'].strip(), 1353 # line['Form'].strip(), 1354 # line[u'Packungsgr\xf6\xdfe'].strip(), 1355 # line['Abpackungsmenge'].strip(), 1356 # line['Einheit'].strip(), 1357 # line['Hersteller'].strip(), 1358 # line['PZN'].strip() 1359 # ) 1360 #============================================================ 1361 drug_data_source_interfaces = { 1362 'Deutschland: Gelbe Liste/MMI (Windows)': cGelbeListeWindowsInterface, 1363 'Deutschland: Gelbe Liste/MMI (WINE)': cGelbeListeWineInterface, 1364 'FreeDiams (FR, US, CA, ZA)': cFreeDiamsInterface 1365 } 1366 1367 #============================================================ 1368 #============================================================ 1369 # substances in use across all patients 1370 #------------------------------------------------------------ 1371 _SQL_get_consumable_substance = u""" 1372 SELECT *, xmin 1373 FROM ref.consumable_substance 1374 WHERE %s 1375 """ 1376
1377 -class cConsumableSubstance(gmBusinessDBObject.cBusinessDBObject):
1378 1379 _cmd_fetch_payload = _SQL_get_consumable_substance % u"pk = %s" 1380 _cmds_store_payload = [ 1381 u"""UPDATE ref.consumable_substance SET 1382 description = %(description)s, 1383 atc_code = gm.nullify_empty_string(%(atc_code)s), 1384 amount = %(amount)s, 1385 unit = gm.nullify_empty_string(%(unit)s) 1386 WHERE 1387 pk = %(pk)s 1388 AND 1389 xmin = %(xmin)s 1390 AND 1391 -- must not currently be used with a patient directly 1392 NOT EXISTS ( 1393 SELECT 1 1394 FROM clin.substance_intake 1395 WHERE 1396 fk_drug_component IS NULL 1397 AND 1398 fk_substance = %(pk)s 1399 LIMIT 1 1400 ) 1401 AND 1402 -- must not currently be used with a patient indirectly, either 1403 NOT EXISTS ( 1404 SELECT 1 1405 FROM clin.substance_intake 1406 WHERE 1407 fk_drug_component IS NOT NULL 1408 AND 1409 fk_drug_component = ( 1410 SELECT r_ls2b.pk 1411 FROM ref.lnk_substance2brand r_ls2b 1412 WHERE fk_substance = %(pk)s 1413 ) 1414 LIMIT 1 1415 ) 1416 -- -- must not currently be used with a branded drug 1417 -- -- (but this would make it rather hard fixing branded drugs which contain only this substance) 1418 -- NOT EXISTS ( 1419 -- SELECT 1 1420 -- FROM ref.lnk_substance2brand 1421 -- WHERE fk_substance = %(pk)s 1422 -- LIMIT 1 1423 -- ) 1424 RETURNING 1425 xmin 1426 """ 1427 ] 1428 _updatable_fields = [ 1429 u'description', 1430 u'atc_code', 1431 u'amount', 1432 u'unit' 1433 ] 1434 #--------------------------------------------------------
1435 - def save_payload(self, conn=None):
1436 success, data = super(self.__class__, self).save_payload(conn = conn) 1437 1438 if not success: 1439 return (success, data) 1440 1441 if self._payload[self._idx['atc_code']] is not None: 1442 atc = self._payload[self._idx['atc_code']].strip() 1443 if atc != u'': 1444 gmATC.propagate_atc ( 1445 substance = self._payload[self._idx['description']].strip(), 1446 atc = atc 1447 ) 1448 1449 return (success, data)
1450 #-------------------------------------------------------- 1451 # properties 1452 #--------------------------------------------------------
1453 - def _get_is_in_use_by_patients(self):
1454 cmd = u""" 1455 SELECT 1456 EXISTS ( 1457 SELECT 1 1458 FROM clin.substance_intake 1459 WHERE 1460 fk_drug_component IS NULL 1461 AND 1462 fk_substance = %(pk)s 1463 LIMIT 1 1464 ) OR EXISTS ( 1465 SELECT 1 1466 FROM clin.substance_intake 1467 WHERE 1468 fk_drug_component IS NOT NULL 1469 AND 1470 fk_drug_component IN ( 1471 SELECT r_ls2b.pk 1472 FROM ref.lnk_substance2brand r_ls2b 1473 WHERE fk_substance = %(pk)s 1474 ) 1475 LIMIT 1 1476 )""" 1477 args = {'pk': self.pk_obj} 1478 1479 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False) 1480 return rows[0][0]
1481 1482 is_in_use_by_patients = property(_get_is_in_use_by_patients, lambda x:x) 1483 #--------------------------------------------------------
1484 - def _get_is_drug_component(self):
1485 cmd = u""" 1486 SELECT EXISTS ( 1487 SELECT 1 1488 FROM ref.lnk_substance2brand 1489 WHERE fk_substance = %(pk)s 1490 LIMIT 1 1491 )""" 1492 args = {'pk': self.pk_obj} 1493 1494 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False) 1495 return rows[0][0]
1496 1497 is_drug_component = property(_get_is_drug_component, lambda x:x)
1498 #------------------------------------------------------------
1499 -def get_consumable_substances(order_by=None):
1500 if order_by is None: 1501 order_by = u'true' 1502 else: 1503 order_by = u'true ORDER BY %s' % order_by 1504 cmd = _SQL_get_consumable_substance % order_by 1505 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = True) 1506 return [ cConsumableSubstance(row = {'data': r, 'idx': idx, 'pk_field': 'pk'}) for r in rows ]
1507 #------------------------------------------------------------
1508 -def create_consumable_substance(substance=None, atc=None, amount=None, unit=None):
1509 1510 substance = substance 1511 if atc is not None: 1512 atc = atc.strip() 1513 1514 converted, amount = gmTools.input2decimal(amount) 1515 if not converted: 1516 raise ValueError('<amount> must be a number: %s (%s)', amount, type(amount)) 1517 1518 args = { 1519 'desc': substance.strip(), 1520 'amount': amount, 1521 'unit': unit.strip(), 1522 'atc': atc 1523 } 1524 cmd = u""" 1525 SELECT pk FROM ref.consumable_substance 1526 WHERE 1527 lower(description) = lower(%(desc)s) 1528 AND 1529 amount = %(amount)s 1530 AND 1531 unit = %(unit)s 1532 """ 1533 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}]) 1534 1535 if len(rows) == 0: 1536 cmd = u""" 1537 INSERT INTO ref.consumable_substance (description, atc_code, amount, unit) VALUES ( 1538 %(desc)s, 1539 gm.nullify_empty_string(%(atc)s), 1540 %(amount)s, 1541 gm.nullify_empty_string(%(unit)s) 1542 ) RETURNING pk""" 1543 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True, get_col_idx = False) 1544 1545 gmATC.propagate_atc(substance = substance, atc = atc) 1546 1547 return cConsumableSubstance(aPK_obj = rows[0]['pk'])
1548 #------------------------------------------------------------
1549 -def delete_consumable_substance(substance=None):
1550 args = {'pk': substance} 1551 cmd = u""" 1552 DELETE FROM ref.consumable_substance 1553 WHERE 1554 pk = %(pk)s 1555 AND 1556 1557 -- must not currently be used with a patient 1558 NOT EXISTS ( 1559 SELECT 1 1560 FROM clin.v_pat_substance_intake 1561 WHERE pk_substance = %(pk)s 1562 LIMIT 1 1563 ) 1564 AND 1565 1566 -- must not currently be used with a branded drug 1567 NOT EXISTS ( 1568 SELECT 1 1569 FROM ref.lnk_substance2brand 1570 WHERE fk_substance = %(pk)s 1571 LIMIT 1 1572 )""" 1573 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}]) 1574 return True
1575 #------------------------------------------------------------
1576 -class cSubstanceMatchProvider(gmMatchProvider.cMatchProvider_SQL2):
1577 1578 _pattern = regex.compile(r'^\D+\s*\d+$', regex.UNICODE | regex.LOCALE) 1579 _query1 = u""" 1580 SELECT 1581 pk::text, 1582 (description || ' ' || amount || ' ' || unit) as subst 1583 FROM ref.consumable_substance 1584 WHERE description %(fragment_condition)s 1585 ORDER BY subst 1586 LIMIT 50""" 1587 _query2 = u""" 1588 SELECT 1589 pk::text, 1590 (description || ' ' || amount || ' ' || unit) as subst 1591 FROM ref.consumable_substance 1592 WHERE 1593 %(fragment_condition)s 1594 ORDER BY subst 1595 LIMIT 50""" 1596 1597 #--------------------------------------------------------
1598 - def getMatchesByPhrase(self, aFragment):
1599 """Return matches for aFragment at start of phrases.""" 1600 1601 if cSubstanceMatchProvider._pattern.match(aFragment): 1602 self._queries = [cSubstanceMatchProvider._query2] 1603 fragment_condition = """description ILIKE %(desc)s 1604 AND 1605 amount::text ILIKE %(amount)s""" 1606 self._args['desc'] = u'%s%%' % regex.sub(r'\s*\d+$', u'', aFragment) 1607 self._args['amount'] = u'%s%%' % regex.sub(r'^\D+\s*', u'', aFragment) 1608 else: 1609 self._queries = [cSubstanceMatchProvider._query1] 1610 fragment_condition = u"ILIKE %(fragment)s" 1611 self._args['fragment'] = u"%s%%" % aFragment 1612 1613 return self._find_matches(fragment_condition)
1614 #--------------------------------------------------------
1615 - def getMatchesByWord(self, aFragment):
1616 """Return matches for aFragment at start of words inside phrases.""" 1617 1618 if cSubstanceMatchProvider._pattern.match(aFragment): 1619 self._queries = [cSubstanceMatchProvider._query2] 1620 1621 desc = regex.sub(r'\s*\d+$', u'', aFragment) 1622 desc = gmPG2.sanitize_pg_regex(expression = desc, escape_all = False) 1623 1624 fragment_condition = """description ~* %(desc)s 1625 AND 1626 amount::text ILIKE %(amount)s""" 1627 1628 self._args['desc'] = u"( %s)|(^%s)" % (desc, desc) 1629 self._args['amount'] = u'%s%%' % regex.sub(r'^\D+\s*', u'', aFragment) 1630 else: 1631 self._queries = [cSubstanceMatchProvider._query1] 1632 fragment_condition = u"~* %(fragment)s" 1633 aFragment = gmPG2.sanitize_pg_regex(expression = aFragment, escape_all = False) 1634 self._args['fragment'] = u"( %s)|(^%s)" % (aFragment, aFragment) 1635 1636 return self._find_matches(fragment_condition)
1637 #--------------------------------------------------------
1638 - def getMatchesBySubstr(self, aFragment):
1639 """Return matches for aFragment as a true substring.""" 1640 1641 if cSubstanceMatchProvider._pattern.match(aFragment): 1642 self._queries = [cSubstanceMatchProvider._query2] 1643 fragment_condition = """description ILIKE %(desc)s 1644 AND 1645 amount::text ILIKE %(amount)s""" 1646 self._args['desc'] = u'%%%s%%' % regex.sub(r'\s*\d+$', u'', aFragment) 1647 self._args['amount'] = u'%s%%' % regex.sub(r'^\D+\s*', u'', aFragment) 1648 else: 1649 self._queries = [cSubstanceMatchProvider._query1] 1650 fragment_condition = u"ILIKE %(fragment)s" 1651 self._args['fragment'] = u"%%%s%%" % aFragment 1652 1653 return self._find_matches(fragment_condition)
1654 #============================================================
1655 -class cSubstanceIntakeEntry(gmBusinessDBObject.cBusinessDBObject):
1656 """Represents a substance currently taken by a patient.""" 1657 1658 _cmd_fetch_payload = u"SELECT * FROM clin.v_pat_substance_intake WHERE pk_substance_intake = %s" 1659 _cmds_store_payload = [ 1660 u"""UPDATE clin.substance_intake SET 1661 clin_when = %(started)s, 1662 discontinued = %(discontinued)s, 1663 discontinue_reason = gm.nullify_empty_string(%(discontinue_reason)s), 1664 schedule = gm.nullify_empty_string(%(schedule)s), 1665 aim = gm.nullify_empty_string(%(aim)s), 1666 narrative = gm.nullify_empty_string(%(notes)s), 1667 intake_is_approved_of = %(intake_is_approved_of)s, 1668 fk_episode = %(pk_episode)s, 1669 1670 preparation = ( 1671 case 1672 when %(pk_brand)s is NULL then %(preparation)s 1673 else NULL 1674 end 1675 )::text, 1676 1677 is_long_term = ( 1678 case 1679 when ( 1680 (%(is_long_term)s is False) 1681 and 1682 (%(duration)s is NULL) 1683 ) is True then null 1684 else %(is_long_term)s 1685 end 1686 )::boolean, 1687 1688 duration = ( 1689 case 1690 when %(is_long_term)s is True then null 1691 else %(duration)s 1692 end 1693 )::interval 1694 WHERE 1695 pk = %(pk_substance_intake)s 1696 AND 1697 xmin = %(xmin_substance_intake)s 1698 RETURNING 1699 xmin as xmin_substance_intake 1700 """ 1701 ] 1702 _updatable_fields = [ 1703 u'started', 1704 u'discontinued', 1705 u'discontinue_reason', 1706 u'preparation', 1707 u'intake_is_approved_of', 1708 u'schedule', 1709 u'duration', 1710 u'aim', 1711 u'is_long_term', 1712 u'notes', 1713 u'pk_episode' 1714 ] 1715 #--------------------------------------------------------
1716 - def format(self, left_margin=0, date_format='%Y %B %d', one_line=True, allergy=None, show_all_brand_components=False):
1717 if one_line: 1718 return self.format_as_one_line(left_margin = left_margin, date_format = date_format) 1719 1720 return self.format_as_multiple_lines ( 1721 left_margin = left_margin, 1722 date_format = date_format, 1723 allergy = allergy, 1724 show_all_brand_components = show_all_brand_components 1725 )
1726 #--------------------------------------------------------
1727 - def format_as_one_line(self, left_margin=0, date_format='%Y %B %d'):
1728 1729 if self._payload[self._idx['duration']] is None: 1730 duration = gmTools.bool2subst ( 1731 self._payload[self._idx['is_long_term']], 1732 _('long-term'), 1733 _('short-term'), 1734 _('?short-term') 1735 ) 1736 else: 1737 duration = gmDateTime.format_interval ( 1738 self._payload[self._idx['duration']], 1739 accuracy_wanted = gmDateTime.acc_days 1740 ) 1741 1742 line = u'%s%s (%s %s): %s %s%s %s (%s)' % ( 1743 u' ' * left_margin, 1744 self._payload[self._idx['started']].strftime(date_format), 1745 gmTools.u_right_arrow, 1746 duration, 1747 self._payload[self._idx['substance']], 1748 self._payload[self._idx['amount']], 1749 self._payload[self._idx['unit']], 1750 self._payload[self._idx['preparation']], 1751 gmTools.bool2subst(self._payload[self._idx['is_currently_active']], _('ongoing'), _('inactive'), _('?ongoing')) 1752 ) 1753 1754 return line
1755 #--------------------------------------------------------
1756 - def format_as_multiple_lines(self, left_margin=0, date_format='%Y %B %d', allergy=None, show_all_brand_components=False):
1757 1758 txt = _('Substance intake entry (%s, %s) [#%s] \n') % ( 1759 gmTools.bool2subst ( 1760 boolean = self._payload[self._idx['is_currently_active']], 1761 true_return = gmTools.bool2subst ( 1762 boolean = self._payload[self._idx['seems_inactive']], 1763 true_return = _('active, needs check'), 1764 false_return = _('active'), 1765 none_return = _('assumed active') 1766 ), 1767 false_return = _('inactive') 1768 ), 1769 gmTools.bool2subst ( 1770 boolean = self._payload[self._idx['intake_is_approved_of']], 1771 true_return = _('approved'), 1772 false_return = _('unapproved') 1773 ), 1774 self._payload[self._idx['pk_substance_intake']] 1775 ) 1776 1777 if allergy is not None: 1778 certainty = gmTools.bool2subst(allergy['definite'], _('definite'), _('suspected')) 1779 txt += u'\n' 1780 txt += u' !! ---- Cave ---- !!\n' 1781 txt += u' %s (%s): %s (%s)\n' % ( 1782 allergy['l10n_type'], 1783 certainty, 1784 allergy['descriptor'], 1785 gmTools.coalesce(allergy['reaction'], u'')[:40] 1786 ) 1787 txt += u'\n' 1788 1789 txt += u' ' + _('Substance: %s [#%s]\n') % (self._payload[self._idx['substance']], self._payload[self._idx['pk_substance']]) 1790 txt += u' ' + _('Preparation: %s\n') % self._payload[self._idx['preparation']] 1791 txt += u' ' + _('Amount per dose: %s %s') % (self._payload[self._idx['amount']], self._payload[self._idx['unit']]) 1792 if self.ddd is not None: 1793 txt += u' (DDD: %s %s)' % (self.ddd['ddd'], self.ddd['unit']) 1794 txt += u'\n' 1795 txt += gmTools.coalesce(self._payload[self._idx['atc_substance']], u'', _(' ATC (substance): %s\n')) 1796 1797 txt += u'\n' 1798 1799 txt += gmTools.coalesce ( 1800 self._payload[self._idx['brand']], 1801 u'', 1802 _(' Brand name: %%s [#%s]\n') % self._payload[self._idx['pk_brand']] 1803 ) 1804 txt += gmTools.coalesce(self._payload[self._idx['atc_brand']], u'', _(' ATC (brand): %s\n')) 1805 if show_all_brand_components and (self._payload[self._idx['pk_brand']] is not None): 1806 brand = self.containing_drug 1807 if len(brand['pk_substances']) > 1: 1808 for comp in brand['components']: 1809 if comp.startswith(self._payload[self._idx['substance']] + u'::'): 1810 continue 1811 txt += _(' Other component: %s\n') % comp 1812 1813 txt += u'\n' 1814 1815 txt += gmTools.coalesce(self._payload[self._idx['schedule']], u'', _(' Regimen: %s\n')) 1816 1817 if self._payload[self._idx['is_long_term']]: 1818 duration = u' %s %s' % (gmTools.u_right_arrow, gmTools.u_infinity) 1819 else: 1820 if self._payload[self._idx['duration']] is None: 1821 duration = u'' 1822 else: 1823 duration = u' %s %s' % (gmTools.u_right_arrow, gmDateTime.format_interval(self._payload[self._idx['duration']], gmDateTime.acc_days)) 1824 1825 txt += _(' Started %s%s%s\n') % ( 1826 gmDateTime.pydt_strftime ( 1827 self._payload[self._idx['started']], 1828 format = date_format, 1829 accuracy = gmDateTime.acc_days 1830 ), 1831 duration, 1832 gmTools.bool2subst(self._payload[self._idx['is_long_term']], _(' (long-term)'), _(' (short-term)'), u'') 1833 ) 1834 1835 if self._payload[self._idx['discontinued']] is not None: 1836 txt += _(' Discontinued %s\n') % ( 1837 gmDateTime.pydt_strftime ( 1838 self._payload[self._idx['discontinued']], 1839 format = date_format, 1840 accuracy = gmDateTime.acc_days 1841 ) 1842 ) 1843 txt += _(' Reason: %s\n') % self._payload[self._idx['discontinue_reason']] 1844 1845 txt += u'\n' 1846 1847 txt += gmTools.coalesce(self._payload[self._idx['aim']], u'', _(' Aim: %s\n')) 1848 txt += gmTools.coalesce(self._payload[self._idx['episode']], u'', _(' Episode: %s\n')) 1849 txt += gmTools.coalesce(self._payload[self._idx['health_issue']], u'', _(' Health issue: %s\n')) 1850 txt += gmTools.coalesce(self._payload[self._idx['notes']], u'', _(' Advice: %s\n')) 1851 1852 txt += u'\n' 1853 1854 txt += _(u'Revision: #%(row_ver)s, %(mod_when)s by %(mod_by)s.') % { 1855 'row_ver': self._payload[self._idx['row_version']], 1856 'mod_when': gmDateTime.pydt_strftime(self._payload[self._idx['modified_when']]), 1857 'mod_by': self._payload[self._idx['modified_by']] 1858 } 1859 1860 return txt
1861 #--------------------------------------------------------
1862 - def turn_into_allergy(self, encounter_id=None, allergy_type='allergy'):
1863 allg = gmAllergy.create_allergy ( 1864 allergene = self._payload[self._idx['substance']], 1865 allg_type = allergy_type, 1866 episode_id = self._payload[self._idx['pk_episode']], 1867 encounter_id = encounter_id 1868 ) 1869 allg['substance'] = gmTools.coalesce ( 1870 self._payload[self._idx['brand']], 1871 self._payload[self._idx['substance']] 1872 ) 1873 allg['reaction'] = self._payload[self._idx['discontinue_reason']] 1874 allg['atc_code'] = gmTools.coalesce(self._payload[self._idx['atc_substance']], self._payload[self._idx['atc_brand']]) 1875 if self._payload[self._idx['external_code_brand']] is not None: 1876 allg['substance_code'] = u'%s::::%s' % (self._payload[self._idx['external_code_type_brand']], self._payload[self._idx['external_code_brand']]) 1877 1878 if self._payload[self._idx['pk_brand']] is None: 1879 allg['generics'] = self._payload[self._idx['substance']] 1880 else: 1881 comps = [ c['substance'] for c in self.containing_drug.components ] 1882 if len(comps) == 0: 1883 allg['generics'] = self._payload[self._idx['substance']] 1884 else: 1885 allg['generics'] = u'; '.join(comps) 1886 1887 allg.save() 1888 return allg
1889 #-------------------------------------------------------- 1890 # properties 1891 #--------------------------------------------------------
1892 - def _get_ddd(self):
1893 1894 try: self.__ddd 1895 except AttributeError: self.__ddd = None 1896 1897 if self.__ddd is not None: 1898 return self.__ddd 1899 1900 if self._payload[self._idx['atc_substance']] is not None: 1901 ddd = gmATC.atc2ddd(atc = self._payload[self._idx['atc_substance']]) 1902 if len(ddd) != 0: 1903 self.__ddd = ddd[0] 1904 else: 1905 if self._payload[self._idx['atc_brand']] is not None: 1906 ddd = gmATC.atc2ddd(atc = self._payload[self._idx['atc_brand']]) 1907 if len(ddd) != 0: 1908 self.__ddd = ddd[0] 1909 1910 return self.__ddd
1911 1912 ddd = property(_get_ddd, lambda x:x) 1913 #--------------------------------------------------------
1914 - def _get_external_code(self):
1915 drug = self.containing_drug 1916 1917 if drug is None: 1918 return None 1919 1920 return drug.external_code
1921 1922 external_code = property(_get_external_code, lambda x:x) 1923 #--------------------------------------------------------
1924 - def _get_external_code_type(self):
1925 drug = self.containing_drug 1926 1927 if drug is None: 1928 return None 1929 1930 return drug.external_code_type
1931 1932 external_code_type = property(_get_external_code_type, lambda x:x) 1933 #--------------------------------------------------------
1934 - def _get_containing_drug(self):
1935 if self._payload[self._idx['pk_brand']] is None: 1936 return None 1937 1938 return cBrandedDrug(aPK_obj = self._payload[self._idx['pk_brand']])
1939 1940 containing_drug = property(_get_containing_drug, lambda x:x) 1941 #--------------------------------------------------------
1942 - def _get_parsed_schedule(self):
1943 tests = [ 1944 # lead, trail 1945 ' 1-1-1-1 ', 1946 # leading dose 1947 '1-1-1-1', 1948 '22-1-1-1', 1949 '1/3-1-1-1', 1950 '/4-1-1-1' 1951 ] 1952 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}$" 1953 for test in tests: 1954 print test.strip(), ":", regex.match(pattern, test.strip())
1955 #------------------------------------------------------------
1956 -def substance_intake_exists(pk_component=None, pk_substance=None, pk_identity=None):
1957 args = {'comp': pk_component, 'subst': pk_substance, 'pat': pk_identity} 1958 1959 where_clause = u""" 1960 fk_encounter IN ( 1961 SELECT pk FROM clin.encounter WHERE fk_patient = %(pat)s 1962 ) 1963 AND 1964 """ 1965 1966 if pk_substance is not None: 1967 where_clause += u'fk_substance = %(subst)s' 1968 if pk_component is not None: 1969 where_clause += u'fk_drug_component = %(comp)s' 1970 1971 cmd = u"""SELECT exists ( 1972 SELECT 1 FROM clin.substance_intake 1973 WHERE 1974 %s 1975 LIMIT 1 1976 )""" % where_clause 1977 1978 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}]) 1979 return rows[0][0]
1980 #------------------------------------------------------------
1981 -def create_substance_intake(pk_substance=None, pk_component=None, preparation=None, encounter=None, episode=None):
1982 1983 args = { 1984 'enc': encounter, 1985 'epi': episode, 1986 'comp': pk_component, 1987 'subst': pk_substance, 1988 'prep': preparation 1989 } 1990 1991 if pk_component is None: 1992 cmd = u""" 1993 INSERT INTO clin.substance_intake ( 1994 fk_encounter, 1995 fk_episode, 1996 intake_is_approved_of, 1997 fk_substance, 1998 preparation 1999 ) VALUES ( 2000 %(enc)s, 2001 %(epi)s, 2002 False, 2003 %(subst)s, 2004 %(prep)s 2005 ) 2006 RETURNING pk""" 2007 else: 2008 cmd = u""" 2009 INSERT INTO clin.substance_intake ( 2010 fk_encounter, 2011 fk_episode, 2012 intake_is_approved_of, 2013 fk_drug_component 2014 ) VALUES ( 2015 %(enc)s, 2016 %(epi)s, 2017 False, 2018 %(comp)s 2019 ) 2020 RETURNING pk""" 2021 2022 try: 2023 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True) 2024 except gmPG2.dbapi.InternalError, e: 2025 if e.pgerror is None: 2026 raise 2027 if 'prevent_duplicate_component' in e.pgerror: 2028 _log.exception('will not create duplicate substance intake entry') 2029 _log.error(e.pgerror) 2030 return None 2031 raise 2032 2033 return cSubstanceIntakeEntry(aPK_obj = rows[0][0])
2034 #------------------------------------------------------------
2035 -def delete_substance_intake(substance=None):
2036 cmd = u'delete from clin.substance_intake where pk = %(pk)s' 2037 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': {'pk': substance}}])
2038 #------------------------------------------------------------
2039 -def format_substance_intake_notes(emr=None, output_format=u'latex', table_type=u'by-brand'):
2040 2041 tex = u'\n\\noindent %s\n' % _('Additional notes') 2042 tex += u'\n' 2043 tex += u'\\noindent \\begin{tabularx}{\\textwidth}{|>{\\RaggedRight}X|l|>{\\RaggedRight}X|p{7.5cm}|}\n' 2044 tex += u'\\hline\n' 2045 tex += u'%s {\\scriptsize (%s)} & %s & %s \\tabularnewline \n' % (_('Substance'), _('Brand'), _('Strength'), _('Aim')) 2046 tex += u'\\hline\n' 2047 tex += u'%s\n' 2048 tex += u'\\end{tabularx}\n\n' 2049 2050 current_meds = emr.get_current_substance_intake ( 2051 include_inactive = False, 2052 include_unapproved = False, 2053 order_by = u'brand, substance' 2054 ) 2055 2056 # create lines 2057 lines = [] 2058 for med in current_meds: 2059 if med['brand'] is None: 2060 brand = u'' 2061 else: 2062 brand = u': {\\tiny %s}' % gmTools.tex_escape_string(med['brand']) 2063 if med['aim'] is None: 2064 aim = u'' 2065 else: 2066 aim = u'{\\scriptsize %s}' % gmTools.tex_escape_string(med['aim']) 2067 lines.append(u'%s ({\\small %s}%s) & %s%s & %s \\tabularnewline\n \\hline' % ( 2068 gmTools.tex_escape_string(med['substance']), 2069 gmTools.tex_escape_string(med['preparation']), 2070 brand, 2071 med['amount'], 2072 gmTools.tex_escape_string(med['unit']), 2073 aim 2074 )) 2075 2076 return tex % u'\n'.join(lines)
2077 2078 #------------------------------------------------------------
2079 -def format_substance_intake(emr=None, output_format=u'latex', table_type=u'by-brand'):
2080 2081 tex = u'\\noindent %s {\\tiny (%s)\\par}\n' % (_('Medication list'), _('ordered by brand')) 2082 tex += u'\n' 2083 tex += u'\\noindent \\begin{tabularx}{\\textwidth}{|>{\\RaggedRight}X|>{\\RaggedRight}X|}\n' 2084 tex += u'\\hline\n' 2085 tex += u'%s & %s \\tabularnewline \n' % (_('Drug'), _('Regimen / Advice')) 2086 tex += u'\\hline\n' 2087 tex += u'\\hline\n' 2088 tex += u'%s\n' 2089 tex += u'\\end{tabularx}\n' 2090 2091 current_meds = emr.get_current_substance_intake ( 2092 include_inactive = False, 2093 include_unapproved = False, 2094 order_by = u'brand, substance' 2095 ) 2096 2097 # aggregate data 2098 line_data = {} 2099 for med in current_meds: 2100 identifier = gmTools.coalesce(med['brand'], med['substance']) 2101 2102 try: 2103 line_data[identifier] 2104 except KeyError: 2105 line_data[identifier] = {'brand': u'', 'preparation': u'', 'schedule': u'', 'notes': [], 'strengths': []} 2106 2107 line_data[identifier]['brand'] = identifier 2108 line_data[identifier]['strengths'].append(u'%s %s%s' % (med['substance'][:20], med['amount'], med['unit'].strip())) 2109 line_data[identifier]['preparation'] = med['preparation'] 2110 line_data[identifier]['schedule'] = gmTools.coalesce(med['schedule'], u'') 2111 if med['notes'] is not None: 2112 if med['notes'] not in line_data[identifier]['notes']: 2113 line_data[identifier]['notes'].append(med['notes']) 2114 2115 # create lines 2116 already_seen = [] 2117 lines = [] 2118 line1_template = u'%s %s & %s \\tabularnewline' 2119 line2_template = u' {\\tiny %s\\par} & {\\scriptsize %s\\par} \\tabularnewline' 2120 line3_template = u' & {\\scriptsize %s\\par} \\tabularnewline' 2121 2122 for med in current_meds: 2123 identifier = gmTools.coalesce(med['brand'], med['substance']) 2124 2125 if identifier in already_seen: 2126 continue 2127 2128 already_seen.append(identifier) 2129 2130 lines.append (line1_template % ( 2131 gmTools.tex_escape_string(line_data[identifier]['brand']), 2132 gmTools.tex_escape_string(line_data[identifier]['preparation']), 2133 gmTools.tex_escape_string(line_data[identifier]['schedule']) 2134 )) 2135 2136 strengths = gmTools.tex_escape_string(u' / '.join(line_data[identifier]['strengths'])) 2137 if len(line_data[identifier]['notes']) == 0: 2138 first_note = u'' 2139 else: 2140 first_note = gmTools.tex_escape_string(line_data[identifier]['notes'][0]) 2141 lines.append(line2_template % (strengths, first_note)) 2142 if len(line_data[identifier]['notes']) > 1: 2143 for note in line_data[identifier]['notes'][1:]: 2144 lines.append(line3_template % gmTools.tex_escape_string(note)) 2145 2146 lines.append(u'\\hline') 2147 2148 return tex % u'\n'.join(lines)
2149 #============================================================ 2150 _SQL_get_drug_components = u'SELECT * FROM ref.v_drug_components WHERE %s' 2151
2152 -class cDrugComponent(gmBusinessDBObject.cBusinessDBObject):
2153 2154 _cmd_fetch_payload = _SQL_get_drug_components % u'pk_component = %s' 2155 _cmds_store_payload = [ 2156 u"""UPDATE ref.lnk_substance2brand SET 2157 fk_brand = %(pk_brand)s, 2158 fk_substance = %(pk_consumable_substance)s 2159 WHERE 2160 NOT EXISTS ( 2161 SELECT 1 2162 FROM clin.substance_intake 2163 WHERE fk_drug_component = %(pk_component)s 2164 LIMIT 1 2165 ) 2166 AND 2167 pk = %(pk_component)s 2168 AND 2169 xmin = %(xmin_lnk_substance2brand)s 2170 RETURNING 2171 xmin AS xmin_lnk_substance2brand 2172 """ 2173 ] 2174 _updatable_fields = [ 2175 u'pk_brand', 2176 u'pk_consumable_substance' 2177 ] 2178 #-------------------------------------------------------- 2179 # properties 2180 #--------------------------------------------------------
2181 - def _get_containing_drug(self):
2182 return cBrandedDrug(aPK_obj = self._payload[self._idx['pk_brand']])
2183 2184 containing_drug = property(_get_containing_drug, lambda x:x) 2185 #--------------------------------------------------------
2186 - def _get_is_in_use_by_patients(self):
2187 return self._payload[self._idx['is_in_use']]
2188 2189 is_in_use_by_patients = property(_get_is_in_use_by_patients, lambda x:x) 2190 #--------------------------------------------------------
2191 - def _get_substance(self):
2192 return cConsumableSubstance(aPK_obj = self._payload[self._idx['pk_consumable_substance']])
2193 2194 substance = property(_get_substance, lambda x:x)
2195 #------------------------------------------------------------
2196 -def get_drug_components():
2197 cmd = _SQL_get_drug_components % u'true ORDER BY brand, substance' 2198 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = True) 2199 return [ cDrugComponent(row = {'data': r, 'idx': idx, 'pk_field': 'pk_component'}) for r in rows ]
2200 #------------------------------------------------------------
2201 -class cDrugComponentMatchProvider(gmMatchProvider.cMatchProvider_SQL2):
2202 2203 _pattern = regex.compile(r'^\D+\s*\d+$', regex.UNICODE | regex.LOCALE) 2204 _query_desc_only = u""" 2205 SELECT DISTINCT ON (component) 2206 pk_component, 2207 (substance || ' ' || amount || unit || ' ' || preparation || ' (' || brand || ')') 2208 AS component 2209 FROM ref.v_drug_components 2210 WHERE 2211 substance %(fragment_condition)s 2212 OR 2213 brand %(fragment_condition)s 2214 ORDER BY component 2215 LIMIT 50""" 2216 _query_desc_and_amount = u""" 2217 2218 SELECT DISTINCT ON (component) 2219 pk_component, 2220 (substance || ' ' || amount || unit || ' ' || preparation || ' (' || brand || ')') 2221 AS component 2222 FROM ref.v_drug_components 2223 WHERE 2224 %(fragment_condition)s 2225 ORDER BY component 2226 LIMIT 50""" 2227 #--------------------------------------------------------
2228 - def getMatchesByPhrase(self, aFragment):
2229 """Return matches for aFragment at start of phrases.""" 2230 2231 if cDrugComponentMatchProvider._pattern.match(aFragment): 2232 self._queries = [cDrugComponentMatchProvider._query_desc_and_amount] 2233 fragment_condition = """(substance ILIKE %(desc)s OR brand ILIKE %(desc)s) 2234 AND 2235 amount::text ILIKE %(amount)s""" 2236 self._args['desc'] = u'%s%%' % regex.sub(r'\s*\d+$', u'', aFragment) 2237 self._args['amount'] = u'%s%%' % regex.sub(r'^\D+\s*', u'', aFragment) 2238 else: 2239 self._queries = [cDrugComponentMatchProvider._query_desc_only] 2240 fragment_condition = u"ILIKE %(fragment)s" 2241 self._args['fragment'] = u"%s%%" % aFragment 2242 2243 return self._find_matches(fragment_condition)
2244 #--------------------------------------------------------
2245 - def getMatchesByWord(self, aFragment):
2246 """Return matches for aFragment at start of words inside phrases.""" 2247 2248 if cDrugComponentMatchProvider._pattern.match(aFragment): 2249 self._queries = [cDrugComponentMatchProvider._query_desc_and_amount] 2250 2251 desc = regex.sub(r'\s*\d+$', u'', aFragment) 2252 desc = gmPG2.sanitize_pg_regex(expression = desc, escape_all = False) 2253 2254 fragment_condition = """(substance ~* %(desc)s OR brand ~* %(desc)s) 2255 AND 2256 amount::text ILIKE %(amount)s""" 2257 2258 self._args['desc'] = u"( %s)|(^%s)" % (desc, desc) 2259 self._args['amount'] = u'%s%%' % regex.sub(r'^\D+\s*', u'', aFragment) 2260 else: 2261 self._queries = [cDrugComponentMatchProvider._query_desc_only] 2262 fragment_condition = u"~* %(fragment)s" 2263 aFragment = gmPG2.sanitize_pg_regex(expression = aFragment, escape_all = False) 2264 self._args['fragment'] = u"( %s)|(^%s)" % (aFragment, aFragment) 2265 2266 return self._find_matches(fragment_condition)
2267 #--------------------------------------------------------
2268 - def getMatchesBySubstr(self, aFragment):
2269 """Return matches for aFragment as a true substring.""" 2270 2271 if cDrugComponentMatchProvider._pattern.match(aFragment): 2272 self._queries = [cDrugComponentMatchProvider._query_desc_and_amount] 2273 fragment_condition = """(substance ILIKE %(desc)s OR brand ILIKE %(desc)s) 2274 AND 2275 amount::text ILIKE %(amount)s""" 2276 self._args['desc'] = u'%%%s%%' % regex.sub(r'\s*\d+$', u'', aFragment) 2277 self._args['amount'] = u'%s%%' % regex.sub(r'^\D+\s*', u'', aFragment) 2278 else: 2279 self._queries = [cDrugComponentMatchProvider._query_desc_only] 2280 fragment_condition = u"ILIKE %(fragment)s" 2281 self._args['fragment'] = u"%%%s%%" % aFragment 2282 2283 return self._find_matches(fragment_condition)
2284 2285 #============================================================
2286 -class cBrandedDrug(gmBusinessDBObject.cBusinessDBObject):
2287 """Represents a drug as marketed by a manufacturer.""" 2288 2289 _cmd_fetch_payload = u"SELECT * FROM ref.v_branded_drugs WHERE pk_brand = %s" 2290 _cmds_store_payload = [ 2291 u"""UPDATE ref.branded_drug SET 2292 description = %(brand)s, 2293 preparation = %(preparation)s, 2294 atc_code = gm.nullify_empty_string(%(atc)s), 2295 external_code = gm.nullify_empty_string(%(external_code)s), 2296 external_code_type = gm.nullify_empty_string(%(external_code_type)s), 2297 is_fake = %(is_fake_brand)s, 2298 fk_data_source = %(pk_data_source)s 2299 WHERE 2300 pk = %(pk_brand)s 2301 AND 2302 xmin = %(xmin_branded_drug)s 2303 RETURNING 2304 xmin AS xmin_branded_drug 2305 """ 2306 ] 2307 _updatable_fields = [ 2308 u'brand', 2309 u'preparation', 2310 u'atc', 2311 u'is_fake_brand', 2312 u'external_code', 2313 u'external_code_type', 2314 u'pk_data_source' 2315 ] 2316 #--------------------------------------------------------
2317 - def save_payload(self, conn=None):
2318 success, data = super(self.__class__, self).save_payload(conn = conn) 2319 2320 if not success: 2321 return (success, data) 2322 2323 if self._payload[self._idx['atc']] is not None: 2324 atc = self._payload[self._idx['atc']].strip() 2325 if atc != u'': 2326 gmATC.propagate_atc ( 2327 substance = self._payload[self._idx['brand']].strip(), 2328 atc = atc 2329 ) 2330 2331 return (success, data)
2332 #--------------------------------------------------------
2333 - def set_substances_as_components(self, substances=None):
2334 2335 if self.is_in_use_by_patients: 2336 return False 2337 2338 pk_substances2keep = [ s['pk'] for s in substances ] 2339 args = {'brand': self._payload[self._idx['pk_brand']]} 2340 queries = [] 2341 2342 # INSERT those which are not there yet 2343 cmd = u""" 2344 INSERT INTO ref.lnk_substance2brand ( 2345 fk_brand, 2346 fk_substance 2347 ) 2348 SELECT 2349 %(brand)s, 2350 %(subst)s 2351 WHERE NOT EXISTS ( 2352 SELECT 1 2353 FROM ref.lnk_substance2brand 2354 WHERE 2355 fk_brand = %(brand)s 2356 AND 2357 fk_substance = %(subst)s 2358 )""" 2359 for pk in pk_substances2keep: 2360 args['subst'] = pk 2361 queries.append({'cmd': cmd, 'args': args}) 2362 2363 # DELETE those that don't belong anymore 2364 args['substances2keep'] = tuple(pk_substances2keep) 2365 cmd = u""" 2366 DELETE FROM ref.lnk_substance2brand 2367 WHERE 2368 fk_brand = %(brand)s 2369 AND 2370 fk_substance NOT IN %(substances2keep)s""" 2371 queries.append({'cmd': cmd, 'args': args}) 2372 2373 gmPG2.run_rw_queries(queries = queries) 2374 self.refetch_payload() 2375 2376 return True
2377 #--------------------------------------------------------
2378 - def add_component(self, substance=None, atc=None, amount=None, unit=None, pk_substance=None):
2379 2380 args = { 2381 'brand': self.pk_obj, 2382 'subst': substance, 2383 'atc': atc, 2384 'pk_subst': pk_substance 2385 } 2386 2387 if pk_substance is None: 2388 consumable = create_consumable_substance(substance = substance, atc = atc, amount = amount, unit = unit) 2389 args['pk_subst'] = consumable['pk'] 2390 2391 # already a component 2392 cmd = u""" 2393 SELECT pk_component 2394 FROM ref.v_drug_components 2395 WHERE 2396 pk_brand = %(brand)s 2397 AND 2398 (( 2399 (lower(substance) = lower(%(subst)s)) 2400 OR 2401 (lower(atc_substance) = lower(%(atc)s)) 2402 OR 2403 (pk_consumable_substance = %(pk_subst)s) 2404 ) IS TRUE) 2405 """ 2406 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False) 2407 2408 if len(rows) > 0: 2409 return 2410 2411 # create it 2412 cmd = u""" 2413 INSERT INTO ref.lnk_substance2brand (fk_brand, fk_substance) 2414 VALUES (%(brand)s, %(pk_subst)s) 2415 """ 2416 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}]) 2417 self.refetch_payload()
2418 #------------------------------------------------------------
2419 - def remove_component(self, substance=None):
2420 if len(self._payload[self._idx['components']]) == 1: 2421 _log.error('cannot remove the only component of a drug') 2422 return False 2423 2424 args = {'brand': self.pk_obj, 'comp': substance} 2425 cmd = u""" 2426 DELETE FROM ref.lnk_substance2brand 2427 WHERE 2428 fk_brand = %(brand)s 2429 AND 2430 fk_substance = %(comp)s 2431 AND 2432 NOT EXISTS ( 2433 SELECT 1 2434 FROM clin.substance_intake 2435 WHERE fk_drug_component = %(comp)s 2436 LIMIT 1 2437 ) 2438 """ 2439 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}]) 2440 self.refetch_payload() 2441 2442 return True
2443 #-------------------------------------------------------- 2444 # properties 2445 #--------------------------------------------------------
2446 - def _get_external_code(self):
2447 if self._payload[self._idx['external_code']] is None: 2448 return None 2449 2450 return self._payload[self._idx['external_code']]
2451 2452 external_code = property(_get_external_code, lambda x:x) 2453 #--------------------------------------------------------
2454 - def _get_external_code_type(self):
2455 2456 # FIXME: maybe evaluate fk_data_source ? 2457 if self._payload[self._idx['external_code_type']] is None: 2458 return None 2459 2460 return self._payload[self._idx['external_code_type']]
2461 2462 external_code_type = property(_get_external_code_type, lambda x:x) 2463 #--------------------------------------------------------
2464 - def _get_components(self):
2465 cmd = _SQL_get_drug_components % u'pk_brand = %(brand)s' 2466 args = {'brand': self._payload[self._idx['pk_brand']]} 2467 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True) 2468 return [ cDrugComponent(row = {'data': r, 'idx': idx, 'pk_field': 'pk_component'}) for r in rows ]
2469 2470 components = property(_get_components, lambda x:x) 2471 #--------------------------------------------------------
2473 if self._payload[self._idx['pk_substances']] is None: 2474 return [] 2475 cmd = _SQL_get_consumable_substance % u'pk IN %(pks)s' 2476 args = {'pks': tuple(self._payload[self._idx['pk_substances']])} 2477 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True) 2478 return [ cConsumableSubstance(row = {'data': r, 'idx': idx, 'pk_field': 'pk'}) for r in rows ]
2479 2480 components_as_substances = property(_get_components_as_substances, lambda x:x) 2481 #--------------------------------------------------------
2482 - def _get_is_vaccine(self):
2483 cmd = u'SELECT EXISTS (SELECT 1 FROM clin.vaccine WHERE fk_brand = %(fk_brand)s)' 2484 args = {'fk_brand': self._payload[self._idx['pk_brand']]} 2485 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False) 2486 return rows[0][0]
2487 2488 is_vaccine = property(_get_is_vaccine, lambda x:x) 2489 #--------------------------------------------------------
2490 - def _get_is_in_use_by_patients(self):
2491 cmd = u""" 2492 SELECT EXISTS ( 2493 SELECT 1 2494 FROM clin.substance_intake 2495 WHERE 2496 fk_drug_component IS NOT NULL 2497 AND 2498 fk_drug_component IN ( 2499 SELECT r_ls2b.pk 2500 FROM ref.lnk_substance2brand r_ls2b 2501 WHERE fk_brand = %(pk)s 2502 ) 2503 LIMIT 1 2504 )""" 2505 args = {'pk': self.pk_obj} 2506 2507 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False) 2508 return rows[0][0]
2509 2510 is_in_use_by_patients = property(_get_is_in_use_by_patients, lambda x:x)
2511 #------------------------------------------------------------
2512 -def get_branded_drugs():
2513 cmd = u'SELECT pk FROM ref.branded_drug ORDER BY description' 2514 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = False) 2515 return [ cBrandedDrug(aPK_obj = r['pk']) for r in rows ]
2516 #------------------------------------------------------------
2517 -def get_drug_by_brand(brand_name=None, preparation=None):
2518 args = {'brand': brand_name, 'prep': preparation} 2519 2520 cmd = u'SELECT pk FROM ref.branded_drug WHERE lower(description) = lower(%(brand)s) AND lower(preparation) = lower(%(prep)s)' 2521 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False) 2522 2523 if len(rows) == 0: 2524 return None 2525 2526 return cBrandedDrug(aPK_obj = rows[0]['pk'])
2527 #------------------------------------------------------------
2528 -def create_branded_drug(brand_name=None, preparation=None, return_existing=False):
2529 2530 if preparation is None: 2531 preparation = _('units') 2532 2533 if preparation.strip() == u'': 2534 preparation = _('units') 2535 2536 if return_existing: 2537 drug = get_drug_by_brand(brand_name = brand_name, preparation = preparation) 2538 if drug is not None: 2539 return drug 2540 2541 cmd = u'INSERT INTO ref.branded_drug (description, preparation) VALUES (%(brand)s, %(prep)s) RETURNING pk' 2542 args = {'brand': brand_name, 'prep': preparation} 2543 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True, get_col_idx = False) 2544 2545 return cBrandedDrug(aPK_obj = rows[0]['pk'])
2546 #------------------------------------------------------------
2547 -def delete_branded_drug(brand=None):
2548 queries = [] 2549 args = {'pk': brand} 2550 2551 # delete components 2552 cmd = u""" 2553 DELETE FROM ref.lnk_substance2brand 2554 WHERE 2555 fk_brand = %(pk)s 2556 AND 2557 NOT EXISTS ( 2558 SELECT 1 2559 FROM clin.v_pat_substance_intake 2560 WHERE pk_brand = %(pk)s 2561 LIMIT 1 2562 ) 2563 """ 2564 queries.append({'cmd': cmd, 'args': args}) 2565 2566 # delete drug 2567 cmd = u""" 2568 DELETE FROM ref.branded_drug 2569 WHERE 2570 pk = %(pk)s 2571 AND 2572 NOT EXISTS ( 2573 SELECT 1 2574 FROM clin.v_pat_substance_intake 2575 WHERE pk_brand = %(pk)s 2576 LIMIT 1 2577 ) 2578 """ 2579 queries.append({'cmd': cmd, 'args': args}) 2580 2581 gmPG2.run_rw_queries(queries = queries)
2582 #============================================================ 2583 # main 2584 #------------------------------------------------------------ 2585 if __name__ == "__main__": 2586 2587 if len(sys.argv) < 2: 2588 sys.exit() 2589 2590 if sys.argv[1] != 'test': 2591 sys.exit() 2592 2593 from Gnumed.pycommon import gmLog2 2594 from Gnumed.pycommon import gmI18N 2595 from Gnumed.business import gmPerson 2596 2597 gmI18N.activate_locale() 2598 # gmDateTime.init() 2599 #--------------------------------------------------------
2600 - def test_MMI_interface():
2601 mmi = cGelbeListeWineInterface() 2602 print mmi 2603 print "interface definition:", mmi.version 2604 print "database versions: ", mmi.get_data_source_version()
2605 #--------------------------------------------------------
2606 - def test_MMI_file():
2607 mmi_file = cGelbeListeCSVFile(filename = sys.argv[2]) 2608 for drug in mmi_file: 2609 print "-------------" 2610 print '"%s" (ATC: %s / PZN: %s)' % (drug['name'], drug['atc'], drug['pzn']) 2611 for stoff in drug['wirkstoffe']: 2612 print " Wirkstoff:", stoff 2613 raw_input() 2614 if mmi_file.has_unknown_fields is not None: 2615 print "has extra data under [%s]" % gmTools.default_csv_reader_rest_key 2616 for key in mmi_file.csv_fieldnames: 2617 print key, '->', drug[key] 2618 raw_input() 2619 mmi_file.close()
2620 #--------------------------------------------------------
2621 - def test_mmi_switch_to():
2622 mmi = cGelbeListeWineInterface() 2623 mmi.switch_to_frontend(blocking = True)
2624 #--------------------------------------------------------
2625 - def test_mmi_let_user_select_drugs():
2626 mmi = cGelbeListeWineInterface() 2627 mmi_file = mmi.__let_user_select_drugs() 2628 for drug in mmi_file: 2629 print "-------------" 2630 print '"%s" (ATC: %s / PZN: %s)' % (drug['name'], drug['atc'], drug['pzn']) 2631 for stoff in drug['wirkstoffe']: 2632 print " Wirkstoff:", stoff 2633 print drug 2634 mmi_file.close()
2635 #--------------------------------------------------------
2636 - def test_mmi_import_drugs():
2637 mmi = cGelbeListeWineInterface() 2638 mmi.import_drugs()
2639 #--------------------------------------------------------
2640 - def test_mmi_interaction_check():
2641 mmi = cGelbeListeInterface() 2642 print mmi 2643 print "interface definition:", mmi.version 2644 # Metoprolol + Hct vs Citalopram 2645 diclofenac = '7587712' 2646 phenprocoumon = '4421744' 2647 mmi.check_interactions(drug_ids_list = [diclofenac, phenprocoumon])
2648 #-------------------------------------------------------- 2649 # FreeDiams 2650 #--------------------------------------------------------
2651 - def test_fd_switch_to():
2652 gmPerson.set_active_patient(patient = gmPerson.cIdentity(aPK_obj = 12)) 2653 fd = cFreeDiamsInterface() 2654 fd.patient = gmPerson.gmCurrentPatient() 2655 # fd.switch_to_frontend(blocking = True) 2656 fd.import_fd2gm_file_as_drugs(filename = sys.argv[2])
2657 #--------------------------------------------------------
2658 - def test_fd_show_interactions():
2659 gmPerson.set_active_patient(patient = gmPerson.cIdentity(aPK_obj = 12)) 2660 fd = cFreeDiamsInterface() 2661 fd.patient = gmPerson.gmCurrentPatient() 2662 fd.check_interactions(substances = fd.patient.get_emr().get_current_substance_intake(include_unapproved = True))
2663 #-------------------------------------------------------- 2664 # generic 2665 #--------------------------------------------------------
2666 - def test_create_substance_intake():
2667 drug = create_substance_intake ( 2668 pk_component = 2, 2669 encounter = 1, 2670 episode = 1 2671 ) 2672 print drug
2673 #--------------------------------------------------------
2674 - def test_show_components():
2675 drug = cBrandedDrug(aPK_obj = sys.argv[2]) 2676 print drug 2677 print drug.components
2678 #--------------------------------------------------------
2679 - def test_get_consumable_substances():
2680 for s in get_consumable_substances(): 2681 print s
2682 #--------------------------------------------------------
2683 - def test_drug2renal_insufficiency_url():
2684 drug2renal_insufficiency_url(search_term = 'Metoprolol')
2685 #-------------------------------------------------------- 2686 # MMI/Gelbe Liste 2687 #test_MMI_interface() 2688 #test_MMI_file() 2689 #test_mmi_switch_to() 2690 #test_mmi_let_user_select_drugs() 2691 #test_mmi_import_substances() 2692 #test_mmi_import_drugs() 2693 2694 # FreeDiams 2695 test_fd_switch_to() 2696 #test_fd_show_interactions() 2697 2698 # generic 2699 #test_interaction_check() 2700 #test_create_substance_intake() 2701 #test_show_components() 2702 #test_get_consumable_substances() 2703 2704 #test_drug2renal_insufficiency_url() 2705 #============================================================ 2706