feat(projects): rolled-up project value (newest stage wins per deal, cumulative)

- computeValuation helper: per deal_uuid, the invoice total (installments
  summed, storno netted) wins over the quote; contracts carry no total so
  never contribute. Summed across the project's events, split by currency.
- Value column on the Project Overview list + a value/paid block in the
  cockpit header. Both gated by bills.view/quotes.view so no figure leaks.
- listProjects computes all values in two bulk queries (not per-project).
- en + de i18n; six unit assertions cover the rule's edge cases.
This commit is contained in:
Luca
2026-06-06 13:48:46 +02:00
parent dffcf6269f
commit 7ca243780a
7 changed files with 165 additions and 7 deletions
+5
View File
@@ -3403,6 +3403,7 @@
"name": "Projekt",
"customer": "Kunde",
"events": "Events",
"value": "Wert",
"status": "Status",
"updated": "Aktualisiert"
},
@@ -3410,6 +3411,10 @@
"label": "Projekt",
"none": "Kein Projekt"
},
"value": {
"label": "Projektwert",
"paid": "bezahlt"
},
"events": {
"title": "Events",
"none": "Diesem Projekt sind noch keine Events zugeordnet.",
+5
View File
@@ -3403,6 +3403,7 @@
"name": "Project",
"customer": "Customer",
"events": "Events",
"value": "Value",
"status": "Status",
"updated": "Updated"
},
@@ -3410,6 +3411,10 @@
"label": "Project",
"none": "No project"
},
"value": {
"label": "Project value",
"paid": "paid"
},
"events": {
"title": "Events",
"none": "No events grouped under this project yet.",