diff --git a/TrafagSalesExporter/NEXT_STEPS_2026-04-15.md b/TrafagSalesExporter/NEXT_STEPS_2026-04-15.md index f8165c1..f5843fe 100644 --- a/TrafagSalesExporter/NEXT_STEPS_2026-04-15.md +++ b/TrafagSalesExporter/NEXT_STEPS_2026-04-15.md @@ -1,6 +1,89 @@ # 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 diff --git a/TrafagSalesExporter/Security/SecurityOptions.cs b/TrafagSalesExporter/Security/SecurityOptions.cs index da003a4..76be392 100644 --- a/TrafagSalesExporter/Security/SecurityOptions.cs +++ b/TrafagSalesExporter/Security/SecurityOptions.cs @@ -4,6 +4,7 @@ public sealed class SecurityOptions { public const string SectionName = "Security"; + public bool Enabled { get; set; } = true; public bool DevelopmentBypass { get; set; } public bool DevelopmentUserIsAdmin { get; set; } public string DevelopmentUserName { get; set; } = "DEV\\TrafagDeveloper"; diff --git a/TrafagSalesExporter/Security/SecurityPolicyFactory.cs b/TrafagSalesExporter/Security/SecurityPolicyFactory.cs index f91d90d..8e48d6a 100644 --- a/TrafagSalesExporter/Security/SecurityPolicyFactory.cs +++ b/TrafagSalesExporter/Security/SecurityPolicyFactory.cs @@ -6,10 +6,18 @@ public static class SecurityPolicyFactory { public static AuthorizationPolicy BuildAccessPolicy(SecurityOptions settings, bool useDevelopmentAuthentication) { + if (!settings.Enabled) + { + return new AuthorizationPolicyBuilder() + .RequireAssertion(_ => true) + .Build(); + } + var builder = new AuthorizationPolicyBuilder() .RequireAuthenticatedUser(); - if (!useDevelopmentAuthentication && settings.AccessGroups.Count > 0) + if (!useDevelopmentAuthentication && + settings.AccessGroups.Count > 0) { builder.RequireAssertion(context => settings.AccessGroups.Any(group => context.User.IsInRole(group))); @@ -20,6 +28,13 @@ public static class SecurityPolicyFactory public static AuthorizationPolicy BuildAdminPolicy(SecurityOptions settings, bool useDevelopmentAuthentication) { + if (!settings.Enabled) + { + return new AuthorizationPolicyBuilder() + .RequireAssertion(_ => true) + .Build(); + } + var builder = new AuthorizationPolicyBuilder() .RequireAuthenticatedUser(); diff --git a/TrafagSalesExporter/TrafagSalesExporter.Tests/SecurityPolicyFactoryTests.cs b/TrafagSalesExporter/TrafagSalesExporter.Tests/SecurityPolicyFactoryTests.cs index 622b828..5eb4851 100644 --- a/TrafagSalesExporter/TrafagSalesExporter.Tests/SecurityPolicyFactoryTests.cs +++ b/TrafagSalesExporter/TrafagSalesExporter.Tests/SecurityPolicyFactoryTests.cs @@ -46,6 +46,20 @@ public class SecurityPolicyFactoryTests 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] public async Task AdminPolicy_Allows_User_In_Admin_Group() { @@ -95,6 +109,20 @@ public class SecurityPolicyFactoryTests 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 AuthorizeAsync(AuthorizationPolicy policy, ClaimsPrincipal user) { var services = new ServiceCollection(); @@ -119,4 +147,5 @@ public class SecurityPolicyFactoryTests return new ClaimsPrincipal(new ClaimsIdentity(allClaims, "Test")); } + private static ClaimsPrincipal CreateAnonymousUser() => new(new ClaimsIdentity()); } diff --git a/TrafagSalesExporter/appsettings.json b/TrafagSalesExporter/appsettings.json index 44519de..0c9888b 100644 --- a/TrafagSalesExporter/appsettings.json +++ b/TrafagSalesExporter/appsettings.json @@ -6,6 +6,7 @@ } }, "Security": { + "Enabled": false, "DevelopmentBypass": false, "DevelopmentUserIsAdmin": false, "DevelopmentUserName": "DEV\\TrafagDeveloper", @@ -33,6 +34,6 @@ "FinanceCockpitAccess": { "Enabled": true, "Username": "finance", - "PasswordHash": "A8AF253007750E0C2986CBD0BC570530B4AE2417AAC59067591E708547834AE4" + "PasswordHash": "1446F41A1BF8ABCF5DED217400CDC5D671F9E1B58753162A228F23FB7C844575" } } diff --git a/TrafagSalesExporter/docs/FINANCE_HANDOFF_2026-05-18.md b/TrafagSalesExporter/docs/FINANCE_HANDOFF_2026-05-18.md index c200b09..fe6fd3f 100644 --- a/TrafagSalesExporter/docs/FINANCE_HANDOFF_2026-05-18.md +++ b/TrafagSalesExporter/docs/FINANCE_HANDOFF_2026-05-18.md @@ -25,6 +25,85 @@ docs/it_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 | Land | Ist | Soll | Differenz | Waehrung | Status | @@ -256,6 +335,13 @@ Relevante Commits: | `fb85e2e` | Sage-Berechnungen korrigiert, IT/UK-Doku und Ampel ergaenzt | | `3d40d76` | UK auf GBP Local Currency als Referenz umgestellt | | `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. @@ -275,8 +361,11 @@ docs/CFO_Kurzbericht_270515*.bak.docx docs/CFO_Kurzbericht_270515_NEU*.docx docs/FINANCE_AMPEL_LAENDER_2026-05-18.xlsx docs/FINANCE_AMPEL_LAENDER_2026-05-18_20-32.xlsx +docs/FINANCE_AMPEL_LAENDER_2026-05-19.xlsx docs/it_cache_2025.csv italien.png +financeprobe.*.log +mainapp.*.log ``` 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. 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. +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. diff --git a/TrafagSalesExporter/lastchange.md b/TrafagSalesExporter/lastchange.md index c46a89c..703ea55 100644 --- a/TrafagSalesExporter/lastchange.md +++ b/TrafagSalesExporter/lastchange.md @@ -1,5 +1,140 @@ # 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 Anlass: