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:
parent
b4f0213136
commit
04928f78b8
|
@ -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
|
||||||
|
;
|
|
@ -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
|
||||||
|
;
|
|
@ -22,6 +22,9 @@ import java.util.Properties;
|
||||||
|
|
||||||
import org.adempiere.util.PaymentUtil;
|
import org.adempiere.util.PaymentUtil;
|
||||||
import org.compiere.util.CLogger;
|
import org.compiere.util.CLogger;
|
||||||
|
import org.compiere.util.Env;
|
||||||
|
import org.compiere.util.IBAN;
|
||||||
|
import org.compiere.util.Util;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BP Bank Account Model
|
* BP Bank Account Model
|
||||||
|
@ -207,6 +210,17 @@ public class MBPBankAccount extends X_C_BP_BankAccount
|
||||||
setCreditCardVV(encrpytedCvv);
|
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;
|
return true;
|
||||||
} // beforeSave
|
} // beforeSave
|
||||||
|
|
||||||
|
|
|
@ -123,6 +123,29 @@ public class MBankAccount extends X_C_BankAccount
|
||||||
return msgreturn.toString();
|
return msgreturn.toString();
|
||||||
} // getName
|
} // 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
|
* After Save
|
||||||
* @param newRecord new record
|
* @param newRecord new record
|
||||||
|
@ -135,23 +158,5 @@ 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
|
||||||
|
|
|
@ -38,8 +38,10 @@ import org.compiere.process.ProcessInfo;
|
||||||
import org.compiere.util.CLogger;
|
import org.compiere.util.CLogger;
|
||||||
import org.compiere.util.DB;
|
import org.compiere.util.DB;
|
||||||
import org.compiere.util.Env;
|
import org.compiere.util.Env;
|
||||||
|
import org.compiere.util.IBAN;
|
||||||
import org.compiere.util.Msg;
|
import org.compiere.util.Msg;
|
||||||
import org.compiere.util.Trx;
|
import org.compiere.util.Trx;
|
||||||
|
import org.compiere.util.Util;
|
||||||
import org.compiere.util.ValueNamePair;
|
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;
|
return true;
|
||||||
} // beforeSave
|
} // beforeSave
|
||||||
|
|
||||||
|
|
|
@ -26,8 +26,10 @@ import org.compiere.process.DocAction;
|
||||||
import org.compiere.process.ProcessCall;
|
import org.compiere.process.ProcessCall;
|
||||||
import org.compiere.process.ProcessInfo;
|
import org.compiere.process.ProcessInfo;
|
||||||
import org.compiere.util.Env;
|
import org.compiere.util.Env;
|
||||||
|
import org.compiere.util.IBAN;
|
||||||
import org.compiere.util.Msg;
|
import org.compiere.util.Msg;
|
||||||
import org.compiere.util.Trx;
|
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);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 ENABLE_PAYMENTBOX_BUTTON = "ENABLE_PAYMENTBOX_BUTTON";
|
||||||
public static final String GRIDTABLE_LOAD_TIMEOUT_IN_SECONDS = "GRIDTABLE_LOAD_TIMEOUT_IN_SECONDS";
|
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 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 Invoice_ReverseUseNewNumber = "Invoice_ReverseUseNewNumber";
|
||||||
public static final String JASPER_SWAP_MAX_PAGES = "JASPER_SWAP_MAX_PAGES";
|
public static final String JASPER_SWAP_MAX_PAGES = "JASPER_SWAP_MAX_PAGES";
|
||||||
public static final String LASTRUN_RECORD_COUNT = "LASTRUN_RECORD_COUNT";
|
public static final String LASTRUN_RECORD_COUNT = "LASTRUN_RECORD_COUNT";
|
||||||
|
|
|
@ -5,63 +5,87 @@ import java.math.BigInteger;
|
||||||
import java.util.ResourceBundle;
|
import java.util.ResourceBundle;
|
||||||
|
|
||||||
public class IBAN {
|
public class IBAN {
|
||||||
/**
|
|
||||||
* Determines if the given IBAN is valid based on the check digit.
|
/**
|
||||||
* To validate the checksum:
|
* @param iban
|
||||||
* 1. Check that the total IBAN length is correct as per the country. If not, the IBAN is invalid.
|
* @return normalized IBAN
|
||||||
* 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.
|
public static String normalizeIBAN(String iban)
|
||||||
* If the remainder is 1 you have a valid IBAN number.
|
{
|
||||||
* @param iban
|
if (iban!=null)
|
||||||
* @return boolean indicating if specific IBAN has a valid check digit
|
{
|
||||||
*/
|
return iban.trim().replace(" ", "") ;
|
||||||
public static boolean isCheckDigitValid(String iban) {
|
}
|
||||||
if (null == iban) return false;
|
return null ;
|
||||||
|
}
|
||||||
int validIBANLength = getValidIBANLength(iban);
|
/**
|
||||||
if (validIBANLength < 4) return false;
|
* Determines if the given IBAN is valid based on the check digit. To
|
||||||
if (iban.length() != validIBANLength) return false;
|
* 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
|
||||||
BigInteger numericIBAN = getNumericIBAN(iban, false);
|
* 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();
|
BigInteger numericIBAN = getNumericIBAN(iban, false);
|
||||||
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) {
|
int checkDigit = numericIBAN.mod(new BigInteger("97")).intValue();
|
||||||
return Character.valueOf(Character.toUpperCase(letter)).compareTo(Character.valueOf('A'));
|
return checkDigit == 1;
|
||||||
}
|
} catch (Exception e) {
|
||||||
|
return 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
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'));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue