Example #1
0
/**
 * Parse a batch file for data for the csv record
 * 
 * The array returned has a key 'file' which is for the files_batch.csv
 * and a key 'claim' with a subarray for each claim
 * 
 * @see csv_files_header() for values
 * @uses csv_x12_segments()
 * @param string $batch_file   name of x12-837 batch file
 * @return array
 */
function ibr_batch_csv_data($batch_file_path)
{
    //
    // read the file and transform it into an array of segment arrays
    // then loop through the segment arrays and copy desired items
    // to a data array for writing to the csv_file and csv_claims files
    //
    // get the segments from csv_record_include function csv_x12_segments
    $ar_batch = csv_x12_segments($batch_file_path, 'batch', $seg_array = FALSE);
    // debug
    //var_dump(array_keys($ar_batch) ) .PHP_EOL;
    //
    if (is_array($ar_batch)) {
        $batch_file = basename($ar_batch['path']);
        $elem_d = $ar_batch['delimiters']['e'];
        //
    } else {
        csv_edihist_log("ibr_batch_csv_data did not get segments for {$batch_file}");
        return FALSE;
    }
    //
    $ar_data = array();
    $st_ct = -1;
    $seg_ct = 0;
    //
    foreach ($ar_batch['segments'] as $segtxt) {
        // debug
        //echo "$segtxt  <br />" .PHP_EOL;
        //
        $seg = explode($elem_d, $segtxt);
        // increment segment count for testing
        $seg_ct++;
        // these values will occur once per file
        // $fname = $batch_file; 			// $ar_data[$st_ct][8] = $batch_file
        if ($seg[0] == "ISA") {
            $x12partner = $seg[6];
            $f_mtime = '20' . $seg[9];
            $x12version = $seg[12];
            $ctrl_num = strval($seg[13]);
            // $ar_data[$st_ct][10] = $ctrl_num
            //
            continue;
        }
        if ($seg[0] == 'GS') {
            $f_mtime = $seg[4];
            continue;
        }
        // get GE segment for files data claim count
        if ($seg[0] == "GE") {
            $clm_ct = $seg[1];
            continue;
        }
        // now we need to create a sub array for each ST block
        if ($seg[0] == "ST") {
            $st_ct++;
            // OpenEMR 837 places each claim in an ST block
            $ln_st = $seg_ct;
            $st_num = strval($seg[2]);
            // $ar_data[$st_ct][9] = $st_num;
            continue;
        }
        if ($seg[0] == "BHT") {
            $bht03 = $seg[3];
            $ins_pos = '';
            // since this is '0123' and not useful, we will construct it
            // below with $ctrl_num.$st_num
            continue;
        }
        if ($seg[0] == "HL") {
            $hlevel = strval($seg[3]);
            continue;
        }
        if ($seg[0] == "SBR") {
            if (($hlevel == '22' || $hlevel == '23') && !$ins_pos) {
                $ins_pos = $seg[1];
            }
            //$ins_pos = $seg[1];
            continue;
        }
        if ($seg[0] == "CAS") {
            // on theory that CAS will only appear on secondary claims
            if ($ins_pos == 'P') {
                $ins_pos = 'S';
            }
        }
        if ($seg[0] == "NM1" && $seg[1] == "PR") {
            if ($ins_pos == "P") {
                $ins_primary = $seg[3];
                // $ar_data[$st_ct][7] = $ins_primary;
            }
            if ($ins_pos == "S") {
                $ins_secondary = $seg[3];
                // $ar_data[$st_ct][8] = $ins_secondary;
            }
            continue;
        }
        if ($seg[0] == "NM1" && strpos("|IL|QC", $seg[1])) {
            // The NM1*QC segment is in the batch file if the patient is not
            // the subscriber, and it comes after the NM1*IL segment,
            // so get something in either case, but errors can leave blanks
            $pt_lname = $pt_lname ? $pt_lname : $seg[3];
            // $ar_data[$st_ct][0] = $pt_lname
            $pt_fname = $pt_fname ? $pt_fname : $seg[4];
            // $ar_data[$st_ct][1] = $pt_fname
            continue;
        }
        if ($seg[0] == "NM1" && $seg[1] == '82') {
            $providerid = $seg[9];
            continue;
        }
        if ($seg[0] == "CLM") {
            $inv_split = preg_split('/\\D/', $seg[1], 2, PREG_SPLIT_NO_EMPTY);
            $pid = $inv_split[0];
            // $ar_data[$st_ct][2] = $pid
            $enctr = $inv_split[1];
            // $ar_data[$st_ct][3] = $enctr
            $clm01 = $seg[1];
            $fee = $seg[2];
            // $ar_data[$st_ct][5] = $fee
            continue;
        }
        if ($seg[0] == "DTP" && $seg[1] == "472") {
            $svc_date = $seg[3];
            // $ar_data[$st_ct][4] = $svc_date
            continue;
        }
        if ($seg[0] == "AMT" && $seg[1] == "F5") {
            $pt_paid = $seg[2];
            // $ar_data[$st_ct][6] = $pt_paid
            continue;
        }
        if ($seg[0] == "SE") {
            // end of ST block, get claim array and go back
            // debug  count lines
            $ln_ct = $seg[1];
            //
            $ln_test = $seg_ct - $ln_st + 1;
            if ($ln_test != $ln_ct) {
                csv_edihist_log("ibr_batch_csv_data: ST segment count error {$ln_test} {$ln_ct}");
            }
            //['batch']['claim'] = array('PtName', 'SvcDate', 'clm01', 'InsLevel', 'Ctn_837', 'File_837', 'Fee', 'PtPaid', 'Provider' );
            // now put ar_data in order
            //
            $ar_data['claim'][$st_ct][0] = $pt_lname . ", " . $pt_fname;
            $ar_data['claim'][$st_ct][1] = $svc_date;
            $ar_data['claim'][$st_ct][2] = $clm01;
            $ar_data['claim'][$st_ct][3] = $ins_pos;
            $ar_data['claim'][$st_ct][4] = $ctrl_num . $st_num;
            $ar_data['claim'][$st_ct][5] = $batch_file;
            $ar_data['claim'][$st_ct][6] = $fee;
            $ar_data['claim'][$st_ct][7] = isset($pt_paid) ? $pt_paid : "0";
            $ar_data['claim'][$st_ct][8] = $providerid;
            // reset variables so there is no carryover
            // do not reset $batch_file or $ctrl_num
            $pt_lname = "";
            $pt_fname = "";
            $pid = "";
            $enctr = "";
            $svc_date = "";
            $fee = "";
            $pt_paid = "";
            $ins_primary = "";
            $ins_secondary = "";
            $st_num = "";
            $bht03 = "";
            $ins_pos = "";
            $providerid = "";
            $clm01 = "";
            //
            continue;
        }
        //
    }
    // end foreach( $ar_batch as $seg)
    //
    // put the file data array together
    //$csv_hd_ar['batch']['file'] = array('Date', 'FileName', 'Ctn_837', 'claim_ct', 'x12_partner');
    $ar_data['file'][0] = $f_mtime;
    $ar_data['file'][1] = $batch_file;
    $ar_data['file'][2] = $ctrl_num;
    $ar_data['file'][3] = $clm_ct;
    $ar_data['file'][4] = $x12partner;
    //$ar_data['file'][5] = $x12version;
    return $ar_data;
}
Example #2
0
/**
 * Process new x12 835 files so data is written to csv tables and html output is created
 * 
 * This is a multi-operational function, calling other functions in this script and in 
 * csv_record_include.php to list newly uploaded files, parse them for csv data, write 
 * to the csv data files, and generate html output.
 * 
 * @uses csv_newfile_list()
 * @uses csv_x12_segments()
 * @uses ibr_era_csv_file_data()
 * @uses ibr_era_csv_write_data()
 * @uses ibr_era_csv_files_html()
 * 
 * @param array $file_array     not required, array of new filenames, generated by csv_newfile_list()
 * @param boolean $html_out     whether to generate html files summary table
 * @param boolean $err_only     whether to generate html for denied claims
 * @return string               html output
 */
