C/S NPR Tip & DR/SQL Tip

Joe Cocuzzo, Senior Vice President – Report Writing Services

This month we have a quick tip for NPR fans (Client/Server only) and a SQL /DR tip written by Thomas Harlan my DR Technical Team Lead.  If only we had a RD tip, we’d have a trifecta.

C/S NPR Tip: Page 1 of N via MEDITECH utility program

We recently found out that MEDITECH has a utility you can call from the footnote of a report and print a Page X of Y message on your NPR reports. The utility is called:

%Z.rw.page.count(XPOS,YPOS,STRING) where

XPOS = KB article and program say this is X dot position @300DPI, but I think it is COL

YPOS = KB article and program say this is Y dot position, but I find it to be line of page header with first line =0

STRING is an option string to use for message, default is Page XX of YY, but you could send “Pg XX with exciting conclusion on YY” if you wanted a different message.

MEDITECH has a KB article on the utility: 47296. This utility is very handy, although it is not sufficient compensation for other sins of the Print Manager in C/S (no trays, no legal size paper, no print direction, no overlay macros, and so on).

Neither MAGIC nor RD has this feature. Years ago, we showed a way to do this for MAGIC that involved diverting print output to a file and doing a search/replace and then sending the data out to the printer. Back then (before print on VIEW), this worked even when spooling or downloading, but the technique needs updating for MAGIC to cope with spooling’s multiple SAFs (one per page to support VIEW).  Stay tuned for an updated MAGIC report showing how to do Page X of Y including when spooling.

If you just stick a footnote on your report like this:

You’ll get this on your page header:

DR/SQL Revamping ADM Patient Events into Patient Flow

One of the challenges in working with data structures developed for NPR (or M/AT) in the DR is that both NPR and M/AT retrieve data via a loop, while DR expects things to be arranged so they can be fetched in a set. A good example of this is AdmVisitEvents.

AdmVisitEvents has multiple kinds of data embedded within one table, including when the patient is bedded, and then moved from room to room, and then discharged.

Inevitably you’ll need to pull an inpatient location at a point in time and there won’t be a handy field with the Location/Room/Bed where the patient was when something occurred. And when you turn to AdmVisitEvents to find that situational information… you realize that the structure of the table is just not what you want.

The immediate way to get the patient Location is to embed a sub-query into your main SQL SELECT to fetch the patient Room:

SELECT TOP 1 AVE.LocationID

FROM   Livedb.dbo.AdmVisitEvents AVE

WHERE RX.SourceID = AVE.SourceID

AND RX.VisitID = AVE.VisitID

AND  AVE.UndoneSeqID IS NULL

AND  AVE.EffectiveDateTime <= RXA.AdministrationDateTime

AND  AVE.LocationID IS NOT NULL

ORDER BY AVE.EffectiveDateTime DESC, AVE.EventSeqID DESC

(In this snippet, we’re starting from PhaRx (RX) / PhaRxAdministrations RXA) to find the patient unit at the time of a medication administration.)

This answers the immediate question — where was the patient at the time of the administration. But it has issues… first, with a sub-query structured this way, we can only get one (1) field back (LocationID), and second, we have to create a loop in SQL (which SQL does not perform terribly well) with that ORDER BY and TOP 1 structure.

If we wanted to get LocationID, RoomID, and Bed in three separate fields – we would have to do three sub-queries, each returning one field. And as we add more sub-queries, the performance of our report begins to drop off precipitously!

What we want instead is a way to get at the AdmVisitEvents data so that we can JOIN to a table where each patient flow event (a stay in a location/room/bed) is in a single row, so we can do something like:

LEFT JOIN #tFlow ADT ON ( ADT.VisitID = RX.VisitID

AND ADT.SourceID = RX.SourceID

AND RXA.AdministrationDateTime >= ADT.FromDateTime

AND RXA.AdministrationDateTime <= ADT.ThruDateTime )

That is very clean! And now any field we need from #tFlow, we can reference in our query via the ADT alias — and since no sub-queries are involved, it’s fast.

The challenge now is creating this #tFlow table when we need it. And we only want to write that code once, in a reusable way. We need either a stored procedure or a table-valued function to go process AdmVisitEvents for us and create a nice flattened temporary table we can use.

You can download a copy of IatricPatientFlow.sql from iWeb and implement it on your DR server to get a pre-packaged function to do just this. That table-valued function works like so:

  1. First we look for any patient in-house during the date range we are interested in.
  2. Then we take that list of patient visits and fetch all of their Events into a temp table. When we do that, we only look for Events with a Location, that are not un-done, are not ‘FIXED’ records, and there are some kind of Event codes that are excluded.
  3. We sweep that raw list of Events and look for events where there is a change of location or status, and we create yet another temp table that captures the start and end times of the patient being in a specific place.
  4. Finally we create our nice summary table and address some data quirks where the last patient status isn’t correct (unless we correct it… ) and extra discharge rows are discarded.

That process takes a set of Event data that looks like this:

EffectiveDateTime

NewLocationID

NewRoomID

NewBed

NewStatus

OldLocationID

OldRoomID

OldBed

OldStatus

2014-01-20 18:29:00

ED

REG ER

