BeWoDarmstadt/Teamuebersicht - Erweiterung QA um andere abrechenbare Stunden

SupportOID=162860
This commit is contained in:
2026-05-15 13:55:38 +02:00
parent f7b1d991bf
commit 92201d7018
4 changed files with 203 additions and 106 deletions

1
.gitignore vendored
View File

@@ -417,3 +417,4 @@ FodyWeavers.xsd
/ReportImp/RatPlusTat/CustomBudgetnachweisAnhangRO.cs /ReportImp/RatPlusTat/CustomBudgetnachweisAnhangRO.cs
/.claude/worktrees /.claude/worktrees
/.claude /.claude
/CLAUDE.md

View File

@@ -16,124 +16,124 @@ using DevExpress.XtraReports.UI;
namespace BeWoDarmstadt namespace BeWoDarmstadt
{ {
public class CustomReportCreator : DefaultReportCreator public class CustomReportCreator : DefaultReportCreator
{ {
public override XtraReport CreateQueryReport(long queryOid, string queryReportId) public override XtraReport CreateQueryReport(long queryOid, string queryReportId)
{ {
if (queryOid == 100 || queryOid == 101) if (queryOid == 100 || queryOid == 101)
{ {
return CreateZeitzuschlagsbeleg(queryOid, queryReportId); return CreateZeitzuschlagsbeleg(queryOid, queryReportId);
} }
if (queryOid == 110) if (queryOid == 110)
{ {
return CreateTeamuebersichtByCategory(queryOid, queryReportId, "qualifiziert"); return CreateTeamuebersichtByCategory(queryOid, queryReportId, "qualifiziert");
} }
if (queryOid == 111) if (queryOid == 111)
{ {
return CreateTeamuebersichtByCategory(queryOid, queryReportId, "kompensatorisch"); return CreateTeamuebersichtByCategory(queryOid, queryReportId, "kompensatorisch");
} }
return base.CreateQueryReport(queryOid, queryReportId); return base.CreateQueryReport(queryOid, queryReportId);
} }
private XtraReport CreateZeitzuschlagsbeleg(long queryOid, string queryReportId) private XtraReport CreateZeitzuschlagsbeleg(long queryOid, string queryReportId)
{ {
var query = DAOFactory.GenericDAO.LoadByID<Query>(queryOid); var query = DAOFactory.GenericDAO.LoadByID<Query>(queryOid);
if (query == null) if (query == null)
return new XtraReport(); return new XtraReport();
var path = Path.Combine(TempPath, queryReportId + ".xml"); var path = Path.Combine(TempPath, queryReportId + ".xml");
var table = Utils.XMLDeserialize<DataTable>(path); var table = Utils.XMLDeserialize<DataTable>(path);
var qro = QueryRO.Create(query, table); var qro = QueryRO.Create(query, table);
if (qro.Rows.Count > 0) if (qro.Rows.Count > 0)
{ {
long? employeeOid = BeWo.Data.Security.UserRightHelper.GetLoggedInUser().Employee.Oid; long? employeeOid = BeWo.Data.Security.UserRightHelper.GetLoggedInUser().Employee.Oid;
if (qro.Rows[0].Field2 != null && qro.Rows[0].Field2.ToString() != "0") if (qro.Rows[0].Field2 != null && qro.Rows[0].Field2.ToString() != "0")
employeeOid = Int64.Parse(qro.Rows[0].Field2.ToString()); employeeOid = Int64.Parse(qro.Rows[0].Field2.ToString());
DateTime monat = DateTime.Parse(qro.Rows[0].Field1.ToString()); DateTime monat = DateTime.Parse(qro.Rows[0].Field1.ToString());
DateTimeSpan span = new DateTimeSpan(); DateTimeSpan span = new DateTimeSpan();
span.StartDateTime = monat; span.StartDateTime = monat;
span.EndDateTime = monat.AddMonths(1).AddTicks(-1); 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(); var msb = new CustomMitarbeiterstundenkontoBerechnung();
msb.CreateReport(ro); msb.CreateReport(ro);
XtraReport allReports = null; XtraReport allReports = null;
foreach (var ed in ro.EmployeeDetailList) foreach (var ed in ro.EmployeeDetailList)
{ {
ed.StundenGesamtIst += ed.Custom10; ed.StundenGesamtIst += ed.Custom10;
Zeitzuschlagsbeleg beleg = new Zeitzuschlagsbeleg(); Zeitzuschlagsbeleg beleg = new Zeitzuschlagsbeleg();
beleg.SetReportDataSource(ro.ReportStartDate, ed); beleg.SetReportDataSource(ro.ReportStartDate, ed);
beleg.CreateDocument(); beleg.CreateDocument();
if (allReports == null) if (allReports == null)
allReports = beleg; allReports = beleg;
else else
allReports.Pages.AddRange(beleg.Pages); allReports.Pages.AddRange(beleg.Pages);
} }
if (allReports != null) if (allReports != null)
{ {
return allReports; return allReports;
} }
} }
return new XtraReport(); return new XtraReport();
} }
private XtraReport CreateTeamuebersichtByCategory(long queryOid, string queryReportId, string leistungskategorie) private XtraReport CreateTeamuebersichtByCategory(long queryOid, string queryReportId, string leistungskategorie)
{ {
var query = DAOFactory.GenericDAO.LoadByID<Query>(queryOid); var query = DAOFactory.GenericDAO.LoadByID<Query>(queryOid);
if (query == null) if (query == null)
return new XtraReport(); return new XtraReport();
var path = Path.Combine(TempPath, queryReportId + ".xml"); var path = Path.Combine(TempPath, queryReportId + ".xml");
var table = Utils.XMLDeserialize<DataTable>(path); var table = Utils.XMLDeserialize<DataTable>(path);
var qro = QueryRO.Create(query, table); var qro = QueryRO.Create(query, table);
if (qro.Rows.Count > 0) if (qro.Rows.Count > 0)
{ {
DateTime param = DateTime.Parse(qro.Rows[0].Field1.ToString()); DateTime param = DateTime.Parse(qro.Rows[0].Field1.ToString());
DateTime start = new DateTime(param.Year, 1, 1); DateTime start = new DateTime(param.Year, 1, 1);
DateTime end = param.AddMonths(1).AddDays(-1); DateTime end = param.AddMonths(1).AddDays(-1);
var ro = FinanceRO.Create(start, end, true, false); var ro = FinanceRO.Create(start, end, true, false);
ro.SupportConceptFinanceList = ro.SupportConceptFinanceList.Where(sc => sc.Leistungskategorie != null && ro.SupportConceptFinanceList = ro.SupportConceptFinanceList.Where(sc => sc.Leistungskategorie == null ||
sc.Leistungskategorie.IndexOf(leistungskategorie, StringComparison.OrdinalIgnoreCase) >= 0).ToList(); sc.Leistungskategorie.IndexOf(leistungskategorie, StringComparison.OrdinalIgnoreCase) >= 0).ToList();
var druck = new Teamuebersicht(); var druck = new Teamuebersicht();
druck.SetReportDataSource(ro); druck.SetReportDataSource(ro);
return druck; return druck;
} }
return new XtraReport(); return new XtraReport();
} }
public override XtraReport CreateAuslastungReport(long? employeeOid, IList<long> teamOids, DateTime startDate, DateTime endDate) public override XtraReport CreateAuslastungReport(long? employeeOid, IList<long> teamOids, DateTime startDate, DateTime endDate)
{ {
IBeWoReport<MitarbeiterauslastungRO> report; IBeWoReport<MitarbeiterauslastungRO> report;
MitarbeiterauslastungRO x; MitarbeiterauslastungRO x;
if (teamOids != null && teamOids.Count > 0) if (teamOids != null && teamOids.Count > 0)
{ {
IList<long> employeeOids = new List<long>(); IList<long> employeeOids = new List<long>();
report = FindReportImp<MitarbeiterauslastungRO>("TeamauslastungNachMitarbeiter"); report = FindReportImp<MitarbeiterauslastungRO>("TeamauslastungNachMitarbeiter");
x = MitarbeiterauslastungRO.Create(employeeOids, teamOids, startDate, endDate, false); x = MitarbeiterauslastungRO.Create(employeeOids, teamOids, startDate, endDate, false);
} }
else else
{ {
report = FindReportImp<MitarbeiterauslastungRO>("Mitarbeiterauslastung"); report = FindReportImp<MitarbeiterauslastungRO>("Mitarbeiterauslastung");
x = MitarbeiterauslastungRO.Create(employeeOid, teamOids, startDate, endDate); x = MitarbeiterauslastungRO.Create(employeeOid, teamOids, startDate, endDate);
} }
report.SetReportDataSource(x); report.SetReportDataSource(x);
return report as XtraReport; return report as XtraReport;
} }
} }
} }

