'; echo 'PROCESO DE TIMBRADO, FACTURA DE CONTADO. CFDI VERSIÓN 4.0'; echo ''; echo 'LogoSAT'; ### 1. CONFIGURACIÓN INICIAL ###################################################### # 1.1 Configuración de zona horaria date_default_timezone_set('America/Mexico_City'); $Fec1 = date("d/m/Y"); $Fec2 = date("Y/m/d"); $Hora = date("H:i:s"); echo $Fec1." | ".$Hora."

"; # 1.2 Muestra la zona horaria predeterminada del servidor (opcional a mostrar) echo '
'; echo 'ZONA HORARIA PREDETERMINADA'; echo '
'; echo '
'; echo date_default_timezone_get(); echo '

'; ### 2. ASIGNACIÓN DE VALORES A VARIABLES ################################################### $SendaPEMS = "archs_pem/"; // 2.1 Directorio en donde se encuentran los archivos *.cer.pem y *.key.pem (para efectos de demostración se utilizan los que proporciona el SAT para pruebas). $SendaCFDI = "archs_cfdi/"; // 2.2 Directorio en donde se almacenarán los archivos *.xml (CFDIs). $SendaGRAFS = "archs_graf/"; // 2.3 Directorio en donde se almacenan los archivos .jpg (logo de la empresa) y .png (códigos bidimensionales). // 2.5 Datos de acceso del usuario (proporcionados por www.finkok.com) modo de integración (para pruebas) o producción. $username = "appwebpuntodeventa@gmail.com"; $password = "appPVweb@440"; ### MUESTRA LOS DATOS DEL USUARIO QUE ESTÁ TIMBRANDO (OPCIONAL A MOSTRAR) ###### echo '
'; echo 'DATOS DEL USUARIO QUE ESTÁ TIMBRANDO'; echo '
'; echo '
'; echo 'USUARIO: '.$username."
"; echo 'PASSWORD: '.$password."
"; echo '

'; ### 3. DEFINICIÓN DE VARIABLES INICIALES ########################################## $noCertificado = "30001000000400002434"; // 3.1 Número de certificado. $file_cer = "EKU9003173C9.cer.pem"; // 3.2 Nombre del archivo .cer.pem $file_key = "EKU9003173C9.key.pem"; // 3.3 Nombre del archivo .cer.key ################################################################################### ### 4. DATOS GENERALES DE LA FACTURA ################################################## $fact_serie = "A"; // 4.1 Número de serie. $fact_folio = mt_rand(1000, 9999); // 4.2 Número de folio (para efectos de demostración se asigna de manera aleatoria). $NoFac = $fact_serie.$fact_folio; // 4.3 Serie de la factura concatenado con el número de folio. $fact_tipcompr = "I"; // 4.4 Tipo de comprobante. $fact_exportacion = "01"; // 4.5 Atributo requerido para expresar si el comprobante ampara una operación de exportación. $tasa_iva = 16; // 4.6 Tasa del impuesto IVA. $subTotal = 0; // 4.7 Subtotal, suma de los importes antes de descuentos e impuestos (se calculan mas abajo). $descuento = 0; // 4.8 Descuento (se calculan mas abajo). $IVA = 0; // 4.9 IVA, suma de los impuestos (se calculan mas abajo). $total = 0; // 4.10 Total, Subtotal - Descuentos + Impuestos (se calculan mas abajo). $fecha_fact = date("Y-m-d")."T".date("H:i:s"); // 4.11 Fecha y hora de facturación. $NumCtaPago = "6473"; // 4.12 Número de cuenta (sólo últimos 4 dígitos, opcional). $condicionesDePago = "CONDICIONES"; // 4.13 Condiciones de pago. $formaDePago = "01"; // 4.14 Forma de pago. $metodoDePago = "PUE"; // 4.15 Clave del método de pago. Consultar catálogos de métodos de pago del SAT. $TipoCambio = 1; // 4.16 Tipo de cambio de la moneda. $LugarExpedicion = "45079"; // 4.17 Lugar de expedición (código postal). $moneda = "MXN"; // 4.18 Moneda $totalImpuestosRetenidos = 0; // 4.19 Total de impuestos retenidos (se calculan mas abajo). $totalImpuestosTrasladados = 0; // 4.20 Total de impuestos trasladados (se calculan mas abajo). ### No. DE CFDI ASIGNADO (CONTROL INTERNO) ###### echo '
'; echo 'No. DE CFDI'; echo '
'; echo '
'; echo $NoFac; echo '

