Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   Factura Electronica AFIP Resuelto/Funcionando (https://www.clubdelphi.com/foros/showthread.php?t=88675)

adripugliesso 14-07-2015 22:26:12

Factura Electronica AFIP Resuelto/Funcionando
 
Sin ocx, sin componentes 100% codigo delphi

Tengo el codigo en delphi para solicitar cae y demas funciones del webservice de Afip funcionando 100% codigo puro de delphi sin OCX ni Componentes Raros.

Saludos..


PD: Enseguida pondré enlace al código, que lo subiré al FTP.


.

giulichajari 15-07-2015 16:56:08

Cita:

Empezado por adripugliesso (Mensaje 494460)
Sin ocx, sin componentes 100% codigo delphi

Tengo el codigo en delphi para solicitar cae y demas funciones del webservice de Afip funcionando 100% codigo puro de delphi sin OCX ni Componentes Raros.

Saludos..


PD: Enseguida pondré enlace al código, que lo subiré al FTP.


.

Es decir que te tomaste el trabajo de importar los webservices? y realizar todo el trabajo?
Felicitaciones entonces

adripugliesso 15-07-2015 17:14:57

Claro lo que hice fue importar los WDSL y luego utilizarlos en mi codigo.

egostar 15-07-2015 18:28:35

Cita:

Empezado por adripugliesso (Mensaje 494495)
Claro lo que hice fue importar los WDSL y luego utilizarlos en mi codigo.

Respecto al firmado, ¿que usaste? API, componentes ???

Saludos y felicidades.

adripugliesso 15-07-2015 21:09:20

En el firmado lo unico que hago es usar el shellExecute llamando a un Bat que lo que hace es ejecutar las lineas de Openssl.


Código Delphi [-]
procedure CreaXMLFirmado();
var p1: string;
    r: PAnsiChar;
begin
  memo1.Clear;
  memo1.Lines.Add('c:');
  memo1.Lines.Add('cd /');
  memo1.Lines.Add('cd OpenSSL-Win32');
  memo1.Lines.Add('cd bin');
  memo1.Lines.Add('openssl smime -sign -in ' + ruta + 'ticketsf.xml -out '+ ruta + 'ticketf.xml -inkey ' + ruta + 'cert.key -signer '+ruta +'cert.crt -outform PEM -nodetach ');
  memo1.Lines.SaveToFile(ruta + 'firmar.bat');
  memo1.Clear;

ShellExecute(0, 'open', PAnsiChar(ruta + 'firmar.bat'), 'param1 param2',  nil,  SW_HIDE);
end;

tenes que tener instalado el Openssl en la ruta donde lo llamas

Casimiro Notevi 15-07-2015 21:16:40

Recuerda poner los tags al código fuente, ejemplo:


egostar 15-07-2015 21:19:07

Cita:

Empezado por adripugliesso (Mensaje 494500)
En el firmado lo unico que hago es usar el shellExecute llamando a un Bat que lo que hace es ejecutar las lineas de Openssl.


Código Delphi [-]
procedure CreaXMLFirmado();
var p1: string;
    r: PAnsiChar;
begin
  memo1.Clear;
  memo1.Lines.Add('c:');
  memo1.Lines.Add('cd /');
  memo1.Lines.Add('cd OpenSSL-Win32');
  memo1.Lines.Add('cd bin');
  memo1.Lines.Add('openssl smime -sign -in ' + ruta + 'ticketsf.xml -out '+ ruta + 'ticketf.xml -inkey ' + ruta + 'cert.key -signer '+ruta +'cert.crt -outform PEM -nodetach ');
  memo1.Lines.SaveToFile(ruta + 'firmar.bat');
  memo1.Clear;

ShellExecute(0, 'open', PAnsiChar(ruta + 'firmar.bat'), 'param1 param2',
  nil,  SW_HIDE);
end;

tenes que tener instalado el Openssl en la ruta donde lo llamas

Muy interesante ^\||/, muchas gracias.

Saludos

adripugliesso 03-08-2015 12:53:45

Metodo para Solicitar el CAE
 
Código Delphi [-]
procedure TForm1.Button8Click(Sender: TObject);
var
  port: ServiceSoap;
  respuesta: FECAEResponse;
  Auth: FEAuthRequest;
  Request: FECAERequest;

  CAECabReq : FECAECabRequest;
  CAEDetReq : FECAEDetRequest;
  ACAEDetReq : ArrayOfFECAEDetRequest;
  ADetIva : ArrayOfAlicIva;
  DetIva21 : AlicIva;
  DetIva105 : AlicIva;
  Tributos : Tributo;
  ATributos : ArrayOfTributo;
  CbtesAsoc : CbteAsoc;
  ACbtesAsoc : ArrayOfCbteAsoc;

  x, i : Integer;
  NroComp : Integer;

  iva : boolean;

begin


  screen.Cursor := crHourGlass;


//  edDesde.Text := TimeToStr(now);
  auth      := FeAuthRequest.Create;
  Request   :=  FECAERequest.Create;
  CAEDetReq := FECAEDetRequest.Create;
  CAECabReq := FECAECabRequest.Create;
  DetIva21  := AlicIva.Create;
  DetIva105 := AlicIva.Create;

  SetLength(ACAEDetReq,1);

  Request.FeCabReq        := CAECabReq;
  ACAEDetReq[0]           := CAEDetReq;
  Request.FeDetReq        := ACAEDetReq;

  //si tiene percepciones crea array
//  if STRTOFLOAT(edtPercIIBB.Text) > 0 then
//  begin
//    Tributos := Tributo.Create;
//    SetLength(ATributos,1);
//    ATributos[0]                             := Tributos;
//    Request.FeDetReq[0].Tributos             := ATributos;
//  end;

  //si tiene los 2 ivas dimensiona para 2 sino 1
//  if (STRTOFLOAT(edtIVA105.Text) > 0) and (STRTOFLOAT(edtIVA21.Text) > 0)
//  then
//  begin
//    SetLength(ADetIva,2);
//    ADetIVA[0]              := DetIva21;
//    ADetIVA[1]              := DetIva105;
//    Request.FeDetReq[0].Iva := ADetIva;
//  end
//  else
//  begin
    SetLength(ADetIva,1);
   ADetIVA[0]              := DetIva21;
    Request.FeDetReq[0].Iva := ADetIva;

//  end;


  // si lleva documento vinculado
//  i:= dbTipoCbte.KeyValue;
//  if (i IN [2,3,7,8]) then
//  begin
//    CbtesAsoc := CbteAsoc.Create;
//    SetLength(ACbtesAsoc,1);
//    ACbtesAsoc[0]                             := CbtesAsoc;
//    Request.FeDetReq[0].CbtesAsoc             := ACbtesAsoc;

//  end;


  iva:=false;

  auth.Cuit   := cuit;
  auth.token  := token;
  auth.Sign   := sign;


  //   FeCabReq
  Request.FeCabReq.CantReg  := 1;  //   cantidad de registros
  Request.FeCabReq.CbteTipo := 1;    //   1=fc.A 2=nd.A 3=nc.A    6=fc.B 7=nd.B 8=nc.B
  Request.FeCabReq.PtoVta   := 2;    //   Punto de venta

  //   FecDetReq
  Request.FeDetReq[0].Concepto  := 1;   //   1=productos, 2=servicios, 3=ambos
  Request.FeDetReq[0].DocTipo   := 80; //80 -cuit   86 - cuil   96-dni
  Request.FeDetReq[0].DocNro    := 20000000001; //cuit del cliente

  NroComp := STRTOINT64(edit1.Text);
  
  Request.FeDetReq[0].CbteDesde   := NroComp;
  Request.FeDetReq[0].CbteHasta   := NroComp;
  Request.FeDetReq[0].CbteFch     := formatdatetime('yyyymmdd',now);
  Request.FeDetReq[0].ImpTotal    := 121;
  Request.FeDetReq[0].ImpTotConc  := 0;
  Request.FeDetReq[0].ImpNeto     := 100;
  Request.FeDetReq[0].ImpOpEx     := 0;
  Request.FeDetReq[0].ImpIva      := 21;
  Request.FeDetReq[0].ImpTrib     := 0;  //si tiene percepciones de IIBB o IVA van aca

  if Request.FeDetReq[0].Concepto <> 1 then
  begin
    //------------------------------------------------------------------------
    Request.FeDetReq[0].FchServDesde := FormatDateTime('yyyymmdd',now);         //   solo para concepto 2 o 3
    Request.FeDetReq[0].FchServHasta := FormatDateTime('yyyymmdd',now);          //   solo para concepto 2 o 3
    Request.FeDetReq[0].FchVtoPago   := FormatDateTime('yyyymmdd',now);          //   solo para concepto 2 o 3
    //------------------------------------------------------------------------
  end;

  Request.FeDetReq[0].MonId      := 'PES';
  Request.FeDetReq[0].MonCotiz   := 1;
  //    Request.FeDetReq[0].FchServDesde :=          //   solo para concepto 2 o 3


 // i:= dbTipoCbte.KeyValue;
 // if (i IN [2,3,7,8]) then //es nota de debito o credito lleva doc asociado
 // begin
 //   Request.FeDetReq[0].CbtesAsoc[0].Tipo   := dbTipoCbteVinc.KeyValue;    //  tipo del comprobante asociado (nc/nd)
 //   Request.FeDetReq[0].CbtesAsoc[0].PtoVta := STRTOINT(edtCompVincPto.Text);    //  Punto de venta de la nc
 //   Request.FeDetReq[0].CbtesAsoc[0].Nro    := STRTOINT64(edtCompVincComp.Text);    //  numero de la (nc/nd)
 //end;

  //carga retencion de IIBB si tiene
//  if STRTOFLOAT(edtPercIIBB.Text) > 0 then
//  begin
//      Request.FeDetReq[0].Tributos[0].Id       :=  2;    //2-Imp provincial
//      Request.FeDetReq[0].Tributos[0].Desc     :=  'PERCEPCION DE IIBB BS AS' ;    // Descripcion
//      Request.FeDetReq[0].Tributos[0].BaseImp  :=  STRTOFLOAT(edtSubtotal.Text);    // base imponible
//      Request.FeDetReq[0].Tributos[0].Alic     :=  STRTOFLOAT(edtPercep.Text);    // alicuota
//      Request.FeDetReq[0].Tributos[0].importe  :=  STRTOFLOAT(edtPercIIBB.Text) ;    // imp del tributo
//  end;

  //la factura contiene 2 tipos de iva 10.5 y 21%
//  if (STRTOFLOAT(edtIVA105.Text) > 0) and (STRTOFLOAT(edtIVA21.Text) > 0) then
//  begin
//    Request.FeDetReq[0].Iva[1].id       := 4;     //   alicuota 10.5%
//    Request.FeDetReq[0].Iva[1].BaseImp  := STRTOFLOAT(LNeto105.Caption); //   base imponible
//    Request.FeDetReq[0].Iva[1].importe  := STRTOFLOAT(edtIva105.Text);//   Importe del impuesto
//
//    Request.FeDetReq[0].Iva[0].id       := 5;     //   alicuota 21%
//    Request.FeDetReq[0].Iva[0].BaseImp  := STRTOFLOAT(LNeto21.Caption); //   base imponible
//    Request.FeDetReq[0].Iva[0].importe  := STRTOFLOAT(edtIva21.TExt);//   Importe del impuesto
//    iva := true;
//  end;

  //la factura contiene iva 10.5
//  if (STRTOFLOAT(edtIVA105.Text) > 0) and NOT(iva) then
//  begin
//    Request.FeDetReq[0].Iva[0].id       := 4;     //   alicuota 10.5%
//    Request.FeDetReq[0].Iva[0].BaseImp  := STRTOFLOAT(LNeto105.Caption); //   base imponible
//    Request.FeDetReq[0].Iva[0].importe  := STRTOFLOAT(edtIva105.Text);//   Importe del impuesto
//  end;


  //la factura contiene iva 21
//  if NOT(iva) and (STRTOFLOAT(edtIVA21.Text) > 0) then
//  begin
    Request.FeDetReq[0].Iva[0].id       := 5;     //   alicuota 21%
    Request.FeDetReq[0].Iva[0].BaseImp  := 100; //   base imponible
    Request.FeDetReq[0].Iva[0].importe  := 21;//   Importe del impuesto
//  end;

    //la factura NO LLEVA IVA DISCRIMINADO ES B
//  if (LLetra.Caption = 'B') then
//  begin
//    Request.FeDetReq[0].Iva[0].id       := 3;     //   alicuota 10.5%
//    Request.FeDetReq[0].Iva[0].BaseImp  := STRTOFLOAT(edtSubtotal.Text); //   base imponible
//    Request.FeDetReq[0].Iva[0].importe  := 0;//   Importe del impuesto
//  end;


  //    Request.FeDetReq[0].Opcionales[0].Id    := s(4)    //  id del opcional
  //    Request.FeDetReq[0].Opcionales[0].Valor := s(250); //  valor
  

    port := GetServiceSoap(false,'', httprio1);

    Respuesta := port.FECAESolicitar(Auth,Request );


    Memo1.Lines.Add('RESULTADO: ' + respuesta.fedetresp[0].Resultado);
    Memo1.Lines.Add('CAE: ' + respuesta.fedetresp[0].CAE);
    Memo1.Lines.Add('FECHA VENC: ' + respuesta.fedetresp[0].CAEFchVto);




    //si retorna cae, registra venta
//    if (respuesta.fedetresp[0].Resultado = 'A') then RegistraVenta;




    //--------------------------
    //   ARRAY DE OBSERVACIONES
    //--------------------------
  for x := 0 to high( Respuesta.feDetResp[0].observaciones ) do

      Showmessage('Observ. Code  : '+inttostr(respuesta.fedetresp[0].observaciones[x].Code) +
      ' - Observ. Msg.  : '+respuesta.fedetresp[0].Observaciones[x].Msg);

  
  for x := 0 to High( respuesta.Errors ) do
    Showmessage('Errores : '+inttostr(Respuesta.Errors[x].Code)+' || '+Respuesta.Errors[x].Msg);
   

  auth.Free;
  respuesta.Free;
  Tributos.Free;
  CbtesAsoc.Free;
  DetIva21.Free;
  DetIva105.Free;
 // edHasta.Text := timetostr(now);

  screen.Cursor := crDefault;
end;

AgustinOrtu 03-08-2015 17:57:44

Muy interesante, y eso que lo hiciste por el camino mas dificil ^\||/

El compañero Delphius de DelphiAccess (aunque tambien esta en este foro) propuso en algun momento una iniciativa para implementar los WebService. Seria interesante que el punto de partida sea tu trabajo

Saludos

adripugliesso 04-08-2015 12:46:53

Importate
 
Les comento algo que es clave y sin esto no funcionan los servicios del Webservice de Afip usando WSDL.

1 - Importamos el servicio de WSDL de Afip a nuestra aplicacion para ello vamos a:

Archivo - Nuevos - Otros - Solapa WebService - WDSL Importer

Luego en direccion de importacion ponemos:

Ambiente de prueba (Testing/Homologación):
WS Autenticación y Autorización: https://wsaahomo.afip.gov.ar/ws/services/LoginCms?WSDL
WS Facturación Electrónica: https://wswhomo.afip.gov.ar/wsfev1/service.asmx?WSDL

Ambiente real (Producción):
WS Autenticación y Autorización: https://wsaa.afip.gov.ar/ws/services/LoginCms?WSDL
WS Facturación Electrónica: https://servicios1.afip.gov.ar/wsfev1/service.asmx?WSDL

Al hacer esto se nos va a agregar a nuestra aplicacion las unit con los metodos directos de los webservice de afip para usar como funciones internas de la aplicacion.

2 - Lo importante y aca viene el secreto es que en las dos unit que se agregan de WSFEv1 hay que ir a la parte de INITIALIZATION y agregar la linea:

Código Delphi [-]
 //se agrega esto
  InvRegistry.RegisterInvokeOptions(TypeInfo(ServiceSoap), ioDocument);

adripugliesso 04-08-2015 22:02:55

Otros Detalles
 
Para los que usen webservice importando el WSDL

Forma de llamar a un método, en este caso (FEParamGetTiposDoc):
Código Delphi [-]
procedure TForm1.Button5Click(Sender: TObject);
var
  FEAuth : FEAuthRequest;
  x : Integer;
  s: DocTipoResponse;
  WS: ServiceSoap;
begin
  screen.Cursor := crHourGlass;

  WS := GetServiceSoap(false,'', httprio1);

  FEAuth  := FEAuthRequest.Create;
  try
    FEAuth.Token := token;
    FEAuth.Sign  := sign;
    FEAuth.Cuit  := cuit;

    Memo1.Clear;

    s := WS.FEParamGetTiposDoc(FEAuth);

    if (Length(s.ResultGet) > 0) then
    begin
      for x := 0 to high( s.ResultGet ) do
      Memo1.lines.Add(
        INTTOSTR(s.ResultGet[x].id)+' || '+
        s.ResultGet[x].Desc+' || '+
        s.ResultGet[x].FchDesde+' || '+
        s.ResultGet[x].FchHasta );
     end;

      if (Length(s.Errors) > 0) then
      showmessage(s.Errors[0].Msg);

  finally
    FEAuth.Free;
    s.Free;
  end;
  screen.Cursor := crDefault;
end;
Lo importante en esto es agregar en el componente HTTPRIO:
Código Delphi [-]
procedure TForm1.HTTPRIO1AfterExecute(const MethodName: String;
  SOAPResponse: TStream);
var
  texto : String;
   f: Integer;
   sl: TStringList;
begin
   SoapResponse.Position := 0;
   f:= FileCreate('after.xml');
   sMemo1.lines.add('===========  AFTER EXECUTE  =====================');
   setlength( texto, SOAPResponse.size );
   soapResponse.Read(Texto[1], SOAPResponse.Size);
   smemo1.lines.add( Texto );
   smemo1.lines.add('----------------------------------------------');
   sMemo1.lines.add( MethodName );
   smemo1.lines.add('======== FIN AFTER EXECUTE ======================');

   FileWrite(f, texto[1], Length(texto));
   FileClose(f);

   sl := TStringList.Create;
   try
     sl.Text := Texto;
     sl.SaveToFile('after-sl.xml');
   finally
     sl.Free;
   end;

end;

Casimiro Notevi 04-08-2015 22:56:37

De nuestra guía de estilo:
Cita:

6. No escribir nunca los mensajes en mayúsculas, esto denota falta de respeto a los foristas.
Escribir en mayúsculas equivale a gritar.

adripugliesso 04-08-2015 23:09:50

disculpas no lo sabia, como lo modifico??

Casimiro Notevi 04-08-2015 23:13:12

Pues es así en todo internet en todo el mundo :)
Voy a editarlo.
Gracias por tu colaboración :)

