another billing class and moved reports to billing (#2683)
[openemr.git] / src / Billing / EDI_270.php
blob245016c7c6d3f78b592a0de56a4b5291d696a7b4
1 <?php
2 /**
3 * Inc file for the 270 / 271 creation and uploading
5 * This program creates the segments for the x12 270 eligibility file
6 * It also allows the reading and storing of the x12 271 file
8 * @package OpenEMR
9 * @link http://www.open-emr.org
10 * @author Terry Hill <terry@lilysystems.com>
11 * @author Brady Miller <brady.g.miller@gmail.com>
12 * @author Jerry Padgett <sjpadgett@gmail.com>
13 * @author Stephen Waite <stephen.waite@cmsvt.com>
14 * @copyright Copyright (c) 2010 MMF Systems, Inc
15 * @copyright Copyright (c) 2016 Terry Hill <terry@lillysystems.com>
16 * @copyright Copyright (c) 2017 Brady Miller <brady.g.miller@gmail.com>
17 * @copyright Copyright (c) 2019 Jerry Padgett <sjpadgett@gmail.com>
18 * @copyright Copyright (c) 2019 Stephen Waite <stephen.waite@cmsvt.com>
19 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
21 namespace OpenEMR\Billing;
23 require_once(dirname(__FILE__) . "/../../library/edihistory/codes/edih_271_code_class.php");
25 use OpenEMR\Common\Http\oeHttp;
26 use OpenEMR\Common\Utils\RandomGenUtils;
28 // @TODO global to become private var when this goes to a class.
30 class EDI_270
32 // SEGMENT FUNCTION START
33 // ISA Segment - EDI-270 format
35 // @sjpadgett's recommendation to try singleton class, see _rest_config.php
36 // basically prevents external construction
37 private function __construct()
41 public static function create_ISA($row, $X12info, $segTer, $compEleSep)
43 $ISA = array();
44 $ISA[0] = "ISA"; // Interchange Control Header Segment ID
45 $ISA[1] = "00"; // Author Info Qualifier
46 $ISA[2] = str_pad("0000000", 10, " "); // Author Information
47 $ISA[3] = "00"; // Security Information Qualifier
48 // MEDI-CAL NOTE: For Leased-Line & Dial-Up use '01',
49 // for BATCH use '00'.
50 // '00' No Security Information Present
51 // (No Meaningful Information in I04)
52 $ISA[4] = str_pad("0000000000", 10, " "); // Security Information
53 $ISA[5] = str_pad($X12info['x12_isa05'], 2, " "); // Interchange ID Qualifier
54 $ISA[6] = str_pad($X12info['x12_sender_id'], 15, " "); // INTERCHANGE SENDER ID
55 $ISA[7] = str_pad($X12info['x12_isa07'], 2, " "); // Interchange ID Qualifier
56 $ISA[8] = str_pad($X12info['x12_receiver_id'], 15, " "); // INTERCHANGE RECEIVER ID
57 $ISA[9] = str_pad(date('ymd'), 6, " "); // Interchange Date (YYMMDD)
58 $ISA[10] = str_pad(date('Hi'), 4, " "); // Interchange Time (HHMM)
59 $ISA[11] = "^"; // Interchange Control Standards Identifier
60 $ISA[12] = str_pad("00501", 5, " "); // Interchange Control Version Number
61 $ISA[13] = str_pad("000000001", 9, " "); // INTERCHANGE CONTROL NUMBER
62 $ISA[14] = str_pad($X12info['x12_isa14'], 1, " "); // Acknowledgment Request [0= not requested, 1= requested]
63 $ISA[15] = str_pad($X12info['x12_isa15'], 1, " "); // Usage Indicator [ P = Production Data, T = Test Data ]
64 $ISA['Created'] = implode('*', $ISA); // Data Element Separator
65 $ISA['Created'] = $ISA['Created'] . "*";
66 $ISA['Created'] = $ISA ['Created'] . $compEleSep . $segTer;
68 return trim($ISA['Created']);
71 // GS Segment - EDI-270 format
72 public static function create_GS($row, $X12info, $segTer, $compEleSep)
74 $GS = array();
75 $GS[0] = "GS"; // Functional Group Header Segment ID
76 $GS[1] = "HS"; // Functional ID Code [ HS = Eligibility, Coverage or Benefit Inquiry (270) ]
77 $GS[2] = $X12info['x12_sender_id']; // Application Sender's ID
78 $GS[3] = $X12info['x12_receiver_id']; // Application Receiver's ID
79 $GS[4] = date('Ymd'); // Date [CCYYMMDD]
80 $GS[5] = date('His'); // Time [HHMM] Group Creation Time
81 $GS[6] = "2"; // Group Control Number No zeros for 5010
82 $GS[7] = "X"; // Responsible Agency Code Accredited Standards Committee X12 ]
83 $GS[8] = "005010X279A1"; // Version Release / Industry[ Identifier Code Query 005010X279A1
84 $GS['Created'] = implode('*', $GS); // Data Element Separator
85 $GS['Created'] = $GS ['Created'] . $segTer; // change the information in the tag or change the tag
86 return trim($GS['Created']);
89 // ST Segment - EDI-270 format
90 public static function create_ST($row, $X12info, $segTer, $compEleSep)
92 $ST = array();
93 $ST[0] = "ST"; // Transaction Set Header Segment ID
94 $ST[1] = "270"; // Transaction Set Identifier Code (Inquiry Request)
95 $ST[2] = "000000003"; // Transaction Set Control Number - Must match SE's
96 $ST[3] = "005010X279A1"; // Standard 005010X279A1 in $ST[3]
97 $ST['Created'] = implode('*', $ST); // Data Element Separator
98 $ST['Created'] = $ST ['Created'] . $segTer;
99 return trim($ST['Created']);
102 // BHT Segment - EDI-270 format
103 public static function create_BHT($row, $X12info, $segTer, $compEleSep)
105 $BHT = array();
106 $BHT[0] = "BHT"; // Beginning of Hierarchical Transaction Segment ID
107 $BHT[1] = "0022"; // Subscriber Structure Code
108 $BHT[2] = "13"; // Purpose Code - This is a Request
109 $BHT[3] = "PROVTest600"; // Submitter Transaction Identifier
110 // This information is required by the information Receiver when using Real Time transactions.
111 // For BATCH this can be used for optional information.
112 $BHT[4] = str_pad(date('Ymd'), 8, " "); // Date Transaction Set Created
113 $BHT[5] = str_pad(date('Hi'), 4, " "); // Time Transaction Set Created no space after and 1300 is plenty
114 $BHT['Created'] = implode('*', $BHT); // Data Element Separator
115 $BHT['Created'] = $BHT ['Created'] . $segTer;
116 return trim($BHT['Created']);
119 // HL Segment - EDI-270 format
120 public static function create_HL($row, $nHlCounter, $X12info, $segTer, $compEleSep)
122 $HL = array();
123 $HL[0] = "HL"; // Hierarchical Level Segment ID
124 $HL_LEN[0] = 2;
125 $HL[1] = $nHlCounter; // Hierarchical ID No.
126 if ($nHlCounter == 1) {
127 $HL[2] = "";
128 $HL[3] = 20; // Description: Identifies the payor, maintainer, or source of the information.
129 $HL[4] = 1; // 1 Additional Subordinate HL Data Segment in This Hierarchical Structure.
130 } else if ($nHlCounter == 2) {
131 $HL[2] = 1; // Hierarchical Parent ID Number
132 $HL[3] = 21; // Hierarchical Level Code. '21' Information Receiver
133 $HL[4] = 1; // 1 Additional Subordinate HL Data Segment in This Hierarchical Structure.
134 } else {
135 $HL[2] = 2;
136 $HL[3] = 22; // Hierarchical Level Code.'22' Subscriber
137 $HL[4] = 0; // 0 no Additional Subordinate in the Hierarchical Structure.
139 $HL['Created'] = implode('*', $HL); // Data Element Separator
140 $HL['Created'] = $HL ['Created'] . $segTer;
141 return trim($HL['Created']);
144 // NM1 Segment - EDI-270 format
145 public static function create_NM1($row, $nm1Cast, $X12info, $segTer, $compEleSep)
147 $NM1 = array();
148 $NM1[0] = "NM1"; // Subscriber Name Segment ID
149 if ($nm1Cast == 'PR') {
150 $NM1[1] = "PR"; // Entity ID Code - Payer [PR Payer]
151 $NM1[2] = "2"; // Entity Type - Non-Person
152 $NM1[3] = $row["payer_name"]; // Organizational Name
153 $NM1[4] = ""; // Data Element not required.
154 $NM1[5] = ""; // Data Element not required.
155 $NM1[6] = ""; // Data Element not required.
156 $NM1[7] = ""; // Data Element not required.
157 $NM1[8] = "PI"; // 5010 no longer uses "46"
158 if ($GLOBALS['enable_oa']) {
159 $payerId = $row['eligibility_id'];
160 } else {
161 $payerId = $row['cms_id'];
163 $NM1[9] = $payerId; // Application Sender's ID
164 } else if ($nm1Cast == 'FA') {
165 $NM1[1] = "FA"; // Entity ID Code - Facility [FA Facility]
166 $NM1[2] = "2"; // Entity Type - Non-Person
167 $NM1[3] = $row['facility_name']; // Organizational Name
168 $NM1[4] = ""; // Data Element not required.
169 $NM1[5] = ""; // Data Element not required.
170 $NM1[6] = ""; // Data Element not required.
171 $NM1[7] = ""; // Data Element not required.
172 $NM1[8] = "FI";
173 $NM1[9] = $row['facility_npi'];
174 } else if ($nm1Cast == '1P') {
175 $NM1[1] = "1P"; // Entity ID Code - Provider
176 $NM1[2] = "2"; // Entity Type - Non-Person
177 $NM1[3] = $row['facility_name']; // Organizational Name
178 $NM1[4] = ""; // Data Element not required.
179 $NM1[5] = ""; // Data Element not required.
180 $NM1[6] = ""; // Data Element not required.
181 $NM1[7] = ""; // Data Element not required.
182 $NM1[8] = "XX";
183 $NM1[9] = $row['provider_npi'];
184 } else if ($nm1Cast == 'IL') {
185 $NM1[1] = "IL"; // Insured or Subscriber
186 $NM1[2] = "1"; // Entity Type - Person
187 $NM1[3] = $row['lname']; // last Name
188 $NM1[4] = $row['fname']; // first Name
189 $NM1[5] = $row['mname']; // middle Name
190 $NM1[6] = ""; // data element
191 $NM1[7] = ""; // data element
192 $NM1[8] = "MI"; // Identification Code Qualifier
193 $NM1[9] = $row['policy_number']; // Identification Code
195 $NM1['Created'] = implode('*', $NM1); // Data Element Separator
196 $NM1['Created'] = $NM1['Created'] . $segTer;
197 return trim($NM1['Created']);
200 // REF Segment - EDI-270 format
201 public static function create_REF($row, $ref, $X12info, $segTer, $compEleSep)
203 $REF = array();
204 $REF[0] = "REF"; // Subscriber Additional Identification does not want this for anything
205 if ($ref == '1P') {
206 $REF[1] = "4A"; // Reference Identification Qualifier
207 $REF[2] = $row['provider_pin']; // Provider Pin.
208 } else {
209 $REF[1] = "EJ"; // 'EJ' for Patient Account Number does not want this for patient
210 $REF[2] = $row['pid']; // Patient Account No.
212 $REF['Created'] = implode('*', $REF); // Data Element Separator
213 $REF['Created'] = $REF['Created'] . $segTer;
214 return trim($REF['Created']);
217 // TRN Segment - EDI-270 format
218 function create_TRN($row, $tracno, $refiden, $X12info, $segTer, $compEleSep)
220 $TRN = array();
221 $TRN[0] = "TRN"; // Subscriber Trace Number Segment ID
222 $TRN[1] = "1"; // Trace Type Code � Current Transaction Trace Numbers
223 $TRN[2] = $tracno; // Trace Number
224 $TRN[3] = "9000000000"; // Originating Company ID � must be 10 positions in length
225 $TRN[4] = $refiden; // Additional Entity Identifier (i.e. Subdivision)
226 $TRN['Created'] = implode('*', $TRN); // Data Element Separator
227 $TRN['Created'] = $TRN['Created'] . $segTer;
228 return trim($TRN['Created']);
231 // DMG Segment - EDI-270 format
232 public static function create_DMG($row, $X12info, $segTer, $compEleSep)
234 $DMG = array();
235 $DMG[0] = "DMG"; // Date or Time or Period Segment ID
236 $DMG[1] = "D8"; // Date Format Qualifier - (D8 means CCYYMMDD)
237 $DMG[2] = $row['dob']; // Subscriber's Birth date
238 $DMG[3] = strtoupper($row['sex'][0]);
239 $DMG['Created'] = implode('*', $DMG); // Data Element Separator
240 $DMG['Created'] = $DMG['Created'] . $segTer;
241 return trim($DMG['Created']);
244 // DTP Segment - EDI-270 format
245 public static function create_DTP($row, $qual, $X12info, $segTer, $compEleSep)
247 $DTP = array();
248 $DTP[0] = "DTP"; // Date or Time or Period Segment ID
249 $DTP[1] = $qual; // Qualifier - Date of Service
250 $DTP[2] = "D8"; // Date Format Qualifier - (D8 means CCYYMMDD)
251 if ($qual == '102') {
252 $DTP[3] = $row['date']; // Ins effective Date
253 } else {
254 switch ($X12info['x12_dtp03']) {
255 case 'A':
256 $dtp_date = !empty($row['pc_eventDate']) && $row['pc_eventDate'] > '20010101' ? $row['pc_eventDate'] : date("Ymd");
257 break;
258 case 'E':
259 $dtp_date = !empty($row['date']) && $row['date'] > '20010101' ? $row['date'] : date("Ymd");
260 break;
261 default:
262 $dtp_date = date("Ymd");
264 $DTP[3] = $dtp_date; // Date of Service
266 $DTP['Created'] = implode('*', $DTP); // Data Element Separator
267 $DTP['Created'] = $DTP['Created'] . $segTer;
268 return trim($DTP['Created']);
271 // EQ Segment - EDI-270 format
272 public static function create_EQ($row, $X12info, $segTer, $compEleSep)
274 $EQ = array();
275 $EQ[0] = "EQ"; // Subscriber Eligibility or Benefit Inquiry Information
276 $EQ[1] = "30"; // Service Type Code
277 $EQ['Created'] = implode('*', $EQ); // Data Element Separator
278 $EQ['Created'] = $EQ['Created'] . $segTer;
279 return trim($EQ['Created']);
282 // SE Segment - EDI-270 format
283 public static function create_SE($row, $segmentcount, $X12info, $segTer, $compEleSep)
285 $SE = array();
286 $SE[0] = "SE"; // Transaction Set Trailer Segment ID
287 $SE[1] = $segmentcount; // Segment Count
288 $SE[2] = "000000003"; // Transaction Set Control Number - Must match ST's
289 $SE['Created'] = implode('*', $SE); // Data Element Separator
290 $SE['Created'] = $SE['Created'] . $segTer;
291 return trim($SE['Created']);
294 // GE Segment - EDI-270 format
295 public static function create_GE($row, $X12info, $segTer, $compEleSep)
297 $GE = array();
298 $GE[0] = "GE"; // Functional Group Trailer Segment ID
299 $GE[1] = "1"; // Number of included Transaction Sets
300 $GE[2] = "2"; // Group Control Number
301 $GE['Created'] = implode('*', $GE); // Data Element Separator
302 $GE['Created'] = $GE['Created'] . $segTer;
303 return trim($GE['Created']);
306 // IEA Segment - EDI-270 format
307 public static function create_IEA($row, $X12info, $segTer, $compEleSep)
309 $IEA = array();
310 $IEA[0] = "IEA"; // Interchange Control Trailer Segment ID
311 $IEA[1] = "1"; // Number of included Functional Groups
312 $IEA[2] = "000000001"; // Interchange Control Number
313 $IEA['Created'] = implode('*', $IEA);
314 $IEA['Created'] = $IEA['Created'] . $segTer;
315 return trim($IEA['Created']);
318 public static function translate_relationship($relationship)
320 switch ($relationship) {
321 case "spouse":
322 return "01";
323 break;
324 case "child":
325 return "19";
326 break;
327 case "self":
328 default:
329 return "S";
333 // EDI-270 Batch file Generation
334 public static function print_elig($res, $X12info, $segTer, $compEleSep)
336 $i = 1;
337 $PATEDI = "";
338 // For Header Segment
339 $nHlCounter = 1;
340 $rowCount = 0;
341 $trcNo = 1234501;
342 $refiden = 5432101;
343 foreach ($res as $row) {
344 if ($nHlCounter == 1) {
345 // create ISA
346 $PATEDI = self::create_ISA($row, $X12info, $segTer, $compEleSep);
347 // create GS
348 $PATEDI .= self::create_GS($row, $X12info, $segTer, $compEleSep);
349 // create ST
350 $PATEDI .= self::create_ST($row, $X12info, $segTer, $compEleSep);
351 // create BHT
352 $PATEDI .= self::create_BHT($row, $X12info, $segTer, $compEleSep);
353 // For Payer Segment
354 $PATEDI .= self::create_HL($row, 1, $X12info, $segTer, $compEleSep);
355 $PATEDI .= self::create_NM1($row, 'PR', $X12info, $segTer, $compEleSep);
356 // For Provider Segment
357 $PATEDI .= self::create_HL($row, 2, $X12info, $segTer, $compEleSep);
358 $PATEDI .= self::create_NM1($row, '1P', $X12info, $segTer, $compEleSep); // 5010 no longer uses FA
359 $nHlCounter = $nHlCounter + 2;
360 $segmentcount = 6; // segment counts - start from ST
362 // For Subscriber Segment
363 $PATEDI .= self::create_HL($row, $nHlCounter, $X12info, $segTer, $compEleSep);
364 $PATEDI .= self::create_NM1($row, 'IL', $X12info, $segTer, $compEleSep);
365 // send pid so we get it back in 271
366 $PATEDI .= self::create_REF($row, 'EJ', '', $segTer, '');
367 $PATEDI .= self::create_DMG($row, $X12info, $segTer, $compEleSep);
368 $PATEDI .= self::create_DTP($row, '291', $X12info, $segTer, $compEleSep);
369 $PATEDI .= self::create_EQ($row, $X12info, $segTer, $compEleSep);
370 $segmentcount = $segmentcount + 6;
371 $nHlCounter = $nHlCounter + 1;
372 $rowCount = $rowCount + 1;
373 $trcNo = $trcNo + 1;
374 $refiden = $refiden + 1;
375 if ($rowCount == count($res)) {
376 $segmentcount = $segmentcount + 1;
377 $PATEDI .= self::create_SE($row, $segmentcount, $X12info, $segTer, $compEleSep);
378 $PATEDI .= self::create_GE($row, $X12info, $segTer, $compEleSep);
379 $PATEDI .= self::create_IEA($row, $X12info, $segTer, $compEleSep);
382 echo $PATEDI;
385 public static function requestEligibleTransaction($pid = 0, $eFlag = false)
387 $query = "SELECT
388 d.facility_id,
389 p.lname,
390 p.fname,
391 p.mname,
392 DATE_FORMAT(p.dob, '%Y%m%d') as dob,
393 p.ss,
394 p.sex,
395 p.pid,
396 p.pubpid,
397 p.providerID,
398 i.subscriber_ss,
399 i.policy_number,
400 i.provider as payer_id,
401 i.subscriber_relationship,
402 i.subscriber_lname,
403 i.subscriber_fname,
404 i.subscriber_mname,
405 DATE_FORMAT(i.subscriber_DOB, '%Y%m%d') as subscriber_dob,
406 i.policy_number,
407 i.subscriber_sex,
408 DATE_FORMAT(i.date, '%Y%m%d') as date,
409 d.lname as provider_lname,
410 d.fname as provider_fname,
411 d.npi as provider_npi,
412 d.upin as provider_pin,
413 f.federal_ein as federal_ein,
414 f.facility_npi as facility_npi,
415 f.name as facility_name,
416 c.cms_id as cms_id,
417 c.eligibility_id as eligibility_id,
418 c.x12_default_eligibility_id as partner,
419 c.name as payer_name
420 FROM patient_data AS p
421 LEFT JOIN users AS d on (p.providerID = d.id)
422 LEFT JOIN facility AS f on (f.id = d.facility_id)
423 LEFT JOIN insurance_data AS i ON (i.id =(SELECT id FROM insurance_data AS i WHERE pid = p.pid AND type = 'primary' ORDER BY date DESC LIMIT 1))
424 LEFT JOIN insurance_companies as c ON (c.id = i.provider)
425 WHERE p.pid = ?";
426 $res = sqlStatement($query, array($pid));
428 $details = self::requestRealTimeEligible($res, '', "~", ':', true);
429 $isError = strpos($details, "Error:");
430 $isError = $isError !== false ? $isError : strpos($details, "AAA");
431 if ($isError !== false) {
432 $details = substr($details, $isError);
433 return "<div>" . nl2br(text($details)) . "</div>";
436 return true;
439 // EDI-270 RealTime Request & Response
440 // RealTime requires one transaction per request.
442 public static function requestRealTimeEligible($res, $X12info, $segTer, $compEleSep, $eFlag = false)
444 $rowCount = 0;
445 $totalCount = count($res);
446 $down_accum = $log = $error_accum = '';
447 foreach ($res as $row) {
448 if (!$X12info) {
449 $X12info = self::getX12Partner($row['partner']);
451 if ($row['providerID'] === 0 || !$row['provider_npi']) {
452 $error_accum .= xlt("Error") . ": " . xlt("Provider Missing Add one in Choices") . "\n";
454 if (!$row['eligibility_id']) {
455 $error_accum .= xlt("Error") . ": " . xlt("Missing Insurance Payer Id") . "\n";
457 if (!$row['policy_number'] || !$row['subscriber_dob']) {
458 $error_accum .= xlt("Error") . ": " . xlt("Missing Subscriber Policy Number or DOB") . "\n";
460 if (!empty($error_accum)) {
461 return $error_accum;
463 // create ISA
464 $PATEDI = self::create_ISA($row, $X12info, $segTer, $compEleSep);
465 // create GS
466 $PATEDI .= self::create_GS($row, $X12info, $segTer, $compEleSep);
467 // create ST
468 $PATEDI .= self::create_ST($row, $X12info, $segTer, $compEleSep);
469 // create BHT
470 $PATEDI .= self::create_BHT($row, $X12info, $segTer, $compEleSep);
471 // For Payer Segment
472 $PATEDI .= self::create_HL($row, 1, $X12info, $segTer, $compEleSep);
473 $PATEDI .= self::create_NM1($row, 'PR', $X12info, $segTer, $compEleSep);
474 // For Provider Segment
475 $PATEDI .= self::create_HL($row, 2, $X12info, $segTer, $compEleSep);
476 // unsure but 'FA' may have to be an option vs '1P'
477 $PATEDI .= self::create_NM1($row, '1P', $X12info, $segTer, $compEleSep);
478 // For Subscriber Segment
479 $PATEDI .= self::create_HL($row, 3, $X12info, $segTer, $compEleSep);
480 $PATEDI .= self::create_NM1($row, 'IL', $X12info, $segTer, $compEleSep);
481 // send pid so we get it back in 271
482 $PATEDI .= self::create_REF($row, 'EJ', '', $segTer, '');
483 $PATEDI .= self::create_DMG($row, $X12info, $segTer, $compEleSep);
484 // 2110
485 $PATEDI .= self::create_DTP($row, '291', $X12info, $segTer, $compEleSep);
486 $PATEDI .= self::create_EQ($row, $X12info, $segTer, $compEleSep);
487 // the end
488 $PATEDI .= self::create_SE($row, 13, $X12info, $segTer, $compEleSep);
489 $PATEDI .= self::create_GE($row, $X12info, $segTer, $compEleSep);
490 $PATEDI .= self::create_IEA($row, $X12info, $segTer, $compEleSep);
491 // make request
492 $result = self::requestEligibility($X12info['id'], $PATEDI);
493 $rowCount++;
494 $e = strpos($result, "Error:");
495 if ($e !== false) {
496 $error_accum = $result;
497 } else {
498 $down_accum .= $result . "\n"; // delimit for next new request
501 $log .= "*** 270 " . xlt("Request Message") . " $rowCount of $totalCount\n" . $PATEDI . "\n" . $error_accum . "\n"; // keep a log.
502 $error_accum = '';
504 // parse the 271 responses from 270 requests sent.
505 $process = self::parseEdi271($down_accum);
506 $log = xlt("List of ") . $rowCount . " " . xlt("Requests Sent") . ":\n" . $log . "\n" . $process;
507 if ($eFlag) {
508 return $log;
511 return $rowCount;
514 // Report Generation
516 public static function show_elig($res, $X12info, $segTer, $compEleSep)
519 $i = 0;
520 echo " <div id='report_results'>
521 <table class='table table-striped table-hover'>
522 <thead>
523 <th>" . text(xl('Facility Name')) . "</th>
524 <th>" . text(xl('Facility NPI')) . "</th>
525 <th>" . text(xl('Insurance Comp')) . "</th>
526 <th>" . text(xl('Appt Date')) . "</th>
527 <th>" . text(xl('Policy No')) . "</th>
528 <th>" . text(xl('Patient Name')) . "</th>
529 <th>" . text(xl('DOB')) . "</th>
530 <th>" . text(xl('Gender')) . "</th>
531 <th>" . text(xl('SSN')) . "</th>
532 <th> &nbsp; </th>
533 </thead>
534 <tbody>";
536 foreach ($res as $row) {
537 $i = $i + 1;
538 // what the heck is below for... looks abandoned.
539 $elig = array();
540 $elig[0] = $row['facility_name']; // Inquiring Provider Name calendadr
541 $elig[1] = $row['facility_npi']; // Inquiring Provider NPI
542 $elig[2] = $row['payer_name']; // Payer Name our insurance co name
543 $elig[3] = $row['policy_number']; // Subscriber ID
544 $elig[4] = $row['subscriber_lname']; // Subscriber Last Name
545 $elig[5] = $row['subscriber_fname']; // Subscriber First Name
546 $elig[6] = $row['subscriber_mname']; // Subscriber Middle Initial
547 $elig[7] = $row['subscriber_dob']; // Subscriber Date of Birth
548 $elig[8] = substr($row['subscriber_sex'], 0, 1); // Subscriber Sex
549 $elig[9] = $row['subscriber_ss']; // Subscriber SSN
550 $elig[10] = self::translate_relationship($row['subscriber_relationship']); // Pt Relationship to insured
551 $elig[11] = $row['lname']; // Dependent Last Name
552 $elig[12] = $row['fname']; // Dependent First Name
553 $elig[13] = $row['mname']; // Dependent Middle Initial
554 $elig[14] = $row['dob']; // Dependent Date of Birth
555 $elig[15] = substr($row['sex'], 0, 1); // Dependent Sex
556 $elig[16] = $row['pc_eventDate']; // Date of service
557 $elig[17] = "30"; // Service Type
558 $elig[18] = $row['pubpid']; // Patient Account Number pubpid
560 echo " <tr id='PR" . $i . "_" . text($row['policy_number']) . "'>
561 <td class ='detail'>" . text($row['facility_name']) . "</td>
562 <td class ='detail'>" . text($row['facility_npi']) . "</td>
563 <td class ='detail'>" . text($row['payer_name']) . "</td>
564 <td class ='detail'>" . text(date("m/d/Y", strtotime($row['pc_eventDate']))) . "</td>
565 <td class ='detail'>" . text($row['policy_number']) . "</td>
566 <td class ='detail'>" . text($row['subscriber_lname'] . " " . $row['subscriber_fname']) . "</td>
567 <td class ='detail'>" . text($row['subscriber_dob']) . "</td>
568 <td class ='detail'>" . text($row['subscriber_sex']) . "</td>
569 <td class ='detail'>" . text($row['subscriber_ss']) . "</td>
570 <td class ='detail'>
571 <img src=\"" . $GLOBALS['images_static_relative'] . "/deleteBtn.png\" title=" . text(xl('Delete Row')) . " style='cursor:pointer;cursor:hand;' onclick='deletetherow(\"" . $i . "_" . text($row['policy_number']) . "\")'>
572 </td>
573 </tr>
575 unset($elig); // see ..
578 if ($i == 0) {
579 echo " <tr>
580 <td class='norecord' colspan=9>
581 <div style='padding:5px;font-family:arial;font-size:13px;text-align:center;'>" . text(xl('No records found')) . "</div>
582 </td>
583 </tr> ";
585 echo " </tbody>
586 </table>";
589 // To Show Eligibility Verification data
590 public static function show_eligibility_information($pid, $flag = false)
592 $query =
593 "SELECT eligr.*, eligv.insurance_id, eligv.copay, insd.pid, insc.name, " .
594 "Date_Format(eligv.eligibility_check_date, '%W %M %e, %Y %h:%i %p') AS verificationDate " .
595 "FROM eligibility_verification eligv " .
596 "INNER JOIN benefit_eligibility eligr ON eligr.verification_id = eligv.verification_id " .
597 "INNER JOIN insurance_data insd ON insd.id = eligv.insurance_id " .
598 "INNER JOIN insurance_companies insc ON insc.id = insd.provider " .
599 "WHERE insd.pid = ? AND eligv.eligibility_check_date = " .
600 "(SELECT Max(eligibility_verification.eligibility_check_date) FROM eligibility_verification " .
601 "WHERE eligibility_verification.insurance_id = eligv.insurance_id)";
602 $result = sqlStatement($query, array($pid));
604 $showString = "<div class='row'>";
605 $col = 1;
606 $title = 1;
607 while ($benefit = sqlFetchArray($result)) {
608 if ($title) {
609 $title = 0;
610 $showString .= "<div class='col col-sm-12'>\n";
611 $showString .= "<b>" . xlt('Insurance Provider') . ":</b> " . (!empty($benefit['name']) ? text($benefit['name']) : xlt('n/a')) . "<br/>\n";
612 $showString .= "<b>" . xlt('Verified On') . ":</b> " . text($benefit['verificationDate']) . "<br/><br/>\n";
613 $showString .= "</div><br/>\n";
615 $benefit['start_date'] = strpos($benefit['start_date'], "0000") === false ? $benefit['start_date'] : '';
616 $benefit['end_date'] = strpos($benefit['end_date'], "0000") === false ? $benefit['end_date'] : '';
617 $color = "";
618 switch ($benefit['type']) {
619 case '1':
620 $color = "darkred";
621 break;
622 case 'A':
623 $color = "blue";
624 break;
625 case 'B':
626 $color = "red";
627 break;
628 case 'C':
629 $color = "green";
630 break;
631 case 'F':
632 $color = "darkgreen";
633 break;
635 $showString .= "\n<div class='col col-sm-6' >\n";
636 $showString .= !empty($benefit['benefit_type']) ? "<b style='color: $color'>" . xlt('Benefit Type') . ": " . text($benefit['benefit_type']) . "</b><br />\n" : '';
637 $showString .= !empty($benefit['start_date']) ? "<b>" . xlt('Start Date') . ":</b> " . text(date("m/d/Y", strtotime($benefit['start_date']))) . "<br />\n" : '';
638 $showString .= !empty($benefit['end_date']) ? "<b>" . xlt('End Date') . ":</b> " . text(date("m/d/Y", strtotime($benefit['end_date']))) . "<br />\n" : '';
639 $showString .= !empty($benefit['coverage_level']) ? "<b>" . xlt('Coverage Level') . ":</b> " . text($benefit['coverage_level']) . "<br />\n" : '';
640 $showString .= !empty($benefit['coverage_type']) ? "<b>" . xlt('Coverage Type') . ":</b> " . text($benefit['coverage_type']) . "<br />\n" : '';
641 $showString .= !empty($benefit['plan_type']) ? "<b>" . xlt('Plan Type') . ":</b> " . text($benefit['plan_type']) . "<br />\n" : '';
642 $showString .= !empty($benefit['plan_desc']) ? "<b>" . xlt('Plan Description') . ":</b> " . text(text($benefit['plan_desc'])) . "<br />\n" : '';
643 $showString .= !empty($benefit['coverage_period']) ? "<b>" . xlt('Coverage Period') . ":</b> " . text($benefit['coverage_period']) . "<br />\n" : '';
644 $showString .= !empty($benefit['amount']) ? "<b>" . xlt('Amount') . ":</b> " . text($benefit['amount']) . "<br />\n" : '';
645 $showString .= !empty($benefit['percent']) ? "<b>" . xlt('Percentage') . ":</b> " . text($benefit['percent']) . "<br />\n" : '';
646 $showString .= !empty($benefit['network_ind']) ? "<b>" . xlt('Network Indicator') . ":</b> " . text($benefit['network_ind']) . "<br />\n" : '';
647 $showString .= !empty($benefit['message']) ? "<b>" . xlt('Message') . ":</b> " . text($benefit['message']) . "<br />\n" : '';
648 $showString .= "</div>";
650 if ($col === 2) {
651 $showString .= "</div>\n<br/><div class='row'>\n";
652 $col = 0;
654 $col++;
656 if ($col === 2) {
657 $showString .= "</div>";
659 if ($title === 1) {
660 $showString = "<br><span><b>" . xlt("Nothing To Report") . "</b></span><br>";
662 $showString .= "</div>\n";
663 echo $showString;
666 // For EDI 271
667 // Function to save the values in eligibility_verification table
668 public static function eligibility_verification_save($subscriber = [])
670 $verification_id = 0;
671 $insurance_id = 0;
672 $partner_id = $subscriber['isa_sender_id'];
673 $patient_id = $subscriber['pid'];
675 $query = "SELECT id, copay FROM insurance_data WHERE type = 'primary' and pid = ?";
676 $insId = sqlQuery($query, array($patient_id));
677 if ($insId !== false) {
678 $insurance_id = $insId['id'];
679 $copay = $insId['copay'];
682 $query = "SELECT verification_id FROM eligibility_verification WHERE insurance_id = ?";
683 $resId = sqlQuery($query, array($insurance_id));
684 if ($resId !== false) {
685 $verification_id = $resId['verification_id'];
688 if (!empty($insurance_id)) {
689 $sqlBindArray = array();
690 $query = "REPLACE INTO eligibility_verification SET verification_id = ?, insurance_id = ?, response_id = ?, eligibility_check_date = now(), create_date = now()";
691 array_push($sqlBindArray, $verification_id, $insurance_id, $partner_id);
693 $res = sqlInsert($query, $sqlBindArray);
694 if (!$verification_id) {
695 $verification_id = $res;
699 $query = "DELETE FROM `benefit_eligibility` WHERE `benefit_eligibility`.`verification_id` = ?";
700 $res = sqlStatement($query, array($verification_id));
702 foreach ($subscriber['benefits'] as $benefit) {
703 $bind = array(
704 $verification_id,
705 "A",
706 date('Y/m/d H:i'),
707 date('Y/m/d H:i'),
708 $benefit['type'],
709 $benefit['benefit_type'],
710 $benefit['start_date'],
711 $benefit['end_date'],
712 $benefit['coverage_level'],
713 $benefit['coverage_type'],
714 $benefit['plan_type'],
715 $benefit['plan_desc'],
716 $benefit['coverage_period'],
717 $benefit['amount'],
718 $benefit['percent'],
719 $benefit['network_ind'],
720 $benefit['message']
723 $query = "INSERT INTO `benefit_eligibility` " .
724 "(`verification_id`, `response_status`, `response_create_date`, `response_modify_date`, `type`, `benefit_type`, `start_date`, " .
725 "`end_date`, `coverage_level`, `coverage_type`, `plan_type`, `plan_description`, `coverage_period`, `amount`, `percent`, `network_ind`, `message`) " .
726 "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
727 $res = sqlStatement($query, $bind);
731 // return array of X12 partners
732 // if id return just that id
733 public static function getX12Partner($id = 0)
735 // @TODO move to class
736 global $X12info;
737 $id = (int)$id;
738 $returnval = [];
740 if ((int)$id > 0) {
741 $returnval = sqlQuery("select * from x12_partners WHERE id = ?", array($id));
742 $X12info = $returnval;
743 } else {
744 $rez = sqlStatement("select * from x12_partners");
745 for ($iter = 0; $row = sqlFetchArray($rez); $iter++) {
746 $returnval[$iter] = $row;
750 return $returnval;
753 // return array of provider usernames
754 public static function getUsernames()
756 $rez = sqlStatement("select distinct username, lname, fname,id from users " .
757 "where authorized = 1 and username != ''");
758 for ($iter = 0; $row = sqlFetchArray($rez); $iter++) {
759 $returnval[$iter] = $row;
762 return $returnval;
765 // return formated array
767 public static function arrFormated(&$item, $key)
769 $item = strstr($item, '_');
770 $item = substr($item, 1, strlen($item) - 1);
771 $item = "'" . $item;
774 public static function requestEligibility($partner = '', $x12_270 = '')
776 global $X12info;
777 if (((int)$X12info['id'] !== (int)$partner) && (int)$partner > 0) {
778 $X12info = self::getX12Partner($partner);
781 $payloadId = "3b8c13f5-11e2-43bf-bc47-737cca04f3fe"; // a default fallback
782 if (function_exists('openssl_random_pseudo_bytes') === true) {
783 $data = openssl_random_pseudo_bytes(16);
784 $data[6] = chr(ord($data[6]) & 0x0f | 0x40);
785 $data[8] = chr(ord($data[8]) & 0x3f | 0x80);
786 $payloadId = vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
789 $boundary = RandomGenUtils::createUniqueToken(12);
790 $rt_passwrd = $X12info['x12_isa04'];
791 $rt_user = $X12info['x12_isa02'];
792 $sender_id = $X12info['x12_sender_id'];
793 $receiver_id = $X12info['x12_receiver_id'];
794 $now_date = date("Y-m-d\TH:i:s\Z");
795 $headers = array(
796 'Content-Type' => "multipart/form-data; boundary=$boundary",
797 'Host' => ' wsd.officeally.com'
800 // IMPORTANT: Do not change the format of $mime_body below.
801 // HTTP MIME Multipart is non-normative. LFs matter...
803 $mime_body = <<<MIMEBODY
804 --$boundary
805 Content-Disposition: form-data; name="ProcessingMode"
807 RealTime
808 --$boundary
809 Content-Disposition: form-data; name="TimeStamp"
811 $now_date
812 --$boundary
813 Content-Disposition: form-data; name="PayloadID"
815 $payloadId
816 --$boundary
817 Content-Disposition: form-data; name="CORERuleVersion"
819 2.2.0
820 --$boundary
821 Content-Disposition: form-data; name="ReceiverID"
823 $receiver_id
824 --$boundary
825 Content-Disposition: form-data; name="SenderID"
827 $sender_id
828 --$boundary
829 Content-Disposition: form-data; name="PayloadType"
831 X12_270_Request_005010X279A1
832 --$boundary
833 Content-Disposition: form-data; name="UserName"
835 $rt_user
836 --$boundary
837 Content-Disposition: form-data; name="Password"
839 $rt_passwrd
840 --$boundary
841 Content-Disposition: form-data; name="Payload"
843 $x12_270
844 --$boundary--
845 MIMEBODY;
846 // send the request
847 $response = oeHttp::bodyFormat('body')
848 //->setDebug('5000')/* @todo uncomment and set proxy port to debug eg Fiddler */
849 ->usingHeaders($headers)
850 ->post('https://wsd.officeally.com/TransactionSite/rtx.aspx', $mime_body); // @TODO put request urls in x12 partner's for versatility.
852 $formBody = $response->body();
853 $contentType = $response->header('Content-Type')[0];
854 $hContentLength = (int)$response->header('Content-Length')[0];
855 $cksum = ($hContentLength - strlen($formBody)) === 0 ? true : false; // validate content size
856 $formData = self::mimeParse($formBody, $contentType);
858 $errors = '';
859 if (!$cksum) {
860 $errors .= "Error:" . xlt("Request Content Fails Integrity Test");
862 if ($response->status() !== 200) {
863 $errors .= "\nError:" . xlt("Http Error") . ": " . $response->getReasonPhrase() . " : " . $response->status();
865 if ($formData['ErrorCode'] != "Success") {
866 $errors .= "\nError:" . $formData['ErrorCode'] . "\n" . $formData['ErrorMessage'];
868 if ($errors) {
869 $errors .= $formData['Payload'] ? "\nError:" . $formData['Payload'] : '';
870 return $errors;
873 $x12_271 = $formData['Payload'];
875 return $x12_271;
878 public static function mimeParse($formBody = '', $contentType)
880 $mimeBody = preg_replace('~\r\n?~', "\r", $formBody);
881 list($contentType, $bound, $cs) = explode(";", trim($contentType)); // $contentType & $cs are throwaways
882 $bound = explode("=", trim($bound, ' '))[1];
883 $mimeFields = preg_split("/-+$bound/", $mimeBody);
884 array_pop($mimeFields);
885 $hold = $isMatches = [];
886 foreach ($mimeFields as $id => $field) {
887 if (empty($field)) {
888 continue;
890 preg_match('/name=\"([^\"]*)\"[\n|\r]+([^\n\r].*)?\r$/s', $field, $isMatches);
891 if (preg_match('/^(.*)\[\]$/i', $isMatches[1], $hold)) {
892 $mimeData[$hold[1]][] = $isMatches[2];
893 } else {
894 $mimeData[$isMatches[1]] = $isMatches[2];
897 return $mimeData;
900 public static function getPatientMatch($fn, $ln, $sex, $dob)
902 $fn = "%" . $fn . "%";
903 $ln = "%" . $ln . "%";
904 $sex = "%" . $sex . "%";
905 $dob = date("Y-m-d", strtotime($dob));
906 $sql = "SELECT pid FROM patient_data WHERE fname LIKE ? && lname LIKE ? && sex LIKE ? && DOB LIKE ?";
907 $rtn = sqlQuery($sql, array($fn, $ln, $sex, $dob));
909 return $rtn['pid'] ? $rtn['pid'] : 0;
912 public static function parseEdi271($content)
915 $codes = new edih_271_codes('*', '^');
916 $target = $GLOBALS['edi_271_file_path'];
917 $log = "";
918 // not sure if want to save yet
919 $target = $target . time();
921 $responses = explode("\n", $content);
922 if (empty($responses)) {
923 $responses = $content;
926 // Loop through each 271. '\n' delims records in batch.
927 foreach ($responses as $new) {
928 if (empty($new)) {
929 continue;
931 $AAA = array();
932 $subscribers = array();
933 $benefits = array();
934 $in = array();
935 $in['pid'] = 0;
936 $loop = array();
937 $loop['id'] = 0;
938 $loop['parent'] = 0;
939 $loop['error'] = 1;
940 $trace = -1;
942 $segments = explode("~", $new);
944 if (count($segments) < 6) {
945 if (file_exists($target)) {
946 unlink($target);
948 continue;
951 foreach ($segments as $segment) {
952 $elements = explode("*", $segment);
953 $ecnt = count($elements);
954 // sanitize
955 for ($i = 0; $i < $ecnt; $i++) {
956 $elements[$i] = text(trim($elements[$i]));
958 // Switch Case for Segment
959 switch ($elements[0]) {
960 case 'ISA':
961 $loop[1] = $elements[2];
962 $in['isa_sender_id'] = $elements[6];
963 $in['isa_receiver_id'] = $elements[8];
964 $in['isa_control_number'] = $elements[13];
965 break;
967 case 'HL':
968 $loop['id'] = (int)$elements[1];
969 $loop['parent'] = (int)$elements[2];
970 $loop['error'] = (int)$elements[4];
971 break;
973 case 'NM1':
974 if ($loop['id'] === 1) {//"PR" payer
975 $in['payer_org'] = $elements[3];
976 $in['payer_member_id'] = $elements[9];
977 } elseif ($loop['id'] === 2) { //"1P" or "FA"
978 $in['provider_org'] = $elements[3];
979 $in['provider_member_id'] = $elements[9];
980 } elseif ($elements[1] == "IL" || $loop['context'] == "TRN") { //"IL"
981 $in['trace'] = $trace;
982 $in['subscriber_lname'] = $elements[3];
983 $in['subscriber_fname'] = $elements[4];
984 $in['subscriber_mname'] = $elements[5];
985 $in['subscriber_member_id'] = $elements[9];
986 $in['verify_date'] = date('Y/m/d H:i:s');
988 $loop['context'] = $elements[0];
989 break;
991 case 'DMG':
992 if ($elements[1] == "D8") {
993 $in['subscriber_dob'] = $elements[2];
995 $in['subscriber_sex'] = $elements[3];
996 $loop['context'] = $elements[0];
997 // 2100A-C should be done so get our patient id.
998 if (!(int)$in['pid']) {
999 $in['pid'] = (int)self::getPatientMatch(
1000 $in['subscriber_fname'],
1001 $in['subscriber_lname'],
1002 $in['subscriber_sex'],
1003 $in['subscriber_dob']
1006 break;
1008 case 'TRN':
1009 if ($trace === -1) {
1010 $trace++;
1011 break; // subscriber not set yet
1013 $trace++;
1014 if ($in['pid']) {
1015 $in['benefits'] = $benefits ? $benefits : [];
1016 array_push($subscribers, $in);
1017 $loop['context'] = $elements[0];
1018 $benefits = [];
1020 break;
1022 case 'REF':
1023 if ($elements[1] == "EJ") {
1024 $in['pid'] = (int)$elements[2];
1025 if (!$in['pid']) {
1026 $in['pid'] = (int)self::getPatientMatch(
1027 $in['subscriber_fname'],
1028 $in['subscriber_lname'],
1029 $in['subscriber_sex'],
1030 $in['subscriber_dob']
1034 break;
1036 case 'DTP':
1037 if ($elements[2] == "D8") {
1038 $loop['start_date'] = $elements[3] ? date("Y-m-d", strtotime($elements[3])) : '';
1039 $loop['end_date'] = '';
1040 } elseif ($elements[2] == "RD8") {
1041 $tmp = explode('-', $elements[3]);
1042 $loop['start_date'] = $tmp[0] ? date("Y-m-d", strtotime($tmp[0])) : '';
1043 $loop['end_date'] = !empty($tmp[1]) ? date("Y-m-d", strtotime($tmp[1])) : '';
1045 if ($loop['context'] == "EB") {
1046 $bcnt = count($benefits) - 1;
1047 $benefits[$bcnt]['start_date'] = $loop['start_date'];
1048 $benefits[$bcnt]['end_date'] = $loop['end_date'];
1050 break;
1052 case 'EB':
1053 $eb = array(
1054 'type' => $elements[1],
1055 'benefit_type' => $codes->get_271_code("EB01", $elements[1]) ? $codes->get_271_code("EB01", $elements[1]) : $elements[1],
1056 'start_date' => '',
1057 'end_date' => '',
1058 'coverage_level' => $elements[2] ? $codes->get_271_code("EB02", $elements[2]) : $elements[2],
1059 'coverage_type' => $elements[3] ? $codes->get_271_code("EB03", $elements[3]) : $elements[3],
1060 'plan_type' => $elements[4] ? $codes->get_271_code("EB04", $elements[4]) : $elements[4],
1061 'plan_description' => $elements[5],
1062 'coverage_period' => $elements[6] ? $codes->get_271_code("EB06", $elements[6]) : $elements[6],
1063 'amount' => $elements[7] ? number_format($elements[7], 2, '.', '') : '',
1064 'percent' => $elements[8],
1065 'network_ind' => $elements[12] ? $codes->get_271_code("EB12", $elements[12]) : $elements[12],
1066 'message' => '' // any MSG segments that may be assoc with this EB.
1068 $loop['context'] = "EB";
1069 array_push($benefits, $eb);
1070 break;
1072 case 'AAA':
1073 $error = array(
1074 'request_ind' => $elements[1],
1075 'reason_code' => $elements[3] . " : " . $codes->get_271_code("AAA03", $elements[3]),
1076 'follow_up' => $elements[4] . " : " . $codes->get_271_code("AAA04", $elements[4])
1078 array_push($AAA, $error);
1079 break;
1081 case 'MSG':
1082 $bcnt = count($benefits) - 1;
1083 if ($bcnt > -1) {
1084 $benefits[$bcnt]['message'] = $benefits[$bcnt]['message'] ? $benefits[$bcnt]['message'] . ":" : '';
1085 $benefits[$bcnt]['message'] .= $elements[1];
1087 break;
1089 case 'SE':
1090 $in['benefits'] = $benefits ? $benefits : [];
1091 if ($in['pid']) {
1092 array_push($subscribers, $in);
1094 $loop['context'] = $elements[0];
1095 $benefits = [];
1096 break;
1098 case 'IEA':
1099 // save
1100 $elog = '';
1101 if (count($subscribers) < 1) {
1102 $elog = xlt("Error") . ": " . xlt("Unknown Transaction Error Maybe Subscriber Effective or DOB Dates");
1104 foreach ($subscribers as $subscriber) {
1105 self::eligibility_verification_save($subscriber);
1107 break;
1110 // some debug logging
1111 if (!$GLOBALS['disable_eligibility_log']) {
1112 $log .= "*------------------- " . xlt("271 Returned") . " --------------------*\n" . $new . "\n" . (isset($AAA[0]) ? (xlt("AAA Segments") . ":\n" . print_r($AAA, true)) : "\n") . $elog;
1113 $log .= self::makeEligibilityReport($subscribers);
1118 return $log;
1121 public static function makeEligibilityReport($subscribers = [])
1123 $binfo = '';
1124 foreach ($subscribers as $subscriber) {
1125 $binfo .=
1126 xlt("Subscriber Member") . ": " . $subscriber['subscriber_fname'] . " " . $subscriber['subscriber_lname'] . " " . $subscriber['subscriber_mname'] .
1127 " " . xlt("Member Id") . ": " . $subscriber['subscriber_member_id'] . " ---*\n";
1128 $cnt = count($subscriber['benefits']);
1129 if ($cnt < 1) {
1130 $binfo .= "*** " . xlt("Nothing returned to report") . " ***\n";
1132 foreach ($subscriber['benefits'] as $key => $benefits) {
1133 foreach ($benefits as $key => $benefit) {
1134 if ($key == 'type') {
1135 $binfo .= "\n";
1137 if (empty($benefit) || $key == 'type') {
1138 continue;
1140 $binfo .= "\t" . ucwords(str_replace('_', ' ', $key)) . ": " . $benefit . "\n";
1145 return $binfo;