diff options
Diffstat (limited to 'src/administration.cpp')
| -rw-r--r-- | src/administration.cpp | 266 |
1 files changed, 247 insertions, 19 deletions
diff --git a/src/administration.cpp b/src/administration.cpp index e6c9821..0cca2b7 100644 --- a/src/administration.cpp +++ b/src/administration.cpp @@ -1,3 +1,5 @@ +#define _CRT_SECURE_NO_WARNINGS + #include <string.h> #include <stdlib.h> #include <assert.h> @@ -33,12 +35,12 @@ static int compare_tax_countries(const void *a, const void *b) return strcmp(objA->country_code, objB->country_code); } -static invoice_status administation_get_random_invoice_status() +static invoice_status administration_get_random_invoice_status() { return (invoice_status)(rand() % invoice_status::INVOICE_END); } -static void administation_get_random_project(char* project_id) +static void administration_get_random_project(char* project_id) { int size = list_size(&g_administration.projects); if (size > 0) { @@ -48,7 +50,7 @@ static void administation_get_random_project(char* project_id) } } -static void administation_get_random_cost_center(char* cost_center_id) +static void administration_get_random_cost_center(char* cost_center_id) { int size = list_size(&g_administration.cost_centers); if (size > 0) { @@ -58,7 +60,7 @@ static void administation_get_random_cost_center(char* cost_center_id) } } -static contact* administation_get_random_contact() +static contact* administration_get_random_contact() { int size = list_size(&g_administration.contacts); if (size > 0) { @@ -76,7 +78,7 @@ static time_t administration_get_default_invoice_expire_duration() static void administration_recalculate_billing_item_totals(billing_item* item); -static void administation_get_random_billing_items(invoice* inv) +static void administration_get_random_billing_items(invoice* inv) { int amount = 1 + rand() % 20; @@ -364,22 +366,22 @@ static void administration_create_debug_data() #define ADD_INVOICE(_outgoing)\ {\ invoice inv = administration_invoice_create_empty();\ - if (_outgoing) inv.supplier = administration_company_info_get(); else inv.supplier = *administation_get_random_contact();\ - if (_outgoing) inv.customer = *administation_get_random_contact(); else inv.customer = administration_company_info_get();\ - administation_get_random_project(inv.project_id);\ - administation_get_random_cost_center(inv.cost_center_id);\ + if (_outgoing) inv.supplier = administration_company_info_get(); else inv.supplier = *administration_get_random_contact();\ + if (_outgoing) inv.customer = *administration_get_random_contact(); else inv.customer = administration_company_info_get();\ + administration_get_random_project(inv.project_id);\ + if (!_outgoing) administration_get_random_cost_center(inv.cost_center_id);\ inv.is_outgoing = _outgoing;\ - inv.status = administation_get_random_invoice_status();\ + inv.status = administration_get_random_invoice_status();\ inv.issued_at = time(NULL) - (86400 * (rand() % 720));\ inv.delivered_at = inv.issued_at;\ inv.expires_at = inv.issued_at + administration_get_default_invoice_expire_duration();\ - administation_get_random_billing_items(&inv);\ + administration_get_random_billing_items(&inv);\ administration_invoice_add(&inv);\ } // Create about 2 years of random data. - for (int i = 0; i < 1; i++) { ADD_INVOICE(1); } - for (int i = 0; i < 1; i++) { ADD_INVOICE(0); } + for (int i = 0; i < 200; i++) { ADD_INVOICE(1); } + for (int i = 0; i < 200; i++) { ADD_INVOICE(0); } } static s32 administration_create_sequence_number() @@ -407,7 +409,9 @@ void administration_create() administration_create_debug_data(); - administration_writer_save_all_async(); + //administration_writer_save_all_async(); + income_statement* statement = (income_statement*)malloc(sizeof(income_statement)); + administration_create_income_statement(statement); } static void administration_destroy_list(list_t *list) @@ -430,8 +434,194 @@ void administration_destroy() administration_destroy_list(&g_administration.cost_centers); } -// General functions. +// Other functions. // ======================= +static void time_t_to_quarter(time_t time, u16* year, u8* quarter) +{ + struct tm *lt = localtime(&time); + //sprinf(buffer, "%dQ%d", lt->tm_mon / 3, lt->tm_year / 100); + *year = (u16)((1900+lt->tm_year) % 100); + *quarter = (u8)(lt->tm_mon / 3); +} + +static void administration_debug_print_income_statement(income_statement* statement) +{ + for (u32 i = 0; i < statement->quarter_count; i++) + { + quarterly_report report = statement->quarters[i]; + + printf("=== %dQ%d ===\n", report.quarter+1, report.year); + printf("general revenue: %.2f\n", report.uncategorized_revenue); + printf("general taxes: %.2f\n", report.uncategorized_taxes); + printf("general expenses: %.2f\n", report.uncategorized_expenses); + + for (u32 x = 0; x < report.report_count; x++) + { + project_report pr = report.reports[x]; + + project proj; + administration_project_get_by_id(&proj, pr.project_id); + printf("PROJECT: %s\n", proj.description); + printf(" revenue: %.2f\n", pr.revenue); + printf(" taxes: %.2f\n", pr.taxes); + printf(" expenses: %.2f\n", pr.expenses_total); + + for (u32 y = 0; y < pr.expense_count; y++) + { + project_expense expense = pr.expenses[y]; + + cost_center costcenter; + administration_cost_center_get_by_id(&costcenter, expense.cost_center_id); + printf(" %s: %.2f\n", costcenter.code, expense.total); + } + } + + printf("\n"); + } +} + +void administration_create_income_statement(income_statement* statement) +{ + assert(statement); + statement->quarter_count = 0; + + u32 invoice_count = administration_invoice_count(); + invoice* invoice_buffer = (invoice*)malloc(sizeof(invoice)*invoice_count); + invoice_count = administration_invoice_get_all(invoice_buffer); + + // Find oldest and youngest invoice. + time_t oldest = INT64_MAX; + time_t youngest = 0; + for (u32 i = 0; i < invoice_count; i++) + { + if (invoice_buffer[i].delivered_at < oldest) oldest = invoice_buffer[i].delivered_at; + if (invoice_buffer[i].delivered_at > youngest) youngest = invoice_buffer[i].delivered_at; + } + + u16 oldest_year; + u8 oldest_quarter; + time_t_to_quarter(oldest, &oldest_year, &oldest_quarter); + + u16 youngest_year; + u8 youngest_quarter; + time_t_to_quarter(youngest, &youngest_year, &youngest_quarter); + + u32 num_quarters = (youngest_quarter+1 + (youngest_year*4)) - (oldest_quarter + (oldest_year*4)); + assert(num_quarters <= MAX_LEN_INCOME_STATEMENT_REPORT_QUARTERS); + + // Generate quarters. + for (u32 i = 0; i < num_quarters; i++) + { + quarterly_report quarter; + quarter.year = oldest_year + (u16)((oldest_quarter+i) / 4); + quarter.quarter = (u8)((oldest_quarter + (i)) % 4); + quarter.uncategorized_expenses = 0.0f; + quarter.uncategorized_revenue = 0.0f; + quarter.uncategorized_taxes = 0.0f; + quarter.report_count = 0; + snprintf(quarter.quarter_str, MAX_LEN_SHORT_DESC, "%dQ%d", quarter.quarter+1, quarter.year); + + u32 project_count = administration_project_count(); + project* project_buffer = (project*)malloc(sizeof(project)*project_count); + project_count = administration_project_get_all(project_buffer); + assert(project_count <= MAX_LEN_QUARTERLY_REPORT_PROJECTS); + + u32 costcenter_count = administration_cost_center_count(); + cost_center* costcenter_buffer = (cost_center*)malloc(sizeof(cost_center)*costcenter_count); + costcenter_count = administration_cost_center_get_all(costcenter_buffer); + assert(costcenter_count <= MAX_LEN_PROJECT_REPORT_COSTCENTERS); + + for (u32 x = 0; x < project_count; x++) + { + project_report report; + report.expenses_total = 0.0f; + report.revenue = 0.0f; + report.taxes = 0.0f; + report.expense_count = 0; + strops_copy(report.project_id, project_buffer[x].id, MAX_LEN_ID); + strops_copy(report.description, project_buffer[x].description, MAX_LEN_LONG_DESC); + + for (u32 y = 0; y < costcenter_count; y++) + { + project_expense expense; + strops_copy(expense.cost_center_id, costcenter_buffer[y].id, MAX_LEN_ID); + strops_copy(expense.description, costcenter_buffer[y].description, MAX_LEN_LONG_DESC); + expense.total = 0.0f; + report.expenses[report.expense_count++] = expense; + } + + quarter.reports[quarter.report_count++] = report; + } + + statement->quarters[statement->quarter_count++] = quarter; + } + + // Fill quarters. + for (u32 i = 0; i < invoice_count; i++) + { + invoice* inv = &invoice_buffer[i]; + + u16 yy; + u8 qq; + time_t_to_quarter(inv->delivered_at, &yy, &qq); + + u32 report_index = (qq + (yy*4)) - (oldest_quarter + (oldest_year*4)); + + quarterly_report* quarter = &statement->quarters[report_index]; + assert(yy == quarter->year && qq == quarter->quarter); + + if (strcmp(inv->project_id, "") == 0) { + if (inv->is_outgoing) { + quarter->uncategorized_revenue += inv->total; + quarter->uncategorized_taxes += inv->tax; + } + else { + quarter->uncategorized_expenses += inv->total; + } + } + else { + int project_report_index = -1; + for (u32 x = 0; x < quarter->report_count; x++) + { + if (strcmp(quarter->reports[x].project_id, inv->project_id) == 0) { + project_report_index = x; + break; + } + } + assert(project_report_index != -1); + + project_report* report = &quarter->reports[project_report_index]; + + if (inv->is_outgoing) { + report->revenue += inv->total; + report->taxes += inv->tax; + } + else { + report->expenses_total += inv->total; + + if (strcmp(inv->cost_center_id, "") != 0) { + int expense_report_index = -1; + for (u32 x = 0; x < report->expense_count; x++) + { + if (strcmp(report->expenses[x].cost_center_id, inv->cost_center_id) == 0) { + expense_report_index = x; + break; + } + } + assert(expense_report_index != -1); + + project_expense* expense = &report->expenses[expense_report_index]; + expense->total += inv->total; + } + } + } + } + + //administration_debug_print_income_statement(statement); + + free(invoice_buffer); +} + char* administration_file_path_get() { return g_administration.path; @@ -447,7 +637,7 @@ void administration_company_info_set(contact data) g_administration.company_info = data; } -administration* administation_get() +administration* administration_get() { return &g_administration; } @@ -635,6 +825,25 @@ u32 administration_project_count() return list_size(&g_administration.projects); } +bool administration_project_get_by_id(project* buffer, char* id) +{ + assert(buffer); + + list_iterator_start(&g_administration.projects); + while (list_iterator_hasnext(&g_administration.projects)) { + project c = *(project *)list_iterator_next(&g_administration.projects); + if (strcmp(c.id, id) == 0) + { + *buffer = c; + list_iterator_stop(&g_administration.projects); + return true; + } + } + list_iterator_stop(&g_administration.projects); + + return false; +} + u32 administration_project_get_all(project* buffer) { u32 write_cursor = 0; @@ -853,6 +1062,25 @@ u32 administration_cost_center_count() return list_size(&g_administration.cost_centers); } +bool administration_cost_center_get_by_id(cost_center* buffer, char* id) +{ + assert(buffer); + + 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, id) == 0) + { + *buffer = c; + list_iterator_stop(&g_administration.cost_centers); + return true; + } + } + list_iterator_stop(&g_administration.cost_centers); + + return false; +} + u32 administration_cost_center_get_all(cost_center* buffer) { assert(buffer); @@ -1059,7 +1287,7 @@ bool administration_invoice_remove(invoice* inv) static void administration_invoice_set_refs(invoice* inv) { // This function makes sure that contact info referenced in the IDs actually - // matches the contact info stored in administation, if not we make new contacts. + // matches the contact info stored in administration, if not we make new contacts. // Check if supplier info is equal to contact stored in supplier id, in case we autocomplete and edit data after, // this should be handled as a new contact. @@ -1203,12 +1431,12 @@ u32 administration_invoice_count() return list_size(&g_administration.invoices); } -u32 administation_invoice_get_incomming_count() +u32 administration_invoice_get_incomming_count() { return g_administration.expense_count; } -u32 administation_invoice_get_outgoing_count() +u32 administration_invoice_get_outgoing_count() { return g_administration.invoice_count; } |
