summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/CHANGES.rst1
-rw-r--r--include/administration.hpp16
-rw-r--r--include/administration_reader.hpp9
-rw-r--r--include/file_templates.hpp15
-rw-r--r--include/strops.hpp3
-rw-r--r--src/administration.cpp67
-rw-r--r--src/administration_reader.cpp249
-rw-r--r--src/administration_writer.cpp2
-rw-r--r--src/locales/en.cpp2
-rw-r--r--src/strops.cpp5
-rw-r--r--src/ui/ui_contacts.cpp2
-rw-r--r--src/ui/ui_log.cpp2
-rw-r--r--src/ui/ui_main.cpp2
-rw-r--r--src/ui/ui_start.cpp4
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);