summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAldrik Ramaekers <aldrikboy@gmail.com>2025-09-26 17:58:31 +0200
committerAldrik Ramaekers <aldrikboy@gmail.com>2025-09-26 17:58:31 +0200
commitfb8361d11bdf8c21d2e9d3b94bae444089ba0d96 (patch)
tree9ab563c0c3eefb71ee4a1db6079d58e377a252a3
parente2321f28730adcb8d67800a434ebc7d60a6dcccb (diff)
log read and write failures
-rw-r--r--docs/CHANGES.rst2
-rw-r--r--include/log.hpp7
-rw-r--r--src/administration.cpp10
-rw-r--r--src/administration_reader.cpp62
-rw-r--r--src/administration_writer.cpp27
-rw-r--r--src/log.cpp46
-rw-r--r--src/ui/ui_log.cpp2
7 files changed, 119 insertions, 37 deletions
diff --git a/docs/CHANGES.rst b/docs/CHANGES.rst
index 8d07a81..630f0b9 100644
--- a/docs/CHANGES.rst
+++ b/docs/CHANGES.rst
@@ -1,10 +1,8 @@
.. _changes:
TODO:
-- move xml functions out of administration reader into xml.c
- refactor _add functions to use _import functions
- write tests that check error handling for corrupt files. (e.g. references to tax rates, project and cost center that failed to load)
-- log load failures
- it is possible a referenced tax rate is loaded after an invoice is loaded. This means all invoices need to be recalculated after file load. (try to write a test for this).
- get rid of customer_id and supplier_id.
diff --git a/include/log.hpp b/include/log.hpp
index 5efad6e..4e3f4f5 100644
--- a/include/log.hpp
+++ b/include/log.hpp
@@ -19,6 +19,7 @@
#include "timer.h"
#include "imgui.h"
#include "config.hpp"
+#include "administration.hpp"
#define MAX_LEN_LOG_HISTORY 256
#define MAX_LEN_LOG_TXT 128
@@ -27,10 +28,14 @@ typedef struct {
u32 write_cursor;
u32 history_length;
char history[MAX_LEN_LOG_HISTORY][MAX_LEN_LOG_TXT];
+ ImVec4 colors[MAX_LEN_LOG_HISTORY];
} log;
#define STOPWATCH_START tick_t timestamp_start = timer_current();
#define STOPWATCH_TIME (timer_elapsed(timestamp_start)*1000.0f)
log* get_log();
-void log_add(const char* fmt, ...) IM_FMTARGS(2); \ No newline at end of file
+
+void log_aerr(a_err errors);
+void log_info(const char* fmt, ...) IM_FMTARGS(2);
+void log_error(const char* fmt, ...) IM_FMTARGS(2); \ No newline at end of file
diff --git a/src/administration.cpp b/src/administration.cpp
index 7e1eeb7..51a47b4 100644
--- a/src/administration.cpp
+++ b/src/administration.cpp
@@ -475,7 +475,7 @@ void administration_create()
list_init(&g_administration.cost_centers);
strops_copy(g_administration.path, "", sizeof(g_administration.path));
- log_add("Setup took %.3fms.", STOPWATCH_TIME);
+ log_info("Setup took %.3fms.", STOPWATCH_TIME);
}
static void administration_destroy_list(list_t *list)
@@ -824,7 +824,7 @@ void administration_create_income_statement(income_statement* statement)
free(invoice_buffer);
- log_add("Created income statement in %.3fms.", STOPWATCH_TIME);
+ log_info("Created income statement in %.3fms.", STOPWATCH_TIME);
}
void administration_set_file_path(char* path)
@@ -2128,11 +2128,10 @@ a_err administration_billing_item_import_to_invoice(invoice* invoice, billing_it
memcpy(tb, &item, sizeof(billing_item));
administration_recalculate_billing_item_totals(tb);
- administration_recalculate_invoice_totals(invoice);
-
if (!list_append(&invoice->billing_items, tb)) {
return A_ERR_GENERIC;
}
+ administration_recalculate_invoice_totals(invoice);
return A_ERR_SUCCESS;
}
@@ -2149,11 +2148,10 @@ a_err administration_billing_item_add_to_invoice(invoice* invoice, billing_item
strops_copy(tb->currency, invoice->currency, MAX_LEN_CURRENCY); // Set billing item currency to invoice currency.
administration_recalculate_billing_item_totals(tb);
- administration_recalculate_invoice_totals(invoice);
-
if (!list_append(&invoice->billing_items, tb)) {
return A_ERR_GENERIC;
}
+ administration_recalculate_invoice_totals(invoice);
g_administration.next_id++;
diff --git a/src/administration_reader.cpp b/src/administration_reader.cpp
index 91f62a9..fb2fbf0 100644
--- a/src/administration_reader.cpp
+++ b/src/administration_reader.cpp
@@ -118,7 +118,7 @@ bool administration_reader_open_existing(char* file_path)
zip_close(zip);
- log_add("Imported '%s' in %.3fms.", file_path, STOPWATCH_TIME);
+ log_info("Imported '%s' in %.3fms.", file_path, STOPWATCH_TIME);
return true;
}
@@ -240,10 +240,16 @@ bool administration_reader_import_invoice(char* buffer, size_t buffer_size)
free(child_name);
}
- bool result = administration_invoice_import(&data);
- log_add("Loaded invoice '%s' in %.3fms.", data.sequential_number, STOPWATCH_TIME);
+ a_err result = administration_invoice_import(&data);
+ if (result == A_ERR_SUCCESS) {
+ log_info("Loaded invoice '%s' in %.3fms.", data.sequential_number, STOPWATCH_TIME);
+ }
+ else {
+ log_aerr(result);
+ log_error("ERROR loading invoice '%s'.", data.sequential_number);
+ }
- return result;
+ return result == A_ERR_SUCCESS;
}
bool administration_reader_import_contact(char* buffer, size_t buffer_size)
@@ -273,8 +279,14 @@ bool administration_reader_import_contact(char* buffer, size_t buffer_size)
xml_get_str(node_address, data.address.postal, MAX_LEN_ADDRESS, "Postal");
xml_get_str(node_address, data.address.region, MAX_LEN_ADDRESS, "Region");
- bool result = administration_contact_import(data);
- log_add("Loaded contact '%s' in %.3fms.", data.name, STOPWATCH_TIME);
+ a_err result = administration_contact_import(data);
+ if (result == A_ERR_SUCCESS) {
+ log_info("Loaded contact '%s' in %.3fms.", data.name, STOPWATCH_TIME);
+ }
+ else {
+ log_aerr(result);
+ log_error("ERROR loading contact '%s'.", data.name);
+ }
return result;
}
@@ -295,9 +307,15 @@ bool administration_reader_import_project(char* buffer, size_t buffer_size)
data.start_date = xml_get_s64(root, "StartDate");
data.end_date = xml_get_s64(root, "EndDate");
- bool result = administration_project_import(data);
- log_add("Loaded project in %.3fms. id=%s description=%s state=%d started=%lld end=%lld",
- STOPWATCH_TIME, data.id, data.description, data.state, data.start_date, data.end_date);
+ a_err result = administration_project_import(data);
+ if (result == A_ERR_SUCCESS) {
+ log_info("Loaded project in %.3fms. id=%s description=%s state=%d started=%lld end=%lld",
+ STOPWATCH_TIME, data.id, data.description, data.state, data.start_date, data.end_date);
+ }
+ else {
+ log_aerr(result);
+ log_error("ERROR loading project '%s'.", data.id);
+ }
return result;
}
@@ -316,9 +334,15 @@ bool administration_reader_import_cost_center(char* buffer, size_t buffer_size)
xml_get_str(root, data.code, MAX_LEN_CODE, "Code");
xml_get_str(root, data.description, MAX_LEN_LONG_DESC, "Description");
- bool result = administration_cost_center_import(data);
- log_add("Loaded cost center in %.3fms. id=%s code=%s description=%s",
- STOPWATCH_TIME, data.id, data.code, data.description);
+ a_err result = administration_cost_center_import(data);
+ if (result == A_ERR_SUCCESS) {
+ log_info("Loaded cost center in %.3fms. id=%s code=%s description=%s",
+ STOPWATCH_TIME, data.id, data.code, data.description);
+ }
+ else {
+ log_aerr(result);
+ log_error("ERROR loading cost center '%s'.", data.id);
+ }
return result;
}
@@ -338,9 +362,15 @@ bool administration_reader_import_tax_rate(char* buffer, size_t buffer_size)
xml_get_str(root, data.category_code, MAX_LEN_CODE, "Category");
data.rate = xml_get_float(root, "Rate");
- bool result = administration_tax_rate_import(data);
- log_add("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);
+ a_err result = administration_tax_rate_import(data);
+ if (result == A_ERR_SUCCESS) {
+ log_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);
+ }
+ else {
+ log_aerr(result);
+ log_error("ERROR loading tax rate '%s'.", data.id);
+ }
return result;
}
@@ -357,7 +387,7 @@ bool administration_reader_import_administration_info(char* buffer, size_t buffe
administration_set_next_id(xml_get_s32(root, "NextId"));
administration_set_next_sequence_number(xml_get_s32(root, "NextSequenceNumber"));
- log_add("Loaded administration info in %.3fms. next_id=%d next_sequence_number=%d",
+ log_info("Loaded administration info in %.3fms. next_id=%d next_sequence_number=%d",
STOPWATCH_TIME, administration_get_next_id(), administration_get_next_sequence_number());
return true;
diff --git a/src/administration_writer.cpp b/src/administration_writer.cpp
index 75f5daf..c27b3e3 100644
--- a/src/administration_writer.cpp
+++ b/src/administration_writer.cpp
@@ -122,7 +122,8 @@ static bool _administration_writer_delete_entry_by_name(char* entry)
if (zip_entries_delete(zip_write, indices, 1) < 0) result = 0;
zip_close(zip_write);
- log_add("Deleted entry '%s' in %.3fms.", entry, STOPWATCH_TIME);
+ if (result) log_info("Deleted entry '%s' in %.3fms.", entry, STOPWATCH_TIME);
+ else log_error("Failed to delete entry '%s'.", entry);
return result;
}
@@ -487,7 +488,9 @@ bool administration_writer_save_invoice_blocking(invoice inv)
free(file_content);
- log_add("Saved invoice '%s' in %.3fms.", inv.sequential_number, STOPWATCH_TIME);
+ if (result) log_info("Saved invoice '%s' in %.3fms.", inv.sequential_number, STOPWATCH_TIME);
+ else log_error("Failed to save invoice '%s'.", inv.sequential_number);
+
return result;
}
@@ -535,7 +538,9 @@ bool administration_writer_save_project_blocking(project project)
free(file_content);
- log_add("Saved project '%s' in %.3fms.", project.description, STOPWATCH_TIME);
+ if (result) log_info("Saved project '%s' in %.3fms.", project.description, STOPWATCH_TIME);
+ else log_error("Failed to save project '%s'.", project.description);
+
return result;
}
@@ -581,7 +586,9 @@ bool administration_writer_save_cost_center_blocking(cost_center cost)
free(file_content);
- log_add("Saved cost center '%s' in %.3fms.", cost.code, STOPWATCH_TIME);
+ if (result) log_info("Saved cost center '%s' in %.3fms.", cost.code, STOPWATCH_TIME);
+ else log_error("Failed to save cost center '%s'.", cost.code);
+
return result;
}
@@ -628,7 +635,9 @@ bool administration_writer_save_tax_rate_blocking(tax_rate rate)
free(file_content);
- log_add("Saved tax rate '%s/%.1f' in %.3fms.", rate.country_code, rate.rate, STOPWATCH_TIME);
+ if (result) log_info("Saved tax rate '%s/%.1f' in %.3fms.", rate.country_code, rate.rate, STOPWATCH_TIME);
+ else log_error("Failed to save tax rate '%s/%.1f'.", rate.country_code, rate.rate);
+
return result;
}
@@ -686,7 +695,9 @@ bool administration_writer_save_contact_blocking(contact c)
free(file_content);
- log_add("Saved contact '%s' in %.3fms.", c.name, STOPWATCH_TIME);
+ if (result) log_info("Saved contact '%s' in %.3fms.", c.name, STOPWATCH_TIME);
+ else log_error("Failed to save contact '%s'.", c.name);
+
return result;
}
@@ -735,7 +746,9 @@ bool administration_writer_save_all_administration_info_blocking()
free(file_content);
- log_add("Saved administration info in %.3fms.", STOPWATCH_TIME);
+ if (result) log_info("Saved administration info in %.3fms.", STOPWATCH_TIME);
+ else log_error("Failed to save administration info.");
+
return result;
}
diff --git a/src/log.cpp b/src/log.cpp
index 270a636..839ebbe 100644
--- a/src/log.cpp
+++ b/src/log.cpp
@@ -27,12 +27,10 @@ log* get_log()
return &g_log;
}
-void log_add(const char* fmt, ...)
+static void log_message(const char* fmt, ImVec4 color, va_list args)
{
- va_list args;
- va_start(args, fmt);
vsnprintf(g_log.history[g_log.write_cursor], MAX_LEN_LOG_TXT, fmt, args);
- va_end(args);
+ g_log.colors[g_log.write_cursor] = color;
tick_t ms_since_epoch = timer_system();
char time_buf[50];
@@ -64,3 +62,43 @@ void log_add(const char* fmt, ...)
g_log.history_length++;
if (g_log.history_length > MAX_LEN_LOG_HISTORY) g_log.history_length = MAX_LEN_LOG_HISTORY;
}
+
+void log_aerr(a_err errors)
+{
+ if (errors & A_ERR_GENERIC) log_error(" ERROR: Generic error");
+ if (errors & A_ERR_NOT_FOUND) log_error(" ERROR: Not found");
+ if (errors & A_ERR_MISSING_DESCRIPTION) log_error(" ERROR: Missing description");
+ if (errors & A_ERR_CODE_EXISTS) log_error(" ERROR: Code already exists");
+ if (errors & A_ERR_MISSING_BILLING_ITEMS) log_error(" ERROR: Missing billing items");
+ if (errors & A_ERR_INVALID_ADDRESSEE) log_error(" ERROR: Invalid addressee");
+ if (errors & A_ERR_INVALID_CUSTOMER) log_error(" ERROR: Invalid customer");
+ if (errors & A_ERR_INVALID_SUPPLIER) log_error(" ERROR: Invalid supplier");
+ if (errors & A_ERR_MISSING_NAME) log_error(" ERROR: Missing name");
+ if (errors & A_ERR_MISSING_CITY) log_error(" ERROR: Missing city");
+ if (errors & A_ERR_MISSING_POSTAL) log_error(" ERROR: Missing postal code");
+ if (errors & A_ERR_MISSING_ADDRESS1) log_error(" ERROR: Missing address line 1");
+ if (errors & A_ERR_MISSING_COUNTRYCODE) log_error(" ERROR: Missing country code");
+ if (errors & A_ERR_MISSING_TAXID) log_error(" ERROR: Missing tax ID");
+ if (errors & A_ERR_MISSING_BUSINESSID) log_error(" ERROR: Missing business ID");
+ if (errors & A_ERR_MAX_ITEMS_REACHED) log_error(" ERROR: Maximum items reached");
+ if (errors & A_ERR_MISSING_CODE) log_error(" ERROR: Missing code");
+ if (errors & A_ERR_MISSING_EMAIL) log_error(" ERROR: Missing email");
+ if (errors & A_ERR_MISSING_TAX_RATE) log_error(" ERROR: Missing tax rate");
+ if (errors & A_ERR_INVALID_BILLING_ITEM) log_error(" ERROR: Invalid billing item");
+}
+
+void log_error(const char* fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ log_message(fmt, ImVec4(1,0,0,1), args);
+ va_end(args);
+}
+
+void log_info(const char* fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ log_message(fmt, ImVec4(1,1,1,1), args);
+ va_end(args);
+}
diff --git a/src/ui/ui_log.cpp b/src/ui/ui_log.cpp
index da0d29d..5b380a3 100644
--- a/src/ui/ui_log.cpp
+++ b/src/ui/ui_log.cpp
@@ -31,6 +31,6 @@ void ui_draw_log()
if (cursor < 0) {
cursor = (l->write_cursor + i) % MAX_LEN_LOG_HISTORY;
}
- ImGui::Text(l->history[cursor]);
+ ImGui::TextColored(l->colors[cursor], l->history[cursor]);
}
} \ No newline at end of file