Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Delphi para la web (https://www.clubdelphi.com/foros/forumdisplay.php?f=51)
-   -   Consumir servicio web con WDSL - autentificación WS-Security (https://www.clubdelphi.com/foros/showthread.php?t=87914)

frankizzio 18-03-2015 19:44:40

Consumir servicio web con WDSL - autentificación WS-Security
 
1 Archivos Adjunto(s)
Hola,
Mi nombre es Franco, y estoy a cargo de un proyecto de Facturación electrónica en Perú,
buscando información sobre el tema pude ver que existe la posibilidad de crear clases definidas mediante el WDSL Importer de delphi en File/New/Other/WebServices/,
El link que utilizo es el siguiente h t tps://w ww.sunat. gob.pe: 443/ol-ti-it cpgem-beta/bill Service?wsdl

Pero cuando trato de realizar la conexión, enviando el arreglo de bits y el nombre del archivo como se especifica(datos demo) me aparece un mensaje de error como si no se hubiera creado algo.

Este es mi código

Código Delphi [-]
procedure TForm1.Button1Click(Sender: TObject);
var
  tBillServ : billService;
  tSendB    : sendBill;
  ByteA     : TByteDynArray;
  tSendBResp: sendBillResponse;
begin
  tSendB:=sendBill.Create;
  tSendBResp:=sendBillResponse.Create;
  tSendB.fileName:='Demo.zip';
  SetLength(ByteA,2);
  ByteA[0]:=10;
  ByteA[1]:=20;
  tSendB.contentFile:=ByteA;
  tSendBResp:=tBillServ.sendBill(tSendB);
end;

¿En que me estoy equivocando?, La conexión es mediante Soap utilizando WS-Security usando el modelo UserNameToken y no se si se necesite realizar un procedimiento más, soy nuevo en este tipo de procesos y no encuentro info que me pueda orientar.
Espero que me puedan ayudar, gracias.

Adjunto archivo generado por el WDSL Importer

jhonny 18-03-2015 21:47:42

Ahí no hay de otra que apegarse a la documentación del servicio, el WSDL es muy completo y nos colabora mucho en ese sentido, pero hay detalles que requieren de la documentación y sobre todo de la claridad acerca de la funcionalidad que ofrece el servicio.

jhonny 18-03-2015 21:58:50

Por otro lado, mirando el WSDL importado... solo estás asignando el nombre del archivo a tSendB.fileName, debe estar haciéndote falta asignar el arreglo de Bytes (Podrías usar un TBytesStream para cargar el archivo Demo.zip) a tSendB.contentFile, es muy probable que (Sin haber leido la documentación por mi parte) por ahí sea el norte de lo que buscas.

frankizzio 18-03-2015 22:12:57

Consumir servicio con WDSL - autentificación WS-Security
 
Hola Jhonny gracias por responder,

El servicio es de una entidad del estado, la cual consiste en enviar un arreglo de bits(de un archivo zipeado) y el nombre del archivo, esto con la autentificación WS-Security, ahora lo que no se es si las clases que se generan resuelven todo ese problema o tengo que utilizar el componente HTTPRIO para realizar la conexión con el servicio web.

En su manual de programador dicen lo siguiente

1) Los documentos XML de la factura, boleta de venta y notas de crédito y debito, así como del resumen diario y comunicaciones de baja, antes de ser enviados a la SUNAT, deberán ser empaquetados en un archivo ZIP.
...
3) El envío de los archivos ZIP, indicados en el punto 1, será vía WebServices.
4) El servicio Web estará protegido con un esquema de seguridad basado en WSSecurity.
5) El modelo de seguridad usado en WSSecurity será UsernameToken

El servicio web de recepción cuenta con un método personalizado para aceptar cada tipo de documento electrónico. Los métodos de recepción definidos son los siguientes:
- sendBill, este método recibe un archivo ZIP con un único documento XML de comprobante y devuelve un archivo Zip que contiene un documento XML que es la constancia de aceptación ó rechazo.
- sendSummary, este método recibe un archivo Zip con un único documento XML de resúmenes, ya sea resumen de boletas o comunicación de bajas. Devuelve un ticket con el que posteriormente utilizando el método getStatus se puede obtener el archivo Zip que contiene un documento XML que es la constancia de aceptación o rechazo.
- getStatus, este método recibe el ticket como parámetro y devuelve un objeto que indica el estado del proceso y en caso de haber terminado, devuelve adjunta la constancia de aceptación o rechazo.

