DiakonischesWerkMuelheimTwg/Export/DatevExporter.cs - neu + Umstellung Invoicing um Erlöskonten sicher zuordnen zu können

SupportOID=168755
This commit is contained in:
2026-07-22 14:43:29 +02:00
parent f8fd931476
commit 6abefef781
7 changed files with 217 additions and 6 deletions

View File

@@ -66,6 +66,8 @@
<DependentUpon>Belegungsquoten.cs</DependentUpon>
</Compile>
<Compile Include="Calculation\CustomCalculations.cs" />
<Compile Include="Export\CustomDataExporter.cs" />
<Compile Include="Export\DatevExporter.cs" />
<Compile Include="Finanzauswertung.cs">
<SubType>Component</SubType>
</Compile>

View File

@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using BeWo.Service.Core;
using BeWo.Service.Plugins;
using BS.Shared.Core;
using BS.Shared.DataContracts;
using Utils = BS.Shared.Core.Utils;
namespace DiakonischesWerkMuelheimTwg.Export
{
public class CustomDataExporter : DataExporter
{
public override QueryDC CreateQuery(QueryDC query)
{
return DatevExporter.CreateQuery(query);
}
}
}

View File

@@ -0,0 +1,176 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Text;
using BeWo.Data.Access;
using BeWo.Data.Entities;
using BeWo.Service.DCEntityMapper;
using BS.Shared;
using BS.Shared.DataContracts;
using BS.Shared.Extensions;
namespace DiakonischesWerkMuelheimTwg.Export
{
public class DatevExporter
{
public static QueryDC CreateQuery(QueryDC query)
{
DateTime dt = DateTime.Now;
DateTime.TryParse(query.Parameter[0].Value.ToString(), out dt);
query.FileName = String.Format("Datev Export {0:yyyyMM}.csv", dt);
query.QueryResult = GetAbrechnungenString(dt);
return query;
}
public static String GetAbrechnungenString(DateTime date)
{
StringBuilder sb = new StringBuilder();
sb.Append("Betrag;S/H;BU;Gegenkonto;Blg 1;Dat;Konto;Kst;Text");
var s = GetMonatlicheRechnungenString(date);
if (!String.IsNullOrWhiteSpace(s))
{
sb.AppendLine();
sb.Append(s);
}
return sb.ToString();
}
public static String GetMonatlicheRechnungenString(DateTime date)
{
var sql = GetMonatlicheRechnungenSql(date);
var dt = ExecuteQuery(sql, date);
StringBuilder sb = new StringBuilder();
foreach (DataRow row in dt.Rows)
{
if (sb.Length > 0)
{
sb.AppendLine();
}
String buchungstext = "";
long? c2sOid = (long?)row[5];
if (c2sOid.HasValue)
{
var c2s = DAOFactory.GenericDAO.LoadByID<CostBearer2SupportConcept>(c2sOid.Value);
var c = c2s.SupportConcept.Customer;
buchungstext = String.Format("{0}, {1} {2:MM}/{2:yy}", c.Person.LastName, c.Person.FirstName, row[8]);
}
string konto = String.Format("{0}", row[1]).Trim(); // customer.DebitorNumber
string kostenstelle = String.Format("{0}", row[4]).Trim(); // customer.CostCenter
string belegfeld1 = String.Format("{0}", row[3]).Trim(); // ib.invoicenumber
string gegenkonto = ErmittleErloeskonto((long)row[10]); // ib.Oid -> 40920 Pflege/Barbetrag, sonst 40910 ABW
sb.Append(BuildBuchungszeile(row[0], konto, gegenkonto, belegfeld1, row[2], kostenstelle, buchungstext));
}
return sb.ToString();
}
// Spalten: Betrag;S/H;BU;Gegenkonto;Blg 1;Dat;Konto;Kst;Text
private static String BuildBuchungszeile(object betrag, string konto, string gegenkonto, string belegfeld1, object belegdatum, string kostenstelle, string buchungstext)
{
StringBuilder sb = new StringBuilder();
sb.Append(String.Format("{0:0.00}", betrag)); // Betrag
sb.Append(";S"); // S/H
sb.Append(";"); // BU (leer)
sb.Append(";");
sb.Append(gegenkonto); // Gegenkonto
sb.Append(";");
sb.Append(belegfeld1); // Blg 1
sb.Append(";");
sb.Append(String.Format("{0:ddMM}", belegdatum)); // Dat
sb.Append(";");
sb.Append(konto); // Konto
sb.Append(";");
//sb.Append(kostenstelle); // Kst (leer)
sb.Append(";");
sb.Append(buchungstext); // Text
return sb.ToString();
}
// Kunde hat kein festes Erloeskonto: 40920 fuer Pflege/Barbetrag, 40910 fuer ABW.
// Massgeblich ist die UnitDescription der InvoiceItems; ist diese leer (Rechnung vor Juli 2026), gilt die ItemDescription.
private static String ErmittleErloeskonto(long invoiceBaseOid)
{
var invoice = DAOFactory.SearchDAO.GetServiceInvoiceByInvoiceBaseOid(invoiceBaseOid);
if (invoice != null && invoice.ServiceInvoicePeriodList != null)
{
foreach (var period in invoice.ServiceInvoicePeriodList)
{
if (period.InvoiceItemList == null)
{
continue;
}
foreach (var item in period.InvoiceItemList)
{
string text = !String.IsNullOrWhiteSpace(item.UnitDescription) ? item.UnitDescription : item.ItemDescription;
if (EnthaeltPflegeOderBarbetrag(text))
{
return "40920"; // Pflege / Barbetrag
}
}
}
}
return "40910"; // ABW (Umkehrschluss: kein Pflege/Barbetrag)
}
private static bool EnthaeltPflegeOderBarbetrag(string text)
{
if (String.IsNullOrEmpty(text))
{
return false;
}
return text.IndexOf("Pflege", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("Barbetrag", StringComparison.OrdinalIgnoreCase) >= 0;
}
private static String GetMonatlicheRechnungenSql(DateTime date)
{
String sql = @"
select
sip.Claim,
c.DebitorNumber,
ib.InvoiceDate,
ib.invoicenumber,
c.CostCenter,
c2s.Oid,
ib.InvoiceId,
c2s.Notice AS 'Kostenstelle',
ib.`AccountingPeriodEnd`,
ib.`AccountingPeriodStart`,
ib.Oid
from
person p
inner join customer c on c.personoid = p.oid
inner join supportconcept sc on sc.customeroid = c.oid
inner join costbearer2supportconcept c2s on c2s.supportconceptoid = sc.oid
inner join invoicebase ib on ib.costbearer2supportconceptoid = c2s.oid
inner join serviceinvoice si on si.invoicebaseoid = ib.oid
inner join serviceinvoiceperiod sip on sip.serviceinvoiceoid = si.oid
WHERE ib.`AccountingPeriodEnd` >= ':Monat_Start' AND ib.`AccountingPeriodEnd` < ':Monat_End' and ib.IsActive = 1
order by ib.invoicenumber
";
return sql;
}
public static DataTable ExecuteQuery(String sql, DateTime dt)
{
var newsql = sql;
newsql = newsql.Replace(":Abrechnungsmonat", String.Format("{0:dd.MM.yyyy}", dt));
newsql = newsql.Replace(":Belegnr", String.Format("{0:yyMM}", dt));
newsql = newsql.Replace(":Monat_MM", String.Format("{0:MM}", dt));
newsql = newsql.Replace(":Monat_Start", String.Format("{0:yyyy-MM}-01", dt));
dt = dt.AddMonths(1);
newsql = newsql.Replace(":Monat_End", String.Format("{0:yyyy-MM}-01", dt));
return DAOFactory.AdoDAO.ExecuteQuery(newsql).Tables[0];
}
}
}

View File

@@ -64,7 +64,8 @@ namespace DiakonischesWerkMuelheimTwg.Invoicing
AccountingInterval = billingData.AccountingInterval,
AmountPerUnit = billingData.AmountPerUnit,
UnitCount = billingData.UnitCount,
ItemDescription = description
ItemDescription = description,
UnitDescription = "Pflege"
});
}
}