iMia 19-08-2015 08:37:58

Fantástica aportación y explicación Adripugliesso...
Ye falta explicar el porque de un par de cosas...

- El añadir la llamada "InvRegistry.RegisterInvokeOptions(TypeInfo(ServiceSoap), ioDocument);" en la claúsula Inizialization es por que ese WS no soporta SOAP 1.2 con tipos text/xml... con eso se le indica que el contenido es simplemente text. Es debido a un fallo en los servidores de tomcat que no se suelen configurar de forma correcta.

- En el HTTPRIO, añadir el afterexecute, no es realmente necesario, pero se hace para monitorear los mensajes recibidos y poder guardarlo y analizarlos... pero es algo que se puede obviar...

rruffino 22-04-2016 02:31:32

Consulta
 
Hola, buenas noches!
Yo tambien estoy usando directamente los webservices pero se me ha dado un caso, y es cuando el comprobante a validar solo tiene importes EXENTOS, cuando armo el objeto de Detalle, necesito sacarle el apartado IVA para no presentarlo sino da error en la validacion. Alguien sabe como hacerlo?

giulichajari 23-04-2016 18:48:50

Por lo que veo si has usado openssl, entonces no usas el WSDL de WSAA de autorizacion digamos??

hsbelli 29-04-2016 21:13:02

