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
301
306
311
312
313 _SQL_get_test_types = u"SELECT * FROM clin.v_test_types WHERE %s"
314
316 """Represents one test result type."""
317
318 _cmd_fetch_payload = _SQL_get_test_types % u"pk_test_type = %s"
319
320 _cmds_store_payload = [
321 u"""UPDATE clin.test_type SET
322 abbrev = gm.nullify_empty_string(%(abbrev)s),
323 name = gm.nullify_empty_string(%(name)s),
324 loinc = gm.nullify_empty_string(%(loinc)s),
325 comment = gm.nullify_empty_string(%(comment_type)s),
326 conversion_unit = gm.nullify_empty_string(%(conversion_unit)s),
327 fk_test_org = %(pk_test_org)s,
328 fk_meta_test_type = %(pk_meta_test_type)s
329 WHERE
330 pk = %(pk_test_type)s
331 AND
332 xmin = %(xmin_test_type)s
333 RETURNING
334 xmin AS xmin_test_type"""
335 ]
336
337 _updatable_fields = [
338 'abbrev',
339 'name',
340 'loinc',
341 'comment_type',
342 'conversion_unit',
343 'pk_test_org',
344 'pk_meta_test_type'
345 ]
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
363 cmd = u'SELECT EXISTS(SELECT 1 FROM clin.test_result WHERE fk_type = %(pk_type)s)'
364 args = {'pk_type': self._payload[self._idx['pk_test_type']]}
365 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}])
366 return rows[0][0]
367
368 in_use = property(_get_in_use, lambda x:x)
369
386
388 if self._payload[self._idx['pk_test_panels']] is None:
389 return None
390
391 return [ cTestPanel(aPK_obj = pk) for pk in self._payload[self._idx['pk_test_panels']] ]
392
393 test_panels = property(_get_test_panels, lambda x:x)
394
447
448
450 cmd = u'select * from clin.v_test_types %s' % gmTools.coalesce(order_by, u'', u'order by %s')
451 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = True)
452 return [ cMeasurementType(row = {'pk_field': 'pk_test_type', 'data': r, 'idx': idx}) for r in rows ]
453
455
456 if (abbrev is None) and (name is None):
457 raise ValueError('must have <abbrev> and/or <name> set')
458
459 where_snippets = []
460
461 if lab is None:
462 where_snippets.append('pk_test_org IS NULL')
463 else:
464 try:
465 int(lab)
466 where_snippets.append('pk_test_org = %(lab)s')
467 except (TypeError, ValueError):
468 where_snippets.append('pk_test_org = (SELECT pk_test_org FROM clin.v_test_orgs WHERE unit = %(lab)s)')
469
470 if abbrev is not None:
471 where_snippets.append('abbrev = %(abbrev)s')
472
473 if name is not None:
474 where_snippets.append('name = %(name)s')
475
476 where_clause = u' and '.join(where_snippets)
477 cmd = u"select * from clin.v_test_types where %s" % where_clause
478 args = {'lab': lab, 'abbrev': abbrev, 'name': name}
479
480 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
481
482 if len(rows) == 0:
483 return None
484
485 tt = cMeasurementType(row = {'pk_field': 'pk_test_type', 'data': rows[0], 'idx': idx})
486 return tt
487
489 cmd = u'delete from clin.test_type where pk = %(pk)s'
490 args = {'pk': measurement_type}
491 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
492
494 """Create or get test type."""
495
496 ttype = find_measurement_type(lab = lab, abbrev = abbrev, name = name)
497
498 if ttype is not None:
499 return ttype
500
501 _log.debug('creating test type [%s:%s:%s:%s]', lab, abbrev, name, unit)
502
503
504 if unit is None:
505 _log.error('need <unit> to create test type: %s:%s:%s:%s' % (lab, abbrev, name, unit))
506 raise ValueError('need <unit> to create test type')
507
508
509 cols = []
510 val_snippets = []
511 vals = {}
512
513
514 if lab is None:
515 lab = create_test_org()['pk_test_org']
516
517 cols.append('fk_test_org')
518 try:
519 vals['lab'] = int(lab)
520 val_snippets.append('%(lab)s')
521 except:
522 vals['lab'] = lab
523 val_snippets.append('(SELECT pk_test_org FROM clin.v_test_orgs WHERE unit = %(lab)s)')
524
525
526 cols.append('abbrev')
527 val_snippets.append('%(abbrev)s')
528 vals['abbrev'] = abbrev
529
530
531 cols.append('conversion_unit')
532 val_snippets.append('%(unit)s')
533 vals['unit'] = unit
534
535
536 if name is not None:
537 cols.append('name')
538 val_snippets.append('%(name)s')
539 vals['name'] = name
540
541 col_clause = u', '.join(cols)
542 val_clause = u', '.join(val_snippets)
543 queries = [
544 {'cmd': u'insert into clin.test_type (%s) values (%s)' % (col_clause, val_clause), 'args': vals},
545 {'cmd': u"select * from clin.v_test_types where pk_test_type = currval(pg_get_serial_sequence('clin.test_type', 'pk'))"}
546 ]
547 rows, idx = gmPG2.run_rw_queries(queries = queries, get_col_idx = True, return_data = True)
548 ttype = cMeasurementType(row = {'pk_field': 'pk_test_type', 'data': rows[0], 'idx': idx})
549
550 return ttype
551
552
553 -class cTestResult(gmBusinessDBObject.cBusinessDBObject):
554 """Represents one test result."""
555
556 _cmd_fetch_payload = u"select * from clin.v_test_results where pk_test_result = %s"
557
558 _cmds_store_payload = [
559 u"""update clin.test_result set
560 clin_when = %(clin_when)s,
561 narrative = nullif(trim(%(comment)s), ''),
562 val_num = %(val_num)s,
563 val_alpha = nullif(trim(%(val_alpha)s), ''),
564 val_unit = nullif(trim(%(val_unit)s), ''),
565 val_normal_min = %(val_normal_min)s,
566 val_normal_max = %(val_normal_max)s,
567 val_normal_range = nullif(trim(%(val_normal_range)s), ''),
568 val_target_min = %(val_target_min)s,
569 val_target_max = %(val_target_max)s,
570 val_target_range = nullif(trim(%(val_target_range)s), ''),
571 abnormality_indicator = nullif(trim(%(abnormality_indicator)s), ''),
572 norm_ref_group = nullif(trim(%(norm_ref_group)s), ''),
573 note_test_org = nullif(trim(%(note_test_org)s), ''),
574 material = nullif(trim(%(material)s), ''),
575 material_detail = nullif(trim(%(material_detail)s), ''),
576 fk_intended_reviewer = %(pk_intended_reviewer)s,
577 fk_encounter = %(pk_encounter)s,
578 fk_episode = %(pk_episode)s,
579 fk_type = %(pk_test_type)s,
580 fk_request = %(pk_request)s
581 where
582 pk = %(pk_test_result)s and
583 xmin = %(xmin_test_result)s""",
584 u"""select xmin_test_result from clin.v_test_results where pk_test_result = %(pk_test_result)s"""
585 ]
586
587 _updatable_fields = [
588 'clin_when',
589 'comment',
590 'val_num',
591 'val_alpha',
592 'val_unit',
593 'val_normal_min',
594 'val_normal_max',
595 'val_normal_range',
596 'val_target_min',
597 'val_target_max',
598 'val_target_range',
599 'abnormality_indicator',
600 'norm_ref_group',
601 'note_test_org',
602 'material',
603 'material_detail',
604 'pk_intended_reviewer',
605 'pk_encounter',
606 'pk_episode',
607 'pk_test_type',
608 'pk_request'
609 ]
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
917
919
920 cmd = u"""
921 select
922 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)
923 pk_patient,
924 val_unit,
925 val_normal_min, val_normal_max, val_normal_range,
926 val_target_min, val_target_max, val_target_range,
927 norm_ref_group,
928 coalesce(norm_ref_group, '') as norm_ref_group_str
929 from
930 clin.v_test_results
931 where
932 pk_test_type = %(pk_type)s
933 """
934 args = {'pk_type': self._payload[self._idx['pk_test_type']]}
935 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}])
936 return rows
937
939 raise AttributeError('[%s]: reference ranges not settable') % self.__class__.__name__
940
941 reference_ranges = property(_get_reference_ranges, _set_reference_ranges)
942
945
946 test_type = property(_get_test_type, lambda x:x)
947
948 - def set_review(self, technically_abnormal=None, clinically_relevant=None, comment=None, make_me_responsible=False):
949
950
951 if self._payload[self._idx['reviewed']]:
952 self.__change_existing_review (
953 technically_abnormal = technically_abnormal,
954 clinically_relevant = clinically_relevant,
955 comment = comment
956 )
957 else:
958
959
960 if technically_abnormal is None:
961 if clinically_relevant is None:
962 comment = gmTools.none_if(comment, u'', strip_string = True)
963 if comment is None:
964 if make_me_responsible is False:
965 return True
966 self.__set_new_review (
967 technically_abnormal = technically_abnormal,
968 clinically_relevant = clinically_relevant,
969 comment = comment
970 )
971
972 if make_me_responsible is True:
973 cmd = u"SELECT pk FROM dem.staff WHERE db_user = current_user"
974 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}])
975 self['pk_intended_reviewer'] = rows[0][0]
976 self.save_payload()
977 return
978
979 self.refetch_payload()
980
981 - def get_adjacent_results(self, desired_earlier_results=1, desired_later_results=1, max_offset=None):
982
983 if desired_earlier_results < 1:
984 raise ValueError('<desired_earlier_results> must be > 0')
985
986 if desired_later_results < 1:
987 raise ValueError('<desired_later_results> must be > 0')
988
989 args = {
990 'pat': self._payload[self._idx['pk_patient']],
991 'ttyp': self._payload[self._idx['pk_test_type']],
992 'tloinc': self._payload[self._idx['loinc_tt']],
993 'mtyp': self._payload[self._idx['pk_meta_test_type']],
994 'mloinc': self._payload[self._idx['loinc_meta']],
995 'when': self._payload[self._idx['clin_when']],
996 'offset': max_offset
997 }
998 WHERE = u'((pk_test_type = %(ttyp)s) OR (loinc_tt = %(tloinc)s))'
999 WHERE_meta = u'((pk_meta_test_type = %(mtyp)s) OR (loinc_meta = %(mloinc)s))'
1000 if max_offset is not None:
1001 WHERE = WHERE + u' AND (clin_when BETWEEN (%(when)s - %(offset)s) AND (%(when)s + %(offset)s))'
1002 WHERE_meta = WHERE_meta + u' AND (clin_when BETWEEN (%(when)s - %(offset)s) AND (%(when)s + %(offset)s))'
1003
1004 SQL = u"""
1005 SELECT * FROM clin.v_test_results
1006 WHERE
1007 pk_patient = %%(pat)s
1008 AND
1009 clin_when %s %%(when)s
1010 AND
1011 %s
1012 ORDER BY clin_when
1013 LIMIT %s"""
1014
1015
1016 earlier_results = []
1017
1018 cmd = SQL % (u'<', WHERE, desired_earlier_results)
1019 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
1020 if len(rows) > 0:
1021 earlier_results.extend([ cTestResult(row = {'pk_field': 'pk_test_result', 'idx': idx, 'data': r}) for r in rows ])
1022
1023 missing_results = desired_earlier_results - len(earlier_results)
1024 if missing_results > 0:
1025 cmd = SQL % (u'<', WHERE_meta, missing_results)
1026 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
1027 if len(rows) > 0:
1028 earlier_results.extend([ cTestResult(row = {'pk_field': 'pk_test_result', 'idx': idx, 'data': r}) for r in rows ])
1029
1030
1031 later_results = []
1032
1033 cmd = SQL % (u'>', WHERE, desired_later_results)
1034 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
1035 if len(rows) > 0:
1036 later_results.extend([ cTestResult(row = {'pk_field': 'pk_test_result', 'idx': idx, 'data': r}) for r in rows ])
1037
1038 missing_results = desired_later_results - len(later_results)
1039 if missing_results > 0:
1040 cmd = SQL % (u'>', WHERE_meta, missing_results)
1041 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
1042 if len(rows) > 0:
1043 later_results.extend([ cTestResult(row = {'pk_field': 'pk_test_result', 'idx': idx, 'data': r}) for r in rows ])
1044
1045 return earlier_results, later_results
1046
1047
1048
1049 - def __set_new_review(self, technically_abnormal=None, clinically_relevant=None, comment=None):
1050 """Add a review to a row.
1051
1052 - if technically abnormal is not provided/None it will be set
1053 to True if the lab's indicator has a meaningful value
1054 - if clinically relevant is not provided/None it is set to
1055 whatever technically abnormal is
1056 """
1057 if technically_abnormal is None:
1058 technically_abnormal = False
1059 if self._payload[self._idx['abnormality_indicator']] is not None:
1060 if self._payload[self._idx['abnormality_indicator']].strip() != u'':
1061 technically_abnormal = True
1062
1063 if clinically_relevant is None:
1064 clinically_relevant = technically_abnormal
1065
1066 cmd = u"""
1067 INSERT INTO clin.reviewed_test_results (
1068 fk_reviewed_row,
1069 is_technically_abnormal,
1070 clinically_relevant,
1071 comment
1072 ) VALUES (
1073 %(pk)s,
1074 %(abnormal)s,
1075 %(relevant)s,
1076 gm.nullify_empty_string(%(cmt)s)
1077 )"""
1078 args = {
1079 'pk': self._payload[self._idx['pk_test_result']],
1080 'abnormal': technically_abnormal,
1081 'relevant': clinically_relevant,
1082 'cmt': comment
1083 }
1084
1085 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
1086
1088 """Change a review on a row.
1089
1090 - if technically abnormal/clinically relevant are
1091 None they are not set
1092 """
1093 args = {
1094 'pk_row': self._payload[self._idx['pk_test_result']],
1095 'abnormal': technically_abnormal,
1096 'relevant': clinically_relevant,
1097 'cmt': comment
1098 }
1099
1100 set_parts = [
1101 u'fk_reviewer = (SELECT pk FROM dem.staff WHERE db_user = current_user)',
1102 u'comment = gm.nullify_empty_string(%(cmt)s)'
1103 ]
1104
1105 if technically_abnormal is not None:
1106 set_parts.append(u'is_technically_abnormal = %(abnormal)s')
1107
1108 if clinically_relevant is not None:
1109 set_parts.append(u'clinically_relevant = %(relevant)s')
1110
1111 cmd = u"""
1112 UPDATE clin.reviewed_test_results SET
1113 %s
1114 WHERE
1115 fk_reviewed_row = %%(pk_row)s
1116 """ % u',\n '.join(set_parts)
1117
1118 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
1119
1120
1121 -def get_test_results(pk_patient=None, encounters=None, episodes=None, order_by=None):
1122
1123 where_parts = []
1124
1125 if pk_patient is not None:
1126 where_parts.append(u'pk_patient = %(pat)s')
1127 args = {'pat': pk_patient}
1128
1129
1130
1131
1132
1133 if encounters is not None:
1134 where_parts.append(u'pk_encounter IN %(encs)s')
1135 args['encs'] = tuple(encounters)
1136
1137 if episodes is not None:
1138 where_parts.append(u'pk_episode IN %(epis)s')
1139 args['epis'] = tuple(episodes)
1140
1141 if order_by is None:
1142 order_by = u''
1143 else:
1144 order_by = u'ORDER BY %s' % order_by
1145
1146 cmd = u"""
1147 SELECT * FROM clin.v_test_results
1148 WHERE %s
1149 %s
1150 """ % (
1151 u' AND '.join(where_parts),
1152 order_by
1153 )
1154 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
1155
1156 tests = [ cTestResult(row = {'pk_field': 'pk_test_result', 'idx': idx, 'data': r}) for r in rows ]
1157 return tests
1158
1159
1161
1162 if None not in [test_type, loinc]:
1163 raise ValueError('either <test_type> or <loinc> must be None')
1164
1165 args = {
1166 'pat': patient,
1167 'ttyp': test_type,
1168 'loinc': loinc,
1169 'ts': timestamp,
1170 'intv': tolerance_interval
1171 }
1172
1173 where_parts = [u'pk_patient = %(pat)s']
1174 if test_type is not None:
1175 where_parts.append(u'pk_test_type = %(ttyp)s')
1176 elif loinc is not None:
1177 where_parts.append(u'((loinc_tt IN %(loinc)s) OR (loinc_meta IN %(loinc)s))')
1178 args['loinc'] = tuple(loinc)
1179
1180 if tolerance_interval is None:
1181 where_parts.append(u'clin_when = %(ts)s')
1182 else:
1183 where_parts.append(u'clin_when between (%(ts)s - %(intv)s::interval) AND (%(ts)s + %(intv)s::interval)')
1184
1185 cmd = u"""
1186 SELECT * FROM clin.v_test_results
1187 WHERE
1188 %s
1189 ORDER BY
1190 abs(extract(epoch from age(clin_when, %%(ts)s)))
1191 LIMIT 1""" % u' AND '.join(where_parts)
1192
1193 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
1194 if len(rows) == 0:
1195 return None
1196
1197 return cTestResult(row = {'pk_field': 'pk_test_result', 'idx': idx, 'data': rows[0]})
1198
1199
1201
1202 if None not in [test_type, loinc]:
1203 raise ValueError('either <test_type> or <loinc> must be None')
1204
1205 if no_of_results < 1:
1206 raise ValueError('<no_of_results> must be > 0')
1207
1208 args = {
1209 'pat': patient,
1210 'ttyp': test_type,
1211 'loinc': loinc
1212 }
1213
1214 where_parts = [u'pk_patient = %(pat)s']
1215 if test_type is not None:
1216 where_parts.append(u'pk_test_type = %(ttyp)s')
1217 elif loinc is not None:
1218 where_parts.append(u'((loinc_tt IN %(loinc)s) OR (loinc_meta IN %(loinc)s))')
1219 args['loinc'] = tuple(loinc)
1220
1221 cmd = u"""
1222 SELECT * FROM clin.v_test_results
1223 WHERE
1224 %s
1225 ORDER BY clin_when DESC
1226 LIMIT %s""" % (
1227 u' AND '.join(where_parts),
1228 no_of_results
1229 )
1230 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
1231 if len(rows) == 0:
1232 return None
1233
1234 if no_of_results == 1:
1235 return cTestResult(row = {'pk_field': 'pk_test_result', 'idx': idx, 'data': rows[0]})
1236
1237 return [ cTestResult(row = {'pk_field': 'pk_test_result', 'idx': idx, 'data': r}) for r in rows ]
1238
1239
1241 try:
1242 pk = int(result)
1243 except (TypeError, AttributeError):
1244 pk = result['pk_test_result']
1245
1246 cmd = u'DELETE FROM clin.test_result WHERE pk = %(pk)s'
1247 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': {'pk': pk}}])
1248
1249
1250 -def create_test_result(encounter=None, episode=None, type=None, intended_reviewer=None, val_num=None, val_alpha=None, unit=None):
1251
1252 cmd1 = u"""
1253 insert into clin.test_result (
1254 fk_encounter,
1255 fk_episode,
1256 fk_type,
1257 fk_intended_reviewer,
1258 val_num,
1259 val_alpha,
1260 val_unit
1261 ) values (
1262 %(enc)s,
1263 %(epi)s,
1264 %(type)s,
1265 %(rev)s,
1266 %(v_num)s,
1267 %(v_alpha)s,
1268 %(unit)s
1269 )"""
1270
1271 cmd2 = u"""
1272 select *
1273 from
1274 clin.v_test_results
1275 where
1276 pk_test_result = currval(pg_get_serial_sequence('clin.test_result', 'pk'))"""
1277
1278 args = {
1279 u'enc': encounter,
1280 u'epi': episode,
1281 u'type': type,
1282 u'rev': intended_reviewer,
1283 u'v_num': val_num,
1284 u'v_alpha': val_alpha,
1285 u'unit': unit
1286 }
1287
1288 rows, idx = gmPG2.run_rw_queries (
1289 queries = [
1290 {'cmd': cmd1, 'args': args},
1291 {'cmd': cmd2}
1292 ],
1293 return_data = True,
1294 get_col_idx = True
1295 )
1296
1297 tr = cTestResult(row = {
1298 'pk_field': 'pk_test_result',
1299 'idx': idx,
1300 'data': rows[0]
1301 })
1302
1303 return tr
1304
1305
1316
1317
1318 -def __tests2latex_minipage(results=None, width=u'1.5cm', show_time=False, show_range=True):
1319
1320 if len(results) == 0:
1321 return u'\\begin{minipage}{%s} \\end{minipage}' % width
1322
1323 lines = []
1324 for t in results:
1325
1326 tmp = u''
1327
1328 if show_time:
1329 tmp += u'{\\tiny (%s)} ' % t['clin_when'].strftime('%H:%M')
1330
1331 tmp += u'%.8s' % t['unified_val']
1332
1333 lines.append(tmp)
1334 tmp = u''
1335
1336 if show_range:
1337 has_range = (
1338 t['unified_target_range'] is not None
1339 or
1340 t['unified_target_min'] is not None
1341 or
1342 t['unified_target_max'] is not None
1343 )
1344 if has_range:
1345 if t['unified_target_range'] is not None:
1346 tmp += u'{\\tiny %s}' % t['unified_target_range']
1347 else:
1348 tmp += u'{\\tiny %s}' % (
1349 gmTools.coalesce(t['unified_target_min'], u'- ', u'%s - '),
1350 gmTools.coalesce(t['unified_target_max'], u'', u'%s')
1351 )
1352 lines.append(tmp)
1353
1354 return u'\\begin{minipage}{%s} \\begin{flushright} %s \\end{flushright} \\end{minipage}' % (width, u' \\\\ '.join(lines))
1355
1356
1358
1359 if len(results) == 0:
1360 return u''
1361
1362 lines = []
1363 for t in results:
1364
1365 tmp = u''
1366
1367 if show_time:
1368 tmp += u'\\tiny %s ' % t['clin_when'].strftime('%H:%M')
1369
1370 tmp += u'\\normalsize %.8s' % t['unified_val']
1371
1372 lines.append(tmp)
1373 tmp = u'\\tiny %s' % gmTools.coalesce(t['val_unit'], u'', u'%s ')
1374
1375 if not show_range:
1376 lines.append(tmp)
1377 continue
1378
1379 has_range = (
1380 t['unified_target_range'] is not None
1381 or
1382 t['unified_target_min'] is not None
1383 or
1384 t['unified_target_max'] is not None
1385 )
1386
1387 if not has_range:
1388 lines.append(tmp)
1389 continue
1390
1391 if t['unified_target_range'] is not None:
1392 tmp += u'[%s]' % t['unified_target_range']
1393 else:
1394 tmp += u'[%s%s]' % (
1395 gmTools.coalesce(t['unified_target_min'], u'--', u'%s--'),
1396 gmTools.coalesce(t['unified_target_max'], u'', u'%s')
1397 )
1398 lines.append(tmp)
1399
1400 return u' \\\\ '.join(lines)
1401
1402
1478
1479
1481
1482 if filename is None:
1483 filename = gmTools.get_unique_filename(prefix = u'gm2gpl-', suffix = '.dat')
1484
1485
1486 series = {}
1487 for r in results:
1488 try:
1489 series[r['unified_name']].append(r)
1490 except KeyError:
1491 series[r['unified_name']] = [r]
1492
1493 gp_data = codecs.open(filename, 'wb', 'utf8')
1494
1495 gp_data.write(u'# %s\n' % _('GNUmed test results export for Gnuplot plotting'))
1496 gp_data.write(u'# -------------------------------------------------------------\n')
1497 gp_data.write(u'# first line of index: test type abbreviation & name\n')
1498 gp_data.write(u'#\n')
1499 gp_data.write(u'# clin_when at full precision\n')
1500 gp_data.write(u'# value\n')
1501 gp_data.write(u'# unit\n')
1502 gp_data.write(u'# unified (target or normal) range: lower bound\n')
1503 gp_data.write(u'# unified (target or normal) range: upper bound\n')
1504 gp_data.write(u'# normal range: lower bound\n')
1505 gp_data.write(u'# normal range: upper bound\n')
1506 gp_data.write(u'# target range: lower bound\n')
1507 gp_data.write(u'# target range: upper bound\n')
1508 gp_data.write(u'# clin_when formatted into string as x-axis tic label\n')
1509 gp_data.write(u'# -------------------------------------------------------------\n')
1510
1511 for test_type in series.keys():
1512 if len(series[test_type]) == 0:
1513 continue
1514
1515 r = series[test_type][0]
1516 title = u'%s (%s)' % (
1517 r['unified_abbrev'],
1518 r['unified_name']
1519 )
1520 gp_data.write(u'\n\n"%s" "%s"\n' % (title, title))
1521
1522 prev_date = None
1523 prev_year = None
1524 for r in series[test_type]:
1525 curr_date = r['clin_when'].strftime('%Y-%m-%d')
1526 if curr_date == prev_date:
1527 gp_data.write(u'\n# %s\n' % _('blank line inserted to allow for discontinued line drawing for same-day values'))
1528 if show_year:
1529 if r['clin_when'].year == prev_year:
1530 when_template = '%b %d %H:%M'
1531 else:
1532 when_template = '%b %d %H:%M (%Y)'
1533 prev_year = r['clin_when'].year
1534 else:
1535 when_template = '%b %d'
1536 gp_data.write (u'%s %s "%s" %s %s %s %s %s %s "%s"\n' % (
1537 r['clin_when'].strftime('%Y-%m-%d_%H:%M'),
1538 r['unified_val'],
1539 gmTools.coalesce(r['val_unit'], u'"<?>"'),
1540 gmTools.coalesce(r['unified_target_min'], u'"<?>"'),
1541 gmTools.coalesce(r['unified_target_max'], u'"<?>"'),
1542 gmTools.coalesce(r['val_normal_min'], u'"<?>"'),
1543 gmTools.coalesce(r['val_normal_max'], u'"<?>"'),
1544 gmTools.coalesce(r['val_target_min'], u'"<?>"'),
1545 gmTools.coalesce(r['val_target_max'], u'"<?>"'),
1546 gmDateTime.pydt_strftime (
1547 r['clin_when'],
1548 format = when_template,
1549 accuracy = gmDateTime.acc_minutes
1550 )
1551 ))
1552 prev_date = curr_date
1553
1554 gp_data.close()
1555
1556 return filename
1557
1558
1559 -class cLabResult(gmBusinessDBObject.cBusinessDBObject):
1560 """Represents one lab result."""
1561
1562 _cmd_fetch_payload = """
1563 select *, xmin_test_result from v_results4lab_req
1564 where pk_result=%s"""
1565 _cmds_lock_rows_for_update = [
1566 """select 1 from test_result where pk=%(pk_result)s and xmin=%(xmin_test_result)s for update"""
1567 ]
1568 _cmds_store_payload = [
1569 """update test_result set
1570 clin_when = %(val_when)s,
1571 narrative = %(progress_note_result)s,
1572 fk_type = %(pk_test_type)s,
1573 val_num = %(val_num)s::numeric,
1574 val_alpha = %(val_alpha)s,
1575 val_unit = %(val_unit)s,
1576 val_normal_min = %(val_normal_min)s,
1577 val_normal_max = %(val_normal_max)s,
1578 val_normal_range = %(val_normal_range)s,
1579 val_target_min = %(val_target_min)s,
1580 val_target_max = %(val_target_max)s,
1581 val_target_range = %(val_target_range)s,
1582 abnormality_indicator = %(abnormal)s,
1583 norm_ref_group = %(ref_group)s,
1584 note_provider = %(note_provider)s,
1585 material = %(material)s,
1586 material_detail = %(material_detail)s
1587 where pk = %(pk_result)s""",
1588 """select xmin_test_result from v_results4lab_req where pk_result=%(pk_result)s"""
1589 ]
1590
1591 _updatable_fields = [
1592 'val_when',
1593 'progress_note_result',
1594 'val_num',
1595 'val_alpha',
1596 'val_unit',
1597 'val_normal_min',
1598 'val_normal_max',
1599 'val_normal_range',
1600 'val_target_min',
1601 'val_target_max',
1602 'val_target_range',
1603 'abnormal',
1604 'ref_group',
1605 'note_provider',
1606 'material',
1607 'material_detail'
1608 ]
1609
1610 - def __init__(self, aPK_obj=None, row=None):
1611 """Instantiate.
1612
1613 aPK_obj as dict:
1614 - patient_id
1615 - when_field (see view definition)
1616 - when
1617 - test_type
1618 - val_num
1619 - val_alpha
1620 - unit
1621 """
1622
1623 if aPK_obj is None:
1624 gmBusinessDBObject.cBusinessDBObject.__init__(self, row=row)
1625 return
1626 pk = aPK_obj
1627
1628 if type(aPK_obj) == types.DictType:
1629
1630 if None in [aPK_obj['patient_id'], aPK_obj['when'], aPK_obj['when_field'], aPK_obj['test_type'], aPK_obj['unit']]:
1631 raise gmExceptions.ConstructorError, 'parameter error: %s' % aPK_obj
1632 if (aPK_obj['val_num'] is None) and (aPK_obj['val_alpha'] is None):
1633 raise gmExceptions.ConstructorError, 'parameter error: val_num and val_alpha cannot both be None'
1634
1635 where_snippets = [
1636 'pk_patient=%(patient_id)s',
1637 'pk_test_type=%(test_type)s',
1638 '%s=%%(when)s' % aPK_obj['when_field'],
1639 'val_unit=%(unit)s'
1640 ]
1641 if aPK_obj['val_num'] is not None:
1642 where_snippets.append('val_num=%(val_num)s::numeric')
1643 if aPK_obj['val_alpha'] is not None:
1644 where_snippets.append('val_alpha=%(val_alpha)s')
1645
1646 where_clause = ' and '.join(where_snippets)
1647 cmd = "select pk_result from v_results4lab_req where %s" % where_clause
1648 data = gmPG.run_ro_query('historica', cmd, None, aPK_obj)
1649 if data is None:
1650 raise gmExceptions.ConstructorError, 'error getting lab result for: %s' % aPK_obj
1651 if len(data) == 0:
1652 raise gmExceptions.NoSuchClinItemError, 'no lab result for: %s' % aPK_obj
1653 pk = data[0][0]
1654
1655 gmBusinessDBObject.cBusinessDBObject.__init__(self, aPK_obj=pk)
1656
1658 cmd = """
1659 select
1660 %s,
1661 vbp.title,
1662 vbp.firstnames,
1663 vbp.lastnames,
1664 vbp.dob
1665 from v_basic_person vbp
1666 where vbp.pk_identity=%%s""" % self._payload[self._idx['pk_patient']]
1667 pat = gmPG.run_ro_query('historica', cmd, None, self._payload[self._idx['pk_patient']])
1668 return pat[0]
1669
1670 -class cLabRequest(gmBusinessDBObject.cBusinessDBObject):
1671 """Represents one lab request."""
1672
1673 _cmd_fetch_payload = """
1674 select *, xmin_lab_request from v_lab_requests
1675 where pk_request=%s"""
1676 _cmds_lock_rows_for_update = [
1677 """select 1 from lab_request where pk=%(pk_request)s and xmin=%(xmin_lab_request)s for update"""
1678 ]
1679 _cmds_store_payload = [
1680 """update lab_request set
1681 request_id=%(request_id)s,
1682 lab_request_id=%(lab_request_id)s,
1683 clin_when=%(sampled_when)s,
1684 lab_rxd_when=%(lab_rxd_when)s,
1685 results_reported_when=%(results_reported_when)s,
1686 request_status=%(request_status)s,
1687 is_pending=%(is_pending)s::bool,
1688 narrative=%(progress_note)s
1689 where pk=%(pk_request)s""",
1690 """select xmin_lab_request from v_lab_requests where pk_request=%(pk_request)s"""
1691 ]
1692 _updatable_fields = [
1693 'request_id',
1694 'lab_request_id',
1695 'sampled_when',
1696 'lab_rxd_when',
1697 'results_reported_when',
1698 'request_status',
1699 'is_pending',
1700 'progress_note'
1701 ]
1702
1703 - def __init__(self, aPK_obj=None, row=None):
1704 """Instantiate lab request.
1705
1706 The aPK_obj can be either a dict with the keys "req_id"
1707 and "lab" or a simple primary key.
1708 """
1709
1710 if aPK_obj is None:
1711 gmBusinessDBObject.cBusinessDBObject.__init__(self, row=row)
1712 return
1713 pk = aPK_obj
1714
1715 if type(aPK_obj) == types.DictType:
1716
1717 try:
1718 aPK_obj['req_id']
1719 aPK_obj['lab']
1720 except:
1721 _log.exception('[%s:??]: faulty <aPK_obj> structure: [%s]' % (self.__class__.__name__, aPK_obj), sys.exc_info())
1722 raise gmExceptions.ConstructorError, '[%s:??]: cannot derive PK from [%s]' % (self.__class__.__name__, aPK_obj)
1723
1724 where_snippets = []
1725 vals = {}
1726 where_snippets.append('request_id=%(req_id)s')
1727 if type(aPK_obj['lab']) == types.IntType:
1728 where_snippets.append('pk_test_org=%(lab)s')
1729 else:
1730 where_snippets.append('lab_name=%(lab)s')
1731 where_clause = ' and '.join(where_snippets)
1732 cmd = "select pk_request from v_lab_requests where %s" % where_clause
1733
1734 data = gmPG.run_ro_query('historica', cmd, None, aPK_obj)
1735 if data is None:
1736 raise gmExceptions.ConstructorError, '[%s:??]: error getting lab request for [%s]' % (self.__class__.__name__, aPK_obj)
1737 if len(data) == 0:
1738 raise gmExceptions.NoSuchClinItemError, '[%s:??]: no lab request for [%s]' % (self.__class__.__name__, aPK_obj)
1739 pk = data[0][0]
1740
1741 gmBusinessDBObject.cBusinessDBObject.__init__(self, aPK_obj=pk)
1742
1744 cmd = """
1745 select vpi.pk_patient, vbp.title, vbp.firstnames, vbp.lastnames, vbp.dob
1746 from v_pat_items vpi, v_basic_person vbp
1747 where
1748 vpi.pk_item=%s
1749 and
1750 vbp.pk_identity=vpi.pk_patient"""
1751 pat = gmPG.run_ro_query('historica', cmd, None, self._payload[self._idx['pk_item']])
1752 if pat is None:
1753 _log.error('cannot get patient for lab request [%s]' % self._payload[self._idx['pk_item']])
1754 return None
1755 if len(pat) == 0:
1756 _log.error('no patient associated with lab request [%s]' % self._payload[self._idx['pk_item']])
1757 return None
1758 return pat[0]
1759
1760
1761
1762 -def create_lab_request(lab=None, req_id=None, pat_id=None, encounter_id=None, episode_id=None):
1763 """Create or get lab request.
1764
1765 returns tuple (status, value):
1766 (True, lab request instance)
1767 (False, error message)
1768 (None, housekeeping_todo primary key)
1769 """
1770 req = None
1771 aPK_obj = {
1772 'lab': lab,
1773 'req_id': req_id
1774 }
1775 try:
1776 req = cLabRequest (aPK_obj)
1777 except gmExceptions.NoSuchClinItemError, msg:
1778 _log.info('%s: will try to create lab request' % str(msg))
1779 except gmExceptions.ConstructorError, msg:
1780 _log.exception(str(msg), sys.exc_info(), verbose=0)
1781 return (False, msg)
1782
1783 if req is not None:
1784 db_pat = req.get_patient()
1785 if db_pat is None:
1786 _log.error('cannot cross-check patient on lab request')
1787 return (None, '')
1788
1789 if pat_id != db_pat[0]:
1790 _log.error('lab request found for [%s:%s] but patient mismatch: expected [%s], in DB [%s]' % (lab, req_id, pat_id, db_pat))
1791 me = '$RCSfile: gmPathLab.py,v $ $Revision: 1.81 $'
1792 to = 'user'
1793 prob = _('The lab request already exists but belongs to a different patient.')
1794 sol = _('Verify which patient this lab request really belongs to.')
1795 ctxt = _('lab [%s], request ID [%s], expected link with patient [%s], currently linked to patient [%s]') % (lab, req_id, pat_id, db_pat)
1796 cat = 'lab'
1797 status, data = gmPG.add_housekeeping_todo(me, to, prob, sol, ctxt, cat)
1798 return (None, data)
1799 return (True, req)
1800
1801 queries = []
1802 if type(lab) is types.IntType:
1803 cmd = "insert into lab_request (fk_encounter, fk_episode, fk_test_org, request_id) values (%s, %s, %s, %s)"
1804 else:
1805 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)"
1806 queries.append((cmd, [encounter_id, episode_id, str(lab), req_id]))
1807 cmd = "select currval('lab_request_pk_seq')"
1808 queries.append((cmd, []))
1809
1810 result, err = gmPG.run_commit('historica', queries, True)
1811 if result is None:
1812 return (False, err)
1813 try:
1814 req = cLabRequest(aPK_obj=result[0][0])
1815 except gmExceptions.ConstructorError, msg:
1816 _log.exception(str(msg), sys.exc_info(), verbose=0)
1817 return (False, msg)
1818 return (True, req)
1819
1820 -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):
1821 tres = None
1822 data = {
1823 'patient_id': patient_id,
1824 'when_field': when_field,
1825 'when': when,
1826 'test_type': test_type,
1827 'val_num': val_num,
1828 'val_alpha': val_alpha,
1829 'unit': unit
1830 }
1831 try:
1832 tres = cLabResult(aPK_obj=data)
1833
1834 _log.error('will not overwrite existing test result')
1835 _log.debug(str(tres))
1836 return (None, tres)
1837 except gmExceptions.NoSuchClinItemError:
1838 _log.debug('test result not found - as expected, will create it')
1839 except gmExceptions.ConstructorError, msg:
1840 _log.exception(str(msg), sys.exc_info(), verbose=0)
1841 return (False, msg)
1842 if request is None:
1843 return (False, _('need lab request when inserting lab result'))
1844
1845 if encounter_id is None:
1846 encounter_id = request['pk_encounter']
1847 queries = []
1848 cmd = "insert into test_result (fk_encounter, fk_episode, fk_type, val_num, val_alpha, val_unit) values (%s, %s, %s, %s, %s, %s)"
1849 queries.append((cmd, [encounter_id, request['pk_episode'], test_type, val_num, val_alpha, unit]))
1850 cmd = "insert into lnk_result2lab_req (fk_result, fk_request) values ((select currval('test_result_pk_seq')), %s)"
1851 queries.append((cmd, [request['pk_request']]))
1852 cmd = "select currval('test_result_pk_seq')"
1853 queries.append((cmd, []))
1854
1855 result, err = gmPG.run_commit('historica', queries, True)
1856 if result is None:
1857 return (False, err)
1858 try:
1859 tres = cLabResult(aPK_obj=result[0][0])
1860 except gmExceptions.ConstructorError, msg:
1861 _log.exception(str(msg), sys.exc_info(), verbose=0)
1862 return (False, msg)
1863 return (True, tres)
1864
1866
1867 if limit < 1:
1868 limit = 1
1869
1870 lim = limit + 1
1871 cmd = """
1872 select pk_result
1873 from v_results4lab_req
1874 where reviewed is false
1875 order by pk_patient
1876 limit %s""" % lim
1877 rows = gmPG.run_ro_query('historica', cmd)
1878 if rows is None:
1879 _log.error('error retrieving unreviewed lab results')
1880 return (None, _('error retrieving unreviewed lab results'))
1881 if len(rows) == 0:
1882 return (False, [])
1883
1884 if len(rows) == lim:
1885 more_avail = True
1886
1887 del rows[limit]
1888 else:
1889 more_avail = False
1890 results = []
1891 for row in rows:
1892 try:
1893 results.append(cLabResult(aPK_obj=row[0]))
1894 except gmExceptions.ConstructorError:
1895 _log.exception('skipping unreviewed lab result [%s]' % row[0], sys.exc_info(), verbose=0)
1896 return (more_avail, results)
1897
1899 lim = limit + 1
1900 cmd = "select pk from lab_request where is_pending is true limit %s" % lim
1901 rows = gmPG.run_ro_query('historica', cmd)
1902 if rows is None:
1903 _log.error('error retrieving pending lab requests')
1904 return (None, None)
1905 if len(rows) == 0:
1906 return (False, [])
1907 results = []
1908
1909 if len(rows) == lim:
1910 too_many = True
1911
1912 del rows[limit]
1913 else:
1914 too_many = False
1915 requests = []
1916 for row in rows:
1917 try:
1918 requests.append(cLabRequest(aPK_obj=row[0]))
1919 except gmExceptions.ConstructorError:
1920 _log.exception('skipping pending lab request [%s]' % row[0], sys.exc_info(), verbose=0)
1921 return (too_many, requests)
1922
1924 """Get logically next request ID for given lab.
1925
1926 - incrementor_func:
1927 - if not supplied the next ID is guessed
1928 - if supplied it is applied to the most recently used ID
1929 """
1930 if type(lab) == types.IntType:
1931 lab_snippet = 'vlr.fk_test_org=%s'
1932 else:
1933 lab_snippet = 'vlr.lab_name=%s'
1934 lab = str(lab)
1935 cmd = """
1936 select request_id
1937 from lab_request lr0
1938 where lr0.clin_when = (
1939 select max(vlr.sampled_when)
1940 from v_lab_requests vlr
1941 where %s
1942 )""" % lab_snippet
1943 rows = gmPG.run_ro_query('historica', cmd, None, lab)
1944 if rows is None:
1945 _log.warning('error getting most recently used request ID for lab [%s]' % lab)
1946 return ''
1947 if len(rows) == 0:
1948 return ''
1949 most_recent = rows[0][0]
1950
1951 if incrementor_func is not None:
1952 try:
1953 next = incrementor_func(most_recent)
1954 except TypeError:
1955 _log.error('cannot call incrementor function [%s]' % str(incrementor_func))
1956 return most_recent
1957 return next
1958
1959 for pos in range(len(most_recent)):
1960 header = most_recent[:pos]
1961 trailer = most_recent[pos:]
1962 try:
1963 return '%s%s' % (header, str(int(trailer) + 1))
1964 except ValueError:
1965 header = most_recent[:-1]
1966 trailer = most_recent[-1:]
1967 return '%s%s' % (header, chr(ord(trailer) + 1))
1968
1970 """Calculate BMI.
1971
1972 mass: kg
1973 height: cm
1974 age: not yet used
1975
1976 returns:
1977 (True/False, data)
1978 True: data = (bmi, lower_normal, upper_normal)
1979 False: data = error message
1980 """
1981 converted, mass = gmTools.input2decimal(mass)
1982 if not converted:
1983 return False, u'mass: cannot convert <%s> to Decimal' % mass
1984
1985 converted, height = gmTools.input2decimal(height)
1986 if not converted:
1987 return False, u'height: cannot convert <%s> to Decimal' % height
1988
1989 approx_surface = (height / decimal.Decimal(100))**2
1990 bmi = mass / approx_surface
1991
1992 print mass, height, '->', approx_surface, '->', bmi
1993
1994 lower_normal_mass = 20.0 * approx_surface
1995 upper_normal_mass = 25.0 * approx_surface
1996
1997 return True, (bmi, lower_normal_mass, upper_normal_mass)
1998
1999
2000
2001 if __name__ == '__main__':
2002
2003 if len(sys.argv) < 2:
2004 sys.exit()
2005
2006 if sys.argv[1] != 'test':
2007 sys.exit()
2008
2009 import time
2010
2011 gmI18N.activate_locale()
2012 gmI18N.install_domain()
2013
2014
2016 tr = create_test_result (
2017 encounter = 1,
2018 episode = 1,
2019 type = 1,
2020 intended_reviewer = 1,
2021 val_num = '12',
2022 val_alpha=None,
2023 unit = 'mg/dl'
2024 )
2025 print tr
2026 return tr
2027
2031
2036
2038 print "test_result()"
2039
2040 data = {
2041 'patient_id': 12,
2042 'when_field': 'val_when',
2043 'when': '2000-09-17 18:23:00+02',
2044 'test_type': 9,
2045 'val_num': 17.3,
2046 'val_alpha': None,
2047 'unit': 'mg/l'
2048 }
2049 lab_result = cLabResult(aPK_obj=data)
2050 print lab_result
2051 fields = lab_result.get_fields()
2052 for field in fields:
2053 print field, ':', lab_result[field]
2054 print "updatable:", lab_result.get_updatable_fields()
2055 print time.time()
2056 print lab_result.get_patient()
2057 print time.time()
2058
2060 print "test_request()"
2061 try:
2062
2063
2064 data = {
2065 'req_id': 'EML#SC937-0176-CEC#11',
2066 'lab': 'Enterprise Main Lab'
2067 }
2068 lab_req = cLabRequest(aPK_obj=data)
2069 except gmExceptions.ConstructorError, msg:
2070 print "no such lab request:", msg
2071 return
2072 print lab_req
2073 fields = lab_req.get_fields()
2074 for field in fields:
2075 print field, ':', lab_req[field]
2076 print "updatable:", lab_req.get_updatable_fields()
2077 print time.time()
2078 print lab_req.get_patient()
2079 print time.time()
2080
2085
2090
2098
2103
2108
2117
2119 done, data = calculate_bmi(mass = sys.argv[2], height = sys.argv[3])
2120 bmi, low, high = data
2121
2122 print "BMI:", bmi
2123 print "low:", low, "kg"
2124 print "hi :", high, "kg"
2125
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145 test_test_panel()
2146
2147
2148