Ejemplo SOAP para invocar el servicio SendBill:
Código:

<soapenv:Envelope xmlns:soapenv="h ttp://sche mas.xmlsoap.org/soap/envelope/" xmlns:ser="ht tp://serv ice.sunat.gob.pe" xmlns:wsse="h ttp://do cs.o asis-open.org/wss/2004/01/oasis-200401-wss-wssec urity-secext-1.0.xsd"> <soapenv:Header> <wsse:Security> <wsse:UsernameToken> <wsse:Username>20100066603MODDATOS</wsse:Username> <wsse:Password>moddatos</wsse:Password> </wsse:UsernameToken> </wsse:Security> </soapenv:Header> <soapenv:Body> <ser:sendBill> <fileName>20100066603-01-F001-1.zip</fileName> <contentFile>cid:20100066603-01-F001-1.zip</contentFile> </ser:sendBill> </soapenv:Body> </soapenv:Envelope>
Por otro lado, lo que hice fue llenar con otro TByteDynArray llamado ByteA el ContentFile porque aún no tengo el archivo generado con todas las especificaciones, entonces que no cargue el archivo Zip puede ser el problema

frankizzio 18-03-2015 22:16:14

Consumir servicio con WDSL - autentificación WS-Security
 
Cuando ejecuto la aplicación de prueba me aparece una violación de acceso como si un componente no este creado, los dos tienen valores, el filename y el contentfile, es más en tiempo de depuración puedo comprobarlo.

frankizzio 19-03-2015 20:28:13

Consumir servicio con WDSL - autentificación WS-Security
 
Lo resolví utilizando esta función

Código Delphi [-]
function GetbillService(UseWSDL: Boolean; Addr: string;var HTTPRIO: THTTPRIO): billService;
 const
  defWSDL = 'htt ps://ww w. sunat. gob. pe:443/ol-ti-itcpgem-beta/billService?wsdl';
  defURL  = 'htt ps://w ww.s unat. gob. pe:443/ol-ti-itcpgem-beta/billService';
  defSvc  = 'billService';
  defPrt  = 'BillServicePort';
 var
  RIO: THTTPRIO;
 begin
  if (Addr = '') then
  begin
    if UseWSDL then
      Addr := defWSDL
    else
      Addr := defURL;
  end;
  if HTTPRIO = nil then
    RIO := THTTPRIO.Create(nil)
  else
    RIO := HTTPRIO;
  try
    Result := (RIO as billService);
    if UseWSDL then
    begin
      RIO.WSDLLocation := Addr;
      RIO.Service := defSvc;
      RIO.Port := defPrt;
    end else
      RIO.URL := Addr;
  finally
    if (Result = nil) and (HTTPRIO = nil) then
      RIO.Free;
  end;

 end;

Y utilizandolo en la acción del botón

Código Delphi [-]
    tBillServ:=GetbillService(True,'',HTTPRIO1);

Establezco la conexión pero el WSDL Importer no generó la cabecera de seguridad UsernameToken, ahora un nuevo dilema, buscando en internet encuentro info sobre como implementar una unit llamada WSSE.pas pero no me queda claro su función
Cómo puedo configurar la cabecera para que aparezca de la siguiente manera

Código:

<soapenv:Envelope xmlns:soapenv="ht tp:// sc hem as. xmls ap .o rg/soap/env elope/" xmlns:ser="h tt p: //ser vice. sun at .go b .pe" xmlns:wsse="ht tp:// do cs. oasis- op en. org /wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"> <soapenv:Header> <wsse:Security> <wsse:UsernameToken> <wsse:Username>20100066603MODDATOS</wsse:Username> <wsse:Password>moddatos</wsse:Password> </wsse:UsernameToken> </wsse:Security> </soapenv:Header> <soapenv:Body> <ser:sendBill> <fileName>20100066603-01-F001-1.zip</fileName> <contentFile>cid:20100066603-01-F001-1.zip</contentFile> </ser:sendBill> </soapenv:Body> </soapenv:Envelope>

