diff --git a/FileProcessor.BusinessLogic.Tests/DomainServiceHelperTests.cs b/FileProcessor.BusinessLogic.Tests/DomainServiceHelperTests.cs index 1b264b1..bf857c2 100644 --- a/FileProcessor.BusinessLogic.Tests/DomainServiceHelperTests.cs +++ b/FileProcessor.BusinessLogic.Tests/DomainServiceHelperTests.cs @@ -2,6 +2,7 @@ using FileProcessor.BusinessLogic.Services; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Identity.Client; +using Shared.EventStore.Helpers; using Shouldly; using SimpleResults; using Xunit; diff --git a/FileProcessor.BusinessLogic/Services/FileProcessorDomainService.cs b/FileProcessor.BusinessLogic/Services/FileProcessorDomainService.cs index 1a042d4..02dd2eb 100644 --- a/FileProcessor.BusinessLogic/Services/FileProcessorDomainService.cs +++ b/FileProcessor.BusinessLogic/Services/FileProcessorDomainService.cs @@ -1,13 +1,13 @@ -using System.Diagnostics.CodeAnalysis; -using System.Reflection.Metadata.Ecma335; -using FileProcessor.Models; +using Shared.EventStore.Helpers; +using TransactionProcessor.DataTransferObjects.Responses.Merchant; + +namespace FileProcessor.BusinessLogic.Services; + +using System.Diagnostics.CodeAnalysis; using Shared.Results; using SimpleResults; using TransactionProcessor.DataTransferObjects.Responses.Contract; using TransactionProcessor.DataTransferObjects.Responses.Operator; - -namespace FileProcessor.BusinessLogic.Services; - using System; using System.Collections.Generic; using System.IO; @@ -17,15 +17,12 @@ namespace FileProcessor.BusinessLogic.Services; using System.Text; using System.Threading; using System.Threading.Tasks; -using Azure.Core; using Common; using FileAggregate; using FileFormatHandlers; using FileImportLogAggregate; -using FileProcessor.DataTransferObjects.Responses; -using FileProcessor.Models; +using Models; using Managers; -using MediatR; using Newtonsoft.Json; using Requests; using SecurityService.Client; @@ -37,8 +34,19 @@ namespace FileProcessor.BusinessLogic.Services; using Shared.Logger; using TransactionProcessor.Client; using TransactionProcessor.DataTransferObjects; -using FileDetails = FileProcessor.Models.FileDetails; -using FileLine = FileProcessor.Models.FileLine; +using FileDetails = Models.FileDetails; +using FileLine = Models.FileLine; + +public interface IFileProcessorDomainService +{ + Task> UploadFile(FileCommands.UploadFileCommand command, CancellationToken cancellationToken); + + Task ProcessUploadedFile(FileCommands.ProcessUploadedFileCommand command, + CancellationToken cancellationToken); + + Task ProcessTransactionForFileLine(FileCommands.ProcessTransactionForFileLineCommand command, + CancellationToken cancellationToken); +} public class FileProcessorDomainService : IFileProcessorDomainService { @@ -153,37 +161,33 @@ public async Task> UploadFile(FileCommands.UploadFileCommand comman // Move the file Result getFileProfileResult = await this.FileProcessorManager.GetFileProfile(command.FileProfileId, cancellationToken); - if (getFileProfileResult.IsFailed) - { + if (getFileProfileResult.IsFailed) { return ResultHelpers.CreateFailure(getFileProfileResult); } + FileProfile fileProfile = getFileProfileResult.Data; - if (fileProfile == null) - { + if (fileProfile == null) { return Result.NotFound($"No file profile found with Id {command.FileProfileId}"); } // Copy file from the temp location to file processing listening directory IFileInfo file = this.FileSystem.FileInfo.New(command.FilePath); - if (file.Exists == false) - { + if (file.Exists == false) { return Result.NotFound($"File {file.FullName} not found"); } + String originalName = file.Name; - if (this.FileSystem.Directory.Exists(fileProfile.ListeningDirectory) == false) - { + if (this.FileSystem.Directory.Exists(fileProfile.ListeningDirectory) == false) { return Result.NotFound($"Directory {fileProfile.ListeningDirectory} not found"); } // Read the file data String fileContent = null; //Open file for Read\Write - using (Stream fs = file.Open(FileMode.OpenOrCreate, FileAccess.Read, FileShare.Read)) - { + await using (Stream fs = file.Open(FileMode.OpenOrCreate, FileAccess.Read, FileShare.Read)) { //Create object of StreamReader by passing FileStream object on which it needs to operates on - using (StreamReader sr = new StreamReader(fs)) - { + using (StreamReader sr = new StreamReader(fs)) { //Use ReadToEnd method to read all the content from file fileContent = await sr.ReadToEndAsync(cancellationToken); } @@ -195,7 +199,7 @@ public async Task> UploadFile(FileCommands.UploadFileCommand comman file.MoveTo(fileDestination, overwrite: true); // Update Import log aggregate - var stateResult= fileImportLogAggregate.AddImportedFile(fileId, command.MerchantId, command.UserId, command.FileProfileId, originalName, fileDestination, command.FileUploadedDateTime); + Result stateResult= fileImportLogAggregate.AddImportedFile(fileId, command.MerchantId, command.UserId, command.FileProfileId, originalName, fileDestination, command.FileUploadedDateTime); if (stateResult.IsFailed) return stateResult; @@ -231,7 +235,10 @@ public async Task ProcessUploadedFile(FileCommands.ProcessUploadedFileCo return ResultHelpers.CreateFailure(operatorIdResult); Logger.LogWarning("About to Create File"); - fileAggregate.CreateFile(command.FileImportLogId, command.EstateId, command.MerchantId, command.UserId, command.FileProfileId, command.FilePath, command.FileUploadedDateTime, operatorIdResult.Data); + Result stateResult = fileAggregate.CreateFile(command.FileImportLogId, command.EstateId, command.MerchantId, command.UserId, command.FileProfileId, command.FilePath, command.FileUploadedDateTime, operatorIdResult.Data); + if (stateResult.IsFailed) + return stateResult; + Logger.LogWarning("About to return success"); return Result.Success(); @@ -253,9 +260,9 @@ private async Task> GetOperatorIdForFileProfile(Guid estateId, Guid Logger.LogInformation($"file profile {fileProfileId} not found"); return ResultHelpers.CreateFailure(fileProfileResult); } - var fileProfile = fileProfileResult.Data; + FileProfile fileProfile = fileProfileResult.Data; - var getTokenResult = await this.GetToken(cancellationToken); + Result getTokenResult = await this.GetToken(cancellationToken); if (getTokenResult.IsFailed) { return ResultHelpers.CreateFailure(getTokenResult); } @@ -279,20 +286,17 @@ public async Task ProcessTransactionForFileLine(FileCommands.ProcessTran Result result = await ApplyFileUpdates(async (FileAggregate fileAggregate) => { FileDetails fileDetails = fileAggregate.GetFile(); - if (fileDetails.FileLines.Any() == false) - { + if (fileDetails.FileLines.Any() == false) { return Result.Invalid($"File Id [{command.FileId}] has no lines added"); } FileLine fileLine = fileDetails.FileLines.SingleOrDefault(f => f.LineNumber == command.LineNumber); - if (fileLine == null) - { + if (fileLine == null) { return Result.NotFound($"File Line Number {command.LineNumber} not found in File Id {command.FileId}"); } - if (fileLine.ProcessingResult != ProcessingResult.NotProcessed) - { + if (fileLine.ProcessingResult != ProcessingResult.NotProcessed) { // Line already processed return Result.Success(); } @@ -308,17 +312,20 @@ public async Task ProcessTransactionForFileLine(FileCommands.ProcessTran if (this.FileLineCanBeIgnored(fileLine.LineData, fileProfile.FileFormatHandler)) { // Write something to aggregate to say line was explicity ignored - fileAggregate.RecordFileLineAsIgnored(fileLine.LineNumber); + Result stateResult = fileAggregate.RecordFileLineAsIgnored(fileLine.LineNumber); + if (stateResult.IsFailed) + return stateResult; return Result.Success(); } // need to now parse the line (based on the file format), this builds the metadata Dictionary transactionMetadata = this.ParseFileLine(fileLine.LineData, fileProfile.FileFormatHandler); - if (transactionMetadata.Any() == false) - { + if (transactionMetadata.Any() == false) { // Line failed to parse so record this - fileAggregate.RecordFileLineAsRejected(fileLine.LineNumber, "Invalid Format"); + Result stateResult = fileAggregate.RecordFileLineAsRejected(fileLine.LineNumber, "Invalid Format"); + if (stateResult.IsFailed) + return stateResult; return Result.Success(); } @@ -327,63 +334,55 @@ public async Task ProcessTransactionForFileLine(FileCommands.ProcessTran transactionMetadata.Add("FileLineNumber", fileLine.LineNumber.ToString()); String operatorName = fileProfile.OperatorName; - if (transactionMetadata.ContainsKey("OperatorName")) - { + if (transactionMetadata.ContainsKey("OperatorName")) { // extract the value operatorName = transactionMetadata["OperatorName"]; transactionMetadata = transactionMetadata.Where(x => x.Key != "OperatorName").ToDictionary(x => x.Key, x => x.Value); } - var getTokenResult = await this.GetToken(cancellationToken); - if (getTokenResult.IsFailed) - { + Result getTokenResult = await this.GetToken(cancellationToken); + if (getTokenResult.IsFailed) { return ResultHelpers.CreateFailure(getTokenResult); } + this.TokenResponse = getTokenResult.Data; - Interlocked.Increment(ref FileProcessorDomainService.TransactionNumber); + Interlocked.Increment(ref TransactionNumber); // Get the merchant details - var getMerchantResult = await this.TransactionProcessorClient.GetMerchant(this.TokenResponse.AccessToken, fileDetails.EstateId, fileDetails.MerchantId, cancellationToken); - if (getMerchantResult.IsFailed) - { + Result getMerchantResult = await this.TransactionProcessorClient.GetMerchant(this.TokenResponse.AccessToken, fileDetails.EstateId, fileDetails.MerchantId, cancellationToken); + if (getMerchantResult.IsFailed) { return ResultHelpers.CreateFailure(getMerchantResult); } - var merchant = getMerchantResult.Data; + MerchantResponse merchant = getMerchantResult.Data; - var getContractsResult = await this.TransactionProcessorClient.GetMerchantContracts(this.TokenResponse.AccessToken, fileDetails.EstateId, fileDetails.MerchantId, cancellationToken); - if (getContractsResult.IsFailed) - { + Result> getContractsResult = await this.TransactionProcessorClient.GetMerchantContracts(this.TokenResponse.AccessToken, fileDetails.EstateId, fileDetails.MerchantId, cancellationToken); + if (getContractsResult.IsFailed) { return ResultHelpers.CreateFailure(getContractsResult); } List contracts = getContractsResult.Data; - if (contracts.Any() == false) - { + if (contracts.Any() == false) { return Result.NotFound($"No contracts found for Merchant Id {fileDetails.MerchantId} on estate Id {fileDetails.EstateId}"); } ContractResponse? contract = null; - if (fileProfile.OperatorName == "Voucher") - { + if (fileProfile.OperatorName == "Voucher") { contract = contracts.SingleOrDefault(c => c.Description.Contains(operatorName)); } - else - { + else { contract = contracts.SingleOrDefault(c => c.OperatorName == operatorName); } - if (contract == null) - { + if (contract == null) { return Result.NotFound($"No merchant contract for operator Id {operatorName} found for Merchant Id {merchant.MerchantId}"); } ContractProduct? product = contract.Products.SingleOrDefault(p => p.Value == null); // TODO: Is this enough or should the name be used and stored in file profile?? - if (product == null) - { + if (product == null) { return Result.NotFound($"No variable value product found on the merchant contract for operator Id {fileProfile.OperatorName} and Merchant Id {merchant.MerchantId}"); } @@ -393,7 +392,7 @@ public async Task ProcessTransactionForFileLine(FileCommands.ProcessTran EstateId = fileDetails.EstateId, MerchantId = fileDetails.MerchantId, TransactionDateTime = fileDetails.FileReceivedDateTime, - TransactionNumber = FileProcessorDomainService.TransactionNumber.ToString(), + TransactionNumber = TransactionNumber.ToString(), TransactionType = "Sale", ContractId = contract.ContractId, DeviceIdentifier = merchant.Devices.First().Value, @@ -422,19 +421,22 @@ public async Task ProcessTransactionForFileLine(FileCommands.ProcessTran Result result= await this.TransactionProcessorClient.PerformTransaction(this.TokenResponse.AccessToken, serialisedRequestMessage, cancellationToken); if (result.IsFailed) return ResultHelpers.CreateFailure(result); - var serialisedResponseMessage = result.Data; + SerialisedMessage serialisedResponseMessage = result.Data; // Get the sale transaction response SaleTransactionResponse saleTransactionResponse = JsonConvert.DeserializeObject(serialisedResponseMessage.SerialisedData); - if (saleTransactionResponse.ResponseCode == "0000") - { + if (saleTransactionResponse.ResponseCode == "0000") { // record response against file line in file aggregate - fileAggregate.RecordFileLineAsSuccessful(command.LineNumber, saleTransactionResponse.TransactionId); + Result stateResult = fileAggregate.RecordFileLineAsSuccessful(command.LineNumber, saleTransactionResponse.TransactionId); + if (stateResult.IsFailed) + return stateResult; } else { - fileAggregate.RecordFileLineAsFailed(command.LineNumber, saleTransactionResponse.TransactionId, saleTransactionResponse.ResponseCode, saleTransactionResponse.ResponseMessage); + Result stateResult = fileAggregate.RecordFileLineAsFailed(command.LineNumber, saleTransactionResponse.TransactionId, saleTransactionResponse.ResponseCode, saleTransactionResponse.ResponseMessage); + if (stateResult.IsFailed) + return stateResult; } return Result.Success(); @@ -510,7 +512,9 @@ private async Task ProcessFile(Guid fileId, String[] fileLines = fileContent.Split(fileProfile.LineTerminator); foreach (String fileLine in fileLines) { - fileAggregate.AddFileLine(fileLine.Trim()); + Result stateResult = fileAggregate.AddFileLine(fileLine.Trim()); + if (stateResult.IsFailed) + return stateResult; } } @@ -611,35 +615,4 @@ private async Task> GetToken(CancellationToken cancellatio return this.TokenResponse; } -} - -public static class DomainServiceHelper -{ - public static Result HandleGetAggregateResult(Result result, Guid aggregateId, bool isNotFoundError = true) - where T : Aggregate, new() // Constraint: T is a subclass of Aggregate and has a parameterless constructor - { - Logger.LogWarning($"Result is {JsonConvert.SerializeObject(result)}"); - Logger.LogWarning($"aggregateId is {aggregateId}"); - Logger.LogWarning($"isNotFoundError is {isNotFoundError}"); - - if (result.IsFailed && result.Status != ResultStatus.NotFound) { - Logger.LogWarning("In here 1"); - return ResultHelpers.CreateFailure(result); - } - - if (result.Status == ResultStatus.NotFound && isNotFoundError) - { - Logger.LogWarning("In here 2"); - return ResultHelpers.CreateFailure(result); - } - - Logger.LogWarning("In here 3"); - T aggregate = result.Status switch - { - ResultStatus.NotFound => new T { AggregateId = aggregateId }, // Set AggregateId when creating a new instance - _ => result.Data - }; - - return Result.Success(aggregate); - } } \ No newline at end of file diff --git a/FileProcessor.BusinessLogic/Services/IFileProcessorDomainService.cs b/FileProcessor.BusinessLogic/Services/IFileProcessorDomainService.cs index 665ae2a..b83f763 100644 --- a/FileProcessor.BusinessLogic/Services/IFileProcessorDomainService.cs +++ b/FileProcessor.BusinessLogic/Services/IFileProcessorDomainService.cs @@ -9,14 +9,5 @@ namespace FileProcessor.BusinessLogic.Services using MediatR; using Requests; - public interface IFileProcessorDomainService - { - Task> UploadFile(FileCommands.UploadFileCommand command, CancellationToken cancellationToken); - - Task ProcessUploadedFile(FileCommands.ProcessUploadedFileCommand command, - CancellationToken cancellationToken); - - Task ProcessTransactionForFileLine(FileCommands.ProcessTransactionForFileLineCommand command, - CancellationToken cancellationToken); - } + } diff --git a/FileProcessor.FileAggregate.Tests/FileAggregateTests.cs b/FileProcessor.FileAggregate.Tests/FileAggregateTests.cs index 0c6aeab..a93c0ec 100644 --- a/FileProcessor.FileAggregate.Tests/FileAggregateTests.cs +++ b/FileProcessor.FileAggregate.Tests/FileAggregateTests.cs @@ -1,4 +1,5 @@ using System; +using SimpleResults; using Xunit; namespace FileProcessor.FileAggregate.Tests @@ -34,8 +35,9 @@ public void FileAggregate_CanBeCreated_InvalidFileId_IsCreated() public void FileAggregate_CreateFile_FileIsCreated() { FileAggregate fileAggregate = FileAggregate.Create(TestData.FileId); - fileAggregate.CreateFile(TestData.FileImportLogId, TestData.EstateId, TestData.MerchantId, TestData.UserId, + var result = fileAggregate.CreateFile(TestData.FileImportLogId, TestData.EstateId, TestData.MerchantId, TestData.UserId, TestData.FileProfileId, TestData.FileLocation, TestData.FileUploadedDateTime, TestData.SafaricomOperatorId); + result.IsSuccess.ShouldBeTrue(); fileAggregate.IsCreated.ShouldBeTrue(); FileDetails fileDetails = fileAggregate.GetFile(); @@ -59,17 +61,14 @@ public void FileAggregate_CreateFile_FileAlreadyCreated_NoErrorThrown() fileAggregate.CreateFile(TestData.FileImportLogId, TestData.EstateId, TestData.MerchantId, TestData.UserId, TestData.FileProfileId, TestData.FileLocation, TestData.FileUploadedDateTime, TestData.SafaricomOperatorId); - Should.NotThrow(() => - { - - fileAggregate.CreateFile(TestData.FileImportLogId, + var result = fileAggregate.CreateFile(TestData.FileImportLogId, TestData.EstateId, TestData.MerchantId, TestData.UserId, TestData.FileProfileId, TestData.FileLocation, TestData.FileUploadedDateTime, TestData.SafaricomOperatorId); - }); + result.IsSuccess.ShouldBeTrue(); } [Fact] @@ -78,7 +77,8 @@ public void FileAggregate_AddFileLine_FileLineAdded() FileAggregate fileAggregate = FileAggregate.Create(TestData.FileId); fileAggregate.CreateFile(TestData.FileImportLogId, TestData.EstateId, TestData.MerchantId, TestData.UserId, TestData.FileProfileId, TestData.FileLocation, TestData.FileUploadedDateTime, TestData.SafaricomOperatorId); - fileAggregate.AddFileLine(TestData.FileLine); + var result = fileAggregate.AddFileLine(TestData.FileLine); + result.IsSuccess.ShouldBeTrue(); FileDetails fileDetails = fileAggregate.GetFile(); fileDetails.FileLines.ShouldNotBeNull(); @@ -101,7 +101,8 @@ public void FileAggregate_AddFileLine_AddDuplicateLine_FileLineIsNotAddedAdded() fileAggregate.CreateFile(TestData.FileImportLogId, TestData.EstateId, TestData.MerchantId, TestData.UserId, TestData.FileProfileId, TestData.FileLocation, TestData.FileUploadedDateTime, TestData.SafaricomOperatorId); fileAggregate.AddFileLine(TestData.FileLine); - fileAggregate.AddFileLine(TestData.FileLine); + var result = fileAggregate.AddFileLine(TestData.FileLine); + result.IsSuccess.ShouldBeTrue(); FileDetails fileDetails = fileAggregate.GetFile(); fileDetails.FileLines.ShouldNotBeNull(); @@ -111,14 +112,12 @@ public void FileAggregate_AddFileLine_AddDuplicateLine_FileLineIsNotAddedAdded() } [Fact] - public void FileAggregate_AddFileLine_FileNotCreated_FileLineAdded() - { + public void FileAggregate_AddFileLine_FileNotCreated_FileLineAdded() { FileAggregate fileAggregate = FileAggregate.Create(TestData.FileId); - Should.Throw(() => - { - fileAggregate.AddFileLine(TestData.FileLine); - }); + var result = fileAggregate.AddFileLine(TestData.FileLine); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); } [Fact] @@ -128,7 +127,8 @@ public void FileAggregate_RecordFileLineAsSuccessful_FileLineUpdatedAsSuccessful fileAggregate.CreateFile(TestData.FileImportLogId, TestData.EstateId, TestData.MerchantId, TestData.UserId, TestData.FileProfileId, TestData.FileLocation, TestData.FileUploadedDateTime, TestData.SafaricomOperatorId); fileAggregate.AddFileLine(TestData.FileLine); - fileAggregate.RecordFileLineAsSuccessful(TestData.LineNumber, TestData.TransactionId); + var result = fileAggregate.RecordFileLineAsSuccessful(TestData.LineNumber, TestData.TransactionId); + result.IsSuccess.ShouldBeTrue(); FileDetails fileDetails = fileAggregate.GetFile(); fileDetails.FileLines.ShouldNotBeNull(); @@ -152,10 +152,9 @@ public void FileAggregate_RecordFileLineAsSuccessful_FileNotCreated_ErrorThrown( { FileAggregate fileAggregate = FileAggregate.Create(TestData.FileId); - Should.Throw(() => - { - fileAggregate.RecordFileLineAsSuccessful(TestData.LineNumber, TestData.TransactionId); - }); + var result = fileAggregate.RecordFileLineAsSuccessful(TestData.LineNumber, TestData.TransactionId); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); } [Fact] @@ -165,10 +164,9 @@ public void FileAggregate_RecordFileLineAsSuccessful_FileHasNoLine_ErrorThrown() fileAggregate.CreateFile(TestData.FileImportLogId, TestData.EstateId, TestData.MerchantId, TestData.UserId, TestData.FileProfileId, TestData.FileLocation, TestData.FileUploadedDateTime, TestData.SafaricomOperatorId); - Should.Throw(() => - { - fileAggregate.RecordFileLineAsSuccessful(TestData.LineNumber, TestData.TransactionId); - }); + var result = fileAggregate.RecordFileLineAsSuccessful(TestData.LineNumber, TestData.TransactionId); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); } [Fact] @@ -178,10 +176,9 @@ public void FileAggregate_RecordFileLineAsSuccessful_LineNotFound_ErrorThrown() fileAggregate.CreateFile(TestData.FileImportLogId, TestData.EstateId, TestData.MerchantId, TestData.UserId, TestData.FileProfileId, TestData.FileLocation, TestData.FileUploadedDateTime, TestData.SafaricomOperatorId); fileAggregate.AddFileLine(TestData.FileLine); - Should.Throw(() => - { - fileAggregate.RecordFileLineAsSuccessful(TestData.NotFoundLineNumber, TestData.TransactionId); - }); + var result = fileAggregate.RecordFileLineAsSuccessful(TestData.NotFoundLineNumber, TestData.TransactionId); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.NotFound); } [Fact] @@ -191,7 +188,8 @@ public void FileAggregate_RecordFileLineAsFailed_FileLineUpdatedAsFailed() fileAggregate.CreateFile(TestData.FileImportLogId, TestData.EstateId, TestData.MerchantId, TestData.UserId, TestData.FileProfileId, TestData.FileLocation, TestData.FileUploadedDateTime, TestData.SafaricomOperatorId); fileAggregate.AddFileLine(TestData.FileLine); - fileAggregate.RecordFileLineAsFailed(TestData.LineNumber, TestData.TransactionId,TestData.ResponseCodeFailed, TestData.ResponseMessageFailed); + var result = fileAggregate.RecordFileLineAsFailed(TestData.LineNumber, TestData.TransactionId,TestData.ResponseCodeFailed, TestData.ResponseMessageFailed); + result.IsSuccess.ShouldBeTrue(); FileDetails fileDetails = fileAggregate.GetFile(); fileDetails.FileLines.ShouldNotBeNull(); @@ -215,10 +213,10 @@ public void FileAggregate_RecordFileLineAsFailed_FileNotCreated_ErrorThrown() { FileAggregate fileAggregate = FileAggregate.Create(TestData.FileId); - Should.Throw(() => - { - fileAggregate.RecordFileLineAsFailed(TestData.LineNumber, TestData.TransactionId, TestData.ResponseCodeFailed, TestData.ResponseMessageFailed); - }); + var result = fileAggregate.RecordFileLineAsFailed(TestData.LineNumber, TestData.TransactionId, TestData.ResponseCodeFailed, TestData.ResponseMessageFailed); + + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); } [Fact] @@ -228,10 +226,9 @@ public void FileAggregate_RecordFileLineAsFailed_FileHasNoLines_ErrorThrown() fileAggregate.CreateFile(TestData.FileImportLogId, TestData.EstateId, TestData.MerchantId, TestData.UserId, TestData.FileProfileId, TestData.FileLocation, TestData.FileUploadedDateTime, TestData.SafaricomOperatorId); - Should.Throw(() => - { - fileAggregate.RecordFileLineAsFailed(TestData.LineNumber, TestData.TransactionId, TestData.ResponseCodeFailed, TestData.ResponseMessageFailed); - }); + var result = fileAggregate.RecordFileLineAsFailed(TestData.LineNumber, TestData.TransactionId, TestData.ResponseCodeFailed, TestData.ResponseMessageFailed); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); } [Fact] @@ -241,10 +238,10 @@ public void FileAggregate_RecordFileLineAsFailed_LineNotFound_ErrorThrown() fileAggregate.CreateFile(TestData.FileImportLogId, TestData.EstateId, TestData.MerchantId, TestData.UserId, TestData.FileProfileId, TestData.FileLocation, TestData.FileUploadedDateTime, TestData.SafaricomOperatorId); fileAggregate.AddFileLine(TestData.FileLine); - Should.Throw(() => - { - fileAggregate.RecordFileLineAsFailed(TestData.NotFoundLineNumber, TestData.TransactionId, TestData.ResponseCodeFailed, TestData.ResponseMessageFailed); - }); + var result = fileAggregate.RecordFileLineAsFailed(TestData.NotFoundLineNumber, TestData.TransactionId, TestData.ResponseCodeFailed, TestData.ResponseMessageFailed); + + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.NotFound); } [Fact] @@ -254,7 +251,8 @@ public void FileAggregate_RecordFileLineAsIgnored_FileLineUpdatedAsIgnored() fileAggregate.CreateFile(TestData.FileImportLogId, TestData.EstateId, TestData.MerchantId, TestData.UserId, TestData.FileProfileId, TestData.FileLocation, TestData.FileUploadedDateTime, TestData.SafaricomOperatorId); fileAggregate.AddFileLine(TestData.FileLine); - fileAggregate.RecordFileLineAsIgnored(TestData.LineNumber); + var result = fileAggregate.RecordFileLineAsIgnored(TestData.LineNumber); + result.IsSuccess.ShouldBeTrue(); FileDetails fileDetails = fileAggregate.GetFile(); fileDetails.FileLines.ShouldNotBeNull(); @@ -277,10 +275,10 @@ public void FileAggregate_RecordFileLineAsIgnored_FileNotCreated_ErrorThrown() { FileAggregate fileAggregate = FileAggregate.Create(TestData.FileId); - Should.Throw(() => - { - fileAggregate.RecordFileLineAsIgnored(TestData.LineNumber); - }); + var result = fileAggregate.RecordFileLineAsIgnored(TestData.LineNumber); + + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); } [Fact] @@ -290,10 +288,10 @@ public void FileAggregate_FileAggregate_RecordFileLineAsIgnored_FileHasNoLine_Er fileAggregate.CreateFile(TestData.FileImportLogId, TestData.EstateId, TestData.MerchantId, TestData.UserId, TestData.FileProfileId, TestData.FileLocation, TestData.FileUploadedDateTime, TestData.SafaricomOperatorId); - Should.Throw(() => - { - fileAggregate.RecordFileLineAsIgnored(TestData.LineNumber); - }); + var result = fileAggregate.RecordFileLineAsIgnored(TestData.LineNumber); + + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); } [Fact] @@ -303,10 +301,10 @@ public void FileAggregate_RecordFileLineAsIgnored_LineNotFound_ErrorThrown() fileAggregate.CreateFile(TestData.FileImportLogId, TestData.EstateId, TestData.MerchantId, TestData.UserId, TestData.FileProfileId, TestData.FileLocation, TestData.FileUploadedDateTime, TestData.SafaricomOperatorId); fileAggregate.AddFileLine(TestData.FileLine); - Should.Throw(() => - { - fileAggregate.RecordFileLineAsIgnored(TestData.NotFoundLineNumber); - }); + var result = fileAggregate.RecordFileLineAsIgnored(TestData.NotFoundLineNumber); + + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.NotFound); } @@ -318,7 +316,8 @@ public void FileAggregate_RecordFileLineAsRejected_FileLineUpdatedAsRejected() fileAggregate.CreateFile(TestData.FileImportLogId, TestData.EstateId, TestData.MerchantId, TestData.UserId, TestData.FileProfileId, TestData.FileLocation, TestData.FileUploadedDateTime, TestData.SafaricomOperatorId); fileAggregate.AddFileLine(TestData.FileLine); - fileAggregate.RecordFileLineAsRejected(TestData.LineNumber,TestData.RejectionReason); + var result = fileAggregate.RecordFileLineAsRejected(TestData.LineNumber, TestData.RejectionReason); + result.IsSuccess.ShouldBeTrue(); FileDetails fileDetails = fileAggregate.GetFile(); fileDetails.FileLines.ShouldNotBeNull(); @@ -343,10 +342,10 @@ public void FileAggregate_RecordFileLineAsRejected_FileNotCreated_ErrorThrown() { FileAggregate fileAggregate = FileAggregate.Create(TestData.FileId); - Should.Throw(() => - { - fileAggregate.RecordFileLineAsRejected(TestData.LineNumber,TestData.RejectionReason); - }); + var result = fileAggregate.RecordFileLineAsRejected(TestData.LineNumber,TestData.RejectionReason); + + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); } [Fact] @@ -356,10 +355,10 @@ public void FileAggregate_RecordFileLineAsRejected_FileHasNoLine_ErrorThrown() fileAggregate.CreateFile(TestData.FileImportLogId, TestData.EstateId, TestData.MerchantId, TestData.UserId, TestData.FileProfileId, TestData.FileLocation, TestData.FileUploadedDateTime, TestData.SafaricomOperatorId); - Should.Throw(() => - { - fileAggregate.RecordFileLineAsRejected(TestData.LineNumber,TestData.RejectionReason); - }); + var result = fileAggregate.RecordFileLineAsRejected(TestData.LineNumber,TestData.RejectionReason); + + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); } [Fact] @@ -369,10 +368,10 @@ public void FileAggregate_RecordFileLineAsRejected_LineNotFound_ErrorThrown() fileAggregate.CreateFile(TestData.FileImportLogId, TestData.EstateId, TestData.MerchantId, TestData.UserId, TestData.FileProfileId, TestData.FileLocation, TestData.FileUploadedDateTime, TestData.SafaricomOperatorId); fileAggregate.AddFileLine(TestData.FileLine); - Should.Throw(() => - { - fileAggregate.RecordFileLineAsRejected(TestData.NotFoundLineNumber, TestData.RejectionReason); - }); + var result = fileAggregate.RecordFileLineAsRejected(TestData.NotFoundLineNumber, TestData.RejectionReason); + + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.NotFound); } } } diff --git a/FileProcessor.FileAggregate/FileAggregate.cs b/FileProcessor.FileAggregate/FileAggregate.cs index fe7a0ce..0002df0 100644 --- a/FileProcessor.FileAggregate/FileAggregate.cs +++ b/FileProcessor.FileAggregate/FileAggregate.cs @@ -1,5 +1,6 @@ using System; using FileProcessor.Models; +using SimpleResults; namespace FileProcessor.FileAggregate { @@ -98,113 +99,119 @@ public static void PlayEvent(this FileAggregate aggregate, FileProcessingComplet aggregate.IsCompleted = true; } - public static void CreateFile(this FileAggregate aggregate, Guid fileImportLogId, Guid estateId, Guid merchantId, Guid userId, Guid fileProfileId, String fileLocation, DateTime fileReceivedDateTime, Guid operatorId) + public static Result CreateFile(this FileAggregate aggregate, Guid fileImportLogId, Guid estateId, Guid merchantId, Guid userId, Guid fileProfileId, String fileLocation, DateTime fileReceivedDateTime, Guid operatorId) { if (aggregate.IsCreated) - return; + return Result.Success(); - FileCreatedEvent fileCreatedEvent = new FileCreatedEvent(aggregate.AggregateId, fileImportLogId, estateId, merchantId, userId, fileProfileId, fileLocation, fileReceivedDateTime, operatorId); + FileCreatedEvent fileCreatedEvent = new(aggregate.AggregateId, fileImportLogId, estateId, merchantId, userId, fileProfileId, fileLocation, fileReceivedDateTime, operatorId); aggregate.ApplyAndAppend(fileCreatedEvent); + + return Result.Success(); } - public static void AddFileLine(this FileAggregate aggregate, String fileLine) + public static Result AddFileLine(this FileAggregate aggregate, String fileLine) { - if (aggregate.IsCreated == false) - { - throw new InvalidOperationException($"File Id {aggregate.AggregateId} has not been uploaded yet"); + if (aggregate.IsCreated == false) { + return Result.Invalid($"File Id {aggregate.AggregateId} has not been uploaded yet"); } Boolean lineAlreadyExists = aggregate.FileLines.Any(f => f.LineData == fileLine); // We already have this line so just return if (lineAlreadyExists) - return; + return Result.Success(); Int32 lineNumber = aggregate.FileLines.Count + 1; - FileLineAddedEvent fileLineAddedEvent = new FileLineAddedEvent(aggregate.AggregateId, aggregate.EstateId, aggregate.MerchantId, lineNumber, fileLine); + FileLineAddedEvent fileLineAddedEvent = new(aggregate.AggregateId, aggregate.EstateId, aggregate.MerchantId, lineNumber, fileLine); aggregate.ApplyAndAppend(fileLineAddedEvent); + return Result.Success(); } - public static void RecordFileLineAsIgnored(this FileAggregate aggregate, Int32 lineNumber) + public static Result RecordFileLineAsIgnored(this FileAggregate aggregate, Int32 lineNumber) { if (aggregate.FileLines.Any() == false) { - throw new InvalidOperationException("File has no lines to mark as ignored"); + return Result.Invalid("File has no lines to mark as ignored"); } if (aggregate.FileLines.SingleOrDefault(l => l.LineNumber == lineNumber) == null) { - throw new NotFoundException($"File line with number {lineNumber} not found to mark as ignored"); + return Result.NotFound($"File line with number {lineNumber} not found to mark as ignored"); } - FileLineProcessingIgnoredEvent fileLineProcessingIgnoredEvent = - new FileLineProcessingIgnoredEvent(aggregate.AggregateId, aggregate.EstateId, aggregate.MerchantId, lineNumber); + FileLineProcessingIgnoredEvent fileLineProcessingIgnoredEvent = new(aggregate.AggregateId, aggregate.EstateId, aggregate.MerchantId, lineNumber); aggregate.ApplyAndAppend(fileLineProcessingIgnoredEvent); aggregate.CompletedChecks(); + + return Result.Success(); } - public static void RecordFileLineAsRejected(this FileAggregate aggregate, Int32 lineNumber, String reason) + public static Result RecordFileLineAsRejected(this FileAggregate aggregate, Int32 lineNumber, String reason) { if (aggregate.FileLines.Any() == false) { - throw new InvalidOperationException("File has no lines to mark as rejected"); + return Result.Invalid("File has no lines to mark as rejected"); } if (aggregate.FileLines.SingleOrDefault(l => l.LineNumber == lineNumber) == null) { - throw new NotFoundException($"File line with number {lineNumber} not found to mark as rejected"); + return Result.NotFound($"File line with number {lineNumber} not found to mark as rejected"); } - FileLineProcessingRejectedEvent fileLineProcessingRejectedEvent = - new FileLineProcessingRejectedEvent(aggregate.AggregateId, aggregate.EstateId, aggregate.MerchantId, lineNumber, reason); + FileLineProcessingRejectedEvent fileLineProcessingRejectedEvent = new(aggregate.AggregateId, aggregate.EstateId, aggregate.MerchantId, lineNumber, reason); aggregate.ApplyAndAppend(fileLineProcessingRejectedEvent); aggregate.CompletedChecks(); + + return Result.Success(); } - public static void RecordFileLineAsSuccessful(this FileAggregate aggregate, Int32 lineNumber, Guid transactionId) + public static Result RecordFileLineAsSuccessful(this FileAggregate aggregate, Int32 lineNumber, Guid transactionId) { if (aggregate.FileLines.Any() == false) { - throw new InvalidOperationException("File has no lines to mark as successful"); + return Result.Invalid("File has no lines to mark as successful"); } if (aggregate.FileLines.SingleOrDefault(l => l.LineNumber == lineNumber) == null) { - throw new NotFoundException($"File line with number {lineNumber} not found to mark as successful"); + return Result.NotFound($"File line with number {lineNumber} not found to mark as successful"); } - FileLineProcessingSuccessfulEvent fileLineProcessingSuccessfulEvent = - new FileLineProcessingSuccessfulEvent(aggregate.AggregateId, aggregate.EstateId,aggregate.MerchantId, lineNumber, transactionId); + FileLineProcessingSuccessfulEvent fileLineProcessingSuccessfulEvent = new(aggregate.AggregateId, aggregate.EstateId, aggregate.MerchantId, lineNumber, transactionId); aggregate.ApplyAndAppend(fileLineProcessingSuccessfulEvent); aggregate.CompletedChecks(); + + return Result.Success(); } - public static void RecordFileLineAsFailed(this FileAggregate aggregate,Int32 lineNumber, Guid transactionId, String responseCode, String responseMessage) + public static Result RecordFileLineAsFailed(this FileAggregate aggregate,Int32 lineNumber, Guid transactionId, String responseCode, String responseMessage) { if (aggregate.FileLines.Any() == false) { - throw new InvalidOperationException("File has no lines to mark as failed"); + return Result.Invalid("File has no lines to mark as failed"); } if (aggregate.FileLines.SingleOrDefault(l => l.LineNumber == lineNumber) == null) { - throw new NotFoundException($"File line with number {lineNumber} not found to mark as failed"); + return Result.NotFound($"File line with number {lineNumber} not found to mark as failed"); } - FileLineProcessingFailedEvent fileLineProcessingFailedEvent = - new FileLineProcessingFailedEvent(aggregate.AggregateId, aggregate.EstateId, aggregate.MerchantId, lineNumber, transactionId, responseCode, responseMessage); + FileLineProcessingFailedEvent fileLineProcessingFailedEvent = new(aggregate.AggregateId, aggregate.EstateId, aggregate.MerchantId, lineNumber, transactionId, responseCode, responseMessage); aggregate.ApplyAndAppend(fileLineProcessingFailedEvent); aggregate.CompletedChecks(); + + return Result.Success(); } ///