2014-01-21 03:22:00

IC

ICU01

1

ADM IN

ED

REG ER

2014-01-21 21:50:00

M/S

MS24

1

ADM IN

IC

ICU01

1

2014-01-22 05:17:00

IC

ICU01

1

ADM IN

M/S

MS24

1

2014-01-22 14:50:00

M/S

MS16

1

ADM IN

IC

ICU01

1

And makes it look like this:

FromDateTime

ThruDateTime

VisitStatus

LocationID

RoomID

Bed

StayInMinutes

2014-01-20 18:29:00

2014-01-21 03:21:59

REG ER

ED

MS16

1

533

2014-01-21 03:22:00

2014-01-21 21:49:59

ADM IN

IC

ICU01

1

1,108

2014-01-21 21:50:00

2014-01-22 05:16:59

ADM IN

M/S

MS24

1

447

2014-01-22 05:17:00

2014-01-22 14:49:59

ADM IN

IC

ICU01

1

573

2014-01-22 14:50:00

2014-01-26 12:15:00

DIS IN

M/S

MS16

1

5,605

At any given point in time during the stay, we can then immediately find which Location, Room, Bed, and Status. We also get a summary of the time spent in the location.

To use this, in your reporting stored procedure (you are using a stored procedure for each report, aren’t you?) you create a little on-the-fly temp table:

SELECT ADT.*

INTO   #tFlow

FROM   zcus.dbo.IatricPatientFlow( ‘IAT’      — Change to your site SourceID to test

,’IATRIC’  — Change to your facility ID to test

,’2014-01-01′

,’2014-01-31′ ) ADT

;

And then use the JOIN above to bring that data into your query.

Don’t forget to clean up afterwards at the end of your stored procedure!

DROP TABLE #tFlow ;

Performance Note: The patient flow function runs at a test site, with 1.3 million rows in AdmVisitEvents, for a month of visits, in three seconds. It could have a bit better performance after being recast as a stored procedure using temp tables (rather than variables) inside IatricPatientFlow, but then it would require more setup and cleanup code, and could not be nested as deeply as a function.

Extra Credit! You can adapt the code to break out the patient by the day, calculating their stay in each location by day, which then makes calculating Patient Day Equivalent metrics for Nursing Quality Measures very easy.

The SQL code has been uploaded to our report library as IatricPatientFlow.txt.

Visit our report library at http://www.iatric.com/Information/NPRReportLibrarySearch.aspx to look them up.

You can find additional Report Writing Tips on our website at http://www.iatric.com/Information/NPRTips.aspx, as well as information about our on-site Report Writer Training and Report Writing Services.

To subscribe for email notifications for new Report Writing classes, please follow this link:

http://www.iatric.com/Information/Classes.aspx.

For more information, please contact Karen Roemer at 978.805.3142 or email
karen.roemer@iatric.com
.

This article originally appeared in the April 2014 issue of Iatric Systems Updates! newsletter.)

Report Writing Tip: March 2014 – Run Report for Period without prompting for date range (Client/Server or MAGIC)

Joe Cocuzzo, Senior Vice President – Report Writing Services

Run Report for Period without prompting for date range (Client/Server or MAGIC)

It is common to have a report that should be run for a GL period (here we assume this is a calendar month) and the easiest way to program this is to prompt for a date range and let the user figure out how many days in the month. You can add some error checking to reject an ending date that is not the last day of the month with an “FCL” attribute, but another approach would be to prompt them for the GL period and write some code to get the start and end dates based on the period selected.

This month we will show you how to add this programming to your report in a “start” macro and, for extra credit, show how to have the report run automatically for the prior month for the case where it is scheduled to run after month end.

First we set up a report with a date based index, in this example we want to go through BAR transactions in BAR.BCH:

MAGIC:

NPT Tip

Client/Server:

NPT Tip

Next we set up selections to prompt for a period, to restrict to “RCP” transactions, and to limit the report to a date range we will create from the GL period selected.

NPT Tip

We need to write a small “start” macro to use the period that the user has selected to put the start date of the period in /FROM and the end date in /THRU.

When you prompt for field, the value supplied by the user at run time is stored in the temp file and the value is stored in a variable which has a name based on a “b”, “c” or “e” based on the selection operator. “b” for GT and GE. “e” for “LT and LE” and “c” for EQ or IG. When you are prompting for a field that is in some other DPM (not the DPM of the report), the screen translator puts the “b”, “c”, or “e” after the DPM.

So we will have the user selected period in MIS.GL.PERIOD.c.period.

All we need to do is to put that value into MIS.GL.PERIOD.period (the subscript of the GL period dictionary) and then we have the ending date in @MIS.GL.PERIOD.ending.date to put into /FROM.

Then cut the YYYYMMDD off  that value (using $6) and add a “01″ and you have the start date to put in /THRU.

NPT Tip

Then add a footnote to call the macro at “START”

The AL = ALGORITHM, the START is where the code gets called and “start” is the name of the macro on this report that is going to be incorporated into the report program by the translator at the “start” point (after printer and some report setup, but before any looping on indexes and record selection).

NPT Tip