hola, en que seccion del ftp esta el archivo con los fuentes y como se llama dicho archivo?
gracias!

saludos

fredymam 20-07-2016 15:26:15

Hola!! comunidad

Estaba teniendo el mismo problema en Delphi7 y la corrección que publicaron
Código Delphi [-]
 InvRegistry.RegisterInvokeOptions(TypeInfo(ServiceSoap), ioDocument);
resolvió gran parte :):)

Aunque ahora tengo otro problema con CbtesAsoc, Tributos y Otros; y resulta imposible enviarlos vacíos, dando el siguiente error:

--->> Observaciones:
Code: 10062 - Msg.: Si envia CbtesAsoc, CbteAsoc es obligatorio.
Code: 10052 - Msg.: Si envia Opcionales, Opcional es obligatorio.


Código Delphi [-]
var
  Retenciones : ArrayOfTributo;
  Detalle        : FECAEDetRequest;
begin
  SetLength(Retenciones,0);
  Detalle.CbtesAsoc := Retenciones;

SpyO_O 24-04-2017 06:57:49

OpenSSL
 
Hola Amigo, gracias por el aporte.
Estoy interesado en ver como llamas al webservices "logincms", yo estoy haciendo lo siguiente , pero obtengo siempre el mensaje de error "El CMS es inválido".
Código Delphi [-]
procedure TForm1.Button1Click(Sender: TObject);
var
 vService:uLogincms.LoginCMS;
 vCms:String;
