"ValorUnitario"=>$abdDatArt[$i]["valorUnitario"], "Importe"=>$abdDatArt[$i]["importe"], "ObjetoImp"=>utf8_decode($abdDatArt[$i]["ObjetoImp"]) ) ); } $complemento = $xml->createElement("cfdi:Complemento"); $complemento = $root->appendChild($complemento); $Pagos = $xml->createElement("pago20:Pagos"); $Pagos = $complemento->appendChild($Pagos); cargaAtt($Pagos, array("xmlns:pago20"=>"http://www.sat.gob.mx/Pagos20", "Version"=>"2.0" ) ); $totales = $xml->createElement("pago20:Totales"); $total = $Pagos->appendChild($totales); $lSoloTotal = true; if($TotalRetencionesIVA > 0.00) { $lSoloTotal = false; cargaAtt($total, array( "TotalRetencionesIVA"=>number_format($TotalRetencionesIVA,2,'.',''), "MontoTotalPagos"=>number_format($MontoTotalPagos,2,'.','') ) ); } if($TotalRetencionesISR > 0.00 && $TotalTrasladosBaseIVA16 == 0.00) { $lSoloTotal = false; cargaAtt($total, array( "TotalRetencionesISR"=>number_format($TotalRetencionesISR,2,'.',''), "MontoTotalPagos"=>number_format($MontoTotalPagos,2,'.','') ) ); } if($TotalRetencionesIEPS > 0.00) { $lSoloTotal = false; cargaAtt($total, array( "TotalRetencionesIEPS"=>number_format($TotalRetencionesIEPS,2,'.',''), "MontoTotalPagos"=>number_format($MontoTotalPagos,2,'.','') ) ); } if($TotalTrasladosBaseIVA16 > 0.00) { $lSoloTotal = false; if($TotalRetencionesISR > 0.00) { cargaAtt($total, array( "TotalRetencionesISR"=>number_format($TotalRetencionesISR,2,'.',''), "TotalTrasladosBaseIVA16"=>number_format($TotalTrasladosBaseIVA16,2,'.',''), "TotalTrasladosImpuestoIVA16"=>number_format($TotalTrasladosImpuestoIVA16,2,'.',''), "MontoTotalPagos"=>number_format($MontoTotalPagos,2,'.','') ) ); } else { cargaAtt($total, array( "TotalTrasladosBaseIVA16"=>number_format($TotalTrasladosBaseIVA16,2,'.',''), "TotalTrasladosImpuestoIVA16"=>number_format($TotalTrasladosImpuestoIVA16,2,'.',''), "MontoTotalPagos"=>number_format($MontoTotalPagos,2,'.','') ) ); } } if($TotalTrasladosBaseIVA8 > 0.00) { $lSoloTotal = false; cargaAtt($total, array( "TotalTrasladosBaseIVA8"=>number_format($TotalTrasladosBaseIVA8,2,'.',''), "TotalTrasladosImpuestoIVA8"=>number_format($TotalTrasladosImpuestoIVA8,2,'.',''), "MontoTotalPagos"=>number_format($MontoTotalPagos,2,'.','') ) ); } if($TotalTrasladosBaseIVA0 > 0.00) { $lSoloTotal = false; cargaAtt($total, array( "TotalTrasladosBaseIVA0"=>number_format($TotalTrasladosBaseIVA0,2,'.',''), "TotalTrasladosImpuestoIVA0"=>number_format($TotalTrasladosImpuestoIVA0,2,'.',''), "MontoTotalPagos"=>number_format($MontoTotalPagos,2,'.','') ) ); } if($TotalTrasladosBaseIVAExento > 0.00) { $lSoloTotal = false; cargaAtt($total, array( "TotalTrasladosBaseIVAExento"=>number_format($TotalTrasladosBaseIVAExento,2,'.',''), "MontoTotalPagos"=>number_format($MontoTotalPagos,2,'.','') ) ); } if($lSoloTotal == true) { $lSoloTotal = false; cargaAtt($total, array("MontoTotalPagos"=>number_format($MontoTotalPagos,2,'.',''))); } $pago = $xml->createElement("pago20:Pago"); $pago = $Pagos->appendChild($pago); if ($MonedaP == "MXN") { cargaAtt($pago, array( "FechaPago"=>$FechaPago, "FormaDePagoP"=>$FormaDePagoP, "MonedaP"=>$MonedaP, "TipoCambioP"=>1, "Monto"=>number_format($Monto,2,'.',''), "NumOperacion"=>$NumOperacion, "RfcEmisorCtaOrd"=>$RfcEmisorCtaOrd, "NomBancoOrdExt"=>$NomBancoOrdExt, "CtaOrdenante"=>$CtaOrdenante, "RfcEmisorCtaBen"=>$RfcEmisorCtaBen, "CtaBeneficiario"=>$CtaBeneficiario, "TipoCadPago"=>$TipoCadPago, "CertPago"=>$CertPago, "CadPago"=>$CadPago, "SelloPago"=>$SelloPago, "xmlns:pago20"=>"http://www.sat.gob.mx/Pagos20" ) ); } else { cargaAtt($pago, array( "FechaPago"=>$FechaPago, "FormaDePagoP"=>$FormaDePagoP, "MonedaP"=>$MonedaP, "TipoCambioP"=>number_format($TipoCambioP,6,'.',''), "Monto"=>number_format($Monto,2,'.',''), "NumOperacion"=>$NumOperacion, "RfcEmisorCtaOrd"=>$RfcEmisorCtaOrd, "NomBancoOrdExt"=>$NomBancoOrdExt, "CtaOrdenante"=>$CtaOrdenante, "RfcEmisorCtaBen"=>$RfcEmisorCtaBen, "CtaBeneficiario"=>$CtaBeneficiario, "TipoCadPago"=>$TipoCadPago, "CertPago"=>$CertPago, "CadPago"=>$CadPago, "SelloPago"=>$SelloPago, "xmlns:pago20"=>"http://www.sat.gob.mx/Pagos20" ) ); } $impuestosP = false; $RDR_ImpuestoDR = ""; $RDR_ImporteDR = 0.00; $TDR_BaseDR = 0.00; $TDR_ImpuestoDR = ""; $TDR_TipoFactorDR = ""; $TDR_TasaOCuotaDR = 0.00; $TDR_ImporteDR = 0.00; #== Ciclo "for", recopilación de datos de documento e integración de sus respectivos nodos = $lImpuestosDR = false; for ($i=0; $icreateElement("pago20:DoctoRelacionado"); $doctoRel = $pago->appendChild($doctoRel); if($abdDatDoc[$i]["MonedaDR"] == $MonedaP) { cargaAtt($doctoRel, array( "IdDocumento"=>utf8_decode($abdDatDoc[$i]["IdDocumento"]), "Serie"=>$abdDatDoc[$i]["Serie"], "Folio"=>$abdDatDoc[$i]["Folio"], "MonedaDR"=>utf8_decode($abdDatDoc[$i]["MonedaDR"]), //este valor lo cambié porque si los valores de la moneda son iguales la equivalencia debe de ser 1 pero se tiene que verificar // "EquivalenciaDR"=>$abdDatDoc[$i]["TipoCambioDR"], "EquivalenciaDR"=>1, "NumParcialidad"=>$abdDatDoc[$i]["NumParcialidad"], "ImpSaldoAnt"=>number_format($abdDatDoc[$i]["ImpSaldoAnt"],2,'.',''), "ImpPagado"=>number_format($abdDatDoc[$i]["ImpPagado"],2,'.',''), "ImpSaldoInsoluto"=>number_format($abdDatDoc[$i]["ImpSaldoInsoluto"],2,'.',''), "ObjetoImpDR"=>$abdDatDoc[$i]["ObjetoImpDR"] ) ); } else { cargaAtt($doctoRel, array( "IdDocumento"=>utf8_decode($abdDatDoc[$i]["IdDocumento"]), "Serie"=>$abdDatDoc[$i]["Serie"], "Folio"=>$abdDatDoc[$i]["Folio"], "MonedaDR"=>utf8_decode($abdDatDoc[$i]["MonedaDR"]), "EquivalenciaDR"=>$abdDatDoc[$i]["TipoCambioDR"], "NumParcialidad"=>$abdDatDoc[$i]["NumParcialidad"], "ImpSaldoAnt"=>number_format($abdDatDoc[$i]["ImpSaldoAnt"],2,'.',''), "ImpPagado"=>number_format($abdDatDoc[$i]["ImpPagado"],2,'.',''), "ImpSaldoInsoluto"=>number_format($abdDatDoc[$i]["ImpSaldoInsoluto"],2,'.',''), "ObjetoImpDR"=>$abdDatDoc[$i]["ObjetoImpDR"] ) ); } // Verificamos si aplica desglose de impuestos o no if($abdDatDoc[$i]["ObjetoImpDR"] == "02") { $impuestosP = true; $impuestosDR = $xml->createElement("pago20:ImpuestosDR"); $impuestosDR = $doctoRel->appendChild($impuestosDR); if($abdDatDoc[$i]["RDR_ImpuestoDR"] == "001") { $retencionesDR = $xml->createElement("pago20:RetencionesDR"); $retencionesDR = $impuestosDR->appendChild($retencionesDR); $retencionDR = $xml->createElement("pago20:RetencionDR"); $retencionDR = $retencionesDR->appendChild($retencionDR); $RDR_ImpuestoDR = $abdDatDoc[$i]["RDR_ImpuestoDR"]; $RDR_ImporteDR = $RDR_ImporteDR + $abdDatDoc[$i]["RDR_ImporteDR"]; cargaAtt($retencionDR, array( "BaseDR"=>number_format($abdDatDoc[$i]["RDR_BaseDR"],2,'.',''), "ImpuestoDR"=>$abdDatDoc[$i]["RDR_ImpuestoDR"], "TipoFactorDR"=>$abdDatDoc[$i]["RDR_TipoFactorDR"], "TasaOCuotaDR"=>number_format($abdDatDoc[$i]["RDR_TasaOCuotaDR"],6,'.',''), "ImporteDR"=>number_format($abdDatDoc[$i]["RDR_ImporteDR"],2,'.','') ) ); } if($abdDatDoc[$i]["TDR_ImpuestoDR"] == "02") { $trasladosDR = $xml->createElement("pago20:TrasladosDR"); $trasladosDR = $impuestosDR->appendChild($trasladosDR); $trasaldoDR = $xml->createElement("pago20:TrasladoDR"); $trasaldoDR = $trasladosDR->appendChild($trasaldoDR); $TDR_BaseDR = $TDR_BaseDR + $abdDatDoc[$i]["TDR_BaseDR"]; $TDR_ImpuestoDR = $abdDatDoc[$i]["TDR_ImpuestoDR"]; $TDR_TipoFactorDR = $abdDatDoc[$i]["TDR_TipoFactorDR"]; $TDR_TasaOCuotaDR = $abdDatDoc[$i]["TDR_TasaOCuotaDR"]; $TDR_ImporteDR = $TDR_ImporteDR + $abdDatDoc[$i]["TDR_ImporteDR"]; cargaAtt($trasaldoDR, array( "BaseDR"=>number_format($abdDatDoc[$i]["TDR_BaseDR"],2,'.',''), "ImpuestoDR"=>$abdDatDoc[$i]["TDR_ImpuestoDR"], "TipoFactorDR"=>$abdDatDoc[$i]["TDR_TipoFactorDR"], "TasaOCuotaDR"=>number_format($abdDatDoc[$i]["TDR_TasaOCuotaDR"],6,'.',''), "ImporteDR"=>number_format($abdDatDoc[$i]["TDR_ImporteDR"],2,'.','') ) ); } } } // Resumen de Impuestos en caso de Aplicar. if($impuestosP == true) { $impuestosP = $xml->createElement("pago20:ImpuestosP"); $impuestosP = $pago->appendChild($impuestosP); if($RDR_ImpuestoDR == "001") { if ($MonedaP == "MXN" && $MonedaDR != "MXN") { $RDR_ImporteDR = round($RDR_ImporteDR * (1/$TipoCambioDR), 2, PHP_ROUND_HALF_UP); } $retencionesP = $xml->createElement("pago20:RetencionesP"); $retencionesP = $impuestosP->appendChild($retencionesP); $retencionP = $xml->createElement("pago20:RetencionP"); $retencionP = $retencionesP->appendChild($retencionP); cargaAtt($retencionP, array( "ImpuestoP"=>$RDR_ImpuestoDR, "ImporteP"=>number_format($RDR_ImporteDR,2,'.','') ) ); } if($TDR_ImpuestoDR == "002") { if ($MonedaP == "MXN" && $MonedaDR != "MXN") { $TDR_BaseDR = round($TDR_BaseDR * (1/$TipoCambioDR), 2, PHP_ROUND_HALF_UP); $TDR_ImporteDR = round($TDR_ImporteDR * (1/$TipoCambioDR), 2, PHP_ROUND_HALF_UP); } if ($MonedaP != "MXN" && $MonedaDR == "MXN") { $TDR_BaseDR = round($TDR_BaseDR / $TipoCambioDR, 6, PHP_ROUND_HALF_UP); $TDR_ImporteDR = round($TDR_ImporteDR / $TipoCambioDR, 6, PHP_ROUND_HALF_UP); } $trasladosP = $xml->createElement("pago20:TrasladosP"); $trasladosP = $impuestosP->appendChild($trasladosP); $trasladoP = $xml->createElement("pago20:TrasladoP"); $trasladoP = $trasladosP->appendChild($trasladoP); cargaAtt($trasladoP, array( "BaseP"=>number_format($TDR_BaseDR,6,'.',''), "ImpuestoP"=>$TDR_ImpuestoDR, "TipoFactorP"=>$TDR_TipoFactorDR, "TasaOCuotaP"=>number_format($TDR_TasaOCuotaDR,6,'.',''), "ImporteP"=>number_format($TDR_ImporteDR,6,'.','') ) ); } } #== 10.7 Termina de conformarse la "Cadena original" con doble || $cadena_original .= "|"; if ($tipoTest > 0){ #=== Muestra la cadena original (opcional a mostrar) ======================= echo '
'; echo 'CADENA ORIGINAL'; echo '
'; echo '
'; echo $cadena_original; echo '

'; } #=== Muestra la cadena original (opcional a mostrar) ======================= #== 10.8 Proceso para obtener el sello digital del archivo .pem.key ========= $keyid = openssl_get_privatekey(file_get_contents($SendaPEMS.$file_key)); openssl_sign($cadena_original, $crypttext, $keyid, OPENSSL_ALGO_SHA256); openssl_free_key($keyid); #== 10.9 Se convierte la cadena digital a Base 64 =========================== $sello = base64_encode($crypttext); if ($tipoTest > 0){ #=== Muestra el sello (opcional a mostrar) ================================= echo '
'; echo 'SELLO'; echo '
'; echo '
'; echo $sello; echo '

'; } #== 10.10 Proceso para extraer el certificado del sello digital ================== $file = $SendaPEMS.$file_cer; // Ruta al archivo $datos = file($file); $certificado = ""; $carga=false; for ($i=0; $i 0){ #=== Muestra el certificado del sello digital (opcional a mostrar) ========= echo '
'; echo 'CERTIFICADO DEL SELLO DIGITAL'; echo '
'; echo '
'; echo $certificado; echo '

'; } #== 10.11 Se continua con la integración de nodos =========================== $root->setAttribute("Sello",$sello); $root->setAttribute("Certificado",$certificado); # Certificado. #== Fin de la integración de nodos ========================================= #=== 10.12 Se guarda el archivo .XML antes de ser timbrado ======================= $NomArchCFDI = $SendaCFDI."PreCFDI-33_".$NoFac.".xml"; $NomArchPDF1 = $SendaCFDI."VP_CFDI_".$fact_serie.str_pad($fact_folio, 6, "0", STR_PAD_LEFT)."_".$invoiceNumber.".pdf"; $NomArchXML = "PreCFDI-33_".$NoFac.".xml"; $NomArchPDF = "CFDI_".$fact_serie.str_pad($fact_folio, 6, "0", STR_PAD_LEFT)."_CP.pdf"; $cfdi = $xml->saveXML(); $xml->formatOutput = true; $xml->save($NomArchCFDI); // Guarda el archivo .XML (sin timbrar) en el directorio predeterminado. unset($xml); #=== 10.13 Se dan permisos de escritura al archivo .xml. ========================= chmod($NomArchCFDI, 0777); ### 11. PROCESO DE TIMBRADO ######################################################## if ($tipoTest > 0){ #=== Se muestra el .XML antes de ser timbrado (opcional a mostrar)========== echo '
'; echo 'FACTURA .XML A TIMBRAR'; echo '
'; echo '
'; echo htmlspecialchars($cfdi); echo '

'; } #== 11.1 Se crea una variable de tipo DOM y se le carga el CFDI ================================= $xml2 = new DOMDocument(); $xml2->loadXML($cfdi); #== 11.2 Proceso de validación de la variable de tipo DOM (estructura del CFDI a timbrar) contra el esquema cfdv32.xsd ========================== $fname = $SendaCFDI."PreCFDI-33_".$NoFac.".xml"; if(!file_exists($fname)){ die(PHP_EOL . "File not found" . PHP_EOL . PHP_EOL); } $handle = fopen($fname, "r"); $sData = ''; #== 11.3 Convirtiendo el contenido del CFDI a BASE 64 ====================== while(!feof($handle)) $sData .= fread($handle, filesize($fname)); fclose($handle); //print_r($sData); $b64 = base64_encode($sData); $response = ''; if($abdDatPAC["tipoTim"] == 1){ ## Timbrado en producción $urlLocation = 'https://solucionfactible.com/ws/services/Timbrado'; } else { ## Timbrado en pruebas $urlLocation = 'https://testing.solucionfactible.com/ws/services/Timbrado'; } #== 11.5 Se lleva a cabo el timbrado del XML ============================ try { $client = new SoapClient($urlPAC); $client->__setLocation($urlLocation); $params = array('usuario' => $username, 'password' => $password, 'cfdiBase64'=>$b64, 'zip'=>False); $response = $client->__soapCall('timbrarBase64', array('parameters' => $params)); } catch (SoapFault $fault) { $j_array = array('code' => "400", "message" => $fault->faultcode."-".$fault->faultstring); $Resultado = json_encode($j_array); echo $Resultado; return; } $ret = $response->return; if($ret->status != 200) { $j_array = array('code' => "500", "message" => "ERROR EN EL PROCESO DE TIMBRADO. ".$ret->status." - ".$ret->mensaje); $Resultado = json_encode($j_array); echo $Resultado; return; } #=== 11.7 Muestra los resultados del timbrado del CFDI ========================= $RespServ = $ret->resultados->cfdiTimbrado; if($RespServ == NULL){ $j_array = array('code' => "600", "message" => "ERROR EN EL PROCESO DE TIMBRADO. status: ".$ret->status.", mensaje: ".$ret->mensaje.". ==> Resultado Timbrado: "." status: ".$ret->resultados->status.", mensaje: ".$ret->resultados->mensaje); $Resultado = json_encode($j_array); echo $Resultado; return; } if ($tipoTest > 0){ #== 12.5 Se muestra el .XML ya timbrado (CFDI V 3.2), opcional a mostrar ===== echo '
'; echo 'FACTURA .XML (CFDI) YA TIMBRADA'; echo '
'; echo '
'; echo htmlspecialchars($RespServ); echo '

