@@ -516,41 +516,31 @@ public async Task<Result<List<Merchant>>> GetRecentMerchants(MerchantQueries.Get
516516 var merchantsQuery = context . Merchants . Select ( m => new {
517517 MerchantReportingId = m . MerchantReportingId ,
518518 Name = m . Name ,
519- LastSaleDateTime = m . LastSaleDateTime ,
520- LastSale = m . LastSaleDate ,
521519 CreatedDateTime = m . CreatedDateTime ,
522- LastStatement = m . LastStatementGenerated ,
523520 MerchantId = m . MerchantId ,
524521 Reference = m . Reference ,
525- AddressInfo = context . MerchantAddresses . Where ( ma => ma . MerchantId == m . MerchantId ) . OrderByDescending ( ma => ma . CreatedDateTime ) . Select ( ma => new {
526- ma . AddressLine1 ,
527- ma . AddressLine2 ,
528- ma . Country ,
529- ma . PostalCode ,
530- ma . Region ,
531- ma . Town
532- // Add more properties as needed
533- } ) . FirstOrDefault ( ) , // Get the first matching MerchantAddress or null
534- ContactInfo = context . MerchantContacts . Where ( mc => mc . MerchantId == m . MerchantId ) . OrderByDescending ( mc => mc . CreatedDateTime ) . Select ( mc => new { mc . Name , mc . EmailAddress , mc . PhoneNumber } ) . FirstOrDefault ( ) , // Get the first matching MerchantContact or null
535- EstateReportingId = context . Estates . Single ( e => e . EstateId == m . EstateId ) . EstateReportingId
522+ AddressInfo = context . MerchantAddresses . Where ( ma => ma . MerchantId == m . MerchantId )
523+ . OrderByDescending ( ma => ma . CreatedDateTime )
524+ . Select ( ma => new { ma . AddressLine1 , ma . AddressLine2 , ma . Country , ma . PostalCode , ma . Region , ma . Town } )
525+ . FirstOrDefault ( ) ,
526+ ContactInfo = context . MerchantContacts . Where ( mc => mc . MerchantId == m . MerchantId )
527+ . OrderByDescending ( mc => mc . CreatedDateTime )
528+ . Select ( mc => new { mc . Name , mc . EmailAddress , mc . PhoneNumber } )
529+ . FirstOrDefault ( )
536530 } ) . OrderByDescending ( m => m . CreatedDateTime ) . Take ( 3 ) ;
537531
538532 var recentMerchantsResult = await ExecuteQuerySafeToList ( merchantsQuery , cancellationToken , "Error retrieving recent merchants" ) ;
539533 if ( recentMerchantsResult . IsFailed )
540534 return ResultHelpers . CreateFailure ( recentMerchantsResult ) ;
541535
542- var recentMerchants = recentMerchantsResult . Data ;
543-
544- List < Merchant > merchantList = new ( ) ;
545- foreach ( var merchant in recentMerchants ) {
536+ List < Merchant > merchantList = recentMerchantsResult . Data . Select ( merchant => {
546537 Merchant model = new ( ) {
547538 MerchantId = merchant . MerchantId ,
548539 Name = merchant . Name ,
549540 Reference = merchant . Reference ,
550541 MerchantReportingId = merchant . MerchantReportingId ,
551542 CreatedDateTime = merchant . CreatedDateTime ,
552543 } ;
553-
554544 if ( merchant . AddressInfo != null ) {
555545 model . AddressLine1 = merchant . AddressInfo . AddressLine1 ;
556546 model . AddressLine2 = merchant . AddressInfo . AddressLine2 ;
@@ -559,15 +549,13 @@ public async Task<Result<List<Merchant>>> GetRecentMerchants(MerchantQueries.Get
559549 model . Town = merchant . AddressInfo . Town ;
560550 model . Region = merchant . AddressInfo . Region ;
561551 }
562-
563552 if ( merchant . ContactInfo != null ) {
564553 model . ContactName = merchant . ContactInfo . Name ;
565554 model . ContactEmail = merchant . ContactInfo . EmailAddress ;
566555 model . ContactPhone = merchant . ContactInfo . PhoneNumber ;
567556 }
568-
569- merchantList . Add ( model ) ;
570- }
557+ return model ;
558+ } ) . ToList ( ) ;
571559
572560 return Result . Success ( merchantList ) ;
573561 }
@@ -665,12 +653,26 @@ public async Task<Result<Operator>> GetOperator(OperatorQueries.GetOperatorQuery
665653
666654 public async Task < Result < TransactionDetailReportResponse > > GetTransactionDetailReport ( TransactionQueries . TransactionDetailReportQuery request ,
667655 CancellationToken cancellationToken ) {
668-
669- TransactionDetailReportResponse response = null ;
670656 using ResolvedDbContext < EstateManagementContext > ? resolvedContext = this . Resolver . Resolve ( EstateManagementDatabaseName , request . EstateId . ToString ( ) ) ;
671657 await using EstateManagementContext context = resolvedContext . Context ;
672658
673- var query = from t in context . Transactions
659+ var query = ApplyTransactionDetailFilters ( BuildTransactionDetailBaseQuery ( context , request . Request ) , request . Request ) ;
660+ var queryResult = await ExecuteQuerySafeToList ( query , cancellationToken , "Error retrieving transaction details report" ) ;
661+
662+ if ( queryResult . IsFailed )
663+ return ResultHelpers . CreateFailure ( queryResult ) ;
664+
665+ var queryResults = queryResult . Data ;
666+
667+ if ( queryResults . Any ( ) == false )
668+ return new TransactionDetailReportResponse { Summary = new TransactionDetailSummary ( ) , Transactions = new List < TransactionDetail > ( ) } ;
669+
670+ return Result . Success ( MapToTransactionDetailResponse ( queryResults ) ) ;
671+ }
672+
673+ private static IQueryable < TransactionDetailQueryResult > BuildTransactionDetailBaseQuery ( EstateManagementContext context ,
674+ TransactionDetailReportRequest request ) {
675+ return from t in context . Transactions
674676 join cp in context . ContractProducts on new { t . ContractProductId , t . ContractId } equals new { cp . ContractProductId , cp . ContractId }
675677 join m in context . Merchants on t . MerchantId equals m . MerchantId
676678 join o in context . Operators on t . OperatorId equals o . OperatorId
@@ -679,10 +681,10 @@ from msf in msfJoin.DefaultIfEmpty()
679681 // left join Settlements (msf may be null)
680682 join s in context . Settlements on msf . SettlementId equals s . SettlementId into sJoin
681683 from s in sJoin . DefaultIfEmpty ( )
682- where t . TransactionType != "Logon" && t . TransactionDate >= request . Request . StartDate && t . TransactionDate <= request . Request . EndDate
683- select new {
684- t . TransactionId ,
685- t . TransactionDateTime ,
684+ where t . TransactionType != "Logon" && t . TransactionDate >= request . StartDate && t . TransactionDate <= request . EndDate
685+ select new TransactionDetailQueryResult {
686+ TransactionId = t . TransactionId ,
687+ TransactionDateTime = t . TransactionDateTime ,
686688 MerchantId = m . MerchantId ,
687689 MerchantReportingId = m . MerchantReportingId ,
688690 MerchantName = m . Name ,
@@ -698,33 +700,21 @@ from s in sJoin.DefaultIfEmpty()
698700 FeeValue = msf != null ? msf . FeeValue : 0m ,
699701 SettlementId = s != null ? s . SettlementId : Guid . Empty ,
700702 } ;
703+ }
701704
702- // Now apply the filters
703- if ( request . Request . Merchants != null && request . Request . Merchants . Any ( ) ) {
704- query = query . Where ( q => request . Request . Merchants . Contains ( q . MerchantReportingId ) ) ;
705- }
706-
707- if ( request . Request . Products != null && request . Request . Products . Any ( ) ) {
708- query = query . Where ( q => request . Request . Products . Contains ( q . ContractProductReportingId ) ) ;
709- }
710-
711- if ( request . Request . Operators != null && request . Request . Operators . Any ( ) ) {
712- query = query . Where ( q => request . Request . Operators . Contains ( q . OperatorReportingId ) ) ;
713- }
714-
715- var queryResult = await ExecuteQuerySafeToList ( query , cancellationToken , "Error retrieving transaction details report" ) ;
716-
717- if ( queryResult . IsFailed )
718- return ResultHelpers . CreateFailure ( queryResult ) ;
719-
720- // Ok now enumerate the results
721- var queryResults = queryResult . Data ;
722-
723- if ( queryResults . Any ( ) == false )
724- return new TransactionDetailReportResponse { Summary = new TransactionDetailSummary ( ) , Transactions = new List < TransactionDetail > ( ) } ;
705+ private static IQueryable < TransactionDetailQueryResult > ApplyTransactionDetailFilters ( IQueryable < TransactionDetailQueryResult > query ,
706+ TransactionDetailReportRequest request ) {
707+ if ( request . Merchants != null && request . Merchants . Any ( ) )
708+ query = query . Where ( q => request . Merchants . Contains ( q . MerchantReportingId ) ) ;
709+ if ( request . Products != null && request . Products . Any ( ) )
710+ query = query . Where ( q => request . Products . Contains ( q . ContractProductReportingId ) ) ;
711+ if ( request . Operators != null && request . Operators . Any ( ) )
712+ query = query . Where ( q => request . Operators . Contains ( q . OperatorReportingId ) ) ;
713+ return query ;
714+ }
725715
726- // Now to translate the results
727- response = new TransactionDetailReportResponse {
716+ private static TransactionDetailReportResponse MapToTransactionDetailResponse ( List < TransactionDetailQueryResult > queryResults ) {
717+ return new TransactionDetailReportResponse {
728718 Transactions = queryResults . Select ( q => new TransactionDetail {
729719 Id = q . TransactionId ,
730720 DateTime = q . TransactionDateTime ,
@@ -745,8 +735,6 @@ from s in sJoin.DefaultIfEmpty()
745735 } ) . ToList ( ) ,
746736 Summary = new TransactionDetailSummary { TransactionCount = queryResults . Count ( ) , TotalValue = queryResults . Sum ( q => q . Value ) , TotalFees = queryResults . Sum ( q => q . FeeValue ) }
747737 } ;
748-
749- return Result . Success ( response ) ;
750738 }
751739
752740 public async Task < Result < TransactionSummaryByMerchantResponse > > GetTransactionSummaryByMerchantReport ( TransactionQueries . TransactionSummaryByMerchantQuery request ,
@@ -1152,44 +1140,48 @@ public async Task<Result<ProductPerformanceResponse>> GetProductPerformanceRepor
11521140
11531141 using ResolvedDbContext < EstateManagementContext > ? resolvedContext = this . Resolver . Resolve ( EstateManagementDatabaseName , request . EstateId . ToString ( ) ) ;
11541142 await using EstateManagementContext context = resolvedContext . Context ;
1155- var grandTotalAmountQuery = ( from t in context . Transactions where t . TransactionType == "Sale" && t . TransactionDate >= new DateTime ( 2025 , 12 , 21 ) && t . TransactionDate <= new DateTime ( 2025 , 12 , 25 ) select t . TransactionAmount ) ;
11561143
1144+ var grandTotalAmountQuery = ( from t in context . Transactions where t . TransactionType == "Sale" && t . TransactionDate >= new DateTime ( 2025 , 12 , 21 ) && t . TransactionDate <= new DateTime ( 2025 , 12 , 25 ) select t . TransactionAmount ) ;
11571145 var grandTotalAmountResult = await ExecuteQuerySafeSum < decimal > ( grandTotalAmountQuery , cancellationToken ) ;
11581146 if ( grandTotalAmountResult . IsFailed )
11591147 return ResultHelpers . CreateFailure ( grandTotalAmountResult ) ;
11601148 var grandTotalAmount = grandTotalAmountResult . Data ;
11611149
1162- var query = from t in context . Transactions
1150+ var query = BuildProductPerformanceQuery ( context , request . StartDate , request . EndDate , grandTotalAmount ) ;
1151+ var queryResult = await ExecuteQuerySafeToList ( query , cancellationToken ) ;
1152+ if ( queryResult . IsFailed )
1153+ return ResultHelpers . CreateFailure ( queryResult ) ;
1154+ var queryResults = queryResult . Data ;
1155+ if ( queryResults . Any ( ) == false )
1156+ return Result . Success ( new ProductPerformanceResponse ( ) { Summary = new ProductPerformanceSummary ( ) , ProductDetails = new List < ProductPerformanceDetail > ( ) } ) ;
1157+
1158+ return Result . Success ( BuildProductPerformanceResponse ( queryResults ) ) ;
1159+ }
1160+
1161+ private static IQueryable < ProductPerformanceItemData > BuildProductPerformanceQuery ( EstateManagementContext context ,
1162+ DateTime startDate ,
1163+ DateTime endDate ,
1164+ decimal grandTotalAmount ) {
1165+ return from t in context . Transactions
11631166 join cp in context . ContractProducts on new { t . ContractProductId , t . ContractId } equals new { cp . ContractProductId , cp . ContractId }
11641167 join c in context . Contracts on t . ContractId equals c . ContractId
1165- where t . TransactionType == "Sale" && t . TransactionDate >= request . StartDate && t . TransactionDate <= request . EndDate
1166- group t by new {
1167- cp . ProductName ,
1168- cp . ContractProductId ,
1169- cp . ContractProductReportingId ,
1170- c . ContractId ,
1171- c . ContractReportingId
1172- }
1168+ where t . TransactionType == "Sale" && t . TransactionDate >= startDate && t . TransactionDate <= endDate
1169+ group t by new { cp . ProductName , cp . ContractProductId , cp . ContractProductReportingId , c . ContractId , c . ContractReportingId }
11731170 into g
1174- select new {
1175- g . Key . ProductName ,
1176- g . Key . ContractProductId ,
1177- g . Key . ContractProductReportingId ,
1178- g . Key . ContractId ,
1179- g . Key . ContractReportingId ,
1171+ select new ProductPerformanceItemData {
1172+ ProductName = g . Key . ProductName ,
1173+ ContractProductId = g . Key . ContractProductId ,
1174+ ContractProductReportingId = g . Key . ContractProductReportingId ,
1175+ ContractId = g . Key . ContractId ,
1176+ ContractReportingId = g . Key . ContractReportingId ,
11801177 TransactionCount = g . Count ( ) ,
11811178 TotalAmount = g . Sum ( x => x . TransactionAmount ) ,
11821179 PercentOfTotalAmount = grandTotalAmount == 0 ? 0 : 100.0m * g . Sum ( x => x . TransactionAmount ) / grandTotalAmount
11831180 } ;
1181+ }
11841182
1185- var queryResult = await ExecuteQuerySafeToList ( query , cancellationToken ) ;
1186- if ( queryResult . IsFailed )
1187- return ResultHelpers . CreateFailure ( queryResult ) ;
1188- var queryResults = queryResult . Data ;
1189- if ( queryResults . Any ( ) == false )
1190- return Result . Success ( new ProductPerformanceResponse ( ) { Summary = new ProductPerformanceSummary ( ) , ProductDetails = new List < ProductPerformanceDetail > ( ) } ) ;
1191-
1192- ProductPerformanceResponse response = new ProductPerformanceResponse ( ) {
1183+ private ProductPerformanceResponse BuildProductPerformanceResponse ( List < ProductPerformanceItemData > queryResults ) {
1184+ return new ProductPerformanceResponse {
11931185 ProductDetails = queryResults . Select ( q => new ProductPerformanceDetail {
11941186 ProductName = q . ProductName ,
11951187 ProductId = q . ContractProductId ,
@@ -1202,8 +1194,6 @@ into g
12021194 } ) . ToList ( ) ,
12031195 Summary = new ProductPerformanceSummary { TotalCount = queryResults . Sum ( q => q . TransactionCount ) , TotalValue = queryResults . Sum ( q => q . TotalAmount ) , AveragePerProduct = this . SafeDivide ( queryResults . Sum ( q => q . TotalAmount ) , queryResults . Count ) , TotalProducts = queryResults . Count ( ) }
12041196 } ;
1205-
1206- return Result . Success ( response ) ;
12071197 }
12081198
12091199 public async Task < Result < List < TodaysSalesByHour > > > GetTodaysSalesByHour ( TransactionQueries . TodaysSalesByHour request ,
@@ -1418,6 +1408,23 @@ private sealed class MerchantTransactionFinalProjection {
14181408 public int AuthorisedCount { get ; init ; }
14191409 public int DeclinedCount { get ; init ; }
14201410 public decimal AuthorisedPercentage { get ; init ; }
1411+ private sealed class TransactionDetailQueryResult {
1412+ public Guid TransactionId { get ; init ; }
1413+ public DateTime TransactionDateTime { get ; init ; }
1414+ public Guid MerchantId { get ; init ; }
1415+ public int MerchantReportingId { get ; init ; }
1416+ public string ? MerchantName { get ; init ; }
1417+ public Guid OperatorId { get ; init ; }
1418+ public int OperatorReportingId { get ; init ; }
1419+ public string ? OperatorName { get ; init ; }
1420+ public string ? ProductName { get ; init ; }
1421+ public Guid ContractProductId { get ; init ; }
1422+ public int ContractProductReportingId { get ; init ; }
1423+ public string ? TransactionType { get ; init ; }
1424+ public string ? Status { get ; init ; }
1425+ public decimal Value { get ; init ; }
1426+ public decimal FeeValue { get ; init ; }
1427+ public Guid SettlementId { get ; init ; }
14211428 }
14221429
14231430 private sealed class ContractBaseData {
@@ -1448,6 +1455,17 @@ private sealed class ContractFeeData {
14481455 public bool IsEnabled { get ; init ; }
14491456 }
14501457
1458+ private sealed class ProductPerformanceItemData {
1459+ public string ? ProductName { get ; init ; }
1460+ public Guid ContractProductId { get ; init ; }
1461+ public int ContractProductReportingId { get ; init ; }
1462+ public Guid ContractId { get ; init ; }
1463+ public int ContractReportingId { get ; init ; }
1464+ public int TransactionCount { get ; init ; }
1465+ public decimal TotalAmount { get ; init ; }
1466+ public decimal PercentOfTotalAmount { get ; init ; }
1467+ }
1468+
14511469 #endregion
14521470 }
14531471
0 commit comments