diff options
| author | Aldrik Ramaekers <aldrikboy@gmail.com> | 2025-08-09 15:51:45 +0200 |
|---|---|---|
| committer | Aldrik Ramaekers <aldrikboy@gmail.com> | 2025-08-09 15:51:45 +0200 |
| commit | 66d21e5fef32f64219f0f0b86c3b4b4a74623ba1 (patch) | |
| tree | ef04496d4712d69eaf4dd56aec9195db9a6e952d /src | |
| parent | 94e52baaed095f571c41cabe80d3a6b7e03653d2 (diff) | |
cost center crud
Diffstat (limited to 'src')
| -rw-r--r-- | src/administration.cpp | 132 | ||||
| -rw-r--r-- | src/locales.cpp | 2 | ||||
| -rw-r--r-- | src/locales/en.cpp | 16 | ||||
| -rw-r--r-- | src/ui/ui_contacts.cpp | 13 | ||||
| -rw-r--r-- | src/ui/ui_projects.cpp | 2 | ||||
| -rw-r--r-- | src/ui/ui_settings.cpp | 113 |
6 files changed, 265 insertions, 13 deletions
diff --git a/src/administration.cpp b/src/administration.cpp index 0353276..e41942e 100644 --- a/src/administration.cpp +++ b/src/administration.cpp @@ -2,6 +2,7 @@ #include <stdlib.h> #include <assert.h> #include <time.h> +#include <stdio.h> #include "strops.hpp" #include "administration.hpp" @@ -156,14 +157,41 @@ static void administration_create_default_tax_brackets() ADD_BRACKET("SE", 12.0f, "tax.reduced"); } +static void administration_create_default_cost_centers() +{ + #define ADD_COSTCENTER(_description, _code)\ + {\ + cost_center* tb = (cost_center*)malloc(sizeof(cost_center));\ + snprintf(tb->id, sizeof(tb->id), "E/%d", administration_create_id());\ + memcpy(tb->description, _description, sizeof(tb->description));\ + memcpy(tb->code, _code, sizeof(tb->code));\ + list_append(&g_administration.cost_centers, tb);\ + g_administration.next_id++;\ + } + + ADD_COSTCENTER("costcenter.general_expenses", "GENE"); + ADD_COSTCENTER("costcenter.administration_general_management", "ADMN"); + ADD_COSTCENTER("costcenter.finance_accounting", "FINC"); + ADD_COSTCENTER("costcenter.information_technology", "INFO"); + ADD_COSTCENTER("costcenter.sales_marketing", "SALE"); + ADD_COSTCENTER("costcenter.operations_production", "OPER"); + ADD_COSTCENTER("costcenter.supply_chain_logistics", "SUPP"); + ADD_COSTCENTER("costcenter.research_development", "RDEV"); + ADD_COSTCENTER("costcenter.facilities_maintenance", "FACL"); + ADD_COSTCENTER("costcenter.customer_service_support", "CUST"); + ADD_COSTCENTER("costcenter.other_specialized", "OTHR"); +} + void administration_create() { list_init(&g_administration.contacts); list_init(&g_administration.projects); list_init(&g_administration.tax_brackets); + list_init(&g_administration.cost_centers); strops_copy(g_administration.path, "", sizeof(g_administration.path)); administration_create_default_tax_brackets(); + administration_create_default_cost_centers(); } void administration_destroy() @@ -171,6 +199,7 @@ void administration_destroy() list_destroy(&g_administration.contacts); list_destroy(&g_administration.projects); list_destroy(&g_administration.tax_brackets); + list_destroy(&g_administration.cost_centers); } bool administration_create_contact(contact data) @@ -184,6 +213,13 @@ bool administration_create_contact(contact data) return true; } +bool administration_can_contact_be_deleted(contact data) +{ + (void)data; + // TODO + return true; +} + bool administration_update_contact(contact data) { list_iterator_start(&g_administration.contacts); @@ -285,7 +321,7 @@ u32 administration_get_projects(u32 page_index, u32 page_size, project* buffer) void administration_cancel_project(project data) { data.end_date = time(NULL); - data.state = project_state::CANCELLED; + data.state = project_state::PROJECT_CANCELLED; administration_update_project(data); } @@ -293,9 +329,9 @@ char* administration_project_get_status_string(project data) { switch(data.state) { - case project_state::RUNNING: return "project.state.running"; - case project_state::PAUSED: return "project.state.paused"; - case project_state::CANCELLED: return "project.state.cancelled"; + case project_state::PROJECT_RUNNING: return "project.state.running"; + case project_state::PROJECT_PAUSED: return "project.state.paused"; + case project_state::PROJECT_CANCELLED: return "project.state.cancelled"; default: assert(0); break; } return ""; @@ -303,7 +339,7 @@ char* administration_project_get_status_string(project data) bool administration_create_project(project data) { - data.state = project_state::RUNNING; + data.state = project_state::PROJECT_RUNNING; data.start_date = time(NULL); data.end_date = 0; project* new_project = (project*)malloc(sizeof(project)); @@ -378,4 +414,90 @@ u32 administration_get_tax_brackets(country_tax_bracket* buffer) list_iterator_stop(&g_administration.tax_brackets); return write_cursor; +} + +u32 administration_get_cost_center_count() +{ + return list_size(&g_administration.cost_centers); +} + +u32 administration_get_cost_centers(cost_center* buffer) +{ + assert(buffer); + + u32 write_cursor = 0; + + list_iterator_start(&g_administration.cost_centers); + while (list_iterator_hasnext(&g_administration.cost_centers)) { + cost_center c = *(cost_center *)list_iterator_next(&g_administration.cost_centers); + buffer[write_cursor++] = c; + } + list_iterator_stop(&g_administration.cost_centers); + + return write_cursor; +} + +static bool administration_get_cost_center_by_code(char* code, cost_center* buffer) +{ + bool result = false; + list_iterator_start(&g_administration.cost_centers); + while (list_iterator_hasnext(&g_administration.cost_centers)) { + cost_center c = *(cost_center *)list_iterator_next(&g_administration.cost_centers); + *buffer = c; + if (strcmp(code, c.code) == 0) { + result = true; + break; + } + } + list_iterator_stop(&g_administration.cost_centers); + + return result; +} + +bool administration_verify_cost_center_description(char* text) +{ + return strlen(text) != 0; +} + +bool administration_verify_cost_center_code(char* code) +{ + if (strlen(code) == 0) return false; + + cost_center cost_center; + bool found = administration_get_cost_center_by_code(code, &cost_center); + return !found; +} + +bool administration_add_cost_center(cost_center data) +{ + cost_center cs; + bool found = administration_get_cost_center_by_code(data.code, &cs); + if (found) return false; + + cost_center* tb = (cost_center*)malloc(sizeof(cost_center)); + snprintf(tb->id, sizeof(tb->id), "E/%d", administration_create_id()); + memcpy(tb->description, data.description, sizeof(tb->description)); + memcpy(tb->code, data.code, sizeof(tb->code)); + list_append(&g_administration.cost_centers, tb); + + g_administration.next_id++; + + return true; +} + +bool administration_update_cost_center(cost_center data) +{ + list_iterator_start(&g_administration.cost_centers); + while (list_iterator_hasnext(&g_administration.cost_centers)) { + cost_center* c = (cost_center *)list_iterator_next(&g_administration.cost_centers); + + if (strcmp(c->id, data.id) == 0) { + memcpy(c, &data, sizeof(data)); + list_iterator_stop(&g_administration.cost_centers); + return true; + } + } + list_iterator_stop(&g_administration.cost_centers); + + return false; }
\ No newline at end of file diff --git a/src/locales.cpp b/src/locales.cpp index 363d3c9..89c8499 100644 --- a/src/locales.cpp +++ b/src/locales.cpp @@ -28,5 +28,5 @@ const char* localize(const char* key) return g_locale.entries[i].value; } } - return "[!MISSING!]"; + return key; }
\ No newline at end of file diff --git a/src/locales/en.cpp b/src/locales/en.cpp index 3c208ef..3c6bafd 100644 --- a/src/locales/en.cpp +++ b/src/locales/en.cpp @@ -19,6 +19,19 @@ locale_entry en_locales[] = { {"form.confirmCancelProject", "Are you sure you want to cancel this Project?"}, {"form.required", "required"}, + // Default cost centers + {"costcenter.general_expenses", "General Expenses"}, + {"costcenter.administration_general_management", "Administration & General Management"}, + {"costcenter.finance_accounting", "Finance & Accounting"}, + {"costcenter.information_technology", "Information Technology (IT)"}, + {"costcenter.sales_marketing", "Sales & Marketing"}, + {"costcenter.operations_production", "Operations / Production"}, + {"costcenter.supply_chain_logistics", "Supply Chain & Logistics"}, + {"costcenter.research_development", "Research & Development"}, + {"costcenter.facilities_maintenance", "Facilities & Maintenance"}, + {"costcenter.customer_service_support", "Customer Service & Support"}, + {"costcenter.other_specialized", "Other / Specialized"}, + // Tax strings. {"tax.reverse_charge", "Reverse tax"}, {"tax.exempt", "Tax exempt"}, @@ -93,8 +106,11 @@ locale_entry en_locales[] = { // Settings strings. {"settings.table.company", "Company"}, {"settings.table.vatrates", "VAT Rates"}, + {"settings.table.costcenters", "Cost Centers"}, {"settings.vat.table.country", "Country"}, {"settings.vat.table.rates", "Rates"}, + {"settings.costcenters.table.code", "Code"}, + {"settings.costcenters.table.description", "Description"}, }; const int en_locale_count = sizeof(en_locales) / sizeof(en_locales[0]);
\ No newline at end of file diff --git a/src/ui/ui_contacts.cpp b/src/ui/ui_contacts.cpp index 24f45f7..e00fb78 100644 --- a/src/ui/ui_contacts.cpp +++ b/src/ui/ui_contacts.cpp @@ -196,12 +196,13 @@ static void draw_contact_list() } ImGui::SameLine(); - - // TODO check to make sure no invoices are connected to this contact. - snprintf(btn_name, sizeof(btn_name), "%s##%d", localize("form.delete"), i); - if (ImGui::Button(btn_name)) { - selected_for_removal = c; - ImGui::OpenPopup("ConfirmDeletePopup"); + if (administration_can_contact_be_deleted(c)) + { + snprintf(btn_name, sizeof(btn_name), "%s##%d", localize("form.delete"), i); + if (ImGui::Button(btn_name)) { + selected_for_removal = c; + ImGui::OpenPopup("ConfirmDeletePopup"); + } } } diff --git a/src/ui/ui_projects.cpp b/src/ui/ui_projects.cpp index a831f60..377155e 100644 --- a/src/ui/ui_projects.cpp +++ b/src/ui/ui_projects.cpp @@ -130,7 +130,7 @@ static void draw_project_list() current_view_state = view_state::VIEW; } - if (c.state == project_state::RUNNING) + if (c.state == project_state::PROJECT_RUNNING) { ImGui::SameLine(); snprintf(btn_name, sizeof(btn_name), "%s##%d", localize("form.change"), i); diff --git a/src/ui/ui_settings.cpp b/src/ui/ui_settings.cpp index 97e0503..7854be3 100644 --- a/src/ui/ui_settings.cpp +++ b/src/ui/ui_settings.cpp @@ -10,9 +10,19 @@ extern bool draw_contact_form(contact* buffer, bool back_button_enabled = true, bool viewing_only = false); static contact company_info; + country_tax_bracket* tax_brackets; u32 tax_bracket_count; +cost_center* cost_centers; +u32 cost_center_count; + +void ui_destroy_settings() +{ + free(tax_brackets); + free(cost_centers); +} + void ui_setup_settings() { company_info = administration_get_company_info(); @@ -20,6 +30,10 @@ void ui_setup_settings() tax_bracket_count = administration_get_tax_bracket_count(); tax_brackets = (country_tax_bracket*)malloc(tax_bracket_count * sizeof(country_tax_bracket)); administration_get_tax_brackets(tax_brackets); + + cost_center_count = administration_get_cost_center_count(); + cost_centers = (cost_center*)malloc(cost_center_count * sizeof(cost_center)); + administration_get_cost_centers(cost_centers); } static void ui_draw_vat_rates() @@ -66,6 +80,100 @@ static void ui_draw_vat_rates() } } +static void ui_draw_cost_centers() +{ + static bool is_adding_item = false; + static cost_center new_cost_center; + + static bool is_editing_item = false; + static u32 editing_item_index = 0; + + if (ImGui::BeginTable("TableCostCenters", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) { + + ImGui::TableSetupColumn(localize("settings.costcenters.table.code"), ImGuiTableColumnFlags_WidthFixed, 140); + ImGui::TableSetupColumn(localize("settings.costcenters.table.description")); + + for (u32 i = 0; i < cost_center_count; i++) { + cost_center c = cost_centers[i]; + + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); ImGui::Text(c.code); + ImGui::TableSetColumnIndex(1); + + if (is_editing_item && editing_item_index == i) + { + ImGui::InputText("##Description", new_cost_center.description, IM_ARRAYSIZE(new_cost_center.description)); + + bool is_desc_valid = administration_verify_cost_center_description(new_cost_center.description); + + if (!is_desc_valid) ImGui::BeginDisabled(); + ImGui::SameLine(); + if (ImGui::Button(localize("form.save"))) { + is_editing_item = false; + is_adding_item = false; + + administration_update_cost_center(new_cost_center); + + ui_destroy_settings(); + ui_setup_settings(); + } + if (!is_desc_valid) ImGui::EndDisabled(); + } + else + { + ImGui::Text(localize(c.description)); + } + + if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) + { + is_editing_item = true; + is_adding_item = false; + editing_item_index = i; + new_cost_center = c; + } + } + + if (is_adding_item) + { + ImGui::TableNextRow(); + + bool is_code_valid = administration_verify_cost_center_code(new_cost_center.code); + if (!is_code_valid) ImGui::PushStyleColor(ImGuiCol_FrameBg, IM_COL32(255, 0, 0, 64)); + ImGui::TableSetColumnIndex(0); ImGui::InputText("##Code", new_cost_center.code, IM_ARRAYSIZE(new_cost_center.code)); + if (!is_code_valid) ImGui::PopStyleColor(); + + bool is_desc_valid = administration_verify_cost_center_description(new_cost_center.description); + if (!is_desc_valid) ImGui::PushStyleColor(ImGuiCol_FrameBg, IM_COL32(255, 0, 0, 64)); + ImGui::TableSetColumnIndex(1); ImGui::InputText("##Description", new_cost_center.description, IM_ARRAYSIZE(new_cost_center.description)); + if (!is_desc_valid) ImGui::PopStyleColor(); + + bool can_save = is_code_valid && is_desc_valid; + + if (!can_save) ImGui::BeginDisabled(); + ImGui::SameLine(); + if (ImGui::Button(localize("form.create"))) + { + is_adding_item = false; + is_editing_item = false; + administration_add_cost_center(new_cost_center); + + ui_destroy_settings(); + ui_setup_settings(); + } + if (!can_save) ImGui::EndDisabled(); + } + + ImGui::EndTable(); + } + + if (!is_adding_item && ImGui::Button(localize("form.create"))) + { + is_adding_item = true; + is_editing_item = false; + memset(&new_cost_center, 0, sizeof(new_cost_center)); + } +} + void ui_draw_settings() { if (ImGui::BeginTabBar("SettingsTabBar")) @@ -84,6 +192,11 @@ void ui_draw_settings() ui_draw_vat_rates(); ImGui::EndTabItem(); } + if (ImGui::BeginTabItem(localize("settings.table.costcenters"))) + { + ui_draw_cost_centers(); + ImGui::EndTabItem(); + } ImGui::EndTabBar(); } }
\ No newline at end of file |