'; ### 5. MUESTRA LA ZONA HORARIA PREDETERMINADA DEL SERVIDOR (OPCIONAL A MOSTRAR) ###### echo '
'; echo 'FECHA Y HORA DE SOLICITUD DE TIMBRADO'; echo '
'; echo '
'; echo $fecha_fact; // 5.1 Se muestra solo para consultar y confirmar que sea la correcta. echo '

'; ### 6. ARRAYS QUE CONTIENEN LOS ARTICULOS QUE FORMAN PARTE DE LA VENTA ##################### $Array_ClaveProdServ = ['23241610']; // 6.1 Clave del SAT correspondiente al artículo o servicio (consultar el catálogo de productos del SAT). $Array_NoIdentificacion = ['CORCOB']; // 6.2 Clave asignada al artículo o servicio, sistema local. $Array_Cantidad = ['5']; // 6.3 Cantidad. $Array_ClaveUnidad = ['H87']; // 6.4 Clave del SAT correspondiente a la unidad de medida (consultar el catálogo de productos del SAT). $Array_Unidad = ['PIEZA']; // 6.5 Descripción de la unidad de medida. $Array_Descripcion = ['CORTADOR DE TUBO DE COBRE']; // 6.6 Descripción del artículo o servicio. $Array_ValorUnitario = ['125.50']; // 6.7 Valor unitario del artículo o servicio. $Array_Importe = ['627.50']; // 6.8 Importe del artículo o servicio. $Array_Descuento = ['0']; // 6.9 Descuento aplicado al artículo o servicio. $Array_ObjetoImp = ['02']; // Atributo requerido para expresar si el pago del documento relacionado es objeto o no de impuesto. ### 7. ARRAYS QUE CONTIENEN LOS IMPUESTOS TRASLADADOS Y RETENIDOS POR CONCEPTO ############# // Trasladados. $ArrayTraslado_Base = ['627.50']; // 7.1 Atributo requerido para señalar la base para el cálculo del impuesto, la determinación de la base se realiza de acuerdo con las disposiciones fiscales vigentes. No se permiten valores negativos $ArrayTraslado_Impuesto = ['002']; // 7.2 Atributo requerido para señalar la clave del tipo de impuesto trasladado aplicable al concepto (consultar catálogos del SAT). $ArrayTraslado_TipoFactor = ['Tasa']; // 7.3 Atributo requerido para señalar la clave del tipo de factor que se aplica a la base del impuesto (consultar catálogos del SAT). $ArrayTraslado_TasaOCuota = ['0.160000']; // 7.4 Atributo condicional para señalar el valor de la tasa o cuota del impuesto que se traslada para el presente concepto. Es requerido cuando el atributo TipoFactor tenga una clave que corresponda a Tasa o Cuota (consultar catálogos del SAT). $ArrayTraslado_Importe = ['100.40']; // 7.5 Atributo condicional para señalar el importe del impuesto trasladado que aplica al concepto. No se permiten valores negativos. Es requerido cuando TipoFactor sea Tasa o Cuota // Retenciones. // $ArrayRetencion_Base = ['0', '0', '0']; // 7.6 Atributo requerido para señalar la base para el cálculo de la retención, la determinación de la base se realiza de acuerdo con las disposiciones fiscales vigentes. No se permiten valores negativos. // $ArrayRetencion_Impuesto = ['0', '0', '0']; // 7.7 Atributo requerido para señalar la clave del tipo de impuesto retenido aplicable al concepto (consultar catálogos del SAT). // $ArrayRetencion_TipoFactor = ['Tasa', 'Tasa', 'Tasa']; // 7.8 Atributo requerido para señalar la clave del tipo de factor que se aplica a la base del impuesto (consultar catálogos del SAT). // $ArrayRetencion_TasaOCuota = ['0.10', '0.10', '0.10']; // 7.9 Atributo requerido para señalar la tasa o cuota del impuesto que se retiene para el presente concepto (consultar catálogos del SAT). // $ArrayRetencion_Importe = ['0', '0', '0']; // 7.10 Atributo requerido para señalar el importe del impuesto retenido que aplica al concepto. No se permiten valores negativos. ### 8 DETERMINANDO TOTALES ##################################################### $ArrayRetencion_Importe = []; // 8.1 Calculando subTotal. for ($i=0; $icreateElement("cfdi:Comprobante"); $root = $xml->appendChild($root); $cadena_original='||'; $noatt= array(); #== 11.2 Se crea e inserta el primer nodo donde se declaran los namespaces ====== cargaAtt($root, array( "xsi:schemaLocation"=>"http://www.sat.gob.mx/cfd/4 http://www.sat.gob.mx/sitio_internet/cfd/4/cfdv40.xsd", "xmlns:cfdi"=>"http://www.sat.gob.mx/cfd/4", "xmlns:xs"=>"http://www.w3.org/2001/XMLSchema", "xmlns:xsi"=>"http://www.w3.org/2001/XMLSchema-instance" ) ); $mifecha= date('Y-m-d H:i:s'); $NuevaFecha = strtotime ( '+0 hour' , strtotime ($mifecha) ) ; $NuevaFecha = strtotime ( '-1 minute' , $NuevaFecha ) ; $NuevaFecha = strtotime ( '+0 second' , $NuevaFecha ) ; $NuevaHora = date ( 'H:i:s' , $NuevaFecha); echo $mifecha . " | " . $NuevaFecha; echo "