You might think this footnote is from the Department of Redundancy Department, but it actually is far better (in my opinion) to name your macros based on where they are called (or included in report translation) than with some invented name about what they do.

Two advantages:

  1. If you look at a report written by someone else, you know that a macro called “detail” is called per record. If you see a macro called “guts” and another called “process” what does that tell you about where the code is executed?
  2. After you write the macro and are about to write the footnote reference, with my method you do not have to remember what you just called the macro, you just have to remember what you always would call it.

Extra Credit:

What if you schedule the report for the 5th day of the next month, allowing five days for any Month End snafus. How can we have the report run from the scheduler and automatically run for the prior month?

There is a scheduler convention to run for a calendar month, including a way to run for the prior calendar month, but I do not think there is a “prior period” convention, so we’d need to created a date range prompt version of the report to get that functionality.  Instead, we can schedule the report with no period selected and modify our macro code to automatically run for the prior month.

In keeping with the MEDITECH practice of creating small annoying differences in the report writer between platforms, if you use the IG operator in MAGIC, the fields remains required, but if you use IG in C/S the field is optional.  So, in MAGIC we need to go into the “Edit Elements” routine and change REQ=1 to REQ=N or REQ=”” to avoid:

NPT Tip

NPT Tip

NPT Tip

If we look at the C/S version of the report we see that the screen translator has already done things this way for us:

NPT Tip

Now we need to modify our “start” macro so we use the MIS.GL.PERIOD.c.period selected if the report was run by the user (and a period was selected) or we use the current date and figure out the prior month if no period is selected. This adds a bit of convenience for the user because if they typically run for the prior month, then they can just leave the period blank and run the report and it will automatically do this.

First we write an IF statement and call two “sub-macros” based on whether we detect a period in the temp field or not. The way to break your macro into sub-macros is to call the submacro using an @ sign followed by some label, which should be all upper case with no spaces. Then these submacros are in the macro code separated by a single blank line and the same label with no leading @. This makes your code more readable and easier to maintain. Also you can use the same sub-macro in multiple places. You can nest these calls and have a macro call a sub-macro which then calls another sub-macro.

Warning – do not create infinite recursion like this:

IF{CONDITION  @SUBMACRO}

SUBMACRO

@DO.STUFF

DO.STUFF

@SUBMACRO

If you do this, your translation will crash. If you submerge the translation, you can run your (MAGIC at least) system out of space.

Here is our new macro (C/S version, but MAGIC is identical) with the code to run for either the selected period or the prior month when no period is selected:

NPT Tip

So if we run the report for no period:

NPT Tip

Or if we run the report for a user-selected period:

NPT Tip

This example report BAR.BCH.zcus.is.eupdate.run.for.period has been uploaded to both our MAGIC and C/S report libraries.

Visit our report library at http://www.iatric.com/Information/NPRReportLibrarySearch.aspx to look them up.

You can find additional Report Writing Tips on our website at http://www.iatric.com/Information/NPRTips.aspx, as well as information about our on-site Report Writer Training and Report Writing Services.

To subscribe for email notifications for new Report Writing classes, please follow this link:

http://www.iatric.com/Information/Classes.aspx.

For more information, please contact Karen Roemer at 978.805.3142 or email
karen.roemer@iatric.com
.

This article originally appeared in the January 2014 issue of Iatric Systems Updates! newsletter.)

Report Writing Tip: January 2014 – NPR Hot Key Report to See Activity (MAGIC only)

How often do you need to go change something about “the census report” only to go into Process Reports and see the following in your lookup:

Image

Most of you know that you can get out of Process Reports, and then go over to #57 “List Report Usage” on the customization menu:

Image

It isn’t terribly convenient to go over to this other option, and then deal with the never wanted BEGINNING/END defaults that MEDITECH application programmers like to include in standard reports:

Image

We can delete out the BEGINNING and type in the first of our list of suspects, then delete out the END and put in the last of our list (assuming no squirrels have run past our office window, causing distraction and loss of report internal name from short term memory).

Image

For the MAGIC platform, we can create a report in NPR.REP that can go on an NPR “hot key” menu and automatically use the last DPM and last procedure from the temporary file to provide an much more convenient activity list.

Image

We write our NPR report in the usage log segment:

Image

We can take advantage of the “spacebar – return” feature of Process Reports on the MAGIC platform, where the last DPM and the last procedure edited are kept in /.SV.DPM and /.SV.PROC respectively.

We set up selections on Page 2 for a report range:

Image

Then we can use the “Edit Elements” routine to add custom defaults.

Image

For the start of the default range, we use this:

Image

Note that unlike for CDS default attributes, you use DFT2 (not DFT).

For the end of the range we add a “zzz” to the procedure, and loop backward 1x on the procedure global to be likely to get all the copies of the report without having to type our own range.

Image

If we go to our hot key menu while editing “ADM.PAT.zcus.is.census.report”,” we get the following default range of reports:

Image

We build a simple report to list the title and procedure urn in a header and the saved activity in the detail line. We need to use two computed fields to deal with the fact that the run.time field is an “S(0)” time stamp, holding the number of seconds since March 1, 1980. To change this into a date, we use the Z program %Z.date.in.magic(run.time) in a “DATE” type computed field:

Image

