#!/bin/sh # # idb_direct -- directly interact with CareVue's idb on behalf of a HL7 # transaction # # SYNOPSIS # # idb_direct -e event -r recno -l bed [-s recno2] [-m bed2] [-n nbed] # [-c] [-H height] [-W weight] [-S BSA] # idb_direct -e 1|8 -r recno -l bed [-c] [-H height] [-W weight] [-S BSA] # idb_direct -e 2 -r recno -l old_bed -n new_bed # idb_direct -e 3 -r recno -l bed # idb_direct -e 17 -r recno1 -l bed1 -s recno2 -m bed2 # # DESCRIPTION # # The actions being taken by this script can be freely programmed # and depend on local considerations. # # CareVue does only accept medical record numbers (recno) for # patient reference. CareVue's own HL7 interface, however, fails to # report many application error conditions, such as admitting a # patient into an occupied bed. This script takes the medical # record number(s) and bed identifier(s) of a patient (or a pair of # patients) and tests (1) whether the bed is free or occupied, (2) # whether the patient is known or unknown (by his/her record # number), and (3) whether the given (known) patient is assigned to # the given (occupied) bed or else the bed is occupied by a # different patient. Currently, however, there is no way to report # the identity of the other patient back to the calling program. # # For the HL7 events A01 (admission), A03 (discharge), and A08 # (update pat. info.), only the first bed/patient is tested. For # A02 (transfer) the second recno is set equal to the first while # the first bed is the source bed and the second bed is the # destination bed. Thus one can test, whether the patient was # already transfered to the new bed (i.e. if the second bed is # occupied by the given known patient). # # NOTE: All patient locations are assumed to be within one and the # same careunit. # # If observations (weight, height, and BSA) are supplied and the # commit flag (-c) is also given, these values are written into the # patient record. If the relevant entities (AdmitWt, etc.) do not # yet exist, they are inserted and linked to the patient record # before. # # Any write access to the database requires the patient record to # be known to the patient manager in order to avoid severe database # havoc. Therefore the ptMgrSup program is repeatedly polled until # the patient is found. This can be most efficciently handled # by waiting for the admitted patient to appear in the census # (ptMgrSup -c) only during the commit phase (-c) of the admission # (-e 1) transaction. Thus any successive transaction can be quite # sure that it won't get into conflict with a pending admission. # # The idb part requires the script new_wt_ht_bsa to be accessible # within the standard path in the CHARTING domain. This sh script # calls dbload in order to insert new entities in the ADT # observation classes. # # RETURN VALUE # # The return value is to be interpreted as a bitset, where the # least significant triple denotes the first (or only) given # bed/patient and the more significant triple denotes the second # bed/patient. The most significant bit is the error flag. The # following table defines the meaning of each bit in a triple: # # Bitset Value Meaning # ------------------------------------------------------ # 001 1 bed is occupied (by whoever) # 010 2 patient is known (assigned to whatever location) # 111 7 bed is occupied, patient is known, and given # patient is assigned to the given bed # # CONFIGURABLE CONSTANTS LOGFILE=/var/tmp/idb_direct.log # # begin logging # if [ "$1" = "-t" ] then shift else exec >>$LOGFILE 2>&1 fi echo `date` "$0" echo arguments: "$*" # # ADMIN and CAREVUE, CVHOST, CVUSER are set from either the environment # or from the files /usr/hl7/etc/{admin,carevue} # if [ -z "$ADMIN" ] then if [ -r /usr/hl7/etc/admin ] then export ADMIN=`cat /usr/hl7/etc/admin` else if [ -n "$USER" ] then export ADMIN="$USER" else echo who are you? please define USER, ADMIN or /usr/hl7/etc/admin >&2 exit 2 fi fi fi if [ -z "$CAREVUE" ] then if [ -r /usr/hl7/etc/carevue ] then export CAREVUE=`cat /usr/hl7/etc/carevue` export CVUSER=`expr "$CAREVUE" : '^\([^@]*\)@.*$'` export CVHOST=`expr "$CAREVUE" : '^[^@]*@\(.*\)$'` else echo must define environment CAREVUE or /usr/hl7/etc/carevue >&2 exit 2 fi fi # # abbreviations for regular expression components # Pnum='[0-9][0-9]*' Ptab=' ' Pcol='[^ ]*' # # the HL7-ER encoded NULL value # NULL='""' # # This function faciliates remote execution commands in the CHARTING # domain # remote() { rsh -K -l $CVUSER $CVHOST " . /usr/M1215A/carevue/etc/carevue_env ; . /usr/M1215A/carevue/etc/go_charting ; $*" } # # CareVue system message warning # smwarn() { echo -n "issuing system message: " remote "smtool -f HL7_$1 ; smtool -t 300 -D HL7_$1 \"$2\"" mail -s "$2" $ADMIN <<__END__ $2 Event: $event 1st bed: $first_bed 2nd bed: $second_bed __END__ } # # Resolve options and arguments # event= bed= bed2= recno= recno2= admht= admwt= bsa= commit=false optstr='e:l:m:n:r:s:H:W:S:c' # usage() { echo "usage: idb_direct -e 1|8 -r recno -l bed [-c] [-H height] [-W weight] [-S BSA] idb_direct -e 2 -r recno -l old_bed -n new_bed idb_direct -e 3 -r recno -l bed idb_direct -e 17 -r recno1 -l bed1 -s recno2 -m bed2" >&2 exit 4 } # while getopts $optstr opt do # resolve HL7-ER encoded NULL value to the string: "NULL" if [ "$OPTARG" = "$NULL" ] then OPTARG=NULL fi case $opt in e) event=$OPTARG ;; c) commit=true ;; l) bed=$OPTARG ;; n) bed2=$OPTARG ;; m) bed2=$OPTARG ;; r) recno=$OPTARG ;; s) recno2=$OPTARG ;; H) admht=$OPTARG ;; W) admwt=$OPTARG ;; S) bsa=$OPTARG ;; *) usage ;; esac done # # Check for required arguments not given # if [ -z "$event" ] then usage fi # # a transaction event deals with a single patient in two possible beds # if [ 0$event -eq 2 ] then recno2=$recno fi # # Any OBX values? # if [ -n "$admht" ] || [ -n "$admwt" ] || [ -n "$bsa" ] then obxvalues_pending=true else obxvalues_pending=false fi # # Check for the beds being occupied or empty # get_census() { if ! remote ptMgrSup -c > /tmp/$$.census then echo error abort rm -f /tmp/$$.census exit 128 fi } # # check the status of a bed/patient # # arguments: [-n] which bed recno [status_pat] # # sets the variables: ${which}_bed, ${which}_occupied, ${which}_known, # and ${which}_ident by side effect, where ${which} is either first or # second (as given by the first argument). # The status_pat is an egrep(1) pattern that should be specified if # constraints regarding the patient status are to be made. Default is # no constraints. Example: '(admitted|stat admit)' means that a # patient is regarded to be known only if he is admitted or # stat-admitted. # # Normally, an in-progress status requires to wait until definitive # patient and status information is avaliable, otherwhise we might # assert occupied and not ident event though the patient in question # is just in process to be admitted. If we absolutely do not wish to # wait, the -n option is supplied as the first argument. # check() { local nowait=false if [ "$1" = "-n" ] then nowait=true shift fi local which="$1" local bed="$2" local recno="$3" local status="$4" test -z "$bed" && bed="$Pcol" test "$bed" = "NULL" && bed="" test -z "$recno" && recno="$Pcol" test "$recno" = "NULL" && recno="" test -z "$status" && status="$Pcol" test "$status" = "NULL" && status="" local occupied=false local known=false local ident=false local bedstat local cnt local had_to_wait=false if [ "$bed" != "$Pcol" ] then bedstat="`egrep "^$Pnum$Ptab$bed$Ptab" /tmp/$$.census`" cnt=0 while ( ! $nowait ) && [ $cnt -lt 6 ] && [ -n "$bedstat" ] do if ( echo "$bedstat" |grep -q 'admission in progress' ) then sleep 10 get_census bedstat="`egrep "^$Pnum$Ptab$bed$Ptab" /tmp/$$.census`" cnt=$(( $cnt + 1 )) else break fi done if [ -n "$bedstat" ] then occupied=true else bedstat="empty" fi fi if [ "$recno" != "$Pcol" ] then if $occupied && echo "$bedstat" \ | egrep "^$Pnum$Ptab$bed$Ptab$Pcol$Ptab$recno$Ptab$status$Ptab" then known=true ident=true patstat="$bedstat" else patstat="`egrep "^$Pnum$Ptab$Pcol$Ptab$Pcol$Ptab$recno$Ptab" \ /tmp/$$.census`" cnt=0 while ( ! $nowait ) && [ $cnt -lt 6 ] && [ -n "$patstat" ] do if ( echo "$patstat" |grep -q 'admission in progress' ) then sleep 10 had_to_wait=true get_census patstat="`egrep "^$Pnum$Ptab$Pcol$Ptab$Pcol$Ptab$recno$Ptab" \ /tmp/$$.census`" cnt=$(( $cnt + 1 )) else # by the time, the patient is available, the bed status may # have changed -- thus, redo the whole check if $had_to_wait then check "$1" "$2" "$3" "$4" return $? else break fi fi done if echo "$patstat" \ | egrep "^$Pnum$Ptab$Pcol$Ptab$Pcol$Ptab$recno$Ptab$status$Ptab" then known=true fi fi fi setvar ${which}_bed "$bedstat" setvar ${which}_pat "$patstat" setvar ${which}_occupied "$occupied" setvar ${which}_known "$known" setvar ${which}_ident "$ident" [ -n "$bed" ] || [ -n "$recno" ] } # # Get the census # get_census # # 1st bed # if check first "$bed" "$recno" '(admitted|stat admit)' then echo 1st: $first_bed fi # # 2nd bed needed for # special cases: A02 (transfer a patient) # A17 (swap two patients) # if check second "$bed2" "$recno2" then echo 2nd: $second_bed fi # # Get the PRID from the patient manager. If patient is known at all by # the ptmgr, (i.e. test -n "$first_pat") then check whether admission # is in progress. If it is, wait until this status changes (timeout may # be quite long, because there are good chances that this status # changes at some time). # If, however, the patient is not known at all, we should wait a bit # for the patient record to appear, especially if we are in a A01 # (admit) transaction. If it appears we have to wait for exit from # in-progress status. # ptmgr_id="" if $commit && $obxvalues_pending then test_pat="$first_pat" cnt=0 while [ 0$event -eq 1 ] && [ $cnt -lt 6 ] do if [ -n "$test_pat" ] then break else sleep 10 get_census check test '' "$recno" '' cnt=$(( $cnt + 1 )) fi done if [ -n "$test_pat" ] then ptmgr_id="`echo $test_pat |cut -d' ' -f1`" echo PRID is $ptmgr_id fi fi # # Do the database access: fill in observation values if $first_known # and $obxvalues_pending # if $commit && $obxvalues_pending && [ -n "$ptmgr_id" ] then rsh -K -l $CVUSER $CVHOST " . /usr/M1215A/carevue/etc/carevue_env . /usr/M1215A/carevue/etc/go_charting idb -q -s <<__END__ set ColumnMode; set WaitMode; set Patient $ptmgr_id; assign ADMWT \"NULL\"; select admitWt into ADMWT from Patients; if \"\\\$ADMWT\" = \"NULL\"; ! new_wt_ht_bsa \\\$PATIENT; select objectId into ADMWT from AdmitWt; select objectId into HTEVT from HeightEvent; select objectId into BSAEV from BSAEvent; update admitWt=(AdmitWt,\\\$ADMWT) from Patients; update ht=(HeightEvent,\\\$HTEVT) from Patients; update BSA=(BSAEvent,\\\$BSAEV) from Patients; fi; if \"$admwt\" = \"\"; else; update value=\"$admwt\" from AdmitWt; fi; if \"$admht\" = \"\"; else; update value1=\"$admht\" from HeightEvent; fi; if \"$bsa\" = \"\"; else; update value1=\"$bsa\" from BSAEvent; fi; __END__ " fi # # issue warnings # if $first_occupied && ( ! $first_ident ) && [ 0$event -eq 1 ] then smwarn $bed$recno "Patient $recno auf Warteliste, da Bett $bed belegt ist" fi if [ -n "$bed2" ] && $second_occupied && ( ! $second_ident ) && [ 0$event -eq 2 ] then smwarn $bed2$recno2 "Patient $recno nicht verschoben, da bett $bed2 belegt ist" fi # # construct return value indicating bed/patient status (see above) # retval=0 $first_occupied && retval=1 $first_known && retval=$(($retval + 2)) $first_ident && retval=$(($retval + 4)) $second_occupied && retval=$(($retval + 8)) $second_known && retval=$(($retval + 16)) $second_ident && retval=$(($retval + 32)) # # and return # printf "`date` return 0%o\n" $retval rm -f /tmp/$$.census exit $retval