From ab414f3475f7b6cfe96b920035f2c22c77f45833 Mon Sep 17 00:00:00 2001 From: Stuart Ferguson Date: Wed, 15 Nov 2023 17:04:48 +0000 Subject: [PATCH] Added operator perfomance api --- .../IReportingManager.cs | 2 + .../ReportingManager.cs | 35 ++++ .../EstateReportingApiClient.cs | 34 ++++ .../IEstateReportingApiClient.cs | 2 + .../FactTransactionsControllerTests.cs | 149 ++++++++++++++++++ .../Controllers/FactTransactionsController.cs | 27 ++++ 6 files changed, 249 insertions(+) diff --git a/EstateReportingAPI.BusinessLogic/IReportingManager.cs b/EstateReportingAPI.BusinessLogic/IReportingManager.cs index c2c1f94..1915a75 100644 --- a/EstateReportingAPI.BusinessLogic/IReportingManager.cs +++ b/EstateReportingAPI.BusinessLogic/IReportingManager.cs @@ -23,5 +23,7 @@ public interface IReportingManager{ Task GetMerchantPerformance(Guid estateId, DateTime comparisonDate, List merchantIds,CancellationToken cancellationToken); Task GetProductPerformance(Guid estateId, DateTime comparisonDate, List productIds, CancellationToken cancellationToken); + Task GetOperatorPerformance(Guid estateId, DateTime comparisonDate, List operatorIds, CancellationToken cancellationToken); + #endregion } \ No newline at end of file diff --git a/EstateReportingAPI.BusinessLogic/ReportingManager.cs b/EstateReportingAPI.BusinessLogic/ReportingManager.cs index d2671d5..7a7928f 100644 --- a/EstateReportingAPI.BusinessLogic/ReportingManager.cs +++ b/EstateReportingAPI.BusinessLogic/ReportingManager.cs @@ -489,6 +489,41 @@ public async Task GetProductPerformance(Guid estateId, DateTime com return response; } + public async Task GetOperatorPerformance(Guid estateId, DateTime comparisonDate, List operatorIds, CancellationToken cancellationToken){ + EstateManagementGenericContext? context = await this.ContextFactory.GetContext(estateId, ReportingManager.ConnectionStringIdentifier, cancellationToken); + + // First we need to get a value of todays sales + var todaysSalesQuery = (from t in context.Transactions + where t.IsAuthorised && t.TransactionType == "Sale" + && t.TransactionDate == DateTime.Now.Date + && t.TransactionTime <= DateTime.Now.TimeOfDay + select t); + + var comparisonSalesQuery = (from t in context.Transactions + where t.IsAuthorised && t.TransactionType == "Sale" + && t.TransactionDate == comparisonDate + && t.TransactionTime <= DateTime.Now.TimeOfDay + select t); + + + if (operatorIds.Any()) + { + todaysSalesQuery = todaysSalesQuery.Where(t => operatorIds.Contains(t.OperatorIdentifier)); + comparisonSalesQuery = comparisonSalesQuery.Where(t => operatorIds.Contains(t.OperatorIdentifier)); + } + + TodaysSales response = new TodaysSales + { + ComparisonSalesCount = comparisonSalesQuery.Count(), + ComparisonSalesValue = comparisonSalesQuery.Sum(t => t.TransactionAmount), + ComparisonAverageSalesValue = comparisonSalesQuery.Sum(t => t.TransactionAmount) / comparisonSalesQuery.Count(), + TodaysSalesCount = todaysSalesQuery.Count(), + TodaysSalesValue = todaysSalesQuery.Sum(t => t.TransactionAmount), + TodaysAverageSalesValue = todaysSalesQuery.Sum(t => t.TransactionAmount) / todaysSalesQuery.Count() + }; + return response; + } + public async Task> GetMerchants(Guid estateId, CancellationToken cancellationToken){ EstateManagementGenericContext? context = await this.ContextFactory.GetContext(estateId, ReportingManager.ConnectionStringIdentifier, cancellationToken); diff --git a/EstateReportingAPI.Client/EstateReportingApiClient.cs b/EstateReportingAPI.Client/EstateReportingApiClient.cs index c875514..1c02cb2 100644 --- a/EstateReportingAPI.Client/EstateReportingApiClient.cs +++ b/EstateReportingAPI.Client/EstateReportingApiClient.cs @@ -247,6 +247,40 @@ public async Task GetProductPerformance(String accessToken, Guid es return response; } + public async Task GetOperatorPerformance(String accessToken, Guid estateId, DateTime comparisonDate, List operatorIds, CancellationToken cancellationToken){ + // Serialize the integer array into a comma-separated string + string serializedArray = string.Join(",", operatorIds); + + TodaysSales response = null; + + String requestUri = this.BuildRequestUrl($"/api/facts/transactions/operators/performance?comparisonDate={comparisonDate.Date:yyyy-MM-dd}&operatorIds={serializedArray}"); + + try + { + HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, requestUri); + request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); + request.Headers.Add("EstateId", estateId.ToString()); + + // Make the Http Call here + HttpResponseMessage httpResponse = await this.HttpClient.SendAsync(request, cancellationToken); + + // Process the response + String content = await this.HandleResponse(httpResponse, cancellationToken); + + // call was successful so now deserialise the body to the response object + response = JsonConvert.DeserializeObject(content); + } + catch (Exception ex) + { + // An exception has occurred, add some additional information to the message + Exception exception = new Exception($"Error getting operator performance for estate {estateId}.", ex); + + throw exception; + } + + return response; + } + public async Task GetMerchantKpi(String accessToken, Guid estateId, CancellationToken cancellationToken){ MerchantKpi response = null; diff --git a/EstateReportingAPI.Client/IEstateReportingApiClient.cs b/EstateReportingAPI.Client/IEstateReportingApiClient.cs index 7f91182..f1a1370 100644 --- a/EstateReportingAPI.Client/IEstateReportingApiClient.cs +++ b/EstateReportingAPI.Client/IEstateReportingApiClient.cs @@ -31,6 +31,8 @@ public interface IEstateReportingApiClient{ Task GetMerchantPerformance(String accessToken, Guid estateId, DateTime comparisonDate, List merchantIds,CancellationToken cancellationToken); Task GetProductPerformance(String accessToken, Guid estateId, DateTime comparisonDate, List productIds, CancellationToken cancellationToken); + + Task GetOperatorPerformance(String accessToken, Guid estateId, DateTime comparisonDate, List operatorIds, CancellationToken cancellationToken); #endregion } } \ No newline at end of file diff --git a/EstateReportingAPI.IntegrationTests/FactTransactionsControllerTests.cs b/EstateReportingAPI.IntegrationTests/FactTransactionsControllerTests.cs index f601d0f..6d1c2e8 100644 --- a/EstateReportingAPI.IntegrationTests/FactTransactionsControllerTests.cs +++ b/EstateReportingAPI.IntegrationTests/FactTransactionsControllerTests.cs @@ -886,5 +886,154 @@ public async Task FactTransactionsControllerController_ProductPerformance_Multip todaysSales.ComparisonSalesValue.ShouldBe(comparisonDateTransactions.Where(c => productFilterList.Contains(c.ContractProductReportingId)).Sum(c => c.TransactionAmount)); } + [Fact] + public async Task FactTransactionsControllerController_OperatorPerformance_AllOperators_SalesReturned() + { + EstateManagementGenericContext context = new EstateManagementSqlServerContext(ControllerTestsBase.GetLocalConnectionString($"EstateReportingReadModel{this.TestId.ToString()}")); + var todaysTransactions = new List(); + var comparisonDateTransactions = new List(); + DatabaseHelper helper = new DatabaseHelper(context); + // TODO: make counts dynamic + DateTime todaysDateTime = DateTime.Now; + DateTime comparisonDate = DateTime.Now.AddDays(-1).AddHours(-1); + + List operatorIds = new List{ + "Operator1", + "Operator2", + "Operator3" + }; + + foreach (String operatorId in operatorIds) + { + + for (int i = 0; i < 25; i++) + { + Decimal amount = 100 + i; + Transaction transaction = await helper.AddTransaction(todaysDateTime.AddHours(-1), 1, operatorId,1, "0000", amount); + todaysTransactions.Add(transaction); + } + + for (int i = 0; i < 21; i++) + { + Decimal amount = 100 + i; + Transaction transaction = await helper.AddTransaction(comparisonDate, 1, operatorId, 1, "0000", amount); + comparisonDateTransactions.Add(transaction); + } + } + + HttpResponseMessage response = await this.CreateAndSendHttpRequestMessage($"api/facts/transactions/operators/performance?comparisonDate={comparisonDate.ToString("yyyy-MM-dd")}"); + + response.IsSuccessStatusCode.ShouldBeTrue(); + String content = await response.Content.ReadAsStringAsync(CancellationToken.None); + TodaysSales? todaysSales = JsonConvert.DeserializeObject(content); + todaysSales.ComparisonSalesCount.ShouldBe(comparisonDateTransactions.Count); + todaysSales.ComparisonSalesValue.ShouldBe(comparisonDateTransactions.Sum(c => c.TransactionAmount)); + + todaysSales.TodaysSalesCount.ShouldBe(todaysTransactions.Count); + todaysSales.ComparisonSalesValue.ShouldBe(comparisonDateTransactions.Sum(c => c.TransactionAmount)); + } + + [Fact] + public async Task FactTransactionsControllerController_OperatorPerformance_SingleOperator_SalesReturned() + { + EstateManagementGenericContext context = new EstateManagementSqlServerContext(ControllerTestsBase.GetLocalConnectionString($"EstateReportingReadModel{this.TestId.ToString()}")); + var todaysTransactions = new List(); + var comparisonDateTransactions = new List(); + DatabaseHelper helper = new DatabaseHelper(context); + // TODO: make counts dynamic + DateTime todaysDateTime = DateTime.Now; + DateTime comparisonDate = DateTime.Now.AddDays(-1).AddHours(-1); + + List operatorIds = new List{ + "Operator1", + "Operator2", + "Operator3" + }; + + foreach (String operatorId in operatorIds) + { + + for (int i = 0; i < 25; i++) + { + Decimal amount = 100 + i; + Transaction transaction = await helper.AddTransaction(todaysDateTime.AddHours(-1), 1, operatorId, 1, "0000", amount); + todaysTransactions.Add(transaction); + } + + for (int i = 0; i < 21; i++) + { + Decimal amount = 100 + i; + Transaction transaction = await helper.AddTransaction(comparisonDate, 1, operatorId, 1, "0000", amount); + comparisonDateTransactions.Add(transaction); + } + } + List operatorFilterList = new List{ + "Operator2" + }; + string serializedArray = string.Join(",", operatorFilterList); + + HttpResponseMessage response = await this.CreateAndSendHttpRequestMessage($"api/facts/transactions/operators/performance?comparisonDate={comparisonDate.ToString("yyyy-MM-dd")}&operatorIds={serializedArray}"); + + response.IsSuccessStatusCode.ShouldBeTrue(); + String content = await response.Content.ReadAsStringAsync(CancellationToken.None); + TodaysSales? todaysSales = JsonConvert.DeserializeObject(content); + todaysSales.ComparisonSalesCount.ShouldBe(comparisonDateTransactions.Count(c => operatorFilterList.Contains(c.OperatorIdentifier))); + todaysSales.ComparisonSalesValue.ShouldBe(comparisonDateTransactions.Where(c => operatorFilterList.Contains(c.OperatorIdentifier)).Sum(c => c.TransactionAmount)); + + todaysSales.TodaysSalesCount.ShouldBe(todaysTransactions.Count(c => operatorFilterList.Contains(c.OperatorIdentifier))); + todaysSales.ComparisonSalesValue.ShouldBe(comparisonDateTransactions.Where(c => operatorFilterList.Contains(c.OperatorIdentifier)).Sum(c => c.TransactionAmount)); + } + + [Fact] + public async Task FactTransactionsControllerController_OperatorPerformance_MultipleOperators_SalesReturned() + { + EstateManagementGenericContext context = new EstateManagementSqlServerContext(ControllerTestsBase.GetLocalConnectionString($"EstateReportingReadModel{this.TestId.ToString()}")); + var todaysTransactions = new List(); + var comparisonDateTransactions = new List(); + DatabaseHelper helper = new DatabaseHelper(context); + // TODO: make counts dynamic + DateTime todaysDateTime = DateTime.Now; + DateTime comparisonDate = DateTime.Now.AddDays(-1).AddHours(-1); + + List operatorIds = new List{ + "Operator1", + "Operator2", + "Operator3" + }; + + foreach (String operatorId in operatorIds) + { + + for (int i = 0; i < 25; i++) + { + Decimal amount = 100 + i; + Transaction transaction = await helper.AddTransaction(todaysDateTime.AddHours(-1), 1, operatorId, 1, "0000", amount); + todaysTransactions.Add(transaction); + } + + for (int i = 0; i < 21; i++) + { + Decimal amount = 100 + i; + Transaction transaction = await helper.AddTransaction(comparisonDate, 1, operatorId, 1, "0000", amount); + comparisonDateTransactions.Add(transaction); + } + } + List operatorFilterList = new List{ + "Operator2", + "Operator3" + }; + string serializedArray = string.Join(",", operatorFilterList); + + HttpResponseMessage response = await this.CreateAndSendHttpRequestMessage($"api/facts/transactions/operators/performance?comparisonDate={comparisonDate.ToString("yyyy-MM-dd")}&operatorIds={serializedArray}"); + + response.IsSuccessStatusCode.ShouldBeTrue(); + String content = await response.Content.ReadAsStringAsync(CancellationToken.None); + TodaysSales? todaysSales = JsonConvert.DeserializeObject(content); + todaysSales.ComparisonSalesCount.ShouldBe(comparisonDateTransactions.Count(c => operatorFilterList.Contains(c.OperatorIdentifier))); + todaysSales.ComparisonSalesValue.ShouldBe(comparisonDateTransactions.Where(c => operatorFilterList.Contains(c.OperatorIdentifier)).Sum(c => c.TransactionAmount)); + + todaysSales.TodaysSalesCount.ShouldBe(todaysTransactions.Count(c => operatorFilterList.Contains(c.OperatorIdentifier))); + todaysSales.ComparisonSalesValue.ShouldBe(comparisonDateTransactions.Where(c => operatorFilterList.Contains(c.OperatorIdentifier)).Sum(c => c.TransactionAmount)); + } } diff --git a/EstateReportingAPI/Controllers/FactTransactionsController.cs b/EstateReportingAPI/Controllers/FactTransactionsController.cs index 4d1e9c3..11d9476 100644 --- a/EstateReportingAPI/Controllers/FactTransactionsController.cs +++ b/EstateReportingAPI/Controllers/FactTransactionsController.cs @@ -229,6 +229,33 @@ public async Task GetProductPerformance([FromHeader] Guid estateI return this.Ok(response); } + + [HttpGet] + [Route("operators/performance")] + public async Task GetOperatorPerformance([FromHeader] Guid estateId, [FromQuery] DateTime comparisonDate, [FromQuery] string? operatorIds, CancellationToken cancellationToken) + { + + List operatorIdFilter = new List(); + if (String.IsNullOrEmpty(operatorIds) == false) + { + operatorIdFilter = operatorIds.Split(',').ToList(); + + } + + Models.TodaysSales model = await this.ReportingManager.GetOperatorPerformance(estateId, comparisonDate, operatorIdFilter, cancellationToken); + + TodaysSales response = new TodaysSales + { + ComparisonSalesCount = model.ComparisonSalesCount, + ComparisonSalesValue = model.ComparisonSalesValue, + TodaysSalesCount = model.TodaysSalesCount, + TodaysSalesValue = model.TodaysSalesValue, + ComparisonAverageSalesValue = model.ComparisonAverageSalesValue, + TodaysAverageSalesValue = model.TodaysAverageSalesValue, + }; + + return this.Ok(response); + } }