1 """GNUmed measurements related business objects."""
2
3
4
5 __author__ = "K.Hilbert <Karsten.Hilbert@gmx.net>"
6 __license__ = "GPL"
7
8
9 import types
10 import sys
11 import logging
12 import codecs
13 import decimal
14
15
16 if __name__ == '__main__':
17 sys.path.insert(0, '../../')
18
19 from Gnumed.pycommon import gmDateTime
20 if __name__ == '__main__':
21 from Gnumed.pycommon import gmLog2
22 from Gnumed.pycommon import gmI18N
23 gmDateTime.init()
24 from Gnumed.pycommon import gmExceptions
25 from Gnumed.pycommon import gmBusinessDBObject
26 from Gnumed.pycommon import gmPG2
27 from Gnumed.pycommon import gmTools
28 from Gnumed.pycommon import gmDispatcher
29 from Gnumed.pycommon import gmHooks
30 from Gnumed.business import gmOrganization
31 from Gnumed.business import gmCoding
32
33
34 _log = logging.getLogger('gm.lab')
35
36
40
41 gmDispatcher.connect(_on_test_result_modified, u'test_result_mod_db')
42
43
44 -class cTestOrg(gmBusinessDBObject.cBusinessDBObject):
45 """Represents one test org/lab."""
46 _cmd_fetch_payload = u"""SELECT * FROM clin.v_test_orgs WHERE pk_test_org = %s"""
47 _cmds_store_payload = [
48 u"""UPDATE clin.test_org SET
49 fk_org_unit = %(pk_org_unit)s,
50 contact = gm.nullify_empty_string(%(test_org_contact)s),
51 comment = gm.nullify_empty_string(%(comment)s)
52 WHERE
53 pk = %(pk_test_org)s
54 AND
55 xmin = %(xmin_test_org)s
56 RETURNING
57 xmin AS xmin_test_org
58 """
59 ]
60 _updatable_fields = [
61 u'pk_org_unit',
62 u'test_org_contact',
63 u'comment'
64 ]
65
102
104 args = {'pk': test_org}
105 cmd = u"""
106 DELETE FROM clin.test_org
107 WHERE
108 pk = %(pk)s
109 AND
110 NOT EXISTS (SELECT 1 FROM clin.lab_request WHERE fk_test_org = %(pk)s LIMIT 1)
111 AND
112 NOT EXISTS (SELECT 1 FROM clin.test_type WHERE fk_test_org = %(pk)s LIMIT 1)
113 """
114 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
115
117 cmd = u'SELECT * FROM clin.v_test_orgs ORDER BY %s' % order_by
118 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = True)
119 return [ cTestOrg(row = {'pk_field': 'pk_test_org', 'data': r, 'idx': idx}) for r in rows ]
120
121
122
123
124 _SQL_get_test_panels = u"SELECT * FROM clin.v_test_panels WHERE %s"
125
126 -class cTestPanel(gmBusinessDBObject.cBusinessDBObject):
127 """Represents a grouping/listing of tests into a panel."""
128
129 _cmd_fetch_payload = _SQL_get_test_panels % u"pk_test_panel = %s"
130 _cmds_store_payload = [
131 u"""
132 UPDATE clin.test_panel SET
133 description = gm.nullify_empty_string(%(description)s),
134 comment = gm.nullify_empty_string(%(comment)s),
135 fk_test_types = %(pk_test_types)s
136 WHERE
137 pk = %(pk_test_panel)s
138 AND
139 xmin = %(xmin_test_panel)s
140 RETURNING
141 xmin AS xmin_test_panel
142 """
143 ]
144 _updatable_fields = [
145 u'description',
146 u'comment',
147 u'pk_test_types'
148 ]
149
151 """<pk_code> must be a value from ref.coding_system_root.pk_coding_system (clin.lnk_code2item_root.fk_generic_code)"""
152 cmd = u"INSERT INTO clin.lnk_code2tst_pnl (fk_item, fk_generic_code) values (%(tp)s, %(code)s)"
153 args = {
154 'tp': self._payload[self._idx['pk_test_panel']],
155 'code': pk_code
156 }
157 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
158 return True
159
161 """<pk_code> must be a value from ref.coding_system_root.pk_coding_system (clin.lnk_code2item_root.fk_generic_code)"""
162 cmd = u"DELETE FROM clin.lnk_code2tst_pnl WHERE fk_item = %(tp)s AND fk_generic_code = %(code)s"
163 args = {
164 'tp': self._payload[self._idx['pk_test_panel']],
165 'code': pk_code
166 }
167 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
168 return True
169
170
171
173 if self._payload[self._idx['pk_test_types']] is None:
174 return None
175
176 rows, idx = gmPG2.run_ro_queries (
177 queries = [{
178 'cmd': _SQL_get_test_types % u'pk_test_type IN %(pks)s ORDER BY unified_abbrev',
179 'args': {'pks': tuple(self._payload[self._idx['pk_test_types']])}
180 }],
181 get_col_idx = True
182 )
183 return [ cMeasurementType(row = {'data': r, 'idx': idx, 'pk_field': 'pk_test_type'}) for r in rows ]
184
185 test_types = property(_get_test_types, lambda x:x)
186
188 if len(self._payload[self._idx['pk_generic_codes']]) == 0:
189 return []
190
191 cmd = gmCoding._SQL_get_generic_linked_codes % u'pk_generic_code IN %(pks)s'
192 args = {'pks': tuple(self._payload[self._idx['pk_generic_codes']])}
193 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
194 return [ gmCoding.cGenericLinkedCode(row = {'data': r, 'idx': idx, 'pk_field': 'pk_lnk_code2item'}) for r in rows ]
195
197 queries = []
198
199 if len(self._payload[self._idx['pk_generic_codes']]) > 0:
200 queries.append ({
201 'cmd': u'DELETE FROM clin.lnk_code2tst_pnl WHERE fk_item = %(tp)s AND fk_generic_code IN %(codes)s',
202 'args': {
203 'tp': self._payload[self._idx['pk_test_panel']],
204 'codes': tuple(self._payload[self._idx['pk_generic_codes']])
205 }
206 })
207
208 for pk_code in pk_codes:
209 queries.append ({
210 'cmd': u'INSERT INTO clin.lnk_code2test_panel (fk_item, fk_generic_code) VALUES (%(tp)s, %(pk_code)s)',
211 'args': {
212 'tp': self._payload[self._idx['pk_test_panel']],
213 'pk_code': pk_code
214 }
215 })
216 if len(queries) == 0:
217 return
218
219 rows, idx = gmPG2.run_rw_queries(queries = queries)
220 return
221
222 generic_codes = property(_get_generic_codes, _set_generic_codes)
223
263
265 if order_by is None:
266 order_by = u'true'
267 else:
268 order_by = u'true ORDER BY %s' % order_by
269
270 cmd = _SQL_get_test_panels % order_by
271 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = True)
272 return [ cTestPanel(row = {'data': r, 'idx': idx, 'pk_field': 'pk_test_panel'}) for r in rows ]
273
275
276 args = {u'desc': description.strip()}
277 cmd = u"""
278 INSERT INTO clin.test_panel (description)
279 VALUES (gm.nullify_empty_string(%(desc)s))
280 RETURNING pk
281 """
282 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True, get_col_idx = False)
283
284 return cTestPanel(aPK_obj = rows[0]['pk'])
285
287 args = {'pk': pk}
288 cmd = u"DELETE FROM clin.test_panel WHERE pk = %(pk)s"
289 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
290 return True
291
292
335
336
341
342
347
348
349 _SQL_get_test_types = u"SELECT * FROM clin.v_test_types WHERE %s"
350
352 """Represents one test result type."""
353
354 _cmd_fetch_payload = _SQL_get_test_types % u"pk_test_type = %s"
355
356 _cmds_store_payload = [
357 u"""UPDATE clin.test_type SET
358 abbrev = gm.nullify_empty_string(%(abbrev)s),
359 name = gm.nullify_empty_string(%(name)s),
360 loinc = gm.nullify_empty_string(%(loinc)s),
361 comment = gm.nullify_empty_string(%(comment_type)s),
362 conversion_unit = gm.nullify_empty_string(%(conversion_unit)s),
363 fk_test_org = %(pk_test_org)s,
364 fk_meta_test_type = %(pk_meta_test_type)s
365 WHERE
366 pk = %(pk_test_type)s
367 AND
368 xmin = %(xmin_test_type)s
369 RETURNING
370 xmin AS xmin_test_type"""
371 ]
372
373 _updatable_fields = [
374 'abbrev',
375 'name',
376 'loinc',
377 'comment_type',
378 'conversion_unit',
379 'pk_test_org',
380 'pk_meta_test_type'
381 ]
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
401 cmd = u'SELECT EXISTS(SELECT 1 FROM clin.test_result WHERE fk_type = %(pk_type)s)'
402 args = {'pk_type': self._payload[self._idx['pk_test_type']]}
403 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}])
404 return rows[0][0]
405
406 in_use = property(_get_in_use, lambda x:x)
407
424
426 if self._payload[self._idx['pk_test_panels']] is None:
427 return None
428
429 return [ cTestPanel(aPK_obj = pk) for pk in self._payload[self._idx['pk_test_panels']] ]
430
431 test_panels = property(_get_test_panels, lambda x:x)
432
439
440 meta_test_type = property(get_meta_test_type, lambda x:x)
441
494
495
497 cmd = u'select * from clin.v_test_types %s' % gmTools.coalesce(order_by, u'', u'order by %s')
498 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = True)
499 return [ cMeasurementType(row = {'pk_field': 'pk_test_type', 'data': r, 'idx': idx}) for r in rows ]
500
501
503
504 if (abbrev is None) and (name is None):
505 raise ValueError('must have <abbrev> and/or <name> set')
506
507 where_snippets = []
508
509 if lab is None:
510 where_snippets.append('pk_test_org IS NULL')
511 else:
512 try:
513 int(lab)
514 where_snippets.append('pk_test_org = %(lab)s')
515 except (TypeError, ValueError):
516 where_snippets.append('pk_test_org = (SELECT pk_test_org FROM clin.v_test_orgs WHERE unit = %(lab)s)')
517
518 if abbrev is not None:
519 where_snippets.append('abbrev = %(abbrev)s')
520
521 if name is not None:
522 where_snippets.append('name = %(name)s')
523
524 where_clause = u' and '.join(where_snippets)
525 cmd = u"select * from clin.v_test_types where %s" % where_clause
526 args = {'lab': lab, 'abbrev': abbrev, 'name': name}
527
528 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
529
530 if len(rows) == 0:
531 return None
532
533 tt = cMeasurementType(row = {'pk_field': 'pk_test_type', 'data': rows[0], 'idx': idx})
534 return tt
535
536
538 cmd = u'delete from clin.test_type where pk = %(pk)s'
539 args = {'pk': measurement_type}
540 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
541
542
544 """Create or get test type."""
545
546 ttype = find_measurement_type(lab = lab, abbrev = abbrev, name = name)
547
548 if ttype is not None:
549 return ttype
550
551 _log.debug('creating test type [%s:%s:%s:%s]', lab, abbrev, name, unit)
552
553
554 if unit is None:
555 _log.error('need <unit> to create test type: %s:%s:%s:%s' % (lab, abbrev, name, unit))
556 raise ValueError('need <unit> to create test type')
557
558
559 cols = []
560 val_snippets = []
561 vals = {}
562
563
564 if lab is None:
565 lab = create_test_org()['pk_test_org']
566
567 cols.append('fk_test_org')
568 try:
569 vals['lab'] = int(lab)
570 val_snippets.append('%(lab)s')
571 except:
572 vals['lab'] = lab
573 val_snippets.append('(SELECT pk_test_org FROM clin.v_test_orgs WHERE unit = %(lab)s)')
574
575
576 cols.append('abbrev')
577 val_snippets.append('%(abbrev)s')
578 vals['abbrev'] = abbrev
579
580
581 cols.append('conversion_unit')
582 val_snippets.append('%(unit)s')
583 vals['unit'] = unit
584
585
586 if name is not None:
587 cols.append('name')
588 val_snippets.append('%(name)s')
589 vals['name'] = name
590
591 col_clause = u', '.join(cols)
592 val_clause = u', '.join(val_snippets)
593 queries = [
594 {'cmd': u'insert into clin.test_type (%s) values (%s)' % (col_clause, val_clause), 'args': vals},
595 {'cmd': u"select * from clin.v_test_types where pk_test_type = currval(pg_get_serial_sequence('clin.test_type', 'pk'))"}
596 ]
597 rows, idx = gmPG2.run_rw_queries(queries = queries, get_col_idx = True, return_data = True)
598 ttype = cMeasurementType(row = {'pk_field': 'pk_test_type', 'data': rows[0], 'idx': idx})
599
600 return ttype
601
602
603 -class cTestResult(gmBusinessDBObject.cBusinessDBObject):
604 """Represents one test result."""
605
606 _cmd_fetch_payload = u"select * from clin.v_test_results where pk_test_result = %s"
607
608 _cmds_store_payload = [
609 u"""update clin.test_result set
610 clin_when = %(clin_when)s,
611 narrative = nullif(trim(%(comment)s), ''),
612 val_num = %(val_num)s,
613 val_alpha = nullif(trim(%(val_alpha)s), ''),
614 val_unit = nullif(trim(%(val_unit)s), ''),
615 val_normal_min = %(val_normal_min)s,
616 val_normal_max = %(val_normal_max)s,
617 val_normal_range = nullif(trim(%(val_normal_range)s), ''),
618 val_target_min = %(val_target_min)s,
619 val_target_max = %(val_target_max)s,
620 val_target_range = nullif(trim(%(val_target_range)s), ''),
621 abnormality_indicator = nullif(trim(%(abnormality_indicator)s), ''),
622 norm_ref_group = nullif(trim(%(norm_ref_group)s), ''),
623 note_test_org = nullif(trim(%(note_test_org)s), ''),
624 material = nullif(trim(%(material)s), ''),
625 material_detail = nullif(trim(%(material_detail)s), ''),
626 fk_intended_reviewer = %(pk_intended_reviewer)s,
627 fk_encounter = %(pk_encounter)s,
628 fk_episode = %(pk_episode)s,
629 fk_type = %(pk_test_type)s,
630 fk_request = %(pk_request)s
631 where
632 pk = %(pk_test_result)s and
633 xmin = %(xmin_test_result)s""",
634 u"""select xmin_test_result from clin.v_test_results where pk_test_result = %(pk_test_result)s"""
635 ]
636
637 _updatable_fields = [
638 'clin_when',
639 'comment',
640 'val_num',
641 'val_alpha',
642 'val_unit',
643 'val_normal_min',
644 'val_normal_max',
645 'val_normal_range',
646 'val_target_min',
647 'val_target_max',
648 'val_target_range',
649 'abnormality_indicator',
650 'norm_ref_group',
651 'note_test_org',
652 'material',
653 'material_detail',
654 'pk_intended_reviewer',
655 'pk_encounter',
656 'pk_episode',
657 'pk_test_type',
658 'pk_request'
659 ]
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
967
969
970 cmd = u"""
971 select
972 distinct on (norm_ref_group_str, val_unit, val_normal_min, val_normal_max, val_normal_range, val_target_min, val_target_max, val_target_range)
973 pk_patient,
974 val_unit,
975 val_normal_min, val_normal_max, val_normal_range,
976 val_target_min, val_target_max, val_target_range,
977 norm_ref_group,
978 coalesce(norm_ref_group, '') as norm_ref_group_str
979 from
980 clin.v_test_results
981 where
982 pk_test_type = %(pk_type)s
983 """
984 args = {'pk_type': self._payload[self._idx['pk_test_type']]}
985 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}])
986 return rows
987
989 raise AttributeError('[%s]: reference ranges not settable') % self.__class__.__name__
990
991 reference_ranges = property(_get_reference_ranges, _set_reference_ranges)
992
995
996 test_type = property(_get_test_type, lambda x:x)
997
998 - def set_review(self, technically_abnormal=None, clinically_relevant=None, comment=None, make_me_responsible=False):
999
1000
1001 if self._payload[self._idx['reviewed']]:
1002 self.__change_existing_review (
1003 technically_abnormal = technically_abnormal,
1004 clinically_relevant = clinically_relevant,
1005 comment = comment
1006 )
1007 else:
1008
1009
1010 if technically_abnormal is None:
1011 if clinically_relevant is None:
1012 comment = gmTools.none_if(comment, u'', strip_string = True)
1013 if comment is None:
1014 if make_me_responsible is False:
1015 return True
1016 self.__set_new_review (
1017 technically_abnormal = technically_abnormal,
1018 clinically_relevant = clinically_relevant,
1019 comment = comment
1020 )
1021
1022 if make_me_responsible is True:
1023 cmd = u"SELECT pk FROM dem.staff WHERE db_user = current_user"
1024 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}])
1025 self['pk_intended_reviewer'] = rows[0][0]
1026 self.save_payload()
1027 return
1028
1029 self.refetch_payload()
1030
1031 - def get_adjacent_results(self, desired_earlier_results=1, desired_later_results=1, max_offset=None):
1032
1033 if desired_earlier_results < 1:
1034 raise ValueError('<desired_earlier_results> must be > 0')
1035
1036 if desired_later_results < 1:
1037 raise ValueError('<desired_later_results> must be > 0')
1038
1039 args = {
1040 'pat': self._payload[self._idx['pk_patient']],
1041 'ttyp': self._payload[self._idx['pk_test_type']],
1042 'tloinc': self._payload[self._idx['loinc_tt']],
1043 'mtyp': self._payload[self._idx['pk_meta_test_type']],
1044 'mloinc': self._payload[self._idx['loinc_meta']],
1045 'when': self._payload[self._idx['clin_when']],
1046 'offset': max_offset
1047 }
1048 WHERE = u'((pk_test_type = %(ttyp)s) OR (loinc_tt = %(tloinc)s))'
1049 WHERE_meta = u'((pk_meta_test_type = %(mtyp)s) OR (loinc_meta = %(mloinc)s))'
1050 if max_offset is not None:
1051 WHERE = WHERE + u' AND (clin_when BETWEEN (%(when)s - %(offset)s) AND (%(when)s + %(offset)s))'
1052 WHERE_meta = WHERE_meta + u' AND (clin_when BETWEEN (%(when)s - %(offset)s) AND (%(when)s + %(offset)s))'
1053
1054 SQL = u"""
1055 SELECT * FROM clin.v_test_results
1056 WHERE
1057 pk_patient = %%(pat)s
1058 AND
1059 clin_when %s %%(when)s
1060 AND
1061 %s
1062 ORDER BY clin_when
1063 LIMIT %s"""
1064
1065
1066 earlier_results = []
1067
1068 cmd = SQL % (u'<', WHERE, desired_earlier_results)
1069 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
1070 if len(rows) > 0:
1071 earlier_results.extend([ cTestResult(row = {'pk_field': 'pk_test_result', 'idx': idx, 'data': r}) for r in rows ])
1072
1073 missing_results = desired_earlier_results - len(earlier_results)
1074 if missing_results > 0:
1075 cmd = SQL % (u'<', WHERE_meta, missing_results)
1076 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
1077 if len(rows) > 0:
1078 earlier_results.extend([ cTestResult(row = {'pk_field': 'pk_test_result', 'idx': idx, 'data': r}) for r in rows ])
1079
1080
1081 later_results = []
1082
1083 cmd = SQL % (u'>', WHERE, desired_later_results)
1084 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
1085 if len(rows) > 0:
1086 later_results.extend([ cTestResult(row = {'pk_field': 'pk_test_result', 'idx': idx, 'data': r}) for r in rows ])
1087
1088 missing_results = desired_later_results - len(later_results)
1089 if missing_results > 0:
1090 cmd = SQL % (u'>', WHERE_meta, missing_results)
1091 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
1092 if len(rows) > 0:
1093 later_results.extend([ cTestResult(row = {'pk_field': 'pk_test_result', 'idx': idx, 'data': r}) for r in rows ])
1094
1095 return earlier_results, later_results
1096
1097
1098
1099 - def __set_new_review(self, technically_abnormal=None, clinically_relevant=None, comment=None):
1100 """Add a review to a row.
1101
1102 - if technically abnormal is not provided/None it will be set
1103 to True if the lab's indicator has a meaningful value
1104 - if clinically relevant is not provided/None it is set to
1105 whatever technically abnormal is
1106 """
1107 if technically_abnormal is None:
1108 technically_abnormal = False
1109 if self._payload[self._idx['abnormality_indicator']] is not None:
1110 if self._payload[self._idx['abnormality_indicator']].strip() != u'':
1111 technically_abnormal = True
1112
1113 if clinically_relevant is None:
1114 clinically_relevant = technically_abnormal
1115
1116 cmd = u"""
1117 INSERT INTO clin.reviewed_test_results (
1118 fk_reviewed_row,
1119 is_technically_abnormal,
1120 clinically_relevant,
1121 comment
1122 ) VALUES (
1123 %(pk)s,
1124 %(abnormal)s,
1125 %(relevant)s,
1126 gm.nullify_empty_string(%(cmt)s)
1127 )"""
1128 args = {
1129 'pk': self._payload[self._idx['pk_test_result']],
1130 'abnormal': technically_abnormal,
1131 'relevant': clinically_relevant,
1132 'cmt': comment
1133 }
1134
1135 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
1136
1138 """Change a review on a row.
1139
1140 - if technically abnormal/clinically relevant are
1141 None they are not set
1142 """
1143 args = {
1144 'pk_row': self._payload[self._idx['pk_test_result']],
1145 'abnormal': technically_abnormal,
1146 'relevant': clinically_relevant,
1147 'cmt': comment
1148 }
1149
1150 set_parts = [
1151 u'fk_reviewer = (SELECT pk FROM dem.staff WHERE db_user = current_user)',
1152 u'comment = gm.nullify_empty_string(%(cmt)s)'
1153 ]
1154
1155 if technically_abnormal is not None:
1156 set_parts.append(u'is_technically_abnormal = %(abnormal)s')
1157
1158 if clinically_relevant is not None:
1159 set_parts.append(u'clinically_relevant = %(relevant)s')
1160
1161 cmd = u"""
1162 UPDATE clin.reviewed_test_results SET
1163 %s
1164 WHERE
1165 fk_reviewed_row = %%(pk_row)s
1166 """ % u',\n '.join(set_parts)
1167
1168 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
1169
1170
1171 -def get_test_results(pk_patient=None, encounters=None, episodes=None, order_by=None):
1172
1173 where_parts = []
1174
1175 if pk_patient is not None:
1176 where_parts.append(u'pk_patient = %(pat)s')
1177 args = {'pat': pk_patient}
1178
1179
1180
1181
1182
1183 if encounters is not None:
1184 where_parts.append(u'pk_encounter IN %(encs)s')
1185 args['encs'] = tuple(encounters)
1186
1187 if episodes is not None:
1188 where_parts.append(u'pk_episode IN %(epis)s')
1189 args['epis'] = tuple(episodes)
1190
1191 if order_by is None:
1192 order_by = u''
1193 else:
1194 order_by = u'ORDER BY %s' % order_by
1195
1196 cmd = u"""
1197 SELECT * FROM clin.v_test_results
1198 WHERE %s
1199 %s
1200 """ % (
1201 u' AND '.join(where_parts),
1202 order_by
1203 )
1204 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
1205
1206 tests = [ cTestResult(row = {'pk_field': 'pk_test_result', 'idx': idx, 'data': r}) for r in rows ]
1207 return tests
1208
1209
1211
1212 if None not in [test_type, loinc]:
1213 raise ValueError('either <test_type> or <loinc> must be None')
1214
1215 args = {
1216 'pat': patient,
1217 'ttyp': test_type,
1218 'loinc': loinc,
1219 'ts': timestamp,
1220 'intv': tolerance_interval
1221 }
1222
1223 where_parts = [u'pk_patient = %(pat)s']
1224 if test_type is not None:
1225 where_parts.append(u'pk_test_type = %(ttyp)s')
1226 elif loinc is not None:
1227 where_parts.append(u'((loinc_tt IN %(loinc)s) OR (loinc_meta IN %(loinc)s))')
1228 args['loinc'] = tuple(loinc)
1229
1230 if tolerance_interval is None:
1231 where_parts.append(u'clin_when = %(ts)s')
1232 else:
1233 where_parts.append(u'clin_when between (%(ts)s - %(intv)s::interval) AND (%(ts)s + %(intv)s::interval)')
1234
1235 cmd = u"""
1236 SELECT * FROM clin.v_test_results
1237 WHERE
1238 %s
1239 ORDER BY
1240 abs(extract(epoch from age(clin_when, %%(ts)s)))
1241 LIMIT 1""" % u' AND '.join(where_parts)
1242
1243 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
1244 if len(rows) == 0:
1245 return None
1246
1247 return cTestResult(row = {'pk_field': 'pk_test_result', 'idx': idx, 'data': rows[0]})
1248
1249
1251
1252 if None not in [test_type, loinc]:
1253 raise ValueError('either <test_type> or <loinc> must be None')
1254
1255 if no_of_results < 1:
1256 raise ValueError('<no_of_results> must be > 0')
1257
1258 args = {
1259 'pat': patient,
1260 'ttyp': test_type,
1261 'loinc': loinc
1262 }
1263
1264 where_parts = [u'pk_patient = %(pat)s']
1265 if test_type is not None:
1266 where_parts.append(u'pk_test_type = %(ttyp)s')
1267 elif loinc is not None:
1268 where_parts.append(u'((loinc_tt IN %(loinc)s) OR (loinc_meta IN %(loinc)s))')
1269 args['loinc'] = tuple(loinc)
1270
1271 cmd = u"""
1272 SELECT * FROM clin.v_test_results
1273 WHERE
1274 %s
1275 ORDER BY clin_when DESC
1276 LIMIT %s""" % (
1277 u' AND '.join(where_parts),
1278 no_of_results
1279 )
1280 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
1281 if len(rows) == 0:
1282 return None
1283
1284 if no_of_results == 1:
1285 return cTestResult(row = {'pk_field': 'pk_test_result', 'idx': idx, 'data': rows[0]})
1286
1287 return [ cTestResult(row = {'pk_field': 'pk_test_result', 'idx': idx, 'data': r}) for r in rows ]
1288
1289
1291 try:
1292 pk = int(result)
1293 except (TypeError, AttributeError):
1294 pk = result['pk_test_result']
1295
1296 cmd = u'DELETE FROM clin.test_result WHERE pk = %(pk)s'
1297 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': {'pk': pk}}])
1298
1299
1300 -def create_test_result(encounter=None, episode=None, type=None, intended_reviewer=None, val_num=None, val_alpha=None, unit=None):
1301
1302 cmd1 = u"""
1303 insert into clin.test_result (
1304 fk_encounter,
1305 fk_episode,
1306 fk_type,
1307 fk_intended_reviewer,
1308 val_num,
1309 val_alpha,
1310 val_unit
1311 ) values (
1312 %(enc)s,
1313 %(epi)s,
1314 %(type)s,
1315 %(rev)s,
1316 %(v_num)s,
1317 %(v_alpha)s,
1318 %(unit)s
1319 )"""
1320
1321 cmd2 = u"""
1322 select *
1323 from
1324 clin.v_test_results
1325 where
1326 pk_test_result = currval(pg_get_serial_sequence('clin.test_result', 'pk'))"""
1327
1328 args = {
1329 u'enc': encounter,
1330 u'epi': episode,
1331 u'type': type,
1332 u'rev': intended_reviewer,
1333 u'v_num': val_num,
1334 u'v_alpha': val_alpha,
1335 u'unit': unit
1336 }
1337
1338 rows, idx = gmPG2.run_rw_queries (
1339 queries = [
1340 {'cmd': cmd1, 'args': args},
1341 {'cmd': cmd2}
1342 ],
1343 return_data = True,
1344 get_col_idx = True
1345 )
1346
1347 tr = cTestResult(row = {
1348 'pk_field': 'pk_test_result',
1349 'idx': idx,
1350 'data': rows[0]
1351 })
1352
1353 return tr
1354
1355
1366
1367
1368 -def __tests2latex_minipage(results=None, width=u'1.5cm', show_time=False, show_range=True):
1369
1370 if len(results) == 0:
1371 return u'\\begin{minipage}{%s} \\end{minipage}' % width
1372
1373 lines = []
1374 for t in results:
1375
1376 tmp = u''
1377
1378 if show_time:
1379 tmp += u'{\\tiny (%s)} ' % t['clin_when'].strftime('%H:%M')
1380
1381 tmp += u'%.8s' % t['unified_val']
1382
1383 lines.append(tmp)
1384 tmp = u''
1385
1386 if show_range:
1387 has_range = (
1388 t['unified_target_range'] is not None
1389 or
1390 t['unified_target_min'] is not None
1391 or
1392 t['unified_target_max'] is not None
1393 )
1394 if has_range:
1395 if t['unified_target_range'] is not None:
1396 tmp += u'{\\tiny %s}' % t['unified_target_range']
1397 else:
1398 tmp += u'{\\tiny %s}' % (
1399 gmTools.coalesce(t['unified_target_min'], u'- ', u'%s - '),
1400 gmTools.coalesce(t['unified_target_max'], u'', u'%s')
1401 )
1402 lines.append(tmp)
1403
1404 return u'\\begin{minipage}{%s} \\begin{flushright} %s \\end{flushright} \\end{minipage}' % (width, u' \\\\ '.join(lines))
1405
1406
1408
1409 if len(results) == 0:
1410 return u''
1411
1412 lines = []
1413 for t in results:
1414
1415 tmp = u''
1416
1417 if show_time:
1418 tmp += u'\\tiny %s ' % t['clin_when'].strftime('%H:%M')
1419
1420 tmp += u'\\normalsize %.8s' % t['unified_val']
1421
1422 lines.append(tmp)
1423 tmp = u'\\tiny %s' % gmTools.coalesce(t['val_unit'], u'', u'%s ')
1424
1425 if not show_range:
1426 lines.append(tmp)
1427 continue
1428
1429 has_range = (
1430 t['unified_target_range'] is not None
1431 or
1432 t['unified_target_min'] is not None
1433 or
1434 t['unified_target_max'] is not None
1435 )
1436
1437 if not has_range:
1438 lines.append(tmp)
1439 continue
1440
1441 if t['unified_target_range'] is not None:
1442 tmp += u'[%s]' % t['unified_target_range']
1443 else:
1444 tmp += u'[%s%s]' % (
1445 gmTools.coalesce(t['unified_target_min'], u'--', u'%s--'),
1446 gmTools.coalesce(t['unified_target_max'], u'', u'%s')
1447 )
1448 lines.append(tmp)
1449
1450 return u' \\\\ '.join(lines)
1451
1452
1528
1529
1531
1532 if filename is None:
1533 filename = gmTools.get_unique_filename(prefix = u'gm2gpl-', suffix = '.dat')
1534
1535
1536 series = {}
1537 for r in results:
1538 try:
1539 series[r['unified_name']].append(r)
1540 except KeyError:
1541 series[r['unified_name']] = [r]
1542
1543 gp_data = codecs.open(filename, 'wb', 'utf8')
1544
1545 gp_data.write(u'# %s\n' % _('GNUmed test results export for Gnuplot plotting'))
1546 gp_data.write(u'# -------------------------------------------------------------\n')
1547 gp_data.write(u'# first line of index: test type abbreviation & name\n')
1548 gp_data.write(u'#\n')
1549 gp_data.write(u'# clin_when at full precision\n')
1550 gp_data.write(u'# value\n')
1551 gp_data.write(u'# unit\n')
1552 gp_data.write(u'# unified (target or normal) range: lower bound\n')
1553 gp_data.write(u'# unified (target or normal) range: upper bound\n')
1554 gp_data.write(u'# normal range: lower bound\n')
1555 gp_data.write(u'# normal range: upper bound\n')
1556 gp_data.write(u'# target range: lower bound\n')
1557 gp_data.write(u'# target range: upper bound\n')
1558 gp_data.write(u'# clin_when formatted into string as x-axis tic label\n')
1559 gp_data.write(u'# -------------------------------------------------------------\n')
1560
1561 for test_type in series.keys():
1562 if len(series[test_type]) == 0:
1563 continue
1564
1565 r = series[test_type][0]
1566 title = u'%s (%s)' % (
1567 r['unified_abbrev'],
1568 r['unified_name']
1569 )
1570 gp_data.write(u'\n\n"%s" "%s"\n' % (title, title))
1571
1572 prev_date = None
1573 prev_year = None
1574 for r in series[test_type]:
1575 curr_date = r['clin_when'].strftime('%Y-%m-%d')
1576 if curr_date == prev_date:
1577 gp_data.write(u'\n# %s\n' % _('blank line inserted to allow for discontinued line drawing for same-day values'))
1578 if show_year:
1579 if r['clin_when'].year == prev_year:
1580 when_template = '%b %d %H:%M'
1581 else:
1582 when_template = '%b %d %H:%M (%Y)'
1583 prev_year = r['clin_when'].year
1584 else:
1585 when_template = '%b %d'
1586 gp_data.write (u'%s %s "%s" %s %s %s %s %s %s "%s"\n' % (
1587 r['clin_when'].strftime('%Y-%m-%d_%H:%M'),
1588 r['unified_val'],
1589 gmTools.coalesce(r['val_unit'], u'"<?>"'),
1590 gmTools.coalesce(r['unified_target_min'], u'"<?>"'),
1591 gmTools.coalesce(r['unified_target_max'], u'"<?>"'),
1592 gmTools.coalesce(r['val_normal_min'], u'"<?>"'),
1593 gmTools.coalesce(r['val_normal_max'], u'"<?>"'),
1594 gmTools.coalesce(r['val_target_min'], u'"<?>"'),
1595 gmTools.coalesce(r['val_target_max'], u'"<?>"'),
1596 gmDateTime.pydt_strftime (
1597 r['clin_when'],
1598 format = when_template,
1599 accuracy = gmDateTime.acc_minutes
1600 )
1601 ))
1602 prev_date = curr_date
1603
1604 gp_data.close()
1605
1606 return filename
1607
1608
1609 -class cLabResult(gmBusinessDBObject.cBusinessDBObject):
1610 """Represents one lab result."""
1611
1612 _cmd_fetch_payload = """
1613 select *, xmin_test_result from v_results4lab_req
1614 where pk_result=%s"""
1615 _cmds_lock_rows_for_update = [
1616 """select 1 from test_result where pk=%(pk_result)s and xmin=%(xmin_test_result)s for update"""
1617 ]
1618 _cmds_store_payload = [
1619 """update test_result set
1620 clin_when = %(val_when)s,
1621 narrative = %(progress_note_result)s,
1622 fk_type = %(pk_test_type)s,
1623 val_num = %(val_num)s::numeric,
1624 val_alpha = %(val_alpha)s,
1625 val_unit = %(val_unit)s,
1626 val_normal_min = %(val_normal_min)s,
1627 val_normal_max = %(val_normal_max)s,
1628 val_normal_range = %(val_normal_range)s,
1629 val_target_min = %(val_target_min)s,
1630 val_target_max = %(val_target_max)s,
1631 val_target_range = %(val_target_range)s,
1632 abnormality_indicator = %(abnormal)s,
1633 norm_ref_group = %(ref_group)s,
1634 note_provider = %(note_provider)s,
1635 material = %(material)s,
1636 material_detail = %(material_detail)s
1637 where pk = %(pk_result)s""",
1638 """select xmin_test_result from v_results4lab_req where pk_result=%(pk_result)s"""
1639 ]
1640
1641 _updatable_fields = [
1642 'val_when',
1643 'progress_note_result',
1644 'val_num',
1645 'val_alpha',
1646 'val_unit',
1647 'val_normal_min',
1648 'val_normal_max',
1649 'val_normal_range',
1650 'val_target_min',
1651 'val_target_max',
1652 'val_target_range',
1653 'abnormal',
1654 'ref_group',
1655 'note_provider',
1656 'material',
1657 'material_detail'
1658 ]
1659
1660 - def __init__(self, aPK_obj=None, row=None):
1661 """Instantiate.
1662
1663 aPK_obj as dict:
1664 - patient_id
1665 - when_field (see view definition)
1666 - when
1667 - test_type
1668 - val_num
1669 - val_alpha
1670 - unit
1671 """
1672
1673 if aPK_obj is None:
1674 gmBusinessDBObject.cBusinessDBObject.__init__(self, row=row)
1675 return
1676 pk = aPK_obj
1677
1678 if type(aPK_obj) == types.DictType:
1679
1680 if None in [aPK_obj['patient_id'], aPK_obj['when'], aPK_obj['when_field'], aPK_obj['test_type'], aPK_obj['unit']]:
1681 raise gmExceptions.ConstructorError, 'parameter error: %s' % aPK_obj
1682 if (aPK_obj['val_num'] is None) and (aPK_obj['val_alpha'] is None):
1683 raise gmExceptions.ConstructorError, 'parameter error: val_num and val_alpha cannot both be None'
1684
1685 where_snippets = [
1686 'pk_patient=%(patient_id)s',
1687 'pk_test_type=%(test_type)s',
1688 '%s=%%(when)s' % aPK_obj['when_field'],
1689 'val_unit=%(unit)s'
1690 ]
1691 if aPK_obj['val_num'] is not None:
1692 where_snippets.append('val_num=%(val_num)s::numeric')
1693 if aPK_obj['val_alpha'] is not None:
1694 where_snippets.append('val_alpha=%(val_alpha)s')
1695
1696 where_clause = ' and '.join(where_snippets)
1697 cmd = "select pk_result from v_results4lab_req where %s" % where_clause
1698 data = gmPG.run_ro_query('historica', cmd, None, aPK_obj)
1699 if data is None:
1700 raise gmExceptions.ConstructorError, 'error getting lab result for: %s' % aPK_obj
1701 if len(data) == 0:
1702 raise gmExceptions.NoSuchClinItemError, 'no lab result for: %s' % aPK_obj
1703 pk = data[0][0]
1704
1705 gmBusinessDBObject.cBusinessDBObject.__init__(self, aPK_obj=pk)
1706
1708 cmd = """
1709 select
1710 %s,
1711 vbp.title,
1712 vbp.firstnames,
1713 vbp.lastnames,
1714 vbp.dob
1715 from v_basic_person vbp
1716 where vbp.pk_identity=%%s""" % self._payload[self._idx['pk_patient']]
1717 pat = gmPG.run_ro_query('historica', cmd, None, self._payload[self._idx['pk_patient']])
1718 return pat[0]
1719
1720 -class cLabRequest(gmBusinessDBObject.cBusinessDBObject):
1721 """Represents one lab request."""
1722
1723 _cmd_fetch_payload = """
1724 select *, xmin_lab_request from v_lab_requests
1725 where pk_request=%s"""
1726 _cmds_lock_rows_for_update = [
1727 """select 1 from lab_request where pk=%(pk_request)s and xmin=%(xmin_lab_request)s for update"""
1728 ]
1729 _cmds_store_payload = [
1730 """update lab_request set
1731 request_id=%(request_id)s,
1732 lab_request_id=%(lab_request_id)s,
1733 clin_when=%(sampled_when)s,
1734 lab_rxd_when=%(lab_rxd_when)s,
1735 results_reported_when=%(results_reported_when)s,
1736 request_status=%(request_status)s,
1737 is_pending=%(is_pending)s::bool,
1738 narrative=%(progress_note)s
1739 where pk=%(pk_request)s""",
1740 """select xmin_lab_request from v_lab_requests where pk_request=%(pk_request)s"""
1741 ]
1742 _updatable_fields = [
1743 'request_id',
1744 'lab_request_id',
1745 'sampled_when',
1746 'lab_rxd_when',
1747 'results_reported_when',
1748 'request_status',
1749 'is_pending',
1750 'progress_note'
1751 ]
1752
1753 - def __init__(self, aPK_obj=None, row=None):
1754 """Instantiate lab request.
1755
1756 The aPK_obj can be either a dict with the keys "req_id"
1757 and "lab" or a simple primary key.
1758 """
1759
1760 if aPK_obj is None:
1761 gmBusinessDBObject.cBusinessDBObject.__init__(self, row=row)
1762 return
1763 pk = aPK_obj
1764
1765 if type(aPK_obj) == types.DictType:
1766
1767 try:
1768 aPK_obj['req_id']
1769 aPK_obj['lab']
1770 except:
1771 _log.exception('[%s:??]: faulty <aPK_obj> structure: [%s]' % (self.__class__.__name__, aPK_obj), sys.exc_info())
1772 raise gmExceptions.ConstructorError, '[%s:??]: cannot derive PK from [%s]' % (self.__class__.__name__, aPK_obj)
1773
1774 where_snippets = []
1775 vals = {}
1776 where_snippets.append('request_id=%(req_id)s')
1777 if type(aPK_obj['lab']) == types.IntType:
1778 where_snippets.append('pk_test_org=%(lab)s')
1779 else:
1780 where_snippets.append('lab_name=%(lab)s')
1781 where_clause = ' and '.join(where_snippets)
1782 cmd = "select pk_request from v_lab_requests where %s" % where_clause
1783
1784 data = gmPG.run_ro_query('historica', cmd, None, aPK_obj)
1785 if data is None:
1786 raise gmExceptions.ConstructorError, '[%s:??]: error getting lab request for [%s]' % (self.__class__.__name__, aPK_obj)
1787 if len(data) == 0:
1788 raise gmExceptions.NoSuchClinItemError, '[%s:??]: no lab request for [%s]' % (self.__class__.__name__, aPK_obj)
1789 pk = data[0][0]
1790
1791 gmBusinessDBObject.cBusinessDBObject.__init__(self, aPK_obj=pk)
1792
1794 cmd = """
1795 select vpi.pk_patient, vbp.title, vbp.firstnames, vbp.lastnames, vbp.dob
1796 from v_pat_items vpi, v_basic_person vbp
1797 where
1798 vpi.pk_item=%s
1799 and
1800 vbp.pk_identity=vpi.pk_patient"""
1801 pat = gmPG.run_ro_query('historica', cmd, None, self._payload[self._idx['pk_item']])
1802 if pat is None:
1803 _log.error('cannot get patient for lab request [%s]' % self._payload[self._idx['pk_item']])
1804 return None
1805 if len(pat) == 0:
1806 _log.error('no patient associated with lab request [%s]' % self._payload[self._idx['pk_item']])
1807 return None
1808 return pat[0]
1809
1810
1811
1812 -def create_lab_request(lab=None, req_id=None, pat_id=None, encounter_id=None, episode_id=None):
1813 """Create or get lab request.
1814
1815 returns tuple (status, value):
1816 (True, lab request instance)
1817 (False, error message)
1818 (None, housekeeping_todo primary key)
1819 """
1820 req = None
1821 aPK_obj = {
1822 'lab': lab,
1823 'req_id': req_id
1824 }
1825 try:
1826 req = cLabRequest (aPK_obj)
1827 except gmExceptions.NoSuchClinItemError, msg:
1828 _log.info('%s: will try to create lab request' % str(msg))
1829 except gmExceptions.ConstructorError, msg:
1830 _log.exception(str(msg), sys.exc_info(), verbose=0)
1831 return (False, msg)
1832
1833 if req is not None:
1834 db_pat = req.get_patient()
1835 if db_pat is None:
1836 _log.error('cannot cross-check patient on lab request')
1837 return (None, '')
1838
1839 if pat_id != db_pat[0]:
1840 _log.error('lab request found for [%s:%s] but patient mismatch: expected [%s], in DB [%s]' % (lab, req_id, pat_id, db_pat))
1841 me = '$RCSfile: gmPathLab.py,v $ $Revision: 1.81 $'
1842 to = 'user'
1843 prob = _('The lab request already exists but belongs to a different patient.')
1844 sol = _('Verify which patient this lab request really belongs to.')
1845 ctxt = _('lab [%s], request ID [%s], expected link with patient [%s], currently linked to patient [%s]') % (lab, req_id, pat_id, db_pat)
1846 cat = 'lab'
1847 status, data = gmPG.add_housekeeping_todo(me, to, prob, sol, ctxt, cat)
1848 return (None, data)
1849 return (True, req)
1850
1851 queries = []
1852 if type(lab) is types.IntType:
1853 cmd = "insert into lab_request (fk_encounter, fk_episode, fk_test_org, request_id) values (%s, %s, %s, %s)"
1854 else:
1855 cmd = "insert into lab_request (fk_encounter, fk_episode, fk_test_org, request_id) values (%s, %s, (select pk from test_org where internal_OBSOLETE_name=%s), %s)"
1856 queries.append((cmd, [encounter_id, episode_id, str(lab), req_id]))
1857 cmd = "select currval('lab_request_pk_seq')"
1858 queries.append((cmd, []))
1859
1860 result, err = gmPG.run_commit('historica', queries, True)
1861 if result is None:
1862 return (False, err)
1863 try:
1864 req = cLabRequest(aPK_obj=result[0][0])
1865 except gmExceptions.ConstructorError, msg:
1866 _log.exception(str(msg), sys.exc_info(), verbose=0)
1867 return (False, msg)
1868 return (True, req)
1869
1870 -def create_lab_result(patient_id=None, when_field=None, when=None, test_type=None, val_num=None, val_alpha=None, unit=None, encounter_id=None, request=None):
1871 tres = None
1872 data = {
1873 'patient_id': patient_id,
1874 'when_field': when_field,
1875 'when': when,
1876 'test_type': test_type,
1877 'val_num': val_num,
1878 'val_alpha': val_alpha,
1879 'unit': unit
1880 }
1881 try:
1882 tres = cLabResult(aPK_obj=data)
1883
1884 _log.error('will not overwrite existing test result')
1885 _log.debug(str(tres))
1886 return (None, tres)
1887 except gmExceptions.NoSuchClinItemError:
1888 _log.debug('test result not found - as expected, will create it')
1889 except gmExceptions.ConstructorError, msg:
1890 _log.exception(str(msg), sys.exc_info(), verbose=0)
1891 return (False, msg)
1892 if request is None:
1893 return (False, _('need lab request when inserting lab result'))
1894
1895 if encounter_id is None:
1896 encounter_id = request['pk_encounter']
1897 queries = []
1898 cmd = "insert into test_result (fk_encounter, fk_episode, fk_type, val_num, val_alpha, val_unit) values (%s, %s, %s, %s, %s, %s)"
1899 queries.append((cmd, [encounter_id, request['pk_episode'], test_type, val_num, val_alpha, unit]))
1900 cmd = "insert into lnk_result2lab_req (fk_result, fk_request) values ((select currval('test_result_pk_seq')), %s)"
1901 queries.append((cmd, [request['pk_request']]))
1902 cmd = "select currval('test_result_pk_seq')"
1903 queries.append((cmd, []))
1904
1905 result, err = gmPG.run_commit('historica', queries, True)
1906 if result is None:
1907 return (False, err)
1908 try:
1909 tres = cLabResult(aPK_obj=result[0][0])
1910 except gmExceptions.ConstructorError, msg:
1911 _log.exception(str(msg), sys.exc_info(), verbose=0)
1912 return (False, msg)
1913 return (True, tres)
1914
1916
1917 if limit < 1:
1918 limit = 1
1919
1920 lim = limit + 1
1921 cmd = """
1922 select pk_result
1923 from v_results4lab_req
1924 where reviewed is false
1925 order by pk_patient
1926 limit %s""" % lim
1927 rows = gmPG.run_ro_query('historica', cmd)
1928 if rows is None:
1929 _log.error('error retrieving unreviewed lab results')
1930 return (None, _('error retrieving unreviewed lab results'))
1931 if len(rows) == 0:
1932 return (False, [])
1933
1934 if len(rows) == lim:
1935 more_avail = True
1936
1937 del rows[limit]
1938 else:
1939 more_avail = False
1940 results = []
1941 for row in rows:
1942 try:
1943 results.append(cLabResult(aPK_obj=row[0]))
1944 except gmExceptions.ConstructorError:
1945 _log.exception('skipping unreviewed lab result [%s]' % row[0], sys.exc_info(), verbose=0)
1946 return (more_avail, results)
1947
1949 lim = limit + 1
1950 cmd = "select pk from lab_request where is_pending is true limit %s" % lim
1951 rows = gmPG.run_ro_query('historica', cmd)
1952 if rows is None:
1953 _log.error('error retrieving pending lab requests')
1954 return (None, None)
1955 if len(rows) == 0:
1956 return (False, [])
1957 results = []
1958
1959 if len(rows) == lim:
1960 too_many = True
1961
1962 del rows[limit]
1963 else:
1964 too_many = False
1965 requests = []
1966 for row in rows:
1967 try:
1968 requests.append(cLabRequest(aPK_obj=row[0]))
1969 except gmExceptions.ConstructorError:
1970 _log.exception('skipping pending lab request [%s]' % row[0], sys.exc_info(), verbose=0)
1971 return (too_many, requests)
1972
1974 """Get logically next request ID for given lab.
1975
1976 - incrementor_func:
1977 - if not supplied the next ID is guessed
1978 - if supplied it is applied to the most recently used ID
1979 """
1980 if type(lab) == types.IntType:
1981 lab_snippet = 'vlr.fk_test_org=%s'
1982 else:
1983 lab_snippet = 'vlr.lab_name=%s'
1984 lab = str(lab)
1985 cmd = """
1986 select request_id
1987 from lab_request lr0
1988 where lr0.clin_when = (
1989 select max(vlr.sampled_when)
1990 from v_lab_requests vlr
1991 where %s
1992 )""" % lab_snippet
1993 rows = gmPG.run_ro_query('historica', cmd, None, lab)
1994 if rows is None:
1995 _log.warning('error getting most recently used request ID for lab [%s]' % lab)
1996 return ''
1997 if len(rows) == 0:
1998 return ''
1999 most_recent = rows[0][0]
2000
2001 if incrementor_func is not None:
2002 try:
2003 next = incrementor_func(most_recent)
2004 except TypeError:
2005 _log.error('cannot call incrementor function [%s]' % str(incrementor_func))
2006 return most_recent
2007 return next
2008
2009 for pos in range(len(most_recent)):
2010 header = most_recent[:pos]
2011 trailer = most_recent[pos:]
2012 try:
2013 return '%s%s' % (header, str(int(trailer) + 1))
2014 except ValueError:
2015 header = most_recent[:-1]
2016 trailer = most_recent[-1:]
2017 return '%s%s' % (header, chr(ord(trailer) + 1))
2018
2020 """Calculate BMI.
2021
2022 mass: kg
2023 height: cm
2024 age: not yet used
2025
2026 returns:
2027 (True/False, data)
2028 True: data = (bmi, lower_normal, upper_normal)
2029 False: data = error message
2030 """
2031 converted, mass = gmTools.input2decimal(mass)
2032 if not converted:
2033 return False, u'mass: cannot convert <%s> to Decimal' % mass
2034
2035 converted, height = gmTools.input2decimal(height)
2036 if not converted:
2037 return False, u'height: cannot convert <%s> to Decimal' % height
2038
2039 approx_surface = (height / decimal.Decimal(100))**2
2040 bmi = mass / approx_surface
2041
2042 print mass, height, '->', approx_surface, '->', bmi
2043
2044 lower_normal_mass = 20.0 * approx_surface
2045 upper_normal_mass = 25.0 * approx_surface
2046
2047 return True, (bmi, lower_normal_mass, upper_normal_mass)
2048
2049
2050
2051 if __name__ == '__main__':
2052
2053 if len(sys.argv) < 2:
2054 sys.exit()
2055
2056 if sys.argv[1] != 'test':
2057 sys.exit()
2058
2059 import time
2060
2061 gmI18N.activate_locale()
2062 gmI18N.install_domain()
2063
2064
2066 tr = create_test_result (
2067 encounter = 1,
2068 episode = 1,
2069 type = 1,
2070 intended_reviewer = 1,
2071 val_num = '12',
2072 val_alpha=None,
2073 unit = 'mg/dl'
2074 )
2075 print tr
2076 return tr
2077
2081
2086
2088 print "test_result()"
2089
2090 data = {
2091 'patient_id': 12,
2092 'when_field': 'val_when',
2093 'when': '2000-09-17 18:23:00+02',
2094 'test_type': 9,
2095 'val_num': 17.3,
2096 'val_alpha': None,
2097 'unit': 'mg/l'
2098 }
2099 lab_result = cLabResult(aPK_obj=data)
2100 print lab_result
2101 fields = lab_result.get_fields()
2102 for field in fields:
2103 print field, ':', lab_result[field]
2104 print "updatable:", lab_result.get_updatable_fields()
2105 print time.time()
2106 print lab_result.get_patient()
2107 print time.time()
2108
2110 print "test_request()"
2111 try:
2112
2113
2114 data = {
2115 'req_id': 'EML#SC937-0176-CEC#11',
2116 'lab': 'Enterprise Main Lab'
2117 }
2118 lab_req = cLabRequest(aPK_obj=data)
2119 except gmExceptions.ConstructorError, msg:
2120 print "no such lab request:", msg
2121 return
2122 print lab_req
2123 fields = lab_req.get_fields()
2124 for field in fields:
2125 print field, ':', lab_req[field]
2126 print "updatable:", lab_req.get_updatable_fields()
2127 print time.time()
2128 print lab_req.get_patient()
2129 print time.time()
2130
2135
2140
2148
2153
2158
2167
2169 done, data = calculate_bmi(mass = sys.argv[2], height = sys.argv[3])
2170 bmi, low, high = data
2171
2172 print "BMI:", bmi
2173 print "low:", low, "kg"
2174 print "hi :", high, "kg"
2175
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195 test_test_panel()
2196
2197
2198