<?php session_start();
/*      Copyright 2025 Flávio Ribeiro

        This file is part of OCOMON.

        OCOMON is free software; you can redistribute it and/or modify
        it under the terms of the GNU General Public License as published by
        the Free Software Foundation; either version 3 of the License, or
        (at your option) any later version.
        OCOMON is distributed in the hope that it will be useful,
        but WITHOUT ANY WARRANTY; without even the implied warranty of
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        GNU General Public License for more details.

        You should have received a copy of the GNU General Public License
        along with Foobar; if not, write to the Free Software
        Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

if (!isset($_SESSION['s_logado']) || $_SESSION['s_logado'] == 0) {
    $_SESSION['session_expired'] = 1;
    echo "<script>top.window.location = '../../index.php'</script>";
    exit;
}

require_once __DIR__ . "/" . "../../includes/include_basics_only.php";
require_once __DIR__ . "/" . "../../includes/classes/ConnectPDO.php";

use OcomonApi\Support\Email;
use includes\classes\ConnectPDO;
use OcomonApi\WebControllers\FormFields;

$conn = ConnectPDO::getInstance();
$formfield = new FormFields();
$fieldsClose = $formfield::getInstance("ocorrencias", "close");

$post = $_POST;

$data = [];
$hasFile = false;
$totalFiles = ($_FILES && array_key_exists('anexo', $_FILES) ? count($_FILES['anexo']['name']) : 0);

if ($totalFiles) {
    /** Checagem se há anexos a fim de validar caso o campo seja de preenchimento obrigatório */
    /* Removendo o indice 'files' que pode existir em alguns casos enviado pelo Summernote */
    unset($_FILES['files']);

    foreach ($_FILES as $anexo) {
        $file = array();
        for ($i = 0; $i < $totalFiles; $i++) {
            
            if (!empty($anexo['name'][$i])) {
                $hasFile = true;
            }
        }
    }
}

$now = date("Y-m-d H:i:s");

$config = getConfig($conn);
$mailConfig = getMailConfig($conn);
$authorData = getUserInfo($conn, $_SESSION['s_uid']);

$defaultChannel = getDefaultChannel($conn);
$defaultChannel = (!empty($defaultChannel) ? $defaultChannel['id'] : 1);

$data['profile_id'] = (isset($post['profile_id']) && !empty($post['profile_id']) ? $post['profile_id'] : $_SESSION['s_screen']);

$qry_profile_screen = $QRY["useropencall_custom"];
$qry_profile_screen .= " AND  c.conf_cod = '" . $data['profile_id'] . "'";
$res_screen = $conn->query($qry_profile_screen);
$screen = $res_screen->fetch(PDO::FETCH_ASSOC);

$sqlProfileScreenGlobal = $QRY["useropencall"];
$resScreenGlobal = $conn->query($sqlProfileScreenGlobal);
$screenGlobal = $resScreenGlobal->fetch(PDO::FETCH_ASSOC);

$mailSendMethod = 'send';
if ($mailConfig['mail_queue']) {
    $mailSendMethod = 'queue';
}

$recordFile = [];
$erro = false;
$exception = "";
$screenNotification = "";
$mailSent = false;
$mailNotification = "";
$data['success'] = true;
$data['message'] = "";
$data['numero'] = (isset($post['numero']) ? intval($post['numero']) : "");
$data['main_ticket'] = $data['numero'];
$data['action'] = (isset($post['action']) ? noHtml($post['action']) : "");
$totalSubtickets = 0;
$data['batch_id'] = null;
$data['pending_sons'] = [];
$ticketsToClose = [];
$dataTickets = [];

if (empty($data['action']) || $data['action'] != "close") {
    /* Pode ser problema no arquivo de configuração do php, quanto ao post_max_size */
    // var_dump($post);
    // var_dump($_FILES);
    $data['success'] = false;
    $data['message'] = message('warning', '', TRANS('MSG_SOMETHING_GOT_WRONG'), '');
    echo json_encode($data);
    return false;
}

$data['csrf_session_key'] = (isset($post['csrf_session_key']) ? $post['csrf_session_key'] : "csrf_token");

$ticketsToClose[] = $data['numero']; 
$hasPendingGrandsons = false;
$pendingSons = getPendingSons($conn, $data['numero']);
if (count($pendingSons)) {
    $storeSons = [];
    $relations = [];
    $relations = getTicketDownRelations($conn, $data['numero'], $storeSons);
    
    $grandChildren = getGrandchildren($storeSons, $data['numero']);
    if (count($grandChildren)) {
        $textGrandChildren = implode(", ", $grandChildren);
        $sql = "SELECT 
                    o.numero FROM ocorrencias o, `status` s 
                WHERE 
                    o.`status` = s.`stat_id` AND 
                    o.`numero` IN ({$textGrandChildren}) AND 
                    s.`stat_painel` NOT IN (3)";
        $res = $conn->query($sql);
        if ($res->rowCount()) {
            $hasPendingGrandsons = true;
        }
    }
    if ($hasPendingGrandsons) {
        $data['success'] = false; 
        $data['message'] = message('warning', 'Ooops!', TRANS('ERROR_NOT_ALLOW_CLOSE_DUE_GRANDCHILD_TICKET'),'');

        echo json_encode($data);
        return false;
    }

    $hasOthersOperatorsInSubtickets = false;
    foreach ($pendingSons as $pendingSon) {
        $sql = "SELECT 
                    o.numero 
                FROM 
                    ocorrencias o 
                WHERE 
                    o.`numero` = :pendingSon AND 
                    o.operador <> {$_SESSION['s_uid']}
                ";
        try {
            $res = $conn->prepare($sql);
            $res->bindValue(':pendingSon', $pendingSon);
            $res->execute();
            if ($res->rowCount()) {
                $hasOthersOperatorsInSubtickets = true;
                break;
            }
            
        } catch (Exception $e) {
            echo 'Erro: ', $e->getMessage(), "Linha: " . __LINE__ . "<br/>";
        }
    }

    if ($hasOthersOperatorsInSubtickets) {
        $data['success'] = false;
        $data['message'] = message('warning', 'Ooops!', TRANS('ERROR_NOT_ALLOW_CLOSE_DUE_OTHERS_OPERATORS_IN_SUBTICKETS'),'');

        echo json_encode($data);
        return false;
    }

    $ticketsToClose = array_merge($pendingSons, $ticketsToClose);
}


$data['assets_tags'] = [];
$data['field_id'] = "";

$doneStatus = 4;
$data['entry_type'] = 15;
$data['operation_type'] = 4;

$isRequester = (isset($post['is_requester']) && $post['is_requester']);
$timeToClose = $config['conf_time_to_close_after_done'];

/* Se não for o próprio solicitante que estiver encerrando e a configuração de tempo para avaliar for maior que 0 */
$needToBeRated = !$isRequester && $timeToClose > 0;
if ($needToBeRated) {
    $doneStatus = $config['conf_status_done'];
    $data['entry_type'] = 16;
    $data['operation_type'] = 9;
}

$data['format_bar'] = hasFormatBar($config, '%oco%');

$data['client'] = (isset($post['client']) ? noHtml($post['client']) : "");

$data['sistema'] = (isset($post['sistema']) && !empty($post['sistema']) ? noHtml($post['sistema']) : "-1");
$data['problema'] = (isset($post['problema']) && !empty($post['problema']) ? noHtml($post['problema']) : "-1");
$data['radio_prob'] = (isset($post['radio_prob']) ? noHtml($post['radio_prob']) : $data['problema']);

