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
This commit is contained in:
Christoph Schwörer
2026-08-26 07:43:51 +02:00
parent 18edae75b6
commit f045b99a25
24664 changed files with 5846716 additions and 1 deletions
@@ -0,0 +1,493 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Centron.BusinessLogic;
using Centron.BusinessLogic.Administration.Settings;
using Centron.BusinessLogic.Sales.CustomerAssets.Contracts;
using Centron.BusinessLogic.Sales.Receipts;
using Centron.BusinessLogic.Sales.Receipts.DataAndResults;
using Centron.BusinessLogic.WebServices.Sales.Receipts;
using Centron.Data.Entities.Sales.Receipts.ContractLists;
using Centron.Interfaces;
using Centron.Interfaces.Administration.Environment;
using Centron.Interfaces.Administration.Settings;
using Centron.Interfaces.BL;
using Centron.Interfaces.Sales.BillingCenter.Contracts;
using Centron.Interfaces.Sales.Receipts;
using Centron.Tests.EndToEnd.Infrastructure;
using CentronSoftware.Centron.WebServices.Entities.Sales.Receipts.ContractLists;
using Xunit.Abstractions;
namespace Centron.Tests.EndToEnd.Tests.Contracts
{
/// <summary>
/// End-to-end tests for the ContractBL.CloseContract() method.
/// Tests the automatic contract closure functionality based on termination/end dates.
/// </summary>
public class ContractCloseTests : EndToEndTest
{
// Test data constants
private const int _customerI3D = 10022;
private const int _testUserI3D = 11;
private const int _contractKindI3D = 12;
// Fixed reference date for all tests to ensure deterministic behavior
private readonly DateTime _referenceDate = new DateTime(2025, 5, 1); // May 1st, 2025
public ContractCloseTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper)
{
// Set to true only when you need to update expected files
//Verifier.OverrideExpectedFiles = true; // Remove this line after updating expected files
}
public override void Execute()
{
TestAutomaticClosureDisabled(new BLSession());
TestAutomatedProlongationContract_ShouldNotClose_WhenTerminationEqualsLastBookingTo(new BLSession());
TestAutomatedProlongationContract_ShouldClose_WhenTerminationExceeded(new BLSession());
TestNormalContract_ShouldNotClose_WhenEndDateEqualsLastBookingTo(new BLSession());
TestNormalContract_ShouldClose_WhenEndDateExceeded(new BLSession());
TestContract_ShouldNotClose_WhenNoTerminationOrEndDate(new BLSession());
TestContract_ShouldNotClose_WhenManualCalculation(new BLSession());
TestBugScenario_ContractBilledOnTerminationDate_ShouldNotCloseUntilNextDay(new BLSession());
}
/// <summary>
/// Test that no contracts are closed when automatic closure is disabled
/// </summary>
private void TestAutomaticClosureDisabled(BLSession session)
{
// Arrange
var contractBL = session.GetBL<ContractBL>();
var settingsBL = session.GetBL<AppSettingsBL>();
// Disable automatic closure
var setting = settingsBL.GetSettingsForUpdate(ApplicationSettingID.AutomaticallyCloseExpiredContracts);
setting.UpdateBool(ApplicationSettingID.AutomaticallyCloseExpiredContracts, false);
setting.SaveSettings();
// Create a contract that would normally be closed (termination 10 days before reference date)
var expiredContract = CreateTestContract(session,
contractTermination: _referenceDate.AddDays(-10),
lastBookingTo: _referenceDate.AddDays(-10),
automatedProlongation: true);
var contractsBefore = GetActiveContracts(session);
// Act - pass reference date to CloseContract
contractBL.CloseContract(_referenceDate);
// Assert
var contractsAfter = GetActiveContracts(session);
Verifier.Verify("AutomaticClosure_Disabled_NoContractsClosed", new
{
ContractsBeforeCount = contractsBefore.Count(),
ContractsAfterCount = contractsAfter.Count(),
TestContractStillActive = contractsAfter.Any(c => c.I3D == expiredContract.I3D)
});
// Cleanup
CleanupTestContract(session, expiredContract.I3D);
}
/// <summary>
/// Test that automated prolongation contracts should NOT close when termination equals LastBookingTo
/// but the termination date has not been reached yet (future date)
/// This tests the specific bug fix where contracts were closing prematurely
/// </summary>
private void TestAutomatedProlongationContract_ShouldNotClose_WhenTerminationEqualsLastBookingTo(BLSession session)
{
// Arrange
var contractBL = session.GetBL<ContractBL>();
var settingsBL = session.GetBL<AppSettingsBL>();
// Enable automatic closure
var setting = settingsBL.GetSettingsForUpdate(ApplicationSettingID.AutomaticallyCloseExpiredContracts);
setting.UpdateBool(ApplicationSettingID.AutomaticallyCloseExpiredContracts, true);
setting.SaveSettings();
// Termination date is in the future (30 days after reference date)
var terminationDate = _referenceDate.AddDays(30);
var testContract = CreateTestContract(session,
contractTermination: terminationDate,
lastBookingTo: terminationDate, // Fully billed, but termination date not reached yet
automatedProlongation: true);
// Act - pass reference date to CloseContract
contractBL.CloseContract(_referenceDate);
// Assert
var contractAfter = GetContractById(session, testContract.I3D);
Verifier.Verify("AutomatedProlongation_NotClosed_WhenTerminationEqualsLastBookingTo", new
{
ContractI3D = testContract.I3D,
ContractState = contractAfter?.State.ToString(),
ContractTermination = testContract.ContractTermination?.ToString("yyyy-MM-dd"),
LastBookingTo = testContract.LastBookingTo?.ToString("yyyy-MM-dd"),
ReferenceDate = _referenceDate.ToString("yyyy-MM-dd"),
AutomatedProlongation = testContract.AutomatedProlongation,
ShouldRemainActive = contractAfter?.State == ReceiptState.Active,
Reason = "Termination date is in the future, contract should remain active"
});
// Cleanup
CleanupTestContract(session, testContract.I3D);
}
/// <summary>
/// Test that automated prolongation contracts should close when termination is exceeded
/// and reference date is after the termination date
/// </summary>
private void TestAutomatedProlongationContract_ShouldClose_WhenTerminationExceeded(BLSession session)
{
// Arrange
var contractBL = session.GetBL<ContractBL>();
var settingsBL = session.GetBL<AppSettingsBL>();
// Enable automatic closure
var setting = settingsBL.GetSettingsForUpdate(ApplicationSettingID.AutomaticallyCloseExpiredContracts);
setting.UpdateBool(ApplicationSettingID.AutomaticallyCloseExpiredContracts, true);
setting.SaveSettings();
// Termination date is in the past (10 days before reference date)
var terminationDate = _referenceDate.AddDays(-10);
var testContract = CreateTestContract(session,
contractTermination: terminationDate,
lastBookingTo: terminationDate, // Fully billed and termination date passed
automatedProlongation: true);
// Act - pass reference date to CloseContract
contractBL.CloseContract(_referenceDate);
// Assert
var contractAfter = GetContractById(session, testContract.I3D);
Verifier.Verify("AutomatedProlongation_Closed_WhenTerminationExceeded", new
{
ContractI3D = testContract.I3D,
ContractState = contractAfter?.State.ToString(),
ContractTermination = testContract.ContractTermination?.ToString("yyyy-MM-dd"),
LastBookingTo = testContract.LastBookingTo?.ToString("yyyy-MM-dd"),
ReferenceDate = _referenceDate.ToString("yyyy-MM-dd"),
AutomatedProlongation = testContract.AutomatedProlongation,
ShouldBeClosed = contractAfter?.State == ReceiptState.Completed,
Reason = "Termination date is in the past and contract is fully billed"
});
// Cleanup
CleanupTestContract(session, testContract.I3D);
}
/// <summary>
/// Test that normal contracts should NOT close when end date equals LastBookingTo
/// but the end date has not been reached yet (future date)
/// </summary>
private void TestNormalContract_ShouldNotClose_WhenEndDateEqualsLastBookingTo(BLSession session)
{
// Arrange
var contractBL = session.GetBL<ContractBL>();
var settingsBL = session.GetBL<AppSettingsBL>();
// Enable automatic closure
var setting = settingsBL.GetSettingsForUpdate(ApplicationSettingID.AutomaticallyCloseExpiredContracts);
setting.UpdateBool(ApplicationSettingID.AutomaticallyCloseExpiredContracts, true);
setting.SaveSettings();
// End date is in the future (30 days after reference date)
var endDate = _referenceDate.AddDays(30);
var testContract = CreateTestContract(session,
contractEnd: endDate,
lastBookingTo: endDate, // Fully billed, but end date not reached yet
automatedProlongation: false);
// Act - pass reference date to CloseContract
contractBL.CloseContract(_referenceDate);
// Assert
var contractAfter = GetContractById(session, testContract.I3D);
Verifier.Verify("NormalContract_NotClosed_WhenEndDateEqualsLastBookingTo", new
{
ContractI3D = testContract.I3D,
ContractState = contractAfter?.State.ToString(),
ContractEnd = testContract.ContractEnd?.ToString("yyyy-MM-dd"),
LastBookingTo = testContract.LastBookingTo?.ToString("yyyy-MM-dd"),
ReferenceDate = _referenceDate.ToString("yyyy-MM-dd"),
AutomatedProlongation = testContract.AutomatedProlongation,
ShouldRemainActive = contractAfter?.State == ReceiptState.Active,
Reason = "End date is in the future, contract should remain active"
});
// Cleanup
CleanupTestContract(session, testContract.I3D);
}
/// <summary>
/// Test that normal contracts should close when end date is exceeded
/// and reference date is after the end date
/// </summary>
private void TestNormalContract_ShouldClose_WhenEndDateExceeded(BLSession session)
{
// Arrange
var contractBL = session.GetBL<ContractBL>();
var settingsBL = session.GetBL<AppSettingsBL>();
// Enable automatic closure
var setting = settingsBL.GetSettingsForUpdate(ApplicationSettingID.AutomaticallyCloseExpiredContracts);
setting.UpdateBool(ApplicationSettingID.AutomaticallyCloseExpiredContracts, true);
setting.SaveSettings();
// End date is in the past (10 days before reference date)
var endDate = _referenceDate.AddDays(-10);
var testContract = CreateTestContract(session,
contractEnd: endDate,
lastBookingTo: endDate, // Fully billed and end date passed
automatedProlongation: false);
// Act - pass reference date to CloseContract
contractBL.CloseContract(_referenceDate);
// Assert
var contractAfter = GetContractById(session, testContract.I3D);
Verifier.Verify("NormalContract_Closed_WhenEndDateExceeded", new
{
ContractI3D = testContract.I3D,
ContractState = contractAfter?.State.ToString(),
ContractEnd = testContract.ContractEnd?.ToString("yyyy-MM-dd"),
LastBookingTo = testContract.LastBookingTo?.ToString("yyyy-MM-dd"),
ReferenceDate = _referenceDate.ToString("yyyy-MM-dd"),
AutomatedProlongation = testContract.AutomatedProlongation,
ShouldBeClosed = contractAfter?.State == ReceiptState.Completed,
Reason = "End date is in the past and contract is fully billed"
});
// Cleanup
CleanupTestContract(session, testContract.I3D);
}
/// <summary>
/// Test that contracts without termination or end date are not processed
/// </summary>
private void TestContract_ShouldNotClose_WhenNoTerminationOrEndDate(BLSession session)
{
// Arrange
var contractBL = session.GetBL<ContractBL>();
var settingsBL = session.GetBL<AppSettingsBL>();
// Enable automatic closure
var setting = settingsBL.GetSettingsForUpdate(ApplicationSettingID.AutomaticallyCloseExpiredContracts);
setting.UpdateBool(ApplicationSettingID.AutomaticallyCloseExpiredContracts, true);
setting.SaveSettings();
var testContract = CreateTestContract(session,
contractTermination: null,
contractEnd: null,
lastBookingTo: _referenceDate.AddDays(10),
automatedProlongation: true);
// Act - pass reference date to CloseContract
contractBL.CloseContract(_referenceDate);
// Assert
var contractAfter = GetContractById(session, testContract.I3D);
Verifier.Verify("Contract_NotProcessed_WhenNoTerminationOrEndDate", new
{
ContractI3D = testContract.I3D,
ContractState = contractAfter?.State.ToString(),
HasContractTermination = testContract.ContractTermination.HasValue,
HasContractEnd = testContract.ContractEnd.HasValue,
ShouldRemainActive = contractAfter?.State == ReceiptState.Active
});
// Cleanup
CleanupTestContract(session, testContract.I3D);
}
/// <summary>
/// Test the specific bug scenario from the bug report:
/// Contract is billed on the termination date, but should not close until the next day
/// Bug: Contract was closed on 14.04 when LastBookingTo was 30.04 and TerminationDate was 30.04
/// Expected: Contract should only close on 01.05 (day after termination date)
/// </summary>
private void TestBugScenario_ContractBilledOnTerminationDate_ShouldNotCloseUntilNextDay(BLSession session)
{
// Arrange
var contractBL = session.GetBL<ContractBL>();
var settingsBL = session.GetBL<AppSettingsBL>();
// Enable automatic closure
var setting = settingsBL.GetSettingsForUpdate(ApplicationSettingID.AutomaticallyCloseExpiredContracts);
setting.UpdateBool(ApplicationSettingID.AutomaticallyCloseExpiredContracts, true);
setting.SaveSettings();
// Simulate the bug scenario: Contract termination is 10 days after reference date
// and it's already billed up to that date
var terminationDate = _referenceDate.AddDays(10);
var testContract = CreateTestContract(session,
contractTermination: terminationDate,
lastBookingTo: terminationDate, // Billed on termination date (like 30.04)
automatedProlongation: true);
// Act - Run on the reference date (which is before termination date)
contractBL.CloseContract(_referenceDate);
// Assert
var contractAfter = GetContractById(session, testContract.I3D);
Verifier.Verify("BugScenario_ContractNotClosedWhenBilledOnTerminationDate", new
{
ContractI3D = testContract.I3D,
ContractState = contractAfter?.State.ToString(),
ContractTermination = testContract.ContractTermination?.ToString("yyyy-MM-dd"),
LastBookingTo = testContract.LastBookingTo?.ToString("yyyy-MM-dd"),
ReferenceDate = _referenceDate.ToString("yyyy-MM-dd"),
DaysUntilTermination = (terminationDate - _referenceDate).Days,
ShouldRemainActive = contractAfter?.State == ReceiptState.Active,
Reason = "Contract is fully billed but termination date not yet reached - should remain active"
});
// Cleanup
CleanupTestContract(session, testContract.I3D);
}
/// <summary>
/// Test that manual calculation contracts are not processed
/// </summary>
private void TestContract_ShouldNotClose_WhenManualCalculation(BLSession session)
{
// Arrange
var contractBL = session.GetBL<ContractBL>();
var settingsBL = session.GetBL<AppSettingsBL>();
// Enable automatic closure
var setting = settingsBL.GetSettingsForUpdate(ApplicationSettingID.AutomaticallyCloseExpiredContracts);
setting.UpdateBool(ApplicationSettingID.AutomaticallyCloseExpiredContracts, true);
setting.SaveSettings();
var testContract = CreateTestContract(session,
contractTermination: _referenceDate.AddDays(-10),
lastBookingTo: _referenceDate.AddDays(-10),
automatedProlongation: true,
calculationKind: ContractCalculationKind.Manual); // Manual calculation
// Act - pass reference date to CloseContract
contractBL.CloseContract(_referenceDate);
// Assert
var contractAfter = GetContractById(session, testContract.I3D);
Verifier.Verify("Contract_NotProcessed_WhenManualCalculation", new
{
ContractI3D = testContract.I3D,
ContractState = contractAfter?.State.ToString(),
CalculationKind = testContract.CalculationKind.ToString(),
ShouldRemainActive = contractAfter?.State == ReceiptState.Active
});
// Cleanup
CleanupTestContract(session, testContract.I3D);
}
#region Helper Methods
/// <summary>
/// Creates a test contract with specified parameters
/// </summary>
private ReceiptContract CreateTestContract(BLSession session,
DateTime? contractTermination = null,
DateTime? contractEnd = null,
DateTime? lastBookingTo = null,
bool automatedProlongation = true,
ContractCalculationKind calculationKind = ContractCalculationKind.Auto)
{
var loggedInUser = this.GetLoggedInUser(_testUserI3D);
var receiptWebServiceBL = session.GetBL<ReceiptWebServiceBL>();
// Create new contract
var result = receiptWebServiceBL.CreateNewReceipt(
CentronObjectKindNumeric.ContractClass,
loggedInUser,
_customerI3D,
new CreateReceiptData(),
null, null, true, false, true);
var contractDTO = (ReceiptContractDTO)result.Data.Receipt;
// Set contract properties
contractDTO.ContractKindI3D = _contractKindI3D;
contractDTO.CalculationKind = calculationKind;
contractDTO.AutomatedProlongation = automatedProlongation;
contractDTO.ContractTermination = contractTermination;
contractDTO.ContractEnd = contractEnd;
contractDTO.FirstPaidDate = DateTime.Now.AddDays(-30);
// Save the contract
var saveResult = receiptWebServiceBL.SaveReceipt(contractDTO, loggedInUser.User,
new SaveReceiptData { IgnoreCallbacks = true }, false, CreatedThroughApplication.CentronNet, null);
if (saveResult.Status != ResultStatus.Success)
{
throw new InvalidOperationException($"Failed to create test contract: {saveResult.Message}");
}
// Update LastBookingTo if specified (this needs to be done after saving)
if (lastBookingTo.HasValue)
{
var receiptBL = session.GetBL<ReceiptBL>();
var contract = receiptBL.GetReceiptByI3D<ReceiptContract>(saveResult.Data.Receipt.I3D);
contract.LastBookingTo = lastBookingTo;
receiptBL.SaveReceipt(contract, loggedInUser.User,
new SaveReceiptData { IgnoreCallbacks = true }, false, CreatedThroughApplication.CentronNet);
}
return session.GetBL<ReceiptBL>().GetReceiptByI3D<ReceiptContract>(saveResult.Data.Receipt.I3D);
}
/// <summary>
/// Gets all active contracts
/// </summary>
private List<ReceiptContract> GetActiveContracts(BLSession session)
{
var receiptBL = session.GetBL<ReceiptBL>();
return receiptBL.GetReceipts<ReceiptContract>(f => f.State == ReceiptState.Active).ToList();
}
/// <summary>
/// Gets a contract by ID
/// </summary>
private ReceiptContract GetContractById(BLSession session, int contractI3D)
{
var receiptBL = session.GetBL<ReceiptBL>();
return receiptBL.GetReceiptByI3D<ReceiptContract>(contractI3D);
}
/// <summary>
/// Cleans up test contract
/// </summary>
private void CleanupTestContract(BLSession session, int contractI3D)
{
try
{
var receiptBL = session.GetBL<ReceiptBL>();
var contract = this.GetContractById(session, contractI3D);
if (contract != null)
{
var loggedInUser = this.GetLoggedInUser(_testUserI3D);
contract.State = ReceiptState.Completed;
receiptBL.SaveReceipt(contract, loggedInUser.User,
new SaveReceiptData { IgnoreCallbacks = true }, false, CreatedThroughApplication.CentronNet);
}
}
catch
{
// Ignore cleanup errors in tests
}
}
#endregion
}
}