/* * Copyright (c) 1995, 1996 Gunther Schadow. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #pragma implementation "results.h" #include "results.h" #include "abl300.h" #include "y.tab.h" #include "OBXseg.h" #include "ORUmsg.h" #include "Unit.h" #include "xios.h" #include "logfile.h" #include "LOINC.h" #include "patinfo.h" #include "operinfo.h" #include "illp-session.h" #include "DataTypeCode.h" #include #include #include #include Result::Result(int sid, int oid, const char *value, int uid, bool error) { // translate observation id to LOINC Loinc loinc; Unit unit; NMtyp number(value); if(!number.ispresent() || number.isnull()) return; toLOINC(oid, uid, sid, number, loinc, unit); _obx.Obs.ObsIde.Ide = (const char *)loinc; _obx.Obs.ObsIde.Text = loinc.getMeasure(); _obx.Obs.ObsIde.CodSys = "LN"; // FIXME! Code IDs are codes as well! _obx.Obs.ObsValue = STtyp(number); _obx.Obs.Units.Ide = unit; _obx.Obs.ValueType = DataTypeCode::NMval; if(!error) { _obx.Obs.ObsResStatus = ObsResStatusCodesIntCode::ResEntNotVer; } else { _obx.Obs.ObsResStatus = ObsResStatusCodesIntCode::ResCanBeObtForThisObs; _obx.NotesAndCom[0].SetIdNotesAndCom = 1; // This is tautologic!!! _obx.NotesAndCom[0].SouOfCom = SouOfComCode::AncFilDepIsSouOfCom; _obx.NotesAndCom[0].Com[0] = "Messung ist fehlerhaft"; } } void Battery::append(const Result *x) { _obr.OBXgroup.prepend(x->_obx); } void Battery::settype(int x) { type = x; #ifdef MULTI_OBR _obr.ObsReq.UniSerId.Ide = analyzer(x); #endif } void Battery::seterror(const char *s) { if(s != NULL) error = strdup(s); else { if(error != NULL) delete [] error; error = NULL; } #ifdef MULTI_OBR _obr.NotesAndCom[0].Com[0] = IDtyp(x); #endif } Battery::~Battery() { if(error != NULL) delete [] error; } Battery::Battery(const Battery &x) { type = x.type; if(x.error != NULL) error = strdup(x.error); else error = NULL; _obr = x._obr; } const Battery &Battery::operator=(const Battery &x) { type = x.type; if(x.error != NULL) error = strdup(x.error); else { if(error != NULL) delete [] error; error = NULL; } _obr = x._obr; return *this; } void Batteries::append(const Battery *x) { #ifdef MULTI_OBR _robr.prepend(x->_obr); #else for(const repstruc *robxg = &x->_obr.OBXgroup; !robxg->end(); robxg = robxg->next()) { ORUmsg::GRPgrp::OBRgrp::OBXgrp &obxg = robxg->first(); _robr[0].OBXgroup.prepend(obxg); // append to single OBR group _robr[0].OBXgroup[0].Obs.ProSId.Ide = analyzer(x->type); } if(x->error != NULL) { _robr[0].NotesAndCom[0].SetIdNotesAndCom = 1; _robr[0].NotesAndCom[0].SouOfCom = SouOfComCode::AncFilDepIsSouOfCom; _robr[0].NotesAndCom[0].Com.prepend(clws(trws(x->error))); } #endif } Header::Header() { time_stamp = NULL; pre_observ = NULL; patient_id = NULL; error = NULL; } Header::~Header() { if(time_stamp != NULL) delete time_stamp; if(pre_observ != NULL) delete pre_observ; if(patient_id != NULL) delete patient_id; if(error != NULL) delete error; } Job::Job(Header *h, Batteries *b) { // prepend pre-observations b->append(h->pre_observ); // assign observations _grp.OBRgroup = b->_robr; // resolve operator id operinfo opi(h->operator_id); // set patient identification patinfo pti(h->patient_id); if(pti.visit_nr != NULL) { _grp.PIDgroup.PatIde.PatIdIntId[0].IdNum = pti.patient_id; _grp.PIDgroup.PatIde.PatName.FamName = pti.family_name; _grp.PIDgroup.PatIde.PatName.GivenName = pti.given_name; _grp.PIDgroup.PatIde.Sex = pti.sex; if(pti.dob_day != 0 && pti.dob_month != 0) _grp.PIDgroup.PatIde.DateOfBirth = Date(pti.dob_year, pti.dob_month, pti.dob_day); // FIXME! a constant! _grp.PIDgroup.PatVisit.AssPatLoc.NurseUnit = "060_IOP"; _grp.PIDgroup.PatVisit.AssPatLoc.Room = pti.room; _grp.PIDgroup.PatVisit.AssPatLoc.Bed = pti.bed; _grp.PIDgroup.PatVisit.VisitNum.IdNum = pti.visit_nr; } else { _grp.PIDgroup.PatIde.AltPatId = h->patient_id; } // set header information for all OBR segments int set_id_obr = 1; for(repstruc *robrg = &_grp.OBRgroup; !robrg->end(); robrg = robrg->next()) { ORUmsg::GRPgrp::OBRgrp &obrg = robrg->first(); obrg.ObsReq.SetIdObsReq = set_id_obr++; obrg.ObsReq.FilOrderNum.Com1 = h->sample_no; obrg.ObsReq.DiaGnoServSectId = DiaGnoSerSecIdCode::BloodGases; obrg.ObsReq.SpeSou.Com1 = specimen(h->specimen_type); obrg.ObsReq.ResStatus = ResStatusCode::ResStoNotYetVer; obrg.ObsReq.SpeRecDateTime = *h->time_stamp; obrg.ObsReq.ResRptStaChngDateTime.set(); if(opi.operator_id != -1) { // FIXME (is a CN in the CM!) (FIX HL7!) obrg.ObsReq.Tec[0].Com1 = opi.operator_id; obrg.ObsReq.Tec[0].Com2 = opi.family_name; obrg.ObsReq.Tec[0].Com3 = opi.given_name; } int set_id_obx = 1; for(repstruc *robxg = &obrg.OBXgroup; !robxg->end(); robxg = robxg->next()) { ORUmsg::GRPgrp::OBRgrp::OBXgrp &obxg = robxg->first(); obxg.Obs.SetIdObsSim = set_id_obx++; obxg.Obs.DateTimeOfTheObs = *h->time_stamp; obxg.Obs.ResObs.IdNum = opi.operator_id; obxg.Obs.ResObs.FamName = opi.family_name; obxg.Obs.ResObs.GivenName = opi.given_name; #ifdef MULTI_OBR obxg.Obs.ProSId = obrg.ObsReq.UniSerId; #endif } } } void eject(Job *j) { ORUmsg oru; oru.GRPgroup[0] = j->_grp; // update MSH segment oru.MesHea.SenApp = App; oru.MesHea.SenFac = Fac; oru.MesHea.RecApp = RecApp; oru.MesHea.RecFac = RecFac; stamp(oru.MesHea.DateTimeOfMes); oru.MesHea.ProId = ProIdCode::Pro; oru.MesHea.VerId = VerIdCode::_2_2val; if(!oru.GRPgroup[0].PIDgroup.PatVisit.commit()) // i.e. no patient { // there is no PatVisit, meaning that we havn't been able to // locate the patient in the CareVue census (or in whatever the // class patinfo / PatByBed program looks for the PTID) we have // a ``orphaned'' result message. This is written directly into // our journal, without the need to send it anywhere else. strstream s; s.form("ORP%05u", (u_int)getpid()) << '\0'; oru.MesHea.MesConTrolId = s.str(); oru.commit(); strstream js; js << PGLOG "/" << '/' << App << '/' << Fac << '/' << s.str() << '\0'; fstream jout(js.str(), ios::out); // this is the journal file xios _jout(jout); s.freeze(0); js.freeze(0); // print the request to the journal jout << hl7er << oru << flush; } else { // if the PatVisit segment is present, we send the message on to who // ever was assigned to receive the result (which is told by the // global variables: host and service). // the transaction id is used for the journal and acklog files as well strstream s; s.form("REQ%05u", (u_int)getpid()) << '\0'; strstream js; js << PGLOG "/" << '/' << App << '/' << Fac << '/' << s.str() << '\0'; strstream as; as << PGLOG "/" << '/' << App << '/' << Fac << '/'; as.form("ACK%05u", (u_int)getpid()) << '\0'; oru.MesHea.MesConTrolId = s.str(); oru.commit(); fstream jout(js.str(), ios::out); // this is the journal file fstream aout(as.str(), ios::out); // and this is the acklog file s.freeze(0); js.freeze(0); as.freeze(0); xios xjout(jout), xaout(aout); oru.commit(); // print the request to the journal jout << hl7er << oru << flush; ANYmsg ack; ack.allow(UniMesIdCode::ACKval); if(chat_illp(host, service, oru, ack) == FAIL) LOGWARNING("send message failed"); // print the result to the acklog aout << hl7er << ack << flush; } }