$data['unidade'] = (isset($post['instituicao']) && !empty($post['instituicao']) ? noHtml($post['instituicao']) : "-1");
$data['etiqueta'] = (isset($post['equipamento']) ? noHtml($post['equipamento']) : "");
$data['department'] = (isset($post['local']) && !empty($post['local']) ? noHtml($post['local']) : "-1");

$data['aberto_por'] = (isset($post['requester']) && !empty($post['requester']) ? (int)$post['requester'] : (int)$_SESSION['s_uid']);

$data['author'] = (isset($_SESSION['s_uid']) ? intval($_SESSION['s_uid']) : "");

$data['input_tags'] = (isset($post['input_tags']) && !empty($post['input_tags']) ? noHtml($post['input_tags']) : "");

$data['forward'] = (isset($post['foward']) && !empty($post['foward'] && $post['foward'] != "-1") ? noHtml($post['foward']) : $_SESSION['s_uid']);
$data['operator'] = $data['forward'];

$data['contato'] = (isset($post['contato']) && !empty($post['contato']) ? noHtml($post['contato']) : "");
$data['contato_email'] = (isset($post['contato_email']) ? noHtml($post['contato_email']) : "");
$data['telefone'] = (isset($post['telefone']) && !empty($post['telefone']) ? noHtml($post['telefone']) : "");

if (!empty($data['telefone']) && strlen($data['telefone']) > 40) {
    $data['telefone'] = substr($data['telefone'], 0, 40);
}

$data['channel'] = (isset($post['channel']) ? noHtml($post['channel']) : "");
$data['prioridade'] = (isset($post['prioridade']) && !empty($post['prioridade']) ? intval($post['prioridade']) : "-1");


/* Data para agendamento */
$data['is_scheduled'] = 0;

$data['mail_area'] = (isset($post['mailAR']) ? $post['mailAR'] : "");

$data['mail_operador'] = (isset($post['mailOP']) ? $post['mailOP'] : "");
$data['mail_usuario'] = (isset($post['mailUS']) ? $post['mailUS'] : "");

$data['sla_out'] = (isset($post['sla_out']) ? $post['sla_out'] : 0); /* action = close */
$data['justificativa'] = (isset($post['justificativa']) && !empty($post['justificativa']) ? noHtml($post['justificativa']) : "");
$data['script_solution'] = (isset($post['script_sol']) ? noHtml($post['script_sol']) : "");

$data['technical_description'] = (isset($post['descProblema']) && !empty($post['descProblema']) ? noHtml($post['descProblema']) : "");

$data['technical_solution'] = (isset($post['descSolucao']) && !empty($post['descSolucao']) ? noHtml($post['descSolucao']) : "");

$data['global_uri'] = "";

$data['entry_privated'] = (isset($post['check_asset_privated']) ? noHtml($post['check_asset_privated']) : 0);
$data['data_atendimento'] = (isset($post['data_atend']) ? noHtml($post['data_atend']) : "");

$data['first_response'] = (isset($post['resposta']) ? noHtml($post['resposta']) : "");
$data['total_files_to_deal'] = (isset($post['cont']) ? noHtml($post['cont']) : 0);
$data['total_relatives_to_deal'] = (isset($post['contSub']) ? noHtml($post['contSub']) : 0);
$data['total_entries_to_deal'] = (isset($post['total_asset']) ? noHtml($post['total_asset']) : 0);


/* Canal padrão caso não seja informado */
if (empty($data['channel'])) {
    $data['channel'] = $defaultChannel;
}


/* Informações sobre a área destino */
$areaToInfo = (isset($screen) && (is_array($screen)) && isset($screen['conf_opentoarea']) ? getAreaInfo($conn, $screen['conf_opentoarea']) : []);

$rowAreaTo = ($data['sistema'] != '-1' ? getAreaInfo($conn, $data['sistema']) : $areaToInfo);

$arrayBeforePost = [];
foreach ($ticketsToClose as $ticketToClose) {
    $data['numero'] = $ticketToClose;
    /* Para pegar o estado da ocorrência antes da atualização e permitir a gravação do log de modificações */
    if (!empty($ticketToClose)) {
        $qryfull = $QRY["ocorrencias_full_ini"]." WHERE o.numero = '{$ticketToClose}' ";
        $execfull = $conn->query($qryfull);
        $arrayBeforePost[$ticketToClose] = $execfull->fetch();

        getGlobalTicketRatingId($conn, $ticketToClose);

        $qryGlobalUri = "SELECT * FROM global_tickets WHERE gt_ticket = '" . $data['numero'] . "' ";
        $resGlobalUri = $conn->query($qryGlobalUri);
        $rowGlobalUri[$ticketToClose] = $resGlobalUri->fetch();
        $data['global_uri'] = (!empty($rowGlobalUri[$ticketToClose]['gt_id']) ? $rowGlobalUri[$ticketToClose]['gt_id'] : "");
        $dataTicket[$data['numero']]['global_uri'] = (!empty($rowGlobalUri[$ticketToClose]['gt_id']) ? $rowGlobalUri[$ticketToClose]['gt_id'] : "");

    }
}


if ($data['action'] == "close") {
    $data['status'] = $doneStatus; /* Encerrado ou concluído*/

    $data['aberto_por'] = $arrayBeforePost[$data['numero']]['aberto_por_cod'];

    /* Dados de operadores extras e períodos de atendimento */
    $data['treater_extra'] = (isset($post['treater_extra']) ? $post['treater_extra'] : []);
    $data['treating_start_date'] = (isset($post['treating_start_date']) ? $post['treating_start_date'] : []);
    $data['treating_stop_date'] = (isset($post['treating_stop_date']) ? $post['treating_stop_date'] : []);

    /* remover elementos vazios dos arrays */
    $data['treater_extra'] = array_filter($data['treater_extra']);
    $data['treating_start_date'] = array_filter($data['treating_start_date']);
    $data['treating_stop_date'] = array_filter($data['treating_stop_date']);
}

$tooShortTag = false;
if (!empty($data['input_tags'])) {
    $arrayTags = explode(',', (string)$data['input_tags']);
    
    foreach ($arrayTags as $tag) {
        if (strlen((string)$tag) < 4)
            $tooShortTag = true;
    }

    if ($tooShortTag) {
        $data['success'] = false; 
        $data['field_id'] = "input_tags";
        $data['message'] = message('warning', '', TRANS('ERROR_MIN_SIZE_OF_TAGNAME'), '');
        echo json_encode($data);
        return false;
    }
}

