| Home | Trees | Indices | Help |
|
|---|
|
|
1 # -*- coding: utf8 -*-
2 """GNUmed health related business object.
3
4 license: GPL v2 or later
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 from Gnumed.business import gmCoding
25
26
27 _log = logging.getLogger('gm.emr')
28 _log.info(__version__)
29
30 try: _
31 except NameError: _ = lambda x:x
32 #============================================================
33 # diagnostic certainty classification
34 #============================================================
35 __diagnostic_certainty_classification_map = None
36
38
39 global __diagnostic_certainty_classification_map
40
41 if __diagnostic_certainty_classification_map is None:
42 __diagnostic_certainty_classification_map = {
43 None: u'',
44 u'A': _(u'A: Sign'),
45 u'B': _(u'B: Cluster of signs'),
46 u'C': _(u'C: Syndromic diagnosis'),
47 u'D': _(u'D: Scientific diagnosis')
48 }
49
50 try:
51 return __diagnostic_certainty_classification_map[classification]
52 except KeyError:
53 return _(u'<%s>: unknown diagnostic certainty classification') % classification
54 #============================================================
55 # Health Issues API
56 #============================================================
57 laterality2str = {
58 None: u'?',
59 u'na': u'',
60 u'sd': _('bilateral'),
61 u'ds': _('bilateral'),
62 u's': _('left'),
63 u'd': _('right')
64 }
65
66 #============================================================
68 """Represents one health issue."""
69
70 _cmd_fetch_payload = u"select *, xmin_health_issue from clin.v_health_issues where pk_health_issue=%s"
71 _cmds_store_payload = [
72 u"""update clin.health_issue set
73 description = %(description)s,
74 summary = gm.nullify_empty_string(%(summary)s),
75 age_noted = %(age_noted)s,
76 laterality = gm.nullify_empty_string(%(laterality)s),
77 grouping = gm.nullify_empty_string(%(grouping)s),
78 diagnostic_certainty_classification = gm.nullify_empty_string(%(diagnostic_certainty_classification)s),
79 is_active = %(is_active)s,
80 clinically_relevant = %(clinically_relevant)s,
81 is_confidential = %(is_confidential)s,
82 is_cause_of_death = %(is_cause_of_death)s
83 where
84 pk = %(pk_health_issue)s and
85 xmin = %(xmin_health_issue)s""",
86 u"select xmin as xmin_health_issue from clin.health_issue where pk = %(pk_health_issue)s"
87 ]
88 _updatable_fields = [
89 'description',
90 'summary',
91 'grouping',
92 'age_noted',
93 'laterality',
94 'is_active',
95 'clinically_relevant',
96 'is_confidential',
97 'is_cause_of_death',
98 'diagnostic_certainty_classification'
99 ]
100 #--------------------------------------------------------
101 - def __init__(self, aPK_obj=None, encounter=None, name='xxxDEFAULTxxx', patient=None, row=None):
102 pk = aPK_obj
103
104 if (pk is not None) or (row is not None):
105 gmBusinessDBObject.cBusinessDBObject.__init__(self, aPK_obj=pk, row=row)
106 return
107
108 if patient is None:
109 cmd = u"""select *, xmin_health_issue from clin.v_health_issues
110 where
111 description = %(desc)s
112 and
113 pk_patient = (select fk_patient from clin.encounter where pk = %(enc)s)"""
114 else:
115 cmd = u"""select *, xmin_health_issue from clin.v_health_issues
116 where
117 description = %(desc)s
118 and
119 pk_patient = %(pat)s"""
120
121 queries = [{'cmd': cmd, 'args': {'enc': encounter, 'desc': name, 'pat': patient}}]
122 rows, idx = gmPG2.run_ro_queries(queries = queries, get_col_idx = True)
123
124 if len(rows) == 0:
125 raise gmExceptions.NoSuchBusinessObjectError, 'no health issue for [enc:%s::desc:%s::pat:%s]' % (encounter, name, patient)
126
127 pk = rows[0][0]
128 r = {'idx': idx, 'data': rows[0], 'pk_field': 'pk_health_issue'}
129
130 gmBusinessDBObject.cBusinessDBObject.__init__(self, row=r)
131 #--------------------------------------------------------
132 # external API
133 #--------------------------------------------------------
135 """Method for issue renaming.
136
137 @param description
138 - the new descriptive name for the issue
139 @type description
140 - a string instance
141 """
142 # sanity check
143 if not type(description) in [str, unicode] or description.strip() == '':
144 _log.error('<description> must be a non-empty string')
145 return False
146 # update the issue description
147 old_description = self._payload[self._idx['description']]
148 self._payload[self._idx['description']] = description.strip()
149 self._is_modified = True
150 successful, data = self.save_payload()
151 if not successful:
152 _log.error('cannot rename health issue [%s] with [%s]' % (self, description))
153 self._payload[self._idx['description']] = old_description
154 return False
155 return True
156 #--------------------------------------------------------
158 cmd = u"SELECT * FROM clin.v_pat_episodes WHERE pk_health_issue = %(pk)s"
159 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': {'pk': self.pk_obj}}], get_col_idx = True)
160 return [ cEpisode(row = {'data': r, 'idx': idx, 'pk_field': 'pk_episode'}) for r in rows ]
161 #--------------------------------------------------------
163 """ttl in days"""
164 open_episode = self.get_open_episode()
165 if open_episode is None:
166 return True
167 earliest, latest = open_episode.get_access_range()
168 ttl = datetime.timedelta(ttl)
169 now = datetime.datetime.now(tz=latest.tzinfo)
170 if (latest + ttl) > now:
171 return False
172 open_episode['episode_open'] = False
173 success, data = open_episode.save_payload()
174 if success:
175 return True
176 return False # should be an exception
177 #--------------------------------------------------------
179 open_episode = self.get_open_episode()
180 open_episode['episode_open'] = False
181 success, data = open_episode.save_payload()
182 if success:
183 return True
184 return False
185 #--------------------------------------------------------
187 cmd = u"select exists (select 1 from clin.episode where fk_health_issue = %s and is_open is True)"
188 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': [self.pk_obj]}])
189 return rows[0][0]
190 #--------------------------------------------------------
192 cmd = u"select pk from clin.episode where fk_health_issue = %s and is_open is True"
193 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': [self.pk_obj]}])
194 if len(rows) == 0:
195 return None
196 return cEpisode(aPK_obj=rows[0][0])
197 #--------------------------------------------------------
199 if self._payload[self._idx['age_noted']] is None:
200 return u'<???>'
201
202 # since we've already got an interval we are bound to use it,
203 # further transformation will only introduce more errors,
204 # later we can improve this deeper inside
205 return gmDateTime.format_interval_medically(self._payload[self._idx['age_noted']])
206 #--------------------------------------------------------
208 """<pk_code> must be a value from ref.coding_system_root.pk_coding_system (clin.lnk_code2item_root.fk_generic_code)"""
209 cmd = u"INSERT INTO clin.lnk_code2h_issue (fk_item, fk_generic_code) values (%(item)s, %(code)s)"
210 args = {
211 'item': self._payload[self._idx['pk_health_issue']],
212 'code': pk_code
213 }
214 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
215 return True
216 #--------------------------------------------------------
218 """<pk_code> must be a value from ref.coding_system_root.pk_coding_system (clin.lnk_code2item_root.fk_generic_code)"""
219 cmd = u"DELETE FROM clin.lnk_code2h_issue WHERE fk_item = %(item)s AND fk_generic_code = %(code)s"
220 args = {
221 'item': self._payload[self._idx['pk_health_issue']],
222 'code': pk_code
223 }
224 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
225 return True
226 #--------------------------------------------------------
228 rows = gmClinNarrative.get_as_journal (
229 issues = (self.pk_obj,),
230 order_by = u'pk_episode, pk_encounter, clin_when, scr, src_table'
231 )
232
233 if len(rows) == 0:
234 return u''
235
236 left_margin = u' ' * left_margin
237
238 lines = []
239 lines.append(_('Clinical data generated during encounters under this health issue:'))
240
241 prev_epi = None
242 for row in rows:
243 if row['pk_episode'] != prev_epi:
244 lines.append(u'')
245 prev_epi = row['pk_episode']
246
247 when = row['clin_when'].strftime(date_format).decode(gmI18N.get_encoding())
248 top_row = u'%s%s %s (%s) %s' % (
249 gmTools.u_box_top_left_arc,
250 gmTools.u_box_horiz_single,
251 gmClinNarrative.soap_cat2l10n_str[row['real_soap_cat']],
252 when,
253 gmTools.u_box_horiz_single * 5
254 )
255 soap = gmTools.wrap (
256 text = row['narrative'],
257 width = 60,
258 initial_indent = u' ',
259 subsequent_indent = u' ' + left_margin
260 )
261 row_ver = u''
262 if row['row_version'] > 0:
263 row_ver = u'v%s: ' % row['row_version']
264 bottom_row = u'%s%s %s, %s%s %s' % (
265 u' ' * 40,
266 gmTools.u_box_horiz_light_heavy,
267 row['modified_by'],
268 row_ver,
269 row['date_modified'],
270 gmTools.u_box_horiz_heavy_light
271 )
272
273 lines.append(top_row)
274 lines.append(soap)
275 lines.append(bottom_row)
276
277 eol_w_margin = u'\n%s' % left_margin
278 return left_margin + eol_w_margin.join(lines) + u'\n'
279 #--------------------------------------------------------
281
282 if patient.ID != self._payload[self._idx['pk_patient']]:
283 msg = '<patient>.ID = %s but health issue %s belongs to patient %s' % (
284 patient.ID,
285 self._payload[self._idx['pk_health_issue']],
286 self._payload[self._idx['pk_patient']]
287 )
288 raise ValueError(msg)
289
290 lines = []
291
292 lines.append(_('Health Issue %s%s%s%s [#%s]') % (
293 u'\u00BB',
294 self._payload[self._idx['description']],
295 u'\u00AB',
296 gmTools.coalesce (
297 initial = self.laterality_description,
298 instead = u'',
299 template_initial = u' (%s)',
300 none_equivalents = [None, u'', u'?']
301 ),
302 self._payload[self._idx['pk_health_issue']]
303 ))
304
305 if self._payload[self._idx['is_confidential']]:
306 lines.append('')
307 lines.append(_(' ***** CONFIDENTIAL *****'))
308 lines.append('')
309
310 if self._payload[self._idx['is_cause_of_death']]:
311 lines.append('')
312 lines.append(_(' contributed to death of patient'))
313 lines.append('')
314
315 enc = cEncounter(aPK_obj = self._payload[self._idx['pk_encounter']])
316 lines.append (_(' Created during encounter: %s (%s - %s) [#%s]') % (
317 enc['l10n_type'],
318 enc['started_original_tz'].strftime('%Y-%m-%d %H:%M'),
319 enc['last_affirmed_original_tz'].strftime('%H:%M'),
320 self._payload[self._idx['pk_encounter']]
321 ))
322
323 if self._payload[self._idx['age_noted']] is not None:
324 lines.append(_(' Noted at age: %s') % self.age_noted_human_readable())
325
326 lines.append(u' ' + _('Status') + u': %s, %s%s' % (
327 gmTools.bool2subst(self._payload[self._idx['is_active']], _('active'), _('inactive')),
328 gmTools.bool2subst(self._payload[self._idx['clinically_relevant']], _('clinically relevant'), _('not clinically relevant')),
329 gmTools.coalesce (
330 initial = diagnostic_certainty_classification2str(self._payload[self._idx['diagnostic_certainty_classification']]),
331 instead = u'',
332 template_initial = u', %s',
333 none_equivalents = [None, u'']
334 )
335 ))
336
337 if self._payload[self._idx['summary']] is not None:
338 lines.append(u'')
339 lines.append(gmTools.wrap (
340 text = self._payload[self._idx['summary']],
341 width = 60,
342 initial_indent = u' ',
343 subsequent_indent = u' '
344 ))
345
346 # codes
347 codes = self.generic_codes
348 if len(codes) > 0:
349 lines.append(u'')
350 for c in codes:
351 lines.append(u' %s: %s (%s - %s)' % (
352 c['code'],
353 c['term'],
354 c['name_short'],
355 c['version']
356 ))
357 del codes
358
359 lines.append(u'')
360
361 emr = patient.get_emr()
362
363 # episodes
364 epis = emr.get_episodes(issues = [self._payload[self._idx['pk_health_issue']]])
365 if epis is None:
366 lines.append(_('Error retrieving episodes for this health issue.'))
367 elif len(epis) == 0:
368 lines.append(_('There are no episodes for this health issue.'))
369 else:
370 lines.append (
371 _('Episodes: %s (most recent: %s%s%s)') % (
372 len(epis),
373 gmTools.u_left_double_angle_quote,
374 emr.get_most_recent_episode(issue = self._payload[self._idx['pk_health_issue']])['description'],
375 gmTools.u_right_double_angle_quote
376 )
377 )
378 for epi in epis:
379 lines.append(u' \u00BB%s\u00AB (%s)' % (
380 epi['description'],
381 gmTools.bool2subst(epi['episode_open'], _('ongoing'), _('closed'))
382 ))
383
384 lines.append('')
385
386 # encounters
387 first_encounter = emr.get_first_encounter(issue_id = self._payload[self._idx['pk_health_issue']])
388 last_encounter = emr.get_last_encounter(issue_id = self._payload[self._idx['pk_health_issue']])
389
390 if first_encounter is None or last_encounter is None:
391 lines.append(_('No encounters found for this health issue.'))
392 else:
393 encs = emr.get_encounters(issues = [self._payload[self._idx['pk_health_issue']]])
394 lines.append(_('Encounters: %s (%s - %s):') % (
395 len(encs),
396 first_encounter['started_original_tz'].strftime('%m/%Y'),
397 last_encounter['last_affirmed_original_tz'].strftime('%m/%Y')
398 ))
399 lines.append(_(' Most recent: %s - %s') % (
400 last_encounter['started_original_tz'].strftime('%Y-%m-%d %H:%M'),
401 last_encounter['last_affirmed_original_tz'].strftime('%H:%M')
402 ))
403
404 # medications
405 meds = emr.get_current_substance_intake (
406 issues = [ self._payload[self._idx['pk_health_issue']] ],
407 order_by = u'is_currently_active, started, substance'
408 )
409
410 if len(meds) > 0:
411 lines.append(u'')
412 lines.append(_('Active medications: %s') % len(meds))
413 for m in meds:
414 lines.append(m.format(left_margin = (left_margin + 1)))
415 del meds
416
417 # hospital stays
418 stays = emr.get_hospital_stays (
419 issues = [ self._payload[self._idx['pk_health_issue']] ]
420 )
421 if len(stays) > 0:
422 lines.append(u'')
423 lines.append(_('Hospital stays: %s') % len(stays))
424 for s in stays:
425 lines.append(s.format(left_margin = (left_margin + 1)))
426 del stays
427
428 # procedures
429 procs = emr.get_performed_procedures (
430 issues = [ self._payload[self._idx['pk_health_issue']] ]
431 )
432 if len(procs) > 0:
433 lines.append(u'')
434 lines.append(_('Procedures performed: %s') % len(procs))
435 for p in procs:
436 lines.append(p.format(left_margin = (left_margin + 1)))
437 del procs
438
439 # family history
440 fhx = emr.get_family_history(issues = [ self._payload[self._idx['pk_health_issue']] ])
441 if len(fhx) > 0:
442 lines.append(u'')
443 lines.append(_('Family History: %s') % len(fhx))
444 for f in fhx:
445 lines.append(f.format (
446 left_margin = (left_margin + 1),
447 include_episode = True,
448 include_comment = True,
449 include_codes = False
450 ))
451 del fhx
452
453 epis = self.get_episodes()
454 if len(epis) > 0:
455 epi_pks = [ e['pk_episode'] for e in epis ]
456
457 # documents
458 doc_folder = patient.get_document_folder()
459 docs = doc_folder.get_documents(episodes = epi_pks)
460 if len(docs) > 0:
461 lines.append(u'')
462 lines.append(_('Documents: %s') % len(docs))
463 del docs
464
465 # test results
466 tests = emr.get_test_results_by_date(episodes = epi_pks)
467 if len(tests) > 0:
468 lines.append(u'')
469 lines.append(_('Measurements and Results: %s') % len(tests))
470 del tests
471
472 # vaccinations
473 vaccs = emr.get_vaccinations(episodes = epi_pks)
474 if len(vaccs) > 0:
475 lines.append(u'')
476 lines.append(_('Vaccinations:'))
477 for vacc in vaccs:
478 lines.extend(vacc.format(with_reaction = True))
479 del vaccs
480
481 del epis
482
483 left_margin = u' ' * left_margin
484 eol_w_margin = u'\n%s' % left_margin
485 return left_margin + eol_w_margin.join(lines) + u'\n'
486 #--------------------------------------------------------
487 # properties
488 #--------------------------------------------------------
489 episodes = property(get_episodes, lambda x:x)
490 #--------------------------------------------------------
491 open_episode = property(get_open_episode, lambda x:x)
492 #--------------------------------------------------------
494 cmd = u"""SELECT
495 coalesce (
496 (SELECT pk FROM clin.episode WHERE fk_health_issue = %(issue)s AND is_open IS TRUE),
497 (SELECT pk FROM clin.v_pat_episodes WHERE fk_health_issue = %(issue)s ORDER BY last_affirmed DESC limit 1)
498 )"""
499 args = {'issue': self.pk_obj}
500 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
501 if len(rows) == 0:
502 return None
503 return cEpisode(aPK_obj = rows[0][0])
504
505 latest_episode = property(_get_latest_episode, lambda x:x)
506 #--------------------------------------------------------
508 try:
509 return laterality2str[self._payload[self._idx['laterality']]]
510 except KeyError:
511 return u'<???>'
512
513 laterality_description = property(_get_laterality_description, lambda x:x)
514 #--------------------------------------------------------
516 return diagnostic_certainty_classification2str(self._payload[self._idx['diagnostic_certainty_classification']])
517
518 diagnostic_certainty_description = property(_get_diagnostic_certainty_description, lambda x:x)
519 #--------------------------------------------------------
521 if len(self._payload[self._idx['pk_generic_codes']]) == 0:
522 return []
523
524 cmd = gmCoding._SQL_get_generic_linked_codes % u'pk_generic_code IN %(pks)s'
525 args = {'pks': tuple(self._payload[self._idx['pk_generic_codes']])}
526 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
527 return [ gmCoding.cGenericLinkedCode(row = {'data': r, 'idx': idx, 'pk_field': 'pk_lnk_code2item'}) for r in rows ]
528
530 queries = []
531 # remove all codes
532 if len(self._payload[self._idx['pk_generic_codes']]) > 0:
533 queries.append ({
534 'cmd': u'DELETE FROM clin.lnk_code2h_issue WHERE fk_item = %(issue)s AND fk_generic_code IN %(codes)s',
535 'args': {
536 'issue': self._payload[self._idx['pk_health_issue']],
537 'codes': tuple(self._payload[self._idx['pk_generic_codes']])
538 }
539 })
540 # add new codes
541 for pk_code in pk_codes:
542 queries.append ({
543 'cmd': u'INSERT INTO clin.lnk_code2h_issue (fk_item, fk_generic_code) VALUES (%(issue)s, %(pk_code)s)',
544 'args': {
545 'issue': self._payload[self._idx['pk_health_issue']],
546 'pk_code': pk_code
547 }
548 })
549 if len(queries) == 0:
550 return
551 # run it all in one transaction
552 rows, idx = gmPG2.run_rw_queries(queries = queries)
553 return
554
555 generic_codes = property(_get_generic_codes, _set_generic_codes)
556 #============================================================
558 """Creates a new health issue for a given patient.
559
560 description - health issue name
561 """
562 try:
563 h_issue = cHealthIssue(name = description, encounter = encounter, patient = patient)
564 return h_issue
565 except gmExceptions.NoSuchBusinessObjectError:
566 pass
567
568 queries = []
569 cmd = u"insert into clin.health_issue (description, fk_encounter) values (%(desc)s, %(enc)s)"
570 queries.append({'cmd': cmd, 'args': {'desc': description, 'enc': encounter}})
571
572 cmd = u"select currval('clin.health_issue_pk_seq')"
573 queries.append({'cmd': cmd})
574
575 rows, idx = gmPG2.run_rw_queries(queries = queries, return_data = True)
576 h_issue = cHealthIssue(aPK_obj = rows[0][0])
577
578 return h_issue
579 #-----------------------------------------------------------
581 if isinstance(health_issue, cHealthIssue):
582 pk = health_issue['pk_health_issue']
583 else:
584 pk = int(health_issue)
585
586 try:
587 gmPG2.run_rw_queries(queries = [{'cmd': u'delete from clin.health_issue where pk=%(pk)s', 'args': {'pk': pk}}])
588 except gmPG2.dbapi.IntegrityError:
589 # should be parsing pgcode/and or error message
590 _log.exception('cannot delete health issue')
591 raise gmExceptions.DatabaseObjectInUseError('cannot delete health issue, it is in use')
592 #------------------------------------------------------------
593 # use as dummy for unassociated episodes
595 issue = {
596 'pk_health_issue': None,
597 'description': _('Unattributed episodes'),
598 'age_noted': None,
599 'laterality': u'na',
600 'is_active': True,
601 'clinically_relevant': True,
602 'is_confidential': None,
603 'is_cause_of_death': False,
604 'is_dummy': True,
605 'grouping': None
606 }
607 return issue
608 #-----------------------------------------------------------
610 return cProblem (
611 aPK_obj = {
612 'pk_patient': health_issue['pk_patient'],
613 'pk_health_issue': health_issue['pk_health_issue'],
614 'pk_episode': None
615 },
616 try_potential_problems = allow_irrelevant
617 )
618 #============================================================
619 # episodes API
620 #============================================================
622 """Represents one clinical episode.
623 """
624 _cmd_fetch_payload = u"select * from clin.v_pat_episodes where pk_episode=%s"
625 _cmds_store_payload = [
626 u"""update clin.episode set
627 fk_health_issue = %(pk_health_issue)s,
628 is_open = %(episode_open)s::boolean,
629 description = %(description)s,
630 summary = gm.nullify_empty_string(%(summary)s),
631 diagnostic_certainty_classification = gm.nullify_empty_string(%(diagnostic_certainty_classification)s)
632 where
633 pk = %(pk_episode)s and
634 xmin = %(xmin_episode)s""",
635 u"""select xmin_episode from clin.v_pat_episodes where pk_episode = %(pk_episode)s"""
636 ]
637 _updatable_fields = [
638 'pk_health_issue',
639 'episode_open',
640 'description',
641 'summary',
642 'diagnostic_certainty_classification'
643 ]
644 #--------------------------------------------------------
645 - def __init__(self, aPK_obj=None, id_patient=None, name='xxxDEFAULTxxx', health_issue=None, row=None, encounter=None):
646 pk = aPK_obj
647 if pk is None and row is None:
648
649 where_parts = [u'description = %(desc)s']
650
651 if id_patient is not None:
652 where_parts.append(u'pk_patient = %(pat)s')
653
654 if health_issue is not None:
655 where_parts.append(u'pk_health_issue = %(issue)s')
656
657 if encounter is not None:
658 where_parts.append(u'pk_patient = (select fk_patient from clin.encounter where pk = %(enc)s)')
659
660 args = {
661 'pat': id_patient,
662 'issue': health_issue,
663 'enc': encounter,
664 'desc': name
665 }
666
667 cmd = u"select * from clin.v_pat_episodes where %s" % u' and '.join(where_parts)
668
669 rows, idx = gmPG2.run_ro_queries(
670 queries = [{'cmd': cmd, 'args': args}],
671 get_col_idx=True
672 )
673
674 if len(rows) == 0:
675 raise gmExceptions.NoSuchBusinessObjectError, 'no episode for [%s:%s:%s:%s]' % (id_patient, name, health_issue, encounter)
676
677 r = {'idx': idx, 'data': rows[0], 'pk_field': 'pk_episode'}
678 gmBusinessDBObject.cBusinessDBObject.__init__(self, row=r)
679
680 else:
681 gmBusinessDBObject.cBusinessDBObject.__init__(self, aPK_obj=pk, row=row)
682 #--------------------------------------------------------
683 # external API
684 #--------------------------------------------------------
686 """Get earliest and latest access to this episode.
687
688 Returns a tuple(earliest, latest).
689 """
690 cmd = u"""
691 select
692 min(earliest),
693 max(latest)
694 from (
695 (select
696 (case when clin_when < modified_when
697 then clin_when
698 else modified_when
699 end) as earliest,
700 (case when clin_when > modified_when
701 then clin_when
702 else modified_when
703 end) as latest
704 from
705 clin.clin_root_item
706 where
707 fk_episode = %(pk)s
708
709 ) union all (
710
711 select
712 modified_when as earliest,
713 modified_when as latest
714 from
715 clin.episode
716 where
717 pk = %(pk)s
718 )
719 ) as ranges"""
720 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': {'pk': self.pk_obj}}])
721 if len(rows) == 0:
722 return (gmNull.cNull(warn=False), gmNull.cNull(warn=False))
723 return (rows[0][0], rows[0][1])
724 #--------------------------------------------------------
727 #--------------------------------------------------------
729 return gmClinNarrative.get_narrative (
730 soap_cats = soap_cats,
731 encounters = encounters,
732 episodes = [self.pk_obj],
733 order_by = order_by
734 )
735 #--------------------------------------------------------
737 """Method for episode editing, that is, episode renaming.
738
739 @param description
740 - the new descriptive name for the encounter
741 @type description
742 - a string instance
743 """
744 # sanity check
745 if description.strip() == '':
746 _log.error('<description> must be a non-empty string instance')
747 return False
748 # update the episode description
749 old_description = self._payload[self._idx['description']]
750 self._payload[self._idx['description']] = description.strip()
751 self._is_modified = True
752 successful, data = self.save_payload()
753 if not successful:
754 _log.error('cannot rename episode [%s] to [%s]' % (self, description))
755 self._payload[self._idx['description']] = old_description
756 return False
757 return True
758 #--------------------------------------------------------
760 """<pk_code> must be a value from ref.coding_system_root.pk_coding_system (clin.lnk_code2item_root.fk_generic_code)"""
761
762 if pk_code in self._payload[self._idx['pk_generic_codes']]:
763 return
764
765 cmd = u"""
766 INSERT INTO clin.lnk_code2episode
767 (fk_item, fk_generic_code)
768 SELECT
769 %(item)s,
770 %(code)s
771 WHERE NOT EXISTS (
772 SELECT 1 FROM clin.lnk_code2episode
773 WHERE
774 fk_item = %(item)s
775 AND
776 fk_generic_code = %(code)s
777 )"""
778 args = {
779 'item': self._payload[self._idx['pk_episode']],
780 'code': pk_code
781 }
782 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
783 return
784 #--------------------------------------------------------
786 """<pk_code> must be a value from ref.coding_system_root.pk_coding_system (clin.lnk_code2item_root.fk_generic_code)"""
787 cmd = u"DELETE FROM clin.lnk_code2episode WHERE fk_item = %(item)s AND fk_generic_code = %(code)s"
788 args = {
789 'item': self._payload[self._idx['pk_episode']],
790 'code': pk_code
791 }
792 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
793 return True
794 #--------------------------------------------------------
796 rows = gmClinNarrative.get_as_journal (
797 episodes = (self.pk_obj,),
798 order_by = u'pk_encounter, clin_when, scr, src_table'
799 #order_by = u'pk_encounter, scr, clin_when, src_table'
800 )
801
802 if len(rows) == 0:
803 return u''
804
805 lines = []
806
807 lines.append(_('Clinical data generated during encounters within this episode:'))
808
809 left_margin = u' ' * left_margin
810
811 prev_enc = None
812 for row in rows:
813 if row['pk_encounter'] != prev_enc:
814 lines.append(u'')
815 prev_enc = row['pk_encounter']
816
817 when = row['clin_when'].strftime(date_format).decode(gmI18N.get_encoding())
818 top_row = u'%s%s %s (%s) %s' % (
819 gmTools.u_box_top_left_arc,
820 gmTools.u_box_horiz_single,
821 gmClinNarrative.soap_cat2l10n_str[row['real_soap_cat']],
822 when,
823 gmTools.u_box_horiz_single * 5
824 )
825 soap = gmTools.wrap (
826 text = row['narrative'],
827 width = 60,
828 initial_indent = u' ',
829 subsequent_indent = u' ' + left_margin
830 )
831 row_ver = u''
832 if row['row_version'] > 0:
833 row_ver = u'v%s: ' % row['row_version']
834 bottom_row = u'%s%s %s, %s%s %s' % (
835 u' ' * 40,
836 gmTools.u_box_horiz_light_heavy,
837 row['modified_by'],
838 row_ver,
839 row['date_modified'],
840 gmTools.u_box_horiz_heavy_light
841 )
842
843 lines.append(top_row)
844 lines.append(soap)
845 lines.append(bottom_row)
846
847 eol_w_margin = u'\n%s' % left_margin
848 return left_margin + eol_w_margin.join(lines) + u'\n'
849 #--------------------------------------------------------
851
852 if patient.ID != self._payload[self._idx['pk_patient']]:
853 msg = '<patient>.ID = %s but episode %s belongs to patient %s' % (
854 patient.ID,
855 self._payload[self._idx['pk_episode']],
856 self._payload[self._idx['pk_patient']]
857 )
858 raise ValueError(msg)
859
860 lines = []
861
862 # episode details
863 lines.append (_('Episode %s%s%s [#%s]') % (
864 gmTools.u_left_double_angle_quote,
865 self._payload[self._idx['description']],
866 gmTools.u_right_double_angle_quote,
867 self._payload[self._idx['pk_episode']]
868 ))
869
870 enc = cEncounter(aPK_obj = self._payload[self._idx['pk_encounter']])
871 lines.append (u' ' + _('Created during encounter: %s (%s - %s) [#%s]') % (
872 enc['l10n_type'],
873 enc['started_original_tz'].strftime('%Y-%m-%d %H:%M'),
874 enc['last_affirmed_original_tz'].strftime('%H:%M'),
875 self._payload[self._idx['pk_encounter']]
876 ))
877
878 emr = patient.get_emr()
879 encs = emr.get_encounters(episodes = [self._payload[self._idx['pk_episode']]])
880 first_encounter = None
881 last_encounter = None
882 if (encs is not None) and (len(encs) > 0):
883 first_encounter = emr.get_first_encounter(episode_id = self._payload[self._idx['pk_episode']])
884 last_encounter = emr.get_last_encounter(episode_id = self._payload[self._idx['pk_episode']])
885 if self._payload[self._idx['episode_open']]:
886 end = gmDateTime.pydt_now_here()
887 end_str = gmTools.u_ellipsis
888 else:
889 end = last_encounter['last_affirmed']
890 end_str = last_encounter['last_affirmed'].strftime('%m/%Y')
891 age = gmDateTime.format_interval_medically(end - first_encounter['started'])
892 lines.append(_(' Duration: %s (%s - %s)') % (
893 age,
894 first_encounter['started'].strftime('%m/%Y'),
895 end_str
896 ))
897
898 lines.append(u' ' + _('Status') + u': %s%s' % (
899 gmTools.bool2subst(self._payload[self._idx['episode_open']], _('active'), _('finished')),
900 gmTools.coalesce (
901 initial = diagnostic_certainty_classification2str(self._payload[self._idx['diagnostic_certainty_classification']]),
902 instead = u'',
903 template_initial = u', %s',
904 none_equivalents = [None, u'']
905 )
906 ))
907
908 if self._payload[self._idx['summary']] is not None:
909 lines.append(u'')
910 lines.append(gmTools.wrap (
911 text = self._payload[self._idx['summary']],
912 width = 60,
913 initial_indent = u' ',
914 subsequent_indent = u' '
915 )
916 )
917
918 # codes
919 codes = self.generic_codes
920 if len(codes) > 0:
921 lines.append(u'')
922 for c in codes:
923 lines.append(u' %s: %s (%s - %s)' % (
924 c['code'],
925 c['term'],
926 c['name_short'],
927 c['version']
928 ))
929 del codes
930
931 lines.append(u'')
932
933 # encounters
934 if encs is None:
935 lines.append(_('Error retrieving encounters for this episode.'))
936 elif len(encs) == 0:
937 #lines.append(_('There are no encounters for this episode.'))
938 pass
939 else:
940 lines.append(_('Last worked on: %s\n') % last_encounter['last_affirmed_original_tz'].strftime('%Y-%m-%d %H:%M'))
941
942 if len(encs) < 4:
943 line = _('%s encounter(s) (%s - %s):')
944 else:
945 line = _('1st and (up to 3) most recent (of %s) encounters (%s - %s):')
946 lines.append(line % (
947 len(encs),
948 first_encounter['started'].strftime('%m/%Y'),
949 last_encounter['last_affirmed'].strftime('%m/%Y')
950 ))
951
952 lines.append(u' %s - %s (%s):%s' % (
953 first_encounter['started_original_tz'].strftime('%Y-%m-%d %H:%M'),
954 first_encounter['last_affirmed_original_tz'].strftime('%H:%M'),
955 first_encounter['l10n_type'],
956 gmTools.coalesce (
957 first_encounter['assessment_of_encounter'],
958 gmTools.coalesce (
959 first_encounter['reason_for_encounter'],
960 u'',
961 u' \u00BB%s\u00AB' + (u' (%s)' % _('RFE'))
962 ),
963 u' \u00BB%s\u00AB' + (u' (%s)' % _('AOE'))
964 )
965 ))
966
967 if len(encs) > 4:
968 lines.append(_(' ... %s skipped ...') % (len(encs) - 4))
969
970 for enc in encs[1:][-3:]:
971 lines.append(u' %s - %s (%s):%s' % (
972 enc['started_original_tz'].strftime('%Y-%m-%d %H:%M'),
973 enc['last_affirmed_original_tz'].strftime('%H:%M'),
974 enc['l10n_type'],
975 gmTools.coalesce (
976 enc['assessment_of_encounter'],
977 gmTools.coalesce (
978 enc['reason_for_encounter'],
979 u'',
980 u' \u00BB%s\u00AB' + (u' (%s)' % _('RFE'))
981 ),
982 u' \u00BB%s\u00AB' + (u' (%s)' % _('AOE'))
983 )
984 ))
985 del encs
986
987 # spell out last encounter
988 if last_encounter is not None:
989 lines.append('')
990 lines.append(_('Progress notes in most recent encounter:'))
991 lines.extend(last_encounter.format_soap (
992 episodes = [ self._payload[self._idx['pk_episode']] ],
993 left_margin = left_margin,
994 soap_cats = 'soap',
995 emr = emr
996 ))
997
998 # documents
999 doc_folder = patient.get_document_folder()
1000 docs = doc_folder.get_documents (
1001 episodes = [ self._payload[self._idx['pk_episode']] ]
1002 )
1003
1004 if len(docs) > 0:
1005 lines.append('')
1006 lines.append(_('Documents: %s') % len(docs))
1007
1008 for d in docs:
1009 lines.append(u' %s %s:%s%s' % (
1010 d['clin_when'].strftime('%Y-%m-%d'),
1011 d['l10n_type'],
1012 gmTools.coalesce(d['comment'], u'', u' "%s"'),
1013 gmTools.coalesce(d['ext_ref'], u'', u' (%s)')
1014 ))
1015 del docs
1016
1017 # hospital stays
1018 stays = emr.get_hospital_stays(episodes = [ self._payload[self._idx['pk_episode']] ])
1019 if len(stays) > 0:
1020 lines.append('')
1021 lines.append(_('Hospital stays: %s') % len(stays))
1022 for s in stays:
1023 lines.append(s.format(left_margin = (left_margin + 1)))
1024 del stays
1025
1026 # procedures
1027 procs = emr.get_performed_procedures(episodes = [ self._payload[self._idx['pk_episode']] ])
1028 if len(procs) > 0:
1029 lines.append(u'')
1030 lines.append(_('Procedures performed: %s') % len(procs))
1031 for p in procs:
1032 lines.append(p.format (
1033 left_margin = (left_margin + 1),
1034 include_episode = False,
1035 include_codes = True
1036 ))
1037 del procs
1038
1039 # family history
1040 fhx = emr.get_family_history(episodes = [ self._payload[self._idx['pk_episode']] ])
1041 if len(fhx) > 0:
1042 lines.append(u'')
1043 lines.append(_('Family History: %s') % len(fhx))
1044 for f in fhx:
1045 lines.append(f.format (
1046 left_margin = (left_margin + 1),
1047 include_episode = False,
1048 include_comment = True,
1049 include_codes = True
1050 ))
1051 del fhx
1052
1053 # test results
1054 tests = emr.get_test_results_by_date(episodes = [ self._payload[self._idx['pk_episode']] ])
1055
1056 if len(tests) > 0:
1057 lines.append('')
1058 lines.append(_('Measurements and Results:'))
1059
1060 for t in tests:
1061 lines.extend(t.format (
1062 with_review = False,
1063 with_comments = False,
1064 date_format = '%Y-%m-%d'
1065 ))
1066 del tests
1067
1068 # vaccinations
1069 vaccs = emr.get_vaccinations (
1070 episodes = [ self._payload[self._idx['pk_episode']] ],
1071 order_by = u'date_given DESC, vaccine'
1072 )
1073
1074 if len(vaccs) > 0:
1075 lines.append(u'')
1076 lines.append(_('Vaccinations:'))
1077
1078 for vacc in vaccs:
1079 lines.extend(vacc.format (
1080 with_indications = True,
1081 with_comment = True,
1082 with_reaction = True,
1083 date_format = '%Y-%m-%d'
1084 ))
1085 del vaccs
1086
1087 left_margin = u' ' * left_margin
1088 eol_w_margin = u'\n%s' % left_margin
1089 return left_margin + eol_w_margin.join(lines) + u'\n'
1090 #--------------------------------------------------------
1091 # properties
1092 #--------------------------------------------------------
1094 return diagnostic_certainty_classification2str(self._payload[self._idx['diagnostic_certainty_classification']])
1095
1096 diagnostic_certainty_description = property(_get_diagnostic_certainty_description, lambda x:x)
1097 #--------------------------------------------------------
1099 if len(self._payload[self._idx['pk_generic_codes']]) == 0:
1100 return []
1101
1102 cmd = gmCoding._SQL_get_generic_linked_codes % u'pk_generic_code IN %(pks)s'
1103 args = {'pks': tuple(self._payload[self._idx['pk_generic_codes']])}
1104 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
1105 return [ gmCoding.cGenericLinkedCode(row = {'data': r, 'idx': idx, 'pk_field': 'pk_lnk_code2item'}) for r in rows ]
1106
1108 queries = []
1109 # remove all codes
1110 if len(self._payload[self._idx['pk_generic_codes']]) > 0:
1111 queries.append ({
1112 'cmd': u'DELETE FROM clin.lnk_code2episode WHERE fk_item = %(epi)s AND fk_generic_code IN %(codes)s',
1113 'args': {
1114 'epi': self._payload[self._idx['pk_episode']],
1115 'codes': tuple(self._payload[self._idx['pk_generic_codes']])
1116 }
1117 })
1118 # add new codes
1119 for pk_code in pk_codes:
1120 queries.append ({
1121 'cmd': u'INSERT INTO clin.lnk_code2episode (fk_item, fk_generic_code) VALUES (%(epi)s, %(pk_code)s)',
1122 'args': {
1123 'epi': self._payload[self._idx['pk_episode']],
1124 'pk_code': pk_code
1125 }
1126 })
1127 if len(queries) == 0:
1128 return
1129 # run it all in one transaction
1130 rows, idx = gmPG2.run_rw_queries(queries = queries)
1131 return
1132
1133 generic_codes = property(_get_generic_codes, _set_generic_codes)
1134 #--------------------------------------------------------
1136 cmd = u"""SELECT EXISTS (
1137 SELECT 1 FROM clin.clin_narrative
1138 WHERE
1139 fk_episode = %(epi)s
1140 AND
1141 fk_encounter IN (
1142 SELECT pk FROM clin.encounter WHERE fk_patient = %(pat)s
1143 )
1144 )"""
1145 args = {
1146 u'pat': self._payload[self._idx['pk_patient']],
1147 u'epi': self._payload[self._idx['pk_episode']]
1148 }
1149 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
1150 return rows[0][0]
1151
1152 has_narrative = property(_get_has_narrative, lambda x:x)
1153 #============================================================
1154 -def create_episode(pk_health_issue=None, episode_name=None, is_open=False, allow_dupes=False, encounter=None):
1155 """Creates a new episode for a given patient's health issue.
1156
1157 pk_health_issue - given health issue PK
1158 episode_name - name of episode
1159 """
1160 if not allow_dupes:
1161 try:
1162 episode = cEpisode(name=episode_name, health_issue=pk_health_issue, encounter = encounter)
1163 if episode['episode_open'] != is_open:
1164 episode['episode_open'] = is_open
1165 episode.save_payload()
1166 return episode
1167 except gmExceptions.ConstructorError:
1168 pass
1169
1170 queries = []
1171 cmd = u"insert into clin.episode (fk_health_issue, description, is_open, fk_encounter) values (%s, %s, %s::boolean, %s)"
1172 queries.append({'cmd': cmd, 'args': [pk_health_issue, episode_name, is_open, encounter]})
1173 queries.append({'cmd': cEpisode._cmd_fetch_payload % u"currval('clin.episode_pk_seq')"})
1174 rows, idx = gmPG2.run_rw_queries(queries = queries, return_data=True, get_col_idx=True)
1175
1176 episode = cEpisode(row={'data': rows[0], 'idx': idx, 'pk_field': 'pk_episode'})
1177 return episode
1178 #-----------------------------------------------------------
1180 if isinstance(episode, cEpisode):
1181 pk = episode['pk_episode']
1182 else:
1183 pk = int(episode)
1184
1185 try:
1186 gmPG2.run_rw_queries(queries = [{'cmd': u'delete from clin.episode where pk=%(pk)s', 'args': {'pk': pk}}])
1187 except gmPG2.dbapi.IntegrityError:
1188 # should be parsing pgcode/and or error message
1189 _log.exception('cannot delete episode')
1190 raise gmExceptions.DatabaseObjectInUseError('cannot delete episode, it is in use')
1191 #-----------------------------------------------------------
1193 return cProblem (
1194 aPK_obj = {
1195 'pk_patient': episode['pk_patient'],
1196 'pk_episode': episode['pk_episode'],
1197 'pk_health_issue': episode['pk_health_issue']
1198 },
1199 try_potential_problems = allow_closed
1200 )
1201 #============================================================
1202 # encounter API
1203 #============================================================
1205 """Represents one encounter."""
1206
1207 _cmd_fetch_payload = u"select * from clin.v_pat_encounters where pk_encounter = %s"
1208 _cmds_store_payload = [
1209 u"""UPDATE clin.encounter SET
1210 started = %(started)s,
1211 last_affirmed = %(last_affirmed)s,
1212 fk_location = %(pk_location)s,
1213 fk_type = %(pk_type)s,
1214 reason_for_encounter = gm.nullify_empty_string(%(reason_for_encounter)s),
1215 assessment_of_encounter = gm.nullify_empty_string(%(assessment_of_encounter)s)
1216 WHERE
1217 pk = %(pk_encounter)s AND
1218 xmin = %(xmin_encounter)s
1219 """,
1220 # need to return all fields so we can survive in-place upgrades
1221 u"""select * from clin.v_pat_encounters where pk_encounter = %(pk_encounter)s"""
1222 ]
1223 _updatable_fields = [
1224 'started',
1225 'last_affirmed',
1226 'pk_location',
1227 'pk_type',
1228 'reason_for_encounter',
1229 'assessment_of_encounter'
1230 ]
1231 #--------------------------------------------------------
1233 """Set the encounter as the active one.
1234
1235 "Setting active" means making sure the encounter
1236 row has the youngest "last_affirmed" timestamp of
1237 all encounter rows for this patient.
1238 """
1239 self['last_affirmed'] = gmDateTime.pydt_now_here()
1240 self.save()
1241 #--------------------------------------------------------
1243 """
1244 Moves every element currently linked to the current encounter
1245 and the source_episode onto target_episode.
1246
1247 @param source_episode The episode the elements are currently linked to.
1248 @type target_episode A cEpisode intance.
1249 @param target_episode The episode the elements will be relinked to.
1250 @type target_episode A cEpisode intance.
1251 """
1252 if source_episode['pk_episode'] == target_episode['pk_episode']:
1253 return True
1254
1255 queries = []
1256 cmd = u"""
1257 UPDATE clin.clin_root_item
1258 SET fk_episode = %(trg)s
1259 WHERE
1260 fk_encounter = %(enc)s AND
1261 fk_episode = %(src)s
1262 """
1263 rows, idx = gmPG2.run_rw_queries(queries = [{
1264 'cmd': cmd,
1265 'args': {
1266 'trg': target_episode['pk_episode'],
1267 'enc': self.pk_obj,
1268 'src': source_episode['pk_episode']
1269 }
1270 }])
1271 self.refetch_payload()
1272 return True
1273 #--------------------------------------------------------
1275
1276 relevant_fields = [
1277 'pk_location',
1278 'pk_type',
1279 'pk_patient',
1280 'reason_for_encounter',
1281 'assessment_of_encounter'
1282 ]
1283 for field in relevant_fields:
1284 if self._payload[self._idx[field]] != another_object[field]:
1285 _log.debug('mismatch on [%s]: "%s" vs. "%s"', field, self._payload[self._idx[field]], another_object[field])
1286 return False
1287
1288 relevant_fields = [
1289 'started',
1290 'last_affirmed',
1291 ]
1292 for field in relevant_fields:
1293 if self._payload[self._idx[field]] is None:
1294 if another_object[field] is None:
1295 continue
1296 _log.debug('mismatch on [%s]: "%s" vs. "%s"', field, self._payload[self._idx[field]], another_object[field])
1297 return False
1298
1299 if another_object[field] is None:
1300 return False
1301
1302 # compares at minute granularity
1303 if self._payload[self._idx[field]].strftime('%Y-%m-%d %H:%M') != another_object[field].strftime('%Y-%m-%d %H:%M'):
1304 _log.debug('mismatch on [%s]: "%s" vs. "%s"', field, self._payload[self._idx[field]], another_object[field])
1305 return False
1306
1307 # compare codes
1308 # 1) RFE
1309 if another_object['pk_generic_codes_rfe'] is None:
1310 if self._payload[self._idx['pk_generic_codes_rfe']] is not None:
1311 return False
1312 if another_object['pk_generic_codes_rfe'] is not None:
1313 if self._payload[self._idx['pk_generic_codes_rfe']] is None:
1314 return False
1315 if (
1316 (another_object['pk_generic_codes_rfe'] is None)
1317 and
1318 (self._payload[self._idx['pk_generic_codes_rfe']] is None)
1319 ) is False:
1320 if set(another_object['pk_generic_codes_rfe']) != set(self._payload[self._idx['pk_generic_codes_rfe']]):
1321 return False
1322 # 2) AOE
1323 if another_object['pk_generic_codes_aoe'] is None:
1324 if self._payload[self._idx['pk_generic_codes_aoe']] is not None:
1325 return False
1326 if another_object['pk_generic_codes_aoe'] is not None:
1327 if self._payload[self._idx['pk_generic_codes_aoe']] is None:
1328 return False
1329 if (
1330 (another_object['pk_generic_codes_aoe'] is None)
1331 and
1332 (self._payload[self._idx['pk_generic_codes_aoe']] is None)
1333 ) is False:
1334 if set(another_object['pk_generic_codes_aoe']) != set(self._payload[self._idx['pk_generic_codes_aoe']]):
1335 return False
1336
1337 return True
1338 #--------------------------------------------------------
1340 cmd = u"""
1341 select exists (
1342 select 1 from clin.v_pat_items where pk_patient = %(pat)s and pk_encounter = %(enc)s
1343 union all
1344 select 1 from blobs.v_doc_med where pk_patient = %(pat)s and pk_encounter = %(enc)s
1345 )"""
1346 args = {
1347 'pat': self._payload[self._idx['pk_patient']],
1348 'enc': self.pk_obj
1349 }
1350 rows, idx = gmPG2.run_ro_queries (
1351 queries = [{
1352 'cmd': cmd,
1353 'args': args
1354 }]
1355 )
1356 return rows[0][0]
1357 #--------------------------------------------------------
1359 cmd = u"""
1360 select exists (
1361 select 1 from clin.v_pat_items where pk_patient=%(pat)s and pk_encounter=%(enc)s
1362 )"""
1363 args = {
1364 'pat': self._payload[self._idx['pk_patient']],
1365 'enc': self.pk_obj
1366 }
1367 rows, idx = gmPG2.run_ro_queries (
1368 queries = [{
1369 'cmd': cmd,
1370 'args': args
1371 }]
1372 )
1373 return rows[0][0]
1374 #--------------------------------------------------------
1376 """soap_cats: <space> = admin category"""
1377
1378 if soap_cats is None:
1379 soap_cats = u'soap '
1380 else:
1381 soap_cats = soap_cats.lower()
1382
1383 cats = []
1384 for cat in soap_cats:
1385 if cat in u'soap':
1386 cats.append(cat)
1387 continue
1388 if cat == u' ':
1389 cats.append(None)
1390
1391 cmd = u"""
1392 SELECT EXISTS (
1393 SELECT 1 FROM clin.clin_narrative
1394 WHERE
1395 fk_encounter = %(enc)s
1396 AND
1397 soap_cat IN %(cats)s
1398 LIMIT 1
1399 )
1400 """
1401 args = {'enc': self._payload[self._idx['pk_encounter']], 'cats': tuple(cats)}
1402 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd,'args': args}])
1403 return rows[0][0]
1404 #--------------------------------------------------------
1406 cmd = u"""
1407 select exists (
1408 select 1 from blobs.v_doc_med where pk_patient = %(pat)s and pk_encounter = %(enc)s
1409 )"""
1410 args = {
1411 'pat': self._payload[self._idx['pk_patient']],
1412 'enc': self.pk_obj
1413 }
1414 rows, idx = gmPG2.run_ro_queries (
1415 queries = [{
1416 'cmd': cmd,
1417 'args': args
1418 }]
1419 )
1420 return rows[0][0]
1421 #--------------------------------------------------------
1423
1424 if soap_cat is not None:
1425 soap_cat = soap_cat.lower()
1426
1427 if episode is None:
1428 epi_part = u'fk_episode is null'
1429 else:
1430 epi_part = u'fk_episode = %(epi)s'
1431
1432 cmd = u"""
1433 select narrative
1434 from clin.clin_narrative
1435 where
1436 fk_encounter = %%(enc)s
1437 and
1438 soap_cat = %%(cat)s
1439 and
1440 %s
1441 order by clin_when desc
1442 limit 1
1443 """ % epi_part
1444
1445 args = {'enc': self.pk_obj, 'cat': soap_cat, 'epi': episode}
1446
1447 rows, idx = gmPG2.run_ro_queries (
1448 queries = [{
1449 'cmd': cmd,
1450 'args': args
1451 }]
1452 )
1453 if len(rows) == 0:
1454 return None
1455
1456 return rows[0][0]
1457 #--------------------------------------------------------
1459 cmd = u"""
1460 SELECT * FROM clin.v_pat_episodes
1461 WHERE
1462 pk_episode IN (
1463
1464 SELECT DISTINCT fk_episode
1465 FROM clin.clin_root_item
1466 WHERE fk_encounter = %%(enc)s
1467
1468 UNION
1469
1470 SELECT DISTINCT fk_episode
1471 FROM blobs.doc_med
1472 WHERE fk_encounter = %%(enc)s
1473 )
1474 %s"""
1475 args = {'enc': self.pk_obj}
1476 if exclude is not None:
1477 cmd = cmd % u'AND pk_episode NOT IN %(excluded)s'
1478 args['excluded'] = tuple(exclude)
1479 else:
1480 cmd = cmd % u''
1481
1482 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
1483
1484 return [ cEpisode(row = {'data': r, 'idx': idx, 'pk_field': 'pk_episode'}) for r in rows ]
1485 #--------------------------------------------------------
1487 """<pk_code> must be a value from ref.coding_system_root.pk_coding_system (clin.lnk_code2item_root.fk_generic_code)"""
1488 if field == u'rfe':
1489 cmd = u"INSERT INTO clin.lnk_code2rfe (fk_item, fk_generic_code) values (%(item)s, %(code)s)"
1490 elif field == u'aoe':
1491 cmd = u"INSERT INTO clin.lnk_code2aoe (fk_item, fk_generic_code) values (%(item)s, %(code)s)"
1492 else:
1493 raise ValueError('<field> must be one of "rfe" or "aoe", not "%s"', field)
1494 args = {
1495 'item': self._payload[self._idx['pk_encounter']],
1496 'code': pk_code
1497 }
1498 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
1499 return True
1500 #--------------------------------------------------------
1502 """<pk_code> must be a value from ref.coding_system_root.pk_coding_system (clin.lnk_code2item_root.fk_generic_code)"""
1503 if field == u'rfe':
1504 cmd = u"DELETE FROM clin.lnk_code2rfe WHERE fk_item = %(item)s AND fk_generic_code = %(code)s"
1505 elif field == u'aoe':
1506 cmd = u"DELETE FROM clin.lnk_code2aoe WHERE fk_item = %(item)s AND fk_generic_code = %(code)s"
1507 else:
1508 raise ValueError('<field> must be one of "rfe" or "aoe", not "%s"', field)
1509 args = {
1510 'item': self._payload[self._idx['pk_encounter']],
1511 'code': pk_code
1512 }
1513 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
1514 return True
1515 #--------------------------------------------------------
1516 - def format_soap(self, episodes=None, left_margin=0, soap_cats='soap', emr=None, issues=None):
1517
1518 lines = []
1519 for soap_cat in soap_cats:
1520 soap_cat_narratives = emr.get_clin_narrative (
1521 episodes = episodes,
1522 issues = issues,
1523 encounters = [self._payload[self._idx['pk_encounter']]],
1524 soap_cats = [soap_cat]
1525 )
1526 if soap_cat_narratives is None:
1527 continue
1528 if len(soap_cat_narratives) == 0:
1529 continue
1530
1531 lines.append(u'%s%s %s %s' % (
1532 gmTools.u_box_top_left_arc,
1533 gmTools.u_box_horiz_single,
1534 gmClinNarrative.soap_cat2l10n_str[soap_cat],
1535 gmTools.u_box_horiz_single * 5
1536 ))
1537 for soap_entry in soap_cat_narratives:
1538 txt = gmTools.wrap (
1539 text = soap_entry['narrative'],
1540 width = 75,
1541 initial_indent = u'',
1542 subsequent_indent = (u' ' * left_margin)
1543 )
1544 lines.append(txt)
1545 when = gmDateTime.pydt_strftime (
1546 soap_entry['date'],
1547 format = '%Y-%m-%d %H:%M',
1548 accuracy = gmDateTime.acc_minutes
1549 )
1550 txt = u'%s%s %.8s, %s %s' % (
1551 u' ' * 40,
1552 gmTools.u_box_horiz_light_heavy,
1553 soap_entry['provider'],
1554 when,
1555 gmTools.u_box_horiz_heavy_light
1556 )
1557 lines.append(txt)
1558 lines.append('')
1559
1560 return lines
1561 #--------------------------------------------------------
1563
1564 nothing2format = (
1565 (self._payload[self._idx['reason_for_encounter']] is None)
1566 and
1567 (self._payload[self._idx['assessment_of_encounter']] is None)
1568 and
1569 (self.has_soap_narrative(soap_cats = u'soap') is False)
1570 )
1571 if nothing2format:
1572 return u''
1573
1574 if date_format is None:
1575 date_format = '%A, %B %d %Y'
1576
1577 tex = u'\\multicolumn{2}{l}{%s: %s ({\\footnotesize %s - %s})} \\tabularnewline \n' % (
1578 gmTools.tex_escape_string(self._payload[self._idx['l10n_type']]),
1579 self._payload[self._idx['started']].strftime(date_format).decode(gmI18N.get_encoding()),
1580 self._payload[self._idx['started']].strftime('%H:%M'),
1581 self._payload[self._idx['last_affirmed']].strftime('%H:%M')
1582 )
1583 tex += u'\\hline \\tabularnewline \n'
1584
1585 for epi in self.get_episodes():
1586 soaps = epi.get_narrative(soap_cats = soap_cats, encounters = [self.pk_obj], order_by = soap_order)
1587 if len(soaps) == 0:
1588 continue
1589 tex += u'\\multicolumn{2}{l}{\\emph{%s: %s%s}} \\tabularnewline \n' % (
1590 gmTools.tex_escape_string(_('Problem')),
1591 gmTools.tex_escape_string(epi['description']),
1592 gmTools.coalesce (
1593 initial = diagnostic_certainty_classification2str(epi['diagnostic_certainty_classification']),
1594 instead = u'',
1595 template_initial = u' {\\footnotesize [%s]}',
1596 none_equivalents = [None, u'']
1597 )
1598 )
1599 if epi['pk_health_issue'] is not None:
1600 tex += u'\\multicolumn{2}{l}{\\emph{%s: %s%s}} \\tabularnewline \n' % (
1601 gmTools.tex_escape_string(_('Health issue')),
1602 gmTools.tex_escape_string(epi['health_issue']),
1603 gmTools.coalesce (
1604 initial = diagnostic_certainty_classification2str(epi['diagnostic_certainty_classification_issue']),
1605 instead = u'',
1606 template_initial = u' {\\footnotesize [%s]}',
1607 none_equivalents = [None, u'']
1608 )
1609 )
1610 for soap in soaps:
1611 tex += u'{\\small %s} & {\\small %s} \\tabularnewline \n' % (
1612 gmClinNarrative.soap_cat2l10n[soap['soap_cat']],
1613 gmTools.tex_escape_string(soap['narrative'].strip(u'\n'))
1614 )
1615 tex += u' & \\tabularnewline \n'
1616
1617 if self._payload[self._idx['reason_for_encounter']] is not None:
1618 tex += u'%s & %s \\tabularnewline \n' % (
1619 gmTools.tex_escape_string(_('RFE')),
1620 gmTools.tex_escape_string(self._payload[self._idx['reason_for_encounter']])
1621 )
1622 if self._payload[self._idx['assessment_of_encounter']] is not None:
1623 tex += u'%s & %s \\tabularnewline \n' % (
1624 gmTools.tex_escape_string(_('AOE')),
1625 gmTools.tex_escape_string(self._payload[self._idx['assessment_of_encounter']])
1626 )
1627
1628 tex += u'\\hline \\tabularnewline \n'
1629 tex += u' & \\tabularnewline \n'
1630
1631 return tex
1632 #--------------------------------------------------------
1633 - 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, with_family_history=True):
1634 """Format an encounter.
1635
1636 with_co_encountlet_hints:
1637 - whether to include which *other* episodes were discussed during this encounter
1638 - (only makes sense if episodes != None)
1639 """
1640 lines = []
1641
1642 if fancy_header:
1643 lines.append(u'%s%s: %s - %s (@%s)%s [#%s]' % (
1644 u' ' * left_margin,
1645 self._payload[self._idx['l10n_type']],
1646 self._payload[self._idx['started_original_tz']].strftime('%Y-%m-%d %H:%M'),
1647 self._payload[self._idx['last_affirmed_original_tz']].strftime('%H:%M'),
1648 self._payload[self._idx['source_time_zone']],
1649 gmTools.coalesce(self._payload[self._idx['assessment_of_encounter']], u'', u' \u00BB%s\u00AB'),
1650 self._payload[self._idx['pk_encounter']]
1651 ))
1652
1653 lines.append(_(' your time: %s - %s (@%s = %s%s)\n') % (
1654 self._payload[self._idx['started']].strftime('%Y-%m-%d %H:%M'),
1655 self._payload[self._idx['last_affirmed']].strftime('%H:%M'),
1656 gmDateTime.current_local_iso_numeric_timezone_string,
1657 gmTools.bool2subst (
1658 gmDateTime.dst_currently_in_effect,
1659 gmDateTime.py_dst_timezone_name,
1660 gmDateTime.py_timezone_name
1661 ),
1662 gmTools.bool2subst(gmDateTime.dst_currently_in_effect, u' - ' + _('daylight savings time in effect'), u'')
1663 ))
1664
1665 if self._payload[self._idx['reason_for_encounter']] is not None:
1666 lines.append(u'%s: %s' % (_('RFE'), self._payload[self._idx['reason_for_encounter']]))
1667 codes = self.generic_codes_rfe
1668 for c in codes:
1669 lines.append(u' %s: %s (%s - %s)' % (
1670 c['code'],
1671 c['term'],
1672 c['name_short'],
1673 c['version']
1674 ))
1675 if len(codes) > 0:
1676 lines.append(u'')
1677
1678 if self._payload[self._idx['assessment_of_encounter']] is not None:
1679 lines.append(u'%s: %s' % (_('AOE'), self._payload[self._idx['assessment_of_encounter']]))
1680 codes = self.generic_codes_aoe
1681 for c in codes:
1682 lines.append(u' %s: %s (%s - %s)' % (
1683 c['code'],
1684 c['term'],
1685 c['name_short'],
1686 c['version']
1687 ))
1688 if len(codes) > 0:
1689 lines.append(u'')
1690 del codes
1691
1692 else:
1693 now = gmDateTime.pydt_now_here()
1694 if now.strftime('%Y-%m-%d') == self._payload[self._idx['started_original_tz']].strftime('%Y-%m-%d'):
1695 start = u'%s %s' % (
1696 _('today'),
1697 self._payload[self._idx['started_original_tz']].strftime('%H:%M')
1698 )
1699 else:
1700 start = self._payload[self._idx['started_original_tz']].strftime('%Y-%m-%d %H:%M')
1701 lines.append(u'%s%s: %s - %s%s' % (
1702 u' ' * left_margin,
1703 self._payload[self._idx['l10n_type']],
1704 start,
1705 self._payload[self._idx['last_affirmed_original_tz']].strftime('%H:%M'),
1706 gmTools.coalesce(self._payload[self._idx['assessment_of_encounter']], u'', u' \u00BB%s\u00AB')
1707 ))
1708 if with_rfe_aoe:
1709 if self._payload[self._idx['reason_for_encounter']] is not None:
1710 lines.append(u'%s: %s' % (_('RFE'), self._payload[self._idx['reason_for_encounter']]))
1711 codes = self.generic_codes_rfe
1712 for c in codes:
1713 lines.append(u' %s: %s (%s - %s)' % (
1714 c['code'],
1715 c['term'],
1716 c['name_short'],
1717 c['version']
1718 ))
1719 if len(codes) > 0:
1720 lines.append(u'')
1721 if self._payload[self._idx['assessment_of_encounter']] is not None:
1722 lines.append(u'%s: %s' % (_('AOE'), self._payload[self._idx['assessment_of_encounter']]))
1723 codes = self.generic_codes_aoe
1724 if len(codes) > 0:
1725 lines.append(u'')
1726 for c in codes:
1727 lines.append(u' %s: %s (%s - %s)' % (
1728 c['code'],
1729 c['term'],
1730 c['name_short'],
1731 c['version']
1732 ))
1733 if len(codes) > 0:
1734 lines.append(u'')
1735 del codes
1736
1737 if with_soap:
1738 lines.append(u'')
1739
1740 if patient.ID != self._payload[self._idx['pk_patient']]:
1741 msg = '<patient>.ID = %s but encounter %s belongs to patient %s' % (
1742 patient.ID,
1743 self._payload[self._idx['pk_encounter']],
1744 self._payload[self._idx['pk_patient']]
1745 )
1746 raise ValueError(msg)
1747
1748 emr = patient.get_emr()
1749
1750 lines.extend(self.format_soap (
1751 episodes = episodes,
1752 left_margin = left_margin,
1753 soap_cats = 'soap',
1754 emr = emr,
1755 issues = issues
1756 ))
1757
1758 # # family history
1759 # if with_family_history:
1760 # if episodes is not None:
1761 # fhx = emr.get_family_history(episodes = episodes)
1762 # if len(fhx) > 0:
1763 # lines.append(u'')
1764 # lines.append(_('Family History: %s') % len(fhx))
1765 # for f in fhx:
1766 # lines.append(f.format (
1767 # left_margin = (left_margin + 1),
1768 # include_episode = False,
1769 # include_comment = True
1770 # ))
1771 # del fhx
1772
1773 # test results
1774 if with_tests:
1775 tests = emr.get_test_results_by_date (
1776 episodes = episodes,
1777 encounter = self._payload[self._idx['pk_encounter']]
1778 )
1779 if len(tests) > 0:
1780 lines.append('')
1781 lines.append(_('Measurements and Results:'))
1782
1783 for t in tests:
1784 lines.extend(t.format())
1785
1786 del tests
1787
1788 # vaccinations
1789 if with_vaccinations:
1790 vaccs = emr.get_vaccinations (
1791 episodes = episodes,
1792 encounters = [ self._payload[self._idx['pk_encounter']] ],
1793 order_by = u'date_given DESC, vaccine'
1794 )
1795
1796 if len(vaccs) > 0:
1797 lines.append(u'')
1798 lines.append(_('Vaccinations:'))
1799
1800 for vacc in vaccs:
1801 lines.extend(vacc.format (
1802 with_indications = True,
1803 with_comment = True,
1804 with_reaction = True,
1805 date_format = '%Y-%m-%d'
1806 ))
1807 del vaccs
1808
1809 # documents
1810 if with_docs:
1811 doc_folder = patient.get_document_folder()
1812 docs = doc_folder.get_documents (
1813 episodes = episodes,
1814 encounter = self._payload[self._idx['pk_encounter']]
1815 )
1816
1817 if len(docs) > 0:
1818 lines.append(u'')
1819 lines.append(_('Documents:'))
1820
1821 for d in docs:
1822 lines.append(u' %s %s:%s%s' % (
1823 d['clin_when'].strftime('%Y-%m-%d'),
1824 d['l10n_type'],
1825 gmTools.coalesce(d['comment'], u'', u' "%s"'),
1826 gmTools.coalesce(d['ext_ref'], u'', u' (%s)')
1827 ))
1828
1829 del docs
1830
1831 # co-encountlets
1832 if with_co_encountlet_hints:
1833 if episodes is not None:
1834 other_epis = self.get_episodes(exclude = episodes)
1835 if len(other_epis) > 0:
1836 lines.append(u'')
1837 lines.append(_('%s other episodes touched upon during this encounter:') % len(other_epis))
1838 for epi in other_epis:
1839 lines.append(u' %s%s%s%s' % (
1840 gmTools.u_left_double_angle_quote,
1841 epi['description'],
1842 gmTools.u_right_double_angle_quote,
1843 gmTools.coalesce(epi['health_issue'], u'', u' (%s)')
1844 ))
1845
1846 eol_w_margin = u'\n%s' % (u' ' * left_margin)
1847 return u'%s\n' % eol_w_margin.join(lines)
1848 #--------------------------------------------------------
1849 # properties
1850 #--------------------------------------------------------
1852 if len(self._payload[self._idx['pk_generic_codes_rfe']]) == 0:
1853 return []
1854
1855 cmd = gmCoding._SQL_get_generic_linked_codes % u'pk_generic_code IN %(pks)s'
1856 args = {'pks': tuple(self._payload[self._idx['pk_generic_codes_rfe']])}
1857 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
1858 return [ gmCoding.cGenericLinkedCode(row = {'data': r, 'idx': idx, 'pk_field': 'pk_lnk_code2item'}) for r in rows ]
1859
1861 queries = []
1862 # remove all codes
1863 if len(self._payload[self._idx['pk_generic_codes_rfe']]) > 0:
1864 queries.append ({
1865 'cmd': u'DELETE FROM clin.lnk_code2rfe WHERE fk_item = %(enc)s AND fk_generic_code IN %(codes)s',
1866 'args': {
1867 'enc': self._payload[self._idx['pk_encounter']],
1868 'codes': tuple(self._payload[self._idx['pk_generic_codes_rfe']])
1869 }
1870 })
1871 # add new codes
1872 for pk_code in pk_codes:
1873 queries.append ({
1874 'cmd': u'INSERT INTO clin.lnk_code2rfe (fk_item, fk_generic_code) VALUES (%(enc)s, %(pk_code)s)',
1875 'args': {
1876 'enc': self._payload[self._idx['pk_encounter']],
1877 'pk_code': pk_code
1878 }
1879 })
1880 if len(queries) == 0:
1881 return
1882 # run it all in one transaction
1883 rows, idx = gmPG2.run_rw_queries(queries = queries)
1884 self.refetch_payload()
1885 return
1886
1887 generic_codes_rfe = property(_get_generic_codes_rfe, _set_generic_codes_rfe)
1888 #--------------------------------------------------------
1890 if len(self._payload[self._idx['pk_generic_codes_aoe']]) == 0:
1891 return []
1892
1893 cmd = gmCoding._SQL_get_generic_linked_codes % u'pk_generic_code IN %(pks)s'
1894 args = {'pks': tuple(self._payload[self._idx['pk_generic_codes_aoe']])}
1895 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
1896 return [ gmCoding.cGenericLinkedCode(row = {'data': r, 'idx': idx, 'pk_field': 'pk_lnk_code2item'}) for r in rows ]
1897
1899 queries = []
1900 # remove all codes
1901 if len(self._payload[self._idx['pk_generic_codes_aoe']]) > 0:
1902 queries.append ({
1903 'cmd': u'DELETE FROM clin.lnk_code2aoe WHERE fk_item = %(enc)s AND fk_generic_code IN %(codes)s',
1904 'args': {
1905 'enc': self._payload[self._idx['pk_encounter']],
1906 'codes': tuple(self._payload[self._idx['pk_generic_codes_aoe']])
1907 }
1908 })
1909 # add new codes
1910 for pk_code in pk_codes:
1911 queries.append ({
1912 'cmd': u'INSERT INTO clin.lnk_code2aoe (fk_item, fk_generic_code) VALUES (%(enc)s, %(pk_code)s)',
1913 'args': {
1914 'enc': self._payload[self._idx['pk_encounter']],
1915 'pk_code': pk_code
1916 }
1917 })
1918 if len(queries) == 0:
1919 return
1920 # run it all in one transaction
1921 rows, idx = gmPG2.run_rw_queries(queries = queries)
1922 self.refetch_payload()
1923 return
1924
1925 generic_codes_aoe = property(_get_generic_codes_aoe, _set_generic_codes_aoe)
1926 #-----------------------------------------------------------
1928 """Creates a new encounter for a patient.
1929
1930 fk_patient - patient PK
1931 fk_location - encounter location
1932 enc_type - type of encounter
1933
1934 FIXME: we don't deal with location yet
1935 """
1936 if enc_type is None:
1937 enc_type = u'in surgery'
1938 # insert new encounter
1939 queries = []
1940 try:
1941 enc_type = int(enc_type)
1942 cmd = u"""
1943 INSERT INTO clin.encounter (
1944 fk_patient, fk_location, fk_type
1945 ) VALUES (
1946 %(pat)s,
1947 -1,
1948 %(typ)s
1949 ) RETURNING pk"""
1950 except ValueError:
1951 enc_type = enc_type
1952 cmd = u"""
1953 insert into clin.encounter (
1954 fk_patient, fk_location, fk_type
1955 ) values (
1956 %(pat)s,
1957 -1,
1958 coalesce (
1959 (select pk from clin.encounter_type where description = %(typ)s),
1960 -- pick the first available
1961 (select pk from clin.encounter_type limit 1)
1962 )
1963 ) RETURNING pk"""
1964 args = {'pat': fk_patient, 'typ': enc_type}
1965 queries.append({'cmd': cmd, 'args': args})
1966 rows, idx = gmPG2.run_rw_queries(queries = queries, return_data = True, get_col_idx = False)
1967 encounter = cEncounter(aPK_obj = rows[0]['pk'])
1968
1969 return encounter
1970 #-----------------------------------------------------------
1972
1973 rows, idx = gmPG2.run_rw_queries(
1974 queries = [{
1975 'cmd': u"select i18n.upd_tx(%(desc)s, %(l10n_desc)s)",
1976 'args': {'desc': description, 'l10n_desc': l10n_description}
1977 }],
1978 return_data = True
1979 )
1980
1981 success = rows[0][0]
1982 if not success:
1983 _log.warning('updating encounter type [%s] to [%s] failed', description, l10n_description)
1984
1985 return {'description': description, 'l10n_description': l10n_description}
1986 #-----------------------------------------------------------
1988 """This will attempt to create a NEW encounter type."""
1989
1990 # need a system name, so derive one if necessary
1991 if description is None:
1992 description = l10n_description
1993
1994 args = {
1995 'desc': description,
1996 'l10n_desc': l10n_description
1997 }
1998
1999 _log.debug('creating encounter type: %s, %s', description, l10n_description)
2000
2001 # does it exist already ?
2002 cmd = u"select description, _(description) from clin.encounter_type where description = %(desc)s"
2003 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}])
2004
2005 # yes
2006 if len(rows) > 0:
2007 # both system and l10n name are the same so all is well
2008 if (rows[0][0] == description) and (rows[0][1] == l10n_description):
2009 _log.info('encounter type [%s] already exists with the proper translation')
2010 return {'description': description, 'l10n_description': l10n_description}
2011
2012 # or maybe there just wasn't a translation to
2013 # the current language for this type yet ?
2014 cmd = u"select exists (select 1 from i18n.translations where orig = %(desc)s and lang = i18n.get_curr_lang())"
2015 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}])
2016
2017 # there was, so fail
2018 if rows[0][0]:
2019 _log.error('encounter type [%s] already exists but with another translation')
2020 return None
2021
2022 # else set it
2023 cmd = u"select i18n.upd_tx(%(desc)s, %(l10n_desc)s)"
2024 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
2025 return {'description': description, 'l10n_description': l10n_description}
2026
2027 # no
2028 queries = [
2029 {'cmd': u"insert into clin.encounter_type (description) values (%(desc)s)", 'args': args},
2030 {'cmd': u"select i18n.upd_tx(%(desc)s, %(l10n_desc)s)", 'args': args}
2031 ]
2032 rows, idx = gmPG2.run_rw_queries(queries = queries)
2033
2034 return {'description': description, 'l10n_description': l10n_description}
2035 #-----------------------------------------------------------
2037 cmd = u"""
2038 SELECT
2039 _(description) AS l10n_description,
2040 description
2041 FROM
2042 clin.encounter_type
2043 ORDER BY
2044 l10n_description
2045 """
2046 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}])
2047 return rows
2048 #-----------------------------------------------------------
2050 cmd = u"SELECT * from clin.encounter_type where description = %s"
2051 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': [description]}])
2052 return rows
2053 #-----------------------------------------------------------
2055 cmd = u"delete from clin.encounter_type where description = %(desc)s"
2056 args = {'desc': description}
2057 try:
2058 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
2059 except gmPG2.dbapi.IntegrityError, e:
2060 if e.pgcode == gmPG2.sql_error_codes.FOREIGN_KEY_VIOLATION:
2061 return False
2062 raise
2063
2064 return True
2065 #============================================================
2067 """Represents one problem.
2068
2069 problems are the aggregation of
2070 .clinically_relevant=True issues and
2071 .is_open=True episodes
2072 """
2073 _cmd_fetch_payload = u'' # will get programmatically defined in __init__
2074 _cmds_store_payload = [u"select 1"]
2075 _updatable_fields = []
2076
2077 #--------------------------------------------------------
2079 """Initialize.
2080
2081 aPK_obj must contain the keys
2082 pk_patient
2083 pk_episode
2084 pk_health_issue
2085 """
2086 if aPK_obj is None:
2087 raise gmExceptions.ConstructorError, 'cannot instatiate cProblem for PK: [%s]' % (aPK_obj)
2088
2089 # As problems are rows from a view of different emr struct items,
2090 # the PK can't be a single field and, as some of the values of the
2091 # composed PK may be None, they must be queried using 'is null',
2092 # so we must programmatically construct the SQL query
2093 where_parts = []
2094 pk = {}
2095 for col_name in aPK_obj.keys():
2096 val = aPK_obj[col_name]
2097 if val is None:
2098 where_parts.append('%s IS NULL' % col_name)
2099 else:
2100 where_parts.append('%s = %%(%s)s' % (col_name, col_name))
2101 pk[col_name] = val
2102
2103 # try to instantiate from true problem view
2104 cProblem._cmd_fetch_payload = u"""
2105 SELECT *, False as is_potential_problem
2106 FROM clin.v_problem_list
2107 WHERE %s""" % u' AND '.join(where_parts)
2108
2109 try:
2110 gmBusinessDBObject.cBusinessDBObject.__init__(self, aPK_obj=pk)
2111 return
2112 except gmExceptions.ConstructorError:
2113 _log.exception('actual problem not found, trying "potential" problems')
2114 if try_potential_problems is False:
2115 raise
2116
2117 # try to instantiate from potential-problems view
2118 cProblem._cmd_fetch_payload = u"""
2119 SELECT *, True as is_potential_problem
2120 FROM clin.v_potential_problem_list
2121 WHERE %s""" % u' AND '.join(where_parts)
2122 gmBusinessDBObject.cBusinessDBObject.__init__(self, aPK_obj=pk)
2123 #--------------------------------------------------------
2125 """
2126 Retrieve the cEpisode instance equivalent to this problem.
2127 The problem's type attribute must be 'episode'
2128 """
2129 if self._payload[self._idx['type']] != 'episode':
2130 _log.error('cannot convert problem [%s] of type [%s] to episode' % (self._payload[self._idx['problem']], self._payload[self._idx['type']]))
2131 return None
2132 return cEpisode(aPK_obj = self._payload[self._idx['pk_episode']])
2133 #--------------------------------------------------------
2135 """
2136 Retrieve the cHealthIssue instance equivalent to this problem.
2137 The problem's type attribute must be 'issue'
2138 """
2139 if self._payload[self._idx['type']] != 'issue':
2140 _log.error('cannot convert problem [%s] of type [%s] to health issue' % (self._payload[self._idx['problem']], self._payload[self._idx['type']]))
2141 return None
2142 return cHealthIssue(aPK_obj = self._payload[self._idx['pk_health_issue']])
2143 #--------------------------------------------------------
2145
2146 if self._payload[self._idx['type']] == u'issue':
2147 episodes = [ cHealthIssue(aPK_obj = self._payload[self._idx['pk_health_issue']]).latest_episode ]
2148 #xxxxxxxxxxxxx
2149
2150 emr = patient.get_emr()
2151
2152 doc_folder = gmDocuments.cDocumentFolder(aPKey = patient.ID)
2153 return doc_folder.get_visual_progress_notes (
2154 health_issue = self._payload[self._idx['pk_health_issue']],
2155 episode = self._payload[self._idx['pk_episode']]
2156 )
2157 #--------------------------------------------------------
2158 # properties
2159 #--------------------------------------------------------
2160 # doubles as 'diagnostic_certainty_description' getter:
2162 return diagnostic_certainty_classification2str(self._payload[self._idx['diagnostic_certainty_classification']])
2163
2164 diagnostic_certainty_description = property(get_diagnostic_certainty_description, lambda x:x)
2165 #--------------------------------------------------------
2167 if self._payload[self._idx['type']] == u'issue':
2168 cmd = u"""
2169 SELECT * FROM clin.v_linked_codes WHERE
2170 item_table = 'clin.lnk_code2h_issue'::regclass
2171 AND
2172 pk_item = %(item)s
2173 """
2174 args = {'item': self._payload[self._idx['pk_health_issue']]}
2175 else:
2176 cmd = u"""
2177 SELECT * FROM clin.v_linked_codes WHERE
2178 item_table = 'clin.lnk_code2episode'::regclass
2179 AND
2180 pk_item = %(item)s
2181 """
2182 args = {'item': self._payload[self._idx['pk_episode']]}
2183
2184 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
2185 return [ gmCoding.cGenericLinkedCode(row = {'data': r, 'idx': idx, 'pk_field': 'pk_lnk_code2item'}) for r in rows ]
2186
2187 generic_codes = property(_get_generic_codes, lambda x:x)
2188 #-----------------------------------------------------------
2190 """Retrieve the cEpisode instance equivalent to the given problem.
2191
2192 The problem's type attribute must be 'episode'
2193
2194 @param problem: The problem to retrieve its related episode for
2195 @type problem: A gmEMRStructItems.cProblem instance
2196 """
2197 if isinstance(problem, cEpisode):
2198 return problem
2199
2200 exc = TypeError('cannot convert [%s] to episode' % problem)
2201
2202 if not isinstance(problem, cProblem):
2203 raise exc
2204
2205 if problem['type'] != 'episode':
2206 raise exc
2207
2208 return cEpisode(aPK_obj = problem['pk_episode'])
2209 #-----------------------------------------------------------
2211 """Retrieve the cIssue instance equivalent to the given problem.
2212
2213 The problem's type attribute must be 'issue'.
2214
2215 @param problem: The problem to retrieve the corresponding issue for
2216 @type problem: A gmEMRStructItems.cProblem instance
2217 """
2218 if isinstance(problem, cHealthIssue):
2219 return problem
2220
2221 exc = TypeError('cannot convert [%s] to health issue' % problem)
2222
2223 if not isinstance(problem, cProblem):
2224 raise exc
2225
2226 if problem['type'] != 'issue':
2227 raise exc
2228
2229 return cHealthIssue(aPK_obj = problem['pk_health_issue'])
2230 #-----------------------------------------------------------
2232 """Transform given problem into either episode or health issue instance.
2233 """
2234 if isinstance(problem, (cEpisode, cHealthIssue)):
2235 return problem
2236
2237 exc = TypeError('cannot reclass [%s] instance to either episode or health issue' % type(problem))
2238
2239 if not isinstance(problem, cProblem):
2240 _log.debug(u'%s' % problem)
2241 raise exc
2242
2243 if problem['type'] == 'episode':
2244 return cEpisode(aPK_obj = problem['pk_episode'])
2245
2246 if problem['type'] == 'issue':
2247 return cHealthIssue(aPK_obj = problem['pk_health_issue'])
2248
2249 raise exc
2250 #============================================================
2252
2253 _cmd_fetch_payload = u"select * from clin.v_pat_hospital_stays where pk_hospital_stay = %s"
2254 _cmds_store_payload = [
2255 u"""update clin.hospital_stay set
2256 clin_when = %(admission)s,
2257 discharge = %(discharge)s,
2258 narrative = gm.nullify_empty_string(%(hospital)s),
2259 fk_episode = %(pk_episode)s,
2260 fk_encounter = %(pk_encounter)s
2261 where
2262 pk = %(pk_hospital_stay)s and
2263 xmin = %(xmin_hospital_stay)s""",
2264 u"""select xmin_hospital_stay from clin.v_pat_hospital_stays where pk_hospital_stay = %(pk_hospital_stay)s"""
2265 ]
2266 _updatable_fields = [
2267 'admission',
2268 'discharge',
2269 'hospital',
2270 'pk_episode',
2271 'pk_encounter'
2272 ]
2273 #-------------------------------------------------------
2275
2276 if self._payload[self._idx['discharge']] is not None:
2277 dis = u' - %s' % self._payload[self._idx['discharge']].strftime('%Y %b %d').decode(gmI18N.get_encoding())
2278 else:
2279 dis = u''
2280
2281 line = u'%s%s%s%s: %s%s%s' % (
2282 u' ' * left_margin,
2283 self._payload[self._idx['admission']].strftime('%Y %b %d').decode(gmI18N.get_encoding()),
2284 dis,
2285 gmTools.coalesce(self._payload[self._idx['hospital']], u'', u' (%s)'),
2286 gmTools.u_left_double_angle_quote,
2287 self._payload[self._idx['episode']],
2288 gmTools.u_right_double_angle_quote
2289 )
2290
2291 return line
2292 #-----------------------------------------------------------
2294 queries = [{
2295 # this assumes non-overarching stays
2296 'cmd': u'SELECT * FROM clin.v_pat_hospital_stays WHERE pk_patient = %(pat)s ORDER BY admission DESC LIMIT 1',
2297 'args': {'pat': patient}
2298 }]
2299 rows, idx = gmPG2.run_ro_queries(queries = queries, get_col_idx = True)
2300 if len(rows) == 0:
2301 return None
2302 return cHospitalStay(row = {'idx': idx, 'data': rows[0], 'pk_field': 'pk_hospital_stay'})
2303 #-----------------------------------------------------------
2305
2306 queries = [{
2307 'cmd': u'SELECT * FROM clin.v_pat_hospital_stays WHERE pk_patient = %(pat)s ORDER BY admission',
2308 'args': {'pat': patient}
2309 }]
2310
2311 rows, idx = gmPG2.run_ro_queries(queries = queries, get_col_idx = True)
2312
2313 return [ cHospitalStay(row = {'idx': idx, 'data': r, 'pk_field': 'pk_hospital_stay'}) for r in rows ]
2314 #-----------------------------------------------------------
2316
2317 queries = [{
2318 'cmd': u'INSERT INTO clin.hospital_stay (fk_encounter, fk_episode) VALUES (%(enc)s, %(epi)s) RETURNING pk',
2319 'args': {'enc': encounter, 'epi': episode}
2320 }]
2321 rows, idx = gmPG2.run_rw_queries(queries = queries, return_data = True)
2322
2323 return cHospitalStay(aPK_obj = rows[0][0])
2324 #-----------------------------------------------------------
2326 cmd = u'DELETE FROM clin.hospital_stay WHERE pk = %(pk)s'
2327 args = {'pk': stay}
2328 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
2329 return True
2330 #============================================================
2332
2333 _cmd_fetch_payload = u"select * from clin.v_pat_procedures where pk_procedure = %s"
2334 _cmds_store_payload = [
2335 u"""UPDATE clin.procedure SET
2336 soap_cat = 'p',
2337 clin_when = %(clin_when)s,
2338 clin_end = %(clin_end)s,
2339 is_ongoing = %(is_ongoing)s,
2340 clin_where = NULLIF (
2341 COALESCE (
2342 %(pk_hospital_stay)s::TEXT,
2343 gm.nullify_empty_string(%(clin_where)s)
2344 ),
2345 %(pk_hospital_stay)s::TEXT
2346 ),
2347 narrative = gm.nullify_empty_string(%(performed_procedure)s),
2348 fk_hospital_stay = %(pk_hospital_stay)s,
2349 fk_episode = %(pk_episode)s,
2350 fk_encounter = %(pk_encounter)s
2351 WHERE
2352 pk = %(pk_procedure)s AND
2353 xmin = %(xmin_procedure)s
2354 RETURNING xmin as xmin_procedure"""
2355 ]
2356 _updatable_fields = [
2357 'clin_when',
2358 'clin_end',
2359 'is_ongoing',
2360 'clin_where',
2361 'performed_procedure',
2362 'pk_hospital_stay',
2363 'pk_episode',
2364 'pk_encounter'
2365 ]
2366 #-------------------------------------------------------
2368
2369 if (attribute == 'pk_hospital_stay') and (value is not None):
2370 gmBusinessDBObject.cBusinessDBObject.__setitem__(self, 'clin_where', None)
2371
2372 if (attribute == 'clin_where') and (value is not None) and (value.strip() != u''):
2373 gmBusinessDBObject.cBusinessDBObject.__setitem__(self, 'pk_hospital_stay', None)
2374
2375 gmBusinessDBObject.cBusinessDBObject.__setitem__(self, attribute, value)
2376 #-------------------------------------------------------
2378
2379 if self._payload[self._idx['is_ongoing']]:
2380 end = _(' (ongoing)')
2381 else:
2382 end = self._payload[self._idx['clin_end']]
2383 if end is None:
2384 end = u''
2385 else:
2386 end = u' - %s' % end.strftime('%Y %b %d').decode(gmI18N.get_encoding())
2387
2388 line = u'%s%s%s (%s): %s' % (
2389 (u' ' * left_margin),
2390 self._payload[self._idx['clin_when']].strftime('%Y %b %d').decode(gmI18N.get_encoding()),
2391 end,
2392 self._payload[self._idx['clin_where']],
2393 self._payload[self._idx['performed_procedure']]
2394 )
2395 if include_episode:
2396 line = u'%s (%s)' % (line, self._payload[self._idx['episode']])
2397
2398 if include_codes:
2399 codes = self.generic_codes
2400 if len(codes) > 0:
2401 line += u'\n'
2402 for c in codes:
2403 line += u'%s %s: %s (%s - %s)\n' % (
2404 (u' ' * left_margin),
2405 c['code'],
2406 c['term'],
2407 c['name_short'],
2408 c['version']
2409 )
2410 del codes
2411
2412 return line
2413 #--------------------------------------------------------
2415 """<pk_code> must be a value from ref.coding_system_root.pk_coding_system (clin.lnk_code2item_root.fk_generic_code)"""
2416 cmd = u"INSERT INTO clin.lnk_code2procedure (fk_item, fk_generic_code) values (%(issue)s, %(code)s)"
2417 args = {
2418 'issue': self._payload[self._idx['pk_procedure']],
2419 'code': pk_code
2420 }
2421 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
2422 return True
2423 #--------------------------------------------------------
2425 """<pk_code> must be a value from ref.coding_system_root.pk_coding_system (clin.lnk_code2item_root.fk_generic_code)"""
2426 cmd = u"DELETE FROM clin.lnk_code2procedure WHERE fk_item = %(issue)s AND fk_generic_code = %(code)s"
2427 args = {
2428 'issue': self._payload[self._idx['pk_procedure']],
2429 'code': pk_code
2430 }
2431 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
2432 return True
2433 #--------------------------------------------------------
2434 # properties
2435 #--------------------------------------------------------
2437 if len(self._payload[self._idx['pk_generic_codes']]) == 0:
2438 return []
2439
2440 cmd = gmCoding._SQL_get_generic_linked_codes % u'pk_generic_code IN %(pks)s'
2441 args = {'pks': tuple(self._payload[self._idx['pk_generic_codes']])}
2442 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
2443 return [ gmCoding.cGenericLinkedCode(row = {'data': r, 'idx': idx, 'pk_field': 'pk_lnk_code2item'}) for r in rows ]
2444
2446 queries = []
2447 # remove all codes
2448 if len(self._payload[self._idx['pk_generic_codes']]) > 0:
2449 queries.append ({
2450 'cmd': u'DELETE FROM clin.lnk_code2procedure WHERE fk_item = %(proc)s AND fk_generic_code IN %(codes)s',
2451 'args': {
2452 'proc': self._payload[self._idx['pk_procedure']],
2453 'codes': tuple(self._payload[self._idx['pk_generic_codes']])
2454 }
2455 })
2456 # add new codes
2457 for pk_code in pk_codes:
2458 queries.append ({
2459 'cmd': u'INSERT INTO clin.lnk_code2procedure (fk_item, fk_generic_code) VALUES (%(proc)s, %(pk_code)s)',
2460 'args': {
2461 'proc': self._payload[self._idx['pk_procedure']],
2462 'pk_code': pk_code
2463 }
2464 })
2465 if len(queries) == 0:
2466 return
2467 # run it all in one transaction
2468 rows, idx = gmPG2.run_rw_queries(queries = queries)
2469 return
2470
2471 generic_codes = property(_get_generic_codes, _set_generic_codes)
2472 #-----------------------------------------------------------
2474
2475 queries = [
2476 {
2477 'cmd': u'select * from clin.v_pat_procedures where pk_patient = %(pat)s order by clin_when',
2478 'args': {'pat': patient}
2479 }
2480 ]
2481
2482 rows, idx = gmPG2.run_ro_queries(queries = queries, get_col_idx = True)
2483
2484 return [ cPerformedProcedure(row = {'idx': idx, 'data': r, 'pk_field': 'pk_procedure'}) for r in rows ]
2485 #-----------------------------------------------------------
2487 queries = [
2488 {
2489 'cmd': u'select * from clin.v_pat_procedures where pk_patient = %(pat)s order by clin_when DESC LIMIT 1',
2490 'args': {'pat': patient}
2491 }
2492 ]
2493 rows, idx = gmPG2.run_ro_queries(queries = queries, get_col_idx = True)
2494 if len(rows) == 0:
2495 return None
2496 return cPerformedProcedure(row = {'idx': idx, 'data': rows[0], 'pk_field': 'pk_procedure'})
2497 #-----------------------------------------------------------
2498 -def create_performed_procedure(encounter=None, episode=None, location=None, hospital_stay=None, procedure=None):
2499
2500 queries = [{
2501 'cmd': u"""
2502 INSERT INTO clin.procedure (
2503 fk_encounter,
2504 fk_episode,
2505 soap_cat,
2506 clin_where,
2507 fk_hospital_stay,
2508 narrative
2509 ) VALUES (
2510 %(enc)s,
2511 %(epi)s,
2512 'p',
2513 gm.nullify_empty_string(%(loc)s),
2514 %(stay)s,
2515 gm.nullify_empty_string(%(proc)s)
2516 )
2517 RETURNING pk""",
2518 'args': {'enc': encounter, 'epi': episode, 'loc': location, 'stay': hospital_stay, 'proc': procedure}
2519 }]
2520
2521 rows, idx = gmPG2.run_rw_queries(queries = queries, return_data = True)
2522
2523 return cPerformedProcedure(aPK_obj = rows[0][0])
2524 #-----------------------------------------------------------
2526 cmd = u'delete from clin.procedure where pk = %(pk)s'
2527 args = {'pk': procedure}
2528 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
2529 return True
2530 #============================================================
2531 # main - unit testing
2532 #------------------------------------------------------------
2533 if __name__ == '__main__':
2534
2535 if len(sys.argv) < 2:
2536 sys.exit()
2537
2538 if sys.argv[1] != 'test':
2539 sys.exit()
2540
2541 #--------------------------------------------------------
2542 # define tests
2543 #--------------------------------------------------------
2545 print "\nProblem test"
2546 print "------------"
2547 prob = cProblem(aPK_obj={'pk_patient': 12, 'pk_health_issue': 1, 'pk_episode': None})
2548 print prob
2549 fields = prob.get_fields()
2550 for field in fields:
2551 print field, ':', prob[field]
2552 print '\nupdatable:', prob.get_updatable_fields()
2553 epi = prob.get_as_episode()
2554 print '\nas episode:'
2555 if epi is not None:
2556 for field in epi.get_fields():
2557 print ' .%s : %s' % (field, epi[field])
2558 #--------------------------------------------------------
2560 print "\nhealth issue test"
2561 print "-----------------"
2562 h_issue = cHealthIssue(aPK_obj=2)
2563 print h_issue
2564 fields = h_issue.get_fields()
2565 for field in fields:
2566 print field, ':', h_issue[field]
2567 print "has open episode:", h_issue.has_open_episode()
2568 print "open episode:", h_issue.get_open_episode()
2569 print "updateable:", h_issue.get_updatable_fields()
2570 h_issue.close_expired_episode(ttl=7300)
2571 h_issue = cHealthIssue(encounter = 1, name = u'post appendectomy/peritonitis')
2572 print h_issue
2573 print h_issue.format_as_journal()
2574 #--------------------------------------------------------
2576 print "\nepisode test"
2577 print "------------"
2578 episode = cEpisode(aPK_obj=1)
2579 print episode
2580 fields = episode.get_fields()
2581 for field in fields:
2582 print field, ':', episode[field]
2583 print "updatable:", episode.get_updatable_fields()
2584 raw_input('ENTER to continue')
2585
2586 old_description = episode['description']
2587 old_enc = cEncounter(aPK_obj = 1)
2588
2589 desc = '1-%s' % episode['description']
2590 print "==> renaming to", desc
2591 successful = episode.rename (
2592 description = desc
2593 )
2594 if not successful:
2595 print "error"
2596 else:
2597 print "success"
2598 for field in fields:
2599 print field, ':', episode[field]
2600
2601 print "episode range:", episode.get_access_range()
2602
2603 raw_input('ENTER to continue')
2604
2605 #--------------------------------------------------------
2607 print "\nencounter test"
2608 print "--------------"
2609 encounter = cEncounter(aPK_obj=1)
2610 print encounter
2611 fields = encounter.get_fields()
2612 for field in fields:
2613 print field, ':', encounter[field]
2614 print "updatable:", encounter.get_updatable_fields()
2615 #--------------------------------------------------------
2617 encounter = cEncounter(aPK_obj=1)
2618 print encounter
2619 print ""
2620 print encounter.format_latex()
2621 #--------------------------------------------------------
2623 procs = get_performed_procedures(patient = 12)
2624 for proc in procs:
2625 print proc.format(left_margin=2)
2626 #--------------------------------------------------------
2628 stay = create_hospital_stay(encounter = 1, episode = 2)
2629 stay['hospital'] = u'Starfleet Galaxy General Hospital'
2630 stay.save_payload()
2631 print stay
2632 for s in get_patient_hospital_stays(12):
2633 print s
2634 delete_hospital_stay(stay['pk_hospital_stay'])
2635 stay = create_hospital_stay(encounter = 1, episode = 4)
2636 #--------------------------------------------------------
2638 tests = [None, 'A', 'B', 'C', 'D', 'E']
2639
2640 for t in tests:
2641 print type(t), t
2642 print type(diagnostic_certainty_classification2str(t)), diagnostic_certainty_classification2str(t)
2643 #--------------------------------------------------------
2648 #--------------------------------------------------------
2649 # run them
2650 #test_episode()
2651 #test_problem()
2652 #test_encounter()
2653 #test_health_issue()
2654 #test_hospital_stay()
2655 #test_performed_procedure()
2656 #test_diagnostic_certainty_classification_map()
2657 #test_encounter2latex()
2658 test_episode_codes()
2659 #============================================================
2660
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Mon Dec 5 04:00:22 2011 | http://epydoc.sourceforge.net |