a pretty comprehensive xml import module
[openemr.git] / library / Claim.class.php
blob5f3fc3cf7e5db95c46c71559d5324cb59094afd9
1 <?php
2 // Copyright (C) 2007 Rod Roark <rod@sunsetsystems.com>
3 //
4 // This program is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU General Public License
6 // as published by the Free Software Foundation; either version 2
7 // of the License, or (at your option) any later version.
9 require_once(dirname(__FILE__) . "/classes/Address.class.php");
10 require_once(dirname(__FILE__) . "/classes/InsuranceCompany.class.php");
11 require_once(dirname(__FILE__) . "/sql-ledger.inc");
12 require_once(dirname(__FILE__) . "/invoice_summary.inc.php");
14 // This enforces the X12 Basic Character Set. Page A2.
16 function x12clean($str) {
17 return preg_replace('/[^A-Z0-9!"\\&\'()+,\\-.\\/;?= ]/', '', strtoupper($str));
20 class Claim {
22 var $pid; // patient id
23 var $encounter_id; // encounter id
24 var $procs; // array of procedure rows from billing table
25 var $x12_partner; // row from x12_partners table
26 var $encounter; // row from form_encounter table
27 var $facility; // row from facility table
28 var $billing_facility; // row from facility table
29 var $provider; // row from users table (rendering provider)
30 var $referrer; // row from users table (referring provider)
31 var $insurance_numbers; // row from insurance_numbers table for current payer
32 var $patient_data; // row from patient_data table
33 var $billing_options; // row from form_misc_billing_options table
34 var $invoice; // result from get_invoice_summary()
35 var $payers; // array of arrays, for all payers
37 function loadPayerInfo(&$billrow) {
38 global $sl_err;
39 $encounter_date = substr($this->encounter['date'], 0, 10);
41 // Create the $payers array. This contains data for all insurances
42 // with the current one always at index 0, and the others in payment
43 // order starting at index 1.
45 $this->payers = array();
46 $this->payers[0] = array();
47 $query = "SELECT * FROM insurance_data WHERE " .
48 "pid = '{$this->pid}' AND provider != '' AND " .
49 "date <= '$encounter_date' " .
50 "ORDER BY type ASC, date DESC";
51 // echo "<br>$query<br>"; // debugging
52 $dres = sqlStatement($query);
53 $prevtype = '';
54 while ($drow = sqlFetchArray($dres)) {
55 if (strcmp($prevtype, $drow['type']) == 0) continue;
56 $prevtype = $drow['type'];
57 $ins = ($drow['provider'] == $billrow['payer_id']) ?
58 0 : count($this->payers);
59 $crow = sqlQuery("SELECT * FROM insurance_companies WHERE " .
60 "id = '" . $drow['provider'] . "'");
61 $orow = new InsuranceCompany($drow['provider']);
62 $this->payers[$ins] = array();
63 $this->payers[$ins]['data'] = $drow;
64 $this->payers[$ins]['company'] = $crow;
65 $this->payers[$ins]['object'] = $orow;
68 $this->using_modifiers = true;
70 // Get payment and adjustment details if there are any previous payers.
72 $this->invoice = array();
73 if ($this->payerSequence() != 'P') {
74 SLConnect();
75 $arres = SLQuery("select id from ar where invnumber = " .
76 "'{$this->pid}.{$this->encounter_id}'");
77 if ($sl_err) die($sl_err);
78 $arrow = SLGetRow($arres, 0);
79 if ($arrow) {
80 $this->invoice = get_invoice_summary($arrow['id'], true);
82 SLClose();
83 // Secondary claims might not have modifiers in SQL-Ledger data.
84 // In that case, note that we should not try to match on them.
85 $this->using_modifiers = false;
86 foreach ($this->invoice as $key => $trash) {
87 if (strpos($key, ':')) $this->using_modifiers = true;
92 // Constructor. Loads relevant database information.
94 function Claim($pid, $encounter_id) {
95 $this->pid = $pid;
96 $this->encounter_id = $encounter_id;
97 $this->procs = array();
99 // We need the encounter date before we can identify the payers.
100 $sql = "SELECT * FROM form_encounter WHERE " .
101 "pid = '{$this->pid}' AND " .
102 "encounter = '{$this->encounter_id}'";
103 $this->encounter = sqlQuery($sql);
105 // Sort by procedure timestamp in order to get some consistency. In particular
106 // we determine the provider from the first procedure in this array.
107 $sql = "SELECT * FROM billing WHERE " .
108 "encounter = '{$this->encounter_id}' AND pid = '{$this->pid}' AND " .
109 "(code_type = 'CPT4' OR code_type = 'HCPCS') AND " .
110 "activity = '1' ORDER BY date, id";
111 $res = sqlStatement($sql);
112 while ($row = sqlFetchArray($res)) {
113 if (!$row['units']) $row['units'] = 1;
114 // Load prior payer data at the first opportunity in order to get
115 // the using_modifiers flag that is referenced below.
116 if (empty($this->procs)) $this->loadPayerInfo($row);
117 // Consolidate duplicate procedures.
118 foreach ($this->procs as $key => $trash) {
119 if (strcmp($this->procs[$key]['code'],$row['code']) == 0 &&
120 (strcmp($this->procs[$key]['modifier'],$row['modifier']) == 0 ||
121 !$this->using_modifiers))
123 $this->procs[$key]['units'] += $row['units'];
124 $this->procs[$key]['fee'] += $row['fee'];
125 continue 2; // skip to next table row
128 $this->procs[] = $row;
131 $sql = "SELECT * FROM x12_partners WHERE " .
132 "id = '" . $this->procs[0]['x12_partner_id'] . "'";
133 $this->x12_partner = sqlQuery($sql);
135 $sql = "SELECT * FROM facility WHERE " .
136 "name = '" . addslashes($this->encounter['facility']) . "' " .
137 "ORDER BY id LIMIT 1";
138 $this->facility = sqlQuery($sql);
140 $sql = "SELECT * FROM users WHERE " .
141 "id = '" . $this->procs[0]['provider_id'] . "'";
142 $this->provider = sqlQuery($sql);
144 $sql = "SELECT * FROM facility " .
145 "ORDER BY billing_location DESC, id ASC LIMIT 1";
146 $this->billing_facility = sqlQuery($sql);
148 $sql = "SELECT * FROM insurance_numbers WHERE " .
149 "(insurance_company_id = '" . $this->procs[0]['payer_id'] .
150 "' OR insurance_company_id is NULL) AND " .
151 "provider_id = '" . $this->provider['id'] .
152 "' order by insurance_company_id DESC LIMIT 1";
153 $this->insurance_numbers = sqlQuery($sql);
155 $sql = "SELECT * FROM patient_data WHERE " .
156 "pid = '{$this->pid}' " .
157 "ORDER BY id LIMIT 1";
158 $this->patient_data = sqlQuery($sql);
160 $sql = "SELECT fpa.* FROM forms JOIN form_misc_billing_options AS fpa " .
161 "ON fpa.id = forms.form_id WHERE " .
162 "forms.encounter = '{$this->encounter_id}' AND " .
163 "forms.pid = '{$this->pid}' AND " .
164 "forms.formdir = 'misc_billing_options' " .
165 "ORDER BY forms.date";
166 $this->billing_options = sqlQuery($sql);
168 $sql = "SELECT * FROM users WHERE " .
169 "id = '" . $this->patient_data['providerID'] . "'";
170 $this->referrer = sqlQuery($sql);
171 if (!$this->referrer) $this->referrer = array();
173 } // end constructor
175 // Return an array of adjustments from the designated prior payer for the
176 // designated procedure key (might be procedure:modifier), or for the claim
177 // level. For each adjustment give date, group code, reason code, amount.
178 // Note this will include "patient responsibility" adjustments which are
179 // not adjustments to OUR invoice, but they reduce the amount that the
180 // insurance company pays.
182 function payerAdjustments($ins, $code='Claim') {
183 $aadj = array();
185 // If we have no modifiers stored in SQL-Ledger for this claim,
186 // then we cannot use a modifier passed in with the key.
187 $tmp = strpos($code, ':');
188 if ($tmp && !$this->using_modifiers) $code = substr($code, 0, $tmp);
190 // For payments, source always starts with "Ins" or "Pt".
191 // Nonzero adjustment reason examples:
192 // Ins1 adjust code 42 (Charges exceed ... (obsolete))
193 // Ins1 adjust code 45 (Charges exceed your contracted/ legislated fee arrangement)
194 // Ins1 adjust code 97 (Payment is included in the allowance for another service/procedure)
195 // Ins1 adjust code A2 (Contractual adjustment)
196 // Ins adjust Ins1
197 // adjust code 45
198 // Zero adjustment reason examples:
199 // Co-pay: 25.00
200 // Coinsurance: 11.46 (code 2) Note: fix remits to identify insurance
201 // To deductible: 0.22 (code 1) Note: fix remits to identify insurance
202 // To copay Ins1 (manual entry)
203 // To ded'ble Ins1 (manual entry)
205 if (!empty($this->invoice[$code])) {
206 $date = '';
207 $deductible = 0;
208 $coinsurance = 0;
209 $inslabel = ($this->payerSequence($ins) == 'S') ? 'Ins2' : 'Ins1';
210 $insnumber = substr($inslabel, 3);
212 // Compute this procedure's patient responsibility amount as of this
213 // prior payer, which is the original charge minus all insurance
214 // payments and "hard" adjustments up to this payer.
215 $ptresp = $this->invoice[$code]['chg'] + $this->invoice[$code]['adj'];
216 foreach ($this->invoice[$code]['dtl'] as $key => $value) {
217 if (preg_match("/^Ins(\d)/i", $value['src'], $tmp)) {
218 if ($tmp[1] <= $insnumber) $ptresp -= $value['pmt'];
220 else if (trim(substr($key, 0, 10))) { // not an adjustment if no date
221 if (!preg_match("/Ins(\d)/i", $value['rsn'], $tmp) || $tmp[1] <= $insnumber)
222 $ptresp += $value['chg']; // adjustments are negative charges
225 if ($ptresp < 0) $ptresp = 0; // we may be insane but try to hide it
227 // Main loop, to extract adjustments for this payer and procedure.
228 foreach ($this->invoice[$code]['dtl'] as $key => $value) {
229 $tmp = str_replace('-', '', trim(substr($key, 0, 10)));
230 if ($tmp) $date = $tmp;
231 if ($tmp && $value['pmt'] == 0) { // not original charge and not a payment
232 $rsn = $value['rsn'];
233 $chg = 0 - $value['chg']; // adjustments are negative charges
235 $gcode = 'CO'; // default group code = contractual obligation
236 $rcode = '45'; // default reason code = max fee exceeded (code 42 is obsolete)
238 if (preg_match("/Ins adjust $inslabel/i", $rsn, $tmp)) {
239 // From manual post. Take the defaults.
241 else if (preg_match("/To copay $inslabel/i", $rsn, $tmp) && !$chg) {
242 $coinsurance = $ptresp; // from manual post
243 continue;
245 else if (preg_match("/To ded'ble $inslabel/i", $rsn, $tmp) && !$chg) {
246 $deductible = $ptresp; // from manual post
247 continue;
249 else if (preg_match("/$inslabel copay: (\S+)/i", $rsn, $tmp) && !$chg) {
250 $coinsurance = $tmp[1]; // from 835 as of 6/2007
251 continue;
253 else if (preg_match("/$inslabel coins: (\S+)/i", $rsn, $tmp) && !$chg) {
254 $coinsurance = $tmp[1]; // from 835 and manual post as of 6/2007
255 continue;
257 else if (preg_match("/$inslabel dedbl: (\S+)/i", $rsn, $tmp) && !$chg) {
258 $deductible = $tmp[1]; // from 835 and manual post as of 6/2007
259 continue;
261 else if (preg_match("/$inslabel ptresp: (\S+)/i", $rsn, $tmp) && !$chg) {
262 continue; // from 835 as of 6/2007
264 else if (preg_match("/$inslabel adjust code (\S+)/i", $rsn, $tmp)) {
265 $rcode = $tmp[1]; // from 835
267 else if (preg_match("/$inslabel/i", $rsn, $tmp)) {
268 // Take the defaults.
270 else if (preg_match('/Ins(\d)/i', $rsn, $tmp) && $tmp[1] != $insnumber) {
271 continue; // it's for some other payer
273 else if ($insnumber == '1') {
274 if (preg_match("/\$\s*adjust code (\S+)/i", $rsn, $tmp)) {
275 $rcode = $tmp[1]; // from 835
277 else if ($chg) {
278 // Other adjustments default to Ins1.
280 else if (preg_match("/Co-pay: (\S+)/i", $rsn, $tmp) ||
281 preg_match("/Coinsurance: (\S+)/i", $rsn, $tmp)) {
282 $coinsurance = 0 + $tmp[1]; // from 835 before 6/2007
283 continue;
285 else if (preg_match("/To deductible: (\S+)/i", $rsn, $tmp)) {
286 $deductible = 0 + $tmp[1]; // from 835 before 6/2007
287 continue;
289 else {
290 continue; // there is no adjustment amount
293 else {
294 continue; // it's for primary and that's not us
297 $aadj[] = array($date, $gcode, $rcode, sprintf('%.2f', $chg));
299 } // end if
300 } // end foreach
302 // If we really messed it up, at least avoid negative numbers.
303 if ($coinsurance > $ptresp) $coinsurance = $ptresp;
304 if ($deductible > $ptresp) $deductible = $ptresp;
306 // Find out if this payer paid anything at all on this claim. This will
307 // help us allocate any unknown patient responsibility amounts.
308 $thispaidanything = 0;
309 foreach($this->invoice as $codekey => $codeval) {
310 foreach ($codeval['dtl'] as $key => $value) {
311 if (preg_match("/$inslabel/i", $value['src'], $tmp)) {
312 $thispaidanything += $value['pmt'];
317 // Allocate any unknown patient responsibility by guessing if the
318 // deductible has been satisfied.
319 if ($thispaidanything)
320 $coinsurance = $ptresp - $deductible;
321 else
322 $deductible = $ptresp - $coinsurance;
324 if ($date && $deductible != 0)
325 $aadj[] = array($date, 'PR', '1', sprintf('%.2f', $deductible));
326 if ($date && $coinsurance != 0)
327 $aadj[] = array($date, 'PR', '2', sprintf('%.2f', $coinsurance));
329 } // end if
331 return $aadj;
334 // Return date, total payments and total "hard" adjustments from the given
335 // prior payer. If $code is specified then only that procedure key is
336 // selected, otherwise it's for the whole claim.
338 function payerTotals($ins, $code='') {
339 // If we have no modifiers stored in SQL-Ledger for this claim,
340 // then we cannot use a modifier passed in with the key.
341 $tmp = strpos($code, ':');
342 if ($tmp && !$this->using_modifiers) $code = substr($code, 0, $tmp);
344 $inslabel = ($this->payerSequence($ins) == 'S') ? 'Ins2' : 'Ins1';
345 $paytotal = 0;
346 $adjtotal = 0;
347 $date = '';
348 foreach($this->invoice as $codekey => $codeval) {
349 if ($code && strcmp($codekey,$code) != 0) continue;
350 foreach ($codeval['dtl'] as $key => $value) {
351 if (preg_match("/$inslabel/i", $value['src'], $tmp)) {
352 if (!$date) $date = str_replace('-', '', trim(substr($key, 0, 10)));
353 $paytotal += $value['pmt'];
356 $aarr = $this->payerAdjustments($ins, $codekey);
357 foreach ($aarr as $a) {
358 if (strcmp($a[1],'PR') != 0) $adjtotal += $a[3];
359 if (!$date) $date = $a[0];
362 return array($date, sprintf('%.2f', $paytotal), sprintf('%.2f', $adjtotal));
365 // Return the amount already paid by the patient.
367 function patientPaidAmount() {
369 // TBD: This does not work for a primary claim because $this->invoice
370 // is not loaded. Might be good to get the co-pay from the billing
371 // table in that case.
373 $amount = 0;
374 foreach($this->invoice as $codekey => $codeval) {
375 foreach ($codeval['dtl'] as $key => $value) {
376 if (!preg_match("/Ins/i", $value['src'], $tmp)) {
377 $amount += $value['pmt'];
381 return sprintf('%.2f', $amount);
384 // Return invoice total, including adjustments but not payments.
386 function invoiceTotal() {
387 $amount = 0;
388 foreach($this->invoice as $codekey => $codeval) {
389 $amount += $codeval['chg'];
391 return sprintf('%.2f', $amount);
394 // Number of procedures in this claim.
395 function procCount() {
396 return count($this->procs);
399 // Number of payers for this claim. Ranges from 1 to 3.
400 function payerCount() {
401 return count($this->payers);
404 function x12gsversionstring() {
405 return x12clean(trim($this->x12_partner['x12_version']));
408 function x12gssenderid() {
409 $tmp = $this->x12_partner['x12_sender_id'];
410 while (strlen($tmp) < 15) $tmp .= " ";
411 return $tmp;
414 function x12gsreceiverid() {
415 $tmp = $this->x12_partner['x12_receiver_id'];
416 while (strlen($tmp) < 15) $tmp .= " ";
417 return $tmp;
420 function cliaCode() {
421 return x12clean(trim($this->facility['domain_identifier']));
424 function billingFacilityName() {
425 return x12clean(trim($this->billing_facility['name']));
428 function billingFacilityStreet() {
429 return x12clean(trim($this->billing_facility['street']));
432 function billingFacilityCity() {
433 return x12clean(trim($this->billing_facility['city']));
436 function billingFacilityState() {
437 return x12clean(trim($this->billing_facility['state']));
440 function billingFacilityZip() {
441 return x12clean(trim($this->billing_facility['postal_code']));
444 function billingFacilityETIN() {
445 return x12clean(trim(str_replace('-', '', $this->billing_facility['federal_ein'])));
448 function billingFacilityNPI() {
449 return x12clean(trim($this->billing_facility['facility_npi']));
452 function billingContactName() {
453 return x12clean(trim($this->billing_facility['attn']));
456 function billingContactPhone() {
457 if (preg_match("/([2-9]\d\d)\D*(\d\d\d)\D*(\d\d\d\d)/",
458 $this->billing_facility['phone'], $tmp))
460 return $tmp[1] . $tmp[2] . $tmp[3];
462 return '';
465 function facilityName() {
466 return x12clean(trim($this->facility['name']));
469 function facilityStreet() {
470 return x12clean(trim($this->facility['street']));
473 function facilityCity() {
474 return x12clean(trim($this->facility['city']));
477 function facilityState() {
478 return x12clean(trim($this->facility['state']));
481 function facilityZip() {
482 return x12clean(trim($this->facility['postal_code']));
485 function facilityETIN() {
486 return x12clean(trim(str_replace('-', '', $this->facility['federal_ein'])));
489 function facilityNPI() {
490 return x12clean(trim($this->facility['facility_npi']));
493 function facilityPOS() {
494 return x12clean(trim($this->facility['pos_code']));
497 function clearingHouseName() {
498 return x12clean(trim($this->x12_partner['name']));
501 function clearingHouseETIN() {
502 return x12clean(trim(str_replace('-', '', $this->x12_partner['id_number'])));
505 function providerNumberType() {
506 return $this->insurance_numbers['provider_number_type'];
509 function providerNumber() {
510 return x12clean(trim(str_replace('-', '', $this->insurance_numbers['provider_number'])));
513 // Returns 'P', 'S' or 'T'.
515 function payerSequence($ins=0) {
516 return strtoupper(substr($this->payers[$ins]['data']['type'], 0, 1));
519 // Returns the HIPAA code of the patient-to-subscriber relationship.
521 function insuredRelationship($ins=0) {
522 $tmp = strtolower($this->payers[$ins]['data']['subscriber_relationship']);
523 if (strcmp($tmp,'self' ) == 0) return '18';
524 if (strcmp($tmp,'spouse') == 0) return '01';
525 if (strcmp($tmp,'child' ) == 0) return '19';
526 if (strcmp($tmp,'other' ) == 0) return 'G8';
527 return $tmp; // should not happen
530 function insuredTypeCode($ins=0) {
531 if (strcmp($this->claimType($ins),'MB') == 0 && $this->payerSequence($ins) != 'P')
532 return '12'; // medicare secondary working aged beneficiary or
533 // spouse with employer group health plan
534 return '';
537 // Is the patient also the subscriber?
539 function isSelfOfInsured($ins=0) {
540 $tmp = strtolower($this->payers[$ins]['data']['subscriber_relationship']);
541 return (strcmp($tmp,'self') == 0);
544 function groupNumber($ins=0) {
545 return x12clean(trim($this->payers[$ins]['data']['group_number']));
548 function groupName($ins=0) {
549 return x12clean(trim($this->payers[$ins]['data']['subscriber_employer']));
552 function claimType($ins=0) {
553 if (empty($this->payers[$ins]['object'])) return '';
554 return $this->payers[$ins]['object']->get_freeb_claim_type();
557 function insuredLastName($ins=0) {
558 return x12clean(trim($this->payers[$ins]['data']['subscriber_lname']));
561 function insuredFirstName($ins=0) {
562 return x12clean(trim($this->payers[$ins]['data']['subscriber_fname']));
565 function insuredMiddleName($ins=0) {
566 return x12clean(trim($this->payers[$ins]['data']['subscriber_mname']));
569 function policyNumber($ins=0) { // "ID"
570 return x12clean(trim($this->payers[$ins]['data']['policy_number']));
573 function insuredStreet($ins=0) {
574 return x12clean(trim($this->payers[$ins]['data']['subscriber_street']));
577 function insuredCity($ins=0) {
578 return x12clean(trim($this->payers[$ins]['data']['subscriber_city']));
581 function insuredState($ins=0) {
582 return x12clean(trim($this->payers[$ins]['data']['subscriber_state']));
585 function insuredZip($ins=0) {
586 return x12clean(trim($this->payers[$ins]['data']['subscriber_postal_code']));
589 function insuredDOB($ins=0) {
590 return str_replace('-', '', $this->payers[$ins]['data']['subscriber_DOB']);
593 function insuredSex($ins=0) {
594 return strtoupper(substr($this->payers[$ins]['data']['subscriber_sex'], 0, 1));
597 function payerName($ins=0) {
598 return x12clean(trim($this->payers[$ins]['company']['name']));
601 function payerStreet($ins=0) {
602 if (empty($this->payers[$ins]['object'])) return '';
603 $tmp = $this->payers[$ins]['object'];
604 $tmp = $tmp->get_address();
605 return x12clean(trim($tmp->get_line1()));
608 function payerCity($ins=0) {
609 if (empty($this->payers[$ins]['object'])) return '';
610 $tmp = $this->payers[$ins]['object'];
611 $tmp = $tmp->get_address();
612 return x12clean(trim($tmp->get_city()));
615 function payerState($ins=0) {
616 if (empty($this->payers[$ins]['object'])) return '';
617 $tmp = $this->payers[$ins]['object'];
618 $tmp = $tmp->get_address();
619 return x12clean(trim($tmp->get_state()));
622 function payerZip($ins=0) {
623 if (empty($this->payers[$ins]['object'])) return '';
624 $tmp = $this->payers[$ins]['object'];
625 $tmp = $tmp->get_address();
626 return x12clean(trim($tmp->get_zip()));
629 function payerID($ins=0) {
630 return x12clean(trim($this->payers[$ins]['company']['cms_id']));
633 function patientLastName() {
634 return x12clean(trim($this->patient_data['lname']));
637 function patientFirstName() {
638 return x12clean(trim($this->patient_data['fname']));
641 function patientMiddleName() {
642 return x12clean(trim($this->patient_data['mname']));
645 function patientStreet() {
646 return x12clean(trim($this->patient_data['street']));
649 function patientCity() {
650 return x12clean(trim($this->patient_data['city']));
653 function patientState() {
654 return x12clean(trim($this->patient_data['state']));
657 function patientZip() {
658 return x12clean(trim($this->patient_data['postal_code']));
661 function patientDOB() {
662 return str_replace('-', '', $this->patient_data['DOB']);
665 function patientSex() {
666 return strtoupper(substr($this->patient_data['sex'], 0, 1));
669 function cptCode($prockey) {
670 return x12clean(trim($this->procs[$prockey]['code']));
673 function cptModifier($prockey) {
674 return x12clean(trim($this->procs[$prockey]['modifier']));
677 // Returns the procedure code, followed by ":modifier" if there is one.
678 function cptKey($prockey) {
679 $tmp = $this->cptModifier($prockey);
680 return $this->cptCode($prockey) . ($tmp ? ":$tmp" : "");
683 function cptCharges($prockey) {
684 return x12clean(trim($this->procs[$prockey]['fee']));
687 function cptUnits($prockey) {
688 if (empty($this->procs[$prockey]['units'])) return '1';
689 return x12clean(trim($this->procs[$prockey]['units']));
692 // NDC drug ID.
693 function cptNDCID($prockey) {
694 $ndcinfo = $this->procs[$prockey]['ndc_info'];
695 if (preg_match('/^N4(\S+)\s+(\S\S)(.*)/', $ndcinfo, $tmp)) {
696 $ndc = $tmp[1];
697 if (preg_match('/^(\d+)-(\d+)-(\d+)$/', $ndc, $tmp)) {
698 return sprintf('%05d-%04d-%02d', $tmp[1], $tmp[2], $tmp[3]);
700 return x12clean($ndc); // format is bad but return it anyway
702 return '';
705 // NDC drug unit of measure code.
706 function cptNDCUOM($prockey) {
707 $ndcinfo = $this->procs[$prockey]['ndc_info'];
708 if (preg_match('/^N4(\S+)\s+(\S\S)(.*)/', $ndcinfo, $tmp))
709 return x12clean($tmp[2]);
710 return '';
713 // NDC drug number of units.
714 function cptNDCQuantity($prockey) {
715 $ndcinfo = $this->procs[$prockey]['ndc_info'];
716 if (preg_match('/^N4(\S+)\s+(\S\S)(.*)/', $ndcinfo, $tmp))
717 return x12clean($tmp[3]);
718 return '';
721 function onsetDate() {
722 return str_replace('-', '', substr($this->encounter['onset_date'], 0, 10));
725 function serviceDate() {
726 return str_replace('-', '', substr($this->encounter['date'], 0, 10));
729 function priorAuth() {
730 return x12clean(trim($this->billing_options['prior_auth_number']));
733 // Returns an array of unique primary diagnoses. Periods are stripped.
734 function diagArray() {
735 $da = array();
736 foreach ($this->procs as $row) {
737 $tmp = explode(':', $row['justify']);
738 if (count($tmp)) {
739 $diag = str_replace('.', '', $tmp[0]);
740 $da[$diag] = $diag;
743 return $da;
746 // Compute the 1-relative index in diagArray for the given procedure.
747 function diagIndex($prockey) {
748 $da = $this->diagArray();
749 $tmp = explode(':', $this->procs[$prockey]['justify']);
750 if (empty($tmp)) return '';
751 $diag = str_replace('.', '', $tmp[0]);
752 $i = 0;
753 foreach ($da as $value) {
754 ++$i;
755 if (strcmp($value,$diag) == 0) return $i;
757 return '';
760 function providerLastName() {
761 return x12clean(trim($this->provider['lname']));
764 function providerFirstName() {
765 return x12clean(trim($this->provider['fname']));
768 function providerMiddleName() {
769 return x12clean(trim($this->provider['mname']));
772 function providerNPI() {
773 return x12clean(trim($this->provider['npi']));
776 function providerUPIN() {
777 return x12clean(trim($this->provider['upin']));
780 function providerSSN() {
781 return x12clean(trim(str_replace('-', '', $this->provider['federaltaxid'])));
784 function referrerLastName() {
785 return x12clean(trim($this->referrer['lname']));
788 function referrerFirstName() {
789 return x12clean(trim($this->referrer['fname']));
792 function referrerMiddleName() {
793 return x12clean(trim($this->referrer['mname']));
796 function referrerNPI() {
797 return x12clean(trim($this->referrer['npi']));
800 function referrerUPIN() {
801 return x12clean(trim($this->referrer['upin']));
804 function referrerSSN() {
805 return x12clean(trim(str_replace('-', '', $this->referrer['federaltaxid'])));