diff options
| author | Aldrik Ramaekers <aldrikboy@gmail.com> | 2025-09-13 12:40:22 +0200 |
|---|---|---|
| committer | Aldrik Ramaekers <aldrikboy@gmail.com> | 2025-09-13 12:40:22 +0200 |
| commit | d8a9d534a5a39fd3d51a6ffaf92fde39a4b4077c (patch) | |
| tree | eb15c2c464147b467417684fbaaebfd37da89bc3 | |
| parent | fb1ae39f1abe0dd0335489451e09a24e2336e606 (diff) | |
save file import: contact, project, tax brackets, cost centers, administration info
| -rw-r--r-- | docs/CHANGES.rst | 1 | ||||
| -rw-r--r-- | include/administration.hpp | 16 | ||||
| -rw-r--r-- | include/administration_reader.hpp | 9 | ||||
| -rw-r--r-- | include/file_templates.hpp | 15 | ||||
| -rw-r--r-- | include/strops.hpp | 3 | ||||
| -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 |
14 files changed, 352 insertions, 27 deletions
diff --git a/docs/CHANGES.rst b/docs/CHANGES.rst index d7ab498..7c7ef64 100644 --- a/docs/CHANGES.rst +++ b/docs/CHANGES.rst @@ -1,6 +1,7 @@ .. _changes: TODO: +- write tests for writer and reader - Send invoice by email - create invoice from PDF file - create invoice from image of receipt diff --git a/include/administration.hpp b/include/administration.hpp index b971e2c..fe3d7b2 100644 --- a/include/administration.hpp +++ b/include/administration.hpp @@ -25,6 +25,8 @@ #define MAX_LEN_PROJECT_REPORT_COSTCENTERS 50 #define MAX_BILLING_ITEMS 50 +#define MY_COMPANY_ID "C/1" + typedef struct { char id[MAX_LEN_ID]; // T/[id] @@ -63,7 +65,7 @@ typedef struct address address; contact_type type; char taxid[MAX_LEN_TAXID]; // Required for business contact - char businessid[MAX_LEN_TAXID]; // Required for business contact + char businessid[MAX_LEN_BUSINESSID]; // Required for business contact char email[MAX_LEN_EMAIL]; char phone_number[MAX_LEN_PHONE]; char bank_account[MAX_LEN_BANK]; @@ -308,6 +310,8 @@ typedef struct } income_statement; // Administration callback functions. +// These are called when adding/updating/deleting entries. +// These are NOT called when using import functions. typedef void (*data_changed_event)(); typedef void (*data_deleted_event)(char id[MAX_LEN_ID]); typedef void (*invoice_changed_event)(invoice* invoice); @@ -338,9 +342,10 @@ typedef struct // Setup functions. // ======================= -void administration_create(); -void administration_destroy(); +void administration_create(); // TODO remove and move into other setup functions +void administration_destroy(); // TODO remove and move into other setup functions void administration_create_empty(char* save_file); +void administration_create_from_file(char* save_file); // Callback functions. // ======================= @@ -357,6 +362,7 @@ void administration_set_project_changed_event_callback(project_changed_event administration* administration_get(); // TODO get rid of this and make indivual getters and setters char* administration_file_path_get(); contact administration_company_info_get(); +void administration_company_info_import(contact data); void administration_company_info_set(contact data); void administration_create_income_statement(income_statement* statement); char* administration_get_currency_symbol_from_currency(char* code); @@ -368,6 +374,7 @@ bool administration_has_save_path(); // ======================= u32 administration_contact_count(); contact administration_contact_create_empty(); +bool administration_contact_import(contact data); bool administration_contact_add(contact data); bool administration_contact_update(contact data); bool administration_contact_remove(contact data); @@ -385,6 +392,7 @@ u32 administration_contact_get_all(contact* buffer); // ======================= u32 administration_project_count(); project administration_project_create_empty(); +bool administration_project_import(project data); bool administration_project_add(project data); bool administration_project_update(project data); bool administration_project_remove(project data); @@ -400,6 +408,7 @@ bool administration_project_get_by_id(project* buffer, char* id); // Tax bracket functions. // ======================= u32 administration_tax_bracket_count(); +bool administration_tax_bracket_import(country_tax_bracket data); bool administration_tax_bracket_add(country_tax_bracket data); bool administration_tax_bracket_update(country_tax_bracket data); @@ -410,6 +419,7 @@ u32 administration_tax_bracket_get_by_country(country_tax_bracket* buffer, c // Cost center functions. // ======================= u32 administration_cost_center_count(); +bool administration_cost_center_import(cost_center data); bool administration_cost_center_add(cost_center data); bool administration_cost_center_update(cost_center data); diff --git a/include/administration_reader.hpp b/include/administration_reader.hpp index 528cc40..ed932bc 100644 --- a/include/administration_reader.hpp +++ b/include/administration_reader.hpp @@ -1,3 +1,10 @@ #pragma once -bool administration_reader_open_new();
\ No newline at end of file +bool administration_reader_open_new(); +bool administration_reader_open_existing(char* file_path); + +bool administration_reader_import_administration_info(char* buffer, size_t buffer_size); +bool administration_reader_import_tax_bracket(char* buffer, size_t buffer_size); +bool administration_reader_import_cost_center(char* buffer, size_t buffer_size); +bool administration_reader_import_project(char* buffer, size_t buffer_size); +bool administration_reader_import_contact(char* buffer, size_t buffer_size);
\ No newline at end of file diff --git a/include/file_templates.hpp b/include/file_templates.hpp index de3f509..cb89050 100644 --- a/include/file_templates.hpp +++ b/include/file_templates.hpp @@ -5,22 +5,22 @@ const char* project_save_template = " <State>{{PROJECT_STATE}}</State>\n" " <StartDate>{{PROJECT_STARTDATE}}</StartDate>\n" " <EndDate>{{PROJECT_ENDDATE}}</EndDate>\n" -"</Project>\n"; +"</Project>"; const char* costcenter_save_template = "<CostCenter>\n" " <Id>{{COSTCENTER_ID}}</Id>\n" " <Code>{{COSTCENTER_CODE}}</Code>\n" " <Description>{{COSTCENTER_DESCRIPTION}}</Description>\n" -"</CostCenter>\n"; +"</CostCenter>"; const char* taxbracket_save_template = "<CountryTaxBracket>\n" " <Id>{{TAXBRACKET_ID}}</Id>\n" " <CountryCode>{{TAXBRACKET_COUNTRY}}</CountryCode>\n" " <Rate>{{TAXBRACKET_RATE}}</Rate>\n" -" <Description>{{TAXBRACKET_CATEGORY}}</Description>\n" -"</CountryTaxBracket>\n"; +" <Category>{{TAXBRACKET_CATEGORY}}</Category>\n" +"</CountryTaxBracket>"; const char* contact_save_template = "<Contact>\n" @@ -40,14 +40,15 @@ const char* contact_save_template = " <Postal>{{CONTACT_POSTAL}}</Postal>\n" " <Region>{{CONTACT_REGION}}</Region>\n" " </Address>\n" -"</Contact>\n"; +"</Contact>"; const char* administration_save_template = "<Administration>\n" " <NextId>{{NEXT_ID}}</NextId>\n" +" <CompanyInfoId>{{COMPANY_ID}}</CompanyInfoId>\n" " <NextSequenceNumber>{{NEXT_SEQUENCE_NUMBER}}</NextSequenceNumber>\n" " <ProgramVersion>{{PROGRAM_VERSION}}</ProgramVersion>\n" -"</Administration>\n"; +"</Administration>"; const char* peppol_invoice_tax_subtotal_template = " <cac:TaxSubtotal>\n" @@ -173,4 +174,4 @@ const char *peppol_invoice_template = "\n" " {{INVOICE_LINE_LIST}}" "\n" -"</Invoice>\n"; +"</Invoice>"; diff --git a/include/strops.hpp b/include/strops.hpp index 2874c4d..412becc 100644 --- a/include/strops.hpp +++ b/include/strops.hpp @@ -6,4 +6,5 @@ char* strops_stristr(char* a, char* b); void strops_replace(char *buf, size_t buf_size, const char *search, const char *replace); void strops_replace_int32(char *buf, size_t buf_size, const char *search, int32_t number); void strops_replace_int64(char *buf, size_t buf_size, const char *search, int64_t number); -void strops_replace_float(char *buf, size_t buf_size, const char *search, float number, int decimals);
\ No newline at end of file +void strops_replace_float(char *buf, size_t buf_size, const char *search, float number, int decimals); +bool strops_prefix(const char *pre, const char *str);
\ No newline at end of file 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); |