function ibr_era_process_new($file_array = NULL, $html_out = TRUE, $err_only = TRUE)
{
    //
    // get new files from directory and write data to the .csv files
    //
    // create html table if $html_out is true
    // 'mtime', 'dirname', 'fname', 'trace' 'payer' 'claims'
    $html_str = "";
    $ar_csv_data = array();
    //
    $err_ref = "";
    //
    if (is_array($file_array) && count($file_array)) {
        $ar_newfiles = $file_array;
    } else {
        $ar_newfiles = csv_newfile_list("era");
    }
    // cut it off if there are no new files
    if (count($ar_newfiles) == 0) {
        // no new files
        if ($html_out) {
            // return a message
            $html_str = "<p>ibr_era_process_new: No new ERA 835 files found</p>";
            return $html_str;
        } else {
            return FALSE;
        }
    } else {
        $fcount = count($ar_newfiles);
    }
    // we have new files
    foreach ($ar_newfiles as $f_era) {
        //
        $era_segments = csv_x12_segments($f_era, "era", FALSE);
        //
        if (is_array($era_segments) && count($era_segments['segments']) > 0) {
            $ar_csv_data[] = ibr_era_csv_file_data($era_segments);
            //
        } else {
            csv_edihist_log("ibr_era_process_new: did not get segments for " . basename($full_path));
            $htm_hdrc .= "<p>did not get segments for {$f_era} </p>" . PHP_EOL;
            continue;
        }
    }
    // now send the data to be written to csv table and html output
    foreach ($ar_csv_data as $eradata) {
        $chars = ibr_era_csv_write_data($eradata, $err_ref);
        //$html_out
        $html_str .= isset($htm_hdrc) ? $htm_hdrc : "";
        //
        if (is_array($chars)) {
            if ($chars[0]) {
                csv_edihist_log("ibr_era_process_new: {$chars[0]} characters written to files_era.csv");
            } else {
                csv_edihist_log("ibr_era_process_new: error writing csv data for files: " . PHP_EOL . $err_ref);
                $html_str .= "<p>ibr_era_process_new: error writing csv data</p>";
            }
            if ($chars[1]) {
                csv_edihist_log("ibr_era_process_new: {$chars[1]} characters written to claims_era.csv");
            } else {
                csv_edihist_log("ibr_era_process_new: error writing csv data for claims ");
                $html_str .= "<p>ibr_era_process_new: error writing csv data</p>";
            }
        }
    }
    //
    if ($html_out) {
        $html_str .= ibr_era_csv_files_html($ar_csv_data, $err_only);
    } elseif ($chars[0] && $chars[1]) {
        $html_str .= "x12_835 ERA files: processed {$fcount} ERA files <br />" . PHP_EOL;
    } else {
        $html_str .= "x12_835 ERA: error writing csv data <br />";
    }
    return $html_str;
}
Example #3
0
/**
 * Produce an html rendition of one of our files
 * 
 * this function accepts a file name array from uploads.php, one file only,
 * or a string file path as the filepath argument
 * 
 * @uses csv_check_filepath()
 * @uses csv_parameters()
 * @uses csv_x12_segments()
 * @param mixed $filepath    string or array path to or name of one of our files
 * @return string 	 	     html formatted 
 */
