1
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
26
27 __diagnostic_certainty_classification_map = None
28
46
47
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
122 - def rename(self, description=None):
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
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
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
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
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
202
203 diagnostic_certainty_description = property(_get_diagnostic_certainty_description, lambda x:x)
204
367
369 """Creates a new health issue for a given patient.
370
371 description - health issue name
372 """
373 try:
374 h_issue = cHealthIssue(name = description, encounter = encounter, patient = patient)
375 return h_issue
376 except gmExceptions.NoSuchBusinessObjectError:
377 pass
378
379 queries = []
380 cmd = u"insert into clin.health_issue (description, fk_encounter) values (%(desc)s, %(enc)s)"
381 queries.append({'cmd': cmd, 'args': {'desc': description, 'enc': encounter}})
382
383 cmd = u"select currval('clin.health_issue_pk_seq')"
384 queries.append({'cmd': cmd})
385
386 rows, idx = gmPG2.run_rw_queries(queries = queries, return_data = True)
387 h_issue = cHealthIssue(aPK_obj = rows[0][0])
388
389 return h_issue
390
392 if isinstance(health_issue, cHealthIssue):
393 pk = health_issue['pk_health_issue']
394 else:
395 pk = int(health_issue)
396
397 try:
398 gmPG2.run_rw_queries(queries = [{'cmd': u'delete from clin.health_issue where pk=%(pk)s', 'args': {'pk': pk}}])
399 except gmPG2.dbapi.IntegrityError:
400
401 _log.exception('cannot delete health issue')
402 raise gmExceptions.DatabaseObjectInUseError('cannot delete health issue, it is in use')
403
404
406 issue = {
407 'pk_health_issue': None,
408 'description': _('Unattributed episodes'),
409 'age_noted': None,
410 'laterality': u'na',
411 'is_active': True,
412 'clinically_relevant': True,
413 'is_confidential': None,
414 'is_cause_of_death': False,
415 'is_dummy': True
416 }
417 return issue
418
420 return cProblem (
421 aPK_obj = {
422 'pk_patient': health_issue['pk_patient'],
423 'pk_health_issue': health_issue['pk_health_issue'],
424 'pk_episode': None
425 },
426 try_potential_problems = allow_irrelevant
427 )
428
429
430
431 -class cEpisode(gmBusinessDBObject.cBusinessDBObject):
432 """Represents one clinical episode.
433 """
434 _cmd_fetch_payload = u"select * from clin.v_pat_episodes where pk_episode=%s"
435 _cmds_store_payload = [
436 u"""update clin.episode set
437 fk_health_issue = %(pk_health_issue)s,
438 is_open = %(episode_open)s::boolean,
439 description = %(description)s,
440 diagnostic_certainty_classification = gm.nullify_empty_string(%(diagnostic_certainty_classification)s)
441 where
442 pk = %(pk_episode)s and
443 xmin = %(xmin_episode)s""",
444 u"""select xmin_episode from clin.v_pat_episodes where pk_episode = %(pk_episode)s"""
445 ]
446 _updatable_fields = [
447 'pk_health_issue',
448 'episode_open',
449 'description',
450 'diagnostic_certainty_classification'
451 ]
452
453 - def __init__(self, aPK_obj=None, id_patient=None, name='xxxDEFAULTxxx', health_issue=None, row=None, encounter=None):
454 pk = aPK_obj
455 if pk is None and row is None:
456
457 where_parts = [u'description = %(desc)s']
458
459 if id_patient is not None:
460 where_parts.append(u'pk_patient = %(pat)s')
461
462 if health_issue is not None:
463 where_parts.append(u'pk_health_issue = %(issue)s')
464
465 if encounter is not None:
466 where_parts.append(u'pk_patient = (select fk_patient from clin.encounter where pk = %(enc)s)')
467
468 args = {
469 'pat': id_patient,
470 'issue': health_issue,
471 'enc': encounter,
472 'desc': name
473 }
474
475 cmd = u"select * from clin.v_pat_episodes where %s" % u' and '.join(where_parts)
476
477 rows, idx = gmPG2.run_ro_queries(
478 queries = [{'cmd': cmd, 'args': args}],
479 get_col_idx=True
480 )
481
482 if len(rows) == 0:
483 raise gmExceptions.NoSuchBusinessObjectError, 'no episode for [%s:%s:%s:%s]' % (id_patient, name, health_issue, encounter)
484
485 r = {'idx': idx, 'data': rows[0], 'pk_field': 'pk_episode'}
486 gmBusinessDBObject.cBusinessDBObject.__init__(self, row=r)
487
488 else:
489 gmBusinessDBObject.cBusinessDBObject.__init__(self, aPK_obj=pk, row=row)
490
492 """Get earliest and latest access to this episode.
493
494 Returns a tuple(earliest, latest).
495 """
496 cmd = u"""
497 select
498 min(earliest),
499 max(latest)
500 from (
501 (select
502 (case when clin_when < modified_when
503 then clin_when
504 else modified_when
505 end) as earliest,
506 (case when clin_when > modified_when
507 then clin_when
508 else modified_when
509 end) as latest
510 from
511 clin.clin_root_item
512 where
513 fk_episode = %(pk)s
514
515 ) union all (
516
517 select
518 modified_when as earliest,
519 modified_when as latest
520 from
521 clin.episode
522 where
523 pk = %(pk)s
524 )
525 ) as ranges"""
526 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': {'pk': self.pk_obj}}])
527 if len(rows) == 0:
528 return (gmNull.cNull(warn=False), gmNull.cNull(warn=False))
529 return (rows[0][0], rows[0][1])
530
532 return self._payload[self._idx['pk_patient']]
533
534 - def rename(self, description=None):
535 """Method for episode editing, that is, episode renaming.
536
537 @param description
538 - the new descriptive name for the encounter
539 @type description
540 - a string instance
541 """
542
543 if description.strip() == '':
544 _log.error('<description> must be a non-empty string instance')
545 return False
546
547 old_description = self._payload[self._idx['description']]
548 self._payload[self._idx['description']] = description.strip()
549 self._is_modified = True
550 successful, data = self.save_payload()
551 if not successful:
552 _log.error('cannot rename episode [%s] to [%s]' % (self, description))
553 self._payload[self._idx['description']] = old_description
554 return False
555 return True
556
559
560 diagnostic_certainty_description = property(_get_diagnostic_certainty_description, lambda x:x)
561
726
727 -def create_episode(pk_health_issue=None, episode_name=None, is_open=False, allow_dupes=False, encounter=None):
728 """Creates a new episode for a given patient's health issue.
729
730 pk_health_issue - given health issue PK
731 episode_name - name of episode
732 """
733 if not allow_dupes:
734 try:
735 episode = cEpisode(name=episode_name, health_issue=pk_health_issue, encounter = encounter)
736 if episode['episode_open'] != is_open:
737 episode['episode_open'] = is_open
738 episode.save_payload()
739 return episode
740 except gmExceptions.ConstructorError:
741 pass
742
743 queries = []
744 cmd = u"insert into clin.episode (fk_health_issue, description, is_open, fk_encounter) values (%s, %s, %s::boolean, %s)"
745 queries.append({'cmd': cmd, 'args': [pk_health_issue, episode_name, is_open, encounter]})
746 queries.append({'cmd': cEpisode._cmd_fetch_payload % u"currval('clin.episode_pk_seq')"})
747 rows, idx = gmPG2.run_rw_queries(queries = queries, return_data=True, get_col_idx=True)
748
749 episode = cEpisode(row={'data': rows[0], 'idx': idx, 'pk_field': 'pk_episode'})
750 return episode
751
753 if isinstance(episode, cEpisode):
754 pk = episode['pk_episode']
755 else:
756 pk = int(episode)
757
758 try:
759 gmPG2.run_rw_queries(queries = [{'cmd': u'delete from clin.episode where pk=%(pk)s', 'args': {'pk': pk}}])
760 except gmPG2.dbapi.IntegrityError:
761
762 _log.exception('cannot delete episode')
763 raise gmExceptions.DatabaseObjectInUseError('cannot delete episode, it is in use')
764
766 return cProblem (
767 aPK_obj = {
768 'pk_patient': episode['pk_patient'],
769 'pk_episode': episode['pk_episode'],
770 'pk_health_issue': episode['pk_health_issue']
771 },
772 try_potential_problems = allow_closed
773 )
774
775
776
777 -class cEncounter(gmBusinessDBObject.cBusinessDBObject):
778 """Represents one encounter."""
779 _cmd_fetch_payload = u"select * from clin.v_pat_encounters where pk_encounter = %s"
780 _cmds_store_payload = [
781 u"""update clin.encounter set
782 started = %(started)s,
783 last_affirmed = %(last_affirmed)s,
784 fk_location = %(pk_location)s,
785 fk_type = %(pk_type)s,
786 reason_for_encounter = gm.nullify_empty_string(%(reason_for_encounter)s),
787 assessment_of_encounter = gm.nullify_empty_string(%(assessment_of_encounter)s)
788 where
789 pk = %(pk_encounter)s and
790 xmin = %(xmin_encounter)s""",
791 u"""select xmin_encounter from clin.v_pat_encounters where pk_encounter=%(pk_encounter)s"""
792 ]
793 _updatable_fields = [
794 'started',
795 'last_affirmed',
796 'pk_location',
797 'pk_type',
798 'reason_for_encounter',
799 'assessment_of_encounter'
800 ]
801
803 """Set the enconter as the active one.
804
805 "Setting active" means making sure the encounter
806 row has the youngest "last_affirmed" timestamp of
807 all encounter rows for this patient.
808 """
809 self['last_affirmed'] = gmDateTime.pydt_now_here()
810 self.save()
811
813 """
814 Moves every element currently linked to the current encounter
815 and the source_episode onto target_episode.
816
817 @param source_episode The episode the elements are currently linked to.
818 @type target_episode A cEpisode intance.
819 @param target_episode The episode the elements will be relinked to.
820 @type target_episode A cEpisode intance.
821 """
822 if source_episode['pk_episode'] == target_episode['pk_episode']:
823 return True
824
825 queries = []
826 cmd = u"""
827 UPDATE clin.clin_root_item
828 SET fk_episode = %(trg)s
829 WHERE
830 fk_encounter = %(enc)s AND
831 fk_episode = %(src)s
832 """
833 rows, idx = gmPG2.run_rw_queries(queries = [{
834 'cmd': cmd,
835 'args': {
836 'trg': target_episode['pk_episode'],
837 'enc': self.pk_obj,
838 'src': source_episode['pk_episode']
839 }
840 }])
841 self.refetch_payload()
842 return True
843
845
846 relevant_fields = [
847 'pk_location',
848 'pk_type',
849 'pk_patient',
850 'reason_for_encounter',
851 'assessment_of_encounter'
852 ]
853 for field in relevant_fields:
854 if self._payload[self._idx[field]] != another_object[field]:
855 _log.debug('mismatch on [%s]: "%s" vs. "%s"', field, self._payload[self._idx[field]], another_object[field])
856 return False
857
858 relevant_fields = [
859 'started',
860 'last_affirmed',
861 ]
862 for field in relevant_fields:
863 if self._payload[self._idx[field]] is None:
864 if another_object[field] is None:
865 continue
866 _log.debug('mismatch on [%s]: "%s" vs. "%s"', field, self._payload[self._idx[field]], another_object[field])
867 return False
868
869 if another_object[field] is None:
870 return False
871
872
873 if self._payload[self._idx[field]].strftime('%Y-%m-%d %H:%M') != another_object[field].strftime('%Y-%m-%d %H:%M'):
874 _log.debug('mismatch on [%s]: "%s" vs. "%s"', field, self._payload[self._idx[field]], another_object[field])
875 return False
876
877 return True
878
880 cmd = u"""
881 select exists (
882 select 1 from clin.v_pat_items where pk_patient = %(pat)s and pk_encounter = %(enc)s
883 union all
884 select 1 from blobs.v_doc_med where pk_patient = %(pat)s and pk_encounter = %(enc)s
885 )"""
886 args = {
887 'pat': self._payload[self._idx['pk_patient']],
888 'enc': self.pk_obj
889 }
890 rows, idx = gmPG2.run_ro_queries (
891 queries = [{
892 'cmd': cmd,
893 'args': args
894 }]
895 )
896 return rows[0][0]
897
899 cmd = u"""
900 select exists (
901 select 1 from clin.v_pat_items where pk_patient=%(pat)s and pk_encounter=%(enc)s
902 )"""
903 args = {
904 'pat': self._payload[self._idx['pk_patient']],
905 'enc': self.pk_obj
906 }
907 rows, idx = gmPG2.run_ro_queries (
908 queries = [{
909 'cmd': cmd,
910 'args': args
911 }]
912 )
913 return rows[0][0]
914
916 cmd = u"""
917 select exists (
918 select 1 from blobs.v_doc_med where pk_patient = %(pat)s and pk_encounter = %(enc)s
919 )"""
920 args = {
921 'pat': self._payload[self._idx['pk_patient']],
922 'enc': self.pk_obj
923 }
924 rows, idx = gmPG2.run_ro_queries (
925 queries = [{
926 'cmd': cmd,
927 'args': args
928 }]
929 )
930 return rows[0][0]
931
933
934 if soap_cat is not None:
935 soap_cat = soap_cat.lower()
936
937 if episode is None:
938 epi_part = u'fk_episode is null'
939 else:
940 epi_part = u'fk_episode = %(epi)s'
941
942 cmd = u"""
943 select narrative
944 from clin.clin_narrative
945 where
946 fk_encounter = %%(enc)s
947 and
948 soap_cat = %%(cat)s
949 and
950 %s
951 order by clin_when desc
952 limit 1
953 """ % epi_part
954
955 args = {'enc': self.pk_obj, 'cat': soap_cat, 'epi': episode}
956
957 rows, idx = gmPG2.run_ro_queries (
958 queries = [{
959 'cmd': cmd,
960 'args': args
961 }]
962 )
963 if len(rows) == 0:
964 return None
965
966 return rows[0][0]
967
999
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1119 """Creates a new encounter for a patient.
1120
1121 fk_patient - patient PK
1122 fk_location - encounter location
1123 enc_type - type of encounter
1124
1125 FIXME: we don't deal with location yet
1126 """
1127 if enc_type is None:
1128 enc_type = u'in surgery'
1129
1130 queries = []
1131 try:
1132 enc_type = int(enc_type)
1133 cmd = u"""
1134 insert into clin.encounter (
1135 fk_patient, fk_location, fk_type
1136 ) values (
1137 %s, -1, %s
1138 )"""
1139 except ValueError:
1140 enc_type = enc_type
1141 cmd = u"""
1142 insert into clin.encounter (
1143 fk_patient, fk_location, fk_type
1144 ) values (
1145 %s, -1, coalesce((select pk from clin.encounter_type where description=%s), 0)
1146 )"""
1147 queries.append({'cmd': cmd, 'args': [fk_patient, enc_type]})
1148 queries.append({'cmd': cEncounter._cmd_fetch_payload % u"currval('clin.encounter_pk_seq')"})
1149 rows, idx = gmPG2.run_rw_queries(queries=queries, return_data=True, get_col_idx=True)
1150 encounter = cEncounter(row={'data': rows[0], 'idx': idx, 'pk_field': 'pk_encounter'})
1151
1152 return encounter
1153
1155
1156 rows, idx = gmPG2.run_rw_queries(
1157 queries = [{
1158 'cmd': u"select i18n.upd_tx(%(desc)s, %(l10n_desc)s)",
1159 'args': {'desc': description, 'l10n_desc': l10n_description}
1160 }],
1161 return_data = True
1162 )
1163
1164 success = rows[0][0]
1165 if not success:
1166 _log.warning('updating encounter type [%s] to [%s] failed', description, l10n_description)
1167
1168 return {'description': description, 'l10n_description': l10n_description}
1169
1171 """This will attempt to create a NEW encounter type."""
1172
1173
1174 if description is None:
1175 description = l10n_description
1176
1177 args = {
1178 'desc': description,
1179 'l10n_desc': l10n_description
1180 }
1181
1182 _log.debug('creating encounter type: %s, %s', description, l10n_description)
1183
1184
1185 cmd = u"select description, _(description) from clin.encounter_type where description = %(desc)s"
1186 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}])
1187
1188
1189 if len(rows) > 0:
1190
1191 if (rows[0][0] == description) and (rows[0][1] == l10n_description):
1192 _log.info('encounter type [%s] already exists with the proper translation')
1193 return {'description': description, 'l10n_description': l10n_description}
1194
1195
1196
1197 cmd = u"select exists (select 1 from i18n.translations where orig = %(desc)s and lang = i18n.get_curr_lang())"
1198 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}])
1199
1200
1201 if rows[0][0]:
1202 _log.error('encounter type [%s] already exists but with another translation')
1203 return None
1204
1205
1206 cmd = u"select i18n.upd_tx(%(desc)s, %(l10n_desc)s)"
1207 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
1208 return {'description': description, 'l10n_description': l10n_description}
1209
1210
1211 queries = [
1212 {'cmd': u"insert into clin.encounter_type (description) values (%(desc)s)", 'args': args},
1213 {'cmd': u"select i18n.upd_tx(%(desc)s, %(l10n_desc)s)", 'args': args}
1214 ]
1215 rows, idx = gmPG2.run_rw_queries(queries = queries)
1216
1217 return {'description': description, 'l10n_description': l10n_description}
1218
1220 cmd = u"select _(description) as l10n_description, description from clin.encounter_type"
1221 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}])
1222 return rows
1223
1228
1230 cmd = u"delete from clin.encounter_type where description = %(desc)s"
1231 args = {'desc': description}
1232 try:
1233 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
1234 except gmPG2.dbapi.IntegrityError, e:
1235 if e.pgcode == gmPG2.sql_error_codes.FOREIGN_KEY_VIOLATION:
1236 return False
1237 raise
1238
1239 return True
1240
1241 -class cProblem(gmBusinessDBObject.cBusinessDBObject):
1242 """Represents one problem.
1243
1244 problems are the aggregation of
1245 .clinically_relevant=True issues and
1246 .is_open=True episodes
1247 """
1248 _cmd_fetch_payload = u''
1249 _cmds_store_payload = [u"select 1"]
1250 _updatable_fields = []
1251
1252
1253 - def __init__(self, aPK_obj=None, try_potential_problems=False):
1254 """Initialize.
1255
1256 aPK_obj must contain the keys
1257 pk_patient
1258 pk_episode
1259 pk_health_issue
1260 """
1261 if aPK_obj is None:
1262 raise gmExceptions.ConstructorError, 'cannot instatiate cProblem for PK: [%s]' % (aPK_obj)
1263
1264
1265
1266
1267
1268 where_parts = []
1269 pk = {}
1270 for col_name in aPK_obj.keys():
1271 val = aPK_obj[col_name]
1272 if val is None:
1273 where_parts.append('%s IS NULL' % col_name)
1274 else:
1275 where_parts.append('%s = %%(%s)s' % (col_name, col_name))
1276 pk[col_name] = val
1277
1278
1279 cProblem._cmd_fetch_payload = u"""
1280 SELECT *, False as is_potential_problem
1281 FROM clin.v_problem_list
1282 WHERE %s""" % u' AND '.join(where_parts)
1283
1284 try:
1285 gmBusinessDBObject.cBusinessDBObject.__init__(self, aPK_obj=pk)
1286 return
1287 except gmExceptions.ConstructorError:
1288 _log.exception('problem not found, trying potential problems')
1289 if try_potential_problems is False:
1290 raise
1291
1292
1293 cProblem._cmd_fetch_payload = u"""
1294 SELECT *, True as is_potential_problem
1295 FROM clin.v_potential_problem_list
1296 WHERE %s""" % u' AND '.join(where_parts)
1297 gmBusinessDBObject.cBusinessDBObject.__init__(self, aPK_obj=pk)
1298
1300 """
1301 Retrieve the cEpisode instance equivalent to this problem.
1302 The problem's type attribute must be 'episode'
1303 """
1304 if self._payload[self._idx['type']] != 'episode':
1305 _log.error('cannot convert problem [%s] of type [%s] to episode' % (self._payload[self._idx['problem']], self._payload[self._idx['type']]))
1306 return None
1307 return cEpisode(aPK_obj=self._payload[self._idx['pk_episode']])
1308
1309
1312
1313 diagnostic_certainty_description = property(get_diagnostic_certainty_description, lambda x:x)
1314
1316
1317 _cmd_fetch_payload = u"select * from clin.v_pat_hospital_stays where pk_hospital_stay = %s"
1318 _cmds_store_payload = [
1319 u"""update clin.hospital_stay set
1320 clin_when = %(admission)s,
1321 discharge = %(discharge)s,
1322 narrative = gm.nullify_empty_string(%(hospital)s),
1323 fk_episode = %(pk_episode)s,
1324 fk_encounter = %(pk_encounter)s
1325 where
1326 pk = %(pk_hospital_stay)s and
1327 xmin = %(xmin_hospital_stay)s""",
1328 u"""select xmin_hospital_stay from clin.v_pat_hospital_stays where pk_hospital_stay = %(pk_hospital_stay)s"""
1329 ]
1330 _updatable_fields = [
1331 'admission',
1332 'discharge',
1333 'hospital',
1334 'pk_episode',
1335 'pk_encounter'
1336 ]
1337
1356
1358
1359 queries = [
1360 {
1361 'cmd': u'select * from clin.v_pat_hospital_stays where pk_patient = %(pat)s order by admission',
1362 'args': {'pat': patient}
1363 }
1364 ]
1365
1366 rows, idx = gmPG2.run_ro_queries(queries = queries, get_col_idx = True)
1367
1368 return [ cHospitalStay(row = {'idx': idx, 'data': r, 'pk_field': 'pk_hospital_stay'}) for r in rows ]
1369
1371
1372 queries = [
1373 {
1374 'cmd': u'insert into clin.hospital_stay (fk_encounter, fk_episode) values (%(enc)s, %(epi)s)',
1375 'args': {'enc': encounter, 'epi': episode}
1376 },
1377 {'cmd': u"select currval('clin.hospital_stay_pk_seq')"}
1378 ]
1379
1380 rows, idx = gmPG2.run_rw_queries(queries = queries, return_data = True)
1381
1382 return cHospitalStay(aPK_obj = rows[0][0])
1383
1385 cmd = u'delete from clin.hospital_stay where pk = %(pk)s'
1386 args = {'pk': stay}
1387 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
1388 return True
1389
1438
1451
1476
1482
1483
1484
1485 if __name__ == '__main__':
1486
1487 if len(sys.argv) < 2:
1488 sys.exit()
1489
1490 if sys.argv[1] != 'test':
1491 sys.exit()
1492
1493
1494
1495
1497 print "\nProblem test"
1498 print "------------"
1499 prob = cProblem(aPK_obj={'pk_patient': 12, 'pk_health_issue': 1, 'pk_episode': None})
1500 print prob
1501 fields = prob.get_fields()
1502 for field in fields:
1503 print field, ':', prob[field]
1504 print '\nupdatable:', prob.get_updatable_fields()
1505 epi = prob.get_as_episode()
1506 print '\nas episode:'
1507 if epi is not None:
1508 for field in epi.get_fields():
1509 print ' .%s : %s' % (field, epi[field])
1510
1525
1527 print "\nepisode test"
1528 print "------------"
1529 episode = cEpisode(aPK_obj=1)
1530 print episode
1531 fields = episode.get_fields()
1532 for field in fields:
1533 print field, ':', episode[field]
1534 print "updatable:", episode.get_updatable_fields()
1535 raw_input('ENTER to continue')
1536
1537 old_description = episode['description']
1538 old_enc = cEncounter(aPK_obj = 1)
1539
1540 desc = '1-%s' % episode['description']
1541 print "==> renaming to", desc
1542 successful = episode.rename (
1543 description = desc
1544 )
1545 if not successful:
1546 print "error"
1547 else:
1548 print "success"
1549 for field in fields:
1550 print field, ':', episode[field]
1551
1552 print "episode range:", episode.get_access_range()
1553
1554 raw_input('ENTER to continue')
1555
1556
1558 print "\nencounter test"
1559 print "--------------"
1560 encounter = cEncounter(aPK_obj=1)
1561 print encounter
1562 fields = encounter.get_fields()
1563 for field in fields:
1564 print field, ':', encounter[field]
1565 print "updatable:", encounter.get_updatable_fields()
1566
1571
1581
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597 test_diagnostic_certainty_classification_map()
1598
1599