fix for qbo changes
This commit is contained in:
@@ -14,6 +14,7 @@ const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
let oauthClient = null;
|
||||
let _lastSavedAccessToken = null;
|
||||
const tokenFile = path.join(__dirname, 'qbo_token.json');
|
||||
|
||||
const getOAuthClient = () => {
|
||||
@@ -72,13 +73,16 @@ function saveTokens() {
|
||||
try {
|
||||
const client = getOAuthClient();
|
||||
const token = client.getToken();
|
||||
|
||||
// Debug: Was genau bekommen wir vom Client?
|
||||
console.log("💾 Speichere Token... refresh_token vorhanden:", !!token.refresh_token,
|
||||
"| access_token Länge:", (token.access_token || '').length,
|
||||
"| realmId:", token.realmId || 'FEHLT');
|
||||
|
||||
// Sicherstellen dass alle Pflichtfelder vorhanden sind
|
||||
|
||||
// ── NEU: Nur speichern wenn access_token sich tatsächlich geändert hat ──
|
||||
if (token.access_token === _lastSavedAccessToken) {
|
||||
return; // Token unverändert – kein Save, kein Log
|
||||
}
|
||||
_lastSavedAccessToken = token.access_token;
|
||||
|
||||
const ts = new Date().toISOString().replace('T',' ').substring(0,19);
|
||||
console.log(`[${ts}] 💾 Token changed – saving (realmId: ${token.realmId || 'FEHLT'})`);
|
||||
|
||||
const tokenToSave = {
|
||||
token_type: token.token_type || 'bearer',
|
||||
access_token: token.access_token,
|
||||
@@ -88,16 +92,17 @@ function saveTokens() {
|
||||
realmId: token.realmId || process.env.QBO_REALM_ID,
|
||||
createdAt: token.createdAt || new Date().toISOString()
|
||||
};
|
||||
|
||||
|
||||
fs.writeFileSync(tokenFile, JSON.stringify(tokenToSave, null, 2));
|
||||
console.log("💾 Tokens erfolgreich in qbo_token.json gespeichert.");
|
||||
console.log(`[${ts}] 💾 Token saved to qbo_token.json`);
|
||||
} catch (e) {
|
||||
console.error("❌ Fehler beim Speichern der Tokens:", e.message);
|
||||
console.error(`❌ Fehler beim Speichern der Tokens: ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
async function makeQboApiCall(requestOptions) {
|
||||
const client = getOAuthClient();
|
||||
const ts = () => new Date().toISOString().replace('T',' ').substring(0,19);
|
||||
|
||||
const currentToken = client.getToken();
|
||||
if (!currentToken || !currentToken.refresh_token) {
|
||||
@@ -105,29 +110,17 @@ async function makeQboApiCall(requestOptions) {
|
||||
}
|
||||
|
||||
const doRefresh = async () => {
|
||||
console.log("🔄 QBO Token Refresh wird ausgeführt...");
|
||||
|
||||
// Den Refresh Token als String extrahieren
|
||||
console.log(`[${ts()}] 🔄 QBO Token Refresh...`);
|
||||
const refreshTokenStr = currentToken.refresh_token;
|
||||
console.log("🔑 Refresh Token (erste 15 Zeichen):", refreshTokenStr.substring(0, 15) + "...");
|
||||
|
||||
try {
|
||||
// KRITISCHER FIX: refreshUsingToken() statt refresh() verwenden!
|
||||
//
|
||||
// refresh() ruft intern validateToken() auf, das bei unvollständigem
|
||||
// Token-Objekt "The Refresh token is invalid" wirft — OHNE jemals
|
||||
// Intuit zu kontaktieren.
|
||||
//
|
||||
// refreshUsingToken() akzeptiert den RT als String und umgeht das.
|
||||
const authResponse = await client.refreshUsingToken(refreshTokenStr);
|
||||
console.log("✅ Token erfolgreich erneuert via refreshUsingToken().");
|
||||
saveTokens();
|
||||
console.log(`[${ts()}] ✅ Token refreshed via refreshUsingToken()`);
|
||||
saveTokens(); // saveTokens prüft selbst ob sich was geändert hat
|
||||
return authResponse;
|
||||
} catch (e) {
|
||||
const errMsg = e.originalMessage || e.message || String(e);
|
||||
console.error("❌ Refresh fehlgeschlagen:", errMsg);
|
||||
if (e.intuit_tid) console.error(" intuit_tid:", e.intuit_tid);
|
||||
|
||||
console.error(`[${ts()}] ❌ Refresh failed: ${errMsg}`);
|
||||
if (e.intuit_tid) console.error(` intuit_tid: ${e.intuit_tid}`);
|
||||
if (errMsg.includes('invalid_grant')) {
|
||||
throw new Error(
|
||||
"Der Refresh Token ist bei Intuit ungültig (invalid_grant). " +
|
||||
@@ -140,35 +133,32 @@ async function makeQboApiCall(requestOptions) {
|
||||
|
||||
try {
|
||||
const response = await client.makeApiCall(requestOptions);
|
||||
|
||||
const data = response.getJson ? response.getJson() : response.json;
|
||||
|
||||
|
||||
if (data.fault && data.fault.error) {
|
||||
const errorCode = data.fault.error[0].code;
|
||||
|
||||
if (errorCode === '3200' || errorCode === '3202' || errorCode === '3100') {
|
||||
console.log(`⚠️ QBO meldet Token-Fehler (${errorCode}). Versuche Refresh und Retry...`);
|
||||
console.log(`[${ts()}] ⚠️ QBO Token-Fehler (${errorCode}) – Refresh & Retry...`);
|
||||
await doRefresh();
|
||||
return await client.makeApiCall(requestOptions);
|
||||
}
|
||||
throw new Error(`QBO API Error ${errorCode}: ${data.fault.error[0].message}`);
|
||||
}
|
||||
|
||||
saveTokens();
|
||||
// ── Kein saveTokens() hier – Token hat sich nicht geändert ──
|
||||
return response;
|
||||
|
||||
} catch (e) {
|
||||
const isAuthError =
|
||||
e.response?.status === 401 ||
|
||||
(e.authResponse && e.authResponse.response && e.authResponse.response.status === 401) ||
|
||||
const isAuthError =
|
||||
e.response?.status === 401 ||
|
||||
(e.authResponse?.response?.status === 401) ||
|
||||
e.message?.includes('AuthenticationFailed');
|
||||
|
||||
if (isAuthError) {
|
||||
console.log("⚠️ 401 Unauthorized / AuthFailed erhalten. Versuche Refresh und Retry...");
|
||||
console.log(`[${ts()}] ⚠️ 401 – Refresh & Retry...`);
|
||||
await doRefresh();
|
||||
return await client.makeApiCall(requestOptions);
|
||||
}
|
||||
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user