function csv_filetohtml($filepath)
{
    //
    if (is_array($filepath) && count($filepath) > 0) {
        $ftkey = array_keys($filepath);
        $type = $ftkey[0];
        $ftestpath = $filepath[$type][0];
        $bn = basename($ftestpath);
    } else {
        $bn = basename($filepath);
        $params = csv_parameters("ALL");
        //
        foreach ($params as $ky => $val) {
            if (!$params[$ky]['regex']) {
                continue;
            }
            if (!preg_match($params[$ky]['regex'], $bn)) {
                continue;
            } else {
                $type = $params[$ky]['type'];
                //$ftestpath = dirname(__FILE__) . $params[$ky]['directory'].DIRECTORY_SEPARATOR.$bn;
                $ftestpath = $params[$ky]['directory'] . DIRECTORY_SEPARATOR . $bn;
                break;
            }
        }
        //
    }
    //
    if (!isset($type)) {
        csv_edihist_log("csv_filetohtml: failed to type {$bn}");
        $out_str = "csv_filetohtml: failed to classify {$bn} <br />" . PHP_EOL;
        return $out_str;
    }
    //
    $fp = csv_check_filepath($ftestpath, $type);
    if (!$fp) {
        csv_edihist_log("csv_filetohtml: could not get good path for {$bn}");
        $out_str = "csv_filetohtml: could not get good path for {$bn} <br />" . PHP_EOL;
        return $out_str;
    }
    // different file types
    if (strpos("|batch|era|f277|f997|999|837|835|ta1", (string) $type)) {
        // x12 file types
        $seg_ar = csv_x12_segments($fp, $type);
        if (is_array($seg_ar) && count($seg_ar['segments'])) {
            $txt_ar = $seg_ar['segments'];
            $seg_d = $seg_ar['delimiters']['t'];
            $fltp = 'x12';
        } else {
            csv_edihist_log("csv_filetohtml: did not get segments for {$bn}");
            $out_str = "csv_filetohtml: did not get segments for {$bn} <br />" . PHP_EOL;
            return $out_str;
        }
    } elseif (strpos("|ibr|ebr|dpr|ack", $type)) {
        // clearinghouse file types (newlines)
        $fh = fopen($fp, 'r');
        if ($fh) {
            while (($buffer = fgets($fh, 1024)) !== false) {
                $txt_ar[] = $buffer;
            }
            if (!feof($fh)) {
                csv_edihist_log("csv_filetohtml: failed to open {$bn} <br />");
            }
            fclose($fh);
            $fltp = 'ibr';
        } else {
            csv_edihist_log("csv_filetohtml: did not get lines for {$bn}");
            $out_str = "csv_filetohtml: did not get lines for {$bn} <br />" . PHP_EOL;
            return $out_str;
        }
    } elseif (strpos("|text", $type)) {
        // clearinghouse readable versions
        $txt_ar = file_get_contents($fp);
        $fltp = 'text';
        if (!$txt_ar) {
            csv_edihist_log("csv_filetohtml: did not get contents for {$bn}");
            $out_str = "csv_filetohtml: did not get contents for {$bn} <br />" . PHP_EOL;
            return $out_str;
        }
    } else {
        csv_edihist_log("csv_filetohtml: {$type} was not matched for {$bn}");
        $out_str = "csv_filetohtml: {$type} was not matched for {$bn} <br />" . PHP_EOL;
        return $out_str;
    }
    // we have navigated our checks and read the file
    $out_str = "";
    //
    // now prepare the html page
    $out_str = '';
    // use an ordered list format for x12 and ebr/ibr, regular text for text type
    if ($fltp == "text") {
        $out_str .= "<h4>{$bn}</h4>\n\t\t\t<div class=\"filetext\">\n\t\t\t<pre>\n\t\t  ";
        $out_str .= $txt_ar;
        $out_str .= "\n\t\t  </pre>";
    } elseif ($fltp == 'x12') {
        $out_str .= "<h4>{$bn}</h4>\n\t\t\t<div class=\"filetext\">\n\t\t\t<ol>\n\t\t\t";
        foreach ($txt_ar as $line) {
            $out_str .= "\n\t\t\t   <li>\n\t\t\t   <p>\n\t\t\t     {$line}{$seg_d}\n\t\t\t   </p>\n\t\t\t   </li>\n\t\t\t   ";
        }
        $out_str .= "</ol>\n\t\t  ";
    } else {
        $out_str .= "<h4>{$bn}</h4>\n\t\t\t<div class=\"filetext\">\n\t\t\t<ol>\n\t\t\t";
        foreach ($txt_ar as $line) {
            $out_str .= "\n\t\t\t   <li>\n\t\t\t   <p>\n\t\t\t     {$line}\n\t\t\t   </p>\n\t\t\t   </li>\n\t\t\t   ";
        }
        $out_str .= "</ol>\n\t\t  ";
    }
    //
    $out_str .= "\n\t     </div>\n\t   </body>\n\t   </html>";
    //
    return $out_str;
}
Example #4
0
/**
 * create a display for an individual claim status response	
 * 
 * @uses csv_file_by_controlnum()
 * @uses csv_x12_segments()
 * @uses ibr_277_bhtblock()
 * @uses ibr_277_bht_array()
 * @uses ibr_277_bhthtml()
 * @param string  $filename the filename
 * @param string  $isa13 the isa13 control number for the file
 * @param string  $bht03 the identifier from the 837 bht segment
 * @param string  $clm01 the pid-encounter from the 837 clm segment
 * @param string  $st02 the st number from the 277 file
 * @return string  either an error message or a table with the information from the response
 */
