Files
fuj-management/go/internal/web/qr.go
Jan Novak fe935235e8
All checks were successful
Deploy to K8s / deploy (push) Successful in 8s
feat(go): M6.6 — /qr, /sync-bank, /flush-cache, /version pages
- GET /qr: Czech QR Platba PNG; ports Python qr_code() exactly
  (account validation, amount clamping, * stripping, SPD format)
- GET /sync-bank: Fio sync → infer → cache flush with captured log
- GET+POST /flush-cache: form + action, shows deleted count
- GET /version: JSON alias of /api/version (Python parity)
- FlushCache() added to membership.Sources; wired through api.Handler
- web.ActionHandlers{BankSync} closure-based dep injection for sync
- New dep: github.com/skip2/go-qrcode
- TestQRBuildSPD (9 cases), TestServeQR, TestServeFlushCache{GET,POST},
  TestServeSync, TestServeVersion added

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 14:26:54 +02:00

51 lines
1.3 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package web
import (
"fmt"
"regexp"
"strings"
"unicode/utf8"
qrcode "github.com/skip2/go-qrcode"
)
var validAccount = regexp.MustCompile(`^[A-Z]{2}\d{2,34}$|^\d{1,16}/\d{4}$`)
// BuildSPD builds a Czech QR Platba SPD string, matching Python's qr_code handler.
// Invalid account falls back to defaultAccount.
// Amount is clamped to [0, 10_000_000]; non-numeric input becomes "0.00".
// Message is truncated to 60 runes and stripped of '*' characters.
func BuildSPD(account, amount, message, defaultAccount string) string {
if !validAccount.MatchString(account) {
account = defaultAccount
}
var amtStr string
var f float64
if _, err := fmt.Sscanf(amount, "%f", &f); err != nil || f < 0 || f > 10_000_000 {
amtStr = "0.00"
} else {
amtStr = fmt.Sprintf("%.2f", f)
}
if utf8.RuneCountInString(message) > 60 {
runes := []rune(message)
message = string(runes[:60])
}
message = strings.ReplaceAll(message, "*", "")
var accStr string
if parts := strings.SplitN(account, "/", 2); len(parts) == 2 {
accStr = parts[0] + "*BC:" + parts[1]
} else {
accStr = account
}
return fmt.Sprintf("SPD*1.0*ACC:%s*AM:%s*CC:CZK*MSG:%s", accStr, amtStr, message)
}
// RenderQRCode encodes payload as a PNG QR code (256×256, error correction Medium).
func RenderQRCode(payload string) ([]byte, error) {
return qrcode.Encode(payload, qrcode.Medium, 256)
}