332 lines
12 KiB
C#
332 lines
12 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.ServiceModel;
|
|
using System.Text;
|
|
using System.Windows.Forms;
|
|
using BeWo.Data.Access;
|
|
using BeWo.Data.Entities;
|
|
using BeWo.Service.DCEntityMapper;
|
|
using BeWo.Service.Invoicing;
|
|
using BeWo.Service.Plugins;
|
|
using BeWo.Service.ServiceContracts;
|
|
using BS.Shared;
|
|
using BS.Shared.Core;
|
|
using BS.Shared.DataContracts;
|
|
using BS.Shared.Extensions;
|
|
using BS.Shared.Services;
|
|
using DevExpress.Data.Helpers;
|
|
using Service.Invoicing;
|
|
|
|
namespace AWOMuensterlandRecklinghausen.Invoicing
|
|
{
|
|
public class CustomInvoiceCreation : SbdDefaultInvoiceCreation
|
|
{
|
|
public override void SetInvoiceId(ServiceInvoice invoice)
|
|
{
|
|
if (invoice.InvoiceBase.AccountingPeriodStart > new DateTime(2024, 03, 31)) //neues Rechnungsformular
|
|
{
|
|
invoice.InvoiceBase.InvoiceId = "SBD2024";
|
|
}
|
|
else
|
|
{
|
|
invoice.InvoiceBase.InvoiceId = "SBD";
|
|
}
|
|
invoice.InvoiceBase.InvoiceTypeText = "Abrechnung Schulbegleitender Dienst";
|
|
}
|
|
|
|
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);
|
|
|
|
if (ShouldCreateFixedAmounts(serviceInvoicePeriod, supportConceptApprovalPeriod, cb2sc))
|
|
{
|
|
CreateFixedAmounts(serviceInvoicePeriod, supportConceptApprovalPeriod, cb2sc);
|
|
}
|
|
else
|
|
{
|
|
|
|
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();
|
|
|
|
|
|
var itemList = CreateAllInvoiceItems(cb2sc, serviceRecordsInPeriod, invoicePeriod, serviceInvoicePeriod.SupportConceptApprovalPeriod, calc);
|
|
serviceInvoicePeriod.InvoiceItemList.AddRange(itemList);
|
|
}
|
|
}
|
|
|
|
public override IList<InvoiceItem> CreateSbdInvoiceItems(Customer customer, List<ServiceRecordDC> serviceRecordsInPeriod, DateTimeSpan invoicePeriod, SupportConceptApprovalPeriod scap, Calculations calc)
|
|
{
|
|
IList<InvoiceItem> result = new List<InvoiceItem>();
|
|
var ccSchule = GetCostCenterSchule(customer); //Kostenstellen setzen sich zusammen aus: Schule (3Stellen) und Qualifikation MA 3 Stellen
|
|
string ccEmp; //GetHauptbetreuer(customer, true);
|
|
Dictionary<long, string> emp2Value = new Dictionary<long, string>();
|
|
|
|
IList<InvoiceItem> srList = new List<InvoiceItem>();
|
|
foreach (ServiceRecordDC iServiceRecord in serviceRecordsInPeriod)
|
|
{
|
|
if (iServiceRecord.ServiceDescription.Category.IsBillable)
|
|
{
|
|
if (!iServiceRecord.AlreadyAccounted)
|
|
{
|
|
var invoiceItem = CreateInvoiceItem(iServiceRecord, scap, calc);
|
|
if (invoiceItem.ItemDescription.ToLower().Contains("pool"))
|
|
{
|
|
ccEmp = "510"; //Bei Pool ist die Qualifikation MA hinfällig -> immer 510
|
|
}
|
|
else
|
|
{
|
|
long empOid = iServiceRecord.Employee.EmployeeOid;
|
|
if (emp2Value.ContainsKey(iServiceRecord.Employee.EmployeeOid))
|
|
{
|
|
ccEmp = emp2Value[empOid];
|
|
}
|
|
else
|
|
{
|
|
var emp = DAOFactory.GenericDAO.GetByID<Employee>(empOid);
|
|
if (emp == null)
|
|
{
|
|
ccEmp = "312500".Substring(3, 3);
|
|
emp2Value.Add(0, ccEmp);
|
|
}
|
|
else
|
|
{
|
|
if (emp.TaxNumber == null || emp.TaxNumber == "")
|
|
{
|
|
//throw new FaultException<BeWoFault>(new BeWoFault(String.Format("Bei Mitarbeiter*in {0} wurde keine Kostenstelle hinterlegt", emp.Person.FirstNameLastName), BeWoFaultType.CustomWithoutDetails));
|
|
emp.TaxNumber = "312500";
|
|
}
|
|
ccEmp = emp.TaxNumber.Substring(3, 3);
|
|
emp2Value.Add(empOid, ccEmp);
|
|
}
|
|
}
|
|
}
|
|
//Sonderfälle -> wenn MA mit anderer Quali vertritt, teilweise weiter Ursprungskostenstelle:
|
|
if (ccEmp == "560") //FK vertritt bei ENFK
|
|
{
|
|
if (invoiceItem.ItemDescription.ToLower().Contains("enfk"))
|
|
{
|
|
ccEmp = "550";
|
|
}
|
|
}
|
|
if (ccEmp == "550") //ENFK vertritt bei FSJ
|
|
{
|
|
if (invoiceItem.ItemDescription.ToLower().Contains("fsj"))
|
|
{
|
|
ccEmp = "540";
|
|
}
|
|
}
|
|
invoiceItem.UnitDescription = String.Format("{0}{1}", ccSchule, ccEmp);
|
|
srList.Add(invoiceItem);
|
|
|
|
iServiceRecord.AlreadyAccounted = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
Dictionary<String, bool> dayDict = new Dictionary<String, bool>();
|
|
foreach (var item in srList)
|
|
{
|
|
String key = String.Format("{0:dd.MM.yyyy}", item.ItemPeriodStart);
|
|
|
|
if (!dayDict.ContainsKey(key))
|
|
{
|
|
dayDict.Add(key, true);
|
|
}
|
|
|
|
result.Add(item);
|
|
}
|
|
|
|
var newList = result.Where(i => i.UnitCount.HasValue && i.UnitCount.Value > 0).OrderBy(i => i.ItemPeriodStart).ToList();
|
|
return newList;
|
|
}
|
|
|
|
private IList<InvoiceItem> CreateRateFactorInvoiceItems(IList<InvoiceItem> basisList, DateTimeSpan invoicePeriod, SupportConceptApprovalPeriod scap, Calculations calc)
|
|
{
|
|
IList<InvoiceItem> newList = new List<InvoiceItem>();
|
|
var rfItem = new InvoiceItem();
|
|
decimal hours = 0;
|
|
decimal hourlyRate = 0;
|
|
decimal ratefactor = 0;
|
|
|
|
foreach (var item in basisList)
|
|
{
|
|
newList.Add(item);
|
|
if (item.RateFactor != null && item.RateFactor > 0)
|
|
{
|
|
rfItem = new InvoiceItem();
|
|
rfItem.ItemPeriodStart = item.ItemPeriodStart;
|
|
rfItem.ItemPeriodEnd = item.ItemPeriodEnd;
|
|
rfItem.RateFactor = item.RateFactor;
|
|
hours = item.UnitCount ?? 0;
|
|
hourlyRate = item.AmountPerUnit ?? 0;
|
|
ratefactor = item.RateFactor ?? 0;
|
|
|
|
rfItem.AmountPerUnit = Math.Round(hourlyRate * (ratefactor / 100), 2, MidpointRounding.AwayFromZero);
|
|
rfItem.UnitCount = hours;
|
|
rfItem.AmountTotal = Math.Round((rfItem.AmountPerUnit ?? 0) * hours, 2, MidpointRounding.AwayFromZero);
|
|
rfItem.GrossAmountTotal = rfItem.AmountTotal;
|
|
rfItem.ItemDescription = String.Format("{0:0.##}% Zuschlag auf Betreuungszeit", ratefactor);
|
|
newList.Add(rfItem);
|
|
}
|
|
}
|
|
return newList;
|
|
}
|
|
|
|
public override IList<InvoiceItem> CreateAllInvoiceItems(CostBearer2SupportConcept c2s, List<ServiceRecordDC> serviceRecordsInPeriod, DateTimeSpan invoicePeriod, SupportConceptApprovalPeriod scap, Calculations calc)
|
|
{
|
|
var items = CreateSbdInvoiceItems(c2s.SupportConcept.Customer, serviceRecordsInPeriod, invoicePeriod, scap, calc);
|
|
|
|
decimal hours = 0;
|
|
decimal hourlyRate = 0;
|
|
decimal ratefactor = 0;
|
|
bool pausenabzug = CheckPausenabzug(c2s.SupportConcept);
|
|
|
|
var crList = MapperFactory.CostRatePeriodDC_CostRatePeriod.MapToNewDCs(c2s.CostBearer.CostRatePeriods);
|
|
|
|
foreach (var item in items)
|
|
{
|
|
if (!item.AmountPerUnit.HasValue)
|
|
{
|
|
item.AmountPerUnit = GetCostRateValue(crList, CostRatePeriodType.HourlyRate, item.ItemPeriodStart.Value);
|
|
}
|
|
if (!item.RateFactor.HasValue)
|
|
{
|
|
item.RateFactor = GetCostRateValue(crList, CostRatePeriodType.RateFactor, item.ItemPeriodStart.Value);
|
|
}
|
|
|
|
item.ItemPeriodStart = item.ItemPeriodStart;
|
|
item.ItemPeriodEnd = item.ItemPeriodEnd;
|
|
if (pausenabzug && item.ServiceRecord.GroupOid != null && item.ServiceRecord.GroupRoundedDuration > 360) //Brummel - die ist in Minuten
|
|
{
|
|
item.UnitCount = (decimal?)((item.ServiceRecord.GroupRoundedDuration - 30) / item.ServiceRecord.GroupPersonCount / 60);
|
|
}
|
|
if (item.ServiceRecord.GroupOid == null && pausenabzug && item.UnitCount > 6)
|
|
{
|
|
item.UnitCount -= (decimal)0.5;
|
|
//hours = item.UnitCount ?? 0;
|
|
}
|
|
if (item.ServiceRecord.Notice != null && item.ServiceRecord.Notice.StartsWith("KF-Pauschale"))
|
|
{
|
|
item.UnitCount = 10;
|
|
item.ItemDescription = "Klassenfahrt-Pauschale";
|
|
}
|
|
item.UnitCount = Math.Round(item.UnitCount ?? 0, 2, MidpointRounding.AwayFromZero);
|
|
hours = item.UnitCount ?? 0;
|
|
hourlyRate = item.AmountPerUnit ?? 0;
|
|
ratefactor = item.RateFactor ?? 0;
|
|
item.AmountTotal = Math.Round(hourlyRate * hours, 2, MidpointRounding.AwayFromZero);
|
|
item.GrossAmountTotal = item.AmountTotal;
|
|
|
|
}
|
|
var basisList = CreateSummaryInvoiceItems(items, invoicePeriod, scap, calc);
|
|
|
|
return CreateRateFactorInvoiceItems(basisList, invoicePeriod, scap, calc);
|
|
}
|
|
|
|
public override IList<InvoiceItem> CreateSummaryInvoiceItems(IList<InvoiceItem> itemList, DateTimeSpan invoicePeriod, SupportConceptApprovalPeriod scap, Calculations calc)
|
|
{
|
|
return CreateSummaryInvoiceItems(itemList, invoicePeriod, scap, calc, true);
|
|
}
|
|
|
|
public override IList<InvoiceItem> CreateSummaryInvoiceItems(IList<InvoiceItem> itemList,
|
|
DateTimeSpan invoicePeriod, SupportConceptApprovalPeriod scap, Calculations calc, bool summaryPerMonth)
|
|
{
|
|
return CreateSummaryInvoiceItems(itemList, invoicePeriod, scap, calc, summaryPerMonth, true);
|
|
}
|
|
|
|
public override string GetSummaryItemKey(SupportConceptApprovalPeriod scap, InvoiceItem iitem, bool summaryPerMonth)
|
|
{
|
|
String key = String.Format("{0}_{1}_{2}", iitem.AmountPerUnit, iitem.ItemDescription, iitem.UnitDescription);
|
|
if (summaryPerMonth)
|
|
{
|
|
key = String.Format("{0}_{1}_{2}_{3:yyyyMM}", iitem.AmountPerUnit, iitem.ItemDescription, iitem.UnitDescription, iitem.ItemPeriodStart);
|
|
}
|
|
return key;
|
|
}
|
|
|
|
private string GetHauptbetreuer(Customer customer, bool costcenter)
|
|
{
|
|
foreach (var e2c in customer.Employee2CustomerList)
|
|
{
|
|
foreach (var v2e in e2c.ValueList)
|
|
{
|
|
if (v2e.Entry.Type == ValueListEntryType.StaffRoleType && v2e.Entry.Value == "Hauptbetreuung")
|
|
{
|
|
if (costcenter && e2c.Employee.TaxNumber.Length > 0)
|
|
{
|
|
return e2c.Employee.TaxNumber.Substring(3, 3);
|
|
}
|
|
else
|
|
{
|
|
return e2c.Employee.Person.FirstNameLastName;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//throw new FaultException<BeWoFault>(new BeWoFault(String.Format("Es wurde keine Hauptbetreuung für {0} gefunden.", customer.Person.FirstNameLastName), BeWoFaultType.CustomWithoutDetails));
|
|
return "";
|
|
}
|
|
|
|
private decimal GetCostRateValue(List<CostRatePeriodDC> crList, CostRatePeriodType t, DateTime date)
|
|
{
|
|
var cp = crList.GetCostRatePeriodForDate(t, date);
|
|
if (cp != null && cp.CostRateValue.HasValue)
|
|
return cp.CostRateValue.Value;
|
|
return 0;
|
|
}
|
|
|
|
|
|
private string GetCostCenterSchule(Customer c)
|
|
{
|
|
foreach (var c2o in c.Customer2OrganisationList)
|
|
{
|
|
foreach (var v2e in c2o.ValueList)
|
|
{
|
|
if (v2e.Entry.Type == ValueListEntryType.EnvironmentOrganisationType && v2e.Entry.Value.ToLower().Contains("schule"))
|
|
{
|
|
if (c2o.Organisation.DebitorNumber != null)
|
|
{
|
|
return c2o.Organisation.DebitorNumber.Trim();
|
|
}
|
|
else
|
|
{
|
|
return "300";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//throw new FaultException<BeWoFault>(new BeWoFault(String.Format("Es wurde keine Schule für { 0 } gefunden.", c.Person.FirstNameLastName), BeWoFaultType.CustomWithoutDetails));
|
|
return "300";
|
|
}
|
|
|
|
private bool CheckPausenabzug(SupportConcept sc)
|
|
{
|
|
var vv = sc.VarFieldValueList.FirstOrDefault(v => v.VarFieldDefOid.Value == 90);
|
|
if (vv != null)
|
|
{
|
|
var varFieldValue = BS.Shared.Core.Utils.XMLDeserializeFromString(vv.SerializedValue, Type.GetType(vv.TypeName));
|
|
if (varFieldValue != null && varFieldValue.ToString().ToLower() == "true")
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
}
|