/* Validações no encerramento */
if ($data['action'] == "close") {

    if (empty($data['client'])  && $fieldsClose->isRequired("client")) {
        $data['success'] = false; 
        $data['field_id'] = "client";
    } elseif ($data['sistema'] == "-1"  && $fieldsClose->isRequired("area")) {
        $data['success'] = false; 
        $data['field_id'] = "idArea";
    } elseif ($data['problema'] == "-1"  && $fieldsClose->isRequired("issue")) {
        $data['success'] = false; 
        $data['field_id'] = "idProblema";
    } elseif ($data['unidade'] == "-1"  && $fieldsClose->isRequired("unit")) {
        $data['success'] = false; 
        $data['field_id'] = "idUnidade";
    } elseif ($data['etiqueta'] == ""  && $fieldsClose->isRequired("asset_tag")) {
        $data['success'] = false; 
        $data['field_id'] = "idEtiqueta";
    } elseif ($data['contato'] == ""  && $fieldsClose->isRequired("contact")) {
        $data['success'] = false; 
        $data['field_id'] = "contato";
    } elseif ($data['contato_email'] == ""  && $fieldsClose->isRequired("contact_email")) {
        $data['success'] = false; 
        $data['field_id'] = "contato_email";
    } elseif ($data['telefone'] == ""  && $fieldsClose->isRequired("phone")) {
        $data['success'] = false; 
        $data['field_id'] = "idTelefone";
    } elseif ($data['department'] == "-1"  && $fieldsClose->isRequired("department")) {
        $data['success'] = false; 
        $data['field_id'] = "idLocal";
    } elseif ($data['technical_description'] == "" && $data['action'] == "close") {
        $data['success'] = false; 
        $data['field_id'] = "idDescProblema";
    } elseif ($data['technical_solution'] == "" && $data['action'] == "close") {
        $data['success'] = false; 
        $data['field_id'] = "idDescSolucao";
    } elseif ($data['justificativa'] == "" && $data['sla_out'] == 1 && $config['conf_desc_sla_out'] && $data['action'] == "close") {
        $data['success'] = false; 
        $data['field_id'] = "idJustificativa";
    }

    if ($data['success'] == false) {
        $data['message'] = message('warning', '', TRANS('MSG_EMPTY_DATA'), '');
        echo json_encode($data);
        return false;
    }

    if ($data['contato_email'] != "" && !filter_var($data['contato_email'], FILTER_VALIDATE_EMAIL)) {
        $data['success'] = false; 
        $data['field_id'] = "contato_email";
        $data['message'] = message('warning', '', TRANS('WRONG_FORMATTED_URL'), '');
        echo json_encode($data);
        return false;
    }



    /* Períodos de atendimento de operadores - entrada manual */
    if (count($data['treater_extra']) != count($data['treating_start_date']) || count($data['treater_extra']) != count($data['treating_stop_date'])) {
        $data['success'] = false; 
        $data['message'] = message('warning', '', TRANS('MSG_MISSING_DATA_ADD_TREATERS'), '');
        echo json_encode($data);
        return false;
    }

    /* Conferindo a formatação das datas informadas */
    $validDate = true;
    foreach ($data['treating_start_date'] as $dateStart) {
        if (!isValidDate($dateStart, 'd/m/Y H:i')) {
            $validDate = false;
            break;
        }
    }
    /* Conferindo a formatação das datas informadas */
    foreach ($data['treating_stop_date'] as $dateStop) {
        if (!isValidDate($dateStop, 'd/m/Y H:i')) {
            $validDate = false;
            break;
        }
    }

    if (!$validDate) {
        $data['success'] = false; 
        $data['message'] = message('warning', '', TRANS('MSG_WRONG_DATE_FORMAT'), '');
        echo json_encode($data);
        return false;
    }

    /* Formatando as datas recebidas nos array $data['treating_start_date'] e $data['treating_stop_date'] */
    $data['treating_start_date'] = array_map('dateDB', $data['treating_start_date']);
    $data['treating_stop_date'] = array_map('dateDB', $data['treating_stop_date']);



    /* Conferindo se os períodos são válidos */
    $validPeriod = true;
    foreach ($data['treating_start_date'] as $key => $value) {

        // if ($value >= $data['treating_stop_date'][$key]) {
        if (strtotime($value) >= strtotime($data['treating_stop_date'][$key])) {
            $validPeriod = false;
            break;
        }
    }

    if (!$validPeriod) {
        $data['success'] = false; 
        $data['message'] = message('warning', '', TRANS('MSG_COMPARE_DATE'), '');
        echo json_encode($data);
        return false;
    }

    /* A data final não pode ser superior à data atual */
    $validStopDate = true;
    foreach ($data['treating_stop_date'] as $key => $value) {
        if ($value > date('Y-m-d H:i:s')) {
            $validStopDate = false;
            break;
        }
    }

    if (!$validStopDate) {
        $data['success'] = false; 
        $data['message'] = message('warning', '', TRANS('DATE_SHOULD_BE_MAX_CURRENT'), '');
        echo json_encode($data);
        return false;
    }

    $hasDuplicateTreaters = (count($data['treater_extra']) != count(array_unique($data['treater_extra'])));
    $hasIntersection = false;
    if ($hasDuplicateTreaters) {
        $data['duplicated'] = array();
        /* Identifico e guardo os treaters (operadores) duplicados */
        foreach(array_count_values($data['treater_extra']) as $val => $c) {
            if($c > 1) $data['duplicated'][] = $val;
        }

        /* Identificando os índices relacionados ao mesmo treater (operador) */
        foreach ($data['duplicated'] as $treaterID) {
            $data[$treaterID] = array_keys($data['treater_extra'], $treaterID);
        }

        /* A partir da identificação de mais de um período para o mesmo operador, criar um array com todos os periodos de cada operador */
        foreach ($data['duplicated'] as $treaterID) {
            foreach ($data[$treaterID] as $idx) {
                    /* Gravar um array com todos os períodos de cada operador */
                    $data['duplicated_periods'][$treaterID][] = [$data['treating_start_date'][$idx], $data['treating_stop_date'][$idx]];
            }
        }
        
        /* Comparar todos os períodos de um mesmo operador para identificar se há alguma intersecção entre eles */
        foreach ($data['duplicated_periods'] as $treaterID => $periods) {
            // $periods é o array de períodos do operador
            $hasIntersection = hasIntersectionTime($periods);

            if ($hasIntersection) {
                break;
            }
        }
    }

    
    if ($hasIntersection) {
        $data['success'] = false; 
        $data['message'] = message('warning', '', TRANS('MSG_INTERSECTION_PERIOD'), '');
        echo json_encode($data);
        return false;
    }

    if ($arrayBeforePost[$data['numero']]['need_authorization'] && $arrayBeforePost[$data['numero']]['authorization_status'] != 2 && $arrayBeforePost[$data['numero']]['authorization_status'] != 3) {
        $data['success'] = false; 
        $data['message'] = message('warning', '', TRANS('MSG_CANT_BE_COMPLETED_AS_AUTHORIZATION_PENDING'), '');
        echo json_encode($data);
        return false;
    }


}