View File

@@ -6,7 +6,9 @@ using BeWo.Data.Entities;
using BeWo.Report; using BeWo.Report;
using BeWo.Report.ReportObjects; using BeWo.Report.ReportObjects;
using BeWo.Service.DCEntityMapper; using BeWo.Service.DCEntityMapper;
using BS.Shared;
using BS.Shared.DataContracts; using BS.Shared.DataContracts;
using BS.Shared.DataContracts.Compact;
using BS.Shared.Extensions; using BS.Shared.Extensions;
using BS.Shared.Services; using BS.Shared.Services;
@@ -25,6 +27,13 @@ namespace BeWoDarmstadt
DateTime end = pRO.ReportEndDate.Value; DateTime end = pRO.ReportEndDate.Value;
DateTime monthStart = new DateTime(pRO.ReportEndDate.Value.Year, pRO.ReportEndDate.Value.Month, 1); DateTime monthStart = new DateTime(pRO.ReportEndDate.Value.Year, pRO.ReportEndDate.Value.Month, 1);
// ServiceDescriptions einmal vorladen, falls QA-Einträge vorhanden sind
Dictionary<long, ServiceDescriptionDC> 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) if (pRO.SupportConceptFinanceList != null)
{ {
foreach (var scRo in pRO.SupportConceptFinanceList) foreach (var scRo in pRO.SupportConceptFinanceList)
@@ -39,22 +48,40 @@ namespace BeWoDarmstadt
scRo.Custom1 = team; scRo.Custom1 = team;
} }
if (scRo.Costbearer2Supportconcept.SupportConcept.Customer.CustomerAlias == null) if (scRo.Costbearer2Supportconcept.SupportConcept.Customer.CustomerAlias == null)
{
scRo.Costbearer2Supportconcept.SupportConcept.Customer.CustomerAlias = scRo.Costbearer2Supportconcept.SupportConcept.CustomerFullName; scRo.Costbearer2Supportconcept.SupportConcept.Customer.CustomerAlias = scRo.Costbearer2Supportconcept.SupportConcept.CustomerFullName;
if (scRo.Costbearer2Supportconcept.SupportConcept.Customer.CustomerAlias == "513") }
{ //if (scRo.Costbearer2Supportconcept.SupportConcept.Customer.CustomerAlias == "160")
var Test = 1; // {
} // var Test = 1;
// }
//Hole zus<EFBFBD>tzlich Werte nur f<EFBFBD>r einzelnen Monat //Hole zusätzlich Werte nur für einzelnen Monat
var cb2sc = scRo.Costbearer2Supportconcept; var cb2sc = scRo.Costbearer2Supportconcept;
var costRateDcs = cb2sc.CostBearer.CostRatePeriods; var costRateDcs = cb2sc.CostBearer.CostRatePeriods;
var calc = BS.Shared.Services.Calculations.GetInstance(cb2sc.CostBearer.CostBearerID); var calc = BS.Shared.Services.Calculations.GetInstance(cb2sc.CostBearer.CostBearerID);
scRo.ApprovedHours = GetApprovedHoursOhneFahrzeitForPeriod(cb2sc, monthStart, end, scRo.SupportConceptApprovalPeriod); scRo.ApprovedHours = GetApprovedHoursOhneFahrzeitForPeriod(cb2sc, monthStart, end, scRo.SupportConceptApprovalPeriod);
scRo.BillableHours = 0; scRo.BillableHours = 0;
scRo.BillableHoursInReportTimeSpan = 0;
scRo.AmountPaid = 0; scRo.AmountPaid = 0;
scRo.AmountTotal = 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<long>((scRo.ServiceRecords ?? new List<ServiceRecordDC>()).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) if (scRo.ServiceRecords != null)
{ {
@@ -68,6 +95,10 @@ namespace BeWoDarmstadt
{ {
scRo.BillableHours += calc.GetBillableDurationInMinutes(sr, false) / 60; 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; this.bindingSource1.DataSource = pRO;
} }
private Dictionary<long, ServiceDescriptionDC> LoadServiceDescriptionDict()
{
var allServiceDescs = DAOFactory.GenericDAO.GetAll<ServiceDescription>();
var dict = new Dictionary<long, ServiceDescriptionDC>();
foreach (var sd in allServiceDescs)
{
if (sd.Oid.HasValue)
{
dict[sd.Oid.Value] = MapperFactory.ServiceDescriptionDC_ServiceDescription.MapToNewDC(sd);
}
}
return dict;
}
private List<ServiceRecordDC> LoadBillableNonKompensatorischRecords(
SupportConceptCostBearerRelDC cb2sc,
FinanceRO.SupportConceptFinanceRO scRo,
HashSet<long> existingOids,
Dictionary<long, ServiceDescriptionDC> serviceDict)
{
var result = new List<ServiceRecordDC>();
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<long, ValueListEntryType>() };
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) private string GetTeams(FinanceRO.SupportConceptFinanceRO scRo)
{ {
var c = DAOFactory.GenericDAO.GetByID<Customer>(scRo.Costbearer2Supportconcept.SupportConcept.Customer.CustomerOid); var c = DAOFactory.GenericDAO.GetByID<Customer>(scRo.Costbearer2Supportconcept.SupportConcept.Customer.CustomerOid);
@@ -88,12 +188,8 @@ namespace BeWoDarmstadt
return scRo.Costbearer2Supportconcept.SupportConcept.Customer.RelatedTeams; return scRo.Costbearer2Supportconcept.SupportConcept.Customer.RelatedTeams;
} }
private decimal GetApprovedHoursOhneFahrzeitForPeriod(SupportConceptCostBearerRelDC relDC, private decimal GetApprovedHoursOhneFahrzeitForPeriod(SupportConceptCostBearerRelDC relDC, DateTime pStart, DateTime pEnd, SupportConceptApprovalPeriodDC filterScap = null)
DateTime pStart,
DateTime pEnd,
SupportConceptApprovalPeriodDC filterScap = null)
{ {
var costRatePeriods = relDC.CostBearer.CostRatePeriods; var costRatePeriods = relDC.CostBearer.CostRatePeriods;
decimal approvedHours = 0; decimal approvedHours = 0;
DateTime start = pStart; DateTime start = pStart;

View File

@@ -303,7 +303,7 @@ namespace BeWoDarmstadt
this.lblTitel.Padding = new DevExpress.XtraPrinting.PaddingInfo(2, 2, 0, 0, 100F); this.lblTitel.Padding = new DevExpress.XtraPrinting.PaddingInfo(2, 2, 0, 0, 100F);
this.lblTitel.SizeF = new System.Drawing.SizeF(652.9166F, 23F); this.lblTitel.SizeF = new System.Drawing.SizeF(652.9166F, 23F);
this.lblTitel.StylePriority.UseFont = false; this.lblTitel.StylePriority.UseFont = false;
this.lblTitel.Text = "Monats<EFBFBD>bersicht je Team f<EFBFBD>r [ReportEndDate!MMMM] [ReportEndDate!yyyy] "; this.lblTitel.Text = "Monatsübersicht je Team für [ReportEndDate!MMMM] [ReportEndDate!yyyy] ";
// //
// DetailReport // DetailReport
// //