Home | Trees | Indices | Help |
|
---|
|
1 # -*- coding: utf8 -*- 2 """GNUmed health related business object. 3 4 license: GPL 5 """ 6 #============================================================ 7 __version__ = "$Revision: 1.157 $" 8 __author__ = "Carlos Moro <cfmoro1976@yahoo.es>, <karsten.hilbert@gmx.net>" 9 10 import types, sys, string, datetime, logging, time 11 12 13 if __name__ == '__main__': 14 sys.path.insert(0, '../../') 15 from Gnumed.pycommon import gmPG2 16 from Gnumed.pycommon import gmI18N 17 from Gnumed.pycommon import gmTools 18 from Gnumed.pycommon import gmDateTime 19 from Gnumed.pycommon import gmBusinessDBObject 20 from Gnumed.pycommon import gmNull 21 from Gnumed.pycommon import gmExceptions 22 23 from Gnumed.business import gmClinNarrative 24 25 26 _log = logging.getLogger('gm.emr') 27 _log.info(__version__) 28 29 try: _ 30 except NameError: _ = lambda x:x 31 #============================================================ 32 # diagnostic certainty classification 33 #============================================================ 34 __diagnostic_certainty_classification_map = None 3537 38 global __diagnostic_certainty_classification_map 39 40 if __diagnostic_certainty_classification_map is None: 41 __diagnostic_certainty_classification_map = { 42 None: u'', 43 u'A': _(u'A: Sign'), 44 u'B': _(u'B: Cluster of signs'), 45 u'C': _(u'C: Syndromic diagnosis'), 46 u'D': _(u'D: Scientific diagnosis') 47 } 48 49 try: 50 return __diagnostic_certainty_classification_map[classification] 51 except KeyError: 52 return _(u'<%s>: unknown diagnostic certainty classification') % classification53 #============================================================ 54 # Health Issues API 55 #============================================================ 56 laterality2str = { 57 None: u'?', 58 u'na': u'', 59 u'sd': _('bilateral'), 60 u'ds': _('bilateral'), 61 u's': _('left'), 62 u'd': _('right') 63 } 64 65 #============================================================67 """Represents one health issue.""" 68 69 _cmd_fetch_payload = u"select *, xmin_health_issue from clin.v_health_issues where pk_health_issue=%s" 70 _cmds_store_payload = [ 71 u"""update clin.health_issue set 72 description = %(description)s, 73 summary = gm.nullify_empty_string(%(summary)s), 74 age_noted = %(age_noted)s, 75 laterality = gm.nullify_empty_string(%(laterality)s), 76 grouping = gm.nullify_empty_string(%(grouping)s), 77 diagnostic_certainty_classification = gm.nullify_empty_string(%(diagnostic_certainty_classification)s), 78 is_active = %(is_active)s, 79 clinically_relevant = %(clinically_relevant)s, 80 is_confidential = %(is_confidential)s, 81 is_cause_of_death = %(is_cause_of_death)s 82 where 83 pk = %(pk_health_issue)s and 84 xmin = %(xmin_health_issue)s""", 85 u"select xmin as xmin_health_issue from clin.health_issue where pk = %(pk_health_issue)s" 86 ] 87 _updatable_fields = [ 88 'description', 89 'summary', 90 'grouping', 91 'age_noted', 92 'laterality', 93 'is_active', 94 'clinically_relevant', 95 'is_confidential', 96 'is_cause_of_death', 97 'diagnostic_certainty_classification' 98 ] 99 #--------------------------------------------------------474 #============================================================100 - def __init__(self, aPK_obj=None, encounter=None, name='xxxDEFAULTxxx', patient=None, row=None):101 pk = aPK_obj 102 103 if (pk is not None) or (row is not None): 104 gmBusinessDBObject.cBusinessDBObject.__init__(self, aPK_obj=pk, row=row) 105 return 106 107 if patient is None: 108 cmd = u"""select *, xmin_health_issue from clin.v_health_issues 109 where 110 description = %(desc)s 111 and 112 pk_patient = (select fk_patient from clin.encounter where pk = %(enc)s)""" 113 else: 114 cmd = u"""select *, xmin_health_issue from clin.v_health_issues 115 where 116 description = %(desc)s 117 and 118 pk_patient = %(pat)s""" 119 120 queries = [{'cmd': cmd, 'args': {'enc': encounter, 'desc': name, 'pat': patient}}] 121 rows, idx = gmPG2.run_ro_queries(queries = queries, get_col_idx = True) 122 123 if len(rows) == 0: 124 raise gmExceptions.NoSuchBusinessObjectError, 'no health issue for [enc:%s::desc:%s::pat:%s]' % (encounter, name, patient) 125 126 pk = rows[0][0] 127 r = {'idx': idx, 'data': rows[0], 'pk_field': 'pk_health_issue'} 128 129 gmBusinessDBObject.cBusinessDBObject.__init__(self, row=r)130 #-------------------------------------------------------- 131 # external API 132 #--------------------------------------------------------134 """Method for issue renaming. 135 136 @param description 137 - the new descriptive name for the issue 138 @type description 139 - a string instance 140 """ 141 # sanity check 142 if not type(description) in [str, unicode] or description.strip() == '': 143 _log.error('<description> must be a non-empty string') 144 return False 145 # update the issue description 146 old_description = self._payload[self._idx['description']] 147 self._payload[self._idx['description']] = description.strip() 148 self._is_modified = True 149 successful, data = self.save_payload() 150 if not successful: 151 _log.error('cannot rename health issue [%s] with [%s]' % (self, description)) 152 self._payload[self._idx['description']] = old_description 153 return False 154 return True155 #--------------------------------------------------------157 cmd = u"SELECT * FROM clin.v_pat_episodes WHERE pk_health_issue = %(pk)s" 158 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': {'pk': self.pk_obj}}], get_col_idx = True) 159 return [ cEpisode(row = {'data': r, 'idx': idx, 'pk_field': 'pk_episode'}) for r in rows ]160 #--------------------------------------------------------162 """ttl in days""" 163 open_episode = self.get_open_episode() 164 if open_episode is None: 165 return True 166 earliest, latest = open_episode.get_access_range() 167 ttl = datetime.timedelta(ttl) 168 now = datetime.datetime.now(tz=latest.tzinfo) 169 if (latest + ttl) > now: 170 return False 171 open_episode['episode_open'] = False 172 success, data = open_episode.save_payload() 173 if success: 174 return True 175 return False # should be an exception176 #--------------------------------------------------------178 open_episode = self.get_open_episode() 179 open_episode['episode_open'] = False 180 success, data = open_episode.save_payload() 181 if success: 182 return True 183 return False184 #--------------------------------------------------------186 cmd = u"select exists (select 1 from clin.episode where fk_health_issue = %s and is_open is True)" 187 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': [self.pk_obj]}]) 188 return rows[0][0]189 #--------------------------------------------------------191 cmd = u"select pk from clin.episode where fk_health_issue = %s and is_open is True" 192 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': [self.pk_obj]}]) 193 if len(rows) == 0: 194 return None 195 return cEpisode(aPK_obj=rows[0][0])196 #--------------------------------------------------------198 if self._payload[self._idx['age_noted']] is None: 199 return u'<???>' 200 201 # since we've already got an interval we are bound to use it, 202 # further transformation will only introduce more errors, 203 # later we can improve this deeper inside 204 return gmDateTime.format_interval_medically(self._payload[self._idx['age_noted']])205 #--------------------------------------------------------207 rows = gmClinNarrative.get_as_journal ( 208 issues = (self.pk_obj,), 209 order_by = u'pk_episode, pk_encounter, clin_when, scr, src_table' 210 ) 211 212 if len(rows) == 0: 213 return u'' 214 215 left_margin = u' ' * left_margin 216 217 lines = [] 218 lines.append(_('Clinical data generated during encounters under this health issue:')) 219 220 prev_epi = None 221 for row in rows: 222 if row['pk_episode'] != prev_epi: 223 lines.append(u'') 224 prev_epi = row['pk_episode'] 225 226 when = row['clin_when'].strftime(date_format).decode(gmI18N.get_encoding()) 227 top_row = u'%s%s %s (%s) %s' % ( 228 gmTools.u_box_top_left_arc, 229 gmTools.u_box_horiz_single, 230 gmClinNarrative.soap_cat2l10n_str[row['real_soap_cat']], 231 when, 232 gmTools.u_box_horiz_single * 5 233 ) 234 soap = gmTools.wrap ( 235 text = row['narrative'], 236 width = 60, 237 initial_indent = u' ', 238 subsequent_indent = u' ' + left_margin 239 ) 240 row_ver = u'' 241 if row['row_version'] > 0: 242 row_ver = u'v%s: ' % row['row_version'] 243 bottom_row = u'%s%s %s, %s%s %s' % ( 244 u' ' * 40, 245 gmTools.u_box_horiz_light_heavy, 246 row['modified_by'], 247 row_ver, 248 row['date_modified'], 249 gmTools.u_box_horiz_heavy_light 250 ) 251 252 lines.append(top_row) 253 lines.append(soap) 254 lines.append(bottom_row) 255 256 eol_w_margin = u'\n%s' % left_margin 257 return left_margin + eol_w_margin.join(lines) + u'\n'258 #--------------------------------------------------------260 261 if patient.ID != self._payload[self._idx['pk_patient']]: 262 msg = '<patient>.ID = %s but health issue %s belongs to patient %s' % ( 263 patient.ID, 264 self._payload[self._idx['pk_health_issue']], 265 self._payload[self._idx['pk_patient']] 266 ) 267 raise ValueError(msg) 268 269 lines = [] 270 271 lines.append(_('Health Issue %s%s%s%s [#%s]') % ( 272 u'\u00BB', 273 self._payload[self._idx['description']], 274 u'\u00AB', 275 gmTools.coalesce ( 276 initial = self.laterality_description, 277 instead = u'', 278 template_initial = u' (%s)', 279 none_equivalents = [None, u'', u'?'] 280 ), 281 self._payload[self._idx['pk_health_issue']] 282 )) 283 284 if self._payload[self._idx['is_confidential']]: 285 lines.append('') 286 lines.append(_(' ***** CONFIDENTIAL *****')) 287 lines.append('') 288 289 if self._payload[self._idx['is_cause_of_death']]: 290 lines.append('') 291 lines.append(_(' contributed to death of patient')) 292 lines.append('') 293 294 enc = cEncounter(aPK_obj = self._payload[self._idx['pk_encounter']]) 295 lines.append (_(' Created during encounter: %s (%s - %s) [#%s]') % ( 296 enc['l10n_type'], 297 enc['started_original_tz'].strftime('%Y-%m-%d %H:%M'), 298 enc['last_affirmed_original_tz'].strftime('%H:%M'), 299 self._payload[self._idx['pk_encounter']] 300 )) 301 302 if self._payload[self._idx['age_noted']] is not None: 303 lines.append(_(' Noted at age: %s') % self.age_noted_human_readable()) 304 305 lines.append(u' ' + _('Status') + u': %s, %s%s' % ( 306 gmTools.bool2subst(self._payload[self._idx['is_active']], _('active'), _('inactive')), 307 gmTools.bool2subst(self._payload[self._idx['clinically_relevant']], _('clinically relevant'), _('not clinically relevant')), 308 gmTools.coalesce ( 309 initial = diagnostic_certainty_classification2str(self._payload[self._idx['diagnostic_certainty_classification']]), 310 instead = u'', 311 template_initial = u', %s', 312 none_equivalents = [None, u''] 313 ) 314 )) 315 316 if self._payload[self._idx['summary']] is not None: 317 lines.append(u'') 318 lines.append(gmTools.wrap ( 319 text = self._payload[self._idx['summary']], 320 width = 60, 321 initial_indent = u' ', 322 subsequent_indent = u' ' 323 )) 324 325 lines.append(u'') 326 327 emr = patient.get_emr() 328 329 # episodes 330 epis = emr.get_episodes(issues = [self._payload[self._idx['pk_health_issue']]]) 331 if epis is None: 332 lines.append(_('Error retrieving episodes for this health issue.')) 333 elif len(epis) == 0: 334 lines.append(_('There are no episodes for this health issue.')) 335 else: 336 lines.append ( 337 _('Episodes: %s (most recent: %s%s%s)') % ( 338 len(epis), 339 gmTools.u_left_double_angle_quote, 340 emr.get_most_recent_episode(issue = self._payload[self._idx['pk_health_issue']])['description'], 341 gmTools.u_right_double_angle_quote 342 ) 343 ) 344 lines.append('') 345 for epi in epis: 346 lines.append(u' \u00BB%s\u00AB (%s)' % ( 347 epi['description'], 348 gmTools.bool2subst(epi['episode_open'], _('ongoing'), _('closed')) 349 )) 350 351 lines.append('') 352 353 # encounters 354 first_encounter = emr.get_first_encounter(issue_id = self._payload[self._idx['pk_health_issue']]) 355 last_encounter = emr.get_last_encounter(issue_id = self._payload[self._idx['pk_health_issue']]) 356 357 if first_encounter is None or last_encounter is None: 358 lines.append(_('No encounters found for this health issue.')) 359 else: 360 encs = emr.get_encounters(issues = [self._payload[self._idx['pk_health_issue']]]) 361 lines.append(_('Encounters: %s (%s - %s):') % ( 362 len(encs), 363 first_encounter['started_original_tz'].strftime('%m/%Y'), 364 last_encounter['last_affirmed_original_tz'].strftime('%m/%Y') 365 )) 366 lines.append(_(' Most recent: %s - %s') % ( 367 last_encounter['started_original_tz'].strftime('%Y-%m-%d %H:%M'), 368 last_encounter['last_affirmed_original_tz'].strftime('%H:%M') 369 )) 370 371 # medications 372 meds = emr.get_current_substance_intake ( 373 issues = [ self._payload[self._idx['pk_health_issue']] ], 374 order_by = u'is_currently_active, started, substance' 375 ) 376 377 if len(meds) > 0: 378 lines.append(u'') 379 lines.append(_('Active medications: %s') % len(meds)) 380 for m in meds: 381 lines.append(m.format(left_margin = (left_margin + 1))) 382 del meds 383 384 # hospital stays 385 stays = emr.get_hospital_stays ( 386 issues = [ self._payload[self._idx['pk_health_issue']] ] 387 ) 388 389 if len(stays) > 0: 390 lines.append(u'') 391 lines.append(_('Hospital stays: %s') % len(stays)) 392 for s in stays: 393 lines.append(s.format(left_margin = (left_margin + 1))) 394 del stays 395 396 # procedures 397 procs = emr.get_performed_procedures ( 398 issues = [ self._payload[self._idx['pk_health_issue']] ] 399 ) 400 401 if len(procs) > 0: 402 lines.append(u'') 403 lines.append(_('Procedures performed: %s') % len(procs)) 404 for p in procs: 405 lines.append(p.format(left_margin = (left_margin + 1))) 406 del procs 407 408 epis = self.get_episodes() 409 if len(epis) > 0: 410 epi_pks = [ e['pk_episode'] for e in epis ] 411 412 # documents 413 doc_folder = patient.get_document_folder() 414 docs = doc_folder.get_documents(episodes = epi_pks) 415 if len(docs) > 0: 416 lines.append(u'') 417 lines.append(_('Documents: %s') % len(docs)) 418 del docs 419 420 # test results 421 tests = emr.get_test_results_by_date(episodes = epi_pks) 422 if len(tests) > 0: 423 lines.append(u'') 424 lines.append(_('Measurements and Results: %s') % len(tests)) 425 del tests 426 427 # vaccinations 428 vaccs = emr.get_vaccinations(episodes = epi_pks) 429 if len(vaccs) > 0: 430 lines.append(u'') 431 lines.append(_('Vaccinations:')) 432 for vacc in vaccs: 433 lines.extend(vacc.format(with_reaction = True)) 434 del vaccs 435 436 del epis 437 438 left_margin = u' ' * left_margin 439 eol_w_margin = u'\n%s' % left_margin 440 return left_margin + eol_w_margin.join(lines) + u'\n'441 #-------------------------------------------------------- 442 # properties 443 #-------------------------------------------------------- 444 episodes = property(get_episodes, lambda x:x) 445 #-------------------------------------------------------- 446 open_episode = property(get_open_episode, lambda x:x) 447 #--------------------------------------------------------449 cmd = u"""SELECT 450 coalesce ( 451 (SELECT pk FROM clin.episode WHERE fk_health_issue = %(issue)s AND is_open IS TRUE), 452 (SELECT pk FROM clin.v_pat_episodes WHERE fk_health_issue = %(issue)s ORDER BY last_affirmed DESC limit 1) 453 )""" 454 args = {'issue': self.pk_obj} 455 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False) 456 if len(rows) == 0: 457 return None 458 return cEpisode(aPK_obj = rows[0][0])459 460 latest_episode = property(_get_latest_episode, lambda x:x) 461 #--------------------------------------------------------463 try: 464 return laterality2str[self._payload[self._idx['laterality']]] 465 except KeyError: 466 return u'<???>'467 468 laterality_description = property(_get_laterality_description, lambda x:x) 469 #--------------------------------------------------------471 return diagnostic_certainty_classification2str(self._payload[self._idx['diagnostic_certainty_classification']])472 473 diagnostic_certainty_description = property(_get_diagnostic_certainty_description, lambda x:x)476 """Creates a new health issue for a given patient. 477 478 description - health issue name 479 """ 480 try: 481 h_issue = cHealthIssue(name = description, encounter = encounter, patient = patient) 482 return h_issue 483 except gmExceptions.NoSuchBusinessObjectError: 484 pass 485 486 queries = [] 487 cmd = u"insert into clin.health_issue (description, fk_encounter) values (%(desc)s, %(enc)s)" 488 queries.append({'cmd': cmd, 'args': {'desc': description, 'enc': encounter}}) 489 490 cmd = u"select currval('clin.health_issue_pk_seq')" 491 queries.append({'cmd': cmd}) 492 493 rows, idx = gmPG2.run_rw_queries(queries = queries, return_data = True) 494 h_issue = cHealthIssue(aPK_obj = rows[0][0]) 495 496 return h_issue497 #-----------------------------------------------------------499 if isinstance(health_issue, cHealthIssue): 500 pk = health_issue['pk_health_issue'] 501 else: 502 pk = int(health_issue) 503 504 try: 505 gmPG2.run_rw_queries(queries = [{'cmd': u'delete from clin.health_issue where pk=%(pk)s', 'args': {'pk': pk}}]) 506 except gmPG2.dbapi.IntegrityError: 507 # should be parsing pgcode/and or error message 508 _log.exception('cannot delete health issue') 509 raise gmExceptions.DatabaseObjectInUseError('cannot delete health issue, it is in use')510 #------------------------------------------------------------ 511 # use as dummy for unassociated episodes513 issue = { 514 'pk_health_issue': None, 515 'description': _('Unattributed episodes'), 516 'age_noted': None, 517 'laterality': u'na', 518 'is_active': True, 519 'clinically_relevant': True, 520 'is_confidential': None, 521 'is_cause_of_death': False, 522 'is_dummy': True, 523 'grouping': None 524 } 525 return issue526 #-----------------------------------------------------------528 return cProblem ( 529 aPK_obj = { 530 'pk_patient': health_issue['pk_patient'], 531 'pk_health_issue': health_issue['pk_health_issue'], 532 'pk_episode': None 533 }, 534 try_potential_problems = allow_irrelevant 535 )536 #============================================================ 537 # episodes API 538 #============================================================540 """Represents one clinical episode. 541 """ 542 _cmd_fetch_payload = u"select * from clin.v_pat_episodes where pk_episode=%s" 543 _cmds_store_payload = [ 544 u"""update clin.episode set 545 fk_health_issue = %(pk_health_issue)s, 546 is_open = %(episode_open)s::boolean, 547 description = %(description)s, 548 summary = gm.nullify_empty_string(%(summary)s), 549 diagnostic_certainty_classification = gm.nullify_empty_string(%(diagnostic_certainty_classification)s) 550 where 551 pk = %(pk_episode)s and 552 xmin = %(xmin_episode)s""", 553 u"""select xmin_episode from clin.v_pat_episodes where pk_episode = %(pk_episode)s""" 554 ] 555 _updatable_fields = [ 556 'pk_health_issue', 557 'episode_open', 558 'description', 559 'summary', 560 'diagnostic_certainty_classification' 561 ] 562 #--------------------------------------------------------943 #============================================================563 - def __init__(self, aPK_obj=None, id_patient=None, name='xxxDEFAULTxxx', health_issue=None, row=None, encounter=None):564 pk = aPK_obj 565 if pk is None and row is None: 566 567 where_parts = [u'description = %(desc)s'] 568 569 if id_patient is not None: 570 where_parts.append(u'pk_patient = %(pat)s') 571 572 if health_issue is not None: 573 where_parts.append(u'pk_health_issue = %(issue)s') 574 575 if encounter is not None: 576 where_parts.append(u'pk_patient = (select fk_patient from clin.encounter where pk = %(enc)s)') 577 578 args = { 579 'pat': id_patient, 580 'issue': health_issue, 581 'enc': encounter, 582 'desc': name 583 } 584 585 cmd = u"select * from clin.v_pat_episodes where %s" % u' and '.join(where_parts) 586 587 rows, idx = gmPG2.run_ro_queries( 588 queries = [{'cmd': cmd, 'args': args}], 589 get_col_idx=True 590 ) 591 592 if len(rows) == 0: 593 raise gmExceptions.NoSuchBusinessObjectError, 'no episode for [%s:%s:%s:%s]' % (id_patient, name, health_issue, encounter) 594 595 r = {'idx': idx, 'data': rows[0], 'pk_field': 'pk_episode'} 596 gmBusinessDBObject.cBusinessDBObject.__init__(self, row=r) 597 598 else: 599 gmBusinessDBObject.cBusinessDBObject.__init__(self, aPK_obj=pk, row=row)600 #-------------------------------------------------------- 601 # external API 602 #--------------------------------------------------------604 """Get earliest and latest access to this episode. 605 606 Returns a tuple(earliest, latest). 607 """ 608 cmd = u""" 609 select 610 min(earliest), 611 max(latest) 612 from ( 613 (select 614 (case when clin_when < modified_when 615 then clin_when 616 else modified_when 617 end) as earliest, 618 (case when clin_when > modified_when 619 then clin_when 620 else modified_when 621 end) as latest 622 from 623 clin.clin_root_item 624 where 625 fk_episode = %(pk)s 626 627 ) union all ( 628 629 select 630 modified_when as earliest, 631 modified_when as latest 632 from 633 clin.episode 634 where 635 pk = %(pk)s 636 ) 637 ) as ranges""" 638 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': {'pk': self.pk_obj}}]) 639 if len(rows) == 0: 640 return (gmNull.cNull(warn=False), gmNull.cNull(warn=False)) 641 return (rows[0][0], rows[0][1])642 #-------------------------------------------------------- 645 #--------------------------------------------------------647 return gmClinNarrative.get_narrative(soap_cats = None, encounters = encounters, episodes = [self.pk_obj])648 #--------------------------------------------------------650 """Method for episode editing, that is, episode renaming. 651 652 @param description 653 - the new descriptive name for the encounter 654 @type description 655 - a string instance 656 """ 657 # sanity check 658 if description.strip() == '': 659 _log.error('<description> must be a non-empty string instance') 660 return False 661 # update the episode description 662 old_description = self._payload[self._idx['description']] 663 self._payload[self._idx['description']] = description.strip() 664 self._is_modified = True 665 successful, data = self.save_payload() 666 if not successful: 667 _log.error('cannot rename episode [%s] to [%s]' % (self, description)) 668 self._payload[self._idx['description']] = old_description 669 return False 670 return True671 #--------------------------------------------------------673 rows = gmClinNarrative.get_as_journal ( 674 episodes = (self.pk_obj,), 675 order_by = u'pk_encounter, clin_when, scr, src_table' 676 #order_by = u'pk_encounter, scr, clin_when, src_table' 677 ) 678 679 if len(rows) == 0: 680 return u'' 681 682 lines = [] 683 684 lines.append(_('Clinical data generated during encounters within this episode:')) 685 686 left_margin = u' ' * left_margin 687 688 prev_enc = None 689 for row in rows: 690 if row['pk_encounter'] != prev_enc: 691 lines.append(u'') 692 prev_enc = row['pk_encounter'] 693 694 when = row['clin_when'].strftime(date_format).decode(gmI18N.get_encoding()) 695 top_row = u'%s%s %s (%s) %s' % ( 696 gmTools.u_box_top_left_arc, 697 gmTools.u_box_horiz_single, 698 gmClinNarrative.soap_cat2l10n_str[row['real_soap_cat']], 699 when, 700 gmTools.u_box_horiz_single * 5 701 ) 702 soap = gmTools.wrap ( 703 text = row['narrative'], 704 width = 60, 705 initial_indent = u' ', 706 subsequent_indent = u' ' + left_margin 707 ) 708 row_ver = u'' 709 if row['row_version'] > 0: 710 row_ver = u'v%s: ' % row['row_version'] 711 bottom_row = u'%s%s %s, %s%s %s' % ( 712 u' ' * 40, 713 gmTools.u_box_horiz_light_heavy, 714 row['modified_by'], 715 row_ver, 716 row['date_modified'], 717 gmTools.u_box_horiz_heavy_light 718 ) 719 720 lines.append(top_row) 721 lines.append(soap) 722 lines.append(bottom_row) 723 724 eol_w_margin = u'\n%s' % left_margin 725 return left_margin + eol_w_margin.join(lines) + u'\n'726 #--------------------------------------------------------728 729 if patient.ID != self._payload[self._idx['pk_patient']]: 730 msg = '<patient>.ID = %s but episode %s belongs to patient %s' % ( 731 patient.ID, 732 self._payload[self._idx['pk_episode']], 733 self._payload[self._idx['pk_patient']] 734 ) 735 raise ValueError(msg) 736 737 lines = [] 738 739 # episode details 740 lines.append (_('Episode %s%s%s (%s%s) [#%s]\n') % ( 741 gmTools.u_left_double_angle_quote, 742 self._payload[self._idx['description']], 743 gmTools.u_right_double_angle_quote, 744 gmTools.coalesce ( 745 initial = diagnostic_certainty_classification2str(self._payload[self._idx['diagnostic_certainty_classification']]), 746 instead = u'', 747 template_initial = u'%s, ', 748 none_equivalents = [None, u''] 749 ), 750 gmTools.bool2subst(self._payload[self._idx['episode_open']], _('active'), _('finished')), 751 self._payload[self._idx['pk_episode']] 752 )) 753 754 enc = cEncounter(aPK_obj = self._payload[self._idx['pk_encounter']]) 755 lines.append (_('Created during encounter: %s (%s - %s) [#%s]\n') % ( 756 enc['l10n_type'], 757 enc['started_original_tz'].strftime('%Y-%m-%d %H:%M'), 758 enc['last_affirmed_original_tz'].strftime('%H:%M'), 759 self._payload[self._idx['pk_encounter']] 760 )) 761 762 if self._payload[self._idx['summary']] is not None: 763 lines.append(gmTools.wrap ( 764 text = self._payload[self._idx['summary']], 765 width = 60, 766 initial_indent = u' ', 767 subsequent_indent = u' ' 768 ) 769 ) 770 lines.append(u'') 771 772 # encounters 773 emr = patient.get_emr() 774 encs = emr.get_encounters(episodes = [self._payload[self._idx['pk_episode']]]) 775 first_encounter = None 776 last_encounter = None 777 if encs is None: 778 lines.append(_('Error retrieving encounters for this episode.')) 779 elif len(encs) == 0: 780 lines.append(_('There are no encounters for this episode.')) 781 else: 782 first_encounter = emr.get_first_encounter(episode_id = self._payload[self._idx['pk_episode']]) 783 last_encounter = emr.get_last_encounter(episode_id = self._payload[self._idx['pk_episode']]) 784 785 lines.append(_('Last worked on: %s\n') % last_encounter['last_affirmed_original_tz'].strftime('%Y-%m-%d %H:%M')) 786 787 lines.append(_('1st and (up to 3) most recent (of %s) encounters (%s - %s):') % ( 788 len(encs), 789 first_encounter['started'].strftime('%m/%Y'), 790 last_encounter['last_affirmed'].strftime('%m/%Y') 791 )) 792 793 lines.append(u' %s - %s (%s):%s' % ( 794 first_encounter['started_original_tz'].strftime('%Y-%m-%d %H:%M'), 795 first_encounter['last_affirmed_original_tz'].strftime('%H:%M'), 796 first_encounter['l10n_type'], 797 gmTools.coalesce ( 798 first_encounter['assessment_of_encounter'], 799 gmTools.coalesce ( 800 first_encounter['reason_for_encounter'], 801 u'', 802 u' \u00BB%s\u00AB' + (u' (%s)' % _('RFE')) 803 ), 804 u' \u00BB%s\u00AB' + (u' (%s)' % _('AOE')) 805 ) 806 )) 807 808 if len(encs) > 4: 809 lines.append(_(' ... %s skipped ...') % (len(encs) - 4)) 810 811 for enc in encs[1:][-3:]: 812 lines.append(u' %s - %s (%s):%s' % ( 813 enc['started_original_tz'].strftime('%Y-%m-%d %H:%M'), 814 enc['last_affirmed_original_tz'].strftime('%H:%M'), 815 enc['l10n_type'], 816 gmTools.coalesce ( 817 enc['assessment_of_encounter'], 818 gmTools.coalesce ( 819 enc['reason_for_encounter'], 820 u'', 821 u' \u00BB%s\u00AB' + (u' (%s)' % _('RFE')) 822 ), 823 u' \u00BB%s\u00AB' + (u' (%s)' % _('AOE')) 824 ) 825 )) 826 del encs 827 828 # spell out last encounter 829 if last_encounter is not None: 830 lines.append('') 831 lines.append(_('Progress notes in most recent encounter:')) 832 lines.extend(last_encounter.format_soap ( 833 episodes = [ self._payload[self._idx['pk_episode']] ], 834 left_margin = left_margin, 835 soap_cats = 'soap', 836 emr = emr 837 )) 838 839 # documents 840 doc_folder = patient.get_document_folder() 841 docs = doc_folder.get_documents ( 842 episodes = [ self._payload[self._idx['pk_episode']] ] 843 ) 844 845 if len(docs) > 0: 846 lines.append('') 847 lines.append(_('Documents: %s') % len(docs)) 848 849 for d in docs: 850 lines.append(u' %s %s:%s%s' % ( 851 d['clin_when'].strftime('%Y-%m-%d'), 852 d['l10n_type'], 853 gmTools.coalesce(d['comment'], u'', u' "%s"'), 854 gmTools.coalesce(d['ext_ref'], u'', u' (%s)') 855 )) 856 del docs 857 858 # hospital stays 859 stays = emr.get_hospital_stays ( 860 episodes = [ self._payload[self._idx['pk_episode']] ] 861 ) 862 863 if len(stays) > 0: 864 lines.append('') 865 lines.append(_('Hospital stays: %s') % len(stays)) 866 867 for s in stays: 868 lines.append(s.format(left_margin = (left_margin + 1))) 869 del stays 870 871 # procedures 872 procs = emr.get_performed_procedures ( 873 episodes = [ self._payload[self._idx['pk_episode']] ] 874 ) 875 876 if len(procs) > 0: 877 lines.append(u'') 878 lines.append(_('Procedures performed: %s') % len(procs)) 879 for p in procs: 880 lines.append(p.format(left_margin = (left_margin + 1), include_episode = False)) 881 del procs 882 883 # test results 884 tests = emr.get_test_results_by_date(episodes = [ self._payload[self._idx['pk_episode']] ]) 885 886 if len(tests) > 0: 887 lines.append('') 888 lines.append(_('Measurements and Results:')) 889 890 for t in tests: 891 lines.extend(t.format ( 892 with_review = False, 893 with_comments = False, 894 date_format = '%Y-%m-%d' 895 )) 896 del tests 897 898 # vaccinations 899 vaccs = emr.get_vaccinations(episodes = [ self._payload[self._idx['pk_episode']] ]) 900 901 if len(vaccs) > 0: 902 lines.append(u'') 903 lines.append(_('Vaccinations:')) 904 905 for vacc in vaccs: 906 lines.extend(vacc.format ( 907 with_indications = True, 908 with_comment = True, 909 with_reaction = True, 910 date_format = '%Y-%m-%d' 911 )) 912 del vaccs 913 914 left_margin = u' ' * left_margin 915 eol_w_margin = u'\n%s' % left_margin 916 return left_margin + eol_w_margin.join(lines) + u'\n'917 #-------------------------------------------------------- 918 # properties 919 #--------------------------------------------------------921 return diagnostic_certainty_classification2str(self._payload[self._idx['diagnostic_certainty_classification']])922 923 diagnostic_certainty_description = property(_get_diagnostic_certainty_description, lambda x:x) 924 #--------------------------------------------------------926 cmd = u"""SELECT EXISTS ( 927 SELECT 1 FROM clin.clin_narrative 928 WHERE 929 fk_episode = %(epi)s 930 AND 931 fk_encounter IN ( 932 SELECT pk FROM clin.encounter WHERE fk_patient = %(pat)s 933 ) 934 )""" 935 args = { 936 u'pat': self._payload[self._idx['pk_patient']], 937 u'epi': self._payload[self._idx['pk_episode']] 938 } 939 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False) 940 return rows[0][0]941 942 has_narrative = property(_get_has_narrative, lambda x:x)944 -def create_episode(pk_health_issue=None, episode_name=None, is_open=False, allow_dupes=False, encounter=None):945 """Creates a new episode for a given patient's health issue. 946 947 pk_health_issue - given health issue PK 948 episode_name - name of episode 949 """ 950 if not allow_dupes: 951 try: 952 episode = cEpisode(name=episode_name, health_issue=pk_health_issue, encounter = encounter) 953 if episode['episode_open'] != is_open: 954 episode['episode_open'] = is_open 955 episode.save_payload() 956 return episode 957 except gmExceptions.ConstructorError: 958 pass 959 960 queries = [] 961 cmd = u"insert into clin.episode (fk_health_issue, description, is_open, fk_encounter) values (%s, %s, %s::boolean, %s)" 962 queries.append({'cmd': cmd, 'args': [pk_health_issue, episode_name, is_open, encounter]}) 963 queries.append({'cmd': cEpisode._cmd_fetch_payload % u"currval('clin.episode_pk_seq')"}) 964 rows, idx = gmPG2.run_rw_queries(queries = queries, return_data=True, get_col_idx=True) 965 966 episode = cEpisode(row={'data': rows[0], 'idx': idx, 'pk_field': 'pk_episode'}) 967 return episode968 #-----------------------------------------------------------970 if isinstance(episode, cEpisode): 971 pk = episode['pk_episode'] 972 else: 973 pk = int(episode) 974 975 try: 976 gmPG2.run_rw_queries(queries = [{'cmd': u'delete from clin.episode where pk=%(pk)s', 'args': {'pk': pk}}]) 977 except gmPG2.dbapi.IntegrityError: 978 # should be parsing pgcode/and or error message 979 _log.exception('cannot delete episode') 980 raise gmExceptions.DatabaseObjectInUseError('cannot delete episode, it is in use')981 #-----------------------------------------------------------983 return cProblem ( 984 aPK_obj = { 985 'pk_patient': episode['pk_patient'], 986 'pk_episode': episode['pk_episode'], 987 'pk_health_issue': episode['pk_health_issue'] 988 }, 989 try_potential_problems = allow_closed 990 )991 #============================================================ 992 # encounter API 993 #============================================================995 """Represents one encounter.""" 996 997 _cmd_fetch_payload = u"select * from clin.v_pat_encounters where pk_encounter = %s" 998 _cmds_store_payload = [ 999 u"""update clin.encounter set 1000 started = %(started)s, 1001 last_affirmed = %(last_affirmed)s, 1002 fk_location = %(pk_location)s, 1003 fk_type = %(pk_type)s, 1004 reason_for_encounter = gm.nullify_empty_string(%(reason_for_encounter)s), 1005 assessment_of_encounter = gm.nullify_empty_string(%(assessment_of_encounter)s) 1006 where 1007 pk = %(pk_encounter)s and 1008 xmin = %(xmin_encounter)s""", 1009 u"""select xmin_encounter from clin.v_pat_encounters where pk_encounter=%(pk_encounter)s""" 1010 ] 1011 _updatable_fields = [ 1012 'started', 1013 'last_affirmed', 1014 'pk_location', 1015 'pk_type', 1016 'reason_for_encounter', 1017 'assessment_of_encounter' 1018 ] 1019 #--------------------------------------------------------1450 #-----------------------------------------------------------1021 """Set the enconter as the active one. 1022 1023 "Setting active" means making sure the encounter 1024 row has the youngest "last_affirmed" timestamp of 1025 all encounter rows for this patient. 1026 """ 1027 self['last_affirmed'] = gmDateTime.pydt_now_here() 1028 self.save()1029 #--------------------------------------------------------1031 """ 1032 Moves every element currently linked to the current encounter 1033 and the source_episode onto target_episode. 1034 1035 @param source_episode The episode the elements are currently linked to. 1036 @type target_episode A cEpisode intance. 1037 @param target_episode The episode the elements will be relinked to. 1038 @type target_episode A cEpisode intance. 1039 """ 1040 if source_episode['pk_episode'] == target_episode['pk_episode']: 1041 return True 1042 1043 queries = [] 1044 cmd = u""" 1045 UPDATE clin.clin_root_item 1046 SET fk_episode = %(trg)s 1047 WHERE 1048 fk_encounter = %(enc)s AND 1049 fk_episode = %(src)s 1050 """ 1051 rows, idx = gmPG2.run_rw_queries(queries = [{ 1052 'cmd': cmd, 1053 'args': { 1054 'trg': target_episode['pk_episode'], 1055 'enc': self.pk_obj, 1056 'src': source_episode['pk_episode'] 1057 } 1058 }]) 1059 self.refetch_payload() 1060 return True1061 #--------------------------------------------------------1063 1064 relevant_fields = [ 1065 'pk_location', 1066 'pk_type', 1067 'pk_patient', 1068 'reason_for_encounter', 1069 'assessment_of_encounter' 1070 ] 1071 for field in relevant_fields: 1072 if self._payload[self._idx[field]] != another_object[field]: 1073 _log.debug('mismatch on [%s]: "%s" vs. "%s"', field, self._payload[self._idx[field]], another_object[field]) 1074 return False 1075 1076 relevant_fields = [ 1077 'started', 1078 'last_affirmed', 1079 ] 1080 for field in relevant_fields: 1081 if self._payload[self._idx[field]] is None: 1082 if another_object[field] is None: 1083 continue 1084 _log.debug('mismatch on [%s]: "%s" vs. "%s"', field, self._payload[self._idx[field]], another_object[field]) 1085 return False 1086 1087 if another_object[field] is None: 1088 return False 1089 1090 #if self._payload[self._idx[field]].strftime('%Y-%m-%d %H:%M:%S %Z') != another_object[field].strftime('%Y-%m-%d %H:%M:%S %Z'): 1091 if self._payload[self._idx[field]].strftime('%Y-%m-%d %H:%M') != another_object[field].strftime('%Y-%m-%d %H:%M'): 1092 _log.debug('mismatch on [%s]: "%s" vs. "%s"', field, self._payload[self._idx[field]], another_object[field]) 1093 return False 1094 1095 return True1096 #--------------------------------------------------------1098 cmd = u""" 1099 select exists ( 1100 select 1 from clin.v_pat_items where pk_patient = %(pat)s and pk_encounter = %(enc)s 1101 union all 1102 select 1 from blobs.v_doc_med where pk_patient = %(pat)s and pk_encounter = %(enc)s 1103 )""" 1104 args = { 1105 'pat': self._payload[self._idx['pk_patient']], 1106 'enc': self.pk_obj 1107 } 1108 rows, idx = gmPG2.run_ro_queries ( 1109 queries = [{ 1110 'cmd': cmd, 1111 'args': args 1112 }] 1113 ) 1114 return rows[0][0]1115 #--------------------------------------------------------1117 cmd = u""" 1118 select exists ( 1119 select 1 from clin.v_pat_items where pk_patient=%(pat)s and pk_encounter=%(enc)s 1120 )""" 1121 args = { 1122 'pat': self._payload[self._idx['pk_patient']], 1123 'enc': self.pk_obj 1124 } 1125 rows, idx = gmPG2.run_ro_queries ( 1126 queries = [{ 1127 'cmd': cmd, 1128 'args': args 1129 }] 1130 ) 1131 return rows[0][0]1132 #--------------------------------------------------------1134 cmd = u""" 1135 select exists ( 1136 select 1 from blobs.v_doc_med where pk_patient = %(pat)s and pk_encounter = %(enc)s 1137 )""" 1138 args = { 1139 'pat': self._payload[self._idx['pk_patient']], 1140 'enc': self.pk_obj 1141 } 1142 rows, idx = gmPG2.run_ro_queries ( 1143 queries = [{ 1144 'cmd': cmd, 1145 'args': args 1146 }] 1147 ) 1148 return rows[0][0]1149 #--------------------------------------------------------1151 1152 if soap_cat is not None: 1153 soap_cat = soap_cat.lower() 1154 1155 if episode is None: 1156 epi_part = u'fk_episode is null' 1157 else: 1158 epi_part = u'fk_episode = %(epi)s' 1159 1160 cmd = u""" 1161 select narrative 1162 from clin.clin_narrative 1163 where 1164 fk_encounter = %%(enc)s 1165 and 1166 soap_cat = %%(cat)s 1167 and 1168 %s 1169 order by clin_when desc 1170 limit 1 1171 """ % epi_part 1172 1173 args = {'enc': self.pk_obj, 'cat': soap_cat, 'epi': episode} 1174 1175 rows, idx = gmPG2.run_ro_queries ( 1176 queries = [{ 1177 'cmd': cmd, 1178 'args': args 1179 }] 1180 ) 1181 if len(rows) == 0: 1182 return None 1183 1184 return rows[0][0]1185 #--------------------------------------------------------1187 cmd = u""" 1188 SELECT * FROM clin.v_pat_episodes 1189 WHERE 1190 pk_episode IN ( 1191 1192 SELECT DISTINCT fk_episode 1193 FROM clin.clin_root_item 1194 WHERE fk_encounter = %%(enc)s 1195 1196 UNION 1197 1198 SELECT DISTINCT fk_episode 1199 FROM blobs.doc_med 1200 WHERE fk_encounter = %%(enc)s 1201 ) 1202 %s""" 1203 args = {'enc': self.pk_obj} 1204 if exclude is not None: 1205 cmd = cmd % u'AND pk_episode NOT IN %(excluded)s' 1206 args['excluded'] = tuple(exclude) 1207 else: 1208 cmd = cmd % u'' 1209 1210 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True) 1211 1212 return [ cEpisode(row = {'data': r, 'idx': idx, 'pk_field': 'pk_episode'}) for r in rows ]1213 #--------------------------------------------------------1214 - def format_soap(self, episodes=None, left_margin=0, soap_cats='soap', emr=None, issues=None):1215 1216 lines = [] 1217 for soap_cat in soap_cats: 1218 soap_cat_narratives = emr.get_clin_narrative ( 1219 episodes = episodes, 1220 issues = issues, 1221 encounters = [self._payload[self._idx['pk_encounter']]], 1222 soap_cats = [soap_cat] 1223 ) 1224 if soap_cat_narratives is None: 1225 continue 1226 if len(soap_cat_narratives) == 0: 1227 continue 1228 1229 lines.append(u'-- %s ----------' % gmClinNarrative.soap_cat2l10n_str[soap_cat]) 1230 for soap_entry in soap_cat_narratives: 1231 txt = gmTools.wrap ( 1232 text = u'%s\n (%.8s %s)' % ( 1233 soap_entry['narrative'], 1234 soap_entry['provider'], 1235 soap_entry['date'].strftime('%Y-%m-%d %H:%M') 1236 ), 1237 width = 75, 1238 initial_indent = u'', 1239 subsequent_indent = (u' ' * left_margin) 1240 ) 1241 lines.append(txt) 1242 lines.append('') 1243 1244 return lines1245 #--------------------------------------------------------1247 1248 if date_format is None: 1249 date_format = '%A, %B %d %Y' 1250 1251 tex = u'\\multicolumn{2}{l}{%s: %s ({\\footnotesize %s - %s})} \\tabularnewline \n' % ( 1252 gmTools.tex_escape_string(self._payload[self._idx['l10n_type']]), 1253 self._payload[self._idx['started']].strftime(date_format).decode(gmI18N.get_encoding()), 1254 self._payload[self._idx['started']].strftime('%H:%M'), 1255 self._payload[self._idx['last_affirmed']].strftime('%H:%M') 1256 ) 1257 tex += u'\\hline \\tabularnewline \n' 1258 1259 for epi in self.get_episodes(): 1260 soaps = epi.get_narrative(soap_cats = soap_cats, encounters = [self.pk_obj]) 1261 if len(soaps) == 0: 1262 continue 1263 tex += u'\\multicolumn{2}{l}{\\emph{%s%s%s%s}} \\tabularnewline \n' % ( 1264 # tex += u' & \\emph{%s%s%s%s} \\tabularnewline \n' % ( 1265 gmTools.tex_escape_string(epi['description']), 1266 gmTools.coalesce ( 1267 initial = diagnostic_certainty_classification2str(epi['diagnostic_certainty_classification']), 1268 instead = u'', 1269 template_initial = u' {\\footnotesize [%s]}', 1270 none_equivalents = [None, u''] 1271 ), 1272 gmTools.tex_escape_string(gmTools.coalesce(epi['health_issue'], u'', u' (%s)')), 1273 gmTools.coalesce ( 1274 initial = diagnostic_certainty_classification2str(epi['diagnostic_certainty_classification_issue']), 1275 instead = u'', 1276 template_initial = u' {\\footnotesize [%s]}', 1277 none_equivalents = [None, u''] 1278 ), 1279 ) 1280 for soap in soaps: 1281 tex += u'{\\small %s} & {\\small %s} \\tabularnewline \n' % ( 1282 gmClinNarrative.soap_cat2l10n[soap['soap_cat']], 1283 gmTools.tex_escape_string(soap['narrative'].strip(u'\n')) 1284 ) 1285 tex += u' & \\tabularnewline \n' 1286 1287 if self._payload[self._idx['reason_for_encounter']] is not None: 1288 tex += u'%s & %s \\tabularnewline \n' % ( 1289 gmTools.tex_escape_string(_('RFE')), 1290 gmTools.tex_escape_string(self._payload[self._idx['reason_for_encounter']]) 1291 ) 1292 if self._payload[self._idx['assessment_of_encounter']] is not None: 1293 tex += u'%s & %s \\tabularnewline \n' % ( 1294 gmTools.tex_escape_string(_('AOE')), 1295 gmTools.tex_escape_string(self._payload[self._idx['assessment_of_encounter']]) 1296 ) 1297 1298 tex += u'\\hline \\tabularnewline \n' 1299 tex += u' & \\tabularnewline \n' 1300 1301 return tex1302 #--------------------------------------------------------1303 - def format(self, episodes=None, with_soap=False, left_margin=0, patient=None, issues=None, with_docs=True, with_tests=True, fancy_header=True, with_vaccinations=True, with_co_encountlet_hints=False, with_rfe_aoe=False):1304 """Format an encounter. 1305 1306 with_co_encountlet_hints: 1307 - whether to include which *other* episodes were discussed during this encounter 1308 - (only makes sense if episodes != None) 1309 """ 1310 lines = [] 1311 1312 if fancy_header: 1313 lines.append(u'%s%s: %s - %s (@%s)%s [#%s]' % ( 1314 u' ' * left_margin, 1315 self._payload[self._idx['l10n_type']], 1316 self._payload[self._idx['started_original_tz']].strftime('%Y-%m-%d %H:%M'), 1317 self._payload[self._idx['last_affirmed_original_tz']].strftime('%H:%M'), 1318 self._payload[self._idx['source_time_zone']], 1319 gmTools.coalesce(self._payload[self._idx['assessment_of_encounter']], u'', u' \u00BB%s\u00AB'), 1320 self._payload[self._idx['pk_encounter']] 1321 )) 1322 1323 lines.append(_(' your time: %s - %s (@%s = %s%s)\n') % ( 1324 self._payload[self._idx['started']].strftime('%Y-%m-%d %H:%M'), 1325 self._payload[self._idx['last_affirmed']].strftime('%H:%M'), 1326 gmDateTime.current_local_iso_numeric_timezone_string, 1327 gmTools.bool2subst ( 1328 gmDateTime.dst_currently_in_effect, 1329 gmDateTime.py_dst_timezone_name, 1330 gmDateTime.py_timezone_name 1331 ), 1332 gmTools.bool2subst(gmDateTime.dst_currently_in_effect, u' - ' + _('daylight savings time in effect'), u'') 1333 )) 1334 1335 if self._payload[self._idx['reason_for_encounter']] is not None: 1336 lines.append(u'%s: %s' % (_('RFE'), self._payload[self._idx['reason_for_encounter']])) 1337 1338 if self._payload[self._idx['assessment_of_encounter']] is not None: 1339 lines.append(u'%s: %s' % (_('AOE'), self._payload[self._idx['assessment_of_encounter']])) 1340 1341 else: 1342 lines.append(u'%s%s: %s - %s%s' % ( 1343 u' ' * left_margin, 1344 self._payload[self._idx['l10n_type']], 1345 self._payload[self._idx['started_original_tz']].strftime('%Y-%m-%d %H:%M'), 1346 self._payload[self._idx['last_affirmed_original_tz']].strftime('%H:%M'), 1347 gmTools.coalesce(self._payload[self._idx['assessment_of_encounter']], u'', u' \u00BB%s\u00AB') 1348 )) 1349 if with_rfe_aoe: 1350 if self._payload[self._idx['reason_for_encounter']] is not None: 1351 lines.append(u'%s: %s' % (_('RFE'), self._payload[self._idx['reason_for_encounter']])) 1352 if self._payload[self._idx['assessment_of_encounter']] is not None: 1353 lines.append(u'%s: %s' % (_('AOE'), self._payload[self._idx['assessment_of_encounter']])) 1354 1355 if with_soap: 1356 lines.append(u'') 1357 1358 if patient.ID != self._payload[self._idx['pk_patient']]: 1359 msg = '<patient>.ID = %s but encounter %s belongs to patient %s' % ( 1360 patient.ID, 1361 self._payload[self._idx['pk_encounter']], 1362 self._payload[self._idx['pk_patient']] 1363 ) 1364 raise ValueError(msg) 1365 1366 emr = patient.get_emr() 1367 1368 lines.extend(self.format_soap ( 1369 episodes = episodes, 1370 left_margin = left_margin, 1371 soap_cats = 'soap', 1372 emr = emr, 1373 issues = issues 1374 )) 1375 1376 # test results 1377 if with_tests: 1378 tests = emr.get_test_results_by_date ( 1379 episodes = episodes, 1380 encounter = self._payload[self._idx['pk_encounter']] 1381 ) 1382 if len(tests) > 0: 1383 lines.append('') 1384 lines.append(_('Measurements and Results:')) 1385 1386 for t in tests: 1387 lines.extend(t.format()) 1388 1389 del tests 1390 1391 # vaccinations 1392 if with_vaccinations: 1393 vaccs = emr.get_vaccinations ( 1394 episodes = episodes, 1395 encounters = [ self._payload[self._idx['pk_encounter']] ] 1396 ) 1397 1398 if len(vaccs) > 0: 1399 lines.append(u'') 1400 lines.append(_('Vaccinations:')) 1401 1402 for vacc in vaccs: 1403 lines.extend(vacc.format ( 1404 with_indications = True, 1405 with_comment = True, 1406 with_reaction = True, 1407 date_format = '%Y-%m-%d' 1408 )) 1409 del vaccs 1410 1411 # documents 1412 if with_docs: 1413 doc_folder = patient.get_document_folder() 1414 docs = doc_folder.get_documents ( 1415 episodes = episodes, 1416 encounter = self._payload[self._idx['pk_encounter']] 1417 ) 1418 1419 if len(docs) > 0: 1420 lines.append(u'') 1421 lines.append(_('Documents:')) 1422 1423 for d in docs: 1424 lines.append(u' %s %s:%s%s' % ( 1425 d['clin_when'].strftime('%Y-%m-%d'), 1426 d['l10n_type'], 1427 gmTools.coalesce(d['comment'], u'', u' "%s"'), 1428 gmTools.coalesce(d['ext_ref'], u'', u' (%s)') 1429 )) 1430 1431 del docs 1432 1433 # co-encountlets 1434 if with_co_encountlet_hints: 1435 if episodes is not None: 1436 other_epis = self.get_episodes(exclude = episodes) 1437 if len(other_epis) > 0: 1438 lines.append(u'') 1439 lines.append(_('%s other episodes touched upon during this encounter:') % len(other_epis)) 1440 for epi in other_epis: 1441 lines.append(u' %s%s%s%s' % ( 1442 gmTools.u_left_double_angle_quote, 1443 epi['description'], 1444 gmTools.u_right_double_angle_quote, 1445 gmTools.coalesce(epi['health_issue'], u'', u' (%s)') 1446 )) 1447 1448 eol_w_margin = u'\n%s' % (u' ' * left_margin) 1449 return u'%s\n' % eol_w_margin.join(lines)1452 """Creates a new encounter for a patient. 1453 1454 fk_patient - patient PK 1455 fk_location - encounter location 1456 enc_type - type of encounter 1457 1458 FIXME: we don't deal with location yet 1459 """ 1460 if enc_type is None: 1461 enc_type = u'in surgery' 1462 # insert new encounter 1463 queries = [] 1464 try: 1465 enc_type = int(enc_type) 1466 cmd = u""" 1467 insert into clin.encounter ( 1468 fk_patient, fk_location, fk_type 1469 ) values ( 1470 %s, -1, %s 1471 )""" 1472 except ValueError: 1473 enc_type = enc_type 1474 cmd = u""" 1475 insert into clin.encounter ( 1476 fk_patient, fk_location, fk_type 1477 ) values ( 1478 %s, -1, coalesce((select pk from clin.encounter_type where description=%s), 0) 1479 )""" 1480 queries.append({'cmd': cmd, 'args': [fk_patient, enc_type]}) 1481 queries.append({'cmd': cEncounter._cmd_fetch_payload % u"currval('clin.encounter_pk_seq')"}) 1482 rows, idx = gmPG2.run_rw_queries(queries=queries, return_data=True, get_col_idx=True) 1483 encounter = cEncounter(row={'data': rows[0], 'idx': idx, 'pk_field': 'pk_encounter'}) 1484 1485 return encounter1486 #-----------------------------------------------------------1488 1489 rows, idx = gmPG2.run_rw_queries( 1490 queries = [{ 1491 'cmd': u"select i18n.upd_tx(%(desc)s, %(l10n_desc)s)", 1492 'args': {'desc': description, 'l10n_desc': l10n_description} 1493 }], 1494 return_data = True 1495 ) 1496 1497 success = rows[0][0] 1498 if not success: 1499 _log.warning('updating encounter type [%s] to [%s] failed', description, l10n_description) 1500 1501 return {'description': description, 'l10n_description': l10n_description}1502 #-----------------------------------------------------------1504 """This will attempt to create a NEW encounter type.""" 1505 1506 # need a system name, so derive one if necessary 1507 if description is None: 1508 description = l10n_description 1509 1510 args = { 1511 'desc': description, 1512 'l10n_desc': l10n_description 1513 } 1514 1515 _log.debug('creating encounter type: %s, %s', description, l10n_description) 1516 1517 # does it exist already ? 1518 cmd = u"select description, _(description) from clin.encounter_type where description = %(desc)s" 1519 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}]) 1520 1521 # yes 1522 if len(rows) > 0: 1523 # both system and l10n name are the same so all is well 1524 if (rows[0][0] == description) and (rows[0][1] == l10n_description): 1525 _log.info('encounter type [%s] already exists with the proper translation') 1526 return {'description': description, 'l10n_description': l10n_description} 1527 1528 # or maybe there just wasn't a translation to 1529 # the current language for this type yet ? 1530 cmd = u"select exists (select 1 from i18n.translations where orig = %(desc)s and lang = i18n.get_curr_lang())" 1531 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}]) 1532 1533 # there was, so fail 1534 if rows[0][0]: 1535 _log.error('encounter type [%s] already exists but with another translation') 1536 return None 1537 1538 # else set it 1539 cmd = u"select i18n.upd_tx(%(desc)s, %(l10n_desc)s)" 1540 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}]) 1541 return {'description': description, 'l10n_description': l10n_description} 1542 1543 # no 1544 queries = [ 1545 {'cmd': u"insert into clin.encounter_type (description) values (%(desc)s)", 'args': args}, 1546 {'cmd': u"select i18n.upd_tx(%(desc)s, %(l10n_desc)s)", 'args': args} 1547 ] 1548 rows, idx = gmPG2.run_rw_queries(queries = queries) 1549 1550 return {'description': description, 'l10n_description': l10n_description}1551 #-----------------------------------------------------------1553 cmd = u"select _(description) as l10n_description, description from clin.encounter_type" 1554 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}]) 1555 return rows1556 #-----------------------------------------------------------1558 cmd = u"SELECT * from clin.encounter_type where description = %s" 1559 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': [description]}]) 1560 return rows1561 #-----------------------------------------------------------1563 cmd = u"delete from clin.encounter_type where description = %(desc)s" 1564 args = {'desc': description} 1565 try: 1566 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}]) 1567 except gmPG2.dbapi.IntegrityError, e: 1568 if e.pgcode == gmPG2.sql_error_codes.FOREIGN_KEY_VIOLATION: 1569 return False 1570 raise 1571 1572 return True1573 #============================================================1575 """Represents one problem. 1576 1577 problems are the aggregation of 1578 .clinically_relevant=True issues and 1579 .is_open=True episodes 1580 """ 1581 _cmd_fetch_payload = u'' # will get programmatically defined in __init__ 1582 _cmds_store_payload = [u"select 1"] 1583 _updatable_fields = [] 1584 1585 #--------------------------------------------------------1663 #-----------------------------------------------------------1587 """Initialize. 1588 1589 aPK_obj must contain the keys 1590 pk_patient 1591 pk_episode 1592 pk_health_issue 1593 """ 1594 if aPK_obj is None: 1595 raise gmExceptions.ConstructorError, 'cannot instatiate cProblem for PK: [%s]' % (aPK_obj) 1596 1597 # As problems are rows from a view of different emr struct items, 1598 # the PK can't be a single field and, as some of the values of the 1599 # composed PK may be None, they must be queried using 'is null', 1600 # so we must programmatically construct the SQL query 1601 where_parts = [] 1602 pk = {} 1603 for col_name in aPK_obj.keys(): 1604 val = aPK_obj[col_name] 1605 if val is None: 1606 where_parts.append('%s IS NULL' % col_name) 1607 else: 1608 where_parts.append('%s = %%(%s)s' % (col_name, col_name)) 1609 pk[col_name] = val 1610 1611 # try to instantiate from true problem view 1612 cProblem._cmd_fetch_payload = u""" 1613 SELECT *, False as is_potential_problem 1614 FROM clin.v_problem_list 1615 WHERE %s""" % u' AND '.join(where_parts) 1616 1617 try: 1618 gmBusinessDBObject.cBusinessDBObject.__init__(self, aPK_obj=pk) 1619 return 1620 except gmExceptions.ConstructorError: 1621 _log.exception('actual problem not found, trying "potential" problems') 1622 if try_potential_problems is False: 1623 raise 1624 1625 # try to instantiate from potential-problems view 1626 cProblem._cmd_fetch_payload = u""" 1627 SELECT *, True as is_potential_problem 1628 FROM clin.v_potential_problem_list 1629 WHERE %s""" % u' AND '.join(where_parts) 1630 gmBusinessDBObject.cBusinessDBObject.__init__(self, aPK_obj=pk)1631 #--------------------------------------------------------1633 """ 1634 Retrieve the cEpisode instance equivalent to this problem. 1635 The problem's type attribute must be 'episode' 1636 """ 1637 if self._payload[self._idx['type']] != 'episode': 1638 _log.error('cannot convert problem [%s] of type [%s] to episode' % (self._payload[self._idx['problem']], self._payload[self._idx['type']])) 1639 return None 1640 return cEpisode(aPK_obj = self._payload[self._idx['pk_episode']])1641 #--------------------------------------------------------1643 1644 if self._payload[self._idx['type']] == u'issue': 1645 episodes = [ cHealthIssue(aPK_obj = self._payload[self._idx['pk_health_issue']]).latest_episode ] 1646 #xxxxxxxxxxxxx 1647 1648 emr = patient.get_emr() 1649 1650 doc_folder = gmDocuments.cDocumentFolder(aPKey = patient.ID) 1651 return doc_folder.get_visual_progress_notes ( 1652 health_issue = self._payload[self._idx['pk_health_issue']], 1653 episode = self._payload[self._idx['pk_episode']] 1654 )1655 #-------------------------------------------------------- 1656 # properties 1657 #-------------------------------------------------------- 1658 # doubles as 'diagnostic_certainty_description' getter:1660 return diagnostic_certainty_classification2str(self._payload[self._idx['diagnostic_certainty_classification']])1661 1662 diagnostic_certainty_description = property(get_diagnostic_certainty_description, lambda x:x)1665 """Retrieve the cEpisode instance equivalent to the given problem. 1666 1667 The problem's type attribute must be 'episode' 1668 1669 @param problem: The problem to retrieve its related episode for 1670 @type problem: A gmEMRStructItems.cProblem instance 1671 """ 1672 if isinstance(problem, cEpisode): 1673 return problem 1674 1675 exc = TypeError('cannot convert [%s] to episode' % problem) 1676 1677 if not isinstance(problem, cProblem): 1678 raise exc 1679 1680 if problem['type'] != 'episode': 1681 raise exc 1682 1683 return cEpisode(aPK_obj = problem['pk_episode'])1684 #-----------------------------------------------------------1686 """Retrieve the cIssue instance equivalent to the given problem. 1687 1688 The problem's type attribute must be 'issue'. 1689 1690 @param problem: The problem to retrieve the corresponding issue for 1691 @type problem: A gmEMRStructItems.cProblem instance 1692 """ 1693 if isinstance(problem, cHealthIssue): 1694 return problem 1695 1696 exc = TypeError('cannot convert [%s] to health issue' % problem) 1697 1698 if not isinstance(problem, cProblem): 1699 raise exc 1700 1701 if problem['type'] != 'issue': 1702 raise exc 1703 1704 return cHealthIssue(aPK_obj = problem['pk_health_issue'])1705 #-----------------------------------------------------------1707 """Transform given problem into either episode or health issue instance. 1708 """ 1709 if isinstance(problem, (cEpisode, cHealthIssue)): 1710 return problem 1711 1712 exc = TypeError('cannot reclass [%s] instance to either episode or health issue' % type(problem)) 1713 1714 if not isinstance(problem, cProblem): 1715 _log.debug(u'%s' % problem) 1716 raise exc 1717 1718 if problem['type'] == 'episode': 1719 return cEpisode(aPK_obj = problem['pk_episode']) 1720 1721 if problem['type'] == 'issue': 1722 return cHealthIssue(aPK_obj = problem['pk_health_issue']) 1723 1724 raise exc1725 #============================================================1727 1728 _cmd_fetch_payload = u"select * from clin.v_pat_hospital_stays where pk_hospital_stay = %s" 1729 _cmds_store_payload = [ 1730 u"""update clin.hospital_stay set 1731 clin_when = %(admission)s, 1732 discharge = %(discharge)s, 1733 narrative = gm.nullify_empty_string(%(hospital)s), 1734 fk_episode = %(pk_episode)s, 1735 fk_encounter = %(pk_encounter)s 1736 where 1737 pk = %(pk_hospital_stay)s and 1738 xmin = %(xmin_hospital_stay)s""", 1739 u"""select xmin_hospital_stay from clin.v_pat_hospital_stays where pk_hospital_stay = %(pk_hospital_stay)s""" 1740 ] 1741 _updatable_fields = [ 1742 'admission', 1743 'discharge', 1744 'hospital', 1745 'pk_episode', 1746 'pk_encounter' 1747 ] 1748 #-------------------------------------------------------1767 #-----------------------------------------------------------1750 1751 if self._payload[self._idx['discharge']] is not None: 1752 dis = u' - %s' % self._payload[self._idx['discharge']].strftime('%Y %b %d').decode(gmI18N.get_encoding()) 1753 else: 1754 dis = u'' 1755 1756 line = u'%s%s%s%s: %s%s%s' % ( 1757 u' ' * left_margin, 1758 self._payload[self._idx['admission']].strftime('%Y %b %d').decode(gmI18N.get_encoding()), 1759 dis, 1760 gmTools.coalesce(self._payload[self._idx['hospital']], u'', u' (%s)'), 1761 gmTools.u_left_double_angle_quote, 1762 self._payload[self._idx['episode']], 1763 gmTools.u_right_double_angle_quote 1764 ) 1765 1766 return line1769 1770 queries = [{ 1771 'cmd': u'SELECT * FROM clin.v_pat_hospital_stays WHERE pk_patient = %(pat)s ORDER BY admission', 1772 'args': {'pat': patient} 1773 }] 1774 1775 rows, idx = gmPG2.run_ro_queries(queries = queries, get_col_idx = True) 1776 1777 return [ cHospitalStay(row = {'idx': idx, 'data': r, 'pk_field': 'pk_hospital_stay'}) for r in rows ]1778 #-----------------------------------------------------------1780 1781 queries = [{ 1782 'cmd': u'INSERT INTO clin.hospital_stay (fk_encounter, fk_episode) VALUES (%(enc)s, %(epi)s) RETURNING pk', 1783 'args': {'enc': encounter, 'epi': episode} 1784 }] 1785 rows, idx = gmPG2.run_rw_queries(queries = queries, return_data = True) 1786 1787 return cHospitalStay(aPK_obj = rows[0][0])1788 #-----------------------------------------------------------1790 cmd = u'DELETE FROM clin.hospital_stay WHERE pk = %(pk)s' 1791 args = {'pk': stay} 1792 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}]) 1793 return True1794 #============================================================1796 1797 _cmd_fetch_payload = u"select * from clin.v_pat_procedures where pk_procedure = %s" 1798 _cmds_store_payload = [ 1799 u"""UPDATE clin.procedure SET 1800 soap_cat = 'p', 1801 clin_when = %(clin_when)s, 1802 clin_end = %(clin_end)s, 1803 is_ongoing = %(is_ongoing)s, 1804 clin_where = NULLIF ( 1805 COALESCE ( 1806 %(pk_hospital_stay)s::TEXT, 1807 gm.nullify_empty_string(%(clin_where)s) 1808 ), 1809 %(pk_hospital_stay)s::TEXT 1810 ), 1811 narrative = gm.nullify_empty_string(%(performed_procedure)s), 1812 fk_hospital_stay = %(pk_hospital_stay)s, 1813 fk_episode = %(pk_episode)s, 1814 fk_encounter = %(pk_encounter)s 1815 WHERE 1816 pk = %(pk_procedure)s AND 1817 xmin = %(xmin_procedure)s 1818 RETURNING xmin as xmin_procedure""" 1819 ] 1820 _updatable_fields = [ 1821 'clin_when', 1822 'clin_end', 1823 'is_ongoing', 1824 'clin_where', 1825 'performed_procedure', 1826 'pk_hospital_stay', 1827 'pk_episode', 1828 'pk_encounter' 1829 ] 1830 #-------------------------------------------------------1863 #-----------------------------------------------------------1832 1833 if (attribute == 'pk_hospital_stay') and (value is not None): 1834 gmBusinessDBObject.cBusinessDBObject.__setitem__(self, 'clin_where', None) 1835 1836 if (attribute == 'clin_where') and (value is not None) and (value.strip() != u''): 1837 gmBusinessDBObject.cBusinessDBObject.__setitem__(self, 'pk_hospital_stay', None) 1838 1839 gmBusinessDBObject.cBusinessDBObject.__setitem__(self, attribute, value)1840 #-------------------------------------------------------1842 1843 if self._payload[self._idx['is_ongoing']]: 1844 end = _(' (ongoing)') 1845 else: 1846 end = self._payload[self._idx['clin_end']] 1847 if end is None: 1848 end = u'' 1849 else: 1850 end = u' - %s' % end.strftime('%Y %b %d').decode(gmI18N.get_encoding()) 1851 1852 line = u'%s%s%s, %s: %s' % ( 1853 (u' ' * left_margin), 1854 self._payload[self._idx['clin_when']].strftime('%Y %b %d').decode(gmI18N.get_encoding()), 1855 end, 1856 self._payload[self._idx['clin_where']], 1857 self._payload[self._idx['performed_procedure']] 1858 ) 1859 if include_episode: 1860 line = u'%s (%s)' % (line, self._payload[self._idx['episode']]) 1861 1862 return line1865 1866 queries = [ 1867 { 1868 'cmd': u'select * from clin.v_pat_procedures where pk_patient = %(pat)s order by clin_when', 1869 'args': {'pat': patient} 1870 } 1871 ] 1872 1873 rows, idx = gmPG2.run_ro_queries(queries = queries, get_col_idx = True) 1874 1875 return [ cPerformedProcedure(row = {'idx': idx, 'data': r, 'pk_field': 'pk_procedure'}) for r in rows ]1876 #-----------------------------------------------------------1877 -def create_performed_procedure(encounter=None, episode=None, location=None, hospital_stay=None, procedure=None):1878 1879 queries = [{ 1880 'cmd': u""" 1881 INSERT INTO clin.procedure ( 1882 fk_encounter, 1883 fk_episode, 1884 soap_cat, 1885 clin_where, 1886 fk_hospital_stay, 1887 narrative 1888 ) VALUES ( 1889 %(enc)s, 1890 %(epi)s, 1891 'p', 1892 gm.nullify_empty_string(%(loc)s), 1893 %(stay)s, 1894 gm.nullify_empty_string(%(proc)s) 1895 ) 1896 RETURNING pk""", 1897 'args': {'enc': encounter, 'epi': episode, 'loc': location, 'stay': hospital_stay, 'proc': procedure} 1898 }] 1899 1900 rows, idx = gmPG2.run_rw_queries(queries = queries, return_data = True) 1901 1902 return cPerformedProcedure(aPK_obj = rows[0][0])1903 #-----------------------------------------------------------1905 cmd = u'delete from clin.procedure where pk = %(pk)s' 1906 args = {'pk': procedure} 1907 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}]) 1908 return True1909 #============================================================ 1910 # main - unit testing 1911 #------------------------------------------------------------ 1912 if __name__ == '__main__': 1913 1914 if len(sys.argv) < 2: 1915 sys.exit() 1916 1917 if sys.argv[1] != 'test': 1918 sys.exit() 1919 1920 #-------------------------------------------------------- 1921 # define tests 1922 #--------------------------------------------------------1924 print "\nProblem test" 1925 print "------------" 1926 prob = cProblem(aPK_obj={'pk_patient': 12, 'pk_health_issue': 1, 'pk_episode': None}) 1927 print prob 1928 fields = prob.get_fields() 1929 for field in fields: 1930 print field, ':', prob[field] 1931 print '\nupdatable:', prob.get_updatable_fields() 1932 epi = prob.get_as_episode() 1933 print '\nas episode:' 1934 if epi is not None: 1935 for field in epi.get_fields(): 1936 print ' .%s : %s' % (field, epi[field])1937 #--------------------------------------------------------1939 print "\nhealth issue test" 1940 print "-----------------" 1941 h_issue = cHealthIssue(aPK_obj=2) 1942 print h_issue 1943 fields = h_issue.get_fields() 1944 for field in fields: 1945 print field, ':', h_issue[field] 1946 print "has open episode:", h_issue.has_open_episode() 1947 print "open episode:", h_issue.get_open_episode() 1948 print "updateable:", h_issue.get_updatable_fields() 1949 h_issue.close_expired_episode(ttl=7300) 1950 h_issue = cHealthIssue(encounter = 1, name = u'post appendectomy/peritonitis') 1951 print h_issue 1952 print h_issue.format_as_journal()1953 #--------------------------------------------------------1955 print "\nepisode test" 1956 print "------------" 1957 episode = cEpisode(aPK_obj=1) 1958 print episode 1959 fields = episode.get_fields() 1960 for field in fields: 1961 print field, ':', episode[field] 1962 print "updatable:", episode.get_updatable_fields() 1963 raw_input('ENTER to continue') 1964 1965 old_description = episode['description'] 1966 old_enc = cEncounter(aPK_obj = 1) 1967 1968 desc = '1-%s' % episode['description'] 1969 print "==> renaming to", desc 1970 successful = episode.rename ( 1971 description = desc 1972 ) 1973 if not successful: 1974 print "error" 1975 else: 1976 print "success" 1977 for field in fields: 1978 print field, ':', episode[field] 1979 1980 print "episode range:", episode.get_access_range() 1981 1982 raw_input('ENTER to continue')1983 1984 #--------------------------------------------------------1986 print "\nencounter test" 1987 print "--------------" 1988 encounter = cEncounter(aPK_obj=1) 1989 print encounter 1990 fields = encounter.get_fields() 1991 for field in fields: 1992 print field, ':', encounter[field] 1993 print "updatable:", encounter.get_updatable_fields()1994 #--------------------------------------------------------1996 encounter = cEncounter(aPK_obj=1) 1997 print encounter 1998 print "" 1999 print encounter.format_latex()2000 #--------------------------------------------------------2002 procs = get_performed_procedures(patient = 12) 2003 for proc in procs: 2004 print proc.format(left_margin=2)2005 #--------------------------------------------------------2007 stay = create_hospital_stay(encounter = 1, episode = 2) 2008 stay['hospital'] = u'Starfleet Galaxy General Hospital' 2009 stay.save_payload() 2010 print stay 2011 for s in get_patient_hospital_stays(12): 2012 print s 2013 delete_hospital_stay(stay['pk_hospital_stay']) 2014 stay = create_hospital_stay(encounter = 1, episode = 4)2015 #--------------------------------------------------------2017 tests = [None, 'A', 'B', 'C', 'D', 'E'] 2018 2019 for t in tests: 2020 print type(t), t 2021 print type(diagnostic_certainty_classification2str(t)), diagnostic_certainty_classification2str(t)2022 2023 #-------------------------------------------------------- 2024 # run them 2025 #test_episode() 2026 #test_problem() 2027 #test_encounter() 2028 #test_health_issue() 2029 #test_hospital_stay() 2030 #test_performed_procedure() 2031 #test_diagnostic_certainty_classification_map() 2032 test_encounter2latex() 2033 #============================================================ 2034
Home | Trees | Indices | Help |
|
---|
Generated by Epydoc 3.0.1 on Thu Mar 17 03:57:18 2011 | http://epydoc.sourceforge.net |