git-svn-id: https://192.168.0.254/svn/Proyectos.AbetoDesign_FactuGES/trunk@111 93f398dd-4eb6-7a46-baf6-13f46f578da2
453 lines
12 KiB
ObjectPascal
453 lines
12 KiB
ObjectPascal
{*******************************************************}
|
|
{ }
|
|
{ IBAN }
|
|
{ }
|
|
{ Copyright (C) 2011 Heiko Adams }
|
|
{ }
|
|
{*******************************************************}
|
|
|
|
{
|
|
The contents of this file are subject to the Mozilla Public License
|
|
Version 1.1 (the "License"); you may not use this file except in
|
|
compliance with the License. You may obtain a copy of the License at
|
|
http://www.mozilla.org/MPL/
|
|
|
|
Software distributed under the License is distributed on an "AS IS"
|
|
basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
|
License for the specific language governing rights and limitations
|
|
under the License.
|
|
|
|
The Original Code is IBAN.pas.
|
|
|
|
The Initial Developer of the Original Code is Heiko Adams <heiko.adams@gmail.com>.
|
|
|
|
Contributor(s): ______________________________________.
|
|
}
|
|
|
|
unit IBAN;
|
|
|
|
interface
|
|
|
|
uses IBANMetrics;
|
|
|
|
type
|
|
TIBAN = class
|
|
private
|
|
FAccountID: string;
|
|
FBankCode: string;
|
|
FCountry: string;
|
|
FIBAN: string;
|
|
// 20130830 Heiko Adams
|
|
FLastError: Integer;
|
|
|
|
FMetrics: TIBANMetrics;
|
|
|
|
function EncodeCountry(const aLand: string): string;
|
|
function Modulo97(const aIBAN:string):Integer;
|
|
function CheckIBAN: Boolean;
|
|
function CalcIBAN: string;
|
|
function GetLand: string;
|
|
function GetCountryFromIBAN: string;
|
|
procedure SetCountry(const aValue: string);
|
|
procedure SetIBAN(const aValue: string);
|
|
procedure FillM97Tab;
|
|
// 20130830 Heiko Adams
|
|
procedure SetErrorCode(nError: Integer);
|
|
public
|
|
// 20130830 Heiko Adams ...
|
|
// Don't use these properties because they are deprecated and will be
|
|
// removed in future versions of this class!
|
|
property Konto: string read FAccountID write FAccountID;
|
|
property BLZ: string read FBankCode write FBankCode;
|
|
property Land: string read GetLand write SetCountry;
|
|
// ... 20130830 Heiko Adams
|
|
|
|
// 20130830 Heiko Adams i18n version of german named public properties ...
|
|
property BankAccount: string read FAccountID write FAccountID;
|
|
property BankCode: string read FBankCode write FBankCode;
|
|
property Country: string read GetLand write SetCountry;
|
|
// ... 20130830 Heiko Adams
|
|
|
|
property IBAN: string read CalcIBAN write SetIBAN;
|
|
property Valid: Boolean read CheckIBAN;
|
|
// 20130830 Heiko Adams
|
|
property ErrorCode: Integer read FLastError;
|
|
|
|
function checkIBANCode(const sIban: String): boolean; deprecated;
|
|
function IsIBAN(const s:string):boolean;
|
|
|
|
// 20130830 Heiko Adams ...
|
|
function GetAccountNumberFromIBAN: string;
|
|
function GetBankCodeFromIBAN: string;
|
|
// ... 20130830 Heiko Adams
|
|
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
end;
|
|
|
|
var
|
|
m97tab:array[0..96,0..9] of byte;
|
|
|
|
implementation
|
|
|
|
uses SysUtils, Windows;
|
|
|
|
destructor TIBAN.Destroy;
|
|
begin
|
|
ZeroMemory(@FMetrics, SizeOf(FMetrics));
|
|
inherited;
|
|
end;
|
|
|
|
constructor TIBAN.Create;
|
|
begin
|
|
inherited;
|
|
// 20130830 Heiko Adams
|
|
SetErrorCode(0);
|
|
FillM97Tab;
|
|
end;
|
|
|
|
procedure TIBAN.SetErrorCode(nError: Integer);
|
|
begin
|
|
FLastError := nError;
|
|
end;
|
|
|
|
function TIBAN.GetAccountNumberFromIBAN: string;
|
|
begin
|
|
Result := EmptyStr;
|
|
// 20130830 Heiko Adams
|
|
SetErrorCode(0);
|
|
|
|
if {(Assigned(FMetrics)) and} (trim(FIBAN) <> EmptyStr) then
|
|
Result := Copy(FIBAN, FMetrics.nStartKTO, FMetrics.nLenKTO)
|
|
// 20130830 Heiko Adams ...
|
|
else
|
|
SetErrorCode(-180);
|
|
// ... 20130830 Heiko Adams
|
|
end;
|
|
|
|
function TIBAN.GetBankCodeFromIBAN: string;
|
|
begin
|
|
Result := EmptyStr;
|
|
// 20130830 Heiko Adams
|
|
SetErrorCode(0);
|
|
|
|
if {Assigned(FMetrics) and} (trim(FIBAN) <> EmptyStr) then
|
|
Result := Copy(FIBAN, FMetrics.nStartBLZ, FMetrics.nLenBLZ)
|
|
// 20130830 Heiko Adams ...
|
|
else
|
|
SetErrorCode(-190);
|
|
// ... 20130830 Heiko Adams
|
|
end;
|
|
|
|
procedure TIBAN.SetCountry(const aValue: string);
|
|
begin
|
|
// 20130830 Heiko Adams
|
|
SetErrorCode(0);
|
|
FCountry := Trim(UpperCase(Copy(aValue, 1, 2)));
|
|
|
|
if (Length(FCountry) < 2) then
|
|
// 20130830 Heiko Adams
|
|
//raise Exception.CreateFmt('Invalid country code: %s', [aValue]);
|
|
SetErrorCode(-100);
|
|
|
|
ZeroMemory(@FMetrics, SizeOf(FMetrics));
|
|
FMetrics := GetIBANMetrics(FCountry);
|
|
|
|
//20130901 Heiko Adams
|
|
SetErrorCode(FMetrics.nErrorCode);
|
|
end;
|
|
|
|
function TIBAN.GetCountryFromIBAN: string;
|
|
begin
|
|
// 20130830 Heiko Adams
|
|
SetErrorCode(0);
|
|
|
|
if (Trim(FIBAN) = EmptyStr) then
|
|
// 20130830 Heiko Adams
|
|
//raise Exception.Create('IBAN not set');
|
|
SetErrorCode(-110);
|
|
|
|
Result := Copy(FIBAN, 1, 2);
|
|
end;
|
|
|
|
procedure TIBAN.SetIBAN(const aValue: string);
|
|
begin
|
|
// 20130830 Heiko Adams
|
|
SetErrorCode(0);
|
|
|
|
if (Trim(aValue) = EmptyStr) then
|
|
// 20130830 Heiko Adams
|
|
//raise Exception.Create('No IBAN submitted');
|
|
SetErrorCode(-120);
|
|
|
|
FIBAN := aValue;
|
|
SetCountry(GetCountryFromIBAN);
|
|
end;
|
|
|
|
function TIBAN.GetLand: string;
|
|
begin
|
|
// 20130830 Heiko Adams
|
|
SetErrorCode(0);
|
|
Result := EmptyStr;
|
|
|
|
if not (FCountry = EmptyStr) then
|
|
Result := FCountry
|
|
else if not (FIBAN = EmptyStr) then
|
|
Result := GetCountryFromIBAN
|
|
else
|
|
// 20130830 Heiko Adams
|
|
//raise Exception.Create('No country or IBAN set');
|
|
SetErrorCode(-130);
|
|
end;
|
|
|
|
// Original code by shima (http://www.delphipraxis.net/1061658-post6.html)
|
|
function TIBAN.Modulo97(const aIBAN:string):Integer;
|
|
const
|
|
m36:string = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
|
var
|
|
nCounter, nPruef : Integer;
|
|
begin
|
|
// 20130830 Heiko Adams
|
|
SetErrorCode(0);
|
|
Result := 0;
|
|
|
|
for nCounter := 1 to Length(aIBAN) do
|
|
begin
|
|
nPruef := Pos(aIBAN[nCounter], m36) ;
|
|
|
|
if (nPruef = 0) then
|
|
// 20130830 Heiko Adams
|
|
//raise Exception.CreateFmt('Modulo97PruefZiffer(%s): invalid data', [aIBAN]);
|
|
SetErrorCode(-140);
|
|
|
|
Dec(nPruef);
|
|
|
|
if (nPruef > 9) then
|
|
begin
|
|
Result := Result * 10 + (nPruef div 10);
|
|
nPruef := nPruef mod 10;
|
|
end;
|
|
|
|
Result := Result * 10 + nPruef;
|
|
Result := Result mod 97;
|
|
end;
|
|
end;
|
|
|
|
// Code beigesteuert von Amateurprofi (http://www.delphipraxis.net/159320-iban-ueberpruefen.html#post1154665)
|
|
procedure TIBAN.FillM97Tab;
|
|
var
|
|
i,j:Integer;
|
|
begin
|
|
for i:=0 to 96 do
|
|
for j:=0 to 9 do
|
|
m97tab[i,j]:=(i*10+j) Mod 97;
|
|
end;
|
|
|
|
function TIBAN.EncodeCountry(const aLand: string): string;
|
|
var
|
|
sLetter: Char;
|
|
begin
|
|
// 20130830 Heiko Adams
|
|
SetErrorCode(0);
|
|
|
|
if (Length(Trim(aLand)) <> 2) then
|
|
SetErrorCode(-100);
|
|
// 20130830 Heiko Adams
|
|
//raise Exception.CreateFmt('Invalid country code: %s', [aLand]);
|
|
|
|
for sLetter in aLand do
|
|
case sLetter of
|
|
'A': Result := Result + '10';
|
|
'B': Result := Result + '11';
|
|
'C': Result := Result + '12';
|
|
'D': Result := Result + '13';
|
|
'E': Result := Result + '14';
|
|
'F': Result := Result + '15';
|
|
'G': Result := Result + '16';
|
|
'H': Result := Result + '17';
|
|
'I': Result := Result + '18';
|
|
'J': Result := Result + '19';
|
|
'K': Result := Result + '20';
|
|
'L': Result := Result + '21';
|
|
'M': Result := Result + '22';
|
|
'N': Result := Result + '23';
|
|
'O': Result := Result + '24';
|
|
'P': Result := Result + '25';
|
|
'Q': Result := Result + '26';
|
|
'R': Result := Result + '27';
|
|
'S': Result := Result + '28';
|
|
'T': Result := Result + '29';
|
|
'U': Result := Result + '30';
|
|
'V': Result := Result + '31';
|
|
'W': Result := Result + '32';
|
|
'X': Result := Result + '33';
|
|
'Y': Result := Result + '34';
|
|
'Z': Result := Result + '35';
|
|
else
|
|
// 20130830 Heiko Adams
|
|
//raise Exception.CreateFmt('Invalid country code: %s', [aLand]);
|
|
SetErrorCode(-100);
|
|
end;
|
|
end;
|
|
|
|
function TIBAN.CheckIBAN(): Boolean;
|
|
var
|
|
sBLZ: string;
|
|
sKTO: string;
|
|
sIBAN: string;
|
|
sLand: string;
|
|
sControl: string;
|
|
begin
|
|
// 20130830 Heiko Adams
|
|
SetErrorCode(0);
|
|
Result := (Length(FIBAN) = FMetrics.nLenIBAN);
|
|
|
|
if Result then
|
|
begin
|
|
sControl := Copy(FIBAN, 3, 2);
|
|
sBLZ := Copy(FIBAN, FMetrics.nStartBLZ, FMetrics.nLenBLZ);
|
|
sKTO := Copy(FIBAN, FMetrics.nStartKTO, FMetrics.nLenKTO);
|
|
sLand := EncodeCountry(GetCountryFromIBAN);
|
|
sIBAN := sBLZ + sKTO + sLand + sControl;
|
|
Result := (Modulo97(sIBAN) = 1);
|
|
end
|
|
// 20130830 Heiko Adams ...
|
|
else
|
|
SetErrorCode(-150);
|
|
// ... 20130830 Heiko Adams
|
|
end;
|
|
|
|
function TIBAN.CalcIBAN(): string;
|
|
var
|
|
sKTO: string;
|
|
sIBAN: string;
|
|
nControl: Integer;
|
|
sControl: string;
|
|
const
|
|
sSuffix = '00';
|
|
nControlBase = 98;
|
|
begin
|
|
sKTO := StringOfChar('0', FMetrics.nLenKTO - Length(FAccountID)) + FAccountID;
|
|
sIBAN := FBankCode + sKTO + EncodeCountry(FCountry)+ sSuffix;
|
|
nControl := Modulo97(sIBAN);
|
|
nControl := nControlBase - nControl;
|
|
|
|
// 20120224 Heiko Adams
|
|
// make shure controlnumber has allways two characters
|
|
// thanks to Henry van der Mark for this hint
|
|
//FIBAN := FLand + IntToStr(nControl) + FBLZ + sKTO;
|
|
sControl := IntToStr(nControl);
|
|
|
|
if (nControl < 10) then
|
|
sControl := '0' + sControl;
|
|
|
|
FIBAN := FCountry + sControl + FBankCode + sKTO;
|
|
|
|
Result := FIBAN;
|
|
end;
|
|
|
|
// Prüfung einer IBAN auf formale Korrektheit (ohne Prüfung der Gültigkeit des Länderkürzels)
|
|
// Autor: Dr. Michael Schramm, Bordesholm
|
|
function TIBAN.checkIBANCode(const sIban: String): boolean;
|
|
var k,i,n,len: integer; c: char;
|
|
buff: array[0..67] of char;
|
|
begin
|
|
result:= false;
|
|
n:= length(sIban);
|
|
|
|
if (n < 5) or (n > 34) then
|
|
exit;
|
|
|
|
len:= 0;
|
|
k:= 5;
|
|
|
|
repeat // IBAN als Ziffernfolge in geänderter Reihenfolge in buff schreiben
|
|
c:= sIban[k];
|
|
|
|
if (c >= '0') and (c <= '9') then
|
|
begin
|
|
buff[len]:= c;
|
|
inc(len)
|
|
end
|
|
else if (c >= 'A') and (c <= 'Z') then
|
|
begin
|
|
i:= ord(c)-55;
|
|
buff[len]:= char(i div 10 + 48);
|
|
inc(len);
|
|
buff[len]:= char(i mod 10 + 48);
|
|
inc(len);
|
|
end
|
|
else
|
|
exit;
|
|
|
|
inc(k);
|
|
|
|
if (k > n) then
|
|
k:= 1
|
|
until k = 5;
|
|
|
|
i:= 0; // aktueller Rest für Modulo-Berechnung
|
|
|
|
for k:= 0 to len-1 do
|
|
begin // modulo 97 berechnen
|
|
i:= (i * 10 + ord(buff[k]) - 48) mod 97;
|
|
end;
|
|
|
|
result:= (i = 1)
|
|
end;
|
|
|
|
// Code beigesteuert von Amateurprofi (http://www.delphipraxis.net/159320-iban-ueberpruefen.html#post1154665)
|
|
function TIBAN.IsIBAN(const s:string):boolean;
|
|
var
|
|
len: integer;
|
|
cs: byte;
|
|
function GetCheckSum(first,last:integer):boolean;
|
|
var
|
|
i: integer;
|
|
c: integer;
|
|
begin
|
|
for i:=first to last do
|
|
begin
|
|
c:=Ord(s[i])-48;
|
|
|
|
case c of
|
|
0..9 : cs:=m97tab[cs,c];
|
|
17..42 : cs:=m97tab[m97tab[cs,(c-7) Div 10],(c-7) Mod 10];
|
|
else
|
|
Exit;
|
|
end;
|
|
end;
|
|
result:=true;
|
|
end;
|
|
begin
|
|
// 20130830 Heiko Adams
|
|
SetErrorCode(0);
|
|
len:=Length(s);
|
|
|
|
if (len<5) or (len>34) then
|
|
begin
|
|
// 20130830 Heiko Adams
|
|
SetErrorCode(-160);
|
|
Exit;
|
|
end;
|
|
|
|
cs:=0;
|
|
|
|
if not GetCheckSum(5,len) then
|
|
begin
|
|
// 20130830 Heiko Adams
|
|
SetErrorCode(-170);
|
|
Exit;
|
|
end;
|
|
|
|
if not GetCheckSum(1,4) then
|
|
begin
|
|
// 20130830 Heiko Adams
|
|
SetErrorCode(-170);
|
|
Exit;
|
|
end;
|
|
|
|
Result := (cs=1);
|
|
end;
|
|
|
|
end.
|