/* * Copyright (c) 2025 Aldrik Ramaekers * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include "countries.hpp" #include "strops.hpp" time_t _nl_get_default_invoice_expire_duration() { return (15 * 24 * 60 * 60); // 15 days } void _nl_fill_tax_report_with_categories(tax_report* report) { report->lines[report->line_count++] = tax_line {"taxes.nl.1", "", 0.0f, 0.0f, false, false}; report->lines[report->line_count++] = tax_line {"taxes.nl.1a", "1a", 0.0f, 0.0f, true, true}; report->lines[report->line_count++] = tax_line {"taxes.nl.1b", "1b", 0.0f, 0.0f, true, true}; report->lines[report->line_count++] = tax_line {"taxes.nl.1c", "1c", 0.0f, 0.0f, true, true}; report->lines[report->line_count++] = tax_line {"taxes.nl.1d", "1d", 0.0f, 0.0f, true, true}; report->lines[report->line_count++] = tax_line {"taxes.nl.1e", "1e", 0.0f, 0.0f, true, false}; report->lines[report->line_count++] = tax_line {"taxes.nl.2", "", 0.0f, 0.0f, false, false}; report->lines[report->line_count++] = tax_line {"taxes.nl.2a", "2a", 0.0f, 0.0f, true, true}; report->lines[report->line_count++] = tax_line {"taxes.nl.3", "", 0.0f, 0.0f, false, false}; report->lines[report->line_count++] = tax_line {"taxes.nl.3a", "3a", 0.0f, 0.0f, true, false}; report->lines[report->line_count++] = tax_line {"taxes.nl.3b", "3b", 0.0f, 0.0f, true, false}; report->lines[report->line_count++] = tax_line {"taxes.nl.3c", "3c", 0.0f, 0.0f, true, false}; report->lines[report->line_count++] = tax_line {"taxes.nl.4", "", 0.0f, 0.0f, false, false}; report->lines[report->line_count++] = tax_line {"taxes.nl.4a", "4a", 0.0f, 0.0f, true, true}; report->lines[report->line_count++] = tax_line {"taxes.nl.4b", "4b", 0.0f, 0.0f, true, true}; report->lines[report->line_count++] = tax_line {"taxes.nl.5", "", 0.0f, 0.0f, false, false}; report->lines[report->line_count++] = tax_line {"taxes.nl.5a", "5a", 0.0f, 0.0f, false, true}; report->lines[report->line_count++] = tax_line {"taxes.nl.5b", "5b", 0.0f, 0.0f, false, true}; report->lines[report->line_count++] = tax_line {"taxes.total", "5c", 0.0f, 0.0f, false, true}; } bool _nl_add_billing_item_to_tax_report(tax_report* report, invoice* inv, billing_item* item) { // https://goedestartbelastingdienst.nl/wiki/view/7494ecb4-f6d2-4f85-a200-5a3ee5d45b75/btw-aangifte-het-invullen-van-de-verschillende-rubrieken tax_rate rate; a_err err = administration::tax_rate_get_by_id(&rate, item->tax_rate_id); if (err != A_ERR_SUCCESS) return 0; tax_subtotal totals = administration::billing_item_convert_to_default_currency(inv, *item); if (inv->is_outgoing) { tax_line* a5 = administration::get_tax_line_from_report(report, "5a"); // Total owed. if (strops::equals(inv->customer.address.country_code, "NL")) { if (rate.rate == 21.0f) { tax_line* tl = administration::get_tax_line_from_report(report, "1a"); tl->total_net += totals.net; tl->total_tax += totals.tax; a5->total_tax += totals.tax; } else if (rate.rate == 9.0f) { tax_line* tl = administration::get_tax_line_from_report(report, "1b"); tl->total_net += totals.net; tl->total_tax += totals.tax; a5->total_tax += totals.tax; } // TODO 1c else if (rate.rate > 0.0f) { tax_line* tl = administration::get_tax_line_from_report(report, "1d"); tl->total_net += totals.net; tl->total_tax += totals.tax; a5->total_tax += totals.tax; } else if (rate.rate == 0.0f) { tax_line* tl = administration::get_tax_line_from_report(report, "1e"); tl->total_net += totals.net; tl->total_tax += totals.tax; a5->total_tax += totals.tax; } } else if (!country::is_EU(inv->customer.address.country_code)) { tax_line* tl = administration::get_tax_line_from_report(report, "3a"); tl->total_net += totals.net; // Tax is paid to country of customer. } else { tax_line* tl = administration::get_tax_line_from_report(report, "3b"); tl->total_net += totals.net; // Tax is paid to country of customer. } // TODO 3c } else { tax_line* a5 = administration::get_tax_line_from_report(report, "5a"); // Total owed. tax_line* b5 = administration::get_tax_line_from_report(report, "5b"); // Input tax. if (strops::equals(inv->supplier.address.country_code, "NL")) { if (strops::equals(rate.category_code, "AE")) { // NL reverse charge. tax_line* tl = administration::get_tax_line_from_report(report, "2a"); tl->total_net += totals.net; tl->total_tax += totals.net * 0.21f; // TODO fr? a5->total_tax += totals.net * 0.21f; b5->total_tax += totals.net * 0.21f; } else { b5->total_tax += totals.tax; } } else if (!country::is_EU(inv->supplier.address.country_code)) { tax_line* tl = administration::get_tax_line_from_report(report, "4a"); tl->total_net += totals.net; tl->total_tax += totals.net * 0.21f; a5->total_tax += totals.net * 0.21f; b5->total_tax += totals.net * 0.21f; } else { tax_line* tl = administration::get_tax_line_from_report(report, "4b"); tl->total_net += totals.net; tl->total_tax += totals.net * 0.21f; a5->total_tax += totals.net * 0.21f; b5->total_tax += totals.net * 0.21f; } } return 1; } float _nl_calculate_tax_report_final(tax_report* report) { tax_line* a5 = administration::get_tax_line_from_report(report, "5a"); // Total owed. tax_line* b5 = administration::get_tax_line_from_report(report, "5b"); // Input tax. tax_line* total = administration::get_tax_line_from_report(report, "5c"); total->total_tax = a5->total_tax - b5->total_tax; if (total->total_tax < 0.0f) total->total_tax = (float)ceil(total->total_tax); else total->total_tax = (float)floor(total->total_tax); return total->total_tax; } time_t _nl_get_invoice_date_to_use_for_tax_report(invoice* inv) { if (!inv->is_outgoing) { // Intra-Community services need to be reported in the quarter the service was delivered. if (administration::invoice_has_intra_community_services(inv)) { return inv->delivered_at; } } return inv->issued_at; } country_impl _nl_country_impl = { "NL", true, _nl_get_default_invoice_expire_duration, _nl_fill_tax_report_with_categories, _nl_add_billing_item_to_tax_report, _nl_calculate_tax_report_final, _nl_get_invoice_date_to_use_for_tax_report, };