From 60dfc4cab91b0076901cac81ba6cb1f2d198b06c Mon Sep 17 00:00:00 2001 From: Aldrik Ramaekers Date: Sun, 19 Oct 2025 13:49:36 +0200 Subject: new tax rate format, ui and r/w --- TODO | 1 + include/administration.hpp | 12 +++++++----- include/file_templates.hpp | 6 +++--- src/administration.cpp | 39 +++++++++++++++++++++++++++++++++++++++ src/administration_reader.cpp | 20 ++++++++++++++------ src/administration_writer.cpp | 19 +++++++++++++------ src/ui/ui_settings.cpp | 20 ++++++++++++++++---- 7 files changed, 93 insertions(+), 24 deletions(-) diff --git a/TODO b/TODO index f371bfb..807ca74 100644 --- a/TODO +++ b/TODO @@ -6,6 +6,7 @@ Refactor: - replace strncpy and similar with strops functions - There is alot of memory leakage - remove category_code from tax rate and get it from internal code as it has nothing to do with our administration. +- replace strlen with strops function Testing: - write tests for all NL tax categories diff --git a/include/administration.hpp b/include/administration.hpp index 151df2a..c8013b9 100644 --- a/include/administration.hpp +++ b/include/administration.hpp @@ -57,7 +57,7 @@ typedef enum #define MAX_TAX_SECTION_PER_RATE 3 typedef struct { - char id[MAX_LEN_ID]; // T/[id] + char id[MAX_LEN_ID]; // T/[id] TODO: can we get rid of this? char internal_code[MAX_LEN_SHORT_DESC]; float rate; // 0-100% u32 tax_section_count; @@ -538,12 +538,14 @@ namespace administration { tax_rate tax_rate_create_empty(); a_err tax_rate_import(tax_rate data); a_err tax_rate_add(tax_rate data); - a_err tax_rate_update(tax_rate data); + a_err tax_rate_exists(tax_rate data); + a_err tax_rate_remove(tax_rate data); - a_err tax_rate_get_by_shorthandle(tax_rate* buffer, char* handle); - a_err tax_rate_get_by_id(tax_rate* buffer, char* id); + a_err tax_rate_update(tax_rate data); // TODO remove + a_err tax_rate_get_by_shorthandle(tax_rate* buffer, char* handle); // TODO remove + a_err tax_rate_get_by_id(tax_rate* buffer, char* id); // TODO remove u32 tax_rate_get_all(tax_rate* buffer); - u32 tax_rate_get_by_country(tax_rate* buffer, u32 code_count, char** country_codes); + u32 tax_rate_get_by_country(tax_rate* buffer, u32 code_count, char** country_codes); // TODO remove // Cost center functions. // ======================= diff --git a/include/file_templates.hpp b/include/file_templates.hpp index b4a4a07..c44e624 100644 --- a/include/file_templates.hpp +++ b/include/file_templates.hpp @@ -34,10 +34,10 @@ namespace file_template { static const char* taxrate_save_template = "\n" - " {{TAXBRACKET_ID}}\n" - " {{TAXBRACKET_COUNTRY}}\n" + " {{TAXBRACKET_INTERNAL_CODE}}\n" " {{TAXBRACKET_RATE}}\n" - " {{TAXBRACKET_CATEGORY}}\n" + " {{TAXBRACKET_TYPE}}\n" + " {{TAXBRACKET_SECTIONS}}\n" ""; static const char* contact_save_template = diff --git a/src/administration.cpp b/src/administration.cpp index d01ec61..93af778 100644 --- a/src/administration.cpp +++ b/src/administration.cpp @@ -1045,6 +1045,45 @@ tax_rate administration::tax_rate_create_empty() return result; } +a_err administration::tax_rate_remove(tax_rate data) +{ + list_iterator_start(&g_administration.tax_rates); + while (list_iterator_hasnext(&g_administration.tax_rates)) { + tax_rate* c = (tax_rate *)list_iterator_next(&g_administration.tax_rates); + + if (strcmp(c->internal_code, data.internal_code) == 0) + { + list_iterator_stop(&g_administration.tax_rates); + if (list_delete(&g_administration.tax_rates, c) != 0) return A_ERR_GENERIC; + + char filename[MAX_LEN_PATH]; + strops::format(filename, sizeof(filename), "T/%s", c->internal_code); + if (data_deleted_event_callback) data_deleted_event_callback(filename); + return A_ERR_SUCCESS; + } + } + list_iterator_stop(&g_administration.tax_rates); + + return A_ERR_NOT_FOUND; +} + +a_err administration::tax_rate_exists(tax_rate data) +{ + list_iterator_start(&g_administration.tax_rates); + while (list_iterator_hasnext(&g_administration.tax_rates)) { + tax_rate c = *(tax_rate *)list_iterator_next(&g_administration.tax_rates); + + if (strcmp(c.internal_code, data.internal_code) == 0) + { + list_iterator_stop(&g_administration.tax_rates); + return A_ERR_SUCCESS; + } + } + list_iterator_stop(&g_administration.tax_rates); + + return A_ERR_NOT_FOUND; +} + a_err administration::tax_rate_get_by_shorthandle(tax_rate* buffer, char* handle) { assert(buffer); diff --git a/src/administration_reader.cpp b/src/administration_reader.cpp index 41ebdca..976c533 100644 --- a/src/administration_reader.cpp +++ b/src/administration_reader.cpp @@ -374,19 +374,27 @@ bool administration_reader::import_tax_rate(char* buffer, size_t buffer_size) struct xml_node* root = xml_document_root(document); tax_rate data = {0}; - xml_get_str(root, data.id, MAX_LEN_ID, "Id"); - xml_get_str(root, data.country_code, MAX_LEN_COUNTRY_CODE, "CountryCode"); - xml_get_str(root, data.category_code, MAX_LEN_CODE, "Category"); + xml_get_str(root, data.internal_code, MAX_LEN_ID, "Id"); data.rate = xml_get_float(root, "Rate"); + data.type = static_cast(xml_get_s32(root, "Type")); + + char tsb[MAX_LEN_LONG_DESC]; + xml_get_str(root, tsb, MAX_LEN_LONG_DESC, "TaxSections"); + + for (char *p = strops::tokenize(tsb,"##"); p != NULL; p = strtok(NULL, "##")) + { + if (strlen(p) > 0) + strops::copy(data.tax_sections[data.tax_section_count++], p, MAX_LEN_SHORT_DESC); + } a_err result = administration::tax_rate_import(data); if (result == A_ERR_SUCCESS) { - logger::info("Loaded tax rate info in %.3fms. id=%s country_code=%s category_code=%s rate=%.2f", - STOPWATCH_TIME, data.id, data.country_code, data.category_code, data.rate); + logger::info("Loaded tax rate info in %.3fms. internal_code=%s", + STOPWATCH_TIME, data.internal_code); } else { logger::aerr(result); - logger::error("ERROR loading tax rate '%s'.", data.id); + logger::error("ERROR loading tax rate '%s'.", data.internal_code); } return result; diff --git a/src/administration_writer.cpp b/src/administration_writer.cpp index 6b28367..ee22022 100644 --- a/src/administration_writer.cpp +++ b/src/administration_writer.cpp @@ -669,14 +669,21 @@ bool administration_writer::save_tax_rate_blocking(tax_rate rate) int buf_length = 0; char* file_content = copy_template(file_template::taxrate_save_template, &buf_length); - strops::replace(file_content, buf_length, "{{TAXBRACKET_ID}}", rate.id); - strops::replace(file_content, buf_length, "{{TAXBRACKET_COUNTRY}}", rate.country_code); + strops::replace(file_content, buf_length, "{{TAXBRACKET_INTERNAL_CODE}}", rate.internal_code); strops::replace_float(file_content, buf_length, "{{TAXBRACKET_RATE}}", rate.rate, 2); - strops::replace(file_content, buf_length, "{{TAXBRACKET_CATEGORY}}", rate.category_code); + strops::replace_int32(file_content, buf_length, "{{TAXBRACKET_TYPE}}", static_cast(rate.type)); + + char tax_sections_buffer[MAX_LEN_LONG_DESC]; + char* write_cursor = tax_sections_buffer; + for (u32 i = 0; i < rate.tax_section_count; i++) { + write_cursor += strops::format(write_cursor, MAX_LEN_LONG_DESC, "%s##", rate.tax_sections[i]); + } + + strops::replace(file_content, buf_length, "{{TAXBRACKET_SECTIONS}}", tax_sections_buffer); //// Write to Disk. char final_path[50]; - strops::format(final_path, 50, "%s.xml", rate.id); + strops::format(final_path, 50, "T/%s.xml", rate.internal_code); int final_length = (int)strlen(file_content); if (!xml_parse_document((uint8_t*)file_content, final_length)) result = 0; @@ -684,8 +691,8 @@ bool administration_writer::save_tax_rate_blocking(tax_rate rate) memops::unalloc(file_content); - if (result) logger::info("Saved tax rate '%s/%.1f' in %.3fms.", rate.country_code, rate.rate, STOPWATCH_TIME); - else logger::error("Failed to save tax rate '%s/%.1f'.", rate.country_code, rate.rate); + if (result) logger::info("Saved tax rate '%s' in %.3fms.", rate.internal_code, STOPWATCH_TIME); + else logger::error("Failed to save tax rate '%s'.", rate.internal_code); return result; } diff --git a/src/ui/ui_settings.cpp b/src/ui/ui_settings.cpp index 7feacb2..c1a27a2 100644 --- a/src/ui/ui_settings.cpp +++ b/src/ui/ui_settings.cpp @@ -68,8 +68,9 @@ static void draw_vat_rates() char id[MAX_LEN_SHORT_DESC]; strops::format(id, MAX_LEN_SHORT_DESC, "TableVatRates##%d", static_cast(type_iter)); - if (ImGui::BeginTable(id, 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) { + if (ImGui::BeginTable(id, 4, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) { + ImGui::TableSetupColumn("##check", ImGuiTableColumnFlags_WidthFixed, 25); ImGui::TableSetupColumn(locale::get("settings.vat.table.outgoing"), ImGuiTableColumnFlags_WidthStretch); ImGui::TableSetupColumn(locale::get("settings.vat.table.rates"), ImGuiTableColumnFlags_WidthFixed, 120); ImGui::TableSetupColumn(locale::get("settings.vat.table.section"), ImGuiTableColumnFlags_WidthFixed, 200); @@ -79,18 +80,29 @@ static void draw_vat_rates() tax_rate c = tax_rates[i]; if (c.type != type_iter) continue; + ImGui::PushID(i); + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); + bool toggle = administration::tax_rate_exists(c) == A_ERR_SUCCESS; + if (ImGui::Checkbox("##toggle", &toggle)) { + if (toggle) administration::tax_rate_add(c); + else administration::tax_rate_remove(c); + } + char localized_code[MAX_LEN_LONG_DESC]; strops::format(localized_code, MAX_LEN_LONG_DESC, "taxrate.code.%s", c.internal_code); - ImGui::TableSetColumnIndex(0); ImGui::TextUnformatted(locale::get(localized_code)); - ImGui::TableSetColumnIndex(1); ImGui::Text("%.2f%%", c.rate); - ImGui::TableSetColumnIndex(2); + ImGui::TableSetColumnIndex(1); ImGui::TextUnformatted(locale::get(localized_code)); + ImGui::TableSetColumnIndex(2); ImGui::Text("%.2f%%", c.rate); + ImGui::TableSetColumnIndex(3); for (u32 x = 0; x < c.tax_section_count; x++) { if (x == 0) ImGui::TextUnformatted(c.tax_sections[x]); else ImGui::Text(", %s", c.tax_sections[x]); if (x != c.tax_section_count-1) ImGui::SameLine(0, 0); } + + ImGui::PopID(); } ImGui::EndTable(); -- cgit v1.2.3-70-g09d2