summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAldrik Ramaekers <aldrikboy@gmail.com>2025-10-19 13:49:36 +0200
committerAldrik Ramaekers <aldrikboy@gmail.com>2025-10-19 13:49:36 +0200
commit60dfc4cab91b0076901cac81ba6cb1f2d198b06c (patch)
treeb5408e86171782eb28017702b79e47f0ca03ed89
parent18bfbc423d188683973a0a3d6c31c9225158e262 (diff)
new tax rate format, ui and r/w
-rw-r--r--TODO1
-rw-r--r--include/administration.hpp12
-rw-r--r--include/file_templates.hpp6
-rw-r--r--src/administration.cpp39
-rw-r--r--src/administration_reader.cpp20
-rw-r--r--src/administration_writer.cpp19
-rw-r--r--src/ui/ui_settings.cpp20
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 =
"<CountryTaxBracket>\n"
- " <Id>{{TAXBRACKET_ID}}</Id>\n"
- " <CountryCode>{{TAXBRACKET_COUNTRY}}</CountryCode>\n"
+ " <Id>{{TAXBRACKET_INTERNAL_CODE}}</Id>\n"
" <Rate>{{TAXBRACKET_RATE}}</Rate>\n"
- " <Category>{{TAXBRACKET_CATEGORY}}</Category>\n"
+ " <Type>{{TAXBRACKET_TYPE}}</Type>\n"
+ " <TaxSections>{{TAXBRACKET_SECTIONS}}</TaxSections>\n"
"</CountryTaxBracket>";
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<tax_rate_type>(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<int>(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<int>(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();