From c3f5ad40cfa17d39044a34ee46a14233033d33ed Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 18 Jun 2026 11:01:56 +0200 Subject: [PATCH] Neuen Basis Fibu Export --- .../FiBuExport/DefaultDatevExport.cs | 23 + .../Invoicing/FiBuExport/DefaultFiBuExport.cs | 446 ++++++++++++++++++ Service/Invoicing/FiBuExport/FiBuDatensatz.cs | 27 ++ 3 files changed, 496 insertions(+) create mode 100644 Service/Invoicing/FiBuExport/DefaultDatevExport.cs create mode 100644 Service/Invoicing/FiBuExport/DefaultFiBuExport.cs create mode 100644 Service/Invoicing/FiBuExport/FiBuDatensatz.cs diff --git a/Service/Invoicing/FiBuExport/DefaultDatevExport.cs b/Service/Invoicing/FiBuExport/DefaultDatevExport.cs new file mode 100644 index 000000000..856a8fdeb --- /dev/null +++ b/Service/Invoicing/FiBuExport/DefaultDatevExport.cs @@ -0,0 +1,23 @@ +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 BeWo.Service.Invoicing.FibuExport +{ + public class DefaultDatevExport : DefaultFiBuExport + { + public DefaultDatevExport(QueryDC query) : base(query) + { + } + + + } +} \ No newline at end of file diff --git a/Service/Invoicing/FiBuExport/DefaultFiBuExport.cs b/Service/Invoicing/FiBuExport/DefaultFiBuExport.cs new file mode 100644 index 000000000..ef4d8ff69 --- /dev/null +++ b/Service/Invoicing/FiBuExport/DefaultFiBuExport.cs @@ -0,0 +1,446 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.IO; +using System.Linq; +using System.Text; +using BeWo.Data.Access; +using BeWo.Data.Entities; +using BeWo.Service.DCEntityMapper; +using BeWo.Service.Invoicing.FiBuExport; +using BS.Shared; +using BS.Shared.DataContracts; +using BS.Shared.Extensions; + +namespace BeWo.Service.Invoicing.FibuExport +{ + public class DefaultFiBuExport + { + + public QueryDC Query { get; set; } + public DateTime Datum { get; set; } + public bool FilterNachRechnungsdatum { get; set; } + + public DefaultFiBuExport(QueryDC query) + { + Query = query; + DateTime dt = DateTime.Now; + DateTime.TryParse(query.Parameter[0].Value.ToString(), out dt); + + Datum = dt; + FilterNachRechnungsdatum = false; + } + + + public virtual QueryDC CreateQuery() + { + Query.FileName = GetFileName(); + Query.QueryResult = GetResultString(); + + return Query; + } + + + public virtual String GetFileName() + { + return String.Format("Export {0:yyyyMM}.csv", Datum); + } + + public virtual string GetResultString() + { + return GetCsvString(); + } + + public virtual List> GetHeader() + { + return new List> + { + new KeyValuePair ("Betrag", "Betrag"), + new KeyValuePair ("Belegnummer", "Belegnummer"), + new KeyValuePair ("Datum", "Datum"), + new KeyValuePair ("Konto", "KontoHilfeplan"), + new KeyValuePair ("Gegenkonto", "Debitornummer"), + new KeyValuePair ("Kostenstelle", "KostenstelleKlient"), + new KeyValuePair ("Buchungstext", "Buchungstext") + }; + } + + public virtual String GetCsvString(String separator = ";") + { + StringBuilder sb = new StringBuilder(); + + var header = GetHeader(); + if (header != null && header.Count > 0) + { + sb.AppendLine(String.Join(separator, header.Select(k => k.Key))); + } + + var daten = CreateDatensaetze(); + + var s = GetDatenCsv(daten); + + if (!String.IsNullOrWhiteSpace(s)) + { + sb.Append(s); + } + + return sb.ToString(); + } + + public virtual IList CreateDatensaetze() + { + return CreateDatensaetze(true, true, true, true); + } + + public virtual string GetDatenCsv(IList daten, String separator = ";") + { + StringBuilder sb = new StringBuilder(); + + var header = GetHeader(); + foreach (var item in daten) + { + sb.AppendLine(String.Join(separator, GetDatensatzValues(item, header))); + } + + return sb.ToString(); + } + + public virtual string[] GetDatensatzValues(FiBuDatensatz item, List> header) + { + var values = new List(); + foreach (var kv in header) + { + var test = GetDatensatzValue(item, kv.Value); + if (test != null) + { + values.Add(test.ToString()); + } + else + { + values.Add(String.Empty); + } + } + return values.ToArray(); + } + + public virtual string GetDatensatzValue(FiBuDatensatz item, string propertyName) + { + if ("Betrag".Equals(propertyName)) + { + return String.Format("{0:0.00}", item.Betrag); + } + if ("Datum".Equals(propertyName)) + { + return String.Format("{0:dd.MM.yyyy}", item.Datum); + } + var test = item.GetPropertyValue(propertyName); + if (test != null) + { + return test.ToString(); + } + return String.Empty; + } + + public virtual IList CreateDatensaetze(bool holeSammelRechnungen, bool holeSpitzabrechnungen, bool holeStundenBetraege, bool holeAbschlagszahlungen) + { + var result = new List(); + + if (holeSammelRechnungen) + { + var sql = GetSammelRechnungenSql(); + var dt = ExecuteQuery(sql); + + result.AddRange(GetRechnungenDatensaetze(dt)); + } + if (holeSpitzabrechnungen) + { + var sql = GetSpitzabrechnungenSql(); + var dt = ExecuteQuery(sql); + + result.AddRange(GetRechnungenDatensaetze(dt)); + } + if (holeStundenBetraege) + { + var sql = GetMonatlicheBetraegeAnhandGeleisteterStundenSql(); + var dt = ExecuteQuery(sql); + + result.AddRange(GetRechnungenDatensaetze(dt)); + } + if (holeAbschlagszahlungen) + { + var sql = GetAbschlagszahlungenSql(); + var dt = ExecuteQuery(sql); + + result.AddRange(GetRechnungenDatensaetze(dt)); + } + return result; + } + + private IEnumerable GetRechnungenDatensaetze(DataTable dt) + { + var result = new List(); + + foreach (DataRow row in dt.Rows) + { + var fd = CreateFibuDatensatz(row); + + result.Add(fd); + } + + return result; + } + + public virtual FiBuDatensatz CreateFibuDatensatz(DataRow row) + { + var fd = new FiBuDatensatz(); + + fd.CustomerLastName = row[0].ToString(); + fd.CustomerFirstName = row[1].ToString(); + fd.Betrag = (decimal?)row[2]; + fd.DebitorNummer = row[3].ToString(); + fd.Datum = (DateTime)row[4]; + fd.Belegnummer = row[5].ToString(); + fd.InvoiceId = row[6].ToString(); + fd.KostenstelleKlient = row[7].ToString(); + fd.OrganisationName = row[8].ToString(); + fd.KontoHilfeplan = row[9].ToString(); + fd.KostenstelleHilfeplan = row[10].ToString(); + fd.Costbearer2SupportConceptOid = (long?)row[11]; + fd.CustomerOid = (long?)row[12]; + + return fd; + } + + public virtual String GetSammelRechnungenSql() + { + String sql = @" + select + p.Lastname, + p.Firstname, + sip.Claim, + c.DebitorNumber, + ib.InvoiceDate, + ib.invoicenumber, + ib.InvoiceId, + c.CostCenter, + org.Name, + c2s.KontoHilfeplan, + c2s.KostenstelleHilfeplan, + c2s.Oid as 'c2sOid', + c.Oid as 'CustomerOid' + 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 costbearer cb on c2s.costbeareroid = cb.oid + inner join organisation org on org.costbeareroid = cb.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 DATUMFILTER AND ib.IsActive = 1 AND ib.`IsExported` = 0 + "; + if (FilterNachRechnungsdatum) + { + sql = sql.Replace("DATUMFILTER", "ib.InvoiceDate >= ':Monat_Start' AND ib.InvoiceDate < ':Monat_End'"); + } + else + { + sql = sql.Replace("DATUMFILTER", "ib.`AccountingPeriodEnd` >= ':Monat_Start' AND ib.`AccountingPeriodEnd` < ':Monat_End'"); + } + return sql; + } + + public virtual String GetSpitzabrechnungenSql() + { + String sql = @" + select + p.Lastname, + p.Firstname, + si.Claim, + c.DebitorNumber, + ib.InvoiceDate, + ib.invoicenumber, + ib.InvoiceId, + c.CostCenter, + org.Name, + c2s.KontoHilfeplan, + c2s.KostenstelleHilfeplan, + c2s.Oid as 'c2sOid', + c.Oid as 'CustomerOid' + from invoicebase ib + join settlementinvoice si on si.invoicebaseoid = ib.oid + join supportconcept sc on sc.oid = ib.supportconceptoid + join costbearer2supportconcept c2s on c2s.supportconceptoid = sc.oid + join costbearer cb on c2s.costbeareroid = cb.oid + join organisation org on org.costbeareroid = cb.oid + join customer c on c.oid = sc.customeroid + join `person` p on c.`PersonOid` = p.`Oid` + WHERE DATUMFILTER + AND ib.type = 1 AND ib.isactive = 1 and c.isactive <> 0 AND ib.`IsExported` = 0 + "; + //if (FilterNachRechnungsdatum) + //{ + sql = sql.Replace("DATUMFILTER", "ib.InvoiceDate >= ':Monat_Start' AND ib.InvoiceDate < ':Monat_End'"); + //} + //else + //{ + // sql = sql.Replace("DATUMFILTER", "ib.`AccountingPeriodEnd` >= ':Monat_Start' AND ib.`AccountingPeriodEnd` < ':Monat_End'"); + //} + return sql; + } + + + + public virtual String GetAbschlagszahlungenSql() + { + String sql = @" + SELECT + p.Lastname, + p.Firstname, + at.Amount as 'Betrag', + c.DebitorNumber, + at.BookingDate, + at.Notice, + 'Abschlagszahlung', + c.CostCenter, + org.Name, + c2s.KontoHilfeplan, + c2s.KostenstelleHilfeplan, + c2s.Oid as 'c2sOid', + c.Oid as 'CustomerOid' + from accountingtransaction at + join costbearer2supportconcept c2s on c2s.oid = at.costbearer2supportconceptoid + join costbearer cb on c2s.costbeareroid = cb.oid + join organisation org on org.costbeareroid = cb.oid + join supportconcept sc on sc.oid = c2s.supportconceptoid + join customer c on sc.customeroid = c.oid + join person p on c.personoid = p.oid + WHERE at.`BookingDate` >= ':Monat_Start' AND at.`BookingDate` < ':Monat_End' and c.`IsActive` <> 0 AND sc.`IsActive` <> 0 + ORDER BY p.`LastName`, p.`FirstName` + "; + return sql; + } + + public virtual String GetMonatlicheBetraegeAnhandGeleisteterStundenSql() + { + return GetMonatlicheBetraegeAnhandGeleisteterStundenSql("LVR%"); + } + + public virtual String GetMonatlicheBetraegeAnhandGeleisteterStundenSql(String organisationFilter, String fehlkontaktString = "Fehlkontakt") + { + String sql = @" + SELECT + qry.LastName, + qry.FirstName, + sum(qry.Betrag), + qry.DebitorNumber, + null, + null, + null, + qry.CostCenter, + qry.Kostentraeger, + qry.KontoHilfeplan, + qry.KostenstelleHilfeplan, + qry.cb2scOid, + qry.CustomerOid + FROM + ( + (SELECT + IF(crpRateFactor.`CostRateValue` is null, ROUND((sr.`GeleisteteFLM` / 60) * (SELECT crp.`CostRateValue` FROM `costrateperiod` crp WHERE crp.`ObjectTid` = 22 AND crp.`CostRateType` = 0 AND crp.`ObjectOid` = cb2sc.`CostBearerOid` AND (crp.`EndDate` is null or crp.`EndDate` > ':Monat_Start') order by IF(crp.`EndDate` is null, MAKEDATE(9999,365),crp.`EndDate`) LIMIT 1 )), + ROUND(ROUND((sr.`GeleisteteFLM` / 60), 2) * (SELECT crp.`CostRateValue` FROM `costrateperiod` crp WHERE crp.`ObjectTid` = 22 AND crp.`CostRateType` = 0 AND crp.`ObjectOid` = cb2sc.`CostBearerOid` AND (crp.`EndDate` is null or crp.`EndDate` > ':Monat_Start') order by IF(crp.`EndDate` is null, MAKEDATE(9999,365),crp.`EndDate`) LIMIT 1 ) * ((100 + crpRateFactor.`CostRateValue`)/100), 2)) AS 'Betrag', + c.DebitorNumber, + c.CostCenter, + cb2sc.KontoHilfeplan, + p.LastName, + p.FirstName, + CONCAT(p.`LastName`, ', ', p.`FirstName`) as 'Verwendung', + org.Name AS Kostentraeger, + cb2sc.Oid as 'cb2scOid', + c.Oid as 'CustomerOid' + FROM `supportconcept` sc + INNER JOIN `costbearer2supportconcept` cb2sc ON sc.`Oid` = cb2sc.`SupportConceptOid` + INNER JOIN `costbearer` cb ON cb2sc.`CostBearerOid` = cb.`Oid` + LEFT JOIN + (SELECT crp.`ObjectOid`, crp.`CostRateValue` FROM `costrateperiod` crp + WHERE crp.`ObjectTid` = 22 AND crp.`CostRateType` = 2 AND(crp.`EndDate` is null or crp.`EndDate` > NOW())) + AS crpRateFactor ON crpRateFactor.`ObjectOid` = cb.`Oid` + INNER JOIN `organisation` org ON org.`CostBearerOid` = cb.`Oid` + INNER JOIN `customer` c ON sc.`CustomerOid` = c.`Oid` + INNER JOIN `person` p on c.`PersonOid` = p.`Oid` + LEFT JOIN + (SELECT sr2.`CostBearer2SupportConceptOid`, SUM(sr2.`roundedduration` / IF(sr2.`GroupEmployeeCount` is null, 1, sr2.`GroupEmployeeCount`)) AS GeleisteteFLM FROM `servicerecord` sr2 + INNER JOIN `servicedescription` sd ON sr2.`ServiceDescriptionOid` = sd.`Oid` + INNER JOIN `servicecategory` sc ON sd.`ServiceCategoryOid` = sc.`Oid` + WHERE sr2.`StartDate` >= ':Monat_Start' AND sr2.`StartDate` < ':Monat_End' AND sc.`Billable` = 1 FEHLKONTAKTFILTER1 GROUP BY sr2.`CostBearer2SupportConceptOid`) + AS sr ON sr.`CostBearer2SupportConceptOid` = cb2sc.`Oid` + WHERE ORGANISATIONFILTER c.`IsActive` <> 0 AND sc.`IsActive` <> 0 AND (sr.`GeleisteteFLM` is not null)) + UNION + (SELECT + ROUND(0.8 * (sr.`GeleisteteFLM` / 60) * (SELECT crp.`CostRateValue` FROM `costrateperiod` crp WHERE crp.`ObjectTid` = 22 AND crp.`CostRateType` = 0 AND crp.`ObjectOid` = cb2sc.`CostBearerOid` AND (crp.`EndDate` is null or crp.`EndDate` > ':Monat_Start') order by IF(crp.`EndDate` is null, MAKEDATE(9999,365),crp.`EndDate`) LIMIT 1 ),2) AS 'Betrag', + c.DebitorNumber, + c.CostCenter, + cb2sc.KontoHilfeplan, + p.LastName, + p.FirstName, + CONCAT(p.`LastName`, ', ', p.`FirstName`) as 'Verwendung', + org.Name AS Kostentraeger, + cb2sc.Oid as 'cb2scOid', + c.Oid as 'CustomerOid' + FROM `supportconcept` sc + INNER JOIN `costbearer2supportconcept` cb2sc ON sc.`Oid` = cb2sc.`SupportConceptOid` + INNER JOIN `costbearer` cb ON cb2sc.`CostBearerOid` = cb.`Oid` + INNER JOIN `organisation` org ON org.`CostBearerOid` = cb.`Oid` + INNER JOIN `customer` c ON sc.`CustomerOid` = c.`Oid` + INNER JOIN `person` p on c.`PersonOid` = p.`Oid` + LEFT JOIN + (SELECT sr2.`CostBearer2SupportConceptOid`, SUM(sr2.`roundedduration` / IF(sr2.`GroupEmployeeCount` is null, 1, sr2.`GroupEmployeeCount`)) AS GeleisteteFLM FROM `servicerecord` sr2 + INNER JOIN `servicedescription` sd ON sr2.`ServiceDescriptionOid` = sd.`Oid` + INNER JOIN `servicecategory` sc ON sd.`ServiceCategoryOid` = sc.`Oid` + WHERE sr2.`StartDate` >= ':Monat_Start' AND sr2.`StartDate` < ':Monat_End' AND sc.`Billable` = 1 FEHLKONTAKTFILTER2 GROUP BY sr2.`CostBearer2SupportConceptOid`) + AS sr ON sr.`CostBearer2SupportConceptOid` = cb2sc.`Oid` + WHERE ORGANISATIONFILTER c.`IsActive` <> 0 AND sc.`IsActive` <> 0 AND (sr.`GeleisteteFLM` is not null)) + )qry + GROUP BY qry.cb2scOid + "; + + String orgFilter = ""; + if (!String.IsNullOrEmpty(organisationFilter)) + { + if (organisationFilter.Contains("%")) + { + sql = sql.Replace("ORGANISATIONFILTER", String.Format("org.Name LIKE '{0}' AND", organisationFilter)); + } + else + { + sql = sql.Replace("ORGANISATIONFILTER", String.Format("org.Name = '{0}' AND", organisationFilter)); + } + } + + String fkFilter1 = ""; + String fkFilter2 = ""; + if (!String.IsNullOrEmpty(fehlkontaktString)) + { + fkFilter1 = String.Format("AND sd.Name <> '{0}'", fehlkontaktString); + fkFilter2 = String.Format("AND sd.Name = '{0}'", fehlkontaktString); + } + sql = sql.Replace("FEHLKONTAKTFILTER1", fkFilter1); + sql = sql.Replace("FEHLKONTAKTFILTER2", fkFilter2); + return sql; + } + + + + public virtual DataTable ExecuteQuery(String sql) + { + var newsql = sql; + newsql = newsql.Replace(":Abrechnungsmonat", String.Format("{0:dd.MM.yyyy}", Datum)); + newsql = newsql.Replace(":Belegnr", String.Format("{0:yyMM}", Datum)); + newsql = newsql.Replace(":Monat_MM", String.Format("{0:MM}", Datum)); + newsql = newsql.Replace(":Monat_Start", String.Format("{0:yyyy-MM}-01", Datum)); + newsql = newsql.Replace(":Monat_End", String.Format("{0:yyyy-MM}-01", Datum.AddMonths(1))); + + return DAOFactory.AdoDAO.ExecuteQuery(newsql).Tables[0]; + } + } +} \ No newline at end of file diff --git a/Service/Invoicing/FiBuExport/FiBuDatensatz.cs b/Service/Invoicing/FiBuExport/FiBuDatensatz.cs new file mode 100644 index 000000000..78a0c1dad --- /dev/null +++ b/Service/Invoicing/FiBuExport/FiBuDatensatz.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BeWo.Service.Invoicing.FiBuExport +{ + public class FiBuDatensatz + { + public String CustomerFirstName { get; set; } + public String CustomerLastName { get; set; } + public decimal? Betrag { get; set; } + public String Belegnummer { get; set; } + public DateTime Datum { get; set; } + public String DebitorNummer { get; set; } + public String KontoHilfeplan { get; set; } + public String KostenstelleKlient { get; set; } + public String KostenstelleHilfeplan { get; set; } + public String Buchungstext { get; set; } + public String InvoiceId { get; set; } + public String OrganisationName { get; set; } + public long? Costbearer2SupportConceptOid { get; set; } + public long? CustomerOid { get; set; } + + } +}