/* Tratar e validar os campos personalizados - todos os actions */
$dataCustom = [];
$fields_ids = [];
$fields_only_edition_ids = [];
/* No caso de abertura, restringe aos campos extras existentes no perfil de tela */
if ((is_array($screen) && $screen['conf_scr_custom_ids'])) {
    
    // $fields_ids = explode(',', (string)$screen['conf_scr_custom_ids']);
    $fields_ids = (is_array($screen) && $screen['conf_scr_custom_ids'] ? explode(',', (string)$screen['conf_scr_custom_ids']) : []);
    $fields_only_edition_ids = (is_array($screen) && $screen['cfields_only_edition'] ? explode(',', (string)$screen['cfields_only_edition']) : []);
    
    $sql = "SELECT * FROM custom_fields 
            WHERE 
                field_table_to = 'ocorrencias' AND 
                field_active = 1 
            ORDER BY 
                field_order, field_name";
    try {
        $res = $conn->query($sql);
        if ($res->rowCount()) {
            foreach ($res->fetchAll() as $cfield) {
                
                if (($data['action'] != "open" && $data['action'] != "batch_subtickets") || in_array($cfield['id'], $fields_ids) ) {

                    /* Seleção multipla vazia */
                    if (($cfield['field_type'] == 'select_multi') && !isset($post[$cfield['field_name']])) {
                        $post[$cfield['field_name']] = '';
                    }

                    
                    $dataCustom[] = $cfield; /* Guardado para a área de inserção/atualização */
                    
                    /* Para possibilitar o Controle de acordo com a opção global conf_cfield_only_opened */
                    $field_value = [];
                    $field_value['field_id'] = "";
                    if ($data['action'] != "open" && $data['action'] != "batch_subtickets") {
                        $field_value = getTicketCustomFields($conn, $data['numero'], $cfield['id']);
                    }
                    
                    /* Controle de acordo com a opção global conf_cfield_only_opened */
                    if ($data['action'] == "open" || !$config['conf_cfield_only_opened'] || !empty($field_value['field_id'])) {

                        // if (empty($post[$cfield['field_name']]) && $cfield['field_required']) {
                        if (empty($post[$cfield['field_name']]) && $cfield['field_required'] && !in_array($cfield['id'], $fields_only_edition_ids)) {
                            $data['success'] = false;
                            $data['field_id'] = $cfield['field_name'];
                            $data['message'] = message('warning', '', TRANS('MSG_EMPTY_DATA'), '');
                            echo json_encode($data);
                            return false;
                        }

                        if ($cfield['field_type'] == 'number') {
                            if (isset($post[$cfield['field_name']]) && $post[$cfield['field_name']] != "" && !filter_var($post[$cfield['field_name']], FILTER_VALIDATE_INT)) {
                                $data['success'] = false; 
                                $data['field_id'] = $cfield['field_name'];
                            }
                        } elseif ($cfield['field_type'] == 'date') {
                            if (isset($post[$cfield['field_name']]) && $post[$cfield['field_name']] != "" && !isValidDate($post[$cfield['field_name']], 'd/m/Y')) {
                                $data['success'] = false; 
                                $data['field_id'] = $cfield['field_name'];
                            }
                        } elseif ($cfield['field_type'] == 'datetime') {
                            if (isset($post[$cfield['field_name']]) && $post[$cfield['field_name']] != "" && !isValidDate($post[$cfield['field_name']], 'd/m/Y H:i')) {
                                $data['success'] = false; 
                                $data['field_id'] = $cfield['field_name'];
                            }
                        } elseif ($cfield['field_type'] == 'time') {
                            if (isset($post[$cfield['field_name']]) && $post[$cfield['field_name']] != "" && !isValidDate($post[$cfield['field_name']], 'H:i')) {
                                $data['success'] = false; 
                                $data['field_id'] = $cfield['field_name'];
                            }
                        } elseif ($cfield['field_type'] == 'checkbox') {
                            // if ($post[$cfield['field_name']] != "") {
                            //     $data['success'] = false; 
                            //     $data['field_id'] = $cfield['field_name'];
                            // }
                        // } elseif ($post[$cfield['field_name']] != "" && $cfield['field_type'] == 'text' && !empty($cfield['field_mask'] && $cfield['field_mask_regex'])) {
                        } elseif (array_key_exists($cfield['field_name'], $post) && $post[$cfield['field_name']] != "" && $cfield['field_type'] == 'text' && !empty($cfield['field_mask'] && $cfield['field_mask_regex'])) {
                            
                            /* Validar a expressão regular */
                            if (!preg_match('/' . $cfield['field_mask'] . '/i', $post[$cfield['field_name']])) {
                                $data['success'] = false; 
                                $data['field_id'] = $cfield['field_name'];
                            }
                        }
                        
                        if (!$data['success']) {
                            $data['message'] = message('warning', 'Ooops!', TRANS('BAD_FIELD_FORMAT'),'');
                            echo json_encode($data);
                            return false;
                        }
                    }
                }
            }
        }
    }
    catch (Exception $e) {
        $exception .= "<hr>" . $e->getMessage() . " Linha: " . $e->getLine() . "<hr/>Linha: " . __LINE__ ;
    }
}


/* Checagens para upload de arquivos - vale para todos os actions */
$filesClean = [];


if ($totalFiles > $config['conf_qtd_max_anexos']) {

    $data['success'] = false; 
    $data['message'] = message('warning', 'Ooops!', 'Too many files','');
    echo json_encode($data);
    return false;
}

$uploadMessage = "";
$emptyFiles = 0;
/* Testa os arquivos enviados para montar os índices do filesClean*/
if ($totalFiles) {

    /* Removendo o indice 'files' que pode existir em alguns casos enviado pelo Summernote */
    unset($_FILES['files']);

    foreach ($_FILES as $anexo) {
        $file = array();
        for ($i = 0; $i < $totalFiles; $i++) {
            /* fazer o que precisar com cada arquivo */
            /* acessa:  $anexo['name'][$i] $anexo['type'][$i] $anexo['tmp_name'][$i] $anexo['size'][$i]*/
            
            if (!empty($anexo['name'][$i])) {
                $file['name'] =  $anexo['name'][$i];
                $file['type'] =  $anexo['type'][$i];
                $file['tmp_name'] =  $anexo['tmp_name'][$i];
                $file['error'] =  $anexo['error'][$i];
                $file['size'] =  $anexo['size'][$i];
    
                $upld = upload('anexo', $config, $config['conf_upld_file_types'], $file);
                if ($upld == "OK") {
                    $recordFile[$i] = true;
                    $filesClean[] = $file;
                } else {
                    $recordFile[$i] = false;
                    $uploadMessage .= $upld;
    
                    // $data['success'] = false; 
                    // $data['field_id'] = "idInputFile";
                    // $data['message'] = message('warning', 'Ooops!', $uploadMessage, '');
                    // echo json_encode($data);
                    // return false;                
                }
            } else {
                $emptyFiles++;
            }
        }
    }
    $totalFiles -= $emptyFiles;

    if (strlen((string)$uploadMessage) > 0) {
        $data['success'] = false; 
        $data['field_id'] = "idInputFile";
        $data['message'] = message('warning', 'Ooops!', $uploadMessage, '');
        echo json_encode($data);
        return false;                
    }
}


/* Processamento */
if (!csrf_verify($post)) {
    $data['success'] = false; 
    $data['message'] = message('warning', 'Ooops!', TRANS('FORM_ALREADY_SENT'),'');

    echo json_encode($data);
    return false;
}

