Files
BeWoPlaner/ReportImp/Mittelpunkt/Invoicing/CustomInvoiceCreation.cs

198 lines
12 KiB
C#

using BeWo.Data.Access;
using BeWo.Data.Entities;
using BeWo.Service.Invoicing;
using BS.Shared;
using BS.Shared.Core;
using BS.Shared.DataContracts;
using BS.Shared.Services;
using DevExpress.Utils.DragDrop;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Mittelpunkt.Invoicing
{
public class CustomInvoiceCreation : InvoiceCreation
{
public override IList<InvoiceItem> CreateInvoiceItems(List<ServiceRecordDC> serviceRecordsInPeriod, DateTimeSpan invoicePeriod, SupportConceptApprovalPeriod scap, Calculations calc)
{
serviceRecordsInPeriod = serviceRecordsInPeriod.OrderBy(s => s.Start).ToList();
decimal? bewilligtGesamt = scap.ApprovedBETotal;
decimal? bewilligtProMonat = 0;
// Gesamt bewilligte Stunden setzen, damit im nächsten Schritt davon alles bisher abgerechnete abgezogen werden kann
if (bewilligtGesamt == null && scap.EndDate.HasValue && scap.StartDate.HasValue)
{
if (scap.ApprovedBEInterval == SupportConceptApprovalInterval.Weekly)
{
bewilligtGesamt = Convert.ToDecimal((scap.EndDate.Value - scap.StartDate.Value).TotalDays) / 7m * scap.ApprovedBEPerInterval;
bewilligtProMonat = scap.ApprovedBEPerInterval * 4.35m;
}
else if (scap.ApprovedBEInterval == SupportConceptApprovalInterval.Monthly)
{
// Ist nur ein Monat bewilligt, kann der komplette Wert genommen werden
if (scap.StartDate.HasValue && scap.EndDate.HasValue &&
scap.StartDate.Value.Month == scap.EndDate.Value.Month && scap.StartDate.Value.Year == scap.EndDate.Value.Year &&
scap.EndDate.Value.Day == DateTime.DaysInMonth(scap.EndDate.Value.Year, scap.EndDate.Value.Month))
{
bewilligtGesamt = scap.ApprovedBEPerInterval;
}
else
{
bewilligtGesamt = Convert.ToDecimal((scap.EndDate.Value - scap.StartDate.Value).TotalDays) / 30.4375m * scap.ApprovedBEPerInterval;
}
bewilligtProMonat = scap.ApprovedBEPerInterval;
}
else
{
bewilligtGesamt = scap.ApprovedBEPerInterval.Value;
bewilligtProMonat = bewilligtGesamt / 30.4375m;
}
}
else if (bewilligtGesamt != null && scap.EndDate.HasValue && scap.StartDate.HasValue)
bewilligtProMonat = bewilligtGesamt / (Convert.ToDecimal((scap.EndDate.Value - scap.StartDate.Value).TotalDays) / 30.4375m);
// Alle bisherigen Rechnungen holen und die Stunden rausziehen
var invoices = DAOFactory.SearchDAO.GetServiceInvoices(scap.CostBearer2SupportConcept.CostBearer.Oid.Value, scap.CostBearer2SupportConcept.SupportConcept.Oid, new DateTimeSpan(scap.StartDate.Value, scap.EndDate.Value));
decimal bisDatoAbgerechnetGesamt = 0;
foreach (var inv in invoices)
{
foreach (var sip in inv.ServiceInvoicePeriodList)
{
foreach (var item in sip.InvoiceItemList)
{
var rf = item.RateFactor.HasValue ? item.RateFactor.Value / 100 + 1 : 1;
bisDatoAbgerechnetGesamt += item.UnitCount.Value * rf;
}
}
}
decimal offeneBewilligteStunden = bewilligtGesamt.Value - bisDatoAbgerechnetGesamt;
var crpWithRateFactor = scap.CostBearer2SupportConcept.CostBearer.CostRatePeriods.FirstOrDefault(crp => crp.CostRateType == BS.Shared.CostRatePeriodType.RateFactor);
var ratefactor = crpWithRateFactor != null ? (100 + crpWithRateFactor.CostRateValue.Value) / 100 : 1m;
var list = new List<InvoiceItem>();
int week = 0;
int monat = 0;
decimal wochenstunden = 0;
decimal monatsstunden = 0;
foreach (ServiceRecordDC iServiceRecord in serviceRecordsInPeriod)
{
if (iServiceRecord.Start.Value.Date >= new DateTime(2026, 06, 22))
{
}
// Woche des Jahres in jedem Durchlauf bestimmen, damit bei nicht übertragbaren Stunden nur so viel wie bewilligt abgerechnet wird
CultureInfo info = CultureInfo.CurrentCulture;
Calendar kalender = info.Calendar;
CalendarWeekRule kalenderWochenregel = info.DateTimeFormat.CalendarWeekRule;
DayOfWeek ersterTagDerWoche = info.DateTimeFormat.FirstDayOfWeek;
int aktuelleWoche = kalender.GetWeekOfYear(iServiceRecord.Start.Value, kalenderWochenregel, ersterTagDerWoche);
int aktuellerMonat = iServiceRecord.Start.Value.Month;
// Wenn die aktuelle Woche bzw der aktuelle Monat nicht der aus den vorherigen Eintrag ist, resetten
if (aktuelleWoche != week)
wochenstunden = 0;
if (aktuellerMonat != monat)
monatsstunden = 0;
if (iServiceRecord.ServiceDescription.Category.IsBillable)
{
if (!iServiceRecord.AlreadyAccounted)
{
// Differenz ist das noch übrige Bewilligungsbudget abzüglich des ServiceRecords mit Faktor, da die Bewilligung schon inkl. Faktor ist
var differenz = offeneBewilligteStunden - iServiceRecord.RoundedDuration * ratefactor / 60;
// Sollten die Stunden nicht übertragbar sein muss bedacht werden, wie viele Stunden die Woche schon geleistet wurden bzw. wie viele noch möglich sind
if (!scap.IsApprovedBEShifting && scap.ApprovedBEPerInterval != null)
{
// Wöchentliche Stundenbewilligung
if (scap.ApprovedBEInterval == SupportConceptApprovalInterval.Weekly)
{
// Wenn die Stunden, die diese Woche geleistet wurden, schon über der wöchentlichen Bewilligung liegen, skippen.
if (wochenstunden >= bewilligtProMonat.Value / 4.35m)
continue;
// Ist die Summe aus aktuellem ServiceRecord und aktuellen Wochenstunden mehr als die wöchentliche Bewilligung, muss der ServiceRecord angepasst werden
if (iServiceRecord.RoundedDuration * ratefactor / 60 + wochenstunden > bewilligtProMonat / 4.35m)
{
// Ermitteln, wie viele Stunden OHNE FAKTOR für die Woche noch möglich sind (Bewilligt pro Woche - Geleistet diese Woche)
var inDieserWocheNochMoeglicheStunden = (bewilligtProMonat / 4.35m - wochenstunden ) / ratefactor;
// Bewilligungsbudget anpassen, da hier nur so viel abgezogen werden darf wie für die Woche bewilligt war
differenz = offeneBewilligteStunden - inDieserWocheNochMoeglicheStunden.Value;
// Zeit des ServiceRecord so reduzieren, dass die Zeit + Faktor den Wert ergibt, der noch offen bewilligt für diese Woche ist
iServiceRecord.RoundedDuration = inDieserWocheNochMoeglicheStunden.Value * 60;
if (iServiceRecord.Start.HasValue)
iServiceRecord.End = iServiceRecord.Start.Value.AddMinutes(Convert.ToDouble(iServiceRecord.RoundedDuration));
}
}
// Monatliche Stundenbewilligung
if (scap.ApprovedBEInterval == SupportConceptApprovalInterval.Monthly)
{
// Wenn die Stunden, die diesen Monat geleistet wurden, schon über der monatlichen Bewilligung liegen, skippen.
if (monatsstunden >= bewilligtProMonat.Value)
continue;
// Ist die Summe aus aktuellem ServiceRecord und aktuellen Monatsstunden mehr als die monatliche Bewilligung, muss der ServiceRecord angepasst werden
if (iServiceRecord.RoundedDuration * ratefactor / 60 + monatsstunden > bewilligtProMonat)
{
// Ermitteln, wie viele Stunden OHNE FAKTOR für den Monat noch möglich sind (Bewilligt pro Monat - Geleistet diesen Monat)
var inDiesemMonatNochMoeglicheStunden = (bewilligtProMonat - monatsstunden) / ratefactor;
// Bewilligungsbudget anpassen, da hier nur so viel abgezogen werden darf wie für den Monat bewilligt war
differenz = offeneBewilligteStunden - inDiesemMonatNochMoeglicheStunden.Value;
// Zeit des ServiceRecord so reduzieren, dass die Zeit + Faktor den Wert ergibt, der noch offen bewilligt für diesen Monat ist
iServiceRecord.RoundedDuration = inDiesemMonatNochMoeglicheStunden.Value * 60;
if (iServiceRecord.Start.HasValue)
iServiceRecord.End = iServiceRecord.Start.Value.AddMinutes(Convert.ToDouble(iServiceRecord.RoundedDuration));
}
}
}
// Ist die Differenz negativ, heißt das, dass mit dem aktuellen ServiceRecord mehr geleistet wurde, als bewilligt
if (differenz < 0)
{
// Mehr geleistet als bewilligt: ServiceRecord auf die Dauer setzen, die von der Bewilligung noch erlaubt ist
iServiceRecord.RoundedDuration += differenz / 1.2m * 60; // += nutzen, weil die Differenz in dem Fall negativ ist
if (iServiceRecord.End.HasValue)
iServiceRecord.End.Value.AddMinutes(Convert.ToDouble(iServiceRecord.RoundedDuration));
}
InvoiceItem invoiceItem = CreateInvoiceItem(iServiceRecord, scap, calc);
if (invoiceItem != null)
{
list.Add(invoiceItem);
}
iServiceRecord.AlreadyAccounted = true;
// Wochen- und Monatsstunden um die Dauer des ServiceRecords + Faktor erhöhen, damit beim nächsten Durchlauf geprüft werden kann, ob der nächste
// Eintrag die Bewilligung überschreitet, falls die Stunden NICHT übertragbar sind
wochenstunden += iServiceRecord.RoundedDuration * ratefactor / 60;
monatsstunden += iServiceRecord.RoundedDuration * ratefactor / 60;
// Noch offene bewilligte Stunden reduzieren
offeneBewilligteStunden -= iServiceRecord.RoundedDuration * ratefactor / 60;
}
// Woche und Monat für nächsten Durchlauf setzen, damit geprüft werden kann, ob der nächste Eintrag in einer neuen Woche / einem neuen Monat liegt
week = aktuelleWoche;
monat = aktuellerMonat;
}
}
return base.CreateSummaryInvoiceItems(list, invoicePeriod, scap, calc);
}
}
}