diff --git a/TransactionProcessor.Aggregates.Tests/ContractAggregateTests.cs b/TransactionProcessor.Aggregates.Tests/ContractAggregateTests.cs index f2a48d6..2845d7e 100644 --- a/TransactionProcessor.Aggregates.Tests/ContractAggregateTests.cs +++ b/TransactionProcessor.Aggregates.Tests/ContractAggregateTests.cs @@ -1,4 +1,5 @@ using Shouldly; +using SimpleResults; using TransactionProcessor.Models.Contract; using TransactionProcessor.Testing; @@ -18,7 +19,8 @@ public void ContractAggregate_CanBeCreated_IsCreated() public void ContractAggregate_Create_IsCreated() { ContractAggregate aggregate = ContractAggregate.Create(TestData.ContractId); - aggregate.Create(TestData.EstateId, TestData.OperatorId, TestData.ContractDescription); + Result result = aggregate.Create(TestData.EstateId, TestData.OperatorId, TestData.ContractDescription); + result.IsSuccess.ShouldBeTrue(); aggregate.AggregateId.ShouldBe(TestData.ContractId); aggregate.EstateId.ShouldBe(TestData.EstateId); @@ -32,10 +34,10 @@ public void ContractAggregate_Create_InvalidEstateId_ErrorThrown() { ContractAggregate aggregate = ContractAggregate.Create(TestData.ContractId); - Should.Throw(() => - { - aggregate.Create(Guid.Empty, TestData.OperatorId, TestData.ContractDescription); - }); + Result result = aggregate.Create(Guid.Empty, TestData.OperatorId, TestData.ContractDescription); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); + result.Message.ShouldContain("Estate Id must not be an empty Guid"); } [Fact] @@ -43,10 +45,10 @@ public void ContractAggregate_Create_InvalidOperatorId_ErrorThrown() { ContractAggregate aggregate = ContractAggregate.Create(TestData.ContractId); - Should.Throw(() => - { - aggregate.Create(TestData.EstateId, Guid.Empty, TestData.ContractDescription); - }); + Result result = aggregate.Create(TestData.EstateId, Guid.Empty, TestData.ContractDescription); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); + result.Message.ShouldContain("Operator Id must not be an empty Guid"); } [Theory] @@ -56,10 +58,10 @@ public void ContractAggregate_Create_InvalidDescription_ErrorThrown(String descr { ContractAggregate aggregate = ContractAggregate.Create(TestData.ContractId); - Should.Throw(() => - { - aggregate.Create(TestData.EstateId, TestData.OperatorId, description); - }); + Result result = aggregate.Create(TestData.EstateId, TestData.OperatorId, description); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); + result.Message.ShouldContain("Contract description must not be null or empty"); } [Fact] @@ -68,12 +70,13 @@ public void ContractAggregate_AddFixedValueProduct_ProductAdded() ContractAggregate aggregate = ContractAggregate.Create(TestData.ContractId); aggregate.Create(TestData.EstateId, TestData.OperatorId, TestData.ContractDescription); - aggregate.AddFixedValueProduct(TestData.FixedContractProductId, + Result result = aggregate.AddFixedValueProduct(TestData.FixedContractProductId, TestData.ProductName, TestData.ProductDisplayText, TestData.ProductFixedValue, TestData.ProductTypeMobileTopup); - + result.IsSuccess.ShouldBeTrue(); + List products = aggregate.GetProducts(); products.Count.ShouldBe(1); Product product= products.Single(); @@ -86,19 +89,38 @@ public void ContractAggregate_AddFixedValueProduct_ProductAdded() } [Fact] - public void ContractAggregate_AddFixedValueProduct_DuplicateProduct_ErrorThrown() + public void ContractAggregate_AddFixedValueProduct_DuplicateProduct_NoErrorThrown() { ContractAggregate aggregate = ContractAggregate.Create(TestData.ContractId); aggregate.Create(TestData.EstateId, TestData.OperatorId, TestData.ContractDescription); aggregate.AddFixedValueProduct(TestData.FixedContractProductId, TestData.ProductName, TestData.ProductDisplayText, TestData.ProductFixedValue, TestData.ProductTypeMobileTopup); + List products = aggregate.GetProducts(); + products.Count.ShouldBe(1); + + Result result = aggregate.AddFixedValueProduct(TestData.FixedContractProductId, TestData.ProductName, TestData.ProductDisplayText, TestData.ProductFixedValue, TestData.ProductTypeMobileTopup); + result.IsSuccess.ShouldBeTrue(); + products = aggregate.GetProducts(); + products.Count.ShouldBe(1); + } - Should.Throw(() => - { - aggregate.AddFixedValueProduct(TestData.FixedContractProductId, TestData.ProductName, TestData.ProductDisplayText, TestData.ProductFixedValue, TestData.ProductTypeMobileTopup); - }); + [Fact] + public void ContractAggregate_AddFixedValueProduct_InvalidProductId_ErrorThrown() + { + ContractAggregate aggregate = ContractAggregate.Create(TestData.ContractId); + aggregate.Create(TestData.EstateId, TestData.OperatorId, TestData.ContractDescription); + + Result result = aggregate.AddFixedValueProduct(Guid.Empty, + TestData.ProductName, + TestData.ProductDisplayText, + TestData.ProductFixedValue, + TestData.ProductTypeMobileTopup); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); + result.Message.ShouldContain("Product Id must not be an empty Guid"); } + [Theory] [InlineData(null)] [InlineData("")] @@ -107,10 +129,10 @@ public void ContractAggregate_AddFixedValueProduct_InvalidProductName_ErrorThrow ContractAggregate aggregate = ContractAggregate.Create(TestData.ContractId); aggregate.Create(TestData.EstateId, TestData.OperatorId, TestData.ContractDescription); - Should.Throw(() => - { - aggregate.AddFixedValueProduct(TestData.FixedContractProductId, productName, TestData.ProductDisplayText, TestData.ProductFixedValue, TestData.ProductTypeMobileTopup); - }); + Result result = aggregate.AddFixedValueProduct(TestData.FixedContractProductId, productName, TestData.ProductDisplayText, TestData.ProductFixedValue, TestData.ProductTypeMobileTopup); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); + result.Message.ShouldContain("Product Name must not be null or empty"); } [Theory] @@ -121,10 +143,10 @@ public void ContractAggregate_AddFixedValueProduct_InvalidProductDisplayText_Err ContractAggregate aggregate = ContractAggregate.Create(TestData.ContractId); aggregate.Create(TestData.EstateId, TestData.OperatorId, TestData.ContractDescription); - Should.Throw(() => - { - aggregate.AddFixedValueProduct(TestData.FixedContractProductId, TestData.ProductName, displayText, TestData.ProductFixedValue,TestData.ProductTypeMobileTopup); - }); + Result result = aggregate.AddFixedValueProduct(TestData.FixedContractProductId, TestData.ProductName, displayText, TestData.ProductFixedValue,TestData.ProductTypeMobileTopup); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); + result.Message.ShouldContain("Product Display Text must not be null or empty"); } [Theory] @@ -135,10 +157,10 @@ public void ContractAggregate_AddFixedValueProduct_InvalidProductValue_ErrorThro ContractAggregate aggregate = ContractAggregate.Create(TestData.ContractId); aggregate.Create(TestData.EstateId, TestData.OperatorId, TestData.ContractDescription); - Should.Throw(() => - { - aggregate.AddFixedValueProduct(TestData.FixedContractProductId, TestData.ProductName, TestData.ProductDisplayText, value, TestData.ProductTypeMobileTopup); - }); + Result result = aggregate.AddFixedValueProduct(TestData.FixedContractProductId, TestData.ProductName, TestData.ProductDisplayText, value, TestData.ProductTypeMobileTopup); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); + result.Message.ShouldContain("Product value must not be zero or negative"); } [Fact] @@ -147,8 +169,9 @@ public void ContractAggregate_AddVariableValueProduct_ProductAdded() ContractAggregate aggregate = ContractAggregate.Create(TestData.ContractId); aggregate.Create(TestData.EstateId, TestData.OperatorId, TestData.ContractDescription); - aggregate.AddVariableValueProduct(TestData.VariableContractProductId, TestData.ProductName, TestData.ProductDisplayText, TestData.ProductTypeMobileTopup); - + Result result = aggregate.AddVariableValueProduct(TestData.VariableContractProductId, TestData.ProductName, TestData.ProductDisplayText, TestData.ProductTypeMobileTopup); + result.IsSuccess.ShouldBeTrue(); + List products = aggregate.GetProducts(); products.Count.ShouldBe(1); Product product = products.Single(); @@ -167,11 +190,28 @@ public void ContractAggregate_AddVariableValueProduct_DuplicateProduct_ErrorThro aggregate.Create(TestData.EstateId, TestData.OperatorId, TestData.ContractDescription); aggregate.AddVariableValueProduct(TestData.VariableContractProductId, TestData.ProductName, TestData.ProductDisplayText, TestData.ProductTypeMobileTopup); + List products = aggregate.GetProducts(); + products.Count.ShouldBe(1); + + Result result = aggregate.AddVariableValueProduct(TestData.VariableContractProductId, TestData.ProductName, TestData.ProductDisplayText, TestData.ProductTypeMobileTopup); + result.IsSuccess.ShouldBeTrue(); + products = aggregate.GetProducts(); + products.Count.ShouldBe(1); + } + + [Fact] + public void ContractAggregate_AddVariableValueProduct_InvalidProductId_ErrorThrown() + { + ContractAggregate aggregate = ContractAggregate.Create(TestData.ContractId); + aggregate.Create(TestData.EstateId, TestData.OperatorId, TestData.ContractDescription); - Should.Throw(() => - { - aggregate.AddVariableValueProduct(TestData.VariableContractProductId, TestData.ProductName, TestData.ProductDisplayText, TestData.ProductTypeMobileTopup); - }); + Result result = aggregate.AddVariableValueProduct(Guid.Empty, + TestData.ProductName, + TestData.ProductDisplayText, + TestData.ProductTypeMobileTopup); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); + result.Message.ShouldContain("Product Id must not be an empty Guid"); } [Theory] @@ -182,10 +222,10 @@ public void ContractAggregate_AddVariableValueProduct_InvalidProductName_ErrorTh ContractAggregate aggregate = ContractAggregate.Create(TestData.ContractId); aggregate.Create(TestData.EstateId, TestData.OperatorId, TestData.ContractDescription); - Should.Throw(() => - { - aggregate.AddVariableValueProduct(TestData.VariableContractProductId, productName, TestData.ProductDisplayText, TestData.ProductTypeMobileTopup); - }); + Result result = aggregate.AddVariableValueProduct(TestData.VariableContractProductId, productName, TestData.ProductDisplayText, TestData.ProductTypeMobileTopup); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); + result.Message.ShouldContain("Product Name must not be null or empty"); } [Theory] @@ -196,10 +236,10 @@ public void ContractAggregate_AddVariableValueProduct_InvalidProductDisplayText_ ContractAggregate aggregate = ContractAggregate.Create(TestData.ContractId); aggregate.Create(TestData.EstateId, TestData.OperatorId, TestData.ContractDescription); - Should.Throw(() => - { - aggregate.AddVariableValueProduct(TestData.VariableContractProductId, TestData.ProductName, displayText, TestData.ProductTypeMobileTopup); - }); + Result result = aggregate.AddVariableValueProduct(TestData.VariableContractProductId, TestData.ProductName, displayText, TestData.ProductTypeMobileTopup); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); + result.Message.ShouldContain("Product Display Text must not be null or empty"); } [Fact] @@ -230,7 +270,8 @@ public void ContractAggregate_AddTransactionFee_FixedValueProduct_TransactionFee List products = aggregate.GetProducts(); Product product = products.Single(); - aggregate.AddTransactionFee(product, TestData.TransactionFeeId, TestData.TransactionFeeDescription, calculationType, feeType, TestData.TransactionFeeValue); + Result result = aggregate.AddTransactionFee(product, TestData.TransactionFeeId, TestData.TransactionFeeDescription, calculationType, feeType, TestData.TransactionFeeValue); + result.IsSuccess.ShouldBeTrue(); List productsAfterFeeAdded = aggregate.GetProducts(); Product productWithFees = productsAfterFeeAdded.Single(); @@ -258,10 +299,9 @@ public void ContractAggregate_AddTransactionFee_FixedValueProduct_InvalidFeeId_E List products = aggregate.GetProducts(); Product product = products.Single(); - Should.Throw(() => - { - aggregate.AddTransactionFee(product, Guid.Empty, TestData.TransactionFeeDescription, calculationType, feeType, TestData.TransactionFeeValue); - }); + var result = aggregate.AddTransactionFee(product, Guid.Empty, TestData.TransactionFeeDescription, calculationType, feeType, TestData.TransactionFeeValue); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); } [Theory] @@ -282,10 +322,9 @@ public void ContractAggregate_AddTransactionFee_FixedValueProduct_InvalidFeeDesc List products = aggregate.GetProducts(); Product product = products.Single(); - Should.Throw(() => - { - aggregate.AddTransactionFee(product, TestData.TransactionFeeId, feeDescription, calculationType, feeType, TestData.TransactionFeeValue); - }); + var result = aggregate.AddTransactionFee(product, TestData.TransactionFeeId, feeDescription, calculationType, feeType, TestData.TransactionFeeValue); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); } [Theory] @@ -302,7 +341,8 @@ public void ContractAggregate_AddTransactionFee_VariableValueProduct_Transaction List products = aggregate.GetProducts(); Product product = products.Single(); - aggregate.AddTransactionFee(product, TestData.TransactionFeeId, TestData.TransactionFeeDescription, calculationType, feeType, TestData.TransactionFeeValue); + var result = aggregate.AddTransactionFee(product, TestData.TransactionFeeId, TestData.TransactionFeeDescription, calculationType, feeType, TestData.TransactionFeeValue); + result.IsSuccess.ShouldBeTrue(); List productsAfterFeeAdded = aggregate.GetProducts(); Product productWithFees = productsAfterFeeAdded.Single(); @@ -330,10 +370,9 @@ public void ContractAggregate_AddTransactionFee_VariableValueProduct_InvalidFeeI List products = aggregate.GetProducts(); Product product = products.Single(); - Should.Throw(() => - { - aggregate.AddTransactionFee(product, Guid.Empty, TestData.TransactionFeeDescription, calculationType, feeType, TestData.TransactionFeeValue); - }); + var result = aggregate.AddTransactionFee(product, Guid.Empty, TestData.TransactionFeeDescription, calculationType, feeType, TestData.TransactionFeeValue); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); } [Theory] @@ -354,10 +393,9 @@ public void ContractAggregate_AddTransactionFee_VariableValueProduct_InvalidFeeD List products = aggregate.GetProducts(); Product product = products.Single(); - Should.Throw(() => - { - aggregate.AddTransactionFee(product, TestData.TransactionFeeId, feeDescription, calculationType, feeType, TestData.TransactionFeeValue); - }); + var result = aggregate.AddTransactionFee(product, TestData.TransactionFeeId, feeDescription, calculationType, feeType, TestData.TransactionFeeValue); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); } [Theory] @@ -370,10 +408,9 @@ public void ContractAggregate_AddTransactionFee_NullProduct_ErrorThrown(Calculat ContractAggregate aggregate = ContractAggregate.Create(TestData.ContractId); aggregate.Create(TestData.EstateId, TestData.OperatorId, TestData.ContractDescription); - Should.Throw(() => - { - aggregate.AddTransactionFee(null, TestData.TransactionFeeId, TestData.TransactionFeeDescription, calculationType, feeType, TestData.TransactionFeeValue); - }); + var result = aggregate.AddTransactionFee(null, TestData.TransactionFeeId, TestData.TransactionFeeDescription, calculationType, feeType, TestData.TransactionFeeValue); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); } [Theory] @@ -387,10 +424,9 @@ public void ContractAggregate_AddTransactionFee_ProductNotFound_ErrorThrown(Calc aggregate.Create(TestData.EstateId, TestData.OperatorId, TestData.ContractDescription); aggregate.AddFixedValueProduct(TestData.FixedContractProductId,TestData.ProductName, TestData.ProductDisplayText, TestData.ProductFixedValue, TestData.ProductTypeMobileTopup); - Should.Throw(() => - { - aggregate.AddTransactionFee(new Product(), TestData.TransactionFeeId, TestData.TransactionFeeDescription, calculationType, feeType,TestData.TransactionFeeValue); - }); + var result = aggregate.AddTransactionFee(new Product(), TestData.TransactionFeeId, TestData.TransactionFeeDescription, calculationType, feeType,TestData.TransactionFeeValue); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); } [Theory] @@ -405,10 +441,9 @@ public void ContractAggregate_AddTransactionFee_FixedValueProduct_InvalidCalcula List products = aggregate.GetProducts(); Product product = products.Single(); - Should.Throw(() => - { - aggregate.AddTransactionFee(product, TestData.TransactionFeeId, TestData.TransactionFeeDescription, (CalculationType)99, feeType, TestData.TransactionFeeValue); - }); + var result = aggregate.AddTransactionFee(product, TestData.TransactionFeeId, TestData.TransactionFeeDescription, (CalculationType)99, feeType, TestData.TransactionFeeValue); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); } [Theory] @@ -423,10 +458,9 @@ public void ContractAggregate_AddTransactionFee_FixedValueProduct_InvalidFeeType List products = aggregate.GetProducts(); Product product = products.Single(); - Should.Throw(() => - { - aggregate.AddTransactionFee(product, TestData.TransactionFeeId, TestData.TransactionFeeDescription, calculationType, (FeeType)99, TestData.TransactionFeeValue); - }); + var result = aggregate.AddTransactionFee(product, TestData.TransactionFeeId, TestData.TransactionFeeDescription, calculationType, (FeeType)99, TestData.TransactionFeeValue); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); } [Theory] @@ -447,10 +481,9 @@ public void ContractAggregate_AddTransactionFee_VariableValueProduct_InvalidFeeV List products = aggregate.GetProducts(); Product product = products.Single(); - Should.Throw(() => - { - aggregate.AddTransactionFee(product, TestData.TransactionFeeId, TestData.TransactionFeeDescription, calculationType, feeType, feeValue); - }); + var result = aggregate.AddTransactionFee(product, TestData.TransactionFeeId, TestData.TransactionFeeDescription, calculationType, feeType, feeValue); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); } [Theory] @@ -471,10 +504,10 @@ public void ContractAggregate_AddTransactionFee_FixedValueProduct_InvalidFeeValu List products = aggregate.GetProducts(); Product product = products.Single(); - Should.Throw(() => - { - aggregate.AddTransactionFee(product, TestData.TransactionFeeId, TestData.TransactionFeeDescription, calculationType,feeType, feeValue); - }); + var result = aggregate.AddTransactionFee(product, TestData.TransactionFeeId, TestData.TransactionFeeDescription, calculationType,feeType, feeValue); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); + } [Theory] @@ -489,10 +522,9 @@ public void ContractAggregate_AddTransactionFee_VariableValueProduct_InvalidCalc List products = aggregate.GetProducts(); Product product = products.Single(); - Should.Throw(() => - { - aggregate.AddTransactionFee(product, TestData.TransactionFeeId, TestData.TransactionFeeDescription, (CalculationType)99, feeType, TestData.TransactionFeeValue); - }); + var result = aggregate.AddTransactionFee(product, TestData.TransactionFeeId, TestData.TransactionFeeDescription, (CalculationType)99, feeType, TestData.TransactionFeeValue); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); } [Theory] @@ -507,10 +539,9 @@ public void ContractAggregate_AddTransactionFee_VariableValueProduct_InvalidFeeT List products = aggregate.GetProducts(); Product product = products.Single(); - Should.Throw(() => - { - aggregate.AddTransactionFee(product, TestData.TransactionFeeId, TestData.TransactionFeeDescription, calculationType,(FeeType)99, TestData.TransactionFeeValue); - }); + var result = aggregate.AddTransactionFee(product, TestData.TransactionFeeId, TestData.TransactionFeeDescription, calculationType,(FeeType)99, TestData.TransactionFeeValue); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); } [Theory] @@ -535,7 +566,8 @@ public void ContractAggregate_DisableTransactionFee_TransactionFeeIsDisabled(Cal ContractProductTransactionFee? fee = productWithFees.TransactionFees.Single(); fee.IsEnabled.ShouldBeTrue(); - aggregate.DisableTransactionFee(TestData.VariableContractProductId, TestData.TransactionFeeId); + Result result = aggregate.DisableTransactionFee(TestData.VariableContractProductId, TestData.TransactionFeeId); + result.IsSuccess.ShouldBeTrue(); productsAfterFeeAdded = aggregate.GetProducts(); productWithFees = productsAfterFeeAdded.Single(); @@ -545,15 +577,14 @@ public void ContractAggregate_DisableTransactionFee_TransactionFeeIsDisabled(Cal } [Fact] - public void ContractAggregate_DisableTransactionFee_ProductNotFound_ErrorThrown() - { + public void ContractAggregate_DisableTransactionFee_ProductNotFound_ErrorThrown() { ContractAggregate aggregate = ContractAggregate.Create(TestData.ContractId); aggregate.Create(TestData.EstateId, TestData.OperatorId, TestData.ContractDescription); - Should.Throw(() => - { - aggregate.DisableTransactionFee(TestData.VariableContractProductId, TestData.TransactionFeeId); - }); + Result result = aggregate.DisableTransactionFee(TestData.VariableContractProductId, TestData.TransactionFeeId); + + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); } [Fact] @@ -563,10 +594,9 @@ public void ContractAggregate_DisableTransactionFee_TransactionFeeNotFound_Error aggregate.Create(TestData.EstateId, TestData.OperatorId, TestData.ContractDescription); aggregate.AddVariableValueProduct(TestData.VariableContractProductId, TestData.ProductName, TestData.ProductDisplayText, TestData.ProductTypeMobileTopup); - Should.Throw(() => - { - aggregate.DisableTransactionFee(TestData.VariableContractProductId, TestData.TransactionFeeId); - }); + Result result = aggregate.DisableTransactionFee(TestData.VariableContractProductId, TestData.TransactionFeeId); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); } } } diff --git a/TransactionProcessor.Aggregates/ContractAggregate.cs b/TransactionProcessor.Aggregates/ContractAggregate.cs index 8da483a..22cf872 100644 --- a/TransactionProcessor.Aggregates/ContractAggregate.cs +++ b/TransactionProcessor.Aggregates/ContractAggregate.cs @@ -1,113 +1,140 @@ -using System.Diagnostics.CodeAnalysis; -using Shared.DomainDrivenDesign.EventSourcing; +using Shared.DomainDrivenDesign.EventSourcing; using Shared.EventStore.Aggregate; using Shared.General; +using SimpleResults; +using System.Diagnostics.CodeAnalysis; using TransactionProcessor.DomainEvents; using TransactionProcessor.Models.Contract; +using static Google.Protobuf.Reflection.FeatureSet.Types; namespace TransactionProcessor.Aggregates{ public static class ContractAggregateExtensions{ #region Methods - public static void AddFixedValueProduct(this ContractAggregate aggregate, + public static Result AddFixedValueProduct(this ContractAggregate aggregate, Guid productId, String productName, String displayText, Decimal value, ProductType productType){ - Guard.ThrowIfInvalidGuid(productId, typeof(ArgumentNullException), "Product Id cannot be an empty Guid"); - Guard.ThrowIfNullOrEmpty(productName, typeof(ArgumentNullException), "Product Name must not be null or empty"); - Guard.ThrowIfNullOrEmpty(displayText, typeof(ArgumentNullException), "Product Display Text must not be null or empty"); - Guard.ThrowIfZero(value, typeof(ArgumentOutOfRangeException), "Product value must not be zero"); - Guard.ThrowIfNegative(value, typeof(ArgumentOutOfRangeException), "Product value must not be negative"); - + if (productId == Guid.Empty) + return Result.Invalid("Product Id must not be an empty Guid"); + if (String.IsNullOrEmpty(productName)) + return Result.Invalid("Product Name must not be null or empty"); + if (String.IsNullOrEmpty(displayText)) + return Result.Invalid("Product Display Text must not be null or empty"); + if (value <= 0) + return Result.Invalid("Product value must not be zero or negative"); + // Check product not already added if (aggregate.Products.Any(p => p.Name == productName)){ - throw new InvalidOperationException($"Product Name {productName} has already been added to the contract"); + return Result.Success(); } ContractDomainEvents.FixedValueProductAddedToContractEvent fixedValueProductAddedToContractEvent = new(aggregate.AggregateId, aggregate.EstateId, productId, productName, displayText, value, (Int32)productType); aggregate.ApplyAndAppend(fixedValueProductAddedToContractEvent); + + return Result.Success(); } - public static void AddTransactionFee(this ContractAggregate aggregate, + public static Result AddTransactionFee(this ContractAggregate aggregate, Product product, Guid transactionFeeId, String description, CalculationType calculationType, FeeType feeType, Decimal value){ - Guard.ThrowIfInvalidGuid(transactionFeeId, typeof(ArgumentNullException), "Transaction Fee Id cannot be an empty Guid"); - Guard.ThrowIfNull(product, typeof(ArgumentNullException), "Product to add fee for cannot be null"); - Guard.ThrowIfNullOrEmpty(description, typeof(ArgumentNullException), "Transaction Fee description must not be null or empty"); - Guard.ThrowIfZero(value, typeof(ArgumentOutOfRangeException), "Transaction Fee value cannot be zero"); - Guard.ThrowIfNegative(value, typeof(ArgumentOutOfRangeException), "Transaction Fee value cannot be negative"); - + if (transactionFeeId == Guid.Empty) + return Result.Invalid("Transaction Fee Id cannot be an empty Guid"); + if (product == null) + return Result.Invalid("Product to add fee for cannot be null"); + if (String.IsNullOrEmpty(description)) + return Result.Invalid("Transaction Fee description must not be null or empty"); + if (value <= 0) + return Result.Invalid("Transaction Fee value must not be zero or negative"); + if (aggregate.Products.Any(p => p.ContractProductId == product.ContractProductId) == false){ - throw new InvalidOperationException($"Product Id {product.ContractProductId} is not a valid product on this contract"); + return Result.Invalid($"Product Id {product.ContractProductId} is not a valid product on this contract"); } - - Guard.ThrowIfInvalidEnum(typeof(CalculationType), calculationType, nameof(calculationType)); - Guard.ThrowIfInvalidEnum(typeof(FeeType), feeType, nameof(feeType)); - + if (Enum.IsDefined(typeof(CalculationType), calculationType) == false) + return Result.Invalid("Calculation Type not valid"); + if (Enum.IsDefined(typeof(FeeType), feeType) == false) + return Result.Invalid("Fee Type not valid"); + ContractDomainEvents.TransactionFeeForProductAddedToContractEvent transactionFeeForProductAddedToContractEvent = - new ContractDomainEvents.TransactionFeeForProductAddedToContractEvent(aggregate.AggregateId, aggregate.EstateId, product.ContractProductId, transactionFeeId, description, (Int32)calculationType, (Int32)feeType, value); + new(aggregate.AggregateId, aggregate.EstateId, product.ContractProductId, transactionFeeId, description, (Int32)calculationType, (Int32)feeType, value); aggregate.ApplyAndAppend(transactionFeeForProductAddedToContractEvent); + + return Result.Success(); } - public static void AddVariableValueProduct(this ContractAggregate aggregate, + public static Result AddVariableValueProduct(this ContractAggregate aggregate, Guid productId, String productName, String displayText, ProductType productType){ - Guard.ThrowIfNullOrEmpty(productName, typeof(ArgumentNullException), "Product Name must not be null or empty"); - Guard.ThrowIfNullOrEmpty(displayText, typeof(ArgumentNullException), "Product Display Text must not be null or empty"); + if (productId == Guid.Empty) + return Result.Invalid("Product Id must not be an empty Guid"); + if (String.IsNullOrEmpty(productName)) + return Result.Invalid("Product Name must not be null or empty"); + if (String.IsNullOrEmpty(displayText)) + return Result.Invalid("Product Display Text must not be null or empty"); // Check product not already added if (aggregate.Products.Any(p => p.Name == productName)){ - throw new InvalidOperationException($"Product Name {productName} has already been added to the contract"); + return Result.Success(); } ContractDomainEvents.VariableValueProductAddedToContractEvent variableValueProductAddedToContractEvent = new(aggregate.AggregateId, aggregate.EstateId, productId, productName, displayText, (Int32)productType); aggregate.ApplyAndAppend(variableValueProductAddedToContractEvent); + + return Result.Success(); } - public static void Create(this ContractAggregate aggregate, + public static Result Create(this ContractAggregate aggregate, Guid estateId, Guid operatorId, String description){ - Guard.ThrowIfInvalidGuid(estateId, typeof(ArgumentNullException), "Estate Id must not be an empty Guid"); - Guard.ThrowIfInvalidGuid(operatorId, typeof(ArgumentNullException), "Operator Id must not be an empty Guid"); - Guard.ThrowIfNullOrEmpty(description, typeof(ArgumentNullException), "Contract description must not be null or empty"); - - ContractDomainEvents.ContractCreatedEvent contractCreatedEvent = new ContractDomainEvents.ContractCreatedEvent(aggregate.AggregateId, estateId, operatorId, description); + + if(estateId == Guid.Empty) + return Result.Invalid("Estate Id must not be an empty Guid"); + if (operatorId == Guid.Empty) + return Result.Invalid("Operator Id must not be an empty Guid"); + if (String.IsNullOrEmpty(description)) + return Result.Invalid("Contract description must not be null or empty"); + + ContractDomainEvents.ContractCreatedEvent contractCreatedEvent = new(aggregate.AggregateId, estateId, operatorId, description); aggregate.ApplyAndAppend(contractCreatedEvent); + + return Result.Success(); } - public static void DisableTransactionFee(this ContractAggregate aggregate, + public static Result DisableTransactionFee(this ContractAggregate aggregate, Guid productId, Guid transactionFeeId){ if (aggregate.Products.Any(p => p.ContractProductId == productId) == false){ - throw new InvalidOperationException($"Product Id {productId} is not a valid product on this contract"); + return Result.Invalid($"Product Id {productId} is not a valid product on this contract"); } Product product = aggregate.Products.Single(p => p.ContractProductId == productId); if (product.TransactionFees.Any(f => f.TransactionFeeId == transactionFeeId) == false){ - throw new InvalidOperationException($"Transaction Fee Id {transactionFeeId} is not a valid for product {product.Name} on this contract"); + return Result.Invalid($"Transaction Fee Id {transactionFeeId} is not a valid for product {product.Name} on this contract"); } - ContractDomainEvents.TransactionFeeForProductDisabledEvent transactionFeeForProductDisabledEvent = new ContractDomainEvents.TransactionFeeForProductDisabledEvent(aggregate.AggregateId, - aggregate.EstateId, - productId, - transactionFeeId); + ContractDomainEvents.TransactionFeeForProductDisabledEvent transactionFeeForProductDisabledEvent = new(aggregate.AggregateId, + aggregate.EstateId, + productId, + transactionFeeId); aggregate.ApplyAndAppend(transactionFeeForProductDisabledEvent); + + return Result.Success(); } /// diff --git a/TransactionProcessor.BusinessLogic/Services/ContractDomainService.cs b/TransactionProcessor.BusinessLogic/Services/ContractDomainService.cs index 8a537ca..75d5f11 100644 --- a/TransactionProcessor.BusinessLogic/Services/ContractDomainService.cs +++ b/TransactionProcessor.BusinessLogic/Services/ContractDomainService.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net.WebSockets; using System.Threading; using System.Threading.Tasks; using Newtonsoft.Json.Linq; @@ -68,14 +69,12 @@ public async Task AddProductToContract(ContractCommands.AddProductToCont return Result.Forbidden($"Contract Id [{command.ContractId}] must be created to add products"); } - if (command.RequestDTO.Value.HasValue) { - contractAggregate.AddFixedValueProduct(command.ProductId, command.RequestDTO.ProductName, - command.RequestDTO.DisplayText, command.RequestDTO.Value.Value, productType); - } - else { - contractAggregate.AddVariableValueProduct(command.ProductId, command.RequestDTO.ProductName, - command.RequestDTO.DisplayText, productType); - } + Result stateResult = command.RequestDTO.Value.HasValue switch { + true => contractAggregate.AddFixedValueProduct(command.ProductId, command.RequestDTO.ProductName, command.RequestDTO.DisplayText, command.RequestDTO.Value.Value, productType), + _ => contractAggregate.AddVariableValueProduct(command.ProductId, command.RequestDTO.ProductName, command.RequestDTO.DisplayText, productType) + }; + if (stateResult.IsFailed) + return ResultHelpers.CreateFailure(stateResult); Result saveResult = await this.AggregateService.Save(contractAggregate, cancellationToken); if (saveResult.IsFailed) @@ -113,7 +112,9 @@ public async Task AddTransactionFeeForProductToContract(ContractCommands throw new InvalidOperationException($"Product Id [{command.ProductId}] not added to contract [{contractAggregate.Description}]"); } - contractAggregate.AddTransactionFee(product, command.TransactionFeeId, command.RequestDTO.Description, calculationType, feeType, command.RequestDTO.Value); + Result stateResult = contractAggregate.AddTransactionFee(product, command.TransactionFeeId, command.RequestDTO.Description, calculationType, feeType, command.RequestDTO.Value); + if (stateResult.IsFailed) + return ResultHelpers.CreateFailure(stateResult); Result saveResult = await this.AggregateService.Save(contractAggregate, cancellationToken); if (saveResult.IsFailed) @@ -138,8 +139,10 @@ public async Task DisableTransactionFeeForProduct(ContractCommands.Disab ContractAggregate contractAggregate = contractResult.Data; - contractAggregate.DisableTransactionFee(command.ProductId, command.TransactionFeeId); - + Result stateResult = contractAggregate.DisableTransactionFee(command.ProductId, command.TransactionFeeId); + if (stateResult.IsFailed) + return ResultHelpers.CreateFailure(stateResult); + Result saveResult = await this.AggregateService.Save(contractAggregate, cancellationToken); if (saveResult.IsFailed) return ResultHelpers.CreateFailure(saveResult); @@ -200,7 +203,9 @@ public async Task CreateContract(ContractCommands.CreateContractCommand { return Result.Forbidden($"Contract Id [{command.ContractId}] already created for estate [{estate.Name}]"); } - contractAggregate.Create(command.EstateId, command.RequestDTO.OperatorId, command.RequestDTO.Description); + Result stateResult = contractAggregate.Create(command.EstateId, command.RequestDTO.OperatorId, command.RequestDTO.Description); + if (stateResult.IsFailed) + return ResultHelpers.CreateFailure(stateResult); Result saveResult = await this.AggregateService.Save(contractAggregate, cancellationToken); if (saveResult.IsFailed)