"; #== 11.3 Rutina de integración de nodos ========================================= cargaAtt($root, array( "Version"=>"4.0", "Serie"=>$fact_serie, "Folio"=>$fact_folio, "Fecha"=>date("Y-m-d")."T". $NuevaHora, "FormaPago"=>$formaDePago, "NoCertificado"=>$noCertificado, "CondicionesDePago"=>$condicionesDePago, "SubTotal"=>$subTotal, "Descuento"=>number_format($descuento,2,'.',''), "Moneda"=>$moneda, "TipoCambio"=>$TipoCambio, "Total"=>$total, "TipoDeComprobante"=>$fact_tipcompr, "Exportacion"=>$fact_exportacion, "MetodoPago"=>$metodoDePago, "LugarExpedicion"=>$LugarExpedicion ) ); $emisor = $xml->createElement("cfdi:Emisor"); $emisor = $root->appendChild($emisor); cargaAtt($emisor, array("Rfc"=>$emisor_rfc, "Nombre"=>$emisor_rs, "RegimenFiscal"=>$emisor_ClaRegFis ) ); $receptor = $xml->createElement("cfdi:Receptor"); $receptor = $root->appendChild($receptor); cargaAtt($receptor, array( "Rfc"=>$receptor_rfc, "Nombre"=>$receptor_rs, "DomicilioFiscalReceptor"=>$DomicilioFiscalReceptor, "RegimenFiscalReceptor"=>$RegimenFiscalReceptor, "UsoCFDI"=>$UsoCFDI ) ); $conceptos = $xml->createElement("cfdi:Conceptos"); $conceptos = $root->appendChild($conceptos); #== 11.4 Ciclo "for", recopilación de datos de artículos e integración de sus respectivos nodos = for ($i=0; $icreateElement("cfdi:Concepto"); $concepto = $conceptos->appendChild($concepto); cargaAtt($concepto, array( "ClaveProdServ"=>$Array_ClaveProdServ[$i], "NoIdentificacion"=>$Array_NoIdentificacion[$i], "Cantidad"=>$Array_Cantidad[$i], "ClaveUnidad"=>$Array_ClaveUnidad[$i], "Unidad"=>$Array_Unidad[$i], "Descripcion"=>$Array_Descripcion[$i], "ValorUnitario"=>number_format($Array_ValorUnitario[$i],2,'.',''), "Importe"=>number_format($Array_Importe[$i],6,'.',''), "Descuento"=>number_format($Array_Descuento[$i],2,'.',''), "ObjetoImp"=>$Array_ObjetoImp[$i] ) ); $impuestos = $xml->createElement("cfdi:Impuestos"); $impuestos = $concepto->appendChild($impuestos); $Traslados = $xml->createElement("cfdi:Traslados"); $Traslados = $impuestos->appendChild($Traslados); $Traslado = $xml->createElement("cfdi:Traslado"); $Traslado = $Traslados->appendChild($Traslado); if ($ArrayTraslado_TipoFactor[$i]=="Exento"){ cargaAtt($Traslado, array( "Base"=>number_format($ArrayTraslado_Base[$i],2,'.',''), "Impuesto"=>$ArrayTraslado_Impuesto[$i], "TipoFactor"=>$ArrayTraslado_TipoFactor[$i] ) ); }else{ cargaAtt($Traslado, array( "Base"=>number_format($ArrayTraslado_Base[$i],2,'.',''), "Impuesto"=>$ArrayTraslado_Impuesto[$i], "TipoFactor"=>$ArrayTraslado_TipoFactor[$i], "TasaOCuota"=>$ArrayTraslado_TasaOCuota[$i], "Importe"=>number_format($ArrayTraslado_Importe[$i],2,'.','') ) ); } // $Retenciones = $xml->createElement("cfdi:Retenciones"); // $Retenciones = $impuestos->appendChild($Retenciones); // // $Retencion = $xml->createElement("cfdi:Retencion"); // $Retencion = $Retenciones->appendChild($Retencion); // // cargaAtt($Retencion, array( // "Base"=>number_format($ArrayRetencion_Base[$i],2,'.',''), // "Impuesto"=>$ArrayRetencion_Impuesto[$i], // "TipoFactor"=>$ArrayRetencion_TipoFactor[$i], // "TasaOCuota"=>$ArrayRetencion_TasaOCuota[$i], // "Importe"=>number_format($ArrayRetencion_Importe[$i],2,'.','') // ) // ); } #== 11.5 Impuestos retenidos y trasladados ========================================== $Impuestos = $xml->createElement("cfdi:Impuestos"); $Impuestos = $root->appendChild($Impuestos); // $Retenciones = $xml->createElement("cfdi:Retenciones"); // $Retenciones = $Impuestos->appendChild($Retenciones); // // $Retencion = $xml->createElement("cfdi:Retencion"); // $Retencion = $Retenciones->appendChild($Retencion); // // cargaAtt($Retencion, array( // "Impuesto"=>"002", // "Importe"=>number_format($totalImpuestosRetenidos,2,'.','') // ) // ); // // cargaAtt($Impuestos, array( // "TotalImpuestosRetenidos"=>number_format($totalImpuestosRetenidos,2,'.','') // ) // ); $Traslados = $xml->createElement("cfdi:Traslados"); $Traslados = $Impuestos->appendChild($Traslados); $Traslado = $xml->createElement("cfdi:Traslado"); $Traslado = $Traslados->appendChild($Traslado); cargaAtt($Traslado, array( "Base"=>number_format($SumaBases,2,'.',''), "Impuesto"=>"002", "TipoFactor"=>"Tasa", "TasaOCuota"=>"0.160000", "Importe"=>number_format($totalImpuestosTrasladados,2,'.','') ) ); cargaAtt($Impuestos, array( "TotalImpuestosTrasladados"=>number_format($totalImpuestosTrasladados,2,'.','') ) ); $complemento = $xml->createElement("cfdi:Complemento"); $complemento = $root->appendChild($complemento); #== 11.6 Termina de conformarse la "Cadena original" con doble || $cadena_original .= "|"; // Descomentar si se desea obtener en archivo .TXT la Cadena Original. // $file = fopen($SendaCFDI."CadenaOriginal_Factura_".$NoFac.".txt", "w"); // fwrite($file, $cadena_original . PHP_EOL); // fclose($file); // chmod($SendaCFDI."CadenaOriginal_Factura_".$NoFac.".txt", 0777); #=== Muestra la cadena original (opcional a mostrar) ======================= echo '
'; echo 'CADENA ORIGINAL'; echo '
'; echo '
'; echo $cadena_original; echo '

