diff options
| author | Anders Betts <anders.betts@gmail.com> | 2026-09-21 11:45:54 +0200 |
|---|---|---|
| committer | Anders Betts <anders.betts@gmail.com> | 2026-09-21 11:45:54 +0200 |
| commit | e1dd7112e0346914710566660625da0f6b866e8a (patch) | |
| tree | c4b0d5c7f6f62c1c4c38245e7c001b3fd4b03e74 /clients/screens_settings.c | |
| parent | 182f0a592b6fe97fc1ff87add227f9d52a4ef902 (diff) | |
| download | bokf-0.1.55.tar.gz bokf-0.1.55.zip | |
tui: payroll screens, Företag/System menu and settings splitv0.1.55
Diffstat (limited to 'clients/screens_settings.c')
| -rw-r--r-- | clients/screens_settings.c | 348 |
1 files changed, 182 insertions, 166 deletions
diff --git a/clients/screens_settings.c b/clients/screens_settings.c index 6440150..c6a46c5 100644 --- a/clients/screens_settings.c +++ b/clients/screens_settings.c @@ -193,22 +193,181 @@ static void board_screen(struct app *a) } } +struct setting_field { + const char *key; + const char *label; + const char *const *choices; + int nchoices; + int mask; +}; + +static void setting_save(struct app *a, const struct setting_field *f, + const char *value, const char *title) +{ + if (f->mask && !*value) + return; /* empty secret means keep the stored one */ + yyjson_mut_doc *d = yyjson_mut_doc_new(NULL); + yyjson_mut_val *o = yyjson_mut_obj(d); + yyjson_mut_doc_set_root(d, o); + yyjson_mut_obj_add_strcpy(d, o, "key", f->key); + yyjson_mut_obj_add_strcpy(d, o, "value", value); + char *args = yyjson_mut_write(d, 0, NULL); + yyjson_mut_doc_free(d); + if (!args) + return; + char *rr = client_rpc(&a->conn, "settings.set", a->session, a->org, args); + free(args); + if (rr && client_ok(rr)) { + if (strcmp(f->key, "default_series") == 0) + snprintf(a->default_series, sizeof a->default_series, "%s", + value); + else if (strcmp(f->key, "attachment_dir") == 0) + snprintf(a->attachment_dir, sizeof a->attachment_dir, "%s", + value); + } else { + show_error(title, rr); + } + free(rr); +} + +static void settings_form(struct app *a, const char *title, + const struct setting_field *fields, int n, + int can_edit, int show_password_status, int *focus) +{ + for (;;) { + if (g_quit) + return; + char *resp = client_rpc(&a->conn, "settings.get", a->session, a->org, + "{}"); + if (!resp || !client_ok(resp)) { + show_error(title, resp); + free(resp); + return; + } + char *vals[8]; + int choice[8]; + struct tui_form_field ff[8]; + memset(ff, 0, sizeof ff); + for (int i = 0; i < n; i++) { + char path[64]; + vals[i] = xcalloc(512, 1); + snprintf(path, sizeof path, "result.%s", fields[i].key); + char *v = jstr_dup(resp, path); + snprintf(vals[i], 512, "%s", v ? v : ""); + free(v); + ff[i].label = fields[i].label; + ff[i].value = vals[i]; + ff[i].cap = 512; + ff[i].kind = TUI_F_TEXT; + ff[i].mask = fields[i].mask; + choice[i] = 0; + if (fields[i].choices) { + ff[i].kind = TUI_F_CHOICE; + ff[i].choices = fields[i].choices; + ff[i].nchoices = fields[i].nchoices; + ff[i].choice = &choice[i]; + for (int k = 0; k < fields[i].nchoices; k++) + if (strcmp(vals[i], fields[i].choices[k]) == 0) + choice[i] = k; + } + } + char pwstatus[192]; + struct tui_form_action acts[1]; + memset(acts, 0, sizeof acts); + if (show_password_status) { + int pw_set = jbool_val(resp, "result.smtp_password_set", 0); + snprintf(pwstatus, sizeof pwstatus, + "SMTP-lösenord (lämna tomt för oförändrat): %s", + pw_set ? "satt" : "inte satt"); + acts[0].label = pwstatus; + acts[0].enabled = -1; + } + free(resp); + tui_form_hint("upp/ned/Home/End Enter = ändra F5 = uppdatera" + " Esc/q = tillbaka ^C = avsluta"); + int r = tui_form_run_actions(title, ff, n, can_edit, acts, + show_password_status ? 1 : 0, NULL, + focus); + if (r >= 0 && r < n) { + const char *val = vals[r]; + if (fields[r].choices) + val = fields[r].choices[choice[r]]; + setting_save(a, &fields[r], val, title); + } + for (int i = 0; i < n; i++) + free(vals[i]); + if (r == TUI_FORM_BACK) + return; + } +} + +static const char *const SECURITY_CHOICES[] = { "starttls", "tls", "plain" }; + +static const struct setting_field INVOICE_SETTINGS[] = { + { "default_series", "Standardserie", NULL, 0, 0 }, + { "invoice_receivable_account", "Fordringskonto", NULL, 0, 0 }, + { "invoice_revenue_account", "Intäktskonto", NULL, 0, 0 }, + { "invoice_bankgiro", "Bankgiro", NULL, 0, 0 }, + { "invoice_our_ref", "Vår referens (faktura)", NULL, 0, 0 }, +}; + +static const struct setting_field SMTP_SETTINGS[] = { + { "smtp_host", "SMTP-server", NULL, 0, 0 }, + { "smtp_port", "SMTP-port", NULL, 0, 0 }, + { "smtp_user", "SMTP-användare", NULL, 0, 0 }, + { "smtp_from", "SMTP-avsändare", NULL, 0, 0 }, + { "smtp_reply_to", "SMTP-svarsadress", NULL, 0, 0 }, + { "smtp_security", "SMTP-säkerhet", SECURITY_CHOICES, 3, 0 }, + { "smtp_password", "SMTP-lösenord", NULL, 0, 1 }, +}; + +static const struct setting_field SYSTEM_SETTINGS[] = { + { "attachment_dir", "Bilagornas mapp", NULL, 0, 0 }, +}; + +static int settings_can_write(struct app *a) +{ + return a->role[0] && (strcmp(a->role, "owner") == 0 || + strcmp(a->role, "bookkeeper") == 0); +} + +static void invoice_settings_screen(struct app *a) +{ + static int sel = 0; + settings_form(a, "Fakturauppgifter", INVOICE_SETTINGS, + (int)(sizeof INVOICE_SETTINGS / sizeof INVOICE_SETTINGS[0]), + settings_can_write(a), 0, &sel); +} + +static void smtp_settings_screen(struct app *a) +{ + static int sel = 0; + settings_form(a, "E-post (SMTP)", SMTP_SETTINGS, + (int)(sizeof SMTP_SETTINGS / sizeof SMTP_SETTINGS[0]), + settings_can_write(a), 1, &sel); +} + +void system_settings_screen(struct app *a) +{ + static int sel = 0; + settings_form(a, "Systeminställningar", SYSTEM_SETTINGS, + (int)(sizeof SYSTEM_SETTINGS / sizeof SYSTEM_SETTINGS[0]), + settings_can_write(a), 0, &sel); +} + void company_screen(struct app *a) { static int sel = 0; const int nf = (int)(sizeof COMPANY_FIELDS / sizeof COMPANY_FIELDS[0]); - const int ninv = 2; - static const char *const invkeys[2] = { "invoice_bankgiro", - "invoice_our_ref" }; - static const char *const invlabels[2] = { "Bankgiro", - "Vår referens (faktura)" }; int owner = a->role[0] && strcmp(a->role, "owner") == 0; + int writer = settings_can_write(a); + const char *settings_reason = writer ? NULL : "du har inte behörighet"; for (;;) { if (g_quit) return; char *resp = client_rpc(&a->conn, "org.get", a->session, a->org, "{}"); if (!resp || !client_ok(resp)) { - show_error("Företagsuppgifter", resp); + show_error("Bolaget", resp); free(resp); return; } @@ -233,26 +392,15 @@ void company_screen(struct app *a) ff[i].kind = TUI_F_TEXT; } free(resp); - char *sresp = - client_rpc(&a->conn, "settings.get", a->session, a->org, "{}"); - for (int i = 0; i < ninv; i++) { - char path[64]; - int idx = nf + i; - vals[idx] = xcalloc(512, 1); - snprintf(path, sizeof path, "result.%s", invkeys[i]); - char *v = sresp ? jstr_dup(sresp, path) : NULL; - snprintf(vals[idx], 512, "%s", v ? v : ""); - free(v); - ff[idx].label = invlabels[i]; - ff[idx].value = vals[idx]; - ff[idx].cap = 512; - ff[idx].kind = TUI_F_TEXT; - } - free(sresp); - ff[nf + ninv].label = "Styrelseledamöter"; - ff[nf + ninv].kind = TUI_F_ACTION; - int r = tui_form_run("Företagsuppgifter", ff, nf + ninv + 1, owner, - &sel); + struct tui_form_action acts[3] = { + { "Fakturauppgifter…", writer ? 1 : 0, settings_reason }, + { "E-post (SMTP)…", writer ? 1 : 0, settings_reason }, + { "Styrelseledamöter", 1, NULL }, + }; + tui_form_hint("upp/ned/Tab = flytta Enter = ändra/utför" + " F5 = uppdatera Esc/q = tillbaka ^C = avsluta"); + int r = tui_form_run_actions("Bolaget", ff, nf, owner, acts, 3, NULL, + &sel); if (r >= 0 && r < nf) { if (!company_field_valid(&COMPANY_FIELDS[r], vals[r])) { tui_message("Ogiltigt värde", "%s", COMPANY_FIELDS[r].label); @@ -275,150 +423,18 @@ void company_screen(struct app *a) show_error("Kunde inte spara", rr); free(rr); } - } else if (r >= nf && r < nf + ninv) { - yyjson_mut_doc *d = yyjson_mut_doc_new(NULL); - yyjson_mut_val *o = yyjson_mut_obj(d); - yyjson_mut_doc_set_root(d, o); - yyjson_mut_obj_add_strcpy(d, o, "key", invkeys[r - nf]); - yyjson_mut_obj_add_strcpy(d, o, "value", vals[r]); - char *args = yyjson_mut_write(d, 0, NULL); - yyjson_mut_doc_free(d); - char *rr = client_rpc(&a->conn, "settings.set", a->session, - a->org, args); - free(args); - if (!rr || !client_ok(rr)) - show_error("Kunde inte spara", rr); - free(rr); } - if (r == nf + ninv) - board_screen(a); - for (int i = 0; i < nf + ninv; i++) + for (int i = 0; i < nf; i++) free(vals[i]); - if (r == TUI_FORM_BACK) + if (r == TUI_FORM_ACTION + 0) + invoice_settings_screen(a); + else if (r == TUI_FORM_ACTION + 1) + smtp_settings_screen(a); + else if (r == TUI_FORM_ACTION + 2) + board_screen(a); + else if (r == TUI_FORM_BACK) return; } } -static const char *const SETTING_KEYS[] = { - "default_series", - "attachment_dir", - "invoice_receivable_account", - "invoice_revenue_account", - "smtp_host", - "smtp_port", - "smtp_user", - "smtp_from", - "smtp_reply_to", - "smtp_security", - "smtp_password", -}; -static const char *const SETTING_LABELS[] = { - "Standardserie", - "Bilagornas mapp", - "Fordringskonto", - "Intäktskonto", - "SMTP-server", - "SMTP-port", - "SMTP-användare", - "SMTP-avsändare", - "SMTP-svarsadress", - "SMTP-säkerhet", - "SMTP-lösenord", -}; -static const char *const SECURITY_CHOICES[] = { "starttls", "tls", "plain" }; -void settings_screen(struct app *a) -{ - static int sel = 0; - const int nset = (int)(sizeof SETTING_KEYS / sizeof SETTING_KEYS[0]); - for (;;) { - if (g_quit) - return; - char *resp = - client_rpc(&a->conn, "settings.get", a->session, a->org, "{}"); - if (!resp || !client_ok(resp)) { - show_error("Inställningar", resp); - free(resp); - return; - } - int pw_set = jbool_val(resp, "result.smtp_password_set", 0); - char pwstatus[192]; - snprintf(pwstatus, sizeof pwstatus, - "SMTP-lösenord (lämna tomt för oförändrat): %s", - pw_set ? "satt" : "inte satt"); - char *vals[16]; - struct tui_form_field ff[16]; - memset(ff, 0, sizeof ff); - int sec_choice = 0; - for (int i = 0; i < nset; i++) { - char path[64], *v; - vals[i] = xcalloc(512, 1); - snprintf(path, sizeof path, "result.%s", SETTING_KEYS[i]); - v = jstr_dup(resp, path); - snprintf(vals[i], 512, "%s", v ? v : ""); - free(v); - const char *key = SETTING_KEYS[i]; - ff[i].label = SETTING_LABELS[i]; - ff[i].value = vals[i]; - ff[i].cap = 512; - ff[i].kind = TUI_F_TEXT; - if (strcmp(key, "smtp_security") == 0) { - ff[i].kind = TUI_F_CHOICE; - ff[i].choices = SECURITY_CHOICES; - ff[i].nchoices = 3; - ff[i].choice = &sec_choice; - for (int k = 0; k < 3; k++) - if (strcmp(vals[i], SECURITY_CHOICES[k]) == 0) - sec_choice = k; - } else if (strcmp(key, "smtp_password") == 0) { - ff[i].mask = 1; - } - } - free(resp); - struct tui_form_action acts[1]; - memset(acts, 0, sizeof acts); - acts[0].label = pwstatus; - acts[0].enabled = -1; /* dim status row, not selectable */ - int r = tui_form_run_actions( - "Inställningar", ff, nset, 1, acts, 1, - "upp/ned/Home/End Enter = ändra F5 = uppdatera" - " Esc/q = tillbaka ^C = avsluta", - &sel); - if (r >= 0 && r < nset) { - const char *key = SETTING_KEYS[r]; - const char *val = vals[r]; - if (strcmp(key, "smtp_security") == 0) - val = SECURITY_CHOICES[sec_choice]; - if (strcmp(key, "smtp_password") == 0 && !*vals[r]) { - /* empty means "keep the stored secret" */ - } else { - yyjson_mut_doc *d = yyjson_mut_doc_new(NULL); - yyjson_mut_val *o = yyjson_mut_obj(d); - yyjson_mut_doc_set_root(d, o); - yyjson_mut_obj_add_strcpy(d, o, "key", key); - yyjson_mut_obj_add_strcpy(d, o, "value", val); - char *args = yyjson_mut_write(d, 0, NULL); - yyjson_mut_doc_free(d); - char *rr = client_rpc(&a->conn, "settings.set", a->session, - a->org, args); - free(args); - if (rr && client_ok(rr)) { - snprintf(vals[r], 512, "%s", val); - if (strcmp(key, "default_series") == 0) - snprintf(a->default_series, - sizeof a->default_series, "%s", val); - else if (strcmp(key, "attachment_dir") == 0) - snprintf(a->attachment_dir, - sizeof a->attachment_dir, "%s", val); - } else { - show_error("Kunde inte spara inställningen", rr); - } - free(rr); - } - } - for (int i = 0; i < nset; i++) - free(vals[i]); - if (r == TUI_FORM_BACK) - return; - } -} |
