From b66b82b62484ff75d45814d725cfec3a2b3db5e8 Mon Sep 17 00:00:00 2001 From: StuartFerguson Date: Sun, 16 Aug 2026 05:57:41 +0100 Subject: [PATCH] make calls in repo idempodent --- .../EstateManagementGenericContext.cs | 2 +- .../ContractEventTests.cs | 63 +++- .../EstateEventTests.cs | 38 +- .../FileImportLogEventTests.cs | 145 +++++++- .../MerchantEventTests.cs | 336 +++++++++++++++++- .../OperatorEventTests.cs | 50 ++- .../SettlementEventTests.cs | 146 ++++++++ .../StatementEventTests.cs | 19 +- .../TransactionEventTests.cs | 299 ++++++++++++++++ .../TransactionProcessor.DatabaseTests.csproj | 2 +- ...TransactionProcessorReadModelRepository.cs | 22 +- TransactionProcessor.Testing/TestData.cs | 31 ++ 12 files changed, 1127 insertions(+), 26 deletions(-) create mode 100644 TransactionProcessor.DatabaseTests/SettlementEventTests.cs create mode 100644 TransactionProcessor.DatabaseTests/TransactionEventTests.cs diff --git a/TransactionProcessor.Database/Contexts/EstateManagementGenericContext.cs b/TransactionProcessor.Database/Contexts/EstateManagementGenericContext.cs index ac47dfd8..7b3ced45 100644 --- a/TransactionProcessor.Database/Contexts/EstateManagementGenericContext.cs +++ b/TransactionProcessor.Database/Contexts/EstateManagementGenericContext.cs @@ -665,7 +665,7 @@ public static class DomainEventHelper public static Guid GetContractProductId(IDomainEvent domainEvent) => DomainEventHelper.GetProperty(domainEvent, "ProductId"); - public static Guid GetContractProductTransactionFeeId(IDomainEvent domainEvent) => DomainEventHelper.GetProperty(domainEvent, "FeeId"); + public static Guid GetContractProductTransactionFeeId(IDomainEvent domainEvent) => DomainEventHelper.GetProperty(domainEvent, "TransactionFeeId"); public static Guid GetEstateId(IDomainEvent domainEvent) => DomainEventHelper.GetProperty(domainEvent, "EstateId"); public static Guid GetOperatorId(IDomainEvent domainEvent) => DomainEventHelper.GetProperty(domainEvent, "OperatorId"); diff --git a/TransactionProcessor.DatabaseTests/ContractEventTests.cs b/TransactionProcessor.DatabaseTests/ContractEventTests.cs index 54518827..9f469fa4 100644 --- a/TransactionProcessor.DatabaseTests/ContractEventTests.cs +++ b/TransactionProcessor.DatabaseTests/ContractEventTests.cs @@ -46,13 +46,64 @@ public async Task AddContract_ContractIsAdded() } [Fact] - public async Task AddContract_EventReplayHandled() { - Result result = await this.Repository.AddContract(TestData.DomainEvents.ContractCreatedEvent, CancellationToken.None); - result.IsSuccess.ShouldBeTrue(); + public async Task AddContract_EventReplayHandled() { + Result result = await this.Repository.AddContract(TestData.DomainEvents.ContractCreatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); - result = await this.Repository.AddContract(TestData.DomainEvents.ContractCreatedEvent, CancellationToken.None); - result.IsSuccess.ShouldBeTrue(); - } + result = await this.Repository.AddContract(TestData.DomainEvents.ContractCreatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + } + + [Fact] + public async Task AddContractToMerchant_ContractIsAddedToMerchant() + { + Result result = await this.Repository.AddContract(TestData.DomainEvents.ContractCreatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + result = await this.Repository.AddContractToMerchant(TestData.DomainEvents.ContractAddedToMerchantEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + EstateManagementContext context = this.GetContext(); + MerchantContract? merchantContract = await context.MerchantContracts.SingleOrDefaultAsync(c => c.MerchantId == TestData.DomainEvents.ContractAddedToMerchantEvent.MerchantId && c.ContractId == TestData.DomainEvents.ContractAddedToMerchantEvent.ContractId); + merchantContract.ShouldNotBeNull(); + merchantContract.IsDeleted.ShouldBeFalse(); + } + + [Fact] + public async Task RemoveContractFromMerchant_ContractIsMarkedDeleted() + { + Result result = await this.Repository.AddContract(TestData.DomainEvents.ContractCreatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + result = await this.Repository.AddContractToMerchant(TestData.DomainEvents.ContractAddedToMerchantEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + result = await this.Repository.RemoveContractFromMerchant(TestData.DomainEvents.ContractRemovedFromMerchantEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + EstateManagementContext context = this.GetContext(); + MerchantContract? merchantContract = await context.MerchantContracts.SingleOrDefaultAsync(c => c.MerchantId == TestData.DomainEvents.ContractRemovedFromMerchantEvent.MerchantId && c.ContractId == TestData.DomainEvents.ContractRemovedFromMerchantEvent.ContractId); + merchantContract.ShouldNotBeNull(); + merchantContract.IsDeleted.ShouldBeTrue(); + } + + [Fact] + public async Task DisableContractProductTransactionFee_TransactionFeeIsDisabled() + { + Result result = await this.Repository.AddContract(TestData.DomainEvents.ContractCreatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue("Add"); + result = await this.Repository.AddContractProduct(TestData.DomainEvents.FixedValueProductAddedToContractEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue("Product Add"); + result = await this.Repository.AddContractProductTransactionFee(TestData.DomainEvents.TransactionFeeForProductAddedToContractEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue("Fee Add"); + + result = await this.Repository.DisableContractProductTransactionFee(TestData.DomainEvents.TransactionFeeForProductDisabledEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(result.Message); + + EstateManagementContext context = this.GetContext(); + ContractProductTransactionFee? contractProductTransactionFee = await context.ContractProductTransactionFees.SingleOrDefaultAsync(c => c.ContractProductTransactionFeeId == TestData.DomainEvents.TransactionFeeForProductDisabledEvent.TransactionFeeId); + contractProductTransactionFee.ShouldNotBeNull(); + contractProductTransactionFee.IsEnabled.ShouldBeFalse(); + } [Fact] public async Task AddContractProduct_ContractProductIsAdded() diff --git a/TransactionProcessor.DatabaseTests/EstateEventTests.cs b/TransactionProcessor.DatabaseTests/EstateEventTests.cs index b2ab58d7..be211407 100644 --- a/TransactionProcessor.DatabaseTests/EstateEventTests.cs +++ b/TransactionProcessor.DatabaseTests/EstateEventTests.cs @@ -1,4 +1,5 @@ using Microsoft.EntityFrameworkCore; +using Shared.Logger; using Shouldly; using SimpleResults; using TransactionProcessor.Database.Contexts; @@ -6,6 +7,25 @@ namespace TransactionProcessor.DatabaseTests; +public class MigrationTests : BaseTest { + public override async ValueTask InitializeAsync() { + + Logger.Initialise(new Shared.Logger.NullLogger()); + + this.TestId = Guid.NewGuid(); + + await this.StartSqlContainer(); + await this.GetRepository(); + } + + [Fact] + public async Task CreateReadModel_EstateDatabaseIsMigrated() + { + Result result = await this.Repository.CreateReadModel(TestData.DomainEvents.EstateCreatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + } +} + public class EstateEventTests : BaseTest { [Fact] public async Task AddEstate_EstateIsAdded() @@ -15,6 +35,7 @@ public async Task AddEstate_EstateIsAdded() EstateManagementContext context = this.GetContext(); var estate = await context.Estates.SingleOrDefaultAsync(f => f.EstateId == TestData.DomainEvents.EstateCreatedEvent.EstateId); estate.ShouldNotBeNull(); + estate.Name.ShouldBe(TestData.DomainEvents.EstateCreatedEvent.EstateName); } [Fact] @@ -46,4 +67,19 @@ public async Task AddEstateSecurityUser_EventReplayHandled() result = await this.Repository.AddEstateSecurityUser(TestData.DomainEvents.EstateSecurityUserAddedEvent, CancellationToken.None); result.IsSuccess.ShouldBeTrue(); } -} \ No newline at end of file + + [Fact] + public async Task UpdateEstate_EstateReferenceIsUpdated() + { + Result result = await this.Repository.AddEstate(TestData.DomainEvents.EstateCreatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + result = await this.Repository.UpdateEstate(TestData.DomainEvents.EstateReferenceAllocatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + EstateManagementContext context = this.GetContext(); + var estate = await context.Estates.SingleOrDefaultAsync(f => f.EstateId == TestData.DomainEvents.EstateReferenceAllocatedEvent.EstateId); + estate.ShouldNotBeNull(); + estate.Reference.ShouldBe(TestData.DomainEvents.EstateReferenceAllocatedEvent.EstateReference); + } +} diff --git a/TransactionProcessor.DatabaseTests/FileImportLogEventTests.cs b/TransactionProcessor.DatabaseTests/FileImportLogEventTests.cs index 405d787d..b23736d0 100644 --- a/TransactionProcessor.DatabaseTests/FileImportLogEventTests.cs +++ b/TransactionProcessor.DatabaseTests/FileImportLogEventTests.cs @@ -1,12 +1,35 @@ -using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; using Shouldly; using SimpleResults; using TransactionProcessor.Database.Contexts; +using TransactionProcessor.Database.Entities; using TransactionProcessor.Testing; namespace TransactionProcessor.DatabaseTests; public class FileImportLogEventTests : BaseTest { + private async Task CreateFileImportLogAsync() + { + Result result = await this.Repository.AddFileImportLog(TestData.DomainEvents.ImportLogCreatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + } + + private async Task CreateFileAsync() + { + await this.CreateFileImportLogAsync(); + + Result result = await this.Repository.AddFile(TestData.DomainEvents.FileCreatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + } + + private async Task CreateFileLineAsync() + { + await this.CreateFileAsync(); + + Result result = await this.Repository.AddFileLineToFile(TestData.DomainEvents.FileLineAddedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + } + [Fact] public async Task AddFileImportLog_FileImportLogIsAdded() { @@ -15,6 +38,8 @@ public async Task AddFileImportLog_FileImportLogIsAdded() EstateManagementContext context = this.GetContext(); var fileImportLog = await context.FileImportLogs.SingleOrDefaultAsync(f => f.FileImportLogId == TestData.DomainEvents.ImportLogCreatedEvent.FileImportLogId); fileImportLog.ShouldNotBeNull(); + fileImportLog.EstateId.ShouldBe(TestData.DomainEvents.ImportLogCreatedEvent.EstateId); + fileImportLog.ImportLogDate.ShouldBe(TestData.DomainEvents.ImportLogCreatedEvent.ImportLogDateTime.Date); } [Fact] @@ -35,6 +60,8 @@ public async Task AddFileImportLogFile_FileImportLogIsAdded() EstateManagementContext context = this.GetContext(); var fileImportLogFile = await context.FileImportLogFiles.SingleOrDefaultAsync(f => f.FileImportLogId == TestData.DomainEvents.FileAddedToImportLogEvent.FileImportLogId && f.FileId == TestData.DomainEvents.FileAddedToImportLogEvent.FileId); fileImportLogFile.ShouldNotBeNull(); + fileImportLogFile.FilePath.ShouldBe(TestData.DomainEvents.FileAddedToImportLogEvent.FilePath); + fileImportLogFile.OriginalFileName.ShouldBe(TestData.DomainEvents.FileAddedToImportLogEvent.OriginalFileName); } [Fact] @@ -46,4 +73,118 @@ public async Task AddFileImportLogFile_EventReplayHandled() result = await this.Repository.AddFileToImportLog(TestData.DomainEvents.FileAddedToImportLogEvent, CancellationToken.None); result.IsSuccess.ShouldBeTrue(); } -} \ No newline at end of file + + [Fact] + public async Task AddFile_FileIsAdded() + { + await this.CreateFileImportLogAsync(); + + Result result = await this.Repository.AddFile(TestData.DomainEvents.FileCreatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + EstateManagementContext context = this.GetContext(); + TransactionProcessor.Database.Entities.File? file = await context.Files.SingleOrDefaultAsync(f => f.FileId == TestData.DomainEvents.FileCreatedEvent.FileId); + file.ShouldNotBeNull(); + file.EstateId.ShouldBe(TestData.DomainEvents.FileCreatedEvent.EstateId); + file.MerchantId.ShouldBe(TestData.DomainEvents.FileCreatedEvent.MerchantId); + file.FileLocation.ShouldBe(TestData.DomainEvents.FileCreatedEvent.FileLocation); + file.FileReceivedDate.ShouldBe(TestData.DomainEvents.FileCreatedEvent.FileReceivedDateTime.Date); + file.IsCompleted.ShouldBeFalse(); + } + + [Fact] + public async Task AddFile_EventReplayHandled() + { + await this.CreateFileImportLogAsync(); + + Result result = await this.Repository.AddFile(TestData.DomainEvents.FileCreatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + result = await this.Repository.AddFile(TestData.DomainEvents.FileCreatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + } + + [Fact] + public async Task AddFileLineToFile_FileLineIsAdded() + { + await this.CreateFileAsync(); + + Result result = await this.Repository.AddFileLineToFile(TestData.DomainEvents.FileLineAddedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + EstateManagementContext context = this.GetContext(); + FileLine? fileLine = await context.FileLines.SingleOrDefaultAsync(f => f.FileId == TestData.DomainEvents.FileLineAddedEvent.FileId && f.LineNumber == TestData.DomainEvents.FileLineAddedEvent.LineNumber); + fileLine.ShouldNotBeNull(); + fileLine.FileLineData.ShouldBe(TestData.DomainEvents.FileLineAddedEvent.FileLine); + fileLine.Status.ShouldBe("P"); + } + + [Fact] + public async Task AddFileLineToFile_EventReplayHandled() + { + await this.CreateFileAsync(); + + Result result = await this.Repository.AddFileLineToFile(TestData.DomainEvents.FileLineAddedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + result = await this.Repository.AddFileLineToFile(TestData.DomainEvents.FileLineAddedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + } + + [Fact] + public async Task UpdateFileAsComplete_FileIsCompleted() + { + await this.CreateFileAsync(); + + Result result = await this.Repository.UpdateFileAsComplete(TestData.DomainEvents.FileProcessingCompletedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + EstateManagementContext context = this.GetContext(); + TransactionProcessor.Database.Entities.File? file = await context.Files.SingleOrDefaultAsync(f => f.FileId == TestData.DomainEvents.FileProcessingCompletedEvent.FileId); + file.ShouldNotBeNull(); + file.IsCompleted.ShouldBeTrue(); + } + + [Fact] + public async Task UpdateFileLineSuccessful_FileLineIsUpdated() + { + await this.CreateFileLineAsync(); + + Result result = await this.Repository.UpdateFileLine(TestData.DomainEvents.FileLineProcessingSuccessfulEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + EstateManagementContext context = this.GetContext(); + FileLine? fileLine = await context.FileLines.SingleOrDefaultAsync(f => f.FileId == TestData.DomainEvents.FileLineProcessingSuccessfulEvent.FileId && f.LineNumber == TestData.DomainEvents.FileLineProcessingSuccessfulEvent.LineNumber); + fileLine.ShouldNotBeNull(); + fileLine.Status.ShouldBe("S"); + fileLine.TransactionId.ShouldBe(TestData.DomainEvents.FileLineProcessingSuccessfulEvent.TransactionId); + } + + [Fact] + public async Task UpdateFileLineFailed_FileLineIsUpdated() + { + await this.CreateFileLineAsync(); + + Result result = await this.Repository.UpdateFileLine(TestData.DomainEvents.FileLineProcessingFailedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + EstateManagementContext context = this.GetContext(); + FileLine? fileLine = await context.FileLines.SingleOrDefaultAsync(f => f.FileId == TestData.DomainEvents.FileLineProcessingFailedEvent.FileId && f.LineNumber == TestData.DomainEvents.FileLineProcessingFailedEvent.LineNumber); + fileLine.ShouldNotBeNull(); + fileLine.Status.ShouldBe("F"); + fileLine.TransactionId.ShouldBe(TestData.DomainEvents.FileLineProcessingFailedEvent.TransactionId); + } + + [Fact] + public async Task UpdateFileLineIgnored_FileLineIsUpdated() + { + await this.CreateFileLineAsync(); + + Result result = await this.Repository.UpdateFileLine(TestData.DomainEvents.FileLineProcessingIgnoredEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + EstateManagementContext context = this.GetContext(); + FileLine? fileLine = await context.FileLines.SingleOrDefaultAsync(f => f.FileId == TestData.DomainEvents.FileLineProcessingIgnoredEvent.FileId && f.LineNumber == TestData.DomainEvents.FileLineProcessingIgnoredEvent.LineNumber); + fileLine.ShouldNotBeNull(); + fileLine.Status.ShouldBe("I"); + fileLine.TransactionId.ShouldBe(Guid.Empty); + } +} diff --git a/TransactionProcessor.DatabaseTests/MerchantEventTests.cs b/TransactionProcessor.DatabaseTests/MerchantEventTests.cs index a68c4566..3c4e3a34 100644 --- a/TransactionProcessor.DatabaseTests/MerchantEventTests.cs +++ b/TransactionProcessor.DatabaseTests/MerchantEventTests.cs @@ -1,13 +1,25 @@ -using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; using Shouldly; using SimpleResults; using TransactionProcessor.Database.Contexts; using TransactionProcessor.Database.Entities; +using TransactionProcessor.DomainEvents; using TransactionProcessor.Testing; namespace TransactionProcessor.DatabaseTests; public class MerchantEventTests : BaseTest { + private async Task CreateMerchantAsync() + { + Result result = await this.Repository.AddMerchant(TestData.DomainEvents.MerchantCreatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + } + + private static MerchantDomainEvents.MerchantOpeningHoursUpdatedEvent CreateMerchantOpeningHoursUpdatedEvent(DayOfWeek dayOfWeek, String opening, String closing) + { + return new MerchantDomainEvents.MerchantOpeningHoursUpdatedEvent(TestData.MerchantId, TestData.EstateId, (Int32)dayOfWeek, opening, closing); + } + [Fact] public async Task AddMerchant_MerchantIsAdded() { @@ -26,9 +38,72 @@ public async Task AddMerchant_EventReplayHandled() { result.IsSuccess.ShouldBeTrue(); } + [Fact] + public async Task AddMerchantAddress_MerchantAddressIsAdded() + { + await this.CreateMerchantAsync(); + + Result result = await this.Repository.AddMerchantAddress(TestData.DomainEvents.AddressAddedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + EstateManagementContext context = this.GetContext(); + MerchantAddress? merchantAddress = await context.MerchantAddresses.SingleOrDefaultAsync(c => c.AddressId == TestData.DomainEvents.AddressAddedEvent.AddressId); + merchantAddress.ShouldNotBeNull(); + merchantAddress.MerchantId.ShouldBe(TestData.DomainEvents.AddressAddedEvent.MerchantId); + merchantAddress.AddressLine1.ShouldBe(TestData.DomainEvents.AddressAddedEvent.AddressLine1); + merchantAddress.AddressLine2.ShouldBe(TestData.DomainEvents.AddressAddedEvent.AddressLine2); + merchantAddress.AddressLine3.ShouldBe(TestData.DomainEvents.AddressAddedEvent.AddressLine3); + merchantAddress.AddressLine4.ShouldBe(TestData.DomainEvents.AddressAddedEvent.AddressLine4); + merchantAddress.Town.ShouldBe(TestData.DomainEvents.AddressAddedEvent.Town); + merchantAddress.Region.ShouldBe(TestData.DomainEvents.AddressAddedEvent.Region); + merchantAddress.PostalCode.ShouldBe(TestData.DomainEvents.AddressAddedEvent.PostalCode); + merchantAddress.Country.ShouldBe(TestData.DomainEvents.AddressAddedEvent.Country); + } + + [Fact] + public async Task AddMerchantAddress_EventReplayHandled() + { + await this.CreateMerchantAsync(); + + Result result = await this.Repository.AddMerchantAddress(TestData.DomainEvents.AddressAddedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + result = await this.Repository.AddMerchantAddress(TestData.DomainEvents.AddressAddedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + } + + [Fact] + public async Task AddMerchantContact_MerchantContactIsAdded() + { + await this.CreateMerchantAsync(); + + Result result = await this.Repository.AddMerchantContact(TestData.DomainEvents.ContactAddedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + EstateManagementContext context = this.GetContext(); + MerchantContact? merchantContact = await context.MerchantContacts.SingleOrDefaultAsync(c => c.ContactId == TestData.DomainEvents.ContactAddedEvent.ContactId); + merchantContact.ShouldNotBeNull(); + merchantContact.MerchantId.ShouldBe(TestData.DomainEvents.ContactAddedEvent.MerchantId); + merchantContact.Name.ShouldBe(TestData.DomainEvents.ContactAddedEvent.ContactName); + merchantContact.EmailAddress.ShouldBe(TestData.DomainEvents.ContactAddedEvent.ContactEmailAddress); + merchantContact.PhoneNumber.ShouldBe(TestData.DomainEvents.ContactAddedEvent.ContactPhoneNumber); + } + + [Fact] + public async Task AddMerchantContact_EventReplayHandled() + { + await this.CreateMerchantAsync(); + + Result result = await this.Repository.AddMerchantContact(TestData.DomainEvents.ContactAddedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + result = await this.Repository.AddMerchantContact(TestData.DomainEvents.ContactAddedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + } + [Fact] public async Task AddMerchantDevice_MerchantContractIsAdded() { + await this.CreateMerchantAsync(); + Result result = await this.Repository.AddMerchantDevice(TestData.DomainEvents.DeviceAddedToMerchantEvent, CancellationToken.None); result.IsSuccess.ShouldBeTrue(); EstateManagementContext context = this.GetContext(); @@ -38,15 +113,129 @@ public async Task AddMerchantDevice_MerchantContractIsAdded() [Fact] public async Task AddMerchantDevice_EventReplayHandled() { + await this.CreateMerchantAsync(); + Result result = await this.Repository.AddMerchantDevice(TestData.DomainEvents.DeviceAddedToMerchantEvent, CancellationToken.None); result.IsSuccess.ShouldBeTrue(); result = await this.Repository.AddMerchantDevice(TestData.DomainEvents.DeviceAddedToMerchantEvent, CancellationToken.None); result.IsSuccess.ShouldBeTrue(); } + [Fact] + public async Task AddMerchantOperator_MerchantOperatorIsAdded() + { + await this.CreateMerchantAsync(); + + Result result = await this.Repository.AddMerchantOperator(TestData.DomainEvents.OperatorAssignedToMerchantEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + EstateManagementContext context = this.GetContext(); + MerchantOperator? merchantOperator = await context.MerchantOperators.SingleOrDefaultAsync(c => c.OperatorId == TestData.DomainEvents.OperatorAssignedToMerchantEvent.OperatorId && c.MerchantId == TestData.DomainEvents.OperatorAssignedToMerchantEvent.MerchantId); + merchantOperator.ShouldNotBeNull(); + merchantOperator.Name.ShouldBe(TestData.DomainEvents.OperatorAssignedToMerchantEvent.Name); + merchantOperator.MerchantNumber.ShouldBe(TestData.DomainEvents.OperatorAssignedToMerchantEvent.MerchantNumber); + merchantOperator.TerminalNumber.ShouldBe(TestData.DomainEvents.OperatorAssignedToMerchantEvent.TerminalNumber); + merchantOperator.IsDeleted.ShouldBeFalse(); + } + + [Fact] + public async Task AddMerchantOperator_EventReplayHandled() + { + await this.CreateMerchantAsync(); + + Result result = await this.Repository.AddMerchantOperator(TestData.DomainEvents.OperatorAssignedToMerchantEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + result = await this.Repository.AddMerchantOperator(TestData.DomainEvents.OperatorAssignedToMerchantEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + } + + [Fact] + public async Task AddMerchantSecurityUser_MerchantSecurityUserIsAdded() + { + await this.CreateMerchantAsync(); + + Result result = await this.Repository.AddMerchantSecurityUser(TestData.DomainEvents.MerchantSecurityUserAddedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + EstateManagementContext context = this.GetContext(); + MerchantSecurityUser? merchantSecurityUser = await context.MerchantSecurityUsers.SingleOrDefaultAsync(c => c.SecurityUserId == TestData.DomainEvents.MerchantSecurityUserAddedEvent.SecurityUserId); + merchantSecurityUser.ShouldNotBeNull(); + merchantSecurityUser.MerchantId.ShouldBe(TestData.DomainEvents.MerchantSecurityUserAddedEvent.MerchantId); + merchantSecurityUser.EmailAddress.ShouldBe(TestData.DomainEvents.MerchantSecurityUserAddedEvent.EmailAddress); + } + + [Fact] + public async Task AddMerchantSecurityUser_EventReplayHandled() + { + await this.CreateMerchantAsync(); + + Result result = await this.Repository.AddMerchantSecurityUser(TestData.DomainEvents.MerchantSecurityUserAddedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + result = await this.Repository.AddMerchantSecurityUser(TestData.DomainEvents.MerchantSecurityUserAddedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + } + + [Fact] + public async Task AddMerchantSchedule_MerchantScheduleIsAdded() + { + await this.CreateMerchantAsync(); + + Result result = await this.Repository.AddMerchantSchedule(TestData.DomainEvents.MerchantScheduleCreatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + EstateManagementContext context = this.GetContext(); + MerchantSchedule? merchantSchedule = await context.MerchantSchedules.SingleOrDefaultAsync(c => c.MerchantScheduleId == TestData.DomainEvents.MerchantScheduleCreatedEvent.MerchantScheduleId); + merchantSchedule.ShouldNotBeNull(); + merchantSchedule.EstateId.ShouldBe(TestData.DomainEvents.MerchantScheduleCreatedEvent.EstateId); + merchantSchedule.MerchantId.ShouldBe(TestData.DomainEvents.MerchantScheduleCreatedEvent.MerchantId); + merchantSchedule.Year.ShouldBe(TestData.DomainEvents.MerchantScheduleCreatedEvent.Year); + } + + [Fact] + public async Task AddMerchantSchedule_EventReplayHandled() + { + await this.CreateMerchantAsync(); + + Result result = await this.Repository.AddMerchantSchedule(TestData.DomainEvents.MerchantScheduleCreatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + result = await this.Repository.AddMerchantSchedule(TestData.DomainEvents.MerchantScheduleCreatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + } + + [Fact] + public async Task RemoveOperatorFromMerchant_MerchantOperatorIsMarkedDeleted() + { + await this.CreateMerchantAsync(); + Result result = await this.Repository.AddMerchantOperator(TestData.DomainEvents.OperatorAssignedToMerchantEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + result = await this.Repository.RemoveOperatorFromMerchant(TestData.DomainEvents.OperatorRemovedFromMerchantEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + EstateManagementContext context = this.GetContext(); + MerchantOperator? merchantOperator = await context.MerchantOperators.SingleOrDefaultAsync(c => c.OperatorId == TestData.DomainEvents.OperatorRemovedFromMerchantEvent.OperatorId && c.MerchantId == TestData.DomainEvents.OperatorRemovedFromMerchantEvent.MerchantId); + merchantOperator.ShouldNotBeNull(); + merchantOperator.IsDeleted.ShouldBeTrue(); + } + + [Fact] + public async Task RemoveOperatorFromMerchant_EventReplayHandled() + { + await this.CreateMerchantAsync(); + Result result = await this.Repository.AddMerchantOperator(TestData.DomainEvents.OperatorAssignedToMerchantEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + result = await this.Repository.RemoveOperatorFromMerchant(TestData.DomainEvents.OperatorRemovedFromMerchantEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + result = await this.Repository.RemoveOperatorFromMerchant(TestData.DomainEvents.OperatorRemovedFromMerchantEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + } + [Fact] public async Task SwapMerchantDevice_MerchantDeviceIsAdded() { + await this.CreateMerchantAsync(); + Result result = await this.Repository.AddMerchantDevice(TestData.DomainEvents.DeviceAddedToMerchantEvent, CancellationToken.None); result.IsSuccess.ShouldBeTrue(); result = await this.Repository.SwapMerchantDevice(TestData.DomainEvents.DeviceSwappedForMerchantEvent, CancellationToken.None); @@ -66,6 +255,8 @@ public async Task SwapMerchantDevice_MerchantDeviceIsAdded() [Fact] public async Task SwapMerchantDevice_EventReplayHandled() { + await this.CreateMerchantAsync(); + Result result = await this.Repository.AddMerchantDevice(TestData.DomainEvents.DeviceAddedToMerchantEvent, CancellationToken.None); result.IsSuccess.ShouldBeTrue(); result = await this.Repository.SwapMerchantDevice(TestData.DomainEvents.DeviceSwappedForMerchantEvent, CancellationToken.None); @@ -94,4 +285,145 @@ public async Task SwapMerchantDevice_EventReplayHandled() merchantDevice.DeviceIdentifier.ShouldBe(TestData.DomainEvents.DeviceSwappedForMerchantEvent.NewDeviceIdentifier); merchantDevice.IsEnabled.ShouldBeTrue(); } -} \ No newline at end of file + + [Fact] + public async Task UpdateMerchantName_MerchantIsUpdated() + { + await this.CreateMerchantAsync(); + + Result result = await this.Repository.UpdateMerchant(TestData.DomainEvents.MerchantNameUpdatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + EstateManagementContext context = this.GetContext(); + Merchant? merchant = await context.Merchants.SingleOrDefaultAsync(c => c.MerchantId == TestData.DomainEvents.MerchantNameUpdatedEvent.MerchantId); + merchant.ShouldNotBeNull(); + merchant.Name.ShouldBe(TestData.DomainEvents.MerchantNameUpdatedEvent.MerchantName); + } + + [Fact] + public async Task UpdateMerchantReference_MerchantIsUpdated() + { + await this.CreateMerchantAsync(); + + Result result = await this.Repository.UpdateMerchant(TestData.DomainEvents.MerchantReferenceAllocatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + EstateManagementContext context = this.GetContext(); + Merchant? merchant = await context.Merchants.SingleOrDefaultAsync(c => c.MerchantId == TestData.DomainEvents.MerchantReferenceAllocatedEvent.MerchantId); + merchant.ShouldNotBeNull(); + merchant.Reference.ShouldBe(TestData.DomainEvents.MerchantReferenceAllocatedEvent.MerchantReference); + } + + [Fact] + public async Task UpdateMerchantSettlementSchedule_MerchantIsUpdated() + { + await this.CreateMerchantAsync(); + + Result result = await this.Repository.UpdateMerchant(TestData.DomainEvents.SettlementScheduleChangedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + EstateManagementContext context = this.GetContext(); + Merchant? merchant = await context.Merchants.SingleOrDefaultAsync(c => c.MerchantId == TestData.DomainEvents.SettlementScheduleChangedEvent.MerchantId); + merchant.ShouldNotBeNull(); + merchant.SettlementSchedule.ShouldBe(TestData.DomainEvents.SettlementScheduleChangedEvent.SettlementSchedule); + } + + [Fact] + public async Task UpdateMerchantAddress_MerchantAddressIsUpdated() + { + await this.CreateMerchantAsync(); + Result result = await this.Repository.AddMerchantAddress(TestData.DomainEvents.AddressAddedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + result = await this.Repository.UpdateMerchantAddress(TestData.DomainEvents.MerchantAddressLine1UpdatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + result = await this.Repository.UpdateMerchantAddress(TestData.DomainEvents.MerchantAddressLine2UpdatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + result = await this.Repository.UpdateMerchantAddress(TestData.DomainEvents.MerchantAddressLine3UpdatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + result = await this.Repository.UpdateMerchantAddress(TestData.DomainEvents.MerchantAddressLine4UpdatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + result = await this.Repository.UpdateMerchantAddress(TestData.DomainEvents.MerchantCountyUpdatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + result = await this.Repository.UpdateMerchantAddress(TestData.DomainEvents.MerchantRegionUpdatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + result = await this.Repository.UpdateMerchantAddress(TestData.DomainEvents.MerchantTownUpdatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + result = await this.Repository.UpdateMerchantAddress(TestData.DomainEvents.MerchantPostalCodeUpdatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + EstateManagementContext context = this.GetContext(); + MerchantAddress? merchantAddress = await context.MerchantAddresses.SingleOrDefaultAsync(c => c.AddressId == TestData.DomainEvents.AddressAddedEvent.AddressId); + merchantAddress.ShouldNotBeNull(); + merchantAddress.AddressLine1.ShouldBe(TestData.DomainEvents.MerchantAddressLine1UpdatedEvent.AddressLine1); + merchantAddress.AddressLine2.ShouldBe(TestData.DomainEvents.MerchantAddressLine2UpdatedEvent.AddressLine2); + merchantAddress.AddressLine3.ShouldBe(TestData.DomainEvents.MerchantAddressLine3UpdatedEvent.AddressLine3); + merchantAddress.AddressLine4.ShouldBe(TestData.DomainEvents.MerchantAddressLine4UpdatedEvent.AddressLine4); + merchantAddress.Country.ShouldBe(TestData.DomainEvents.MerchantCountyUpdatedEvent.Country); + merchantAddress.Region.ShouldBe(TestData.DomainEvents.MerchantRegionUpdatedEvent.Region); + merchantAddress.Town.ShouldBe(TestData.DomainEvents.MerchantTownUpdatedEvent.Town); + merchantAddress.PostalCode.ShouldBe(TestData.DomainEvents.MerchantPostalCodeUpdatedEvent.PostalCode); + } + + [Fact] + public async Task UpdateMerchantContact_MerchantContactIsUpdated() + { + await this.CreateMerchantAsync(); + Result result = await this.Repository.AddMerchantContact(TestData.DomainEvents.ContactAddedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + result = await this.Repository.UpdateMerchantContact(TestData.DomainEvents.MerchantContactNameUpdatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + result = await this.Repository.UpdateMerchantContact(TestData.DomainEvents.MerchantContactEmailAddressUpdatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + result = await this.Repository.UpdateMerchantContact(TestData.DomainEvents.MerchantContactPhoneNumberUpdatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + EstateManagementContext context = this.GetContext(); + MerchantContact? merchantContact = await context.MerchantContacts.SingleOrDefaultAsync(c => c.ContactId == TestData.DomainEvents.ContactAddedEvent.ContactId); + merchantContact.ShouldNotBeNull(); + merchantContact.Name.ShouldBe(TestData.DomainEvents.MerchantContactNameUpdatedEvent.ContactName); + merchantContact.EmailAddress.ShouldBe(TestData.DomainEvents.MerchantContactEmailAddressUpdatedEvent.ContactEmailAddress); + merchantContact.PhoneNumber.ShouldBe(TestData.DomainEvents.MerchantContactPhoneNumberUpdatedEvent.ContactPhoneNumber); + } + + [Fact] + public async Task UpdateMerchantOpeningHours_MerchantOpeningHoursIsUpdated() + { + await this.CreateMerchantAsync(); + + Result result = await this.Repository.UpdateMerchantOpeningHours(TestData.DomainEvents.MerchantOpeningHoursUpdatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + result = await this.Repository.UpdateMerchantOpeningHours(CreateMerchantOpeningHoursUpdatedEvent(DayOfWeek.Tuesday, "0900", "1800"), CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + result = await this.Repository.UpdateMerchantOpeningHours(CreateMerchantOpeningHoursUpdatedEvent(DayOfWeek.Wednesday, "1000", "1900"), CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + result = await this.Repository.UpdateMerchantOpeningHours(CreateMerchantOpeningHoursUpdatedEvent(DayOfWeek.Thursday, "1100", "2000"), CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + result = await this.Repository.UpdateMerchantOpeningHours(CreateMerchantOpeningHoursUpdatedEvent(DayOfWeek.Friday, "1200", "2100"), CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + result = await this.Repository.UpdateMerchantOpeningHours(CreateMerchantOpeningHoursUpdatedEvent(DayOfWeek.Saturday, "1300", "2200"), CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + result = await this.Repository.UpdateMerchantOpeningHours(CreateMerchantOpeningHoursUpdatedEvent(DayOfWeek.Sunday, "1400", "2300"), CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + EstateManagementContext context = this.GetContext(); + MerchantOpeningHours? merchantOpeningHours = await context.MerchantOpeningHours.SingleOrDefaultAsync(c => c.MerchantId == TestData.MerchantId); + merchantOpeningHours.ShouldNotBeNull(); + merchantOpeningHours.MondayOpening.ShouldBe("0800"); + merchantOpeningHours.MondayClosing.ShouldBe("1700"); + merchantOpeningHours.TuesdayOpening.ShouldBe("0900"); + merchantOpeningHours.TuesdayClosing.ShouldBe("1800"); + merchantOpeningHours.WednesdayOpening.ShouldBe("1000"); + merchantOpeningHours.WednesdayClosing.ShouldBe("1900"); + merchantOpeningHours.ThursdayOpening.ShouldBe("1100"); + merchantOpeningHours.ThursdayClosing.ShouldBe("2000"); + merchantOpeningHours.FridayOpening.ShouldBe("1200"); + merchantOpeningHours.FridayClosing.ShouldBe("2100"); + merchantOpeningHours.SaturdayOpening.ShouldBe("1300"); + merchantOpeningHours.SaturdayClosing.ShouldBe("2200"); + merchantOpeningHours.SundayOpening.ShouldBe("1400"); + merchantOpeningHours.SundayClosing.ShouldBe("2300"); + } +} diff --git a/TransactionProcessor.DatabaseTests/OperatorEventTests.cs b/TransactionProcessor.DatabaseTests/OperatorEventTests.cs index 554c4380..a9a283bd 100644 --- a/TransactionProcessor.DatabaseTests/OperatorEventTests.cs +++ b/TransactionProcessor.DatabaseTests/OperatorEventTests.cs @@ -16,6 +16,9 @@ public async Task AddOperator_OperatorIsAdded() EstateManagementContext context = this.GetContext(); Operator? @operator = await context.Operators.SingleOrDefaultAsync(c => c.OperatorId == TestData.DomainEvents.OperatorCreatedEvent.OperatorId); @operator.ShouldNotBeNull(); + @operator.Name.ShouldBe(TestData.DomainEvents.OperatorCreatedEvent.Name); + @operator.RequireCustomMerchantNumber.ShouldBe(TestData.DomainEvents.OperatorCreatedEvent.RequireCustomMerchantNumber); + @operator.RequireCustomTerminalNumber.ShouldBe(TestData.DomainEvents.OperatorCreatedEvent.RequireCustomTerminalNumber); } [Fact] @@ -27,4 +30,49 @@ public async Task AddOperator_EventReplayHandled() result = await this.Repository.AddOperator(TestData.DomainEvents.OperatorCreatedEvent, CancellationToken.None); result.IsSuccess.ShouldBeTrue(); } -} \ No newline at end of file + + [Fact] + public async Task UpdateOperatorName_OperatorIsUpdated() + { + Result result = await this.Repository.AddOperator(TestData.DomainEvents.OperatorCreatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + result = await this.Repository.UpdateOperator(TestData.DomainEvents.OperatorNameUpdatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + EstateManagementContext context = this.GetContext(); + Operator? @operator = await context.Operators.SingleOrDefaultAsync(c => c.OperatorId == TestData.DomainEvents.OperatorCreatedEvent.OperatorId); + @operator.ShouldNotBeNull(); + @operator.Name.ShouldBe(TestData.DomainEvents.OperatorNameUpdatedEvent.Name); + } + + [Fact] + public async Task UpdateOperatorRequireCustomMerchantNumber_OperatorIsUpdated() + { + Result result = await this.Repository.AddOperator(TestData.DomainEvents.OperatorCreatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + result = await this.Repository.UpdateOperator(TestData.DomainEvents.OperatorRequireCustomMerchantNumberChangedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + EstateManagementContext context = this.GetContext(); + Operator? @operator = await context.Operators.SingleOrDefaultAsync(c => c.OperatorId == TestData.DomainEvents.OperatorCreatedEvent.OperatorId); + @operator.ShouldNotBeNull(); + @operator.RequireCustomMerchantNumber.ShouldBe(TestData.DomainEvents.OperatorRequireCustomMerchantNumberChangedEvent.RequireCustomMerchantNumber); + } + + [Fact] + public async Task UpdateOperatorRequireCustomTerminalNumber_OperatorIsUpdated() + { + Result result = await this.Repository.AddOperator(TestData.DomainEvents.OperatorCreatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + result = await this.Repository.UpdateOperator(TestData.DomainEvents.OperatorRequireCustomTerminalNumberChangedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + EstateManagementContext context = this.GetContext(); + Operator? @operator = await context.Operators.SingleOrDefaultAsync(c => c.OperatorId == TestData.DomainEvents.OperatorCreatedEvent.OperatorId); + @operator.ShouldNotBeNull(); + @operator.RequireCustomTerminalNumber.ShouldBe(TestData.DomainEvents.OperatorRequireCustomTerminalNumberChangedEvent.RequireCustomTerminalNumber); + } +} diff --git a/TransactionProcessor.DatabaseTests/SettlementEventTests.cs b/TransactionProcessor.DatabaseTests/SettlementEventTests.cs new file mode 100644 index 00000000..62bcf264 --- /dev/null +++ b/TransactionProcessor.DatabaseTests/SettlementEventTests.cs @@ -0,0 +1,146 @@ +using Microsoft.EntityFrameworkCore; +using Shouldly; +using SimpleResults; +using TransactionProcessor.Database.Contexts; +using TransactionProcessor.Database.Entities; +using TransactionProcessor.DomainEvents; +using TransactionProcessor.Testing; + +namespace TransactionProcessor.DatabaseTests; + +public class SettlementEventTests : BaseTest +{ + [Fact] + public async Task CreateSettlement_SettlementIsAdded() + { + Result result = await this.Repository.CreateSettlement(TestData.DomainEvents.SettlementCreatedForDateEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + EstateManagementContext context = this.GetContext(); + Settlement? settlement = await context.Settlements.SingleOrDefaultAsync(c => c.SettlementId == TestData.DomainEvents.SettlementCreatedForDateEvent.SettlementId); + settlement.ShouldNotBeNull(); + } + + [Fact] + public async Task CreateSettlement_EventReplayHandled() + { + Result result = await this.Repository.CreateSettlement(TestData.DomainEvents.SettlementCreatedForDateEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + result = await this.Repository.CreateSettlement(TestData.DomainEvents.SettlementCreatedForDateEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + } + + [Fact] + public async Task MarkSettlementAsProcessingStarted_SettlementIsUpdated() + { + Result result = await this.Repository.CreateSettlement(TestData.DomainEvents.SettlementCreatedForDateEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + result = await this.Repository.MarkSettlementAsProcessingStarted(TestData.DomainEvents.SettlementProcessingStartedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + EstateManagementContext context = this.GetContext(); + Settlement? settlement = await context.Settlements.SingleOrDefaultAsync(c => c.SettlementId == TestData.DomainEvents.SettlementProcessingStartedEvent.SettlementId); + settlement.ShouldNotBeNull(); + settlement.ProcessingStarted.ShouldBeTrue(); + settlement.ProcessingStartedDateTIme.ShouldBe(TestData.DomainEvents.SettlementProcessingStartedEvent.ProcessingStartedDateTime); + } + + [Fact] + public async Task MarkSettlementAsCompleted_SettlementIsUpdated() + { + Result result = await this.Repository.CreateSettlement(TestData.DomainEvents.SettlementCreatedForDateEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + result = await this.Repository.MarkSettlementAsCompleted(TestData.DomainEvents.SettlementCompletedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + EstateManagementContext context = this.GetContext(); + Settlement? settlement = await context.Settlements.SingleOrDefaultAsync(c => c.SettlementId == TestData.DomainEvents.SettlementCompletedEvent.SettlementId); + settlement.ShouldNotBeNull(); + settlement.IsCompleted.ShouldBeTrue(); + } + + [Fact] + public async Task AddPendingMerchantFeeToSettlement_MerchantFeeIsAdded() + { + Result result = await this.Repository.AddPendingMerchantFeeToSettlement(TestData.DomainEvents.MerchantFeeAddedPendingSettlementEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + EstateManagementContext context = this.GetContext(); + MerchantSettlementFee? merchantSettlementFee = await context.MerchantSettlementFees.SingleOrDefaultAsync(f => + f.SettlementId == TestData.DomainEvents.MerchantFeeAddedPendingSettlementEvent.SettlementId && + f.TransactionId == TestData.DomainEvents.MerchantFeeAddedPendingSettlementEvent.TransactionId && + f.ContractProductTransactionFeeId == TestData.DomainEvents.MerchantFeeAddedPendingSettlementEvent.FeeId); + + merchantSettlementFee.ShouldNotBeNull(); + merchantSettlementFee.IsSettled.ShouldBeFalse(); + } + + [Fact] + public async Task AddPendingMerchantFeeToSettlement_EventReplayHandled() + { + Result result = await this.Repository.AddPendingMerchantFeeToSettlement(TestData.DomainEvents.MerchantFeeAddedPendingSettlementEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + result = await this.Repository.AddPendingMerchantFeeToSettlement(TestData.DomainEvents.MerchantFeeAddedPendingSettlementEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + } + + [Fact] + public async Task AddSettledMerchantFeeToSettlement_MerchantFeeIsAdded() + { + Result result = await this.Repository.AddSettledMerchantFeeToSettlement(TestData.SettledMerchantFeeAddedToTransactionEvent(TestData.SettlementDate), CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + EstateManagementContext context = this.GetContext(); + MerchantSettlementFee? merchantSettlementFee = await context.MerchantSettlementFees.SingleOrDefaultAsync(f => + f.SettlementId == TestData.SettlementAggregateId && + f.TransactionId == TestData.SettlementAggregateId && + f.ContractProductTransactionFeeId == TestData.TransactionFeeId); + + merchantSettlementFee.ShouldNotBeNull(); + merchantSettlementFee.IsSettled.ShouldBeTrue(); + } + + [Fact] + public async Task AddSettledMerchantFeeToSettlement_EventReplayHandled() + { + Result result = await this.Repository.AddSettledMerchantFeeToSettlement(TestData.SettledMerchantFeeAddedToTransactionEvent(TestData.SettlementDate), CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + result = await this.Repository.AddSettledMerchantFeeToSettlement(TestData.SettledMerchantFeeAddedToTransactionEvent(TestData.SettlementDate), CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + } + + [Fact] + public async Task MarkMerchantFeeAsSettled_MerchantFeeIsMarkedSettled() + { + SettlementDomainEvents.MerchantFeeAddedPendingSettlementEvent pendingEvent = new( + TestData.SettlementId, + TestData.EstateId, + TestData.MerchantId, + TestData.TransactionId, + TestData.CalculatedFeeValue, + TestData.FeeCalculationType, + TestData.SettledFeeId1, + TestData.FeeValue, + TestData.TransactionFeeCalculateDateTime); + + Result result = await this.Repository.AddPendingMerchantFeeToSettlement(pendingEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + result = await this.Repository.MarkMerchantFeeAsSettled(TestData.DomainEvents.MerchantFeeSettledEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + EstateManagementContext context = this.GetContext(); + MerchantSettlementFee? merchantSettlementFee = await context.MerchantSettlementFees.SingleOrDefaultAsync(f => + f.SettlementId == TestData.DomainEvents.MerchantFeeSettledEvent.SettlementId && + f.TransactionId == TestData.DomainEvents.MerchantFeeSettledEvent.TransactionId && + f.ContractProductTransactionFeeId == TestData.DomainEvents.MerchantFeeSettledEvent.FeeId); + + merchantSettlementFee.ShouldNotBeNull(); + merchantSettlementFee.IsSettled.ShouldBeTrue(); + } +} diff --git a/TransactionProcessor.DatabaseTests/StatementEventTests.cs b/TransactionProcessor.DatabaseTests/StatementEventTests.cs index 1344bcea..34a40803 100644 --- a/TransactionProcessor.DatabaseTests/StatementEventTests.cs +++ b/TransactionProcessor.DatabaseTests/StatementEventTests.cs @@ -16,6 +16,8 @@ public async Task CreateStatement_StatementIsAdded() EstateManagementContext context = this.GetContext(); StatementHeader? statement = await context.StatementHeaders.SingleOrDefaultAsync(c => c.StatementId == TestData.DomainEvents.StatementCreatedEvent.MerchantStatementId); statement.ShouldNotBeNull(); + statement.StatementCreatedDate.ShouldBe(TestData.DomainEvents.StatementCreatedEvent.StatementDate.Date); + statement.StatementCreatedDateTime.ShouldBe(TestData.DomainEvents.StatementCreatedEvent.StatementDate); } [Fact] public async Task CreateStatement_EventReplayHandled() @@ -25,4 +27,19 @@ public async Task CreateStatement_EventReplayHandled() result = await this.Repository.CreateStatement(TestData.DomainEvents.StatementCreatedEvent, CancellationToken.None); result.IsSuccess.ShouldBeTrue(); } -} \ No newline at end of file + + [Fact] + public async Task MarkStatementAsGenerated_StatementIsUpdated() + { + Result result = await this.Repository.CreateStatement(TestData.DomainEvents.StatementCreatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + result = await this.Repository.MarkStatementAsGenerated(TestData.DomainEvents.StatementGeneratedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + EstateManagementContext context = this.GetContext(); + StatementHeader? statement = await context.StatementHeaders.SingleOrDefaultAsync(c => c.StatementId == TestData.DomainEvents.StatementCreatedEvent.MerchantStatementId); + statement.ShouldNotBeNull(); + statement.StatementGeneratedDate.ShouldBe(TestData.DomainEvents.StatementGeneratedEvent.DateGenerated); + } +} diff --git a/TransactionProcessor.DatabaseTests/TransactionEventTests.cs b/TransactionProcessor.DatabaseTests/TransactionEventTests.cs new file mode 100644 index 00000000..aab610eb --- /dev/null +++ b/TransactionProcessor.DatabaseTests/TransactionEventTests.cs @@ -0,0 +1,299 @@ +using Microsoft.EntityFrameworkCore; +using Shouldly; +using SimpleResults; +using TransactionProcessor.Aggregates; +using TransactionProcessor.Database.Contexts; +using TransactionProcessor.Database.Entities; +using TransactionProcessor.Testing; +using System.Collections.Generic; + +namespace TransactionProcessor.DatabaseTests; + +public class TransactionEventTests : BaseTest { + private async Task CreateOperatorAsync() + { + Result result = await this.Repository.AddOperator(TestData.DomainEvents.OperatorCreatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + } + + private async Task CreateContractAsync() + { + await this.CreateOperatorAsync(); + + Result result = await this.Repository.AddContract(TestData.DomainEvents.ContractCreatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + } + + private async Task CreateMerchantAsync() + { + Result result = await this.Repository.AddMerchant(TestData.DomainEvents.MerchantCreatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + } + + private async Task CreateTransactionAsync() + { + Result result = await this.Repository.StartTransaction(TestData.DomainEvents.TransactionHasStartedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + } + + private async Task CreateTransactionWithProductDetailsAsync() + { + await this.CreateContractAsync(); + await this.CreateTransactionAsync(); + + Result result = await this.Repository.AddProductDetailsToTransaction(TestData.DomainEvents.ProductDetailsAddedToTransactionEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + } + + [Fact] + public async Task StartTransaction_TransactionIsAdded() + { + Result result = await this.Repository.StartTransaction(TestData.DomainEvents.TransactionHasStartedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + EstateManagementContext context = this.GetContext(); + Transaction? transaction = await context.Transactions.SingleOrDefaultAsync(t => t.TransactionId == TestData.DomainEvents.TransactionHasStartedEvent.TransactionId); + transaction.ShouldNotBeNull(); + transaction.MerchantId.ShouldBe(TestData.DomainEvents.TransactionHasStartedEvent.MerchantId); + transaction.TransactionDate.ShouldBe(TestData.DomainEvents.TransactionHasStartedEvent.TransactionDateTime.Date); + transaction.TransactionDateTime.ShouldBe(TestData.DomainEvents.TransactionHasStartedEvent.TransactionDateTime); + transaction.TransactionNumber.ShouldBe(TestData.DomainEvents.TransactionHasStartedEvent.TransactionNumber); + transaction.TransactionReference.ShouldBe(TestData.DomainEvents.TransactionHasStartedEvent.TransactionReference); + transaction.TransactionType.ShouldBe(TestData.DomainEvents.TransactionHasStartedEvent.TransactionType); + transaction.DeviceIdentifier.ShouldBe(TestData.DomainEvents.TransactionHasStartedEvent.DeviceIdentifier); + transaction.TransactionAmount.ShouldBe(TestData.DomainEvents.TransactionHasStartedEvent.TransactionAmount.GetValueOrDefault()); + transaction.IsCompleted.ShouldBeFalse(); + } + + [Fact] + public async Task StartTransaction_EventReplayHandled() + { + Result result = await this.Repository.StartTransaction(TestData.DomainEvents.TransactionHasStartedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + result = await this.Repository.StartTransaction(TestData.DomainEvents.TransactionHasStartedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + } + + [Fact] + public async Task CompleteTransaction_TransactionIsCompleted() + { + await this.CreateTransactionAsync(); + + Result result = await this.Repository.CompleteTransaction(TestData.DomainEvents.TransactionHasBeenCompletedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + EstateManagementContext context = this.GetContext(); + Transaction? transaction = await context.Transactions.SingleOrDefaultAsync(t => t.TransactionId == TestData.DomainEvents.TransactionHasBeenCompletedEvent.TransactionId); + transaction.ShouldNotBeNull(); + transaction.IsCompleted.ShouldBeTrue(); + } + + [Fact] + public async Task RecordTransactionAdditionalRequestData_RequestDataIsStored() + { + Result result = await this.Repository.RecordTransactionAdditionalRequestData(TestData.DomainEvents.AdditionalRequestDataRecordedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + EstateManagementContext context = this.GetContext(); + TransactionAdditionalRequestData? requestData = await context.TransactionsAdditionalRequestData.SingleOrDefaultAsync(t => t.TransactionId == TestData.DomainEvents.AdditionalRequestDataRecordedEvent.TransactionId); + requestData.ShouldNotBeNull(); + requestData.Amount.ShouldBe("123.45"); + requestData.CustomerAccountNumber.ShouldBe("12345678"); + } + + [Fact] + public async Task RecordTransactionAdditionalResponseData_ResponseDataIsStored() + { + Result result = await this.Repository.RecordTransactionAdditionalResponseData(TestData.DomainEvents.AdditionalResponseDataRecordedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + EstateManagementContext context = this.GetContext(); + TransactionAdditionalResponseData? responseData = await context.TransactionsAdditionalResponseData.SingleOrDefaultAsync(t => t.TransactionId == TestData.DomainEvents.AdditionalResponseDataRecordedEvent.TransactionId); + responseData.ShouldNotBeNull(); + responseData.TransactionId.ShouldBe(TestData.DomainEvents.AdditionalResponseDataRecordedEvent.TransactionId); + responseData.TransactionReportingId.ShouldBe(0); + } + + [Fact] + public async Task SetTransactionAmount_TransactionAmountIsUpdated() + { + await this.CreateTransactionAsync(); + + Result result = await this.Repository.SetTransactionAmount(TestData.DomainEvents.AdditionalRequestDataRecordedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + EstateManagementContext context = this.GetContext(); + Transaction? transaction = await context.Transactions.SingleOrDefaultAsync(t => t.TransactionId == TestData.DomainEvents.TransactionHasStartedEvent.TransactionId); + transaction.ShouldNotBeNull(); + transaction.TransactionAmount.ShouldBe(123.45m); + } + + [Fact] + public async Task AddProductDetailsToTransaction_TransactionIsUpdated() + { + await this.CreateContractAsync(); + await this.CreateTransactionAsync(); + + Result result = await this.Repository.AddProductDetailsToTransaction(TestData.DomainEvents.ProductDetailsAddedToTransactionEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + EstateManagementContext context = this.GetContext(); + Transaction? transaction = await context.Transactions.SingleOrDefaultAsync(t => t.TransactionId == TestData.DomainEvents.ProductDetailsAddedToTransactionEvent.TransactionId); + transaction.ShouldNotBeNull(); + transaction.ContractId.ShouldBe(TestData.DomainEvents.ProductDetailsAddedToTransactionEvent.ContractId); + transaction.ContractProductId.ShouldBe(TestData.DomainEvents.ProductDetailsAddedToTransactionEvent.ProductId); + transaction.OperatorId.ShouldBe(TestData.OperatorId); + } + + [Fact] + public async Task AddSourceDetailsToTransaction_TransactionSourceIsUpdated() + { + await this.CreateTransactionAsync(); + + Result result = await this.Repository.AddSourceDetailsToTransaction(TestData.DomainEvents.TransactionSourceAddedToTransactionEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + EstateManagementContext context = this.GetContext(); + Transaction? transaction = await context.Transactions.SingleOrDefaultAsync(t => t.TransactionId == TestData.DomainEvents.TransactionSourceAddedToTransactionEvent.TransactionId); + transaction.ShouldNotBeNull(); + transaction.TransactionSource.ShouldBe(TestData.DomainEvents.TransactionSourceAddedToTransactionEvent.TransactionSource); + } + + [Fact] + public async Task UpdateTransactionAuthorisation_LocallyAuthorisedTransactionIsUpdated() + { + await this.CreateTransactionAsync(); + + Result result = await this.Repository.UpdateTransactionAuthorisation(TestData.DomainEvents.TransactionHasBeenLocallyAuthorisedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + EstateManagementContext context = this.GetContext(); + Transaction? transaction = await context.Transactions.SingleOrDefaultAsync(t => t.TransactionId == TestData.DomainEvents.TransactionHasBeenLocallyAuthorisedEvent.TransactionId); + transaction.ShouldNotBeNull(); + transaction.IsAuthorised.ShouldBeTrue(); + transaction.AuthorisationCode.ShouldBe(TestData.AuthorisationCode); + transaction.ResponseCode.ShouldBe(TestData.ResponseCode.ToCodeString()); + transaction.ResponseMessage.ShouldBe(TestData.ResponseMessage); + } + + [Fact] + public async Task UpdateTransactionAuthorisation_LocallyDeclinedTransactionIsUpdated() + { + await this.CreateTransactionAsync(); + + Result result = await this.Repository.UpdateTransactionAuthorisation(TestData.DomainEvents.TransactionHasBeenLocallyDeclinedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + EstateManagementContext context = this.GetContext(); + Transaction? transaction = await context.Transactions.SingleOrDefaultAsync(t => t.TransactionId == TestData.DomainEvents.TransactionHasBeenLocallyDeclinedEvent.TransactionId); + transaction.ShouldNotBeNull(); + transaction.IsAuthorised.ShouldBeFalse(); + transaction.ResponseCode.ShouldBe(TestData.DeclinedResponseCode.ToCodeString()); + transaction.ResponseMessage.ShouldBe(TestData.DeclinedResponseMessage); + } + + [Fact] + public async Task UpdateTransactionAuthorisation_OperatorAuthorisedTransactionIsUpdated() + { + await this.CreateTransactionAsync(); + + Result result = await this.Repository.UpdateTransactionAuthorisation(TestData.DomainEvents.TransactionAuthorisedByOperatorEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + EstateManagementContext context = this.GetContext(); + Transaction? transaction = await context.Transactions.SingleOrDefaultAsync(t => t.TransactionId == TestData.DomainEvents.TransactionAuthorisedByOperatorEvent.TransactionId); + transaction.ShouldNotBeNull(); + transaction.IsAuthorised.ShouldBeTrue(); + transaction.AuthorisationCode.ShouldBe(TestData.OperatorAuthorisationCode); + transaction.ResponseCode.ShouldBe(TestData.ResponseCode.ToCodeString()); + transaction.ResponseMessage.ShouldBe(TestData.ResponseMessage); + } + + [Fact] + public async Task UpdateTransactionAuthorisation_OperatorDeclinedTransactionIsUpdated() + { + await this.CreateTransactionAsync(); + + Result result = await this.Repository.UpdateTransactionAuthorisation(TestData.DomainEvents.TransactionDeclinedByOperatorEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + EstateManagementContext context = this.GetContext(); + Transaction? transaction = await context.Transactions.SingleOrDefaultAsync(t => t.TransactionId == TestData.DomainEvents.TransactionDeclinedByOperatorEvent.TransactionId); + transaction.ShouldNotBeNull(); + transaction.IsAuthorised.ShouldBeFalse(); + transaction.ResponseCode.ShouldBe(TestData.DeclinedResponseCode.ToCodeString()); + transaction.ResponseMessage.ShouldBe(TestData.DeclinedResponseMessage); + } + + [Fact] + public async Task RecordTransactionTimings_TimingsAreStored() + { + Result result = await this.Repository.RecordTransactionTimings(TestData.DomainEvents.TransactionTimingsAddedToTransactionEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + EstateManagementContext context = this.GetContext(); + TransactionTimings? timings = await context.TransactionTimings.SingleOrDefaultAsync(t => t.TransactionId == TestData.DomainEvents.TransactionTimingsAddedToTransactionEvent.TransactionId); + timings.ShouldNotBeNull(); + timings.TransactionStartedDateTime.ShouldBe(TestData.DomainEvents.TransactionTimingsAddedToTransactionEvent.TransactionStartedDateTime); + timings.OperatorCommunicationsStartedDateTime.ShouldBe(TestData.DomainEvents.TransactionTimingsAddedToTransactionEvent.OperatorCommunicationsStartedEvent); + timings.OperatorCommunicationsCompletedDateTime.ShouldBe(TestData.DomainEvents.TransactionTimingsAddedToTransactionEvent.OperatorCommunicationsCompletedEvent); + timings.TransactionCompletedDateTime.ShouldBe(TestData.DomainEvents.TransactionTimingsAddedToTransactionEvent.TransactionCompletedDateTime); + timings.TotalTransactionInMilliseconds.ShouldBe(300000d); + timings.OperatorCommunicationsDurationInMilliseconds.ShouldBe(120000d); + timings.TransactionProcessingDurationInMilliseconds.ShouldBe(180000d); + } + + [Fact] + public async Task AddTransactionToStatement_StatementLineIsAdded() + { + await this.CreateTransactionWithProductDetailsAsync(); + + Result result = await this.Repository.AddTransactionToStatement(TestData.DomainEvents.TransactionAddedToStatementForDateEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + EstateManagementContext context = this.GetContext(); + StatementLine? statementLine = await context.StatementLines.SingleOrDefaultAsync(s => s.StatementId == TestData.DomainEvents.TransactionAddedToStatementForDateEvent.MerchantStatementId && s.TransactionId == TestData.DomainEvents.TransactionAddedToStatementForDateEvent.TransactionId); + statementLine.ShouldNotBeNull(); + statementLine.ActivityDate.ShouldBe(TestData.DomainEvents.TransactionAddedToStatementForDateEvent.TransactionDateTime.Date); + statementLine.ActivityDateTime.ShouldBe(TestData.DomainEvents.TransactionAddedToStatementForDateEvent.TransactionDateTime); + statementLine.ActivityDescription.ShouldBe($"{TestData.OperatorName} Transaction"); + statementLine.ActivityType.ShouldBe(1); + statementLine.OutAmount.ShouldBe(TestData.DomainEvents.TransactionAddedToStatementForDateEvent.TransactionValue); + statementLine.InAmount.ShouldBe(0); + } + + [Fact] + public async Task AddSettledFeeToStatement_StatementLineIsAdded() + { + await this.CreateTransactionWithProductDetailsAsync(); + + Result result = await this.Repository.AddSettledFeeToStatement(TestData.DomainEvents.SettledFeeAddedToStatementForDateEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + EstateManagementContext context = this.GetContext(); + StatementLine? statementLine = await context.StatementLines.SingleOrDefaultAsync(s => s.StatementId == TestData.DomainEvents.SettledFeeAddedToStatementForDateEvent.MerchantStatementId && s.TransactionId == TestData.DomainEvents.SettledFeeAddedToStatementForDateEvent.TransactionId); + statementLine.ShouldNotBeNull(); + statementLine.ActivityDate.ShouldBe(TestData.DomainEvents.SettledFeeAddedToStatementForDateEvent.SettledDateTime.Date); + statementLine.ActivityDateTime.ShouldBe(TestData.DomainEvents.SettledFeeAddedToStatementForDateEvent.SettledDateTime); + statementLine.ActivityDescription.ShouldBe($"{TestData.OperatorName} Transaction Fee"); + statementLine.ActivityType.ShouldBe(2); + statementLine.InAmount.ShouldBe(TestData.DomainEvents.SettledFeeAddedToStatementForDateEvent.SettledValue); + statementLine.OutAmount.ShouldBe(0); + } + + [Fact] + public async Task UpdateMerchant_TransactionCompletionUpdatesMerchantLastSale() + { + await this.CreateMerchantAsync(); + + Result result = await this.Repository.UpdateMerchant(TestData.DomainEvents.TransactionHasBeenCompletedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + EstateManagementContext context = this.GetContext(); + Merchant? merchant = await context.Merchants.SingleOrDefaultAsync(m => m.MerchantId == TestData.DomainEvents.TransactionHasBeenCompletedEvent.MerchantId); + merchant.ShouldNotBeNull(); + merchant.LastSaleDate.ShouldBe(TestData.DomainEvents.TransactionHasBeenCompletedEvent.CompletedDateTime.Date); + merchant.LastSaleDateTime.ShouldBe(TestData.DomainEvents.TransactionHasBeenCompletedEvent.CompletedDateTime); + } +} diff --git a/TransactionProcessor.DatabaseTests/TransactionProcessor.DatabaseTests.csproj b/TransactionProcessor.DatabaseTests/TransactionProcessor.DatabaseTests.csproj index 25efa11d..b1244687 100644 --- a/TransactionProcessor.DatabaseTests/TransactionProcessor.DatabaseTests.csproj +++ b/TransactionProcessor.DatabaseTests/TransactionProcessor.DatabaseTests.csproj @@ -5,7 +5,7 @@ enable enable false - None + Full diff --git a/TransactionProcessor.Repository/ITransactionProcessorReadModelRepository.cs b/TransactionProcessor.Repository/ITransactionProcessorReadModelRepository.cs index 9aec32fe..5b9f63aa 100644 --- a/TransactionProcessor.Repository/ITransactionProcessorReadModelRepository.cs +++ b/TransactionProcessor.Repository/ITransactionProcessorReadModelRepository.cs @@ -432,7 +432,7 @@ public async Task AddMerchantAddress(AddressAddedEvent domainEvent, await context.MerchantAddresses.AddAsync(merchantAddress, cancellationToken); - return await context.SaveChangesAsync(cancellationToken); + return await context.SaveChangesWithDuplicateHandling(cancellationToken); } public async Task AddMerchantContact(ContactAddedEvent domainEvent, @@ -452,7 +452,7 @@ public async Task AddMerchantContact(ContactAddedEvent domainEvent, await context.MerchantContacts.AddAsync(merchantContact, cancellationToken); - return await context.SaveChangesAsync(cancellationToken); + return await context.SaveChangesWithDuplicateHandling(cancellationToken); } public async Task AddMerchantDevice(DeviceAddedToMerchantEvent domainEvent, @@ -519,7 +519,7 @@ public async Task AddMerchantOperator(OperatorAssignedToMerchantEvent do await context.MerchantOperators.AddAsync(merchantOperator, cancellationToken); - return await context.SaveChangesAsync(cancellationToken); + return await context.SaveChangesWithDuplicateHandling(cancellationToken); } public async Task AddMerchantSecurityUser(SecurityUserAddedToMerchantEvent domainEvent, @@ -537,7 +537,7 @@ public async Task AddMerchantSecurityUser(SecurityUserAddedToMerchantEve await context.MerchantSecurityUsers.AddAsync(merchantSecurityUser, cancellationToken); - return await context.SaveChangesAsync(cancellationToken); + return await context.SaveChangesWithDuplicateHandling(cancellationToken); } public async Task UpdateMerchant(SettlementScheduleChangedEvent domainEvent, CancellationToken cancellationToken) @@ -839,7 +839,7 @@ public async Task AddContractToMerchant(ContractAddedToMerchantEvent dom }; await context.MerchantContracts.AddAsync(merchantContract, cancellationToken); - return await context.SaveChangesAsync(cancellationToken); + return await context.SaveChangesWithDuplicateHandling(cancellationToken); } public async Task UpdateMerchant(MerchantReferenceAllocatedEvent domainEvent, CancellationToken cancellationToken) @@ -1308,7 +1308,7 @@ public async Task CreateFloatActivity(FloatDomainEvents.FloatCreditPurch FloatId = domainEvent.FloatId }; await context.FloatActivity.AddAsync(floatActivity, cancellationToken); - return await context.SaveChangesAsync(cancellationToken); + return await context.SaveChangesWithDuplicateHandling(cancellationToken); } public async Task CreateFloatActivity(FloatDomainEvents.FloatDecreasedByTransactionEvent domainEvent, @@ -1332,7 +1332,7 @@ public async Task CreateFloatActivity(FloatDomainEvents.FloatDecreasedBy FloatId = domainEvent.FloatId }; await context.FloatActivity.AddAsync(floatActivity, cancellationToken); - return await context.SaveChangesAsync(cancellationToken); + return await context.SaveChangesWithDuplicateHandling(cancellationToken); } public async Task CreateReadModel(EstateDomainEvents.EstateCreatedEvent domainEvent, @@ -1365,7 +1365,7 @@ public async Task CreateSettlement(SettlementDomainEvents.SettlementCrea await context.Settlements.AddAsync(settlement, cancellationToken); - return await context.SaveChangesAsync(cancellationToken); + return await context.SaveChangesWithDuplicateHandling(cancellationToken); } public async Task DisableContractProductTransactionFee(ContractDomainEvents.TransactionFeeForProductDisabledEvent domainEvent, @@ -1947,7 +1947,7 @@ public async Task AddFile(FileCreatedEvent domainEvent, await context.Files.AddAsync(file, cancellationToken); - return await context.SaveChangesAsync(cancellationToken); + return await context.SaveChangesWithDuplicateHandling(cancellationToken); } public async Task AddFileImportLog(ImportLogCreatedEvent domainEvent, @@ -2307,7 +2307,7 @@ public async Task AddEstateOperator(EstateDomainEvents.OperatorAddedToEs estateOperator.IsDeleted = null; } - return await context.SaveChangesAsync(cancellationToken); + return await context.SaveChangesWithDuplicateHandling(cancellationToken); } public async Task RemoveOperatorFromEstate(EstateDomainEvents.OperatorRemovedFromEstateEvent domainEvent, @@ -2327,7 +2327,7 @@ public async Task RemoveOperatorFromEstate(EstateDomainEvents.OperatorRe estateOperator.IsDeleted = true; } - return await context.SaveChangesAsync(cancellationToken); + return await context.SaveChangesWithDuplicateHandling(cancellationToken); } } } diff --git a/TransactionProcessor.Testing/TestData.cs b/TransactionProcessor.Testing/TestData.cs index 66bed237..3a624225 100644 --- a/TransactionProcessor.Testing/TestData.cs +++ b/TransactionProcessor.Testing/TestData.cs @@ -2623,6 +2623,25 @@ public static class DomainEvents { public static ReconciliationDomainEvents.ReconciliationHasStartedEvent ReconciliationHasStartedEvent => new ReconciliationDomainEvents.ReconciliationHasStartedEvent(TestData.TransactionId, TestData.EstateId, TestData.MerchantId, TestData.TransactionDateTime); public static FloatDomainEvents.FloatCreatedForContractProductEvent FloatCreatedForContractProductEvent => new FloatDomainEvents.FloatCreatedForContractProductEvent(FloatAggregateId, EstateId, ContractId, VariableContractProductId, FloatCreatedDateTime); + public static TransactionDomainEvents.TransactionHasStartedEvent TransactionHasStartedEvent => new TransactionDomainEvents.TransactionHasStartedEvent(TestData.TransactionId, TestData.EstateId, TestData.MerchantId, TestData.TransactionDateTime1, TestData.TransactionNumber, TestData.TransactionTypeSale.ToString(), TestData.TransactionReference, TestData.DeviceIdentifier, TestData.TransactionAmount); + public static TransactionDomainEvents.AdditionalRequestDataRecordedEvent AdditionalRequestDataRecordedEvent => new TransactionDomainEvents.AdditionalRequestDataRecordedEvent(TestData.TransactionId, TestData.EstateId, TestData.MerchantId, TestData.OperatorId, new Dictionary + { + { "Amount", "123.45" }, + { "CustomerAccountNumber", "12345678" } + }, TestData.TransactionDateTime1); + public static TransactionDomainEvents.AdditionalResponseDataRecordedEvent AdditionalResponseDataRecordedEvent => new TransactionDomainEvents.AdditionalResponseDataRecordedEvent(TestData.TransactionId, TestData.EstateId, TestData.MerchantId, TestData.OperatorId, new Dictionary + { + { "ResponseCode", TestData.ResponseCode.ToCodeString() } + }, TestData.TransactionDateTime1); + public static TransactionDomainEvents.ProductDetailsAddedToTransactionEvent ProductDetailsAddedToTransactionEvent => new TransactionDomainEvents.ProductDetailsAddedToTransactionEvent(TestData.TransactionId, TestData.EstateId, TestData.MerchantId, TestData.ContractId, TestData.FixedContractProductId, TestData.TransactionDateTime1); + public static TransactionDomainEvents.TransactionSourceAddedToTransactionEvent TransactionSourceAddedToTransactionEvent => new TransactionDomainEvents.TransactionSourceAddedToTransactionEvent(TestData.TransactionId, TestData.EstateId, TestData.MerchantId, 3, TestData.TransactionDateTime1); + public static TransactionDomainEvents.TransactionHasBeenLocallyAuthorisedEvent TransactionHasBeenLocallyAuthorisedEvent => new TransactionDomainEvents.TransactionHasBeenLocallyAuthorisedEvent(TestData.TransactionId, TestData.EstateId, TestData.MerchantId, TestData.AuthorisationCode, TestData.ResponseCode.ToCodeString(), TestData.ResponseMessage, TestData.TransactionDateTime1); + public static TransactionDomainEvents.TransactionHasBeenLocallyDeclinedEvent TransactionHasBeenLocallyDeclinedEvent => new TransactionDomainEvents.TransactionHasBeenLocallyDeclinedEvent(TestData.TransactionId, TestData.EstateId, TestData.MerchantId, TestData.DeclinedResponseCode.ToCodeString(), TestData.DeclinedResponseMessage, TestData.TransactionDateTime1); + public static TransactionDomainEvents.TransactionAuthorisedByOperatorEvent TransactionAuthorisedByOperatorEvent => new TransactionDomainEvents.TransactionAuthorisedByOperatorEvent(TestData.TransactionId, TestData.EstateId, TestData.MerchantId, TestData.OperatorId, TestData.OperatorAuthorisationCode, TestData.OperatorResponseCode, TestData.OperatorResponseMessage, "OPERATOR-TXN-1", TestData.ResponseCode.ToCodeString(), TestData.ResponseMessage, TestData.TransactionDateTime1); + public static TransactionDomainEvents.TransactionDeclinedByOperatorEvent TransactionDeclinedByOperatorEvent => new TransactionDomainEvents.TransactionDeclinedByOperatorEvent(TestData.TransactionId, TestData.EstateId, TestData.MerchantId, TestData.OperatorId, TestData.DeclinedOperatorResponseCode, TestData.DeclinedOperatorResponseMessage, TestData.DeclinedResponseCode.ToCodeString(), TestData.DeclinedResponseMessage, TestData.TransactionDateTime1); + public static TransactionDomainEvents.TransactionTimingsAddedToTransactionEvent TransactionTimingsAddedToTransactionEvent => new TransactionDomainEvents.TransactionTimingsAddedToTransactionEvent(TestData.TransactionId, TestData.EstateId, TestData.MerchantId, TestData.TransactionDateTime1, TestData.TransactionDateTime1.AddMinutes(1), TestData.TransactionDateTime1.AddMinutes(3), TestData.TransactionDateTime1.AddMinutes(5)); + public static MerchantStatementForDateDomainEvents.TransactionAddedToStatementForDateEvent TransactionAddedToStatementForDateEvent => new MerchantStatementForDateDomainEvents.TransactionAddedToStatementForDateEvent(MerchantStatementForDateId1, Guid.Parse("2D7E6B2F-9C73-4C64-9D80-15D497D2D2B3"), EstateId, MerchantId, MerchantStatementId, TransactionId, TransactionDateTime1, TransactionAmount1.Value); + public static MerchantStatementForDateDomainEvents.SettledFeeAddedToStatementForDateEvent SettledFeeAddedToStatementForDateEvent => new MerchantStatementForDateDomainEvents.SettledFeeAddedToStatementForDateEvent(MerchantStatementForDateId1, Guid.Parse("7F6B6E17-1DF7-4C86-9DD4-1CE6FD35F1A9"), EstateId, MerchantId, MerchantStatementId, SettledFeeId1, TransactionId, SettledFeeDateTime1, SettledFeeAmount1); public static TransactionDomainEvents.TransactionHasBeenCompletedEvent TransactionHasBeenCompletedEvent => new TransactionDomainEvents.TransactionHasBeenCompletedEvent(TestData.TransactionId, TestData.EstateId, TestData.MerchantId, @@ -2639,6 +2658,10 @@ public static class DomainEvents { public static MerchantDomainEvents.WithdrawalMadeEvent WithdrawalMadeEvent => new(MerchantId, EstateId, WithdrawalId, WithdrawalDateTime, WithdrawalAmount.Value); public static MerchantStatementForDateDomainEvents.StatementCreatedForDateEvent StatementCreatedForDateEvent => new(MerchantStatementForDateId1, ActivityDate1, StatementDate, MerchantStatementId, EstateId, MerchantId); + public static SettlementDomainEvents.SettlementCreatedForDateEvent SettlementCreatedForDateEvent => new(SettlementId, EstateId, MerchantId, SettlementDate); + public static SettlementDomainEvents.SettlementProcessingStartedEvent SettlementProcessingStartedEvent => new(SettlementId, EstateId, MerchantId, TransactionDateTime); + public static SettlementDomainEvents.SettlementCompletedEvent SettlementCompletedEvent => new(SettlementId, EstateId, MerchantId); + public static SettlementDomainEvents.MerchantFeeAddedPendingSettlementEvent MerchantFeeAddedPendingSettlementEvent => new(SettlementId, EstateId, MerchantId, TransactionId, CalculatedFeeValue, FeeCalculationType, TransactionFeeId, FeeValue, TransactionFeeCalculateDateTime); public static SettlementDomainEvents.MerchantFeeSettledEvent MerchantFeeSettledEvent => new(SettlementId, EstateId, MerchantId, TransactionId, CalculatedFeeValue, FeeCalculationType, SettledFeeId1, FeeValue, TransactionFeeCalculateDateTime, SettlementDate); public static MerchantStatementDomainEvents.StatementCreatedEvent StatementCreatedEvent => new(TestData.MerchantStatementId, TestData.EstateId, TestData.MerchantId, StatementDate); @@ -2671,6 +2694,7 @@ public static class DomainEvents { new MerchantDomainEvents.ContractAddedToMerchantEvent(TestData.MerchantId, TestData.EstateId, TestData.ContractId); + public static MerchantDomainEvents.ContractRemovedFromMerchantEvent ContractRemovedFromMerchantEvent => new MerchantDomainEvents.ContractRemovedFromMerchantEvent(TestData.MerchantId, TestData.EstateId, TestData.ContractId); public static MerchantDomainEvents.AddressAddedEvent AddressAddedEvent => new MerchantDomainEvents.AddressAddedEvent(TestData.MerchantId, @@ -2708,6 +2732,7 @@ public static class DomainEvents { public static MerchantDomainEvents.SecurityUserAddedToMerchantEvent MerchantSecurityUserAddedEvent => new MerchantDomainEvents.SecurityUserAddedToMerchantEvent(TestData.MerchantId, TestData.EstateId, TestData.MerchantSecurityUserId, TestData.EmailAddress); public static MerchantDomainEvents.SettlementScheduleChangedEvent SettlementScheduleChangedEvent => new MerchantDomainEvents.SettlementScheduleChangedEvent(TestData.MerchantId, TestData.EstateId, (Int32)TestData.SettlementSchedule, TestData.NextSettlementDate); + public static MerchantDomainEvents.MerchantOpeningHoursUpdatedEvent MerchantOpeningHoursUpdatedEvent => new MerchantDomainEvents.MerchantOpeningHoursUpdatedEvent(TestData.MerchantId, TestData.EstateId, (Int32)DayOfWeek.Monday, "0800", "1700"); public static MerchantScheduleDomainEvents.MerchantScheduleCreatedEvent MerchantScheduleCreatedEvent => new(TestData.MerchantScheduleId, TestData.EstateId, TestData.MerchantId, TestData.MerchantScheduleYear); public static MerchantScheduleDomainEvents.MerchantScheduleMonthUpdatedEvent MerchantScheduleMonthUpdatedEvent => new(TestData.MerchantScheduleId, TestData.EstateId, TestData.MerchantId, TestData.MerchantScheduleYear, 12, [25, 26]); //public static StatementGeneratedEvent StatementGeneratedEvent => new StatementGeneratedEvent(TestData.MerchantStatementId, TestData.EstateId, TestData.MerchantId, TestData.StatementGeneratedDate); @@ -2773,6 +2798,12 @@ public static class DomainEvents { public static ImportLogCreatedEvent ImportLogCreatedEvent => new ImportLogCreatedEvent(FileImportLogId, EstateId, ImportLogDateTime); public static FileAddedToImportLogEvent FileAddedToImportLogEvent => new FileAddedToImportLogEvent(FileImportLogId, FileId, EstateId, MerchantId, EstateSecurityUserId, FileProfileId, FileName, FilePath, FileUploadedDateTime ); + public static FileProcessor.File.DomainEvents.FileCreatedEvent FileCreatedEvent => new FileProcessor.File.DomainEvents.FileCreatedEvent(FileId, FileImportLogId, EstateId, MerchantId, EstateSecurityUserId, FileProfileId, FilePath, FileUploadedDateTime, OperatorId); + public static FileProcessor.File.DomainEvents.FileLineAddedEvent FileLineAddedEvent => new FileProcessor.File.DomainEvents.FileLineAddedEvent(FileId, EstateId, MerchantId, 1, "Test file line"); + public static FileProcessor.File.DomainEvents.FileProcessingCompletedEvent FileProcessingCompletedEvent => new FileProcessor.File.DomainEvents.FileProcessingCompletedEvent(FileId, EstateId, MerchantId, FileUploadedDateTime.AddMinutes(30)); + public static FileProcessor.File.DomainEvents.FileLineProcessingSuccessfulEvent FileLineProcessingSuccessfulEvent => new FileProcessor.File.DomainEvents.FileLineProcessingSuccessfulEvent(FileId, EstateId, MerchantId, 1, TransactionId); + public static FileProcessor.File.DomainEvents.FileLineProcessingFailedEvent FileLineProcessingFailedEvent => new FileProcessor.File.DomainEvents.FileLineProcessingFailedEvent(FileId, EstateId, MerchantId, 1, TransactionId2, OperatorResponseCode, OperatorResponseMessage); + public static FileProcessor.File.DomainEvents.FileLineProcessingIgnoredEvent FileLineProcessingIgnoredEvent => new FileProcessor.File.DomainEvents.FileLineProcessingIgnoredEvent(FileId, EstateId, MerchantId, 1); } }