Nando @ Aria Media

( learning Clojure ColdFusion Lucee Javascript jQuery Angular CSS Linux Apache HTML5 & etc )

Check Digit Computation for Swiss Pay Slips

| Comments

I’m working on a business application that generates invoices and pay slips for a company in Switzerland. Instead of checks, the Swiss banking system uses a pay slip, and these have an account number, a reference number and of course the total which should be paid, all with check digits, similar to what is found on credit card numbers. At first I thought the check digit was generated by the Luhn algorithm, for which I could find plentiful examples, even in ColdFusion, such as Dan Vega’s post explaining how to generate credit card numbers with correct check digits. The meat of his implementation is here, which expects an array, ccnumber, with the card number in it and and cclen, which is of course arrayLen( ccnumber )

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<cfscript>
  /* the luhn Algorithm is used to create the check digit number */
  var sum = 0;
  for(j=1; j < cclen; j++) {
      var digit = ccnumber[j];
      // length of 16 for Visa|Mastercard|Discover && length of 15 for Amex
      if( (cclen == 16 && j % 2 != 0) || (cclen == 15 && j % 2 == 0) ){
          digit = digit * 2;
          if(digit > 9){
              digit = ( left(digit,1) + right(digit,1) );
          } else {
              digit = digit;
          }
      }
      sum += digit;
  }
  var check_digit = [0,9,8,7,6,5,4,3,2,1];
  ccnumber[cclen] = check_digit[(sum % 10 + 1)];
</cfscript>

I was hoping I could quickly adapt the above for my use case. However, I was disappointed to learn that Swiss pay slips use a non-standard algorithm to calculculate check digits. And genuinely disheartened when I was left staring at this explanation of the algorithm, the only one that seems to be provided by the banking sector.

Check digit computation module 10, recursive

If you study it for a few minutes, you’ll see how the check digit is calculated, using the chart provided. But it doesn’t give much of a clue what algorithm should be used to generate the check digit, except in the title, which seems to suggest it might use mod 10, recursively, if you assume that it has been translated from German incorrectly, module instead of modulo or modulus.

After a few sessions of Googling, I found an example someone wrote in Delphi that seemed to demonstate it could be tackled rather simply, with a single array representing the entire chart. Unfortunately I couldn’t grok some of the nuances of the syntax.

Then I ran across another set of examples variations of C and Visual Basic. His comment at the top of the page reads:

Haben Sie sich auch schon über die nicht sehr programmiergerechte Beschreibung in den Unterlagen der PostFinance und der Telekurs geärgert? … which my Swiss client on this project translated as “The descriptions from PostFinance and Telekurs are shit…” - not at all useful for programmers.

The VB example looked familiar enough, and after a bit of mucking around, came up with this CFML function that seems to work to generate the check digit, passing every test I’ve thown at it from the pay slips I have laying around.

1
2
3
4
5
6
7
8
9
10
11
12
<cfscript>
  public numeric function calCheckDigit( string number ) {
      var arrTable = [0,9,4,6,8,2,7,1,3,5];
      var carry = 0;
      var i = 1;
      for ( i = 1; i <= len( number ); i++ ) {
          carry = arrTable[ ( ( carry + mid( number, i, 1 ) ) % 10 ) + 1 ];
      }

      return ( 10 - carry ) % 10;
  }
 </cfscript>

If you compare the VB solution with the above, you’ll see I’m adding 1 to each calculated index value. That’s because ColdFusion arrays are 1-based rather than 0-based. If you happen to be using this example to build a similar function in another language that has 0 based arrays, remove the + 1 from line 7.

This function expects a string with consecutive numeric digits 0-9 only. It will blow up if any other characters are passed into it.

Here are some reference links for solving the more general problem of generating Swiss payment slips:

Manual ISR - Orange Inpayment Slip with reference number - the clearest explanation I’ve found regarding how the data is structured and placed on the pay slip.

Record Description Electronic services - the only information currently here is reproduced in the logic diagram above.

Comments