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
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ namespace EstateReportingAPI.BusinessLogic.Queries;
public record TransactionQueries {
public record TodaysSalesQuery(Guid EstateId, Int32 MerchantReportingId, Int32 OperatorReportingId, DateTime ComparisonDate) : IRequest<Result<TodaysSales>>;
public record TodaysFailedSales(Guid EstateId, DateTime ComparisonDate, String ResponseCode) : IRequest<Result<TodaysSales>>;
public record TransactionDetailReportQuery(Guid EstateId, TransactionDetailReportRequest Request) : IRequest<Result<TransactionDetailReportResponse>>;
}
95 changes: 93 additions & 2 deletions EstateReportingAPI.BusinessLogic/ReportingManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
Task<Contract> GetContract(ContractQueries.GetContractQuery request, CancellationToken cancellationToken);
Task<TodaysSales> GetTodaysFailedSales(TransactionQueries.TodaysFailedSales request, CancellationToken cancellationToken);
Task<TodaysSales> GetTodaysSales(TransactionQueries.TodaysSalesQuery request, CancellationToken cancellationToken);

Task<Estate> GetEstate(EstateQueries.GetEstateQuery request, CancellationToken cancellationToken);
Task<List<EstateOperator>> GetEstateOperators(EstateQueries.GetEstateOperatorsQuery request, CancellationToken cancellationToken);
Task<MerchantKpi> GetMerchantsTransactionKpis(MerchantQueries.GetTransactionKpisQuery request, CancellationToken cancellationToken);
Expand All @@ -38,9 +37,11 @@
Task<List<MerchantOperator>> GetMerchantOperators(MerchantQueries.GetMerchantOperatorsQuery request, CancellationToken cancellationToken);
Task<List<MerchantContract>> GetMerchantContracts(MerchantQueries.GetMerchantContractsQuery request, CancellationToken cancellationToken);
Task<List<MerchantDevice>> GetMerchantDevices(MerchantQueries.GetMerchantDevicesQuery request, CancellationToken cancellationToken);

Task<Operator> GetOperator(OperatorQueries.GetOperatorQuery request, CancellationToken cancellationToken);

Task<TransactionDetailReportResponse> GetTransactionDetailReport(TransactionQueries.TransactionDetailReportQuery request,
CancellationToken cancellationToken);

#endregion
}

Expand Down Expand Up @@ -593,6 +594,95 @@
return @operator;
}

public async Task<TransactionDetailReportResponse> GetTransactionDetailReport(TransactionQueries.TransactionDetailReportQuery request,

Check warning on line 597 in EstateReportingAPI.BusinessLogic/ReportingManager.cs

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

EstateReportingAPI.BusinessLogic/ReportingManager.cs#L597

Method ReportingManager::GetTransactionDetailReport has 78 lines of code (limit is 50)

Check warning on line 597 in EstateReportingAPI.BusinessLogic/ReportingManager.cs

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

EstateReportingAPI.BusinessLogic/ReportingManager.cs#L597

Method ReportingManager::GetTransactionDetailReport has a cyclomatic complexity of 15 (limit is 8)
CancellationToken cancellationToken) {

TransactionDetailReportResponse response = null;
using ResolvedDbContext<EstateManagementContext>? resolvedContext = this.Resolver.Resolve(EstateManagementDatabaseName, request.EstateId.ToString());
await using EstateManagementContext context = resolvedContext.Context;

var query = from t in context.Transactions
join cp in context.ContractProducts
on new { t.ContractProductId, t.ContractId } equals new { cp.ContractProductId, cp.ContractId }
join m in context.Merchants on t.MerchantId equals m.MerchantId
join o in context.Operators on t.OperatorId equals o.OperatorId
join msf in context.MerchantSettlementFees on t.TransactionId equals msf.TransactionId into msfJoin
from msf in msfJoin.DefaultIfEmpty()
// left join Settlements (msf may be null)
join s in context.Settlements on msf.SettlementId equals s.SettlementId into sJoin
from s in sJoin.DefaultIfEmpty()
where t.TransactionType != "Logon"
&& t.IsAuthorised // equivalent to IsAuthorised = 1
&& t.TransactionDate >= request.Request.StartDate
&& t.TransactionDate <= request.Request.EndDate
select new
{
t.TransactionId,
t.TransactionDateTime,
MerchantId = m.MerchantId,
MerchantReportingId = m.MerchantReportingId,
MerchantName = m.Name,
OperatorId = o.OperatorId,
OperatorReportingId = o.OperatorReportingId,
OperatorName = o.Name,
ProductName = cp.ProductName,
ContractProductId = cp.ContractProductId,
ContractProductReportingId = cp.ContractProductReportingId,
TransactionType = t.TransactionType,
Status = t.IsAuthorised ? "Authorised" : "Declined",
Value = t.TransactionAmount,
FeeValue = msf != null ? msf.FeeValue : 0m,
SettlementId = s != null ? s.SettlementId : Guid.Empty,
};

// Now apply the filters
if (request.Request.Merchants != null && request.Request.Merchants.Any()) {
query = query.Where(q => request.Request.Merchants.Contains(q.MerchantReportingId));
}
if (request.Request.Products != null && request.Request.Products.Any())
{
query = query.Where(q => request.Request.Products.Contains(q.ContractProductReportingId));
}
if (request.Request.Operators != null && request.Request.Operators.Any())
{
query = query.Where(q => request.Request.Operators.Contains(q.OperatorReportingId));
}

// Ok now enumerate the results
var queryResults = await query.ToListAsync(cancellationToken);
if (queryResults.Any() == false)
return response;

// Now to translate the results
response = new TransactionDetailReportResponse {
Transactions = queryResults.Select(q => new TransactionDetail {
Id = q.TransactionId,
DateTime = q.TransactionDateTime,
MerchantId = q.MerchantId,
MerchantReportingId = q.MerchantReportingId,
Merchant = q.MerchantName,
OperatorId = q.OperatorId,
OperatorReportingId = q.OperatorReportingId,
Operator = q.OperatorName,
Product = q.ProductName,
ProductId = q.ContractProductId,
ProductReportingId = q.ContractProductReportingId,
Type = q.TransactionType,
Status = q.Status,
Value = q.Value,
TotalFees = q.FeeValue,
SettlementReference = q.SettlementId.ToString()
}).ToList(),
Summary = new TransactionDetailSummary {
TransactionCount = queryResults.Count(),
TotalValue = queryResults.Sum(q => q.Value),
TotalFees = queryResults.Sum(q => q.FeeValue)
}
};

return response;
}

