Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions FIleProcessor.Models/FileImportLogQueryResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace FileProcessor.Models
{
using System.Collections.Generic;

public class FileImportLogQueryResult
{
public List<FileImportLog> 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;
}
}
4 changes: 4 additions & 0 deletions FIleProcessor.Models/FileLine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<TransactionDispatchAttempt> FailedDispatchAttempts { get; set; } = new();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,14 @@ public async Task<Result<FileProfileModel>> GetFileProfile(Guid fileProfileId,
return Result.Success();
}

public async Task<Result<List<Models.FileImportLog>>> GetFileImportLogs(Guid estateId,
DateTime startDateTime,
DateTime endDateTime,
Guid? merchantId,
CancellationToken cancellationToken) {
public async Task<Result<Models.FileImportLogQueryResult>> GetFileImportLogs(Guid estateId,
DateOnly startDate,
DateOnly endDate,
Guid? merchantId,
Int32 pageNumber,
Int32 pageSize,
Boolean descending,
CancellationToken cancellationToken) {
return Result.Success();
}

Expand Down
51 changes: 47 additions & 4 deletions FileProcessor.BusinessLogic.Tests/FileProcessingManagerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<List<FileImportLog>> getFileImportLogsResult = await this.Manager.GetFileImportLogs(TestData.EstateId, TestData.ImportLogStartDate, TestData.ImportLogEndDate, null, CancellationToken.None);
Result<FileImportLogQueryResult> 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<FileImportLog> importLogs = getFileImportLogsResult.Data;
List<FileImportLog> importLogs = getFileImportLogsResult.Data.FileImportLogs;
this.VerifyImportLogs(TestData.FileImportLogs,importLogs);
}

Expand All @@ -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<List<FileImportLog>> importLogs = await this.Manager.GetFileImportLogs(TestData.EstateId, TestData.ImportLogStartDate, TestData.ImportLogEndDate, TestData.MerchantId, CancellationToken.None);
Result<FileImportLogQueryResult> 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]
Expand Down Expand Up @@ -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<FileImportLogQueryResult> 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<FileImportLog> 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()
{
Expand Down
45 changes: 39 additions & 6 deletions FileProcessor.BusinessLogic/Managers/FileProcessorManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,16 +83,39 @@ private async Task<EstateManagementContext> GetContext(Guid estateId)
}


public async Task<Result<List<FileImportLog>>> GetFileImportLogs(Guid estateId,
DateTime startDateTime,
DateTime endDateTime,
public async Task<Result<FileImportLogQueryResult>> 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<TransactionProcessor.Database.Entities.FileImportLog> 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<TransactionProcessor.Database.Entities.FileImportLog> 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,
Expand All @@ -109,7 +132,7 @@ public async Task<Result<List<FileImportLog>>> 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){
Expand All @@ -122,7 +145,13 @@ public async Task<Result<List<FileImportLog>>> GetFileImportLogs(Guid estateId,
}

List<FileImportLog> 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<Result<FileImportLog>> GetFileImportLog(Guid fileImportLogId,
Expand All @@ -140,6 +169,7 @@ public async Task<Result<FileImportLog>> 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 };


Expand All @@ -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)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public interface IFileProcessorManager

Task<Result<FileProfileModel>> GetFileProfile(Guid fileProfileId, CancellationToken cancellationToken);

Task<Result<List<Models.FileImportLog>>> GetFileImportLogs(Guid estateId, DateTime startDateTime, DateTime endDateTime, Guid? merchantId, CancellationToken cancellationToken);
Task<Result<Models.FileImportLogQueryResult>> GetFileImportLogs(Guid estateId, DateOnly startDate, DateOnly endDate, Guid? merchantId, Int32 pageNumber, Int32 pageSize, Boolean descending, CancellationToken cancellationToken);

Task<Result<Models.FileImportLog>> GetFileImportLog(Guid fileImportLogId, Guid estateId, Guid? merchantId, CancellationToken cancellationToken);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public class FileRequestHandler : IRequestHandler<FileCommands.ProcessTransactio
IRequestHandler<FileCommands.ProcessUploadedFileCommand, Result>,
IRequestHandler<FileCommands.UploadFileCommand, Result>,
IRequestHandler<FileQueries.GetFileQuery, Result<FileDetails>>,
IRequestHandler<FileQueries.GetImportLogsQuery, Result<List<Models.FileImportLog>>>,
IRequestHandler<FileQueries.GetImportLogsQuery, Result<Models.FileImportLogQueryResult>>,
IRequestHandler<FileQueries.GetImportLogQuery, Result<Models.FileImportLog>>,
IRequestHandler<FileCommands.ReplayFileLineCommand, Result>
{
Expand Down Expand Up @@ -48,9 +48,9 @@ public async Task<Result<FileDetails>> Handle(FileQueries.GetFileQuery query,
return await this.Manager.GetFile(query.FileId, query.EstateId, cancellationToken);
}

public async Task<Result<List<Models.FileImportLog>>> Handle(FileQueries.GetImportLogsQuery query,
public async Task<Result<Models.FileImportLogQueryResult>> 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<Result<Models.FileImportLog>> Handle(FileQueries.GetImportLogQuery query,
Expand Down
4 changes: 2 additions & 2 deletions FileProcessor.BusinessLogic/Requests/FileQueries.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ namespace FileProcessor.BusinessLogic.Requests;
public record FileQueries {
public record GetFileQuery(Guid FileId, Guid EstateId) : IRequest<Result<FileDetails>>;

public record GetImportLogsQuery(Guid EstateId, DateTime StartDateTime, DateTime EndDateTime, Guid? MerchantId) : IRequest<Result<List<Models.FileImportLog>>>;
public record GetImportLogsQuery(Guid EstateId, DateOnly StartDate, DateOnly EndDate, Guid? MerchantId, Int32 PageNumber = 1, Int32 PageSize = 50, Boolean Descending = false) : IRequest<Result<Models.FileImportLogQueryResult>>;

public record GetImportLogQuery(Guid FileImportLogId,
Guid EstateId,
Guid? MerchantId) : IRequest<Result<FileProcessor.Models.FileImportLog>>;
}
}
35 changes: 12 additions & 23 deletions FileProcessor.Client/FileProcessorClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -180,39 +180,28 @@ public async Task<Result<ApiFileImportLog>> GetFileImportLog(String accessToken,
/// </summary>
/// <param name="accessToken">The access token.</param>
/// <param name="estateId">The estate identifier.</param>
/// <param name="startDateTime">The start date time.</param>
/// <param name="endDateTime">The end date time.</param>
/// <param name="startDate">The first calendar date.</param>
/// <param name="endDate">The last calendar date.</param>
/// <param name="merchantId">The merchant identifier.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns></returns>
public async Task<Result<FileImportLogList>> 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<FileImportLogList> result = await this.Get<FileImportLogList>(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<FileImportLogList> result = await this.Get<FileImportLogList>(requestUri, accessToken, cancellationToken);
return result.IsFailed ? ResultHelpers.CreateFailure(result) : result;
}

/// <summary>
Expand Down
Loading
Loading