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 $tmp = strtolower($dtlinfo['src']);
122 for ($i = 1; $i <= 3; ++
$i) {
123 if (strpos($tmp, "ins$i") !== false) $payer_type = $i;
125 arPostPayment($pid, $encounter, $session_id, $dtlinfo['pmt'], $code,
126 $payer_type, $source, 0, "$dtldate 00:00:00");
128 sqlStatement("UPDATE ar_session SET pay_total = pay_total + '" .
129 $dtlinfo['pmt'] . "' WHERE session_id = '$session_id'");
132 else { // it's an adjustment
133 $tmp = strtolower($dtlinfo['rsn']);
134 for ($i = 1; $i <= 3; ++
$i) {
135 if (strpos($tmp, "ins$i") !== false) $payer_type = $i;
137 arPostAdjustment($pid, $encounter, $session_id, 0 - $dtlinfo['chg'],
138 $code, $payer_type, $dtlinfo['rsn'], 0, "$dtldate 00:00:00");
146 // Compute last insurance level billed.
147 $last_level_billed = 0;
149 $invdate = $row['transdate'];
150 $tmp = sqlQuery("SELECT type FROM insurance_data WHERE " .
151 "pid = '$patient_id' AND provider = '$last_biller' AND " .
152 "date <= '$invdate' ORDER BY date DESC, id ASC LIMIT 1");
153 $last_level_billed = ($tmp['type'] == 'tertiary') ?
154 3 : ($tmp['type'] == 'secondary') ?
2 : 1;
157 // Compute last insurance level closed.
158 $last_level_closed = 0;
159 $tmp = strtolower($row['shipvia']);
160 for ($i = 1; $i <= 3; ++
$i) {
161 if (strpos($tmp, "ins$i") !== false) $last_level_closed = $i;
164 // Compute last statement date and number of statements sent.
165 $last_stmt_date = "NULL";
168 $tmp = strtolower($row['intnotes']);
169 while (($i = strpos($tmp, 'statement sent ', $i)) !== false) {
171 $last_stmt_date = "'" . substr($tmp, $i, 10) . "'";
175 sqlStatement("UPDATE form_encounter SET " .
176 "last_level_billed = '$last_level_billed', " .
177 "last_level_closed = '$last_level_closed', " .
178 "last_stmt_date = $last_stmt_date, " .
179 "stmt_count = '$stmt_count'");
181 // Show a warning for any unmatched copays.
182 foreach ($copays as $copay) {
183 echo "Co-pay of \$$copay in the encounter was not found in " .
184 "SQL-Ledger invoice $pid.$encounter.<br />\n";
191 echo "$invoice_count SQL-Ledger invoices were processed.<br />\n";
192 echo "$activity_count payments and adjustments were posted.<br />\n";