Si quieres probar el ejemplo para ver si funciona haz clic aquí
Si ya sabes de que trata esto y solo quieres el código
Si ya sabes de que trata esto y solo quieres el código
fuente ve al final del post, para ver las facturas y validarlas con
la herramienta del SAT entonces ve a esta dirección
esta aplicación crea al mismo tiempo el PDF y el XML
esta aplicación crea al mismo tiempo el PDF y el XML
Prólogo
Este script que libero lo hice en un solo día y evidentemente es muy austero, no utiliza una base de datos, no valida la entrada de datos (si es numérico, cadena vacía, comillas, etc), queda en ti revisar que no haya campos vacios y todo lo que es necesario revisar, a grandes rasgos te comento que el SAT especifíca que no se permiten comillas simples ni dobles, tampoco campos obligatorios vacíos los cuales están marcados con * en el formulario.
Que quede claro, esta aplicación no es un producto terminado con aspiraciones comerciales es simplemente un ejemplo dirigido a los programadores en PHP con el objetivo de que puedan adaptarlo al sistema ERP de la empresa en la que laboran y por supuesto es una aplicación más de mi portafolio web. Si tienes XAMPP entonces debería funcionar inmediatamente ya que este paquete incluye OpenSSL y en la descarga están todos los archivos necesarios para descomprimir la carpeta en htdocs y ejecutar el ejemplo.
Como dije en el post anterior he estado ocupado con esto de la facturación electrónica, no me había interesado por la criptografìa hasta ahora pero ya no me parece tan aburrida como hace unos meses. Se ha dicho muchas veces y creo firmemente que se aprende más en el trabajo que en la escuela., me metí en este rollo porqué me lo pidio el Administrador en el trabajo, el viernes terminé de migrar el modulo de facturación al nuevo esquema de facturación electrónica y la verdad aunque muchos han compartido información al respecto algunos de una forma dispersa, pero me ayude bastante de la web, sobre todo en este link, por ello he decidido liberar un script y una especie de tutorial para implementar este show. Siempre lo he dicho, el software es un servicio, no un producto, y en el caso de la facturación electrónica no puede ser más evidente.
Prefacio
Te platico brevemente que la facturación electrónica en México ya lleva algunos años aunque ha tomado mayor relevancia desde el año pasado debido a que a partir de enero 2011 se volvió obligatoria su implementación para aquellas empresas que facturen más de 4 millones al año, sin embargo si dichas empresas aún tienen facturas impresas pueden seguirlas usando hasta la fecha de caducidad de las mismas, pero en la realidad muchos clientes están pidiendo ya facturas electrónicas por lo que algunas han tenido que comenzar antes.
En este contexto hay 2 posibilidades, que la empresa emita facturas por sus propios medios, o bien mediante un tercero, la mala noticia es que todas aquellas que hayan comenzado a facturar en enero de 2011 van a requerir el timbrado que es una validación de sus CFDs (comprobantes fiscales digitales) de un tercero, y esto cuesta dinero ya que incluso he sabido de precios ridículamente altos como 8 pesos por folio. Pero en fin, si tu empresa emite facturas por sus propios medios esta herramienta te servirá.
Pues bien, un CFD es simplemente un archivo de texto en formato XML y el reporte mensual para el SAT es un archivo de texto plano, evidentemente hay reglas para su correcta estructuración, lo que debemos consultar para generar los archivos adecuadamente son 2 documentos, el primero es el anexo 20 de la resolución miscelanea fiscal para 2010 que describe la estructura del XML y el reporte mensual, el segundo documento es el detalle para la generación de la cadena original. No es necesario que los leas en este momento, pero si te recomiendo guardarlos por si surgen dudas durante la implementación en tu empresa.
Partimos de la premisa que tenemos 2 archivos, uno es el certificado que nos da el SAT (llave publica con extensión .CER), el otro archivo es la clave privada (llave privada con extensión .KEY), usaremos estos archivos para firmar y validar nuestros CFDs que enviemos a los clientes. Al certificado se le llama llave pública porque va incrustado en cada CFD que emitimos, en otras palabras, su contenido lo conocerá cualquiera que reciba nuestros documentos, la llave privada se le conoce así porque solo nosotros la utilizamos y es muy importante resguardarla bien o de lo contrario cualquiera podrá facturar con nuestro nombre.
Pues bien cuando emitimos una factura tenemos que elaborar una cadena de texto (la famosa cadena original) que en su interior lista la mayoria de los datos que se muestran en la factura impresa tradicional, por ejemplo datos del documento, del emisor, del cliente, el detalle de lo que se factura y también el detalle de los impuestos, un ejemplo del formato de esta cadena sería como sigue:
||esta|es|una|cadena|cualquiera|con|10|campos|separados|por pipes||
De la cadena original se hace un resumen o digestión con el algoritmo SHA-1 (hasta el año 2010 se usaba el algoritmo MD5) la cual genera una cadena más corta y codificada, por ejemplo la digestión de la cadena anterior sería tal como se ve a continuación, cabe mencionar que la digestión MD5 generaría una cadena resultante diferente:
Luego esta "digestión" se firma con nuestra llave privada, al firmar estaremos acreditando que nosotros somos los autores de esa cadena y su digestión, entonces aunque alguien tenga la cadena original y le aplique la digestión SHA1, el resultado será diferente pues la habrá firmado con su propia llave, la digestión firmada es una cadena con caracteres que ocasionan problemas en la mayoría de los sistemas, por ejemplo después de firmar la digestión, el resultado se ve así:
La cadena firmada se pasa a Base64 con el objetivo de convertir a caracteres alfanuméricos y obtenemos el Sello Digital, que sin duda se puede utilizar en los sistemas informáticos sin causar problemas, el resultado de pasar a base64 la cadena firmada se vería como se muestra abajo:
Tanto la cadena original como el sello digital se deben exhibir en la factura impresa, pero en el archivo XML solo se incrusta el contenido del certificado y el sello digital, la cadena original no se incluye pues el XML tiene la misma información que la cadena original (y más), esto quiere decir también que el XML y la cadena original deben tener los mismo campos que se incluyen en ambos y los mismos datos, por ejemplo, si en la cadena original pones el domiciclio con minúsculas y en el XML con mayúsculas entonces el CFD será invalido para el SAT, aún cuando la cadena original y el sello digital sean correctos.
Debes saber que en caso de una auditoría lo único que cuenta como CFD es el XML, el PDF o la impresión no tiene validez ante el SAT, pero para emplacar un auto en el módulo de control vehícular te pedirán la factura impresa y no el XML, almenos así es a la fecha. Quizás esto cambien en los próximos años.
SHA1 = 1449421a32a39ddea55af16e1566cf95d270f269
G ¹;-zpI"‡Ò¡heA™¯ýES"'S¬jK Ÿ¼ Æ ¶äC ·g7j þçÖ ûÕl]ü׉œ9¥Ê×\k †8a¬ ¸F¬»ãe1f«D\œ À¨ ±* ¦fʘŴŸ wcÓa2 pC’_éuéÛÝãÅc¬ž‹íWühŸ¡
La cadena firmada se pasa a Base64 con el objetivo de convertir a caracteres alfanuméricos y obtenemos el Sello Digital, que sin duda se puede utilizar en los sistemas informáticos sin causar problemas, el resultado de pasar a base64 la cadena firmada se vería como se muestra abajo:
CEcSuTstenBJIofSoWhlQZmv/UVTIidTrGpLGZ+8HcYDtuRDFL
dnN2oHHv7n1hAJ+9VsXQD814mcOaXK11xrGRwehjhhrBK4Rqy74
2WNMWarRFycFMCoD7EqgQymZsqYxbSfC3dj02EyDnBDkl+N6XXp
293jxWOsnovtV/xon6E=
Tanto la cadena original como el sello digital se deben exhibir en la factura impresa, pero en el archivo XML solo se incrusta el contenido del certificado y el sello digital, la cadena original no se incluye pues el XML tiene la misma información que la cadena original (y más), esto quiere decir también que el XML y la cadena original deben tener los mismo campos que se incluyen en ambos y los mismos datos, por ejemplo, si en la cadena original pones el domiciclio con minúsculas y en el XML con mayúsculas entonces el CFD será invalido para el SAT, aún cuando la cadena original y el sello digital sean correctos.
Debes saber que en caso de una auditoría lo único que cuenta como CFD es el XML, el PDF o la impresión no tiene validez ante el SAT, pero para emplacar un auto en el módulo de control vehícular te pedirán la factura impresa y no el XML, almenos así es a la fecha. Quizás esto cambien en los próximos años.
En resumen tenemos 2 archivos que usaremos para identificar y firmar nuestros comprobantes fiscales digitales, en cada factura creamos una cadena que lista los datos principales, a esta cadena le hacemos una digestión con el algoritmo SHA-1 y luego firmamos con nuestra llave privada para asegurar que nuestros documentos son infalsificables (un cambio en la cadena original genera un sello diferente) luego metemos el certificado y el sello en el XML y tenemos listo el CFD.
Tutorial
Ya sabemos a grandes rasgos lo que vamos a hacer, ahora veremos como hacerlo, esto asumiendo que ya tienes operativo un servidor web con soporte PHP, si no es así prueba con esta guía rápida que he elaborado en otro post anterior:
Tutorial
Ya sabemos a grandes rasgos lo que vamos a hacer, ahora veremos como hacerlo, esto asumiendo que ya tienes operativo un servidor web con soporte PHP, si no es así prueba con esta guía rápida que he elaborado en otro post anterior:
- Lo primero es instalar OpenSSL que es una librería con multitud de algoritmos para cifrado, hay varias versiones pues es software libre, en mi caso he utilizado WIN32OpenSSL, evidentemente si usas linux o windows en 64 bits deberás utilizar otra distribución. Instalarlo no tiene mayor complejidad, deja las rutas por default y debería quedar C:/OpenSSL
- OpenSSL utiliza los certificados y claves en formato PEM, por lo que tenemos que convertir los originales del SAT a este formato, no te preocupes no dañamos ni perdemos los originales, de hecho la conversión es sencilla pero se tiene que hacer desde consola, es decir hay que copiar los archivos a donde esté el openssl.exe y teclear algunos comandos que puedes ver en detalle en este texto que también viene en la descarga al final con todos los archivos de este post. No tienes que teclear todo a mano, puedes copiar y pegar en la consola como lo muestra la imagen de abajo, haciendo clic derecho sobre la barra de titulo de la ventana.
Nota la dirección donde está el openssl.exe y nota que ahi mismo tengo
los 2 archivos originales, el CER y el KEY
- Si lo has hecho bien tenemos ya el certificado y la clave en formato PEM, adicionalmente como te comenté más arriba tenemos que darle al cliente nuestra llave publica o certificado, lo podemos hacer de 2 formas, la primera y la mejor es leer el contenido del certificado e incrustar el texto en el XML, lo segundo es enviarles el archivo con extensión .CER, en el texto de arriba viene el comando en OpenSSL para leer el certificado, lo que tienes que hacer es copiar de la consola el contenido del certificado y guardarlo en texto para poder usarlo después cuando hagamos el XML desde PHP, lo único que nos interesa es lo que está entre el Begin y el End Certificate.
Lo que está en el archivo de texto lo meteremos en el XML
más adelante te muestro como
- Ya con los archivos en formato PEM, es cuestión de generar correctamente la cadena original, para generar la cadena original podemos guiarnos de este link, no todos los campos son obligatorios, los que no utilices (como numero interior, referencia, aduana etc) no se listan en la cadena, no debe haber espacios en blanco entre dos pipes | | que son los caracteres delimitadores entre campos, dicho sea de paso, la cadena debe estar en codificación UTF-8. Un ejemplo de cadena lo puedes ver abajo además de la digestión SHA-1 de la misma y luego la digestión firmarla con nuestra llave privada y codificada en base64.
Ten en cuenta que antes del 2011 las facturas electrónicas
tenia que ir digeridas en MD5, para hacerlo con este algoritmo
es igual, solo pon MD5 en vez de SHA1 en el script de php
- Generar el archivo XML es fácil, se hace como cuando se escribe cualquier archivo de texto desde PHP, el error que puedes tener es con el PDF ya que todo dentro del PDF ya está en UTF-8, entonces no es necesario codificar la cadena original como cuando lo haces en un script que genera solo HTML (suponiendo que solo generas el XML y no el PDF), es por ello que en el script que viene en la descarga no verás que se codifica en UTF-8, si pasas la cadena por la función utf8_encode() generarías otro sello diferente que obviamente sería invalido.
Còdigo resaltado con la instrucción para digerir y firmar en un solo paso
con la cadena original sin pasarla a UTF-8 pues al generar un PDF ya se
trabaja en esta codificación
A diferencia de las etiquetas HTML, en los archivos XML
debes tener cuidado con los retornos de carro y saltos de linea
pues si pones todo el archivo de corrido no lo reconocerá
el validador del SAT ni Dreamweaver , para incrustar el certificado
se lee desde php el archivo de texto certificado.txt que hicimos
al principio del post, también podrías ponerlo directamente como una
cadena dentro de php pero hace que se vea más feo el código
- Lo ultimo es validar el CFD con la herramienta pitera del SAT, es en Java así que debes tener el plugin correspondiente en tu navegador, esperar a que cargue, cargar tu XML y luego tomarte un café mientras esperas a que analice el XML. Aqui abajo puedes ver que el PITUS Billing Script genera CFDs validos :p
Algunos errores que hacen que tu sello sea invalido es que no coincida
la cadena original que generaste con el XML, en principio mi script no da
lata pero si te dijera ese error ya tienes una noción de que pasa
incluso haz la prueba y cambia una letra de algún atributo del XML y verás que
al validarlo te dará error, otro error puede ser debido a los saltos de linea en el XML
Pues bien algunas conclusiones al respecto de este desarrollo es que la solución que varios adoptan de usar el Shell de PHP para ejecutar el openssl.exe pasando como argumentos archivos de texto no sirve para un entorno de producción pues genera sellos inválidos en algunas ocasiones, esto lo comprobé en el modulo de facturación del trabajo, así que es mejor utilizar las funciones propias de PHP para openssl.
Sin duda hay mucho dinero detrás de esta medida, ya que como comenté al principio hay proveedores certificador por el SAT que te cobran por folio así que seguramente algunos familiares de funcionarios tuvieron información desde el principio pudiendose adelantar a sacar sus plataformas. Es verdad que esto ahorrará mucho papel pero lo principal es que hará mucho más fácil de rastrear para el gobierno a los evasores de impuestos. Para nadie es un secreto que puedes comprar facturas para comprobar gastos, pues con este nuevo esquema de facturación electrónica eso se va a volver difícil y creo que se terminará eventualmente.
Sin duda hay mucho dinero detrás de esta medida, ya que como comenté al principio hay proveedores certificador por el SAT que te cobran por folio así que seguramente algunos familiares de funcionarios tuvieron información desde el principio pudiendose adelantar a sacar sus plataformas. Es verdad que esto ahorrará mucho papel pero lo principal es que hará mucho más fácil de rastrear para el gobierno a los evasores de impuestos. Para nadie es un secreto que puedes comprar facturas para comprobar gastos, pues con este nuevo esquema de facturación electrónica eso se va a volver difícil y creo que se terminará eventualmente.
Si usas XAMPP entonces ya tienes OpenSSL configurado para usar en PHP, lo cual te permite utilizar las instrucciones que utilizo en el script, sin embargo es más comodo bajarse una distribución para convertir los archivos a PEM, en concreto la versión que te mencioné arriba también te sirve para usar un programita que encontré y sirve para verificar tus sellos tanto en MD5 como SHA1, es muy bueno salvo el detalle de que es solo para windows y no valida los XML, pero es muy útil si no tienes acceso al validador del SAT para comprobar tus sellos.
Lo que no hace este script es generar los reportes mensuales, hacerlo es mucho más sencillo que todo esto, es un simple archivo de texto y es en base a los CFDs que hayas emitido en el mes, para el caso de CFDs del tipo Egresos o Traslados queda a desarrollo de cada quién según lo requiera, por eso libero el código, debes saber que no valido nada con el objetivo de tener un código corto y limpio, así que queda a tu entera responsabilidad ver que no falten datos, en el formulario de la aplicación se marcan con asteriscos y negritas los campos obligatorios.
La aplicación está lista para facturar con los campos que ya están llenos, si dejas todo como está y haces clic en el botón te genera una CFD válido y que está basado en un ejemplo del SAT. Solo me queda dejarte aqui la descarga de toda la aplicación y abajo unas capturas del script funcionando.
No se alcanza a ver todo el formulario, abajo
simplemente hay más campos para conceptos
descuento y el botón para crear el CFD
Puedes personalizar la factura a tu gusto, por ejemplo aqui
se muestra una marca de agua que podria ser la factura de una agencia
de motocicletas, solo por poner un ejemplo jeje
En tu aplicación tienes que reemplazar la imagen de la
se muestra una marca de agua que podria ser la factura de una agencia
de motocicletas, solo por poner un ejemplo jeje
En tu aplicación tienes que reemplazar la imagen de la
cédula del RFC y el logo, ambas están en JPG, también debes
especificar en el script de PHP los datos de facturación
para el caso de tu empresa en particular