begin
    Memo1.Clear;
    Memo1.Lines.LoadFromFile('C:\Afip\myProject\manual\tra.xml.firmado');
    vcms:=Memo1.Lines.Text;
    vService:=ulogincms.GetLoginCMS();
    Memo1.lines.text:=vService.loginCms(vcms);

La unit uLogincms es el wdsl importado de https://wsaahomo.afip.gov.ar/ws/services/LoginCms?wsdl

Podrías darme una mano con esto por favor? , no encontré en el FTP el código que habias dicho que lo subirías .

Gracias


Cita:

Empezado por adripugliesso (Mensaje 494460)
Sin ocx, sin componentes 100% codigo delphi

Tengo el codigo en delphi para solicitar cae y demas funciones del webservice de Afip funcionando 100% codigo puro de delphi sin OCX ni Componentes Raros.

Saludos..


PD: Enseguida pondré enlace al código, que lo subiré al FTP.


.


hgiacobone 19-05-2017 20:08:36

Cita:

Empezado por Casimiro Notevi (Mensaje 495232)
De nuestra guía de estilo:
Escribir en mayúsculas equivale a gritar.

La cosa es que el tipo se mandó flor de post explicando algo que es muy solicitado por toda la comunidad, y le observan terrible bobada. :confused:

Poner en "Mayúsculas" el nombre de una instrucción Pascal, no es ni por asomo, una violación a la guia de estilo. Aparte, la suposición de que las mayusculas representan un grito :eek:, al menos a estas alturas, solo se considera una cuestión folclórica y tal vez hoy solo es utilizado por "History Chanel" cuando tratan temas como el inicio de las terminales de texto. Y tal vez ni eso.

