From 2a69643bf580514712276324fb8c4ea9a512494c Mon Sep 17 00:00:00 2001 From: Anders Betts Date: Sun, 20 Sep 2026 15:23:20 +0200 Subject: invoice: customer, sequence, preview and issue commands --- tests/test_core.c | 518 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 518 insertions(+) (limited to 'tests') diff --git a/tests/test_core.c b/tests/test_core.c index a78a940..fa7b5e4 100644 --- a/tests/test_core.c +++ b/tests/test_core.c @@ -16,6 +16,7 @@ #include "client.h" #include "config.h" #include "db.h" +#include "invoice.h" #include "protocol.h" #include "sessions.h" #include "util.h" @@ -2199,6 +2200,523 @@ int main(void) CHECK_STR(d, "result.items.0.account", "1940"); yyjson_doc_free(d); + /* ---------------- invoicing: customers, sequence, issue ---------- */ + + d = call(reqf("{\"v\":1,\"id\":\"300\",\"cmd\":\"settings.get\"," + "\"session\":\"%s\",\"org\":%d}", + g_session, (int)org_id)); + CHECK_OK(d); + CHECK_STR(d, "result.invoice_receivable_account", "1510"); + CHECK_STR(d, "result.invoice_revenue_account", "3001"); + yyjson_doc_free(d); + + d = call(reqf("{\"v\":1,\"id\":\"301\",\"cmd\":\"customer.create\"," + "\"session\":\"%s\",\"org\":%d,\"args\":{\"name\":" + "\"Andra bygg AB\",\"address\":\"Storgatan 1\"," + "\"postal_code\":\"171 63\",\"city\":\"Solna\"," + "\"vat_nr\":\"SE559232855201\"," + "\"email\":\"faktura@andra.se\",\"your_ref\":\"Eric\"," + "\"payment_days\":30}}", + g_session, (int)org_id)); + CHECK_OK(d); + int64_t cust1 = jint(d, "result.id"); + CHECK(cust1 > 0); + CHECK_STR(d, "result.name", "Andra bygg AB"); + CHECK_STR(d, "result.city", "Solna"); + CHECK_STR(d, "result.email", "faktura@andra.se"); + CHECK(jint(d, "result.payment_days") == 30); + CHECK(jbool(d, "result.active")); + yyjson_doc_free(d); + + d = call(reqf("{\"v\":1,\"id\":\"302\",\"cmd\":\"customer.create\"," + "\"session\":\"%s\",\"org\":%d,\"args\":{\"name\":" + "\"Andra bygg AB\"}}", + g_session, (int)org_id)); + CHECK_STR(d, "error.code", "CONFLICT"); + yyjson_doc_free(d); + + d = call(reqf("{\"v\":1,\"id\":\"303\",\"cmd\":\"customer.create\"," + "\"session\":\"%s\",\"org\":%d,\"dry_run\":true,\"args\":" + "{\"name\":\"Tillfällig AB\"}}", + g_session, (int)org_id)); + CHECK_OK(d); + CHECK(jbool(d, "result.dry_run")); + CHECK_STR(d, "result.name", "Tillfällig AB"); + CHECK(jint(d, "result.payment_days") == 30); + yyjson_doc_free(d); + + d = call(reqf("{\"v\":1,\"id\":\"304\",\"cmd\":\"customer.create\"," + "\"session\":\"%s\",\"org\":%d,\"args\":{\"name\":" + "\"NZ Bygg AB\",\"city\":\"Bromma\"}}", + g_session, (int)org_id)); + CHECK_OK(d); + int64_t cust2 = jint(d, "result.id"); + CHECK(cust2 > 0); + CHECK(jint(d, "result.payment_days") == 30); + yyjson_doc_free(d); + + d = call(reqf("{\"v\":1,\"id\":\"305\",\"cmd\":\"customer.get\"," + "\"session\":\"%s\",\"org\":%d,\"args\":{\"id\":%lld}}", + g_session, (int)org_id, (long long)cust1)); + CHECK_OK(d); + CHECK_STR(d, "result.name", "Andra bygg AB"); + CHECK_STR(d, "result.address", "Storgatan 1"); + yyjson_doc_free(d); + + d = call(reqf("{\"v\":1,\"id\":\"306\",\"cmd\":\"customer.get\"," + "\"session\":\"%s\",\"org\":%d,\"args\":{\"id\":999999}}", + g_session, (int)org_id)); + CHECK_STR(d, "error.code", "NOT_FOUND"); + yyjson_doc_free(d); + + d = call(reqf("{\"v\":1,\"id\":\"307\",\"cmd\":\"customer.list\"," + "\"session\":\"%s\",\"org\":%d}", + g_session, (int)org_id)); + CHECK_OK(d); + CHECK(yyjson_arr_size(jget(d, "result.items")) == 2); + CHECK_STR(d, "result.items.0.name", "Andra bygg AB"); + CHECK_STR(d, "result.items.1.name", "NZ Bygg AB"); + yyjson_doc_free(d); + + d = call(reqf("{\"v\":1,\"id\":\"308\",\"cmd\":\"customer.update\"," + "\"session\":\"%s\",\"org\":%d,\"args\":{\"id\":%lld," + "\"city\":\"Sundbyberg\",\"your_ref\":\"Lars\"}}", + g_session, (int)org_id, (long long)cust1)); + CHECK_OK(d); + CHECK_STR(d, "result.city", "Sundbyberg"); + CHECK_STR(d, "result.your_ref", "Lars"); + CHECK_STR(d, "result.address", "Storgatan 1"); + CHECK_STR(d, "result.name", "Andra bygg AB"); + yyjson_doc_free(d); + + d = call(reqf("{\"v\":1,\"id\":\"309\",\"cmd\":\"customer.update\"," + "\"session\":\"%s\",\"org\":%d,\"args\":{\"id\":%lld," + "\"name\":\"Andra bygg AB\"}}", + g_session, (int)org_id, (long long)cust2)); + CHECK_STR(d, "error.code", "CONFLICT"); + yyjson_doc_free(d); + + d = call(reqf("{\"v\":1,\"id\":\"310\",\"cmd\":\"customer.update\"," + "\"session\":\"%s\",\"org\":%d,\"args\":{\"id\":999999," + "\"city\":\"X\"}}", + g_session, (int)org_id)); + CHECK_STR(d, "error.code", "NOT_FOUND"); + yyjson_doc_free(d); + + d = call(reqf("{\"v\":1,\"id\":\"311\",\"cmd\":\"customer.update\"," + "\"session\":\"%s\",\"org\":%d,\"dry_run\":true,\"args\":" + "{\"id\":%lld,\"city\":\"Nacka\"}}", + g_session, (int)org_id, (long long)cust1)); + CHECK_OK(d); + CHECK(jbool(d, "result.dry_run")); + CHECK_STR(d, "result.city", "Nacka"); + yyjson_doc_free(d); + + d = call(reqf("{\"v\":1,\"id\":\"312\",\"cmd\":\"customer.get\"," + "\"session\":\"%s\",\"org\":%d,\"args\":{\"id\":%lld}}", + g_session, (int)org_id, (long long)cust1)); + CHECK_OK(d); + CHECK_STR(d, "result.city", "Sundbyberg"); + yyjson_doc_free(d); + + d = call(reqf("{\"v\":1,\"id\":\"313\",\"cmd\":\"customer.archive\"," + "\"session\":\"%s\",\"org\":%d,\"args\":{\"id\":%lld," + "\"active\":false}}", + g_session, (int)org_id, (long long)cust2)); + CHECK_OK(d); + CHECK(jint(d, "result.id") == cust2); + CHECK(!jbool(d, "result.active")); + yyjson_doc_free(d); + + d = call(reqf("{\"v\":1,\"id\":\"314\",\"cmd\":\"customer.list\"," + "\"session\":\"%s\",\"org\":%d,\"args\":" + "{\"active_only\":true}}", + g_session, (int)org_id)); + CHECK_OK(d); + CHECK(yyjson_arr_size(jget(d, "result.items")) == 1); + CHECK_STR(d, "result.items.0.name", "Andra bygg AB"); + yyjson_doc_free(d); + + d = call(reqf("{\"v\":1,\"id\":\"315\",\"cmd\":\"customer.archive\"," + "\"session\":\"%s\",\"org\":%d,\"args\":{\"id\":999999," + "\"active\":false}}", + g_session, (int)org_id)); + CHECK_STR(d, "error.code", "NOT_FOUND"); + yyjson_doc_free(d); + + d = call(reqf("{\"v\":1,\"id\":\"320\",\"cmd\":\"invoice.sequence_get\"," + "\"session\":\"%s\",\"org\":%d}", + g_session, (int)org_id)); + CHECK_OK(d); + CHECK(jint(d, "result.next_number") == 1); + yyjson_doc_free(d); + + d = call(reqf("{\"v\":1,\"id\":\"321\",\"cmd\":\"invoice.sequence_set\"," + "\"session\":\"%s\",\"org\":%d,\"args\":{\"next_number\":" + "0}}", + g_session, (int)org_id)); + CHECK_STR(d, "error.code", "INVALID_ARGS"); + yyjson_doc_free(d); + + d = call(reqf("{\"v\":1,\"id\":\"322\",\"cmd\":\"invoice.sequence_set\"," + "\"session\":\"%s\",\"org\":%d,\"args\":{\"next_number\":" + "17761}}", + g_session, (int)org_id)); + CHECK_OK(d); + CHECK(jint(d, "result.next_number") == 17761); + yyjson_doc_free(d); + + d = call(reqf("{\"v\":1,\"id\":\"323\",\"cmd\":\"invoice.sequence_get\"," + "\"session\":\"%s\",\"org\":%d}", + g_session, (int)org_id)); + CHECK_OK(d); + CHECK(jint(d, "result.next_number") == 17761); + yyjson_doc_free(d); + + char draft_args[2048]; + snprintf(draft_args, sizeof draft_args, + "{\"customer_id\":%lld,\"invoice_date\":\"2026-09-20\"," + "\"due_date\":\"2026-10-20\",\"delivery_date\":\"2026-09-20\"," + "\"your_ref\":\"Lars\",\"our_ref\":\"Anders\",\"notes\":\"\"," + "\"rows\":[{\"article_no\":\"\",\"description\":" + "\"Utvecklingsarbete\",\"quantity\":\"61\",\"unit\":\"tim\"," + "\"unit_price_ore\":120000,\"note\":\"\",\"vat_code\":\"25\"," + "\"account\":\"\"}]}", + (long long)cust1); + + d = call(reqf("{\"v\":1,\"id\":\"330\",\"cmd\":\"invoice.preview\"," + "\"session\":\"%s\",\"org\":%d,\"args\":%s}", + g_session, (int)org_id, draft_args)); + CHECK_OK(d); + CHECK(jint(d, "result.number") == 17761); + char number_str[32]; + snprintf(number_str, sizeof number_str, "%lld", + (long long)jint(d, "result.number")); + char expect_ocr[40]; + snprintf(expect_ocr, sizeof expect_ocr, "%s%d", number_str, + invoice_ocr_check(number_str)); + CHECK_STR(d, "result.ocr", expect_ocr); + CHECK(jint(d, "result.net_ore") == 7320000); + CHECK(jint(d, "result.vat_ore") == 1830000); + CHECK(jint(d, "result.total_ore") == 9150000); + const char *pdf_b64 = jstr(d, "result.content_base64"); + char *preview_b64 = pdf_b64 ? xstrdup(pdf_b64) : NULL; + CHECK(preview_b64 && strncmp(preview_b64, "JVBERi0", 7) == 0); + yyjson_doc_free(d); + + d = call(reqf("{\"v\":1,\"id\":\"331\",\"cmd\":\"invoice.preview\"," + "\"session\":\"%s\",\"org\":%d,\"args\":%s}", + g_session, (int)org_id, draft_args)); + CHECK_OK(d); + CHECK(preview_b64 && jstr(d, "result.content_base64") && + strcmp(jstr(d, "result.content_base64"), preview_b64) == 0); + yyjson_doc_free(d); + + d = call(reqf("{\"v\":1,\"id\":\"332\",\"cmd\":\"invoice.sequence_get\"," + "\"session\":\"%s\",\"org\":%d}", + g_session, (int)org_id)); + CHECK_OK(d); + CHECK(jint(d, "result.next_number") == 17761); + yyjson_doc_free(d); + + d = call(reqf("{\"v\":1,\"id\":\"333\",\"cmd\":\"invoice.preview\"," + "\"session\":\"%s\",\"org\":%d,\"args\":{\"customer_id\":" + "%lld,\"invoice_date\":\"2026-09-20\",\"due_date\":" + "\"2026-10-20\",\"rows\":[{\"description\":\"X\"," + "\"quantity\":\"1\",\"unit_price_ore\":100," + "\"vat_code\":\"99\"}]}}", + g_session, (int)org_id, (long long)cust1)); + CHECK_STR(d, "error.code", "INVALID_ARGS"); + yyjson_doc_free(d); + + d = call(reqf("{\"v\":1,\"id\":\"334\",\"cmd\":\"invoice.preview\"," + "\"session\":\"%s\",\"org\":%d,\"args\":{\"customer_id\":" + "%lld,\"invoice_date\":\"2026-09-20\",\"due_date\":" + "\"2026-10-20\",\"rows\":[{\"description\":\"X\"," + "\"quantity\":\"1,2345\",\"unit_price_ore\":100," + "\"vat_code\":\"25\"}]}}", + g_session, (int)org_id, (long long)cust1)); + CHECK_STR(d, "error.code", "INVALID_ARGS"); + yyjson_doc_free(d); + + d = call(reqf("{\"v\":1,\"id\":\"335\",\"cmd\":\"invoice.preview\"," + "\"session\":\"%s\",\"org\":%d,\"args\":{\"customer_id\":" + "%lld,\"invoice_date\":\"2026-09-20\",\"due_date\":" + "\"2026-10-20\",\"rows\":[{\"description\":\"X\"," + "\"quantity\":\"0\",\"unit_price_ore\":100," + "\"vat_code\":\"25\"}]}}", + g_session, (int)org_id, (long long)cust1)); + CHECK_STR(d, "error.code", "INVALID_ARGS"); + yyjson_doc_free(d); + + d = call(reqf("{\"v\":1,\"id\":\"336\",\"cmd\":\"invoice.preview\"," + "\"session\":\"%s\",\"org\":%d,\"args\":{\"customer_id\":" + "999999,\"invoice_date\":\"2026-09-20\",\"due_date\":" + "\"2026-10-20\",\"rows\":[{\"description\":\"X\"," + "\"quantity\":\"1\",\"unit_price_ore\":100," + "\"vat_code\":\"25\"}]}}", + g_session, (int)org_id)); + CHECK_STR(d, "error.code", "NOT_FOUND"); + yyjson_doc_free(d); + + d = call(reqf("{\"v\":1,\"id\":\"337\",\"cmd\":\"invoice.preview\"," + "\"session\":\"%s\",\"org\":%d,\"args\":{\"customer_id\":" + "%lld,\"invoice_date\":\"2026-09-20\",\"due_date\":" + "\"2026-10-20\",\"rows\":[{\"description\":\"X\"," + "\"quantity\":\"1\",\"unit_price_ore\":100," + "\"vat_code\":\"25\"}]}}", + g_session, (int)org_id, (long long)cust2)); + CHECK_STR(d, "error.code", "NOT_FOUND"); + yyjson_doc_free(d); + + d = call(reqf("{\"v\":1,\"id\":\"337a\",\"cmd\":\"invoice.preview\"," + "\"session\":\"%s\",\"org\":%d,\"args\":{\"customer_id\":" + "%lld,\"invoice_date\":\"2026-09-20\",\"due_date\":" + "\"2026-10-20\",\"rows\":[{\"description\":\"X\"," + "\"quantity\":\"1000\",\"unit_price_ore\":" + "9223372036854775807,\"vat_code\":\"25\"}]}}", + g_session, (int)org_id, (long long)cust1)); + CHECK_STR(d, "error.code", "INVALID_ARGS"); + yyjson_doc_free(d); + + d = call(reqf("{\"v\":1,\"id\":\"337b\",\"cmd\":\"invoice.preview\"," + "\"session\":\"%s\",\"org\":%d,\"args\":{\"customer_id\":" + "%lld,\"invoice_date\":\"2026-09-20\",\"due_date\":" + "\"2026-10-20\",\"rows\":[{\"description\":\"X\"," + "\"quantity\":\"1\",\"unit_price_ore\":-1," + "\"vat_code\":\"25\"}]}}", + g_session, (int)org_id, (long long)cust1)); + CHECK_STR(d, "error.code", "INVALID_ARGS"); + yyjson_doc_free(d); + + { + char rows_json[8192]; + size_t off = 0; + off += (size_t)snprintf(rows_json + off, sizeof rows_json - off, "["); + for (int i = 0; i < 20 && off < sizeof rows_json - 256; i++) + off += (size_t)snprintf( + rows_json + off, sizeof rows_json - off, + "%s{\"description\":\"Rad %d\",\"quantity\":\"1\"," + "\"unit_price_ore\":100,\"vat_code\":\"25\"}", + i ? "," : "", i + 1); + snprintf(rows_json + off, sizeof rows_json - off, "]"); + d = call(reqf("{\"v\":1,\"id\":\"337c\",\"cmd\":\"invoice.preview\"," + "\"session\":\"%s\",\"org\":%d,\"args\":{\"customer_id\":" + "%lld,\"invoice_date\":\"2026-09-20\",\"due_date\":" + "\"2026-10-20\",\"rows\":%s}}", + g_session, (int)org_id, (long long)cust1, rows_json)); + CHECK_STR(d, "error.code", "TOO_LARGE"); + yyjson_doc_free(d); + } + + d = call(reqf("{\"v\":1,\"id\":\"338\",\"cmd\":\"invoice.issue\"," + "\"session\":\"%s\",\"org\":%d,\"dry_run\":true,\"args\":" + "{\"customer_id\":%lld,\"invoice_date\":\"2026-09-20\"," + "\"due_date\":\"2026-10-20\",\"rows\":[{\"description\":" + "\"X\",\"quantity\":\"1\",\"unit_price_ore\":100," + "\"vat_code\":\"25\",\"account\":\"9999\"}]}}", + g_session, (int)org_id, (long long)cust1)); + CHECK_STR(d, "error.code", "ACCOUNT_NOT_FOUND"); + yyjson_doc_free(d); + + int64_t vouchers_before = db_count(g_db, "SELECT count(*) FROM vouchers"); + int64_t attachments_before = + db_count(g_db, "SELECT count(*) FROM attachments"); + + d = call(reqf("{\"v\":1,\"id\":\"340\",\"cmd\":\"invoice.issue\"," + "\"session\":\"%s\",\"org\":%d,\"dry_run\":true,\"args\":%s}", + g_session, (int)org_id, draft_args)); + CHECK_OK(d); + CHECK(jbool(d, "result.dry_run")); + CHECK(jint(d, "result.number") == 17761); + CHECK_STR(d, "result.ocr", expect_ocr); + CHECK(jint(d, "result.net_ore") == 7320000); + CHECK(jint(d, "result.vat_ore") == 1830000); + CHECK(jint(d, "result.total_ore") == 9150000); + yyjson_val *dry_doc = jget(d, "result.document_id"); + CHECK(dry_doc && yyjson_is_null(dry_doc)); + yyjson_doc_free(d); + CHECK(db_count(g_db, "SELECT count(*) FROM vouchers") == vouchers_before); + CHECK(db_count(g_db, "SELECT count(*) FROM attachments") == + attachments_before); + + d = call(reqf("{\"v\":1,\"id\":\"341\",\"cmd\":\"invoice.sequence_get\"," + "\"session\":\"%s\",\"org\":%d}", + g_session, (int)org_id)); + CHECK_OK(d); + CHECK(jint(d, "result.next_number") == 17761); + yyjson_doc_free(d); + + d = call(reqf("{\"v\":1,\"id\":\"350\",\"cmd\":\"invoice.issue\"," + "\"session\":\"%s\",\"org\":%d,\"args\":%s}", + g_session, (int)org_id, draft_args)); + CHECK_OK(d); + int64_t inv1 = jint(d, "result.id"); + int64_t doc1 = jint(d, "result.document_id"); + int64_t vou1 = jint(d, "result.voucher_id"); + CHECK(inv1 > 0); + CHECK(doc1 > 0); + CHECK(vou1 > 0); + CHECK(jint(d, "result.number") == 17761); + CHECK_STR(d, "result.ocr", expect_ocr); + CHECK(jint(d, "result.net_ore") == 7320000); + CHECK(jint(d, "result.vat_ore") == 1830000); + CHECK(jint(d, "result.total_ore") == 9150000); + yyjson_doc_free(d); + CHECK(db_count(g_db, "SELECT count(*) FROM vouchers") == vouchers_before + 1); + CHECK(db_count(g_db, "SELECT count(*) FROM attachments") == + attachments_before + 1); + + d = call(reqf("{\"v\":1,\"id\":\"351\",\"cmd\":\"voucher.get\"," + "\"session\":\"%s\",\"org\":%d,\"args\":{\"id\":%lld}}", + g_session, (int)org_id, (long long)vou1)); + CHECK_OK(d); + CHECK_STR(d, "result.source", "invoice"); + CHECK_STR(d, "result.date", "2026-09-20"); + CHECK(find_amount(d, "result.rows", "account", "1510", "debit_ore") == + 9150000); + CHECK(find_amount(d, "result.rows", "account", "3001", "credit_ore") == + 7320000); + CHECK(find_amount(d, "result.rows", "account", "2610", "credit_ore") == + 1830000); + CHECK(find_amount(d, "result.rows", "account", "1510", "credit_ore") == 0); + yyjson_doc_free(d); + + d = call(reqf("{\"v\":1,\"id\":\"352\",\"cmd\":\"invoice.get\"," + "\"session\":\"%s\",\"org\":%d,\"args\":{\"id\":%lld}}", + g_session, (int)org_id, (long long)inv1)); + CHECK_OK(d); + CHECK_STR(d, "result.status", "issued"); + CHECK(jint(d, "result.customer_id") == cust1); + CHECK_STR(d, "result.customer_name", "Andra bygg AB"); + CHECK_STR(d, "result.ocr", expect_ocr); + CHECK(jint(d, "result.document_id") == doc1); + CHECK(jint(d, "result.voucher_id") == vou1); + CHECK(yyjson_arr_size(jget(d, "result.rows")) == 1); + CHECK(jint(d, "result.rows.0.quantity_milli") == 61000); + CHECK(jint(d, "result.rows.0.amount_ore") == 7320000); + CHECK_STR(d, "result.rows.0.vat_code", "25"); + CHECK_STR(d, "result.rows.0.account", "3001"); + CHECK_STR(d, "result.rows.0.unit", "tim"); + yyjson_doc_free(d); + + d = call(reqf("{\"v\":1,\"id\":\"353\",\"cmd\":\"invoice.pdf\"," + "\"session\":\"%s\",\"org\":%d,\"args\":{\"id\":%lld}}", + g_session, (int)org_id, (long long)inv1)); + CHECK_OK(d); + const char *stored = jstr(d, "result.content_base64"); + CHECK(stored && preview_b64 && strcmp(stored, preview_b64) == 0); + yyjson_doc_free(d); + + d = call(reqf("{\"v\":1,\"id\":\"355\",\"cmd\":\"invoice.issue\"," + "\"session\":\"%s\",\"org\":%d,\"args\":{\"customer_id\":" + "%lld,\"invoice_date\":\"2026-09-21\",\"due_date\":" + "\"2026-10-21\",\"rows\":[{\"description\":\"Konsult\"," + "\"quantity\":\"2,5\",\"unit\":\"tim\"," + "\"unit_price_ore\":100000,\"vat_code\":\"12\"," + "\"account\":\"3002\"}]}}", + g_session, (int)org_id, (long long)cust1)); + CHECK_OK(d); + int64_t inv2 = jint(d, "result.id"); + int64_t doc2 = jint(d, "result.document_id"); + int64_t vou2 = jint(d, "result.voucher_id"); + CHECK(inv2 > inv1); + CHECK(doc2 > doc1); + CHECK(vou2 > vou1); + CHECK(jint(d, "result.number") == 17762); + CHECK(jint(d, "result.net_ore") == 250000); + CHECK(jint(d, "result.vat_ore") == 30000); + CHECK(jint(d, "result.total_ore") == 280000); + yyjson_doc_free(d); + CHECK(db_count(g_db, "SELECT count(*) FROM vouchers") == vouchers_before + 2); + CHECK(db_count(g_db, "SELECT count(*) FROM attachments") == + attachments_before + 2); + + d = call(reqf("{\"v\":1,\"id\":\"356\",\"cmd\":\"voucher.get\"," + "\"session\":\"%s\",\"org\":%d,\"args\":{\"id\":%lld}}", + g_session, (int)org_id, (long long)vou2)); + CHECK_OK(d); + CHECK_STR(d, "result.source", "invoice"); + CHECK(find_amount(d, "result.rows", "account", "1510", "debit_ore") == + 280000); + CHECK(find_amount(d, "result.rows", "account", "2620", "credit_ore") == + 30000); + CHECK(find_amount(d, "result.rows", "account", "3002", "credit_ore") == + 250000); + CHECK(find_amount(d, "result.rows", "account", "2610", "credit_ore") == -1); + yyjson_doc_free(d); + + d = call(reqf("{\"v\":1,\"id\":\"357\",\"cmd\":\"invoice.list\"," + "\"session\":\"%s\",\"org\":%d}", + g_session, (int)org_id)); + CHECK_OK(d); + CHECK(yyjson_arr_size(jget(d, "result.items")) == 2); + CHECK(jint(d, "result.items.0.number") == 17762); + CHECK(jint(d, "result.items.1.number") == 17761); + CHECK_STR(d, "result.items.0.customer_name", "Andra bygg AB"); + CHECK_STR(d, "result.items.0.status", "issued"); + yyjson_doc_free(d); + + d = call(reqf("{\"v\":1,\"id\":\"358\",\"cmd\":\"invoice.list\"," + "\"session\":\"%s\",\"org\":%d,\"args\":{\"customer_id\":" + "%lld}}", + g_session, (int)org_id, (long long)cust1)); + CHECK_OK(d); + CHECK(yyjson_arr_size(jget(d, "result.items")) == 2); + yyjson_doc_free(d); + + d = call(reqf("{\"v\":1,\"id\":\"359\",\"cmd\":\"invoice.list\"," + "\"session\":\"%s\",\"org\":%d,\"args\":{\"customer_id\":" + "%lld}}", + g_session, (int)org_id, (long long)cust2)); + CHECK_OK(d); + CHECK(yyjson_arr_size(jget(d, "result.items")) == 0); + yyjson_doc_free(d); + + d = call(reqf("{\"v\":1,\"id\":\"360\",\"cmd\":\"invoice.list\"," + "\"session\":\"%s\",\"org\":%d,\"args\":{\"status\":" + "\"credited\"}}", + g_session, (int)org_id)); + CHECK_OK(d); + CHECK(yyjson_arr_size(jget(d, "result.items")) == 0); + yyjson_doc_free(d); + + d = call(reqf("{\"v\":1,\"id\":\"361\",\"cmd\":\"invoice.list\"," + "\"session\":\"%s\",\"org\":%d,\"args\":{\"limit\":1}}", + g_session, (int)org_id)); + CHECK_OK(d); + CHECK(yyjson_arr_size(jget(d, "result.items")) == 1); + CHECK(jint(d, "result.items.0.number") == 17762); + yyjson_doc_free(d); + + d = call(reqf("{\"v\":1,\"id\":\"362\",\"cmd\":\"invoice.list\"," + "\"session\":\"%s\",\"org\":%d,\"args\":{\"status\":" + "\"nope\"}}", + g_session, (int)org_id)); + CHECK_STR(d, "error.code", "INVALID_ARGS"); + yyjson_doc_free(d); + + d = call(reqf("{\"v\":1,\"id\":\"363\",\"cmd\":\"invoice.get\"," + "\"session\":\"%s\",\"org\":%d,\"args\":{\"id\":999999}}", + g_session, (int)org_id)); + CHECK_STR(d, "error.code", "NOT_FOUND"); + yyjson_doc_free(d); + + d = call(reqf("{\"v\":1,\"id\":\"364\",\"cmd\":\"invoice.pdf\"," + "\"session\":\"%s\",\"org\":%d,\"args\":{\"id\":999999}}", + g_session, (int)org_id)); + CHECK_STR(d, "error.code", "NOT_FOUND"); + yyjson_doc_free(d); + + d = call(reqf("{\"v\":1,\"id\":\"365\",\"cmd\":\"invoice.sequence_get\"," + "\"session\":\"%s\",\"org\":%d}", + g_session, (int)org_id)); + CHECK_OK(d); + CHECK(jint(d, "result.next_number") == 17763); + yyjson_doc_free(d); + + free(preview_b64); + /* ---------------- moms rules: ranges merge per box ------------- */ d = call(reqf("{\"v\":1,\"id\":\"110\",\"cmd\":\"org.create\"," "\"session\":\"%s\",\"args\":{\"name\":\"Moms AB\"}}", -- cgit v1.3