diff --git a/TransactionProcessing.MerchantPos/Runtime/ApiClient.cs b/TransactionProcessing.MerchantPos/Runtime/ApiClient.cs index b113f95..01ad9ef 100644 --- a/TransactionProcessing.MerchantPos/Runtime/ApiClient.cs +++ b/TransactionProcessing.MerchantPos/Runtime/ApiClient.cs @@ -1,11 +1,13 @@ -using System.Net.Http.Headers; -using System.Text; using MerchantPos.EF.Models; using Newtonsoft.Json; +using Newtonsoft.Json.Linq; using SecurityService.Client; using SecurityService.DataTransferObjects.Responses; using Shared.Logger; using SimpleResults; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http.Headers; +using System.Text; using TransactionProcessor.Client; using TransactionProcessor.DataTransferObjects; using TransactionProcessor.DataTransferObjects.Requests.Merchant; @@ -18,6 +20,9 @@ namespace TransactionProcessing.MerchantPos.Runtime; public interface IApiClient { Task> GetToken(String clientId, String clientSecret, MerchantConfig cfg, CancellationToken cancellationToken); + + Task> GetMerchant(MerchantConfig cfg, TokenResponse token, CancellationToken cancellationToken); + Task SendLogon(MerchantConfig cfg, TokenResponse token, Int32 transactionNumber, CancellationToken cancellationToken); Task> GetProductList(MerchantConfig cfg, TokenResponse token, CancellationToken cancellationToken); @@ -49,6 +54,40 @@ public async Task> GetToken(String clientId, return await this.SecurityClient.GetToken(cfg.Username, cfg.Password, clientId, clientSecret, cancellationToken); } + public async Task> GetMerchant(MerchantConfig cfg, + TokenResponse token, + CancellationToken cancellationToken) { + + Guid estateId = cfg.EstateId; + Guid merchantId = cfg.MerchantId; + + String requestUri = this.BuildRequestUrl($"api/merchants?applicationVersion={cfg.ApplicationVersion}"); + + Logger.LogInformation("About to request merchant details"); + Logger.LogDebug($"Merchant Request details: Estate Id {estateId} Merchant Id {merchantId} Access Token {token.AccessToken}"); + + HttpRequestMessage request = new(HttpMethod.Get, requestUri); + request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token.AccessToken); + var httpResponse = await this.HttpClient.SendAsync(request, cancellationToken); + + // Process the response + Result content = await this.HandleResponseX(httpResponse, cancellationToken); + + if (content.IsFailed) + { + Logger.LogInformation($"GetMerchant failed {content.Status}"); + } + + Logger.LogDebug($"Merchant Response details: Status {httpResponse.StatusCode} Payload {content.Data}"); + //MerchantResponse + + MerchantResponse responseData = JsonConvert.DeserializeObject(content.Data); + + Logger.LogDebug($"Merchant Response: [{JsonConvert.SerializeObject(responseData)}]"); + + return responseData; + } + public async Task SendLogon(MerchantConfig cfg, TokenResponse token, Int32 transactionNumber, @@ -92,7 +131,7 @@ public async Task> GetProductList(MerchantConfig cfg, Logger.LogInformation($"GetMerchantContracts failed {content.Status}"); } - Logger.LogDebug($"Transaction Response details: Status {httpResponse.StatusCode} Payload {content.Data}"); + Logger.LogDebug($"Merchant Contract Response details: Status {httpResponse.StatusCode} Payload {content.Data}"); List? responseData = JsonConvert.DeserializeObject>(content.Data); @@ -499,4 +538,29 @@ public enum ProductSubType BillPaymentPostPay, BillPaymentPrePay, Voucher -} \ No newline at end of file +} + +[ExcludeFromCodeCoverage] +public class MerchantResponse +{ + [JsonProperty("estate_id")] + public Guid EstateId { get; set; } + + [JsonProperty("merchant_id")] + public Guid MerchantId { get; set; } + + [JsonProperty("merchant_name")] + public string MerchantName { get; set; } + + [JsonProperty("opening_hours")] + public Dictionary OpeningHours { get; set; } +} + +public class OpeningHoursResponse +{ + [JsonProperty("opening")] + public string Opening { get; set; } + + [JsonProperty("closing")] + public string Closing { get; set; } +} diff --git a/TransactionProcessing.MerchantPos/Runtime/MerchantConfig.cs b/TransactionProcessing.MerchantPos/Runtime/MerchantConfig.cs index f889ae0..677bb73 100644 --- a/TransactionProcessing.MerchantPos/Runtime/MerchantConfig.cs +++ b/TransactionProcessing.MerchantPos/Runtime/MerchantConfig.cs @@ -21,4 +21,5 @@ public class MerchantConfig public TimeOnly OpeningTime { get; set; } = new(8, 0); public List Products { get; set; } public Boolean RequiresEndOfDay { get; set; } = true; + public MerchantResponse Merchant { get; set; } } \ No newline at end of file diff --git a/TransactionProcessing.MerchantPos/Runtime/MerchantRuntime.cs b/TransactionProcessing.MerchantPos/Runtime/MerchantRuntime.cs index 85ade89..24bffbe 100644 --- a/TransactionProcessing.MerchantPos/Runtime/MerchantRuntime.cs +++ b/TransactionProcessing.MerchantPos/Runtime/MerchantRuntime.cs @@ -140,6 +140,10 @@ private async Task StartupSequence(MerchantConfig cfg, // 3. Balance decimal balance = await ApiClient.GetBalance(cfg, this.CurrentServiceToken, cancellationToken); await Repository.UpdateBalance(cfg.MerchantId,cfg.MerchantName, balance); + + // 4. get the merchant record + var merchant = await ApiClient.GetMerchant(cfg, this.CurrentUserToken, cancellationToken); + cfg.Merchant = merchant.Data; } private async Task RunMainLoop(MerchantConfig cfg, @@ -150,8 +154,22 @@ private async Task RunMainLoop(MerchantConfig cfg, Merchant merchant = await this.Repository.GetMerchant(cfg.MerchantId); // Wait until the merchant's configured opening time DateTime currentTime = DateTime.Now; - TimeSpan openingTime = cfg.OpeningTime.ToTimeSpan(); - TimeSpan closingTime = cfg.ClosingTime.ToTimeSpan(); + + // Get the current days opening and closing time + TimeSpan openingTime; + TimeSpan closingTime; + Boolean found = cfg.Merchant.OpeningHours.TryGetValue(DateTime.Now.DayOfWeek, out var openingHours); + if (found == false) { + // fallback to the configured default opening and closing time if no specific hours for the day of week + openingTime = cfg.OpeningTime.ToTimeSpan(); + closingTime = cfg.ClosingTime.ToTimeSpan(); + } + else { + // We have opening and closing times for the current day of week, so use those + openingTime = TimeSpan.ParseExact(openingHours.Opening, "hhmm", null); + closingTime = TimeSpan.ParseExact(openingHours.Closing, "hhmm", null); + } + if (currentTime.TimeOfDay < openingTime) { TimeSpan delay = openingTime - currentTime.TimeOfDay; Logger.LogInformation($"Merchant {cfg.MerchantName} sleeping until opening time {cfg.OpeningTime}");