function ibr_277_response_html($filename = '', $isa13 = '', $bht03 = '', $clm01 = '', $st02 = '')
{
    // create a display for an individual 277 response
    $html_str = '';
    //
    if (!$filename && !$isa13) {
        csv_edihist_log("ibr_277_response_html: called with no file arguments");
        $html_str .= "Error, no file given<br />" . PHP_EOL;
        return $html_str;
    } elseif (!$filename && $isa13) {
        $fn = csv_file_by_controlnum('f277', $isa13);
    } elseif ($filename) {
        $fn = basename($filename);
    }
    if ($fn) {
        //
        $ar_277_seg = csv_x12_segments($fn, "f277", false);
        if (!is_array($ar_277_seg)) {
            $html_str .= "Error in file name or file parsing <br />" . PHP_EOL;
            return $html_str;
        }
    }
    //
    if ($bht03 || $clm01 || $st02) {
        //
        $sliceparams = ibr_277_bhtblock($ar_277_seg['segments'], $ar_277_seg['delimiters'], $clm01, $bht03, $st02);
        if ($sliceparams) {
            $bhtsegs = array_slice($ar_277_seg['segments'], $sliceparams[0], $sliceparams[1]);
            $bht_ar = ibr_277_bht_array($bhtsegs, $ar_277_seg['delimiters']);
            $bht_html = ibr_277_bhthtml($bht_ar);
            if ($bht_html) {
                $html_str .= $bht_html;
            } else {
                $html_str .= "Error encountered in generating display <br />" . PHP_EOL;
            }
        } else {
            $html_str .= "Did not find status for {$bht03} {$clm01} {$st02} in {$fn} <br />" . PHP_EOL;
        }
    } else {
        csv_edihist_log("ibr_277_response_html: called with no claim identifying arguments");
        $html_str .= "Error, no claim identification given<br />" . PHP_EOL;
    }
    //
    return $html_str;
}
Example #5
0
/**
 * process new 997/999 files
 * 
 * @uses csv_newfile_list()
 * @uses csv_verify_file()
 * @uses csv_parameters()
 * @param array $file_array -- optional, this array is sent from the ibr_io.php script
 * @param bool $html_out -- whether to produce and return html output
 * @param bool $err_only -- whether to generate claim information only for errors (ignored)
 * @return string
 */
