diff options
| author | Aldrik Ramaekers <aldrikboy@gmail.com> | 2025-09-17 11:00:25 +0200 |
|---|---|---|
| committer | Aldrik Ramaekers <aldrikboy@gmail.com> | 2025-09-17 11:00:25 +0200 |
| commit | 3a3fac243c013f3d211bb5141e18c82e62deacf9 (patch) | |
| tree | 16e9b62e05a6e63952572e984cb71889f914a264 | |
| parent | 885f413e9ae887979a59d0ca7238246429dd81ad (diff) | |
add tax rates of destination country as option for billing items
| -rw-r--r-- | docs/CHANGES.rst | 1 | ||||
| -rw-r--r-- | include/administration.hpp | 2 | ||||
| -rw-r--r-- | src/administration.cpp | 18 | ||||
| -rw-r--r-- | src/locales/en.cpp | 1 | ||||
| -rw-r--r-- | src/ui/ui_expenses.cpp | 156 | ||||
| -rw-r--r-- | src/ui/ui_invoices.cpp | 13 |
6 files changed, 29 insertions, 162 deletions
diff --git a/docs/CHANGES.rst b/docs/CHANGES.rst index 35f5a5b..6611e50 100644 --- a/docs/CHANGES.rst +++ b/docs/CHANGES.rst @@ -16,7 +16,6 @@ TODO: - net negative billing items should set tax to 0. - validate data within administration on save to make sure it is valid for transmissions. (e.g. rules of https://docs.peppol.eu/poacc/billing/3.0/syntax/ubl-invoice/cac-AccountingSupplierParty/cac-Party/cbc-EndpointID/) - View local business number / vat number naming on contact form. e.g. when country is austria: "Österreichische Umsatzsteuer-Identifikationsnummer" -- outgoing invoices should always have default currency - ICP reports v0.1 (master) diff --git a/include/administration.hpp b/include/administration.hpp index ad94c37..2d8908d 100644 --- a/include/administration.hpp +++ b/include/administration.hpp @@ -434,7 +434,7 @@ a_err administration_tax_rate_update(tax_rate data); a_err administration_tax_rate_get_by_id(tax_rate* buffer, char* id); u32 administration_tax_rate_get_all(tax_rate* buffer); -u32 administration_tax_rate_get_by_country(tax_rate* buffer, char* country_code); +u32 administration_tax_rate_get_by_country(tax_rate* buffer, u32 code_count, char** country_codes); // Cost center functions. // ======================= diff --git a/src/administration.cpp b/src/administration.cpp index ccbd284..404bd1e 100644 --- a/src/administration.cpp +++ b/src/administration.cpp @@ -109,7 +109,9 @@ static void administration_get_random_billing_items(invoice* inv) if (item.net < item.discount) item.discount = 0.0f; tax_rate buffer[20]; - u32 rate_count = administration_tax_rate_get_by_country(buffer, inv->supplier.address.country_code); + + char* country_codes[1] = {inv->supplier.address.country_code}; + u32 rate_count = administration_tax_rate_get_by_country(buffer, 1, country_codes); tax_rate rand_rate = buffer[rand() % rate_count]; strops_copy(item.tax_rate_id, rand_rate.id, MAX_LEN_ID); @@ -1303,7 +1305,7 @@ a_err administration_tax_rate_add(tax_rate data) return A_ERR_SUCCESS; } -u32 administration_tax_rate_get_by_country(tax_rate* buffer, char* country_code) +u32 administration_tax_rate_get_by_country(tax_rate* buffer, u32 code_count, char** country_codes) { assert(buffer); @@ -1313,7 +1315,17 @@ u32 administration_tax_rate_get_by_country(tax_rate* buffer, char* country_code) while (list_iterator_hasnext(&g_administration.tax_rates)) { tax_rate c = *(tax_rate *)list_iterator_next(&g_administration.tax_rates); - if (strcmp(c.country_code, country_code) == 0 || strcmp(c.country_code, "00") == 0) buffer[write_cursor++] = c; + if (strcmp(c.country_code, "00") == 0) { + buffer[write_cursor++] = c; + continue; + } + + for (u32 x = 0; x < code_count; x++) { + if (strcmp(c.country_code, country_codes[x]) == 0) { + buffer[write_cursor++] = c; + continue; + } + } } list_iterator_stop(&g_administration.tax_rates); diff --git a/src/locales/en.cpp b/src/locales/en.cpp index d70a282..cbb1d13 100644 --- a/src/locales/en.cpp +++ b/src/locales/en.cpp @@ -137,6 +137,7 @@ locale_entry en_locales[] = { {"invoice.form.expiresat", "Invoice expires at"}, {"invoice.form.deliveredat", "Product/service delivered at"}, {"invoice.form.billinginformation", "Billing information"}, + {"invoice.form.billedTo", "Billed to"}, {"invoice.form.triangulation", "Shipping information differs from billing information (triangulation)"}, {"invoice.form.shippinginformation", "Shipping information"}, {"invoice.form.add", "+ Billing item"}, diff --git a/src/ui/ui_expenses.cpp b/src/ui/ui_expenses.cpp index 75bd268..d1259a8 100644 --- a/src/ui/ui_expenses.cpp +++ b/src/ui/ui_expenses.cpp @@ -23,8 +23,9 @@ static billing_item* invoice_items_buffer = 0; void ui_draw_address_form(address* buffer); void draw_contact_form_ex(contact* buffer, bool viewing_only = false, bool with_autocomplete = false, bool* on_autocomplete = 0); -void draw_tax_rate_selector(char* tax_rate_id, tax_rate* buffer, char* country_code); +void draw_tax_rate_selector(char* tax_rate_id, tax_rate* buffer, char* orig_country, char* dest_country); bool draw_currency_selector(char* currency); +void draw_invoice_items_form(invoice* invoice, bool is_outgoing); void draw_costcenter_selector(char* costcenter_id, cost_center* buffer) { @@ -124,155 +125,6 @@ void ui_setup_expenses() invoice_items_buffer = (billing_item*)malloc(sizeof(billing_item) * invoice_items_count); } -static void draw_expense_items_form(invoice* invoice) -{ - billing_item* buffer = invoice_items_buffer; - u32 invoice_items = administration_billing_item_get_all_for_invoice(invoice, buffer); - - if (ImGui::BeginTable("TableBillingItems", 9, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) { - - ImGui::TableSetupColumn("##actions", ImGuiTableColumnFlags_WidthFixed, 20); - ImGui::TableSetupColumn(localize("invoice.table.amount"), ImGuiTableColumnFlags_WidthFixed, 80); - ImGui::TableSetupColumn(localize("invoice.table.description")); - ImGui::TableSetupColumn(localize("invoice.table.price"), ImGuiTableColumnFlags_WidthFixed, 100); - ImGui::TableSetupColumn(localize("invoice.table.discount"), ImGuiTableColumnFlags_WidthFixed, 100); - ImGui::TableSetupColumn(localize("invoice.table.net"), ImGuiTableColumnFlags_WidthFixed, 100); - ImGui::TableSetupColumn(localize("invoice.table.tax%"), ImGuiTableColumnFlags_WidthFixed, 120); - ImGui::TableSetupColumn(localize("invoice.table.tax"), ImGuiTableColumnFlags_WidthFixed, 100); - ImGui::TableSetupColumn(localize("invoice.table.total"), ImGuiTableColumnFlags_WidthFixed, 100); - - ImGui::TableHeadersRow(); - - for (u32 i = 0; i < invoice_items; i++) - { - billing_item item = buffer[i]; - - ImGui::TableNextRow(); - - ImGui::PushID(i); - - ImGui::TableSetColumnIndex(0); - if (ImGui::Button("X")) - { - administration_billing_item_remove_from_invoice(invoice, item); - } - - ImGui::TableSetColumnIndex(1); - ImGui::InputFloat("##amount", &item.amount, 0.0f, 0.0f, "%.0f"); - ImGui::SameLine(); - - // Toggle between X and % - { - const char* items[] = { "X", "%" }; - if (ImGui::BeginCombo("Mode", items[item.amount_is_percentage])) { - for (int n = 0; n < 2; n++) { - bool is_selected = (n == (int)item.amount_is_percentage); - if (ImGui::Selectable(items[n], is_selected)) { - item.amount_is_percentage = n; - } - if (is_selected) { - ImGui::SetItemDefaultFocus(); - } - } - ImGui::EndCombo(); - } - } - - ImGui::TableSetColumnIndex(2); - ImGui::PushItemWidth(-1); - ImGui::InputText("##desc", item.description, IM_ARRAYSIZE(item.description)); - ImGui::PopItemWidth(); - - ImGui::TableSetColumnIndex(3); - ImGui::PushItemWidth(-1); - ImGui::InputFloat("##price", &item.net_per_item, 0.0f, 0.0f, "%.2f"); - ImGui::PopItemWidth(); - - ImGui::TableSetColumnIndex(4); - ImGui::InputFloat("##discount", &item.discount, 0.0f, 0.0f, "%.2f"); - ImGui::SameLine(); - - // Toggle between currency and % - { - const char* items[] = { item.currency, "%" }; - if (ImGui::BeginCombo("Mode##discountMode", items[item.discount_is_percentage])) { - for (int n = 0; n < 2; n++) { - bool is_selected = (n == (int)item.discount_is_percentage); - if (ImGui::Selectable(items[n], is_selected)) { - item.discount_is_percentage = n; - } - if (is_selected) { - ImGui::SetItemDefaultFocus(); - } - } - ImGui::EndCombo(); - } - } - - ImGui::TableSetColumnIndex(5); - ImGui::Text("%.2f %s", item.net, item.currency); - - ImGui::TableSetColumnIndex(6); - ImGui::PushItemWidth(-1); - // TODO: should be country of invoice issuer - draw_tax_rate_selector(item.tax_rate_id, tax_rate_list_buffer, administration_company_info_get().address.country_code); - ImGui::PopItemWidth(); - - ImGui::TableSetColumnIndex(7); - ImGui::Text("%.2f %s", item.tax, item.currency); - - ImGui::TableSetColumnIndex(8); - ImGui::Text("%.2f %s", item.total, item.currency); - - ImGui::PopID(); - - administration_billing_item_update_in_invoice(invoice, item); - } - - ImGui::TableNextRow(); - ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0, IM_COL32(70, 70, 70, 255)); - - ImGui::TableSetColumnIndex(5); - ImGui::Text("%.2f %s", invoice->orig_net, invoice->currency); - - ImGui::TableSetColumnIndex(7); - ImGui::Text("%.2f %s", invoice->orig_tax, invoice->currency); - - ImGui::TableSetColumnIndex(8); - ImGui::Text("%.2f %s", invoice->orig_total, invoice->currency); - - if (strcmp(invoice->currency, administration_get_default_currency()) != 0) { - ImGui::TableNextRow(); - ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0, IM_COL32(50, 50, 50, 255)); - - ImGui::TableSetColumnIndex(2); - ImGui::Text("%s %s", localize("invoice.form.finalSettlement"), administration_get_default_currency()); - - ImGui::TableSetColumnIndex(4); - ImGui::InputFloat("##final_allowance", &invoice->allowance, 0.0f, 0.0f, "%.2f"); - ImGui::SameLine(); - ImGui::Text("%s", administration_get_default_currency()); - - ImGui::TableSetColumnIndex(5); - ImGui::InputFloat("##final_net", &invoice->net, 0.0f, 0.0f, "%.2f"); - ImGui::SameLine(); - ImGui::Text("%s", administration_get_default_currency()); - - ImGui::TableSetColumnIndex(7); - ImGui::InputFloat("##final_tax", &invoice->tax, 0.0f, 0.0f, "%.2f"); - ImGui::SameLine(); - ImGui::Text("%s", administration_get_default_currency()); - - ImGui::TableSetColumnIndex(8); - ImGui::InputFloat("##final_total", &invoice->total, 0.0f, 0.0f, "%.2f"); - ImGui::SameLine(); - ImGui::Text("%s", administration_get_default_currency()); - } - - ImGui::EndTable(); - } -} - static void draw_expense_form(invoice* buffer, bool viewing_only = false) { if (viewing_only) ImGui::BeginDisabled(); @@ -285,7 +137,7 @@ static void draw_expense_form(invoice* buffer, bool viewing_only = false) ImGui::Text("%s: %s", localize("invoice.form.invoicenumber"), buffer->sequential_number); // 3. Billed to (you) - ImGui::Text("%s: %s", localize("invoice.form.billinginformation"), buffer->customer.name); + ImGui::Text("%s: %s", localize("invoice.form.billedTo"), buffer->customer.name); // 4. Invoice issued at tm issued_at_date = *gmtime(&buffer->issued_at); @@ -360,7 +212,7 @@ static void draw_expense_form(invoice* buffer, bool viewing_only = false) } // 13. Invoice items form - draw_expense_items_form(buffer); + draw_invoice_items_form(buffer, false); if (viewing_only) ImGui::EndDisabled(); } diff --git a/src/ui/ui_invoices.cpp b/src/ui/ui_invoices.cpp index 6db7054..5ec9297 100644 --- a/src/ui/ui_invoices.cpp +++ b/src/ui/ui_invoices.cpp @@ -47,10 +47,11 @@ void ui_setup_invoices() project_list_buffer = (project*) malloc(sizeof(project) * project_count); } -void draw_tax_rate_selector(char* tax_rate_id, tax_rate* buffer, char* country_code) +void draw_tax_rate_selector(char* tax_rate_id, tax_rate* buffer, char* orig_country, char* dest_country) { tax_rate* selected_tax_rate = NULL; - u32 tax_rate_count = administration_tax_rate_get_by_country(buffer, country_code); + char* country_codes[2] = {orig_country, dest_country}; + u32 tax_rate_count = administration_tax_rate_get_by_country(buffer, 2, country_codes); // Select tax rate by given id. if (strlen(tax_rate_id) > 0) @@ -158,7 +159,7 @@ bool draw_currency_selector(char* currency) return result; } -static void draw_invoice_items_form(invoice* invoice) +void draw_invoice_items_form(invoice* invoice, bool is_outgoing) { billing_item* buffer = invoice_items_buffer; u32 invoice_items = administration_billing_item_get_all_for_invoice(invoice, buffer); @@ -248,7 +249,9 @@ static void draw_invoice_items_form(invoice* invoice) ImGui::TableSetColumnIndex(6); ImGui::PushItemWidth(-1); - draw_tax_rate_selector(item.tax_rate_id, tax_rate_list_buffer, administration_company_info_get().address.country_code); + draw_tax_rate_selector(item.tax_rate_id, tax_rate_list_buffer, + administration_company_info_get().address.country_code, + is_outgoing ? invoice->customer.address.country_code : invoice->supplier.address.country_code); ImGui::PopItemWidth(); ImGui::TableSetColumnIndex(7); @@ -390,7 +393,7 @@ static void draw_invoice_form(invoice* buffer, bool viewing_only = false) } // 13. Invoice items form - draw_invoice_items_form(buffer); + draw_invoice_items_form(buffer, true); if (viewing_only) ImGui::EndDisabled(); } |
