diff options
| author | Aldrik Ramaekers <aldrikboy@gmail.com> | 2025-08-16 11:10:29 +0200 |
|---|---|---|
| committer | Aldrik Ramaekers <aldrikboy@gmail.com> | 2025-08-16 11:10:29 +0200 |
| commit | 05bc81cd42c5aeff7cfb6cf6b18f88792e7c16c9 (patch) | |
| tree | 7bc9c0439507b4531ed78578e441b12cba4dda4e /src/administration.cpp | |
| parent | f67e92f55b6223f2806c3d5ef1cbe2a638920562 (diff) | |
invoice form work
Diffstat (limited to 'src/administration.cpp')
| -rw-r--r-- | src/administration.cpp | 195 |
1 files changed, 188 insertions, 7 deletions
diff --git a/src/administration.cpp b/src/administration.cpp index 56d8663..2e16775 100644 --- a/src/administration.cpp +++ b/src/administration.cpp @@ -262,6 +262,12 @@ static void administration_create_debug_data() ADD_PROJECT("Retail store #1"); ADD_PROJECT("Retail store #2"); ADD_PROJECT("Kayak rental"); + + // Company info. + strops_copy(g_administration.company_info.name, "Aldrik Ramaekers", sizeof(g_administration.company_info.name)); + strops_copy(g_administration.company_info.address.address1, "Keerderstraat 81", sizeof(g_administration.company_info.address.address1)); + strops_copy(g_administration.company_info.address.address2, "6226XW Maastricht", sizeof(g_administration.company_info.address.address2)); + strops_copy(g_administration.company_info.address.country_code, "NL", sizeof(g_administration.company_info.address.country_code)); } void administration_create() @@ -269,11 +275,6 @@ void administration_create() g_administration.next_id = 1; g_administration.next_sequence_number = 1; - strops_copy(g_administration.company_info.name, "Aldrik Ramaekers", sizeof(g_administration.company_info.name)); - strops_copy(g_administration.company_info.address.address1, "Keerderstraat 81", sizeof(g_administration.company_info.address.address1)); - strops_copy(g_administration.company_info.address.address2, "6226XW Maastricht", sizeof(g_administration.company_info.address.address2)); - strops_copy(g_administration.company_info.address.country_code, "NL", sizeof(g_administration.company_info.address.country_code)); - list_init(&g_administration.contacts); list_init(&g_administration.projects); list_init(&g_administration.tax_brackets); @@ -408,6 +409,25 @@ u32 administration_get_project_count() return list_size(&g_administration.projects); } +u32 administration_get_billing_items_count(invoice* invoice) +{ + return list_size(&invoice->billing_items); +} + +u32 administration_get_all_billing_items_for_invoice(invoice* invoice, billing_item* buffer) +{ + u32 write_cursor = 0; + + list_iterator_start(&invoice->billing_items); + while (list_iterator_hasnext(&invoice->billing_items)) { + billing_item c = *(billing_item *)list_iterator_next(&invoice->billing_items); + buffer[write_cursor++] = c; + } + list_iterator_stop(&invoice->billing_items); + + return write_cursor; +} + u32 administration_get_all_projects(project* buffer) { u32 write_cursor = 0; @@ -543,6 +563,23 @@ bool administration_add_tax_bracket(country_tax_bracket data) return true; } +u32 administration_get_tax_brackets_for_country(country_tax_bracket* buffer, char* country_code) +{ + assert(buffer); + + u32 write_cursor = 0; + + list_iterator_start(&g_administration.tax_brackets); + while (list_iterator_hasnext(&g_administration.tax_brackets)) { + country_tax_bracket c = *(country_tax_bracket *)list_iterator_next(&g_administration.tax_brackets); + + if (strcmp(c.country_code, country_code) == 0 || strcmp(c.country_code, "00") == 0) buffer[write_cursor++] = c; + } + list_iterator_stop(&g_administration.tax_brackets); + + return write_cursor; +} + u32 administration_get_tax_brackets(country_tax_bracket* buffer) { assert(buffer); @@ -576,8 +613,6 @@ bool administration_update_tax_bracket(country_tax_bracket data) return false; } - - u32 administration_get_cost_center_count() { return list_size(&g_administration.cost_centers); @@ -689,6 +724,68 @@ static time_t administration_get_default_invoice_expire_duration() return (30 * 24 * 60 * 60); // 30 days } +billing_item administration_create_empty_billing_item() +{ + billing_item item; + memset(&item, 0, sizeof(billing_item)); + item.amount = 1; + return item; +} + +bool administration_add_billing_item_to_invoice(invoice* invoice, billing_item item) +{ + billing_item* tb = (billing_item*)malloc(sizeof(billing_item)); + memcpy(tb, &item, sizeof(billing_item)); + snprintf(tb->id, sizeof(tb->id), "B/%d", administration_create_id()); + strops_copy(tb->invoice_id, invoice->id, sizeof(tb->invoice_id)); + list_append(&invoice->billing_items, tb); + strops_copy(tb->currency, invoice->currency, CURRENCY_LENGTH); // Set billing item currency to invoice currency. + + g_administration.next_id++; + + return true; +} + +static char* administration_get_default_currency_for_country(char* country_code) +{ + if (country_code == NULL || strlen(country_code) != 2) + return "EUR"; // default + + // Non-euro EU currencies + if (strcmp(country_code, "BG") == 0) return "BGN"; // Bulgaria + else if (strcmp(country_code, "CZ") == 0) return "CZK"; // Czechia + else if (strcmp(country_code, "DK") == 0) return "DKK"; // Denmark + else if (strcmp(country_code, "HU") == 0) return "HUF"; // Hungary + else if (strcmp(country_code, "PL") == 0) return "PLN"; // Poland + else if (strcmp(country_code, "RO") == 0) return "RON"; // Romania + else if (strcmp(country_code, "SE") == 0) return "SEK"; // Sweden + + // Eurozone members + else if (strcmp(country_code, "AT") == 0) return "EUR"; // Austria + else if (strcmp(country_code, "BE") == 0) return "EUR"; // Belgium + else if (strcmp(country_code, "CY") == 0) return "EUR"; // Cyprus + else if (strcmp(country_code, "DE") == 0) return "EUR"; // Germany + else if (strcmp(country_code, "EE") == 0) return "EUR"; // Estonia + else if (strcmp(country_code, "ES") == 0) return "EUR"; // Spain + else if (strcmp(country_code, "FI") == 0) return "EUR"; // Finland + else if (strcmp(country_code, "FR") == 0) return "EUR"; // France + else if (strcmp(country_code, "GR") == 0) return "EUR"; // Greece + else if (strcmp(country_code, "HR") == 0) return "EUR"; // Croatia + else if (strcmp(country_code, "IE") == 0) return "EUR"; // Ireland + else if (strcmp(country_code, "IT") == 0) return "EUR"; // Italy + else if (strcmp(country_code, "LT") == 0) return "EUR"; // Lithuania + else if (strcmp(country_code, "LU") == 0) return "EUR"; // Luxembourg + else if (strcmp(country_code, "LV") == 0) return "EUR"; // Latvia + else if (strcmp(country_code, "MT") == 0) return "EUR"; // Malta + else if (strcmp(country_code, "NL") == 0) return "EUR"; // Netherlands + else if (strcmp(country_code, "PT") == 0) return "EUR"; // Portugal + else if (strcmp(country_code, "SI") == 0) return "EUR"; // Slovenia + else if (strcmp(country_code, "SK") == 0) return "EUR"; // Slovakia + + // Default fallback + return "EUR"; +} + invoice administration_create_empty_invoice() { invoice result; @@ -698,6 +795,8 @@ invoice administration_create_empty_invoice() result.issued_at = time(NULL); result.delivered_at = time(NULL); result.expires_at = time(NULL) + administration_get_default_invoice_expire_duration(); + list_init(&result.billing_items); // @leak + strops_copy(result.currency, administration_get_default_currency_for_country(g_administration.company_info.address.country_code), CURRENCY_LENGTH); return result; } @@ -715,4 +814,86 @@ project administration_create_empty_project() memset(&result, 0, sizeof(project)); snprintf(result.id, sizeof(result.id), "P/%d", administration_create_id()); return result; +} + +static bool administration_get_tax_bracket_by_id(country_tax_bracket* buffer, char* id) +{ + assert(buffer); + + list_iterator_start(&g_administration.tax_brackets); + while (list_iterator_hasnext(&g_administration.tax_brackets)) { + country_tax_bracket c = *(country_tax_bracket *)list_iterator_next(&g_administration.tax_brackets); + if (strcmp(c.id, id) == 0) + { + *buffer = c; + list_iterator_stop(&g_administration.tax_brackets); + return true; + } + } + list_iterator_stop(&g_administration.tax_brackets); + + return false; +} + +static void administration_recalculate_billing_item_totals(billing_item* item) +{ + if (item->amount_is_percentage) + { + item->net = item->net_per_item * (item->amount / 100.0f); + } + else + { + item->net = item->net_per_item * item->amount; + } + + if (item->discount != 0) + { + if (item->discount_is_percentage) + { + item->net -= item->net * (item->discount / 100.0f); + } + else + { + item->net -= item->discount; + } + } + + country_tax_bracket bracket; + if (administration_get_tax_bracket_by_id(&bracket, item->tax_bracket_id)) + { + item->tax = item->net * (bracket.rate/100.0f); + } + + item->total = item->net + item->tax; +} + +bool administration_update_billing_item_of_invoice(invoice* invoice, billing_item item) +{ + list_iterator_start(&invoice->billing_items); + while (list_iterator_hasnext(&invoice->billing_items)) { + billing_item* c = (billing_item *)list_iterator_next(&invoice->billing_items); + + if (strcmp(c->id, item.id) == 0) { + memcpy(c, &item, sizeof(billing_item)); + administration_recalculate_billing_item_totals(c); + list_iterator_stop(&invoice->billing_items); + return true; + } + } + list_iterator_stop(&invoice->billing_items); + + return false; +} + +void administration_invoice_set_currency(invoice* invoice, char* currency) +{ + strops_copy(invoice->currency, currency, CURRENCY_LENGTH); + + list_iterator_start(&invoice->billing_items); + while (list_iterator_hasnext(&invoice->billing_items)) { + billing_item* c = (billing_item *)list_iterator_next(&invoice->billing_items); + + strops_copy(c->currency, currency, CURRENCY_LENGTH); + } + list_iterator_stop(&invoice->billing_items); }
\ No newline at end of file |