public async Task<List<Merchant>> GetMerchants(MerchantQueries.GetMerchantsQuery request,
CancellationToken cancellationToken) {
using ResolvedDbContext<EstateManagementContext>? resolvedContext = this.Resolver.Resolve(EstateManagementDatabaseName, request.EstateId.ToString());
Expand Down Expand Up @@ -844,3 +934,4 @@

#endregion
}

Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
namespace EstateReportingAPI.BusinessLogic.RequestHandlers;

public class TransactionRequestHandler : IRequestHandler<TransactionQueries.TodaysFailedSales, Result<TodaysSales>>,
IRequestHandler<TransactionQueries.TodaysSalesQuery, Result<TodaysSales>>{
IRequestHandler<TransactionQueries.TodaysSalesQuery, Result<TodaysSales>>,
IRequestHandler<TransactionQueries.TransactionDetailReportQuery, Result<TransactionDetailReportResponse>> {
private readonly IReportingManager Manager;

public TransactionRequestHandler(IReportingManager manager) {
Expand All @@ -24,4 +25,10 @@ public async Task<Result<TodaysSales>> Handle(TransactionQueries.TodaysSalesQuer
var result = await this.Manager.GetTodaysSales(request, cancellationToken);
return Result.Success(result);
}

public async Task<Result<TransactionDetailReportResponse>> Handle(TransactionQueries.TransactionDetailReportQuery request,
CancellationToken cancellationToken) {
var result = await this.Manager.GetTransactionDetailReport(request, cancellationToken);
return Result.Success(result);
}
}
70 changes: 69 additions & 1 deletion EstateReportingAPI.DataTrasferObjects/TransactionResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,20 @@
namespace EstateReportingAPI.DataTransferObjects{
using Newtonsoft.Json;

public class TransactionDetailReportRequest
{
[JsonProperty("operators")]
public List<Int32>? Operators { get; set; }
[JsonProperty("merchants")]
public List<Int32>? Merchants { get; set; }
[JsonProperty("products")]
public List<Int32>? Products { get; set; }
[JsonProperty("start_date")]
public DateTime StartDate { get; set; }
[JsonProperty("end_date")]
public DateTime EndDate { get; set; }
}

public class TransactionResult{
[JsonProperty("transaction_amount")]
public Decimal TransactionAmount{ get; set; }
Expand Down Expand Up @@ -46,7 +60,7 @@ public class TransactionSearchRequest{

[JsonProperty("merchants")]
public List<Int32>? Merchants{ get; set; }

[JsonProperty("query_date")]
public DateTime QueryDate{ get; set; }

Expand Down Expand Up @@ -87,4 +101,58 @@ public enum GroupByOption{
Product
}

public class TransactionDetailReportResponse
{
[JsonProperty("transactions")]
public List<TransactionDetail> Transactions { get; set; }
[JsonProperty("summary")]
public TransactionDetailSummary Summary { get; set; }
}

public class TransactionDetailSummary
{
[JsonProperty("total_value")]
public Decimal TotalValue { get; set; }
[JsonProperty("total_fees")]
public Decimal TotalFees { get; set; }
[JsonProperty("transaction_count")]
public Int32 TransactionCount { get; set; }
}

public class TransactionDetail
{
[JsonProperty("id")]
public Guid Id { get; set; }
[JsonProperty("date_time")]
public DateTime DateTime { get; set; }
[JsonProperty("merchant")]
public String Merchant { get; set; }
[JsonProperty("merchant_id")]
public Guid MerchantId { get; set; }
[JsonProperty("merchant_reporting_id")]
public Int32 MerchantReportingId { get; set; }
[JsonProperty("operator")]
public String Operator { get; set; }
[JsonProperty("operator_id")]
public Guid OperatorId { get; set; }
[JsonProperty("operator_reporting_id")]
public Int32 OperatorReportingId { get; set; }
[JsonProperty("product")]
public String Product { get; set; }
[JsonProperty("product_id")]
public Guid ProductId { get; set; }
[JsonProperty("product_reporting_id")]
public Int32 ProductReportingId { get; set; }
[JsonProperty("type")]
public String Type { get; set; }
[JsonProperty("status")]
public String Status { get; set; }
[JsonProperty("value")]
public Decimal Value { get; set; }
[JsonProperty("total_fees")]
public Decimal TotalFees { get; set; }
[JsonProperty("settlement_reference")]
public String SettlementReference { get; set; }
}

}
Loading
Loading