Como sugerencia, deberían reveer este tipo de comentarios absurdos.
Cordialmente,
YAKO

hgiacobone 19-05-2017 20:10:31

Estimado amigo adripugliesso
Subiste el código al FTP del sitio ?
Donde podemos encontrar más info sobre tu solución?

adripugliesso 19-05-2017 20:55:37

Proyecto Ejemplo en Delphi 7
 
1 Archivos Adjunto(s)
Acá les dejo un proyecto de ejemplo hecho en Delphi 7 de como usar los WebService de AFIP para Facturación Electrónica.

Cualquier duda consulten..

Espero que les sirva.-

Casimiro Notevi 19-05-2017 23:48:16

Cita:

Empezado por hgiacobone (Mensaje 516885)
La cosa es que el tipo se mandó flor de post explicando algo que es muy solicitado por toda la comunidad, y le observan terrible bobada. :confused:
Poner en "Mayúsculas" el nombre de una instrucción Pascal, no es ni por asomo, una violación a la guia de estilo. Aparte, la suposición de que las mayusculas representan un grito :eek:, al menos a estas alturas, solo se considera una cuestión folclórica y tal vez hoy solo es utilizado por "History Chanel" cuando tratan temas como el inicio de las terminales de texto. Y tal vez ni eso.
Como sugerencia, deberían reveer este tipo de comentarios absurdos.
Cordialmente,
YAKO

