(Példa egy IBAN felépítésre, ahol igazából a ‘check digits’ rész az érdekes, azt ezt követő BBAN változó hosszúságú lehet, from: www.jknc.eu/ibanbic)
Egy ideje napi szinten dolgozom IBAN azonosítókkal, főleg első körös IT tesztek kapcsán, így szükségessé vált néhány, ezt támogató programocska is.
Maga az IBAN egy igen fontos azonosító a nemzetközi gyakorlatban, mert ennek hiányában elég problémás lenne a nemzetközi utalás, pl. a különböző nemzeti számlaformátumok miatt (BBAN: Basic Bank Account Number).
Az IBAN egy nemzetközi bankszámlaszám (angolul: International Bank Account Number). Egy kétbetűs országkódból, egy kétjegyű ellenőrző kódból és az adott országban szabvány karakterszámú bankszámlaszámból áll.
A magyarországi IBAN számlaszámok egységesen a HU karakterekkel kezdődnek, ezt követi a kétjegyű ellenőrző kód és a magyar szabvány szerinti 24 karakterű számlaszám.
(from: www.erstebank.hu/hu/tudastar/vallalatok/mindennapi-bankolas/fizetese-megoldasok/atutalasok-es-beszedesek/mi-az-iban)
IBAN képzés szabályai és annak használat az ISO 13616-1:2007 (Financial services – International bank account number (IBAN) — Part 1: Structure of the IBAN) szabványban szerepel. A ugyan dokumentum fizetős, de az esetek 95%-ában bőven elegendő az on-line fellelhető ismeretanyag is a használatához (itt bele lehet lapozni a szabványba is, illetve látható annak „tartalomjegyzéke”).
A lényeg az alábbi:
The IBAN consists of up to 34 alphanumeric characters, as follows:
– country code using ISO 3166-1 alpha-2 – two letters,
– check digits – two digits, and
– Basic Bank Account Number (BBAN) – up to 30 alphanumeric characters that are country-specific.
(from: en.wikipedia.org/wiki/International_Bank_Account_Number)
A nemzeti számlák struktúrája pedig pl. itt megtekinthető.
Gyakran írok ilyen kis tool-okat, mert az esetek többségében már középtávon bőven megtérülnek… Sajnos a legtöbbször nem mentem őket igazából sehova sem, így néha el-el vesznek, ami azért sajnálatos. Ezen próbálok változtatni, pl. jelen bejegyzéssel is…
Egyrészt az oldalon már elérhető egy standard, magyar, 3×8 számból álló bankszámlaszámból IBAN számot előállító „alkalmazás”, amit ha lesz némi időm akkor tovább is fejlesztek, IBAN validátorral és nemcsak magyar számlaszámok támogatásával. Bár ez utóbbi kicsit nagyobb falat a sok eltérő BBAN, pontosabban ezek megfelelő validálása miatt. A kizárólag magyar számlaszámok támogatására optimalizált, nagyon leegyszerűsített IBAN algoritmus is generalizálandó, ami elvileg nem egy nagy feladat, de ettől még számos hibalehetőséget hordoz :).
A magyar IBAN előállítása valójában cca. 7 sor Javascript-ben és nagyjából 5 PL/SQL-ben, hiszen az egyetlen kritikus pont a checksum kiszámolása. Az algoritmus kicsit trükkös, mert a BBAN módosított formában használandó, de a lényeg, hogy a végére kell kerüljön a ‘173000’ (ami egyébként a ‘HU00’ átírásából adódik H=17, U=30, részletek itt). Ez pl. az alábbi módon történhet:
1 2 3 4 5 6 7 8 9 |
var checksum = 98 - mod97(normGiroToProc.toString() + '173000'); function mod97(szlaNum) { var m = 0; for (var i = 0; i < szlaNum.length; ++i) { m = ((m * 10) + parseInt(szlaNum.charAt(i), 10)) % 97; } return m; } |
Számomra legérdekesebb rész nem is az IBAN algoritmusa, sokkal inkább a „pad” funkció hiánya volt JS oldalon, mert egy fontos lépés, hogy ha a checksum egy számjegyű, akkor egy vezető nullát is hozzá kell írni. Én valamiért úgy emlékeztem, hogy van ilyen… Szerencsére az Internet megoldotta ezt nekem egy, a maga nemében elegáns függvénnyel:
1 2 3 4 5 6 |
function padIt(toPad) { var str = toPad.toString(); var pad = "00"; var padded = pad.substring(0, pad.length - str.length) + str; return padded; } |
UPDATE: jól tudtam, van: String.padStart(), de most már mindegy… Viszont működése egyszerűen ellenőrizhető bármely böngésző konzolján:
>> tmp=’teszt’
<- „teszt”
>> tmp.padStart(10,’0′)
<- „00000teszt”
(from: Firefox/Konzol teszt)
Másrészt szükségem volt Oracle oldalon egy kifejezetten magyar IBAN validátorra, ami szintén nem bonyolult, a Wikipedia vonatkozó leírása is bőven egyszerűsíthető, ha csak a magyar IBAN validálása a cél.
Ennek megfelelően a PL/SQL blokk (minimális hibakezeléssel):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
SET SERVEROUTPUT ON accept x char prompt 'Ellenőrizni kívánt IBAN: ' DECLARE p_iban VARCHAR2(34)/*:='hu56167200130430014045821008'*/; chs VARCHAR2(34); l_sub1 VARCHAR2(34); alphabet varchar(40):='ABCDEFGHIJKLMNOPQRSTUVWXYZ'; res int; BEGIN p_iban := '&x'; if (upper(SUBSTR(p_iban,0,2))!='HU') OR (p_iban is NULL) then res:=NULL; raise_application_error( -20200, 'IBAN not starts with HU prefix. Please check!' ); else l_sub1:= SUBSTR(p_iban,5); chs:=mod(l_sub1||(9+INSTR(alphabet, upper(SUBSTR(p_iban,0,1))))||(9+INSTR(alphabet, upper(SUBSTR(p_iban,2,1))))||SUBSTR(p_iban,3,2),97); if chs = 1 THEN res:=1; else res:=0; end if; DBMS_OUTPUT.PUT_LINE('---'); DBMS_OUTPUT.PUT_LINE(res); end if; END ; / |
Illetve a már tetszőlegesen hívható funkció:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
create or replace FUNCTION hu_iban_check (p_iban IN VARCHAR2) RETURN int AS chs VARCHAR2(34); l_sub1 VARCHAR2(34); alphabet VARCHAR(40):='ABCDEFGHIJKLMNOPQRSTUVWXYZ'; res INT; BEGIN IF UPPER(SUBSTR(p_iban,0,2))!='HU' OR (p_iban is NULL) THEN raise_application_error(-20001, 'IBAN not starts with HU prefix. Please check!'); res:=NULL; ELSE l_sub1:= SUBSTR(p_iban,5); chs:=mod(l_sub1||(9+INSTR(alphabet, UPPER(SUBSTR(p_iban,0,1))))||(9+INSTR(alphabet, UPPER(SUBSTR(p_iban,2,1))))||SUBSTR(p_iban,3,2),97); if chs = 1 THEN res:=1; ELSE res:=0; END IF; RETURN res; END IF; END hu_iban_check ; /* --Ellenőrzéshez: SELECT 'hu56167200130430014045821008' ,decode(hu_iban_check('hu56167200130430014045821008'),1,'OK',0,'NOK') AS "VALID_IBAN-E?" FROM dual; */ |
UPDATE: Oracle IBAN generátor, két eltérő megvalósítással:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
DECLARE ACCOUNTNUMBER VARCHAR2(24); -- function esetén ez lesz a bejövő adat CHECKSUM INTEGER; IBAN_MOD VARCHAR2(34); IBAN_JS VARCHAR2(34); HU_DEFAULT VARCHAR2(6):='173000'; -- H:17 U:30, blank checksum:00 M NUMBER :=0; BEGIN ACCOUNTNUMBER := '117734010156613200000000'; -- teszthez -- JS átirat FOR I IN 1 .. LENGTH(ACCOUNTNUMBER||HU_DEFAULT) LOOP M:=MOD((M*10)+TO_NUMBER(SUBSTR(ACCOUNTNUMBER||HU_DEFAULT,I,1)),97); END LOOP; --ORACLE MOD() közvetlen megoldás CHECKSUM := 98 - MOD(ACCOUNTNUMBER||HU_DEFAULT,97); IBAN_MOD := 'HU'||lpad(CHECKSUM,2,0)||' '||ACCOUNTNUMBER; IBAN_JS := 'HU'||lpad(TO_NUMBER(98-M),2,0||' '||ACCOUNTNUMBER; DBMS_OUTPUT.PUT_LINE(CHECKSUM); DBMS_OUTPUT.PUT_LINE(IBAN_MOD); DBMS_OUTPUT.PUT_LINE(98-M); DBMS_OUTPUT.PUT_LINE(IBAN_JS); END; |
Klassz cikk, nagyon hasznos volt!
A javascript checksum generáló eljáráshoz lenne annyi gondolatom, hogy a cikkbeli függvény rövidíthető a kicsit haladóbb Array szintaxissal így:
return szlaNum.split(”).reduce((accumulator, currentValue) => ((accumulator*10) + parseInt(currentValue, 10)) % 97);