/******************************************************************************
* Product: Adempiere ERP & CRM Smart Business Solution *
* Copyright (C) 1999-2006 ComPiere, Inc. All Rights Reserved. *
* This program is free software; you can redistribute it and/or modify it *
* under the terms version 2 of the GNU General Public License as published *
* by the Free Software Foundation. This program is distributed in the hope *
* that it will be useful, but WITHOUT ANY WARRANTY; without even the implied *
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU General Public License for more details. *
* You should have received a copy of the GNU General Public License along *
* with this program; if not, write to the Free Software Foundation, Inc., *
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *
* For the text or an alternative of this public license, you may reach us *
* ComPiere, Inc., 2620 Augustine Dr. #245, Santa Clara, CA 95054, USA *
* or via info@compiere.org or http://www.compiere.org/license.html *
*****************************************************************************/
package org.compiere.model;
import java.util.Calendar;
import java.util.StringTokenizer;
import java.util.logging.Level;
import org.compiere.util.CLogger;
import org.compiere.util.Env;
import org.compiere.util.Msg;
/**
* Payment Validation Routines
*
* @author Jorg Janke
* @version $Id: MPaymentValidate.java,v 1.2 2006/07/30 00:51:05 jjanke Exp $
*/
public class MPaymentValidate
{
/** Static Logger */
private static CLogger s_log = CLogger.getCLogger (MPaymentValidate.class);
/**
* Is this a valid Credit Card Expire Date?
* @param mmyy Expire in form of mmyy
* @return "" or Error AD_Message
*/
public static String validateCreditCardExp (String mmyy)
{
String exp = checkNumeric(mmyy);
if (exp.length() != 4)
return Msg.getMsg(Env.getCtx(), "CreditCardExpFormat");
//
String mmStr = exp.substring(0,2);
String yyStr = exp.substring(2,4);
//
int mm = 0;
int yy = 0;
try
{
mm = Integer.parseInt(mmStr);
yy = Integer.parseInt(yyStr);
}
catch (Exception e)
{
return Msg.getMsg(Env.getCtx(), "CreditCardExpFormat");
}
return validateCreditCardExp(mm,yy);
} // validateCreditCardExp
/**
* Return Month of Expire
* @param mmyy Expire in form of mmyy
* @return month
*/
public static int getCreditCardExpMM (String mmyy)
{
String mmStr = mmyy.substring(0,2);
int mm = 0;
try
{
mm = Integer.parseInt(mmStr);
}
catch (Exception e)
{
}
return mm;
} // getCreditCardExpMM
/**
* Return Year of Expire
* @param mmyy Expire in form of mmyy
* @return year
*/
public static int getCreditCardExpYY (String mmyy)
{
String yyStr = mmyy.substring(2);
int yy = 0;
try
{
yy = Integer.parseInt(yyStr);
}
catch (Exception e)
{
}
return yy;
} // getCreditCardExpYY
/**
* Is this a valid Credit Card Expire Date?
* @param mm month
* @param yy year
* @return "" or Error AD_Message
*/
public static String validateCreditCardExp (int mm, int yy)
{
if (mm < 1 || mm > 12)
return Msg.getMsg(Env.getCtx(), "CreditCardExpMonth");
// Today's date
Calendar cal = Calendar.getInstance();
int year = cal.get(Calendar.YEAR) - 2000; // two digits
int month = cal.get(Calendar.MONTH) + 1; // zero based
//
if (yy < year)
return Msg.getMsg(Env.getCtx(), "CreditCardExpired");
else if (yy == year && mm < month)
return Msg.getMsg(Env.getCtx(), "CreditCardExpired");
return "";
} // validateCreditCardExp
/**
* Validate Credit Card Number.
* - Based on LUHN formula
* @param creditCardNumber credit card number
* @return "" or Error AD_Message
*/
public static String validateCreditCardNumber (String creditCardNumber)
{
if (creditCardNumber == null || creditCardNumber.length() == 0)
return Msg.getMsg(Env.getCtx(), "CreditCardNumberError");
/**
* 1: Double the value of alternate digits beginning with
* the first right-hand digit (low order).
* 2: Add the individual digits comprising the products
* obtained in step 1 to each of the unaffected digits
* in the original number.
* 3: Subtract the total obtained in step 2 from the next higher
* number ending in 0 [this in the equivalent of calculating
* the "tens complement" of the low order digit (unit digit)
* of the total].
* If the total obtained in step 2 is a number ending in zero
* (30, 40 etc.), the check digit is 0.
* Example:
* Account number: 4992 73 9871 6
*
* 4 9 9 2 7 3 9 8 7 1 6
* x2 x2 x2 x2 x2
* -------------------------------
* 4 18 9 4 7 6 9 16 7 2 6
*
* 4 + 1 + 8 + 9 + 4 + 7 + 6 + 9 + 1 + 6 + 7 + 2 + 6 = 70
* 70 % 10 = 0
*/
// Clean up number
String ccNumber1 = checkNumeric(creditCardNumber);
int ccLength = ccNumber1.length();
// Reverse string
StringBuilder buf = new StringBuilder();
for (int i = ccLength; i != 0; i--)
buf.append(ccNumber1.charAt(i-1));
String ccNumber = buf.toString();
int sum = 0;
for (int i = 0; i < ccLength; i++)
{
int digit = Character.getNumericValue(ccNumber.charAt(i));
if (i % 2 == 1)
{
digit *= 2;
if (digit > 9)
digit -= 9;
}
sum += digit;
}
if (sum % 10 == 0)
return "";
if (s_log.isLoggable(Level.FINE)) s_log.fine("validateCreditCardNumber - " + creditCardNumber + " -> "
+ ccNumber + ", Luhn=" + sum);
return Msg.getMsg(Env.getCtx(), "CreditCardNumberError");
} // validateCreditCardNumber
/**
* Validate Credit Card Number.
* - Check Card Type and Length
* @param creditCardNumber CC Number
* @param creditCardType CC Type
* @return "" or Error AD_Message
*/
public static String validateCreditCardNumber (String creditCardNumber, String creditCardType)
{
if (creditCardNumber == null || creditCardType == null)
return Msg.getMsg(Env.getCtx(), "CreditCardNumberError");
// http://www.beachnet.com/~hstiles/cardtype.html
// http://staff.semel.fi/~kribe/document/luhn.htm
String ccStartList = ""; // comma separated list of starting numbers
String ccLengthList = ""; // comma separated list of lengths
//
if (creditCardType.equals(X_C_Payment.CREDITCARDTYPE_MasterCard))
{
ccStartList = "51,52,53,54,55";
ccLengthList = "16";
}
else if (creditCardType.equals(X_C_Payment.CREDITCARDTYPE_Visa))
{
ccStartList = "4";
ccLengthList = "13,16";
}
else if (creditCardType.equals(X_C_Payment.CREDITCARDTYPE_Amex))
{
ccStartList = "34,37";
ccLengthList = "15";
}
else if (creditCardType.equals(X_C_Payment.CREDITCARDTYPE_Discover))
{
ccStartList = "6011";
ccLengthList = "16";
}
else if (creditCardType.equals(X_C_Payment.CREDITCARDTYPE_Diners))
{
ccStartList = "300,301,302,303,304,305,36,38";
ccLengthList = "14";
}
else
{
// enRouteCard
ccStartList = "2014,2149";
ccLengthList = "15";
// JCBCard
ccStartList += ",3088,3096,3112,3158,3337,3528";
ccLengthList += ",16";
// JCBCard
ccStartList += ",2131,1800";
ccLengthList += ",15";
}
// Clean up number
String ccNumber = checkNumeric(creditCardNumber);
/**
* Check Length
*/
int ccLength = ccNumber.length();
boolean ccLengthOK = false;
StringTokenizer st = new StringTokenizer(ccLengthList, ",", false);
while (st.hasMoreTokens() && !ccLengthOK)
{
int l = Integer.parseInt(st.nextToken());
if (ccLength == l)
ccLengthOK = true;
}
if (!ccLengthOK)
{
if (s_log.isLoggable(Level.FINE)) s_log.fine("validateCreditCardNumber Length="
+ ccLength + " <> " + ccLengthList);
return Msg.getMsg(Env.getCtx(), "CreditCardNumberError");
}
/**
* Check Start Digits
*/
boolean ccIdentified = false;
st = new StringTokenizer(ccStartList, ",", false);
while (st.hasMoreTokens() && !ccIdentified)
{
if (ccNumber.startsWith(st.nextToken()))
ccIdentified = true;
}
if (!ccIdentified)
if (s_log.isLoggable(Level.FINE)) s_log.fine("validateCreditCardNumber Type="
+ creditCardType + " <> " + ccStartList);
//
String check = validateCreditCardNumber(ccNumber);
if (check.length() != 0)
return check;
if (!ccIdentified)
return Msg.getMsg(Env.getCtx(), "CreditCardNumberProblem?");
return "";
} // validateCreditCardNumber
/**
* Validate Verification Code
* @param creditCardVV CC Verification Code
* @return "" or Error AD_Message
*/
public static String validateCreditCardVV (String creditCardVV)
{
if (creditCardVV == null)
return "";
int length = checkNumeric(creditCardVV).length();
if (length == 3 || length == 4)
return "";
try
{
Integer.parseInt (creditCardVV);
return "";
}
catch (NumberFormatException ex)
{
if (s_log.isLoggable(Level.FINE)) s_log.fine("validateCreditCardVV - " + ex);
}
if (s_log.isLoggable(Level.FINE)) s_log.fine("validateCreditCardVV - length=" + length);
return Msg.getMsg(Env.getCtx(), "CreditCardVVError");
} // validateCreditCardVV
/**
* Validate Verification Code
* @param creditCardVV CC Verification Code
* @param creditCardType CC Type see CC_
* @return "" or Error AD_Message
*/
public static String validateCreditCardVV (String creditCardVV, String creditCardType)
{
// no data
if (creditCardVV == null || creditCardVV.length() == 0
|| creditCardType == null || creditCardType.length() == 0)
return "";
int length = checkNumeric(creditCardVV).length();
// Amex = 4 digits
if (creditCardType.equals(X_C_Payment.CREDITCARDTYPE_Amex))
{
if (length == 4)
{
try
{
Integer.parseInt (creditCardVV);
return "";
}
catch (NumberFormatException ex)
{
if (s_log.isLoggable(Level.FINE)) s_log.fine("validateCreditCardVV - " + ex);
}
}
if (s_log.isLoggable(Level.FINE)) s_log.fine("validateCreditCardVV(4) CC=" + creditCardType + ", length=" + length);
return Msg.getMsg(Env.getCtx(), "CreditCardVVError");
}
// Visa & MasterCard - 3 digits
if (creditCardType.equals(X_C_Payment.CREDITCARDTYPE_Visa)
|| creditCardType.equals(X_C_Payment.CREDITCARDTYPE_MasterCard))
{
if (length == 3)
{
try
{
Integer.parseInt (creditCardVV);
return "";
}
catch (NumberFormatException ex)
{
if (s_log.isLoggable(Level.FINE)) s_log.fine("validateCreditCardVV - " + ex);
}
}
if (s_log.isLoggable(Level.FINE)) s_log.fine("validateCreditCardVV(3) CC=" + creditCardType + ", length=" + length);
return Msg.getMsg(Env.getCtx(), "CreditCardVVError");
}
// Other
return "";
} // validateCreditCardVV
/**
* Validate Routing Number
* @param routingNo Routing No
* @return "" or Error AD_Message
*/
public static String validateRoutingNo (String routingNo)
{
int length = checkNumeric(routingNo).length();
// US - length 9
// Germany - length 8
// Japan - 7
// CH - 5
// Issue: Bank account country
if (length > 0)
return "";
return Msg.getMsg(Env.getCtx(), "PaymentBankRoutingNotValid");
} // validateBankRoutingNo
/**
* Validate Account No
* @param AccountNo AccountNo
* @return "" or Error AD_Message
*/
public static String validateAccountNo (String AccountNo)
{
int length = checkNumeric(AccountNo).length();
if (length > 0)
return "";
return Msg.getMsg(Env.getCtx(), "PaymentBankAccountNotValid");
} // validateBankAccountNo
/**
* Validate Check No
* @param CheckNo CheckNo
* @return "" or Error AD_Message
*/
public static String validateCheckNo (String CheckNo)
{
int length = checkNumeric(CheckNo).length();
if (length > 0)
return "";
return Msg.getMsg(Env.getCtx(), "PaymentBankCheckNotValid");
} // validateBankCheckNo
/**
* Remove all non Digit characters
* @param data input
* @return the digits of the data - ignore the rest
*/
public static String checkNumeric (String data)
{
if (data == null || data.length() == 0)
return "";
// Remove all non Digits
StringBuilder sb = new StringBuilder();
for (int i = 0; i < data.length(); i++)
{
if (Character.isDigit(data.charAt(i)))
sb.append(data.charAt(i));
}
return sb.toString();
} // checkNumeric
} // MPaymentValidate