From c6ec82b8138936189d33b99020db45b30d2d8343 Mon Sep 17 00:00:00 2001 From: Stuart Ferguson Date: Thu, 12 Feb 2026 17:07:41 +0000 Subject: [PATCH 1/3] Refactor to use Result pattern for queries and handlers Standardized all business logic and request handler methods to return Result for consistent error and not-found handling. Introduced helper methods in ReportingManager for safe query execution. Updated all MediatR handlers to propagate Result directly. Upgraded Shared, Shared.Results, and related NuGet packages to 2026.2.1. Improved error handling, code consistency, and maintainability across the API. --- .../EstateReportingAPI.BusinessLogic.csproj | 3 +- .../ReportingManager.cs | 576 ++++++++++++------ .../RequestHandlers/CalendarRequestHandler.cs | 29 +- .../RequestHandlers/ContractRequestHandler.cs | 8 +- .../RequestHandlers/EstateRequestHandler.cs | 6 +- .../RequestHandlers/MerchantRequestHandler.cs | 25 +- .../RequestHandlers/OperatorRequestHandler.cs | 6 +- .../TransactionRequestHandler.cs | 6 +- .../EstateReportingAPI.Client.csproj | 4 +- ...EstateReportingAPI.IntegrationTests.csproj | 6 +- EstateReportingAPI/EstateReportingAPI.csproj | 6 +- 11 files changed, 421 insertions(+), 254 deletions(-) diff --git a/EstateReportingAPI.BusinessLogic/EstateReportingAPI.BusinessLogic.csproj b/EstateReportingAPI.BusinessLogic/EstateReportingAPI.BusinessLogic.csproj index b77b8a9..550ecfd 100644 --- a/EstateReportingAPI.BusinessLogic/EstateReportingAPI.BusinessLogic.csproj +++ b/EstateReportingAPI.BusinessLogic/EstateReportingAPI.BusinessLogic.csproj @@ -9,7 +9,8 @@ - + + diff --git a/EstateReportingAPI.BusinessLogic/ReportingManager.cs b/EstateReportingAPI.BusinessLogic/ReportingManager.cs index 5e723a7..523ddb6 100644 --- a/EstateReportingAPI.BusinessLogic/ReportingManager.cs +++ b/EstateReportingAPI.BusinessLogic/ReportingManager.cs @@ -1,16 +1,19 @@ -using System.Linq.Expressions; -using EstateReportingAPI.BusinessLogic.Queries; +using EstateReportingAPI.BusinessLogic.Queries; using SimpleResults; +using System.Linq.Expressions; using TransactionProcessor.Database.Contexts; using TransactionProcessor.Database.Entities; using TransactionProcessor.Database.Entities.Summary; 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 Calendar = Models.Calendar; @@ -19,27 +22,27 @@ namespace EstateReportingAPI.BusinessLogic; public interface IReportingManager { #region Methods - Task> GetCalendarComparisonDates(CalendarQueries.GetComparisonDatesQuery request, CancellationToken cancellationToken); - Task> GetCalendarDates(CalendarQueries.GetAllDatesQuery request, CancellationToken cancellationToken); - Task> GetCalendarYears(CalendarQueries.GetYearsQuery request, CancellationToken cancellationToken); - Task> GetRecentMerchants(MerchantQueries.GetRecentMerchantsQuery request, CancellationToken cancellationToken); - Task> GetRecentContracts(ContractQueries.GetRecentContractsQuery request, CancellationToken cancellationToken); - Task> GetContracts(ContractQueries.GetContractsQuery request, CancellationToken cancellationToken); - Task GetContract(ContractQueries.GetContractQuery request, CancellationToken cancellationToken); - Task GetTodaysFailedSales(TransactionQueries.TodaysFailedSales request, CancellationToken cancellationToken); - Task GetTodaysSales(TransactionQueries.TodaysSalesQuery request, CancellationToken cancellationToken); - Task GetEstate(EstateQueries.GetEstateQuery request, CancellationToken cancellationToken); - Task> GetEstateOperators(EstateQueries.GetEstateOperatorsQuery request, CancellationToken cancellationToken); - Task GetMerchantsTransactionKpis(MerchantQueries.GetTransactionKpisQuery request, CancellationToken cancellationToken); - Task> GetOperators(OperatorQueries.GetOperatorsQuery request, CancellationToken cancellationToken); - Task> GetMerchants(MerchantQueries.GetMerchantsQuery request, CancellationToken cancellationToken); - Task GetMerchant(MerchantQueries.GetMerchantQuery request, CancellationToken cancellationToken); - Task> GetMerchantOperators(MerchantQueries.GetMerchantOperatorsQuery request, CancellationToken cancellationToken); - Task> GetMerchantContracts(MerchantQueries.GetMerchantContractsQuery request, CancellationToken cancellationToken); - Task> GetMerchantDevices(MerchantQueries.GetMerchantDevicesQuery request, CancellationToken cancellationToken); - Task GetOperator(OperatorQueries.GetOperatorQuery request, CancellationToken cancellationToken); - - Task GetTransactionDetailReport(TransactionQueries.TransactionDetailReportQuery request, + Task>> GetCalendarComparisonDates(CalendarQueries.GetComparisonDatesQuery request, CancellationToken cancellationToken); + Task>> GetCalendarDates(CalendarQueries.GetAllDatesQuery request, CancellationToken cancellationToken); + Task>> GetCalendarYears(CalendarQueries.GetYearsQuery request, CancellationToken cancellationToken); + Task>> GetRecentMerchants(MerchantQueries.GetRecentMerchantsQuery request, CancellationToken cancellationToken); + Task>> GetRecentContracts(ContractQueries.GetRecentContractsQuery request, CancellationToken cancellationToken); + Task>> GetContracts(ContractQueries.GetContractsQuery request, CancellationToken cancellationToken); + Task> GetContract(ContractQueries.GetContractQuery request, CancellationToken cancellationToken); + Task> GetTodaysFailedSales(TransactionQueries.TodaysFailedSales request, CancellationToken cancellationToken); + Task> GetTodaysSales(TransactionQueries.TodaysSalesQuery request, CancellationToken cancellationToken); + Task> GetEstate(EstateQueries.GetEstateQuery request, CancellationToken cancellationToken); + Task>> GetEstateOperators(EstateQueries.GetEstateOperatorsQuery request, CancellationToken cancellationToken); + Task> GetMerchantsTransactionKpis(MerchantQueries.GetTransactionKpisQuery request, CancellationToken cancellationToken); + Task>> GetOperators(OperatorQueries.GetOperatorsQuery request, CancellationToken cancellationToken); + Task>> GetMerchants(MerchantQueries.GetMerchantsQuery request, CancellationToken cancellationToken); + Task> GetMerchant(MerchantQueries.GetMerchantQuery request, CancellationToken cancellationToken); + Task>> GetMerchantOperators(MerchantQueries.GetMerchantOperatorsQuery request, CancellationToken cancellationToken); + Task>> GetMerchantContracts(MerchantQueries.GetMerchantContractsQuery request, CancellationToken cancellationToken); + Task>> GetMerchantDevices(MerchantQueries.GetMerchantDevicesQuery request, CancellationToken cancellationToken); + Task> GetOperator(OperatorQueries.GetOperatorQuery request, CancellationToken cancellationToken); + + Task> GetTransactionDetailReport(TransactionQueries.TransactionDetailReportQuery request, CancellationToken cancellationToken); #endregion @@ -61,29 +64,62 @@ public ReportingManager(IDbContextResolver resolver) { #region Methods - public async Task> GetCalendarComparisonDates(CalendarQueries.GetComparisonDatesQuery request, - CancellationToken cancellationToken) { - using ResolvedDbContext? resolvedContext = this.Resolver.Resolve(EstateManagementDatabaseName, request.EstateId.ToString()); - await using EstateManagementContext context = resolvedContext.Context; + private static async Task>> ExecuteQuerySafeToList(IQueryable query,CancellationToken cancellationToken,string contextMessage = null) + { + try + { + List items = await query.ToListAsync(cancellationToken); + return Result.Success(items); + } + catch (Exception ex) + { + string msg = contextMessage == null ? $"Error executing query: {ex.Message}" : $"{contextMessage}: {ex.Message}"; + return Result.Failure(msg); + } + } - //DateTime startOfYear = new(DateTime.Now.Year, 1, 1); + private static async Task> ExecuteQuerySafeSingleOrDefault(IQueryable query, CancellationToken cancellationToken, string contextMessage = null) + { + try + { + T item = await query.SingleOrDefaultAsync(cancellationToken); - //List entities = context.Calendar.Where(c => c.Date >= startOfYear && c.Date < DateTime.Now.Date.AddDays(-1)).OrderByDescending(d => d.Date).ToList(); + if (item == null) + return Result.NotFound(contextMessage); + + return Result.Success(item); + } + catch (Exception ex) + { + string msg = contextMessage == null ? $"Error executing query: {ex.Message}" : $"{contextMessage}: {ex.Message}"; + return Result.Failure(msg); + } + } + public async Task>> GetCalendarComparisonDates(CalendarQueries.GetComparisonDatesQuery request, + CancellationToken cancellationToken) { + using ResolvedDbContext? resolvedContext = this.Resolver.Resolve(EstateManagementDatabaseName, request.EstateId.ToString()); + await using EstateManagementContext context = resolvedContext.Context; + DateTime today = DateTime.Today; DateTime startDate = today.AddYears(-1); DateTime endDate = today.AddDays(-1); // yesterday - List entities = - context.Calendar - .Where(c => c.Date >= startDate && - c.Date < endDate) - .OrderByDescending(c => c.Date) - .ToList(); + var result = await ExecuteQuerySafeToList( + context.Calendar.Where(c => c.Date >= startDate && c.Date < endDate) + .OrderByDescending(c => c.Date), cancellationToken, "Error retrieving calendar comparison dates"); + + if (result.IsFailed) + return ResultHelpers.CreateFailure(result); + + var entities = result.Data; - List result = new(); + if (entities.Any() == false) + return Result.NotFound("No calendar dates found"); + + List response = new(); foreach (TransactionProcessor.Database.Entities.Calendar calendar in entities) - result.Add(new Calendar { + response.Add(new Calendar { Date = calendar.Date, DayOfWeek = calendar.DayOfWeek, Year = calendar.Year, @@ -97,19 +133,26 @@ public async Task> GetCalendarComparisonDates(CalendarQueries.Get YearWeekNumber = calendar.YearWeekNumber }); - return result; + return Result.Success(response); } - public async Task> GetCalendarDates(CalendarQueries.GetAllDatesQuery request, - CancellationToken cancellationToken) { + public async Task>> GetCalendarDates(CalendarQueries.GetAllDatesQuery request, + CancellationToken cancellationToken) { using ResolvedDbContext? resolvedContext = this.Resolver.Resolve(EstateManagementDatabaseName, request.EstateId.ToString()); await using EstateManagementContext context = resolvedContext.Context; - List entities = context.Calendar.Where(c => c.Date <= DateTime.Now.Date).ToList(); - List result = new(); + var result = await ExecuteQuerySafeToList( + context.Calendar.Where(c => c.Date <= DateTime.Now.Date), cancellationToken, "Error retrieving calendar dates"); + + if (result.IsFailed) + return ResultHelpers.CreateFailure(result); + + var entities = result.Data; + + List response = new(); foreach (TransactionProcessor.Database.Entities.Calendar calendar in entities) - result.Add(new Calendar { + response.Add(new Calendar { Date = calendar.Date, DayOfWeek = calendar.DayOfWeek, Year = calendar.Year, @@ -123,47 +166,56 @@ public async Task> GetCalendarDates(CalendarQueries.GetAllDatesQu YearWeekNumber = calendar.YearWeekNumber }); - return result; + return Result.Success(response); } - public async Task> GetCalendarYears(CalendarQueries.GetYearsQuery request, + public async Task>> GetCalendarYears(CalendarQueries.GetYearsQuery request, CancellationToken cancellationToken) { using ResolvedDbContext? resolvedContext = this.Resolver.Resolve(EstateManagementDatabaseName, request.EstateId.ToString()); await using EstateManagementContext context = resolvedContext.Context; - List years = context.Calendar.Where(c => c.Date <= DateTime.Now.Date).GroupBy(c => c.Year).Select(y => y.Key).ToList(); + var result = await ExecuteQuerySafeToList( + context.Calendar.Where(c => c.Date <= DateTime.Now.Date).GroupBy(c => c.Year).Select(y => y.Key), + cancellationToken, "Error retrieving calendar years"); - return years; + if (result.IsFailed) + return ResultHelpers.CreateFailure(result); + + return result; } - public async Task> GetContracts(ContractQueries.GetContractsQuery request, + public async Task>> GetContracts(ContractQueries.GetContractsQuery request, CancellationToken cancellationToken) { using ResolvedDbContext? resolvedContext = this.Resolver.Resolve(EstateManagementDatabaseName, request.EstateId.ToString()); await using EstateManagementContext context = resolvedContext.Context; // Step 1: load contracts with operator name via a left-join (translatable) - var baseContracts = await (from c in context.Contracts - join o in context.Operators on c.OperatorId equals o.OperatorId into ops - from o in ops.DefaultIfEmpty() - select new - { - c.ContractId, - c.ContractReportingId, - c.Description, - c.EstateId, - c.OperatorId, - OperatorName = o != null ? o.Name : null - }) - .OrderByDescending(x => x.Description) - .ToListAsync(cancellationToken); - - if (!baseContracts.Any()) + var baseContractsQuery = (from c in context.Contracts + join o in context.Operators on c.OperatorId equals o.OperatorId into ops + from o in ops.DefaultIfEmpty() + select new { + c.ContractId, + c.ContractReportingId, + c.Description, + c.EstateId, + c.OperatorId, + OperatorName = o != null ? o.Name : null + }).OrderByDescending(x => x.Description); + + var baseContractsQueryResult = await ExecuteQuerySafeToList(baseContractsQuery, cancellationToken, "Error retrieving contracts - Step 1"); + + if (baseContractsQueryResult.IsFailed) + return ResultHelpers.CreateFailure(baseContractsQueryResult); + + var baseContractEntities = baseContractsQueryResult.Data; + + if (baseContractEntities.Any() == false) return new List(); - var contractIds = baseContracts.Select(b => b.ContractId).ToList(); + var contractIds = baseContractEntities.Select(b => b.ContractId).ToList(); // Step 2: load related products for all contracts in one query - var products = await context.ContractProducts + var productsQuery = context.ContractProducts .Where(cp => contractIds.Contains(cp.ContractId)) .Select(cp => new { @@ -173,13 +225,19 @@ from o in ops.DefaultIfEmpty() cp.ProductName, cp.ProductType, cp.Value - }) - .ToListAsync(cancellationToken); + }); - var productIds = products.Select(p => p.ContractProductId).ToList(); + var productsQueryResult = await ExecuteQuerySafeToList(productsQuery, cancellationToken, "Error retrieving contracts - Step 2"); + + if (productsQueryResult.IsFailed) + return ResultHelpers.CreateFailure(productsQueryResult); + + var productEntities = productsQueryResult.Data; + + var productIds = productEntities.Select(p => p.ContractProductId).ToList(); // Step 3: load fees for those products in one query - var fees = await context.ContractProductTransactionFees + var feesQuery = context.ContractProductTransactionFees .Where(tf => productIds.Contains(tf.ContractProductId)) .Select(tf => new { @@ -190,11 +248,17 @@ from o in ops.DefaultIfEmpty() tf.ContractProductId, tf.Description, tf.IsEnabled - }) - .ToListAsync(cancellationToken); + }); + + var feesQueryResult = await ExecuteQuerySafeToList(feesQuery, cancellationToken, "Error retrieving contracts - Step 3"); + + if (feesQueryResult.IsFailed) + return ResultHelpers.CreateFailure(feesQueryResult); + + var feesEntities = feesQueryResult.Data; // Assemble the model in memory - List result = baseContracts.Select(b => new Contract + List result = baseContractEntities.Select(b => new Contract { ContractId = b.ContractId, ContractReportingId = b.ContractReportingId, @@ -202,7 +266,7 @@ from o in ops.DefaultIfEmpty() EstateId = b.EstateId, OperatorName = b.OperatorName, OperatorId = b.OperatorId, - Products = products + Products = productEntities .Where(p => p.ContractId == b.ContractId) .Select(p => new Models.ContractProduct { @@ -212,7 +276,7 @@ from o in ops.DefaultIfEmpty() ProductName = p.ProductName, ProductType = p.ProductType, Value = p.Value, - TransactionFees = fees + TransactionFees = feesEntities .Where(f => f.ContractProductId == p.ContractProductId && f.IsEnabled) .Select(f => new ContractProductTransactionFee { Description = f.Description,Value = f.Value, CalculationType = f.CalculationType, FeeType = f.FeeType, TransactionFeeId = f.ContractProductTransactionFeeId}) .ToList() @@ -220,17 +284,17 @@ from o in ops.DefaultIfEmpty() .ToList() }).ToList(); - return result; + return Result.Success(result); } - public async Task GetContract(ContractQueries.GetContractQuery request, + public async Task> GetContract(ContractQueries.GetContractQuery request, CancellationToken cancellationToken) { using ResolvedDbContext? resolvedContext = this.Resolver.Resolve(EstateManagementDatabaseName, request.EstateId.ToString()); await using EstateManagementContext context = resolvedContext.Context; // Step 1: load contracts with operator name via a left-join (translatable) - var baseContract = await (from c in context.Contracts + var baseContractQuery = (from c in context.Contracts join o in context.Operators on c.OperatorId equals o.OperatorId into ops from o in ops.DefaultIfEmpty() where c.ContractId == request.ContractId @@ -243,14 +307,18 @@ from o in ops.DefaultIfEmpty() c.OperatorId, OperatorName = o != null ? o.Name : null }) - .OrderByDescending(x => x.Description) - .SingleOrDefaultAsync(cancellationToken); + .OrderByDescending(x => x.Description); - if (baseContract == null) - return null; + var baseContractQueryResult = await ExecuteQuerySafeSingleOrDefault(baseContractQuery, cancellationToken, "Error retrieving contract - Step 1"); + + if (baseContractQueryResult.IsFailed) + return ResultHelpers.CreateFailure(baseContractQueryResult); + + var baseContract = baseContractQueryResult.Data; + // Step 2: load related products for all contracts in one query - var products = await context.ContractProducts + var productsQuery = context.ContractProducts .Where(cp => cp.ContractId == baseContract.ContractId) .Select(cp => new { @@ -260,13 +328,18 @@ from o in ops.DefaultIfEmpty() cp.ProductName, cp.ProductType, cp.Value - }) - .ToListAsync(cancellationToken); + }); + + var productsQueryResult = await ExecuteQuerySafeToList(productsQuery, cancellationToken, "Error retrieving contract - Step 2"); + if (productsQueryResult.IsFailed) + return ResultHelpers.CreateFailure(productsQueryResult); + + var products = productsQueryResult.Data; var productIds = products.Select(p => p.ContractProductId).ToList(); // Step 3: load fees for those products in one query - var fees = await context.ContractProductTransactionFees + var feesQuery = context.ContractProductTransactionFees .Where(tf => productIds.Contains(tf.ContractProductId)) .Select(tf => new { @@ -276,8 +349,14 @@ from o in ops.DefaultIfEmpty() tf.Value, tf.ContractProductId, tf.Description - }) - .ToListAsync(cancellationToken); + }); + + var feesQueryResult = await ExecuteQuerySafeToList(feesQuery, cancellationToken, "Error retrieving contract - Step 3"); + + if (feesQueryResult.IsFailed) + return ResultHelpers.CreateFailure(feesQueryResult); + + var fees = feesQueryResult.Data; // Assemble the model in memory Contract result = new Contract @@ -306,15 +385,15 @@ from o in ops.DefaultIfEmpty() .ToList() }; - return result; + return Result.Success(result); } - public async Task> GetRecentContracts(ContractQueries.GetRecentContractsQuery request, + public async Task>> GetRecentContracts(ContractQueries.GetRecentContractsQuery request, CancellationToken cancellationToken) { using ResolvedDbContext? resolvedContext = this.Resolver.Resolve(EstateManagementDatabaseName, request.EstateId.ToString()); await using EstateManagementContext context = resolvedContext.Context; - var contracts = context.Contracts.Select(c => new Contract(){ + IQueryable contractsQuery = context.Contracts.Select(c => new Contract(){ ContractId = c.ContractId, ContractReportingId = c.ContractReportingId, Description = c.Description, @@ -323,19 +402,32 @@ public async Task> GetRecentContracts(ContractQueries.GetRecentCo OperatorId = c.OperatorId, }).OrderByDescending(c => c.Description).Take(3); - return await contracts.ToListAsync(cancellationToken); + Result> result = await ExecuteQuerySafeToList(contractsQuery, cancellationToken, "Error retrieving recent contracts"); + + if (result.IsFailed) + return ResultHelpers.CreateFailure(result); + + return result; } - public async Task GetTodaysFailedSales(TransactionQueries.TodaysFailedSales request, + public async Task> GetTodaysFailedSales(TransactionQueries.TodaysFailedSales request, CancellationToken cancellationToken) { using ResolvedDbContext? resolvedContext = this.Resolver.Resolve(EstateManagementDatabaseName, request.EstateId.ToString()); await using EstateManagementContext context = resolvedContext.Context; - List todaysSales = await (from t in context.TodayTransactions where t.IsAuthorised == false && t.TransactionType == "Sale" && t.ResponseCode == request.ResponseCode select t.TransactionAmount).ToListAsync(cancellationToken); - - List comparisonSales = await (from t in context.TransactionHistory where t.IsAuthorised == false && t.TransactionType == "Sale" && t.TransactionDate == request.ComparisonDate && t.TransactionTime <= DateTime.Now.TimeOfDay && t.ResponseCode == request.ResponseCode select t.TransactionAmount).ToListAsync(cancellationToken); + var todaysSalesQuery = (from t in context.TodayTransactions where t.IsAuthorised == false && t.TransactionType == "Sale" && t.ResponseCode == request.ResponseCode select t.TransactionAmount); + var comparisonSalesQuery = (from t in context.TransactionHistory where t.IsAuthorised == false && t.TransactionType == "Sale" && t.TransactionDate == request.ComparisonDate && t.TransactionTime <= DateTime.Now.TimeOfDay && t.ResponseCode == request.ResponseCode select t.TransactionAmount); + + var todaysSalesQueryResult = await ExecuteQuerySafeToList(todaysSalesQuery, cancellationToken, "Error retrieving todays failed sales"); + if (todaysSalesQueryResult.IsFailed) + return ResultHelpers.CreateFailure(todaysSalesQueryResult); + var comparisonSalesQueryResult = await ExecuteQuerySafeToList(comparisonSalesQuery, cancellationToken, "Error retrieving comparison failed sales"); + if (comparisonSalesQueryResult.IsFailed) + return ResultHelpers.CreateFailure(comparisonSalesQueryResult); + var todaysSales = todaysSalesQueryResult.Data; + var comparisonSales = comparisonSalesQueryResult.Data; TodaysSales response = new() { ComparisonSalesCount = comparisonSales.Count, @@ -345,10 +437,10 @@ public async Task GetTodaysFailedSales(TransactionQueries.TodaysFai TodaysSalesValue = todaysSales.Sum(), TodaysAverageSalesValue = this.SafeDivide(todaysSales.Sum(), todaysSales.Count) }; - return response; + return Result.Success(response); } - public async Task GetTodaysSales(TransactionQueries.TodaysSalesQuery request, + public async Task> GetTodaysSales(TransactionQueries.TodaysSalesQuery request, CancellationToken cancellationToken) { using ResolvedDbContext? resolvedContext = this.Resolver.Resolve(EstateManagementDatabaseName, request.EstateId.ToString()); await using EstateManagementContext context = resolvedContext.Context; @@ -359,6 +451,14 @@ public async Task GetTodaysSales(TransactionQueries.TodaysSalesQuer todaysSales = todaysSales.ApplyMerchantFilter(request.MerchantReportingId).ApplyOperatorFilter(request.OperatorReportingId); comparisonSales = comparisonSales.ApplyMerchantFilter(request.MerchantReportingId).ApplyOperatorFilter(request.OperatorReportingId); + var todaysSalesQueryResult = await ExecuteQuerySafeToList(todaysSales, cancellationToken, "Error retrieving todays failed sales"); + if (todaysSalesQueryResult.IsFailed) + return ResultHelpers.CreateFailure(todaysSalesQueryResult); + var comparisonSalesQueryResult = await ExecuteQuerySafeToList(comparisonSales, cancellationToken, "Error retrieving comparison failed sales"); + if (comparisonSalesQueryResult.IsFailed) + return ResultHelpers.CreateFailure(comparisonSalesQueryResult); + + Decimal todaysSalesValue = await todaysSales.SumAsync(t => t.TransactionAmount, cancellationToken); Int32 todaysSalesCount = await todaysSales.CountAsync(cancellationToken); Decimal comparisonSalesValue = await comparisonSales.SumAsync(t => t.TransactionAmount, cancellationToken); @@ -372,17 +472,17 @@ public async Task GetTodaysSales(TransactionQueries.TodaysSalesQuer TodaysAverageSalesValue = SafeDivide(todaysSalesValue, todaysSalesCount), ComparisonAverageSalesValue = SafeDivide(comparisonSalesValue,comparisonSalesCount) }; - return response; + return Result.Success(response); } - public async Task> GetEstateOperators(EstateQueries.GetEstateOperatorsQuery request, + public async Task>> GetEstateOperators(EstateQueries.GetEstateOperatorsQuery request, CancellationToken cancellationToken) { using ResolvedDbContext? resolvedContext = this.Resolver.Resolve(EstateManagementDatabaseName, request.EstateId.ToString()); await using EstateManagementContext context = resolvedContext.Context; - //var operatorEntities = context.EstateOperators.Where(e => e.EstateId == estateId).AsQueryable(); - //var x = operatorEntities.Join() - var operatorEntities = await context.EstateOperators + + + var operatorQuery = context.EstateOperators .Join( context.Operators, eo => new { eo.OperatorId, eo.EstateId }, @@ -392,9 +492,13 @@ public async Task> GetEstateOperators(EstateQueries.GetEsta EstateOperator = eo, Operator = op }) - .Where(e => e.EstateOperator.EstateId == request.EstateId && (e.EstateOperator.IsDeleted ?? false) == false) - .ToListAsync(cancellationToken); + .Where(e => e.EstateOperator.EstateId == request.EstateId && (e.EstateOperator.IsDeleted ?? false) == false); + + var operatorQueryResult = await ExecuteQuerySafeToList(operatorQuery, cancellationToken, "Error retrieving estate operators"); + if (operatorQueryResult.IsFailed) + return ResultHelpers.CreateFailure(operatorQueryResult); + var operatorEntities = operatorQueryResult.Data; List operators = new(); foreach (var operatorEntity in operatorEntities) { @@ -404,24 +508,43 @@ public async Task> GetEstateOperators(EstateQueries.GetEsta }); } - return operators; + return Result.Success(operators); } - public async Task GetEstate(EstateQueries.GetEstateQuery request, - CancellationToken cancellationToken) { + public async Task> GetEstate(EstateQueries.GetEstateQuery request, + CancellationToken cancellationToken) { using ResolvedDbContext? resolvedContext = this.Resolver.Resolve(EstateManagementDatabaseName, request.EstateId.ToString()); await using EstateManagementContext context = resolvedContext.Context; - var estate = await context.Estates.Where(e => e.EstateId == request.EstateId).SingleOrDefaultAsync(cancellationToken); + var estateQueryResult = await ExecuteQuerySafeSingleOrDefault(context.Estates.Where(e => e.EstateId == request.EstateId), cancellationToken, "Error retrieving estate"); + + if (estateQueryResult.IsFailed) + return ResultHelpers.CreateFailure(estateQueryResult); + var estate = estateQueryResult.Data; // Operators - var operators = await context.Operators.Where(e => e.EstateId == request.EstateId).ToListAsync(cancellationToken); + var operatorsListQueryResult = await ExecuteQuerySafeToList(context.Operators.Where(e => e.EstateId == request.EstateId), cancellationToken, "Error retrieving estate operators"); + if (operatorsListQueryResult.IsFailed) + return ResultHelpers.CreateFailure(operatorsListQueryResult); + var operators = operatorsListQueryResult.Data; + // Users - var users = await context.EstateSecurityUsers.Where(e => e.EstateId == request.EstateId).ToListAsync(cancellationToken); + var usersListQueryResult = await ExecuteQuerySafeToList(context.EstateSecurityUsers.Where(e => e.EstateId == request.EstateId), cancellationToken, "Error retrieving estate users"); + if (usersListQueryResult.IsFailed) + return ResultHelpers.CreateFailure(usersListQueryResult); + var users = usersListQueryResult.Data; + // Merchants - var merchants = await context.Merchants.Where(e => e.EstateId == request.EstateId).ToListAsync(cancellationToken); + var merchantsListQueryResult = await ExecuteQuerySafeToList(context.Merchants.Where(e => e.EstateId == request.EstateId), cancellationToken, "Error retrieving merchants"); + if (merchantsListQueryResult.IsFailed) + return ResultHelpers.CreateFailure(merchantsListQueryResult); + var merchants = merchantsListQueryResult.Data; + // Contracts - var contracts = await context.Contracts.Where(e => e.EstateId == request.EstateId).ToListAsync(cancellationToken); + var contractsListQueryResult = await ExecuteQuerySafeToList(context.Contracts.Where(e => e.EstateId == request.EstateId), cancellationToken, "Error retrieving contracts"); + if (contractsListQueryResult.IsFailed) + return ResultHelpers.CreateFailure(contractsListQueryResult); + var contracts = contractsListQueryResult.Data; Estate result = new() { @@ -472,13 +595,13 @@ private Decimal SafeDivide(Decimal number, - public async Task> GetRecentMerchants(MerchantQueries.GetRecentMerchantsQuery request, + public async Task>> GetRecentMerchants(MerchantQueries.GetRecentMerchantsQuery request, CancellationToken cancellationToken) { using ResolvedDbContext? resolvedContext = this.Resolver.Resolve(EstateManagementDatabaseName, request.EstateId.ToString()); await using EstateManagementContext context = resolvedContext.Context; - var merchants = context.Merchants.Select(m => new { + var merchantsQuery = context.Merchants.Select(m => new { MerchantReportingId = m.MerchantReportingId, Name = m.Name, LastSaleDateTime = m.LastSaleDateTime, @@ -504,64 +627,77 @@ public async Task> GetRecentMerchants(MerchantQueries.GetRecentMe EstateReportingId = context.Estates.Single(e => e.EstateId == m.EstateId).EstateReportingId }).OrderByDescending(m => m.CreatedDateTime).Take(3); + var recentMerchantsResult = await ExecuteQuerySafeToList(merchantsQuery, cancellationToken, "Error retrieving recent merchants"); + if (recentMerchantsResult.IsFailed) + return ResultHelpers.CreateFailure(recentMerchantsResult); + + var recentMerchants = recentMerchantsResult.Data; + List merchantList = new(); - foreach (var result in merchants) + foreach (var merchant in recentMerchants) { Merchant model = new() { - MerchantId = result.MerchantId, - Name = result.Name, - Reference = result.Reference, - MerchantReportingId = result.MerchantReportingId, - CreatedDateTime = result.CreatedDateTime, + MerchantId = merchant.MerchantId, + Name = merchant.Name, + Reference = merchant.Reference, + MerchantReportingId = merchant.MerchantReportingId, + CreatedDateTime = merchant.CreatedDateTime, }; - if (result.AddressInfo != null) { - model.AddressLine1 = result.AddressInfo.AddressLine1; - model.AddressLine2 = result.AddressInfo.AddressLine2; - model.Country = result.AddressInfo.Country; - model.PostCode = result.AddressInfo.PostalCode; - model.Town = result.AddressInfo.Town; - model.Region = result.AddressInfo.Region; + if (merchant.AddressInfo != null) { + model.AddressLine1 = merchant.AddressInfo.AddressLine1; + model.AddressLine2 = merchant.AddressInfo.AddressLine2; + model.Country = merchant.AddressInfo.Country; + model.PostCode = merchant.AddressInfo.PostalCode; + model.Town = merchant.AddressInfo.Town; + model.Region = merchant.AddressInfo.Region; } - if (result.ContactInfo != null) { - model.ContactName = result.ContactInfo.Name; - model.ContactEmail = result.ContactInfo.EmailAddress; - model.ContactPhone = result.ContactInfo.PhoneNumber; + if (merchant.ContactInfo != null) { + model.ContactName = merchant.ContactInfo.Name; + model.ContactEmail = merchant.ContactInfo.EmailAddress; + model.ContactPhone = merchant.ContactInfo.PhoneNumber; } merchantList.Add(model); } - return merchantList; + return Result.Success(merchantList); } - public async Task GetMerchantsTransactionKpis(MerchantQueries.GetTransactionKpisQuery request, + public async Task> GetMerchantsTransactionKpis(MerchantQueries.GetTransactionKpisQuery request, CancellationToken cancellationToken) { using ResolvedDbContext? resolvedContext = this.Resolver.Resolve(EstateManagementDatabaseName, request.EstateId.ToString()); await using EstateManagementContext context = resolvedContext.Context; - var merchants = await context.Merchants.Select(m => new { m.Name, m.LastSaleDate, m.LastSaleDateTime }).ToListAsync(); - Int32 merchantsWithSaleInLastHour = (from m in context.Merchants where m.LastSaleDate == DateTime.Now.Date && m.LastSaleDateTime >= DateTime.Now.AddHours(-1) select m.MerchantReportingId).Count(); + + var merchantsQuery = context.Merchants.Select(m => new { m.Name, m.LastSaleDate, m.LastSaleDateTime }); + var merchantsQueryResult = await ExecuteQuerySafeToList(merchantsQuery, cancellationToken, "Error retrieving merchants for KPI's"); + if (merchantsQueryResult.IsFailed) + return ResultHelpers.CreateFailure(merchantsQueryResult); + + var merchants = merchantsQueryResult.Data; + + Int32 merchantsWithSaleInLastHour = (from m in merchants where m.LastSaleDate == DateTime.Now.Date && m.LastSaleDateTime >= DateTime.Now.AddHours(-1) select m).Count(); - Int32 merchantsWithNoSaleToday = (from m in context.Merchants where m.LastSaleDate >= DateTime.Now.Date.AddDays(-7) && m.LastSaleDate <= DateTime.Now.Date.AddDays(-1) select m.MerchantReportingId).Count(); + Int32 merchantsWithNoSaleToday = (from m in merchants where m.LastSaleDate >= DateTime.Now.Date.AddDays(-7) && m.LastSaleDate <= DateTime.Now.Date.AddDays(-1) select m).Count(); - Int32 merchantsWithNoSaleInLast7Days = (from m in context.Merchants where m.LastSaleDate <= DateTime.Now.Date.AddDays(-7) select m.MerchantReportingId).Count(); + Int32 merchantsWithNoSaleInLast7Days = (from m in merchants where m.LastSaleDate <= DateTime.Now.Date.AddDays(-7) select m).Count(); MerchantKpi response = new() { MerchantsWithSaleInLastHour = merchantsWithSaleInLastHour, MerchantsWithNoSaleToday = merchantsWithNoSaleToday, MerchantsWithNoSaleInLast7Days = merchantsWithNoSaleInLast7Days }; - return response; + return Result.Success(response); } - public async Task> GetOperators(OperatorQueries.GetOperatorsQuery request, + public async Task>> GetOperators(OperatorQueries.GetOperatorsQuery request, CancellationToken cancellationToken) { using ResolvedDbContext? resolvedContext = this.Resolver.Resolve(EstateManagementDatabaseName, request.EstateId.ToString()); await using EstateManagementContext context = resolvedContext.Context; - List operators = await (from o in context.Operators - select new Operator + var operatorQuery = (from o in context.Operators + select new { Name = o.Name, EstateReportingId = context.Estates.Single(e => e.EstateId == o.EstateId).EstateReportingId, @@ -569,32 +705,65 @@ public async Task> GetOperators(OperatorQueries.GetOperatorsQuery OperatorReportingId = o.OperatorReportingId, RequireCustomMerchantNumber = o.RequireCustomMerchantNumber, RequireCustomTerminalNumber = o.RequireCustomTerminalNumber - }).ToListAsync(cancellationToken); + }); + + var operatorResult = await ExecuteQuerySafeToList(operatorQuery, cancellationToken, "Error retrieving operator"); - return operators; + if (operatorResult.IsFailed) + return ResultHelpers.CreateFailure(operatorResult); + + List operators = new List(); + foreach (var op in operatorResult.Data) { + operators.Add(new Operator + { + Name = op.Name, + EstateReportingId = op.EstateReportingId, + OperatorId = op.OperatorId, + OperatorReportingId = op.OperatorReportingId, + RequireCustomMerchantNumber = op.RequireCustomMerchantNumber, + RequireCustomTerminalNumber = op.RequireCustomTerminalNumber + }); + } + + return Result.Success(operators); } - public async Task GetOperator(OperatorQueries.GetOperatorQuery request, + public async Task> GetOperator(OperatorQueries.GetOperatorQuery request, CancellationToken cancellationToken) { using ResolvedDbContext? resolvedContext = this.Resolver.Resolve(EstateManagementDatabaseName, request.EstateId.ToString()); await using EstateManagementContext context = resolvedContext.Context; - Operator @operator = await (from o in context.Operators + var operatorQuery = (from o in context.Operators where o.OperatorId == request.OperatorId - select new Operator { - Name = o.Name, - EstateReportingId = context.Estates.Single(e => e.EstateId == o.EstateId).EstateReportingId, - OperatorId = o.OperatorId, + select new { + Name = o.Name, + EstateReportingId = context.Estates.Single(e => e.EstateId == o.EstateId).EstateReportingId, + OperatorId = o.OperatorId, OperatorReportingId = o.OperatorReportingId, RequireCustomMerchantNumber = o.RequireCustomMerchantNumber, RequireCustomTerminalNumber = o.RequireCustomTerminalNumber - }).SingleOrDefaultAsync(cancellationToken); + }); + + var operatorResult = await ExecuteQuerySafeSingleOrDefault(operatorQuery, cancellationToken, "Error retrieving operator"); - return @operator; + if (operatorResult.IsFailed) + return ResultHelpers.CreateFailure(operatorResult); + + var @operator = new Operator + { + Name = operatorResult.Data.Name, + EstateReportingId = operatorResult.Data.EstateReportingId, + OperatorId = operatorResult.Data.OperatorId, + OperatorReportingId = operatorResult.Data.OperatorReportingId, + RequireCustomMerchantNumber = operatorResult.Data.RequireCustomMerchantNumber, + RequireCustomTerminalNumber = operatorResult.Data.RequireCustomTerminalNumber + }; + + return Result.Success(@operator); } - public async Task GetTransactionDetailReport(TransactionQueries.TransactionDetailReportQuery request, + public async Task GetTransactionDetailReport(TransactionQueries.TransactionDetailReportQuery request, CancellationToken cancellationToken) { TransactionDetailReportResponse response = null; @@ -648,8 +817,14 @@ from s in sJoin.DefaultIfEmpty() query = query.Where(q => request.Request.Operators.Contains(q.OperatorReportingId)); } + var queryResult = await ExecuteQuerySafeToList(query, cancellationToken, "Error retrieving transaction details resport"); + + if (queryResult.IsFailed) + return ResultHelpers.CreateFailure(queryResult); + // Ok now enumerate the results - var queryResults = await query.ToListAsync(cancellationToken); + var queryResults = queryResult.Data; + if (queryResults.Any() == false) return new TransactionDetailReportResponse { @@ -687,8 +862,8 @@ from s in sJoin.DefaultIfEmpty() return response; } - public async Task> GetMerchants(MerchantQueries.GetMerchantsQuery request, - CancellationToken cancellationToken) { + public async Task>> GetMerchants(MerchantQueries.GetMerchantsQuery request, + CancellationToken cancellationToken) { using ResolvedDbContext? resolvedContext = this.Resolver.Resolve(EstateManagementDatabaseName, request.EstateId.ToString()); await using EstateManagementContext context = resolvedContext.Context; @@ -731,11 +906,17 @@ public async Task> GetMerchants(MerchantQueries.GetMerchantsQuery merchantWithAddresses = merchantWithAddresses.Where(m => m.Address.PostalCode == request.QueryOptions.PostCode).AsQueryable(); } + var queryResults = await ExecuteQuerySafeToList(merchantWithAddresses, cancellationToken, "Error retrieving merchants"); + + if (queryResults.IsFailed) + return ResultHelpers.CreateFailure(queryResults); + + var merchants = queryResults.Data; + // Ok now enumerate the results - var queryResults = await merchantWithAddresses.ToListAsync(cancellationToken); - List merchants = new(); - foreach (var queryResult in queryResults) { - merchants.Add(new Merchant { + List response = new(); + foreach (var queryResult in merchants) { + response.Add(new Merchant { Balance = 0, CreatedDateTime = queryResult.Merchant.CreatedDateTime, Name = queryResult.Merchant.Name, @@ -752,16 +933,16 @@ public async Task> GetMerchants(MerchantQueries.GetMerchantsQuery }); } - return merchants; + return Result.Success(response); } - public async Task GetMerchant(MerchantQueries.GetMerchantQuery request, + public async Task> GetMerchant(MerchantQueries.GetMerchantQuery request, CancellationToken cancellationToken) { using ResolvedDbContext? resolvedContext = this.Resolver.Resolve(EstateManagementDatabaseName, request.EstateId.ToString()); await using EstateManagementContext context = resolvedContext.Context; - var merchant = await context.Merchants.Select(m => new { + var merchantQuery = context.Merchants.Select(m => new { MerchantReportingId = m.MerchantReportingId, Name = m.Name, LastSaleDateTime = m.LastSaleDateTime, @@ -781,17 +962,16 @@ public async Task GetMerchant(MerchantQueries.GetMerchantQuery request ma.Town // Add more properties as needed }).FirstOrDefault(), // Get the first matching MerchantAddress or null - ContactInfo = context.MerchantContacts.Where(mc => mc.MerchantId == m.MerchantId).OrderByDescending(mc => mc.CreatedDateTime).Select(mc => new { - mc.ContactId, - mc.Name, - mc.EmailAddress, - mc.PhoneNumber - }).FirstOrDefault(), // Get the first matching MerchantContact or null + ContactInfo = context.MerchantContacts.Where(mc => mc.MerchantId == m.MerchantId).OrderByDescending(mc => mc.CreatedDateTime).Select(mc => new { mc.ContactId, mc.Name, mc.EmailAddress, mc.PhoneNumber }).FirstOrDefault(), // Get the first matching MerchantContact or null EstateReportingId = context.Estates.Single(e => e.EstateId == m.EstateId).EstateReportingId - }).Where(m => m.MerchantId == request.MerchantId).SingleOrDefaultAsync(cancellationToken); + }).Where(m => m.MerchantId == request.MerchantId); + + var merchantQueryResult = await ExecuteQuerySafeSingleOrDefault(merchantQuery, cancellationToken, "Error getting merchant"); + + if (merchantQueryResult.IsFailed) + return ResultHelpers.CreateFailure(merchantQueryResult); - if (merchant == null) - return null; + var merchant = merchantQueryResult.Data; // Ok now enumerate the results Merchant result = new Merchant @@ -815,17 +995,23 @@ public async Task GetMerchant(MerchantQueries.GetMerchantQuery request ContactEmail = merchant.ContactInfo.EmailAddress, ContactPhone = merchant.ContactInfo.PhoneNumber }; - - return result; + + return Result.Success(result); } - public async Task> GetMerchantOperators(MerchantQueries.GetMerchantOperatorsQuery request, - CancellationToken cancellationToken) { + public async Task>> GetMerchantOperators(MerchantQueries.GetMerchantOperatorsQuery request, + CancellationToken cancellationToken) { using ResolvedDbContext? resolvedContext = this.Resolver.Resolve(EstateManagementDatabaseName, request.EstateId.ToString()); await using EstateManagementContext context = resolvedContext.Context; - List merchantOperators = await context.MerchantOperators.Where(mo => mo.MerchantId == request.MerchantId && mo.IsDeleted == false) - .ToListAsync(cancellationToken); + var merchantOperatorsQuery = context.MerchantOperators.Where(mo => mo.MerchantId == request.MerchantId && mo.IsDeleted == false); + + var merchantOperatorsQueryResult = await ExecuteQuerySafeToList(merchantOperatorsQuery, cancellationToken, "Error getting merchant devices"); + + if (merchantOperatorsQueryResult.IsFailed) + return ResultHelpers.CreateFailure(merchantOperatorsQueryResult); + + var merchantOperators = merchantOperatorsQueryResult.Data; List result = new(); foreach (TransactionProcessor.Database.Entities.MerchantOperator merchantOperator in merchantOperators) { @@ -839,15 +1025,15 @@ public async Task> GetMerchantOperators(MerchantQueries.G }); } - return result; + return Result.Success(result); } - public async Task> GetMerchantContracts(MerchantQueries.GetMerchantContractsQuery request, - CancellationToken cancellationToken) { + public async Task>> GetMerchantContracts(MerchantQueries.GetMerchantContractsQuery request, + CancellationToken cancellationToken) { using ResolvedDbContext? resolvedContext = this.Resolver.Resolve(EstateManagementDatabaseName, request.EstateId.ToString()); await using EstateManagementContext context = resolvedContext.Context; - var merchantContracts = await context.MerchantContracts.Where(mo => mo.MerchantId == request.MerchantId && mo.IsDeleted == false) + var merchantContractsQuery = context.MerchantContracts.Where(mo => mo.MerchantId == request.MerchantId && mo.IsDeleted == false) .Select(mc => new { mc.ContractId, mc.IsDeleted, @@ -864,8 +1050,14 @@ public async Task> GetMerchantContracts(MerchantQueries.G }).ToList() // Add more properties as needed }).SingleOrDefault() - }) - .ToListAsync(cancellationToken); + }); + + var merchantContractsQueryResult = await ExecuteQuerySafeToList(merchantContractsQuery, cancellationToken, "Error getting merchant devices"); + + if (merchantContractsQueryResult.IsFailed) + return ResultHelpers.CreateFailure(merchantContractsQueryResult); + + var merchantContracts = merchantContractsQueryResult.Data; List result = new(); foreach (var merchantContract in merchantContracts) @@ -895,15 +1087,21 @@ public async Task> GetMerchantContracts(MerchantQueries.G result.Add(c); } - return result; + return Result.Success(result); } - public async Task> GetMerchantDevices(MerchantQueries.GetMerchantDevicesQuery request, - CancellationToken cancellationToken) { + public async Task>> GetMerchantDevices(MerchantQueries.GetMerchantDevicesQuery request, + CancellationToken cancellationToken) { using ResolvedDbContext? resolvedContext = this.Resolver.Resolve(EstateManagementDatabaseName, request.EstateId.ToString()); await using EstateManagementContext context = resolvedContext.Context; - List merchantDevices = await context.MerchantDevices.Where(mo => mo.MerchantId == request.MerchantId).ToListAsync(cancellationToken); + var merchantDevicesQuery = context.MerchantDevices.Where(mo => mo.MerchantId == request.MerchantId); + var merchantDevicesQueryResult = await ExecuteQuerySafeToList(merchantDevicesQuery, cancellationToken, "Error getting merchant devices"); + + if (merchantDevicesQueryResult.IsFailed) + return ResultHelpers.CreateFailure(merchantDevicesQueryResult); + + var merchantDevices = merchantDevicesQueryResult.Data; List result = new(); foreach (TransactionProcessor.Database.Entities.MerchantDevice merchantDevice in merchantDevices) @@ -917,7 +1115,7 @@ public async Task> GetMerchantDevices(MerchantQueries.GetMe }); } - return result; + return Result.Success(result); } private IQueryable BuildTodaySalesQuery(EstateManagementContext context) { diff --git a/EstateReportingAPI.BusinessLogic/RequestHandlers/CalendarRequestHandler.cs b/EstateReportingAPI.BusinessLogic/RequestHandlers/CalendarRequestHandler.cs index 2ffa65a..ba2b226 100644 --- a/EstateReportingAPI.BusinessLogic/RequestHandlers/CalendarRequestHandler.cs +++ b/EstateReportingAPI.BusinessLogic/RequestHandlers/CalendarRequestHandler.cs @@ -1,6 +1,7 @@ using EstateReportingAPI.BusinessLogic.Queries; using EstateReportingAPI.Models; using MediatR; +using Shared.Results; using SimpleResults; namespace EstateReportingAPI.BusinessLogic.RequestHandlers; @@ -13,35 +14,21 @@ public CalendarRequestHandler(IReportingManager manager) { } public async Task>> Handle(CalendarQueries.GetAllDatesQuery request, CancellationToken cancellationToken) { - List result = await this.Manager.GetCalendarDates(request, cancellationToken); - - if (result.Any() == false) { - return Result.NotFound("No calendar dates found"); - } - - return Result.Success(result); - + return await this.Manager.GetCalendarDates(request, cancellationToken); } public async Task>> Handle(CalendarQueries.GetComparisonDatesQuery request, CancellationToken cancellationToken) { - List result = await this.Manager.GetCalendarComparisonDates(request, cancellationToken); - if (result.Any() == false) - { - return Result.NotFound("No calendar comparison dates found"); - } + Result> result = await this.Manager.GetCalendarComparisonDates(request, cancellationToken); - return Result.Success(result); + if (result.IsFailed) + return ResultHelpers.CreateFailure(result); + + return Result.Success(result.Data); } public async Task>> Handle(CalendarQueries.GetYearsQuery request, CancellationToken cancellationToken) { - List result = await this.Manager.GetCalendarYears(request, cancellationToken); - if (result.Any() == false) - { - return Result.NotFound("No calendar years found"); - } - - return Result.Success(result); + return await this.Manager.GetCalendarYears(request, cancellationToken); } } \ No newline at end of file diff --git a/EstateReportingAPI.BusinessLogic/RequestHandlers/ContractRequestHandler.cs b/EstateReportingAPI.BusinessLogic/RequestHandlers/ContractRequestHandler.cs index a56373e..d763de1 100644 --- a/EstateReportingAPI.BusinessLogic/RequestHandlers/ContractRequestHandler.cs +++ b/EstateReportingAPI.BusinessLogic/RequestHandlers/ContractRequestHandler.cs @@ -18,21 +18,19 @@ public ContractRequestHandler(IReportingManager manager) } public async Task>> Handle(ContractQueries.GetRecentContractsQuery request, CancellationToken cancellationToken) { - var result = await this.Manager.GetRecentContracts(request, cancellationToken); - return Result.Success(result); + return await this.Manager.GetRecentContracts(request, cancellationToken); } public async Task>> Handle(ContractQueries.GetContractsQuery request, CancellationToken cancellationToken) { var result = await this.Manager.GetContracts(request, cancellationToken); - return Result.Success(result); + return result; } public async Task> Handle(ContractQueries.GetContractQuery request, CancellationToken cancellationToken) { - var result = await this.Manager.GetContract(request, cancellationToken); - return Result.Success(result); + return await this.Manager.GetContract(request, cancellationToken); } } \ No newline at end of file diff --git a/EstateReportingAPI.BusinessLogic/RequestHandlers/EstateRequestHandler.cs b/EstateReportingAPI.BusinessLogic/RequestHandlers/EstateRequestHandler.cs index e07c589..44437c1 100644 --- a/EstateReportingAPI.BusinessLogic/RequestHandlers/EstateRequestHandler.cs +++ b/EstateReportingAPI.BusinessLogic/RequestHandlers/EstateRequestHandler.cs @@ -18,13 +18,11 @@ public EstateRequestHandler(IReportingManager manager) public async Task> Handle(EstateQueries.GetEstateQuery request, CancellationToken cancellationToken) { - var result = await this.Manager.GetEstate(request, cancellationToken); - return Result.Success(result); + return await this.Manager.GetEstate(request, cancellationToken); } public async Task>> Handle(EstateQueries.GetEstateOperatorsQuery request, CancellationToken cancellationToken) { - var result = await this.Manager.GetEstateOperators(request, cancellationToken); - return Result.Success(result); + return await this.Manager.GetEstateOperators(request, cancellationToken); } } \ No newline at end of file diff --git a/EstateReportingAPI.BusinessLogic/RequestHandlers/MerchantRequestHandler.cs b/EstateReportingAPI.BusinessLogic/RequestHandlers/MerchantRequestHandler.cs index e642e6c..bd46bd6 100644 --- a/EstateReportingAPI.BusinessLogic/RequestHandlers/MerchantRequestHandler.cs +++ b/EstateReportingAPI.BusinessLogic/RequestHandlers/MerchantRequestHandler.cs @@ -21,47 +21,36 @@ public MerchantRequestHandler(IReportingManager manager) public async Task>> Handle(MerchantQueries.GetRecentMerchantsQuery request, CancellationToken cancellationToken) { - var result = await this.Manager.GetRecentMerchants(request, cancellationToken); - return Result.Success(result); + return await this.Manager.GetRecentMerchants(request, cancellationToken); } public async Task> Handle(MerchantQueries.GetTransactionKpisQuery request, CancellationToken cancellationToken) { - var result = await this.Manager.GetMerchantsTransactionKpis(request, cancellationToken); - return Result.Success(result); + return await this.Manager.GetMerchantsTransactionKpis(request, cancellationToken); } public async Task>> Handle(MerchantQueries.GetMerchantsQuery request, CancellationToken cancellationToken) { - var result = await this.Manager.GetMerchants(request, cancellationToken); - return Result.Success(result); + return await this.Manager.GetMerchants(request, cancellationToken); } public async Task> Handle(MerchantQueries.GetMerchantQuery request, CancellationToken cancellationToken) { - var result = await this.Manager.GetMerchant(request, cancellationToken); - - if (result == null) - return Result.NotFound(); - - return Result.Success(result); + return await this.Manager.GetMerchant(request, cancellationToken); } public async Task>> Handle(MerchantQueries.GetMerchantContractsQuery request, CancellationToken cancellationToken) { - var result = await this.Manager.GetMerchantContracts(request, cancellationToken); - return Result.Success(result); + return await this.Manager.GetMerchantContracts(request, cancellationToken); } public async Task>> Handle(MerchantQueries.GetMerchantOperatorsQuery request, CancellationToken cancellationToken) { - var result = await this.Manager.GetMerchantOperators(request, cancellationToken); - return Result.Success(result); + return await this.Manager.GetMerchantOperators(request, cancellationToken); } public async Task>> Handle(MerchantQueries.GetMerchantDevicesQuery request, CancellationToken cancellationToken) { - var result = await this.Manager.GetMerchantDevices(request, cancellationToken); - return Result.Success(result); + return await this.Manager.GetMerchantDevices(request, cancellationToken); } } \ No newline at end of file diff --git a/EstateReportingAPI.BusinessLogic/RequestHandlers/OperatorRequestHandler.cs b/EstateReportingAPI.BusinessLogic/RequestHandlers/OperatorRequestHandler.cs index e6c7c0f..41384c7 100644 --- a/EstateReportingAPI.BusinessLogic/RequestHandlers/OperatorRequestHandler.cs +++ b/EstateReportingAPI.BusinessLogic/RequestHandlers/OperatorRequestHandler.cs @@ -17,13 +17,11 @@ public OperatorRequestHandler(IReportingManager manager) { public async Task>> Handle(OperatorQueries.GetOperatorsQuery request, CancellationToken cancellationToken) { - List result = await this.Manager.GetOperators(request, cancellationToken); - return Result.Success(result); + return await this.Manager.GetOperators(request, cancellationToken); } public async Task> Handle(OperatorQueries.GetOperatorQuery request, CancellationToken cancellationToken) { - Operator result = await this.Manager.GetOperator(request, cancellationToken); - return Result.Success(result); + return await this.Manager.GetOperator(request, cancellationToken); } } \ No newline at end of file diff --git a/EstateReportingAPI.BusinessLogic/RequestHandlers/TransactionRequestHandler.cs b/EstateReportingAPI.BusinessLogic/RequestHandlers/TransactionRequestHandler.cs index 694e98b..7d90384 100644 --- a/EstateReportingAPI.BusinessLogic/RequestHandlers/TransactionRequestHandler.cs +++ b/EstateReportingAPI.BusinessLogic/RequestHandlers/TransactionRequestHandler.cs @@ -16,14 +16,12 @@ public TransactionRequestHandler(IReportingManager manager) { public async Task> Handle(TransactionQueries.TodaysFailedSales request, CancellationToken cancellationToken) { - var result = await this.Manager.GetTodaysFailedSales(request, cancellationToken); - return Result.Success(result); + return await this.Manager.GetTodaysFailedSales(request, cancellationToken); } public async Task> Handle(TransactionQueries.TodaysSalesQuery request, CancellationToken cancellationToken) { - var result = await this.Manager.GetTodaysSales(request, cancellationToken); - return Result.Success(result); + return await this.Manager.GetTodaysSales(request, cancellationToken); } public async Task> Handle(TransactionQueries.TransactionDetailReportQuery request, diff --git a/EstateReportingAPI.Client/EstateReportingAPI.Client.csproj b/EstateReportingAPI.Client/EstateReportingAPI.Client.csproj index dc35b67..26e9874 100644 --- a/EstateReportingAPI.Client/EstateReportingAPI.Client.csproj +++ b/EstateReportingAPI.Client/EstateReportingAPI.Client.csproj @@ -7,9 +7,9 @@ - + - + diff --git a/EstateReportingAPI.IntegrationTests/EstateReportingAPI.IntegrationTests.csproj b/EstateReportingAPI.IntegrationTests/EstateReportingAPI.IntegrationTests.csproj index fb50b6e..da9c3c4 100644 --- a/EstateReportingAPI.IntegrationTests/EstateReportingAPI.IntegrationTests.csproj +++ b/EstateReportingAPI.IntegrationTests/EstateReportingAPI.IntegrationTests.csproj @@ -22,9 +22,9 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - - - + + + diff --git a/EstateReportingAPI/EstateReportingAPI.csproj b/EstateReportingAPI/EstateReportingAPI.csproj index 12832ee..090108b 100644 --- a/EstateReportingAPI/EstateReportingAPI.csproj +++ b/EstateReportingAPI/EstateReportingAPI.csproj @@ -12,8 +12,8 @@ - - + + @@ -21,7 +21,7 @@ - + From 354e1eb5e549b0a7408c451d7868d2a3616b8682 Mon Sep 17 00:00:00 2001 From: Stuart Ferguson Date: Thu, 12 Feb 2026 17:47:38 +0000 Subject: [PATCH 2/3] oops --- EstateReportingAPI.BusinessLogic/ReportingManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EstateReportingAPI.BusinessLogic/ReportingManager.cs b/EstateReportingAPI.BusinessLogic/ReportingManager.cs index 523ddb6..6352e05 100644 --- a/EstateReportingAPI.BusinessLogic/ReportingManager.cs +++ b/EstateReportingAPI.BusinessLogic/ReportingManager.cs @@ -763,7 +763,7 @@ public async Task> GetOperator(OperatorQueries.GetOperatorQuery return Result.Success(@operator); } - public async Task GetTransactionDetailReport(TransactionQueries.TransactionDetailReportQuery request, + public async Task> GetTransactionDetailReport(TransactionQueries.TransactionDetailReportQuery request, CancellationToken cancellationToken) { TransactionDetailReportResponse response = null; From 160e58e0283239c89c35102384eeddcc33df4948 Mon Sep 17 00:00:00 2001 From: Stuart Ferguson Date: Thu, 12 Feb 2026 20:52:03 +0000 Subject: [PATCH 3/3] :| --- .../RequestHandlers/TransactionRequestHandler.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/EstateReportingAPI.BusinessLogic/RequestHandlers/TransactionRequestHandler.cs b/EstateReportingAPI.BusinessLogic/RequestHandlers/TransactionRequestHandler.cs index 7d90384..82fa12d 100644 --- a/EstateReportingAPI.BusinessLogic/RequestHandlers/TransactionRequestHandler.cs +++ b/EstateReportingAPI.BusinessLogic/RequestHandlers/TransactionRequestHandler.cs @@ -26,7 +26,6 @@ public async Task> Handle(TransactionQueries.TodaysSalesQuer public async Task> Handle(TransactionQueries.TransactionDetailReportQuery request, CancellationToken cancellationToken) { - var result = await this.Manager.GetTransactionDetailReport(request, cancellationToken); - return Result.Success(result); + return await this.Manager.GetTransactionDetailReport(request, cancellationToken); } } \ No newline at end of file