#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "client.h" #include "tui.h" #include "formula.h" #include "util.h" #include "version.h" #include "yyjson.h" #include "ui.h" static const char *type_sv(const char *t) { if (!t) return ""; if (strcmp(t, "asset") == 0) return "Tillgång"; if (strcmp(t, "liability") == 0) return "Skuld"; if (strcmp(t, "equity") == 0) return "Eget kapital"; if (strcmp(t, "revenue") == 0) return "Intäkt"; if (strcmp(t, "expense") == 0) return "Kostnad"; return t; } /* Moms treatment for an account: the stored vat_code when set, otherwise derived from the BAS account name (which carries the rate). Accounts whose treatment depends on the transaction stay blank. */ static const char *vat_display(const char *name, const char *vat_code, char *buf, size_t cap) { if (vat_code && *vat_code) { snprintf(buf, cap, "%s", vat_code); return buf; } if (!name || !*name) return ""; int pct = 0; for (const char *p = name; *p;) { if (*p >= '0' && *p <= '9') { const char *q = p; int v = 0; while (*q >= '0' && *q <= '9') { v = v * 10 + (*q - '0'); q++; } while (*q == ' ') q++; if (*q == '%') { pct = v; break; } p = q; continue; } p++; } int in = strstr(name, "Ingående moms") != NULL; int out = strstr(name, "Utgående moms") != NULL; int reverse = strstr(name, "omvänd") != NULL; if (in || out) { if (pct) snprintf(buf, cap, "%s %d%%", in ? "Ing" : "Utg", pct); else snprintf(buf, cap, "%s", in ? "Ing" : "Utg"); return buf; } if (pct) { snprintf(buf, cap, "%d%%%s", pct, reverse ? " omv" : ""); return buf; } if (strstr(name, "momsfri") || strstr(name, "momsfritt") || strstr(name, "momsefri")) return "Momsfri"; if (strstr(name, "Redovisningskonto för moms")) return "Avräkning"; if (reverse) return "Omvänd"; if (strstr(name, "moms")) return "Moms"; return ""; } /* Kontolista: every account with the details that apply to it. */ void accounts_report(struct app *a) { for (;;) { char *resp = client_rpc(&a->conn, "account.list", a->session, a->org, "{\"active_only\":false}"); if (!resp || !client_ok(resp)) { show_error("Kontolista", resp); free(resp); return; } size_t n = jarr_size(resp, "result.items"); int name_w = COLS - 45; if (name_w < 12) name_w = 12; struct buf text; buf_init(&text); char line[2048]; int hdr = snprintf(line, sizeof line, MK_STICKY "%-6s %-*s %-12s %-5s %-6s %-8s\n", "Konto", name_w, "Namn", "Typ", "Aktiv", "SRU", "Moms"); buf_append(&text, line, (size_t)hdr); int sep_w = 6 + 1 + name_w + 1 + 12 + 1 + 5 + 1 + 6 + 1 + 8; for (int i = 0; i < sep_w && i < (int)sizeof line - 1; i++) line[i] = '-'; line[sep_w < (int)sizeof line ? sep_w : (int)sizeof line - 1] = '\n'; buf_append(&text, line, (size_t)(sep_w < (int)sizeof line ? sep_w + 1 : (int)sizeof line)); int64_t active_count = 0; for (size_t i = 0; i < n; i++) { char path[64]; snprintf(path, sizeof path, "result.items.%zu.number", i); char *number = jstr_dup(resp, path); snprintf(path, sizeof path, "result.items.%zu.name", i); char *name = jstr_dup(resp, path); snprintf(path, sizeof path, "result.items.%zu.type", i); char *type = jstr_dup(resp, path); snprintf(path, sizeof path, "result.items.%zu.active", i); int active = jbool_val(resp, path, 0); snprintf(path, sizeof path, "result.items.%zu.sru_code", i); char *sru = jstr_dup(resp, path); snprintf(path, sizeof path, "result.items.%zu.vat_code", i); char *vat = jstr_dup(resp, path); char ncol[512]; char vatbuf[32]; char tibuf[32]; snprintf(ncol, sizeof ncol, "%s", name ? name : ""); tui_pad_field(ncol, sizeof ncol, name_w); snprintf(tibuf, sizeof tibuf, "%s", type_sv(type)); tui_pad_field(tibuf, sizeof tibuf, 12); snprintf(line, sizeof line, "%-6s %s %s %-5s %-6s %-8s\n", number ? number : "", ncol, tibuf, active ? "ja" : "nej", sru ? sru : "", vat_display(name, vat, vatbuf, sizeof vatbuf)); buf_append(&text, line, strlen(line)); if (active) active_count++; free(number); free(name); free(type); free(sru); free(vat); } snprintf(line, sizeof line, "\n%lld konton, varav %lld aktiva.\n", (long long)n, (long long)active_count); buf_append(&text, line, strlen(line)); buf_append(&text, "\0", 1); int again = tui_pager("Kontolista", (char *)text.p, NULL); buf_free(&text); free(resp); if (!again) return; } }