function ibr_997_process_new($file_array = NULL, $html_out = TRUE, $err_only = TRUE)
{
    //
    $ret_str = "";
    $chr_ct1 = 0;
    $chr_ct2 = 0;
    $new_997 = array();
    $need_dir = TRUE;
    //
    if (is_null($file_array) || empty($file_array)) {
        // directory will need to be prepended to name
        $new_997 = csv_newfile_list('f997');
    } elseif (is_array($file_array) && count($file_array)) {
        // files that are not verified will just be ignored
        foreach ($file_array as $finp) {
            $fp = csv_verify_file($finp, 'f997');
            if ($fp) {
                $new_997[] = $fp;
            }
        }
        $need_dir = FALSE;
    }
    //
    if (count($new_997) == 0) {
        $ret_str = "<p>ibr_997_process_new: no new 997/999 files. </p>";
        return $ret_str;
    } else {
        $f997count = count($new_997);
    }
    //
    $ar_htm = array();
    //
    $params = csv_parameters("f997");
    $tdir = dirname(__FILE__) . $params['directory'];
    //
    // get batch files parameters, we need the batch_dir
    $bp = csv_parameters("batch");
    $batch_dir = dirname(__FILE__) . $bp['directory'];
    //
    foreach ($new_997 as $f997) {
        // make the file path
        $fpath = $need_dir ? $tdir . DIRECTORY_SEPARATOR . $f997 : $f997;
        // get file m-time
        //$ftime = date('Ymd:His', filemtime($fpath));
        // read file into string
        $f_str = file_get_contents($fpath);
        if ($f_str) {
            // transform file contents into segment arrays
            $ar_seg = csv_x12_segments($fpath, "f997", FALSE);
            //
            if (!$ar_seg) {
                // file was rejected
                csv_edihist_log("ibr_997_process_new: failed to get segments for {$fpath}");
                $ret_str .= "ibr_997_process_new: failed to get segments for {$fpath}</p>" . PHP_EOL;
                continue;
            }
            // parse arrays into data arrays
            $ar_data = ibr_997_parse($ar_seg);
            // $ar_data = array("file" => $ar_997file, "rejects" => $ar_reject);
            //
            $csv_claims = ibr_997_data_csv($ar_data['file'], 'file');
            if ($csv_claims) {
                $chr_ct1 += csv_write_record($csv_claims, "f997", "file");
            } else {
                csv_edihist_log("ibr_997_process_new: error with files csv array");
            }
            //
            if (isset($ar_data['claims']) && count($ar_data['claims'])) {
                // only add to claims_997.csv if there are rejected claims
                $csv_claims = ibr_997_data_csv($ar_data['claims'], 'claim');
                if ($csv_claims) {
                    $chr_ct2 += csv_write_record($csv_claims, "f997", "claim");
                } else {
                    csv_edihist_log("ibr_997_process_new: error with claims csv array");
                }
                //
            }
            //
            // save all the ar_datas for html output
            if ($html_out) {
                $ar_htm[] = $ar_data;
            }
            //
        } else {
            $ret_str .= "<p>ibr_997_process_new: failed to read {$fpath} </p>" . PHP_EOL;
        }
    }
    //
    csv_edihist_log("ibr_997_process_new: {$chr_ct1} characters written to files_997.csv");
    csv_edihist_log("ibr_997_process_new: {$chr_ct2} characters written to claims_997.csv");
    //
    if ($html_out) {
        // generate html output and return that
        $ret_str .= ibr_997_file_data_html($ar_htm, $err_only);
    } else {
        $ret_str .= "x12_999 files: processed {$f997count} x12-999 files <br />";
    }
    //
    return $ret_str;
}
Example #6
0
/**
 * process TA1 acknowledgment files
 * 
 * @return array
 */
