fter 194.48915899998974ms 2025-10-22 10:33:58.520 [info] [streamChoices] solution 0 returned. finish reason: [stop] 2025-10-22 10:33:59.464 [info] [fetchCompletions] Request 019afedc-ce71-4934-be60-7e72f9e571ab at finished with 200 status after 230.04160300001968ms 2025-10-22 10:33:59.548 [info] [streamChoices] solution 0 returned. finish reason: [stop] 2025-10-22 10:34:00.235 [info] [fetchCompletions] Request 69902d81-efc7-4f08-953d-c1408fc09b71 at finished with 200 status after 320.73911599989515ms 2025-10-22 10:34:00.307 [info] [streamChoices] solution 0 returned. finish reason: [stop] 2025-10-22 10:34:00.846 [info] [fetchCompletions] Request a0ebb58c-10b1-4aa6-9373-e36163317ef5 at finished with 200 status after 333.47002899996005ms 2025-10-22 10:34:00.916 [info] [streamChoices] solution 0 returned. finish reason: [stop] 2025-10-22 11:35:47.766 [info] [fetcher] Using Helix fetcher, Electron fetcher is not available. 2025-10-22 11:35:47.766 [info] [code-referencing] Public code references are enabled. 2025-10-22 11:35:47.850 [info] [fetcher] Using Helix fetcher, Electron fetcher is not available. 2025-10-22 11:37:14.100 [info] [fetchCompletions] Request 6dccffd0-a961-4efa-aa47-2059e46855c4 at finished with 200 status after 419.4541169991717ms 2025-10-22 11:37:14.667 [info] [fetchCompletions] Request e4ecdbd3-41cd-487a-a29d-902a773c1ace at finished with 200 status after 391.29322300013155ms 2025-10-22 11:37:14.769 [info] [fetchCompletions] Request 33d8af8e-0a70-4aac-b356-2c564e2fc4f8 at finished with 200 status after 268.8799350000918ms 2025-10-22 11:37:14.971 [info] [streamChoices] solution 0 returned. finish reason: [stop] 2025-10-22 11:37:15.095 [info] [fetchCompletions] Request 003e92d2-72e5-47bc-a8a6-f0bd855e59cb at finished with 200 status after 226.66641899943352ms 2025-10-22 11:37:15.733 [info] [fetchCompletions] Request 520adfcb-4ae0-4d03-bf8f-be1030288883 at finished with 200 status after 248.2319329995662ms 2025-10-22 11:37:15.860 [info] [streamChoices] solution 0 returned. finish reason: [stop] 2025-10-22 11:37:16.510 [info] [fetchCompletions] Request eb91056e-5861-4794-9d42-379b4b0e893f at finished with 200 status after 207.3668540008366ms 2025-10-22 11:37:16.922 [info] [fetchCompletions] Request d7e98b2a-f8d6-451e-9a7b-5b5f5e7f3790 at finished with 200 status after 195.25700199976563ms 2025-10-22 11:37:17.219 [info] [streamChoices] solution 0 returned. finish reason: [stop] 2025-10-22 11:37:17.331 [info] [fetchCompletions] Request 04089330-885d-4cc8-a237-9422e3071fa4 at finished with 200 status after 224.84054899960756ms 2025-10-22 11:37:17.526 [error] [AsyncCompletionManager] [04089330-885d-4cc8-a237-9422e3071fa4] Request errored with AbortError: The operation was aborted. at AbortSignal.abortHandler (/home/ubuntu/.vscode-server/extensions/github.copilot-1.387.0/node_modules/@adobe/helix-fetch/src/fetch/index.js:106:17) at AbortSignal.[nodejs.internal.kHybridDispatch] (node:internal/event_target:827:20) at AbortSignal.dispatchEvent (node:internal/event_target:762:26) at runAbort (node:internal/abort_controller:486:10) at abortSignal (node:internal/abort_controller:457:3) at AbortControl $v) $out[strtolower($k)] = $v; return $out; } $__PDF_EXTRAS = []; $__headers = getallheaders_lower(); // Log para depuración error_log("Headers recibidos: " . print_r(array_keys($__headers), true)); if (!empty($__headers['x-cfdi-pdf-extras'])) { error_log("Header x-cfdi-pdf-extras encontrado"); $decoded = base64_decode($__headers['x-cfdi-pdf-extras'], true); if ($decoded !== false) { $__PDF_EXTRAS = json_decode($decoded, true) ?: []; error_log("Datos JSON decodificados: " . print_r($__PDF_EXTRAS, true)); } else { error_log("Error al decodificar base64"); } } else { error_log("No se encontró el header x-cfdi-pdf-extras"); // Mostrar todos los headers disponibles para debugging error_log("Headers disponibles: " . implode(', ', array_keys($__headers))); } // Construir mapa por índice: 1..n $DescPDFByIndex = []; // idx => "texto" // PRIMERO: Buscar en 'conceptos' (lo que estás enviando) if (!empty($__PDF_EXTRAS['conceptos']) && is_array($__PDF_EXTRAS['conceptos'])) { foreach ($__PDF_EXTRAS['conceptos'] as $c) { $idx = isset($c['idx']) ? intval($c['idx']) : null; $txt = isset($c['desc_pdf']) ? trim((string)$c['desc_pdf']) : ''; if ($idx && $txt !== '') $DescPDFByIndex[$idx] = $txt; } } // SEGUNDO: Como fallback, buscar en 'articulos' (por compatibilidad) else if (!empty($__PDF_EXTRAS['articulos']) && is_array($__PDF_EXTRAS['articulos'])) { foreach ($__PDF_EXTRAS['articulos'] as $idx => $c) { $txt = isset($c['descripcionPDF']) ? trim((string)$c['descripcionPDF']) : ''; if ($txt !== '') $DescPDFByIndex[$idx+1] = $txt; // +1 porque los índices comienzan en 1 } } // Agregar logging para depuración error_log("Mapa de descripciones: " . print_r($DescPDFByIndex, true)); #============================================================================================================ #== 1. CREAMOS LA CLASE Y OBTENEMOS LOS DATOS BASICOS DEL REPORTE #============================================================================================================ class PDF extends FPDF { function Footer() { $this->SetFont('arial','B',10); $this->SetTextColor(128,0,0); $this->SetXY(2.2,26.7); $this->Cell(15.6, 0.30, utf8_decode("ESTE DOCUMENTO ES UNA REPRESENTACIÓN IMPRESA DE UN CFDI"), 0, 1,'C', 0); $this->SetTextColor(0,0,0); $this->SetFont('arial','',10); $this->SetXY(19.4,26.7); $this->Cell(0.8, 0.25, $this->PageNo().'/{nb}', 0, 1,'L', 0); } } $SendaArchsCFDI = "archs_cfdi/"; $SendaArchsGraf = "archs_graf/"; $FechaHoraEmision = date("Y-m-d")."T".date("H:i:s"); $Obs = ""; $StatusCFDI = "ACTIVO"; $PaginaWeb = "www.ecrubio.com"; $SumaImportes = 0; $TotImpuestos = 0; $UUID = ""; $Fact_Fecha = ""; $selloCFD = ""; $noCertificado = ""; $noCertificadoSAT = ""; $fechaTim = ""; $selloSAT = ""; $versionTim = ""; $rfcPAC = ""; // Obtener parámetros (pueden venir por GET o POST) $invoiceNumber = isset($_REQUEST['invoice_number']) ? $_REQUEST['invoice_number'] : null; $clientNumber = isset($_REQUEST['client_number']) ? $_REQUEST['client_number'] : null; $folio = isset($_REQUEST['folio']) ? $_REQUEST['folio'] : null; // Validar que se recibieron // if (!$invoiceNumber || !$clientNumber) { // echo json_encode([ // "success" => false, // "message" => "Faltan parámetros: invoice_number y/o client_number" // ]); // exit; // } // Obtener abreviatura del año (últimos dos dígitos) $yearShort = date("y"); // ejemplo: 2025 → "25" $result = ""; // Construir la cadena if($folio != null && $folio != "" && $folio != "null" && $folio != "undefined"){ $result = $folio; }else{ $result = "ComExt3/AMJ/{$invoiceNumber}/{$yearShort} {$clientNumber}"; } try { // Leer el cuerpo de la petición $xml = file_get_contents('php://input'); if (empty($xml)) { throw new Exception('No se recibió ningún XML'); } } catch (Exception $e) { http_response_code(400); echo json_encode([ 'success' => false, 'error' => $e->getMessage() ]); } #============================================================================================================ #== 2. OBTENIENDO DATOS DEL ARCHIVO .XML #============================================================================================================ $DOM = new DOMDocument('1.0', 'utf-8'); $DOM->preserveWhiteSpace = FALSE; $DOM->loadXML($xml); $params = $DOM->getElementsByTagName('TimbreFiscalDigital'); foreach ($params as $param) { $UUID = $param->getAttribute('UUID'); $noCertificadoSAT = $param->getAttribute('NoCertificadoSAT'); $selloCFD = $param->getAttribute('SelloCFD'); $selloSAT = $param->getAttribute('SelloSAT'); $rfcPAC = $param->getAttribute('RfcProvCertif'); $fechaTim = $param->getAttribute('FechaTimbrado'); $versionTim = $param->getAttribute('Version'); } $params = $DOM->getElementsByTagName('Emisor'); foreach ($params as $param) { $Emisor_Nom = $param->getAttribute('Nombre'); $Emisor_RFC = $param->getAttribute('Rfc'); $Emisor_Regimen = $param->getAttribute('RegimenFiscal'); } $params = $DOM->getElementsByTagName('Receptor'); foreach ($params as $param) { $Receptor_Nom = $param->getAttribute('Nombre'); $Receptor_RFC = $param->getAttribute('Rfc'); $Receptor_UsoCFDI = $param->getAttribute('UsoCFDI'); $Receptor_DomFis = $param->getAttribute('DomicilioFiscalReceptor'); $Receptor_RegFis = $param->getAttribute('RegimenFiscalReceptor'); } $params = $DOM->getElementsByTagName('Comprobante'); foreach ($params as $param) { $Fact_Fecha = $param->getAttribute('Fecha'); $Fact_Serie = $param->getAttribute('Serie'); $Fact_Folio = $param->getAttribute('Folio'); $Fact_NoFact = $Fact_Serie.' - '.str_pad($Fact_Folio, 6, "0", STR_PAD_LEFT); $descuento = $param->getAttribute('Descuento'); $subTotal = $param->getAttribute('SubTotal'); $total = $param->getAttribute('Total'); $version = $param->getAttribute('Version'); $noCertificado = $param->getAttribute('NoCertificado'); $formaDePago = $param->getAttribute('FormaPago'); $metodoDePago = $param->getAttribute('MetodoPago'); $moneda = $param->getAttribute('Moneda'); $tipoCambio = $param->getAttribute('TipoCambio'); $NumCtaPago = ""; $LugarExpedicion = $param->getAttribute('LugarExpedicion'); $FechaHoraEmision = $param->getAttribute('Fecha'); } if (strlen($Fact_NoFact) == 0){ $Fact_NoFact = "S/N"; } // Adicionado por FFR en MArzo 30, 2019 // Para el manejo de los CFDI Relacionados $Tipo_Relacion = ""; $params = $DOM->getElementsByTagName('CfdiRelacionados'); foreach ($params as $param) { $Tipo_Relacion = $param->getAttribute('TipoRelacion'); } $i = 0; $params = $DOM->getElementsByTagName('cfdiRelacionado'); foreach ($params as $param) { $ArrayUUID[$i] = $param->getAttribute('UUID'); $i++; } $i = 0; $k = 0; $ImpTot = 0; $ImporteTotalIVA = 0; $ImporteTotalIEPS = 0; $ImporteTotalISR = 0; $ImporteTotalIVAR = 0; $params = $DOM->getElementsByTagName('Concepto'); foreach ($params as $param) { $ArrayCant[$i] = $param->getAttribute('Cantidad'); $ArrayCvePro[$i] = $param->getAttribute('ClaveProdServ'); $ArrayUniMed[$i] = $param->getAttribute('Unidad'); $ArrayClaArtSer[$i] = $param->getAttribute('ClaveUnidad'); $ArrayArtSer[$i] = $param->getAttribute('Descripcion'); $ArrayPreUni[$i] = $param->getAttribute('ValorUnitario'); $ArrayDescuento[$i] = $param->getAttribute('Descuento'); $ArrayImporte[$i] = $param->getAttribute('Importe'); // Added by facc's on Feb 28, 2022 for CFDI 4.0 $ArrayObjImpu[$i] = $param->getAttribute('ObjetoImp'); $lTipImp = 0; $traslados = $param->getElementsByTagName('Traslado'); foreach ($traslados as $traslado) { $lTipImp = 1; $ArrayTrasladoImpo[$i] = $traslado->getAttribute('Importe'); $ArrayTrasladoTasa[$i] = $traslado->getAttribute('TasaOCuota'); $ArrayTrasladoTipo[$i] = $traslado->getAttribute('TipoFactor'); $ArrayTrasladoImpu[$i] = $traslado->getAttribute('Impuesto'); $ArrayTrasladoBase[$i] = $traslado->getAttribute('Base'); $TotImpuestos = $TotImpuestos + $traslado->getAttribute('Importe'); if ($traslado->getAttribute('Impuesto') == "002") { // IVA $ImporteTotalIVA = $ImporteTotalIVA + $traslado->getAttribute('Importe'); } if ($traslado->getAttribute('Impuesto') == "003") { // IEPS $ImporteTotalIEPS = $ImporteTotalIEPS + $traslado->getAttribute('Importe'); } } $retenciones = $param->getElementsByTagName('Retencion'); foreach ($retenciones as $retencion) { $lTipImp = 2; $ArrayRetencionImpo[$i] = $retencion->getAttribute('Importe'); $ArrayRetencionTasa[$i] = $retencion->getAttribute('TasaOCuota'); $ArrayRetencionTipo[$i] = $retencion->getAttribute('TipoFactor'); $ArrayRetencionImpu[$i] = $retencion->getAttribute('Impuesto'); $ArrayRetencionBase[$i] = $retencion->getAttribute('Base'); if ($retencion->getAttribute('Impuesto')=="001") { // ISR $ImporteTotalISR = $ImporteTotalISR + $retencion->getAttribute('Importe'); } if ($retencion->getAttribute('Impuesto')=="002") { // ISR $ImporteTotalIVAR = $ImporteTotalIVAR + $retencion->getAttribute('Importe'); } } $SumaImportes = $SumaImportes + $ArrayImporte[$i]; $posConcepto = $i + 1; // Descripción para PDF priorizando lo que llegó en el header (JSON) if (isset($DescPDFByIndex[$posConcepto]) && strlen($DescPDFByIndex[$posConcepto]) > 0) { $ArrayArtSerPDF[$i] = $DescPDFByIndex[$posConcepto]; error_log("Usando descripción personalizada para concepto $posConcepto: " . $DescPDFByIndex[$posConcepto]); } else { $ArrayArtSerPDF[$i] = $ArrayArtSer[$i]; // fallback a lo que trae el XML error_log("Usando descripción del XML para concepto $posConcepto: " . $ArrayArtSer[$i]); } $i++; } if ($fechaTim != "") { $CadOri = "||".$versionTim."|".$UUID."|".$fechaTim."|".$rfcPAC."|".$selloCFD."|".$noCertificadoSAT."||"; } else { $CadOri = "||".$versionTim."|".$UUID."|".$Fact_Fecha."|".$rfcPAC."|".$selloCFD."|".$noCertificadoSAT."||"; } #============================================================================================================ #== 3. Crear archivo .PNG con codigo bidimensional #============================================================================================================ $filename = ""; if ($UUID != "") { $filename = $SendaArchsGraf."/Img_".$UUID.".png"; $CadImpTot = ProcesImpTot($total); $CadImpTot = str_replace ( ",", '', $CadImpTot); $CadSello = substr($selloCFD,-8); $Cadena = "https://verificacfdi.facturaelectronica.sat.gob.mx/default.aspx?id=".$UUID."&re=".$Emisor_RFC."&rr=".$Receptor_RFC."&tt=".$CadImpTot."&fe=".$CadSello; QRcode::png($Cadena, $filename, 'H', 3, 2); chmod($filename, 0777); } #============================================================================================================ #== 4. CONSTRUYENDO EL DOCUMENTOS CON LA LIBRERÍA FPDF #============================================================================================================ $pdf = new PDF('P', 'cm', 'A4'); $SAFE = 0.5; $pdf->AliasNbPages(); $pdf->AddPage(); $pdf->AddFont('IDAutomationHC39M','','IDAutomationHC39M.php'); $pdf->AddFont('verdana','','verdana.php'); $pdf->SetMargins($SAFE, $SAFE, $SAFE); $pdf->SetAutoPageBreak(true, $SAFE); $pdf->SetLineWidth(0.02); $pdf->SetFillColor(0,0,0); #============================================================================================================ #== 4.1 ENCABEZADO DE LA FACTURA #============================================================================================================ $X = 0; $Y = 0; $pdf->image("archs_graf/Membrete_RVA.jpg",$X+1, $Y+1 , 9, 2.3); $pdf->image("archs_graf/LogoSAT.jpg",$X+16.6, $Y+3.4 , 0, 0); $pdf->SetTextColor(128,0,0); $pdf->SetFont('arial','B',13); $pdf->SetXY($X+11.7,$Y+1.20+0.1); $pdf->Cell(1.5, 0.25, "COMPROBANTE FISCAL DIGITAL", 0, 1,'L', 0); $pdf->SetTextColor(0,0,0); $pdf->SetFont('arial','B',10); $pdf->SetXY($X+15.5,$Y+1.96); $pdf->Cell(2.5, 0.25, "FOLIO:", 0, 1,'L', 0); $pdf->SetTextColor(171,17,17); $pdf->SetFont('arial','B',14); $pdf->SetXY($X+17,$Y+1.95); $pdf->Cell(1, 0.25, $Fact_NoFact, 0, 1,'L', 0); $pdf->SetTextColor(0,0,0); $pdf->SetFont('arial','B',9); $pdf->SetXY($X+10.5,$Y+2.05); $pdf->Cell(2, 0.25, "FOLIO FISCAL:", 0, 1,'L', 0); $pdf->SetTextColor(17,71,121); $pdf->SetFont('arial','B',11); $pdf->SetXY($X+10.5+0.5,$Y+2.6); $pdf->Cell(2, 0.25, $UUID, 0, 1,'L', 0); $pdf->SetTextColor(0,0,0); $pdf->SetFont('arial','B',9); $pdf->SetXY($X+10.5,$Y+2.5+0.6); $pdf->Cell(2, 0.25, "CERTIFICADO SAT:", 0, 1,'L', 0); $pdf->SetTextColor(17,71,121); $pdf->SetFont('arial','',10); $pdf->SetXY($X+10.5+0.5,$Y+2.5+0.6+0.4); $pdf->Cell(2, 0.25, $noCertificadoSAT, 0, 1,'L', 0); $pdf->SetTextColor(0,0,0); $pdf->SetFont('arial','B',9); $pdf->SetXY($X+10.5,$Y+4.06); $pdf->Cell(2, 0.25, "CERTIFICADO DEL EMISOR:", 0, 1,'L', 0); $pdf->SetTextColor(17,71,121); $pdf->SetFont('arial','',10); $pdf->SetXY($X+10.5+0.5,$Y+4.06+0.4); $pdf->Cell(2, 0.25, $noCertificado, 0, 1,'L', 0); $pdf->SetTextColor(0,0,0); $pdf->SetFont('arial','B',9); $pdf->SetXY($X+10.5,$Y+4.46+0.5); $pdf->Cell(2, 0.25, utf8_decode("FECHA HORA DE EMISIÓN:"), 0, 1,'L', 0); $pdf->SetTextColor(17,71,121); $pdf->SetFont('arial','',9); $pdf->SetXY($X+10.5+0.5,$Y+4.46+0.5+0.34); $pdf->MultiCell(9.4, 0.35, str_replace("T"," ",utf8_decode($FechaHoraEmision)), 0, 'L'); $pdf->SetTextColor(0,0,0); $pdf->SetFont('arial','B',9); $pdf->SetXY($X+10.5,$Y+6); $pdf->Cell(2, 0.25, utf8_decode("FECHA HORA DE CERTIFICACIÓN:"), 0, 1,'L', 0); $pdf->SetTextColor(17,71,121); $pdf->SetFont('arial','',9); $pdf->SetXY($X+10.5+5.5,$Y+6); $pdf->Cell(2, 0.25, str_replace("T"," ",$fechaTim), 0, 1,'L', 0); $pdf->SetTextColor(0,0,0); $pdf->SetFont('arial','B',9); $pdf->SetXY($X+10.5,$Y+6.6); $pdf->Cell(2, 0.25, utf8_decode("TIPO DE COMPROBANTE:"), 0, 1,'L', 0); $pdf->SetFont('arial','',9); $pdf->SetTextColor(17,71,121); $pdf->SetXY($X+14.7,$Y+6.6); $pdf->Cell(1, 0.25, utf8_decode("I - INGRESO"), 0, 1,'L', 0); $pdf->SetFont('arial','B',14); $pdf->SetTextColor(17,71,121); $pdf->SetXY($X+19.0,$Y+6.6); $pdf->Cell(1, 0.25, utf8_decode("v4.0"), 0, 1,'L', 0); $pdf->SetFont('arial','',9); $pdf->SetDrawColor(128,0,0); $pdf->SetLineWidth(0.05); $pdf->RoundedRect($X+10.4, $Y+1, 10, 6.14, 0.2, ''); #============================================================================================================ #== 4.2 DATOS DEL EMISOR #============================================================================================================ #==$pdf->SetFillColor(84,141,212); $pdf->SetFillColor(223,234,247); $pdf->RoundedRect($X+1, $Y+3.5, 9, 3.64, 0.2, 'F'); #==$pdf->SetTextColor(255,255,255); $pdf->SetTextColor(0,0,0); $pdf->SetFont('arial','B',11); $pdf->SetXY($X+1.05,$Y+3.7); $pdf->Cell(1, 0.25, "EMISOR:", 0, 1,'L', 0); #==$pdf->SetTextColor(255,255,255); $pdf->SetTextColor(0,0,0); $pdf->SetFont('arial','B',12); $pdf->SetXY($X+1.4,$Y+4.0+0.2); $pdf->MultiCell(8.6, 0.45, utf8_decode($Emisor_Nom), 0, 'C'); #==$pdf->SetTextColor(255,255,255); $pdf->SetTextColor(0,0,0); $pdf->SetFont('arial','B',10); $pdf->SetXY($X+1.05,$Y+3.7+0.45+1.25); $pdf->Cell(1, 0.25, "RFC:", 0, 1,'L', 0); #==$pdf->SetTextColor(255,255,255); $pdf->SetTextColor(0,0,0); $pdf->SetFont('arial','',11); $pdf->SetXY($X+2.05,$Y+3.7+0.45+1.25); $pdf->Cell(1, 0.25, utf8_decode($Emisor_RFC), 0, 1,'L', 0); #==$pdf->SetTextColor(255,255,255); $pdf->SetTextColor(0,0,0); $pdf->SetFont('arial','B',9); $pdf->SetXY($X+1.05,$Y+3.7+0.45+1.8); $pdf->Cell(1, 0.25, utf8_decode("LUGAR DE EXPEDICIÓN:"), 0, 1,'L', 0); #==$pdf->SetTextColor(255,255,255); $pdf->SetTextColor(0,0,0); $pdf->SetFont('arial','',10); $pdf->SetXY($X+1.05+4,$Y+3.7+0.45+1.8); $pdf->Cell(1, 0.25, $LugarExpedicion, 0, 1,'L', 0); #==$pdf->SetTextColor(255,255,255); $pdf->SetTextColor(0,0,0); $pdf->SetFont('arial','B',9); $pdf->SetXY($X+1.05,$Y+4.2+0.45+1.8); $pdf->Cell(1, 0.25, utf8_decode("RÉGIMEN FISCAL:"), 0, 1,'L', 0); #==$pdf->SetTextColor(255,255,255); $pdf->SetTextColor(0,0,0); $pdf->SetFont('arial','',10); $pdf->SetXY($X+0.05+4,$Y+4.2+0.45+1.8); $pdf->Cell(1, 0.25, $Emisor_Regimen, 0, 1,'L', 0); $Y = $Y -1; #============================================================================================================ #== 4.3 DATOS DEL RECEPTOR #============================================================================================================ #==$pdf->SetFillColor(191,191,191); $pdf->SetFillColor(222,222,222); #==$pdf->SetFillColor(223,234,247); $pdf->RoundedRect($X+1, $Y+8.4, 19.4, 1.7, 0.2, 'F'); $pdf->SetTextColor(0,0,0); $pdf->SetFont('arial','B',11); $pdf->SetXY($X+1.05,$Y+8.6); $pdf->Cell(1, 0.25, "RECEPTOR:", 0, 1,'L', 0); $pdf->SetTextColor(0,0,0); $pdf->SetFont('arial','B',10); $pdf->SetXY($X+1.5,$Y+8.4+0.60); $pdf->Cell(1, 0.25, utf8_decode($Receptor_Nom), 0, 1,'L', 0); $pdf->SetTextColor(0,0,0); $pdf->SetFont('arial','B',10); $pdf->SetXY($X+1.05,$Y+9.5+0.1); $pdf->Cell(1, 0.25, "RFC:", 0, 1,'L', 0); $pdf->SetTextColor(0,0,0); $pdf->SetFont('arial','',11); $pdf->SetXY($X+1.05+0.9,$Y+9.5+0.1); $pdf->Cell(1, 0.25, $Receptor_RFC, 0, 1,'L', 0); $pdf->SetTextColor(0,0,0); $pdf->SetFont('arial','B',10); $pdf->SetXY($X+6,$Y+9.5+0.1); $pdf->Cell(2, 0.25, utf8_decode("USO CFDI:"), 0, 1,'L', 0); $pdf->SetTextColor(0,0,0); $pdf->SetFont('arial','',11); $pdf->SetXY($X+6+2,$Y+9.5+0.1); $pdf->Cell(1, 0.25, $Receptor_UsoCFDI, 0, 1,'L', 0); $pdf->SetTextColor(0,0,0); $pdf->SetFont('arial','B',10); $pdf->SetXY($X+10,$Y+9.5+0.1); $pdf->Cell(2, 0.25, utf8_decode("RÉGIMEN FISCAL:"), 0, 1,'L', 0); $pdf->SetTextColor(0,0,0); $pdf->SetFont('arial','',11); $pdf->SetXY($X+10+3.3,$Y+9.5+0.1); $pdf->Cell(1, 0.25, $Receptor_RegFis, 0, 1,'L', 0); $pdf->SetTextColor(0,0,0); $pdf->SetFont('arial','B',10); $pdf->SetXY($X+15.5,$Y+9.5+0.1); $pdf->Cell(2, 0.25, utf8_decode("CÓDIGO POSTAL:"), 0, 1,'L', 0); $pdf->SetTextColor(0,0,0); $pdf->SetFont('arial','',11); $pdf->SetXY($X+15.5+3.3,$Y+9.5+0.1); $pdf->Cell(1, 0.25, $Receptor_DomFis, 0, 1,'L', 0); $pdf->SetDrawColor(0,0,0); $pdf->SetLineWidth(0.02); VerifStatusCFDI($pdf, $StatusCFDI); $Puntero = 0; $a = 9.58; $b = 0; $c = 0; $Y = $Y + 1; #============================================================================================================ #== 4.3 REGISTROS DE ARTÍCULOS #============================================================================================================ $Y = $pdf->GetY()+0.20; if (strlen($Obs)==0) { $Y = $Y + 1.1; } else { $Y = $Y + 0.8; } $Regs = 0; $RefAgregPag = 0; Titulos($pdf, $Y-0.8); $TotRegs = count($ArrayCant); for ($i=0; $i<$TotRegs; $i++) { $pdf->SetFont('arial','',8); $pdf->SetTextColor(0,0,0); $pdf->SetXY($X+0.75,$Y); $pdf->Cell(1.5, 0.30, $ArrayCant[$i], 0, 1,'C', 0); $pdf->SetXY($X+1.975,$Y); $pdf->Cell(1.0, 0.30, utf8_decode($ArrayClaArtSer[$i]), 0, 1,'L', 0); $pdf->SetXY($X+2.6,$Y); $pdf->MultiCell(2.0, 0.30, utf8_decode($ArrayUniMed[$i]), 0, 'L', 0); $pdf->SetXY($X+4.5,$Y); $pdf->Cell(2.0, 0.30, utf8_decode($ArrayCvePro[$i]), 0, 1,'L', 0); $pdf->SetXY($X+6.2,$Y); $pdf->Cell(1.7, 0.30, number_format($ArrayPreUni[$i],2), 0, 1,'R', 0); $pdf->SetXY($X+8.0,$Y); $pdf->Cell(1.8, 0.30, number_format($ArrayImporte[$i],2), 0, 1,'R', 0); $pdf->SetXY($X+10.6,$Y); // $pdf->Cell(1.8, 0.30, number_format($ArrayDescuento[$i],2), 0, 1,'R', 0); $pdf->SetXY($X+12.8,$Y); $pdf->Cell(1.0, 0.30, utf8_decode($ArrayObjImpu[$i]), 0, 1,'C', 0); if($lTipImp == 1) { $pdf->SetXY($X+13.75,$Y); $pdf->Cell(1.8, 0.30, number_format($ArrayTrasladoBase[$i],2), 0, 1,'R', 0); $pdf->SetXY($X+15.6,$Y); $pdf->Cell(1.0, 0.30, $ArrayTrasladoImpu[$i], 0, 1,'L', 0); $pdf->SetXY($X+16.4,$Y); $pdf->Cell(1.0, 0.30, $ArrayTrasladoTipo[$i], 0, 1,'L', 0); $pdf->SetXY($X+16.8,$Y); $pdf->Cell(1.8, 0.30, number_format($ArrayTrasladoTasa[$i],6), 0, 1,'R', 0); $pdf->SetXY($X+18.5,$Y); $pdf->Cell(1.8, 0.30, number_format($ArrayTrasladoImpo[$i],2), 0, 1,'R', 0); } if($lTipImp == 2) { $pdf->SetXY($X+13.75,$Y); $pdf->Cell(1.8, 0.30, number_format($ArrayRetencionBase[$i],2), 0, 1,'R', 0); $pdf->SetXY($X+15.6,$Y); $pdf->Cell(1.0, 0.30, $ArrayRetencionImpu[$i], 0, 1,'L', 0); $pdf->SetXY($X+16.4,$Y); $pdf->Cell(1.0, 0.30, $ArrayRetencionTipo[$i], 0, 1,'L', 0); $pdf->SetXY($X+16.8,$Y); $pdf->Cell(1.8, 0.30, number_format($ArrayRetencionTasa[$i],6), 0, 1,'R', 0); $pdf->SetXY($X+18.5,$Y); $pdf->Cell(1.8, 0.30, number_format($ArrayRetencionImpo[$i],2), 0, 1,'R', 0); } $pdf->line($X+1, $Y-0.1, $X+20.4, $Y-0.1); $Y = $Y + 0.70; $pdf->SetFont('arial','B',8); $pdf->SetTextColor(0,0,0); $pdf->SetXY($X+1.0,$Y); $pdf->Cell(1.0, 0.30, utf8_decode("Descripción:"), 0, 1,'L', 0); $pdf->SetFont('arial','',8); $pdf->SetTextColor(0,0,0); $pdf->SetXY($X+2.8,$Y); $pdf->MultiCell(17.3, 0.30, utf8_decode($ArrayArtSerPDF[$i]), 0, 'J', 0); //$pdf->Write(0.4,''); $YY = $pdf->GetY()+0.18; $Puntero = $pdf->GetY(); $Y = $YY; $Regs++; if ($Puntero>23.5) { if ($TotRegs>$Regs) { $pdf->AddPage(); Titulos($pdf, 1.5); $Y = 2.4; } else { $pdf->AddPage(); $Y = 1.4; } } } #============================================================================================================ #== 4.4 IMPRESIÓN DE LOS SUBTOTALES. #============================================================================================================ if ($Puntero<=23.5) { SubTotales($pdf, $Y, $subTotal, $descuento, $ImporteTotalIVA, $ImporteTotalIEPS, $total, $formaDePago, $metodoDePago, $NumCtaPago, $Puntero, $moneda, $tipoCambio, $ImporteTotalISR, $ImporteTotalIVAR); } if ($Puntero>23.5 && $TotRegs==$Regs) { SubTotales($pdf, $Y, $subTotal, $descuento, $ImporteTotalIVA, $ImporteTotalIEPS, $total, $formaDePago, $metodoDePago, $NumCtaPago, $Puntero, $moneda, $tipoCambio, $ImporteTotalISR, $ImporteTotalIVAR); } // === 4.2.1 DATOS DE CONTACTO / DOMICILIO ======================= $extraText = "Rio Duero No. 31, Col. Cuauhtémoc, 06500 Ciudad de México, México. Tel.: 55 5242 0700 | 55 5208 1700\n"; $extraText .= "Blvd. de Los Reyes 6431 Oficina 1307, San Bernardino Tlaxcalancingo, 72820 San Andrés Cholula, Puebla. Tel.: 22 2241 9005\n"; $extraText .= $result; // Opcional: título $pdf->SetFont('arial','B',10); $pdf->SetTextColor(0,0,0); $curY = $pdf->GetY() + 0.90; // un pequeño espacio después del régimen fiscal $pdf->SetXY($X + 1.05, $curY); $pdf->Cell(0, 0.25, utf8_decode("DOMICILIO / CONTACTO:"), 0, 1, 'L'); $pdf->SetFont('arial','',9); $pdf->SetXY($X + 1.05, $pdf->GetY() + 0.2); $pdf->MultiCell(15, 0.32, utf8_decode($extraText), 0, 'L'); // Aumenté el ancho a 15 (ajusta según necesidad) #============================================================================================================ #== 4.4.1 CFDI Relacionados. #============================================================================================================ #============================================================================================================ #== 4.3 REGISTROS DE CFDI RELACIONADOS #============================================================================================================ if($Tipo_Relacion <> "") { $Y = $pdf->GetY()+0.50; $pdf->SetTextColor(0,0,0); $pdf->SetFont('arial','B',11); $pdf->SetXY($X+1.05,$Y); $pdf->Cell(1, 0.25, "CFDI RELACIONADOS", 0, 1,'L', 0); $Y = $pdf->GetY()+0.20; // ==================== NUEVO: TABLA DE CFDI RELACIONADOS ==================== // Verificar si tenemos datos de CFDI relacionados desde el header $cfdiRelacionadosExtras = $__PDF_EXTRAS['cfdi_relacionados'] ?? null; if ($cfdiRelacionadosExtras && !empty($cfdiRelacionadosExtras['uuids'])) { // Configurar estilos de la tabla $pdf->SetFont('arial','B',9); $pdf->SetFillColor(223,234,247); // Color de fondo para encabezados // Dibujar encabezados de la tabla $pdf->SetXY($X+1.05, $Y); $pdf->Cell(4.0, 0.35, "TIPO RELACION", 1, 0, 'C', true); $pdf->Cell(14.0, 0.35, "FOLIO FISCAL", 1, 1, 'C', true); $Y = $pdf->GetY(); // Dibujar filas de datos $pdf->SetFont('arial','',8); $pdf->SetFillColor(255,255,255); foreach ($cfdiRelacionadosExtras['uuids'] as $uuidRelacionado) { if (!empty($uuidRelacionado['uuid'])) { $pdf->SetXY($X+1.05, $Y); $pdf->Cell(4.0, 0.35, $Tipo_Relacion, 1, 0, 'C', true); $pdf->Cell(14.0, 0.35, $uuidRelacionado['uuid'], 1, 1, 'L', true); $Y = $pdf->GetY(); } } $Y += 0.20; // Espacio después de la tabla } else { // Fallback: mostrar sin tabla si no hay datos en el header $pdf->SetFont('arial','',9); $pdf->SetXY($X+6.0,$Y-0.20); $pdf->Cell(1, 0.25, utf8_decode("Tipo de Relación: ").$Tipo_Relacion, 0, 1,'L', 0); $TotRegs = count($ArrayUUID); for ($i=0; $i<$TotRegs; $i++) { $YY = $pdf->GetY()+0.10; $Y = $YY; $pdf->SetFont('arial','',8); $pdf->SetTextColor(0,0,0); $pdf->SetXY($X+1.05,$Y); $pdf->Cell(1.5, 0.30, $ArrayUUID[$i], 0, 1,'L', 0); } } // ==================== FIN TABLA DE CFDI RELACIONADOS ==================== } #============================================================================================================ #== 4.5 IMPRESIÓN DE LOS DATOS INFERIORES. #============================================================================================================ if ($Puntero<18.5) { if ($filename != "") { DatosInf($pdf, $filename, 0, $selloCFD, $selloSAT, $CadOri, $PaginaWeb); } } if ($Puntero>=18.5 && $Puntero<23.5) { $pdf->AddPage(); //$pdf->image("archs_graf/FondoTenue.jpg",1, 5 , 19.5, 18); if ($filename != "") { DatosInf($pdf, $filename, -20.5, $selloCFD, $selloSAT, $CadOri, $PaginaWeb); } } if ($Puntero>=23.5) { if ($filename != "") { DatosInf($pdf, $filename, $Puntero -41, $selloCFD, $selloSAT, $CadOri, $PaginaWeb); } } // Limpiar buffer de salida por si hay algo antes ob_clean(); // Configurar headers para PDF header('Content-Type: application/pdf'); header('Content-Disposition: inline; filename="cfdi_'.$Fact_NoFact.'.pdf"'); header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0'); header('Pragma: no-cache'); header('Expires: 0'); // Generar y enviar el PDF directamente $pdfContent = $pdf->Output('', 'S'); // 'S' para obtener como string // Opcional: Limpiar archivo temporal del QR si existe if (file_exists($filename)) { unlink($filename); } // Enviar el contenido del PDF echo $pdfContent; exit; #============================================================================================================ #== FUNCIONES GENERALES #============================================================================================================ function Titulos($pdf, $Y){ $Y = $Y + 0.24; $pdf->SetTextColor(0,0,0); $pdf->SetFont('arial','B',8); $pdf->SetXY(0.75,$Y); $pdf->Cell(1.5, 0.30, "Cant.", 0, 1,'C', 0); $pdf->SetXY(1.95,$Y); $pdf->Cell(1.8, 0.30, "Unidad", 0, 1,'L', 0); $pdf->SetXY(4.5,$Y); $pdf->Cell(3.3, 0.30, "Clave", 0, 1,'L', 0); $pdf->SetXY(6.2,$Y); $pdf->Cell(1.7, 0.30, utf8_decode("V. Unitario"), 0, 1,'R', 0); $pdf->SetXY(8.0,$Y); $pdf->Cell(1.8, 0.30, utf8_decode("Importe"), 0, 1,'R', 0); $pdf->SetXY(10.6,$Y); // $pdf->Cell(1.8, 0.30, utf8_decode("Descuento"), 0, 1,'R', 0); $pdf->SetXY(12.8,$Y); $pdf->Cell(1.0, 0.30, utf8_decode("Objeto"), 0, 1,'L', 0); $pdf->SetXY(13.75,$Y); $pdf->Cell(1.7, 0.30, utf8_decode("Base"), 0, 1,'R', 0); $pdf->SetXY(15.5,$Y); $pdf->Cell(1.0, 0.30, utf8_decode("Impto"), 0, 1,'L', 0); $pdf->SetXY(16.4,$Y); $pdf->Cell(1.0, 0.30, utf8_decode("Tipo"), 0, 1,'L', 0); $pdf->SetXY(16.8,$Y); $pdf->Cell(1.7, 0.30, utf8_decode("Tasa"), 0, 1,'R', 0); $pdf->SetXY(18.5,$Y); $pdf->Cell(1.8, 0.30, utf8_decode("Importe"), 0, 1,'R', 0); } function SubTotales($pdf, $Y, $subTotal, $descuento, $ImporteTotalIVA, $ImporteTotalIEPS, $total, $formaDePago, $metodoDePago, $NumCtaPago, $Puntero, $moneda, $tipoCambio, $ImporteTotalISR, $ImporteTotalIVAR){ $X = 0; $Y = $Y - 0.00; //== Subtotales ============================================================ $pdf->SetTextColor(0,0,0); $pdf->SetFont('arial','B',9); $pdf->SetXY($X+16.27,$Y+0.35); // $pdf->Cell(1.7, 0.30, "Descuento:", 0, 1,'R', 0); $pdf->SetFont('arial','',9); $pdf->SetXY($X+16.16+2.5,$Y+0.35); // $pdf->Cell(1.7, 0.30, number_format($descuento,2), 0, 1,'R', 0); $pdf->SetFont('arial','B',9); $pdf->SetXY($X+16.27,$Y+0.35+0.5); $pdf->Cell(1.7, 0.30, "Subtotal:", 0, 0,'R', 0); $pdf->SetFont('arial','',9); $pdf->SetXY($X+16.16+2.5,$Y+0.35+0.5); $pdf->Cell(1.7, 0.30, number_format($subTotal-$descuento,2), 0, 1,'R', 0); if ($ImporteTotalIVAR > 0) { $pdf->SetFont('arial','B',9); $pdf->SetXY($X+16.27,$Y+0.35+(0.5*2)); $pdf->Cell(1.7, 0.30, "IVA RETENIDO:", 0, 0,'R', 0); $pdf->SetFont('arial','',9); $pdf->SetXY($X+16.16+2.5,$Y+0.35+(0.5*2)); $pdf->Cell(1.7, 0.30, number_format($ImporteTotalIVAR,2), 0, 1,'R', 0); } if ($ImporteTotalISR > 0) { $pdf->SetFont('arial','B',9); $pdf->SetXY($X+16.27,$Y+0.35+(0.5*2)); $pdf->Cell(1.7, 0.30, "IMPUESTOS RETENIDOS:", 0, 0,'R', 0); $pdf->SetFont('arial','',9); $pdf->SetXY($X+16.16+2.5,$Y+0.35+(0.5*2)); $pdf->Cell(1.7, 0.30, number_format($ImporteTotalISR,2), 0, 1,'R', 0); } $pdf->SetFont('arial','B',9); $pdf->SetXY($X+16.27,$Y+0.35+(0.5*3)); $pdf->Cell(1.7, 0.30, "IVA:", 0, 0,'R', 0); $pdf->SetFont('arial','',9); $pdf->SetXY($X+16.16+2.5,$Y+0.35+(0.5*3)); $pdf->Cell(1.7, 0.30, number_format($ImporteTotalIVA,2), 0, 1,'R', 0); $pdf->SetFont('arial','B',9); $pdf->SetXY($X+16.27,$Y+0.37+(0.5*4)); $pdf->Cell(1.7, 0.30, "Total:", 0, 1,'R', 0); $pdf->SetFont('arial','',9); $pdf->SetXY($X+16.16+2.5,$Y+0.37+(0.5*4)); $pdf->Cell(1.7, 0.30, number_format($total,2), 0, 1,'R', 0); //================================================================ $pdf->SetFont('arial','B',9); $pdf->SetXY($X+1,$Y+0.35); $pdf->Cell(1.7, 0.30, "Total con letra: ", 0, 1,'L', 0); $pdf->SetFont('arial','',8); $pdf->SetXY($X+1,$Y+0.35+0.40); //$pdf->Cell(1.7, 0.30, NumLet($total,$moneda), 0, 1,'L', 0); $pdf->Cell(1.7, 0.30, convertirNumeroLetra($total,$moneda), 0, 1,'L', 0); $pdf->SetFont('arial','B',9); $pdf->SetXY($X+1,$Y+0.35+0.40+0.8); $pdf->Cell(1.7, 0.30, "Forma de pago:", 0, 1,'L', 0); $pdf->SetFont('arial','',9); $pdf->SetXY($X+3.6,$Y+0.35+0.40+0.8); $pdf->Cell(1.7, 0.30, utf8_decode($formaDePago), 0, 1,'L', 0); $pdf->SetFont('arial','B',9); $pdf->SetXY($X+9.15,$Y+0.35+0.40+0.8); $pdf->Cell(1.7, 0.30, "Moneda:", 0, 1,'L', 0); $pdf->SetFont('arial','',9); $pdf->SetXY($X+10.7,$Y+0.35+0.40+0.8); $pdf->Cell(1.7, 0.30, utf8_decode($moneda), 0, 1,'L', 0); $pdf->SetFont('arial','B',9); $pdf->SetXY($X+1,$Y+0.35+0.40+1.3); $pdf->Cell(1.7, 0.30, utf8_decode("Método de pago:"), 0, 1,'L', 0); $pdf->SetFont('arial','',9); $pdf->SetXY($X+3.76,$Y+0.35+0.40+1.3); $pdf->Cell(1.7, 0.30, utf8_decode($metodoDePago), 0, 1,'L', 0); $pdf->SetFont('arial','B',9); $pdf->SetXY($X+8,$Y+0.35+0.40+1.3); $pdf->Cell(1.7, 0.30, utf8_decode("Tipo de Cambio:"), 0, 1,'L', 0); $pdf->SetFont('arial','',9); $pdf->SetXY($X+10.7,$Y+0.35+0.40+1.3); $pdf->Cell( 1.7, 0.30, !empty($tipoCambio) ? number_format($tipoCambio, 4) : "1.0000", 0, 1, 'L', 0 ); $pdf->SetDrawColor(128,0,0); $pdf->SetLineWidth(0.05); $pdf->RoundedRect($X+1, $Y+0.15, 19.4, 2.60, 0.2, ''); $pdf->SetDrawColor(0,0,0); $pdf->SetLineWidth(0.02); if (strlen($NumCtaPago)>0){ $pdf->SetFont('arial','B',9); $pdf->SetXY($X+1,$Y+0.35+0.40+1.8); $pdf->Cell(1.7, 0.30, utf8_decode("Número de cuenta:"), 0, 1,'L', 0); $pdf->SetFont('arial','',9); $pdf->SetXY($X+3.76+0.3,$Y+0.35+0.40+1.8); $pdf->Cell(1.7, 0.30, $NumCtaPago, 0, 1,'L', 0); } } function DatosInf($pdf, $filename, $Y, $selloCFD, $selloSAT, $CadOri, $PaginaWeb){ $pdf->SetFont('arial','B',9); $pdf->SetXY(1.2,22.9+$Y-0.2 -0.7); $pdf->Cell(1.7,0.30, "Sello digital del CFDI:", 0, 1,'L', 0); $pdf->SetFont('arial','',7); $pdf->SetXY(1.2,+22.9+0.35+$Y-0.2 -0.7); $pdf->MultiCell(19.4, 0.25, $selloCFD, 0, 'L', 0); $pdf->SetFont('arial','B',9); $pdf->SetXY(4.2,21.9+2+$Y -0.7); $pdf->Cell(1.7, 0.30, "Sello del SAT:", 0, 1,'L', 0); $pdf->SetFont('arial','',7); $pdf->SetXY(4.2,21.9+0.35+2+$Y -0.7); $pdf->MultiCell(16.1, 0.25, $selloSAT, 0, 'L', 0); $pdf->SetFont('arial','B',9); $pdf->SetXY(4.2,25+0.5+$Y -0.7); $pdf->Cell(1.7, 0.30, utf8_decode("Cadena original del complemento de certificación digital del SAT:"), 0, 1,'L', 0); $pdf->SetFont('arial','',7); $pdf->SetXY(4.2,25.1+0.5+0.25+$Y -0.7); $pdf->MultiCell(16.1, 0.25, $CadOri, 0, 'L', 0); if ($filename != "") { $pdf->Image($filename,1.2,23.8+$Y -0.7,3,3,'PNG'); } } function ProcesImpTot($ImpTot){ $ImpTot = number_format($ImpTot, 4); $ArrayImpTot = explode(".", $ImpTot); $NumEnt = $ArrayImpTot[0]; $NumDec = ProcesDecFac($ArrayImpTot[1]); return $NumEnt.".".$NumDec; } function ProcesDecFac($Num){ $FolDec = ""; if ($Num < 10){$FolDec = "00000".$Num;} if ($Num > 9 and $Num < 100){$FolDec = $Num."0000";} if ($Num > 99 and $Num < 1000){$FolDec = $Num."000";} if ($Num > 999 and $Num < 10000){$FolDec = $Num."00";} if ($Num > 9999 and $Num < 100000){$FolDec = $Num."0";} return $FolDec; } function VerifStatusCFDI($pdf, $StatusCFDI){ if ($StatusCFDI=="CANCELADO"){ $pdf->SetLineWidth(0.1); $pdf->SetDrawColor(200,0,0); $pdf->SetTextColor(200,0,0); $pdf->SetFont('verdana','',53); $pdf->RoundedRect(4.4, 7.4-2.5, 12.6, 2.05, 0.4, ''); $pdf->SetXY(1,8.4-2.5); $pdf->Cell(19.4, 0.30, "CANCELADO", 0, 1,'C', 0); $pdf->SetLineWidth(0.02); $pdf->SetDrawColor(0,0,0); $pdf->SetTextColor(0,0,0); } }