Files
Masterarbeit/QuellCode/CentronERP/tests/Centron.Tests.EndToEnd/Tests/Dunning/DunningTests.cs
T
Christoph Schwörer f045b99a25 Codebasis als Dateien ins Arbeitsrepo statt als Gitlink
QuellCode/CentronERP war nur als Gitlink (Submodul-Referenz auf 79c1142)
getrackt, ohne .gitmodules und ohne erreichbares Remote. Der
Untersuchungsgegenstand der Versuchsreihe war damit nicht reproduzierbar
gesichert: Ein Klon haette ein leeres Verzeichnis erhalten, und die Belege
der 3.287 Anforderungen waeren nicht ueberpruefbar gewesen.

Umstellung:
- Historie nach c:\DEV\CentronERP_git_snapshot_79c1142 ausgelagert
  (vollstaendig lesbar, enthaelt 79c1142 und Vorgaenger 89ccfd6)
- Gitlink aus dem Index entfernt
- Dateiinhalt aufgenommen: 24.557 Dateien, rund 333 MB

Die verschachtelte .gitignore der Codebasis gilt weiter, Build-Artefakte
bleiben ausgeschlossen. Details in Versuche/Versuch_01/_Codebasis-Nachweis.md
2026-08-26 07:43:51 +02:00

583 lines
22 KiB
C#