jhonny 22-03-2015 07:32:55

Ahhh caramba, cierto, no comprendo como se me pasó ese asunto, el WSDL Importer siempre crea una función con el Get ante puesto y el nombre del servicio... para consumir el IInvokable :p :p :p, que bueno que lo encontraste por sí mismo.

frankizzio 22-03-2015 20:04:09

Gracias Jhonny, tuve una semana informándome de los conceptos de este tipo de web service aún me falta mucho pero allí vamos.

HubelSB 18-10-2016 18:45:44

Saludos
 
Saludos tambien trabajo con el tema de la SUNAT y en delphi, sobre el proceso de formar los XML utilize las plantillas de sunat y lo pase a un decodificador que me genera codigo fuente a partir del XML de la SUNAT, asi el proceso se hizo repetitivo para el kit de homologacion, en la parte de cifrado estoy utilizando XMLSec que lo ejecuto en segundo plano, una vez listo el XML firmado lo comprimo con 7zip, y ahora estoy en la parte de envio, estare subiendo todo el codigo, conforme avance, aunque recientemente recibi una charla por parte de la SUNAT donde se me informo sobre el SISTEMA FACTURADOR SUNAT, al cual solo hay que pasarle archivos planos, TXTs, con los campos a enviar y hace todo el proceso en el que hemos estado trabajando, voy a probarlo, si funciona todo ok, quedaria un camino mas en caso no terminar con el codigo.

D1360666 22-12-2016 16:38:44

consulta
 
Hola yo estoy con un problema similar.
Importe el wsdl con el importer, pero no sé como generar el WS-SECURITY.
tengo un WSDL para desarrollar facturación electrónica en Uruguay.

En caso de no importar con el Importer.

Manualmente como se debe hacer?

Gracias saludos!!

HubelSB 25-12-2016 00:06:01

Tengo Respuesta
 
1). Con el WSDL Importer, darle la direccion del WS, para mi caso :

https://e-beta.sunat.gob.pe/ol-ti-it...llService?wsdl

se genera la unidad billService1.pas

la cual contiene la siguiente funcion GetbillService, ojo segun las versiones de delphi estas cambian en D7 y D2007 no se soportan los InvRegistry.RegisterParamInfo, si quieres generar un billService para versiones antiguas marca la opcion TXSxxxx for simple nillable, asi se genera un billservice capaz de usarse en versiones anteriores, yo estoy usando XE4 y bueno ahora D10.1 Berlin, esto de los webservices es mejor hacerlo con versiones nuevas, aunque las antiguas generan ejecutables mas rapidos.

2). Utilizar billservice1.pas

Para mi caso hay securidad ws-token, asi que para implementar la cabecera donde enviar el usuario y clave use THTTPReqResp

En un boton poner el siguiente codigo, ojo para la SUNAT peru, nos responde con un zip dentro del cual esta un xml con la respuesta si el documento ha sido aceptado o no, el archivo tiene que ser cargado en un array de bytes asi que lineas mas abajo te dejo los procedure que use.

Aun no termino el proyecto, ahora con wireshark estoy examinando como viajan los paquetes hacia el servidor, con la finalidad de ver si cumplen con el estandar que solicita SUNAT, cuando lo tengo listo lo libero :D hubelsolis@hotmail.com


procedure TForm1.Button1Click(Sender: TObject);
const
defWSDL = 'https://e-beta.sunat.gob.pe/ol-ti-itcpfegem-beta/billService?wsdl';
defURL = 'https://e-beta.sunat.gob.pe:443/ol-ti-itcpfegem-beta/billService';
defSvc = 'billService';
defPrt = 'BillServicePort';
var
tBillServ : billService;
Archivo : String;
Envio : TByteDynArray;
Respuesta : TByteDynArray;

HTTPReqResp1: THTTPReqResp;
HTTPRIO1 : THTTPRIO;
begin
HTTPReqResp1 := THTTPReqResp.create(nil);
HTTPReqResp1.Password := 'moddatos';
HTTPReqResp1.username := '20489697042MODDATOS';

