minor fixes to prior commits
[openemr.git] / library / edi.inc
blobe787c29e918b735f553b9f5fc15b861eb4125e87
1 <?php
2 /**
3  * Inc file for the 270 / 271 creation and uploading
4  *
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
7  *
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
20  */
21 require_once("$srcdir/edihistory/codes/edih_271_code_class.php");
23 use OpenEMR\Common\Http\oeHttp;
24 use OpenEMR\Common\Utils\RandomGenUtils;
26 // @TODO global to become private var when this goes to a class.
28 global $X12info;
30 // SEGMENT FUNCTION START
32 // ISA Segment  - EDI-270 format
34 function create_ISA($row, $X12info, $segTer, $compEleSep)
36     $ISA     =  array();
37     $ISA[0] = "ISA"; // Interchange Control Header Segment ID
38     $ISA[1] = "00";  // Author Info Qualifier
39     $ISA[2] = str_pad("0000000", 10, " ");        // Author Information
40     $ISA[3] = "00"; //   Security Information Qualifier
41                     //   MEDI-CAL NOTE: For Leased-Line & Dial-Up use '01',
42                     //   for BATCH use '00'.
43                     //   '00' No Security Information Present
44                     //   (No Meaningful Information in I04)
45     $ISA[4] = str_pad("0000000000", 10, " ");         // Security Information
46     $ISA[5] = str_pad($X12info['x12_isa05'], 2, " ");              // Interchange ID Qualifier
47     $ISA[6] = str_pad($X12info['x12_sender_id'], 15, " ");      // INTERCHANGE SENDER ID
48     $ISA[7] = str_pad($X12info['x12_isa07'], 2, " ");              // Interchange ID Qualifier
49     $ISA[8] = str_pad($X12info['x12_receiver_id'], 15, " ");      // INTERCHANGE RECEIVER ID
50     $ISA[9] = str_pad(date('ymd'), 6, " ");       // Interchange Date (YYMMDD)
51     $ISA[10] = str_pad(date('Hi'), 4, " ");       // Interchange Time (HHMM)
52     $ISA[11] = "^";                                 // Interchange Control Standards Identifier
53     $ISA[12] = str_pad("00501", 5, " ");          // Interchange Control Version Number
54     $ISA[13] = str_pad("000000001", 9, " ");      // INTERCHANGE CONTROL NUMBER
55     $ISA[14] = str_pad($X12info['x12_isa14'], 1, " ");              // Acknowledgment Request [0= not requested, 1= requested]
56     $ISA[15] =  str_pad($X12info['x12_isa15'], 1, " ");                 // Usage Indicator [ P = Production Data, T = Test Data ]
57     $ISA['Created'] = implode('*', $ISA);       // Data Element Separator
58     $ISA['Created'] = $ISA['Created'] ."*";
59     $ISA['Created'] = $ISA ['Created'] . $compEleSep . $segTer;
61     return trim($ISA['Created']);
63 // GS Segment  - EDI-270 format
64 function create_GS($row, $X12info, $segTer, $compEleSep)
66     $GS    = array();
67     $GS[0] = "GS";                      // Functional Group Header Segment ID
68     $GS[1] = "HS";                      // Functional ID Code [ HS = Eligibility, Coverage or Benefit Inquiry (270) ]
69     $GS[2] =  $X12info['x12_sender_id'];              // Application Sender's ID
70     $GS[3] =  $X12info['x12_receiver_id'];              // Application Receiver's ID
71     $GS[4] = date('Ymd');               // Date [CCYYMMDD]
72     $GS[5] = date('His');               // Time [HHMM] Group Creation Time
73     $GS[6] = "2";                       // Group Control Number No zeros for 5010
74     $GS[7] = "X";                   // Responsible Agency Code Accredited Standards Committee X12 ]
75     $GS[8] = "005010X279A1";            // Version Release / Industry[ Identifier Code Query 005010X279A1
76     $GS['Created'] = implode('*', $GS);         // Data Element Separator
77     $GS['Created'] = $GS ['Created'] . $segTer;  // change the information in the tag or change the tag
78     return trim($GS['Created']);
80 // ST Segment  - EDI-270 format
81 function create_ST($row, $X12info, $segTer, $compEleSep)
83     $ST    =    array();
84     $ST[0] = "ST";                              // Transaction Set Header Segment ID
85     $ST[1] = "270";                                 // Transaction Set Identifier Code (Inquiry Request)
86     $ST[2] = "000000003";                       // Transaction Set Control Number - Must match SE's
87     $ST[3] = "005010X279A1";                    // Standard 005010X279A1 in $ST[3]
88     $ST['Created'] = implode('*', $ST);             // Data Element Separator
89     $ST['Created'] = $ST ['Created'] . $segTer;
90     return trim($ST['Created']);
92 // BHT Segment  - EDI-270 format
93 function create_BHT($row, $X12info, $segTer, $compEleSep)
95     $BHT    =   array();
96     $BHT[0] = "BHT";                        // Beginning of Hierarchical Transaction Segment ID
97     $BHT[1] = "0022";                       // Subscriber Structure Code
98     $BHT[2] = "13";                         // Purpose Code - This is a Request
99     $BHT[3] = "PROVTest600";                //  Submitter Transaction Identifier
100     // This information is required by the information Receiver when using Real Time transactions.
101     // For BATCH this can be used for optional information.
102     $BHT[4] = str_pad(date('Ymd'), 8, " ");           // Date Transaction Set Created
103     $BHT[5] = str_pad(date('Hi'), 4, " ");            // Time Transaction Set Created no space after and 1300 is plenty
104     $BHT['Created'] = implode('*', $BHT);           // Data Element Separator
105     $BHT['Created'] = $BHT ['Created'] . $segTer;
106     return trim($BHT['Created']);
108 // HL Segment  - EDI-270 format
109 function create_HL($row, $nHlCounter, $X12info, $segTer, $compEleSep)
111     $HL         = array();
112     $HL[0]      = "HL";             // Hierarchical Level Segment ID
113     $HL_LEN[0]  =  2;
114     $HL[1] = $nHlCounter;       // Hierarchical ID No.
115     if ($nHlCounter == 1) {
116         $HL[2] = "";
117         $HL[3] = 20;            // Description: Identifies the payor, maintainer, or source of the information.
118         $HL[4] = 1;                 // 1 Additional Subordinate HL Data Segment in This Hierarchical Structure.
119     } else if ($nHlCounter == 2) {
120         $HL[2] = 1;                 // Hierarchical Parent ID Number
121         $HL[3] = 21;            // Hierarchical Level Code. '21' Information Receiver
122         $HL[4] = 1;                 // 1 Additional Subordinate HL Data Segment in This Hierarchical Structure.
123     } else {
124         $HL[2] = 2;
125         $HL[3] = 22;            // Hierarchical Level Code.'22' Subscriber
126         $HL[4] = 0;                 // 0 no Additional Subordinate in the Hierarchical Structure.
127     }
128     $HL['Created'] = implode('*', $HL);         // Data Element Separator
129     $HL['Created'] = $HL ['Created'] . $segTer;
130     return trim($HL['Created']);
132 // NM1 Segment  - EDI-270 format
133 function create_NM1($row, $nm1Cast, $X12info, $segTer, $compEleSep)
135     $NM1 = array();
136     $NM1[0] = "NM1";                    // Subscriber Name Segment ID
137     if ($nm1Cast == 'PR') {
138         $NM1[1] = "PR";                         // Entity ID Code - Payer [PR Payer]
139         $NM1[2] = "2";                      // Entity Type - Non-Person
140         $NM1[3] = $row["payer_name"];       // Organizational Name
141         $NM1[4] = "";                       // Data Element not required.
142         $NM1[5] = "";                       // Data Element not required.
143         $NM1[6] = "";                       // Data Element not required.
144         $NM1[7] = "";                       // Data Element not required.
145         $NM1[8] = "PI";                     // 5010 no longer uses "46"
146         if ($GLOBALS['enable_oa']) {
147             $payerId = $row['eligibility_id'];
148         } else {
149             $payerId = $row['cms_id'];
150         }
151         $NM1[9] = $payerId; // Application Sender's ID
152     } else if ($nm1Cast == 'FA') {
153         $NM1[1] = "FA";                     // Entity ID Code - Facility [FA Facility]
154         $NM1[2] = "2";                      // Entity Type - Non-Person
155         $NM1[3] = $row['facility_name'];            // Organizational Name
156         $NM1[4] = "";           // Data Element not required.
157         $NM1[5] = "";           // Data Element not required.
158         $NM1[6] = "";                       // Data Element not required.
159         $NM1[7] = "";                       // Data Element not required.
160         $NM1[8] = "FI";
161         $NM1[9] = $row['facility_npi'];
162     } else if ($nm1Cast == '1P') {
163         $NM1[1] = "1P";                     // Entity ID Code - Provider
164         $NM1[2] = "2";                      // Entity Type - Non-Person
165         $NM1[3] = $row['facility_name'];   // Organizational Name
166         $NM1[4] = "";   // Data Element not required.
167         $NM1[5] = "";                       // Data Element not required.
168         $NM1[6] = "";                       // Data Element not required.
169         $NM1[7] = "";                       // Data Element not required.
170         $NM1[8] = "XX";
171         $NM1[9] = $row['provider_npi'];
172     } else if ($nm1Cast == 'IL') {
173         $NM1[1] = "IL";                         // Insured or Subscriber
174         $NM1[2] = "1";                      // Entity Type - Person
175         $NM1[3] = $row['lname'];                // last Name
176         $NM1[4] = $row['fname'];                // first Name
177         $NM1[5] = $row['mname'];                // middle Name
178         $NM1[6] = "";                       // data element
179         $NM1[7] = "";                       // data element
180         $NM1[8] = "MI";                     // Identification Code Qualifier
181         $NM1[9] = $row['policy_number'];    // Identification Code
182     }
183     $NM1['Created'] = implode('*', $NM1);               // Data Element Separator
184     $NM1['Created'] = $NM1['Created'] . $segTer;
185     return trim($NM1['Created']);
187 // REF Segment  - EDI-270 format
188 function create_REF($row, $ref, $X12info, $segTer, $compEleSep)
190     $REF    =   array();
191     $REF[0] = "REF";                            // Subscriber Additional Identification    does not want this for anything
192     if ($ref == '1P') {
193         $REF[1] = "4A";                         // Reference Identification Qualifier
194         $REF[2] = $row['provider_pin'];         // Provider Pin.
195     } else {
196         $REF[1] = "EJ";                         // 'EJ' for Patient Account Number     does not want this for patient
197         $REF[2] = $row['pid'];                  // Patient Account No.
198     }
199     $REF['Created'] = implode('*', $REF);  // Data Element Separator
200     $REF['Created'] = $REF['Created'] . $segTer;
201     return trim($REF['Created']);
203 // TRN Segment - EDI-270 format
204 function create_TRN($row, $tracno, $refiden, $X12info, $segTer, $compEleSep)
206     $TRN    =   array();
207     $TRN[0] = "TRN";                        // Subscriber Trace Number Segment ID
208     $TRN[1] = "1";                          // Trace Type Code ï¿½ Current Transaction Trace Numbers
209     $TRN[2] = $tracno;                      // Trace Number
210     $TRN[3] = "9000000000";                 // Originating Company ID ï¿½ must be 10 positions in length
211     $TRN[4] = $refiden;                     // Additional Entity Identifier (i.e. Subdivision)
212     $TRN['Created'] = implode('*', $TRN); // Data Element Separator
213     $TRN['Created'] = $TRN['Created'] . $segTer;
214     return trim($TRN['Created']);
216 // DMG Segment - EDI-270 format
217 function create_DMG($row, $X12info, $segTer, $compEleSep)
219     $DMG    =   array();
220     $DMG[0] = "DMG";                            // Date or Time or Period Segment ID
221     $DMG[1] = "D8";                             // Date Format Qualifier - (D8 means CCYYMMDD)
222     $DMG[2] = $row['dob'];                      // Subscriber's Birth date
223     $DMG[3] = strtoupper($row['sex'][0]);
224     $DMG['Created'] = implode('*', $DMG);  // Data Element Separator
225     $DMG['Created'] = $DMG['Created'] .  $segTer;
226     return trim($DMG['Created']);
228 // DTP Segment - EDI-270 format
229 function create_DTP($row, $qual, $X12info, $segTer, $compEleSep)
231     $DTP    =   array();
232     $DTP[0] = "DTP";                            // Date or Time or Period Segment ID
233     $DTP[1] = $qual;                            // Qualifier - Date of Service
234     $DTP[2] = "D8";                             // Date Format Qualifier - (D8 means CCYYMMDD)
235     if ($qual == '102') {
236         $DTP[3] = $row['date'];                 // Ins effective Date
237     } else {
238         switch ($X12info['x12_dtp03']) {
239             case 'A':
240                 $dtp_date = !empty($row['pc_eventDate']) && $row['pc_eventDate'] > '20010101' ? $row['pc_eventDate'] : date("Ymd");
241                 break;
242             case 'E':
243                 $dtp_date = !empty($row['date']) && $row['date'] > '20010101' ? $row['date'] : date("Ymd");
244                 break;
245             default:
246                 $dtp_date = date("Ymd");
247         }
248         $DTP[3] = $dtp_date;  // Date of Service
249     }
250     $DTP['Created'] = implode('*', $DTP);   // Data Element Separator
251     $DTP['Created'] = $DTP['Created'] .  $segTer;
252     return trim($DTP['Created']);
254 // EQ Segment - EDI-270 format
255 function create_EQ($row, $X12info, $segTer, $compEleSep)
257     $EQ         =   array();
258     $EQ[0]  = "EQ";                                     // Subscriber Eligibility or Benefit Inquiry Information
259     $EQ[1]  = "30";                                     // Service Type Code
260     $EQ['Created'] = implode('*', $EQ);                 // Data Element Separator
261     $EQ['Created'] = $EQ['Created'] . $segTer;
262     return trim($EQ['Created']);
264 // SE Segment - EDI-270 format
265 function create_SE($row, $segmentcount, $X12info, $segTer, $compEleSep)
267     $SE     =   array();
268     $SE[0] = "SE";                              // Transaction Set Trailer Segment ID
269     $SE[1] = $segmentcount;                     // Segment Count
270     $SE[2] = "000000003";                       // Transaction Set Control Number - Must match ST's
271     $SE['Created'] = implode('*', $SE);    // Data Element Separator
272     $SE['Created'] = $SE['Created'] . $segTer;
273     return trim($SE['Created']);
275 // GE Segment - EDI-270 format
276 function create_GE($row, $X12info, $segTer, $compEleSep)
278     $GE     =   array();
279     $GE[0]  = "GE";                          // Functional Group Trailer Segment ID
280     $GE[1]  = "1";                           // Number of included Transaction Sets
281     $GE[2]  = "2";                           // Group Control Number
282     $GE['Created'] = implode('*', $GE); // Data Element Separator
283     $GE['Created'] = $GE['Created'] . $segTer;
284     return trim($GE['Created']);
286 // IEA Segment - EDI-270 format
287 function create_IEA($row, $X12info, $segTer, $compEleSep)
289     $IEA    =   array();
290     $IEA[0] = "IEA";                        // Interchange Control Trailer Segment ID
291     $IEA[1] = "1";                          // Number of included Functional Groups
292     $IEA[2] = "000000001";                  // Interchange Control Number
293     $IEA['Created'] = implode('*', $IEA);
294     $IEA['Created'] = $IEA['Created'] .  $segTer;
295     return trim($IEA['Created']);
298 function translate_relationship($relationship)
300     switch ($relationship) {
301         case "spouse":
302             return "01";
303             break;
304         case "child":
305             return "19";
306             break;
307         case "self":
308         default:
309             return "S";
310     }
313 // EDI-270 Batch file Generation
314 function print_elig($res, $X12info, $segTer, $compEleSep)
316     $i=1;
317     $PATEDI    = "";
318     // For Header Segment
319     $nHlCounter = 1;
320     $rowCount   = 0;
321     $trcNo      = 1234501;
322     $refiden    = 5432101;
323     foreach ($res as $row) {
324         if ($nHlCounter == 1) {
325             // create ISA
326             $PATEDI    = create_ISA($row, $X12info, $segTer, $compEleSep);
327             // create GS
328             $PATEDI   .= create_GS($row, $X12info, $segTer, $compEleSep);
329             // create ST
330             $PATEDI   .= create_ST($row, $X12info, $segTer, $compEleSep);
331             // create BHT
332             $PATEDI   .= create_BHT($row, $X12info, $segTer, $compEleSep);
333             // For Payer Segment
334             $PATEDI  .= create_HL($row, 1, $X12info, $segTer, $compEleSep);
335             $PATEDI  .= create_NM1($row, 'PR', $X12info, $segTer, $compEleSep);
336             // For Provider Segment
337             $PATEDI  .= create_HL($row, 2, $X12info, $segTer, $compEleSep);
338             $PATEDI  .= create_NM1($row, '1P', $X12info, $segTer, $compEleSep);  // 5010 no longer uses FA
339             $nHlCounter = $nHlCounter + 2;
340             $segmentcount = 6; // segment counts - start from ST
341         }
342         // For Subscriber Segment
343         $PATEDI  .= create_HL($row, $nHlCounter, $X12info, $segTer, $compEleSep);
344         $PATEDI  .= create_NM1($row, 'IL', $X12info, $segTer, $compEleSep);
345         // send pid so we get it back in 271
346         $PATEDI .= create_REF($row, 'EJ', '', $segTer, '');
347         $PATEDI .= create_DMG($row, $X12info, $segTer, $compEleSep);
348         $PATEDI .= create_DTP($row, '291', $X12info, $segTer, $compEleSep);
349         $PATEDI .= create_EQ($row, $X12info, $segTer, $compEleSep);
350         $segmentcount = $segmentcount + 6;
351         $nHlCounter = $nHlCounter + 1;
352         $rowCount = $rowCount + 1;
353         $trcNo = $trcNo + 1;
354         $refiden = $refiden + 1;
355         if ($rowCount == count($res)) {
356             $segmentcount = $segmentcount + 1;
357             $PATEDI   .= create_SE($row, $segmentcount, $X12info, $segTer, $compEleSep);
358             $PATEDI   .= create_GE($row, $X12info, $segTer, $compEleSep);
359             $PATEDI   .= create_IEA($row, $X12info, $segTer, $compEleSep);
360         }
361     }
362     echo $PATEDI;
365 function requestEligibleTransaction($pid = 0, $eFlag = false)
367     $query = "SELECT 
368             d.facility_id,
369             p.lname,
370             p.fname,
371             p.mname,
372             DATE_FORMAT(p.dob, '%Y%m%d') as dob,
373             p.ss,
374             p.sex,
375             p.pid,
376             p.pubpid,
377             p.providerID,
378             i.subscriber_ss,
379             i.policy_number,
380             i.provider as payer_id,
381             i.subscriber_relationship,
382             i.subscriber_lname,
383             i.subscriber_fname,
384             i.subscriber_mname,
385             DATE_FORMAT(i.subscriber_DOB, '%Y%m%d') as subscriber_dob,
386             i.policy_number,
387             i.subscriber_sex,
388             DATE_FORMAT(i.date, '%Y%m%d') as date,
389             d.lname as provider_lname,
390             d.fname as provider_fname,
391             d.npi as provider_npi,
392             d.upin as provider_pin,
393             f.federal_ein as federal_ein,
394             f.facility_npi as facility_npi,
395             f.name as facility_name,
396             c.cms_id as cms_id,
397             c.eligibility_id as eligibility_id,
398             c.x12_default_eligibility_id as partner,
399             c.name as payer_name
400         FROM patient_data AS p 
401         LEFT JOIN users AS d on (p.providerID = d.id)
402         LEFT JOIN facility AS f on (f.id = d.facility_id)
403         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))
404         LEFT JOIN insurance_companies as c ON (c.id = i.provider)
405         WHERE p.pid = ?";
406     $res = sqlStatement($query, array($pid));
408     $details = requestRealTimeEligible($res, '', "~", ':', true);
409     $isError = strpos($details, "Error:");
410     $isError = $isError !== false ? $isError : strpos($details, "AAA");
411     if ($isError !== false) {
412         $details = substr($details, $isError);
413         return "<div>" . nl2br(text($details)) . "</div>";
414     }
416     return true;
419 // EDI-270 RealTime Request & Response
420 // RealTime requires one transaction per request.
422 function requestRealTimeEligible($res, $X12info, $segTer, $compEleSep, $eFlag = false)
424     $rowCount = 0;
425     $totalCount = count($res);
426     $down_accum = $log = $error_accum = '';
427     foreach ($res as $row) {
428         if (!$X12info) {
429             $X12info = getX12Partner($row['partner']);
430         }
431         if ($row['providerID'] === 0 || !$row['provider_npi']) {
432             $error_accum .= xlt("Error") . ": " . xlt("Provider Missing Add one in Choices") . "\n";
433         }
434         if (!$row['eligibility_id']) {
435             $error_accum .= xlt("Error") . ": " . xlt("Missing Insurance Payer Id") . "\n";
436         }
437         if (!$row['policy_number'] || !$row['subscriber_dob']) {
438             $error_accum .= xlt("Error") . ": " . xlt("Missing Subscriber Policy Number or DOB") . "\n";
439         }
440         if (!empty($error_accum)) {
441             return $error_accum;
442         }
443         // create ISA
444         $PATEDI = create_ISA($row, $X12info, $segTer, $compEleSep);
445         // create GS
446         $PATEDI .= create_GS($row, $X12info, $segTer, $compEleSep);
447         // create ST
448         $PATEDI .= create_ST($row, $X12info, $segTer, $compEleSep);
449         // create BHT
450         $PATEDI .= create_BHT($row, $X12info, $segTer, $compEleSep);
451         // For Payer Segment
452         $PATEDI .= create_HL($row, 1, $X12info, $segTer, $compEleSep);
453         $PATEDI .= create_NM1($row, 'PR', $X12info, $segTer, $compEleSep);
454         // For Provider Segment
455         $PATEDI .= create_HL($row, 2, $X12info, $segTer, $compEleSep);
456         //$PATEDI .= create_NM1($row, 'FA', $X12info, $segTer, $compEleSep); // unsure but this may have to be an option
457         $PATEDI .= create_NM1($row, '1P', $X12info, $segTer, $compEleSep);
458         // For Subscriber Segment
459         $PATEDI .= create_HL($row, 3, $X12info, $segTer, $compEleSep);
460         $PATEDI .= create_NM1($row, 'IL', $X12info, $segTer, $compEleSep);
461         // send pid so we get it back in 271
462         $PATEDI .= create_REF($row, 'EJ', '', $segTer, '');
463         $PATEDI .= create_DMG($row, $X12info, $segTer, $compEleSep);
464         // 2110
465         $PATEDI .= create_DTP($row, '291', $X12info, $segTer, $compEleSep);
466         $PATEDI .= create_EQ($row, $X12info, $segTer, $compEleSep);
467         // the end
468         $PATEDI .= create_SE($row, 13, $X12info, $segTer, $compEleSep);
469         $PATEDI .= create_GE($row, $X12info, $segTer, $compEleSep);
470         $PATEDI .= create_IEA($row, $X12info, $segTer, $compEleSep);
471         // make request
472         $result = requestEligibility($X12info['id'], $PATEDI);
473         $rowCount++;
474         $e = strpos($result, "Error:");
475         if ($e !== false) {
476             $error_accum = $result;
477         } else {
478             $down_accum .= $result . "\n"; // delimit for next new request
479         }
481         $log .= "*** 270 " . xlt("Request Message") . " $rowCount of $totalCount\n" . $PATEDI . "\n" . $error_accum . "\n"; // keep a log.
482         $error_accum = '';
483     }
484     // parse the 271 responses from 270 requests sent.
485     $process = parseEdi271($down_accum);
486     $log = xlt("List of ") . $rowCount .  " " . xlt("Requests Sent") . ":\n" . $log . "\n" . $process;
487     if ($eFlag) {
488         return $log;
489     }
491     return $rowCount;
493 // Report Generation
495 function show_elig($res, $X12info, $segTer, $compEleSep)
498     $i=0;
499     echo "      <div id='report_results'>
500     <table class='table table-striped table-hover'>
501         <thead>
502             <th>". text(xl('Facility Name')) ."</th>
503             <th>". text(xl('Facility NPI')) ."</th>
504             <th>". text(xl('Insurance Comp')) ."</th>
505             <th>". text(xl('Appt Date')) ."</th>
506             <th>". text(xl('Policy No')) ."</th>
507             <th>". text(xl('Patient Name')) ."</th>
508             <th>". text(xl('DOB')) ."</th>
509             <th>". text(xl('Gender')) ."</th>
510             <th>". text(xl('SSN')) ."</th>
511             <th>        &nbsp;                    </th>
512         </thead>
513         <tbody>";
515     foreach ($res as $row) {
516         $i= $i+1;
517         // what the heck is below for... looks abandoned.
518         $elig     = array();
519         $elig[0]  = $row['facility_name'];              // Inquiring Provider Name  calendadr
520         $elig[1]  = $row['facility_npi'];               // Inquiring Provider NPI
521         $elig[2]  = $row['payer_name'];                     // Payer Name  our insurance co name
522         $elig[3]  = $row['policy_number'];              // Subscriber ID
523         $elig[4]  = $row['subscriber_lname'];               // Subscriber Last Name
524         $elig[5]  = $row['subscriber_fname'];               // Subscriber First Name
525         $elig[6]  = $row['subscriber_mname'];               // Subscriber Middle Initial
526         $elig[7]  = $row['subscriber_dob'];                 // Subscriber Date of Birth
527         $elig[8]  = substr($row['subscriber_sex'], 0, 1);       // Subscriber Sex
528         $elig[9]  = $row['subscriber_ss'];              // Subscriber SSN
529         $elig[10] = translate_relationship($row['subscriber_relationship']);    // Pt Relationship to insured
530         $elig[11] = $row['lname'];                  // Dependent Last Name
531         $elig[12] = $row['fname'];                  // Dependent First Name
532         $elig[13] = $row['mname'];                  // Dependent Middle Initial
533         $elig[14] = $row['dob'];                    // Dependent Date of Birth
534         $elig[15] = substr($row['sex'], 0, 1);              // Dependent Sex
535         $elig[16] = $row['pc_eventDate'];               // Date of service
536         $elig[17] = "30";                       // Service Type
537         $elig[18] = $row['pubpid'];                     // Patient Account Number pubpid
539         echo "  <tr id='PR".$i."_". text($row['policy_number'])."'>
540                                 <td class ='detail'>". text($row['facility_name']) ."</td>
541                                 <td class ='detail'>".  text($row['facility_npi']) ."</td>
542                                 <td class ='detail'>". text($row['payer_name']) ."</td>
543                                 <td class ='detail'>". text(date("m/d/Y", strtotime($row['pc_eventDate']))) ."</td>
544                                 <td class ='detail'>".  text($row['policy_number']) ."</td>
545                                 <td class ='detail'>". text($row['subscriber_lname']." ". $row['subscriber_fname']) ."</td>
546                                 <td class ='detail'>".  text($row['subscriber_dob']) ."</td>
547                                 <td class ='detail'>".  text($row['subscriber_sex']) ."</td>
548                                 <td class ='detail'>".  text($row['subscriber_ss']) ."</td>
549                                 <td class ='detail'>
550                                 <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']) . "\")'>
551                                 </td>
552                         </tr>
553                 ";
554         unset($elig); // see ..
555     }
557     if ($i==0) {
558         echo "  <tr>
559                                 <td class='norecord' colspan=9>
560                                         <div style='padding:5px;font-family:arial;font-size:13px;text-align:center;'>". text(xl('No records found')) . "</div>
561                                 </td>
562                         </tr>   ";
563     }
564         echo "  </tbody>
565                         </table>";
568 // To Show Eligibility Verification data
569 function show_eligibility_information($pid, $flag = false)
571     $query =
572         "SELECT eligr.*, eligv.insurance_id, eligv.copay, insd.pid, insc.name, " .
573         "Date_Format(eligv.eligibility_check_date, '%W %M %e, %Y %h:%i %p') AS verificationDate " .
574         "FROM eligibility_verification eligv " .
575         "INNER JOIN benefit_eligibility eligr ON eligr.verification_id = eligv.verification_id " .
576         "INNER JOIN insurance_data insd ON insd.id = eligv.insurance_id " .
577         "INNER JOIN insurance_companies insc ON insc.id = insd.provider " .
578         "WHERE insd.pid = ? AND eligv.eligibility_check_date = " .
579         "(SELECT Max(eligibility_verification.eligibility_check_date) FROM eligibility_verification ".
580         "WHERE eligibility_verification.insurance_id = eligv.insurance_id)";
581     $result = sqlStatement($query, array($pid));
583     $showString = "<div class='row'>";
584     $col = 1;
585     $title = 1;
586     while ($benefit = sqlFetchArray($result)) {
587         if ($title) {
588             $title = 0;
589             $showString .= "<div class='col col-sm-12'>\n";
590             $showString .= "<b>" . xlt('Insurance Provider') . ":</b> " . (!empty($benefit['name']) ? text($benefit['name']) : xlt('n/a')) . "<br/>\n";
591             $showString .= "<b>" . xlt('Verified On') . ":</b> " . text($benefit['verificationDate']) . "<br/><br/>\n";
592             $showString .= "</div><br/>\n";
593         }
594         $benefit['start_date'] = strpos($benefit['start_date'], "0000") === false ? $benefit['start_date'] : '';
595         $benefit['end_date'] = strpos($benefit['end_date'], "0000") === false ? $benefit['end_date'] : '';
596         $color = "";
597         switch ($benefit['type']) {
598             case '1':
599                 $color = "darkred";
600                 break;
601             case 'A':
602                 $color = "blue";
603                 break;
604             case 'B':
605                 $color = "red";
606                 break;
607             case 'C':
608                 $color = "green";
609                 break;
610             case 'F':
611                 $color = "darkgreen";
612                 break;
613         }
614         $showString .= "\n<div class='col col-sm-6' >\n";
615         $showString .= !empty($benefit['benefit_type']) ? "<b style='color: $color'>" . xlt('Benefit Type') . ": " .  text($benefit['benefit_type']) . "</b><br />\n" : '';
616         $showString .= !empty($benefit['start_date']) ? "<b>" . xlt('Start Date') . ":</b> " . text(date("m/d/Y", strtotime($benefit['start_date']))) . "<br />\n" : '';
617         $showString .= !empty($benefit['end_date']) ? "<b>" . xlt('End Date') . ":</b> " . text(date("m/d/Y", strtotime($benefit['end_date']))) . "<br />\n" : '';
618         $showString .= !empty($benefit['coverage_level']) ? "<b>" . xlt('Coverage Level') . ":</b> " .text($benefit['coverage_level']) . "<br />\n" : '';
619         $showString .= !empty($benefit['coverage_type']) ? "<b>" . xlt('Coverage Type') . ":</b> " . text($benefit['coverage_type']) . "<br />\n" : '';
620         $showString .= !empty($benefit['plan_type']) ? "<b>" . xlt('Plan Type') . ":</b> " .  text($benefit['plan_type']) . "<br />\n" : '';
621         $showString .= !empty($benefit['plan_desc']) ? "<b>" . xlt('Plan Description') . ":</b> " .  text(text($benefit['plan_desc'])) . "<br />\n" : '';
622         $showString .= !empty($benefit['coverage_period']) ? "<b>" . xlt('Coverage Period') . ":</b> " . text($benefit['coverage_period']) . "<br />\n" : '';
623         $showString .= !empty($benefit['amount']) ? "<b>" . xlt('Amount') . ":</b> " . text($benefit['amount']) . "<br />\n" : '';
624         $showString .= !empty($benefit['percent']) ? "<b>" . xlt('Percentage') . ":</b> " . text($benefit['percent']) . "<br />\n" : '';
625         $showString .= !empty($benefit['network_ind']) ? "<b>" . xlt('Network Indicator') . ":</b> " . text($benefit['network_ind']) . "<br />\n" : '';
626         $showString .= !empty($benefit['message']) ? "<b>" . xlt('Message') . ":</b> " . text($benefit['message']) . "<br />\n" : '';
627         $showString .= "</div>";
629         if ($col === 2) {
630             $showString .= "</div>\n<br/><div class='row'>\n";
631             $col = 0;
632         }
633         $col++;
634     }
635     if ($col === 2) {
636         $showString .= "</div>";
637     }
638     if ($title === 1) {
639         $showString = "<br><span><b>" . xlt("Nothing To Report") . "</b></span><br>";
640     }
641     $showString .= "</div>\n";
642     echo $showString;
645 // For EDI 271
646 // Function to save the values in eligibility_verification table
647 function eligibility_verification_save($subscriber = [])
649     $verification_id = 0;
650     $insurance_id = 0;
651     $partner_id = $subscriber['isa_sender_id'];
652     $patient_id = $subscriber['pid'];
654     $query = "SELECT id, copay FROM insurance_data WHERE type = 'primary' and pid = ?";
655     $insId = sqlQuery($query, array($patient_id));
656     if ($insId !== false) {
657         $insurance_id = $insId['id'];
658         $copay = $insId['copay'];
659     }
661     $query = "SELECT verification_id FROM eligibility_verification WHERE insurance_id = ?";
662     $resId = sqlQuery($query, array($insurance_id));
663     if ($resId !== false) {
664         $verification_id = $resId['verification_id'];
665     }
667     if (!empty($insurance_id)) {
668         $sqlBindArray = array();
669         $query = "REPLACE INTO eligibility_verification SET verification_id = ?, insurance_id = ?, response_id = ?, eligibility_check_date = now(), create_date = now()";
670         array_push($sqlBindArray, $verification_id, $insurance_id, $partner_id);
672         $res = sqlInsert($query, $sqlBindArray);
673         if (!$verification_id) {
674             $verification_id = $res;
675         }
676     }
678     $query = "DELETE FROM `benefit_eligibility` WHERE `benefit_eligibility`.`verification_id` = ?";
679     $res = sqlStatement($query, array($verification_id));
681     foreach ($subscriber['benefits'] as $benefit) {
682         $bind = array(
683             $verification_id,
684             "A",
685             date('Y/m/d H:i'),
686             date('Y/m/d H:i'),
687             $benefit['type'],
688             $benefit['benefit_type'],
689             $benefit['start_date'],
690             $benefit['end_date'],
691             $benefit['coverage_level'],
692             $benefit['coverage_type'],
693             $benefit['plan_type'],
694             $benefit['plan_desc'],
695             $benefit['coverage_period'],
696             $benefit['amount'],
697             $benefit['percent'],
698             $benefit['network_ind'],
699             $benefit['message']
700         );
702         $query = "INSERT INTO `benefit_eligibility` " .
703             "(`verification_id`, `response_status`, `response_create_date`, `response_modify_date`, `type`, `benefit_type`, `start_date`, " .
704             "`end_date`, `coverage_level`, `coverage_type`, `plan_type`, `plan_description`, `coverage_period`, `amount`, `percent`, `network_ind`, `message`) " .
705             "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
706         $res = sqlStatement($query, $bind);
707     }
710 // return array of X12 partners
711 // if id return just that id
712 function getX12Partner($id = 0)
714     // @TODO move to class
715     global $X12info;
716     $id = (int)$id;
717     $returnval = [];
719     if ((int)$id > 0) {
720         $returnval = sqlQuery("select * from x12_partners WHERE id = ?", array($id));
721         $X12info = $returnval;
722     } else {
723         $rez = sqlStatement("select * from x12_partners");
724         for ($iter = 0; $row = sqlFetchArray($rez); $iter++) {
725             $returnval[$iter] = $row;
726         }
727     }
729     return $returnval;
732 // return array of provider usernames
733 function getUsernames()
735     $rez = sqlStatement("select distinct username, lname, fname,id from users " .
736         "where authorized = 1 and username != ''");
737     for ($iter = 0; $row = sqlFetchArray($rez); $iter++) {
738         $returnval[$iter] = $row;
739     }
741     return $returnval;
744 // return formated array
746 function arrFormated(&$item, $key)
748     $item = strstr($item, '_');
749     $item = substr($item, 1, strlen($item) - 1);
750     $item = "'" . $item;
753 function requestEligibility($partner = '', $x12_270 = '')
755     global $X12info;
756     if (((int)$X12info['id'] !== (int)$partner) && (int)$partner > 0) {
757         $X12info = getX12Partner($partner);
758     }
760     $payloadId = "3b8c13f5-11e2-43bf-bc47-737cca04f3fe"; // a default fallback
761     if (function_exists('openssl_random_pseudo_bytes') === true) {
762         $data = openssl_random_pseudo_bytes(16);
763         $data[6] = chr(ord($data[6]) & 0x0f | 0x40);
764         $data[8] = chr(ord($data[8]) & 0x3f | 0x80);
765         $payloadId = vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
766     }
768     $boundary = RandomGenUtils::createUniqueToken(12);
769     $rt_passwrd = $X12info['x12_isa04'];
770     $rt_user = $X12info['x12_isa02'];
771     $sender_id = $X12info['x12_sender_id'];
772     $receiver_id = $X12info['x12_receiver_id'];
773     $now_date = date("Y-m-d\TH:i:s\Z");
774     $headers = array(
775         'Content-Type' => "multipart/form-data; boundary=$boundary",
776         'Host' => ' wsd.officeally.com'
777     );
779 // IMPORTANT: Do not change the format of $mime_body below.
780 // HTTP MIME Multipart is non-normative. LFs matter...
782     $mime_body = <<<MIMEBODY
783 --$boundary
784 Content-Disposition: form-data; name="ProcessingMode"
786 RealTime
787 --$boundary
788 Content-Disposition: form-data; name="TimeStamp"
790 $now_date
791 --$boundary
792 Content-Disposition: form-data; name="PayloadID"
794 $payloadId
795 --$boundary
796 Content-Disposition: form-data; name="CORERuleVersion"
798 2.2.0
799 --$boundary
800 Content-Disposition: form-data; name="ReceiverID"
802 $receiver_id
803 --$boundary
804 Content-Disposition: form-data; name="SenderID"
806 $sender_id
807 --$boundary
808 Content-Disposition: form-data; name="PayloadType"
810 X12_270_Request_005010X279A1
811 --$boundary
812 Content-Disposition: form-data; name="UserName"
814 $rt_user
815 --$boundary
816 Content-Disposition: form-data; name="Password"
818 $rt_passwrd
819 --$boundary
820 Content-Disposition: form-data; name="Payload"
822 $x12_270
823 --$boundary--
824 MIMEBODY;
825     // send the request
826     $response = oeHttp::bodyFormat('body')
827         //->setDebug('5000')/* @todo uncomment and set proxy port to debug eg Fiddler */
828         ->usingHeaders($headers)
829         ->post('https://wsd.officeally.com/TransactionSite/rtx.aspx', $mime_body); // @TODO put request urls in x12 partner's for versatility.
831     $formBody = $response->body();
832     $contentType = $response->header('Content-Type')[0];
833     $hContentLength = (int)$response->header('Content-Length')[0];
834     $cksum = ($hContentLength - strlen($formBody)) === 0 ? true : false; // validate content size
835     $formData = mimeParse($formBody, $contentType);
837     $errors = '';
838     if (!$cksum) {
839         $errors .= "Error:" . xlt("Request Content Fails Integrity Test");
840     }
841     if ($response->status() !== 200) {
842         $errors .= "\nError:" . xlt("Http Error") . ": " . $response->getReasonPhrase() .  " : " . $response->status();
843     }
844     if ($formData['ErrorCode'] != "Success") {
845         $errors .= "\nError:" . $formData['ErrorCode'] . "\n" . $formData['ErrorMessage'];
846     }
847     if ($errors) {
848         $errors .= $formData['Payload'] ? "\nError:" . $formData['Payload'] : '';
849         return $errors;
850     }
852     $x12_271 = $formData['Payload'];
854     return $x12_271;
857 function mimeParse($formBody = '', $contentType)
859     $mimeBody = preg_replace('~\r\n?~', "\r", $formBody);
860     list($contentType, $bound, $cs) = explode(";", trim($contentType)); // $contentType & $cs are throwaways
861     $bound = explode("=", trim($bound, ' '))[1];
862     $mimeFields = preg_split("/-+$bound/", $mimeBody);
863     array_pop($mimeFields);
864     $hold = $isMatches = [];
865     foreach ($mimeFields as $id => $field) {
866         if (empty($field)) {
867             continue;
868         }
869         preg_match('/name=\"([^\"]*)\"[\n|\r]+([^\n\r].*)?\r$/s', $field, $isMatches);
870         if (preg_match('/^(.*)\[\]$/i', $isMatches[1], $hold)) {
871             $mimeData[$hold[1]][] = $isMatches[2];
872         } else {
873             $mimeData[$isMatches[1]] = $isMatches[2];
874         }
875     }
876     return $mimeData;
879 function getPatientMatch($fn, $ln, $sex, $dob)
881     $fn = "%" . $fn . "%";
882     $ln = "%" . $ln . "%";
883     $sex = "%" . $sex . "%";
884     $dob = date("Y-m-d", strtotime($dob));
885     $sql = "SELECT pid FROM patient_data WHERE fname LIKE ? && lname LIKE ? && sex LIKE ? && DOB LIKE ?";
886     $rtn = sqlQuery($sql, array($fn, $ln, $sex, $dob));
888     return $rtn['pid'] ? $rtn['pid'] : 0;
891 function parseEdi271($content)
894     $codes = new edih_271_codes('*', '^');
895     $target = $GLOBALS['edi_271_file_path'];
896     $log = "";
897     // not sure if want to save yet
898     $target = $target . time();
900     $responses = explode("\n", $content);
901     if (empty($responses)) {
902         $responses = $content;
903     }
905 // Loop through each 271. '\n' delims records in batch.
906     foreach ($responses as $new) {
907         if (empty($new)) {
908             continue;
909         }
910         $AAA = array();
911         $subscribers = array();
912         $benefits = array();
913         $in = array();
914         $in['pid'] = 0;
915         $loop = array();
916         $loop['id'] = 0;
917         $loop['parent'] = 0;
918         $loop['error'] = 1;
919         $trace = -1;
921         $segments = explode("~", $new);
923         if (count($segments) < 6) {
924             if (file_exists($target)) {
925                 unlink($target);
926             }
927             continue;
928         }
930         foreach ($segments as $segment) {
931             $elements = explode("*", $segment);
932             $ecnt = count($elements);
933             // sanitize
934             for ($i = 0; $i < $ecnt; $i++) {
935                 $elements[$i] = text(trim($elements[$i]));
936             }
937             // Switch Case for Segment
938             switch ($elements[0]) {
939                 case 'ISA':
940                     $loop[1] = $elements[2];
941                     $in['isa_sender_id'] = $elements[6];
942                     $in['isa_receiver_id'] = $elements[8];
943                     $in['isa_control_number'] = $elements[13];
944                     break;
946                 case 'HL':
947                     $loop['id'] = (int)$elements[1];
948                     $loop['parent'] = (int)$elements[2];
949                     $loop['error'] = (int)$elements[4];
950                     break;
952                 case 'NM1':
953                     if ($loop['id'] === 1) {//"PR" payer
954                         $in['payer_org'] = $elements[3];
955                         $in['payer_member_id'] = $elements[9];
956                     } elseif ($loop['id'] === 2) { //"1P" or "FA"
957                         $in['provider_org'] = $elements[3];
958                         $in['provider_member_id'] = $elements[9];
959                     } elseif ($elements[1] == "IL" || $loop['context'] == "TRN") { //"IL"
960                         $in['trace'] = $trace;
961                         $in['subscriber_lname'] = $elements[3];
962                         $in['subscriber_fname'] = $elements[4];
963                         $in['subscriber_mname'] = $elements[5];
964                         $in['subscriber_member_id'] = $elements[9];
965                         $in['verify_date'] = date('Y/m/d H:i:s');
966                     }
967                     $loop['context'] = $elements[0];
968                     break;
970                 case 'DMG':
971                     if ($elements[1] == "D8") {
972                         $in['subscriber_dob'] = $elements[2];
973                     }
974                     $in['subscriber_sex'] = $elements[3];
975                     $loop['context'] = $elements[0];
976                     // 2100A-C should be done so get our patient id.
977                     if (!(int)$in['pid']) {
978                         $in['pid'] = (int)getPatientMatch(
979                             $in['subscriber_fname'],
980                             $in['subscriber_lname'],
981                             $in['subscriber_sex'],
982                             $in['subscriber_dob']
983                         );
984                     }
985                     break;
987                 case 'TRN':
988                     if ($trace === -1) {
989                         $trace++;
990                         break; // subscriber not set yet
991                     }
992                     $trace++;
993                     if ($in['pid']) {
994                         $in['benefits'] = $benefits ? $benefits : [];
995                         array_push($subscribers, $in);
996                         $loop['context'] = $elements[0];
997                         $benefits = [];
998                     }
999                     break;
1001                 case 'REF':
1002                     if ($elements[1] == "EJ") {
1003                         $in['pid'] = (int)$elements[2];
1004                         if (!$in['pid']) {
1005                             $in['pid'] = (int)getPatientMatch(
1006                                 $in['subscriber_fname'],
1007                                 $in['subscriber_lname'],
1008                                 $in['subscriber_sex'],
1009                                 $in['subscriber_dob']
1010                             );
1011                         }
1012                     }
1013                     break;
1015                 case 'DTP':
1016                     if ($elements[2] == "D8") {
1017                         $loop['start_date'] = $elements[3] ? date("Y-m-d", strtotime($elements[3])) : '';
1018                         $loop['end_date'] = '';
1019                     } elseif ($elements[2] == "RD8") {
1020                         $tmp = explode('-', $elements[3]);
1021                         $loop['start_date'] = $tmp[0] ? date("Y-m-d", strtotime($tmp[0])) : '';
1022                         $loop['end_date'] = !empty($tmp[1]) ? date("Y-m-d", strtotime($tmp[1])) : '';
1023                     }
1024                     if ($loop['context'] == "EB") {
1025                         $bcnt = count($benefits) - 1;
1026                         $benefits[$bcnt]['start_date'] = $loop['start_date'];
1027                         $benefits[$bcnt]['end_date'] = $loop['end_date'];
1028                     }
1029                     break;
1031                 case 'EB':
1032                     $eb = array(
1033                         'type' => $elements[1],
1034                         'benefit_type' =>  $codes->get_271_code("EB01", $elements[1]) ?  $codes->get_271_code("EB01", $elements[1]) : $elements[1],
1035                         'start_date' => '',
1036                         'end_date' => '',
1037                         'coverage_level' => $elements[2] ?  $codes->get_271_code("EB02", $elements[2]) :$elements[2],
1038                         'coverage_type' => $elements[3] ?  $codes->get_271_code("EB03", $elements[3]) :$elements[3],
1039                         'plan_type' =>  $elements[4] ?  $codes->get_271_code("EB04", $elements[4]) : $elements[4],
1040                         'plan_description' => $elements[5],
1041                         'coverage_period' =>  $elements[6] ?  $codes->get_271_code("EB06", $elements[6]) : $elements[6],
1042                         'amount' => $elements[7] ? number_format($elements[7], 2, '.', '') : '',
1043                         'percent' => $elements[8],
1044                         'network_ind' => $elements[12] ?  $codes->get_271_code("EB12", $elements[12]) : $elements[12],
1045                         'message' => '' // any MSG segments that may be assoc with this EB.
1046                     );
1047                     $loop['context'] = "EB";
1048                     array_push($benefits, $eb);
1049                     break;
1051                 case 'AAA':
1052                     $error = array(
1053                         'request_ind' => $elements[1],
1054                         'reason_code' => $elements[3] . " : " .  $codes->get_271_code("AAA03", $elements[3]),
1055                         'follow_up' => $elements[4] . " : " .  $codes->get_271_code("AAA04", $elements[4])
1056                     );
1057                     array_push($AAA, $error);
1058                     break;
1060                 case 'MSG':
1061                     $bcnt = count($benefits) - 1;
1062                     if ($bcnt > -1) {
1063                         $benefits[$bcnt]['message'] = $benefits[$bcnt]['message'] ? $benefits[$bcnt]['message'] . ":" : '';
1064                         $benefits[$bcnt]['message'] .= $elements[1];
1065                     }
1066                     break;
1068                 case 'SE':
1069                     $in['benefits'] = $benefits ? $benefits : [];
1070                     if ($in['pid']) {
1071                         array_push($subscribers, $in);
1072                     }
1073                     $loop['context'] = $elements[0];
1074                     $benefits = [];
1075                     break;
1077                 case 'IEA':
1078                     // save
1079                     $elog = '';
1080                     if (count($subscribers) < 1) {
1081                         $elog = xlt("Error") . ": " . xlt("Unknown Transaction Error Maybe Subscriber Effective or DOB Dates");
1082                     }
1083                     foreach ($subscribers as $subscriber) {
1084                         eligibility_verification_save($subscriber);
1085                     }
1086                     break;
1087             }
1088         }
1089         // some debug logging
1090         if (!$GLOBALS['disable_eligibility_log']) {
1091             $log .= "*------------------- " . xlt("271 Returned") . " --------------------*\n" . $new . "\n" . (isset($AAA[0]) ? (xlt("AAA Segments") . ":\n" . print_r($AAA, true)) : "\n") . $elog;
1092             $log .= makeEligibilityReport($subscribers);
1093         }
1094     }
1097     return $log;
1100 function makeEligibilityReport($subscribers = [])
1102     $binfo = '';
1103     foreach ($subscribers as $subscriber) {
1104         $binfo .=
1105             xlt("Subscriber Member") . ": " . $subscriber['subscriber_fname'] . " " . $subscriber['subscriber_lname'] . " " . $subscriber['subscriber_mname'] .
1106             " " .xlt("Member Id") . ": " . $subscriber['subscriber_member_id'] . " ---*\n";
1107         $cnt = count($subscriber['benefits']);
1108         if ($cnt < 1) {
1109             $binfo .= "*** " . xlt("Nothing returned to report") . " ***\n";
1110         }
1111         foreach ($subscriber['benefits'] as $key => $benefits) {
1112             foreach ($benefits as $key => $benefit) {
1113                 if ($key == 'type') {
1114                     $binfo .= "\n";
1115                 }
1116                 if (empty($benefit) || $key == 'type') {
1117                     continue;
1118                 }
1119                 $binfo .= "\t" . ucwords(str_replace('_', ' ', $key)) . ": " . $benefit . "\n";
1120             }
1121         }
1122     }
1124     return $binfo;