bigdata-mx / factura-electronica

Librería de componentes Java para el desarrollo de aplicaciones de Factura Electrónica (CFDI)
Apache License 2.0
94 stars 107 forks source link

Sello Valido en el SAT e Inválido con la Librería #77

Open Carodial opened 11 years ago

Carodial commented 11 years ago

Hola el problema que tengo es el siguiente: Al validar un XML cuyas cantidades o importes no tenga el formato con dos decimales, marca Sello Invalido, la misma factura la paso en el SAT y me dice que el sello es válido.

importe="9543.870000" valorUnitario="9543.870000" cantidad="1.000000"> ó cantidad=".39"

Hay alguna forma de que el sello se tome tal y como vienen los valores en el XML, sin que haga ajustes.

elmer-garduno commented 11 years ago

Si, hemos visto este problema antes, déjame revisar el código y ver si hay una solución pronto.

Carodial commented 11 years ago

Buenas tardes, sobre este tema alguien ya lo pudo solucionar.

Agradecería mucho su ayuda.

elmer-garduno commented 11 years ago

El problema es el que la librería de XSD está transformando los dígitos a decimales y al ponerlos en la cadena original los pone como números sin los decimales adicionales y eso impide que valide correctamente.

Alguien ha encontrado solución para esto?

cesar-martinezg commented 10 years ago

Buenas tardes, me tope con el mismo problema y normalmente retornaba a los usuarios finales que hablaran con sus PACs y volvieran a generar su factura cuando tenian datos como cantidad="02" o importe=".25" o importe="1.200000".

Sin embargo en este momento me vi obligado a dar solución definitiva ya que el SAT para los ex-REPECOs y que ahora pertenecen al Régimen de Incorporación Fiscal obliga a que expidan los CFDI por su portal. Y el propio SAT expide las facturas con los detalles de los ejemplos expuestos, y el que mas me dio problema fue la fecha ya que ellos la expresan asi "2014-05-14T12:25:03Z", con la Z al final, lo cual las librerias de bigdata al usar el Binder para DateTime omite dicha información, por lo cuál resulta en un sello inválido.

La solución que implemente fue:

1- Agregar el método sobrecargado a la clase correspondiente (en mi caso CFDv32.java) verificar y getOriginalBytes, recibiendo un InputStream, creo que el autor de la libreria o alguien mas lo comento en otro post. 2- Los nuevos métodos sobrecargados deberian verse así:

public void verificar(InputStream in) throws Exception{ String certStr = document.getCertificado(); Base64 b64 = new Base64(); byte[] cbs = b64.decode(certStr); X509Certificate cert = KeyLoader .loadX509Certificate(new ByteArrayInputStream(cbs)); String sigStr = document.getSello(); byte[] signature = b64.decode(sigStr); byte[] bytes = getOriginalBytes(in); Signature sig = Signature.getInstance("SHA1withRSA"); sig.initVerify(cert); sig.update(bytes); boolean bool = sig.verify(signature); if (!bool) { throw new Exception("Sello de Emisor inválido");//("Invalid signature"); } }

byte[] getOriginalBytes(InputStream in) throws Exception{ ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { Source source = new StreamSource(in); Source xsl = new StreamSource(getClass().getResourceAsStream(XSLT)); Result out = new StreamResult(baos); TransformerFactory factory = tf; if (factory == null) { factory = TransformerFactory.newInstance(); factory.setURIResolver(new URIResolverImpl()); } Transformer transformer = factory .newTransformer(new StreamSource(getClass().getResourceAsStream(XSLT))); transformer.transform(source, out); } finally { in.close(); }

  return baos.toByteArray();

}

Con lo cuál solo basta hacer la invocación necesaria enviando algun FileInputStream p. ej. obviamente teniendo instanciado previamente el objeto CFDv32 correctamente.

No lo aplico al SVN/GitHub ya que yo cuento con una version de la libreria que es desde las primeras versiones y he ido modificando y adecuando a mis necesidades. Espero ayudar a varios con este tema que en realidad llega a ser desesperante.

residentemzt commented 10 years ago

Excelente apoyo gracias El 26/05/2014 18:04, "poseidon24" notifications@github.com escribió:

Buenas tardes, me tope con el mismo problema y normalmente retornaba a los usuarios finales que hablaran con sus PACs y volvieran a generar su factura cuando tenian datos como cantidad="02" o importe=".25" o importe="1.200000".

Sin embargo en este momento me vi obligado a dar solución definitiva ya que el SAT para los ex-REPECOs y que ahora pertenecen al Régimen de Incorporación Fiscal obliga a que expidan los CFDI por su portal. Y el propio SAT expide las facturas con los detalles de los ejemplos expuestos, y el que mas me dio problema fue la fecha ya que ellos la expresan asi "2014-05-14T12:25:03Z", con la Z al final, lo cual las librerias de bigdata al usar el Binder para DateTime omite dicha información, por lo cuál resulta en un sello inválido.

La solución que implemente fue:

1- Agregar el método sobrecargado a la clase correspondiente (en mi caso CFDv32.java) verificar y getOriginalBytes, recibiendo un InputStream, creo que el autor de la libreria o alguien mas lo comento en otro post. 2- Los nuevos métodos sobrecargados deberian verse así:

public void verificar(InputStream in) throws Exception{ String certStr = document.getCertificado(); Base64 b64 = new Base64(); byte[] cbs = b64.decode(certStr); X509Certificate cert = KeyLoader .loadX509Certificate(new ByteArrayInputStream(cbs)); String sigStr = document.getSello(); byte[] signature = b64.decode(sigStr); byte[] bytes = getOriginalBytes(in); Signature sig = Signature.getInstance("SHA1withRSA"); sig.initVerify(cert); sig.update(bytes); boolean bool = sig.verify(signature); if (!bool) { throw new Exception("Sello de Emisor inválido");//("Invalid signature"); } }

byte[] getOriginalBytes(InputStream in) throws Exception{ ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { Source source = new StreamSource(in); Source xsl = new StreamSource(getClass().getResourceAsStream(XSLT)); Result out = new StreamResult(baos); TransformerFactory factory = tf; if (factory == null) { factory = TransformerFactory.newInstance(); factory.setURIResolver(new URIResolverImpl()); } Transformer transformer = factory .newTransformer(new StreamSource(getClass().getResourceAsStream(XSLT))); transformer.transform(source, out); } finally { in.close(); }

return baos.toByteArray();

}

Con lo cuál solo basta hacer la invocación necesaria enviando algun FileInputStream p. ej. obviamente teniendo instanciado previamente el objeto CFDv32 correctamente.

No lo aplico al SVN/GitHub ya que yo cuento con una version de la libreria que es desde las primeras versiones y he ido modificando y adecuando a mis necesidades. Espero ayudar a varios con este tema que en realidad llega a ser desesperante.

— Reply to this email directly or view it on GitHubhttps://github.com/bigdata-mx/factura-electronica/issues/77#issuecomment-44224856 .

Carodial commented 10 years ago

Muchas gracias por el aporte, ahorita estoy en proyecto pero en cuanto pueda lo probaré. El may 26, 2014 7:04 p.m., "poseidon24" notifications@github.com escribió:

Buenas tardes, me tope con el mismo problema y normalmente retornaba a los usuarios finales que hablaran con sus PACs y volvieran a generar su factura cuando tenian datos como cantidad="02" o importe=".25" o importe="1.200000".

Sin embargo en este momento me vi obligado a dar solución definitiva ya que el SAT para los ex-REPECOs y que ahora pertenecen al Régimen de Incorporación Fiscal obliga a que expidan los CFDI por su portal. Y el propio SAT expide las facturas con los detalles de los ejemplos expuestos, y el que mas me dio problema fue la fecha ya que ellos la expresan asi "2014-05-14T12:25:03Z", con la Z al final, lo cual las librerias de bigdata al usar el Binder para DateTime omite dicha información, por lo cuál resulta en un sello inválido.

La solución que implemente fue:

1- Agregar el método sobrecargado a la clase correspondiente (en mi caso CFDv32.java) verificar y getOriginalBytes, recibiendo un InputStream, creo que el autor de la libreria o alguien mas lo comento en otro post. 2- Los nuevos métodos sobrecargados deberian verse así:

public void verificar(InputStream in) throws Exception{ String certStr = document.getCertificado(); Base64 b64 = new Base64(); byte[] cbs = b64.decode(certStr); X509Certificate cert = KeyLoader .loadX509Certificate(new ByteArrayInputStream(cbs)); String sigStr = document.getSello(); byte[] signature = b64.decode(sigStr); byte[] bytes = getOriginalBytes(in); Signature sig = Signature.getInstance("SHA1withRSA"); sig.initVerify(cert); sig.update(bytes); boolean bool = sig.verify(signature); if (!bool) { throw new Exception("Sello de Emisor inválido");//("Invalid signature"); } }

byte[] getOriginalBytes(InputStream in) throws Exception{ ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { Source source = new StreamSource(in); Source xsl = new StreamSource(getClass().getResourceAsStream(XSLT)); Result out = new StreamResult(baos); TransformerFactory factory = tf; if (factory == null) { factory = TransformerFactory.newInstance(); factory.setURIResolver(new URIResolverImpl()); } Transformer transformer = factory .newTransformer(new StreamSource(getClass().getResourceAsStream(XSLT))); transformer.transform(source, out); } finally { in.close(); }

return baos.toByteArray();

}

Con lo cuál solo basta hacer la invocación necesaria enviando algun FileInputStream p. ej. obviamente teniendo instanciado previamente el objeto CFDv32 correctamente.

No lo aplico al SVN/GitHub ya que yo cuento con una version de la libreria que es desde las primeras versiones y he ido modificando y adecuando a mis necesidades. Espero ayudar a varios con este tema que en realidad llega a ser desesperante.

— Reply to this email directly or view it on GitHubhttps://github.com/bigdata-mx/factura-electronica/issues/77#issuecomment-44224856 .