// qbo_helper.js require('dotenv').config(); const OAuthClient = require('intuit-oauth'); let oauthClient = null; const getOAuthClient = () => { if (!oauthClient) { oauthClient = new OAuthClient({ clientId: process.env.QBO_CLIENT_ID, clientSecret: process.env.QBO_CLIENT_SECRET, environment: process.env.QBO_ENVIRONMENT || 'sandbox', redirectUri: process.env.QBO_REDIRECT_URI, token: { access_token: process.env.QBO_ACCESS_TOKEN || '', refresh_token: process.env.QBO_REFRESH_TOKEN || '', realmId: process.env.QBO_REALM_ID } }); } return oauthClient; }; async function makeQboApiCall(requestOptions) { const client = getOAuthClient(); // Funktion zum Aktualisieren des Tokens const doRefresh = async () => { console.log("🔄 QBO Token Refresh wird ausgeführt (401 Error gefangen)..."); try { const authResponse = await client.refresh(); console.log("✅ Token erfolgreich erneuert."); // Hier müsste man idealerweise die neuen Tokens speichern return authResponse; } catch (e) { console.error("❌ Refresh fehlgeschlagen:", e.originalMessage || e); throw e; } }; // --- ÄNDERUNG: KEINE VORAB-PRÜFUNG MEHR --- // Wir vertrauen darauf, dass der Token in der .env aktuell ist (da du ihn gerade generiert hast). // Wir entfernen client.isAccessTokenValid(), da dies oft falsch negativ ist nach Neustart. try { // Versuch 1: Einfach machen! const response = await client.makeApiCall(requestOptions); // Prüfen, ob QBO eine Fehlermeldung im Body sendet (trotz HTTP 200/400) const data = response.getJson ? response.getJson() : response.json; if (data.fault && data.fault.error) { const errorCode = data.fault.error[0].code; // Fehler 3202 = Missing Access Token / Invalid // Manchmal sendet QBO auch 401 im Body if (errorCode === '3202' || errorCode === '3100') { console.log(`⚠️ QBO meldet Token-Fehler (${errorCode}). Versuche Refresh und Retry...`); await doRefresh(); return await client.makeApiCall(requestOptions); } // Anderen API-Fehler werfen (z.B. Validierung) throw new Error(`QBO API Error ${errorCode}: ${data.fault.error[0].message}`); } return response; } catch (e) { // HTTP 401 Unauthorized fangen -> Das ist der ECHTE Indikator, dass der Token abgelaufen ist const isAuthError = e.response?.status === 401 || (e.authResponse && e.authResponse.response && e.authResponse.response.status === 401); if (isAuthError) { console.log("⚠️ 401 Unauthorized erhalten. Versuche Refresh und Retry..."); await doRefresh(); return await client.makeApiCall(requestOptions); } // Alle anderen Fehler weiterwerfen throw e; } } module.exports = { getOAuthClient, makeQboApiCall };