2 // Copyright (C) 2008 Rod Roark <rod@sunsetsystems.com>
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 // This may be run after an upgraded OpenEMR has been installed.
10 // Its purpose is to extract A/R information from SQL-Ledger and
11 // convert it to the OpenEMR tables that maintain A/R internally,
12 // thus eliminating SQL-Ledger.
14 $ignoreAuth=true; // no login required
16 require_once('interface/globals.php');
17 require_once('library/sql-ledger.inc');
18 require_once('library/invoice_summary.inc.php');
19 require_once('library/sl_eob.inc.php');
21 $tmp = sqlQuery("SELECT count(*) AS count FROM ar_activity");
22 if ($tmp['count']) die("ar_activity and ar_session must be empty to run this script!");
26 <title
>OpenEMR Conversion from SQL
-Ledger
</title
>
27 <link rel
='STYLESHEET' href
='interface/themes/style_blue.css'>
30 <span
class='title'>OpenEMR Conversion from SQL
-Ledger
</span
>
39 $res = SLQuery("SELECT id, invnumber, transdate, shipvia, intnotes " .
40 "FROM ar ORDER BY id");
42 for ($irow = 0; $irow < SLRowCount($res); ++
$irow) {
43 $row = SLGetRow($res, $irow);
44 list($pid, $encounter) = explode(".", $row['invnumber']);
48 $svcdate = $row['transdate'];
50 // Scan billing table items to get the provider ID and copays.
51 $bres = sqlStatement("SELECT * FROM billing WHERE " .
52 "pid = '$pid' AND encounter = '$encounter' AND activity = 1 " .
53 "AND billed = 1 AND fee != 0 ORDER BY fee DESC");
54 while ($brow = sqlFetchArray($bres)) {
55 if (!$provider_id) $provider_id = $brow['provider_id'];
56 if (!$last_biller && !empty($brow['payer_id'])) $last_biller = $brow['payer_id'];
57 if ($brow['code_type'] == 'COPAY') $copays[] = 0 - $brow['fee'];
60 // Delete any TAX rows from billing for encounters in SQL-Ledger.
61 sqlStatement("UPDATE billing SET activity = 0 WHERE " .
62 "pid = '$pid' AND encounter = '$encounter' AND " .
65 $invlines = get_invoice_summary($row['id'], true);
67 // print_r($invlines); // debugging
70 foreach ($invlines as $codekey => $codeinfo) {
71 ksort($codeinfo['dtl']);
72 $code = strtoupper($codekey);
73 if ($code == 'CO-PAY' ||
$code == 'UNKNOWN') $code = '';
75 foreach ($codeinfo['dtl'] as $dtlkey => $dtlinfo) {
76 $dtldate = trim(substr($dtlkey, 0, 10));
77 if (empty($dtldate)) {
78 // Insert taxes but ignore other charges.
80 sqlInsert("INSERT INTO billing ( date, encounter, code_type, code, code_text, " .
81 "pid, authorized, user, groupname, activity, billed, provider_id, " .
82 "modifier, units, fee, ndc_info, justify ) values ( " .
83 "'$svcdate 00:00:00', '$encounter', 'TAX', 'TAX', '" . $dtlinfo['dsc'] . "', " .
84 "'$pid', '1', '$provider_id', 'Default', 1, 1, $provider_id, '', '1', " .
85 "'" . $dtlinfo['chg'] . "', '', '' )");
87 continue; // otherwise skip charges
89 $payer_id = empty($dtlinfo['ins']) ?
0 : $dtlinfo['ins'];
92 // Compute a reasonable "source" value. For payments this will
93 // commonly be a check number, for adjustments we have none.
94 $source = empty($dtlinfo['src']) ?
'' : $dtlinfo['src'];
95 $source = preg_replace('!^Ins[123]/!i', '', $source);
96 $source = preg_replace('!^Pt/!i', '', $source);
97 if ($source == '' && empty($dtlinfo['pmt'])) {
98 $source = 'From SQL-Ledger';
101 // For insurance payers look up or create the session table entry.
103 $session_id = arGetSession($payer_id, $source, $dtldate);
105 // For non-insurance payers deal with copay duplication.
106 else if ($code == '') {
107 if (!empty($dtlinfo['pmt'])) {
108 // Skip payments that are already present in the billing table as copays.
109 foreach ($copays as $key => $value) {
110 if ($value == $dtlinfo['pmt']) {
111 unset($copays[$key]);
112 continue 2; // skip this detail item
116 } // end not insurance
120 if (!empty($dtlinfo['pmt'])) { // it's a payment
121 for ($i = 1; $i <= 3; ++
$i) {
122 if (stripos($dtlinfo['src'], "Ins$i") !== false) $payer_type = $i;
124 arPostPayment($pid, $encounter, $session_id, $dtlinfo['pmt'], $code,
125 $payer_type, $source, 0, "$dtldate 00:00:00");
127 sqlStatement("UPDATE ar_session SET pay_total = pay_total + '" .
128 $dtlinfo['pmt'] . "' WHERE session_id = '$session_id'");
131 else { // it's an adjustment
132 for ($i = 1; $i <= 3; ++
$i) {
133 if (stripos($dtlinfo['rsn'], "Ins$i") !== false) $payer_type = $i;
135 arPostAdjustment($pid, $encounter, $session_id, 0 - $dtlinfo['chg'],
136 $code, $payer_type, $dtlinfo['rsn'], 0, "$dtldate 00:00:00");
144 // Compute last insurance level billed.
145 $last_level_billed = 0;
147 $invdate = $row['transdate'];
148 $tmp = sqlQuery("SELECT type FROM insurance_data WHERE " .
149 "pid = '$patient_id' AND provider = '$last_biller' AND " .
150 "date <= '$invdate' ORDER BY date DESC, id ASC LIMIT 1");
151 $last_level_billed = ($tmp['type'] == 'tertiary') ?
152 3 : ($tmp['type'] == 'secondary') ?
2 : 1;
155 // Compute last insurance level closed.
156 $last_level_closed = 0;
157 for ($i = 1; $i <= 3; ++
$i) {
158 if (stripos($row['shipvia'], "Ins$i") !== false) $last_level_closed = $i;
161 // Compute last statement date and number of statements sent.
162 $last_stmt_date = "NULL";
165 while ($i = stripos($row['intnotes'], 'Statement sent ', $i) !== false) {
167 $last_stmt_date = "'" . substr($row['intnotes'], $i, 10) . "'";
171 sqlStatement("UPDATE form_encounter SET " .
172 "last_level_billed = '$last_level_billed', " .
173 "last_level_closed = '$last_level_closed', " .
174 "last_stmt_date = $last_stmt_date, " .
175 "stmt_count = '$stmt_count'");
177 // Show a warning for any unmatched copays.
178 foreach ($copays as $copay) {
179 echo "Co-pay of \$$copay in the encounter was not found in " .
180 "SQL-Ledger invoice $pid.$encounter.<br />\n";
187 echo "$invoice_count SQL-Ledger invoices were processed.<br />\n";
188 echo "$activity_count payments and adjustments were posted.<br />\n";