You might wonder why there is no @ sign on the field @run.time. You can actually write it either way, since it is a subscript of the report activity segment, @run.time and run.time (with no @ sign) translate to exactly the same local variable.

For an HHMM (time) field from the S(0) run.time value, we use %Z.time.out(run.time):

Image

The @run.user and @run.dir are just fields and we can use the possessive @run.user’s.name also.

When we run the report for the default range, we can see that the ADM.PAT.zcus.is.census.report2 is the current version:

Image

The NPR.REP.zcus.is.hot.key.report has been uploaded to our MAGIC report library. Unfortunately, Client/Server does not have “hot key” menus and does not have the “spacebar return” recall feature. You can launch a new MEDITECH session from the session management button, but managing to peek back at the original session and figure out which report was being processed is just too hard, sorry!

Visit our report library athttp://www.iatric.com/Information/NPRReportLibrarySearch.aspx to look them up.

You can find additional Report Writing Tips on our website athttp://www.iatric.com/Information/NPRTips.aspx, as well as information about our on-site Report Writer Training and Report Writing Services.

To subscribe for email notifications for new Report Writing classes, please follow this link:
http://www.iatric.com/Information/Classes.aspx.

For more information, please contact Karen Roemer at 978.805.3142 or email karen.roemer@iatric.com.

This article originally appeared in the January 2014 issue of Iatric Systems Updates! newsletter.)

Report Writing Services: December 2013 – NPR Sunday Puzzler solved with NPR report (MAGIC example)

Joe Cocuzzo, Senior Vice President – Report Writing Services

NPR Sunday Puzzler solved with NPR report (MAGIC example)

There is a “Sunday Puzzler” feature of Weekend Edition on NPR Radio on Sundays. The host is Will Shortz, crossword editor of the New York Times.  Occasionally, he provides a puzzle that can be solved by exploiting MAGIC string operators and the spell check dictionary, or this week, using the Zip code dictionary and a specially rigged MPI.

The listener challenge from December 8th; deadline for submission Thursday, December 12th at 3pm ET.

“Next week’s challenge from listener Pete Collins of Ann Arbor, Michigan: Name a U.S. city in nine letters. Shift the third letter six places later in the alphabet. Then shift the last letter seven places later in the alphabet. The result will be a family name featured in the title of a famous work of fiction. What is the city, and what is the family name?”

We have, in effect, a dictionary of US cities in the MIS.ZIP dictionary and we can check the MRI name index for a last name match to find family names that might solve the puzzle. We will need to cheat a bit on the last count.

First we write an MRI.PAT report using the “actual.name.index” as follows:

Image 1

We set up the report so that we do an LI selection against a list of last names:

Image 2

Next, we write a start macro that loops through all the zip codes in MIS.ZIP, picking out all the cities that are nine characters long, and then changing the 3rd and the 9th character as specified and trying to match that new string to any last names in the MPI.

If we get a match, we will build a structure like this:

CITY^/LAST[NEWSTRING]  where NEWSTRING has a 3rd and 9th character changed per the puzzle rules.

Hint: I started the report at a hospital in Oregon that appeared to have a complete Zip code dictionary, but found it lacking and had to move the report to a Michigan hospital to solve the puzzle.

The first part of the macro creates a list of nine character cities in a temporary array:

Image 3

Remember that MAGIC numbers characters in a string starting from zero, so when we need to change the 3rd and 9th characters, we get the characters like this:

CITY#2 = third character

CITY#8 = ninth character

Before we change the string, we change it to all upper case like this:

@MIS.ZIP.city~$L.TO.U^CITY

The ~ is the translate operator and the $L.TO.U is a system string for MAGIC hospitals that will allow the translate to change a to A, b to B, and so on.

In C/S you would use the @Trl2u function like this:

@MIS.ZIP.city@Trl2u^CITY

We are supposed to move six down the alphabet for the third character (A becomes G, for example) and seven down the alphabet for the ninth character.

If we take the E(ncode) value of the third character and add six and then take the D(ecode) of that number, we will move six “down” the alphabet.  To avoid going past “Z” we check to make sure we are under 91 in the ASCII table.

We make a new string “NEWCITY” by using the $ and % operators to take everything to the left of the 2nd position $2, concatenating the new third character, then concatenating everything to the right of the 2nd position.

We do the same thing with the 9th character, but adding seven rather than six.  Because this is the last character, we can just do NEWCITY$8_CHAR^NEWCITY to make the final change.

Image 4

The final step is to use the new string in the actual name index as the “last.name.indexed” subscript and use the @First() operation to see if there are any patients with that last name in the MPI. You could also use @Next if you did it like this:

NEWCITY^last.name.indexed

“”^first.name.indexed,

IF{@Next(first.name.indexed,@actual.name.index) CITY^/LAST[last.name.indexed]}

@First loops from nil and does not assign back to the subscript

Looking at the object code for @First vs @Next will illustrate:

Image 5

If we run this report in just the right hospital (with a certain city in the Zip code dictionary) and just the right set of folks in the MPI, we can solve the puzzle:

Image 6

You have until Thursday 3pm ET to submit an entry.