'; #== 11.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); #== 11.9 Se convierte la cadena digital a Base 64 ========================== $sello = base64_encode($crypttext); // Firma. #=== Muestra el sello (opcional a mostrar) ================================= echo '
'; echo 'SELLO'; echo '
'; echo '
'; echo $sello; echo '

'; #== 11.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'; echo 'CERTIFICADO DEL SELLO DIGITAL'; echo ''; echo '
'; echo $certificado; echo '

'; #== 11.12 Se continua con la integración de nodos =========================== $root->setAttribute("Sello",$sello); $root->setAttribute("Certificado",$certificado); # Certificado. #== Fin de la integración de nodos ========================================= $NomArchCFDI = $SendaCFDI."PreCFDI-40_Factura_".$NoFac.".xml"; #=== 11.12 Se guarda el archivo .XML antes de ser timbrado ======================= $cfdi = $xml->saveXML(); $xml->formatOutput = true; $xml->save($NomArchCFDI); // Guarda el archivo .XML (sin timbrar) en el directorio predeterminado. unset($xml); #=== 11.13 Se dan permisos de escritura al archivo .xml. ========================= chmod($NomArchCFDI, 0777); ##### FIN DE LA CREACIÓN DEL ARCHIVO .XML ANTES DE SER TIMBRADO #################################################### die(); ### 12. PROCESO DE TIMBRADO ######################################################## #=== Se muestra el .XML antes de ser timbrado (opcional a mostrar)========== echo '
'; echo 'FACTURA .XML A TIMBRAR'; echo '
'; echo '
'; echo htmlspecialchars($cfdi); echo '

