diff options
| author | Aldrik Ramaekers <aldrikboy@gmail.com> | 2025-10-12 13:14:11 +0200 |
|---|---|---|
| committer | Aldrik Ramaekers <aldrikboy@gmail.com> | 2025-10-12 13:14:11 +0200 |
| commit | b6990df3d783da0a09e8b6a825d9ebeb7314466a (patch) | |
| tree | c9a858fcacd3c24b05a6a5d9da00e6a28e16dcc3 | |
| parent | 955af14f6664574df1ff47e073e39f8d48d6355a (diff) | |
mark invalid invoices, projects, contacts in ui
| -rw-r--r-- | TODO | 4 | ||||
| -rw-r--r-- | include/ui.hpp | 1 | ||||
| -rw-r--r-- | manual/01_features.md | 4 | ||||
| -rw-r--r-- | src/administration.cpp | 12 | ||||
| -rw-r--r-- | src/locales/en.cpp | 3 | ||||
| -rw-r--r-- | src/ui/imgui_extensions.cpp | 36 | ||||
| -rw-r--r-- | src/ui/ui_contacts.cpp | 8 | ||||
| -rw-r--r-- | src/ui/ui_expenses.cpp | 8 | ||||
| -rw-r--r-- | src/ui/ui_invoices.cpp | 10 | ||||
| -rw-r--r-- | src/ui/ui_projects.cpp | 8 |
10 files changed, 76 insertions, 18 deletions
@@ -2,7 +2,7 @@ TODO: - for invoice importing using AI: all address data should be editable because import is not perfect - for invoice importing using AI: file path should not be editable as it is imported - create invoice PDF for NL https://goedestartbelastingdienst.nl/wiki/view/50bdccd8-f9a0-4297-b57f-3a6651cbe05c/factuureisen -- toggle on invoice form wether price in inclusive of tax. +- toggle on invoice form wether price is inclusive of tax. - retrieve available balance from AI api & show in settings/services. - let user choose the model to use in settings/services/ai - real error logging for OpenAI and importing in general @@ -10,8 +10,6 @@ TODO: - log_set_depth function so data can be grouped - log elapsed time for ai requests - refactor _add functions to use _import functions -- _import functions should not check for validity and should never fail because of invalid data -- invalid invoices should be marked in the UI - write tests that check error handling for corrupt files. (e.g. references to tax rates, project and cost center that failed to load) - 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). - invoice sequential number should be modifyable & checked for uniqueness (for external invoices being imported) diff --git a/include/ui.hpp b/include/ui.hpp index 0f71c1e..76b5395 100644 --- a/include/ui.hpp +++ b/include/ui.hpp @@ -113,4 +113,5 @@ namespace ImGui void FormTaxRateCombo(char* tax_rate_id, char* orig_country, char* dest_country, bool has_error); bool FormCurrencyCombo(char* currency); void FormToggleCombo(bool *buffer, char* option1, char* option2); + bool DrawWarningIcon(float radius); }
\ No newline at end of file diff --git a/manual/01_features.md b/manual/01_features.md index 5a397dd..f26ba6a 100644 --- a/manual/01_features.md +++ b/manual/01_features.md @@ -1,11 +1,11 @@ # Introduction -OpenBooks is a simple and portable accounting tool. This tool aims to be EU VAT Directive compliant and has country specific compliance, invoice keeping and tax reporting. +OpenBooks is a simple and portable accounting tool. This tool aims to be EU VAT Directive compliant and has country specific compliance for invoice keeping and tax reporting. What OpenBooks can do: --------------- - OpenBooks handles administration of invoices, expenses, receipts, contacts, projects, VAT rates and cost centers. -- OpenBooks can export/email invoices in PDF, UBL and Peppol format. +- OpenBooks can export/send invoices in PDF, UBL and Peppol format. - OpenBooks can send and receive invoices over the Peppol network (using a locally run `Holodeck <https://holodeck-b2b.org/>` instance). - OpenBooks can create tax reports and audit files (see supported countries list). - OpenBooks can create and export income statements. diff --git a/src/administration.cpp b/src/administration.cpp index 495f847..6e6cfb4 100644 --- a/src/administration.cpp +++ b/src/administration.cpp @@ -799,9 +799,6 @@ void administration::company_info_set(contact data) // ======================= a_err administration::contact_import(contact data) { - a_err result = administration::contact_is_valid(data); - if (result != A_ERR_SUCCESS) return result; - if (strcmp(data.id, MY_COMPANY_ID) == 0) { administration::company_info_import(data); @@ -1104,9 +1101,6 @@ char* administration::project_get_status_string(project data) a_err administration::project_import(project data) { - a_err result = administration::project_is_valid(data); - if (result != A_ERR_SUCCESS) return result; - project* new_project = (project*)memops::alloc(sizeof(project)); if (!new_project) return A_ERR_GENERIC; @@ -1443,9 +1437,6 @@ a_err administration::cost_center_is_valid(cost_center data) a_err administration::cost_center_import(cost_center data) { - a_err result = administration::cost_center_is_valid(data); - if (result != A_ERR_SUCCESS) return result; - cost_center* tb = (cost_center*)memops::alloc(sizeof(cost_center)); if (!tb) return A_ERR_GENERIC; @@ -1701,9 +1692,6 @@ a_err administration::invoice_update(invoice* inv) a_err administration::invoice_import(invoice* inv) { - //a_err result = administration::invoice_is_valid(inv); - //if (result != A_ERR_SUCCESS) return result; - inv->is_triangulation = !(memcmp(&inv->addressee.address, &inv->customer.address, sizeof(address)) == 0); inv->issued_at -= (inv->issued_at % 86400); diff --git a/src/locales/en.cpp b/src/locales/en.cpp index e68e930..8ab4eaf 100644 --- a/src/locales/en.cpp +++ b/src/locales/en.cpp @@ -24,6 +24,9 @@ locale_entry en_locales[] = { {"ui.invoiceRequirementP2", "needs to be completed before adding invoices."}, {"ui.next", "Next >>"}, {"ui.prev", "<< Prev"}, + {"ui.tooltip.invalidInvoice", "Invoice has missing information."}, + {"ui.tooltip.invalidProject", "Project has missing information."}, + {"ui.tooltip.invalidContact", "Contact has missing information."}, // Status strings. {"status.saved", "[Saved to disk]"}, diff --git a/src/ui/imgui_extensions.cpp b/src/ui/imgui_extensions.cpp index ee0bebb..0bfd5c8 100644 --- a/src/ui/imgui_extensions.cpp +++ b/src/ui/imgui_extensions.cpp @@ -470,4 +470,40 @@ namespace ImGui ImGui::EndCombo(); } } + + bool DrawWarningIcon(float radius) + { + ImGui::SameLine(); + + ImVec2 cursor_pos = ImGui::GetCursorScreenPos(); + ImVec2 center = ImVec2(cursor_pos.x + radius, cursor_pos.y + radius + 4); + + ImGui::PushID((int)center.y); + ImDrawList* draw_list = ImGui::GetWindowDrawList(); + + // Draw red circle + draw_list->AddCircleFilled(center, radius, IM_COL32(255, 0, 0, 255)); + + // Draw exclamation mark + float line_height = radius * 0.9f; + float line_thickness = radius * 0.3f; + float dot_radius = radius * 0.2f; + + ImVec2 line_start(center.x - line_thickness/3.0f, center.y - line_height * 0.7f); + ImVec2 line_end(center.x - line_thickness/3.0f, center.y + line_height * 0.1f); + + // Vertical bar + draw_list->AddLine(line_start, line_end, IM_COL32(255, 255, 255, 255), line_thickness); + + // Bottom dot + draw_list->AddCircleFilled(ImVec2(center.x - dot_radius/3.0f, center.y + line_height * 0.55f), dot_radius, IM_COL32(255, 255, 255, 255)); + + ImGui::SetCursorScreenPos(ImVec2(center.x - radius, center.y - radius)); + ImGui::InvisibleButton("##warning_icon", ImVec2(radius * 2, radius * 2)); + ImGui::PopID(); + if (ImGui::IsItemHovered()) { + return true; + } + return false; + } }
\ No newline at end of file diff --git a/src/ui/ui_contacts.cpp b/src/ui/ui_contacts.cpp index 7d585c9..30d01de 100644 --- a/src/ui/ui_contacts.cpp +++ b/src/ui/ui_contacts.cpp @@ -154,6 +154,14 @@ static void draw_contact_list() ImGui::TableNextRow(); ImGui::TableSetColumnIndex(0); ImGui::Text(c.id); + + if (administration::contact_is_valid(c) != A_ERR_SUCCESS) + { + if (ImGui::DrawWarningIcon(8.0f)) { + ImGui::SetTooltip(locale::get("ui.tooltip.invalidContact")); + } + } + ImGui::TableSetColumnIndex(1); ImGui::Text(c.name); ImGui::TableSetColumnIndex(2); ImGui::Text("%s %s", c.address.address1, c.address.address2); diff --git a/src/ui/ui_expenses.cpp b/src/ui/ui_expenses.cpp index e22b5b1..b3c878a 100644 --- a/src/ui/ui_expenses.cpp +++ b/src/ui/ui_expenses.cpp @@ -228,6 +228,14 @@ static void draw_expenses_list() ImGui::TableNextRow(); ImGui::TableSetColumnIndex(0); ImGui::Text(c.sequential_number); + + if (administration::invoice_is_valid(&c) != A_ERR_SUCCESS) + { + if (ImGui::DrawWarningIcon(8.0f)) { + ImGui::SetTooltip(locale::get("ui.tooltip.invalidInvoice")); + } + } + ImGui::TableSetColumnIndex(1); ImGui::Text(c.supplier.name); ImGui::TableSetColumnIndex(2); ImGui::Text(c.customer.name); diff --git a/src/ui/ui_invoices.cpp b/src/ui/ui_invoices.cpp index 850c9a3..fbc6eb0 100644 --- a/src/ui/ui_invoices.cpp +++ b/src/ui/ui_invoices.cpp @@ -311,7 +311,7 @@ static void draw_invoices_list() if (ImGui::BeginTable("TableInvoices", 7, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) { - ImGui::TableSetupColumn(locale::get("invoice.table.invoicenumber"), ImGuiTableColumnFlags_WidthFixed, 120); + ImGui::TableSetupColumn(locale::get("invoice.table.invoicenumber"), ImGuiTableColumnFlags_WidthFixed, 130); ImGui::TableSetupColumn(locale::get("invoice.table.customer")); ImGui::TableSetupColumn(locale::get("invoice.table.addressee")); ImGui::TableSetupColumn(locale::get("invoice.table.issuedat")); @@ -325,6 +325,14 @@ static void draw_invoices_list() ImGui::TableNextRow(); ImGui::TableSetColumnIndex(0); ImGui::Text(c.sequential_number); + + if (administration::invoice_is_valid(&c) != A_ERR_SUCCESS) + { + if (ImGui::DrawWarningIcon(8.0f)) { + ImGui::SetTooltip(locale::get("ui.tooltip.invalidInvoice")); + } + } + ImGui::TableSetColumnIndex(1); ImGui::Text(c.customer.name); ImGui::TableSetColumnIndex(2); ImGui::Text(c.addressee.name); diff --git a/src/ui/ui_projects.cpp b/src/ui/ui_projects.cpp index 66cc336..43a8eb4 100644 --- a/src/ui/ui_projects.cpp +++ b/src/ui/ui_projects.cpp @@ -134,6 +134,14 @@ static void draw_project_list() ImGui::TableNextRow(); ImGui::TableSetColumnIndex(0); ImGui::Text(c.id); + + if (administration::project_is_valid(c) != A_ERR_SUCCESS) + { + if (ImGui::DrawWarningIcon(8.0f)) { + ImGui::SetTooltip(locale::get("ui.tooltip.invalidInvoice")); + } + } + ImGui::TableSetColumnIndex(1); ImGui::Text(locale::get(administration::project_get_status_string(c))); ImGui::TableSetColumnIndex(2); ImGui::Text(c.description); |