I actually gave up on the cities in the Oregon hospital’s zip code dictionary after reviewing all the changed nine character strings manually and finding no likely solutions. Next, I got a list of US cities from some internet crossword puzzle dictionary and ran the string transformation against that list and saw that I’d need to find a customer in Michigan and also register some of just the right brothers in their test MPI to get my puzzle report to work.

Visit our report library at http://www.iatric.com/Information/NPRReportLibrarySearch.aspx to look them up.

You can find additional Report Writing Tips on our website at http://www.iatric.com/Information/NPRTips.aspx, as well as information about our on-site Report Writer Training and Report Writing Services.

To subscribe for email notifications for new Report Writing classes, please follow this link:

http://www.iatric.com/Information/Classes.aspx.

For more information, please contact Karen Roemer at 978.805.3142 or email
karen.roemer@iatric.com
.

This article originally appeared in the December 2013 issue of Iatric Systems Updates! newsletter.)

Report Writing Services: November 2013: Adding custom dictionary lookup with CH and GRP attributes (and how to mimic GRP= in Client/Server)

Adding custom dictionary lookup with CH and GRP attributes (and how to mimic GRP= in Client/Server)

by Joe Cocuzzo, Senior Vice President – Report Writing Services

When using the MAGIC NPR report writer, you have two choices if you want to have a custom lookup on a computed field. You can add a CH= (Choice) attribute using the Edit Elements routing from the Process Reports menu:

Image 1 Image 2

Or in MAGIC only, you can add a GRP=<group mnemonic> attribute to a computed field in the field attributes.

Image 3

Client/Server (C/S) supports the CH option but not the GRP= field attribute. This month we will describe the two options for MAGIC, and show how to duplicate the GRP feature with a custom ID program in C/S.

CH works well when you want to give the user a hardcoded set of choices. I like to use it if I am building a report with multiple output modes:

Here is how it looks when done (identical approach) in a C/S or 6.x site:

At times, however, you want to prompt the user for a selection from a Group Response dictionary in MIS. One example is if you are trying to allow the user to pick a particular group response element that you are going to compare to a query response to select records. Another example is where you want to create a special dictionary with a large number of entries that would not fit in a CH attribute string, which is limited to 255 characters.

In MAGIC, you can just create a computed select field, free text, length 10, and add a GRP= attribute.

Now the computed selection field presents the group response dictionary:

For C/S, the GRP= attribute is not supported, but you can get equivalent functionality by creating your own ID program (or using ours from the example report from this tip).

Remember, you can just USE this code as is (just change the group mnemonic at the top line to match the group you want to have for a lookup). The details below are for those interested in how the code actually works.

You write a macro as a program, and attach it view the “Edit Elements” option like this:

Image

There are two steps in the ID program; first we loop through the desired group dictionary and create a typical MEDITECH dictionary file in a temporary structure.

Step #1

We want to turn this:
Into This:

The MEDITECH generic ID program we want to use for the lookup wants a structure that looks like this:

/GLOBAL[subscript]|0 = Y (active flag) |1 = name |2 extra fields as needed

So it is easier to just loop through the group response dictionary and create a temporary structure than to write a non dictionary lookup program (or find one). Also, a group response dictionary is never going to be that big, so moving it to a temp file works fine.

Step #2
Next we set up some arguments and call the standard C/S dictionary lookup program. The program has the following arguments:

Z.id(A,B,C,D,E,F) where
A= “name of” the structure to do the lookup on. We build our temp dictionary in the example in /LI so, we pass ^LI in the “A” argument
B = the value the user entered before hitting F12 (that is passed into our ID program in variable A)
C = A queued string of column headers for the dictionary lookup
D = A queued string of expressions that will build the data for each column
E = “AR” for restrict to “A”ctive entries and “R”eject new entries. This is what you want, because you don’t want to have the user able to create new entries and file them.
F = A title for the lookup window

Here is the section of the macro that does this for our example report:

And here is how the lookup behaves:

We have uploaded the C/S version of ABS.PAT.zcus.is.eupdate.choices.and.grp to our report library. Visit:http://www.iatric.com/Information/NPRReportLibrarySearch.aspx to look them up.

You can find additional Report Writing Tips on our website athttp://www.iatric.com/Information/NPRTips.aspx, as well as information about our on-site Report Writer Training and Report Writing Services.

To subscribe for email notifications for new Report Writing classes, please follow this link:
http://www.iatric.com/Information/Classes.aspx.

For more information, please contact Karen Roemer at 978.805.3142 or emailkaren.roemer@iatric.com.

This article originally appeared in the November 2013 issue of Iatric Systems Updates! newsletter.)

Report Writing Tips – October 2013: Utility Report to Assist with Syntax Checker Changes – MAGIC, Client/Server or 6.x

Joe Cocuzzo, Senior Vice President – Report Writing Services

Utility Report to Assist with Syntax Checker Changes – MAGIC, Client/Server or 6.x

As most Report Writers are aware, the customer version of the NPR report writer includes a “syntax checker,” which does a string search of source code and a string search of object code to attempt to block commands that could delete or alter data.

Recently, MEDITECH became aware of a way code could be written that could result in changes to the database, and they have released a change to the checker that has the unfortunate side effect of disabling many innocent reports. We have had customers with tens to hundreds of reports affected. Most hospitals are getting this change along with a 5.66 update, but I believe it can be delivered in 5.64 as well.

It is very important to fix all affected reports that are still in use and move the fixed reports into your LIVE directory before MEDITECH runs the syntax checking job in LIVE, or you will have reports and  screens crashing due to broken reports.

In MAGIC, you will get two new routines on the NPR customization menu:

image 1

In C/S and 6x, you will get two new routines on the Reports menu:

image 2

Typically MEDITECH runs the first “Check Macro Syntax” background job and you may be a lucky winner and see many reports affected.

Here is a C/S site with 132 reports broken by the change:

image 3

Here is a MAGIC site with 784 reports broken:

image 41

Unfortunately, the “Print Syntax Results” routine does not include report activity, or allow you to limit the listing on some kind of usage basis, so you do not have an easy way to triage your fixing, to avoid wasting efforts on:

ADM.PAT.zcus.is.great.great.great.grandfather

ADM.PAT.zcus.is.great.great.grandfather

ADM.PAT.zcus.is.great.grandfather

ADM.PAT.zcus.is.grandfather

ADM.PAT.zcus.is.father

And you can just fix: ADM.PAT.zcus.is.son (provided sonny’s macros are local).

This month I will show how you can write (or how I have written) a report that allows you to restrict your list to reports with activity on or after some reasonable cut off date, and be reasonably sure that you have fixed all reports in use. Note that if you call report macros as programs from a CDS, that report will not have activity. You can check the CDS issue by trying to re-file the screens that might be affected in TEST after the syntax check has been run.

The reports I will describe can be used “as is” and should prove very useful for sites with many reports caught by the new syntax checking. You do not need to go through my detailed discussion of how the report is written, unless you are interested in the techniques I used, and furthering your geeky education.

The first step to duplicate the standard report is to look at the MEDITECH “Print Check Syntax Results” report that they deliver with this change.

We can list the customization menu from LIST REPORTS to see the name of the procedure: NPR.PROC.check.syntax.print.

Just for fun, we can try to initialize from this standard report:

image 5

At Iatric Systems, our slogan about the “Initialize Report from Standard” routine is:  “The More You Need It… The Less Likely It is to Work.”

In this case, it is not complex code and a difference between the two Report Writing tools that stops us, but the fact that MEDITECH set up the data segment they created to not allow access for the Customer Report Writer.

We can list the report and see that is uses a detail segment of NPR.PROC.check.syntax, and if we look at the data definitions with Programmer’s NPR we see:

image 6

While we are poking around on the MEDITECH side of the house, we might as well take the opportunity to copy (to the Windows Clipboard) the ID code from the compile # field (cs.urn) so we can use the same lookup in the Customer Report Writer report we are about to create:

image 7

This is an extra credit step, and we could have just prompted the user for an integer with no lookup and our custom version of their report would still have worked fine.

Ironically, the C/S lookup attribute is ID=%NPR.PROC.check.syntax.id(A), but the C/S syntax checker won’t let you call an NPR.PROC program. So your syntax checker report gets stuck on the syntax checker. The solution is to copy the source code into your own NPR.REP.zcus.is.rw.check.syntax.with.activity.M.id macro, add the NPR.PROC dpm to all the fields, and grumble to yourself about the whole unhelpful syntax checking situation.

How can we deal with the fact that the detail segment “check.syntax” cannot be used by the customer report writer? Since we can write a report in NPR.REP and get report data (urn of report, title, and activity), we can write a loop in a start macro to go thru the “check.syntax” segment, check activity in NPR.REP, and make a list of reports in slash that our NPR.REP based report can use for selection.

Both C/S and MAGIC reports can get data from segments set to “Cust R/W Access” = N, so we can write a start macro in NPR.REP and loop on all the reports found by the compile selected and then check last activity.

The MAGIC DPM lookup will even show you the segment and fields, and the segment information:

image 8

Unfortunately, the C/S field lookup program will not show segments flagged as unavailable, but you can still use them in a macro or computed field or line attribute.

Our MAGIC report in written in NPR.REP, with a detail segment of npr.rep.main.

Our C/S report is written in NPR.REP, with a detail segment of main.

image 9

In the selections we prompt for the compile number, select urn against a list in /URN, provide an option to include or omit activity, and allow the user to provide a “last run on/after” date.

image 10

The start macro of both reports (MAGIC or C/S) contains identical code:

image 11

Both reports use two ECB-ECE loops to print both the macros found by the syntax checker:

This loop goes thru the syntax checker data and prints the macro and the syntax message:

image 12

This loop prints activity:

image 13

Here is sample output from the C/S version of the report.

image 14

Remember, these reports are designed to be used “as is,” so even if you skimmed through this entire article to get the report names from the bottom note, you can take these and use them to cope with the recent syntax checker changes and possibly save significant time and trouble.

We have uploaded the MAGIC and C/S version of these reports to our report library under NPR.REP.zcus.is.rw.check.syntax.with.activity – visit: http://www.iatric.com/Information/NPRReportLibrarySearch.aspx to look them up.

