From a5d3ddf6d512bc459cfa450c6b449c2e7a245373 Mon Sep 17 00:00:00 2001 From: Anders Betts Date: Fri, 18 Sep 2026 14:32:23 +0200 Subject: reports: Kapitas-style TUI tables, corrected moms rules (schema v3) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The report views dumped JSON; they now render Saldobalans, Resultatrapport (previous-year column, 89xx bokfört/ej bokfört), Balansrapport (Ing balans/Ing saldo/Period/Utg balans, Beräknat resultat) and Momsrapport ruta för ruta, with Swedish amount formatting (1 234,56). The moms starter rules missed 33xx sales, sent reverse-charge VAT 2614 to box 10 instead of 30 and had box 48 positive. Rules may now share a box and report.vat sums them; box 49 is the sum of the moms boxes only. Schema v3 replaces the rules for existing orgs. Verified on a copy of the live DB: 05=703 200, 10=175 800, 20=1 453, 30=851, 48=-1 030, 49=175 621, matching the Kapitas 2027 export. Ctrl+R reload passes --socket and auto-login no longer rewrites tui.conf; pty tests now run through scripts/tui-sandbox.sh so they cannot touch the real config, cache or bw session. --- tests/test_core.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) (limited to 'tests/test_core.c') diff --git a/tests/test_core.c b/tests/test_core.c index fa808ac..27948d6 100644 --- a/tests/test_core.c +++ b/tests/test_core.c @@ -1301,6 +1301,77 @@ int main(void) CHECK_STR(d, "result.attachment_dir", "/tmp/bilagor"); yyjson_doc_free(d); + /* ---------------- moms rules: ranges merge per box ------------- */ + d = call(reqf("{\"v\":1,\"id\":\"110\",\"cmd\":\"org.create\"," + "\"session\":\"%s\",\"args\":{\"name\":\"Moms AB\"}}", + g_session)); + CHECK_OK(d); + int64_t vat_org = jint(d, "result.id"); + CHECK(vat_org > 0); + yyjson_doc_free(d); + + d = call(reqf("{\"v\":1,\"id\":\"111\",\"cmd\":\"voucher.post\"," + "\"session\":\"%s\",\"org\":%d,\"args\":{\"date\":" + "\"2026-02-01\",\"description\":\"Försäljning A\",\"rows\":[" + "{\"account\":\"1930\",\"debit_ore\":125000}," + "{\"account\":\"3001\",\"credit_ore\":100000}," + "{\"account\":\"2611\",\"credit_ore\":25000}]}}", + g_session, (int)vat_org)); + CHECK_OK(d); + yyjson_doc_free(d); + + d = call(reqf("{\"v\":1,\"id\":\"112\",\"cmd\":\"voucher.post\"," + "\"session\":\"%s\",\"org\":%d,\"args\":{\"date\":" + "\"2026-02-02\",\"description\":\"Försäljning B\",\"rows\":[" + "{\"account\":\"1930\",\"debit_ore\":62500}," + "{\"account\":\"3105\",\"credit_ore\":50000}," + "{\"account\":\"2611\",\"credit_ore\":12500}]}}", + g_session, (int)vat_org)); + CHECK_OK(d); + yyjson_doc_free(d); + + d = call(reqf("{\"v\":1,\"id\":\"113\",\"cmd\":\"voucher.post\"," + "\"session\":\"%s\",\"org\":%d,\"args\":{\"date\":" + "\"2026-02-03\",\"description\":\"EU-inköp\",\"rows\":[" + "{\"account\":\"4515\",\"debit_ore\":10000}," + "{\"account\":\"2645\",\"debit_ore\":2500}," + "{\"account\":\"2614\",\"credit_ore\":2500}," + "{\"account\":\"2410\",\"credit_ore\":10000}]}}", + g_session, (int)vat_org)); + CHECK_OK(d); + yyjson_doc_free(d); + + d = call(reqf("{\"v\":1,\"id\":\"114\",\"cmd\":\"voucher.post\"," + "\"session\":\"%s\",\"org\":%d,\"args\":{\"date\":" + "\"2026-02-04\",\"description\":\"IT-tjänst\",\"rows\":[" + "{\"account\":\"6540\",\"debit_ore\":8000}," + "{\"account\":\"2641\",\"debit_ore\":2000}," + "{\"account\":\"2410\",\"credit_ore\":10000}]}}", + g_session, (int)vat_org)); + CHECK_OK(d); + yyjson_doc_free(d); + + d = call(reqf("{\"v\":1,\"id\":\"115\",\"cmd\":\"report.vat\"," + "\"session\":\"%s\",\"org\":%d,\"args\":" + "{\"from\":\"2026-02-01\",\"to\":\"2026-02-28\"}}", + g_session, (int)vat_org)); + CHECK_OK(d); + CHECK(vat_box(d, "05") == 150000); + CHECK(vat_box(d, "10") == 37500); + CHECK(vat_box(d, "20") == 10000); + CHECK(vat_box(d, "30") == 2500); + CHECK(vat_box(d, "48") == -4500); + CHECK(vat_box(d, "49") == 35500); + int n05 = 0; + yyjson_val *boxes = jget(d, "result.boxes"); + for (size_t i = 0; i < yyjson_arr_size(boxes); i++) { + yyjson_val *box = yyjson_obj_get(yyjson_arr_get(boxes, i), "box"); + if (box && yyjson_is_str(box) && strcmp(yyjson_get_str(box), "05") == 0) + n05++; + } + CHECK(n05 == 1); + yyjson_doc_free(d); + /* close fiscal year and verify hard stop */ d = call(reqf("{\"v\":1,\"id\":\"73\",\"cmd\":\"fiscal_year.close\"," "\"session\":\"%s\",\"org\":%d,\"args\":{\"id\":%lld," -- cgit v1.3