View File

@@ -52,6 +52,13 @@ namespace DiakonischesWerkMuelheimTwg.Invoicing
}
}
public override InvoiceItem CreateInvoiceItem(ServiceRecordDC iServiceRecord, SupportConceptApprovalPeriod scap, Calculations calc)
{
var ii = base.CreateInvoiceItem(iServiceRecord, scap, calc);
ii.UnitDescription = "ABW";
return ii;
}
public override IList<InvoiceItem> CreateSummaryInvoiceItems(IList<InvoiceItem> itemList, DateTimeSpan invoicePeriod, SupportConceptApprovalPeriod scap,
Calculations calc, bool summaryPerMonth)
{
@@ -172,7 +179,6 @@ namespace DiakonischesWerkMuelheimTwg.Invoicing
return newlist;
}
public bool RundeRateFactorMitBetrag { get; set; }
}
}

View File

@@ -40,7 +40,6 @@ namespace DiakonischesWerkMuelheimTwg.Invoicing
return new CustomInvoiceCreation();
}
}
}
}

View File

@@ -101,7 +101,8 @@ namespace DiakonischesWerkMuelheimTwg.Invoicing
ItemPeriodEnd = serviceInvoicePeriod.End,
AccountingInterval = AccountingIntervalType.Daily,
AmountPerUnit = 0,
UnitCount = 0
UnitCount = 0,
UnitDescription = supportConceptApprovalPeriod.ServiceCategory != null ? supportConceptApprovalPeriod.ServiceCategory.Name : "Pflege"
};
// Gibt es einen Krankenhausaufenthalt während der Abrechnungszeit, dürfen währenddessen nur 75% abgerechnet werden
var item75Prozent = new InvoiceItem()
@@ -113,7 +114,8 @@ namespace DiakonischesWerkMuelheimTwg.Invoicing
ItemPeriodEnd = serviceInvoicePeriod.End,
AccountingInterval = AccountingIntervalType.Daily,
AmountPerUnit = 0,
UnitCount = 0
UnitCount = 0,
UnitDescription = supportConceptApprovalPeriod.ServiceCategory != null ? supportConceptApprovalPeriod.ServiceCategory.Name : "Pflege"
};
var abwesenheiten = cb2sc.SupportConcept.Customer.AbsenceTimes.Where(a => a.AbsenceReason.Description.ToLower().Contains("krankenhaus"));
@@ -163,5 +165,12 @@ namespace DiakonischesWerkMuelheimTwg.Invoicing
return CreateSummaryInvoiceItems(list, invoicePeriod, scap, calc);
}
public override InvoiceItem CreateInvoiceItem(ServiceRecordDC iServiceRecord, SupportConceptApprovalPeriod scap, Calculations calc)
{
var ii = base.CreateInvoiceItem(iServiceRecord, scap, calc);
ii.UnitDescription = "Pflege";
return ii;
}
}
}