invoice-system/import_customers_qbo.js

157 lines
6.2 KiB
JavaScript

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();