import com.sun.jna.*;
// libfacturista.java 2013-08-06, DLL para generar el XML, sellar y timbrar.
// Ejemplo de uso de libfacturista en Java
// Se requiere JNA (Java Native Access), si no dispone de este en su entorno, puede usar https://github.com/twall/jna/
//* Ariel Medina - 2013 - facturista.com
// Ejemplo de uso en GNU/Linux
// javac -classpath .:jna-3.5.1.jar libfacturista.java
// java -cp .:jna-3.5.1.jar -Djna.library.path=/usr/lib libfacturista cfdi_ejemplo.xml cfdi_timbrado.xml
// En windows debera renombrar libfacturista.dll a facturista.dll y ponerlo en la ruta de busqueda de Java
public class libfacturista {
// dll funcs
public static native
String libfacturista_version();
public static native
int cfdi_comprobante(String version, String serie, String folio, String fecha,
String formaDePago, String subTotal, String TipoCambio, String Moneda, String total,
String metodoDePago, String tipoDeComprobante, String LugarExpedicion, String NumCtaPago,
String FolioFiscalOrig, String SerieFolioFiscalOrig, String FechaFolioFiscalOrig, String MontoFolioFiscalOrig);
public static native
int cfdi_emisor(int pcfdi, String rfc, String nombre);
public static native
int cfdi_emisor_regimen(int pcfdi, String Regimen);
public static native
int cfdi_emisor_domicilio(int pcfdi, String calle, String noExterior, String noInterior,
String colonia, String localidad, String municipio, String estado, String pais, String codigoPostal, String referencia);
public static native
int cfdi_emisor_expedido_en(int pcfdi, String calle, String noExterior, String noInterior,
String colonia, String localidad, String municipio, String estado, String pais, String codigoPostal, String referencia);
public static native
int cfdi_receptor(int pcfdi, String rfc, String nombre);
public static native
int cfdi_receptor_domicilio(int pcfdi, String calle, String noExterior, String noInterior,
String colonia, String localidad, String municipio, String estado, String pais, String codigoPostal, String referencia);
public static native
int cfdi_impuestos(int pcfdi, String totalImpuestosRetenidos, String totalImpuestosTrasladados);
public static native
int cfdi_impuestos_retencion(int pcfdi, String impuesto, String importe);
public static native
int cfdi_impuestos_traslado(int pcfdi, String impuesto, String importe, String tasa);
public static native
int cfdi_concepto(int pcfdi, String cantidad, String unidad, String noIdentificacion,
String descripcion, String valorUnitario, String importe);
public static native
int cfdi_concepto_informacionaduanera(int hc, String numero, String fecha, String aduana);
public static native
int cfdi_concepto_cuentapredial(int hc, String numero);
public static native
int cfdi_concepto_parte(int hc, String cantidad, String unidad, String noIdentificacion,
String descripcion, String valorUnitario, String importe);
public static native
int cfdi_concepto_ComplementoConcepto(int hc);
public static native
int cfdi_xml_cargar(int h, String rutaFuente);
public static native
int cfdi_xml_guardar(int h, String rutaDestino, int decorar);
public static native
int cfdi_xml_validar(int h, String archivoXML, String archivoXSD, String parametros);
public static native
int cfdi_sellar_pkcs8(int h, String rutaLlavePrivada, String contrasena, String rutaCertificado, String rutaDestino, int decorar);
public static native
int cfdi_sellar_pem(int h, String rutaLlavePrivada, String contrasena, String rutaCertificado, String rutaDestino, int decorar);
public static native
int cfdi_sellar(int h, String rutaLlavePrivada, String rutaCertificado, String rutaDestino, int decorar);
public static native
int cfdi_timbrar(int h, String rutaFuente, String rutaDestino, int numeroPAC, String parametros);
public static native
int cfdi_cancelar(int h, int numeroPAC, String parametros);
public static native
int cfdi_recuperar(int h, String rutaDestino, int numeroPAC, String parametros);
public static native
String cfdi_estado_cuenta(int h, int numeroPAC, String parametros);
public static native
String cfdi_error(int h);
public static native
String cfdi_resultado(int h);
public static native
String cfdi_xml_atributo(int h, String ruta, String nombre);
public static native
int cfdi_xml_atributo_agregar(int h, String ruta, String nombre, String valor);
public static native
int cfdi_xml_atributo_borrar(int h, String ruta, String nombre);
public static native
String cfdi_cadena_original(int h);
public static native
String cfdi_cadena_original_sat(int h);
public static native
String cfdi_uuid(int h);
public static native
String cfdi_fecha_timbrado(int h);
public static native
String cfdi_numero_certificado_sat(int h);
public static native
String cfdi_sello_cfd(int h);
public static native
String cfdi_sello_sat(int h);
public static native
String cfdi_sello(int h);
public static native
String cfdi_fecha(int h);
// si no damos rutaCertificado, lo toma del XML
public static native
String cfdi_numero_certificado(int h, String rutaCertificado);
public static native
int xml_caller_charset(int h, String charset);
public static native
int xml_node(int h, String path);
public static native
int xml_node_children_number(int h);
public static native
int xml_node_by_index(int h, int index);
public static native
String xml_node_name(int h);
public static native
int xml_node_by_name(int h, String name);
public static native
String xml_node_attribute(int h, String name);
public static native
String xml_serialize(int h, int decorate);
public static native
int xml_insert(int h, String path, String XMLstring, int indexFather, int indexChildren);
public static native
int set_rsmm(String rsmm);
public static native
int set_client_charset(int charsetNumber);
public static native
int cfdi_validar(int h, String archivoXML, String parametros);
public static native
int cfdi_timbrar_lote(int h, String rutaFuente, String rutaDestino, String parametrosLote, int numeroPAC, String parametrosPAC);
static { Native.register("facturista"); }
// Funcion para realizar el timbrado, parametros:
// xml - archivoFuente
// xmltim - archivoDestino
// pruebas - true si queremos servidor de pruebas
// solotimbrado - true si queremos servicio de Solo Timbrado
// h - manejador del XML, si es diferente de 0, lo consideramos como el XML fuente e ignoramos el primer parametro
static
Boolean timbrar(String xml, String xmltim, Boolean pruebas, Boolean solotimbrado, int h)
{
String timbre, params, rfc, uuid;
// Los nombres de archivo no deberian estar vacios
if((h==0 && xml.length()<1) || xmltim.length()<1)
{
System.out.println("Nombre de archivo fuente o destino no es valido");
return false;
}
if(h==0)
{
// Solo se carga si la estructura XML es correcta
h=cfdi_xml_cargar(0,xml);
}
if(h!=0)
{
// Aprovechamos para verificar si tiene timbre
timbre=cfdi_xml_atributo(h,"cfdi:Comprobante/cfdi:Complemento/tfd:TimbreFiscalDigital","UUID");
if(timbre.length()>0)
{
System.out.println("El archivo ya tiene timbre: "+timbre);
return false;
}
// Obtenemos el RFC del emisor
rfc=cfdi_xml_atributo(h,"cfdi:Comprobante/cfdi:Emisor","rfc");
if(rfc.length()<1)
{
System.out.println("No se pudo determinar el RFC");
return false;
}
// Parametro TransaccionID para el PAC
params="TransaccionID=1234567890";
// Si se trata de pruebas, ponemos el servidor y puerto adecuado en los parametros
if(pruebas)
params=params+";RFC=AAA010101AAA;Servidor=pruebas.ecodex.com.mx;Puerto=2044";
else
params=params+";RFC="+rfc;
// Si no quiere solo timbrado, entonces indicamos al PAC que (re)selle
if(!solotimbrado)
params=params+";Sellar=1";
// Intentamos timbrar
if(cfdi_timbrar(h,xml,xmltim,1,params)!=0)
{
h=cfdi_xml_cargar(h,xmltim);
if (h!=0)
{
uuid=cfdi_xml_atributo(h,"cfdi:Comprobante/cfdi:Complemento/tfd:TimbreFiscalDigital","UUID");
System.out.println("Folio fiscal : "+uuid+"; archivo: "+xmltim);
return true;
}
else
System.out.println("La factura fue timbrada pero no se pudo cargar; archivo "+xmltim);
}
else
System.out.println("Ha fallado el timbrado, "+cfdi_error(h));
}
return false;
}
// libfacturista
public static void main(String[] args)
{
if(args.length>0)
{
System.out.println("Uso: libfacturista.class \nEj.:\n\tjava -cp .:jna-3.5.1.jar -Djna.library.path=/usr/lib libfacturista\n");
return;
}
int h, he, hr, hc, hi;
String rutaLlavePrivada, contrasena, rutaCertificado, rutaDestino, xmlTimbrado, version, estadoCuenta;
rutaLlavePrivada="./aaa010101aaa__csd_01.key";
contrasena="12345678a";
rutaCertificado="./aaa010101aaa__csd_01.cer";
rutaDestino="./cfdi_sellado.xml";
xmlTimbrado="./cfdi_timbrado_java.xml";
h=cfdi_comprobante("3.2", "A", "1234", "2013-06-27T18:43:11", "Pago en una sola exhibicion", "6172.50", "12.34", "USD", "7124.75", "Efectivo", "ingreso", "Campeche, Campeche", "3849", "", "", "", "");
// Los caracteres están en UTF8, pero si los vamos a mostrar al usuario en controles de Windows,
// y nuestro Windows no soporta el UTF8
// debemos decirle a libfacturista que convierta las cadenas a ACP ( ANSI Code Page)
// antes de devolverlas
xml_caller_charset(h,"acp");
he=cfdi_emisor(h,"MEVA7809229CA","facturista.com");
if (he==0)
{
System.out.println( cfdi_error(h) );
return; //-1
}
cfdi_emisor_domicilio(he,"31", "7", "Piso 3A", "Col. Mexico", "Campeche", "Municipio de Campeche", "Campeche", "Mexico", "24000", "Por la CFE");
// En caso de ser una sucursal, agregamos su direccion
cfdi_emisor_expedido_en(he,"39", "8", "Depto. 25", "Col. Jalisco", "San Nicolas de los Garza", "Monterrey", "Nuevo Leon", "Mexico", "74000", "Cerca de Telmex");
cfdi_emisor_regimen(he,"Regimen 1");
cfdi_emisor_regimen(he,"Regimen 2");
// el RFC de los clientes no debe contener guiones o espacios
hr=cfdi_receptor(h,"X&XX010101AAA","nombre_tu_cliente");
// los clientes deben tener desglosada su direccion para poder llenar los campos del receptor
cfdi_receptor_domicilio(hr,"Paseo de Montejo", "1234", "456", "Col. Europea", "Ciudad gotica", "Municipio de Merida", "Yucatan", "Mexico", "38294", "Por la cascada");
// aqui ponemos el detalle de la factura, en vez de los conceptos del ejemplo
// deberia poner información de su BD
hc=cfdi_concepto(h,"10", "PZA", "1", "Memoria USB", "123.45", "1234.50");
cfdi_concepto_informacionaduanera(hc,"12345", "2011-01-01","Aduana nogales");
hc=cfdi_concepto(h,"10", "PZA", "2", "Memoria USB", "123.45", "1234.50");
cfdi_concepto_cuentapredial(hc,"3836463729385495");
hc=cfdi_concepto(h,"10", "PZA", "3", "Memoria USB", "123.45", "1234.50");
cfdi_concepto_parte(h,"10", "PZA", "3", "Parte 1", "123.45", "1234.50");
cfdi_concepto_parte(h,"10", "PZA", "3", "Parte 2", "123.45", "1234.50");
hc=cfdi_concepto(h,"10", "PZA", "4", "Memoria USB", "123.45", "1234.50");
hc=cfdi_concepto(h,"10", "PZA", "5", "Memoria USB", "123.45", "1234.50");
hi=cfdi_impuestos(h,"35.35","987.60");
cfdi_impuestos_retencion(hi,"ISR","12.12");
cfdi_impuestos_retencion(hi,"IVA","23.23");
cfdi_impuestos_traslado(hi,"IVA", "987.60", "16.00");
cfdi_impuestos_traslado(hi,"IEPS", "0.00", "0.00");
System.out.println("Cadena original:" + cfdi_cadena_original(h) );
// Si es DLL demo, no se guarda en un archivo el XML sellado, pero se queda en memoria
// para poder timbrarlo; al final obtenemos el XML timbrado en un archivo
if ( cfdi_sellar_pkcs8(h, rutaLlavePrivada, contrasena, rutaCertificado, rutaDestino,1) != 0 )
{
//if(timbrar("cfdi_ejemplo.xml",xmlTimbrado,true,false,0))
// poniendo la cadena vacia y el manejador en el ultimo parametro, se timbra lo que hay en memoria
if(timbrar("",xmlTimbrado,true,false,h))
{
estadoCuenta = cfdi_estado_cuenta(h, 1, "RFC=AAA010101AAA;TransaccionID=456;Servidor=pruebas.ecodex.com.mx;Puerto=2044");
System.out.println(estadoCuenta);
}
else
System.out.println("Error al timbrar: " + cfdi_error(h) );
}
else
System.out.println("Error al sellar: " + cfdi_error(h) );
version = libfacturista_version();
System.out.println(version);
}
}