Skip to content

Instantly share code, notes, and snippets.

@hasokeric
Last active June 3, 2024 12:11
Show Gist options
  • Save hasokeric/987852e08efad682c4e7a48af9e7a417 to your computer and use it in GitHub Desktop.
Save hasokeric/987852e08efad682c4e7a48af9e7a417 to your computer and use it in GitHub Desktop.
NACHA Check Digit Validation and Extraction
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"));
}
}
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;
}
// 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