Document AI role and HR exclusions
This commit is contained in:
@@ -8,6 +8,15 @@ namespace TrafagSalesExporter.Services;
|
||||
internal sealed class HrKpiDashboardBuilder
|
||||
{
|
||||
private readonly HrKpiDataSourceOptions _dataSources;
|
||||
private static readonly HashSet<string> ExcludedPersonNameKeys = new(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
NormalizePersonExclusionKey("Angelina Jolie"),
|
||||
NormalizePersonExclusionKey("Brad Pitt"),
|
||||
NormalizePersonExclusionKey("Peter Muster"),
|
||||
NormalizePersonExclusionKey("ICT Trafag"),
|
||||
NormalizePersonExclusionKey("Empfanger Reminder"),
|
||||
NormalizePersonExclusionKey("Empfänger Reminder")
|
||||
};
|
||||
|
||||
public HrKpiDashboardBuilder(HrKpiDataSourceOptions dataSources)
|
||||
{
|
||||
@@ -40,6 +49,12 @@ internal sealed class HrKpiDashboardBuilder
|
||||
var employees = LoadEmployees(context, timeRows, sapRows);
|
||||
var absences = LoadAbsences(context);
|
||||
var leavers = LoadLeavers(context);
|
||||
var excludedRows =
|
||||
employees.RemoveAll(x => IsExcludedTestPerson(x.NameVoll)) +
|
||||
absences.RemoveAll(x => IsExcludedTestPerson(x.Name)) +
|
||||
leavers.RemoveAll(x => IsExcludedTestPerson(x.NameVoll));
|
||||
if (excludedRows > 0)
|
||||
result.Notices.Add($"{excludedRows:N0} Testpersonen-Zeilen wurden aus dem HR-KPI-Dashboard ausgeschlossen.");
|
||||
|
||||
result.OrganisationOptions = employees
|
||||
.Select(x => x.Organisationseinheit)
|
||||
@@ -939,6 +954,18 @@ internal sealed class HrKpiDashboardBuilder
|
||||
private static string NormalizeKey(string value)
|
||||
=> value.Trim().ToUpperInvariant();
|
||||
|
||||
private static bool IsExcludedTestPerson(string? name)
|
||||
=> !string.IsNullOrWhiteSpace(name) &&
|
||||
ExcludedPersonNameKeys.Contains(NormalizePersonExclusionKey(name));
|
||||
|
||||
private static string NormalizePersonExclusionKey(string value)
|
||||
{
|
||||
var normalized = NormalizeReason(value)
|
||||
.Replace(",", " ", StringComparison.OrdinalIgnoreCase);
|
||||
var parts = normalized.Split(' ', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
||||
return string.Join(" ", parts.OrderBy(x => x, StringComparer.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
private static int? ParseCostCenter(string value)
|
||||
{
|
||||
var raw = value.Split('/')[0].Trim();
|
||||
|
||||
@@ -211,6 +211,45 @@ public sealed class HrKpiServiceTests : IDisposable
|
||||
Assert.Contains(result.Leavers, row => row.Austrittsart == "Ruhestand" && row.FluktuationAusschlussgrund == "Pensionierung");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BuildAsync_Excludes_Configured_Test_Persons_From_All_Hr_Kpi_Views()
|
||||
{
|
||||
RewriteEmployeeRows(
|
||||
[
|
||||
[1001, "Alpha, Anna", "Org A", "100 / Org A", "Engineer", "n", new DateTime(2020, 1, 1), "Aktiv", "0:00", 25, 0, 0, 100000, "CHF"],
|
||||
[9001, "Jolie, Angelina", "Test", "999 / Test", "Engineer", "n", new DateTime(2020, 1, 1), "Aktiv", "0:00", 25, 0, 0, 100000, "CHF"],
|
||||
[9002, "Brad Pitt", "Test", "999 / Test", "Engineer", "n", new DateTime(2020, 1, 1), "Aktiv", "0:00", 25, 0, 0, 100000, "CHF"],
|
||||
[9003, "Peter Muster", "Test", "999 / Test", "Engineer", "n", new DateTime(2020, 1, 1), "Aktiv", "0:00", 25, 0, 0, 100000, "CHF"]
|
||||
]);
|
||||
WriteWorkbook(Path.Combine(_folder, "Abwesenheitinstunden.xlsx"),
|
||||
[
|
||||
"Personalnummer", "Nachname, Vorname (Link Personal)", "Organisation", "Stelle", "Personal Status",
|
||||
"Krankheit angetreten (Stunden Ind.)", "Krank nicht buchbar angetreten (Stunden Ind.)"
|
||||
],
|
||||
[
|
||||
[1001, "Alpha, Anna", "Org A", "Engineer", "Aktiv", 8.4, 0],
|
||||
[9004, "ICT Trafag", "Test", "Engineer", "Aktiv", 8.4, 0]
|
||||
]);
|
||||
RewriteLeaverRows(
|
||||
[
|
||||
[1001, "Alpha, Anna", "Org A", "Engineer", "Inaktiv", new DateTime(2025, 3, 10), new DateTime(2020, 1, 1), "Arbeitnehmer Kuendigung"],
|
||||
[9005, "Empfänger Reminder", "Test", "Engineer", "Inaktiv", new DateTime(2025, 3, 10), new DateTime(2020, 1, 1), "Arbeitnehmer Kuendigung"]
|
||||
]);
|
||||
|
||||
var result = await _service.BuildAsync(new HrKpiOptions
|
||||
{
|
||||
DataFolder = _folder,
|
||||
Year = 2025
|
||||
});
|
||||
|
||||
Assert.DoesNotContain(result.Employees, row => row.NameVoll.Contains("Angelina", StringComparison.OrdinalIgnoreCase));
|
||||
Assert.DoesNotContain(result.Employees, row => row.NameVoll.Contains("Brad Pitt", StringComparison.OrdinalIgnoreCase));
|
||||
Assert.DoesNotContain(result.Employees, row => row.NameVoll.Contains("Peter Muster", StringComparison.OrdinalIgnoreCase));
|
||||
Assert.DoesNotContain(result.Absences, row => row.Name.Contains("ICT Trafag", StringComparison.OrdinalIgnoreCase));
|
||||
Assert.DoesNotContain(result.Leavers, row => row.NameVoll.Contains("Reminder", StringComparison.OrdinalIgnoreCase));
|
||||
Assert.Contains(result.Notices, notice => notice.Contains("Testpersonen", StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
private static void WriteFixtureFiles(string folder)
|
||||
{
|
||||
WriteWorkbook(Path.Combine(folder, "Saldiperstichdatum.xlsx"),
|
||||
|
||||
Binary file not shown.
@@ -11,6 +11,7 @@ Ziel: Aufbau eines modernen, uebersichtlichen Intranet-Dashboards fuer das Group
|
||||
| 1 | Fuehrendes CFO-Dokument verwenden: `FINANCE_CHEF_SUMMARY_2026-05-15.docx` | Offen |
|
||||
| 1 | Offene Finance-Entscheide mit Andreas/Finance durchgehen | Offen |
|
||||
| 1 | Italien-Abweichung klaeren: Berechnungsart, Deduplizierung, Intercompany | Offen |
|
||||
| 1 | Italien IC-Diagnose besprechen: Trafag, Magnetic Sense/Magnets Sense und Gesellschaft fuer Sensorik erklaeren einen grossen Teil, aber nicht die ganze Abweichung | Offen |
|
||||
| 1 | Deutschland: finalen Jahresfile 2025 beschaffen | Offen |
|
||||
| 2 | UK/England: Jahresvollstaendigkeit und Restdifferenz pruefen | Offen |
|
||||
| 2 | CH/AT: Sollzuordnung und Trennung final bestaetigen | Offen |
|
||||
@@ -29,3 +30,29 @@ Ziel im Termin:
|
||||
- Offene Laenderabweichungen priorisieren.
|
||||
- Pro Land festlegen, welche Datenquelle und Berechnungslogik final gilt.
|
||||
|
||||
## IT / Intercompany Diagnose
|
||||
|
||||
Aktuelle Diagnose fuer Italien:
|
||||
|
||||
| Kennzahl | Wert |
|
||||
| --- | ---: |
|
||||
| IT Ist vor IC-Abzug | 14.704.336,29 EUR |
|
||||
| Rhino/check.xlsx Soll | 7.669.840,00 EUR |
|
||||
| Abweichung vor IC | +7.034.496,29 EUR |
|
||||
| Erkannter IC-/2nd-party-Abzug | 4.397.746,90 EUR |
|
||||
| IT Ist exkl. IC | 10.306.589,39 EUR |
|
||||
| Restabweichung nach IC | +2.636.749,39 EUR |
|
||||
|
||||
Verwendete IC-/2nd-party-Marker:
|
||||
|
||||
- `TRAFAG`
|
||||
- `MAGNETIC SENSE`
|
||||
- `MAGNETS SENSE`
|
||||
- `GESELLSCHAFT FUER SENSORIK`
|
||||
- `GESELLSCHAFT FUR SENSORIK`
|
||||
|
||||
Bewertung:
|
||||
|
||||
- Intercompany/2nd-party erklaert einen grossen Teil der IT-Abweichung.
|
||||
- Die Summe passt dadurch deutlich besser, aber noch nicht vollstaendig.
|
||||
- Restabweichung weiter pruefen: Summenlogik, Beleg/Position-Deduplizierung, Gutschriften/Storno und weitere lokale IC-Kunden oder Schreibweisen.
|
||||
|
||||
@@ -1349,6 +1349,66 @@ Ergebnis:
|
||||
- Build erfolgreich.
|
||||
- 3 bestehende MudBlazor-Analyzer-Warnungen in `Logs.razor`, `Transformations.razor` und `Standorte.razor`.
|
||||
|
||||
## CFO-Bericht IT/Intercompany Diagnose 2026-05-15
|
||||
|
||||
Ergaenzt:
|
||||
|
||||
- `docs/CFO_Kurzbericht_270515.docx`
|
||||
- `docs/FINANCE_DASHBOARD_TODO_2026-05-15.md`
|
||||
|
||||
Inhalt:
|
||||
|
||||
- IT/Intercompany-Diagnose fuer die grosse Italien-Abweichung.
|
||||
- Marker dokumentiert: `TRAFAG`, `MAGNETIC SENSE`, `MAGNETS SENSE`, `GESELLSCHAFT FUER SENSORIK`, `GESELLSCHAFT FUR SENSORIK`.
|
||||
- Zahlen:
|
||||
- IT Ist vor IC-Abzug: `14.704.336,29 EUR`
|
||||
- IC-/2nd-party-Abzug: `4.397.746,90 EUR`
|
||||
- IT Ist exkl. IC: `10.306.589,39 EUR`
|
||||
- Rhino/check.xlsx Soll: `7.669.840,00 EUR`
|
||||
- Restabweichung nach IC: `+2.636.749,39 EUR`
|
||||
|
||||
Bewertung:
|
||||
|
||||
- Intercompany/2nd-party erklaert einen grossen Teil der IT-Abweichung.
|
||||
- Restabweichung bleibt offen und muss ueber Summenlogik, Beleg/Position-Deduplizierung, Gutschriften/Storno und weitere lokale IC-Kunden oder Schreibweisen geprueft werden.
|
||||
|
||||
## HR KPI Testpersonen-Ausschluss 2026-05-15
|
||||
|
||||
Geaendert:
|
||||
|
||||
- Folgende Testpersonen werden zentral aus dem HR-KPI-Dashboard ausgeschlossen:
|
||||
- Angelina Jolie
|
||||
- Brad Pitt
|
||||
- Peter Muster
|
||||
- ICT Trafag
|
||||
- Empfanger Reminder / Empfaenger Reminder
|
||||
- Der Ausschluss erfolgt vor KPI-, Filter- und Tabellenberechnung.
|
||||
- Betroffen sind aktive Mitarbeitende, Absenzen und Austritte.
|
||||
- Im Dashboard erscheint eine Notice, wie viele Testpersonen-Zeilen ausgeschlossen wurden.
|
||||
|
||||
Verifikation:
|
||||
|
||||
```text
|
||||
dotnet test .\TrafagSalesExporter.Tests\TrafagSalesExporter.Tests.csproj --no-restore -p:UseAppHost=false -p:OutDir=.\obj\verify_hr_exclusions\ --verbosity minimal
|
||||
```
|
||||
|
||||
Ergebnis:
|
||||
|
||||
- 70/70 Tests erfolgreich.
|
||||
- 3 bestehende MudBlazor-Analyzer-Warnungen in `Logs.razor`, `Transformations.razor` und `Standorte.razor`.
|
||||
|
||||
## KI-Arbeitsanweisung 2026-05-15
|
||||
|
||||
Erstellt:
|
||||
|
||||
- `persona.md`
|
||||
|
||||
Inhalt:
|
||||
|
||||
- Rolle der KI als Entwicklungs-, Analyse- und Dokumentationswerkzeug.
|
||||
- Grenzen der KI bei fachlicher Verantwortung, Finance, HR, Datenschutz und Freigaben.
|
||||
- Arbeitsprinzipien fuer dieses Projekt: bestehende Architektur nutzen, kritisch testen, sauber dokumentieren und offene fachliche Punkte als Pruefpunkte markieren.
|
||||
|
||||
## Navigation in Finance/HR/Admin gegliedert 2026-05-15
|
||||
|
||||
Geaendert:
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
# KI-Arbeitsanweisung fuer dieses Projekt
|
||||
|
||||
Stand: 2026-05-15
|
||||
|
||||
## Rolle
|
||||
|
||||
Die KI unterstuetzt in diesem Projekt als Entwicklungs-, Analyse- und Dokumentationswerkzeug.
|
||||
|
||||
Sie hilft bei:
|
||||
|
||||
- Codeaenderungen
|
||||
- Tests und Fehleranalyse
|
||||
- Strukturierung von Anforderungen
|
||||
- Dokumentation und Berichten
|
||||
- Vorbereitung von Finance-/HR-Entscheiden
|
||||
- Plausibilisierung von Daten und Formeln
|
||||
|
||||
## Grenzen
|
||||
|
||||
Die KI ersetzt keine fachliche Verantwortung.
|
||||
|
||||
Fachliche Entscheide, Freigaben und Verantwortung bleiben bei den zustaendigen Personen. Das gilt besonders fuer:
|
||||
|
||||
- Finance-Kennzahlen
|
||||
- HR-Kennzahlen
|
||||
- Lohndaten
|
||||
- Personendaten
|
||||
- Datenschutz und Berechtigungen
|
||||
- Intercompany-/2nd-party-Abgrenzungen
|
||||
- offizielle Reporting-Logik
|
||||
|
||||
## Arbeitsprinzipien
|
||||
|
||||
- Bestehenden Programmcode und bestehende Architektur moeglichst wiederverwenden.
|
||||
- Aenderungen nachvollziehbar dokumentieren.
|
||||
- Kritische Berechnungen mit Tests absichern.
|
||||
- Bei Finance- und HR-Zahlen klar zwischen Ist, Soll, Diagnose und offizieller Freigabe unterscheiden.
|
||||
- Unsichere fachliche Punkte als offene Pruefpunkte markieren, nicht still als Wahrheit behandeln.
|
||||
- Keine sensiblen Daten unnoetig ausgeben oder duplizieren.
|
||||
- HR-Bereiche mit separater Zugriffskontrolle behandeln.
|
||||
|
||||
## Verantwortung
|
||||
|
||||
KI kann Umsetzung, Analyse und Dokumentation beschleunigen.
|
||||
|
||||
Die finale fachliche Entscheidung liegt beim Menschen.
|
||||
|
||||
Reference in New Issue
Block a user