You can find additional Report Writing Tips on our website at http://www.iatric.com/Information/NPRTips.aspx, as well as information about our on-site Report Writer Training and Report Writing Services.

To subscribe for email notifications for new Report Writing classes, please follow this link:

http://www.iatric.com/Information/Classes.aspx.

For more information, please contact Karen Roemer at 978.805.3142 or email
karen.roemer@iatric.com
.

This article originally appeared in theOctober 2013 issue of Iatric Systems Updates! newsletter.)

Report Writing Tips – September 2013: When is an Order Actually Two Orders? (Client/Server or MAGIC)

Joe Cocuzzo, Senior Vice President – Report Writing Services

When is an Order Actually Two Orders? (Client/Server or MAGIC)

Moving report detail segment to count the same record multiple times.

I recently had a site ask for a report listing all telephone or verbal orders, with an option to show just unsigned or both signed and unsigned orders.   The hospital wanted the option to sort by patient or by ordering provider.

This is a simple report (or so I thought), just select orders for an order date range and check to see that the source is “V” or “T”.

The site reported that I was “missing” some “verbal orders” and gave me an example, which actually looked like this:

The site thinks of this as two orders, an original written order from DAND, followed by a subsequent order (a stop order actually) by telephone by PCOWAN.

I can adjust the selection logic so that I pick up orders with a source of T or V, or an edit.pom.source of T or V, but I might need to list the same order on different dates and under different doctors. I can’t use the unsigned index because the report needs to be able to include both signed and unsigned orders.

Here is an example order that needs signing by two different doctors:

How can I get my report to print the same order under each doctor who either entered the order with a source of V or T, or edited the order with an edit.pom.source of V or T?

I have three options:

  1. Build an MV array for all my output, or some temporary structure that I loop through with an ECB-ECE loop.The disadvantage of this approach is that all my fields would need to be computed fields and automatic totaling with Z.count or FNC=TOT would not be available.
  2. Rewrite the temporary file to include the same order multiple times. This works well, but as the syntax checker blocks 1 ^/R.TF you need to code around the syntax checker, especially in MAGIC where1^ /[“temp”,SORT1,SORT2…] only works if the sort file stays under the MIS max records parameter and does not swap out to disk.
  3. Move the detail segment of the report from the main (where you get each order one time only) to the edit.data segment, and select the order if either of the following are true:- The edit.urn = 1 and the source is V or T

    - The edit urn >1 and the pom.edit.source is V or T

    In each case, test whether the user has asked for unsigned orders only and if they have, check to see if the order was subsequently signed by the appropriate doctor.

Option C seems best for this example.  Let’s see how the report should be written:

We set up the sorts as follows:

xx.sort1 sorts by doctor for the first edit transaction for provider sorting, by the @edit.pom.provider on all other transactions for provider sorting, and by patient name if name sorting is selected.

xx.sort2 sorts by patient name if you are doing primary sort by doctor, otherwise lets the orders list by edit.date by setting the sort at this level to a 1.

Remaining sorts are by edit.date, then urn, then edit.urn.

The selection is for an order date range, and then we have a computed selection field:

The xx.ck field calls a macro as a program, and passes the urn and the edit urn as arguments A and B:

We check each edit transaction. If we are on the first edit transaction that is the initial entry of the order, and we want to include the order if the @source is V or T. For additional flexibility, the user can elect to discard signed orders so we have some extra code to throw out signed orders by looping forward through subsequent transactions to see if the doctor did sign. Logic is similar for edits to orders, but for those we are checking for @edit.pom.source of V or T and checking the @edit.pom.provider to see if that doctor signed.

When we look for signing, we parse out the doctor from the “signed for” transaction with the % (right of) operator to get everything to the right of position 16 and for good luck we strip any leading and trailing spaces with :0S.

The final piece is to write a “detail” macro to loop forward to find the signed date and time and to calculate some elapsed time values and characterize the order as either not signed, on-time, or late.

The detail macro is attached with a footnote. For Client/Server only, you need to add a BUF NONE footnote. MAGIC would just have AL D detail:

In the C/S version of the report, you need to prevent “buffering” of the detail segment into a temporary structure. Otherwise, the detail macro looping code will loop on a temp structure that will only contain the one edit transaction that was selected by the report. Your code in the macro will be perfect, but will be changed when incorporated into the report itself (the .R program) and will not work at all to find signing transactions.

Here are the gory details (relevant to C/S only):

Macro source code: (written fine, should work)

Macro object code:

Report object code:

Then your macro also tries to loop on this temp:

If we add BUF NONE footnote:

Here is a sample of the report, with PHI removed. We show whether orders were signed within 72 hours and some percentages per doctor and for all doctors:

Client/Server and MAGIC version of this report OE.ORD.zcus.is.phone.and.verbal.orders2 are available on our website in our report library on our website: http://www.iatric.com/Information/NPRReportLibrarySearch.aspx.

You can find additional Report Writing Tips on our website at http://www.iatric.com/Information/NPRTips.aspx, as well as information about our on-site Report Writer Training and Report Writing Services.

To subscribe for email notifications for new Report Writing classes, please follow this link:

http://www.iatric.com/Information/Classes.aspx.

For more information, please contact Karen Roemer at 978.805.3142 or email
karen.roemer@iatric.com
.

