diff options
| -rw-r--r-- | clients/bokftui.c | 19 | ||||
| -rw-r--r-- | clients/screens_dashboard.c | 21 | ||||
| -rw-r--r-- | clients/ui.c | 6 | ||||
| -rw-r--r-- | clients/ui.h | 1 | ||||
| -rw-r--r-- | docs/PROTOCOL.md | 1 | ||||
| -rw-r--r-- | docs/STATE.md | 5 | ||||
| -rw-r--r-- | docs/TUI-GUIDELINES.md | 8 | ||||
| -rwxr-xr-x | scripts/tui-golden.py | 33 |
8 files changed, 85 insertions, 9 deletions
diff --git a/clients/bokftui.c b/clients/bokftui.c index 867e63e..19a63cf 100644 --- a/clients/bokftui.c +++ b/clients/bokftui.c @@ -286,7 +286,9 @@ static int login_screen(struct app *a) } } -static int select_org(struct app *a) +/* Org picker; the cursor starts on the current org. 0 when one was + chosen (a->org set), -1 on Esc or error. */ +int select_org(struct app *a) { char *resp = client_rpc(&a->conn, "session.list_orgs", a->session, 0, "{}"); if (!resp || !client_ok(resp)) { @@ -319,17 +321,20 @@ static int select_org(struct app *a) free(name); free(role); } - int sel = tui_select_list("Välj organisation att representera", items, (int)n, - 0, 0, NULL, 0, NULL, 0); + int start = 0; + for (size_t i = 0; i < n; i++) + if (ids[i] == a->org) + start = (int)i; + int sel = tui_select_list("Välj organisation att representera", items, + (int)n, start, 0, NULL, 0, NULL, 0); for (size_t i = 0; i < n; i++) free(items[i]); free(items); free(resp); - if (sel < 0) - return -1; - a->org = ids[sel]; + if (sel >= 0) + a->org = ids[sel]; free(ids); - return 0; + return sel >= 0 ? 0 : -1; } static void usage(FILE *f) diff --git a/clients/screens_dashboard.c b/clients/screens_dashboard.c index 83b4f6a..127d4df 100644 --- a/clients/screens_dashboard.c +++ b/clients/screens_dashboard.c @@ -274,9 +274,27 @@ static const char *const MAIN_ITEMS[] = { "Rapporter", "Bokslut", "Bolaget", "System", "Ingående balans", "Räkenskapsår", + "Byt bolag", "Logga ut / avsluta", }; +/* Picks another org and reloads everything that belongs to the org: its + context (name, role, current fiscal year, series) and the remembered + list selections. */ +static void switch_org(struct app *a) +{ + int64_t old = a->org; + if (select_org(a) != 0 || a->org == old) + return; + a->voucher_sel = 0; + a->invoice_sel = 0; + a->customer_sel = 0; + a->employee_sel = 0; + a->payroll_sel = 0; + app_refresh_context(a); + update_status(a); +} + void dashboard(struct app *a) { static int last_sel = 0; @@ -335,6 +353,9 @@ void dashboard(struct app *a) select_fiscal_year(a); break; case 12: + switch_org(a); + break; + case 13: return; default: break; diff --git a/clients/ui.c b/clients/ui.c index cda0883..2eb2dfe 100644 --- a/clients/ui.c +++ b/clients/ui.c @@ -183,6 +183,12 @@ void replace_x_into(const char *src, double x, char *dst, size_t cap) void app_refresh_context(struct app *a) { + a->org_name[0] = '\0'; + a->role[0] = '\0'; + a->fy = 0; + a->fy_label[0] = '\0'; + a->fy_start[0] = '\0'; + a->fy_end[0] = '\0'; char args[64]; snprintf(args, sizeof args, "{\"org\":%lld}", (long long)a->org); char *resp = client_rpc(&a->conn, "session.use_org", a->session, 0, args); diff --git a/clients/ui.h b/clients/ui.h index 8574121..884adbf 100644 --- a/clients/ui.h +++ b/clients/ui.h @@ -76,6 +76,7 @@ void kr_whole(int64_t ore, char *buf, size_t n); int parse_x_double(const char *s, double *out); void replace_x_into(const char *src, double x, char *dst, size_t cap); void app_refresh_context(struct app *a); +int select_org(struct app *a); char *rpc_dry(struct app *a, const char *cmd, const char *args); char *read_file_b64(const char *path); char *file_browser(struct app *a, const char *start_dir); diff --git a/docs/PROTOCOL.md b/docs/PROTOCOL.md index 2bd889f..ae1098f 100644 --- a/docs/PROTOCOL.md +++ b/docs/PROTOCOL.md @@ -935,6 +935,7 @@ Args: `name:type(values)[!][=default]`, `!` = required. commands. Implemented screens (0.1.0-dev): - **Inloggning** — server, user, password; org picker when several exist. + **Byt bolag** in the main menu reopens the picker during the session. - **Dashboard** — status line with org, fiscal year, role and user. - **Verifikat** — list and detail view (rows with column headers, an underlag section separated by a rule, hash, link to corrected voucher); `c` diff --git a/docs/STATE.md b/docs/STATE.md index 9d954cd..31d6b14 100644 --- a/docs/STATE.md +++ b/docs/STATE.md @@ -14,6 +14,11 @@ unit tests and the docs consistency check. ## Resume here (2026-09-22) +- **Byt bolag (2026-09-23, branch `eff/switch-org`)**: a main-menu item + reopens the org picker and switches org in the running session (context + reloaded, list selections cleared). `app_refresh_context` now clears the + previous org's name/role/fiscal year first, so an org without a readable + year no longer shows the old one. - **Goto search (2026-09-23, branch `eff/goto-search`)**: `g` followed by a letter searches the row texts of any list or menu (case-insensitive, åäö too; up/down = next/previous match); a digit still jumps to a row number. diff --git a/docs/TUI-GUIDELINES.md b/docs/TUI-GUIDELINES.md index c2aff3d..68316e3 100644 --- a/docs/TUI-GUIDELINES.md +++ b/docs/TUI-GUIDELINES.md @@ -125,8 +125,12 @@ struct tui_action { ## Session start After login the org picker ("Välj organisation att representera") is always -shown; the selected org is fixed for the session (`--org ID` bypasses it for -scripts). The fiscal year is chosen from the dashboard and is changeable +shown (`--org ID` bypasses it for scripts). "Byt bolag" in the main menu +opens the same picker, with the cursor on the current org, and switches the +session to the chosen one: `session.use_org`, then the org's name, role, +current fiscal year and series are reloaded and the remembered list +selections are cleared; `Esc` keeps the current org. `Ctrl+R` keeps the +switched org. The fiscal year is chosen from the dashboard and is changeable during the session; the `Räkenskapsår` screen also closes and reopens years there. diff --git a/scripts/tui-golden.py b/scripts/tui-golden.py index 71e1273..0dfde5f 100755 --- a/scripts/tui-golden.py +++ b/scripts/tui-golden.py @@ -41,6 +41,8 @@ from pathlib import Path ORG_NAME = "Test AB" ORG_NR = "5560123456" +ORG2_NAME = "Andra AB" +ORG2_NR = "5560654321" DOWNLOAD_PATH = f"/tmp/bokf-golden-dl-{os.getpid()}.txt" KEYS = { @@ -618,6 +620,32 @@ SCENARIOS = [ ], }, { + # "Byt bolag" in the main menu switches org and its context (name, + # year); Esc in the picker keeps the current org. + "name": "switch-org", + "screen": "dashboard", + "expect": ["{org_name}", "Byt bolag", "Logga ut / avsluta"], + "steps": [ + { + "keys": ["g", "byt", "enter", "enter"], + "expect": ["Välj organisation att representera", + "Andra AB"], + }, + { + "keys": ["esc"], + "expect": ["{org_name} |", "Byt bolag"], + }, + { + "keys": ["enter", "down", "enter"], + "expect": ["Andra AB |", "Byt bolag"], + }, + { + "keys": ["1"], + "expect": ["sorterade på nummer", "Nytt verifikat"], + }, + ], + }, + { # Backspace in a freshly opened field edits the value; the next # key must not replace everything. "name": "form-edit-backspace", @@ -1207,6 +1235,11 @@ def setup_rig(repo, tmp, env): "tax_table": 30, "tax_column": 1, "email": "test@example.com"})], env) + # a second org for "Byt bolag"; the TUI always starts in the first + run_checked([str(bind / "bokfctl"), "--socket", str(sock), + "--user", "admin", "--password", env["BOKFD_PASSWORD"], + "org.create", + json.dumps({"name": ORG2_NAME, "org_nr": ORG2_NR})], env) return daemon, sock, org_id, fy |
