Skip to content

Commit 31cf351

Browse files
committed
Pankkiviivakoodi, 2025
1 parent 1b03df9 commit 31cf351

2 files changed

Lines changed: 197 additions & 0 deletions

File tree

pankkiviivakoodi/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Pankkiviivakoodi
2+
3+
https://Metabolix.github.io/random-programming-examples/pankkiviivakoodi/

pankkiviivakoodi/index.html

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1" />
6+
<title>Pankkiviivakoodi</title>
7+
<script>
8+
function tarkasta_kerroin_137(num) {
9+
return num.match(/./g).reverse().reduce((a, b, i) => a + ((+b) * [1, 7, 3][i % 3]), 0) % 10 == 0;
10+
}
11+
12+
function tarkasta_mod_97_10(num) {
13+
return BigInt(num.substr(4) + num.substr(0, 4).replace(/[A-Z]/g, c => c.charCodeAt(0) - 55)) % 97n == 1n;
14+
}
15+
16+
function tarkista_tilinumero(tili) {
17+
let tiliStr = tili.toUpperCase().replace(/\s/g, "");
18+
if (!tiliStr.match(/^[ABCDEFGHIJKLMNOPQRSTUVWXYZ]{2}[0123456789]{16}$/)) {
19+
throw new Error("Tilinumero ei ole IBAN-muotoinen");
20+
}
21+
if (!tarkasta_mod_97_10(tiliStr)) {
22+
throw new Error("Tilinumero ei ole kelvollinen (väärä tarkistusluku)");
23+
}
24+
if (!tiliStr.startsWith("FI")) {
25+
throw new Error("Tilinumero ei ole suomalainen");
26+
}
27+
return tiliStr.substr(2);
28+
}
29+
30+
function tarkista_summa(summa) {
31+
let summaArr = summa.replace(/\s|'/g, "").replace(/,/g, ".").split(".");
32+
if (summaArr.length > 2) {
33+
throw new Error("Summassa voi olla vain yksi desimaalierotin");
34+
}
35+
let e = (summaArr[0] || "0").replace(/^\+?0*/, "").padStart(6, "0");
36+
let c = (summaArr[1] || "0").replace(/0*$/, "").padEnd(2, "0");
37+
let summaStr = e + c;
38+
if (summaStr.match(/[^0123456789]/)) {
39+
throw new Error("Summassa voi olla vain numeroita");
40+
}
41+
if (e.length > 6) {
42+
throw new Error("Summa voi olla enintään 999999,99 euroa");
43+
}
44+
if (c.length > 2) {
45+
throw new Error("Summassa voi olla korkeintaan kaksi desimaalia");
46+
}
47+
return summaStr;
48+
}
49+
50+
function tarkista_viite(viite) {
51+
let viiteStr = viite.toUpperCase().replace(/\s/g, "") || "0";
52+
if (!viiteStr.match(/^RF[0123456789]{2}/)) {
53+
if (!viiteStr.match(/^[0123456789]{1,20}$/g)) {
54+
throw new Error("Viitenumeron tulee olla suomalainen tai RF-viite");
55+
}
56+
if (!tarkasta_kerroin_137(viiteStr)) {
57+
throw new Error("Viitenumeron tarkistusluku on väärä");
58+
}
59+
return viiteStr.padStart(23, "0");
60+
}
61+
if (!viiteStr.match(/^RF[0123456789]{2,23}$/g)) {
62+
throw new Error("Viivakoodin RF-viitteessä tulee olla 2–23 numeroa");
63+
}
64+
if (!tarkasta_mod_97_10(viiteStr)) {
65+
throw new Error("RF-viitteen tarkistusluku on väärä");
66+
}
67+
return viiteStr.substr(2, 2) + viiteStr.substr(4).padStart(21, "0");
68+
}
69+
70+
function tarkista_erapaiva(erapaiva) {
71+
let m = erapaiva.match(/^\d\d(\d\d)-(\d\d)-(\d\d)$/);
72+
let erapaivaStr = m ? m[1] + m[2] + m[3] : "";
73+
if (erapaivaStr.length != 6) {
74+
throw new Error("Eräpäivä on väärän muotoinen, syötä päivämäärä muodossa YYYY-MM-DD");
75+
}
76+
return erapaivaStr;
77+
}
78+
79+
function encode_Code_128C(s) {
80+
if (!s.match(/^([0-9][0-9])+$/)) {
81+
throw new Error("Viivakoodin tulee sisältää parillinen määrä numeroita");
82+
}
83+
let symbols = [105, ...s.match(/\d\d/g).map(c => parseInt(c))];
84+
let checksum = symbols.reduce((a, b, i) => a + b * (i || 1), 0) % 103;
85+
symbols.push(checksum);
86+
symbols.push(106);
87+
const widths = [212222, 222122, 222221, 121223, 121322, 131222, 122213, 122312, 132212, 221213, 221312, 231212, 112232, 122132, 122231, 113222, 123122, 123221, 223211, 221132, 221231, 213212, 223112, 312131, 311222, 321122, 321221, 312212, 322112, 322211, 212123, 212321, 232121, 111323, 131123, 131321, 112313, 132113, 132311, 211313, 231113, 231311, 112133, 112331, 132131, 113123, 113321, 133121, 313121, 211331, 231131, 213113, 213311, 213131, 311123, 311321, 331121, 312113, 312311, 332111, 314111, 221411, 431111, 111224, 111422, 121124, 121421, 141122, 141221, 112214, 112412, 122114, 122411, 142112, 142211, 241211, 221114, 413111, 241112, 134111, 111242, 121142, 121241, 114212, 124112, 124211, 411212, 421112, 421211, 212141, 214121, 412121, 111143, 111341, 131141, 114113, 114311, 411113, 411311, 113141, 114131, 311141, 411131, 211412, 211214, 211232, 2331112];
88+
return symbols.map(s => "" + widths[s]).join("");
89+
}
90+
91+
document.addEventListener("DOMContentLoaded", function() {
92+
let form = document.querySelector("form");
93+
let tilinumero = document.getElementById("tilinumero");
94+
let viite = document.getElementById("viite");
95+
let summa = document.getElementById("summa");
96+
let erapaiva = document.getElementById("erapaiva");
97+
let tiedot = document.getElementById("tiedot");
98+
let viivakoodiTxt = document.getElementById("viivakoodi-txt");
99+
let viivakoodiSvg = document.getElementById("viivakoodi-svg");
100+
101+
if (!erapaiva.value) {
102+
erapaiva.value = new Date().toISOString().slice(0, 10);
103+
}
104+
105+
function tee_viivakoodi() {
106+
tiedot.textContent = "";
107+
viivakoodiTxt.textContent = "";
108+
viivakoodiSvg.innerHTML = "";
109+
110+
function tarkista(input, funktio) {
111+
let e;
112+
try {
113+
input.setCustomValidity("");
114+
return funktio(input.value);
115+
} catch (e) {
116+
input.setCustomValidity(e.message);
117+
tiedot.textContent += e.message + "\n";
118+
}
119+
}
120+
121+
let koodi = [
122+
viite.value.match(/RF/) ? "5" : "4",
123+
tarkista(tilinumero, tarkista_tilinumero),
124+
tarkista(summa, tarkista_summa),
125+
tarkista(viite, tarkista_viite),
126+
tarkista(erapaiva, tarkista_erapaiva),
127+
].join("");
128+
129+
if (!koodi.match(/^[0-9]{54}$/)) {
130+
return;
131+
}
132+
133+
let purku = koodi.replace(/([45])(\d{16})(\d{8})(\d{23})(\d{6})/, (_, versio, tilinumero, summa, viite, erapaiva) => {
134+
tilinumero = "FI" + tilinumero;
135+
summa = summa.replace(/0*(\d+)(\d{2})/, "$1,$2");
136+
viite_rf = "RF" + viite.substr(0, 2) + viite.substr(2).replace(/^0*/, "");
137+
viite_fi = viite.replace(/^0*/, "");
138+
viite = versio == 4 ? viite_fi : viite_rf;
139+
cc = new Date().getFullYear() / 100 | 0;
140+
erapaiva = erapaiva.replace(/(\d{2})(\d{2})(\d{2})/, cc + "$1-$2-$3");
141+
return `Tili: ${tilinumero}\nSumma: ${summa} euroa\nViite: ${viite}\nEräpäivä: ${erapaiva}`;
142+
});
143+
144+
tiedot.textContent = purku;
145+
viivakoodiTxt.textContent = koodi;
146+
147+
let w = 0, h = 40;
148+
let svg = encode_Code_128C(koodi).match(/[0-9]/g).map((bar_width, i) => {
149+
let x = w;
150+
w += +bar_width;
151+
return (i % 2) ? "" : `<rect x='${x}' y='0' width='${bar_width}' height='${h}' fill='black'/>\n`;
152+
}).join("");
153+
154+
viivakoodiSvg.innerHTML = `
155+
<svg
156+
xmlns="http://www.w3.org/2000/svg"
157+
viewBox="0 0 ${w} ${h}"
158+
style='margin: 1em 0 1em; min-width: ${w}px; width: 40em; max-width: 100%;'
159+
>
160+
${svg}
161+
</svg>
162+
`;
163+
}
164+
165+
tilinumero.addEventListener("input", tee_viivakoodi);
166+
viite.addEventListener("input", tee_viivakoodi);
167+
summa.addEventListener("input", tee_viivakoodi);
168+
erapaiva.addEventListener("input", tee_viivakoodi);
169+
tee_viivakoodi();
170+
});
171+
</script>
172+
</head>
173+
<body>
174+
<h1>Pankkiviivakoodi</h1>
175+
<form>
176+
<dl>
177+
<dt>Saajan tilinumero</dt>
178+
<dd><input type="text" id="tilinumero" required /></dd>
179+
<dt>Viite</dt>
180+
<dd><input type="text" id="viite" /></dd>
181+
<dt>Summa</dt>
182+
<dd><input type="text" id="summa" /></dd>
183+
<dt>Eräpäivä</dt>
184+
<dd><input type="date" id="erapaiva" /></dd>
185+
</dl>
186+
</form>
187+
<dl>
188+
<dt>Tulos</dt>
189+
<dd id="tiedot" style="white-space: pre-wrap; margin-bottom: 1em;"></dd>
190+
<dd id="viivakoodi-txt" style="margin-bottom: 1em;"></dd>
191+
<dd id="viivakoodi-svg"></dd>
192+
</dl>
193+
</body>
194+
</html>

0 commit comments

Comments
 (0)