(This article originally appeared in the September 2013 issue of Iatric Systems Updates! newsletter.)

Report Writing Tips – August 2013: Find Duplicate Medical Records (Client/Server, MAGIC or 6.0)

Joe Cocuzzo, Senior Vice President – Report Writing Services

Find Duplicate Medical Records (Client/Server, MAGIC or 6.0)

Recently, a user posting to Meditech-L was looking for a report that could compare patient records in MRI and find all cases where “different” patients have the same name, birth date, and social security number. This means that they have different unit numbers at the same facility, so MEDITECH would treat them as different patients even though they are very likely to be missed merges, and actually the same person.

This makes a good “NPR tip,” showing how to use a macro as a program for selection, and the code is the same for the MAGIC, C/S or 6.x platform.

First, we build a simple MRI.PAT report with no index.

We sort by xx.name with a header and trailer. If we used a sort of @name, a middle initial or difference in case would separate our matches. Instead, we build a computed field that will keep our name matches in groups. The Z.convert.name program is used by MEDITECH in the MRI.PAT filer program to build the subscripts of the @actual.name.index.

To select our records, we use a computed select field “xx.ck” that calls a program:

In the program, we are going to loop on the “actual.name.index” to take the @name from the record we are checking and loop through all the name matches to see if the patient also matches on DOB and SSN, has not already been merged, and has a unit number.

We could have also used the social security index to find all patients with the same SSN, name, and DOB, but I thought that some sites might want to remove the SSN match criteria, and that makes the name index approach more flexible.

In MAGIC, the actual.name.index looks like this:

In Client/Server, it has some additional subscripts after urn, but our looping code can ignore this, as we only need to loop to the urn level. Therefore, the same macro code works in both C/S and MAGIC.

While we might have been able to squeeze our looping/matching into a computed field, using a program instead allows us unlimited “elbow room,” and we can be sure we will not “step on” subscript values that the report is using. In a computed field, nilling or changing the value of a subscript that your report is looping on can cause your report to either end early or loop forever. In a macro written and called as a program, you have a separate set of local variables so this cannot happen.

Our macro looks like this:

For extra credit, we create a computed total field to count the number of matches like this:

Here is some test system output from a MAGIC site:

Here is some test system output from a 6.0 site:

Sample reports: MRI.PAT.zcus.is.find.dup.pts2 have been created for both MAGIC and C/S (or 6.x) systems and uploaded to the report library on our website: http://www.iatric.com/Information/NPRReportLibrarySearch.aspx.

You can find additional Report Writing Tips on our website at http://www.iatric.com/Information/NPRTips.aspx, as well as information about our on-site Report Writer Training and Report Writing Services.

To subscribe for email notifications for new Report Writing classes, please follow this link:

http://www.iatric.com/Information/Classes.aspx.

For more information, please contact Karen Roemer at 978.805.3142 or email karen.roemer@iatric.com.

(This article originally appeared in the August 2013 issue of Iatric Systems Updates! newsletter.)

Report Writing Tips July 2013: Force Client/Server or MAGIC Report to Download File

Joe Cocuzzo, Senior Vice President – Report Writing Services

At our recent “rebroadcast” of the 2013 MUSE RD/NPR “Tips and Tricks” session, participants were particularly interested in how to force either a Client/Server or MAGIC NPR report direct to a download file, where the user does not see any Print On: prompt, and the report itself defines the path and file name for the output. In the “Tricks” session, I showed the C/S approach, but not the MAGIC one, so I have included both methods in this tip for our newsletter.

In C/S, you can use the “EDIT ELEMENTS” routine to add an IFE attribute and put a path into Z.c.cust.rw.download.path. The user will not be prompted for an output destination and the report will automatically download to the path you load with your attribute code.

The Edit Elements routine allows you to attach field attributes to report selection fields in a similar fashion to the way you write attributes for Customer Defined Screens. We can exploit an IFE attribute (used to control whether the cursor stops at a field) to put the path into Z.c.cust.rw.path as the selection screen is displayed.

NPR Image 1

Here is what the IFE attribute should look like; substitute the local path and file name you wish to use for my example path and file here:

NPR Image 2

In MAGIC, you can imbed a program call in the title of the report, and use the program to set up an “auto download.”

NPR Image 3

Since the title of the report is executed as a line of programming code when the selection screen is displayed (and again as the report banner is built for each page), we can use some quotes and underscores to imbed a program call in the title. We use a macro built as a program to set the report up to download, and we return the desired title as the last line of the program.

NPR Image 4

Since the MAGIC program involves quite a bit more code, I have uploaded this demonstration report to our MAGIC report library: ADM.PAT.zcus.is.auto.download

You can find additional Report Writing Tips on our website at http://www.iatric.com/Information/NPRTips.aspx, as well as information about our on-site Report Writer Training and Report Writing Services.

To subscribe for email notifications for new Report Writing classes, please follow this link:

http://www.iatric.com/Information/Classes.aspx.

For more information, please contact Karen Roemer at 978.805.3142 or email
karen.roemer@iatric.com
.

(This article originally appeared in the July 2013 issue of Iatric Systems Updates! newsletter.)