IDEMPIERE-1200

Validate IBAN in C_BankAccount, C_BP_BankAccount, C_Payment, C_PaymentTransaction
Config via IBAN_VALIDATION, Default is Y
This commit is contained in:
markus_bozem 2017-02-17 21:14:57 +01:00
parent b4f0213136
commit 04928f78b8
8 changed files with 161 additions and 74 deletions

View File

@ -0,0 +1,10 @@
SET SQLBLANKLINES ON
SET DEFINE OFF
-- IBAN validation IDEMPIERE-1200
-- Jan 19, 2017 10:54:38 AM CET
INSERT INTO AD_SysConfig (AD_SysConfig_ID,AD_Client_ID,AD_Org_ID,Created,Updated,CreatedBy,UpdatedBy,IsActive,Name,Value,Description,EntityType,ConfigurationLevel,AD_SysConfig_UU) VALUES (200086,0,0,TO_DATE('2017-01-19 10:54:37','YYYY-MM-DD HH24:MI:SS'),TO_DATE('2017-01-19 10:54:37','YYYY-MM-DD HH24:MI:SS'),0,0,'Y','IBAN_VALIDATION','Y','Enables the validation of IBAN fields','D','S','1b324142-ae32-4cff-9ea9-792df3e4d142')
;
SELECT register_migration_script('201701191158_IDEMPIERE-1200') FROM dual
;

View File

@ -0,0 +1,7 @@
-- IBAN validation IDEMPIERE-1200
-- Jan 19, 2017 10:54:38 AM CET
INSERT INTO AD_SysConfig (AD_SysConfig_ID,AD_Client_ID,AD_Org_ID,Created,Updated,CreatedBy,UpdatedBy,IsActive,Name,Value,Description,EntityType,ConfigurationLevel,AD_SysConfig_UU) VALUES (200086,0,0,TO_TIMESTAMP('2017-01-19 10:54:37','YYYY-MM-DD HH24:MI:SS'),TO_TIMESTAMP('2017-01-19 10:54:37','YYYY-MM-DD HH24:MI:SS'),0,0,'Y','IBAN_VALIDATION','Y','Enables the validation of IBAN fields','D','S','1b324142-ae32-4cff-9ea9-792df3e4d142')
;
SELECT register_migration_script('201701191158_IDEMPIERE-1200') FROM dual
;

View File