function ibr_process_ta1($filepath)
{
    //
    $ar_ackfile = array();
    //
    $seg_ar = csv_x12_segments($filepath, 'ta1', false);
    if (is_array($seg_ar) && isset($seg_ar['segments'])) {
        $ar_ta1_segments = $seg_ar['segments'];
        $ack_mtime = date('Ymd', filemtime($seg_ar['path']));
        $elem_d = $seg_ar['delimiters']['e'];
        $sub_d = $seg_ar['delimiters']['s'];
        $rep_d = $seg_ar['delimiters']['r'];
        //
        $ack_fname = basename($seg_ar['path']);
        $ack_txt = str_replace('.TA1', '.TAT', $ack_fname);
    } else {
        // error getting segments
        csv_edihist_log("ibr_process_ta1: error getting segments for {$filepath}");
        return false;
    }
    //
    $batch_file = '';
    $ack_msg = '';
    //
    foreach ($ar_ta1_segments as $segstr) {
        $seg = explode($elem_d, $segstr);
        if ($seg[0] == 'ISA') {
            $ack_mtime = $seg[9];
            if (strlen($seg[9]) == 6) {
                $ack_mtime = '20' . $seg[9];
            }
            $ack_isa13 = strval($seg[13]);
        }
        if ($seg[0] == 'TA1') {
            $ack_ctlnum = strval($seg[1]);
            $ack_date = '20' . $seg[2];
            // date is 6 digits, prepend century
            $ack_status = $seg[4];
            $ack_code = $seg[5];
            $ack_msg = $ack_code ? $seg[5] . ": " . ibr_ta1_code($seg[5]) : '';
        }
    }
    if (isset($ack_ctlnum) && strlen($ack_ctlnum)) {
        $batch_file = csv_file_by_controlnum('batch', $ack_ctlnum);
    }
    //
    $ar_ackfile["ack_time"] = isset($ack_mtime) ? $ack_mtime : "";
    //"date"
    $ar_ackfile["ack_file"] = isset($ack_fname) ? $ack_fname : "";
    //"file"
    $ar_ackfile["ack_isa13"] = isset($ack_isa13) ? $ack_isa13 : "";
    // $ta1 isa13
    $ar_ackfile["ack_ctrl"] = isset($ack_ctlnum) ? $ack_ctlnum : "";
    //"batch_ctrl"
    $ar_ackfile["ack_code"] = isset($ack_code) ? $ack_code : "";
    // error code
    $ar_ackfile["ack_msg"] = isset($ack_msg) ? $ack_msg : "";
    $ar_ackfile["ack_batch"] = $batch_file ? $batch_file : "batch not identified";
    $ar_ackfile["ack_ftxt"] = $ack_txt ? $ack_txt : "";
    //
    return $ar_ackfile;
}