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