Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

LuhnCalc and bpay MOD10 version 5

I am using the following PHP code to calculate a CRN for BPay:

<?php
function LuhnCalc($number) {
  $chars = array_reverse(str_split($number, 1));
  $odd = array_intersect_key($chars, array_fill_keys(range(1, count($chars), 2), null));
  $even = array_intersect_key($chars, array_fill_keys(range(0, count($chars), 2), null));
  $even = array_map(function($n) { return ($n >= 5)?2 * $n - 9:2 * $n; }, $even);
  $total = array_sum($odd) + array_sum($even);
  return ((floor($total / 10) + 1) * 10 - $total) % 10;
}
print LuhnCalc($_GET['num']);
?>

However it seems that BPAY is version 5 of MOD 10, for which I can't find any documentation. It seems to not be the same as MOD10.

The following numbers where tested:

2005,1597,3651,0584,9675

bPAY
2005 = 20052
1597 = 15976
3651 = 36514
0584 = 05840
9675 = 96752

MY CODE 
2005 = 20057 
1597 = 15974 
3651 = 36517 
0584 = 05843 
9675 = 96752

As you can see, none of them match the BPAY numbers.

like image 333
RussellHarrower Avatar asked Jun 13 '12 22:06

RussellHarrower


3 Answers

This PHP function will generate BPay reference numbers based on the mod10 version 5 algorithm.

Who knows why BPay can't add this to their website. I only found an explanation by googling finding the algorithm being called "MOD10V05" instead of "Mod 10 version 5".

function generateBpayRef($number) {

    $number = preg_replace("/\D/", "", $number);

    // The seed number needs to be numeric
    if(!is_numeric($number)) return false;

    // Must be a positive number
    if($number <= 0) return false;

    // Get the length of the seed number
    $length = strlen($number);

    $total = 0;

    // For each character in seed number, sum the character multiplied by its one based array position (instead of normal PHP zero based numbering)
    for($i = 0; $i < $length; $i++) $total += $number{$i} * ($i + 1);

    // The check digit is the result of the sum total from above mod 10
    $checkdigit = fmod($total, 10);

    // Return the original seed plus the check digit
    return $number . $checkdigit;

}
like image 51
Nick Adams Avatar answered Oct 14 '22 15:10

Nick Adams


Here's a way of implementing the "MOD10V5" algorithm (or "mod 10 version 5") using a t-sql user defined function in SQL server. It accepts a Customer ID up to 9 characters long, and return an 11 character CRN (Customer Reference Number).

I also prepended a version number onto the start of my CustomerID, you could do this too if you think you might end up changing it in the future.

CREATE Function [dbo].[CalculateBPayCRN]
(
    @CustomerID nvarchar(9)
)
RETURNS varchar(11)
AS
BEGIN

    DECLARE @NewCRN nvarchar(11)
    DECLARE @Multiplier TINYINT 
    DECLARE @Sum int
    DECLARE @SubTotal int  
    DECLARE @CheckDigit int  
    DECLARE @ReturnVal BIGINT

    SELECT @Multiplier = 1
    SELECT @SubTotal = 0

    -- If it's less than 9 characters, pad it with 0's, then prepend a '1'

    SELECT  @NewCRN = '1' + right('000000000'+ rtrim(@CustomerID), 9)

    -- loop through each digit in the @NewCRN, multiple it by the correct weighting and subtotal it:

    WHILE @Multiplier <= LEN(@NewCRN)  
    BEGIN  

        SET @Sum =  CAST(SUBSTRING(@NewCRN,@Multiplier,1) AS TINYINT) * @Multiplier  
        SET @SubTotal = @SubTotal + @Sum  
        SET @Multiplier = @Multiplier + 1  

    END 

    -- mod 10 the subtotal and the result is our check digit

    SET @CheckDigit = @SubTotal % 10  

    SELECT @ReturnVal = @NewCRN + cast(@CheckDigit as varchar)

    RETURN @ReturnVal
END
GO
like image 1
Rocklan Avatar answered Oct 14 '22 14:10

Rocklan


Modula 10 V1 in PHP. Tested against my Windows dataflex routine and it is the same.

function generateBpayRef($number) {
    //Mod 10 v1
    $number = preg_replace("/\D/", "", $number);

    // The seed number needs to be numeric
    if(!is_numeric($number)) return false;
    // Must be a positive number
    if($number <= 0) return false;

    $stringMemberNo =  "$number";
    $stringMemberNo = str_pad($stringMemberNo, 6, "0", STR_PAD_LEFT);  
    //echo " Padded Number is $stringMemberNo  ";
    $crn = $stringMemberNo;

    for($i=0;$i<7;$i++){
           $crnval = substr($crn,(5-$i),1);
           $iPartVal = $iWeight * $crnval;

           if($iPartVal>9){
             //echo " Greater than 9: $iPartVal ";
             $firstChar = substr($iPartVal,0,1); 
             $secondChar = substr($iPartVal,1,1);                           
             $iPartVal=$firstChar+$secondChar;
             //$iPartVal -= 9;

           }
           $iSum+=$iPartVal;

           $iWeight++;
           if ($iWeight>2){$iWeight=1;}

           //echo " CRN: $crnval ] Weight: $iWeight ] Part: $iPartVal ] SUM: $iSum ";
    }
    $iSum %= 10;

    if($iSum==0){
        //echo " zero check  is $iSum ";                    
        //return $iSum;
    }
    else{
        //return 10-$iSum;
        $iSum=(10-$iSum);
    }
    //echo " Check is a $iSum ";                                        

    $BpayMemberNo  = $stringMemberNo . $iSum ;
    echo " New: $BpayMemberNo ";
    return ($BpayMemberNo);
}
like image 1
Peter Brooks Avatar answered Oct 14 '22 16:10

Peter Brooks