Skip to content

Commit 0b5bf15

Browse files
Add merchant details API integration and opening hours logic
Integrated a new API call to fetch merchant details and opening hours. - Added GetMerchant to IApiClient and implemented in ApiClient. - Introduced MerchantResponse and OpeningHoursResponse models. - Updated MerchantConfig to store MerchantResponse. - MerchantRuntime now fetches and stores merchant details during initialization. - Main loop now uses per-day opening hours if available, falling back to defaults otherwise. - Improved logging for merchant contract responses. - Cleaned up and added necessary using statements.
1 parent 32f4fce commit 0b5bf15

3 files changed

Lines changed: 89 additions & 6 deletions

File tree

TransactionProcessing.MerchantPos/Runtime/ApiClient.cs

Lines changed: 68 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
using System.Net.Http.Headers;
2-
using System.Text;
31
using MerchantPos.EF.Models;
42
using Newtonsoft.Json;
3+
using Newtonsoft.Json.Linq;
54
using SecurityService.Client;
65
using SecurityService.DataTransferObjects.Responses;
76
using Shared.Logger;
87
using SimpleResults;
8+
using System.Diagnostics.CodeAnalysis;
9+
using System.Net.Http.Headers;
10+
using System.Text;
911
using TransactionProcessor.Client;
1012
using TransactionProcessor.DataTransferObjects;
1113
using TransactionProcessor.DataTransferObjects.Requests.Merchant;
@@ -18,6 +20,9 @@ namespace TransactionProcessing.MerchantPos.Runtime;
1820
public interface IApiClient
1921
{
2022
Task<Result<TokenResponse>> GetToken(String clientId, String clientSecret, MerchantConfig cfg, CancellationToken cancellationToken);
23+
24+
Task<Result<MerchantResponse>> GetMerchant(MerchantConfig cfg, TokenResponse token, CancellationToken cancellationToken);
25+
2126
Task SendLogon(MerchantConfig cfg, TokenResponse token,
2227
Int32 transactionNumber, CancellationToken cancellationToken);
2328
Task<List<Product>> GetProductList(MerchantConfig cfg, TokenResponse token, CancellationToken cancellationToken);
@@ -49,6 +54,40 @@ public async Task<Result<TokenResponse>> GetToken(String clientId,
4954
return await this.SecurityClient.GetToken(cfg.Username, cfg.Password, clientId, clientSecret, cancellationToken);
5055
}
5156

57+
public async Task<Result<MerchantResponse>> GetMerchant(MerchantConfig cfg,
58+
TokenResponse token,
59+
CancellationToken cancellationToken) {
60+
61+
Guid estateId = cfg.EstateId;
62+
Guid merchantId = cfg.MerchantId;
63+
64+
String requestUri = this.BuildRequestUrl($"api/merchants?applicationVersion={cfg.ApplicationVersion}");
65+
66+
Logger.LogInformation("About to request merchant details");
67+
Logger.LogDebug($"Merchant Request details: Estate Id {estateId} Merchant Id {merchantId} Access Token {token.AccessToken}");
68+
69+
HttpRequestMessage request = new(HttpMethod.Get, requestUri);
70+
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token.AccessToken);
71+
var httpResponse = await this.HttpClient.SendAsync(request, cancellationToken);
72+
73+
// Process the response
74+
Result<String> content = await this.HandleResponseX(httpResponse, cancellationToken);
75+
76+
if (content.IsFailed)
77+
{
78+
Logger.LogInformation($"GetMerchant failed {content.Status}");
79+
}
80+
81+
Logger.LogDebug($"Merchant Response details: Status {httpResponse.StatusCode} Payload {content.Data}");
82+
//MerchantResponse
83+
84+
MerchantResponse responseData = JsonConvert.DeserializeObject<MerchantResponse>(content.Data);
85+
86+
Logger.LogDebug($"Merchant Response: [{JsonConvert.SerializeObject(responseData)}]");
87+
88+
return responseData;
89+
}
90+
5291
public async Task SendLogon(MerchantConfig cfg,
5392
TokenResponse token,
5493
Int32 transactionNumber,
@@ -92,7 +131,7 @@ public async Task<List<Product>> GetProductList(MerchantConfig cfg,
92131
Logger.LogInformation($"GetMerchantContracts failed {content.Status}");
93132
}
94133

95-
Logger.LogDebug($"Transaction Response details: Status {httpResponse.StatusCode} Payload {content.Data}");
134+
Logger.LogDebug($"Merchant Contract Response details: Status {httpResponse.StatusCode} Payload {content.Data}");
96135

97136
List<ContractResponseX>? responseData = JsonConvert.DeserializeObject<List<ContractResponseX>>(content.Data);
98137

@@ -499,4 +538,29 @@ public enum ProductSubType
499538
BillPaymentPostPay,
500539
BillPaymentPrePay,
501540
Voucher
502-
}
541+
}
542+
543+
[ExcludeFromCodeCoverage]
544+
public class MerchantResponse
545+
{
546+
[JsonProperty("estate_id")]
547+
public Guid EstateId { get; set; }
548+
549+
[JsonProperty("merchant_id")]
550+
public Guid MerchantId { get; set; }
551+
552+
[JsonProperty("merchant_name")]
553+
public string MerchantName { get; set; }
554+
555+
[JsonProperty("opening_hours")]
556+
public Dictionary<DayOfWeek, OpeningHoursResponse> OpeningHours { get; set; }
557+
}
558+
559+
public class OpeningHoursResponse
560+
{
561+
[JsonProperty("opening")]
562+
public string Opening { get; set; }
563+
564+
[JsonProperty("closing")]
565+
public string Closing { get; set; }
566+
}

TransactionProcessing.MerchantPos/Runtime/MerchantConfig.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,5 @@ public class MerchantConfig
2121
public TimeOnly OpeningTime { get; set; } = new(8, 0);
2222
public List<Product> Products { get; set; }
2323
public Boolean RequiresEndOfDay { get; set; } = true;
24+
public MerchantResponse Merchant { get; set; }
2425
}

TransactionProcessing.MerchantPos/Runtime/MerchantRuntime.cs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,10 @@ private async Task StartupSequence(MerchantConfig cfg,
140140
// 3. Balance
141141
decimal balance = await ApiClient.GetBalance(cfg, this.CurrentServiceToken, cancellationToken);
142142
await Repository.UpdateBalance(cfg.MerchantId,cfg.MerchantName, balance);
143+
144+
// 4. get the merchant record
145+
var merchant = await ApiClient.GetMerchant(cfg, this.CurrentUserToken, cancellationToken);
146+
cfg.Merchant = merchant.Data;
143147
}
144148

145149
private async Task RunMainLoop(MerchantConfig cfg,
@@ -150,8 +154,22 @@ private async Task RunMainLoop(MerchantConfig cfg,
150154
Merchant merchant = await this.Repository.GetMerchant(cfg.MerchantId);
151155
// Wait until the merchant's configured opening time
152156
DateTime currentTime = DateTime.Now;
153-
TimeSpan openingTime = cfg.OpeningTime.ToTimeSpan();
154-
TimeSpan closingTime = cfg.ClosingTime.ToTimeSpan();
157+
158+
// Get the current days opening and closing time
159+
TimeSpan openingTime;
160+
TimeSpan closingTime;
161+
Boolean found = cfg.Merchant.OpeningHours.TryGetValue(DateTime.Now.DayOfWeek, out var openingHours);
162+
if (found == false) {
163+
// fallback to the configured default opening and closing time if no specific hours for the day of week
164+
openingTime = cfg.OpeningTime.ToTimeSpan();
165+
closingTime = cfg.ClosingTime.ToTimeSpan();
166+
}
167+
else {
168+
// We have opening and closing times for the current day of week, so use those
169+
openingTime = TimeSpan.ParseExact(openingHours.Opening, "hhmm", null);
170+
closingTime = TimeSpan.ParseExact(openingHours.Closing, "hhmm", null);
171+
}
172+
155173
if (currentTime.TimeOfDay < openingTime) {
156174
TimeSpan delay = openingTime - currentTime.TimeOfDay;
157175
Logger.LogInformation($"Merchant {cfg.MerchantName} sleeping until opening time {cfg.OpeningTime}");

0 commit comments

Comments
 (0)