using Centron.BusinessLogic;
using Centron.BusinessLogic.EmployeeArea;
using Centron.BusinessLogic.Sales.Customers;
using Centron.BusinessLogic.Sales.Receipts.DataAndResults;
using Centron.BusinessLogic.WebServices;
using Centron.BusinessLogic.WebServices.Sales.Receipts;
using Centron.Data.Entities.Administration.Logins;
using Centron.Data.Entities.CustomerArea;
using Centron.Data.Entities.Sales.Receipts.Invoices.Dunning;
using Centron.Data.WebServices.Mail;
using Centron.Data.WebServices.Sales.Receipts.CreditVouchers;
using Centron.Interfaces;
using Centron.Interfaces.Administration.Environment;
using Centron.Interfaces.BL;
using Centron.Interfaces.Sales.Receipts.InsertReceipts;
using Centron.Interfaces.Sales.Receipts.Invoices.Dunning;
using Centron.Tests.EndToEnd.Infrastructure;
using CentronSoftware.Centron.WebServices.Entities.Mail.Templates;
using CentronSoftware.Centron.WebServices.Entities.Sales.Receipts.Invoices.Dunning;
using CentronSoftware.Centron.WebServices.EntitiesWrongPlace.Sales.Receipts.DataAndResults;
using System;
using System.Collections.Generic;
using System.Linq;
using Xunit;
using Xunit.Abstractions;
namespace Centron.Tests.EndToEnd.Tests.Dunning
{
public class DunningTests : EndToEndTest
{
private readonly int _referenceCustomerI3D = 10000;
// NOTE: these tests also test OPOS at the same time
public DunningTests(ITestOutputHelper testOutputHelper)
: base(testOutputHelper)
{
this.Verifier.Settings.IgnoreProperty<DunningSettingsDTO>(f => f.AdvisorEmailTextVariables);
this.Verifier.Settings.IgnoreProperty<DunningSettingsDTO>(f => f.CustomerEmailTextVariables);
this.Verifier.Settings.IgnoreProperty<InvoiceDunningDTO>(f => f.NextDueDateInDays);
this.Verifier.Settings.IgnoreProperty<InvoiceDunningDTO>(f => f.NextDueDate);
this.Verifier.Settings.IgnoreProperty<DunningRunResultDTO>(f => f.ReceiptReports);
this.Verifier.Settings.IgnoreProperty<DunningRunResultDTO>(f => f.Report);
this.Verifier.Settings.IgnoreProperty<DunningRunResultDTO>(f => f.ReportFileName);
this.Verifier.Settings.IgnoreProperty<DunningRunItemDTO>(f => f.DeletedDate); //Test is a bit flaky with this property sometimes being equal to Date, sometimes not
this.Verifier.Settings.IgnoreProperty<MailDTO>(f => f.MailAttachments);
}
public override void Execute()
{
this.PrepareDatabase();
// dunningBL
this.GetCustomers();
this.CalculateDunningStatistics();
this.UpdateDunningStopAndInfo();
this.GetAndUpdateSettings();
this.GetAndUpdateCustomerSettings();
// dunningRunBL
this.ExecuteDunningRun();
this.LoadDunningRuns();
this.ResetDunningRun();
}
private void PrepareDatabase()
{
// reset all invoices dunning stuff and close all
this.Sql(@"UPDATE RechKopf
SET Mahnung1Datum = NULL,
Mahnung1BearbeiterI3D = NULL,
Mahnung2Datum = NULL,
Mahnung2BearbeiterI3D = NULL,
Mahnung3Datum = NULL,
Mahnung3BearbeiterI3D = NULL,
MahnInfo = NULL,
MahnStop = NULL,
Mahnstufe = 0,
Datum = '2020-01-01 00:00:00.000',
FaelligAm = '2020-01-20 00:00:00.000',
Status = 2");
this.Sql(@"UPDATE RechKopf
SET Status = 1
WHERE I3D = 1 OR I3D = 2 OR I3D = 11 OR I3D = 13 OR I3D = 14");
this.Sql(@"UPDATE RechKopf
SET Status = 1,
FaelligAm = DATEADD(day, 5, GETDATE())
WHERE I3D = 3 OR I3D = 4 OR I3D = 26");
this.Sql(@"UPDATE RechKopf
SET Status = 1,
Mahnung1Datum = '2020-01-25 00:00:00.000',
Mahnung1BearbeiterI3D = 26,
Mahnstufe = 1
WHERE I3D = 29 OR I3D = 30 OR I3D = 35");
this.Sql(@"UPDATE RechKopf
SET Status = 1,
Mahnung1Datum = '2020-01-25 00:00:00.000',
Mahnung1BearbeiterI3D = 26,
Mahnstufe = 1,
MahnStop = 1,
MahnInfo = 'MahnInfo entry'
WHERE I3D = 31 OR I3D = 32");
this.Sql(@"UPDATE RechKopf
SET Status = 1,
Mahnung1Datum = '2020-01-25 00:00:00.000',
Mahnung1BearbeiterI3D = 26,
Mahnung2Datum = '2020-02-20 00:00:00.000',
Mahnung2BearbeiterI3D = 26,
Mahnstufe = 2
WHERE I3D = 36 OR I3D = 38 OR I3D = 39 OR I3D = 37");
this.Sql(@"UPDATE RechKopf
SET Status = 1,
Mahnung1Datum = '2020-01-25 00:00:00.000',
Mahnung1BearbeiterI3D = 26,
Mahnung2Datum = '2020-02-20 00:00:00.000',
Mahnung2BearbeiterI3D = 26,
Mahnung3Datum = '2020-03-20 00:00:00.000',
Mahnung3BearbeiterI3D = 26,
Mahnstufe = 3
WHERE I3D = 40 OR I3D = 41 OR I3D = 51 OR I3D = 54");
this.Sql(@$"UPDATE AccountCustomers
SET DunningInfo = 'DunningInfo',
DunningStop = 1,
DunningStopBegin = '2018-01-01 00:00:00.000',
DunningStopEnd = '2018-02-02 00:00:00.000'
WHERE Number = {this._referenceCustomerI3D}");
this.ForwardInvoiceToCreditVoucherPartsByPrice();
this.ForwardInvoiceToCreditVoucherPartsByQuantity();
}
private void ForwardInvoiceToCreditVoucherPartsByPrice()
{
var referenceInvoiceI3D = 51;
using var session = new BLSession();
var bl = session.GetBL<ReceiptWebServiceBL>();
var user = this.GetLoggedInUser();
var invoice = bl.GetReceiptByI3D(referenceInvoiceI3D, CentronObjectKindNumeric.InvoiceClass, user).ThrowIfError();
var forwardedReceipt = bl.ForwardReceipt(
CentronObjectKindNumeric.CreditVoucherClass,
user.User,
new ForwardReceiptData
{
CreateReceiptData = new CreateReceiptData
{
IgnoreCallbacks = true,
},
CreateReceiptItemsFromExistingItemsData = new List<CreateReceiptItemsFromExistingItemsData>
{
new()
{
IgnoreCallbacks = true,
},
},
IgnoreCallbacks = true
},
new List<ReceiptToForward>
{
new ReceiptToForward
{
ReceiptKind = invoice.ReceiptKind,
ReceiptI3D = invoice.I3D
}
},
null,
InsertReceiptTakeoverOptions.Reference,
true,
false).ThrowIfError();
var creditVoucher = (ReceiptCreditVoucherDTO)forwardedReceipt.Receipt;
var articlePos = creditVoucher.Items.First(f => f.ArticleCode == "SERHM");
articlePos.BasePrice = 100;
session.GetBL<ReceiptWebServiceBL>().SaveReceipt(
creditVoucher,
user.User,
new SaveReceiptData
{
IgnoreCallbacks = true
},
false,
CreatedThroughApplication.CentronNet,
null).ThrowIfError();
// the invoice is now closed so we need to manually reopen it
this.Sql(@$"UPDATE RechKopf
SET Status = 1
WHERE I3D = {referenceInvoiceI3D}");
}
private void ForwardInvoiceToCreditVoucherPartsByQuantity()
{
using var session = new BLSession();
var bl = session.GetBL<ReceiptWebServiceBL>();
var user = this.GetLoggedInUser();
var invoice = bl.GetReceiptByI3D(54, CentronObjectKindNumeric.InvoiceClass, user).ThrowIfError();
var forwardedReceipt = bl.ForwardReceipt(
CentronObjectKindNumeric.CreditVoucherClass,
user.User,
new ForwardReceiptData
{
CreateReceiptData = new CreateReceiptData
{
IgnoreCallbacks = true,
},
CreateReceiptItemsFromExistingItemsData = new List<CreateReceiptItemsFromExistingItemsData>
{
new()
{
IgnoreCallbacks = true,
},
},
IgnoreCallbacks = true
},
new List<ReceiptToForward>
{
new ReceiptToForward
{
ReceiptKind = invoice.ReceiptKind,
ReceiptI3D = invoice.I3D
}
},
null,
InsertReceiptTakeoverOptions.Reference,
true,
false).ThrowIfError();
var creditVoucher = (ReceiptCreditVoucherDTO)forwardedReceipt.Receipt;
var articlePos = creditVoucher.Items.First(f => f.ArticleCode == "SERHM");
Assert.NotNull(articlePos.QuantityComplete);
// the value should be exactly 2.0 but comparing decimals like this is not a great idea
Assert.InRange(articlePos.QuantityComplete.Value, (decimal)1.9, (decimal)2.1);
articlePos.QuantityComplete = 1;
session.GetBL<ReceiptWebServiceBL>().SaveReceipt(
creditVoucher,
user.User,
new SaveReceiptData
{
IgnoreCallbacks = true
},
false,
CreatedThroughApplication.CentronNet,
null).ThrowIfError();
}
#region DunningBL
private void GetCustomers()
{
using (var session = new BLSession())
{
InternalLoad("WithoutFilter", new DunningCustomerFilter());
InternalLoad("IncludeDunningStop", new DunningCustomerFilter
{
InDunningStop = true
});
InternalLoad("IncludingNoDunningLevel", new DunningCustomerFilter
{
IncludeNoDunningLevel = true
});
InternalLoad("IncludingCreditVouchers", new DunningCustomerFilter
{
IncludeCreditVouchers = true
});
InternalLoad("IncludingNotReadyForDunning", new DunningCustomerFilter
{
IncludeNotReadyForDunning = true
});
InternalLoad("NoneLevel", new DunningCustomerFilter
{
DunningLevels = new List<DunningLevel>
{
DunningLevel.None
}
});
InternalLoad("Level1", new DunningCustomerFilter
{
DunningLevels = new List<DunningLevel>
{
DunningLevel.Level1
}
});
InternalLoad("Level2", new DunningCustomerFilter
{
DunningLevels = new List<DunningLevel>
{
DunningLevel.Level2
}
});
InternalLoad("Level3", new DunningCustomerFilter
{
DunningLevels = new List<DunningLevel>
{
DunningLevel.Level3
}
});
InternalLoad("Level12", new DunningCustomerFilter
{
DunningLevels = new List<DunningLevel>
{
DunningLevel.Level1,
DunningLevel.Level2
}
});
InternalLoad("Level13", new DunningCustomerFilter
{
DunningLevels = new List<DunningLevel>
{
DunningLevel.Level1,
DunningLevel.Level3
}
});
void InternalLoad(string name, DunningCustomerFilter filter)
{
using (var bl2 = new BLSession())
{
// we need to set this to always true, otherwise we'll get 0 because this will filter everything before today
filter.IncludeBeforeDueDate = true;
var customers = bl2.GetBL<DunningWebServiceBL>().GetDunningCustomers(filter, this.GetLoggedInUser());
this.Verifier.Verify("DunningCustomers" + name, customers);
}
}
}
}
private void UpdateDunningStopAndInfo()
{
using (var session = new BLSession())
{
var invoiceDunningI3D = 2;
session.GetBL<DunningWebServiceBL>().UpdateDunningStopAndInfo(invoiceDunningI3D,
CentronObjectKindNumeric.InvoiceClass,
true,
"Updated dunning stop info for receipt",
new DateTime(2020, 1, 1),
new DateTime(2022, 1, 1),
this.GetLoggedInUser());
var invoiceDunning = session.GetBL<DunningWebServiceBL>().GetEntityById<InvoiceDunning>(invoiceDunningI3D);
this.Verifier.Verify("UpdatedInvoiceDunning", ObjectMapper.Map<InvoiceDunning, InvoiceDunningDTO>(invoiceDunning));
}
using (var session = new BLSession())
{
session.GetBL<DunningWebServiceBL>().UpdateDunningStopAndInfo(this._referenceCustomerI3D,
CentronObjectKindNumeric.CustomerClass,
true,
"Updated dunning stop info for customer",
new DateTime(2020, 1, 1),
new DateTime(2022, 1, 1),
this.GetLoggedInUser());
var customer = session.GetBL<DunningWebServiceBL>().GetDunningCustomers(new DunningCustomerFilter
{
CustomerI3Ds = new List<int>
{
this._referenceCustomerI3D
}
}, this.GetLoggedInUser()).FirstOrDefault();
this.Verifier.Verify("UpdatedCustomerDunningStop", customer);
}
}
private void CalculateDunningStatistics()
{
using (var session = new BLSession())
{
var statistics = session.GetBL<DunningWebServiceBL>().CalculateDunningStatistics(new DunningCustomerFilter
{
// we need to set this to always true, otherwise we'll get 0 because this will filter everything before today
IncludeBeforeDueDate = true
}, this.GetLoggedInUser());
this.Verifier.Verify("DunningStatistics", statistics);
}
}
private void GetAndUpdateSettings()
{
using (var session = new BLSession())
{
var bl = session.GetBL<DunningWebServiceBL>();
var settings = bl.GetSettings();
this.Verifier.Verify("DunningSettings", settings);
settings.DefaultInterest = 20;
settings.ShowLevel1 = true;
settings.Level1AfterDays = 20;
settings.Level1Fees = 20;
settings.Level1Text = "Updated settings text";
settings.ShowLevel2 = true;
settings.Level2AfterDays = 20;
settings.Level2Fees = 20;
settings.Level2Text = "Updated settings text";
settings.ShowLevel3 = true;
settings.Level3AfterDays = 20;
settings.Level3Fees = 20;
settings.Level3Text = "Updated settings text";
settings.PaymentToleranceInDays = 20;
bl.UpdateSettings(settings);
var updatedSettings = bl.GetSettings();
this.Verifier.Verify("UpdatedDunningSettings", updatedSettings);
}
}
private void GetAndUpdateCustomerSettings()
{
using (var session = new BLSession())
{
session.GetBL<DunningWebServiceBL>().UpdateDunningSettingsForCustomer(this._referenceCustomerI3D,
2,
DunningSendType.Print,
true,
this.GetLoggedInUser());
var updatedCustomer = session.GetBL<CustomerBL>().GetCustomer(this._referenceCustomerI3D);
this.Verifier.Verify("DunningCustomerSettings", new CustomerDunningSettingsTestClass(updatedCustomer));
}
}
private class CustomerDunningSettingsTestClass
{
public int CustomerI3D { get; set; }
public int? ContactPersonI3D { get; set; }
public DunningSendType? SendType { get; set; }
public bool UseAlternativeInvoiceAddress { get; set; }
public CustomerDunningSettingsTestClass(Customer customer)
{
this.CustomerI3D = customer.I3D;
this.ContactPersonI3D = customer.DunningContactPerson?.I3D;
switch (customer.DunningKind)
{
case "Mail":
this.SendType = DunningSendType.Mail;
break;
case "Print":
this.SendType = DunningSendType.Print;
break;
case "Fax":
this.SendType = DunningSendType.Fax;
break;
default:
this.SendType = null;
break;
}
this.UseAlternativeInvoiceAddress = customer.DunningAtAlternateInvoiceAddress;
}
}
#endregion
private void ExecuteDunningRun()
{
DunningCustomerDTO customer;
using (var session = new BLSession())
{
customer = session.GetBL<DunningWebServiceBL>().GetDunningCustomers(new DunningCustomerFilter
{
IncludeBeforeDueDate = true,
CustomerI3Ds = new List<int>
{
this._referenceCustomerI3D
}
}, this.GetLoggedInUser()).FirstOrDefault();
}
using (var session = new BLSession())
{
var bl = session.GetBL<DunningRunWebServiceBL>();
bl.EndToEndTestMode = true;
var result = bl.ExecuteDunningRun(new DunningRunForCustomerDTO
{
Customer = customer,
Invoices = customer.Invoices.Where(f => f.DunningLevel != DunningLevel.Level3).ToList(),
CreditVouchers = customer.CreditVouchers,
MailBody = new MailBodyDTO
{
Text = "Email Body",
Type = Interfaces.Mail.Enums.CentronMailBodyType.Plain
},
MailSubject = "Email Subject",
SendType = DunningSendType.Mail
}, this.GetLoggedInUser());
this.Verifier.Verify("DunningRun", result);
}
}
private void LoadDunningRuns()
{
using (var session = new BLSession())
{
var runs = session.GetBL<DunningRunWebServiceBL>().GetDunningRuns(new DunningRunFilter
{
TimeSpan = LogTimeSpan.Last30Days,
CustomerI3Ds = new List<int>
{
this._referenceCustomerI3D
}
}, this.GetLoggedInUser());
this.Verifier.Verify("SingleDunningRun", runs);
}
}
private void ResetDunningRun()
{
using (var session = new BLSession())
{
var dunningRunNumber = 9;
session.GetBL<DunningRunWebServiceBL>().ResetDunningRun(dunningRunNumber, this.GetLoggedInUser());
var resetDunningRun = session.GetBL<DunningRunWebServiceBL>().GetDunningRuns(new DunningRunFilter
{
DunningRunNumbers = new List<int>
{
dunningRunNumber
}
}, this.GetLoggedInUser());
this.Verifier.Verify("ResetSingleDunningRun", resetDunningRun);
}
}
}
}