HTTPRIO1 := THTTPRIO.Create(nil);
HTTPRIO1.HTTPWebNode := HTTPReqResp1;
HTTPRIO1.WSDLLocation := defWSDL;
HTTPRIO1.Service := defSvc;
HTTPRIO1.Port := defPrt;

// levanto el servicio
tBillServ:=GetbillService(TRUE,'',HTTPRIO1);
Archivo:='20489697042-03-BB01-00000003.ZIP';
envio:= FileToByteArray('D:\'+Archivo);

// envio
try
respuesta:=tBillServ.sendBill(Archivo,envio);
except
on E : Exception do
ShowMessage(E.ClassName+' error raised, with message : '+E.Message);
end;

ByteArrayToFIle(respuesta, 'D:\respuestas\rptab.zip' );

end;



procedure ByteArrayToFIle(const ByteArray : TByteDynArray; const FileName : string );
var Count : integer;
F : FIle of Byte;
pTemp : Pointer;
begin
AssignFile( F, FileName );
Rewrite(F);
try
Count := Length( ByteArray );
pTemp := @ByteArray[0];
BlockWrite(F, pTemp^, Count );
finally
CloseFile( F );
end;
end;

function FIleToByteArray( const FileName : string ) : TByteDynArray;
const BLOCK_SIZE=1024;
var BytesRead, BytesToWrite, Count : integer;
F : FIle of Byte;
pTemp : Pointer;
begin
AssignFile( F, FileName );
Reset(F);
try
Count := FileSize( F );
SetLength(Result, Count );
pTemp := @Result[0];
BytesRead := BLOCK_SIZE;
while (BytesRead = BLOCK_SIZE ) do
begin
BytesToWrite := Min(Count, BLOCK_SIZE);
BlockRead(F, pTemp^, BytesToWrite , BytesRead );
pTemp := Pointer(LongInt(pTemp) + BLOCK_SIZE);
Count := Count-BytesRead;
end;
finally
CloseFile( F );
end;
end;

D1360666 26-12-2016 19:59:27

Muchas gracias amigos Husbel.
Lo voy a probar y les aviso como me fué.
Saludos.

Casimiro Notevi 26-12-2016 20:17:05

Cita:

Empezado por HubelSB (Mensaje 511995)
1)...

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



Gracias :)

D1360666 27-12-2016 14:11:20

Husbel amigo te consulto.
En lugar de utilizar ws-token, si uso username utilizo el mismo componente??

D1360666 23-01-2017 14:39:40

ws
 
Tengo una duda. Porque he probado muchas cosas y no llego a poder agregar un header de seguridad al comunicarme con un WS con el componente HTTPRIO y el Wsdl importer.

Estoy comunicando con un sistema de facturación eletrónica en Uruguay.
Importo el Wsdl, agrego un HTTPRIO, pero al tener seguridad la comunicación con ws-token, username y password.
Como tengo que hacer para agregar un header a la comunicación, si hay algún ejemplo les agradezco amigos.

He leído un poco sobre InvokeRegistry, etc pero no llego a una solución.
Gracias, saludos!!

jpanta 09-06-2017 16:55:15

Cita:

Empezado por HubelSB (Mensaje 511995)
1). Con el WSDL Importer, darle la direccion del WS, para mi caso :

https://e-beta.sunat.gob.pe/ol-ti-it...llService?wsdl

se genera la unidad billService1.pas

la cual contiene la siguiente funcion GetbillService, ojo segun las versiones de delphi estas cambian en D7 y D2007 no se soportan los InvRegistry.RegisterParamInfo, si quieres generar un billService para versiones antiguas marca la opcion TXSxxxx for simple nillable, asi se genera un billservice capaz de usarse en versiones anteriores, yo estoy usando XE4 y bueno ahora D10.1 Berlin, esto de los webservices es mejor hacerlo con versiones nuevas, aunque las antiguas generan ejecutables mas rapidos.

2). Utilizar billservice1.pas

