Belgium VAT-Controle function

Post Reply
User avatar
Marc Venken
Posts: 727
Joined: Tue Jun 14, 2016 7:51 am

Belgium VAT-Controle function

Post by Marc Venken »

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 20.08 with Harbour
User avatar
Silvio.Falconi
Posts: 4956
Joined: Thu Oct 18, 2012 7:17 pm

Re: Belgium VAT-Controle function

Post by Silvio.Falconi »

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
I use : FiveWin for Harbour August 2020 (Revision) - Harbour 3.2.0dev (r1712141320) - Bcc7.30 - xMate ver. 1.15.3 - PellesC
User avatar
driessen
Posts: 1239
Joined: Mon Oct 10, 2005 11:26 am
Location: Genk, Belgium

Re: Belgium VAT-Controle function

Post by driessen »

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

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. 21.01 - Harbour 3.2.0 (October 2020) - xHarbour Builder (January 2020) - Bcc7
User avatar
Marc Venken
Posts: 727
Joined: Tue Jun 14, 2016 7:51 am

Re: Belgium VAT-Controle function

Post by Marc Venken »

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

Code: Select all

#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 20.08 with Harbour
User avatar
driessen
Posts: 1239
Joined: Mon Oct 10, 2005 11:26 am
Location: Genk, Belgium

Re: Belgium VAT-Controle function

Post by driessen »

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. 21.01 - Harbour 3.2.0 (October 2020) - xHarbour Builder (January 2020) - Bcc7
User avatar
nageswaragunupudi
Posts: 8017
Joined: Sun Nov 19, 2006 5:22 am
Location: India
Contact:

Re: Belgium VAT-Controle function

Post by nageswaragunupudi »

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

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
Post Reply