diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/administration.cpp | 67 | ||||
| -rw-r--r-- | src/administration_reader.cpp | 249 | ||||
| -rw-r--r-- | src/administration_writer.cpp | 2 | ||||
| -rw-r--r-- | src/locales/en.cpp | 2 | ||||
| -rw-r--r-- | src/strops.cpp | 5 | ||||
| -rw-r--r-- | src/ui/ui_contacts.cpp | 2 | ||||
| -rw-r--r-- | src/ui/ui_log.cpp | 2 | ||||
| -rw-r--r-- | src/ui/ui_main.cpp | 2 | ||||
| -rw-r--r-- | src/ui/ui_start.cpp | 4 |
9 files changed, 320 insertions, 15 deletions
diff --git a/src/administration.cpp b/src/administration.cpp index 1684442..49b2559 100644 --- a/src/administration.cpp +++ b/src/administration.cpp @@ -365,7 +365,7 @@ static void administration_create_debug_data() ADD_PROJECT("Kayak rental"); // Company info. - snprintf(g_administration.company_info.id, sizeof(g_administration.company_info.id), "C/%d", administration_create_id()); + snprintf(g_administration.company_info.id, sizeof(g_administration.company_info.id), "%s", MY_COMPANY_ID); 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, "", sizeof(g_administration.company_info.address.address2)); @@ -443,8 +443,17 @@ void administration_set_project_changed_event_callback(project_changed_event ev) // Setup functions. // ======================= +void administration_create_from_file(char* save_file) +{ + strops_copy(g_administration.path, save_file, sizeof(g_administration.path)); + strops_copy(g_administration.program_version, PROGRAM_VERSION, sizeof(g_administration.program_version)); +} + void administration_create_empty(char* save_file) { + g_administration.next_id = 2; + g_administration.next_sequence_number = 1; + strops_copy(g_administration.path, save_file, sizeof(g_administration.path)); strops_copy(g_administration.program_version, PROGRAM_VERSION, sizeof(g_administration.program_version)); administration_company_info_set(administration_contact_create_empty()); @@ -459,9 +468,6 @@ void administration_create() { STOPWATCH_START; - g_administration.next_id = 1; - g_administration.next_sequence_number = 1; - list_init(&g_administration.invoices); list_init(&g_administration.contacts); list_init(&g_administration.projects); @@ -592,6 +598,7 @@ void administration_create_income_statement(income_statement* statement) statement->quarter_count = 0; u32 invoice_count = administration_invoice_count(); + if (invoice_count == 0) return; invoice* invoice_buffer = (invoice*)malloc(sizeof(invoice)*invoice_count); invoice_count = administration_invoice_get_all(invoice_buffer); @@ -784,6 +791,12 @@ contact administration_company_info_get() return g_administration.company_info; } +void administration_company_info_import(contact data) +{ + g_administration.company_info = data; + strops_copy(g_administration.default_currency, administration_get_default_currency_for_country(g_administration.company_info.address.country_code), MAX_LEN_CURRENCY); +} + void administration_company_info_set(contact data) { g_administration.company_info = data; @@ -800,6 +813,21 @@ administration* administration_get() // Contact functions. // ======================= +bool administration_contact_import(contact data) +{ + if (strcmp(data.id, MY_COMPANY_ID) == 0) + { + administration_company_info_import(data); + return true; + } + + contact* new_contact = (contact*)malloc(sizeof(contact)); + memcpy((void*)new_contact, (void*)&data, sizeof(contact)); + list_append(&g_administration.contacts, new_contact); + + return true; +} + bool administration_contact_add(contact data) { if (!administration_contact_is_valid(data)) return false; @@ -1070,6 +1098,15 @@ char* administration_project_get_status_string(project data) return ""; } +bool administration_project_import(project data) +{ + project* new_project = (project*)malloc(sizeof(project)); + memcpy((void*)new_project, (void*)&data, sizeof(project)); + list_append(&g_administration.projects, new_project); + + return true; +} + bool administration_project_add(project data) { if (!administration_project_is_valid(data)) return false; @@ -1173,12 +1210,26 @@ u32 administration_tax_bracket_count() return list_size(&g_administration.tax_brackets); } +bool administration_tax_bracket_import(country_tax_bracket data) +{ + country_tax_bracket* tb = (country_tax_bracket*)malloc(sizeof(country_tax_bracket)); + memcpy((void*)tb, (void*)&data, sizeof(country_tax_bracket)); + + list_append(&g_administration.tax_brackets, tb); + + list_attributes_comparator(&g_administration.tax_brackets, compare_tax_countries); + list_sort(&g_administration.tax_brackets, -1); + return true; +} + bool administration_tax_bracket_add(country_tax_bracket data) { country_tax_bracket* tb = (country_tax_bracket*)malloc(sizeof(country_tax_bracket)); memcpy((void*)tb, (void*)&data, sizeof(country_tax_bracket)); snprintf(tb->id, sizeof(tb->id), "T/%d", administration_create_id()); + list_append(&g_administration.tax_brackets, tb); + g_administration.next_id++; list_attributes_comparator(&g_administration.tax_brackets, compare_tax_countries); @@ -1317,6 +1368,14 @@ bool administration_cost_center_verify_code(char* code) return !found; } +bool administration_cost_center_import(cost_center data) +{ + cost_center* tb = (cost_center*)malloc(sizeof(cost_center)); + memcpy(tb, &data, sizeof(cost_center)); + list_append(&g_administration.cost_centers, tb); + return true; +} + bool administration_cost_center_add(cost_center data) { cost_center cs; diff --git a/src/administration_reader.cpp b/src/administration_reader.cpp index 150c045..b3caeac 100644 --- a/src/administration_reader.cpp +++ b/src/administration_reader.cpp @@ -1,11 +1,12 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> #include <zip.h> #include <xml.h> -#include <stdlib.h> -#include <threads.h> #include "log.hpp" -#include "ui.hpp" #include "strops.hpp" +#include "administration_reader.hpp" #include "administration_writer.hpp" #include "tinyfiledialogs.h" @@ -19,9 +20,245 @@ bool administration_reader_open_new() administration_create_empty(save_path); - //administration_writer_save_all_cost_centers_blocking(); - //administration_writer_save_all_tax_brackets_blocking(); - //administration_writer_save_all_administration_info_blocking(); + return true; +} + +bool administration_reader_open_existing(char* file_path) +{ + if (file_path == NULL) { + // @localize + char const * lFilterPatterns[1] = { "*.openbook" }; + file_path = tinyfd_openFileDialog("Select save file", NULL, 1, lFilterPatterns, NULL, 0); + + if (!file_path) return false; + } + + STOPWATCH_START; + + administration_create_from_file(file_path); + + zip_t* zip = zip_open(file_path, 0, 'r'); + + size_t i, n = zip_entries_total(zip); + for (i = 0; i < n; ++i) { + zip_entry_openbyindex(zip, i); + { + const char *name = zip_entry_name(zip); + int isdir = zip_entry_isdir(zip); + if (isdir) continue; + unsigned long long size = zip_entry_size(zip); + + char* buffer = (char*)malloc(size+1); + memset(buffer, 0, size+1); + zip_entry_read(zip, (void**)&buffer, (size_t*)&size); + + if (strlen(name) == 0) continue; + + if (strcmp(name, ADMIN_FILE_INFO) == 0) + { + administration_reader_import_administration_info(buffer, (size_t)size); + } + else if (strops_prefix("T/", name)) + { + administration_reader_import_tax_bracket(buffer, (size_t)size); + } + else if (strops_prefix("E/", name)) + { + administration_reader_import_cost_center(buffer, (size_t)size); + } + else if (strops_prefix("P/", name)) + { + administration_reader_import_project(buffer, (size_t)size); + } + else if (strops_prefix("C/", name)) + { + administration_reader_import_contact(buffer, (size_t)size); + } + + free(buffer); + } + zip_entry_close(zip); + } + + zip_close(zip); + + log_add("Imported '%s' in %.3fms.", file_path, STOPWATCH_TIME); return true; } + +static s64 _get_xml_s64(xml_node* root, char* child_name) +{ + struct xml_node* node = xml_easy_child(root, (uint8_t *)child_name, 0); + + char xml_content[512]; + memset(xml_content, 0, 512); + struct xml_string* str = xml_node_content(node); + xml_string_copy(str, (uint8_t *)xml_content, xml_string_length(str)); + + char *endptr; + long long val = strtoll(xml_content, &endptr, 10); + + s64 num = (int64_t) val; + return num; +} + +static s32 _get_xml_s32(xml_node* root, char* child_name) +{ + struct xml_node* node = xml_easy_child(root, (uint8_t *)child_name, 0); + + char xml_content[512]; + memset(xml_content, 0, 512); + struct xml_string* str = xml_node_content(node); + xml_string_copy(str, (uint8_t *)xml_content, xml_string_length(str)); + + char *endptr; + long val = strtol(xml_content, &endptr, 10); + + s32 num = (int32_t) val; + return num; +} + +static float _get_xml_float(xml_node* root, char* child_name) +{ + struct xml_node* node = xml_easy_child(root, (uint8_t *)child_name, 0); + + char xml_content[512]; + memset(xml_content, 0, 512); + struct xml_string* str = xml_node_content(node); + xml_string_copy(str, (uint8_t *)xml_content, xml_string_length(str)); + + char *endptr; + float val = strtof(xml_content, &endptr); + return val; +} + +static char* _get_xml_str(xml_node* root, char* buffer, size_t bufsize, char* child_name) +{ + struct xml_node* node = xml_easy_child(root, (uint8_t *)child_name, 0); + + memset(buffer, 0, bufsize); + struct xml_string* str = xml_node_content(node); + xml_string_copy(str, (uint8_t *)buffer, xml_string_length(str)); + + return buffer; +} + +bool administration_reader_import_contact(char* buffer, size_t buffer_size) +{ + STOPWATCH_START; + + xml_document* document = xml_parse_document((uint8_t *)buffer, buffer_size); + if (!document) return false; + + struct xml_node* root = xml_document_root(document); + + contact data; + _get_xml_str(root, data.id, MAX_LEN_ID, "Id"); + _get_xml_str(root, data.name, MAX_LEN_LONG_DESC, "Name"); + data.type = (contact_type)_get_xml_s32(root, "Type"); + _get_xml_str(root, data.taxid, MAX_LEN_TAXID, "TaxId"); + _get_xml_str(root, data.businessid, MAX_LEN_BUSINESSID, "BusinessId"); + _get_xml_str(root, data.email, MAX_LEN_EMAIL, "Email"); + _get_xml_str(root, data.phone_number, MAX_LEN_PHONE, "PhoneNumber"); + _get_xml_str(root, data.bank_account, MAX_LEN_BANK, "BankAccount"); + + struct xml_node* node_address = xml_easy_child(root, (uint8_t *)"Address", 0); + _get_xml_str(node_address, data.address.address1, MAX_LEN_ADDRESS, "AddressLine1"); + _get_xml_str(node_address, data.address.address2, MAX_LEN_ADDRESS, "AddressLine2"); + _get_xml_str(node_address, data.address.country_code, MAX_LEN_COUNTRY_CODE, "CountryCode"); + _get_xml_str(node_address, data.address.city, MAX_LEN_ADDRESS, "City"); + _get_xml_str(node_address, data.address.postal, MAX_LEN_ADDRESS, "Postal"); + _get_xml_str(node_address, data.address.region, MAX_LEN_ADDRESS, "Region"); + + bool result = administration_contact_import(data); + log_add("Loaded contact '%s' in %.3fms.", data.name, STOPWATCH_TIME); + + return result; +} + +bool administration_reader_import_project(char* buffer, size_t buffer_size) +{ + STOPWATCH_START; + + xml_document* document = xml_parse_document((uint8_t *)buffer, buffer_size); + if (!document) return false; + + struct xml_node* root = xml_document_root(document); + + project data; + _get_xml_str(root, data.id, MAX_LEN_ID, "Id"); + _get_xml_str(root, data.description, MAX_LEN_LONG_DESC, "Description"); + data.state = (project_state)_get_xml_s32(root, "State"); + data.start_date = _get_xml_s64(root, "StartDate"); + data.end_date = _get_xml_s64(root, "EndDate"); + + bool result = administration_project_import(data); + log_add("Loaded project in %.3fms. id=%s description=%s state=%d started=%lld end=%lld", + STOPWATCH_TIME, data.id, data.description, data.state, data.start_date, data.end_date); + + return result; +} + +bool administration_reader_import_cost_center(char* buffer, size_t buffer_size) +{ + STOPWATCH_START; + + xml_document* document = xml_parse_document((uint8_t *)buffer, buffer_size); + if (!document) return false; + + struct xml_node* root = xml_document_root(document); + + cost_center data; + _get_xml_str(root, data.id, MAX_LEN_ID, "Id"); + _get_xml_str(root, data.code, MAX_LEN_CODE, "Code"); + _get_xml_str(root, data.description, MAX_LEN_LONG_DESC, "Description"); + + bool result = administration_cost_center_import(data); + log_add("Loaded cost center in %.3fms. id=%s code=%s description=%s", + STOPWATCH_TIME, data.id, data.code, data.description); + + return result; +} + +bool administration_reader_import_tax_bracket(char* buffer, size_t buffer_size) +{ + STOPWATCH_START; + + xml_document* document = xml_parse_document((uint8_t *)buffer, buffer_size); + if (!document) return false; + + struct xml_node* root = xml_document_root(document); + + country_tax_bracket data; + _get_xml_str(root, data.id, MAX_LEN_ID, "Id"); + _get_xml_str(root, data.country_code, MAX_LEN_COUNTRY_CODE, "CountryCode"); + _get_xml_str(root, data.category_code, MAX_LEN_CODE, "Category"); + data.rate = _get_xml_float(root, "Rate"); + + bool result = administration_tax_bracket_import(data); + log_add("Loaded tax bracket info in %.3fms. id=%s country_code=%s category_code=%s rate=%.2f", + STOPWATCH_TIME, data.id, data.country_code, data.category_code, data.rate); + + return result; +} + +bool administration_reader_import_administration_info(char* buffer, size_t buffer_size) +{ + STOPWATCH_START; + + xml_document* document = xml_parse_document((uint8_t *)buffer, buffer_size); + if (!document) return false; + + struct xml_node* root = xml_document_root(document); + + administration* ad = administration_get(); + ad->next_id = _get_xml_s32(root, "NextId"); + ad->next_sequence_number = _get_xml_s32(root, "NextSequenceNumber"); + _get_xml_str(root, ad->company_info.id, MAX_LEN_ID, "CompanyInfoId"); + + log_add("Loaded administration info in %.3fms. next_id=%d next_sequence_number=%d company_id=%s", + STOPWATCH_TIME, ad->next_id, ad->next_sequence_number, ad->company_info.id); + + return true; +}
\ No newline at end of file diff --git a/src/administration_writer.cpp b/src/administration_writer.cpp index 70a18bc..f8b4302 100644 --- a/src/administration_writer.cpp +++ b/src/administration_writer.cpp @@ -8,6 +8,7 @@ #include "log.hpp" #include "ui.hpp" #include "strops.hpp" +#include "administration_reader.hpp" #include "administration_writer.hpp" #include "tinyfiledialogs.h" #include "file_templates.hpp" @@ -606,6 +607,7 @@ bool administration_writer_save_all_administration_info_blocking() int buf_length = 0; char* file_content = administration_writer_copy_template(administration_save_template, &buf_length); + strops_replace(file_content, buf_length, "{{COMPANY_ID}}", administration_company_info_get().id); strops_replace_int32(file_content, buf_length, "{{NEXT_ID}}", administration_get()->next_id); strops_replace_int32(file_content, buf_length, "{{NEXT_SEQUENCE_NUMBER}}", administration_get()->next_sequence_number); strops_replace(file_content, buf_length, "{{PROGRAM_VERSION}}", administration_get()->program_version); diff --git a/src/locales/en.cpp b/src/locales/en.cpp index 7b0821a..a5309a3 100644 --- a/src/locales/en.cpp +++ b/src/locales/en.cpp @@ -92,7 +92,7 @@ locale_entry en_locales[] = { {"contact.form.identifier", "Identifier"}, {"contact.form.fullname", "Full name / name of business"}, {"contact.form.address1", "Street name + house number, appt. number, etc."}, - {"contact.form.address2", "Zip, city"}, + {"contact.form.address2", "Address line 2"}, {"contact.form.country", "Country"}, {"contact.form.type", "Customer type"}, {"contact.form.type.business", "Business"}, diff --git a/src/strops.cpp b/src/strops.cpp index 208aaed..6179f82 100644 --- a/src/strops.cpp +++ b/src/strops.cpp @@ -4,6 +4,11 @@ #include "strops.hpp" +bool strops_prefix(const char *pre, const char *str) +{ + return strncmp(pre, str, strlen(pre)) == 0; +} + size_t strops_copy(char *dst, const char *src, size_t size) { size_t srclen; diff --git a/src/ui/ui_contacts.cpp b/src/ui/ui_contacts.cpp index ed770d9..e7afd7a 100644 --- a/src/ui/ui_contacts.cpp +++ b/src/ui/ui_contacts.cpp @@ -28,7 +28,7 @@ void ui_draw_address_form(address* buffer) ImGui::SetNextItemWidth(widthAvailable*0.5f); snprintf(id, sizeof(id), "%s##%p", localize("contact.form.address2"), buffer); ImGui::InputTextWithHint(id, localize("contact.form.address2"), buffer->address2, IM_ARRAYSIZE(buffer->address2)); - ImGui::SameLine();ui_helper_draw_required_tag(); + //ImGui::SameLine();ui_helper_draw_required_tag(); ImGui::SetNextItemWidth(widthAvailable*0.5f); snprintf(id, sizeof(id), "%s##%p", localize("contact.form.city"), buffer); diff --git a/src/ui/ui_log.cpp b/src/ui/ui_log.cpp index 08a0a72..4943548 100644 --- a/src/ui/ui_log.cpp +++ b/src/ui/ui_log.cpp @@ -11,7 +11,7 @@ void ui_draw_log() for (int i = (int)l->history_length-1; i >= 0; i--) { - u32 cursor = l->write_cursor - l->history_length + i; + s32 cursor = l->write_cursor - l->history_length + i; if (cursor < 0) { cursor = (l->write_cursor + i) % MAX_LEN_LOG_HISTORY; } diff --git a/src/ui/ui_main.cpp b/src/ui/ui_main.cpp index b245d88..59c4156 100644 --- a/src/ui/ui_main.cpp +++ b/src/ui/ui_main.cpp @@ -60,7 +60,7 @@ void ui_draw_main() if (ImGui::BeginMenu("File")) { if (ImGui::MenuItem("New")) { administration_reader_open_new(); } - if (ImGui::MenuItem("Open")) { /* Handle Save */ } + if (ImGui::MenuItem("Open")) { administration_reader_open_existing(NULL); } ImGui::EndMenu(); } diff --git a/src/ui/ui_start.cpp b/src/ui/ui_start.cpp index dd7b54d..90326f5 100644 --- a/src/ui/ui_start.cpp +++ b/src/ui/ui_start.cpp @@ -22,7 +22,9 @@ void ui_draw_start() ImGui::NextColumn(); if (ImGui::Button("Load", buttonSize)) { - + if (administration_reader_open_existing(NULL)) { + ui_set_state(main_state::UI_INVOICES); + } } ImGui::Columns(1); |
