776 lines
29 KiB
C#
776 lines
29 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
|
|
using BeWo.Data.Access;
|
|
using BeWo.Data.Entities;
|
|
using BeWo.Service.DCEntityMapper;
|
|
|
|
using BS.Shared;
|
|
using BS.Shared.Core;
|
|
using BS.Shared.DataContracts;
|
|
using BS.Shared.DataContracts.Compact;
|
|
using BS.Shared.Extensions;
|
|
using BS.Shared.Services;
|
|
using BeWo.Service.Configuration;
|
|
|
|
namespace BeWo.Service.Plugins
|
|
{
|
|
public class ServiceRecordValidator : AbstractIDSpecificDefaultClass<ServiceRecordValidator>
|
|
{
|
|
public virtual Dictionary<ServiceRecordDC, List<ServiceRecordValidationResult>> ValidateGroupServiceRecordEntry(ServiceRecordDC pServiceRecord, List<ServiceRecordDC> groupServiceRecords, List<CompactEmployeeDC> employees, DateTime? date, int maxDaysEditServiceRecordsAllowed, decimal flsTotalRounded, out Dictionary<long, string> overlappingRecords, out Dictionary<long, string> overlappingEmployees)
|
|
{
|
|
var result = new Dictionary<ServiceRecordDC, List<ServiceRecordValidationResult>>();
|
|
overlappingRecords = new Dictionary<long, string>();
|
|
overlappingEmployees = new Dictionary<long, string>();
|
|
long gid = pServiceRecord.GroupOid ?? -1;
|
|
|
|
|
|
foreach (ServiceRecordDC groupRecord in groupServiceRecords)
|
|
{
|
|
DateTime start = groupRecord.Start.Value;
|
|
bool noTime = start.Hour == 0 && start.Minute == 0 && start.Second == 1; //Keine Zeit angegeben
|
|
|
|
if (!noTime)
|
|
{
|
|
IList<ServiceRecord> records =
|
|
DAOFactory.SearchDAO.FindServiceRecordsDetailsForLastDays(
|
|
groupRecord.CostBearer2SupportConceptOid.Value, null);
|
|
|
|
// 1. ServiceRecordOverlapping
|
|
try
|
|
{
|
|
records = records.Where(r =>
|
|
{
|
|
bool valid = true;
|
|
|
|
if (r.GroupOid.HasValue)
|
|
valid = r.GroupOid.Value != gid;
|
|
|
|
return valid;
|
|
}).ToList();
|
|
|
|
List<ServiceRecord> belongsToSupportConcept = records.ToList();
|
|
|
|
bool overlapping =
|
|
belongsToSupportConcept.Any(
|
|
rec =>
|
|
TimeSpanOverlapsWithOtherTimeSpan(groupRecord.Start, rec.Start,
|
|
groupRecord.GroupRoundedDuration ?? groupRecord.RoundedDuration,
|
|
rec.GroupRoundedDuration ?? rec.RoundedDuration));
|
|
|
|
if (overlapping)
|
|
{
|
|
result.AddOrUpdateValueInDictionary(groupRecord,
|
|
new List<ServiceRecordValidationResult> { ServiceRecordValidationResult.ServiceRecordOverlapping });
|
|
|
|
ServiceRecord rec =
|
|
belongsToSupportConcept.First(
|
|
re =>
|
|
TimeSpanOverlapsWithOtherTimeSpan(groupRecord.Start, re.Start,
|
|
groupRecord.GroupRoundedDuration ?? groupRecord.RoundedDuration,
|
|
re.GroupRoundedDuration ?? re.RoundedDuration));
|
|
overlappingRecords.Add(groupRecord.ServiceRecordOid.Value,
|
|
rec.Start.Value.ToShortTimeString() + ", Dauer " +
|
|
string.Format("{0:0}", rec.GroupRoundedDuration ?? rec.RoundedDuration) + ", " +
|
|
groupRecord.Customer.FullName);
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
result.AddOrUpdateValueInDictionary(groupRecord,
|
|
new List<ServiceRecordValidationResult> { ServiceRecordValidationResult.Error });
|
|
}
|
|
|
|
// 2. EmployeeOverlapping
|
|
try
|
|
{
|
|
foreach (CompactEmployeeDC employee in employees)
|
|
{
|
|
var span = new DateTimeSpan();
|
|
span.StartDate = start.Date.AddDays(-1);
|
|
span.EndDate = groupRecord.End.Value.Date.AddDays(1);
|
|
|
|
IList<ServiceRecord> empRecords = DAOFactory.SearchDAO.FindEmployeeServiceRecords(employee.EmployeeOid, span, null, null);
|
|
if (groupRecord.ServiceRecordOid.HasValue)
|
|
{
|
|
empRecords = empRecords.Where(r => r.Oid != groupRecord.ServiceRecordOid.Value).ToList();
|
|
}
|
|
empRecords = empRecords.Where(r => r.Start.HasValue && r.Start.Value.Second == 0).ToList();
|
|
|
|
|
|
bool overlapping =
|
|
empRecords.Any(
|
|
record =>
|
|
TimeSpanOverlapsWithOtherTimeSpan(pServiceRecord.Start, record.Start, pServiceRecord.RoundedDuration,
|
|
record.RoundedDuration));
|
|
|
|
if (overlapping)
|
|
{
|
|
result.AddOrUpdateValueInDictionary(groupRecord,
|
|
new List<ServiceRecordValidationResult> { ServiceRecordValidationResult.EmployeeOverlapping });
|
|
overlappingEmployees.Add(groupRecord.ServiceRecordOid.Value,
|
|
string.Format("{1}, {0}", employee.FirstName, employee.LastName));
|
|
}
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
result.AddOrUpdateValueInDictionary(groupRecord,
|
|
new List<ServiceRecordValidationResult> { ServiceRecordValidationResult.Error });
|
|
}
|
|
}
|
|
// 4. ApprovedFLSOverspending
|
|
try
|
|
{
|
|
SupportConceptCostBearerRelDC reldc = MapperFactory.SupportConceptCostBearerRelDC_CostBearer2SupportConcept.MapToNewDC(DAOFactory.GenericDAO.GetByID<CostBearer2SupportConcept>(groupRecord.CostBearer2SupportConceptOid.Value));
|
|
Calculations calc = PluginLoader.FindClass<Calculations>(reldc.CostBearer.CostBearerID) ?? Calculations.GetInstance(reldc.CostBearer.CostBearerID);
|
|
decimal totalFLSApproved = calc.GetApprovedHoursTotal(reldc, true) ?? 0m;
|
|
|
|
if (totalFLSApproved > 0)
|
|
{
|
|
decimal totalFLSNew = flsTotalRounded + (groupRecord.RoundedDuration / 60);
|
|
if (pServiceRecord.ServiceDescription.Category.IsBillable && totalFLSNew > totalFLSApproved)
|
|
result.AddOrUpdateValueInDictionary(groupRecord, new List<ServiceRecordValidationResult> { ServiceRecordValidationResult.OutsideOfSupportConcept });
|
|
}
|
|
|
|
// 3. OutsideOfSupportConcept
|
|
if (date.HasValue && reldc.StartDate.HasValue && reldc.EndDate.HasValue)
|
|
if (!date.Value.InBetween(reldc.StartDate.Value, reldc.EndDate.Value, true))
|
|
result.AddOrUpdateValueInDictionary(groupRecord, new List<ServiceRecordValidationResult> { ServiceRecordValidationResult.OutsideOfSupportConcept });
|
|
}
|
|
catch (Exception)
|
|
{
|
|
result.AddOrUpdateValueInDictionary(groupRecord, new List<ServiceRecordValidationResult> { ServiceRecordValidationResult.Error });
|
|
}
|
|
|
|
// 6. SettlementInvoiceAlreadyExisting
|
|
try
|
|
{
|
|
IList<SettlementInvoice> allSettlementInvoices = DAOFactory.GenericDAO.GetAll<SettlementInvoice>();
|
|
|
|
if (allSettlementInvoices.Where(rechnung => rechnung.InvoiceBase.CostBearer2SupportConcept.Oid.HasValue).Any(rechnung => rechnung.InvoiceBase.CostBearer2SupportConcept.Oid.Value.Equals(groupRecord.CostBearer2SupportConceptOid.Value) && rechnung.IsActive.Equals(ActivationTypeId.Active)))
|
|
result.AddOrUpdateValueInDictionary(groupRecord, new List<ServiceRecordValidationResult> { ServiceRecordValidationResult.SettlementInvoiceAlreadyExisting });
|
|
}
|
|
catch (Exception)
|
|
{
|
|
result.AddOrUpdateValueInDictionary(groupRecord, new List<ServiceRecordValidationResult> { ServiceRecordValidationResult.Error });
|
|
}
|
|
|
|
try
|
|
{
|
|
// 5. Frist
|
|
var settings = AppSettings.CreateSettings();
|
|
|
|
if (settings.AnzTageZeiterfassErfolgt > 0)
|
|
{
|
|
var dt = new DateTime(date.Value.Year, date.Value.Month, 1);
|
|
dt = dt.AddDays(settings.AnzTageZeiterfassErfolgt);
|
|
if (DateTime.Now >= dt)
|
|
result.AddOrUpdateValueInDictionary(groupRecord, new List<ServiceRecordValidationResult> { ServiceRecordValidationResult.FristAbgelaufen });
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
result.AddOrUpdateValueInDictionary(groupRecord, new List<ServiceRecordValidationResult> { ServiceRecordValidationResult.Error });
|
|
}
|
|
|
|
if (maxDaysEditServiceRecordsAllowed <= 0)
|
|
return result;
|
|
|
|
|
|
try
|
|
{
|
|
// 6. OutOfEditLimit
|
|
var dt = new DateTime(date.Value.Year, date.Value.Month, 1);
|
|
dt = dt.AddMonths(1);
|
|
dt = dt.AddDays(maxDaysEditServiceRecordsAllowed + 1);
|
|
if (DateTime.Now >= dt)
|
|
result.AddOrUpdateValueInDictionary(groupRecord, new List<ServiceRecordValidationResult> { ServiceRecordValidationResult.OutOfEditLimit });
|
|
|
|
}
|
|
catch (Exception)
|
|
{
|
|
result.AddOrUpdateValueInDictionary(groupRecord, new List<ServiceRecordValidationResult> { ServiceRecordValidationResult.Error });
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public virtual List<ServiceRecordValidationResultDC> ValidateServiceRecord(ServiceRecordDC newServiceRecord,
|
|
SupportConceptStatisticsDC statistics, int maxDaysEditServiceRecordsAllowed,
|
|
IList<long> employeeOids, IList<long> cb2scOids)
|
|
{
|
|
var result = new List<ServiceRecordValidationResultDC>();
|
|
|
|
|
|
if (!newServiceRecord.Start.HasValue)
|
|
return result;
|
|
|
|
|
|
bool isGroupRecord = (cb2scOids != null && cb2scOids.Count > 1) ||
|
|
(employeeOids != null && employeeOids.Count > 1);
|
|
|
|
|
|
DateTime start = newServiceRecord.Start.Value;
|
|
bool noTime = (start.Hour == 0 && start.Minute == 0 && start.Second == 1); //Keine Zeit angegeben
|
|
if (!noTime)
|
|
{
|
|
noTime = newServiceRecord.ServiceDescription.DoNotCheckOverlapping;
|
|
}
|
|
|
|
var duration = (decimal)newServiceRecord.End.Value.Subtract(newServiceRecord.Start.Value).TotalMinutes;
|
|
if (!noTime && duration == 0)
|
|
{
|
|
noTime = true;
|
|
}
|
|
decimal roundedDuration = duration;
|
|
|
|
var srdc = PluginLoader.FindClass<ServiceRecordDurationCalculator>();
|
|
if (srdc != null)
|
|
{
|
|
srdc.CalculateRoundedDuration(newServiceRecord);
|
|
|
|
roundedDuration = newServiceRecord.RoundedDuration;
|
|
}
|
|
|
|
|
|
if (isGroupRecord)
|
|
{
|
|
var groupcalc = PluginLoader.FindClass<GroupDurationCalculator>();
|
|
|
|
if (groupcalc != null)
|
|
{
|
|
var gd = groupcalc.CalculateGroupDuration(cb2scOids.Count, employeeOids.Count, duration, cb2scOids.ToArray());
|
|
if (gd == null)
|
|
{
|
|
roundedDuration = Math.Round(roundedDuration / cb2scOids.Count, 0, MidpointRounding.AwayFromZero);
|
|
}
|
|
else
|
|
{
|
|
roundedDuration = gd.SingleDuration;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
//var minuteInterval = cbDC.ActualMinuteIntervall;
|
|
//if (minuteInterval > 0)
|
|
newServiceRecord.RoundedDuration = roundedDuration;
|
|
|
|
|
|
decimal rd = newServiceRecord.RoundedDuration;
|
|
decimal? grd = newServiceRecord.GroupRoundedDuration;
|
|
|
|
long? cb2ScOid = null;
|
|
if (newServiceRecord.CostBearer2SupportConceptOid.HasValue)
|
|
{
|
|
cb2ScOid = newServiceRecord.CostBearer2SupportConceptOid.Value;
|
|
}
|
|
|
|
if (!noTime)
|
|
{
|
|
bool overlapsCustomer = false;
|
|
if (cb2ScOid.HasValue)
|
|
{
|
|
// 1. Customer ServiceRecordOverlapping
|
|
try
|
|
{
|
|
//Nur für abrechenbare Leistungen prüfen.
|
|
if (newServiceRecord.ServiceDescription.Category.IsBillable)
|
|
{
|
|
IList<ServiceRecord> records = DAOFactory.SearchDAO.FindServiceRecordsDetailsForLastDays(cb2ScOid.Value,
|
|
null);
|
|
|
|
if (newServiceRecord.ServiceRecordOid.HasValue)
|
|
{
|
|
records = records.Where(r => r.Oid != newServiceRecord.ServiceRecordOid.Value).ToList();
|
|
}
|
|
//if (isGroupRecord && newServiceRecord.GroupOid.HasValue)
|
|
//{
|
|
// records = records.Where(r => !r.GroupOid.HasValue || r.GroupOid != newServiceRecord.GroupOid).ToList();
|
|
// }
|
|
records = records.Where(r => r.Start.HasValue && r.Start.Value.Second == 0).ToList();
|
|
|
|
if (isGroupRecord && newServiceRecord.GroupOid.HasValue)
|
|
{
|
|
records =
|
|
records.Where(r => !r.GroupOid.HasValue || r.GroupOid != newServiceRecord.GroupOid).ToList();
|
|
}
|
|
|
|
|
|
ServiceRecord overlappingRecord =
|
|
records.FirstOrDefault(
|
|
record => record.ServiceDescription.ServiceCategory.IsBillable &&
|
|
TimeSpanOverlapsWithOtherTimeSpan(start, record.Start,
|
|
grd ?? rd,
|
|
record.GroupRoundedDuration ?? record.RoundedDuration));
|
|
|
|
if (overlappingRecord != null)
|
|
{
|
|
overlapsCustomer = true;
|
|
var rdc = new ServiceRecordValidationResultDC
|
|
{
|
|
ResultType = ServiceRecordValidationResult.ServiceRecordOverlapping,
|
|
Message = String.Format("{0}, Dauer {1:0} Minuten", overlappingRecord.Start.Value.ToShortTimeString(),
|
|
overlappingRecord.GroupRoundedDuration ?? overlappingRecord.RoundedDuration)
|
|
};
|
|
|
|
Customer c = overlappingRecord.Customer;
|
|
if (c != null)
|
|
{
|
|
rdc.CustomerName = String.Format("{0}, {1}", c.Person.LastName, c.Person.FirstName);
|
|
}
|
|
Employee e = overlappingRecord.Employee;
|
|
if (e != null)
|
|
{
|
|
rdc.EmployeeName = String.Format("{0} {1}", e.Person.FirstName, e.Person.LastName);
|
|
}
|
|
|
|
|
|
result.Add(rdc);
|
|
}
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
result.Add(new ServiceRecordValidationResultDC { ResultType = ServiceRecordValidationResult.Error });
|
|
}
|
|
}
|
|
|
|
|
|
// 2. EmployeeOverlapping
|
|
if (!overlapsCustomer)
|
|
{
|
|
if (!isGroupRecord)
|
|
{
|
|
ServiceRecordValidationResultDC resultdc = CheckOverlappingEmployeeServiceRecords(newServiceRecord, start, newServiceRecord.Employee.EmployeeOid, rd);
|
|
if (resultdc != null)
|
|
result.Add(resultdc);
|
|
}
|
|
else if (employeeOids != null)
|
|
{
|
|
foreach (long employeeOid in employeeOids)
|
|
{
|
|
ServiceRecordValidationResultDC resultdc = null;
|
|
if (resultdc == null)
|
|
{
|
|
resultdc = CheckOverlappingEmployeeServiceRecords(newServiceRecord, start, employeeOid, grd ?? rd);
|
|
if (resultdc != null)
|
|
result.Add(resultdc);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
try
|
|
{
|
|
// 5. Frist
|
|
var settings = AppSettings.CreateSettings();
|
|
|
|
if (settings.AnzTageZeiterfassErfolgt > 0)
|
|
{
|
|
var dt = new DateTime(start.Year, start.Month, start.Day);
|
|
dt = dt.AddDays(settings.AnzTageZeiterfassErfolgt + 1);
|
|
if (DateTime.Now >= dt)
|
|
result.Add(new ServiceRecordValidationResultDC { ResultType = ServiceRecordValidationResult.FristAbgelaufen });
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
result.Add(new ServiceRecordValidationResultDC { ResultType = ServiceRecordValidationResult.Error });
|
|
}
|
|
|
|
|
|
if (cb2ScOid.HasValue)
|
|
{
|
|
SupportConceptCostBearerRelDC reldc =
|
|
MapperFactory.SupportConceptCostBearerRelDC_CostBearer2SupportConcept.MapToNewDC(
|
|
DAOFactory.GenericDAO.GetByID<CostBearer2SupportConcept>(cb2ScOid.Value));
|
|
|
|
// 4. ApprovedFLSOverspending
|
|
try
|
|
{
|
|
var resultOverspending = CheckApprovedOverspending(reldc, newServiceRecord);
|
|
if (resultOverspending != null)
|
|
{
|
|
result.Add(resultOverspending);
|
|
}
|
|
|
|
// 3. OutsideOfSupportConcept
|
|
if (reldc.StartDate.HasValue && reldc.EndDate.HasValue)
|
|
if (!start.InBetween(reldc.StartDate.Value, reldc.EndDate.Value, true))
|
|
{
|
|
var dc = new ServiceRecordValidationResultDC
|
|
{
|
|
ResultType = ServiceRecordValidationResult.OutsideOfSupportConcept,
|
|
StartDate = reldc.StartDate.Value,
|
|
EndDate = reldc.EndDate.Value
|
|
};
|
|
result.Add(dc);
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
result.Add(new ServiceRecordValidationResultDC { ResultType = ServiceRecordValidationResult.Error });
|
|
}
|
|
|
|
// 6. SettlementInvoiceAlreadyExisting
|
|
try
|
|
{
|
|
IList<SettlementInvoice> allSettlementInvoices =
|
|
DAOFactory.SearchDAO.GetSettlementInvoiceByCostBearer2SupportConceptOid(cb2ScOid.Value);
|
|
if (allSettlementInvoices.Count > 0)
|
|
{
|
|
var r = new ServiceRecordValidationResultDC
|
|
{
|
|
ResultType = ServiceRecordValidationResult.SettlementInvoiceAlreadyExisting
|
|
};
|
|
r.CustomerName = reldc.SupportConcept.CustomerFullName;
|
|
result.Add(r);
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
result.Add(new ServiceRecordValidationResultDC { ResultType = ServiceRecordValidationResult.Error });
|
|
}
|
|
|
|
//7. Prüfe ob Datum in Zukunft liegt
|
|
if (CheckZukunft())
|
|
{
|
|
//7. Prüfe ob Datum in Zukunft liegt
|
|
if (start.Date > DateTime.Now)
|
|
{
|
|
result.Add(new ServiceRecordValidationResultDC
|
|
{
|
|
ResultType = ServiceRecordValidationResult.Custom,
|
|
Message = "Das gewählte Datum darf nicht in der Zukunft liegen."
|
|
});
|
|
}
|
|
|
|
}
|
|
|
|
// 8. OutOfEditLimit
|
|
try
|
|
{
|
|
if (maxDaysEditServiceRecordsAllowed > 0)
|
|
{
|
|
var dt = new DateTime(start.Year, start.Month, 1);
|
|
dt = dt.AddMonths(1);
|
|
dt = dt.AddDays(maxDaysEditServiceRecordsAllowed);
|
|
if (DateTime.Now >= dt)
|
|
result.Add(new ServiceRecordValidationResultDC
|
|
{
|
|
ResultType = ServiceRecordValidationResult.OutOfEditLimit
|
|
});
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
result.Add(new ServiceRecordValidationResultDC { ResultType = ServiceRecordValidationResult.Error });
|
|
}
|
|
|
|
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public virtual ServiceRecordValidationResultDC CheckApprovedOverspending(SupportConceptCostBearerRelDC reldc, ServiceRecordDC newServiceRecord)
|
|
{
|
|
decimal totalFLSApproved = 0;
|
|
var factory = PluginLoader.FindClass<ServiceRecordStatisticFactory>();
|
|
SupportConceptStatisticsDC stats = null;
|
|
|
|
if (factory == null)
|
|
{
|
|
factory = new ServiceRecordStatisticFactory();
|
|
}
|
|
|
|
Calculations calc = PluginLoader.FindClass<Calculations>(reldc.CostBearer.CostBearerID) ?? Calculations.GetInstance(reldc.CostBearer.CostBearerID);
|
|
//if (reldc.ApprovalPeriodList != null && reldc.ApprovalPeriodList.Count > 1)
|
|
//{
|
|
// stats = factory.CreateSupportConceptStatisticsImpl(reldc.CostBearer2SupportConceptOid.Value,
|
|
// DateTime.Now, newServiceRecord.ServiceRecordOid);
|
|
// }
|
|
//else
|
|
//{
|
|
totalFLSApproved = calc.GetApprovedHoursTotal(reldc, true) ?? 0m;
|
|
//}
|
|
|
|
|
|
if (totalFLSApproved > 0)
|
|
{
|
|
stats = factory.CreateSupportConceptStatisticsImpl(reldc.CostBearer2SupportConceptOid.Value,
|
|
DateTime.Now, newServiceRecord.ServiceRecordOid);
|
|
|
|
|
|
decimal flmTotalRounded = 0;
|
|
decimal flmApprovedForPeriod = 0;
|
|
|
|
SupportConceptPeriodStatisticsDC periodStat = GetStatisticsForServiceRecord(stats, newServiceRecord);
|
|
if (periodStat != null)
|
|
{
|
|
flmTotalRounded = periodStat.MinutesProvidedTotalRounded;
|
|
flmApprovedForPeriod = periodStat.MinutesApprovedTotal;
|
|
|
|
}
|
|
else
|
|
{
|
|
flmTotalRounded = stats.MinutesProvidedTotalRounded;
|
|
flmApprovedForPeriod = stats.MinutesApprovedTotal;
|
|
}
|
|
|
|
decimal totalFLSNew = (flmTotalRounded + newServiceRecord.RoundedDuration) / 60;
|
|
if (flmApprovedForPeriod > 0 && totalFLSNew > (flmApprovedForPeriod / 60))
|
|
|
|
{
|
|
if (newServiceRecord.ServiceDescription.Category.IsBillable ||
|
|
(periodStat != null && periodStat.SupportConceptApprovalPeriod != null && periodStat.SupportConceptApprovalPeriod.ServiceCategory != null))
|
|
{
|
|
var dc = new ServiceRecordValidationResultDC
|
|
{
|
|
ResultType = ServiceRecordValidationResult.ApprovedFLSOverspending,
|
|
ApprovedHours = Math.Round((flmApprovedForPeriod / 60), 2, MidpointRounding.AwayFromZero),
|
|
HoursNew = Math.Round(totalFLSNew, 2, MidpointRounding.AwayFromZero)
|
|
};
|
|
|
|
dc.CustomerName = reldc.SupportConcept.CustomerFullName;
|
|
return dc;
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
public virtual bool CheckZukunft()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
public virtual ServiceRecordValidationResultDC CheckOverlappingEmployeeServiceRecords(ServiceRecordDC newServiceRecord, DateTime start, long employeeOid, decimal roundedDuration)
|
|
{
|
|
var span = new DateTimeSpan();
|
|
span.StartDate = start.Date.AddDays(-1);
|
|
span.EndDate = newServiceRecord.End.Value.Date.AddDays(1);
|
|
IList<ServiceRecord> empRecords = DAOFactory.SearchDAO.FindEmployeeServiceRecords(employeeOid, span, null, null);
|
|
if (newServiceRecord.ServiceRecordOid.HasValue)
|
|
{
|
|
empRecords = empRecords.Where(r => r.Oid != newServiceRecord.ServiceRecordOid.Value).ToList();
|
|
}
|
|
if (newServiceRecord.GroupOid.HasValue)
|
|
{
|
|
empRecords = empRecords.Where(r => !r.GroupOid.HasValue || r.GroupOid != newServiceRecord.GroupOid).ToList();
|
|
}
|
|
empRecords = empRecords.Where(r => r.Start.HasValue && r.Start.Value.Second == 0).ToList();
|
|
|
|
|
|
String[] ignoreNames = GetIgnoreCategoriesForOverlappingCheck();
|
|
|
|
if (ignoreNames != null)
|
|
{
|
|
bool ignore = ignoreNames.Contains(newServiceRecord.ServiceDescription.Category.Name);
|
|
|
|
if (ignore)
|
|
{
|
|
empRecords =
|
|
empRecords.Where(r => ignoreNames.Contains(r.ServiceDescription.ServiceCategory.Name)).ToList();
|
|
}
|
|
else
|
|
{
|
|
empRecords =
|
|
empRecords.Where(r => !ignoreNames.Contains(r.ServiceDescription.ServiceCategory.Name)).ToList();
|
|
}
|
|
}
|
|
ignoreNames = GetIgnoreServiceDescriptionsForOverlappingCheck();
|
|
|
|
if (ignoreNames != null)
|
|
{
|
|
bool ignore = ignoreNames.Contains(newServiceRecord.ServiceDescription.Name);
|
|
|
|
if (ignore)
|
|
{
|
|
empRecords =
|
|
empRecords.Where(r => ignoreNames.Contains(r.ServiceDescription.Name)).ToList();
|
|
}
|
|
else
|
|
{
|
|
empRecords =
|
|
empRecords.Where(r => !ignoreNames.Contains(r.ServiceDescription.Name)).ToList();
|
|
}
|
|
}
|
|
try
|
|
{
|
|
ServiceRecord overlappingRecord =
|
|
empRecords.FirstOrDefault(
|
|
record =>
|
|
TimeSpanOverlapsWithOtherTimeSpan(start, record.Start, roundedDuration, record.RoundedDuration));
|
|
|
|
if (overlappingRecord != null)
|
|
{
|
|
var rdc = new ServiceRecordValidationResultDC
|
|
{
|
|
ResultType = ServiceRecordValidationResult.EmployeeOverlapping,
|
|
Message = String.Format("{0}, Dauer {1:0} Minuten", overlappingRecord.Start.Value.ToShortTimeString(),
|
|
overlappingRecord.GroupRoundedDuration ?? overlappingRecord.RoundedDuration)
|
|
};
|
|
|
|
Customer c = overlappingRecord.Customer;
|
|
if (c != null)
|
|
{
|
|
rdc.Message += String.Format(" bei Klient/in {0}, {1}", c.Person.LastName, c.Person.FirstName);
|
|
}
|
|
Employee e = overlappingRecord.Employee;
|
|
if (e != null)
|
|
{
|
|
rdc.EmployeeName = String.Format("{0} {1}", e.Person.FirstName, e.Person.LastName);
|
|
}
|
|
|
|
return rdc;
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
return new ServiceRecordValidationResultDC { ResultType = ServiceRecordValidationResult.Error };
|
|
}
|
|
return null;
|
|
}
|
|
|
|
|
|
public virtual String[] GetIgnoreCategoriesForOverlappingCheck()
|
|
{
|
|
return null;
|
|
}
|
|
|
|
public virtual String[] GetIgnoreServiceDescriptionsForOverlappingCheck()
|
|
{
|
|
return null;
|
|
}
|
|
|
|
private SupportConceptPeriodStatisticsDC GetStatisticsForServiceRecord(SupportConceptStatisticsDC statistics, ServiceRecordDC newServiceRecord)
|
|
{
|
|
if (statistics != null && statistics.PeriodStatistics.Count > 0)
|
|
{
|
|
//Prüfen, ob es Bewilligungen mit Kategorie gibt:
|
|
if (statistics.PeriodStatistics.Count > 1)
|
|
{
|
|
bool mindestensEinerHatKategorie = false;
|
|
foreach (SupportConceptPeriodStatisticsDC pstat in statistics.PeriodStatistics)
|
|
{
|
|
if (pstat.SupportConceptApprovalPeriod != null &&
|
|
pstat.SupportConceptApprovalPeriod.ServiceCategory != null)
|
|
{
|
|
mindestensEinerHatKategorie = true;
|
|
}
|
|
}
|
|
|
|
if (!mindestensEinerHatKategorie)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
//Prüfen, ob es Bewilligungen mit unterschiedlicher Kategorie gibt:
|
|
bool mindestensZweiHabenUnterschiedlicheKategorie = false;
|
|
ServiceCategoryDC cat = null;
|
|
foreach (SupportConceptPeriodStatisticsDC pstat in statistics.PeriodStatistics)
|
|
{
|
|
if (pstat.SupportConceptApprovalPeriod != null &&
|
|
pstat.SupportConceptApprovalPeriod.ServiceCategory != null)
|
|
{
|
|
if (cat != null)
|
|
{
|
|
if (pstat.SupportConceptApprovalPeriod.ServiceCategory.ServiceCategoryOid !=
|
|
cat.ServiceCategoryOid)
|
|
{
|
|
mindestensZweiHabenUnterschiedlicheKategorie = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
cat = pstat.SupportConceptApprovalPeriod.ServiceCategory;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!mindestensZweiHabenUnterschiedlicheKategorie)
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
foreach (SupportConceptPeriodStatisticsDC pstat in statistics.PeriodStatistics)
|
|
{
|
|
if (BelongsToPeriodStatistic(newServiceRecord, pstat))
|
|
return pstat;
|
|
}
|
|
foreach (SupportConceptPeriodStatisticsDC pstat in statistics.PeriodStatistics)
|
|
{
|
|
if (pstat.SupportConceptApprovalPeriod != null && pstat.SupportConceptApprovalPeriod.ServiceCategory == null)
|
|
{
|
|
if (pstat.SupportConceptApprovalPeriod.StartDate <= newServiceRecord.Start)
|
|
{
|
|
if (!pstat.SupportConceptApprovalPeriod.EndDate.HasValue ||
|
|
(newServiceRecord.Start.Value.Date <= pstat.SupportConceptApprovalPeriod.EndDate.Value.Date))
|
|
{
|
|
return pstat;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public static bool TimeSpanOverlapsWithOtherTimeSpan(DateTime? pStart, DateTime? rStart, decimal pRoundedDuration, decimal rRoundedDuration)
|
|
{
|
|
DateTime? pEnd = pStart.Value.AddMinutes(Convert.ToDouble(pRoundedDuration));
|
|
DateTime? rEnd = rStart.Value.AddMinutes(Convert.ToDouble(rRoundedDuration));
|
|
|
|
bool overlaps = pStart == rStart || rEnd == pEnd || pEnd == rStart || pStart == rEnd ||
|
|
rStart > pStart && rStart < pEnd || rEnd > pStart && rEnd < pEnd ||
|
|
pStart > rStart && pStart < rEnd || pEnd > rStart && pEnd < rEnd;
|
|
|
|
overlaps = !(pEnd <= rStart || pStart >= rEnd);
|
|
return overlaps;
|
|
}
|
|
|
|
private bool BelongsToPeriodStatistic(ServiceRecordDC newServiceRecord, SupportConceptPeriodStatisticsDC pstat)
|
|
{
|
|
if (pstat.SupportConceptApprovalPeriod != null && pstat.SupportConceptApprovalPeriod.ServiceCategory != null)
|
|
if (pstat.SupportConceptApprovalPeriod.ServiceCategory.ServiceCategoryOid ==
|
|
newServiceRecord.ServiceDescription.Category.ServiceCategoryOid)
|
|
{
|
|
if (pstat.SupportConceptApprovalPeriod.StartDate <= newServiceRecord.Start)
|
|
{
|
|
if (!pstat.SupportConceptApprovalPeriod.EndDate.HasValue ||
|
|
(newServiceRecord.Start.Value.Date <= pstat.SupportConceptApprovalPeriod.EndDate.Value.Date))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public List<ServiceRecordValidationResultDC> ValidateServiceRecordDeletion(ServiceRecordDC serviceRecord, long employeeOid)
|
|
{
|
|
var result = new List<ServiceRecordValidationResultDC>();
|
|
|
|
// 1. Prüfe Unterschrift vorhanden
|
|
|
|
if (serviceRecord.SignatureOid.HasValue)
|
|
{
|
|
result.Add(new ServiceRecordValidationResultDC
|
|
{
|
|
Allow = true,
|
|
ResultType = ServiceRecordValidationResult.Custom,
|
|
Message = "Dieser Eintrag wurde bereits unterschrieben.\nMöchten Sie ihn trotzdem löschen?"
|
|
});
|
|
}
|
|
|
|
return result;
|
|
}
|
|
}
|
|
} |