Giter Club home page Giter Club logo

hl7v2's Introduction

NPM Version NPM Downloads Build Status Test Coverage

Dependencies DevDependencies Package Quality

About

HL7 v2 parser, serializer, validator and tcp client/server for NodeJS

Installation

$ npm install hl7v2 --save

Node Compatibility

  • node >= 6.x

Change log

To see changelog click here

License

HL7v2 is available under MIT license.

hl7v2's People

Contributors

dependabot[bot] avatar erayhanoglu avatar k2s avatar markusylisiurunen avatar soup-in-boots avatar srosenda avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

hl7v2's Issues

Null value handling

According to the HL7Wiki, a null value should be denoted with two double quotes (https://wiki.hl7.org/Null). If you use such a value for a date field and try to parse the message with HL7Message.parse, you get the following error:

Error: Invalid date string """"

I browsed through the code to find a place to update the behaviour, but was unsure where would be the correct place to make them. Have you discussed this? Do you have ideas on how the null values should be handled?

getting value of array elements

Thanks for contributing the project! I've been trying it out to see if it can fit our need.

How does one get access to the items in the this._data array? HL7Field.value() only returns the first element. IE in my example below.. how do I get the patient's first and last name from the PID segment?

Do you have any plans mapping the HL7Segment to a JSON object?

const pid = message.getSegment('PID', 0);
console.log(pid.PatientId.value, pid.PatientName.toHL7(), pid.PatientName.value);
console.log(pid);

image

Wrong Message Control ID used in sendReceive?

This is a wonderful library, thanks for creating and supporting it.
I think in the HL7Client there might be a bug.

  _onMessage(msg) {
    const contId = msg.MSH.MessageControlId.value;
    if (this._waitQueue[contId]) {
      const fn = this._waitQueue[contId];
      delete this._waitQueue[contId];
      fn(msg);
      return;
    }
    this.emitSafe('message', msg);
  }

I think the _onMessage function should take the value for contId not from the MSH segment of the response, but from the MSA segment, where the Message Control ID of the original request is echoed. Thus, I think this line is incorrect:
const contId = msg.MSH.MessageControlId.value;

[ERROR] this._data[0].value = value; TypeError: Cannot create property 'value' on string 'Y'

I got this error. Whenever I tried to fix, always lead me to another issue. I need some help, please.

**/mnt/Kingcolon/server/node_modules/hl7v2/lib/HL7Field.js:122
this._data[0].value = value;
^

TypeError: Cannot create property 'value' on string 'Y'
at HL7Field.set value [as value] (/mnt/Kingcolon/server/node_modules/hl7v2/lib/HL7Field.js:122:25)
at /mnt/Kingcolon/server/node_modules/hl7v2/lib/exchange/HL7Client.js:243:40
at new Promise ()
at HL7Client.send (/mnt/Kingcolon/server/node_modules/hl7v2/lib/exchange/HL7Client.js:230:12)
at /mnt/Kingcolon/server/controllers/nhi.js:1027:28**

at /mnt/Kingcolon/server/controllers/nhi.js:1027:28
refters to
.then(() => client.send(msg);

   const testHL7 = async(body) => {
   const DEFAULT_VERSION = "2.5";
   const msg = new HL7Message({version: DEFAULT_VERSION});

   let segMSH = msg.add("MSH");
   segMSH._fields[1]._data = "^~\\&";  // Encoding Characters
   segMSH._fields[2]._data = "EVAS";  // Sending Application
   segMSH._fields[3]._data = "KKK";  // Sending Facility
   segMSH._fields[4]._data = "DCM4CHEE";  // Receiving Application
   segMSH._fields[5]._data = "KKK";  // Recieving Facility
   segMSH._fields[6]._data = `${moment2(new Date()).tz("Asia/Taipei").format("YYYYMMDDHHMMSSZ")}^S`;  
   segMSH._fields[8]._data = "OMI^O23^OMI_O23";  // Message Type
   segMSH._fields[9]._data = "YYYMMDD_patient_no_Type";  // Message Control ID  // ??
   segMSH._fields[10]._data = "T";  // Processing ID, T for training, P for production, D for debugging
   segMSH._fields[11]._data = "2.5";  //Version ID
   segMSH._fields[17]._data = "UNICODE UTF-8";
   
   let segPID = msg.add("PID");
   segPID._fields[1]._data = "patient_no_903874";  // Patient ID -> 病例號
   segPID._fields[2]._data = "K223984446";  // Alternate Patient ID - PID -> 存放病例號
   segPID._fields[4]._data = "林美惠";  // Patient Name -> PID.5.2: Given Name
   segPID._fields[6]._data = `${moment2(new Date("1955-01-23")).tz("Asia/Taipei").format("YYYYMMDDZ")}^D`;  
   segPID._fields[7]._data = "F";  // Sex

   let segPV1 = msg.add("PV1");
   segPV1._fields[1]._data = "O";  // Patient Class -> O stands for Outpatient

   let segORC = msg.add("ORC");
   segORC._fields[0]._data = "NW";  // Order Control, NW stands for New order/service
   // segORC._fields[1]._data = `^IHE_OM_OP^1.3.6.1.4.1.12559.11.1.2.2.4.2^ISO`;  // Placer Order Number
   // segORC._fields[2]._data = `^IHE_OM_OP^1.3.6.1.4.1.12559.11.1.2.2.4.2^ISO`;  // Filler Order Number
   segORC._fields[4]._data = "SC";  // Order Status, SC stands for "In process, scheduled"
   segORC._fields[6]._data = `^20221118&D`;  // Quantity/Timing, ORC.7.4: Start Date/Time

   let segOBR = msg.add("OBR");
   segOBR._fields[1]._data = `^IHE_OM_OP^1.3.6.1.4.1.12559.11.1.2.2.4.2^ISO`;  // Placer Order Number
   // segOBR._fields[2]._data = `^IHE_OM_OP^1.3.6.1.4.1.12559.11.1.2.2.4.2^ISO`;  // Filler Order Number
   segOBR._fields[3]._data = `28017C^coloscopy^Taiwan NHI^2^腸鏡`;  // Universal Service Identifier 
   segOBR._fields[15]._data = `C133225490^doctor name`;  // Ordering Provider 
   segOBR._fields[44]._data = `28017C^coloscopy^Taiwan NHI^2^腸鏡`;  // Procedure Code 

   let segIPC = msg.add("IPC");
   segIPC._fields[4]._data = "ES";  // Modality

   // connection
   const client = new HL7Client();
   client.setKeepAlive(true);
   client.connect(2575, "192.168.0.114")
       .then(() => client.send(msg)
   );

   return;
}

Documentation

Excuse me I am new here, my new task need hl7v2 to send message to PACS, could you tell me how to use this package? There is no document or examples...

Default message timezone support is missing

Noticed that according to the HL7 specification (see e.g. https://hl7-definition.caristix.com/v2/HL7v2.5/Fields/MSH.7) if the MSH.7 - Date/Time Of Message field of the message header specifies a timezone it should be used as the default timezone for the rest of the date/time fields of the message. This feature is not implemented by the library and cannot be implemented outside of it as the current implementation eagerly parses all date & date/time fields to JavaScript Date objects assuming UTC timezone if none is specified in situ in the field itself.

The following failing test cases demonstrate the issue:

  it('should apply message header timestamp timezone to date fields in other segments', function() {
    const msg = HL7Message.parse('MSH|^~\\&|||||201506301532.123+0300|||||2.5\r' +
        'AL1|1|||||20151231\r');
    const seg = msg.getSegment('AL1');
    assert.deepStrictEqual(seg.IdentificationDate.value, new Date('2015-12-31T00:00:00.000+0300'));
  });

  it('should apply message header timestamp timezone to time fields in other segments', function() {
    const msg = HL7Message.parse('MSH|^~\\&|||||201506301532.123+0300|||||2.5\r' +
    'TQ1||||134523');
    const seg = msg.getSegment('TQ1');
    assert.deepStrictEqual(seg.ExplicitTime.value, new Date('0000-01-01T13:45:23.000+0300'));
  });

  it('should apply message header timestamp timezone to date time fields in other segments', function() {
    const msg = HL7Message.parse('MSH|^~\\&|||||201506301532.123+0300||SIU^S12|||2.5\r' +
        'SCH||||||NW^Booking appointed|||||^^20^20150830080000||||||||||||||||\r');
    const seg = msg.getSegment('SCH');
    assert.deepStrictEqual(seg.AppointmentTimingQuantity[0].StartDateTime.value, new Date('2015-08-30T08:30:00.000+0300'));
  });

Test output:

should apply message header timestamp timezone to date fields in other segments:

      AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
+ actual - expected

+ 2015-12-31T00:00:00.000Z
- 2015-12-30T21:00:00.000Z
           ^
      + expected - actual

      -[Date: 2015-12-31T00:00:00.000Z]
      +[Date: 2015-12-30T21:00:00.000Z]

should apply message header timestamp timezone to time fields in other segments:

      AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
+ actual - expected

+ 0000-01-01T13:45:23.000Z
- 0000-01-01T10:45:23.000Z
              ^
      + expected - actual

      -[Date: 0000-01-01T13:45:23.000Z]
      +[Date: 0000-01-01T10:45:23.000Z]

should apply message header timestamp timezone to date time fields in other segments:

      AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
+ actual - expected

+ 2015-08-30T08:00:00.000Z
- 2015-08-30T05:30:00.000Z
              ^
      + expected - actual

      -[Date: 2015-08-30T08:00:00.000Z]
      +[Date: 2015-08-30T05:30:00.000Z]

Example client & server - with some code

Hi,

I am still working on your hl7v2 implementation because it seems very professional and covering most aspects. Just lacking some documentation and examples ;-)

I created a sample-client.js and a sample-server.js based mostly on your tests. It's not perfect as the server is not sending ack yet and client therefore doesn't close it's connection.

Question: Can the library automatically create ACK or ERR based on the input message? How?

//sample-server.js
const {HL7Message, HL7Server, HL7Client, createServer, connect} = require('hl7v2');

 server = new HL7Server();
 server.listen(8080).then(() => {
    console.log('Listening')
    server.use((msg) => {
        // print received HL7v2
        console.log(msg.toHL7().replace(/\r/g, "\r\n"));
        // print decoded structure
        console.log(JSON.stringify(msg, null, 4));

        // simulate database write ;-)
        var ok = Math.random() >= 0.5;
        if (ok) {
            // send ACK
        } else {
            // send ERR
        }

    });
});
//sample-client.js 
const {HL7Message, HL7Server, HL7Client, createServer, connect} = require('hl7v2');
const {EventEmitter} = require('events');

const msg1 = `MSH|^~\\&|LCS|LCA|LIS|TEST9999|19980731153200||ORU^R01|1234|P|2.2
PID|2|2161348462|20809880170|1614614|20809880170^TESTPAT||19760924000000|M|||^^^^00000-0000|||||||86427531^^^03|SSN# HERE
ORC|NW|8642753100012^LIS|20809880170^LCS||||||19980727000000|||HAVILAND
OBR|1|8642753100012^LIS|20809880170^LCS|008342^UPPER RESPIRATORY CULTURE^L|||19980727175800||||||SS#634748641 CH14885 SRC:THROA SRC:PENI|19980727000000||||||20809880170||19980730041800||BN|F
OBX|1|ST|008342^UPPER RESPIRATORY CULTURE^L||FINALREPORT|||||N|F|||19980729160500|BN
ORC|NW|8642753100012^LIS|20809880170^LCS||||||19980727000000|||HAVILAND
OBR|2|8642753100012^LIS|20809880170^LCS|997602^.^L|||19980727175800||||G|||19980727000000||||||20809880170||19980730041800|||F|997602|||008342
OBX|2|CE|997231^RESULT 1^L||M415|||||N|F|||19980729160500|BN
NTE|1|L|MORAXELLA (BRANHAMELLA) CATARRHALIS
NTE|2|L|HEAVY GROWTH
NTE|3|L|BETA LACTAMASE POSITIVE
OBX|3|CE|997232^RESULT 2^L||MR105|||||N|F|||19980729160500|BN
NTE|1|L|ROUTINE RESPIRATORY FLORA
`.replace(/\n/, '\r');

const ev = new EventEmitter();
let receivedData = [];
  
function listenerOnData() {
    if (receivedData.length)
        return Promise.resolve(receivedData.shift());
    return new Promise(resolve => {
        ev.once('data', () => {
            return resolve(receivedData.shift());
        });
    });
}

client = new HL7Client();
client.connect(8080, {host: 'localhost', timeout: 1000}).then(() =>
    client.send(msg1).then(() =>
        listenerOnData().then(data => {
            console.log(data);
            client.close();
        })
    )
);

How to process all ADT messages?

The examples only "listen" to a single message type, like server.use(('ORU^R01', oru) => {.

Is it possible to set up a handler for all messages or a group of messages like 'ADT'?

Set HL7 dictionary version when receiving a message

Hi,
When creating a message I use this code to define the dictionary to use
const ack = new HL7Message({version: '2.3.1'});

But when I listen for an HL7 message the default dictionary is always 2.5, how to set this to 2.3.1,

Thanks

\n replace in test message

To me it looks like the test message in test/09_server.js is only replacing a single occurrence of \n:

const sampleMessage1 = `MSH|^~\\&|LCS|LCA|LIS|TEST9999|19980731153200||ORU^R01|1234|P|2.2
...
NTE|1|L|ROUTINE RESPIRATORY FLORA
`.replace(/\n/, '\r');

Shouldn't it be .replace(/\n/g, '\r');

Can't send the HL7v2 message to DCM4CHEE

I tried HAPI TestPanel ([]https://hapifhir.github.io/hapi-hl7v2/hapi-testpanel/) to assembly the message which project needs and send the message successfully to DCM4CHEE (192.168.0.109:2575). Now, I tried to assembly the HL7 message usuing HL7v2 and send the message to DCM4CHEE. However, I can't see any study in DCM4CHEE MWL. I check the connection between DCM4CHEE and my dev environment, the response said true and no further error message. And I tried to read the test module again and tried something out, no successful work. And then, I don't know what to do. Would you please kind help me out?

    const testHL7 = async() => {
    console.log("testHL7");
    const DEFAULT_VERSION = "2.5.1";
    const msg = new HL7Message({version: DEFAULT_VERSION});

    let segMSH = msg.add("MSH");
    segMSH.FieldSeparator.value = "|";
    segMSH.EncodingCharacters.value = "^~\\&";  // Encoding Characters
    segMSH.SendingApplication.value = "EVAS";  // Sending Application
    segMSH.SendingFacility.value = "Kenkone";  // Sending Facility
    segMSH.ReceivingApplication.value = "DCM4CHEE";  // Receiving Application
    segMSH.ReceivingFacility.value = "dcm4chee-arc";  // Recieving Facility
    segMSH.DateTimeOfMessage.value = `${moment2(new Date()).tz("Asia/Taipei").format("YYYYMMDDHHMMSSZ")}`;  // Date/Time of Message
    segMSH.MessageType.value = "OMI^O23^OMI_O23";  // Message Type
    segMSH.MessageControlId.value = "1111215_903874_2";  // Message Control ID
    segMSH.ProcessingId.value = "T";  // Processing ID, T for training, P for production, D for debugging
    segMSH.VersionId.value = DEFAULT_VERSION;  //Version ID
    // segMSH.CharacterSet.value = "unicodeutf8";  // Try UNICODE UTF8 -> said "Encoding not recognized: 'UNICODE UTF-8'"
    
    let segPID = msg.add("PID");
    segPID.PatientId.value = "K223984446";  // Patient ID -> 身分證字號
    segPID.PatientIdentifierList.value = "903874";  // Patient Identifier List -> 存放病例號
    segPID.PatientName.value = "^林芳芳";  // Patient Name -> PID.5.2: Given Name
    segPID.DateTimeOfBirth.value = `${moment2(new Date("1955-01-23")).tz("Asia/Taipei").format("YYYYMMDDZ")}^D`;  // Date/Time of Birth  // Date/Time of Message //!!時區,時間格式對 PACS 的影響
    console.log("segPID.DateTimeOfBirth.value:", segPID.DateTimeOfBirth.value);
    segPID.AdministrativeSex.value = "F";  // Sex

    let segPV1 = msg.add("PV1");
    segPV1.PatientClass.value = "O";  // Patient Class -> O stands for Outpatient

    let segORC = msg.add("ORC");
    segORC.OrderControl.value = "NW";  // Order Control, NW stands for New order/service
    segORC.OrderStatus.value = "SC";  // Order Status, SC stands for "In process, scheduled"
    segORC.QuantityTiming.value = `^^^20221220&D`;  // Quantity/Timing, ORC.7.4: Start Date/Time

    let segOBR = msg.add("OBR");
    segOBR.OrderingProvider.value = `B205004830^^3`;  // Ordering Provider -> 開單醫師 id
    segOBR.ProcedureCode.value = `28017C^Coloscopy^999NHI`;  // Procedure Code -> 醫令代買

    let segIPC = msg.add("IPC");
    segIPC.AccessionIdentifier.value = "20221215GH937566";  // Accession No
    segIPC.RequestedProcedureId.value = "20221215GH937566";  // Requested Procedure ID
    segIPC.ScheduledProcedureStepId.value = "2";  // Scheduled Procedure Step ID -> 原接醫院的醫令代碼寫在這裡
    segIPC.Modality.value = "ES";  // Modality
    segIPC.ProtocolCode.value = "28017C^Colonscopy^999NHI";  // Protocol Code

    // 連線
    const ev = new EventEmitter();
    // const sockets = new Set();
    // console.log("ev:", ev);
    // console.log("sockets:", sockets);

    let receivedData = [];
    function listenerOnData() {
        if (receivedData.length)
          return Promise.resolve(receivedData.shift());
        return new Promise(resolve => {
          ev.once('data', () => {
            return resolve(receivedData.shift());
          });
        });
      }

    const client = new HL7Client();
    client.setKeepAlive(true);
    client.connect(2575, "192.168.0.109")
        .then(() => console.log("AisConneted:", client.connected))
        .then(() => client.send(msg))
        .then(() => console.log("BisConneted:", client.connected))
        .then(() => listenerOnData()
        .then(data => { console.log(data);})
        .then(() => client.close())
        .then(() => console.log("\(should be closed\)isConneted:", client.connected))
        .catch(e => console.log(e))
    );
    
    console.log("after testHL7 message");
    

    return msg;
    // return (client.connect(2575, '"192.168.0.114"));
}

Cannot find module '/dictionary/2.3.1'

const msg = new hl7v2.HL7Message() msg.add('MSH')

The above statements are causing me to crash getting cannot find module '/dictionary/2.3.1'

I looked into my node_modules and see the dictionary folder is created. I'm unsure if I have just missed a setup step or if there is actually a bug here.

Time fractions (ms) not decoded from Date/Time and Time

I've tested my HL7 implementation with IHE servers (Gazelle), where in the header I've got the following values:
MSH|^~&|PatientManager|IHE|MyApp|MyFacility|20190521132215.844+0200||ACK^Q23^ACK|64321|P|2.5
This message could not be decoded due to the fraction in the Date/Time field, thus I got a timeout instead of being able to process the message.

I think the TS_PATTERN and TM_PATTERN regex are responsible for that in helpers.js.
Once fixed, the message could be handled as intended.

"Encoding not recognized" error message

During testing with various messages I sometimes get an error message:

ERR|^^^&Encoding not recognized: '' (searched as: '')

This is not a string I can find in the source, and I saw that encoding should default to utf-8.

Do you know where this is coming from?

Add component to a field

Hi,

I can't figure out how to construct this segment

DSP|3||58^59^^|||

the code seems to escape the ^ character and not create a component to the field.

Thanks

Custom (Z) segment support

It seems the library does not currently support custom HL7 segments i.e. the so called Z-segments. When a message with a Z-segment is passed to HL7Message.parse an error is thrown (such as ParseError: Unknown HL7 segment type (ZDS)).

Do you have plans of building support for custom segments or thoughts on how the support should be implemented?

How to return two HL7 messages in one callback

Hi,

The client sends Query Request to the server, the latter has to send ACK message and a separate response message at the same time? How can that be acheived? nesting server.use((req) => { ... }); does not work.

Any Example on how to use it

Hello!

I just a have quick question, do you happen to have any particular example on how to use your library? I was checking it and it seems pretty nice however I'd like to know if you have any example on how to use it? I appreciate your time

Include an example server.js

A simple 10 line example server.js to receive messages and print them to console would help.

// not working!
const {HL7Message, HL7Server, HL7Client, createServer, connect} = require('hl7v2');
let server = new HL7Server();  
server.listen(7777).then(() => {
    console.log('Listening')
    server.use((req) => {
        console.log(req.toHL7());
    });
    server.use(() => ack);
});

I looked at the tests as recommend (#4) , but could not get it to work.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.