| 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 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)
474 #============================================================
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_issue
497 #-----------------------------------------------------------
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 episodes
513 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 issue
526 #-----------------------------------------------------------
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 #--------------------------------------------------------
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 True
671 #--------------------------------------------------------
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)
943 #============================================================
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 episode
968 #-----------------------------------------------------------
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 #--------------------------------------------------------
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 True
1061 #--------------------------------------------------------
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 True
1096 #--------------------------------------------------------
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 lines
1245 #--------------------------------------------------------
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 tex
1302 #--------------------------------------------------------
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)
1450 #-----------------------------------------------------------
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 encounter
1486 #-----------------------------------------------------------
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 rows
1556 #-----------------------------------------------------------
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 rows
1561 #-----------------------------------------------------------
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 True
1573 #============================================================
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 #--------------------------------------------------------
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)
1663 #-----------------------------------------------------------
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 exc
1725 #============================================================
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 #-------------------------------------------------------
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 line
1767 #-----------------------------------------------------------
1769
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 True
1794 #============================================================
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 #-------------------------------------------------------
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 line
1863 #-----------------------------------------------------------
1865
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 True
1909 #============================================================
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 Tue Apr 12 03:59:03 2011 | http://epydoc.sourceforge.net |