4 function getBillingById($id, $cols = "*")
6 return sqlQuery("select $cols from billing where id='$id' and activity=1 order by date DESC limit 0,1");
9 function getBillingByPid($pid, $cols = "*")
11 return sqlQuery("select $cols from billing where pid ='$pid' and activity=1 order by date DESC limit 0,1");
14 function getBillingByEncounter($pid, $encounter, $cols = "code_type, code, code_text")
16 $res = sqlStatement("select $cols from billing where encounter = ? and pid=? and activity=1 order by code_type, date ASC", array($encounter,$pid));
19 for ($iter=0; $row=sqlFetchArray($res); $iter++) {
45 $sql = "insert into billing (date, encounter, code_type, code, code_text, " .
46 "pid, authorized, user, groupname, activity, billed, provider_id, " .
47 "modifier, units, fee, ndc_info, justify, notecodes, pricelevel, revenue_code) values (" .
48 "NOW(), ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
49 return sqlInsert($sql, array($encounter_id,$code_type,$code,$code_text,$pid,$authorized,
50 $_SESSION['authId'],$_SESSION['authProvider'],$billed,$provider,$modifier,$units,$fee,
51 $ndc_info,$justify,$notecodes,$pricelevel,$revenue_code));
54 function authorizeBilling($id, $authorized = "1")
56 sqlQuery("update billing set authorized = '$authorized' where id = '$id'");
59 function deleteBilling($id)
61 sqlStatement("update billing set activity = 0 where id = '$id'");
64 function clearBilling($id)
66 sqlStatement("update billing set justify = '' where id = '$id'");
69 // This function supports the Billing page (billing_process.php),
70 // and initiation of secondary processing (sl_eob.inc.php).
71 // It is called in the following situations:
73 // * billing_process.php sets bill_time, bill_process, payer and target on
74 // queueing a claim for processing. Create claims row.
75 // * billing_process.php sets claim status to 2, and payer, on marking a
76 // claim as billed without actually generating any billing. Create a
77 // claims row. In this case bill_process will remain at 0 and process_time
78 // and process_file will not be set.
79 // * billing_process.php sets bill_process, payer, target and x12 partner
80 // before calling gen_x12_837. Create a claims row.
81 // * billing_process.php sets claim status to 2 (billed), bill_process to 2,
82 // process_time and process_file after calling gen_x12_837. Claims row
84 // * billing_process.php sets claim status to 2 (billed) after creating
85 // an electronic batch (hcfa-only with recent changes). Claims
86 // row already exists.
87 // * EOB posting updates claim status to mark a payer as done. Claims row
89 // * EOB posting reopens an encounter for billing a secondary payer. Create
92 // $newversion should be passed to us to indicate if a new claims row
93 // is to be generated, otherwise one must already exist. The payer, if
94 // passed in for the latter case, must match the existing claim.
96 // Currently on the billing page the user can select any of the patient's
97 // payers. That logic will tailor the payer choices to the encounter date.
111 $submitted_claim = ''
114 $sqlBindArray = array();
116 $sql = "SELECT * FROM claims WHERE patient_id = ? AND " .
117 "encounter_id = ? AND status > 0 AND status < 4 ";
118 array_push($sqlBindArray, $patient_id, $encounter_id);
119 if ($payer_id >= 0) {
120 $sql .= "AND payer_id = ? ";
121 $sqlBindArray[] = $payer_id;
124 $sql .= "ORDER BY version DESC LIMIT 1";
125 $row = sqlQuery($sql, $sqlBindArray);
131 $payer_id = $row['payer_id'];
135 $status = $row['status'];
138 if ($bill_process < 0) {
139 $bill_process = $row['bill_process'];
142 if ($partner_id < 0) {
143 $partner_id = $row['x12_partner_id'];
146 if (!$process_file) {
147 $process_file = $row['process_file'];
151 $target = $row['target'];
156 $sqlBindClaimset = array();
158 $sqlBindBillset = array();
159 if (empty($payer_id) || $payer_id < 0) {
163 if ($status==7) {//$status==7 is the claim denial case.
164 $claimset .= ", status = ?";
165 $sqlBindClaimset[] = $status;
166 } elseif ($status >= 0) {
167 $claimset .= ", status = ?";
168 $sqlBindClaimset[] = $status;
170 $billset .= ", billed = 1";
172 $billset .= ", bill_date = NOW()";
175 $billset .= ", billed = 0";
179 if ($status==7) {//$status==7 is the claim denial case.
180 $billset .= ", bill_process = ?";
181 $sqlBindBillset[] = $status;
182 } elseif ($bill_process >= 0) {
183 $claimset .= ", bill_process = ?";
184 $sqlBindClaimset[] = $bill_process;
185 $billset .= ", bill_process = ?";
186 $sqlBindBillset[] = $bill_process;
189 if ($status==7) {//$status==7 is the claim denial case.
190 $claimset .= ", process_file = ?";//Denial reason code is stored here
191 $sqlBindClaimset[] = $process_file;
192 } elseif ($process_file) {
193 $claimset .= ", process_file = ?, process_time = NOW()";
194 $sqlBindClaimset[] = $process_file;
195 $billset .= ", process_file = ?, process_date = NOW()";
196 $sqlBindBillset[] = $process_file;
200 $claimset .= ", target = ?";
201 $sqlBindClaimset[] = $target;
202 $billset .= ", target = ?";
203 $sqlBindBillset[] = $target;
206 if ($payer_id >= 0) {
207 $claimset .= ", payer_id = ?, payer_type = ?";
208 $sqlBindClaimset[] = $payer_id;
209 $sqlBindClaimset[] = $payer_type;
210 $billset .= ", payer_id = ?";
211 $sqlBindBillset[] = $payer_id;
214 if ($partner_id >= 0) {
215 $claimset .= ", x12_partner_id = ?";
216 $sqlBindClaimset[] = $partner_id;
217 $billset .= ", x12_partner_id = ?";
218 $sqlBindBillset[] = $partner_id;
222 $billset = substr($billset, 2);
223 $sqlBindArray = $sqlBindBillset;
224 array_push($sqlBindArray, $encounter_id, $patient_id);
225 sqlStatement("UPDATE billing SET $billset WHERE " .
226 "encounter = ? AND pid= ? AND activity = 1", $sqlBindArray);
229 $claimset .= ", submitted_claim = ?";
230 $sqlBindClaimset[] = $submitted_claim;
231 // If a new claim version is requested, insert its row.
235 $payer_id = ($payer_id < 0) ? $row['payer_id'] : $payer_id;
236 $bill_process = ($bill_process < 0) ? $row['bill_process'] : $bill_process;
237 $process_file = ($process_file) ? $row['process_file'] : $process_file;
238 $target = ($target) ? $row['target'] : $target;
239 $partner_id = ($partner_id < 0) ? $row['x12_partner_id'] : $partner_id;
240 $sql = "INSERT INTO claims SET " .
241 "patient_id = '$patient_id', " .
242 "encounter_id = '$encounter_id', " .
243 "bill_time = UNIX_TIMESTAMP(NOW()), " .
244 "payer_id = '$payer_id', " .
245 "status = '$status', " .
246 "payer_type = '" . $row['payer_type'] . "', " .
247 "bill_process = '$bill_process', " .
248 "process_time = '" . $row['process_time'] . "', " .
249 "process_file = '$process_file', " .
250 "target = '$target', " .
251 "x12_partner_id = '$partner_id'";
254 $version = sqlQuery("SELECT IFNULL(MAX(version),0) + 1 AS increment FROM claims WHERE patient_id = ? AND encounter_id = ?", array($patient_id, $encounter_id));
256 $sqlBindArray = array();
257 array_push($sqlBindArray, $patient_id, $encounter_id);
259 $sql .= "INSERT INTO claims SET " .
261 "encounter_id = ?, " .
262 "bill_time = NOW() $claimset ," .
264 $sqlBindArray = array_merge($sqlBindArray, $sqlBindClaimset);
265 array_push($sqlBindArray, $version['increment']);
266 } else {//Claim automatic forward case.startTra
267 $sql= "INSERT INTO claims SET " .
269 "encounter_id = ?, " .
270 "bill_time = NOW(), status=? ," .
272 array_push($sqlBindArray, $status, $version['increment']);
275 sqlStatement($sql, $sqlBindArray);
277 } // Otherwise update the existing claim row.
279 else if ($claimset) {
280 $sqlBindArray = $sqlBindClaimset;
281 array_push($sqlBindArray, $patient_id, $encounter_id, $row['version']);
282 $claimset = substr($claimset, 2);
283 sqlStatement("UPDATE claims SET $claimset WHERE " .
284 "patient_id = ? AND encounter_id = ? AND " .
285 // "payer_id = '" . $row['payer_id'] . "' AND " .
286 "version = ?", $sqlBindArray);
289 // Whenever a claim is marked billed, update A/R accordingly.
291 if ($payer_type > 0) {
292 sqlStatement("UPDATE form_encounter SET " .
293 "last_level_billed = ? WHERE " .
294 "pid = ? AND encounter = ?", array($payer_type, $patient_id, $encounter_id));
301 // Determine if the encounter is billed. It is considered billed if it
302 // has at least one chargeable item, and all of them are billed.
304 function isEncounterBilled($pid, $encounter)
306 $billed = -1; // no chargeable services yet
308 $bres = sqlStatement(
310 "billing.billed FROM billing, code_types WHERE " .
311 "billing.pid = ? AND " .
312 "billing.encounter = ? AND " .
313 "billing.activity = 1 AND " .
314 "code_types.ct_key = billing.code_type AND " .
315 "code_types.ct_fee = 1 " .
317 "SELECT billed FROM drug_sales WHERE " .
320 array($pid, $encounter, $pid, $encounter)
323 while ($brow = sqlFetchArray($bres)) {
324 if ($brow['billed'] == 0) {
336 // Get the co-pay amount that is effective on the given date.
337 // Or if no insurance on that date, return -1.
339 function getCopay($patient_id, $encdate)
341 $tmp = sqlQuery("SELECT provider, copay FROM insurance_data " .
342 "WHERE pid = '$patient_id' AND type = 'primary' " .
343 "AND date <= '$encdate' ORDER BY date DESC LIMIT 1");
344 if ($tmp['provider']) {
345 return sprintf('%01.2f', 0 + $tmp['copay']);
351 // Get the total co-pay amount paid by the patient for an encounter
352 function getPatientCopay($patient_id, $encounter)
354 $resMoneyGot = sqlStatement(
355 "SELECT sum(pay_amount) as PatientPay FROM ar_activity where ".
356 "pid = ? and encounter = ? and payer_type=0 and account_code='PCP'",
357 array($patient_id,$encounter)
359 //new fees screen copay gives account_code='PCP'
360 $rowMoneyGot = sqlFetchArray($resMoneyGot);
361 $Copay=$rowMoneyGot['PatientPay'];
365 // Get the "next invoice reference number" from this user's pool of reference numbers.
367 function getInvoiceRefNumber()
371 "FROM users AS u, list_options AS lo " .
372 "WHERE u.username = ? AND " .
373 "lo.list_id = 'irnpool' AND lo.option_id = u.irnpool AND lo.activity = 1 LIMIT 1",
374 array($_SESSION['authUser'])
376 return empty($trow['notes']) ? '' : $trow['notes'];
379 // Increment the "next invoice reference number" of this user's pool.
380 // This identifies the "digits" portion of that number and adds 1 to it.
381 // If it contains more than one string of digits, the last is used.
383 function updateInvoiceRefNumber()
385 $irnumber = getInvoiceRefNumber();
386 // Here "?" specifies a minimal match, to get the most digits possible:
387 if (preg_match('/^(.*?)(\d+)(\D*)$/', $irnumber, $matches)) {
388 $newdigs = sprintf('%0' . strlen($matches[2]) . 'd', $matches[2] + 1);
389 $newnumber = $matches[1] . $newdigs . $matches[3];
391 "UPDATE users AS u, list_options AS lo " .
392 "SET lo.notes = ? WHERE " .
393 "u.username = ? AND " .
394 "lo.list_id = 'irnpool' AND lo.option_id = u.irnpool",
395 array($newnumber, $_SESSION['authUser'])
402 // Common function for voiding a receipt or checkout. When voiding a checkout you can specify
403 // $time as a timestamp (yyyy-mm-dd hh:mm:ss) or 'all'; default is the last checkout.
405 function doVoid($patient_id, $encounter_id, $purge = false, $time = '')
407 $what_voided = $purge ? 'checkout' : 'receipt';
413 // Get last checkout timestamp.
415 "(SELECT bill_date FROM billing WHERE " .
416 "pid = ? AND encounter = ? AND activity = 1 AND bill_date IS NOT NULL) " .
418 "(SELECT bill_date FROM drug_sales WHERE " .
419 "pid = ? AND encounter = ? AND bill_date IS NOT NULL) " .
420 "ORDER BY bill_date DESC LIMIT 1",
421 array($patient_id, $encounter_id, $patient_id, $encounter_id)
423 if (!empty($corow['bill_date'])) {
424 $date_original = $corow['bill_date'];
426 } else if ($time == 'all') {
428 "SELECT SUM(pay_amount) AS payments, " .
429 "SUM(adj_amount) AS adjustments FROM ar_activity WHERE " .
430 "pid = ? AND encounter = ?",
431 array($patient_id, $encounter_id)
433 $adjustments = empty($row['adjustments']) ? 0 : $row['adjustments'];
434 $payments = empty($row['payments']) ? 0 : $row['payments'];
436 $date_original = $time;
439 // Get its charges and adjustments.
440 if ($date_original) {
442 "SELECT SUM(pay_amount) AS payments, " .
443 "SUM(adj_amount) AS adjustments FROM ar_activity WHERE " .
444 "pid = ? AND encounter = ? AND post_time = ?",
445 array($patient_id, $encounter_id, $date_original)
447 $adjustments = empty($row['adjustments']) ? 0 : $row['adjustments'];
448 $payments = empty($row['payments']) ? 0 : $row['payments'];
451 // Get old invoice reference number.
453 "SELECT invoice_refno FROM form_encounter WHERE " .
454 "pid = ? AND encounter = ? LIMIT 1",
455 array($patient_id, $encounter_id)
457 $old_invoice_refno = $encrow['invoice_refno'];
459 $usingirnpools = getInvoiceRefNumber();
460 // If not (undoing a checkout or using IRN pools), nothing is done.
461 if ($purge || $usingirnpools) {
462 $query = "INSERT INTO voids SET " .
464 "encounter_id = ?, " .
465 "what_voided = ?, " .
466 "date_voided = NOW(), " .
471 $sqlarr = array($patient_id, $encounter_id, $what_voided, $_SESSION['authUserID'], $adjustments,
472 $payments, $old_invoice_refno);
473 if ($date_original) {
474 $query .= ", date_original = ?";
475 $sqlarr[] = $date_original;
478 sqlStatement($query, $sqlarr);
482 // Purge means delete adjustments and payments from the last checkout
483 // and re-open the visit.
484 if ($date_original) {
486 "DELETE FROM ar_activity WHERE " .
487 "pid = ? AND encounter = ? AND post_time = ?",
488 array($patient_id, $encounter_id, $date_original)
491 "UPDATE billing SET billed = 0, bill_date = NULL WHERE " .
492 "pid = ? AND encounter = ? AND activity = 1 AND " .
493 "bill_date IS NOT NULL AND bill_date = ?",
494 array($patient_id, $encounter_id, $date_original)
497 "update drug_sales SET billed = 0, bill_date = NULL WHERE " .
498 "pid = ? AND encounter = ? AND " .
499 "bill_date IS NOT NULL AND bill_date = ?",
500 array($patient_id, $encounter_id, $date_original)
503 if ($time == 'all') {
505 "DELETE FROM ar_activity WHERE " .
506 "pid = ? AND encounter = ?",
507 array($patient_id, $encounter_id)
512 "UPDATE billing SET billed = 0, bill_date = NULL WHERE " .
513 "pid = ? AND encounter = ? AND activity = 1",
514 array($patient_id, $encounter_id)
517 "update drug_sales SET billed = 0, bill_date = NULL WHERE " .
518 "pid = ? AND encounter = ?",
519 array($patient_id, $encounter_id)
524 "UPDATE form_encounter SET last_level_billed = 0, " .
525 "last_level_closed = 0, stmt_count = 0, last_stmt_date = NULL " .
526 "WHERE pid = ? AND encounter = ?",
527 array($patient_id, $encounter_id)
529 } else if ($usingirnpools) {
530 // Non-purge means just assign a new invoice reference number.
531 $new_invoice_refno = add_escape_custom(updateInvoiceRefNumber());
533 "UPDATE form_encounter " .
534 "SET invoice_refno = ? " .
535 "WHERE pid = ? AND encounter = ?",
536 array($new_invoice_refno, $patient_id, $encounter_id)