From 3f2eb7b10561e7a8b7f88e182fe54db0b5b93d3f Mon Sep 17 00:00:00 2001 From: Hussain Nagaria Date: Thu, 4 Jun 2026 12:09:39 +0530 Subject: [PATCH] fix: auto-select a company when no default is set (#4) Task: Ledger Lab page opened with no default company showed "No company found. Please set a default company." and empty boxes (GitHub issue #4). Key decisions: - Frontend now resolves a company before the first load: if Frappe's client default ("company") is unset, fall back to the first available Company (frappe.db.get_list, oldest first) so the page always opens with data instead of erroring out. - refresh() also syncs the header picker to the server-resolved company, so the field never shows blank while data is loaded (covers the global-default-only case). The change-handler guard prevents a reload loop on programmatic set_value. Files changed: - ledger_lab/ledger_lab/page/ledger_lab/ledger_lab.js (new async init_company(); constructor sequencing; refresh() picker sync) Verified (agent-browser, ledger.localhost): - Cleared global + user company defaults -> reproduced the warning/empty boxes, then confirmed fix falls back to BWH and loads data, no warning. - Restored defaults -> normal case still selects BWH, loads data. Notes for next iteration: only one company (BWH) exists on this bench, so company-switching wasn't re-exercised (logic unchanged). Issue #5 (basic transaction-list filters: show-cancelled, root-type) remains open. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../ledger_lab/page/ledger_lab/ledger_lab.js | 34 +++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/ledger_lab/ledger_lab/page/ledger_lab/ledger_lab.js b/ledger_lab/ledger_lab/page/ledger_lab/ledger_lab.js index de55b9c..3521c7c 100644 --- a/ledger_lab/ledger_lab/page/ledger_lab/ledger_lab.js +++ b/ledger_lab/ledger_lab/page/ledger_lab/ledger_lab.js @@ -80,12 +80,37 @@ class LedgerLab { this.render_skeleton(); this.setup_controls(); this.bind_realtime(); - this.refresh(); - this.load_feed(); + // Resolve a company before the first load so the dashboard always opens + // with data instead of erroring out when no default company is set. + this.init_company().then(() => { + this.refresh(); + this.load_feed(); + }); // Keep the sticky badges' relative times ("just now" → "2m ago") fresh. this.impact_timer = setInterval(() => this.tick_impact_times(), 30000); } + // Ensure a company is always selected on open. Frappe's default ("company") + // can be unset for a user or a freshly-set-up site; rather than letting the + // server error out with "No company found", fall back to the first available + // company so the page opens with data. Keeps the header picker in sync. + async init_company() { + if (!this.company) { + try { + const rows = await frappe.db.get_list("Company", { + fields: ["name"], + order_by: "creation asc", + limit: 1, + }); + if (rows && rows.length) this.company = rows[0].name; + } catch (e) { + // Permission/query issue — leave unset; refresh() surfaces the + // server's message rather than masking it. + } + } + if (this.company) this.company_field.set_value(this.company); + } + render_skeleton() { // All boxes except the derived Net Profit are clickable to reveal the // constituent accounts of that root type (phase 5 drill-down). @@ -592,6 +617,11 @@ class LedgerLab { callback: (r) => { if (!r.message) return; this.company = r.message.company; + // Reflect the server-resolved company in the header picker (it may + // have been blank if no client-side default was set). + if (this.company_field && this.company_field.get_value() !== this.company) { + this.company_field.set_value(this.company); + } this.currency = r.message.currency; this.date_range = r.message.date_range || { start: null, end: null }; const b = r.message.boxes || {};