Para mi caso hay securidad ws-token, asi que para implementar la cabecera donde enviar el usuario y clave use THTTPReqResp

En un boton poner el siguiente codigo, ojo para la SUNAT peru, nos responde con un zip dentro del cual esta un xml con la respuesta si el documento ha sido aceptado o no, el archivo tiene que ser cargado en un array de bytes asi que lineas mas abajo te dejo los procedure que use.

Aun no termino el proyecto, ahora con wireshark estoy examinando como viajan los paquetes hacia el servidor, con la finalidad de ver si cumplen con el estandar que solicita SUNAT, cuando lo tengo listo lo libero :D hubelsolis@hotmail.com


procedure TForm1.Button1Click(Sender: TObject);
const
defWSDL = 'https://e-beta.sunat.gob.pe/ol-ti-itcpfegem-beta/billService?wsdl';
defURL = 'https://e-beta.sunat.gob.pe:443/ol-ti-itcpfegem-beta/billService';
defSvc = 'billService';
defPrt = 'BillServicePort';
var
tBillServ : billService;
Archivo : String;
Envio : TByteDynArray;
Respuesta : TByteDynArray;

HTTPReqResp1: THTTPReqResp;
HTTPRIO1 : THTTPRIO;
begin
HTTPReqResp1 := THTTPReqResp.create(nil);
HTTPReqResp1.Password := 'moddatos';
HTTPReqResp1.username := '20489697042MODDATOS';

HTTPRIO1 := THTTPRIO.Create(nil);
HTTPRIO1.HTTPWebNode := HTTPReqResp1;
HTTPRIO1.WSDLLocation := defWSDL;
HTTPRIO1.Service := defSvc;
HTTPRIO1.Port := defPrt;

// levanto el servicio
tBillServ:=GetbillService(TRUE,'',HTTPRIO1);
Archivo:='20489697042-03-BB01-00000003.ZIP';
envio:= FileToByteArray('D:\'+Archivo);

// envio
try
respuesta:=tBillServ.sendBill(Archivo,envio);
except
on E : Exception do
ShowMessage(E.ClassName+' error raised, with message : '+E.Message);
end;

ByteArrayToFIle(respuesta, 'D:\respuestas\rptab.zip' );

end;



procedure ByteArrayToFIle(const ByteArray : TByteDynArray; const FileName : string );
var Count : integer;
F : FIle of Byte;
pTemp : Pointer;
begin
AssignFile( F, FileName );
Rewrite(F);
try
Count := Length( ByteArray );
pTemp := @ByteArray[0];
BlockWrite(F, pTemp^, Count );
finally
CloseFile( F );
end;
end;

function FIleToByteArray( const FileName : string ) : TByteDynArray;
const BLOCK_SIZE=1024;
var BytesRead, BytesToWrite, Count : integer;
F : FIle of Byte;
pTemp : Pointer;
begin
AssignFile( F, FileName );
Reset(F);
try
Count := FileSize( F );
SetLength(Result, Count );
pTemp := @Result[0];
BytesRead := BLOCK_SIZE;
while (BytesRead = BLOCK_SIZE ) do
begin
BytesToWrite := Min(Count, BLOCK_SIZE);
BlockRead(F, pTemp^, BytesToWrite , BytesRead );
pTemp := Pointer(LongInt(pTemp) + BLOCK_SIZE);
Count := Count-BytesRead;
end;
finally
CloseFile( F );
end;
end;

Hola, he revisado tu código y trabaja sin problemas, al menos lo he probado con delphi xe7 y normal pero estoy tratando de utilizar la WSDL de Consultas pero tengo problemas, siempre me devuelve el siguiente mensaje EL ENCABEZADO DE SEGURIDAD ES INCORRECTO, estoy usando el mismo codigo que usaste para Sendbill

textoxml:=memo1.Lines.Text;//en este memo tengo todo el XML
try
respuesta:=tBillServ.getStatus(textoxml);
except
on E : Exception do
ShowMessage(E.ClassName+' error raised, with message : '+E.Message+'/'+E.ToString);
end;
showmessage(respuesta);

Podrias ayudarme con este problema?


La franja horaria es GMT +2. Ahora son las 22:39:26.

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