1 """GNUmed measurements related business objects."""
2
3
4
5 __version__ = "$Revision: 1.79 $"
6 __author__ = "K.Hilbert <Karsten.Hilbert@gmx.net>"
7 __license__ = "GPL"
8
9
10 import types, sys, logging
11
12
13 if __name__ == '__main__':
14 sys.path.insert(0, '../../')
15 from Gnumed.pycommon import gmLog2, gmDateTime, gmI18N
16 gmDateTime.init()
17 gmI18N.activate_locale()
18 from Gnumed.pycommon import gmExceptions, gmBusinessDBObject, gmPG2, gmTools
19
20
21 _log = logging.getLogger('gm.lab')
22 _log.info(__version__)
23
24
25
26
35
40
45
47 """Represents one unified test type."""
48
49
50 _cmd_fetch_payload = u"""select * from clin.v_unified_test_types where pk_test_type = %s"""
51
52 _cmds_store_payload = []
53
54 _updatable_fields = []
55
57 cmd = u"""
58 SELECT pk_test_result, clin_when
59 FROM clin.v_test_results
60 WHERE pk_patient = %(pat)s
61 ORDER BY clin_when DESC
62 limit 1
63 """
64 args = {'pat': pk_patient}
65 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
66 if len(rows) == 0:
67 return None
68 return cTestResult(aPK_obj = rows[0]['pk_test_result'])
69
71 """Represents one test result type."""
72
73 _cmd_fetch_payload = u"""select * from clin.v_test_types where pk_test_type = %s"""
74
75 _cmds_store_payload = [
76 u"""update clin.test_type set
77 abbrev = %(abbrev)s,
78 name = %(name)s,
79 loinc = gm.nullify_empty_string(%(loinc)s),
80 code = gm.nullify_empty_string(%(code)s),
81 coding_system = gm.nullify_empty_string(%(coding_system)s),
82 comment = gm.nullify_empty_string(%(comment_type)s),
83 conversion_unit = gm.nullify_empty_string(%(conversion_unit)s),
84 fk_test_org = %(pk_test_org)s
85 where pk = %(pk_test_type)s""",
86 u"""select xmin_test_type from clin.v_test_types where pk_test_type = %(pk_test_type)s"""
87 ]
88
89 _updatable_fields = [
90 'abbrev',
91 'name',
92 'loinc',
93 'code',
94 'coding_system',
95 'comment_type',
96 'conversion_unit',
97 'pk_test_org'
98 ]
99
114
116 cmd = u'select exists(select 1 from clin.test_result where fk_type = %(pk_type)s)'
117 args = {'pk_type': self._payload[self._idx['pk_test_type']]}
118 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}])
119 return rows[0][0]
120
121 in_use = property(_get_in_use, lambda x:x)
122
124 cmd = u'select * from clin.v_test_types %s' % gmTools.coalesce(order_by, u'', u'order by %s')
125 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = True)
126 return [ cMeasurementType(row = {'pk_field': 'pk_test_type', 'data': r, 'idx': idx}) for r in rows ]
127
129
130 if (abbrev is None) and (name is None):
131 raise ArgumentError('must have <abbrev> and/or <name> set')
132
133 where_snippets = []
134
135 if lab is None:
136 where_snippets.append('pk_test_org is null')
137 else:
138 try:
139 int(lab)
140 where_snippets.append('pk_test_org = %(lab)s')
141 except (TypeError, ValueError):
142 where_snippets.append('pk_test_org = (select pk from clin.test_org where internal_name = %(lab)s)')
143
144 if abbrev is not None:
145 where_snippets.append('abbrev = %(abbrev)s')
146
147 if name is not None:
148 where_snippets.append('name = %(name)s')
149
150 where_clause = u' and '.join(where_snippets)
151 cmd = u"select * from clin.v_test_types where %s" % where_clause
152 args = {'lab': lab, 'abbrev': abbrev, 'name': name}
153
154 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
155
156 if len(rows) == 0:
157 return None
158
159 tt = cMeasurementType(row = {'pk_field': 'pk_test_type', 'data': rows[0], 'idx': idx})
160 return tt
161
163 cmd = u'delete from clin.test_type where pk = %(pk)s'
164 args = {'pk': measurement_type}
165 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
166
168 """Create or get test type."""
169
170 ttype = find_measurement_type(lab = lab, abbrev = abbrev, name = name)
171
172 if ttype is not None:
173 return ttype
174
175 _log.debug('creating test type [%s:%s:%s:%s]', lab, abbrev, name, unit)
176
177
178 if unit is None:
179 _log.error('need <unit> to create test type: %s:%s:%s:%s' % (lab, abbrev, name, unit))
180 raise ValueError('need <unit> to create test type')
181
182
183 cols = []
184 val_snippets = []
185 vals = {}
186
187
188 if lab is None:
189 lab = create_measurement_org()
190
191 cols.append('fk_test_org')
192 try:
193 vals['lab'] = int(lab)
194 val_snippets.append('%(lab)s')
195 except:
196 vals['lab'] = lab
197 val_snippets.append('(select pk from clin.test_org where internal_name = %(lab)s)')
198
199
200 cols.append('abbrev')
201 val_snippets.append('%(abbrev)s')
202 vals['abbrev'] = abbrev
203
204
205 cols.append('conversion_unit')
206 val_snippets.append('%(unit)s')
207 vals['unit'] = unit
208
209
210 if name is not None:
211 cols.append('name')
212 val_snippets.append('%(name)s')
213 vals['name'] = name
214
215 col_clause = u', '.join(cols)
216 val_clause = u', '.join(val_snippets)
217 queries = [
218 {'cmd': u'insert into clin.test_type (%s) values (%s)' % (col_clause, val_clause), 'args': vals},
219 {'cmd': u"select * from clin.v_test_types where pk_test_type = currval(pg_get_serial_sequence('clin.test_type', 'pk'))"}
220 ]
221 rows, idx = gmPG2.run_rw_queries(queries = queries, get_col_idx = True, return_data = True)
222 ttype = cMeasurementType(row = {'pk_field': 'pk_test_type', 'data': rows[0], 'idx': idx})
223
224 return ttype
225
227
228 if name is None:
229 name = _('inhouse lab')
230 comment = _('auto-generated')
231
232 cmd = u'select * from clin.test_org where internal_name = %(name)s'
233 if comment is not None:
234 comment = comment.strip()
235 args = {'name': name, 'cmt': comment}
236 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}])
237
238 if len(rows) == 0:
239 queries = [
240 {'cmd': u'insert into clin.test_org (fk_org, internal_name, comment) values (null, %(name)s, %(cmt)s)', 'args': args},
241 {'cmd': u"select currval(pg_get_serial_sequence('clin.test_org', 'pk')) as pk"}
242 ]
243 else:
244
245 args['pk'] = rows[0]['pk']
246 queries = [
247 {'cmd': u'update clin.test_org set comment = %(cmt)s where pk = %(pk)s', 'args': args},
248 {'cmd': u'select %(pk)s as pk', 'args': args}
249 ]
250
251 rows, idx = gmPG2.run_rw_queries(queries = queries, return_data = True)
252
253 return rows[0]['pk']
254
255 -class cTestResult(gmBusinessDBObject.cBusinessDBObject):
256 """Represents one test result."""
257
258 _cmd_fetch_payload = u"select * from clin.v_test_results where pk_test_result = %s"
259
260 _cmds_store_payload = [
261 u"""update clin.test_result set
262 clin_when = %(clin_when)s,
263 narrative = nullif(trim(%(comment)s), ''),
264 val_num = %(val_num)s,
265 val_alpha = nullif(trim(%(val_alpha)s), ''),
266 val_unit = nullif(trim(%(val_unit)s), ''),
267 val_normal_min = %(val_normal_min)s,
268 val_normal_max = %(val_normal_max)s,
269 val_normal_range = nullif(trim(%(val_normal_range)s), ''),
270 val_target_min = %(val_target_min)s,
271 val_target_max = %(val_target_max)s,
272 val_target_range = nullif(trim(%(val_target_range)s), ''),
273 abnormality_indicator = nullif(trim(%(abnormality_indicator)s), ''),
274 norm_ref_group = nullif(trim(%(norm_ref_group)s), ''),
275 note_test_org = nullif(trim(%(note_test_org)s), ''),
276 material = nullif(trim(%(material)s), ''),
277 material_detail = nullif(trim(%(material_detail)s), ''),
278 fk_intended_reviewer = %(pk_intended_reviewer)s,
279 fk_encounter = %(pk_encounter)s,
280 fk_episode = %(pk_episode)s,
281 fk_type = %(pk_test_type)s
282 where
283 pk = %(pk_test_result)s and
284 xmin = %(xmin_test_result)s""",
285 u"""select xmin_test_result from clin.v_test_results where pk_test_result = %(pk_test_result)s"""
286 ]
287
288 _updatable_fields = [
289 'clin_when',
290 'comment',
291 'val_num',
292 'val_alpha',
293 'val_unit',
294 'val_normal_min',
295 'val_normal_max',
296 'val_normal_range',
297 'val_target_min',
298 'val_target_max',
299 'val_target_range',
300 'abnormality_indicator',
301 'norm_ref_group',
302 'note_test_org',
303 'material',
304 'material_detail',
305 'pk_intended_reviewer',
306 'pk_encounter',
307 'pk_episode',
308 'pk_test_type'
309 ]
310
346
348
349 cmd = u"""
350 select
351 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)
352 pk_patient,
353 val_unit,
354 val_normal_min, val_normal_max, val_normal_range,
355 val_target_min, val_target_max, val_target_range,
356 norm_ref_group,
357 coalesce(norm_ref_group, '') as norm_ref_group_str
358 from
359 clin.v_test_results
360 where
361 pk_test_type = %(pk_type)s
362 """
363 args = {'pk_type': self._payload[self._idx['pk_test_type']]}
364 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}])
365 return rows
366
368 raise AttributeError('[%s]: reference ranges not settable') % self.__class__.__name__
369
370 reference_ranges = property(_get_reference_ranges, _set_reference_ranges)
371
372 - def set_review(self, technically_abnormal=None, clinically_relevant=None, comment=None, make_me_responsible=False):
373
374 if comment is not None:
375 comment = comment.strip()
376
377 if ((technically_abnormal is None) and
378 (clinically_relevant is None) and
379 (comment is None) and
380 (make_me_responsible is False)):
381 return True
382
383
384 if self._payload[self._idx['reviewed']]:
385 self.__change_existing_review (
386 technically_abnormal = technically_abnormal,
387 clinically_relevant = clinically_relevant,
388 comment = comment
389 )
390 else:
391 self.__set_new_review (
392 technically_abnormal = technically_abnormal,
393 clinically_relevant = clinically_relevant,
394 comment = comment
395 )
396
397 if make_me_responsible is True:
398 cmd = u"select pk from dem.staff where db_user = current_user"
399 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}])
400 self['pk_intended_reviewer'] = rows[0][0]
401 self.save_payload()
402 else:
403 self.refetch_payload()
404
405
406
407 - def __set_new_review(self, technically_abnormal=None, clinically_relevant=None, comment=None):
408 """Add a review to a row.
409
410 - if technically abnormal is not provided/None it will be set
411 to True if the lab's indicator has a meaningful value
412 - if clinically relevant is not provided/None it is set to
413 whatever technically abnormal is
414 """
415 if technically_abnormal is None:
416 technically_abnormal = False
417 if self._payload[self._idx['abnormality_indicator']] is not None:
418 if self._payload[self._idx['abnormality_indicator']].strip() != u'':
419 technically_abnormal = True
420
421 if clinically_relevant is None:
422 clinically_relevant = technically_abnormal
423
424 cmd = u"""
425 insert into clin.reviewed_test_results (
426 fk_reviewed_row,
427 is_technically_abnormal,
428 clinically_relevant,
429 comment
430 ) values (
431 %(pk)s,
432 %(abnormal)s,
433 %(relevant)s,
434 %(cmt)s
435 )"""
436 args = {
437 'pk': self._payload[self._idx['pk_test_result']],
438 'abnormal': technically_abnormal,
439 'relevant': clinically_relevant,
440 'cmt': comment
441 }
442
443 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
444
446 """Change a review on a row.
447
448 - if technically abnormal/clinically relevant/comment are
449 None (or empty) they are not set
450 """
451 args = {
452 'pk_row': self._payload[self._idx['pk_test_result']],
453 'abnormal': technically_abnormal,
454 'relevant': clinically_relevant
455 }
456
457 set_parts = []
458
459 if technically_abnormal is not None:
460 set_parts.append(u'is_technically_abnormal = %(abnormal)s')
461
462 if clinically_relevant is not None:
463 set_parts.append(u'clinically_relevant= %(relevant)s')
464
465 if comment is not None:
466 set_parts.append('comment = %(cmt)s')
467 args['cmt'] = comment
468
469 cmd = u"""
470 update clin.reviewed_test_results set
471 fk_reviewer = (select pk from dem.staff where db_user = current_user),
472 %s
473 where
474 fk_reviewed_row = %%(pk_row)s
475 """ % u',\n '.join(set_parts)
476
477 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
478
480
481 try:
482 pk = int(result)
483 except (TypeError, AttributeError):
484 pk = result['pk_test_result']
485
486 cmd = u'delete from clin.test_result where pk = %(pk)s'
487 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': {'pk': pk}}])
488
489 -def create_test_result(encounter=None, episode=None, type=None, intended_reviewer=None, val_num=None, val_alpha=None, unit=None):
490
491 cmd1 = u"""
492 insert into clin.test_result (
493 fk_encounter,
494 fk_episode,
495 fk_type,
496 fk_intended_reviewer,
497 val_num,
498 val_alpha,
499 val_unit
500 ) values (
501 %(enc)s,
502 %(epi)s,
503 %(type)s,
504 %(rev)s,
505 %(v_num)s,
506 %(v_alpha)s,
507 %(unit)s
508 )"""
509
510 cmd2 = u"""
511 select *
512 from
513 clin.v_test_results
514 where
515 pk_test_result = currval(pg_get_serial_sequence('clin.test_result', 'pk'))"""
516
517 args = {
518 u'enc': encounter,
519 u'epi': episode,
520 u'type': type,
521 u'rev': intended_reviewer,
522 u'v_num': val_num,
523 u'v_alpha': val_alpha,
524 u'unit': unit
525 }
526
527 rows, idx = gmPG2.run_rw_queries (
528 queries = [
529 {'cmd': cmd1, 'args': args},
530 {'cmd': cmd2}
531 ],
532 return_data = True,
533 get_col_idx = True
534 )
535
536 tr = cTestResult(row = {
537 'pk_field': 'pk_test_result',
538 'idx': idx,
539 'data': rows[0]
540 })
541
542 return tr
543
544 -class cLabResult(gmBusinessDBObject.cBusinessDBObject):
545 """Represents one lab result."""
546
547 _cmd_fetch_payload = """
548 select *, xmin_test_result from v_results4lab_req
549 where pk_result=%s"""
550 _cmds_lock_rows_for_update = [
551 """select 1 from test_result where pk=%(pk_result)s and xmin=%(xmin_test_result)s for update"""
552 ]
553 _cmds_store_payload = [
554 """update test_result set
555 clin_when = %(val_when)s,
556 narrative = %(progress_note_result)s,
557 fk_type = %(pk_test_type)s,
558 val_num = %(val_num)s::numeric,
559 val_alpha = %(val_alpha)s,
560 val_unit = %(val_unit)s,
561 val_normal_min = %(val_normal_min)s,
562 val_normal_max = %(val_normal_max)s,
563 val_normal_range = %(val_normal_range)s,
564 val_target_min = %(val_target_min)s,
565 val_target_max = %(val_target_max)s,
566 val_target_range = %(val_target_range)s,
567 abnormality_indicator = %(abnormal)s,
568 norm_ref_group = %(ref_group)s,
569 note_provider = %(note_provider)s,
570 material = %(material)s,
571 material_detail = %(material_detail)s
572 where pk = %(pk_result)s""",
573 """select xmin_test_result from v_results4lab_req where pk_result=%(pk_result)s"""
574 ]
575
576 _updatable_fields = [
577 'val_when',
578 'progress_note_result',
579 'val_num',
580 'val_alpha',
581 'val_unit',
582 'val_normal_min',
583 'val_normal_max',
584 'val_normal_range',
585 'val_target_min',
586 'val_target_max',
587 'val_target_range',
588 'abnormal',
589 'ref_group',
590 'note_provider',
591 'material',
592 'material_detail'
593 ]
594
595 - def __init__(self, aPK_obj=None, row=None):
596 """Instantiate.
597
598 aPK_obj as dict:
599 - patient_id
600 - when_field (see view definition)
601 - when
602 - test_type
603 - val_num
604 - val_alpha
605 - unit
606 """
607
608 if aPK_obj is None:
609 gmBusinessDBObject.cBusinessDBObject.__init__(self, row=row)
610 return
611 pk = aPK_obj
612
613 if type(aPK_obj) == types.DictType:
614
615 if None in [aPK_obj['patient_id'], aPK_obj['when'], aPK_obj['when_field'], aPK_obj['test_type'], aPK_obj['unit']]:
616 raise gmExceptions.ConstructorError, 'parameter error: %s' % aPK_obj
617 if (aPK_obj['val_num'] is None) and (aPK_obj['val_alpha'] is None):
618 raise gmExceptions.ConstructorError, 'parameter error: val_num and val_alpha cannot both be None'
619
620 where_snippets = [
621 'pk_patient=%(patient_id)s',
622 'pk_test_type=%(test_type)s',
623 '%s=%%(when)s' % aPK_obj['when_field'],
624 'val_unit=%(unit)s'
625 ]
626 if aPK_obj['val_num'] is not None:
627 where_snippets.append('val_num=%(val_num)s::numeric')
628 if aPK_obj['val_alpha'] is not None:
629 where_snippets.append('val_alpha=%(val_alpha)s')
630
631 where_clause = ' and '.join(where_snippets)
632 cmd = "select pk_result from v_results4lab_req where %s" % where_clause
633 data = gmPG.run_ro_query('historica', cmd, None, aPK_obj)
634 if data is None:
635 raise gmExceptions.ConstructorError, 'error getting lab result for: %s' % aPK_obj
636 if len(data) == 0:
637 raise gmExceptions.NoSuchClinItemError, 'no lab result for: %s' % aPK_obj
638 pk = data[0][0]
639
640 gmBusinessDBObject.cBusinessDBObject.__init__(self, aPK_obj=pk)
641
643 cmd = """
644 select
645 %s,
646 vbp.title,
647 vbp.firstnames,
648 vbp.lastnames,
649 vbp.dob
650 from v_basic_person vbp
651 where vbp.pk_identity=%%s""" % self._payload[self._idx['pk_patient']]
652 pat = gmPG.run_ro_query('historica', cmd, None, self._payload[self._idx['pk_patient']])
653 return pat[0]
654
655 -class cLabRequest(gmBusinessDBObject.cBusinessDBObject):
656 """Represents one lab request."""
657
658 _cmd_fetch_payload = """
659 select *, xmin_lab_request from v_lab_requests
660 where pk_request=%s"""
661 _cmds_lock_rows_for_update = [
662 """select 1 from lab_request where pk=%(pk_request)s and xmin=%(xmin_lab_request)s for update"""
663 ]
664 _cmds_store_payload = [
665 """update lab_request set
666 request_id=%(request_id)s,
667 lab_request_id=%(lab_request_id)s,
668 clin_when=%(sampled_when)s,
669 lab_rxd_when=%(lab_rxd_when)s,
670 results_reported_when=%(results_reported_when)s,
671 request_status=%(request_status)s,
672 is_pending=%(is_pending)s::bool,
673 narrative=%(progress_note)s
674 where pk=%(pk_request)s""",
675 """select xmin_lab_request from v_lab_requests where pk_request=%(pk_request)s"""
676 ]
677 _updatable_fields = [
678 'request_id',
679 'lab_request_id',
680 'sampled_when',
681 'lab_rxd_when',
682 'results_reported_when',
683 'request_status',
684 'is_pending',
685 'progress_note'
686 ]
687
688 - def __init__(self, aPK_obj=None, row=None):
689 """Instantiate lab request.
690
691 The aPK_obj can be either a dict with the keys "req_id"
692 and "lab" or a simple primary key.
693 """
694
695 if aPK_obj is None:
696 gmBusinessDBObject.cBusinessDBObject.__init__(self, row=row)
697 return
698 pk = aPK_obj
699
700 if type(aPK_obj) == types.DictType:
701
702 try:
703 aPK_obj['req_id']
704 aPK_obj['lab']
705 except:
706 _log.exception('[%s:??]: faulty <aPK_obj> structure: [%s]' % (self.__class__.__name__, aPK_obj), sys.exc_info())
707 raise gmExceptions.ConstructorError, '[%s:??]: cannot derive PK from [%s]' % (self.__class__.__name__, aPK_obj)
708
709 where_snippets = []
710 vals = {}
711 where_snippets.append('request_id=%(req_id)s')
712 if type(aPK_obj['lab']) == types.IntType:
713 where_snippets.append('pk_test_org=%(lab)s')
714 else:
715 where_snippets.append('lab_name=%(lab)s')
716 where_clause = ' and '.join(where_snippets)
717 cmd = "select pk_request from v_lab_requests where %s" % where_clause
718
719 data = gmPG.run_ro_query('historica', cmd, None, aPK_obj)
720 if data is None:
721 raise gmExceptions.ConstructorError, '[%s:??]: error getting lab request for [%s]' % (self.__class__.__name__, aPK_obj)
722 if len(data) == 0:
723 raise gmExceptions.NoSuchClinItemError, '[%s:??]: no lab request for [%s]' % (self.__class__.__name__, aPK_obj)
724 pk = data[0][0]
725
726 gmBusinessDBObject.cBusinessDBObject.__init__(self, aPK_obj=pk)
727
729 cmd = """
730 select vpi.pk_patient, vbp.title, vbp.firstnames, vbp.lastnames, vbp.dob
731 from v_pat_items vpi, v_basic_person vbp
732 where
733 vpi.pk_item=%s
734 and
735 vbp.pk_identity=vpi.pk_patient"""
736 pat = gmPG.run_ro_query('historica', cmd, None, self._payload[self._idx['pk_item']])
737 if pat is None:
738 _log.error('cannot get patient for lab request [%s]' % self._payload[self._idx['pk_item']])
739 return None
740 if len(pat) == 0:
741 _log.error('no patient associated with lab request [%s]' % self._payload[self._idx['pk_item']])
742 return None
743 return pat[0]
744
745
746
747 -def create_lab_request(lab=None, req_id=None, pat_id=None, encounter_id=None, episode_id=None):
748 """Create or get lab request.
749
750 returns tuple (status, value):
751 (True, lab request instance)
752 (False, error message)
753 (None, housekeeping_todo primary key)
754 """
755 req = None
756 aPK_obj = {
757 'lab': lab,
758 'req_id': req_id
759 }
760 try:
761 req = cLabRequest (aPK_obj)
762 except gmExceptions.NoSuchClinItemError, msg:
763 _log.info('%s: will try to create lab request' % str(msg))
764 except gmExceptions.ConstructorError, msg:
765 _log.exception(str(msg), sys.exc_info(), verbose=0)
766 return (False, msg)
767
768 if req is not None:
769 db_pat = req.get_patient()
770 if db_pat is None:
771 _log.error('cannot cross-check patient on lab request')
772 return (None, '')
773
774 if pat_id != db_pat[0]:
775 _log.error('lab request found for [%s:%s] but patient mismatch: expected [%s], in DB [%s]' % (lab, req_id, pat_id, db_pat))
776 me = '$RCSfile: gmPathLab.py,v $ $Revision: 1.79 $'
777 to = 'user'
778 prob = _('The lab request already exists but belongs to a different patient.')
779 sol = _('Verify which patient this lab request really belongs to.')
780 ctxt = _('lab [%s], request ID [%s], expected link with patient [%s], currently linked to patient [%s]') % (lab, req_id, pat_id, db_pat)
781 cat = 'lab'
782 status, data = gmPG.add_housekeeping_todo(me, to, prob, sol, ctxt, cat)
783 return (None, data)
784 return (True, req)
785
786 queries = []
787 if type(lab) is types.IntType:
788 cmd = "insert into lab_request (fk_encounter, fk_episode, fk_test_org, request_id) values (%s, %s, %s, %s)"
789 else:
790 cmd = "insert into lab_request (fk_encounter, fk_episode, fk_test_org, request_id) values (%s, %s, (select pk from test_org where internal_name=%s), %s)"
791 queries.append((cmd, [encounter_id, episode_id, str(lab), req_id]))
792 cmd = "select currval('lab_request_pk_seq')"
793 queries.append((cmd, []))
794
795 result, err = gmPG.run_commit('historica', queries, True)
796 if result is None:
797 return (False, err)
798 try:
799 req = cLabRequest(aPK_obj=result[0][0])
800 except gmExceptions.ConstructorError, msg:
801 _log.exception(str(msg), sys.exc_info(), verbose=0)
802 return (False, msg)
803 return (True, req)
804
805 -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):
806 tres = None
807 data = {
808 'patient_id': patient_id,
809 'when_field': when_field,
810 'when': when,
811 'test_type': test_type,
812 'val_num': val_num,
813 'val_alpha': val_alpha,
814 'unit': unit
815 }
816 try:
817 tres = cLabResult(aPK_obj=data)
818
819 _log.error('will not overwrite existing test result')
820 _log.debug(str(tres))
821 return (None, tres)
822 except gmExceptions.NoSuchClinItemError:
823 _log.debug('test result not found - as expected, will create it')
824 except gmExceptions.ConstructorError, msg:
825 _log.exception(str(msg), sys.exc_info(), verbose=0)
826 return (False, msg)
827 if request is None:
828 return (False, _('need lab request when inserting lab result'))
829
830 if encounter_id is None:
831 encounter_id = request['pk_encounter']
832 queries = []
833 cmd = "insert into test_result (fk_encounter, fk_episode, fk_type, val_num, val_alpha, val_unit) values (%s, %s, %s, %s, %s, %s)"
834 queries.append((cmd, [encounter_id, request['pk_episode'], test_type, val_num, val_alpha, unit]))
835 cmd = "insert into lnk_result2lab_req (fk_result, fk_request) values ((select currval('test_result_pk_seq')), %s)"
836 queries.append((cmd, [request['pk_request']]))
837 cmd = "select currval('test_result_pk_seq')"
838 queries.append((cmd, []))
839
840 result, err = gmPG.run_commit('historica', queries, True)
841 if result is None:
842 return (False, err)
843 try:
844 tres = cLabResult(aPK_obj=result[0][0])
845 except gmExceptions.ConstructorError, msg:
846 _log.exception(str(msg), sys.exc_info(), verbose=0)
847 return (False, msg)
848 return (True, tres)
849
851
852 if limit < 1:
853 limit = 1
854
855 lim = limit + 1
856 cmd = """
857 select pk_result
858 from v_results4lab_req
859 where reviewed is false
860 order by pk_patient
861 limit %s""" % lim
862 rows = gmPG.run_ro_query('historica', cmd)
863 if rows is None:
864 _log.error('error retrieving unreviewed lab results')
865 return (None, _('error retrieving unreviewed lab results'))
866 if len(rows) == 0:
867 return (False, [])
868
869 if len(rows) == lim:
870 more_avail = True
871
872 del rows[limit]
873 else:
874 more_avail = False
875 results = []
876 for row in rows:
877 try:
878 results.append(cLabResult(aPK_obj=row[0]))
879 except gmExceptions.ConstructorError:
880 _log.exception('skipping unreviewed lab result [%s]' % row[0], sys.exc_info(), verbose=0)
881 return (more_avail, results)
882
884 lim = limit + 1
885 cmd = "select pk from lab_request where is_pending is true limit %s" % lim
886 rows = gmPG.run_ro_query('historica', cmd)
887 if rows is None:
888 _log.error('error retrieving pending lab requests')
889 return (None, None)
890 if len(rows) == 0:
891 return (False, [])
892 results = []
893
894 if len(rows) == lim:
895 too_many = True
896
897 del rows[limit]
898 else:
899 too_many = False
900 requests = []
901 for row in rows:
902 try:
903 requests.append(cLabRequest(aPK_obj=row[0]))
904 except gmExceptions.ConstructorError:
905 _log.exception('skipping pending lab request [%s]' % row[0], sys.exc_info(), verbose=0)
906 return (too_many, requests)
907
909 """Get logically next request ID for given lab.
910
911 - lab either test_org PK or test_org.internal_name
912 - incrementor_func:
913 - if not supplied the next ID is guessed
914 - if supplied it is applied to the most recently used ID
915 """
916 if type(lab) == types.IntType:
917 lab_snippet = 'vlr.fk_test_org=%s'
918 else:
919 lab_snippet = 'vlr.lab_name=%s'
920 lab = str(lab)
921 cmd = """
922 select request_id
923 from lab_request lr0
924 where lr0.clin_when = (
925 select max(vlr.sampled_when)
926 from v_lab_requests vlr
927 where %s
928 )""" % lab_snippet
929 rows = gmPG.run_ro_query('historica', cmd, None, lab)
930 if rows is None:
931 _log.warning('error getting most recently used request ID for lab [%s]' % lab)
932 return ''
933 if len(rows) == 0:
934 return ''
935 most_recent = rows[0][0]
936
937 if incrementor_func is not None:
938 try:
939 next = incrementor_func(most_recent)
940 except TypeError:
941 _log.error('cannot call incrementor function [%s]' % str(incrementor_func))
942 return most_recent
943 return next
944
945 for pos in range(len(most_recent)):
946 header = most_recent[:pos]
947 trailer = most_recent[pos:]
948 try:
949 return '%s%s' % (header, str(int(trailer) + 1))
950 except ValueError:
951 header = most_recent[:-1]
952 trailer = most_recent[-1:]
953 return '%s%s' % (header, chr(ord(trailer) + 1))
954
955
956
957 if __name__ == '__main__':
958 import time
959
960
962 tr = create_test_result (
963 encounter = 1,
964 episode = 1,
965 type = 1,
966 intended_reviewer = 1,
967 val_num = '12',
968 val_alpha=None,
969 unit = 'mg/dl'
970 )
971 print tr
972 return tr
973
977
982
984 print "test_result()"
985
986 data = {
987 'patient_id': 12,
988 'when_field': 'val_when',
989 'when': '2000-09-17 18:23:00+02',
990 'test_type': 9,
991 'val_num': 17.3,
992 'val_alpha': None,
993 'unit': 'mg/l'
994 }
995 lab_result = cLabResult(aPK_obj=data)
996 print lab_result
997 fields = lab_result.get_fields()
998 for field in fields:
999 print field, ':', lab_result[field]
1000 print "updatable:", lab_result.get_updatable_fields()
1001 print time.time()
1002 print lab_result.get_patient()
1003 print time.time()
1004
1006 print "test_request()"
1007 try:
1008
1009
1010 data = {
1011 'req_id': 'EML#SC937-0176-CEC#11',
1012 'lab': 'Enterprise Main Lab'
1013 }
1014 lab_req = cLabRequest(aPK_obj=data)
1015 except gmExceptions.ConstructorError, msg:
1016 print "no such lab request:", msg
1017 return
1018 print lab_req
1019 fields = lab_req.get_fields()
1020 for field in fields:
1021 print field, ':', lab_req[field]
1022 print "updatable:", lab_req.get_updatable_fields()
1023 print time.time()
1024 print lab_req.get_patient()
1025 print time.time()
1026
1031
1036
1044
1049
1054
1055 if (len(sys.argv) > 1) and (sys.argv[1] == 'test'):
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067 test_test_type()
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335