{ Ejemplo de uso de libfacturista para timbrar CFDI s en Pascal/FreePascal/Delphi Ariel Medina - facturista.com Para compilar usando Free Pascal Compiler: fpc libfacturista.pas } {$ifdef win32} {$APPTYPE CONSOLE} {$endif} program libfacturista_timbrado; const {$ifdef win32} libfacturista = 'libfacturista.dll'; {$else} libfacturista = 'libfacturista.so'; {$endif} function libfacturista_version: PChar; cdecl; external libfacturista; function cfdi_crear: LongInt; cdecl; external libfacturista; function cfdi_destruir(h: LongInt): LongInt; cdecl; external libfacturista; function cfdi_comprobante_ex(h: LongInt; version: PChar; serie: PChar; folio: PChar; fecha: PChar; formaDePago: PChar; subTotal: PChar; TipoCambio: PChar; Moneda: PChar; total: PChar; metodoDePago: PChar; tipoDeComprobante: PChar; LugarExpedicion: PChar; NumCtaPago: PChar; condicionesDePago: PChar; descuento: PChar; motivoDescuento: PChar; atributosExtra: PChar): LongInt; cdecl; external libfacturista; function cfdi_error(h: LongInt): PChar; cdecl; external libfacturista; function cfdi_xml_cargar(h: LongInt; rutaFuente: PChar): LongInt; cdecl; external libfacturista; function cfdi_xml_guardar(h: LongInt; rutaDestino: PChar; decorar: LongInt): LongInt; cdecl; external libfacturista; function cfdi_xml_atributo(h: LongInt; ruta: PChar; nombre: PChar): PChar; cdecl; external libfacturista; function cfdi_xml_serializar(h: LongInt; decorar: LongInt): PChar; cdecl; external libfacturista; function cfdi_xml_atributo_agregar(h: LongInt; ruta: PChar; nombre: PChar; valor: PChar): LongInt; cdecl; external libfacturista; function cfdi_xml_atributo_borrar(h: LongInt; ruta: PChar; nombre: PChar): LongInt; cdecl; external libfacturista; function cfdi_cadena_original(h: LongInt): PChar; cdecl; external libfacturista; function cfdi_cadena_original_sat(h: LongInt): PChar; cdecl; external libfacturista; function cfdi_uuid(h: LongInt): PChar; cdecl; external libfacturista; function cfdi_fecha_timbrado(h: LongInt): PChar; cdecl; external libfacturista; function cfdi_numero_certificado_sat(h: LongInt): PChar; cdecl; external libfacturista; function cfdi_sello_cfd(h: LongInt): PChar; cdecl; external libfacturista; function cfdi_sello_sat(h: LongInt): PChar; cdecl; external libfacturista; function cfdi_sello(h: LongInt): PChar; cdecl; external libfacturista; function cfdi_fecha(h: LongInt): PChar; cdecl; external libfacturista; function cfdi_numero_certificado(h: LongInt; rutaCertificado: PChar): PChar; cdecl; external libfacturista; function cfdi_sellar(h: LongInt; rutaLlavePrivada: PChar; rutaCertificado: PChar; rutaDestino: PChar; decorar: LongInt): LongInt; cdecl; external libfacturista; function cfdi_sellar_pem(h: LongInt; rutaLlavePrivada: PChar; contrasena: PChar; rutaCertificado: PChar; rutaDestino: PChar; decorar: LongInt): LongInt; cdecl; external libfacturista; function cfdi_sellar_pkcs8(h: LongInt; rutaLlavePrivada: PChar; contrasena: PChar; rutaCertificado: PChar; rutaDestino: PChar; decorar: LongInt): LongInt; cdecl; external libfacturista; function cfdi_comprobante(version: PChar; serie: PChar; folio: PChar; fecha: PChar; formaDePago: PChar; subTotal: PChar; TipoCambio: PChar; Moneda: PChar; total: PChar; metodoDePago: PChar; tipoDeComprobante: PChar; LugarExpedicion: PChar; NumCtaPago: PChar; FolioFiscalOrig: PChar; SerieFolioFiscalOrig: PChar; FechaFolioFiscalOrig: PChar; MontoFolioFiscalOrig: PChar): LongInt; cdecl; external libfacturista; function cfdi_emisor(pcfdi: LongInt; rfc: PChar; nombre: PChar): LongInt; cdecl; external libfacturista; function cfdi_emisor_regimen(pcfdi: LongInt; Regimen: PChar): LongInt; cdecl; external libfacturista; function cfdi_emisor_domicilio(pcfdi: LongInt; calle: PChar; noExterior: PChar; noInterior: PChar; colonia: PChar; localidad: PChar; municipio: PChar; estado: PChar; pais: PChar; codigoPostal: PChar; referencia: PChar): LongInt; cdecl; external libfacturista; function cfdi_emisor_expedido_en(pcfdi: LongInt; calle: PChar; noExterior: PChar; noInterior: PChar; colonia: PChar; localidad: PChar; municipio: PChar; estado: PChar; pais: PChar; codigoPostal: PChar; referencia: PChar): LongInt; cdecl; external libfacturista; function cfdi_receptor(pcfdi: LongInt; rfc: PChar; nombre: PChar): LongInt; cdecl; external libfacturista; function cfdi_receptor_domicilio(pcfdi: LongInt; calle: PChar; noExterior: PChar; noInterior: PChar; colonia: PChar; localidad: PChar; municipio: PChar; estado: PChar; pais: PChar; codigoPostal: PChar; referencia: PChar): LongInt; cdecl; external libfacturista; function cfdi_impuestos(pcfdi: LongInt; totalImpuestosRetenidos: PChar; totalImpuestosTrasladados: PChar): LongInt; cdecl; external libfacturista; function cfdi_impuestos_retencion(pcfdi: LongInt; impuesto: PChar; importe: PChar): LongInt; cdecl; external libfacturista; function cfdi_impuestos_traslado(pcfdi: LongInt; impuesto: PChar; importe: PChar; tasa: PChar): LongInt; cdecl; external libfacturista; function cfdi_concepto(pcfdi: LongInt; cantidad: PChar; unidad: PChar; noIdentificacion: PChar; descripcion: PChar; valorUnitario: PChar; importe: PChar): LongInt; cdecl; external libfacturista; function cfdi_concepto_informacionaduanera(hc: LongInt; numero: PChar; fecha: PChar; aduana: PChar): LongInt; cdecl; external libfacturista; function cfdi_concepto_cuentapredial(hc: LongInt; numero: PChar): LongInt; cdecl; external libfacturista; function cfdi_concepto_parte(hc: LongInt; cantidad: PChar; unidad: PChar; noIdentificacion: PChar; descripcion: PChar; valorUnitario: PChar; importe: PChar): LongInt; cdecl; external libfacturista; function cfdi_concepto_ComplementoConcepto(hc: LongInt): LongInt; cdecl; external libfacturista; function xml_caller_charset(h: LongInt; charset: PChar): LongInt; cdecl; external libfacturista; function xml_node(h: LongInt; path: PChar): LongInt; cdecl; external libfacturista; function xml_node_children_number(h: LongInt): LongInt; cdecl; external libfacturista; function xml_node_by_index(h: LongInt; index: LongInt): LongInt; cdecl; external libfacturista; function xml_node_name(h: LongInt): PChar; cdecl; external libfacturista; function xml_node_by_name(h: LongInt; name: PChar): LongInt; cdecl; external libfacturista; function xml_node_attribute(h: LongInt; name: PChar): PChar; cdecl; external libfacturista; function cfdi_timbrar(h: LongInt; rutaFuente: PChar; rutaDestino: PChar; numeroPAC: LongInt; parametros: PChar): LongInt; cdecl; external libfacturista; function cfdi_cancelar(h: LongInt; numeroPAC: LongInt; parametros: PChar): LongInt; cdecl; external libfacturista; function cfdi_recuperar(h: LongInt; rutaDestino: PChar; numeroPAC: LongInt; parametros: PChar): LongInt; cdecl; external libfacturista; function cfdi_estado_cuenta(h: LongInt; numeroPAC: LongInt; parametros: PChar): PChar; cdecl; external libfacturista; function xml_serialize(h: LongInt; decorate: LongInt): PChar; cdecl; external libfacturista; function xml_insert(h: LongInt; path: PChar; XMLstring: PChar; indexFather: LongInt; indexChildren: LongInt): LongInt; cdecl; external libfacturista; function set_rsmm(rsmm: PChar): LongInt; cdecl; external libfacturista; function set_client_charset(charsetNumber: LongInt): LongInt; cdecl; external libfacturista; function cfdi_validar(h: LongInt; archivoXML: PChar; parametros: PChar): LongInt; cdecl; external libfacturista; function cfdi_timbrar_lote(h: LongInt; rutaFuente: PChar; rutaDestino: PChar; parametrosLote: PChar; numeroPAC: LongInt; parametrosPAC: PChar): LongInt; cdecl; external libfacturista; Function timbrar: Boolean; var xml1, xml2: PChar; h: LongInt; begin xml1:='cfdi_ejemplo.xml'; xml2:='cfdi_timbrado.xml'; h:=0; if cfdi_timbrar(h,xml1,xml2,1,'RFC=AAA010101AAA;TransaccionID=456;Servidor=pruebas.ecodex.com.mx;Puerto=2044;Sellar=1')<1 then begin writeln(cfdi_error(0)); timbrar:=False; end else begin timbrar:=True; h:=cfdi_xml_cargar(h,xml2); if h>0 then writeln( xml1 , ' ha sido timbrado (' , xml2 ,'), folio fiscal ' , cfdi_xml_atributo(h,'cfdi:Comprobante/cfdi:Complemento/tfd:TimbreFiscalDigital','UUID')) else writeln (xml1 , ' ha sido timbrado (' , xml2 , ') pero no se pudo cargar el archivo destino $xml2. ' , cfdi_error(h)); end; end; { Esta funcion construye el XML, lo sella y timbra Necesita que en el directorio esten aaa010101aaa__csd_01.key y aaa010101aaa__csd_01.cer El archivo timbrado será cfdi_timbrado_pascal.xml } Function sellar: Boolean; var h, he, hr, hc, hi, res: LongInt; rutaLlavePrivada, contrasena, rutaCertificado, rutaDestino, xmlTimbrado, version, estadoCuenta: PChar; begin sellar := False; rutaLlavePrivada := './aaa010101aaa__csd_01.key'; contrasena := '12345678a'; rutaCertificado := './aaa010101aaa__csd_01.cer'; rutaDestino := './cfdi_sellado.xml'; xmlTimbrado := './cfdi_timbrado_pascal.xml'; { En versiones >= 1.01.05 se sugiere usar el siguiente par de funciones en vez de solo cfdi_comprobante() } h := cfdi_crear(); h := cfdi_comprobante_ex(h,'3.2', 'A', '1234', '2013-09-06T18:43:11', 'Pago en una sola exhibicion', '6172.50', '12.34', 'USD', '7124.75', 'Efectivo', 'ingreso', 'Campeche, Campeche', '3849', 'venta a credito', '10.50', 'descuento por pronto pago', ''); { 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 En la version 1.01.04 ya no es necesario llamarla, Ansi es predeterminado en Windows Preferible llamar a set_client_charset() en caso necesario res = xml_caller_charset(h,'acp') } he := cfdi_emisor(h,'AAA010101AAA','facturista.com'); if he = 0 Then begin writeln ( cfdi_error(h) ); exit; end; res := 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 } res := cfdi_emisor_expedido_en(he,'39', '8', 'Depto. 25', 'Col. Jalisco', 'San Nicolas de los Garza', 'Monterrey', 'Nuevo Leon', 'Mexico', '74000', 'Cerca de Telmex'); res := cfdi_emisor_regimen(he,'Regimen 1'); res := 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 } res := 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'); res := cfdi_concepto_informacionaduanera(hc,'12345', '2011-01-01','Aduana nogales'); hc := cfdi_concepto(h,'10', 'PZA', '2', 'Memoria USB', '123.45', '1234.50'); res := cfdi_concepto_cuentapredial(hc,'3836463729385495'); hc := cfdi_concepto(h,'10', 'PZA', '3', 'Memoria USB', '123.45', '1234.50'); res := cfdi_concepto_parte(h,'10', 'PZA', '3', 'Parte 1', '123.45', '1234.50'); res := 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'); res := cfdi_impuestos_retencion(hi,'ISR','12.12'); res := cfdi_impuestos_retencion(hi,'IVA','23.23'); res := cfdi_impuestos_traslado(hi,'IVA', '987.60', '16.00'); res := cfdi_impuestos_traslado(hi,'IEPS', '0.00', '0.00'); writeln ('Cadena original: ' , cfdi_cadena_original(h) ); { 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 Then begin { poniendo el manejador en el primer parametro y la cadena vacia en el segundo, se timbra lo que hay en memoria } if cfdi_timbrar(h, '', xmlTimbrado, 1, 'RFC=AAA010101AAA;TransaccionID=456;Servidor=pruebas.ecodex.com.mx;Puerto=2044;Sellar=1' ) <> 0 Then begin sellar := True; writeln( xmlTimbrado + ' es el nuevo CFDI sellado y timbrado' ); estadoCuenta := cfdi_estado_cuenta(h, 1, 'RFC=AAA010101AAA;TransaccionID=456;Servidor=pruebas.ecodex.com.mx;Puerto=2044'); writeln(estadoCuenta); end else writeln('Error al timbrar: ' , cfdi_error(h) ); end else writeln('Error al sellar: ' , cfdi_error(h) ); cfdi_destruir(h); end; begin if ParamCount()>0 then timbrar() else sellar(); end.