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
235 changes: 2 additions & 233 deletions EstateReportingAPI.BusinessLogic/ReportingManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,104 +13,8 @@ namespace EstateReportingAPI.BusinessLogic{
using Merchant = Models.Merchant;
using Operator = Models.Operator;

public class FeeTransactionProjection
{
public MerchantSettlementFee Fee { get; set; }
public Transaction Txn { get; set; }
}

public static class ReportingManagerExtensions{
public static IQueryable<FeeTransactionProjection> ApplyMerchantFilter(
this IQueryable<FeeTransactionProjection> query,
EstateManagementContext context,
List<int> merchantIds)
{
if (merchantIds == null || merchantIds.Count == 0)
return query;

return from q in query
join m in context.Merchants
on q.Txn.MerchantId equals m.MerchantId
where merchantIds.Contains(m.MerchantReportingId)
select q;
}

public static IQueryable<FeeTransactionProjection> ApplyOperatorFilter(
this IQueryable<FeeTransactionProjection> query,
EstateManagementContext context,
List<int> operatorIds)
{
if (operatorIds == null || operatorIds.Count == 0)
return query;

return from q in query
join o in context.Operators
on q.Txn.OperatorId equals o.OperatorId
where operatorIds.Contains(o.OperatorReportingId)
select q;
}

public static IQueryable<FeeTransactionProjection> ApplyProductFilter(
this IQueryable<FeeTransactionProjection> query,
EstateManagementContext context,
List<int> productIds)
{
if (productIds == null || productIds.Count == 0)
return query;

return from q in query
join cp in context.ContractProducts
on q.Txn.ContractProductId equals cp.ContractProductId
where productIds.Contains(cp.ContractProductReportingId)
select q;
}

public static IQueryable<UnsettledFee> ApplyProductGrouping(this IQueryable<FeeTransactionProjection> fees,
EstateManagementContext context)
{
return from f in fees
join cp in context.ContractProducts on f.Txn.ContractProductId equals cp.ContractProductId
join c in context.Contracts on cp.ContractId equals c.ContractId
join op in context.Operators on c.OperatorId equals op.OperatorId
group f by new { op.Name, cp.ProductName } into g
select new UnsettledFee
{
DimensionName = $"{g.Key.Name} - {g.Key.ProductName}",
FeesValue = g.Sum(x => x.Fee.CalculatedValue),
FeesCount = g.Count()
};
}

public static IQueryable<UnsettledFee> ApplyMerchantGrouping(this IQueryable<FeeTransactionProjection> fees,
EstateManagementContext context)
{
return from f in fees
join merchant in context.Merchants on f.Fee.MerchantId equals merchant.MerchantId
group f by merchant.Name into g
select new UnsettledFee
{
DimensionName = g.Key,
FeesValue = g.Sum(x => x.Fee.CalculatedValue),
FeesCount = g.Count()
};
}

public static IQueryable<UnsettledFee> ApplyOperatorGrouping(this IQueryable<FeeTransactionProjection> fees,
EstateManagementContext context)
{
return from f in fees
join op in context.Operators on f.Txn.OperatorId equals op.OperatorId
group f by op.Name into g
select new UnsettledFee
{
DimensionName = g.Key,
FeesValue = g.Sum(x => x.Fee.CalculatedValue),
FeesCount = g.Count()
};
}
}

public class ReportingManager : IReportingManager{
public partial class ReportingManager : IReportingManager{
private readonly IDbContextResolver<EstateManagementContext> Resolver;


Expand All @@ -126,41 +30,6 @@ public ReportingManager(IDbContextResolver<EstateManagementContext> resolver) {

#region Methods


private IQueryable<FeeTransactionProjection> BuildUnsettledFeesQuery(
EstateManagementContext context,
DateTime startDate,
DateTime endDate)
{
return from merchantSettlementFee in context.MerchantSettlementFees
join transaction in context.Transactions
on merchantSettlementFee.TransactionId equals transaction.TransactionId
where merchantSettlementFee.FeeCalculatedDateTime.Date >= startDate &&
merchantSettlementFee.FeeCalculatedDateTime.Date <= endDate
select new FeeTransactionProjection { Fee = merchantSettlementFee, Txn = transaction };
}

public async Task<List<UnsettledFee>> GetUnsettledFees(Guid estateId, DateTime startDate, DateTime endDate, List<Int32> merchantIds, List<Int32> operatorIds, List<Int32> productIds, GroupByOption? groupByOption, CancellationToken cancellationToken){

using ResolvedDbContext<EstateManagementContext>? resolvedContext = this.Resolver.Resolve(EstateManagementDatabaseName, estateId.ToString());
await using EstateManagementContext context = resolvedContext.Context;

IQueryable<FeeTransactionProjection> query = BuildUnsettledFeesQuery(context, startDate, endDate)
.ApplyMerchantFilter(context, merchantIds)
.ApplyOperatorFilter(context, operatorIds)
.ApplyProductFilter(context, productIds);

// Perform grouping
IQueryable<UnsettledFee> groupedQuery = groupByOption switch
{
GroupByOption.Merchant => query.ApplyMerchantGrouping(context),
GroupByOption.Operator => query.ApplyOperatorGrouping(context),
GroupByOption.Product => query.ApplyProductGrouping(context),
};
return await groupedQuery.ToListAsync(cancellationToken);

}

public async Task<List<Calendar>> GetCalendarComparisonDates(Guid estateId, CancellationToken cancellationToken){
using ResolvedDbContext<EstateManagementContext>? resolvedContext = this.Resolver.Resolve(EstateManagementDatabaseName, estateId.ToString());
await using EstateManagementContext context = resolvedContext.Context;
Expand Down Expand Up @@ -819,107 +688,7 @@ public async Task<TodaysSales> GetOperatorPerformance(Guid estateId, DateTime co

return response;
}

public async Task<List<TransactionResult>> TransactionSearch(Guid estateId, TransactionSearchRequest searchRequest, PagingRequest pagingRequest, SortingRequest sortingRequest, CancellationToken cancellationToken){
// Base query before any filtering is added
using ResolvedDbContext<EstateManagementContext>? resolvedContext = this.Resolver.Resolve(EstateManagementDatabaseName, estateId.ToString());
await using EstateManagementContext context = resolvedContext.Context;

var mainQuery = (from txn in context.Transactions
join merchant in context.Merchants on txn.MerchantId equals merchant.MerchantId
join @operator in context.Operators on txn.OperatorId equals @operator.OperatorId
join product in context.ContractProducts on txn.ContractProductId equals product.ContractProductId
where txn.TransactionDate == searchRequest.QueryDate.Date
select new
{
Transaction = txn,
Merchant = merchant,
Operator = @operator,
Product = product
}).AsQueryable();

// Now apply the filtering
if (searchRequest.Operators != null && searchRequest.Operators.Any())
{
mainQuery = mainQuery.Where(m => searchRequest.Operators.Contains(m.Operator.OperatorReportingId));
}

if (searchRequest.Merchants != null && searchRequest.Merchants.Any())
{
mainQuery = mainQuery.Where(m => searchRequest.Merchants.Contains(m.Merchant.MerchantReportingId));
}

if (searchRequest.ValueRange != null)
{
mainQuery = mainQuery.Where(m => m.Transaction.TransactionAmount >= searchRequest.ValueRange.StartValue &&
m.Transaction.TransactionAmount <= searchRequest.ValueRange.EndValue);
}

if (String.IsNullOrEmpty(searchRequest.AuthCode) == false)
{
mainQuery = mainQuery.Where(m => m.Transaction.AuthorisationCode == searchRequest.AuthCode);
}

if (String.IsNullOrEmpty(searchRequest.ResponseCode) == false)
{
mainQuery = mainQuery.Where(m => m.Transaction.ResponseCode == searchRequest.ResponseCode);
}

if (String.IsNullOrEmpty(searchRequest.TransactionNumber) == false)
{
mainQuery = mainQuery.Where(m => m.Transaction.TransactionNumber == searchRequest.TransactionNumber);
}

Int32 skipCount = 0;
if (pagingRequest.Page > 1)
{
skipCount = (pagingRequest.Page - 1) * pagingRequest.PageSize;
}

if (sortingRequest != null)
{
// Handle order by here, cant think of a better way of achieving this
mainQuery = (sortingRequest.SortDirection, sortingRequest.SortField) switch
{
(SortDirection.Ascending, SortField.MerchantName) => mainQuery.OrderBy(m => m.Merchant.Name),
(SortDirection.Ascending, SortField.OperatorName) => mainQuery.OrderBy(m => m.Operator.Name),
(SortDirection.Ascending, SortField.TransactionAmount) => mainQuery.OrderBy(m => m.Transaction.TransactionAmount),
(SortDirection.Descending, SortField.MerchantName) => mainQuery.OrderByDescending(m => m.Merchant.Name),
(SortDirection.Descending, SortField.OperatorName) => mainQuery.OrderByDescending(m => m.Operator.Name),
(SortDirection.Descending, SortField.TransactionAmount) => mainQuery.OrderByDescending(m => m.Transaction.TransactionAmount),
_ => mainQuery.OrderByDescending(m => m.Transaction.TransactionDateTime)
};
}

var queryResults = await mainQuery.Skip(skipCount).Take(pagingRequest.PageSize)
.ToListAsync(cancellationToken);

List<TransactionResult> results = new List<TransactionResult>();

queryResults.ForEach(qr =>
{
results.Add(new TransactionResult
{
MerchantReportingId = qr.Merchant.MerchantReportingId,
ResponseCode = qr.Transaction.ResponseCode,
IsAuthorised = qr.Transaction.IsAuthorised,
MerchantName = qr.Merchant.Name,
OperatorName = qr.Operator.Name,
OperatorReportingId = qr.Operator.OperatorReportingId,
Product = qr.Product.ProductName,
ProductReportingId = qr.Product.ContractProductReportingId,
ResponseMessage = qr.Transaction.ResponseMessage,
TransactionDateTime = qr.Transaction.TransactionDateTime,
TransactionId = qr.Transaction.TransactionId,
TransactionReportingId = qr.Transaction.TransactionReportingId,
TransactionSource = qr.Transaction.TransactionSource.ToString(), // TODO: Name for this
TransactionAmount = qr.Transaction.TransactionAmount
});
});

return results;
}


public async Task<List<Merchant>> GetMerchants(Guid estateId,
CancellationToken cancellationToken) {
using ResolvedDbContext<EstateManagementContext>? resolvedContext = this.Resolver.Resolve(EstateManagementDatabaseName, estateId.ToString());
Expand Down
Loading
Loading