summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--docs/CHANGES.rst9
-rw-r--r--include/administration.hpp12
-rw-r--r--include/file_templates.hpp109
-rw-r--r--libs/ImGuiDatePicker/ImGuiDatePicker.cpp2
-rw-r--r--src/administration.cpp1
-rw-r--r--src/administration_writer.cpp65
-rw-r--r--src/ui/ui_settings.cpp2
8 files changed, 165 insertions, 38 deletions
diff --git a/.gitignore b/.gitignore
index 9fafbe8..b822716 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
imgui.ini
-build/* \ No newline at end of file
+build/*
+example.openbook \ No newline at end of file
diff --git a/docs/CHANGES.rst b/docs/CHANGES.rst
index 7c7ef64..e9881ec 100644
--- a/docs/CHANGES.rst
+++ b/docs/CHANGES.rst
@@ -9,8 +9,7 @@ TODO:
- read invoice from Holodeck instance
- send invoice via Holodeck instance
- View invoice history for contacts
-- View invoice history for projects
-- Create monthly and quarterly results (per project).
+- View invoice history for projects
- Create quarterly tax reports for NL.
- Make sure invoices/expenses cannot be added when company info is empty/invalid.
- net negative billing items should not also have discounts.
@@ -19,7 +18,9 @@ TODO:
- View local business number / vat number naming on contact form. e.g. when country is austria: "Österreichische Umsatzsteuer-Identifikationsnummer"
- add allowances to invoice items
- add accounting cost to invoice
-- if an invoice currency != default currency, final amount should be manually set as the total is always represented in the default currency.
+- outgoing invoices should always have default currency
+- if an incomming invoice currency != default currency, final amount should be manually set as the total is always represented in the default currency.
+- ICP reports
v0.1 (master)
@@ -31,5 +32,5 @@ v0.1 (master)
- Generate default VAT rates
- Generate default cost centers
- Reading & writing administration files
-- Archive invoices in Peppol BIS 3.0 format.
+- Archive invoices in Peppol BIS 3.0 format
- Quarterly income statement reports \ No newline at end of file
diff --git a/include/administration.hpp b/include/administration.hpp
index fe3d7b2..95d4622 100644
--- a/include/administration.hpp
+++ b/include/administration.hpp
@@ -109,18 +109,15 @@ typedef struct
float amount;
bool amount_is_percentage;
char description[MAX_LEN_LONG_DESC];
- float net_per_item;
+ float net_per_item; // Net per item before discount.
float discount;
bool discount_is_percentage;
float allowance; // Total discount.
- float net;
+ float net; // Total net, with discount.
char currency[MAX_LEN_CURRENCY]; // 3 letter code
char tax_bracket_id[MAX_LEN_ID]; // T/[id]
float tax;
float total;
-
- // TODO uninplemented
- char tax_section[MAX_LEN_TAX_SECTION];
} billing_item;
/**
@@ -257,11 +254,6 @@ typedef struct
invoice_status status;
bool is_outgoing; // Outgoing or incomming invoice.
payment_information payment_means;
-
- bool is_intra_community; // TODO uninplemented
- time_t payment_on_account_date; // TODO uninplemented
- char tax_representative[MAX_LEN_LONG_DESC]; // TODO uninplemented
- char corrected_sequential_number[MAX_LEN_ID]; // TODO uninplemented
// Used for forms, not stored on disk. Filled when retrieved.
contact supplier;
diff --git a/include/file_templates.hpp b/include/file_templates.hpp
index cb89050..af2f373 100644
--- a/include/file_templates.hpp
+++ b/include/file_templates.hpp
@@ -64,23 +64,37 @@ const char* peppol_invoice_tax_subtotal_template =
" </cac:TaxSubtotal>\n";
const char* peppol_invoice_line_template =
-" <cac:InvoiceLine>\n"
-" <cbc:ID>{{LINE_ID}}</cbc:ID>\n"
-" <cbc:InvoicedQuantity unitCode=\"{{UNIT_CODE}}\">{{QUANTITY}}</cbc:InvoicedQuantity>\n"
-" <cbc:LineExtensionAmount currencyID=\"{{CURRENCY}}\">{{LINE_AMOUNT}}</cbc:LineExtensionAmount>\n"
-" <cac:Item>\n"
-" <cbc:Name>{{ITEM_NAME}}</cbc:Name>\n"
-" <cac:ClassifiedTaxCategory>\n"
-" <cbc:ID>{{LINE_TAX_CATEGORY}}</cbc:ID>\n"
-" <cbc:Percent>{{LINE_TAX_PERCENT}}</cbc:Percent>\n"
-" <cac:TaxScheme>\n"
-" <cbc:ID>VAT</cbc:ID>\n"
-" </cac:TaxScheme>\n"
-" </cac:ClassifiedTaxCategory>\n"
-" </cac:Item>\n"
-" <cac:Price>\n"
-" <cbc:PriceAmount currencyID=\"{{CURRENCY}}\">{{UNIT_PRICE}}</cbc:PriceAmount>\n"
-" </cac:Price>\n"
+" <cac:InvoiceLine>\n"
+" <cbc:ID>{{LINE_ID}}</cbc:ID>\n"
+" <cbc:InvoicedQuantity unitCode=\"{{UNIT_CODE}}\">{{QUANTITY}}</cbc:InvoicedQuantity>\n"
+" <cbc:LineExtensionAmount currencyID=\"{{CURRENCY}}\">{{LINE_AMOUNT}}</cbc:LineExtensionAmount>\n"
+
+" <cac:OrderLineReference>\n"
+" <cbc:LineID>{{TAX_BRACKET_ID}}</cbc:LineID>\n"
+" </cac:OrderLineReference>\n"
+
+" <cac:AllowanceCharge>\n"
+" <cbc:ChargeIndicator>false</cbc:ChargeIndicator>\n"
+" <cbc:AllowanceChargeReason>Discount</cbc:AllowanceChargeReason>\n"
+" {{ALLOWANCE_IS_PERCENTAGE}}\n"
+" <cbc:Amount currencyID=\"{{CURRENCY}}\">{{DISCOUNT_TOTAL}}</cbc:Amount>\n"
+" <cbc:BaseAmount currencyID=\"{{CURRENCY}}\">{{DISCOUNT_BASE_AMOUNT}}</cbc:BaseAmount>\n"
+" </cac:AllowanceCharge>\n"
+
+" <cac:Item>\n"
+" <cbc:Name>{{ITEM_NAME}}</cbc:Name>\n"
+" <cac:ClassifiedTaxCategory>\n"
+" <cbc:ID>{{LINE_TAX_CATEGORY}}</cbc:ID>\n"
+" <cbc:Percent>{{LINE_TAX_PERCENT}}</cbc:Percent>\n"
+" <cac:TaxScheme>\n"
+" <cbc:ID>VAT</cbc:ID>\n"
+" </cac:TaxScheme>\n"
+" </cac:ClassifiedTaxCategory>\n"
+" </cac:Item>\n"
+
+" <cac:Price>\n"
+" <cbc:PriceAmount currencyID=\"{{CURRENCY}}\">{{UNIT_PRICE}}</cbc:PriceAmount>\n"
+" </cac:Price>\n"
" </cac:InvoiceLine>\n";
const char *peppol_invoice_template =
@@ -94,12 +108,25 @@ const char *peppol_invoice_template =
"\n"
" <cbc:ID>{{INVOICE_ID}}</cbc:ID>\n"
" <cbc:IssueDate>{{ISSUE_DATE}}</cbc:IssueDate>\n"
+" <cbc:DueDate>{{DUE_DATE}}</cbc:DueDate>\n"
" <cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode>\n"
" <cbc:DocumentCurrencyCode>{{CURRENCY}}</cbc:DocumentCurrencyCode>\n"
"\n"
+" <cac:AdditionalDocumentReference>\n"
+" <cbc:ID>{{INVOICE_DOCUMENT}}</cbc:ID>\n"
+" </cac:AdditionalDocumentReference>\n"
+"\n"
+" <cac:ProjectReference>\n"
+" <cbc:ID>{{PROJECT_ID}}</cbc:ID>\n"
+" </cac:ProjectReference>\n"
+" <cbc:AccountingCost>{{COST_CENTER_CODE}}</cbc:AccountingCost>\n"
+"\n"
" <cac:AccountingSupplierParty>\n"
" <cac:Party>\n"
" <cbc:EndpointID schemeID=\"{{SUPPLIER_ENDPOINT_SCHEME}}\">{{SUPPLIER_ENDPOINT_ID}}</cbc:EndpointID>\n"
+" <cac:PartyIdentification>\n"
+" <cbc:ID schemeID=\"ZZZ\">{{SUPPLIER_ID}}</cbc:ID>\n"
+" </cac:PartyIdentification>\n"
" <cac:PartyName>\n"
" <cbc:Name>{{SUPPLIER_NAME}}</cbc:Name>\n"
" </cac:PartyName>\n"
@@ -119,12 +146,27 @@ const char *peppol_invoice_template =
" <cbc:ID>VAT</cbc:ID>\n"
" </cac:TaxScheme>\n"
" </cac:PartyTaxScheme>\n"
+"\n"
+" <cac:PartyLegalEntity>\n"
+" <cbc:RegistrationName>{{SUPPLIER_LEGAL_NAME}}</cbc:RegistrationName>\n"
+" <cbc:CompanyID schemeID=\"ZZZ\">{{SUPPLIER_BUSINESS_ID}}</cbc:CompanyID>\n"
+" </cac:PartyLegalEntity>\n"
+"\n"
+" <cac:Contact>\n"
+" <cbc:Name>{{SUPPLIER_NAME}}</cbc:Name>\n"
+" <cbc:Telephone>{{SUPPLIER_PHONE_NUMBER}}</cbc:Telephone>\n"
+" <cbc:ElectronicMail>{{SUPPLIER_EMAIL}}</cbc:ElectronicMail>\n"
+" </cac:Contact>\n"
+"\n"
" </cac:Party>\n"
" </cac:AccountingSupplierParty>\n"
"\n"
" <cac:AccountingCustomerParty>\n"
" <cac:Party>\n"
" <cbc:EndpointID schemeID=\"{{CUSTOMER_ENDPOINT_SCHEME}}\">{{CUSTOMER_ENDPOINT_ID}}</cbc:EndpointID>\n"
+" <cac:PartyIdentification>\n"
+" <cbc:ID schemeID=\"ZZZ\">{{CUSTOMER_ID}}</cbc:ID>\n"
+" </cac:PartyIdentification>\n"
" <cac:PartyName>\n"
" <cbc:Name>{{CUSTOMER_NAME}}</cbc:Name>\n"
" </cac:PartyName>\n"
@@ -144,9 +186,42 @@ const char *peppol_invoice_template =
" <cbc:ID>VAT</cbc:ID>\n"
" </cac:TaxScheme>\n"
" </cac:PartyTaxScheme>\n"
+"\n"
+" <cac:PartyLegalEntity>\n"
+" <cbc:RegistrationName>{{CUSTOMER_LEGAL_NAME}}</cbc:RegistrationName>\n"
+" <cbc:CompanyID schemeID=\"ZZZ\">{{CUSTOMER_BUSINESS_ID}}</cbc:CompanyID>\n"
+" </cac:PartyLegalEntity>\n"
+"\n"
+" <cac:Contact>\n"
+" <cbc:Name>{{CUSTOMER_NAME}}</cbc:Name>\n"
+" <cbc:Telephone>{{CUSTOMER_PHONE_NUMBER}}</cbc:Telephone>\n"
+" <cbc:ElectronicMail>{{CUSTOMER_EMAIL}}</cbc:ElectronicMail>\n"
+" </cac:Contact>\n"
+"\n"
" </cac:Party>\n"
" </cac:AccountingCustomerParty>\n"
"\n"
+"<cac:Delivery>\n"
+" <cbc:ActualDeliveryDate>{{DELIVERY_DATE}}</cbc:ActualDeliveryDate>\n"
+" <cac:DeliveryLocation>\n"
+" <cac:Address>\n"
+" <cbc:StreetName>{{DELIVERY_STREET}}</cbc:StreetName>\n"
+" <cbc:AdditionalStreetName>{{DELIVERY_STREET2}}</cbc:AdditionalStreetName>\n"
+" <cbc:CityName>{{DELIVERY_CITY}}</cbc:CityName>\n"
+" <cbc:PostalZone>{{DELIVERY_POSTAL}}</cbc:PostalZone>\n"
+" <cbc:CountrySubentity>{{DELIVERY_REGION}}</cbc:CountrySubentity>\n"
+" <cac:Country>\n"
+" <cbc:IdentificationCode>{{DELIVERY_COUNTRY}}</cbc:IdentificationCode>\n"
+" </cac:Country>\n"
+" </cac:Address>\n"
+" </cac:DeliveryLocation>\n"
+" <cac:DeliveryParty>\n"
+" <cac:PartyName>\n"
+" <cbc:Name>{{DELIVERY_NAME}}</cbc:Name>\n"
+" </cac:PartyName>\n"
+" </cac:DeliveryParty>\n"
+"</cac:Delivery>\n"
+"\n"
" <cac:PaymentMeans>\n"
" <cbc:PaymentMeansCode>{{PAYMENT_TYPE}}</cbc:PaymentMeansCode>\n"
" <cbc:PaymentID>{{INVOICE_ID}}</cbc:PaymentID>\n"
diff --git a/libs/ImGuiDatePicker/ImGuiDatePicker.cpp b/libs/ImGuiDatePicker/ImGuiDatePicker.cpp
index 8c81b2b..207a902 100644
--- a/libs/ImGuiDatePicker/ImGuiDatePicker.cpp
+++ b/libs/ImGuiDatePicker/ImGuiDatePicker.cpp
@@ -361,7 +361,7 @@ namespace ImGui
if (Button(std::to_string(day).c_str(), ImVec2(GetContentRegionAvail().x, GetTextLineHeightWithSpacing() + 5.0f)))
{
- v = EncodeTimePoint(day, month, year);
+ v = EncodeTimePoint(day+1, month, year);
res = true;
CloseCurrentPopup();
}
diff --git a/src/administration.cpp b/src/administration.cpp
index 49b2559..2a18747 100644
--- a/src/administration.cpp
+++ b/src/administration.cpp
@@ -799,6 +799,7 @@ void administration_company_info_import(contact data)
void administration_company_info_set(contact data)
{
+ strops_copy(data.id, MY_COMPANY_ID, sizeof(data.id));
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);
diff --git a/src/administration_writer.cpp b/src/administration_writer.cpp
index f8b4302..779a5f1 100644
--- a/src/administration_writer.cpp
+++ b/src/administration_writer.cpp
@@ -229,7 +229,7 @@ bool administration_writer_save_invoice_blocking(invoice inv)
STOPWATCH_START;
bool result = 1;
- int buf_length = 150000; // Ballpark file content size.
+ int buf_length = 150000; // Ballpark file content size.
char* file_content = (char*)malloc(buf_length);
memset(file_content, 0, buf_length);
memcpy(file_content, peppol_invoice_template, strlen(peppol_invoice_template));
@@ -237,12 +237,31 @@ bool administration_writer_save_invoice_blocking(invoice inv)
struct tm *tm_info = 0;
char date_buffer[11]; // "YYYY-MM-DD" + null terminator
+ // properties not stored from invoice:
+ // - id (can be retrieved from filename)
+ // - invoice allowance (can be recalculated from billing items)
+
+ // properties not stored from supplier/customer/addressee:
+ // - type
+ // - bank account
+ // These can all be retrieved from existing contacts.
+
+ // properties not stored from billing item:
+ // - invoice_id (not necessary)
+ // - discount (can be recalculated from line_amount - (quantity * unit_price) )
+ // - tax (can be recalculated)
+ // - total (can be recalculated)
+
strops_replace(file_content, buf_length, "{{INVOICE_ID}}", inv.sequential_number);
strops_replace(file_content, buf_length, "{{CURRENCY}}", inv.currency);
+ strops_replace(file_content, buf_length, "{{PROJECT_ID}}", inv.project_id);
+ strops_replace(file_content, buf_length, "{{COST_CENTER_CODE}}", inv.cost_center_id);
+ strops_replace(file_content, buf_length, "{{INVOICE_DOCUMENT}}", inv.document);
// Supplier data
strops_replace(file_content, buf_length, "{{SUPPLIER_ENDPOINT_SCHEME}}", administration_writer_get_eas_scheme_for_address(inv.supplier.address));
strops_replace(file_content, buf_length, "{{SUPPLIER_ENDPOINT_ID}}", administration_writer_get_eas_id_for_contact(inv.supplier));
+ strops_replace(file_content, buf_length, "{{SUPPLIER_ID}}", inv.supplier.id);
strops_replace(file_content, buf_length, "{{SUPPLIER_NAME}}", inv.supplier.name);
strops_replace(file_content, buf_length, "{{SUPPLIER_STREET}}", inv.supplier.address.address1);
strops_replace(file_content, buf_length, "{{SUPPLIER_STREET2}}", inv.supplier.address.address2);
@@ -251,10 +270,15 @@ bool administration_writer_save_invoice_blocking(invoice inv)
strops_replace(file_content, buf_length, "{{SUPPLIER_REGION}}", inv.supplier.address.region);
strops_replace(file_content, buf_length, "{{SUPPLIER_COUNTRY}}", inv.supplier.address.country_code);
strops_replace(file_content, buf_length, "{{SUPPLIER_VAT_ID}}", inv.supplier.taxid);
+ strops_replace(file_content, buf_length, "{{SUPPLIER_LEGAL_NAME}}", inv.supplier.name);
+ strops_replace(file_content, buf_length, "{{SUPPLIER_BUSINESS_ID}}", inv.supplier.businessid);
+ strops_replace(file_content, buf_length, "{{SUPPLIER_PHONE_NUMBER}}", inv.supplier.phone_number);
+ strops_replace(file_content, buf_length, "{{SUPPLIER_EMAIL}}", inv.supplier.email);
// Customer data
strops_replace(file_content, buf_length, "{{CUSTOMER_ENDPOINT_SCHEME}}", administration_writer_get_eas_scheme_for_address(inv.customer.address));
strops_replace(file_content, buf_length, "{{CUSTOMER_ENDPOINT_ID}}", administration_writer_get_eas_id_for_contact(inv.customer));
+ strops_replace(file_content, buf_length, "{{CUSTOMER_ID}}", inv.customer.id);
strops_replace(file_content, buf_length, "{{CUSTOMER_NAME}}", inv.customer.name);
strops_replace(file_content, buf_length, "{{CUSTOMER_STREET}}", inv.customer.address.address1);
strops_replace(file_content, buf_length, "{{CUSTOMER_STREET2}}", inv.customer.address.address2);
@@ -263,6 +287,22 @@ bool administration_writer_save_invoice_blocking(invoice inv)
strops_replace(file_content, buf_length, "{{CUSTOMER_REGION}}", inv.customer.address.region);
strops_replace(file_content, buf_length, "{{CUSTOMER_COUNTRY}}", inv.customer.address.country_code);
strops_replace(file_content, buf_length, "{{CUSTOMER_VAT_ID}}", inv.customer.taxid);
+ strops_replace(file_content, buf_length, "{{CUSTOMER_LEGAL_NAME}}", inv.customer.name);
+ strops_replace(file_content, buf_length, "{{CUSTOMER_BUSINESS_ID}}", inv.customer.businessid);
+ strops_replace(file_content, buf_length, "{{CUSTOMER_PHONE_NUMBER}}", inv.customer.phone_number);
+ strops_replace(file_content, buf_length, "{{CUSTOMER_EMAIL}}", inv.customer.email);
+
+ // Delivery data
+ tm_info = localtime(&inv.delivered_at);
+ strftime(date_buffer, sizeof(date_buffer), "%Y-%m-%d", tm_info);
+ strops_replace(file_content, buf_length, "{{DELIVERY_DATE}}", date_buffer);
+ strops_replace(file_content, buf_length, "{{DELIVERY_NAME}}", inv.addressee.name);
+ strops_replace(file_content, buf_length, "{{DELIVERY_STREET}}", inv.addressee.address.address1);
+ strops_replace(file_content, buf_length, "{{DELIVERY_STREET2}}", inv.addressee.address.address2);
+ strops_replace(file_content, buf_length, "{{DELIVERY_CITY}}", inv.addressee.address.city);
+ strops_replace(file_content, buf_length, "{{DELIVERY_POSTAL}}", inv.addressee.address.postal);
+ strops_replace(file_content, buf_length, "{{DELIVERY_REGION}}", inv.addressee.address.region);
+ strops_replace(file_content, buf_length, "{{DELIVERY_COUNTRY}}", inv.addressee.address.country_code);
// Payment means
strops_replace_int32(file_content, buf_length, "{{PAYMENT_TYPE}}", inv.payment_means.payment_method);
@@ -270,7 +310,7 @@ bool administration_writer_save_invoice_blocking(invoice inv)
strops_replace(file_content, buf_length, "{{SUPPLIER_BIC}}", inv.payment_means.service_provider_id);
// Tax breakdown
- strops_replace_float(file_content, buf_length, "{{TOTAL_TAX_AMOUNT}}", inv.total, 2);
+ strops_replace_float(file_content, buf_length, "{{TOTAL_TAX_AMOUNT}}", inv.tax, 2);
{ // Create tax subtotal list.
country_tax_bracket* tax_bracket_buffer = (country_tax_bracket*)malloc(sizeof(country_tax_bracket)*administration_billing_item_count(&inv));
u32 tax_bracket_count = administration_invoice_get_tax_brackets(&inv, tax_bracket_buffer);
@@ -337,10 +377,23 @@ bool administration_writer_save_invoice_blocking(invoice inv)
strops_replace(billing_item_file_content, billing_item_buf_length, "{{ITEM_NAME}}", bi.description);
strops_replace(billing_item_file_content, billing_item_buf_length, "{{LINE_TAX_CATEGORY}}", bracket.category_code);
strops_replace_float(billing_item_file_content, billing_item_buf_length, "{{LINE_TAX_PERCENT}}", bracket.rate, 2);
- strops_replace_float(billing_item_file_content, billing_item_buf_length, "{{LINE_AMOUNT}}", bi.net, 2);
+ strops_replace_float(billing_item_file_content, billing_item_buf_length, "{{LINE_AMOUNT}}", bi.net, 2); // line amount = net_per_item * items_count - discount
strops_replace_float(billing_item_file_content, billing_item_buf_length, "{{QUANTITY}}", bi.amount, 2);
- strops_replace_float(billing_item_file_content, billing_item_buf_length, "{{UNIT_PRICE}}", bi.net_per_item, 2);
+ strops_replace_float(billing_item_file_content, billing_item_buf_length, "{{UNIT_PRICE}}", bi.net_per_item, 2); // unit price before discount
strops_replace(billing_item_file_content, billing_item_buf_length, "{{UNIT_CODE}}", bi.amount_is_percentage ? "%" : "X");
+ strops_replace(billing_item_file_content, billing_item_buf_length, "{{TAX_BRACKET_ID}}", bi.tax_bracket_id);
+
+ if (bi.discount_is_percentage) {
+ strops_replace(billing_item_file_content, billing_item_buf_length, "{{ALLOWANCE_IS_PERCENTAGE}}",
+ "<cbc:MultiplierFactorNumeric>{{DISCOUNT_TOTAL_PERCENTAGE}}</cbc:MultiplierFactorNumeric>");
+ strops_replace_float(billing_item_file_content, billing_item_buf_length, "{{DISCOUNT_TOTAL_PERCENTAGE}}", bi.allowance / (bi.net + bi.allowance), 2);
+ }
+ else {
+ strops_replace(billing_item_file_content, billing_item_buf_length, "{{ALLOWANCE_IS_PERCENTAGE}}", "");
+ }
+
+ strops_replace_float(billing_item_file_content, billing_item_buf_length, "{{DISCOUNT_TOTAL}}", bi.allowance, 2);
+ strops_replace_float(billing_item_file_content, billing_item_buf_length, "{{DISCOUNT_BASE_AMOUNT}}", bi.net + bi.allowance, 2); // Total net before discount.
u32 content_len = (u32)strlen(billing_item_file_content);
memcpy(billing_item_list_buffer+billing_item_list_buffer_cursor, billing_item_file_content, content_len);
@@ -360,6 +413,10 @@ bool administration_writer_save_invoice_blocking(invoice inv)
strftime(date_buffer, sizeof(date_buffer), "%Y-%m-%d", tm_info);
strops_replace(file_content, buf_length, "{{ISSUE_DATE}}", date_buffer);
+ tm_info = localtime(&inv.expires_at);
+ strftime(date_buffer, sizeof(date_buffer), "%Y-%m-%d", tm_info);
+ strops_replace(file_content, buf_length, "{{DUE_DATE}}", date_buffer);
+
//// Write to Disk.
char final_path[50];
snprintf(final_path, 50, "%s.xml", inv.id);
diff --git a/src/ui/ui_settings.cpp b/src/ui/ui_settings.cpp
index ae05b1a..dfe6b96 100644
--- a/src/ui/ui_settings.cpp
+++ b/src/ui/ui_settings.cpp
@@ -61,7 +61,7 @@ static void ui_draw_vat_rates()
country_tax_bracket c = tax_brackets[i];
// Set to false for shared rates.
- bool can_be_modified = true;
+ bool can_be_modified = false;
// Check for fixed rates shared accross countries.
if (strcmp(c.country_code, "00") == 0)