Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   General/Noticias (https://www.clubdelphi.com/foros/forumdisplay.php?f=64)
-   -   Verificación de VAT comunitario (https://www.clubdelphi.com/foros/showthread.php?t=97564)

ermendalenda 09-07-2025 17:41:02

Pués ni idea, están devolviendo error.
He hecho un trace:
Cita:

== Info: Mark bundle as not supporting multiuse
<= Recv header, 26 bytes (0x1a)
0000: 48 54 54 50 2f 31 2e 31 20 34 30 30 20 42 61 64 HTTP/1.1 400 Bad
0010: 20 52 65 71 75 65 73 74 0d 0a Request..


ermendalenda 09-07-2025 18:21:59

Cita:

Empezado por ermendalenda (Mensaje 566245)
Pués ni idea, están devolviendo error.
He hecho un trace:

Edito:
Parece que eso que he puesto no es un error, es un aviso, pero es cierto que no devuelven nada. Esperemos que sea algo puntual.

Logan05 10-07-2025 11:25:39

Cita:

Empezado por ermendalenda (Mensaje 566246)
Edito:
Parece que eso que he puesto no es un error, es un aviso, pero es cierto que no devuelven nada. Esperemos que sea algo puntual.

he probado a enviar los xml de ejemplo de YellowStone y ermendalenda a las siguientes direcciones

"http://ec.europa.eu/taxation_customs/vies/services/checkVatService" 'web para comprobacion de VATs
"https://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl" 'web para comprobacion de VATs

pero solo consigo errores 400 o 405 si lo intento con GET en lugar de POST :o

también lo estoy probando con el TIN, pero tampoco consigo avanzar....
"https://ec.europa.eu/taxation_customs/tin/services/checkTinService.wsdl" 'web para comprobacion de TINs

lo he probado con y sin certificado, sin diferencia alguna ¿que estoy haciendo mal?

novatico 10-07-2025 11:40:14

Buenos días, ya os he comentado en alguna ocasión que no trabajo en Delphi sino con Visual Foxpro, pero estoy en estos foros por su calidad y buena orientación. Me habéis sacado de apuros en muchas ocasiones.

Para la consulta de VATs yo tengo este proceso en Visual Foxpro que funciona, pero no se pasarlo a Delphi. Lo adjunto por si alguno sabe.
Los datos de prueba que adjunto son válidos y devuelve los datos correctos.

LOCAL lcCountryCode, lcUatNumber, lcUrl, loHTTP, lcResponseText, loXML, lcValid, lcName, lcAddress
*
lcCountryCode = "LU" && Código de país (ej. ES para España, DE para Alemania)
lcVatNumber = "20260743" && Número de IVA sin el prefijo del país

*!* Construir la URL para la API REST de VIES
lcUrl = "https://ec.europa.eu/taxation_customs/vies/rest-api/ms/" + lcCountryCode + "/vat/" + lcVatNumber

*!* Crear el objeto MSXML2.ServerXMLHTTP para la petición HTTP
loHTTP = CREATEOBJECT("MSXML2.ServerXMLHTTP")
IF TYPE("loHTTP") = "O" AND NOT ISNULL(loHTTP)
TRY
loHTTP.OPEN("GET", lcUrl, .F.) && .F. para síncrono, .T. para asíncrono
loHTTP.SEND()

lcResponseText = loHTTP.RESPONSETEXT

*!* Procesar la respuesta JSON (la API REST devuelve JSON)
*!* En VFP, el parseo de JSON no es nativo, necesitarás una función o librería de terceros
*!* para parsear JSON, o un procesamiento de cadenas si la respuesta es simple.
*!* Ejemplo simplificado de cómo buscar "valid" en el texto:

* Si la respuesta es JSON, podrías tener algo como: {"countryCode":"ES","vatNumber":"A28014878","requestDate":"2025-07-04+02:00","valid":true,"name":"MARCADONA","address":"CALLE DE LA CERA, 123\nBARCELONA"}

IF ATC(["isValid" : true], lcResponseText) > 0
lcValid = .T.
MESSAGEBOX("VAT válido.", 64, "Resultado VIES")

* Extraer nombre y dirección (requiere parseo JSON más sofisticado o manejo de cadenas)
* Por ejemplo, para un parsing básico de "name":
lnPosName = ATC(["name" : "], lcResponseText)
IF lnPosName > 0
lcTemp = SUBSTR(lcResponseText, lnPosName + LEN(["name" : "]))
lnEndName = AT('"', lcTemp)
lcName = IIF(lnEndName > 0, SUBSTR(lcTemp, 1, lnEndName - 1), "")
MESSAGEBOX("Nombre: " + lcName, 64, "Datos VIES")
ENDIF

* Y similar para "address"
lnPosAddress = ATC(["address" : "], lcResponseText)
IF lnPosAddress > 0
lcTemp = SUBSTR(lcResponseText, lnPosAddress + LEN(["address" : "]))
lnEndAddress = AT('"', lcTemp)
lcAddress = IIF(lnEndAddress > 0, SUBSTR(lcTemp, 1, lnEndAddress - 1), "")
lcAddress = STRTRAN(lcAddress, "\n", CHR(13)+CHR(10)) && Reemplazar saltos de línea JSON por CR/LF
MESSAGEBOX("Dirección: " + lcAddress, 64, "Datos VIES")
ENDIF

ELSE
lcValid = .F.
IF ATC(["isValid" : false], lcResponseText) > 0
lnPosName = ATC(["userError" : "], lcResponseText)
IF lnPosName > 0
lcTemp = SUBSTR(lcResponseText, lnPosName + LEN(["userError" : "]))
lnEndName = AT('"', lcTemp)
lcName = IIF(lnEndName > 0, SUBSTR(lcTemp, 1, lnEndName - 1), "")
MESSAGEBOX("VAT: " + lcName, 64, "Datos VIES")
ENDIF
else
MESSAGEBOX("VAT no válido o error en la consulta.", 48, "Resultado VIES")
Endif

IF !EMPTY(lcResponseText)
_cliptext = lcResponseText
Endif
ENDIF

CATCH TO loException
MESSAGEBOX("Error al conectar o procesar: " + loException.MESSAGE, 16, "Error VIES")
ENDTRY
ELSE
MESSAGEBOX("No se pudo crear el objeto MSXML2.ServerXMLHTTP. Asegúrate de que esté registrado.", 16, "Error")
ENDIF

RELEASE loHTTP


Espero que os sirva.

Un saludo.

Logan05 10-07-2025 11:40:38

Cita:

Empezado por Logan05 (Mensaje 566256)

¿que estoy haciendo mal?

Los ejemplos son perfectos, era yo que la estaba liando al motar el xml!!!! :o , ya he conseguido que me responda

Muchas gracias por vuestra ayuda!!!

novatico 10-07-2025 11:46:12

Le he pedido a la IA que me pase el código y me saca ésto.. Ni idea de si es correcto.

uses
System.Net.HttpClient, System.Net.HttpClientComponent, System.JSON, System.SysUtils, System.Classes, Vcl.Dialogs;

procedure CheckVAT;
var
CountryCode, VatNumber, Url: string;
HttpClient: THTTPClient;
Response: IHTTPResponse;
JsonValue: TJSONValue;
JSONObject: TJSONObject;
IsValid: Boolean;
Name, Address, ErrorMsg: string;
begin
CountryCode := 'LU'; // Ej. 'ES', 'DE', etc.
VatNumber := '20260743';

Url := Format('https://ec.europa.eu/taxation_customs/vies/rest-api/ms/%s/vat/%s', [CountryCode, VatNumber]);

HttpClient := THTTPClient.Create;
try
Response := HttpClient.Get(Url);
if Response.StatusCode = 200 then
begin
JsonValue := TJSONObject.ParseJSONValue(Response.ContentAsString);
if Assigned(JsonValue) then
begin
JSONObject := JsonValue as TJSONObject;
IsValid := JSONObject.GetValue<Boolean>('isValid');

if IsValid then
begin
Name := JSONObject.GetValue<string>('name');
Address := JSONObject.GetValue<string>('address').Replace('\n', sLineBreak);
ShowMessage('VAT válido.' + sLineBreak +
'Nombre: ' + Name + sLineBreak +
'Dirección: ' + Address);
end
else
begin
ErrorMsg := JSONObject.GetValue<string>('userError');
ShowMessage('VAT no válido. Mensaje: ' + ErrorMsg);
end;
end;
end
else
ShowMessage('Error HTTP: ' + Response.StatusCode.ToString);
except
on E: Exception do
ShowMessage('Excepción: ' + E.Message);
end;
HttpClient.Free;
end;

Faneka 10-07-2025 11:52:57

Cita:

Empezado por novatico (Mensaje 566257)
Buenos días, ya os he comentado en alguna ocasión que no trabajo en Delphi sino con Visual Foxpro, pero estoy en estos foros por su calidad y buena orientación. Me habéis sacado de apuros en muchas ocasiones.

Para la consulta de VATs yo tengo este proceso en Visual Foxpro que funciona, pero no se pasarlo a Delphi. Lo adjunto por si alguno sabe.
Los datos de prueba que adjunto son válidos y devuelve los datos correctos.

LOCAL lcCountryCode, lcUatNumber, lcUrl, loHTTP, lcResponseText, loXML, lcValid, lcName, lcAddress
*
lcCountryCode = "LU" && Código de país (ej. ES para España, DE para Alemania)
lcVatNumber = "20260743" && Número de IVA sin el prefijo del país

*!* Construir la URL para la API REST de VIES
lcUrl = "https://ec.europa.eu/taxation_customs/vies/rest-api/ms/" + lcCountryCode + "/vat/" + lcVatNumber

*!* Crear el objeto MSXML2.ServerXMLHTTP para la petición HTTP
loHTTP = CREATEOBJECT("MSXML2.ServerXMLHTTP")
IF TYPE("loHTTP") = "O" AND NOT ISNULL(loHTTP)
TRY
loHTTP.OPEN("GET", lcUrl, .F.) && .F. para síncrono, .T. para asíncrono
loHTTP.SEND()

lcResponseText = loHTTP.RESPONSETEXT

*!* Procesar la respuesta JSON (la API REST devuelve JSON)
*!* En VFP, el parseo de JSON no es nativo, necesitarás una función o librería de terceros
*!* para parsear JSON, o un procesamiento de cadenas si la respuesta es simple.
*!* Ejemplo simplificado de cómo buscar "valid" en el texto:

* Si la respuesta es JSON, podrías tener algo como: {"countryCode":"ES","vatNumber":"A28014878","requestDate":"2025-07-04+02:00","valid":true,"name":"MARCADONA","address":"CALLE DE LA CERA, 123\nBARCELONA"}

IF ATC(["isValid" : true], lcResponseText) > 0
lcValid = .T.
MESSAGEBOX("VAT válido.", 64, "Resultado VIES")

* Extraer nombre y dirección (requiere parseo JSON más sofisticado o manejo de cadenas)
* Por ejemplo, para un parsing básico de "name":
lnPosName = ATC(["name" : "], lcResponseText)
IF lnPosName > 0
lcTemp = SUBSTR(lcResponseText, lnPosName + LEN(["name" : "]))
lnEndName = AT('"', lcTemp)
lcName = IIF(lnEndName > 0, SUBSTR(lcTemp, 1, lnEndName - 1), "")
MESSAGEBOX("Nombre: " + lcName, 64, "Datos VIES")
ENDIF

* Y similar para "address"
lnPosAddress = ATC(["address" : "], lcResponseText)
IF lnPosAddress > 0
lcTemp = SUBSTR(lcResponseText, lnPosAddress + LEN(["address" : "]))
lnEndAddress = AT('"', lcTemp)
lcAddress = IIF(lnEndAddress > 0, SUBSTR(lcTemp, 1, lnEndAddress - 1), "")
lcAddress = STRTRAN(lcAddress, "\n", CHR(13)+CHR(10)) && Reemplazar saltos de línea JSON por CR/LF
MESSAGEBOX("Dirección: " + lcAddress, 64, "Datos VIES")
ENDIF

ELSE
lcValid = .F.
IF ATC(["isValid" : false], lcResponseText) > 0
lnPosName = ATC(["userError" : "], lcResponseText)
IF lnPosName > 0
lcTemp = SUBSTR(lcResponseText, lnPosName + LEN(["userError" : "]))
lnEndName = AT('"', lcTemp)
lcName = IIF(lnEndName > 0, SUBSTR(lcTemp, 1, lnEndName - 1), "")
MESSAGEBOX("VAT: " + lcName, 64, "Datos VIES")
ENDIF
else
MESSAGEBOX("VAT no válido o error en la consulta.", 48, "Resultado VIES")
Endif

IF !EMPTY(lcResponseText)
_cliptext = lcResponseText
Endif
ENDIF

CATCH TO loException
MESSAGEBOX("Error al conectar o procesar: " + loException.MESSAGE, 16, "Error VIES")
ENDTRY
ELSE
MESSAGEBOX("No se pudo crear el objeto MSXML2.ServerXMLHTTP. Asegúrate de que esté registrado.", 16, "Error")
ENDIF

RELEASE loHTTP


Espero que os sirva.

Un saludo.

Funciona a la perfección ;), yo tambien trabajo en visual foxpro :D

YellowStone 10-07-2025 12:31:02

Cita:

Empezado por Logan05 (Mensaje 566258)
Los ejemplos son perfectos, era yo que la estaba liando al motar el xml!!!! :o , ya he conseguido que me responda

Muchas gracias por vuestra ayuda!!!

^\||/ Estupendo

ermendalenda 10-07-2025 13:20:58

Cita:

Empezado por YellowStone (Mensaje 566262)
^\||/ Estupendo

Puedes poner wl xml que pasas ahora, por que a mi me funcionaba antes y ya no

edari 10-07-2025 13:29:07

Yo también he conseguido respuesta desde un xml llamado con curl


xml
Código PHP:

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope
    xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:urn="urn:ec.europa.eu:taxud:vies:services:checkVat:types">
   <soapenv:Header/>
   <soapenv:Body>
      <urn:checkVat>
         <urn:countryCode>DE</urn:countryCode>
         <urn:vatNumber>813518999</urn:vatNumber>
      </urn:checkVat>
   </soapenv:Body>
</soapenv:Envelope>


curl
Código PHP:

curl.exe -X POST https://ec.europa.eu/taxation_customs/vies/services/checkVatService -H "Content-Type: text/xml; charset=UTF8" -d @\AEAT\VIESNIF.XML -o \AEAT\RESPVIES.XML 


Gracias por vuestra ayuda o empujón ^\||/^\||/

Logan05 10-07-2025 13:57:53

Cita:

Empezado por ermendalenda (Mensaje 566267)
Puedes poner wl xml que pasas ahora, por que a mi me funcionaba antes y ya no

Código:

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:Datos="urn:ec.europa.eu:taxud:vies:services:checkVat:types">
  <soapenv:Body>
    <Datos:checkVat>
      <Datos:countryCode>DE</Datos:countryCode>
      <Datos:vatNumber>813518999</Datos:vatNumber>
    </Datos:checkVat>
  </soapenv:Body>
</soapenv:Envelope>

esto a mi me funciona

ermendalenda 10-07-2025 14:32:03

Gracias, antes funcionaba, se ve que han metido un control nuevo en la solicitud y ya no vale por defecto enviarle el xml y hay que decir si envias json o xml:
Cita:

-H "Content-Type: text/xml; charset=UTF8"
Le he añadido también :
Cita:

-H 'SOAPAction: "checkVat"'
Por que no se si alguna vez también va a pasar lo mismo

YellowStone 10-07-2025 16:02:45

Yo les paso estos Headers.

hServidor.Request.CustomHeaders.AddValue('Accept', '*/*');
hServidor.Request.CustomHeaders.AddValue('Accept-Encoding', 'identify');
hServidor.Request.CustomHeaders.AddValue('Charset', 'utf-8');
hServidor.Request.CustomHeaders.AddValue('Content-Type', 'text/xml');
hServidor.Request.CustomHeaders.AddValue('Connection', 'keep-alive');
hServidor.Request.CustomHeaders.AddValue('SOAPAction', 'checkVatService');

edari 14-07-2025 12:45:16

Hola de nuevo,


Puede ser que este tipo de clientes intracomunitarios (y supongo que también los extra...) Verifactu trague todos los "cifes" sin validar nada aunque lo tengas como PASAPORTE, DOCUMENTO PAIS DE ORIGEN, CERTIFICADO DE RESIDENCIA, OTRO DOCUMENTO PROBATORIO ?


Un saludo


La franja horaria es GMT +2. Ahora son las 22:20:53.

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