How-To de facturación electrónica (verificación de facturas)

En el artículo anterior comentábamos del proceso de el firmado o “sellado” de documentos. En esta entrega, veremos brevemente el proceso de validación de las facturas que recibimos por parte de nuestros proveedores.

De acuerdo a las reglas del Servicio de Administración Tributaria (SAT), el que recibe una factura electrónica es responsable de validar su autenticidad, por lo cual tenemos que idear mecanismos que aseguren este requisito.

Veamos un ejemplo en el cual me dan una factura a validar para saberl si cumple con los criterios mínimos para ser aceptada, en este caso recibo un documento (v.g. “NEO0303288Z1FAA9.xml”) en formato XML que contiene la siguiente información relevante:

$ cat NEO0303288Z1FAA9.xml
 
<?xml version="1.0" encoding="UTF-8"?> 
<Comprobante xmlns="http://www.sat.gob.mx/cfd/2"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
             xsi:schemaLocation="http://www.sat.gob.mx/cfd/2 
                                 http://www.sat.gob.mx/sitio_internet/cfd/2/cfdv2.xsd"
             version="2.0"
             serie="AA"
             folio="9"
             fecha="2010-12-27T14:03:21"
             sello="KgWheSp62N9E18uRA1EcC1tdAPuWA0Q0z6h+TbZLYgkc6IRA+TAWk6KBDPcn/euKePfXhcSPtEqjp6RsA1k2EUldBMmClQadjGfxjTO14oO+RzSInckAwfrGL/W0BO9OizkNNS+PDswduIquczZqXDfuPNHqOnLgwhdiyYH7LLU="
             noAprobacion="353857"
             anoAprobacion="2010"
             formaDePago="Pago en una sola exhibición"
             noCertificado="00001000000102436855"
             certificado="MIIEDzCCAvegAwIBAgIUMD...

vean los campos “version” y “noCertificado”, estos nos dan información importante para el proceso de validación del documento.

El campo version nos indica con que archivo de transformación debemos procesar la factura. Si el valor del campo es “2.0” entonces debemos aplicar el archivo cadenaoriginal_2_0.xslt, en caso de que el valor sea “3.0”, debemos aplicar el archivo cadenaoriginal_3_0.xslt.

El campo noCertificado nos da el número del Certificado del Sello Digital (CSD) que necesitamos para validar el “sello” del documeto.

el archivo XML puede tener un certificado embebido, pero este puede llegar a ser apócrifo, y según la ley es “opcional”, por lo cual tenemos que buscar el certificado emitido por el SAT de alguna manera.

Obteniendo los certificados del SAT

Note que la aplicación CertiSAT Web, al buscar recuperar certificados me daba una información interesante:

Las ligas a los certificados tienen una estructura predecible, por lo cual puedo armar una regla de extracción del certificado (el cual es público) y obtenerlo directo del SAT para corroborar la información de la factura.

Si tenemos en nuestra factura en XML el valor “00001000000102436855” en el campo de “noCertificado”, entonces podemos inferir el siguiente comando para obtenerlo:

$ wget ftp://ftp2.sat.gob.mx/Certificados/FEA/000010/000001/02/43/68/00001000000102436855.cer

Si se fijan, la ruta de los directorios del FTP del SAT utilizan “ftp://ftp2.sat.gob.mx/Certificados/FEA/”, seguido por los 6 digitos del inicio del nombre del certificado, despues los siguientes 6 y lo siguiente en 3 pares de digitos que componen el nombre del mismo, despreciando los 2 últimos caracteres.

Validando la factura por medio del certificado y el “sello”

Necesitamos una pequeña regla de transformación que llamaremos “saca_sello.xslt” que contiene lo siguiente:

 
<xsl:stylesheet version = '1.0'
    xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
    xmlns:cfd="http://www.sat.gob.mx/cfd/2">
 
<xsl:output method = "text" /> 
 
<xsl:template match="cfd:Comprobante">
      <xsl:value-of select="@sello"/>
</xsl:template>
 
</xsl:stylesheet>

Obtenemos el sello y lo dejamos en el archivo de trabajo “sello.enc”, con el siguiente comando:

$ xsltproc saca_sello.xslt NEO0303288Z1FAA9.xml | openssl enc -base64 -d -A -out sello.enc

Ahora obtenemos la llave pública, del emisor de la factura, contenido en el certificado emitido por el SAT:

$ openssl x509 -inform DER -outform PEM -in 00001000000102436855.cer -pubkey > 00001000000102436855.cer.pem

Ahora podemos usar la llave pública para validar el documento:

$ xsltproc cadenaoriginal_2_0.xslt NEO0303288Z1FAA9.xml | openssl dgst -md5 -verify 00001000000102436855.cer.pem -signature sello.enc

A partir del 1o de enero del 2011, los documentos generados deberan usar SHA1 en lugar de MD5, aunque hay que validar con MD5 los documentos generados anteriormente a la mencionada fecha. La validación de cadena original versión 2.0 (medios propios), quedaría así:

$ xsltproc cadenaoriginal_2_0.xslt NEO0303288Z1FAA9.xml | openssl dgst -sha1 -verify 00001000000102436855.cer.pem -signature sello.enc

En el caso de que nuestra factura en XML diga en el campo de versión el valor “3.0”, deberemos usar esta variante del comando:

$ xsltproc cadenaoriginal_3_0.xslt NEO0303288Z1FAA9.xml | openssl dgst -sha1 -verify 00001000000102436855.cer.pem -signature sello.enc

Esto dara algunos “warnings” y si pasa la validación dara la leyenda “Verified OK” en caso contrario debemos rechazar la factura.

Finalmente, con ayuda de OpenSSL, obtenemos información importante para la validación con este comando:

$ openssl x509 -inform DER -in 00001000000102436855.cer -noout -issuer -subject -startdate -enddate -serial
 
issuer= /CN=A.C. del Servicio de Administraci\xC3\xB3n Tributaria/O=Servicio de Administraci\xC3\xB3n Tributaria/emailAddress=acods@sat.gob.mx/streetAddress=Av. Hidalgo 77, Col. Guerrero/postalCode=06300/C=MX/ST=Distrito Federal/L=Cuauhtemoc/unstructuredName=Responsable: Fernando Mart\xC3\xADnez Coss
subject= /CN=NEOCENTER SA DE CV/name=NEOCENTER SA DE CV/O=NEOCENTER SA DE CV/x500UniqueIdentifier=NEO0303288Z1 / AAWA630919KZ5/serialNumber= / AAWA630919HDFPNL07/OU=UNIDAD
notBefore=Dec 20 19:42:36 2010 GMT
notAfter=Dec 19 19:42:36 2012 GMT
serial=3030303031303030303030313032343336383535

La información que nos da es la del SAT, la del emisor, la fecha de vigencia del certificado con la que se “sello” la factura y el número de serie del certificado, este esta en formato Hexadecimal, que al convertirlo a decimal nos da el número de certificado que obtuvimos previamente.

Si la fecha de la factura en XML no esta entre las cotas de tiempo definidas en el certificado, o el número de certificado y nombre no coincide con el del emisor, debemos rechazar esta factura.

Validando las series y folios del documento

Es fácil recibir facturas que pasan por los validadores del SAT, pero que no son emitidas por la persona u empresa reales, por lo cual hay que prestar atención al proceso de validación. de CSD y folios

Nuevamente recurrimos al FTP del SAT para obtener dos archivos (que se actualizan diario y miden varios megas) donde estan la relación de CSD’s otorgados y las series de facturas:

wget ftp://ftp2.sat.gob.mx/agti_servicio_ftp/verifica_comprobante_ftp/CSD.txt
 
wget ftp://ftp2.sat.gob.mx/agti_servicio_ftp/verifica_comprobante_ftp/FoliosCFD.txt

Queda al lector subir esta información a una Base de datos para agilizar las consultas, pero en este caso ejemplificare la busqueda con comandos de bash.

$ grep "00001000000102436855" CSD.txt 
00001000000102436855|2010-12-20 19:42:36|2012-12-19 19:42:36|NEO0303288Z1|A

Aquí buscamos si el número de CSD corresponde al R.F.C. del emisor, noten que el último caracter de la linea nos indica si el CSD esta activo o revocado, en este caso esta activo. Esto tambíen nos muestra las fechas de vigencia contenidas en el certifcado.

Si el número de certificado no nos da nada en la busqueda, aun teniendo las últimas versiones de los archivos de CSD y folios, quiere decir que es un certificado de FIEL y no uno de sellos autorizados, por lo que deberán rechazar el documento.

Ahora busquemos si la serie de facturas es válida:

grep "NEO0303288Z1" FoliosCFD.txt 
NEO0303288Z1|353857|2010|AA|1|5000
NEO0303288Z1|353857|2010|CC|1|500

Hacemos las busquedas por R.F.C., ya que las facturas estan asociadas al emisor y no al sello. Vemos que la factura emitida es una serie válida.

Esto es una muestra de un proceso que debe automatizarse, tomando en cuanta que los archivos de “CSD.txt” y “FoliosCFD.txt” aumentan diario, no se si el SAT tenga algún formato no acumulativo sino diario de las diferencias de los cambios.

Con esto concluimos el proceso de validación y en otra artículo hablaremos de como usar las transformaciones de XSLT para emitir documentos impresos a partir del XML de la factura electrónica ya sellada.

También hablaremos de un proyecto que queremos compartir con ustedes llamadao “SAT-O-Matic”, que pretende hacer un sistema Open Source y GPL para la emisión, validación e impresión de documentos orientado a usuarios no iniciados. Enfocaremos esfuerzos para ayudar a la iniciativa de Mauricio Baeza (de Universo Libre), que esta haciendo una excelente herramienta de facturación electrónica utilizando OpenOffice/LibreOffice, para que ademas de soportar “Medios Propios” (versión 2.0) pueda soportar el esquema de “Proveedor Autorizado de Certificación” (versión 3.0)

Agradecimientos

Agradezco la ayuda de Salvador Ortíz de Matías Software Group, Fernando Ortíz y de Mauricio Baeza de Universo Libre por la ayuda y orientación prestada con sus opiniones y artículos.

Autor: Fernando “El Pop” Romo (pop at cofradia.org), twitter @El_Pop


2 votes, average: 5.00 out of 52 votes, average: 5.00 out of 52 votes, average: 5.00 out of 52 votes, average: 5.00 out of 52 votes, average: 5.00 out of 5 (2 votes, average: 5.00 out of 5)
You need to be a registered member to rate this post.
Loading...
Paranoia Fan Club, Programacion, software libre, Tips técnicos | RSS 2.0 |     9,220 views

RSS feed

2 Comments »

Comment by mauriciobaeza
2010-12-29 10:26:37

Hola Pop…
Hola a todos…

Las bases de datos de folios, series, y certificados (series) son publicas…

ftp://ftp2.sat.gob.mx/agti_servicio_ftp/verifica_comprobante_ftp/

Saludos

 
Comment by El Pop
2010-12-29 10:37:25

gracias Mauricio!, eso era lo que me faltaba 🙂

 
Name (required)
E-mail (required - never shown publicly)
URI
Your Comment (smaller size | larger size)
You may use <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> in your comment.

Trackback responses to this post