| 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
35
37
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') % classification
53 #============================================================
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 #--------------------------------------------------------
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 True
155 #--------------------------------------------------------
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 exception
176 #--------------------------------------------------------
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 False
184 #--------------------------------------------------------
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 for epi in epis:
345 lines.append(u' \u00BB%s\u00AB (%s)' % (
346 epi['description'],
347 gmTools.bool2subst(epi['episode_open'], _('ongoing'), _('closed'))
348 ))
349
350 lines.append('')
351
352 # encounters
353 first_encounter = emr.get_first_encounter(issue_id = self._payload[self._idx['pk_health_issue']])
354 last_encounter = emr.get_last_encounter(issue_id = self._payload[self._idx['pk_health_issue']])
355
356 if first_encounter is None or last_encounter is None:
357 lines.append(_('No encounters found for this health issue.'))
358 else:
359 encs = emr.get_encounters(issues = [self._payload[self._idx['pk_health_issue']]])
360 lines.append(_('Encounters: %s (%s - %s):') % (
361 len(encs),
362 first_encounter['started_original_tz'].strftime('%m/%Y'),
363 last_encounter['last_affirmed_original_tz'].strftime('%m/%Y')
364 ))
365 lines.append(_(' Most recent: %s - %s') % (
366 last_encounter['started_original_tz'].strftime('%Y-%m-%d %H:%M'),
367 last_encounter['last_affirmed_original_tz'].strftime('%H:%M')
368 ))
369
370 # medications
371 meds = emr.get_current_substance_intake (
372 issues = [ self._payload[self._idx['pk_health_issue']] ],
373 order_by = u'is_currently_active, started, substance'
374 )
375
376 if len(meds) > 0:
377 lines.append(u'')
378 lines.append(_('Active medications: %s') % len(meds))
379 for m in meds:
380 lines.append(m.format(left_margin = (left_margin + 1)))
381 del meds
382
383 # hospital stays
384 stays = emr.get_hospital_stays (
385 issues = [ self._payload[self._idx['pk_health_issue']] ]
386 )
387
388 if len(stays) > 0:
389 lines.append(u'')
390 lines.append(_('Hospital stays: %s') % len(stays))
391 for s in stays:
392 lines.append(s.format(left_margin = (left_margin + 1)))
393 del stays
394
395 # procedures
396 procs = emr.get_performed_procedures (
397 issues = [ self._payload[self._idx['pk_health_issue']] ]
398 )
399
400 if len(procs) > 0:
401 lines.append(u'')
402 lines.append(_('Procedures performed: %s') % len(procs))
403 for p in procs:
404 lines.append(p.format(left_margin = (left_margin + 1)))
405 del procs
406
407 epis = self.get_episodes()
408 if len(epis) > 0:
409 epi_pks = [ e['pk_episode'] for e in epis ]
410
411 # documents
412 doc_folder = patient.get_document_folder()
413 docs = doc_folder.get_documents(episodes = epi_pks)
414 if len(docs) > 0:
415 lines.append(u'')
416 lines.append(_('Documents: %s') % len(docs))
417 del docs
418
419 # test results
420 tests = emr.get_test_results_by_date(episodes = epi_pks)
421 if len(tests) > 0:
422 lines.append(u'')
423 lines.append(_('Measurements and Results: %s') % len(tests))
424 del tests
425
426 # vaccinations
427 vaccs = emr.get_vaccinations(episodes = epi_pks)
428 if len(vaccs) > 0:
429 lines.append(u'')
430 lines.append(_('Vaccinations:'))
431 for vacc in vaccs:
432 lines.extend(vacc.format(with_reaction = True))
433 del vaccs
434
435 del epis
436
437 left_margin = u' ' * left_margin
438 eol_w_margin = u'\n%s' % left_margin
439 return left_margin + eol_w_margin.join(lines) + u'\n'
440 #--------------------------------------------------------
441 # properties
442 #--------------------------------------------------------
443 episodes = property(get_episodes, lambda x:x)
444 #--------------------------------------------------------
445 open_episode = property(get_open_episode, lambda x:x)
446 #--------------------------------------------------------
448 cmd = u"""SELECT
449 coalesce (
450 (SELECT pk FROM clin.episode WHERE fk_health_issue = %(issue)s AND is_open IS TRUE),
451 (SELECT pk FROM clin.v_pat_episodes WHERE fk_health_issue = %(issue)s ORDER BY last_affirmed DESC limit 1)
452 )"""
453 args = {'issue': self.pk_obj}
454 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
455 if len(rows) == 0:
456 return None
457 return cEpisode(aPK_obj = rows[0][0])
458
459 latest_episode = property(_get_latest_episode, lambda x:x)
460 #--------------------------------------------------------
462 try:
463 return laterality2str[self._payload[self._idx['laterality']]]
464 except KeyError:
465 return u'<???>'
466
467 laterality_description = property(_get_laterality_description, lambda x:x)
468 #--------------------------------------------------------
470 return diagnostic_certainty_classification2str(self._payload[self._idx['diagnostic_certainty_classification']])
471
472 diagnostic_certainty_description = property(_get_diagnostic_certainty_description, lambda x:x)
473 #============================================================
475 """Creates a new health issue for a given patient.
476
477 description - health issue name
478 """
479 try:
480 h_issue = cHealthIssue(name = description, encounter = encounter, patient = patient)
481 return h_issue
482 except gmExceptions.NoSuchBusinessObjectError:
483 pass
484
485 queries = []
486 cmd = u"insert into clin.health_issue (description, fk_encounter) values (%(desc)s, %(enc)s)"
487 queries.append({'cmd': cmd, 'args': {'desc': description, 'enc': encounter}})
488
489 cmd = u"select currval('clin.health_issue_pk_seq')"
490 queries.append({'cmd': cmd})
491
492 rows, idx = gmPG2.run_rw_queries(queries = queries, return_data = True)
493 h_issue = cHealthIssue(aPK_obj = rows[0][0])
494
495 return h_issue
496 #-----------------------------------------------------------
498 if isinstance(health_issue, cHealthIssue):
499 pk = health_issue['pk_health_issue']
500 else:
501 pk = int(health_issue)
502
503 try:
504 gmPG2.run_rw_queries(queries = [{'cmd': u'delete from clin.health_issue where pk=%(pk)s', 'args': {'pk': pk}}])
505 except gmPG2.dbapi.IntegrityError:
506 # should be parsing pgcode/and or error message
507 _log.exception('cannot delete health issue')
508 raise gmExceptions.DatabaseObjectInUseError('cannot delete health issue, it is in use')
509 #------------------------------------------------------------
510 # use as dummy for unassociated episodes
512 issue = {
513 'pk_health_issue': None,
514 'description': _('Unattributed episodes'),
515 'age_noted': None,
516 'laterality': u'na',
517 'is_active': True,
518 'clinically_relevant': True,
519 'is_confidential': None,
520 'is_cause_of_death': False,
521 'is_dummy': True,
522 'grouping': None
523 }
524 return issue
525 #-----------------------------------------------------------
527 return cProblem (
528 aPK_obj = {
529 'pk_patient': health_issue['pk_patient'],
530 'pk_health_issue': health_issue['pk_health_issue'],
531 'pk_episode': None
532 },
533 try_potential_problems = allow_irrelevant
534 )
535 #============================================================
536 # episodes API
537 #============================================================
539 """Represents one clinical episode.
540 """
541 _cmd_fetch_payload = u"select * from clin.v_pat_episodes where pk_episode=%s"
542 _cmds_store_payload = [
543 u"""update clin.episode set
544 fk_health_issue = %(pk_health_issue)s,
545 is_open = %(episode_open)s::boolean,
546 description = %(description)s,
547 summary = gm.nullify_empty_string(%(summary)s),
548 diagnostic_certainty_classification = gm.nullify_empty_string(%(diagnostic_certainty_classification)s)
549 where
550 pk = %(pk_episode)s and
551 xmin = %(xmin_episode)s""",
552 u"""select xmin_episode from clin.v_pat_episodes where pk_episode = %(pk_episode)s"""
553 ]
554 _updatable_fields = [
555 'pk_health_issue',
556 'episode_open',
557 'description',
558 'summary',
559 'diagnostic_certainty_classification'
560 ]
561 #--------------------------------------------------------
562 - def __init__(self, aPK_obj=None, id_patient=None, name='xxxDEFAULTxxx', health_issue=None, row=None, encounter=None):
563 pk = aPK_obj
564 if pk is None and row is None:
565
566 where_parts = [u'description = %(desc)s']
567
568 if id_patient is not None:
569 where_parts.append(u'pk_patient = %(pat)s')
570
571 if health_issue is not None:
572 where_parts.append(u'pk_health_issue = %(issue)s')
573
574 if encounter is not None:
575 where_parts.append(u'pk_patient = (select fk_patient from clin.encounter where pk = %(enc)s)')
576
577 args = {
578 'pat': id_patient,
579 'issue': health_issue,
580 'enc': encounter,
581 'desc': name
582 }
583
584 cmd = u"select * from clin.v_pat_episodes where %s" % u' and '.join(where_parts)
585
586 rows, idx = gmPG2.run_ro_queries(
587 queries = [{'cmd': cmd, 'args': args}],
588 get_col_idx=True
589 )
590
591 if len(rows) == 0:
592 raise gmExceptions.NoSuchBusinessObjectError, 'no episode for [%s:%s:%s:%s]' % (id_patient, name, health_issue, encounter)
593
594 r = {'idx': idx, 'data': rows[0], 'pk_field': 'pk_episode'}
595 gmBusinessDBObject.cBusinessDBObject.__init__(self, row=r)
596
597 else:
598 gmBusinessDBObject.cBusinessDBObject.__init__(self, aPK_obj=pk, row=row)
599 #--------------------------------------------------------
600 # external API
601 #--------------------------------------------------------
603 """Get earliest and latest access to this episode.
604
605 Returns a tuple(earliest, latest).
606 """
607 cmd = u"""
608 select
609 min(earliest),
610 max(latest)
611 from (
612 (select
613 (case when clin_when < modified_when
614 then clin_when
615 else modified_when
616 end) as earliest,
617 (case when clin_when > modified_when
618 then clin_when
619 else modified_when
620 end) as latest
621 from
622 clin.clin_root_item
623 where
624 fk_episode = %(pk)s
625
626 ) union all (
627
628 select
629 modified_when as earliest,
630 modified_when as latest
631 from
632 clin.episode
633 where
634 pk = %(pk)s
635 )
636 ) as ranges"""
637 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': {'pk': self.pk_obj}}])
638 if len(rows) == 0:
639 return (gmNull.cNull(warn=False), gmNull.cNull(warn=False))
640 return (rows[0][0], rows[0][1])
641 #--------------------------------------------------------
644 #--------------------------------------------------------
646 return gmClinNarrative.get_narrative (
647 soap_cats = soap_cats,
648 encounters = encounters,
649 episodes = [self.pk_obj],
650 order_by = order_by
651 )
652 #--------------------------------------------------------
654 """Method for episode editing, that is, episode renaming.
655
656 @param description
657 - the new descriptive name for the encounter
658 @type description
659 - a string instance
660 """
661 # sanity check
662 if description.strip() == '':
663 _log.error('<description> must be a non-empty string instance')
664 return False
665 # update the episode description
666 old_description = self._payload[self._idx['description']]
667 self._payload[self._idx['description']] = description.strip()
668 self._is_modified = True
669 successful, data = self.save_payload()
670 if not successful:
671 _log.error('cannot rename episode [%s] to [%s]' % (self, description))
672 self._payload[self._idx['description']] = old_description
673 return False
674 return True
675 #--------------------------------------------------------
677 rows = gmClinNarrative.get_as_journal (
678 episodes = (self.pk_obj,),
679 order_by = u'pk_encounter, clin_when, scr, src_table'
680 #order_by = u'pk_encounter, scr, clin_when, src_table'
681 )
682
683 if len(rows) == 0:
684 return u''
685
686 lines = []
687
688 lines.append(_('Clinical data generated during encounters within this episode:'))
689
690 left_margin = u' ' * left_margin
691
692 prev_enc = None
693 for row in rows:
694 if row['pk_encounter'] != prev_enc:
695 lines.append(u'')
696 prev_enc = row['pk_encounter']
697
698 when = row['clin_when'].strftime(date_format).decode(gmI18N.get_encoding())
699 top_row = u'%s%s %s (%s) %s' % (
700 gmTools.u_box_top_left_arc,
701 gmTools.u_box_horiz_single,
702 gmClinNarrative.soap_cat2l10n_str[row['real_soap_cat']],
703 when,
704 gmTools.u_box_horiz_single * 5
705 )
706 soap = gmTools.wrap (
707 text = row['narrative'],
708 width = 60,
709 initial_indent = u' ',
710 subsequent_indent = u' ' + left_margin
711 )
712 row_ver = u''
713 if row['row_version'] > 0:
714 row_ver = u'v%s: ' % row['row_version']
715 bottom_row = u'%s%s %s, %s%s %s' % (
716 u' ' * 40,
717 gmTools.u_box_horiz_light_heavy,
718 row['modified_by'],
719 row_ver,
720 row['date_modified'],
721 gmTools.u_box_horiz_heavy_light
722 )
723
724 lines.append(top_row)
725 lines.append(soap)
726 lines.append(bottom_row)
727
728 eol_w_margin = u'\n%s' % left_margin
729 return left_margin + eol_w_margin.join(lines) + u'\n'
730 #--------------------------------------------------------
732
733 if patient.ID != self._payload[self._idx['pk_patient']]:
734 msg = '<patient>.ID = %s but episode %s belongs to patient %s' % (
735 patient.ID,
736 self._payload[self._idx['pk_episode']],
737 self._payload[self._idx['pk_patient']]
738 )
739 raise ValueError(msg)
740
741 lines = []
742
743 # episode details
744 lines.append (_('Episode %s%s%s [#%s]') % (
745 gmTools.u_left_double_angle_quote,
746 self._payload[self._idx['description']],
747 gmTools.u_right_double_angle_quote,
748 self._payload[self._idx['pk_episode']]
749 ))
750
751 enc = cEncounter(aPK_obj = self._payload[self._idx['pk_encounter']])
752 lines.append (u' ' + _('Created during encounter: %s (%s - %s) [#%s]') % (
753 enc['l10n_type'],
754 enc['started_original_tz'].strftime('%Y-%m-%d %H:%M'),
755 enc['last_affirmed_original_tz'].strftime('%H:%M'),
756 self._payload[self._idx['pk_encounter']]
757 ))
758
759 emr = patient.get_emr()
760 encs = emr.get_encounters(episodes = [self._payload[self._idx['pk_episode']]])
761 first_encounter = None
762 last_encounter = None
763 if (encs is not None) and (len(encs) > 0):
764 first_encounter = emr.get_first_encounter(episode_id = self._payload[self._idx['pk_episode']])
765 last_encounter = emr.get_last_encounter(episode_id = self._payload[self._idx['pk_episode']])
766 if self._payload[self._idx['episode_open']]:
767 end = gmDateTime.pydt_now_here()
768 end_str = gmTools.u_ellipsis
769 else:
770 end = last_encounter['last_affirmed']
771 end_str = last_encounter['last_affirmed'].strftime('%m/%Y')
772 age = gmDateTime.format_interval_medically(end - first_encounter['started'])
773 lines.append(_(' Duration: %s (%s - %s)') % (
774 age,
775 first_encounter['started'].strftime('%m/%Y'),
776 end_str
777 ))
778
779 lines.append(u' ' + _('Status') + u': %s%s' % (
780 gmTools.bool2subst(self._payload[self._idx['episode_open']], _('active'), _('finished')),
781 gmTools.coalesce (
782 initial = diagnostic_certainty_classification2str(self._payload[self._idx['diagnostic_certainty_classification']]),
783 instead = u'',
784 template_initial = u', %s',
785 none_equivalents = [None, u'']
786 )
787 ))
788
789 if self._payload[self._idx['summary']] is not None:
790 lines.append(u'')
791 lines.append(gmTools.wrap (
792 text = self._payload[self._idx['summary']],
793 width = 60,
794 initial_indent = u' ',
795 subsequent_indent = u' '
796 )
797 )
798
799 lines.append(u'')
800
801 # encounters
802 if encs is None:
803 lines.append(_('Error retrieving encounters for this episode.'))
804 elif len(encs) == 0:
805 lines.append(_('There are no encounters for this episode.'))
806 else:
807 lines.append(_('Last worked on: %s\n') % last_encounter['last_affirmed_original_tz'].strftime('%Y-%m-%d %H:%M'))
808
809 if len(encs) < 4:
810 line = _('%s encounter(s) (%s - %s):')
811 else:
812 line = _('1st and (up to 3) most recent (of %s) encounters (%s - %s):')
813 lines.append(line % (
814 len(encs),
815 first_encounter['started'].strftime('%m/%Y'),
816 last_encounter['last_affirmed'].strftime('%m/%Y')
817 ))
818
819 lines.append(u' %s - %s (%s):%s' % (
820 first_encounter['started_original_tz'].strftime('%Y-%m-%d %H:%M'),
821 first_encounter['last_affirmed_original_tz'].strftime('%H:%M'),
822 first_encounter['l10n_type'],
823 gmTools.coalesce (
824 first_encounter['assessment_of_encounter'],
825 gmTools.coalesce (
826 first_encounter['reason_for_encounter'],
827 u'',
828 u' \u00BB%s\u00AB' + (u' (%s)' % _('RFE'))
829 ),
830 u' \u00BB%s\u00AB' + (u' (%s)' % _('AOE'))
831 )
832 ))
833
834 if len(encs) > 4:
835 lines.append(_(' ... %s skipped ...') % (len(encs) - 4))
836
837 for enc in encs[1:][-3:]:
838 lines.append(u' %s - %s (%s):%s' % (
839 enc['started_original_tz'].strftime('%Y-%m-%d %H:%M'),
840 enc['last_affirmed_original_tz'].strftime('%H:%M'),
841 enc['l10n_type'],
842 gmTools.coalesce (
843 enc['assessment_of_encounter'],
844 gmTools.coalesce (
845 enc['reason_for_encounter'],
846 u'',
847 u' \u00BB%s\u00AB' + (u' (%s)' % _('RFE'))
848 ),
849 u' \u00BB%s\u00AB' + (u' (%s)' % _('AOE'))
850 )
851 ))
852 del encs
853
854 # spell out last encounter
855 if last_encounter is not None:
856 lines.append('')
857 lines.append(_('Progress notes in most recent encounter:'))
858 lines.extend(last_encounter.format_soap (
859 episodes = [ self._payload[self._idx['pk_episode']] ],
860 left_margin = left_margin,
861 soap_cats = 'soap',
862 emr = emr
863 ))
864
865 # documents
866 doc_folder = patient.get_document_folder()
867 docs = doc_folder.get_documents (
868 episodes = [ self._payload[self._idx['pk_episode']] ]
869 )
870
871 if len(docs) > 0:
872 lines.append('')
873 lines.append(_('Documents: %s') % len(docs))
874
875 for d in docs:
876 lines.append(u' %s %s:%s%s' % (
877 d['clin_when'].strftime('%Y-%m-%d'),
878 d['l10n_type'],
879 gmTools.coalesce(d['comment'], u'', u' "%s"'),
880 gmTools.coalesce(d['ext_ref'], u'', u' (%s)')
881 ))
882 del docs
883
884 # hospital stays
885 stays = emr.get_hospital_stays (
886 episodes = [ self._payload[self._idx['pk_episode']] ]
887 )
888
889 if len(stays) > 0:
890 lines.append('')
891 lines.append(_('Hospital stays: %s') % len(stays))
892
893 for s in stays:
894 lines.append(s.format(left_margin = (left_margin + 1)))
895 del stays
896
897 # procedures
898 procs = emr.get_performed_procedures (
899 episodes = [ self._payload[self._idx['pk_episode']] ]
900 )
901
902 if len(procs) > 0:
903 lines.append(u'')
904 lines.append(_('Procedures performed: %s') % len(procs))
905 for p in procs:
906 lines.append(p.format(left_margin = (left_margin + 1), include_episode = False))
907 del procs
908
909 # test results
910 tests = emr.get_test_results_by_date(episodes = [ self._payload[self._idx['pk_episode']] ])
911
912 if len(tests) > 0:
913 lines.append('')
914 lines.append(_('Measurements and Results:'))
915
916 for t in tests:
917 lines.extend(t.format (
918 with_review = False,
919 with_comments = False,
920 date_format = '%Y-%m-%d'
921 ))
922 del tests
923
924 # vaccinations
925 vaccs = emr.get_vaccinations(episodes = [ self._payload[self._idx['pk_episode']] ])
926
927 if len(vaccs) > 0:
928 lines.append(u'')
929 lines.append(_('Vaccinations:'))
930
931 for vacc in vaccs:
932 lines.extend(vacc.format (
933 with_indications = True,
934 with_comment = True,
935 with_reaction = True,
936 date_format = '%Y-%m-%d'
937 ))
938 del vaccs
939
940 left_margin = u' ' * left_margin
941 eol_w_margin = u'\n%s' % left_margin
942 return left_margin + eol_w_margin.join(lines) + u'\n'
943 #--------------------------------------------------------
944 # properties
945 #--------------------------------------------------------
947 return diagnostic_certainty_classification2str(self._payload[self._idx['diagnostic_certainty_classification']])
948
949 diagnostic_certainty_description = property(_get_diagnostic_certainty_description, lambda x:x)
950 #--------------------------------------------------------
952 cmd = u"""SELECT EXISTS (
953 SELECT 1 FROM clin.clin_narrative
954 WHERE
955 fk_episode = %(epi)s
956 AND
957 fk_encounter IN (
958 SELECT pk FROM clin.encounter WHERE fk_patient = %(pat)s
959 )
960 )"""
961 args = {
962 u'pat': self._payload[self._idx['pk_patient']],
963 u'epi': self._payload[self._idx['pk_episode']]
964 }
965 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
966 return rows[0][0]
967
968 has_narrative = property(_get_has_narrative, lambda x:x)
969 #============================================================
970 -def create_episode(pk_health_issue=None, episode_name=None, is_open=False, allow_dupes=False, encounter=None):
971 """Creates a new episode for a given patient's health issue.
972
973 pk_health_issue - given health issue PK
974 episode_name - name of episode
975 """
976 if not allow_dupes:
977 try:
978 episode = cEpisode(name=episode_name, health_issue=pk_health_issue, encounter = encounter)
979 if episode['episode_open'] != is_open:
980 episode['episode_open'] = is_open
981 episode.save_payload()
982 return episode
983 except gmExceptions.ConstructorError:
984 pass
985
986 queries = []
987 cmd = u"insert into clin.episode (fk_health_issue, description, is_open, fk_encounter) values (%s, %s, %s::boolean, %s)"
988 queries.append({'cmd': cmd, 'args': [pk_health_issue, episode_name, is_open, encounter]})
989 queries.append({'cmd': cEpisode._cmd_fetch_payload % u"currval('clin.episode_pk_seq')"})
990 rows, idx = gmPG2.run_rw_queries(queries = queries, return_data=True, get_col_idx=True)
991
992 episode = cEpisode(row={'data': rows[0], 'idx': idx, 'pk_field': 'pk_episode'})
993 return episode
994 #-----------------------------------------------------------
996 if isinstance(episode, cEpisode):
997 pk = episode['pk_episode']
998 else:
999 pk = int(episode)
1000
1001 try:
1002 gmPG2.run_rw_queries(queries = [{'cmd': u'delete from clin.episode where pk=%(pk)s', 'args': {'pk': pk}}])
1003 except gmPG2.dbapi.IntegrityError:
1004 # should be parsing pgcode/and or error message
1005 _log.exception('cannot delete episode')
1006 raise gmExceptions.DatabaseObjectInUseError('cannot delete episode, it is in use')
1007 #-----------------------------------------------------------
1009 return cProblem (
1010 aPK_obj = {
1011 'pk_patient': episode['pk_patient'],
1012 'pk_episode': episode['pk_episode'],
1013 'pk_health_issue': episode['pk_health_issue']
1014 },
1015 try_potential_problems = allow_closed
1016 )
1017 #============================================================
1018 # encounter API
1019 #============================================================
1021 """Represents one encounter."""
1022
1023 _cmd_fetch_payload = u"select * from clin.v_pat_encounters where pk_encounter = %s"
1024 _cmds_store_payload = [
1025 u"""update clin.encounter set
1026 started = %(started)s,
1027 last_affirmed = %(last_affirmed)s,
1028 fk_location = %(pk_location)s,
1029 fk_type = %(pk_type)s,
1030 reason_for_encounter = gm.nullify_empty_string(%(reason_for_encounter)s),
1031 assessment_of_encounter = gm.nullify_empty_string(%(assessment_of_encounter)s)
1032 where
1033 pk = %(pk_encounter)s and
1034 xmin = %(xmin_encounter)s""",
1035 u"""select xmin_encounter from clin.v_pat_encounters where pk_encounter=%(pk_encounter)s"""
1036 ]
1037 _updatable_fields = [
1038 'started',
1039 'last_affirmed',
1040 'pk_location',
1041 'pk_type',
1042 'reason_for_encounter',
1043 'assessment_of_encounter'
1044 ]
1045 #--------------------------------------------------------
1047 """Set the enconter as the active one.
1048
1049 "Setting active" means making sure the encounter
1050 row has the youngest "last_affirmed" timestamp of
1051 all encounter rows for this patient.
1052 """
1053 self['last_affirmed'] = gmDateTime.pydt_now_here()
1054 self.save()
1055 #--------------------------------------------------------
1057 """
1058 Moves every element currently linked to the current encounter
1059 and the source_episode onto target_episode.
1060
1061 @param source_episode The episode the elements are currently linked to.
1062 @type target_episode A cEpisode intance.
1063 @param target_episode The episode the elements will be relinked to.
1064 @type target_episode A cEpisode intance.
1065 """
1066 if source_episode['pk_episode'] == target_episode['pk_episode']:
1067 return True
1068
1069 queries = []
1070 cmd = u"""
1071 UPDATE clin.clin_root_item
1072 SET fk_episode = %(trg)s
1073 WHERE
1074 fk_encounter = %(enc)s AND
1075 fk_episode = %(src)s
1076 """
1077 rows, idx = gmPG2.run_rw_queries(queries = [{
1078 'cmd': cmd,
1079 'args': {
1080 'trg': target_episode['pk_episode'],
1081 'enc': self.pk_obj,
1082 'src': source_episode['pk_episode']
1083 }
1084 }])
1085 self.refetch_payload()
1086 return True
1087 #--------------------------------------------------------
1089
1090 relevant_fields = [
1091 'pk_location',
1092 'pk_type',
1093 'pk_patient',
1094 'reason_for_encounter',
1095 'assessment_of_encounter'
1096 ]
1097 for field in relevant_fields:
1098 if self._payload[self._idx[field]] != another_object[field]:
1099 _log.debug('mismatch on [%s]: "%s" vs. "%s"', field, self._payload[self._idx[field]], another_object[field])
1100 return False
1101
1102 relevant_fields = [
1103 'started',
1104 'last_affirmed',
1105 ]
1106 for field in relevant_fields:
1107 if self._payload[self._idx[field]] is None:
1108 if another_object[field] is None:
1109 continue
1110 _log.debug('mismatch on [%s]: "%s" vs. "%s"', field, self._payload[self._idx[field]], another_object[field])
1111 return False
1112
1113 if another_object[field] is None:
1114 return False
1115
1116 #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'):
1117 if self._payload[self._idx[field]].strftime('%Y-%m-%d %H:%M') != another_object[field].strftime('%Y-%m-%d %H:%M'):
1118 _log.debug('mismatch on [%s]: "%s" vs. "%s"', field, self._payload[self._idx[field]], another_object[field])
1119 return False
1120
1121 return True
1122 #--------------------------------------------------------
1124 cmd = u"""
1125 select exists (
1126 select 1 from clin.v_pat_items where pk_patient = %(pat)s and pk_encounter = %(enc)s
1127 union all
1128 select 1 from blobs.v_doc_med where pk_patient = %(pat)s and pk_encounter = %(enc)s
1129 )"""
1130 args = {
1131 'pat': self._payload[self._idx['pk_patient']],
1132 'enc': self.pk_obj
1133 }
1134 rows, idx = gmPG2.run_ro_queries (
1135 queries = [{
1136 'cmd': cmd,
1137 'args': args
1138 }]
1139 )
1140 return rows[0][0]
1141 #--------------------------------------------------------
1143 cmd = u"""
1144 select exists (
1145 select 1 from clin.v_pat_items where pk_patient=%(pat)s and pk_encounter=%(enc)s
1146 )"""
1147 args = {
1148 'pat': self._payload[self._idx['pk_patient']],
1149 'enc': self.pk_obj
1150 }
1151 rows, idx = gmPG2.run_ro_queries (
1152 queries = [{
1153 'cmd': cmd,
1154 'args': args
1155 }]
1156 )
1157 return rows[0][0]
1158 #--------------------------------------------------------
1160 """soap_cats: <space> = admin category"""
1161
1162 if soap_cats is None:
1163 soap_cats = u'soap '
1164 else:
1165 soap_cats = soap_cats.lower()
1166
1167 cats = []
1168 for cat in soap_cats:
1169 if cat in u'soap':
1170 cats.append(cat)
1171 continue
1172 if cat == u' ':
1173 cats.append(None)
1174
1175 cmd = u"""
1176 SELECT EXISTS (
1177 SELECT 1 FROM clin.clin_narrative
1178 WHERE
1179 fk_encounter = %(enc)s
1180 AND
1181 soap_cat IN %(cats)s
1182 LIMIT 1
1183 )
1184 """
1185 args = {'enc': self._payload[self._idx['pk_encounter']], 'cats': tuple(cats)}
1186 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd,'args': args}])
1187 return rows[0][0]
1188 #--------------------------------------------------------
1190 cmd = u"""
1191 select exists (
1192 select 1 from blobs.v_doc_med where pk_patient = %(pat)s and pk_encounter = %(enc)s
1193 )"""
1194 args = {
1195 'pat': self._payload[self._idx['pk_patient']],
1196 'enc': self.pk_obj
1197 }
1198 rows, idx = gmPG2.run_ro_queries (
1199 queries = [{
1200 'cmd': cmd,
1201 'args': args
1202 }]
1203 )
1204 return rows[0][0]
1205 #--------------------------------------------------------
1207
1208 if soap_cat is not None:
1209 soap_cat = soap_cat.lower()
1210
1211 if episode is None:
1212 epi_part = u'fk_episode is null'
1213 else:
1214 epi_part = u'fk_episode = %(epi)s'
1215
1216 cmd = u"""
1217 select narrative
1218 from clin.clin_narrative
1219 where
1220 fk_encounter = %%(enc)s
1221 and
1222 soap_cat = %%(cat)s
1223 and
1224 %s
1225 order by clin_when desc
1226 limit 1
1227 """ % epi_part
1228
1229 args = {'enc': self.pk_obj, 'cat': soap_cat, 'epi': episode}
1230
1231 rows, idx = gmPG2.run_ro_queries (
1232 queries = [{
1233 'cmd': cmd,
1234 'args': args
1235 }]
1236 )
1237 if len(rows) == 0:
1238 return None
1239
1240 return rows[0][0]
1241 #--------------------------------------------------------
1243 cmd = u"""
1244 SELECT * FROM clin.v_pat_episodes
1245 WHERE
1246 pk_episode IN (
1247
1248 SELECT DISTINCT fk_episode
1249 FROM clin.clin_root_item
1250 WHERE fk_encounter = %%(enc)s
1251
1252 UNION
1253
1254 SELECT DISTINCT fk_episode
1255 FROM blobs.doc_med
1256 WHERE fk_encounter = %%(enc)s
1257 )
1258 %s"""
1259 args = {'enc': self.pk_obj}
1260 if exclude is not None:
1261 cmd = cmd % u'AND pk_episode NOT IN %(excluded)s'
1262 args['excluded'] = tuple(exclude)
1263 else:
1264 cmd = cmd % u''
1265
1266 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
1267
1268 return [ cEpisode(row = {'data': r, 'idx': idx, 'pk_field': 'pk_episode'}) for r in rows ]
1269 #--------------------------------------------------------
1270 - def format_soap(self, episodes=None, left_margin=0, soap_cats='soap', emr=None, issues=None):
1271
1272 lines = []
1273 for soap_cat in soap_cats:
1274 soap_cat_narratives = emr.get_clin_narrative (
1275 episodes = episodes,
1276 issues = issues,
1277 encounters = [self._payload[self._idx['pk_encounter']]],
1278 soap_cats = [soap_cat]
1279 )
1280 if soap_cat_narratives is None:
1281 continue
1282 if len(soap_cat_narratives) == 0:
1283 continue
1284
1285 lines.append(u'-- %s ----------' % gmClinNarrative.soap_cat2l10n_str[soap_cat])
1286 for soap_entry in soap_cat_narratives:
1287 txt = gmTools.wrap (
1288 text = u'%s\n (%.8s %s)' % (
1289 soap_entry['narrative'],
1290 soap_entry['provider'],
1291 soap_entry['date'].strftime('%Y-%m-%d %H:%M')
1292 ),
1293 width = 75,
1294 initial_indent = u'',
1295 subsequent_indent = (u' ' * left_margin)
1296 )
1297 lines.append(txt)
1298 lines.append('')
1299
1300 return lines
1301 #--------------------------------------------------------
1303
1304 nothing2format = (
1305 (self._payload[self._idx['reason_for_encounter']] is None)
1306 and
1307 (self._payload[self._idx['assessment_of_encounter']] is None)
1308 and
1309 (self.has_soap_narrative(soap_cats = u'soap') is False)
1310 )
1311 if nothing2format:
1312 return u''
1313
1314 if date_format is None:
1315 date_format = '%A, %B %d %Y'
1316
1317 tex = u'\\multicolumn{2}{l}{%s: %s ({\\footnotesize %s - %s})} \\tabularnewline \n' % (
1318 gmTools.tex_escape_string(self._payload[self._idx['l10n_type']]),
1319 self._payload[self._idx['started']].strftime(date_format).decode(gmI18N.get_encoding()),
1320 self._payload[self._idx['started']].strftime('%H:%M'),
1321 self._payload[self._idx['last_affirmed']].strftime('%H:%M')
1322 )
1323 tex += u'\\hline \\tabularnewline \n'
1324
1325 for epi in self.get_episodes():
1326 soaps = epi.get_narrative(soap_cats = soap_cats, encounters = [self.pk_obj], order_by = soap_order)
1327 if len(soaps) == 0:
1328 continue
1329 tex += u'\\multicolumn{2}{l}{\\emph{%s: %s%s}} \\tabularnewline \n' % (
1330 gmTools.tex_escape_string(_('Problem')),
1331 gmTools.tex_escape_string(epi['description']),
1332 gmTools.coalesce (
1333 initial = diagnostic_certainty_classification2str(epi['diagnostic_certainty_classification']),
1334 instead = u'',
1335 template_initial = u' {\\footnotesize [%s]}',
1336 none_equivalents = [None, u'']
1337 )
1338 )
1339 if epi['pk_health_issue'] is not None:
1340 tex += u'\\multicolumn{2}{l}{\\emph{%s: %s%s}} \\tabularnewline \n' % (
1341 gmTools.tex_escape_string(_('Health issue')),
1342 gmTools.tex_escape_string(epi['health_issue']),
1343 gmTools.coalesce (
1344 initial = diagnostic_certainty_classification2str(epi['diagnostic_certainty_classification_issue']),
1345 instead = u'',
1346 template_initial = u' {\\footnotesize [%s]}',
1347 none_equivalents = [None, u'']
1348 )
1349 )
1350 for soap in soaps:
1351 tex += u'{\\small %s} & {\\small %s} \\tabularnewline \n' % (
1352 gmClinNarrative.soap_cat2l10n[soap['soap_cat']],
1353 gmTools.tex_escape_string(soap['narrative'].strip(u'\n'))
1354 )
1355 tex += u' & \\tabularnewline \n'
1356
1357 if self._payload[self._idx['reason_for_encounter']] is not None:
1358 tex += u'%s & %s \\tabularnewline \n' % (
1359 gmTools.tex_escape_string(_('RFE')),
1360 gmTools.tex_escape_string(self._payload[self._idx['reason_for_encounter']])
1361 )
1362 if self._payload[self._idx['assessment_of_encounter']] is not None:
1363 tex += u'%s & %s \\tabularnewline \n' % (
1364 gmTools.tex_escape_string(_('AOE')),
1365 gmTools.tex_escape_string(self._payload[self._idx['assessment_of_encounter']])
1366 )
1367
1368 tex += u'\\hline \\tabularnewline \n'
1369 tex += u' & \\tabularnewline \n'
1370
1371 return tex
1372 #--------------------------------------------------------
1373 - 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):
1374 """Format an encounter.
1375
1376 with_co_encountlet_hints:
1377 - whether to include which *other* episodes were discussed during this encounter
1378 - (only makes sense if episodes != None)
1379 """
1380 lines = []
1381
1382 if fancy_header:
1383 lines.append(u'%s%s: %s - %s (@%s)%s [#%s]' % (
1384 u' ' * left_margin,
1385 self._payload[self._idx['l10n_type']],
1386 self._payload[self._idx['started_original_tz']].strftime('%Y-%m-%d %H:%M'),
1387 self._payload[self._idx['last_affirmed_original_tz']].strftime('%H:%M'),
1388 self._payload[self._idx['source_time_zone']],
1389 gmTools.coalesce(self._payload[self._idx['assessment_of_encounter']], u'', u' \u00BB%s\u00AB'),
1390 self._payload[self._idx['pk_encounter']]
1391 ))
1392
1393 lines.append(_(' your time: %s - %s (@%s = %s%s)\n') % (
1394 self._payload[self._idx['started']].strftime('%Y-%m-%d %H:%M'),
1395 self._payload[self._idx['last_affirmed']].strftime('%H:%M'),
1396 gmDateTime.current_local_iso_numeric_timezone_string,
1397 gmTools.bool2subst (
1398 gmDateTime.dst_currently_in_effect,
1399 gmDateTime.py_dst_timezone_name,
1400 gmDateTime.py_timezone_name
1401 ),
1402 gmTools.bool2subst(gmDateTime.dst_currently_in_effect, u' - ' + _('daylight savings time in effect'), u'')
1403 ))
1404
1405 if self._payload[self._idx['reason_for_encounter']] is not None:
1406 lines.append(u'%s: %s' % (_('RFE'), self._payload[self._idx['reason_for_encounter']]))
1407
1408 if self._payload[self._idx['assessment_of_encounter']] is not None:
1409 lines.append(u'%s: %s' % (_('AOE'), self._payload[self._idx['assessment_of_encounter']]))
1410
1411 else:
1412 lines.append(u'%s%s: %s - %s%s' % (
1413 u' ' * left_margin,
1414 self._payload[self._idx['l10n_type']],
1415 self._payload[self._idx['started_original_tz']].strftime('%Y-%m-%d %H:%M'),
1416 self._payload[self._idx['last_affirmed_original_tz']].strftime('%H:%M'),
1417 gmTools.coalesce(self._payload[self._idx['assessment_of_encounter']], u'', u' \u00BB%s\u00AB')
1418 ))
1419 if with_rfe_aoe:
1420 if self._payload[self._idx['reason_for_encounter']] is not None:
1421 lines.append(u'%s: %s' % (_('RFE'), self._payload[self._idx['reason_for_encounter']]))
1422 if self._payload[self._idx['assessment_of_encounter']] is not None:
1423 lines.append(u'%s: %s' % (_('AOE'), self._payload[self._idx['assessment_of_encounter']]))
1424
1425 if with_soap:
1426 lines.append(u'')
1427
1428 if patient.ID != self._payload[self._idx['pk_patient']]:
1429 msg = '<patient>.ID = %s but encounter %s belongs to patient %s' % (
1430 patient.ID,
1431 self._payload[self._idx['pk_encounter']],
1432 self._payload[self._idx['pk_patient']]
1433 )
1434 raise ValueError(msg)
1435
1436 emr = patient.get_emr()
1437
1438 lines.extend(self.format_soap (
1439 episodes = episodes,
1440 left_margin = left_margin,
1441 soap_cats = 'soap',
1442 emr = emr,
1443 issues = issues
1444 ))
1445
1446 # test results
1447 if with_tests:
1448 tests = emr.get_test_results_by_date (
1449 episodes = episodes,
1450 encounter = self._payload[self._idx['pk_encounter']]
1451 )
1452 if len(tests) > 0:
1453 lines.append('')
1454 lines.append(_('Measurements and Results:'))
1455
1456 for t in tests:
1457 lines.extend(t.format())
1458
1459 del tests
1460
1461 # vaccinations
1462 if with_vaccinations:
1463 vaccs = emr.get_vaccinations (
1464 episodes = episodes,
1465 encounters = [ self._payload[self._idx['pk_encounter']] ]
1466 )
1467
1468 if len(vaccs) > 0:
1469 lines.append(u'')
1470 lines.append(_('Vaccinations:'))
1471
1472 for vacc in vaccs:
1473 lines.extend(vacc.format (
1474 with_indications = True,
1475 with_comment = True,
1476 with_reaction = True,
1477 date_format = '%Y-%m-%d'
1478 ))
1479 del vaccs
1480
1481 # documents
1482 if with_docs:
1483 doc_folder = patient.get_document_folder()
1484 docs = doc_folder.get_documents (
1485 episodes = episodes,
1486 encounter = self._payload[self._idx['pk_encounter']]
1487 )
1488
1489 if len(docs) > 0:
1490 lines.append(u'')
1491 lines.append(_('Documents:'))
1492
1493 for d in docs:
1494 lines.append(u' %s %s:%s%s' % (
1495 d['clin_when'].strftime('%Y-%m-%d'),
1496 d['l10n_type'],
1497 gmTools.coalesce(d['comment'], u'', u' "%s"'),
1498 gmTools.coalesce(d['ext_ref'], u'', u' (%s)')
1499 ))
1500
1501 del docs
1502
1503 # co-encountlets
1504 if with_co_encountlet_hints:
1505 if episodes is not None:
1506 other_epis = self.get_episodes(exclude = episodes)
1507 if len(other_epis) > 0:
1508 lines.append(u'')
1509 lines.append(_('%s other episodes touched upon during this encounter:') % len(other_epis))
1510 for epi in other_epis:
1511 lines.append(u' %s%s%s%s' % (
1512 gmTools.u_left_double_angle_quote,
1513 epi['description'],
1514 gmTools.u_right_double_angle_quote,
1515 gmTools.coalesce(epi['health_issue'], u'', u' (%s)')
1516 ))
1517
1518 eol_w_margin = u'\n%s' % (u' ' * left_margin)
1519 return u'%s\n' % eol_w_margin.join(lines)
1520 #-----------------------------------------------------------
1522 """Creates a new encounter for a patient.
1523
1524 fk_patient - patient PK
1525 fk_location - encounter location
1526 enc_type - type of encounter
1527
1528 FIXME: we don't deal with location yet
1529 """
1530 if enc_type is None:
1531 enc_type = u'in surgery'
1532 # insert new encounter
1533 queries = []
1534 try:
1535 enc_type = int(enc_type)
1536 cmd = u"""
1537 INSERT INTO clin.encounter (
1538 fk_patient, fk_location, fk_type
1539 ) VALUES (
1540 %(pat)s,
1541 -1,
1542 %(typ)s
1543 ) RETURNING pk"""
1544 except ValueError:
1545 enc_type = enc_type
1546 cmd = u"""
1547 insert into clin.encounter (
1548 fk_patient, fk_location, fk_type
1549 ) values (
1550 %(pat)s,
1551 -1,
1552 coalesce((select pk from clin.encounter_type where description = %(typ)s), 0)
1553 ) RETURNING pk"""
1554 args = {'pat': fk_patient, 'typ': enc_type}
1555 queries.append({'cmd': cmd, 'args': args})
1556 rows, idx = gmPG2.run_rw_queries(queries = queries, return_data = True, get_col_idx = False)
1557 encounter = cEncounter(aPK_obj = rows[0]['pk'])
1558
1559 return encounter
1560 #-----------------------------------------------------------
1562
1563 rows, idx = gmPG2.run_rw_queries(
1564 queries = [{
1565 'cmd': u"select i18n.upd_tx(%(desc)s, %(l10n_desc)s)",
1566 'args': {'desc': description, 'l10n_desc': l10n_description}
1567 }],
1568 return_data = True
1569 )
1570
1571 success = rows[0][0]
1572 if not success:
1573 _log.warning('updating encounter type [%s] to [%s] failed', description, l10n_description)
1574
1575 return {'description': description, 'l10n_description': l10n_description}
1576 #-----------------------------------------------------------
1578 """This will attempt to create a NEW encounter type."""
1579
1580 # need a system name, so derive one if necessary
1581 if description is None:
1582 description = l10n_description
1583
1584 args = {
1585 'desc': description,
1586 'l10n_desc': l10n_description
1587 }
1588
1589 _log.debug('creating encounter type: %s, %s', description, l10n_description)
1590
1591 # does it exist already ?
1592 cmd = u"select description, _(description) from clin.encounter_type where description = %(desc)s"
1593 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}])
1594
1595 # yes
1596 if len(rows) > 0:
1597 # both system and l10n name are the same so all is well
1598 if (rows[0][0] == description) and (rows[0][1] == l10n_description):
1599 _log.info('encounter type [%s] already exists with the proper translation')
1600 return {'description': description, 'l10n_description': l10n_description}
1601
1602 # or maybe there just wasn't a translation to
1603 # the current language for this type yet ?
1604 cmd = u"select exists (select 1 from i18n.translations where orig = %(desc)s and lang = i18n.get_curr_lang())"
1605 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}])
1606
1607 # there was, so fail
1608 if rows[0][0]:
1609 _log.error('encounter type [%s] already exists but with another translation')
1610 return None
1611
1612 # else set it
1613 cmd = u"select i18n.upd_tx(%(desc)s, %(l10n_desc)s)"
1614 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
1615 return {'description': description, 'l10n_description': l10n_description}
1616
1617 # no
1618 queries = [
1619 {'cmd': u"insert into clin.encounter_type (description) values (%(desc)s)", 'args': args},
1620 {'cmd': u"select i18n.upd_tx(%(desc)s, %(l10n_desc)s)", 'args': args}
1621 ]
1622 rows, idx = gmPG2.run_rw_queries(queries = queries)
1623
1624 return {'description': description, 'l10n_description': l10n_description}
1625 #-----------------------------------------------------------
1627 cmd = u"select _(description) as l10n_description, description from clin.encounter_type"
1628 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}])
1629 return rows
1630 #-----------------------------------------------------------
1632 cmd = u"SELECT * from clin.encounter_type where description = %s"
1633 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': [description]}])
1634 return rows
1635 #-----------------------------------------------------------
1637 cmd = u"delete from clin.encounter_type where description = %(desc)s"
1638 args = {'desc': description}
1639 try:
1640 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
1641 except gmPG2.dbapi.IntegrityError, e:
1642 if e.pgcode == gmPG2.sql_error_codes.FOREIGN_KEY_VIOLATION:
1643 return False
1644 raise
1645
1646 return True
1647 #============================================================
1649 """Represents one problem.
1650
1651 problems are the aggregation of
1652 .clinically_relevant=True issues and
1653 .is_open=True episodes
1654 """
1655 _cmd_fetch_payload = u'' # will get programmatically defined in __init__
1656 _cmds_store_payload = [u"select 1"]
1657 _updatable_fields = []
1658
1659 #--------------------------------------------------------
1661 """Initialize.
1662
1663 aPK_obj must contain the keys
1664 pk_patient
1665 pk_episode
1666 pk_health_issue
1667 """
1668 if aPK_obj is None:
1669 raise gmExceptions.ConstructorError, 'cannot instatiate cProblem for PK: [%s]' % (aPK_obj)
1670
1671 # As problems are rows from a view of different emr struct items,
1672 # the PK can't be a single field and, as some of the values of the
1673 # composed PK may be None, they must be queried using 'is null',
1674 # so we must programmatically construct the SQL query
1675 where_parts = []
1676 pk = {}
1677 for col_name in aPK_obj.keys():
1678 val = aPK_obj[col_name]
1679 if val is None:
1680 where_parts.append('%s IS NULL' % col_name)
1681 else:
1682 where_parts.append('%s = %%(%s)s' % (col_name, col_name))
1683 pk[col_name] = val
1684
1685 # try to instantiate from true problem view
1686 cProblem._cmd_fetch_payload = u"""
1687 SELECT *, False as is_potential_problem
1688 FROM clin.v_problem_list
1689 WHERE %s""" % u' AND '.join(where_parts)
1690
1691 try:
1692 gmBusinessDBObject.cBusinessDBObject.__init__(self, aPK_obj=pk)
1693 return
1694 except gmExceptions.ConstructorError:
1695 _log.exception('actual problem not found, trying "potential" problems')
1696 if try_potential_problems is False:
1697 raise
1698
1699 # try to instantiate from potential-problems view
1700 cProblem._cmd_fetch_payload = u"""
1701 SELECT *, True as is_potential_problem
1702 FROM clin.v_potential_problem_list
1703 WHERE %s""" % u' AND '.join(where_parts)
1704 gmBusinessDBObject.cBusinessDBObject.__init__(self, aPK_obj=pk)
1705 #--------------------------------------------------------
1707 """
1708 Retrieve the cEpisode instance equivalent to this problem.
1709 The problem's type attribute must be 'episode'
1710 """
1711 if self._payload[self._idx['type']] != 'episode':
1712 _log.error('cannot convert problem [%s] of type [%s] to episode' % (self._payload[self._idx['problem']], self._payload[self._idx['type']]))
1713 return None
1714 return cEpisode(aPK_obj = self._payload[self._idx['pk_episode']])
1715 #--------------------------------------------------------
1717
1718 if self._payload[self._idx['type']] == u'issue':
1719 episodes = [ cHealthIssue(aPK_obj = self._payload[self._idx['pk_health_issue']]).latest_episode ]
1720 #xxxxxxxxxxxxx
1721
1722 emr = patient.get_emr()
1723
1724 doc_folder = gmDocuments.cDocumentFolder(aPKey = patient.ID)
1725 return doc_folder.get_visual_progress_notes (
1726 health_issue = self._payload[self._idx['pk_health_issue']],
1727 episode = self._payload[self._idx['pk_episode']]
1728 )
1729 #--------------------------------------------------------
1730 # properties
1731 #--------------------------------------------------------
1732 # doubles as 'diagnostic_certainty_description' getter:
1734 return diagnostic_certainty_classification2str(self._payload[self._idx['diagnostic_certainty_classification']])
1735
1736 diagnostic_certainty_description = property(get_diagnostic_certainty_description, lambda x:x)
1737 #-----------------------------------------------------------
1739 """Retrieve the cEpisode instance equivalent to the given problem.
1740
1741 The problem's type attribute must be 'episode'
1742
1743 @param problem: The problem to retrieve its related episode for
1744 @type problem: A gmEMRStructItems.cProblem instance
1745 """
1746 if isinstance(problem, cEpisode):
1747 return problem
1748
1749 exc = TypeError('cannot convert [%s] to episode' % problem)
1750
1751 if not isinstance(problem, cProblem):
1752 raise exc
1753
1754 if problem['type'] != 'episode':
1755 raise exc
1756
1757 return cEpisode(aPK_obj = problem['pk_episode'])
1758 #-----------------------------------------------------------
1760 """Retrieve the cIssue instance equivalent to the given problem.
1761
1762 The problem's type attribute must be 'issue'.
1763
1764 @param problem: The problem to retrieve the corresponding issue for
1765 @type problem: A gmEMRStructItems.cProblem instance
1766 """
1767 if isinstance(problem, cHealthIssue):
1768 return problem
1769
1770 exc = TypeError('cannot convert [%s] to health issue' % problem)
1771
1772 if not isinstance(problem, cProblem):
1773 raise exc
1774
1775 if problem['type'] != 'issue':
1776 raise exc
1777
1778 return cHealthIssue(aPK_obj = problem['pk_health_issue'])
1779 #-----------------------------------------------------------
1781 """Transform given problem into either episode or health issue instance.
1782 """
1783 if isinstance(problem, (cEpisode, cHealthIssue)):
1784 return problem
1785
1786 exc = TypeError('cannot reclass [%s] instance to either episode or health issue' % type(problem))
1787
1788 if not isinstance(problem, cProblem):
1789 _log.debug(u'%s' % problem)
1790 raise exc
1791
1792 if problem['type'] == 'episode':
1793 return cEpisode(aPK_obj = problem['pk_episode'])
1794
1795 if problem['type'] == 'issue':
1796 return cHealthIssue(aPK_obj = problem['pk_health_issue'])
1797
1798 raise exc
1799 #============================================================
1801
1802 _cmd_fetch_payload = u"select * from clin.v_pat_hospital_stays where pk_hospital_stay = %s"
1803 _cmds_store_payload = [
1804 u"""update clin.hospital_stay set
1805 clin_when = %(admission)s,
1806 discharge = %(discharge)s,
1807 narrative = gm.nullify_empty_string(%(hospital)s),
1808 fk_episode = %(pk_episode)s,
1809 fk_encounter = %(pk_encounter)s
1810 where
1811 pk = %(pk_hospital_stay)s and
1812 xmin = %(xmin_hospital_stay)s""",
1813 u"""select xmin_hospital_stay from clin.v_pat_hospital_stays where pk_hospital_stay = %(pk_hospital_stay)s"""
1814 ]
1815 _updatable_fields = [
1816 'admission',
1817 'discharge',
1818 'hospital',
1819 'pk_episode',
1820 'pk_encounter'
1821 ]
1822 #-------------------------------------------------------
1824
1825 if self._payload[self._idx['discharge']] is not None:
1826 dis = u' - %s' % self._payload[self._idx['discharge']].strftime('%Y %b %d').decode(gmI18N.get_encoding())
1827 else:
1828 dis = u''
1829
1830 line = u'%s%s%s%s: %s%s%s' % (
1831 u' ' * left_margin,
1832 self._payload[self._idx['admission']].strftime('%Y %b %d').decode(gmI18N.get_encoding()),
1833 dis,
1834 gmTools.coalesce(self._payload[self._idx['hospital']], u'', u' (%s)'),
1835 gmTools.u_left_double_angle_quote,
1836 self._payload[self._idx['episode']],
1837 gmTools.u_right_double_angle_quote
1838 )
1839
1840 return line
1841 #-----------------------------------------------------------
1843
1844 queries = [{
1845 'cmd': u'SELECT * FROM clin.v_pat_hospital_stays WHERE pk_patient = %(pat)s ORDER BY admission',
1846 'args': {'pat': patient}
1847 }]
1848
1849 rows, idx = gmPG2.run_ro_queries(queries = queries, get_col_idx = True)
1850
1851 return [ cHospitalStay(row = {'idx': idx, 'data': r, 'pk_field': 'pk_hospital_stay'}) for r in rows ]
1852 #-----------------------------------------------------------
1854
1855 queries = [{
1856 'cmd': u'INSERT INTO clin.hospital_stay (fk_encounter, fk_episode) VALUES (%(enc)s, %(epi)s) RETURNING pk',
1857 'args': {'enc': encounter, 'epi': episode}
1858 }]
1859 rows, idx = gmPG2.run_rw_queries(queries = queries, return_data = True)
1860
1861 return cHospitalStay(aPK_obj = rows[0][0])
1862 #-----------------------------------------------------------
1864 cmd = u'DELETE FROM clin.hospital_stay WHERE pk = %(pk)s'
1865 args = {'pk': stay}
1866 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
1867 return True
1868 #============================================================
1870
1871 _cmd_fetch_payload = u"select * from clin.v_pat_procedures where pk_procedure = %s"
1872 _cmds_store_payload = [
1873 u"""UPDATE clin.procedure SET
1874 soap_cat = 'p',
1875 clin_when = %(clin_when)s,
1876 clin_end = %(clin_end)s,
1877 is_ongoing = %(is_ongoing)s,
1878 clin_where = NULLIF (
1879 COALESCE (
1880 %(pk_hospital_stay)s::TEXT,
1881 gm.nullify_empty_string(%(clin_where)s)
1882 ),
1883 %(pk_hospital_stay)s::TEXT
1884 ),
1885 narrative = gm.nullify_empty_string(%(performed_procedure)s),
1886 fk_hospital_stay = %(pk_hospital_stay)s,
1887 fk_episode = %(pk_episode)s,
1888 fk_encounter = %(pk_encounter)s
1889 WHERE
1890 pk = %(pk_procedure)s AND
1891 xmin = %(xmin_procedure)s
1892 RETURNING xmin as xmin_procedure"""
1893 ]
1894 _updatable_fields = [
1895 'clin_when',
1896 'clin_end',
1897 'is_ongoing',
1898 'clin_where',
1899 'performed_procedure',
1900 'pk_hospital_stay',
1901 'pk_episode',
1902 'pk_encounter'
1903 ]
1904 #-------------------------------------------------------
1906
1907 if (attribute == 'pk_hospital_stay') and (value is not None):
1908 gmBusinessDBObject.cBusinessDBObject.__setitem__(self, 'clin_where', None)
1909
1910 if (attribute == 'clin_where') and (value is not None) and (value.strip() != u''):
1911 gmBusinessDBObject.cBusinessDBObject.__setitem__(self, 'pk_hospital_stay', None)
1912
1913 gmBusinessDBObject.cBusinessDBObject.__setitem__(self, attribute, value)
1914 #-------------------------------------------------------
1916
1917 if self._payload[self._idx['is_ongoing']]:
1918 end = _(' (ongoing)')
1919 else:
1920 end = self._payload[self._idx['clin_end']]
1921 if end is None:
1922 end = u''
1923 else:
1924 end = u' - %s' % end.strftime('%Y %b %d').decode(gmI18N.get_encoding())
1925
1926 line = u'%s%s%s, %s: %s' % (
1927 (u' ' * left_margin),
1928 self._payload[self._idx['clin_when']].strftime('%Y %b %d').decode(gmI18N.get_encoding()),
1929 end,
1930 self._payload[self._idx['clin_where']],
1931 self._payload[self._idx['performed_procedure']]
1932 )
1933 if include_episode:
1934 line = u'%s (%s)' % (line, self._payload[self._idx['episode']])
1935
1936 return line
1937 #-----------------------------------------------------------
1939
1940 queries = [
1941 {
1942 'cmd': u'select * from clin.v_pat_procedures where pk_patient = %(pat)s order by clin_when',
1943 'args': {'pat': patient}
1944 }
1945 ]
1946
1947 rows, idx = gmPG2.run_ro_queries(queries = queries, get_col_idx = True)
1948
1949 return [ cPerformedProcedure(row = {'idx': idx, 'data': r, 'pk_field': 'pk_procedure'}) for r in rows ]
1950 #-----------------------------------------------------------
1951 -def create_performed_procedure(encounter=None, episode=None, location=None, hospital_stay=None, procedure=None):
1952
1953 queries = [{
1954 'cmd': u"""
1955 INSERT INTO clin.procedure (
1956 fk_encounter,
1957 fk_episode,
1958 soap_cat,
1959 clin_where,
1960 fk_hospital_stay,
1961 narrative
1962 ) VALUES (
1963 %(enc)s,
1964 %(epi)s,
1965 'p',
1966 gm.nullify_empty_string(%(loc)s),
1967 %(stay)s,
1968 gm.nullify_empty_string(%(proc)s)
1969 )
1970 RETURNING pk""",
1971 'args': {'enc': encounter, 'epi': episode, 'loc': location, 'stay': hospital_stay, 'proc': procedure}
1972 }]
1973
1974 rows, idx = gmPG2.run_rw_queries(queries = queries, return_data = True)
1975
1976 return cPerformedProcedure(aPK_obj = rows[0][0])
1977 #-----------------------------------------------------------
1979 cmd = u'delete from clin.procedure where pk = %(pk)s'
1980 args = {'pk': procedure}
1981 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
1982 return True
1983 #============================================================
1984 # main - unit testing
1985 #------------------------------------------------------------
1986 if __name__ == '__main__':
1987
1988 if len(sys.argv) < 2:
1989 sys.exit()
1990
1991 if sys.argv[1] != 'test':
1992 sys.exit()
1993
1994 #--------------------------------------------------------
1995 # define tests
1996 #--------------------------------------------------------
1998 print "\nProblem test"
1999 print "------------"
2000 prob = cProblem(aPK_obj={'pk_patient': 12, 'pk_health_issue': 1, 'pk_episode': None})
2001 print prob
2002 fields = prob.get_fields()
2003 for field in fields:
2004 print field, ':', prob[field]
2005 print '\nupdatable:', prob.get_updatable_fields()
2006 epi = prob.get_as_episode()
2007 print '\nas episode:'
2008 if epi is not None:
2009 for field in epi.get_fields():
2010 print ' .%s : %s' % (field, epi[field])
2011 #--------------------------------------------------------
2013 print "\nhealth issue test"
2014 print "-----------------"
2015 h_issue = cHealthIssue(aPK_obj=2)
2016 print h_issue
2017 fields = h_issue.get_fields()
2018 for field in fields:
2019 print field, ':', h_issue[field]
2020 print "has open episode:", h_issue.has_open_episode()
2021 print "open episode:", h_issue.get_open_episode()
2022 print "updateable:", h_issue.get_updatable_fields()
2023 h_issue.close_expired_episode(ttl=7300)
2024 h_issue = cHealthIssue(encounter = 1, name = u'post appendectomy/peritonitis')
2025 print h_issue
2026 print h_issue.format_as_journal()
2027 #--------------------------------------------------------
2029 print "\nepisode test"
2030 print "------------"
2031 episode = cEpisode(aPK_obj=1)
2032 print episode
2033 fields = episode.get_fields()
2034 for field in fields:
2035 print field, ':', episode[field]
2036 print "updatable:", episode.get_updatable_fields()
2037 raw_input('ENTER to continue')
2038
2039 old_description = episode['description']
2040 old_enc = cEncounter(aPK_obj = 1)
2041
2042 desc = '1-%s' % episode['description']
2043 print "==> renaming to", desc
2044 successful = episode.rename (
2045 description = desc
2046 )
2047 if not successful:
2048 print "error"
2049 else:
2050 print "success"
2051 for field in fields:
2052 print field, ':', episode[field]
2053
2054 print "episode range:", episode.get_access_range()
2055
2056 raw_input('ENTER to continue')
2057
2058 #--------------------------------------------------------
2060 print "\nencounter test"
2061 print "--------------"
2062 encounter = cEncounter(aPK_obj=1)
2063 print encounter
2064 fields = encounter.get_fields()
2065 for field in fields:
2066 print field, ':', encounter[field]
2067 print "updatable:", encounter.get_updatable_fields()
2068 #--------------------------------------------------------
2070 encounter = cEncounter(aPK_obj=1)
2071 print encounter
2072 print ""
2073 print encounter.format_latex()
2074 #--------------------------------------------------------
2076 procs = get_performed_procedures(patient = 12)
2077 for proc in procs:
2078 print proc.format(left_margin=2)
2079 #--------------------------------------------------------
2081 stay = create_hospital_stay(encounter = 1, episode = 2)
2082 stay['hospital'] = u'Starfleet Galaxy General Hospital'
2083 stay.save_payload()
2084 print stay
2085 for s in get_patient_hospital_stays(12):
2086 print s
2087 delete_hospital_stay(stay['pk_hospital_stay'])
2088 stay = create_hospital_stay(encounter = 1, episode = 4)
2089 #--------------------------------------------------------
2091 tests = [None, 'A', 'B', 'C', 'D', 'E']
2092
2093 for t in tests:
2094 print type(t), t
2095 print type(diagnostic_certainty_classification2str(t)), diagnostic_certainty_classification2str(t)
2096
2097 #--------------------------------------------------------
2098 # run them
2099 #test_episode()
2100 #test_problem()
2101 #test_encounter()
2102 #test_health_issue()
2103 #test_hospital_stay()
2104 #test_performed_procedure()
2105 #test_diagnostic_certainty_classification_map()
2106 test_encounter2latex()
2107 #============================================================
2108
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Thu May 19 03:59:05 2011 | http://epydoc.sourceforge.net |