Ese mensaje es de hace 2 años, y el mensaje al que se refiere se editó para cumplir las normas.
En fin, bobadas, las que tú has soltado.

seti.roman 30-05-2017 01:17:30

OpensslUtils
 
Hola, soy nuevo en este Foro, les dejo algo que puede servirles, quizás no esté muy claro. Es para firmar el ticket sin usar un Bat a la librería Openssl.
Deben conseguir OpensslUtils, que no recuerdo donde la encontré e incorporarla al proyecto.

Les adjunto el código que uso yo. Espero les sea útil.

Código:

function Tcomprobante.crearfirma: string;
var
  signer: TMessageSigner;
  camino: String;
  ruta: Pwidechar;
  firma: String;
  position: integer;
begin
  camino := ExpandFileName(application.ExeName + '\..\keys');
  ruta := Pwidechar(camino);

  fgeneracion := now();
  fexpiracion := inchour(fgeneracion,1);

  signer := TMessageSigner.Create;
  signer.LoadPrivateKey(ruta +'\'+ responsable.edita_responsables['llave'], '');
  signer.LoadCertificate(ruta + '\'+ responsable.edita_responsables['cert']);

  signer.PlainMessage :=
  '<?xml version="1.0" encoding="UTF-8" ?>'+
  '<loginTicketRequest version="1.0">'+
  '<header>'+
  '<uniqueId>123456</uniqueId>'+
  '<generationTime>'+formatdatetime('yyyy-MM-dd',fgeneracion)+'T'+formatdatetime('hh:mm',fgeneracion)+':00-03:00</generationTime>'+
  '<expirationTime>'+formatdatetime('yyyy-MM-dd',fexpiracion)+'T'+formatdatetime('hh:mm',fexpiracion)+':00-03:00</expirationTime>'+
  '</header>'+
  '<service>wsfe</service>'+
  '</loginTicketRequest>';

  signer.MIMESign;

  firma := signer.SignedMessage;
  firma := rightstr(firma,length(firma)-186);

  position := ansipos('==', firma);
  if position <> 0 then
  begin
    delete(firma,position,length(firma));
  end;

  result := firma;
end;


sanamarain 30-10-2017 17:53:14

Hola también soy nuevo en el foro. Pude implementar una interface de factura electrónica con éxito y rápidamente sobre Delphi 7 gracias al gran aporte de adripugliesso, pero me interesa generar el CMS directamente sin la intervención de openssl como binario externo, es decir con la OpensslUtils que ya conseguí de la web de la universidad de Genoa de Marco Ferrante para la versión .7b de openssl (dll).
La consulta es para seti.roman, hay alguna otra rutina para implementar además de la que ya compartiste? Porque no logro validar el CMS generado.
Llego a crear el smime.p7m que es el archivo firmado con signed-data en formato Email, luego quito la cabecera, codifico en base64 y envío pero algo estoy haciendo mal o está faltando porque me devuelve "CMS inválido".

Saludos

seti.roman 30-10-2017 19:42:34

Hola, estuve probando hoy nuevamente y me pasó que la firma es inválida (antes funcionaba).
1) Estoy modificando el código a ver si lo hago andar nuevamente.

2) Yo uso la librería OpenSSLUtils.pas (0.9.6b) que también necesita libeay32.pas (0.9.6b) y las agrego al proyecto
(agregala a uses: OpenSSLUtils y libeay32 en tu form o módulo)

seti.roman 30-10-2017 20:13:23

Ahora va corregido y (por ahora) funcionando:

Código:

function Tcomprobante.crearfirma: string;
var
  signer: TMessageSigner;
  ruta: Pwidechar;
  firma: String;
  position: integer;
