From 92201d70182b2b45eb62ea27ec1757ca30c3899e Mon Sep 17 00:00:00 2001 From: Alexandra Date: Fri, 15 May 2026 13:55:38 +0200 Subject: [PATCH] BeWoDarmstadt/Teamuebersicht - Erweiterung QA um andere abrechenbare Stunden SupportOID=162860 --- .gitignore | 1 + .../BeWoDarmstadt/CustomReportCreator.cs | 190 +++++++++--------- ReportImp/BeWoDarmstadt/Teamuebersicht.cs | 116 ++++++++++- .../BeWoDarmstadt/Teamuebersicht.designer.cs | 2 +- 4 files changed, 203 insertions(+), 106 deletions(-) diff --git a/.gitignore b/.gitignore index eac96fd63..25de44304 100644 --- a/.gitignore +++ b/.gitignore @@ -417,3 +417,4 @@ FodyWeavers.xsd /ReportImp/RatPlusTat/CustomBudgetnachweisAnhangRO.cs /.claude/worktrees /.claude +/CLAUDE.md diff --git a/ReportImp/BeWoDarmstadt/CustomReportCreator.cs b/ReportImp/BeWoDarmstadt/CustomReportCreator.cs index d5d637b95..a5dde8422 100644 --- a/ReportImp/BeWoDarmstadt/CustomReportCreator.cs +++ b/ReportImp/BeWoDarmstadt/CustomReportCreator.cs @@ -16,124 +16,124 @@ using DevExpress.XtraReports.UI; namespace BeWoDarmstadt { - public class CustomReportCreator : DefaultReportCreator - { - public override XtraReport CreateQueryReport(long queryOid, string queryReportId) - { - if (queryOid == 100 || queryOid == 101) - { - return CreateZeitzuschlagsbeleg(queryOid, queryReportId); - } - if (queryOid == 110) - { - return CreateTeamuebersichtByCategory(queryOid, queryReportId, "qualifiziert"); - } - if (queryOid == 111) - { - return CreateTeamuebersichtByCategory(queryOid, queryReportId, "kompensatorisch"); - } - return base.CreateQueryReport(queryOid, queryReportId); + public class CustomReportCreator : DefaultReportCreator + { + public override XtraReport CreateQueryReport(long queryOid, string queryReportId) + { + if (queryOid == 100 || queryOid == 101) + { + return CreateZeitzuschlagsbeleg(queryOid, queryReportId); + } + if (queryOid == 110) + { + return CreateTeamuebersichtByCategory(queryOid, queryReportId, "qualifiziert"); + } + if (queryOid == 111) + { + return CreateTeamuebersichtByCategory(queryOid, queryReportId, "kompensatorisch"); + } + return base.CreateQueryReport(queryOid, queryReportId); } - private XtraReport CreateZeitzuschlagsbeleg(long queryOid, string queryReportId) - { - var query = DAOFactory.GenericDAO.LoadByID(queryOid); + private XtraReport CreateZeitzuschlagsbeleg(long queryOid, string queryReportId) + { + var query = DAOFactory.GenericDAO.LoadByID(queryOid); - if (query == null) - return new XtraReport(); + if (query == null) + return new XtraReport(); - var path = Path.Combine(TempPath, queryReportId + ".xml"); - var table = Utils.XMLDeserialize(path); - var qro = QueryRO.Create(query, table); + var path = Path.Combine(TempPath, queryReportId + ".xml"); + var table = Utils.XMLDeserialize(path); + var qro = QueryRO.Create(query, table); - if (qro.Rows.Count > 0) - { - long? employeeOid = BeWo.Data.Security.UserRightHelper.GetLoggedInUser().Employee.Oid; - if (qro.Rows[0].Field2 != null && qro.Rows[0].Field2.ToString() != "0") - employeeOid = Int64.Parse(qro.Rows[0].Field2.ToString()); + if (qro.Rows.Count > 0) + { + long? employeeOid = BeWo.Data.Security.UserRightHelper.GetLoggedInUser().Employee.Oid; + if (qro.Rows[0].Field2 != null && qro.Rows[0].Field2.ToString() != "0") + employeeOid = Int64.Parse(qro.Rows[0].Field2.ToString()); - DateTime monat = DateTime.Parse(qro.Rows[0].Field1.ToString()); - DateTimeSpan span = new DateTimeSpan(); - span.StartDateTime = monat; - span.EndDateTime = monat.AddMonths(1).AddTicks(-1); + DateTime monat = DateTime.Parse(qro.Rows[0].Field1.ToString()); + DateTimeSpan span = new DateTimeSpan(); + span.StartDateTime = monat; + span.EndDateTime = monat.AddMonths(1).AddTicks(-1); - MitarbeiterstundenkontoRO ro = MitarbeiterstundenkontoRO.Create(employeeOid, null, monat, monat.AddMonths(1), null); + MitarbeiterstundenkontoRO ro = MitarbeiterstundenkontoRO.Create(employeeOid, null, monat, monat.AddMonths(1), null); var msb = new CustomMitarbeiterstundenkontoBerechnung(); - msb.CreateReport(ro); + msb.CreateReport(ro); - XtraReport allReports = null; + XtraReport allReports = null; - foreach (var ed in ro.EmployeeDetailList) - { - ed.StundenGesamtIst += ed.Custom10; + foreach (var ed in ro.EmployeeDetailList) + { + ed.StundenGesamtIst += ed.Custom10; - Zeitzuschlagsbeleg beleg = new Zeitzuschlagsbeleg(); + Zeitzuschlagsbeleg beleg = new Zeitzuschlagsbeleg(); - beleg.SetReportDataSource(ro.ReportStartDate, ed); + beleg.SetReportDataSource(ro.ReportStartDate, ed); - beleg.CreateDocument(); - if (allReports == null) - allReports = beleg; - else - allReports.Pages.AddRange(beleg.Pages); - } + beleg.CreateDocument(); + if (allReports == null) + allReports = beleg; + else + allReports.Pages.AddRange(beleg.Pages); + } - if (allReports != null) - { - return allReports; - } - } - return new XtraReport(); + if (allReports != null) + { + return allReports; + } + } + return new XtraReport(); } - private XtraReport CreateTeamuebersichtByCategory(long queryOid, string queryReportId, string leistungskategorie) - { - var query = DAOFactory.GenericDAO.LoadByID(queryOid); + private XtraReport CreateTeamuebersichtByCategory(long queryOid, string queryReportId, string leistungskategorie) + { + var query = DAOFactory.GenericDAO.LoadByID(queryOid); - if (query == null) - return new XtraReport(); + if (query == null) + return new XtraReport(); - var path = Path.Combine(TempPath, queryReportId + ".xml"); - var table = Utils.XMLDeserialize(path); - var qro = QueryRO.Create(query, table); + var path = Path.Combine(TempPath, queryReportId + ".xml"); + var table = Utils.XMLDeserialize(path); + var qro = QueryRO.Create(query, table); - if (qro.Rows.Count > 0) - { - DateTime param = DateTime.Parse(qro.Rows[0].Field1.ToString()); - DateTime start = new DateTime(param.Year, 1, 1); - DateTime end = param.AddMonths(1).AddDays(-1); + if (qro.Rows.Count > 0) + { + DateTime param = DateTime.Parse(qro.Rows[0].Field1.ToString()); + DateTime start = new DateTime(param.Year, 1, 1); + DateTime end = param.AddMonths(1).AddDays(-1); - var ro = FinanceRO.Create(start, end, true, false); - ro.SupportConceptFinanceList = ro.SupportConceptFinanceList.Where(sc => sc.Leistungskategorie != null && - sc.Leistungskategorie.IndexOf(leistungskategorie, StringComparison.OrdinalIgnoreCase) >= 0).ToList(); + var ro = FinanceRO.Create(start, end, true, false); + ro.SupportConceptFinanceList = ro.SupportConceptFinanceList.Where(sc => sc.Leistungskategorie == null || + sc.Leistungskategorie.IndexOf(leistungskategorie, StringComparison.OrdinalIgnoreCase) >= 0).ToList(); - var druck = new Teamuebersicht(); - druck.SetReportDataSource(ro); - return druck; - } + var druck = new Teamuebersicht(); + druck.SetReportDataSource(ro); + return druck; + } - return new XtraReport(); - } + return new XtraReport(); + } - public override XtraReport CreateAuslastungReport(long? employeeOid, IList teamOids, DateTime startDate, DateTime endDate) - { - IBeWoReport report; - MitarbeiterauslastungRO x; - if (teamOids != null && teamOids.Count > 0) - { - IList employeeOids = new List(); - report = FindReportImp("TeamauslastungNachMitarbeiter"); - x = MitarbeiterauslastungRO.Create(employeeOids, teamOids, startDate, endDate, false); - } - else - { - report = FindReportImp("Mitarbeiterauslastung"); - x = MitarbeiterauslastungRO.Create(employeeOid, teamOids, startDate, endDate); - } + public override XtraReport CreateAuslastungReport(long? employeeOid, IList teamOids, DateTime startDate, DateTime endDate) + { + IBeWoReport report; + MitarbeiterauslastungRO x; + if (teamOids != null && teamOids.Count > 0) + { + IList employeeOids = new List(); + report = FindReportImp("TeamauslastungNachMitarbeiter"); + x = MitarbeiterauslastungRO.Create(employeeOids, teamOids, startDate, endDate, false); + } + else + { + report = FindReportImp("Mitarbeiterauslastung"); + x = MitarbeiterauslastungRO.Create(employeeOid, teamOids, startDate, endDate); + } - report.SetReportDataSource(x); + report.SetReportDataSource(x); - return report as XtraReport; - } - } + return report as XtraReport; + } + } } diff --git a/ReportImp/BeWoDarmstadt/Teamuebersicht.cs b/ReportImp/BeWoDarmstadt/Teamuebersicht.cs index f2c16c528..e55fadbe8 100644 --- a/ReportImp/BeWoDarmstadt/Teamuebersicht.cs +++ b/ReportImp/BeWoDarmstadt/Teamuebersicht.cs @@ -6,7 +6,9 @@ using BeWo.Data.Entities; using BeWo.Report; using BeWo.Report.ReportObjects; using BeWo.Service.DCEntityMapper; +using BS.Shared; using BS.Shared.DataContracts; +using BS.Shared.DataContracts.Compact; using BS.Shared.Extensions; using BS.Shared.Services; @@ -25,6 +27,13 @@ namespace BeWoDarmstadt DateTime end = pRO.ReportEndDate.Value; DateTime monthStart = new DateTime(pRO.ReportEndDate.Value.Year, pRO.ReportEndDate.Value.Month, 1); + // ServiceDescriptions einmal vorladen, falls QA-Einträge vorhanden sind + Dictionary serviceDictCache = null; + if (pRO.SupportConceptFinanceList != null && pRO.SupportConceptFinanceList.Any(sc => sc.Leistungskategorie != null && sc.Leistungskategorie.IndexOf("qualifiziert", StringComparison.OrdinalIgnoreCase) >= 0)) + { + serviceDictCache = LoadServiceDescriptionDict(); + } + if (pRO.SupportConceptFinanceList != null) { foreach (var scRo in pRO.SupportConceptFinanceList) @@ -39,22 +48,40 @@ namespace BeWoDarmstadt scRo.Custom1 = team; } if (scRo.Costbearer2Supportconcept.SupportConcept.Customer.CustomerAlias == null) + { scRo.Costbearer2Supportconcept.SupportConcept.Customer.CustomerAlias = scRo.Costbearer2Supportconcept.SupportConcept.CustomerFullName; - if (scRo.Costbearer2Supportconcept.SupportConcept.Customer.CustomerAlias == "513") - { - var Test = 1; - } + } + //if (scRo.Costbearer2Supportconcept.SupportConcept.Customer.CustomerAlias == "160") + // { + // var Test = 1; + // } - //Hole zus�tzlich Werte nur f�r einzelnen Monat + //Hole zusätzlich Werte nur für einzelnen Monat var cb2sc = scRo.Costbearer2Supportconcept; var costRateDcs = cb2sc.CostBearer.CostRatePeriods; var calc = BS.Shared.Services.Calculations.GetInstance(cb2sc.CostBearer.CostBearerID); scRo.ApprovedHours = GetApprovedHoursOhneFahrzeitForPeriod(cb2sc, monthStart, end, scRo.SupportConceptApprovalPeriod); scRo.BillableHours = 0; + scRo.BillableHoursInReportTimeSpan = 0; scRo.AmountPaid = 0; scRo.AmountTotal = 0; + // Bei qualifizierter Assistenz: alle abrechenbaren, nicht-kompensatorischen Records des Hilfeplanis hinzufügen, die noch nicht in ServiceRecords enthalten sind + // die dokumentieren teilweise völlig beliebig bei Gruppenbuchungen + if (scRo.Leistungskategorie != null && scRo.Leistungskategorie.IndexOf("qualifiziert", StringComparison.OrdinalIgnoreCase) >= 0 && serviceDictCache != null) + { + var existingOids = new HashSet((scRo.ServiceRecords ?? new List()).Where(r => r.ServiceRecordOid.HasValue).Select(r => r.ServiceRecordOid.Value)); + var additionalRecords = LoadBillableNonKompensatorischRecords(cb2sc, scRo, existingOids, serviceDictCache); + if (scRo.ServiceRecords == null) + { + scRo.ServiceRecords = additionalRecords; + } + else + { + scRo.ServiceRecords.AddRange(additionalRecords); + } + } if (scRo.ServiceRecords != null) { @@ -68,6 +95,10 @@ namespace BeWoDarmstadt { scRo.BillableHours += calc.GetBillableDurationInMinutes(sr, false) / 60; } + if (sr.Start >= start && sr.Start.Value.Date <= end) + { + scRo.BillableHoursInReportTimeSpan += calc.GetBillableDurationInMinutes(sr, false) / 60; + } } } } @@ -78,6 +109,75 @@ namespace BeWoDarmstadt this.bindingSource1.DataSource = pRO; } + private Dictionary LoadServiceDescriptionDict() + { + var allServiceDescs = DAOFactory.GenericDAO.GetAll(); + var dict = new Dictionary(); + foreach (var sd in allServiceDescs) + { + if (sd.Oid.HasValue) + { + dict[sd.Oid.Value] = MapperFactory.ServiceDescriptionDC_ServiceDescription.MapToNewDC(sd); + } + } + return dict; + } + + private List LoadBillableNonKompensatorischRecords( + SupportConceptCostBearerRelDC cb2sc, + FinanceRO.SupportConceptFinanceRO scRo, + HashSet existingOids, + Dictionary serviceDict) + { + var result = new List(); + + string sql = string.Format( + "SELECT Oid, Version, StartDate, EndDate, DistanceInMeter, CostBearer2SupportConceptOid, Betrag, ServiceDescriptionOid, RoundedDuration, GroupEmployeeCount, GroupPersonCount, GroupRoundedDuration, GroupOid " + + "FROM servicerecord WHERE CostBearer2SupportConceptOid = {0}", cb2sc.CostBearer2SupportConceptOid.Value); + + var sqlresult = DAOFactory.SearchDAO.GetSqlResult(sql); + + foreach (object[] row in sqlresult) + { + long? oid = (long?)row[0]; + if (!oid.HasValue || existingOids.Contains(oid.Value)) + continue; + + long? sdOid = (long?)row[7]; + if (!sdOid.HasValue || !serviceDict.ContainsKey(sdOid.Value)) + continue; + + var sd = serviceDict[sdOid.Value]; + if (sd.Category == null || + !sd.Category.IsBillable || + (sd.Category.Name ?? "").IndexOf("kompensatorisch", StringComparison.OrdinalIgnoreCase) >= 0) + continue; + + var sr = new ServiceRecordDC(); + sr.ServiceRecordOid = oid; + sr.ServiceRecordVersion = (long?)row[1]; + sr.Start = (DateTime?)row[2]; + sr.End = (DateTime?)row[3]; + sr.CostBearer2SupportConceptOid = (long?)row[5]; + sr.Betrag = (decimal?)row[6]; + sr.ServiceDescription = sd; + sr.RoundedDuration = (decimal)row[8]; + sr.GroupEmployeeCount = (int?)row[9]; + sr.GroupPersonCount = (int?)row[10]; + sr.GroupRoundedDuration = (decimal?)row[11]; + sr.GroupOid = (long?)row[12]; + // Pflichtfelder für GetBillableDurationInMinutes (analog zu FinanceRO.Create) + sr.Employee = new CompactEmployeeDC { ValueListEntries = new Dictionary() }; + sr.CostBearer = cb2sc.CostBearer; + sr.SupportConcept = scRo.Costbearer2Supportconcept.SupportConcept; + sr.Customer = scRo.Costbearer2Supportconcept.SupportConcept.Customer; + + result.Add(sr); + } + + return result; + } + private string GetTeams(FinanceRO.SupportConceptFinanceRO scRo) { var c = DAOFactory.GenericDAO.GetByID(scRo.Costbearer2Supportconcept.SupportConcept.Customer.CustomerOid); @@ -88,12 +188,8 @@ namespace BeWoDarmstadt return scRo.Costbearer2Supportconcept.SupportConcept.Customer.RelatedTeams; } - private decimal GetApprovedHoursOhneFahrzeitForPeriod(SupportConceptCostBearerRelDC relDC, - DateTime pStart, - DateTime pEnd, - SupportConceptApprovalPeriodDC filterScap = null) + private decimal GetApprovedHoursOhneFahrzeitForPeriod(SupportConceptCostBearerRelDC relDC, DateTime pStart, DateTime pEnd, SupportConceptApprovalPeriodDC filterScap = null) { - var costRatePeriods = relDC.CostBearer.CostRatePeriods; decimal approvedHours = 0; DateTime start = pStart; diff --git a/ReportImp/BeWoDarmstadt/Teamuebersicht.designer.cs b/ReportImp/BeWoDarmstadt/Teamuebersicht.designer.cs index a54996539..6c8881fd3 100644 --- a/ReportImp/BeWoDarmstadt/Teamuebersicht.designer.cs +++ b/ReportImp/BeWoDarmstadt/Teamuebersicht.designer.cs @@ -303,7 +303,7 @@ namespace BeWoDarmstadt this.lblTitel.Padding = new DevExpress.XtraPrinting.PaddingInfo(2, 2, 0, 0, 100F); this.lblTitel.SizeF = new System.Drawing.SizeF(652.9166F, 23F); this.lblTitel.StylePriority.UseFont = false; - this.lblTitel.Text = "Monats�bersicht je Team f�r [ReportEndDate!MMMM] [ReportEndDate!yyyy] "; + this.lblTitel.Text = "Monatsübersicht je Team für [ReportEndDate!MMMM] [ReportEndDate!yyyy] "; // // DetailReport //