Years ago I needed to test in one of my Delphi software packages if the ID that is typed is accurate.  Now I want to document my function to validate the ID. And the software in question tested thousands of ID's, and look to work.

Firstly the South African ID is made up the in following way.

Format: {YYMMDD}{G}{SSS}{C}{A}{Z}
YYMMDD : Date of birth.
G : Gender. 0-4 Female; 5-9 Male.
SSS : Sequence No. for DOB/G combination.
C : Citizenship. 0 SA; 1 Other.
A : Usually 8, or 9 [can be other values]
Z : Control digit calculated in the following section

The formula is as follows to calculate the check digit. I will use the example ID of my source website. 800101 5009 087

1. Add all the digits in the odd positions (excluding last digit).

8 + 0 + 0 + 5 + 0 + 0 = 13

2. Move the even positions into a field and multiply the number by 2.

011098 x 2 = 22196

3. Add the digits of the result in #2.

2 + 2 + 1 + 9 + 6 = 20

4. Add the answer in #1 to the answer in #3.

13 + 20 = 33

5. Subtract the second digit in #4 from 10.

10 - 3 = 7

6. If #5 comes out as 10 you must use 0.

Now for the Delphi function to validate the ID.

Firstly the loop to add all the odd positions.

      i := 1;
      oddValue := 0;
      while i < 13 do
      begin
         oddValue := oddValue + StrtoInt(copy(ID,i,1));
         i := i + 2;
      end; 

Then the loop to move the even positions into an field.

      i := 2;
      evenString := '';
      while i < 13 do
      begin
         evenString := evenString + copy(ID,i,1);
         i := i + 2;
      end; 

 Multiply the even positions loop value by 2.

evenString := InttoStr(StrtoInt(evenString) * 2);

 Now we need to add each of the characters of the even answer.

      evenValue := 0;
      for i := 1 to Length(evenString) do
      begin
         evenValue := evenValue + StrtoInt(copy(evenString,i,1));
      end; 

 Add the odd answer and the even answer together.

i := oddValue + evenValue; 

 Subtract second digit from answer from 10.

CheckDigit := 10 - strtoint(copy(InttoStr(i),2,1)); 

 If answer is 10 use zero.

      If CheckDigit > 9 then
        CheckDigit := 0;

 Finally check if the check digit is the same.

      If copy(ID,13,1) <> InttoStr(CheckDigit) then
        ValidateIDNEW := False;

Now here is the function all together.

Link to the test project code written in Lazarus at GitHub. The original old function was written in Delphi. With my own projects I am starting to convert from Delphi to Lazarus.

function TMainForm.ValidateIDNEW(ID: String): Boolean;
var
    oddValue, evenValue, i, CheckDigit: Integer;
    evenString: String;
begin
  ValidateIDNEW := True;
  If  Length(ID) = 13 then
  begin
    try
      i := 1;
      oddValue := 0;
      while i < 13 do
      begin
        // 1. Add all the digits in the odd positions (excluding last digit).
         oddValue := oddValue + StrtoInt(copy(ID,i,1));
         i := i + 2;
      end;
      i := 2;
      evenString := '';
      while i < 13 do
      begin
        // 2. Move the even positions into a field and multiply the number by 2.
         evenString := evenString + copy(ID,i,1);
         i := i + 2;
      end;
      evenString := InttoStr(StrtoInt(evenString) * 2);

      evenValue := 0;
      for i := 1 to Length(evenString) do
      begin
         // 3. Add the digits of the result in 2.
         evenValue := evenValue + StrtoInt(copy(evenString,i,1));
      end;

      // 4. Add the answer in 1. to the answer in 3.
      i := oddValue + evenValue;

      // 5. Subtract the second digit in 4. from 10.
      CheckDigit := 10 - strtoint(copy(InttoStr(i),2,1));
      If CheckDigit > 9 then
        CheckDigit := 0;
      If copy(ID,13,1) <> InttoStr(CheckDigit) then
        ValidateIDNEW := False;
    except
      ValidateIDNEW := False;
    end;
  end
  else
    ValidateIDNEW := False;
end;  

And if you wondered why I called the function new I tidied it up a bit. The function below was written long time ago when I just started, and the original version had no loops in it.

function TMainForm.ValidateID(ID: String): Boolean;
var
    i1, i2, i3, i4, i5: Integer;
    s: String;
begin
  ValidateID := True;
  If  Length(ID) = 13 then
  begin
    try
      i1 := StrtoInt(copy(ID,1,1)) + StrtoInt(copy(ID,3,1)) + StrtoInt(copy(ID,5,1)) + StrtoInt(copy(ID,7,1)) + StrtoInt(copy(ID,9,1)) + StrtoInt(copy(ID,11,1));
      i2 := StrtoInt(copy(ID,2,1) + copy(ID,4,1) + copy(ID,6,1) + copy(ID,8,1) + copy(ID,10,1) + copy(ID,12,1)) * 2;
      If Length(InttoStr(i2)) = 5 then
        s := '0' + InttoStr(i2)
      else
      begin
        If Length(InttoStr(i2)) = 4 then
          s := '00' + InttoStr(i2)
        else
        begin
          If Length(InttoStr(i2)) = 3 then
            s := '000' + InttoStr(i2)
          else
            s := InttoStr(i2);
        end;
      end;
      If Length(s) = 6 then
        i3 := StrtoInt(copy(s,1,1)) + StrtoInt(copy(s,2,1)) + StrtoInt(copy(s,3,1)) + StrtoInt(copy(s,4,1)) + StrtoInt(copy(s,5,1)) + StrtoInt(copy(s,6,1))
      else
        i3 := StrtoInt(copy(s,1,1)) + StrtoInt(copy(s,2,1)) + StrtoInt(copy(s,3,1)) + StrtoInt(copy(s,4,1)) + StrtoInt(copy(s,5,1)) + StrtoInt(copy(s,6,1)) + StrtoInt(copy(s,7,1));

      i4 := i1 + i3;
      i5 := 10 - strtoint(copy(InttoStr(i4),2,1));
      If i5 > 9 then
        i5 := 0;
      If copy(ID,13,1) <> InttoStr(i5) then
        ValidateID := False;
    except
      ValidateID := False;
    end;
  end
  else
    ValidateID := False;
end;  

 Source: http://geekswithblogs.net/willemf/archive/2005/10/30/58561.aspx