require('dotenv').config(); const OAuthClient = require('intuit-oauth'); const { Client } = require('pg'); // --- KONFIGURATION --- const totalLimit = null; // --------------------- const config = { 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: { // Wir brauchen initial nur den Refresh Token, Access holen wir uns neu access_token: process.env.QBO_ACCESS_TOKEN, refresh_token: process.env.QBO_REFRESH_TOKEN, realmId: process.env.QBO_REALM_ID } }; // SPEZIAL-CONFIG FรœR LOKALEN ZUGRIFF AUF DOCKER DB const dbConfig = { user: process.env.DB_USER, // WICHTIG: Lokal ist es immer localhost host: 'localhost', database: process.env.DB_NAME, password: process.env.DB_PASSWORD, // WICHTIG: Laut deinem docker-compose mapst du 5433 auf 5432! port: 5433, }; async function importCustomers() { const oauthClient = new OAuthClient(config); const pgClient = new Client(dbConfig); try { // console.log("๐Ÿ”„ 1. Versuche Token zu erneuern..."); // try { // // Token Refresh erzwingen bevor wir starten // const authResponse = await oauthClient.refresh(); // console.log("โœ… Token erfolgreich erneuert!"); // // Optional: Das neue Token in der Session speichern, falls nรถtig // } catch (tokenErr) { // console.error("โŒ Token Refresh fehlgeschlagen. Prรผfe QBO_REFRESH_TOKEN in .env"); // console.error(tokenErr.originalMessage || tokenErr); // return; // Abbruch // } console.log(`๐Ÿ”Œ 2. Verbinde zur DB (Port ${dbConfig.port})...`); await pgClient.connect(); console.log(`โœ… DB Verbunden.`); // --- AB HIER DER NORMALE IMPORT --- let startPosition = 1; let totalProcessed = 0; let hasMore = true; while (hasMore) { let limitForThisBatch = 100; if (totalLimit) { const remaining = totalLimit - totalProcessed; if (remaining <= 0) break; limitForThisBatch = Math.min(100, remaining); } const query = `SELECT * FROM Customer STARTPOSITION ${startPosition} MAXRESULTS ${limitForThisBatch}`; console.log(`๐Ÿ“ก QBO Request: Hole ${limitForThisBatch} Kunden ab Pos ${startPosition}...`); const baseUrl = config.environment === 'production' ? 'https://quickbooks.api.intuit.com/' : 'https://sandbox-quickbooks.api.intuit.com/'; const response = await oauthClient.makeApiCall({ url: `${baseUrl}v3/company/${config.token.realmId}/query?query=${encodeURI(query)}`, method: 'GET', }); const data = response.getJson ? response.getJson() : response.json; const customers = data.QueryResponse?.Customer || []; console.log(`๐Ÿ“ฅ QBO Response: ${customers.length} Kunden erhalten.`); if (customers.length === 0) { hasMore = false; break; } for (const c of customers) { try { const rawPhone = c.PrimaryPhone?.FreeFormNumber || ""; const formattedAccountNumber = rawPhone.replace(/\D/g, ""); const sql = ` INSERT INTO customers ( name, line1, line2, line3, line4, city, state, zip_code, account_number, email, phone, phone2, taxable, qbo_id, qbo_sync_token, updated_at ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, NOW()) ON CONFLICT (qbo_id) DO UPDATE SET name = EXCLUDED.name, line1 = EXCLUDED.line1, line2 = EXCLUDED.line2, line3 = EXCLUDED.line3, line4 = EXCLUDED.line4, city = EXCLUDED.city, state = EXCLUDED.state, zip_code = EXCLUDED.zip_code, email = EXCLUDED.email, phone = EXCLUDED.phone, phone2 = EXCLUDED.phone2, qbo_sync_token = EXCLUDED.qbo_sync_token, taxable = EXCLUDED.taxable, updated_at = NOW(); `; const values = [ c.CompanyName || c.DisplayName, c.BillAddr?.Line1 || null, c.BillAddr?.Line2 || null, c.BillAddr?.Line3 || null, c.BillAddr?.Line4 || null, c.BillAddr?.City || null, c.BillAddr?.CountrySubDivisionCode || null, c.BillAddr?.PostalCode || null, formattedAccountNumber || null, c.PrimaryEmailAddr?.Address || null, c.PrimaryPhone?.FreeFormNumber || null, c.AlternatePhone?.FreeFormNumber || null, c.Taxable || false, c.Id, c.SyncToken ]; await pgClient.query(sql, values); totalProcessed++; process.stdout.write("."); } catch (rowError) { console.error(`\nโŒ DB Fehler bei Kunde ID ${c.Id}:`, rowError.message); } } console.log(""); if (customers.length < limitForThisBatch) hasMore = false; startPosition += customers.length; } console.log(`\n๐ŸŽ‰ Fertig! ${totalProcessed} Kunden verarbeitet.`); } catch (e) { console.error("\n๐Ÿ’€ FATAL ERROR:", e.message); if(e.authResponse) console.log(JSON.stringify(e.authResponse, null, 2)); } finally { await pgClient.end(); } } importCustomers();