fix(qr): ServicePass Link URL-Handling & APPKILL Token Ablaufprüfung
All checks were successful
Build and Deploy / build (push) Successful in 52s

This commit is contained in:
DanielS
2026-09-22 22:20:44 +02:00
parent 35730c22c3
commit d8de844f4b

View File

@@ -60,20 +60,58 @@ async function processQrSetup(qrPayload) {
const cleanUrl = url.replace(/\/$/, '');
// 1. GET ServicePass: GET {url}/@LNK{servicepasslink}
const linkUrl = `${cleanUrl}/@LNK${servicepasslink}`;
const resLink = await fetch(linkUrl, {
method: 'GET',
headers: { 'User-Agent': 'Getraenkekarte-POS-Client/1.0' }
});
// Endpunkt-Varianten für ServicePass Link (Cloud-Instanzen unterstützen @LNK... oder @...)
const candidateUrls = [
`${cleanUrl}/@${servicepasslink}`,
`${cleanUrl}/@LNK${servicepasslink}`,
`${cleanUrl}/LNK${servicepasslink}`,
`${cleanUrl}/@LNK/${servicepasslink}`,
`${cleanUrl}/WWSVC/@LNK${servicepasslink}`
];
if (!resLink.ok) {
throw new Error(`Fehler beim Abruf von ServicePass (@LNK): ${resLink.status} ${resLink.statusText}`);
let resLink = null;
let responseText = '';
let usedUrl = '';
for (const cUrl of candidateUrls) {
try {
const res = await fetch(cUrl, {
method: 'GET',
headers: { 'User-Agent': 'Getraenkekarte-POS-Client/1.0' }
});
if (res.ok) {
resLink = res;
responseText = await res.text();
usedUrl = cUrl;
break;
}
} catch (e) {}
}
const passData = await resLink.json();
const passId = passData.passId || passData.PassId || passData.id;
const appId = passData.appId || passData.AppId || passData.key;
if (!resLink) {
throw new Error(`Fehler beim Abruf von ServicePass (@LNK): 404 Resource not found`);
}
let passId = '';
let appId = '';
try {
const passData = JSON.parse(responseText);
passId = passData.passId || passData.PassId || passData.id;
appId = passData.appId || passData.AppId || passData.key;
} catch (e) {
// Falls Text / Delimiter Format
if (responseText.includes('APPKILL')) {
throw new Error(`QR-Code Token abgelaufen oder bereits verbraucht (Server meldet: APPKILL). Bitte neuen QR-Code im Kassensystem erzeugen.`);
}
const parts = responseText.split('@)').map(s => s.trim()).filter(Boolean);
if (parts.length >= 2) {
passId = parts[0];
appId = parts[1];
} else {
throw new Error(`Unerwartete Antwort von ServicePass: ${responseText}`);
}
}
if (!passId || !appId) {
throw new Error('Antwort von ServicePass enthält keine gültige passId/appId');
@@ -86,7 +124,7 @@ async function processQrSetup(qrPayload) {
upsert.run('pos_app_id', appId);
if (mdcDeviceId) upsert.run('pos_cash_register', String(mdcDeviceId));
// 3. Pass aktivieren (PUT /WWSVC/EXECURL/{passId}/CASPOS.PUT/REGISTERID={mdcDeviceId}/ENTITY=SERVICEPASS/SERVICEPASS_ID={passId})
// 3. Pass aktivieren
const devId = mdcDeviceId || '1';
const activatePath = `/WWSVC/EXECURL/${passId}/CASPOS.PUT/REGISTERID=${devId}/ENTITY=SERVICEPASS/SERVICEPASS_ID=${passId}`;
const activateUrl = `${cleanUrl}${activatePath}`;