Files
upn-qr/src/views/index.ejs
2022-01-19 00:14:22 +00:00

312 lines
15 KiB
Plaintext

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>UPN-QR | Open generator for UPN QR codes</title>
<link rel="stylesheet" href="/public/style.css">
</head>
<style>
section div {
padding-left: 25px;
display: grid;
}
.credits {
display: grid;
align-items: center;
justify-content: center;
text-align: center;
}
.maker {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
row-gap: .5rem;
column-gap: .5rem;
}
.maker > div:nth-last-child(1) { grid-column-end: -1; }
.maker > div:nth-last-child(2) { grid-column-end: -2; }
</style>
<body>
<section>
<h1>About</h1>
<p>
This API was developed for personal use, but modified and later released for public use.
It is an unofficial application with the sole purpose of simplifying QR code generation for universal payment ordes (<a href="https://upn-qr.si">https://upn-qr.si</a>).
The application does not keep any long-term logs.
</p>
</section>
<section>
<h1>Terms of usage</h1>
<p>Because The Bank Association in Slovenia <a href="https://www.gov.si/zbirke/storitve/vkljucitev-v-izdajanje-upn-s-kodo-qr/" target="_blank">prohibits</a> the printing and use of UPN-QR codes on bills by any unapthorized party, you must be <a href="https://www.upn-qr.si/sl/registracija-izdajatelja">authorized</a> in order to use this application to generate a QR code and print it on a bill. You can use it to create QR codes and send them in a digital form</p>
</section>
<section>
<h1 id="maker"><a href="#maker">&#128279;</a> Form maker</h1>
<span>Fill in the fields with static information and leave empty the ones that the user has to fill out.</span>
<form action="/form" method="get" class="maker">
<div>
<label for="title">Form title</label>
<input type="text" placeholder="First half of the bike" name="title">
</div>
<div>
<label for="client-name">Client name</label>
<input type="text" placeholder="Peter Novak" name="client-name">
</div>
<div>
<label for="client-address">Client address</label>
<input type="text" placeholder="Ravna ulica 13 a" name="client-address">
</div>
<div>
<label for="client-city">Client city</label>
<input type="text" placeholder="1000 Ljubljana" name="client-city">
</div>
<div>
<label for="amount">Amount</label>
<input type="number" placeholder="00000001132" min="0" max="99999999999" name="amount">
</div>
<div>
<label for="code">Purpose code</label>
<input type="text" placeholder="OTHR" name="code">
</div>
<div>
<label for="purpose">Payment purpose</label>
<input type="text" placeholder="moutain bike first half" name="purpose">
</div>
<div>
<label for="iban">IBAN</label>
<input type="text" placeholder="SI56047500000280672" name="iban">
</div>
<div>
<label for="reference">Reference</label>
<input type="text" placeholder="SI121234567890120" name="reference">
</div>
<div>
<label for="issuer-name">Issuer name</label>
<input type="text" placeholder="Spletne strani na 123" name="issuer-name">
</div>
<div>
<label for="issuer-address">Issuer address</label>
<input type="text" placeholder="Za deveto smreko 15 k" name="issuer-address">
</div>
<div>
<label for="issuer-city">Issuer city</label>
<input type="text" placeholder="1000 Ljubljana" name="issuer-city">
</div>
<div>
<button id="copyurl" type="button">Copy image URL</button>
</div>
<div>
<input type="submit" value="Create form">
</div>
</div>
</section>
<script>
function val (name) { return document.getElementsByName(name)?.[0]?.value || "" }
function getNewUrl () {
const qstring = [
["client_name", val("client-name")],
["client_address", val("client-address")],
["client_city", val("client-city")],
["amount", val("amount").padStart(11, "0")],
["purpose_code", val("code")],
["payment_purpose", val("purpose")],
["iban", val("iban")],
["reference", val("reference")],
["issuer_name", val("issuer-name")],
["issuer_address", val("issuer-address")],
["issuer_city", val("issuer-city")],
].map(v => `${v[0]}=${v[1]}`).join("&")
return `${window.location.origin}/api/qrcode?${qstring}`
}
const copyBtn = document.getElementById("copyurl")
copyBtn.addEventListener("click", () => copyUrl())
function copyUrl () {
try {
const dummy = document.createElement('input')
document.body.appendChild(dummy)
dummy.value = getNewUrl()
dummy.select()
document.execCommand('copy')
document.body.removeChild(dummy)
copyBtn.innerText = "Copied!"
copyBtn.classList.add("success")
setTimeout(() => {
copyBtn.innerText = "Copy image URL"
copyBtn.classList.remove("success")
}, 750)
} catch (error) {
console.error(error)
copyBtn.innerText = "Failed!"
copyBtn.classList.add("error")
setTimeout(() => {
copyBtn.innerText = "Copy image URL"
copyBtn.classList.remove("error")
}, 750)
}
}
</script>
<section>
<h1 id="api"><a href="#api">&#128279;</a> API</h1>
<h4 id="api-qrcode"><a href="#api-qrcode">&#128279;</a> <code>GET /api/qrcode</code></h4>
<div>
<span>Returns a <code>image/png</code> image if successful (OK 200), else returns the following JSON <code>{ ok: false, errors: String[] }</code> where <code>errors</code> is an array of descriptive strings.</span>
<br>
<pre>
&#x3C;!-- Meant to be used as direct image source, for example --&#x3E;
&#x3C;img src="https://upn-qr.gitapp.si/api/qrcode?client_name=Šolski center Nova Gorica&client_address=Cankarjeva ulica 8a&client_city=5000 Nova Gorica&amount=00000001000&payment_purpose=placilo&iban=SI56020170014356205&reference=SI121234567890120&issuer_name=Hitre Spletne Strani Na 123&issuer_address=Namisljena ulica 1a&issuer_city=1000 Ljubljana"&#x3E;
</pre>
<img src="/api/qrcode?client_name=Šolski center Nova Gorica&client_address=Cankarjeva ulica 8a&client_city=5000 Nova Gorica&amount=00000001000&payment_purpose=placilo&iban=SI56020170014356205&reference=SI121234567890120&issuer_name=Hitre Spletne Strani Na 123&issuer_address=Namisljena ulica 1a&issuer_city=1000 Ljubljana">
</div>
<br>
<div>
<b>Query parameters:</b>
<p>Following the specification from official documentation - <a href="https://www.upn-qr.si/uploads/files/NavodilaZaProgramerjeUPNQR.pdf">NavodilaZaProgramerjeUPNQR.pdf</a>, section <code>4. Vsebina kode QR</code>.</p>
<h5 id="api-qrcode-client_name"><a href="#api-qrcode-client_name">&#128279;</a> <code>client_name</code></h5>
<div>
<span>Regex: <code>^[a-zA-Z0-9ČŠŽĐ'](?:[A-Z0-9 ČŠŽĐ']{0,31}[A-Z0-9ČŠŽĐ'])?$/i</code></span>
<br>
<span>Demo: <a href="https://regex101.com/r/pNmOI0/1">regex101.com/r/pNmOI0/1</a></span>
<br>
<span>Description: Name and surname of the client. Max length 33 characters including spaces and numbers.</span>
<br>
<span>Example: Peter Novak</span>
</div>
<h5 id="api-qrcode-client_address"><a href="#api-qrcode-client_address">&#128279;</a> <code>client_address</code></h5>
<div>
<span>Regex: <code>^[a-zA-Z0-9ČŠŽĐ](?:[A-Z0-9 ČŠŽĐ]{0,31}[A-Z0-9ČŠŽĐ])?$/i</code></span>
<br>
<span>Demo: <a href="https://regex101.com/r/JA4wmM/1">regex101.com/r/JA4wmM/1</a></span>
<br>
<span>Description: Full client address in long form. Max length 33 characters including spaces and numbers.</span>
<br>
<span>Example: Ravna ulica 13 a</span>
</div>
<h5 id="api-qrcode-client_city"><a href="#api-qrcode-client_city">&#128279;</a> <code>client_city</code></h5>
<div>
<span>Regex: <code>^[a-zA-Z0-9ČŠŽĐ](?:[A-Z0-9 ČŠŽĐ]{0,31}[A-Z0-9ČŠŽĐ])?$/i</code></span>
<br>
<span>Demo: <a href="https://regex101.com/r/pK3oEm/1">regex101.com/r/5QMpTn/1</a></span>
<br>
<span>Description: Client's city including postal code</span>
<br>
<span>Example: 1000 Ljubljana</span>
</div>
<h5 id="api-qrcode-amount"><a href="#api-qrcode-amount">&#128279;</a> <code>amount</code></h5>
<div>
<span>Regex: <code>^(?=.{11}$)[0]{1,11}[0-9]{0,11}$</code></span>
<br>
<span>Demo: <a href="https://regex101.com/r/Tyq5S1/1">regex101.com/r/Tyq5S1/1</a></span>
<br>
<span>Description: Total amount to pay. Must contain 11 numbers. Last two numbers are decimal places (cents).</span>
<br>
<span>Example (11,32€): 00000001132</span>
</div>
<h5 id="api-qrcode-purpose_code"><a href="#api-qrcode-purpose_code">&#128279;</a> <code>purpose_code</code></h5>
<div>
<span>Regex: <code>^[A-Z]{4}$</code></span>
<br>
<span>Demo: <a href="https://regex101.com/r/TsiZQJ/1">regex101.com/r/TsiZQJ/1</a></span>
<br>
<span>Default: OTHR</span>
<br>
<span>Description: Must contain 4 uppercase characters compliant with public purpose code library <a href="https://www.nlb.si/sepa-koda-namena-prebivalstvo">www.nlb.si/sepa-koda-namena-prebivalstvo</a></span>
<br>
<span>Example: OTHR</span>
</div>
<h5 id="api-qrcode-payment_purpose"><a href="#api-qrcode-payment_purpose">&#128279;</a> <code>payment_purpose</code></h5>
<div>
<span>Regex: <code>^[A-Z0-9ČŠŽĐ](?:[A-Z0-9 ČŠŽĐ\-:;_'"]{0,40}[A-Z0-9ČŠŽĐ])?$</code></span>
<br>
<span>Demo: <a href="https://regex101.com/r/egl24t/1">regex101.com/r/egl24t/1</a></span>
<br>
<span>Description: A Can contain any character including ŠČŽĐ and space. Max length 33 characters including space.</span>
<br>
<span>Example: moutain bike first half</span>
</div>
<h5 id="api-qrcode-iban"><a href="#api-qrcode-iban">&#128279;</a> <code>iban</code></h5>
<div>
<span>Regex: <code>^[A-Z]{2}\d{17}$</code></span>
<br>
<span>Demo: <a href="https://regex101.com/r/8bXDvh/1">regex101.com/r/8bXDvh/1</a></span>
<br>
<span>Description: Must contain country code (exp. SI56). No spaces allowed. Max length 34 characters</span>
<br>
<span>Example: SI56047500000280672</span>
</div>
<h5 id="api-qrcode-reference"><a href="#api-qrcode-reference">&#128279;</a> <code>reference</code></h5>
<div>
<span>Regex: <code>^[A-Z]{2}[0-9\-]{1,24}$</code></span>
<br>
<span>Demo: <a href="https://regex101.com/r/2tSYMw/1">regex101.com/r/2tSYMw/1</a></span>
<br>
<span>Description: Must contain reference model (exp. SI00) and reference (1234-2002). Max length 4+22 numbers and minus symbols. No spaces allowed.</span>
<br>
<span>Example: SI121234567890120</span>
</div>
<h5 id="api-qrcode-issuer_name"><a href="#api-qrcode-issuer_name">&#128279;</a> <code>issuer_name</code></h5>
<div>
<span>Regex: <code>^[a-zA-Z0-9ČŠŽĐ'](?:[A-Z0-9 ČŠŽĐ']{0,31}[A-Z0-9ČŠŽĐ'])?$/i</code></span>
<br>
<span>Demo: <a href="https://regex101.com/r/JW7Ywq/1">regex101.com/r/JW7Ywq/1</a></span>
<br>
<span>Description: Name and surname of the issuer or company name. Max length 33 characters including spaces and numbers.</span>
<br>
<span>Example: Spletne strani na 123</span>
</div>
<h5 id="api-qrcode-issuer_address"><a href="#api-qrcode-issuer_address">&#128279;</a> <code>issuer_address</code></h5>
<div>
<span>Regex: <code>^[a-zA-Z0-9ČŠŽĐ](?:[A-Z0-9 ČŠŽĐ]{0,31}[A-Z0-9ČŠŽĐ])?$/i</code></span>
<br>
<span>Demo: <a href="https://regex101.com/r/5oKk0T/1">regex101.com/r/5oKk0T/1</a></span>
<br>
<span>Description: Full issuer address in long form. Max length 33 characters including spaces and numbers.</span>
<br>
<span>Example: Za deveto smreko 15 k</span>
</div>
<h5 id="api-qrcode-issuer_city"><a href="#api-qrcode-issuer_city">&#128279;</a> <code>issuer_city</code></h5>
<div>
<span>Regex: <code>^[a-zA-Z0-9ČŠŽĐ](?:[A-Z0-9 ČŠŽĐ]{0,31}[A-Z0-9ČŠŽĐ])?$/i</code></span>
<br>
<span>Demo: <a href="https://regex101.com/r/JfuNU1/1">regex101.com/r/JfuNU1/1</a></span>
<br>
<span>Description: Issuer city including postal code</span>
<br>
<span>Example: 1000 Ljubljana</span>
</div>
<!-- <h5><code>query</code></h5>
<div>
Regex: <code></code>
<br>
Demo: <a href=""></a>
</div> -->
</div>
<div class="credits">
<span>-- - --</span>
Development and hosting: <a href="https://aljaxus.eu">Aljaž Starc</a>
Initial insight: <a href="http://www.valentincic.eu/">Tjaž Valentinčič</a>
<span>-</span>
<a href="https://gitplac.si/aljaxus/upn-qr">gitplac.si/aljaxus/upn-qr</a>
<span>-</span>
</div>
</section>
</body>
</html>