Document finance workflow and security toggle

This commit is contained in:
2026-05-19 14:26:04 +02:00
parent b23f73ecd6
commit 383796df87
7 changed files with 358 additions and 3 deletions
+84 -1
View File
@@ -1,6 +1,89 @@
# Next Steps # Next Steps
Stand: 2026-05-05 Stand: 2026-05-19
## Nachtrag 2026-05-19 Finance-Cockpit-Login finalisieren
Aktueller Stand:
- Finance Cockpit hat einen separaten Login.
- HR-KPI-Login und Finance-Cockpit-Login sind technisch getrennte Services/Konfigurationen.
- Finance-Konfiguration liegt in `appsettings.json` unter `FinanceCockpitAccess`.
- Aktueller Benutzer: `finance`.
- Finance nutzt ein eigenes Passwort: `Trafag-Finance-Cockpit-2026!`.
- Globale AD-/Rollenpruefung ist fuer den Moment mit `Security.Enabled = false` deaktiviert.
- Die AD-Gruppen sind nicht geloescht und bleiben in `AccessGroups`/`AdminGroups` dokumentiert.
Wichtig:
- Finance- und HR-KPI-Sperren laufen weiter ueber eigene Passwortabfragen.
- AD/Rollen koennen spaeter durch `Security.Enabled = true` wieder aktiviert werden.
Noch offen:
1. Entscheiden, wann AD-/Rollenpruefung wieder aktiviert wird.
2. Bei Reaktivierung `Security.Enabled` auf `true` setzen und Gruppen pruefen.
3. Pruefen, ob direkte Run-/Export-/FinanceProbe-Endpunkte ebenfalls geschuetzt werden muessen.
4. In Browser testen:
```text
http://127.0.0.1:5099/finance-cockpit/vergleich
```
5. Nach Entsperren pruefen, dass Navigation und `Finance sperren` korrekt funktionieren.
## Nachtrag 2026-05-19 Finance-Vergleich / Formeldoku
Erledigt:
- `/finance-cockpit/vergleich` nutzt dieselbe `FinanceReconciliationService`-Logik wie die FinanceProbe.
- Leere Ist-Zeilen werden in der Haupt-App ausgefiltert.
- Berechnungslogik pro Land wurde dokumentiert:
```text
docs/FINANCE_BERECHNUNGSFORMELN_LAENDER_2026-05-19.md
```
Naechster Check:
- Bei neuer Datenladung `/finance-cockpit/vergleich` und `/finance` gegeneinander vergleichen.
- Besonders ES, AT, UK und IT weiter fachlich klaeren.
## Nachtrag 2026-05-19 Zentrale Excel fuer Finance-Filter
Erledigt:
- Die zentrale Excel `Sales_All_yyyy-MM-dd.xlsx` enthaelt im Blatt `Sales` einen Finance-Spaltenblock:
```text
Finance | Year
Finance | Country Key
Finance | Date
Finance | Net Sales Actual
Finance | Currency
Finance | Include
Finance | Source Value Field
```
- Die zentrale Excel enthaelt ein Hilfsblatt `Finance Filter Hilfe`.
- Das Hilfsblatt erklaert, wie Finance dieselben Ist-Summen wie im Testprogramm erhaelt:
```text
Finance | Year = 2025
Finance | Country Key = Land
Finance | Include = TRUE
Summe Finance | Net Sales Actual
```
Geprueft:
- Excel-Finance-Spalten wurden gegen `FinanceReconciliationService` fuer 2025 verglichen.
- AT, CH, ES, FR, IN, IT, UK und US ergaben jeweils `MATCH` mit Differenz `0.00`.
Naechster praktischer Check:
- Nach dem naechsten echten Export die SharePoint-Datei `Sales_All_yyyy-MM-dd.xlsx` oeffnen und mit Finance die Filter-/Summenlogik einmal gemeinsam durchgehen.
- Dabei darauf achten, dass nicht versehentlich alte Spalten wie `Land`, `TSC`, `Document Total LC` oder `Sales Price/Value` direkt fuer CFO-Summen verwendet werden.
## Nachtrag 2026-05-11 UK_B1 Mapping fertigstellen ## Nachtrag 2026-05-11 UK_B1 Mapping fertigstellen
@@ -4,6 +4,7 @@ public sealed class SecurityOptions
{ {
public const string SectionName = "Security"; public const string SectionName = "Security";
public bool Enabled { get; set; } = true;
public bool DevelopmentBypass { get; set; } public bool DevelopmentBypass { get; set; }
public bool DevelopmentUserIsAdmin { get; set; } public bool DevelopmentUserIsAdmin { get; set; }
public string DevelopmentUserName { get; set; } = "DEV\\TrafagDeveloper"; public string DevelopmentUserName { get; set; } = "DEV\\TrafagDeveloper";
@@ -6,10 +6,18 @@ public static class SecurityPolicyFactory
{ {
public static AuthorizationPolicy BuildAccessPolicy(SecurityOptions settings, bool useDevelopmentAuthentication) public static AuthorizationPolicy BuildAccessPolicy(SecurityOptions settings, bool useDevelopmentAuthentication)
{ {
if (!settings.Enabled)
{
return new AuthorizationPolicyBuilder()
.RequireAssertion(_ => true)
.Build();
}
var builder = new AuthorizationPolicyBuilder() var builder = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser(); .RequireAuthenticatedUser();
if (!useDevelopmentAuthentication && settings.AccessGroups.Count > 0) if (!useDevelopmentAuthentication &&
settings.AccessGroups.Count > 0)
{ {
builder.RequireAssertion(context => builder.RequireAssertion(context =>
settings.AccessGroups.Any(group => context.User.IsInRole(group))); settings.AccessGroups.Any(group => context.User.IsInRole(group)));
@@ -20,6 +28,13 @@ public static class SecurityPolicyFactory
public static AuthorizationPolicy BuildAdminPolicy(SecurityOptions settings, bool useDevelopmentAuthentication) public static AuthorizationPolicy BuildAdminPolicy(SecurityOptions settings, bool useDevelopmentAuthentication)
{ {
if (!settings.Enabled)
{
return new AuthorizationPolicyBuilder()
.RequireAssertion(_ => true)
.Build();
}
var builder = new AuthorizationPolicyBuilder() var builder = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser(); .RequireAuthenticatedUser();
@@ -46,6 +46,20 @@ public class SecurityPolicyFactoryTests
Assert.True(result.Succeeded); Assert.True(result.Succeeded);
} }
[Fact]
public async Task AccessPolicy_Allows_User_When_Security_Is_Disabled()
{
var policy = SecurityPolicyFactory.BuildAccessPolicy(new SecurityOptions
{
Enabled = false,
AccessGroups = ["TRAFAG\\TrafagSalesExporter-Users"]
}, useDevelopmentAuthentication: false);
var result = await AuthorizeAsync(policy, CreateAnonymousUser());
Assert.True(result.Succeeded);
}
[Fact] [Fact]
public async Task AdminPolicy_Allows_User_In_Admin_Group() public async Task AdminPolicy_Allows_User_In_Admin_Group()
{ {
@@ -95,6 +109,20 @@ public class SecurityPolicyFactoryTests
Assert.False(result.Succeeded); Assert.False(result.Succeeded);
} }
[Fact]
public async Task AdminPolicy_Allows_User_When_Security_Is_Disabled()
{
var policy = SecurityPolicyFactory.BuildAdminPolicy(new SecurityOptions
{
Enabled = false,
AdminGroups = ["TRAFAG\\TrafagSalesExporter-Admins"]
}, useDevelopmentAuthentication: false);
var result = await AuthorizeAsync(policy, CreateAnonymousUser());
Assert.True(result.Succeeded);
}
private static async Task<AuthorizationResult> AuthorizeAsync(AuthorizationPolicy policy, ClaimsPrincipal user) private static async Task<AuthorizationResult> AuthorizeAsync(AuthorizationPolicy policy, ClaimsPrincipal user)
{ {
var services = new ServiceCollection(); var services = new ServiceCollection();
@@ -119,4 +147,5 @@ public class SecurityPolicyFactoryTests
return new ClaimsPrincipal(new ClaimsIdentity(allClaims, "Test")); return new ClaimsPrincipal(new ClaimsIdentity(allClaims, "Test"));
} }
private static ClaimsPrincipal CreateAnonymousUser() => new(new ClaimsIdentity());
} }
+2 -1
View File
@@ -6,6 +6,7 @@
} }
}, },
"Security": { "Security": {
"Enabled": false,
"DevelopmentBypass": false, "DevelopmentBypass": false,
"DevelopmentUserIsAdmin": false, "DevelopmentUserIsAdmin": false,
"DevelopmentUserName": "DEV\\TrafagDeveloper", "DevelopmentUserName": "DEV\\TrafagDeveloper",
@@ -33,6 +34,6 @@
"FinanceCockpitAccess": { "FinanceCockpitAccess": {
"Enabled": true, "Enabled": true,
"Username": "finance", "Username": "finance",
"PasswordHash": "A8AF253007750E0C2986CBD0BC570530B4AE2417AAC59067591E708547834AE4" "PasswordHash": "1446F41A1BF8ABCF5DED217400CDC5D671F9E1B58753162A228F23FB7C844575"
} }
} }
@@ -25,6 +25,85 @@ docs/it_cache_2025.csv
docs/spain_cache_2025.csv docs/spain_cache_2025.csv
``` ```
## Nachtrag 2026-05-19
Nach diesem Handoff wurden noch vier relevante Schritte umgesetzt und committed:
1. Haupt-App-Finance-Vergleich an FinanceProbe angeglichen.
2. Leere Ist-Zeilen ohne belastbaren Ist-Wert aus dem Finance-Vergleich gefiltert.
3. Berechnungsformeln je Land dokumentiert.
4. Finance Cockpit mit separatem Login technisch geschuetzt; fachliche/produktive Abnahme noch offen.
Wichtige neue Doku:
```text
docs/FINANCE_BERECHNUNGSFORMELN_LAENDER_2026-05-19.md
```
Diese Datei beschreibt die aktuell verwendete Soll/Ist-Logik fuer `/finance-cockpit/vergleich` und `/finance`, inklusive Jahresfilter, Kandidatenberechnung, Deduplizierung, bevorzugter Ist-Variante und landesspezifischer Quellen/Formeln.
Neue Finance-Cockpit-Sperre, Stand technisch:
- `FinanceCockpitAccessService`
- `FinanceCockpitAccessOptions`
- `FinanceCockpitUnlockPanel`
- Konfiguration in `appsettings.json` unter `FinanceCockpitAccess`
- DI-Registrierung in `Program.cs`
- Route-/Navigation-Schutz in `Routes.razor` und `NavMenu.razor`
Wichtig: Der HR-KPI-Login bleibt separat. Die neue Sperre betrifft das Finance Cockpit und laeuft wie HR-KPI ueber Benutzername plus SHA-256-Passwort-Hash. Finance hat ein eigenes Passwort:
```text
Benutzer: finance
Passwort: Trafag-Finance-Cockpit-2026!
```
AD-/Rollenpruefung ist fuer den Moment nicht geloescht, sondern in `appsettings.json` mit `Security.Enabled = false` deaktiviert. Die vorhandenen `AccessGroups` und `AdminGroups` bleiben in der Konfiguration stehen und koennen spaeter wieder aktiviert werden. Die Finance-Sperre bleibt davon unabhaengig aktiv.
### Zentrale Excel fuer CFO-/Finance-Filter
Die zentrale Datei `Sales_All_yyyy-MM-dd.xlsx` enthaelt am rechten Ende einen zusammengehoerigen Finance-Spaltenblock:
```text
Finance | Year
Finance | Country Key
Finance | Date
Finance | Net Sales Actual
Finance | Currency
Finance | Include
Finance | Source Value Field
```
Zusaetzlich wird nur in der zentralen Datei ein Hilfsblatt erzeugt:
```text
Finance Filter Hilfe
```
Damit soll Finance dieselben Ist-Summen aus Excel filtern koennen wie im Testprogramm bzw. auf `/finance-cockpit/vergleich`.
Vorgehen im Excel:
1. `Finance | Year` auf das gewuenschte Jahr filtern, z. B. `2025`.
2. `Finance | Country Key` auf Land filtern, z. B. `IT`, `UK`, `ES`, `AT`.
3. `Finance | Include = TRUE` filtern.
4. `Finance | Net Sales Actual` summieren.
Gepruefter Vergleich gegen `FinanceReconciliationService` fuer 2025:
| Key | Finance-Service | Excel-Finance-Spalten | Differenz |
| --- | ---: | ---: | ---: |
| AT | `3'438'121.37` | `3'438'121.37` | `0.00` |
| CH | `43'521'390.82` | `43'521'390.82` | `0.00` |
| ES | `3'082'320.18` | `3'082'320.18` | `0.00` |
| FR | `1'471'218.44` | `1'471'218.44` | `0.00` |
| IN | `750'936'591.38` | `750'936'591.38` | `0.00` |
| IT | `7'669'641.47` | `7'669'641.47` | `0.00` |
| UK | `3'533'710.09` | `3'533'710.09` | `0.00` |
| US | `3'749'865.33` | `3'749'865.33` | `0.00` |
Hinweis: Fuer AT/CH waehlt der Finance-Service intern `Nettofakturawert Hauswaehrung pro Position`; in den aktuellen Daten ist dieser Wert identisch mit `SalesPriceValue`, daher stimmen die Excel-Finance-Spalten exakt.
## Aktuelle Soll/Ist-Werte ## Aktuelle Soll/Ist-Werte
| Land | Ist | Soll | Differenz | Waehrung | Status | | Land | Ist | Soll | Differenz | Waehrung | Status |
@@ -256,6 +335,13 @@ Relevante Commits:
| `fb85e2e` | Sage-Berechnungen korrigiert, IT/UK-Doku und Ampel ergaenzt | | `fb85e2e` | Sage-Berechnungen korrigiert, IT/UK-Doku und Ampel ergaenzt |
| `3d40d76` | UK auf GBP Local Currency als Referenz umgestellt | | `3d40d76` | UK auf GBP Local Currency als Referenz umgestellt |
| `f721d95` | Aktuelle Excel und Spanien-Cache ergaenzt | | `f721d95` | Aktuelle Excel und Spanien-Cache ergaenzt |
| `bc6bfdf` | Finance-Handoff dokumentiert |
| `8f1b1b8` | Haupt-Finance-Vergleich an Probe angeglichen |
| `f855e06` | Leere Ist-Zeilen im Finance-Vergleich gefiltert |
| `5c654ad` | Finance-Berechnungsformeln je Land dokumentiert |
| `9c544af` | Finance Cockpit mit Login technisch geschuetzt |
| `ebbc5a1` | Finance-Filterspalten in zentrale Excel ergaenzt |
| `b23f73e` | Finance-Hilfsblatt in zentrale Excel ergaenzt |
Dieses Handoff wurde danach als weiterer Commit hinzugefuegt. Dieses Handoff wurde danach als weiterer Commit hinzugefuegt.
@@ -275,8 +361,11 @@ docs/CFO_Kurzbericht_270515*.bak.docx
docs/CFO_Kurzbericht_270515_NEU*.docx docs/CFO_Kurzbericht_270515_NEU*.docx
docs/FINANCE_AMPEL_LAENDER_2026-05-18.xlsx docs/FINANCE_AMPEL_LAENDER_2026-05-18.xlsx
docs/FINANCE_AMPEL_LAENDER_2026-05-18_20-32.xlsx docs/FINANCE_AMPEL_LAENDER_2026-05-18_20-32.xlsx
docs/FINANCE_AMPEL_LAENDER_2026-05-19.xlsx
docs/it_cache_2025.csv docs/it_cache_2025.csv
italien.png italien.png
financeprobe.*.log
mainapp.*.log
``` ```
Wenn weitergearbeitet wird, zuerst `git status --short` pruefen und keine fremden/alten Dateien blind loeschen. Wenn weitergearbeitet wird, zuerst `git status --short` pruefen und keine fremden/alten Dateien blind loeschen.
@@ -287,3 +376,5 @@ Wenn weitergearbeitet wird, zuerst `git status --short` pruefen und keine fremde
2. AT: Differenz `-5'741.63 EUR` analysieren. 2. AT: Differenz `-5'741.63 EUR` analysieren.
3. UK: Restdifferenz `-5'261.91 GBP` klaeren, aber UK ist jetzt nahe am LC-Soll. 3. UK: Restdifferenz `-5'261.91 GBP` klaeren, aber UK ist jetzt nahe am LC-Soll.
4. IT: provisorischen Kundenausschluss fachlich bestaetigen oder durch offizielle B1/Rhino-Filterregel ersetzen. 4. IT: provisorischen Kundenausschluss fachlich bestaetigen oder durch offizielle B1/Rhino-Filterregel ersetzen.
5. AD-/Rollenpruefung spaeter wieder aktivieren, sobald geklaert ist, welche Gruppen produktiv gelten. Dazu `Security.Enabled` wieder auf `true` setzen; Gruppen sind nicht geloescht.
6. `/finance-cockpit/vergleich` und `/finance` nebeneinander pruefen, wenn neue Daten geladen wurden; beide sollen dieselbe `FinanceReconciliationService`-Logik nutzen.
+135
View File
@@ -1,5 +1,140 @@
# Last Change 2026-05-04 # Last Change 2026-05-04
## Finance Cockpit Login und Vergleichsnachtrag 2026-05-19
Nach dem Finance-Handoff vom 2026-05-18 wurden noch mehrere Schritte umgesetzt:
- Haupt-App-Seite `/finance-cockpit/vergleich` wurde an die Logik und Darstellung der FinanceProbe angeglichen.
- Leere Ist-Zeilen ohne belastbaren Ist-Wert werden im Finance-Vergleich ausgefiltert.
- Die verwendeten Berechnungsformeln je Land wurden dokumentiert:
```text
docs/FINANCE_BERECHNUNGSFORMELN_LAENDER_2026-05-19.md
```
- Finance Cockpit erhielt einen separaten Login, unabhaengig vom HR-KPI-Login.
Technischer Stand Finance-Cockpit-Login:
- Konfiguration: `FinanceCockpitAccess` in `appsettings.json`
- Benutzer im aktuellen Stand: `finance`
- Passwort ist als SHA-256-Hash gespeichert.
- Finance nutzt ein eigenes Passwort: `Trafag-Finance-Cockpit-2026!`.
- HR-KPI nutzt weiterhin seine eigene `HrKpiAccess`-Konfiguration.
- Umsetzung:
- `Services/FinanceCockpitAccessService.cs`
- `Security/FinanceCockpitAccessOptions.cs`
- `Components/FinanceCockpit/FinanceCockpitUnlockPanel.razor`
- `Components/Routes.razor`
- `Components/Layout/NavMenu.razor`
- Registrierung in `Program.cs`
AD-/Rollenstand:
- `Security.Enabled = false` deaktiviert die globale AD-/Rollenpruefung fuer den Moment.
- Die vorhandenen `AccessGroups` und `AdminGroups` bleiben in `appsettings.json` stehen und wurden nicht geloescht.
- Wenn AD/Rollen wieder gelten sollen, `Security.Enabled` auf `true` setzen.
- Finance- und HR-KPI-Sperren bleiben auch bei deaktivierter AD-Pruefung aktiv.
Relevante Commits:
```text
8f1b1b8 Align main finance comparison with probe
f855e06 Filter empty actual finance rows
5c654ad Document finance formulas by country
9c544af Protect finance cockpit with login
```
## Zentrale Excel Finance-Filter 2026-05-19
Die zentrale Laenderdatei `Sales_All_yyyy-MM-dd.xlsx` wurde fuer den CFO-/Finance-Abgleich erweitert.
Im Blatt `Sales` gibt es rechts einen zusammengehoerigen Finance-Spaltenblock:
```text
Finance | Year
Finance | Country Key
Finance | Date
Finance | Net Sales Actual
Finance | Currency
Finance | Include
Finance | Source Value Field
```
Ziel:
- Finance kann im zentralen Excel dieselben Ist-Summen erzeugen wie im Testprogramm.
- Es muss nicht geraten werden, ob `Land`, `TSC`, `Sales Price/Value`, `Document Total LC`, `posting date` oder `invoice date` zu verwenden ist.
Filterregel fuer Finance:
```text
Finance | Year = 2025
Finance | Country Key = gewuenschtes Land
Finance | Include = TRUE
Summe ueber Finance | Net Sales Actual
```
Nur in der zentralen Datei wird ein zweites Blatt erzeugt:
```text
Finance Filter Hilfe
```
Dieses Hilfsblatt beschreibt die zusammengehoerigen Finance-Spalten und die konkrete Filter-/Summenlogik.
Verifikation:
- Build erfolgreich:
```text
dotnet build .\TrafagSalesExporter.csproj --no-restore -p:UseAppHost=false -p:OutDir=.\obj\verify_finance_help_sheet\ --verbosity minimal
```
- Preview-Excel erzeugt und geprueft:
```text
.tmp_tools\GenerateConsolidatedPreview\out\Sales_All_2026-05-19.xlsx
```
- Gepruefte Blaetter:
```text
Sales | Finance Filter Hilfe
```
- Finance-Spaltenblock im Blatt `Sales`:
```text
36: Finance | Year
37: Finance | Country Key
38: Finance | Date
39: Finance | Net Sales Actual
40: Finance | Currency
41: Finance | Include
42: Finance | Source Value Field
```
- Summenvergleich gegen `FinanceReconciliationService` fuer 2025:
| Key | Finance-Service | Excel-Finance-Spalten | Status |
| --- | ---: | ---: | --- |
| AT | `3'438'121.37` | `3'438'121.37` | MATCH |
| CH | `43'521'390.82` | `43'521'390.82` | MATCH |
| ES | `3'082'320.18` | `3'082'320.18` | MATCH |
| FR | `1'471'218.44` | `1'471'218.44` | MATCH |
| IN | `750'936'591.38` | `750'936'591.38` | MATCH |
| IT | `7'669'641.47` | `7'669'641.47` | MATCH |
| UK | `3'533'710.09` | `3'533'710.09` | MATCH |
| US | `3'749'865.33` | `3'749'865.33` | MATCH |
Relevante Commits:
```text
ebbc5a1 Add finance filter columns to consolidated export
b23f73e Add finance filter help sheet
```
## UK_B1 Mapping / FinanceProbe Nachtrag 2026-05-11 ## UK_B1 Mapping / FinanceProbe Nachtrag 2026-05-11
Anlass: Anlass: