using System.Globalization; using Centron.BusinessLogic.Administration.Masterdata; using Centron.DAO; using Centron.DAO.Mappings; using Centron.DAO.Mappings.Administration; using Centron.Data.Entities.Administration.MasterData; using FluentNHibernate.Cfg; using FluentNHibernate.Cfg.Db; using JetBrains.Annotations; using NHibernate; using NHibernate.Tool.hbm2ddl; namespace Centron.Tests.BL.Administration.Masterdata; /// /// Tests for the AssetConditionBL class, specifically testing the BR-DE-18 Skonto formatting /// for ZUGFeRD/XRechnung export functionality. /// [TestSubject(typeof(AssetConditionBL))] public class AssetConditionBLTest { [Fact] public void GetPaymentConditionSkontoInBR_DE_18Format_ReturnsNull_WhenNoConditionExists() { // Arrange using var session = CreateSession(); var daoSession = new DAOSession(session); var sut = new AssetConditionBL(daoSession); var nonExistentI3D = 999; // Act var result = sut.GetPaymentConditionSkontoInBR_DE_18Format(nonExistentI3D); // Assert Assert.Null(result); } [Fact] public void GetPaymentConditionSkontoInBR_DE_18Format_ReturnsNull_WhenNoSkontoData() { // Arrange using var session = CreateSession(); var condition = new AssetCondition { ShortName = "NO_SKONTO", Skonto1OffDay = 0, Skonto1Percent = 0, Skonto2OffDay = 0, Skonto2Percent = 0 }; session.Save(condition); session.Flush(); var daoSession = new DAOSession(session); var sut = new AssetConditionBL(daoSession); // Act var result = sut.GetPaymentConditionSkontoInBR_DE_18Format(condition.I3D); // Assert Assert.Null(result); } [Fact] public void GetPaymentConditionSkontoInBR_DE_18Format_FormatsCorrectly_WhenSingleSkontoLevel() { // Arrange using var session = CreateSession(); var condition = new AssetCondition { ShortName = "SKONTO_14_2.5", Skonto1OffDay = 14, Skonto1Percent = 2.5, Skonto2OffDay = 0, Skonto2Percent = 0 }; session.Save(condition); session.Flush(); var daoSession = new DAOSession(session); var sut = new AssetConditionBL(daoSession); // Act var result = sut.GetPaymentConditionSkontoInBR_DE_18Format(condition.I3D); // Assert Assert.Equal("#SKONTO#TAGE=14#PROZENT=2.50#", result); } [Fact] public void GetPaymentConditionSkontoInBR_DE_18Format_FormatsCorrectly_WhenTwoSkontoLevels() { // Arrange using var session = CreateSession(); var condition = new AssetCondition { ShortName = "SKONTO_MULTI", Skonto1OffDay = 10, Skonto1Percent = 3.0, Skonto2OffDay = 30, Skonto2Percent = 1.5 }; session.Save(condition); session.Flush(); var daoSession = new DAOSession(session); var sut = new AssetConditionBL(daoSession); // Act var result = sut.GetPaymentConditionSkontoInBR_DE_18Format(condition.I3D); // Assert Assert.Equal($"#SKONTO#TAGE=10#PROZENT=3.00#{Environment.NewLine}#SKONTO#TAGE=30#PROZENT=1.50#", result); } [Fact] public void GetPaymentConditionSkontoInBR_DE_18Format_UsesInvariantCulture_WhenGermanCultureIsSet() { // Arrange var originalCulture = Thread.CurrentThread.CurrentCulture; try { Thread.CurrentThread.CurrentCulture = new CultureInfo("de-DE"); using var session = CreateSession(); var condition = new AssetCondition { ShortName = "SKONTO_DE", Skonto1OffDay = 14, Skonto1Percent = 2.75, Skonto2OffDay = 0, Skonto2Percent = 0 }; session.Save(condition); session.Flush(); var daoSession = new DAOSession(session); var sut = new AssetConditionBL(daoSession); // Act var result = sut.GetPaymentConditionSkontoInBR_DE_18Format(condition.I3D); // Assert Assert.Equal("#SKONTO#TAGE=14#PROZENT=2.75#", result); Assert.DoesNotContain(",", result); // Should use dot, not comma } finally { Thread.CurrentThread.CurrentCulture = originalCulture; } } [Fact] public void GetPaymentConditionSkontoInBR_DE_18Format_ReturnsCorrectFormat_WhenOnlySkonto2HasData() { // Arrange using var session = CreateSession(); var condition = new AssetCondition { ShortName = "SKONTO2_ONLY", Skonto1OffDay = 0, Skonto1Percent = 0, Skonto2OffDay = 21, Skonto2Percent = 1.25 }; session.Save(condition); session.Flush(); var daoSession = new DAOSession(session); var sut = new AssetConditionBL(daoSession); // Act var result = sut.GetPaymentConditionSkontoInBR_DE_18Format(condition.I3D); // Assert Assert.Equal("#SKONTO#TAGE=21#PROZENT=1.25#", result); } [Theory] [InlineData(14, 0)] // Days without percent [InlineData(0, 2.5)] // Percent without days public void GetPaymentConditionSkontoInBR_DE_18Format_ReturnsNull_WhenIncompleteData(int days, double percent) { // Arrange using var session = CreateSession(); var condition = new AssetCondition { ShortName = "INCOMPLETE", Skonto1OffDay = days, Skonto1Percent = percent, Skonto2OffDay = 0, Skonto2Percent = 0 }; session.Save(condition); session.Flush(); var daoSession = new DAOSession(session); var sut = new AssetConditionBL(daoSession); // Act var result = sut.GetPaymentConditionSkontoInBR_DE_18Format(condition.I3D); // Assert Assert.Null(result); } [Theory] [InlineData(7, 0.5, "#SKONTO#TAGE=7#PROZENT=0.50#")] [InlineData(5, 10.99, "#SKONTO#TAGE=5#PROZENT=10.99#")] [InlineData(365, 99.99, "#SKONTO#TAGE=365#PROZENT=99.99#")] public void GetPaymentConditionSkontoInBR_DE_18Format_HandlesEdgeCases_Correctly(int days, double percent, string expected) { // Arrange using var session = CreateSession(); var condition = new AssetCondition { ShortName = "EDGE_CASE", Skonto1OffDay = days, Skonto1Percent = percent, Skonto2OffDay = 0, Skonto2Percent = 0 }; session.Save(condition); session.Flush(); var daoSession = new DAOSession(session); var sut = new AssetConditionBL(daoSession); // Act var result = sut.GetPaymentConditionSkontoInBR_DE_18Format(condition.I3D); // Assert Assert.Equal(expected, result); } private static ISession CreateSession() { var fluentConfig = Fluently.Configure() .Database(SQLiteConfiguration.Standard.InMemory()) .Mappings(m => { m.FluentMappings.Add(); }); var sessionFactory = fluentConfig.BuildSessionFactory(); var session = sessionFactory.OpenSession(); // Create schema in the in-memory database new SchemaExport(fluentConfig.BuildConfiguration()) .Execute(false, true, false, session.Connection, null); return session; } }