'; #== 12.1 Se crea una variable de tipo DOM y se le carga el CFDI ================================= $xml2 = new DOMDocument(); $xml2->loadXML($cfdi); #== 12.2 Convirtiendo el contenido del CFDI a BASE 64 ====================== $xml_cfdi_base64 = base64_encode($cfdi); #== Modo transición ======================================== // $process = curl_init('https://demo-transicion.finkok.com'); #== 12.3 Datos de acceso al servidor de pruebas ============================ $process = curl_init('https://demo-facturacion.finkok.com/servicios/soap/stamp.wsdl'); #== 12.4 Datos de acceso al servidor de producción ========================= # $process = curl_init('https://facturacion.finkok.com/servicios/soap/stamp.wsdl'); #== 12.5 Creando el SOAP de envío ============================================== $cfdixml = << $xml_cfdi_base64 $username $password XML; #== 12.6 Proceso para guardar los datos que se envían al servidor en un archivo .XML ======================== $NomArchSoap = $SendaCFDI."SOAP_Envio_Factura_".$NoFac.".xml"; #== 12.6.1 Si el archivo ya se encuentra se elimina =========================== if (file_exists ($NomArchSoap)==true){ unlink($NomArchSoap); } #== 12.6.2 Se crea el archivo .XML con el SOAP ================================ // Descomentar si se desea crear el archivo XML con el SOAP de envío. // $fp = fopen($NomArchSoap,"a"); // fwrite($fp, $cfdixml); // fclose($fp); // chmod($NomArchSoap, 0777); #=== 12.7 Muestra el contenido del SOAP que se envía al servidor del PAC (REQUEST) ========================= echo '
'; echo 'CONTENIDO DEL SOAP QUE SE ENVIA AL SERVIDOR DEL PAC'; echo '
'; echo '
'; echo htmlspecialchars($cfdixml); echo '

'; #== 12.8 Se envía el contenido del SOAP al servidor del PAC ===================== curl_setopt($process, CURLOPT_HTTPHEADER, array('Content-Type: text/xml',' charset=utf-8')); curl_setopt($process, CURLOPT_POSTFIELDS, $cfdixml); curl_setopt($process, CURLOPT_RETURNTRANSFER, true); curl_setopt($process, CURLOPT_POST, true); curl_setopt($process, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($process, CURLOPT_SSL_VERIFYHOST, false); $RespServ = curl_exec($process); #== 12.9 Se muestra la respuesta del servidor del PAC (opcional a mostrar) ================ echo '
'; echo 'RESPUESTA DEL SERVIDOR DEL PAC'; echo '
'; echo '
'; echo htmlspecialchars($RespServ); echo '

'; curl_close($process); ## FIN DEL PROCESO DE TIMBRADO ################################################# ## 13. PROCESOS POSTERIORES AL TIMBRADO ######################################## #== 13.1 Se asigna la respuesta del servidor a una variable de tipo DOM ==== $VarXML = new DOMDocument(); $VarXML->loadXML($RespServ); #== 13.2 Se graba la respuesta del servidor a un archivo .xml // Descomentar si se desea crear el archivo XML con la respuesta del servidor. // $VarXML->save($SendaCFDI."RespServ_Factura_".$NoFac.".xml"); // chmod($SendaCFDI."RespServ_Factura_".$NoFac.".xml", 0777); echo "
"; #== 13.3 Se asigna el contenido del tag "xml" a una variable =============== $RespServ = $VarXML->getElementsByTagName('xml'); #== 13.4 Se obtiene el valor del nodo ====================================== $valor_del_nodo = ""; foreach($RespServ as $Nodo){ $valor_del_nodo = $Nodo->nodeValue; } #== Si el nodo contiene datos se realizan los siguientes procesos ====== if($valor_del_nodo != ""){ // unlink($SendaCFDI."xlst_".$NoFac.".xml"); <-- Puede ser descomentado para eliminar el archivo .XML sin timbrar. #== 13.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($Nodo->nodeValue); echo '

