4 ms 2025-04-30 13:42:17.267 [info] [streamChoices] solution 0 returned. finish reason: [stop] 2025-04-30 13:42:17.269 [info] [streamChoices] request done: headerRequestId: [363a8219-9611-4b0d-9a93-7930fb8aaea6] model deployment ID: [] 2025-04-30 13:42:24.428 [info] [fetchCompletions] request.response: [https://proxy.individual.githubcopilot.com/v1/engines/gpt-4o-copilot/completions] took 275.48207099922 ms 2025-04-30 13:42:24.429 [info] [streamChoices] solution 0 returned. finish reason: [stop] 2025-04-30 13:42:24.431 [info] [streamChoices] request done: headerRequestId: [79639eb7-7b59-4980-8ecc-a062e5699d04] model deployment ID: [] 2025-04-30 13:46:14.035 [info] [fetchCompletions] request.response: [https://proxy.individual.githubcopilot.com/v1/engines/gpt-4o-copilot/completions] took 486.58926399983466 ms 2025-04-30 13:46:14.036 [info] [streamChoices] solution 0 returned. finish reason: [stop] 2025-04-30 13:46:14.037 [info] [streamChoices] request done: headerRequestId: [c73c2668-b087-456c-9b99-17bab11dd095] model deployment ID: [] 2025-04-30 13:46:16.761 [info] [fetchCompletions] request.response: [https://proxy.individual.githubcopilot.com/v1/engines/gpt-4o-copilot/completions] took 309.3975649997592 ms 2025-04-30 13:46:16.762 [info] [streamChoices] solution 0 returned. finish reason: [stop] 2025-04-30 13:46:16.763 [info] [streamChoices] request done: headerRequestId: [ad5ef061-b1a4-4f4d-ba5c-a6ab293dba84] model deployment ID: [] 2025-04-30 13:46:17.393 [info] [fetchCompletions] request.response: [https://proxy.individual.githubcopilot.com/v1/engines/gpt-4o-copilot/completions] took 376.7783809993416 ms 2025-04-30 13:46:17.395 [info] [streamChoices] solution 0 returned. finish reason: [stop] 2025-04-30 13:46:17.396 [info] [streamChoices] request done: headerRequestId: [0e493a6f-0706-4d02-b42a-d8de7141687f] model deployment ID: [] 2025-04-30 13:46:19.293 [info] [fetchCompletions] request.response: [https://proxy.individual.githubcopilot.com/v1/engines/gpt-4o-copilot/completions] took 306.945442000404 ms 2025-04-30 13:46:19.295 [info] [streamChoices] solution 0 returned. finish reason: [stop] 2025-04-30 13:46:19.297 [info] [streamChoices] request done: headerRequestId: [703df50d-169f-4242-a1bc-33188f11d71a] model deployment ID: [] 2025-04-30 13:46:20.780 [info] [fetchCompletions] request.response: [https://proxy.individual.githubcopilot.com/v1/engines/gpt-4o-copilot/completions] took 480.61922600120306 ms 2025-04-30 13:46:20.782 [info] [streamChoices] solution 0 returned. finish reason: [stop] 2025-04-30 13:46:20.783 [info] [streamChoices] request done: headerRequestId: [f9adaa84-00f5-4aaa-acfb-c1506ae7abbb] model deployment ID: [] 2025-04-30 13:46:22.897 [info] [fetchCompletions] request.response: [https://proxy.individual.githubcopilot.com/v1/engines/gpt-4o-copilot/completions] took 244.06528200022876 ms 2025-04-30 13:46:22.899 [info] [streamChoices] solution 0 returned. finish reason: [stop] 2025-04-30 13:46:22.902 [info] [streamChoices] request done: headerRequestId: [33df7041-ef62-4453-b68b-1c39a36945d5] model deployment ID: [] 2025-04-30 13:46:50.853 [info] [fetchCompletions] request.response: [https://proxy.individual.githubcopilot.com/v1/engines/gpt-4o-copilot/completions] took 328.267711000517 ms 2025-04-30 13:46:50.855 [info] [streamChoices] request done: headerRequestId: [b83968c2-acb5-4ef8-8577-962cc7661eb5] model deployment ID: [] 2025-04-30 13:46:51.152 [info] [fetchCompletions] request.response: [https://proxy.individual.githubcopilot.com/v1/engines/gpt-4o-copilot/completions] took 343.5495079997927 ms 2025-04-30 13:46:51.155 [info] [streamChoices] solution 0 returned. finish reason: [stop] 2025-04-30 13:46:51.157 [info] [streamChoices] request done: headerRequestId: [5b7c44e5-e120-46e0-957b-d3f4e0807ff9] model deployment ID: [] 2025-04-30 13:46:52.190 [info] [fetchCompletions] request.response: [https://proxy.individual.githubcopilot.com/v1/engines/gpt-4o-copilot/completions] took 257.70522999949753 ms 2025-04-30 13:46:52.192 [info] [streamChoices] request done: headerRequestId: [2b5a8496-79a2-4c5f-8a1 "301", "message" => "ERROR - [wsPolizasAnalytics] Parametros incompletos para el Servicio Web, faltan el appOwner"); $Resultado = json_encode($j_array); echo $Resultado; return $Resultado; } if($anio == "") { $j_array = array('code' => "302", "message" => "ERROR - [wsPolizasAnalytics] Parametros incompletos para el Servicio Web, faltan el Anio de vigencia"); $Resultado = json_encode($j_array); echo $Resultado; return $Resultado; } if($mes == "") { $j_array = array('code' => "303", "message" => "ERROR - [wsPolizasAnalytics] Parametros incompletos para el Servicio Web, faltan el Mes de vigencia"); $Resultado = json_encode($j_array); echo $Resultado; return $Resultado; } if($organi_id_Analytics == "") { $j_array = array('code' => "304", "message" => "ERROR - [wsPolizasAnalytics] Parametros incompletos para el Servicio Web, faltan el Organization ID de Analytics"); $Resultado = json_encode($j_array); echo $Resultado; return $Resultado; } if($RFC == "") { $j_array = array('code' => "305", "message" => "ERROR - [wsPolizasAnalytics] Parametros incompletos para el Servicio Web, faltan el RFC"); $Resultado = json_encode($j_array); echo $Resultado; return $Resultado; } if($idWorkspace == "") { $j_array = array('code' => "306", "message" => "ERROR - [wsPolizasAnalytics] Parametros incompletos para el Servicio Web, faltan el ID del workspace"); $Resultado = json_encode($j_array); echo $Resultado; return $Resultado; } if($idView == "") { $j_array = array('code' => "307", "message" => "ERROR - [wsPolizasAnalytics] Parametros incompletos para el Servicio Web, faltan el Organization ID de la vista"); $Resultado = json_encode($j_array); echo $Resultado; return $Resultado; } $dirBase = realpath("../"); ### DEFINICIÓN DE CONSTANTES ################################################### $SendaPEM = "archs_pem/"; $SendaXML = "archs_xml/"; $SendaZIP = "archs_zip/"; #---------------------------------------------------------------- #== Llamado para generar el token para donatello #---------------------------------------------------------------- $curl = curl_init(); curl_setopt_array($curl, array( CURLOPT_URL => 'https://donatello.aptuslegal.app/oauth/token/'.$organi_id_Analytics, CURLOPT_RETURNTRANSFER => true, CURLOPT_ENCODING => '', CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 0, CURLOPT_FOLLOWLOCATION => true, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, CURLOPT_CUSTOMREQUEST => 'GET', CURLOPT_HTTPHEADER => array( 'Authorization: Token e68d5a079f937ea29ad2ec5a5b105b75491a0e0c' ), )); $response = curl_exec($curl); curl_close($curl); // Decodificamos la respuesta JSON $data = json_decode($response, true); // Accedemos al valor de 'access_token de donatello' $access_token = $data['access_token']; #---------------------------------------------------------------- #== Hacemos el llamado para generar la obtención de los datos en la operación Bulk y obtenemos el Job ID. #---------------------------------------------------------------- $curl = curl_init(); $dia = obtenerDiasDelMes($mes); if($dia == "Formato de mes inválido."){ $j_array = array('code' => "309", "message" => "ERROR - [wsPolizasAnalytics] El formato del parámetro del mes no es valido"); $Resultado = json_encode($j_array); echo $Resultado; return $Resultado; } curl_setopt_array($curl, array( CURLOPT_URL => 'https://analyticsapi.zoho.com/restapi/v2/bulk/workspaces/'.$idWorkspace.'/views/'.$idView.'/data?CONFIG=%7B%22criteria%22%3A%22%5C%22Fecha%20de%20transaccion%5C%22%20between%20%27'.$anio.'-'.$mes.'-01%27%20and%20%27'.$anio.'-'.$mes.'-'.$dia.'%27%22%2C%20%22responseFormat%22%3A%22json%22%7D', CURLOPT_RETURNTRANSFER => true, CURLOPT_ENCODING => '', CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 0, CURLOPT_FOLLOWLOCATION => true, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, CURLOPT_CUSTOMREQUEST => 'GET', CURLOPT_HTTPHEADER => array( 'ZANALYTICS-ORGID: '.$organi_id_Analytics, 'Authorization: Zoho-oauthtoken '.$access_token, 'Content-Type: application/json' ), )); $response = curl_exec($curl); curl_close($curl); $responseData = json_decode($response, true); ob_start(); echo '
';
  print_r($responseData);
  echo '
'; $debug_output = ob_get_clean(); // Acceder al 'jobId' $jobId = $responseData['data']['jobId']; #---------------------------------------------------------------- #== Obtenemos el status del JobId para saber si se puede descargar la respuesta #---------------------------------------------------------------- $jobStatus = "JOB IN PROGRESS"; while ($jobStatus === "JOB IN PROGRESS") { $curl = curl_init(); curl_setopt_array($curl, array( CURLOPT_URL => 'https://analyticsapi.zoho.com/restapi/v2/bulk/workspaces/'.$idWorkspace.'/exportjobs/'.$jobId, CURLOPT_RETURNTRANSFER => true, CURLOPT_ENCODING => '', CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 0, CURLOPT_FOLLOWLOCATION => true, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, CURLOPT_CUSTOMREQUEST => 'GET', CURLOPT_HTTPHEADER => array( 'ZANALYTICS-ORGID: '.$organi_id_Analytics, 'Authorization: Zoho-oauthtoken '.$access_token ), )); $response = curl_exec($curl); // Decodificar la respuesta JSON $responseData = json_decode($response, true); // Verificar el status del trabajo if (isset($responseData['data']['jobStatus'])) { $jobStatus = $responseData['data']['jobStatus']; } else { // Si no se encuentra jobStatus en la respuesta, salir del ciclo $j_array = array('code' => "311", "message" => "ERROR - [wsPolizasAnalytics] Error al esperar el Status de JobId de Analytics"); $Resultado = json_encode($j_array); echo $Resultado; return $Resultado; } // Esperar 5 segundos antes de volver a consultar sleep(5); } //Si se obtiene un status diferente al esperado lo interpreta como error if($jobStatus != "JOB COMPLETED"){ $j_array = array('code' => "312", "message" => "ERROR - [wsPolizasAnalytics] Error el Status del JobId inesperado"); $Resultado = json_encode($j_array); echo $Resultado; return $Resultado; } if (isset($responseData['data']['downloadUrl'])) { $downloadUrl = $responseData['data']['downloadUrl']; // echo "Download URL: " . $downloadUrl; } else { $j_array = array('code' => "313", "message" => "ERROR - [wsPolizasAnalytics] Error al obtener el downloadUrl de Analytics"); $Resultado = json_encode($j_array); echo $Resultado; return $Resultado; } #---------------------------------------------------------------- #== Llamado para la obtención de los datos en formato JSON de la vista de Analytics. #---------------------------------------------------------------- $curl = curl_init(); curl_setopt_array($curl, array( CURLOPT_URL => $downloadUrl, CURLOPT_RETURNTRANSFER => true, CURLOPT_ENCODING => '', CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 0, CURLOPT_FOLLOWLOCATION => true, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, CURLOPT_CUSTOMREQUEST => 'GET', CURLOPT_HTTPHEADER => array( 'ZANALYTICS-ORGID: '.$organi_id_Analytics, 'Authorization: Zoho-oauthtoken '.$access_token ), )); $response = curl_exec($curl); curl_close($curl); // Decodificar el JSON $responseData = json_decode($response, true); // Verificar si el campo 'data' existe if (isset($responseData['data'])) { #---------------------------------------------------------------- #== Creación de la variable de tipo DOM, aquí se conforma el XML a timbrar posteriormente. #---------------------------------------------------------------- $xml = new DOMdocument('1.0', 'UTF-8'); $root = $xml->createElement("PLZ:Polizas"); $root = $xml->appendChild($root); #== Se crea e inserta el primer nodo donde se declaran los namespaces ====== cargaAttNodo( $root, array("xsi:schemaLocation"=>"http://www.sat.gob.mx/esquemas/ContabilidadE/1_3/PolizasPeriodo/PolizasPeriodo_1_3.xsd", "xmlns:PLZ"=>"http://www.sat.gob.mx/esquemas/ContabilidadE/1_3/PolizasPeriodo", "xmlns:xsi"=>"http://www.w3.org/2001/XMLSchema") ); #== Rutina de integración de nodos ========================================= cargaAttNodo($root, array( "Version"=>"1.3", "RFC"=>$RFC, "Mes"=>$mes, "Anio"=>$anio, "Tipo Solicitud"=>"AF", "NumOrden"=>"1" ) ); $sumTotalDebe = 0; $sumTotalHaber = 0; $totalDebe = 0; $totalHaber = 0; $polizaControl = ""; $polizaNodo = null; // Variable para mantener la referencia al nodo Poliza $numeroTotalPolizas = 0; $array = array_reverse($responseData['data']); foreach ($array as $item) { // Asignar cada valor a variables $tipoPoliza = $item['Tipo Poliza']; $transaccion = $item['Transaccion']; $fechaTransaccion = str_replace('.', '-', $item['Fecha de transaccion']); $idCuenta = $item['ID de la cuenta']; $nombre = $item['Nombre']; $debe = $item['Debe']; $haber = $item['Haber']; $creditoDebitoTotal = $item['Credito-Debito - Total']; $debitoCreditoTotal = $item['Debito-Credito Total']; $concepto = $item['Concepto']; $numCta = $item['NumCta']; $UUID = $item['UUID']; $rfc = $item['RFC']; $monto = $item['Monto total']; // Cuando detectas una nueva transacción (nueva póliza) if($transaccion != $polizaControl){ // Crear una nueva póliza $polizaControl = $transaccion; $Poliza = $xml->createElement("PLZ:Poliza"); $polizaNodo = $root->appendChild($Poliza); cargaAttNodo($polizaNodo, array( "NumUnIdenPol" => $transaccion, "Fecha" => $fechaTransaccion, "Concepto" => $tipoPoliza )); // Reiniciar los totales para la nueva póliza $totalDebe = 0; $totalHaber = 0; } // Crear un nodo Transaccion y agregarlo a la póliza actual $transaccion = $xml->createElement("PLZ:Transaccion"); $nodo = $Poliza->appendChild($transaccion); cargaAttNodo($nodo, array( "NumCta" => $numCta, "DesCta" => $nombre, "Concepto" => $concepto, "Debe" => $debe, "Haber" => $haber )); // Crear nodo PLZ:CompNal y agregarlo dentro del nodo Transaccion si existe alguno de estos valores, de lo contrario no se agrega if($UUID != "" || $rfc != "" || $monto != ""){ $compNal = $xml->createElement("PLZ:CompNal"); $compNal = $nodo->appendChild($compNal); cargaAttNodo($compNal, array( "UUID_CFDI" => $UUID, "RFC" => $rfc, "MontoTotal" => $monto )); } // Acumular los valores de Debe y Haber $totalDebe += (float)$debe; $totalHaber += (float)$haber; // Acumular los totales generales $sumTotalDebe += (float)$debe; $sumTotalHaber += (float)$haber; $numeroTotalPolizas += 1; } // Para la última póliza en el loop, también agregamos el MontoTotal if ($polizaNodo !== null) { $montoTotal = $totalDebe - $totalHaber; $polizaNodo->setAttribute("MontoTotal", number_format($montoTotal, 2, '.', '')); // Agregar MontoTotal al final } // Establecer el tipo de contenido a XML y devolver el contenido // header('Content-Type: application/xml; charset=utf-8'); // echo $xml->saveXML(); #=== Se guarda el archivo .XML del Catalogo de Cuentas ======================= $file_name_with_full_path = '/var/www/html/aptusContaElec/archs_xml/'.$RFC.$anio.$mes."PP.xml"; #=== Si existe el archivo XML se elimina para crear el nuevo ======================= if(!file_exists($file_name_with_full_path)){ unlink($file_name_with_full_path); } #=== Se guarda el archivo XML creado ======================= $polizaXML = $xml->saveXML(); $xml->formatOutput = true; $xml->save($file_name_with_full_path); unset($xml); #=== Se dan permisos de escritura al archivo .xml. ========================= chmod($file_name_with_full_path, 0777); #=== Se procede a crear el archivo ZIP del Catalogo de Cuentas ========================= $zip = new ZipArchive(); $nombreArchivoZip = '/var/www/html/aptusContaElec/archs_zip/'.$RFC.$anio.$mes."PP.zip"; $nameArchZip = $RFC.$anio.$mes."PL.zip"; #=== Si existe el archivo ZIP se elimina para crear el nuevo ======================= if(!file_exists($nombreArchivoZip)){ unlink($nombreArchivoZip); } if (!$zip->open($nombreArchivoZip, ZipArchive::CREATE | ZipArchive::OVERWRITE)) { exit("Error abriendo ZIP en $nombreArchivoZip"); } $nombre = basename($file_name_with_full_path); $zip->addFile($file_name_with_full_path, $nombre); $resultado = $zip->close(); if ($resultado) { } else { $j_array = array('code' => "318", "message" => "ERROR - [wsPolizasAnalytics] Error al crear el archivo ZIP"); $Resultado = json_encode($j_array); echo $Resultado; return $Resultado; } #---------------------------------------------------------------- # Se sube archivo ZIP a Workdrive #---------------------------------------------------------------- $woa_access_token = oauth($appOwner, 'ZWorkrdv', $woa_RefreshToken, $woa_ClientId, $woa_ClientSecret, $woa_RedirectUri, $woa_GrantType, $woa_AuthUrl); $urlWorkdrv = 'https://workdrive.zoho.com/api/v1/upload?parent_id='.$wdrv_parent_id.'&filename='.$nameArchZip.'&override-name-exist=true'; $curl = curl_init(); curl_setopt_array($curl, array( CURLOPT_URL => $urlWorkdrv, CURLOPT_RETURNTRANSFER => true, CURLOPT_ENCODING => '', CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 0, CURLOPT_FOLLOWLOCATION => true, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, CURLOPT_CUSTOMREQUEST => 'POST', CURLOPT_POSTFIELDS => array('content'=> new CURLFILE($nombreArchivoZip)), CURLOPT_HTTPHEADER => array('Authorization: Zoho-oauthtoken '.$woa_access_token ), ) ); $response = curl_exec($curl); curl_close($curl); #=== FIN DEL PROCESO ======================= $j_array = array('code' => "200", 'message' => "Proceso de creacion de archivo de pólizas del periodo exitoso", 'xml_file_name' => $RFC.$anio.$mes."PP.xml", 'zip_file_name' => $RFC.$anio.$mes."PP.zip",'Total de Polizas' => $numeroTotalPolizas,'Total Debe' =>number_format($sumTotalDebe, 2, '.', ''),'Total Haber' => number_format($sumTotalHaber, 2, '.', '')); $Resultado = json_encode($j_array); echo $Resultado; return $Resultado; } else { $j_array = array('code' => "315", "message" => "ERROR - [wsPolizasAnalytics] No se obtuvieron datos de la vista"); $Resultado = json_encode($j_array); echo $Resultado; return $Resultado; } ### FUNCIONES DEL MÓDULO ######################################################### # Función que integra los nodos al archivo .XML function cargaAttNodo(&$nodo, $attr){ global $xmldoc; foreach ($attr as $key => $val){ $val = preg_replace('/\s\s+/', ' ', $val); $val = trim($val); if (strlen($val)>0){ $val = utf8_encode(str_replace("|","/",$val)); $nodo->setAttribute($key,$val); } } } function obtenerDiasDelMes($mes) { // Validar que el parámetro sea una cadena con dos dígitos if (!preg_match('/^\d{2}$/', $mes)) { return "Formato de mes inválido."; } // Obtener el año actual $anio = date("Y"); // Usar la función `cal_days_in_month` para obtener la cantidad de días del mes $dias = cal_days_in_month(CAL_GREGORIAN, intval($mes), $anio); return $dias; }