anghelvalentin / CountryValidator

C# Validations for Social Security Numbers, VAT Codes and tax identification numbers
https://randommer.io/SocialNumber/VatValidator
36 stars 20 forks source link

Current Dutch VAT numbers do not validate #9

Open flecktarn121 opened 2 years ago

flecktarn121 commented 2 years ago

Hi,

I am not really sure about this, but aparrently the Netherlands has changed the format of their VAT numbers. The number NL000099998B57 (example taken from this webpage of the Dutch goverment) does not validate.

anghelvalentin commented 2 years ago

Hello, I have tried to validate that number with https://ec.europa.eu/taxation_customs/vies/?locale=en . It seems that is a wrong number.

I've read that the NL VAT number uses check sum in order to ensure that the number is legit. I don't know if it is still used by authorities.

McTristan commented 2 years ago

We also have issues with newer numbers, the VIES portal states the number is correct.

It is not easy to find information about this, I found this link but I assume you are using this algorithm already:

https://help.afas.nl/help/EN/SE/Fin_Config_VatIct_NrChck.htm

McTristan commented 2 years ago

It seems there is an additional modulo 97 based algorithm now:

// Positions 1-2 must be NL, positions 13-14 must be digits. Positions 3-12 can contain digits, uppercase letters, '+' and ' '. // Each letter is replaced by two-digit number, where 'A' = 10, 'B' = 11, ..., 'Z' = 35; '+' = 36, '' = 37. // Remainder of division the converted VAT number by 97 must be equal to 1. // Example: NL123456789B13 is converted to 2321 123456789 11 13, i.e. to 23211234567891113 integer number. 23211234567891113 mod 97 = 1, it is a valid VAT number.

So I guess two checks need to be implemented and either of one should be valid to accept the VAT number.

McTristan commented 2 years ago

I would also assume, as the number can contain now uppercase letters, + and * the regex should be reworked

McTristan commented 2 years ago

I can provide a valid number which should work with the modulo 97 approach - it is kind of private so I don't know how to pass it to you.

Paul-Gerarts commented 7 months ago

I'm astonished I can't find anything about the newer NL VAT numbers elsewhere but here. The change dates back to Q4 2021. Here's something I had to whip up quick in Java 21 with the org.apache.commons.lang3 library, thanks to McTristan's algorithm (I would love to read the source!). It works with the example provided (and I tested it with other private data): NL123456789B13

public boolean checkNewerDutchVat(String vatNumber) {
        if (Pattern.compile("(NL)?[\\dA-Z+*]{10}[\\d]{2}").matcher(vatNumber).matches()) {
            StringBuilder parsedVatNumber = new StringBuilder();
            char[] vatNumberChars = vatNumber.toCharArray();

            for (char vatNumberChar : vatNumberChars) {
                String charSequence = "" + vatNumberChar;

                if (StringUtils.isNumeric(charSequence)) {
                    parsedVatNumber.append(charSequence);
                } else {
                    if ("+".equals(charSequence)) {
                        parsedVatNumber.append("36");
                    } else if ("*".equals(charSequence)) {
                        parsedVatNumber.append("37");
                    } else {
                        // subtraction from ASCII-value
                        parsedVatNumber.append(vatNumberChar - 55);
                    }
                }
            }
            return Long.parseLong(parsedVatNumber.toString()) % 97 == 1;
        }
        return false;
    }