diff --git a/FIleProcessor.Models/FileImportLogQueryResult.cs b/FIleProcessor.Models/FileImportLogQueryResult.cs new file mode 100644 index 0000000..bdf3b6f --- /dev/null +++ b/FIleProcessor.Models/FileImportLogQueryResult.cs @@ -0,0 +1,17 @@ +namespace FileProcessor.Models +{ + using System.Collections.Generic; + + public class FileImportLogQueryResult + { + public List FileImportLogs { get; set; } = new(); + + public int PageNumber { get; set; } + + public int PageSize { get; set; } + + public int TotalCount { get; set; } + + public bool HasMore => PageNumber * PageSize < TotalCount; + } +} diff --git a/FIleProcessor.Models/FileLine.cs b/FIleProcessor.Models/FileLine.cs index db06d06..fb08964 100644 --- a/FIleProcessor.Models/FileLine.cs +++ b/FIleProcessor.Models/FileLine.cs @@ -17,6 +17,10 @@ public class FileLine public String RejectedReason { get; set; } + public String FailureReason { get; set; } + + public String ResponseCode { get; set; } + public Int32 DispatchAttemptCount { get; set; } public List FailedDispatchAttempts { get; set; } = new(); diff --git a/FileProcessor.BusinessLogic.Tests/DummyFileProcessorDomainService.cs b/FileProcessor.BusinessLogic.Tests/DummyFileProcessorDomainService.cs index ab7de3c..a0a5323 100644 --- a/FileProcessor.BusinessLogic.Tests/DummyFileProcessorDomainService.cs +++ b/FileProcessor.BusinessLogic.Tests/DummyFileProcessorDomainService.cs @@ -38,11 +38,14 @@ public async Task> GetFileProfile(Guid fileProfileId, return Result.Success(); } - public async Task>> GetFileImportLogs(Guid estateId, - DateTime startDateTime, - DateTime endDateTime, - Guid? merchantId, - CancellationToken cancellationToken) { + public async Task> GetFileImportLogs(Guid estateId, + DateOnly startDate, + DateOnly endDate, + Guid? merchantId, + Int32 pageNumber, + Int32 pageSize, + Boolean descending, + CancellationToken cancellationToken) { return Result.Success(); } diff --git a/FileProcessor.BusinessLogic.Tests/FileProcessingManagerTests.cs b/FileProcessor.BusinessLogic.Tests/FileProcessingManagerTests.cs index e7bf07b..45066dc 100644 --- a/FileProcessor.BusinessLogic.Tests/FileProcessingManagerTests.cs +++ b/FileProcessor.BusinessLogic.Tests/FileProcessingManagerTests.cs @@ -100,9 +100,9 @@ public async Task FileProcessingManager_GetFileImportLogs_NoMerchantId_ImportLog this.Context.Merchants.Add(new Merchant { MerchantId = TestData.MerchantId, Name = TestData.MerchantName }); await this.Context.SaveChangesAsync(); - Result> getFileImportLogsResult = await this.Manager.GetFileImportLogs(TestData.EstateId, TestData.ImportLogStartDate, TestData.ImportLogEndDate, null, CancellationToken.None); + Result getFileImportLogsResult = await this.Manager.GetFileImportLogs(TestData.EstateId, DateOnly.FromDateTime(TestData.ImportLogStartDate), DateOnly.FromDateTime(TestData.ImportLogEndDate), null, 1, 50, false, CancellationToken.None); getFileImportLogsResult.IsSuccess.ShouldBeTrue(); - List importLogs = getFileImportLogsResult.Data; + List importLogs = getFileImportLogsResult.Data.FileImportLogs; this.VerifyImportLogs(TestData.FileImportLogs,importLogs); } @@ -116,9 +116,9 @@ public async Task FileProcessingManager_GetFileImportLogs_WithMerchantId_ImportL this.Context.Merchants.Add(new Merchant { MerchantId = TestData.MerchantId, Name = TestData.MerchantName }); await this.Context.SaveChangesAsync(); - Result> importLogs = await this.Manager.GetFileImportLogs(TestData.EstateId, TestData.ImportLogStartDate, TestData.ImportLogEndDate, TestData.MerchantId, CancellationToken.None); + Result importLogsResult = await this.Manager.GetFileImportLogs(TestData.EstateId, DateOnly.FromDateTime(TestData.ImportLogStartDate), DateOnly.FromDateTime(TestData.ImportLogEndDate), TestData.MerchantId, 1, 50, false, CancellationToken.None); - this.VerifyImportLogs(TestData.FileImportLogs,importLogs, TestData.MerchantId); + this.VerifyImportLogs(TestData.FileImportLogs, importLogsResult.Data.FileImportLogs, TestData.MerchantId); } [Fact] @@ -151,6 +151,49 @@ public async Task FileProcessingManager_GetFileImportLog_WithMerchantId_ImportLo this.VerifyImportLog(TestData.FileImportLogs.First(),importLog, TestData.MerchantId); } + [Fact] + public async Task FileProcessingManager_GetFileImportLogs_DateOnlyRangeIsInclusiveAndPaged() + { + this.Context.FileImportLogs.AddRange(TestData.FileImportLogs); + this.Context.FileImportLogFiles.AddRange(TestData.FileImportLog1Files); + this.Context.FileImportLogFiles.AddRange(TestData.FileImportLog2Files); + this.Context.Merchants.Add(new Merchant { MerchantId = TestData.MerchantId, Name = TestData.MerchantName }); + await this.Context.SaveChangesAsync(); + + Result result = await this.Manager.GetFileImportLogs( + TestData.EstateId, + DateOnly.FromDateTime(TestData.ImportLogStartDate), + DateOnly.FromDateTime(TestData.ImportLogEndDate), + null, + 1, + 1, + false, + CancellationToken.None); + + result.IsSuccess.ShouldBeTrue(); + result.Data.FileImportLogs.ShouldHaveSingleItem(); + result.Data.FileImportLogs.Single().FileImportLogId.ShouldBe(TestData.FileImportLogId1); + result.Data.TotalCount.ShouldBe(2); + result.Data.HasMore.ShouldBeTrue(); + } + + [Fact] + public async Task FileProcessingManager_GetFileImportLog_FilesAreScopedToRequestedImportLog() + { + this.Context.FileImportLogs.AddRange(TestData.FileImportLogs); + this.Context.FileImportLogFiles.AddRange(TestData.FileImportLog1Files); + this.Context.FileImportLogFiles.AddRange(TestData.FileImportLog2Files); + this.Context.Merchants.Add(new Merchant { MerchantId = TestData.MerchantId, Name = TestData.MerchantName }); + this.Context.Files.AddRange(TestData.Files1); + await this.Context.SaveChangesAsync(); + + Result result = await this.Manager.GetFileImportLog(TestData.FileImportLogId1, TestData.EstateId, null, CancellationToken.None); + + result.IsSuccess.ShouldBeTrue(); + result.Data.Files.ShouldNotBeEmpty(); + result.Data.Files.ShouldAllBe(file => TestData.FileImportLog1Files.Any(expected => expected.FileId == file.FileId)); + } + [Fact] public async Task FileProcessingManager_GetFileImportLogForFile_ReturnsEntryWithoutFileReadModelRow() { diff --git a/FileProcessor.BusinessLogic/Managers/FileProcessorManager.cs b/FileProcessor.BusinessLogic/Managers/FileProcessorManager.cs index e8fbeda..14ec124 100644 --- a/FileProcessor.BusinessLogic/Managers/FileProcessorManager.cs +++ b/FileProcessor.BusinessLogic/Managers/FileProcessorManager.cs @@ -83,16 +83,39 @@ private async Task GetContext(Guid estateId) } - public async Task>> GetFileImportLogs(Guid estateId, - DateTime startDateTime, - DateTime endDateTime, + public async Task> GetFileImportLogs(Guid estateId, + DateOnly startDate, + DateOnly endDate, Guid? merchantId, + Int32 pageNumber, + Int32 pageSize, + Boolean descending, CancellationToken cancellationToken) { + if (pageNumber < 1 || pageSize < 1 || pageSize > 200) + return Result.Invalid("Page number must be at least 1 and page size must be between 1 and 200"); + + if (endDate < startDate) + return Result.Invalid("End date must be on or after start date"); + + DateTime startDateTime = startDate.ToDateTime(TimeOnly.MinValue, DateTimeKind.Utc); + DateTime endDateTime = endDate.AddDays(1).ToDateTime(TimeOnly.MinValue, DateTimeKind.Utc); + EstateManagementContext context = await this.GetContext(estateId); + IQueryable importLogs = context.FileImportLogs + .Where(f => f.EstateId == estateId && f.ImportLogDateTime >= startDateTime && f.ImportLogDateTime < endDateTime); + + if (descending) + importLogs = importLogs.OrderByDescending(f => f.ImportLogDateTime).ThenByDescending(f => f.FileImportLogId); + else + importLogs = importLogs.OrderBy(f => f.ImportLogDateTime).ThenBy(f => f.FileImportLogId); + + Int32 totalCount = await importLogs.CountAsync(cancellationToken); List importLogQuery = - await context.FileImportLogs.Where(f => f.ImportLogDateTime >= startDateTime).ToListAsync(cancellationToken); + await importLogs.Skip((pageNumber - 1) * pageSize).Take(pageSize).ToListAsync(cancellationToken); + + Guid[] importLogIds = importLogQuery.Select(f => f.FileImportLogId).ToArray(); var importLogFileQuery = await context.FileImportLogFiles .Join(context.Files, @@ -109,7 +132,7 @@ public async Task>> GetFileImportLogs(Guid estateId, file, merchant }) - .Where(fi => importLogQuery.Select(f => f.FileImportLogId).Contains(fi.file.fileImportLogFile.FileImportLogId)) + .Where(fi => importLogIds.Contains(fi.file.fileImportLogFile.FileImportLogId)) .ToListAsync(cancellationToken); if (merchantId.HasValue){ @@ -122,7 +145,13 @@ public async Task>> GetFileImportLogs(Guid estateId, } List model = this.ModelFactory.ConvertFrom(estateId, importLogQuery, entityData); - return Result.Success(model); + return Result.Success(new FileImportLogQueryResult + { + FileImportLogs = model, + PageNumber = pageNumber, + PageSize = pageSize, + TotalCount = totalCount + }); } public async Task> GetFileImportLog(Guid fileImportLogId, @@ -140,6 +169,7 @@ public async Task> GetFileImportLog(Guid fileImportLogId, var query = from fileImportLogFile in context.FileImportLogFiles join file in context.Files on fileImportLogFile.FileId equals file.FileId join merchant in context.Merchants on file.MerchantId equals merchant.MerchantId + where fileImportLogFile.FileImportLogId == fileImportLogId select new { fileImportLogFile, file, merchant }; @@ -152,6 +182,9 @@ join merchant in context.Merchants on file.MerchantId equals merchant.MerchantId // Enumerate at the end var importLogFileQuery = await query.ToListAsync(cancellationToken); + if (importLogQuery == null || importLogQuery.EstateId != estateId) + return Result.NotFound($"No import log found for Id [{fileImportLogId}]"); + List<(FileImportLogFile, TransactionProcessor.Database.Entities.File,Merchant)> entityData = new List<(FileImportLogFile, TransactionProcessor.Database.Entities.File, Merchant)>(); foreach (var file in importLogFileQuery) { diff --git a/FileProcessor.BusinessLogic/Managers/IFileProcessorManager.cs b/FileProcessor.BusinessLogic/Managers/IFileProcessorManager.cs index fb3a3aa..77b194e 100644 --- a/FileProcessor.BusinessLogic/Managers/IFileProcessorManager.cs +++ b/FileProcessor.BusinessLogic/Managers/IFileProcessorManager.cs @@ -20,7 +20,7 @@ public interface IFileProcessorManager Task> GetFileProfile(Guid fileProfileId, CancellationToken cancellationToken); - Task>> GetFileImportLogs(Guid estateId, DateTime startDateTime, DateTime endDateTime, Guid? merchantId, CancellationToken cancellationToken); + Task> GetFileImportLogs(Guid estateId, DateOnly startDate, DateOnly endDate, Guid? merchantId, Int32 pageNumber, Int32 pageSize, Boolean descending, CancellationToken cancellationToken); Task> GetFileImportLog(Guid fileImportLogId, Guid estateId, Guid? merchantId, CancellationToken cancellationToken); diff --git a/FileProcessor.BusinessLogic/RequestHandlers/FileRequestHandler.cs b/FileProcessor.BusinessLogic/RequestHandlers/FileRequestHandler.cs index a7a29fe..ed9587c 100644 --- a/FileProcessor.BusinessLogic/RequestHandlers/FileRequestHandler.cs +++ b/FileProcessor.BusinessLogic/RequestHandlers/FileRequestHandler.cs @@ -16,7 +16,7 @@ public class FileRequestHandler : IRequestHandler, IRequestHandler, IRequestHandler>, - IRequestHandler>>, + IRequestHandler>, IRequestHandler>, IRequestHandler { @@ -48,9 +48,9 @@ public async Task> Handle(FileQueries.GetFileQuery query, return await this.Manager.GetFile(query.FileId, query.EstateId, cancellationToken); } - public async Task>> Handle(FileQueries.GetImportLogsQuery query, + public async Task> Handle(FileQueries.GetImportLogsQuery query, CancellationToken cancellationToken) { - return await this.Manager.GetFileImportLogs(query.EstateId, query.StartDateTime, query.EndDateTime, query.MerchantId, cancellationToken); + return await this.Manager.GetFileImportLogs(query.EstateId, query.StartDate, query.EndDate, query.MerchantId, query.PageNumber, query.PageSize, query.Descending, cancellationToken); } public async Task> Handle(FileQueries.GetImportLogQuery query, diff --git a/FileProcessor.BusinessLogic/Requests/FileQueries.cs b/FileProcessor.BusinessLogic/Requests/FileQueries.cs index 7916629..63112c2 100644 --- a/FileProcessor.BusinessLogic/Requests/FileQueries.cs +++ b/FileProcessor.BusinessLogic/Requests/FileQueries.cs @@ -11,9 +11,9 @@ namespace FileProcessor.BusinessLogic.Requests; public record FileQueries { public record GetFileQuery(Guid FileId, Guid EstateId) : IRequest>; - public record GetImportLogsQuery(Guid EstateId, DateTime StartDateTime, DateTime EndDateTime, Guid? MerchantId) : IRequest>>; + public record GetImportLogsQuery(Guid EstateId, DateOnly StartDate, DateOnly EndDate, Guid? MerchantId, Int32 PageNumber = 1, Int32 PageSize = 50, Boolean Descending = false) : IRequest>; public record GetImportLogQuery(Guid FileImportLogId, Guid EstateId, Guid? MerchantId) : IRequest>; -} \ No newline at end of file +} diff --git a/FileProcessor.Client/FileProcessorClient.cs b/FileProcessor.Client/FileProcessorClient.cs index 3ac4d6d..e5539e4 100644 --- a/FileProcessor.Client/FileProcessorClient.cs +++ b/FileProcessor.Client/FileProcessorClient.cs @@ -180,39 +180,28 @@ public async Task> GetFileImportLog(String accessToken, /// /// The access token. /// The estate identifier. - /// The start date time. - /// The end date time. + /// The first calendar date. + /// The last calendar date. /// The merchant identifier. /// The cancellation token. /// public async Task> GetFileImportLogs(String accessToken, Guid estateId, - DateTime startDateTime, - DateTime endDateTime, + DateOnly startDate, + DateOnly endDate, Guid? merchantId, + Int32 pageNumber, + Int32 pageSize, + Boolean descending, CancellationToken cancellationToken) { - String requestUri = - this.BuildRequestUrl( - $"/api/fileImportLogs?estateId={estateId}&startDateTime={startDateTime.Date:yyyy-MM-dd}&endDateTime={endDateTime.Date:yyyy-MM-dd}"); + String requestUri = this.BuildRequestUrl( + $"/api/fileImportLogs?estateId={estateId}&startDate={startDate:yyyy-MM-dd}&endDate={endDate:yyyy-MM-dd}&pageNumber={pageNumber}&pageSize={pageSize}&descending={descending}"); - if (merchantId.HasValue) { + if (merchantId.HasValue) requestUri += $"&merchantId={merchantId}"; - } - - try { - Result result = await this.Get(requestUri, accessToken, cancellationToken); - - if (result.IsFailed) - return ResultHelpers.CreateFailure(result); - return result; - } - catch (Exception ex) { - // An exception has occurred, add some additional information to the message - Exception exception = new Exception("Error getting list of file import logs.", ex); - - throw exception; - } + Result result = await this.Get(requestUri, accessToken, cancellationToken); + return result.IsFailed ? ResultHelpers.CreateFailure(result) : result; } /// diff --git a/FileProcessor.Client/IFileProcessorClient.cs b/FileProcessor.Client/IFileProcessorClient.cs index 3d9b516..861c484 100644 --- a/FileProcessor.Client/IFileProcessorClient.cs +++ b/FileProcessor.Client/IFileProcessorClient.cs @@ -72,16 +72,19 @@ Task> GetFileImportLog(String accessToken, /// /// The access token. /// The estate identifier. - /// The start date time. - /// The end date time. + /// The first calendar date. + /// The last calendar date. /// The merchant identifier. /// The cancellation token. /// Task> GetFileImportLogs(String accessToken, Guid estateId, - DateTime startDateTime, - DateTime endDateTime, + DateOnly startDate, + DateOnly endDate, Guid? merchantId, + Int32 pageNumber, + Int32 pageSize, + Boolean descending, CancellationToken cancellationToken); /// diff --git a/FileProcessor.DataTransferObjects/Responses/FileImportLogList.cs b/FileProcessor.DataTransferObjects/Responses/FileImportLogList.cs index c621ab7..eadb0d1 100644 --- a/FileProcessor.DataTransferObjects/Responses/FileImportLogList.cs +++ b/FileProcessor.DataTransferObjects/Responses/FileImportLogList.cs @@ -11,6 +11,14 @@ public class FileImportLogList public List FileImportLogs { get; set; } + public int PageNumber { get; set; } + + public int PageSize { get; set; } + + public int TotalCount { get; set; } + + public bool HasMore { get; set; } + #endregion } -} \ No newline at end of file +} diff --git a/FileProcessor.DataTransferObjects/Responses/FileLine.cs b/FileProcessor.DataTransferObjects/Responses/FileLine.cs index 074c8c5..51561ad 100644 --- a/FileProcessor.DataTransferObjects/Responses/FileLine.cs +++ b/FileProcessor.DataTransferObjects/Responses/FileLine.cs @@ -1,6 +1,7 @@ namespace FileProcessor.DataTransferObjects.Responses { using System; + using System.Collections.Generic; public class FileLine { @@ -11,6 +12,16 @@ public class FileLine public Guid TransactionId { get; set; } + public Guid EventId { get; set; } + public String RejectionReason { get; set; } + + public String FailureReason { get; set; } + + public String ResponseCode { get; set; } + + public Int32 DispatchAttemptCount { get; set; } + + public List FailedDispatchAttempts { get; set; } = new(); } -} \ No newline at end of file +} diff --git a/FileProcessor.DataTransferObjects/Responses/TransactionDispatchAttempt.cs b/FileProcessor.DataTransferObjects/Responses/TransactionDispatchAttempt.cs new file mode 100644 index 0000000..f604a75 --- /dev/null +++ b/FileProcessor.DataTransferObjects/Responses/TransactionDispatchAttempt.cs @@ -0,0 +1,13 @@ +namespace FileProcessor.DataTransferObjects.Responses +{ + using System; + + public class TransactionDispatchAttempt + { + public Int32 TransactionNumber { get; set; } + + public String FailureType { get; set; } + + public DateTime AttemptedAt { get; set; } + } +} diff --git a/FileProcessor.FileAggregate/FileAggregate.cs b/FileProcessor.FileAggregate/FileAggregate.cs index 0cd4561..5c7b96d 100644 --- a/FileProcessor.FileAggregate/FileAggregate.cs +++ b/FileProcessor.FileAggregate/FileAggregate.cs @@ -100,6 +100,8 @@ public static void PlayEvent(this FileAggregate aggregate, FileLineProcessingFai FileLine fileLine = aggregate.FileLines.Single(f => f.LineNumber == domainEvent.LineNumber); fileLine.TransactionId = domainEvent.TransactionId; fileLine.ProcessingResult = ProcessingResult.Failed; + fileLine.ResponseCode = domainEvent.ResponseCode; + fileLine.FailureReason = domainEvent.ResponseMessage; fileLine.DispatchAttemptCount++; } diff --git a/FileProcessor.IntegrationTesting.Helpers/FileProcessorSteps.cs b/FileProcessor.IntegrationTesting.Helpers/FileProcessorSteps.cs index 710bf85..7eb6673 100644 --- a/FileProcessor.IntegrationTesting.Helpers/FileProcessorSteps.cs +++ b/FileProcessor.IntegrationTesting.Helpers/FileProcessorSteps.cs @@ -138,9 +138,12 @@ public async Task WhenIGetTheImportLogsBetweenAndTheFollowingDataIsReturned(Stri await Retry.For(async () => { var getFileImportLogsResult = await this.FileProcessorClient.GetFileImportLogs(accessToken, estate.EstateDetails.EstateId, - queryStartDate, - queryEndDate, + DateOnly.FromDateTime(queryStartDate), + DateOnly.FromDateTime(queryEndDate), null, + 1, + 50, + false, CancellationToken.None); getFileImportLogsResult.IsSuccess.ShouldBeTrue(); FileImportLogList importLogList = getFileImportLogsResult.Data; @@ -165,9 +168,12 @@ public async Task WhenIGetTheImportLogForTheFollowingFileInformationIsReturned(S DateTime queryStartDate = ReqnrollTableHelper.GetDateForDateString(startDate, DateTime.Now); var importLogListResult = await this.FileProcessorClient.GetFileImportLogs(accessToken, estate.EstateDetails.EstateId, - queryStartDate, - queryStartDate, + DateOnly.FromDateTime(queryStartDate), + DateOnly.FromDateTime(queryStartDate), null, + 1, + 50, + false, CancellationToken.None); importLogListResult.IsSuccess.ShouldBeTrue(); var importLogList = importLogListResult.Data; @@ -205,9 +211,12 @@ public async Task WhenIGetTheImportLogForEstateTheDateOnTheImportLogIs(String ac var getFileImportLogsResult = await this.FileProcessorClient.GetFileImportLogs(accessToken, estate.EstateDetails.EstateId, - expectedDate.AddDays(-1), - DateTime.Now, + DateOnly.FromDateTime(expectedDate.AddDays(-1)), + DateOnly.FromDateTime(DateTime.Now), null, + 1, + 50, + false, CancellationToken.None); getFileImportLogsResult.IsSuccess.ShouldBeTrue(); diff --git a/FileProcessor.Testing/TestData.cs b/FileProcessor.Testing/TestData.cs index 9943594..6edd3e6 100644 --- a/FileProcessor.Testing/TestData.cs +++ b/FileProcessor.Testing/TestData.cs @@ -868,7 +868,7 @@ public static List GetMerchantContractsResponseNoNullValueProd public static FileQueries.GetImportLogsQuery GetImportLogsQuery => new FileQueries.GetImportLogsQuery(EstateId, LogQueryStartDate, LogQueryEndDate, MerchantId); public static FileQueries.GetImportLogQuery GetImportLogQuery => new FileQueries.GetImportLogQuery(FileImportLogId, EstateId, MerchantId); - public static DateTime LogQueryStartDate = new DateTime(2024, 12, 12); - public static DateTime LogQueryEndDate = new DateTime(2024, 12, 12); + public static DateOnly LogQueryStartDate = new DateOnly(2024, 12, 12); + public static DateOnly LogQueryEndDate = new DateOnly(2024, 12, 12); } } diff --git a/FileProcessor.Tests/ModelFactoryTests.cs b/FileProcessor.Tests/ModelFactoryTests.cs index 6f19cc5..c20b109 100644 --- a/FileProcessor.Tests/ModelFactoryTests.cs +++ b/FileProcessor.Tests/ModelFactoryTests.cs @@ -75,6 +75,35 @@ public void ModelFactory_ConvertFrom_FileDetails_IsConverted() this.VerifyFileDetails(fileDetails, result); } + [Fact] + public void ModelFactory_ConvertFrom_FileDetails_ExposesLineDiagnostics() + { + FileDetails fileDetails = TestData.FileDetailsModel; + FileLine line = fileDetails.FileLines.First(); + line.EventId = Guid.NewGuid(); + line.TransactionId = Guid.NewGuid(); + line.DispatchAttemptCount = 2; + line.FailureReason = "operator rejected transaction"; + line.ResponseCode = "E42"; + line.FailedDispatchAttempts.Add(new FileProcessor.Models.TransactionDispatchAttempt + { + TransactionNumber = 7, + FailureType = "timeout", + AttemptedAt = new DateTime(2026, 10, 16, 12, 30, 0, DateTimeKind.Utc) + }); + + DataTransferObjects.Responses.FileDetails result = ModelFactory.ConvertFrom(fileDetails); + DataTransferObjects.Responses.FileLine responseLine = result.FileLines.Single(l => l.LineNumber == line.LineNumber); + + responseLine.EventId.ShouldBe(line.EventId); + responseLine.TransactionId.ShouldBe(line.TransactionId); + responseLine.DispatchAttemptCount.ShouldBe(2); + responseLine.FailureReason.ShouldBe("operator rejected transaction"); + responseLine.ResponseCode.ShouldBe("E42"); + responseLine.FailedDispatchAttempts.ShouldHaveSingleItem(); + responseLine.FailedDispatchAttempts.Single().AttemptedAt.ShouldBe(line.FailedDispatchAttempts.Single().AttemptedAt); + } + private void VerifyFileDetails(FileDetails source, DataTransferObjects.Responses.FileDetails fileDetails) { diff --git a/FileProcessor/Common/ModelFactory.cs b/FileProcessor/Common/ModelFactory.cs index e3e9e3b..521c33e 100644 --- a/FileProcessor/Common/ModelFactory.cs +++ b/FileProcessor/Common/ModelFactory.cs @@ -30,6 +30,16 @@ public static FileImportLogList ConvertFrom(List fileImpor return result; } + public static FileImportLogList ConvertFrom(Models.FileImportLogQueryResult queryResult) + { + FileImportLogList result = ConvertFrom(queryResult.FileImportLogs); + result.PageNumber = queryResult.PageNumber; + result.PageSize = queryResult.PageSize; + result.TotalCount = queryResult.TotalCount; + result.HasMore = queryResult.HasMore; + return result; + } + /// /// Converts from. /// @@ -88,7 +98,17 @@ public static FileDetailsResponse ConvertFrom(Models.FileDetails fileDetails) LineNumber = fileDetailsFileLine.LineNumber, ProcessingResult = TranslateProcessingResult(fileDetailsFileLine.ProcessingResult), TransactionId = fileDetailsFileLine.TransactionId, - RejectionReason = fileDetailsFileLine.RejectedReason + EventId = fileDetailsFileLine.EventId, + RejectionReason = fileDetailsFileLine.RejectedReason, + FailureReason = fileDetailsFileLine.FailureReason, + ResponseCode = fileDetailsFileLine.ResponseCode, + DispatchAttemptCount = fileDetailsFileLine.DispatchAttemptCount, + FailedDispatchAttempts = fileDetailsFileLine.FailedDispatchAttempts?.Select(attempt => new DataTransferObjects.Responses.TransactionDispatchAttempt + { + TransactionNumber = attempt.TransactionNumber, + FailureType = attempt.FailureType, + AttemptedAt = attempt.AttemptedAt + }).ToList() ?? new List() }); } diff --git a/FileProcessor/Handlers/FileImportLogHandlers.cs b/FileProcessor/Handlers/FileImportLogHandlers.cs index 7bfdfde..0c9ce22 100644 --- a/FileProcessor/Handlers/FileImportLogHandlers.cs +++ b/FileProcessor/Handlers/FileImportLogHandlers.cs @@ -16,13 +16,18 @@ public static class FileImportLogHandlers { public static async Task GetImportLogsAsync(IMediator mediator, [FromQuery] Guid estateId, - [FromQuery] DateTime startDateTime, - [FromQuery] DateTime endDateTime, + [FromQuery] DateOnly startDate, + [FromQuery] DateOnly endDate, [FromQuery] Guid? merchantId, + [FromQuery] Int32 pageNumber, + [FromQuery] Int32 pageSize, + [FromQuery] Boolean descending, CancellationToken cancellationToken) { - FileQueries.GetImportLogsQuery query = new(estateId, startDateTime, endDateTime, merchantId); - Result> result = await mediator.Send(query, cancellationToken); + pageNumber = pageNumber == 0 ? 1 : pageNumber; + pageSize = pageSize == 0 ? 50 : pageSize; + FileQueries.GetImportLogsQuery query = new(estateId, startDate, endDate, merchantId, pageNumber, pageSize, descending); + Result result = await mediator.Send(query, cancellationToken); return ResponseFactory.FromResult(result, ModelFactory.ConvertFrom); } @@ -38,4 +43,4 @@ public static async Task GetImportLogAsync(IMediator mediator, return ResponseFactory.FromResult(result, ModelFactory.ConvertFrom); } -} \ No newline at end of file +}