| 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, gmExceptions, gmNull, gmBusinessDBObject, gmDateTime, gmTools, gmI18N
16 from Gnumed.business import gmClinNarrative
17
18
19 _log = logging.getLogger('gm.emr')
20 _log.info(__version__)
21
22 try: _
23 except NameError: _ = lambda x:x
24 #============================================================
25 # diagnostic certainty classification
26 #============================================================
27 __diagnostic_certainty_classification_map = None
28
30
31 global __diagnostic_certainty_classification_map
32
33 if __diagnostic_certainty_classification_map is None:
34 __diagnostic_certainty_classification_map = {
35 None: u'',
36 u'A': _(u'A: Sign'),
37 u'B': _(u'B: Cluster of signs'),
38 u'C': _(u'C: Syndromic diagnosis'),
39 u'D': _(u'D: Scientific diagnosis')
40 }
41
42 try:
43 return __diagnostic_certainty_classification_map[classification]
44 except KeyError:
45 return _(u'%s: unknown diagnostic certainty classification') % classification
46 #============================================================
47 # Health Issues API
48 #============================================================
49 laterality2str = {
50 None: u'?',
51 u'na': u'',
52 u'sd': _('bilateral'),
53 u'ds': _('bilateral'),
54 u's': _('left'),
55 u'd': _('right')
56 }
57
58 #============================================================
60 """Represents one health issue."""
61
62 _cmd_fetch_payload = u"select *, xmin_health_issue from clin.v_health_issues where pk_health_issue=%s"
63 _cmds_store_payload = [
64 u"""update clin.health_issue set
65 description = %(description)s,
66 age_noted = %(age_noted)s,
67 laterality = gm.nullify_empty_string(%(laterality)s),
68 grouping = gm.nullify_empty_string(%(grouping)s),
69 diagnostic_certainty_classification = gm.nullify_empty_string(%(diagnostic_certainty_classification)s),
70 is_active = %(is_active)s,
71 clinically_relevant = %(clinically_relevant)s,
72 is_confidential = %(is_confidential)s,
73 is_cause_of_death = %(is_cause_of_death)s
74 where
75 pk = %(pk_health_issue)s and
76 xmin = %(xmin_health_issue)s""",
77 u"select xmin as xmin_health_issue from clin.health_issue where pk = %(pk_health_issue)s"
78 ]
79 _updatable_fields = [
80 'description',
81 'grouping',
82 'age_noted',
83 'laterality',
84 'is_active',
85 'clinically_relevant',
86 'is_confidential',
87 'is_cause_of_death',
88 'diagnostic_certainty_classification'
89 ]
90 #--------------------------------------------------------
91 - def __init__(self, aPK_obj=None, encounter=None, name='xxxDEFAULTxxx', patient=None, row=None):
92 pk = aPK_obj
93
94 if (pk is not None) or (row is not None):
95 gmBusinessDBObject.cBusinessDBObject.__init__(self, aPK_obj=pk, row=row)
96 return
97
98 if patient is None:
99 cmd = u"""select *, xmin_health_issue from clin.v_health_issues
100 where
101 description = %(desc)s
102 and
103 pk_patient = (select fk_patient from clin.encounter where pk = %(enc)s)"""
104 else:
105 cmd = u"""select *, xmin_health_issue from clin.v_health_issues
106 where
107 description = %(desc)s
108 and
109 pk_patient = %(pat)s"""
110
111 queries = [{'cmd': cmd, 'args': {'enc': encounter, 'desc': name, 'pat': patient}}]
112 rows, idx = gmPG2.run_ro_queries(queries = queries, get_col_idx = True)
113
114 if len(rows) == 0:
115 raise gmExceptions.NoSuchBusinessObjectError, 'no health issue for [enc:%s::desc:%s::pat:%s]' % (encounter, name, patient)
116
117 pk = rows[0][0]
118 r = {'idx': idx, 'data': rows[0], 'pk_field': 'pk_health_issue'}
119
120 gmBusinessDBObject.cBusinessDBObject.__init__(self, row=r)
121 #--------------------------------------------------------
123 """Method for issue renaming.
124
125 @param description
126 - the new descriptive name for the issue
127 @type description
128 - a string instance
129 """
130 # sanity check
131 if not type(description) in [str, unicode] or description.strip() == '':
132 _log.error('<description> must be a non-empty string')
133 return False
134 # update the issue description
135 old_description = self._payload[self._idx['description']]
136 self._payload[self._idx['description']] = description.strip()
137 self._is_modified = True
138 successful, data = self.save_payload()
139 if not successful:
140 _log.error('cannot rename health issue [%s] with [%s]' % (self, description))
141 self._payload[self._idx['description']] = old_description
142 return False
143 return True
144 #--------------------------------------------------------
146 cmd = u"select * from clin.v_pat_episodes where pk_health_issue = %(pk)s"
147 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': {'pk': self.pk_obj}}], get_col_idx = True)
148 return [ cEpisode(row = {'data': r, 'idx': idx, 'pk_field': 'pk_episode'}) for r in rows ]
149 #--------------------------------------------------------
151 """ttl in days"""
152 open_episode = self.get_open_episode()
153 if open_episode is None:
154 return True
155 earliest, latest = open_episode.get_access_range()
156 ttl = datetime.timedelta(ttl)
157 now = datetime.datetime.now(tz=latest.tzinfo)
158 if (latest + ttl) > now:
159 return False
160 open_episode['episode_open'] = False
161 success, data = open_episode.save_payload()
162 if success:
163 return True
164 return False # should be an exception
165 #--------------------------------------------------------
167 open_episode = self.get_open_episode()
168 open_episode['episode_open'] = False
169 success, data = open_episode.save_payload()
170 if success:
171 return True
172 return False
173 #--------------------------------------------------------
175 cmd = u"select exists (select 1 from clin.episode where fk_health_issue = %s and is_open is True)"
176 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': [self.pk_obj]}])
177 return rows[0][0]
178 #--------------------------------------------------------
180 cmd = u"select pk from clin.episode where fk_health_issue = %s and is_open is True"
181 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': [self.pk_obj]}])
182 if len(rows) == 0:
183 return None
184 return cEpisode(aPK_obj=rows[0][0])
185 #--------------------------------------------------------
187 if self._payload[self._idx['age_noted']] is None:
188 return u'<???>'
189
190 return gmDateTime.format_interval_medically(self._payload[self._idx['age_noted']])
191 #--------------------------------------------------------
193 try:
194 return laterality2str[self._payload[self._idx['laterality']]]
195 except KeyError:
196 return u'<???>'
197
198 laterality_description = property(_get_laterality_description, lambda x:x)
199 #--------------------------------------------------------
201 return diagnostic_certainty_classification2str(self._payload[self._idx['diagnostic_certainty_classification']])
202
203 diagnostic_certainty_description = property(_get_diagnostic_certainty_description, lambda x:x)
204 #--------------------------------------------------------
206
207 if patient.ID != self._payload[self._idx['pk_patient']]:
208 msg = '<patient>.ID = %s but health issue %s belongs to patient %s' % (
209 patient.ID,
210 self._payload[self._idx['pk_health_issue']],
211 self._payload[self._idx['pk_patient']]
212 )
213 raise ValueError(msg)
214
215 lines = []
216
217 lines.append(_('Health Issue %s%s%s%s [#%s]') % (
218 u'\u00BB',
219 self._payload[self._idx['description']],
220 u'\u00AB',
221 gmTools.coalesce (
222 initial = self.laterality_description,
223 instead = u'',
224 template_initial = u' (%s)',
225 none_equivalents = [None, u'', u'?']
226 ),
227 self._payload[self._idx['pk_health_issue']]
228 ))
229
230 if self._payload[self._idx['is_confidential']]:
231 lines.append('')
232 lines.append(_(' ***** CONFIDENTIAL *****'))
233 lines.append('')
234
235 if self._payload[self._idx['is_cause_of_death']]:
236 lines.append('')
237 lines.append(_(' contributed to death of patient'))
238 lines.append('')
239
240 enc = cEncounter(aPK_obj = self._payload[self._idx['pk_encounter']])
241 lines.append (_(' Created during encounter: %s (%s - %s) [#%s]') % (
242 enc['l10n_type'],
243 enc['started_original_tz'].strftime('%Y-%m-%d %H:%M'),
244 enc['last_affirmed_original_tz'].strftime('%H:%M'),
245 self._payload[self._idx['pk_encounter']]
246 ))
247
248 if self._payload[self._idx['age_noted']] is not None:
249 lines.append(_(' Noted at age: %s') % self.age_noted_human_readable())
250
251 lines.append(_(' Status: %s, %s%s') % (
252 gmTools.bool2subst(self._payload[self._idx['is_active']], _('active'), _('inactive')),
253 gmTools.bool2subst(self._payload[self._idx['clinically_relevant']], _('clinically relevant'), _('not clinically relevant')),
254 gmTools.coalesce (
255 initial = diagnostic_certainty_classification2str(self._payload[self._idx['diagnostic_certainty_classification']]),
256 instead = u'',
257 template_initial = u', %s',
258 none_equivalents = [None, u'']
259 ),
260 ))
261 lines.append('')
262
263 emr = patient.get_emr()
264
265 # episodes
266 epis = emr.get_episodes(issues = [self._payload[self._idx['pk_health_issue']]])
267 if epis is None:
268 lines.append(_('Error retrieving episodes for this health issue.'))
269 elif len(epis) == 0:
270 lines.append(_('There are no episodes for this health issue.'))
271 else:
272 lines.append (
273 _('Episodes: %s (most recent: %s%s%s)') % (
274 len(epis),
275 gmTools.u_left_double_angle_quote,
276 emr.get_most_recent_episode(issue = self._payload[self._idx['pk_health_issue']])['description'],
277 gmTools.u_right_double_angle_quote
278 )
279 )
280 lines.append('')
281 for epi in epis:
282 lines.append(u' \u00BB%s\u00AB (%s)' % (
283 epi['description'],
284 gmTools.bool2subst(epi['episode_open'], _('ongoing'), _('closed'))
285 ))
286
287 lines.append('')
288
289 # encounters
290 first_encounter = emr.get_first_encounter(issue_id = self._payload[self._idx['pk_health_issue']])
291 last_encounter = emr.get_last_encounter(issue_id = self._payload[self._idx['pk_health_issue']])
292
293 if first_encounter is None or last_encounter is None:
294 lines.append(_('No encounters found for this health issue.'))
295 else:
296 encs = emr.get_encounters(issues = [self._payload[self._idx['pk_health_issue']]])
297 lines.append(_('Encounters: %s (%s - %s):') % (
298 len(encs),
299 first_encounter['started_original_tz'].strftime('%m/%Y'),
300 last_encounter['last_affirmed_original_tz'].strftime('%m/%Y')
301 ))
302 lines.append(_(' Most recent: %s - %s') % (
303 last_encounter['started_original_tz'].strftime('%Y-%m-%d %H:%M'),
304 last_encounter['last_affirmed_original_tz'].strftime('%H:%M')
305 ))
306
307 # medications
308 meds = emr.get_current_substance_intake (
309 issues = [ self._payload[self._idx['pk_health_issue']] ],
310 order_by = u'is_currently_active, started, substance'
311 )
312
313 if len(meds) > 0:
314 lines.append(u'')
315 lines.append(_('Active medications: %s') % len(meds))
316 for m in meds:
317 lines.append(m.format(left_margin = (left_margin + 1)))
318 del meds
319
320 # hospital stays
321 stays = emr.get_hospital_stays (
322 issues = [ self._payload[self._idx['pk_health_issue']] ]
323 )
324
325 if len(stays) > 0:
326 lines.append(u'')
327 lines.append(_('Hospital stays: %s') % len(stays))
328 for s in stays:
329 lines.append(s.format(left_margin = (left_margin + 1)))
330 del stays
331
332 # procedures
333 procs = emr.get_performed_procedures (
334 issues = [ self._payload[self._idx['pk_health_issue']] ]
335 )
336
337 if len(procs) > 0:
338 lines.append(u'')
339 lines.append(_('Procedures performed: %s') % len(procs))
340 for p in procs:
341 lines.append(p.format(left_margin = (left_margin + 1)))
342 del procs
343
344 epis = self.get_episodes()
345 if len(epis) > 0:
346 epi_pks = [ e['pk_episode'] for e in epis ]
347
348 # documents
349 doc_folder = patient.get_document_folder()
350 docs = doc_folder.get_documents(episodes = epi_pks)
351 if len(docs) > 0:
352 lines.append(u'')
353 lines.append(_('Documents: %s') % len(docs))
354 del docs
355
356 # test results
357 tests = emr.get_test_results_by_date(episodes = epi_pks)
358 if len(tests) > 0:
359 lines.append(u'')
360 lines.append(_('Measurements and Results: %s') % len(tests))
361 del tests
362
363 # vaccinations
364 vaccs = emr.get_vaccinations(episodes = epi_pks)
365 if len(vaccs) > 0:
366 lines.append(u'')
367 lines.append(_('Vaccinations:'))
368 for vacc in vaccs:
369 lines.extend(vacc.format(with_reaction = True))
370 del vaccs
371
372 del epis
373
374 left_margin = u' ' * left_margin
375 eol_w_margin = u'\n%s' % left_margin
376 return left_margin + eol_w_margin.join(lines) + u'\n'
377 #============================================================
379 """Creates a new health issue for a given patient.
380
381 description - health issue name
382 """
383 try:
384 h_issue = cHealthIssue(name = description, encounter = encounter, patient = patient)
385 return h_issue
386 except gmExceptions.NoSuchBusinessObjectError:
387 pass
388
389 queries = []
390 cmd = u"insert into clin.health_issue (description, fk_encounter) values (%(desc)s, %(enc)s)"
391 queries.append({'cmd': cmd, 'args': {'desc': description, 'enc': encounter}})
392
393 cmd = u"select currval('clin.health_issue_pk_seq')"
394 queries.append({'cmd': cmd})
395
396 rows, idx = gmPG2.run_rw_queries(queries = queries, return_data = True)
397 h_issue = cHealthIssue(aPK_obj = rows[0][0])
398
399 return h_issue
400 #-----------------------------------------------------------
402 if isinstance(health_issue, cHealthIssue):
403 pk = health_issue['pk_health_issue']
404 else:
405 pk = int(health_issue)
406
407 try:
408 gmPG2.run_rw_queries(queries = [{'cmd': u'delete from clin.health_issue where pk=%(pk)s', 'args': {'pk': pk}}])
409 except gmPG2.dbapi.IntegrityError:
410 # should be parsing pgcode/and or error message
411 _log.exception('cannot delete health issue')
412 raise gmExceptions.DatabaseObjectInUseError('cannot delete health issue, it is in use')
413 #------------------------------------------------------------
414 # use as dummy for unassociated episodes
416 issue = {
417 'pk_health_issue': None,
418 'description': _('Unattributed episodes'),
419 'age_noted': None,
420 'laterality': u'na',
421 'is_active': True,
422 'clinically_relevant': True,
423 'is_confidential': None,
424 'is_cause_of_death': False,
425 'is_dummy': True
426 }
427 return issue
428 #-----------------------------------------------------------
430 return cProblem (
431 aPK_obj = {
432 'pk_patient': health_issue['pk_patient'],
433 'pk_health_issue': health_issue['pk_health_issue'],
434 'pk_episode': None
435 },
436 try_potential_problems = allow_irrelevant
437 )
438 #============================================================
439 # episodes API
440 #============================================================
442 """Represents one clinical episode.
443 """
444 _cmd_fetch_payload = u"select * from clin.v_pat_episodes where pk_episode=%s"
445 _cmds_store_payload = [
446 u"""update clin.episode set
447 fk_health_issue = %(pk_health_issue)s,
448 is_open = %(episode_open)s::boolean,
449 description = %(description)s,
450 diagnostic_certainty_classification = gm.nullify_empty_string(%(diagnostic_certainty_classification)s)
451 where
452 pk = %(pk_episode)s and
453 xmin = %(xmin_episode)s""",
454 u"""select xmin_episode from clin.v_pat_episodes where pk_episode = %(pk_episode)s"""
455 ]
456 _updatable_fields = [
457 'pk_health_issue',
458 'episode_open',
459 'description',
460 'diagnostic_certainty_classification'
461 ]
462 #--------------------------------------------------------
463 - def __init__(self, aPK_obj=None, id_patient=None, name='xxxDEFAULTxxx', health_issue=None, row=None, encounter=None):
464 pk = aPK_obj
465 if pk is None and row is None:
466
467 where_parts = [u'description = %(desc)s']
468
469 if id_patient is not None:
470 where_parts.append(u'pk_patient = %(pat)s')
471
472 if health_issue is not None:
473 where_parts.append(u'pk_health_issue = %(issue)s')
474
475 if encounter is not None:
476 where_parts.append(u'pk_patient = (select fk_patient from clin.encounter where pk = %(enc)s)')
477
478 args = {
479 'pat': id_patient,
480 'issue': health_issue,
481 'enc': encounter,
482 'desc': name
483 }
484
485 cmd = u"select * from clin.v_pat_episodes where %s" % u' and '.join(where_parts)
486
487 rows, idx = gmPG2.run_ro_queries(
488 queries = [{'cmd': cmd, 'args': args}],
489 get_col_idx=True
490 )
491
492 if len(rows) == 0:
493 raise gmExceptions.NoSuchBusinessObjectError, 'no episode for [%s:%s:%s:%s]' % (id_patient, name, health_issue, encounter)
494
495 r = {'idx': idx, 'data': rows[0], 'pk_field': 'pk_episode'}
496 gmBusinessDBObject.cBusinessDBObject.__init__(self, row=r)
497
498 else:
499 gmBusinessDBObject.cBusinessDBObject.__init__(self, aPK_obj=pk, row=row)
500 #--------------------------------------------------------
502 """Get earliest and latest access to this episode.
503
504 Returns a tuple(earliest, latest).
505 """
506 cmd = u"""
507 select
508 min(earliest),
509 max(latest)
510 from (
511 (select
512 (case when clin_when < modified_when
513 then clin_when
514 else modified_when
515 end) as earliest,
516 (case when clin_when > modified_when
517 then clin_when
518 else modified_when
519 end) as latest
520 from
521 clin.clin_root_item
522 where
523 fk_episode = %(pk)s
524
525 ) union all (
526
527 select
528 modified_when as earliest,
529 modified_when as latest
530 from
531 clin.episode
532 where
533 pk = %(pk)s
534 )
535 ) as ranges"""
536 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': {'pk': self.pk_obj}}])
537 if len(rows) == 0:
538 return (gmNull.cNull(warn=False), gmNull.cNull(warn=False))
539 return (rows[0][0], rows[0][1])
540 #--------------------------------------------------------
543 #--------------------------------------------------------
545 """Method for episode editing, that is, episode renaming.
546
547 @param description
548 - the new descriptive name for the encounter
549 @type description
550 - a string instance
551 """
552 # sanity check
553 if description.strip() == '':
554 _log.error('<description> must be a non-empty string instance')
555 return False
556 # update the episode description
557 old_description = self._payload[self._idx['description']]
558 self._payload[self._idx['description']] = description.strip()
559 self._is_modified = True
560 successful, data = self.save_payload()
561 if not successful:
562 _log.error('cannot rename episode [%s] to [%s]' % (self, description))
563 self._payload[self._idx['description']] = old_description
564 return False
565 return True
566 #--------------------------------------------------------
568 return diagnostic_certainty_classification2str(self._payload[self._idx['diagnostic_certainty_classification']])
569
570 diagnostic_certainty_description = property(_get_diagnostic_certainty_description, lambda x:x)
571 #--------------------------------------------------------
573
574 if patient.ID != self._payload[self._idx['pk_patient']]:
575 msg = '<patient>.ID = %s but episode %s belongs to patient %s' % (
576 patient.ID,
577 self._payload[self._idx['pk_episode']],
578 self._payload[self._idx['pk_patient']]
579 )
580 raise ValueError(msg)
581
582 lines = []
583
584 # episode details
585 lines.append (_('Episode %s%s%s (%s%s) [#%s]\n') % (
586 gmTools.u_left_double_angle_quote,
587 self._payload[self._idx['description']],
588 gmTools.u_right_double_angle_quote,
589 gmTools.coalesce (
590 initial = diagnostic_certainty_classification2str(self._payload[self._idx['diagnostic_certainty_classification']]),
591 instead = u'',
592 template_initial = u'%s, ',
593 none_equivalents = [None, u'']
594 ),
595 gmTools.bool2subst(self._payload[self._idx['episode_open']], _('active'), _('finished')),
596 self._payload[self._idx['pk_episode']]
597 ))
598
599 enc = cEncounter(aPK_obj = self._payload[self._idx['pk_encounter']])
600 lines.append (_('Created during encounter: %s (%s - %s) [#%s]\n') % (
601 enc['l10n_type'],
602 enc['started_original_tz'].strftime('%Y-%m-%d %H:%M'),
603 enc['last_affirmed_original_tz'].strftime('%H:%M'),
604 self._payload[self._idx['pk_encounter']]
605 ))
606
607 # encounters
608 emr = patient.get_emr()
609 encs = emr.get_encounters(episodes = [self._payload[self._idx['pk_episode']]])
610 first_encounter = None
611 last_encounter = None
612 if encs is None:
613 lines.append(_('Error retrieving encounters for this episode.'))
614 elif len(encs) == 0:
615 lines.append(_('There are no encounters for this episode.'))
616 else:
617 first_encounter = emr.get_first_encounter(episode_id = self._payload[self._idx['pk_episode']])
618 last_encounter = emr.get_last_encounter(episode_id = self._payload[self._idx['pk_episode']])
619
620 lines.append(_('Last worked on: %s\n') % last_encounter['last_affirmed_original_tz'].strftime('%Y-%m-%d %H:%M'))
621
622 lines.append(_('1st and (up to 3) most recent (of %s) encounters (%s - %s):') % (
623 len(encs),
624 first_encounter['started'].strftime('%m/%Y'),
625 last_encounter['last_affirmed'].strftime('%m/%Y')
626 ))
627
628 lines.append(u' %s - %s (%s):%s' % (
629 first_encounter['started_original_tz'].strftime('%Y-%m-%d %H:%M'),
630 first_encounter['last_affirmed_original_tz'].strftime('%H:%M'),
631 first_encounter['l10n_type'],
632 gmTools.coalesce (
633 first_encounter['assessment_of_encounter'],
634 gmTools.coalesce (
635 first_encounter['reason_for_encounter'],
636 u'',
637 u' \u00BB%s\u00AB' + (u' (%s)' % _('RFE'))
638 ),
639 u' \u00BB%s\u00AB' + (u' (%s)' % _('AOE'))
640 )
641 ))
642
643 if len(encs) > 4:
644 lines.append(_(' ... %s skipped ...') % (len(encs) - 4))
645
646 for enc in encs[1:][-3:]:
647 lines.append(u' %s - %s (%s):%s' % (
648 enc['started_original_tz'].strftime('%Y-%m-%d %H:%M'),
649 enc['last_affirmed_original_tz'].strftime('%H:%M'),
650 enc['l10n_type'],
651 gmTools.coalesce (
652 enc['assessment_of_encounter'],
653 gmTools.coalesce (
654 enc['reason_for_encounter'],
655 u'',
656 u' \u00BB%s\u00AB' + (u' (%s)' % _('RFE'))
657 ),
658 u' \u00BB%s\u00AB' + (u' (%s)' % _('AOE'))
659 )
660 ))
661 del encs
662
663 # spell out last encounter
664 if last_encounter is not None:
665 lines.append('')
666 lines.append(_('Progress notes in most recent encounter:'))
667 lines.extend(last_encounter.format_soap (
668 episodes = [ self._payload[self._idx['pk_episode']] ],
669 left_margin = left_margin,
670 soap_cats = 'soap',
671 emr = emr
672 ))
673
674 # documents
675 doc_folder = patient.get_document_folder()
676 docs = doc_folder.get_documents (
677 episodes = [ self._payload[self._idx['pk_episode']] ]
678 )
679
680 if len(docs) > 0:
681 lines.append('')
682 lines.append(_('Documents: %s') % len(docs))
683
684 for d in docs:
685 lines.append(u' %s %s:%s%s' % (
686 d['clin_when'].strftime('%Y-%m-%d'),
687 d['l10n_type'],
688 gmTools.coalesce(d['comment'], u'', u' "%s"'),
689 gmTools.coalesce(d['ext_ref'], u'', u' (%s)')
690 ))
691 del docs
692
693 # hospital stays
694 stays = emr.get_hospital_stays (
695 episodes = [ self._payload[self._idx['pk_episode']] ]
696 )
697
698 if len(stays) > 0:
699 lines.append('')
700 lines.append(_('Hospital stays: %s') % len(stays))
701
702 for s in stays:
703 lines.append(s.format(left_margin = (left_margin + 1)))
704 del stays
705
706 # procedures
707 procs = emr.get_performed_procedures (
708 episodes = [ self._payload[self._idx['pk_episode']] ]
709 )
710
711 if len(procs) > 0:
712 lines.append(u'')
713 lines.append(_('Procedures performed: %s') % len(procs))
714 for p in procs:
715 lines.append(p.format(left_margin = (left_margin + 1), include_episode = False))
716 del procs
717
718 # test results
719 tests = emr.get_test_results_by_date(episodes = [ self._payload[self._idx['pk_episode']] ])
720
721 if len(tests) > 0:
722 lines.append('')
723 lines.append(_('Measurements and Results:'))
724
725 for t in tests:
726 lines.extend(t.format (
727 with_review = False,
728 with_comments = False,
729 date_format = '%Y-%m-%d'
730 ))
731 del tests
732
733 # vaccinations
734 vaccs = emr.get_vaccinations(episodes = [ self._payload[self._idx['pk_episode']] ])
735
736 if len(vaccs) > 0:
737 lines.append(u'')
738 lines.append(_('Vaccinations:'))
739
740 for vacc in vaccs:
741 lines.extend(vacc.format (
742 with_indications = True,
743 with_comment = True,
744 with_reaction = True,
745 date_format = '%Y-%m-%d'
746 ))
747 del vaccs
748
749 left_margin = u' ' * left_margin
750 eol_w_margin = u'\n%s' % left_margin
751 return left_margin + eol_w_margin.join(lines) + u'\n'
752 #============================================================
753 -def create_episode(pk_health_issue=None, episode_name=None, is_open=False, allow_dupes=False, encounter=None):
754 """Creates a new episode for a given patient's health issue.
755
756 pk_health_issue - given health issue PK
757 episode_name - name of episode
758 """
759 if not allow_dupes:
760 try:
761 episode = cEpisode(name=episode_name, health_issue=pk_health_issue, encounter = encounter)
762 if episode['episode_open'] != is_open:
763 episode['episode_open'] = is_open
764 episode.save_payload()
765 return episode
766 except gmExceptions.ConstructorError:
767 pass
768
769 queries = []
770 cmd = u"insert into clin.episode (fk_health_issue, description, is_open, fk_encounter) values (%s, %s, %s::boolean, %s)"
771 queries.append({'cmd': cmd, 'args': [pk_health_issue, episode_name, is_open, encounter]})
772 queries.append({'cmd': cEpisode._cmd_fetch_payload % u"currval('clin.episode_pk_seq')"})
773 rows, idx = gmPG2.run_rw_queries(queries = queries, return_data=True, get_col_idx=True)
774
775 episode = cEpisode(row={'data': rows[0], 'idx': idx, 'pk_field': 'pk_episode'})
776 return episode
777 #-----------------------------------------------------------
779 if isinstance(episode, cEpisode):
780 pk = episode['pk_episode']
781 else:
782 pk = int(episode)
783
784 try:
785 gmPG2.run_rw_queries(queries = [{'cmd': u'delete from clin.episode where pk=%(pk)s', 'args': {'pk': pk}}])
786 except gmPG2.dbapi.IntegrityError:
787 # should be parsing pgcode/and or error message
788 _log.exception('cannot delete episode')
789 raise gmExceptions.DatabaseObjectInUseError('cannot delete episode, it is in use')
790 #-----------------------------------------------------------
792 return cProblem (
793 aPK_obj = {
794 'pk_patient': episode['pk_patient'],
795 'pk_episode': episode['pk_episode'],
796 'pk_health_issue': episode['pk_health_issue']
797 },
798 try_potential_problems = allow_closed
799 )
800 #============================================================
801 # encounter API
802 #============================================================
804 """Represents one encounter."""
805 _cmd_fetch_payload = u"select * from clin.v_pat_encounters where pk_encounter = %s"
806 _cmds_store_payload = [
807 u"""update clin.encounter set
808 started = %(started)s,
809 last_affirmed = %(last_affirmed)s,
810 fk_location = %(pk_location)s,
811 fk_type = %(pk_type)s,
812 reason_for_encounter = gm.nullify_empty_string(%(reason_for_encounter)s),
813 assessment_of_encounter = gm.nullify_empty_string(%(assessment_of_encounter)s)
814 where
815 pk = %(pk_encounter)s and
816 xmin = %(xmin_encounter)s""",
817 u"""select xmin_encounter from clin.v_pat_encounters where pk_encounter=%(pk_encounter)s"""
818 ]
819 _updatable_fields = [
820 'started',
821 'last_affirmed',
822 'pk_location',
823 'pk_type',
824 'reason_for_encounter',
825 'assessment_of_encounter'
826 ]
827 #--------------------------------------------------------
829 """Set the enconter as the active one.
830
831 "Setting active" means making sure the encounter
832 row has the youngest "last_affirmed" timestamp of
833 all encounter rows for this patient.
834 """
835 self['last_affirmed'] = gmDateTime.pydt_now_here()
836 self.save()
837 #--------------------------------------------------------
839 """
840 Moves every element currently linked to the current encounter
841 and the source_episode onto target_episode.
842
843 @param source_episode The episode the elements are currently linked to.
844 @type target_episode A cEpisode intance.
845 @param target_episode The episode the elements will be relinked to.
846 @type target_episode A cEpisode intance.
847 """
848 if source_episode['pk_episode'] == target_episode['pk_episode']:
849 return True
850
851 queries = []
852 cmd = u"""
853 UPDATE clin.clin_root_item
854 SET fk_episode = %(trg)s
855 WHERE
856 fk_encounter = %(enc)s AND
857 fk_episode = %(src)s
858 """
859 rows, idx = gmPG2.run_rw_queries(queries = [{
860 'cmd': cmd,
861 'args': {
862 'trg': target_episode['pk_episode'],
863 'enc': self.pk_obj,
864 'src': source_episode['pk_episode']
865 }
866 }])
867 self.refetch_payload()
868 return True
869 #--------------------------------------------------------
871
872 relevant_fields = [
873 'pk_location',
874 'pk_type',
875 'pk_patient',
876 'reason_for_encounter',
877 'assessment_of_encounter'
878 ]
879 for field in relevant_fields:
880 if self._payload[self._idx[field]] != another_object[field]:
881 _log.debug('mismatch on [%s]: "%s" vs. "%s"', field, self._payload[self._idx[field]], another_object[field])
882 return False
883
884 relevant_fields = [
885 'started',
886 'last_affirmed',
887 ]
888 for field in relevant_fields:
889 if self._payload[self._idx[field]] is None:
890 if another_object[field] is None:
891 continue
892 _log.debug('mismatch on [%s]: "%s" vs. "%s"', field, self._payload[self._idx[field]], another_object[field])
893 return False
894
895 if another_object[field] is None:
896 return False
897
898 #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'):
899 if self._payload[self._idx[field]].strftime('%Y-%m-%d %H:%M') != another_object[field].strftime('%Y-%m-%d %H:%M'):
900 _log.debug('mismatch on [%s]: "%s" vs. "%s"', field, self._payload[self._idx[field]], another_object[field])
901 return False
902
903 return True
904 #--------------------------------------------------------
906 cmd = u"""
907 select exists (
908 select 1 from clin.v_pat_items where pk_patient = %(pat)s and pk_encounter = %(enc)s
909 union all
910 select 1 from blobs.v_doc_med where pk_patient = %(pat)s and pk_encounter = %(enc)s
911 )"""
912 args = {
913 'pat': self._payload[self._idx['pk_patient']],
914 'enc': self.pk_obj
915 }
916 rows, idx = gmPG2.run_ro_queries (
917 queries = [{
918 'cmd': cmd,
919 'args': args
920 }]
921 )
922 return rows[0][0]
923 #--------------------------------------------------------
925 cmd = u"""
926 select exists (
927 select 1 from clin.v_pat_items where pk_patient=%(pat)s and pk_encounter=%(enc)s
928 )"""
929 args = {
930 'pat': self._payload[self._idx['pk_patient']],
931 'enc': self.pk_obj
932 }
933 rows, idx = gmPG2.run_ro_queries (
934 queries = [{
935 'cmd': cmd,
936 'args': args
937 }]
938 )
939 return rows[0][0]
940 #--------------------------------------------------------
942 cmd = u"""
943 select exists (
944 select 1 from blobs.v_doc_med where pk_patient = %(pat)s and pk_encounter = %(enc)s
945 )"""
946 args = {
947 'pat': self._payload[self._idx['pk_patient']],
948 'enc': self.pk_obj
949 }
950 rows, idx = gmPG2.run_ro_queries (
951 queries = [{
952 'cmd': cmd,
953 'args': args
954 }]
955 )
956 return rows[0][0]
957 #--------------------------------------------------------
959
960 if soap_cat is not None:
961 soap_cat = soap_cat.lower()
962
963 if episode is None:
964 epi_part = u'fk_episode is null'
965 else:
966 epi_part = u'fk_episode = %(epi)s'
967
968 cmd = u"""
969 select narrative
970 from clin.clin_narrative
971 where
972 fk_encounter = %%(enc)s
973 and
974 soap_cat = %%(cat)s
975 and
976 %s
977 order by clin_when desc
978 limit 1
979 """ % epi_part
980
981 args = {'enc': self.pk_obj, 'cat': soap_cat, 'epi': episode}
982
983 rows, idx = gmPG2.run_ro_queries (
984 queries = [{
985 'cmd': cmd,
986 'args': args
987 }]
988 )
989 if len(rows) == 0:
990 return None
991
992 return rows[0][0]
993 #--------------------------------------------------------
995
996 lines = []
997 for soap_cat in soap_cats:
998 soap_cat_narratives = emr.get_clin_narrative (
999 episodes = episodes,
1000 issues = issues,
1001 encounters = [self._payload[self._idx['pk_encounter']]],
1002 soap_cats = [soap_cat]
1003 )
1004 if soap_cat_narratives is None:
1005 continue
1006 if len(soap_cat_narratives) == 0:
1007 continue
1008
1009 lines.append(u'-- %s ----------' % gmClinNarrative.soap_cat2l10n_str[soap_cat])
1010 for soap_entry in soap_cat_narratives:
1011 txt = gmTools.wrap (
1012 text = u'%s\n (%.8s %s)' % (
1013 soap_entry['narrative'],
1014 soap_entry['provider'],
1015 soap_entry['date'].strftime('%Y-%m-%d %H:%M')
1016 ),
1017 width = 75,
1018 initial_indent = u'',
1019 subsequent_indent = (u' ' * left_margin)
1020 )
1021 lines.append(txt)
1022 lines.append('')
1023
1024 return lines
1025 #--------------------------------------------------------
1026 - 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):
1027
1028 lines = []
1029
1030 if fancy_header:
1031 lines.append(u'%s%s: %s - %s (@%s)%s [#%s]' % (
1032 u' ' * left_margin,
1033 self._payload[self._idx['l10n_type']],
1034 self._payload[self._idx['started_original_tz']].strftime('%Y-%m-%d %H:%M'),
1035 self._payload[self._idx['last_affirmed_original_tz']].strftime('%H:%M'),
1036 self._payload[self._idx['source_time_zone']],
1037 gmTools.coalesce(self._payload[self._idx['assessment_of_encounter']], u'', u' \u00BB%s\u00AB'),
1038 self._payload[self._idx['pk_encounter']]
1039 ))
1040
1041 lines.append(_(' your time: %s - %s (@%s = %s%s)\n') % (
1042 self._payload[self._idx['started']].strftime('%Y-%m-%d %H:%M'),
1043 self._payload[self._idx['last_affirmed']].strftime('%H:%M'),
1044 gmDateTime.current_local_iso_numeric_timezone_string,
1045 gmTools.bool2subst (
1046 gmDateTime.dst_currently_in_effect,
1047 gmDateTime.py_dst_timezone_name,
1048 gmDateTime.py_timezone_name
1049 ),
1050 gmTools.bool2subst(gmDateTime.dst_currently_in_effect, u' - ' + _('daylight savings time in effect'), u'')
1051 ))
1052
1053 lines.append(u'%s: %s' % (
1054 _('RFE'),
1055 gmTools.coalesce(self._payload[self._idx['reason_for_encounter']], u'')
1056 ))
1057 lines.append(u'%s: %s' % (
1058 _('AOE'),
1059 gmTools.coalesce(self._payload[self._idx['assessment_of_encounter']], u'')
1060 ))
1061
1062 else:
1063 lines.append(u'%s%s: %s - %s%s' % (
1064 u' ' * left_margin,
1065 self._payload[self._idx['l10n_type']],
1066 self._payload[self._idx['started_original_tz']].strftime('%Y-%m-%d %H:%M'),
1067 self._payload[self._idx['last_affirmed_original_tz']].strftime('%H:%M'),
1068 gmTools.coalesce(self._payload[self._idx['assessment_of_encounter']], u'', u' \u00BB%s\u00AB')
1069 ))
1070
1071 if with_soap:
1072 lines.append(u'')
1073
1074 if patient.ID != self._payload[self._idx['pk_patient']]:
1075 msg = '<patient>.ID = %s but encounter %s belongs to patient %s' % (
1076 patient.ID,
1077 self._payload[self._idx['pk_encounter']],
1078 self._payload[self._idx['pk_patient']]
1079 )
1080 raise ValueError(msg)
1081
1082 emr = patient.get_emr()
1083
1084 lines.extend(self.format_soap (
1085 episodes = episodes,
1086 left_margin = left_margin,
1087 soap_cats = 'soap',
1088 emr = emr,
1089 issues = issues
1090 ))
1091
1092 # test results
1093 if with_tests:
1094 tests = emr.get_test_results_by_date (
1095 episodes = episodes,
1096 encounter = self._payload[self._idx['pk_encounter']]
1097 )
1098 if len(tests) > 0:
1099 lines.append('')
1100 lines.append(_('Measurements and Results:'))
1101
1102 for t in tests:
1103 lines.extend(t.format())
1104
1105 del tests
1106
1107 # vaccinations
1108 if with_vaccinations:
1109 vaccs = emr.get_vaccinations (
1110 episodes = episodes,
1111 encounters = [ self._payload[self._idx['pk_encounter']] ]
1112 )
1113
1114 if len(vaccs) > 0:
1115 lines.append(u'')
1116 lines.append(_('Vaccinations:'))
1117
1118 for vacc in vaccs:
1119 lines.extend(vacc.format (
1120 with_indications = True,
1121 with_comment = True,
1122 with_reaction = True,
1123 date_format = '%Y-%m-%d'
1124 ))
1125 del vaccs
1126
1127 # documents
1128 if with_docs:
1129 doc_folder = patient.get_document_folder()
1130 docs = doc_folder.get_documents (
1131 episodes = episodes,
1132 encounter = self._payload[self._idx['pk_encounter']]
1133 )
1134
1135 if len(docs) > 0:
1136 lines.append('')
1137 lines.append(_('Documents:'))
1138
1139 for d in docs:
1140 lines.append(u' %s %s:%s%s' % (
1141 d['clin_when'].strftime('%Y-%m-%d'),
1142 d['l10n_type'],
1143 gmTools.coalesce(d['comment'], u'', u' "%s"'),
1144 gmTools.coalesce(d['ext_ref'], u'', u' (%s)')
1145 ))
1146
1147 del docs
1148
1149 eol_w_margin = u'\n%s' % (u' ' * left_margin)
1150 return u'%s\n' % eol_w_margin.join(lines)
1151 #-----------------------------------------------------------
1153 """Creates a new encounter for a patient.
1154
1155 fk_patient - patient PK
1156 fk_location - encounter location
1157 enc_type - type of encounter
1158
1159 FIXME: we don't deal with location yet
1160 """
1161 if enc_type is None:
1162 enc_type = u'in surgery'
1163 # insert new encounter
1164 queries = []
1165 try:
1166 enc_type = int(enc_type)
1167 cmd = u"""
1168 insert into clin.encounter (
1169 fk_patient, fk_location, fk_type
1170 ) values (
1171 %s, -1, %s
1172 )"""
1173 except ValueError:
1174 enc_type = enc_type
1175 cmd = u"""
1176 insert into clin.encounter (
1177 fk_patient, fk_location, fk_type
1178 ) values (
1179 %s, -1, coalesce((select pk from clin.encounter_type where description=%s), 0)
1180 )"""
1181 queries.append({'cmd': cmd, 'args': [fk_patient, enc_type]})
1182 queries.append({'cmd': cEncounter._cmd_fetch_payload % u"currval('clin.encounter_pk_seq')"})
1183 rows, idx = gmPG2.run_rw_queries(queries=queries, return_data=True, get_col_idx=True)
1184 encounter = cEncounter(row={'data': rows[0], 'idx': idx, 'pk_field': 'pk_encounter'})
1185
1186 return encounter
1187 #-----------------------------------------------------------
1189
1190 rows, idx = gmPG2.run_rw_queries(
1191 queries = [{
1192 'cmd': u"select i18n.upd_tx(%(desc)s, %(l10n_desc)s)",
1193 'args': {'desc': description, 'l10n_desc': l10n_description}
1194 }],
1195 return_data = True
1196 )
1197
1198 success = rows[0][0]
1199 if not success:
1200 _log.warning('updating encounter type [%s] to [%s] failed', description, l10n_description)
1201
1202 return {'description': description, 'l10n_description': l10n_description}
1203 #-----------------------------------------------------------
1205 """This will attempt to create a NEW encounter type."""
1206
1207 # need a system name, so derive one if necessary
1208 if description is None:
1209 description = l10n_description
1210
1211 args = {
1212 'desc': description,
1213 'l10n_desc': l10n_description
1214 }
1215
1216 _log.debug('creating encounter type: %s, %s', description, l10n_description)
1217
1218 # does it exist already ?
1219 cmd = u"select description, _(description) from clin.encounter_type where description = %(desc)s"
1220 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}])
1221
1222 # yes
1223 if len(rows) > 0:
1224 # both system and l10n name are the same so all is well
1225 if (rows[0][0] == description) and (rows[0][1] == l10n_description):
1226 _log.info('encounter type [%s] already exists with the proper translation')
1227 return {'description': description, 'l10n_description': l10n_description}
1228
1229 # or maybe there just wasn't a translation to
1230 # the current language for this type yet ?
1231 cmd = u"select exists (select 1 from i18n.translations where orig = %(desc)s and lang = i18n.get_curr_lang())"
1232 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}])
1233
1234 # there was, so fail
1235 if rows[0][0]:
1236 _log.error('encounter type [%s] already exists but with another translation')
1237 return None
1238
1239 # else set it
1240 cmd = u"select i18n.upd_tx(%(desc)s, %(l10n_desc)s)"
1241 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
1242 return {'description': description, 'l10n_description': l10n_description}
1243
1244 # no
1245 queries = [
1246 {'cmd': u"insert into clin.encounter_type (description) values (%(desc)s)", 'args': args},
1247 {'cmd': u"select i18n.upd_tx(%(desc)s, %(l10n_desc)s)", 'args': args}
1248 ]
1249 rows, idx = gmPG2.run_rw_queries(queries = queries)
1250
1251 return {'description': description, 'l10n_description': l10n_description}
1252 #-----------------------------------------------------------
1254 cmd = u"select _(description) as l10n_description, description from clin.encounter_type"
1255 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}])
1256 return rows
1257 #-----------------------------------------------------------
1259 cmd = u"SELECT * from clin.encounter_type where description = %s"
1260 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': [description]}])
1261 return rows
1262 #-----------------------------------------------------------
1264 cmd = u"delete from clin.encounter_type where description = %(desc)s"
1265 args = {'desc': description}
1266 try:
1267 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
1268 except gmPG2.dbapi.IntegrityError, e:
1269 if e.pgcode == gmPG2.sql_error_codes.FOREIGN_KEY_VIOLATION:
1270 return False
1271 raise
1272
1273 return True
1274 #============================================================
1276 """Represents one problem.
1277
1278 problems are the aggregation of
1279 .clinically_relevant=True issues and
1280 .is_open=True episodes
1281 """
1282 _cmd_fetch_payload = u'' # will get programmatically defined in __init__
1283 _cmds_store_payload = [u"select 1"]
1284 _updatable_fields = []
1285
1286 #--------------------------------------------------------
1288 """Initialize.
1289
1290 aPK_obj must contain the keys
1291 pk_patient
1292 pk_episode
1293 pk_health_issue
1294 """
1295 if aPK_obj is None:
1296 raise gmExceptions.ConstructorError, 'cannot instatiate cProblem for PK: [%s]' % (aPK_obj)
1297
1298 # As problems are rows from a view of different emr struct items,
1299 # the PK can't be a single field and, as some of the values of the
1300 # composed PK may be None, they must be queried using 'is null',
1301 # so we must programmatically construct the SQL query
1302 where_parts = []
1303 pk = {}
1304 for col_name in aPK_obj.keys():
1305 val = aPK_obj[col_name]
1306 if val is None:
1307 where_parts.append('%s IS NULL' % col_name)
1308 else:
1309 where_parts.append('%s = %%(%s)s' % (col_name, col_name))
1310 pk[col_name] = val
1311
1312 # try to instantiate from true problem view
1313 cProblem._cmd_fetch_payload = u"""
1314 SELECT *, False as is_potential_problem
1315 FROM clin.v_problem_list
1316 WHERE %s""" % u' AND '.join(where_parts)
1317
1318 try:
1319 gmBusinessDBObject.cBusinessDBObject.__init__(self, aPK_obj=pk)
1320 return
1321 except gmExceptions.ConstructorError:
1322 _log.exception('problem not found, trying potential problems')
1323 if try_potential_problems is False:
1324 raise
1325
1326 # try to instantiate from non-problem view
1327 cProblem._cmd_fetch_payload = u"""
1328 SELECT *, True as is_potential_problem
1329 FROM clin.v_potential_problem_list
1330 WHERE %s""" % u' AND '.join(where_parts)
1331 gmBusinessDBObject.cBusinessDBObject.__init__(self, aPK_obj=pk)
1332 #--------------------------------------------------------
1334 """
1335 Retrieve the cEpisode instance equivalent to this problem.
1336 The problem's type attribute must be 'episode'
1337 """
1338 if self._payload[self._idx['type']] != 'episode':
1339 _log.error('cannot convert problem [%s] of type [%s] to episode' % (self._payload[self._idx['problem']], self._payload[self._idx['type']]))
1340 return None
1341 return cEpisode(aPK_obj=self._payload[self._idx['pk_episode']])
1342 #--------------------------------------------------------
1343 # doubles as 'diagnostic_certainty_description' getter:
1345 return diagnostic_certainty_classification2str(self._payload[self._idx['diagnostic_certainty_classification']])
1346
1347 diagnostic_certainty_description = property(get_diagnostic_certainty_description, lambda x:x)
1348 #============================================================
1350
1351 _cmd_fetch_payload = u"select * from clin.v_pat_hospital_stays where pk_hospital_stay = %s"
1352 _cmds_store_payload = [
1353 u"""update clin.hospital_stay set
1354 clin_when = %(admission)s,
1355 discharge = %(discharge)s,
1356 narrative = gm.nullify_empty_string(%(hospital)s),
1357 fk_episode = %(pk_episode)s,
1358 fk_encounter = %(pk_encounter)s
1359 where
1360 pk = %(pk_hospital_stay)s and
1361 xmin = %(xmin_hospital_stay)s""",
1362 u"""select xmin_hospital_stay from clin.v_pat_hospital_stays where pk_hospital_stay = %(pk_hospital_stay)s"""
1363 ]
1364 _updatable_fields = [
1365 'admission',
1366 'discharge',
1367 'hospital',
1368 'pk_episode',
1369 'pk_encounter'
1370 ]
1371 #-------------------------------------------------------
1373
1374 if self._payload[self._idx['discharge']] is not None:
1375 dis = u' - %s' % self._payload[self._idx['discharge']].strftime('%Y %b %d').decode(gmI18N.get_encoding())
1376 else:
1377 dis = u''
1378
1379 line = u'%s%s%s%s: %s%s%s' % (
1380 u' ' * left_margin,
1381 self._payload[self._idx['admission']].strftime('%Y %b %d').decode(gmI18N.get_encoding()),
1382 dis,
1383 gmTools.coalesce(self._payload[self._idx['hospital']], u'', u' (%s)'),
1384 gmTools.u_left_double_angle_quote,
1385 self._payload[self._idx['episode']],
1386 gmTools.u_right_double_angle_quote
1387 )
1388
1389 return line
1390 #-----------------------------------------------------------
1392
1393 queries = [
1394 {
1395 'cmd': u'select * from clin.v_pat_hospital_stays where pk_patient = %(pat)s order by admission',
1396 'args': {'pat': patient}
1397 }
1398 ]
1399
1400 rows, idx = gmPG2.run_ro_queries(queries = queries, get_col_idx = True)
1401
1402 return [ cHospitalStay(row = {'idx': idx, 'data': r, 'pk_field': 'pk_hospital_stay'}) for r in rows ]
1403 #-----------------------------------------------------------
1405
1406 queries = [
1407 {
1408 'cmd': u'insert into clin.hospital_stay (fk_encounter, fk_episode) values (%(enc)s, %(epi)s)',
1409 'args': {'enc': encounter, 'epi': episode}
1410 },
1411 {'cmd': u"select currval('clin.hospital_stay_pk_seq')"}
1412 ]
1413
1414 rows, idx = gmPG2.run_rw_queries(queries = queries, return_data = True)
1415
1416 return cHospitalStay(aPK_obj = rows[0][0])
1417 #-----------------------------------------------------------
1419 cmd = u'delete from clin.hospital_stay where pk = %(pk)s'
1420 args = {'pk': stay}
1421 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
1422 return True
1423 #============================================================
1425
1426 _cmd_fetch_payload = u"select * from clin.v_pat_procedures where pk_procedure = %s"
1427 _cmds_store_payload = [
1428 u"""update clin.procedure set
1429 clin_when = %(clin_when)s,
1430 clin_where = gm.nullify_empty_string(%(clin_where)s),
1431 narrative = gm.nullify_empty_string(%(performed_procedure)s),
1432 fk_hospital_stay = %(pk_hospital_stay)s,
1433 fk_episode = %(pk_episode)s,
1434 fk_encounter = %(pk_encounter)s
1435 where
1436 pk = %(pk_procedure)s and
1437 xmin = %(xmin_procedure)s
1438 """,
1439 u"""select xmin_procedure from clin.v_pat_procedures where pk_procedure = %(pk_procedure)s"""
1440 ]
1441 _updatable_fields = [
1442 'clin_when',
1443 'clin_where',
1444 'performed_procedure',
1445 'pk_hospital_stay',
1446 'pk_episode',
1447 'pk_encounter'
1448 ]
1449 #-------------------------------------------------------
1451
1452 if (attribute == 'pk_hospital_stay') and (value is not None):
1453 gmBusinessDBObject.cBusinessDBObject.__setitem__(self, 'clin_where', None)
1454
1455 if (attribute == 'clin_where') and (value is not None) and (value.strip() != u''):
1456 gmBusinessDBObject.cBusinessDBObject.__setitem__(self, 'pk_hospital_stay', None)
1457
1458 gmBusinessDBObject.cBusinessDBObject.__setitem__(self, attribute, value)
1459 #-------------------------------------------------------
1461
1462 line = u'%s%s (%s): %s' % (
1463 (u' ' * left_margin),
1464 self._payload[self._idx['clin_when']].strftime('%Y %b %d').decode(gmI18N.get_encoding()),
1465 self._payload[self._idx['clin_where']],
1466 self._payload[self._idx['performed_procedure']]
1467 )
1468 if include_episode:
1469 line = u'%s (%s)' % (line, self._payload[self._idx['episode']])
1470
1471 return line
1472 #-----------------------------------------------------------
1474
1475 queries = [
1476 {
1477 'cmd': u'select * from clin.v_pat_procedures where pk_patient = %(pat)s order by clin_when',
1478 'args': {'pat': patient}
1479 }
1480 ]
1481
1482 rows, idx = gmPG2.run_ro_queries(queries = queries, get_col_idx = True)
1483
1484 return [ cPerformedProcedure(row = {'idx': idx, 'data': r, 'pk_field': 'pk_procedure'}) for r in rows ]
1485 #-----------------------------------------------------------
1486 -def create_performed_procedure(encounter=None, episode=None, location=None, hospital_stay=None, procedure=None):
1487
1488 queries = [{
1489 'cmd': u"""
1490 insert into clin.procedure (
1491 fk_encounter,
1492 fk_episode,
1493 clin_where,
1494 fk_hospital_stay,
1495 narrative
1496 ) values (
1497 %(enc)s,
1498 %(epi)s,
1499 gm.nullify_empty_string(%(loc)s),
1500 %(stay)s,
1501 %(proc)s
1502 )
1503 returning pk""",
1504 'args': {'enc': encounter, 'epi': episode, 'loc': location, 'stay': hospital_stay, 'proc': procedure}
1505 }]
1506
1507 rows, idx = gmPG2.run_rw_queries(queries = queries, return_data = True)
1508
1509 return cPerformedProcedure(aPK_obj = rows[0][0])
1510 #-----------------------------------------------------------
1512 cmd = u'delete from clin.procedure where pk = %(pk)s'
1513 args = {'pk': procedure}
1514 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
1515 return True
1516 #============================================================
1517 # main - unit testing
1518 #------------------------------------------------------------
1519 if __name__ == '__main__':
1520
1521 if len(sys.argv) < 2:
1522 sys.exit()
1523
1524 if sys.argv[1] != 'test':
1525 sys.exit()
1526
1527 #--------------------------------------------------------
1528 # define tests
1529 #--------------------------------------------------------
1531 print "\nProblem test"
1532 print "------------"
1533 prob = cProblem(aPK_obj={'pk_patient': 12, 'pk_health_issue': 1, 'pk_episode': None})
1534 print prob
1535 fields = prob.get_fields()
1536 for field in fields:
1537 print field, ':', prob[field]
1538 print '\nupdatable:', prob.get_updatable_fields()
1539 epi = prob.get_as_episode()
1540 print '\nas episode:'
1541 if epi is not None:
1542 for field in epi.get_fields():
1543 print ' .%s : %s' % (field, epi[field])
1544 #--------------------------------------------------------
1546 print "\nhealth issue test"
1547 print "-----------------"
1548 h_issue = cHealthIssue(aPK_obj=2)
1549 print h_issue
1550 fields = h_issue.get_fields()
1551 for field in fields:
1552 print field, ':', h_issue[field]
1553 print "has open episode:", h_issue.has_open_episode()
1554 print "open episode:", h_issue.get_open_episode()
1555 print "updateable:", h_issue.get_updatable_fields()
1556 h_issue.close_expired_episode(ttl=7300)
1557 h_issue = cHealthIssue(encounter = 1, name = u'post appendectomy/peritonitis')
1558 print h_issue
1559 #--------------------------------------------------------
1561 print "\nepisode test"
1562 print "------------"
1563 episode = cEpisode(aPK_obj=1)
1564 print episode
1565 fields = episode.get_fields()
1566 for field in fields:
1567 print field, ':', episode[field]
1568 print "updatable:", episode.get_updatable_fields()
1569 raw_input('ENTER to continue')
1570
1571 old_description = episode['description']
1572 old_enc = cEncounter(aPK_obj = 1)
1573
1574 desc = '1-%s' % episode['description']
1575 print "==> renaming to", desc
1576 successful = episode.rename (
1577 description = desc
1578 )
1579 if not successful:
1580 print "error"
1581 else:
1582 print "success"
1583 for field in fields:
1584 print field, ':', episode[field]
1585
1586 print "episode range:", episode.get_access_range()
1587
1588 raw_input('ENTER to continue')
1589
1590 #--------------------------------------------------------
1592 print "\nencounter test"
1593 print "--------------"
1594 encounter = cEncounter(aPK_obj=1)
1595 print encounter
1596 fields = encounter.get_fields()
1597 for field in fields:
1598 print field, ':', encounter[field]
1599 print "updatable:", encounter.get_updatable_fields()
1600 #--------------------------------------------------------
1602 procs = get_performed_procedures(patient = 12)
1603 for proc in procs:
1604 print proc.format(left_margin=2)
1605 #--------------------------------------------------------
1607 stay = create_hospital_stay(encounter = 1, episode = 2)
1608 stay['hospital'] = u'Starfleet Galaxy General Hospital'
1609 stay.save_payload()
1610 print stay
1611 for s in get_patient_hospital_stays(12):
1612 print s
1613 delete_hospital_stay(stay['pk_hospital_stay'])
1614 stay = create_hospital_stay(encounter = 1, episode = 4)
1615 #--------------------------------------------------------
1617 tests = [None, 'A', 'B', 'C', 'D', 'E']
1618
1619 for t in tests:
1620 print type(t), t
1621 print type(diagnostic_certainty_classification2str(t)), diagnostic_certainty_classification2str(t)
1622
1623 #--------------------------------------------------------
1624 # run them
1625 #test_episode()
1626 #test_problem()
1627 #test_encounter()
1628 #test_health_issue()
1629 #test_hospital_stay()
1630 #test_performed_procedure()
1631 test_diagnostic_certainty_classification_map()
1632 #============================================================
1633
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Mon Jun 28 04:11:59 2010 | http://epydoc.sourceforge.net |