feat(accounting): manual "add expense" (no document) on the ledger

Adds an "Add expense" action to the expenses ledger for costs with no inbound
document — mileage, per-diem, a cash receipt, etc.

- accounting.service: createExpense() -> POST /admin/expenses
  (createManualExpense); CategorizePayload gains `description`.
- ExpensesLedgerPage: AddExpenseModal with supplier / description / amount /
  currency / disposition (company expense / pass-through / re-bill — no
  duplicate, there's no document to dedupe). Company-expense picks a category;
  re-bill uses the customer picker + markup and chains createExpense -> rebill
  into an editable scheduled invoice, same as inbox triage. "Add expense"
  button in the filter row.
- i18n: accounting.ledger.{addExpense,addTitle,description,descriptionHint,
  createdToast} (EN + DE); shared field labels reuse accounting.inbox.field.*.

Verified: en/de JSON valid; npm run build green.
This commit is contained in:
Luca
2026-06-11 01:01:40 +02:00
parent e111522415
commit 703f72742d
4 changed files with 159 additions and 3 deletions
+6 -1
View File
@@ -3483,7 +3483,12 @@
"reference": "Referenz (optional)",
"confirmPaid": "Als bezahlt markieren",
"paidToast": "Als bezahlt markiert.",
"unpaidToast": "Als nicht bezahlt markiert."
"unpaidToast": "Als nicht bezahlt markiert.",
"addExpense": "Aufwand hinzufügen",
"addTitle": "Aufwand hinzufügen",
"description": "Beschreibung",
"descriptionHint": "z. B. Kilometer, Spesenpauschale, Barbeleg",
"createdToast": "Aufwand hinzugefügt."
}
},
"calendar": {
+6 -1
View File
@@ -3483,7 +3483,12 @@
"reference": "Reference (optional)",
"confirmPaid": "Mark paid",
"paidToast": "Marked as paid.",
"unpaidToast": "Marked as not paid."
"unpaidToast": "Marked as not paid.",
"addExpense": "Add expense",
"addTitle": "Add expense",
"description": "Description",
"descriptionHint": "e.g. mileage, per-diem, cash receipt",
"createdToast": "Expense added."
}
},
"calendar": {