272 lines
12 KiB
C#
272 lines
12 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Data;
|
|
using System.Linq;
|
|
using BeWo.Data.Access;
|
|
using BeWo.Data.Entities;
|
|
using BeWo.Report.ReportObjects;
|
|
using BeWo.Service.DCEntityMapper;
|
|
using BeWo.Service.Invoicing;
|
|
using BeWo.Service.Plugins;
|
|
using BS.Shared;
|
|
using BS.Shared.Core;
|
|
using BS.Shared.DataContracts;
|
|
using BS.Shared.DataContracts.Compact;
|
|
using BS.Shared.Extensions;
|
|
using BS.Shared.Services;
|
|
|
|
namespace FeidPartnerReports.Invoicing
|
|
{
|
|
public class CollectiveInvoiceCreation : InvoiceCreation
|
|
{
|
|
private DateTime? accountingPeriodStart = null;
|
|
private DateTime? accountingPeriodEnd = null;
|
|
private decimal AMOUNT_PER_KMQA = 0.0222m;
|
|
private bool monthly = true;
|
|
|
|
public override void SetInvoiceId(ServiceInvoice invoice)
|
|
{
|
|
invoice.InvoiceBase.InvoiceId = "Sammelrechnung";
|
|
invoice.InvoiceBase.InvoiceTypeText = "Sammelrechnung";
|
|
}
|
|
|
|
public override void SetInvoiceBaseData(int invoiceCounter, ServiceInvoice invoice, CostBearer costBearer, DateTimeSpan invoicePeriod,
|
|
IList<CompactSupportConceptDC> supportConceptList)
|
|
{
|
|
if (invoicePeriod != null)
|
|
{
|
|
accountingPeriodStart = invoicePeriod.StartDate;
|
|
accountingPeriodEnd = invoicePeriod.EndDate;
|
|
var pauschVar = base.GetPreis("Fahrzeitenzuschlag qA", (DateTime)accountingPeriodStart);
|
|
if (pauschVar != 0)
|
|
{
|
|
AMOUNT_PER_KMQA = pauschVar;
|
|
}
|
|
}
|
|
base.SetInvoiceBaseData(invoiceCounter, invoice, costBearer, invoicePeriod, supportConceptList);
|
|
}
|
|
|
|
public override void SetInvoiceItems(ServiceInvoice invoice,
|
|
ServiceInvoicePeriod serviceInvoicePeriod,
|
|
SupportConceptApprovalPeriodDC supportConceptApprovalPeriod,
|
|
CostBearer2SupportConcept cb2sc,
|
|
DateTimeSpan invoicePeriod,
|
|
List<ServiceRecordDC> serviceRecords)
|
|
{
|
|
BS.Shared.Services.Calculations calc = PluginLoader.FindClass<BS.Shared.Services.Calculations>(_SpecificID) ?? BS.Shared.Services.Calculations.GetInstance(_SpecificID);
|
|
CreateFixedAmounts(serviceInvoicePeriod, supportConceptApprovalPeriod, cb2sc);
|
|
}
|
|
|
|
public override ServiceInvoice CreateCollectiveBilling(CostBearer costBearer, DateTimeSpan invoicePeriod, Dictionary<CompactSupportConceptDC, List<ServiceRecordDC>> supportConcepts2ServiceRecords)
|
|
{
|
|
var invoice = new ServiceInvoice();
|
|
var newDict = new Dictionary<CompactSupportConceptDC, List<ServiceRecordDC>>();
|
|
bool unbewilligte = true;
|
|
|
|
if (supportConcepts2ServiceRecords.Any(sc2sr => sc2sr.Key.IsApproved)) // Für normalen Rechnungslauf
|
|
{
|
|
unbewilligte = false;
|
|
}
|
|
foreach (var sc2sr in supportConcepts2ServiceRecords)
|
|
{
|
|
if (!unbewilligte && sc2sr.Key.IsApproved)
|
|
{
|
|
newDict.Add(sc2sr.Key, sc2sr.Value);
|
|
}
|
|
else if (unbewilligte)
|
|
{
|
|
newDict.Add(sc2sr.Key, sc2sr.Value); // Rechnungsvorschau für Unbewilligte Hilfepläne in Berichten
|
|
}
|
|
}
|
|
|
|
SetRecipientInformation(invoice, costBearer);
|
|
SetSenderInformation(invoice);
|
|
SetInvoiceBaseData(0, invoice, costBearer, invoicePeriod, newDict.Keys.ToList());
|
|
SetCollectiveBillingBaseData(0, invoice, costBearer, invoicePeriod, newDict);
|
|
|
|
SetCollectiveBillingServiceInvoicePeriods(invoice, invoicePeriod, newDict);
|
|
|
|
SetServiceInvoicePeriodAmounts(invoice);
|
|
|
|
// Spitzabrechnung
|
|
if (invoicePeriod == null)
|
|
{
|
|
SetAmountAdvancePayments(invoice);
|
|
}
|
|
return invoice;
|
|
}
|
|
|
|
public override void CreateFixedAmounts(ServiceInvoicePeriod serviceInvoicePeriod, SupportConceptApprovalPeriodDC supportConceptApprovalPeriod, CostBearer2SupportConcept cb2sc)
|
|
{
|
|
var calc = PluginLoader.FindClass<BS.Shared.Services.Calculations>(_SpecificID) ?? BS.Shared.Services.Calculations.GetInstance(_SpecificID);
|
|
var data = calc.GetFixedBillingData(supportConceptApprovalPeriod, serviceInvoicePeriod.Start, serviceInvoicePeriod.End);
|
|
|
|
DateTime start = accountingPeriodStart.Value;
|
|
DateTime end = accountingPeriodEnd.Value;
|
|
|
|
if (supportConceptApprovalPeriod.ServiceCategory != null && data != null && data.Count > 0)
|
|
{
|
|
if (supportConceptApprovalPeriod.StartDate.HasValue && supportConceptApprovalPeriod.StartDate.Value > start)
|
|
{
|
|
start = supportConceptApprovalPeriod.StartDate.Value;
|
|
}
|
|
if (supportConceptApprovalPeriod.EndDate.HasValue && supportConceptApprovalPeriod.EndDate.Value < end)
|
|
{
|
|
end = supportConceptApprovalPeriod.EndDate.Value;
|
|
}
|
|
decimal preis = (decimal)Math.Round((double)data[0].AmountTotal, 2, MidpointRounding.AwayFromZero);
|
|
decimal days = (decimal)(end - start).TotalDays + 1;
|
|
|
|
// im Normalfall monatliche Abrechnung
|
|
if (start.Year == end.Year && start.Month == end.Month)
|
|
{
|
|
CreateInvoiceItemsLwv(serviceInvoicePeriod, supportConceptApprovalPeriod, start, end, preis, null);
|
|
}
|
|
// ...aber es können auch Zeiträume für einzelne Klienten nachträglich abgerechnet werden,
|
|
// dann monatliche Rechnungsposition
|
|
else
|
|
{
|
|
monthly = false;
|
|
var monthlyDict = data
|
|
.GroupBy(e => new DateTime(e.BillingPeriodStart.Value.Year, e.BillingPeriodStart.Value.Month, 1))
|
|
.ToDictionary(
|
|
g => g.Key,
|
|
g => g.OrderBy(e => e.BillingPeriodStart).ToList() // Liste der Einträge in diesem Monat
|
|
);
|
|
|
|
foreach (var kvp in monthlyDict.OrderBy(k => k.Key))
|
|
{
|
|
var month = kvp.Key; // z.B. 2025-01-01
|
|
var entries = kvp.Value;
|
|
preis = (decimal)Math.Round((double)entries[0].AmountTotal, 2, MidpointRounding.AwayFromZero);
|
|
days = entries.Count;
|
|
var lastday = entries.LastOrDefault();
|
|
CreateInvoiceItemsLwv(serviceInvoicePeriod, supportConceptApprovalPeriod, entries[0].BillingPeriodStart.Value, lastday.BillingPeriodStart.Value, preis, days);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void CreateInvoiceItemsLwv(ServiceInvoicePeriod serviceInvoicePeriod, SupportConceptApprovalPeriodDC supportConceptApprovalPeriod, DateTime start, DateTime end, decimal preis, decimal? days)
|
|
{
|
|
if (days == null)
|
|
{
|
|
days = (decimal)(end - start).TotalDays + 1;
|
|
}
|
|
var ii = new InvoiceItem
|
|
{
|
|
ItemPeriodStart = serviceInvoicePeriod.Start,
|
|
ItemPeriodEnd = serviceInvoicePeriod.End,
|
|
SupportConceptApprovalPeriodOid = supportConceptApprovalPeriod.SupportConceptApprovalPeriodOid,
|
|
AccountingInterval = AccountingIntervalType.Daily,
|
|
UnitCount = days,
|
|
UnitDescription = String.Format("{0:MM.yyyy}", start),
|
|
Notice = "keine Minuten"
|
|
};
|
|
if (supportConceptApprovalPeriod.ServiceCategory.Name.Contains("Bedarfsgruppe"))
|
|
{
|
|
bool teilmonat = false;
|
|
if (supportConceptApprovalPeriod.StartDate != null && supportConceptApprovalPeriod.StartDate > start)
|
|
{
|
|
start = supportConceptApprovalPeriod.StartDate.Value;
|
|
teilmonat = true;
|
|
}
|
|
if (supportConceptApprovalPeriod.EndDate != null && supportConceptApprovalPeriod.EndDate < end)
|
|
{
|
|
end = supportConceptApprovalPeriod.EndDate.Value;
|
|
teilmonat = true;
|
|
}
|
|
|
|
ii.AccountingInterval = AccountingIntervalType.Monthly;
|
|
ii.ItemDescription = supportConceptApprovalPeriod.ServiceCategory.Name;
|
|
ii.UnitCount = 1;
|
|
ii.AmountPerUnit = preis;
|
|
if (teilmonat)
|
|
{
|
|
var teiltage = (double)(end - start).TotalDays + 1;
|
|
ii.AmountPerUnit = (decimal)Math.Round((double)preis / 30.42 * teiltage, 2, MidpointRounding.AwayFromZero);
|
|
}
|
|
ii.AmountTotal = ii.AmountPerUnit;
|
|
ii.GrossAmountTotal = ii.AmountTotal;
|
|
ii.Notice = "";
|
|
serviceInvoicePeriod.InvoiceItemList.Add(ii);
|
|
return;
|
|
}
|
|
if (supportConceptApprovalPeriod.ApprovedBEPerInterval.HasValue)
|
|
{
|
|
ii.Notice = String.Format("{0:n0}", supportConceptApprovalPeriod.ApprovedBEPerInterval.Value);
|
|
if (!monthly) // Bei Nachberechnung muss der Preis monatlich geprüft werden
|
|
{
|
|
var pauschVar = base.GetPreis("Fahrzeitenzuschlag qA", start);
|
|
if (pauschVar != 0)
|
|
{
|
|
AMOUNT_PER_KMQA = pauschVar;
|
|
}
|
|
}
|
|
if (supportConceptApprovalPeriod.ServiceCategory.Name.Contains("Fahrzeit"))
|
|
{
|
|
ii.AmountPerUnit = supportConceptApprovalPeriod.ApprovedBEPerInterval * AMOUNT_PER_KMQA;
|
|
ii.ItemDescription = "Fahrzeiten QA";
|
|
}
|
|
else
|
|
{
|
|
if (supportConceptApprovalPeriod.ApprovedFixedAmount != null)
|
|
{
|
|
ii.AmountPerUnit = supportConceptApprovalPeriod.ApprovedFixedAmount;
|
|
}
|
|
else
|
|
{
|
|
ii.AmountPerUnit = supportConceptApprovalPeriod.ApprovedBEPerInterval * (decimal)Math.Round((double)preis / 60, 4, MidpointRounding.AwayFromZero);
|
|
}
|
|
ii.ItemDescription = "Qualifizierte Assistenz";
|
|
}
|
|
|
|
ii.AmountPerUnit = Math.Round((decimal)ii.AmountPerUnit, 2, MidpointRounding.AwayFromZero);
|
|
ii.AmountTotal = ii.UnitCount * ii.AmountPerUnit;
|
|
ii.GrossAmountTotal = ii.AmountTotal;
|
|
}
|
|
serviceInvoicePeriod.InvoiceItemList.Add(ii);
|
|
|
|
if (supportConceptApprovalPeriod.MonthlyPayment.HasValue && supportConceptApprovalPeriod.MonthlyPayment > 0)
|
|
{
|
|
var equity = supportConceptApprovalPeriod.MonthlyPayment.Value;
|
|
if (equity > 0)
|
|
{
|
|
var iiE = new InvoiceItem();
|
|
iiE.UnitCount = 1;
|
|
iiE.AmountPerUnit = equity;
|
|
iiE.AmountTotal = -equity;
|
|
iiE.GrossAmountTotal = -equity;
|
|
iiE.ItemPeriodStart = ii.ItemPeriodStart;
|
|
iiE.ItemPeriodEnd = ii.ItemPeriodEnd;
|
|
iiE.Notice = "";
|
|
iiE.SupportConceptApprovalPeriodOid = ii.SupportConceptApprovalPeriodOid;
|
|
iiE.ItemDescription = "Eigenanteil";
|
|
iiE.UnitDescription = String.Format("{0:MM.yyyy}", start);
|
|
|
|
serviceInvoicePeriod.InvoiceItemList.Add(iiE);
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void SetServiceInvoicePeriodAmounts(ServiceInvoice invoice)
|
|
{
|
|
foreach (ServiceInvoicePeriod iPeriod in invoice.ServiceInvoicePeriodList)
|
|
{
|
|
iPeriod.Claim = 0;
|
|
if (iPeriod.SupportConceptApprovalPeriod.ServiceCategory.Name != "qA" && iPeriod.ApprovedFixedAmount.HasValue && iPeriod.ApprovedFixedAmount.Value != 0)
|
|
iPeriod.Claim = iPeriod.ApprovedFixedAmount;
|
|
else
|
|
{
|
|
foreach (InvoiceItem item in iPeriod.InvoiceItemList)
|
|
{
|
|
if (item.GrossAmountTotal.HasValue)
|
|
iPeriod.Claim += item.GrossAmountTotal;
|
|
}
|
|
}
|
|
iPeriod.Claim = Math.Round(iPeriod.Claim.Value, 2, MidpointRounding.AwayFromZero);
|
|
}
|
|
}
|
|
}
|
|
}
|