commit bca5704bbd20da5f8128386f2f393e1618cb6fb3
parent cf9ae8dba232ab06638a3a1800569d28a54167d1
Author: Florian Dold <dold@taler.net>
Date: Fri, 21 Aug 2026 12:37:59 +0200
merchant frontend: add self-contained customer pages
Diffstat:
11 files changed, 635 insertions(+), 22 deletions(-)
diff --git a/.gitmodules b/.gitmodules
@@ -2,7 +2,3 @@
path = doc/prebuilt
url = ../taler-docs.git
branch = prebuilt
-[submodule "contrib/wallet-core"]
- path = contrib/wallet-core
- url = ../taler-typescript-core.git
- branch = prebuilt
diff --git a/contrib/meson.build b/contrib/meson.build
@@ -18,22 +18,6 @@ install_data(
)
-dist_tmplpkgdata_DATA = [
- 'offer_refund.en',
- 'request_payment.en',
- 'show_order_details.en',
-]
-fs = import('fs')
-
-foreach f : dist_tmplpkgdata_DATA
- f_must = '@0@.must'.format(f)
- fs.copyfile(
- 'wallet-core' / 'backend' / '@0@.html'.format(f),
- f_must,
- install: true,
- install_dir: get_option('datadir') / 'taler-merchant' / 'templates',
- )
-endforeach
install_data(
'kyc_text.en.must',
'account_status.en.must',
diff --git a/contrib/wallet-core b/contrib/wallet-core
@@ -1 +0,0 @@
-Subproject commit 45c7768f9153846198dac99b6a9015477b9d7d2a
diff --git a/src/frontend/meson.build b/src/frontend/meson.build
@@ -0,0 +1,8 @@
+# This build file is in the public domain.
+
+install_data(
+ 'offer_refund.en.must',
+ 'request_payment.en.must',
+ 'show_order_details.en.must',
+ install_dir: get_option('datadir') / 'taler-merchant' / 'templates',
+)
diff --git a/src/frontend/offer_refund.en.must b/src/frontend/offer_refund.en.must
@@ -0,0 +1,172 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <meta name="referrer" content="no-referrer">
+ <meta name="taler-support" content="uri">
+ <meta name="taler-uri" content="{{ taler_refund_uri }}">
+ <noscript><meta http-equiv="refresh" content="5"></noscript>
+ <title>Refund available for {{ order_summary }}</title>
+ <style>
+ :root {
+ color-scheme: light;
+ --taler-blue: #0042b3;
+ --taler-slate: #586a88;
+ --taler-ink: #172033;
+ --taler-muted: #64748b;
+ --taler-border: #d9dfeb;
+ --taler-panel: #f8f9fc;
+ --taler-qr-frame: #f1f1f4;
+ --taler-success: #147d55;
+ --taler-success-bg: #e9f7f1;
+ font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
+ font-synthesis: none;
+ }
+ * { box-sizing: border-box; }
+ html { min-width: 18rem; background: #fff; color: var(--taler-ink); }
+ body { min-height: 100vh; margin: 0; display: flex; flex-direction: column; }
+ a { color: var(--taler-blue); }
+ a:focus-visible, button:focus-visible { outline: .2rem solid #7aa7f5; outline-offset: .18rem; }
+ .site-header, .site-footer, main { width: min(72rem, calc(100% - 2rem)); margin-inline: auto; }
+ .site-header { min-height: 5.5rem; display: flex; align-items: center; border-bottom: 1px solid var(--taler-border); }
+ .brand { display: inline-flex; align-items: center; }
+ .brand img { display: block; width: 8.4rem; height: auto; }
+ main { flex: 1; display: grid; place-items: center; padding: 3.5rem 0; }
+ .page-grid { width: 100%; display: grid; grid-template-columns: minmax(18rem, 25rem) minmax(20rem, 1fr); gap: clamp(2.5rem, 7vw, 7rem); align-items: center; }
+ .eyebrow { margin: 0 0 .55rem; color: var(--taler-blue); font-size: .78rem; font-weight: 750; letter-spacing: .1em; text-transform: uppercase; }
+ h1 { max-width: 18ch; margin: 0; font-size: clamp(2rem, 4.5vw, 3.5rem); line-height: 1.08; letter-spacing: -.035em; }
+ .lede { max-width: 36rem; margin: 1rem 0 0; color: var(--taler-slate); font-size: 1.08rem; line-height: 1.65; }
+ .amount { margin: 1.8rem 0 .2rem; color: var(--taler-blue); font-size: clamp(2.1rem, 5vw, 3rem); font-weight: 780; line-height: 1.05; letter-spacing: -.025em; overflow-wrap: anywhere; }
+ .amount-note { margin: .55rem 0 0; color: var(--taler-slate); font-size: 1rem; }
+ .details { margin: 2rem 0 0; display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: .8rem 1.25rem; }
+ .details dt { color: var(--taler-muted); }
+ .details dd { margin: 0; font-weight: 620; overflow-wrap: anywhere; }
+ .action { display: inline-flex; min-height: 3rem; margin-top: 1.75rem; padding: .75rem 1.2rem; align-items: center; justify-content: center; border-radius: .55rem; background: var(--taler-blue); color: #fff; font-weight: 720; text-decoration: none; box-shadow: 0 .35rem 1rem rgb(0 66 179 / 20%); }
+ .action:hover { background: #003994; }
+ .wallet-help { margin: 1rem 0 0; color: var(--taler-muted); font-size: .92rem; }
+ .qr-column { display: grid; justify-items: center; gap: 1rem; }
+ .qr-instruction { margin: 0; max-width: 26rem; color: var(--taler-slate); text-align: center; line-height: 1.5; }
+ .qr-frame { position: relative; width: min(100%, 25rem); aspect-ratio: 1; padding: 6.25%; overflow: hidden; border-radius: 8%; background: var(--taler-qr-frame); }
+ .qr-code { width: 100%; height: 100%; background: #fff; }
+ .qr-code > svg { display: block; width: 100%; height: 100%; fill: #000; }
+ .qr-motion { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
+ .qr-motion rect { fill: none; stroke: url(#taler-scan-gradient); stroke-width: 2.6; stroke-linecap: round; stroke-dasharray: 57 343; animation: scan 4s linear infinite; }
+ .qr-motion rect + rect { animation-delay: -2s; }
+ .qr-badge { position: absolute; inset: 50% auto auto 50%; height: 12.5%; width: auto; transform: translate(-50%, -50%); }
+ @keyframes scan { to { stroke-dashoffset: -400; } }
+ .claimed { width: min(100%, 25rem); aspect-ratio: 1; display: grid; place-items: center; padding: 2.5rem; border-radius: 8%; background: var(--taler-qr-frame); text-align: center; }
+ .claimed-icon { width: 4.25rem; height: 4.25rem; margin: 0 auto 1.3rem; display: grid; place-items: center; border-radius: 50%; background: var(--taler-blue); color: #fff; font-size: 2rem; }
+ .claimed h2 { margin: 0; font-size: 1.35rem; }
+ .claimed p { margin: .65rem 0 0; color: var(--taler-slate); line-height: 1.55; }
+ .site-footer { padding: 1.5rem 0 2rem; display: flex; flex-wrap: wrap; justify-content: space-between; gap: .6rem 1.5rem; border-top: 1px solid var(--taler-border); color: var(--taler-muted); font-size: .82rem; }
+ .site-footer p { margin: 0; }
+ .site-footer a { color: inherit; }
+ .status-card { width: min(44rem, 100%); padding: clamp(1.4rem, 4vw, 3rem); border: 1px solid var(--taler-border); border-radius: 1rem; background: #fff; box-shadow: 0 1rem 3rem rgb(30 48 80 / 8%); }
+ .status-mark { width: 3.5rem; height: 3.5rem; margin-bottom: 1.4rem; display: grid; place-items: center; border-radius: 50%; background: var(--taler-success-bg); color: var(--taler-success); font-size: 1.65rem; font-weight: 800; }
+ .message { margin: 1.7rem 0 0; padding: 1rem 1.1rem; border-left: .25rem solid var(--taler-blue); border-radius: .2rem .5rem .5rem .2rem; background: #f1f5ff; line-height: 1.55; }
+ .secondary-link { display: inline-block; margin-top: 1.3rem; font-weight: 650; overflow-wrap: anywhere; }
+ [hidden] { display: none !important; }
+ @media (max-width: 47rem) {
+ .site-header { min-height: 4.5rem; }
+ .brand img { width: 7rem; }
+ main { padding: 2.25rem 0 3rem; place-items: start center; }
+ .page-grid { grid-template-columns: 1fr; gap: 2.5rem; }
+ .qr-column { grid-row: 1; }
+ .copy-column { grid-row: 2; }
+ h1 { font-size: clamp(2rem, 10vw, 3rem); }
+ .details { grid-template-columns: 1fr; gap: .25rem; }
+ .details dd { margin-bottom: .75rem; }
+ .action { width: 100%; }
+ .site-footer { flex-direction: column; }
+ }
+ @media (prefers-reduced-motion: reduce) {
+ .qr-motion rect { animation: none; }
+ .qr-motion rect + rect { stroke-dashoffset: -200; }
+ }
+</style>
+</head>
+<body>
+<header class="site-header">
+ <a class="brand" href="https://taler.net/" rel="noreferrer" referrerpolicy="no-referrer" aria-label="GNU Taler">
+ <img src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBoZWlnaHQ9IjQ0Ny43NjEiIGlkPSJzY3JlZW5zaG90LTUwZWRmYjcyLTU4YzMtODA2ZC04MDA3LTljZWU5ZmI3N2FiZSIgdmlld0JveD0iMCAwIDEwMDAgNDQ3Ljc2MSIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIGZpbGw9Im5vbmUiIHZlcnNpb249IjEuMSI+PGcgaWQ9InNoYXBlLTUwZWRmYjcyLTU4YzMtODA2ZC04MDA3LTljZWU5ZmI3N2FiZSIgd2lkdGg9IjY3MCIgaGVpZ2h0PSIzMDAiIHJ4PSIwIiByeT0iMCIgc3R5bGU9ImZpbGw6IHJnYigwLCAwLCAwKTsiPjxnIGlkPSJzaGFwZS01MGVkZmI3Mi01OGMzLTgwNmQtODAwNy05Y2VlOWZiNzdhYmYiIHN0eWxlPSJkaXNwbGF5OiBub25lOyI+PGcgY2xhc3M9ImZpbGxzIiBpZD0iZmlsbHMtNTBlZGZiNzItNThjMy04MDZkLTgwMDctOWNlZTlmYjc3YWJmIj48cmVjdCB3aWR0aD0iMTAwMCIgaGVpZ2h0PSI0NDcuNzYxMTk0MDI5ODUwNyIgeD0iMCIgdHJhbnNmb3JtPSJtYXRyaXgoMS4wMDAwMDAsIDAuMDAwMDAwLCAwLjAwMDAwMCwgMS4wMDAwMDAsIDAuMDAwMDAwLCAwLjAwMDAwMCkiIHN0eWxlPSJmaWxsOiBub25lOyIgcnk9IjAiIGZpbGw9Im5vbmUiIHJ4PSIwIiB5PSIwIi8+PC9nPjwvZz48ZyBpZD0ic2hhcGUtNTBlZGZiNzItNThjMy04MDZkLTgwMDctOWNlZTlmYjc3YWMwIiByeD0iMCIgcnk9IjAiIHN0eWxlPSJmaWxsOiByZ2IoMCwgMCwgMCk7Ij48ZyBpZD0ic2hhcGUtNTBlZGZiNzItNThjMy04MDZkLTgwMDctOWNlZTlmYjc3YWM2Ij48ZyBjbGFzcz0iZmlsbHMiIGlkPSJmaWxscy01MGVkZmI3Mi01OGMzLTgwNmQtODAwNy05Y2VlOWZiNzdhYzYiPjxwYXRoIGQ9Ik00MzEuMTU1LDUuNTc4QzUwOC43MTYsNS41NzgsNTc2LjA3Nyw1Mi4zNTAsNjEwLjA2NiwxMjEuMDEwTDU4MS4xMjMsMTIxLjAxMEM1NDkuNjg1LDY3Ljc3OCw0OTQuMjc0LDMyLjQyOCw0MzEuMTU1LDMyLjQyOEMzMzMuMTkyLDMyLjQyOCwyNTMuNzc3LDExNy41NjMsMjUzLjc3NywyMjIuNTgwQzI1My43NzcsMjczLjk4MiwyNzIuODEwLDMyMC42MTQsMzAzLjcyNiwzNTQuODM0QzI5Ny4wNDcsMzYwLjQxMSwyODkuOTM3LDM2NS40MjAsMjgyLjQ1NSwzNjkuNzkzQzI0OS4xMTIsMzMxLjExMiwyMjguNzMxLDI3OS40MDMsMjI4LjczMSwyMjIuNTgwQzIyOC43MzEsMTAyLjczNCwzMTkuMzU5LDUuNTc4LDQzMS4xNTUsNS41NzhaWk02MDkuNTIzLDMyNS4yNTNDNTc1LjM2MiwzOTMuMzE0LDUwOC4zMDEsNDM5LjU4Myw0MzEuMTU1LDQzOS41ODNDNDI1LjkxOCw0MzkuNTgzLDQyMC43MjcsNDM5LjM2OSw0MTUuNTg5LDQzOC45NTFDNDMwLjc3NCw0MzEuMTg0LDQ0NS4wMTAsNDIxLjYzNSw0NTguMDY5LDQxMC41NTZDNTA5LjQxNyw0MDIuMTc2LDU1My41MjEsMzcwLjE5MCw1ODAuNDY2LDMyNS4yNTNaIiBzdHlsZT0iZmlsbC1ydWxlOiBldmVub2RkOyBzdHJva2U6IG5vbmU7IHN0cm9rZS13aWR0aDogMC4zMjc5NDM7IGZpbGw6IHJnYigwLCA2NiwgMTc5KTsgZmlsbC1vcGFjaXR5OiAxOyIvPjwvZz48L2c+PGcgaWQ9InNoYXBlLTUwZWRmYjcyLTU4YzMtODA2ZC04MDA3LTljZWU5ZmI3N2FjNyI+PGcgY2xhc3M9ImZpbGxzIiBpZD0iZmlsbHMtNTBlZGZiNzItNThjMy04MDZkLTgwMDctOWNlZTlmYjc3YWM3Ij48cGF0aCBkPSJNMzE5LjQ2NSw1LjU3OEMzMjQuNzAxLDUuNTc4LDMyOS44OTIsNS43OTIsMzM1LjAzMCw2LjIxMEMzMTkuODQ1LDEzLjk3NywzMDUuNjA5LDIzLjUyNSwyOTIuNTUxLDM0LjYwNUMyMDcuMzYxLDQ4LjUwNywxNDIuMDg3LDEyNy4zNzEsMTQyLjA4NywyMjIuNTgwQzE0Mi4wODcsMjkzLjU0OCwxNzguMzU5LDM1NS40MjYsMjMyLjEwNiwzODguMDk3QzIyNC4xNzgsMzg5LjQyNywyMTYuMDUyLDM5MC4xMjIsMjA3Ljc3NCwzOTAuMTIyQzIwMS42MDcsMzkwLjEyMiwxOTUuNTI4LDM4OS43MjYsMTg5LjU0OCwzODguOTgxQzE0NS4yMjksMzQ5LjE3NCwxMTcuMDQwLDI4OS40MTEsMTE3LjA0MCwyMjIuNTgwQzExNy4wNDAsMTAyLjczNCwyMDcuNjY5LDUuNTc4LDMxOS40NjUsNS41NzhaWk0zNDYuMzc5LDQxMC41NTZDMzk3LjcyNyw0MDIuMTc2LDQ0MS44MzIsMzcwLjE4OCw0NjguNzc2LDMyNS4yNTFMNDk3LjgzNCwzMjUuMjUxQzQ2My42NzMsMzkzLjMxMiwzOTYuNjEyLDQzOS41ODMsMzE5LjQ2NSw0MzkuNTgzQzMxNC4yMjcsNDM5LjU4MywzMDkuMDM3LDQzOS4zNjksMzAzLjg5OSw0MzguOTUxQzMxOS4wODMsNDMxLjE4MywzMzMuMzIxLDQyMS42MzYsMzQ2LjM3OSw0MTAuNTU2WlpNNDY5LjQzMiwxMjEuMDEwQzQ1My44MTMsOTQuNTY5LDQzMi4yODAsNzIuNTM5LDQwNi44MjMsNTcuMDYzQzQxNC43NTEsNTUuNzM0LDQyMi44NzcsNTUuMDM5LDQzMS4xNTUsNTUuMDM5QzQzNy4zMjEsNTUuMDM5LDQ0My40MDEsNTUuNDM0LDQ0OS4zODEsNTYuMTgwQzQ2OS4zNjIsNzQuMTI2LDQ4Ni4wNjQsOTYuMTMxLDQ5OC4zODIsMTIxLjAxMFoiIHN0eWxlPSJmaWxsLXJ1bGU6IGV2ZW5vZGQ7IHN0cm9rZTogbm9uZTsgc3Ryb2tlLXdpZHRoOiAwLjMyNzk0MzsgZmlsbDogcmdiKDAsIDY2LCAxNzkpOyBmaWxsLW9wYWNpdHk6IDE7Ii8+PC9nPjwvZz48ZyBpZD0ic2hhcGUtNTBlZGZiNzItNThjMy04MDZkLTgwMDctOWNlZTlmYjc3YWM4Ij48ZyBjbGFzcz0iZmlsbHMiIGlkPSJmaWxscy01MGVkZmI3Mi01OGMzLTgwNmQtODAwNy05Y2VlOWZiNzdhYzgiPjxwYXRoIGQ9Ik0yMDcuNzc0LDUuNTc4QzIxMy4wNjksNS41NzgsMjE4LjMxNSw1Ljc5OSwyMjMuNTA4LDYuMjI2QzIwOC4zNTIsMTMuOTgyLDE5NC4xMzksMjMuNTEyLDE4MS4xMDMsMzQuNTY4Qzk1Ljc5NCw0OC4zNjEsMzAuMzk3LDEyNy4yODEsMzAuMzk3LDIyMi41ODBDMzAuMzk3LDMyNy41OTgsMTA5LjgxMiw0MTIuNzMyLDIwNy43NzQsNDEyLjczMkMyNzAuNDU5LDQxMi43MzIsMzI1LjU0NywzNzcuODcxLDM1Ny4wOTYsMzI1LjI1MUwzODYuMTQ0LDMyNS4yNTFDMzUxLjk4MywzOTMuMzEyLDI4NC45MjIsNDM5LjU4MywyMDcuNzc0LDQzOS41ODNDOTUuOTc5LDQzOS41ODMsNS4zNTAsMzQyLjQyNyw1LjM1MCwyMjIuNTgwQzUuMzUwLDEwMi43MzQsOTUuOTc5LDUuNTc4LDIwNy43NzQsNS41NzhaWk0zNTcuNzM4LDEyMS4wMTBDMzUxLjIxMSwxMDkuOTYyLDM0My42NTQsOTkuNjgxLDMzNS4yMDYsOTAuMzMxQzM0MS44ODUsODQuNzU0LDM0OC45OTQsNzkuNzQyLDM1Ni40NzYsNzUuMzY5QzM2OC4yODIsODkuMDY2LDM3OC40NjAsMTA0LjM5NywzODYuNjg3LDEyMS4wMTBaIiBzdHlsZT0iZmlsbC1ydWxlOiBldmVub2RkOyBzdHJva2U6IG5vbmU7IHN0cm9rZS13aWR0aDogMC4zMjc5NDM7IGZpbGw6IHJnYigwLCA2NiwgMTc5KTsgZmlsbC1vcGFjaXR5OiAxOyIvPjwvZz48L2c+PC9nPjxnIGlkPSJzaGFwZS01MGVkZmI3Mi01OGMzLTgwNmQtODAwNy05Y2VlOWZiNzdhYzEiPjxnIGNsYXNzPSJmaWxscyIgaWQ9ImZpbGxzLTUwZWRmYjcyLTU4YzMtODA2ZC04MDA3LTljZWU5ZmI3N2FjMSI+PHBhdGggZD0iTTM3OC43ODMsMTcxLjE4OUw0MjQuMzYwLDE3MS4xODlMNDI0LjM2MCwxNDYuMDk5TDMwNy43NDksMTQ2LjA5OUwzMDcuNzQ5LDE3MS4xODlMMzUzLjMyNywxNzEuMTg5TDM1My4zMjcsMzAwLjE2MEwzNzguNzgzLDMwMC4xNjBaIi8+PC9nPjwvZz48ZyBpZD0ic2hhcGUtNTBlZGZiNzItNThjMy04MDZkLTgwMDctOWNlZTlmYjc3YWMyIj48ZyBjbGFzcz0iZmlsbHMiIGlkPSJmaWxscy01MGVkZmI3Mi01OGMzLTgwNmQtODAwNy05Y2VlOWZiNzdhYzIiPjxwYXRoIGQ9Ik00NjAuOTMzLDI2Mi45NjdMNTI4Ljg4OCwyNjIuOTY3TDU0My40NjYsMzAwLjE2MUw1NzAuMTU2LDMwMC4xNjFMNTA2LjkyMSwxNDUuMDAwTDQ4My41MTgsMTQ1LjAwMEw0MjAuMjg0LDMwMC4xNjFMNDQ2LjE1MiwzMDAuMTYxWk01MTkuNjUwLDIzOC45NzVMNDcwLjE3NCwyMzguOTc1TDQ5NC44MDksMTc3LjM1MVoiLz48L2c+PC9nPjxnIGlkPSJzaGFwZS01MGVkZmI3Mi01OGMzLTgwNmQtODAwNy05Y2VlOWZiNzdhYzMiPjxnIGNsYXNzPSJmaWxscyIgaWQ9ImZpbGxzLTUwZWRmYjcyLTU4YzMtODA2ZC04MDA3LTljZWU5ZmI3N2FjMyI+PHBhdGggZD0iTTYxNS45NTIsMTQ2LjEwMEw1OTMuMTY0LDE0Ni4xMDBMNTkzLjE2NCwzMDAuMTYxTDY5NS4zOTAsMzAwLjE2MUw2OTUuMzkwLDI3NS43MzJDNjY4LjkxMSwyNzUuNzMyLDY0Mi40MzEsMjc1LjczMiw2MTUuOTUyLDI3NS43MzJaIi8+PC9nPjwvZz48ZyBpZD0ic2hhcGUtNTBlZGZiNzItNThjMy04MDZkLTgwMDctOWNlZTlmYjc3YWM0Ij48ZyBjbGFzcz0iZmlsbHMiIGlkPSJmaWxscy01MGVkZmI3Mi01OGMzLTgwNmQtODAwNy05Y2VlOWZiNzdhYzQiPjxwYXRoIGQ9Ik04MjguMjIwLDE0Ni4xMDBMNzIxLjg3MywxNDYuMTAwTDcyMS44NzMsMzAwLjE2MUw4MjkuMjQ3LDMwMC4xNjFMODI5LjI0NywyNzUuNzMyTDc0Ni45MjAsMjc1LjczMkw3NDYuOTIwLDIzNC41NzRMODE4Ljk4MSwyMzQuNTc0TDgxOC45ODEsMjEwLjE0Nkw3NDYuOTIwLDIxMC4xNDZMNzQ2LjkyMCwxNzAuNTMwTDgyOC4yMjAsMTcwLjUzMFoiLz48L2c+PC9nPjxnIGlkPSJzaGFwZS01MGVkZmI3Mi01OGMzLTgwNmQtODAwNy05Y2VlOWZiNzdhYzUiPjxnIGNsYXNzPSJmaWxscyIgaWQ9ImZpbGxzLTUwZWRmYjcyLTU4YzMtODA2ZC04MDA3LTljZWU5ZmI3N2FjNSI+PHBhdGggZD0iTTk1MS4xOTYsMTk2LjM5MUM5NTEuMTk2LDIwNC4zNDksOTQ4LjUyNywyMTAuNjk2LDk0My4xNTUsMjE1LjM5MEM5MzcuODE3LDIyMC4xMjMsOTMwLjU5NywyMjIuNDY5LDkyMS41MjksMjIyLjQ2OUw4ODQuNDcyLDIyMi40NjlMODg0LjQ3MiwxNzAuNTMwTDkyMS4zMjQsMTcwLjUzMEM5MzAuODAyLDE3MC41MzAsOTM4LjE1OCwxNzIuNjk0LDk0My4zNjEsMTc3LjA1OEM5NDguNTk2LDE4MS4zODcsOTUxLjE5NiwxODcuODQzLDk1MS4xOTYsMTk2LjM5MVpaTTk4MS4zNzUsMzAwLjE2MUw5NDIuNTczLDI0MS44MzdDOTQ3LjYzNywyNDAuMzcwLDk1Mi4yNTcsMjM4LjI4MSw5NTYuNDMyLDIzNS41NjVDOTYwLjYwNSwyMzIuODUxLDk2NC4xOTksMjI5LjU0OSw5NjcuMjA5LDIyNS42NjJDOTcwLjIyMSwyMjEuNzczLDk3Mi41ODIsMjE3LjI5OCw5NzQuMjkyLDIxMi4yMzdDOTc2LjAwMywyMDcuMTc1LDk3Ni44NTgsMjAxLjQxNSw5NzYuODU4LDE5NC45NTlDOTc2Ljg1OCwxODcuNDc2LDk3NS42MjcsMTgwLjY5MSw5NzMuMTYzLDE3NC42MDFDOTcwLjY5OSwxNjguNTEyLDk2Ny4xNzUsMTYzLjM3Niw5NjIuNTkxLDE1OS4xOTRDOTU4LjAwNSwxNTUuMDEzLDk1Mi4zOTQsMTUxLjc4NSw5NDUuNzU2LDE0OS41MTBDOTM5LjExNywxNDcuMjM1LDkzMS42OTIsMTQ2LjEwMCw5MjMuNDgwLDE0Ni4xMDBMODU5LjQyNSwxNDYuMTAwTDg1OS40MjUsMzAwLjE2MUw4ODQuNDcyLDMwMC4xNjFMODg0LjQ3MiwyNDYuNDYwTDkxNi4xOTEsMjQ2LjQ2MEw5NTEuNjA2LDMwMC4xNjFaIi8+PC9nPjwvZz48L2c+PC9zdmc+" alt="GNU Taler">
+ </a>
+</header>
+<main>
+ <div class="page-grid">
+ <section class="copy-column" aria-labelledby="page-title">
+ <p class="eyebrow">{{ merchant_name }}</p>
+ <h1 id="page-title">Collect your refund</h1>
+ <p class="lede">{{ order_summary }}</p>
+ <p class="amount">{{ refund_remaining }}</p>
+ <p class="amount-note">Remaining to collect</p>
+ <dl class="details">
+ <dt>Merchant</dt><dd>{{ merchant_name }}</dd>
+ <dt>Order ID</dt><dd>{{ order_id }}</dd>
+ <dt>Total granted</dt><dd>{{ refund_amount }}</dd>
+ {{#has_refund_taken}}<dt>Already collected</dt><dd>{{ refund_taken }}</dd>{{/has_refund_taken}}
+ </dl>
+ <a class="action" href="{{ taler_refund_uri }}">Open Taler wallet</a>
+ <p class="wallet-help">Keep this page open. It updates when your wallet has collected the refund.</p>
+ </section>
+ <section class="qr-column">
+ <div class="qr-frame" aria-label="QR code for the Taler wallet">
+ <div class="qr-code">{{{ taler_refund_qrcode_svg }}}</div>
+ <svg class="qr-motion" viewBox="0 0 100 100" aria-hidden="true" focusable="false">
+ <defs><linearGradient id="taler-scan-gradient"><stop offset="0" stop-color="#f1f1f4"/><stop offset=".5" stop-color="#0042b3"/><stop offset="1" stop-color="#f1f1f4"/></linearGradient></defs>
+ <rect x="1.3" y="1.3" width="97.4" height="97.4" rx="8" pathLength="400"/>
+ <rect x="1.3" y="1.3" width="97.4" height="97.4" rx="8" pathLength="400"/>
+ </svg>
+ <img class="qr-badge" src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iOTUiIGlkPSJzY3JlZW5zaG90LWI4NzE4ZWFkLTQ1OTItODA1Zi04MDA3LWE5ZWY1NWYwYTQxYiIgdmlld0JveD0iMCAwIDIwMCA5NSIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIGZpbGw9Im5vbmUiIHZlcnNpb249IjEuMSI+PGcgaWQ9InNoYXBlLWI4NzE4ZWFkLTQ1OTItODA1Zi04MDA3LWE5ZWY1NWYwYTQxYiI+PGcgY2xhc3M9ImZyYW1lLWNvbnRhaW5lci13cmFwcGVyIj48ZyBjbGFzcz0iZnJhbWUtY29udGFpbmVyLWJsdXIiPjxnIGNsYXNzPSJmcmFtZS1jb250YWluZXItc2hhZG93cyI+PGcgZmlsbD0ibm9uZSI+PGcgY2xhc3M9ImZpbGxzIiBpZD0iZmlsbHMtYjg3MThlYWQtNDU5Mi04MDVmLTgwMDctYTllZjU1ZjBhNDFiIj48cmVjdCB3aWR0aD0iMjAwIiBoZWlnaHQ9Ijk1IiBjbGFzcz0iZnJhbWUtYmFja2dyb3VuZCIgeD0iMCIgdHJhbnNmb3JtPSJtYXRyaXgoMS4wMDAwMDAsIDAuMDAwMDAwLCAwLjAwMDAwMCwgMS4wMDAwMDAsIDAuMDAwMDAwLCAwLjAwMDAwMCkiIHN0eWxlPSJmaWxsOiByZ2IoMjU1LCAyNTUsIDI1NSk7IGZpbGwtb3BhY2l0eTogMTsiIHJ5PSI0Ny41IiByeD0iNDcuNSIgeT0iMCIvPjwvZz48ZyBjbGFzcz0iZnJhbWUtY2hpbGRyZW4iPjxnIGlkPSJzaGFwZS1iODcxOGVhZC00NTkyLTgwNWYtODAwNy1hOWVmNTVmMGE0MWMiIHdpZHRoPSI2NzAiIGhlaWdodD0iMzAwIiByeD0iMCIgcnk9IjAiIHN0eWxlPSJmaWxsOiByZ2IoMCwgMCwgMCk7Ij48ZyBpZD0ic2hhcGUtYjg3MThlYWQtNDU5Mi04MDVmLTgwMDctYTllZjU1ZjBhNDFkIiBzdHlsZT0iZGlzcGxheTogbm9uZTsiPjxnIGNsYXNzPSJmaWxscyIgaWQ9ImZpbGxzLWI4NzE4ZWFkLTQ1OTItODA1Zi04MDA3LWE5ZWY1NWYwYTQxZCI+PHJlY3Qgd2lkdGg9IjE4MCIgaGVpZ2h0PSI4MC43NjkyMzA3NjkyMzA5NCIgeD0iMTAiIHRyYW5zZm9ybT0ibWF0cml4KDEuMDAwMDAwLCAwLjAwMDAwMCwgMC4wMDAwMDAsIDEuMDAwMDAwLCAwLjAwMDAwMCwgMC4wMDAwMDApIiBzdHlsZT0iZmlsbDogbm9uZTsiIHJ5PSIwIiBmaWxsPSJub25lIiByeD0iMCIgeT0iNy4xMTUzODQ2MTUzODQzMDEiLz48L2c+PC9nPjxnIGlkPSJzaGFwZS1iODcxOGVhZC00NTkyLTgwNWYtODAwNy1hOWVmNTVmMGE0MWUiIHJ4PSIwIiByeT0iMCIgc3R5bGU9ImZpbGw6IHJnYigwLCAwLCAwKTsiPjxnIGlkPSJzaGFwZS1iODcxOGVhZC00NTkyLTgwNWYtODAwNy1hOWVmNTVmMGE0MjQiPjxnIGNsYXNzPSJmaWxscyIgaWQ9ImZpbGxzLWI4NzE4ZWFkLTQ1OTItODA1Zi04MDA3LWE5ZWY1NWYwYTQyNCI+PHBhdGggZD0iTTg3LjYwNzkxMDE1NjI1LDguMTIxNTgyMDMxMjVDMTAxLjU2ODgxNzEzODY3MTg4LDguMTIxNTgyMDMxMjUsMTEzLjY5Mzc4NjYyMTA5Mzc1LDE2LjU1ODU5Mzc1LDExOS44MTE3OTgwOTU3MDMxMiwyOC45NDM2MDM1MTU2MjVMMTE0LjYwMjIzMzg4NjcxODc1LDI4Ljk0MzYwMzUxNTYyNUMxMDguOTQzMjM3MzA0Njg3NSwxOS4zNDEzMDg1OTM3NSw5OC45NjkyNjg3OTg4MjgxMiwxMi45NjQ4NDM3NSw4Ny42MDc5MTAxNTYyNSwxMi45NjQ4NDM3NUM2OS45NzQ1NDgzMzk4NDM3NSwxMi45NjQ4NDM3NSw1NS42Nzk5NjIxNTgyMDMxMjUsMjguMzIxNzc3MzQzNzUsNTUuNjc5OTYyMTU4MjAzMTI1LDQ3LjI2NTM4MDg1OTM3NUM1NS42Nzk5NjIxNTgyMDMxMjUsNTYuNTM3NTk3NjU2MjUsNTkuMTA1ODY1NDc4NTE1NjI1LDY0Ljk0OTIxODc1LDY0LjY3MDYyMzc3OTI5Njg4LDcxLjEyMTgyNjE3MTg3NUM2My40Njg1MDU4NTkzNzUsNzIuMTI3OTI5Njg3NSw2Mi4xODg2MjkxNTAzOTA2MjUsNzMuMDMxNDk0MTQwNjI1LDYwLjg0MTgyNzM5MjU3ODEyNSw3My44MjAzMTI1QzU0Ljg0MDE0ODkyNTc4MTI1LDY2Ljg0Mjc3MzQzNzUsNTEuMTcxNTA4Nzg5MDYyNSw1Ny41MTUzODA4NTkzNzUsNTEuMTcxNTA4Nzg5MDYyNSw0Ny4yNjUzODA4NTkzNzVDNTEuMTcxNTA4Nzg5MDYyNSwyNS42NDY5NzI2NTYyNSw2Ny40ODQ2NDk2NTgyMDMxMiw4LjEyMTU4MjAzMTI1LDg3LjYwNzkxMDE1NjI1LDguMTIxNTgyMDMxMjVaTTExOS43MTQxNzIzNjMyODEyNSw2NS43ODYxMzI4MTI1QzExMy41NjUxMjQ1MTE3MTg3NSw3OC4wNjI5ODgyODEyNSwxMDEuNDk0MjMyMTc3NzM0MzgsODYuNDA5NDIzODI4MTI1LDg3LjYwNzkxMDE1NjI1LDg2LjQwOTQyMzgyODEyNUM4Ni42NjUxOTE2NTAzOTA2Miw4Ni40MDk0MjM4MjgxMjUsODUuNzMwODA0NDQzMzU5MzgsODYuMzcwODQ5NjA5Mzc1LDg0LjgwNjA5MTMwODU5Mzc1LDg2LjI5NTQxMDE1NjI1Qzg3LjUzOTM5ODE5MzM1OTM4LDg0Ljg5NDI4NzEwOTM3NSw5MC4xMDE4MzcxNTgyMDMxMiw4My4xNzE4NzUsOTIuNDUyMzMxNTQyOTY4NzUsODEuMTczMzM5ODQzNzVDMTAxLjY5NDk3NjgwNjY0MDYyLDc5LjY2MTg2NTIzNDM3NSwxMDkuNjMzODE5NTgwMDc4MTIsNzMuODkxODQ1NzAzMTI1LDExNC40ODM4MjU2ODM1OTM3NSw2NS43ODYxMzI4MTI1WiIgc3R5bGU9ImZpbGwtcnVsZTogZXZlbm9kZDsgc3Ryb2tlOiBub25lOyBzdHJva2Utd2lkdGg6IDAuMzI3OTQzOyBmaWxsOiByZ2IoMCwgNjYsIDE3OSk7IGZpbGwtb3BhY2l0eTogMTsiLz48L2c+PC9nPjxnIGlkPSJzaGFwZS1iODcxOGVhZC00NTkyLTgwNWYtODAwNy1hOWVmNTVmMGE0MjUiPjxnIGNsYXNzPSJmaWxscyIgaWQ9ImZpbGxzLWI4NzE4ZWFkLTQ1OTItODA1Zi04MDA3LWE5ZWY1NWYwYTQyNSI+PHBhdGggZD0iTTY3LjUwMzYzMTU5MTc5Njg4LDguMTIxNTgyMDMxMjVDNjguNDQ2MjU4NTQ0OTIxODgsOC4xMjE1ODIwMzEyNSw2OS4zODA2MTUyMzQzNzUsOC4xNjAxNTYyNSw3MC4zMDU0MTk5MjE4NzUsOC4yMzU1OTU3MDMxMjVDNjcuNTcyMTEzMDM3MTA5MzgsOS42MzY3MTg3NSw2NS4wMDk1ODI1MTk1MzEyNSwxMS4zNTg4ODY3MTg3NSw2Mi42NTkwODgxMzQ3NjU2MjUsMTMuMzU3NjY2MDE1NjI1QzQ3LjMyNDk1MTE3MTg3NSwxNS44NjUyMzQzNzUsMzUuNTc1NjUzMDc2MTcxODc1LDMwLjA5MTA2NDQ1MzEyNSwzNS41NzU2NTMwNzYxNzE4NzUsNDcuMjY1MzgwODU5Mzc1QzM1LjU3NTY1MzA3NjE3MTg3NSw2MC4wNjY4OTQ1MzEyNSw0Mi4xMDQ1NTMyMjI2NTYyNSw3MS4yMjg3NTk3NjU2MjUsNTEuNzc5MTEzNzY5NTMxMjUsNzcuMTIyMDcwMzEyNUM1MC4zNTE5NTkyMjg1MTU2MjUsNzcuMzYyMDYwNTQ2ODc1LDQ4Ljg4OTI4MjIyNjU2MjUsNzcuNDg3MzA0Njg3NSw0Ny4zOTkzMjI1MDk3NjU2MjUsNzcuNDg3MzA0Njg3NUM0Ni4yODkzMDY2NDA2MjUsNzcuNDg3MzA0Njg3NSw0NS4xOTUwMDczMjQyMTg3NSw3Ny40MTYwMTU2MjUsNDQuMTE4NTYwNzkxMDE1NjI1LDc3LjI4MTQ5NDE0MDYyNUMzNi4xNDEyOTYzODY3MTg3NSw3MC4xMDEwNzQyMTg3NSwzMS4wNjcyMzAyMjQ2MDkzNzUsNTkuMzIwODAwNzgxMjUsMzEuMDY3MjMwMjI0NjA5Mzc1LDQ3LjI2NTM4MDg1OTM3NUMzMS4wNjcyMzAyMjQ2MDkzNzUsMjUuNjQ2OTcyNjU2MjUsNDcuMzgwMzcxMDkzNzUsOC4xMjE1ODIwMzEyNSw2Ny41MDM2MzE1OTE3OTY4OCw4LjEyMTU4MjAzMTI1Wk03Mi4zNDgxNDQ1MzEyNSw4MS4xNzMzMzk4NDM3NUM4MS41OTA5NDIzODI4MTI1LDc5LjY2MTg2NTIzNDM3NSw4OS41Mjk2OTM2MDM1MTU2Miw3My44OTE2MDE1NjI1LDk0LjM3OTc2MDc0MjE4NzUsNjUuNzg1NjQ0NTMxMjVMOTkuNjEwMDc2OTA0Mjk2ODgsNjUuNzg1NjQ0NTMxMjVDOTMuNDYxMDkwMDg3ODkwNjIsNzguMDYyNzQ0MTQwNjI1LDgxLjM5MDE2NzIzNjMyODEyLDg2LjQwOTQyMzgyODEyNSw2Ny41MDM2MzE1OTE3OTY4OCw4Ni40MDk0MjM4MjgxMjVDNjYuNTYwODgyNTY4MzU5MzgsODYuNDA5NDIzODI4MTI1LDY1LjYyNjYxNzQzMTY0MDYyLDg2LjM3MDg0OTYwOTM3NSw2NC43MDE4MTI3NDQxNDA2Miw4Ni4yOTU0MTAxNTYyNUM2Ny40MzQ5MzY1MjM0Mzc1LDg0Ljg5NDA0Mjk2ODc1LDY5Ljk5Nzc3MjIxNjc5Njg4LDgzLjE3MjExOTE0MDYyNSw3Mi4zNDgxNDQ1MzEyNSw4MS4xNzMzMzk4NDM3NVpNOTQuNDk3ODAyNzM0Mzc1LDI4Ljk0MzYwMzUxNTYyNUM5MS42ODY0MDEzNjcxODc1LDI0LjE3NDA3MjI2NTYyNSw4Ny44MTA0NTUzMjIyNjU2MiwyMC4yMDAxOTUzMTI1LDgzLjIyODA4ODM3ODkwNjI1LDE3LjQwODY5MTQwNjI1Qzg0LjY1NTI0MjkxOTkyMTg4LDE3LjE2ODk0NTMxMjUsODYuMTE3ODU4ODg2NzE4NzUsMTcuMDQzNDU3MDMxMjUsODcuNjA3OTEwMTU2MjUsMTcuMDQzNDU3MDMxMjVDODguNzE3ODY0OTkwMjM0MzgsMTcuMDQzNDU3MDMxMjUsODkuODEyMjI1MzQxNzk2ODgsMTcuMTE0OTkwMjM0Mzc1LDkwLjg4ODY3MTg3NSwxNy4yNDkyNjc1NzgxMjVDOTQuNDg1MTA3NDIxODc1LDIwLjQ4NjU3MjI2NTYyNSw5Ny40OTE1MTYxMTMyODEyNSwyNC40NTU4MTA1NDY4NzUsOTkuNzA4NzA5NzE2Nzk2ODgsMjguOTQzNjAzNTE1NjI1WiIgc3R5bGU9ImZpbGwtcnVsZTogZXZlbm9kZDsgc3Ryb2tlOiBub25lOyBzdHJva2Utd2lkdGg6IDAuMzI3OTQzOyBmaWxsOiByZ2IoMCwgNjYsIDE3OSk7IGZpbGwtb3BhY2l0eTogMTsiLz48L2c+PC9nPjxnIGlkPSJzaGFwZS1iODcxOGVhZC00NTkyLTgwNWYtODAwNy1hOWVmNTVmMGE0MjYiPjxnIGNsYXNzPSJmaWxscyIgaWQ9ImZpbGxzLWI4NzE4ZWFkLTQ1OTItODA1Zi04MDA3LWE5ZWY1NWYwYTQyNiI+PHBhdGggZD0iTTQ3LjM5OTMyMjUwOTc2NTYyNSw4LjEyMTU4MjAzMTI1QzQ4LjM1MjQ0NzUwOTc2NTYyNSw4LjEyMTU4MjAzMTI1LDQ5LjI5Njc4MzQ0NzI2NTYyNSw4LjE2MTM3Njk1MzEyNSw1MC4yMzE1MDYzNDc2NTYyNSw4LjIzODUyNTM5MDYyNUM0Ny41MDMyOTU4OTg0Mzc1LDkuNjM3NDUxMTcxODc1LDQ0Ljk0NTA5ODg3Njk1MzEyNSwxMS4zNTY2ODk0NTMxMjUsNDIuNTk4NDQ5NzA3MDMxMjUsMTMuMzUxMDc0MjE4NzVDMjcuMjQyOTUwNDM5NDUzMTI1LDE1LjgzOTExMTMyODEyNSwxNS40NzEzNzQ1MTE3MTg3NSwzMC4wNzQ5NTExNzE4NzUsMTUuNDcxMzc0NTExNzE4NzUsNDcuMjY1MzgwODU5Mzc1QzE1LjQ3MTM3NDUxMTcxODc1LDY2LjIwODk4NDM3NSwyOS43NjYwODI3NjM2NzE4NzUsODEuNTY1OTE3OTY4NzUsNDcuMzk5MzIyNTA5NzY1NjI1LDgxLjU2NTkxNzk2ODc1QzU4LjY4MjY3ODIyMjY1NjI1LDgxLjU2NTkxNzk2ODc1LDY4LjU5ODU0MTI1OTc2NTYyLDc1LjI3NzU4Nzg5MDYyNSw3NC4yNzczMTMyMzI0MjE4OCw2NS43ODU2NDQ1MzEyNUw3OS41MDU4Mjg4NTc0MjE4OCw2NS43ODU2NDQ1MzEyNUM3My4zNTY4NzI1NTg1OTM3NSw3OC4wNjI3NDQxNDA2MjUsNjEuMjg1ODg4NjcxODc1LDg2LjQwOTQyMzgyODEyNSw0Ny4zOTkzMjI1MDk3NjU2MjUsODYuNDA5NDIzODI4MTI1QzI3LjI3NjEyMzA0Njg3NSw4Ni40MDk0MjM4MjgxMjUsMTAuOTYzMDQzMjEyODkwNjI1LDY4Ljg4NDAzMzIwMzEyNSwxMC45NjMwNDMyMTI4OTA2MjUsNDcuMjY1MzgwODU5Mzc1QzEwLjk2MzA0MzIxMjg5MDYyNSwyNS42NDY5NzI2NTYyNSwyNy4yNzYxMjMwNDY4NzUsOC4xMjE1ODIwMzEyNSw0Ny4zOTkzMjI1MDk3NjU2MjUsOC4xMjE1ODIwMzEyNVpNNzQuMzkyODgzMzAwNzgxMjUsMjguOTQzNjAzNTE1NjI1QzczLjIxODAxNzU3ODEyNSwyNi45NTA5Mjc3MzQzNzUsNzEuODU3NjY2MDE1NjI1LDI1LjA5NjQzNTU0Njg3NSw3MC4zMzcxNTgyMDMxMjUsMjMuNDA5NjY3OTY4NzVDNzEuNTM5MzY3Njc1NzgxMjUsMjIuNDAzODA4NTkzNzUsNzIuODE5MDAwMjQ0MTQwNjIsMjEuNDk5NTExNzE4NzUsNzQuMTY1NjQ5NDE0MDYyNSwyMC43MTA5Mzc1Qzc2LjI5MDcxMDQ0OTIxODc1LDIzLjE4MTY0MDYyNSw3OC4xMjI4MzMyNTE5NTMxMiwyNS45NDcwMjE0ODQzNzUsNzkuNjAzNjk4NzMwNDY4NzUsMjguOTQzNjAzNTE1NjI1WiIgc3R5bGU9ImZpbGwtcnVsZTogZXZlbm9kZDsgc3Ryb2tlOiBub25lOyBzdHJva2Utd2lkdGg6IDAuMzI3OTQzOyBmaWxsOiByZ2IoMCwgNjYsIDE3OSk7IGZpbGwtb3BhY2l0eTogMTsiLz48L2c+PC9nPjwvZz48ZyBpZD0ic2hhcGUtYjg3MThlYWQtNDU5Mi04MDVmLTgwMDctYTllZjU1ZjBhNDFmIj48ZyBjbGFzcz0iZmlsbHMiIGlkPSJmaWxscy1iODcxOGVhZC00NTkyLTgwNWYtODAwNy1hOWVmNTVmMGE0MWYiPjxwYXRoIGQ9Ik03OC4xODA5NjkyMzgyODEyNSwzNy45OTUzNjEzMjgxMjVMODYuMzg0ODg3Njk1MzEyNSwzNy45OTUzNjEzMjgxMjVMODYuMzg0ODg3Njk1MzEyNSwzMy40Njk0ODI0MjE4NzVMNjUuMzk0ODA1OTA4MjAzMTIsMzMuNDY5NDgyNDIxODc1TDY1LjM5NDgwNTkwODIwMzEyLDM3Ljk5NTM2MTMyODEyNUw3My41OTg4MTU5MTc5Njg3NSwzNy45OTUzNjEzMjgxMjVMNzMuNTk4ODE1OTE3OTY4NzUsNjEuMjU5NzY1NjI1TDc4LjE4MDk2OTIzODI4MTI1LDYxLjI1OTc2NTYyNVoiLz48L2c+PC9nPjxnIGlkPSJzaGFwZS1iODcxOGVhZC00NTkyLTgwNWYtODAwNy1hOWVmNTVmMGE0MjAiPjxnIGNsYXNzPSJmaWxscyIgaWQ9ImZpbGxzLWI4NzE4ZWFkLTQ1OTItODA1Zi04MDA3LWE5ZWY1NWYwYTQyMCI+PHBhdGggZD0iTTkyLjk2Nzk4NzA2MDU0Njg4LDU0LjU1MDUzNzEwOTM3NUwxMDUuMTk5OTIwNjU0Mjk2ODgsNTQuNTUwNTM3MTA5Mzc1TDEwNy44MjM4ODMwNTY2NDA2Miw2MS4yNTk3NjU2MjVMMTEyLjYyODAyMTI0MDIzNDM4LDYxLjI1OTc2NTYyNUwxMDEuMjQ1ODgwMTI2OTUzMTIsMzMuMjcwOTk2MDkzNzVMOTcuMDMzMjk0Njc3NzM0MzgsMzMuMjcwOTk2MDkzNzVMODUuNjUxMTIzMDQ2ODc1LDYxLjI1OTc2NTYyNUw5MC4zMDc0MzQwODIwMzEyNSw2MS4yNTk3NjU2MjVaTTEwMy41MzcwMTc4MjIyNjU2Miw1MC4yMjI5MDAzOTA2MjVMOTQuNjMxMjU2MTAzNTE1NjIsNTAuMjIyOTAwMzkwNjI1TDk5LjA2NTY0MzMxMDU0Njg4LDM5LjEwNjkzMzU5Mzc1WiIvPjwvZz48L2c+PGcgaWQ9InNoYXBlLWI4NzE4ZWFkLTQ1OTItODA1Zi04MDA3LWE5ZWY1NWYwYTQyMSI+PGcgY2xhc3M9ImZpbGxzIiBpZD0iZmlsbHMtYjg3MThlYWQtNDU5Mi04MDVmLTgwMDctYTllZjU1ZjBhNDIxIj48cGF0aCBkPSJNMTIwLjg3MTM5ODkyNTc4MTI1LDMzLjQ2OTQ4MjQyMTg3NUwxMTYuNzY5NTkyMjg1MTU2MjUsMzMuNDY5NDgyNDIxODc1TDExNi43Njk1OTIyODUxNTYyNSw2MS4yNTk3NjU2MjVMMTM1LjE3MDEzNTQ5ODA0Njg4LDYxLjI1OTc2NTYyNUwxMzUuMTcwMTM1NDk4MDQ2ODgsNTYuODUzMjcxNDg0Mzc1QzEzMC40MDM5MzA2NjQwNjI1LDU2Ljg1MzI3MTQ4NDM3NSwxMjUuNjM3NjM0Mjc3MzQzNzUsNTYuODUzMjcxNDg0Mzc1LDEyMC44NzEzOTg5MjU3ODEyNSw1Ni44NTMyNzE0ODQzNzVaIi8+PC9nPjwvZz48ZyBpZD0ic2hhcGUtYjg3MThlYWQtNDU5Mi04MDVmLTgwMDctYTllZjU1ZjBhNDIyIj48ZyBjbGFzcz0iZmlsbHMiIGlkPSJmaWxscy1iODcxOGVhZC00NTkyLTgwNWYtODAwNy1hOWVmNTVmMGE0MjIiPjxwYXRoIGQ9Ik0xNTkuMDc5NTg5ODQzNzUsMzMuNDY5NDgyNDIxODc1TDEzOS45MzcyMjUzNDE3OTY4OCwzMy40Njk0ODI0MjE4NzVMMTM5LjkzNzIyNTM0MTc5Njg4LDYxLjI1OTc2NTYyNUwxNTkuMjY0NDA0Mjk2ODc1LDYxLjI1OTc2NTYyNUwxNTkuMjY0NDA0Mjk2ODc1LDU2Ljg1MzI3MTQ4NDM3NUwxNDQuNDQ1NTU2NjQwNjI1LDU2Ljg1MzI3MTQ4NDM3NUwxNDQuNDQ1NTU2NjQwNjI1LDQ5LjQyODk1NTA3ODEyNUwxNTcuNDE2NjU2NDk0MTQwNjIsNDkuNDI4OTU1MDc4MTI1TDE1Ny40MTY2NTY0OTQxNDA2Miw0NS4wMjI0NjA5Mzc1TDE0NC40NDU1NTY2NDA2MjUsNDUuMDIyNDYwOTM3NUwxNDQuNDQ1NTU2NjQwNjI1LDM3Ljg3NjIyMDcwMzEyNUwxNTkuMDc5NTg5ODQzNzUsMzcuODc2MjIwNzAzMTI1WiIvPjwvZz48L2c+PGcgaWQ9InNoYXBlLWI4NzE4ZWFkLTQ1OTItODA1Zi04MDA3LWE5ZWY1NWYwYTQyMyI+PGcgY2xhc3M9ImZpbGxzIiBpZD0iZmlsbHMtYjg3MThlYWQtNDU5Mi04MDVmLTgwMDctYTllZjU1ZjBhNDIzIj48cGF0aCBkPSJNMTgxLjIxNTI0MDQ3ODUxNTYyLDQyLjU0MTI1OTc2NTYyNUMxODEuMjE1MjQwNDc4NTE1NjIsNDMuOTc2ODA2NjQwNjI1LDE4MC43MzQ4MzI3NjM2NzE4OCw0NS4xMjE4MjYxNzE4NzUsMTc5Ljc2NzgyMjI2NTYyNSw0NS45Njg1MDU4NTkzNzVDMTc4LjgwNzA5ODM4ODY3MTg4LDQ2LjgyMjI2NTYyNSwxNzcuNTA3NDQ2Mjg5MDYyNSw0Ny4yNDUzNjEzMjgxMjUsMTc1Ljg3NTE4MzEwNTQ2ODc1LDQ3LjI0NTM2MTMyODEyNUwxNjkuMjA0ODY0NTAxOTUzMTIsNDcuMjQ1MzYxMzI4MTI1TDE2OS4yMDQ4NjQ1MDE5NTMxMiwzNy44NzYyMjA3MDMxMjVMMTc1LjgzODI4NzM1MzUxNTYyLDM3Ljg3NjIyMDcwMzEyNUMxNzcuNTQ0MzQyMDQxMDE1NjIsMzcuODc2MjIwNzAzMTI1LDE3OC44Njg0OTk3NTU4NTkzOCwzOC4yNjY2MDE1NjI1LDE3OS44MDQ5MDExMjMwNDY4OCwzOS4wNTM5NTUwNzgxMjVDMTgwLjc0NzIyMjkwMDM5MDYyLDM5LjgzNDk2MDkzNzUsMTgxLjIxNTI0MDQ3ODUxNTYyLDQwLjk5OTI2NzU3ODEyNSwxODEuMjE1MjQwNDc4NTE1NjIsNDIuNTQxMjU5NzY1NjI1Wk0xODYuNjQ3NDkxNDU1MDc4MTIsNjEuMjU5NzY1NjI1TDE3OS42NjMyMDgwMDc4MTI1LDUwLjczOTAxMzY3MTg3NUMxODAuNTc0NTg0OTYwOTM3NSw1MC40NzQzNjUyMzQzNzUsMTgxLjQwNjE4ODk2NDg0Mzc1LDUwLjA5NzY1NjI1LDE4Mi4xNTc3MTQ4NDM3NSw0OS42MDc2NjYwMTU2MjVDMTgyLjkwODkzNTU0Njg3NSw0OS4xMTgxNjQwNjI1LDE4My41NTU4MTY2NTAzOTA2Miw0OC41MjI0NjA5Mzc1LDE4NC4wOTc2ODY3Njc1NzgxMiw0Ny44MjEyODkwNjI1QzE4NC42Mzk4MzE1NDI5Njg3NSw0Ny4xMTk2Mjg5MDYyNSwxODUuMDY0NjY2NzQ4MDQ2ODgsNDYuMzEyNzQ0MTQwNjI1LDE4NS4zNzI2MTk2Mjg5MDYyNSw0NS4zOTk2NTgyMDMxMjVDMTg1LjY4MDQ4MDk1NzAzMTI1LDQ0LjQ4NjU3MjI2NTYyNSwxODUuODM0MzgxMTAzNTE1NjIsNDMuNDQ3NTA5NzY1NjI1LDE4NS44MzQzODExMDM1MTU2Miw0Mi4yODI5NTg5ODQzNzVDMTg1LjgzNDM4MTEwMzUxNTYyLDQwLjkzMzEwNTQ2ODc1LDE4NS42MTI3OTI5Njg3NSwzOS43MDkyMjg1MTU2MjUsMTg1LjE2OTI4MTAwNTg1OTM4LDM4LjYxMDU5NTcwMzEyNUMxODQuNzI1ODYwNTk1NzAzMTIsMzcuNTEyNDUxMTcxODc1LDE4NC4wOTE1ODMyNTE5NTMxMiwzNi41ODU5Mzc1LDE4My4yNjYzMjY5MDQyOTY4OCwzNS44MzE1NDI5Njg3NUMxODIuNDQwODg3NDUxMTcxODgsMzUuMDc3MzkyNTc4MTI1LDE4MS40MzA4Nzc2ODU1NDY4OCwzNC40OTUxMTcxODc1LDE4MC4yMzYwODM5ODQzNzUsMzQuMDg0NzE2Nzk2ODc1QzE3OS4wNDEwNDYxNDI1NzgxMiwzMy42NzQzMTY0MDYyNSwxNzcuNzA0NTI4ODA4NTkzNzUsMzMuNDY5NDgyNDIxODc1LDE3Ni4yMjY0NzA5NDcyNjU2MiwzMy40Njk0ODI0MjE4NzVMMTY0LjY5NjUzMzIwMzEyNSwzMy40Njk0ODI0MjE4NzVMMTY0LjY5NjUzMzIwMzEyNSw2MS4yNTk3NjU2MjVMMTY5LjIwNDg2NDUwMTk1MzEyLDYxLjI1OTc2NTYyNUwxNjkuMjA0ODY0NTAxOTUzMTIsNTEuNTcyOTk4MDQ2ODc1TDE3NC45MTQ0NTkyMjg1MTU2Miw1MS41NzI5OTgwNDY4NzVMMTgxLjI4OTAzMTk4MjQyMTg4LDYxLjI1OTc2NTYyNVoiLz48L2c+PC9nPjwvZz48L2c+PC9nPjwvZz48L2c+PC9nPjwvZz48L3N2Zz4=" alt="">
+</div>
+ <p class="qr-instruction">Scan this code with the Taler wallet on your phone.</p>
+ </section>
+ </div>
+</main>
+<div id="page-config" data-status-url="{{ order_status_url }}" hidden></div>
+<footer class="site-footer">
+ <p>Payments with privacy by <a href="https://taler.net/" rel="noreferrer" referrerpolicy="no-referrer">GNU Taler</a></p>
+ <p>Copyright © 2014–2026 Taler Systems SA</p>
+</footer>
+<script>
+(() => {
+ "use strict";
+ const config = document.getElementById("page-config");
+ let delay = 750;
+
+ async function poll() {
+ let statusUrl;
+ try {
+ statusUrl = new URL(config.dataset.statusUrl, window.location.href);
+ statusUrl.searchParams.set("await_refund_obtained", "yes");
+ statusUrl.searchParams.set("timeout_ms", "60000");
+ } catch (_) {
+ return;
+ }
+ try {
+ const response = await fetch(statusUrl, {
+ headers: { "Accept": "application/json" },
+ cache: "no-store",
+ credentials: "same-origin",
+ referrerPolicy: "no-referrer"
+ });
+ if (response.status === 200) {
+ const body = await response.json();
+ if (!body.refund_pending) {
+ window.location.reload();
+ return;
+ }
+ delay = 750;
+ } else {
+ delay = Math.min(delay * 2, 10000);
+ }
+ } catch (_) {
+ delay = Math.min(delay * 2, 10000);
+ }
+ window.setTimeout(poll, delay);
+ }
+ poll();
+})();
+</script>
+</body>
+</html>
diff --git a/src/frontend/request_payment.en.must b/src/frontend/request_payment.en.must
@@ -0,0 +1,228 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <meta name="referrer" content="no-referrer">
+ <meta name="taler-support" content="uri">
+ <meta name="taler-uri" content="{{ taler_pay_uri }}">
+ <noscript><meta http-equiv="refresh" content="5"></noscript>
+ <title>Pay {{ order_summary }} with GNU Taler</title>
+ <style>
+ :root {
+ color-scheme: light;
+ --taler-blue: #0042b3;
+ --taler-slate: #586a88;
+ --taler-ink: #172033;
+ --taler-muted: #64748b;
+ --taler-border: #d9dfeb;
+ --taler-panel: #f8f9fc;
+ --taler-qr-frame: #f1f1f4;
+ --taler-success: #147d55;
+ --taler-success-bg: #e9f7f1;
+ font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
+ font-synthesis: none;
+ }
+ * { box-sizing: border-box; }
+ html { min-width: 18rem; background: #fff; color: var(--taler-ink); }
+ body { min-height: 100vh; margin: 0; display: flex; flex-direction: column; }
+ a { color: var(--taler-blue); }
+ a:focus-visible, button:focus-visible { outline: .2rem solid #7aa7f5; outline-offset: .18rem; }
+ .site-header, .site-footer, main { width: min(72rem, calc(100% - 2rem)); margin-inline: auto; }
+ .site-header { min-height: 5.5rem; display: flex; align-items: center; border-bottom: 1px solid var(--taler-border); }
+ .brand { display: inline-flex; align-items: center; }
+ .brand img { display: block; width: 8.4rem; height: auto; }
+ main { flex: 1; display: grid; place-items: center; padding: 3.5rem 0; }
+ .page-grid { width: 100%; display: grid; grid-template-columns: minmax(18rem, 25rem) minmax(20rem, 1fr); gap: clamp(2.5rem, 7vw, 7rem); align-items: center; }
+ .eyebrow { margin: 0 0 .55rem; color: var(--taler-blue); font-size: .78rem; font-weight: 750; letter-spacing: .1em; text-transform: uppercase; }
+ h1 { max-width: 18ch; margin: 0; font-size: clamp(2rem, 4.5vw, 3.5rem); line-height: 1.08; letter-spacing: -.035em; }
+ .lede { max-width: 36rem; margin: 1rem 0 0; color: var(--taler-slate); font-size: 1.08rem; line-height: 1.65; }
+ .amount { margin: 1.8rem 0 .2rem; color: var(--taler-blue); font-size: clamp(2.1rem, 5vw, 3rem); font-weight: 780; line-height: 1.05; letter-spacing: -.025em; overflow-wrap: anywhere; }
+ .amount-note { margin: .55rem 0 0; color: var(--taler-slate); font-size: 1rem; }
+ .details { margin: 2rem 0 0; display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: .8rem 1.25rem; }
+ .details dt { color: var(--taler-muted); }
+ .details dd { margin: 0; font-weight: 620; overflow-wrap: anywhere; }
+ .action { display: inline-flex; min-height: 3rem; margin-top: 1.75rem; padding: .75rem 1.2rem; align-items: center; justify-content: center; border-radius: .55rem; background: var(--taler-blue); color: #fff; font-weight: 720; text-decoration: none; box-shadow: 0 .35rem 1rem rgb(0 66 179 / 20%); }
+ .action:hover { background: #003994; }
+ .wallet-help { margin: 1rem 0 0; color: var(--taler-muted); font-size: .92rem; }
+ .qr-column { display: grid; justify-items: center; gap: 1rem; }
+ .qr-instruction { margin: 0; max-width: 26rem; color: var(--taler-slate); text-align: center; line-height: 1.5; }
+ .qr-frame { position: relative; width: min(100%, 25rem); aspect-ratio: 1; padding: 6.25%; overflow: hidden; border-radius: 8%; background: var(--taler-qr-frame); }
+ .qr-code { width: 100%; height: 100%; background: #fff; }
+ .qr-code > svg { display: block; width: 100%; height: 100%; fill: #000; }
+ .qr-motion { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
+ .qr-motion rect { fill: none; stroke: url(#taler-scan-gradient); stroke-width: 2.6; stroke-linecap: round; stroke-dasharray: 57 343; animation: scan 4s linear infinite; }
+ .qr-motion rect + rect { animation-delay: -2s; }
+ .qr-badge { position: absolute; inset: 50% auto auto 50%; height: 12.5%; width: auto; transform: translate(-50%, -50%); }
+ @keyframes scan { to { stroke-dashoffset: -400; } }
+ .claimed { width: min(100%, 25rem); aspect-ratio: 1; display: grid; place-items: center; padding: 2.5rem; border-radius: 8%; background: var(--taler-qr-frame); text-align: center; }
+ .claimed-icon { width: 4.25rem; height: 4.25rem; margin: 0 auto 1.3rem; display: grid; place-items: center; border-radius: 50%; background: var(--taler-blue); color: #fff; font-size: 2rem; }
+ .claimed h2 { margin: 0; font-size: 1.35rem; }
+ .claimed p { margin: .65rem 0 0; color: var(--taler-slate); line-height: 1.55; }
+ .site-footer { padding: 1.5rem 0 2rem; display: flex; flex-wrap: wrap; justify-content: space-between; gap: .6rem 1.5rem; border-top: 1px solid var(--taler-border); color: var(--taler-muted); font-size: .82rem; }
+ .site-footer p { margin: 0; }
+ .site-footer a { color: inherit; }
+ .status-card { width: min(44rem, 100%); padding: clamp(1.4rem, 4vw, 3rem); border: 1px solid var(--taler-border); border-radius: 1rem; background: #fff; box-shadow: 0 1rem 3rem rgb(30 48 80 / 8%); }
+ .status-mark { width: 3.5rem; height: 3.5rem; margin-bottom: 1.4rem; display: grid; place-items: center; border-radius: 50%; background: var(--taler-success-bg); color: var(--taler-success); font-size: 1.65rem; font-weight: 800; }
+ .message { margin: 1.7rem 0 0; padding: 1rem 1.1rem; border-left: .25rem solid var(--taler-blue); border-radius: .2rem .5rem .5rem .2rem; background: #f1f5ff; line-height: 1.55; }
+ .secondary-link { display: inline-block; margin-top: 1.3rem; font-weight: 650; overflow-wrap: anywhere; }
+ [hidden] { display: none !important; }
+ @media (max-width: 47rem) {
+ .site-header { min-height: 4.5rem; }
+ .brand img { width: 7rem; }
+ main { padding: 2.25rem 0 3rem; place-items: start center; }
+ .page-grid { grid-template-columns: 1fr; gap: 2.5rem; }
+ .qr-column { grid-row: 1; }
+ .copy-column { grid-row: 2; }
+ h1 { font-size: clamp(2rem, 10vw, 3rem); }
+ .details { grid-template-columns: 1fr; gap: .25rem; }
+ .details dd { margin-bottom: .75rem; }
+ .action { width: 100%; }
+ .site-footer { flex-direction: column; }
+ }
+ @media (prefers-reduced-motion: reduce) {
+ .qr-motion rect { animation: none; }
+ .qr-motion rect + rect { stroke-dashoffset: -200; }
+ }
+</style>
+</head>
+<body>
+<header class="site-header">
+ <a class="brand" href="https://taler.net/" rel="noreferrer" referrerpolicy="no-referrer" aria-label="GNU Taler">
+ <img src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBoZWlnaHQ9IjQ0Ny43NjEiIGlkPSJzY3JlZW5zaG90LTUwZWRmYjcyLTU4YzMtODA2ZC04MDA3LTljZWU5ZmI3N2FiZSIgdmlld0JveD0iMCAwIDEwMDAgNDQ3Ljc2MSIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIGZpbGw9Im5vbmUiIHZlcnNpb249IjEuMSI+PGcgaWQ9InNoYXBlLTUwZWRmYjcyLTU4YzMtODA2ZC04MDA3LTljZWU5ZmI3N2FiZSIgd2lkdGg9IjY3MCIgaGVpZ2h0PSIzMDAiIHJ4PSIwIiByeT0iMCIgc3R5bGU9ImZpbGw6IHJnYigwLCAwLCAwKTsiPjxnIGlkPSJzaGFwZS01MGVkZmI3Mi01OGMzLTgwNmQtODAwNy05Y2VlOWZiNzdhYmYiIHN0eWxlPSJkaXNwbGF5OiBub25lOyI+PGcgY2xhc3M9ImZpbGxzIiBpZD0iZmlsbHMtNTBlZGZiNzItNThjMy04MDZkLTgwMDctOWNlZTlmYjc3YWJmIj48cmVjdCB3aWR0aD0iMTAwMCIgaGVpZ2h0PSI0NDcuNzYxMTk0MDI5ODUwNyIgeD0iMCIgdHJhbnNmb3JtPSJtYXRyaXgoMS4wMDAwMDAsIDAuMDAwMDAwLCAwLjAwMDAwMCwgMS4wMDAwMDAsIDAuMDAwMDAwLCAwLjAwMDAwMCkiIHN0eWxlPSJmaWxsOiBub25lOyIgcnk9IjAiIGZpbGw9Im5vbmUiIHJ4PSIwIiB5PSIwIi8+PC9nPjwvZz48ZyBpZD0ic2hhcGUtNTBlZGZiNzItNThjMy04MDZkLTgwMDctOWNlZTlmYjc3YWMwIiByeD0iMCIgcnk9IjAiIHN0eWxlPSJmaWxsOiByZ2IoMCwgMCwgMCk7Ij48ZyBpZD0ic2hhcGUtNTBlZGZiNzItNThjMy04MDZkLTgwMDctOWNlZTlmYjc3YWM2Ij48ZyBjbGFzcz0iZmlsbHMiIGlkPSJmaWxscy01MGVkZmI3Mi01OGMzLTgwNmQtODAwNy05Y2VlOWZiNzdhYzYiPjxwYXRoIGQ9Ik00MzEuMTU1LDUuNTc4QzUwOC43MTYsNS41NzgsNTc2LjA3Nyw1Mi4zNTAsNjEwLjA2NiwxMjEuMDEwTDU4MS4xMjMsMTIxLjAxMEM1NDkuNjg1LDY3Ljc3OCw0OTQuMjc0LDMyLjQyOCw0MzEuMTU1LDMyLjQyOEMzMzMuMTkyLDMyLjQyOCwyNTMuNzc3LDExNy41NjMsMjUzLjc3NywyMjIuNTgwQzI1My43NzcsMjczLjk4MiwyNzIuODEwLDMyMC42MTQsMzAzLjcyNiwzNTQuODM0QzI5Ny4wNDcsMzYwLjQxMSwyODkuOTM3LDM2NS40MjAsMjgyLjQ1NSwzNjkuNzkzQzI0OS4xMTIsMzMxLjExMiwyMjguNzMxLDI3OS40MDMsMjI4LjczMSwyMjIuNTgwQzIyOC43MzEsMTAyLjczNCwzMTkuMzU5LDUuNTc4LDQzMS4xNTUsNS41NzhaWk02MDkuNTIzLDMyNS4yNTNDNTc1LjM2MiwzOTMuMzE0LDUwOC4zMDEsNDM5LjU4Myw0MzEuMTU1LDQzOS41ODNDNDI1LjkxOCw0MzkuNTgzLDQyMC43MjcsNDM5LjM2OSw0MTUuNTg5LDQzOC45NTFDNDMwLjc3NCw0MzEuMTg0LDQ0NS4wMTAsNDIxLjYzNSw0NTguMDY5LDQxMC41NTZDNTA5LjQxNyw0MDIuMTc2LDU1My41MjEsMzcwLjE5MCw1ODAuNDY2LDMyNS4yNTNaIiBzdHlsZT0iZmlsbC1ydWxlOiBldmVub2RkOyBzdHJva2U6IG5vbmU7IHN0cm9rZS13aWR0aDogMC4zMjc5NDM7IGZpbGw6IHJnYigwLCA2NiwgMTc5KTsgZmlsbC1vcGFjaXR5OiAxOyIvPjwvZz48L2c+PGcgaWQ9InNoYXBlLTUwZWRmYjcyLTU4YzMtODA2ZC04MDA3LTljZWU5ZmI3N2FjNyI+PGcgY2xhc3M9ImZpbGxzIiBpZD0iZmlsbHMtNTBlZGZiNzItNThjMy04MDZkLTgwMDctOWNlZTlmYjc3YWM3Ij48cGF0aCBkPSJNMzE5LjQ2NSw1LjU3OEMzMjQuNzAxLDUuNTc4LDMyOS44OTIsNS43OTIsMzM1LjAzMCw2LjIxMEMzMTkuODQ1LDEzLjk3NywzMDUuNjA5LDIzLjUyNSwyOTIuNTUxLDM0LjYwNUMyMDcuMzYxLDQ4LjUwNywxNDIuMDg3LDEyNy4zNzEsMTQyLjA4NywyMjIuNTgwQzE0Mi4wODcsMjkzLjU0OCwxNzguMzU5LDM1NS40MjYsMjMyLjEwNiwzODguMDk3QzIyNC4xNzgsMzg5LjQyNywyMTYuMDUyLDM5MC4xMjIsMjA3Ljc3NCwzOTAuMTIyQzIwMS42MDcsMzkwLjEyMiwxOTUuNTI4LDM4OS43MjYsMTg5LjU0OCwzODguOTgxQzE0NS4yMjksMzQ5LjE3NCwxMTcuMDQwLDI4OS40MTEsMTE3LjA0MCwyMjIuNTgwQzExNy4wNDAsMTAyLjczNCwyMDcuNjY5LDUuNTc4LDMxOS40NjUsNS41NzhaWk0zNDYuMzc5LDQxMC41NTZDMzk3LjcyNyw0MDIuMTc2LDQ0MS44MzIsMzcwLjE4OCw0NjguNzc2LDMyNS4yNTFMNDk3LjgzNCwzMjUuMjUxQzQ2My42NzMsMzkzLjMxMiwzOTYuNjEyLDQzOS41ODMsMzE5LjQ2NSw0MzkuNTgzQzMxNC4yMjcsNDM5LjU4MywzMDkuMDM3LDQzOS4zNjksMzAzLjg5OSw0MzguOTUxQzMxOS4wODMsNDMxLjE4MywzMzMuMzIxLDQyMS42MzYsMzQ2LjM3OSw0MTAuNTU2WlpNNDY5LjQzMiwxMjEuMDEwQzQ1My44MTMsOTQuNTY5LDQzMi4yODAsNzIuNTM5LDQwNi44MjMsNTcuMDYzQzQxNC43NTEsNTUuNzM0LDQyMi44NzcsNTUuMDM5LDQzMS4xNTUsNTUuMDM5QzQzNy4zMjEsNTUuMDM5LDQ0My40MDEsNTUuNDM0LDQ0OS4zODEsNTYuMTgwQzQ2OS4zNjIsNzQuMTI2LDQ4Ni4wNjQsOTYuMTMxLDQ5OC4zODIsMTIxLjAxMFoiIHN0eWxlPSJmaWxsLXJ1bGU6IGV2ZW5vZGQ7IHN0cm9rZTogbm9uZTsgc3Ryb2tlLXdpZHRoOiAwLjMyNzk0MzsgZmlsbDogcmdiKDAsIDY2LCAxNzkpOyBmaWxsLW9wYWNpdHk6IDE7Ii8+PC9nPjwvZz48ZyBpZD0ic2hhcGUtNTBlZGZiNzItNThjMy04MDZkLTgwMDctOWNlZTlmYjc3YWM4Ij48ZyBjbGFzcz0iZmlsbHMiIGlkPSJmaWxscy01MGVkZmI3Mi01OGMzLTgwNmQtODAwNy05Y2VlOWZiNzdhYzgiPjxwYXRoIGQ9Ik0yMDcuNzc0LDUuNTc4QzIxMy4wNjksNS41NzgsMjE4LjMxNSw1Ljc5OSwyMjMuNTA4LDYuMjI2QzIwOC4zNTIsMTMuOTgyLDE5NC4xMzksMjMuNTEyLDE4MS4xMDMsMzQuNTY4Qzk1Ljc5NCw0OC4zNjEsMzAuMzk3LDEyNy4yODEsMzAuMzk3LDIyMi41ODBDMzAuMzk3LDMyNy41OTgsMTA5LjgxMiw0MTIuNzMyLDIwNy43NzQsNDEyLjczMkMyNzAuNDU5LDQxMi43MzIsMzI1LjU0NywzNzcuODcxLDM1Ny4wOTYsMzI1LjI1MUwzODYuMTQ0LDMyNS4yNTFDMzUxLjk4MywzOTMuMzEyLDI4NC45MjIsNDM5LjU4MywyMDcuNzc0LDQzOS41ODNDOTUuOTc5LDQzOS41ODMsNS4zNTAsMzQyLjQyNyw1LjM1MCwyMjIuNTgwQzUuMzUwLDEwMi43MzQsOTUuOTc5LDUuNTc4LDIwNy43NzQsNS41NzhaWk0zNTcuNzM4LDEyMS4wMTBDMzUxLjIxMSwxMDkuOTYyLDM0My42NTQsOTkuNjgxLDMzNS4yMDYsOTAuMzMxQzM0MS44ODUsODQuNzU0LDM0OC45OTQsNzkuNzQyLDM1Ni40NzYsNzUuMzY5QzM2OC4yODIsODkuMDY2LDM3OC40NjAsMTA0LjM5NywzODYuNjg3LDEyMS4wMTBaIiBzdHlsZT0iZmlsbC1ydWxlOiBldmVub2RkOyBzdHJva2U6IG5vbmU7IHN0cm9rZS13aWR0aDogMC4zMjc5NDM7IGZpbGw6IHJnYigwLCA2NiwgMTc5KTsgZmlsbC1vcGFjaXR5OiAxOyIvPjwvZz48L2c+PC9nPjxnIGlkPSJzaGFwZS01MGVkZmI3Mi01OGMzLTgwNmQtODAwNy05Y2VlOWZiNzdhYzEiPjxnIGNsYXNzPSJmaWxscyIgaWQ9ImZpbGxzLTUwZWRmYjcyLTU4YzMtODA2ZC04MDA3LTljZWU5ZmI3N2FjMSI+PHBhdGggZD0iTTM3OC43ODMsMTcxLjE4OUw0MjQuMzYwLDE3MS4xODlMNDI0LjM2MCwxNDYuMDk5TDMwNy43NDksMTQ2LjA5OUwzMDcuNzQ5LDE3MS4xODlMMzUzLjMyNywxNzEuMTg5TDM1My4zMjcsMzAwLjE2MEwzNzguNzgzLDMwMC4xNjBaIi8+PC9nPjwvZz48ZyBpZD0ic2hhcGUtNTBlZGZiNzItNThjMy04MDZkLTgwMDctOWNlZTlmYjc3YWMyIj48ZyBjbGFzcz0iZmlsbHMiIGlkPSJmaWxscy01MGVkZmI3Mi01OGMzLTgwNmQtODAwNy05Y2VlOWZiNzdhYzIiPjxwYXRoIGQ9Ik00NjAuOTMzLDI2Mi45NjdMNTI4Ljg4OCwyNjIuOTY3TDU0My40NjYsMzAwLjE2MUw1NzAuMTU2LDMwMC4xNjFMNTA2LjkyMSwxNDUuMDAwTDQ4My41MTgsMTQ1LjAwMEw0MjAuMjg0LDMwMC4xNjFMNDQ2LjE1MiwzMDAuMTYxWk01MTkuNjUwLDIzOC45NzVMNDcwLjE3NCwyMzguOTc1TDQ5NC44MDksMTc3LjM1MVoiLz48L2c+PC9nPjxnIGlkPSJzaGFwZS01MGVkZmI3Mi01OGMzLTgwNmQtODAwNy05Y2VlOWZiNzdhYzMiPjxnIGNsYXNzPSJmaWxscyIgaWQ9ImZpbGxzLTUwZWRmYjcyLTU4YzMtODA2ZC04MDA3LTljZWU5ZmI3N2FjMyI+PHBhdGggZD0iTTYxNS45NTIsMTQ2LjEwMEw1OTMuMTY0LDE0Ni4xMDBMNTkzLjE2NCwzMDAuMTYxTDY5NS4zOTAsMzAwLjE2MUw2OTUuMzkwLDI3NS43MzJDNjY4LjkxMSwyNzUuNzMyLDY0Mi40MzEsMjc1LjczMiw2MTUuOTUyLDI3NS43MzJaIi8+PC9nPjwvZz48ZyBpZD0ic2hhcGUtNTBlZGZiNzItNThjMy04MDZkLTgwMDctOWNlZTlmYjc3YWM0Ij48ZyBjbGFzcz0iZmlsbHMiIGlkPSJmaWxscy01MGVkZmI3Mi01OGMzLTgwNmQtODAwNy05Y2VlOWZiNzdhYzQiPjxwYXRoIGQ9Ik04MjguMjIwLDE0Ni4xMDBMNzIxLjg3MywxNDYuMTAwTDcyMS44NzMsMzAwLjE2MUw4MjkuMjQ3LDMwMC4xNjFMODI5LjI0NywyNzUuNzMyTDc0Ni45MjAsMjc1LjczMkw3NDYuOTIwLDIzNC41NzRMODE4Ljk4MSwyMzQuNTc0TDgxOC45ODEsMjEwLjE0Nkw3NDYuOTIwLDIxMC4xNDZMNzQ2LjkyMCwxNzAuNTMwTDgyOC4yMjAsMTcwLjUzMFoiLz48L2c+PC9nPjxnIGlkPSJzaGFwZS01MGVkZmI3Mi01OGMzLTgwNmQtODAwNy05Y2VlOWZiNzdhYzUiPjxnIGNsYXNzPSJmaWxscyIgaWQ9ImZpbGxzLTUwZWRmYjcyLTU4YzMtODA2ZC04MDA3LTljZWU5ZmI3N2FjNSI+PHBhdGggZD0iTTk1MS4xOTYsMTk2LjM5MUM5NTEuMTk2LDIwNC4zNDksOTQ4LjUyNywyMTAuNjk2LDk0My4xNTUsMjE1LjM5MEM5MzcuODE3LDIyMC4xMjMsOTMwLjU5NywyMjIuNDY5LDkyMS41MjksMjIyLjQ2OUw4ODQuNDcyLDIyMi40NjlMODg0LjQ3MiwxNzAuNTMwTDkyMS4zMjQsMTcwLjUzMEM5MzAuODAyLDE3MC41MzAsOTM4LjE1OCwxNzIuNjk0LDk0My4zNjEsMTc3LjA1OEM5NDguNTk2LDE4MS4zODcsOTUxLjE5NiwxODcuODQzLDk1MS4xOTYsMTk2LjM5MVpaTTk4MS4zNzUsMzAwLjE2MUw5NDIuNTczLDI0MS44MzdDOTQ3LjYzNywyNDAuMzcwLDk1Mi4yNTcsMjM4LjI4MSw5NTYuNDMyLDIzNS41NjVDOTYwLjYwNSwyMzIuODUxLDk2NC4xOTksMjI5LjU0OSw5NjcuMjA5LDIyNS42NjJDOTcwLjIyMSwyMjEuNzczLDk3Mi41ODIsMjE3LjI5OCw5NzQuMjkyLDIxMi4yMzdDOTc2LjAwMywyMDcuMTc1LDk3Ni44NTgsMjAxLjQxNSw5NzYuODU4LDE5NC45NTlDOTc2Ljg1OCwxODcuNDc2LDk3NS42MjcsMTgwLjY5MSw5NzMuMTYzLDE3NC42MDFDOTcwLjY5OSwxNjguNTEyLDk2Ny4xNzUsMTYzLjM3Niw5NjIuNTkxLDE1OS4xOTRDOTU4LjAwNSwxNTUuMDEzLDk1Mi4zOTQsMTUxLjc4NSw5NDUuNzU2LDE0OS41MTBDOTM5LjExNywxNDcuMjM1LDkzMS42OTIsMTQ2LjEwMCw5MjMuNDgwLDE0Ni4xMDBMODU5LjQyNSwxNDYuMTAwTDg1OS40MjUsMzAwLjE2MUw4ODQuNDcyLDMwMC4xNjFMODg0LjQ3MiwyNDYuNDYwTDkxNi4xOTEsMjQ2LjQ2MEw5NTEuNjA2LDMwMC4xNjFaIi8+PC9nPjwvZz48L2c+PC9zdmc+" alt="GNU Taler">
+ </a>
+</header>
+<main>
+ <div class="page-grid">
+ <section class="copy-column" aria-labelledby="page-title">
+ <p class="eyebrow">{{ merchant_name }}</p>
+ <h1 id="page-title">Pay with GNU Taler</h1>
+ <p class="lede">{{ order_summary }}</p>
+ {{#order_amount}}<p class="amount">{{ order_amount }}</p>{{/order_amount}}
+ {{#multiple_payment_options}}<p class="amount-note">The amount and payment option are selected in your wallet.</p>{{/multiple_payment_options}}
+ <dl class="details">
+ <dt>Merchant</dt><dd>{{ merchant_name }}</dd>
+ <dt>Order ID</dt><dd>{{ order_id }}</dd>
+ <dt>Pay before</dt><dd><time id="pay-deadline" data-epoch="{{ pay_deadline.t_s }}">{{ pay_deadline.t_s }}</time></dd>
+ </dl>
+ <a id="wallet-link" class="action" href="{{ taler_pay_uri }}">Open Taler wallet</a>
+ <p class="wallet-help">No wallet yet? <a href="https://wallet.taler.net/" rel="noreferrer" referrerpolicy="no-referrer">Get a Taler wallet</a>.</p>
+ </section>
+ <section class="qr-column" aria-live="polite">
+ {{^claimed}}
+ <div class="qr-frame" aria-label="QR code for the Taler wallet">
+ <div class="qr-code">{{{ taler_pay_qrcode_svg }}}</div>
+ <svg class="qr-motion" viewBox="0 0 100 100" aria-hidden="true" focusable="false">
+ <defs><linearGradient id="taler-scan-gradient"><stop offset="0" stop-color="#f1f1f4"/><stop offset=".5" stop-color="#0042b3"/><stop offset="1" stop-color="#f1f1f4"/></linearGradient></defs>
+ <rect x="1.3" y="1.3" width="97.4" height="97.4" rx="8" pathLength="400"/>
+ <rect x="1.3" y="1.3" width="97.4" height="97.4" rx="8" pathLength="400"/>
+ </svg>
+ <img class="qr-badge" src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iOTUiIGlkPSJzY3JlZW5zaG90LWI4NzE4ZWFkLTQ1OTItODA1Zi04MDA3LWE5ZWY1NWYwYTQxYiIgdmlld0JveD0iMCAwIDIwMCA5NSIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIGZpbGw9Im5vbmUiIHZlcnNpb249IjEuMSI+PGcgaWQ9InNoYXBlLWI4NzE4ZWFkLTQ1OTItODA1Zi04MDA3LWE5ZWY1NWYwYTQxYiI+PGcgY2xhc3M9ImZyYW1lLWNvbnRhaW5lci13cmFwcGVyIj48ZyBjbGFzcz0iZnJhbWUtY29udGFpbmVyLWJsdXIiPjxnIGNsYXNzPSJmcmFtZS1jb250YWluZXItc2hhZG93cyI+PGcgZmlsbD0ibm9uZSI+PGcgY2xhc3M9ImZpbGxzIiBpZD0iZmlsbHMtYjg3MThlYWQtNDU5Mi04MDVmLTgwMDctYTllZjU1ZjBhNDFiIj48cmVjdCB3aWR0aD0iMjAwIiBoZWlnaHQ9Ijk1IiBjbGFzcz0iZnJhbWUtYmFja2dyb3VuZCIgeD0iMCIgdHJhbnNmb3JtPSJtYXRyaXgoMS4wMDAwMDAsIDAuMDAwMDAwLCAwLjAwMDAwMCwgMS4wMDAwMDAsIDAuMDAwMDAwLCAwLjAwMDAwMCkiIHN0eWxlPSJmaWxsOiByZ2IoMjU1LCAyNTUsIDI1NSk7IGZpbGwtb3BhY2l0eTogMTsiIHJ5PSI0Ny41IiByeD0iNDcuNSIgeT0iMCIvPjwvZz48ZyBjbGFzcz0iZnJhbWUtY2hpbGRyZW4iPjxnIGlkPSJzaGFwZS1iODcxOGVhZC00NTkyLTgwNWYtODAwNy1hOWVmNTVmMGE0MWMiIHdpZHRoPSI2NzAiIGhlaWdodD0iMzAwIiByeD0iMCIgcnk9IjAiIHN0eWxlPSJmaWxsOiByZ2IoMCwgMCwgMCk7Ij48ZyBpZD0ic2hhcGUtYjg3MThlYWQtNDU5Mi04MDVmLTgwMDctYTllZjU1ZjBhNDFkIiBzdHlsZT0iZGlzcGxheTogbm9uZTsiPjxnIGNsYXNzPSJmaWxscyIgaWQ9ImZpbGxzLWI4NzE4ZWFkLTQ1OTItODA1Zi04MDA3LWE5ZWY1NWYwYTQxZCI+PHJlY3Qgd2lkdGg9IjE4MCIgaGVpZ2h0PSI4MC43NjkyMzA3NjkyMzA5NCIgeD0iMTAiIHRyYW5zZm9ybT0ibWF0cml4KDEuMDAwMDAwLCAwLjAwMDAwMCwgMC4wMDAwMDAsIDEuMDAwMDAwLCAwLjAwMDAwMCwgMC4wMDAwMDApIiBzdHlsZT0iZmlsbDogbm9uZTsiIHJ5PSIwIiBmaWxsPSJub25lIiByeD0iMCIgeT0iNy4xMTUzODQ2MTUzODQzMDEiLz48L2c+PC9nPjxnIGlkPSJzaGFwZS1iODcxOGVhZC00NTkyLTgwNWYtODAwNy1hOWVmNTVmMGE0MWUiIHJ4PSIwIiByeT0iMCIgc3R5bGU9ImZpbGw6IHJnYigwLCAwLCAwKTsiPjxnIGlkPSJzaGFwZS1iODcxOGVhZC00NTkyLTgwNWYtODAwNy1hOWVmNTVmMGE0MjQiPjxnIGNsYXNzPSJmaWxscyIgaWQ9ImZpbGxzLWI4NzE4ZWFkLTQ1OTItODA1Zi04MDA3LWE5ZWY1NWYwYTQyNCI+PHBhdGggZD0iTTg3LjYwNzkxMDE1NjI1LDguMTIxNTgyMDMxMjVDMTAxLjU2ODgxNzEzODY3MTg4LDguMTIxNTgyMDMxMjUsMTEzLjY5Mzc4NjYyMTA5Mzc1LDE2LjU1ODU5Mzc1LDExOS44MTE3OTgwOTU3MDMxMiwyOC45NDM2MDM1MTU2MjVMMTE0LjYwMjIzMzg4NjcxODc1LDI4Ljk0MzYwMzUxNTYyNUMxMDguOTQzMjM3MzA0Njg3NSwxOS4zNDEzMDg1OTM3NSw5OC45NjkyNjg3OTg4MjgxMiwxMi45NjQ4NDM3NSw4Ny42MDc5MTAxNTYyNSwxMi45NjQ4NDM3NUM2OS45NzQ1NDgzMzk4NDM3NSwxMi45NjQ4NDM3NSw1NS42Nzk5NjIxNTgyMDMxMjUsMjguMzIxNzc3MzQzNzUsNTUuNjc5OTYyMTU4MjAzMTI1LDQ3LjI2NTM4MDg1OTM3NUM1NS42Nzk5NjIxNTgyMDMxMjUsNTYuNTM3NTk3NjU2MjUsNTkuMTA1ODY1NDc4NTE1NjI1LDY0Ljk0OTIxODc1LDY0LjY3MDYyMzc3OTI5Njg4LDcxLjEyMTgyNjE3MTg3NUM2My40Njg1MDU4NTkzNzUsNzIuMTI3OTI5Njg3NSw2Mi4xODg2MjkxNTAzOTA2MjUsNzMuMDMxNDk0MTQwNjI1LDYwLjg0MTgyNzM5MjU3ODEyNSw3My44MjAzMTI1QzU0Ljg0MDE0ODkyNTc4MTI1LDY2Ljg0Mjc3MzQzNzUsNTEuMTcxNTA4Nzg5MDYyNSw1Ny41MTUzODA4NTkzNzUsNTEuMTcxNTA4Nzg5MDYyNSw0Ny4yNjUzODA4NTkzNzVDNTEuMTcxNTA4Nzg5MDYyNSwyNS42NDY5NzI2NTYyNSw2Ny40ODQ2NDk2NTgyMDMxMiw4LjEyMTU4MjAzMTI1LDg3LjYwNzkxMDE1NjI1LDguMTIxNTgyMDMxMjVaTTExOS43MTQxNzIzNjMyODEyNSw2NS43ODYxMzI4MTI1QzExMy41NjUxMjQ1MTE3MTg3NSw3OC4wNjI5ODgyODEyNSwxMDEuNDk0MjMyMTc3NzM0MzgsODYuNDA5NDIzODI4MTI1LDg3LjYwNzkxMDE1NjI1LDg2LjQwOTQyMzgyODEyNUM4Ni42NjUxOTE2NTAzOTA2Miw4Ni40MDk0MjM4MjgxMjUsODUuNzMwODA0NDQzMzU5MzgsODYuMzcwODQ5NjA5Mzc1LDg0LjgwNjA5MTMwODU5Mzc1LDg2LjI5NTQxMDE1NjI1Qzg3LjUzOTM5ODE5MzM1OTM4LDg0Ljg5NDI4NzEwOTM3NSw5MC4xMDE4MzcxNTgyMDMxMiw4My4xNzE4NzUsOTIuNDUyMzMxNTQyOTY4NzUsODEuMTczMzM5ODQzNzVDMTAxLjY5NDk3NjgwNjY0MDYyLDc5LjY2MTg2NTIzNDM3NSwxMDkuNjMzODE5NTgwMDc4MTIsNzMuODkxODQ1NzAzMTI1LDExNC40ODM4MjU2ODM1OTM3NSw2NS43ODYxMzI4MTI1WiIgc3R5bGU9ImZpbGwtcnVsZTogZXZlbm9kZDsgc3Ryb2tlOiBub25lOyBzdHJva2Utd2lkdGg6IDAuMzI3OTQzOyBmaWxsOiByZ2IoMCwgNjYsIDE3OSk7IGZpbGwtb3BhY2l0eTogMTsiLz48L2c+PC9nPjxnIGlkPSJzaGFwZS1iODcxOGVhZC00NTkyLTgwNWYtODAwNy1hOWVmNTVmMGE0MjUiPjxnIGNsYXNzPSJmaWxscyIgaWQ9ImZpbGxzLWI4NzE4ZWFkLTQ1OTItODA1Zi04MDA3LWE5ZWY1NWYwYTQyNSI+PHBhdGggZD0iTTY3LjUwMzYzMTU5MTc5Njg4LDguMTIxNTgyMDMxMjVDNjguNDQ2MjU4NTQ0OTIxODgsOC4xMjE1ODIwMzEyNSw2OS4zODA2MTUyMzQzNzUsOC4xNjAxNTYyNSw3MC4zMDU0MTk5MjE4NzUsOC4yMzU1OTU3MDMxMjVDNjcuNTcyMTEzMDM3MTA5MzgsOS42MzY3MTg3NSw2NS4wMDk1ODI1MTk1MzEyNSwxMS4zNTg4ODY3MTg3NSw2Mi42NTkwODgxMzQ3NjU2MjUsMTMuMzU3NjY2MDE1NjI1QzQ3LjMyNDk1MTE3MTg3NSwxNS44NjUyMzQzNzUsMzUuNTc1NjUzMDc2MTcxODc1LDMwLjA5MTA2NDQ1MzEyNSwzNS41NzU2NTMwNzYxNzE4NzUsNDcuMjY1MzgwODU5Mzc1QzM1LjU3NTY1MzA3NjE3MTg3NSw2MC4wNjY4OTQ1MzEyNSw0Mi4xMDQ1NTMyMjI2NTYyNSw3MS4yMjg3NTk3NjU2MjUsNTEuNzc5MTEzNzY5NTMxMjUsNzcuMTIyMDcwMzEyNUM1MC4zNTE5NTkyMjg1MTU2MjUsNzcuMzYyMDYwNTQ2ODc1LDQ4Ljg4OTI4MjIyNjU2MjUsNzcuNDg3MzA0Njg3NSw0Ny4zOTkzMjI1MDk3NjU2MjUsNzcuNDg3MzA0Njg3NUM0Ni4yODkzMDY2NDA2MjUsNzcuNDg3MzA0Njg3NSw0NS4xOTUwMDczMjQyMTg3NSw3Ny40MTYwMTU2MjUsNDQuMTE4NTYwNzkxMDE1NjI1LDc3LjI4MTQ5NDE0MDYyNUMzNi4xNDEyOTYzODY3MTg3NSw3MC4xMDEwNzQyMTg3NSwzMS4wNjcyMzAyMjQ2MDkzNzUsNTkuMzIwODAwNzgxMjUsMzEuMDY3MjMwMjI0NjA5Mzc1LDQ3LjI2NTM4MDg1OTM3NUMzMS4wNjcyMzAyMjQ2MDkzNzUsMjUuNjQ2OTcyNjU2MjUsNDcuMzgwMzcxMDkzNzUsOC4xMjE1ODIwMzEyNSw2Ny41MDM2MzE1OTE3OTY4OCw4LjEyMTU4MjAzMTI1Wk03Mi4zNDgxNDQ1MzEyNSw4MS4xNzMzMzk4NDM3NUM4MS41OTA5NDIzODI4MTI1LDc5LjY2MTg2NTIzNDM3NSw4OS41Mjk2OTM2MDM1MTU2Miw3My44OTE2MDE1NjI1LDk0LjM3OTc2MDc0MjE4NzUsNjUuNzg1NjQ0NTMxMjVMOTkuNjEwMDc2OTA0Mjk2ODgsNjUuNzg1NjQ0NTMxMjVDOTMuNDYxMDkwMDg3ODkwNjIsNzguMDYyNzQ0MTQwNjI1LDgxLjM5MDE2NzIzNjMyODEyLDg2LjQwOTQyMzgyODEyNSw2Ny41MDM2MzE1OTE3OTY4OCw4Ni40MDk0MjM4MjgxMjVDNjYuNTYwODgyNTY4MzU5MzgsODYuNDA5NDIzODI4MTI1LDY1LjYyNjYxNzQzMTY0MDYyLDg2LjM3MDg0OTYwOTM3NSw2NC43MDE4MTI3NDQxNDA2Miw4Ni4yOTU0MTAxNTYyNUM2Ny40MzQ5MzY1MjM0Mzc1LDg0Ljg5NDA0Mjk2ODc1LDY5Ljk5Nzc3MjIxNjc5Njg4LDgzLjE3MjExOTE0MDYyNSw3Mi4zNDgxNDQ1MzEyNSw4MS4xNzMzMzk4NDM3NVpNOTQuNDk3ODAyNzM0Mzc1LDI4Ljk0MzYwMzUxNTYyNUM5MS42ODY0MDEzNjcxODc1LDI0LjE3NDA3MjI2NTYyNSw4Ny44MTA0NTUzMjIyNjU2MiwyMC4yMDAxOTUzMTI1LDgzLjIyODA4ODM3ODkwNjI1LDE3LjQwODY5MTQwNjI1Qzg0LjY1NTI0MjkxOTkyMTg4LDE3LjE2ODk0NTMxMjUsODYuMTE3ODU4ODg2NzE4NzUsMTcuMDQzNDU3MDMxMjUsODcuNjA3OTEwMTU2MjUsMTcuMDQzNDU3MDMxMjVDODguNzE3ODY0OTkwMjM0MzgsMTcuMDQzNDU3MDMxMjUsODkuODEyMjI1MzQxNzk2ODgsMTcuMTE0OTkwMjM0Mzc1LDkwLjg4ODY3MTg3NSwxNy4yNDkyNjc1NzgxMjVDOTQuNDg1MTA3NDIxODc1LDIwLjQ4NjU3MjI2NTYyNSw5Ny40OTE1MTYxMTMyODEyNSwyNC40NTU4MTA1NDY4NzUsOTkuNzA4NzA5NzE2Nzk2ODgsMjguOTQzNjAzNTE1NjI1WiIgc3R5bGU9ImZpbGwtcnVsZTogZXZlbm9kZDsgc3Ryb2tlOiBub25lOyBzdHJva2Utd2lkdGg6IDAuMzI3OTQzOyBmaWxsOiByZ2IoMCwgNjYsIDE3OSk7IGZpbGwtb3BhY2l0eTogMTsiLz48L2c+PC9nPjxnIGlkPSJzaGFwZS1iODcxOGVhZC00NTkyLTgwNWYtODAwNy1hOWVmNTVmMGE0MjYiPjxnIGNsYXNzPSJmaWxscyIgaWQ9ImZpbGxzLWI4NzE4ZWFkLTQ1OTItODA1Zi04MDA3LWE5ZWY1NWYwYTQyNiI+PHBhdGggZD0iTTQ3LjM5OTMyMjUwOTc2NTYyNSw4LjEyMTU4MjAzMTI1QzQ4LjM1MjQ0NzUwOTc2NTYyNSw4LjEyMTU4MjAzMTI1LDQ5LjI5Njc4MzQ0NzI2NTYyNSw4LjE2MTM3Njk1MzEyNSw1MC4yMzE1MDYzNDc2NTYyNSw4LjIzODUyNTM5MDYyNUM0Ny41MDMyOTU4OTg0Mzc1LDkuNjM3NDUxMTcxODc1LDQ0Ljk0NTA5ODg3Njk1MzEyNSwxMS4zNTY2ODk0NTMxMjUsNDIuNTk4NDQ5NzA3MDMxMjUsMTMuMzUxMDc0MjE4NzVDMjcuMjQyOTUwNDM5NDUzMTI1LDE1LjgzOTExMTMyODEyNSwxNS40NzEzNzQ1MTE3MTg3NSwzMC4wNzQ5NTExNzE4NzUsMTUuNDcxMzc0NTExNzE4NzUsNDcuMjY1MzgwODU5Mzc1QzE1LjQ3MTM3NDUxMTcxODc1LDY2LjIwODk4NDM3NSwyOS43NjYwODI3NjM2NzE4NzUsODEuNTY1OTE3OTY4NzUsNDcuMzk5MzIyNTA5NzY1NjI1LDgxLjU2NTkxNzk2ODc1QzU4LjY4MjY3ODIyMjY1NjI1LDgxLjU2NTkxNzk2ODc1LDY4LjU5ODU0MTI1OTc2NTYyLDc1LjI3NzU4Nzg5MDYyNSw3NC4yNzczMTMyMzI0MjE4OCw2NS43ODU2NDQ1MzEyNUw3OS41MDU4Mjg4NTc0MjE4OCw2NS43ODU2NDQ1MzEyNUM3My4zNTY4NzI1NTg1OTM3NSw3OC4wNjI3NDQxNDA2MjUsNjEuMjg1ODg4NjcxODc1LDg2LjQwOTQyMzgyODEyNSw0Ny4zOTkzMjI1MDk3NjU2MjUsODYuNDA5NDIzODI4MTI1QzI3LjI3NjEyMzA0Njg3NSw4Ni40MDk0MjM4MjgxMjUsMTAuOTYzMDQzMjEyODkwNjI1LDY4Ljg4NDAzMzIwMzEyNSwxMC45NjMwNDMyMTI4OTA2MjUsNDcuMjY1MzgwODU5Mzc1QzEwLjk2MzA0MzIxMjg5MDYyNSwyNS42NDY5NzI2NTYyNSwyNy4yNzYxMjMwNDY4NzUsOC4xMjE1ODIwMzEyNSw0Ny4zOTkzMjI1MDk3NjU2MjUsOC4xMjE1ODIwMzEyNVpNNzQuMzkyODgzMzAwNzgxMjUsMjguOTQzNjAzNTE1NjI1QzczLjIxODAxNzU3ODEyNSwyNi45NTA5Mjc3MzQzNzUsNzEuODU3NjY2MDE1NjI1LDI1LjA5NjQzNTU0Njg3NSw3MC4zMzcxNTgyMDMxMjUsMjMuNDA5NjY3OTY4NzVDNzEuNTM5MzY3Njc1NzgxMjUsMjIuNDAzODA4NTkzNzUsNzIuODE5MDAwMjQ0MTQwNjIsMjEuNDk5NTExNzE4NzUsNzQuMTY1NjQ5NDE0MDYyNSwyMC43MTA5Mzc1Qzc2LjI5MDcxMDQ0OTIxODc1LDIzLjE4MTY0MDYyNSw3OC4xMjI4MzMyNTE5NTMxMiwyNS45NDcwMjE0ODQzNzUsNzkuNjAzNjk4NzMwNDY4NzUsMjguOTQzNjAzNTE1NjI1WiIgc3R5bGU9ImZpbGwtcnVsZTogZXZlbm9kZDsgc3Ryb2tlOiBub25lOyBzdHJva2Utd2lkdGg6IDAuMzI3OTQzOyBmaWxsOiByZ2IoMCwgNjYsIDE3OSk7IGZpbGwtb3BhY2l0eTogMTsiLz48L2c+PC9nPjwvZz48ZyBpZD0ic2hhcGUtYjg3MThlYWQtNDU5Mi04MDVmLTgwMDctYTllZjU1ZjBhNDFmIj48ZyBjbGFzcz0iZmlsbHMiIGlkPSJmaWxscy1iODcxOGVhZC00NTkyLTgwNWYtODAwNy1hOWVmNTVmMGE0MWYiPjxwYXRoIGQ9Ik03OC4xODA5NjkyMzgyODEyNSwzNy45OTUzNjEzMjgxMjVMODYuMzg0ODg3Njk1MzEyNSwzNy45OTUzNjEzMjgxMjVMODYuMzg0ODg3Njk1MzEyNSwzMy40Njk0ODI0MjE4NzVMNjUuMzk0ODA1OTA4MjAzMTIsMzMuNDY5NDgyNDIxODc1TDY1LjM5NDgwNTkwODIwMzEyLDM3Ljk5NTM2MTMyODEyNUw3My41OTg4MTU5MTc5Njg3NSwzNy45OTUzNjEzMjgxMjVMNzMuNTk4ODE1OTE3OTY4NzUsNjEuMjU5NzY1NjI1TDc4LjE4MDk2OTIzODI4MTI1LDYxLjI1OTc2NTYyNVoiLz48L2c+PC9nPjxnIGlkPSJzaGFwZS1iODcxOGVhZC00NTkyLTgwNWYtODAwNy1hOWVmNTVmMGE0MjAiPjxnIGNsYXNzPSJmaWxscyIgaWQ9ImZpbGxzLWI4NzE4ZWFkLTQ1OTItODA1Zi04MDA3LWE5ZWY1NWYwYTQyMCI+PHBhdGggZD0iTTkyLjk2Nzk4NzA2MDU0Njg4LDU0LjU1MDUzNzEwOTM3NUwxMDUuMTk5OTIwNjU0Mjk2ODgsNTQuNTUwNTM3MTA5Mzc1TDEwNy44MjM4ODMwNTY2NDA2Miw2MS4yNTk3NjU2MjVMMTEyLjYyODAyMTI0MDIzNDM4LDYxLjI1OTc2NTYyNUwxMDEuMjQ1ODgwMTI2OTUzMTIsMzMuMjcwOTk2MDkzNzVMOTcuMDMzMjk0Njc3NzM0MzgsMzMuMjcwOTk2MDkzNzVMODUuNjUxMTIzMDQ2ODc1LDYxLjI1OTc2NTYyNUw5MC4zMDc0MzQwODIwMzEyNSw2MS4yNTk3NjU2MjVaTTEwMy41MzcwMTc4MjIyNjU2Miw1MC4yMjI5MDAzOTA2MjVMOTQuNjMxMjU2MTAzNTE1NjIsNTAuMjIyOTAwMzkwNjI1TDk5LjA2NTY0MzMxMDU0Njg4LDM5LjEwNjkzMzU5Mzc1WiIvPjwvZz48L2c+PGcgaWQ9InNoYXBlLWI4NzE4ZWFkLTQ1OTItODA1Zi04MDA3LWE5ZWY1NWYwYTQyMSI+PGcgY2xhc3M9ImZpbGxzIiBpZD0iZmlsbHMtYjg3MThlYWQtNDU5Mi04MDVmLTgwMDctYTllZjU1ZjBhNDIxIj48cGF0aCBkPSJNMTIwLjg3MTM5ODkyNTc4MTI1LDMzLjQ2OTQ4MjQyMTg3NUwxMTYuNzY5NTkyMjg1MTU2MjUsMzMuNDY5NDgyNDIxODc1TDExNi43Njk1OTIyODUxNTYyNSw2MS4yNTk3NjU2MjVMMTM1LjE3MDEzNTQ5ODA0Njg4LDYxLjI1OTc2NTYyNUwxMzUuMTcwMTM1NDk4MDQ2ODgsNTYuODUzMjcxNDg0Mzc1QzEzMC40MDM5MzA2NjQwNjI1LDU2Ljg1MzI3MTQ4NDM3NSwxMjUuNjM3NjM0Mjc3MzQzNzUsNTYuODUzMjcxNDg0Mzc1LDEyMC44NzEzOTg5MjU3ODEyNSw1Ni44NTMyNzE0ODQzNzVaIi8+PC9nPjwvZz48ZyBpZD0ic2hhcGUtYjg3MThlYWQtNDU5Mi04MDVmLTgwMDctYTllZjU1ZjBhNDIyIj48ZyBjbGFzcz0iZmlsbHMiIGlkPSJmaWxscy1iODcxOGVhZC00NTkyLTgwNWYtODAwNy1hOWVmNTVmMGE0MjIiPjxwYXRoIGQ9Ik0xNTkuMDc5NTg5ODQzNzUsMzMuNDY5NDgyNDIxODc1TDEzOS45MzcyMjUzNDE3OTY4OCwzMy40Njk0ODI0MjE4NzVMMTM5LjkzNzIyNTM0MTc5Njg4LDYxLjI1OTc2NTYyNUwxNTkuMjY0NDA0Mjk2ODc1LDYxLjI1OTc2NTYyNUwxNTkuMjY0NDA0Mjk2ODc1LDU2Ljg1MzI3MTQ4NDM3NUwxNDQuNDQ1NTU2NjQwNjI1LDU2Ljg1MzI3MTQ4NDM3NUwxNDQuNDQ1NTU2NjQwNjI1LDQ5LjQyODk1NTA3ODEyNUwxNTcuNDE2NjU2NDk0MTQwNjIsNDkuNDI4OTU1MDc4MTI1TDE1Ny40MTY2NTY0OTQxNDA2Miw0NS4wMjI0NjA5Mzc1TDE0NC40NDU1NTY2NDA2MjUsNDUuMDIyNDYwOTM3NUwxNDQuNDQ1NTU2NjQwNjI1LDM3Ljg3NjIyMDcwMzEyNUwxNTkuMDc5NTg5ODQzNzUsMzcuODc2MjIwNzAzMTI1WiIvPjwvZz48L2c+PGcgaWQ9InNoYXBlLWI4NzE4ZWFkLTQ1OTItODA1Zi04MDA3LWE5ZWY1NWYwYTQyMyI+PGcgY2xhc3M9ImZpbGxzIiBpZD0iZmlsbHMtYjg3MThlYWQtNDU5Mi04MDVmLTgwMDctYTllZjU1ZjBhNDIzIj48cGF0aCBkPSJNMTgxLjIxNTI0MDQ3ODUxNTYyLDQyLjU0MTI1OTc2NTYyNUMxODEuMjE1MjQwNDc4NTE1NjIsNDMuOTc2ODA2NjQwNjI1LDE4MC43MzQ4MzI3NjM2NzE4OCw0NS4xMjE4MjYxNzE4NzUsMTc5Ljc2NzgyMjI2NTYyNSw0NS45Njg1MDU4NTkzNzVDMTc4LjgwNzA5ODM4ODY3MTg4LDQ2LjgyMjI2NTYyNSwxNzcuNTA3NDQ2Mjg5MDYyNSw0Ny4yNDUzNjEzMjgxMjUsMTc1Ljg3NTE4MzEwNTQ2ODc1LDQ3LjI0NTM2MTMyODEyNUwxNjkuMjA0ODY0NTAxOTUzMTIsNDcuMjQ1MzYxMzI4MTI1TDE2OS4yMDQ4NjQ1MDE5NTMxMiwzNy44NzYyMjA3MDMxMjVMMTc1LjgzODI4NzM1MzUxNTYyLDM3Ljg3NjIyMDcwMzEyNUMxNzcuNTQ0MzQyMDQxMDE1NjIsMzcuODc2MjIwNzAzMTI1LDE3OC44Njg0OTk3NTU4NTkzOCwzOC4yNjY2MDE1NjI1LDE3OS44MDQ5MDExMjMwNDY4OCwzOS4wNTM5NTUwNzgxMjVDMTgwLjc0NzIyMjkwMDM5MDYyLDM5LjgzNDk2MDkzNzUsMTgxLjIxNTI0MDQ3ODUxNTYyLDQwLjk5OTI2NzU3ODEyNSwxODEuMjE1MjQwNDc4NTE1NjIsNDIuNTQxMjU5NzY1NjI1Wk0xODYuNjQ3NDkxNDU1MDc4MTIsNjEuMjU5NzY1NjI1TDE3OS42NjMyMDgwMDc4MTI1LDUwLjczOTAxMzY3MTg3NUMxODAuNTc0NTg0OTYwOTM3NSw1MC40NzQzNjUyMzQzNzUsMTgxLjQwNjE4ODk2NDg0Mzc1LDUwLjA5NzY1NjI1LDE4Mi4xNTc3MTQ4NDM3NSw0OS42MDc2NjYwMTU2MjVDMTgyLjkwODkzNTU0Njg3NSw0OS4xMTgxNjQwNjI1LDE4My41NTU4MTY2NTAzOTA2Miw0OC41MjI0NjA5Mzc1LDE4NC4wOTc2ODY3Njc1NzgxMiw0Ny44MjEyODkwNjI1QzE4NC42Mzk4MzE1NDI5Njg3NSw0Ny4xMTk2Mjg5MDYyNSwxODUuMDY0NjY2NzQ4MDQ2ODgsNDYuMzEyNzQ0MTQwNjI1LDE4NS4zNzI2MTk2Mjg5MDYyNSw0NS4zOTk2NTgyMDMxMjVDMTg1LjY4MDQ4MDk1NzAzMTI1LDQ0LjQ4NjU3MjI2NTYyNSwxODUuODM0MzgxMTAzNTE1NjIsNDMuNDQ3NTA5NzY1NjI1LDE4NS44MzQzODExMDM1MTU2Miw0Mi4yODI5NTg5ODQzNzVDMTg1LjgzNDM4MTEwMzUxNTYyLDQwLjkzMzEwNTQ2ODc1LDE4NS42MTI3OTI5Njg3NSwzOS43MDkyMjg1MTU2MjUsMTg1LjE2OTI4MTAwNTg1OTM4LDM4LjYxMDU5NTcwMzEyNUMxODQuNzI1ODYwNTk1NzAzMTIsMzcuNTEyNDUxMTcxODc1LDE4NC4wOTE1ODMyNTE5NTMxMiwzNi41ODU5Mzc1LDE4My4yNjYzMjY5MDQyOTY4OCwzNS44MzE1NDI5Njg3NUMxODIuNDQwODg3NDUxMTcxODgsMzUuMDc3MzkyNTc4MTI1LDE4MS40MzA4Nzc2ODU1NDY4OCwzNC40OTUxMTcxODc1LDE4MC4yMzYwODM5ODQzNzUsMzQuMDg0NzE2Nzk2ODc1QzE3OS4wNDEwNDYxNDI1NzgxMiwzMy42NzQzMTY0MDYyNSwxNzcuNzA0NTI4ODA4NTkzNzUsMzMuNDY5NDgyNDIxODc1LDE3Ni4yMjY0NzA5NDcyNjU2MiwzMy40Njk0ODI0MjE4NzVMMTY0LjY5NjUzMzIwMzEyNSwzMy40Njk0ODI0MjE4NzVMMTY0LjY5NjUzMzIwMzEyNSw2MS4yNTk3NjU2MjVMMTY5LjIwNDg2NDUwMTk1MzEyLDYxLjI1OTc2NTYyNUwxNjkuMjA0ODY0NTAxOTUzMTIsNTEuNTcyOTk4MDQ2ODc1TDE3NC45MTQ0NTkyMjg1MTU2Miw1MS41NzI5OTgwNDY4NzVMMTgxLjI4OTAzMTk4MjQyMTg4LDYxLjI1OTc2NTYyNVoiLz48L2c+PC9nPjwvZz48L2c+PC9nPjwvZz48L2c+PC9nPjwvZz48L3N2Zz4=" alt="">
+</div>
+ <p class="qr-instruction">Scan this code with the Taler wallet on your phone.</p>
+ {{/claimed}}
+ {{#claimed}}
+ <div class="claimed">
+ <div>
+ <div class="claimed-icon" aria-hidden="true">✓</div>
+ <h2>Order claimed by wallet</h2>
+ <p>Waiting for the wallet to complete the payment…</p>
+ </div>
+ </div>
+ {{/claimed}}
+ </section>
+ </div>
+</main>
+<div id="page-config"
+ data-status-url="{{ order_status_url }}"
+ data-claimed="{{#claimed}}true{{/claimed}}{{^claimed}}false{{/claimed}}"
+ hidden></div>
+<footer class="site-footer">
+ <p>Payments with privacy by <a href="https://taler.net/" rel="noreferrer" referrerpolicy="no-referrer">GNU Taler</a></p>
+ <p>Copyright © 2014–2026 Taler Systems SA</p>
+</footer>
+<script>
+(() => {
+ "use strict";
+ const deadline = document.getElementById("pay-deadline");
+ if (deadline) {
+ const raw = deadline.dataset.epoch;
+ if (raw && raw !== "never") {
+ const date = new Date(Number(raw) * 1000);
+ if (!Number.isNaN(date.getTime())) {
+ deadline.dateTime = date.toISOString();
+ deadline.textContent = new Intl.DateTimeFormat(undefined, {
+ dateStyle: "medium", timeStyle: "short"
+ }).format(date);
+ }
+ } else if (raw === "never") {
+ deadline.textContent = "No deadline";
+ }
+ }
+
+ const config = document.getElementById("page-config");
+ const claimed = config.dataset.claimed === "true";
+ let delay = 750;
+
+ async function poll() {
+ let statusUrl;
+ try {
+ statusUrl = new URL(config.dataset.statusUrl, window.location.href);
+ statusUrl.searchParams.set("timeout_ms", "60000");
+ } catch (_) {
+ return;
+ }
+ try {
+ const response = await fetch(statusUrl, {
+ headers: { "Accept": "application/json" },
+ cache: "no-store",
+ credentials: "same-origin",
+ referrerPolicy: "no-referrer"
+ });
+ let body = {};
+ try { body = await response.json(); } catch (_) {}
+ if (response.status === 200) {
+ if (body.fulfillment_url) {
+ window.location.replace(body.fulfillment_url);
+ } else {
+ window.location.reload();
+ }
+ return;
+ }
+ if (response.status === 202) {
+ if (body.public_reorder_url) {
+ window.location.replace(body.public_reorder_url);
+ } else {
+ window.location.reload();
+ }
+ return;
+ }
+ if (response.status === 402) {
+ if (body.already_paid_order_id && body.fulfillment_url) {
+ window.location.replace(body.fulfillment_url);
+ return;
+ }
+ if (body.taler_pay_uri) {
+ const walletLink = document.getElementById("wallet-link");
+ const uriMeta = document.querySelector('meta[name="taler-uri"]');
+ walletLink.href = body.taler_pay_uri;
+ uriMeta.content = body.taler_pay_uri;
+ }
+ if (!claimed) {
+ window.location.reload();
+ return;
+ }
+ delay = 750;
+ } else {
+ delay = Math.min(delay * 2, 10000);
+ }
+ } catch (_) {
+ delay = Math.min(delay * 2, 10000);
+ }
+ window.setTimeout(poll, delay);
+ }
+ poll();
+})();
+</script>
+</body>
+</html>
diff --git a/src/frontend/show_order_details.en.must b/src/frontend/show_order_details.en.must
@@ -0,0 +1,113 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <meta name="referrer" content="no-referrer">
+ <title>Payment complete for {{ order_summary }}</title>
+ <style>
+ :root {
+ color-scheme: light;
+ --taler-blue: #0042b3;
+ --taler-slate: #586a88;
+ --taler-ink: #172033;
+ --taler-muted: #64748b;
+ --taler-border: #d9dfeb;
+ --taler-panel: #f8f9fc;
+ --taler-qr-frame: #f1f1f4;
+ --taler-success: #147d55;
+ --taler-success-bg: #e9f7f1;
+ font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
+ font-synthesis: none;
+ }
+ * { box-sizing: border-box; }
+ html { min-width: 18rem; background: #fff; color: var(--taler-ink); }
+ body { min-height: 100vh; margin: 0; display: flex; flex-direction: column; }
+ a { color: var(--taler-blue); }
+ a:focus-visible, button:focus-visible { outline: .2rem solid #7aa7f5; outline-offset: .18rem; }
+ .site-header, .site-footer, main { width: min(72rem, calc(100% - 2rem)); margin-inline: auto; }
+ .site-header { min-height: 5.5rem; display: flex; align-items: center; border-bottom: 1px solid var(--taler-border); }
+ .brand { display: inline-flex; align-items: center; }
+ .brand img { display: block; width: 8.4rem; height: auto; }
+ main { flex: 1; display: grid; place-items: center; padding: 3.5rem 0; }
+ .page-grid { width: 100%; display: grid; grid-template-columns: minmax(18rem, 25rem) minmax(20rem, 1fr); gap: clamp(2.5rem, 7vw, 7rem); align-items: center; }
+ .eyebrow { margin: 0 0 .55rem; color: var(--taler-blue); font-size: .78rem; font-weight: 750; letter-spacing: .1em; text-transform: uppercase; }
+ h1 { max-width: 18ch; margin: 0; font-size: clamp(2rem, 4.5vw, 3.5rem); line-height: 1.08; letter-spacing: -.035em; }
+ .lede { max-width: 36rem; margin: 1rem 0 0; color: var(--taler-slate); font-size: 1.08rem; line-height: 1.65; }
+ .amount { margin: 1.8rem 0 .2rem; color: var(--taler-blue); font-size: clamp(2.1rem, 5vw, 3rem); font-weight: 780; line-height: 1.05; letter-spacing: -.025em; overflow-wrap: anywhere; }
+ .amount-note { margin: .55rem 0 0; color: var(--taler-slate); font-size: 1rem; }
+ .details { margin: 2rem 0 0; display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: .8rem 1.25rem; }
+ .details dt { color: var(--taler-muted); }
+ .details dd { margin: 0; font-weight: 620; overflow-wrap: anywhere; }
+ .action { display: inline-flex; min-height: 3rem; margin-top: 1.75rem; padding: .75rem 1.2rem; align-items: center; justify-content: center; border-radius: .55rem; background: var(--taler-blue); color: #fff; font-weight: 720; text-decoration: none; box-shadow: 0 .35rem 1rem rgb(0 66 179 / 20%); }
+ .action:hover { background: #003994; }
+ .wallet-help { margin: 1rem 0 0; color: var(--taler-muted); font-size: .92rem; }
+ .qr-column { display: grid; justify-items: center; gap: 1rem; }
+ .qr-instruction { margin: 0; max-width: 26rem; color: var(--taler-slate); text-align: center; line-height: 1.5; }
+ .qr-frame { position: relative; width: min(100%, 25rem); aspect-ratio: 1; padding: 6.25%; overflow: hidden; border-radius: 8%; background: var(--taler-qr-frame); }
+ .qr-code { width: 100%; height: 100%; background: #fff; }
+ .qr-code > svg { display: block; width: 100%; height: 100%; fill: #000; }
+ .qr-motion { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
+ .qr-motion rect { fill: none; stroke: url(#taler-scan-gradient); stroke-width: 2.6; stroke-linecap: round; stroke-dasharray: 57 343; animation: scan 4s linear infinite; }
+ .qr-motion rect + rect { animation-delay: -2s; }
+ .qr-badge { position: absolute; inset: 50% auto auto 50%; height: 12.5%; width: auto; transform: translate(-50%, -50%); }
+ @keyframes scan { to { stroke-dashoffset: -400; } }
+ .claimed { width: min(100%, 25rem); aspect-ratio: 1; display: grid; place-items: center; padding: 2.5rem; border-radius: 8%; background: var(--taler-qr-frame); text-align: center; }
+ .claimed-icon { width: 4.25rem; height: 4.25rem; margin: 0 auto 1.3rem; display: grid; place-items: center; border-radius: 50%; background: var(--taler-blue); color: #fff; font-size: 2rem; }
+ .claimed h2 { margin: 0; font-size: 1.35rem; }
+ .claimed p { margin: .65rem 0 0; color: var(--taler-slate); line-height: 1.55; }
+ .site-footer { padding: 1.5rem 0 2rem; display: flex; flex-wrap: wrap; justify-content: space-between; gap: .6rem 1.5rem; border-top: 1px solid var(--taler-border); color: var(--taler-muted); font-size: .82rem; }
+ .site-footer p { margin: 0; }
+ .site-footer a { color: inherit; }
+ .status-card { width: min(44rem, 100%); padding: clamp(1.4rem, 4vw, 3rem); border: 1px solid var(--taler-border); border-radius: 1rem; background: #fff; box-shadow: 0 1rem 3rem rgb(30 48 80 / 8%); }
+ .status-mark { width: 3.5rem; height: 3.5rem; margin-bottom: 1.4rem; display: grid; place-items: center; border-radius: 50%; background: var(--taler-success-bg); color: var(--taler-success); font-size: 1.65rem; font-weight: 800; }
+ .message { margin: 1.7rem 0 0; padding: 1rem 1.1rem; border-left: .25rem solid var(--taler-blue); border-radius: .2rem .5rem .5rem .2rem; background: #f1f5ff; line-height: 1.55; }
+ .secondary-link { display: inline-block; margin-top: 1.3rem; font-weight: 650; overflow-wrap: anywhere; }
+ [hidden] { display: none !important; }
+ @media (max-width: 47rem) {
+ .site-header { min-height: 4.5rem; }
+ .brand img { width: 7rem; }
+ main { padding: 2.25rem 0 3rem; place-items: start center; }
+ .page-grid { grid-template-columns: 1fr; gap: 2.5rem; }
+ .qr-column { grid-row: 1; }
+ .copy-column { grid-row: 2; }
+ h1 { font-size: clamp(2rem, 10vw, 3rem); }
+ .details { grid-template-columns: 1fr; gap: .25rem; }
+ .details dd { margin-bottom: .75rem; }
+ .action { width: 100%; }
+ .site-footer { flex-direction: column; }
+ }
+ @media (prefers-reduced-motion: reduce) {
+ .qr-motion rect { animation: none; }
+ .qr-motion rect + rect { stroke-dashoffset: -200; }
+ }
+</style>
+</head>
+<body>
+<header class="site-header">
+ <a class="brand" href="https://taler.net/" rel="noreferrer" referrerpolicy="no-referrer" aria-label="GNU Taler">
+ <img src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBoZWlnaHQ9IjQ0Ny43NjEiIGlkPSJzY3JlZW5zaG90LTUwZWRmYjcyLTU4YzMtODA2ZC04MDA3LTljZWU5ZmI3N2FiZSIgdmlld0JveD0iMCAwIDEwMDAgNDQ3Ljc2MSIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIGZpbGw9Im5vbmUiIHZlcnNpb249IjEuMSI+PGcgaWQ9InNoYXBlLTUwZWRmYjcyLTU4YzMtODA2ZC04MDA3LTljZWU5ZmI3N2FiZSIgd2lkdGg9IjY3MCIgaGVpZ2h0PSIzMDAiIHJ4PSIwIiByeT0iMCIgc3R5bGU9ImZpbGw6IHJnYigwLCAwLCAwKTsiPjxnIGlkPSJzaGFwZS01MGVkZmI3Mi01OGMzLTgwNmQtODAwNy05Y2VlOWZiNzdhYmYiIHN0eWxlPSJkaXNwbGF5OiBub25lOyI+PGcgY2xhc3M9ImZpbGxzIiBpZD0iZmlsbHMtNTBlZGZiNzItNThjMy04MDZkLTgwMDctOWNlZTlmYjc3YWJmIj48cmVjdCB3aWR0aD0iMTAwMCIgaGVpZ2h0PSI0NDcuNzYxMTk0MDI5ODUwNyIgeD0iMCIgdHJhbnNmb3JtPSJtYXRyaXgoMS4wMDAwMDAsIDAuMDAwMDAwLCAwLjAwMDAwMCwgMS4wMDAwMDAsIDAuMDAwMDAwLCAwLjAwMDAwMCkiIHN0eWxlPSJmaWxsOiBub25lOyIgcnk9IjAiIGZpbGw9Im5vbmUiIHJ4PSIwIiB5PSIwIi8+PC9nPjwvZz48ZyBpZD0ic2hhcGUtNTBlZGZiNzItNThjMy04MDZkLTgwMDctOWNlZTlmYjc3YWMwIiByeD0iMCIgcnk9IjAiIHN0eWxlPSJmaWxsOiByZ2IoMCwgMCwgMCk7Ij48ZyBpZD0ic2hhcGUtNTBlZGZiNzItNThjMy04MDZkLTgwMDctOWNlZTlmYjc3YWM2Ij48ZyBjbGFzcz0iZmlsbHMiIGlkPSJmaWxscy01MGVkZmI3Mi01OGMzLTgwNmQtODAwNy05Y2VlOWZiNzdhYzYiPjxwYXRoIGQ9Ik00MzEuMTU1LDUuNTc4QzUwOC43MTYsNS41NzgsNTc2LjA3Nyw1Mi4zNTAsNjEwLjA2NiwxMjEuMDEwTDU4MS4xMjMsMTIxLjAxMEM1NDkuNjg1LDY3Ljc3OCw0OTQuMjc0LDMyLjQyOCw0MzEuMTU1LDMyLjQyOEMzMzMuMTkyLDMyLjQyOCwyNTMuNzc3LDExNy41NjMsMjUzLjc3NywyMjIuNTgwQzI1My43NzcsMjczLjk4MiwyNzIuODEwLDMyMC42MTQsMzAzLjcyNiwzNTQuODM0QzI5Ny4wNDcsMzYwLjQxMSwyODkuOTM3LDM2NS40MjAsMjgyLjQ1NSwzNjkuNzkzQzI0OS4xMTIsMzMxLjExMiwyMjguNzMxLDI3OS40MDMsMjI4LjczMSwyMjIuNTgwQzIyOC43MzEsMTAyLjczNCwzMTkuMzU5LDUuNTc4LDQzMS4xNTUsNS41NzhaWk02MDkuNTIzLDMyNS4yNTNDNTc1LjM2MiwzOTMuMzE0LDUwOC4zMDEsNDM5LjU4Myw0MzEuMTU1LDQzOS41ODNDNDI1LjkxOCw0MzkuNTgzLDQyMC43MjcsNDM5LjM2OSw0MTUuNTg5LDQzOC45NTFDNDMwLjc3NCw0MzEuMTg0LDQ0NS4wMTAsNDIxLjYzNSw0NTguMDY5LDQxMC41NTZDNTA5LjQxNyw0MDIuMTc2LDU1My41MjEsMzcwLjE5MCw1ODAuNDY2LDMyNS4yNTNaIiBzdHlsZT0iZmlsbC1ydWxlOiBldmVub2RkOyBzdHJva2U6IG5vbmU7IHN0cm9rZS13aWR0aDogMC4zMjc5NDM7IGZpbGw6IHJnYigwLCA2NiwgMTc5KTsgZmlsbC1vcGFjaXR5OiAxOyIvPjwvZz48L2c+PGcgaWQ9InNoYXBlLTUwZWRmYjcyLTU4YzMtODA2ZC04MDA3LTljZWU5ZmI3N2FjNyI+PGcgY2xhc3M9ImZpbGxzIiBpZD0iZmlsbHMtNTBlZGZiNzItNThjMy04MDZkLTgwMDctOWNlZTlmYjc3YWM3Ij48cGF0aCBkPSJNMzE5LjQ2NSw1LjU3OEMzMjQuNzAxLDUuNTc4LDMyOS44OTIsNS43OTIsMzM1LjAzMCw2LjIxMEMzMTkuODQ1LDEzLjk3NywzMDUuNjA5LDIzLjUyNSwyOTIuNTUxLDM0LjYwNUMyMDcuMzYxLDQ4LjUwNywxNDIuMDg3LDEyNy4zNzEsMTQyLjA4NywyMjIuNTgwQzE0Mi4wODcsMjkzLjU0OCwxNzguMzU5LDM1NS40MjYsMjMyLjEwNiwzODguMDk3QzIyNC4xNzgsMzg5LjQyNywyMTYuMDUyLDM5MC4xMjIsMjA3Ljc3NCwzOTAuMTIyQzIwMS42MDcsMzkwLjEyMiwxOTUuNTI4LDM4OS43MjYsMTg5LjU0OCwzODguOTgxQzE0NS4yMjksMzQ5LjE3NCwxMTcuMDQwLDI4OS40MTEsMTE3LjA0MCwyMjIuNTgwQzExNy4wNDAsMTAyLjczNCwyMDcuNjY5LDUuNTc4LDMxOS40NjUsNS41NzhaWk0zNDYuMzc5LDQxMC41NTZDMzk3LjcyNyw0MDIuMTc2LDQ0MS44MzIsMzcwLjE4OCw0NjguNzc2LDMyNS4yNTFMNDk3LjgzNCwzMjUuMjUxQzQ2My42NzMsMzkzLjMxMiwzOTYuNjEyLDQzOS41ODMsMzE5LjQ2NSw0MzkuNTgzQzMxNC4yMjcsNDM5LjU4MywzMDkuMDM3LDQzOS4zNjksMzAzLjg5OSw0MzguOTUxQzMxOS4wODMsNDMxLjE4MywzMzMuMzIxLDQyMS42MzYsMzQ2LjM3OSw0MTAuNTU2WlpNNDY5LjQzMiwxMjEuMDEwQzQ1My44MTMsOTQuNTY5LDQzMi4yODAsNzIuNTM5LDQwNi44MjMsNTcuMDYzQzQxNC43NTEsNTUuNzM0LDQyMi44NzcsNTUuMDM5LDQzMS4xNTUsNTUuMDM5QzQzNy4zMjEsNTUuMDM5LDQ0My40MDEsNTUuNDM0LDQ0OS4zODEsNTYuMTgwQzQ2OS4zNjIsNzQuMTI2LDQ4Ni4wNjQsOTYuMTMxLDQ5OC4zODIsMTIxLjAxMFoiIHN0eWxlPSJmaWxsLXJ1bGU6IGV2ZW5vZGQ7IHN0cm9rZTogbm9uZTsgc3Ryb2tlLXdpZHRoOiAwLjMyNzk0MzsgZmlsbDogcmdiKDAsIDY2LCAxNzkpOyBmaWxsLW9wYWNpdHk6IDE7Ii8+PC9nPjwvZz48ZyBpZD0ic2hhcGUtNTBlZGZiNzItNThjMy04MDZkLTgwMDctOWNlZTlmYjc3YWM4Ij48ZyBjbGFzcz0iZmlsbHMiIGlkPSJmaWxscy01MGVkZmI3Mi01OGMzLTgwNmQtODAwNy05Y2VlOWZiNzdhYzgiPjxwYXRoIGQ9Ik0yMDcuNzc0LDUuNTc4QzIxMy4wNjksNS41NzgsMjE4LjMxNSw1Ljc5OSwyMjMuNTA4LDYuMjI2QzIwOC4zNTIsMTMuOTgyLDE5NC4xMzksMjMuNTEyLDE4MS4xMDMsMzQuNTY4Qzk1Ljc5NCw0OC4zNjEsMzAuMzk3LDEyNy4yODEsMzAuMzk3LDIyMi41ODBDMzAuMzk3LDMyNy41OTgsMTA5LjgxMiw0MTIuNzMyLDIwNy43NzQsNDEyLjczMkMyNzAuNDU5LDQxMi43MzIsMzI1LjU0NywzNzcuODcxLDM1Ny4wOTYsMzI1LjI1MUwzODYuMTQ0LDMyNS4yNTFDMzUxLjk4MywzOTMuMzEyLDI4NC45MjIsNDM5LjU4MywyMDcuNzc0LDQzOS41ODNDOTUuOTc5LDQzOS41ODMsNS4zNTAsMzQyLjQyNyw1LjM1MCwyMjIuNTgwQzUuMzUwLDEwMi43MzQsOTUuOTc5LDUuNTc4LDIwNy43NzQsNS41NzhaWk0zNTcuNzM4LDEyMS4wMTBDMzUxLjIxMSwxMDkuOTYyLDM0My42NTQsOTkuNjgxLDMzNS4yMDYsOTAuMzMxQzM0MS44ODUsODQuNzU0LDM0OC45OTQsNzkuNzQyLDM1Ni40NzYsNzUuMzY5QzM2OC4yODIsODkuMDY2LDM3OC40NjAsMTA0LjM5NywzODYuNjg3LDEyMS4wMTBaIiBzdHlsZT0iZmlsbC1ydWxlOiBldmVub2RkOyBzdHJva2U6IG5vbmU7IHN0cm9rZS13aWR0aDogMC4zMjc5NDM7IGZpbGw6IHJnYigwLCA2NiwgMTc5KTsgZmlsbC1vcGFjaXR5OiAxOyIvPjwvZz48L2c+PC9nPjxnIGlkPSJzaGFwZS01MGVkZmI3Mi01OGMzLTgwNmQtODAwNy05Y2VlOWZiNzdhYzEiPjxnIGNsYXNzPSJmaWxscyIgaWQ9ImZpbGxzLTUwZWRmYjcyLTU4YzMtODA2ZC04MDA3LTljZWU5ZmI3N2FjMSI+PHBhdGggZD0iTTM3OC43ODMsMTcxLjE4OUw0MjQuMzYwLDE3MS4xODlMNDI0LjM2MCwxNDYuMDk5TDMwNy43NDksMTQ2LjA5OUwzMDcuNzQ5LDE3MS4xODlMMzUzLjMyNywxNzEuMTg5TDM1My4zMjcsMzAwLjE2MEwzNzguNzgzLDMwMC4xNjBaIi8+PC9nPjwvZz48ZyBpZD0ic2hhcGUtNTBlZGZiNzItNThjMy04MDZkLTgwMDctOWNlZTlmYjc3YWMyIj48ZyBjbGFzcz0iZmlsbHMiIGlkPSJmaWxscy01MGVkZmI3Mi01OGMzLTgwNmQtODAwNy05Y2VlOWZiNzdhYzIiPjxwYXRoIGQ9Ik00NjAuOTMzLDI2Mi45NjdMNTI4Ljg4OCwyNjIuOTY3TDU0My40NjYsMzAwLjE2MUw1NzAuMTU2LDMwMC4xNjFMNTA2LjkyMSwxNDUuMDAwTDQ4My41MTgsMTQ1LjAwMEw0MjAuMjg0LDMwMC4xNjFMNDQ2LjE1MiwzMDAuMTYxWk01MTkuNjUwLDIzOC45NzVMNDcwLjE3NCwyMzguOTc1TDQ5NC44MDksMTc3LjM1MVoiLz48L2c+PC9nPjxnIGlkPSJzaGFwZS01MGVkZmI3Mi01OGMzLTgwNmQtODAwNy05Y2VlOWZiNzdhYzMiPjxnIGNsYXNzPSJmaWxscyIgaWQ9ImZpbGxzLTUwZWRmYjcyLTU4YzMtODA2ZC04MDA3LTljZWU5ZmI3N2FjMyI+PHBhdGggZD0iTTYxNS45NTIsMTQ2LjEwMEw1OTMuMTY0LDE0Ni4xMDBMNTkzLjE2NCwzMDAuMTYxTDY5NS4zOTAsMzAwLjE2MUw2OTUuMzkwLDI3NS43MzJDNjY4LjkxMSwyNzUuNzMyLDY0Mi40MzEsMjc1LjczMiw2MTUuOTUyLDI3NS43MzJaIi8+PC9nPjwvZz48ZyBpZD0ic2hhcGUtNTBlZGZiNzItNThjMy04MDZkLTgwMDctOWNlZTlmYjc3YWM0Ij48ZyBjbGFzcz0iZmlsbHMiIGlkPSJmaWxscy01MGVkZmI3Mi01OGMzLTgwNmQtODAwNy05Y2VlOWZiNzdhYzQiPjxwYXRoIGQ9Ik04MjguMjIwLDE0Ni4xMDBMNzIxLjg3MywxNDYuMTAwTDcyMS44NzMsMzAwLjE2MUw4MjkuMjQ3LDMwMC4xNjFMODI5LjI0NywyNzUuNzMyTDc0Ni45MjAsMjc1LjczMkw3NDYuOTIwLDIzNC41NzRMODE4Ljk4MSwyMzQuNTc0TDgxOC45ODEsMjEwLjE0Nkw3NDYuOTIwLDIxMC4xNDZMNzQ2LjkyMCwxNzAuNTMwTDgyOC4yMjAsMTcwLjUzMFoiLz48L2c+PC9nPjxnIGlkPSJzaGFwZS01MGVkZmI3Mi01OGMzLTgwNmQtODAwNy05Y2VlOWZiNzdhYzUiPjxnIGNsYXNzPSJmaWxscyIgaWQ9ImZpbGxzLTUwZWRmYjcyLTU4YzMtODA2ZC04MDA3LTljZWU5ZmI3N2FjNSI+PHBhdGggZD0iTTk1MS4xOTYsMTk2LjM5MUM5NTEuMTk2LDIwNC4zNDksOTQ4LjUyNywyMTAuNjk2LDk0My4xNTUsMjE1LjM5MEM5MzcuODE3LDIyMC4xMjMsOTMwLjU5NywyMjIuNDY5LDkyMS41MjksMjIyLjQ2OUw4ODQuNDcyLDIyMi40NjlMODg0LjQ3MiwxNzAuNTMwTDkyMS4zMjQsMTcwLjUzMEM5MzAuODAyLDE3MC41MzAsOTM4LjE1OCwxNzIuNjk0LDk0My4zNjEsMTc3LjA1OEM5NDguNTk2LDE4MS4zODcsOTUxLjE5NiwxODcuODQzLDk1MS4xOTYsMTk2LjM5MVpaTTk4MS4zNzUsMzAwLjE2MUw5NDIuNTczLDI0MS44MzdDOTQ3LjYzNywyNDAuMzcwLDk1Mi4yNTcsMjM4LjI4MSw5NTYuNDMyLDIzNS41NjVDOTYwLjYwNSwyMzIuODUxLDk2NC4xOTksMjI5LjU0OSw5NjcuMjA5LDIyNS42NjJDOTcwLjIyMSwyMjEuNzczLDk3Mi41ODIsMjE3LjI5OCw5NzQuMjkyLDIxMi4yMzdDOTc2LjAwMywyMDcuMTc1LDk3Ni44NTgsMjAxLjQxNSw5NzYuODU4LDE5NC45NTlDOTc2Ljg1OCwxODcuNDc2LDk3NS42MjcsMTgwLjY5MSw5NzMuMTYzLDE3NC42MDFDOTcwLjY5OSwxNjguNTEyLDk2Ny4xNzUsMTYzLjM3Niw5NjIuNTkxLDE1OS4xOTRDOTU4LjAwNSwxNTUuMDEzLDk1Mi4zOTQsMTUxLjc4NSw5NDUuNzU2LDE0OS41MTBDOTM5LjExNywxNDcuMjM1LDkzMS42OTIsMTQ2LjEwMCw5MjMuNDgwLDE0Ni4xMDBMODU5LjQyNSwxNDYuMTAwTDg1OS40MjUsMzAwLjE2MUw4ODQuNDcyLDMwMC4xNjFMODg0LjQ3MiwyNDYuNDYwTDkxNi4xOTEsMjQ2LjQ2MEw5NTEuNjA2LDMwMC4xNjFaIi8+PC9nPjwvZz48L2c+PC9zdmc+" alt="GNU Taler">
+ </a>
+</header>
+<main>
+ <article class="status-card" aria-labelledby="page-title">
+ <div class="status-mark" aria-hidden="true">✓</div>
+ <p class="eyebrow">Payment complete</p>
+ <h1 id="page-title">Thank you for your payment</h1>
+ <p class="lede">{{ order_summary }}</p>
+ <dl class="details">
+ <dt>Paid</dt><dd>{{ order_amount }}</dd>
+ <dt>Merchant</dt><dd>{{ merchant_name }}</dd>
+ <dt>Order ID</dt><dd>{{ order_id }}</dd>
+ {{#has_refund}}<dt>Refunded</dt><dd>{{ refund_amount }}</dd>{{/has_refund}}
+ </dl>
+ {{#fulfillment_message}}<p class="message">{{ fulfillment_message }}</p>{{/fulfillment_message}}
+ {{#fulfillment_url}}<a class="secondary-link" href="{{ fulfillment_url }}" rel="noreferrer" referrerpolicy="no-referrer">Continue to your purchase</a>{{/fulfillment_url}}
+ </article>
+</main>
+<footer class="site-footer">
+ <p>Payments with privacy by <a href="https://taler.net/" rel="noreferrer" referrerpolicy="no-referrer">GNU Taler</a></p>
+ <p>Copyright © 2014–2026 Taler Systems SA</p>
+</footer>
+</body>
+</html>
diff --git a/src/meson.build b/src/meson.build
@@ -1,4 +1,5 @@
# This build file is in the public domain
+subdir('frontend')
subdir('include')
subdir('util')
subdir('bank')
diff --git a/src/testing/meson.build b/src/testing/meson.build
@@ -8,6 +8,7 @@ check_SCRIPTS = [
'test_merchant_instance_purge',
'test_merchant_kyc',
'test_merchant_order_creation',
+ 'test_merchant_order_refund',
'test_merchant_order_autocleanup',
'test_merchant_product_creation',
'test_merchant_statistics',
diff --git a/src/testing/test_merchant_order_creation.sh b/src/testing/test_merchant_order_creation.sh
@@ -5,9 +5,26 @@ set -eu
function clean_wallet() {
rm -f "${WALLET_DB}"
+ rm -f "${HTML_RESPONSE}"
exit_cleanup
}
+function assert_html_contains() {
+ if ! grep -Fq -- "$2" "$1"
+ then
+ cat "$1" >&2
+ exit_fail "Expected rendered HTML to contain: $2"
+ fi
+}
+
+function assert_html_rendered() {
+ if grep -Fq -- '{{' "$1"
+ then
+ cat "$1" >&2
+ exit_fail "Rendered HTML contains unresolved Mustache markup"
+ fi
+}
+
# Replace with 0 for nexus...
USE_FAKEBANK=1
@@ -38,6 +55,7 @@ setup -c "test_template.conf" \
-em \
$BANK_FLAGS
LAST_RESPONSE=$(mktemp -p "${TMPDIR:-/tmp}" test_response.conf-XXXXXX)
+HTML_RESPONSE="${LAST_RESPONSE}.html"
CONF="test_template.conf.edited"
WALLET_DB=$(mktemp -p "${TMPDIR:-/tmp}" test_wallet.json-XXXXXX)
EXCHANGE_URL="http://localhost:8081/"
@@ -173,7 +191,7 @@ RANDOM_IMG='data:image/png;base64,abcdefg'
echo -n "Creating order without TOKEN..."
STATUS=$(curl 'http://localhost:9966/private/orders' \
- -d '{"create_token":false,"refund_delay":{"d_us":0},"order":{"amount":"TESTKUDOS:7","summary":"3","products":[{"description":"desct","image":"'"$RANDOM_IMG"'","price":"TESTKUDOS:1","taxes":[],"unit":"u","quantity":1}]}}' \
+ -d '{"create_token":false,"refund_delay":{"d_us":0},"order":{"amount":"TESTKUDOS:7","summary":"3 <unsafe> & tea","products":[{"description":"desct","image":"'"$RANDOM_IMG"'","price":"TESTKUDOS:1","taxes":[],"unit":"u","quantity":1}]}}' \
-w "%{http_code}" -s -o "$LAST_RESPONSE")
if [ "$STATUS" != "200" ]
@@ -203,6 +221,23 @@ then
fi
echo "OK"
+echo -n "Checking unclaimed order HTML..."
+STATUS=$(curl -H 'Accept: text/html' \
+ "http://localhost:9966/orders/${ORDER_ID}" \
+ -w "%{http_code}" -s -o "$HTML_RESPONSE")
+if [ "$STATUS" != "402" ]
+then
+ cat "$HTML_RESPONSE" >&2
+ exit_fail "Expected 402 payment HTML. Got: $STATUS"
+fi
+assert_html_contains "$HTML_RESPONSE" 'Pay with GNU Taler'
+assert_html_contains "$HTML_RESPONSE" 'TESTKUDOS:7'
+assert_html_contains "$HTML_RESPONSE" '3 <unsafe> & tea'
+assert_html_contains "$HTML_RESPONSE" "$ORDER_ID"
+assert_html_contains "$HTML_RESPONSE" 'class="qr-frame"'
+assert_html_rendered "$HTML_RESPONSE"
+echo "OK"
+
#
# CREATE AN ORDER WITHOUT TOKEN WITH FULLFILMENT URL
#
@@ -310,6 +345,20 @@ then
fi
echo "OK"
+echo -n "Checking multi-option order HTML..."
+STATUS=$(curl -H 'Accept: text/html' \
+ "http://localhost:9966/orders/${ORDER_ID}?token=${TOKEN}" \
+ -w "%{http_code}" -s -o "$HTML_RESPONSE")
+if [ "$STATUS" != "402" ]
+then
+ cat "$HTML_RESPONSE" >&2
+ exit_fail "Expected 402 payment HTML. Got: $STATUS"
+fi
+assert_html_contains "$HTML_RESPONSE" 'Expensive purchase'
+assert_html_contains "$HTML_RESPONSE" 'selected in your wallet'
+assert_html_rendered "$HTML_RESPONSE"
+echo "OK"
+
echo -n "Claming order with token family ..."
STATUS=$(curl http://localhost:9966/orders/"$ORDER_ID"/claim \
-d '{"nonce":"0FTTZ475NBECCZN97VFTN6DEKWVKJ8AQY9PWR6VS36JZQFS66YG0","token":"'"$TOKEN"'"}' \
@@ -323,6 +372,20 @@ fi
echo " OK"
+echo -n "Checking claimed order HTML..."
+STATUS=$(curl -H 'Accept: text/html' \
+ "http://localhost:9966/orders/${ORDER_ID}?token=${TOKEN}" \
+ -w "%{http_code}" -s -o "$HTML_RESPONSE")
+if [ "$STATUS" != "402" ]
+then
+ cat "$HTML_RESPONSE" >&2
+ exit_fail "Expected 402 claimed payment HTML. Got: $STATUS"
+fi
+assert_html_contains "$HTML_RESPONSE" 'Order claimed by wallet'
+assert_html_contains "$HTML_RESPONSE" 'data-claimed="true"'
+assert_html_rendered "$HTML_RESPONSE"
+echo "OK"
+
# echo -n "Fetching pay URL for order ..."
# STATUS=$(curl "http://localhost:9966/private/orders/${ORDER_ID}" \
# -w "%{http_code}" -s -o "$LAST_RESPONSE")
@@ -515,6 +578,21 @@ then
exit_fail "Order status should be 'paid'. got: $ORDER_STATUS"
fi
+echo -n "Checking paid order HTML..."
+STATUS=$(curl -H 'Accept: text/html' \
+ "http://localhost:9966/orders/${ORDER_ID}?token=${TOKEN}" \
+ -w "%{http_code}" -s -o "$HTML_RESPONSE")
+if [ "$STATUS" != "200" ]
+then
+ cat "$HTML_RESPONSE" >&2
+ exit_fail "Expected 200 paid order HTML. Got: $STATUS"
+fi
+assert_html_contains "$HTML_RESPONSE" 'Payment complete'
+assert_html_contains "$HTML_RESPONSE" 'TESTKUDOS:1'
+assert_html_contains "$HTML_RESPONSE" "$ORDER_ID"
+assert_html_rendered "$HTML_RESPONSE"
+echo "OK"
+
#
# WIRE TRANSFER TO MERCHANT AND NOTIFY BACKEND
#
diff --git a/src/testing/test_merchant_order_refund.sh b/src/testing/test_merchant_order_refund.sh
@@ -5,9 +5,26 @@ set -eu
function clean_wallet() {
echo rm -f "${WALLET_DB}"
+ rm -f "${HTML_RESPONSE}"
exit_cleanup
}
+function assert_html_contains() {
+ if ! grep -Fq -- "$2" "$1"
+ then
+ cat "$1" >&2
+ exit_fail "Expected rendered HTML to contain: $2"
+ fi
+}
+
+function assert_html_rendered() {
+ if grep -Fq -- '{{' "$1"
+ then
+ cat "$1" >&2
+ exit_fail "Rendered HTML contains unresolved Mustache markup"
+ fi
+}
+
# Replace with 0 for nexus...
USE_FAKEBANK=1
@@ -38,6 +55,7 @@ setup -c "test_template.conf" \
-r "merchant-exchange-default" \
$BANK_FLAGS
LAST_RESPONSE=$(mktemp -p "${TMPDIR:-/tmp}" test_response.conf-XXXXXX)
+HTML_RESPONSE="${LAST_RESPONSE}.html"
CONF="test_template.conf.edited"
WALLET_DB=$(mktemp -p "${TMPDIR:-/tmp}" test_wallet.json-XXXXXX)
EXCHANGE_URL="http://localhost:8081/"
@@ -234,6 +252,21 @@ fi
REFUND_URI=$(jq -e -r .taler_refund_uri < "$LAST_RESPONSE")
echo " OK"
+echo -n "Checking refund HTML..."
+STATUS=$(curl -H 'Accept: text/html' \
+ "http://localhost:9966/orders/${ORDER_ID}?token=${TOKEN}" \
+ -w "%{http_code}" -s -o "$HTML_RESPONSE")
+if [ "$STATUS" != "200" ]
+then
+ cat "$HTML_RESPONSE" >&2
+ exit_fail "Expected 200 refund HTML. Got: $STATUS"
+fi
+assert_html_contains "$HTML_RESPONSE" 'Collect your refund'
+assert_html_contains "$HTML_RESPONSE" 'TESTKUDOS:1'
+assert_html_contains "$HTML_RESPONSE" 'class="qr-frame"'
+assert_html_rendered "$HTML_RESPONSE"
+echo "OK"
+
REFUND_START=$(date +%s)
echo "First refund order ${REFUND_URI} ..."
set -x