IDEMPIERE-1200 Check consistency of IBAN
This commit is contained in:
parent
d5cba25082
commit
b4f0213136
|
@ -21,6 +21,8 @@ import java.util.Properties;
|
||||||
|
|
||||||
import org.compiere.util.CCache;
|
import org.compiere.util.CCache;
|
||||||
import org.compiere.util.Env;
|
import org.compiere.util.Env;
|
||||||
|
import org.compiere.util.IBAN;
|
||||||
|
import org.compiere.util.Util;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -133,5 +135,23 @@ public class MBankAccount extends X_C_BankAccount
|
||||||
return insert_Accounting("C_BankAccount_Acct", "C_AcctSchema_Default", null);
|
return insert_Accounting("C_BankAccount_Acct", "C_AcctSchema_Default", null);
|
||||||
return success;
|
return success;
|
||||||
} // afterSave
|
} // afterSave
|
||||||
|
|
||||||
|
protected boolean beforeSave (boolean newRecord)
|
||||||
|
{
|
||||||
|
if (!Util.isEmpty(getIBAN())) {
|
||||||
|
setIBAN(getIBAN().trim().replace(" ", ""));
|
||||||
|
try {
|
||||||
|
if (!IBAN.isCheckDigitValid(getIBAN())) {
|
||||||
|
log.saveError("Error", "IBAN is invalid");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.saveError("Error", "IBAN is invalid");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
} // MBankAccount
|
} // MBankAccount
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
package org.compiere.util;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
|
||||||
|
import java.util.ResourceBundle;
|
||||||
|
|
||||||
|
public class IBAN {
|
||||||
|
/**
|
||||||
|
* Determines if the given IBAN is valid based on the check digit.
|
||||||
|
* To validate the checksum:
|
||||||
|
* 1. Check that the total IBAN length is correct as per the country. If not, the IBAN is invalid.
|
||||||
|
* 2. Move the four initial characters to the end of the string.
|
||||||
|
* 3. Replace the letters in the string with digits, expanding the string as necessary, such that A=10, B=11 and Z=35.
|
||||||
|
* 4. Convert the string to an integer and mod-97 the entire number.
|
||||||
|
* If the remainder is 1 you have a valid IBAN number.
|
||||||
|
* @param iban
|
||||||
|
* @return boolean indicating if specific IBAN has a valid check digit
|
||||||
|
*/
|
||||||
|
public static boolean isCheckDigitValid(String iban) {
|
||||||
|
if (null == iban) return false;
|
||||||
|
|
||||||
|
int validIBANLength = getValidIBANLength(iban);
|
||||||
|
if (validIBANLength < 4) return false;
|
||||||
|
if (iban.length() != validIBANLength) return false;
|
||||||
|
|
||||||
|
BigInteger numericIBAN = getNumericIBAN(iban, false);
|
||||||
|
|
||||||
|
int checkDigit = numericIBAN.mod(new BigInteger("97")).intValue();
|
||||||
|
return checkDigit == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Using the IBAN.properties file gets the valid fixed length value for a country code.
|
||||||
|
* Only uses the first 2 characters of the given string.
|
||||||
|
* @param countryCode
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static int getValidIBANLength(String countryCode) {
|
||||||
|
String code = countryCode.substring(0,2).toUpperCase();
|
||||||
|
String length = ResourceBundle.getBundle(IBAN.class.getCanonicalName()).getString("length."+code);
|
||||||
|
if (length == null) return -1;
|
||||||
|
return Integer.valueOf(length).intValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BigInteger getNumericIBAN(String iban, boolean isCheckDigitAtEnd) {
|
||||||
|
String endCheckDigitIBAN = iban;
|
||||||
|
if (!isCheckDigitAtEnd) {
|
||||||
|
//Move first four characters to end of string to put check digit at end
|
||||||
|
endCheckDigitIBAN = iban.substring(4) + iban.substring(0, 4);
|
||||||
|
}
|
||||||
|
StringBuffer numericIBAN = new StringBuffer();
|
||||||
|
for (int i = 0; i < endCheckDigitIBAN.length(); i++) {
|
||||||
|
if (Character.isDigit(endCheckDigitIBAN.charAt(i))) {
|
||||||
|
numericIBAN.append(endCheckDigitIBAN.charAt(i));
|
||||||
|
} else {
|
||||||
|
numericIBAN.append(10 + getAlphabetPosition(endCheckDigitIBAN.charAt(i)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new BigInteger(numericIBAN.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getAlphabetPosition(char letter) {
|
||||||
|
return Character.valueOf(Character.toUpperCase(letter)).compareTo(Character.valueOf('A'));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
# IBAN related properties. Includes IBAN lengths for different countries
|
||||||
|
length.AD=24
|
||||||
|
length.AT=20
|
||||||
|
length.BE=16
|
||||||
|
length.BA=20
|
||||||
|
length.BG=22
|
||||||
|
length.CH=21
|
||||||
|
length.CY=28
|
||||||
|
length.CZ=24
|
||||||
|
length.DE=22
|
||||||
|
length.DK=18
|
||||||
|
length.EE=20
|
||||||
|
length.ES=24
|
||||||
|
length.FO=18
|
||||||
|
length.FI=18
|
||||||
|
length.FR=27
|
||||||
|
length.GB=22
|
||||||
|
length.GI=23
|
||||||
|
length.GL=18
|
||||||
|
length.GR=27
|
||||||
|
length.HU=28
|
||||||
|
length.HR=21
|
||||||
|
length.IE=22
|
||||||
|
length.IS=26
|
||||||
|
length.IT=27
|
||||||
|
length.LI=21
|
||||||
|
length.LT=20
|
||||||
|
length.LU=20
|
||||||
|
length.LV=21
|
||||||
|
length.MA=24
|
||||||
|
length.MC=27
|
||||||
|
length.MK=19
|
||||||
|
length.MT=31
|
||||||
|
length.NL=18
|
||||||
|
length.NO=15
|
||||||
|
length.PL=28
|
||||||
|
length.PT=25
|
||||||
|
length.RO=24
|
||||||
|
length.RS=22
|
||||||
|
length.SE=24
|
||||||
|
length.SI=19
|
||||||
|
length.SK=24
|
||||||
|
length.SM=27
|
||||||
|
length.TN=24
|
||||||
|
length.TR=26
|
Loading…
Reference in New Issue