updated language constants and tables
[openemr.git] / library / Claim.class.php
blob14e70d238e3118eb48b3c967b3dee9ce075390c3
1 <?php
2 // Copyright (C) 2007-2009 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 $supervisor; // row from users table (supervising provider)
32 var $insurance_numbers; // row from insurance_numbers table for current payer
33 var $supervisor_numbers; // row from insurance_numbers table for current payer
34 var $patient_data; // row from patient_data table
35 var $billing_options; // row from form_misc_billing_options table
36 var $invoice; // result from get_invoice_summary()
37 var $payers; // array of arrays, for all payers
38 var $copay; // total of copays from the billing table
40 function loadPayerInfo(&$billrow) {
41 global $sl_err;
42 $encounter_date = substr($this->encounter['date'], 0, 10);
44 // Create the $payers array. This contains data for all insurances
45 // with the current one always at index 0, and the others in payment
46 // order starting at index 1.
48 $this->payers = array();
49 $this->payers[0] = array();
50 $query = "SELECT * FROM insurance_data WHERE " .
51 "pid = '{$this->pid}' AND " .
52 "date <= '$encounter_date' " .
53 "ORDER BY type ASC, date DESC";
54 $dres = sqlStatement($query);
55 $prevtype = '';
56 while ($drow = sqlFetchArray($dres)) {
57 if (strcmp($prevtype, $drow['type']) == 0) continue;
58 $prevtype = $drow['type'];
59 // Very important to look at entries with a missing provider because
60 // they indicate no insurance as of the given date.
61 if (empty($drow['provider'])) continue;
62 $ins = count($this->payers);
63 if ($drow['provider'] == $billrow['payer_id'] && empty($this->payers[0]['data'])) $ins = 0;
64 $crow = sqlQuery("SELECT * FROM insurance_companies WHERE " .
65 "id = '" . $drow['provider'] . "'");
66 $orow = new InsuranceCompany($drow['provider']);
67 $this->payers[$ins] = array();
68 $this->payers[$ins]['data'] = $drow;
69 $this->payers[$ins]['company'] = $crow;
70 $this->payers[$ins]['object'] = $orow;
73 // This kludge hands most cases of a rare ambiguous situation, where
74 // the primary insurance company is the same as the secondary. It seems
75 // nobody planned for that!
77 for ($i = 1; $i < count($this->payers); ++$i) {
78 if ($billrow['process_date'] &&
79 $this->payers[0]['data']['provider'] == $this->payers[$i]['data']['provider'])
81 $tmp = $this->payers[0];
82 $this->payers[0] = $this->payers[$i];
83 $this->payers[$i] = $tmp;
87 $this->using_modifiers = true;
89 // Get payment and adjustment details if there are any previous payers.
91 $this->invoice = array();
92 if ($this->payerSequence() != 'P') {
93 if ($GLOBALS['oer_config']['ws_accounting']['enabled'] === 2) {
94 $this->invoice = ar_get_invoice_summary($this->pid, $this->encounter_id, true);
96 else if ($GLOBALS['oer_config']['ws_accounting']['enabled']) {
97 SLConnect();
98 $arres = SLQuery("select id from ar where invnumber = " .
99 "'{$this->pid}.{$this->encounter_id}'");
100 if ($sl_err) die($sl_err);
101 $arrow = SLGetRow($arres, 0);
102 if ($arrow) {
103 $this->invoice = get_invoice_summary($arrow['id'], true);
105 SLClose();
107 // Secondary claims might not have modifiers in SQL-Ledger data.
108 // In that case, note that we should not try to match on them.
109 $this->using_modifiers = false;
110 foreach ($this->invoice as $key => $trash) {
111 if (strpos($key, ':')) $this->using_modifiers = true;
116 // Constructor. Loads relevant database information.
118 function Claim($pid, $encounter_id) {
119 $this->pid = $pid;
120 $this->encounter_id = $encounter_id;
121 $this->procs = array();
122 $this->copay = 0;
124 // We need the encounter date before we can identify the payers.
125 $sql = "SELECT * FROM form_encounter WHERE " .
126 "pid = '{$this->pid}' AND " .
127 "encounter = '{$this->encounter_id}'";
128 $this->encounter = sqlQuery($sql);
130 // Sort by procedure timestamp in order to get some consistency.
131 $sql = "SELECT * FROM billing WHERE " .
132 "encounter = '{$this->encounter_id}' AND pid = '{$this->pid}' AND " .
133 "(code_type = 'CPT4' OR code_type = 'HCPCS' OR code_type = 'COPAY') AND " .
134 "activity = '1' ORDER BY date, id";
135 $res = sqlStatement($sql);
136 while ($row = sqlFetchArray($res)) {
137 if ($row['code_type'] == 'COPAY') {
138 $this->copay -= $row['fee'];
139 continue;
141 if (!$row['units']) $row['units'] = 1;
142 // Load prior payer data at the first opportunity in order to get
143 // the using_modifiers flag that is referenced below.
144 if (empty($this->procs)) $this->loadPayerInfo($row);
145 // Consolidate duplicate procedures.
146 foreach ($this->procs as $key => $trash) {
147 if (strcmp($this->procs[$key]['code'],$row['code']) == 0 &&
148 (strcmp($this->procs[$key]['modifier'],$row['modifier']) == 0 ||
149 !$this->using_modifiers))
151 $this->procs[$key]['units'] += $row['units'];
152 $this->procs[$key]['fee'] += $row['fee'];
153 continue 2; // skip to next table row
157 // If there is a row-specific provider then get its details.
158 if (!empty($row['provider_id'])) {
159 // Get service provider data for this row.
160 $sql = "SELECT * FROM users WHERE id = '" . $row['provider_id'] . "'";
161 $row['provider'] = sqlQuery($sql);
162 // Get insurance numbers for this row's provider.
163 $sql = "SELECT * FROM insurance_numbers WHERE " .
164 "(insurance_company_id = '" . $row['payer_id'] .
165 "' OR insurance_company_id is NULL) AND " .
166 "provider_id = '" . $row['provider_id'] . "' " .
167 "ORDER BY insurance_company_id DESC LIMIT 1";
168 $row['insurance_numbers'] = sqlQuery($sql);
171 $this->procs[] = $row;
174 $sql = "SELECT * FROM x12_partners WHERE " .
175 "id = '" . $this->procs[0]['x12_partner_id'] . "'";
176 $this->x12_partner = sqlQuery($sql);
178 $sql = "SELECT * FROM facility WHERE " .
179 "id = '" . addslashes($this->encounter['facility_id']) . "' " .
180 "LIMIT 1";
181 $this->facility = sqlQuery($sql);
183 /*****************************************************************
184 $provider_id = $this->procs[0]['provider_id'];
185 *****************************************************************/
186 $provider_id = $this->encounter['provider_id'];
187 $sql = "SELECT * FROM users WHERE id = '$provider_id'";
188 $this->provider = sqlQuery($sql);
190 $sql = "SELECT * FROM facility " .
191 "ORDER BY billing_location DESC, id ASC LIMIT 1";
192 $this->billing_facility = sqlQuery($sql);
194 $sql = "SELECT * FROM insurance_numbers WHERE " .
195 "(insurance_company_id = '" . $this->procs[0]['payer_id'] .
196 "' OR insurance_company_id is NULL) AND " .
197 "provider_id = '$provider_id' " .
198 "ORDER BY insurance_company_id DESC LIMIT 1";
199 $this->insurance_numbers = sqlQuery($sql);
201 $sql = "SELECT * FROM patient_data WHERE " .
202 "pid = '{$this->pid}' " .
203 "ORDER BY id LIMIT 1";
204 $this->patient_data = sqlQuery($sql);
206 $sql = "SELECT fpa.* FROM forms JOIN form_misc_billing_options AS fpa " .
207 "ON fpa.id = forms.form_id WHERE " .
208 "forms.encounter = '{$this->encounter_id}' AND " .
209 "forms.pid = '{$this->pid}' AND " .
210 "forms.formdir = 'misc_billing_options' " .
211 "ORDER BY forms.date";
212 $this->billing_options = sqlQuery($sql);
214 $referrer_id = (empty($GLOBALS['MedicareReferrerIsRenderer']) ||
215 $this->insurance_numbers['provider_number_type'] != '1C') ?
216 $this->patient_data['providerID'] : $provider_id;
217 $sql = "SELECT * FROM users WHERE id = '$referrer_id'";
218 $this->referrer = sqlQuery($sql);
219 if (!$this->referrer) $this->referrer = array();
221 $supervisor_id = $this->encounter['supervisor_id'];
222 $sql = "SELECT * FROM users WHERE id = '$supervisor_id'";
223 $this->supervisor = sqlQuery($sql);
224 if (!$this->supervisor) $this->supervisor = array();
226 $sql = "SELECT * FROM insurance_numbers WHERE " .
227 "(insurance_company_id = '" . $this->procs[0]['payer_id'] .
228 "' OR insurance_company_id is NULL) AND " .
229 "provider_id = '$supervisor_id' " .
230 "ORDER BY insurance_company_id DESC LIMIT 1";
231 $this->supervisor_numbers = sqlQuery($sql);
232 if (!$this->supervisor_numbers) $this->supervisor_numbers = array();
234 } // end constructor
236 // Return an array of adjustments from the designated prior payer for the
237 // designated procedure key (might be procedure:modifier), or for the claim
238 // level. For each adjustment give date, group code, reason code, amount.
239 // Note this will include "patient responsibility" adjustments which are
240 // not adjustments to OUR invoice, but they reduce the amount that the
241 // insurance company pays.
243 function payerAdjustments($ins, $code='Claim') {
244 $aadj = array();
246 // If we have no modifiers stored in SQL-Ledger for this claim,
247 // then we cannot use a modifier passed in with the key.
248 $tmp = strpos($code, ':');
249 if ($tmp && !$this->using_modifiers) $code = substr($code, 0, $tmp);
251 // For payments, source always starts with "Ins" or "Pt".
252 // Nonzero adjustment reason examples:
253 // Ins1 adjust code 42 (Charges exceed ... (obsolete))
254 // Ins1 adjust code 45 (Charges exceed your contracted/ legislated fee arrangement)
255 // Ins1 adjust code 97 (Payment is included in the allowance for another service/procedure)
256 // Ins1 adjust code A2 (Contractual adjustment)
257 // Ins adjust Ins1
258 // adjust code 45
259 // Zero adjustment reason examples:
260 // Co-pay: 25.00
261 // Coinsurance: 11.46 (code 2) Note: fix remits to identify insurance
262 // To deductible: 0.22 (code 1) Note: fix remits to identify insurance
263 // To copay Ins1 (manual entry)
264 // To ded'ble Ins1 (manual entry)
266 if (!empty($this->invoice[$code])) {
267 $date = '';
268 $deductible = 0;
269 $coinsurance = 0;
270 $inslabel = ($this->payerSequence($ins) == 'S') ? 'Ins2' : 'Ins1';
271 $insnumber = substr($inslabel, 3);
273 // Compute this procedure's patient responsibility amount as of this
274 // prior payer, which is the original charge minus all insurance
275 // payments and "hard" adjustments up to this payer.
276 $ptresp = $this->invoice[$code]['chg'] + $this->invoice[$code]['adj'];
277 foreach ($this->invoice[$code]['dtl'] as $key => $value) {
278 if (preg_match("/^Ins(\d)/i", $value['src'], $tmp)) {
279 if ($tmp[1] <= $insnumber) $ptresp -= $value['pmt'];
281 else if (trim(substr($key, 0, 10))) { // not an adjustment if no date
282 if (!preg_match("/Ins(\d)/i", $value['rsn'], $tmp) || $tmp[1] <= $insnumber)
283 $ptresp += $value['chg']; // adjustments are negative charges
286 if ($ptresp < 0) $ptresp = 0; // we may be insane but try to hide it
288 // Main loop, to extract adjustments for this payer and procedure.
289 foreach ($this->invoice[$code]['dtl'] as $key => $value) {
290 $tmp = str_replace('-', '', trim(substr($key, 0, 10)));
291 if ($tmp) $date = $tmp;
292 if ($tmp && $value['pmt'] == 0) { // not original charge and not a payment
293 $rsn = $value['rsn'];
294 $chg = 0 - $value['chg']; // adjustments are negative charges
296 $gcode = 'CO'; // default group code = contractual obligation
297 $rcode = '45'; // default reason code = max fee exceeded (code 42 is obsolete)
299 if (preg_match("/Ins adjust $inslabel/i", $rsn, $tmp)) {
300 // From manual post. Take the defaults.
302 else if (preg_match("/To copay $inslabel/i", $rsn, $tmp) && !$chg) {
303 $coinsurance = $ptresp; // from manual post
304 continue;
306 else if (preg_match("/To ded'ble $inslabel/i", $rsn, $tmp) && !$chg) {
307 $deductible = $ptresp; // from manual post
308 continue;
310 else if (preg_match("/$inslabel copay: (\S+)/i", $rsn, $tmp) && !$chg) {
311 $coinsurance = $tmp[1]; // from 835 as of 6/2007
312 continue;
314 else if (preg_match("/$inslabel coins: (\S+)/i", $rsn, $tmp) && !$chg) {
315 $coinsurance = $tmp[1]; // from 835 and manual post as of 6/2007
316 continue;
318 else if (preg_match("/$inslabel dedbl: (\S+)/i", $rsn, $tmp) && !$chg) {
319 $deductible = $tmp[1]; // from 835 and manual post as of 6/2007
320 continue;
322 else if (preg_match("/$inslabel ptresp: (\S+)/i", $rsn, $tmp) && !$chg) {
323 continue; // from 835 as of 6/2007
325 else if (preg_match("/$inslabel adjust code (\S+)/i", $rsn, $tmp)) {
326 $rcode = $tmp[1]; // from 835
328 else if (preg_match("/$inslabel/i", $rsn, $tmp)) {
329 // Take the defaults.
331 else if (preg_match('/Ins(\d)/i', $rsn, $tmp) && $tmp[1] != $insnumber) {
332 continue; // it's for some other payer
334 else if ($insnumber == '1') {
335 if (preg_match("/\$\s*adjust code (\S+)/i", $rsn, $tmp)) {
336 $rcode = $tmp[1]; // from 835
338 else if ($chg) {
339 // Other adjustments default to Ins1.
341 else if (preg_match("/Co-pay: (\S+)/i", $rsn, $tmp) ||
342 preg_match("/Coinsurance: (\S+)/i", $rsn, $tmp)) {
343 $coinsurance = 0 + $tmp[1]; // from 835 before 6/2007
344 continue;
346 else if (preg_match("/To deductible: (\S+)/i", $rsn, $tmp)) {
347 $deductible = 0 + $tmp[1]; // from 835 before 6/2007
348 continue;
350 else {
351 continue; // there is no adjustment amount
354 else {
355 continue; // it's for primary and that's not us
358 if ($rcode == '42') $rcode= '45'; // reason 42 is obsolete
359 $aadj[] = array($date, $gcode, $rcode, sprintf('%.2f', $chg));
361 } // end if
362 } // end foreach
364 // If we really messed it up, at least avoid negative numbers.
365 if ($coinsurance > $ptresp) $coinsurance = $ptresp;
366 if ($deductible > $ptresp) $deductible = $ptresp;
368 // Find out if this payer paid anything at all on this claim. This will
369 // help us allocate any unknown patient responsibility amounts.
370 $thispaidanything = 0;
371 foreach($this->invoice as $codekey => $codeval) {
372 foreach ($codeval['dtl'] as $key => $value) {
373 if (preg_match("/$inslabel/i", $value['src'], $tmp)) {
374 $thispaidanything += $value['pmt'];
379 // Allocate any unknown patient responsibility by guessing if the
380 // deductible has been satisfied.
381 if ($thispaidanything)
382 $coinsurance = $ptresp - $deductible;
383 else
384 $deductible = $ptresp - $coinsurance;
386 if ($date && $deductible != 0)
387 $aadj[] = array($date, 'PR', '1', sprintf('%.2f', $deductible));
388 if ($date && $coinsurance != 0)
389 $aadj[] = array($date, 'PR', '2', sprintf('%.2f', $coinsurance));
391 } // end if
393 return $aadj;
396 // Return date, total payments and total "hard" adjustments from the given
397 // prior payer. If $code is specified then only that procedure key is
398 // selected, otherwise it's for the whole claim.
400 function payerTotals($ins, $code='') {
401 // If we have no modifiers stored in SQL-Ledger for this claim,
402 // then we cannot use a modifier passed in with the key.
403 $tmp = strpos($code, ':');
404 if ($tmp && !$this->using_modifiers) $code = substr($code, 0, $tmp);
406 $inslabel = ($this->payerSequence($ins) == 'S') ? 'Ins2' : 'Ins1';
407 $paytotal = 0;
408 $adjtotal = 0;
409 $date = '';
410 foreach($this->invoice as $codekey => $codeval) {
411 if ($code && strcmp($codekey,$code) != 0) continue;
412 foreach ($codeval['dtl'] as $key => $value) {
413 if (preg_match("/$inslabel/i", $value['src'], $tmp)) {
414 if (!$date) $date = str_replace('-', '', trim(substr($key, 0, 10)));
415 $paytotal += $value['pmt'];
418 $aarr = $this->payerAdjustments($ins, $codekey);
419 foreach ($aarr as $a) {
420 if (strcmp($a[1],'PR') != 0) $adjtotal += $a[3];
421 if (!$date) $date = $a[0];
424 return array($date, sprintf('%.2f', $paytotal), sprintf('%.2f', $adjtotal));
427 // Return the amount already paid by the patient.
429 function patientPaidAmount() {
430 // For primary claims $this->invoice is not loaded, so get the co-pay
431 // from the billing table instead.
432 if (empty($this->invoice)) return $this->copay;
434 $amount = 0;
435 foreach($this->invoice as $codekey => $codeval) {
436 foreach ($codeval['dtl'] as $key => $value) {
437 if (!preg_match("/Ins/i", $value['src'], $tmp)) {
438 $amount += $value['pmt'];
442 return sprintf('%.2f', $amount);
445 // Return invoice total, including adjustments but not payments.
447 function invoiceTotal() {
448 $amount = 0;
449 foreach($this->invoice as $codekey => $codeval) {
450 $amount += $codeval['chg'];
452 return sprintf('%.2f', $amount);
455 // Number of procedures in this claim.
456 function procCount() {
457 return count($this->procs);
460 // Number of payers for this claim. Ranges from 1 to 3.
461 function payerCount() {
462 return count($this->payers);
465 function x12gsversionstring() {
466 return x12clean(trim($this->x12_partner['x12_version']));
469 function x12gssenderid() {
470 $tmp = $this->x12_partner['x12_sender_id'];
471 while (strlen($tmp) < 15) $tmp .= " ";
472 return $tmp;
475 function x12gsreceiverid() {
476 $tmp = $this->x12_partner['x12_receiver_id'];
477 while (strlen($tmp) < 15) $tmp .= " ";
478 return $tmp;
481 function cliaCode() {
482 return x12clean(trim($this->facility['domain_identifier']));
485 function billingFacilityName() {
486 return x12clean(trim($this->billing_facility['name']));
489 function billingFacilityStreet() {
490 return x12clean(trim($this->billing_facility['street']));
493 function billingFacilityCity() {
494 return x12clean(trim($this->billing_facility['city']));
497 function billingFacilityState() {
498 return x12clean(trim($this->billing_facility['state']));
501 function billingFacilityZip() {
502 return x12clean(trim($this->billing_facility['postal_code']));
505 function billingFacilityETIN() {
506 return x12clean(trim(str_replace('-', '', $this->billing_facility['federal_ein'])));
509 function billingFacilityNPI() {
510 return x12clean(trim($this->billing_facility['facility_npi']));
513 # The billing facility and the patient must both accept for this to return true.
514 function billingFacilityAssignment($ins=0) {
515 $tmp = strtoupper($this->payers[$ins]['data']['accept_assignment']);
516 if (strcmp($tmp,'FALSE') == 0) return '0';
517 return !empty($this->billing_facility['accepts_assignment']);
520 function billingContactName() {
521 return x12clean(trim($this->billing_facility['attn']));
524 function billingContactPhone() {
525 if (preg_match("/([2-9]\d\d)\D*(\d\d\d)\D*(\d\d\d\d)/",
526 $this->billing_facility['phone'], $tmp))
528 return $tmp[1] . $tmp[2] . $tmp[3];
530 return '';
533 function facilityName() {
534 return x12clean(trim($this->facility['name']));
537 function facilityStreet() {
538 return x12clean(trim($this->facility['street']));
541 function facilityCity() {
542 return x12clean(trim($this->facility['city']));
545 function facilityState() {
546 return x12clean(trim($this->facility['state']));
549 function facilityZip() {
550 return x12clean(trim($this->facility['postal_code']));
553 function facilityETIN() {
554 return x12clean(trim(str_replace('-', '', $this->facility['federal_ein'])));
557 function facilityNPI() {
558 return x12clean(trim($this->facility['facility_npi']));
561 function facilityPOS() {
562 return x12clean(trim($this->facility['pos_code']));
565 function clearingHouseName() {
566 return x12clean(trim($this->x12_partner['name']));
569 function clearingHouseETIN() {
570 return x12clean(trim(str_replace('-', '', $this->x12_partner['id_number'])));
573 function providerNumberType($prockey=-1) {
574 $tmp = ($prockey < 0 || empty($this->procs[$prockey]['provider_id'])) ?
575 $this->insurance_numbers : $this->procs[$prockey]['insurance_numbers'];
576 return $tmp['provider_number_type'];
579 function providerNumber($prockey=-1) {
580 $tmp = ($prockey < 0 || empty($this->procs[$prockey]['provider_id'])) ?
581 $this->insurance_numbers : $this->procs[$prockey]['insurance_numbers'];
582 return x12clean(trim(str_replace('-', '', $tmp['provider_number'])));
585 function providerGroupNumber($prockey=-1) {
586 $tmp = ($prockey < 0 || empty($this->procs[$prockey]['provider_id'])) ?
587 $this->insurance_numbers : $this->procs[$prockey]['insurance_numbers'];
588 return x12clean(trim(str_replace('-', '', $tmp['group_number'])));
591 // Returns 'P', 'S' or 'T'.
593 function payerSequence($ins=0) {
594 return strtoupper(substr($this->payers[$ins]['data']['type'], 0, 1));
597 // Returns the HIPAA code of the patient-to-subscriber relationship.
599 function insuredRelationship($ins=0) {
600 $tmp = strtolower($this->payers[$ins]['data']['subscriber_relationship']);
601 if (strcmp($tmp,'self' ) == 0) return '18';
602 if (strcmp($tmp,'spouse') == 0) return '01';
603 if (strcmp($tmp,'child' ) == 0) return '19';
604 if (strcmp($tmp,'other' ) == 0) return 'G8';
605 return $tmp; // should not happen
608 function insuredTypeCode($ins=0) {
609 if (strcmp($this->claimType($ins),'MB') == 0 && $this->payerSequence($ins) != 'P')
610 return '12'; // medicare secondary working aged beneficiary or
611 // spouse with employer group health plan
612 return '';
615 // Is the patient also the subscriber?
617 function isSelfOfInsured($ins=0) {
618 $tmp = strtolower($this->payers[$ins]['data']['subscriber_relationship']);
619 return (strcmp($tmp,'self') == 0);
622 function planName($ins=0) {
623 return x12clean(trim($this->payers[$ins]['data']['plan_name']));
626 function policyNumber($ins=0) { // "ID"
627 return x12clean(trim($this->payers[$ins]['data']['policy_number']));
630 function groupNumber($ins=0) {
631 return x12clean(trim($this->payers[$ins]['data']['group_number']));
634 function groupName($ins=0) {
635 return x12clean(trim($this->payers[$ins]['data']['subscriber_employer']));
638 // Claim types are:
639 // 16 Other HCFA
640 // MB Medicare Part B
641 // MC Medicaid
642 // CH ChampUSVA
643 // CH ChampUS
644 // BL Blue Cross Blue Shield
645 // 16 FECA
646 // 09 Self Pay
647 // 10 Central Certification
648 // 11 Other Non-Federal Programs
649 // 12 Preferred Provider Organization (PPO)
650 // 13 Point of Service (POS)
651 // 14 Exclusive Provider Organization (EPO)
652 // 15 Indemnity Insurance
653 // 16 Health Maintenance Organization (HMO) Medicare Risk
654 // AM Automobile Medical
655 // CI Commercial Insurance Co.
656 // DS Disability
657 // HM Health Maintenance Organization
658 // LI Liability
659 // LM Liability Medical
660 // OF Other Federal Program
661 // TV Title V
662 // VA Veterans Administration Plan
663 // WC Workers Compensation Health Plan
664 // ZZ Mutually Defined
666 function claimType($ins=0) {
667 if (empty($this->payers[$ins]['object'])) return '';
668 return $this->payers[$ins]['object']->get_freeb_claim_type();
671 function insuredLastName($ins=0) {
672 return x12clean(trim($this->payers[$ins]['data']['subscriber_lname']));
675 function insuredFirstName($ins=0) {
676 return x12clean(trim($this->payers[$ins]['data']['subscriber_fname']));
679 function insuredMiddleName($ins=0) {
680 return x12clean(trim($this->payers[$ins]['data']['subscriber_mname']));
683 function insuredStreet($ins=0) {
684 return x12clean(trim($this->payers[$ins]['data']['subscriber_street']));
687 function insuredCity($ins=0) {
688 return x12clean(trim($this->payers[$ins]['data']['subscriber_city']));
691 function insuredState($ins=0) {
692 return x12clean(trim($this->payers[$ins]['data']['subscriber_state']));
695 function insuredZip($ins=0) {
696 return x12clean(trim($this->payers[$ins]['data']['subscriber_postal_code']));
699 function insuredPhone($ins=0) {
700 if (preg_match("/([2-9]\d\d)\D*(\d\d\d)\D*(\d\d\d\d)/",
701 $this->payers[$ins]['data']['subscriber_phone'], $tmp))
702 return $tmp[1] . $tmp[2] . $tmp[3];
703 return '';
706 function insuredDOB($ins=0) {
707 return str_replace('-', '', $this->payers[$ins]['data']['subscriber_DOB']);
710 function insuredSex($ins=0) {
711 return strtoupper(substr($this->payers[$ins]['data']['subscriber_sex'], 0, 1));
714 function payerName($ins=0) {
715 return x12clean(trim($this->payers[$ins]['company']['name']));
718 function payerAttn($ins=0) {
719 return x12clean(trim($this->payers[$ins]['company']['attn']));
722 function payerStreet($ins=0) {
723 if (empty($this->payers[$ins]['object'])) return '';
724 $tmp = $this->payers[$ins]['object'];
725 $tmp = $tmp->get_address();
726 return x12clean(trim($tmp->get_line1()));
729 function payerCity($ins=0) {
730 if (empty($this->payers[$ins]['object'])) return '';
731 $tmp = $this->payers[$ins]['object'];
732 $tmp = $tmp->get_address();
733 return x12clean(trim($tmp->get_city()));
736 function payerState($ins=0) {
737 if (empty($this->payers[$ins]['object'])) return '';
738 $tmp = $this->payers[$ins]['object'];
739 $tmp = $tmp->get_address();
740 return x12clean(trim($tmp->get_state()));
743 function payerZip($ins=0) {
744 if (empty($this->payers[$ins]['object'])) return '';
745 $tmp = $this->payers[$ins]['object'];
746 $tmp = $tmp->get_address();
747 return x12clean(trim($tmp->get_zip()));
750 function payerID($ins=0) {
751 return x12clean(trim($this->payers[$ins]['company']['cms_id']));
754 function patientLastName() {
755 return x12clean(trim($this->patient_data['lname']));
758 function patientFirstName() {
759 return x12clean(trim($this->patient_data['fname']));
762 function patientMiddleName() {
763 return x12clean(trim($this->patient_data['mname']));
766 function patientStreet() {
767 return x12clean(trim($this->patient_data['street']));
770 function patientCity() {
771 return x12clean(trim($this->patient_data['city']));
774 function patientState() {
775 return x12clean(trim($this->patient_data['state']));
778 function patientZip() {
779 return x12clean(trim($this->patient_data['postal_code']));
782 function patientPhone() {
783 $ptphone = $this->patient_data['phone_home'];
784 if (!$ptphone) $ptphone = $this->patient_data['phone_biz'];
785 if (!$ptphone) $ptphone = $this->patient_data['phone_cell'];
786 if (preg_match("/([2-9]\d\d)\D*(\d\d\d)\D*(\d\d\d\d)/", $ptphone, $tmp))
787 return $tmp[1] . $tmp[2] . $tmp[3];
788 return '';
791 function patientDOB() {
792 return str_replace('-', '', $this->patient_data['DOB']);
795 function patientSex() {
796 return strtoupper(substr($this->patient_data['sex'], 0, 1));
799 // Patient Marital Status: M = Married, S = Single, or something else.
800 function patientStatus() {
801 return strtoupper(substr($this->patient_data['status'], 0, 1));
804 // This should be UNEMPLOYED, STUDENT, PT STUDENT, or anything else to
805 // indicate employed.
806 function patientOccupation() {
807 return strtoupper(x12clean(trim($this->patient_data['occupation'])));
810 function cptCode($prockey) {
811 return x12clean(trim($this->procs[$prockey]['code']));
814 function cptModifier($prockey) {
815 return x12clean(trim($this->procs[$prockey]['modifier']));
818 // Returns the procedure code, followed by ":modifier" if there is one.
819 function cptKey($prockey) {
820 $tmp = $this->cptModifier($prockey);
821 return $this->cptCode($prockey) . ($tmp ? ":$tmp" : "");
824 function cptCharges($prockey) {
825 return x12clean(trim($this->procs[$prockey]['fee']));
828 function cptUnits($prockey) {
829 if (empty($this->procs[$prockey]['units'])) return '1';
830 return x12clean(trim($this->procs[$prockey]['units']));
833 // NDC drug ID.
834 function cptNDCID($prockey) {
835 $ndcinfo = $this->procs[$prockey]['ndc_info'];
836 if (preg_match('/^N4(\S+)\s+(\S\S)(.*)/', $ndcinfo, $tmp)) {
837 $ndc = $tmp[1];
838 if (preg_match('/^(\d+)-(\d+)-(\d+)$/', $ndc, $tmp)) {
839 return sprintf('%05d-%04d-%02d', $tmp[1], $tmp[2], $tmp[3]);
841 return x12clean($ndc); // format is bad but return it anyway
843 return '';
846 // NDC drug unit of measure code.
847 function cptNDCUOM($prockey) {
848 $ndcinfo = $this->procs[$prockey]['ndc_info'];
849 if (preg_match('/^N4(\S+)\s+(\S\S)(.*)/', $ndcinfo, $tmp))
850 return x12clean($tmp[2]);
851 return '';
854 // NDC drug number of units.
855 function cptNDCQuantity($prockey) {
856 $ndcinfo = $this->procs[$prockey]['ndc_info'];
857 if (preg_match('/^N4(\S+)\s+(\S\S)(.*)/', $ndcinfo, $tmp)) {
858 return x12clean(ltrim($tmp[3], '0'));
860 return '';
863 function onsetDate() {
864 return str_replace('-', '', substr($this->encounter['onset_date'], 0, 10));
867 function serviceDate() {
868 return str_replace('-', '', substr($this->encounter['date'], 0, 10));
871 function priorAuth() {
872 return x12clean(trim($this->billing_options['prior_auth_number']));
875 function isRelatedEmployment() {
876 return !empty($this->billing_options['employment_related']);
879 function isRelatedAuto() {
880 return !empty($this->billing_options['auto_accident']);
883 function isRelatedOther() {
884 return !empty($this->billing_options['other_accident']);
887 function autoAccidentState() {
888 return x12clean(trim($this->billing_options['accident_state']));
891 function isUnableToWork() {
892 return !empty($this->billing_options['is_unable_to_work']);
895 function offWorkFrom() {
896 return str_replace('-', '', substr($this->billing_options['off_work_from'], 0, 10));
899 function offWorkTo() {
900 return str_replace('-', '', substr($this->billing_options['off_work_to'], 0, 10));
903 function isHospitalized() {
904 return !empty($this->billing_options['is_hospitalized']);
907 function hospitalizedFrom() {
908 return str_replace('-', '', substr($this->billing_options['hospitalization_date_from'], 0, 10));
911 function hospitalizedTo() {
912 return str_replace('-', '', substr($this->billing_options['hospitalization_date_to'], 0, 10));
915 function isOutsideLab() {
916 return !empty($this->billing_options['outside_lab']);
919 function outsideLabAmount() {
920 return sprintf('%.2f', 0 + $this->billing_options['lab_amount']);
923 function medicaidResubmissionCode() {
924 return x12clean(trim($this->billing_options['medicaid_resubmission_code']));
927 function medicaidOriginalReference() {
928 return x12clean(trim($this->billing_options['medicaid_original_reference']));
931 function frequencyTypeCode() {
932 return empty($this->billing_options['replacement_claim']) ? '1' : '7';
935 function additionalNotes() {
936 return x12clean(trim($this->billing_options['comments']));
939 // Returns an array of unique diagnoses. Periods are stripped.
940 function diagArray() {
941 $da = array();
942 foreach ($this->procs as $row) {
943 $atmp = explode(':', $row['justify']);
944 foreach ($atmp as $tmp) {
945 if (!empty($tmp)) {
946 $diag = str_replace('.', '', $tmp);
947 $da[$diag] = $diag;
951 return $da;
954 // Compute one 1-relative index in diagArray for the given procedure.
955 // This function is obsolete, use diagIndexArray() instead.
956 function diagIndex($prockey) {
957 $da = $this->diagArray();
958 $tmp = explode(':', $this->procs[$prockey]['justify']);
959 if (empty($tmp)) return '';
960 $diag = str_replace('.', '', $tmp[0]);
961 $i = 0;
962 foreach ($da as $value) {
963 ++$i;
964 if (strcmp($value,$diag) == 0) return $i;
966 return '';
969 // Compute array of 1-relative diagArray indices for the given procedure.
970 function diagIndexArray($prockey) {
971 $dia = array();
972 $da = $this->diagArray();
973 $atmp = explode(':', $this->procs[$prockey]['justify']);
974 foreach ($atmp as $tmp) {
975 if (!empty($tmp)) {
976 $diag = str_replace('.', '', $tmp);
977 $i = 0;
978 foreach ($da as $value) {
979 ++$i;
980 if (strcmp($value,$diag) == 0) $dia[] = $i;
984 return $dia;
987 function providerLastName($prockey=-1) {
988 $tmp = ($prockey < 0 || empty($this->procs[$prockey]['provider_id'])) ?
989 $this->provider : $this->procs[$prockey]['provider'];
990 return x12clean(trim($tmp['lname']));
993 function providerFirstName($prockey=-1) {
994 $tmp = ($prockey < 0 || empty($this->procs[$prockey]['provider_id'])) ?
995 $this->provider : $this->procs[$prockey]['provider'];
996 return x12clean(trim($tmp['fname']));
999 function providerMiddleName($prockey=-1) {
1000 $tmp = ($prockey < 0 || empty($this->procs[$prockey]['provider_id'])) ?
1001 $this->provider : $this->procs[$prockey]['provider'];
1002 return x12clean(trim($tmp['mname']));
1005 function providerNPI($prockey=-1) {
1006 $tmp = ($prockey < 0 || empty($this->procs[$prockey]['provider_id'])) ?
1007 $this->provider : $this->procs[$prockey]['provider'];
1008 return x12clean(trim($tmp['npi']));
1011 function providerUPIN($prockey=-1) {
1012 $tmp = ($prockey < 0 || empty($this->procs[$prockey]['provider_id'])) ?
1013 $this->provider : $this->procs[$prockey]['provider'];
1014 return x12clean(trim($tmp['upin']));
1017 function providerSSN($prockey=-1) {
1018 $tmp = ($prockey < 0 || empty($this->procs[$prockey]['provider_id'])) ?
1019 $this->provider : $this->procs[$prockey]['provider'];
1020 return x12clean(trim(str_replace('-', '', $tmp['federaltaxid'])));
1023 function providerTaxonomy($prockey=-1) {
1024 $tmp = ($prockey < 0 || empty($this->procs[$prockey]['provider_id'])) ?
1025 $this->provider : $this->procs[$prockey]['provider'];
1026 if (empty($tmp['taxonomy'])) return '207Q00000X';
1027 return x12clean(trim($tmp['taxonomy']));
1030 function referrerLastName() {
1031 return x12clean(trim($this->referrer['lname']));
1034 function referrerFirstName() {
1035 return x12clean(trim($this->referrer['fname']));
1038 function referrerMiddleName() {
1039 return x12clean(trim($this->referrer['mname']));
1042 function referrerNPI() {
1043 return x12clean(trim($this->referrer['npi']));
1046 function referrerUPIN() {
1047 return x12clean(trim($this->referrer['upin']));
1050 function referrerSSN() {
1051 return x12clean(trim(str_replace('-', '', $this->referrer['federaltaxid'])));
1054 function referrerTaxonomy() {
1055 if (empty($this->referrer['taxonomy'])) return '207Q00000X';
1056 return x12clean(trim($this->referrer['taxonomy']));
1059 function supervisorLastName() {
1060 return x12clean(trim($this->supervisor['lname']));
1063 function supervisorFirstName() {
1064 return x12clean(trim($this->supervisor['fname']));
1067 function supervisorMiddleName() {
1068 return x12clean(trim($this->supervisor['mname']));
1071 function supervisorNPI() {
1072 return x12clean(trim($this->supervisor['npi']));
1075 function supervisorUPIN() {
1076 return x12clean(trim($this->supervisor['upin']));
1079 function supervisorSSN() {
1080 return x12clean(trim(str_replace('-', '', $this->supervisor['federaltaxid'])));
1083 function supervisorTaxonomy() {
1084 if (empty($this->supervisor['taxonomy'])) return '207Q00000X';
1085 return x12clean(trim($this->supervisor['taxonomy']));
1088 function supervisorNumberType() {
1089 return $this->supervisor_numbers['provider_number_type'];
1092 function supervisorNumber() {
1093 return x12clean(trim(str_replace('-', '', $this->supervisor_numbers['provider_number'])));