'; #=== 13.6 Guardando el CFDI en archivo .XML ============================ $NomArchXML = "CFDI-40_Factura_".$NoFac.".xml"; $NomArchPDF = "CFDI-40_Factura_".$NoFac.".pdf"; $xmlt = new DOMDocument(); $xmlt->loadXML($valor_del_nodo); $xmlt->save($SendaCFDI.$NomArchXML); chmod($SendaCFDI.$NomArchXML, 0777); #== 13.7 Procesos para extraer datos del Timbre Fiscal del CFDI ========= $docXML = new DOMDocument(); $docXML->load($SendaCFDI."CFDI-40_Factura_".$NoFac.".xml"); $params = $docXML->getElementsByTagName("Comprobante"); foreach ($params as $param) { $VersionCFDI = $param->getAttribute("Version"); $Total = $param->getAttribute('Total'); $Serie = $param->getAttribute('Serie'); $Folio = $param->getAttribute('Folio'); } $SerieFolio = $Serie.$Folio; $comprobante = $docXML->getElementsByTagName("TimbreFiscalDigital"); #== 13.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'); echo '
'; echo 'Serie y Folio: '.$SerieFolio.'
'; echo 'Versión de CFDI: '.$VersionCFDI.'
'; echo 'Versión de timbre: '.$version_timbre.'
'; echo 'Sello del SAT: '.$sello_SAT.'
'; echo 'Certificado del SAT: '.$cert_SAT.'
'; echo 'Sello del CFDI: '.$sello_CFD.'
'; echo 'Fecha de timbrado: '.$tim_fecha.'
'; echo 'Folio fiscal: '.$tim_uuid.'
'; echo 'Importe total: '.$Total.'

'; echo '
'; } $params = $docXML->getElementsByTagName('Emisor'); foreach ($params as $param) { $Emisor_RFC = $param->getAttribute('Rfc'); } $params = $docXML->getElementsByTagName('Receptor'); foreach ($params as $param) { $Receptor_RFC = $param->getAttribute('Rfc'); } $params = $docXML->getElementsByTagName('Comprobante'); foreach ($params as $param) { $total = $param->getAttribute('Total'); } #== 13.9 Se crea el archivo .PNG con codigo bidimensional ================================= $filename = "archs_graf/Img_".$tim_uuid.".png"; $CadImpTot = ProcesImpTot($total); $Cadena = "?re=".$Emisor_RFC."&rr=".$Receptor_RFC."&tt=".$CadImpTot."&id=".$tim_uuid; QRcode::png($Cadena, $filename, 'H', 3, 2); chmod($filename, 0777); echo '
'; echo 'GRÁFICO "QR" RESULTANTE.'; echo '
'; echo ''.$filename.''; #== 13.10 Se crea código HTML para mostrar opciones al usuario. ?> TODO supply a title
     

Antes de verifica si un CFDI es cancelable o no espere unos 3 min. para que
el UUID del CFDI recien timbrado esté disponible en el servidor del SAT.

     
getElementsByTagName('CodigoError'); foreach($codigoError as $NodoStatus){ $valorNod = $NodoStatus->nodeValue; } echo '
'; echo 'CÓDIGO DE ERROR.'; echo '
'; echo '
'; echo $valorNod; echo '
'; } ##### FIN DE PROCEDIMIENTOS #################################################### ### 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); foreach ($attr as $key => $val){ $val = preg_replace('/\s\s+/', ' ', $val); $val = trim($val); if (strlen($val)>0){ $val = 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ón que integra los nodos al archivo .XML sin integrar a la "Cadena original". function cargaAttSinIntACad(&$nodo, $attr){ global $xml; $quitar = array('sello'=>1,'noCertificado'=>1,'certificado'=>1); foreach ($attr as $key => $val){ $val = preg_replace('/\s\s+/', ' ', $val); $val = trim($val); if (strlen($val)>0){ $val = str_replace("|","/",$val); $nodo->setAttribute($key,$val); if (!isset($quitar[$key])) if (substr($key,0,3) != "xml" && substr($key,0,4) != "xsi:"); } } } # 14.3 Funciónes que da formato al "Importe total" como lo requiere el SAT para ser integrado al código QR. function ProcesImpTot($ImpTot){ $ImpTot = number_format($ImpTot, 4); // <== Se agregó el 30 de abril de 2017. $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; }