2024-12-09 11:16:17 +01:00
using System ;
using System.Collections.Generic ;
using System.Linq ;
using System.ServiceModel ;
using BeWo.Data.Access ;
using BeWo.Data.Entities ;
using BeWo.Data.Security ;
using BeWo.Service.Configuration ;
using BeWo.Service.Core ;
using BeWo.Service.DCEntityMapper ;
using BeWo.Service.Invoicing ;
using BS.Shared ;
using BS.Shared.Core ;
using BS.Shared.DataContracts ;
using BS.Shared.DataContracts.Compact ;
using BS.Shared.Extensions ;
2025-11-07 14:54:55 +01:00
using BS.Shared.Models ;
2024-12-09 11:16:17 +01:00
namespace BeWo.Service.Plugins
{
2026-04-27 15:55:32 +02:00
public class AccountingService : AbstractIDSpecificDefaultClass < AccountingService >
{
public virtual List < ServiceInvoiceDC > GenerateInitialServiceInvoices ( long costBearerOid , long? supportConceptOid , DateTimeSpan invoicePeriod )
2024-12-09 11:16:17 +01:00
{
2026-04-27 15:55:32 +02:00
var cs = PluginLoader . FindClass < CustomerService > ( ) ;
IEnumerable < CompactSupportConceptDC > supportConcepts ;
// GetAllActiveSupportConceptCostbearer returns a "Flat" SupportConcept List, one for each CostBearer2SupportConcept!
if ( ! supportConceptOid . HasValue )
{
supportConcepts = cs . GetAllActiveSupportConceptCostbearer ( false , true , 0 )
. Where ( i = > i . CostBearerOids2CostBearerRelOids . ContainsKey ( costBearerOid ) ) ;
}
else
{
supportConcepts = cs . GetCompactSupportConcepts ( supportConceptOid . Value , null )
. Where ( i = > i . CostBearerOids2CostBearerRelOids . ContainsKey ( costBearerOid ) ) ;
}
DateTimeSpan newSpan = null ;
if ( invoicePeriod ! = null )
{
//invoicePeriod.StartDateTime = invoicePeriod.StartDateTime.Date;
//invoicePeriod.EndDateTime = invoicePeriod.EndDateTime.Date;
newSpan = new DateTimeSpan ( ) ;
newSpan . StartDateTime = invoicePeriod . StartDateTime . Date ;
newSpan . EndDateTime = invoicePeriod . EndDateTime . Date . AddDays ( 1 ) . AddTicks ( - 1 ) ;
if ( ! supportConceptOid . HasValue )
{
supportConcepts =
supportConcepts . Where ( sc = > sc . StartDate < newSpan . EndDateTime & & sc . EndDate > = newSpan . StartDate ) ;
}
}
var supportConcepts2ServiceRecords = supportConcepts . ToDictionary (
i = > i ,
i = > MapperFactory . ServiceRecordDC_ServiceRecord . MapToNewDCs (
DAOFactory . SearchDAO . FindServiceRecordsInSpan ( i . CostBearerRelOids [ 0 ] , newSpan ) ) ) ;
var cb = DAOFactory . GenericDAO . LoadByID < CostBearer > ( costBearerOid ) ;
String tenant = PluginLoader . Tenant ;
var factory = PluginLoader . FindClass < InvoiceFactory > ( cb . ID ) ;
if ( factory = = null )
{
factory = InvoiceFactory . GetInstance ( cb . ID , tenant ) ;
}
var creator = factory . CreateInvoiceCreator ( cb . ID , tenant , supportConcepts2ServiceRecords ) ;
var newInvoices = creator . GenerateServiceInvoices ( costBearerOid , invoicePeriod , supportConcepts2ServiceRecords ) ;
//Prüfe ob Rechnungen neu sind oder Diff vorhanden
var differenzRechnungChecks = GetNewInvoices ( newInvoices , invoicePeriod ? . StartDate , invoicePeriod ? . EndDate ) ;
var resultList = ErstelleNeueRechnungen ( differenzRechnungChecks ) ;
return resultList ;
}
protected virtual List < ServiceInvoiceDC > ErstelleNeueRechnungen ( List < DifferenzRechnungCheck > differenzRechnungChecks )
2024-12-09 11:16:17 +01:00
{
2026-04-27 15:55:32 +02:00
var rechnungen = new List < ServiceInvoiceDC > ( ) ;
foreach ( var item in differenzRechnungChecks )
{
if ( item . VorhandeneRechungen . Count = = 0 | | ! item . VorhandeneRechungen . Any ( r = > item . NeueRechnung . InvoiceBase . CustomerOid = = r . InvoiceBase . CustomerOid ) )
{
item . NeueRechnung . InvoiceBase . NeuErstellen = true ;
rechnungen . Add ( item . NeueRechnung ) ;
}
else
{
var diffRechnung = ErstelleDifferenzRechnung ( item ) ;
if ( diffRechnung ! = null )
{
diffRechnung . InvoiceBase . NeuErstellen = false ;
rechnungen . Add ( diffRechnung ) ;
}
}
}
return rechnungen ;
}
protected virtual ServiceInvoiceDC ErstelleDifferenzRechnung ( DifferenzRechnungCheck item )
{
ServiceInvoiceDC diffRechnung = null ;
//var alterBetrag = item.VorhandeneRechungen.Sum(i => i.ClaimSum ?? 0);
var letzteRg = item . VorhandeneRechungen . OrderByDescending ( r = > r . ServiceInvoiceOid ) . FirstOrDefault ( ) ;
letzteRg = item . VorhandeneRechungen . FirstOrDefault ( r = > item . NeueRechnung . InvoiceBase . CustomerOid = = r . InvoiceBase . CustomerOid ) ;
if ( letzteRg ! = null )
{
if ( item . NeueRechnung . ClaimSum = = letzteRg . ClaimSum )
{
diffRechnung = item . NeueRechnung ;
diffRechnung . InvoiceBase . NeuErstellen = false ;
diffRechnung . InvoiceBase . Hinweise = String . Format ( "Rechnung wurde bereits erstellt" ) ;
}
else
{
diffRechnung = new ServiceInvoiceDC ( ) ;
diffRechnung . OriginalZurDifferenz = item . NeueRechnung ;
diffRechnung . InvoiceBase = new InvoiceBaseDC ( ) ;
CopyInvoiceBaseDC ( item . NeueRechnung . InvoiceBase , diffRechnung ) ;
ServiceInvoice counterInvoice = new ServiceInvoice ( ) ;
var serviceInvoice = DAOFactory . SearchDAO . GetServiceInvoiceByInvoiceBaseOid ( letzteRg . InvoiceBase . InvoiceBaseOid . Value ) ;
CopyServiceInvoice ( serviceInvoice , counterInvoice ) ;
SetzeStornoInfos ( counterInvoice ) ;
SetzeRechnungspositionenServiceInvoice ( diffRechnung , counterInvoice , item ) ;
2025-07-22 16:33:57 +02:00
2025-10-21 16:25:51 +02:00
diffRechnung . InvoiceBase . NeuErstellen = true ;
2026-04-27 15:55:32 +02:00
diffRechnung . InvoiceBase . Hinweise = String . Format ( "Rechnungsdifferenz zu Rechnung {0} in Höhe von {1:c}" , letzteRg . InvoiceBase . InvoiceNumber , letzteRg . InvoiceBase . TotalAmount . Value ) ;
}
}
2025-07-22 16:33:57 +02:00
2026-04-27 15:55:32 +02:00
return diffRechnung ;
2024-12-09 11:16:17 +01:00
}
protected virtual List < DifferenzRechnungCheck > GetNewInvoices ( List < ServiceInvoiceDC > invoices , DateTime ? start , DateTime ? end )
{
List < DifferenzRechnungCheck > result = new List < DifferenzRechnungCheck > ( ) ;
var existingInvoices = DAOFactory . SearchDAO . GetInvoiceBases ( start , end , false ) ;
foreach ( var si in invoices )
{
2026-04-27 15:55:32 +02:00
var checkResult = new DifferenzRechnungCheck ( ) ;
result . Add ( checkResult ) ;
checkResult . NeueRechnung = si ;
checkResult . VorhandeneRechungen = new List < ServiceInvoiceDC > ( ) ;
2024-12-09 11:16:17 +01:00
foreach ( var i2 in existingInvoices . Where ( i = > i . Type = = InvoiceType . Service ) )
{
2026-04-27 15:55:32 +02:00
if ( si . InvoiceBase . SupportConceptCostBearerRelDc ! = null & & si . InvoiceBase . SupportConceptCostBearerRelDc . CostBearer2SupportConceptOid = = i2 . CostBearer2SupportConceptOid )
2025-05-23 12:23:49 +02:00
{
2026-04-27 15:55:32 +02:00
var siAlt = DAOFactory . SearchDAO . GetServiceInvoiceByInvoiceBaseOid ( i2 . Oid . Value ) ;
var siDCAlt = MapperFactory . ServiceInvoiceDC_ServiceInvoice . MapToNewDC ( siAlt ) ;
checkResult . VorhandeneRechungen . Add ( siDCAlt ) ;
}
else // Sammelrechnung
{
if ( i2 . SupportConceptOid = = invoices [ 0 ] . InvoiceBase . SupportConceptOid )
{
var siAlt = DAOFactory . SearchDAO . GetServiceInvoiceByInvoiceBaseOid ( i2 . Oid . Value ) ;
var siDCAlt = MapperFactory . ServiceInvoiceDC_ServiceInvoice . MapToNewDC ( siAlt ) ;
if ( siAlt . ServiceInvoicePeriodList ! = null & & siAlt . ServiceInvoicePeriodList . Count > 0 )
{
foreach ( var i in invoices )
{
if ( i . ServiceInvoicePeriods ! = null & & i . ServiceInvoicePeriods . Count > 0 )
{
foreach ( var sip in siDCAlt . ServiceInvoicePeriods )
{
if ( sip . Customer ! = null & & i . ServiceInvoicePeriods . Any ( s = > s . Customer . CustomerOid = = sip . Customer . CustomerOid ) )
{
checkResult . VorhandeneRechungen . Add ( siDCAlt ) ;
break ;
}
}
}
}
}
}
}
}
2024-12-09 11:16:17 +01:00
}
return result ;
}
public virtual List < long > UpdateServiceInvoices ( List < ServiceInvoiceDC > invoices )
2026-04-27 15:55:32 +02:00
{
//if (!Data.Security.UserRightHelper.LoggedInUserHasRight(UserRightType.AccountingTransactionView_Create))
//{
// throw new FaultException<BeWoFault>(new BeWoFault("Du kommst hier nicht rein!", BeWoFaultType.CustomWithoutDetails));
//}
var originals = DAOFactory . GenericDAO . LoadByIDs < ServiceInvoice > ( invoices . Select ( i = > i . ServiceInvoiceOid . Value ) ) ;
MapperFactory . ServiceInvoiceDC_ServiceInvoice . MergeWithEntitys ( invoices , originals ) ;
DAOFactory . GenericDAO . Update ( originals ) ;
return originals . Select ( e = > e . Version . Value ) . ToList ( ) ;
}
public virtual List < InvoiceBaseDC > GetInvoiceBases ( DateTime ? startDate , DateTime ? endDate )
2024-12-09 11:16:17 +01:00
{
DateTime ? end = endDate ;
if ( end . HasValue )
{
end = end . Value . Date . AddDays ( 1 ) . AddTicks ( - 1 ) ;
}
var list = DAOFactory . SearchDAO . GetInvoiceBases ( startDate , end ) ;
return MapperFactory . InvoiceBaseDC_InvoiceBase . MapToNewDCs ( list ) ;
}
2026-04-27 15:55:32 +02:00
public virtual List < InvoiceBaseDC > GetInvoiceBases ( DateTime ? startDate , DateTime ? endDate , bool filterByInvoiceDate )
{
DateTime ? end = endDate ;
if ( end . HasValue )
{
end = end . Value . Date . AddDays ( 1 ) . AddTicks ( - 1 ) ;
}
var list = DAOFactory . SearchDAO . GetInvoiceBases ( startDate , end , filterByInvoiceDate ) ;
return MapperFactory . InvoiceBaseDC_InvoiceBase . MapToNewDCs ( list ) ;
2024-12-09 11:16:17 +01:00
}
2026-04-27 15:55:32 +02:00
public virtual List < InvoiceBaseDC > GetInvoiceBases ( DateTime ? startDate , DateTime ? endDate , long costBearerOid , String invoiceId )
{
DateTime ? end = endDate ;
if ( end . HasValue )
{
end = end . Value . Date . AddDays ( 1 ) . AddTicks ( - 1 ) ;
}
var list = DAOFactory . SearchDAO . GetInvoiceBases ( startDate , end , costBearerOid , invoiceId ) ;
return MapperFactory . InvoiceBaseDC_InvoiceBase . MapToNewDCs ( list ) ;
}
public virtual void DeactivateInvoiceBases ( List < InvoiceBaseDC > invoices )
{
ServiceLogic . SetActivationType < InvoiceBase > ( invoices . ToDictionary ( i = > i . InvoiceBaseOid . Value , i = > i . InvoiceBaseVersion . Value ) , ActivationTypeId . Deleted ) ;
}
2024-12-09 11:16:17 +01:00
public virtual void DeactivateServiceInvoices ( List < ServiceInvoiceDC > invoices )
2026-04-27 15:55:32 +02:00
{
ServiceLogic . SetActivationType < ServiceInvoice > ( invoices . ToDictionary ( i = > i . ServiceInvoiceOid . Value , i = > i . ServiceInvoiceVersion . Value ) , ActivationTypeId . Deleted ) ;
ServiceLogic . SetActivationType < InvoiceBase > ( invoices . ToDictionary ( i = > i . InvoiceBase . InvoiceBaseOid . Value , i = > i . InvoiceBase . InvoiceBaseVersion . Value ) , ActivationTypeId . Deleted ) ;
}
2024-12-09 11:16:17 +01:00
2026-04-27 15:55:32 +02:00
public virtual void StorniereInvoiceBases ( List < InvoiceBaseDC > invoices )
{
2024-12-09 11:16:17 +01:00
foreach ( var item in invoices )
{
2026-04-27 15:55:32 +02:00
if ( item . Type = = InvoiceType . Service )
{
ErstelleStornoRechnung ( item ) ;
}
2024-12-09 11:16:17 +01:00
else if ( item . Type = = InvoiceType . Settlement )
{
2026-04-27 15:55:32 +02:00
ErstelleStornoSpitzabrechnung ( item ) ;
}
else
{
ErstelleStornoAllgemeineRechnung ( item ) ;
2024-12-09 11:16:17 +01:00
}
2026-04-27 15:55:32 +02:00
}
}
public virtual InvoiceBase ErstelleStornoAllgemeineRechnung ( InvoiceBaseDC ibdc )
{
InvoiceBase newInvoice = new InvoiceBase ( ) ;
2024-12-09 11:16:17 +01:00
2026-04-27 15:55:32 +02:00
var oldInvoice = DAOFactory . GenericDAO . LoadByID < InvoiceBase > ( ibdc . InvoiceBaseOid . Value ) ;
2024-12-09 11:16:17 +01:00
2026-04-27 15:55:32 +02:00
CopyInvoiceBase ( oldInvoice , newInvoice ) ;
SetzeStornoInfos ( newInvoice ) ;
2024-12-09 11:16:17 +01:00
2026-04-27 15:55:32 +02:00
return newInvoice ;
}
2024-12-09 11:16:17 +01:00
2026-04-27 15:55:32 +02:00
public virtual ServiceInvoice ErstelleStornoRechnung ( InvoiceBaseDC ibdc )
{
ServiceInvoice newInvoice = new ServiceInvoice ( ) ;
var serviceInvoice = DAOFactory . SearchDAO . GetServiceInvoiceByInvoiceBaseOid ( ibdc . InvoiceBaseOid . Value ) ;
2024-12-09 11:16:17 +01:00
2026-04-27 15:55:32 +02:00
CopyServiceInvoice ( serviceInvoice , newInvoice ) ;
SetzeStornoInfos ( newInvoice ) ;
2024-12-09 11:16:17 +01:00
return newInvoice ;
2026-04-27 15:55:32 +02:00
}
2024-12-09 11:16:17 +01:00
2026-04-27 15:55:32 +02:00
public virtual SettlementInvoice ErstelleStornoSpitzabrechnung ( InvoiceBaseDC ibdc )
{
SettlementInvoice newInvoice = new SettlementInvoice ( ) ;
newInvoice . InvoiceBase = new InvoiceBase ( ) ;
2024-12-09 11:16:17 +01:00
2026-04-27 15:55:32 +02:00
var settlementInvoice = DAOFactory . SearchDAO . GetSettlementInvoiceByInvoiceBaseOid ( ibdc . InvoiceBaseOid . Value ) ;
2024-12-09 11:16:17 +01:00
2026-04-27 15:55:32 +02:00
CopySettlementInvoice ( settlementInvoice , newInvoice ) ;
SetzeStornoInfos ( newInvoice ) ;
2024-12-09 11:16:17 +01:00
2026-04-27 15:55:32 +02:00
if ( newInvoice . InvoiceBase . InvoiceItems . Count = = 0 & & newInvoice . Claim . HasValue )
{
newInvoice . InvoiceBase . InvoiceItems . Add ( new InvoiceItem
{
AmountTotal = newInvoice . Claim ,
ItemPeriodStart = newInvoice . InvoiceBase . AccountingPeriodStart ,
ItemPeriodEnd = newInvoice . InvoiceBase . AccountingPeriodEnd ,
ItemDescription = "Spitzabrechnung"
2024-12-09 11:16:17 +01:00
2026-04-27 15:55:32 +02:00
} ) ;
}
2024-12-09 11:16:17 +01:00
2026-04-27 15:55:32 +02:00
return newInvoice ;
}
public virtual ServiceInvoice ErstelleStornoRechnung ( ServiceInvoiceDC sidc )
{
ServiceInvoice newInvoice = new ServiceInvoice ( ) ;
2024-12-09 11:16:17 +01:00
2026-04-27 15:55:32 +02:00
var serviceInvoice = DAOFactory . GenericDAO . LoadByID < ServiceInvoice > ( sidc . ServiceInvoiceOid . Value ) ;
2024-12-09 11:16:17 +01:00
2026-04-27 15:55:32 +02:00
CopyServiceInvoice ( serviceInvoice , newInvoice ) ;
SetzeStornoInfos ( newInvoice ) ;
return newInvoice ;
2024-12-09 11:16:17 +01:00
}
2026-04-27 15:55:32 +02:00
public virtual void SaveStornoRechnung ( InvoiceBase originalInvoice , ServiceInvoice stornoInvoice )
{
DAOFactory . GenericDAO . Insert ( stornoInvoice ) ;
originalInvoice . StornoInvoiceBaseOid = stornoInvoice . Oid ;
DAOFactory . GenericDAO . Update ( originalInvoice ) ;
}
public virtual void SetzeStornoInfos ( InvoiceBase newInvoice )
{
foreach ( var ii in newInvoice . InvoiceItems )
{
if ( ii . AmountTotal . HasValue )
{
ii . AmountTotal * = - 1 ;
}
if ( ii . GrossAmountTotal . HasValue )
{
ii . GrossAmountTotal * = - 1 ;
}
}
}
public virtual void SetzeStornoInfos ( SettlementInvoice newInvoice )
{
if ( newInvoice . Claim . HasValue )
newInvoice . Claim * = - 1 ;
if ( newInvoice . AmountBillableTotal . HasValue )
newInvoice . AmountBillableTotal * = - 1 ;
if ( newInvoice . AmountTotalAdvancedPaidWithNewHourlyRate . HasValue )
newInvoice . AmountTotalAdvancedPaidWithNewHourlyRate * = - 1 ;
if ( newInvoice . AmountTotalAdvancedPaidWithOldHourlyRate . HasValue )
newInvoice . AmountTotalAdvancedPaidWithOldHourlyRate * = - 1 ;
if ( newInvoice . AmountWithRateFactor . HasValue )
newInvoice . AmountWithRateFactor * = - 1 ;
if ( newInvoice . AmountRateFactor . HasValue )
newInvoice . AmountRateFactor * = - 1 ;
// FLS-Felder negieren, damit isDefaultSpitzabrechnung-Pfad negative Positionen berechnet
if ( newInvoice . ApprovedFLSWithActualHourlyRate . HasValue )
newInvoice . ApprovedFLSWithActualHourlyRate * = - 1 ;
if ( newInvoice . ApprovedFLSWithOldHourlyRate . HasValue )
newInvoice . ApprovedFLSWithOldHourlyRate * = - 1 ;
// XMLData aktualisieren: Claim (wird vom Mapper als TotalAmount verwendet) und
// ApprovedFLSWithHourlyRate3 (nur bei DifferentHourlyRateCount == 3 vorhanden) negieren
if ( newInvoice . InvoiceBase ! = null & & ! string . IsNullOrEmpty ( newInvoice . InvoiceBase . XMLData ) )
{
var xmlDC = BS . Shared . Core . Utils . XMLDeserializeFromString < SettlementDC > ( newInvoice . InvoiceBase . XMLData ) ;
if ( xmlDC ! = null )
{
bool xmlChanged = false ;
if ( xmlDC . Claim ! = 0 )
{
xmlDC . Claim * = - 1 ;
xmlChanged = true ;
}
if ( xmlDC . ApprovedFLSWithHourlyRate3 ! = 0 )
{
xmlDC . ApprovedFLSWithHourlyRate3 * = - 1 ;
xmlChanged = true ;
2024-12-09 11:16:17 +01:00
}
2026-04-27 15:55:32 +02:00
if ( xmlChanged )
newInvoice . InvoiceBase . XMLData = BS . Shared . Core . Utils . XMLSerializeToString ( xmlDC ) ;
}
}
2024-12-09 11:16:17 +01:00
2026-04-27 15:55:32 +02:00
SetzeStornoInfos ( newInvoice . InvoiceBase ) ;
}
2024-12-09 11:16:17 +01:00
2026-04-27 15:55:32 +02:00
public virtual void SetzeStornoInfos ( ServiceInvoice newInvoice )
{
foreach ( var sip in newInvoice . ServiceInvoicePeriodList )
{
sip . HoursNotBillableAbsence = 0 ;
sip . HoursNotBillableNotApproved = 0 ;
if ( sip . Claim . HasValue )
{
sip . Claim * = - 1 ;
}
2024-12-09 11:16:17 +01:00
2026-04-27 15:55:32 +02:00
foreach ( var ii in sip . InvoiceItemList )
{
if ( ii . AmountTotal . HasValue )
{
ii . AmountTotal * = - 1 ;
}
if ( ii . GrossAmountTotal . HasValue )
{
ii . GrossAmountTotal * = - 1 ;
}
}
}
}
public void CopyServiceInvoice ( ServiceInvoice existingInvoice , ServiceInvoice copyInvoice )
{
copyInvoice . AmountAdvancePayments = existingInvoice . AmountAdvancePayments ;
copyInvoice . AmountEquityContribution = existingInvoice . AmountEquityContribution ;
copyInvoice . ServiceUnitOid = existingInvoice . ServiceUnitOid ;
CopyInvoiceBase ( existingInvoice . InvoiceBase , copyInvoice . InvoiceBase ) ;
foreach ( var sip in existingInvoice . ServiceInvoicePeriodList )
{
var copySip = new ServiceInvoicePeriod ( ) ;
copyInvoice . ServiceInvoicePeriodList . Add ( copySip ) ;
CopyServiceInvoicePeriod ( sip , copySip ) ;
}
}
2024-12-09 11:16:17 +01:00
2026-04-27 15:55:32 +02:00
public void CopySettlementInvoice ( SettlementInvoice existing , SettlementInvoice copy )
{
copy . AmountAdvancedPayments = existing . AmountAdvancedPayments ;
copy . AmountBillableTotal = existing . AmountBillableTotal ;
copy . AmountRateFactor = existing . AmountRateFactor ;
copy . AmountTotalAdvancedPaidWithNewHourlyRate = existing . AmountTotalAdvancedPaidWithNewHourlyRate ;
copy . AmountTotalAdvancedPaidWithOldHourlyRate = existing . AmountTotalAdvancedPaidWithOldHourlyRate ;
copy . AmountWithRateFactor = existing . AmountWithRateFactor ;
copy . ApprovalNoticeDate = existing . ApprovalNoticeDate ;
copy . ApprovedFLS = existing . ApprovedFLS ;
copy . ApprovedFLSWithActualHourlyRate = existing . ApprovedFLSWithActualHourlyRate ;
copy . ApprovedFLSWithOldHourlyRate = existing . ApprovedFLSWithOldHourlyRate ;
copy . Claim = existing . Claim ;
copy . ErrorNotice = existing . ErrorNotice ;
copy . HourlyRateNew = existing . HourlyRateNew ;
copy . HourlyRateNewStartDate = existing . HourlyRateNewStartDate ;
copy . HourlyRateOld = existing . HourlyRateOld ;
copy . HourlyRateOldEndDate = existing . HourlyRateOldEndDate ;
copy . RecordedBillableFLSBrutto = existing . RecordedBillableFLSBrutto ;
copy . RecordedBillableFLSNetto = existing . RecordedBillableFLSNetto ;
copy . RecordedBillableFLSNotBillableCustomerAbsent = existing . RecordedBillableFLSNotBillableCustomerAbsent ;
copy . RecordedBillableFLSNotBillableOutOfApprovedSpan = existing . RecordedBillableFLSNotBillableOutOfApprovedSpan ;
CopyInvoiceBase ( existing . InvoiceBase , copy . InvoiceBase ) ;
2024-12-09 11:16:17 +01:00
}
2026-04-27 15:55:32 +02:00
public void CopyInvoiceBase ( InvoiceBase existing , InvoiceBase copy )
{
copy . AccountingPeriodEnd = existing . AccountingPeriodEnd ;
copy . AccountingPeriodStart = existing . AccountingPeriodStart ;
copy . CostBearer2SupportConcept = existing . CostBearer2SupportConcept ;
copy . CreatorFirstName = existing . CreatorFirstName ;
copy . CreatorLastName = existing . CreatorLastName ;
copy . CustomerReferenceNumber = existing . CustomerReferenceNumber ;
copy . DueDate = existing . DueDate ;
copy . DunningLetterCount = existing . DunningLetterCount ;
copy . InvoiceDate = existing . InvoiceDate ;
copy . InvoiceId = existing . InvoiceId ;
copy . InvoiceNumber = existing . InvoiceNumber ;
copy . InvoiceTitle = existing . InvoiceTitle ;
copy . InvoiceTypeText = existing . InvoiceTypeText ;
copy . IsPaid = existing . IsPaid ;
copy . IsPrinted = existing . IsPrinted ;
copy . RecipientCostBearerOid = existing . RecipientCostBearerOid ;
copy . RecipientCustomerOid = existing . RecipientCustomerOid ;
copy . RecipientDivision = existing . RecipientDivision ;
copy . RecipientOrganisation = existing . RecipientOrganisation ;
copy . RecipientOrganisationOid = existing . RecipientOrganisationOid ;
copy . RecipientPersonFirstName = existing . RecipientPersonFirstName ;
copy . RecipientPersonLastName = existing . RecipientPersonLastName ;
copy . RecipientPersonOid = existing . RecipientPersonOid ;
copy . SenderDivision = existing . SenderDivision ;
copy . SenderFirstName = existing . SenderFirstName ;
copy . SenderLastName = existing . SenderLastName ;
copy . SenderOrganisation = existing . SenderOrganisation ;
copy . SupportConceptOid = existing . SupportConceptOid ;
copy . Type = existing . Type ;
copy . XMLData = existing . XMLData ;
foreach ( var ii in existing . InvoiceItems )
{
var copyItem = new InvoiceItem ( ) ;
copy . InvoiceItems . Add ( copyItem ) ;
CopyInvoiceItem ( ii , copyItem ) ;
}
if ( existing . RecipientAddress ! = null )
{
copy . RecipientAddress = CreateCopyAddress ( existing . RecipientAddress ) ;
}
if ( existing . RecipientContacts ! = null )
{
2024-12-09 11:16:17 +01:00
copy . RecipientContacts = new List < Contact > ( ) ;
2026-04-27 15:55:32 +02:00
foreach ( var existingContact in existing . RecipientContacts )
{
copy . RecipientContacts . Add ( CreateCopyContact ( existingContact ) ) ;
}
}
if ( existing . SenderAddress ! = null )
{
copy . SenderAddress = existing . SenderAddress ;
}
if ( existing . SenderContacts ! = null )
{
copy . SenderContacts = new List < Contact > ( ) ;
foreach ( var existingContact in existing . SenderContacts )
{
copy . SenderContacts . Add ( CreateCopyContact ( existingContact ) ) ;
}
}
}
public void CopyInvoiceBaseDC ( InvoiceBaseDC orgRechnung , ServiceInvoiceDC diffRechnung )
{
diffRechnung . InvoiceBase . DiffErstellen = true ;
diffRechnung . InvoiceBase . AccountingPeriodStart = orgRechnung . AccountingPeriodStart ;
diffRechnung . InvoiceBase . AccountingPeriodEnd = orgRechnung . AccountingPeriodEnd ;
diffRechnung . InvoiceBase . CustomerLastName = orgRechnung . CustomerLastName ;
diffRechnung . InvoiceBase . CustomerFirstName = orgRechnung . CustomerFirstName ;
diffRechnung . InvoiceBase . CustomerReferenceNumber = orgRechnung . CustomerReferenceNumber ;
diffRechnung . InvoiceBase . InvoiceBaseOid = orgRechnung . InvoiceBaseOid ;
diffRechnung . InvoiceBase . InvoiceDate = orgRechnung . InvoiceDate ;
diffRechnung . InvoiceBase . InvoiceId = orgRechnung . InvoiceId ;
diffRechnung . InvoiceBase . InvoiceNumber = orgRechnung . InvoiceNumber ;
diffRechnung . InvoiceBase . InvoiceTitle = orgRechnung . InvoiceTitle ;
diffRechnung . InvoiceBase . InvoiceTypeText = orgRechnung . InvoiceTypeText ;
diffRechnung . InvoiceBase . RecipientAddressLine1 = orgRechnung . RecipientAddressLine1 ;
diffRechnung . InvoiceBase . RecipientAddressOid = orgRechnung . RecipientAddressOid ;
diffRechnung . InvoiceBase . RecipientAddressVersion = orgRechnung . RecipientAddressVersion ;
diffRechnung . InvoiceBase . RecipientContactInformations = orgRechnung . RecipientContactInformations ;
diffRechnung . InvoiceBase . RecipientCostBearerOid = orgRechnung . RecipientCostBearerOid ;
diffRechnung . InvoiceBase . RecipientCustomerOid = orgRechnung . RecipientCustomerOid ;
diffRechnung . InvoiceBase . RecipientDivision = orgRechnung . RecipientDivision ;
diffRechnung . InvoiceBase . RecipientOrganisation = orgRechnung . RecipientOrganisation ;
diffRechnung . InvoiceBase . RecipientOrganisationOid = orgRechnung . RecipientOrganisationOid ;
diffRechnung . InvoiceBase . RecipientPersonFirstName = orgRechnung . RecipientPersonFirstName ;
diffRechnung . InvoiceBase . RecipientPersonLastName = orgRechnung . RecipientPersonLastName ;
diffRechnung . InvoiceBase . RecipientPersonOid = orgRechnung . RecipientPersonOid ;
diffRechnung . InvoiceBase . RecipientPostCode = orgRechnung . RecipientPostCode ;
diffRechnung . InvoiceBase . RecipientSalutationAddressField = orgRechnung . RecipientSalutationAddressField ;
diffRechnung . InvoiceBase . RecipientStreet = orgRechnung . RecipientStreet ;
diffRechnung . InvoiceBase . RecipientTown = orgRechnung . RecipientTown ;
diffRechnung . InvoiceBase . SenderAddressOid = orgRechnung . SenderAddressOid ;
diffRechnung . InvoiceBase . SenderAddressVersion = orgRechnung . SenderAddressVersion ;
diffRechnung . InvoiceBase . SenderContactInformations = orgRechnung . SenderContactInformations ;
diffRechnung . InvoiceBase . SenderDivision = orgRechnung . SenderDivision ;
diffRechnung . InvoiceBase . SenderFirstName = orgRechnung . SenderFirstName ;
diffRechnung . InvoiceBase . SenderLastName = orgRechnung . SenderLastName ;
diffRechnung . InvoiceBase . SenderOrganisation = orgRechnung . SenderOrganisation ;
diffRechnung . InvoiceBase . SenderPostCode = orgRechnung . SenderPostCode ;
diffRechnung . InvoiceBase . SenderStreet = orgRechnung . SenderStreet ;
diffRechnung . InvoiceBase . SenderTown = orgRechnung . SenderTown ;
diffRechnung . InvoiceBase . SupportConceptCostBearerRelDc = orgRechnung . SupportConceptCostBearerRelDc ;
diffRechnung . InvoiceBase . SupportConceptOid = orgRechnung . SupportConceptOid ;
diffRechnung . InvoiceBase . TotalAmount = orgRechnung . TotalAmount ;
diffRechnung . InvoiceBase . Type = orgRechnung . Type ;
}
public Contact CreateCopyContact ( Contact existingContact )
{
Contact newContact = new Contact ( ) ;
newContact . Value = existingContact . Value ;
newContact . Type = existingContact . Type ;
return newContact ;
}
public Address CreateCopyAddress ( Address address )
{
Address newAddress = new Address ( ) ;
newAddress . AddressLine1 = address . AddressLine1 ;
newAddress . AddressLine2 = address . AddressLine2 ;
newAddress . Country = address . Country ;
newAddress . PostalCode = address . PostalCode ;
newAddress . State = address . State ;
newAddress . Street = address . Street ;
newAddress . Town = address . Town ;
return newAddress ;
2024-12-09 11:16:17 +01:00
}
2026-04-27 15:55:32 +02:00
public void CopyServiceInvoicePeriod ( ServiceInvoicePeriod existingSip , ServiceInvoicePeriod copySip )
{
copySip . AccountingInterval = existingSip . AccountingInterval ;
copySip . ApprovedAmountDefaultHourlyRate = existingSip . ApprovedAmountDefaultHourlyRate ;
copySip . ApprovedBE = existingSip . ApprovedBE ;
copySip . ApprovedFixedAmount = existingSip . ApprovedFixedAmount ;
copySip . ApprovedHours = existingSip . ApprovedHours ;
copySip . Claim = existingSip . Claim ;
copySip . End = existingSip . End ;
copySip . HoursNotBillableAbsence = existingSip . HoursNotBillableAbsence ;
copySip . HoursNotBillableNotApproved = existingSip . HoursNotBillableNotApproved ;
copySip . ServiceUnitName = existingSip . ServiceUnitName ;
copySip . Start = existingSip . Start ;
copySip . Notice = existingSip . Notice ;
2024-12-09 11:16:17 +01:00
copySip . Customer = existingSip . Customer ;
copySip . SupportConceptApprovalPeriod = existingSip . SupportConceptApprovalPeriod ;
2026-04-27 15:55:32 +02:00
foreach ( var ii in existingSip . InvoiceItemList )
{
var copyItem = new InvoiceItem ( ) ;
copySip . InvoiceItemList . Add ( copyItem ) ;
CopyInvoiceItem ( ii , copyItem ) ;
}
2024-12-09 11:16:17 +01:00
}
2026-04-27 15:55:32 +02:00
public void CopyInvoiceItem ( InvoiceItem existingItem , InvoiceItem copyItem )
{
copyItem . AccountingInterval = existingItem . AccountingInterval ;
copyItem . AmountPerUnit = existingItem . AmountPerUnit ;
copyItem . AmountTotal = existingItem . AmountTotal ;
copyItem . ApprovalUnit = existingItem . AccountingInterval ;
copyItem . ApprovedPerUnit = existingItem . ApprovedPerUnit ;
copyItem . GrossAmountTotal = existingItem . GrossAmountTotal ;
copyItem . ItemDescription = existingItem . ItemDescription ;
copyItem . ItemPeriodEnd = existingItem . ItemPeriodEnd ;
copyItem . ItemPeriodStart = existingItem . ItemPeriodStart ;
copyItem . MaxApprovedAmount = existingItem . MaxApprovedAmount ;
copyItem . MaxApprovedUnitCount = existingItem . MaxApprovedUnitCount ;
copyItem . RateFactor = existingItem . RateFactor ;
copyItem . ReceivedAmount = existingItem . ReceivedAmount ;
copyItem . SupportConceptApprovalPeriodOid = existingItem . SupportConceptApprovalPeriodOid ;
copyItem . UnitCount = existingItem . UnitCount ;
copyItem . UnitDescription = existingItem . UnitDescription ;
copyItem . Notice = existingItem . Notice ;
2024-12-09 11:16:17 +01:00
copyItem . ServiceRecord = existingItem . ServiceRecord ;
}
2026-04-27 15:55:32 +02:00
public virtual void SetzeRechnungspositionenServiceInvoice ( ServiceInvoiceDC diffRechnung , ServiceInvoice counterInvoice , DifferenzRechnungCheck item )
{
var siDCAlt = MapperFactory . ServiceInvoiceDC_ServiceInvoice . MapToNewDC ( counterInvoice ) ;
if ( siDCAlt . ServiceInvoicePeriods ! = null & & siDCAlt . ServiceInvoicePeriods . Count > 0 )
{
diffRechnung . ServiceInvoicePeriods = siDCAlt . ServiceInvoicePeriods ;
}
if ( item . NeueRechnung . ServiceInvoicePeriods ! = null & & item . NeueRechnung . ServiceInvoicePeriods . Count > 0 )
{
if ( diffRechnung . ServiceInvoicePeriods = = null )
{
diffRechnung . ServiceInvoicePeriods = item . NeueRechnung . ServiceInvoicePeriods ;
}
else
{
foreach ( var NewSip in item . NeueRechnung . ServiceInvoicePeriods )
{
if ( NewSip . InvoiceItems ! = null & & NewSip . InvoiceItems . Count > 0 )
{
if ( NewSip . Customer ! = null & & diffRechnung . ServiceInvoicePeriods . Any ( s = > s . Customer . CustomerOid = = NewSip . Customer . CustomerOid ) & &
NewSip . SupportConceptApprovalPeriod ! = null & & NewSip . SupportConceptApprovalPeriod . SupportConceptApprovalPeriodOid . HasValue
& & diffRechnung . ServiceInvoicePeriods . Any ( s = > s . SupportConceptApprovalPeriod ! = null & & s . SupportConceptApprovalPeriod . SupportConceptApprovalPeriodOid . HasValue
& & s . SupportConceptApprovalPeriod . SupportConceptApprovalPeriodOid . Value = = NewSip . SupportConceptApprovalPeriod . SupportConceptApprovalPeriodOid . Value ) )
{
var ip = diffRechnung . ServiceInvoicePeriods . Where ( s = > s . SupportConceptApprovalPeriod ! = null & & s . SupportConceptApprovalPeriod . SupportConceptApprovalPeriodOid . Value = = NewSip . SupportConceptApprovalPeriod . SupportConceptApprovalPeriodOid . Value ) . First ( ) ;
2025-07-22 16:33:57 +02:00
if ( ip . InvoiceItems ! = null & & ip . InvoiceItems . Count > 0 )
{
ip . Claim + = NewSip . Claim ;
foreach ( var ii in NewSip . InvoiceItems )
{
ip . InvoiceItems . Add ( ii ) ;
}
// Bei Rechnungspositionen mit negativem Betrag auf alte Rechnung verweisen
foreach ( var iitem in ip . InvoiceItems )
{
if ( iitem . AmountTotal < 0 )
{
var vorhandeneRechnung = item . VorhandeneRechungen . FirstOrDefault ( r = > r . InvoiceBase ! = null & & r . InvoiceBase . CustomerOid = = ip . Customer . CustomerOid ) ;
if ( vorhandeneRechnung ! = null )
iitem . ItemDescription + = string . Format ( " (am {0:dd.MM.yyyy} in Rechnung {1} berechnet)" , vorhandeneRechnung . InvoiceBase . InvoiceDate , vorhandeneRechnung . InvoiceBase . InvoiceNumber ) ;
}
}
}
}
else
2026-04-27 15:55:32 +02:00
{
diffRechnung . ServiceInvoicePeriods . Add ( NewSip ) ;
}
}
}
}
}
}
public virtual Settlement2DC ErstelleDifferenzSpitzabrechnung ( Settlement2DC neueRechnung , Settlement2DC letzteRechnung )
{
neueRechnung . Claim = neueRechnung . Claim - letzteRechnung . Claim ;
var differenzItems = new List < InvoiceItemDC > ( ) ;
// Exaktieselbe Erkennung wie SettlementReport.cs für isDefaultSpitzabrechnung:
// genau 1 Item mit Bezeichnung "Spitzabrechnung"/"Spitzabrechung", GrossAmountTotal==null, RateFactor==null
bool letzteIstOldWay = letzteRechnung . InvoiceItems = = null
| | ( letzteRechnung . InvoiceItems . Count = = 1 & & ( letzteRechnung . InvoiceItems [ 0 ] . ItemDescription = = "Spitzabrechnung" | | letzteRechnung . InvoiceItems [ 0 ] . ItemDescription = = "Spitzabrechung" )
& & letzteRechnung . InvoiceItems [ 0 ] . GrossAmountTotal = = null & & letzteRechnung . InvoiceItems [ 0 ] . RateFactor = = null ) ;
if ( letzteIstOldWay )
{
// Storno der alten Gesamtsumme als einzelne explizite Position
differenzItems . Add ( new InvoiceItemDC
{
AmountTotal = - ( letzteRechnung . Claim ? ? 0 ) ,
GrossAmountTotal = - ( letzteRechnung . Claim ? ? 0 ) ,
ItemPeriodStart = letzteRechnung . AccountingPeriodStart ,
ItemPeriodEnd = letzteRechnung . AccountingPeriodEnd ,
ItemDescription = "Storno"
} ) ;
// Neue Rechnung als Old-Way mit expliziten Items (isDefaultSpitzabrechnung = false im Report)
bool neueHatExpliziteItems = neueRechnung . InvoiceItems ! = null & & neueRechnung . InvoiceItems . Any ( ii = > ii . GrossAmountTotal ! = null ) ;
if ( neueHatExpliziteItems )
differenzItems . AddRange ( neueRechnung . InvoiceItems ) ;
else
differenzItems . AddRange ( ErstelleExpliziteSpitzabrechnungsItems ( neueRechnung ) ) ;
// Claim aus den tatsächlichen Items berechnen (Storno + neue Items),
// da bei old-way Rechnungen neueRechnung.Claim null sein kann
neueRechnung . Claim = differenzItems . Sum ( i = > i . AmountTotal ? ? 0 m ) ;
}
else
{
// Normalfall: Items der alten Rechnung negieren (SettlementReport2 → SettlementReport2)
if ( letzteRechnung . InvoiceItems ! = null )
{
foreach ( var item in letzteRechnung . InvoiceItems )
{
differenzItems . Add ( new InvoiceItemDC
{
AmountTotal = - ( item . AmountTotal ? ? 0 ) ,
GrossAmountTotal = item . GrossAmountTotal . HasValue ? - item . GrossAmountTotal : null ,
AmountPerUnit = item . AmountPerUnit ,
ApprovedPerUnit = item . ApprovedPerUnit ,
ItemPeriodStart = item . ItemPeriodStart ,
ItemPeriodEnd = item . ItemPeriodEnd ,
UnitDescription = item . UnitDescription ,
UnitCount = item . UnitCount ,
RateFactor = item . RateFactor ,
ItemDescription = item . ItemDescription + " (Storno)"
} ) ;
}
}
if ( neueRechnung . InvoiceItems ! = null )
differenzItems . AddRange ( neueRechnung . InvoiceItems ) ;
}
neueRechnung . InvoiceItems = differenzItems ;
neueRechnung . Notice = string . Format ( "Differenzrechnung zu Rechnung {0} vom {1:dd.MM.yyyy}" , letzteRechnung . InvoiceNumber , letzteRechnung . InvoiceDate ) ;
return neueRechnung ;
}
private IList < InvoiceItemDC > ErstelleExpliziteSpitzabrechnungsItems ( Settlement2DC dc )
2024-12-09 11:16:17 +01:00
{
2026-04-27 15:55:32 +02:00
decimal fact = 1 ;
if ( dc . RateFactor ! = null & & dc . RateFactor . Value > 0 )
{
fact = ( 100 + dc . RateFactor . Value ) / 100 ;
}
decimal? rateFactor = fact ! = 1 ? fact : ( decimal? ) null ;
var items = new List < InvoiceItemDC > ( ) ;
2024-12-09 11:16:17 +01:00
2026-04-27 15:55:32 +02:00
// Periode mit drittem Stundensatz (nur bei DifferentHourlyRateCount >= 3)
if ( dc . DifferentHourlyRateCount > = 3 )
{
items . Add ( new InvoiceItemDC
{
ItemPeriodStart = dc . AccountingPeriodStart ,
ItemPeriodEnd = dc . HourlyRateEndDate3 ,
UnitCount = dc . ApprovedFLSWithHourlyRate3 ,
AmountPerUnit = dc . HourlyRate3 ,
RateFactor = rateFactor ,
GrossAmountTotal = dc . ApprovedFLSWithHourlyRate3 * fact * dc . HourlyRate3 ,
AmountTotal = dc . ApprovedFLSWithHourlyRate3 * fact * dc . HourlyRate3
} ) ;
}
// Periode mit altem Stundensatz (bei DifferentHourlyRateCount >= 2)
if ( dc . DifferentHourlyRateCount > = 2 )
{
items . Add ( new InvoiceItemDC
{
ItemPeriodStart = dc . DifferentHourlyRateCount > = 3 ? dc . HourlyRateOldStartDate : dc . AccountingPeriodStart ,
ItemPeriodEnd = dc . HourlyRateOldEndDate ,
UnitCount = dc . ApprovedFLSWithOldHourlyRate ,
AmountPerUnit = dc . HourlyRateOld ,
RateFactor = rateFactor ,
GrossAmountTotal = dc . ApprovedFLSWithOldHourlyRate * fact * ( dc . HourlyRateOld ? ? 0 ) ,
AmountTotal = dc . ApprovedFLSWithOldHourlyRate * fact * ( dc . HourlyRateOld ? ? 0 )
} ) ;
}
2024-12-09 11:16:17 +01:00
2026-04-27 15:55:32 +02:00
// Periode mit aktuellem Stundensatz (immer vorhanden)
items . Add ( new InvoiceItemDC
{
ItemPeriodStart = dc . DifferentHourlyRateCount > = 2 ? dc . HourlyRateNewStartDate : dc . AccountingPeriodStart ,
ItemPeriodEnd = dc . AccountingPeriodEnd ,
UnitCount = dc . ApprovedFLSWithActualHourlyRate ,
AmountPerUnit = dc . HourlyRateNew ,
RateFactor = rateFactor ,
GrossAmountTotal = dc . ApprovedFLSWithActualHourlyRate * fact * ( dc . HourlyRateNew ? ? 0 ) ,
AmountTotal = dc . ApprovedFLSWithActualHourlyRate * fact * ( dc . HourlyRateNew ? ? 0 )
} ) ;
return items ;
2024-12-09 11:16:17 +01:00
}
2026-04-27 15:55:32 +02:00
public virtual AddressInformation GetAddressInformation ( long? customer_oid = null )
{
var user = UserRightHelper . GetLoggedInUser ( ) . Employee ;
var mandator = AppSettings . GetMandatorEntity ( ) ;
return new AddressInformation ( )
{
IKLeistungserbringer = mandator . IKLeistungserbringer ,
Fax = user . Person . Contacts . FirstOrDefault ( x = > x . Type = = ContactType . business_Fax ) ? . Value . ToNullIfEmpty ( ) ,
Mail = user . Person . Contacts . FirstOrDefault ( x = > x . Type = = ContactType . business_Mail ) ? . Value . ToNullIfEmpty ( ) ,
Phone = user . Person . Contacts . FirstOrDefault ( x = > x . Type = = ContactType . business_Phone ) ? . Value . ToNullIfEmpty ( ) ,
OrganisationName = mandator . Name ,
PostCode = mandator . PostalCode ,
Street = mandator . Street ,
Town = mandator . Town ,
Website = mandator . Website
} ;
}
}
public class DifferenzRechnungCheck
2024-12-09 11:16:17 +01:00
{
public ServiceInvoiceDC NeueRechnung { get ; set ; }
public IList < ServiceInvoiceDC > VorhandeneRechungen { get ; set ; }
}
2019-02-12 19:32:04 +01:00
}