MH: AsbRheinErftDuerenSBD qual.abh. Stundensätze

This commit is contained in:
2026-07-22 15:04:42 +02:00
parent f491354f65
commit 89eacef09f
2 changed files with 145 additions and 1 deletions

View File

@@ -64,5 +64,149 @@ namespace AsbRheinErftDuerenSBD.Invoicing
}); ; }); ;
} }
} }
public override IList<InvoiceItem> CreateInvoiceItems(List<ServiceRecordDC> serviceRecordsInPeriod, DateTimeSpan invoicePeriod, SupportConceptApprovalPeriod scap, Calculations calc)
{
IList<InvoiceItem> result = new List<InvoiceItem>();
var list = new List<InvoiceItem>();
foreach (ServiceRecordDC iServiceRecord in serviceRecordsInPeriod)
{
if (iServiceRecord.ServiceDescription.Category.IsBillable)
{
if (!iServiceRecord.AlreadyAccounted)
{
InvoiceItem invoiceItem = CreateInvoiceItem(iServiceRecord, scap, calc);
if (invoiceItem != null)
{
invoiceItem.ItemDescription = String.Format("{0} {1}", iServiceRecord.Employee.FirstName, iServiceRecord.Employee.LastName);
if (iServiceRecord.ServiceDescription.Category.Name.Contains("Sonstige"))
{
invoiceItem.ItemDescription += "\n" + iServiceRecord.ServiceDescription.Name;
}
list.Add(invoiceItem);
}
iServiceRecord.AlreadyAccounted = true;
}
}
}
Dictionary<String, bool> dayDict = new Dictionary<String, bool>();
foreach (var item in list)
{
String key = String.Format("{0:dd.MM.yyyy}", item.ItemPeriodStart);
if (!dayDict.ContainsKey(key))
{
dayDict.Add(key, true);
}
result.Add(item);
}
var newList = result.Where(i => i.UnitCount.HasValue && i.UnitCount.Value > 0).OrderBy(i => i.ItemPeriodStart).ToList();
return CreateSummaryInvoiceItems(newList, invoicePeriod, scap, calc);
}
// Claude: Der Stundensatz richtet sich nach der Qualifikation des dokumentierenden Mitarbeiters.
// Vorbild: TeamPfeil/Invoicing/CustomInvoiceCreation.cs (ohne Korridor-Logik).
public override InvoiceItem CreateInvoiceItem(ServiceRecordDC iServiceRecord, SupportConceptApprovalPeriod scap, Calculations calc)
{
var invoiceItem = new InvoiceItem();
// Standardabrechnungsdaten des ServiceRecords. Diese berücksichtigen bereits die normale
// CostRatePeriod des Kostenträgers, ggf. überschrieben durch die CostRatePeriods der
// ServiceDescription bzw. ServiceCategory. Sie dienen als Fallback, wenn keine
// (passende) Mitarbeiterqualifikation gefunden wird.
BillingData bd = calc.GetBillingData(iServiceRecord);
decimal stundensatz = 0;
// Claude: Qualifikation des Mitarbeiters ermitteln.
var qualifikation = iServiceRecord.Employee.ValueListEntries
.FirstOrDefault(v => v.Value == ValueListEntryType.StaffQualificationsType);
long qualiOid = qualifikation.Key;
// Claude: Für diese Qualifikationen (OID 70/71) gibt es eigene Stundensätze im Kostenträger.
if (qualiOid == 70) // Fachkraft
{
stundensatz = GetStundensatz(scap.CostBearer2SupportConcept, qualiOid, iServiceRecord.Start);
invoiceItem.ItemDescription = "Fachkraft";
}
else if (qualiOid == 71) // Hilfskraft
{
stundensatz = GetStundensatz(scap.CostBearer2SupportConcept, qualiOid, iServiceRecord.Start);
invoiceItem.ItemDescription = "Hilfskraft";
}
// Gibt es Stundensätze für Leistung oder Leistungskategorie, müssen die natürlich überschreiben
if (iServiceRecord.ServiceDescription.CostRatePeriods != null && iServiceRecord.ServiceDescription.CostRatePeriods.Count > 0)
{
var crp = iServiceRecord.ServiceDescription.CostRatePeriods.GetCostRatePeriodForDate(CostRatePeriodType.AmountOfMoney, iServiceRecord.Start.Value);
if (crp != null && crp.CostRateValue != null && crp.CostRateValue > 0)
{
stundensatz = crp.CostRateValue.Value;
}
}
else if (iServiceRecord.ServiceDescription.Category.CostRatePeriods != null && iServiceRecord.ServiceDescription.Category.CostRatePeriods.Count > 0)
{
var crp = iServiceRecord.ServiceDescription.Category.CostRatePeriods.GetCostRatePeriodForDate(CostRatePeriodType.AmountOfMoney, iServiceRecord.Start.Value);
if (crp != null && crp.CostRateValue != null && crp.CostRateValue > 0)
{
stundensatz = crp.CostRateValue.Value;
}
}
if (stundensatz != 0)
{
// Claude: Qualifikationsabhängiger Stundensatz gefunden -> diesen verwenden.
invoiceItem.AmountPerUnit = stundensatz;
invoiceItem.AmountTotal = stundensatz * bd.UnitCount;
invoiceItem.GrossAmountTotal = stundensatz * bd.UnitCount;
}
else
{
// Claude: Keine (passende) Qualifikation -> Standardabrechnung wie in InvoiceCreation.
invoiceItem.AmountPerUnit = bd.AmountPerUnit;
invoiceItem.AmountTotal = bd.AmountTotal;
invoiceItem.GrossAmountTotal = bd.GrossAmountTotal;
invoiceItem.ItemDescription = iServiceRecord.ServiceDescription.Name;
}
invoiceItem.UnitCount = bd.UnitCount;
invoiceItem.ItemPeriodStart = bd.BillingPeriodStart;
invoiceItem.ItemPeriodEnd = bd.BillingPeriodEnd;
invoiceItem.RateFactor = bd.RateFactor;
invoiceItem.AccountingInterval = bd.AccountingInterval;
invoiceItem.ServiceRecord = DAOFactory.GenericDAO.LoadByID<ServiceRecord>(iServiceRecord.ServiceRecordOid.Value);
if (scap != null)
invoiceItem.SupportConceptApprovalPeriodOid = scap.Oid;
return invoiceItem;
}
// Claude: Liefert den qualifikationsabhängigen Stundensatz (HourlyRate) des Kostenträgers, sonst 0.
private decimal GetStundensatz(CostBearer2SupportConcept c2s, long vleOid, DateTime? date)
{
if (c2s.CostBearer.CostRatePeriods != null)
{
// ValueListEntryOid:
// 70 Fachkraft
// 71 Hilfskraft
var crpList = MapperFactory.CostRatePeriodDC_CostRatePeriod.MapToNewDCs(c2s.CostBearer.CostRatePeriods);
var cp = crpList.GetCostRatePeriodForDate(CostRatePeriodType.HourlyRate, (DateTime)date, vleOid);
if (cp != null && cp.CostRateValue.HasValue)
{
return cp.CostRateValue.Value;
}
}
return 0;
}
} }
} }

View File

@@ -134,7 +134,7 @@ namespace AsbRheinErftDuerenSBD.Invoicing
invoiceItem.UnitCount = bd.UnitCount; invoiceItem.UnitCount = bd.UnitCount;
invoiceItem.ItemPeriodStart = bd.BillingPeriodStart; invoiceItem.ItemPeriodStart = bd.BillingPeriodStart;
invoiceItem.ItemPeriodEnd = bd.BillingPeriodEnd; invoiceItem.ItemPeriodEnd = bd.BillingPeriodEnd;
invoiceItem.RateFactor = bd.RateFactor; invoiceItem.RateFactor = bd.RateFactor;