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 EstateReportingAPI.BusinessLogic/Queries/SettlementQueries.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System.Diagnostics.CodeAnalysis;
using EstateReportingAPI.Models;
using MediatR;
using SimpleResults;

namespace EstateReportingAPI.BusinessLogic.Queries;

[ExcludeFromCodeCoverage]
public record SettlementQueries {
public record TodaysSettlementQuery(Guid EstateId, DateTime ComparisonDate) : IRequest<Result<TodaysSettlement>>;
}

[ExcludeFromCodeCoverage]
public record FileImportLogQueries
{
public record GetFileImportLogListQuery(Guid EstateId, Guid? MerchantId, DateTime StartDate, DateTime EndDate) : IRequest<Result<List<FileImportLog>>>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,4 @@ public record TransactionSummaryByMerchantQuery(Guid EstateId, TransactionSummar
public record TransactionSummaryByOperatorQuery(Guid EstateId, TransactionSummaryByOperatorRequest Request) : IRequest<Result<TransactionSummaryByOperatorResponse>>;
public record ProductPerformanceQuery(Guid EstateId, DateTime StartDate, DateTime EndDate) : IRequest<Result<ProductPerformanceResponse>>;
public record TodaysSalesByHour(Guid estateId, DateTime comparisonDate) : IRequest<Result<List<Models.TodaysSalesByHour>>>;
}

[ExcludeFromCodeCoverage]
public record SettlementQueries {
public record TodaysSettlementQuery(Guid EstateId, DateTime ComparisonDate) : IRequest<Result<Models.TodaysSettlement>>;
}
99 changes: 86 additions & 13 deletions EstateReportingAPI.BusinessLogic/ReportingManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ namespace EstateReportingAPI.BusinessLogic;
using MerchantBalanceProjectionState = TransactionProcessor.ProjectionEngine.Database.Database.Entities.MerchantBalanceProjectionState;

public interface IReportingManager
{
#region Methods
{
Task<Result<List<Calendar>>> GetCalendarComparisonDates(CalendarQueries.GetComparisonDatesQuery request, CancellationToken cancellationToken);
Task<Result<List<Calendar>>> GetCalendarDates(CalendarQueries.GetAllDatesQuery request, CancellationToken cancellationToken);
Task<Result<List<Int32>>> GetCalendarYears(CalendarQueries.GetYearsQuery request, CancellationToken cancellationToken);
Expand Down Expand Up @@ -57,11 +56,13 @@ Task<Result<ProductPerformanceResponse>> GetProductPerformanceReport(Transaction
Task<Result<List<TodaysSalesByHour>>> GetTodaysSalesByHour(TransactionQueries.TodaysSalesByHour request,
CancellationToken cancellationToken);
Task<Result<TodaysSettlement>> GetTodaysSettlement(SettlementQueries.TodaysSettlementQuery request,
CancellationToken cancellationToken);
#endregion

CancellationToken cancellationToken);

Task<Result<MerchantScheduleResponse>> GetMerchantSchedule(MerchantQueries.GetMerchantScheduleQuery request,
CancellationToken cancellationToken);

Task<Result<List<FileImportLog>>> GetFileImportLogList(FileImportLogQueries.GetFileImportLogListQuery request,
CancellationToken cancellationToken);
}

public class ReportingManager : IReportingManager {
Expand All @@ -70,16 +71,10 @@ public class ReportingManager : IReportingManager {
private Guid Id;
private static readonly String EstateManagementDatabaseName = "TransactionProcessorReadModel";

#region Constructors

public ReportingManager(IDbContextResolver<EstateManagementContext> resolver) {
this.Resolver = resolver;
}

#endregion

#region Methods

private static async Task<Result<T>> ExecuteQuerySafeSum<T>(IQueryable query,
CancellationToken cancellationToken,
string contextMessage = null) {
Expand Down Expand Up @@ -1390,6 +1385,70 @@ join d in context.MerchantScheduleMonths on s.MerchantScheduleId equals d.Mercha
return response;
}

public async Task<Result<List<FileImportLog>>> GetFileImportLogList(FileImportLogQueries.GetFileImportLogListQuery request,
CancellationToken cancellationToken) {
using ResolvedDbContext<EstateManagementContext>? resolvedContext = this.Resolver.Resolve(EstateManagementDatabaseName, request.EstateId.ToString());
await using EstateManagementContext context = resolvedContext.Context;
// Build flat projection of the required data then assemble into hierarchical models in-memory
var flatQuery = from fil in context.FileImportLogs
join f in context.Files on fil.FileImportLogId equals f.FileImportLogId
join esu in context.EstateSecurityUsers on f.UserId equals esu.SecurityUserId into esuJoin
from esu in esuJoin.DefaultIfEmpty()
join m in context.Merchants on f.MerchantId equals m.MerchantId into mJoin
from m in mJoin.DefaultIfEmpty()
join fl in context.FileLines on f.FileId equals fl.FileId
where fil.ImportLogDate >= request.StartDate && fil.ImportLogDate <= request.EndDate
&& (request.MerchantId == null || f.MerchantId == request.MerchantId)
select new FileImportFlatData {
FileImportLogId = fil.FileImportLogId,
ImportLogDateTime = fil.ImportLogDateTime,
FileId = f.FileId,
FileName = f.FileLocation,
FileProfileId = f.FileProfileId,
DateTimeUploaded = f.FileReceivedDateTime,
UserId = f.UserId,
UploadedBy = esu != null ? esu.EmailAddress : null,
MerchantId = f.MerchantId,
MerchantName = m != null ? m.Name : null,
LineNumber = fl.LineNumber,
LineContents = fl.FileLineData,
LineStatus = fl.Status
};

var flatResult = await ExecuteQuerySafeToList(flatQuery, cancellationToken, "Error retrieving file import logs");

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

var flatItems = flatResult.Data;

// assemble hierarchical model
var fileImportLogs = flatItems
.GroupBy(x => new { x.FileImportLogId, x.ImportLogDateTime })
.Select(g => new FileImportLog {
FileImportLogId = g.Key.FileImportLogId,
ImportLogDateTime = g.Key.ImportLogDateTime,
FileDetailsList = g.GroupBy(f => new { f.FileId, f.FileName, f.FileProfileId, f.DateTimeUploaded, f.UserId, f.UploadedBy, f.MerchantId, f.MerchantName })
.Select(fg => new FileDetails {
FileId = fg.Key.FileId,
FileName = fg.Key.FileName,
FileProfile = fg.Key.FileProfileId != null ? fg.Key.FileProfileId.ToString() : null,
DateTimeUploaded = fg.Key.DateTimeUploaded,
UserId = fg.Key.UserId,
UploadedBy = fg.Key.UploadedBy,
MerchantId = fg.Key.MerchantId,
MerchantName = fg.Key.MerchantName,
FileLines = fg.Select(fl => new FileLine {
LineNumber = fl.LineNumber,
LineContents = fl.LineContents,
LineStatus = fl.LineStatus
}).ToList()
}).ToList()
}).ToList();

return Result.Success(fileImportLogs);
}

private async Task<DatabaseProjections.SettlementGroupProjection> GetSettlementSummary(IQueryable<DatabaseProjections.ComparisonSettlementTransactionProjection> query,
CancellationToken cancellationToken) {
// Get the settleed fees summary
Expand Down Expand Up @@ -1637,5 +1696,19 @@ private sealed class ProductPerformanceItemData {
public decimal PercentOfTotalAmount { get; init; }
}

#endregion
}
private sealed class FileImportFlatData {
public Guid FileImportLogId { get; init; }
public DateTime ImportLogDateTime { get; init; }
public Guid FileId { get; init; }
public string? FileName { get; init; }
public Guid? FileProfileId { get; init; }
public DateTime DateTimeUploaded { get; init; }
public Guid UserId { get; init; }
public string? UploadedBy { get; init; }
public Guid MerchantId { get; init; }
public string? MerchantName { get; init; }
public int LineNumber { get; init; }
public string? LineContents { get; init; }
public string? LineStatus { get; init; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using EstateReportingAPI.BusinessLogic.Queries;
using EstateReportingAPI.Models;
using MediatR;
using SimpleResults;

namespace EstateReportingAPI.BusinessLogic.RequestHandlers;

public class SettlementRequestHandler : IRequestHandler<SettlementQueries.TodaysSettlementQuery, Result<TodaysSettlement>>
{
private readonly IReportingManager Manager;
public SettlementRequestHandler(IReportingManager manager) {
this.Manager = manager;
}
public async Task<Result<TodaysSettlement>> Handle(SettlementQueries.TodaysSettlementQuery request,
CancellationToken cancellationToken) {
return await this.Manager.GetTodaysSettlement(request, cancellationToken);
}
}

public class FileImportLogRequestHandler : IRequestHandler<FileImportLogQueries.GetFileImportLogListQuery, Result<List<FileImportLog>>>
{
private readonly IReportingManager Manager;
public FileImportLogRequestHandler(IReportingManager manager)
{
this.Manager = manager;
}

public async Task<Result<List<FileImportLog>>> Handle(FileImportLogQueries.GetFileImportLogListQuery request,
CancellationToken cancellationToken) {
return await this.Manager.GetFileImportLogList(request, cancellationToken);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,6 @@

namespace EstateReportingAPI.BusinessLogic.RequestHandlers;

public class SettlementRequestHandler : IRequestHandler<SettlementQueries.TodaysSettlementQuery, Result<TodaysSettlement>>
{
private readonly IReportingManager Manager;
public SettlementRequestHandler(IReportingManager manager) {
this.Manager = manager;
}
public async Task<Result<TodaysSettlement>> Handle(SettlementQueries.TodaysSettlementQuery request,
CancellationToken cancellationToken) {
return await this.Manager.GetTodaysSettlement(request, cancellationToken);
}
}

public class TransactionRequestHandler : IRequestHandler<TransactionQueries.TodaysFailedSales, Result<TodaysSales>>,
IRequestHandler<TransactionQueries.TodaysSalesQuery, Result<TodaysSales>>,
IRequestHandler<TransactionQueries.TransactionDetailReportQuery, Result<TransactionDetailReportResponse>>,
Expand Down
17 changes: 17 additions & 0 deletions EstateReportingAPI.DataTrasferObjects/FileDetails.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;

namespace EstateReportingAPI.DataTransferObjects;

public class FileDetails
{
public Guid FileId { get; set; }
public string FileName { get; set; }
public string FileProfile { get; set; }
public DateTime DateTimeUploaded { get; set; }
public Guid UserId { get; set; }
public string UploadedBy { get; set; }
public Guid MerchantId { get; set; }
public string MerchantName { get; set; }
public List<FileLine> FileLines { get; set; } = new List<FileLine>();
}
11 changes: 11 additions & 0 deletions EstateReportingAPI.DataTrasferObjects/FileImportLog.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;

namespace EstateReportingAPI.DataTransferObjects;

public class FileImportLog
{
public Guid FileImportLogId { get; set; }
public DateTime ImportLogDateTime { get; set; }
public List<FileDetails> FileDetailsList { get; set; }
}
10 changes: 10 additions & 0 deletions EstateReportingAPI.DataTrasferObjects/FileLine.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System;

namespace EstateReportingAPI.DataTransferObjects;

public sealed class FileLine
{
public int LineNumber { get; set; }
public string LineContents { get; set; }
public String LineStatus { get; set; }
}
63 changes: 63 additions & 0 deletions EstateReportingAPI.IntegrationTests/DatabaseHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@
using MerchantDevice = TransactionProcessor.Database.Entities.MerchantDevice;
using MerchantOperator = TransactionProcessor.Database.Entities.MerchantOperator;
using Operator = TransactionProcessor.Database.Entities.Operator;
using FileImportLog = TransactionProcessor.Database.Entities.FileImportLog;
using DbFile = TransactionProcessor.Database.Entities.File;
using FileLine = TransactionProcessor.Database.Entities.FileLine;
using EstateSecurityUser = TransactionProcessor.Database.Entities.EstateSecurityUser;

namespace EstateReportingAPI.IntegrationTests;

Expand All @@ -40,6 +44,65 @@ public DatabaseHelper(EstateManagementContext context, Guid estateId) {
this.EstateId = estateId;
}

public async Task<Guid> AddEstateUser(String estateName, string name, string email){
Estate? estate = await this.Context.Estates.SingleOrDefaultAsync(e => e.Name == estateName);
if (estate == null) throw new Exception($"No estate found with name {estateName}");

EstateSecurityUser user = new EstateSecurityUser {
EstateId = estate.EstateId,
SecurityUserId = Guid.NewGuid(),
EmailAddress = email
};

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

return user.SecurityUserId;
}

public async Task<Guid> AddFileImportLog(Guid estateId, DateTime importDate){
FileImportLog fil = new FileImportLog {
FileImportLogId = Guid.NewGuid(),
EstateId = estateId,
ImportLogDateTime = importDate,
ImportLogDate = importDate.Date
};

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

return fil.FileImportLogId;
}

public async Task<Guid> AddFile(Guid fileImportLogId, Guid merchantId, Guid userId, string fileLocation){
DbFile file = new DbFile {
FileId = Guid.NewGuid(),
FileImportLogId = fileImportLogId,
FileLocation = fileLocation,
FileProfileId = Guid.NewGuid(),
FileReceivedDateTime = DateTime.Now,
UserId = userId,
MerchantId = merchantId
};

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

return file.FileId;
}

public async Task AddFileLine(Guid fileId, int lineNumber, string data, string status){
FileLine fl = new FileLine {
FileId = fileId,
LineNumber = lineNumber,
FileLineData = data,
Status = status
};

await this.Context.AddAsync(fl);
await this.Context.SaveChangesAsync(CancellationToken.None);
}

public async Task DeleteAllMerchants(){
List<Merchant> merchants = await this.Context.Merchants.ToListAsync();
this.Context.RemoveRange(merchants);
Expand Down
Loading
Loading