{
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.