begin
  ruta := Pwidechar(ExpandFileName(application.ExeName + '\..\keys'));

  fgeneracion := now();
  fexpiracion := inchour(fgeneracion,1);

  signer := TMessageSigner.Create;
  signer.LoadPrivateKey(ruta +'\'+ responsable.edita_responsables['llave'], '');
  signer.LoadCertificate(ruta + '\'+ responsable.edita_responsables['cert']);

  signer.PlainMessage :=
  '<?xml version="1.0" encoding="UTF-8" ?>'+
  '<loginTicketRequest version="1.0">'+
  '<header>'+
  '<uniqueId>123456</uniqueId>'+
  '<generationTime>'+formatdatetime('yyyy-MM-dd',fgeneracion)+'T'+formatdatetime('hh:mm',fgeneracion)+':00-03:00</generationTime>'+
  '<expirationTime>'+formatdatetime('yyyy-MM-dd',fexpiracion)+'T'+formatdatetime('hh:mm',fexpiracion)+':00-03:00</expirationTime>'+
  '</header>'+
  '<service>wsfe</service>'+
  '</loginTicketRequest>';

  signer.MIMESign;

  firma := signer.SignedMessage;
  firma := rightstr(firma,length(firma)-188); //*********** AGREGUE 2

  position := ansipos('==', firma);
  if position <> 0 then
  begin
    delete(firma,position+2,length(firma)); //******** SUME 2 A LA POSICION PARA QUE INCLUYA LOS ==
  end;
  xgs.observartexto(firma);
  result := firma;
end;


seti.roman 30-10-2017 20:28:27

Cita:

Empezado por sanamarain (Mensaje 522129)
Hola también soy nuevo en el foro. Pude implementar una interface de factura electrónica con éxito y rápidamente sobre Delphi 7 gracias al gran aporte de adripugliesso, pero me interesa generar el CMS directamente sin la intervención de openssl como binario externo, es decir con la OpensslUtils que ya conseguí de la web de la universidad de Genoa de Marco Ferrante para la versión .7b de openssl (dll).
La consulta es para seti.roman, hay alguna otra rutina para implementar además de la que ya compartiste? Porque no logro validar el CMS generado.
Llego a crear el smime.p7m que es el archivo firmado con signed-data en formato Email, luego quito la cabecera, codifico en base64 y envío pero algo estoy haciendo mal o está faltando porque me devuelve "CMS inválido".

Saludos

A ver, yo tuve que hacer esto con el token y el sign cuando los recibía después de enviar la solicitud firmada,
dado que venian con etiquetas y algún caractér raro, no me acuerdo muy bien. Te lo paso:

Código:

function Tcomprobante.autenticar: Tstringlist;
var
  autenticar: Tstringlist;
begin
  autenticar := Tstringlist.Create;
  autenticar.Text := (HTautenticar as LoginCms).loginCms(crearfirma);

  result := autenticar;
end;

function Tcomprobante.obteneraut: Tstringlist;
var
  cms: Tstringlist;
  i: Integer;
  token: String;
  sign: String;
begin
  cms := Tstringlist.Create;
  cms := autenticar;

  for i := 0 to cms.Count-1 do
  begin
    cms[i] := Trimleft(cms[i]);

    if StartsText('<token>',cms[i]) then
    begin
      cms[i] := cms[i].Replace('<token>', '');
      cms[i] := cms[i].Replace('</token>', '');
      token := cms[i];

      cms[i+1] := cms[i+1].Replace('<sign>', '');
      cms[i+1] := cms[i+1].Replace('</sign>', '');
      sign := cms[i+1];
    end;
  end;

  cms.Clear;

  cms.Add(Trimleft(token));
  cms.Add(Trimleft(sign));

  guardaraut(cms[0],cms[1]);
end;


sanamarain 01-11-2017 13:31:41

Muchas gracias por la pronta respuesta. Aún no lo he probado, pero intuía que estaba firmando mal por la comparación que yo hacía con la firma generada por openssl por línea de comandos. Sólo me faltaba la firma (para no hacerlo con openssl.exe), lo demás está todo implementado. Muchísimas gracias también por el código de la recuperación del token y sign. En un momento lo pruebo y posteo como me fue.

sanamarain 01-11-2017 13:52:55

Funcionó perfectamente!!! Sólo cambiando las líneas de las funciones rightstr y delete.
Muchísimas gracias, había dado muchas vueltas con esto y la solución era sencilla.

lucho6007 21-12-2017 15:00:10

Hola gente! Estuve probando el ejemplo subido, compila perfecto sobre XE3, lo pruebo con certificados de homomlogación en un Windows 10 de 64 bits y genera bien el CAE. Pruebo el mismo ejecutable sobre una máquina virtual con XP y me dice: No se a podido establecer una conexión con el servidor - URL:https://wsaahomo.afip.gov.ar/ws/services/LoginCms - SOAPAction:""

Lo mas extraño es que si pruebo en la misma VM los componentes PyAFIPws si se conecta y genera los CAEs...

Alguien tiene idea que pasa?
Muchas gracias por su tiempo!

lucho6007 21-12-2017 22:00:25

Me auto-respondo:
Funcoina sólo si tiene XP service pack 3, y
"Verificar tener activada la casilla "USAR TLS 1.0" en "Opciones de Internet->Opciones Avanzadas"

lucho6007 23-12-2017 21:17:00

Código de barras
 
Hola colegas, alguno tiene idea cómo generar el código de barras que se imprime en la Fact. electrónica?
Es decir, ya tengo como codificarlo, pero no se como armar las "barras".
Se que va CUIT, Pto de venta, CAE, etc pero no se como armar las barras... Alguno tiene idea??

Muchas gracias y felices fiestas!

aledieb 26-12-2017 13:41:59

Hola,
Cita:

Empezado por lucho6007 (Mensaje 523736)
Hola colegas, alguno tiene idea cómo generar el código de barras que se imprime en la Fact. electrónica?
Es decir, ya tengo como codificarlo, pero no se como armar las "barras".
Se que va CUIT, Pto de venta, CAE, etc pero no se como armar las barras... Alguno tiene idea??

Muchas gracias y felices fiestas!

Tenes que usar algún componente para código de barra o de reportes que lo incluya, el tipo de código de barra es el Interleaved 2 of 5, fastreport lo incluye y permite generar el código de verificación.

Este es uno que genera una imagen bmp ó jpg Version 3.7, Copyright (c) 2014-2017 WINSOFT, http://www.winsoft.sk

lucho6007 26-12-2017 14:02:39

Finalmente lo hice a mano, me basé en el codigo en Pyhton de PyAFIPws:
Código Delphi [-]
function GenerarImagen(AImage: TImage; Codigo: String; BaseWidth: Integer = 3; Width: Integer = 0; Height: Integer = 30): Boolean;
var Wide, Narrow, Barra, Espacio: Integer;
    BarraStr: String;
    XPos, I, J: Integer;

const Bars: array[0..11] of string = ('nnwwn', 'wnnnw', 'nwnnw', 'wwnnn', 'nnwnw', 'wnwnn', 'nwwnn', 'nnnww', 'wnnwn', 'nwnwn', 'nn', 'wn');
begin
  if AImage = nil then begin
    AImage:= TImage.Create(nil);
  end;

  Result:= False;
  Wide:= BaseWidth;
  Narrow:= BaseWidth div 3;

  if Odd(Length(Codigo)) then begin
    Codigo:= '0' + Codigo;
  end;

  Codigo:= '::' + Codigo + ';:'; // A y Z en el original

  if Width = 0 then begin
    Width:= (Length(Codigo) * 3) * BaseWidth + (10 * Narrow);
  end;
  AImage.Width:= Width;
  AImage.Height:= Height;

  AImage.Canvas.Pen.Color := clWhite;
  AImage.Canvas.Brush.Color:= clWhite;
  AImage.Canvas.Rectangle(0, 0, AImage.Width, AImage.Height);
  AImage.Canvas.Brush.Color:= clBlack;
  AImage.Canvas.Pen.Color := clBlack;

  XPos:= 18;
  I:= 1;
  while I <= Length(Codigo) do begin
    Barra:= Ord(Codigo[i]) - Ord('0');
    Espacio:= Ord(Codigo[I + 1]) - Ord('0');
    BarraStr:= '';
    for J:= 1 to Length(Bars[Barra]) do begin
      BarraStr:= BarraStr + Bars[Barra][J] + Bars[Espacio][J];
    end;

    for J:= 1 to Length(BarraStr) do begin
      if BarraStr[J] = 'n' then begin
        Width:= Narrow;
      end
      else begin
        Width:= Wide;
      end;
      if Odd(J) then begin
        AImage.Canvas.Rectangle(XPos, 0, XPos + Width, Height);
      end;
      XPos:= XPos + Width;
    end;
    Inc(I, 2);
  end;
  Result:= True;
end;

hagsoft 19-07-2018 04:51:33

me da error de base64 en delphi berlin 10.1 alguna idea ?

Casimiro Notevi 19-07-2018 08:31:58

¿Dónde y qué error?

aledieb 09-08-2018 21:25:02

Cita:

Empezado por hagsoft (Mensaje 527686)
me da error de base64 en delphi berlin 10.1 alguna idea ?


Proba lo que arme, esta sin terminar pero te puede servir: http://www.clubdelphi.com/foros/showthread.php?t=92602

ingfnmonteros 09-01-2019 18:58:40

Cita:

Empezado por adripugliesso (Mensaje 516889)
Acá les dejo un proyecto de ejemplo hecho en Delphi 7 de como usar los WebService de AFIP para Facturación Electrónica.

Cualquier duda consulten..

Espero que les sirva.-

Hola como están soy nuevo en esto, cuando intento correr el ejemplo de adripugliesso - WebService de AFIP para Facturación Electrónica
me sale el siguiente error: no se puede decodificar base64 al momento de generar el sign y token
Estuve leyendo todo el foro y entendiendo el código, pero me parece que me esta faltando algo por hacer, es mi primera ves con openssl y todo esto
Alguien me podria dar una pista para seguir adelante, lo compile con delphi 7


La franja horaria es GMT +2. Ahora son las 07:56:14.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi