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); } }