All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.knightsoftnet.validators.shared.impl.AbstractTaxTinNumberValidator Maven / Gradle / Ivy

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
 * agreements. See the NOTICE file distributed with this work for additional information regarding
 * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance with the License. You may obtain a
 * copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */

package de.knightsoftnet.validators.shared.impl;

import org.apache.commons.lang3.StringUtils;

import java.lang.annotation.Annotation;

import jakarta.validation.ConstraintValidator;

/**
 * Common Stuff from Tax and Tin Validator.
 *
 * @author Manfred Tremmel
 *
 */
public abstract class AbstractTaxTinNumberValidator
    implements ConstraintValidator {
  /**
   * modulo 11.
   */
  protected static final int MODULO_11 = 11;

  /**
   * error message key.
   */
  protected String message;

  /**
   * field name of the country code field.
   */
  protected String fieldCountryCode;

  /**
   * are lower case country codes allowed (true/false).
   */
  protected boolean allowLowerCaseCountryCode;


  /**
   * check the Tax Number/Tax Identification Number, country version for Austria.
   *
   * @param number tax number/tax identification number to check
   * @return true if checksum is ok
   */
  protected boolean checkAtNumber(final String number) {
    final int checkSum = number.charAt(8) - '0';
    final int sum = number.charAt(0) - '0' + squareSum((number.charAt(1) - '0') * 2) //
        + number.charAt(2) - '0' + squareSum((number.charAt(3) - '0') * 2) //
        + number.charAt(4) - '0' + squareSum((number.charAt(5) - '0') * 2) //
        + number.charAt(6) - '0' + squareSum((number.charAt(7) - '0') * 2);
    final int calculatedCheckSum = (80 - sum) % 10;
    return checkSum == calculatedCheckSum;
  }

  /**
   * check the Tax Identification Number number, country version for Denmark.
   *
   * @param number vat id to check
   * @return true if checksum is ok
   */
  protected boolean checkDk(final String number) {
    final int checkSum = number.charAt(9) - '0';
    final int sum = ((number.charAt(0) - '0') * 4 //
        + (number.charAt(1) - '0') * 2 //
        + (number.charAt(2) - '0') * 3 //
        + (number.charAt(3) - '0') * 7 //
        + (number.charAt(4) - '0') * 6 //
        + (number.charAt(5) - '0') * 5 //
        + (number.charAt(6) - '0') * 4 //
        + (number.charAt(7) - '0') * 3 //
        + (number.charAt(8) - '0') * 2) //
        % MODULO_11;
    int calculatedCheckSum = MODULO_11 - sum;
    if (calculatedCheckSum == 10) {
      calculatedCheckSum = 0;
    }
    return checkSum == calculatedCheckSum;
  }

  /**
   * check the Tax Identification Number number, country version for Estonia.
   *
   * @param number vat id to check
   * @return true if checksum is ok
   */
  protected boolean checkEe(final String number) {
    final int checkSum = number.charAt(10) - '0';
    int calculatedCheckSum = ((number.charAt(0) - '0') * 1 //
        + (number.charAt(1) - '0') * 2 //
        + (number.charAt(2) - '0') * 3 //
        + (number.charAt(3) - '0') * 4 //
        + (number.charAt(4) - '0') * 5 //
        + (number.charAt(5) - '0') * 6 //
        + (number.charAt(6) - '0') * 7 //
        + (number.charAt(7) - '0') * 8 //
        + (number.charAt(8) - '0') * 9 //
        + (number.charAt(9) - '0') * 1) //
        % MODULO_11;
    if (calculatedCheckSum == 10) {
      calculatedCheckSum = ((number.charAt(0) - '0') * 3 //
          + (number.charAt(1) - '0') * 4 //
          + (number.charAt(2) - '0') * 5 //
          + (number.charAt(3) - '0') * 6 //
          + (number.charAt(4) - '0') * 7 //
          + (number.charAt(5) - '0') * 8 //
          + (number.charAt(6) - '0') * 9 //
          + (number.charAt(7) - '0') * 1 //
          + (number.charAt(8) - '0') * 2 //
          + (number.charAt(9) - '0') * 3) //
          % MODULO_11 % 10;
    }
    return checkSum == calculatedCheckSum;
  }

  /**
   * check the Tax Identification Number number, country version for Spain.
   *
   * @param number vat id to check
   * @return true if checksum is ok
   */
  protected boolean checkEs(final String number) {
    final char[] checkArray = {'T', 'R', 'W', 'A', 'G', 'M', 'Y', 'F', 'P', 'D', 'X', 'B', 'N', 'J',
        'Z', 'S', 'Q', 'V', 'H', 'L', 'C', 'K', 'E'};
    final char checkSum = number.charAt(8);
    final char calculatedCheckSum;
    final int sum;
    if (StringUtils.isNumeric(StringUtils.substring(number, 0, 8))) {
      // dni
      sum = Integer.parseInt(StringUtils.substring(number, 0, 8)) % 23;
      calculatedCheckSum = checkArray[sum];
    } else if (number.charAt(0) >= 'X' && number.charAt(0) <= 'Z') {
      // cif
      sum = Integer.parseInt(number.charAt(0) - '0' + StringUtils.substring(number, 1, 8)) % 23;
      calculatedCheckSum = checkArray[sum];
    } else {
      // nie
      final char letter = number.charAt(0);
      final String numberWork = StringUtils.substring(number, 1, 8);

      int evenSum = 0;
      int oddSum = 0;

      for (int i = 0; i < numberWork.length(); i++) {
        int charAsNum = numberWork.charAt(i) - '0';

        // Odd positions (Even index equals to odd position. i=0 equals first position)
        if (i % 2 == 0) {
          // Odd positions are multiplied first.
          charAsNum *= 2;

          // If the multiplication is bigger than 10 we need to adjust
          oddSum += charAsNum < 10 ? charAsNum : charAsNum - 9;

          // Even positions
          // Just sum them
        } else {
          evenSum += charAsNum;
        }

      }

      final int control_digit = (10 - (evenSum + oddSum) % 10) % 10;
      final char control_letter = "JABCDEFGHI".charAt(control_digit);

      switch (letter) {
        case 'A':
        case 'B':
        case 'E':
        case 'H':
          // Control must be a digit
          calculatedCheckSum = (char) (control_digit + '0');
          break;
        case 'K':
        case 'P':
        case 'Q':
        case 'S':
          // Control must be a letter
          calculatedCheckSum = control_letter;
          break;
        default:
          // Can be either
          if (control_letter == checkSum) {
            calculatedCheckSum = control_letter;
          } else {
            calculatedCheckSum = (char) (control_digit + '0');
          }
          break;
      }
    }
    return checkSum == calculatedCheckSum;
  }

  /**
   * check the Tax Identification Number number, default modulo 11.
   *
   * @param number vat id to check
   * @return true if checksum is ok
   */
  protected boolean checkModulo11(final String number) {
    final int checkSum = number.charAt(number.length() - 1) - '0';
    int sum = 10;
    for (int i = 0; i < number.length() - 1; i++) {
      int summe = (number.charAt(i) - '0' + sum) % 10;
      if (summe == 0) {
        summe = 10;
      }
      sum = 2 * summe % MODULO_11;
    }
    int calculatedCheckSum = MODULO_11 - sum;
    if (calculatedCheckSum == 10) {
      calculatedCheckSum = 0;
    }
    return checkSum == calculatedCheckSum;
  }

  /**
   * check the Tax Identification Number number, country version for countries using unique master
   * citizen number .
   *
   * @param number vat id to check
   * @return true if checksum is ok
   */
  protected boolean checkUniqueMasterCitizenNumber(final String number) {
    final int checkSum = number.charAt(12) - '0';
    final int sum = ((number.charAt(0) - '0' + number.charAt(6) - '0') * 7 //
        + (number.charAt(1) - '0' + number.charAt(7) - '0') * 6 //
        + (number.charAt(2) - '0' + number.charAt(8) - '0') * 5 //
        + (number.charAt(3) - '0' + number.charAt(9) - '0') * 4 //
        + (number.charAt(4) - '0' + number.charAt(10) - '0') * 3 //
        + (number.charAt(5) - '0' + number.charAt(11) - '0') * 2) //
        % MODULO_11;
    int calculatedCheckSum = MODULO_11 - sum;
    if (calculatedCheckSum == 10) {
      calculatedCheckSum = 0;
    }
    return checkSum == calculatedCheckSum;
  }

  /**
   * check the Tax Identification Number number, country version for Netherlands.
   *
   * @param number vat id to check
   * @return true if checksum is ok
   */
  protected boolean checkNl(final String number) {
    final int checkSum = number.charAt(8) - '0';
    int sum = 0;
    for (int i = 0; i < number.length() - 1; i++) {
      sum += (number.charAt(i) - '0') * (9 - i);
    }
    sum -= checkSum;
    return sum % 11 == 0;
  }

  /**
   * check the Tax Identification Number number, country version for Poland.
   *
   * @param number vat id to check
   * @return true if checksum is ok
   */
  protected boolean checkPl(final String number) {
    final int checkSum = number.charAt(number.length() - 1) - '0';
    int calculatedCheckSum;
    if (StringUtils.length(number) == 11) {
      // PESEL
      final int sum = (number.charAt(0) - '0') * 1 //
          + (number.charAt(1) - '0') * 3 //
          + (number.charAt(2) - '0') * 7 //
          + (number.charAt(3) - '0') * 9 //
          + (number.charAt(4) - '0') * 1 //
          + (number.charAt(5) - '0') * 3 //
          + (number.charAt(6) - '0') * 7 //
          + (number.charAt(7) - '0') * 9 //
          + (number.charAt(8) - '0') * 1 //
          + (number.charAt(9) - '0') * 3;
      calculatedCheckSum = sum % 10;
      if (calculatedCheckSum != 0) {
        calculatedCheckSum = 10 - sum % 10;
      }
    } else {
      // NIP
      final int sum = (number.charAt(0) - '0') * 6 //
          + (number.charAt(1) - '0') * 5 //
          + (number.charAt(2) - '0') * 7 //
          + (number.charAt(3) - '0') * 2 //
          + (number.charAt(4) - '0') * 3 //
          + (number.charAt(5) - '0') * 4 //
          + (number.charAt(6) - '0') * 5 //
          + (number.charAt(7) - '0') * 6 //
          + (number.charAt(8) - '0') * 7;
      calculatedCheckSum = sum % MODULO_11;
    }
    return checkSum == calculatedCheckSum;
  }

  /**
   * calculate square sum.
   *
   * @param value value to calculate square sum for
   * @return square sum
   */
  protected static int squareSum(final int value) {
    int result = 0;
    for (final char valueDigit : String.valueOf(value).toCharArray()) {
      result += Character.digit(valueDigit, 10);
    }
    return result;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy