Marc-Henri Poget, software project manager at the University Hospital of Lausanne, Switzerland, shares his experiences creating a billing application utilizing Perl.
If you have a Perl, Python, or PHP success story, I’d like to feature your work in my Weblog. Please send your success story to Glenn Bisignani (email@example.com).
Easy Healthcare Billing with Perl
Billing applications usually contain complex rules that transform raw activity into billable activity. This is especially true in healthcare where fixed prices are applied for repeated medical services.
At the University Hospital of Lausanne, Switzerland, there are many applications that send billing data based on the medical and technical activities, to the hospital information system (HIS). The HIS then combine those billing data to produce the invoices.
The introduction of a new medical tariff at the beginning of 2004 was the unique opportunity to improve existing applications billing modules. As the responsible for the pathology information system, I faced the choice of either configuring the available vendor provided billing module or rewriting it. Since the existing module exhibited bad performances, was not so well integrated within our infrastructure and was difficult to configure to cope with the new medical tariff, I thought about rewriting it. The new module had not only to apply the transformation rules that produce billable data, it also generates ASCII files to be sent to the HIS and handles the ASCII files with error messages returned by the HIS.
I wrote the whole billing application in Perl 5.8.0, using DBI 1.37 and DBD Oracle 1.14. In addition, I wrote Korn Shell scripts responsible to setup the environment variables, launch the Perl scripts, manage the ASCII files and send e-mails containing billing errors using the Unix mailx command. Being a data centered application, the new billing application consists mostly in several steps that either perform SQL requests or process the data. The first step gets the exams eligible for billing and the associated raw activity data. Then, the billing rules are applied to produce billable data. The final step updates the database and generates the ASCII file for the HIS.
In order to make changes in rules easier, I chose to group all the rules in a dedicated Perl module which embodies the domain specific knowledge. Billing rules handle a structure in memory that contains both the raw and billable data. The structure itself is manipulated through primitives that ease rules writing (this could be rewritten in true OO Perl as well, but the main point is to ensure both encapsulation and abstraction). As an example, consider the following extract from the rules module:
$nNbAct = NbActByExam($aActes, ‘TS1′);
if ($nNbAct == 2)
NewVal($aActes, ‘TS1′, 0);
NewVal($aActes, ‘TS2′, 1);
Trace(4, “2 slides read by the pathologist”);
elsif ($nNbAct > 2)
NewVal($aActes, ‘TS1′, 0);
NewVal($aActes, ‘TSN’, 1);
Trace(4, “More than 2 slides read by the pathologist”);
} # if
The variable $aActes is a reference to the structure that contains both the raw and billable data for an exam. In this case, the NbActByExam primitive retrieves the total number of acts of type TS1, which corresponds to the number of microscope slides read by the physician. There are 3 billing codes for this case:
• TS1, price X, exactly 1 slide has been read by the pathologist,
• TS2, price Y, exactly 2 slides have been read by the pathologist,
• TSN, price Z, 3 or more slides have been read by the pathologist.
Thus, the above code is a straightforward translation of the rules. When $nNbAct equals 1, no changes are made. When $nNbAct equals 2, the number of TS1 acts is set to 0 through the NewVal primitive and the number of TS2 acts is set to 1. The same principle applies when $nNbAct is greater than 2. In this case, rules application order can be easily defined, therefore, I didn’t design a complex rules engine to choose which rules to fire. I simply coded the rules one after the other as in the above example.
While the HIS processes the ASCII file contained the billable data, it generates another ASCII file with the errors such as bad patient number, wrong billing date and some others. Since these errors require actions from an office clerk, the billing application needs to update the exam status so that it can be billed again after correction. Moreover, the application needs to notify the errors to the office clerk, it performs that by automatically sending HTML formatted mails.
To ease development and testing, I implemented 2 features. First, a logging module able to write traces to a file (more convenient for batch applications) has been written. Trace levels allow selecting what is written in the logfile. In the above code sample, there are 2 calls to the Trace function with a level of 4. A trace level of 4 is used to display very detailed information, such as which rule has been applied, as opposed to a trace level of 1 used to display more general information, such as a successful connection to the database. In addition to the level of each trace, there is a current trace level at runtime, used to filter out all the traces with levels greater than the current level. The default current level is kept low to avoid filling the logfile with large amounts of data. When debugging is required, the current level is increased so that more traces are written.
Second, when testing database applications, it is convenient to avoid updates so that tests can be easily repeated with the same data. I implemented a test mode that disables the commit and issues a rollback at the end of execution. Since the update, insert and delete operations are performed in the Oracle rollback segment, which is visible within the database session held by the Perl program, it remains possible to check out what has been changed in the database by issuing DBI calls from the Perl debugger prompt.
Perl and the DBI module have brought many benefits to this project. The expressive power of Perl and the ease of issuing database requests through DBI allowed to quickly craft this application. Moreover Perl is used for many tasks in our computer department including: system administration, web development and integration. I’m myself using Perl since 1997, therefore the language and its environment were a natural choice for this project. Perl’s string handling capabilities made the task of handling ASCII files a breeze and its data structure and memory management facilities helped to map the data to the application domain very easily. And last, but not least, a tenfold improvement over the previous vendor provided implementation in a compiled language has been measured.
Marc-Henri Poget is a project manager in the computer department of the University Hospital of Lausanne, Switzerland. He holds a degree in software engineering from the Swiss Institute of Technology (www.epfl.ch) as well as an MBA. He is involved in medical packages deployment and his interests include project management, troubleshooting and open source software.
He can be reached at Marc-Henri.Poget@hospvd.ch.