Belgium VAT-Controle function

Belgium VAT-Controle function

Postby Marc Venken » Fri Mar 27, 2020 9:18 pm

Hello Michel, Marc

Have any of you have a working Vat-controle for Belgium vat numbers ? I want to check if new customers are having a correct vat number and maybe the option of filling in the customer data from online data.
Marc Venken
Using: FWH 23.04 with Harbour
User avatar
Marc Venken
 
Posts: 1446
Joined: Tue Jun 14, 2016 7:51 am
Location: Belgium

Re: Belgium VAT-Controle function

Postby Silvio.Falconi » Fri Mar 27, 2020 9:30 pm

You could always use our Italian control if the customer VAT number is created in the same way also in Belgium
I fiund this
https://vatcalculator.eu/belgium-vat-calculator/
but you perhaps mean another vat number

I found VAT number format: BE 0999.999.999 (10 digits)

https://github.com/DragonBe/vies/issues/76
there is a php source code
https://github.com/DragonBe/vies/blob/m ... sponse.php
Since from 1991/1992 ( fw for clipper Rel. 14.4 - Momos)
I use : FiveWin for Harbour November 2023 - January 2024 - Harbour 3.2.0dev (harbour_bcc770_32_20240309) - Bcc7.70 - xMate ver. 1.15.3 - PellesC - mail: silvio[dot]falconi[at]gmail[dot]com
User avatar
Silvio.Falconi
 
Posts: 7075
Joined: Thu Oct 18, 2012 7:17 pm

Re: Belgium VAT-Controle function

Postby driessen » Fri Mar 27, 2020 10:50 pm

Hi Marc,

This is the function I have made to check a Belgian VAT-number.
The picture of the VAT-number = "BE0999.999.999"

The code is :
Code: Select all  Expand view  RUN
FUNCTION Contr_BTW(nBTWNUM,nLAND,nDlg,nONDNUM,nBTWLIST) // Controle Belgisch BTW-nummer

   LOCAL OldPar   := ALIAS()
   LOCAL TN1      := 0
   LOCAL TN2      := 0
   LOCAL cTel     := 0
   LOCAL cRet     := .T.

   IF ALLTRIM(nLAND) = "B" .AND. !EMPTY(&nBTWNUM) .AND. ALLTRIM(&nBTWNUM) <> ".   ." .AND. LEFT(UPPER(&nBTWNUM),2) = "BE"

      &nBTWNUM := LEFT(ALLTRIM(&nBTWNUM),14)

      FOR x = 4 TO LEN(ALLTRIM(SUBSTR(&nBTWNUM,4,11)))
          IF (SUBSTR(ALLTRIM(&nBTWNUM),x,1) < "0" .OR. SUBSTR(ALLTRIM(&nBTWNUM),x,1) > "9") .AND. ((x <> 7 .AND. x <> 11) .OR. ((x = 7 .OR. x = 11) .AND. SUBSTR(ALLTRIM(&nBTWNUM),x,1) <> "."))
             cTel++
          ENDIF
      NEXT
      IF cTel = 0
         IF LEN(ALLTRIM(&nBTWNUM)) = 12
            &nBTWNUM := LEFT(SUBSTR(ALLTRIM(&nBTWNUM),1,6) + "." + SUBSTR(ALLTRIM(&nBTWNUM),7,3) + "." + RIGHT(ALLTRIM(&nBTWNUM),10,3) + SPACE(20),20)
            nDlg:Update()
         ENDIF
         TN1 := VAL(SUBSTR(ALLTRIM(&nBTWNUM),3,4) + SUBSTR(ALLTRIM(&nBTWNUM),8,3) + SUBSTR(ALLTRIM(&nBTWNUM),12,1))
         TN2 := (( TN1 / 97) - INT(TN1 / 97)) * 97
         IF !(cTel = 0 .AND. INT(VAL(SUBSTR(ALLTRIM(&nBTWNUM),13,2))) = 97 - INT(TN2 + 0.5))
            cRet := .F.
         ENDIF
      ELSEIF LEFT(UPPER(&nBTWNUM),2) = "BE"
         cRet := .F.
      ENDIF

      IF cRet
         IF LEFT(UPPER(ALLTRIM(&nBTWNUM)),2) = "BE"
            IF !EMPTY(nONDNUM) .AND. (EMPTY(&nONDNUM) .OR. ALLTRIM(&nONDNUM) = ".   .")
               &nONDNUM := RIGHT(ALLTRIM(&nBTWNUM),12)
               IF !EMPTY(nBTWLIST) .AND. !EMPTY(&nBTWNUM)
                  &nBTWLIST := .T.
               ENDIF
            ENDIF
            nDlg:Update()
         ENDIF
      ENDIF

      IF LEN(ALLTRIM(&nBTWNUM)) < 14
         &nBTWNUM := LEFT(ALLTRIM(&nBTWNUM) + SPACE(14),14)
         cRet := .F.
      ENDIF

      IF !cRet
        MsgAlert("Dit Belgisch BTW-nummer is niet correct !!!","Opgelet")
      ENDIF

   ENDIF

