using System; using System.Collections.Generic; using System.Reflection; using Centron.BusinessLogic; using Centron.BusinessLogic.WebServices.Sales.CustomerAssets.AutomaticFactura; using Centron.Data.Entities.Administration.Logins; using Centron.Data.WebServices.Sales.Receipts.Invoices; using Centron.Interfaces.BL; using Centron.Interfaces.Sales.BillingCenter.Contracts; using Centron.Tests.EndToEnd.Infrastructure; using CentronSoftware.Centron.WebServices.Entities.Sales.BillingCenter.Contracts; using Xunit.Abstractions; namespace Centron.Tests.EndToEnd.Tests.AutomaticFactura { public class AutomaticFacturaRMMTests : EndToEndTest { // Test data constants private const int TestContractI3D = 1; // Assuming contract with RMM articles exists private const int TestCustomerI3D = 10010; // Standard test customer private const int TestUserI3D = 11; // Standard test user public AutomaticFacturaRMMTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { // Ignore dynamic properties that change with each run this.Verifier.Settings.IgnoreProperty(f => f.CreatedAt); this.Verifier.Settings.IgnoreProperty(f => f.ChangedAt); // Note: ReceiptInvoiceItemDTO doesn't have CreatedAt/ChangedAt properties } public override void Execute() { // Ignore this test for now // SKA : 2025-07-15 : It's a good base for a future unit test. But at the moment it's hard to test the RMM-Functionality // We have to first encapsulate the call of the external Riverbird Service, so that we can test it // this.PrepareDatabase(); // // // Test single interval (fallback case) // this.TestSingleIntervalRMM(); // // // Test multiple intervals (new functionality) // this.TestMultipleIntervalsRMM(); } private void PrepareDatabase() { // Ensure we have test data for RMM functionality // This would typically involve setting up contract article references, etc. using (var session = new BLSession()) { // Any database preparation needed for RMM testing // For now, we'll rely on existing test data } } /// /// Tests the fallback case with a single billing interval. /// This should work exactly as before the refactoring. /// private void TestSingleIntervalRMM() { using (var session = new BLSession()) { var loggedInUser = this.GetLoggedInUser(TestUserI3D); // Create a billing parameter with single interval var billingParam = new ContractToInvoiceParam { ContractID = new KeyValuePair(TestContractI3D, "Test Contract"), InvoiceFrom = DateTime.Today.AddDays(-30), InvoiceTo = DateTime.Today, InvoiceIntervalCount = 1, // Single interval BillingIntervalKind = BillingIntervalKinds.Monthly, BillingIntervalDuration = 1 }; // Create a test invoice var invoice = this.CreateTestInvoice(session, loggedInUser); // Add RMM placeholder to test removal and replacement this.AddRMMPlaceholderToInvoice(invoice); var automaticFacturaWebServiceBL = session.GetBL(); // This is the method we're testing - it should handle single interval correctly try { // Use reflection to call the private CheckRMMArticle method var checkRMMMethod = typeof(AutomaticFacturaWebServiceBL).GetMethod("CheckRMMArticle", BindingFlags.NonPublic | BindingFlags.Instance); checkRMMMethod?.Invoke(automaticFacturaWebServiceBL, new object[] { invoice, billingParam, loggedInUser }); // Verify the result this.Verifier.Verify("SingleInterval_RMM_Invoice", invoice); } catch (Exception ex) { // If RMM service is not available, we expect a specific exception if (ex.InnerException?.GetType().Name == "RMMServiceUnavailableException") { this.Verifier.Verify("SingleInterval_RMM_ServiceUnavailable", ex.InnerException.Message); } else { throw; } } } } /// /// Tests the new functionality with multiple billing intervals. /// Device counts should be summed across all intervals. /// private void TestMultipleIntervalsRMM() { using (var session = new BLSession()) { var loggedInUser = this.GetLoggedInUser(TestUserI3D); // Create billing parameters with multiple intervals var billingParam = new ContractToInvoiceParam { ContractID = new KeyValuePair(TestContractI3D, "Test Contract"), InvoiceFrom = DateTime.Today.AddDays(-60), InvoiceTo = DateTime.Today, InvoiceIntervalCount = 2, // Two intervals BillingIntervalKind = BillingIntervalKinds.Monthly, BillingIntervalDuration = 1 }; // Create a test invoice var invoice = this.CreateTestInvoice(session, loggedInUser); // Add RMM placeholder to test removal and replacement this.AddRMMPlaceholderToInvoice(invoice); var automaticFacturaWebServiceBL = session.GetBL(); try { // Use reflection to call the private CheckRMMArticle method var checkRMMMethod = typeof(AutomaticFacturaWebServiceBL).GetMethod("CheckRMMArticle", BindingFlags.NonPublic | BindingFlags.Instance); checkRMMMethod?.Invoke(automaticFacturaWebServiceBL, new object[] { invoice, billingParam, loggedInUser }); // Verify the result - should show summed device counts this.Verifier.Verify("MultipleIntervals_RMM_Invoice", invoice); } catch (Exception ex) { // If RMM service is not available, we expect a specific exception if (ex.InnerException?.GetType().Name == "RMMServiceUnavailableException") { this.Verifier.Verify("MultipleIntervals_RMM_ServiceUnavailable", ex.InnerException.Message); } else { throw; } } } } /// /// Tests quarterly billing with different BillingIntervalDuration values. /// private void TestQuarterlyIntervalsRMM() { using (var session = new BLSession()) { var loggedInUser = this.GetLoggedInUser(TestUserI3D); // Test quarterly billing - Variant 1: BillingIntervalKind=Quarterly, Duration=1 var billingParamQuarterly = new ContractToInvoiceParam { ContractID = new KeyValuePair(TestContractI3D, "Test Contract"), InvoiceFrom = DateTime.Today.AddDays(-180), InvoiceTo = DateTime.Today, InvoiceIntervalCount = 2, // Two quarters BillingIntervalKind = BillingIntervalKinds.Quarterly, BillingIntervalDuration = 1 }; // Test quarterly billing - Variant 2: BillingIntervalKind=Monthly, Duration=3 var billingParamMonthly3 = new ContractToInvoiceParam { ContractID = new KeyValuePair(TestContractI3D, "Test Contract"), InvoiceFrom = DateTime.Today.AddDays(-180), InvoiceTo = DateTime.Today, InvoiceIntervalCount = 2, // Two 3-month periods BillingIntervalKind = BillingIntervalKinds.Monthly, BillingIntervalDuration = 3 // Every 3 months }; var automaticFacturaWebServiceBL = session.GetBL(); // Test both variants to ensure they produce equivalent results this.TestBillingParameterVariant(session, automaticFacturaWebServiceBL, loggedInUser, billingParamQuarterly, "Quarterly_Variant1"); this.TestBillingParameterVariant(session, automaticFacturaWebServiceBL, loggedInUser, billingParamMonthly3, "Quarterly_Variant2"); } } private void TestBillingParameterVariant(BLSession session, AutomaticFacturaWebServiceBL webServiceBL, LoggedInUser loggedInUser, ContractToInvoiceParam billingParam, string testName) { var invoice = this.CreateTestInvoice(session, loggedInUser); this.AddRMMPlaceholderToInvoice(invoice); try { var checkRMMMethod = typeof(AutomaticFacturaWebServiceBL).GetMethod("CheckRMMArticle", BindingFlags.NonPublic | BindingFlags.Instance); checkRMMMethod?.Invoke(webServiceBL, new object[] { invoice, billingParam, loggedInUser }); this.Verifier.Verify($"{testName}_RMM_Invoice", invoice); } catch (Exception ex) { if (ex.InnerException?.GetType().Name == "RMMServiceUnavailableException") { this.Verifier.Verify($"{testName}_RMM_ServiceUnavailable", ex.InnerException.Message); } else { throw; } } } private ReceiptInvoiceDTO CreateTestInvoice(BLSession session, LoggedInUser loggedInUser) { // Create a minimal test invoice var invoice = new ReceiptInvoiceDTO { CustomerI3D = TestCustomerI3D, Items = new List(), CreatedAt = DateTime.Now, ChangedAt = DateTime.Now }; return invoice; } private void AddRMMPlaceholderToInvoice(ReceiptInvoiceDTO invoice) { // Add a placeholder RMM item to test removal and replacement var rmmPlaceholderItem = new ReceiptInvoiceItemDTO { Text = "Test item with @@RMMArtikel@@ placeholder", RichText = "Rich text with @@RMMArtikel@@ placeholder", QuantityComplete = 1 }; invoice.Items.Add(rmmPlaceholderItem); } } }