@ -22,6 +22,9 @@ import java.util.Properties;
import org.adempiere.util.PaymentUtil;
import org.compiere.util.CLogger;
import org.compiere.util.Env;
import org.compiere.util.IBAN;
import org.compiere.util.Util;
/**
* BP Bank Account Model
@ -207,6 +210,17 @@ public class MBPBankAccount extends X_C_BP_BankAccount
setCreditCardVV(encrpytedCvv);
}
if (MSysConfig.getBooleanValue(MSysConfig.IBAN_VALIDATION, false,
Env.getContextAsInt(Env.getCtx(), "#AD_Client_ID"))) {
if (!Util.isEmpty(getIBAN())) {
setIBAN(IBAN.normalizeIBAN(getIBAN()));
if (!IBAN.isCheckDigitValid(getIBAN())) {
log.saveError("Error", "IBAN is invalid");
return false;
}
}
}
return true;
} // beforeSave

View File

@ -123,6 +123,29 @@ public class MBankAccount extends X_C_BankAccount
return msgreturn.toString();
} // getName
/**
* Before Save
* @param newRecord new record
* @return success
*/
protected boolean beforeSave(boolean newRecord) {
if (MSysConfig.getBooleanValue(MSysConfig.IBAN_VALIDATION, false,
Env.getContextAsInt(Env.getCtx(), "#AD_Client_ID"))) {
if (!Util.isEmpty(getIBAN())) {
setIBAN(IBAN.normalizeIBAN(getIBAN()));
if (!IBAN.isCheckDigitValid(getIBAN())) {
log.saveError("Error", "IBAN is invalid");
return false;
}
}
}
return true;
} // beforeSave
/**
* After Save
* @param newRecord new record
@ -136,22 +159,4 @@ public class MBankAccount extends X_C_BankAccount
return success;
} // 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

View File

@ -38,8 +38,10 @@ import org.compiere.process.ProcessInfo;
import org.compiere.util.CLogger;
import org.compiere.util.DB;
import org.compiere.util.Env;
import org.compiere.util.IBAN;
import org.compiere.util.Msg;
import org.compiere.util.Trx;
import org.compiere.util.Util;
import org.compiere.util.ValueNamePair;
/**
@ -796,6 +798,17 @@ public class MPayment extends X_C_Payment
}
}
if (MSysConfig.getBooleanValue(MSysConfig.IBAN_VALIDATION, false,
Env.getContextAsInt(Env.getCtx(), "#AD_Client_ID"))) {
if (!Util.isEmpty(getIBAN())) {
setIBAN(IBAN.normalizeIBAN(getIBAN()));
if (!IBAN.isCheckDigitValid(getIBAN())) {
log.saveError("Error", "IBAN is invalid");
return false;
}
}
}
return true;
} // beforeSave

View File

@ -26,8 +26,10 @@ import org.compiere.process.DocAction;
import org.compiere.process.ProcessCall;
import org.compiere.process.ProcessInfo;
import org.compiere.util.Env;
import org.compiere.util.IBAN;
import org.compiere.util.Msg;
import org.compiere.util.Trx;
import org.compiere.util.Util;
/**
*
@ -81,6 +83,17 @@ public class MPaymentTransaction extends X_C_PaymentTransaction implements Proce
setCreditCardVV(encrpytedCvv);
}
if (MSysConfig.getBooleanValue(MSysConfig.IBAN_VALIDATION, false,
Env.getContextAsInt(Env.getCtx(), "#AD_Client_ID"))) {
if (!Util.isEmpty(getIBAN())) {
setIBAN(IBAN.normalizeIBAN(getIBAN()));
if (!IBAN.isCheckDigitValid(getIBAN())) {
log.saveError("Error", "IBAN is invalid");
return false;
}
}
}
return true;
}

View File

@ -84,6 +84,7 @@ public class MSysConfig extends X_AD_SysConfig
public static final String ENABLE_PAYMENTBOX_BUTTON = "ENABLE_PAYMENTBOX_BUTTON";
public static final String GRIDTABLE_LOAD_TIMEOUT_IN_SECONDS = "GRIDTABLE_LOAD_TIMEOUT_IN_SECONDS";
public static final String HTML_REPORT_THEME = "HTML_REPORT_THEME";
public static final String IBAN_VALIDATION = "IBAN_VALIDATION" ;
public static final String Invoice_ReverseUseNewNumber = "Invoice_ReverseUseNewNumber";
public static final String JASPER_SWAP_MAX_PAGES = "JASPER_SWAP_MAX_PAGES";
public static final String LASTRUN_RECORD_COUNT = "LASTRUN_RECORD_COUNT";

View File

@ -5,63 +5,87 @@ 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;
/**
* @param iban
* @return normalized IBAN
*/
BigInteger numericIBAN = getNumericIBAN(iban, false);
public static String normalizeIBAN(String iban)
{
if (iban!=null)
{
return iban.trim().replace(" ", "") ;
}
return null ;
}
/**
* 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) {
try {
if (null == iban)
return false;
int validIBANLength = getValidIBANLength(iban);
if (validIBANLength < 4)
return false;
if (iban.length() != validIBANLength)
return false;
int checkDigit = numericIBAN.mod(new BigInteger("97")).intValue();
return checkDigit == 1;
}
BigInteger numericIBAN = getNumericIBAN(iban, false);
/**
* 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();
}
int checkDigit = numericIBAN.mod(new BigInteger("97")).intValue();
return checkDigit == 1;
} catch (Exception e) {
return false;
}
}
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)));
}
}
/**
* 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();
}
return new BigInteger(numericIBAN.toString());
}
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)));
}
}
private static int getAlphabetPosition(char letter) {
return Character.valueOf(Character.toUpperCase(letter)).compareTo(Character.valueOf('A'));
}
return new BigInteger(numericIBAN.toString());
}
private static int getAlphabetPosition(char letter) {
return Character.valueOf(Character.toUpperCase(letter)).compareTo(Character.valueOf('A'));
}
}