From 15f226748d35abc749e1e53424e99eb30948def2 Mon Sep 17 00:00:00 2001 From: StuartFerguson Date: Tue, 2 Sep 2025 19:48:08 +0100 Subject: [PATCH] operator aggregate returns results --- .../OperatorAggregateTests.cs | 68 ++++++++++++++++--- .../OperatorAggregate.cs | 19 ++++-- .../Services/OperatorDomainService.cs | 8 ++- 3 files changed, 79 insertions(+), 16 deletions(-) diff --git a/TransactionProcessor.Aggregates.Tests/OperatorAggregateTests.cs b/TransactionProcessor.Aggregates.Tests/OperatorAggregateTests.cs index fbe56f11..9227b289 100644 --- a/TransactionProcessor.Aggregates.Tests/OperatorAggregateTests.cs +++ b/TransactionProcessor.Aggregates.Tests/OperatorAggregateTests.cs @@ -1,4 +1,5 @@ using Shouldly; +using SimpleResults; using TransactionProcessor.Testing; namespace TransactionProcessor.Aggregates.Tests @@ -23,7 +24,8 @@ public void OperatorAggregate_CanBeCreated_IsCreated() public void OperatorAggregate_Create_IsCreated() { OperatorAggregate aggregate = OperatorAggregate.Create(TestData.OperatorId); - aggregate.Create(TestData.EstateId, TestData.OperatorName, TestData.RequireCustomMerchantNumber, TestData.RequireCustomTerminalNumber); + var result = aggregate.Create(TestData.EstateId, TestData.OperatorName, TestData.RequireCustomMerchantNumber, TestData.RequireCustomTerminalNumber); + result.IsSuccess.ShouldBeTrue(); aggregate.AggregateId.ShouldBe(TestData.OperatorId); aggregate.Name.ShouldBe(TestData.OperatorName); @@ -33,11 +35,34 @@ public void OperatorAggregate_Create_IsCreated() aggregate.RequireCustomMerchantNumber.ShouldBe(TestData.RequireCustomMerchantNumber); } + [Fact] + public void OperatorAggregate_Create_EstateIdEmpty_ErrorReturned() + { + OperatorAggregate aggregate = OperatorAggregate.Create(TestData.OperatorId); + var result = aggregate.Create(Guid.Empty, TestData.OperatorName, TestData.RequireCustomMerchantNumber, TestData.RequireCustomTerminalNumber); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); + result.Message.ShouldBe("Estate Id must not be an empty Guid"); + } + + [Theory] + [InlineData(null)] + [InlineData("")] + public void OperatorAggregate_Create_NameInvalid_ErrorReturned(String operatorName) + { + OperatorAggregate aggregate = OperatorAggregate.Create(TestData.OperatorId); + var result = aggregate.Create(TestData.EstateId, operatorName, TestData.RequireCustomMerchantNumber, TestData.RequireCustomTerminalNumber); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); + result.Message.ShouldBe("Operator name must not be null or empty"); + } + [Fact] public void OperatorAggregate_GetOperator_OperatorIsReturned() { OperatorAggregate aggregate = OperatorAggregate.Create(TestData.OperatorId); aggregate.Create(TestData.EstateId, TestData.OperatorName, TestData.RequireCustomMerchantNumber, TestData.RequireCustomTerminalNumber); + TransactionProcessor.Models.Operator.Operator @operator = aggregate.GetOperator(); @operator.OperatorId.ShouldBe(TestData.OperatorId); @operator.Name.ShouldBe(TestData.OperatorName); @@ -45,21 +70,44 @@ public void OperatorAggregate_GetOperator_OperatorIsReturned() @operator.RequireCustomMerchantNumber.ShouldBe(TestData.RequireCustomMerchantNumber); } + [Theory] + [InlineData("Alice", "Bob", "Bob")] + [InlineData("alice", "Alice", "alice")] + [InlineData("Alice", null, "Alice")] + [InlineData("Alice", "", "Alice")] + public void OperatorAggregate_UpdateOperator_OperatorName_IsUpdated(String existingName, String newName, String expectedName) + { + OperatorAggregate aggregate = OperatorAggregate.Create(TestData.OperatorId); + aggregate.Create(TestData.EstateId, existingName, TestData.RequireCustomMerchantNumberTrue, TestData.RequireCustomTerminalNumberTrue); + + Result result = aggregate.UpdateOperator(newName, TestData.RequireCustomMerchantNumberTrue, TestData.RequireCustomTerminalNumberTrue); + result.IsSuccess.ShouldBeTrue(); + + aggregate.Name.ShouldBe(expectedName); + } + [Fact] - public void OperatorAggregate_UpdateOperator_IsUpdated() + public void OperatorAggregate_UpdateOperator_RequireCustomMerchantNumber_IsUpdated() { OperatorAggregate aggregate = OperatorAggregate.Create(TestData.OperatorId); - aggregate.Create(TestData.EstateId, TestData.OperatorName, TestData.RequireCustomMerchantNumberFalse, TestData.RequireCustomTerminalNumberFalse); + aggregate.Create(TestData.EstateId, TestData.OperatorName, TestData.RequireCustomMerchantNumberTrue, TestData.RequireCustomTerminalNumberTrue); - aggregate.Name.ShouldBe(TestData.OperatorName); - aggregate.RequireCustomTerminalNumber.ShouldBe(TestData.RequireCustomMerchantNumberFalse); - aggregate.RequireCustomMerchantNumber.ShouldBe(TestData.RequireCustomTerminalNumberFalse); + Result result = aggregate.UpdateOperator(TestData.OperatorName, TestData.RequireCustomMerchantNumberFalse, TestData.RequireCustomTerminalNumberTrue); + result.IsSuccess.ShouldBeTrue(); + + aggregate.RequireCustomMerchantNumber.ShouldBe(TestData.RequireCustomMerchantNumberFalse); + } + + [Fact] + public void OperatorAggregate_UpdateOperator_RequireCustomTerminalNumber_IsUpdated() + { + OperatorAggregate aggregate = OperatorAggregate.Create(TestData.OperatorId); + aggregate.Create(TestData.EstateId, TestData.OperatorName, TestData.RequireCustomMerchantNumberTrue, TestData.RequireCustomTerminalNumberTrue); - aggregate.UpdateOperator(TestData.OperatorName2, TestData.RequireCustomMerchantNumberTrue, TestData.RequireCustomTerminalNumberTrue); + Result result = aggregate.UpdateOperator(TestData.OperatorName, TestData.RequireCustomMerchantNumberTrue, TestData.RequireCustomTerminalNumberFalse); + result.IsSuccess.ShouldBeTrue(); - aggregate.Name.ShouldBe(TestData.OperatorName2); - aggregate.RequireCustomTerminalNumber.ShouldBe(TestData.RequireCustomMerchantNumberTrue); - aggregate.RequireCustomMerchantNumber.ShouldBe(TestData.RequireCustomTerminalNumberTrue); + aggregate.RequireCustomTerminalNumber.ShouldBe(TestData.RequireCustomTerminalNumberFalse); } } } diff --git a/TransactionProcessor.Aggregates/OperatorAggregate.cs b/TransactionProcessor.Aggregates/OperatorAggregate.cs index 7a772a37..d85c4b4a 100644 --- a/TransactionProcessor.Aggregates/OperatorAggregate.cs +++ b/TransactionProcessor.Aggregates/OperatorAggregate.cs @@ -1,7 +1,10 @@ using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.Contracts; +using System.Diagnostics.Tracing; using Shared.DomainDrivenDesign.EventSourcing; using Shared.EventStore.Aggregate; using Shared.General; +using SimpleResults; using TransactionProcessor.DomainEvents; namespace TransactionProcessor.Aggregates @@ -37,21 +40,27 @@ public static void PlayEvent(this OperatorAggregate aggregate, OperatorDomainEve aggregate.RequireCustomTerminalNumber = domainEvent.RequireCustomTerminalNumber; } - public static void Create(this OperatorAggregate aggregate, + [Pure] + public static Result Create(this OperatorAggregate aggregate, Guid estateId, String name, Boolean requireCustomMerchantNumber, Boolean requireCustomTerminalNumber) { - Guard.ThrowIfInvalidGuid(estateId, typeof(ArgumentNullException), "Estate Id must not be an empty Guid"); - Guard.ThrowIfNullOrEmpty(name, typeof(ArgumentNullException), "Operator name must not be null or empty"); + if (estateId == Guid.Empty) + return Result.Invalid("Estate Id must not be an empty Guid"); + if (String.IsNullOrEmpty(name)) + return Result.Invalid("Operator name must not be null or empty"); OperatorDomainEvents.OperatorCreatedEvent operatorCreatedEvent = new(aggregate.AggregateId, estateId, name, requireCustomMerchantNumber, requireCustomTerminalNumber); aggregate.ApplyAndAppend(operatorCreatedEvent); + + return Result.Success(); } - public static void UpdateOperator(this OperatorAggregate aggregate, + [Pure] + public static Result UpdateOperator(this OperatorAggregate aggregate, String name, Boolean requireCustomMerchantNumber, Boolean requireCustomTerminalNumber) @@ -74,6 +83,8 @@ public static void UpdateOperator(this OperatorAggregate aggregate, OperatorDomainEvents.OperatorRequireCustomTerminalNumberChangedEvent operatorRequireCustomTerminalNumberChangedEvent = new(aggregate.AggregateId, aggregate.EstateId, requireCustomTerminalNumber); aggregate.ApplyAndAppend(operatorRequireCustomTerminalNumberChangedEvent); } + + return Result.Success(); } } diff --git a/TransactionProcessor.BusinessLogic/Services/OperatorDomainService.cs b/TransactionProcessor.BusinessLogic/Services/OperatorDomainService.cs index aaa060ac..0a669497 100644 --- a/TransactionProcessor.BusinessLogic/Services/OperatorDomainService.cs +++ b/TransactionProcessor.BusinessLogic/Services/OperatorDomainService.cs @@ -50,7 +50,9 @@ public async Task CreateOperator(OperatorCommands.CreateOperatorCommand return Result.Forbidden($"Operator with Id {command.RequestDto.OperatorId} already created"); } - operatorAggregate.Create(command.EstateId, command.RequestDto.Name, command.RequestDto.RequireCustomMerchantNumber.GetValueOrDefault(), command.RequestDto.RequireCustomTerminalNumber.GetValueOrDefault()); + Result stateResult = operatorAggregate.Create(command.EstateId, command.RequestDto.Name, command.RequestDto.RequireCustomMerchantNumber.GetValueOrDefault(), command.RequestDto.RequireCustomTerminalNumber.GetValueOrDefault()); + if (stateResult.IsFailed) + return ResultHelpers.CreateFailure(stateResult); Result saveResult = await this.AggregateService.Save(operatorAggregate, cancellationToken); if (saveResult.IsFailed) @@ -83,9 +85,11 @@ public async Task UpdateOperator(OperatorCommands.UpdateOperatorCommand return Result.Forbidden($"Estate with Id {command.EstateId} not created"); } - operatorAggregate.UpdateOperator(command.RequestDto.Name, + Result stateResult = operatorAggregate.UpdateOperator(command.RequestDto.Name, command.RequestDto.RequireCustomMerchantNumber.GetValueOrDefault(), command.RequestDto.RequireCustomTerminalNumber.GetValueOrDefault()); + if (stateResult.IsFailed) + return ResultHelpers.CreateFailure(stateResult); Result saveResult = await this.AggregateService.Save(operatorAggregate, cancellationToken); if (saveResult.IsFailed)