MH: LebenshilfeStadeMID Ausnahmefall Pausen Timo

SupportOID=168937
This commit is contained in:
2026-07-24 12:10:57 +02:00
parent 56f94efb5f
commit 2aa6c10bfb

View File

@@ -11,8 +11,10 @@ namespace LebenshilfeStadeMID
public class CustomMitarbeiterstundenkontoBerechnung : MitarbeiterstundenkontoBerechnung
{
private const int ANZ_WOCHENTAGE = 5;
private Dictionary<string, decimal> _SollStundenProTagDict = new Dictionary<string, decimal>(); //Speicher die Sollstunden aus den Betreuungszeiten des Kindes pro EmployeeOid und Tag (Key = {employee oid}_{datum])
private Dictionary<string, decimal> _SollStundenProTagDict = new Dictionary<string, decimal>(); //Speicher die Sollstunden aus den Betreuungszeiten des Kindes pro EmployeeOid und Tag (Key = {employee oid}_{datum])
private DateTime _BerichtsAnfang = DateTime.MinValue;
// Claude: Sonderfall Timo Lafram Cache CustomerOid -> ist dieser Klient (vermeidet wiederholtes Nachladen des Customers)
private readonly Dictionary<long, bool> _IstTimoLaframCache = new Dictionary<long, bool>();
protected override void StarteBerechnung(DateTime berichtsAnfang, DateTime berichtsEnde, MitarbeiterstundenkontoRO.EmployeeDetail empDetail)
{
@@ -273,6 +275,106 @@ namespace LebenshilfeStadeMID
return dd;
}
// Claude: Sonderfall Klient "Timo Lafram" für zusammenhängende Arbeitsblöcke, die (auch) Zeit für diesen
// Klienten enthalten, wird KEINE automatische Pause abgezogen. Alle übrigen Tage/Blöcke bleiben unverändert
// (Standardverhalten wie bisher = SONST IMMER Pause).
public override decimal CalculateBreakMinutesNeu(MitarbeiterstundenkontoRO.DayDetail dayDetail)
{
// Kein Timo-Lafram-Eintrag an diesem Tag -> unverändertes Standardverhalten
if (dayDetail.ServiceRecords == null || !dayDetail.ServiceRecords.Any(IstTimoLaframRecord))
{
return base.CalculateBreakMinutesNeu(dayDetail);
}
decimal addHours = 0;
if (dayDetail.ZusammenhaengendeZeitraeume != null && dayDetail.ZusammenhaengendeZeitraeume.Count > 0)
{
foreach (var span in dayDetail.ZusammenhaengendeZeitraeume)
{
// Blöcke mit Timo-Lafram-Zeit: keine automatische Pause abziehen
if (SpanEnthaeltTimoLaframZeit(dayDetail, span.StartDateTime, span.EndDateTime))
continue;
addHours -= BerechneGesetzlichePauseInMinuten(dayDetail, span.StartDateTime, span.EndDateTime) / 60;
}
return addHours;
}
// Fallback (keine ZusammenhaengendeZeitraeume) analog zum Standard, Timo-Lafram-Blöcke überspringen
if (dayDetail.EndDateTime1.HasValue && dayDetail.StartDateTime1.HasValue
&& !SpanEnthaeltTimoLaframZeit(dayDetail, dayDetail.StartDateTime1.Value, dayDetail.EndDateTime1.Value))
{
addHours -= BerechneGesetzlichePauseInMinuten(dayDetail, dayDetail.StartDateTime1.Value, dayDetail.EndDateTime1.Value) / 60;
}
if (dayDetail.EndDateTime2.HasValue && dayDetail.StartDateTime2.HasValue
&& !SpanEnthaeltTimoLaframZeit(dayDetail, dayDetail.StartDateTime2.Value, dayDetail.EndDateTime2.Value))
{
addHours -= BerechneGesetzlichePauseInMinuten(dayDetail, dayDetail.StartDateTime2.Value, dayDetail.EndDateTime2.Value) / 60;
}
if (dayDetail.EndDateTime3.HasValue && dayDetail.StartDateTime3.HasValue
&& !SpanEnthaeltTimoLaframZeit(dayDetail, dayDetail.StartDateTime3.Value, dayDetail.EndDateTime3.Value))
{
addHours -= BerechneGesetzlichePauseInMinuten(dayDetail, dayDetail.StartDateTime3.Value, dayDetail.EndDateTime3.Value) / 60;
}
if (dayDetail.EndDateTime4.HasValue && dayDetail.StartDateTime4.HasValue
&& !SpanEnthaeltTimoLaframZeit(dayDetail, dayDetail.StartDateTime4.Value, dayDetail.EndDateTime4.Value))
{
addHours -= BerechneGesetzlichePauseInMinuten(dayDetail, dayDetail.StartDateTime4.Value, dayDetail.EndDateTime4.Value) / 60;
}
return addHours;
}
// Claude: Prüft, ob im angegebenen Zeitraum (zusammenhängender Arbeitsblock) ein ServiceRecord für den
// Klienten "Timo Lafram" liegt. Die Blöcke werden aus den Startzeiten der Records gebildet, daher genügt
// die Prüfung, ob der Start eines Timo-Records innerhalb des Blocks liegt.
private bool SpanEnthaeltTimoLaframZeit(MitarbeiterstundenkontoRO.DayDetail dayDetail, DateTime spanStart, DateTime spanEnde)
{
if (dayDetail.ServiceRecords == null)
return false;
foreach (var sr in dayDetail.ServiceRecords)
{
if (!IstTimoLaframRecord(sr))
continue;
if (sr.Start >= spanStart && sr.Start < spanEnde)
return true;
}
return false;
}
// Claude: Erkennt den Klienten "Timo Lafram" über den Namen (Vorname + Nachname, Groß/Klein und
// Leerzeichen unkritisch). Ergebnis wird je CustomerOid gecacht.
private bool IstTimoLaframRecord(StundenkontoServiceRecord sr)
{
if (sr == null || !sr.CustomerOid.HasValue)
return false;
long oid = sr.CustomerOid.Value;
bool istTimo;
if (_IstTimoLaframCache.TryGetValue(oid, out istTimo))
return istTimo;
istTimo = false;
var customer = sr.Customer;
if (customer != null && customer.Person != null)
{
var vorname = (customer.Person.FirstName ?? "").Trim();
var nachname = (customer.Person.LastName ?? "").Trim();
istTimo = vorname.Equals("Timo", StringComparison.OrdinalIgnoreCase)
&& nachname.Equals("Lafram", StringComparison.OrdinalIgnoreCase);
}
_IstTimoLaframCache[oid] = istTimo;
return istTimo;
}
public override decimal? GetSollStundenForAbsenceTime(MitarbeiterstundenkontoRO.EmployeeDetail ed, AbsenceTime at, DateTime datum)
{
var key = String.Format("{0}_{1:yyyyMMdd}", ed.Employee.Oid, datum);