Last active
June 3, 2024 12:11
-
-
Save hasokeric/987852e08efad682c4e7a48af9e7a417 to your computer and use it in GitHub Desktop.
NACHA Check Digit Validation and Extraction
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Linq; | |
public class Program | |
{ | |
public static void Main() | |
{ | |
Func<string, int> GetCheckDigit = _routingNumber => | |
(10 - _routingNumber.Where(char.IsDigit) | |
.Select((digit, index) => (digit - '0') * new[] { 3, 7, 1 }[index % 3]) | |
.Sum() % 10) % 10; | |
Func<string, bool> IsValidCheckDigit = _routingNumber => | |
{ | |
return (10 - _routingNumber.Where(char.IsDigit) | |
.Select((digit, index) => (digit - '0') * new[] { 3, 7, 1 }[index % 3]) | |
.Sum() % 10) % 10 == 0; | |
}; | |
Console.WriteLine(IsValidCheckDigit("123456")); | |
Console.WriteLine(IsValidCheckDigit("123456890")); | |
Console.WriteLine(GetCheckDigit("123456")); | |
Console.WriteLine(GetCheckDigit("1234563")); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public int GetCheckDigit(string routingNumber) | |
{ | |
if (routingNumber.Length != 8 || !routingNumber.All(char.IsDigit)) | |
throw new ArgumentException("Routing number must be 8 digits long."); | |
int[] weights = { 3, 7, 1 }; | |
int sum = routingNumber.Select((digit, index) => (digit - '0') * weights[index % 3]).Sum(); | |
int remainder = sum % 10; | |
return (10 - remainder) % 10; | |
} | |
public int GetCheckDigit2(string routingNumber) | |
{ | |
return (10 - routingNumber.Where(char.IsDigit) | |
.Select((digit, index) => (digit - '0') * new[] { 3, 7, 1 }[index % 3]) | |
.Sum() % 10) % 10; | |
} | |
public bool IsValidCheckDigit(string routingNumber) | |
{ | |
return (10 - routingNumber.Where(char.IsDigit) | |
.Select((digit, index) => (digit - '0') * new[] { 3, 7, 1 }[index % 3]) | |
.Sum() % 10) % 10 == 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Mandatory Fields for Electronic Bank Interface | |
// Initialize Helpers | |
Func<string, bool> IsNumeric = (_inValue) => | |
{ | |
long number; | |
return Int64.TryParse(_inValue, out number); | |
}; | |
Func<string, int> GetCheckDigit = _routingNumber => | |
(10 - _routingNumber.Where(char.IsDigit) | |
.Select((digit, index) => (digit - '0') * new[] { 3, 7, 1 }[index % 3]) | |
.Sum() % 10) % 10; | |
Func<string, bool> IsValidCheckDigit = _routingNumber => | |
{ | |
return (10 - _routingNumber.Where(char.IsDigit) | |
.Select((digit, index) => (digit - '0') * new[] { 3, 7, 1 }[index % 3]) | |
.Sum() % 10) % 10 == 0; | |
}; | |
// Get Vendor Row | |
var ttVendBankRow = ds.VendBank.FirstOrDefault(x => (x.Added() || x.Updated()) && x.Company == Session.CompanyID); | |
if (ttVendBankRow != null) | |
{ | |
// Get Pay Method Row | |
var payMethodRow = Db.PayMethod | |
.Where(x => x.Company == Session.CompanyID && x.PMUID == ttVendBankRow.PMUID) | |
.Select(x => new { x.Company, x.PMUID, x.Name, x.Type, x.PMSource, x.EFTHeadUID, x.OutputFile }) | |
.FirstOrDefault(); | |
// Always Require These Good Practice | |
if (ttVendBankRow.CountryNum == 0) | |
{ | |
throw new BLException("Pay To Country is required."); | |
} | |
else if (ttVendBankRow.BCountryNum == 0) | |
{ | |
throw new BLException("Suppliers Bank Country is required."); | |
} | |
// If Pay Method is Electronic Interface and contains ACH or WIRE | |
if (payMethodRow.Type == 1 && (payMethodRow.Name.ToUpper().Contains("ACH") || payMethodRow.Name.ToUpper().Contains("WIRE"))) | |
{ | |
// Get Country ISO Code | |
string countryISOCode = Db.Country | |
.Where(c => c.Company == Session.CompanyID && c.CountryNum == ttVendBankRow.CountryNum) | |
.Select(c => c.ISOCode) | |
.DefaultIfEmpty("") | |
.First(); | |
if (countryISOCode == string.Empty) | |
{ | |
throw new BLException("The Selected Country does not have ISO Code Configured."); | |
} | |
// Validate Output File for Electronic Interface is Configured | |
if (string.IsNullOrEmpty(payMethodRow.OutputFile)) | |
{ | |
throw new BLException("Output File is not configured for Electronic Interface."); | |
} | |
// | |
// WIRE PAYMENT | |
// | |
if (payMethodRow.Name.ToUpper().Contains("WIRE")) | |
{ | |
// International Always Requires Swift | |
if (ttVendBankRow.SwiftNum == string.Empty && countryISOCode != "US" && countryISOCode != "CA") | |
{ | |
throw new BLException("WIRE - Bank Identifier (SWIFT) is required."); | |
} | |
else if (ttVendBankRow.LocalBIC == string.Empty && ttVendBankRow.SwiftNum == string.Empty) | |
{ | |
throw new BLException("WIRE - Bank Routing Number (ABA) or Bank Identifier (SWIFT) is required."); | |
} | |
} | |
// | |
// ACH PAYMENT | |
// | |
else if (payMethodRow.Name.ToUpper().Contains("ACH")) | |
{ | |
if (ttVendBankRow.LocalBIC == string.Empty) | |
{ | |
throw new BLException("ACH - Bank Routing Number (ABA) is required."); | |
} | |
} | |
// If Canada then Address, City, State and Zip Code are Mandatory | |
if (countryISOCode == "CA" | |
&& (ttVendBankRow.Address1 == string.Empty | |
|| ttVendBankRow.City == string.Empty | |
|| ttVendBankRow.State == string.Empty | |
|| ttVendBankRow.PostalCode == string.Empty)) | |
{ | |
throw new BLException("Address, City, State and Zip Code are Mandatory for CANADA."); | |
} | |
// If we ever do Intermediate Bank Transfers we will need this | |
/*if (ttVendBankRow["InterBankISOCountry_c"] == string.Empty | |
&& (ttVendBankRow["InterBankName_c"] != string.Empty | |
|| ttVendBankRow["InterBankStreet_c"] != string.Empty | |
|| ttVendBankRow["InterBankBldg_c"] != string.Empty | |
|| ttVendBankRow["InterBankZip_c"] != string.Empty | |
|| ttVendBankRow["InterBankCity_c"] != string.Empty | |
|| ttVendBankRow["InterBankState_c"] != string.Empty)) | |
{ | |
throw new BLException("Wire Intermediate Bank - Country is required."); | |
}*/ | |
// Validate Bank Account Number, LocalBIC and SwiftNum for format if they have been specified. | |
if (!string.IsNullOrEmpty(ttVendBankRow.BankAcctNumber) && (ttVendBankRow.BankAcctNumber.Length < 5 || !IsNumeric(ttVendBankRow.BankAcctNumber))) | |
{ | |
throw new BLException("Bank Account Number is not in the correct format. It should contain at least 5 characters with only numbers."); | |
} | |
else if (!string.IsNullOrEmpty(ttVendBankRow.LocalBIC) && (ttVendBankRow.LocalBIC.Length < 8 || !IsNumeric(ttVendBankRow.LocalBIC))) | |
{ | |
throw new BLException("Bank Routing Number (ABA/BIC) is not in the correct format. It should contain at least 8 characters with only numbers. US Routing Numbers should be 9 digits."); | |
} | |
// SWIFT should have some alpha characters not just numbers | |
else if (!string.IsNullOrEmpty(ttVendBankRow.SwiftNum) && (ttVendBankRow.SwiftNum.Length < 8 || IsNumeric(ttVendBankRow.SwiftNum))) | |
{ | |
throw new BLException("Bank Identifier (SWIFT) is not in the correct format. It should contain at least 8 characters with some alpha characters."); | |
} | |
// Validate Routing Number Check Digit | |
if (!string.IsNullOrEmpty(ttVendBankRow.LocalBIC) && !IsValidCheckDigit(ttVendBankRow.LocalBIC)) | |
{ | |
throw new BLException("Bank Routing Number (ABA/BIC) is not valid. Check Digit is incorrect. It should be " + GetCheckDigit(ttVendBankRow.LocalBIC)); | |
} | |
// Bank Account Number should not be the same as the Routing Number | |
if (ttVendBankRow.BankAcctNumber == ttVendBankRow.LocalBIC) | |
{ | |
throw new BLException("Bank Account Number should not be the same as the Bank Routing Number."); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment