248 lines
12 KiB
C#
248 lines
12 KiB
C#
using BeWo.Data.Access;
|
|
using BeWo.Data.Entities;
|
|
using BeWo.Data.Models.XRechnung;
|
|
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.Extensions;
|
|
using BS.Shared.Services;
|
|
using DevExpress.Data.Helpers;
|
|
using DevExpress.DataProcessing.InMemoryDataProcessor;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
|
|
namespace SBBMainzReports.Invoicing
|
|
{
|
|
public class CustomInvoiceCreationQA : InvoiceCreation
|
|
{
|
|
// Bei QA werden werden pauschal die bewilligten Stunden pro Woche abgerechnet
|
|
// nur wenn ein Kontingent bewilligt wurde, wird es nach Zeiterfassung abgerechnet
|
|
|
|
bool bienen_ = false;
|
|
public override void SetInvoiceItems(ServiceInvoice invoice,
|
|
ServiceInvoicePeriod serviceInvoicePeriod,
|
|
SupportConceptApprovalPeriodDC supportConceptApprovalPeriod,
|
|
CostBearer2SupportConcept cb2sc,
|
|
DateTimeSpan invoicePeriod,
|
|
List<ServiceRecordDC> serviceRecords)
|
|
{
|
|
Calculations calc = PluginLoader.FindClass<Calculations>(_SpecificID) ?? Calculations.GetInstance(_SpecificID);
|
|
List<ServiceRecordDC> serviceRecordsInPeriod = serviceRecords.Where(
|
|
i =>
|
|
{
|
|
bool valid = i.Start.Value.InBetween(serviceInvoicePeriod.Start.Value, serviceInvoicePeriod.End.Value, true);
|
|
|
|
if (valid && serviceInvoicePeriod.SupportConceptApprovalPeriod != null && serviceInvoicePeriod.SupportConceptApprovalPeriod.ServiceCategory != null)
|
|
valid = serviceInvoicePeriod.SupportConceptApprovalPeriod.ServiceCategory.Oid == i.ServiceDescription.Category.ServiceCategoryOid;
|
|
return valid;
|
|
}).ToList();
|
|
if (cb2sc.CustomerReferenceNumber != null && cb2sc.CustomerReferenceNumber.Trim().ToLower().EndsWith("b") || (cb2sc.AuswahlBezeichnung != null && cb2sc.AuswahlBezeichnung.Trim().ToLower().Contains("bienen")))
|
|
{
|
|
bienen_ = true;
|
|
}
|
|
if (ShouldCreateFixedAmounts(serviceInvoicePeriod, supportConceptApprovalPeriod, cb2sc))
|
|
{
|
|
CreateFixedAmounts(serviceInvoicePeriod, supportConceptApprovalPeriod, cb2sc);
|
|
// Erweiterung um Wegepauschale
|
|
if (serviceRecordsInPeriod.Count > 0 && !bienen_)
|
|
{
|
|
InvoiceItem wg = null;
|
|
wg = CreateWegepauschale(serviceRecordsInPeriod, invoicePeriod, serviceInvoicePeriod.SupportConceptApprovalPeriod);
|
|
if (wg != null)
|
|
{
|
|
serviceInvoicePeriod.InvoiceItemList.Add(wg);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (serviceRecordsInPeriod.Count > 0)
|
|
{
|
|
var absenceTimes = MapperFactory.AbsenceTimeDC_AbsenceTime.MapToNewDCs(cb2sc.SupportConcept.Customer.AbsenceTimes);
|
|
Dictionary<DateTimeSpan, decimal> span2Hours = calc.GetAbsencesTimesNotBillable(absenceTimes);
|
|
|
|
serviceInvoicePeriod.HoursNotBillableAbsence +=
|
|
calc.GetHoursNotBillableDueToAbsenceTimes(supportConceptApprovalPeriod,
|
|
cb2sc.CostBearer.CostRatePeriods.MapToNewDCs(),
|
|
serviceRecordsInPeriod,
|
|
span2Hours,
|
|
true, true);
|
|
if (!supportConceptApprovalPeriod.IsApprovedBEShifting)
|
|
{
|
|
serviceInvoicePeriod.HoursNotBillableNotApproved +=
|
|
calc.GetHoursNotBillableDueToMoreThanApproved(supportConceptApprovalPeriod,
|
|
cb2sc.CostBearer.CostRatePeriods.MapToNewDCs(),
|
|
serviceRecordsInPeriod,
|
|
true, true);
|
|
}
|
|
|
|
var itemList = CreateInvoiceItems(serviceRecordsInPeriod, invoicePeriod, serviceInvoicePeriod.SupportConceptApprovalPeriod, calc);
|
|
serviceInvoicePeriod.InvoiceItemList.AddRange(itemList);
|
|
}
|
|
}
|
|
}
|
|
|
|
public override bool ShouldCreateFixedAmounts(ServiceInvoicePeriod serviceInvoicePeriod, SupportConceptApprovalPeriodDC scap, CostBearer2SupportConcept cb2sc)
|
|
{
|
|
if (scap.ApprovedBEInterval.Value == SupportConceptApprovalInterval.Weekly && scap.ApprovedBEInterval.HasValue && scap.ApprovedBEPerInterval.HasValue)
|
|
{
|
|
return true;
|
|
}
|
|
if (scap.Notice != null && scap.Notice.ToLower().StartsWith("kontingent") && scap.ApprovedBETotal.HasValue)
|
|
{
|
|
List<CostRatePeriodDC> crList = scap.ServiceCategory.CostRatePeriods;
|
|
AccountingIntervalType? ai = scap.ServiceCategory.AccountingInterval;
|
|
|
|
if (ai.HasValue && crList.Count(c => c.CostRateValue.HasValue) > 0)
|
|
{
|
|
return ai.Value != AccountingIntervalType.Hourly;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public override void CreateFixedAmounts(ServiceInvoicePeriod serviceInvoicePeriod, SupportConceptApprovalPeriodDC supportConceptApprovalPeriod, CostBearer2SupportConcept cb2sc)
|
|
{
|
|
var calc = PluginLoader.FindClass<Calculations>(_SpecificID) ?? Calculations.GetInstance(_SpecificID);
|
|
var scap = supportConceptApprovalPeriod;
|
|
var crList = scap.ServiceCategory.CostRatePeriods;
|
|
var cr = crList.GetCostRatePeriodForDate(BS.Shared.CostRatePeriodType.AmountOfMoney, serviceInvoicePeriod.Start.Value);
|
|
if (cr != null && cr.CostRateValue.HasValue)
|
|
{
|
|
decimal? hourlyRate = cr.CostRateValue.Value;
|
|
decimal weeklyFactor = 4.33m;
|
|
// Anteilige Berechnung nur in dem Monat, in dem der HP tatsächlich beginnt bzw. endet -
|
|
// in allen anderen (vollen) Monaten wird der volle Monatsfaktor berechnet
|
|
if (scap.StartDate.HasValue && scap.StartDate.Value.Day > 7 && serviceInvoicePeriod.Start.HasValue
|
|
&& scap.StartDate.Value.Year == serviceInvoicePeriod.Start.Value.Year && scap.StartDate.Value.Month == serviceInvoicePeriod.Start.Value.Month)
|
|
{
|
|
int startDay = scap.StartDate.Value.Day;
|
|
if (startDay <= 14)
|
|
{
|
|
weeklyFactor = Math.Min(weeklyFactor, 3m);
|
|
}
|
|
else if (startDay <= 21)
|
|
{
|
|
weeklyFactor = Math.Min(weeklyFactor, 2m);
|
|
}
|
|
else
|
|
{
|
|
weeklyFactor = Math.Min(weeklyFactor, 1m);
|
|
}
|
|
}
|
|
if (scap.EndDate.HasValue && scap.EndDate.Value.Day < 22 && serviceInvoicePeriod.End.HasValue
|
|
&& scap.EndDate.Value.Year == serviceInvoicePeriod.End.Value.Year && scap.EndDate.Value.Month == serviceInvoicePeriod.End.Value.Month)
|
|
{
|
|
int endDay = scap.EndDate.Value.Day;
|
|
if (endDay >= 15)
|
|
{
|
|
weeklyFactor = Math.Min(weeklyFactor, 3m);
|
|
}
|
|
else if (endDay >= 8)
|
|
{
|
|
weeklyFactor = Math.Min(weeklyFactor, 2m);
|
|
}
|
|
else
|
|
{
|
|
weeklyFactor = Math.Min(weeklyFactor, 1m);
|
|
}
|
|
}
|
|
|
|
decimal approvedHours = 0;
|
|
decimal approvedHoursMonth = 0;
|
|
if (scap.ApprovedBEInterval.HasValue && scap.ApprovedBEInterval.Value == SupportConceptApprovalInterval.Weekly && scap.ApprovedBEPerInterval.HasValue)
|
|
{
|
|
approvedHours = scap.ApprovedBEPerInterval.Value;
|
|
approvedHoursMonth = weeklyFactor * scap.ApprovedBEPerInterval.Value;
|
|
}
|
|
decimal amount = approvedHoursMonth * hourlyRate.Value;
|
|
serviceInvoicePeriod.InvoiceItemList.Add(new InvoiceItem
|
|
{
|
|
AmountTotal = amount,
|
|
GrossAmountTotal = amount,
|
|
ItemPeriodStart = serviceInvoicePeriod.Start,
|
|
ItemPeriodEnd = serviceInvoicePeriod.End,
|
|
AmountPerUnit = hourlyRate.Value,
|
|
ItemDescription = "Fachleistungseinheiten/Woche",
|
|
UnitDescription = "QA/Woche",
|
|
UnitCount = approvedHours,
|
|
Notice = approvedHoursMonth.ToString("n2")
|
|
});
|
|
}
|
|
}
|
|
|
|
public override IList<InvoiceItem> CreateInvoiceItems(List<ServiceRecordDC> serviceRecordsInPeriod, DateTimeSpan invoicePeriod, SupportConceptApprovalPeriod scap,
|
|
BS.Shared.Services.Calculations calc)
|
|
{
|
|
var list = base.CreateInvoiceItems(serviceRecordsInPeriod, invoicePeriod, scap, calc);
|
|
InvoiceItem wg = null;
|
|
if (list.Count > 0 && !bienen_)
|
|
{
|
|
wg = CreateWegepauschale(serviceRecordsInPeriod, invoicePeriod, scap);
|
|
if (wg != null)
|
|
{
|
|
list.Add(wg);
|
|
}
|
|
}
|
|
return list;
|
|
}
|
|
|
|
private InvoiceItem CreateWegepauschale(List<ServiceRecordDC> serviceRecordsInPeriod, DateTimeSpan invoicePeriod, SupportConceptApprovalPeriod scap)
|
|
{
|
|
decimal wegepauschale = 17.35m;
|
|
wegepauschale = base.GetPreis("Wegepauschale", invoicePeriod.StartDate);
|
|
int countWege = 0;
|
|
//Anzahl der Zeiterfassungseinträge, die nicht im Büro stattfinden
|
|
countWege = serviceRecordsInPeriod.Where(r => r.ServiceDescription.CategoryName.Contains("QA") && !r.ServiceDescription.Name.Contains("Büro")).Count();
|
|
|
|
if (countWege > 0)
|
|
{
|
|
decimal anzahlWege = countWege;
|
|
var invoiceItem = new InvoiceItem();
|
|
invoiceItem.AmountPerUnit = wegepauschale;
|
|
invoiceItem.UnitCount = anzahlWege;
|
|
invoiceItem.AmountTotal = anzahlWege * wegepauschale;
|
|
invoiceItem.ItemPeriodStart = invoicePeriod.StartDate;
|
|
invoiceItem.ItemPeriodEnd = invoicePeriod.EndDate;
|
|
invoiceItem.RateFactor = null;
|
|
invoiceItem.GrossAmountTotal = invoiceItem.AmountTotal;
|
|
invoiceItem.ItemDescription = "Wegepauschale/Anzahl";
|
|
if (scap != null)
|
|
{
|
|
invoiceItem.SupportConceptApprovalPeriodOid = scap.Oid;
|
|
}
|
|
|
|
return invoiceItem;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public override void SetRecipientInformation(ServiceInvoice serviceInvoice, CostBearer costBearer)
|
|
{
|
|
base.SetRecipientInformation(serviceInvoice, costBearer);
|
|
if (serviceInvoice.InvoiceBase.CostBearer2SupportConcept != null)
|
|
{
|
|
var refNumber = serviceInvoice.InvoiceBase.CostBearer2SupportConcept.CustomerReferenceNumber;
|
|
if (!string.IsNullOrEmpty(refNumber))
|
|
{
|
|
var parts = refNumber.Split('.');
|
|
if (parts.Length == 3 && parts[0].Trim() == "50" && int.TryParse(parts[1].Trim(), out _))
|
|
{
|
|
string sachgebiet = parts[1].Trim();
|
|
string suffix = $"Sachgebiet {sachgebiet}";
|
|
if (string.IsNullOrEmpty(serviceInvoice.InvoiceBase.RecipientDivision))
|
|
serviceInvoice.InvoiceBase.RecipientDivision = suffix;
|
|
else if (!serviceInvoice.InvoiceBase.RecipientDivision.EndsWith(suffix))
|
|
serviceInvoice.InvoiceBase.RecipientDivision += $" {suffix}";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|