'; } ## 12. PROCESOS POSTERIORES AL TIMBRADO ######################################## #== 12.1 Se asigna la respuesta del servidor a una variable de tipo DOM ==== $VarXML = new DOMDocument(); $VarXML->loadXML($RespServ); #== 12.2 Se graba la respuesta del servidor a un archivo .xml $VarXML->save($SendaCFDI."RespServ_".$NoFac.".xml"); chmod($SendaCFDI."RespServ_".$NoFac.".xml", 0777); $NomArchXML = "CFDI_".$fact_serie.str_pad($fact_folio, 6, "0", STR_PAD_LEFT)."_CP.xml"; $NomArchPDF = "CFDI_".$fact_serie.str_pad($fact_folio, 6, "0", STR_PAD_LEFT)."_CP.pdf"; $xmlt = new DOMDocument(); $xmlt->loadXML($RespServ); $xmlt->save($SendaCFDI.$NomArchXML); chmod($SendaCFDI.$NomArchXML, 0777); #== 12.7 Procesos para extraer datos del Timbre Fiscal del CFDI ========= $docXML = new DOMDocument(); //$docXML->load($SendaCFDI."Fact_CFDI_".$NoFac.".xml"); $docXML->load($SendaCFDI.$NomArchXML); $comprobante = $docXML->getElementsByTagName("TimbreFiscalDigital"); #== 12.8 Se obtienen contenidos de los atributos y se asignan a variables para ser mostrados ======= foreach($comprobante as $timFis){ $version_timbre = $timFis->getAttribute('Version'); $sello_SAT = $timFis->getAttribute('SelloSAT'); $cert_SAT = $timFis->getAttribute('NoCertificadoSAT'); $sello_CFD = $timFis->getAttribute('SelloCFD'); $tim_fecha = $timFis->getAttribute('FechaTimbrado'); $tim_uuid = $timFis->getAttribute('UUID'); $tim_RfcPac = $timFis->getAttribute('RfcProvCertif'); } #== 12.9 Se crea el archivo .PNG con codigo bidimensional ================================= $filename = "archs_graf/Img_".$tim_uuid.".png"; ### 13. CREACION DE PDF Y ENVIO DE CORREO CON XML Y PDF ########################### # 13.1 Creación del Archivo PDF //$url = 'http://64.235.39.50/aptusCFDIRF/wsComPagoPDF_VP_v33.php?NomArchXML='.$NomArchXML.'&NomArchPDF='.$NomArchPDF; if($TipPDFGen == 1) { $url = 'https://aptuslegal.app/aptusCFDIRF/'.$FormatoPDF.'.php?NomArchXML='.$NomArchXML.'&NomArchPDF='.$NomArchPDF.'&pDirRecep='.$sDireRecep .'&tipoCambioPDF='.$tipoCambioPDF; } else { $url = 'https://aptuslegal.app/aptusCFDIRF/'.$FormatoPDF.'.php?NomArchXML='.$NomArchXML.'&NomArchPDF='.$NomArchPDF .'&tipoCambioPDF='.$tipoCambioPDF; } $objCurl = curl_init(); curl_setopt($objCurl, CURLOPT_URL, $url); curl_setopt($objCurl, CURLOPT_HEADER, 0); curl_setopt($objCurl, CURLOPT_RETURNTRANSFER, true); curl_exec($objCurl); curl_close($objCurl); # 13.3 Envio del Archivos a Invoice de Zoho Creator # Primero el PDF $file_name_with_full_path = '/var/www/html/aptusCFDIRF/archs_cfdi/'.$NomArchPDF; //$request_url = 'https://creator.zoho.com/api/xml/fileupload/scope=creatorapi'; # Actualización a API V2 y OAuth JFA y FFR 2021-06-18 $request_url = 'https://creator.zoho.com/api/v2/'.$appOwner.'/'.$applnkname.'/report/CFDI_Pago_v33_Borradores/'.$bRecId.'/File_CFDI_PDF/upload'; if (function_exists('curl_file_create')) { // php 5.6+ $cFile = curl_file_create($file_name_with_full_path); } else { $cFile = '@' . realpath($file_name_with_full_path); } $post = array( 'file'=> $cFile); $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $request_url); //curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $post); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); #JFA: Cambiamos el método de Autenticación a OAuth curl_setopt($ch, CURLOPT_HTTPHEADER, array('Authorization: Zoho-oauthtoken ' . $access_token)); $r = curl_exec($ch); curl_close ($ch); # Segundo el XML $file_name_with_full_path = '/var/www/html/aptusCFDIRF/archs_cfdi/'.$NomArchXML; # Actualización a API V2 y OAuth JFA y FFR 2021-06-18 $request_url = 'https://creator.zoho.com/api/v2/'.$appOwner.'/'.$applnkname.'/report/CFDI_Pago_v33_Borradores/'.$bRecId.'/File_CFDI_XML/upload'; if (function_exists('curl_file_create')) { // php 5.6+ $cFile = curl_file_create($file_name_with_full_path); } else { $cFile = '@' . realpath($file_name_with_full_path); } $post = array( 'file'=> $cFile); $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $request_url); //curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $post); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); #JFA: Cambiamos el método de Autenticación a OAuth curl_setopt($ch, CURLOPT_HTTPHEADER, array('Authorization: Zoho-oauthtoken ' . $access_token)); $r = curl_exec($ch); curl_close ($ch); if ($paymentID != "") { # 13.4 Envio del Archivos a Invoice de Zoho Books # Primero actualizamos el access_token de Books #== Datos y Variables para OAuth Token $boa_ClientId = $abdDatGen["B_OAuth_client_id"]; $boa_ClientSecret = $abdDatGen["B_OAuth_client_secret"]; $boa_RefreshToken = $abdDatGen["B_OAuth_refresh_token"]; $boa_GrantType = $abdDatGen["B_OAuth_grant_type"]; $boa_RedirectUri = $abdDatGen["B_OAuth_redirect_uri"]; $boa_AuthUrl = "https://accounts.zoho.com/oauth/v2/token"; #---------------------------------------------------------------- # JFA: 2021-06-12 # Obtenemos el access_token #---------------------------------------------------------------- $boa_access_token = oauth($appOwner, 'ZBooks', $boa_RefreshToken, $boa_ClientId, $boa_ClientSecret, $boa_RedirectUri, $boa_GrantType, $boa_AuthUrl); //echo $access_token; # Primero el PDF $file_name_with_full_path = '/var/www/html/aptusCFDIRF/archs_cfdi/'.$NomArchPDF; $request_url = 'https://www.zohoapis.com/books/v3/customerpayments/'.$paymentID.'/attachment'; if (function_exists('curl_file_create')) { // php 5.6+ $cFile = curl_file_create($file_name_with_full_path); } else { $cFile = '@' . realpath($file_name_with_full_path); } $post = array( // 'authtoken' => $authtoken_ZB, 'organization_id' => $organi_id_ZB, 'can_send_in_mail' => 'true', 'attachment'=> $cFile); $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $request_url); //curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $post); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); #JFA: Cambiamos el método de Autenticación a OAuth curl_setopt($ch, CURLOPT_HTTPHEADER, array('Authorization: Zoho-oauthtoken ' . $boa_access_token)); $r = curl_exec($ch); curl_close ($ch); $ra = json_decode($r); $resultPDF = $ra->code.' - '.$ra->message; # Segundo el XML $file_name_with_full_path = '/var/www/html/aptusCFDIRF/archs_cfdi/'.$NomArchXML; $request_url = 'https://www.zohoapis.com/books/v3/customerpayments/'.$paymentID.'/attachment'; if (function_exists('curl_file_create')) { // php 5.6+ $cFile = curl_file_create($file_name_with_full_path); } else { $cFile = '@' . realpath($file_name_with_full_path); } $post = array( // 'authtoken' => $authtoken_ZB, 'organization_id' => $organi_id_ZB, 'can_send_in_mail' => 'true', 'attachment'=> $cFile); $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $request_url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $post); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_HTTPHEADER, array('Authorization: Zoho-oauthtoken ' . $boa_access_token)); $r = curl_exec($ch); curl_close ($ch); $ra = json_decode($r); $resultXML = $ra->code.' - '.$ra->message; } #== Se elimina los archivos de trabajo unlink($SendaCFDI."PreCFDI-33_".$NoFac.".xml"); unlink($SendaCFDI."RespServ_".$NoFac.".xml"); unlink($filename); $j_array = array('code' => "200", 'message' => "Proceso de creacion de CFDI fue exitoso", 'version_timbre' => $version_timbre, 'cert_SAT' => $cert_SAT, 'tim_fecha' => $tim_fecha, 'tim_uuid' => $tim_uuid, 'tim_RfcPac' => $tim_RfcPac, 'sello_SAT' => $sello_SAT, 'sello_CFD' => $sello_CFD); $Resultado = json_encode($j_array); echo $Resultado; return; ### 14. FUNCIONES DEL MÓDULO ######################################################### # 14.1 Función que integra los nodos al archivo .XML y forma la "Cadena original". function cargaAtt(&$nodo, $attr){ global $xml, $cadena_original; $quitar = array('sello'=>1, 'noCertificado'=>1, 'certificado'=>1, 'xmlns:pago10'=>1); 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); if (!isset($quitar[$key])) if (substr($key,0,3) != "xml" && substr($key,0,4) != "xsi:") $cadena_original .= $val . "|"; } } } # 14.2 Funciónes que da formato al "Importe total" como lo requiere el SAT para ser integrado al código QR. function ProcesImpTot($ImpTot){ $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; }