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
Empty file added .github/copilot-instructions.md
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@

<ItemGroup>
<PackageReference Include="MediatR" Version="14.1.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.DynamicLinq" Version="10.7.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.DynamicLinq" Version="10.7.2" />
<PackageReference Include="Shared" Version="2026.5.6" />
<PackageReference Include="Shared.Results" Version="2026.5.6" />
<PackageReference Include="TransactionProcessor.Database" Version="2026.4.3-build355" />
<PackageReference Include="TransactionProcessor.Database" Version="2026.5.2-build358" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,10 @@ public record FileImportLogQueries
{
public record GetFileImportLogListQuery(Guid EstateId, Guid? MerchantId, DateTime StartDate, DateTime EndDate) : IRequest<Result<List<FileImportLog>>>;
public record GetFileImportLogQuery(Guid EstateId, Guid? MerchantId, Guid FileImportLogId) : IRequest<Result<FileImportLog>>;
}

[ExcludeFromCodeCoverage]
public record FileProfileConfigurationQueries
{
public record GetFileProfileConfigurationListQuery(Guid EstateId) : IRequest<Result<List<FileProfileConfiguration>>>;
}
32 changes: 30 additions & 2 deletions EstateReportingAPI.BusinessLogic/ReportingManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,11 @@

namespace EstateReportingAPI.BusinessLogic;

using Azure;
using Microsoft.EntityFrameworkCore;
using Models;
using Shared.EntityFramework;
using Shared.Results;
using System;
using System.ClientModel.Primitives;
using System.Linq;
using System.Threading;
using static Microsoft.EntityFrameworkCore.DbLoggerCategory;
Expand Down Expand Up @@ -65,6 +63,8 @@ Task<Result<List<FileImportLog>>> GetFileImportLogList(FileImportLogQueries.GetF
CancellationToken cancellationToken);
Task<Result<FileImportLog>> GetFileImportLog(FileImportLogQueries.GetFileImportLogQuery request,
CancellationToken cancellationToken);
Task<Result<List<FileProfileConfiguration>>> GetFileProfileConfigurationList(FileProfileConfigurationQueries.GetFileProfileConfigurationListQuery request,
CancellationToken cancellationToken);
}

public class ReportingManager : IReportingManager {
Expand Down Expand Up @@ -1522,6 +1522,34 @@ join fl in context.FileLines on f.FileId equals fl.FileId
return Result.Success(fileImportLogs);
}

public async Task<Result<List<FileProfileConfiguration>>> GetFileProfileConfigurationList(FileProfileConfigurationQueries.GetFileProfileConfigurationListQuery request,
CancellationToken cancellationToken) {
using ResolvedDbContext<EstateManagementContext>? resolvedContext = this.Resolver.Resolve(EstateManagementDatabaseName, request.EstateId.ToString());
await using EstateManagementContext context = resolvedContext.Context;

var query = from c in context.FileProfileConfigurations
join h in context.FileFormatHandlers on c.FileFormatHandlerId equals h.FileFormatHandlerId
join r in context.RequestTypes on c.RequestTypeId equals r.RequestTypeId
join o in context.Operators on c.OperatorId equals o.OperatorId
select new FileProfileConfiguration
{
FileProfileId = c.FileProfileId,
Name = c.Name,
ListeningDirectory = c.ListeningDirectory,
RequestType = r.Name,
OperatorName = o.Name,
LineTerminator = c.LineTerminator,
FileFormatHandler = h.Name
};

Result<List<FileProfileConfiguration>> result = await ExecuteQuerySafeToList(query, cancellationToken, "Error retrieving file import logs");

if (result.IsFailed)
return ResultHelpers.CreateFailure(result);

return Result.Success(result.Data);
}

private async Task<DatabaseProjections.SettlementGroupProjection> GetSettlementSummary(IQueryable<DatabaseProjections.ComparisonSettlementTransactionProjection> query,
CancellationToken cancellationToken) {
// Get the settleed fees summary
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,20 @@ public async Task<Result<FileImportLog>> Handle(FileImportLogQueries.GetFileImpo
{
return await this.Manager.GetFileImportLog(request, cancellationToken);
}
}

public class FileProfileConfigurationRequestHandler : IRequestHandler<FileProfileConfigurationQueries.GetFileProfileConfigurationListQuery, Result<List<FileProfileConfiguration>>>

{
private readonly IReportingManager Manager;
public FileProfileConfigurationRequestHandler(IReportingManager manager)
{
this.Manager = manager;
}

public async Task<Result<List<FileProfileConfiguration>>> Handle(FileProfileConfigurationQueries.GetFileProfileConfigurationListQuery request,
CancellationToken cancellationToken)
{
return await this.Manager.GetFileProfileConfigurationList(request, cancellationToken);
}
}
14 changes: 14 additions & 0 deletions EstateReportingAPI.DataTrasferObjects/FileProfileConfiguration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System;

namespace EstateReportingAPI.DataTransferObjects;

public class FileProfileConfiguration
{
public Guid FileProfileId { get; set; }
public string Name { get; set; }
public string ListeningDirectory { get; set; }
public string RequestType { get; set; }
public string OperatorName { get; set; }
public string LineTerminator { get; set; }
public string FileFormatHandler { get; set; }
}
43 changes: 43 additions & 0 deletions EstateReportingAPI.IntegrationTests/DatabaseHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
using DbFile = TransactionProcessor.Database.Entities.File;
using FileLine = TransactionProcessor.Database.Entities.FileLine;
using EstateSecurityUser = TransactionProcessor.Database.Entities.EstateSecurityUser;
using FileProfileConfiguration = TransactionProcessor.Database.Entities.FileProfileConfiguration;

namespace EstateReportingAPI.IntegrationTests;

Expand Down Expand Up @@ -103,6 +104,48 @@ public async Task AddFileLine(Guid fileId, int lineNumber, string data, string s
await this.Context.SaveChangesAsync(CancellationToken.None);
}

public async Task<Guid> AddFileFormatHandler(string name)
{
Guid id = Guid.NewGuid();
FileFormatHandler h = new() { FileFormatHandlerId = id, Name = name };

await this.Context.AddAsync(h);
await this.Context.SaveChangesAsync(CancellationToken.None);

return id;
}

public async Task<Guid> AddRequestType(string name)
{
Guid id = Guid.NewGuid();
RequestType r = new() { RequestTypeId = id, Name = name };

await this.Context.AddAsync(r);
await this.Context.SaveChangesAsync(CancellationToken.None);

return id;
}

public async Task AddFileProfileConfiguration(Guid fileProfileId,
string name,
string listeningDirectory,
Guid fileFormatHandlerId,
Guid requestTypeId,
Guid operatorId,
string lineTerminator) {
FileProfileConfiguration configuration = new() {
Name = name,
FileFormatHandlerId = fileFormatHandlerId,
FileProfileId = fileProfileId,
LineTerminator = lineTerminator,
ListeningDirectory = listeningDirectory,
OperatorId = operatorId,
RequestTypeId = requestTypeId
};
await this.Context.AddAsync(configuration);
await this.Context.SaveChangesAsync(CancellationToken.None);
}

public async Task DeleteAllMerchants(){
List<Merchant> merchants = await this.Context.Merchants.ToListAsync();
this.Context.RemoveRange(merchants);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@

<ItemGroup>
<PackageReference Include="Swashbuckle.AspNetCore" Version="10.1.5" />
<PackageReference Include="TransactionProcessor.Database" Version="2026.4.3-build355" />
<PackageReference Include="TransactionProcessor.Database" Version="2026.5.2-build358" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="10.0.4" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.4" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.8" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.3.0" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using EstateReportingAPI.DataTransferObjects;
using Microsoft.EntityFrameworkCore;
using System.Linq;
using Shouldly;
using Xunit;

namespace EstateReportingAPI.IntegrationTests
{
public class FileProfileConfigurationEndpointTests : ControllerTestsBase
{
private const string BaseRoute = "api/fileprofiles";

[Fact]
public async Task FileProfileConfiguration_Get_NoData_ReturnsEmptyList()
{
// ensure estate exists
await this.helper.AddEstate("Test Estate", "Ref1");

var result = await this.CreateAndSendHttpRequestMessage<List<FileProfileConfiguration>>($"{BaseRoute}", CancellationToken.None);
result.IsSuccess.ShouldBeTrue();
var list = result.Data;
list.ShouldNotBeNull();
list.Count.ShouldBe(0);
}

[Fact]
public async Task FileProfileConfiguration_Get_ReturnsInsertedData()
{
// setup estate and operator
await this.helper.AddEstate("Test Estate", "Ref1");
var operatorId = await this.helper.AddOperator("Test Estate", "Test Operator");

// insert supporting rows and a profile using helper methods
Guid profileId = Guid.NewGuid();
string handlerName = $"TestHandler-{this.TestId}";
string requestName = $"TestRequest-{this.TestId}";
string profileName = $"TestProfile-{this.TestId}";

Guid handlerId = await this.helper.AddFileFormatHandler(handlerName);
Guid requestId = await this.helper.AddRequestType(requestName);

await this.helper.AddFileProfileConfiguration(profileId, profileName, "C:\\listen", handlerId, requestId, operatorId, "\\n");

var result = await this.CreateAndSendHttpRequestMessage<List<FileProfileConfiguration>>($"{BaseRoute}", CancellationToken.None);
result.IsSuccess.ShouldBeTrue();
var list = result.Data;
list.ShouldNotBeNull();
list.Count.ShouldBeGreaterThan(0);

var match = list.SingleOrDefault(f => f.FileProfileId == profileId);
match.ShouldNotBeNull();
match.Name.ShouldBe(profileName);
}

protected override Task ClearStandingData()
{
return Task.CompletedTask;
}

protected override Task SetupStandingData()
{
// tests will create their own standing data as needed
return Task.CompletedTask;
}
}
}
12 changes: 12 additions & 0 deletions EstateReportingAPI.Models/FileProfileConfiguration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace EstateReportingAPI.Models;

public class FileProfileConfiguration
{
public Guid FileProfileId { get; set; }
public string Name { get; set; } = string.Empty;
public string ListeningDirectory { get; set; } = string.Empty;
public string RequestType { get; set; } = string.Empty;
public string OperatorName { get; set; } = string.Empty;
public string LineTerminator { get; set; } = string.Empty;
public string FileFormatHandler { get; set; } = string.Empty;
}
14 changes: 7 additions & 7 deletions EstateReportingAPI.Tests/EstateReportingAPI.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,20 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.4" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="10.0.4" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.4" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="10.0.4" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="10.0.4" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="10.0.4">
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.8" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="10.0.8" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.8" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="10.0.8" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="10.0.8" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="10.0.8">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.3.0" />
<PackageReference Include="Moq" Version="4.20.72" />
<PackageReference Include="Shouldly" Version="4.3.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="10.1.5" />
<PackageReference Include="TransactionProcessor.Database" Version="2026.4.3-build355" />
<PackageReference Include="TransactionProcessor.Database" Version="2026.5.2-build358" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
<PrivateAssets>all</PrivateAssets>
Expand Down
30 changes: 1 addition & 29 deletions EstateReportingAPI/Bootstrapper/MiddlewareRegistry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ public class MiddlewareRegistry : ServiceRegistry{
public MiddlewareRegistry()
{
this.ConfigureHealthChecks();
//this.ConfigureSwagger();
this.ConfigureAuthentication();
this.ConfigureControllers();
this.ConfigureMiddlewareLogging();
Expand Down Expand Up @@ -50,34 +49,7 @@ private void ConfigureHealthChecks(){
tags: new[] { "db", "sql", "sqlserver" });
}
}

private void ConfigureSwagger(){
this.AddSwaggerGen(c => {
c.SwaggerDoc("v1",
new OpenApiInfo{
Title = "Estate Reporting API",
Version = "1.0",
Description = "A REST Api to manage all aspects of reporting for an estate (merchants, operators and contracts).",
Contact = new OpenApiContact{
Name = "Stuart Ferguson",
Email = "golfhandicapping@btinternet.com"
}
});
// add a custom operation filter which sets default values

c.ExampleFilters();

//Locate the XML files being generated by ASP.NET...
var directory = new DirectoryInfo(AppContext.BaseDirectory);
var xmlFiles = directory.GetFiles("*.xml");

//... and tell Swagger to use those XML comments.
foreach (FileInfo fileInfo in xmlFiles){
c.IncludeXmlComments(fileInfo.FullName);
}
});
}


private void ConfigureAuthentication(){
String? inTestMode = Environment.GetEnvironmentVariable("InTestMode");
if (String.Compare(inTestMode, Boolean.TrueString, StringComparison.InvariantCultureIgnoreCase) != 0){
Expand Down
18 changes: 18 additions & 0 deletions EstateReportingAPI/Endpoints/FileImportLogEndpoints.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,22 @@ public static void MapFileImportLogEndpoints(this IEndpointRouteBuilder app)

group.MapGet("/{fileimportlogid}", FileImportHandler.GetFileImportLog).WithStandardProduces<FileImportLog>();
}
}

public static class FileProfileConfigurationEndpoints
{
private const string BaseRoute = "api/fileprofiles";

public static void MapFileProfileConfigurationEndpoints(this IEndpointRouteBuilder app)
{
RouteGroupBuilder group = app.MapGroup(BaseRoute).WithTags("File Profile Configurations");

Boolean disableAuthorisation = ConfigurationReader.GetValueOrDefault<Boolean>("AppSettings", "DisableAuthorisation", false);
if (disableAuthorisation == false)
{
group = group.RequireAuthorization();
}

group.MapGet("/", FileProfileConfigurationHandler.GetFileProfileConfigurationList).WithStandardProduces<List<FileProfileConfiguration>>();
}
}
2 changes: 1 addition & 1 deletion EstateReportingAPI/EstateReportingAPI.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="10.1.5" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="10.1.5" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="10.0.4" />
<PackageReference Include="TransactionProcessor.Database" Version="2026.4.3-build355" />
<PackageReference Include="TransactionProcessor.Database" Version="2026.5.2-build358" />
<PackageReference Include="Sentry.AspNetCore" Version="6.2.0" />
</ItemGroup>

Expand Down
Loading
Loading