summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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
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);