summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnders Betts <anders.betts@gmail.com>2026-09-17 22:54:18 +0200
committerAnders Betts <anders.betts@gmail.com>2026-09-17 22:54:18 +0200
commit0241122e05ac0bd174d4ec43a5882397c146aa89 (patch)
treef2be5988e8893222130a992ce051bf67200be037
parentf367759f30f43d0f18c4fa3e7160a3ee5604e261 (diff)
downloadbokf-0241122e05ac0bd174d4ec43a5882397c146aa89.tar.gz
bokf-0241122e05ac0bd174d4ec43a5882397c146aa89.zip
Implement org.update (owner) and cover it in testsv0.1.5
-rw-r--r--src/commands.c90
-rw-r--r--tests/test_core.c28
2 files changed, 118 insertions, 0 deletions
diff --git a/src/commands.c b/src/commands.c
index 5ccadfc..948c42c 100644
--- a/src/commands.c
+++ b/src/commands.c
@@ -675,6 +675,94 @@ static yyjson_mut_val *h_org_get(struct req *r)
return o;
}
+static yyjson_mut_val *h_org_update(struct req *r)
+{
+ const char *name = arg_str(r->args, "name");
+ const char *org_nr = arg_str(r->args, "org_nr");
+ const char *vat_nr = arg_str(r->args, "vat_nr");
+ const char *address = arg_str(r->args, "address");
+ const char *postal = arg_str(r->args, "postal_code");
+ const char *city = arg_str(r->args, "city");
+ const char *country = arg_str(r->args, "country");
+ const char *email = arg_str(r->args, "email");
+ const char *phone = arg_str(r->args, "phone");
+ const char *moms = arg_str(r->args, "moms_period");
+ const char *framework = arg_str(r->args, "framework");
+ int64_t fy_month = 0;
+ arg_int(r->args, "fiscal_year_start_month", &fy_month);
+ if (!name && !org_nr && !vat_nr && !address && !postal && !city &&
+ !country && !email && !phone && !moms && !framework && fy_month == 0)
+ return fail(r, "INVALID_ARGS", "nothing to update");
+ if (name && !*name)
+ return fail(r, "INVALID_ARGS", "name cannot be empty");
+ if (fy_month && (fy_month < 1 || fy_month > 12))
+ return fail(r, "INVALID_ARGS", "fiscal_year_start_month must be 1-12");
+ if (moms && strcmp(moms, "month") != 0 && strcmp(moms, "quarter") != 0 &&
+ strcmp(moms, "year") != 0)
+ return fail(r, "INVALID_ARGS", "moms_period must be month, quarter or year");
+ if (framework && strcmp(framework, "K2") != 0 &&
+ strcmp(framework, "K3") != 0)
+ return fail(r, "INVALID_ARGS", "framework must be K2 or K3");
+
+ sqlite3_stmt *st = NULL;
+ if (sqlite3_prepare_v2(
+ r->db,
+ "UPDATE orgs SET"
+ " name=COALESCE(?2,name), org_nr=COALESCE(?3,org_nr),"
+ " vat_nr=COALESCE(?4,vat_nr), address=COALESCE(?5,address),"
+ " postal_code=COALESCE(?6,postal_code), city=COALESCE(?7,city),"
+ " country=COALESCE(?8,country), email=COALESCE(?9,email),"
+ " phone=COALESCE(?10,phone),"
+ " fiscal_year_start_month=CASE WHEN ?11=0"
+ " THEN fiscal_year_start_month ELSE ?11 END,"
+ " moms_period=COALESCE(?12,moms_period),"
+ " framework=COALESCE(?13,framework)"
+ " WHERE id=?1",
+ -1, &st, NULL) != SQLITE_OK)
+ return fail(r, "INTERNAL", "database error");
+ sqlite3_bind_int64(st, 1, r->org_id);
+ const char *texts[9] = { name, org_nr, vat_nr, address, postal,
+ city, country, email, phone };
+ for (int i = 0; i < 9; i++) {
+ if (texts[i])
+ sqlite3_bind_text(st, i + 2, texts[i], -1, SQLITE_TRANSIENT);
+ else
+ sqlite3_bind_null(st, i + 2);
+ }
+ sqlite3_bind_int64(st, 11, fy_month);
+ if (moms)
+ sqlite3_bind_text(st, 12, moms, -1, SQLITE_TRANSIENT);
+ else
+ sqlite3_bind_null(st, 12);
+ if (framework)
+ sqlite3_bind_text(st, 13, framework, -1, SQLITE_TRANSIENT);
+ else
+ sqlite3_bind_null(st, 13);
+ int rc = sqlite3_step(st);
+ sqlite3_finalize(st);
+ if (rc != SQLITE_DONE)
+ return fail(r, "INTERNAL", sqlite3_errmsg(r->db));
+
+ char *reqjson = audit_args_json(r->args);
+ audit_append(r->db, r->org_id, r->sess->user_id, r->sess->token_id,
+ "org.update", reqjson, "OK", NULL);
+ free(reqjson);
+
+ st = NULL;
+ if (sqlite3_prepare_v2(r->db, "SELECT " ORG_COLUMNS
+ " FROM orgs WHERE id=?1",
+ -1, &st, NULL) != SQLITE_OK)
+ return fail(r, "INTERNAL", "database error");
+ sqlite3_bind_int64(st, 1, r->org_id);
+ yyjson_mut_val *o = NULL;
+ if (sqlite3_step(st) == SQLITE_ROW)
+ o = org_json(r, st);
+ sqlite3_finalize(st);
+ if (!o)
+ return fail(r, "NOT_FOUND", "org not found");
+ return o;
+}
+
static yyjson_mut_val *h_org_member_list(struct req *r)
{
yyjson_mut_val *items = yyjson_mut_arr(r->rdoc);
@@ -3572,6 +3660,8 @@ const struct command g_commands[] = {
{ "org.list", "List orgs for the current user", PERM_READ, 0, 0, 0,
h_org_list },
{ "org.get", "Get org details", PERM_READ, 1, 0, 0, h_org_get },
+ { "org.update", "Update org details (owner)", PERM_OWNER, 1, 1, 1,
+ h_org_update },
{ "org.member_list", "List org members", PERM_READ, 1, 0, 0,
h_org_member_list },
{ "org.member_add", "Add a member to the org", PERM_OWNER, 1, 1, 1,
diff --git a/tests/test_core.c b/tests/test_core.c
index 5960665..a9910e9 100644
--- a/tests/test_core.c
+++ b/tests/test_core.c
@@ -393,6 +393,34 @@ int main(void)
CHECK_STR(d, "result.items.0.role", "owner");
yyjson_doc_free(d);
+ d = call(reqf("{\"v\":1,\"id\":\"8b\",\"cmd\":\"org.update\","
+ "\"session\":\"%s\",\"org\":%d,\"args\":"
+ "{\"org_nr\":\"559331-2126\",\"vat_nr\":\"SE559331212601\","
+ "\"address\":\"Lingonvägen 9\",\"postal_code\":\"192 48\","
+ "\"city\":\"Sollentuna\",\"email\":\"a@b.se\","
+ "\"phone\":\"+46700000000\"}}",
+ g_session, (int)org_id));
+ CHECK_OK(d);
+ CHECK_STR(d, "result.vat_nr", "SE559331212601");
+ CHECK_STR(d, "result.org_nr", "559331-2126");
+ yyjson_doc_free(d);
+
+ d = call(reqf("{\"v\":1,\"id\":\"8c\",\"cmd\":\"org.get\","
+ "\"session\":\"%s\",\"org\":%d}",
+ g_session, (int)org_id));
+ CHECK_OK(d);
+ CHECK_STR(d, "result.address", "Lingonvägen 9");
+ CHECK_STR(d, "result.postal_code", "192 48");
+ CHECK_STR(d, "result.city", "Sollentuna");
+ yyjson_doc_free(d);
+
+ d = call(reqf("{\"v\":1,\"id\":\"8d\",\"cmd\":\"org.update\","
+ "\"session\":\"%s\",\"org\":%d,\"args\":"
+ "{\"moms_period\":\"week\"}}",
+ g_session, (int)org_id));
+ CHECK_STR(d, "error.code", "INVALID_ARGS");
+ yyjson_doc_free(d);
+
d = call(reqf("{\"v\":1,\"id\":\"9\",\"cmd\":\"session.use_org\","
"\"session\":\"%s\",\"args\":{\"org\":%d}}",
g_session, (int)org_id));