feat(accounting): supplier-country tax default + configurable default output VAT code

VAT supplier-country reclaim default:
- Migration 134 adds inbound_documents.supplier_country.
- categorizeInbound auto-derives tax_treatment via resolveTaxTreatment:
  explicit treatment wins; else country in the reclaim list → domestic,
  outside it → foreign_vat_non_reclaimable, unknown → domestic. Consumes the
  previously-stored-but-unused accounting_vat_reclaim_countries.
- Triage modal gains a Supplier country dropdown (saved via updateInbound).
  +5 unit tests for resolveTaxTreatment.

Configurable default output VAT code for new invoices:
- New accounting_default_output_vat_code setting (PUT wired; getSettings/type).
- Settings → Accounting dropdown to pick it.
- Invoice + quote editors seed their VAT picker (rate + code) from it on a
  blank new document — skipping edits/conversions, never clobbering a touched
  value. New docs no longer silently start at 0%.

i18n en + de.
This commit is contained in:
Luca
2026-06-18 15:35:58 +02:00
parent 348955b261
commit 267b121d66
11 changed files with 170 additions and 11 deletions
@@ -0,0 +1,25 @@
/**
* Migration 134: supplier country on incoming invoices.
*
* `supplier_country` (ISO-3166 alpha-2) lets categorisation auto-default the
* `tax_treatment`: a supplier whose country is in the install's VAT reclaim
* list (Settings → Accounting → `accounting_vat_reclaim_countries`, typically
* CH / LI) → `domestic` (input VAT reclaimable); otherwise →
* `foreign_vat_non_reclaimable`. Closes the dangling VAT-consolidation slice
* where the reclaim-countries setting was stored but never consumed.
*
* Additive + hasColumn-guarded.
*/
exports.up = async function (knex) {
if (!(await knex.schema.hasTable('inbound_documents'))) return;
if (!(await knex.schema.hasColumn('inbound_documents', 'supplier_country'))) {
await knex.schema.alterTable('inbound_documents', (t) => t.string('supplier_country', 2));
}
};
exports.down = async function (knex) {
if (!(await knex.schema.hasTable('inbound_documents'))) return;
if (await knex.schema.hasColumn('inbound_documents', 'supplier_country')) {
await knex.schema.alterTable('inbound_documents', (t) => t.dropColumn('supplier_country'));
}
};