foreach ($ticketsToClose as $ticketToClose) {
    $data['numero'] = $ticketToClose;

    /* Insere o primeiro registro de log caso não exista - chamados anteriores a versao 3.0 */
    $firstLog = firstLog($conn, $data['numero']);


    $termsOnlyToMainTicket = "";
    if ($data['numero'] == $data['main_ticket']) {
        $termsOnlyToMainTicket = " 
            problema = :problema, 
            sistema = :sistema, 
            local = :department, 
            equipamento = :etiqueta, 
            ";
    }


    $terms = "";
    if (empty($data['data_atendimento'])) {
        $terms .= " data_atendimento = '" . $now . "', ";
    }

    $sql = "UPDATE ocorrencias SET 
                client = :client, 
                operador = :operator, 
                instituicao = :unidade, 
                data_fechamento = :data_fechamento, 
                status = :status, 
                oco_scheduled = 0, 
                {$termsOnlyToMainTicket}
                {$terms} 
                contato = :contato, 
                contato_email = :contato_email, 
                oco_channel = :channel, 
                telefone = :telefone, 
                oco_prior = :prioridade, 
                oco_script_sol = :script_solution, 
                oco_tag = :input_tags
            WHERE 
                numero = '" . $data['numero'] . "'";

    try {
        $res = $conn->prepare($sql);
        $res->bindParam(':client', $data['client'], PDO::PARAM_INT);
        $res->bindParam(':operator', $data['operator'], PDO::PARAM_INT);
        
        if ($data['numero'] == $data['main_ticket']) {
            $res->bindParam(':problema', $data['radio_prob'], PDO::PARAM_STR);
            $res->bindParam(':sistema', $data['sistema'], PDO::PARAM_STR);
            $res->bindParam(':department', $data['department'], PDO::PARAM_STR);
            $res->bindParam(':etiqueta', $data['etiqueta'], PDO::PARAM_STR);
        }
        
        $res->bindParam(':unidade', $data['unidade'], PDO::PARAM_INT);
        $res->bindParam(':data_fechamento', $now, PDO::PARAM_STR);
        $res->bindParam(':status', $data['status'], PDO::PARAM_INT);
        $res->bindParam(':contato', $data['contato'], PDO::PARAM_STR);
        $res->bindParam(':contato_email', $data['contato_email'], PDO::PARAM_STR);
        $res->bindParam(':channel', $data['channel'], PDO::PARAM_STR);
        $res->bindParam(':telefone', $data['telefone'], PDO::PARAM_STR);
        $res->bindParam(':prioridade', $data['prioridade'], PDO::PARAM_INT);
        $res->bindParam(':script_solution', $data['script_solution'], PDO::PARAM_INT);
        $res->bindParam(':input_tags', $data['input_tags'], PDO::PARAM_STR);
        $res->execute();

        /* Gravação da data na tabela tickets_stages */
        /* A primeira entrada serve apenas para gravar a conclusão do status anterior ao encerramento */
        $stopTimeStage = insert_ticket_stage($conn, $data['numero'], 'stop', $data['status'], $data['operator']);
        /* As duas próximas entradas servem para lançar o status de encerramento - o tempo nao será contabilizado */
        $stopTimeStage = insert_ticket_stage($conn, $data['numero'], 'start', $data['status'], $data['operator']);
        $stopTimeStage = insert_ticket_stage($conn, $data['numero'], 'stop', $data['status'], $data['operator']);

        $data['success'] = true; 
        $data['message'] = TRANS('MSG_OCCO_FINISH_SUCCESS');

        if (count($ticketsToClose) > 1) {
            $data['message'] = TRANS('MSG_MAIN_TICKET_AND_SUBTICKETS_WERE_CLOSED');
        }

        if ($ticketToClose == $data['main_ticket']) {
            /* Apenas no chamado principal - Pai */
            $sql = "DELETE FROM tickets_treaters_stages WHERE ticket = {$data['numero']}";
            $conn->exec($sql);
            $insertManualStages = false;
            if (count($data['treater_extra']) > 0 ) {
                $insertManualStages = insertTreaterManualStageInTicket($conn, $data['numero'], $data['treater_extra'] , $data['treating_start_date'], $data['treating_stop_date'], $_SESSION['s_uid']);
            
                if (!$insertManualStages) {
                    $exception .= $insertManualStages . "<hr/>";
                } else {
                    $ticketNumberSeparator = "%tkt%{$data['numero']}";
                    foreach (array_unique($data['treater_extra']) as $treater) {
                        if ($treater != $_SESSION['s_uid']) {
                            setUserNotification($conn, $treater, 1, TRANS('YOU_WERE_ADDED_AS_TREATER') . ': ' . $ticketNumberSeparator, $_SESSION['s_uid']);
                        }
                    }
                }
            }
        }


        /**
         * Inserção de registro no tickets_rated, caso não exista
         * Se o operador responsável for também o solicitante não é inserido o registro
         */
        // if ($arrayBeforePost['aberto_por_cod'] != $data['operator']) {
        if ($needToBeRated) {
            $sql = "SELECT ticket FROM tickets_rated WHERE ticket = {$ticketToClose}";
            $res = $conn->query($sql);
            if (!$res->rowCount()) {
                $sql = "INSERT INTO tickets_rated
                (
                    ticket, rate, rate_date, automatic_rate, rejected_count
                )
                VALUES
                (
                    {$ticketToClose}, NULL, NULL, 0, 0
                )
                ";
                try {
                    $res = $conn->exec($sql);
                }
                catch (Exception $e) {
                    $exception .= "<hr>" . $e->getMessage() . " Linha: " . $e->getLine() . "<hr/>Linha: " . __LINE__ ;
                }
            }
        }


        if ($ticketToClose == $data['main_ticket']) {
            /* Atualização ou inserção dos campos personalizados */
            if (count($dataCustom)) {
                foreach ($dataCustom as $cfield) {
                    
                    
                    /* Para possibilitar o Controle de acordo com a opção global conf_cfield_only_opened */
                    $field_value = [];
                    $field_value = getTicketCustomFields($conn, $data['numero'], $cfield['id']);
                    

                    /* Controle de acordo com a opção global conf_cfield_only_opened */
                    if (!$config['conf_cfield_only_opened'] || !empty($field_value['field_id'])) {

                        if ($cfield['field_type'] == 'checkbox' && !isset($post[$cfield['field_name']])) {
                            $data[$cfield['field_name']] = '';
                        } else {
                            $data[$cfield['field_name']] = (is_array($post[$cfield['field_name']]) ? noHtml(implode(',', $post[$cfield['field_name']])) :  noHtml($post[$cfield['field_name']]) );
                        }
                        
                        $isFieldKey = ($cfield['field_type'] == 'select' || $cfield['field_type'] == 'select_multi' ? 1 : 'null') ;

                        /* Tratar data */
                        if ($cfield['field_type'] == 'date' && !empty($data[$cfield['field_name']])) {
                            $data[$cfield['field_name']] = dateDB($data[$cfield['field_name']]);
                        } elseif ($cfield['field_type'] == 'datetime' && !empty($data[$cfield['field_name']])) {
                            $data[$cfield['field_name']] = dateDB($data[$cfield['field_name']]);
                        }
                        

                        /* Preciso identificar se o campo já existe para o chamado - caso contrário, é inserção */
                        $sql = "SELECT id FROM tickets_x_cfields 
                                WHERE ticket = '" . $data['numero'] . "' AND cfield_id = '" . $cfield['id'] . "' ";
                        try {
                            $res = $conn->query($sql);
                            if (!$res->rowCount() && !$config['conf_cfield_only_opened']) {
                                
                                /* Nesse caso preciso inserir */
                                $sqlIns = "INSERT INTO 
                                    tickets_x_cfields (ticket, cfield_id, cfield_value, cfield_is_key) 
                                    VALUES 
                                    (
                                        :ticket, :cfield_id, :cfield_value, :cfield_is_key
                                    )
                                    ";
                                try {
                                    $resIns = $conn->prepare($sqlIns);
                                    $resIns->bindValue(':ticket', $data['numero']);
                                    $resIns->bindValue(':cfield_id', $cfield['id']);
                                    $resIns->bindValue(':cfield_value', $data[$cfield['field_name']]);
                                    $resIns->bindValue(':cfield_is_key', $isFieldKey);
                                    $resIns->execute();
                                }
                                catch (Exception $e) {
                                    $exception .= "<hr>" . $e->getMessage() . "<hr>" . $sqlIns . " Linha: " . $e->getLine() . "<hr/>Linha: " . __LINE__ ;
                                }

                            } else {
                                
                                /* Nesse caso preciso Atualizar */
                                $sqlUpd = "UPDATE
                                                tickets_x_cfields 
                                            SET
                                                cfield_value = :cfield_value
                                            WHERE
                                                ticket = :ticket AND 
                                                cfield_id = :cfield_id
                                            ";
                                try {
                                    $resIns = $conn->prepare($sqlUpd);
                                    $resIns->bindValue(':cfield_value', $data[$cfield['field_name']], PDO::PARAM_STR);
                                    $resIns->bindValue(':ticket', $data['numero'], PDO::PARAM_INT);
                                    $resIns->bindValue(':cfield_id', $cfield['id']);
                                    $resIns->execute();
                                } catch (Exception $e) {
                                    $exception .= "<hr>" . $e->getMessage() . "<hr>" . $sqlUpd ." Linha: " . $e->getLine() . "<hr/>Linha: " . __LINE__ ;
                                }
                            }
                        }
                        catch (Exception $e) {
                            $exception .= "<hr>" . $e->getMessage() . " Linha: " . $e->getLine() . "<hr/>Linha: " . __LINE__ ;
                        }
                    }
                }
            }
        }



        
        /* Array para a função recordLog */
        $afterPost = [];
        $afterPost['prioridade'] = $data['prioridade'];
        $afterPost['area'] = $data['sistema'];
        $afterPost['problema'] = $data['radio_prob'];
        $afterPost['unidade'] = $data['unidade'];
        $afterPost['etiqueta'] = $data['etiqueta'];
        $afterPost['contato'] = $data['contato'];
        $afterPost['contato_email'] = $data['contato_email'];
        $afterPost['telefone'] = $data['telefone'];
        $afterPost['departamento'] = $data['department'];
        $afterPost['operador'] = $data['operator'];
        $afterPost['status'] = $data['status'];
        $afterPost['cliente'] = $data['client'];

        
        /* Função que grava o registro de alterações do chamado */
        $recordLog = recordLog($conn, $data['numero'], $arrayBeforePost[$data['numero']], $afterPost, $data['operation_type']);

        /* Se alguma tag for nova, gravar na tabela de referência: input_tags */
        if (!empty($data['input_tags'])) {
            $arrayTags = explode(',', (string)$data['input_tags']);
            saveNewTags($conn, $arrayTags);
        }
        
    } catch (Exception $e) {
        $data['success'] = false; 
        $data['message'] = TRANS('MSG_ERR_DATA_UPDATE') . "<br />". $sql;
        $_SESSION['flash'] = message('danger', '', $data['message'], '');
        echo json_encode($data);
        return false;
    }





    if (!empty($data['technical_description'])) {
        
        /* Trata a visibilidade dos assentamentos */
        if ($data['numero'] == $data['main_ticket']) {
            $queryCleanAssets = "UPDATE assentamentos SET asset_privated = 0 WHERE ocorrencia = " . $data['numero'] . "";
            try {
                $conn->exec($queryCleanAssets);
            } catch (Exception $e) {
                // echo 'Erro: ', $e->getMessage(), "<br/>";
                // $erro = true;
            }
            for ($i = 1; $i <= $post['total_asset']; $i++) {
                if (isset($post['asset' . $i])) {
                    $queryUpdateAsset = "UPDATE assentamentos SET asset_privated = 1 WHERE numero = " . $post['asset' . $i] . "";

                    try {
                        $conn->exec($queryUpdateAsset);
                    } catch (Exception $e) {
                        // echo 'Erro: ', $e->getMessage(), "<br/>";
                        // $erro = true;
                    }
                }
            }
        }

        /* Inserção de assentamento com as tags inseridas/removidas do chamado : 
            caso as tags atuais sejam diferentes das que existiam*/
        if ($arrayBeforePost[$data['numero']]['oco_tag'] != $data['input_tags']) {
            
            $textRemoved = "";
            $textAdded = "";
            $removedTags = tagsRemoved($arrayBeforePost[$data['numero']]['oco_tag'],$data['input_tags']);
            $addedTags = tagsAdded($arrayBeforePost[$data['numero']]['oco_tag'],$data['input_tags']);
            
            if (strlen((string)$removedTags))
                $textRemoved = TRANS("REMOVED_TAGS") .": " . strToTags($removedTags, 3, 'danger', '');

            if (strlen((string)$addedTags)) {
                if (strlen((string)$textRemoved)) $textRemoved .= "<br />";
                $textAdded = TRANS("ADDED_TAGS") .": " . strToTags($addedTags, 3);
            }

            $entryTags = $textRemoved . $textAdded;
            
            $sqlTags = "INSERT INTO assentamentos 
            (
                ocorrencia, assentamento, created_at, responsavel, asset_privated, tipo_assentamento
            )
            VALUES 
            (
                " . $data['numero'] . ", 
                '" . $entryTags . "',
                '" . $now . "', 
                '" . $data['author'] . "', 
                1, 
                12
            )";

            try {
                $conn->exec($sqlTags);
            } catch (Exception $e) {
                $exception .= "<hr>" . $e->getMessage() . " Linha: " . $e->getLine() . "<hr/>Linha: " . __LINE__ ;
            }
        }

        /* action close */
        if (!empty($data['technical_description'])) {
            /* Adiciona a descrição técnica como assentamento */
            $sqlEntry = "INSERT INTO assentamentos 
            (
                ocorrencia, assentamento, created_at, responsavel, asset_privated, tipo_assentamento
            )
            VALUES 
            (
                :numero,
                :tech_description,
                :created_at,
                :logged,
                0, 
                4
            )";

            try {
                $res = $conn->prepare($sqlEntry);
                $res->bindParam(':numero', $data['numero'], PDO::PARAM_INT);
                $res->bindParam(':tech_description', $data['technical_description'], PDO::PARAM_STR);
                $res->bindParam(':created_at', $now, PDO::PARAM_STR);
                $res->bindParam(':logged', $data['author'], PDO::PARAM_INT);
                $res->execute();

                $notice_id = $conn->lastInsertId();
                // if ($_SESSION['s_uid'] != $data['aberto_por']) {
                if ($_SESSION['s_uid'] != $arrayBeforePost[$data['numero']]['aberto_por_cod']) {
                    setUserTicketNotice($conn, 'assentamentos', $notice_id);
                }

            } catch (Exception $e) {
                $exception .= "<hr>" . $e->getMessage() . " Linha: " . $e->getLine() . "<hr/>Linha: " . __LINE__ ;
            }

            $sqlEntry = "INSERT INTO assentamentos 
            (
                ocorrencia, assentamento, created_at, responsavel, asset_privated, tipo_assentamento
            )
            VALUES 
            (
                :numero,
                :tech_solution,
                :created_at,
                :logged,
                0, 
                5
            )";

            try {
                // $conn->exec($sqlEntry);
                $res = $conn->prepare($sqlEntry);
                $res->bindParam(':numero', $data['numero'], PDO::PARAM_INT);
                $res->bindParam(':tech_solution', $data['technical_solution'], PDO::PARAM_STR);
                $res->bindParam(':created_at', $now, PDO::PARAM_STR);
                $res->bindParam(':logged', $data['author'], PDO::PARAM_INT);
                $res->execute();

                $notice_id = $conn->lastInsertId();
                // if ($_SESSION['s_uid'] != $data['aberto_por']) {
                if ($_SESSION['s_uid'] != $arrayBeforePost[$data['numero']]['aberto_por_cod']) {
                    setUserTicketNotice($conn, 'assentamentos', $notice_id);
                }


            } catch (Exception $e) {
                $exception .= "<hr>" . $e->getMessage() ." Linha: " . $e->getLine() . "<hr/>Linha: " . __LINE__ ;
            }


            $sqlSolution = "INSERT INTO solucoes 
            (
                numero, problema, solucao, `data`, responsavel
            ) 
            VALUES 
            (
                :numero,
                :technical_description,
                :technical_solution,
                :date,
                :logged
            )";

            try {
                $res = $conn->prepare($sqlSolution);
                $res->bindParam(':numero', $data['numero'], PDO::PARAM_INT);
                $res->bindParam(':technical_description', $data['technical_description'], PDO::PARAM_STR);
                $res->bindParam(':technical_solution', $data['technical_solution'], PDO::PARAM_STR);
                $res->bindParam(':date', $now, PDO::PARAM_STR);
                $res->bindParam(':logged', $data['author'], PDO::PARAM_INT);
                $res->execute();
            } catch (Exception $e) {
                $exception .= "<hr>" . $e->getMessage() . " Linha: " . $e->getLine() . "<hr/>Linha: " . __LINE__ ;
            }
        }

        if (!empty($data['justificativa'])) {
            
            $sqlJustify = "INSERT INTO assentamentos 
            (
                ocorrencia, assentamento, created_at, responsavel, asset_privated, tipo_assentamento
            )
            VALUES 
            (
                :numero,
                :justificativa,
                :created_at,
                :logged,
                0, 
                3
            )";

            try {
                $res = $conn->prepare($sqlJustify);
                $res->bindParam(':numero', $data['numero'], PDO::PARAM_INT);
                $res->bindParam(':justificativa', $data['justificativa'], PDO::PARAM_STR);
                $res->bindParam(':created_at', $now, PDO::PARAM_STR);
                $res->bindParam(':logged', $data['author'], PDO::PARAM_INT);
                $res->execute();

                $notice_id = $conn->lastInsertId();
                // if ($_SESSION['s_uid'] != $data['aberto_por']) {
                if ($_SESSION['s_uid'] != $arrayBeforePost[$data['numero']]['aberto_por_cod']) {
                    setUserTicketNotice($conn, 'assentamentos', $notice_id);
                }

            } catch (Exception $e) {
                $exception .= "<hr>" . $e->getMessage() . " Linha: " . $e->getLine() . "<hr/>Linha: " . __LINE__ ;
            }
        }
    }


    /* Variáveis de ambiente para envio de e-mail: todos os actions */
    $VARS[$ticketToClose] = getEnvVarsValues($conn, $data['numero']);

    $rating_id = $rowGlobalUri[$ticketToClose]['gt_rating_id'];
    $ratingUrl = $VARS[$ticketToClose]['%linkglobal%'] . '&rating_id=' . $rating_id;


    /* Ações exclusivas para o chamado principal */
    if ($data['numero'] == $data['main_ticket']) {
        
        /* Upload de arquivos - Todos os actions */
        foreach ($filesClean as $attach) {
            $fileinput = $attach['tmp_name'];
            $tamanho = getimagesize($fileinput);
            $tamanho2 = filesize($fileinput);

            if (!$tamanho) {
                /* Nâo é imagem */
                unset ($tamanho);
                $tamanho = [];
                $tamanho[0] = "";
                $tamanho[1] = "";
            }

            if (chop($fileinput) != "") {
                // $fileinput should point to a temp file on the server
                // which contains the uploaded file. so we will prepare
                // the file for upload with addslashes and form an sql
                // statement to do the load into the database.
                // $file = addslashes(fread(fopen($fileinput, "r"), 10000000));
                $file = addslashes(fread(fopen($fileinput, "r"), $config['conf_upld_size']));
                $sqlFile = "INSERT INTO imagens (img_nome, img_oco, img_tipo, img_bin, img_largura, img_altura, img_size) values " .
                    "('" . noSpace($attach['name']) . "'," . $data['numero'] . ", '" . $attach['type'] . "', " .
                    "'" . $file . "', " . dbField($tamanho[0]) . ", " . dbField($tamanho[1]) . ", " . dbField($tamanho2) . ")";
                // now we can delete the temp file
                unlink($fileinput);
            }
            try {
                $exec = $conn->exec($sqlFile);
            }
            catch (Exception $e) {
                $data['message'] = $data['message'] . "<hr>" . TRANS('MSG_ERR_NOT_ATTACH_FILE');
                $exception .= "<hr>" . $e->getMessage(). " Linha: " . $e->getLine() . "<hr/>Linha: " . __LINE__ ;
            }
        }
        /* Final do upload de arquivos */
    
    
        //Exclui os anexos marcados - Action edit || close
        if ( $data['total_files_to_deal'] > 0 ) {
            for ($j = 1; $j <= $data['total_files_to_deal']; $j++) {
                if (isset($post['delImg'][$j])) {
                    $qryDel = "DELETE FROM imagens WHERE img_cod = " . $post['delImg'][$j] . "";

                    try {
                        $conn->exec($qryDel);
                    } catch (Exception $e) {
                        // echo 'Erro: ', $e->getMessage(), "<br/>";
                        // $erro = true;
                        $exception .= "<hr>" . $e->getMessage() . " Linha: " . $e->getLine() . "<hr/>Linha: " . __LINE__ ;
                    }
                }
            }
        }

        $isPai = 0;

        /* Só deve ocorrer se o processo não estiver encerrando sub-chamados também */
        if ( $data['total_relatives_to_deal'] > 0 && count($ticketsToClose) == 1 ) {
            /* Checa se um dos vínculos é chamado pai */
            for ($j = 1; $j <= $data['total_relatives_to_deal']; $j++) {

                if (!empty($post['delSub'][$j])) {
                    $sql = "SELECT * FROM ocodeps WHERE dep_pai = " . $post['delSub'][$j] . " AND dep_filho = " . $data['numero'] . " ";
                    try {
                        $result = $conn->query($sql);
                    } catch (Exception $e) {
                        $exception .= "<hr>" . $e->getMessage() . " Linha: " . $e->getLine() . "<hr/>Linha: " . __LINE__ ;
                    }
                    $isPai = $result->rowCount();
                }
            }

            /* Remove chamado pai */
            if ($isPai) {
                $rowPai = $result->fetch();
                $qryDel = "DELETE FROM ocodeps WHERE dep_filho = " . $data['numero'] . " and dep_pai = " . $rowPai['dep_pai'] . "";
                try {
                    $conn->exec($qryDel);
                }
                catch (Exception $e) {
                    $exception .= "<hr>" . $e->getMessage() . " Linha: " . $e->getLine() . "<hr/>Linha: " . __LINE__ ;
                }
            }

            // Remove subchamados
            for ($j = 1; $j <= $data['total_relatives_to_deal']; $j++) {
                if (isset($post['delSub'][$j])) {

                    $qryDel = "DELETE FROM ocodeps WHERE dep_pai = " . $data['numero'] . " and dep_filho = " . $post['delSub'][$j] . "";
                    try {
                        $conn->exec($qryDel);

                        /* Inserir assentamento no chamado ex-pai */
                        $entryMessage = TRANS('TICKET_RELATION_REMOVED') . " " . $post['delSub'][$j];

                        /* Gravar assentamento no chamado pai */
                        $sqlSubTicket = "INSERT INTO assentamentos 
                        (
                            ocorrencia, assentamento, created_at, responsavel, asset_privated, tipo_assentamento
                        )
                        VALUES 
                        (
                            " . $data['numero'] . ", 
                            '" . $entryMessage . "',
                            '" . $now . "', 
                            '" . $data['author'] . "', 
                            0,
                            11
                        )";

                        try {
                            $conn->exec($sqlSubTicket);

                            $notice_id = $conn->lastInsertId();
                            // if ($_SESSION['s_uid'] != $data['aberto_por']) {
                            if ($_SESSION['s_uid'] != $arrayBeforePost[$data['numero']]['aberto_por_cod']) {
                                setUserTicketNotice($conn, 'assentamentos', $notice_id, 11);
                            }
                        } catch (Exception $e) {
                            $exception .= "<hr>" . $e->getMessage() . " Linha: " . $e->getLine() . "<hr/>Linha: " . __LINE__ ;
                        }

                        /* Inserir assentamento no chamado ex-filho */
                        $entryMessage = TRANS('TICKET_RELATION_REMOVED') . " " . $data['numero'];

                        /* Gravar assentamento no chamado filho */
                        $sqlSubTicket = "INSERT INTO assentamentos 
                        (
                            ocorrencia, assentamento, created_at, responsavel, asset_privated, tipo_assentamento
                        )
                        VALUES 
                        (
                            " . $post['delSub'][$j] . ", 
                            '" . $entryMessage . "',
                            '" . $now . "', 
                            '" . $data['author'] . "', 
                            0,
                            11
                        )";

                        try {
                            $conn->exec($sqlSubTicket);

                            $notice_id = $conn->lastInsertId();
                            // if ($_SESSION['s_uid'] != $data['aberto_por']) {
                            if ($_SESSION['s_uid'] != $arrayBeforePost[$data['numero']]['aberto_por_cod']) {
                                setUserTicketNotice($conn, 'assentamentos', $notice_id, 11);
                            }
                        } catch (Exception $e) {
                            $exception .= "<hr>" . $e->getMessage() . " Linha: " . $e->getLine() . "<hr/>Linha: " . __LINE__ ;
                        }

                    } catch (Exception $e) {
                        $exception .= "<hr>" . $e->getMessage() . " Linha: " . $e->getLine() . "<hr/>Linha: " . __LINE__ ;
                    }
                }
            }
        }



        if (!empty($data['mail_area']) && !empty($rowAreaTo)) {
            $event = "encerra-para-area";
            $eventTemplate = getEventMailConfig($conn, $event);

            /* Disparo do e-mail (ou fila no banco) para a área de atendimento */
            $mail = (new Email())->bootstrap(
                transvars($eventTemplate['msg_subject'], $VARS[$ticketToClose]),
                transvars($eventTemplate['msg_body'], $VARS[$ticketToClose]),
                $rowAreaTo['email'],
                $eventTemplate['msg_fromname'],
                $data['numero']
            );

            if (!$mail->{$mailSendMethod}()) {
                $mailNotification .= "<hr>" . TRANS('EMAIL_NOT_SENT') . "<hr>" . $mail->message()->getText();
            }
        }
    
        $openerData = getUserInfo($conn, $arrayBeforePost[$data['numero']]['aberto_por_cod']);

        if (!empty($data['mail_usuario'])) {

            $VARS[$ticketToClose]['%rating_url%'] = TRANS('RATING_NOT_APPLICABLE'); 

            if (($needToBeRated) OR (!empty($data['contato_email']) && $openerData['email'] != $data['contato_email'])) {
                /* Essa variável só existirá nesse contexto */
                $VARS[$ticketToClose]['%rating_url%'] = $ratingUrl; 
            }
            
            $event = 'encerra-para-usuario';
            $eventTemplate = getEventMailConfig($conn, $event);

            $recipient = "";
            if (!empty($data['contato_email'])) {
                $recipient = $data['contato_email'];
            } else {
                $recipient = $openerData['email'];
            }
            
            /* Disparo do e-mail (ou fila no banco) para o contato */
            $mail = (new Email())->bootstrap(
                transvars($eventTemplate['msg_subject'], $VARS[$ticketToClose]),
                transvars($eventTemplate['msg_body'], $VARS[$ticketToClose]),
                $recipient,
                $eventTemplate['msg_fromname'],
                $data['numero']
            );

            if (!$mail->{$mailSendMethod}()) {
                $mailNotification .= "<hr>" . TRANS('EMAIL_NOT_SENT') . "<hr>" . $mail->message()->getText();
            }
        }

        /** Solicitar avaliacao - sempre será enviado quando o chamado não for concluído pelo próprio solicitante */
        $VARS[$ticketToClose]['%rating_url%'] = TRANS('RATING_NOT_APPLICABLE'); 

        if (($needToBeRated) OR (!empty($data['contato_email']) && $openerData['email'] != $data['contato_email'])) {
            /* Essa variável só existirá nesse contexto */
            $VARS[$ticketToClose]['%rating_url%'] = $ratingUrl; 
        
            $event = 'solicita-avaliacao';
            $eventTemplate = getEventMailConfig($conn, $event);
        
            $recipient = "";
            if (!empty($data['contato_email'])) {
                $recipient = $data['contato_email'];
            } else {
                $recipient = $openerData['email'];
            }
            
            /* Disparo do e-mail (ou fila no banco) para o contato */
            $mail = (new Email())->bootstrap(
                transvars($eventTemplate['msg_subject'], $VARS[$ticketToClose]),
                transvars($eventTemplate['msg_body'], $VARS[$ticketToClose]),
                $recipient,
                $eventTemplate['msg_fromname'],
                $data['numero']
            );
        
            if (!$mail->{$mailSendMethod}()) {
                $mailNotification .= "<hr>" . TRANS('EMAIL_NOT_SENT') . "<hr>" . $mail->message()->getText();
            }
        }


        /* E-mail para os usuários monitoradores */
        if (!empty($data['radio_prob'])) {
            $usersXissues = getUsersFromIssueType($conn, $data['radio_prob']);
            foreach ($usersXissues as $userXissue) {
                $event = "encerra-para-area";
                $eventTemplate = getEventMailConfig($conn, $event);

                $recipientData = getUserById($conn, $userXissue['user_id']);
                unset($recipientData['password']);
                unset($recipientData['hash']);

                /* Disparo do e-mail (ou fila no banco) para a área de atendimento */
                $mail = (new Email())->bootstrap(
                    transvars($eventTemplate['msg_subject'], $VARS[$ticketToClose]),
                    transvars($eventTemplate['msg_body'], $VARS[$ticketToClose]),
                    $recipientData['email'],
                    $eventTemplate['msg_fromname'],
                    $data['numero']
                );

                // if (!$mail->queue()) {
                if (!$mail->{$mailSendMethod}()) {
                    $mailNotification .= "<hr>" . TRANS('EMAIL_NOT_SENT') . "<hr>" . $mail->message()->getText();
                }
            }
        }


    } /* Final as ações exclusivas para o chamado principal */

} //final do foreach $ticketsToClose


$_SESSION['flash'] = message('success', '', $data['message'] . $exception . $mailNotification, '');
echo json_encode($data);
return true;
