diff options
| author | Aldrik Ramaekers <aldrikboy@gmail.com> | 2025-08-16 13:56:11 +0200 |
|---|---|---|
| committer | Aldrik Ramaekers <aldrikboy@gmail.com> | 2025-08-16 13:56:11 +0200 |
| commit | 6273aef9aa9a4ac5375710d51a5bc33f62265d76 (patch) | |
| tree | c20f5896a9820229171d134200e975dd4c34c549 /src | |
| parent | 12afa4c63e642452676f77830ec0383a6132883e (diff) | |
invoice table view
Diffstat (limited to 'src')
| -rw-r--r-- | src/administration.cpp | 95 | ||||
| -rw-r--r-- | src/ui/ui_invoices.cpp | 159 |
2 files changed, 249 insertions, 5 deletions
diff --git a/src/administration.cpp b/src/administration.cpp index 6ed7d63..95ae705 100644 --- a/src/administration.cpp +++ b/src/administration.cpp @@ -480,6 +480,23 @@ bool administration_is_project_valid(project data) return strlen(data.description) > 0; } +char* administration_get_invoice_status_string(invoice* invoice) +{ + switch(invoice->status) + { + case invoice_status::INVOICE_CONCEPT: return "invoice.state.concept"; + case invoice_status::INVOICE_SENT: return "invoice.state.sent"; + case invoice_status::INVOICE_REMINDED: return "invoice.state.reminded"; + case invoice_status::INVOICE_PAID: return "invoice.state.paid"; + case invoice_status::INVOICE_EXPIRED: return "invoice.state.expired"; + case invoice_status::INVOICE_CANCELLED: return "invoice.state.cancelled"; + case invoice_status::INVOICE_REFUNDED: return "invoice.state.refunded"; + case invoice_status::INVOICE_CORRECTED: return "invoice.state.corrected"; + default: assert(0); break; + } + return ""; +} + char* administration_project_get_status_string(project data) { switch(data.state) @@ -948,27 +965,103 @@ bool administration_is_invoice_valid(invoice* invoice) return true; } +bool administration_update_invoice(invoice* inv) +{ + if (!administration_is_invoice_valid(inv)) return false; + + // Invoice is valid but customer id is unset means we need to register a new contact. + if (strcmp(inv->customer_id, "") == 0) + { + contact new_contact = administration_create_empty_contact(); + strops_copy(inv->customer_id, new_contact.id, sizeof(new_contact.id)); + strops_copy(inv->customer.id, new_contact.id, sizeof(new_contact.id)); + + memcpy(&new_contact, &inv->customer, sizeof(contact)); + administration_create_contact(new_contact); + + inv->customer = new_contact; + } + + // Addressee is same as customer. + if (!inv->is_triangulation) + { + memcpy(&inv->addressee, &inv->customer, sizeof(contact)); + } + + list_iterator_start(&g_administration.invoices); + while (list_iterator_hasnext(&g_administration.invoices)) { + invoice* c = (invoice *)list_iterator_next(&g_administration.invoices); + + if (strcmp(c->id, inv->id) == 0) + { + memcpy(c, inv, sizeof(invoice)); + list_iterator_stop(&g_administration.invoices); + return true; + } + } + list_iterator_stop(&g_administration.invoices); + return false; +} + bool administration_add_invoice(invoice* inv) { if (!administration_is_invoice_valid(inv)) return false; // Invoice is valid but customer id is unset means we need to register a new contact. - if (strcmp(inv->customer_id, "")) + if (strcmp(inv->customer_id, "") == 0) { contact new_contact = administration_create_empty_contact(); + strops_copy(inv->customer_id, new_contact.id, sizeof(new_contact.id)); strops_copy(inv->customer.id, new_contact.id, sizeof(new_contact.id)); memcpy(&new_contact, &inv->customer, sizeof(contact)); administration_create_contact(new_contact); + + inv->customer = new_contact; + } + + // Addressee is same as customer. + if (!inv->is_triangulation) + { + memcpy(&inv->addressee, &inv->customer, sizeof(contact)); } invoice* new_inv = (invoice*)malloc(sizeof(invoice)); memcpy((void*)new_inv, (void*)inv, sizeof(invoice)); + new_inv->status = invoice_status::INVOICE_CONCEPT; + list_append(&g_administration.invoices, new_inv); g_administration.next_id++; g_administration.next_sequence_number++; return true; +} + +u32 administration_get_invoice_count() +{ + return list_size(&g_administration.invoices); +} + +u32 administration_get_invoices(u32 page_index, u32 page_size, invoice* buffer) +{ + assert(buffer); + + u32 write_cursor = 0; + + u32 read_start = page_index * page_size; + + list_iterator_start(&g_administration.invoices); + while (list_iterator_hasnext(&g_administration.invoices)) { + invoice c = *(invoice *)list_iterator_next(&g_administration.invoices); + + if (g_administration.invoices.iter_pos <= read_start) continue; + + buffer[write_cursor++] = c; + if (write_cursor >= page_size) break; + } + list_iterator_stop(&g_administration.invoices); + + return write_cursor; }
\ No newline at end of file diff --git a/src/ui/ui_invoices.cpp b/src/ui/ui_invoices.cpp index 8c0943c..5d89479 100644 --- a/src/ui/ui_invoices.cpp +++ b/src/ui/ui_invoices.cpp @@ -21,6 +21,12 @@ country_tax_bracket* tax_bracket_list_buffer = 0; void draw_contact_form_ex(contact* buffer, bool viewing_only = false, bool with_autocomplete = false, bool* on_autocomplete = 0); +void ui_destroy_invoices() +{ + free(cost_center_list_buffer); + free(tax_bracket_list_buffer); +} + void ui_setup_invoices() { current_view_state = view_state::LIST; @@ -339,6 +345,8 @@ static void draw_invoice_items_form(invoice* invoice) ImGui::EndTable(); } + + free(buffer); } void draw_invoice_form(invoice* buffer, bool viewing_only = false) @@ -372,7 +380,7 @@ void draw_invoice_form(invoice* buffer, bool viewing_only = false) } ImGui::SameLine(); ImGui::Text("Invoice expires at"); - ImGui::EndDisabled(); + if (!viewing_only) ImGui::EndDisabled(); // 6. Product/service delivered at tm delivered_at_date = *gmtime(&buffer->delivered_at); @@ -390,6 +398,9 @@ void draw_invoice_form(invoice* buffer, bool viewing_only = false) bool on_autocomplete; draw_contact_form_ex(&buffer->customer, false, true, &on_autocomplete); + // TODO: check if customer info is equal to contact stored in customer id, in case we select from dropdown and edit data after, + // this should be handled as a new contact and customer_id should be set to "" so we create a new contact. + if (on_autocomplete) { strops_copy(buffer->customer_id, buffer->customer.id, sizeof(buffer->customer_id)); } @@ -433,11 +444,16 @@ void draw_invoice_form(invoice* buffer, bool viewing_only = false) // 13. Invoice items form draw_invoice_items_form(buffer); - //if (viewing_only) ImGui::EndDisabled(); + if (viewing_only) ImGui::EndDisabled(); } void draw_invoices_list() { + const u32 items_per_page = 50; + static s32 current_page = 0; + s32 max_page = (administration_get_invoice_count() + items_per_page - 1) / items_per_page; + if (max_page == 0) max_page = 1; + // Table header controls: create button and pagination. if (ImGui::Button(localize("form.create"))) { @@ -446,6 +462,131 @@ void draw_invoices_list() active_invoice.supplier = administration_get_company_info(); strops_copy(active_invoice.supplier_id, active_invoice.supplier.id, sizeof(active_invoice.supplier_id)); } + + if (current_page >= max_page-1) current_page = max_page-1; + if (current_page < 0) current_page = 0; + + // Navigate to prev page button. + ImGui::SameLine(); + bool enable_prev = current_page > 0; + if (!enable_prev) ImGui::BeginDisabled(); + if (ImGui::Button("<< Prev") && current_page > 0) current_page--; + if (!enable_prev) ImGui::EndDisabled(); + + ImGui::SameLine(); + ImGui::Text("(%d/%d)", current_page+1, max_page); + + // Navigate to next page button. + ImGui::SameLine(); + bool enable_next = current_page < max_page-1; + if (!enable_next) ImGui::BeginDisabled(); + if (ImGui::Button("Next >>") && current_page < max_page-1) current_page++; + if (!enable_next) ImGui::EndDisabled(); + + ImGui::Spacing(); + + if (ImGui::BeginTable("TableInvoices", 7, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) { + + ImGui::TableSetupColumn("Invoice Number", ImGuiTableColumnFlags_WidthFixed, 120); + ImGui::TableSetupColumn("Customer"); + ImGui::TableSetupColumn("Addressee"); + ImGui::TableSetupColumn("Issued At"); + ImGui::TableSetupColumn("Total"); + ImGui::TableSetupColumn("Status"); + ImGui::TableSetupColumn(""); + ImGui::TableHeadersRow(); + + invoice invoice_list[items_per_page]; + u32 invoice_count = administration_get_invoices(current_page, items_per_page, invoice_list); + + for (u32 i = 0; i < invoice_count; i++) { + invoice c = invoice_list[i]; + + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); ImGui::Text(c.sequential_number); + ImGui::TableSetColumnIndex(1); ImGui::Text(c.customer.name); + ImGui::TableSetColumnIndex(2); ImGui::Text(c.addressee.name); + + struct tm *lt = localtime(&c.issued_at); + char buf[80]; + strftime(buf, sizeof(buf), "%d-%m-%Y", lt); + + ImGui::TableSetColumnIndex(3); ImGui::Text(buf); + ImGui::TableSetColumnIndex(4); ImGui::Text("%.2f %s", c.total, c.currency); + ImGui::TableSetColumnIndex(5); ImGui::Text("%s", localize(administration_get_invoice_status_string(&c))); + ImGui::TableSetColumnIndex(6); + + char btn_name[20]; + snprintf(btn_name, sizeof(btn_name), "%s##%d", localize("form.view"), i); + if (ImGui::Button(btn_name)) { + active_invoice = c; + current_view_state = view_state::VIEW; + } + + ImGui::SameLine(); + + if (c.status == invoice_status::INVOICE_CONCEPT) + { + snprintf(btn_name, sizeof(btn_name), "%s##%d", localize("form.change"), i); + if (ImGui::Button(btn_name)) { + active_invoice = c; + current_view_state = view_state::EDIT; + } + } + + // ImGui::SameLine(); + // 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"); + // } + // } + } + + // Confirmation popup before contact is deleted definitively. + // if (ImGui::BeginPopupModal("ConfirmDeletePopup", nullptr, ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoTitleBar)) { + // ImGui::Text(localize("form.confirmDelete")); + // ImGui::Separator(); + + // if (ImGui::Button(localize("form.yes"), ImVec2(120, 0))) { + // administration_remove_contact(selected_for_removal); + // ImGui::CloseCurrentPopup(); + // } + // ImGui::SameLine(); + // if (ImGui::Button(localize("form.no"), ImVec2(120, 0))) { + // ImGui::CloseCurrentPopup(); + // } + // ImGui::EndPopup(); + // } + + ImGui::EndTable(); + } +} + + +static void ui_draw_invoice_update() +{ + if (ImGui::Button(localize("form.back"))) { + current_view_state = view_state::LIST; + } + + draw_invoice_form(&active_invoice); + + bool can_save = administration_is_invoice_valid(&active_invoice); + if (!can_save) ImGui::BeginDisabled(); + + ImGui::Spacing(); + if (ImGui::Button(localize("form.save"))) { + administration_update_invoice(&active_invoice); + current_view_state = view_state::LIST; + + ui_destroy_invoices(); + ui_setup_invoices(); + } + + if (!can_save) ImGui::EndDisabled(); } static void ui_draw_invoice_create() @@ -463,6 +604,9 @@ static void ui_draw_invoice_create() if (ImGui::Button(localize("form.save"))) { administration_add_invoice(&active_invoice); current_view_state = view_state::LIST; + + ui_destroy_invoices(); + ui_setup_invoices(); } if (!can_save) ImGui::EndDisabled(); @@ -474,7 +618,14 @@ void ui_draw_invoices() { case view_state::LIST: draw_invoices_list(); break; case view_state::CREATE: ui_draw_invoice_create(); break; - case view_state::EDIT: break; - case view_state::VIEW: break; + case view_state::EDIT: ui_draw_invoice_update(); break; + case view_state::VIEW: + { + if (ImGui::Button(localize("form.back"))) { + current_view_state = view_state::LIST; + } + + draw_invoice_form(&active_invoice, true); + } break; } }
\ No newline at end of file |
