better logging

This commit is contained in:
2026-04-02 12:07:39 -05:00
parent 0b738ba530
commit 6e45ce6cf9
2 changed files with 17 additions and 11 deletions

View File

@@ -2,6 +2,14 @@
* Quote & Invoice System - Main Entry Point * Quote & Invoice System - Main Entry Point
* Modularized Backend * Modularized Backend
*/ */
// ── Global timestamp logger must be first line before any require ──
const _ts = () => new Date().toISOString().replace('T', ' ').substring(0, 19);
const _origLog = console.log.bind(console);
const _origWarn = console.warn.bind(console);
const _origError = console.error.bind(console);
console.log = (...a) => _origLog(`[${_ts()}]`, ...a);
console.warn = (...a) => _origWarn(`[${_ts()}]`, ...a);
console.error = (...a) => _origError(`[${_ts()}]`, ...a);
const express = require('express'); const express = require('express');
const path = require('path'); const path = require('path');
const puppeteer = require('puppeteer'); const puppeteer = require('puppeteer');

View File

@@ -409,8 +409,6 @@ router.post('/record-payment', async (req, res) => {
} }
}); });
// Timestamp helper - add once at the top of qbo.js after the requires
const log = (msg) => console.log(`[${new Date().toISOString().replace('T',' ').substring(0,19)}] ${msg}`);
// POST sync payments from QBO // POST sync payments from QBO
router.post('/sync-payments', async (req, res) => { router.post('/sync-payments', async (req, res) => {
@@ -449,7 +447,7 @@ router.post('/sync-payments', async (req, res) => {
(data.QueryResponse?.Invoice || []).forEach(inv => qboInvoices.set(inv.Id, inv)); (data.QueryResponse?.Invoice || []).forEach(inv => qboInvoices.set(inv.Id, inv));
} }
log(`🔍 QBO Sync: ${openInvoices.length} invoices checked, ${qboInvoices.size} loaded from QBO`); console.log(`🔍 QBO Sync: ${openInvoices.length} invoices checked, ${qboInvoices.size} loaded from QBO`);
// ── Collect all unique Payment IDs that need to be fetched ──────── // ── Collect all unique Payment IDs that need to be fetched ────────
// Instead of fetching each payment one-by-one, collect all IDs first // Instead of fetching each payment one-by-one, collect all IDs first
@@ -470,7 +468,7 @@ router.post('/sync-payments', async (req, res) => {
const paymentDepositMap = new Map(); // paymentId -> isDeposited (bool) const paymentDepositMap = new Map(); // paymentId -> isDeposited (bool)
if (paymentIdsToFetch.size > 0) { if (paymentIdsToFetch.size > 0) {
log(`💳 Fetching ${paymentIdsToFetch.size} unique payment(s) from QBO...`); console.log(`💳 Fetching ${paymentIdsToFetch.size} unique payment(s) from QBO...`);
const pmIds = [...paymentIdsToFetch]; const pmIds = [...paymentIdsToFetch];
const pmBatchSize = 30; const pmBatchSize = 30;
for (let i = 0; i < pmIds.length; i += pmBatchSize) { for (let i = 0; i < pmIds.length; i += pmBatchSize) {
@@ -487,10 +485,10 @@ router.post('/sync-payments', async (req, res) => {
paymentDepositMap.set(pm.Id, isDeposited); paymentDepositMap.set(pm.Id, isDeposited);
} }
} catch (e) { } catch (e) {
log(`⚠️ Payment batch fetch error (non-fatal): ${e.message}`); console.log(`⚠️ Payment batch fetch error (non-fatal): ${e.message}`);
} }
} }
log(`💳 Payment deposit status loaded for ${paymentDepositMap.size} payment(s)`); console.log(`💳 Payment deposit status loaded for ${paymentDepositMap.size} payment(s)`);
} }
// ── Process invoices ─────────────────────────────────────────────── // ── Process invoices ───────────────────────────────────────────────
@@ -529,7 +527,7 @@ router.post('/sync-payments', async (req, res) => {
[status, localInv.id] [status, localInv.id]
); );
updated++; updated++;
log(` ✅ #${localInv.invoice_number}: ${status}`); console.log(` ✅ #${localInv.invoice_number}: ${status}`);
} }
const diff = qboTotal - localPaid; const diff = qboTotal - localPaid;
@@ -547,7 +545,7 @@ router.post('/sync-payments', async (req, res) => {
[payResult.rows[0].id, localInv.id, diff] [payResult.rows[0].id, localInv.id, diff]
); );
newPayments++; newPayments++;
log(` 💰 #${localInv.invoice_number}: +$${diff.toFixed(2)} synced`); console.log(` 💰 #${localInv.invoice_number}: +$${diff.toFixed(2)} synced`);
} }
} else if (qboBalance > 0 && qboBalance < qboTotal) { } else if (qboBalance > 0 && qboBalance < qboTotal) {
@@ -576,7 +574,7 @@ router.post('/sync-payments', async (req, res) => {
[payResult.rows[0].id, localInv.id, diff] [payResult.rows[0].id, localInv.id, diff]
); );
newPayments++; newPayments++;
log(` 📎 #${localInv.invoice_number}: Partial +$${diff.toFixed(2)} ($${qboPaid.toFixed(2)} / $${qboTotal.toFixed(2)})`); console.log(` 📎 #${localInv.invoice_number}: Partial +$${diff.toFixed(2)} ($${qboPaid.toFixed(2)} / $${qboTotal.toFixed(2)})`);
} }
} }
} }
@@ -588,7 +586,7 @@ router.post('/sync-payments', async (req, res) => {
await dbClient.query('COMMIT'); await dbClient.query('COMMIT');
log(`✅ Sync complete: ${updated} updated, ${newPayments} new payments`); console.log(`✅ Sync complete: ${updated} updated, ${newPayments} new payments`);
res.json({ res.json({
synced: updated, synced: updated,
new_payments: newPayments, new_payments: newPayments,
@@ -598,7 +596,7 @@ router.post('/sync-payments', async (req, res) => {
} catch (error) { } catch (error) {
await dbClient.query('ROLLBACK').catch(() => {}); await dbClient.query('ROLLBACK').catch(() => {});
log(`❌ Sync Error: ${error.message}`); console.log(`❌ Sync Error: ${error.message}`);
res.status(500).json({ error: 'Sync failed: ' + error.message }); res.status(500).json({ error: 'Sync failed: ' + error.message });
} finally { } finally {
dbClient.release(); dbClient.release();