From 20f8d165691888118c9e8ebbb3346d9106dbd971 Mon Sep 17 00:00:00 2001 From: Stuart Ferguson Date: Tue, 23 Dec 2025 11:43:19 +0000 Subject: [PATCH 1/2] refactor signature of GetUnsettledFees --- .../xunit.runner.json | 2 +- .../Handlers/FactSettlementsHandlers.cs | 74 ++++++++++++++++--- 2 files changed, 63 insertions(+), 13 deletions(-) diff --git a/EstateReportingAPI.IntegrationTests/xunit.runner.json b/EstateReportingAPI.IntegrationTests/xunit.runner.json index cf20db1..29ceb58 100644 --- a/EstateReportingAPI.IntegrationTests/xunit.runner.json +++ b/EstateReportingAPI.IntegrationTests/xunit.runner.json @@ -1,4 +1,4 @@ { - "maxParallelThreads": 1, + "maxParallelThreads": 3, "parallelizeTestCollections": true } \ No newline at end of file diff --git a/EstateReportingAPI/Handlers/FactSettlementsHandlers.cs b/EstateReportingAPI/Handlers/FactSettlementsHandlers.cs index 00f5f02..b97c8bd 100644 --- a/EstateReportingAPI/Handlers/FactSettlementsHandlers.cs +++ b/EstateReportingAPI/Handlers/FactSettlementsHandlers.cs @@ -8,6 +8,61 @@ namespace EstateReportingAPI.Handlers; public static class FactSettlementsHandlers { + + public class GetUnsettledFeesRequest + { + public DateTime StartDate { get; set; } + public DateTime EndDate { get; set; } + public string? MerchantIds { get; set; } + public string? OperatorIds { get; set; } + public string? ProductIds { get; set; } + public GroupByOption? GroupByOption { get; set; } + + // Minimal API binder: called by RequestDelegateFactory when binding complex parameter + public static ValueTask BindAsync(HttpContext context) + { + var q = context.Request.Query; + var req = new GetUnsettledFeesRequest(); + + if (q.TryGetValue("startDate", out var s) || q.TryGetValue(nameof(StartDate), out s)) + { + DateTime.TryParse(s, out var d); + req.StartDate = d; + } + + if (q.TryGetValue("endDate", out var e) || q.TryGetValue(nameof(EndDate), out e)) + { + DateTime.TryParse(e, out var d); + req.EndDate = d; + } + + if (q.TryGetValue("merchantIds", out var m) || q.TryGetValue(nameof(MerchantIds), out m)) + { + req.MerchantIds = m.ToString(); + } + + if (q.TryGetValue("operatorIds", out var o) || q.TryGetValue(nameof(OperatorIds), out o)) + { + req.OperatorIds = o.ToString(); + } + + if (q.TryGetValue("productIds", out var p) || q.TryGetValue(nameof(ProductIds), out p)) + { + req.ProductIds = p.ToString(); + } + + if (q.TryGetValue("groupByOption", out var g) || q.TryGetValue(nameof(GroupByOption), out g)) + { + if (Enum.TryParse(g.ToString(), true, out var gv)) + { + req.GroupByOption = gv; + } + } + + return ValueTask.FromResult(req); + } + } + public static async Task TodaysSettlement([FromHeader] Guid estateId, [FromQuery] int? merchantReportingId, [FromQuery] int? operatorReportingId, @@ -50,25 +105,20 @@ public static async Task LastSettlement([FromHeader] Guid estateId, } public static async Task GetUnsettledFees([FromHeader] Guid estateId, - [FromQuery] DateTime startDate, - [FromQuery] DateTime endDate, - [FromQuery] string? merchantIds, - [FromQuery] string? operatorIds, - [FromQuery] string? productIds, - [FromQuery] GroupByOption? groupByOption, + GetUnsettledFeesRequest request, IMediator mediator, CancellationToken cancellationToken) { - var merchantIdFilter = ParseIds(merchantIds); - var operatorIdFilter = ParseIds(operatorIds); - var productIdFilter = ParseIds(productIds); + var merchantIdFilter = ParseIds(request.MerchantIds); + var operatorIdFilter = ParseIds(request.OperatorIds); + var productIdFilter = ParseIds(request.ProductIds); - var groupByOptionConverted = ConvertGroupByOption(groupByOption.GetValueOrDefault()); + var groupByOptionConverted = ConvertGroupByOption(request.GroupByOption.GetValueOrDefault()); var query = new SettlementQueries.GetUnsettledFeesQuery( estateId, - startDate, - endDate, + request.StartDate, + request.EndDate, merchantIdFilter, operatorIdFilter, productIdFilter, From d1ebe283b6cd6c52174d7c96eda850083dc2ca53 Mon Sep 17 00:00:00 2001 From: Stuart Ferguson Date: Tue, 23 Dec 2025 11:58:47 +0000 Subject: [PATCH 2/2] reduce complexity of BindAsync --- .../Handlers/FactSettlementsHandlers.cs | 60 ++++++++++++------- 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/EstateReportingAPI/Handlers/FactSettlementsHandlers.cs b/EstateReportingAPI/Handlers/FactSettlementsHandlers.cs index b97c8bd..d15311e 100644 --- a/EstateReportingAPI/Handlers/FactSettlementsHandlers.cs +++ b/EstateReportingAPI/Handlers/FactSettlementsHandlers.cs @@ -22,44 +22,58 @@ public class GetUnsettledFeesRequest public static ValueTask BindAsync(HttpContext context) { var q = context.Request.Query; - var req = new GetUnsettledFeesRequest(); + var req = new GetUnsettledFeesRequest(){ + StartDate = ParseDate(q, "startDate", nameof(StartDate)), + EndDate = ParseDate(q, "endDate", nameof(EndDate)), + MerchantIds = GetStringValue(q, "merchantIds", nameof(MerchantIds)), + OperatorIds = GetStringValue(q, "operatorIds", nameof(OperatorIds)), + ProductIds = GetStringValue(q, "productIds", nameof(ProductIds)), + GroupByOption = ParseEnum(q, "groupByOption", nameof(GroupByOption)) + }; - if (q.TryGetValue("startDate", out var s) || q.TryGetValue(nameof(StartDate), out s)) - { - DateTime.TryParse(s, out var d); - req.StartDate = d; - } + return ValueTask.FromResult(req); + } - if (q.TryGetValue("endDate", out var e) || q.TryGetValue(nameof(EndDate), out e)) + // Extracted helpers to reduce cyclomatic complexity in BindAsync + private static DateTime ParseDate(IQueryCollection q, params string[] keys) + { + foreach (var key in keys) { - DateTime.TryParse(e, out var d); - req.EndDate = d; + if (q.TryGetValue(key, out var values) && DateTime.TryParse(values.ToString(), out var dt)) + { + return dt; + } } - if (q.TryGetValue("merchantIds", out var m) || q.TryGetValue(nameof(MerchantIds), out m)) - { - req.MerchantIds = m.ToString(); - } + return default; + } - if (q.TryGetValue("operatorIds", out var o) || q.TryGetValue(nameof(OperatorIds), out o)) + private static string? GetStringValue(IQueryCollection q, params string[] keys) + { + foreach (var key in keys) { - req.OperatorIds = o.ToString(); + if (q.TryGetValue(key, out var values)) + { + var s = values.ToString(); + if (!string.IsNullOrWhiteSpace(s)) + return s; + } } - if (q.TryGetValue("productIds", out var p) || q.TryGetValue(nameof(ProductIds), out p)) - { - req.ProductIds = p.ToString(); - } + return null; + } - if (q.TryGetValue("groupByOption", out var g) || q.TryGetValue(nameof(GroupByOption), out g)) + private static TEnum? ParseEnum(IQueryCollection q, params string[] keys) where TEnum : struct, Enum + { + foreach (var key in keys) { - if (Enum.TryParse(g.ToString(), true, out var gv)) + if (q.TryGetValue(key, out var values) && Enum.TryParse(values.ToString(), true, out var parsed)) { - req.GroupByOption = gv; + return parsed; } } - return ValueTask.FromResult(req); + return null; } }