RETURN(cRet)
Good luck.
Regards,

Michel D.
Genk (Belgium)
_____________________________________________________________________________________________
I use : FiveWin for (x)Harbour v. 24.07 - Harbour 3.2.0 (February 2024) - xHarbour Builder (January 2020) - Bcc773
User avatar
driessen
 
Posts: 1422
Joined: Mon Oct 10, 2005 11:26 am
Location: Genk, Belgium

Re: Belgium VAT-Controle function

Postby Marc Venken » Fri Mar 27, 2020 11:27 pm

I have seen this code working I believe (don't know where I got it)
Now it's not ok anymore

Code: Select all  Expand view  RUN

#include "fivewin.ch"
#if ! defined( DEFAULT_MAX_RECORDS )
#define DEFAULT_MAX_RECORDS   20000
#endif

Static cDoc , cHttp

Function Main()


   TRY
      cDoc := CreateObject( "MSXML2.DOMDocument" )
   CATCH
      Alert("Error object MSXML2.DOMDocument : " + Ole2TxtError())
      return NIL
   END

   TRY
      cHttp := CreateObject( "MSXML2.XMLHTTP" )
   CATCH
      Alert("Error object MSXML2.XMLHTTP : " + Ole2TxtError())
   END

   checkVies( "BE", "0452109872" )


Return nil


//=========================================================================================
Function  checkVies(cCountry, cVatNumber )

Local cResponse := " " ,hVar
Local cRequestXML := ""
local aData:={}

DEFAULT cCountry := "BE"
DEFAULT cVatNumber := "0452109872"
editvars cVatnumber


 cRequestXML := [<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" ] +;
                                    [xmlns:tns1="urn:ec.europa.eu:taxud:vies:services:checkVat:types" ] +;
                                    [xmlns:impl="urn:ec.europa.eu:taxud:vies:services:checkVat"> ] +;
                    [<soap:Header> ]+;
                    [</soap:Header> ]+;
                         [<soap:Body> ]+;
                            [<tns1:checkVat xmlns:tns1="urn:ec.europa.eu:taxud:vies:services:checkVat:types" ]+;
                                            [xmlns="urn:ec.europa.eu:taxud:vies:services:checkVat:types"> ]+;
                            [<tns1:countryCode>] + cCountry + [</tns1:countryCode> ] +;
                            [<tns1:vatNumber>] + cVatNumber + [</tns1:vatNumber> ] +;
                            [</tns1:checkVat> ]+;
                         [</soap:Body> ]+;
                    [</soap:Envelope> ]


      //
       //cHttp:Open( "POST","http://ec.europa.eu/taxation_customs/vies/services/checkVatService", .t.)
      // Wait...
      cHttp:Open( "POST","http://ec.europa.eu/taxation_customs/vies/services/checkVatService", .F.)

      cHttp:SetRequestHeader( "Content-Type"    , "application/x-www-form-urlencoded" )
      cHttp:setRequestHeader('User-Agent', 'node-soap')
      cHttp:setRequestHeader('Accept' , 'text/html,application/xhtml+xml,application/xml,text/xml;q=0.9,*/*;q=0.8')
      cHttp:setRequestHeader('Accept-Encoding', 'none')
      cHttp:setRequestHeader('Accept-Charset', 'utf-8')
      //cHttp:setRequestHeader('Connection', 'close')
      //cHttp:setRequestHeader('Host', 'http://ec.europa.eu/taxation_customs/vies/services/checkVatService')
      cHttp:setRequestHeader('SOAPAction', 'urn:ec.europa.eu:taxud:vies:services:checkVat/checkVat')

      //MsgGet( 'Wait',,@cRequestXML)
      //cDoc:LoadXML( cRequestXML )
      //lXmlHttp.send(lXmlDoc);
      cHttp:send(cRequestXML)
     //cHttp:send(cDOc:xml )
     //If cHttp:status == 200
     // ? cResponse
     cResponse := cHttp:responseText
     ? cResponse
     aadd(aData,BETWEENTAGSARRAY("name","/name",cResponse))
     aadd(aData,BETWEENTAGSARRAY("address","/address",cResponse))

     //xbrowser( BETWEENTAGSARRAY("faultstring","/faultstring",cResponse) )
     xbrowser( aData )
    //endif

RETURN NIL

  FUNCTION BETWEENTAGSARRAY( cStartTag, cEndTag, cInputString, lIncludeTags )

   LOCAL nStartPoint, nEndPoint
   LOCAL nRecords := 00, nFetchLength := 00, aFoundText := Array( DEFAULT_MAX_RECORDS )
   LOCAL cMDML
   LOCAL cInputStringUpper := Upper( cInputString )
   LOCAL cStartTagUpper    := Upper( cStartTag    )
   LOCAL cEndTagUpper      := Upper( cEndTag      )

   hb_Default( @lIncludeTags, .F. )

   DO WHILE .T.

      // Find the starting point of the starting tag.
      nStartPoint := At( cStartTagUpper, SubStr( cInputStringUpper, 01 ) )
      IF nStartPoint > 00

         // Adjust starting point to end of starting tag
         nStartPoint += Len( cStartTagUpper )

         // If the first tag is found strip off string up to and including the starting tag itself
         cInputStringUpper := SubStr( cInputStringUpper, nStartPoint )
         cInputString      := SubStr( cInputString,      nStartPoint )

         // Find the starting point of the second tag, beginning from end of first tag.
         nEndPoint := At( cEndTagUpper, cInputStringUpper )
         IF nEndPoint > 00

            // If the second tag is found calculate its position from start of string.
            nFetchLength := nEndPoint - 1

            IF lIncludeTags
               cMDML := cStartTag + LTrim( SubStr( cInputString, 01, nFetchLength ) ) + cEndTag
            ELSE
               cMDML := LTrim( SubStr( cInputString, 01, nFetchLength ) )
            ENDIF

            IF ++nRecords <= DEFAULT_MAX_RECORDS
               aFoundText[ nRecords ] := cMDML
            ELSE
               // IF we get here it is gonna be oh so slow.
               AAdd( aFoundText, cMDML )
            ENDIF

            // clip off the front of the string then loop to find the next
            cInputStringUpper := SubStr( cInputStringUpper, nFetchLength + 01 )
            cInputString      := SubStr( cInputString,      nFetchLength + 01 )

         ELSE
            EXIT
         ENDIF
      ELSE
         EXIT
      ENDIF
   ENDDO
   IF nRecords < DEFAULT_MAX_RECORDS
      aFoundText := ASize( aFoundText, nRecords )
   ENDIF

   RETURN ( aFoundText )

 
Marc Venken
Using: FWH 23.04 with Harbour
User avatar
Marc Venken
 
Posts: 1446
Joined: Tue Jun 14, 2016 7:51 am
Location: Belgium

Re: Belgium VAT-Controle function

Postby driessen » Fri Mar 27, 2020 11:41 pm

Marc,

Do you know the principle of checking a Belgian VAT-number?

A Belgian VAT-number looks like BE0574.774.488.

Take "BE0" at the start away. You keep 574.774.488.
Get rid of the points. You keep 574774488.
Take the first 7 digits. You keep 5747744.
Divide this result by 97. The result is 59255.0927835.
You keep the decimals : 0.0927835.
Multiply this by 97 and round it with 0 decimals.
The result is 9.
Substract 9 from 97 and this results into 88.
IF 88 is equal to the last 2 figures of you VAT-number, the Belgian VAT-number is correct.

This is what my function does.
Regards,

Michel D.
Genk (Belgium)
_____________________________________________________________________________________________
I use : FiveWin for (x)Harbour v. 24.07 - Harbour 3.2.0 (February 2024) - xHarbour Builder (January 2020) - Bcc773
User avatar
driessen
 
Posts: 1422
Joined: Mon Oct 10, 2005 11:26 am
Location: Genk, Belgium

Re: Belgium VAT-Controle function

Postby nageswaragunupudi » Sat Mar 28, 2020 3:46 am

driessen wrote:Marc,

Do you know the principle of checking a Belgian VAT-number?

A Belgian VAT-number looks like BE0574.774.488.

Take "BE0" at the start away. You keep 574.774.488.
Get rid of the points. You keep 574774488.
Take the first 7 digits. You keep 5747744.
Divide this result by 97. The result is 59255.0927835.
You keep the decimals : 0.0927835.
Multiply this by 97 and round it with 0 decimals.
The result is 9.
Substract 9 from 97 and this results into 88.
IF 88 is equal to the last 2 figures of you VAT-number, the Belgian VAT-number is correct.

This is what my function does.


I tried to implement the above logic in this function:
Code: Select all  Expand view  RUN
function BelgiumVat( cVat )

   local lValid := .f.

   if Left( cVat, 3 ) == "BE0" .and. Len( cVat ) == 14
      cVat     := SubStr( cVat, 4 )
      if SubStr( cVat, 4, 1 ) == "." .and. SubStr( cVat, 8, 1 ) == "."
         cVat  := StrTran( cVat, ".", "" )
         if cVat == Str( Val( cVat ), 9 )
            if 97 - Val( Left( cVat, 7 ) ) % 97 == Val( Right( cVat, 2 ) )
               lValid   := .t.
            endif
         endif
      endif
   endif
return lValid
 

If you have time can this be checked with different vat numbers?

Even this check is valid, there is no guarantee that the number does exist. Checking with the Government's website is the final check.
Regards

G. N. Rao.
Hyderabad, India
User avatar
nageswaragunupudi
 
Posts: 10659
Joined: Sun Nov 19, 2006 5:22 am
Location: India


Return to FiveWin for Harbour/xHarbour

Who is online

Users browsing this forum: No registered users and 65 guests